Заметки за 2009 год

Модули в YUI3

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

Создать модуль можно, например, на основе следующего кода:

YUI.add("mymodule", function(Y) {
    Y.MyModule = function() {
        // конструктор
    };
});

В дальнейшем он используется так:

YUI().use("mymodule", function (Y) {
    var o = new Y.MyModule();
});

Основная задача шаблона — это изолировать модуль и подключать его к экземпляру YUI (переменная Y в YUI.add и YUI.use) только при необходимости.

При создании экземпляра YUI можно указать в конфигурации атрибуты для динамической загрузки нашего модуля и нужных ему зависимостей.

YUI({
    modules: {
        "mymodule":{
            // полный путь к файлу
            fullpath:"mymodule.js",
            // зависимости модуля
            requires: ["dd", "widget"]
        }
    }
}).use("mymodule", function () {
    // код приложения
});

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

Так же эти зависимости нужно указать в YUI.add

YUI.add("mymodule", function(Y) {
    Y.MyModule = function() {
        // конструктор
    };
}, "1.0", {requires: ["dd", "widget"], use: ["dd", "widget"]});

Данные, которые передаются при объявлении, указывают на то, что требуется для работы модуля, когда он загружен и используется в методе YUI.use. Так код модуль может быть явно подключен на странице.

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

Выбор диапазона дат с помощью jQuery UI Datepicker

Для очередного проекта понадобился виджет для выбора даты. Очевидным, по крайней мере для меня, решением было jQuery UI Datepicker. Но когда позже понадобилось выбирать не одну дату, а диапазон, я попал в тупик. В API не было ни какого упоминания о такой возможности. Поисковики все как один выдавали какие-то «самоделки» далеко не первой свежести.

Копнув глубже исходники Datepicker, я все-таки обнаружил возможность выбора диапазона. Реализуется все логика через событие «onSelect».

У экземпляра Datepicker есть флаг stayOpen. Если его установить внутри события, то календарь не закроется после клика, а занесет выбранную дату в поле rangeStart и позволит выбрать еще дату. Когда будет выбран конец диапазона, нужно сбросить флаг stayOpen и обновить содержимое текстового поля.

Внимание! Плагин актуален только для jQuery UI 1.7.x. Для последних версий нужно использовать другую редакцию этого плагина.

(function ($) {

  $.fn.daterange = function () {
    // опции
    var opts = $.extend({
      "dateFormat": "dd.mm.yy",
      "changeMonth": false,
      "changeYear": false,
      "numberOfMonths": 2,
      "rangeSeparator": "-"
    }, arguments[0] || {}, {
      // обработчики событий datepicker
      // закрытие
      "onClose": function (dateText, inst) {
        if ($.isFunction(opts.callback)) {
          opts.callback.apply(this, arguments);
        }
      },
      // выбор даты
      "onSelect": function (dateText, inst) {
        var textStart;
          if (!inst.rangeStart) {
            inst.stayOpen = true;
          } else {
            inst.stayOpen = false;
            textStart = $.datepicker.formatDate(opts.dateFormat, inst.rangeStart);
            if (textStart !== dateText) {
              $(this).val(textStart + " " +
                opts.rangeSeparator + " " + dateText);
            }
          }
      }
    });

    return this.each(function () {
      var input = $(this);
      if (input.is("input")) {
        input.datepicker(opts);
      }
    });
  };

}(jQuery));

Еще одно событие, которое может пригодиться, это «onClose». Оно будет сгенерировано в момент закрытия календаря. В плагине я просто делегирую все исполнение внешнему обработчику, но на практике мне удобно было добавить туда больше функционала.

Плагин может быть проинициализирован любыми параметрами, которые используются в Datepicker. Так как обработчик события «onClose» переопределяется, то вместо него используется поле callback.

Второе дыхание

Обновлено 2013-06-19

Для последних версий jQuery UI вместо stayOpen нужно использовать флаг inline. Однако это только запретит календарю закрыться. Нужно ещё позаботиться о сохранении первой выбранной даты.

(function ($) {

  $.fn.daterange = function () {
    // опции
    var opts = $.extend({
      "dateFormat": "dd.mm.yy",
      "changeMonth": false,
      "changeYear": false,
      "numberOfMonths": 2,
      "rangeSeparator": "-"
    }, arguments[0] || {}, {
      // обработчики событий datepicker
      // закрытие
      "onClose": function (dateText, inst) {
        if ($.isFunction(opts.callback)) {
          opts.callback.apply(this, arguments);
        }
      },
      // выбор даты
      "onSelect": function (dateText, inst) {
        var textStart;
          if (!inst.rangeStart) {
            inst.inline = true;
            inst.rangeStart = dateText;
          } else {
            inst.inline = false;
            textStart = inst.rangeStart;
            if (textStart !== dateText) {
              $(this).val(textStart + " " +
                opts.rangeSeparator + " " + dateText);
              inst.rangeStart = null;
            }
          }
      }
    });

    return this.each(function () {
      var input = $(this);
      if (input.is("input")) {
        input.datepicker(opts);
      }
    });
  };

}(jQuery));
Комментарии к заметке: 20

Сглаживание с суб-пиксельной точностью

Каждый пиксель на стандартном LCD-мониторе состоит из трех независимых компонент: красной, зеленой и синей. Из-за маленького размера этих суб-пикселей наш глаз объединяет их в один пиксель со сплошным цветом. Обычно, чтобы обеспечить сглаживание яркость всех цветовых компонент задается одинаковой, что в результате дает оттенки серого. При отображении с суб-пиксельной точностью яркость каждой цветовой компоненты задается независимо, что воспринимается как увеличенная разрешающая способность монитора. Пиксели уже не воспринимаются как одиночные, а связываются со своими соседями, что позволяет плавно произвести сглаживание. Однако по краям глифов при таком сглаживании образуются цветовые искажения.

Сглаживание с суб-пиксельной точностью

Техника сглаживания с суб-пиксельной точностью опирается на идеально ровную сетку пикселей. Эти условия обеспечиваются только на LCD-мониторах. Сетка CRT-мониторов имеет смещение по горизонтали от линии к линии, что делает эту технику крайне сложной для воспроизведения. Даже LCD-мониторы имеются различия в расположении суб-пикселей, которые должны быть учтены. У одних мониторов порядок следования RGB, а у других — BGR.

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

«Красивый» Javascript код

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

Чтобы удобно и быстро можно было делать проверку кода на соответствие этим соглашениям, он написал приложение JSLint, которое анализирует код и дает подсказки о том, как следует исправить проблемные места.

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

Так в моем коде появились ошибки типа: «Move the invocation into the parens that contain the function» и «Wrap the entire immediate function invocation in parens». Конечно, исправлять старый и работающий код не было нужды, а вот для новых разработок было бы интересно устранить эти сообщения.

JSLint выдает эти ошибки, когда встречает замыкание

(function () {})();

И предлагает оформить его как

(function () {}());

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

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

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

Событие окончания загрузки картинки

Чтобы отследить момент загрузки картинки одного обработчика события «load» бывает не достаточно. Если он будет прикреплен к картинке после того, как она уже была загружена, то событие больше не повторится и обработчик не будет вызван.

Поможет решить эту проблему вспомогательный плагин к jQuery.

;(function ($) {
    $.fn.bindImageLoad = function (callback) {
        function isImageLoaded(img) {
            // Во время события load IE и другие браузеры правильно
            // определяют состояние картинки через атрибут complete.
            // Исключение составляют Gecko-based браузеры.
            if (!img.complete) {
                return false;
            }
            // Тем не менее, у них есть два очень полезных свойства: naturalWidth и naturalHeight.
            // Они дают истинный размер изображения. Если какртинка еще не загрузилась,
            // то они должны быть равны нулю.
            if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) {
                return false;
            }
            // Картинка загружена.
            return true;
        }

        return this.each(function () {
            var ele = $(this);
            if (ele.is("img") && $.isFunction(callback)) {
                ele.one("load", callback);
                if (isImageLoaded(this)) {
                    ele.trigger("load");
                }
            }
        });
    };
})(jQuery);

Обновление: Работу плагина можно посмотреть в примере. Там используется немного модифицированная версия, которая формирует специальное событие.

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