diff --git a/app/scripts/datePicker.js b/app/scripts/datePicker.js index ac9ed8b..72ec09f 100644 --- a/app/scripts/datePicker.js +++ b/app/scripts/datePicker.js @@ -83,7 +83,7 @@ Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function isNow, inValidRange; - datePickerUtils.setParams(tz, firstDay); + datePickerUtils.setParams({ zone: tz, fd: firstDay }); if (!scope.model) { selected.minute(Math.ceil(selected.minute() / step) * step).second(0); @@ -147,7 +147,7 @@ Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function function update() { var view = scope.view; - datePickerUtils.setParams(tz, firstDay); + datePickerUtils.setParams({ zone: tz, fd: firstDay }); if (scope.model && !arrowClick) { scope.date = createMoment(scope.model); @@ -169,6 +169,7 @@ Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function break; case 'hours': scope.hours = datePickerUtils.getVisibleHours(date); + scope.hoursFormat = (scope.hours.isAmPmFormat ? 'hh:mm a' : 'HH:mm'); break; case 'minutes': scope.minutes = datePickerUtils.getVisibleMinutes(date, step); @@ -200,7 +201,7 @@ Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function classes = [], classList = '', i, j; - datePickerUtils.setParams(tz, firstDay); + datePickerUtils.setParams({ zone: tz, fd: firstDay }); if (view === 'date') { var weeks = scope.weeks, week; diff --git a/app/scripts/datePickerUtils.js b/app/scripts/datePickerUtils.js index 8b6cc74..fd3be47 100644 --- a/app/scripts/datePickerUtils.js +++ b/app/scripts/datePickerUtils.js @@ -1,6 +1,6 @@ 'use strict'; angular.module('datePicker').factory('datePickerUtils', function () { - var tz, firstDay; + var tz, firstDay, isAmPmFormat; var createNewDate = function (year, month, day, hour, minute) { var utc = Date.UTC(year | 0, month | 0, day | 0, hour | 0, minute | 0); return tz ? moment.tz(utc, tz) : moment(utc); @@ -125,7 +125,7 @@ angular.module('datePicker').factory('datePickerUtils', function () { } hours.push(pushedDate); } - + hours.isAmPmFormat = isAmPmFormat; return hours; }, isAfter: function (model, date) { @@ -149,9 +149,10 @@ angular.module('datePicker').factory('datePickerUtils', function () { isSameMinutes: function (model, date) { return this.isSameHour(model, date) && model.minutes() === date.minutes(); }, - setParams: function (zone, fd) { - tz = zone; - firstDay = fd; + setParams: function (params) { + tz = angular.isDefined(params.zone) ? params.zone : tz; + firstDay = angular.isDefined(params.fd) ? params.fd : firstDay; + isAmPmFormat = angular.isDefined(params.isAmPmFormat) ? params.isAmPmFormat : isAmPmFormat; }, scopeSearch: function (scope, name, comparisonFn) { var parentScope = scope, diff --git a/app/scripts/dateRange.js b/app/scripts/dateRange.js index 5d25b85..bc45c51 100644 --- a/app/scripts/dateRange.js +++ b/app/scripts/dateRange.js @@ -54,7 +54,7 @@ Module.directive('dateRange', ['$compile', 'datePickerUtils', 'dateTimeConfig', }); } - datePickerUtils.setParams(attrs.timezone); + datePickerUtils.setParams({zone: attrs.timezone}); scope.start = createMoment(scope.start); scope.end = createMoment(scope.end); diff --git a/app/scripts/input.js b/app/scripts/input.js index 5470741..575e2bf 100644 --- a/app/scripts/input.js +++ b/app/scripts/input.js @@ -69,6 +69,8 @@ Module.directive('dateTime', ['$compile', '$document', '$filter', 'dateTimeConfi shownOnce = false, template; + datePickerUtils.setParams({ isAmPmFormat: format.match(/[aA]/) }); + if (index === -1) { views.splice(index, 1); } diff --git a/app/styles/style.less b/app/styles/style.less index 0127b96..ff4552f 100644 --- a/app/styles/style.less +++ b/app/styles/style.less @@ -105,6 +105,13 @@ line-height: 54px; } } + + [ng-switch-when="hours"], [ng-switch-when="minutes"] { + span.am-pm{ + width: 45%; + } + } + [ng-switch-when="date"]{ td { padding: 0; diff --git a/app/templates/datepicker.html b/app/templates/datepicker.html index 85316bd..ecdb057 100644 --- a/app/templates/datepicker.html +++ b/app/templates/datepicker.html @@ -77,7 +77,7 @@ + ng-click="selectDate(hour)" ng-bind="hour|mFormat:hoursFormat:tz"> @@ -98,7 +98,7 @@ + ng-bind="minute|mFormat:'hoursFormat:tz"> diff --git a/dist/angular-datepicker.css b/dist/angular-datepicker.css index 02f2a52..5a9ac6f 100644 --- a/dist/angular-datepicker.css +++ b/dist/angular-datepicker.css @@ -211,6 +211,10 @@ height: 54px; line-height: 54px; } +[date-picker] [ng-switch-when="hours"] span.am-pm, +[date-picker] [ng-switch-when="minutes"] span.am-pm { + width: 45%; +} [date-picker] [ng-switch-when="date"] td { padding: 0; } diff --git a/dist/angular-datepicker.js b/dist/angular-datepicker.js index 7778b35..9957cf5 100644 --- a/dist/angular-datepicker.js +++ b/dist/angular-datepicker.js @@ -1,959 +1,931 @@ (function (global, factory) {'use strict';var fnc;fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) :(typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) :factory(global.angular, global.moment);}(this, function (angular, moment) { -//(function (global, factory) { -// 'use strict'; -// var fnc; -// fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) : -// (typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) : -// factory(global.angular, global.moment); -//}(this, function (angular, moment) { var Module = angular.module('datePicker', []); - Module.constant('datePickerConfig', { - template: 'templates/datepicker.html', - view: 'month', - views: ['year', 'month', 'date', 'hours', 'minutes'], - momentNames: { - year: 'year', - month: 'month', - date: 'day', - hours: 'hours', - minutes: 'minutes', - }, - viewConfig: { - year: ['years', 'isSameYear'], - month: ['months', 'isSameMonth'], - hours: ['hours', 'isSameHour'], - minutes: ['minutes', 'isSameMinutes'], - }, - step: 5 - }); +Module.constant('datePickerConfig', { + template: 'templates/datepicker.html', + view: 'month', + views: ['year', 'month', 'date', 'hours', 'minutes'], + momentNames: { + year: 'year', + month: 'month', + date: 'day', + hours: 'hours', + minutes: 'minutes', + }, + viewConfig: { + year: ['years', 'isSameYear'], + month: ['months', 'isSameMonth'], + hours: ['hours', 'isSameHour'], + minutes: ['minutes', 'isSameMinutes'], + }, + step: 5 +}); //Moment format filter. - Module.filter('mFormat', function () { - return function (m, format, tz) { - if (!(moment.isMoment(m))) { - return moment(m).format(format); - } - return tz ? moment.tz(m, tz).format(format) : m.format(format); - }; - }); - - Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function datePickerDirective(datePickerConfig, datePickerUtils) { - - //noinspection JSUnusedLocalSymbols - return { - // this is a bug ? - require: '?ngModel', - template: '
', - scope: { - model: '=datePicker', - after: '=?', - before: '=?' - }, - link: function (scope, element, attrs, ngModel) { - function prepareViews() { - scope.views = datePickerConfig.views.concat(); - scope.view = attrs.view || datePickerConfig.view; - - scope.views = scope.views.slice( - scope.views.indexOf(attrs.maxView || 'year'), - scope.views.indexOf(attrs.minView || 'minutes') + 1 - ); - - if (scope.views.length === 1 || scope.views.indexOf(scope.view) === -1) { - scope.view = scope.views[0]; - } +Module.filter('mFormat', function () { + return function (m, format, tz) { + if (!(moment.isMoment(m))) { + return moment(m).format(format); + } + return tz ? moment.tz(m, tz).format(format) : m.format(format); + }; +}); + +Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function datePickerDirective(datePickerConfig, datePickerUtils) { + + //noinspection JSUnusedLocalSymbols + return { + // this is a bug ? + require: '?ngModel', + template: '
', + scope: { + model: '=datePicker', + after: '=?', + before: '=?' + }, + link: function (scope, element, attrs, ngModel) { + function prepareViews() { + scope.views = datePickerConfig.views.concat(); + scope.view = attrs.view || datePickerConfig.view; + + scope.views = scope.views.slice( + scope.views.indexOf(attrs.maxView || 'year'), + scope.views.indexOf(attrs.minView || 'minutes') + 1 + ); + + if (scope.views.length === 1 || scope.views.indexOf(scope.view) === -1) { + scope.view = scope.views[0]; } + } - function getDate(name) { - return datePickerUtils.getDate(scope, attrs, name); - } + function getDate(name) { + return datePickerUtils.getDate(scope, attrs, name); + } - var arrowClick = false, - tz = scope.tz = attrs.timezone, - createMoment = datePickerUtils.createMoment, - eventIsForPicker = datePickerUtils.eventIsForPicker, - step = parseInt(attrs.step || datePickerConfig.step, 10), - partial = !!attrs.partial, - minDate = getDate('minDate'), - maxDate = getDate('maxDate'), - pickerID = element[0].id, - now = scope.now = createMoment(), - selected = scope.date = createMoment(scope.model || now), - autoclose = attrs.autoClose === 'true', - // Either gets the 1st day from the attributes, or asks moment.js to give it to us as it is localized. - firstDay = attrs.firstDay && attrs.firstDay >= 0 && attrs.firstDay <= 6 ? parseInt(attrs.firstDay, 10) : moment().weekday(0).day(), - setDate, - prepareViewData, - isSame, - clipDate, - isNow, - inValidRange; - - datePickerUtils.setParams(tz, firstDay); - - if (!scope.model) { - selected.minute(Math.ceil(selected.minute() / step) * step).second(0); - } + var arrowClick = false, + tz = scope.tz = attrs.timezone, + createMoment = datePickerUtils.createMoment, + eventIsForPicker = datePickerUtils.eventIsForPicker, + step = parseInt(attrs.step || datePickerConfig.step, 10), + partial = !!attrs.partial, + minDate = getDate('minDate'), + maxDate = getDate('maxDate'), + pickerID = element[0].id, + now = scope.now = createMoment(), + selected = scope.date = createMoment(scope.model || now), + autoclose = attrs.autoClose === 'true', + // Either gets the 1st day from the attributes, or asks moment.js to give it to us as it is localized. + firstDay = attrs.firstDay && attrs.firstDay >= 0 && attrs.firstDay <= 6 ? parseInt(attrs.firstDay, 10) : moment().weekday(0).day(), + setDate, + prepareViewData, + isSame, + clipDate, + isNow, + inValidRange; + + datePickerUtils.setParams({ zone: tz, fd: firstDay }); + + if (!scope.model) { + selected.minute(Math.ceil(selected.minute() / step) * step).second(0); + } - scope.template = attrs.template || datePickerConfig.template; + scope.template = attrs.template || datePickerConfig.template; - scope.watchDirectChanges = attrs.watchDirectChanges !== undefined; - scope.callbackOnSetDate = attrs.dateChange ? datePickerUtils.findFunction(scope, attrs.dateChange) : undefined; + scope.watchDirectChanges = attrs.watchDirectChanges !== undefined; + scope.callbackOnSetDate = attrs.dateChange ? datePickerUtils.findFunction(scope, attrs.dateChange) : undefined; - prepareViews(); + prepareViews(); - scope.setView = function (nextView) { - if (scope.views.indexOf(nextView) !== -1) { - scope.view = nextView; - } - }; + scope.setView = function (nextView) { + if (scope.views.indexOf(nextView) !== -1) { + scope.view = nextView; + } + }; - scope.selectDate = function (date) { - if (attrs.disabled) { - return false; - } - if (isSame(scope.date, date)) { - date = scope.date; - } - date = clipDate(date); - if (!date) { - return false; - } - scope.date = date; + scope.selectDate = function (date) { + if (attrs.disabled) { + return false; + } + if (isSame(scope.date, date)) { + date = scope.date; + } + date = clipDate(date); + if (!date) { + return false; + } + scope.date = date; - var nextView = scope.views[scope.views.indexOf(scope.view) + 1]; - if ((!nextView || partial) || scope.model) { - setDate(date); - } + var nextView = scope.views[scope.views.indexOf(scope.view) + 1]; + if ((!nextView || partial) || scope.model) { + setDate(date); + } - if (nextView) { - scope.setView(nextView); - } else if (autoclose) { - element.addClass('hidden'); - scope.$emit('hidePicker'); - } else { - prepareViewData(); - } - }; + if (nextView) { + scope.setView(nextView); + } else if (autoclose) { + element.addClass('hidden'); + scope.$emit('hidePicker'); + } else { + prepareViewData(); + } + }; - setDate = function (date) { - if (date) { - scope.model = date; - if (ngModel) { - ngModel.$setViewValue(date); - } + setDate = function (date) { + if (date) { + scope.model = date; + if (ngModel) { + ngModel.$setViewValue(date); } - scope.$emit('setDate', scope.model, scope.view); + } + scope.$emit('setDate', scope.model, scope.view); - //This is duplicated in the new functionality. - if (scope.callbackOnSetDate) { - scope.callbackOnSetDate(attrs.datePicker, scope.date); - } - }; + //This is duplicated in the new functionality. + if (scope.callbackOnSetDate) { + scope.callbackOnSetDate(attrs.datePicker, scope.date); + } + }; - function update() { - var view = scope.view; - datePickerUtils.setParams(tz, firstDay); + function update() { + var view = scope.view; + datePickerUtils.setParams({ zone: tz, fd: firstDay }); - if (scope.model && !arrowClick) { - scope.date = createMoment(scope.model); - arrowClick = false; - } + if (scope.model && !arrowClick) { + scope.date = createMoment(scope.model); + arrowClick = false; + } - var date = scope.date; - - switch (view) { - case 'year': - scope.years = datePickerUtils.getVisibleYears(date); - break; - case 'month': - scope.months = datePickerUtils.getVisibleMonths(date); - break; - case 'date': - scope.weekdays = scope.weekdays || datePickerUtils.getDaysOfWeek(); - scope.weeks = datePickerUtils.getVisibleWeeks(date); - break; - case 'hours': - scope.hours = datePickerUtils.getVisibleHours(date); - break; - case 'minutes': - scope.minutes = datePickerUtils.getVisibleMinutes(date, step); - break; - } + var date = scope.date; - prepareViewData(); + switch (view) { + case 'year': + scope.years = datePickerUtils.getVisibleYears(date); + break; + case 'month': + scope.months = datePickerUtils.getVisibleMonths(date); + break; + case 'date': + scope.weekdays = scope.weekdays || datePickerUtils.getDaysOfWeek(); + scope.weeks = datePickerUtils.getVisibleWeeks(date); + break; + case 'hours': + scope.hours = datePickerUtils.getVisibleHours(date); + scope.hoursFormat = (scope.hours.isAmPmFormat ? 'hh:mm a' : 'HH:mm'); + break; + case 'minutes': + scope.minutes = datePickerUtils.getVisibleMinutes(date, step); + break; } - function watch() { - if (scope.view !== 'date') { - return scope.view; - } - return scope.date ? scope.date.month() : null; + prepareViewData(); + } + + function watch() { + if (scope.view !== 'date') { + return scope.view; } + return scope.date ? scope.date.month() : null; + } - scope.$watch(watch, update); + scope.$watch(watch, update); - if (scope.watchDirectChanges) { - scope.$watch('model', function () { - arrowClick = false; - update(); - }); - } + if (scope.watchDirectChanges) { + scope.$watch('model', function () { + arrowClick = false; + update(); + }); + } - prepareViewData = function () { - var view = scope.view, - date = scope.date, - classes = [], classList = '', - i, j; - - datePickerUtils.setParams(tz, firstDay); - - if (view === 'date') { - var weeks = scope.weeks, week; - for (i = 0; i < weeks.length; i++) { - week = weeks[i]; - classes.push([]); - for (j = 0; j < week.length; j++) { - classList = ''; - if (datePickerUtils.isSameDay(date, week[j])) { - classList += 'active'; - } - if (isNow(week[j], view)) { - classList += ' now'; - } - //if (week[j].month() !== date.month()) classList += ' disabled'; - if (week[j].month() !== date.month() || !inValidRange(week[j])) { - classList += ' disabled'; - } - classes[i].push(classList); - } - } - } else { - var params = datePickerConfig.viewConfig[view], - dates = scope[params[0]], - compareFunc = params[1]; + prepareViewData = function () { + var view = scope.view, + date = scope.date, + classes = [], classList = '', + i, j; - for (i = 0; i < dates.length; i++) { + datePickerUtils.setParams({ zone: tz, fd: firstDay }); + + if (view === 'date') { + var weeks = scope.weeks, week; + for (i = 0; i < weeks.length; i++) { + week = weeks[i]; + classes.push([]); + for (j = 0; j < week.length; j++) { classList = ''; - if (datePickerUtils[compareFunc](date, dates[i])) { + if (datePickerUtils.isSameDay(date, week[j])) { classList += 'active'; } - if (isNow(dates[i], view)) { + if (isNow(week[j], view)) { classList += ' now'; } - if (!inValidRange(dates[i])) { + //if (week[j].month() !== date.month()) classList += ' disabled'; + if (week[j].month() !== date.month() || !inValidRange(week[j])) { classList += ' disabled'; } - classes.push(classList); + classes[i].push(classList); } } - scope.classes = classes; - }; - - scope.next = function (delta) { - var date = moment(scope.date); - delta = delta || 1; - switch (scope.view) { - case 'year': - /*falls through*/ - case 'month': - date.year(date.year() + delta); - break; - case 'date': - date.month(date.month() + delta); - break; - case 'hours': - /*falls through*/ - case 'minutes': - date.hours(date.hours() + delta); - break; - } - date = clipDate(date); - if (date) { - scope.date = date; - setDate(date); - arrowClick = true; - update(); - } - }; - - inValidRange = function (date) { - var valid = true; - if (minDate && minDate.isAfter(date)) { - valid = isSame(minDate, date); - } - if (maxDate && maxDate.isBefore(date)) { - valid &= isSame(maxDate, date); - } - return valid; - }; - - isSame = function (date1, date2) { - return date1.isSame(date2, datePickerConfig.momentNames[scope.view]) ? true : false; - }; - - clipDate = function (date) { - if (minDate && minDate.isAfter(date)) { - return minDate; - } else if (maxDate && maxDate.isBefore(date)) { - return maxDate; - } else { - return date; + } else { + var params = datePickerConfig.viewConfig[view], + dates = scope[params[0]], + compareFunc = params[1]; + + for (i = 0; i < dates.length; i++) { + classList = ''; + if (datePickerUtils[compareFunc](date, dates[i])) { + classList += 'active'; + } + if (isNow(dates[i], view)) { + classList += ' now'; + } + if (!inValidRange(dates[i])) { + classList += ' disabled'; + } + classes.push(classList); } - }; + } + scope.classes = classes; + }; + + scope.next = function (delta) { + var date = moment(scope.date); + delta = delta || 1; + switch (scope.view) { + case 'year': + /*falls through*/ + case 'month': + date.year(date.year() + delta); + break; + case 'date': + date.month(date.month() + delta); + break; + case 'hours': + /*falls through*/ + case 'minutes': + date.hours(date.hours() + delta); + break; + } + date = clipDate(date); + if (date) { + scope.date = date; + setDate(date); + arrowClick = true; + update(); + } + }; - isNow = function (date, view) { - var is = true; - - switch (view) { - case 'minutes': - is &= ~~(now.minutes() / step) === ~~(date.minutes() / step); - /* falls through */ - case 'hours': - is &= now.hours() === date.hours(); - /* falls through */ - case 'date': - is &= now.date() === date.date(); - /* falls through */ - case 'month': - is &= now.month() === date.month(); - /* falls through */ - case 'year': - is &= now.year() === date.year(); - } - return is; - }; + inValidRange = function (date) { + var valid = true; + if (minDate && minDate.isAfter(date)) { + valid = isSame(minDate, date); + } + if (maxDate && maxDate.isBefore(date)) { + valid &= isSame(maxDate, date); + } + return valid; + }; + + isSame = function (date1, date2) { + return date1.isSame(date2, datePickerConfig.momentNames[scope.view]) ? true : false; + }; + + clipDate = function (date) { + if (minDate && minDate.isAfter(date)) { + return minDate; + } else if (maxDate && maxDate.isBefore(date)) { + return maxDate; + } else { + return date; + } + }; + + isNow = function (date, view) { + var is = true; + + switch (view) { + case 'minutes': + is &= ~~(now.minutes() / step) === ~~(date.minutes() / step); + /* falls through */ + case 'hours': + is &= now.hours() === date.hours(); + /* falls through */ + case 'date': + is &= now.date() === date.date(); + /* falls through */ + case 'month': + is &= now.month() === date.month(); + /* falls through */ + case 'year': + is &= now.year() === date.year(); + } + return is; + }; - scope.prev = function (delta) { - return scope.next(-delta || -1); - }; + scope.prev = function (delta) { + return scope.next(-delta || -1); + }; - if (pickerID) { - scope.$on('pickerUpdate', function (event, pickerIDs, data) { - if (eventIsForPicker(pickerIDs, pickerID)) { - var updateViews = false, updateViewData = false; + if (pickerID) { + scope.$on('pickerUpdate', function (event, pickerIDs, data) { + if (eventIsForPicker(pickerIDs, pickerID)) { + var updateViews = false, updateViewData = false; - if (angular.isDefined(data.minDate)) { - minDate = data.minDate ? data.minDate : false; - updateViewData = true; - } - if (angular.isDefined(data.maxDate)) { - maxDate = data.maxDate ? data.maxDate : false; - updateViewData = true; - } + if (angular.isDefined(data.minDate)) { + minDate = data.minDate ? data.minDate : false; + updateViewData = true; + } + if (angular.isDefined(data.maxDate)) { + maxDate = data.maxDate ? data.maxDate : false; + updateViewData = true; + } - if (angular.isDefined(data.minView)) { - attrs.minView = data.minView; - updateViews = true; - } - if (angular.isDefined(data.maxView)) { - attrs.maxView = data.maxView; - updateViews = true; - } - attrs.view = data.view || attrs.view; + if (angular.isDefined(data.minView)) { + attrs.minView = data.minView; + updateViews = true; + } + if (angular.isDefined(data.maxView)) { + attrs.maxView = data.maxView; + updateViews = true; + } + attrs.view = data.view || attrs.view; - if (updateViews) { - prepareViews(); - } + if (updateViews) { + prepareViews(); + } - if (updateViewData) { - update(); - } + if (updateViewData) { + update(); } - }); - } + } + }); } - }; - }]); -//})); - -//(function (global, factory) { -// 'use strict'; -// var fnc; -// fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) : -// (typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) : -// factory(global.angular, global.moment); -//}(this, function (angular, moment) { + } + }; +}]); + angular.module('datePicker').factory('datePickerUtils', function () { - var tz, firstDay; - var createNewDate = function (year, month, day, hour, minute) { - var utc = Date.UTC(year | 0, month | 0, day | 0, hour | 0, minute | 0); - return tz ? moment.tz(utc, tz) : moment(utc); - }; - - return { - getVisibleMinutes: function (m, step) { - var year = m.year(), - month = m.month(), - day = m.date(), - hour = m.hours(), pushedDate, - offset = m.utcOffset() / 60, - minutes = [], minute; - - for (minute = 0; minute < 60; minute += step) { - pushedDate = createNewDate(year, month, day, hour - offset, minute); - minutes.push(pushedDate); - } - return minutes; - }, - getVisibleWeeks: function (m) { - m = moment(m); - var startYear = m.year(), - startMonth = m.month(); + var tz, firstDay, isAmPmFormat; + var createNewDate = function (year, month, day, hour, minute) { + var utc = Date.UTC(year | 0, month | 0, day | 0, hour | 0, minute | 0); + return tz ? moment.tz(utc, tz) : moment(utc); + }; + + return { + getVisibleMinutes: function (m, step) { + var year = m.year(), + month = m.month(), + day = m.date(), + hour = m.hours(), pushedDate, + offset = m.utcOffset() / 60, + minutes = [], minute; + + for (minute = 0; minute < 60; minute += step) { + pushedDate = createNewDate(year, month, day, hour - offset, minute); + minutes.push(pushedDate); + } + return minutes; + }, + getVisibleWeeks: function (m) { + m = moment(m); + var startYear = m.year(), + startMonth = m.month(); - //Set date to the first day of the month - m.date(1); + //Set date to the first day of the month + m.date(1); - //Grab day of the week - var day = m.day(); + //Grab day of the week + var day = m.day(); - //Go back the required number of days to arrive at the previous week start - m.date(firstDay - (day + (firstDay >= day ? 6 : -1))); + //Go back the required number of days to arrive at the previous week start + m.date(firstDay - (day + (firstDay >= day ? 6 : -1))); - var weeks = []; + var weeks = []; - while (weeks.length < 6) { - if (m.year() === startYear && m.month() > startMonth) { - break; - } - weeks.push(this.getDaysOfWeek(m)); - m.add(7, 'd'); + while (weeks.length < 6) { + if (m.year() === startYear && m.month() > startMonth) { + break; } - return weeks; - }, - getVisibleYears: function (d) { - var m = moment(d), - year = m.year(); - - m.year(year - (year % 10)); + weeks.push(this.getDaysOfWeek(m)); + m.add(7, 'd'); + } + return weeks; + }, + getVisibleYears: function (d) { + var m = moment(d), year = m.year(); - var offset = m.utcOffset() / 60, - years = [], - pushedDate, - actualOffset; - - for (var i = 0; i < 12; i++) { - pushedDate = createNewDate(year, 0, 1, 0 - offset); - actualOffset = pushedDate.utcOffset() / 60; - if (actualOffset !== offset) { - pushedDate = createNewDate(year, 0, 1, 0 - actualOffset); - offset = actualOffset; - } - years.push(pushedDate); - year++; + m.year(year - (year % 10)); + year = m.year(); + + var offset = m.utcOffset() / 60, + years = [], + pushedDate, + actualOffset; + + for (var i = 0; i < 12; i++) { + pushedDate = createNewDate(year, 0, 1, 0 - offset); + actualOffset = pushedDate.utcOffset() / 60; + if (actualOffset !== offset) { + pushedDate = createNewDate(year, 0, 1, 0 - actualOffset); + offset = actualOffset; } - return years; - }, - getDaysOfWeek: function (m) { - m = m ? m : (tz ? moment.tz(tz).day(firstDay) : moment().day(firstDay)); - - var year = m.year(), - month = m.month(), - day = m.date(), - days = [], - pushedDate, - offset = m.utcOffset() / 60, - actualOffset; - - for (var i = 0; i < 7; i++) { - pushedDate = createNewDate(year, month, day, 0 - offset, 0, false); - actualOffset = pushedDate.utcOffset() / 60; - if (actualOffset !== offset) { - pushedDate = createNewDate(year, month, day, 0 - actualOffset, 0, false); - } - days.push(pushedDate); - day++; + years.push(pushedDate); + year++; + } + return years; + }, + getDaysOfWeek: function (m) { + m = m ? m : (tz ? moment.tz(tz).day(firstDay) : moment().day(firstDay)); + + var year = m.year(), + month = m.month(), + day = m.date(), + days = [], + pushedDate, + offset = m.utcOffset() / 60, + actualOffset; + + for (var i = 0; i < 7; i++) { + pushedDate = createNewDate(year, month, day, 0 - offset, 0, false); + actualOffset = pushedDate.utcOffset() / 60; + if (actualOffset !== offset) { + pushedDate = createNewDate(year, month, day, 0 - actualOffset, 0, false); } - return days; - }, - getVisibleMonths: function (m) { - var year = m.year(), - offset = m.utcOffset() / 60, - months = [], - pushedDate, - actualOffset; - - for (var month = 0; month < 12; month++) { - pushedDate = createNewDate(year, month, 1, 0 - offset, 0, false); - actualOffset = pushedDate.utcOffset() / 60; - if (actualOffset !== offset) { - pushedDate = createNewDate(year, month, 1, 0 - actualOffset, 0, false); - } - months.push(pushedDate); + days.push(pushedDate); + day++; + } + return days; + }, + getVisibleMonths: function (m) { + var year = m.year(), + offset = m.utcOffset() / 60, + months = [], + pushedDate, + actualOffset; + + for (var month = 0; month < 12; month++) { + pushedDate = createNewDate(year, month, 1, 0 - offset, 0, false); + actualOffset = pushedDate.utcOffset() / 60; + if (actualOffset !== offset) { + pushedDate = createNewDate(year, month, 1, 0 - actualOffset, 0, false); } - return months; - }, - getVisibleHours: function (m) { - var year = m.year(), - month = m.month(), - day = m.date(), - hours = [], - hour, pushedDate, actualOffset, - offset = m.utcOffset() / 60; - - for (hour = 0; hour < 24; hour++) { - pushedDate = createNewDate(year, month, day, hour - offset, 0, false); - actualOffset = pushedDate.utcOffset() / 60; - if (actualOffset !== offset) { - pushedDate = createNewDate(year, month, day, hour - actualOffset, 0, false); - } - hours.push(pushedDate); + months.push(pushedDate); + } + return months; + }, + getVisibleHours: function (m) { + var year = m.year(), + month = m.month(), + day = m.date(), + hours = [], + hour, pushedDate, actualOffset, + offset = m.utcOffset() / 60; + + for (hour = 0; hour < 24; hour++) { + pushedDate = createNewDate(year, month, day, hour - offset, 0, false); + actualOffset = pushedDate.utcOffset() / 60; + if (actualOffset !== offset) { + pushedDate = createNewDate(year, month, day, hour - actualOffset, 0, false); } - - return hours; - }, - isAfter: function (model, date) { - return model && model.unix() >= date.unix(); - }, - isBefore: function (model, date) { - return model.unix() <= date.unix(); - }, - isSameYear: function (model, date) { - return model && model.year() === date.year(); - }, - isSameMonth: function (model, date) { - return this.isSameYear(model, date) && model.month() === date.month(); - }, - isSameDay: function (model, date) { - return this.isSameMonth(model, date) && model.date() === date.date(); - }, - isSameHour: function (model, date) { - return this.isSameDay(model, date) && model.hours() === date.hours(); - }, - isSameMinutes: function (model, date) { - return this.isSameHour(model, date) && model.minutes() === date.minutes(); - }, - setParams: function (zone, fd) { - tz = zone; - firstDay = fd; - }, - scopeSearch: function (scope, name, comparisonFn) { - var parentScope = scope, - nameArray = name.split('.'), - target, i, j = nameArray.length; - - do { - target = parentScope = parentScope.$parent; - - //Loop through provided names. - for (i = 0; i < j; i++) { - target = target[nameArray[i]]; - if (!target) { - continue; - } + hours.push(pushedDate); + } + hours.isAmPmFormat = isAmPmFormat; + return hours; + }, + isAfter: function (model, date) { + return model && model.unix() >= date.unix(); + }, + isBefore: function (model, date) { + return model.unix() <= date.unix(); + }, + isSameYear: function (model, date) { + return model && model.year() === date.year(); + }, + isSameMonth: function (model, date) { + return this.isSameYear(model, date) && model.month() === date.month(); + }, + isSameDay: function (model, date) { + return this.isSameMonth(model, date) && model.date() === date.date(); + }, + isSameHour: function (model, date) { + return this.isSameDay(model, date) && model.hours() === date.hours(); + }, + isSameMinutes: function (model, date) { + return this.isSameHour(model, date) && model.minutes() === date.minutes(); + }, + setParams: function (params) { + tz = angular.isDefined(params.zone) ? params.zone : tz; + firstDay = angular.isDefined(params.fd) ? params.fd : firstDay; + isAmPmFormat = angular.isDefined(params.isAmPmFormat) ? params.isAmPmFormat : isAmPmFormat; + }, + scopeSearch: function (scope, name, comparisonFn) { + var parentScope = scope, + nameArray = name.split('.'), + target, i, j = nameArray.length; + + do { + target = parentScope = parentScope.$parent; + + //Loop through provided names. + for (i = 0; i < j; i++) { + target = target[nameArray[i]]; + if (!target) { + continue; } + } - //If we reached the end of the list for this scope, - //and something was found, trigger the comparison - //function. If the comparison function is happy, return - //found result. Otherwise, continue to the next parent scope - if (target && comparisonFn(target)) { - return target; - } + //If we reached the end of the list for this scope, + //and something was found, trigger the comparison + //function. If the comparison function is happy, return + //found result. Otherwise, continue to the next parent scope + if (target && comparisonFn(target)) { + return target; + } - } while (parentScope.$parent); + } while (parentScope.$parent); - return false; - }, - findFunction: function (scope, name) { - //Search scope ancestors for a matching function. - return this.scopeSearch(scope, name, function (target) { - //Property must also be a function - return angular.isFunction(target); - }); - }, - findParam: function (scope, name) { - //Search scope ancestors for a matching parameter. - return this.scopeSearch(scope, name, function () { - //As long as the property exists, we're good - return true; - }); - }, - createMoment: function (m) { - if (tz) { - return moment.tz(m, tz); - } else { - //If input is a moment, and we have no TZ info, we need to remove TZ - //info from the moment, otherwise the newly created moment will take - //the timezone of the input moment. The easiest way to do that is to - //take the unix timestamp, and use that to create a new moment. - //The new moment will use the local timezone of the user machine. - return moment.isMoment(m) ? moment.unix(m.unix()) : moment(m); - } - }, - getDate: function (scope, attrs, name) { - var result = false; - if (attrs[name]) { - result = this.createMoment(attrs[name]); - if (!result.isValid()) { - result = this.findParam(scope, attrs[name]); - if (result) { - result = this.createMoment(result); - } + return false; + }, + findFunction: function (scope, name) { + //Search scope ancestors for a matching function. + return this.scopeSearch(scope, name, function (target) { + //Property must also be a function + return angular.isFunction(target); + }); + }, + findParam: function (scope, name) { + //Search scope ancestors for a matching parameter. + return this.scopeSearch(scope, name, function () { + //As long as the property exists, we're good + return true; + }); + }, + createMoment: function (m) { + if (tz) { + return moment.tz(m, tz); + } else { + //If input is a moment, and we have no TZ info, we need to remove TZ + //info from the moment, otherwise the newly created moment will take + //the timezone of the input moment. The easiest way to do that is to + //take the unix timestamp, and use that to create a new moment. + //The new moment will use the local timezone of the user machine. + return moment.isMoment(m) ? moment.unix(m.unix()) : moment(m); + } + }, + getDate: function (scope, attrs, name) { + var result = false; + if (attrs[name]) { + result = this.createMoment(attrs[name]); + if (!result.isValid()) { + result = this.findParam(scope, attrs[name]); + if (result) { + result = this.createMoment(result); } } - - return result; - }, - eventIsForPicker: function (targetIDs, pickerID) { - //Checks if an event targeted at a specific picker, via either a string name, or an array of strings. - return (angular.isArray(targetIDs) && targetIDs.indexOf(pickerID) > -1 || targetIDs === pickerID); } - }; - }); -//})); - -//(function (global, factory) { -// 'use strict'; -// var fnc; -// fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) : -// (typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) : -// factory(global.angular, global.moment); -//}(this, function (angular, moment) { -var Module = angular.module('datePicker'); - Module.directive('dateRange', ['$compile', 'datePickerUtils', 'dateTimeConfig', function ($compile, datePickerUtils, dateTimeConfig) { - function getTemplate(attrs, id, model, min, max) { - return dateTimeConfig.template(angular.extend(attrs, { - ngModel: model, - minDate: min && moment.isMoment(min) ? min.format() : false, - maxDate: max && moment.isMoment(max) ? max.format() : false - }), id); - } - - function randomName() { - return 'picker' + Math.random().toString().substr(2); + return result; + }, + eventIsForPicker: function (targetIDs, pickerID) { + //Checks if an event targeted at a specific picker, via either a string name, or an array of strings. + return (angular.isArray(targetIDs) && targetIDs.indexOf(pickerID) > -1 || targetIDs === pickerID); } + }; +}); - return { - scope: { - start: '=', - end: '=' - }, - link: function (scope, element, attrs) { - var dateChange = null, - pickerRangeID = element[0].id, - pickerIDs = [randomName(), randomName()], - createMoment = datePickerUtils.createMoment, - eventIsForPicker = datePickerUtils.eventIsForPicker; - - scope.dateChange = function (modelName, newDate) { - //Notify user if callback exists. - if (dateChange) { - dateChange(modelName, newDate); - } - }; - - function setMax(date) { - scope.$broadcast('pickerUpdate', pickerIDs[0], { - maxDate: date - }); - } - - function setMin(date) { - scope.$broadcast('pickerUpdate', pickerIDs[1], { - minDate: date - }); - } +var Module = angular.module('datePicker'); - if (pickerRangeID) { - scope.$on('pickerUpdate', function (event, targetIDs, data) { - if (eventIsForPicker(targetIDs, pickerRangeID)) { - //If we received an update event, dispatch it to the inner pickers using their IDs. - scope.$broadcast('pickerUpdate', pickerIDs, data); - } - }); +Module.directive('dateRange', ['$compile', 'datePickerUtils', 'dateTimeConfig', function ($compile, datePickerUtils, dateTimeConfig) { + function getTemplate(attrs, id, model, min, max) { + return dateTimeConfig.template(angular.extend(attrs, { + ngModel: model, + minDate: min && moment.isMoment(min) ? min.format() : false, + maxDate: max && moment.isMoment(max) ? max.format() : false + }), id); + } + + function randomName() { + return 'picker' + Math.random().toString().substr(2); + } + + return { + scope: { + start: '=', + end: '=' + }, + link: function (scope, element, attrs) { + var dateChange = null, + pickerRangeID = element[0].id, + pickerIDs = [randomName(), randomName()], + createMoment = datePickerUtils.createMoment, + eventIsForPicker = datePickerUtils.eventIsForPicker; + + scope.dateChange = function (modelName, newDate) { + //Notify user if callback exists. + if (dateChange) { + dateChange(modelName, newDate); } + }; - datePickerUtils.setParams(attrs.timezone); + function setMax(date) { + scope.$broadcast('pickerUpdate', pickerIDs[0], { + maxDate: date + }); + } - scope.start = createMoment(scope.start); - scope.end = createMoment(scope.end); + function setMin(date) { + scope.$broadcast('pickerUpdate', pickerIDs[1], { + minDate: date + }); + } - scope.$watchGroup(['start', 'end'], function (dates) { - //Scope data changed, update picker min/max - setMin(dates[0]); - setMax(dates[1]); + if (pickerRangeID) { + scope.$on('pickerUpdate', function (event, targetIDs, data) { + if (eventIsForPicker(targetIDs, pickerRangeID)) { + //If we received an update event, dispatch it to the inner pickers using their IDs. + scope.$broadcast('pickerUpdate', pickerIDs, data); + } }); + } - if (angular.isDefined(attrs.dateChange)) { - dateChange = datePickerUtils.findFunction(scope, attrs.dateChange); - } + datePickerUtils.setParams({zone: attrs.timezone}); - attrs.onSetDate = 'dateChange'; + scope.start = createMoment(scope.start); + scope.end = createMoment(scope.end); - var template = '
' + - getTemplate(attrs, pickerIDs[0], 'start', false, scope.end) + - '' + - getTemplate(attrs, pickerIDs[1], 'end', scope.start, false) + - '
'; + scope.$watchGroup(['start', 'end'], function (dates) { + //Scope data changed, update picker min/max + setMin(dates[0]); + setMax(dates[1]); + }); - var picker = $compile(template)(scope); - element.append(picker); + if (angular.isDefined(attrs.dateChange)) { + dateChange = datePickerUtils.findFunction(scope, attrs.dateChange); } - }; - }]); -//})); - -//(function (global, factory) { -// 'use strict'; -// var fnc; -// fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) : -// (typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) : -// factory(global.angular, global.moment); -//}(this, function (angular, moment) { + + attrs.onSetDate = 'dateChange'; + + var template = '
' + + getTemplate(attrs, pickerIDs[0], 'start', false, scope.end) + + '' + + getTemplate(attrs, pickerIDs[1], 'end', scope.start, false) + + '
'; + + var picker = $compile(template)(scope); + element.append(picker); + } + }; +}]); + var PRISTINE_CLASS = 'ng-pristine', - DIRTY_CLASS = 'ng-dirty'; - - var Module = angular.module('datePicker'); - - Module.constant('dateTimeConfig', { - template: function (attrs, id) { - return '' + - '
'; - }, - format: 'YYYY-MM-DD HH:mm', - views: ['date', 'year', 'month', 'hours', 'minutes'], - autoClose: false, - position: 'relative' - }); - - Module.directive('dateTimeAppend', function () { - return { - link: function (scope, element) { - element.bind('click', function () { - element.find('input')[0].focus(); - }); + DIRTY_CLASS = 'ng-dirty'; + +var Module = angular.module('datePicker'); + +Module.constant('dateTimeConfig', { + template: function (attrs, id) { + return '' + + '
'; + }, + format: 'YYYY-MM-DD HH:mm', + views: ['date', 'year', 'month', 'hours', 'minutes'], + autoClose: false, + position: 'relative' +}); + +Module.directive('dateTimeAppend', function () { + return { + link: function (scope, element) { + element.bind('click', function () { + element.find('input')[0].focus(); + }); + } + }; +}); + +Module.directive('dateTime', ['$compile', '$document', '$filter', 'dateTimeConfig', '$parse', 'datePickerUtils', function ($compile, $document, $filter, dateTimeConfig, $parse, datePickerUtils) { + var body = $document.find('body'); + var dateFilter = $filter('mFormat'); + + return { + require: 'ngModel', + scope: true, + link: function (scope, element, attrs, ngModel) { + var format = attrs.format || dateTimeConfig.format, + parentForm = element.inheritedData('$formController'), + views = $parse(attrs.views)(scope) || dateTimeConfig.views.concat(), + view = attrs.view || views[0], + index = views.indexOf(view), + dismiss = attrs.autoClose ? $parse(attrs.autoClose)(scope) : dateTimeConfig.autoClose, + picker = null, + pickerID = element[0].id, + position = attrs.position || dateTimeConfig.position, + container = null, + minDate = null, + minValid = null, + maxDate = null, + maxValid = null, + timezone = attrs.timezone || false, + eventIsForPicker = datePickerUtils.eventIsForPicker, + dateChange = null, + shownOnce = false, + template; + + datePickerUtils.setParams({ isAmPmFormat: format.match(/[aA]/) }); + + if (index === -1) { + views.splice(index, 1); } - }; - }); - - Module.directive('dateTime', ['$compile', '$document', '$filter', 'dateTimeConfig', '$parse', 'datePickerUtils', function ($compile, $document, $filter, dateTimeConfig, $parse, datePickerUtils) { - var body = $document.find('body'); - var dateFilter = $filter('mFormat'); - - return { - require: 'ngModel', - scope: true, - link: function (scope, element, attrs, ngModel) { - var format = attrs.format || dateTimeConfig.format, - parentForm = element.inheritedData('$formController'), - views = $parse(attrs.views)(scope) || dateTimeConfig.views.concat(), - view = attrs.view || views[0], - index = views.indexOf(view), - dismiss = attrs.autoClose ? $parse(attrs.autoClose)(scope) : dateTimeConfig.autoClose, - picker = null, - pickerID = element[0].id, - position = attrs.position || dateTimeConfig.position, - container = null, - minDate = null, - minValid = null, - maxDate = null, - maxValid = null, - timezone = attrs.timezone || false, - eventIsForPicker = datePickerUtils.eventIsForPicker, - dateChange = null, - shownOnce = false, - template; - - if (index === -1) { - views.splice(index, 1); - } - views.unshift(view); + views.unshift(view); - function formatter(value) { - return dateFilter(value, format, timezone); - } + function formatter(value) { + return dateFilter(value, format, timezone); + } - function parser(viewValue) { - if (viewValue.length === format.length) { - return viewValue; - } - return undefined; + function parser(viewValue) { + if (viewValue.length === format.length) { + return viewValue; } + return undefined; + } - function setMin(date) { - minDate = date; - attrs.minDate = date ? date.format() : date; - minValid = moment.isMoment(date); - } + function setMin(date) { + minDate = date; + attrs.minDate = date ? date.format() : date; + minValid = moment.isMoment(date); + } - function setMax(date) { - maxDate = date; - attrs.maxDate = date ? date.format() : date; - maxValid = moment.isMoment(date); - } + function setMax(date) { + maxDate = date; + attrs.maxDate = date ? date.format() : date; + maxValid = moment.isMoment(date); + } - ngModel.$formatters.push(formatter); - ngModel.$parsers.unshift(parser); + ngModel.$formatters.push(formatter); + ngModel.$parsers.unshift(parser); - if (angular.isDefined(attrs.minDate)) { - setMin(datePickerUtils.findParam(scope, attrs.minDate)); + if (angular.isDefined(attrs.minDate)) { + setMin(datePickerUtils.findParam(scope, attrs.minDate)); - ngModel.$validators.min = function (value) { - //If we don't have a min / max value, then any value is valid. - return minValid ? moment.isMoment(value) && (minDate.isSame(value) || minDate.isBefore(value)) : true; - }; - } + ngModel.$validators.min = function (value) { + //If we don't have a min / max value, then any value is valid. + return minValid ? moment.isMoment(value) && (minDate.isSame(value) || minDate.isBefore(value)) : true; + }; + } - if (angular.isDefined(attrs.maxDate)) { - setMax(datePickerUtils.findParam(scope, attrs.maxDate)); + if (angular.isDefined(attrs.maxDate)) { + setMax(datePickerUtils.findParam(scope, attrs.maxDate)); - ngModel.$validators.max = function (value) { - return maxValid ? moment.isMoment(value) && (maxDate.isSame(value) || maxDate.isAfter(value)) : true; - }; - } + ngModel.$validators.max = function (value) { + return maxValid ? moment.isMoment(value) && (maxDate.isSame(value) || maxDate.isAfter(value)) : true; + }; + } - if (angular.isDefined(attrs.dateChange)) { - dateChange = datePickerUtils.findFunction(scope, attrs.dateChange); - } + if (angular.isDefined(attrs.dateChange)) { + dateChange = datePickerUtils.findFunction(scope, attrs.dateChange); + } - function getTemplate() { - template = dateTimeConfig.template(attrs); - } + function getTemplate() { + template = dateTimeConfig.template(attrs); + } - function updateInput(event) { - event.stopPropagation(); - if (ngModel.$pristine) { - ngModel.$dirty = true; - ngModel.$pristine = false; - element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS); - if (parentForm) { - parentForm.$setDirty(); - } - ngModel.$render(); + function updateInput(event) { + event.stopPropagation(); + if (ngModel.$pristine) { + ngModel.$dirty = true; + ngModel.$pristine = false; + element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS); + if (parentForm) { + parentForm.$setDirty(); } + ngModel.$render(); } + } - function clear() { - if (picker) { - picker.remove(); - picker = null; - } - if (container) { - container.remove(); - container = null; - } + function clear() { + if (picker) { + picker.remove(); + picker = null; } - - if (pickerID) { - scope.$on('pickerUpdate', function (event, pickerIDs, data) { - if (eventIsForPicker(pickerIDs, pickerID)) { - if (picker) { - //Need to handle situation where the data changed but the picker is currently open. - //To handle this, we can create the inner picker with a random ID, then forward - //any events received to it. - } else { - var validateRequired = false; - if (angular.isDefined(data.minDate)) { - setMin(data.minDate); - validateRequired = true; - } - if (angular.isDefined(data.maxDate)) { - setMax(data.maxDate); - validateRequired = true; - } - - if (angular.isDefined(data.minView)) { - attrs.minView = data.minView; - } - if (angular.isDefined(data.maxView)) { - attrs.maxView = data.maxView; - } - attrs.view = data.view || attrs.view; - - if (validateRequired) { - ngModel.$validate(); - } - if (angular.isDefined(data.format)) { - format = attrs.format = data.format || dateTimeConfig.format; - ngModel.$modelValue = -1; //Triggers formatters. This value will be discarded. - } - getTemplate(); - } - } - }); + if (container) { + container.remove(); + container = null; } + } - function showPicker() { - if (picker) { - return; - } - // create picker element - picker = $compile(template)(scope); - scope.$digest(); - - //If the picker has already been shown before then we shouldn't be binding to events, as these events are already bound to in this scope. - if (!shownOnce) { - scope.$on('setDate', function (event, date, view) { - updateInput(event); - if (dateChange) { - dateChange(attrs.ngModel, date); + if (pickerID) { + scope.$on('pickerUpdate', function (event, pickerIDs, data) { + if (eventIsForPicker(pickerIDs, pickerID)) { + if (picker) { + //Need to handle situation where the data changed but the picker is currently open. + //To handle this, we can create the inner picker with a random ID, then forward + //any events received to it. + } else { + var validateRequired = false; + if (angular.isDefined(data.minDate)) { + setMin(data.minDate); + validateRequired = true; } - if (dismiss && views[views.length - 1] === view) { - clear(); + if (angular.isDefined(data.maxDate)) { + setMax(data.maxDate); + validateRequired = true; } - }); - - scope.$on('hidePicker', function () { - element.triggerHandler('blur'); - }); - scope.$on('$destroy', clear); + if (angular.isDefined(data.minView)) { + attrs.minView = data.minView; + } + if (angular.isDefined(data.maxView)) { + attrs.maxView = data.maxView; + } + attrs.view = data.view || attrs.view; - shownOnce = true; + if (validateRequired) { + ngModel.$validate(); + } + if (angular.isDefined(data.format)) { + format = attrs.format = data.format || dateTimeConfig.format; + ngModel.$modelValue = -1; //Triggers formatters. This value will be discarded. + } + getTemplate(); + } } + }); + } + function showPicker() { + if (picker) { + return; + } + // create picker element + picker = $compile(template)(scope); + scope.$digest(); + + //If the picker has already been shown before then we shouldn't be binding to events, as these events are already bound to in this scope. + if (!shownOnce) { + scope.$on('setDate', function (event, date, view) { + updateInput(event); + if (dateChange) { + dateChange(attrs.ngModel, date); + } + if (dismiss && views[views.length - 1] === view) { + clear(); + } + }); - // move picker below input element - - if (position === 'absolute') { - var pos = element[0].getBoundingClientRect(); - // Support IE8 - var height = pos.height || element[0].offsetHeight; - picker.css({top: (pos.top + height) + 'px', left: pos.left + 'px', display: 'block', position: position}); - body.append(picker); - } else { - // relative - container = angular.element('
'); - element[0].parentElement.insertBefore(container[0], element[0]); - container.append(picker); - // this approach doesn't work - // element.before(picker); - picker.css({top: element[0].offsetHeight + 'px', display: 'block'}); - } - picker.bind('mousedown', function (evt) { - evt.preventDefault(); + scope.$on('hidePicker', function () { + element.triggerHandler('blur'); }); + + scope.$on('$destroy', clear); + + shownOnce = true; } - element.bind('focus', showPicker); - element.bind('blur', clear); - getTemplate(); + + // move picker below input element + + if (position === 'absolute') { + var pos = element[0].getBoundingClientRect(); + // Support IE8 + var height = pos.height || element[0].offsetHeight; + picker.css({top: (pos.top + height) + 'px', left: pos.left + 'px', display: 'block', position: position}); + body.append(picker); + } else { + // relative + container = angular.element('
'); + element[0].parentElement.insertBefore(container[0], element[0]); + container.append(picker); + // this approach doesn't work + // element.before(picker); + picker.css({top: element[0].offsetHeight + 'px', display: 'block'}); + } + picker.bind('mousedown', function (evt) { + evt.preventDefault(); + }); } - }; - }]); -//})); + + element.bind('focus', showPicker); + element.bind('blur', clear); + getTemplate(); + } + }; +}]); angular.module('datePicker').run(['$templateCache', function($templateCache) { $templateCache.put('templates/datepicker.html', @@ -1115,7 +1087,7 @@ $templateCache.put('templates/datepicker.html', "\n" + " ng-class=\"classes[$index]\"\r" + "\n" + - " ng-click=\"selectDate(hour)\" ng-bind=\"hour|mFormat:'HH:mm':tz\">\r" + + " ng-click=\"selectDate(hour)\" ng-bind=\"hour|mFormat:hoursFormat:tz\">\r" + "\n" + " \r" + "\n" + @@ -1157,7 +1129,7 @@ $templateCache.put('templates/datepicker.html', "\n" + " ng-click=\"selectDate(minute)\"\r" + "\n" + - " ng-bind=\"minute|mFormat:'HH:mm':tz\">\r" + + " ng-bind=\"minute|mFormat:'hoursFormat:tz\">\r" + "\n" + " \r" + "\n" + diff --git a/dist/angular-datepicker.min.css b/dist/angular-datepicker.min.css index 3abd9bd..3ba011f 100644 --- a/dist/angular-datepicker.min.css +++ b/dist/angular-datepicker.min.css @@ -1 +1 @@ -.clearfix:after,.clearfix:before{display:table;content:"";line-height:0}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}[date-picker],[date-picker] td,[date-picker] th{-webkit-border-radius:4px;-moz-border-radius:4px}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.date-picker-date-time{position:absolute}.date-range .date-picker-date-time{position:inherit}[date-picker-wrapper]{position:absolute;min-width:220px;z-index:10;display:block;font-size:14px}[date-time-append] [date-picker-wrapper] [date-picker]{margin-top:-30px}[date-time-append] [date-picker]{position:relative;margin-right:-1000px;margin-bottom:-1000px}[date-range] [date-picker] .after.before{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#499dcd;background-image:-moz-linear-gradient(top,#5bc0de,#2f6ab4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f6ab4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f6ab4);background-image:-o-linear-gradient(top,#5bc0de,#2f6ab4);background-image:linear-gradient(to bottom,#5bc0de,#2f6ab4);background-repeat:repeat-x;border-color:#2f6ab4 #2f6ab4 #1f4677;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}[date-range] [date-picker] .after.before.active,[date-range] [date-picker] .after.before.disabled,[date-range] [date-picker] .after.before:active,[date-range] [date-picker] .after.before:hover,[date-range] [date-picker] .after.before[disabled]{color:#fff;background-color:#2f6ab4}[date-range] [date-picker] .after.before.active,[date-range] [date-picker] .after.before:active{background-color:#24528c\9}[date-picker].hidden{display:none}[date-picker]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;border-radius:4px;background-color:#fff;padding:4px}[date-picker] table{margin:0}[date-picker] td,[date-picker] th{padding:4px 5px;text-align:center;width:20px;height:20px;border-radius:4px;border:none}[date-picker] .switch{width:145px}[date-picker] span{display:block;width:23%;height:26px;line-height:25px;float:left;margin:1%;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}[date-picker] span:hover{background:#eee}[date-picker] span.disabled,[date-picker] span.disabled:hover{background:0 0;color:#999;cursor:default}[date-picker] .active,[date-picker] .now{text-shadow:0 -1px 0 rgba(0,0,0,.25);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#fff}[date-picker] .active.active,[date-picker] .active.disabled,[date-picker] .active:active,[date-picker] .active:hover,[date-picker] .active[disabled],[date-picker] .now.active,[date-picker] .now.disabled,[date-picker] .now:active,[date-picker] .now:hover,[date-picker] .now[disabled]{color:#fff;background-color:#04c}[date-picker] .active.active,[date-picker] .active:active,[date-picker] .now.active,[date-picker] .now:active{background-color:#039\9}[date-picker] .now{color:#fff;background-color:#ee735b;background-image:-moz-linear-gradient(top,#ee5f5b,#ee905b);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#ee905b));background-image:-webkit-linear-gradient(top,#ee5f5b,#ee905b);background-image:-o-linear-gradient(top,#ee5f5b,#ee905b);background-image:linear-gradient(to bottom,#ee5f5b,#ee905b);border-color:#ee905b #ee905b #e56218;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}[date-picker] .now.active,[date-picker] .now.disabled,[date-picker] .now:active,[date-picker] .now:hover,[date-picker] .now[disabled]{color:#fff;background-color:#ee905b}[date-picker] .now.active,[date-picker] .now:active{background-color:#e9712d\9}[date-picker] .disabled{background:0 0;color:#999!important;cursor:default}[date-picker] [ng-switch-when=year] span,[date-picker] [ng-switch-when=month] span,[date-picker] [ng-switch-when=minutes] span{height:54px;line-height:54px}[date-picker] [ng-switch-when=date] td{padding:0}[date-picker] [ng-switch-when=date] span{width:100%;height:26px;line-height:26px}[date-picker] [ng-switch-when=date] td span:hover,[date-picker] th:hover{background:#eee;cursor:pointer} \ No newline at end of file +.clearfix:after,.clearfix:before{display:table;content:"";line-height:0}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}[date-picker],[date-picker] td,[date-picker] th{-webkit-border-radius:4px;-moz-border-radius:4px}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.date-picker-date-time{position:absolute}.date-range .date-picker-date-time{position:inherit}[date-picker-wrapper]{position:absolute;min-width:220px;z-index:10;display:block;font-size:14px}[date-time-append] [date-picker-wrapper] [date-picker]{margin-top:-30px}[date-time-append] [date-picker]{position:relative;margin-right:-1000px;margin-bottom:-1000px}[date-range] [date-picker] .after.before{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#499dcd;background-image:-moz-linear-gradient(top,#5bc0de,#2f6ab4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f6ab4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f6ab4);background-image:-o-linear-gradient(top,#5bc0de,#2f6ab4);background-image:linear-gradient(to bottom,#5bc0de,#2f6ab4);background-repeat:repeat-x;border-color:#2f6ab4 #2f6ab4 #1f4677;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}[date-range] [date-picker] .after.before.active,[date-range] [date-picker] .after.before.disabled,[date-range] [date-picker] .after.before:active,[date-range] [date-picker] .after.before:hover,[date-range] [date-picker] .after.before[disabled]{color:#fff;background-color:#2f6ab4}[date-range] [date-picker] .after.before.active,[date-range] [date-picker] .after.before:active{background-color:#24528c\9}[date-picker].hidden{display:none}[date-picker]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;border-radius:4px;background-color:#fff;padding:4px}[date-picker] table{margin:0}[date-picker] td,[date-picker] th{padding:4px 5px;text-align:center;width:20px;height:20px;border-radius:4px;border:none}[date-picker] .switch{width:145px}[date-picker] span{display:block;width:23%;height:26px;line-height:25px;float:left;margin:1%;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}[date-picker] span:hover{background:#eee}[date-picker] span.disabled,[date-picker] span.disabled:hover{background:0 0;color:#999;cursor:default}[date-picker] .active,[date-picker] .now{text-shadow:0 -1px 0 rgba(0,0,0,.25);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#fff}[date-picker] .active.active,[date-picker] .active.disabled,[date-picker] .active:active,[date-picker] .active:hover,[date-picker] .active[disabled],[date-picker] .now.active,[date-picker] .now.disabled,[date-picker] .now:active,[date-picker] .now:hover,[date-picker] .now[disabled]{color:#fff;background-color:#04c}[date-picker] .active.active,[date-picker] .active:active,[date-picker] .now.active,[date-picker] .now:active{background-color:#039\9}[date-picker] .now{color:#fff;background-color:#ee735b;background-image:-moz-linear-gradient(top,#ee5f5b,#ee905b);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#ee905b));background-image:-webkit-linear-gradient(top,#ee5f5b,#ee905b);background-image:-o-linear-gradient(top,#ee5f5b,#ee905b);background-image:linear-gradient(to bottom,#ee5f5b,#ee905b);border-color:#ee905b #ee905b #e56218;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}[date-picker] .now.active,[date-picker] .now.disabled,[date-picker] .now:active,[date-picker] .now:hover,[date-picker] .now[disabled]{color:#fff;background-color:#ee905b}[date-picker] .now.active,[date-picker] .now:active{background-color:#e9712d\9}[date-picker] .disabled{background:0 0;color:#999!important;cursor:default}[date-picker] [ng-switch-when=year] span,[date-picker] [ng-switch-when=month] span,[date-picker] [ng-switch-when=minutes] span{height:54px;line-height:54px}[date-picker] [ng-switch-when=hours] span.am-pm,[date-picker] [ng-switch-when=minutes] span.am-pm{width:45%}[date-picker] [ng-switch-when=date] td{padding:0}[date-picker] [ng-switch-when=date] span{width:100%;height:26px;line-height:26px}[date-picker] [ng-switch-when=date] td span:hover,[date-picker] th:hover{background:#eee;cursor:pointer} \ No newline at end of file diff --git a/dist/angular-datepicker.min.js b/dist/angular-datepicker.min.js index d2754ce..39d7669 100644 --- a/dist/angular-datepicker.min.js +++ b/dist/angular-datepicker.min.js @@ -1 +1 @@ -!function(a,b){"use strict";var c;c="object"==typeof exports&&"undefined"!=typeof module?module.exports=b(require("angular"),require("moment")):"function"==typeof define&&define.amd?define(["angular","moment"],b):b(a.angular,a.moment)}(this,function(a,b){var c=a.module("datePicker",[]);c.constant("datePickerConfig",{template:"templates/datepicker.html",view:"month",views:["year","month","date","hours","minutes"],momentNames:{year:"year",month:"month",date:"day",hours:"hours",minutes:"minutes"},viewConfig:{year:["years","isSameYear"],month:["months","isSameMonth"],hours:["hours","isSameHour"],minutes:["minutes","isSameMinutes"]},step:5}),c.filter("mFormat",function(){return function(a,c,d){return b.isMoment(a)?d?b.tz(a,d).format(c):a.format(c):b(a).format(c)}}),c.directive("datePicker",["datePickerConfig","datePickerUtils",function(c,d){return{require:"?ngModel",template:'
',scope:{model:"=datePicker",after:"=?",before:"=?"},link:function(e,f,g,h){function i(){e.views=c.views.concat(),e.view=g.view||c.view,e.views=e.views.slice(e.views.indexOf(g.maxView||"year"),e.views.indexOf(g.minView||"minutes")+1),(1===e.views.length||-1===e.views.indexOf(e.view))&&(e.view=e.views[0])}function j(a){return d.getDate(e,g,a)}function k(){var a=e.view;d.setParams(t,E),e.model&&!s&&(e.date=u(e.model),s=!1);var b=e.date;switch(a){case"year":e.years=d.getVisibleYears(b);break;case"month":e.months=d.getVisibleMonths(b);break;case"date":e.weekdays=e.weekdays||d.getDaysOfWeek(),e.weeks=d.getVisibleWeeks(b);break;case"hours":e.hours=d.getVisibleHours(b);break;case"minutes":e.minutes=d.getVisibleMinutes(b,w)}n()}function l(){return"date"!==e.view?e.view:e.date?e.date.month():null}var m,n,o,p,q,r,s=!1,t=e.tz=g.timezone,u=d.createMoment,v=d.eventIsForPicker,w=parseInt(g.step||c.step,10),x=!!g.partial,y=j("minDate"),z=j("maxDate"),A=f[0].id,B=e.now=u(),C=e.date=u(e.model||B),D="true"===g.autoClose,E=g.firstDay&&g.firstDay>=0&&g.firstDay<=6?parseInt(g.firstDay,10):b().weekday(0).day();d.setParams(t,E),e.model||C.minute(Math.ceil(C.minute()/w)*w).second(0),e.template=g.template||c.template,e.watchDirectChanges=void 0!==g.watchDirectChanges,e.callbackOnSetDate=g.dateChange?d.findFunction(e,g.dateChange):void 0,i(),e.setView=function(a){-1!==e.views.indexOf(a)&&(e.view=a)},e.selectDate=function(a){if(g.disabled)return!1;if(o(e.date,a)&&(a=e.date),a=p(a),!a)return!1;e.date=a;var b=e.views[e.views.indexOf(e.view)+1];(!b||x||e.model)&&m(a),b?e.setView(b):D?(f.addClass("hidden"),e.$emit("hidePicker")):n()},m=function(a){a&&(e.model=a,h&&h.$setViewValue(a)),e.$emit("setDate",e.model,e.view),e.callbackOnSetDate&&e.callbackOnSetDate(g.datePicker,e.date)},e.$watch(l,k),e.watchDirectChanges&&e.$watch("model",function(){s=!1,k()}),n=function(){var a,b,f=e.view,g=e.date,h=[],i="";if(d.setParams(t,E),"date"===f){var j,k=e.weeks;for(a=0;ad;d+=b)c=e(f,g,h,i-j,d),k.push(c);return k},getVisibleWeeks:function(a){a=b(a);var c=a.year(),e=a.month();a.date(1);var f=a.day();a.date(d-(f+(d>=f?6:-1)));for(var g=[];g.length<6&&!(a.year()===c&&a.month()>e);)g.push(this.getDaysOfWeek(a)),a.add(7,"d");return g},getVisibleYears:function(a){var c=b(a),d=c.year();c.year(d-d%10),d=c.year();for(var f,g,h=c.utcOffset()/60,i=[],j=0;12>j;j++)f=e(d,0,1,0-h),g=f.utcOffset()/60,g!==h&&(f=e(d,0,1,0-g),h=g),i.push(f),d++;return i},getDaysOfWeek:function(a){a=a?a:c?b.tz(c).day(d):b().day(d);for(var f,g,h=a.year(),i=a.month(),j=a.date(),k=[],l=a.utcOffset()/60,m=0;7>m;m++)f=e(h,i,j,0-l,0,!1),g=f.utcOffset()/60,g!==l&&(f=e(h,i,j,0-g,0,!1)),k.push(f),j++;return k},getVisibleMonths:function(a){for(var b,c,d=a.year(),f=a.utcOffset()/60,g=[],h=0;12>h;h++)b=e(d,h,1,0-f,0,!1),c=b.utcOffset()/60,c!==f&&(b=e(d,h,1,0-c,0,!1)),g.push(b);return g},getVisibleHours:function(a){var b,c,d,f=a.year(),g=a.month(),h=a.date(),i=[],j=a.utcOffset()/60;for(b=0;24>b;b++)c=e(f,g,h,b-j,0,!1),d=c.utcOffset()/60,d!==j&&(c=e(f,g,h,b-d,0,!1)),i.push(c);return i},isAfter:function(a,b){return a&&a.unix()>=b.unix()},isBefore:function(a,b){return a.unix()<=b.unix()},isSameYear:function(a,b){return a&&a.year()===b.year()},isSameMonth:function(a,b){return this.isSameYear(a,b)&&a.month()===b.month()},isSameDay:function(a,b){return this.isSameMonth(a,b)&&a.date()===b.date()},isSameHour:function(a,b){return this.isSameDay(a,b)&&a.hours()===b.hours()},isSameMinutes:function(a,b){return this.isSameHour(a,b)&&a.minutes()===b.minutes()},setParams:function(a,b){c=a,d=b},scopeSearch:function(a,b,c){var d,e,f=a,g=b.split("."),h=g.length;do{for(d=f=f.$parent,e=0;h>e;e++){d=d[g[e]]}if(d&&c(d))return d}while(f.$parent);return!1},findFunction:function(b,c){return this.scopeSearch(b,c,function(b){return a.isFunction(b)})},findParam:function(a,b){return this.scopeSearch(a,b,function(){return!0})},createMoment:function(a){return c?b.tz(a,c):b.isMoment(a)?b.unix(a.unix()):b(a)},getDate:function(a,b,c){var d=!1;return b[c]&&(d=this.createMoment(b[c]),d.isValid()||(d=this.findParam(a,b[c]),d&&(d=this.createMoment(d)))),d},eventIsForPicker:function(b,c){return a.isArray(b)&&b.indexOf(c)>-1||b===c}}});var c=a.module("datePicker");c.directive("dateRange",["$compile","datePickerUtils","dateTimeConfig",function(c,d,e){function f(c,d,f,g,h){return e.template(a.extend(c,{ngModel:f,minDate:g&&b.isMoment(g)?g.format():!1,maxDate:h&&b.isMoment(h)?h.format():!1}),d)}function g(){return"picker"+Math.random().toString().substr(2)}return{scope:{start:"=",end:"="},link:function(b,e,h){function i(a){b.$broadcast("pickerUpdate",m[0],{maxDate:a})}function j(a){b.$broadcast("pickerUpdate",m[1],{minDate:a})}var k=null,l=e[0].id,m=[g(),g()],n=d.createMoment,o=d.eventIsForPicker;b.dateChange=function(a,b){k&&k(a,b)},l&&b.$on("pickerUpdate",function(a,c,d){o(c,l)&&b.$broadcast("pickerUpdate",m,d)}),d.setParams(h.timezone),b.start=n(b.start),b.end=n(b.end),b.$watchGroup(["start","end"],function(a){j(a[0]),i(a[1])}),a.isDefined(h.dateChange)&&(k=d.findFunction(b,h.dateChange)),h.onSetDate="dateChange";var p='
'+f(h,m[0],"start",!1,b.end)+''+f(h,m[1],"end",b.start,!1)+"
",q=c(p)(b);e.append(q)}}}]);var d="ng-pristine",e="ng-dirty",c=a.module("datePicker");c.constant("dateTimeConfig",{template:function(a,b){return"
'},format:"YYYY-MM-DD HH:mm",views:["date","year","month","hours","minutes"],autoClose:!1,position:"relative"}),c.directive("dateTimeAppend",function(){return{link:function(a,b){b.bind("click",function(){b.find("input")[0].focus()})}}}),c.directive("dateTime",["$compile","$document","$filter","dateTimeConfig","$parse","datePickerUtils",function(c,f,g,h,i,j){var k=f.find("body"),l=g("mFormat");return{require:"ngModel",scope:!0,link:function(f,g,m,n){function o(a){return l(a,x,L)}function p(a){return a.length===x.length?a:void 0}function q(a){H=a,m.minDate=a?a.format():a,I=b.isMoment(a)}function r(a){J=a,m.maxDate=a?a.format():a,K=b.isMoment(a)}function s(){w=h.template(m)}function t(a){a.stopPropagation(),n.$pristine&&(n.$dirty=!0,n.$pristine=!1,g.removeClass(d).addClass(e),y&&y.$setDirty(),n.$render())}function u(){D&&(D.remove(),D=null),G&&(G.remove(),G=null)}function v(){if(!D){if(D=c(w)(f),f.$digest(),O||(f.$on("setDate",function(a,b,c){t(a),N&&N(m.ngModel,b),C&&z[z.length-1]===c&&u()}),f.$on("hidePicker",function(){g.triggerHandler("blur")}),f.$on("$destroy",u),O=!0),"absolute"===F){var b=g[0].getBoundingClientRect(),d=b.height||g[0].offsetHeight;D.css({top:b.top+d+"px",left:b.left+"px",display:"block",position:F}),k.append(D)}else G=a.element("
"),g[0].parentElement.insertBefore(G[0],g[0]),G.append(D),D.css({top:g[0].offsetHeight+"px",display:"block"});D.bind("mousedown",function(a){a.preventDefault()})}}var w,x=m.format||h.format,y=g.inheritedData("$formController"),z=i(m.views)(f)||h.views.concat(),A=m.view||z[0],B=z.indexOf(A),C=m.autoClose?i(m.autoClose)(f):h.autoClose,D=null,E=g[0].id,F=m.position||h.position,G=null,H=null,I=null,J=null,K=null,L=m.timezone||!1,M=j.eventIsForPicker,N=null,O=!1;-1===B&&z.splice(B,1),z.unshift(A),n.$formatters.push(o),n.$parsers.unshift(p),a.isDefined(m.minDate)&&(q(j.findParam(f,m.minDate)),n.$validators.min=function(a){return I?b.isMoment(a)&&(H.isSame(a)||H.isBefore(a)):!0}),a.isDefined(m.maxDate)&&(r(j.findParam(f,m.maxDate)),n.$validators.max=function(a){return K?b.isMoment(a)&&(J.isSame(a)||J.isAfter(a)):!0}),a.isDefined(m.dateChange)&&(N=j.findFunction(f,m.dateChange)),E&&f.$on("pickerUpdate",function(b,c,d){if(M(c,E))if(D);else{var e=!1;a.isDefined(d.minDate)&&(q(d.minDate),e=!0),a.isDefined(d.maxDate)&&(r(d.maxDate),e=!0),a.isDefined(d.minView)&&(m.minView=d.minView),a.isDefined(d.maxView)&&(m.maxView=d.maxView),m.view=d.view||m.view,e&&n.$validate(),a.isDefined(d.format)&&(x=m.format=d.format||h.format,n.$modelValue=-1),s()}}),g.bind("focus",v),g.bind("blur",u),s()}}}]),a.module("datePicker").run(["$templateCache",function(a){a.put("templates/datepicker.html",'
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
')}])}); \ No newline at end of file +!function(a,b){"use strict";var c;c="object"==typeof exports&&"undefined"!=typeof module?module.exports=b(require("angular"),require("moment")):"function"==typeof define&&define.amd?define(["angular","moment"],b):b(a.angular,a.moment)}(this,function(a,b){var c=a.module("datePicker",[]);c.constant("datePickerConfig",{template:"templates/datepicker.html",view:"month",views:["year","month","date","hours","minutes"],momentNames:{year:"year",month:"month",date:"day",hours:"hours",minutes:"minutes"},viewConfig:{year:["years","isSameYear"],month:["months","isSameMonth"],hours:["hours","isSameHour"],minutes:["minutes","isSameMinutes"]},step:5}),c.filter("mFormat",function(){return function(a,c,d){return b.isMoment(a)?d?b.tz(a,d).format(c):a.format(c):b(a).format(c)}}),c.directive("datePicker",["datePickerConfig","datePickerUtils",function(c,d){return{require:"?ngModel",template:'
',scope:{model:"=datePicker",after:"=?",before:"=?"},link:function(e,f,g,h){function i(){e.views=c.views.concat(),e.view=g.view||c.view,e.views=e.views.slice(e.views.indexOf(g.maxView||"year"),e.views.indexOf(g.minView||"minutes")+1),1!==e.views.length&&-1!==e.views.indexOf(e.view)||(e.view=e.views[0])}function j(a){return d.getDate(e,g,a)}function k(){var a=e.view;d.setParams({zone:t,fd:E}),e.model&&!s&&(e.date=u(e.model),s=!1);var b=e.date;switch(a){case"year":e.years=d.getVisibleYears(b);break;case"month":e.months=d.getVisibleMonths(b);break;case"date":e.weekdays=e.weekdays||d.getDaysOfWeek(),e.weeks=d.getVisibleWeeks(b);break;case"hours":e.hours=d.getVisibleHours(b),e.hoursFormat=e.hours.isAmPmFormat?"hh:mm a":"HH:mm";break;case"minutes":e.minutes=d.getVisibleMinutes(b,w)}n()}function l(){return"date"!==e.view?e.view:e.date?e.date.month():null}var m,n,o,p,q,r,s=!1,t=e.tz=g.timezone,u=d.createMoment,v=d.eventIsForPicker,w=parseInt(g.step||c.step,10),x=!!g.partial,y=j("minDate"),z=j("maxDate"),A=f[0].id,B=e.now=u(),C=e.date=u(e.model||B),D="true"===g.autoClose,E=g.firstDay&&g.firstDay>=0&&g.firstDay<=6?parseInt(g.firstDay,10):b().weekday(0).day();d.setParams({zone:t,fd:E}),e.model||C.minute(Math.ceil(C.minute()/w)*w).second(0),e.template=g.template||c.template,e.watchDirectChanges=void 0!==g.watchDirectChanges,e.callbackOnSetDate=g.dateChange?d.findFunction(e,g.dateChange):void 0,i(),e.setView=function(a){-1!==e.views.indexOf(a)&&(e.view=a)},e.selectDate=function(a){if(g.disabled)return!1;if(o(e.date,a)&&(a=e.date),a=p(a),!a)return!1;e.date=a;var b=e.views[e.views.indexOf(e.view)+1];(!b||x||e.model)&&m(a),b?e.setView(b):D?(f.addClass("hidden"),e.$emit("hidePicker")):n()},m=function(a){a&&(e.model=a,h&&h.$setViewValue(a)),e.$emit("setDate",e.model,e.view),e.callbackOnSetDate&&e.callbackOnSetDate(g.datePicker,e.date)},e.$watch(l,k),e.watchDirectChanges&&e.$watch("model",function(){s=!1,k()}),n=function(){var a,b,f=e.view,g=e.date,h=[],i="";if(d.setParams({zone:t,fd:E}),"date"===f){var j,k=e.weeks;for(a=0;ad;d+=b)c=f(e,g,h,i-j,d),k.push(c);return k},getVisibleWeeks:function(a){a=b(a);var c=a.year(),e=a.month();a.date(1);var f=a.day();a.date(d-(f+(d>=f?6:-1)));for(var g=[];g.length<6&&!(a.year()===c&&a.month()>e);)g.push(this.getDaysOfWeek(a)),a.add(7,"d");return g},getVisibleYears:function(a){var c=b(a),d=c.year();c.year(d-d%10),d=c.year();for(var e,g,h=c.utcOffset()/60,i=[],j=0;12>j;j++)e=f(d,0,1,0-h),g=e.utcOffset()/60,g!==h&&(e=f(d,0,1,0-g),h=g),i.push(e),d++;return i},getDaysOfWeek:function(a){a=a?a:c?b.tz(c).day(d):b().day(d);for(var e,g,h=a.year(),i=a.month(),j=a.date(),k=[],l=a.utcOffset()/60,m=0;7>m;m++)e=f(h,i,j,0-l,0,!1),g=e.utcOffset()/60,g!==l&&(e=f(h,i,j,0-g,0,!1)),k.push(e),j++;return k},getVisibleMonths:function(a){for(var b,c,d=a.year(),e=a.utcOffset()/60,g=[],h=0;12>h;h++)b=f(d,h,1,0-e,0,!1),c=b.utcOffset()/60,c!==e&&(b=f(d,h,1,0-c,0,!1)),g.push(b);return g},getVisibleHours:function(a){var b,c,d,g=a.year(),h=a.month(),i=a.date(),j=[],k=a.utcOffset()/60;for(b=0;24>b;b++)c=f(g,h,i,b-k,0,!1),d=c.utcOffset()/60,d!==k&&(c=f(g,h,i,b-d,0,!1)),j.push(c);return j.isAmPmFormat=e,j},isAfter:function(a,b){return a&&a.unix()>=b.unix()},isBefore:function(a,b){return a.unix()<=b.unix()},isSameYear:function(a,b){return a&&a.year()===b.year()},isSameMonth:function(a,b){return this.isSameYear(a,b)&&a.month()===b.month()},isSameDay:function(a,b){return this.isSameMonth(a,b)&&a.date()===b.date()},isSameHour:function(a,b){return this.isSameDay(a,b)&&a.hours()===b.hours()},isSameMinutes:function(a,b){return this.isSameHour(a,b)&&a.minutes()===b.minutes()},setParams:function(b){c=a.isDefined(b.zone)?b.zone:c,d=a.isDefined(b.fd)?b.fd:d,e=a.isDefined(b.isAmPmFormat)?b.isAmPmFormat:e},scopeSearch:function(a,b,c){var d,e,f=a,g=b.split("."),h=g.length;do{for(d=f=f.$parent,e=0;h>e;e++){d=d[g[e]]}if(d&&c(d))return d}while(f.$parent);return!1},findFunction:function(b,c){return this.scopeSearch(b,c,function(b){return a.isFunction(b)})},findParam:function(a,b){return this.scopeSearch(a,b,function(){return!0})},createMoment:function(a){return c?b.tz(a,c):b.isMoment(a)?b.unix(a.unix()):b(a)},getDate:function(a,b,c){var d=!1;return b[c]&&(d=this.createMoment(b[c]),d.isValid()||(d=this.findParam(a,b[c]),d&&(d=this.createMoment(d)))),d},eventIsForPicker:function(b,c){return a.isArray(b)&&b.indexOf(c)>-1||b===c}}});var c=a.module("datePicker");c.directive("dateRange",["$compile","datePickerUtils","dateTimeConfig",function(c,d,e){function f(c,d,f,g,h){return e.template(a.extend(c,{ngModel:f,minDate:g&&b.isMoment(g)?g.format():!1,maxDate:h&&b.isMoment(h)?h.format():!1}),d)}function g(){return"picker"+Math.random().toString().substr(2)}return{scope:{start:"=",end:"="},link:function(b,e,h){function i(a){b.$broadcast("pickerUpdate",m[0],{maxDate:a})}function j(a){b.$broadcast("pickerUpdate",m[1],{minDate:a})}var k=null,l=e[0].id,m=[g(),g()],n=d.createMoment,o=d.eventIsForPicker;b.dateChange=function(a,b){k&&k(a,b)},l&&b.$on("pickerUpdate",function(a,c,d){o(c,l)&&b.$broadcast("pickerUpdate",m,d)}),d.setParams({zone:h.timezone}),b.start=n(b.start),b.end=n(b.end),b.$watchGroup(["start","end"],function(a){j(a[0]),i(a[1])}),a.isDefined(h.dateChange)&&(k=d.findFunction(b,h.dateChange)),h.onSetDate="dateChange";var p='
'+f(h,m[0],"start",!1,b.end)+''+f(h,m[1],"end",b.start,!1)+"
",q=c(p)(b);e.append(q)}}}]);var d="ng-pristine",e="ng-dirty",c=a.module("datePicker");c.constant("dateTimeConfig",{template:function(a,b){return"
'},format:"YYYY-MM-DD HH:mm",views:["date","year","month","hours","minutes"],autoClose:!1,position:"relative"}),c.directive("dateTimeAppend",function(){return{link:function(a,b){b.bind("click",function(){b.find("input")[0].focus()})}}}),c.directive("dateTime",["$compile","$document","$filter","dateTimeConfig","$parse","datePickerUtils",function(c,f,g,h,i,j){var k=f.find("body"),l=g("mFormat");return{require:"ngModel",scope:!0,link:function(f,g,m,n){function o(a){return l(a,x,L)}function p(a){return a.length===x.length?a:void 0}function q(a){H=a,m.minDate=a?a.format():a,I=b.isMoment(a)}function r(a){J=a,m.maxDate=a?a.format():a,K=b.isMoment(a)}function s(){w=h.template(m)}function t(a){a.stopPropagation(),n.$pristine&&(n.$dirty=!0,n.$pristine=!1,g.removeClass(d).addClass(e),y&&y.$setDirty(),n.$render())}function u(){D&&(D.remove(),D=null),G&&(G.remove(),G=null)}function v(){if(!D){if(D=c(w)(f),f.$digest(),O||(f.$on("setDate",function(a,b,c){t(a),N&&N(m.ngModel,b),C&&z[z.length-1]===c&&u()}),f.$on("hidePicker",function(){g.triggerHandler("blur")}),f.$on("$destroy",u),O=!0),"absolute"===F){var b=g[0].getBoundingClientRect(),d=b.height||g[0].offsetHeight;D.css({top:b.top+d+"px",left:b.left+"px",display:"block",position:F}),k.append(D)}else G=a.element("
"),g[0].parentElement.insertBefore(G[0],g[0]),G.append(D),D.css({top:g[0].offsetHeight+"px",display:"block"});D.bind("mousedown",function(a){a.preventDefault()})}}var w,x=m.format||h.format,y=g.inheritedData("$formController"),z=i(m.views)(f)||h.views.concat(),A=m.view||z[0],B=z.indexOf(A),C=m.autoClose?i(m.autoClose)(f):h.autoClose,D=null,E=g[0].id,F=m.position||h.position,G=null,H=null,I=null,J=null,K=null,L=m.timezone||!1,M=j.eventIsForPicker,N=null,O=!1;j.setParams({isAmPmFormat:x.match(/[aA]/)}),-1===B&&z.splice(B,1),z.unshift(A),n.$formatters.push(o),n.$parsers.unshift(p),a.isDefined(m.minDate)&&(q(j.findParam(f,m.minDate)),n.$validators.min=function(a){return I?b.isMoment(a)&&(H.isSame(a)||H.isBefore(a)):!0}),a.isDefined(m.maxDate)&&(r(j.findParam(f,m.maxDate)),n.$validators.max=function(a){return K?b.isMoment(a)&&(J.isSame(a)||J.isAfter(a)):!0}),a.isDefined(m.dateChange)&&(N=j.findFunction(f,m.dateChange)),E&&f.$on("pickerUpdate",function(b,c,d){if(M(c,E))if(D);else{var e=!1;a.isDefined(d.minDate)&&(q(d.minDate),e=!0),a.isDefined(d.maxDate)&&(r(d.maxDate),e=!0),a.isDefined(d.minView)&&(m.minView=d.minView),a.isDefined(d.maxView)&&(m.maxView=d.maxView),m.view=d.view||m.view,e&&n.$validate(),a.isDefined(d.format)&&(x=m.format=d.format||h.format,n.$modelValue=-1),s()}}),g.bind("focus",v),g.bind("blur",u),s()}}}]),a.module("datePicker").run(["$templateCache",function(a){a.put("templates/datepicker.html",'
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
')}])}); \ No newline at end of file diff --git a/test/spec/datePickerUtilsTest.js b/test/spec/datePickerUtilsTest.js index 681be4a..d65b3f3 100644 --- a/test/spec/datePickerUtilsTest.js +++ b/test/spec/datePickerUtilsTest.js @@ -15,7 +15,7 @@ describe('Test date Picker Utils', function(){ beforeEach(angular.mock.inject(function($injector){ utils = $injector.get('datePickerUtils'); constants = $injector.get('datePickerConfig'); - utils.setParams(tz, firstDay); + utils.setParams({zone: tz, fd: firstDay}); })); /*