diff options
Diffstat (limited to 'jquery-ui-timepicker-addon.js')
-rw-r--r-- | jquery-ui-timepicker-addon.js | 712 |
1 files changed, 458 insertions, 254 deletions
diff --git a/jquery-ui-timepicker-addon.js b/jquery-ui-timepicker-addon.js index 0a4ff02..8d5a107 100644 --- a/jquery-ui-timepicker-addon.js +++ b/jquery-ui-timepicker-addon.js @@ -1,11 +1,11 @@ /* * jQuery timepicker addon * By: Trent Richardson [http://trentrichardson.com] -* Version 1.0.0 -* Last Modified: 02/05/2012 +* Version 1.0.1 +* Last Modified: 07/01/2012 * * Copyright 2012 Trent Richardson -* Dual licensed under the MIT and GPL licenses. +* You may use this project under MIT or GPL licenses. * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt * @@ -18,6 +18,8 @@ * .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } */ +/*jslint evil: true, maxlen: 300, white: false, undef: false, nomen: false, onevar: false */ + (function($) { // Prevent "Uncaught RangeError: Maximum call stack size exceeded" @@ -26,7 +28,7 @@ if ($.ui.timepicker.version) { return; } -$.extend($.ui, { timepicker: { version: "1.0.0" } }); +$.extend($.ui, { timepicker: { version: "1.0.1" } }); /* Time picker manager. Use the singleton instance of this class, $.timepicker, to interact with the time picker. @@ -68,7 +70,9 @@ function Timepicker() { minute: 0, second: 0, millisec: 0, - timezone: '+0000', + timezone: null, + useLocalTimezone: false, + defaultTimezone: "+0000", hourMin: 0, minuteMin: 0, secondMin: 0, @@ -88,13 +92,13 @@ function Timepicker() { separator: ' ', altFieldTimeOnly: true, showTimepicker: true, - timezoneIso8609: false, + timezoneIso8601: false, timezoneList: null, addSliderAccess: false, sliderAccessArgs: null }; $.extend(this._defaults, this.regional['']); -}; +} $.extend(Timepicker.prototype, { $input: null, @@ -110,7 +114,8 @@ $.extend(Timepicker.prototype, { minute: 0, second: 0, millisec: 0, - timezone: '+0000', + timezone: null, + defaultTimezone: "+0000", hourMinOriginal: null, minuteMinOriginal: null, secondMinOriginal: null, @@ -152,20 +157,24 @@ $.extend(Timepicker.prototype, { } tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, { beforeShow: function(input, dp_inst) { - if ($.isFunction(o.beforeShow)) + if ($.isFunction(o.beforeShow)) { return o.beforeShow(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(o.onChangeMonthYear)) + if ($.isFunction(o.onChangeMonthYear)) { o.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst); + } }, onClose: function(dateText, dp_inst) { - if (tp_inst.timeDefined === true && $input.val() != '') + if (tp_inst.timeDefined === true && $input.val() !== '') { tp_inst._updateDateTime(dp_inst); - if ($.isFunction(o.onClose)) + } + if ($.isFunction(o.onClose)) { o.onClose.call($input[0], dateText, dp_inst, tp_inst); + } }, timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker'); }); @@ -174,15 +183,18 @@ $.extend(Timepicker.prototype, { if (tp_inst._defaults.timezoneList === null) { var timezoneList = []; - for (var i = -11; i <= 12; i++) + for (var i = -11; i <= 12; i++) { timezoneList.push((i >= 0 ? '+' : '-') + ('0' + Math.abs(i).toString()).slice(-2) + '00'); - if (tp_inst._defaults.timezoneIso8609) + } + 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; @@ -190,29 +202,34 @@ $.extend(Timepicker.prototype, { tp_inst.ampm = ''; tp_inst.$input = $input; - if (o.altField) + 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) + 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) + 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) + 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) + } + 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) + } + 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) + } + if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) { tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); + } return tp_inst; }, @@ -233,112 +250,32 @@ $.extend(Timepicker.prototype, { // parse the time string from input value or _setTime //######################################################################## _parseTime: function(timeString, withDate) { - var regstr = this._defaults.timeFormat.toString() - .replace(/h{1,2}/ig, '(\\d?\\d)') - .replace(/m{1,2}/ig, '(\\d?\\d)') - .replace(/s{1,2}/ig, '(\\d?\\d)') - .replace(/l{1}/ig, '(\\d?\\d?\\d)') - .replace(/t{1,2}/ig, this._getPatternAmpm()) - .replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?') - .replace(/\s/g, '\\s?') + this._defaults.timeSuffix + '$', - order = this._getFormatPositions(), - ampm = '', - treg; - - if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]); - - if (withDate || !this._defaults.timeOnly) { - // the time should come after x number of characters and a space. - // x = at least the length of text specified by the date format - var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); - // escape special regex characters in the seperator - var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); - regstr = '^.{' + dp_dateFormat.length + ',}?' + this._defaults.separator.replace(specials, "\\$&") + regstr; + if (!this.inst) { + this.inst = $.datepicker._getInst(this.$input[0]); } - - treg = timeString.match(new RegExp(regstr, 'i')); - - if (treg) { - if (order.t !== -1) { - if (treg[order.t] === undefined || treg[order.t].length === 0) { - ampm = ''; - this.ampm = ''; - } else { - ampm = $.inArray(treg[order.t].toUpperCase(), this.amNames) !== -1 ? 'AM' : 'PM'; - this.ampm = this._defaults[ampm == 'AM' ? 'amNames' : 'pmNames'][0]; - } - } - - if (order.h !== -1) { - if (ampm == 'AM' && treg[order.h] == '12') - this.hour = 0; // 12am = 0 hour - else if (ampm == 'PM' && treg[order.h] != '12') - this.hour = (parseFloat(treg[order.h]) + 12).toFixed(0); // 12pm = 12 hour, any other pm = hour + 12 - else this.hour = Number(treg[order.h]); - } - - if (order.m !== -1) this.minute = Number(treg[order.m]); - if (order.s !== -1) this.second = Number(treg[order.s]); - if (order.l !== -1) this.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 = this._defaults.timezoneIso8609 ? 'Z' : '+0000'; - break; - case 5: // +hhmm - if (this._defaults.timezoneIso8609) - tz = tz.substring(1) == '0000' - ? 'Z' - : tz.substring(0, 3) + ':' + tz.substring(3); - break; - case 6: // +hh:mm - if (!this._defaults.timezoneIso8609) - tz = tz == 'Z' || tz.substring(1) == '00:00' - ? '+0000' - : tz.replace(/:/, ''); - else if (tz.substring(1) == '00:00') - tz = 'Z'; - break; - } - this.timezone = tz; + + 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; - } - return false; - }, - - //######################################################################## - // pattern for standard and localized AM/PM markers - //######################################################################## - _getPatternAmpm: function() { - var markers = [], - o = this._defaults; - if (o.amNames) - $.merge(markers, o.amNames); - if (o.pmNames) - $.merge(markers, o.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 - //######################################################################## - _getFormatPositions: function() { - var finds = this._defaults.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; + 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 //######################################################################## @@ -372,7 +309,7 @@ $.extend(Timepicker.prototype, { millisecGridSize = 0, size = null; - // Hours + // Hours html += '<dd class="ui_tpicker_hour"><div id="ui_tpicker_hour_' + dp_id + '"' + ((o.showHour) ? '' : noDisplay) + '></div>'; if (o.showHour && o.hourGrid > 0) { @@ -381,11 +318,14 @@ $.extend(Timepicker.prototype, { for (var h = o.hourMin; h <= hourMax; h += parseInt(o.hourGrid,10)) { hourGridSize++; var tmph = (o.ampm && h > 12) ? h-12 : h; - if (tmph < 10) tmph = '0' + tmph; + if (tmph < 10) { tmph = '0' + tmph; } if (o.ampm) { - if (h == 0) tmph = 12 +'a'; - else if (h < 12) tmph += 'a'; - else tmph += 'p'; + if (h === 0) { + tmph = 12 +'a'; + } else { + if (h < 12) { tmph += 'a'; } + else { tmph += 'p'; } + } } html += '<td>' + tmph + '</td>'; } @@ -455,7 +395,7 @@ $.extend(Timepicker.prototype, { ((o.showTimezone) ? '' : noDisplay) + '></dd>'; html += '</dl></div>'; - $tp = $(html); + var $tp = $(html); // if we only want time picker... if (o.timeOnly === true) { @@ -525,8 +465,23 @@ $.extend(Timepicker.prototype, { .text(typeof val == "object" ? val.label : val); }) ); - this.timezone_select.val((typeof this.timezone != "undefined" && this.timezone != null && this.timezone != "") ? this.timezone : o.timezone); + 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 = timeZoneString(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(); }); @@ -545,10 +500,10 @@ $.extend(Timepicker.prototype, { 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; + if (aph == 12) { h = 0; } + else { h = aph; } + } else if (aph == 12) { h = 12; } + else { h = aph + 12; } } tp_inst.hour_slider.slider("option", "value", h); tp_inst._onTimeChange(); @@ -621,8 +576,8 @@ $.extend(Timepicker.prototype, { } var $buttonPanel = $dp.find('.ui-datepicker-buttonpane'); - if ($buttonPanel.length) $buttonPanel.before($tp); - else $dp.append($tp); + if ($buttonPanel.length) { $buttonPanel.before($tp); } + else { $dp.append($tp); } this.$timeObj = $tp.find('#ui_tpicker_time_'+ dp_id); @@ -645,7 +600,7 @@ $.extend(Timepicker.prototype, { if (this._defaults.addSliderAccess){ var sliderAccessArgs = this._defaults.sliderAccessArgs; setTimeout(function(){ // fix for inline mode - if($tp.find('.ui-slider-access').length == 0){ + if($tp.find('.ui-slider-access').length === 0){ $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs); // fix any grids since sliders are shorter @@ -677,7 +632,7 @@ $.extend(Timepicker.prototype, { 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(!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'), @@ -702,8 +657,9 @@ $.extend(Timepicker.prototype, { this.second = this._defaults.secondMin; this._defaults.millisecMin = minDateTime.getMilliseconds(); } else { - if(this.millisec < this._defaults.millisecMin) + if(this.millisec < this._defaults.millisecMin) { this.millisec = this._defaults.millisecMin; + } this._defaults.millisecMin = this.millisecMinOriginal; } } else { @@ -742,7 +698,7 @@ $.extend(Timepicker.prototype, { this.second = this._defaults.secondMax; this._defaults.millisecMax = maxDateTime.getMilliseconds(); } else { - if(this.millisec > this._defaults.millisecMax) this.millisec = this._defaults.millisecMax; + if(this.millisec > this._defaults.millisecMax) { this.millisec = this._defaults.millisecMax; } this._defaults.millisecMax = this.millisecMaxOriginal; } } else { @@ -764,14 +720,18 @@ $.extend(Timepicker.prototype, { 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) + if(this.hour_slider) { this.hour_slider.slider("option", { min: this._defaults.hourMin, max: hourMax }).slider('value', this.hour); - if(this.minute_slider) + } + if(this.minute_slider) { this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: minMax }).slider('value', this.minute); - if(this.second_slider) + } + if(this.second_slider){ this.second_slider.slider("option", { min: this._defaults.secondMin, max: secMax }).slider('value', this.second); - if(this.millisec_slider) + } + if(this.millisec_slider) { this.millisec_slider.slider("option", { min: this._defaults.millisecMin, max: millisecMax }).slider('value', this.millisec); + } } }, @@ -789,46 +749,46 @@ $.extend(Timepicker.prototype, { 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 (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); + 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)) - || timezone != this.timezone); + 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)) || + 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 (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]); + if (!this.inst) { this.inst = $.datepicker._getInst(this.$input[0]); } this._limitMinMaxDateTime(this.inst, true); } - if (o.ampm) this.ampm = ampm; + if (o.ampm) { this.ampm = ampm; } //this._formatTime(); this.formattedTime = $.datepicker.formatTime(this._defaults.timeFormat, this, this._defaults); - if (this.$timeObj) this.$timeObj.text(this.formattedTime + o.timeSuffix); + if (this.$timeObj) { this.$timeObj.text(this.formattedTime + o.timeSuffix); } this.timeDefined = true; - if (hasChanged) this._updateDateTime(); + if (hasChanged) { this._updateDateTime(); } }, //######################################################################## @@ -852,8 +812,8 @@ $.extend(Timepicker.prototype, { tmptime = $.datepicker.formatTime(tmptime, time, this._defaults); - if (arguments.length) return tmptime; - else this.formattedTime = tmptime; + if (arguments.length) { return tmptime; } + else { this.formattedTime = tmptime; } }, //######################################################################## @@ -867,8 +827,12 @@ $.extend(Timepicker.prototype, { timeAvailable = dt !== null && this.timeDefined; this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg); var formattedDateTime = this.formattedDate; - if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) - return; + // 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; @@ -903,7 +867,7 @@ $.fn.extend({ o = o || {}; var tmp_args = arguments; - if (typeof o == 'object') tmp_args[0] = $.extend(o, { timeOnly: true }); + if (typeof o == 'object') { tmp_args[0] = $.extend(o, { timeOnly: true }); } return $(this).each(function() { $.fn.datetimepicker.apply($(this), tmp_args); @@ -915,25 +879,151 @@ $.fn.extend({ //######################################################################## datetimepicker: function(o) { o = o || {}; - tmp_args = arguments; + var tmp_args = arguments; if (typeof(o) == 'string'){ - if(o == 'getDate') + if(o == 'getDate') { return $.fn.datepicker.apply($(this[0]), tmp_args); - else + } + else { return this.each(function() { var $t = $(this); $t.datepicker.apply($t, tmp_args); }); + } } - else + else { return this.each(function() { var $t = $(this); $t.datepicker($.timepicker._newInst($t, o)._defaults); }); + } } }); +$.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; +}; + +$.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(/h{1,2}/ig, '(\\d?\\d)') + .replace(/m{1,2}/ig, '(\\d?\\d)') + .replace(/s{1,2}/ig, '(\\d?\\d)') + .replace(/l{1}/ig, '(\\d?\\d?\\d)') + .replace(/t{1,2}/ig, getPatternAmpm(o.amNames, o.pmNames)) + .replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?') + .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], 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; +}; + //######################################################################## // format the time all pretty... // format = string format of the time @@ -946,17 +1036,19 @@ $.datepicker.formatTime = function(format, time, options) { time = $.extend({hour:0, minute:0, second:0, millisec:0, timezone:'+0000'}, time); var tmptime = format; - var ampmName = options['amNames'][0]; + var ampmName = options.amNames[0]; var hour = parseInt(time.hour, 10); if (options.ampm) { if (hour > 11){ - ampmName = options['pmNames'][0]; - if(hour > 12) + ampmName = options.pmNames[0]; + if(hour > 12) { hour = hour % 12; + } } - if (hour === 0) + if (hour === 0) { hour = 12; + } } tmptime = tmptime.replace(/(?:hh?|mm?|ss?|[tT]{1,2}|[lz])/g, function(match) { switch (match.toLowerCase()) { @@ -970,8 +1062,9 @@ $.datepicker.formatTime = function(format, time, options) { case 'z': return time.timezone; case 't': case 'tt': if (options.ampm) { - if (match.length == 1) + if (match.length == 1) { ampmName = ampmName.charAt(0); + } return match.charAt(0) == 'T' ? ampmName.toUpperCase() : ampmName.toLowerCase(); } return ''; @@ -1000,7 +1093,7 @@ $.datepicker._selectDate = function (id, dateStr) { this._notifyChange(inst); this._updateDatepicker(inst); } - else this._base_selectDate(id, dateStr); + else { this._base_selectDate(id, dateStr); } }; //############################################################################################# @@ -1025,7 +1118,15 @@ $.datepicker._updateDatepicker = function(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) { + 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(); + } + } } }; @@ -1094,18 +1195,9 @@ $.datepicker._gotoToday = function(id) { var inst = this._getInst($(id)[0]), $dp = inst.dpDiv; this._base_gotoToday(id); - var now = new Date(); var tp_inst = this._get(inst, 'timepicker'); - if (tp_inst && tp_inst._defaults.showTimezone && tp_inst.timezone_select) { - var tzoffset = now.getTimezoneOffset(); // If +0100, returns -60 - var tzsign = tzoffset > 0 ? '-' : '+'; - tzoffset = Math.abs(tzoffset); - var tzmin = tzoffset % 60; - tzoffset = tzsign + ('0' + (tzoffset - tzmin) / 60).slice(-2) + ('0' + tzmin).slice(-2); - if (tp_inst._defaults.timezoneIso8609) - tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3); - tp_inst.timezone_select.val(tzoffset); - } + selectLocalTimeZone(tp_inst); + var now = new Date(); this._setTime(inst, now); $( '.ui-datepicker-today', $dp).click(); }; @@ -1113,9 +1205,11 @@ $.datepicker._gotoToday = function(id) { //####################################################################################### // Disable & enable the Time in the datetimepicker //####################################################################################### -$.datepicker._disableTimepickerDatepicker = function(target, date, withDate) { - var inst = this._getInst(target), - tp_inst = this._get(inst, 'timepicker'); +$.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; @@ -1123,9 +1217,11 @@ $.datepicker._disableTimepickerDatepicker = function(target, date, withDate) { } }; -$.datepicker._enableTimepickerDatepicker = function(target, date, withDate) { - var inst = this._getInst(target), - tp_inst = this._get(inst, 'timepicker'); +$.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; @@ -1146,20 +1242,31 @@ $.datepicker._setTime = function(inst, date) { minute = date ? date.getMinutes() : defaults.minute, second = date ? date.getSeconds() : defaults.second, millisec = date ? date.getMilliseconds() : defaults.millisec; - //check if within min/max times.. - if ((hour < defaults.hourMin || hour > defaults.hourMax) || (minute < defaults.minuteMin || minute > defaults.minuteMax) || (second < defaults.secondMin || second > defaults.secondMax) || (millisec < defaults.millisecMin || millisec > defaults.millisecMax)) { + // correct check if within min/max times. + // Rewritten by Scott A. Woodward + var hourEq = hour === defaults.hourMin, + minuteEq = minute === defaults.minuteMin, + secondEq = second === defaults.secondMin; + var reset = false; + if(hour < defaults.hourMin || hour > defaults.hourMax) + reset = true; + else if( (minute < defaults.minuteMin || minute > defaults.minuteMax) && hourEq) + reset = true; + else if( (second < defaults.secondMin || second > defaults.secondMax ) && hourEq && minuteEq) + reset = true; + else if( (millisec < defaults.millisecMin || millisec > defaults.millisecMax) && hourEq && minuteEq && secondEq) + reset = true; + if(reset) { hour = defaults.hourMin; minute = defaults.minuteMin; second = defaults.secondMin; millisec = defaults.millisecMin; } - tp_inst.hour = hour; tp_inst.minute = minute; tp_inst.second = second; tp_inst.millisec = millisec; - if (tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour); if (tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute); if (tp_inst.second_slider) tp_inst.second_slider.slider('value', second); @@ -1174,9 +1281,11 @@ $.datepicker._setTime = function(inst, date) { // Create new public method to set only time, callable as $().datepicker('setTime', date) //####################################################################################### $.datepicker._setTimeDatepicker = function(target, date, withDate) { - var inst = this._getInst(target), - tp_inst = this._get(inst, 'timepicker'); - + var inst = this._getInst(target); + if (!inst) { return; } + + var tp_inst = this._get(inst, 'timepicker'); + if (tp_inst) { this._setDateFromField(inst); var tp_date; @@ -1186,8 +1295,8 @@ $.datepicker._setTimeDatepicker = function(target, 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; + else { tp_date = new Date(date.getTime()); } + if (tp_date.toString() == 'Invalid Date') { tp_date = undefined; } this._setTime(inst, tp_date); } } @@ -1199,8 +1308,10 @@ $.datepicker._setTimeDatepicker = function(target, date, withDate) { //####################################################################################### $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker; $.datepicker._setDateDatepicker = function(target, date) { - var inst = this._getInst(target), - tp_date = (date instanceof Date) ? new Date(date.getTime()) : 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); @@ -1212,13 +1323,15 @@ $.datepicker._setDateDatepicker = function(target, date) { //####################################################################################### $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker; $.datepicker._getDateDatepicker = function(target, noDefault) { - var inst = this._getInst(target), - tp_inst = this._get(inst, 'timepicker'); + var inst = this._getInst(target); + if (!inst) { return; } + + var tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { 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); + 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); @@ -1230,21 +1343,8 @@ $.datepicker._getDateDatepicker = function(target, noDefault) { //####################################################################################### $.datepicker._base_parseDate = $.datepicker.parseDate; $.datepicker.parseDate = function(format, value, settings) { - var date; - try { - date = this._base_parseDate(format, value, settings); - } 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. - date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings); - } else { - // The underlying error was not related to the time - throw err; - } - } - return date; + var splitRes = splitDateTime(format, value, settings); + return $.datepicker._base_parseDate(format, splitRes[0], settings); }; //####################################################################################### @@ -1265,47 +1365,69 @@ $.datepicker._formatDate = function(inst, day, month, year){ //####################################################################################### $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker; $.datepicker._optionDatepicker = function(target, name, value) { - var inst = this._getInst(target), - tp_inst = this._get(inst, 'timepicker'); + var inst = this._getInst(target); + if (!inst) { return null; } + + var tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { var min = null, max = null, onselect = null; if (typeof name == 'string') { // if min/max was set with the string - if (name === 'minDate' || name === 'minDateTime' ) + if (name === 'minDate' || name === 'minDateTime' ) { min = value; - else if (name === 'maxDate' || name === 'maxDateTime') - max = value; - else if (name === 'onSelect') - onselect = value; - } 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; - } + } + else { + if (name === 'maxDate' || name === 'maxDateTime') { + max = value; + } + else { + if (name === 'onSelect') { + onselect = value; + } + } + } + } 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; + } + } + } + } + } + } if(min) { //if min was set - if (min == 0) + if (min === 0) { min = new Date(); - else + } 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) + if(max===0) { max=new Date(); - else + } else { max= new Date(max); + } tp_inst._defaults.maxDate = max; tp_inst._defaults.maxDateTime = max; - } else if (onselect) + } else if (onselect) { tp_inst._defaults.onSelect = onselect; + } } - if (value === undefined) + if (value === undefined) { return this._base_optionDatepicker(target, name); + } return this._base_optionDatepicker(target, name, value); }; @@ -1314,13 +1436,95 @@ $.datepicker._optionDatepicker = function(target, name, value) { //####################################################################################### function extendRemove(target, props) { $.extend(target, props); - for (var name in props) - if (props[name] === null || props[name] === undefined) + 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 +// If only date is present, time substring eill be '' +//####################################################################################### +var splitDateTime = function(dateFormat, dateTimeString, dateSettings) +{ + try { + var date = $.datepicker._base_parseDate(dateFormat, dateTimeString, dateSettings); + } 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); + var timeString = dateTimeString.substring(dateStringLength); + + return [dateTimeString.substring(0, dateStringLength), 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); + date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings); + if (splitRes[1] !== '') + { + var timeString = splitRes[1]; + var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator; + if ( timeString.indexOf(separator) !== 0) { + throw 'Missing time separator'; + } + timeString = timeString.substring(separator.length); + var 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 = timeZoneString(now); + if (tp_inst._defaults.timezoneIso8601) { + tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3); + } + tp_inst.timezone_select.val(tzoffset); + } +}; + +// Input: Date Object +// Output: String with timezone offset, e.g. '+0100' +var timeZoneString = function(date) +{ + var off = date.getTimezoneOffset() * -10100 / 60; + var timezone = (off >= 0 ? '+' : '-') + Math.abs(off).toString().substr(1); + return timezone; }; $.timepicker = new Timepicker(); // singleton instance -$.timepicker.version = "1.0.0"; +$.timepicker.version = "1.0.1"; })(jQuery); |