Не так давно мне была поставлена задача написать модуль для резервации номеров в отеле. Выбор дат в форме резервации я решил реализовать с помощью виджета jQuery UI Datepicker. Весь модуль мы разбирать не будем, а остановимся на основных моментах с которыми столкнулся я в процессе разработки.
Сперва нам надо создать форму, к которой мы будем подключать виджет jQuery UI Datepicker, я покажу только кусок кода из модуля:
/**
* Form constructor for the reservation form.
*
* @ingroup forms
*/
function mymodule_reservation_form($form, &$form_state) {
$form['arrival'] = array(
'#type' => 'textfield',
'#title' => t('Arrival'),
'#default_value' => date('d.m.Y', REQUEST_TIME), // Устанавливаем в качестве значения по умолчанию сегодняшний день.
'#required' => TRUE,
'#size' => 10,
'#maxlength' => 10,
);
$form['departure'] = array(
'#type' => 'textfield',
'#title' => t('Departure'),
'#default_value' => date('d.m.Y', REQUEST_TIME + 86400), // Устанавливаем в качестве значения по умолчанию завтрашний день.
'#required' => TRUE,
'#size' => 10,
'#maxlength' => 10,
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Verify'),
);
return $form;
}
Переходим непосредственно к подключению виджета jQuery UI Datepicker. Добавляем в функцию, которая формирует форму следующие строки:
$form['#attached']['library'][] = array('system', 'ui.datepicker');
$form['#attached']['js'][] = drupal_get_path('module', 'mymodule') . '/js/mymodule.js';
Создаем mymodule.js и ложим его в каталог mymodule/js/mymodule.js. Содержимое этого файла:
(function ($) {
Drupal.behaviors.myModule = {
attach: function (context){
$('#edit-arrival', context).datepicker();
$('#edit-departure', context).datepicker();
}
}
})(jQuery);
В принципе на этом уже можно было бы остановиться, но мне сразу же бросилось в глаза, что дата выводится в формате mm/dd/yy. Такой вывод лично для меня не удобен и я поменял его на следующий формат dd.mm.yy:
$('#edit-arrival', context).datepicker({
dateFormat: 'dd.mm.yy'
});
$('#edit-departure', context).datepicker({
dateFormat: 'dd.mm.yy'
});
Поскольку я писал форму резервации номеров отеля, то мне потребовалось заблокировать прошедшие дни, причем дата въезда и выезда должны отличаться минимум в 1 день:
$('#edit-arrival', context).datepicker({
dateFormat: 'dd.mm.yy',
minDate: 0 // Устанавливаем в качестве минимальной даты сегодняшний день.
});
$('#edit-departure', context).datepicker({
dateFormat: 'dd.mm.yy',
minDate: 1 // Устанавливаем в качестве минимальной даты завтрашний день.
});
Уже лучше, но теперь необходимо после выбора даты въезда заблокировать в поле даты выезда уже выбранную дату въезда и все даты, которые перед ней:
$('#edit-arrival', context).change(function() {
var strDate = $('#edit-arrival', context).attr('value');
var dateParts = strDate.split('.');
$('#edit-departure', context).datepicker('option', 'minDate', new Date(dateParts[2], dateParts[1] - 1, parseInt(dateParts[0]) + 1));
});
Далее мне захотелось справа от полей добавить иконки календарей, клик по которым вызывает виджет. Для этого в функцию, которая формирует форму, добавляем следующие строки:
$form['#attached']['js'][] = array(
'data' => array(
'mymodule_path' => drupal_get_path('module', 'mymodule'),
),
'type' => 'setting',
);
Теперь мы можем в mymodule.js получить путь к модулю и указать полный путь к изображению календаря:
$('#edit-arrival', context).datepicker({
showOn: 'both', // Показываем виджет как по фокусу input'а, так и по клику на изображение календаря.
buttonImage: Drupal.settings.basePath + Drupal.settings.mymodule_path + '/images/calendar.png', // Указываем путь к изображению с календарем.
buttonImageOnly: true, // Если установлено в false, то отображается button c бэкграундом календаря, если в true, то выводится обычная картинка.
dateFormat: 'dd.mm.yy',
minDate: 0 // Устанавливаем в качестве минимальной даты сегодняшний день.
});
$('#edit-departure', context).datepicker({
showOn: 'both', // Показываем виджет как по фокусу input'а, так и по клику на изображение календаря.
buttonImage: Drupal.settings.basePath + Drupal.settings.mymodule_path + '/images/calendar.png', // Указываем путь к изображению с календарем.
buttonImageOnly: true, // Если установлено в false, то отображается button c бэкграундом календаря, если в true, то выводится обычная картинка.
dateFormat: 'dd.mm.yy',
minDate: 1 // Устанавливаем в качестве минимальной даты завтрашний день.
});
Теперь уже точно можно было бы завершить урок по работе с виджетом jQuery UI Datepicker, если бы не одно но. Сайт к которому я писал модуль на двух языках, поэтому необходимо показывать виджет на языке сайта (по умолчанию он выводится на английском). Для этого воспользуемся возможностями модуля Locale, который входит в ядро. В функцию, которая формирует форму, добавляем следующие строки:
global $language;
$form['#attached']['js'][] = drupal_get_path('module', 'locale') . '/locale.datepicker.js';
$form['#attached']['js'][] = array(
'data' => array(
'jqueryuidatepicker' => array(
'rtl' => $language->direction == LANGUAGE_RTL,
'firstDay' => variable_get('date_first_day', 0),
),
),
'type' => 'setting',
);
Итоговый вид функции, которая формирует форму:
/**
* Form constructor for the reservation form.
*
* @ingroup forms
*/
function mymodule_reservation_form($form, &$form_state) {
global $language;
$form['#attached']['library'][] = array('system', 'ui.datepicker');
$form['#attached']['js'][] = drupal_get_path('module', 'locale') . '/locale.datepicker.js';
$form['#attached']['js'][] = drupal_get_path('module', 'mymodule') . '/js/mymodule.js';
$form['#attached']['js'][] = array(
'data' => array(
'mymodule_path' => drupal_get_path('module', 'mymodule'),
'jqueryuidatepicker' => array(
'rtl' => $language->direction == LANGUAGE_RTL,
'firstDay' => variable_get('date_first_day', 0),
),
),
'type' => 'setting',
);
$form['arrival'] = array(
'#type' => 'textfield',
'#title' => t('Arrival'),
'#default_value' => date('d.m.Y', REQUEST_TIME), // Устанавливаем в качестве значения по умолчанию сегодняшний день.
'#required' => TRUE,
'#size' => 10,
'#maxlength' => 10,
);
$form['departure'] = array(
'#type' => 'textfield',
'#title' => t('Departure'),
'#default_value' => date('d.m.Y', REQUEST_TIME + 86400), // Устанавливаем в качестве значения по умолчанию завтрашний день.
'#required' => TRUE,
'#size' => 10,
'#maxlength' => 10,
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Verify'),
);
return $form;
}
Файл mymodule.js:
(function ($) {
Drupal.behaviors.myModule = {
attach: function (context){
$('#edit-arrival', context).datepicker({
showOn: 'both', // Показываем виджет как по фокусу input'а, так и по клику на изображение календаря.
buttonImage: Drupal.settings.basePath + Drupal.settings.mymodule_path + '/images/calendar.png', // Указываем путь к изображению с календарем.
buttonImageOnly: true, // Если установлено в false, то отображается button c бэкграундом календаря, если в true, то выводится обычная картинка.
dateFormat: 'dd.mm.yy',
minDate: 0 // Устанавливаем в качестве минимальной даты сегодняшний день.
});
$('#edit-departure', context).datepicker({
showOn: 'both', // Показываем виджет как по фокусу input'а, так и по клику на изображение календаря.
buttonImage: Drupal.settings.basePath + Drupal.settings.mymodule_path + '/images/calendar.png', // Указываем путь к изображению с календарем.
buttonImageOnly: true, // Если установлено в false, то отображается button c бэкграундом календаря, если в true, то выводится обычная картинка.
dateFormat: 'dd.mm.yy',
minDate: 1 // Устанавливаем в качестве минимальной даты завтрашний день.
});
$('#edit-arrival', context).change(function() {
var strDate = $(this, context).attr('value');
var dateParts = strDate.split('.');
$('#edit-departure', context).datepicker('option', 'minDate', new Date(dateParts[2], dateParts[1] - 1, parseInt(dateParts[0]) + 1));
});
}
}
})(jQuery);
Результат
