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($) { 16 17 /* 18 * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded" 19 */ 20 $.ui.timepicker = $.ui.timepicker || {}; 21 if ($.ui.timepicker.version) { 22 return; 23 } 24 25 /* 26 * Extend jQueryUI, get it started with our version number 27 */ 28 $.extend($.ui, { 29 timepicker: { 30 version: "1.2" 31 } 32 }); 33 34 /* 35 * Timepicker manager. 36 * Use the singleton instance of this class, $.timepicker, to interact with the time picker. 37 * Settings for (groups of) time pickers are maintained in an instance object, 38 * allowing multiple different settings on the same page. 39 */ 40 var Timepicker = function() { 41 this.regional = []; // Available regional settings, indexed by language code 42 this.regional[''] = { // Default regional settings 43 currentText: 'Now', 44 closeText: 'Done', 45 amNames: ['AM', 'A'], 46 pmNames: ['PM', 'P'], 47 timeFormat: 'HH:mm', 48 timeSuffix: '', 49 timeOnlyTitle: 'Choose Time', 50 timeText: 'Time', 51 hourText: 'Hour', 52 minuteText: 'Minute', 53 secondText: 'Second', 54 millisecText: 'Millisecond', 55 timezoneText: 'Time Zone', 56 isRTL: false 57 }; 58 this._defaults = { // Global defaults for all the datetime picker instances 59 showButtonPanel: true, 60 timeOnly: false, 61 showHour: true, 62 showMinute: true, 63 showSecond: false, 64 showMillisec: false, 65 showTimezone: false, 66 showTime: true, 67 stepHour: 1, 68 stepMinute: 1, 69 stepSecond: 1, 70 stepMillisec: 1, 71 hour: 0, 72 minute: 0, 73 second: 0, 74 millisec: 0, 75 timezone: null, 76 useLocalTimezone: false, 77 defaultTimezone: "+0000", 78 hourMin: 0, 79 minuteMin: 0, 80 secondMin: 0, 81 millisecMin: 0, 82 hourMax: 23, 83 minuteMax: 59, 84 secondMax: 59, 85 millisecMax: 999, 86 minDateTime: null, 87 maxDateTime: null, 88 onSelect: null, 89 hourGrid: 0, 90 minuteGrid: 0, 91 secondGrid: 0, 92 millisecGrid: 0, 93 alwaysSetTime: true, 94 separator: ' ', 95 altFieldTimeOnly: true, 96 altTimeFormat: null, 97 altSeparator: null, 98 altTimeSuffix: null, 99 pickerTimeFormat: null, 100 pickerTimeSuffix: null, 101 showTimepicker: true, 102 timezoneIso8601: false, 103 timezoneList: null, 104 addSliderAccess: false, 105 sliderAccessArgs: null, 106 controlType: 'slider', 107 defaultValue: null, 108 parse: 'strict' 109 }; 110 $.extend(this._defaults, this.regional['']); 111 }; 112 113 $.extend(Timepicker.prototype, { 114 $input: null, 115 $altInput: null, 116 $timeObj: null, 117 inst: null, 118 hour_slider: null, 119 minute_slider: null, 120 second_slider: null, 121 millisec_slider: null, 122 timezone_select: null, 123 hour: 0, 124 minute: 0, 125 second: 0, 126 millisec: 0, 127 timezone: null, 128 defaultTimezone: "+0000", 129 hourMinOriginal: null, 130 minuteMinOriginal: null, 131 secondMinOriginal: null, 132 millisecMinOriginal: null, 133 hourMaxOriginal: null, 134 minuteMaxOriginal: null, 135 secondMaxOriginal: null, 136 millisecMaxOriginal: null, 137 ampm: '', 138 formattedDate: '', 139 formattedTime: '', 140 formattedDateTime: '', 141 timezoneList: null, 142 units: ['hour','minute','second','millisec'], 143 control: null, 144 145 /* 146 * 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 149 */ 150 setDefaults: function(settings) { 151 extendRemove(this._defaults, settings || {}); 152 return this; 153 }, 154 155 /* 156 * Create a new Timepicker instance 157 */ 158 _newInst: function($input, o) { 159 var tp_inst = new Timepicker(), 160 inlineSettings = {}, 161 fns = {}, 162 overrides, i; 163 164 for (var attrName in this._defaults) { 165 if(this._defaults.hasOwnProperty(attrName)){ 166 var attrValue = $input.attr('time:' + attrName); 167 if (attrValue) { 168 try { 169 inlineSettings[attrName] = eval(attrValue); 170 } catch (err) { 171 inlineSettings[attrName] = attrValue; 172 } 173 } 174 } 175 } 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) { 208 return val.toUpperCase(); 209 }); 210 tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { 211 return val.toUpperCase(); 212 }); 213 214 // controlType is string - key to our this._controls 215 if(typeof(tp_inst._defaults.controlType) === 'string'){
216 if($.fn[tp_inst._defaults.controlType] === undefined){ 217 tp_inst._defaults.controlType = 'select'; 218 } 219 tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType]; 220 } 221 // controlType is an object and must implement create, options, value methods 222 else{ 223 tp_inst.control = tp_inst._defaults.controlType; 224 } 225 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 }); 235 } 236 tp_inst._defaults.timezoneList = timezoneList; 237 } 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; 248 tp_inst.ampm = ''; 249 tp_inst.$input = $input; 250 251 if (o.altField) { 252 tp_inst.$altInput = $(o.altField).css({ 253 cursor: 'pointer' 254 }).focus(function() { 255 $input.trigger("focus"); 256 }); 257 } 258 259 if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) { 260 tp_inst._defaults.minDate = new Date(); 261 } 262 if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) { 263 tp_inst._defaults.maxDate = new Date(); 264 } 265 266 // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime.. 267 if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) { 268 tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime()); 269 } 270 if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) { 271 tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime()); 272 } 273 if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) { 274 tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime()); 275 } 276 if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) { 277 tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); 278 } 279 tp_inst.$input.bind('focus', function() { 280 tp_inst._onFocus(); 281 }); 282 283 return tp_inst; 284 }, 285 286 /* 287 * add our sliders to the calendar 288 */ 289 _addTimePicker: function(dp_inst) { 290 var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val(); 291 292 this.timeDefined = this._parseTime(currDT); 293 this._limitMinMaxDateTime(dp_inst, false); 294 this._injectTimePicker(); 295 }, 296 297 /* 298 * parse the time string from input value or _setTime 299 */ 300 _parseTime: function(timeString, withDate) { 301 if (!this.inst) { 302 this.inst = $.datepicker._getInst(this.$input[0]); 303 } 304 305 if (withDate || !this._defaults.timeOnly) { 306 var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); 307 try { 308 var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults); 309 if (!parseRes.timeObj) { 310 return false; 311 } 312 $.extend(this, parseRes.timeObj); 313 } catch (err) { 314 $.timepicker.log("Error parsing the date/time string: " + err +
315 "\ndate/time string = " + timeString + 316 "\ntimeFormat = " + this._defaults.timeFormat + 317 "\ndateFormat = " + dp_dateFormat); 318 return false; 319 } 320 return true; 321 } else { 322 var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults); 323 if (!timeObj) { 324 return false; 325 } 326 $.extend(this, timeObj); 327 return true; 328 } 329 }, 330 331 /* 332 * generate and inject html for timepicker into ui datepicker 333 */ 334 _injectTimePicker: function() { 335 var $dp = this.inst.dpDiv, 336 o = this.inst.settings, 337 tp_inst = this, 338 litem = '', 339 uitem = '', 340 max = {}, 341 gridSize = {}, 342 size = null; 343 344 // Prevent displaying twice 345 if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) { 346 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>' + 348 '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>'; 349 350 // Create the markup 351 for(var i=0,l=this.units.length; i<l; i++){ 352 litem = this.units[i]; 353 uitem = litem.substr(0,1).toUpperCase() + litem.substr(1); 354 // Added by Peter Medeiros: 355 // - Figure out what the hour/minute/second max should be based on the step values. 356 // - 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); 358 gridSize[litem] = 0; 359 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>'; 362 363 if (o['show'+uitem] && o[litem+'Grid'] > 0) { 364 html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>'; 365 366 if(litem == 'hour'){ 367 for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) { 368 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>'; 371 } 372 } 373 else{ 374 for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) { 375 gridSize[litem]++; 376 html += '<td data-for="'+litem+'">' + ((m < 10) ? '0' : '') + m + '</td>'; 377 } 378 } 379 380 html += '</tr></table></div>'; 381 } 382 html += '</dd>'; 383 } 384 385 // 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>'; 388 389 // Create the elements from string 390 html += '</dl></div>'; 391 var $tp = $(html); 392 393 // if we only want time picker... 394 if (o.timeOnly === true) { 395 $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>'); 396 $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide(); 397 } 398 399 // add sliders, adjust grids, add events 400 for(var i=0,l=tp_inst.units.length; i<l; i++){ 401 litem = tp_inst.units[i]; 402 uitem = litem.substr(0,1).toUpperCase() + litem.substr(1); 403 404 // 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]); 406 407 // 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({ 411 width: size + "%", 412 marginLeft: o.isRTL? '0' : ((size / (-2 * gridSize[litem])) + "%"), 413 marginRight: o.isRTL? ((size / (-2 * gridSize[litem])) + "%") : '0', 414 borderCollapse: 'collapse' 415 }).find("td").click(function(e){
416 var $t = $(this), 417 h = $t.html(), 418 n = parseInt(h.replace(/[^0-9]/g),10), 419 ap = h.replace(/[^apm]/ig), 420 f = $t.data('for'); // loses scope, so we use data-for 421 422 if(f == 'hour'){ 423 if(ap.indexOf('p') !== -1 && n < 12){ 424 n += 12; 425 } 426 else{ 427 if(ap.indexOf('a') !== -1 && n === 12){ 428 n = 0; 429 } 430 } 431 } 432 433 tp_inst.control.value(tp_inst, tp_inst[f+'_slider'], litem, n); 434 435 tp_inst._onTimeChange(); 436 tp_inst._onSelectHandler(); 437 }) 438 .css({ 439 cursor: 'pointer', 440 width: (100 / gridSize[litem]) + '%', 441 textAlign: 'center', 442 overflow: 'hidden' 443 }); 444 } // end if grid > 0 445 } // end for loop 446 447 // Add timezone options 448 this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select"); 449 $.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); 452 })); 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); 458 } else { 459 this.timezone_select.val(this.timezone); 460 } 461 } else { 462 if (typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") { 463 this.timezone_select.val(o.defaultTimezone); 464 } else { 465 selectLocalTimeZone(tp_inst); 466 } 467 } 468 this.timezone_select.change(function() {
469 tp_inst._defaults.useLocalTimezone = false; 470 tp_inst._onTimeChange(); 471 tp_inst._onSelectHandler(); 472 }); 473 // End timezone options 474 475 // inject timepicker into datepicker 476 var $buttonPanel = $dp.find('.ui-datepicker-buttonpane'); 477 if ($buttonPanel.length) { 478 $buttonPanel.before($tp); 479 } else { 480 $dp.append($tp); 481 } 482 483 this.$timeObj = $tp.find('.ui_tpicker_time'); 484 485 if (this.inst !== null) { 486 var timeDefined = this.timeDefined; 487 this._onTimeChange(); 488 this.timeDefined = timeDefined; 489 } 490 491 // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/ 492 if (this._defaults.addSliderAccess) { 493 var sliderAccessArgs = this._defaults.sliderAccessArgs, 494 rtl = this._defaults.isRTL; 495 sliderAccessArgs.isRTL = rtl; 496 497 setTimeout(function() { // fix for inline mode 498 if ($tp.find('.ui-slider-access').length === 0) { 499 $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs); 500 501 // fix any grids since sliders are shorter 502 var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true); 503 if (sliderAccessWidth) { 504 $tp.find('table:visible').each(function() { 505 var $g = $(this), 506 oldWidth = $g.outerWidth(), 507 oldMarginLeft = $g.css(rtl? 'marginRight':'marginLeft').toString().replace('%', ''), 508 newWidth = oldWidth - sliderAccessWidth, 509 newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%', 510 css = { width: newWidth, marginRight: 0, marginLeft: 0 }; 511 css[rtl? 'marginRight':'marginLeft'] = newMarginLeft; 512 $g.css(css); 513 });
514 } 515 } 516 }, 10); 517 } 518 // end slideAccess integration 519 520 } 521 }, 522 523 /* 524 * This function tries to limit the ability to go outside the 525 * min/max date range 526 */ 527 _limitMinMaxDateTime: function(dp_inst, adjustSliders) { 528 var o = this._defaults, 529 dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay); 530 531 if (!this._defaults.showTimepicker) { 532 return; 533 } // No time so nothing to check here 534 535 if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) { 536 var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'), 537 minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0); 538 539 if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null) { 540 this.hourMinOriginal = o.hourMin; 541 this.minuteMinOriginal = o.minuteMin; 542 this.secondMinOriginal = o.secondMin; 543 this.millisecMinOriginal = o.millisecMin; 544 } 545 546 if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) { 547 this._defaults.hourMin = minDateTime.getHours(); 548 if (this.hour <= this._defaults.hourMin) { 549 this.hour = this._defaults.hourMin; 550 this._defaults.minuteMin = minDateTime.getMinutes(); 551 if (this.minute <= this._defaults.minuteMin) { 552 this.minute = this._defaults.minuteMin; 553 this._defaults.secondMin = minDateTime.getSeconds(); 554 if (this.second <= this._defaults.secondMin) { 555 this.second = this._defaults.secondMin; 556 this._defaults.millisecMin = minDateTime.getMilliseconds(); 557 } else { 558 if (this.millisec < this._defaults.millisecMin) { 559 this.millisec = this._defaults.millisecMin; 560 } 561 this._defaults.millisecMin = this.millisecMinOriginal; 562 } 563 } else { 564 this._defaults.secondMin = this.secondMinOriginal; 565 this._defaults.millisecMin = this.millisecMinOriginal; 566 } 567 } else { 568 this._defaults.minuteMin = this.minuteMinOriginal; 569 this._defaults.secondMin = this.secondMinOriginal; 570 this._defaults.millisecMin = this.millisecMinOriginal; 571 } 572 } else { 573 this._defaults.hourMin = this.hourMinOriginal; 574 this._defaults.minuteMin = this.minuteMinOriginal; 575 this._defaults.secondMin = this.secondMinOriginal; 576 this._defaults.millisecMin = this.millisecMinOriginal; 577 } 578 } 579 580 if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) { 581 var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'), 582 maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0); 583 584 if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null) { 585 this.hourMaxOriginal = o.hourMax; 586 this.minuteMaxOriginal = o.minuteMax; 587 this.secondMaxOriginal = o.secondMax; 588 this.millisecMaxOriginal = o.millisecMax; 589 } 590 591 if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()) { 592 this._defaults.hourMax = maxDateTime.getHours(); 593 if (this.hour >= this._defaults.hourMax) { 594 this.hour = this._defaults.hourMax; 595 this._defaults.minuteMax = maxDateTime.getMinutes(); 596 if (this.minute >= this._defaults.minuteMax) { 597 this.minute = this._defaults.minuteMax; 598 this._defaults.secondMax = maxDateTime.getSeconds(); 599 if (this.second >= this._defaults.secondMax) { 600 this.second = this._defaults.secondMax; 601 this._defaults.millisecMax = maxDateTime.getMilliseconds(); 602 } else { 603 if (this.millisec > this._defaults.millisecMax) { 604 this.millisec = this._defaults.millisecMax; 605 } 606 this._defaults.millisecMax = this.millisecMaxOriginal; 607 } 608 } else { 609 this._defaults.secondMax = this.secondMaxOriginal; 610 this._defaults.millisecMax = this.millisecMaxOriginal; 611 } 612 } else { 613 this._defaults.minuteMax = this.minuteMaxOriginal; 614 this._defaults.secondMax = this.secondMaxOriginal; 615 this._defaults.millisecMax = this.millisecMaxOriginal; 616 } 617 } else { 618 this._defaults.hourMax = this.hourMaxOriginal; 619 this._defaults.minuteMax = this.minuteMaxOriginal; 620 this._defaults.secondMax = this.secondMaxOriginal; 621 this._defaults.millisecMax = this.millisecMaxOriginal; 622 } 623 } 624 625 if (adjustSliders !== undefined && adjustSliders === true) { 626 var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10), 627 minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10), 628 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); 630 631 if (this.hour_slider) { 632 this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax }); 633 this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour)); 634 } 635 if (this.minute_slider) { 636 this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax }); 637 this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute)); 638 } 639 if (this.second_slider) { 640 this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax }); 641 this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond)); 642 } 643 if (this.millisec_slider) { 644 this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax }); 645 this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec)); 646 } 647 } 648 649 }, 650 651 /* 652 * when a slider moves, set the internal time... 653 * on time change is also called when the time is updated in the text field 654 */ 655 _onTimeChange: function() { 656 var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false, 657 minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false, 658 second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false, 659 millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false, 660 timezone = (this.timezone_select) ? this.timezone_select.val() : false, 661 o = this._defaults, 662 pickerTimeFormat = o.pickerTimeFormat || o.timeFormat, 663 pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix; 664 665 if (typeof(hour) == 'object') { 666 hour = false; 667 } 668 if (typeof(minute) == 'object') { 669 minute = false; 670 } 671 if (typeof(second) == 'object') { 672 second = false; 673 } 674 if (typeof(millisec) == 'object') { 675 millisec = false; 676 } 677 if (typeof(timezone) == 'object') { 678 timezone = false; 679 } 680 681 if (hour !== false) { 682 hour = parseInt(hour, 10); 683 } 684 if (minute !== false) { 685 minute = parseInt(minute, 10); 686 } 687 if (second !== false) { 688 second = parseInt(second, 10); 689 } 690 if (millisec !== false) { 691 millisec = parseInt(millisec, 10); 692 } 693 694 var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0]; 695 696 // If the update was done in the input field, the input field should not be updated. 697 // 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))); 701 702 if (hasChanged) { 703 704 if (hour !== false) { 705 this.hour = hour; 706 } 707 if (minute !== false) { 708 this.minute = minute; 709 } 710 if (second !== false) { 711 this.second = second; 712 } 713 if (millisec !== false) { 714 this.millisec = millisec;
715 } 716 if (timezone !== false) { 717 this.timezone = timezone; 718 } 719 720 if (!this.inst) { 721 this.inst = $.datepicker._getInst(this.$input[0]); 722 } 723 724 this._limitMinMaxDateTime(this.inst, true); 725 } 726 if (useAmpm(o.timeFormat)) { 727 this.ampm = ampm; 728 } 729 730 // Updates the time within the timepicker 731 this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o); 732 if (this.$timeObj) { 733 if(pickerTimeFormat === o.timeFormat){ 734 this.$timeObj.text(this.formattedTime + pickerTimeSuffix); 735 } 736 else{ 737 this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix); 738 } 739 } 740 741 this.timeDefined = true; 742 if (hasChanged) { 743 this._updateDateTime(); 744 } 745 }, 746 747 /* 748 * call custom onSelect. 749 * bind to sliders slidestop, and grid click. 750 */ 751 _onSelectHandler: function() { 752 var onSelect = this._defaults.onSelect || this.inst.settings.onSelect; 753 var inputEl = this.$input ? this.$input[0] : null; 754 if (onSelect && inputEl) { 755 onSelect.apply(inputEl, [this.formattedDateTime, this]); 756 } 757 }, 758 759 /* 760 * update our input with the new date time.. 761 */ 762 _updateDateTime: function(dp_inst) { 763 dp_inst = this.inst || dp_inst; 764 var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)), 765 dateFmt = $.datepicker._get(dp_inst, 'dateFormat'), 766 formatCfg = $.datepicker._getFormatConfig(dp_inst), 767 timeAvailable = dt !== null && this.timeDefined; 768 this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg); 769 var formattedDateTime = this.formattedDate; 770 771 // 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; 776 } 777 778 /* 779 * 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. 781 * If the user manually empty the value in the input field, the date picker will never change selected value. 782 */ 783 //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) { 784 // return; 785 //} 786 787 if (this._defaults.timeOnly === true) { 788 formattedDateTime = this.formattedTime; 789 } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) { 790 formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix; 791 } 792 793 this.formattedDateTime = formattedDateTime; 794 795 if (!this._defaults.showTimepicker) { 796 this.$input.val(this.formattedDate); 797 } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) { 798 this.$altInput.val(this.formattedTime); 799 this.$input.val(this.formattedDate); 800 } else if (this.$altInput) { 801 this.$input.val(formattedDateTime); 802 var altFormattedDateTime = '', 803 altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator, 804 altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix; 805 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; 811 this.$altInput.val(altFormattedDateTime); 812 } else { 813 this.$input.val(formattedDateTime); 814 } 815 816 this.$input.trigger("change"); 817 }, 818 819 _onFocus: function() { 820 if (!this.$input.val() && this._defaults.defaultValue) { 821 this.$input.val(this._defaults.defaultValue); 822 var inst = $.datepicker._getInst(this.$input.get(0)), 823 tp_inst = $.datepicker._get(inst, 'timepicker'); 824 if (tp_inst) {
825 if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { 826 try { 827 $.datepicker._updateDatepicker(inst); 828 } catch (err) { 829 $.timepicker.log(err); 830 } 831 } 832 } 833 } 834 }, 835 836 /* 837 * Small abstraction to control types 838 * We can add more, just be sure to follow the pattern: create, options, value 839 */ 840 _controls: { 841 // slider methods 842 slider: { 843 create: function(tp_inst, obj, unit, val, min, max, step){ 844 var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60 845 return obj.prop('slide', null).slider({ 846 orientation: "horizontal", 847 value: rtl? val*-1 : val, 848 min: rtl? max*-1 : min, 849 max: rtl? min*-1 : max, 850 step: step, 851 slide: function(event, ui) { 852 tp_inst.control.value(tp_inst, $(this), unit, rtl? ui.value*-1:ui.value); 853 tp_inst._onTimeChange(); 854 }, 855 stop: function(event, ui) { 856 tp_inst._onSelectHandler(); 857 } 858 }); 859 }, 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); 866 return Math.abs(obj.slider(opts)); 867 } 868 return obj.slider(opts); 869 } 870 var min = opts.min, 871 max = opts.max; 872 opts.min = opts.max = null; 873 if(min !== undefined) 874 opts.max = min * -1; 875 if(max !== undefined) 876 opts.min = max * -1; 877 return obj.slider(opts); 878 } 879 if(typeof(opts) == 'string' && val !== undefined) 880 return obj.slider(opts, val); 881 return obj.slider(opts); 882 }, 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); 887 return Math.abs(obj.slider('value')); 888 } 889 if(val !== undefined) 890 return obj.slider('value', val); 891 return obj.slider('value'); 892 } 893 }, 894 // select methods 895 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(); 907 sel += '</option>'; 908 } 909 sel += '</select>'; 910 911 obj.children('select').remove(); 912 913 $(sel).appendTo(obj).change(function(e){ 914 tp_inst._onTimeChange(); 915 tp_inst._onSelectHandler(); 916 }); 917 918 return obj; 919 }, 920 options: function(tp_inst, obj, unit, opts, val){ 921 var o = {}, 922 $t = obj.children('select'); 923 if(typeof(opts) == 'string'){ 924 if(val === undefined) 925 return $t.data(opts); 926 o[opts] = val; 927 } 928 else o = opts; 929 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 }, 931 value: function(tp_inst, obj, unit, val){ 932 var $t = obj.children('select'); 933 if(val !== undefined) 934 return $t.val(val); 935 return $t.val(); 936 } 937 } 938 } // end _controls 939 940 }); 941 942 $.fn.extend({ 943 /* 944 * shorthand just to use timepicker.. 945 */ 946 timepicker: function(o) { 947 o = o || {}; 948 var tmp_args = Array.prototype.slice.call(arguments); 949 950 if (typeof o == 'object') { 951 tmp_args[0] = $.extend(o, { 952 timeOnly: true 953 }); 954 } 955 956 return $(this).each(function() { 957 $.fn.datetimepicker.apply($(this), tmp_args); 958 }); 959 }, 960 961 /* 962 * extend timepicker to datepicker 963 */ 964 datetimepicker: function(o) { 965 o = o || {}; 966 var tmp_args = arguments; 967 968 if (typeof(o) == 'string') { 969 if (o == 'getDate') { 970 return $.fn.datepicker.apply($(this[0]), tmp_args); 971 } else { 972 return this.each(function() { 973 var $t = $(this); 974 $t.datepicker.apply($t, tmp_args); 975 });
976 } 977 } else { 978 return this.each(function() { 979 var $t = $(this); 980 $t.datepicker($.timepicker._newInst($t, o)._defaults); 981 }); 982 } 983 } 984 }); 985 986 /* 987 * Public Utility to parse date and time 988 */ 989 $.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) { 990 var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings); 991 if (parseRes.timeObj) { 992 var t = parseRes.timeObj; 993 parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec); 994 } 995 996 return parseRes.date; 997 }; 998 999 /* 1000 * Public utility to parse time 1001 */ 1002 $.datepicker.parseTime = function(timeFormat, timeString, options) { 1003 var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}); 1004 1005 // Strict parse requires the timeString to match the timeFormat exactly 1006 var strictParse = function(f, s, o){ 1007 1008 // pattern for standard and localized AM/PM markers 1009 var getPatternAmpm = function(amNames, pmNames) { 1010 var markers = []; 1011 if (amNames) { 1012 $.merge(markers, amNames); 1013 } 1014 if (pmNames) { 1015 $.merge(markers, pmNames); 1016 } 1017 markers = $.map(markers, function(val) { 1018 return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&'); 1019 }); 1020 return '(' + markers.join('|') + ')?'; 1021 }; 1022 1023 // 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), 1026 orders = { 1027 h: -1, 1028 m: -1, 1029 s: -1, 1030 l: -1, 1031 t: -1, 1032 z: -1 1033 }; 1034 1035 if (finds) { 1036 for (var i = 0; i < finds.length; i++) { 1037 if (orders[finds[i].toString().charAt(0)] == -1) { 1038 orders[finds[i].toString().charAt(0)] = i + 1; 1039 } 1040 } 1041 } 1042 return orders; 1043 }; 1044 1045 var regstr = '^' + f.toString() 1046 .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g, function (match) { 1047 var ml = match.length; 1048 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; }) + ')?'; 1057 } 1058 }) 1059 .replace(/\s/g, '\\s?') + 1060 o.timeSuffix + '$', 1061 order = getFormatPositions(f), 1062 ampm = '', 1063 treg; 1064 1065 treg = s.match(new RegExp(regstr, 'i')); 1066 1067 var resTime = { 1068 hour: 0, 1069 minute: 0, 1070 second: 0, 1071 millisec: 0 1072 }; 1073 1074 if (treg) { 1075 if (order.t !== -1) { 1076 if (treg[order.t] === undefined || treg[order.t].length === 0) { 1077 ampm = ''; 1078 resTime.ampm = ''; 1079 } else { 1080 ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM'; 1081 resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0]; 1082 } 1083 } 1084 1085 if (order.h !== -1) { 1086 if (ampm == 'AM' && treg[order.h] == '12') { 1087 resTime.hour = 0; // 12am = 0 hour 1088 } else { 1089 if (ampm == 'PM' && treg[order.h] != '12') { 1090 resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12 1091 } else { 1092 resTime.hour = Number(treg[order.h]); 1093 } 1094 } 1095 } 1096 1097 if (order.m !== -1) { 1098 resTime.minute = Number(treg[order.m]); 1099 } 1100 if (order.s !== -1) { 1101 resTime.second = Number(treg[order.s]); 1102 } 1103 if (order.l !== -1) { 1104 resTime.millisec = Number(treg[order.l]); 1105 } 1106 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; 1131 } 1132 1133 1134 return resTime; 1135 } 1136 return false; 1137 };// end strictParse 1138 1139 // 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; 1149 } 1150 } 1151 } 1152 1153 return { 1154 hour: d.getHours(), 1155 minute: d.getMinutes(),
1156 second: d.getSeconds(), 1157 millisec: d.getMilliseconds(), 1158 timezone: $.timepicker.timeZoneOffsetString(d) 1159 }; 1160 } 1161 catch(err){ 1162 try{ 1163 return strictParse(f,s,o); 1164 } 1165 catch(err2){ 1166 $.timepicker.log("Unable to parse \ntimeString: "+ s +"\ntimeFormat: "+ f); 1167 } 1168 } 1169 return false; 1170 }; // end looseParse 1171 1172 if(typeof o.parse === "function"){ 1173 return o.parse(timeFormat, timeString, o) 1174 } 1175 if(o.parse === 'loose'){ 1176 return looseParse(timeFormat, timeString, o); 1177 } 1178 return strictParse(timeFormat, timeString, o); 1179 }; 1180 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) { 1188 options = options || {}; 1189 options = $.extend({}, $.timepicker._defaults, options); 1190 time = $.extend({ 1191 hour: 0, 1192 minute: 0, 1193 second: 0, 1194 millisec: 0, 1195 timezone: '+0000' 1196 }, time); 1197 1198 var tmptime = format, 1199 ampmName = options.amNames[0], 1200 hour = parseInt(time.hour, 10); 1201 1202 if (hour > 11) { 1203 ampmName = options.pmNames[0]; 1204 } 1205 1206 tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[lz]|('.*?'|".*?"))/g, function(match) { 1207 switch (match) { 1208 case 'HH': 1209 return ('0' + hour).slice(-2); 1210 case 'H': 1211 return hour; 1212 case 'hh': 1213 return ('0' + convert24to12(hour)).slice(-2); 1214 case 'h': 1215 return convert24to12(hour); 1216 case 'mm': 1217 return ('0' + time.minute).slice(-2); 1218 case 'm': 1219 return time.minute; 1220 case 'ss': 1221 return ('0' + time.second).slice(-2); 1222 case 's': 1223 return time.second; 1224 case 'l': 1225 return ('00' + time.millisec).slice(-3); 1226 case 'z': 1227 return time.timezone === null? options.defaultTimezone : time.timezone; 1228 case 'T': 1229 return ampmName.charAt(0).toUpperCase(); 1230 case 'TT': 1231 return ampmName.toUpperCase(); 1232 case 't': 1233 return ampmName.charAt(0).toLowerCase(); 1234 case 'tt': 1235 return ampmName.toLowerCase(); 1236 default: 1237 return match.replace(/\'/g, "") || "'"; 1238 } 1239 }); 1240 1241 tmptime = $.trim(tmptime); 1242 return tmptime; 1243 }; 1244 1245 /* 1246 * the bad hack :/ override datepicker so it doesnt close on select 1247 // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378 1248 */ 1249 $.datepicker._base_selectDate = $.datepicker._selectDate; 1250 $.datepicker._selectDate = function(id, dateStr) { 1251 var inst = this._getInst($(id)[0]), 1252 tp_inst = this._get(inst, 'timepicker'); 1253 1254 if (tp_inst) { 1255 tp_inst._limitMinMaxDateTime(inst, true); 1256 inst.inline = inst.stay_open = true; 1257 //This way the onSelect handler called from calendarpicker get the full dateTime 1258 this._base_selectDate(id, dateStr); 1259 inst.inline = inst.stay_open = false; 1260 this._notifyChange(inst); 1261 this._updateDatepicker(inst); 1262 } else { 1263 this._base_selectDate(id, dateStr); 1264 } 1265 }; 1266 1267 /* 1268 * second bad hack :/ override datepicker so it triggers an event when changing the input field 1269 * and does not redraw the datepicker on every selectDate event 1270 */ 1271 $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker; 1272 $.datepicker._updateDatepicker = function(inst) { 1273 1274 // don't popup the datepicker if there is another instance already opened 1275 var input = inst.input[0]; 1276 if ($.datepicker._curInst && $.datepicker._curInst != inst && $.datepicker._datepickerShowing && $.datepicker._lastInput != input) { 1277 return; 1278 } 1279 1280 if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) { 1281 1282 this._base_updateDatepicker(inst); 1283 1284 // Reload the time control when changing something in the input text field. 1285 var tp_inst = this._get(inst, 'timepicker'); 1286 if (tp_inst) { 1287 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 } 1295 } 1296 }; 1297 1298 /* 1299 * third bad hack :/ override datepicker so it allows spaces and colon in the input field 1300 */ 1301 $.datepicker._base_doKeyPress = $.datepicker._doKeyPress; 1302 $.datepicker._doKeyPress = function(event) { 1303 var inst = $.datepicker._getInst(event.target), 1304 tp_inst = $.datepicker._get(inst, 'timepicker'); 1305 1306 if (tp_inst) { 1307 if ($.datepicker._get(inst, 'constrainInput')) { 1308 var ampm = useAmpm(tp_inst._defaults.timeFormat), 1309 dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')), 1310 datetimeChars = tp_inst._defaults.timeFormat.toString() 1311 .replace(/[hms]/g, '') 1312 .replace(/TT/g, ampm ? 'APM' : '') 1313 .replace(/Tt/g, ampm ? 'AaPpMm' : '') 1314 .replace(/tT/g, ampm ? 'AaPpMm' : '') 1315 .replace(/T/g, ampm ? 'AP' : '') 1316 .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('')) + 1322 dateChars, 1323 chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode); 1324 return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1); 1325 } 1326 } 1327 1328 return $.datepicker._base_doKeyPress(event); 1329 }; 1330 1331 /* 1332 * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField 1333 */ 1334 $.datepicker._base_updateAlternate = $.datepicker._updateAlternate; 1335 /* Update any alternate field to synchronise with the main field. */ 1336 $.datepicker._updateAlternate = function(inst) { 1337 var tp_inst = this._get(inst, 'timepicker'); 1338 if(tp_inst){ 1339 var altField = tp_inst._defaults.altField; 1340 if (altField) { // update alternate field too 1341 var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat, 1342 date = this._getDate(inst), 1343 formatCfg = $.datepicker._getFormatConfig(inst), 1344 altFormattedDateTime = '', 1345 altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator, 1346 altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix, 1347 altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat; 1348 1349 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) 1352 altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime; 1353 else altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime; 1354 } 1355 $(altField).val(altFormattedDateTime); 1356 } 1357 } 1358 else{ 1359 $.datepicker._base_updateAlternate(inst); 1360 } 1361 }; 1362 1363 /* 1364 * Override key up event to sync manual input changes. 1365 */ 1366 $.datepicker._base_doKeyUp = $.datepicker._doKeyUp; 1367 $.datepicker._doKeyUp = function(event) { 1368 var inst = $.datepicker._getInst(event.target), 1369 tp_inst = $.datepicker._get(inst, 'timepicker'); 1370 1371 if (tp_inst) {
1372 if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { 1373 try { 1374 $.datepicker._updateDatepicker(inst); 1375 } catch (err) { 1376 $.timepicker.log(err); 1377 } 1378 } 1379 } 1380 1381 return $.datepicker._base_doKeyUp(event); 1382 }; 1383 1384 /* 1385 * override "Today" button to also grab the time. 1386 */ 1387 $.datepicker._base_gotoToday = $.datepicker._gotoToday; 1388 $.datepicker._gotoToday = function(id) { 1389 var inst = this._getInst($(id)[0]), 1390 $dp = inst.dpDiv; 1391 this._base_gotoToday(id); 1392 var tp_inst = this._get(inst, 'timepicker'); 1393 selectLocalTimeZone(tp_inst); 1394 var now = new Date(); 1395 this._setTime(inst, now); 1396 $('.ui-datepicker-today', $dp).click(); 1397 }; 1398 1399 /* 1400 * Disable & enable the Time in the datetimepicker 1401 */ 1402 $.datepicker._disableTimepickerDatepicker = function(target) { 1403 var inst = this._getInst(target); 1404 if (!inst) { 1405 return; 1406 } 1407 1408 var tp_inst = this._get(inst, 'timepicker'); 1409 $(target).datepicker('getDate'); // Init selected[Year|Month|Day] 1410 if (tp_inst) { 1411 tp_inst._defaults.showTimepicker = false; 1412 tp_inst._updateDateTime(inst); 1413 } 1414 }; 1415 1416 $.datepicker._enableTimepickerDatepicker = function(target) { 1417 var inst = this._getInst(target); 1418 if (!inst) { 1419 return; 1420 } 1421 1422 var tp_inst = this._get(inst, 'timepicker'); 1423 $(target).datepicker('getDate'); // Init selected[Year|Month|Day] 1424 if (tp_inst) { 1425 tp_inst._defaults.showTimepicker = true; 1426 tp_inst._addTimePicker(inst); // Could be disabled on page load 1427 tp_inst._updateDateTime(inst); 1428 } 1429 }; 1430 1431 /* 1432 * Create our own set time function 1433 */ 1434 $.datepicker._setTime = function(inst, date) { 1435 var tp_inst = this._get(inst, 'timepicker'); 1436 if (tp_inst) { 1437 var defaults = tp_inst._defaults; 1438 1439 // calling _setTime with no date sets time to defaults 1440 tp_inst.hour = date ? date.getHours() : defaults.hour; 1441 tp_inst.minute = date ? date.getMinutes() : defaults.minute; 1442 tp_inst.second = date ? date.getSeconds() : defaults.second; 1443 tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec; 1444 1445 //check if within min/max times.. 1446 tp_inst._limitMinMaxDateTime(inst, true); 1447 1448 tp_inst._onTimeChange(); 1449 tp_inst._updateDateTime(inst); 1450 } 1451 }; 1452 1453 /* 1454 * Create new public method to set only time, callable as $().datepicker('setTime', date) 1455 */ 1456 $.datepicker._setTimeDatepicker = function(target, date, withDate) { 1457 var inst = this._getInst(target); 1458 if (!inst) { 1459 return; 1460 } 1461 1462 var tp_inst = this._get(inst, 'timepicker'); 1463 1464 if (tp_inst) { 1465 this._setDateFromField(inst); 1466 var tp_date; 1467 if (date) { 1468 if (typeof date == "string") { 1469 tp_inst._parseTime(date, withDate); 1470 tp_date = new Date(); 1471 tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); 1472 } else { 1473 tp_date = new Date(date.getTime()); 1474 } 1475 if (tp_date.toString() == 'Invalid Date') { 1476 tp_date = undefined; 1477 } 1478 this._setTime(inst, tp_date); 1479 } 1480 } 1481 1482 }; 1483 1484 /* 1485 * override setDate() to allow setting time too within Date object 1486 */ 1487 $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker; 1488 $.datepicker._setDateDatepicker = function(target, date) { 1489 var inst = this._getInst(target); 1490 if (!inst) { 1491 return; 1492 } 1493 1494 var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date; 1495 1496 this._updateDatepicker(inst); 1497 this._base_setDateDatepicker.apply(this, arguments); 1498 this._setTimeDatepicker(target, tp_date, true); 1499 }; 1500 1501 /* 1502 * override getDate() to allow getting time too within Date object 1503 */ 1504 $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker; 1505 $.datepicker._getDateDatepicker = function(target, noDefault) { 1506 var inst = this._getInst(target); 1507 if (!inst) { 1508 return; 1509 } 1510 1511 var tp_inst = this._get(inst, 'timepicker'); 1512 1513 if (tp_inst) { 1514 // if it hasn't yet been defined, grab from field 1515 if(inst.lastVal === undefined){ 1516 this._setDateFromField(inst, noDefault); 1517 } 1518 1519 var date = this._getDate(inst); 1520 if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
1521 date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); 1522 } 1523 return date; 1524 } 1525 return this._base_getDateDatepicker(target, noDefault); 1526 }; 1527 1528 /* 1529 * override parseDate() because UI 1.8.14 throws an error about "Extra characters" 1530 * An option in datapicker to ignore extra format characters would be nicer. 1531 */ 1532 $.datepicker._base_parseDate = $.datepicker.parseDate; 1533 $.datepicker.parseDate = function(format, value, settings) { 1534 var date; 1535 try { 1536 date = this._base_parseDate(format, value, settings); 1537 } catch (err) { 1538 // Hack! The error message ends with a colon, a space, and 1539 // the "extra" characters. We rely on that instead of 1540 // 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); 1543 } 1544 return date; 1545 }; 1546 1547 /* 1548 * override formatDate to set date with time to the input 1549 */ 1550 $.datepicker._base_formatDate = $.datepicker._formatDate; 1551 $.datepicker._formatDate = function(inst, day, month, year) { 1552 var tp_inst = this._get(inst, 'timepicker'); 1553 if (tp_inst) { 1554 tp_inst._updateDateTime(inst); 1555 return tp_inst.$input.val(); 1556 } 1557 return this._base_formatDate(inst); 1558 }; 1559 1560 /* 1561 * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate 1562 */ 1563 $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker; 1564 $.datepicker._optionDatepicker = function(target, name, value) { 1565 var inst = this._getInst(target), 1566 name_clone; 1567 if (!inst) { 1568 return null; 1569 } 1570 1571 var tp_inst = this._get(inst, 'timepicker'); 1572 if (tp_inst) { 1573 var min = null, 1574 max = null, 1575 onselect = null, 1576 overrides = tp_inst._defaults.evnts, 1577 fns = {}, 1578 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 } 1636 } 1637 if (value === undefined) { 1638 return this._base_optionDatepicker.call($.datepicker, target, name); 1639 } 1640 return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value); 1641 }; 1642 /* 1643 * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype, 1644 * it will return false for all objects 1645 */ 1646 var isEmptyObject = function(obj) { 1647 var prop; 1648 for (prop in obj) { 1649 if (obj.hasOwnProperty(obj)) { 1650 return false; 1651 } 1652 } 1653 return true; 1654 }; 1655 1656 /* 1657 * jQuery extend now ignores nulls! 1658 */ 1659 var extendRemove = function(target, props) { 1660 $.extend(target, props); 1661 for (var name in props) { 1662 if (props[name] === null || props[name] === undefined) { 1663 target[name] = props[name]; 1664 } 1665 } 1666 return target; 1667 }; 1668 1669 /* 1670 * Determine by the time format if should use ampm 1671 * Returns true if should use ampm, false if not 1672 */ 1673 var useAmpm = function(timeFormat){ 1674 return (timeFormat.indexOf('t') !== -1 && timeFormat.indexOf('h') !== -1); 1675 }; 1676 1677 /* 1678 * Converts 24 hour format into 12 hour 1679 * Returns 12 hour without leading 0 1680 */ 1681 var convert24to12 = function(hour) { 1682 if (hour > 12) { 1683 hour = hour - 12; 1684 } 1685 1686 if (hour == 0) { 1687 hour = 12; 1688 } 1689 1690 return String(hour); 1691 }; 1692 1693 /* 1694 * Splits datetime string into date ans time substrings. 1695 * Throws exception when date can't be parsed 1696 * Returns [dateString, timeString] 1697 */ 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
1701split. 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 } 1736 } 1737 return [dateTimeString, '']; 1738 }; 1739 1740 /* 1741 * Internal function to parse datetime interval 1742 * Returns: {date: Date, timeObj: Object}, where 1743 * date - parsed date without time (type Date) 1744 * timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional 1745 */ 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); 1753 1754 if (parsedTime === null) { 1755 throw 'Wrong time format'; 1756 } 1757 return { 1758 date: date, 1759 timeObj: parsedTime 1760 }; 1761 } else { 1762 return { 1763 date: date 1764 }; 1765 } 1766 }; 1767 1768 /* 1769 * Internal function to set timezone_select to the local timezone 1770 */ 1771 var selectLocalTimeZone = function(tp_inst, date) { 1772 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); 1780 } 1781 }; 1782 1783 /* 1784 * Create a Singleton Insance 1785 */ 1786 $.timepicker = new Timepicker(); 1787 1788 /** 1789 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5) 1790 * @param date 1791 * @return string 1792 */ 1793 $.timepicker.timeZoneOffsetString = function(date) { 1794 var off = date.getTimezoneOffset() * -1, 1795 minutes = off % 60, 1796 hours = (off - minutes) / 60; 1797 return (off >= 0 ? '+' : '-') + ('0' + (hours * 101).toString()).slice(-2) + ('0' + (minutes * 101).toString()).slice(-2); 1798 }; 1799 1800 /** 1801 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to 1802 * enforce date range limits. 1803 * 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 1808 */ 1809 $.timepicker.timeRange = function(startTime, endTime, options) { 1810 return $.timepicker.handleRange('timepicker', startTime, endTime, options); 1811 }; 1812 1813 /** 1814 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to 1815 * enforce date range limits. 1816 * @param Element startTime 1817 * @param Element endTime 1818 * @param obj options Options for the `timepicker()` call. Also supports `reformat`, 1819 * 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 1822 */ 1823 $.timepicker.dateTimeRange = function(startTime, endTime, options) { 1824 $.timepicker.dateRange(startTime, endTime, options, 'datetimepicker'); 1825 }; 1826 1827 /** 1828 * Calls `method` on the `startTime` and `endTime` elements, and configures them to 1829 * enforce date range limits. 1830 * @param Element startTime 1831 * @param Element endTime 1832 * @param obj options Options for the `timepicker()` call. Also supports `reformat`, 1833 * 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 1836 */ 1837 $.timepicker.dateRange = function(startTime, endTime, options, method) { 1838 method = method || 'datepicker'; 1839 $.timepicker.handleRange(method, startTime, endTime, options); 1840 }; 1841 1842 /** 1843 * Calls `method` on the `startTime` and `endTime` elements, and configures them to 1844 * 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`, 1849 * a boolean value that can be used to reformat the input values to the `dateFormat`. 1850 * @return jQuery 1851 */ 1852 $.timepicker.handleRange = function(method, startTime, endTime, options) { 1853 $.fn[method].call(startTime, $.extend({ 1854 onClose: function(dateText, inst) { 1855 checkDates(this, endTime, dateText); 1856 }, 1857 onSelect: function(selectedDateTime) { 1858 selected(this, endTime, 'minDate'); 1859 } 1860 }, options, options.start)); 1861 $.fn[method].call(endTime, $.extend({ 1862 onClose: function(dateText, inst) { 1863 checkDates(this, startTime, dateText); 1864 }, 1865 onSelect: function(selectedDateTime) { 1866 selected(this, startTime, 'maxDate'); 1867 } 1868 }, 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 1883 function checkDates(changed, other, dateText) { 1884 if (other.val() && (new Date(startTime.val()) > new Date(endTime.val()))) { 1885 other.val(dateText); 1886 } 1887 } 1888 selected(startTime, endTime, 'minDate'); 1889 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 return $([startTime.get(0), endTime.get(0)]); 1902 }; 1903 1904 /** 1905 * 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 1908 */ 1909 $.timepicker.log = function(err){ 1910 if(window.console) 1911 console.log(err); 1912 }; 1913 1914 /* 1915 * Keep up with the version 1916 */ 1917 $.timepicker.version = "1.2"; 1918 1919})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.