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

How To: Проверить используется летнее время или нет

Тема часовых поясов в отношении веб-страниц поднимается очень редко. Иногда все же приходится вычислять часовые пояса в JavaScript.

Как правило, на странице можно получить текущее время пользователя, которое может быть преобразовано в «универсальное координированное время». Но это время может быть как «зимним», так и «летним » (с поправкой на 1 час). Чтобы проверить, нужно ли использовать поправку или нет, сделаем сравнения часовых поясов для данного региона зимой и летом. В качестве тестовых точек возьмем даты «1 февраля» и «1 августа».


var s,
    now = new Date(),
    nowTZ = now.getTimezoneOffset(),
    winterTZ = new Date(now.getFullYear(), 1, 1).getTimezoneOffset(),
    summerTZ = new Date(now.getFullYear(), 7, 1).getTimezoneOffset();

if (winterTZ === summerTZ) {
    s = 'no daylight saving';
} else {
    if (nowTZ === winterTZ) {
        s = 'winter time';
    } else if (nowTZ === summerTZ) {
        s = 'summer time';
    } else {
        throw new Error('Unknown time zone');
    }
}

В некоторых странах (например, Япония, Китай, большая часть Африки и Южной Америки) перевод на «летнее время» не используется и это можно определить, если часовой пояс зимой и летом не будет отличаться. Если переход на «летнее время» все-таки используется, то проверяем, какой часовой пояс сейчас используется – летний или зимний.

Обновление от 31 октября 2011 года : В России с 5 августа 2011 года вступил в силу «Закон об исчислении времени», отменяющий сезонный перевод часов. Печальной новостью стало то, что в Windows (начиная с XP и заканчивая 7 со всеми последними обновлениями) часовые пояса для дат в прошлом определяются не верно. В браузерах, запущенных нa OSX или Linux, такой проблемы с часовыми поясами для дат в прошлом не возникает.

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

jQuery UI виджет, имитирующий кнопку

В статьях jQuery UI API и Фабрика элементов интерфейса jQuery UI я кратко рассказал о внутреннем устройстве надстройки jQuery UI. На примере кнопки я покажу, как можно писать очень полезные виджеты.

Задача: Написать виджет, имитирующий нажатие и блокирование кнопки. Он так же должен оповещать подписчиков о событиях, происходящих с этой кнопкой.

Объявляем наш виджет.

$.widget("trv.button", {

Так как я его изначально писал для проекта под кодовым названием «TRAVEL», то и пространство имен у меня будет особое, а не стандартное «ui». Если вы будете использовать свое пространство имен (а я настоятельно рекомендую вам это, чтобы избежать путаницы), то не забудьте переименовать классы CSS.

Далее объявляем инициализирующий метод нашего будущего виджета.


    _init: function() {
        var me = this;
        me.element
            .bind('mousedown.' + me.name, function() {
                me._down();
                return false;
            })
            .bind('mouseup.' + me.name, function () {
                me._up();
                return false;
            })
            .bind('click.' + me.name, function(event) {
                if (!me._getData('disabled')) {
                    me._trigger('press', event);
                }
                return false;
            });
    },

В этом методе подписываемся на события, связанные с нажатием левой кнопки мыши — «mousedown», «mouseup» и «click». Я не буду создавать дополнительные элементов для оформления кнопки, так-как предполагаю, что вся необходимая верстка присутствует на странице.


    destroy: function() {
        var me = this;
        me.element
            .unbind('mousedown.' + me.name)
            .unbind('mouseup.' + me.name)
            .unbind('click.' + me.name);
    },

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

Следующие методы носят исключительно вспомогательный характер и не доступны извне.


    _down: function () {
        var me = this;

        if (!me._getData('disabled')) {
            me.element
                .addClass(me.widgetBaseClass + '-pressed')
                .one('mouseout.' + me.name, function () {
                    me._up();
                    me.element.one('mouseover.' + me.name, function () {
                        me._down();
                    });
                });

            $(document).one('mouseup.' + me.name, function () {
                me._up();
            });
        }
    },

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

Стоит заметить, что событие «mouseup» ловится на документе потому, что когда указатель мышки покинет элемент, то он уже не сможет ловить это событие.


    _up: function () {
        var me = this;
        me.element
            .unbind('mouseout.' + me.name)
            .unbind('mouseover.' + me.name)
            .removeClass(this.widgetBaseClass + '-pressed');
    }

Убираем дополнительный CSS класс с элемента, чтобы вернуть кнопку в исходное состояние, и отписываемся от событий «mouseout» и «mouseover».

});

Верстка кнопки может варьироваться вне зависимости от кода. Например, я использую такую:


<span class="trv-button">
    <span class="first-child">
        <em>Press me!</em>
    </span>
</span>

Кнопка полностью состоит из строчных элементов и теоретически может быть размещена внутри текста.

Когда на нее нажимают, то к основному элементу добавляется класс «trv-button-press». Этот класс автоматически создается из названия виджета и суффикса «-press».

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

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

Фабрика элементов интерфейса jQuery UI

Обновление: Некоторые свойства и методы фабрики в версии 1.8 были изменены. Данная статья актуальна только для версий jQuery UI 1.7.x

Фабрика элементов интерфейса или, как их еще называют, виджетов (widget) используется для создания всех элементов jQuery UI . Она защищает от попыток создать несколько экземпляров виджета в одном элементе и от вызова скрытых методов (помеченных подчеркиванием).

Элементы интерфейса создаются функцией $.widget, в качестве параметров которой передается название и прототип:

$.widget('ui.myWidget', { … });

Свойства

  • this.element

    Элемент, который используется для создания экземпляра плагина. Это поле всегда содержит jQuery объект с одним элементом. Если при создании виджета была использована выборка с несколькими элементами, то для каждого элемента из коллекции будет создан свой экземпляр.

  • this.options

    Настройки экземпляра, которые при создании объединяются с настройками по умолчанию, определенными в $.ui.myWidget.defaults . Если у плагина есть какие-то метаданные, то они тоже объединяются с настройками.

  • this.namespace

    Пространство имен плагина (в нашем примере это «ui»). Обычно не используется внутри плагинов.

  • this.name

    Имя плагина (например, «myWidget»). Также редко используется внутри плагина как и пространство имен.

  • this.widgetEventPrefix

    Это свойство используется для определения названия событий, которые генерирует плагин. Например, у диалогового окна есть функция обратного вызова callback close . Когда выполняется эта функция, генерируется событие «dialogclose». Название события — конкатенированные префикс события и название функции обратного вызова. Префикс по умолчанию совпадает с названием виджета, но может быть заменен. Например, для плагина draggable были бы не приемлемы названия событий «draggablestart» и т.п. По этому, меняя префикс на «drag», получаем названия «dragstart» и т.п. Требуемое значение нужно установить $.ui.myWidget.eventPrefix.

  • this.widgetBaseClass

    Это полезное свойство помогает создавать названия CSS классов элементов внутри вашего виджета. Например, чтобы отметить элемент как «активный» вы делаете

    
    element.addClass(this.widgetBaseClass + '-active').
    

    Это свойство широко используется в фабрике и абстрактных плагинах типа $.ui.mouse.

Методы

  • _init

    Это метод, где происходит инициализация и настройка всего необходимого для работы виджета, например, создание элементов или привязка к событиям. Метод выполняется сразу после создания экземпляра.

  • destroy

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

  • option

    Используется для получения и изменения настроек плагина после создания экземпляра. Сигнатура метода аналогична css и attr . Вы можете указать только имя, чтобы получить значение настройки, имя и значение, чтобы изменить настройку или объект для изменения нескольких настроек. Этот метод внутри вызывает _getData или _setData.

  • _getData

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

  • _setData

    Вызывается, когда пользователь устанавливает значения настроек или через метод option . Этот метод может быть переопределен, чтобы плагин реагировал на изменение какой-то настройки. Например, когда меняется значение заголовка диалогового окна, текст в заголовке тоже должен обновиться.

  • enable

    Вспомогательный метод, который вызывает _setData(‘disabled’, false) .

  • disable

    Вспомогательный метод, который вызывает _setData(‘disabled’, true).

  • _trigger

    Метод должен использоваться для запуска функций обратного вызова. Обязательным параметром метода является название функции, который нужно выполнить. Все функции так же генерируют события. Так же вы можете передать объект event, который вызвал запуск. Например, событие перетаскивания «drag» было вызвано событием «mousemove», поэтому в метод _trigger должно быть передано исходное значение события. Третьим параметром может быть произвольные данные, которые передаются в функцию и обработчик события.

Когда плагин переопределяет методы из $.widget.prototype, то оригинальные методы тоже должны быть вызваны:


$.widget('ui.myPlugin', {
    destroy: function() {
        this.element.removeAttr('something');
        $.widget.prototype.destroy.apply(this, arguments);
    }
});

Источник: http://wiki.jqueryui.com/Widget-factory

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

jQuery UI API

Все плагины jQuery UI (widget) имеют общий программный интерфейс (API). Это сокращает этап изучения новых плагинов — если вы уже использовали какой-то плагин, то можно сказать, что знаете как использовать другие. Все плагины имеют настройки, но при этом могут быть проинициализированы без их указания.

Инициализация и настройка

Для инициализации плагина с настройками по умолчанию вы просто вызываете его как любой другой метод jQuery:

$('#my-elem').draggable();

Чтобы задать какие-то опции на этапе инициализации, вы передаете их в одном объекте:

$('#my-elem').draggable({
    axis: 'x',
    containment: 'window'
});

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

$('#my-elem').draggable('option', 'axis', 'y');

Может оказаться так, что вам приходится использовать один и тот же плагин с какими-то особыми настройками. Вместо того, чтобы постоянно указывать одни и те же значения каждый раз при инициализации, вы можете один раз изменить значения по умолчанию для этого плагина:

$.ui.draggable.defaults.containment = 'window';

Методы

Вызов методов уже был продемонстрирован выше на примере метода option . Чтобы не захламлять jQuery горой методов для каждого плагина, все методы вызываются через функцию инициализации. Для вызова какого-то метода плагина вы передаете его имя первым параметром, затем следуют параметры для этого метода. Другими словами, вызов метода method(‘param1’, ‘param2’) становится plugin(‘method’, ‘param1’, ‘param2’).

У каждого плагина есть несколько общих методов:

  • option

    Получить или задать настройки; использует формат параметров аналогичный css или attr

    
    $('#my-elem').draggable('option', 'axis');
    $('#my-elem').draggable('option', 'axis', 'y');
    $('#my-elem').draggable('option', {
        axis: 'y',
        containment: 'window'
    });
    
  • enable

    Включить плагин

    $('#my-elem').draggable('enable');
    
  • disable

    Отключить плагин

    $('#my-elem').draggable('disable');
    
    
  • destroy

    Удалить экземпляр плагина и вернуть элемент в первоначальное состояние.

    $('#my-elem').draggable('destroy');
    

События

Все UI плагины генерируют события, позволяющие разработчику взаимодействовать с ним. Например, draggable генерирует события start, drag и stop . Каждому событию назначается функция обратного вызова (callback). При возникновении события соответствующей функции передаются два параметра — объекты event и ui.

Для объявления функции обратного вызова при настройке укажите ее в соответствующей опции:


$('#my-elem').draggable({
    start: function(event, ui) {
        // обработчик события
    }
});

Так же вы можете привязаться к событию через метод bind jQuery. Нужно отметить, что имя события в этом случае указывается с префиксом для предотвращения коллизий с событиями браузера.


$('#my-elem')
    .draggable()
    .bind('dragstart', function(event, ui) {
        // обработчик события
    });

Оригинал: http://wiki.jqueryui.com/API

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

Рассчитать ширину скролбара

Порой на страницах с «резиновой» версткой необходимо знать ширину скролбара, чтобы правильно вычислить размеры внутренних элементов и их положение. Эта задача решается с помощью следующего алгоритма:

  1. добавить два div в body и разместить их за пределами экрана;
  2. определить ширину внутреннего div;
  3. установить значение «scroll» свойства overflow у внешнего div;
  4. опять определить ширину внутреннего div;
  5. удалить оба div;
  6. вернуть разницу между измеренными ранее значениями ширины.

Для простоты манипуляции с документом используем jQuery


function scrollbarWidth() {
    var div = $('<div style="width:50px; height:50px; overflow:hidden; position:absolute; top:-200px; left:-200px;"><div style="height:100px;"></div></div>').appendTo('body');
    var w1 = $('div', div).innerWidth();
    div.css('overflow-y', 'scroll');
    var w2 = $('div', div).innerWidth();
    $(div).remove();
    return (w1 - w2);
}

Источник: http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php

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