1/*! version : 4.14.30 2 ========================================================= 3 bootstrap-datetimejs 4 https://github.com/Eonasdan/bootstrap-datetimepicker 5 Copyright (c) 2015 Jonathan Peterson 6 ========================================================= 7 */ 8/* 9 The MIT License (MIT) 10 11 Copyright (c) 2015 Jonathan Peterson 12 13 Permission is hereby granted, free of charge, to any person obtaining a copy 14 of this software and associated documentation files (the "Software"), to deal 15 in the Software without restriction, including without limitation the rights 16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 copies of the Software, and to permit persons to whom the Software is 18 furnished to do so, subject to the following conditions: 19 20 The above copyright notice and this permission notice shall be included in 21 all copies or substantial portions of the Software. 22 23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 THE SOFTWARE. 30 */ 31/*global define:false */ 32/*global exports:false */ 33/*global require:false */ 34/*global jQuery:false */ 35/*global moment:false */ 36(function (factory) { 37 'use strict'; 38 if (typeof define === 'function' && define.amd) { 39 // AMD is used - Register as an anonymous module. 40 define(['jquery', 'moment'], factory); 41 } else if (typeof exports === 'object') { 42 factory(require('jquery'), require('moment')); 43 } else { 44 // Neither AMD nor CommonJS used. Use global variables. 45 if (typeof jQuery === 'undefined') { 46 throw 'bootstrap-datetimepicker requires jQuery to be loaded first'; 47 } 48 if (typeof moment === 'undefined') { 49 throw 'bootstrap-datetimepicker requires Moment.js to be loaded first'; 50 } 51 factory(jQuery, moment); 52 } 53}(function ($, moment) { 54 'use strict'; 55 if (!moment) { 56 throw new Error('bootstrap-datetimepicker requires Moment.js to be loaded first'); 57 } 58 59 var dateTimePicker = function (element, options) { 60 var picker = {}, 61 date = moment().startOf('d'), 62 viewDate = date.clone(), 63 unset = true, 64 input, 65 component = false, 66 widget = false, 67 use24Hours, 68 minViewModeNumber = 0, 69 actualFormat, 70 parseFormats, 71 currentViewMode, 72 datePickerModes = [ 73 { 74 clsName: 'days', 75 navFnc: 'M', 76 navStep: 1 77 }, 78 { 79 clsName: 'months', 80 navFnc: 'y', 81 navStep: 1 82 }, 83 { 84 clsName: 'years', 85 navFnc: 'y', 86 navStep: 10 87 }, 88 { 89 clsName: 'decades', 90 navFnc: 'y', 91 navStep: 100 92 } 93 ], 94 viewModes = ['days', 'months', 'years', 'decades'], 95 verticalModes = ['top', 'bottom', 'auto'], 96 horizontalModes = ['left', 'right', 'auto'], 97 toolbarPlacements = ['default', 'top', 'bottom'], 98 keyMap = { 99 'up': 38, 100 38: 'up', 101 'down': 40, 102 40: 'down', 103 'left': 37, 104 37: 'left', 105 'right': 39, 106 39: 'right', 107 'tab': 9, 108 9: 'tab', 109 'escape': 27, 110 27: 'escape', 111 'enter': 13, 112 13: 'enter', 113 'pageUp': 33, 114 33: 'pageUp', 115 'pageDown': 34, 116 34: 'pageDown', 117 'shift': 16, 118 16: 'shift', 119 'control': 17, 120 17: 'control', 121 'space': 32, 122 32: 'space', 123 't': 84, 124 84: 't', 125 'delete': 46, 126 46: 'delete' 127 }, 128 keyState = {}, 129 130 /******************************************************************************** 131 * 132 * Private functions 133 * 134 ********************************************************************************/ 135 isEnabled = function (granularity) { 136 if (typeof granularity !== 'string' || granularity.length > 1) { 137 throw new TypeError('isEnabled expects a single character string parameter'); 138 } 139 switch (granularity) { 140 case 'y': 141 return actualFormat.indexOf('Y') !== -1; 142 case 'M': 143 return actualFormat.indexOf('M') !== -1; 144 case 'd': 145 return actualFormat.toLowerCase().indexOf('d') !== -1; 146 case 'h': 147 case 'H': 148 return actualFormat.toLowerCase().indexOf('h') !== -1; 149 case 'm': 150 return actualFormat.indexOf('m') !== -1; 151 case 's': 152 return actualFormat.indexOf('s') !== -1; 153 default: 154 return false;
155 } 156 }, 157 hasTime = function () { 158 return (isEnabled('h') || isEnabled('m') || isEnabled('s')); 159 }, 160 161 hasDate = function () { 162 return (isEnabled('y') || isEnabled('M') || isEnabled('d')); 163 }, 164 165 getDatePickerTemplate = function () { 166 var headTemplate = $('<thead>') 167 .append($('<tr>') 168 .append($('<th>').addClass('prev').attr('data-action', 'previous') 169 .append($('<span>').addClass(options.icons.previous)) 170 ) 171 .append($('<th>').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5'))) 172 .append($('<th>').addClass('next').attr('data-action', 'next') 173 .append($('<span>').addClass(options.icons.next)) 174 ) 175 ), 176 contTemplate = $('<tbody>') 177 .append($('<tr>') 178 .append($('<td>').attr('colspan', (options.calendarWeeks ? '8' : '7'))) 179 ); 180 181 return [ 182 $('<div>').addClass('datepicker-days') 183 .append($('<table>').addClass('table-condensed') 184 .append(headTemplate) 185 .append($('<tbody>')) 186 ), 187 $('<div>').addClass('datepicker-months') 188 .append($('<table>').addClass('table-condensed') 189 .append(headTemplate.clone()) 190 .append(contTemplate.clone()) 191 ), 192 $('<div>').addClass('datepicker-years') 193 .append($('<table>').addClass('table-condensed') 194 .append(headTemplate.clone()) 195 .append(contTemplate.clone()) 196 ), 197 $('<div>').addClass('datepicker-decades') 198 .append($('<table>').addClass('table-condensed') 199 .append(headTemplate.clone()) 200 .append(contTemplate.clone()) 201 ) 202 ]; 203 }, 204 205 getTimePickerMainTemplate = function () { 206 var topRow = $('<tr>'), 207 middleRow = $('<tr>'), 208 bottomRow = $('<tr>'); 209 210 if (isEnabled('h')) { 211 topRow.append($('<td>') 212 .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Increment Hour'}).addClass('btn').attr('data-action', 'incrementHours') 213 .append($('<span>').addClass(options.icons.up)))); 214 middleRow.append($('<td>') 215 .append($('<span>').addClass('timepicker-hour').attr({'data-time-component':'hours', 'title':'Pick Hour'}).attr('data-action', 'showHours'))); 216 bottomRow.append($('<td>') 217 .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Decrement Hour'}).addClass('btn').attr('data-action', 'decrementHours') 218 .append($('<span>').addClass(options.icons.down)))); 219 } 220 if (isEnabled('m')) { 221 if (isEnabled('h')) { 222 topRow.append($('<td>').addClass('separator')); 223 middleRow.append($('<td>').addClass('separator').html(':')); 224 bottomRow.append($('<td>').addClass('separator')); 225 } 226 topRow.append($('<td>') 227 .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Increment Minute'}).addClass('btn').attr('data-action', 'incrementMinutes') 228 .append($('<span>').addClass(options.icons.up)))); 229 middleRow.append($('<td>') 230 .append($('<span>').addClass('timepicker-minute').attr({'data-time-component': 'minutes', 'title':'Pick Minute'}).attr('data-action', 'showMinutes'))); 231 bottomRow.append($('<td>') 232 .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Decrement Minute'}).addClass('btn').attr('data-action', 'decrementMinutes') 233 .append($('<span>').addClass(options.icons.down)))); 234 } 235 if (isEnabled('s')) { 236 if (isEnabled('m')) { 237 topRow.append($('<td>').addClass('separator')); 238 middleRow.append($('<td>').addClass('separator').html(':')); 239 bottomRow.append($('<td>').addClass('separator')); 240 } 241 topRow.append($('<td>') 242 .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Increment Second'}).addClass('btn').attr('data-action', 'incrementSeconds') 243 .append($('<span>').addClass(options.icons.up)))); 244 middleRow.append($('<td>') 245 .append($('<span>
245').addClass('timepicker-second').attr({'data-time-component': 'seconds', 'title':'Pick Second'}).attr('data-action', 'showSeconds'))); 246 bottomRow.append($('<td>') 247 .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Decrement Second'}).addClass('btn').attr('data-action', 'decrementSeconds') 248 .append($('<span>').addClass(options.icons.down)))); 249 } 250 251 if (!use24Hours) { 252 topRow.append($('<td>').addClass('separator')); 253 middleRow.append($('<td>') 254 .append($('<button>').addClass('btn btn-primary').attr({'data-action': 'togglePeriod', tabindex: '-1', 'title':'Toggle Period'}))); 255 bottomRow.append($('<td>').addClass('separator')); 256 } 257 258 return $('<div>').addClass('timepicker-picker') 259 .append($('<table>').addClass('table-condensed') 260 .append([topRow, middleRow, bottomRow])); 261 }, 262 263 getTimePickerTemplate = function () { 264 var hoursView = $('<div>').addClass('timepicker-hours') 265 .append($('<table>').addClass('table-condensed')), 266 minutesView = $('<div>').addClass('timepicker-minutes') 267 .append($('<table>').addClass('table-condensed')), 268 secondsView = $('<div>').addClass('timepicker-seconds') 269 .append($('<table>').addClass('table-condensed')), 270 ret = [getTimePickerMainTemplate()]; 271 272 if (isEnabled('h')) { 273 ret.push(hoursView); 274 } 275 if (isEnabled('m')) { 276 ret.push(minutesView); 277 } 278 if (isEnabled('s')) { 279 ret.push(secondsView); 280 } 281 282 return ret; 283 }, 284 285 getToolbar = function () { 286 var row = []; 287 if (options.showTodayButton) { 288 row.push($('<td>').append($('<a>').attr({'data-action':'today', 'title':'Go to today'}).append($('<span>').addClass(options.icons.today)))); 289 } 290 if (!options.sideBySide && hasDate() && hasTime()) { 291 row.push($('<td>').append($('<a>').attr({'data-action':'togglePicker', 'title':'Select Time'}).append($('<span>').addClass(options.icons.time)))); 292 } 293 if (options.showClear) { 294 row.push($('<td>').append($('<a>').attr({'data-action':'clear', 'title':'Clear selection'}).append($('<span>').addClass(options.icons.clear)))); 295 } 296 if (options.showClose) { 297 row.push($('<td>').append($('<a>').attr({'data-action':'close', 'title':'Close the picker'}).append($('<span>').addClass(options.icons.close)))); 298 } 299 return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row))); 300 }, 301 302 getTemplate = function () { 303 var template = $('<div>').addClass('bootstrap-datetimepicker-widget dropdown-menu'), 304 dateView = $('<div>').addClass('datepicker').append(getDatePickerTemplate()), 305 timeView = $('<div>').addClass('timepicker').append(getTimePickerTemplate()), 306 content = $('<ul>').addClass('list-unstyled'), 307 toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar()); 308 309 if (options.inline) { 310 template.removeClass('dropdown-menu'); 311 } 312 313 if (use24Hours) { 314 template.addClass('usetwentyfour'); 315 } 316 if (isEnabled('s') && !use24Hours) { 317 template.addClass('wider'); 318 } 319 if (options.sideBySide && hasDate() && hasTime()) { 320 template.addClass('timepicker-sbs'); 321 template.append( 322 $('<div>').addClass('row') 323 .append(dateView.addClass('col-sm-6')) 324 .append(timeView.addClass('col-sm-6')) 325 ); 326 template.append(toolbar); 327 return template; 328 } 329 330 if (options.toolbarPlacement === 'top') { 331 content.append(toolbar); 332 } 333 if (hasDate()) { 334 content.append($('<li>').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView)); 335 } 336 if (options.toolbarPlacement === 'default') { 337 content.append(toolbar); 338 } 339 if (hasTime()) { 340 content.append($('<li>
340').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView)); 341 } 342 if (options.toolbarPlacement === 'bottom') { 343 content.append(toolbar); 344 } 345 return template.append(content); 346 }, 347 348 dataToOptions = function () { 349 var eData, 350 dataOptions = {}; 351 352 if (element.is('input') || options.inline) { 353 eData = element.data(); 354 } else { 355 eData = element.find('input').data(); 356 } 357 358 if (eData.dateOptions && eData.dateOptions instanceof Object) { 359 dataOptions = $.extend(true, dataOptions, eData.dateOptions); 360 } 361 362 $.each(options, function (key) { 363 var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1); 364 if (eData[attributeName] !== undefined) { 365 dataOptions[key] = eData[attributeName]; 366 } 367 }); 368 return dataOptions; 369 }, 370 371 place = function () { 372 var position = (component || element).position(), 373 offset = (component || element).offset(), 374 vertical = options.widgetPositioning.vertical, 375 horizontal = options.widgetPositioning.horizontal, 376 parent; 377 378 if (options.widgetParent) { 379 parent = options.widgetParent.append(widget); 380 } else if (element.is('input')) { 381 parent = element.after(widget).parent(); 382 } else if (options.inline) { 383 parent = element.append(widget); 384 return; 385 } else { 386 parent = element; 387 element.children().first().after(widget); 388 } 389 390 // Top and bottom logic 391 if (vertical === 'auto') { 392 if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() && 393 widget.height() + element.outerHeight() < offset.top) { 394 vertical = 'top'; 395 } else { 396 vertical = 'bottom'; 397 } 398 } 399 400 // Left and right logic 401 if (horizontal === 'auto') { 402 if (parent.width() < offset.left + widget.outerWidth() / 2 && 403 offset.left + widget.outerWidth() > $(window).width()) { 404 horizontal = 'right'; 405 } else { 406 horizontal = 'left'; 407 } 408 } 409 410 if (vertical === 'top') { 411 widget.addClass('top').removeClass('bottom'); 412 } else { 413 widget.addClass('bottom').removeClass('top'); 414 } 415 416 if (horizontal === 'right') { 417 widget.addClass('pull-right'); 418 } else { 419 widget.removeClass('pull-right'); 420 } 421 422 // find the first parent element that has a relative css positioning 423 if (parent.css('position') !== 'relative') { 424 parent = parent.parents().filter(function () { 425 return $(this).css('position') === 'relative'; 426 }).first(); 427 } 428 429 if (parent.length === 0) { 430 throw new Error('datetimepicker component should be placed within a relative positioned container'); 431 } 432 433 widget.css({ 434 top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(), 435 bottom: vertical === 'top' ? position.top + element.outerHeight() : 'auto', 436 left: horizontal === 'left' ? (parent === element ? 0 : position.left) : 'auto', 437 right: horizontal === 'left' ? 'auto' : parent.outerWidth() - element.outerWidth() - (parent === element ? 0 : position.left) 438 }); 439 }, 440 441 notifyEvent = function (e) { 442 if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) { 443 return; 444 } 445 element.trigger(e); 446 }, 447 448 viewUpdate = function (e) { 449 if (e === 'y') { 450 e = 'YYYY'; 451 } 452 notifyEvent({ 453 type: 'dp.update', 454 change: e,
455 viewDate: viewDate.clone() 456 }); 457 }, 458 459 showMode = function (dir) { 460 if (!widget) { 461 return; 462 } 463 if (dir) { 464 currentViewMode = Math.max(minViewModeNumber, Math.min(3, currentViewMode + dir)); 465 } 466 widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show(); 467 }, 468 469 fillDow = function () { 470 var row = $('<tr>'), 471 currentDate = viewDate.clone().startOf('w').startOf('d'); 472 473 if (options.calendarWeeks === true) { 474 row.append($('<th>').addClass('cw').text('#')); 475 } 476 477 while (currentDate.isBefore(viewDate.clone().endOf('w'))) { 478 row.append($('<th>').addClass('dow').text(currentDate.format('dd'))); 479 currentDate.add(1, 'd'); 480 } 481 widget.find('.datepicker-days thead').append(row); 482 }, 483 484 isInDisabledDates = function (testDate) { 485 return options.disabledDates[testDate.format('YYYY-MM-DD')] === true; 486 }, 487 488 isInEnabledDates = function (testDate) { 489 return options.enabledDates[testDate.format('YYYY-MM-DD')] === true; 490 }, 491 492 isInDisabledHours = function (testDate) { 493 return options.disabledHours[testDate.format('H')] === true; 494 }, 495 496 isInEnabledHours = function (testDate) { 497 return options.enabledHours[testDate.format('H')] === true; 498 }, 499 500 isValid = function (targetMoment, granularity) { 501 if (!targetMoment.isValid()) { 502 return false; 503 } 504 if (options.disabledDates && granularity === 'd' && isInDisabledDates(targetMoment)) { 505 return false; 506 } 507 if (options.enabledDates && granularity === 'd' && !isInEnabledDates(targetMoment)) { 508 return false; 509 } 510 if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) { 511 return false; 512 } 513 if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) { 514 return false; 515 } 516 if (options.daysOfWeekDisabled && granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) { 517 return false; 518 } 519 if (options.disabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && isInDisabledHours(targetMoment)) { 520 return false; 521 } 522 if (options.enabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && !isInEnabledHours(targetMoment)) { 523 return false; 524 } 525 if (options.disabledTimeIntervals && (granularity === 'h' || granularity === 'm' || granularity === 's')) { 526 var found = false; 527 $.each(options.disabledTimeIntervals, function () { 528 if (targetMoment.isBetween(this[0], this[1])) { 529 found = true; 530 return false; 531 } 532 }); 533 if (found) { 534 return false; 535 } 536 } 537 return true; 538 }, 539 540 fillMonths = function () { 541 var spans = [], 542 monthsShort = viewDate.clone().startOf('y').startOf('d'); 543 while (monthsShort.isSame(viewDate, 'y')) { 544 spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM'))); 545 monthsShort.add(1, 'M'); 546 } 547 widget.find('.datepicker-months td').empty().append(spans); 548 }, 549 550 updateMonths = function () { 551 var monthsView = widget.find('.datepicker-months'), 552 monthsViewHeader = monthsView.find('th'), 553 months = monthsView.find('tbody').find('span'); 554 555 monthsViewHeader.eq(0).find('span').attr('title', 'Previous Year'); 556 monthsViewHeader.eq(1).attr('title', 'Select Year'); 557 monthsViewHeader.eq(2).find('span').attr('title', 'Next Year'); 558 559 monthsView.find('.disabled').removeClass('disabled'); 560 561 if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) { 562 monthsViewHeader.eq(0).addClass('disabled'); 563 } 564 565 monthsViewHeader.eq(1).text(viewDate.year()); 566 567 if (!isValid(viewDate.clone().add(1, 'y'), 'y')) { 568 monthsViewHeader.eq(2).addClass('disabled'); 569 } 570 571 months.removeClass('active'); 572 if (date.isSame(viewDate, 'y') && !unset) { 573 months.eq(date.month()).addClass('active'); 574 } 575 576 months.each(function (index) { 577 if (!isValid(viewDate.clone().month(index), 'M')) { 578 $(this).addClass('disabled'); 579 } 580 }); 581 }, 582 583 updateYears = function () { 584 var yearsView = widget.find('.datepicker-years'), 585 yearsViewHeader = yearsView.find('th'),
586 startYear = viewDate.clone().subtract(5, 'y'), 587 endYear = viewDate.clone().add(6, 'y'), 588 html = ''; 589 590 yearsViewHeader.eq(0).find('span').attr('title', 'Previous Decade'); 591 yearsViewHeader.eq(1).attr('title', 'Select Decade'); 592 yearsViewHeader.eq(2).find('span').attr('title', 'Next Decade'); 593 594 yearsView.find('.disabled').removeClass('disabled'); 595 596 if (options.minDate && options.minDate.isAfter(startYear, 'y')) { 597 yearsViewHeader.eq(0).addClass('disabled'); 598 } 599 600 yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year()); 601 602 if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) { 603 yearsViewHeader.eq(2).addClass('disabled'); 604 } 605 606 while (!startYear.isAfter(endYear, 'y')) { 607 html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') && !unset ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>'; 608 startYear.add(1, 'y'); 609 } 610 611 yearsView.find('td').html(html); 612 }, 613 614 updateDecades = function () { 615 var decadesView = widget.find('.datepicker-decades'), 616 decadesViewHeader = decadesView.find('th'), 617 startDecade = viewDate.isBefore(moment({y: 1999})) ? moment({y: 1899}) : moment({y: 1999}), 618 endDecade = startDecade.clone().add(100, 'y'), 619 html = ''; 620 621 decadesViewHeader.eq(0).find('span').attr('title', 'Previous Century'); 622 decadesViewHeader.eq(2).find('span').attr('title', 'Next Century'); 623 624 decadesView.find('.disabled').removeClass('disabled'); 625 626 if (startDecade.isSame(moment({y: 1900})) || (options.minDate && options.minDate.isAfter(startDecade, 'y'))) { 627 decadesViewHeader.eq(0).addClass('disabled'); 628 } 629 630 decadesViewHeader.eq(1).text(startDecade.year() + '-' + endDecade.year()); 631 632 if (startDecade.isSame(moment({y: 2000})) || (options.maxDate && options.maxDate.isBefore(endDecade, 'y'))) { 633 decadesViewHeader.eq(2).addClass('disabled'); 634 } 635 636 while (!startDecade.isAfter(endDecade, 'y')) { 637 html += '<span data-action="selectDecade" class="decade' + (startDecade.isSame(date, 'y') ? ' active' : '') + 638 (!isValid(startDecade, 'y') ? ' disabled' : '') + '" data-selection="' + (startDecade.year() + 6) + '">' + (startDecade.year() + 1) + ' - ' + (startDecade.year() + 12) + '</span>'; 639 startDecade.add(12, 'y'); 640 } 641 html += '<span></span><span></span><span></span>'; //push the dangling block over, at least this way it's even 642 643 decadesView.find('td').html(html); 644 }, 645 646 fillDate = function () { 647 var daysView = widget.find('.datepicker-days'), 648 daysViewHeader = daysView.find('th'), 649 currentDate, 650 html = [], 651 row, 652 clsName, 653 i; 654 655 if (!hasDate()) { 656 return; 657 } 658 659 daysViewHeader.eq(0).find('span').attr('title', 'Previous Month'); 660 daysViewHeader.eq(1).attr('title', 'Select Month'); 661 daysViewHeader.eq(2).find('span').attr('title', 'Next Month'); 662 663 daysView.find('.disabled').removeClass('disabled'); 664 daysViewHeader.eq(1).text(viewDate.format(options.dayViewHeaderFormat)); 665 666 if (!isValid(viewDate.clone().subtract(1, 'M'), 'M')) { 667 daysViewHeader.eq(0).addClass('disabled'); 668 } 669 if (!isValid(viewDate.clone().add(1, 'M'), 'M')) { 670 daysViewHeader.eq(2).addClass('disabled'); 671 } 672
673 currentDate = viewDate.clone().startOf('M').startOf('w').startOf('d'); 674 675 for (i = 0; i < 42; i++) { //always display 42 days (should show 6 weeks) 676 if (currentDate.weekday() === 0) { 677 row = $('<tr>'); 678 if (options.calendarWeeks) { 679 row.append('<td class="cw">' + currentDate.week() + '</td>'); 680 } 681 html.push(row); 682 } 683 clsName = ''; 684 if (currentDate.isBefore(viewDate, 'M')) { 685 clsName += ' old'; 686 } 687 if (currentDate.isAfter(viewDate, 'M')) { 688 clsName += ' new'; 689 } 690 if (currentDate.isSame(date, 'd') && !unset) { 691 clsName += ' active'; 692 } 693 if (!isValid(currentDate, 'd')) { 694 clsName += ' disabled'; 695 } 696 if (currentDate.isSame(moment(), 'd')) { 697 clsName += ' today'; 698 } 699 if (currentDate.day() === 0 || currentDate.day() === 6) { 700 clsName += ' weekend'; 701 } 702 row.append('<td data-action="selectDay" data-day="' + currentDate.format('L') + '" class="day' + clsName + '">' + currentDate.date() + '</td>'); 703 currentDate.add(1, 'd'); 704 } 705 706 daysView.find('tbody').empty().append(html); 707 708 updateMonths(); 709 710 updateYears(); 711 712 updateDecades(); 713 }, 714 715 fillHours = function () { 716 var table = widget.find('.timepicker-hours table'), 717 currentHour = viewDate.clone().startOf('d'), 718 html = [], 719 row = $('<tr>'); 720 721 if (viewDate.hour() > 11 && !use24Hours) { 722 currentHour.hour(12); 723 } 724 while (currentHour.isSame(viewDate, 'd') && (use24Hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) { 725 if (currentHour.hour() % 4 === 0) { 726 row = $('<tr>'); 727 html.push(row); 728 } 729 row.append('<td data-action="selectHour" class="hour' + (!isValid(currentHour, 'h') ? ' disabled' : '') + '">' + currentHour.format(use24Hours ? 'HH' : 'hh') + '</td>'); 730 currentHour.add(1, 'h'); 731 } 732 table.empty().append(html); 733 }, 734 735 fillMinutes = function () { 736 var table = widget.find('.timepicker-minutes table'), 737 currentMinute = viewDate.clone().startOf('h'), 738 html = [], 739 row = $('<tr>'), 740 step = options.stepping === 1 ? 5 : options.stepping; 741 742 while (viewDate.isSame(currentMinute, 'h')) { 743 if (currentMinute.minute() % (step * 4) === 0) { 744 row = $('<tr>'); 745 html.push(row); 746 } 747 row.append('<td data-action="selectMinute" class="minute' + (!isValid(currentMinute, 'm') ? ' disabled' : '') + '">' + currentMinute.format('mm') + '</td>'); 748 currentMinute.add(step, 'm'); 749 } 750 table.empty().append(html); 751 }, 752 753 fillSeconds = function () { 754 var table = widget.find('.timepicker-seconds table'), 755 currentSecond = viewDate.clone().startOf('m'), 756 html = [], 757 row = $('<tr>'); 758 759 while (viewDate.isSame(currentSecond, 'm')) { 760 if (currentSecond.second() % 20 === 0) { 761 row = $('<tr>'); 762 html.push(row); 763 } 764 row.append('<td data-action="selectSecond" class="second' + (!isValid(currentSecond, 's') ? ' disabled' : '') + '">' + currentSecond.format('ss') + '</td>'); 765 currentSecond.add(5, 's'); 766 } 767 768 table.empty().append(html); 769 }, 770 771 fillTime = function () {
772 var toggle, newDate, timeComponents = widget.find('.timepicker span[data-time-component]'); 773 774 if (!use24Hours) { 775 toggle = widget.find('.timepicker [data-action=togglePeriod]'); 776 newDate = date.clone().add((date.hours() >= 12) ? -12 : 12, 'h'); 777 778 toggle.text(date.format('A')); 779 780 if (isValid(newDate, 'h')) { 781 toggle.removeClass('disabled'); 782 } else { 783 toggle.addClass('disabled'); 784 } 785 } 786 timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh')); 787 timeComponents.filter('[data-time-component=minutes]').text(date.format('mm')); 788 timeComponents.filter('[data-time-component=seconds]').text(date.format('ss')); 789 790 fillHours(); 791 fillMinutes(); 792 fillSeconds(); 793 }, 794 795 update = function () { 796 if (!widget) { 797 return; 798 } 799 fillDate(); 800 fillTime(); 801 }, 802 803 setValue = function (targetMoment) { 804 var oldDate = unset ? null : date; 805 806 // case of calling setValue(null or false) 807 if (!targetMoment) { 808 unset = true; 809 input.val(''); 810 element.data('date', ''); 811 notifyEvent({ 812 type: 'dp.change', 813 date: false, 814 oldDate: oldDate 815 }); 816 update(); 817 return; 818 } 819 820 targetMoment = targetMoment.clone().locale(options.locale); 821 822 if (options.stepping !== 1) { 823 targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0); 824 } 825 826 if (isValid(targetMoment)) { 827 date = targetMoment; 828 viewDate = date.clone(); 829 input.val(date.format(actualFormat)); 830 element.data('date', date.format(actualFormat)); 831 unset = false; 832 update(); 833 notifyEvent({ 834 type: 'dp.change', 835 date: date.clone(), 836 oldDate: oldDate 837 }); 838 } else { 839 if (!options.keepInvalid) { 840 input.val(unset ? '' : date.format(actualFormat)); 841 } 842 notifyEvent({ 843 type: 'dp.error', 844 date: targetMoment 845 }); 846 } 847 }, 848 849 hide = function () { 850 ///<summary>Hides the widget. Possibly will emit dp.hide</summary> 851 var transitioning = false; 852 if (!widget) { 853 return picker; 854 } 855 // Ignore event if in the middle of a picker transition 856 widget.find('.collapse').each(function () { 857 var collapseData = $(this).data('collapse'); 858 if (collapseData && collapseData.transitioning) { 859 transitioning = true; 860 return false; 861 } 862 return true; 863 }); 864 if (transitioning) { 865 return picker; 866 } 867 if (component && component.hasClass('btn')) { 868 component.toggleClass('active'); 869 } 870 widget.hide(); 871 872 $(window).off('resize', place); 873 widget.off('click', '[data-action]'); 874 widget.off('mousedown', false); 875 876 widget.remove(); 877 widget = false; 878 879 notifyEvent({ 880 type: 'dp.hide', 881 date: date.clone() 882 }); 883 return picker; 884 }, 885 886 clear = function () { 887 setValue(null); 888 }, 889 890 /******************************************************************************** 891 * 892 * Widget UI interaction functions 893 * 894 ********************************************************************************/ 895 actions = { 896 next: function () { 897 var navFnc = datePickerModes[currentViewMode].navFnc; 898 viewDate.add(datePickerModes[currentViewMode].navStep, navFnc); 899 fillDate(); 900 viewUpdate(navFnc); 901 }, 902 903 previous: function () { 904 var navFnc = datePickerModes[currentViewMode].navFnc; 905 viewDate.subtract(datePickerModes[currentViewMode].navStep, navFnc); 906 fillDate(); 907 viewUpdate(navFnc); 908 }, 909 910 pickerSwitch: function () { 911 showMode(1); 912 }, 913 914 selectMonth: function (e) {
915 var month = $(e.target).closest('tbody').find('span').index($(e.target)); 916 viewDate.month(month); 917 if (currentViewMode === minViewModeNumber) { 918 setValue(date.clone().year(viewDate.year()).month(viewDate.month())); 919 if (!options.inline) { 920 hide(); 921 } 922 } else { 923 showMode(-1); 924 fillDate(); 925 } 926 viewUpdate('M'); 927 }, 928 929 selectYear: function (e) { 930 var year = parseInt($(e.target).text(), 10) || 0; 931 viewDate.year(year); 932 if (currentViewMode === minViewModeNumber) { 933 setValue(date.clone().year(viewDate.year())); 934 if (!options.inline) { 935 hide(); 936 } 937 } else { 938 showMode(-1); 939 fillDate(); 940 } 941 viewUpdate('YYYY'); 942 }, 943 944 selectDecade: function (e) { 945 var year = parseInt($(e.target).data('selection'), 10) || 0; 946 viewDate.year(year); 947 if (currentViewMode === minViewModeNumber) { 948 setValue(date.clone().year(viewDate.year())); 949 if (!options.inline) { 950 hide(); 951 } 952 } else { 953 showMode(-1); 954 fillDate(); 955 } 956 viewUpdate('YYYY'); 957 }, 958 959 selectDay: function (e) { 960 var day = viewDate.clone(); 961 if ($(e.target).is('.old')) { 962 day.subtract(1, 'M'); 963 } 964 if ($(e.target).is('.new')) { 965 day.add(1, 'M'); 966 } 967 setValue(day.date(parseInt($(e.target).text(), 10))); 968 if (!hasTime() && !options.keepOpen && !options.inline) { 969 hide(); 970 } 971 }, 972 973 incrementHours: function () { 974 var newDate = date.clone().add(1, 'h'); 975 if (isValid(newDate, 'h')) { 976 setValue(newDate); 977 } 978 }, 979 980 incrementMinutes: function () { 981 var newDate = date.clone().add(options.stepping, 'm'); 982 if (isValid(newDate, 'm')) { 983 setValue(newDate); 984 } 985 }, 986 987 incrementSeconds: function () { 988 var newDate = date.clone().add(1, 's'); 989 if (isValid(newDate, 's')) { 990 setValue(newDate); 991 } 992 }, 993 994 decrementHours: function () { 995 var newDate = date.clone().subtract(1, 'h'); 996 if (isValid(newDate, 'h')) { 997 setValue(newDate); 998 } 999 }, 1000 1001 decrementMinutes: function () { 1002 var newDate = date.clone().subtract(options.stepping, 'm'); 1003 if (isValid(newDate, 'm')) { 1004 setValue(newDate); 1005 } 1006 }, 1007 1008 decrementSeconds: function () { 1009 var newDate = date.clone().subtract(1, 's'); 1010 if (isValid(newDate, 's')) { 1011 setValue(newDate); 1012 } 1013 }, 1014 1015 togglePeriod: function () { 1016 setValue(date.clone().add((date.hours() >= 12) ? -12 : 12, 'h')); 1017 }, 1018 1019 togglePicker: function (e) { 1020 var $this = $(e.target), 1021 $parent = $this.closest('ul'), 1022 expanded = $parent.find('.in'), 1023 closed = $parent.find('.collapse:not(.in)'), 1024 collapseData; 1025 1026 if (expanded && expanded.length) { 1027 collapseData = expanded.data('collapse'); 1028 if (collapseData && collapseData.transitioning) { 1029 return; 1030 } 1031 if (expanded.collapse) { // if collapse plugin is available through bootstrap.js then use it 1032 expanded.collapse('hide'); 1033 closed.collapse('show'); 1034 } else { // otherwise just toggle in class on the two views 1035 expanded.removeClass('in'); 1036 closed.addClass('in'); 1037 } 1038 if ($this.is('span')) { 1039 $this.toggleClass(options.icons.time + ' ' + options.icons.date); 1040 } else { 1041 $this.find('span').toggleClass(options.icons.time + ' ' + options.icons.date); 1042 } 1043 1044 // NOTE: uncomment if toggled state will be restored in show() 1045 //if (component) { 1046 // component.find('span').toggleClass(options.icons.time + ' ' + options.icons.date); 1047 //} 1048 } 1049 }, 1050 1051 showPicker: function () { 1052 widget.find('.timepicker > div:not(.timepicker-picker)').hide(); 1053 widget.find('.timepicker .timepicker-picker').show(); 1054 }, 1055 1056 showHours: function () { 1057 widget.find('.timepicker .timepicker-picker').hide(); 1058 widget.find('.timepicker .timepicker-hours').show(); 1059 }, 1060 1061 showMinutes: function () { 1062 widget.find('.timepicker .timepicker-picker').hide(); 1063 widget.find('.timepicker .timepicker-minutes').show(); 1064 }, 1065 1066 showSeconds: function () { 1067 widget.find('.timepicker .timepicker-picker').hide(); 1068 widget.find('.timepicker .timepicker-seconds').show(); 1069 }, 1070 1071 selectHour: function (e) { 1072 var hour = parseInt($(e.target).text(), 10); 1073 1074 if (!use24Hours) { 1075 if (date.hours() >= 12) { 1076 if (hour !== 12) { 1077 hour += 12; 1078 } 1079 } else { 1080 if (hour === 12) { 1081 hour = 0; 1082 } 1083 } 1084 } 1085 setValue(date.clone().hours(hour)); 1086 actions.showPicker.call(picker); 1087 }, 1088 1089 selectMinute: function (e) { 1090 setValue(date.clone().minutes(parseInt($(e.target).text(), 10))); 1091 actions.showPicker.call(picker); 1092 }, 1093 1094 selectSecond: function (e) { 1095 setValue(date.clone().seconds(parseInt($(e.target).text(), 10))); 1096 actions.showPicker.call(picker); 1097 }, 1098 1099 clear: clear, 1100 1101 today: function () { 1102 if (isValid(moment(), 'd')) { 1103 setValue(moment()); 1104 } 1105 }, 1106 1107 close: hide 1108 }, 1109 1110 doAction = function (e) { 1111 if ($(e.currentTarget).is('.disabled')) { 1112 return false;
1113 } 1114 actions[$(e.currentTarget).data('action')].apply(picker, arguments); 1115 return false; 1116 }, 1117 1118 show = function () { 1119 ///<summary>Shows the widget. Possibly will emit dp.show and dp.change</summary> 1120 var currentMoment, 1121 useCurrentGranularity = { 1122 'year': function (m) { 1123 return m.month(0).date(1).hours(0).seconds(0).minutes(0); 1124 }, 1125 'month': function (m) { 1126 return m.date(1).hours(0).seconds(0).minutes(0); 1127 }, 1128 'day': function (m) { 1129 return m.hours(0).seconds(0).minutes(0); 1130 }, 1131 'hour': function (m) { 1132 return m.seconds(0).minutes(0); 1133 }, 1134 'minute': function (m) { 1135 return m.seconds(0); 1136 } 1137 }; 1138 1139 if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) { 1140 return picker; 1141 } 1142 if (input.val() !== undefined && input.val().trim().length !== 0) { 1143 setValue(parseInputDate(input.val().trim())); 1144 } else if (options.useCurrent && unset && ((input.is('input') && input.val().trim().length === 0) || options.inline)) { 1145 currentMoment = moment(); 1146 if (typeof options.useCurrent === 'string') { 1147 currentMoment = useCurrentGranularity[options.useCurrent](currentMoment); 1148 } 1149 setValue(currentMoment); 1150 } 1151 1152 widget = getTemplate(); 1153 1154 fillDow(); 1155 fillMonths(); 1156 1157 widget.find('.timepicker-hours').hide(); 1158 widget.find('.timepicker-minutes').hide(); 1159 widget.find('.timepicker-seconds').hide(); 1160 1161 update(); 1162 showMode(); 1163 1164 $(window).on('resize', place); 1165 widget.on('click', '[data-action]', doAction); // this handles clicks on the widget 1166 widget.on('mousedown', false); 1167 1168 if (component && component.hasClass('btn')) { 1169 component.toggleClass('active'); 1170 } 1171 widget.show(); 1172 place(); 1173 1174 if (options.focusOnShow && !input.is(':focus')) { 1175 input.focus(); 1176 } 1177 1178 notifyEvent({ 1179 type: 'dp.show' 1180 }); 1181 return picker; 1182 }, 1183 1184 toggle = function () { 1185 /// <summary>Shows or hides the widget</summary> 1186 return (widget ? hide() : show()); 1187 }, 1188 1189 parseInputDate = function (inputDate) { 1190 if (options.parseInputDate === undefined) { 1191 if (moment.isMoment(inputDate) || inputDate instanceof Date) { 1192 inputDate = moment(inputDate); 1193 } else { 1194 inputDate = moment(inputDate, parseFormats, options.useStrict); 1195 } 1196 } else { 1197 inputDate = options.parseInputDate(inputDate); 1198 } 1199 inputDate.locale(options.locale); 1200 return inputDate; 1201 }, 1202 1203 keydown = function (e) { 1204 var handler = null, 1205 index, 1206 index2, 1207 pressedKeys = [], 1208 pressedModifiers = {}, 1209 currentKey = e.which, 1210 keyBindKeys, 1211 allModifiersPressed, 1212 pressed = 'p'; 1213 1214 keyState[currentKey] = pressed; 1215 1216 for (index in keyState) { 1217 if (keyState.hasOwnProperty(index) && keyState[index] === pressed) { 1218 pressedKeys.push(index); 1219 if (parseInt(index, 10) !== currentKey) { 1220 pressedModifiers[index] = true; 1221 } 1222 } 1223 } 1224 1225 for (index in options.keyBinds) { 1226 if (options.keyBinds.hasOwnProperty(index) && typeof (options.keyBinds[index]) === 'function') { 1227 keyBindKeys = index.split(' '); 1228 if (keyBindKeys.length === pressedKeys.length && keyMap[currentKey] === keyBindKeys[keyBindKeys.length - 1]) { 1229 allModifiersPressed = true; 1230 for (index2 = keyBindKeys.length - 2; index2 >= 0; index2--) { 1231 if (!(keyMap[keyBindKeys[index2]] in pressedModifiers)) { 1232 allModifiersPressed = false;
1233 break; 1234 } 1235 } 1236 if (allModifiersPressed) { 1237 handler = options.keyBinds[index]; 1238 break; 1239 } 1240 } 1241 } 1242 } 1243 1244 if (handler) { 1245 handler.call(picker, widget); 1246 e.stopPropagation(); 1247 e.preventDefault(); 1248 } 1249 }, 1250 1251 keyup = function (e) { 1252 keyState[e.which] = 'r'; 1253 e.stopPropagation(); 1254 e.preventDefault(); 1255 }, 1256 1257 change = function (e) { 1258 var val = $(e.target).val().trim(), 1259 parsedDate = val ? parseInputDate(val) : null; 1260 setValue(parsedDate); 1261 e.stopImmediatePropagation(); 1262 return false; 1263 }, 1264 1265 attachDatePickerElementEvents = function () { 1266 input.on({ 1267 'change': change, 1268 'blur': options.debug ? '' : hide, 1269 'keydown': keydown, 1270 'keyup': keyup, 1271 'focus': options.allowInputToggle ? show : '' 1272 }); 1273 1274 if (element.is('input')) { 1275 input.on({ 1276 'focus': show 1277 }); 1278 } else if (component) { 1279 component.on('click', toggle); 1280 component.on('mousedown', false); 1281 } 1282 }, 1283 1284 detachDatePickerElementEvents = function () { 1285 input.off({ 1286 'change': change, 1287 'blur': hide, 1288 'keydown': keydown, 1289 'keyup': keyup, 1290 'focus': options.allowInputToggle ? hide : '' 1291 }); 1292 1293 if (element.is('input')) { 1294 input.off({ 1295 'focus': show 1296 }); 1297 } else if (component) { 1298 component.off('click', toggle); 1299 component.off('mousedown', false); 1300 } 1301 }, 1302 1303 indexGivenDates = function (givenDatesArray) { 1304 // Store given enabledDates and disabledDates as keys. 1305 // This way we can check their existence in O(1) time instead of looping through whole array. 1306 // (for example: options.enabledDates['2014-02-27'] === true) 1307 var givenDatesIndexed = {}; 1308 $.each(givenDatesArray, function () { 1309 var dDate = parseInputDate(this); 1310 if (dDate.isValid()) { 1311 givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true; 1312 } 1313 }); 1314 return (Object.keys(givenDatesIndexed).length) ? givenDatesIndexed : false; 1315 }, 1316 1317 indexGivenHours = function (givenHoursArray) { 1318 // Store given enabledHours and disabledHours as keys. 1319 // This way we can check their existence in O(1) time instead of looping through whole array. 1320 // (for example: options.enabledHours['2014-02-27'] === true) 1321 var givenHoursIndexed = {}; 1322 $.each(givenHoursArray, function () { 1323 givenHoursIndexed[this] = true; 1324 }); 1325 return (Object.keys(givenHoursIndexed).length) ? givenHoursIndexed : false; 1326 }, 1327 1328 initFormatting = function () { 1329 var format = options.format || 'L LT'; 1330 1331 actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput) { 1332 var newinput = date.localeData().longDateFormat(formatInput) || formatInput; 1333 return newinput.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput2) { //temp fix for #740 1334 return date.localeData().longDateFormat(formatInput2) || formatInput2; 1335 }); 1336 }); 1337 1338 1339 parseFormats = options.extraFormats ? options.extraFormats.slice() : []; 1340 if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) { 1341 parseFormats.push(actualFormat); 1342 } 1343 1344 use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.replace(/\[.*?\]/g, '').indexOf('h') < 1); 1345 1346 if (isEnabled('y')) { 1347 minViewModeNumber = 2; 1348 } 1349 if (isEnabled('M')) { 1350 minViewModeNumber = 1; 1351 } 1352 if (isEnabled('d')) { 1353 minViewModeNumber = 0; 1354 } 1355
1356 currentViewMode = Math.max(minViewModeNumber, currentViewMode); 1357 1358 if (!unset) { 1359 setValue(date); 1360 } 1361 }; 1362 1363 /******************************************************************************** 1364 * 1365 * Public API functions 1366 * ===================== 1367 * 1368 * Important: Do not expose direct references to private objects or the options 1369 * object to the outer world. Always return a clone when returning values or make 1370 * a clone when setting a private variable. 1371 * 1372 ********************************************************************************/ 1373 picker.destroy = function () { 1374 ///<summary>Destroys the widget and removes all attached event listeners</summary> 1375 hide(); 1376 detachDatePickerElementEvents(); 1377 element.removeData('DateTimePicker'); 1378 element.removeData('date'); 1379 }; 1380 1381 picker.toggle = toggle; 1382 1383 picker.show = show; 1384 1385 picker.hide = hide; 1386 1387 picker.disable = function () { 1388 ///<summary>Disables the input element, the component is attached to, by adding a disabled="true" attribute to it. 1389 ///If the widget was visible before that call it is hidden. Possibly emits dp.hide</summary> 1390 hide(); 1391 if (component && component.hasClass('btn')) { 1392 component.addClass('disabled'); 1393 } 1394 input.prop('disabled', true); 1395 return picker; 1396 }; 1397 1398 picker.enable = function () { 1399 ///<summary>Enables the input element, the component is attached to, by removing disabled attribute from it.</summary> 1400 if (component && component.hasClass('btn')) { 1401 component.removeClass('disabled'); 1402 } 1403 input.prop('disabled', false); 1404 return picker; 1405 }; 1406 1407 picker.ignoreReadonly = function (ignoreReadonly) { 1408 if (arguments.length === 0) { 1409 return options.ignoreReadonly; 1410 } 1411 if (typeof ignoreReadonly !== 'boolean') { 1412 throw new TypeError('ignoreReadonly () expects a boolean parameter'); 1413 } 1414 options.ignoreReadonly = ignoreReadonly; 1415 return picker; 1416 }; 1417 1418 picker.options = function (newOptions) { 1419 if (arguments.length === 0) { 1420 return $.extend(true, {}, options); 1421 } 1422 1423 if (!(newOptions instanceof Object)) { 1424 throw new TypeError('options() options parameter should be an object'); 1425 } 1426 $.extend(true, options, newOptions); 1427 $.each(options, function (key, value) { 1428 if (picker[key] !== undefined) { 1429 picker[key](value); 1430 } else { 1431 throw new TypeError('option ' + key + ' is not recognized!'); 1432 } 1433 }); 1434 return picker; 1435 }; 1436 1437 picker.date = function (newDate) { 1438 ///<signature helpKeyword="$.fn.datetimepicker.date"> 1439 ///<summary>Returns the component's model current date, a moment object or null if not set.</summary> 1440 ///<returns type="Moment">date.clone()</returns> 1441 ///</signature> 1442 ///<signature> 1443 ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary> 1444 ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, Date, moment, null parameter.</param> 1445 ///</signature> 1446 if (arguments.length === 0) { 1447 if (unset) { 1448 return null; 1449 } 1450 return date.clone(); 1451 } 1452 1453 if (newDate !== null && typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) { 1454 throw new TypeError('date() parameter must be one of [null, string, moment or Date]'); 1455 } 1456 1457 setValue(newDate === null ? null : parseInputDate(newDate)); 1458 return picker; 1459 }; 1460 1461 picker.format = function (newFormat) { 1462 ///<summary>test su</summary> 1463 ///<param name="newFormat">info about para</param> 1464 ///<returns type="string|boolean">returns foo</returns> 1465 if (arguments.length === 0) { 1466 return options.format; 1467 } 1468 1469 if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) { 1470 throw new TypeError('format() expects a sting or boolean:false parameter ' + newFormat); 1471 } 1472 1473 options.format = newFormat; 1474 if (actualFormat) { 1475 initFormatting(); // reinit formatting 1476 } 1477 return picker; 1478 }; 1479 1480 picker.dayViewHeaderFormat = function (newFormat) { 1481 if (arguments.length === 0) { 1482 return options.dayViewHeaderFormat; 1483 } 1484 1485 if (typeof newFormat !== 'string') { 1486 throw new TypeError('dayViewHeaderFormat() expects a string parameter'); 1487 } 1488 1489 options.dayViewHeaderFormat = newFormat; 1490 return picker; 1491 }; 1492 1493 picker.extraFormats = function (formats) { 1494 if (arguments.length === 0) { 1495 return options.extraFormats; 1496 } 1497 1498 if (formats !== false && !(formats instanceof Array)) { 1499 throw new TypeError('extraFormats() expects an array or false parameter'); 1500 } 1501 1502 options.extraFormats = formats; 1503 if (parseFormats) { 1504 initFormatting(); // reinit formatting 1505 } 1506 return picker; 1507 }; 1508 1509 picker.disabledDates = function (dates) { 1510 ///<signature helpKeyword="$.fn.datetimepicker.disabledDates"> 1511 ///<summary>Returns an array with the currently set disabled dates on the component.</summary> 1512 ///<returns type="array">options.disabledDates</returns> 1513 ///</signature> 1514 ///<signature> 1515 ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of 1516 ///options.enabledDates if such exist.</summary> 1517 ///<param name="dates" locid="$.fn.datetimepicker.disabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.
1517</param> 1518 ///</signature> 1519 if (arguments.length === 0) { 1520 return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates); 1521 } 1522 1523 if (!dates) { 1524 options.disabledDates = false; 1525 update(); 1526 return picker; 1527 } 1528 if (!(dates instanceof Array)) { 1529 throw new TypeError('disabledDates() expects an array parameter'); 1530 } 1531 options.disabledDates = indexGivenDates(dates); 1532 options.enabledDates = false; 1533 update(); 1534 return picker; 1535 }; 1536 1537 picker.enabledDates = function (dates) { 1538 ///<signature helpKeyword="$.fn.datetimepicker.enabledDates"> 1539 ///<summary>Returns an array with the currently set enabled dates on the component.</summary> 1540 ///<returns type="array">options.enabledDates</returns> 1541 ///</signature> 1542 ///<signature> 1543 ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledDates if such exist.</summary> 1544 ///<param name="dates" locid="$.fn.datetimepicker.enabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param> 1545 ///</signature> 1546 if (arguments.length === 0) { 1547 return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates); 1548 } 1549 1550 if (!dates) { 1551 options.enabledDates = false; 1552 update(); 1553 return picker; 1554 } 1555 if (!(dates instanceof Array)) { 1556 throw new TypeError('enabledDates() expects an array parameter'); 1557 } 1558 options.enabledDates = indexGivenDates(dates); 1559 options.disabledDates = false; 1560 update(); 1561 return picker; 1562 }; 1563 1564 picker.daysOfWeekDisabled = function (daysOfWeekDisabled) { 1565 if (arguments.length === 0) { 1566 return options.daysOfWeekDisabled.splice(0); 1567 } 1568 1569 if ((typeof daysOfWeekDisabled === 'boolean') && !daysOfWeekDisabled) { 1570 options.daysOfWeekDisabled = false; 1571 update(); 1572 return picker; 1573 } 1574 1575 if (!(daysOfWeekDisabled instanceof Array)) { 1576 throw new TypeError('daysOfWeekDisabled() expects an array parameter'); 1577 } 1578 options.daysOfWeekDisabled = daysOfWeekDisabled.reduce(function (previousValue, currentValue) { 1579 currentValue = parseInt(currentValue, 10); 1580 if (currentValue > 6 || currentValue < 0 || isNaN(currentValue)) { 1581 return previousValue; 1582 } 1583 if (previousValue.indexOf(currentValue) === -1) { 1584 previousValue.push(currentValue); 1585 } 1586 return previousValue; 1587 }, []).sort(); 1588 if (options.useCurrent && !options.keepInvalid) { 1589 var tries = 0; 1590 while (!isValid(date, 'd')) { 1591 date.add(1, 'd'); 1592 if (tries === 7) { 1593 throw 'Tried 7 times to find a valid date'; 1594 } 1595 tries++; 1596 } 1597 setValue(date); 1598 } 1599 update(); 1600 return picker; 1601 }; 1602 1603 picker.maxDate = function (maxDate) { 1604 if (arguments.length === 0) { 1605 return options.maxDate ? options.maxDate.clone() : options.maxDate; 1606 } 1607 1608 if ((typeof maxDate === 'boolean') && maxDate === false) { 1609 options.maxDate = false; 1610 update(); 1611 return picker; 1612 } 1613 1614 if (typeof maxDate === 'string') { 1615 if (maxDate === 'now' || maxDate === 'moment') { 1616 maxDate = moment(); 1617 } 1618 } 1619 1620 var parsedDate = parseInputDate(maxDate); 1621 1622 if (!parsedDate.isValid()) { 1623 throw new TypeError('maxDate() Could not parse date parameter: ' + maxDate); 1624 } 1625 if (options.minDate && parsedDate.isBefore(options.minDate)) { 1626 throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat)); 1627 } 1628 options.maxDate = parsedDate; 1629 if (options.useCurrent && !options.keepInvalid && date.isAfter(maxDate)) { 1630 setValue(options.maxDate); 1631 } 1632 if (viewDate.isAfter(parsedDate)) { 1633 viewDate = parsedDate.clone(); 1634 } 1635 update(); 1636 return picker; 1637 }; 1638 1639 picker.minDate = function (minDate) { 1640 if (arguments.length === 0) { 1641 return options.minDate ? options.minDate.clone() : options.minDate; 1642 } 1643 1644 if ((typeof minDate === 'boolean') && minDate === false) { 1645 options.minDate = false;
1646 update(); 1647 return picker; 1648 } 1649 1650 if (typeof minDate === 'string') { 1651 if (minDate === 'now' || minDate === 'moment') { 1652 minDate = moment(); 1653 } 1654 } 1655 1656 var parsedDate = parseInputDate(minDate); 1657 1658 if (!parsedDate.isValid()) { 1659 throw new TypeError('minDate() Could not parse date parameter: ' + minDate); 1660 } 1661 if (options.maxDate && parsedDate.isAfter(options.maxDate)) { 1662 throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat)); 1663 } 1664 options.minDate = parsedDate; 1665 if (options.useCurrent && !options.keepInvalid && date.isBefore(minDate)) { 1666 setValue(options.minDate); 1667 } 1668 if (viewDate.isBefore(parsedDate)) { 1669 viewDate = parsedDate.clone(); 1670 } 1671 update(); 1672 return picker; 1673 }; 1674 1675 picker.defaultDate = function (defaultDate) { 1676 ///<signature helpKeyword="$.fn.datetimepicker.defaultDate"> 1677 ///<summary>Returns a moment with the options.defaultDate option configuration or false if not set</summary> 1678 ///<returns type="Moment">date.clone()</returns> 1679 ///</signature> 1680 ///<signature> 1681 ///<summary>Will set the picker's inital date. If a boolean:false value is passed the options.defaultDate parameter is cleared.</summary> 1682 ///<param name="defaultDate" locid="$.fn.datetimepicker.defaultDate_p:defaultDate">Takes a string, Date, moment, boolean:false</param> 1683 ///</signature> 1684 if (arguments.length === 0) { 1685 return options.defaultDate ? options.defaultDate.clone() : options.defaultDate; 1686 } 1687 if (!defaultDate) { 1688 options.defaultDate = false; 1689 return picker; 1690 } 1691 1692 if (typeof defaultDate === 'string') { 1693 if (defaultDate === 'now' || defaultDate === 'moment') { 1694 defaultDate = moment(); 1695 } 1696 } 1697 1698 var parsedDate = parseInputDate(defaultDate); 1699 if (!parsedDate.isValid()) { 1700 throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate); 1701 } 1702 if (!isValid(parsedDate)) { 1703 throw new TypeError('defaultDate() date passed is invalid according to component setup validations'); 1704 } 1705 1706 options.defaultDate = parsedDate; 1707 1708 if (options.defaultDate && options.inline || (input.val().trim() === '' && input.attr('placeholder') === undefined)) { 1709 setValue(options.defaultDate); 1710 } 1711 return picker; 1712 }; 1713 1714 picker.locale = function (locale) { 1715 if (arguments.length === 0) { 1716 return options.locale; 1717 } 1718 1719 if (!moment.localeData(locale)) { 1720 throw new TypeError('locale() locale ' + locale + ' is not loaded from moment locales!'); 1721 } 1722 1723 options.locale = locale; 1724 date.locale(options.locale); 1725 viewDate.locale(options.locale); 1726 1727 if (actualFormat) { 1728 initFormatting(); // reinit formatting 1729 } 1730 if (widget) { 1731 hide(); 1732 show(); 1733 } 1734 return picker; 1735 }; 1736 1737 picker.stepping = function (stepping) { 1738 if (arguments.length === 0) { 1739 return options.stepping; 1740 } 1741 1742 stepping = parseInt(stepping, 10); 1743 if (isNaN(stepping) || stepping < 1) { 1744 stepping = 1; 1745 } 1746 options.stepping = stepping; 1747 return picker; 1748 }; 1749 1750 picker.useCurrent = function (useCurrent) { 1751 var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute']; 1752 if (arguments.length === 0) { 1753 return options.useCurrent; 1754 } 1755 1756 if ((typeof useCurrent !== 'boolean') && (typeof useCurrent !== 'string')) { 1757 throw new TypeError('useCurrent() expects a boolean or string parameter'); 1758 } 1759 if (typeof useCurrent === 'string' && useCurrentOptions.indexOf(useCurrent.toLowerCase()) === -1) { 1760 throw new TypeError('useCurrent() expects a string parameter of ' + useCurrentOptions.join(', ')); 1761 } 1762 options.useCurrent = useCurrent; 1763 return picker; 1764 }; 1765 1766 picker.collapse = function (collapse) { 1767 if (arguments.length === 0) { 1768 return options.collapse; 1769 } 1770 1771 if (typeof collapse !== 'boolean') { 1772 throw new TypeError('collapse() expects a boolean parameter'); 1773 } 1774 if (options.collapse === collapse) { 1775 return picker; 1776 } 1777 options.collapse = collapse; 1778 if (widget) { 1779 hide(); 1780 show(); 1781 } 1782 return picker; 1783 }; 1784 1785 picker.icons = function (icons) { 1786 if (arguments.length === 0) { 1787 return $.extend({}, options.icons); 1788 } 1789 1790 if (!(icons instanceof Object)) { 1791 throw new TypeError('icons() expects parameter to be an Object'); 1792 } 1793 $.extend(options.icons, icons); 1794 if (widget) { 1795 hide(); 1796 show(); 1797 } 1798 return picker; 1799 }; 1800 1801 picker.useStrict = function (useStrict) { 1802 if (arguments.length === 0) { 1803 return options.useStrict; 1804 } 1805 1806 if (typeof useStrict !== 'boolean') { 1807 throw new TypeError('useStrict() expects a boolean parameter'); 1808 } 1809 options.useStrict = useStrict; 1810 return picker; 1811 }; 1812 1813 picker.sideBySide = function (sideBySide) { 1814 if (arguments.length === 0) { 1815 return options.sideBySide; 1816 } 1817 1818 if (typeof sideBySide !== 'boolean') { 1819 throw new TypeError('sideBySide() expects a boolean parameter'); 1820 } 1821 options.sideBySide = sideBySide; 1822 if (widget) { 1823 hide(); 1824 show(); 1825 } 1826 return picker; 1827 }; 1828 1829 picker.viewMode = function (viewMode) { 1830 if (arguments.length === 0) { 1831 return options.viewMode; 1832 } 1833 1834 if (typeof viewMode !== 'string') { 1835 throw new TypeError('viewMode() expects a string parameter'); 1836 } 1837 1838 if (viewModes.indexOf(viewMode) === -1) { 1839 throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value'); 1840 } 1841
1842 options.viewMode = viewMode; 1843 currentViewMode = Math.max(viewModes.indexOf(viewMode), minViewModeNumber); 1844 1845 showMode(); 1846 return picker; 1847 }; 1848 1849 picker.toolbarPlacement = function (toolbarPlacement) { 1850 if (arguments.length === 0) { 1851 return options.toolbarPlacement; 1852 } 1853 1854 if (typeof toolbarPlacement !== 'string') { 1855 throw new TypeError('toolbarPlacement() expects a string parameter'); 1856 } 1857 if (toolbarPlacements.indexOf(toolbarPlacement) === -1) { 1858 throw new TypeError('toolbarPlacement() parameter must be one of (' + toolbarPlacements.join(', ') + ') value'); 1859 } 1860 options.toolbarPlacement = toolbarPlacement; 1861 1862 if (widget) { 1863 hide(); 1864 show(); 1865 } 1866 return picker; 1867 }; 1868 1869 picker.widgetPositioning = function (widgetPositioning) { 1870 if (arguments.length === 0) { 1871 return $.extend({}, options.widgetPositioning); 1872 } 1873 1874 if (({}).toString.call(widgetPositioning) !== '[object Object]') { 1875 throw new TypeError('widgetPositioning() expects an object variable'); 1876 } 1877 if (widgetPositioning.horizontal) { 1878 if (typeof widgetPositioning.horizontal !== 'string') { 1879 throw new TypeError('widgetPositioning() horizontal variable must be a string'); 1880 } 1881 widgetPositioning.horizontal = widgetPositioning.horizontal.toLowerCase(); 1882 if (horizontalModes.indexOf(widgetPositioning.horizontal) === -1) { 1883 throw new TypeError('widgetPositioning() expects horizontal parameter to be one of (' + horizontalModes.join(', ') + ')'); 1884 } 1885 options.widgetPositioning.horizontal = widgetPositioning.horizontal; 1886 } 1887 if (widgetPositioning.vertical) { 1888 if (typeof widgetPositioning.vertical !== 'string') { 1889 throw new TypeError('widgetPositioning() vertical variable must be a string'); 1890 } 1891 widgetPositioning.vertical = widgetPositioning.vertical.toLowerCase(); 1892 if (verticalModes.indexOf(widgetPositioning.vertical) === -1) { 1893 throw new TypeError('widgetPositioning() expects vertical parameter to be one of (' + verticalModes.join(', ') + ')'); 1894 } 1895 options.widgetPositioning.vertical = widgetPositioning.vertical; 1896 } 1897 update(); 1898 return picker; 1899 }; 1900 1901 picker.calendarWeeks = function (calendarWeeks) { 1902 if (arguments.length === 0) { 1903 return options.calendarWeeks; 1904 } 1905 1906 if (typeof calendarWeeks !== 'boolean') { 1907 throw new TypeError('calendarWeeks() expects parameter to be a boolean value'); 1908 } 1909 1910 options.calendarWeeks = calendarWeeks; 1911 update(); 1912 return picker; 1913 }; 1914 1915 picker.showTodayButton = function (showTodayButton) { 1916 if (arguments.length === 0) { 1917 return options.showTodayButton; 1918 } 1919 1920 if (typeof showTodayButton !== 'boolean') { 1921 throw new TypeError('showTodayButton() expects a boolean parameter'); 1922 } 1923 1924 options.showTodayButton = showTodayButton; 1925 if (widget) { 1926 hide(); 1927 show(); 1928 } 1929 return picker; 1930 }; 1931 1932 picker.showClear = function (showClear) { 1933 if (arguments.length === 0) { 1934 return options.showClear; 1935 } 1936 1937 if (typeof showClear !== 'boolean') { 1938 throw new TypeError('showClear() expects a boolean parameter'); 1939 } 1940 1941 options.showClear = showClear; 1942 if (widget) { 1943 hide(); 1944 show(); 1945 } 1946 return picker; 1947 }; 1948 1949 picker.widgetParent = function (widgetParent) { 1950 if (arguments.length === 0) { 1951 return options.widgetParent; 1952 } 1953 1954 if (typeof widgetParent === 'string') { 1955 widgetParent = $(widgetParent); 1956 } 1957 1958 if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof $))) { 1959 throw new TypeError('widgetParent() expects a string or a jQuery object parameter'); 1960 } 1961 1962 options.widgetParent = widgetParent; 1963 if (widget) { 1964 hide(); 1965 show(); 1966 } 1967 return picker; 1968 }; 1969 1970 picker.keepOpen = function (keepOpen) { 1971 if (arguments.length === 0) { 1972 return options.keepOpen; 1973 } 1974 1975 if (typeof keepOpen !== 'boolean') { 1976 throw new TypeError('keepOpen() expects a boolean parameter'); 1977 } 1978 1979 options.keepOpen = keepOpen; 1980 return picker; 1981 }; 1982 1983 picker.focusOnShow = function (focusOnShow) { 1984 if (arguments.length === 0) { 1985 return options.focusOnShow; 1986 } 1987 1988 if (typeof focusOnShow !== 'boolean') { 1989 throw new TypeError('focusOnShow() expects a boolean parameter'); 1990 } 1991 1992 options.focusOnShow = focusOnShow; 1993 return picker; 1994 }; 1995 1996 picker.inline = function (inline) { 1997 if (arguments.length === 0) { 1998 return options.inline; 1999 } 2000 2001 if (typeof inline !== 'boolean') {
2002 throw new TypeError('inline() expects a boolean parameter'); 2003 } 2004 2005 options.inline = inline; 2006 return picker; 2007 }; 2008 2009 picker.clear = function () { 2010 clear(); 2011 return picker; 2012 }; 2013 2014 picker.keyBinds = function (keyBinds) { 2015 options.keyBinds = keyBinds; 2016 return picker; 2017 }; 2018 2019 picker.debug = function (debug) { 2020 if (typeof debug !== 'boolean') { 2021 throw new TypeError('debug() expects a boolean parameter'); 2022 } 2023 2024 options.debug = debug; 2025 return picker; 2026 }; 2027 2028 picker.allowInputToggle = function (allowInputToggle) { 2029 if (arguments.length === 0) { 2030 return options.allowInputToggle; 2031 } 2032 2033 if (typeof allowInputToggle !== 'boolean') { 2034 throw new TypeError('allowInputToggle() expects a boolean parameter'); 2035 } 2036 2037 options.allowInputToggle = allowInputToggle; 2038 return picker; 2039 }; 2040 2041 picker.showClose = function (showClose) { 2042 if (arguments.length === 0) { 2043 return options.showClose; 2044 } 2045 2046 if (typeof showClose !== 'boolean') { 2047 throw new TypeError('showClose() expects a boolean parameter'); 2048 } 2049 2050 options.showClose = showClose; 2051 return picker; 2052 }; 2053 2054 picker.keepInvalid = function (keepInvalid) { 2055 if (arguments.length === 0) { 2056 return options.keepInvalid; 2057 } 2058 2059 if (typeof keepInvalid !== 'boolean') { 2060 throw new TypeError('keepInvalid() expects a boolean parameter'); 2061 } 2062 options.keepInvalid = keepInvalid; 2063 return picker; 2064 }; 2065 2066 picker.datepickerInput = function (datepickerInput) { 2067 if (arguments.length === 0) { 2068 return options.datepickerInput; 2069 } 2070 2071 if (typeof datepickerInput !== 'string') { 2072 throw new TypeError('datepickerInput() expects a string parameter'); 2073 } 2074 2075 options.datepickerInput = datepickerInput; 2076 return picker; 2077 }; 2078 2079 picker.parseInputDate = function (parseInputDate) { 2080 if (arguments.length === 0) { 2081 return options.parseInputDate; 2082 } 2083 2084 if (typeof parseInputDate !== 'function') { 2085 throw new TypeError('parseInputDate() sholud be as function'); 2086 } 2087 2088 options.parseInputDate = parseInputDate; 2089 2090 return picker; 2091 }; 2092 2093 picker.disabledTimeIntervals = function (disabledTimeIntervals) { 2094 ///<signature helpKeyword="$.fn.datetimepicker.disabledTimeIntervals"> 2095 ///<summary>Returns an array with the currently set disabled dates on the component.</summary> 2096 ///<returns type="array">options.disabledTimeIntervals</returns> 2097 ///</signature> 2098 ///<signature> 2099 ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of 2100 ///options.enabledDates if such exist.</summary> 2101 ///<param name="dates" locid="$.fn.datetimepicker.disabledTimeIntervals_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param> 2102 ///</signature> 2103 if (arguments.length === 0) { 2104 return (options.disabledTimeIntervals ? $.extend({}, options.disabledTimeIntervals) : options.disabledTimeIntervals); 2105 } 2106 2107 if (!disabledTimeIntervals) { 2108 options.disabledTimeIntervals = false; 2109 update(); 2110 return picker; 2111 } 2112 if (!(disabledTimeIntervals instanceof Array)) { 2113 throw new TypeError('disabledTimeIntervals() expects an array parameter'); 2114 } 2115 options.disabledTimeIntervals = disabledTimeIntervals; 2116 update(); 2117 return picker; 2118 }; 2119 2120 picker.disabledHours = function (hours) { 2121 ///<signature helpKeyword="$.fn.datetimepicker.disabledHours"> 2122 ///<summary>Returns an array with the currently set disabled hours on the component.</summary> 2123 ///<returns type="array">options.disabledHours</returns> 2124 ///</signature> 2125 ///<signature> 2126 ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of 2127 ///options.enabledHours if such exist.</summary> 2128 ///<param name="hours" locid="$.fn.datetimepicker.disabledHours_p:hours">Takes an [ int ] of values and disallows the user to select only from those hours.</param> 2129 ///</signature> 2130 if (arguments.length === 0) { 2131 return (options.disabledHours ? $.extend({}, options.disabledHours) : options.disabledHours); 2132 } 2133 2134 if (!hours) { 2135 options.disabledHours = false;
2136 update(); 2137 return picker; 2138 } 2139 if (!(hours instanceof Array)) { 2140 throw new TypeError('disabledHours() expects an array parameter'); 2141 } 2142 options.disabledHours = indexGivenHours(hours); 2143 options.enabledHours = false; 2144 if (options.useCurrent && !options.keepInvalid) { 2145 var tries = 0; 2146 while (!isValid(date, 'h')) { 2147 date.add(1, 'h'); 2148 if (tries === 24) { 2149 throw 'Tried 24 times to find a valid date'; 2150 } 2151 tries++; 2152 } 2153 setValue(date); 2154 } 2155 update(); 2156 return picker; 2157 }; 2158 2159 picker.enabledHours = function (hours) { 2160 ///<signature helpKeyword="$.fn.datetimepicker.enabledHours"> 2161 ///<summary>Returns an array with the currently set enabled hours on the component.</summary> 2162 ///<returns type="array">options.enabledHours</returns> 2163 ///</signature> 2164 ///<signature> 2165 ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledHours if such exist.</summary> 2166 ///<param name="hours" locid="$.fn.datetimepicker.enabledHours_p:hours">Takes an [ int ] of values and allows the user to select only from those hours.</param> 2167 ///</signature> 2168 if (arguments.length === 0) { 2169 return (options.enabledHours ? $.extend({}, options.enabledHours) : options.enabledHours); 2170 } 2171 2172 if (!hours) { 2173 options.enabledHours = false; 2174 update(); 2175 return picker; 2176 } 2177 if (!(hours instanceof Array)) { 2178 throw new TypeError('enabledHours() expects an array parameter'); 2179 } 2180 options.enabledHours = indexGivenHours(hours); 2181 options.disabledHours = false; 2182 if (options.useCurrent && !options.keepInvalid) { 2183 var tries = 0; 2184 while (!isValid(date, 'h')) { 2185 date.add(1, 'h'); 2186 if (tries === 24) { 2187 throw 'Tried 24 times to find a valid date'; 2188 } 2189 tries++; 2190 } 2191 setValue(date); 2192 } 2193 update(); 2194 return picker; 2195 }; 2196 2197 picker.viewDate = function (newDate) { 2198 ///<signature helpKeyword="$.fn.datetimepicker.viewDate"> 2199 ///<summary>Returns the component's model current viewDate, a moment object or null if not set.</summary> 2200 ///<returns type="Moment">viewDate.clone()</returns> 2201 ///</signature> 2202 ///<signature> 2203 ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary> 2204 ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, viewDate, moment, null parameter.</param> 2205 ///</signature> 2206 if (arguments.length === 0) { 2207 return viewDate.clone(); 2208 } 2209 2210 if (!newDate) { 2211 viewDate = date.clone(); 2212 return picker; 2213 } 2214 2215 if (typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) { 2216 throw new TypeError('viewDate() parameter must be one of [string, moment or Date]'); 2217 } 2218 2219 viewDate = parseInputDate(newDate); 2220 viewUpdate(); 2221 return picker; 2222 }; 2223 2224 // initializing element and component attributes 2225 if (element.is('input')) { 2226 input = element; 2227 } else { 2228 input = element.find(options.datepickerInput); 2229 if (input.size() === 0) { 2230 input = element.find('input'); 2231 } else if (!input.is('input')) { 2232 throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element'); 2233 } 2234 } 2235 2236 if (element.hasClass('input-group')) { 2237 // in case there is more then one 'input-group-addon' Issue #48 2238 if (element.find('.datepickerbutton').size() === 0) { 2239 component = element.find('[class^="input-group-"]'); 2240 } else { 2241 component = element.find('.datepickerbutton'); 2242 } 2243 } 2244 2245 if (!options.inline && !input.is('input')) { 2246 throw new Error('Could not initialize DateTimePicker without an input element'); 2247 } 2248 2249 $.extend(true, options, dataToOptions()); 2250 2251 picker.options(options); 2252 2253 initFormatting(); 2254 2255 attachDatePickerElementEvents(); 2256 2257 if (input.prop('disabled')) { 2258 picker.disable(); 2259 } 2260 if (input.is('input') && input.val().trim().length !== 0) { 2261 setValue(parseInputDate(input.val().trim())); 2262 } 2263 else if (options.defaultDate && input.attr('placeholder')
2263=== undefined) { 2264 setValue(options.defaultDate); 2265 } 2266 if (options.inline) { 2267 show(); 2268 } 2269 return picker; 2270 }; 2271 2272 /******************************************************************************** 2273 * 2274 * jQuery plugin constructor and defaults object 2275 * 2276 ********************************************************************************/ 2277 2278 $.fn.datetimepicker = function (options) { 2279 return this.each(function () { 2280 var $this = $(this); 2281 if (!$this.data('DateTimePicker')) { 2282 // create a private copy of the defaults object 2283 options = $.extend(true, {}, $.fn.datetimepicker.defaults, options); 2284 $this.data('DateTimePicker', dateTimePicker($this, options)); 2285 } 2286 }); 2287 }; 2288 2289 $.fn.datetimepicker.defaults = { 2290 format: false, 2291 dayViewHeaderFormat: 'MMMM YYYY', 2292 extraFormats: false, 2293 stepping: 1, 2294 minDate: false, 2295 maxDate: false, 2296 useCurrent: true, 2297 collapse: true, 2298 locale: moment.locale(), 2299 defaultDate: false, 2300 disabledDates: false, 2301 enabledDates: false, 2302 icons: { 2303 time: 'glyphicon glyphicon-time', 2304 date: 'glyphicon glyphicon-calendar', 2305 up: 'glyphicon glyphicon-chevron-up', 2306 down: 'glyphicon glyphicon-chevron-down', 2307 previous: 'glyphicon glyphicon-chevron-left', 2308 next: 'glyphicon glyphicon-chevron-right', 2309 today: 'glyphicon glyphicon-screenshot', 2310 clear: 'glyphicon glyphicon-trash', 2311 close: 'glyphicon glyphicon-remove' 2312 }, 2313 useStrict: false, 2314 sideBySide: false, 2315 daysOfWeekDisabled: false, 2316 calendarWeeks: false, 2317 viewMode: 'days', 2318 toolbarPlacement: 'default', 2319 showTodayButton: false, 2320 showClear: false, 2321 showClose: false, 2322 widgetPositioning: { 2323 horizontal: 'auto', 2324 vertical: 'auto' 2325 }, 2326 widgetParent: null, 2327 ignoreReadonly: false, 2328 keepOpen: false, 2329 focusOnShow: true, 2330 inline: false, 2331 keepInvalid: false, 2332 datepickerInput: '.datepickerinput', 2333 keyBinds: { 2334 up: function (widget) { 2335 if (!widget) { 2336 return; 2337 } 2338 var d = this.date() || moment(); 2339 if (widget.find('.datepicker').is(':visible')) { 2340 this.date(d.clone().subtract(7, 'd')); 2341 } else { 2342 this.date(d.clone().add(1, 'm')); 2343 } 2344 }, 2345 down: function (widget) { 2346 if (!widget) { 2347 this.show(); 2348 return; 2349 } 2350 var d = this.date() || moment(); 2351 if (widget.find('.datepicker').is(':visible')) { 2352 this.date(d.clone().add(7, 'd')); 2353 } else { 2354 this.date(d.clone().subtract(1, 'm')); 2355 } 2356 }, 2357 'control up': function (widget) { 2358 if (!widget) { 2359 return; 2360 } 2361 var d = this.date() || moment(); 2362 if (widget.find('.datepicker').is(':visible')) { 2363 this.date(d.clone().subtract(1, 'y')); 2364 } else { 2365 this.date(d.clone().add(1, 'h')); 2366 } 2367 }, 2368 'control down': function (widget) { 2369 if (!widget) { 2370 return; 2371 } 2372 var d = this.date() || moment(); 2373 if (widget.find('.datepicker').is(':visible')) { 2374 this.date(d.clone().add(1, 'y')); 2375 } else { 2376 this.date(d.clone().subtract(1, 'h')); 2377 } 2378 }, 2379 left: function (widget) { 2380 if (!widget) { 2381 return; 2382 } 2383 var d = this.date() || moment(); 2384 if (widget.find('.datepicker').is(':visible')) { 2385 this.date(d.clone().subtract(1, 'd')); 2386 } 2387 }, 2388 right: function (widget) { 2389 if (!widget) { 2390 return; 2391 } 2392 var d = this.date() || moment(); 2393 if (widget.find('.datepicker').is(':visible')) { 2394 this.date(d.clone().add(1, 'd')); 2395 } 2396 }, 2397 pageUp: function (widget) { 2398 if (!widget) { 2399 return; 2400 } 2401 var d = this.date() || moment(); 2402 if (widget.find('.datepicker').is(':visible')) { 2403 this.date(d.clone().subtract(1, 'M')); 2404 } 2405 }, 2406 pageDown: function (widget) { 2407 if (!widget) { 2408 return; 2409 } 2410 var d = this.date() || moment(); 2411 if (widget.find('.datepicker').is(':visible')) { 2412 this.date(d.clone().add(1, 'M')); 2413 } 2414 }, 2415 enter: function () { 2416 this.hide(); 2417 }, 2418 escape: function () { 2419 this.hide(); 2420 }, 2421 //tab: function (widget) { //this break the flow of the form. disabling for now 2422 // var toggle = widget.find('.picker-switch a[data-action="togglePicker"]'); 2423 // if(toggle.length > 0) toggle.click(); 2424 //}, 2425 'control space': function (widget) { 2426 if (widget.find('.timepicker').is(':visible')) { 2427 widget.find('.btn[data-action="togglePeriod"]').click(); 2428 } 2429 }, 2430 t: function () { 2431 this.date(moment()); 2432 }, 2433 'delete': function () { 2434 this.clear(); 2435 } 2436 }, 2437 debug: false, 2438 allowInputToggle: false, 2439 disabledTimeIntervals: false, 2440 disabledHours: false, 2441 enabledHours: false, 2442 viewDate: false 2443 }; 2444}));
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.