diff --git a/src/datepicker/datepicker.js b/src/datepicker/datepicker.js index 0d9d078294..3cc489d22f 100644 --- a/src/datepicker/datepicker.js +++ b/src/datepicker/datepicker.js @@ -14,6 +14,26 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position']) maxDate: null }) +.service('DatepickerService', ['datepickerConfig', function(datepickerConfig) { + var WATCHABLE_KEYS = ['showWeeks', 'minDate', 'maxDate']; + + function styleHyphenFormat(propertyName) { + function upperToHyphenLower(match) { + return '-' + match.toLowerCase(); + } + return propertyName.replace(/[A-Z]/g, upperToHyphenLower); + } + + this.collectConfigAttributes = function(attrs, callback) { + var currentKey; + for (currentKey in attrs) { + if (datepickerConfig.hasOwnProperty(currentKey)) { + callback(attrs[currentKey], currentKey, styleHyphenFormat(currentKey), WATCHABLE_KEYS.indexOf(currentKey) !== -1); + } + } + }; +}]) + .controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) { var format = { day: getValue($attrs.dayFormat, dtConfig.dayFormat), @@ -134,7 +154,8 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position']) require: ['datepicker', '?^ngModel'], controller: 'DatepickerController', link: function(scope, element, attrs, ctrls) { - var datepickerCtrl = ctrls[0], ngModel = ctrls[1]; + var datepickerCtrl = ctrls[0], ngModel = ctrls[1], + minDate = attrs.min || attrs.minDate, maxDate = attrs.max || attrs.maxDate; if (!ngModel) { return; // do nothing if no ng-model @@ -152,14 +173,14 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position']) updateShowWeekNumbers(); } - if (attrs.min) { - scope.$parent.$watch($parse(attrs.min), function(value) { + if (minDate) { + scope.$parent.$watch($parse(minDate), function(value) { datepickerCtrl.minDate = value ? new Date(value) : null; refill(); }); } - if (attrs.max) { - scope.$parent.$watch($parse(attrs.max), function(value) { + if (maxDate) { + scope.$parent.$watch($parse(maxDate), function(value) { datepickerCtrl.maxDate = value ? new Date(value) : null; refill(); }); @@ -260,8 +281,8 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position']) closeOnDateSelection: true }) -.directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'datepickerPopupConfig', -function ($compile, $parse, $document, $position, dateFilter, datepickerPopupConfig) { +.directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'datepickerPopupConfig', 'DatepickerService', +function ($compile, $parse, $document, $position, dateFilter, datepickerPopupConfig, DatepickerService) { return { restrict: 'EA', require: 'ngModel', @@ -397,14 +418,23 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon datepickerEl.attr(datepickerAttribute || scopeProperty, scopeProperty); } } - addWatchableAttribute(attrs.min, 'min'); - addWatchableAttribute(attrs.max, 'max'); - if (attrs.showWeeks) { - addWatchableAttribute(attrs.showWeeks, 'showWeeks', 'show-weeks'); - } else { - scope.showWeeks = true; - datepickerEl.attr('show-weeks', 'showWeeks'); + + DatepickerService.collectConfigAttributes(attrs, function(attribute, scopeProperty, datepickerAttribute, watchable) { + if (watchable) { + addWatchableAttribute(attribute, scopeProperty, datepickerAttribute); + } else { + datepickerEl.attr(datepickerAttribute, attribute); + } + }); + + if (!datepickerEl.attr('min-date') && attrs.min) { + addWatchableAttribute(attrs.min, 'min'); } + + if (!datepickerEl.attr('max-date') && attrs.max) { + addWatchableAttribute(attrs.max, 'max'); + } + if (attrs.dateDisabled) { datepickerEl.attr('date-disabled', attrs.dateDisabled); } diff --git a/src/datepicker/test/datepicker.spec.js b/src/datepicker/test/datepicker.spec.js index baf3415e0f..7aeffd89ab 100644 --- a/src/datepicker/test/datepicker.spec.js +++ b/src/datepicker/test/datepicker.spec.js @@ -1240,6 +1240,204 @@ describe('datepicker directive', function () { expect(inputEl.val()).toBe('pizza'); }); }); + + describe('with `show-weeks` attribute', function() { + beforeEach(inject(function () { + $rootScope.showWeeks = false; + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + })); + + it('to hide weeks column', function() { + expect(getWeeks()).toEqual(['', '', '', '', '']); + }); + it('to show weeks column', function() { + $rootScope.showWeeks = true; + $rootScope.$digest(); + expect(getWeeks()).toEqual(["34", "35", "36", "37", "38"]); + }); + }); + + describe('with `min` attribute', function() { + beforeEach(function () { + $rootScope.mindate = new Date("September 12, 2010"); + element = $compile('
')($rootScope); + $rootScope.$digest(); + }); + + it('disables appropriate days in current month', function () { + for (var i = 0; i < 5; i++) { + for (var j = 0; j < 7; j++) { + expect(isDisabledOption(i, j)).toBe((i < 2)); + } + } + }); + + it('disables appropriate days when min date changes', function() { + $rootScope.mindate = new Date("September 5, 2010"); + $rootScope.$digest(); + for (var i = 0; i < 5; i ++) { + for (var j = 0; j < 7; j ++) { + expect(isDisabledOption(i, j)).toBe( (i < 1) ); + } + } + }); + }); + + describe('with `minDate` attribute', function() { + beforeEach(function () { + $rootScope.mindate = new Date("September 12, 2010"); + element = $compile('
')($rootScope); + $rootScope.$digest(); + }); + + it('disables appropriate days in current month', function () { + for (var i = 0; i < 5; i++) { + for (var j = 0; j < 7; j++) { + expect(isDisabledOption(i, j)).toBe((i < 2)); + } + } + }); + + it('disables appropriate days when min date changes', function() { + $rootScope.mindate = new Date("September 5, 2010"); + $rootScope.$digest(); + for (var i = 0; i < 5; i ++) { + for (var j = 0; j < 7; j ++) { + expect(isDisabledOption(i, j)).toBe( (i < 1) ); + } + } + }); + }); + + describe('with `max` attribute', function() { + beforeEach(function() { + $rootScope.maxdate = new Date("September 25, 2010"); + element = $compile('
')($rootScope); + $rootScope.$digest(); + }); + + it('disables appropriate days in current month', function() { + for (var i = 0; i < 5; i ++) { + for (var j = 0; j < 7; j ++) { + expect(isDisabledOption(i, j)).toBe( (i === 4) ); + } + } + }); + + it('disables appropriate days when max date changes', function() { + $rootScope.maxdate = new Date("September 18, 2010"); + $rootScope.$digest(); + for (var i = 0; i < 5; i ++) { + for (var j = 0; j < 7; j ++) { + expect(isDisabledOption(i, j)).toBe( (i > 2) ); + } + } + }); + }); + + describe('with `maxDate` attribute', function() { + beforeEach(function() { + $rootScope.maxdate = new Date("September 25, 2010"); + element = $compile('
')($rootScope); + $rootScope.$digest(); + }); + + it('disables appropriate days in current month', function() { + for (var i = 0; i < 5; i ++) { + for (var j = 0; j < 7; j ++) { + expect(isDisabledOption(i, j)).toBe( (i === 4) ); + } + } + }); + + it('disables appropriate days when max date changes', function() { + $rootScope.maxdate = new Date("September 18, 2010"); + $rootScope.$digest(); + for (var i = 0; i < 5; i ++) { + for (var j = 0; j < 7; j ++) { + expect(isDisabledOption(i, j)).toBe( (i > 2) ); + } + } + }); + }); + + describe('with `day-title-format` attribute', function() { + beforeEach(function() { + $rootScope.maxdate = new Date("September 25, 2010"); + element = $compile('
')($rootScope); + $rootScope.$digest(); + }); + + it('changes the title format in `day` mode', function() { + expect(getTitle()).toBe('September, 10'); + }); + }); + + describe('with datepickerOptions', function() { + beforeEach(inject(function() { + $rootScope.datepickerOptions = { + 'starting-day': 6, + 'show-weeks': false, + 'day-format': "'d'", + 'month-format': "'MMM'", + 'year-format': "'yy'", + 'year-range': 10, + 'day-header-format': "'EEEE'", + 'day-title-format': "'MMMM, yy'", + 'month-title-format': "'yy'" + }; + + element = $compile('
')($rootScope); + $rootScope.$digest(); + })); + + it('changes the title format in `day` mode', function() { + expect(getTitle()).toBe('September, 10'); + }); + + it('changes the title & months format in `month` mode', function() { + clickTitleButton(); + + expect(getTitle()).toBe('10'); + expect(getOptions()).toEqual([ + ['Jan', 'Feb', 'Mar'], + ['Apr', 'May', 'Jun'], + ['Jul', 'Aug', 'Sep'], + ['Oct', 'Nov', 'Dec'] + ]); + }); + + it('changes the title, year format & range in `year` mode', function() { + clickTitleButton(2); + + expect(getTitle()).toBe('01 - 10'); + expect(getOptions()).toEqual([ + ['01', '02', '03', '04', '05'], + ['06', '07', '08', '09', '10'] + ]); + }); + + it('changes the `starting-day` & day headers & format', function() { + expect(getLabels()).toEqual(['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']); + expect(getOptions()).toEqual([ + ['28', '29', '30', '31', '1', '2', '3'], + ['4', '5', '6', '7', '8', '9', '10'], + ['11', '12', '13', '14', '15', '16', '17'], + ['18', '19', '20', '21', '22', '23', '24'], + ['25', '26', '27', '28', '29', '30', '1'] + ]); + }); + + it('changes initial visibility for weeks', function() { + expect(getLabelsRow().find('th').eq(0).css('display')).toBe('none'); + var tr = element.find('tbody').find('tr'); + for (var i = 0; i < 5; i++) { + expect(tr.eq(i).find('td').eq(0).css('display')).toBe('none'); + } + }); + }); }); });