Pull to refresh

Dojo Control для выбора времени

Reading time6 min
Views1.6K
Хочу поделиться моим Dojo-модулем для выбора времени. Этот контролл понадобился мне во время исследований в нашем институте. Задачей контрола было предоставить студентам понятный и быстрый интерфейс для выбора времени.

Выбор часа

Выбор минут

Сначала было желание мимолетно упростить себе жизнь и сделать HTML хард-код в виде двух выпадающих списков с выбором часа и минут, потом подумал почему бы не сделать это в виде Dojo компонента, что даст мне некоторые преимущества:
1. Возможность сделать более красивый и удобный интерфейс
2. Более удобное использование такого компонента для установки/получения текущего времени
3. Возможность легко создавать новые экземпляры компонента с помощью JavaScript, а также полное управление этим компонентом
4. Неплохая экономия трафика
И так приступим. Что должен делать мой компонент:
1. Принимать время в форматах: H:M, количество минут (например 125=2:05)
2. При выборе времени заносить его в скрытое поле для возможности получения времени при отправке формы на сервер
3. Иметь JavaScript — функции для установки/получения текущего времени компонента

Рассмотрим весь процесс разработки.


1. Dojo установлен и настроен. Для начала убедитесь, что Dojo установлен и настроен правильно. В этой статье я не буду рассматривать процесс установки и настройки, так как этот процесс довольно таки хорошо документирован. Предположим что Dojo установлен в папку /js/dojo/dojo.
2. Настройка Dojo для работы с нашими компонентами. Свои компоненты мы желаем размещать в отдельных директориях, которые не будут конфликтовать с Dojo, для собственных Dojo-компонентов создадим папку /js/dojo/switlle
Теперь для использования наших компонентов из этой папки мы должны зарегистрировать этот путь. Сделайте это сразу после подключения Dojo:

3. Создание Dojo модуля TimeSelect. Теперь создадим файл /js/dojo/switlle/TimeSelect.js с таким содержимым:

if (!dojo._hasResource["switlle.dojo.TimeSelect"]) {
dojo._hasResource["switlle.dojo.TimeSelect"] = true;
dojo.require("dojo.cache");
dojo.provide("switlle.dojo.TimeSelect");
dojo.declare("switlle.dojo.TimeSelect", [dijit._Widget, dijit._Templated], {

/*
* В шаблоне указываем необходимые нам узлы для часов и минут,
* а так же скрытое поле для корректной отправки времени на сервер
*/
templateString: " : />",

time: '00:00',
timemin: 0,
name: '',

/*
* В карте атрибутов сделаем мап для переназначения атрибута name
* на узел hiddenFieldNode. Это опять таки для корректной отправки
* времени на сервер
*/
attributeMap: {
name: {
node: "hiddenFieldNode",
type: "attribute"
}
},
buildRendering: function () {
this.inherited(arguments);

/**
* Создаем выпадающий список для часов.
* В выпадающем списке создаем любую HTML разметку с любой детализацией часов.
* Мне нужны были часы с почасовой детализацией, в 24-часовом формате
*/
var thisObj = this;
var hours_dlg = new dijit.TooltipDialog({
content: "<table class='switlle-time-select-hours'><tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td><td>12</td></tr><tr><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td><td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>00</td></tr></table>",
onOpen: function()
{
dojo.query('.switlle-time-select-hours td', this.containerNode).removeClass('hover');
},
postCreate: function()
{
//На все часы повесим необходимые обработчики
dojo.query('.switlle-time-select-hours td', this.containerNode).forEach(function(el){
dojo.connect(el, 'onclick', function(e) {
hours_button.attr('label', e.target.innerHTML);
hours_dlg.onCancel();
thisObj._onChange();
});
dojo.connect(el, 'onmouseover', function(e) {
dojo.addClass(e.target, 'hover');
});
dojo.connect(el, 'onmouseout', function(e) {
dojo.removeClass(e.target, 'hover');
});
});
}
});
var hours_button = new dijit.form.DropDownButton({
label: '00',
dropDown: hours_dlg
});
this.hoursNode.appendChild(hours_button.domNode);
//Запомним эту кнопку для того, чтобы потом устанавливать ей надпись в виде текущего часа
this._hours_button = hours_button;

/**
* Также создадим выпадающий список для минут
* С детализацией через каждые 5 минут
*/
var minutes_dlg = new dijit.TooltipDialog({
content: "<table class='switlle-time-select-minutes'><tr><td>00</td><td>05</td><td>10</td><td>15</td><td>20</td><td>25</td></tr><tr><td>30</td><td>35</td><td>40</td><td>45</td><td>50</td><td>55</td></tr></table>",
onOpen: function()
{
dojo.query('.switlle-time-select-hours td', this.containerNode).removeClass('hover');
},
postCreate: function()
{
//На все минуты повесим необходимые обработчики
dojo.query('.switlle-time-select-minutes td', this.containerNode).forEach(function(el){
dojo.connect(el, 'onclick', function(e) {
minutes_button.attr('label', e.target.innerHTML);
minutes_dlg.onCancel();
thisObj._onChange();
});
dojo.connect(el, 'onmouseover', function(e) {
dojo.addClass(e.target, 'hover');
});
dojo.connect(el, 'onmouseout', function(e) {
dojo.removeClass(e.target, 'hover');
});
});
}
});
var minutes_button = new dijit.form.DropDownButton({
label: '00',
dropDown: minutes_dlg
});
this.minutesNode.appendChild(minutes_button.domNode);
//Запомним эту кнопку для того, чтобы потом устанавливать ей надпись в виде текущей минуты
this._minutes_button = minutes_button;
},
/**
* time setter
*/
_setTimeAttr: function(time) {
this.time = time;
var dot = this.time.indexOf(':');
var hours = parseInt(this.time.substring(0, dot));
var minutes = parseInt(this.time.substring(dot+1));
this._hours_button.attr('label', hours);
this._minutes_button.attr('label', minutes);
this._onChange();
},
/**
* time getter
*/
_getTimeAttr: function() {
return this._hours_button.attr('label')+':'+this._minutes_button.attr('label');
},

/**
* timemin setter
*/
_setTimeminAttr: function(seconds) {
this.timemin = seconds;
var hours = parseInt(seconds/60);
var minutes = seconds-hours*60;
if (hours==0)
hours='00';
if (minutes<10)
minutes='0'+minutes;
this.time = hours+':'+minutes;
this._hours_button.attr('label', hours);
this._minutes_button.attr('label', minutes);
this._onChange();
},
/**
* timemin getter
*/
_getTimeminAttr: function() {
return parseInt( this._hours_button.attr('label'))*60+parseInt(this._minutes_button.attr('label'));
},
/**
* Функция вызываемая при изменнии текущего значения компонента
* В ней станавливаем значение скрытого поля, и вызываем событие onChange,
* на которое смогут подписываться клиенты
*/
_onChange: function() {
this.hiddenFieldNode.value = this.attr('time');
this.onChange(this);
},
onChange: function(control) {
}
});
}


4. Использование компонента. Для использование нашего компонента, его сначала нужно подключить. Для этого немного модифицируем код, в котором мы регистрировали путь к папке с нашими компонентами:

Теперь мы можем добавить в разметку нашей страницы следующий код:
/>
или

Не обращайте никакого внимания на то что первая строчка содержит тег input, а вторая span. Имя тега роли не играет абсолютно, все равно эта конструкция будет заменена на наш шаблон content. А вот два разных атрибута timemin и time вызывают разные setter-ы. В timemin мы передаем количество минут, а в time строковое представление времени.
Также при отправки формы на сервер, мы можем получить значение этого компонента из массива GET или POST с ключом 'timeControl'.
Для того, чтобы создать этот компонент программно с помощью JavaScript, так же не понадобится много труда:


Для программной установки/чтения значения контрола:

И напоследок подпишемся на событие onChange:

Используемые CSS:
.switlle-time-select-hours td, .switlle-time-select-minutes td {
border:1px solid #EEEEEE;
color:#333333;
cursor:pointer;
padding:5px 7px;
text-align:center;
vertical-align:middle;
}
.switlle-time-select-hours td.hover, .switlle-time-select-minutes td.hover {
background-color:#EEEEEE;
border:1px solid #DDDDDD;
}


Конечно контрол можно снабдить еще различными проверками на правильность времени, может будут полезны какие-либо дополнительные украшательства, но это оставим на потом. Основной необходимый мне функционал я получил.
Tags:
Hubs:
Total votes 16: ↑10 and ↓6+4
Comments9

Articles