se-hub/templates/js/libs/date-picker/js/angular-datepicker.js

549 lines
20 KiB
JavaScript

/*global angular navigator*/
(function withAngular(angular) {
'use strict';
angular.module('720kb.datepicker', [])
.directive('datepicker', ['$window', '$compile', '$locale', '$filter', '$interpolate', function manageDirective($window, $compile, $locale, $filter, $interpolate) {
var A_DAY_IN_MILLISECONDS = 86400000;
return {
'restrict': 'AEC',
'scope': {
'dateSet': '@',
'dateMinLimit': '@',
'dateMaxLimit': '@'
},
'link': function linkingFunction($scope, element, attr) {
//get child input
var selector = attr.selector
, thisInput = angular.element(selector ? element[0].querySelector('.' + selector) : element[0].children[0])
, theCalendar
, defaultPrevButton = '<b class="datepicker-default-button">&lang;</b>'
, defaultNextButton = '<b class="datepicker-default-button">&rang;</b>'
, prevButton = attr.buttonPrev || defaultPrevButton
, nextButton = attr.buttonNext || defaultNextButton
, dateFormat = attr.dateFormat
, dateMinLimit
, dateMaxLimit
, date = new Date()
, isMouseOn = false
, isMouseOnInput = false
, datetime = $locale.DATETIME_FORMATS
, pageDatepickers
, htmlTemplate = '<div class="_720kb-datepicker-calendar" ng-blur="hideCalendar()">' +
//month+year header
'<div class="_720kb-datepicker-calendar-header" ng-hide="isMobile()">' +
'<div class="_720kb-datepicker-calendar-header-left">' +
'<a href="javascript:void(0)" ng-click="prevMonth()">' + prevButton + '</a>' +
'</div>' +
'<div class="_720kb-datepicker-calendar-header-middle _720kb-datepicker-calendar-month">' +
'{{month}} <a href="javascript:void(0)" ng-click="showYearsPagination = !showYearsPagination"><span>{{year}} <i ng-if="!showYearsPagination">&dtrif;</i> <i ng-if="showYearsPagination">&urtri;</i> </span> </a>' +
'</div>' +
'<div class="_720kb-datepicker-calendar-header-right">' +
'<a href="javascript:void(0)" ng-click="nextMonth()">' + nextButton + '</a>' +
'</div>' +
'</div>' +
//Mobile month+year pagination
'<div class="_720kb-datepicker-calendar-header" ng-show="isMobile()">' +
'<div class="_720kb-datepicker-calendar-header-middle _720kb-datepicker-mobile-item _720kb-datepicker-calendar-month">' +
'<select ng-model="month" ng-change="selectedMonthHandle(month)">' +
'<option ng-repeat="item in months" ng-selected="month === item" ng-disabled=\'!isSelectableMaxDate(item + " " + day + ", " + year) || !isSelectableMinDate(item + " " + day + ", " + year)\' ng-value="item">{{item}}</option>' +
'</select>' +
'</div>' +
'</div>' +
'<div class="_720kb-datepicker-calendar-header" ng-show="isMobile()">' +
'<div class="_720kb-datepicker-calendar-header-middle _720kb-datepicker-mobile-item _720kb-datepicker-calendar-month">' +
'<select ng-model="mobileYear" ng-change="setNewYear(mobileYear)">' +
'<option ng-repeat="item in paginationYears" ng-selected="year === item" ng-value="item" ng-disabled="!isSelectableMinYear(item) || !isSelectableMaxYear(item)">{{item}}</option>' +
'</select>' +
'</div>' +
'</div>' +
//years pagination header
'<div class="_720kb-datepicker-calendar-header" ng-show="showYearsPagination">' +
'<div class="_720kb-datepicker-calendar-years-pagination">' +
'<a ng-class="{\'_720kb-datepicker-active\': y === year, \'_720kb-datepicker-disabled\': !isSelectableMaxYear(y) || !isSelectableMinYear(y)}" href="javascript:void(0)" ng-click="setNewYear(y)" ng-repeat="y in paginationYears">{{y}}</a>' +
'</div>' +
'<div class="_720kb-datepicker-calendar-years-pagination-pages">' +
'<a href="javascript:void(0)" ng-click="paginateYears(paginationYears[0])" ng-class="{\'_720kb-datepicker-item-hidden\': paginationYearsPrevDisabled}">' + prevButton + '</a>' +
'<a href="javascript:void(0)" ng-click="paginateYears(paginationYears[paginationYears.length -1 ])" ng-class="{\'_720kb-datepicker-item-hidden\': paginationYearsNextDisabled}">' + nextButton + '</a>' +
'</div>' +
'</div>' +
//days column
'<div class="_720kb-datepicker-calendar-days-header">' +
'<div ng-repeat="d in daysInString"> {{d}} </div> ' +
'</div>' +
//days
'<div class="_720kb-datepicker-calendar-body">' +
'<a href="javascript:void(0)" ng-repeat="px in prevMonthDays" class="_720kb-datepicker-calendar-day _720kb-datepicker-disabled">{{px}}</a>' +
'<a href="javascript:void(0)" ng-repeat="item in days" ng-click="setDatepickerDay(item)" ng-class="{\'_720kb-datepicker-active\': day === item, \'_720kb-datepicker-disabled\': !isSelectableMinDate(year + \'/\' + monthNumber + \'/\' + item ) || !isSelectableMaxDate(year + \'/\' + monthNumber + \'/\' + item)}" class="_720kb-datepicker-calendar-day">{{item}}</a>' +
'<a href="javascript:void(0)" ng-repeat="nx in nextMonthDays" class="_720kb-datepicker-calendar-day _720kb-datepicker-disabled">{{nx}}</a>' +
'</div>' +
'</div>' +
'</div>';
// Respect previously configured interpolation symbols.
htmlTemplate = htmlTemplate.replace(/{{/g, $interpolate.startSymbol())
.replace(/}}/g, $interpolate.endSymbol());
$scope.$watch('dateSet', function dateSetWatcher(value) {
if (value) {
date = new Date(value);
$scope.month = $filter('date')(date, 'MMMM');//December-November like
$scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like
$scope.day = Number($filter('date')(date, 'dd')); //01-31 like
$scope.year = Number($filter('date')(date, 'yyyy'));//2014 like
$scope.setDaysInMonth($scope.monthNumber, $scope.year);
}
});
$scope.$watch('dateMinLimit', function dateMinLimitWatcher(value) {
if (value) {
dateMinLimit = value;
}
});
$scope.$watch('dateMaxLimit', function dateMaxLimitWatcher(value) {
if (value) {
dateMaxLimit = value;
}
});
$scope.month = $filter('date')(date, 'MMMM');//December-November like
$scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like
$scope.day = Number($filter('date')(date, 'dd')); //01-31 like
if ($scope.dateMaxLimit) {
$scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy'));//2014 like
} else {
$scope.year = Number($filter('date')(date, 'yyyy'));//2014 like
}
$scope.months = datetime.MONTH;
$scope.daysInString = ['0', '1', '2', '3', '4', '5', '6'].map(function mappingFunc(el) {
return $filter('date')(new Date(new Date('06/08/2014').valueOf() + A_DAY_IN_MILLISECONDS * el), 'EEE');
});
//create the calendar holder
thisInput.after($compile(angular.element(htmlTemplate))($scope));
//get the calendar as element
theCalendar = element[0].querySelector('._720kb-datepicker-calendar');
//some tricky dirty events to fire if click is outside of the calendar and show/hide calendar when needed
thisInput.bind('focus click', function onFocusAndClick() {
isMouseOnInput = true;
$scope.showCalendar();
});
thisInput.bind('focusout blur', function onBlurAndFocusOut() {
isMouseOnInput = false;
});
angular.element(theCalendar).bind('mouseenter', function onMouseEnter() {
isMouseOn = true;
});
angular.element(theCalendar).bind('mouseleave', function onMouseLeave() {
isMouseOn = false;
});
angular.element(theCalendar).bind('focusin', function onCalendarFocus() {
isMouseOn = true;
});
angular.element($window).bind('click focus', function onClickOnWindow() {
if (!isMouseOn &&
!isMouseOnInput && theCalendar) {
$scope.hideCalendar();
}
});
$scope.isMobile = function isMobile() {
if (navigator.userAgent && (navigator.userAgent.match(/Android/i)
|| navigator.userAgent.match(/webOS/i)
|| navigator.userAgent.match(/iPhone/i)
|| navigator.userAgent.match(/iPad/i)
|| navigator.userAgent.match(/iPod/i)
|| navigator.userAgent.match(/BlackBerry/i)
|| navigator.userAgent.match(/Windows Phone/i))){
return true;
}
};
$scope.resetToMinDate = function manageResetToMinDate() {
$scope.month = $filter('date')(new Date(dateMinLimit), 'MMMM');
$scope.monthNumber = Number($filter('date')(new Date(dateMinLimit), 'MM'));
$scope.day = Number($filter('date')(new Date(dateMinLimit), 'dd'));
$scope.year = Number($filter('date')(new Date(dateMinLimit), 'yyyy'));
};
$scope.resetToMaxDate = function manageResetToMaxDate() {
$scope.month = $filter('date')(new Date(dateMaxLimit), 'MMMM');
$scope.monthNumber = Number($filter('date')(new Date(dateMaxLimit), 'MM'));
$scope.day = Number($filter('date')(new Date(dateMaxLimit), 'dd'));
$scope.year = Number($filter('date')(new Date(dateMaxLimit), 'yyyy'));
};
$scope.nextMonth = function manageNextMonth() {
if ($scope.monthNumber === 12) {
$scope.monthNumber = 1;
//its happy new year
$scope.nextYear();
} else {
$scope.monthNumber += 1;
}
//set next month
$scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM');
//reinit days
$scope.setDaysInMonth($scope.monthNumber, $scope.year);
//check if max date is ok
if (dateMaxLimit) {
if (!$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) {
$scope.resetToMaxDate();
}
}
//deactivate selected day
$scope.day = undefined;
};
$scope.selectedMonthHandle = function manageSelectedMonthHandle (selectedMonth) {
$scope.monthNumber = Number($filter('date')(new Date('01 ' + selectedMonth + ' 2000'), 'MM'));
$scope.setDaysInMonth($scope.monthNumber, $scope.year);
$scope.setInputValue();
};
$scope.prevMonth = function managePrevMonth() {
if ($scope.monthNumber === 1) {
$scope.monthNumber = 12;
//its happy new year
$scope.prevYear();
} else {
$scope.monthNumber -= 1;
}
//set next month
$scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM');
//reinit days
$scope.setDaysInMonth($scope.monthNumber, $scope.year);
//check if min date is ok
if (dateMinLimit) {
if (!$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) {
$scope.resetToMinDate();
}
}
//deactivate selected day
$scope.day = undefined;
};
$scope.setNewYear = function setNewYear (year) {
//deactivate selected day
$scope.day = undefined;
if (dateMaxLimit && $scope.year < Number(year)) {
if (!$scope.isSelectableMaxYear(year)) {
return;
}
} else if (dateMinLimit && $scope.year > Number(year)) {
if (!$scope.isSelectableMinYear(year)) {
return;
}
}
$scope.year = Number(year);
$scope.setDaysInMonth($scope.monthNumber, $scope.year);
$scope.paginateYears(year);
};
$scope.nextYear = function manageNextYear() {
$scope.year = Number($scope.year) + 1;
};
$scope.prevYear = function managePrevYear() {
$scope.year = Number($scope.year) - 1;
};
$scope.setInputValue = function manageInputValue() {
if ($scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)
&& $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) {
var modelDate = new Date($scope.year + '/' + $scope.monthNumber + '/' + $scope.day);
if (attr.dateFormat) {
thisInput.val($filter('date')(modelDate, dateFormat));
} else {
thisInput.val(modelDate);
}
thisInput.triggerHandler('input');
thisInput.triggerHandler('change');//just to be sure;
} else {
return false;
}
};
$scope.classHelper = {
'add': function add(ele, klass){
if (ele.className.indexOf(klass) > -1){
return;
}
var classes = ele.className.split(' ');
classes.push(klass);
ele.className = classes.join(' ');
},
'remove': function remove(ele, klass){
var i, classes;
if (ele.className.indexOf(klass) === -1){
return;
}
classes = ele.className.split(' ');
for (i = 0; i < classes.length; i += 1){
if (classes[i] === klass){
classes = classes.slice(0, i).concat(classes.slice(i + 1));
break;
}
}
ele.className = classes.join(' ');
}
};
$scope.showCalendar = function manageShowCalendar() {
//lets hide all the latest instances of datepicker
pageDatepickers = $window.document.getElementsByClassName('_720kb-datepicker-calendar');
angular.forEach(pageDatepickers, function forEachDatepickerPages(value, key) {
if (pageDatepickers[key].classList) {
pageDatepickers[key].classList.remove('_720kb-datepicker-open');
} else {
$scope.classHelper.remove(pageDatepickers[key], '_720kb-datepicker-open');
}
});
if (theCalendar.classList) {
theCalendar.classList.add('_720kb-datepicker-open');
} else {
$scope.classHelper.add(theCalendar, '_720kb-datepicker-open');
}
};
$scope.hideCalendar = function manageHideCalendar() {
if (theCalendar.classList){
theCalendar.classList.remove('_720kb-datepicker-open');
} else {
$scope.classHelper.remove(theCalendar, '_720kb-datepicker-open');
}
};
$scope.setDaysInMonth = function setDaysInMonth(month, year) {
var i
, limitDate = new Date(year, month, 0).getDate()
, firstDayMonthNumber = new Date(year + '/' + month + '/' + 1).getDay()
, lastDayMonthNumber = new Date(year + '/' + month + '/' + limitDate).getDay()
, prevMonthDays = []
, nextMonthDays = []
, howManyNextDays
, howManyPreviousDays
, monthAlias;
$scope.days = [];
for (i = 1; i <= limitDate; i += 1) {
$scope.days.push(i);
}
//get previous month days is first day in month is not Sunday
if (firstDayMonthNumber !== 0) {
howManyPreviousDays = firstDayMonthNumber;
//get previous month
if (Number(month) === 1) {
monthAlias = 12;
} else {
monthAlias = month - 1;
}
//return previous month days
for (i = 1; i <= new Date(year, monthAlias, 0).getDate(); i += 1) {
prevMonthDays.push(i);
}
//attach previous month days
$scope.prevMonthDays = prevMonthDays.slice(-howManyPreviousDays);
} else {
//no need for it
$scope.prevMonthDays = [];
}
//get next month days is first day in month is not Sunday
if (lastDayMonthNumber < 6) {
howManyNextDays = 6 - lastDayMonthNumber;
//get previous month
//return next month days
for (i = 1; i <= howManyNextDays; i += 1) {
nextMonthDays.push(i);
}
//attach previous month days
$scope.nextMonthDays = nextMonthDays;
} else {
//no need for it
$scope.nextMonthDays = [];
}
};
$scope.setDatepickerDay = function setDatepickeDay(day) {
$scope.day = Number(day);
$scope.setInputValue();
$scope.hideCalendar();
};
$scope.paginateYears = function paginateYears (startingYear) {
$scope.paginationYears = [];
var i
, theNewYears = []
, daysToPrepend = 10, daysToAppend = 10;
if ($scope.isMobile()) {
daysToPrepend = 50;
daysToAppend = 50;
if ( $scope.dateMinLimit && $scope.dateMaxLimit) {
startingYear = new Date($scope.dateMaxLimit).getFullYear();
daysToPrepend = startingYear - new Date($scope.dateMinLimit).getFullYear();
daysToAppend = 1;
}
}
for (i = daysToPrepend; i > 0; i -= 1) {
theNewYears.push(Number(startingYear) - i);
}
for (i = 0; i < daysToAppend; i += 1) {
theNewYears.push(Number(startingYear) + i);
}
//check range dates
if (dateMaxLimit && theNewYears && theNewYears.length && !$scope.isSelectableMaxYear(Number(theNewYears[theNewYears.length - 1]) + 1)) {
$scope.paginationYearsNextDisabled = true;
} else {
$scope.paginationYearsNextDisabled = false;
}
if (dateMinLimit && theNewYears && theNewYears.length && !$scope.isSelectableMinYear(Number(theNewYears[0]) - 1)) {
$scope.paginationYearsPrevDisabled = true;
} else {
$scope.paginationYearsPrevDisabled = false;
}
$scope.paginationYears = theNewYears;
};
$scope.isSelectableMinDate = function isSelectableMinDate (aDate) {
//if current date
if (!!dateMinLimit &&
!!new Date(dateMinLimit) &&
new Date(aDate).getTime() < new Date(dateMinLimit).getTime()) {
return false;
}
return true;
};
$scope.isSelectableMaxDate = function isSelectableMaxDate (aDate) {
//if current date
if (!!dateMaxLimit &&
!!new Date(dateMaxLimit) &&
new Date(aDate).getTime() > new Date(dateMaxLimit).getTime()) {
return false;
}
return true;
};
$scope.isSelectableMaxYear = function isSelectableMaxYear (year) {
if (!!dateMaxLimit &&
year > new Date(dateMaxLimit).getFullYear()) {
return false;
}
return true;
};
$scope.isSelectableMinYear = function isSelectableMinYear (year) {
if (!!dateMinLimit &&
year < new Date(dateMinLimit).getFullYear()) {
return false;
}
return true;
};
//check always if given range of dates is ok
if (dateMinLimit && !$scope.isSelectableMinYear($scope.year)) {
$scope.resetToMinDate();
}
if (dateMaxLimit && !$scope.isSelectableMaxYear($scope.year)) {
$scope.resetToMaxDate();
}
$scope.paginateYears($scope.year);
$scope.setDaysInMonth($scope.monthNumber, $scope.year);
}
};
}]);
}(angular));