Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;(function (window, $, undefined) { ;(function () {
- var VERSION = '2.2.3',
- pluginName = 'datepicker',
- autoInitSelector = '.datepicker-here',
- $body, $datepickersContainer,
- containerBuilt = false,
- baseTemplate = '' +
- '<div class="datepicker">' +
- '<i class="datepicker--pointer"></i>' +
- '<nav class="datepicker--nav"></nav>' +
- '<div class="datepicker--content"></div>' +
- '</div>',
- defaults = {
- classes: '',
- inline: false,
- language: 'ru',
- startDate: new Date(),
- firstDay: '',
- weekends: [6, 0],
- dateFormat: '',
- altField: '',
- altFieldDateFormat: '@',
- toggleSelected: true,
- keyboardNav: true,
- position: 'bottom left',
- offset: 12,
- view: 'days',
- minView: 'days',
- showOtherMonths: true,
- selectOtherMonths: true,
- moveToOtherMonthsOnSelect: true,
- showOtherYears: true,
- selectOtherYears: true,
- moveToOtherYearsOnSelect: true,
- minDate: '',
- maxDate: '',
- disableNavWhenOutOfRange: true,
- multipleDates: false, // Boolean or Number
- multipleDatesSeparator: ',',
- range: false,
- todayButton: false,
- clearButton: false,
- showEvent: 'focus',
- autoClose: false,
- // navigation
- monthsField: 'monthsShort',
- prevHtml: '<svg><path d="M 17,12 l -5,5 l 5,5"></path></svg>',
- nextHtml: '<svg><path d="M 14,12 l 5,5 l -5,5"></path></svg>',
- navTitles: {
- days: 'MM, <i>yyyy</i>',
- months: 'yyyy',
- years: 'yyyy1 - yyyy2'
- },
- // timepicker
- timepicker: false,
- onlyTimepicker: false,
- dateTimeSeparator: ' ',
- timeFormat: '',
- minHours: 0,
- maxHours: 24,
- minMinutes: 0,
- maxMinutes: 59,
- hoursStep: 1,
- minutesStep: 1,
- // events
- onSelect: '',
- onShow: '',
- onHide: '',
- onChangeMonth: '',
- onChangeYear: '',
- onChangeDecade: '',
- onChangeView: '',
- onRenderCell: ''
- },
- hotKeys = {
- 'ctrlRight': [17, 39],
- 'ctrlUp': [17, 38],
- 'ctrlLeft': [17, 37],
- 'ctrlDown': [17, 40],
- 'shiftRight': [16, 39],
- 'shiftUp': [16, 38],
- 'shiftLeft': [16, 37],
- 'shiftDown': [16, 40],
- 'altUp': [18, 38],
- 'altRight': [18, 39],
- 'altLeft': [18, 37],
- 'altDown': [18, 40],
- 'ctrlShiftUp': [16, 17, 38]
- },
- datepicker;
- var Datepicker = function (el, options) {
- this.el = el;
- this.$el = $(el);
- this.opts = $.extend(true, {}, defaults, options, this.$el.data());
- if ($body == undefined) {
- $body = $('body');
- }
- if (!this.opts.startDate) {
- this.opts.startDate = new Date();
- }
- if (this.el.nodeName == 'INPUT') {
- this.elIsInput = true;
- }
- if (this.opts.altField) {
- this.$altField = typeof this.opts.altField == 'string' ? $(this.opts.altField) : this.opts.altField;
- }
- this.inited = false;
- this.visible = false;
- this.silent = false; // Need to prevent unnecessary rendering
- this.currentDate = this.opts.startDate;
- this.currentView = this.opts.view;
- this._createShortCuts();
- this.selectedDates = [];
- this.views = {};
- this.keys = [];
- this.minRange = '';
- this.maxRange = '';
- this._prevOnSelectValue = '';
- this.init()
- };
- datepicker = Datepicker;
- datepicker.prototype = {
- VERSION: VERSION,
- viewIndexes: ['days', 'months', 'years'],
- init: function () {
- if (!containerBuilt && !this.opts.inline && this.elIsInput) {
- this._buildDatepickersContainer();
- }
- this._buildBaseHtml();
- this._defineLocale(this.opts.language);
- this._syncWithMinMaxDates();
- if (this.elIsInput) {
- if (!this.opts.inline) {
- // Set extra classes for proper transitions
- this._setPositionClasses(this.opts.position);
- this._bindEvents()
- }
- if (this.opts.keyboardNav && !this.opts.onlyTimepicker) {
- this._bindKeyboardEvents();
- }
- this.$datepicker.on('mousedown', this._onMouseDownDatepicker.bind(this));
- this.$datepicker.on('mouseup', this._onMouseUpDatepicker.bind(this));
- }
- if (this.opts.classes) {
- this.$datepicker.addClass(this.opts.classes)
- }
- if (this.opts.timepicker) {
- this.timepicker = new $.fn.datepicker.Timepicker(this, this.opts);
- this._bindTimepickerEvents();
- }
- if (this.opts.onlyTimepicker) {
- this.$datepicker.addClass('-only-timepicker-');
- }
- this.views[this.currentView] = new $.fn.datepicker.Body(this, this.currentView, this.opts);
- this.views[this.currentView].show();
- this.nav = new $.fn.datepicker.Navigation(this, this.opts);
- this.view = this.currentView;
- this.$el.on('clickCell.adp', this._onClickCell.bind(this));
- this.$datepicker.on('mouseenter', '.datepicker--cell', this._onMouseEnterCell.bind(this));
- this.$datepicker.on('mouseleave', '.datepicker--cell', this._onMouseLeaveCell.bind(this));
- this.inited = true;
- },
- _createShortCuts: function () {
- this.minDate = this.opts.minDate ? this.opts.minDate : new Date(-8639999913600000);
- this.maxDate = this.opts.maxDate ? this.opts.maxDate : new Date(8639999913600000);
- },
- _bindEvents : function () {
- this.$el.on(this.opts.showEvent + '.adp', this._onShowEvent.bind(this));
- this.$el.on('mouseup.adp', this._onMouseUpEl.bind(this));
- this.$el.on('blur.adp', this._onBlur.bind(this));
- this.$el.on('keyup.adp', this._onKeyUpGeneral.bind(this));
- $(window).on('resize.adp', this._onResize.bind(this));
- $('body').on('mouseup.adp', this._onMouseUpBody.bind(this));
- },
- _bindKeyboardEvents: function () {
- this.$el.on('keydown.adp', this._onKeyDown.bind(this));
- this.$el.on('keyup.adp', this._onKeyUp.bind(this));
- this.$el.on('hotKey.adp', this._onHotKey.bind(this));
- },
- _bindTimepickerEvents: function () {
- this.$el.on('timeChange.adp', this._onTimeChange.bind(this));
- },
- isWeekend: function (day) {
- return this.opts.weekends.indexOf(day) !== -1;
- },
- _defineLocale: function (lang) {
- if (typeof lang == 'string') {
- this.loc = $.fn.datepicker.language[lang];
- if (!this.loc) {
- console.warn('Can\'t find language "' + lang + '" in Datepicker.language, will use "ru" instead');
- this.loc = $.extend(true, {}, $.fn.datepicker.language.ru)
- }
- this.loc = $.extend(true, {}, $.fn.datepicker.language.ru, $.fn.datepicker.language[lang])
- } else {
- this.loc = $.extend(true, {}, $.fn.datepicker.language.ru, lang)
- }
- if (this.opts.dateFormat) {
- this.loc.dateFormat = this.opts.dateFormat
- }
- if (this.opts.timeFormat) {
- this.loc.timeFormat = this.opts.timeFormat
- }
- if (this.opts.firstDay !== '') {
- this.loc.firstDay = this.opts.firstDay
- }
- if (this.opts.timepicker) {
- this.loc.dateFormat = [this.loc.dateFormat, this.loc.timeFormat].join(this.opts.dateTimeSeparator);
- }
- if (this.opts.onlyTimepicker) {
- this.loc.dateFormat = this.loc.timeFormat;
- }
- var boundary = this._getWordBoundaryRegExp;
- if (this.loc.timeFormat.match(boundary('aa')) ||
- this.loc.timeFormat.match(boundary('AA'))
- ) {
- this.ampm = true;
- }
- },
- _buildDatepickersContainer: function () {
- containerBuilt = true;
- $body.append('<div class="datepickers-container" id="datepickers-container"></div>');
- $datepickersContainer = $('#datepickers-container');
- },
- _buildBaseHtml: function () {
- var $appendTarget,
- $inline = $('<div class="datepicker-inline">');
- if(this.el.nodeName == 'INPUT') {
- if (!this.opts.inline) {
- $appendTarget = $datepickersContainer;
- } else {
- $appendTarget = $inline.insertAfter(this.$el)
- }
- } else {
- $appendTarget = $inline.appendTo(this.$el)
- }
- this.$datepicker = $(baseTemplate).appendTo($appendTarget);
- this.$content = $('.datepicker--content', this.$datepicker);
- this.$nav = $('.datepicker--nav', this.$datepicker);
- },
- _triggerOnChange: function () {
- if (!this.selectedDates.length) {
- // Prevent from triggering multiple onSelect callback with same argument (empty string) in IE10-11
- if (this._prevOnSelectValue === '') return;
- this._prevOnSelectValue = '';
- return this.opts.onSelect('', '', this);
- }
- var selectedDates = this.selectedDates,
- parsedSelected = datepicker.getParsedDate(selectedDates[0]),
- formattedDates,
- _this = this,
- dates = new Date(
- parsedSelected.year,
- parsedSelected.month,
- parsedSelected.date,
- parsedSelected.hours,
- parsedSelected.minutes
- );
- formattedDates = selectedDates.map(function (date) {
- return _this.formatDate(_this.loc.dateFormat, date)
- }).join(this.opts.multipleDatesSeparator);
- // Create new dates array, to separate it from original selectedDates
- if (this.opts.multipleDates || this.opts.range) {
- dates = selectedDates.map(function(date) {
- var parsedDate = datepicker.getParsedDate(date);
- return new Date(
- parsedDate.year,
- parsedDate.month,
- parsedDate.date,
- parsedDate.hours,
- parsedDate.minutes
- );
- })
- }
- this._prevOnSelectValue = formattedDates;
- this.opts.onSelect(formattedDates, dates, this);
- },
- next: function () {
- var d = this.parsedDate,
- o = this.opts;
- switch (this.view) {
- case 'days':
- this.date = new Date(d.year, d.month + 1, 1);
- if (o.onChangeMonth) o.onChangeMonth(this.parsedDate.month, this.parsedDate.year);
- break;
- case 'months':
- this.date = new Date(d.year + 1, d.month, 1);
- if (o.onChangeYear) o.onChangeYear(this.parsedDate.year);
- break;
- case 'years':
- this.date = new Date(d.year + 10, 0, 1);
- if (o.onChangeDecade) o.onChangeDecade(this.curDecade);
- break;
- }
- },
- prev: function () {
- var d = this.parsedDate,
- o = this.opts;
- switch (this.view) {
- case 'days':
- this.date = new Date(d.year, d.month - 1, 1);
- if (o.onChangeMonth) o.onChangeMonth(this.parsedDate.month, this.parsedDate.year);
- break;
- case 'months':
- this.date = new Date(d.year - 1, d.month, 1);
- if (o.onChangeYear) o.onChangeYear(this.parsedDate.year);
- break;
- case 'years':
- this.date = new Date(d.year - 10, 0, 1);
- if (o.onChangeDecade) o.onChangeDecade(this.curDecade);
- break;
- }
- },
- formatDate: function (string, date) {
- date = date || this.date;
- var result = string,
- boundary = this._getWordBoundaryRegExp,
- locale = this.loc,
- leadingZero = datepicker.getLeadingZeroNum,
- decade = datepicker.getDecade(date),
- d = datepicker.getParsedDate(date),
- fullHours = d.fullHours,
- hours = d.hours,
- ampm = string.match(boundary('aa')) || string.match(boundary('AA')),
- dayPeriod = 'am',
- replacer = this._replacer,
- validHours;
- if (this.opts.timepicker && this.timepicker && ampm) {
- validHours = this.timepicker._getValidHoursFromDate(date, ampm);
- fullHours = leadingZero(validHours.hours);
- hours = validHours.hours;
- dayPeriod = validHours.dayPeriod;
- }
- switch (true) {
- case /@/.test(result):
- result = result.replace(/@/, date.getTime());
- case /aa/.test(result):
- result = replacer(result, boundary('aa'), dayPeriod);
- case /AA/.test(result):
- result = replacer(result, boundary('AA'), dayPeriod.toUpperCase());
- case /dd/.test(result):
- result = replacer(result, boundary('dd'), d.fullDate);
- case /d/.test(result):
- result = replacer(result, boundary('d'), d.date);
- case /DD/.test(result):
- result = replacer(result, boundary('DD'), locale.days[d.day]);
- case /D/.test(result):
- result = replacer(result, boundary('D'), locale.daysShort[d.day]);
- case /mm/.test(result):
- result = replacer(result, boundary('mm'), d.fullMonth);
- case /m/.test(result):
- result = replacer(result, boundary('m'), d.month + 1);
- case /MM/.test(result):
- result = replacer(result, boundary('MM'), this.loc.months[d.month]);
- case /M/.test(result):
- result = replacer(result, boundary('M'), locale.monthsShort[d.month]);
- case /ii/.test(result):
- result = replacer(result, boundary('ii'), d.fullMinutes);
- case /i/.test(result):
- result = replacer(result, boundary('i'), d.minutes);
- case /hh/.test(result):
- result = replacer(result, boundary('hh'), fullHours);
- case /h/.test(result):
- result = replacer(result, boundary('h'), hours);
- case /yyyy/.test(result):
- result = replacer(result, boundary('yyyy'), d.year);
- case /yyyy1/.test(result):
- result = replacer(result, boundary('yyyy1'), decade[0]);
- case /yyyy2/.test(result):
- result = replacer(result, boundary('yyyy2'), decade[1]);
- case /yy/.test(result):
- result = replacer(result, boundary('yy'), d.year.toString().slice(-2));
- }
- return result;
- },
- _replacer: function (str, reg, data) {
- return str.replace(reg, function (match, p1,p2,p3) {
- return p1 + data + p3;
- })
- },
- _getWordBoundaryRegExp: function (sign) {
- var symbols = '\\s|\\.|-|/|\\\\|,|\\$|\\!|\\?|:|;';
- return new RegExp('(^|>|' + symbols + ')(' + sign + ')($|<|' + symbols + ')', 'g');
- },
- selectDate: function (date) {
- var _this = this,
- opts = _this.opts,
- d = _this.parsedDate,
- selectedDates = _this.selectedDates,
- len = selectedDates.length,
- newDate = '';
- if (Array.isArray(date)) {
- date.forEach(function (d) {
- _this.selectDate(d)
- });
- return;
- }
- if (!(date instanceof Date)) return;
- this.lastSelectedDate = date;
- // Set new time values from Date
- if (this.timepicker) {
- this.timepicker._setTime(date);
- }
- // On this step timepicker will set valid values in it's instance
- _this._trigger('selectDate', date);
- // Set correct time values after timepicker's validation
- // Prevent from setting hours or minutes which values are lesser then `min` value or
- // greater then `max` value
- if (this.timepicker) {
- date.setHours(this.timepicker.hours);
- date.setMinutes(this.timepicker.minutes)
- }
- if (_this.view == 'days') {
- if (date.getMonth() != d.month && opts.moveToOtherMonthsOnSelect) {
- newDate = new Date(date.getFullYear(), date.getMonth(), 1);
- }
- }
- if (_this.view == 'years') {
- if (date.getFullYear() != d.year && opts.moveToOtherYearsOnSelect) {
- newDate = new Date(date.getFullYear(), 0, 1);
- }
- }
- if (newDate) {
- _this.silent = true;
- _this.date = newDate;
- _this.silent = false;
- _this.nav._render()
- }
- if (opts.multipleDates && !opts.range) { // Set priority to range functionality
- if (len === opts.multipleDates) return;
- if (!_this._isSelected(date)) {
- _this.selectedDates.push(date);
- }
- } else if (opts.range) {
- if (len == 2) {
- _this.selectedDates = [date];
- _this.minRange = date;
- _this.maxRange = '';
- } else if (len == 1) {
- _this.selectedDates.push(date);
- if (!_this.maxRange){
- _this.maxRange = date;
- } else {
- _this.minRange = date;
- }
- // Swap dates if they were selected via dp.selectDate() and second date was smaller then first
- if (datepicker.bigger(_this.maxRange, _this.minRange)) {
- _this.maxRange = _this.minRange;
- _this.minRange = date;
- }
- _this.selectedDates = [_this.minRange, _this.maxRange]
- } else {
- _this.selectedDates = [date];
- _this.minRange = date;
- }
- } else {
- _this.selectedDates = [date];
- }
- _this._setInputValue();
- if (opts.onSelect) {
- _this._triggerOnChange();
- }
- if (opts.autoClose && !this.timepickerIsActive) {
- if (!opts.multipleDates && !opts.range) {
- _this.hide();
- } else if (opts.range && _this.selectedDates.length == 2) {
- _this.hide();
- }
- }
- _this.views[this.currentView]._render()
- },
- removeDate: function (date) {
- var selected = this.selectedDates,
- _this = this;
- if (!(date instanceof Date)) return;
- return selected.some(function (curDate, i) {
- if (datepicker.isSame(curDate, date)) {
- selected.splice(i, 1);
- if (!_this.selectedDates.length) {
- _this.minRange = '';
- _this.maxRange = '';
- _this.lastSelectedDate = '';
- } else {
- _this.lastSelectedDate = _this.selectedDates[_this.selectedDates.length - 1];
- }
- _this.views[_this.currentView]._render();
- _this._setInputValue();
- if (_this.opts.onSelect) {
- _this._triggerOnChange();
- }
- return true
- }
- })
- },
- today: function () {
- this.silent = true;
- this.view = this.opts.minView;
- this.silent = false;
- this.date = new Date();
- if (this.opts.todayButton instanceof Date) {
- this.selectDate(this.opts.todayButton)
- }
- },
- clear: function () {
- this.selectedDates = [];
- this.minRange = '';
- this.maxRange = '';
- this.views[this.currentView]._render();
- this._setInputValue();
- if (this.opts.onSelect) {
- this._triggerOnChange()
- }
- },
- /**
- * Updates datepicker options
- * @param {String|Object} param - parameter's name to update. If object then it will extend current options
- * @param {String|Number|Object} [value] - new param value
- */
- update: function (param, value) {
- var len = arguments.length,
- lastSelectedDate = this.lastSelectedDate;
- if (len == 2) {
- this.opts[param] = value;
- } else if (len == 1 && typeof param == 'object') {
- this.opts = $.extend(true, this.opts, param)
- }
- this._createShortCuts();
- this._syncWithMinMaxDates();
- this._defineLocale(this.opts.language);
- this.nav._addButtonsIfNeed();
- if (!this.opts.onlyTimepicker) this.nav._render();
- this.views[this.currentView]._render();
- if (this.elIsInput && !this.opts.inline) {
- this._setPositionClasses(this.opts.position);
- if (this.visible) {
- this.setPosition(this.opts.position)
- }
- }
- if (this.opts.classes) {
- this.$datepicker.addClass(this.opts.classes)
- }
- if (this.opts.onlyTimepicker) {
- this.$datepicker.addClass('-only-timepicker-');
- }
- if (this.opts.timepicker) {
- if (lastSelectedDate) this.timepicker._handleDate(lastSelectedDate);
- this.timepicker._updateRanges();
- this.timepicker._updateCurrentTime();
- // Change hours and minutes if it's values have been changed through min/max hours/minutes
- if (lastSelectedDate) {
- lastSelectedDate.setHours(this.timepicker.hours);
- lastSelectedDate.setMinutes(this.timepicker.minutes);
- }
- }
- this._setInputValue();
- return this;
- },
- _syncWithMinMaxDates: function () {
- var curTime = this.date.getTime();
- this.silent = true;
- if (this.minTime > curTime) {
- this.date = this.minDate;
- }
- if (this.maxTime < curTime) {
- this.date = this.maxDate;
- }
- this.silent = false;
- },
- _isSelected: function (checkDate, cellType) {
- var res = false;
- this.selectedDates.some(function (date) {
- if (datepicker.isSame(date, checkDate, cellType)) {
- res = date;
- return true;
- }
- });
- return res;
- },
- _setInputValue: function () {
- var _this = this,
- opts = _this.opts,
- format = _this.loc.dateFormat,
- altFormat = opts.altFieldDateFormat,
- value = _this.selectedDates.map(function (date) {
- return _this.formatDate(format, date)
- }),
- altValues;
- if (opts.altField && _this.$altField.length) {
- altValues = this.selectedDates.map(function (date) {
- return _this.formatDate(altFormat, date)
- });
- altValues = altValues.join(this.opts.multipleDatesSeparator);
- this.$altField.val(altValues);
- }
- value = value.join(this.opts.multipleDatesSeparator);
- this.$el.val(value)
- },
- /**
- * Check if date is between minDate and maxDate
- * @param date {object} - date object
- * @param type {string} - cell type
- * @returns {boolean}
- * @private
- */
- _isInRange: function (date, type) {
- var time = date.getTime(),
- d = datepicker.getParsedDate(date),
- min = datepicker.getParsedDate(this.minDate),
- max = datepicker.getParsedDate(this.maxDate),
- dMinTime = new Date(d.year, d.month, min.date).getTime(),
- dMaxTime = new Date(d.year, d.month, max.date).getTime(),
- types = {
- day: time >= this.minTime && time <= this.maxTime,
- month: dMinTime >= this.minTime && dMaxTime <= this.maxTime,
- year: d.year >= min.year && d.year <= max.year
- };
- return type ? types[type] : types.day
- },
- _getDimensions: function ($el) {
- var offset = $el.offset();
- return {
- width: $el.outerWidth(),
- height: $el.outerHeight(),
- left: offset.left,
- top: offset.top
- }
- },
- _getDateFromCell: function (cell) {
- var curDate = this.parsedDate,
- year = cell.data('year') || curDate.year,
- month = cell.data('month') == undefined ? curDate.month : cell.data('month'),
- date = cell.data('date') || 1;
- return new Date(year, month, date);
- },
- _setPositionClasses: function (pos) {
- pos = pos.split(' ');
- var main = pos[0],
- sec = pos[1],
- classes = 'datepicker -' + main + '-' + sec + '- -from-' + main + '-';
- if (this.visible) classes += ' active';
- this.$datepicker
- .removeAttr('class')
- .addClass(classes);
- },
- setPosition: function (position) {
- position = position || this.opts.position;
- var dims = this._getDimensions(this.$el),
- selfDims = this._getDimensions(this.$datepicker),
- pos = position.split(' '),
- top, left,
- offset = this.opts.offset,
- main = pos[0],
- secondary = pos[1];
- switch (main) {
- case 'top':
- top = dims.top - selfDims.height - offset;
- break;
- case 'right':
- left = dims.left + dims.width + offset;
- break;
- case 'bottom':
- top = dims.top + dims.height + offset;
- break;
- case 'left':
- left = dims.left - selfDims.width - offset;
- break;
- }
- switch(secondary) {
- case 'top':
- top = dims.top;
- break;
- case 'right':
- left = dims.left + dims.width - selfDims.width;
- break;
- case 'bottom':
- top = dims.top + dims.height - selfDims.height;
- break;
- case 'left':
- left = dims.left;
- break;
- case 'center':
- if (/left|right/.test(main)) {
- top = dims.top + dims.height/2 - selfDims.height/2;
- } else {
- left = dims.left + dims.width/2 - selfDims.width/2;
- }
- }
- this.$datepicker
- .css({
- left: left,
- top: top
- })
- },
- show: function () {
- var onShow = this.opts.onShow;
- this.setPosition(this.opts.position);
- this.$datepicker.addClass('active');
- this.visible = true;
- if (onShow) {
- this._bindVisionEvents(onShow)
- }
- },
- hide: function () {
- var onHide = this.opts.onHide;
- this.$datepicker
- .removeClass('active')
- .css({
- left: '-100000px'
- });
- this.focused = '';
- this.keys = [];
- this.inFocus = false;
- this.visible = false;
- this.$el.blur();
- if (onHide) {
- this._bindVisionEvents(onHide)
- }
- },
- down: function (date) {
- this._changeView(date, 'down');
- },
- up: function (date) {
- this._changeView(date, 'up');
- },
- _bindVisionEvents: function (event) {
- this.$datepicker.off('transitionend.dp');
- event(this, false);
- this.$datepicker.one('transitionend.dp', event.bind(this, this, true))
- },
- _changeView: function (date, dir) {
- date = date || this.focused || this.date;
- var nextView = dir == 'up' ? this.viewIndex + 1 : this.viewIndex - 1;
- if (nextView > 2) nextView = 2;
- if (nextView < 0) nextView = 0;
- this.silent = true;
- this.date = new Date(date.getFullYear(), date.getMonth(), 1);
- this.silent = false;
- this.view = this.viewIndexes[nextView];
- },
- _handleHotKey: function (key) {
- var date = datepicker.getParsedDate(this._getFocusedDate()),
- focusedParsed,
- o = this.opts,
- newDate,
- totalDaysInNextMonth,
- monthChanged = false,
- yearChanged = false,
- decadeChanged = false,
- y = date.year,
- m = date.month,
- d = date.date;
- switch (key) {
- case 'ctrlRight':
- case 'ctrlUp':
- m += 1;
- monthChanged = true;
- break;
- case 'ctrlLeft':
- case 'ctrlDown':
- m -= 1;
- monthChanged = true;
- break;
- case 'shiftRight':
- case 'shiftUp':
- yearChanged = true;
- y += 1;
- break;
- case 'shiftLeft':
- case 'shiftDown':
- yearChanged = true;
- y -= 1;
- break;
- case 'altRight':
- case 'altUp':
- decadeChanged = true;
- y += 10;
- break;
- case 'altLeft':
- case 'altDown':
- decadeChanged = true;
- y -= 10;
- break;
- case 'ctrlShiftUp':
- this.up();
- break;
- }
- totalDaysInNextMonth = datepicker.getDaysCount(new Date(y,m));
- newDate = new Date(y,m,d);
- // If next month has less days than current, set date to total days in that month
- if (totalDaysInNextMonth < d) d = totalDaysInNextMonth;
- // Check if newDate is in valid range
- if (newDate.getTime() < this.minTime) {
- newDate = this.minDate;
- } else if (newDate.getTime() > this.maxTime) {
- newDate = this.maxDate;
- }
- this.focused = newDate;
- focusedParsed = datepicker.getParsedDate(newDate);
- if (monthChanged && o.onChangeMonth) {
- o.onChangeMonth(focusedParsed.month, focusedParsed.year)
- }
- if (yearChanged && o.onChangeYear) {
- o.onChangeYear(focusedParsed.year)
- }
- if (decadeChanged && o.onChangeDecade) {
- o.onChangeDecade(this.curDecade)
- }
- },
- _registerKey: function (key) {
- var exists = this.keys.some(function (curKey) {
- return curKey == key;
- });
- if (!exists) {
- this.keys.push(key)
- }
- },
- _unRegisterKey: function (key) {
- var index = this.keys.indexOf(key);
- this.keys.splice(index, 1);
- },
- _isHotKeyPressed: function () {
- var currentHotKey,
- found = false,
- _this = this,
- pressedKeys = this.keys.sort();
- for (var hotKey in hotKeys) {
- currentHotKey = hotKeys[hotKey];
- if (pressedKeys.length != currentHotKey.length) continue;
- if (currentHotKey.every(function (key, i) { return key == pressedKeys[i]})) {
- _this._trigger('hotKey', hotKey);
- found = true;
- }
- }
- return found;
- },
- _trigger: function (event, args) {
- this.$el.trigger(event, args)
- },
- _focusNextCell: function (keyCode, type) {
- type = type || this.cellType;
- var date = datepicker.getParsedDate(this._getFocusedDate()),
- y = date.year,
- m = date.month,
- d = date.date;
- if (this._isHotKeyPressed()){
- return;
- }
- switch(keyCode) {
- case 37: // left
- type == 'day' ? (d -= 1) : '';
- type == 'month' ? (m -= 1) : '';
- type == 'year' ? (y -= 1) : '';
- break;
- case 38: // up
- type == 'day' ? (d -= 7) : '';
- type == 'month' ? (m -= 3) : '';
- type == 'year' ? (y -= 4) : '';
- break;
- case 39: // right
- type == 'day' ? (d += 1) : '';
- type == 'month' ? (m += 1) : '';
- type == 'year' ? (y += 1) : '';
- break;
- case 40: // down
- type == 'day' ? (d += 7) : '';
- type == 'month' ? (m += 3) : '';
- type == 'year' ? (y += 4) : '';
- break;
- }
- var nd = new Date(y,m,d);
- if (nd.getTime() < this.minTime) {
- nd = this.minDate;
- } else if (nd.getTime() > this.maxTime) {
- nd = this.maxDate;
- }
- this.focused = nd;
- },
- _getFocusedDate: function () {
- var focused = this.focused || this.selectedDates[this.selectedDates.length - 1],
- d = this.parsedDate;
- if (!focused) {
- switch (this.view) {
- case 'days':
- focused = new Date(d.year, d.month, new Date().getDate());
- break;
- case 'months':
- focused = new Date(d.year, d.month, 1);
- break;
- case 'years':
- focused = new Date(d.year, 0, 1);
- break;
- }
- }
- return focused;
- },
- _getCell: function (date, type) {
- type = type || this.cellType;
- var d = datepicker.getParsedDate(date),
- selector = '.datepicker--cell[data-year="' + d.year + '"]',
- $cell;
- switch (type) {
- case 'month':
- selector = '[data-month="' + d.month + '"]';
- break;
- case 'day':
- selector += '[data-month="' + d.month + '"][data-date="' + d.date + '"]';
- break;
- }
- $cell = this.views[this.currentView].$el.find(selector);
- return $cell.length ? $cell : $('');
- },
- destroy: function () {
- var _this = this;
- _this.$el
- .off('.adp')
- .data('datepicker', '');
- _this.selectedDates = [];
- _this.focused = '';
- _this.views = {};
- _this.keys = [];
- _this.minRange = '';
- _this.maxRange = '';
- if (_this.opts.inline || !_this.elIsInput) {
- _this.$datepicker.closest('.datepicker-inline').remove();
- } else {
- _this.$datepicker.remove();
- }
- },
- _handleAlreadySelectedDates: function (alreadySelected, selectedDate) {
- if (this.opts.range) {
- if (!this.opts.toggleSelected) {
- // Add possibility to select same date when range is true
- if (this.selectedDates.length != 2) {
- this._trigger('clickCell', selectedDate);
- }
- } else {
- this.removeDate(selectedDate);
- }
- } else if (this.opts.toggleSelected){
- this.removeDate(selectedDate);
- }
- // Change last selected date to be able to change time when clicking on this cell
- if (!this.opts.toggleSelected) {
- this.lastSelectedDate = alreadySelected;
- if (this.opts.timepicker) {
- this.timepicker._setTime(alreadySelected);
- this.timepicker.update();
- }
- }
- },
- _onShowEvent: function (e) {
- if (!this.visible) {
- this.show();
- }
- },
- _onBlur: function () {
- if (!this.inFocus && this.visible) {
- this.hide();
- }
- },
- _onMouseDownDatepicker: function (e) {
- this.inFocus = true;
- },
- _onMouseUpDatepicker: function (e) {
- this.inFocus = false;
- e.originalEvent.inFocus = true;
- if (!e.originalEvent.timepickerFocus) this.$el.focus();
- },
- _onKeyUpGeneral: function (e) {
- var val = this.$el.val();
- if (!val) {
- this.clear();
- }
- },
- _onResize: function () {
- if (this.visible) {
- this.setPosition();
- }
- },
- _onMouseUpBody: function (e) {
- if (e.originalEvent.inFocus) return;
- if (this.visible && !this.inFocus) {
- this.hide();
- }
- },
- _onMouseUpEl: function (e) {
- e.originalEvent.inFocus = true;
- setTimeout(this._onKeyUpGeneral.bind(this),4);
- },
- _onKeyDown: function (e) {
- var code = e.which;
- this._registerKey(code);
- // Arrows
- if (code >= 37 && code <= 40) {
- e.preventDefault();
- this._focusNextCell(code);
- }
- // Enter
- if (code == 13) {
- if (this.focused) {
- if (this._getCell(this.focused).hasClass('-disabled-')) return;
- if (this.view != this.opts.minView) {
- this.down()
- } else {
- var alreadySelected = this._isSelected(this.focused, this.cellType);
- if (!alreadySelected) {
- if (this.timepicker) {
- this.focused.setHours(this.timepicker.hours);
- this.focused.setMinutes(this.timepicker.minutes);
- }
- this.selectDate(this.focused);
- return;
- }
- this._handleAlreadySelectedDates(alreadySelected, this.focused)
- }
- }
- }
- // Esc
- if (code == 27) {
- this.hide();
- }
- },
- _onKeyUp: function (e) {
- var code = e.which;
- this._unRegisterKey(code);
- },
- _onHotKey: function (e, hotKey) {
- this._handleHotKey(hotKey);
- },
- _onMouseEnterCell: function (e) {
- var $cell = $(e.target).closest('.datepicker--cell'),
- date = this._getDateFromCell($cell);
- // Prevent from unnecessary rendering and setting new currentDate
- this.silent = true;
- if (this.focused) {
- this.focused = ''
- }
- $cell.addClass('-focus-');
- this.focused = date;
- this.silent = false;
- if (this.opts.range && this.selectedDates.length == 1) {
- this.minRange = this.selectedDates[0];
- this.maxRange = '';
- if (datepicker.less(this.minRange, this.focused)) {
- this.maxRange = this.minRange;
- this.minRange = '';
- }
- this.views[this.currentView]._update();
- }
- },
- _onMouseLeaveCell: function (e) {
- var $cell = $(e.target).closest('.datepicker--cell');
- $cell.removeClass('-focus-');
- this.silent = true;
- this.focused = '';
- this.silent = false;
- },
- _onTimeChange: function (e, h, m) {
- var date = new Date(),
- selectedDates = this.selectedDates,
- selected = false;
- if (selectedDates.length) {
- selected = true;
- date = this.lastSelectedDate;
- }
- date.setHours(h);
- date.setMinutes(m);
- if (!selected && !this._getCell(date).hasClass('-disabled-')) {
- this.selectDate(date);
- } else {
- this._setInputValue();
- if (this.opts.onSelect) {
- this._triggerOnChange();
- }
- }
- },
- _onClickCell: function (e, date) {
- if (this.timepicker) {
- date.setHours(this.timepicker.hours);
- date.setMinutes(this.timepicker.minutes);
- }
- this.selectDate(date);
- },
- set focused(val) {
- if (!val && this.focused) {
- var $cell = this._getCell(this.focused);
- if ($cell.length) {
- $cell.removeClass('-focus-')
- }
- }
- this._focused = val;
- if (this.opts.range && this.selectedDates.length == 1) {
- this.minRange = this.selectedDates[0];
- this.maxRange = '';
- if (datepicker.less(this.minRange, this._focused)) {
- this.maxRange = this.minRange;
- this.minRange = '';
- }
- }
- if (this.silent) return;
- this.date = val;
- },
- get focused() {
- return this._focused;
- },
- get parsedDate() {
- return datepicker.getParsedDate(this.date);
- },
- set date (val) {
- if (!(val instanceof Date)) return;
- this.currentDate = val;
- if (this.inited && !this.silent) {
- this.views[this.view]._render();
- this.nav._render();
- if (this.visible && this.elIsInput) {
- this.setPosition();
- }
- }
- return val;
- },
- get date () {
- return this.currentDate
- },
- set view (val) {
- this.viewIndex = this.viewIndexes.indexOf(val);
- if (this.viewIndex < 0) {
- return;
- }
- this.prevView = this.currentView;
- this.currentView = val;
- if (this.inited) {
- if (!this.views[val]) {
- this.views[val] = new $.fn.datepicker.Body(this, val, this.opts)
- } else {
- this.views[val]._render();
- }
- this.views[this.prevView].hide();
- this.views[val].show();
- this.nav._render();
- if (this.opts.onChangeView) {
- this.opts.onChangeView(val)
- }
- if (this.elIsInput && this.visible) this.setPosition();
- }
- return val
- },
- get view() {
- return this.currentView;
- },
- get cellType() {
- return this.view.substring(0, this.view.length - 1)
- },
- get minTime() {
- var min = datepicker.getParsedDate(this.minDate);
- return new Date(min.year, min.month, min.date).getTime()
- },
- get maxTime() {
- var max = datepicker.getParsedDate(this.maxDate);
- return new Date(max.year, max.month, max.date).getTime()
- },
- get curDecade() {
- return datepicker.getDecade(this.date)
- }
- };
- // Utils
- // -------------------------------------------------
- datepicker.getDaysCount = function (date) {
- return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
- };
- datepicker.getParsedDate = function (date) {
- return {
- year: date.getFullYear(),
- month: date.getMonth(),
- fullMonth: (date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1, // One based
- date: date.getDate(),
- fullDate: date.getDate() < 10 ? '0' + date.getDate() : date.getDate(),
- day: date.getDay(),
- hours: date.getHours(),
- fullHours: date.getHours() < 10 ? '0' + date.getHours() : date.getHours() ,
- minutes: date.getMinutes(),
- fullMinutes: date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
- }
- };
- datepicker.getDecade = function (date) {
- var firstYear = Math.floor(date.getFullYear() / 10) * 10;
- return [firstYear, firstYear + 9];
- };
- datepicker.template = function (str, data) {
- return str.replace(/#\{([\w]+)\}/g, function (source, match) {
- if (data[match] || data[match] === 0) {
- return data[match]
- }
- });
- };
- datepicker.isSame = function (date1, date2, type) {
- if (!date1 || !date2) return false;
- var d1 = datepicker.getParsedDate(date1),
- d2 = datepicker.getParsedDate(date2),
- _type = type ? type : 'day',
- conditions = {
- day: d1.date == d2.date && d1.month == d2.month && d1.year == d2.year,
- month: d1.month == d2.month && d1.year == d2.year,
- year: d1.year == d2.year
- };
- return conditions[_type];
- };
- datepicker.less = function (dateCompareTo, date, type) {
- if (!dateCompareTo || !date) return false;
- return date.getTime() < dateCompareTo.getTime();
- };
- datepicker.bigger = function (dateCompareTo, date, type) {
- if (!dateCompareTo || !date) return false;
- return date.getTime() > dateCompareTo.getTime();
- };
- datepicker.getLeadingZeroNum = function (num) {
- return parseInt(num) < 10 ? '0' + num : num;
- };
- /**
- * Returns copy of date with hours and minutes equals to 0
- * @param date {Date}
- */
- datepicker.resetTime = function (date) {
- if (typeof date != 'object') return;
- date = datepicker.getParsedDate(date);
- return new Date(date.year, date.month, date.date)
- };
- $.fn.datepicker = function ( options ) {
- return this.each(function () {
- if (!$.data(this, pluginName)) {
- $.data(this, pluginName,
- new Datepicker( this, options ));
- } else {
- var _this = $.data(this, pluginName);
- _this.opts = $.extend(true, _this.opts, options);
- _this.update();
- }
- });
- };
- $.fn.datepicker.Constructor = Datepicker;
- $.fn.datepicker.language = {
- ru: {
- days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
- daysShort: ['Вос','Пон','Вто','Сре','Чет','Пят','Суб'],
- daysMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'],
- months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
- monthsShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'],
- today: 'Сегодня',
- clear: 'Очистить',
- dateFormat: 'dd.mm.yyyy',
- timeFormat: 'hh:ii',
- firstDay: 1
- }
- };
- $(function () {
- $(autoInitSelector).datepicker();
- })
- })();
- ;(function () {
- var templates = {
- days:'' +
- '<div class="datepicker--days datepicker--body">' +
- '<div class="datepicker--days-names"></div>' +
- '<div class="datepicker--cells datepicker--cells-days"></div>' +
- '</div>',
- months: '' +
- '<div class="datepicker--months datepicker--body">' +
- '<div class="datepicker--cells datepicker--cells-months"></div>' +
- '</div>',
- years: '' +
- '<div class="datepicker--years datepicker--body">' +
- '<div class="datepicker--cells datepicker--cells-years"></div>' +
- '</div>'
- },
- datepicker = $.fn.datepicker,
- dp = datepicker.Constructor;
- datepicker.Body = function (d, type, opts) {
- this.d = d;
- this.type = type;
- this.opts = opts;
- this.$el = $('');
- if (this.opts.onlyTimepicker) return;
- this.init();
- };
- datepicker.Body.prototype = {
- init: function () {
- this._buildBaseHtml();
- this._render();
- this._bindEvents();
- },
- _bindEvents: function () {
- this.$el.on('click', '.datepicker--cell', $.proxy(this._onClickCell, this));
- },
- _buildBaseHtml: function () {
- this.$el = $(templates[this.type]).appendTo(this.d.$content);
- this.$names = $('.datepicker--days-names', this.$el);
- this.$cells = $('.datepicker--cells', this.$el);
- },
- _getDayNamesHtml: function (firstDay, curDay, html, i) {
- curDay = curDay != undefined ? curDay : firstDay;
- html = html ? html : '';
- i = i != undefined ? i : 0;
- if (i > 7) return html;
- if (curDay == 7) return this._getDayNamesHtml(firstDay, 0, html, ++i);
- html += '<div class="datepicker--day-name' + (this.d.isWeekend(curDay) ? " -weekend-" : "") + '">' + this.d.loc.daysMin[curDay] + '</div>';
- return this._getDayNamesHtml(firstDay, ++curDay, html, ++i);
- },
- _getCellContents: function (date, type) {
- var classes = "datepicker--cell datepicker--cell-" + type,
- currentDate = new Date(),
- parent = this.d,
- minRange = dp.resetTime(parent.minRange),
- maxRange = dp.resetTime(parent.maxRange),
- opts = parent.opts,
- d = dp.getParsedDate(date),
- render = {},
- html = d.date;
- switch (type) {
- case 'day':
- if (parent.isWeekend(d.day)) classes += " -weekend-";
- if (d.month != this.d.parsedDate.month) {
- classes += " -other-month-";
- if (!opts.selectOtherMonths) {
- classes += " -disabled-";
- }
- if (!opts.showOtherMonths) html = '';
- }
- break;
- case 'month':
- html = parent.loc[parent.opts.monthsField][d.month];
- break;
- case 'year':
- var decade = parent.curDecade;
- html = d.year;
- if (d.year < decade[0] || d.year > decade[1]) {
- classes += ' -other-decade-';
- if (!opts.selectOtherYears) {
- classes += " -disabled-";
- }
- if (!opts.showOtherYears) html = '';
- }
- break;
- }
- if (opts.onRenderCell) {
- render = opts.onRenderCell(date, type) || {};
- html = render.html ? render.html : html;
- classes += render.classes ? ' ' + render.classes : '';
- }
- if (opts.range) {
- if (dp.isSame(minRange, date, type)) classes += ' -range-from-';
- if (dp.isSame(maxRange, date, type)) classes += ' -range-to-';
- if (parent.selectedDates.length == 1 && parent.focused) {
- if (
- (dp.bigger(minRange, date) && dp.less(parent.focused, date)) ||
- (dp.less(maxRange, date) && dp.bigger(parent.focused, date)))
- {
- classes += ' -in-range-'
- }
- if (dp.less(maxRange, date) && dp.isSame(parent.focused, date)) {
- classes += ' -range-from-'
- }
- if (dp.bigger(minRange, date) && dp.isSame(parent.focused, date)) {
- classes += ' -range-to-'
- }
- } else if (parent.selectedDates.length == 2) {
- if (dp.bigger(minRange, date) && dp.less(maxRange, date)) {
- classes += ' -in-range-'
- }
- }
- }
- if (dp.isSame(currentDate, date, type)) classes += ' -current-';
- if (parent.focused && dp.isSame(date, parent.focused, type)) classes += ' -focus-';
- if (parent._isSelected(date, type)) classes += ' -selected-';
- if (!parent._isInRange(date, type) || render.disabled) classes += ' -disabled-';
- return {
- html: html,
- classes: classes
- }
- },
- /**
- * Calculates days number to render. Generates days html and returns it.
- * @param {object} date - Date object
- * @returns {string}
- * @private
- */
- _getDaysHtml: function (date) {
- var totalMonthDays = dp.getDaysCount(date),
- firstMonthDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay(),
- lastMonthDay = new Date(date.getFullYear(), date.getMonth(), totalMonthDays).getDay(),
- daysFromPevMonth = firstMonthDay - this.d.loc.firstDay,
- daysFromNextMonth = 6 - lastMonthDay + this.d.loc.firstDay;
- daysFromPevMonth = daysFromPevMonth < 0 ? daysFromPevMonth + 7 : daysFromPevMonth;
- daysFromNextMonth = daysFromNextMonth > 6 ? daysFromNextMonth - 7 : daysFromNextMonth;
- var startDayIndex = -daysFromPevMonth + 1,
- m, y,
- html = '';
- for (var i = startDayIndex, max = totalMonthDays + daysFromNextMonth; i <= max; i++) {
- y = date.getFullYear();
- m = date.getMonth();
- html += this._getDayHtml(new Date(y, m, i))
- }
- return html;
- },
- _getDayHtml: function (date) {
- var content = this._getCellContents(date, 'day');
- return '<div class="' + content.classes + '" ' +
- 'data-date="' + date.getDate() + '" ' +
- 'data-month="' + date.getMonth() + '" ' +
- 'data-year="' + date.getFullYear() + '">' + content.html + '</div>';
- },
- /**
- * Generates months html
- * @param {object} date - date instance
- * @returns {string}
- * @private
- */
- _getMonthsHtml: function (date) {
- var html = '',
- d = dp.getParsedDate(date),
- i = 0;
- while(i < 12) {
- html += this._getMonthHtml(new Date(d.year, i));
- i++
- }
- return html;
- },
- _getMonthHtml: function (date) {
- var content = this._getCellContents(date, 'month');
- return '<div class="' + content.classes + '" data-month="' + date.getMonth() + '">' + content.html + '</div>'
- },
- _getYearsHtml: function (date) {
- var d = dp.getParsedDate(date),
- decade = dp.getDecade(date),
- firstYear = decade[0] - 1,
- html = '',
- i = firstYear;
- for (i; i <= decade[1] + 1; i++) {
- html += this._getYearHtml(new Date(i , 0));
- }
- return html;
- },
- _getYearHtml: function (date) {
- var content = this._getCellContents(date, 'year');
- return '<div class="' + content.classes + '" data-year="' + date.getFullYear() + '">' + content.html + '</div>'
- },
- _renderTypes: {
- days: function () {
- var dayNames = this._getDayNamesHtml(this.d.loc.firstDay),
- days = this._getDaysHtml(this.d.currentDate);
- this.$cells.html(days);
- this.$names.html(dayNames)
- },
- months: function () {
- var html = this._getMonthsHtml(this.d.currentDate);
- this.$cells.html(html)
- },
- years: function () {
- var html = this._getYearsHtml(this.d.currentDate);
- this.$cells.html(html)
- }
- },
- _render: function () {
- if (this.opts.onlyTimepicker) return;
- this._renderTypes[this.type].bind(this)();
- },
- _update: function () {
- var $cells = $('.datepicker--cell', this.$cells),
- _this = this,
- classes,
- $cell,
- date;
- $cells.each(function (cell, i) {
- $cell = $(this);
- date = _this.d._getDateFromCell($(this));
- classes = _this._getCellContents(date, _this.d.cellType);
- $cell.attr('class',classes.classes)
- });
- },
- show: function () {
- if (this.opts.onlyTimepicker) return;
- this.$el.addClass('active');
- this.acitve = true;
- },
- hide: function () {
- this.$el.removeClass('active');
- this.active = false;
- },
- // Events
- // -------------------------------------------------
- _handleClick: function (el) {
- var date = el.data('date') || 1,
- month = el.data('month') || 0,
- year = el.data('year') || this.d.parsedDate.year,
- dp = this.d;
- // Change view if min view does not reach yet
- if (dp.view != this.opts.minView) {
- dp.down(new Date(year, month, date));
- return;
- }
- // Select date if min view is reached
- var selectedDate = new Date(year, month, date),
- alreadySelected = this.d._isSelected(selectedDate, this.d.cellType);
- if (!alreadySelected) {
- dp._trigger('clickCell', selectedDate);
- return;
- }
- dp._handleAlreadySelectedDates.bind(dp, alreadySelected, selectedDate)();
- },
- _onClickCell: function (e) {
- var $el = $(e.target).closest('.datepicker--cell');
- if ($el.hasClass('-disabled-')) return;
- this._handleClick.bind(this)($el);
- }
- };
- })();
- ;(function () {
- var template = '' +
- '<div class="datepicker--nav-action" data-action="prev">#{prevHtml}</div>' +
- '<div class="datepicker--nav-title">#{title}</div>' +
- '<div class="datepicker--nav-action" data-action="next">#{nextHtml}</div>',
- buttonsContainerTemplate = '<div class="datepicker--buttons"></div>',
- button = '<span class="datepicker--button" data-action="#{action}">#{label}</span>',
- datepicker = $.fn.datepicker,
- dp = datepicker.Constructor;
- datepicker.Navigation = function (d, opts) {
- this.d = d;
- this.opts = opts;
- this.$buttonsContainer = '';
- this.init();
- };
- datepicker.Navigation.prototype = {
- init: function () {
- this._buildBaseHtml();
- this._bindEvents();
- },
- _bindEvents: function () {
- this.d.$nav.on('click', '.datepicker--nav-action', $.proxy(this._onClickNavButton, this));
- this.d.$nav.on('click', '.datepicker--nav-title', $.proxy(this._onClickNavTitle, this));
- this.d.$datepicker.on('click', '.datepicker--button', $.proxy(this._onClickNavButton, this));
- },
- _buildBaseHtml: function () {
- if (!this.opts.onlyTimepicker) {
- this._render();
- }
- this._addButtonsIfNeed();
- },
- _addButtonsIfNeed: function () {
- if (this.opts.todayButton) {
- this._addButton('today')
- }
- if (this.opts.clearButton) {
- this._addButton('clear')
- }
- },
- _render: function () {
- var title = this._getTitle(this.d.currentDate),
- html = dp.template(template, $.extend({title: title}, this.opts));
- this.d.$nav.html(html);
- if (this.d.view == 'years') {
- $('.datepicker--nav-title', this.d.$nav).addClass('-disabled-');
- }
- this.setNavStatus();
- },
- _getTitle: function (date) {
- return this.d.formatDate(this.opts.navTitles[this.d.view], date)
- },
- _addButton: function (type) {
- if (!this.$buttonsContainer.length) {
- this._addButtonsContainer();
- }
- var data = {
- action: type,
- label: this.d.loc[type]
- },
- html = dp.template(button, data);
- if ($('[data-action=' + type + ']', this.$buttonsContainer).length) return;
- this.$buttonsContainer.append(html);
- },
- _addButtonsContainer: function () {
- this.d.$datepicker.append(buttonsContainerTemplate);
- this.$buttonsContainer = $('.datepicker--buttons', this.d.$datepicker);
- },
- setNavStatus: function () {
- if (!(this.opts.minDate || this.opts.maxDate) || !this.opts.disableNavWhenOutOfRange) return;
- var date = this.d.parsedDate,
- m = date.month,
- y = date.year,
- d = date.date;
- switch (this.d.view) {
- case 'days':
- if (!this.d._isInRange(new Date(y, m-1, 1), 'month')) {
- this._disableNav('prev')
- }
- if (!this.d._isInRange(new Date(y, m+1, 1), 'month')) {
- this._disableNav('next')
- }
- break;
- case 'months':
- if (!this.d._isInRange(new Date(y-1, m, d), 'year')) {
- this._disableNav('prev')
- }
- if (!this.d._isInRange(new Date(y+1, m, d), 'year')) {
- this._disableNav('next')
- }
- break;
- case 'years':
- var decade = dp.getDecade(this.d.date);
- if (!this.d._isInRange(new Date(decade[0] - 1, 0, 1), 'year')) {
- this._disableNav('prev')
- }
- if (!this.d._isInRange(new Date(decade[1] + 1, 0, 1), 'year')) {
- this._disableNav('next')
- }
- break;
- }
- },
- _disableNav: function (nav) {
- $('[data-action="' + nav + '"]', this.d.$nav).addClass('-disabled-')
- },
- _activateNav: function (nav) {
- $('[data-action="' + nav + '"]', this.d.$nav).removeClass('-disabled-')
- },
- _onClickNavButton: function (e) {
- var $el = $(e.target).closest('[data-action]'),
- action = $el.data('action');
- this.d[action]();
- },
- _onClickNavTitle: function (e) {
- if ($(e.target).hasClass('-disabled-')) return;
- if (this.d.view == 'days') {
- return this.d.view = 'months'
- }
- this.d.view = 'years';
- }
- }
- })();
- ;(function () {
- var template = '<div class="datepicker--time">' +
- '<div class="datepicker--time-current">' +
- ' <span class="datepicker--time-current-hours">#{hourVisible}</span>' +
- ' <span class="datepicker--time-current-colon">:</span>' +
- ' <span class="datepicker--time-current-minutes">#{minValue}</span>' +
- '</div>' +
- '<div class="datepicker--time-sliders">' +
- ' <div class="datepicker--time-row">' +
- ' <input type="range" name="hours" value="#{hourValue}" min="#{hourMin}" max="#{hourMax}" step="#{hourStep}"/>' +
- ' </div>' +
- ' <div class="datepicker--time-row">' +
- ' <input type="range" name="minutes" value="#{minValue}" min="#{minMin}" max="#{minMax}" step="#{minStep}"/>' +
- ' </div>' +
- '</div>' +
- '</div>',
- datepicker = $.fn.datepicker,
- dp = datepicker.Constructor;
- datepicker.Timepicker = function (inst, opts) {
- this.d = inst;
- this.opts = opts;
- this.init();
- };
- datepicker.Timepicker.prototype = {
- init: function () {
- var input = 'input';
- this._setTime(this.d.date);
- this._buildHTML();
- if (navigator.userAgent.match(/trident/gi)) {
- input = 'change';
- }
- this.d.$el.on('selectDate', this._onSelectDate.bind(this));
- this.$ranges.on(input, this._onChangeRange.bind(this));
- this.$ranges.on('mouseup', this._onMouseUpRange.bind(this));
- this.$ranges.on('mousemove focus ', this._onMouseEnterRange.bind(this));
- this.$ranges.on('mouseout blur', this._onMouseOutRange.bind(this));
- },
- _setTime: function (date) {
- var _date = dp.getParsedDate(date);
- this._handleDate(date);
- this.hours = _date.hours < this.minHours ? this.minHours : _date.hours;
- this.minutes = _date.minutes < this.minMinutes ? this.minMinutes : _date.minutes;
- },
- /**
- * Sets minHours and minMinutes from date (usually it's a minDate)
- * Also changes minMinutes if current hours are bigger then @date hours
- * @param date {Date}
- * @private
- */
- _setMinTimeFromDate: function (date) {
- this.minHours = date.getHours();
- this.minMinutes = date.getMinutes();
- // If, for example, min hours are 10, and current hours are 12,
- // update minMinutes to default value, to be able to choose whole range of values
- if (this.d.lastSelectedDate) {
- if (this.d.lastSelectedDate.getHours() > date.getHours()) {
- this.minMinutes = this.opts.minMinutes;
- }
- }
- },
- _setMaxTimeFromDate: function (date) {
- this.maxHours = date.getHours();
- this.maxMinutes = date.getMinutes();
- if (this.d.lastSelectedDate) {
- if (this.d.lastSelectedDate.getHours() < date.getHours()) {
- this.maxMinutes = this.opts.maxMinutes;
- }
- }
- },
- _setDefaultMinMaxTime: function () {
- var maxHours = 23,
- maxMinutes = 59,
- opts = this.opts;
- this.minHours = opts.minHours < 0 || opts.minHours > maxHours ? 0 : opts.minHours;
- this.minMinutes = opts.minMinutes < 0 || opts.minMinutes > maxMinutes ? 0 : opts.minMinutes;
- this.maxHours = opts.maxHours < 0 || opts.maxHours > maxHours ? maxHours : opts.maxHours;
- this.maxMinutes = opts.maxMinutes < 0 || opts.maxMinutes > maxMinutes ? maxMinutes : opts.maxMinutes;
- },
- /**
- * Looks for min/max hours/minutes and if current values
- * are out of range sets valid values.
- * @private
- */
- _validateHoursMinutes: function (date) {
- if (this.hours < this.minHours) {
- this.hours = this.minHours;
- } else if (this.hours > this.maxHours) {
- this.hours = this.maxHours;
- }
- if (this.minutes < this.minMinutes) {
- this.minutes = this.minMinutes;
- } else if (this.minutes > this.maxMinutes) {
- this.minutes = this.maxMinutes;
- }
- },
- _buildHTML: function () {
- var lz = dp.getLeadingZeroNum,
- data = {
- hourMin: this.minHours,
- hourMax: lz(this.maxHours),
- hourStep: this.opts.hoursStep,
- hourValue: this.hours,
- hourVisible: lz(this.displayHours),
- minMin: this.minMinutes,
- minMax: lz(this.maxMinutes),
- minStep: this.opts.minutesStep,
- minValue: lz(this.minutes)
- },
- _template = dp.template(template, data);
- this.$timepicker = $(_template).appendTo(this.d.$datepicker);
- this.$ranges = $('[type="range"]', this.$timepicker);
- this.$hours = $('[name="hours"]', this.$timepicker);
- this.$minutes = $('[name="minutes"]', this.$timepicker);
- this.$hoursText = $('.datepicker--time-current-hours', this.$timepicker);
- this.$minutesText = $('.datepicker--time-current-minutes', this.$timepicker);
- if (this.d.ampm) {
- this.$ampm = $('<span class="datepicker--time-current-ampm">')
- .appendTo($('.datepicker--time-current', this.$timepicker))
- .html(this.dayPeriod);
- this.$timepicker.addClass('-am-pm-');
- }
- },
- _updateCurrentTime: function () {
- var h = dp.getLeadingZeroNum(this.displayHours),
- m = dp.getLeadingZeroNum(this.minutes);
- this.$hoursText.html(h);
- this.$minutesText.html(m);
- if (this.d.ampm) {
- this.$ampm.html(this.dayPeriod);
- }
- },
- _updateRanges: function () {
- this.$hours.attr({
- min: this.minHours,
- max: this.maxHours
- }).val(this.hours);
- this.$minutes.attr({
- min: this.minMinutes,
- max: this.maxMinutes
- }).val(this.minutes)
- },
- /**
- * Sets minHours, minMinutes etc. from date. If date is not passed, than sets
- * values from options
- * @param [date] {object} - Date object, to get values from
- * @private
- */
- _handleDate: function (date) {
- this._setDefaultMinMaxTime();
- if (date) {
- if (dp.isSame(date, this.d.opts.minDate)) {
- this._setMinTimeFromDate(this.d.opts.minDate);
- } else if (dp.isSame(date, this.d.opts.maxDate)) {
- this._setMaxTimeFromDate(this.d.opts.maxDate);
- }
- }
- this._validateHoursMinutes(date);
- },
- update: function () {
- this._updateRanges();
- this._updateCurrentTime();
- },
- /**
- * Calculates valid hour value to display in text input and datepicker's body.
- * @param date {Date|Number} - date or hours
- * @param [ampm] {Boolean} - 12 hours mode
- * @returns {{hours: *, dayPeriod: string}}
- * @private
- */
- _getValidHoursFromDate: function (date, ampm) {
- var d = date,
- hours = date;
- if (date instanceof Date) {
- d = dp.getParsedDate(date);
- hours = d.hours;
- }
- var _ampm = ampm || this.d.ampm,
- dayPeriod = 'am';
- if (_ampm) {
- switch(true) {
- case hours == 0:
- hours = 12;
- break;
- case hours == 12:
- dayPeriod = 'pm';
- break;
- case hours > 11:
- hours = hours - 12;
- dayPeriod = 'pm';
- break;
- default:
- break;
- }
- }
- return {
- hours: hours,
- dayPeriod: dayPeriod
- }
- },
- set hours (val) {
- this._hours = val;
- var displayHours = this._getValidHoursFromDate(val);
- this.displayHours = displayHours.hours;
- this.dayPeriod = displayHours.dayPeriod;
- },
- get hours() {
- return this._hours;
- },
- // Events
- // -------------------------------------------------
- _onChangeRange: function (e) {
- var $target = $(e.target),
- name = $target.attr('name');
- this.d.timepickerIsActive = true;
- this[name] = $target.val();
- this._updateCurrentTime();
- this.d._trigger('timeChange', [this.hours, this.minutes]);
- this._handleDate(this.d.lastSelectedDate);
- this.update()
- },
- _onSelectDate: function (e, data) {
- this._handleDate(data);
- this.update();
- },
- _onMouseEnterRange: function (e) {
- var name = $(e.target).attr('name');
- $('.datepicker--time-current-' + name, this.$timepicker).addClass('-focus-');
- },
- _onMouseOutRange: function (e) {
- var name = $(e.target).attr('name');
- if (this.d.inFocus) return; // Prevent removing focus when mouse out of range slider
- $('.datepicker--time-current-' + name, this.$timepicker).removeClass('-focus-');
- },
- _onMouseUpRange: function (e) {
- this.d.timepickerIsActive = false;
- }
- };
- })();
- })(window, jQuery);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement