From 4e57c4c28d900c3803d617ce9412c26f4fccb641 Mon Sep 17 00:00:00 2001 From: Kyle Johnson Date: Wed, 21 Jan 2015 10:20:25 -0500 Subject: [PATCH] Add datetimepicker --- web/skins/bootstrap/css/datetimepicker.css | 387 ++++++++++++++++++++ web/skins/bootstrap/includes/functions.php | 2 + web/skins/bootstrap/js/datetimepicker.js | 397 +++++++++++++++++++++ 3 files changed, 786 insertions(+) create mode 100644 web/skins/bootstrap/css/datetimepicker.css create mode 100644 web/skins/bootstrap/js/datetimepicker.js diff --git a/web/skins/bootstrap/css/datetimepicker.css b/web/skins/bootstrap/css/datetimepicker.css new file mode 100644 index 000000000..38afadf74 --- /dev/null +++ b/web/skins/bootstrap/css/datetimepicker.css @@ -0,0 +1,387 @@ +/** + * @license angular-bootstrap-datetimepicker version: 0.3.8 + * (c) 2013-2014 Knight Rider Consulting, Inc. http://www.knightrider.com + * License: MIT + */ + +.datetimepicker { + padding: 4px; + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + direction: ltr; + width: 320px; +} + +.datetimepicker.datetimepicker-rtl { + direction: rtl; +} + +.datetimepicker.datetimepicker-rtl table tr td span { + float: right; +} + +.datetimepicker-dropdown, .datetimepicker-dropdown-left { + top: 0; + left: 0; +} + +[class*=" datetimepicker-dropdown"]:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; +} + +[class*=" datetimepicker-dropdown"]:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; +} + +[class*=" datetimepicker-dropdown-top"]:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-top: 7px solid #ccc; + border-top-color: rgba(0, 0, 0, 0.2); + border-bottom: 0; +} + +[class*=" datetimepicker-dropdown-top"]:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.datetimepicker-dropdown-bottom-left:before { + top: -7px; + right: 6px; +} + +.datetimepicker-dropdown-bottom-left:after { + top: -6px; + right: 7px; +} + +.datetimepicker-dropdown-bottom-right:before { + top: -7px; + left: 6px; +} + +.datetimepicker-dropdown-bottom-right:after { + top: -6px; + left: 7px; +} + +.datetimepicker-dropdown-top-left:before { + bottom: -7px; + right: 6px; +} + +.datetimepicker-dropdown-top-left:after { + bottom: -6px; + right: 7px; +} + +.datetimepicker-dropdown-top-right:before { + bottom: -7px; + left: 6px; +} + +.datetimepicker-dropdown-top-right:after { + bottom: -6px; + left: 7px; +} + +.datetimepicker > div { + display: none; +} + +.datetimepicker.minutes div.datetimepicker-minutes { + display: block; +} + +.datetimepicker.hours div.datetimepicker-hours { + display: block; +} + +.datetimepicker.days div.datetimepicker-days { + display: block; +} + +.datetimepicker.months div.datetimepicker-months { + display: block; +} + +.datetimepicker.years div.datetimepicker-years { + display: block; +} + +.datetimepicker table { + margin: 0; +} + +.datetimepicker .table td, +.datetimepicker .table th { + text-align: center; + width: 14.6%; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: none; +} +.datetimepicker .table-striped > tbody > tr:nth-child(odd) > td, .datetimepicker .table-striped > tbody > tr:nth-child(odd) > td, +.datetimepicker .table-striped > tbody > tr:nth-child(odd) > td, .datetimepicker .table-striped > tbody > tr:nth-child(odd) > th, +.datetimepicker .table-striped > tbody > tr:nth-child(odd) { + background-color: transparent; +} +.datetimepicker table tr td.minute:hover { + background: #eeeeee; + cursor: pointer; +} + +.datetimepicker table tr td.hour:hover { + background: #eeeeee; + cursor: pointer; +} + +.datetimepicker table tr td.day:hover { + background: #eeeeee; + cursor: pointer; +} + +.datetimepicker table tr td.past, +.datetimepicker table tr td.future { + color: #999999; +} + +.datetimepicker table tr td.disabled, +.datetimepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} + +.datetimepicker table tr td.today, +.datetimepicker table tr td.today:hover, +.datetimepicker table tr td.today.disabled, +.datetimepicker table tr td.today.disabled:hover { + background-color: #fde19a; + background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); + background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); + background-image: linear-gradient(top, #fdd49a, #fdf59a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); + border-color: #fdf59a #fdf59a #fbed50; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.datetimepicker table tr td.today:hover, +.datetimepicker table tr td.today:hover:hover, +.datetimepicker table tr td.today.disabled:hover, +.datetimepicker table tr td.today.disabled:hover:hover, +.datetimepicker table tr td.today:active, +.datetimepicker table tr td.today:hover:active, +.datetimepicker table tr td.today.disabled:active, +.datetimepicker table tr td.today.disabled:hover:active, +.datetimepicker table tr td.today.active, +.datetimepicker table tr td.today:hover.active, +.datetimepicker table tr td.today.disabled.active, +.datetimepicker table tr td.today.disabled:hover.active, +.datetimepicker table tr td.today.disabled, +.datetimepicker table tr td.today:hover.disabled, +.datetimepicker table tr td.today.disabled.disabled, +.datetimepicker table tr td.today.disabled:hover.disabled, +.datetimepicker table tr td.today[disabled], +.datetimepicker table tr td.today:hover[disabled], +.datetimepicker table tr td.today.disabled[disabled], +.datetimepicker table tr td.today.disabled:hover[disabled] { + background-color: #fdf59a; +} + +.datetimepicker table tr td.today:active, +.datetimepicker table tr td.today:hover:active, +.datetimepicker table tr td.today.disabled:active, +.datetimepicker table tr td.today.disabled:hover:active, +.datetimepicker table tr td.today.active, +.datetimepicker table tr td.today:hover.active, +.datetimepicker table tr td.today.disabled.active, +.datetimepicker table tr td.today.disabled:hover.active { + background-color: #fbf069 \9; +} + +.datetimepicker table tr td.active, +.datetimepicker table tr td.active:hover, +.datetimepicker table tr td.active.disabled, +.datetimepicker table tr td.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.datetimepicker table tr td.active:hover, +.datetimepicker table tr td.active:hover:hover, +.datetimepicker table tr td.active.disabled:hover, +.datetimepicker table tr td.active.disabled:hover:hover, +.datetimepicker table tr td.active:active, +.datetimepicker table tr td.active:hover:active, +.datetimepicker table tr td.active.disabled:active, +.datetimepicker table tr td.active.disabled:hover:active, +.datetimepicker table tr td.active.active, +.datetimepicker table tr td.active:hover.active, +.datetimepicker table tr td.active.disabled.active, +.datetimepicker table tr td.active.disabled:hover.active, +.datetimepicker table tr td.active.disabled, +.datetimepicker table tr td.active:hover.disabled, +.datetimepicker table tr td.active.disabled.disabled, +.datetimepicker table tr td.active.disabled:hover.disabled, +.datetimepicker table tr td.active[disabled], +.datetimepicker table tr td.active:hover[disabled], +.datetimepicker table tr td.active.disabled[disabled], +.datetimepicker table tr td.active.disabled:hover[disabled] { + background-color: #0044cc; +} + +.datetimepicker table tr td.active:active, +.datetimepicker table tr td.active:hover:active, +.datetimepicker table tr td.active.disabled:active, +.datetimepicker table tr td.active.disabled:hover:active, +.datetimepicker table tr td.active.active, +.datetimepicker table tr td.active:hover.active, +.datetimepicker table tr td.active.disabled.active, +.datetimepicker table tr td.active.disabled:hover.active { + background-color: #003399 \9; +} + +.datetimepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.datetimepicker span.hour { + height: 26px; + line-height: 26px; +} + +.datetimepicker span.minute { + height: 26px; + line-height: 26px; +} + +.datetimepicker table tr td span:hover { + background: #eeeeee; +} + +.datetimepicker table tr td span.disabled, +.datetimepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} + +.datetimepicker table tr td span.active, +.datetimepicker table tr td span.active:hover, +.datetimepicker table tr td span.active.disabled, +.datetimepicker table tr td span.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.datetimepicker table tr td span.active:hover, +.datetimepicker table tr td span.active:hover:hover, +.datetimepicker table tr td span.active.disabled:hover, +.datetimepicker table tr td span.active.disabled:hover:hover, +.datetimepicker table tr td span.active:active, +.datetimepicker table tr td span.active:hover:active, +.datetimepicker table tr td span.active.disabled:active, +.datetimepicker table tr td span.active.disabled:hover:active, +.datetimepicker table tr td span.active.active, +.datetimepicker table tr td span.active:hover.active, +.datetimepicker table tr td span.active.disabled.active, +.datetimepicker table tr td span.active.disabled:hover.active, +.datetimepicker table tr td span.active.disabled, +.datetimepicker table tr td span.active:hover.disabled, +.datetimepicker table tr td span.active.disabled.disabled, +.datetimepicker table tr td span.active.disabled:hover.disabled, +.datetimepicker table tr td span.active[disabled], +.datetimepicker table tr td span.active:hover[disabled], +.datetimepicker table tr td span.active.disabled[disabled], +.datetimepicker table tr td span.active.disabled:hover[disabled] { + background-color: #0044cc; +} + +.datetimepicker table tr td span.active:active, +.datetimepicker table tr td span.active:hover:active, +.datetimepicker table tr td span.active.disabled:active, +.datetimepicker table tr td span.active.disabled:hover:active, +.datetimepicker table tr td span.active.active, +.datetimepicker table tr td span.active:hover.active, +.datetimepicker table tr td span.active.disabled.active, +.datetimepicker table tr td span.active.disabled:hover.active { + background-color: #003399 \9; +} + +.datetimepicker table tr td span.past, +.datetimepicker table tr td span.future { + color: #999999; +} + + + +.datetimepicker thead tr:first-child th, +.datetimepicker tfoot tr:first-child th { + cursor: pointer; +} + +.datetimepicker thead tr:first-child th:hover, +.datetimepicker tfoot tr:first-child th:hover { + background: #eeeeee; +} diff --git a/web/skins/bootstrap/includes/functions.php b/web/skins/bootstrap/includes/functions.php index 863e98335..0a5f24d76 100644 --- a/web/skins/bootstrap/includes/functions.php +++ b/web/skins/bootstrap/includes/functions.php @@ -12,6 +12,7 @@ + @@ -22,5 +23,6 @@ + diff --git a/web/skins/bootstrap/js/datetimepicker.js b/web/skins/bootstrap/js/datetimepicker.js new file mode 100644 index 000000000..8841cb128 --- /dev/null +++ b/web/skins/bootstrap/js/datetimepicker.js @@ -0,0 +1,397 @@ +/*globals define, jQuery */ +/*jslint vars:true */ + +/** + * @license angular-bootstrap-datetimepicker version: 0.3.8 + * (c) 2013-2014 Knight Rider Consulting, Inc. http://www.knightrider.com + * License: MIT + */ + +/** + * + * @author Dale "Ducky" Lotts + * @since 2013-Jul-8 + */ + +(function (factory) { + 'use strict'; + /* istanbul ignore if */ + if (typeof define === 'function' && /* istanbul ignore next */ define.amd) { + define(['angular', 'moment'], factory); // AMD + } else { + factory(window.angular, window.moment); // Browser global + } +}(function (angular, moment) { + 'use strict'; + angular.module('ui.bootstrap.datetimepicker', []) + .constant('dateTimePickerConfig', { + dropdownSelector: null, + minuteStep: 5, + minView: 'minute', + startView: 'day' + }) + .directive('datetimepicker', ['$log', 'dateTimePickerConfig', function datetimepickerDirective($log, defaultConfig) { + + function DateObject() { + + this.dateValue = new Date().getTime(); + this.selectable = true; + + var validProperties = ['dateValue', 'display', 'active', 'selectable', 'past', 'future']; + + for (var prop in arguments[0]) { + /* istanbul ignore else */ + //noinspection JSUnfilteredForInLoop + if (validProperties.indexOf(prop) >= 0) { + //noinspection JSUnfilteredForInLoop + this[prop] = arguments[0][prop]; + } + } + } + + var validateConfiguration = function validateConfiguration(configuration) { + var validOptions = ['startView', 'minView', 'minuteStep', 'dropdownSelector']; + + for (var prop in configuration) { + //noinspection JSUnfilteredForInLoop + if (validOptions.indexOf(prop) < 0) { + throw ('invalid option: ' + prop); + } + } + + // Order of the elements in the validViews array is significant. + var validViews = ['minute', 'hour', 'day', 'month', 'year']; + + if (validViews.indexOf(configuration.startView) < 0) { + throw ('invalid startView value: ' + configuration.startView); + } + + if (validViews.indexOf(configuration.minView) < 0) { + throw ('invalid minView value: ' + configuration.minView); + } + + if (validViews.indexOf(configuration.minView) > validViews.indexOf(configuration.startView)) { + throw ('startView must be greater than minView'); + } + + if (!angular.isNumber(configuration.minuteStep)) { + throw ('minuteStep must be numeric'); + } + if (configuration.minuteStep <= 0 || configuration.minuteStep >= 60) { + throw ('minuteStep must be greater than zero and less than 60'); + } + if (configuration.dropdownSelector !== null && !angular.isString(configuration.dropdownSelector)) { + throw ('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; + } + }; + + return { + restrict: 'E', + require: 'ngModel', + template: '
' + + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '
{{ data.previousViewDate.display }}
{{ day }}
' + + ' {{ dateObject.display }} ' + + '
{{ dateObject.display }}
', + scope: { + onSetTime: '&', + beforeRender: '&' + }, + replace: true, + link: function link(scope, element, attrs, ngModelController) { + + var directiveConfig = {}; + + if (attrs.datetimepickerConfig) { + directiveConfig = scope.$parent.$eval(attrs.datetimepickerConfig); + } + + var configuration = {}; + + angular.extend(configuration, defaultConfig, directiveConfig); + + validateConfiguration(configuration); + + var startOfDecade = function startOfDecade(unixDate) { + var startYear = (parseInt(moment.utc(unixDate).year() / 10, 10) * 10); + return moment.utc(unixDate).year(startYear).startOf('year'); + }; + + var dataFactory = { + year: function year(unixDate) { + var selectedDate = moment.utc(unixDate).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(unixDate)).subtract(1, 'year').startOf('year'); + + var activeYear = ngModelController.$modelValue ? moment(ngModelController.$modelValue).year() : 0; + + var result = { + 'currentView': 'year', + 'nextView': configuration.minView === 'year' ? 'setTime' : 'month', + 'previousViewDate': new DateObject({dateValue: null, display: startDecade + '-' + (startDecade + 9)}), + 'leftDate': new DateObject({dateValue: moment.utc(startDate).subtract(9, 'year').valueOf()}), + 'rightDate': new DateObject({dateValue: 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 = { + 'dateValue': yearMoment.valueOf(), + 'display': yearMoment.format('YYYY'), + 'past': yearMoment.year() < startDecade, + 'future': yearMoment.year() > startDecade + 9, + 'active': yearMoment.year() === activeYear + }; + + result.dates.push(new DateObject(dateValue)); + } + + return result; + }, + + month: function month(unixDate) { + + var startDate = moment.utc(unixDate).startOf('year'); + var previousViewDate = startOfDecade(unixDate); + var activeDate = ngModelController.$modelValue ? moment(ngModelController.$modelValue).format('YYYY-MMM') : 0; + + var result = { + 'previousView': 'year', + 'currentView': 'month', + 'nextView': configuration.minView === 'month' ? 'setTime' : 'day', + 'previousViewDate': new DateObject({ + dateValue: previousViewDate.valueOf(), + display: startDate.format('YYYY') + }), + 'leftDate': new DateObject({dateValue: moment.utc(startDate).subtract(1, 'year').valueOf()}), + 'rightDate': new DateObject({dateValue: 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 = { + 'dateValue': monthMoment.valueOf(), + 'display': monthMoment.format('MMM'), + 'active': monthMoment.format('YYYY-MMM') === activeDate + }; + + result.dates.push(new DateObject(dateValue)); + } + + return result; + }, + + day: function day(unixDate) { + + var selectedDate = moment.utc(unixDate); + 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 activeDate = ngModelController.$modelValue ? moment(ngModelController.$modelValue).format('YYYY-MMM-DD') : ''; + + var result = { + 'previousView': 'month', + 'currentView': 'day', + 'nextView': configuration.minView === 'day' ? 'setTime' : 'hour', + 'previousViewDate': new DateObject({ + dateValue: previousViewDate.valueOf(), + display: startOfMonth.format('YYYY-MMM') + }), + 'leftDate': new DateObject({dateValue: moment.utc(startOfMonth).subtract(1, 'months').valueOf()}), + 'rightDate': new DateObject({dateValue: 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 monthMoment = moment.utc(startDate).add((i * 7) + j, 'days'); + var dateValue = { + 'dateValue': monthMoment.valueOf(), + 'display': monthMoment.format('D'), + 'active': monthMoment.format('YYYY-MMM-DD') === activeDate, + 'past': monthMoment.isBefore(startOfMonth), + 'future': monthMoment.isAfter(endOfMonth) + }; + week.dates.push(new DateObject(dateValue)); + } + result.weeks.push(week); + } + + return result; + }, + + hour: function hour(unixDate) { + var selectedDate = moment.utc(unixDate).startOf('day'); + var previousViewDate = moment.utc(selectedDate).startOf('month'); + + var activeFormat = ngModelController.$modelValue ? moment(ngModelController.$modelValue).format('YYYY-MM-DD H') : ''; + + var result = { + 'previousView': 'day', + 'currentView': 'hour', + 'nextView': configuration.minView === 'hour' ? 'setTime' : 'minute', + 'previousViewDate': new DateObject({ + dateValue: previousViewDate.valueOf(), + display: selectedDate.format('ll') + }), + 'leftDate': new DateObject({dateValue: moment.utc(selectedDate).subtract(1, 'days').valueOf()}), + 'rightDate': new DateObject({dateValue: 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 = { + 'dateValue': hourMoment.valueOf(), + 'display': hourMoment.format('LT'), + 'active': hourMoment.format('YYYY-MM-DD H') === activeFormat + }; + + result.dates.push(new DateObject(dateValue)); + } + + return result; + }, + + minute: function minute(unixDate) { + var selectedDate = moment.utc(unixDate).startOf('hour'); + var previousViewDate = moment.utc(selectedDate).startOf('day'); + var activeFormat = ngModelController.$modelValue ? moment(ngModelController.$modelValue).format('YYYY-MM-DD H:mm') : ''; + + var result = { + 'previousView': 'hour', + 'currentView': 'minute', + 'nextView': 'setTime', + 'previousViewDate': new DateObject({ + dateValue: previousViewDate.valueOf(), + display: selectedDate.format('lll') + }), + 'leftDate': new DateObject({dateValue: moment.utc(selectedDate).subtract(1, 'hours').valueOf()}), + 'rightDate': new DateObject({dateValue: 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 = { + 'dateValue': hourMoment.valueOf(), + 'display': hourMoment.format('LT'), + 'active': hourMoment.format('YYYY-MM-DD H:mm') === activeFormat + }; + + result.dates.push(new DateObject(dateValue)); + } + + return result; + }, + + setTime: function setTime(unixDate) { + var tempDate = new Date(unixDate); + var newDate = new Date(tempDate.getTime() + (tempDate.getTimezoneOffset() * 60000)); + + var oldDate = ngModelController.$modelValue; + ngModelController.$setViewValue(newDate); + + if (configuration.dropdownSelector) { + jQuery(configuration.dropdownSelector).dropdown('toggle'); + } + + scope.onSetTime({newDate: newDate, oldDate: oldDate}); + + return dataFactory[configuration.startView](unixDate); + } + }; + + var getUTCTime = function getUTCTime(modelValue) { + var tempDate = (modelValue ? moment(modelValue).toDate() : new Date()); + return tempDate.getTime() - (tempDate.getTimezoneOffset() * 60000); + }; + + scope.changeView = function changeView(viewName, dateObject, event) { + if (event) { + event.stopPropagation(); + event.preventDefault(); + } + + if (viewName && (dateObject.dateValue > -Infinity) && dateObject.selectable && dataFactory[viewName]) { + var result = dataFactory[viewName](dateObject.dateValue); + + 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; + } + }; + + ngModelController.$render = function $render() { + scope.changeView(configuration.startView, new DateObject({dateValue: getUTCTime(ngModelController.$viewValue)})); + }; + } + }; + }]); +}));