mirror of
https://github.com/HackPlan/angular-datepicker.git
synced 2026-06-14 08:59:00 +08:00
427 lines
18 KiB
JavaScript
427 lines
18 KiB
JavaScript
(function () {
|
||
var Module = angular.module('dateInput', []);
|
||
|
||
|
||
Module.directive('calendar', function () {
|
||
var viewOptions = ['month', 'date', 'year', 'month', 'hours', 'minutes'];
|
||
|
||
function isValidDate(date) {
|
||
return date instanceof Date && !isNaN(date.getTime());
|
||
}
|
||
|
||
function getVisibleMinutes(date) {
|
||
console.time('getVisibleMinutes');
|
||
date = new Date(date || new Date());
|
||
date = new Date(date.getFullYear(),date.getMonth(),date.getDate(),date.getHours());
|
||
var minutes = [];
|
||
var step = 5;
|
||
var stop = date.getTime() + 60 * 60 * 1000;
|
||
while (date.getTime() < stop) {
|
||
minutes.push(date);
|
||
date = new Date(date.getTime() + step * 60 * 1000);
|
||
}
|
||
console.timeEnd('getVisibleMinutes');
|
||
return minutes;
|
||
}
|
||
|
||
function getVisibleWeeks(date) {
|
||
console.time('getVisibleWeeks');
|
||
date = new Date(date || new Date());
|
||
date.setDate(1);
|
||
date.setHours(0);
|
||
date.setMinutes(0);
|
||
date.setSeconds(0);
|
||
date.setMilliseconds(0);
|
||
|
||
if (date.getDay() === 0) {
|
||
date.setDate(-5);
|
||
} else {
|
||
date.setDate(date.getDate() - (date.getDay() - 1));
|
||
}
|
||
if (date.getDate() === 1) {
|
||
date.setDate(-6);
|
||
}
|
||
|
||
|
||
var weeks = [];
|
||
while (weeks.length < 6) {
|
||
var week = [];
|
||
for (var i = 0; i < 7; i++) {
|
||
week.push(new Date(date));
|
||
date.setDate(date.getDate() + 1);
|
||
}
|
||
weeks.push(week);
|
||
}
|
||
console.timeEnd('getVisibleWeeks');
|
||
return weeks;
|
||
}
|
||
|
||
|
||
function getVisibleYears(date) {
|
||
console.time('getVisibleYears');
|
||
var years = [];
|
||
date = new Date(date || new Date());
|
||
date.setFullYear(date.getFullYear() - (date.getFullYear() % 10));
|
||
for (var i = 0; i < 12; i++){
|
||
years.push(new Date(date.getFullYear() + (i - 1), 0, 1));
|
||
}
|
||
console.timeEnd('getVisibleYears');
|
||
return years;
|
||
}
|
||
|
||
function getDaysOfWeek(date) {
|
||
console.time('getDaysOfWeek');
|
||
date = new Date(date || new Date());
|
||
date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||
date.setDate(date.getDate() - (date.getDay() - 1));
|
||
var days = [];
|
||
for (var i = 0; i < 7; i++) {
|
||
days.push(new Date(date));
|
||
date.setDate(date.getDate()+1);
|
||
}
|
||
console.timeEnd('getDaysOfWeek');
|
||
return days;
|
||
}
|
||
|
||
function getVisibleMonths(date) {
|
||
console.time('getVisibleMonths');
|
||
date = new Date(date || new Date());
|
||
var year = date.getFullYear();
|
||
var months = [];
|
||
for (var month = 0; month < 12; month++) {
|
||
months.push(new Date(year,month,1));
|
||
}
|
||
console.timeEnd('getVisibleMonths');
|
||
return months;
|
||
}
|
||
|
||
function getVisibleHours(date) {
|
||
console.time('getVisibleHours');
|
||
date = new Date(date || new Date());
|
||
date.setHours(0);
|
||
date.setMinutes(0);
|
||
date.setSeconds(0);
|
||
date.setMilliseconds(0);
|
||
var hours = [];
|
||
for (var i = 0; i < 24; i++) {
|
||
hours.push(date);
|
||
date = new Date(date.getTime() + 60 * 60 * 1000);
|
||
}
|
||
console.timeEnd('getVisibleHours');
|
||
return hours;
|
||
}
|
||
|
||
return {
|
||
scope : {
|
||
date : '=calendar',
|
||
after : '=?',
|
||
before: '=?'
|
||
},
|
||
link : function (scope, element, attrs) {
|
||
function dateIsValid() {
|
||
return isValidDate(scope.date);
|
||
}
|
||
|
||
scope.views = [];
|
||
for (var attr in attrs) { //noinspection JSUnfilteredForInLoop
|
||
if (viewOptions.indexOf(attr) != -1) { //noinspection JSUnfilteredForInLoop
|
||
scope.views.push(attr);
|
||
}
|
||
}
|
||
if (!scope.views.length) {
|
||
scope.views = ['date', 'month', 'year', 'hours', 'minutes'];
|
||
}
|
||
scope.view = scope.views[0];
|
||
|
||
function hasView(view) {
|
||
return scope.views.indexOf(view) != -1;
|
||
}
|
||
|
||
function ensureDate() {
|
||
// we need to return new instance as ngModel $watch watches only for identity - not for equality
|
||
if (!(isValidDate(scope.date))) {
|
||
scope.date = new Date(2000, 1, 1);
|
||
}
|
||
scope.date = new Date(scope.date);
|
||
}
|
||
|
||
function setYear(date) {
|
||
ensureDate();
|
||
scope.date.setFullYear(date.getFullYear());
|
||
}
|
||
|
||
function setMonth(date) {
|
||
setYear(date);
|
||
scope.date.setMonth(date.getMonth());
|
||
}
|
||
|
||
function setDate(date) {
|
||
setMonth(date);
|
||
scope.date.setDate(date.getDate());
|
||
}
|
||
|
||
function setHours(date) {
|
||
setDate(date);
|
||
scope.date.setHours(date.getHours());
|
||
}
|
||
|
||
function setMinutes(date) {
|
||
setHours(date);
|
||
scope.date.setMinutes(date.getMinutes());
|
||
}
|
||
|
||
scope.setYear = function (date) {
|
||
setYear(date);
|
||
scope.$emit('setYear', date);
|
||
};
|
||
|
||
scope.setMonth = function (date) {
|
||
setMonth(date);
|
||
scope.$emit('setMonth', date);
|
||
};
|
||
|
||
scope.setDate = function (date) {
|
||
setDate(date);
|
||
scope.$emit('setDate', date);
|
||
};
|
||
|
||
scope.setHours = function (date) {
|
||
setHours(date);
|
||
scope.$emit('setHours', date);
|
||
};
|
||
|
||
scope.setMinutes = function (date) {
|
||
setMinutes(date);
|
||
scope.$emit('setMinutes', date);
|
||
};
|
||
|
||
scope.setView = function setView(view) {
|
||
if (hasView(view)) {
|
||
scope.view = view;
|
||
switch(view){
|
||
case 'minutes':scope.minutes=getVisibleMinutes(scope.visibleDate);break;
|
||
case 'hours' :scope.hours = getVisibleHours(scope.visibleDate);break;
|
||
case 'date' :scope.weeks = getVisibleWeeks(scope.visibleDate);break;
|
||
case 'month' :scope.months = getVisibleMonths(scope.visibleDate);break;
|
||
case 'year' :scope.years = getVisibleYears(scope.visibleDate);break;
|
||
}
|
||
}
|
||
};
|
||
|
||
scope.nextMonth = function (delta) {
|
||
scope.visibleDate.setMonth(scope.visibleDate.getMonth() + (delta || 1));
|
||
};
|
||
|
||
scope.prevMonth = function (delta) {
|
||
scope.nextMonth(-delta || -1);
|
||
};
|
||
|
||
scope.nextDay = function (delta) {
|
||
scope.visibleDate.setDate(scope.visibleDate.getDate() + (delta || 1));
|
||
};
|
||
|
||
scope.prevDay = function (delta) {
|
||
scope.nextDay(-delta || -1);
|
||
};
|
||
|
||
scope.nextHour = function (delta) {
|
||
scope.visibleDate.setHours(scope.visibleDate.getHours() + (delta || 1));
|
||
};
|
||
|
||
scope.prevHour = function (delta) {
|
||
scope.nextHour(-delta || -1);
|
||
};
|
||
|
||
scope.nextYear = function (delta) {
|
||
scope.visibleDate.setFullYear(scope.visibleDate.getFullYear() + (delta || 1));
|
||
};
|
||
scope.prevYear = function (delta) {
|
||
scope.nextYear(-delta || -1);
|
||
};
|
||
|
||
scope.visibleDate = new Date();
|
||
|
||
scope.$watch('date', function (date) {
|
||
if (date) {
|
||
scope.visibleDate = new Date(date);
|
||
}
|
||
});
|
||
|
||
scope.isAfter = function (date) {
|
||
return date >= scope.after;
|
||
};
|
||
|
||
scope.isBefore = function (date) {
|
||
return date <= scope.before;
|
||
};
|
||
|
||
function validDate() {
|
||
return scope.date instanceof Date;
|
||
}
|
||
|
||
scope.isSameMinutes = function (date) {
|
||
if (!validDate())return false;
|
||
var b = scope.date;
|
||
return (date.getTime() - date.getSeconds() * 1000 - date.getMilliseconds()) == (b.getTime() - b.getSeconds() * 1000 - b.getMilliseconds());
|
||
};
|
||
|
||
scope.isSameMonth = function (date) {
|
||
if (!validDate())return false;
|
||
return date.getFullYear() === scope.date.getFullYear() && date.getMonth() == scope.date.getMonth();
|
||
};
|
||
|
||
scope.isSameYear = function (date) {
|
||
if (!validDate())return false;
|
||
return date.getFullYear() === scope.date.getFullYear();
|
||
};
|
||
|
||
scope.isSameDate = function (date) {
|
||
if (!validDate())return false;
|
||
return scope.date.getDate() === date.getDate() && scope.isSameMonth(date);
|
||
};
|
||
|
||
scope.isSameHour = function (date) {
|
||
if (!validDate())return false;
|
||
return scope.date.getHours() === date.getHours() && scope.isSameDate(date);
|
||
};
|
||
|
||
scope.isOldMonth = function (date) {
|
||
return date
|
||
.getTime() < scope.visibleDate.getTime() && date.getMonth() != scope.visibleDate.getMonth();
|
||
};
|
||
|
||
scope.isNewHour = function (date) {
|
||
return date.getTime() > scope.visibleDate.getTime() && date.getHours() != scope.visibleDate.getHours();
|
||
};
|
||
|
||
scope.isOldHour = function (date) {
|
||
return date.getTime() < scope.visibleDate.getTime() && date.getHours() != scope.visibleDate.getHours();
|
||
};
|
||
|
||
scope.isNewMonth = function (date) {
|
||
return date.getTime() > scope.visibleDate.getTime() && date.getMonth() != scope.visibleDate.getMonth();
|
||
};
|
||
|
||
|
||
scope.$on('setDate', scope.setView.bind(null, 'hours'));
|
||
scope.$on('setMonth', scope.setView.bind(null, 'date'));
|
||
scope.$on('setHours', scope.setView.bind(null, 'minutes'));
|
||
scope.$on('setYear', scope.setView.bind(null, 'month'));
|
||
|
||
scope.$watch(function () {
|
||
return isValidDate(scope.visibleDate);
|
||
}, function (valid) {
|
||
if (!valid) {
|
||
scope.visibleDate = new Date();
|
||
}
|
||
});
|
||
|
||
//hours
|
||
scope.$watch('[visibleDate.getDate(),visibleDate.getHours()].join()', function () {
|
||
if (scope.view == 'hours') scope.hours = getVisibleHours(scope.visibleDate);
|
||
});
|
||
//date
|
||
scope.$watch('[visibleDate.getFullYear(),visibleDate.getMonth(),visibleDate.getDate()].join()', function () {
|
||
if (scope.view == 'date') {
|
||
scope.weeks = getVisibleWeeks(scope.visibleDate);
|
||
scope.weekdays = getDaysOfWeek(scope.visibleDate);
|
||
}
|
||
});
|
||
|
||
scope.$watch('[visibleDate.getFullYear(),visibleDate.getMonth()].join()', function () {
|
||
if (scope.view == 'month') {
|
||
scope.months = getVisibleMonths(scope.visibleDate);
|
||
}
|
||
});
|
||
|
||
scope.$watch('visibleDate.getYear()', function () {
|
||
if (scope.view == 'year') {
|
||
scope.years = getVisibleYears(scope.visibleDate);
|
||
}
|
||
});
|
||
|
||
scope.$watch('visibleDate.getTime()', function (a,b) {
|
||
if (scope.view == 'minutes') {
|
||
scope.minutes = getVisibleMinutes(scope.visibleDate);
|
||
}
|
||
});
|
||
|
||
},
|
||
transclude: true,
|
||
replace : true,
|
||
// template : '<div ng-transclude ng-switch="view">\n <div class="datetimepicker-days" ng-switch-when="date">\n <table class=" table-condensed">\n <thead>\n <tr>\n <th class="prev" style="visibility: visible;" ng-click="prevMonth()">‹</th>\n <th colspan="5" class="switch" ng-click="setView(\'month\')">{{visibleDate|date:"yyyy MMMM"}}</th>\n <th class="next" style="visibility: visible;" ng-click="nextMonth()">›</i></th>\n </tr>\n <tr>\n <th class="dow" ng-repeat="day in weekdays">{{ day|date:"EEE"}}</th>\n </tr>\n </thead>\n <tbody>\n <tr ng-repeat="week in weeks">\n <td class="day" ng-repeat="day in week" ng-class="{\'active\':isSameDate(day),\'old\':isOldMonth(day),\'new\':isNewMonth(day),\'after\':isAfter(day),\'before\':isBefore(day)}" ng-click="setDate(day)">{{ day.getDate() }}</td>\n </tr>\n </tbody>\n <tfoot>\n <tr>\n <th colspan="7" class="today" style="display: none;">Today</th>\n </tr>\n </tfoot>\n </table>\n </div>\n ' + '<div class="datetimepicker-years" ng-switch-when="year">\n <table class="table-condensed">\n <thead>\n <tr>\n <th class="prev" style="visibility: visible;" ng-click="prevYear(10)">‹</th>\n <th colspan="5" class="switch">{{years[0].getFullYear()}}-{{years[years.length-1].getFullYear()}}</th>\n <th class="next" style="visibility: visible;" ng-click="nextYear(10)">›</i></th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td colspan="7">\n <span class="year" ng-repeat="year in years" ng-class="{\'active\':isSameYear(year)}" ng-click="setYear(year)">{{year.getFullYear()}}</span>\n </td>\n </tr>\n </tbody>\n </table>\n</div>\n\n<div class="datetimepicker-months" ng-switch-when="month">\n <table class="table-condensed">\n <thead>\n <tr>\n <th class="prev" style="visibility: visible;" ng-click="prevYear()">‹</th>\n <th colspan="5" class="switch" ng-click="setView(\'year\')">{{ visibleDate|date:"yyyy" }}</th>\n <th class="next" style="visibility: visible;" ng-click="nextYear()">›</i></th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td colspan="7">\n <span class="month" ng-repeat="month in months"\n ng-class="{\'active\':isSameMonth(month),\'after\':isAfter(month),\'before\':isBefore(month)}"\n ng-click="setMonth(month)">{{month|date:\'MMM\'}}</span>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr>\n <th colspan="7" class="today" style="display: none;">Today</th>\n </tr>\n </tfoot>\n </table>\n</div>\n\n<div class="datetimepicker-hours" ng-switch-when="hours">\n <table class=" table-condensed">\n <thead>\n <tr>\n <th class="prev" style="visibility: visible;" ng-click="prevDay()">‹</th>\n <th colspan="5" class="switch" ng-click="setView(\'date\')">{{ visibleDate|date:"dd MMMM yyyy" }}</th>\n <th class="next" style="visibility: visible;" ng-click="nextDay()">›</i></th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td colspan="7">\n <span class="hour" ng-repeat="hour in hours"\n ng-class="{\'old\':isOldHour(hour),\'new\':isNewHour(hour),\'active\':isSameHour(hour)}"\n ng-click="setHours(hour)">{{hour|date:"HH:mm"}}</span>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr>\n <th colspan="7" class="today" style="display: none;">Today</th>\n </tr>\n </tfoot>\n </table>\n</div>\n<div class="datetimepicker-minutes" ng-switch-when="minutes">\n <table class=" table-condensed">\n <thead>\n <tr>\n <th class="prev" style="visibility: visible;" ng-click="prevHour()">‹</th>\n <th colspan="5" class="switch" ng-click="setView(\'hours\')">{{ visibleDate|date:"dd MMMM yyyy HH:mm" }}</th>\n <th class="next" style="visibility: visible;" ng-click="nextHour()">›</i></th>\n </tr>\n ' + ' </thead>\n <tbody>\n <tr>\n <td colspan="7">\n <span class="minute" ng-repeat="minute in minutes" ng-class="{active:isSameMinutes(minute)}" ng-click="setMinutes(minute)">{{minute|date:"HH:mm"}}</span>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr>\n <th colspan="7" class="today" style="display: none;">Today</th>\n </tr>\n </tfoot>\n </table>\n </div>\n</div>'
|
||
templateUrl:'scripts/template.html'
|
||
};
|
||
});
|
||
|
||
Module.directive('dateTime', function ($compile, $document, $filter) {
|
||
var body = $document.find('body');
|
||
var dateFilter = $filter('date');
|
||
return {
|
||
require: 'ngModel',
|
||
link : function (scope, element, attrs, ngModel) {
|
||
var format = attrs.format || "yyyy-MM-dd HH:mm";
|
||
|
||
var viewsOptions = ['date', 'year', 'month', 'hours', 'minutes', 'month'];
|
||
var views = [];
|
||
for (attr in attrs) {
|
||
//noinspection JSUnfilteredForInLoop
|
||
if (viewsOptions.indexOf(attr) != -1) { //noinspection JSUnfilteredForInLoop
|
||
views.push(attr);
|
||
}
|
||
}
|
||
|
||
function formatter(value) {
|
||
return dateFilter(value, format);
|
||
}
|
||
|
||
ngModel.$formatters = [formatter];
|
||
|
||
var picker = null;
|
||
var clear = angular.noop;
|
||
|
||
element.bind('focus', function () {
|
||
if (!picker) {
|
||
picker = $compile('<div calendar="' + attrs.ngModel + '" class="datetimepicker datetimepicker-dropdown-bottom-left dropdown-menu" format="' + format + '" ' + views.join(' ') + '></div>')(scope);
|
||
body.append(picker);
|
||
picker.bind('mousedown', function () {
|
||
return false;
|
||
});
|
||
var pos = angular.extend({}, element.position(), { height: element[0].offsetHeight });
|
||
picker.css({ top: pos.top + pos.height, left: pos.left, display: 'block', position: 'absolute'});
|
||
scope.$digest();
|
||
}
|
||
return false;
|
||
});
|
||
element.bind('blur', function () {
|
||
clear();
|
||
clear = angular.noop;
|
||
if (picker)picker.remove();
|
||
picker = null;
|
||
});
|
||
}
|
||
};
|
||
});
|
||
|
||
Module.directive('dateRange', function () {
|
||
return {
|
||
template: '<div class="dropdown-menu" style="display: block">\n <table >\n <tr>\n <td valign="top"><div calendar="start" class="datetimepicker" date after="start" before="end"></div></td>\n <td valign="top"><div calendar="end" class="datetimepicker" date after="start" before="end"></div></td>\n </tr>\n </table>\n \n \n</div>',
|
||
scope : {
|
||
start: '=',
|
||
end : '='
|
||
},
|
||
link : function (scope) {
|
||
scope.$watch('start.getTime()', function (value) {
|
||
if (value && scope.end && value > scope.end.getTime()) {
|
||
scope.end = new Date(value);
|
||
}
|
||
});
|
||
scope.$watch('end.getTime()', function (value) {
|
||
if (value && scope.start && value < scope.start.getTime()) {
|
||
scope.start = new Date(value);
|
||
}
|
||
});
|
||
}
|
||
};
|
||
});
|
||
})(); |