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