PluginProbe ʕ •ᴥ•ʔ
Download Manager / 3.3.64
Download Manager v3.3.64
3.3.66 3.3.65 3.3.64 3.3.63 3.3.62 3.3.61 3.3.60 3.3.59 3.3.58 3.3.57 3.3.56 trunk 2.1.3 2.3.0 2.5.96 2.5.97 2.6.2 2.6.96 2.8.3 2.9.99 3.0.4 3.1.05 3.1.07 3.1.08 3.1.11 3.1.12 3.1.14 3.1.17 3.1.18 3.1.22 3.1.23 3.1.24 3.1.25 3.1.26 3.1.27 3.1.28 3.2.04 3.2.13 3.2.14 3.2.16 3.2.18 3.2.19 3.2.21 3.2.22 3.2.23 3.2.24 3.2.25 3.2.27 3.2.28 3.2.29 3.2.30 3.2.31 3.2.32 3.2.33 3.2.34 3.2.35 3.2.37 3.2.38 3.2.39 3.2.40 3.2.41 3.2.42 3.2.43 3.2.44 3.2.45 3.2.46 3.2.47 3.2.48 3.2.49 3.2.50 3.2.51 3.2.52 3.2.53 3.2.54 3.2.55 3.2.56 3.2.57 3.2.58 3.2.59 3.2.60 3.2.61 3.2.63 3.2.64 3.2.65 3.2.66 3.2.67 3.2.68 3.2.69 3.2.70 3.2.71 3.2.72 3.2.73 3.2.74 3.2.75 3.2.76 3.2.77 3.2.78 3.2.79 3.2.80 3.2.81 3.2.82 3.2.83 3.2.84 3.2.85 3.2.86 3.2.87 3.2.88 3.2.89 3.2.90 3.2.91 3.2.92 3.2.93 3.2.94 3.2.95 3.2.96 3.2.97 3.2.98 3.2.99 3.3.00 3.3.01 3.3.02 3.3.03 3.3.04 3.3.05 3.3.06 3.3.07 3.3.08 3.3.09 3.3.10 3.3.11 3.3.12 3.3.13 3.3.14 3.3.15 3.3.16 3.3.17 3.3.18 3.3.19 3.3.20 3.3.21 3.3.22 3.3.23 3.3.24 3.3.25 3.3.26 3.3.27 3.3.28 3.3.29 3.3.30 3.3.31 3.3.32 3.3.33 3.3.34 3.3.35 3.3.36 3.3.37 3.3.38 3.3.39 3.3.40 3.3.41 3.3.42 3.3.43 3.3.44 3.3.45 3.3.46 3.3.47 3.3.48 3.3.49 3.3.50 3.3.51 3.3.52 3.3.53 3.3.54 3.3.55
download-manager / assets / js / jquery-ui-timepicker-addon.js
download-manager / assets / js Last commit date
ads 8 months ago control 8 months ago img 10 years ago blocker.js 2 weeks ago blocker.min.js 2 weeks ago embed.js 5 years ago embed.min.js 7 months ago front.js 1 week ago front.min.js 1 week ago jquery-ui-timepicker-addon.js 10 years ago jquery-ui-timepicker-addon.min.js 7 months ago jquery.dataTables.min.js 1 year ago jquery.validate.js 7 months ago jquery.validate.min.js 2 weeks ago jqueryFileTree.js 5 years ago jqueryFileTree.min.js 7 months ago overwatch.js 7 months ago overwatch.min.js 7 months ago password-strength.js 2 years ago password-strength.min.js 7 months ago simple-scrollbar.js 7 months ago simple-scrollbar.min.js 7 months ago simplebar.js 6 years ago validator.min.js 9 years ago vue.js 9 months ago vue.min.js 9 months ago wpdm-admin.js 2 weeks ago wpdm-admin.min.js 2 weeks ago wpdm.js 6 months ago wpdm.min.js 6 months ago
jquery-ui-timepicker-addon.js
2146 lines
1 /*! jQuery Timepicker Addon - v1.4.3 - 2013-11-30
2 * http://trentrichardson.com/examples/timepicker
3 * Copyright (c) 2013 Trent Richardson; Licensed MIT */
4 (function ($) {
5
6 /*
7 * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
8 */
9 $.ui.timepicker = $.ui.timepicker || {};
10 if ($.ui.timepicker.version) {
11 return;
12 }
13
14 /*
15 * Extend jQueryUI, get it started with our version number
16 */
17 $.extend($.ui, {
18 timepicker: {
19 version: "1.4.3"
20 }
21 });
22
23 /*
24 * Timepicker manager.
25 * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
26 * Settings for (groups of) time pickers are maintained in an instance object,
27 * allowing multiple different settings on the same page.
28 */
29 var Timepicker = function () {
30 this.regional = []; // Available regional settings, indexed by language code
31 this.regional[''] = { // Default regional settings
32 currentText: 'Now',
33 closeText: 'Done',
34 amNames: ['AM', 'A'],
35 pmNames: ['PM', 'P'],
36 timeFormat: 'HH:mm',
37 timeSuffix: '',
38 timeOnlyTitle: 'Choose Time',
39 timeText: 'Time',
40 hourText: 'Hour',
41 minuteText: 'Minute',
42 secondText: 'Second',
43 millisecText: 'Millisecond',
44 microsecText: 'Microsecond',
45 timezoneText: 'Time Zone',
46 isRTL: false
47 };
48 this._defaults = { // Global defaults for all the datetime picker instances
49 showButtonPanel: true,
50 timeOnly: false,
51 showHour: null,
52 showMinute: null,
53 showSecond: null,
54 showMillisec: null,
55 showMicrosec: null,
56 showTimezone: null,
57 showTime: true,
58 stepHour: 1,
59 stepMinute: 1,
60 stepSecond: 1,
61 stepMillisec: 1,
62 stepMicrosec: 1,
63 hour: 0,
64 minute: 0,
65 second: 0,
66 millisec: 0,
67 microsec: 0,
68 timezone: null,
69 hourMin: 0,
70 minuteMin: 0,
71 secondMin: 0,
72 millisecMin: 0,
73 microsecMin: 0,
74 hourMax: 23,
75 minuteMax: 59,
76 secondMax: 59,
77 millisecMax: 999,
78 microsecMax: 999,
79 minDateTime: null,
80 maxDateTime: null,
81 onSelect: null,
82 hourGrid: 0,
83 minuteGrid: 0,
84 secondGrid: 0,
85 millisecGrid: 0,
86 microsecGrid: 0,
87 alwaysSetTime: true,
88 separator: ' ',
89 altFieldTimeOnly: true,
90 altTimeFormat: null,
91 altSeparator: null,
92 altTimeSuffix: null,
93 pickerTimeFormat: null,
94 pickerTimeSuffix: null,
95 showTimepicker: true,
96 timezoneList: null,
97 addSliderAccess: false,
98 sliderAccessArgs: null,
99 controlType: 'slider',
100 defaultValue: null,
101 parse: 'strict'
102 };
103 $.extend(this._defaults, this.regional['']);
104 };
105
106 $.extend(Timepicker.prototype, {
107 $input: null,
108 $altInput: null,
109 $timeObj: null,
110 inst: null,
111 hour_slider: null,
112 minute_slider: null,
113 second_slider: null,
114 millisec_slider: null,
115 microsec_slider: null,
116 timezone_select: null,
117 hour: 0,
118 minute: 0,
119 second: 0,
120 millisec: 0,
121 microsec: 0,
122 timezone: null,
123 hourMinOriginal: null,
124 minuteMinOriginal: null,
125 secondMinOriginal: null,
126 millisecMinOriginal: null,
127 microsecMinOriginal: null,
128 hourMaxOriginal: null,
129 minuteMaxOriginal: null,
130 secondMaxOriginal: null,
131 millisecMaxOriginal: null,
132 microsecMaxOriginal: null,
133 ampm: '',
134 formattedDate: '',
135 formattedTime: '',
136 formattedDateTime: '',
137 timezoneList: null,
138 units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
139 support: {},
140 control: null,
141
142 /*
143 * Override the default settings for all instances of the time picker.
144 * @param {Object} settings object - the new settings to use as defaults (anonymous object)
145 * @return {Object} the manager object
146 */
147 setDefaults: function (settings) {
148 extendRemove(this._defaults, settings || {});
149 return this;
150 },
151
152 /*
153 * Create a new Timepicker instance
154 */
155 _newInst: function ($input, opts) {
156 var tp_inst = new Timepicker(),
157 inlineSettings = {},
158 fns = {},
159 overrides, i;
160
161 for (var attrName in this._defaults) {
162 if (this._defaults.hasOwnProperty(attrName)) {
163 var attrValue = $input.attr('time:' + attrName);
164 if (attrValue) {
165 try {
166 inlineSettings[attrName] = eval(attrValue);
167 } catch (err) {
168 inlineSettings[attrName] = attrValue;
169 }
170 }
171 }
172 }
173
174 overrides = {
175 beforeShow: function (input, dp_inst) {
176 if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
177 return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
178 }
179 },
180 onChangeMonthYear: function (year, month, dp_inst) {
181 // Update the time as well : this prevents the time from disappearing from the $input field.
182 tp_inst._updateDateTime(dp_inst);
183 if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
184 tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
185 }
186 },
187 onClose: function (dateText, dp_inst) {
188 if (tp_inst.timeDefined === true && $input.val() !== '') {
189 tp_inst._updateDateTime(dp_inst);
190 }
191 if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
192 tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
193 }
194 }
195 };
196 for (i in overrides) {
197 if (overrides.hasOwnProperty(i)) {
198 fns[i] = opts[i] || null;
199 }
200 }
201
202 tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
203 evnts: fns,
204 timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
205 });
206 tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
207 return val.toUpperCase();
208 });
209 tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
210 return val.toUpperCase();
211 });
212
213 // detect which units are supported
214 tp_inst.support = detectSupport(
215 tp_inst._defaults.timeFormat +
216 (tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
217 (tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
218
219 // controlType is string - key to our this._controls
220 if (typeof(tp_inst._defaults.controlType) === 'string') {
221 if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
222 tp_inst._defaults.controlType = 'select';
223 }
224 tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
225 }
226 // controlType is an object and must implement create, options, value methods
227 else {
228 tp_inst.control = tp_inst._defaults.controlType;
229 }
230
231 // prep the timezone options
232 var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
233 0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
234 if (tp_inst._defaults.timezoneList !== null) {
235 timezoneList = tp_inst._defaults.timezoneList;
236 }
237 var tzl = timezoneList.length, tzi = 0, tzv = null;
238 if (tzl > 0 && typeof timezoneList[0] !== 'object') {
239 for (; tzi < tzl; tzi++) {
240 tzv = timezoneList[tzi];
241 timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
242 }
243 }
244 tp_inst._defaults.timezoneList = timezoneList;
245
246 // set the default units
247 tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
248 ((new Date()).getTimezoneOffset() * -1);
249 tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
250 tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
251 tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
252 tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
253 tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
254 tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
255 tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
256 tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
257 tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
258 tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
259 tp_inst.ampm = '';
260 tp_inst.$input = $input;
261
262 if (tp_inst._defaults.altField) {
263 tp_inst.$altInput = $(tp_inst._defaults.altField).css({
264 cursor: 'pointer'
265 }).focus(function () {
266 $input.trigger("focus");
267 });
268 }
269
270 if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
271 tp_inst._defaults.minDate = new Date();
272 }
273 if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
274 tp_inst._defaults.maxDate = new Date();
275 }
276
277 // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
278 if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
279 tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
280 }
281 if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
282 tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
283 }
284 if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
285 tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
286 }
287 if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
288 tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
289 }
290 tp_inst.$input.bind('focus', function () {
291 tp_inst._onFocus();
292 });
293
294 return tp_inst;
295 },
296
297 /*
298 * add our sliders to the calendar
299 */
300 _addTimePicker: function (dp_inst) {
301 var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();
302
303 this.timeDefined = this._parseTime(currDT);
304 this._limitMinMaxDateTime(dp_inst, false);
305 this._injectTimePicker();
306 },
307
308 /*
309 * parse the time string from input value or _setTime
310 */
311 _parseTime: function (timeString, withDate) {
312 if (!this.inst) {
313 this.inst = $.datepicker._getInst(this.$input[0]);
314 }
315
316 if (withDate || !this._defaults.timeOnly) {
317 var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
318 try {
319 var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
320 if (!parseRes.timeObj) {
321 return false;
322 }
323 $.extend(this, parseRes.timeObj);
324 } catch (err) {
325 $.timepicker.log("Error parsing the date/time string: " + err +
326 "\ndate/time string = " + timeString +
327 "\ntimeFormat = " + this._defaults.timeFormat +
328 "\ndateFormat = " + dp_dateFormat);
329 return false;
330 }
331 return true;
332 } else {
333 var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
334 if (!timeObj) {
335 return false;
336 }
337 $.extend(this, timeObj);
338 return true;
339 }
340 },
341
342 /*
343 * generate and inject html for timepicker into ui datepicker
344 */
345 _injectTimePicker: function () {
346 var $dp = this.inst.dpDiv,
347 o = this.inst.settings,
348 tp_inst = this,
349 litem = '',
350 uitem = '',
351 show = null,
352 max = {},
353 gridSize = {},
354 size = null,
355 i = 0,
356 l = 0;
357
358 // Prevent displaying twice
359 if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
360 var noDisplay = ' style="display:none;"',
361 html = '<div class="ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
362 '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>';
363
364 // Create the markup
365 for (i = 0, l = this.units.length; i < l; i++) {
366 litem = this.units[i];
367 uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
368 show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
369
370 // Added by Peter Medeiros:
371 // - Figure out what the hour/minute/second max should be based on the step values.
372 // - Example: if stepMinute is 15, then minMax is 45.
373 max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
374 gridSize[litem] = 0;
375
376 html += '<dt class="ui_tpicker_' + litem + '_label"' + (show ? '' : noDisplay) + '>' + o[litem + 'Text'] + '</dt>' +
377 '<dd class="ui_tpicker_' + litem + '"><div class="ui_tpicker_' + litem + '_slider"' + (show ? '' : noDisplay) + '></div>';
378
379 if (show && o[litem + 'Grid'] > 0) {
380 html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
381
382 if (litem === 'hour') {
383 for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
384 gridSize[litem]++;
385 var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
386 html += '<td data-for="' + litem + '">' + tmph + '</td>';
387 }
388 }
389 else {
390 for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
391 gridSize[litem]++;
392 html += '<td data-for="' + litem + '">' + ((m < 10) ? '0' : '') + m + '</td>';
393 }
394 }
395
396 html += '</tr></table></div>';
397 }
398 html += '</dd>';
399 }
400
401 // Timezone
402 var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;
403 html += '<dt class="ui_tpicker_timezone_label"' + (showTz ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
404 html += '<dd class="ui_tpicker_timezone" ' + (showTz ? '' : noDisplay) + '></dd>';
405
406 // Create the elements from string
407 html += '</dl></div>';
408 var $tp = $(html);
409
410 // if we only want time picker...
411 if (o.timeOnly === true) {
412 $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
413 $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
414 }
415
416 // add sliders, adjust grids, add events
417 for (i = 0, l = tp_inst.units.length; i < l; i++) {
418 litem = tp_inst.units[i];
419 uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
420 show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
421
422 // add the slider
423 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]);
424
425 // adjust the grid and add click event
426 if (show && o[litem + 'Grid'] > 0) {
427 size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);
428 $tp.find('.ui_tpicker_' + litem + ' table').css({
429 width: size + "%",
430 marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + "%"),
431 marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + "%") : '0',
432 borderCollapse: 'collapse'
433 }).find("td").click(function (e) {
434 var $t = $(this),
435 h = $t.html(),
436 n = parseInt(h.replace(/[^0-9]/g), 10),
437 ap = h.replace(/[^apm]/ig),
438 f = $t.data('for'); // loses scope, so we use data-for
439
440 if (f === 'hour') {
441 if (ap.indexOf('p') !== -1 && n < 12) {
442 n += 12;
443 }
444 else {
445 if (ap.indexOf('a') !== -1 && n === 12) {
446 n = 0;
447 }
448 }
449 }
450
451 tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);
452
453 tp_inst._onTimeChange();
454 tp_inst._onSelectHandler();
455 }).css({
456 cursor: 'pointer',
457 width: (100 / gridSize[litem]) + '%',
458 textAlign: 'center',
459 overflow: 'hidden'
460 });
461 } // end if grid > 0
462 } // end for loop
463
464 // Add timezone options
465 this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
466 $.fn.append.apply(this.timezone_select,
467 $.map(o.timezoneList, function (val, idx) {
468 return $("<option />").val(typeof val === "object" ? val.value : val).text(typeof val === "object" ? val.label : val);
469 }));
470 if (typeof(this.timezone) !== "undefined" && this.timezone !== null && this.timezone !== "") {
471 var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;
472 if (local_timezone === this.timezone) {
473 selectLocalTimezone(tp_inst);
474 } else {
475 this.timezone_select.val(this.timezone);
476 }
477 } else {
478 if (typeof(this.hour) !== "undefined" && this.hour !== null && this.hour !== "") {
479 this.timezone_select.val(o.timezone);
480 } else {
481 selectLocalTimezone(tp_inst);
482 }
483 }
484 this.timezone_select.change(function () {
485 tp_inst._onTimeChange();
486 tp_inst._onSelectHandler();
487 });
488 // End timezone options
489
490 // inject timepicker into datepicker
491 var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
492 if ($buttonPanel.length) {
493 $buttonPanel.before($tp);
494 } else {
495 $dp.append($tp);
496 }
497
498 this.$timeObj = $tp.find('.ui_tpicker_time');
499
500 if (this.inst !== null) {
501 var timeDefined = this.timeDefined;
502 this._onTimeChange();
503 this.timeDefined = timeDefined;
504 }
505
506 // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
507 if (this._defaults.addSliderAccess) {
508 var sliderAccessArgs = this._defaults.sliderAccessArgs,
509 rtl = this._defaults.isRTL;
510 sliderAccessArgs.isRTL = rtl;
511
512 setTimeout(function () { // fix for inline mode
513 if ($tp.find('.ui-slider-access').length === 0) {
514 $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
515
516 // fix any grids since sliders are shorter
517 var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
518 if (sliderAccessWidth) {
519 $tp.find('table:visible').each(function () {
520 var $g = $(this),
521 oldWidth = $g.outerWidth(),
522 oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),
523 newWidth = oldWidth - sliderAccessWidth,
524 newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
525 css = { width: newWidth, marginRight: 0, marginLeft: 0 };
526 css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;
527 $g.css(css);
528 });
529 }
530 }
531 }, 10);
532 }
533 // end slideAccess integration
534
535 tp_inst._limitMinMaxDateTime(this.inst, true);
536 }
537 },
538
539 /*
540 * This function tries to limit the ability to go outside the
541 * min/max date range
542 */
543 _limitMinMaxDateTime: function (dp_inst, adjustSliders) {
544 var o = this._defaults,
545 dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
546
547 if (!this._defaults.showTimepicker) {
548 return;
549 } // No time so nothing to check here
550
551 if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
552 var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
553 minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
554
555 if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {
556 this.hourMinOriginal = o.hourMin;
557 this.minuteMinOriginal = o.minuteMin;
558 this.secondMinOriginal = o.secondMin;
559 this.millisecMinOriginal = o.millisecMin;
560 this.microsecMinOriginal = o.microsecMin;
561 }
562
563 if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {
564 this._defaults.hourMin = minDateTime.getHours();
565 if (this.hour <= this._defaults.hourMin) {
566 this.hour = this._defaults.hourMin;
567 this._defaults.minuteMin = minDateTime.getMinutes();
568 if (this.minute <= this._defaults.minuteMin) {
569 this.minute = this._defaults.minuteMin;
570 this._defaults.secondMin = minDateTime.getSeconds();
571 if (this.second <= this._defaults.secondMin) {
572 this.second = this._defaults.secondMin;
573 this._defaults.millisecMin = minDateTime.getMilliseconds();
574 if (this.millisec <= this._defaults.millisecMin) {
575 this.millisec = this._defaults.millisecMin;
576 this._defaults.microsecMin = minDateTime.getMicroseconds();
577 } else {
578 if (this.microsec < this._defaults.microsecMin) {
579 this.microsec = this._defaults.microsecMin;
580 }
581 this._defaults.microsecMin = this.microsecMinOriginal;
582 }
583 } else {
584 this._defaults.millisecMin = this.millisecMinOriginal;
585 this._defaults.microsecMin = this.microsecMinOriginal;
586 }
587 } else {
588 this._defaults.secondMin = this.secondMinOriginal;
589 this._defaults.millisecMin = this.millisecMinOriginal;
590 this._defaults.microsecMin = this.microsecMinOriginal;
591 }
592 } else {
593 this._defaults.minuteMin = this.minuteMinOriginal;
594 this._defaults.secondMin = this.secondMinOriginal;
595 this._defaults.millisecMin = this.millisecMinOriginal;
596 this._defaults.microsecMin = this.microsecMinOriginal;
597 }
598 } else {
599 this._defaults.hourMin = this.hourMinOriginal;
600 this._defaults.minuteMin = this.minuteMinOriginal;
601 this._defaults.secondMin = this.secondMinOriginal;
602 this._defaults.millisecMin = this.millisecMinOriginal;
603 this._defaults.microsecMin = this.microsecMinOriginal;
604 }
605 }
606
607 if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
608 var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
609 maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
610
611 if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {
612 this.hourMaxOriginal = o.hourMax;
613 this.minuteMaxOriginal = o.minuteMax;
614 this.secondMaxOriginal = o.secondMax;
615 this.millisecMaxOriginal = o.millisecMax;
616 this.microsecMaxOriginal = o.microsecMax;
617 }
618
619 if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {
620 this._defaults.hourMax = maxDateTime.getHours();
621 if (this.hour >= this._defaults.hourMax) {
622 this.hour = this._defaults.hourMax;
623 this._defaults.minuteMax = maxDateTime.getMinutes();
624 if (this.minute >= this._defaults.minuteMax) {
625 this.minute = this._defaults.minuteMax;
626 this._defaults.secondMax = maxDateTime.getSeconds();
627 if (this.second >= this._defaults.secondMax) {
628 this.second = this._defaults.secondMax;
629 this._defaults.millisecMax = maxDateTime.getMilliseconds();
630 if (this.millisec >= this._defaults.millisecMax) {
631 this.millisec = this._defaults.millisecMax;
632 this._defaults.microsecMax = maxDateTime.getMicroseconds();
633 } else {
634 if (this.microsec > this._defaults.microsecMax) {
635 this.microsec = this._defaults.microsecMax;
636 }
637 this._defaults.microsecMax = this.microsecMaxOriginal;
638 }
639 } else {
640 this._defaults.millisecMax = this.millisecMaxOriginal;
641 this._defaults.microsecMax = this.microsecMaxOriginal;
642 }
643 } else {
644 this._defaults.secondMax = this.secondMaxOriginal;
645 this._defaults.millisecMax = this.millisecMaxOriginal;
646 this._defaults.microsecMax = this.microsecMaxOriginal;
647 }
648 } else {
649 this._defaults.minuteMax = this.minuteMaxOriginal;
650 this._defaults.secondMax = this.secondMaxOriginal;
651 this._defaults.millisecMax = this.millisecMaxOriginal;
652 this._defaults.microsecMax = this.microsecMaxOriginal;
653 }
654 } else {
655 this._defaults.hourMax = this.hourMaxOriginal;
656 this._defaults.minuteMax = this.minuteMaxOriginal;
657 this._defaults.secondMax = this.secondMaxOriginal;
658 this._defaults.millisecMax = this.millisecMaxOriginal;
659 this._defaults.microsecMax = this.microsecMaxOriginal;
660 }
661 }
662
663 if (adjustSliders !== undefined && adjustSliders === true) {
664 var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
665 minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
666 secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
667 millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),
668 microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);
669
670 if (this.hour_slider) {
671 this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax });
672 this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
673 }
674 if (this.minute_slider) {
675 this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax });
676 this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
677 }
678 if (this.second_slider) {
679 this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax });
680 this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
681 }
682 if (this.millisec_slider) {
683 this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax });
684 this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
685 }
686 if (this.microsec_slider) {
687 this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax });
688 this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));
689 }
690 }
691
692 },
693
694 /*
695 * when a slider moves, set the internal time...
696 * on time change is also called when the time is updated in the text field
697 */
698 _onTimeChange: function () {
699 if (!this._defaults.showTimepicker) {
700 return;
701 }
702 var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
703 minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
704 second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
705 millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
706 microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,
707 timezone = (this.timezone_select) ? this.timezone_select.val() : false,
708 o = this._defaults,
709 pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
710 pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
711
712 if (typeof(hour) === 'object') {
713 hour = false;
714 }
715 if (typeof(minute) === 'object') {
716 minute = false;
717 }
718 if (typeof(second) === 'object') {
719 second = false;
720 }
721 if (typeof(millisec) === 'object') {
722 millisec = false;
723 }
724 if (typeof(microsec) === 'object') {
725 microsec = false;
726 }
727 if (typeof(timezone) === 'object') {
728 timezone = false;
729 }
730
731 if (hour !== false) {
732 hour = parseInt(hour, 10);
733 }
734 if (minute !== false) {
735 minute = parseInt(minute, 10);
736 }
737 if (second !== false) {
738 second = parseInt(second, 10);
739 }
740 if (millisec !== false) {
741 millisec = parseInt(millisec, 10);
742 }
743 if (microsec !== false) {
744 microsec = parseInt(microsec, 10);
745 }
746 if (timezone !== false) {
747 timezone = timezone.toString();
748 }
749
750 var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
751
752 // If the update was done in the input field, the input field should not be updated.
753 // If the update was done using the sliders, update the input field.
754 var hasChanged = (
755 hour !== parseInt(this.hour,10) || // sliders should all be numeric
756 minute !== parseInt(this.minute,10) ||
757 second !== parseInt(this.second,10) ||
758 millisec !== parseInt(this.millisec,10) ||
759 microsec !== parseInt(this.microsec,10) ||
760 (this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||
761 (this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or "EST" format, so use toString()
762 );
763
764 if (hasChanged) {
765
766 if (hour !== false) {
767 this.hour = hour;
768 }
769 if (minute !== false) {
770 this.minute = minute;
771 }
772 if (second !== false) {
773 this.second = second;
774 }
775 if (millisec !== false) {
776 this.millisec = millisec;
777 }
778 if (microsec !== false) {
779 this.microsec = microsec;
780 }
781 if (timezone !== false) {
782 this.timezone = timezone;
783 }
784
785 if (!this.inst) {
786 this.inst = $.datepicker._getInst(this.$input[0]);
787 }
788
789 this._limitMinMaxDateTime(this.inst, true);
790 }
791 if (this.support.ampm) {
792 this.ampm = ampm;
793 }
794
795 // Updates the time within the timepicker
796 this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
797 if (this.$timeObj) {
798 if (pickerTimeFormat === o.timeFormat) {
799 this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
800 }
801 else {
802 this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
803 }
804 }
805
806 this.timeDefined = true;
807 if (hasChanged) {
808 this._updateDateTime();
809 this.$input.focus();
810 }
811 },
812
813 /*
814 * call custom onSelect.
815 * bind to sliders slidestop, and grid click.
816 */
817 _onSelectHandler: function () {
818 var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
819 var inputEl = this.$input ? this.$input[0] : null;
820 if (onSelect && inputEl) {
821 onSelect.apply(inputEl, [this.formattedDateTime, this]);
822 }
823 },
824
825 /*
826 * update our input with the new date time..
827 */
828 _updateDateTime: function (dp_inst) {
829 dp_inst = this.inst || dp_inst;
830 var dtTmp = (dp_inst.currentYear > 0?
831 new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :
832 new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
833 dt = $.datepicker._daylightSavingAdjust(dtTmp),
834 //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
835 //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
836 dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
837 formatCfg = $.datepicker._getFormatConfig(dp_inst),
838 timeAvailable = dt !== null && this.timeDefined;
839 this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
840 var formattedDateTime = this.formattedDate;
841
842 // if a slider was changed but datepicker doesn't have a value yet, set it
843 if (dp_inst.lastVal === "") {
844 dp_inst.currentYear = dp_inst.selectedYear;
845 dp_inst.currentMonth = dp_inst.selectedMonth;
846 dp_inst.currentDay = dp_inst.selectedDay;
847 }
848
849 /*
850 * remove following lines to force every changes in date picker to change the input value
851 * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
852 * If the user manually empty the value in the input field, the date picker will never change selected value.
853 */
854 //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
855 // return;
856 //}
857
858 if (this._defaults.timeOnly === true) {
859 formattedDateTime = this.formattedTime;
860 } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
861 formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
862 }
863
864 this.formattedDateTime = formattedDateTime;
865
866 if (!this._defaults.showTimepicker) {
867 this.$input.val(this.formattedDate);
868 } else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {
869 this.$altInput.val(this.formattedTime);
870 this.$input.val(this.formattedDate);
871 } else if (this.$altInput) {
872 this.$input.val(formattedDateTime);
873 var altFormattedDateTime = '',
874 altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator,
875 altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
876
877 if (!this._defaults.timeOnly) {
878 if (this._defaults.altFormat) {
879 altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
880 }
881 else {
882 altFormattedDateTime = this.formattedDate;
883 }
884
885 if (altFormattedDateTime) {
886 altFormattedDateTime += altSeparator;
887 }
888 }
889
890 if (this._defaults.altTimeFormat) {
891 altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
892 }
893 else {
894 altFormattedDateTime += this.formattedTime + altTimeSuffix;
895 }
896 this.$altInput.val(altFormattedDateTime);
897 } else {
898 this.$input.val(formattedDateTime);
899 }
900
901 this.$input.trigger("change");
902 },
903
904 _onFocus: function () {
905 if (!this.$input.val() && this._defaults.defaultValue) {
906 this.$input.val(this._defaults.defaultValue);
907 var inst = $.datepicker._getInst(this.$input.get(0)),
908 tp_inst = $.datepicker._get(inst, 'timepicker');
909 if (tp_inst) {
910 if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
911 try {
912 $.datepicker._updateDatepicker(inst);
913 } catch (err) {
914 $.timepicker.log(err);
915 }
916 }
917 }
918 }
919 },
920
921 /*
922 * Small abstraction to control types
923 * We can add more, just be sure to follow the pattern: create, options, value
924 */
925 _controls: {
926 // slider methods
927 slider: {
928 create: function (tp_inst, obj, unit, val, min, max, step) {
929 var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
930 return obj.prop('slide', null).slider({
931 orientation: "horizontal",
932 value: rtl ? val * -1 : val,
933 min: rtl ? max * -1 : min,
934 max: rtl ? min * -1 : max,
935 step: step,
936 slide: function (event, ui) {
937 tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);
938 tp_inst._onTimeChange();
939 },
940 stop: function (event, ui) {
941 tp_inst._onSelectHandler();
942 }
943 });
944 },
945 options: function (tp_inst, obj, unit, opts, val) {
946 if (tp_inst._defaults.isRTL) {
947 if (typeof(opts) === 'string') {
948 if (opts === 'min' || opts === 'max') {
949 if (val !== undefined) {
950 return obj.slider(opts, val * -1);
951 }
952 return Math.abs(obj.slider(opts));
953 }
954 return obj.slider(opts);
955 }
956 var min = opts.min,
957 max = opts.max;
958 opts.min = opts.max = null;
959 if (min !== undefined) {
960 opts.max = min * -1;
961 }
962 if (max !== undefined) {
963 opts.min = max * -1;
964 }
965 return obj.slider(opts);
966 }
967 if (typeof(opts) === 'string' && val !== undefined) {
968 return obj.slider(opts, val);
969 }
970 return obj.slider(opts);
971 },
972 value: function (tp_inst, obj, unit, val) {
973 if (tp_inst._defaults.isRTL) {
974 if (val !== undefined) {
975 return obj.slider('value', val * -1);
976 }
977 return Math.abs(obj.slider('value'));
978 }
979 if (val !== undefined) {
980 return obj.slider('value', val);
981 }
982 return obj.slider('value');
983 }
984 },
985 // select methods
986 select: {
987 create: function (tp_inst, obj, unit, val, min, max, step) {
988 var sel = '<select class="ui-timepicker-select" data-unit="' + unit + '" data-min="' + min + '" data-max="' + max + '" data-step="' + step + '">',
989 format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;
990
991 for (var i = min; i <= max; i += step) {
992 sel += '<option value="' + i + '"' + (i === val ? ' selected' : '') + '>';
993 if (unit === 'hour') {
994 sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);
995 }
996 else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }
997 else {sel += '0' + i.toString(); }
998 sel += '</option>';
999 }
1000 sel += '</select>';
1001
1002 obj.children('select').remove();
1003
1004 $(sel).appendTo(obj).change(function (e) {
1005 tp_inst._onTimeChange();
1006 tp_inst._onSelectHandler();
1007 });
1008
1009 return obj;
1010 },
1011 options: function (tp_inst, obj, unit, opts, val) {
1012 var o = {},
1013 $t = obj.children('select');
1014 if (typeof(opts) === 'string') {
1015 if (val === undefined) {
1016 return $t.data(opts);
1017 }
1018 o[opts] = val;
1019 }
1020 else { o = opts; }
1021 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'));
1022 },
1023 value: function (tp_inst, obj, unit, val) {
1024 var $t = obj.children('select');
1025 if (val !== undefined) {
1026 return $t.val(val);
1027 }
1028 return $t.val();
1029 }
1030 }
1031 } // end _controls
1032
1033 });
1034
1035 $.fn.extend({
1036 /*
1037 * shorthand just to use timepicker.
1038 */
1039 timepicker: function (o) {
1040 o = o || {};
1041 var tmp_args = Array.prototype.slice.call(arguments);
1042
1043 if (typeof o === 'object') {
1044 tmp_args[0] = $.extend(o, {
1045 timeOnly: true
1046 });
1047 }
1048
1049 return $(this).each(function () {
1050 $.fn.datetimepicker.apply($(this), tmp_args);
1051 });
1052 },
1053
1054 /*
1055 * extend timepicker to datepicker
1056 */
1057 datetimepicker: function (o) {
1058 o = o || {};
1059 var tmp_args = arguments;
1060
1061 if (typeof(o) === 'string') {
1062 if (o === 'getDate') {
1063 return $.fn.datepicker.apply($(this[0]), tmp_args);
1064 } else {
1065 return this.each(function () {
1066 var $t = $(this);
1067 $t.datepicker.apply($t, tmp_args);
1068 });
1069 }
1070 } else {
1071 return this.each(function () {
1072 var $t = $(this);
1073 $t.datepicker($.timepicker._newInst($t, o)._defaults);
1074 });
1075 }
1076 }
1077 });
1078
1079 /*
1080 * Public Utility to parse date and time
1081 */
1082 $.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
1083 var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
1084 if (parseRes.timeObj) {
1085 var t = parseRes.timeObj;
1086 parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
1087 parseRes.date.setMicroseconds(t.microsec);
1088 }
1089
1090 return parseRes.date;
1091 };
1092
1093 /*
1094 * Public utility to parse time
1095 */
1096 $.datepicker.parseTime = function (timeFormat, timeString, options) {
1097 var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),
1098 iso8601 = (timeFormat.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
1099
1100 // Strict parse requires the timeString to match the timeFormat exactly
1101 var strictParse = function (f, s, o) {
1102
1103 // pattern for standard and localized AM/PM markers
1104 var getPatternAmpm = function (amNames, pmNames) {
1105 var markers = [];
1106 if (amNames) {
1107 $.merge(markers, amNames);
1108 }
1109 if (pmNames) {
1110 $.merge(markers, pmNames);
1111 }
1112 markers = $.map(markers, function (val) {
1113 return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
1114 });
1115 return '(' + markers.join('|') + ')?';
1116 };
1117
1118 // figure out position of time elements.. cause js cant do named captures
1119 var getFormatPositions = function (timeFormat) {
1120 var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
1121 orders = {
1122 h: -1,
1123 m: -1,
1124 s: -1,
1125 l: -1,
1126 c: -1,
1127 t: -1,
1128 z: -1
1129 };
1130
1131 if (finds) {
1132 for (var i = 0; i < finds.length; i++) {
1133 if (orders[finds[i].toString().charAt(0)] === -1) {
1134 orders[finds[i].toString().charAt(0)] = i + 1;
1135 }
1136 }
1137 }
1138 return orders;
1139 };
1140
1141 var regstr = '^' + f.toString()
1142 .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
1143 var ml = match.length;
1144 switch (match.charAt(0).toLowerCase()) {
1145 case 'h':
1146 return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1147 case 'm':
1148 return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1149 case 's':
1150 return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1151 case 'l':
1152 return '(\\d?\\d?\\d)';
1153 case 'c':
1154 return '(\\d?\\d?\\d)';
1155 case 'z':
1156 return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
1157 case 't':
1158 return getPatternAmpm(o.amNames, o.pmNames);
1159 default: // literal escaped in quotes
1160 return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
1161 }
1162 })
1163 .replace(/\s/g, '\\s?') +
1164 o.timeSuffix + '$',
1165 order = getFormatPositions(f),
1166 ampm = '',
1167 treg;
1168
1169 treg = s.match(new RegExp(regstr, 'i'));
1170
1171 var resTime = {
1172 hour: 0,
1173 minute: 0,
1174 second: 0,
1175 millisec: 0,
1176 microsec: 0
1177 };
1178
1179 if (treg) {
1180 if (order.t !== -1) {
1181 if (treg[order.t] === undefined || treg[order.t].length === 0) {
1182 ampm = '';
1183 resTime.ampm = '';
1184 } else {
1185 ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';
1186 resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];
1187 }
1188 }
1189
1190 if (order.h !== -1) {
1191 if (ampm === 'AM' && treg[order.h] === '12') {
1192 resTime.hour = 0; // 12am = 0 hour
1193 } else {
1194 if (ampm === 'PM' && treg[order.h] !== '12') {
1195 resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
1196 } else {
1197 resTime.hour = Number(treg[order.h]);
1198 }
1199 }
1200 }
1201
1202 if (order.m !== -1) {
1203 resTime.minute = Number(treg[order.m]);
1204 }
1205 if (order.s !== -1) {
1206 resTime.second = Number(treg[order.s]);
1207 }
1208 if (order.l !== -1) {
1209 resTime.millisec = Number(treg[order.l]);
1210 }
1211 if (order.c !== -1) {
1212 resTime.microsec = Number(treg[order.c]);
1213 }
1214 if (order.z !== -1 && treg[order.z] !== undefined) {
1215 resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);
1216 }
1217
1218
1219 return resTime;
1220 }
1221 return false;
1222 };// end strictParse
1223
1224 // First try JS Date, if that fails, use strictParse
1225 var looseParse = function (f, s, o) {
1226 try {
1227 var d = new Date('2012-01-01 ' + s);
1228 if (isNaN(d.getTime())) {
1229 d = new Date('2012-01-01T' + s);
1230 if (isNaN(d.getTime())) {
1231 d = new Date('01/01/2012 ' + s);
1232 if (isNaN(d.getTime())) {
1233 throw "Unable to parse time with native Date: " + s;
1234 }
1235 }
1236 }
1237
1238 return {
1239 hour: d.getHours(),
1240 minute: d.getMinutes(),
1241 second: d.getSeconds(),
1242 millisec: d.getMilliseconds(),
1243 microsec: d.getMicroseconds(),
1244 timezone: d.getTimezoneOffset() * -1
1245 };
1246 }
1247 catch (err) {
1248 try {
1249 return strictParse(f, s, o);
1250 }
1251 catch (err2) {
1252 $.timepicker.log("Unable to parse \ntimeString: " + s + "\ntimeFormat: " + f);
1253 }
1254 }
1255 return false;
1256 }; // end looseParse
1257
1258 if (typeof o.parse === "function") {
1259 return o.parse(timeFormat, timeString, o);
1260 }
1261 if (o.parse === 'loose') {
1262 return looseParse(timeFormat, timeString, o);
1263 }
1264 return strictParse(timeFormat, timeString, o);
1265 };
1266
1267 /**
1268 * Public utility to format the time
1269 * @param {string} format format of the time
1270 * @param {Object} time Object not a Date for timezones
1271 * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
1272 * @returns {string} the formatted time
1273 */
1274 $.datepicker.formatTime = function (format, time, options) {
1275 options = options || {};
1276 options = $.extend({}, $.timepicker._defaults, options);
1277 time = $.extend({
1278 hour: 0,
1279 minute: 0,
1280 second: 0,
1281 millisec: 0,
1282 microsec: 0,
1283 timezone: null
1284 }, time);
1285
1286 var tmptime = format,
1287 ampmName = options.amNames[0],
1288 hour = parseInt(time.hour, 10);
1289
1290 if (hour > 11) {
1291 ampmName = options.pmNames[0];
1292 }
1293
1294 tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
1295 switch (match) {
1296 case 'HH':
1297 return ('0' + hour).slice(-2);
1298 case 'H':
1299 return hour;
1300 case 'hh':
1301 return ('0' + convert24to12(hour)).slice(-2);
1302 case 'h':
1303 return convert24to12(hour);
1304 case 'mm':
1305 return ('0' + time.minute).slice(-2);
1306 case 'm':
1307 return time.minute;
1308 case 'ss':
1309 return ('0' + time.second).slice(-2);
1310 case 's':
1311 return time.second;
1312 case 'l':
1313 return ('00' + time.millisec).slice(-3);
1314 case 'c':
1315 return ('00' + time.microsec).slice(-3);
1316 case 'z':
1317 return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);
1318 case 'Z':
1319 return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);
1320 case 'T':
1321 return ampmName.charAt(0).toUpperCase();
1322 case 'TT':
1323 return ampmName.toUpperCase();
1324 case 't':
1325 return ampmName.charAt(0).toLowerCase();
1326 case 'tt':
1327 return ampmName.toLowerCase();
1328 default:
1329 return match.replace(/'/g, "");
1330 }
1331 });
1332
1333 return tmptime;
1334 };
1335
1336 /*
1337 * the bad hack :/ override datepicker so it doesn't close on select
1338 // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
1339 */
1340 $.datepicker._base_selectDate = $.datepicker._selectDate;
1341 $.datepicker._selectDate = function (id, dateStr) {
1342 var inst = this._getInst($(id)[0]),
1343 tp_inst = this._get(inst, 'timepicker');
1344
1345 if (tp_inst) {
1346 tp_inst._limitMinMaxDateTime(inst, true);
1347 inst.inline = inst.stay_open = true;
1348 //This way the onSelect handler called from calendarpicker get the full dateTime
1349 this._base_selectDate(id, dateStr);
1350 inst.inline = inst.stay_open = false;
1351 this._notifyChange(inst);
1352 this._updateDatepicker(inst);
1353 } else {
1354 this._base_selectDate(id, dateStr);
1355 }
1356 };
1357
1358 /*
1359 * second bad hack :/ override datepicker so it triggers an event when changing the input field
1360 * and does not redraw the datepicker on every selectDate event
1361 */
1362 $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
1363 $.datepicker._updateDatepicker = function (inst) {
1364
1365 // don't popup the datepicker if there is another instance already opened
1366 var input = inst.input[0];
1367 if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {
1368 return;
1369 }
1370
1371 if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
1372
1373 this._base_updateDatepicker(inst);
1374
1375 // Reload the time control when changing something in the input text field.
1376 var tp_inst = this._get(inst, 'timepicker');
1377 if (tp_inst) {
1378 tp_inst._addTimePicker(inst);
1379 }
1380 }
1381 };
1382
1383 /*
1384 * third bad hack :/ override datepicker so it allows spaces and colon in the input field
1385 */
1386 $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
1387 $.datepicker._doKeyPress = function (event) {
1388 var inst = $.datepicker._getInst(event.target),
1389 tp_inst = $.datepicker._get(inst, 'timepicker');
1390
1391 if (tp_inst) {
1392 if ($.datepicker._get(inst, 'constrainInput')) {
1393 var ampm = tp_inst.support.ampm,
1394 tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,
1395 dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
1396 datetimeChars = tp_inst._defaults.timeFormat.toString()
1397 .replace(/[hms]/g, '')
1398 .replace(/TT/g, ampm ? 'APM' : '')
1399 .replace(/Tt/g, ampm ? 'AaPpMm' : '')
1400 .replace(/tT/g, ampm ? 'AaPpMm' : '')
1401 .replace(/T/g, ampm ? 'AP' : '')
1402 .replace(/tt/g, ampm ? 'apm' : '')
1403 .replace(/t/g, ampm ? 'ap' : '') +
1404 " " + tp_inst._defaults.separator +
1405 tp_inst._defaults.timeSuffix +
1406 (tz ? tp_inst._defaults.timezoneList.join('') : '') +
1407 (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
1408 dateChars,
1409 chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
1410 return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
1411 }
1412 }
1413
1414 return $.datepicker._base_doKeyPress(event);
1415 };
1416
1417 /*
1418 * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
1419 * Update any alternate field to synchronise with the main field.
1420 */
1421 $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
1422 $.datepicker._updateAlternate = function (inst) {
1423 var tp_inst = this._get(inst, 'timepicker');
1424 if (tp_inst) {
1425 var altField = tp_inst._defaults.altField;
1426 if (altField) { // update alternate field too
1427 var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
1428 date = this._getDate(inst),
1429 formatCfg = $.datepicker._getFormatConfig(inst),
1430 altFormattedDateTime = '',
1431 altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
1432 altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
1433 altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
1434
1435 altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
1436 if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {
1437 if (tp_inst._defaults.altFormat) {
1438 altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
1439 }
1440 else {
1441 altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
1442 }
1443 }
1444 $(altField).val(altFormattedDateTime);
1445 }
1446 }
1447 else {
1448 $.datepicker._base_updateAlternate(inst);
1449 }
1450 };
1451
1452 /*
1453 * Override key up event to sync manual input changes.
1454 */
1455 $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
1456 $.datepicker._doKeyUp = function (event) {
1457 var inst = $.datepicker._getInst(event.target),
1458 tp_inst = $.datepicker._get(inst, 'timepicker');
1459
1460 if (tp_inst) {
1461 if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
1462 try {
1463 $.datepicker._updateDatepicker(inst);
1464 } catch (err) {
1465 $.timepicker.log(err);
1466 }
1467 }
1468 }
1469
1470 return $.datepicker._base_doKeyUp(event);
1471 };
1472
1473 /*
1474 * override "Today" button to also grab the time.
1475 */
1476 $.datepicker._base_gotoToday = $.datepicker._gotoToday;
1477 $.datepicker._gotoToday = function (id) {
1478 var inst = this._getInst($(id)[0]),
1479 $dp = inst.dpDiv;
1480 this._base_gotoToday(id);
1481 var tp_inst = this._get(inst, 'timepicker');
1482 selectLocalTimezone(tp_inst);
1483 var now = new Date();
1484 this._setTime(inst, now);
1485 $('.ui-datepicker-today', $dp).click();
1486 };
1487
1488 /*
1489 * Disable & enable the Time in the datetimepicker
1490 */
1491 $.datepicker._disableTimepickerDatepicker = function (target) {
1492 var inst = this._getInst(target);
1493 if (!inst) {
1494 return;
1495 }
1496
1497 var tp_inst = this._get(inst, 'timepicker');
1498 $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1499 if (tp_inst) {
1500 inst.settings.showTimepicker = false;
1501 tp_inst._defaults.showTimepicker = false;
1502 tp_inst._updateDateTime(inst);
1503 }
1504 };
1505
1506 $.datepicker._enableTimepickerDatepicker = function (target) {
1507 var inst = this._getInst(target);
1508 if (!inst) {
1509 return;
1510 }
1511
1512 var tp_inst = this._get(inst, 'timepicker');
1513 $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1514 if (tp_inst) {
1515 inst.settings.showTimepicker = true;
1516 tp_inst._defaults.showTimepicker = true;
1517 tp_inst._addTimePicker(inst); // Could be disabled on page load
1518 tp_inst._updateDateTime(inst);
1519 }
1520 };
1521
1522 /*
1523 * Create our own set time function
1524 */
1525 $.datepicker._setTime = function (inst, date) {
1526 var tp_inst = this._get(inst, 'timepicker');
1527 if (tp_inst) {
1528 var defaults = tp_inst._defaults;
1529
1530 // calling _setTime with no date sets time to defaults
1531 tp_inst.hour = date ? date.getHours() : defaults.hour;
1532 tp_inst.minute = date ? date.getMinutes() : defaults.minute;
1533 tp_inst.second = date ? date.getSeconds() : defaults.second;
1534 tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
1535 tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;
1536
1537 //check if within min/max times..
1538 tp_inst._limitMinMaxDateTime(inst, true);
1539
1540 tp_inst._onTimeChange();
1541 tp_inst._updateDateTime(inst);
1542 }
1543 };
1544
1545 /*
1546 * Create new public method to set only time, callable as $().datepicker('setTime', date)
1547 */
1548 $.datepicker._setTimeDatepicker = function (target, date, withDate) {
1549 var inst = this._getInst(target);
1550 if (!inst) {
1551 return;
1552 }
1553
1554 var tp_inst = this._get(inst, 'timepicker');
1555
1556 if (tp_inst) {
1557 this._setDateFromField(inst);
1558 var tp_date;
1559 if (date) {
1560 if (typeof date === "string") {
1561 tp_inst._parseTime(date, withDate);
1562 tp_date = new Date();
1563 tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1564 tp_date.setMicroseconds(tp_inst.microsec);
1565 } else {
1566 tp_date = new Date(date.getTime());
1567 tp_date.setMicroseconds(date.getMicroseconds());
1568 }
1569 if (tp_date.toString() === 'Invalid Date') {
1570 tp_date = undefined;
1571 }
1572 this._setTime(inst, tp_date);
1573 }
1574 }
1575
1576 };
1577
1578 /*
1579 * override setDate() to allow setting time too within Date object
1580 */
1581 $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
1582 $.datepicker._setDateDatepicker = function (target, date) {
1583 var inst = this._getInst(target);
1584 if (!inst) {
1585 return;
1586 }
1587
1588 if (typeof(date) === 'string') {
1589 date = new Date(date);
1590 if (!date.getTime()) {
1591 $.timepicker.log("Error creating Date object from string.");
1592 }
1593 }
1594
1595 var tp_inst = this._get(inst, 'timepicker');
1596 var tp_date;
1597 if (date instanceof Date) {
1598 tp_date = new Date(date.getTime());
1599 tp_date.setMicroseconds(date.getMicroseconds());
1600 } else {
1601 tp_date = date;
1602 }
1603
1604 // This is important if you are using the timezone option, javascript's Date
1605 // object will only return the timezone offset for the current locale, so we
1606 // adjust it accordingly. If not using timezone option this won't matter..
1607 // If a timezone is different in tp, keep the timezone as is
1608 if (tp_inst && tp_date) {
1609 // look out for DST if tz wasn't specified
1610 if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
1611 tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
1612 }
1613 date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
1614 tp_date = $.timepicker.timezoneAdjust(tp_date, tp_inst.timezone);
1615 }
1616
1617 this._updateDatepicker(inst);
1618 this._base_setDateDatepicker.apply(this, arguments);
1619 this._setTimeDatepicker(target, tp_date, true);
1620 };
1621
1622 /*
1623 * override getDate() to allow getting time too within Date object
1624 */
1625 $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
1626 $.datepicker._getDateDatepicker = function (target, noDefault) {
1627 var inst = this._getInst(target);
1628 if (!inst) {
1629 return;
1630 }
1631
1632 var tp_inst = this._get(inst, 'timepicker');
1633
1634 if (tp_inst) {
1635 // if it hasn't yet been defined, grab from field
1636 if (inst.lastVal === undefined) {
1637 this._setDateFromField(inst, noDefault);
1638 }
1639
1640 var date = this._getDate(inst);
1641 if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
1642 date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1643 date.setMicroseconds(tp_inst.microsec);
1644
1645 // This is important if you are using the timezone option, javascript's Date
1646 // object will only return the timezone offset for the current locale, so we
1647 // adjust it accordingly. If not using timezone option this won't matter..
1648 if (tp_inst.timezone != null) {
1649 // look out for DST if tz wasn't specified
1650 if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
1651 tp_inst.timezone = date.getTimezoneOffset() * -1;
1652 }
1653 date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
1654 }
1655 }
1656 return date;
1657 }
1658 return this._base_getDateDatepicker(target, noDefault);
1659 };
1660
1661 /*
1662 * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
1663 * An option in datapicker to ignore extra format characters would be nicer.
1664 */
1665 $.datepicker._base_parseDate = $.datepicker.parseDate;
1666 $.datepicker.parseDate = function (format, value, settings) {
1667 var date;
1668 try {
1669 date = this._base_parseDate(format, value, settings);
1670 } catch (err) {
1671 // Hack! The error message ends with a colon, a space, and
1672 // the "extra" characters. We rely on that instead of
1673 // attempting to perfectly reproduce the parsing algorithm.
1674 if (err.indexOf(":") >= 0) {
1675 date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);
1676 $.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
1677 } else {
1678 throw err;
1679 }
1680 }
1681 return date;
1682 };
1683
1684 /*
1685 * override formatDate to set date with time to the input
1686 */
1687 $.datepicker._base_formatDate = $.datepicker._formatDate;
1688 $.datepicker._formatDate = function (inst, day, month, year) {
1689 var tp_inst = this._get(inst, 'timepicker');
1690 if (tp_inst) {
1691 tp_inst._updateDateTime(inst);
1692 return tp_inst.$input.val();
1693 }
1694 return this._base_formatDate(inst);
1695 };
1696
1697 /*
1698 * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
1699 */
1700 $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
1701 $.datepicker._optionDatepicker = function (target, name, value) {
1702 var inst = this._getInst(target),
1703 name_clone;
1704 if (!inst) {
1705 return null;
1706 }
1707
1708 var tp_inst = this._get(inst, 'timepicker');
1709 if (tp_inst) {
1710 var min = null,
1711 max = null,
1712 onselect = null,
1713 overrides = tp_inst._defaults.evnts,
1714 fns = {},
1715 prop;
1716 if (typeof name === 'string') { // if min/max was set with the string
1717 if (name === 'minDate' || name === 'minDateTime') {
1718 min = value;
1719 } else if (name === 'maxDate' || name === 'maxDateTime') {
1720 max = value;
1721 } else if (name === 'onSelect') {
1722 onselect = value;
1723 } else if (overrides.hasOwnProperty(name)) {
1724 if (typeof (value) === 'undefined') {
1725 return overrides[name];
1726 }
1727 fns[name] = value;
1728 name_clone = {}; //empty results in exiting function after overrides updated
1729 }
1730 } else if (typeof name === 'object') { //if min/max was set with the JSON
1731 if (name.minDate) {
1732 min = name.minDate;
1733 } else if (name.minDateTime) {
1734 min = name.minDateTime;
1735 } else if (name.maxDate) {
1736 max = name.maxDate;
1737 } else if (name.maxDateTime) {
1738 max = name.maxDateTime;
1739 }
1740 for (prop in overrides) {
1741 if (overrides.hasOwnProperty(prop) && name[prop]) {
1742 fns[prop] = name[prop];
1743 }
1744 }
1745 }
1746 for (prop in fns) {
1747 if (fns.hasOwnProperty(prop)) {
1748 overrides[prop] = fns[prop];
1749 if (!name_clone) { name_clone = $.extend({}, name); }
1750 delete name_clone[prop];
1751 }
1752 }
1753 if (name_clone && isEmptyObject(name_clone)) { return; }
1754 if (min) { //if min was set
1755 if (min === 0) {
1756 min = new Date();
1757 } else {
1758 min = new Date(min);
1759 }
1760 tp_inst._defaults.minDate = min;
1761 tp_inst._defaults.minDateTime = min;
1762 } else if (max) { //if max was set
1763 if (max === 0) {
1764 max = new Date();
1765 } else {
1766 max = new Date(max);
1767 }
1768 tp_inst._defaults.maxDate = max;
1769 tp_inst._defaults.maxDateTime = max;
1770 } else if (onselect) {
1771 tp_inst._defaults.onSelect = onselect;
1772 }
1773 }
1774 if (value === undefined) {
1775 return this._base_optionDatepicker.call($.datepicker, target, name);
1776 }
1777 return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
1778 };
1779
1780 /*
1781 * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
1782 * it will return false for all objects
1783 */
1784 var isEmptyObject = function (obj) {
1785 var prop;
1786 for (prop in obj) {
1787 if (obj.hasOwnProperty(prop)) {
1788 return false;
1789 }
1790 }
1791 return true;
1792 };
1793
1794 /*
1795 * jQuery extend now ignores nulls!
1796 */
1797 var extendRemove = function (target, props) {
1798 $.extend(target, props);
1799 for (var name in props) {
1800 if (props[name] === null || props[name] === undefined) {
1801 target[name] = props[name];
1802 }
1803 }
1804 return target;
1805 };
1806
1807 /*
1808 * Determine by the time format which units are supported
1809 * Returns an object of booleans for each unit
1810 */
1811 var detectSupport = function (timeFormat) {
1812 var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals
1813 isIn = function (f, t) { // does the format contain the token?
1814 return f.indexOf(t) !== -1 ? true : false;
1815 };
1816 return {
1817 hour: isIn(tf, 'h'),
1818 minute: isIn(tf, 'm'),
1819 second: isIn(tf, 's'),
1820 millisec: isIn(tf, 'l'),
1821 microsec: isIn(tf, 'c'),
1822 timezone: isIn(tf, 'z'),
1823 ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),
1824 iso8601: isIn(timeFormat, 'Z')
1825 };
1826 };
1827
1828 /*
1829 * Converts 24 hour format into 12 hour
1830 * Returns 12 hour without leading 0
1831 */
1832 var convert24to12 = function (hour) {
1833 hour %= 12;
1834
1835 if (hour === 0) {
1836 hour = 12;
1837 }
1838
1839 return String(hour);
1840 };
1841
1842 var computeEffectiveSetting = function (settings, property) {
1843 return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];
1844 };
1845
1846 /*
1847 * Splits datetime string into date and time substrings.
1848 * Throws exception when date can't be parsed
1849 * Returns {dateString: dateString, timeString: timeString}
1850 */
1851 var splitDateTime = function (dateTimeString, timeSettings) {
1852 // The idea is to get the number separator occurrences in datetime and the time format requested (since time has
1853 // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
1854 var separator = computeEffectiveSetting(timeSettings, 'separator'),
1855 format = computeEffectiveSetting(timeSettings, 'timeFormat'),
1856 timeParts = format.split(separator), // how many occurrences of separator may be in our format?
1857 timePartsLen = timeParts.length,
1858 allParts = dateTimeString.split(separator),
1859 allPartsLen = allParts.length;
1860
1861 if (allPartsLen > 1) {
1862 return {
1863 dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),
1864 timeString: allParts.splice(0, timePartsLen).join(separator)
1865 };
1866 }
1867
1868 return {
1869 dateString: dateTimeString,
1870 timeString: ''
1871 };
1872 };
1873
1874 /*
1875 * Internal function to parse datetime interval
1876 * Returns: {date: Date, timeObj: Object}, where
1877 * date - parsed date without time (type Date)
1878 * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
1879 */
1880 var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
1881 var date,
1882 parts,
1883 parsedTime;
1884
1885 parts = splitDateTime(dateTimeString, timeSettings);
1886 date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);
1887
1888 if (parts.timeString === '') {
1889 return {
1890 date: date
1891 };
1892 }
1893
1894 parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);
1895
1896 if (!parsedTime) {
1897 throw 'Wrong time format';
1898 }
1899
1900 return {
1901 date: date,
1902 timeObj: parsedTime
1903 };
1904 };
1905
1906 /*
1907 * Internal function to set timezone_select to the local timezone
1908 */
1909 var selectLocalTimezone = function (tp_inst, date) {
1910 if (tp_inst && tp_inst.timezone_select) {
1911 var now = date || new Date();
1912 tp_inst.timezone_select.val(-now.getTimezoneOffset());
1913 }
1914 };
1915
1916 /*
1917 * Create a Singleton Instance
1918 */
1919 $.timepicker = new Timepicker();
1920
1921 /**
1922 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
1923 * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
1924 * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
1925 * @return {string}
1926 */
1927 $.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {
1928 if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {
1929 return tzMinutes;
1930 }
1931
1932 var off = tzMinutes,
1933 minutes = off % 60,
1934 hours = (off - minutes) / 60,
1935 iso = iso8601 ? ':' : '',
1936 tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);
1937
1938 if (tz === '+00:00') {
1939 return 'Z';
1940 }
1941 return tz;
1942 };
1943
1944 /**
1945 * Get the number in minutes that represents a timezone string
1946 * @param {string} tzString formatted like "+0500", "-1245", "Z"
1947 * @return {number} the offset minutes or the original string if it doesn't match expectations
1948 */
1949 $.timepicker.timezoneOffsetNumber = function (tzString) {
1950 var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
1951
1952 if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
1953 return 0;
1954 }
1955
1956 if (!/^(\-|\+)\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back
1957 return tzString;
1958 }
1959
1960 return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
1961 ((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)
1962 parseInt(normalized.substr(3, 2), 10))); // minutes
1963 };
1964
1965 /**
1966 * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
1967 * @param {Date} date
1968 * @param {string} toTimezone formatted like "+0500", "-1245"
1969 * @return {Date}
1970 */
1971 $.timepicker.timezoneAdjust = function (date, toTimezone) {
1972 var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);
1973 if (!isNaN(toTz)) {
1974 date.setMinutes(date.getMinutes() + -date.getTimezoneOffset() - toTz);
1975 }
1976 return date;
1977 };
1978
1979 /**
1980 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
1981 * enforce date range limits.
1982 * n.b. The input value must be correctly formatted (reformatting is not supported)
1983 * @param {Element} startTime
1984 * @param {Element} endTime
1985 * @param {Object} options Options for the timepicker() call
1986 * @return {jQuery}
1987 */
1988 $.timepicker.timeRange = function (startTime, endTime, options) {
1989 return $.timepicker.handleRange('timepicker', startTime, endTime, options);
1990 };
1991
1992 /**
1993 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
1994 * enforce date range limits.
1995 * @param {Element} startTime
1996 * @param {Element} endTime
1997 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
1998 * a boolean value that can be used to reformat the input values to the `dateFormat`.
1999 * @param {string} method Can be used to specify the type of picker to be added
2000 * @return {jQuery}
2001 */
2002 $.timepicker.datetimeRange = function (startTime, endTime, options) {
2003 $.timepicker.handleRange('datetimepicker', startTime, endTime, options);
2004 };
2005
2006 /**
2007 * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
2008 * enforce date range limits.
2009 * @param {Element} startTime
2010 * @param {Element} endTime
2011 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2012 * a boolean value that can be used to reformat the input values to the `dateFormat`.
2013 * @return {jQuery}
2014 */
2015 $.timepicker.dateRange = function (startTime, endTime, options) {
2016 $.timepicker.handleRange('datepicker', startTime, endTime, options);
2017 };
2018
2019 /**
2020 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
2021 * enforce date range limits.
2022 * @param {string} method Can be used to specify the type of picker to be added
2023 * @param {Element} startTime
2024 * @param {Element} endTime
2025 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2026 * a boolean value that can be used to reformat the input values to the `dateFormat`.
2027 * @return {jQuery}
2028 */
2029 $.timepicker.handleRange = function (method, startTime, endTime, options) {
2030 options = $.extend({}, {
2031 minInterval: 0, // min allowed interval in milliseconds
2032 maxInterval: 0, // max allowed interval in milliseconds
2033 start: {}, // options for start picker
2034 end: {} // options for end picker
2035 }, options);
2036
2037 function checkDates(changed, other) {
2038 var startdt = startTime[method]('getDate'),
2039 enddt = endTime[method]('getDate'),
2040 changeddt = changed[method]('getDate');
2041
2042 if (startdt !== null) {
2043 var minDate = new Date(startdt.getTime()),
2044 maxDate = new Date(startdt.getTime());
2045
2046 minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);
2047 maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);
2048
2049 if (options.minInterval > 0 && minDate > enddt) { // minInterval check
2050 endTime[method]('setDate', minDate);
2051 }
2052 else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check
2053 endTime[method]('setDate', maxDate);
2054 }
2055 else if (startdt > enddt) {
2056 other[method]('setDate', changeddt);
2057 }
2058 }
2059 }
2060
2061 function selected(changed, other, option) {
2062 if (!changed.val()) {
2063 return;
2064 }
2065 var date = changed[method].call(changed, 'getDate');
2066 if (date !== null && options.minInterval > 0) {
2067 if (option === 'minDate') {
2068 date.setMilliseconds(date.getMilliseconds() + options.minInterval);
2069 }
2070 if (option === 'maxDate') {
2071 date.setMilliseconds(date.getMilliseconds() - options.minInterval);
2072 }
2073 }
2074 if (date.getTime) {
2075 other[method].call(other, 'option', option, date);
2076 }
2077 }
2078
2079 $.fn[method].call(startTime, $.extend({
2080 onClose: function (dateText, inst) {
2081 checkDates($(this), endTime);
2082 },
2083 onSelect: function (selectedDateTime) {
2084 selected($(this), endTime, 'minDate');
2085 }
2086 }, options, options.start));
2087 $.fn[method].call(endTime, $.extend({
2088 onClose: function (dateText, inst) {
2089 checkDates($(this), startTime);
2090 },
2091 onSelect: function (selectedDateTime) {
2092 selected($(this), startTime, 'maxDate');
2093 }
2094 }, options, options.end));
2095
2096 checkDates(startTime, endTime);
2097 selected(startTime, endTime, 'minDate');
2098 selected(endTime, startTime, 'maxDate');
2099 return $([startTime.get(0), endTime.get(0)]);
2100 };
2101
2102 /**
2103 * Log error or data to the console during error or debugging
2104 * @param {Object} err pass any type object to log to the console during error or debugging
2105 * @return {void}
2106 */
2107 $.timepicker.log = function (err) {
2108 if (window.console) {
2109 window.console.log(err);
2110 }
2111 };
2112
2113 /*
2114 * Add util object to allow access to private methods for testability.
2115 */
2116 $.timepicker._util = {
2117 _extendRemove: extendRemove,
2118 _isEmptyObject: isEmptyObject,
2119 _convert24to12: convert24to12,
2120 _detectSupport: detectSupport,
2121 _selectLocalTimezone: selectLocalTimezone,
2122 _computeEffectiveSetting: computeEffectiveSetting,
2123 _splitDateTime: splitDateTime,
2124 _parseDateTimeInternal: parseDateTimeInternal
2125 };
2126
2127 /*
2128 * Microsecond support
2129 */
2130 if (!Date.prototype.getMicroseconds) {
2131 Date.prototype.microseconds = 0;
2132 Date.prototype.getMicroseconds = function () { return this.microseconds; };
2133 Date.prototype.setMicroseconds = function (m) {
2134 this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));
2135 this.microseconds = m % 1000;
2136 return this;
2137 };
2138 }
2139
2140 /*
2141 * Keep up with the version
2142 */
2143 $.timepicker.version = "1.4.3";
2144
2145 })(jQuery);
2146