1/* 2 * jQuery timepicker addon 3 * By: Trent Richardson [http://trentrichardson.com] 4 * Version 1.0.3 5 * Last Modified: 09/15/2012 6 * 7 * Copyright 2012 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 * HERES THE CSS: 13 * .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } 14 * .ui-timepicker-div dl { text-align: left; } 15 * .ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; } 16 * .ui-timepicker-div dl dd { margin: 0 10px 10px 65px; } 17 * .ui-timepicker-div td { font-size: 90%; } 18 * .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } 19 */ 20 21/*jslint evil: true, white: false, undef: false, nomen: false */ 22 23(function($) { 24 25 /* 26 * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded" 27 */ 28 $.ui.timepicker = $.ui.timepicker || {}; 29 if($.ui.timepicker.version) { 30 return; 31 } 32 33 /* 34 * Extend jQueryUI, get it started with our version number 35 */ 36 $.extend($.ui, { 37 timepicker: { 38 version: "1.0.3" 39 } 40 }); 41 42 /* 43 * Timepicker manager. 44 * Use the singleton instance of this class, $.timepicker, to interact with the time picker. 45 * Settings for (groups of) time pickers are maintained in an instance object, 46 * allowing multiple different settings on the same page. 47 */ 48 function Timepicker() { 49 this.regional = []; // Available regional settings, indexed by language code 50 this.regional[''] = { // Default regional settings 51 currentText: 'Now', 52 closeText: 'Done', 53 ampm: false, 54 amNames: ['AM', 'A'], 55 pmNames: ['PM', 'P'], 56 timeFormat: 'hh:mm tt', 57 timeSuffix: '', 58 timeOnlyTitle: 'Choose Time', 59 timeText: 'Time', 60 hourText: 'Hour', 61 minuteText: 'Minute', 62 secondText: 'Second', 63 millisecText: 'Millisecond', 64 timezoneText: 'Time Zone' 65 }; 66 this._defaults = { // Global defaults for all the datetime picker instances 67 showButtonPanel: true, 68 timeOnly: false, 69 showHour: true, 70 showMinute: true, 71 showSecond: false, 72 showMillisec: false, 73 showTimezone: false, 74 showTime: true, 75 stepHour: 1, 76 stepMinute: 1, 77 stepSecond: 1, 78 stepMillisec: 1, 79 hour: 0, 80 minute: 0, 81 second: 0, 82 millisec: 0, 83 timezone: null, 84 useLocalTimezone: false, 85 defaultTimezone: "+0000", 86 hourMin: 0, 87 minuteMin: 0, 88 secondMin: 0, 89 millisecMin: 0, 90 hourMax: 23, 91 minuteMax: 59, 92 secondMax: 59, 93 millisecMax: 999, 94 minDateTime: null, 95 maxDateTime: null, 96 onSelect: null, 97 hourGrid: 0, 98 minuteGrid: 0, 99 secondGrid: 0, 100 millisecGrid: 0, 101 alwaysSetTime: true, 102 separator: ' ', 103 altFieldTimeOnly: true, 104 altSeparator: null, 105 altTimeSuffix: null, 106 showTimepicker: true, 107 timezoneIso8601: false, 108 timezoneList: null, 109 addSliderAccess: false, 110 sliderAccessArgs: null, 111 defaultValue: null 112 }; 113 $.extend(this._defaults, this.regional['']); 114 } 115 116 $.extend(Timepicker.prototype, { 117 $input: null, 118 $altInput: null, 119 $timeObj: null, 120 inst: null, 121 hour_slider: null, 122 minute_slider: null, 123 second_slider: null, 124 millisec_slider: null, 125 timezone_select: null, 126 hour: 0, 127 minute: 0, 128 second: 0, 129 millisec: 0, 130 timezone: null, 131 defaultTimezone: "+0000", 132 hourMinOriginal: null, 133 minuteMinOriginal: null, 134 secondMinOriginal: null, 135 millisecMinOriginal: null, 136 hourMaxOriginal: null, 137 minuteMaxOriginal: null, 138 secondMaxOriginal: null, 139 millisecMaxOriginal: null, 140 ampm: '', 141 formattedDate: '', 142 formattedTime: '', 143 formattedDateTime: '', 144 timezoneList: null, 145 units: ['hour','minute','second','millisec'], 146 147 /* 148 * Override the default settings for all instances of the time picker. 149 * @param settings object - the new settings to use as defaults (anonymous object) 150 * @return the manager object 151 */ 152 setDefaults: function(settings) { 153 extendRemove(this._defaults, settings || {}); 154 return this; 155 }, 156 157 /* 158 * Create a new Timepicker instance 159 */ 160 _newInst: function($input, o) { 161 var tp_inst = new Timepicker(), 162 inlineSettings = {}; 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 tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, { 177 beforeShow: function(input, dp_inst) { 178 if($.isFunction(o.beforeShow)) { 179 return o.beforeShow(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(o.onChangeMonthYear)) { 186 o.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(o.onClose)) { 194 o.onClose.call($input[0], dateText, dp_inst, tp_inst); 195 } 196 }, 197 timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker'); 198 }); 199 tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { 200 return val.toUpperCase(); 201 }); 202 tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { 203 return val.toUpperCase(); 204 }); 205 206 if(tp_inst._defaults.timezoneList === null) { 207 var timezoneList = ['-1200', '-1100', '-1000', '-0930', '-0900', '-0800', '-0700', '-0600', '-0500', '-0430', '-0400', '-0330', '-0300', '-0200', '-0100', '+0000', 208 '+0100', '+0200', '+0300', '+0330', '+0400', '+0430', '+0500', '+0530', '+0545', '+0600', '+0630', '+0700', '+0800', '+0845', '+0900', '+0930', 209 '+1000', '+1030', '+1100', '+1130', '+1200', '+1245', '+1300', '+1400']; 210 211 if(tp_inst._defaults.timezoneIso8601) { 212 timezoneList = $.map(timezoneList, function(val) { 213 return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3));
214 }); 215 } 216 tp_inst._defaults.timezoneList = timezoneList; 217 } 218 219 tp_inst.timezone = tp_inst._defaults.timezone; 220 tp_inst.hour = tp_inst._defaults.hour; 221 tp_inst.minute = tp_inst._defaults.minute; 222 tp_inst.second = tp_inst._defaults.second; 223 tp_inst.millisec = tp_inst._defaults.millisec; 224 tp_inst.ampm = ''; 225 tp_inst.$input = $input; 226 227 if(o.altField) { 228 tp_inst.$altInput = $(o.altField).css({ 229 cursor: 'pointer' 230 }).focus(function() { 231 $input.trigger("focus"); 232 }); 233 } 234 235 if(tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) { 236 tp_inst._defaults.minDate = new Date(); 237 } 238 if(tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) { 239 tp_inst._defaults.maxDate = new Date(); 240 } 241 242 // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime.. 243 if(tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) { 244 tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime()); 245 } 246 if(tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) { 247 tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime()); 248 } 249 if(tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) { 250 tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime()); 251 } 252 if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) { 253 tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); 254 } 255 tp_inst.$input.bind('focus', function() { 256 tp_inst._onFocus(); 257 }); 258 259 return tp_inst; 260 }, 261 262 /* 263 * add our sliders to the calendar 264 */ 265 _addTimePicker: function(dp_inst) { 266 var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val(); 267 268 this.timeDefined = this._parseTime(currDT); 269 this._limitMinMaxDateTime(dp_inst, false); 270 this._injectTimePicker(); 271 }, 272 273 /* 274 * parse the time string from input value or _setTime 275 */ 276 _parseTime: function(timeString, withDate) { 277 if(!this.inst) { 278 this.inst = $.datepicker._getInst(this.$input[0]); 279 } 280 281 if(withDate || !this._defaults.timeOnly) { 282 var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); 283 try { 284 var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults); 285 if(!parseRes.timeObj) { 286 return false; 287 } 288 $.extend(this, parseRes.timeObj); 289 } catch (err) { 290 return false; 291 } 292 return true; 293 } else { 294 var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults); 295 if(!timeObj) { 296 return false; 297 } 298 $.extend(this, timeObj); 299 return true; 300 } 301 }, 302 303 /* 304 * generate and inject html for timepicker into ui datepicker 305 */ 306 _injectTimePicker: function() { 307 var $dp = this.inst.dpDiv, 308 o = this.inst.settings, 309 tp_inst = this, 310 litem = '', 311 uitem = '', 312 max = {}, 313 gridSize = {}, 314 size = null; 315 316 // Prevent displaying twice 317 if($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) { 318 var noDisplay = ' style="display:none;"', 319 html = '<div class="ui-timepicker-div"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' + 320 '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>'; 321 322 // Create the markup 323 for(var i=0,l=this.units.length; i<l; i++){ 324 litem = this.units[i]; 325 uitem = litem.substr(0,1).toUpperCase() + litem.substr(1); 326 // Added by Peter Medeiros: 327 // - Figure out what the hour/minute/second max should be based on the step values. 328 // - Example: if stepMinute is 15, then minMax is 45. 329 max[litem] = parseInt((o[litem+'Max'] - ((o[litem+'Max'] - o[litem+'Min']) % o['step'+uitem])), 10); 330 gridSize[litem] = 0; 331 332 html += '<dt class="ui_tpicker_'+ litem +'_label"' + ((o['show'+uitem]) ? '' : noDisplay) + '>' + o[litem +'Text'] + '</dt>' + 333 '<dd class="ui_tpicker_'+ litem +'"><div class="ui_tpicker_'+ litem +'_slider"' + ((o['show'+uitem]) ? '' : noDisplay) + '></div>'; 334 335 if(o['show'+uitem] && o[litem+'Grid'] > 0) { 336 html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>'; 337 338 if(litem == 'hour'){ 339 for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) { 340 gridSize[litem]++; 341 var tmph = (o.ampm && h > 12) ? h - 12 : h; 342 if(tmph < 10) { 343 tmph = '0' + tmph; 344 } 345 if(o.ampm) { 346 if(h === 0) { 347 tmph = 12 + 'a'; 348 } else { 349 if(h < 12) { 350 tmph += 'a'; 351 } else { 352 tmph += 'p'; 353 } 354 } 355 } 356 html += '<td data-for="'+litem+'">' + tmph + '</td>'; 357 } 358 } 359 else{ 360 for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) { 361 gridSize[litem]++; 362 html += '<td data-for="'+litem+'">' + ((m < 10) ? '0' : '') + m + '</td>'; 363 } 364 } 365 366 html += '</tr></table></div>'; 367 } 368 html += '</dd>'; 369 } 370 371 // Timezone 372 html += '<dt class="ui_tpicker_timezone_label"' + ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>'; 373 html += '<dd class="ui_tpicker_timezone" ' + ((o.showTimezone) ? '' : noDisplay) + '></dd>'; 374 375 // Create the elements from string 376 html += '</dl></div>'; 377 var $tp = $(html); 378 379 // if we only want time picker... 380 if(o.timeOnly === true) { 381 $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>'); 382 $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide(); 383 } 384 385 // Updated by Peter Medeiros: 386 // - Pass in Event and UI instance into slide function 387 this.hour_slider = $tp.find('.ui_tpicker_hour_slider').prop('slide', null).slider({ 388 orientation: "horizontal", 389 value: this.hour, 390 min: o.hourMin, 391 max: max.hour, 392 step: o.stepHour, 393 slide: function(event, ui) { 394 tp_inst.hour_slider.slider("option", "value", ui.value); 395 tp_inst._onTimeChange(); 396 }, 397 stop: function(event, ui) { 398 tp_inst._onSelectHandler(); 399 } 400 }); 401 402 this.minute_slider = $tp.find('.ui_tpicker_minute_slider').prop('slide', null).slider({ 403 orientation: "horizontal", 404 value: this.minute, 405 min: o.minuteMin, 406 max: max.minute, 407 step: o.stepMinute, 408 slide: function(event, ui) { 409 tp_inst.minute_slider.slider("option", "value", ui.value); 410 tp_inst._onTimeChange(); 411 }, 412 stop: function(event, ui) { 413 tp_inst._onSelectHandler(); 414 } 415 }); 416 417 this.second_slider = $tp.find('.ui_tpicker_second_slider').prop('slide', null).slider({ 418 orientation: "horizontal", 419 value: this.second, 420 min: o.secondMin, 421 max: max.second, 422 step: o.stepSecond, 423 slide: function(event, ui) { 424 tp_inst.second_slider.slider("option", "value", ui.value); 425 tp_inst._onTimeChange(); 426 }, 427 stop: function(event, ui) { 428 tp_inst._onSelectHandler(); 429 } 430 }); 431 432 this.millisec_slider = $tp.find('.ui_tpicker_millisec_slider').prop('slide', null).slider({ 433 orientation: "horizontal", 434 value: this.millisec, 435 min: o.millisecMin, 436 max: max.millisec, 437 step: o.stepMillisec, 438 slide: function(event, ui) { 439 tp_inst.millisec_slider.slider("option", "value", ui.value); 440 tp_inst._onTimeChange(); 441 }, 442 stop: function(event, ui) { 443 tp_inst._onSelectHandler(); 444 } 445 }); 446 447 // add sliders, adjust grids, add events 448 for(var i=0,l=tp_inst.units.length; i<l; i++){ 449 litem = tp_inst.units[i]; 450 uitem = litem.substr(0,1).toUpperCase() + litem.substr(1); 451 452 /* 453 Something fishy happens when assigning to tp_inst['hour_slider'] instead of tp_inst.hour_slider, I think 454 it is because it is assigned as a prototype. Clicking the slider will always change to the previous value 455 not the new one clicked. Ideally this works and reduces the 80+ lines of code above 456 // add the slider 457 tp_inst[litem+'_slider'] = $tp.find('.ui_tpicker_'+litem+'_slider').prop('slide', null).slider({ 458 orientation: "horizontal", 459 value: tp_inst[litem], 460 min: o[litem+'Min'], 461 max: max[litem], 462 step: o['step'+uitem], 463 slide: function(event, ui) { 464 tp_inst[litem+'_slider'].slider("option", "value", ui.value); 465 tp_inst._onTimeChange(); 466 }, 467 stop: function(event, ui) { 468 //Emulate datepicker onSelect behavior. Call on slidestop. 469 tp_inst._onSelectHandler(); 470 } 471 });
472 */ 473 474 // adjust the grid and add click event 475 if(o['show'+uitem] && o[litem+'Grid'] > 0) { 476 size = 100 * gridSize[litem] * o[litem+'Grid'] / (max[litem] - o[litem+'Min']); 477 $tp.find('.ui_tpicker_'+litem+' table').css({ 478 width: size + "%", 479 marginLeft: (size / (-2 * gridSize[litem])) + "%", 480 borderCollapse: 'collapse' 481 }).find("td").click(function(e){ 482 var $t = $(this), 483 h = $t.html(), 484 f = $t.data('for'); // loses scope, so we use data-for 485 486 if(f == 'hour' && o.ampm) { 487 var ap = h.substring(2).toLowerCase(), 488 aph = parseInt(h.substring(0, 2), 10); 489 if(ap == 'a') { 490 if(aph == 12) { 491 h = 0; 492 } else { 493 h = aph; 494 } 495 } else if(aph == 12) { 496 h = 12; 497 } else { 498 h = aph + 12; 499 } 500 } 501 tp_inst[f+'_slider'].slider("option", "value", parseInt(h,10)); 502 tp_inst._onTimeChange(); 503 tp_inst._onSelectHandler(); 504 }) 505 .css({ 506 cursor: 'pointer', 507 width: (100 / gridSize[litem]) + '%', 508 textAlign: 'center', 509 overflow: 'hidden' 510 }); 511 } // end if grid > 0 512 } // end for loop 513 514 // Add timezone options 515 this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select"); 516 $.fn.append.apply(this.timezone_select, 517 $.map(o.timezoneList, function(val, idx) { 518 return $("<option />").val(typeof val == "object" ? val.value : val).text(typeof val == "object" ? val.label : val); 519 })); 520 if(typeof(this.timezone) != "undefined" && this.timezone !== null && this.timezone !== "") { 521 var local_date = new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12); 522 var local_timezone = $.timepicker.timeZoneOffsetString(local_date); 523 if(local_timezone == this.timezone) { 524 selectLocalTimeZone(tp_inst); 525 } else { 526 this.timezone_select.val(this.timezone); 527 } 528 } else { 529 if(typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") { 530 this.timezone_select.val(o.defaultTimezone); 531 } else { 532 selectLocalTimeZone(tp_inst); 533 } 534 } 535 this.timezone_select.change(function() {
vendor: 1,544 bytes, lines 536-578
536 tp_inst._defaults.useLocalTimezone = false; 537 tp_inst._onTimeChange(); 538 }); 539 // End timezone options 540 541 // inject timepicker into datepicker 542 var $buttonPanel = $dp.find('.ui-datepicker-buttonpane'); 543 if($buttonPanel.length) { 544 $buttonPanel.before($tp); 545 } else { 546 $dp.append($tp); 547 } 548 549 this.$timeObj = $tp.find('.ui_tpicker_time'); 550 551 if(this.inst !== null) { 552 var timeDefined = this.timeDefined; 553 this._onTimeChange(); 554 this.timeDefined = timeDefined; 555 } 556 557 // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/ 558 if(this._defaults.addSliderAccess) { 559 var sliderAccessArgs = this._defaults.sliderAccessArgs; 560 setTimeout(function() { // fix for inline mode 561 if($tp.find('.ui-slider-access').length === 0) { 562 $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs); 563 564 // fix any grids since sliders are shorter 565 var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true); 566 if(sliderAccessWidth) { 567 $tp.find('table:visible').each(function() { 568 var $g = $(this), 569 oldWidth = $g.outerWidth(), 570 oldMarginLeft = $g.css('marginLeft').toString().replace('%', ''), 571 newWidth = oldWidth - sliderAccessWidth, 572 newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%'; 573 574 $g.css({ 575 width: newWidth, 576 marginLeft: newMarginLeft 577 }); 578 });
579 } 580 } 581 }, 10); 582 } 583 // end slideAccess integration 584 585 } 586 }, 587 588 /* 589 * This function tries to limit the ability to go outside the 590 * min/max date range 591 */ 592 _limitMinMaxDateTime: function(dp_inst, adjustSliders) { 593 var o = this._defaults, 594 dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay); 595 596 if(!this._defaults.showTimepicker) { 597 return; 598 } // No time so nothing to check here 599 600 if($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) { 601 var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'), 602 minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0); 603 604 if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null) { 605 this.hourMinOriginal = o.hourMin; 606 this.minuteMinOriginal = o.minuteMin; 607 this.secondMinOriginal = o.secondMin; 608 this.millisecMinOriginal = o.millisecMin; 609 } 610 611 if(dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) { 612 this._defaults.hourMin = minDateTime.getHours(); 613 if(this.hour <= this._defaults.hourMin) { 614 this.hour = this._defaults.hourMin; 615 this._defaults.minuteMin = minDateTime.getMinutes(); 616 if(this.minute <= this._defaults.minuteMin) { 617 this.minute = this._defaults.minuteMin; 618 this._defaults.secondMin = minDateTime.getSeconds(); 619 if(this.second <= this._defaults.secondMin) { 620 this.second = this._defaults.secondMin; 621 this._defaults.millisecMin = minDateTime.getMilliseconds(); 622 } else { 623 if(this.millisec < this._defaults.millisecMin) { 624 this.millisec = this._defaults.millisecMin; 625 } 626 this._defaults.millisecMin = this.millisecMinOriginal; 627 } 628 } else { 629 this._defaults.secondMin = this.secondMinOriginal; 630 this._defaults.millisecMin = this.millisecMinOriginal; 631 } 632 } else { 633 this._defaults.minuteMin = this.minuteMinOriginal; 634 this._defaults.secondMin = this.secondMinOriginal; 635 this._defaults.millisecMin = this.millisecMinOriginal; 636 } 637 } else { 638 this._defaults.hourMin = this.hourMinOriginal; 639 this._defaults.minuteMin = this.minuteMinOriginal; 640 this._defaults.secondMin = this.secondMinOriginal; 641 this._defaults.millisecMin = this.millisecMinOriginal; 642 } 643 } 644 645 if($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) { 646 var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'), 647 maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0); 648 649 if(this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null) { 650 this.hourMaxOriginal = o.hourMax; 651 this.minuteMaxOriginal = o.minuteMax; 652 this.secondMaxOriginal = o.secondMax; 653 this.millisecMaxOriginal = o.millisecMax; 654 } 655 656 if(dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()) { 657 this._defaults.hourMax = maxDateTime.getHours(); 658 if(this.hour >= this._defaults.hourMax) { 659 this.hour = this._defaults.hourMax; 660 this._defaults.minuteMax = maxDateTime.getMinutes(); 661 if(this.minute >= this._defaults.minuteMax) { 662 this.minute = this._defaults.minuteMax; 663 this._defaults.secondMax = maxDateTime.getSeconds(); 664 } else if(this.second >= this._defaults.secondMax) { 665 this.second = this._defaults.secondMax; 666 this._defaults.millisecMax = maxDateTime.getMilliseconds(); 667 } else { 668 if(this.millisec > this._defaults.millisecMax) { 669 this.millisec = this._defaults.millisecMax; 670 } 671 this._defaults.millisecMax = this.millisecMaxOriginal; 672 } 673 } else { 674 this._defaults.minuteMax = this.minuteMaxOriginal; 675 this._defaults.secondMax = this.secondMaxOriginal; 676 this._defaults.millisecMax = this.millisecMaxOriginal; 677 } 678 } else { 679 this._defaults.hourMax = this.hourMaxOriginal; 680 this._defaults.minuteMax = this.minuteMaxOriginal; 681 this._defaults.secondMax = this.secondMaxOriginal; 682 this._defaults.millisecMax = this.millisecMaxOriginal; 683 } 684 } 685 686 if(adjustSliders !== undefined && adjustSliders === true) { 687 var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10), 688 minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10), 689 secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10), 690 millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10); 691 692 if(this.hour_slider) { 693 this.hour_slider.slider("option", { 694 min: this._defaults.hourMin, 695 max: hourMax 696 }).slider('value', this.hour); 697 } 698 if(this.minute_slider) { 699 this.minute_slider.slider("option", { 700 min: this._defaults.minuteMin, 701 max: minMax 702 }).slider('value', this.minute); 703 } 704 if(this.second_slider) { 705 this.second_slider.slider("option", { 706 min: this._defaults.secondMin, 707 max: secMax 708 }).slider('value', this.second); 709 } 710 if(this.millisec_slider) { 711 this.millisec_slider.slider("option", { 712 min: this._defaults.millisecMin, 713 max: millisecMax 714 }).slider('value', this.millisec); 715 } 716 } 717 718 }, 719 720 /* 721 * when a slider moves, set the internal time... 722 * on time change is also called when the time is updated in the text field 723 */ 724 _onTimeChange: function() { 725 var hour = (this.hour_slider) ? this.hour_slider.slider('value') : false, 726 minute = (this.minute_slider) ? this.minute_slider.slider('value') : false, 727 second = (this.second_slider) ? this.second_slider.slider('value') : false, 728 millisec = (this.millisec_slider) ? this.millisec_slider.slider('value') : false, 729 timezone = (this.timezone_select) ? this.timezone_select.val() : false, 730 o = this._defaults; 731 732 if(typeof(hour) == 'object') { 733 hour = false; 734 } 735 if(typeof(minute) == 'object') { 736 minute = false; 737 } 738 if(typeof(second) == 'object') { 739 second = false; 740 } 741 if(typeof(millisec) == 'object') { 742 millisec = false; 743 } 744 if(typeof(timezone) == 'object') { 745 timezone = false; 746 } 747 748 if(hour !== false) { 749 hour = parseInt(hour, 10); 750 } 751 if(minute !== false) { 752 minute = parseInt(minute, 10); 753 } 754 if(second !== false) { 755 second = parseInt(second, 10); 756 } 757 if(millisec !== false) { 758 millisec = parseInt(millisec, 10); 759 } 760 761 var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0]; 762 763 // If the update was done in the input field, the input field should not be updated. 764 // If the update was done using the sliders, update the input field. 765 var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || millisec != this.millisec 766 || (this.ampm.length > 0 && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) 767 || ((this.timezone === null && timezone != this.defaultTimezone) || (this.timezone !== null && timezone != this.timezone))); 768 769 if(hasChanged) { 770 771 if(hour !== false) { 772 this.hour = hour; 773 } 774 if(minute !== false) { 775 this.minute = minute; 776 } 777 if(second !== false) { 778 this.second = second; 779 } 780 if(millisec !== false) { 781 this.millisec = millisec;
782 } 783 if(timezone !== false) { 784 this.timezone = timezone; 785 } 786 787 if(!this.inst) { 788 this.inst = $.datepicker._getInst(this.$input[0]); 789 } 790 791 this._limitMinMaxDateTime(this.inst, true); 792 } 793 if(o.ampm) { 794 this.ampm = ampm; 795 } 796 797 //this._formatTime(); 798 this.formattedTime = $.datepicker.formatTime(this._defaults.timeFormat, this, this._defaults); 799 if(this.$timeObj) { 800 this.$timeObj.text(this.formattedTime + o.timeSuffix); 801 } 802 this.timeDefined = true; 803 if(hasChanged) { 804 this._updateDateTime(); 805 } 806 }, 807 808 /* 809 * call custom onSelect. 810 * bind to sliders slidestop, and grid click. 811 */ 812 _onSelectHandler: function() { 813 var onSelect = this._defaults.onSelect || this.inst.settings.onSelect; 814 var inputEl = this.$input ? this.$input[0] : null; 815 if(onSelect && inputEl) { 816 onSelect.apply(inputEl, [this.formattedDateTime, this]); 817 } 818 }, 819 820 /* 821 * left for any backwards compatibility 822 */ 823 _formatTime: function(time, format) { 824 time = time || { 825 hour: this.hour, 826 minute: this.minute, 827 second: this.second, 828 millisec: this.millisec, 829 ampm: this.ampm, 830 timezone: this.timezone 831 }; 832 var tmptime = (format || this._defaults.timeFormat).toString(); 833 834 tmptime = $.datepicker.formatTime(tmptime, time, this._defaults); 835 836 if(arguments.length) { 837 return tmptime; 838 } else { 839 this.formattedTime = tmptime; 840 } 841 }, 842 843 /* 844 * update our input with the new date time.. 845 */ 846 _updateDateTime: function(dp_inst) { 847 dp_inst = this.inst || dp_inst; 848 var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)), 849 dateFmt = $.datepicker._get(dp_inst, 'dateFormat'), 850 formatCfg = $.datepicker._getFormatConfig(dp_inst), 851 timeAvailable = dt !== null && this.timeDefined; 852 this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg); 853 var formattedDateTime = this.formattedDate; 854 855 /* 856 * remove following lines to force every changes in date picker to change the input value 857 * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker. 858 * If the user manually empty the value in the input field, the date picker will never change selected value. 859 */ 860 //if(dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) { 861 // return; 862 //} 863 864 if(this._defaults.timeOnly === true) { 865 formattedDateTime = this.formattedTime; 866 } else if(this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) { 867 formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix; 868 } 869 870 this.formattedDateTime = formattedDateTime; 871 872 if(!this._defaults.showTimepicker) { 873 this.$input.val(this.formattedDate); 874 } else if(this.$altInput && this._defaults.altFieldTimeOnly === true) { 875 this.$altInput.val(this.formattedTime); 876 this.$input.val(this.formattedDate); 877 } else if(this.$altInput) { 878 this.$input.val(formattedDateTime); 879 var altFormattedDateTime = '', 880 altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator, 881 altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix; 882 if(this._defaults.altFormat) altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg); 883 else altFormattedDateTime = this.formattedDate; 884 if(altFormattedDateTime) altFormattedDateTime += altSeparator; 885 if(this._defaults.altTimeFormat) altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix; 886 else altFormattedDateTime += this.formattedTime + altTimeSuffix; 887 this.$altInput.val(altFormattedDateTime); 888 } else { 889 this.$input.val(formattedDateTime); 890 } 891 892 this.$input.trigger("change"); 893 }, 894 895 _onFocus: function() { 896 if(!this.$input.val() && this._defaults.defaultValue) { 897 this.$input.val(this._defaults.defaultValue); 898 var inst = $.datepicker._getInst(this.$input.get(0)), 899 tp_inst = $.datepicker._get(inst, 'timepicker'); 900 if(tp_inst) {
vendor: 2,110 bytes, lines 901-990
901 if(tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { 902 try { 903 $.datepicker._updateDatepicker(inst); 904 } catch (err) { 905 $.datepicker.log(err); 906 } 907 } 908 } 909 } 910 } 911 912 }); 913 914 $.fn.extend({ 915 /* 916 * shorthand just to use timepicker.. 917 */ 918 timepicker: function(o) { 919 o = o || {}; 920 var tmp_args = Array.prototype.slice.call(arguments); 921 922 if(typeof o == 'object') { 923 tmp_args[0] = $.extend(o, { 924 timeOnly: true 925 }); 926 } 927 928 return $(this).each(function() { 929 $.fn.datetimepicker.apply($(this), tmp_args); 930 }); 931 }, 932 933 /* 934 * extend timepicker to datepicker 935 */ 936 datetimepicker: function(o) { 937 o = o || {}; 938 var tmp_args = arguments; 939 940 if(typeof(o) == 'string') { 941 if(o == 'getDate') { 942 return $.fn.datepicker.apply($(this[0]), tmp_args); 943 } else { 944 return this.each(function() { 945 var $t = $(this); 946 $t.datepicker.apply($t, tmp_args); 947 }); 948 } 949 } else { 950 return this.each(function() { 951 var $t = $(this); 952 $t.datepicker($.timepicker._newInst($t, o)._defaults); 953 }); 954 } 955 } 956 }); 957 958 /* 959 * Public Utility to parse date and time 960 */ 961 $.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) { 962 var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings); 963 if(parseRes.timeObj) { 964 var t = parseRes.timeObj; 965 parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec); 966 } 967 968 return parseRes.date; 969 }; 970 971 /* 972 * Public utility to parse time 973 */ 974 $.datepicker.parseTime = function(timeFormat, timeString, options) { 975 976 // pattern for standard and localized AM/PM markers 977 var getPatternAmpm = function(amNames, pmNames) { 978 var markers = []; 979 if(amNames) { 980 $.merge(markers, amNames); 981 } 982 if(pmNames) { 983 $.merge(markers, pmNames); 984 } 985 markers = $.map(markers, function(val) { 986 return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&'); 987 }); 988 return '(' + markers.join('|') + ')?'; 989 }; 990
991 // figure out position of time elements.. cause js cant do named captures 992 var getFormatPositions = function(timeFormat) { 993 var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z)/g), 994 orders = { 995 h: -1, 996 m: -1, 997 s: -1, 998 l: -1, 999 t: -1, 1000 z: -1 1001 }; 1002 1003 if(finds) { 1004 for (var i = 0; i < finds.length; i++) { 1005 if(orders[finds[i].toString().charAt(0)] == -1) { 1006 orders[finds[i].toString().charAt(0)] = i + 1; 1007 } 1008 } 1009 } 1010 return orders; 1011 }; 1012 1013 var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}); 1014 1015 var regstr = '^' + timeFormat.toString() 1016 .replace(/h{1,2}/ig, '(\\d?\\d)') 1017 .replace(/m{1,2}/ig, '(\\d?\\d)') 1018 .replace(/s{1,2}/ig, '(\\d?\\d)') 1019 .replace(/l{1}/ig, '(\\d?\\d?\\d)') 1020 .replace(/t{1,2}/ig, getPatternAmpm(o.amNames, o.pmNames)) 1021 .replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d|\\S+)?') 1022 .replace(/\s/g, '\\s?') + 1023 o.timeSuffix + '$', 1024 order = getFormatPositions(timeFormat), 1025 ampm = '', 1026 treg; 1027 1028 treg = timeString.match(new RegExp(regstr, 'i')); 1029 1030 var resTime = { 1031 hour: 0, 1032 minute: 0, 1033 second: 0, 1034 millisec: 0 1035 }; 1036 1037 if(treg) { 1038 if(order.t !== -1) { 1039 if(treg[order.t] === undefined || treg[order.t].length === 0) { 1040 ampm = ''; 1041 resTime.ampm = ''; 1042 } else { 1043 ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM'; 1044 resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0]; 1045 } 1046 } 1047 1048 if(order.h !== -1) { 1049 if(ampm == 'AM' && treg[order.h] == '12') { 1050 resTime.hour = 0; // 12am = 0 hour 1051 } else { 1052 if(ampm == 'PM' && treg[order.h] != '12') { 1053 resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12 1054 } else { 1055 resTime.hour = Number(treg[order.h]); 1056 } 1057 } 1058 } 1059 1060 if(order.m !== -1) { 1061 resTime.minute = Number(treg[order.m]); 1062 } 1063 if(order.s !== -1) { 1064 resTime.second = Number(treg[order.s]); 1065 } 1066 if(order.l !== -1) { 1067 resTime.millisec = Number(treg[order.l]); 1068 } 1069 if(order.z !== -1 && treg[order.z] !== undefined) { 1070 var tz = treg[order.z].toUpperCase(); 1071 switch (tz.length) { 1072 case 1: 1073 // Z 1074 tz = o.timezoneIso8601 ? 'Z' : '+0000'; 1075 break; 1076 case 5: 1077 // +hhmm 1078 if(o.timezoneIso8601) { 1079 tz = tz.substring(1) == '0000' ? 'Z' : tz.substring(0, 3) + ':' + tz.substring(3); 1080 } 1081 break; 1082 case 6: 1083 // +hh:mm 1084 if(!o.timezoneIso8601) { 1085 tz = tz == 'Z' || tz.substring(1) == '00:00' ? '+0000' : tz.replace(/:/, ''); 1086 } else { 1087 if(tz.substring(1) == '00:00') { 1088 tz = 'Z'; 1089 } 1090 } 1091 break; 1092 } 1093 resTime.timezone = tz; 1094 } 1095 1096 1097 return resTime; 1098 } 1099 1100 return false; 1101 }; 1102 1103 /* 1104 * Public utility to format the time 1105 * format = string format of the time 1106 * time = a {}, not a Date() for timezones 1107 * options = essentially the regional[].. amNames, pmNames, ampm 1108 */ 1109 $.datepicker.formatTime = function(format, time, options) { 1110 options = options || {}; 1111 options = $.extend({}, $.timepicker._defaults, options); 1112 time = $.extend({ 1113 hour: 0, 1114 minute: 0, 1115 second: 0, 1116 millisec: 0, 1117 timezone: '+0000' 1118 }, time); 1119 1120 var tmptime = format; 1121 var ampmName = options.amNames[0]; 1122 1123 var hour = parseInt(time.hour, 10); 1124 if(options.ampm) { 1125 if(hour > 11) { 1126 ampmName = options.pmNames[0]; 1127 if(hour > 12) { 1128 hour = hour % 12; 1129 } 1130 } 1131 if(hour === 0) { 1132 hour = 12; 1133 } 1134 } 1135 tmptime = tmptime.replace(/(?:hh?|mm?|ss?|[tT]{1,2}|[lz]|('.*?'|".*?"))/g, function(match) { 1136 switch (match.toLowerCase()) { 1137 case 'hh': 1138 return ('0' + hour).slice(-2); 1139 case 'h': 1140 return hour; 1141 case 'mm': 1142 return ('0' + time.minute).slice(-2); 1143 case 'm': 1144 return time.minute; 1145 case 'ss': 1146 return ('0' + time.second).slice(-2); 1147 case 's': 1148 return time.second; 1149 case 'l': 1150 return ('00' + time.millisec).slice(-3); 1151 case 'z': 1152 return time.timezone; 1153 case 't': 1154 case 'tt': 1155 if(options.ampm) { 1156 if(match.length == 1) { 1157 ampmName = ampmName.charAt(0);
1158 } 1159 return match.charAt(0) === 'T' ? ampmName.toUpperCase() : ampmName.toLowerCase(); 1160 } 1161 return ''; 1162 default: 1163 return match.replace(/\'/g, "") || "'"; 1164 } 1165 }); 1166 1167 tmptime = $.trim(tmptime); 1168 return tmptime; 1169 }; 1170 1171 /* 1172 * the bad hack :/ override datepicker so it doesnt close on select 1173 // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378 1174 */ 1175 $.datepicker._base_selectDate = $.datepicker._selectDate; 1176 $.datepicker._selectDate = function(id, dateStr) { 1177 var inst = this._getInst($(id)[0]), 1178 tp_inst = this._get(inst, 'timepicker'); 1179 1180 if(tp_inst) { 1181 tp_inst._limitMinMaxDateTime(inst, true); 1182 inst.inline = inst.stay_open = true; 1183 //This way the onSelect handler called from calendarpicker get the full dateTime 1184 this._base_selectDate(id, dateStr); 1185 inst.inline = inst.stay_open = false; 1186 this._notifyChange(inst); 1187 this._updateDatepicker(inst); 1188 } else { 1189 this._base_selectDate(id, dateStr); 1190 } 1191 }; 1192 1193 /* 1194 * second bad hack :/ override datepicker so it triggers an event when changing the input field 1195 * and does not redraw the datepicker on every selectDate event 1196 */ 1197 $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker; 1198 $.datepicker._updateDatepicker = function(inst) { 1199 1200 // don't popup the datepicker if there is another instance already opened 1201 var input = inst.input[0]; 1202 if($.datepicker._curInst && $.datepicker._curInst != inst && $.datepicker._datepickerShowing && $.datepicker._lastInput != input) { 1203 return; 1204 } 1205 1206 if(typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) { 1207 1208 this._base_updateDatepicker(inst); 1209 1210 // Reload the time control when changing something in the input text field. 1211 var tp_inst = this._get(inst, 'timepicker'); 1212 if(tp_inst) { 1213 tp_inst._addTimePicker(inst); 1214
vendor: 2,013 bytes, lines 1215-1265
1215 if(tp_inst._defaults.useLocalTimezone) { //checks daylight saving with the new date. 1216 var date = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay, 12); 1217 selectLocalTimeZone(tp_inst, date); 1218 tp_inst._onTimeChange(); 1219 } 1220 } 1221 } 1222 }; 1223 1224 /* 1225 * third bad hack :/ override datepicker so it allows spaces and colon in the input field 1226 */ 1227 $.datepicker._base_doKeyPress = $.datepicker._doKeyPress; 1228 $.datepicker._doKeyPress = function(event) { 1229 var inst = $.datepicker._getInst(event.target), 1230 tp_inst = $.datepicker._get(inst, 'timepicker'); 1231 1232 if(tp_inst) { 1233 if($.datepicker._get(inst, 'constrainInput')) { 1234 var ampm = tp_inst._defaults.ampm, 1235 dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')), 1236 datetimeChars = tp_inst._defaults.timeFormat.toString() 1237 .replace(/[hms]/g, '') 1238 .replace(/TT/g, ampm ? 'APM' : '') 1239 .replace(/Tt/g, ampm ? 'AaPpMm' : '') 1240 .replace(/tT/g, ampm ? 'AaPpMm' : '') 1241 .replace(/T/g, ampm ? 'AP' : '') 1242 .replace(/tt/g, ampm ? 'apm' : '') 1243 .replace(/t/g, ampm ? 'ap' : '') + 1244 " " + tp_inst._defaults.separator + 1245 tp_inst._defaults.timeSuffix + 1246 (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') + 1247 (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) + 1248 dateChars, 1249 chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode); 1250 return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1); 1251 } 1252 } 1253 1254 return $.datepicker._base_doKeyPress(event); 1255 }; 1256 1257 /* 1258 * Override key up event to sync manual input changes. 1259 */ 1260 $.datepicker._base_doKeyUp = $.datepicker._doKeyUp; 1261 $.datepicker._doKeyUp = function(event) { 1262 var inst = $.datepicker._getInst(event.target), 1263 tp_inst = $.datepicker._get(inst, 'timepicker'); 1264 1265 if(tp_inst) {
1266 if(tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { 1267 try { 1268 $.datepicker._updateDatepicker(inst); 1269 } catch (err) { 1270 $.datepicker.log(err); 1271 } 1272 } 1273 } 1274 1275 return $.datepicker._base_doKeyUp(event); 1276 }; 1277 1278 /* 1279 * override "Today" button to also grab the time. 1280 */ 1281 $.datepicker._base_gotoToday = $.datepicker._gotoToday; 1282 $.datepicker._gotoToday = function(id) { 1283 var inst = this._getInst($(id)[0]), 1284 $dp = inst.dpDiv; 1285 this._base_gotoToday(id); 1286 var tp_inst = this._get(inst, 'timepicker'); 1287 selectLocalTimeZone(tp_inst); 1288 var now = new Date(); 1289 this._setTime(inst, now); 1290 $('.ui-datepicker-today', $dp).click(); 1291 }; 1292 1293 /* 1294 * Disable & enable the Time in the datetimepicker 1295 */ 1296 $.datepicker._disableTimepickerDatepicker = function(target) { 1297 var inst = this._getInst(target); 1298 if(!inst) { 1299 return; 1300 } 1301 1302 var tp_inst = this._get(inst, 'timepicker'); 1303 $(target).datepicker('getDate'); // Init selected[Year|Month|Day] 1304 if(tp_inst) { 1305 tp_inst._defaults.showTimepicker = false; 1306 tp_inst._updateDateTime(inst); 1307 } 1308 }; 1309 1310 $.datepicker._enableTimepickerDatepicker = function(target) { 1311 var inst = this._getInst(target); 1312 if(!inst) { 1313 return; 1314 } 1315 1316 var tp_inst = this._get(inst, 'timepicker'); 1317 $(target).datepicker('getDate'); // Init selected[Year|Month|Day] 1318 if(tp_inst) { 1319 tp_inst._defaults.showTimepicker = true; 1320 tp_inst._addTimePicker(inst); // Could be disabled on page load 1321 tp_inst._updateDateTime(inst); 1322 } 1323 }; 1324 1325 /* 1326 * Create our own set time function 1327 */ 1328 $.datepicker._setTime = function(inst, date) { 1329 var tp_inst = this._get(inst, 'timepicker'); 1330 if(tp_inst) { 1331 var defaults = tp_inst._defaults, 1332 // calling _setTime with no date sets time to defaults 1333 hour = date ? date.getHours() : defaults.hour, 1334 minute = date ? date.getMinutes() : defaults.minute, 1335 second = date ? date.getSeconds() : defaults.second, 1336 millisec = date ? date.getMilliseconds() : defaults.millisec; 1337 //check if within min/max times.. 1338 // correct check if within min/max times. 1339 // Rewritten by Scott A. Woodward 1340 var hourEq = hour === defaults.hourMin, 1341 minuteEq = minute === defaults.minuteMin, 1342 secondEq = second === defaults.secondMin; 1343 var reset = false; 1344 if(hour < defaults.hourMin || hour > defaults.hourMax) reset = true; 1345 else if((minute < defaults.minuteMin || minute > defaults.minuteMax) && hourEq) reset = true; 1346 else if((second < defaults.secondMin || second > defaults.secondMax) && hourEq && minuteEq) reset = true; 1347 else if((millisec < defaults.millisecMin || millisec > defaults.millisecMax) && hourEq && minuteEq && secondEq) reset = true; 1348 if(reset) { 1349 hour = defaults.hourMin; 1350 minute = defaults.minuteMin; 1351 second = defaults.secondMin; 1352 millisec = defaults.millisecMin; 1353 } 1354 tp_inst.hour = hour; 1355 tp_inst.minute = minute; 1356 tp_inst.second = second; 1357 tp_inst.millisec = millisec; 1358 if(tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour); 1359 if(tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute); 1360 if(tp_inst.second_slider) tp_inst.second_slider.slider('value', second); 1361 if(tp_inst.millisec_slider) tp_inst.millisec_slider.slider('value', millisec); 1362 1363 tp_inst._onTimeChange(); 1364 tp_inst._updateDateTime(inst); 1365 } 1366 }; 1367 1368 /* 1369 * Create new public method to set only time, callable as $().datepicker('setTime', date) 1370 */ 1371 $.datepicker._setTimeDatepicker = function(target, date, withDate) { 1372 var inst = this._getInst(target); 1373 if(!inst) { 1374 return; 1375 } 1376 1377 var tp_inst = this._get(inst, 'timepicker'); 1378 1379 if(tp_inst) { 1380 this._setDateFromField(inst); 1381 var tp_date; 1382 if(date) { 1383 if(typeof date == "string") { 1384 tp_inst._parseTime(date, withDate); 1385 tp_date = new Date(); 1386 tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); 1387 } else { 1388 tp_date = new Date(date.getTime()); 1389 } 1390 if(tp_date.toString() == 'Invalid Date') { 1391 tp_date = undefined; 1392 } 1393 this._setTime(inst, tp_date); 1394 } 1395 } 1396 1397 }; 1398 1399 /* 1400 * override setDate() to allow setting time too within Date object 1401 */ 1402 $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker; 1403 $.datepicker._setDateDatepicker = function(target, date) { 1404 var inst = this._getInst(target); 1405 if(!inst) { 1406 return; 1407 } 1408 1409 var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date; 1410 1411 this._updateDatepicker(inst); 1412 this._base_setDateDatepicker.apply(this, arguments); 1413 this._setTimeDatepicker(target, tp_date, true); 1414 }; 1415 1416 /* 1417 * override getDate() to allow getting time too within Date object 1418 */ 1419 $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker; 1420 $.datepicker._getDateDatepicker = function(target, noDefault) { 1421 var inst = this._getInst(target); 1422 if(!inst) { 1423 return; 1424 } 1425 1426 var tp_inst = this._get(inst, 'timepicker'); 1427 1428 if(tp_inst) { 1429 //this._setDateFromField(inst, noDefault); // This keeps setting to today when it shouldn't 1430 var date = this._getDate(inst); 1431 if(date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
1432 date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); 1433 } 1434 return date; 1435 } 1436 return this._base_getDateDatepicker(target, noDefault); 1437 }; 1438 1439 /* 1440 * override parseDate() because UI 1.8.14 throws an error about "Extra characters" 1441 * An option in datapicker to ignore extra format characters would be nicer. 1442 */ 1443 $.datepicker._base_parseDate = $.datepicker.parseDate; 1444 $.datepicker.parseDate = function(format, value, settings) { 1445 var splitRes = splitDateTime(format, value, settings); 1446 return $.datepicker._base_parseDate(format, splitRes[0], settings); 1447 }; 1448 1449 /* 1450 * override formatDate to set date with time to the input 1451 */ 1452 $.datepicker._base_formatDate = $.datepicker._formatDate; 1453 $.datepicker._formatDate = function(inst, day, month, year) { 1454 var tp_inst = this._get(inst, 'timepicker'); 1455 if(tp_inst) { 1456 tp_inst._updateDateTime(inst); 1457 return tp_inst.$input.val(); 1458 } 1459 return this._base_formatDate(inst); 1460 }; 1461 1462 /* 1463 * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate 1464 */ 1465 $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker; 1466 $.datepicker._optionDatepicker = function(target, name, value) { 1467 var inst = this._getInst(target); 1468 if(!inst) { 1469 return null; 1470 } 1471 1472 var tp_inst = this._get(inst, 'timepicker'); 1473 if(tp_inst) { 1474 var min = null, 1475 max = null, 1476 onselect = null; 1477 if(typeof name == 'string') { // if min/max was set with the string 1478 if(name === 'minDate' || name === 'minDateTime') { 1479 min = value; 1480 } else { 1481 if(name === 'maxDate' || name === 'maxDateTime') { 1482 max = value; 1483 } else { 1484 if(name === 'onSelect') { 1485 onselect = value; 1486 } 1487 } 1488 } 1489 } else { 1490 if(typeof name == 'object') { //if min/max was set with the JSON 1491 if(name.minDate) { 1492 min = name.minDate; 1493 } else { 1494 if(name.minDateTime) { 1495 min = name.minDateTime; 1496 } else { 1497 if(name.maxDate) { 1498 max = name.maxDate; 1499 } else { 1500 if(name.maxDateTime) { 1501 max = name.maxDateTime; 1502 } 1503 } 1504 } 1505 } 1506 } 1507 } 1508 if(min) { //if min was set 1509 if(min === 0) { 1510 min = new Date(); 1511 } else { 1512 min = new Date(min); 1513 } 1514 1515 tp_inst._defaults.minDate = min; 1516 tp_inst._defaults.minDateTime = min; 1517 } else if(max) { //if max was set 1518 if(max === 0) { 1519 max = new Date(); 1520 } else { 1521 max = new Date(max); 1522 } 1523 tp_inst._defaults.maxDate = max; 1524 tp_inst._defaults.maxDateTime = max; 1525 } else if(onselect) { 1526 tp_inst._defaults.onSelect = onselect; 1527 } 1528 } 1529 if(value === undefined) { 1530 return this._base_optionDatepicker(target, name); 1531 } 1532 return this._base_optionDatepicker(target, name, value); 1533 }; 1534 1535 /* 1536 * jQuery extend now ignores nulls! 1537 */ 1538 function extendRemove(target, props) { 1539 $.extend(target, props); 1540 for (var name in props) { 1541 if(props[name] === null || props[name] === undefined) { 1542 target[name] = props[name]; 1543 } 1544 } 1545 return target; 1546 } 1547 1548 /* 1549 * Splits datetime string into date ans time substrings. 1550 * Throws exception when date can't be parsed 1551 * Returns [dateString, timeString] 1552 */ 1553 var splitDateTime = function(dateFormat, dateTimeString, dateSettings, timeSettings) { 1554 try { 1555 // The idea is to get the number separator occurances in datetime and the time format requested (since time has 1556 // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split. 1557 var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator, 1558 format = timeSettings && timeSettings.timeFormat ? timeSettings.timeFormat : $.timepicker._defaults.timeFormat, 1559 ampm = timeSettings && timeSettings.ampm ? timeSettings.ampm : $.timepicker._defaults.ampm, 1560 timeParts = format.split(separator), // how many occurances of separator may be in our format? 1561 timePartsLen = timeParts.length, 1562 allParts = dateTimeString.split(separator), 1563 allPartsLen = allParts.length; 1564 1565 // because our default ampm=false, but our default format has tt, we need to filter this out 1566 if(!ampm){ 1567 timeParts = $.trim(format.replace(/t/gi,'')).split(separator); 1568 timePartsLen = timeParts.length; 1569 } 1570 1571 if(allPartsLen > 0) { 1572 return [ 1573 allParts.splice(0,allPartsLen-timePartsLen).join(separator), 1574 allParts.splice(timePartsLen*-1).join(separator) 1575 ]; 1576 } 1577 1578 } catch (err) { 1579 if(err.indexOf(":") >= 0) { 1580 // Hack! The error message ends with a colon, a space, and 1581 // the "extra" characters. We rely on that instead of 1582 // attempting to perfectly reproduce the parsing algorithm. 1583 var dateStringLength = dateTimeString.length - (err.length - err.indexOf(':') - 2), 1584 timeString = dateTimeString.substring(dateStringLength); 1585 1586 return [$.trim(dateTimeString.substring(0, dateStringLength)), $.trim(dateTimeString.substring(dateStringLength))]; 1587 1588 } else { 1589 throw err; 1590 } 1591 } 1592 return [dateTimeString, '']; 1593 }; 1594 1595 /* 1596 * Internal function to parse datetime interval 1597 * Returns: {date: Date, timeObj: Object}, where 1598 * date - parsed date without time (type Date) 1599 * timeObj = {hour:, minute:, second:, millisec: } - parsed time. Optional 1600 */ 1601 var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) { 1602 var date; 1603 var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings, timeSettings); 1604 date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings); 1605 if(splitRes[1] !== '') { 1606 var timeString = splitRes[1], 1607 parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings); 1608 1609 if(parsedTime === null) { 1610 throw 'Wrong time format'; 1611 } 1612 return { 1613 date: date, 1614 timeObj: parsedTime 1615 }; 1616 } else { 1617 return { 1618 date: date 1619 }; 1620 } 1621 }; 1622 1623 /* 1624 * Internal function to set timezone_select to the local timezone 1625 */ 1626 var selectLocalTimeZone = function(tp_inst, date) { 1627 if(tp_inst && tp_inst.timezone_select) {
1628 tp_inst._defaults.useLocalTimezone = true; 1629 var now = typeof date !== 'undefined' ? date : new Date(); 1630 var tzoffset = $.timepicker.timeZoneOffsetString(now); 1631 if(tp_inst._defaults.timezoneIso8601) { 1632 tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3); 1633 } 1634 tp_inst.timezone_select.val(tzoffset); 1635 } 1636 }; 1637 1638 /* 1639 * Create a Singleton Insance 1640 */ 1641 $.timepicker = new Timepicker(); 1642 1643 /** 1644 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5) 1645 * @param date 1646 * @return string 1647 */ 1648 $.timepicker.timeZoneOffsetString = function(date) { 1649 var off = date.getTimezoneOffset() * -1, 1650 minutes = off % 60, 1651 hours = (off - minutes) / 60; 1652 return (off >= 0 ? '+' : '-') + ('0' + (hours * 101).toString()).substr(-2) + ('0' + (minutes * 101).toString()).substr(-2); 1653 }; 1654 1655 /** 1656 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to 1657 * enforce date range limits. 1658 * n.b. The input value must be correctly formatted (reformatting is not supported) 1659 * @param Element startTime 1660 * @param Element endTime 1661 * @param obj options Options for the timepicker() call 1662 * @return jQuery 1663 */ 1664 $.timepicker.timeRange = function(startTime, endTime, options) { 1665 return $.timepicker.handleRange('timepicker', startTime, endTime, options); 1666 }; 1667 1668 /** 1669 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to 1670 * enforce date range limits. 1671 * @param Element startTime 1672 * @param Element endTime 1673 * @param obj options Options for the `timepicker()` call. Also supports `reformat`, 1674 * a boolean value that can be used to reformat the input values to the `dateFormat`. 1675 * @param string method Can be used to specify the type of picker to be added 1676 * @return jQuery 1677 */ 1678 $.timepicker.dateTimeRange = function(startTime, endTime, options) { 1679 $.timepicker.dateRange(startTime, endTime, options, 'datetimepicker'); 1680 }; 1681 1682 /** 1683 * Calls `method` on the `startTime` and `endTime` elements, and configures them to 1684 * enforce date range limits. 1685 * @param Element startTime 1686 * @param Element endTime 1687 * @param obj options Options for the `timepicker()` call. Also supports `reformat`, 1688 * a boolean value that can be used to reformat the input values to the `dateFormat`. 1689 * @param string method Can be used to specify the type of picker to be added 1690 * @return jQuery 1691 */ 1692 $.timepicker.dateRange = function(startTime, endTime, options, method) { 1693 method = method || 'datepicker'; 1694 $.timepicker.handleRange(method, startTime, endTime, options); 1695 }; 1696 1697 /** 1698 * Calls `method` on the `startTime` and `endTime` elements, and configures them to 1699 * enforce date range limits. 1700 * @param string method Can be used to specify the type of picker to be added 1701 * @param Element startTime 1702 * @param Element endTime 1703 * @param obj options Options for the `timepicker()` call. Also supports `reformat`, 1704 * a boolean value that can be used to reformat the input values to the `dateFormat`. 1705 * @return jQuery 1706 */ 1707 $.timepicker.handleRange = function(method, startTime, endTime, options) { 1708 $.fn[method].call(startTime, $.extend({ 1709 onClose: function(dateText, inst) { 1710 checkDates(this, endTime, dateText); 1711 }, 1712 onSelect: function(selectedDateTime) { 1713 selected(this, endTime, 'minDate'); 1714 } 1715 }, options, options.start)); 1716 $.fn[method].call(endTime, $.extend({ 1717 onClose: function(dateText, inst) { 1718 checkDates(this, startTime, dateText); 1719 }, 1720 onSelect: function(selectedDateTime) { 1721 selected(this, startTime, 'maxDate'); 1722 } 1723 }, options, options.end)); 1724 // timepicker doesn't provide access to its 'timeFormat' option, 1725 // nor could I get datepicker.formatTime() to behave with times, so I 1726 // have disabled reformatting for timepicker 1727 if(method != 'timepicker' && options.reformat) { 1728 $([startTime, endTime]).each(function() { 1729 var format = $(this)[method].call($(this), 'option', 'dateFormat'), 1730 date = new Date($(this).val()); 1731 if($(this).val() && date) { 1732 $(this).val($.datepicker.formatDate(format, date)); 1733 } 1734 }); 1735 } 1736 checkDates(startTime, endTime, startTime.val()); 1737 1738 function checkDates(changed, other, dateText) { 1739 if(other.val() && (new Date(startTime.val()) > new Date(endTime.val()))) { 1740 other.val(dateText); 1741 } 1742 } 1743 selected(startTime, endTime, 'minDate'); 1744 selected(endTime, startTime, 'maxDate'); 1745 1746 function selected(changed, other, option) { 1747 if(!$(changed).val()) { 1748 return; 1749 } 1750 var date = $(changed)[method].call($(changed), 'getDate'); 1751 // timepicker doesn't implement 'getDate' and returns a jQuery 1752 if(date.getTime) { 1753 $(other)[method].call($(other), 'option', option, date); 1754 } 1755 } 1756 return $([startTime.get(0), endTime.get(0)]); 1757 }; 1758 1759 /* 1760 * Keep up with the version 1761 */ 1762 $.timepicker.version = "1.0.3"; 1763 1764})(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.