Заметки за апрель 2010 года

Sizzle задом наперед

В состав jQuery входит очень мощная библиотека Sizzle , которая отвечает за получение списка DOM-элементов, соответствующих заданным условиям. В ней реализованы все селекторы CSS3 и некоторые другие, которые не включены в спецификацию.

Хотя в некоторых современных браузерах у DOM-элементов есть специальные методы querySelector и querySelectorAll , которые реализуют этот функционал, тем не менее актуальность этой библиотеки остаётся неизменной из-за поддержки старых браузеров и браузеров, в которых нет эти методов.

Чтобы полностью раскрыть скоростной потенциал Sizzle нужно понимать, как на самом деле происходит фильтрация элементов документа.

Хорошим тоном при составлении правила будет первым селектором использовать получение элемента по атрибуту id , так как эта функция работает очень быстро и реализована во всех браузерах. Как вариант, можно задавать контекст поиска, если он известен, что сильно сокращает количество элементов, которые придется перебирать.

$("#data div.frame p span.dashed");

$("#data").find("div.frame p span.dashed");

$("div.frame p span.dashed", $("#data"));

В каждом правиле (за исключением поиска по id) стоит указывать тег, которому оно соответствует. Функция поиска по тегу тоже присутствует по всех браузерах. Так запрос

$("div.frame p span.dashed");

выполнится быстрее чем

$(".frame p .dashed");

Поиск по значению класса тоже уже реализован во многих браузерах, но в них, скорее всего, будет использоваться метод querySelectorAll.

А теперь самое интересное. Поиск элементов в документе или указанном контексте начинается с самого последнего правила. Затем уже отбрасываются элементы, предки которых не соответствуют требуемым условиям.

$("div.frame p span.dashed");

В этом примере сначала будут найдены все элементы span в документе. Затем отфильтрованы элементы, которые содержат класс dashed . После этого для каждого найденного элемента будет предпринята попытка найти у него предка с тегом p, затем предка с тегом div и классом frame.

Такой, казалось бы, не очевидный подход позволяет резко сократить количество операций на поиск элементов.

Как и везде, в алгоритме Sizzle есть исключение. Запрос типа $("#data span.dashed") будет обработан особым образом — селекторы в этом случае традиционно применятся слева направо.

Комментарии к заметке: 2

Блоки с выноской на поля

Дизайнеры часто в макетах с использованием модульной сетки выносят некоторые блоки за пределы модулей, чтобы добавить задний фон или рамку. Визуально текст в колонке и текст внутри такого блока выровнен по одной линии.

Пример блоков с выноской

Чтобы сверстать этот фрагмент можно задать значение padding для основного текста колонки и сделать его равным 0 у блока с выноской. Этот способ очевиден и надежен, но далеко не универсален. Нужно будет тщательно выверять выравнивание других модулей, которые могут быть привязаны к этой же разметке.

Более гибкий способ — это использование отрицательных значений margin . В этом случае достаточно будет определить 1 класс и добавлять его тем блокам, котором это необходимо.


.block {
    margin-left: -15px;
    margin-right: -15px;
    padding-left: 15px;
    padding-right: 15px;
    position: relative;
    zoom: 1;
}

Величина отступа с отрицательным значением задается в margin, и тут же компенсируется таким же положительным значением в padding.

Для IE 6 и 7 добавляются еще position: relative и свойство zoom: 1, которое включает блоку hasLayout . Замечу, что у родительского блока тоже обязательно должен быть включен hasLayout для корректного отображения.

Оставте свой комментарий

Сжатие файлов на томах HFS+ в Snow Leopard

В Snow Leopard появилась поддержка сжатия на уровне файловой системы — HFS+ compression . Сжатие и распаковка данных происходит полностью прозрачно для всех программ, которые обращаются к таким файлам.

Текущий интерфейс Файндера или какой-либо другой системной программы с GUI не позволяет управлять компрессией. Однако, Apple все же предоставила способ сжимать и распаковывать файлы через командную строку.

У команды ditto в 10.6 появилось несколько опций. Например,

—hfsCompression

When copying files or extracting content from an archive,if the destination is an HFS+ volume that supports compression, all the content will be compressed if appropriate. This is only supported on Mac OS X 10.6 or later, and is only intended to be used in installation and backup scenarios that involve system files. Since files using HFS+ compression are not readable on versions of Mac OS X earlier than 10.6, this flag should not be used when dealing with non-system files or other user-generated content.

Значит, чтобы включить сжатие HFS+, нужно всего лишь выполнить в командной строке

ditto --hfsCompression [src] [dst]

В качестве [src] указывается файл или папка, которая будет сжиматься, а [dst] — путь, где будут размещены сжатые файлы. Команда не заменяет файлы, а создает их сжатые копии в другом месте.

Внимание! Нельзя сжимать файлы, если необходимо подключать этот том в предыдущих версиях Mac OS X. Старые версии не повредят такие файлы, так как они просто не будут доступны для чтения.

На практике выходит не плохая экономия места. Например, сжав папку Developer с загруженной документацией, удалось высвободить около 3Гб (это около 40% от исходного объема) на диске.

Оставте свой комментарий

Установка предпочитаемого языка для программы

Замечательно, что программы для Mac OS X с минимальными затратами для разработчика можно перевести на любой язык мира. Только не всегда интерфейс с фразами на различных языках выглядит одинаково гармонично. Часто слова приходится сокращать, если они не помещаются в отведенные им места.

Все фразы интерфейса на различных языках находятся в файлах .lproj внутри пакета с приложением. Если удалить, например, ru.lproj, то программа лишится перевода на русский язык. Это так же неплохой способ сэкономить место на диске, которое занимает приложение. Вот только при очередном обновлении, а это особенно касается приложений от Apple, пакет с программой полностью заменяется и все файлы .lproj опять появляются.

Чтобы раз и навсегда выбрать предпочитаемый язык для какого-то конкретного приложения можно добавить соответствующее свойство через команду defaults . Во всей системе принято использовать свойство AppleLanguages для задания предпочитаемой последовательности языков.


defaults write -g AppleLanguages -array ru en de

Эта команда задает последовательность «Русский», «Английский», «Немецкий» для всей системы. Аналогичный эффект достигается в пульте «Язык и текст» настроек.

А если указать доменное имя программы, то список предпочитаемых языков будет сохранен только для нее.


defaults write com.apple.iTunes AppleLanguages -array en

Так мы указываем, что iTunes должен использовать только английский. Хочу подчеркнуть, что это свойство имеет тип «массив» даже если указывается только один язык.

Кстати, лично я запускаю iTunes только с английским интерфейсом, чтобы он не переводил мне названия жанров на русский язык, попутно модифицируя содержимое mp3 файлов.

Предпочтения удаляются командой

defaults delete com.apple.iTunes AppleLanguages
Комментарии к заметке: 2

JSONP для инициализации страницы

Блоки с динамическим содержимым уже давно принято обновляться асинхронными запросами на сервер. А вот для наполнения их начальными данными эта техника не слишком хорошо подходит из-за видимой задержки в появлении внешнего оформления блока и самого содержимого блока. Чтобы минимизировать эту задержку данные уже должны находиться на странице во время ее загрузки. Очевидно, что при этом HTML захламляется вкраплениями JavaScript, что не слишком хорошо. Компромиссным вариантом может быть загрузка данных с помощью тега script.

Предположим, что на сервере есть контроллер, который отдает модель данных в виде JSON. Пусть URL, по которому можно получить эти данные, будет http://example.com/data/?page=1, а сами данные


{sites: [
    {id: 1, name: "Yandex.ru", url: "http://yandex.ru/"},
    {id: 2, name: "Google", url: "http://google.com/"},
    {id: 3, name: "NotesKeeper", url: "http://noteskeeper.ru/"}
]}

Этот URL используется в асинхронном запросе, чтобы получить новую страницу блока. Если его подставить в тег script , то он, конечно же, будет загружен и исполнен, но возникнет синтаксическая ошибка, так как объект не был использован в операции присвоения или при вызове функции.

Добавим в параметры к URL еще один http://example.com/data/?page=1&callback=App.render и модифицируем контроллер на сервере так, чтобы этот параметр (при его наличии) подставлялся в выходные данные


App.render( {sites: [
    {id: 1, name: "Yandex.ru", url: "http://yandex.ru/"},
    {id: 2, name: "Google", url: "http://google.com/"},
    {id: 3, name: "NotesKeeper", url: "http://noteskeeper.ru/"}
]} );

Теперь такой адрес можно использовать в теге script. Когда данные будут загружены, то автоматически произойдет вызов указанной функции с моделью.

Контроллер интерфейса может иметь, например, такую структуру


var App = (function () {
    // скрытые переменные приложения
    return {
        // публичные методы приложения
        render: function (model) {
            // действия, которые можно выполнить до полной загрузки документа
            $(function () {
                // изменения в документе, который выполняются только
                // после его полной загрузки
                App.update(model);
            });
        },
        update: function (model) {
            // обновляем содержимое блока
        }
    };
}());

Когда мы получим от сервера модель с начальными данными, то дождемся сигнала о полной загрузке документа, чтобы безопасно можно было начать его изменения, и приступим к построению содержимого блока.

Эта техника и называется JSONP (JSON with padding). Основное применение она нашла в загрузке данных сторонних сервисов, например, таких как Flickr, Yahoo, Google и многих других. Из-за того, что асинхронные запросы для других доменов блокируются политикой безопасности браузера, использование этой техники наряду с iframe является, пожалуй, единственным возможным вариантом.

В одном из проектов, над которым я работаю в последнее время, такой прием успешно используется для загрузки граничных условий валидатора форм.

Оставте свой комментарий