'use strict';
var getTimezoneOffset = function(date) {
(typeof date == 'string') && (date = new Date(date));
var jan = new Date(date.getFullYear(), 0, 1);
var jul = new Date(date.getFullYear(), 6, 1);
var stdTimezoneOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
var isDST = date.getTimezoneOffset() < stdTimezoneOffset;
var offset = isDST ? stdTimezoneOffset - 60 : stdTimezoneOffset;
var diff = offset >=0 ? '-' : '+';
return diff +
("0"+ (offset / 60)).slice(-2) + ':' +
("0"+ (offset % 60)).slice(-2);
};
var DatetimePicker = function($compile, $document, $controller){
var datetimePickerCtrl = $controller('DatetimePickerCtrl'); //directive controller
return {
open: function(options) {
datetimePickerCtrl.openDatetimePicker(options);
},
close: function() {
datetimePickerCtrl.closeDatetimePicker();
}
};
};
DatetimePicker.$inject = ['$compile', '$document', '$controller'];
appDS2.factory('DatetimePicker', DatetimePicker);
var DatetimePickerCtrl = function($compile, $document) {
var datetimePickerEl;
var _this = this;
var removeEl = function(el) {
el && el.remove();
$document[0].body.removeEventListener('click', _this.closeDatetimePicker);
};
this.openDatetimePicker = function(options) {
this.closeDatetimePicker();
var div = angular.element('
');
options.dateFormat && div.attr('date-format', options.dateFormat);
options.ngModel && div.attr('ng-model', options.ngModel);
options.year && div.attr('year', parseInt(options.year));
options.month && div.attr('month', parseInt(options.month));
options.day && div.attr('day', parseInt(options.day));
options.hour && div.attr('hour', parseInt(options.hour));
options.minute && div.attr('minute', parseInt(options.minute));
if (options.dateOnly === '' || options.dateOnly === true) {
div.attr('date-only', 'true');
}
if (options.closeOnSelect === 'false') {
div.attr('close-on-select', 'false');
}
var triggerEl = options.triggerEl;
options.scope = options.scope || angular.element(triggerEl).scope();
datetimePickerEl = $compile(div)(options.scope)[0];
datetimePickerEl.triggerEl = options.triggerEl;
$document[0].body.appendChild(datetimePickerEl);
//show datetimePicker below triggerEl
var bcr = triggerEl.getBoundingClientRect();
options.scope.$apply();
var datePickerElBcr = datetimePickerEl.getBoundingClientRect();
datetimePickerEl.style.position='absolute';
if(bcr.width > datePickerElBcr.width){
datetimePickerEl.style.left= (bcr.left + bcr.width - datePickerElBcr.width + window.scrollX) + 'px';
} else {
datetimePickerEl.style.left= (bcr.left + window.scrollX) + 'px';
}
if (bcr.top < 300 || window.innerHeight - bcr.bottom > 300) {
datetimePickerEl.style.top = (bcr.bottom + window.scrollY) + 'px';
} else {
datetimePickerEl.style.top = (bcr.top - datePickerElBcr.height + window.scrollY) + 'px';
}
$document[0].body.addEventListener('click', this.closeDatetimePicker);
};
this.closeDatetimePicker = function(evt) {
var target = evt && evt.target;
var popupEl = $document[0].querySelector('div[datetime-picker-popup]');
if (evt && target) {
if (target.hasAttribute('datetime-picker')) { // element with datetimePicker behaviour
// do nothing
} else if (popupEl && popupEl.contains(target)) { // datetimePicker itself
// do nothing
} else {
removeEl(popupEl);
}
} else {
removeEl(popupEl);
}
}
};
DatetimePickerCtrl.$inject = ['$compile', '$document'];
appDS2.controller('DatetimePickerCtrl', DatetimePickerCtrl);
var tmpl = [
'' ,
'
',
' ',
' {{months[mv.month].shortName}} {{mv.year}}',
' ',
'
',
'
',
'
{{::dayOfWeek.firstLetter}}
',
'
{{::day}}
',
'
',
' {{::day}}',
'
',
'
{{::day}}
',
'
',
'
',
' {{("0"+inputHour).slice(-2)}} : {{("0"+inputMinute).slice(-2)}}
',
' ',
' ',
'
',
'
'].join("\n");
var datetimePickerPopup = function($locale, dateFilter){
var days, months, daysOfWeek, firstDayOfWeek;
var initVars = function() {
days =[], months=[]; daysOfWeek=[], firstDayOfWeek=0;
for (var i = 1; i <= 31; i++) {
days.push(i);
}
for (var i = 0; i < 12; i++) { //jshint ignore:line
months.push({
fullName: $locale.DATETIME_FORMATS.MONTH[i],
shortName: $locale.DATETIME_FORMATS.SHORTMONTH[i]
});
}
for (var i = 0; i < 7; i++) { //jshint ignore:line
var day = $locale.DATETIME_FORMATS.DAY[(i + firstDayOfWeek) % 7];
daysOfWeek.push({
fullName: day,
firstLetter: day.substr(0, 1)
});
}
firstDayOfWeek = 0;
};
var getMonthView = function(year, month) {
if (month>11) {
year++;
} else if (month < 0) {
year--;
}
month = (month + 12) % 12;
var firstDayOfMonth = new Date(year, month, 1),
lastDayOfMonth = new Date(year, month + 1, 0),
lastDayOfPreviousMonth = new Date(year, month, 0),
daysInMonth = lastDayOfMonth.getDate(),
daysInLastMonth = lastDayOfPreviousMonth.getDate(),
dayOfWeek = firstDayOfMonth.getDay(),
leadingDays = (dayOfWeek - firstDayOfWeek + 7) % 7 || 7, // Ensure there are always leading days to give context
trailingDays = days.slice(0, 6 * 7 - (leadingDays + daysInMonth));
if (trailingDays.length > 7) {
trailingDays = trailingDays.slice(0, trailingDays.length-7);
}
return {
year: year,
month: month,
days: days.slice(0, daysInMonth),
leadingDays: days.slice(- leadingDays - (31 - daysInLastMonth), daysInLastMonth),
trailingDays: trailingDays
};
};
var linkFunc = function(scope, element, attrs, ctrl) { //jshint ignore:line
initVars(); //initialize days, months, daysOfWeek, and firstDayOfWeek;
var dateFormat = attrs.dateFormat || 'short';
scope.months = months;
scope.daysOfWeek = daysOfWeek;
scope.inputHour;
scope.inputMinute;
if (scope.dateOnly === true){
element[0].querySelector('#adp-time').style.display = 'none';
}
scope.$applyAsync( function() {
ctrl.triggerEl = angular.element(element[0].triggerEl);
if (attrs.ngModel) { // need to parse date string
var dateStr = ''+ctrl.triggerEl.scope().$eval(attrs.ngModel);
if (dateStr) {
if (!dateStr.match(/[0-9]{2}:/)) { // if no time is given, add 00:00:00 at the end
dateStr += " 00:00:00";
}
dateStr = dateStr.replace(/([0-9]{2}-[0-9]{2})-([0-9]{4})/,'$2-$1'); //mm-dd-yyyy to yyyy-mm-dd
dateStr = dateStr.replace(/([\/-][0-9]{2,4})\ ([0-9]{2}\:[0-9]{2}\:)/,'$1T$2'); //reformat for FF
dateStr = dateStr.replace(/EDT|EST|CDT|CST|MDT|PDT|PST|UT|GMT/g,''); //remove timezone
dateStr = dateStr.replace(/\s*\(\)\s*/,''); //remove timezone
dateStr = dateStr.replace(/[\-\+][0-9]{2}:?[0-9]{2}$/,''); //remove timezone
dateStr += getTimezoneOffset(dateStr);
var d = new Date(dateStr);
scope.selectedDate = new Date(
d.getFullYear(),
d.getMonth(),
d.getDate(),
d.getHours(),
d.getMinutes(),
d.getSeconds()
);
}
}
if (!scope.selectedDate || isNaN(scope.selectedDate.getTime())) { // no predefined date
var today = new Date();
var year = scope.year || today.getFullYear();
var month = scope.month ? (scope.month-1) : today.getMonth();
var day = scope.day || today.getDate();
var hour = scope.hour || today.getHours();
var minute = scope.minute || today.getMinutes();
scope.selectedDate = new Date(year, month, day, hour, minute, 0);
}
scope.inputHour = scope.selectedDate.getHours();
scope.inputMinute = scope.selectedDate.getMinutes();
// Default to current year and month
scope.mv = getMonthView(scope.selectedDate.getFullYear(), scope.selectedDate.getMonth());
scope.today = dateFilter(new Date(), 'yyyy-M-d');
if (scope.mv.year == scope.selectedDate.getFullYear() && scope.mv.month == scope.selectedDate.getMonth()) {
scope.selectedDay = scope.selectedDate.getDate();
} else {
scope.selectedDay = null;
}
});
/* disable previous months.not current months
scope.addMonth = function (amount) {
var today = new Date();
if((amount==-1) && (scope.mv.month==today.getMonth())){
}
else{
scope.mv = getMonthView(scope.mv.year, scope.mv.month + amount);
}
};*/
scope.addMonth = function (amount) {
scope.mv = getMonthView(scope.mv.year, scope.mv.month + amount);
};
scope.setDate = function (evt) {
var target = angular.element(evt.target)[0];
if (target.className.indexOf('selectable') !== -1) {
scope.updateNgModel(parseInt(target.innerHTML));
if (scope.closeOnSelect !== false) {
ctrl.closeDatetimePicker();
}
}
};
scope.updateNgModel = function(day) {
day = day ? day : scope.selectedDate.getDate();
scope.selectedDate = new Date(
scope.mv.year, scope.mv.month, day, scope.inputHour, scope.inputMinute, 0
);
scope.selectedDay = scope.selectedDate.getDate();
if (attrs.ngModel) {
//console.log('attrs.ngModel',attrs.ngModel);
var elScope = ctrl.triggerEl.scope(), dateValue;
if (elScope.$eval(attrs.ngModel) && elScope.$eval(attrs.ngModel).constructor.name === 'Date') {
dateValue = new Date(dateFilter(scope.selectedDate, dateFormat));
} else {
dateValue = dateFilter(scope.selectedDate, dateFormat);
}
elScope.$eval(attrs.ngModel + '= date', {date: dateValue}); // this line for have the date in the format of mm/dd/yyyy
// elScope.$eval(attrs.ngModel + '= date', {date: scope.selectedDate});// this line in the format of Thu Jul 20 2017 23:59:00 GMT-0400 (Eastern Daylight Time)
}
};
scope.$on('$destroy', ctrl.closeDatetimePicker);
};
return {
restrict: 'A',
template: tmpl,
controller: 'DatetimePickerCtrl',
replace: true,
scope: {
year: '=',
month: '=',
day: '=',
hour: '=',
minute: '=',
dateOnly: '=',
closeOnSelect: '=',
futureOnly:'='
},
link: linkFunc
};
};
datetimePickerPopup.$inject = ['$locale', 'dateFilter'];
appDS2.directive('datetimePickerPopup', datetimePickerPopup);
var datetimePicker = function($parse, DatetimePicker) {
return {
// An ngModel is required to get the controller argument
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
// Attach validation watcher
scope.$watch(attrs.ngModel, function(value) {
if( !value || value == '' ){
return;
}
// The value has already been cleaned by the above code
var date = new Date(value);
ctrl.$setValidity('date', !date? false : true);
var now = new Date();
if( attrs.hasOwnProperty('futureOnly') ){
ctrl.$setValidity('future-only', date < now? false : true);
}
});
element[0].addEventListener('click', function() {
DatetimePicker.open({
triggerEl: element[0],
dateFormat: attrs.dateFormat,
ngModel: attrs.ngModel,
year: attrs.year,
month: attrs.month,
day: attrs.day,
hour: attrs.hour,
minute: attrs.minute,
dateOnly: attrs.dateOnly,
futureOnly: attrs.futureOnly,
closeOnSelect: attrs.closeOnSelect
});
});
}
};
};
datetimePicker.$inject=['$parse', 'DatetimePicker'];
appDS2.directive('datetimePicker', datetimePicker);