UNPKG

gemini-datepicker

Version:
1,116 lines (1,039 loc) 99.6 kB
/** * Created by Greg Zhang */ ;(function (factory) { if (typeof define === 'function' && define.amd) { define(['jquery'], factory); } else if (typeof exports === 'object') { factory(require('jquery')); } else { factory(jQuery); } })(function ($) { 'use strict'; var dateUtils = (function () { var fecha = {}; var token = /d{1,4}|M{1,4}|yy(?:yy)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g; var twoDigits = /\d\d?/; var threeDigits = /\d{3}/; var fourDigits = /\d{4}/; var word = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i; var noop = function () { }; function shorten(arr, sLen) { var newArr = []; for (var i = 0, len = arr.length; i < len; i++) { newArr.push(arr[i].substr(0, sLen)); } return newArr; } function monthUpdate(arrName) { return function (d, v, i18n) { var index = i18n[arrName].indexOf(v.charAt(0).toUpperCase() + v.substr(1).toLowerCase()); if (~index) { d.month = index; } }; } function pad(val, len) { val = String(val); len = len || 2; while (val.length < len) { val = '0' + val; } return val; } var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; var monthNamesShort = shorten(monthNames, 3); var dayNamesShort = shorten(dayNames, 3); fecha.i18n = { dayNamesShort: dayNamesShort, dayNames: dayNames, monthNamesShort: monthNamesShort, monthNames: monthNames, amPm: ['am', 'pm'], DoFn: function DoFn(D) { return D + ['th', 'st', 'nd', 'rd'][D % 10 > 3 ? 0 : (D - D % 10 !== 10) * D % 10]; } }; var formatFlags = { D: function(dateObj) { return dateObj.getDay(); }, DD: function(dateObj) { return pad(dateObj.getDay()); }, Do: function(dateObj, i18n) { return i18n.DoFn(dateObj.getDate()); }, d: function(dateObj) { return dateObj.getDate(); }, dd: function(dateObj) { return pad(dateObj.getDate()); }, ddd: function(dateObj, i18n) { return i18n.dayNamesShort[dateObj.getDay()]; }, dddd: function(dateObj, i18n) { return i18n.dayNames[dateObj.getDay()]; }, M: function(dateObj) { return dateObj.getMonth() + 1; }, MM: function(dateObj) { return pad(dateObj.getMonth() + 1); }, MMM: function(dateObj, i18n) { return i18n.monthNamesShort[dateObj.getMonth()]; }, MMMM: function(dateObj, i18n) { return i18n.monthNames[dateObj.getMonth()]; }, yy: function(dateObj) { return String(dateObj.getFullYear()).substr(2); }, yyyy: function(dateObj) { return dateObj.getFullYear(); }, h: function(dateObj) { return dateObj.getHours() % 12 || 12; }, hh: function(dateObj) { return pad(dateObj.getHours() % 12 || 12); }, H: function(dateObj) { return dateObj.getHours(); }, HH: function(dateObj) { return pad(dateObj.getHours()); }, m: function(dateObj) { return dateObj.getMinutes(); }, mm: function(dateObj) { return pad(dateObj.getMinutes()); }, s: function(dateObj) { return dateObj.getSeconds(); }, ss: function(dateObj) { return pad(dateObj.getSeconds()); }, S: function(dateObj) { return Math.round(dateObj.getMilliseconds() / 100); }, SS: function(dateObj) { return pad(Math.round(dateObj.getMilliseconds() / 10), 2); }, SSS: function(dateObj) { return pad(dateObj.getMilliseconds(), 3); }, a: function(dateObj, i18n) { return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]; }, A: function(dateObj, i18n) { return dateObj.getHours() < 12 ? i18n.amPm[0].toUpperCase() : i18n.amPm[1].toUpperCase(); }, ZZ: function(dateObj) { var o = dateObj.getTimezoneOffset(); return (o > 0 ? '-' : '+') + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4); } }; var parseFlags = { d: [twoDigits, function (d, v) { d.day = v; }], M: [twoDigits, function (d, v) { d.month = v - 1; }], yy: [twoDigits, function (d, v) { var da = new Date(), cent = +('' + da.getFullYear()).substr(0, 2); d.year = '' + (v > 68 ? cent - 1 : cent) + v; }], h: [twoDigits, function (d, v) { d.hour = v; }], m: [twoDigits, function (d, v) { d.minute = v; }], s: [twoDigits, function (d, v) { d.second = v; }], yyyy: [fourDigits, function (d, v) { d.year = v; }], S: [/\d/, function (d, v) { d.millisecond = v * 100; }], SS: [/\d{2}/, function (d, v) { d.millisecond = v * 10; }], SSS: [threeDigits, function (d, v) { d.millisecond = v; }], D: [twoDigits, noop], ddd: [word, noop], MMM: [word, monthUpdate('monthNamesShort')], MMMM: [word, monthUpdate('monthNames')], a: [word, function (d, v, i18n) { var val = v.toLowerCase(); if (val === i18n.amPm[0]) { d.isPm = false; } else if (val === i18n.amPm[1]) { d.isPm = true; } }], ZZ: [/[\+\-]\d\d:?\d\d/, function (d, v) { var parts = (v + '').match(/([\+\-]|\d\d)/gi), minutes; if (parts) { minutes = +(parts[1] * 60) + parseInt(parts[2], 10); d.timezoneOffset = parts[0] === '+' ? minutes : -minutes; } }] }; parseFlags.DD = parseFlags.DD; parseFlags.dddd = parseFlags.ddd; parseFlags.Do = parseFlags.dd = parseFlags.d; parseFlags.mm = parseFlags.m; parseFlags.hh = parseFlags.H = parseFlags.HH = parseFlags.h; parseFlags.MM = parseFlags.M; parseFlags.ss = parseFlags.s; parseFlags.A = parseFlags.a; // Some common format strings fecha.masks = { 'default': 'ddd MMM dd yyyy HH:mm:ss', shortDate: 'M/D/yy', mediumDate: 'MMM d, yyyy', longDate: 'MMMM d, yyyy', fullDate: 'dddd, MMMM d, yyyy', shortTime: 'HH:mm', mediumTime: 'HH:mm:ss', longTime: 'HH:mm:ss.SSS' }; /*** * Format a date * @method format * @param {Date|number} dateObj * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate' */ fecha.format = function (dateObj, mask, i18nSettings) { var i18n = i18nSettings || fecha.i18n; if (typeof dateObj === 'number') { dateObj = new Date(dateObj); } if (Object.prototype.toString.call(dateObj) !== '[object Date]' || isNaN(dateObj.getTime())) { throw new Error('Invalid Date in fecha.format'); } mask = fecha.masks[mask] || mask || fecha.masks['default']; return mask.replace(token, function ($0) { return $0 in formatFlags ? formatFlags[$0](dateObj, i18n) : $0.slice(1, $0.length - 1); }); }; /** * Parse a date string into an object, changes - into / * @method parse * @param {string} dateStr Date string * @param {string} format Date parse format * @returns {Date|boolean} */ fecha.parse = function (dateStr, format, i18nSettings) { var i18n = i18nSettings || fecha.i18n; if (typeof format !== 'string') { throw new Error('Invalid format in fecha.parse'); } format = fecha.masks[format] || format; // Avoid regular expression denial of service, fail early for really long strings // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS if (dateStr.length > 1000) { return false; } var isValid = true; var dateInfo = {}; format.replace(token, function ($0) { if (parseFlags[$0]) { var info = parseFlags[$0]; var index = dateStr.search(info[0]); if (!~index) { isValid = false; } else { dateStr.replace(info[0], function (result) { info[1](dateInfo, result, i18n); dateStr = dateStr.substr(index + result.length); return result; }); } } return parseFlags[$0] ? '' : $0.slice(1, $0.length - 1); }); if (!isValid) { return false; } var today = new Date(); if (dateInfo.isPm === true && dateInfo.hour != null && +dateInfo.hour !== 12) { dateInfo.hour = +dateInfo.hour + 12; } else if (dateInfo.isPm === false && +dateInfo.hour === 12) { dateInfo.hour = 0; } var date; if (dateInfo.timezoneOffset != null) { dateInfo.minute = +(dateInfo.minute || 0) - +dateInfo.timezoneOffset; date = new Date(Date.UTC(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1, dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0)); } else { date = new Date(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1, dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0); } return date; }; return fecha; })(); // Const DAY_DURATION var DAY_DURATION = 86400000; // Const DEFAULT_TIME_FORMAT var DEFAULT_TIME_FORMAT = 'HH:mm:ss'; // Const DEFAULT_TIME_VALUE var DEFAULT_TIME_VALUE = '00:00:00'; // Const DATE_PANEL_Z_INDEX var DATE_PANEL_Z_INDEX = 2008; // Const TIME_PANEL_Z_INDEX var TIME_PANEL_Z_INDEX = DATE_PANEL_Z_INDEX + 1; // Const TIME_PANEL_WIDTH var TIME_PANEL_WIDTH = 154; // Const KEY_CODE_ENTER var KEY_CODE_ENTER = 13; // Const CLASS_PLACEMENT_LEFT_BOTTOM var CLASS_PLACEMENT_LEFT_BOTTOM = 'placement-left-bottom'; // Const CLASS_PLACEMENT_CENTER_BOTTOM var CLASS_PLACEMENT_CENTER_BOTTOM = 'placement-center-bottom'; // Const CLASS_PLACEMENT_RIGHT_BOTTOM var CLASS_PLACEMENT_RIGHT_BOTTOM = 'placement-right-bottom'; // Const IE_MODE var inBrowser = typeof window !== 'undefined'; var UA = inBrowser && window.navigator.userAgent.toLowerCase(); var isIE = UA && /msie|trident/.test(UA); var IE_MODE = document.documentMode; var DatePicker = function ($el, options) { var datepicker = this; var core = { defaults: { readonly: false, disabled: false, type: 'date', // year/month/date/date-range/datetime/datetime-range format: 'yyyy-MM-dd', placeholder: 'Please pick a day', align: 'left', startDate: null, endDate: null, lang: 'en-US', rangeSeparator: '-', weekStart: 0, defaultValue: '', zIndex: DATE_PANEL_Z_INDEX, onChange: null, onShow: null, onHide: null }, _init: function () { // copy property from options datepicker = $.extend(true, datepicker, core.defaults, options || {}); if (datepicker.lang) datepicker = $.extend(datepicker, $.fn.datepicker.lang[datepicker.lang]); var type = datepicker.type; if ((type === 'datetime' || type === 'datetime-range') && datepicker.format === core.defaults.format) { datepicker.format = 'yyyy-MM-dd HH:mm:ss'; } else if (type === 'year') { datepicker.format = 'yyyy'; } else if (type === 'month' && datepicker.format === core.defaults.format) { datepicker.format = 'yyyy-MM'; } // init param date and value datepicker.date = new Date(); datepicker.value = ''; datepicker.yearLabel = datepicker.date.getFullYear(); datepicker.monthLabel = datepicker.date.getMonth(); if (datepicker.readonly) $el.attr('readonly', true); if (datepicker.disabled) $el.attr('disabled', true); if (datepicker.placeholder) $el.attr('placeholder', datepicker.placeholder); core._created(); }, _created: function () { var type = datepicker.type; var align = datepicker.align; var zIndex = datepicker.zIndex; var originX = align === 'center' ? '50%' : align === 'right' ? '100%' : '0'; var $body = $('body'); var dateDom; if (type === 'date' || type === 'month' || type === 'year' || type === 'datetime') { if (type === 'date' || type === 'datetime') { datepicker.currentView = 'dateView'; } else if (type === 'year') { datepicker.currentView = 'yearView'; } else if (type === 'month') { datepicker.currentView = 'monthView'; } // get datepicker panel dateDom = core._generateDateDOM(); } else if (type === 'date-range' || type === 'datetime-range') { // get range datepicker panel dateDom = core._generateRangeDateDOM(); } // append picker panel into the dom tree datepicker.$pickerPanel = $(dateDom).appendTo($body).css({ position: 'absolute', zIndex: parseInt(zIndex, 10) }); if (!isIE || (isIE && IE_MODE > 9)) { datepicker.$pickerPanel.css({transformOrigin: originX + ' 0', msTransformOrigin: originX + ' 0'}); } // set position for time panel if (datepicker.$pickerPanel.find('.gmi-time-panel').length > 0) { var $timePanel = datepicker.$pickerPanel.find('.gmi-time-panel'); $timePanel.css({ width: TIME_PANEL_WIDTH + 'px', position: 'absolute', left: 0, zIndex: TIME_PANEL_Z_INDEX }); datepicker.$timePanel = $timePanel; } // bind EVENT_PICK for $el if ($.isFunction(datepicker.onChange)) { $el.on('pick.datepicker', datepicker.onChange); } // set default date core._setDate(datepicker.defaultValue); // set table show or hide for date, datetime, year, month switch (type) { case 'date': datepicker.$pickerPanel.find('.gmi-date-table').show().siblings().hide(); break; case 'datetime': datepicker.$pickerPanel.find('.gmi-date-table').show().siblings().hide(); break; case 'year': datepicker.$pickerPanel.find('.gmi-year-table').show().siblings().hide(); break; case 'month': datepicker.$pickerPanel.find('.gmi-month-table').show().siblings().hide(); break; } // push date or time value into the input elements core._echoDateOrTimeIntoInput(); // bind events for datepicker core._bindEvent(); }, _unCreate: function () { var $pickPanel = datepicker.$pickerPanel; if ($pickPanel && $pickPanel.length > 0) $pickPanel.remove(); }, _bindEvent: function () { $(document).on('click.datepicker', function (e) { var $target = $(e.target); if (!$target.is($el) && $el.has($target).length <= 0) { core._hidePickerPanel(); } }); // when window resizing or scrolling that the panel will change its position $(window).on('resize.datepicker', function () { core._setDatePanelPosition(); }).on('scroll.datepicker', function () { core._setDatePanelPosition(); }); // bind events for $el $el.on('focus.datepicker', core._elFocusHandler) .on('click.datepicker', core._elClickHandler) .on('change.datepicker', core._elChangeHandler) .on('keyup.datepicker', core._elKeyUpHandler); if ($.isFunction(datepicker.onShow)) { $el.on('show.datepicker', datepicker.onShow); } if ($.isFunction(datepicker.onHide)) { $el.on('show.datepicker', datepicker.onHide); } // cancel bubble for $pickerPanel datepicker.$pickerPanel.on('click.datepicker', function (e) { e.stopPropagation(); }); // bind events for time input datepicker.$pickerPanel.on('focus.datepicker', '.gmi-time-picker--input', function (e) { var $self = $(this); core._setTimeView($self, e); }).on('keyup.datepicker', '.gmi-time-picker--input', function (e) { var $self = $(this); core._setTimeView($self, e); }).on('change.datepicker', '.gmi-time-picker--input', function (e) { var $self = $(this); core._setTimeView($self, e); }); if (datepicker.$timePanel && datepicker.$timePanel.length > 0) { datepicker.$timePanel.on('mouseenter.datepicker', '.gmi-time-panel__body__item', function (e) { // mouseenter var $self = $(this); var $spinner = $self.find('> ul.gmi-time-panel__body__item--spinner'); $self.css('overflow', 'auto'); $spinner.css('width', '100%'); }).on('mouseleave.datepicker', '.gmi-time-panel__body__item', function (e) { // mouseleave var $self = $(this); var $spinner = $self.find('> ul.gmi-time-panel__body__item--spinner'); var selfWidth = $self.outerWidth(); $self.css('overflow', 'hidden'); $spinner.css('width', selfWidth + 'px'); }); datepicker.$timePanel.on('click.datepicker', '.gmi-time-panel__body__item--spinner__item:not(.disabled)', function (e) { var $timeItem = $(this); var $timeItemWrapper = $timeItem.parents('.gmi-time-panel__body__item').eq(0); var role = $timeItem.parents('.gmi-time-panel__body__item--spinner').data('role'); var num = Number($timeItem.text()); var itemHeight = $timeItem.outerHeight(); var scrollTop = num * itemHeight; $timeItem.addClass('active').siblings().removeClass('active'); $timeItemWrapper.scrollTop(scrollTop); e.stopPropagation(); }); // timer panel button events datepicker.$timePanel.on('click.datepicker', '.gmi-time-panel__btn', function (e) { var $self = $(this); var role = $self.data('role'); var tempDate = new Date(); var $delegateTarget = $(e.delegateTarget); var $timeInput = $delegateTarget.siblings('.gmi-time-picker--input'); var $hourSpinner = $delegateTarget.find('.gmi-time-panel__body__item--spinner[data-role="hour"]'); var $minSpinner = $delegateTarget.find('.gmi-time-panel__body__item--spinner[data-role="min"]'); var $secSpinner = $delegateTarget.find('.gmi-time-panel__body__item--spinner[data-role="sec"]'); var hour = Number($hourSpinner.find('> li.active').text()); var minutes = Number($minSpinner.find('> li.active').text()); var seconds = Number($secSpinner.find('> li.active').text()); tempDate.setHours(hour, minutes, seconds, 0); switch (role) { case 'confirm': $timeInput.val($.formatDate(tempDate, DEFAULT_TIME_FORMAT)); $delegateTarget.hide(); var $allTimeInput = datepicker.$pickerPanel.find('.gmi-time-picker--input').filter(function () { return $(this).val() === '' || !$.parseDate($(this).val(), DEFAULT_TIME_FORMAT); }); if ($allTimeInput && $allTimeInput.length === 0) datepicker.$pickerPanel.find('.gmi-picker-panel__link-btn--determine').removeClass('disabled'); break; case 'cancel': $delegateTarget.hide(); break; default: break; } }); } // bind event for td datepicker.$pickerPanel.on('click.datepicker', 'td:not(.disabled)', function (e) { var type = datepicker.type; var format = datepicker.format; var $delegateTarget = $(e.delegateTarget); var $determineButton = $delegateTarget.find('.gmi-picker-panel__link-btn--determine'); var $timeInput; var $td = $(this); var elValue; e.stopPropagation(); if (type === 'date' || type === 'datetime') { var currentView = datepicker.currentView; var year; var month; if (currentView === 'dateView') { // dateView var date = $td.text() === datepicker.todaySuffix ? new Date().getDate() : Number($td.text()); if ($td.hasClass('prev-month') || $td.hasClass('next-month')) { if ($td.hasClass('prev-month')) { year = datepicker.monthLabel - 1 < 0 ? datepicker.yearLabel - 1 : datepicker.yearLabel; month = datepicker.monthLabel - 1 < 0 ? 11 : datepicker.monthLabel - 1; } else if ($td.hasClass('next-month')) { year = datepicker.monthLabel + 1 > 11 ? datepicker.yearLabel + 1 : datepicker.yearLabel; month = datepicker.monthLabel + 1 > 11 ? 0 : datepicker.monthLabel + 1; } if (type === 'date') { elValue = $.formatDate(new Date(year, month, date), format); core._setDate(elValue); } else { elValue = $.formatDate(new Date(year, month, date)); core._setNewDateDOM($delegateTarget, year, month, date); $delegateTarget.find('.gmi-date-table td').removeClass('current').filter(function () { return Number($(this).data('year')) === year && Number($(this).data('month')) === month && Number($(this).text()) === date; }).addClass('current'); datepicker.yearLabel = year; datepicker.monthLabel = month; } } else { year = datepicker.yearLabel; month = datepicker.monthLabel; if (type === 'date') { elValue = $.formatDate(new Date(year, month, date), format); core._setDate(elValue); } else { elValue = $.formatDate(new Date(year, month, date)); $delegateTarget.find('.gmi-date-table').find('td').removeClass('current'); $td.addClass('current'); } } if (type === 'datetime') { $delegateTarget.find('.gmi-date-picker--input').val(elValue); $timeInput = $delegateTarget.find('.gmi-time-picker--input'); if ($timeInput.val() === '' || !$.parseDate($timeInput.val(), DEFAULT_TIME_FORMAT)) { $timeInput.val(DEFAULT_TIME_VALUE); } $determineButton.removeClass('disabled'); return false; } core._hidePickerPanel(); } else if (currentView === 'yearView') { // yearView core._setYearView($td); } else { // monthView core._setMonthView($td); } } else if (type === 'month') { switch (datepicker.currentView) { case 'monthView': core._setMonthView($td); break; case 'yearView': core._setYearView($td); break; default: break; } } else if (type === 'year') { core._setYearView($td); } else if (type === 'date-range' || type === 'datetime-range') { var minDate = datepicker.minDate; var maxDate = datepicker.maxDate; var $startDateInput = $delegateTarget.find('.gmi-date-picker--input[data-role="range-start"]'); var $startTimeInput = $delegateTarget.find('.gmi-time-picker--input[data-role="range-start"]'); var $endDateInput = $delegateTarget.find('.gmi-date-picker--input[data-role="range-end"]'); var $endTimeInput = $delegateTarget.find('.gmi-time-picker--input[data-role="range-end"]'); var value; year = Number($td.data('year')); month = Number($td.data('month')); date = $td.text() === datepicker.todaySuffix ? new Date().getDate() : Number($td.text()); if (minDate && maxDate) { datepicker.minDate = new Date(year, month, date); datepicker.maxDate = null; $delegateTarget.find('.gmi-date-table td').removeClass('start-date in-range end-date'); if (!$td.hasClass('prev-month') && !$td.hasClass('next-month')) $td.addClass('start-date in-range'); if (type === 'datetime-range') { $startDateInput.val($.formatDate(datepicker.minDate)); $determineButton.addClass('disabled'); } } else if (minDate && !maxDate) { if (new Date(year, month, date).getTime() < minDate.getTime()) { datepicker.minDate = new Date(year, month, date); $delegateTarget.find('.gmi-date-table td').removeClass('start-date in-range'); if (!$td.hasClass('prev-month') && !$td.hasClass('next-month')) $td.addClass('start-date in-range'); if (type === 'datetime-range') { $startDateInput.val($.formatDate(datepicker.minDate)); $determineButton.addClass('disabled'); } } else { datepicker.maxDate = new Date(year, month, date); if (!$td.hasClass('prev-month') && !$td.hasClass('next-month')) $td.addClass('end-date in-range'); $delegateTarget.find('.gmi-date-table td').filter(function () { var $self = $(this); var selfYear = Number($self.data('year')); var selfMonth = Number($self.data('month')); var selfDate = $self.text() === datepicker.todaySuffix ? new Date().getDate() : Number($self.text()); var rangeDate = new Date(selfYear, selfMonth, selfDate); return !$self.hasClass('prev-month') && !$self.hasClass('next-month') && (rangeDate > datepicker.minDate.getTime()) && (rangeDate.getTime() < datepicker.maxDate.getTime()); }).addClass('in-range'); if (type === 'date-range') { value = $.formatDate(datepicker.minDate, format) + ' '+ datepicker.rangeSeparator +' ' + $.formatDate(datepicker.maxDate, format); core._setDate(value); core._hidePickerPanel(); } else { $endDateInput.val($.formatDate(datepicker.maxDate)); if ($startTimeInput.val() === '') $startTimeInput.val(DEFAULT_TIME_VALUE); if ($endTimeInput.val() === '') $endTimeInput.val(DEFAULT_TIME_VALUE); $determineButton.removeClass('disabled'); } } } else if (!minDate) { datepicker.minDate = new Date(year, month, date); if (!$td.hasClass('prev-month') && !$td.hasClass('next-month')) $td.addClass('start-date in-range'); if (type === 'datetime-range') { $startDateInput.val($.formatDate(datepicker.minDate)); $determineButton.addClass('disabled'); } } } }); // bind event for month label datepicker.$pickerPanel.on('click.datepicker', '.gmi-date-picker__header__label--month', function (e) { var $monthLabel = $(this); var $yearLabel = $monthLabel.siblings('.gmi-date-picker__header__label--year'); var $delegateTarget = $(e.delegateTarget); var $monthTable = $delegateTarget.find('.gmi-month-table'); var year = datepicker.yearLabel; var month = datepicker.monthLabel; // add current class for month table td if (!$monthTable.find('td').removeClass('current').eq(Number(month)).hasClass('disabled')) { $monthTable.find('td').removeClass('current').eq(Number(month)).addClass('current'); } // change year label text $yearLabel.text(year + ' '+ datepicker.yearSuffix +''); // hide month label $monthLabel.hide(); // show month table core._setNewMonthDOM($delegateTarget, month); // reset picker current view, current view is month view datepicker.currentView = 'monthView'; e.stopPropagation(); }); // bind event for year label datepicker.$pickerPanel.on('click.datepicker', '.gmi-date-picker__header__label--year', function (e) { if (datepicker.currentView === 'yearView') { return false; } var $yearLabel = $(this); var $monthLabel = $yearLabel.siblings('.gmi-date-picker__header__label--month'); var $delegateTarget = $(e.delegateTarget); var year = datepicker.yearLabel; // generate new year dom core._setNewYearDOM($delegateTarget, year, $yearLabel); // hide month label $monthLabel.hide(); // show year table datepicker.currentView = 'yearView'; e.stopPropagation(); }); // bind events for arrow-down and arrow-up datepicker.$pickerPanel.on('click.datepicker', '.gmi-date-picker__header__icon-btn', function (e) { var $delegateTarget = $(e.delegateTarget); var $button = $(this); var action = $button.data('action'); var currentView = datepicker.currentView; switch (action) { case 'prev': core._setPrevButtonAction($delegateTarget, currentView); break; case 'next': core._setNextButtonAction($delegateTarget, currentView); break; default: break; } e.stopPropagation(); }); // bind event for link button datepicker.$pickerPanel.on('click.datepicker', '.gmi-picker-panel__link-btn:not(.gmi-time-panel__btn)', function (e) { var $linkButton = $(this); var $delegateTarget = $(e.delegateTarget); var role = $linkButton.data('role'); var type = datepicker.type; var dateValue; var timeValue; var date; var time; var minDateValue; var minTimeValue; var minDate; var minTime; var minValue; var maxDateValue; var maxTimeValue; var maxDate; var maxTime; var maxValue; var value; switch (role) { case 'determine': if ($linkButton.hasClass('disabled')) { return false; } if (type === 'datetime') { dateValue = $delegateTarget.find('.gmi-date-picker--input').val(); timeValue = $delegateTarget.find('.gmi-time-picker--input').val(); date = $.parseDate(dateValue); time = $.parseDate(timeValue, DEFAULT_TIME_FORMAT); date.setHours(time.getHours(), time.getMinutes(), time.getSeconds(), 0); value = $.formatDate(date, datepicker.format); } else if (type === 'datetime-range') { minDateValue = $delegateTarget.find('.gmi-date-picker--input[data-role="range-start"]').val(); minTimeValue = $delegateTarget.find('.gmi-time-picker--input[data-role="range-start"]').val(); minDate = $.parseDate(minDateValue); minTime = $.parseDate(minTimeValue !== '' ? minTimeValue : DEFAULT_TIME_VALUE, DEFAULT_TIME_FORMAT); minDate.setHours(minTime.getHours(), minTime.getMinutes(), minTime.getSeconds(), 0); minValue = $.formatDate(minDate, datepicker.format); maxDateValue = $delegateTarget.find('.gmi-date-picker--input[data-role="range-end"]').val(); maxTimeValue = $delegateTarget.find('.gmi-time-picker--input[data-role="range-end"]').val(); maxDate = $.parseDate(maxDateValue); maxTime = $.parseDate(maxTimeValue !== '' ? maxTimeValue : DEFAULT_TIME_VALUE, DEFAULT_TIME_FORMAT); maxDate.setHours(maxTime.getHours(), maxTime.getMinutes(), maxTime.getSeconds(), 0); maxValue = $.formatDate(maxDate, datepicker.format); value = minValue + ' '+ datepicker.rangeSeparator +' ' + maxValue; } core._setDate(value); core._hidePickerPanel(); break; case 'now': value = $.formatDate(new Date(), datepicker.format); core._setDate(value); core._hidePickerPanel(); break; case 'clear': core._clear(); break; default: break; } e.stopPropagation(); }); // bind events for range date button datepicker.$pickerPanel.on('click.datepicker', '.gmi-date-range-picker__header__icon-btn', function (e) { var $delegateTarget = $(e.delegateTarget); var $button = $(this); var action = $button.data('action'); core._setRangeDateView($delegateTarget, action); e.stopPropagation(); }); datepicker.$pickerPanel.on('mouseenter.datepicker', 'td:not(.disabled)', function (e) { if (datepicker.type !== 'date-range' && datepicker.type !== 'datetime-range') { return false; } var $delegateTarget = $(e.delegateTarget); var $td = $(this); var year = Number($td.data('year')); var month = Number($td.data('month')); var date = $td.text() === datepicker.todaySuffix ? new Date().getDate() : Number($td.text()); var currentDate = new Date(year, month, date); var minDate = datepicker.minDate; var maxDate = datepicker.maxDate; if (minDate && !maxDate) { datepicker.$minDateTarget = $delegateTarget.find('.gmi-date-table td').filter(function () { return !$(this).hasClass('prev-month') && !$(this).hasClass('next-month') && Number($(this).data('year')) === minDate.getFullYear() && Number($(this).data('month')) === minDate.getMonth() && ($(this).text() === datepicker.todaySuffix ? new Date().getDate() : Number($(this).text())) === minDate.getDate(); }); if (!datepicker.$minDateTarget.hasClass('start-date')) { datepicker.$minDateTarget.addClass('in-range start-date'); } if (currentDate.getTime() >= minDate.getTime()) { $delegateTarget.find('.gmi-date-table td').filter(function () { var inRangeYear = Number($(this).data('year')); var inRangeMonth = Number($(this).data('month')); var inRangeDate = $(this).text() === datepicker.todaySuffix ? new Date().getDate() : Number($(this).text()); return !$(this).hasClass('prev-month') && !$(this).hasClass('next-month') && new Date(inRangeYear, inRangeMonth, inRangeDate).getTime() > minDate.getTime() && new Date(inRangeYear, inRangeMonth, inRangeDate).getTime() < new Date(year, month, date).getTime(); }).addClass('in-range'); if (!$td.hasClass('prev-month') && !$td.hasClass('next-month')) { $td.addClass('in-range end-date'); } else { $delegateTarget.find('.gmi-date-table td').filter(function () { var endDateYear = Number($(this).data('year')); var endDateMonth = Number($(this).data('month')); var endDateDate = $(this).text() === datepicker.todaySuffix ? new Date().getDate() : Number($(this).text()); return !$(this).hasClass('prev-month') && !$(this).hasClass('next-month') && endDateYear === year && endDateMonth === month && endDateDate === date; }).addClass('in-range end-date'); } } } e.stopPropagation(); }).on('mouseleave.datepicker', 'td:not(.disabled)', function (e) { if (datepicker.type !== 'date-range' && datepicker.type !== 'datetime-range') { return false; } var $delegateTarget = $(e.delegateTarget); var $td = $(this); var year = Number($td.data('year')); var month = Number($td.data('month')); var date = $td.text() === datepicker.todaySuffix ? new Date().getDate() : Number($td.text()); var minDate = datepicker.minDate; var maxDate = datepicker.maxDate; if (minDate && !maxDate) { $delegateTarget.find('.gmi-date-table td').filter(function () { return !$(this).hasClass('start-date') && !$(this).hasClass('end-date'); }).removeClass('in-range'); if (!$td.hasClass('prev-month') && !$td.hasClass('next-month')) { $td.removeClass('in-range end-date'); } else { $delegateTarget.find('.gmi-date-table td').filter(function () { var endDateYear = Number($(this).data('year')); var endDateMonth = Number($(this).data('month')); var endDateDate = $(this).text() === datepicker.todaySuffix ? new Date().getDate() : Number($(this).text()); return !$(this).hasClass('prev-month') && !$(this).hasClass('next-month') && endDateYear === year && endDateMonth === month && endDateDate === date; }).removeClass('in-range end-date'); } } e.stopPropagation(); }); }, _unBindEvent: function () { $el.off('focus.datepicker', core._elFocusHandler); $el.off('click.datepicker', core._elClickHandler); $el.off('change.datepicker', core._elChangeHandler); $el.off('keyup.datepicker', core._elKeyUpHandler); $el.off('pick.datepicker', datepicker.onChange); $el.off('show.datepicker', datepicker.onShow); $el.off('hide.datepicker', datepicker.onHide); }, _generateDateDOM: function () { var type = datepicker.type; var hasTimeClass = type === 'datetime' ? 'has-time' : ''; var datetimeHeaderStr = type === 'datetime' ? core._generateDatetimeHeader() : ''; var datetimeFooterStr = type === 'datetime' ? core._generateDatetimeFooter(type) : ''; var startYear = Math.floor(datepicker.date.getFullYear() / 10) * 10; var endYear = Math.floor(datepicker.date.getFullYear() / 10) * 10 + 9; var yearLabel = type === 'date' || type === 'month' || type === 'datetime' ? datepicker.date.getFullYear() + ' '+ datepicker.yearSuffix +'' : startYear + ' '+ datepicker.yearSuffix +'' + ' - ' + endYear + ' '+ datepicker.yearSuffix +''; var monthLabel = datepicker.monthsShort[datepicker.date.getMonth()]; var monthDom = type === 'date' || type === 'datetime' ? '<span class="gmi-date-picker__header__label--month">'+ monthLabel +'</span>' : ''; var dateDomStr = '<div data-role="'+ type +'" class="gmi-picker-panel gmi-date-picker '+ hasTimeClass +'" style="display: none;">' + '<div class="gmi-picker-panel__body">' + datetimeHeaderStr + '<div class="gmi-picker-panel__body__header">' + '<span class="gmi-date-picker__header__label--year">'+ yearLabel +'</span>' + monthDom + '<em data-action="next" class="gmi-date-picker__header__icon-btn gmi-picker-panel__btn--next"></em>' + '<em data-action="prev" class="gmi-date-picker__header__icon-btn gmi-picker-panel__btn--prev"></em>' + '</div>' + '<div class="gmi-picker-panel__body__main">' + core._getDateTable(datepicker.date) + '' + core._getYearTable(datepicker.date.getFullYear()) + '' + core._getMonthTable(datepicker.date.getMonth()) + '</div>' + '</div>' + datetimeFooterStr + '</div>'; return dateDomStr; }, _generateRangeDateDOM: function () { var date = datepicker.date; var firstDate = datepicker.minDate ? datepicker.minDate : date; var nextDate = datepicker.minDate ? $.getNextMonth(datepicker.minDate) : $.getNextMonth(date); var type = datepicker.type; var hasTimeClass = type === 'datetime-range' ? 'has-time' : ''; var rangeDatetimeHeaderStr = type === 'datetime-range' ? core._generateRangeDatetimeHeader() : ''; var rangeDatetimeFooterStr = type === 'datetime-range' ? core._generateDatetimeFooter(type) : ''; var rangeDateDomStr = '<div data-role="'+ type +'" class="gmi-picker-panel gmi-date-range-picker '+ hasTimeClass +'" style="display: none;">' + rangeDatetimeHeaderStr + '<div class="gmi-picker-panel__body gmi-date-range-picker__body">' + '<div class="gmi-picker-panel__body__main f-lt">' + '<div class="gmi-date-range-picker__body__header">' + '<p>'+ firstDate.getFullYear() +' '+ datepicker.yearSuffix +' '+ datepicker.monthsShort[firstDate.getMonth()] +'</p>' + '<em data-action="prev-year" class="gmi-date-range-picker__header__icon-btn gmi-date-range-picker__btn--prev gmi-date-range-picker__btn--prev-year"></em>' + '<em data-action="prev-month" class="gmi-date-range-picker__header__icon-btn gmi-date-range-picker__btn--prev gmi-date-range-picker__btn--prev-month"></em>' + '</div>' + core._getDateTable(firstDate) + '</div>' + '<div class="gmi-picker-panel__body__main f-rt">' + '<div class="gmi-date-range-picker__body__header">' + '<p>'+ nextDate.getFullYear() +' '+ datepicker.yearSuffix +' '+ datepicker.monthsShort[nextDate.getMonth()] +'</p>' + '<em data-action="next-year" class="gmi-date-range-picker__header__icon-btn gmi-date-range-picker__btn--next gmi-date-range-picker__btn--next-year"></em>' + '<em data-action="next-month" class="gmi-date-range-picker__header__icon-btn gmi-date-range-picker__btn--next gmi-date-range-picker__btn--next-month"></em>' + '</div>' + core._getDateTable(nextDate) + '</div>' + '</div>' + rangeDatetimeFooterStr + '</div>'; return rangeDateDomStr; }, _generateDatetimeHeader: function () { var datetimeHeaderStr = '<ul class="gmi-picker-panel__body__header--time">' + '<li class="gmi-picker-panel__body__header--time__wrapper">' + '<div class="gmi-input">' + '<input data-role="date" type="text" readonly class="gmi-input__inner gmi-date-picker--input" placeholder="'+ datepicker.dateInputPlaceholder +'">' + '</div>' + '</li>' + '<li class="gmi-picker-panel__body__header--time__wrapper">' + '<div data-role="date" class="gmi-input gmi-time-picker--wrapper">' + '<input data-role="date" type="text" class="gmi-input__inner gmi-time-picker--input" placeholder="'+ datepicker.dateTimeInputPlaceholder +'">' + core._generateTimePickerDOM('date') + '</div>' + '</li>' + '</ul>'; return datetimeHeaderStr; }, _generateRangeDatetimeHeader: function () { var rangeDatetimeHeaderStr = '<ul class="gmi-picker-panel__body__header--time">' + '<li class="gmi-picker-panel__body__header--time__wrapper gmi-date-range-picker__header--time__wrapper">' + '<div class="gmi-input">' + '<input data-role="range-start" type="text" readonly class="gmi-input__inner gmi-date-picker--input" placeholder="'+ datepicker.rangeStartInputPlaceholder +'">' + '</div>' + '<div data-role="range-start" class="gmi-input gmi-time-picker--wrapper">' + '<input data-role="range-start" type="text" class="gmi-input__inner gmi-time-picker--input" placeholder="'+ datepicker.rangeStartTimeInputPlaceholder +'">' + core._generateTimePickerDOM('range-start') + '</div>' + '</li>' + '<li class="gmi-picker-panel__body__header--time__wrapper gmi-date-range-picker__header--time__wrapper">' + '<div class="gmi-input">' + '<input data-role="range-end" type="text" readonly class="gmi-input__inner gmi-date-picker--input" placeholder="'+ datepicker.rangeEndPlaceholder +'">' + '</div>' + '<div data-role="range-end" class="gmi-input gmi-time-picker--wrapper">' + '<input data-role="range-end" type="text" class="gmi-input__inner gmi-time-picker--input" placeholder="'+ datepicker.rangeEndTimeInputPlaceholder +'">' + core._generateTimePickerDOM('range-end') + '</div>' + '</li>' + '</ul>'; return rangeDatetimeHeaderStr; }, _generateDatetimeFooter: function (type) { var buttonText = type === 'datetime-range' ? datepicker.clearButton : datepicker.nowDateButton; var buttonClass = type === 'datetime-range' ? 'gmi-picker-panel__link-btn--clear' : 'gmi-picker-panel__link-btn--now'; var buttonRole = type === 'datetime-range' ? 'clear' : 'now'; var disabledClass = type === 'datetime-range' && datepicker.minDate && datepicker.maxDate ? '' : type === 'datetime' ? '' : 'disabled'; var datetimeFooterStr = '<div class="gmi-picker-panel__footer">' + '<a href="JavaScript:" data-role="'+ buttonRole +'" class="gmi-picker-panel__link-btn '+ buttonClass +'">'+ buttonText +'</a>' + '<a href="JavaScript:" data-role="determine" class="gmi-picker-panel__link-btn gmi-picker-panel__link-btn--determine '+ disabledClass +'">'+ datepicker.confirmDateButton +'</a>' + '</div>'; return datetimeFooterStr; }, _generateTimePickerDOM: function (role) { var timePickerStr = '<div data-role="'+ role +'" class="gmi-time-panel gmi-time-picker" style="display: none;">' + '<div class="gmi-time-panel__body">' + '<div class="gmi-time-panel__body__item">' + core._getTimeSpinner('hour') + '</div>' + '<div class="gmi-time-panel__body__item">' + core._getTimeSpinner('min') + '</div>' + '<div class="gmi-time-panel__body__item">' + core._getTimeSpinner('sec') + '</div>' + '</div>' + '<div class="gmi-picker-panel__footer gmi-time-panel__footer">' + '<a href="JavaScript:" data-role="cancel" class="gmi-picker-panel__link-btn gmi-time-panel__btn gmi-picker-panel__link-btn--default">'+ datepicker.cancelTimeButton +'</a>' + '<a href="JavaScript:" data-role="confirm" class="gmi-picker-panel__link-btn gmi-time-panel__btn gmi-picker-panel__link-btn--primary">'+ datepicker.confirmDateButton +'</a>' + '</div>' + '</div>'; return timePickerStr; }, _getDateRows: function (nowDate) { var tableRows = [ [], [], [], [], [], [] ]; var year = nowDate.getFullYear(); var month = nowDate.getMonth(); var date = new Date(year, month, 1); var day = $.getFirstDayOfMonth(date);// day of first day var dateCountOfMonth = $.getTotalDayCountOfMonth(date.getFullYear(), date.getMonth()); var dateCountOfLastMonth = $.getTotalDayCountOfMonth(date.getFullYear(), (date.getMonth() === 0 ? 11 : date.getMonth() - 1)); day = (day === 0) ? 7 : day; var offset = -1 * datepicker.weekStart; var rows = tableRows; var count = 1; var firstDayPosition; var startDate = $.getStartDateOfMonth(year, month); var now = $.clearHours(new Date()); // get now time for (var i = 0; i < 6; i++) { var row = rows[i]; for (var j = 0; j < 7; j++) { var cell = row[j]; if (!cell) { cell = { row: i, column: j, type: 'normal', year: date.getFullYear(), month: date.getMonth(), inRange: false, start: false, end: false}; // init cell } cell.type = 'normal'; var index = i * 7 + j; var time = startDate.getTime() + DAY_DURATION * (index - offset); cell.inRange = time >= $.clearHours(datepicker.minDate) && time <= $.clearHours(datepicker.maxDate); cell.start = datepicker.minDate && time === $.clearHours(datepicker.minDate); cell.end = datepicker.maxDate && time === $.clearHours(datepicker.maxDate); cell.disabled = fal