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