From 861e59919ec7cd888f920badb38fb5e9d2adf177 Mon Sep 17 00:00:00 2001 From: bellord13 Date: Tue, 17 Aug 2021 22:01:03 +0300 Subject: [PATCH] fixNsv --- assets/air-datepicker/js/datepicker.js | 2236 ---------------- assets/bsCore/bsCore.js | 20 +- assets/core/core.js | 8 +- assets/core/core.register.js | 16 +- .../css/datepicker.css | 0 .../css/datepicker.min.css | 0 assets/datepicker/js/datepicker.js | 2256 +++++++++++++++++ .../js/datepicker.min.js | 0 .../js/i18n/datepicker.cs.js | 0 .../js/i18n/datepicker.da.js | 0 .../js/i18n/datepicker.de.js | 0 .../js/i18n/datepicker.en.js | 0 .../js/i18n/datepicker.es.js | 0 .../js/i18n/datepicker.fi.js | 0 .../js/i18n/datepicker.fr.js | 0 .../js/i18n/datepicker.hu.js | 0 .../js/i18n/datepicker.nl.js | 0 .../js/i18n/datepicker.pl.js | 0 .../js/i18n/datepicker.pt-BR.js | 0 .../js/i18n/datepicker.pt.js | 0 .../js/i18n/datepicker.ro.js | 0 assets/datepicker/js/i18n/datepicker.ru.js | 12 + .../js/i18n/datepicker.sk.js | 0 .../js/i18n/datepicker.zh.js | 0 assets/mask/mask.js | 60 +- assets/toolkit/toolkit.css | 75 +- assets/toolkit/toolkit.js | 77 +- templates/button.php | 3 +- templates/input.php | 13 +- tests/cheatsheet.php | 49 +- 30 files changed, 2501 insertions(+), 2324 deletions(-) delete mode 100644 assets/air-datepicker/js/datepicker.js rename assets/{air-datepicker => datepicker}/css/datepicker.css (100%) rename assets/{air-datepicker => datepicker}/css/datepicker.min.css (100%) create mode 100644 assets/datepicker/js/datepicker.js rename assets/{air-datepicker => datepicker}/js/datepicker.min.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.cs.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.da.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.de.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.en.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.es.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.fi.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.fr.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.hu.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.nl.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.pl.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.pt-BR.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.pt.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.ro.js (100%) create mode 100644 assets/datepicker/js/i18n/datepicker.ru.js rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.sk.js (100%) rename assets/{air-datepicker => datepicker}/js/i18n/datepicker.zh.js (100%) diff --git a/assets/air-datepicker/js/datepicker.js b/assets/air-datepicker/js/datepicker.js deleted file mode 100644 index ad69b4f..0000000 --- a/assets/air-datepicker/js/datepicker.js +++ /dev/null @@ -1,2236 +0,0 @@ -;(function (window, $, undefined) { ;(function () { - var VERSION = '2.2.3', - pluginName = 'datepicker', - autoInitSelector = '.datepicker-here', - $body, $datepickersContainer, - containerBuilt = false, - baseTemplate = '' + - '
' + - '' + - '' + - '
' + - '
', - 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: '', - nextHtml: '', - navTitles: { - days: 'MM, yyyy', - 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('
'); - $datepickersContainer = $('#datepickers-container'); - }, - - _buildBaseHtml: function () { - var $appendTarget, - $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:'' + - '
' + - '
' + - '
' + - '
', - months: '' + - '
' + - '
' + - '
', - years: '' + - '
' + - '
' + - '
' - }, - 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 += '
' + this.d.loc.daysMin[curDay] + '
'; - - 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 '
' + content.html + '
'; - }, - - /** - * 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 '
' + content.html + '
' - }, - - _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 '
' + content.html + '
' - }, - - _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 = '' + - '
#{prevHtml}
' + - '
#{title}
' + - '
#{nextHtml}
', - buttonsContainerTemplate = '
', - button = '#{label}', - 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 = '
' + - '
' + - ' #{hourVisible}' + - ' :' + - ' #{minValue}' + - '
' + - '
' + - '
' + - ' ' + - '
' + - '
' + - ' ' + - '
' + - '
' + - '
', - 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 = $('') - .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); \ No newline at end of file diff --git a/assets/bsCore/bsCore.js b/assets/bsCore/bsCore.js index dbb72a5..bd27114 100644 --- a/assets/bsCore/bsCore.js +++ b/assets/bsCore/bsCore.js @@ -1,11 +1,12 @@ kit.PluginManager.register('bsCore', function(module, exports, require, global){ - module.exports = { - dom: {}, - util: {}, - }; - var dom = module.exports.dom; - var util = module.exports.util; + /** + * @class kit.bsCore + */ + var bsCore = {}; + var dom = {}; + var util = {}; + /** * -------------------------------------------------------------------------- @@ -1269,7 +1270,7 @@ kit.PluginManager.register('bsCore', function(module, exports, require, global){ * -------------------------------------------------------------------------- */ - module.exports.BaseComponent = function (Data, executeAfterTransition, getElement, EventHandler) { + bsCore.BaseComponent = function (Data, executeAfterTransition, getElement, EventHandler) { const VERSION = '5.0.2' @@ -1333,6 +1334,11 @@ kit.PluginManager.register('bsCore', function(module, exports, require, global){ dom.EventHandler ); + bsCore.util = util; + bsCore.dom = dom; + + + module.exports = bsCore; return module.exports; }); \ No newline at end of file diff --git a/assets/core/core.js b/assets/core/core.js index c928104..888c1e7 100644 --- a/assets/core/core.js +++ b/assets/core/core.js @@ -1,3 +1,8 @@ +/** + * @class kit + * @property {kit.bsCore} + * @property {kit.toolkit} + */ window.kit = window.kit || {}; (function(global){ var stackPromise = {}; @@ -551,4 +556,5 @@ window.kit = window.kit || {}; global.PluginManager = manager; global.exec = manager.exec.bind(manager); global.require = manager.require.bind(manager); -})(kit || window); \ No newline at end of file +})(kit || window); + diff --git a/assets/core/core.register.js b/assets/core/core.register.js index 83539dd..4a5147e 100644 --- a/assets/core/core.register.js +++ b/assets/core/core.register.js @@ -76,9 +76,7 @@ kit.PluginManager.registerPlugins({ deps: ['bsCore'], onRegister: function (plugin) { plugin.onLoadConditionHandler = function (event) { - console.log('1',event); if(event.target && event.target.dataset && event.target.dataset.bsTarget && event.target.dataset.bsToggle === 'modal') { - console.log('2'); kit.exec(plugin.id, function(){ var newEvent = new Event("click"); event.target.dispatchEvent(newEvent); @@ -107,6 +105,20 @@ kit.PluginManager.registerPlugins({ onInstall: function (plugin) { }, }, + datepicker: { + path: '/local/templates.dev/kit/assets/datepicker', + module: '/js/datepicker.js', + type: 'loader', + css: [ + '/css/datepicker.css', + ], + deps: ['jquery'], + onRegister: function (plugin) { + kit.PluginManager.install(plugin.id) + }, + onInstall: function (plugin) { + }, + }, }); diff --git a/assets/air-datepicker/css/datepicker.css b/assets/datepicker/css/datepicker.css similarity index 100% rename from assets/air-datepicker/css/datepicker.css rename to assets/datepicker/css/datepicker.css diff --git a/assets/air-datepicker/css/datepicker.min.css b/assets/datepicker/css/datepicker.min.css similarity index 100% rename from assets/air-datepicker/css/datepicker.min.css rename to assets/datepicker/css/datepicker.min.css diff --git a/assets/datepicker/js/datepicker.js b/assets/datepicker/js/datepicker.js new file mode 100644 index 0000000..9445b8e --- /dev/null +++ b/assets/datepicker/js/datepicker.js @@ -0,0 +1,2256 @@ +kit.PluginManager.register('datepicker', function(module, exports, require, global){ + + var jQuery = $ = require('jquery'); + + + ;(function (window, $, undefined) { + + ;(function () { + var VERSION = '2.2.3', + pluginName = 'datepicker', + autoInitSelector = '.datepicker-here', + $body, $datepickersContainer, + containerBuilt = false, + baseTemplate = '' + + '
' + + '' + + '' + + '
' + + '
', + 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: '', + nextHtml: '', + navTitles: { + days: 'MM, yyyy', + 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() + }; + var triggerEvent = function (el, eventName, options) { + var event; + if (window.CustomEvent) { + event = new CustomEvent(eventName, options); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(eventName, true, true, options); + } + el.dispatchEvent(event); + }; + 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('
'); + $datepickersContainer = $('#datepickers-container'); + }, + + _buildBaseHtml: function () { + var $appendTarget, + $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); + triggerEvent(this.$el[0], 'input', { 'bubbles': true }); + }, + + /** + * 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; + this.$el.addClass('focus'); + if (onShow) { + this._bindVisionEvents(onShow) + } + }, + + hide: function () { + var onHide = this.opts.onHide; + + this.$datepicker + .removeClass('active') + .css({ + left: '-100000px' + }); + + this.focused = ''; + this.keys = []; + + this.$el.removeClass('focus'); + + 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:'' + + '
' + + '
' + + '
' + + '
', + months: '' + + '
' + + '
' + + '
', + years: '' + + '
' + + '
' + + '
' + }, + 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 += '
' + this.d.loc.daysMin[curDay] + '
'; + + 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 '
' + content.html + '
'; + }, + + /** + * 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 '
' + content.html + '
' + }, + + _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 '
' + content.html + '
' + }, + + _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 = '' + + '
#{prevHtml}
' + + '
#{title}
' + + '
#{nextHtml}
', + buttonsContainerTemplate = '
', + button = '#{label}', + 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 = '
' + + '
' + + ' #{hourVisible}' + + ' :' + + ' #{minValue}' + + '
' + + '
' + + '
' + + ' ' + + '
' + + '
' + + ' ' + + '
' + + '
' + + '
', + 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 = $('') + .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); + +}); \ No newline at end of file diff --git a/assets/air-datepicker/js/datepicker.min.js b/assets/datepicker/js/datepicker.min.js similarity index 100% rename from assets/air-datepicker/js/datepicker.min.js rename to assets/datepicker/js/datepicker.min.js diff --git a/assets/air-datepicker/js/i18n/datepicker.cs.js b/assets/datepicker/js/i18n/datepicker.cs.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.cs.js rename to assets/datepicker/js/i18n/datepicker.cs.js diff --git a/assets/air-datepicker/js/i18n/datepicker.da.js b/assets/datepicker/js/i18n/datepicker.da.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.da.js rename to assets/datepicker/js/i18n/datepicker.da.js diff --git a/assets/air-datepicker/js/i18n/datepicker.de.js b/assets/datepicker/js/i18n/datepicker.de.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.de.js rename to assets/datepicker/js/i18n/datepicker.de.js diff --git a/assets/air-datepicker/js/i18n/datepicker.en.js b/assets/datepicker/js/i18n/datepicker.en.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.en.js rename to assets/datepicker/js/i18n/datepicker.en.js diff --git a/assets/air-datepicker/js/i18n/datepicker.es.js b/assets/datepicker/js/i18n/datepicker.es.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.es.js rename to assets/datepicker/js/i18n/datepicker.es.js diff --git a/assets/air-datepicker/js/i18n/datepicker.fi.js b/assets/datepicker/js/i18n/datepicker.fi.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.fi.js rename to assets/datepicker/js/i18n/datepicker.fi.js diff --git a/assets/air-datepicker/js/i18n/datepicker.fr.js b/assets/datepicker/js/i18n/datepicker.fr.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.fr.js rename to assets/datepicker/js/i18n/datepicker.fr.js diff --git a/assets/air-datepicker/js/i18n/datepicker.hu.js b/assets/datepicker/js/i18n/datepicker.hu.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.hu.js rename to assets/datepicker/js/i18n/datepicker.hu.js diff --git a/assets/air-datepicker/js/i18n/datepicker.nl.js b/assets/datepicker/js/i18n/datepicker.nl.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.nl.js rename to assets/datepicker/js/i18n/datepicker.nl.js diff --git a/assets/air-datepicker/js/i18n/datepicker.pl.js b/assets/datepicker/js/i18n/datepicker.pl.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.pl.js rename to assets/datepicker/js/i18n/datepicker.pl.js diff --git a/assets/air-datepicker/js/i18n/datepicker.pt-BR.js b/assets/datepicker/js/i18n/datepicker.pt-BR.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.pt-BR.js rename to assets/datepicker/js/i18n/datepicker.pt-BR.js diff --git a/assets/air-datepicker/js/i18n/datepicker.pt.js b/assets/datepicker/js/i18n/datepicker.pt.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.pt.js rename to assets/datepicker/js/i18n/datepicker.pt.js diff --git a/assets/air-datepicker/js/i18n/datepicker.ro.js b/assets/datepicker/js/i18n/datepicker.ro.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.ro.js rename to assets/datepicker/js/i18n/datepicker.ro.js diff --git a/assets/datepicker/js/i18n/datepicker.ru.js b/assets/datepicker/js/i18n/datepicker.ru.js new file mode 100644 index 0000000..f4e5297 --- /dev/null +++ b/assets/datepicker/js/i18n/datepicker.ru.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['ru'] = { + days: ['Воскресенье','Понедельник','Вторник','Среда','Четверг','Пятница','Суббота'], + daysShort: ['Вос','Пон','Вто','Сре','Чет','Пят','Суб'], + daysMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], + months: ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], + monthsShort: ['Янв','Фев','Мар','Апр','Май','Июн','Июл','Авг','Сен','Окт','Ноя','Дек'], + today: 'Сегодня', + clear: 'Очистить', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/assets/air-datepicker/js/i18n/datepicker.sk.js b/assets/datepicker/js/i18n/datepicker.sk.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.sk.js rename to assets/datepicker/js/i18n/datepicker.sk.js diff --git a/assets/air-datepicker/js/i18n/datepicker.zh.js b/assets/datepicker/js/i18n/datepicker.zh.js similarity index 100% rename from assets/air-datepicker/js/i18n/datepicker.zh.js rename to assets/datepicker/js/i18n/datepicker.zh.js diff --git a/assets/mask/mask.js b/assets/mask/mask.js index af396f5..f15282d 100644 --- a/assets/mask/mask.js +++ b/assets/mask/mask.js @@ -58,6 +58,16 @@ kit.PluginManager.register('mask', function(module, exports, require){ return this.trigger("unmask"); }, mask: function(mask, settings) { + var triggerEvent = function (el, eventName, options) { + var event; + if (window.CustomEvent) { + event = new CustomEvent(eventName, options); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(eventName, true, true, options); + } + el.dispatchEvent(event); + }; var input, defs, tests, @@ -193,6 +203,7 @@ kit.PluginManager.register('mask', function(module, exports, require){ } function androidInputEvent(e) { + console.log('androidInputEvent'); var curVal = input.val(); var pos = input.caret(); if (oldVal && oldVal.length && oldVal.length > curVal.length ) { @@ -228,6 +239,7 @@ kit.PluginManager.register('mask', function(module, exports, require){ function blurEvent(e) { + console.log('blurEvent'); clearInterval(actualCaretID); checkVal(); @@ -235,7 +247,10 @@ kit.PluginManager.register('mask', function(module, exports, require){ input.change(); } + var inputCancel = false; + function keydownEvent(e) { + console.log('keydownEvent'); if (input.prop("readonly")){ return; } @@ -259,6 +274,8 @@ kit.PluginManager.register('mask', function(module, exports, require){ shiftL(begin, end - 1); e.preventDefault(); + inputCancel = true; + triggerEvent(input[0], 'input', { 'bubbles': true }); } else if( k === 13 ) { // enter blurEvent.call(this, e); } else if (k === 27) { // escape @@ -269,6 +286,7 @@ kit.PluginManager.register('mask', function(module, exports, require){ } function keypressEvent(e) { + console.log('keypressEvent'); if (input.prop("readonly")){ return; } @@ -313,6 +331,8 @@ kit.PluginManager.register('mask', function(module, exports, require){ } } e.preventDefault(); + inputCancel = true; + triggerEvent(input[0], 'input', { 'bubbles': true }); } } @@ -412,7 +432,7 @@ kit.PluginManager.register('mask', function(module, exports, require){ function getRaw() { - console.log('mask input.data($.mask.dataName)'); + checkVal(); return $.map(buffer, function(c, i) { return tests[i]&&c!=getPlaceholder(i) ? c : null; }).join(''); @@ -430,6 +450,7 @@ kit.PluginManager.register('mask', function(module, exports, require){ }); function focusEvent () { + console.log('focusEvent'); if (input.prop("readonly")){ return; } @@ -442,20 +463,32 @@ kit.PluginManager.register('mask', function(module, exports, require){ pos = checkVal(); caretTimeoutId = setTimeout(function(){ + console.log('caretTimeoutId') if(input.get(0) !== document.activeElement){ return; } writeBuffer(); if (pos == mask.replace("?","").length) { - input.caret(0, pos); + //input.caret(0, pos); + input.caret(pos); } else { input.caret(pos); } - }, 10); } + function unmask() { + // console.log('mask one unmask'); + input + .off(".mask") + .removeData($.mask.dataName); + if(isInput) { + input.removeData('maskCall'); + } + delete input[0]['mask']; + } + function actualCaret(){ var pos = checkVal(true), c = input.caret(); @@ -467,15 +500,7 @@ kit.PluginManager.register('mask', function(module, exports, require){ } } input - .one("unmask", function() { - // console.log('mask one unmask'); - input - .off(".mask") - .removeData($.mask.dataName); - if(isInput) { - input.removeData('maskCall'); - } - }); + .one("unmask", unmask); isInput && input .on("focus.mask", focusEvent) .on("blur.mask", blurEvent) @@ -483,6 +508,11 @@ kit.PluginManager.register('mask', function(module, exports, require){ .on("keypress.mask", keypressEvent); input .on("input.mask paste.mask", function() { + if(inputCancel) { + inputCancel = false; + return; + } + console.log('input.mask paste.mask'); if (input.prop("readonly")){ return; } @@ -510,6 +540,12 @@ kit.PluginManager.register('mask', function(module, exports, require){ isInput && input.on('input.mask', androidInputEvent); } checkVal(); //Perform initial check for existing values + + this.mask = { + unmask: unmask, + getRaw: getRaw, + isValid: isValid, + }; }); }, }); diff --git a/assets/toolkit/toolkit.css b/assets/toolkit/toolkit.css index b2856e3..1913476 100644 --- a/assets/toolkit/toolkit.css +++ b/assets/toolkit/toolkit.css @@ -182,7 +182,9 @@ padding-right: 10px; padding-left: 10px; } -.kit-field.kit-field--bordered .kit-field__input:focus ~.kit-field__hr { +.kit-field.kit-field--bordered .kit-field__input:focus ~.kit-field__hr, +.kit-field.kit-field--bordered .kit-field__input.focus ~.kit-field__hr +{ border-color: var(--kit-color-primary); } .kit-field.kit-field--bordered .kit-field__input.kit-field--error ~.kit-field__hr @@ -220,10 +222,7 @@ overflow: hidden; } .kit-field textarea, -.kit-field input[type='password'], -.kit-field input[type='email'], -.kit-field input[type='text'], -.kit-field input[type='tel'], +.kit-field input, .kit-field .kit-field__display { pointer-events: auto; background-color: transparent; @@ -281,34 +280,24 @@ --line-clamp-height: var(--line-height-ratio); } .kit-field textarea:focus, -.kit-field input[type='password']:focus, -.kit-field input[type='email']:focus, -.kit-field input[type='text']:focus, -.kit-field input[type='number']:focus, -.kit-field input[type='tel']:focus, -.kit-field .kit-field__display:focus { +.kit-field input:focus, +.kit-field textarea.focus, +.kit-field input.focus { color: var(--kit-color-text); } .kit-field textarea:focus ~.kit-field__label, -.kit-field input[type='password']:focus ~.kit-field__label, -.kit-field input[type='email']:focus ~.kit-field__label, -.kit-field input[type='text']:focus ~.kit-field__label, -.kit-field input[type='number']:focus ~.kit-field__label, -.kit-field input[type='tel']:focus ~.kit-field__label, .kit-field input:focus ~.kit-field__label, -.kit-field .kit-field__display:focus ~.kit-field__label { +.kit-field textarea.focus ~.kit-field__label, +.kit-field input.focus ~.kit-field__label { top: 0; transform: translate(0, 0); font-size: calc(var(--font-size) * var(--kit-field-focus-label-zoom-ratio)); color: var(--kit-color-primary); } .kit-field textarea:focus ~.kit-field__hr:after, -.kit-field input[type='password']:focus ~.kit-field__hr:after, -.kit-field input[type='email']:focus ~.kit-field__hr:after, -.kit-field input[type='text']:focus ~.kit-field__hr:after, -.kit-field input[type='number']:focus ~.kit-field__hr:after, -.kit-field input[type='tel']:focus ~.kit-field__hr:after, -.kit-field .kit-field__display:focus ~.kit-field__hr:after { +.kit-field input:focus ~.kit-field__hr:after, +.kit-field textarea.focus ~.kit-field__hr:after, +.kit-field input.focus ~.kit-field__hr:after { left: 0; width: 100%; } @@ -402,6 +391,19 @@ .kit-field .kit-field--error ~.kit-field__hr:after { border-color: var(--kit-color-error) !important; } + +.kit-field .kit-field--warning ~.kit-field__message +{ + opacity: 1; + visibility: visible; + color: var(--kit-color-warning); +} +.kit-field .kit-field--warning ~.kit-field__label { + color: var(--kit-color-warning) !important; +} +.kit-field .kit-field--warning ~.kit-field__hr:after { + border-color: var(--kit-color-warning) !important; +} .kit-field__text { display: block; -webkit-user-select: none; @@ -1130,7 +1132,8 @@ select.kit-field__input:disabled ~.kit-field__hr { .kit-field--success ~.kit-field__hr { border-color: var(--kit-color-success) !important; } -.kit-field--success:focus ~.kit-field__hr:after { +.kit-field--success:focus ~.kit-field__hr:after, +.kit-field--success.focus ~.kit-field__hr:after { border-color: var(--kit-color-success) !important; } @@ -1186,27 +1189,15 @@ select.kit-field__input:disabled ~.kit-field__hr { .kit-field textarea[readonly]:focus, -.kit-field input[type='password'][readonly]:focus, -.kit-field input[type='email'][readonly]:focus, -.kit-field input[type='text'][readonly]:focus, -.kit-field input[type='tel'][readonly]:focus, -.kit-field .kit-field__display[readonly]:focus { - color: var(--kit-color-readonly); -} -.kit-field textarea[readonly]:focus, -.kit-field input[type='password'][readonly], -.kit-field input[type='email'][readonly], -.kit-field input[type='text'][readonly], -.kit-field input[type='tel'][readonly], -.kit-field .kit-field__display[readonly] { +.kit-field input[readonly]:focus, +.kit-field textarea[readonly].focus, +.kit-field input[readonly].focus { color: var(--kit-color-readonly); } .kit-field textarea[readonly]:focus ~.kit-field__label, -.kit-field input[type='password'][readonly]:focus ~.kit-field__label, -.kit-field input[type='email'][readonly]:focus ~.kit-field__label, -.kit-field input[type='text'][readonly]:focus ~.kit-field__label, -.kit-field input[type='tel'][readonly]:focus ~.kit-field__label, -.kit-field .kit-field__display[readonly]:focus ~.kit-field__label +.kit-field input[readonly]:focus ~.kit-field__label, +.kit-field textarea[readonly].focus ~.kit-field__label, +.kit-field input[readonly].focus ~.kit-field__label { color: var(--kit-color-readonly); } diff --git a/assets/toolkit/toolkit.js b/assets/toolkit/toolkit.js index 6a419b5..66fd5d0 100644 --- a/assets/toolkit/toolkit.js +++ b/assets/toolkit/toolkit.js @@ -3,6 +3,7 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { var $ = require('jquery'); + var __Config = function () { function Config() { @@ -227,7 +228,6 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { key; if (Object.keys(messageObject).length) { - console.log('1'); for (key in messageObject) { msg = messageObject[key]; console.log(msg); @@ -270,7 +270,7 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { } document.addEventListener('click', clickHandler, false); - document.addEventListener('change', chahgeHandler, false); + document.addEventListener('change', changeHandler, false); document.addEventListener('keydown', escapeKeyHandler, false); window.addEventListener('resize', resizeHandler, false); @@ -346,9 +346,10 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { } // изменение инпута - function chahgeHandler(e) { + function changeHandler(e) { var select = e.target; changeSelect(select); + console.log('changeHandler'); } /** @@ -702,6 +703,7 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { this.init(); + console.log('Inputs constructor'); window.addEventListener('resize', function () { return _this.refresh(); @@ -716,6 +718,7 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { return _this.refresh(); }, false); document.addEventListener('input', function (e) { + console.log('input'); return _this.changeFiled(e); }, false); document.addEventListener('paste', function (e) { @@ -728,17 +731,34 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { return _this.changeFiled(e); }, false); document.addEventListener('change', function (e) { + console.log('change'); return _this.switchField(e); }, false); } Inputs.prototype.checkDirty = function checkDirty(element) { - return !element.value && !element.placeholder.length ? element.setAttribute('data-dirty', 'false') : element.setAttribute('data-dirty', 'true'); + var bDirty = false; + + if(element.placeholder.length) { + element.setAttribute('data-dirty', 'true'); + return true; + } + + if(element.mask) { + var raw = element.mask.getRaw(); + bDirty = !!raw.length; + } else { + bDirty = !!element.value; + } + + element.setAttribute('data-dirty', bDirty?'true':'false'); + return bDirty; }; Inputs.prototype.changeFiled = function changeFiled(e) { + console.log('changeFiled'); var _this2 = this; var target = e.target || e; if (target.classList.contains('kit-field__input')) { @@ -818,7 +838,7 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { } }; - Inputs.prototype.setMask = function setMask() { + Inputs.prototype.setTelMask = function () { var _this3 = this; $('[type=tel]').mask(Config.mask.tel, { @@ -826,21 +846,42 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { _this3.fieldNormalize(this); } }).on('blur.mask', function (e) { - _this3.checkDirty(e.currentTarget); + //_this3.checkDirty(e.currentTarget); }); }; - Inputs.prototype.unsetMask = function unsetMask() { + Inputs.prototype.setMask = function () { + var _this3 = this; + + var node = $('[data-mask]'); + + node.each(function(index, item){ + item = $(item); + var placeholder = item.attr('data-mask-placeholder'); + placeholder = placeholder?placeholder:'_'; + item.mask(item.attr('data-mask'), { + placeholder: placeholder, + completed: function completed() { + _this3.fieldNormalize(this); + } + }).on('blur.mask', function (e) { + //_this3.checkDirty(e.currentTarget); + }); + }); + }; + + Inputs.prototype.unsetTelMask = function() { $('input[type=tel]').unmask(); }; Inputs.prototype.init = function init() { this.checkAllInputs(); this.setMask(); + this.setTelMask(); }; Inputs.prototype.refresh = function refresh() { - this.unsetMask(); + this.unsetTelMask(); this.init(); }; @@ -893,11 +934,21 @@ kit.PluginManager.register('toolkit',function(module, exports, require) { var Inputs = new __Inputs(); - module.exports.Helper = Helper; - module.exports.Select = Select(); - module.exports.Config = Config; - module.exports.Message = Message; - module.exports.Inputs = Inputs; + /** + * @class kit.toolkit + */ + var toolkit = { + Helper: Helper, + Select: Select(), + Config: Config, + Message: Message, + Inputs: Inputs, + }; + + + Object.assign(module.exports, toolkit); + + return module.exports; }); diff --git a/templates/button.php b/templates/button.php index 0bfaae1..6a30106 100644 --- a/templates/button.php +++ b/templates/button.php @@ -9,7 +9,6 @@ $preloader = \Wt\Core\Tools::isTrue($arParams['PRELOADER']); -use Wt\Core\Type\Str as Str; ?>