app/assets/javascripts/jquery.xdan.datetimepicker.full.js in xdan-datetimepicker-rails-2.5.1 vs app/assets/javascripts/jquery.xdan.datetimepicker.full.js in xdan-datetimepicker-rails-2.5.2

- old
+ new

@@ -573,11 +573,11 @@ } return ''; } }; })();/** - * @preserve jQuery DateTimePicker plugin v2.4.9 + * @preserve jQuery DateTimePicker plugin v2.5.1 * @homepage http://xdsoft.net/jqplugins/datetimepicker/ * @author Chupurnov Valeriy (<chupurnov@gmail.com>) */ /*global DateFormatter, document,window,jQuery,setTimeout,clearTimeout,HighlightedDate,getCurrentValue*/ ;(function (factory) { @@ -1089,10 +1089,19 @@ ], dayOfWeek: [ "Dumengia", "Glindesdi", "Mardi", "Mesemna", "Gievgia", "Venderdi", "Sonda" ] }, + ka: { // Georgian + months: [ + 'იანვარი', 'თებერვალი', 'მარტი', 'აპრილი', 'მაისი', 'ივნისი', 'ივლისი', 'აგვისტო', 'სექტემბერი', 'ოქტომბერი', 'ნოემბერი', 'დეკემბერი' + ], + dayOfWeekShort: [ + "კვ", "ორშ", "სამშ", "ოთხ", "ხუთ", "პარ", "შაბ" + ], + dayOfWeek: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი"] + }, }, value: '', rtl: false, format: 'Y/m/d H:i', @@ -1178,56 +1187,59 @@ disabledWeekDays: [], yearOffset: 0, beforeShowDay: null, enterLikeTab: true, - showApplyButton: false + showApplyButton: false }; var dateHelper = null, globalLocaleDefault = 'en', globalLocale = 'en'; - + var dateFormatterOptionsDefault = { meridiem: ['AM', 'PM'] }; - + var initDateFormatter = function(){ var locale = default_options.i18n[globalLocale], opts = { days: locale.dayOfWeek, daysShort: locale.dayOfWeekShort, months: locale.months, - monthsShort: $.map(locale.months, function(n){ return n.substring(0, 3) }), + monthsShort: $.map(locale.months, function(n){ return n.substring(0, 3) }), }; - + dateHelper = new DateFormatter({ dateSettings: $.extend({}, dateFormatterOptionsDefault, opts) }); }; - + // for locale settings $.datetimepicker = { setLocale: function(locale){ var newLocale = default_options.i18n[locale]?locale:globalLocaleDefault; if(globalLocale != newLocale){ globalLocale = newLocale; // reinit date formatter initDateFormatter(); } }, + setDateFormatter: function(dateFormatter) { + dateHelper = dateFormatter; + }, RFC_2822: 'D, d M Y H:i:s O', ATOM: 'Y-m-d\TH:i:sP', ISO_8601: 'Y-m-d\TH:i:sO', RFC_822: 'D, d M y H:i:s O', RFC_850: 'l, d-M-y H:i:s T', RFC_1036: 'D, d M y H:i:s O', RFC_1123: 'D, d M Y H:i:s O', RSS: 'D, d M Y H:i:s O', W3C: 'Y-m-d\TH:i:sP' }; - + // first init date formatter initDateFormatter(); // fix for ie8 if (!window.getComputedStyle) { @@ -1274,11 +1286,10 @@ out.x = e.clientX; out.y = e.clientY; } return out; }, - move = 0, timebox, parentHeight, height, scrollbar, scroller, @@ -1344,11 +1355,11 @@ if (touchStart) { event.preventDefault(); calcOffset(event); } }) - .on('touchend touchcancel', function (event) { + .on('touchend touchcancel', function () { touchStart = false; startTopScroll = 0; }); timeboxparent @@ -1406,22 +1417,22 @@ var coord = pointerEventToXY(event); timeboxparent.trigger('scroll_element.xdsoft_scroller', [(startTop - (coord.y - start.y)) / (height - parentHeight)]); } }); - timeboxparent.on('touchend touchcancel', function (event) { + timeboxparent.on('touchend touchcancel', function () { start = false; startTop = 0; }); } timeboxparent.trigger('resize_scroll.xdsoft_scroller', [percent]); }); }; $.fn.datetimepicker = function (opt, opt2) { var result = this, - KEY0 = 48, + KEY0 = 48, KEY9 = 57, _KEY0 = 96, _KEY9 = 105, CTRLKEY = 17, DEL = 46, @@ -1446,11 +1457,11 @@ createDateTimePicker, destroyDateTimePicker, lazyInit = function (input) { input - .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function initOnActionCallback(event) { + .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function initOnActionCallback() { if (input.is(':disabled') || input.data('xdsoft_datetimepicker')) { return; } clearTimeout(lazyInitTimer); lazyInitTimer = setTimeout(function () { @@ -1475,24 +1486,24 @@ '<button type="button" class="xdsoft_next"></button></div>'), calendar = $('<div class="xdsoft_calendar"></div>'), timepicker = $('<div class="xdsoft_timepicker active"><button type="button" class="xdsoft_prev"></button><div class="xdsoft_time_box"></div><button type="button" class="xdsoft_next"></button></div>'), timeboxparent = timepicker.find('.xdsoft_time_box').eq(0), timebox = $('<div class="xdsoft_time_variant"></div>'), - applyButton = $('<button type="button" class="xdsoft_save_selected blue-gradient-button">Save Selected</button>'), + applyButton = $('<button type="button" class="xdsoft_save_selected blue-gradient-button">Save Selected</button>'), monthselect = $('<div class="xdsoft_select xdsoft_monthselect"><div></div></div>'), yearselect = $('<div class="xdsoft_select xdsoft_yearselect"><div></div></div>'), triggerAfterOpen = false, XDSoft_datetime, - + xchangeTimer, timerclick, current_time_index, setPos, timer = 0, - timer1 = 0, - _xdsoft_datetime; + _xdsoft_datetime, + forEachAncestorOf; if (options.id) { datetimepicker.attr('id', options.id); } if (options.style) { @@ -1551,11 +1562,11 @@ .xdsoftScroller() .on('touchstart mousedown.xdsoft', function (event) { event.stopPropagation(); event.preventDefault(); }) - .on('touchstart mousedown.xdsoft', '.xdsoft_option', function (event) { + .on('touchstart mousedown.xdsoft', '.xdsoft_option', function () { if (_xdsoft_datetime.currentTime === undefined || _xdsoft_datetime.currentTime === null) { _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); } var year = _xdsoft_datetime.currentTime.getFullYear(); @@ -1574,56 +1585,16 @@ options.onChangeYear.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); } }); datetimepicker.getValue = function () { - return _xdsoft_datetime.getCurrentTime(); - }; + return _xdsoft_datetime.getCurrentTime(); + }; datetimepicker.setOptions = function (_options) { - var highlightedDates = {}, - getCaretPos = function (input) { - try { - if (document.selection && document.selection.createRange) { - var range = document.selection.createRange(); - return range.getBookmark().charCodeAt(2) - 2; - } - if (input.setSelectionRange) { - return input.selectionStart; - } - } catch (e) { - return 0; - } - }, - setCaretPos = function (node, pos) { - node = (typeof node === "string" || node instanceof String) ? document.getElementById(node) : node; - if (!node) { - return false; - } - if (node.createTextRange) { - var textRange = node.createTextRange(); - textRange.collapse(true); - textRange.moveEnd('character', pos); - textRange.moveStart('character', pos); - textRange.select(); - return true; - } - if (node.setSelectionRange) { - node.setSelectionRange(pos, pos); - return true; - } - return false; - }, - isValidValue = function (mask, value) { - var reg = mask - .replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g, '\\$1') - .replace(/_/g, '{digit+}') - .replace(/([0-9]{1})/g, '{digit$1}') - .replace(/\{digit([0-9]{1})\}/g, '[0-$1_]{1}') - .replace(/\{digit[\+]\}/g, '[0-9_]{1}'); - return (new RegExp(reg)).test(value); - }; + var highlightedDates = {}; + options = $.extend(true, {}, options, _options); if (_options.allowTimes && $.isArray(_options.allowTimes) && _options.allowTimes.length) { options.allowTimes = $.extend(true, [], _options.allowTimes); } @@ -1637,11 +1608,11 @@ } if (_options.allowDateRe && Object.prototype.toString.call(_options.allowDateRe)==="[object String]") { options.allowDateRe = new RegExp(_options.allowDateRe); } - + if (_options.highlightedDates && $.isArray(_options.highlightedDates) && _options.highlightedDates.length) { $.each(_options.highlightedDates, function (index, value) { var splitData = $.map(value.split(','), $.trim), exDesc, hDate = new HighlightedDate(dateHelper.parseDate(splitData[0], options.formatDate), splitData[1], splitData[2]), // date, desc, style @@ -1704,11 +1675,11 @@ if (_options.disabledDates && $.isArray(_options.disabledDates) && _options.disabledDates.length) { options.disabledDates = $.extend(true, [], _options.disabledDates); } if (_options.disabledWeekDays && $.isArray(_options.disabledWeekDays) && _options.disabledWeekDays.length) { - options.disabledWeekDays = $.extend(true, [], _options.disabledWeekDays); + options.disabledWeekDays = $.extend(true, [], _options.disabledWeekDays); } if ((options.open || options.opened) && (!options.inline)) { input.trigger('open.xdsoft'); } @@ -1773,88 +1744,17 @@ mounth_picker .find('.' + options.next) .css('visibility', !options.nextButton ? 'hidden' : 'visible'); - if (options.mask) { - input.off('keydown.xdsoft'); + setMask(options); - if (options.mask === true) { - options.mask = options.format - .replace(/Y/g, '9999') - .replace(/F/g, '9999') - .replace(/m/g, '19') - .replace(/d/g, '39') - .replace(/H/g, '29') - .replace(/i/g, '59') - .replace(/s/g, '59'); - } - - if ($.type(options.mask) === 'string') { - if (!isValidValue(options.mask, input.val())) { - input.val(options.mask.replace(/[0-9]/g, '_')); - setCaretPos(input[0], 0); - } - - input.on('keydown.xdsoft', function (event) { - var val = this.value, - key = event.which, - pos, - digit; - - if (((key >= KEY0 && key <= KEY9) || (key >= _KEY0 && key <= _KEY9)) || (key === BACKSPACE || key === DEL)) { - pos = getCaretPos(this); - digit = (key !== BACKSPACE && key !== DEL) ? String.fromCharCode((_KEY0 <= key && key <= _KEY9) ? key - KEY0 : key) : '_'; - - if ((key === BACKSPACE || key === DEL) && pos) { - pos -= 1; - digit = '_'; - } - - while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) { - pos += (key === BACKSPACE || key === DEL) ? -1 : 1; - } - - val = val.substr(0, pos) + digit + val.substr(pos + 1); - if ($.trim(val) === '') { - val = options.mask.replace(/[0-9]/g, '_'); - } else { - if (pos === options.mask.length) { - event.preventDefault(); - return false; - } - } - - pos += (key === BACKSPACE || key === DEL) ? 0 : 1; - while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) { - pos += (key === BACKSPACE || key === DEL) ? -1 : 1; - } - - if (isValidValue(options.mask, val)) { - this.value = val; - setCaretPos(this, pos); - } else if ($.trim(val) === '') { - this.value = options.mask.replace(/[0-9]/g, '_'); - } else { - input.trigger('error_input.xdsoft'); - } - } else { - if (([AKEY, CKEY, VKEY, ZKEY, YKEY].indexOf(key) !== -1 && ctrlDown) || [ESC, ARROWUP, ARROWDOWN, ARROWLEFT, ARROWRIGHT, F5, CTRLKEY, TAB, ENTER].indexOf(key) !== -1) { - return true; - } - } - - event.preventDefault(); - return false; - }); - } - } if (options.validateOnBlur) { input .off('blur.xdsoft') .on('blur.xdsoft', function () { - if (options.allowBlank && !$.trim($(this).val()).length) { + if (options.allowBlank && (!$.trim($(this).val()).length || (typeof options.mask == "string" && $.trim($(this).val()) === options.mask.replace(/[0-9]/g, '_')))) { $(this).val(null); datetimepicker.data('xdsoft_datetime').empty(); } else if (!dateHelper.parseDate($(this).val(), options.format)) { var splittedHours = +([$(this).val()[0], $(this).val()[1]].join('')), splittedMinutes = +([$(this).val()[2], $(this).val()[3]].join('')); @@ -1872,10 +1772,11 @@ } else { datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val()); } datetimepicker.trigger('changedatetime.xdsoft'); + datetimepicker.trigger('close.xdsoft'); }); } options.dayOfWeekStartPrev = (options.dayOfWeekStart === 0) ? 6 : options.dayOfWeekStart - 1; datetimepicker @@ -2093,16 +1994,16 @@ }; _xdsoft_datetime = new XDSoft_datetime(); applyButton.on('touchend click', function (e) {//pathbrite - e.preventDefault(); - datetimepicker.data('changed', true); - _xdsoft_datetime.setCurrentTime(getCurrentValue()); - input.val(_xdsoft_datetime.str()); - datetimepicker.trigger('close.xdsoft'); - }); + e.preventDefault(); + datetimepicker.data('changed', true); + _xdsoft_datetime.setCurrentTime(getCurrentValue()); + input.val(_xdsoft_datetime.str()); + datetimepicker.trigger('close.xdsoft'); + }); mounth_picker .find('.xdsoft_today_button') .on('touchend mousedown.xdsoft', function () { datetimepicker.data('changed', true); _xdsoft_datetime.setCurrentTime(0); @@ -2165,11 +2066,24 @@ if ($this.hasClass(options.next) && (height - pheight) - options.timeHeightInTimePicker >= top) { timebox.css('marginTop', '-' + (top + options.timeHeightInTimePicker) + 'px'); } else if ($this.hasClass(options.prev) && top - options.timeHeightInTimePicker >= 0) { timebox.css('marginTop', '-' + (top - options.timeHeightInTimePicker) + 'px'); } - timeboxparent.trigger('scroll_element.xdsoft_scroller', [Math.abs(parseInt(timebox.css('marginTop'), 10) / (height - pheight))]); + /** + * Fixed bug: + * When using css3 transition, it will cause a bug that you cannot scroll the timepicker list. + * The reason is that the transition-duration time, if you set it to 0, all things fine, otherwise, this + * would cause a bug when you use jquery.css method. + * Let's say: * { transition: all .5s ease; } + * jquery timebox.css('marginTop') will return the original value which is before you clicking the next/prev button, + * meanwhile the timebox[0].style.marginTop will return the right value which is after you clicking the + * next/prev button. + * + * What we should do: + * Replace timebox.css('marginTop') with timebox[0].style.marginTop. + */ + timeboxparent.trigger('scroll_element.xdsoft_scroller', [Math.abs(parseInt(timebox[0].style.marginTop, 10) / (height - pheight))]); period = (period > 10) ? 10 : period - 10; if (!stop) { timer = setTimeout(arguments_callee4, v || period); } }(500)); @@ -2258,23 +2172,25 @@ } else { customDateSettings = null; } if(options.allowDateRe && Object.prototype.toString.call(options.allowDateRe) === "[object RegExp]"){ - if(!options.allowDateRe.test(start.dateFormat(options.formatDate))){ + if(!options.allowDateRe.test(dateHelper.formatDate(start, options.formatDate))){ classes.push('xdsoft_disabled'); } } else if(options.allowDates && options.allowDates.length>0){ - if(options.allowDates.indexOf(start.dateFormat(options.formatDate)) === -1){ + if(options.allowDates.indexOf(dateHelper.formatDate(start, options.formatDate)) === -1){ classes.push('xdsoft_disabled'); } } else if ((maxDate !== false && start > maxDate) || (minDate !== false && start < minDate) || (customDateSettings && customDateSettings[0] === false)) { classes.push('xdsoft_disabled'); } else if (options.disabledDates.indexOf(dateHelper.formatDate(start, options.formatDate)) !== -1) { classes.push('xdsoft_disabled'); } else if (options.disabledWeekDays.indexOf(day) !== -1) { - classes.push('xdsoft_disabled'); + classes.push('xdsoft_disabled'); + }else if (input.is('[readonly]')) { + classes.push('xdsoft_disabled'); } if (customDateSettings && customDateSettings[1] !== "") { classes.push(customDateSettings[1]); } @@ -2344,16 +2260,17 @@ now.setMinutes(m); m = parseInt(now.getMinutes(), 10); optionDateTime = new Date(_xdsoft_datetime.currentTime); optionDateTime.setHours(h); optionDateTime.setMinutes(m); - classes = []; + classes = []; if ((options.minDateTime !== false && options.minDateTime > optionDateTime) || (options.maxTime !== false && _xdsoft_datetime.strtotime(options.maxTime).getTime() < now.getTime()) || (options.minTime !== false && _xdsoft_datetime.strtotime(options.minTime).getTime() > now.getTime())) { classes.push('xdsoft_disabled'); - } - if ((options.minDateTime !== false && options.minDateTime > optionDateTime) || ((options.disabledMinTime !== false && now.getTime() > _xdsoft_datetime.strtotime(options.disabledMinTime).getTime()) && (options.disabledMaxTime !== false && now.getTime() < _xdsoft_datetime.strtotime(options.disabledMaxTime).getTime()))) { + } else if ((options.minDateTime !== false && options.minDateTime > optionDateTime) || ((options.disabledMinTime !== false && now.getTime() > _xdsoft_datetime.strtotime(options.disabledMinTime).getTime()) && (options.disabledMaxTime !== false && now.getTime() < _xdsoft_datetime.strtotime(options.disabledMaxTime).getTime()))) { classes.push('xdsoft_disabled'); + } else if (input.is('[readonly]')) { + classes.push('xdsoft_disabled'); } current_time = new Date(_xdsoft_datetime.currentTime); current_time.setHours(parseInt(_xdsoft_datetime.currentTime.getHours(), 10)); @@ -2502,11 +2419,10 @@ if (options.inline !== true && options.closeOnTimeSelect === true) { datetimepicker.trigger('close.xdsoft'); } }); - datepicker .on('mousewheel.xdsoft', function (event) { if (!options.scrollMonth) { return true; } @@ -2565,63 +2481,135 @@ xdevent.stopPropagation(); }); current_time_index = 0; + /** + * Runs the callback for each of the specified node's ancestors. + * + * Return FALSE from the callback to stop ascending. + * + * @param {DOMNode} node + * @param {Function} callback + * @returns {undefined} + */ + forEachAncestorOf = function (node, callback) { + do { + node = node.parentNode; + + if (callback(node) === false) { + break; + } + } while (node.nodeName !== 'HTML'); + }; + + /** + * Sets the position of the picker. + * + * @returns {undefined} + */ setPos = function () { - /** - * 修复输入框在window最右边,且输入框的宽度小于日期控件宽度情况下,日期控件显示不全的bug。 - * Bug fixed - The datetimepicker will overflow-y when the width of the date input less than its, which - * could causes part of the datetimepicker being hidden. - * by Soon start - */ - var offset = datetimepicker.data('input').offset(), - datetimepickerelement = datetimepicker.data('input')[0], - top = offset.top + datetimepickerelement.offsetHeight - 1, - left = offset.left, - position = "absolute", - node; + var dateInputOffset, + dateInputElem, + verticalPosition, + left, + position, + datetimepickerElem, + dateInputHasFixedAncestor, + $dateInput, + windowWidth, + verticalAnchorEdge, + datetimepickerCss, + windowHeight, + windowScrollTop; - if ((document.documentElement.clientWidth - offset.left) < datepicker.parent().outerWidth(true)) { - var diff = datepicker.parent().outerWidth(true) - datetimepickerelement.offsetWidth; - left = left - diff; - } - /** - * by Soon end - */ - if (datetimepicker.data('input').parent().css('direction') == 'rtl') - left -= (datetimepicker.outerWidth() - datetimepicker.data('input').outerWidth()); + $dateInput = datetimepicker.data('input'); + dateInputOffset = $dateInput.offset(); + dateInputElem = $dateInput[0]; + + verticalAnchorEdge = 'top'; + verticalPosition = (dateInputOffset.top + dateInputElem.offsetHeight) - 1; + left = dateInputOffset.left; + position = "absolute"; + + windowWidth = $(window).width(); + windowHeight = $(window).height(); + windowScrollTop = $(window).scrollTop(); + + if ((document.documentElement.clientWidth - dateInputOffset.left) < datepicker.parent().outerWidth(true)) { + var diff = datepicker.parent().outerWidth(true) - dateInputElem.offsetWidth; + left = left - diff; + } + + if ($dateInput.parent().css('direction') === 'rtl') { + left -= (datetimepicker.outerWidth() - $dateInput.outerWidth()); + } + if (options.fixed) { - top -= $(window).scrollTop(); + verticalPosition -= windowScrollTop; left -= $(window).scrollLeft(); position = "fixed"; } else { - if (top + datetimepickerelement.offsetHeight > $(window).height() + $(window).scrollTop()) { - top = offset.top - datetimepickerelement.offsetHeight + 1; + dateInputHasFixedAncestor = false; + + forEachAncestorOf(dateInputElem, function (ancestorNode) { + if (window.getComputedStyle(ancestorNode).getPropertyValue('position') === 'fixed') { + dateInputHasFixedAncestor = true; + return false; + } + }); + + if (dateInputHasFixedAncestor) { + position = 'fixed'; + + //If the picker won't fit entirely within the viewport then display it above the date input. + if (verticalPosition + datetimepicker.outerHeight() > windowHeight + windowScrollTop) { + verticalAnchorEdge = 'bottom'; + verticalPosition = (windowHeight + windowScrollTop) - dateInputOffset.top; + } else { + verticalPosition -= windowScrollTop; + } + } else { + if (verticalPosition + dateInputElem.offsetHeight > windowHeight + windowScrollTop) { + verticalPosition = dateInputOffset.top - dateInputElem.offsetHeight + 1; + } } - if (top < 0) { - top = 0; + + if (verticalPosition < 0) { + verticalPosition = 0; } - if (left + datetimepickerelement.offsetWidth > $(window).width()) { - left = $(window).width() - datetimepickerelement.offsetWidth; + + if (left + dateInputElem.offsetWidth > windowWidth) { + left = windowWidth - dateInputElem.offsetWidth; } } - node = datetimepicker[0]; - do { - node = node.parentNode; - if (window.getComputedStyle(node).getPropertyValue('position') === 'relative' && $(window).width() >= node.offsetWidth) { - left = left - (($(window).width() - node.offsetWidth) / 2); - break; + datetimepickerElem = datetimepicker[0]; + + forEachAncestorOf(datetimepickerElem, function (ancestorNode) { + var ancestorNodePosition; + + ancestorNodePosition = window.getComputedStyle(ancestorNode).getPropertyValue('position'); + + if (ancestorNodePosition === 'relative' && windowWidth >= ancestorNode.offsetWidth) { + left = left - ((windowWidth - ancestorNode.offsetWidth) / 2); + return false; } - } while (node.nodeName !== 'HTML'); - datetimepicker.css({ - left: left, - top: top, - position: position }); + + datetimepickerCss = { + position: position, + left: left, + top: '', //Initialize to prevent previous values interfering with new ones. + bottom: '' //Initialize to prevent previous values interfering with new ones. + }; + + datetimepickerCss[verticalAnchorEdge] = verticalPosition; + + datetimepicker.css(datetimepickerCss); }; + datetimepicker .on('open.xdsoft', function (event) { var onShow = true; if (options.onShow && $.isFunction(options.onShow)) { onShow = options.onShow.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), event); @@ -2653,21 +2641,20 @@ if (onClose !== false && !options.opened && !options.inline) { datetimepicker.hide(); } event.stopPropagation(); }) - .on('toggle.xdsoft', function (event) { + .on('toggle.xdsoft', function () { if (datetimepicker.is(':visible')) { datetimepicker.trigger('close.xdsoft'); } else { datetimepicker.trigger('open.xdsoft'); } }) .data('input', input); timer = 0; - timer1 = 0; datetimepicker.data('xdsoft_datetime', _xdsoft_datetime); datetimepicker.setOptions(options); function getCurrentValue() { @@ -2696,15 +2683,143 @@ } return ct || 0; } + function setMask(options) { + + var isValidValue = function (mask, value) { + var reg = mask + .replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g, '\\$1') + .replace(/_/g, '{digit+}') + .replace(/([0-9]{1})/g, '{digit$1}') + .replace(/\{digit([0-9]{1})\}/g, '[0-$1_]{1}') + .replace(/\{digit[\+]\}/g, '[0-9_]{1}'); + return (new RegExp(reg)).test(value); + }, + getCaretPos = function (input) { + try { + if (document.selection && document.selection.createRange) { + var range = document.selection.createRange(); + return range.getBookmark().charCodeAt(2) - 2; + } + if (input.setSelectionRange) { + return input.selectionStart; + } + } catch (e) { + return 0; + } + }, + setCaretPos = function (node, pos) { + node = (typeof node === "string" || node instanceof String) ? document.getElementById(node) : node; + if (!node) { + return false; + } + if (node.createTextRange) { + var textRange = node.createTextRange(); + textRange.collapse(true); + textRange.moveEnd('character', pos); + textRange.moveStart('character', pos); + textRange.select(); + return true; + } + if (node.setSelectionRange) { + node.setSelectionRange(pos, pos); + return true; + } + return false; + }; + if(options.mask) { + input.off('keydown.xdsoft'); + } + if (options.mask === true) { + if (typeof moment != 'undefined') { + options.mask = options.format + .replace(/Y{4}/g, '9999') + .replace(/Y{2}/g, '99') + .replace(/M{2}/g, '19') + .replace(/D{2}/g, '39') + .replace(/H{2}/g, '29') + .replace(/m{2}/g, '59') + .replace(/s{2}/g, '59'); + } else { + options.mask = options.format + .replace(/Y/g, '9999') + .replace(/F/g, '9999') + .replace(/m/g, '19') + .replace(/d/g, '39') + .replace(/H/g, '29') + .replace(/i/g, '59') + .replace(/s/g, '59'); + } + } + + if ($.type(options.mask) === 'string') { + if (!isValidValue(options.mask, input.val())) { + input.val(options.mask.replace(/[0-9]/g, '_')); + setCaretPos(input[0], 0); + } + + input.on('keydown.xdsoft', function (event) { + var val = this.value, + key = event.which, + pos, + digit; + + if (((key >= KEY0 && key <= KEY9) || (key >= _KEY0 && key <= _KEY9)) || (key === BACKSPACE || key === DEL)) { + pos = getCaretPos(this); + digit = (key !== BACKSPACE && key !== DEL) ? String.fromCharCode((_KEY0 <= key && key <= _KEY9) ? key - KEY0 : key) : '_'; + + if ((key === BACKSPACE || key === DEL) && pos) { + pos -= 1; + digit = '_'; + } + + while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) { + pos += (key === BACKSPACE || key === DEL) ? -1 : 1; + } + + val = val.substr(0, pos) + digit + val.substr(pos + 1); + if ($.trim(val) === '') { + val = options.mask.replace(/[0-9]/g, '_'); + } else { + if (pos === options.mask.length) { + event.preventDefault(); + return false; + } + } + + pos += (key === BACKSPACE || key === DEL) ? 0 : 1; + while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) { + pos += (key === BACKSPACE || key === DEL) ? -1 : 1; + } + + if (isValidValue(options.mask, val)) { + this.value = val; + setCaretPos(this, pos); + } else if ($.trim(val) === '') { + this.value = options.mask.replace(/[0-9]/g, '_'); + } else { + input.trigger('error_input.xdsoft'); + } + } else { + if (([AKEY, CKEY, VKEY, ZKEY, YKEY].indexOf(key) !== -1 && ctrlDown) || [ESC, ARROWUP, ARROWDOWN, ARROWLEFT, ARROWRIGHT, F5, CTRLKEY, TAB, ENTER].indexOf(key) !== -1) { + return true; + } + } + + event.preventDefault(); + return false; + }); + } + } + _xdsoft_datetime.setCurrentTime(getCurrentValue()); input .data('xdsoft_datetimepicker', datetimepicker) - .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function (event) { + .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function () { if (input.is(':disabled') || (input.data('xdsoft_datetimepicker').is(':visible') && options.closeOnInputClick)) { return; } clearTimeout(timer); timer = setTimeout(function () { @@ -2712,16 +2827,18 @@ return; } triggerAfterOpen = true; _xdsoft_datetime.setCurrentTime(getCurrentValue()); - + if(options.mask) { + setMask(options); + } datetimepicker.trigger('open.xdsoft'); }, 100); }) .on('keydown.xdsoft', function (event) { - var val = this.value, elementSelector, + var elementSelector, key = event.which; if ([ENTER].indexOf(key) !== -1 && options.enterLikeTab) { elementSelector = $("input:visible,textarea:visible,button:visible,a:visible"); datetimepicker.trigger('close.xdsoft'); elementSelector.eq(elementSelector.index(this) + 1).focus(); @@ -2729,10 +2846,13 @@ } if ([TAB].indexOf(key) !== -1) { datetimepicker.trigger('close.xdsoft'); return true; } + }) + .on('blur.xdsoft', function () { + datetimepicker.trigger('close.xdsoft'); }); }; destroyDateTimePicker = function (input) { var datetimepicker = input.data('xdsoft_datetimepicker'); if (datetimepicker) { @@ -2758,12 +2878,12 @@ .on('keyup.xdsoftctrl', function (e) { if (e.keyCode === CTRLKEY) { ctrlDown = false; } }); - - this.each(function () { + + this.each(function () { var datetimepicker = $(this).data('xdsoft_datetimepicker'), $input; if (datetimepicker) { if ($.type(opt) === 'string') { switch (opt) { case 'show': @@ -2788,14 +2908,14 @@ break; case 'validate': $input = datetimepicker.data('input'); $input.trigger('blur.xdsoft'); break; - default: - if (datetimepicker[opt] && $.isFunction(datetimepicker[opt])) { - result = datetimepicker[opt](opt2); - } + default: + if (datetimepicker[opt] && $.isFunction(datetimepicker[opt])) { + result = datetimepicker[opt](opt2); + } } } else { datetimepicker .setOptions(opt); } @@ -2808,20 +2928,20 @@ lazyInit($(this)); } } }); - return result; + return result; }; + $.fn.datetimepicker.defaults = default_options; function HighlightedDate(date, desc, style) { "use strict"; this.date = date; this.desc = desc; this.style = style; } - })); /*! * jQuery Mousewheel 3.1.13 * * Copyright jQuery Foundation and other contributors