| /* |
| * jQuery timepicker addon |
| * By: Trent Richardson [http://trentrichardson.com] |
| * Version 1.0.5 |
| * Last Modified: 10/06/2012 |
| * |
| * Copyright 2012 Trent Richardson |
| * You may use this project under MIT or GPL licenses. |
| * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt |
| * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt |
| */ |
| |
| /*jslint evil: true, white: false, undef: false, nomen: false */ |
| |
| (function($) { |
| |
| /* |
| * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded" |
| */ |
| $.ui.timepicker = $.ui.timepicker || {}; |
| if ($.ui.timepicker.version) { |
| return; |
| } |
| |
| /* |
| * Extend jQueryUI, get it started with our version number |
| */ |
| $.extend($.ui, { |
| timepicker: { |
| version: "1.0.5" |
| } |
| }); |
| |
| /* |
| * Timepicker manager. |
| * Use the singleton instance of this class, $.timepicker, to interact with the time picker. |
| * Settings for (groups of) time pickers are maintained in an instance object, |
| * allowing multiple different settings on the same page. |
| */ |
| function Timepicker() { |
| this.regional = []; // Available regional settings, indexed by language code |
| this.regional[''] = { // Default regional settings |
| currentText: 'Now', |
| closeText: 'Done', |
| ampm: false, |
| amNames: ['AM', 'A'], |
| pmNames: ['PM', 'P'], |
| timeFormat: 'hh:mm tt', |
| timeSuffix: '', |
| timeOnlyTitle: 'Choose Time', |
| timeText: 'Time', |
| hourText: 'Hour', |
| minuteText: 'Minute', |
| secondText: 'Second', |
| millisecText: 'Millisecond', |
| timezoneText: 'Time Zone', |
| isRTL: false |
| }; |
| this._defaults = { // Global defaults for all the datetime picker instances |
| showButtonPanel: true, |
| timeOnly: false, |
| showHour: true, |
| showMinute: true, |
| showSecond: false, |
| showMillisec: false, |
| showTimezone: false, |
| showTime: true, |
| stepHour: 1, |
| stepMinute: 1, |
| stepSecond: 1, |
| stepMillisec: 1, |
| hour: 0, |
| minute: 0, |
| second: 0, |
| millisec: 0, |
| timezone: null, |
| useLocalTimezone: false, |
| defaultTimezone: "+0000", |
| hourMin: 0, |
| minuteMin: 0, |
| secondMin: 0, |
| millisecMin: 0, |
| hourMax: 23, |
| minuteMax: 59, |
| secondMax: 59, |
| millisecMax: 999, |
| minDateTime: null, |
| maxDateTime: null, |
| onSelect: null, |
| hourGrid: 0, |
| minuteGrid: 0, |
| secondGrid: 0, |
| millisecGrid: 0, |
| alwaysSetTime: true, |
| separator: ' ', |
| altFieldTimeOnly: true, |
| altSeparator: null, |
| altTimeSuffix: null, |
| showTimepicker: true, |
| timezoneIso8601: false, |
| timezoneList: null, |
| addSliderAccess: false, |
| sliderAccessArgs: null, |
| controlType: 'slider', |
| defaultValue: null |
| }; |
| $.extend(this._defaults, this.regional['']); |
| } |
| |
| $.extend(Timepicker.prototype, { |
| $input: null, |
| $altInput: null, |
| $timeObj: null, |
| inst: null, |
| hour_slider: null, |
| minute_slider: null, |
| second_slider: null, |
| millisec_slider: null, |
| timezone_select: null, |
| hour: 0, |
| minute: 0, |
| second: 0, |
| millisec: 0, |
| timezone: null, |
| defaultTimezone: "+0000", |
| hourMinOriginal: null, |
| minuteMinOriginal: null, |
| secondMinOriginal: null, |
| millisecMinOriginal: null, |
| hourMaxOriginal: null, |
| minuteMaxOriginal: null, |
| secondMaxOriginal: null, |
| millisecMaxOriginal: null, |
| ampm: '', |
| formattedDate: '', |
| formattedTime: '', |
| formattedDateTime: '', |
| timezoneList: null, |
| units: ['hour','minute','second','millisec'], |
| control: null, |
| |
| /* |
| * Override the default settings for all instances of the time picker. |
| * @param settings object - the new settings to use as defaults (anonymous object) |
| * @return the manager object |
| */ |
| setDefaults: function(settings) { |
| extendRemove(this._defaults, settings || {}); |
| return this; |
| }, |
| |
| /* |
| * Create a new Timepicker instance |
| */ |
| _newInst: function($input, o) { |
| var tp_inst = new Timepicker(), |
| inlineSettings = {}, |
| fns = {}, |
| overrides, i; |
| |
| for (var attrName in this._defaults) { |
| if(this._defaults.hasOwnProperty(attrName)){ |
| var attrValue = $input.attr('time:' + attrName); |
| if (attrValue) { |
| try { |
| inlineSettings[attrName] = eval(attrValue); |
| } catch (err) { |
| inlineSettings[attrName] = attrValue; |
| } |
| } |
| } |
| } |
| overrides = { |
| beforeShow: function (input, dp_inst) { |
| if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) { |
| return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst); |
| } |
| }, |
| onChangeMonthYear: function (year, month, dp_inst) { |
| // Update the time as well : this prevents the time from disappearing from the $input field. |
| tp_inst._updateDateTime(dp_inst); |
| if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) { |
| tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst); |
| } |
| }, |
| onClose: function (dateText, dp_inst) { |
| if (tp_inst.timeDefined === true && $input.val() !== '') { |
| tp_inst._updateDateTime(dp_inst); |
| } |
| if ($.isFunction(tp_inst._defaults.evnts.onClose)) { |
| tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst); |
| } |
| } |
| }; |
| for (i in overrides) { |
| if (overrides.hasOwnProperty(i)) { |
| fns[i] = o[i] || null; |
| } |
| } |
| tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, overrides, { |
| evnts:fns, |
| timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker'); |
| }); |
| tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { |
| return val.toUpperCase(); |
| }); |
| tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { |
| return val.toUpperCase(); |
| }); |
| |
| // controlType is string - key to our this._controls |
| if(typeof(tp_inst._defaults.controlType) === 'string'){ |
| if(tp_inst._defaults.controlType == 'slider' && $.fn.slider === undefined){ |
| tp_inst._defaults.controlType = 'select'; |
| } |
| tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType]; |
| } |
| // controlType is an object and must implement create, options, value methods |
| else{ |
| tp_inst.control = tp_inst._defaults.controlType; |
| } |
| |
| if (tp_inst._defaults.timezoneList === null) { |
| var timezoneList = ['-1200', '-1100', '-1000', '-0930', '-0900', '-0800', '-0700', '-0600', '-0500', '-0430', '-0400', '-0330', '-0300', '-0200', '-0100', '+0000', |
| '+0100', '+0200', '+0300', '+0330', '+0400', '+0430', '+0500', '+0530', '+0545', '+0600', '+0630', '+0700', '+0800', '+0845', '+0900', '+0930', |
| '+1000', '+1030', '+1100', '+1130', '+1200', '+1245', '+1300', '+1400']; |
| |
| if (tp_inst._defaults.timezoneIso8601) { |
| timezoneList = $.map(timezoneList, function(val) { |
| return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3)); |
| }); |
| } |
| tp_inst._defaults.timezoneList = timezoneList; |
| } |
| |
| tp_inst.timezone = tp_inst._defaults.timezone; |
| tp_inst.hour = tp_inst._defaults.hour; |
| tp_inst.minute = tp_inst._defaults.minute; |
| tp_inst.second = tp_inst._defaults.second; |
| tp_inst.millisec = tp_inst._defaults.millisec; |
| tp_inst.ampm = ''; |
| tp_inst.$input = $input; |
| |
| if (o.altField) { |
| tp_inst.$altInput = $(o.altField).css({ |
| cursor: 'pointer' |
| }).focus(function() { |
| $input.trigger("focus"); |
| }); |
| } |
| |
| if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) { |
| tp_inst._defaults.minDate = new Date(); |
| } |
| if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) { |
| tp_inst._defaults.maxDate = new Date(); |
| } |
| |
| // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime.. |
| if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) { |
| tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime()); |
| } |
| if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) { |
| tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime()); |
| } |
| if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) { |
| tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime()); |
| } |
| if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) { |
| tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); |
| } |
| tp_inst.$input.bind('focus', function() { |
| tp_inst._onFocus(); |
| }); |
| |
| return tp_inst; |
| }, |
| |
| /* |
| * add our sliders to the calendar |
| */ |
| _addTimePicker: function(dp_inst) { |
| var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val(); |
| |
| this.timeDefined = this._parseTime(currDT); |
| this._limitMinMaxDateTime(dp_inst, false); |
| this._injectTimePicker(); |
| }, |
| |
| /* |
| * parse the time string from input value or _setTime |
| */ |
| _parseTime: function(timeString, withDate) { |
| if (!this.inst) { |
| this.inst = $.datepicker._getInst(this.$input[0]); |
| } |
| |
| if (withDate || !this._defaults.timeOnly) { |
| var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); |
| try { |
| var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults); |
| if (!parseRes.timeObj) { |
| return false; |
| } |
| $.extend(this, parseRes.timeObj); |
| } catch (err) { |
| return false; |
| } |
| return true; |
| } else { |
| var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults); |
| if (!timeObj) { |
| return false; |
| } |
| $.extend(this, timeObj); |
| return true; |
| } |
| }, |
| |
| /* |
| * generate and inject html for timepicker into ui datepicker |
| */ |
| _injectTimePicker: function() { |
| var $dp = this.inst.dpDiv, |
| o = this.inst.settings, |
| tp_inst = this, |
| litem = '', |
| uitem = '', |
| max = {}, |
| gridSize = {}, |
| size = null; |
| |
| // Prevent displaying twice |
| if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) { |
| var noDisplay = ' style="display:none;"', |
| html = '<div class="ui-timepicker-div'+ (o.isRTL? ' ui-timepicker-rtl' : '') +'"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' + |
| '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>'; |
| |
| // Create the markup |
| for(var i=0,l=this.units.length; i<l; i++){ |
| litem = this.units[i]; |
| uitem = litem.substr(0,1).toUpperCase() + litem.substr(1); |
| // Added by Peter Medeiros: |
| // - Figure out what the hour/minute/second max should be based on the step values. |
| // - Example: if stepMinute is 15, then minMax is 45. |
| max[litem] = parseInt((o[litem+'Max'] - ((o[litem+'Max'] - o[litem+'Min']) % o['step'+uitem])), 10); |
| gridSize[litem] = 0; |
| |
| html += '<dt class="ui_tpicker_'+ litem +'_label"' + ((o['show'+uitem]) ? '' : noDisplay) + '>' + o[litem +'Text'] + '</dt>' + |
| '<dd class="ui_tpicker_'+ litem +'"><div class="ui_tpicker_'+ litem +'_slider"' + ((o['show'+uitem]) ? '' : noDisplay) + '></div>'; |
| |
| if (o['show'+uitem] && o[litem+'Grid'] > 0) { |
| html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>'; |
| |
| if(litem == 'hour'){ |
| for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) { |
| gridSize[litem]++; |
| var tmph = (o.ampm && h > 12) ? h - 12 : h; |
| if (tmph < 10) { |
| tmph = '0' + tmph; |
| } |
| if (o.ampm) { |
| if (h === 0) { |
| tmph = 12 + 'a'; |
| } else { |
| if (h < 12) { |
| tmph += 'a'; |
| } else { |
| tmph += 'p'; |
| } |
| } |
| } |
| html += '<td data-for="'+litem+'">' + tmph + '</td>'; |
| } |
| } |
| else{ |
| for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) { |
| gridSize[litem]++; |
| html += '<td data-for="'+litem+'">' + ((m < 10) ? '0' : '') + m + '</td>'; |
| } |
| } |
| |
| html += '</tr></table></div>'; |
| } |
| html += '</dd>'; |
| } |
| |
| // Timezone |
| html += '<dt class="ui_tpicker_timezone_label"' + ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>'; |
| html += '<dd class="ui_tpicker_timezone" ' + ((o.showTimezone) ? '' : noDisplay) + '></dd>'; |
| |
| // Create the elements from string |
| html += '</dl></div>'; |
| var $tp = $(html); |
| |
| // if we only want time picker... |
| if (o.timeOnly === true) { |
| $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>'); |
| $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide(); |
| } |
| |
| // add sliders, adjust grids, add events |
| for(var i=0,l=tp_inst.units.length; i<l; i++){ |
| litem = tp_inst.units[i]; |
| uitem = litem.substr(0,1).toUpperCase() + litem.substr(1); |
| |
| // add the slider |
| tp_inst[litem+'_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_'+litem+'_slider'), litem, tp_inst[litem], o[litem+'Min'], max[litem], o['step'+uitem]); |
| |
| // adjust the grid and add click event |
| if (o['show'+uitem] && o[litem+'Grid'] > 0) { |
| size = 100 * gridSize[litem] * o[litem+'Grid'] / (max[litem] - o[litem+'Min']); |
| $tp.find('.ui_tpicker_'+litem+' table').css({ |
| width: size + "%", |
| marginLeft: o.isRTL? '0' : ((size / (-2 * gridSize[litem])) + "%"), |
| marginRight: o.isRTL? ((size / (-2 * gridSize[litem])) + "%") : '0', |
| borderCollapse: 'collapse' |
| }).find("td").click(function(e){ |
| var $t = $(this), |
| h = $t.html(), |
| f = $t.data('for'); // loses scope, so we use data-for |
| |
| if (f == 'hour' && o.ampm) { |
| var ap = h.substring(2).toLowerCase(), |
| aph = parseInt(h.substring(0, 2), 10); |
| if (ap == 'a') { |
| if (aph == 12) { |
| h = 0; |
| } else { |
| h = aph; |
| } |
| } else if (aph == 12) { |
| h = 12; |
| } else { |
| h = aph + 12; |
| } |
| } |
| tp_inst.control.value(tp_inst, tp_inst[f+'_slider'], parseInt(h,10)); |
| |
| tp_inst._onTimeChange(); |
| tp_inst._onSelectHandler(); |
| }) |
| .css({ |
| cursor: 'pointer', |
| width: (100 / gridSize[litem]) + '%', |
| textAlign: 'center', |
| overflow: 'hidden' |
| }); |
| } // end if grid > 0 |
| } // end for loop |
| |
| // Add timezone options |
| this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select"); |
| $.fn.append.apply(this.timezone_select, |
| $.map(o.timezoneList, function(val, idx) { |
| return $("<option />").val(typeof val == "object" ? val.value : val).text(typeof val == "object" ? val.label : val); |
| })); |
| if (typeof(this.timezone) != "undefined" && this.timezone !== null && this.timezone !== "") { |
| var local_date = new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12); |
| var local_timezone = $.timepicker.timeZoneOffsetString(local_date); |
| if (local_timezone == this.timezone) { |
| selectLocalTimeZone(tp_inst); |
| } else { |
| this.timezone_select.val(this.timezone); |
| } |
| } else { |
| if (typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") { |
| this.timezone_select.val(o.defaultTimezone); |
| } else { |
| selectLocalTimeZone(tp_inst); |
| } |
| } |
| this.timezone_select.change(function() { |
| tp_inst._defaults.useLocalTimezone = false; |
| tp_inst._onTimeChange(); |
| }); |
| // End timezone options |
| |
| // inject timepicker into datepicker |
| var $buttonPanel = $dp.find('.ui-datepicker-buttonpane'); |
| if ($buttonPanel.length) { |
| $buttonPanel.before($tp); |
| } else { |
| $dp.append($tp); |
| } |
| |
| this.$timeObj = $tp.find('.ui_tpicker_time'); |
| |
| if (this.inst !== null) { |
| var timeDefined = this.timeDefined; |
| this._onTimeChange(); |
| this.timeDefined = timeDefined; |
| } |
| |
| // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/ |
| if (this._defaults.addSliderAccess) { |
| var sliderAccessArgs = this._defaults.sliderAccessArgs, |
| rtl = this._defaults.isRTL; |
| sliderAccessArgs.isRTL = rtl; |
| |
| setTimeout(function() { // fix for inline mode |
| if ($tp.find('.ui-slider-access').length === 0) { |
| $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs); |
| |
| // fix any grids since sliders are shorter |
| var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true); |
| if (sliderAccessWidth) { |
| $tp.find('table:visible').each(function() { |
| var $g = $(this), |
| oldWidth = $g.outerWidth(), |
| oldMarginLeft = $g.css(rtl? 'marginRight':'marginLeft').toString().replace('%', ''), |
| newWidth = oldWidth - sliderAccessWidth, |
| newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%', |
| css = { width: newWidth, marginRight: 0, marginLeft: 0 }; |
| css[rtl? 'marginRight':'marginLeft'] = newMarginLeft; |
| $g.css(css); |
| }); |
| } |
| } |
| }, 10); |
| } |
| // end slideAccess integration |
| |
| } |
| }, |
| |
| /* |
| * This function tries to limit the ability to go outside the |
| * min/max date range |
| */ |
| _limitMinMaxDateTime: function(dp_inst, adjustSliders) { |
| var o = this._defaults, |
| dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay); |
| |
| if (!this._defaults.showTimepicker) { |
| return; |
| } // No time so nothing to check here |
| |
| if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) { |
| var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'), |
| minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0); |
| |
| if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null) { |
| this.hourMinOriginal = o.hourMin; |
| this.minuteMinOriginal = o.minuteMin; |
| this.secondMinOriginal = o.secondMin; |
| this.millisecMinOriginal = o.millisecMin; |
| } |
| |
| if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) { |
| this._defaults.hourMin = minDateTime.getHours(); |
| if (this.hour <= this._defaults.hourMin) { |
| this.hour = this._defaults.hourMin; |
| this._defaults.minuteMin = minDateTime.getMinutes(); |
| if (this.minute <= this._defaults.minuteMin) { |
| this.minute = this._defaults.minuteMin; |
| this._defaults.secondMin = minDateTime.getSeconds(); |
| if (this.second <= this._defaults.secondMin) { |
| this.second = this._defaults.secondMin; |
| this._defaults.millisecMin = minDateTime.getMilliseconds(); |
| } else { |
| if (this.millisec < this._defaults.millisecMin) { |
| this.millisec = this._defaults.millisecMin; |
| } |
| this._defaults.millisecMin = this.millisecMinOriginal; |
| } |
| } else { |
| this._defaults.secondMin = this.secondMinOriginal; |
| this._defaults.millisecMin = this.millisecMinOriginal; |
| } |
| } else { |
| this._defaults.minuteMin = this.minuteMinOriginal; |
| this._defaults.secondMin = this.secondMinOriginal; |
| this._defaults.millisecMin = this.millisecMinOriginal; |
| } |
| } else { |
| this._defaults.hourMin = this.hourMinOriginal; |
| this._defaults.minuteMin = this.minuteMinOriginal; |
| this._defaults.secondMin = this.secondMinOriginal; |
| this._defaults.millisecMin = this.millisecMinOriginal; |
| } |
| } |
| |
| if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) { |
| var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'), |
| maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0); |
| |
| if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null) { |
| this.hourMaxOriginal = o.hourMax; |
| this.minuteMaxOriginal = o.minuteMax; |
| this.secondMaxOriginal = o.secondMax; |
| this.millisecMaxOriginal = o.millisecMax; |
| } |
| |
| if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()) { |
| this._defaults.hourMax = maxDateTime.getHours(); |
| if (this.hour >= this._defaults.hourMax) { |
| this.hour = this._defaults.hourMax; |
| this._defaults.minuteMax = maxDateTime.getMinutes(); |
| if (this.minute >= this._defaults.minuteMax) { |
| this.minute = this._defaults.minuteMax; |
| this._defaults.secondMax = maxDateTime.getSeconds(); |
| } else if (this.second >= this._defaults.secondMax) { |
| this.second = this._defaults.secondMax; |
| this._defaults.millisecMax = maxDateTime.getMilliseconds(); |
| } else { |
| if (this.millisec > this._defaults.millisecMax) { |
| this.millisec = this._defaults.millisecMax; |
| } |
| this._defaults.millisecMax = this.millisecMaxOriginal; |
| } |
| } else { |
| this._defaults.minuteMax = this.minuteMaxOriginal; |
| this._defaults.secondMax = this.secondMaxOriginal; |
| this._defaults.millisecMax = this.millisecMaxOriginal; |
| } |
| } else { |
| this._defaults.hourMax = this.hourMaxOriginal; |
| this._defaults.minuteMax = this.minuteMaxOriginal; |
| this._defaults.secondMax = this.secondMaxOriginal; |
| this._defaults.millisecMax = this.millisecMaxOriginal; |
| } |
| } |
| |
| if (adjustSliders !== undefined && adjustSliders === true) { |
| var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10), |
| minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10), |
| secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10), |
| millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10); |
| |
| if (this.hour_slider) { |
| this.control.options(this, this.hour_slider, { min: this._defaults.hourMin, max: hourMax }); |
| this.control.value(this, this.hour_slider, this.hour); |
| } |
| if (this.minute_slider) { |
| this.control.options(this, this.minute_slider, { min: this._defaults.minuteMin, max: minMax }); |
| this.control.value(this, this.minute_slider, this.minute); |
| } |
| if (this.second_slider) { |
| this.control.options(this, this.second_slider, { min: this._defaults.secondMin, max: secMax }); |
| this.control.value(this, this.second_slider, this.second); |
| } |
| if (this.millisec_slider) { |
| this.control.options(this, this.millisec_slider, { min: this._defaults.millisecMin, max: millisecMax }); |
| this.control.value(this, this.millisec_slider, this.millisec); |
| } |
| } |
| |
| }, |
| |
| /* |
| * when a slider moves, set the internal time... |
| * on time change is also called when the time is updated in the text field |
| */ |
| _onTimeChange: function() { |
| var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider) : false, |
| minute = (this.minute_slider) ? this.control.value(this, this.minute_slider) : false, |
| second = (this.second_slider) ? this.control.value(this, this.second_slider) : false, |
| millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider) : false, |
| timezone = (this.timezone_select) ? this.timezone_select.val() : false, |
| o = this._defaults; |
| |
| if (typeof(hour) == 'object') { |
| hour = false; |
| } |
| if (typeof(minute) == 'object') { |
| minute = false; |
| } |
| if (typeof(second) == 'object') { |
| second = false; |
| } |
| if (typeof(millisec) == 'object') { |
| millisec = false; |
| } |
| if (typeof(timezone) == 'object') { |
| timezone = false; |
| } |
| |
| if (hour !== false) { |
| hour = parseInt(hour, 10); |
| } |
| if (minute !== false) { |
| minute = parseInt(minute, 10); |
| } |
| if (second !== false) { |
| second = parseInt(second, 10); |
| } |
| if (millisec !== false) { |
| millisec = parseInt(millisec, 10); |
| } |
| |
| var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0]; |
| |
| // If the update was done in the input field, the input field should not be updated. |
| // If the update was done using the sliders, update the input field. |
| var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || millisec != this.millisec |
| || (this.ampm.length > 0 && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) |
| || ((this.timezone === null && timezone != this.defaultTimezone) || (this.timezone !== null && timezone != this.timezone))); |
| |
| if (hasChanged) { |
| |
| if (hour !== false) { |
| this.hour = hour; |
| } |
| if (minute !== false) { |
| this.minute = minute; |
| } |
| if (second !== false) { |
| this.second = second; |
| } |
| if (millisec !== false) { |
| this.millisec = millisec; |
| } |
| if (timezone !== false) { |
| this.timezone = timezone; |
| } |
| |
| if (!this.inst) { |
| this.inst = $.datepicker._getInst(this.$input[0]); |
| } |
| |
| this._limitMinMaxDateTime(this.inst, true); |
| } |
| if (o.ampm) { |
| this.ampm = ampm; |
| } |
| |
| this.formattedTime = $.datepicker.formatTime(this._defaults.timeFormat, this, this._defaults); |
| if (this.$timeObj) { |
| this.$timeObj.text(this.formattedTime + o.timeSuffix); |
| } |
| this.timeDefined = true; |
| if (hasChanged) { |
| this._updateDateTime(); |
| } |
| }, |
| |
| /* |
| * call custom onSelect. |
| * bind to sliders slidestop, and grid click. |
| */ |
| _onSelectHandler: function() { |
| var onSelect = this._defaults.onSelect || this.inst.settings.onSelect; |
| var inputEl = this.$input ? this.$input[0] : null; |
| if (onSelect && inputEl) { |
| onSelect.apply(inputEl, [this.formattedDateTime, this]); |
| } |
| }, |
| |
| /* |
| * update our input with the new date time.. |
| */ |
| _updateDateTime: function(dp_inst) { |
| dp_inst = this.inst || dp_inst; |
| var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)), |
| dateFmt = $.datepicker._get(dp_inst, 'dateFormat'), |
| formatCfg = $.datepicker._getFormatConfig(dp_inst), |
| timeAvailable = dt !== null && this.timeDefined; |
| this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg); |
| var formattedDateTime = this.formattedDate; |
| |
| /* |
| * remove following lines to force every changes in date picker to change the input value |
| * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker. |
| * If the user manually empty the value in the input field, the date picker will never change selected value. |
| */ |
| //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) { |
| // return; |
| //} |
| |
| if (this._defaults.timeOnly === true) { |
| formattedDateTime = this.formattedTime; |
| } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) { |
| formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix; |
| } |
| |
| this.formattedDateTime = formattedDateTime; |
| |
| if (!this._defaults.showTimepicker) { |
| this.$input.val(this.formattedDate); |
| } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) { |
| this.$altInput.val(this.formattedTime); |
| this.$input.val(this.formattedDate); |
| } else if (this.$altInput) { |
| this.$input.val(formattedDateTime); |
| var altFormattedDateTime = '', |
| altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator, |
| altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix; |
| if (this._defaults.altFormat) altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg); |
| else altFormattedDateTime = this.formattedDate; |
| if (altFormattedDateTime) altFormattedDateTime += altSeparator; |
| if (this._defaults.altTimeFormat) altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix; |
| else altFormattedDateTime += this.formattedTime + altTimeSuffix; |
| this.$altInput.val(altFormattedDateTime); |
| } else { |
| this.$input.val(formattedDateTime); |
| } |
| |
| this.$input.trigger("change"); |
| }, |
| |
| _onFocus: function() { |
| if (!this.$input.val() && this._defaults.defaultValue) { |
| this.$input.val(this._defaults.defaultValue); |
| var inst = $.datepicker._getInst(this.$input.get(0)), |
| tp_inst = $.datepicker._get(inst, 'timepicker'); |
| if (tp_inst) { |
| if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { |
| try { |
| $.datepicker._updateDatepicker(inst); |
| } catch (err) { |
| $.datepicker.log(err); |
| } |
| } |
| } |
| } |
| }, |
| |
| /* |
| * Small abstraction to control types |
| * We can add more, just be sure to follow the pattern: create, options, value |
| */ |
| _controls: { |
| // slider methods |
| slider: { |
| create: function(tp_inst, obj, unit, val, min, max, step){ |
| var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60 |
| return obj.prop('slide', null).slider({ |
| orientation: "horizontal", |
| value: rtl? val*-1 : val, |
| min: rtl? max*-1 : min, |
| max: rtl? min*-1 : max, |
| step: step, |
| slide: function(event, ui) { |
| tp_inst.control.value(tp_inst, $(this), rtl? ui.value*-1:ui.value); |
| tp_inst._onTimeChange(); |
| }, |
| stop: function(event, ui) { |
| tp_inst._onSelectHandler(); |
| } |
| }); |
| }, |
| options: function(tp_inst, obj, opts, val){ |
| if(tp_inst._defaults.isRTL){ |
| if(typeof(opts) == 'string'){ |
| if(opts == 'min' || opts == 'max'){ |
| if(val !== undefined) |
| return obj.slider(opts, val*-1); |
| return Math.abs(obj.slider(opts)); |
| } |
| return obj.slider(opts); |
| } |
| var min = opts.min, |
| max = opts.max; |
| opts.min = opts.max = null; |
| if(min !== undefined) |
| opts.max = min * -1; |
| if(max !== undefined) |
| opts.min = max * -1; |
| return obj.slider(opts); |
| } |
| if(typeof(opts) == 'string' && val !== undefined) |
| return obj.slider(opts, val); |
| return obj.slider(opts); |
| }, |
| value: function(tp_inst, obj, val){ |
| if(tp_inst._defaults.isRTL){ |
| if(val !== undefined) |
| return obj.slider('value', val*-1); |
| return Math.abs(obj.slider('value')); |
| } |
| if(val !== undefined) |
| return obj.slider('value', val); |
| return obj.slider('value'); |
| } |
| }, |
| // select methods |
| select: { |
| create: function(tp_inst, obj, unit, val, min, max, step){ |
| var sel = '<select class="ui-timepicker-select" data-unit="'+ unit +'" data-min="'+ min +'" data-max="'+ max +'" data-step="'+ step +'">', |
| ul = tp_inst._defaults.timeFormat.indexOf('t') !== -1? 'toLowerCase':'toUpperCase', |
| m = 0; |
| |
| for(var i=min; i<=max; i+=step){ |
| sel += '<option value="'+ i +'"'+ (i==val? ' selected':'') +'>'; |
| if(unit == 'hour' && tp_inst._defaults.ampm){ |
| m = i%12; |
| if(i === 0 || i === 12) sel += '12'; |
| else if(m < 10) sel += '0'+ m.toString(); |
| else sel += m; |
| sel += ' '+ ((i < 12)? tp_inst._defaults.amNames[0] : tp_inst._defaults.pmNames[0])[ul](); |
| } |
| else if(unit == 'millisec' || i >= 10) sel += i; |
| else sel += '0'+ i.toString(); |
| sel += '</option>'; |
| } |
| sel += '</select>'; |
| |
| obj.children('select').remove(); |
| |
| $(sel).appendTo(obj).change(function(e){ |
| tp_inst._onTimeChange(); |
| tp_inst._onSelectHandler(); |
| }); |
| |
| return obj; |
| }, |
| options: function(tp_inst, obj, opts, val){ |
| var o = {}, |
| $t = obj.children('select'); |
| if(typeof(opts) == 'string'){ |
| if(val === undefined) |
| return $t.data(opts); |
| o[opts] = val; |
| } |
| else o = opts; |
| return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step')); |
| }, |
| value: function(tp_inst, obj, val){ |
| var $t = obj.children('select'); |
| if(val !== undefined) |
| return $t.val(val); |
| return $t.val(); |
| } |
| } |
| } // end _controls |
| |
| }); |
| |
| $.fn.extend({ |
| /* |
| * shorthand just to use timepicker.. |
| */ |
| timepicker: function(o) { |
| o = o || {}; |
| var tmp_args = Array.prototype.slice.call(arguments); |
| |
| if (typeof o == 'object') { |
| tmp_args[0] = $.extend(o, { |
| timeOnly: true |
| }); |
| } |
| |
| return $(this).each(function() { |
| $.fn.datetimepicker.apply($(this), tmp_args); |
| }); |
| }, |
| |
| /* |
| * extend timepicker to datepicker |
| */ |
| datetimepicker: function(o) { |
| o = o || {}; |
| var tmp_args = arguments; |
| |
| if (typeof(o) == 'string') { |
| if (o == 'getDate') { |
| return $.fn.datepicker.apply($(this[0]), tmp_args); |
| } else { |
| return this.each(function() { |
| var $t = $(this); |
| $t.datepicker.apply($t, tmp_args); |
| }); |
| } |
| } else { |
| return this.each(function() { |
| var $t = $(this); |
| $t.datepicker($.timepicker._newInst($t, o)._defaults); |
| }); |
| } |
| } |
| }); |
| |
| /* |
| * Public Utility to parse date and time |
| */ |
| $.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) { |
| var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings); |
| if (parseRes.timeObj) { |
| var t = parseRes.timeObj; |
| parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec); |
| } |
| |
| return parseRes.date; |
| }; |
| |
| /* |
| * Public utility to parse time |
| */ |
| $.datepicker.parseTime = function(timeFormat, timeString, options) { |
| |
| // pattern for standard and localized AM/PM markers |
| var getPatternAmpm = function(amNames, pmNames) { |
| var markers = []; |
| if (amNames) { |
| $.merge(markers, amNames); |
| } |
| if (pmNames) { |
| $.merge(markers, pmNames); |
| } |
| markers = $.map(markers, function(val) { |
| return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&'); |
| }); |
| return '(' + markers.join('|') + ')?'; |
| }; |
| |
| // figure out position of time elements.. cause js cant do named captures |
| var getFormatPositions = function(timeFormat) { |
| var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z|'.*?')/g), |
| orders = { |
| h: -1, |
| m: -1, |
| s: -1, |
| l: -1, |
| t: -1, |
| z: -1 |
| }; |
| |
| if (finds) { |
| for (var i = 0; i < finds.length; i++) { |
| if (orders[finds[i].toString().charAt(0)] == -1) { |
| orders[finds[i].toString().charAt(0)] = i + 1; |
| } |
| } |
| } |
| return orders; |
| }; |
| |
| var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}); |
| |
| var regstr = '^' + timeFormat.toString() |
| .replace(/(hh?|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g, function (match) { |
| switch (match.charAt(0).toLowerCase()) { |
| case 'h': return '(\\d?\\d)'; |
| case 'm': return '(\\d?\\d)'; |
| case 's': return '(\\d?\\d)'; |
| case 'l': return '(\\d?\\d?\\d)'; |
| case 'z': return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?'; |
| case 't': return getPatternAmpm(o.amNames, o.pmNames); |
| default: // literal escaped in quotes |
| return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?'; |
| } |
| }) |
| .replace(/\s/g, '\\s?') + |
| o.timeSuffix + '$', |
| order = getFormatPositions(timeFormat), |
| ampm = '', |
| treg; |
| |
| treg = timeString.match(new RegExp(regstr, 'i')); |
| |
| var resTime = { |
| hour: 0, |
| minute: 0, |
| second: 0, |
| millisec: 0 |
| }; |
| |
| if (treg) { |
| if (order.t !== -1) { |
| if (treg[order.t] === undefined || treg[order.t].length === 0) { |
| ampm = ''; |
| resTime.ampm = ''; |
| } else { |
| ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM'; |
| resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0]; |
| } |
| } |
| |
| if (order.h !== -1) { |
| if (ampm == 'AM' && treg[order.h] == '12') { |
| resTime.hour = 0; // 12am = 0 hour |
| } else { |
| if (ampm == 'PM' && treg[order.h] != '12') { |
| resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12 |
| } else { |
| resTime.hour = Number(treg[order.h]); |
| } |
| } |
| } |
| |
| if (order.m !== -1) { |
| resTime.minute = Number(treg[order.m]); |
| } |
| if (order.s !== -1) { |
| resTime.second = Number(treg[order.s]); |
| } |
| if (order.l !== -1) { |
| resTime.millisec = Number(treg[order.l]); |
| } |
| if (order.z !== -1 && treg[order.z] !== undefined) { |
| var tz = treg[order.z].toUpperCase(); |
| switch (tz.length) { |
| case 1: |
| // Z |
| tz = o.timezoneIso8601 ? 'Z' : '+0000'; |
| break; |
| case 5: |
| // +hhmm |
| if (o.timezoneIso8601) { |
| tz = tz.substring(1) == '0000' ? 'Z' : tz.substring(0, 3) + ':' + tz.substring(3); |
| } |
| break; |
| case 6: |
| // +hh:mm |
| if (!o.timezoneIso8601) { |
| tz = tz == 'Z' || tz.substring(1) == '00:00' ? '+0000' : tz.replace(/:/, ''); |
| } else { |
| if (tz.substring(1) == '00:00') { |
| tz = 'Z'; |
| } |
| } |
| break; |
| } |
| resTime.timezone = tz; |
| } |
| |
| |
| return resTime; |
| } |
| |
| return false; |
| }; |
| |
| /* |
| * Public utility to format the time |
| * format = string format of the time |
| * time = a {}, not a Date() for timezones |
| * options = essentially the regional[].. amNames, pmNames, ampm |
| */ |
| $.datepicker.formatTime = function(format, time, options) { |
| options = options || {}; |
| options = $.extend({}, $.timepicker._defaults, options); |
| time = $.extend({ |
| hour: 0, |
| minute: 0, |
| second: 0, |
| millisec: 0, |
| timezone: '+0000' |
| }, time); |
| |
| var tmptime = format; |
| var ampmName = options.amNames[0]; |
| |
| var hour = parseInt(time.hour, 10); |
| if (options.ampm) { |
| if (hour > 11) { |
| ampmName = options.pmNames[0]; |
| if (hour > 12) { |
| hour = hour % 12; |
| } |
| } |
| if (hour === 0) { |
| hour = 12; |
| } |
| } |
| tmptime = tmptime.replace(/(?:hh?|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g, function(match) { |
| switch (match.toLowerCase()) { |
| case 'hh': |
| return ('0' + hour).slice(-2); |
| case 'h': |
| return hour; |
| case 'mm': |
| return ('0' + time.minute).slice(-2); |
| case 'm': |
| return time.minute; |
| case 'ss': |
| return ('0' + time.second).slice(-2); |
| case 's': |
| return time.second; |
| case 'l': |
| return ('00' + time.millisec).slice(-3); |
| case 'z': |
| return time.timezone === null? options.defaultTimezone : time.timezone; |
| case 't': |
| case 'tt': |
| if (options.ampm) { |
| if (match.length == 1) { |
| ampmName = ampmName.charAt(0); |
| } |
| return match.charAt(0) === 'T' ? ampmName.toUpperCase() : ampmName.toLowerCase(); |
| } |
| return ''; |
| default: |
| return match.replace(/\'/g, "") || "'"; |
| } |
| }); |
| |
| tmptime = $.trim(tmptime); |
| return tmptime; |
| }; |
| |
| /* |
| * the bad hack :/ override datepicker so it doesnt close on select |
| // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378 |
| */ |
| $.datepicker._base_selectDate = $.datepicker._selectDate; |
| $.datepicker._selectDate = function(id, dateStr) { |
| var inst = this._getInst($(id)[0]), |
| tp_inst = this._get(inst, 'timepicker'); |
| |
| if (tp_inst) { |
| tp_inst._limitMinMaxDateTime(inst, true); |
| inst.inline = inst.stay_open = true; |
| //This way the onSelect handler called from calendarpicker get the full dateTime |
| this._base_selectDate(id, dateStr); |
| inst.inline = inst.stay_open = false; |
| this._notifyChange(inst); |
| this._updateDatepicker(inst); |
| } else { |
| this._base_selectDate(id, dateStr); |
| } |
| }; |
| |
| /* |
| * second bad hack :/ override datepicker so it triggers an event when changing the input field |
| * and does not redraw the datepicker on every selectDate event |
| */ |
| $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker; |
| $.datepicker._updateDatepicker = function(inst) { |
| |
| // don't popup the datepicker if there is another instance already opened |
| var input = inst.input[0]; |
| if ($.datepicker._curInst && $.datepicker._curInst != inst && $.datepicker._datepickerShowing && $.datepicker._lastInput != input) { |
| return; |
| } |
| |
| if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) { |
| |
| this._base_updateDatepicker(inst); |
| |
| // Reload the time control when changing something in the input text field. |
| var tp_inst = this._get(inst, 'timepicker'); |
| if (tp_inst) { |
| tp_inst._addTimePicker(inst); |
| |
| if (tp_inst._defaults.useLocalTimezone) { //checks daylight saving with the new date. |
| var date = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay, 12); |
| selectLocalTimeZone(tp_inst, date); |
| tp_inst._onTimeChange(); |
| } |
| } |
| } |
| }; |
| |
| /* |
| * third bad hack :/ override datepicker so it allows spaces and colon in the input field |
| */ |
| $.datepicker._base_doKeyPress = $.datepicker._doKeyPress; |
| $.datepicker._doKeyPress = function(event) { |
| var inst = $.datepicker._getInst(event.target), |
| tp_inst = $.datepicker._get(inst, 'timepicker'); |
| |
| if (tp_inst) { |
| if ($.datepicker._get(inst, 'constrainInput')) { |
| var ampm = tp_inst._defaults.ampm, |
| dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')), |
| datetimeChars = tp_inst._defaults.timeFormat.toString() |
| .replace(/[hms]/g, '') |
| .replace(/TT/g, ampm ? 'APM' : '') |
| .replace(/Tt/g, ampm ? 'AaPpMm' : '') |
| .replace(/tT/g, ampm ? 'AaPpMm' : '') |
| .replace(/T/g, ampm ? 'AP' : '') |
| .replace(/tt/g, ampm ? 'apm' : '') |
| .replace(/t/g, ampm ? 'ap' : '') + |
| " " + tp_inst._defaults.separator + |
| tp_inst._defaults.timeSuffix + |
| (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') + |
| (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) + |
| dateChars, |
| chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode); |
| return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1); |
| } |
| } |
| |
| return $.datepicker._base_doKeyPress(event); |
| }; |
| |
| /* |
| * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField |
| */ |
| $.datepicker._base_updateAlternate = $.datepicker._updateAlternate; |
| /* Update any alternate field to synchronise with the main field. */ |
| $.datepicker._updateAlternate = function(inst) { |
| var tp_inst = this._get(inst, 'timepicker'); |
| if(tp_inst){ |
| var altField = tp_inst._defaults.altField; |
| if (altField) { // update alternate field too |
| var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat, |
| date = this._getDate(inst), |
| formatCfg = $.datepicker._getFormatConfig(inst), |
| altFormattedDateTime = '', |
| altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator, |
| altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix, |
| altTimeFormat = tp_inst._defaults.altTimeFormat !== undefined ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat; |
| |
| altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix; |
| if(!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly){ |
| if(tp_inst._defaults.altFormat) |
| altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, (date === null ? new Date() : date), formatCfg) + altSeparator + altFormattedDateTime; |
| else altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime; |
| } |
| $(altField).val(altFormattedDateTime); |
| } |
| } |
| else{ |
| $.datepicker._base_updateAlternate(inst); |
| } |
| }; |
| |
| /* |
| * Override key up event to sync manual input changes. |
| */ |
| $.datepicker._base_doKeyUp = $.datepicker._doKeyUp; |
| $.datepicker._doKeyUp = function(event) { |
| var inst = $.datepicker._getInst(event.target), |
| tp_inst = $.datepicker._get(inst, 'timepicker'); |
| |
| if (tp_inst) { |
| if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { |
| try { |
| $.datepicker._updateDatepicker(inst); |
| } catch (err) { |
| $.datepicker.log(err); |
| } |
| } |
| } |
| |
| return $.datepicker._base_doKeyUp(event); |
| }; |
| |
| /* |
| * override "Today" button to also grab the time. |
| */ |
| $.datepicker._base_gotoToday = $.datepicker._gotoToday; |
| $.datepicker._gotoToday = function(id) { |
| var inst = this._getInst($(id)[0]), |
| $dp = inst.dpDiv; |
| this._base_gotoToday(id); |
| var tp_inst = this._get(inst, 'timepicker'); |
| selectLocalTimeZone(tp_inst); |
| var now = new Date(); |
| this._setTime(inst, now); |
| $('.ui-datepicker-today', $dp).click(); |
| }; |
| |
| /* |
| * Disable & enable the Time in the datetimepicker |
| */ |
| $.datepicker._disableTimepickerDatepicker = function(target) { |
| var inst = this._getInst(target); |
| if (!inst) { |
| return; |
| } |
| |
| var tp_inst = this._get(inst, 'timepicker'); |
| $(target).datepicker('getDate'); // Init selected[Year|Month|Day] |
| if (tp_inst) { |
| tp_inst._defaults.showTimepicker = false; |
| tp_inst._updateDateTime(inst); |
| } |
| }; |
| |
| $.datepicker._enableTimepickerDatepicker = function(target) { |
| var inst = this._getInst(target); |
| if (!inst) { |
| return; |
| } |
| |
| var tp_inst = this._get(inst, 'timepicker'); |
| $(target).datepicker('getDate'); // Init selected[Year|Month|Day] |
| if (tp_inst) { |
| tp_inst._defaults.showTimepicker = true; |
| tp_inst._addTimePicker(inst); // Could be disabled on page load |
| tp_inst._updateDateTime(inst); |
| } |
| }; |
| |
| /* |
| * Create our own set time function |
| */ |
| $.datepicker._setTime = function(inst, date) { |
| var tp_inst = this._get(inst, 'timepicker'); |
| if (tp_inst) { |
| var defaults = tp_inst._defaults; |
| |
| // calling _setTime with no date sets time to defaults |
| tp_inst.hour = date ? date.getHours() : defaults.hour; |
| tp_inst.minute = date ? date.getMinutes() : defaults.minute; |
| tp_inst.second = date ? date.getSeconds() : defaults.second; |
| tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec; |
| |
| //check if within min/max times.. |
| tp_inst._limitMinMaxDateTime(inst, true); |
| |
| tp_inst._onTimeChange(); |
| tp_inst._updateDateTime(inst); |
| } |
| }; |
| |
| /* |
| * Create new public method to set only time, callable as $().datepicker('setTime', date) |
| */ |
| $.datepicker._setTimeDatepicker = function(target, date, withDate) { |
| var inst = this._getInst(target); |
| if (!inst) { |
| return; |
| } |
| |
| var tp_inst = this._get(inst, 'timepicker'); |
| |
| if (tp_inst) { |
| this._setDateFromField(inst); |
| var tp_date; |
| if (date) { |
| if (typeof date == "string") { |
| tp_inst._parseTime(date, withDate); |
| tp_date = new Date(); |
| tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); |
| } else { |
| tp_date = new Date(date.getTime()); |
| } |
| if (tp_date.toString() == 'Invalid Date') { |
| tp_date = undefined; |
| } |
| this._setTime(inst, tp_date); |
| } |
| } |
| |
| }; |
| |
| /* |
| * override setDate() to allow setting time too within Date object |
| */ |
| $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker; |
| $.datepicker._setDateDatepicker = function(target, date) { |
| var inst = this._getInst(target); |
| if (!inst) { |
| return; |
| } |
| |
| var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date; |
| |
| this._updateDatepicker(inst); |
| this._base_setDateDatepicker.apply(this, arguments); |
| this._setTimeDatepicker(target, tp_date, true); |
| }; |
| |
| /* |
| * override getDate() to allow getting time too within Date object |
| */ |
| $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker; |
| $.datepicker._getDateDatepicker = function(target, noDefault) { |
| var inst = this._getInst(target); |
| if (!inst) { |
| return; |
| } |
| |
| var tp_inst = this._get(inst, 'timepicker'); |
| |
| if (tp_inst) { |
| // if it hasn't yet been defined, grab from field |
| if(inst.lastVal === undefined){ |
| this._setDateFromField(inst, noDefault); |
| } |
| |
| var date = this._getDate(inst); |
| if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) { |
| date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); |
| } |
| return date; |
| } |
| return this._base_getDateDatepicker(target, noDefault); |
| }; |
| |
| /* |
| * override parseDate() because UI 1.8.14 throws an error about "Extra characters" |
| * An option in datapicker to ignore extra format characters would be nicer. |
| */ |
| $.datepicker._base_parseDate = $.datepicker.parseDate; |
| $.datepicker.parseDate = function(format, value, settings) { |
| var date; |
| try { |
| date = this._base_parseDate(format, value, settings); |
| } catch (err) { |
| // Hack! The error message ends with a colon, a space, and |
| // the "extra" characters. We rely on that instead of |
| // attempting to perfectly reproduce the parsing algorithm. |
| date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings); |
| } |
| return date; |
| }; |
| |
| /* |
| * override formatDate to set date with time to the input |
| */ |
| $.datepicker._base_formatDate = $.datepicker._formatDate; |
| $.datepicker._formatDate = function(inst, day, month, year) { |
| var tp_inst = this._get(inst, 'timepicker'); |
| if (tp_inst) { |
| tp_inst._updateDateTime(inst); |
| return tp_inst.$input.val(); |
| } |
| return this._base_formatDate(inst); |
| }; |
| |
| /* |
| * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate |
| */ |
| $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker; |
| $.datepicker._optionDatepicker = function(target, name, value) { |
| var inst = this._getInst(target), |
| name_clone; |
| if (!inst) { |
| return null; |
| } |
| |
| var tp_inst = this._get(inst, 'timepicker'); |
| if (tp_inst) { |
| var min = null, |
| max = null, |
| onselect = null, |
| overrides = tp_inst._defaults.evnts, |
| fns = {}, |
| prop; |
| if (typeof name == 'string') { // if min/max was set with the string |
| if (name === 'minDate' || name === 'minDateTime') { |
| min = value; |
| } else if (name === 'maxDate' || name === 'maxDateTime') { |
| max = value; |
| } else if (name === 'onSelect') { |
| onselect = value; |
| } else if (overrides.hasOwnProperty(name)) { |
| if (typeof (value) === 'undefined') { |
| return overrides[name]; |
| } |
| fns[name] = value; |
| name_clone = {}; //empty results in exiting function after overrides updated |
| } |
| } else if (typeof name == 'object') { //if min/max was set with the JSON |
| if (name.minDate) { |
| min = name.minDate; |
| } else if (name.minDateTime) { |
| min = name.minDateTime; |
| } else if (name.maxDate) { |
| max = name.maxDate; |
| } else if (name.maxDateTime) { |
| max = name.maxDateTime; |
| } |
| for (prop in overrides) { |
| if (overrides.hasOwnProperty(prop) && name[prop]) { |
| fns[prop] = name[prop]; |
| } |
| } |
| } |
| for (prop in fns) { |
| if (fns.hasOwnProperty(prop)) { |
| overrides[prop] = fns[prop]; |
| if (!name_clone) { name_clone = $.extend({}, name);} |
| delete name_clone[prop]; |
| } |
| } |
| if (name_clone && isEmptyObject(name_clone)) { return; } |
| if (min) { //if min was set |
| if (min === 0) { |
| min = new Date(); |
| } else { |
| min = new Date(min); |
| } |
| tp_inst._defaults.minDate = min; |
| tp_inst._defaults.minDateTime = min; |
| } else if (max) { //if max was set |
| if (max === 0) { |
| max = new Date(); |
| } else { |
| max = new Date(max); |
| } |
| tp_inst._defaults.maxDate = max; |
| tp_inst._defaults.maxDateTime = max; |
| } else if (onselect) { |
| tp_inst._defaults.onSelect = onselect; |
| } |
| } |
| if (value === undefined) { |
| return this._base_optionDatepicker.call($.datepicker, target, name); |
| } |
| return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value); |
| }; |
| /* |
| * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype, |
| * it will return false for all objects |
| */ |
| function isEmptyObject (obj) { |
| var prop; |
| for (prop in obj) { |
| if (obj.hasOwnProperty(obj)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| /* |
| * jQuery extend now ignores nulls! |
| */ |
| function extendRemove(target, props) { |
| $.extend(target, props); |
| for (var name in props) { |
| if (props[name] === null || props[name] === undefined) { |
| target[name] = props[name]; |
| } |
| } |
| return target; |
| } |
| |
| /* |
| * Splits datetime string into date ans time substrings. |
| * Throws exception when date can't be parsed |
| * Returns [dateString, timeString] |
| */ |
| var splitDateTime = function(dateFormat, dateTimeString, dateSettings, timeSettings) { |
| try { |
| // The idea is to get the number separator occurances in datetime and the time format requested (since time has |
| // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split. |
| var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator, |
| format = timeSettings && timeSettings.timeFormat ? timeSettings.timeFormat : $.timepicker._defaults.timeFormat, |
| ampm = timeSettings && timeSettings.ampm ? timeSettings.ampm : $.timepicker._defaults.ampm, |
| timeParts = format.split(separator), // how many occurances of separator may be in our format? |
| timePartsLen = timeParts.length, |
| allParts = dateTimeString.split(separator), |
| allPartsLen = allParts.length; |
| |
| // because our default ampm=false, but our default format has tt, we need to filter this out |
| if(!ampm){ |
| timeParts = $.trim(format.replace(/t/gi,'')).split(separator); |
| timePartsLen = timeParts.length; |
| } |
| |
| if (allPartsLen > 1) { |
| return [ |
| allParts.splice(0,allPartsLen-timePartsLen).join(separator), |
| allParts.splice(0,timePartsLen).join(separator) |
| ]; |
| } |
| |
| } catch (err) { |
| if (err.indexOf(":") >= 0) { |
| // Hack! The error message ends with a colon, a space, and |
| // the "extra" characters. We rely on that instead of |
| // attempting to perfectly reproduce the parsing algorithm. |
| var dateStringLength = dateTimeString.length - (err.length - err.indexOf(':') - 2), |
| timeString = dateTimeString.substring(dateStringLength); |
| |
| return [$.trim(dateTimeString.substring(0, dateStringLength)), $.trim(dateTimeString.substring(dateStringLength))]; |
| |
| } else { |
| throw err; |
| } |
| } |
| return [dateTimeString, '']; |
| }; |
| |
| /* |
| * Internal function to parse datetime interval |
| * Returns: {date: Date, timeObj: Object}, where |
| * date - parsed date without time (type Date) |
| * timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional |
| */ |
| var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) { |
| var date; |
| var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings, timeSettings); |
| date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings); |
| if (splitRes[1] !== '') { |
| var timeString = splitRes[1], |
| parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings); |
| |
| if (parsedTime === null) { |
| throw 'Wrong time format'; |
| } |
| return { |
| date: date, |
| timeObj: parsedTime |
| }; |
| } else { |
| return { |
| date: date |
| }; |
| } |
| }; |
| |
| /* |
| * Internal function to set timezone_select to the local timezone |
| */ |
| var selectLocalTimeZone = function(tp_inst, date) { |
| if (tp_inst && tp_inst.timezone_select) { |
| tp_inst._defaults.useLocalTimezone = true; |
| var now = typeof date !== 'undefined' ? date : new Date(); |
| var tzoffset = $.timepicker.timeZoneOffsetString(now); |
| if (tp_inst._defaults.timezoneIso8601) { |
| tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3); |
| } |
| tp_inst.timezone_select.val(tzoffset); |
| } |
| }; |
| |
| /* |
| * Create a Singleton Insance |
| */ |
| $.timepicker = new Timepicker(); |
| |
| /** |
| * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5) |
| * @param date |
| * @return string |
| */ |
| $.timepicker.timeZoneOffsetString = function(date) { |
| var off = date.getTimezoneOffset() * -1, |
| minutes = off % 60, |
| hours = (off - minutes) / 60; |
| return (off >= 0 ? '+' : '-') + ('0' + (hours * 101).toString()).substr(-2) + ('0' + (minutes * 101).toString()).substr(-2); |
| }; |
| |
| /** |
| * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to |
| * enforce date range limits. |
| * n.b. The input value must be correctly formatted (reformatting is not supported) |
| * @param Element startTime |
| * @param Element endTime |
| * @param obj options Options for the timepicker() call |
| * @return jQuery |
| */ |
| $.timepicker.timeRange = function(startTime, endTime, options) { |
| return $.timepicker.handleRange('timepicker', startTime, endTime, options); |
| }; |
| |
| /** |
| * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to |
| * enforce date range limits. |
| * @param Element startTime |
| * @param Element endTime |
| * @param obj options Options for the `timepicker()` call. Also supports `reformat`, |
| * a boolean value that can be used to reformat the input values to the `dateFormat`. |
| * @param string method Can be used to specify the type of picker to be added |
| * @return jQuery |
| */ |
| $.timepicker.dateTimeRange = function(startTime, endTime, options) { |
| $.timepicker.dateRange(startTime, endTime, options, 'datetimepicker'); |
| }; |
| |
| /** |
| * Calls `method` on the `startTime` and `endTime` elements, and configures them to |
| * enforce date range limits. |
| * @param Element startTime |
| * @param Element endTime |
| * @param obj options Options for the `timepicker()` call. Also supports `reformat`, |
| * a boolean value that can be used to reformat the input values to the `dateFormat`. |
| * @param string method Can be used to specify the type of picker to be added |
| * @return jQuery |
| */ |
| $.timepicker.dateRange = function(startTime, endTime, options, method) { |
| method = method || 'datepicker'; |
| $.timepicker.handleRange(method, startTime, endTime, options); |
| }; |
| |
| /** |
| * Calls `method` on the `startTime` and `endTime` elements, and configures them to |
| * enforce date range limits. |
| * @param string method Can be used to specify the type of picker to be added |
| * @param Element startTime |
| * @param Element endTime |
| * @param obj options Options for the `timepicker()` call. Also supports `reformat`, |
| * a boolean value that can be used to reformat the input values to the `dateFormat`. |
| * @return jQuery |
| */ |
| $.timepicker.handleRange = function(method, startTime, endTime, options) { |
| $.fn[method].call(startTime, $.extend({ |
| onClose: function(dateText, inst) { |
| checkDates(this, endTime, dateText); |
| }, |
| onSelect: function(selectedDateTime) { |
| selected(this, endTime, 'minDate'); |
| } |
| }, options, options.start)); |
| $.fn[method].call(endTime, $.extend({ |
| onClose: function(dateText, inst) { |
| checkDates(this, startTime, dateText); |
| }, |
| onSelect: function(selectedDateTime) { |
| selected(this, startTime, 'maxDate'); |
| } |
| }, options, options.end)); |
| // timepicker doesn't provide access to its 'timeFormat' option, |
| // nor could I get datepicker.formatTime() to behave with times, so I |
| // have disabled reformatting for timepicker |
| if (method != 'timepicker' && options.reformat) { |
| $([startTime, endTime]).each(function() { |
| var format = $(this)[method].call($(this), 'option', 'dateFormat'), |
| date = new Date($(this).val()); |
| if ($(this).val() && date) { |
| $(this).val($.datepicker.formatDate(format, date)); |
| } |
| }); |
| } |
| checkDates(startTime, endTime, startTime.val()); |
| |
| function checkDates(changed, other, dateText) { |
| if (other.val() && (new Date(startTime.val()) > new Date(endTime.val()))) { |
| other.val(dateText); |
| } |
| } |
| selected(startTime, endTime, 'minDate'); |
| selected(endTime, startTime, 'maxDate'); |
| |
| function selected(changed, other, option) { |
| if (!$(changed).val()) { |
| return; |
| } |
| var date = $(changed)[method].call($(changed), 'getDate'); |
| // timepicker doesn't implement 'getDate' and returns a jQuery |
| if (date.getTime) { |
| $(other)[method].call($(other), 'option', option, date); |
| } |
| } |
| return $([startTime.get(0), endTime.get(0)]); |
| }; |
| |
| /* |
| * Keep up with the version |
| */ |
| $.timepicker.version = "1.0.5"; |
| |
| })(jQuery); |