jquery-timepicker-addon-rails 1.2.3 → 1.4.1

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