123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- /* globals define, jQuery, module, require, angular, moment */
- /* jslint vars:true */
- /**
- * @license angular-bootstrap-datetimepicker
- * Copyright 2016 Knight Rider Consulting, Inc. http://www.knightrider.com
- * License: MIT
- *
- * @author Dale "Ducky" Lotts
- * @since 2013-Jul-8
- */
- ;(function (root, factory) {
- 'use strict'
- /* istanbul ignore if */
- if (typeof module !== 'undefined' && module.exports) {
- var ng = typeof angular === 'undefined' ? require('angular') : angular
- var mt = typeof moment === 'undefined' ? require('moment') : moment
- factory(ng, mt)
- module.exports = 'ui.bootstrap.datetimepicker'
- /* istanbul ignore next */
- } else if (typeof define === 'function' && /* istanbul ignore next */ define.amd) {
- define(['angular', 'moment'], factory)
- } else {
- factory(root.angular, root.moment)
- }
- }(this, function (angular, moment) {
- 'use strict'
- angular.module('ui.bootstrap.datetimepicker', [])
- .service('dateTimePickerConfig', DateTimePickerConfigProvider)
- .service('dateTimePickerValidator', DateTimePickerValidatorService)
- .directive('datetimepicker', DatetimepickerDirective)
- DatetimepickerDirective.$inject = ['dateTimePickerConfig', 'dateTimePickerValidator']
- function DatetimepickerDirective (defaultConfig, configurationValidator) {
- var directiveDefinition = {
- bindToController: false,
- controller: DirectiveController,
- controllerAs: 'dateTimePickerController',
- replace: true,
- require: 'ngModel',
- restrict: 'E',
- scope: {
- beforeRender: '&',
- onSetTime: '&'
- },
- templateUrl: 'templates/datetimepicker.html'
- }
- DirectiveController.$inject = ['$scope', '$element', '$attrs']
- function DirectiveController ($scope, $element, $attrs) {
- // Configuration
- var ngModelController = $element.controller('ngModel')
- var configuration = createConfiguration()
- $scope.screenReader = configuration.screenReader
- // Behavior
- $scope.changeView = changeView
- ngModelController.$render = $render
- if (configuration.configureOn) {
- $scope.$on(configuration.configureOn, function () {
- configuration = createConfiguration()
- $scope.screenReader = configuration.screenReader
- ngModelController.$render()
- })
- }
- if (configuration.renderOn) {
- $scope.$on(configuration.renderOn, ngModelController.$render)
- }
- // Implementation
- var viewToModelFactory = {
- year: yearModelFactory,
- month: monthModelFactory,
- day: dayModelFactory,
- hour: hourModelFactory,
- minute: minuteModelFactory,
- setTime: setTime
- }
- function changeView (viewName, dateObject, event) {
- if (event) {
- event.stopPropagation()
- event.preventDefault()
- }
- if (viewName && (dateObject.utcDateValue > -Infinity) && dateObject.selectable && viewToModelFactory[viewName]) {
- var result = viewToModelFactory[viewName](dateObject.utcDateValue)
- var weekDates = []
- if (result.weeks) {
- for (var i = 0; i < result.weeks.length; i += 1) {
- var week = result.weeks[i]
- for (var j = 0; j < week.dates.length; j += 1) {
- var weekDate = week.dates[j]
- weekDates.push(weekDate)
- }
- }
- }
- $scope.beforeRender({
- $view: result.currentView,
- $dates: result.dates || weekDates,
- $leftDate: result.leftDate,
- $upDate: result.previousViewDate,
- $rightDate: result.rightDate
- })
- $scope.data = result
- }
- }
- function yearModelFactory (milliseconds) {
- var selectedDate = moment.utc(milliseconds).startOf('year')
- // View starts one year before the decade starts and ends one year after the decade ends
- // i.e. passing in a date of 1/1/2013 will give a range of 2009 to 2020
- // Truncate the last digit from the current year and subtract 1 to get the start of the decade
- var startDecade = (parseInt(selectedDate.year() / 10, 10) * 10)
- var startDate = moment.utc(startOfDecade(milliseconds)).subtract(1, 'year').startOf('year')
- var yearFormat = 'YYYY'
- var activeFormat = formatValue(ngModelController.$modelValue, yearFormat)
- var currentFormat = moment().format(yearFormat)
- var result = {
- 'currentView': 'year',
- 'nextView': configuration.minView === 'year' ? 'setTime' : 'month',
- 'previousViewDate': new DateObject({
- utcDateValue: null,
- display: startDecade + '-' + (startDecade + 9)
- }),
- 'leftDate': new DateObject({utcDateValue: moment.utc(startDate).subtract(9, 'year').valueOf()}),
- 'rightDate': new DateObject({utcDateValue: moment.utc(startDate).add(11, 'year').valueOf()}),
- 'dates': []
- }
- for (var i = 0; i < 12; i += 1) {
- var yearMoment = moment.utc(startDate).add(i, 'years')
- var dateValue = {
- 'active': yearMoment.format(yearFormat) === activeFormat,
- 'current': yearMoment.format(yearFormat) === currentFormat,
- 'display': yearMoment.format(yearFormat),
- 'future': yearMoment.year() > startDecade + 9,
- 'past': yearMoment.year() < startDecade,
- 'utcDateValue': yearMoment.valueOf()
- }
- result.dates.push(new DateObject(dateValue))
- }
- return result
- }
- function monthModelFactory (milliseconds) {
- var startDate = moment.utc(milliseconds).startOf('year')
- var previousViewDate = startOfDecade(milliseconds)
- var monthFormat = 'YYYY-MMM'
- var activeFormat = formatValue(ngModelController.$modelValue, monthFormat)
- var currentFormat = moment().format(monthFormat)
- var result = {
- 'previousView': 'year',
- 'currentView': 'month',
- 'nextView': configuration.minView === 'month' ? 'setTime' : 'day',
- 'previousViewDate': new DateObject({
- utcDateValue: previousViewDate.valueOf(),
- display: startDate.format('YYYY')
- }),
- 'leftDate': new DateObject({utcDateValue: moment.utc(startDate).subtract(1, 'year').valueOf()}),
- 'rightDate': new DateObject({utcDateValue: moment.utc(startDate).add(1, 'year').valueOf()}),
- 'dates': []
- }
- for (var i = 0; i < 12; i += 1) {
- var monthMoment = moment.utc(startDate).add(i, 'months')
- var dateValue = {
- 'active': monthMoment.format(monthFormat) === activeFormat,
- 'current': monthMoment.format(monthFormat) === currentFormat,
- 'display': monthMoment.format('MMM'),
- 'utcDateValue': monthMoment.valueOf()
- }
- result.dates.push(new DateObject(dateValue))
- }
- return result
- }
- function dayModelFactory (milliseconds) {
- var selectedDate = moment.utc(milliseconds)
- var startOfMonth = moment.utc(selectedDate).startOf('month')
- var previousViewDate = moment.utc(selectedDate).startOf('year')
- var endOfMonth = moment.utc(selectedDate).endOf('month')
- var startDate = moment.utc(startOfMonth).subtract(Math.abs(startOfMonth.weekday()), 'days')
- var dayFormat = 'YYYY-MMM-DD'
- var activeFormat = formatValue(ngModelController.$modelValue, dayFormat)
- var currentFormat = moment().format(dayFormat)
- var result = {
- 'previousView': 'month',
- 'currentView': 'day',
- 'nextView': configuration.minView === 'day' ? 'setTime' : 'hour',
- 'previousViewDate': new DateObject({
- utcDateValue: previousViewDate.valueOf(),
- display: startOfMonth.format('YYYY-MMM')
- }),
- 'leftDate': new DateObject({utcDateValue: moment.utc(startOfMonth).subtract(1, 'months').valueOf()}),
- 'rightDate': new DateObject({utcDateValue: moment.utc(startOfMonth).add(1, 'months').valueOf()}),
- 'dayNames': [],
- 'weeks': []
- }
- for (var dayNumber = 0; dayNumber < 7; dayNumber += 1) {
- result.dayNames.push(moment.utc().weekday(dayNumber).format('dd'))
- }
- for (var i = 0; i < 6; i += 1) {
- var week = {dates: []}
- for (var j = 0; j < 7; j += 1) {
- var dayMoment = moment.utc(startDate).add((i * 7) + j, 'days')
- var dateValue = {
- 'active': dayMoment.format(dayFormat) === activeFormat,
- 'current': dayMoment.format(dayFormat) === currentFormat,
- 'display': dayMoment.format('D'),
- 'future': dayMoment.isAfter(endOfMonth),
- 'past': dayMoment.isBefore(startOfMonth),
- 'utcDateValue': dayMoment.valueOf()
- }
- week.dates.push(new DateObject(dateValue))
- }
- result.weeks.push(week)
- }
- return result
- }
- function hourModelFactory (milliseconds) {
- var selectedDate = moment.utc(milliseconds).startOf('day')
- var previousViewDate = moment.utc(selectedDate).startOf('month')
- var hourFormat = 'YYYY-MM-DD H'
- var activeFormat = formatValue(ngModelController.$modelValue, hourFormat)
- var currentFormat = moment().format(hourFormat)
- var result = {
- 'previousView': 'day',
- 'currentView': 'hour',
- 'nextView': configuration.minView === 'hour' ? 'setTime' : 'minute',
- 'previousViewDate': new DateObject({
- utcDateValue: previousViewDate.valueOf(),
- display: selectedDate.format('ll')
- }),
- 'leftDate': new DateObject({utcDateValue: moment.utc(selectedDate).subtract(1, 'days').valueOf()}),
- 'rightDate': new DateObject({utcDateValue: moment.utc(selectedDate).add(1, 'days').valueOf()}),
- 'dates': []
- }
- for (var i = 0; i < 24; i += 1) {
- var hourMoment = moment.utc(selectedDate).add(i, 'hours')
- var dateValue = {
- 'active': hourMoment.format(hourFormat) === activeFormat,
- 'current': hourMoment.format(hourFormat) === currentFormat,
- 'display': hourMoment.format('LT'),
- 'utcDateValue': hourMoment.valueOf()
- }
- result.dates.push(new DateObject(dateValue))
- }
- return result
- }
- function minuteModelFactory (milliseconds) {
- var selectedDate = moment.utc(milliseconds).startOf('hour')
- var previousViewDate = moment.utc(selectedDate).startOf('day')
- var minuteFormat = 'YYYY-MM-DD H:mm'
- var activeFormat = formatValue(ngModelController.$modelValue, minuteFormat)
- var currentFormat = moment().format(minuteFormat)
- var result = {
- 'previousView': 'hour',
- 'currentView': 'minute',
- 'nextView': 'setTime',
- 'previousViewDate': new DateObject({
- utcDateValue: previousViewDate.valueOf(),
- display: selectedDate.format('lll')
- }),
- 'leftDate': new DateObject({utcDateValue: moment.utc(selectedDate).subtract(1, 'hours').valueOf()}),
- 'rightDate': new DateObject({utcDateValue: moment.utc(selectedDate).add(1, 'hours').valueOf()}),
- 'dates': []
- }
- var limit = 60 / configuration.minuteStep
- for (var i = 0; i < limit; i += 1) {
- var hourMoment = moment.utc(selectedDate).add(i * configuration.minuteStep, 'minute')
- var dateValue = {
- 'active': hourMoment.format(minuteFormat) === activeFormat,
- 'current': hourMoment.format(minuteFormat) === currentFormat,
- 'display': hourMoment.format('LT'),
- 'utcDateValue': hourMoment.valueOf()
- }
- result.dates.push(new DateObject(dateValue))
- }
- return result
- }
- function setTime (milliseconds) {
- var tempDate = new Date(milliseconds)
- var newDate = new Date(tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds(), tempDate.getUTCMilliseconds())
- switch (configuration.modelType) {
- case 'Date':
- // No additional work needed
- break
- case 'moment':
- newDate = moment([tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds(), tempDate.getUTCMilliseconds()])
- break
- case 'milliseconds':
- newDate = milliseconds
- break
- default: // It is assumed that the modelType is a formatting string.
- newDate = moment([tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds(), tempDate.getUTCMilliseconds()]).format(configuration.modelType)
- }
- var oldDate = ngModelController.$modelValue
- ngModelController.$setViewValue(newDate)
- if (configuration.dropdownSelector) {
- jQuery(configuration.dropdownSelector).dropdown('toggle')
- }
- $scope.onSetTime({newDate: newDate, oldDate: oldDate})
- return viewToModelFactory[configuration.startView](milliseconds)
- }
- function $render () {
- $scope.changeView(configuration.startView, new DateObject({utcDateValue: getUTCTime(ngModelController.$viewValue)}))
- }
- function startOfDecade (milliseconds) {
- var startYear = (parseInt(moment.utc(milliseconds).year() / 10, 10) * 10)
- return moment.utc(milliseconds).year(startYear).startOf('year')
- }
- function formatValue (timeValue, formatString) {
- if (timeValue) {
- return getMoment(timeValue).format(formatString)
- } else {
- return ''
- }
- }
- /**
- * Converts a time value into a moment.
- *
- * This function is now necessary because moment logs a warning when parsing a string without a format.
- * @param modelValue
- * a time value in any of the supported formats (Date, moment, milliseconds, and string)
- * @returns {moment}
- * representing the specified time value.
- */
- function getMoment (modelValue) {
- return moment(modelValue, angular.isString(modelValue) ? configuration.parseFormat : undefined)
- }
- /**
- * Converts a time value to UCT/GMT time.
- * @param modelValue
- * a time value in any of the supported formats (Date, moment, milliseconds, and string)
- * @returns {number}
- * number of milliseconds since 1/1/1970
- */
- function getUTCTime (modelValue) {
- var tempDate = new Date()
- if (modelValue) {
- var tempMoment = getMoment(modelValue)
- if (tempMoment.isValid()) {
- tempDate = tempMoment.toDate()
- } else {
- throw new Error('Invalid date: ' + modelValue)
- }
- }
- return tempDate.getTime() - (tempDate.getTimezoneOffset() * 60000)
- }
- function createConfiguration () {
- var directiveConfig = {}
- if ($attrs.datetimepickerConfig) {
- directiveConfig = $scope.$parent.$eval($attrs.datetimepickerConfig)
- }
- var configuration = angular.extend({}, defaultConfig, directiveConfig)
- configurationValidator.validate(configuration)
- return configuration
- }
- }
- function DateObject () {
- var tempDate = new Date(arguments[0].utcDateValue)
- var localOffset = tempDate.getTimezoneOffset() * 60000
- this.utcDateValue = tempDate.getTime()
- this.selectable = true
- this.localDateValue = function localDateValue () {
- return this.utcDateValue + localOffset
- }
- var validProperties = ['active', 'current', 'display', 'future', 'past', 'selectable', 'utcDateValue']
- var constructorObject = arguments[0]
- Object.keys(constructorObject).filter(function (key) {
- return validProperties.indexOf(key) >= 0
- }).forEach(function (key) {
- this[key] = constructorObject[key]
- }, this)
- }
- return directiveDefinition
- }
- function DateTimePickerConfigProvider () {
- var defaultConfiguration = {
- configureOn: null,
- dropdownSelector: null,
- minuteStep: 5,
- minView: 'minute',
- modelType: 'Date',
- parseFormat: 'YYYY-MM-DDTHH:mm:ss.SSSZZ',
- renderOn: null,
- startView: 'day'
- }
- var defaultLocalization = {
- 'bg': {previous: 'предишна', next: 'следваща'},
- 'ca': {previous: 'anterior', next: 'següent'},
- 'da': {previous: 'forrige', next: 'næste'},
- 'de': {previous: 'vorige', next: 'weiter'},
- 'en-au': {previous: 'previous', next: 'next'},
- 'en-gb': {previous: 'previous', next: 'next'},
- 'en': {previous: 'previous', next: 'next'},
- 'es-us': {previous: 'atrás', next: 'siguiente'},
- 'es': {previous: 'atrás', next: 'siguiente'},
- 'fi': {previous: 'edellinen', next: 'seuraava'},
- 'fr': {previous: 'précédent', next: 'suivant'},
- 'hu': {previous: 'előző', next: 'következő'},
- 'it': {previous: 'precedente', next: 'successivo'},
- 'ja': {previous: '前へ', next: '次へ'},
- 'ml': {previous: 'മുൻപുള്ളത്', next: 'അടുത്തത്'},
- 'nl': {previous: 'vorige', next: 'volgende'},
- 'pl': {previous: 'poprzednia', next: 'następna'},
- 'pt-br': {previous: 'anteriores', next: 'próximos'},
- 'pt': {previous: 'anterior', next: 'próximo'},
- 'ro': {previous: 'anterior', next: 'următor'},
- 'ru': {previous: 'предыдущая', next: 'следующая'},
- 'sk': {previous: 'predošlá', next: 'ďalšia'},
- 'sv': {previous: 'föregående', next: 'nästa'},
- 'tr': {previous: 'önceki', next: 'sonraki'},
- 'uk': {previous: 'назад', next: 'далі'},
- 'zh-cn': {previous: '上一页', next: '下一页'},
- 'zh-tw': {previous: '上一頁', next: '下一頁'}
- }
- var screenReader = defaultLocalization[moment.locale().toLowerCase()]
- return angular.extend({}, defaultConfiguration, {screenReader: screenReader})
- }
- DateTimePickerValidatorService.$inject = ['$log']
- function DateTimePickerValidatorService ($log) {
- return {
- validate: validator
- }
- function validator (configuration) {
- var validOptions = [
- 'configureOn',
- 'dropdownSelector',
- 'minuteStep',
- 'minView',
- 'modelType',
- 'parseFormat',
- 'renderOn',
- 'startView',
- 'screenReader'
- ]
- var invalidOptions = Object.keys(configuration).filter(function (key) {
- return (validOptions.indexOf(key) < 0)
- })
- if (invalidOptions.length) {
- throw new Error('Invalid options: ' + invalidOptions.join(', '))
- }
- // Order of the elements in the validViews array is significant.
- var validViews = ['minute', 'hour', 'day', 'month', 'year']
- if (validViews.indexOf(configuration.startView) < 0) {
- throw new Error('invalid startView value: ' + configuration.startView)
- }
- if (validViews.indexOf(configuration.minView) < 0) {
- throw new Error('invalid minView value: ' + configuration.minView)
- }
- if (validViews.indexOf(configuration.minView) > validViews.indexOf(configuration.startView)) {
- throw new Error('startView must be greater than minView')
- }
- if (!angular.isNumber(configuration.minuteStep)) {
- throw new Error('minuteStep must be numeric')
- }
- if (configuration.minuteStep <= 0 || configuration.minuteStep >= 60) {
- throw new Error('minuteStep must be greater than zero and less than 60')
- }
- if (configuration.configureOn !== null && !angular.isString(configuration.configureOn)) {
- throw new Error('configureOn must be a string')
- }
- if (configuration.configureOn !== null && configuration.configureOn.length < 1) {
- throw new Error('configureOn must not be an empty string')
- }
- if (configuration.renderOn !== null && !angular.isString(configuration.renderOn)) {
- throw new Error('renderOn must be a string')
- }
- if (configuration.renderOn !== null && configuration.renderOn.length < 1) {
- throw new Error('renderOn must not be an empty string')
- }
- if (configuration.modelType !== null && !angular.isString(configuration.modelType)) {
- throw new Error('modelType must be a string')
- }
- if (configuration.modelType !== null && configuration.modelType.length < 1) {
- throw new Error('modelType must not be an empty string')
- }
- if (configuration.modelType !== 'Date' && configuration.modelType !== 'moment' && configuration.modelType !== 'milliseconds') {
- // modelType contains string format, overriding parseFormat with modelType
- configuration.parseFormat = configuration.modelType
- }
- if (configuration.dropdownSelector !== null && !angular.isString(configuration.dropdownSelector)) {
- throw new Error('dropdownSelector must be a string')
- }
- /* istanbul ignore next */
- if (configuration.dropdownSelector !== null && ((typeof jQuery === 'undefined') || (typeof jQuery().dropdown !== 'function'))) {
- $log.error('Please DO NOT specify the dropdownSelector option unless you are using jQuery AND Bootstrap.js. ' +
- 'Please include jQuery AND Bootstrap.js, or write code to close the dropdown in the on-set-time callback. \n\n' +
- 'The dropdownSelector configuration option is being removed because it will not function properly.')
- delete configuration.dropdownSelector
- }
- }
- }
- })); // eslint-disable-line semi
- //todo datetimepicker.templates.js 在异步加载首次运行有问题,只能将其直接合并。。。
- 'use strict'
- angular.module('ui.bootstrap.datetimepicker').run(['$templateCache', function ($templateCache) {
- $templateCache.put('templates/datetimepicker.html', '<div class="datetimepicker table-responsive">\n <table class="table table-condensed {{ data.currentView }}-view">\n <thead>\n <tr>\n <th class="left" data-ng-click="changeView(data.currentView, data.leftDate, $event)" data-ng-show="data.leftDate.selectable"><i class="glyphicon glyphicon-arrow-left"><span class="sr-only">{{ screenReader.previous }}</span></i>\n </th>\n <th class="switch" colspan="5" data-ng-show="data.previousViewDate.selectable" data-ng-click="changeView(data.previousView, data.previousViewDate, $event)">{{ data.previousViewDate.display }}</th>\n <th class="right" data-ng-click="changeView(data.currentView, data.rightDate, $event)" data-ng-show="data.rightDate.selectable"><i class="glyphicon glyphicon-arrow-right"><span class="sr-only">{{ screenReader.next }}</span></i>\n </th>\n </tr>\n <tr>\n <th class="dow" data-ng-repeat="day in data.dayNames">{{ day }}</th>\n </tr>\n </thead>\n <tbody>\n <tr data-ng-if="data.currentView !== \'day\'">\n <td colspan="7">\n <span class="{{ data.currentView }}" data-ng-repeat="dateObject in data.dates" data-ng-class="{current: dateObject.current, active: dateObject.active, past: dateObject.past, future: dateObject.future, disabled: !dateObject.selectable}" data-ng-click="changeView(data.nextView, dateObject, $event)">{{ dateObject.display }}</span></td>\n </tr>\n <tr data-ng-if="data.currentView === \'day\'" data-ng-repeat="week in data.weeks">\n <td data-ng-repeat="dateObject in week.dates" data-ng-click="changeView(data.nextView, dateObject, $event)" class="day" data-ng-class="{current: dateObject.current, active: dateObject.active, past: dateObject.past, future: dateObject.future, disabled: !dateObject.selectable}">{{ dateObject.display }}</td>\n </tr>\n </tbody>\n </table>\n</div>\n')
- }])
|