jQuery UI Datepicker: добавляем нестандартные элементы навигации по годам

в 14:02, , рубрики: datepicker, javascript, jquery, Веб-разработка, метки: , ,

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

image

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

Решение

После достаточно долгого поиска решения этой на первый взгляд простой задачи стало понятно, что у этого datepicker'а нет опций/методов для реализации заказанного «в 2 клика». Поиск приводил меня к способам добавления дополнительных кнопок на «button panel», изменения шага (количества месяцев) существующих элементов навигации. Но это было не то. Нужно было добавить именно в header календаря, рядом с элементами навигации по месяцам ещё две кнопки.

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

<a class="ui-datepicker-prev ui-corner-all" title="Prev" onclick="DP_jQuery_1345539902544.datepicker._adjustDate('#tbLoungeDate', -1, 'M');">

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

._adjustDate('#tbLoungeDate', -1, 'Y');

Да, действительно, это работает. Теперь осталась последняя проблема. Как добавить кнопки в header календаря. Ведь он перестраивается каждый раз, когда появляется и когда изменяется месяц/год. Один раз, где-то в скрипте добавить дочерний элемент в DIV с классом «ui-datepicker-header» не помогает. Это нужно делать каждый раз при появлении и изменении месяца/года. А именно вот так:

var addPrevNextYearButtons = function (input) {
    setTimeout(function () {
        var btnPrev = $("<a title='Prev year'><span>prev year</span></a>");
        btnPrev.addClass("ui-datepicker-prev-year ui-corner-all");
        btnPrev.click(function () {
            $.datepicker._adjustDate(input, -1, 'Y');
        });

        var btnNext = $("<a title='Next year'><span>next year</span></a>");
        btnNext.addClass("ui-datepicker-prev-year ui-corner-all");
        btnNext.click(function () {
            $.datepicker._adjustDate(input, 1, 'Y');
        });

        var datepickerHeader = $(input).datepicker("widget").find('.ui-datepicker-header');
        datepickerHeader.append(btnPrev);
        datepickerHeader.append(btnNext);
    }, 1);
};

$('#tbLoungeDate').datepicker({
    beforeShow: function (input, inst) {
        addPrevNextYearButtons(input);
    },
    onChangeMonthYear: function (year, month, inst) {
        addPrevNextYearButtons(inst.input[0]);
    }
});

Таймаут необходим, так как события происходят до того как построены внутренности календаря. Создаём элементы навигации, назначаем вышеупомянутый метод для перехода на предыдущий/следующий год в событие «click» и добавляем их в header календаря. Далее остаётся только добавить стиль, чтобы они выглядели как на изображении заказчика.

Вот и всё. Спасибо за внимание. Готов выслушать любые замечания и ответить на любые вопросы.

Автор: brainx64

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js