1/* globals define, jQuery, module, require, angular, moment */ 2/* jslint vars:true */ 3 4/** 5 * @license angular-bootstrap-datetimepicker 6 * Copyright 2016 Knight Rider Consulting, Inc. http://www.knightrider.com 7 * License: MIT 8 * 9 * @author Dale "Ducky" Lotts 10 * @since 2013-Jul-8 11 */ 12 13;(function (root, factory) { 14 'use strict' 15 /* istanbul ignore if */ 16 if (typeof module !== 'undefined' && module.exports) { 17 var ng = typeof angular === 'undefined' ? require('angular') : angular 18 var mt = typeof moment === 'undefined' ? require('moment') : moment 19 factory(ng, mt) 20 module.exports = 'ui.bootstrap.datetimepicker' 21 /* istanbul ignore next */ 22 } else if (typeof define === 'function' && /* istanbul ignore next */ define.amd) { 23 define(['angular', 'moment'], factory) 24 } else { 25 factory(root.angular, root.moment) 26 } 27}(this, function (angular, moment) { 28 'use strict' 29 angular.module('ui.bootstrap.datetimepicker', []) 30 .service('dateTimePickerConfig', DateTimePickerConfigProvider) 31 .service('dateTimePickerValidator', DateTimePickerValidatorService) 32 .directive('datetimepicker', DatetimepickerDirective) 33 34 DatetimepickerDirective.$inject = ['dateTimePickerConfig', 'dateTimePickerValidator'] 35 36 function DatetimepickerDirective (defaultConfig, configurationValidator) { 37 var directiveDefinition = { 38 bindToController: false, 39 controller: DirectiveController, 40 controllerAs: 'dateTimePickerController', 41 replace: true, 42 require: 'ngModel', 43 restrict: 'E', 44 scope: { 45 beforeRender: '&', 46 onSetTime: '&' 47 }, 48 templateUrl: 'templates/datetimepicker.html' 49 } 50 51 DirectiveController.$inject = ['$scope', '$element', '$attrs'] 52 53 function DirectiveController ($scope, $element, $attrs) { 54 // Configuration 55 var ngModelController = $element.controller('ngModel') 56 57 var configuration = createConfiguration() 58 $scope.screenReader = configuration.screenReader 59 60 // Behavior 61 $scope.changeView = changeView 62 ngModelController.$render = $render
63 64 if (configuration.configureOn) { 65 $scope.$on(configuration.configureOn, function () { 66 configuration = createConfiguration() 67 $scope.screenReader = configuration.screenReader 68 ngModelController.$render() 69 }) 70 } 71 72 if (configuration.renderOn) { 73 $scope.$on(configuration.renderOn, ngModelController.$render) 74 } 75 76 // Implementation 77 78 var viewToModelFactory = { 79 year: yearModelFactory, 80 81 month: monthModelFactory, 82 83 day: dayModelFactory, 84 85 hour: hourModelFactory, 86 87 minute: minuteModelFactory, 88 89 setTime: setTime 90 } 91 92 function changeView (viewName, dateObject, event) { 93 if (event) { 94 event.stopPropagation() 95 event.preventDefault() 96 } 97 98 if (viewName && (dateObject.utcDateValue > -Infinity) && dateObject.selectable && viewToModelFactory[viewName]) { 99 var result = viewToModelFactory[viewName](dateObject.utcDateValue) 100 101 var weekDates = [] 102 if (result.weeks) { 103 for (var i = 0; i < result.weeks.length; i += 1) { 104 var week = result.weeks[i] 105 for (var j = 0; j < week.dates.length; j += 1) { 106 var weekDate = week.dates[j] 107 weekDates.push(weekDate) 108 } 109 } 110 } 111 112 $scope.beforeRender({ 113 $view: result.currentView, 114 $dates: result.dates || weekDates, 115 $leftDate: result.leftDate, 116 $upDate: result.previousViewDate, 117 $rightDate: result.rightDate 118 }) 119 120 $scope.data = result 121 } 122 } 123 124 function yearModelFactory (milliseconds) { 125 var selectedDate = moment.utc(milliseconds).startOf('year') 126 // View starts one year before the decade starts and ends one year after the decade ends 127 // i.e. passing in a date of 1/1/2013 will give a range of 2009 to 2020 128 // Truncate the last digit from the current year and subtract 1 to get the start of the decade 129 var startDecade = (parseInt(selectedDate.year() / 10, 10) * 10) 130 var startDate = moment.utc(startOfDecade(milliseconds)).subtract(1, 'year').startOf('year') 131 132 var yearFormat = 'YYYY' 133 var activeFormat = formatValue(ngModelController.$modelValue, yearFormat) 134 var currentFormat = moment().format(yearFormat) 135 136 var result = { 137 'currentView': 'year', 138 'nextView': configuration.minView === 'year' ? 'setTime' : 'month', 139 'previousViewDate': new DateObject({ 140 utcDateValue: null, 141 display: startDecade + '-' + (startDecade + 9) 142 }), 143 'leftDate': new DateObject({utcDateValue: moment.utc(startDate).subtract(9, 'year').valueOf()}), 144 'rightDate': new DateObject({utcDateValue: moment.utc(startDate).add(11, 'year').valueOf()}), 145 'dates': [] 146 } 147 148 for (var i = 0; i < 12; i += 1) { 149 var yearMoment = moment.utc(startDate).add(i, 'years') 150 var dateValue = { 151 'active': yearMoment.format(yearFormat) === activeFormat, 152 'current': yearMoment.format(yearFormat) === currentFormat, 153 'display': yearMoment.format(yearFormat), 154 'future': yearMoment.year() > startDecade + 9, 155 'past': yearMoment.year() < startDecade, 156 'utcDateValue': yearMoment.valueOf() 157 } 158 159 result.dates.push(new DateObject(dateValue)) 160 } 161 162 return result 163 } 164 165 function monthModelFactory (milliseconds) { 166 var startDate = moment.utc(milliseconds).startOf('year') 167 var previousViewDate = startOfDecade(milliseconds) 168 169 var monthFormat = 'YYYY-MMM' 170 var activeFormat = formatValue(ngModelController.$modelValue, monthFormat) 171 var currentFormat = moment().format(monthFormat) 172 173 var result = { 174 'previousView': 'year', 175 'currentView': 'month', 176 'nextView': configuration.minView === 'month' ? 'setTime' : 'day', 177 'previousViewDate': new DateObject({ 178 utcDateValue: previousViewDate.valueOf(), 179 display: startDate.format('YYYY') 180 }), 181 'leftDate': new DateObject({utcDateValue: moment.utc(startDate).subtract(1, 'year').valueOf()}), 182 'rightDate': new DateObject({utcDateValue: moment.utc(startDate).add(1, 'year').valueOf()}), 183 'dates': [] 184 } 185 186 for (var i = 0; i < 12; i += 1) { 187 var monthMoment = moment.utc(startDate).add(i, 'months') 188 var dateValue = { 189 'active': monthMoment.format(monthFormat) === activeFormat, 190 'current': monthMoment.format(monthFormat) === currentFormat, 191 'display': monthMoment.format('MMM'), 192 'utcDateValue': monthMoment.valueOf() 193 } 194 195 result.dates.push(new DateObject(dateValue)) 196 } 197 198 return result 199 } 200 201 function dayModelFactory (milliseconds) { 202 var selectedDate = moment.utc(milliseconds) 203 var startOfMonth = moment.utc(selectedDate).startOf('month') 204 var previousViewDate = moment.utc(selectedDate).startOf('year') 205 var endOfMonth = moment.utc(selectedDate).endOf('month') 206 207 var startDate = moment.utc(startOfMonth).subtract(Math.abs(startOfMonth.weekday()), 'days') 208 209 var dayFormat = 'YYYY-MMM-DD' 210 var activeFormat = formatValue(ngModelController.$modelValue, dayFormat) 211 var currentFormat = moment().format(dayFormat) 212 213 var result = { 214 'previousView': 'month', 215 'currentView': 'day', 216 'nextView': configuration.minView === 'day' ? 'setTime' : 'hour', 217 'previousViewDate': new DateObject({ 218 utcDateValue: previousViewDate.valueOf(), 219 display: startOfMonth.format('YYYY-MMM') 220 }), 221 'leftDate': new DateObject({utcDateValue: moment.utc(startOfMonth).subtract(1, 'months').valueOf()}), 222 'rightDate': new DateObject({utcDateValue: moment.utc(startOfMonth).add(1, 'months').valueOf()}), 223 'dayNames': [], 224 'weeks': [] 225 } 226 227 for (var dayNumber = 0; dayNumber < 7; dayNumber += 1) { 228 result.dayNames.push(moment.utc().weekday(dayNumber).format('dd')) 229 } 230 231 for (var i = 0; i < 6; i += 1) { 232 var week = {dates: []} 233 for (var j = 0; j < 7; j += 1) { 234 var dayMoment = moment.utc(startDate).add((i * 7) + j, 'days') 235 var dateValue = { 236 'active': dayMoment.format(dayFormat) === activeFormat, 237 'current': dayMoment.format(dayFormat) === currentFormat, 238 'display': dayMoment.format('D'), 239 'future': dayMoment.isAfter(endOfMonth), 240 'past': dayMoment.isBefore(startOfMonth), 241 'utcDateValue': dayMoment.valueOf() 242 } 243 week.dates.push(new DateObject(dateValue)) 244 } 245 result.weeks.push(week) 246 } 247 248 return result 249 } 250 251 function hourModelFactory (milliseconds) { 252 var selectedDate = moment.utc(milliseconds).startOf('day') 253 var previousViewDate = moment.utc(selectedDate).startOf('month') 254 255 var hourFormat = 'YYYY-MM-DD H' 256 var activeFormat = formatValue(ngModelController.$modelValue, hourFormat) 257 var currentFormat = moment().format(hourFormat) 258 259 var result = { 260 'previousView': 'day', 261 'currentView': 'hour', 262 'nextView': configuration.minView === 'hour' ? 'setTime' : 'minute', 263 'previousViewDate': new DateObject({ 264 utcDateValue: previousViewDate.valueOf(), 265 display: selectedDate.format('ll') 266 }), 267 'leftDate': new DateObject({utcDateValue: moment.utc(selectedDate).subtract(1, 'days').valueOf()}), 268 'rightDate': new DateObject({utcDateValue: moment.utc(selectedDate).add(1, 'days').valueOf()}), 269 'dates': [] 270 } 271 272 for (var i = 0; i < 24; i += 1) { 273 var hourMoment = moment.utc(selectedDate).add(i, 'hours') 274 var dateValue = { 275 'active': hourMoment.format(hourFormat) === activeFormat, 276 'current': hourMoment.format(hourFormat) === currentFormat, 277 'display': hourMoment.format('LT'), 278 'utcDateValue': hourMoment.valueOf() 279 } 280 281 result.dates.push(new DateObject(dateValue)) 282 } 283 284 return result 285 } 286 287 function minuteModelFactory (milliseconds) { 288 var selectedDate = moment.utc(milliseconds).startOf('hour') 289 var previousViewDate = moment.utc(selectedDate).startOf('day') 290 291 var minuteFormat = 'YYYY-MM-DD H:mm' 292 var activeFormat = formatValue(ngModelController.$modelValue, minuteFormat) 293 var currentFormat = moment().format(minuteFormat) 294 295 var result = { 296 'previousView': 'hour', 297 'currentView': 'minute', 298 'nextView': 'setTime', 299 'previousViewDate': new DateObject({ 300 utcDateValue: previousViewDate.valueOf(), 301 display: selectedDate.format('lll') 302 }), 303 'leftDate': new DateObject({utcDateValue: moment.utc(selectedDate).subtract(1, 'hours').valueOf()}), 304 'rightDate': new DateObject({utcDateValue: moment.utc(selectedDate).add(1, 'hours').valueOf()}), 305 'dates': [] 306 } 307 308 var limit = 60 / configuration.minuteStep 309 310 for (var i = 0; i < limit; i += 1) { 311 var hourMoment = moment.utc(selectedDate).add(i * configuration.minuteStep, 'minute') 312 var dateValue = { 313 'active': hourMoment.format(minuteFormat) === activeFormat, 314 'current': hourMoment.format(minuteFormat) === currentFormat, 315 'display': hourMoment.format('LT'), 316 'utcDateValue': hourMoment.valueOf() 317 } 318 319 result.dates.push(new DateObject(dateValue)) 320 } 321 322 return result 323 } 324 325 function setTime (milliseconds) { 326 var tempDate = new Date(milliseconds) 327 var newDate = new Date(tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds(), tempDate.getUTCMilliseconds()) 328 329 switch (configuration.modelType) { 330 case 'Date': 331 // No additional work needed 332 break 333 case 'moment': 334 newDate = moment([tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds(), tempDate.getUTCMilliseconds()]) 335 break 336 case 'milliseconds': 337 newDate = milliseconds 338 break 339 default: // It is assumed that the modelType is a formatting string. 340 newDate = moment([tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds(), tempDate.getUTCMilliseconds()]).format(configuration.modelType) 341 } 342 343 var oldDate = ngModelController.$modelValue 344 ngModelController.$setViewValue(newDate) 345 346 if (configuration.dropdownSelector) { 347 jQuery(configuration.dropdownSelector).dropdown('toggle') 348 } 349 350 $scope.onSetTime({newDate: newDate, oldDate: oldDate}) 351 352 return viewToModelFactory[configuration.startView](milliseconds) 353 } 354 355 function $render () { 356 $scope.changeView(configuration.startView, new DateObject({utcDateValue: getUTCTime(ngModelController.$viewValue)})) 357 } 358 359 function startOfDecade (milliseconds) { 360 var startYear = (parseInt(moment.utc(milliseconds).year() / 10, 10) * 10) 361 return moment.utc(milliseconds).year(startYear).startOf('year') 362 } 363 364 function formatValue (timeValue, formatString) { 365 if (timeValue) { 366 return getMoment(timeValue).format(formatString) 367 } else { 368 return '' 369 } 370 } 371 372 /** 373 * Converts a time value into a moment. 374 * 375 * This function is now necessary because moment logs a warning when parsing a string without a format. 376 * @param modelValue 377 * a time value in any of the supported formats (Date, moment, milliseconds, and string) 378 * @returns {moment} 379 * representing the specified time value. 380 */ 381 382 function getMoment (modelValue) { 383 return moment(modelValue, angular.isString(modelValue) ? configuration.parseFormat : undefined) 384 } 385 386 /** 387 * Converts a time value to UCT/GMT time. 388 * @param modelValue 389 * a time value in any of the supported formats (Date, moment, milliseconds, and string) 390 * @returns {number} 391 * number of milliseconds since 1/1/1970 392 */ 393 394 function getUTCTime (modelValue) { 395 var tempDate = new Date() 396 if (modelValue) { 397 var tempMoment = getMoment(modelValue) 398 if (tempMoment.isValid()) { 399 tempDate = tempMoment.toDate() 400 } else { 401 throw new Error('Invalid date: ' + modelValue) 402 } 403 } 404 return tempDate.getTime() - (tempDate.getTimezoneOffset() * 60000) 405 } 406 407 function createConfiguration () { 408 var directiveConfig = {} 409 410 if ($attrs.datetimepickerConfig) { 411 directiveConfig = $scope.$parent.$eval($attrs.datetimepickerConfig) 412 } 413 414 var configuration = angular.extend({}, defaultConfig, directiveConfig) 415 416 configurationValidator.validate(configuration) 417 418 return configuration 419 } 420 } 421 422 function DateObject () { 423 var tempDate = new Date(arguments[0].utcDateValue) 424 var localOffset = tempDate.getTimezoneOffset() * 60000 425 426 this.utcDateValue = tempDate.getTime() 427 this.selectable = true 428 429 this.localDateValue = function localDateValue () { 430 return this.utcDateValue + localOffset 431 } 432
433 var validProperties = ['active', 'current', 'display', 'future', 'past', 'selectable', 'utcDateValue'] 434 435 var constructorObject = arguments[0] 436 437 Object.keys(constructorObject).filter(function (key) { 438 return validProperties.indexOf(key) >= 0 439 }).forEach(function (key) { 440 this[key] = constructorObject[key] 441 }, this) 442 } 443 444 return directiveDefinition 445 } 446 447 function DateTimePickerConfigProvider () { 448 var defaultConfiguration = { 449 configureOn: null, 450 dropdownSelector: null, 451 minuteStep: 5, 452 minView: 'minute', 453 modelType: 'Date', 454 parseFormat: 'YYYY-MM-DDTHH:mm:ss.SSSZZ', 455 renderOn: null, 456 startView: 'day' 457 } 458 459 var defaultLocalization = { 460 'bg': {previous: 'пÑедиÑна', next: 'ÑледваÑа'}, 461 'ca': {previous: 'anterior', next: 'següent'}, 462 'da': {previous: 'forrige', next: 'næste'}, 463 'de': {previous: 'vorige', next: 'weiter'}, 464 'en-au': {previous: 'previous', next: 'next'}, 465 'en-gb': {previous: 'previous', next: 'next'}, 466 'en': {previous: 'previous', next: 'next'}, 467 'es-us': {previous: 'atrás', next: 'siguiente'}, 468 'es': {previous: 'atrás', next: 'siguiente'}, 469 'fi': {previous: 'edellinen', next: 'seuraava'}, 470 'fr': {previous: 'précédent', next: 'suivant'}, 471 'hu': {previous: 'elÅzÅ', next: 'következÅ'}, 472 'it': {previous: 'precedente', next: 'successivo'}, 473 'ja': {previous: 'åã¸', next: '次ã¸'}, 474 'ml': {previous: 'à´®àµàµ»à´ªàµà´³àµà´³à´¤àµ', next: 'à´ à´àµà´¤àµà´¤à´¤àµ'}, 475 'nl': {previous: 'vorige', next: 'volgende'}, 476 'pl': {previous: 'poprzednia', next: 'nastÄpna'}, 477 'pt-br': {previous: 'anteriores', next: 'próximos'}, 478 'pt': {previous: 'anterior', next: 'próximo'}, 479 'ro': {previous: 'anterior', next: 'urmÄtor'}, 480 'ru': {previous: 'пÑедÑдÑÑаÑ', next: 'ÑледÑÑÑаÑ'}, 481 'sk': {previous: 'predoÅ¡lá', next: 'ÄalÅ¡ia'}, 482 'sv': {previous: 'föregÃ¥ende', next: 'nästa'}, 483 'tr': {previous: 'önceki', next: 'sonraki'}, 484 'uk': {previous: 'назад', next: 'далÑ'}, 485 'zh-cn': {previous: 'ä¸ä¸é¡µ', next: 'ä¸ä¸é¡µ'}, 486 'zh-tw': {previous: 'ä¸ä¸é ', next: 'ä¸ä¸é '} 487 } 488 489 var screenReader = defaultLocalization[moment.locale().toLowerCase()] 490 491 return angular.extend({}, defaultConfiguration, {screenReader: screenReader}) 492 } 493 494 DateTimePickerValidatorService.$inject = ['$log'] 495 496 function DateTimePickerValidatorService ($log) { 497 return { 498 validate: validator 499 } 500 501 function validator (configuration) { 502 var validOptions = [ 503 'configureOn', 504 'dropdownSelector', 505 'minuteStep', 506 'minView', 507 'modelType', 508 'parseFormat', 509 'renderOn', 510 'startView', 511 'screenReader' 512 ] 513 514 var invalidOptions = Object.keys(configuration).filter(function (key) { 515 return (validOptions.indexOf(key) < 0) 516 }) 517 518 if (invalidOptions.length) { 519 throw new Error('Invalid options: ' + invalidOptions.join(', ')) 520 } 521 522 // Order of the elements in the validViews array is significant. 523 var validViews = ['minute', 'hour', 'day', 'month', 'year'] 524 525 if (validViews.indexOf(configuration.startView) < 0) { 526 throw new Error('invalid startView value: ' + configuration.startView) 527 } 528 529 if (validViews.indexOf(configuration.minView) < 0) { 530 throw new Error('invalid minView value: ' + configuration.minView) 531 } 532 533 if (validViews.indexOf(configuration.minView) > validViews.indexOf(configuration.startView)) { 534 throw new Error('startView must be greater than minView') 535 } 536 537 if (!angular.isNumber(configuration.minuteStep)) { 538 throw new Error('minuteStep must be numeric') 539 } 540 if (configuration.minuteStep <= 0 || configuration.minuteStep >= 60) { 541 throw new Error('minuteStep must be greater than zero and less than 60') 542 } 543 if (configuration.configureOn !== null && !angular.isString(configuration.configureOn)) { 544 throw new Error('configureOn must be a string') 545 } 546 if (configuration.configureOn !== null && configuration.configureOn.length < 1) { 547 throw new Error('configureOn must not be an empty string') 548 } 549 if (configuration.renderOn !== null && !angular.isString(configuration.renderOn)) { 550 throw new Error('renderOn must be a string') 551 } 552 if (configuration.renderOn !== null && configuration.renderOn.length < 1) { 553 throw new Error('renderOn must not be an empty string') 554 } 555 if (configuration.modelType !== null && !angular.isString(configuration.modelType)) { 556 throw new Error('modelType must be a string') 557 } 558 if (configuration.modelType !== null && configuration.modelType.length < 1) { 559 throw new Error('modelType must not be an empty string') 560 } 561 if (configuration.modelType !== 'Date' && configuration.modelType !== 'moment' && configuration.modelType !== 'milliseconds') { 562 // modelType contains string format, overriding parseFormat with modelType 563 configuration.parseFormat = configuration.modelType 564 } 565 if (configuration.dropdownSelector !== null && !angular.isString(configuration.dropdownSelector)) { 566 throw new Error('dropdownSelector must be a string') 567 } 568 569 /* istanbul ignore next */ 570 if (configuration.dropdownSelector !== null && ((typeof jQuery === 'undefined') || (typeof jQuery().dropdown !== 'function'))) { 571 $log.error('Please DO NOT specify the dropdownSelector option unless you are using jQuery AND Bootstrap.js. ' + 572 'Please include jQuery AND Bootstrap.js, or write code to close the dropdown in the on-set-time callback. \n\n' + 573 'The dropdownSelector configuration option is being removed because it will not function properly.') 574 delete configuration.dropdownSelector 575 } 576 } 577 } 578}))
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.