Заметки за 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