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