vendor/assets/javascripts/bootstrap-datetimepicker.js in bootstrap3-datetimepicker-rails-4.17.37 vs vendor/assets/javascripts/bootstrap-datetimepicker.js in bootstrap3-datetimepicker-rails-4.17.42

- old
+ new

@@ -1,6 +1,6 @@ -/*! version : 4.17.37 +/*! version : 4.17.42 ========================================================= bootstrap-datetimejs https://github.com/Eonasdan/bootstrap-datetimepicker Copyright (c) 2015 Jonathan Peterson ========================================================= @@ -37,11 +37,11 @@ 'use strict'; if (typeof define === 'function' && define.amd) { // AMD is used - Register as an anonymous module. define(['jquery', 'moment'], factory); } else if (typeof exports === 'object') { - factory(require('jquery'), require('moment')); + module.exports = factory(require('jquery'), require('moment')); } else { // Neither AMD nor CommonJS used. Use global variables. if (typeof jQuery === 'undefined') { throw 'bootstrap-datetimepicker requires jQuery to be loaded first'; } @@ -130,44 +130,34 @@ /******************************************************************************** * * Private functions * ********************************************************************************/ + + hasTimeZone = function () { + return moment.tz !== undefined && options.timeZone !== undefined && options.timeZone !== null && options.timeZone !== ''; + }, + getMoment = function (d) { - var tzEnabled = false, - returnMoment, - currentZoneOffset, - incomingZoneOffset, - timeZoneIndicator, - dateWithTimeZoneInfo; + var returnMoment; - if (moment.tz !== undefined && options.timeZone !== undefined && options.timeZone !== null && options.timeZone !== '') { - tzEnabled = true; - } if (d === undefined || d === null) { - if (tzEnabled) { - returnMoment = moment().tz(options.timeZone).startOf('d'); - } else { - returnMoment = moment().startOf('d'); - } + returnMoment = moment(); //TODO should this use format? and locale? + } else if (hasTimeZone()) { // There is a string to parse and a default time zone + // parse with the tz function which takes a default time zone if it is not in the format string + returnMoment = moment.tz(d, parseFormats, options.useStrict, options.timeZone); } else { - if (tzEnabled) { - currentZoneOffset = moment().tz(options.timeZone).utcOffset(); - incomingZoneOffset = moment(d, parseFormats, options.useStrict).utcOffset(); - if (incomingZoneOffset !== currentZoneOffset) { - timeZoneIndicator = moment().tz(options.timeZone).format('Z'); - dateWithTimeZoneInfo = moment(d, parseFormats, options.useStrict).format('YYYY-MM-DD[T]HH:mm:ss') + timeZoneIndicator; - returnMoment = moment(dateWithTimeZoneInfo, parseFormats, options.useStrict).tz(options.timeZone); - } else { - returnMoment = moment(d, parseFormats, options.useStrict).tz(options.timeZone); - } - } else { - returnMoment = moment(d, parseFormats, options.useStrict); - } + returnMoment = moment(d, parseFormats, options.useStrict); } + + if (hasTimeZone()) { + returnMoment.tz(options.timeZone); + } + return returnMoment; }, + isEnabled = function (granularity) { if (typeof granularity !== 'string' || granularity.length > 1) { throw new TypeError('isEnabled expects a single character string parameter'); } switch (granularity) { @@ -186,10 +176,11 @@ return actualFormat.indexOf('s') !== -1; default: return false; } }, + hasTime = function () { return (isEnabled('h') || isEnabled('m') || isEnabled('s')); }, hasDate = function () { @@ -241,53 +232,51 @@ middleRow = $('<tr>'), bottomRow = $('<tr>'); if (isEnabled('h')) { topRow.append($('<td>') - .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementHour}).addClass('btn').attr('data-action', 'incrementHours') - .append($('<span>').addClass(options.icons.up)))); + .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementHour }).addClass('btn').attr('data-action', 'incrementHours').append($('<span>').addClass(options.icons.up)))); middleRow.append($('<td>') - .append($('<span>').addClass('timepicker-hour').attr({'data-time-component':'hours', 'title': options.tooltips.pickHour}).attr('data-action', 'showHours'))); + .append($('<span>').addClass('timepicker-hour').attr({ 'data-time-component': 'hours', 'title': options.tooltips.pickHour }).attr('data-action', 'showHours'))); bottomRow.append($('<td>') - .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementHour}).addClass('btn').attr('data-action', 'decrementHours') - .append($('<span>').addClass(options.icons.down)))); + .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementHour }).addClass('btn').attr('data-action', 'decrementHours').append($('<span>').addClass(options.icons.down)))); } if (isEnabled('m')) { if (isEnabled('h')) { topRow.append($('<td>').addClass('separator')); middleRow.append($('<td>').addClass('separator').html(':')); bottomRow.append($('<td>').addClass('separator')); } topRow.append($('<td>') - .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementMinute}).addClass('btn').attr('data-action', 'incrementMinutes') + .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementMinute }).addClass('btn').attr('data-action', 'incrementMinutes') .append($('<span>').addClass(options.icons.up)))); middleRow.append($('<td>') - .append($('<span>').addClass('timepicker-minute').attr({'data-time-component': 'minutes', 'title': options.tooltips.pickMinute}).attr('data-action', 'showMinutes'))); + .append($('<span>').addClass('timepicker-minute').attr({ 'data-time-component': 'minutes', 'title': options.tooltips.pickMinute }).attr('data-action', 'showMinutes'))); bottomRow.append($('<td>') - .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementMinute}).addClass('btn').attr('data-action', 'decrementMinutes') + .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementMinute }).addClass('btn').attr('data-action', 'decrementMinutes') .append($('<span>').addClass(options.icons.down)))); } if (isEnabled('s')) { if (isEnabled('m')) { topRow.append($('<td>').addClass('separator')); middleRow.append($('<td>').addClass('separator').html(':')); bottomRow.append($('<td>').addClass('separator')); } topRow.append($('<td>') - .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementSecond}).addClass('btn').attr('data-action', 'incrementSeconds') + .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementSecond }).addClass('btn').attr('data-action', 'incrementSeconds') .append($('<span>').addClass(options.icons.up)))); middleRow.append($('<td>') - .append($('<span>').addClass('timepicker-second').attr({'data-time-component': 'seconds', 'title': options.tooltips.pickSecond}).attr('data-action', 'showSeconds'))); + .append($('<span>').addClass('timepicker-second').attr({ 'data-time-component': 'seconds', 'title': options.tooltips.pickSecond }).attr('data-action', 'showSeconds'))); bottomRow.append($('<td>') - .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementSecond}).addClass('btn').attr('data-action', 'decrementSeconds') + .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementSecond }).addClass('btn').attr('data-action', 'decrementSeconds') .append($('<span>').addClass(options.icons.down)))); } if (!use24Hours) { topRow.append($('<td>').addClass('separator')); middleRow.append($('<td>') - .append($('<button>').addClass('btn btn-primary').attr({'data-action': 'togglePeriod', tabindex: '-1', 'title': options.tooltips.togglePeriod}))); + .append($('<button>').addClass('btn btn-primary').attr({ 'data-action': 'togglePeriod', tabindex: '-1', 'title': options.tooltips.togglePeriod }))); bottomRow.append($('<td>').addClass('separator')); } return $('<div>').addClass('timepicker-picker') .append($('<table>').addClass('table-condensed') @@ -317,20 +306,20 @@ }, getToolbar = function () { var row = []; if (options.showTodayButton) { - row.push($('<td>').append($('<a>').attr({'data-action':'today', 'title': options.tooltips.today}).append($('<span>').addClass(options.icons.today)))); + row.push($('<td>').append($('<a>').attr({ 'data-action': 'today', 'title': options.tooltips.today }).append($('<span>').addClass(options.icons.today)))); } if (!options.sideBySide && hasDate() && hasTime()) { - row.push($('<td>').append($('<a>').attr({'data-action':'togglePicker', 'title': options.tooltips.selectTime}).append($('<span>').addClass(options.icons.time)))); + row.push($('<td>').append($('<a>').attr({ 'data-action': 'togglePicker', 'title': options.tooltips.selectTime }).append($('<span>').addClass(options.icons.time)))); } if (options.showClear) { - row.push($('<td>').append($('<a>').attr({'data-action':'clear', 'title': options.tooltips.clear}).append($('<span>').addClass(options.icons.clear)))); + row.push($('<td>').append($('<a>').attr({ 'data-action': 'clear', 'title': options.tooltips.clear }).append($('<span>').addClass(options.icons.clear)))); } if (options.showClose) { - row.push($('<td>').append($('<a>').attr({'data-action':'close', 'title': options.tooltips.close}).append($('<span>').addClass(options.icons.close)))); + row.push($('<td>').append($('<a>').attr({ 'data-action': 'close', 'title': options.tooltips.close }).append($('<span>').addClass(options.icons.close)))); } return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row))); }, getTemplate = function () { @@ -470,11 +459,11 @@ throw new Error('datetimepicker component should be placed within a relative positioned container'); } widget.css({ top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(), - bottom: vertical === 'top' ? position.top + element.outerHeight() : 'auto', + bottom: vertical === 'top' ? parent.outerHeight() - (parent === element ? 0 : position.top) : 'auto', left: horizontal === 'left' ? (parent === element ? 0 : position.left) : 'auto', right: horizontal === 'left' ? 'auto' : parent.outerWidth() - element.outerWidth() - (parent === element ? 0 : position.left) }); }, @@ -652,33 +641,39 @@ }, updateDecades = function () { var decadesView = widget.find('.datepicker-decades'), decadesViewHeader = decadesView.find('th'), - startDecade = moment({y: viewDate.year() - (viewDate.year() % 100) - 1}), + startDecade = moment({ y: viewDate.year() - (viewDate.year() % 100) - 1 }), endDecade = startDecade.clone().add(100, 'y'), startedAt = startDecade.clone(), + minDateDecade = false, + maxDateDecade = false, + endDecadeYear, html = ''; decadesViewHeader.eq(0).find('span').attr('title', options.tooltips.prevCentury); decadesViewHeader.eq(2).find('span').attr('title', options.tooltips.nextCentury); decadesView.find('.disabled').removeClass('disabled'); - if (startDecade.isSame(moment({y: 1900})) || (options.minDate && options.minDate.isAfter(startDecade, 'y'))) { + if (startDecade.isSame(moment({ y: 1900 })) || (options.minDate && options.minDate.isAfter(startDecade, 'y'))) { decadesViewHeader.eq(0).addClass('disabled'); } decadesViewHeader.eq(1).text(startDecade.year() + '-' + endDecade.year()); - if (startDecade.isSame(moment({y: 2000})) || (options.maxDate && options.maxDate.isBefore(endDecade, 'y'))) { + if (startDecade.isSame(moment({ y: 2000 })) || (options.maxDate && options.maxDate.isBefore(endDecade, 'y'))) { decadesViewHeader.eq(2).addClass('disabled'); } while (!startDecade.isAfter(endDecade, 'y')) { - html += '<span data-action="selectDecade" class="decade' + (startDecade.isSame(date, 'y') ? ' active' : '') + - (!isValid(startDecade, 'y') ? ' disabled' : '') + '" data-selection="' + (startDecade.year() + 6) + '">' + (startDecade.year() + 1) + ' - ' + (startDecade.year() + 12) + '</span>'; + endDecadeYear = startDecade.year() + 12; + minDateDecade = options.minDate && options.minDate.isAfter(startDecade, 'y') && options.minDate.year() <= endDecadeYear; + maxDateDecade = options.maxDate && options.maxDate.isAfter(startDecade, 'y') && options.maxDate.year() <= endDecadeYear; + html += '<span data-action="selectDecade" class="decade' + (date.isAfter(startDecade) && date.year() <= endDecadeYear ? ' active' : '') + + (!isValid(startDecade, 'y') && !minDateDecade && !maxDateDecade ? ' disabled' : '') + '" data-selection="' + (startDecade.year() + 6) + '">' + (startDecade.year() + 1) + ' - ' + (startDecade.year() + 12) + '</span>'; startDecade.add(12, 'y'); } html += '<span></span><span></span><span></span>'; //push the dangling block over, at least this way it's even decadesView.find('td').html(html); @@ -859,17 +854,21 @@ return; } targetMoment = targetMoment.clone().locale(options.locale); + if (hasTimeZone()) { + targetMoment.tz(options.timeZone); + } + if (options.stepping !== 1) { - targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0); + targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping)).seconds(0); } if (isValid(targetMoment)) { date = targetMoment; - viewDate = date.clone(); + //viewDate = date.clone(); // TODO this doesn't work right on first use input.val(date.format(actualFormat)); element.data('date', date.format(actualFormat)); unset = false; update(); notifyEvent({ @@ -878,20 +877,29 @@ oldDate: oldDate }); } else { if (!options.keepInvalid) { input.val(unset ? '' : date.format(actualFormat)); + } else { + notifyEvent({ + type: 'dp.change', + date: targetMoment, + oldDate: oldDate + }); } notifyEvent({ type: 'dp.error', - date: targetMoment + date: targetMoment, + oldDate: oldDate }); } }, + /** + * Hides the widget. Possibly will emit dp.hide + */ hide = function () { - ///<summary>Hides the widget. Possibly will emit dp.hide</summary> var transitioning = false; if (!widget) { return picker; } // Ignore event if in the middle of a picker transition @@ -923,17 +931,32 @@ date: date.clone() }); input.blur(); + currentViewMode = 0; + viewDate = date.clone(); + return picker; }, clear = function () { setValue(null); }, + parseInputDate = function (inputDate) { + if (options.parseInputDate === undefined) { + if (!moment.isMoment(inputDate)) { + inputDate = getMoment(inputDate); + } + } else { + inputDate = options.parseInputDate(inputDate); + } + //inputDate.locale(options.locale); + return inputDate; + }, + /******************************************************************************** * * Widget UI interaction functions * ********************************************************************************/ @@ -1159,12 +1182,14 @@ } actions[$(e.currentTarget).data('action')].apply(picker, arguments); return false; }, + /** + * Shows the widget. Possibly will emit dp.show and dp.change + */ show = function () { - ///<summary>Shows the widget. Possibly will emit dp.show and dp.change</summary> var currentMoment, useCurrentGranularity = { 'year': function (m) { return m.month(0).date(1).hours(0).seconds(0).minutes(0); }, @@ -1185,18 +1210,17 @@ if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) { return picker; } if (input.val() !== undefined && input.val().trim().length !== 0) { setValue(parseInputDate(input.val().trim())); - } else if (options.useCurrent && unset && ((input.is('input') && input.val().trim().length === 0) || options.inline)) { + } else if (unset && options.useCurrent && (options.inline || (input.is('input') && input.val().trim().length === 0))) { currentMoment = getMoment(); if (typeof options.useCurrent === 'string') { currentMoment = useCurrentGranularity[options.useCurrent](currentMoment); } setValue(currentMoment); } - widget = getTemplate(); fillDow(); fillMonths(); @@ -1212,42 +1236,29 @@ widget.on('mousedown', false); if (component && component.hasClass('btn')) { component.toggleClass('active'); } - widget.show(); place(); - + widget.show(); if (options.focusOnShow && !input.is(':focus')) { input.focus(); } notifyEvent({ type: 'dp.show' }); return picker; }, + /** + * Shows or hides the widget + */ toggle = function () { - /// <summary>Shows or hides the widget</summary> return (widget ? hide() : show()); }, - parseInputDate = function (inputDate) { - if (options.parseInputDate === undefined) { - if (moment.isMoment(inputDate) || inputDate instanceof Date) { - inputDate = moment(inputDate); - } else { - inputDate = getMoment(inputDate); - } - } else { - inputDate = options.parseInputDate(inputDate); - } - inputDate.locale(options.locale); - return inputDate; - }, - keydown = function (e) { var handler = null, index, index2, pressedKeys = [], @@ -1511,11 +1522,11 @@ if (arguments.length === 0) { return options.format; } if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) { - throw new TypeError('format() expects a sting or boolean:false parameter ' + newFormat); + throw new TypeError('format() expects a string or boolean:false parameter ' + newFormat); } options.format = newFormat; if (actualFormat) { initFormatting(); // reinit formatting @@ -1526,10 +1537,14 @@ picker.timeZone = function (newZone) { if (arguments.length === 0) { return options.timeZone; } + if (typeof newZone !== 'string') { + throw new TypeError('newZone() expects a string parameter'); + } + options.timeZone = newZone; return picker; }; @@ -1643,12 +1658,12 @@ }, []).sort(); if (options.useCurrent && !options.keepInvalid) { var tries = 0; while (!isValid(date, 'd')) { date.add(1, 'd'); - if (tries === 7) { - throw 'Tried 7 times to find a valid date'; + if (tries === 31) { + throw 'Tried 31 times to find a valid date'; } tries++; } setValue(date); } @@ -1746,10 +1761,12 @@ } if (typeof defaultDate === 'string') { if (defaultDate === 'now' || defaultDate === 'moment') { defaultDate = getMoment(); + } else { + defaultDate = getMoment(defaultDate); } } var parsedDate = parseInputDate(defaultDate); if (!parsedDate.isValid()) { @@ -2082,10 +2099,14 @@ clear(); return picker; }; picker.keyBinds = function (keyBinds) { + if (arguments.length === 0) { + return options.keyBinds; + } + options.keyBinds = keyBinds; return picker; }; picker.getMoment = function (d) { @@ -2267,20 +2288,16 @@ setValue(date); } update(); return picker; }; - + /** + * Returns the component's model current viewDate, a moment object or null if not set. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration. + * @param {Takes string, viewDate, moment, null parameter.} newDate + * @returns {viewDate.clone()} + */ picker.viewDate = function (newDate) { - ///<signature helpKeyword="$.fn.datetimepicker.viewDate"> - ///<summary>Returns the component's model current viewDate, a moment object or null if not set.</summary> - ///<returns type="Moment">viewDate.clone()</returns> - ///</signature> - ///<signature> - ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary> - ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, viewDate, moment, null parameter.</param> - ///</signature> if (arguments.length === 0) { return viewDate.clone(); } if (!newDate) { @@ -2300,20 +2317,20 @@ // initializing element and component attributes if (element.is('input')) { input = element; } else { input = element.find(options.datepickerInput); - if (input.size() === 0) { + if (input.length === 0) { input = element.find('input'); } else if (!input.is('input')) { throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element'); } } if (element.hasClass('input-group')) { // in case there is more then one 'input-group-addon' Issue #48 - if (element.find('.datepickerbutton').size() === 0) { + if (element.find('.datepickerbutton').length === 0) { component = element.find('.input-group-addon'); } else { component = element.find('.datepickerbutton'); } } @@ -2353,23 +2370,71 @@ * * jQuery plugin constructor and defaults object * ********************************************************************************/ + /** + * See (http://jquery.com/). + * @name jQuery + * @class + * See the jQuery Library (http://jquery.com/) for full details. This just + * documents the function and classes that are added to jQuery by this plug-in. + */ + /** + * See (http://jquery.com/) + * @name fn + * @class + * See the jQuery Library (http://jquery.com/) for full details. This just + * documents the function and classes that are added to jQuery by this plug-in. + * @memberOf jQuery + */ + /** + * Show comments + * @class datetimepicker + * @memberOf jQuery.fn + */ $.fn.datetimepicker = function (options) { - return this.each(function () { - var $this = $(this); - if (!$this.data('DateTimePicker')) { - // create a private copy of the defaults object - options = $.extend(true, {}, $.fn.datetimepicker.defaults, options); - $this.data('DateTimePicker', dateTimePicker($this, options)); + options = options || {}; + + var args = Array.prototype.slice.call(arguments, 1), + isInstance = true, + thisMethods = ['destroy', 'hide', 'show', 'toggle'], + returnValue; + + if (typeof options === 'object') { + return this.each(function () { + var $this = $(this); + if (!$this.data('DateTimePicker')) { + // create a private copy of the defaults object + options = $.extend(true, {}, $.fn.datetimepicker.defaults, options); + $this.data('DateTimePicker', dateTimePicker($this, options)); + } + }); + } else if (typeof options === 'string') { + this.each(function () { + var $this = $(this), + instance = $this.data('DateTimePicker'); + if (!instance) { + throw new Error('bootstrap-datetimepicker("' + options + '") method was called on an element that is not using DateTimePicker'); + } + + returnValue = instance[options].apply(instance, args); + isInstance = returnValue === instance; + }); + + if (isInstance || $.inArray(options, thisMethods) > -1) { + return this; } - }); + + return returnValue; + } + + throw new TypeError('Invalid arguments for DateTimePicker: ' + options); }; $.fn.datetimepicker.defaults = { - timeZone: 'Etc/UTC', + timeZone: '', format: false, dayViewHeaderFormat: 'MMMM YYYY', extraFormats: false, stepping: 1, minDate: false, @@ -2529,10 +2594,13 @@ //tab: function (widget) { //this break the flow of the form. disabling for now // var toggle = widget.find('.picker-switch a[data-action="togglePicker"]'); // if(toggle.length > 0) toggle.click(); //}, 'control space': function (widget) { + if (!widget) { + return; + } if (widget.find('.timepicker').is(':visible')) { widget.find('.btn[data-action="togglePeriod"]').click(); } }, t: function () { @@ -2547,6 +2615,9 @@ disabledTimeIntervals: false, disabledHours: false, enabledHours: false, viewDate: false }; + if (typeof module !== 'undefined') { + module.exports = $.fn.datetimepicker; + } }));