geektimes

jQueryUI timePicker — виджет для выбора времени

  • вторник, 25 ноября 2014 г. в 02:10:45
http://habrahabr.ru/post/244057/

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

Не знаю, то ли я плохо искал (на plugins.jqueri.com есть только один подобный — KitKatClock, но он несколько «недоработан»), то ли искать не хотел, то ли и в правду до такого элемента никому дела нет. В общем, поскольку часть интерфейса, которую я разрабатывал, была ориентирована на заполнение полей пальцем (целевая аудитория устройств — инфокиоски) или, реже, мышкой, а полей для ввода времени было предостаточно, я решил родить еще один никому не нужный jquery-плагин.

Итак. Постановка ТЗ.
  1. Основные задачи которые должен решать элемент — более быстрый ввод времени в поле, без клавиатуры. В идеале — в два щелчка. Алгоритм выбора времени должен быть интуитивно понятным;
  2. Изначальная ориентированность на сенсорные экраны. Элемент должен предотвращать нежелательное всплытие экранной клавиатуры устройства; грамотно позиционироваться на экране так, чтобы, по возможности, не закрывать поле ввода и не выходить за пределы экрана;
  3. На десктопных машинах не мешать (а лучше — помогать) пользователю заполнять поле с клавиатуры, если он использует её как преимущественное средство ввода. Помощь может заключаться, скажем, в автоподстановке разделительного «:» символа. Т.е. человеку достаточно вводить только цифры;
  4. Обеспечивать совместимость со старыми браузерами. Да, да — без IE6 никуда. В целевых инфокиосках используется специализированное ПО, базирующееся на библиотеках сами-знаете-кого и именно той версии;
  5. Обеспечить совместимость с jQueryUI Calendar. Наш элемент должен корректно работать с полями, к которым уже присоединен любимый нами календарь, дополняя его и не мешая ему;
  6. Подключение и использование должно быть простым.


Подключение элемента почти тривиально:

<link rel="stylesheet" href="clock-ui.css" type="text/css"/>
<script language="javascript" src="clock-ui.min.js"></script>

Правда, есть одно но. Элемент использует изображения. И эти изображения могут располагаться у вас совсем в других местах. Изображения же прописаны в стилях. То есть используя такой элемент на своем сайте, вы должны поместить картинки куда надо, а затем внести соответствующие изменения в стили.

Скрытый текст
Я думал об использовании dataURI. Но, во-первых, css-файл становится объемным (что не хорошо), а во-вторых, IE это не нравится. Если кто расскажет как элегантно решить эту задачу, буду признателен.

Скрытый текст
Я думал об использовании SVG. Даже потратил 4 часа (!) на то, чтобы нарисовать часики в Xara Xtreme. Но к сожалению, Xara, при попытке экспортировать файл из родного формата в SVG, либо вылетает с ошибкой, либо сохраняет пустой файл. Жалко потраченного времени. Если есть добрые люди, способные сделать экспорт, будут рад. Обязательно соберу версию элемента на чистом SVG.
Вот этот файл.


Активация элемента еще проще:

$('input.time').timePicker();

Здесь мы связываем все текстовые поля, имеющие класс time, с нашим элементом. Причем допустимы повторные вызовы.

Можно вызывать для полей, связанных с календарем, при условии, что первым инициализируется календарь. Чтобы timePicker смог вставлять значение времени в такие совмещенные поля, необходимо у datePicker задать в опции dateFormat (и/или в altFormat) символ 'T' отделенный хотя бы одним пробелом:

$('.date')
		.datepicker({dateFormat: 'dd.mm.yy T'})
		.timePicker();

Если у календаря существует altField и altFormat и также содержит 'T', время будет устанавливаться и в нем.

Элемент timePicker поддерживает инициализацию с опциями. Опций не так много, но они есть.
  • Параметр touchscreen говорит элементу: является ли текущий тип устройства сенсорным? На самом деле элемент сам умеет определять такие устройства. Однако в процессе тестирования на инфокиосках столкнулись с тем, что экраны инфокиосков хоть и являются сенсорными, встроенный браузер события touchstart не поддерживает. Что приводило к неправильной работе элемента. Используйте параметр для решения таких ситуаций.
  • Параметр compatible (по умолчанию true). Предназначен для обеспечения совместимости со старыми браузерами. Например, элементу нужно, чтобы браузер обязательно поддерживал border-radius и background-size — иначе верстка станет не корректной. Если поддержка этих свойств есть, смело устанавливайте compatible = false, например так:

    $('.time').timePicker({
        compatible: !(Modernizr.backgroundsize && Modernizr.borderradius)
    });
    

  • Параметры defaultHour, defaultMinute задают время «по умолчанию» для пустых полей. Время задается в 12-часовом формате (от нуля). Параметр PM (логический) указывает на после полуденное время. Например, код ниже заставит элемент считать, что у пустых полей (или изначально некорректно заполненных), время равно 12:00:

    $('.time').timePicker({
        defaultHour: 0, defaultMinute: 0, PM: true
    });
    

  • Наконец, onOpened, onClosed устанавливают ваши обработчики на соответственно открытие и закрытие виджета. Важное замечание: обработчик вызывается уже после того, как виджет изменит свою видимость.


Существует два способа получить значение времени, выбранного в поле.

Первый: непосредственно считать value поля. В нашем проекте такие поля идут как строки и анализируются на стороне сервера, поэтому такое решение нас вполне устраивает.

Второй: можно прочитать время в «сыром» формате, например, так:

var hours = $('#element').data().hours,
    minutes = $('#element').data().minutes,
    pm = $('#element').data().pm_time;

Наконец, если вам необходимо получить время в unix-формате (в секундах от начала cуток), используйте:

$('#element').date().time;

Скрытый текст
Для элементов, связанных с календарем, хотелось сделать получение даты и времени более элегантно, через
$('#element').datepicker('getDate')
Но к сожалению, повлиять на дату элемента datePicker через getDate/setDate не удалось. Календарь, когда был скрыт, упорно возвращал текущую дату, а не выбранную ранее в поле.


Желающим протестировать работу элемента добро пожаловать.

Проект, как повелось, на гитхабе.