PageSourceSearch

https://smartrack.live/lib/angular-bootstrap-datetimepicker/src/js/datetimepicker.js

js smartrack.live collected 2026-10-02 01:05:30 UTC 22,620 bytes, 578 lines download raw bytes

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.