Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
feat(datepicker): add datepickerOptions support
Browse files Browse the repository at this point in the history
- Add support for options object to concisely configure datepicker

Closes #5340
  • Loading branch information
wesleycho committed Jan 27, 2016
1 parent 61cdef1 commit e58c42c
Show file tree
Hide file tree
Showing 3 changed files with 472 additions and 48 deletions.
197 changes: 152 additions & 45 deletions src/datepicker/datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,66 +31,172 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
// Modes chain
this.modes = ['day', 'month', 'year'];

// Interpolated configuration attributes
angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle'], function(key) {
self[key] = angular.isDefined($attrs[key]) ? $interpolate($attrs[key])($scope.$parent) : datepickerConfig[key];
});
if ($attrs.datepickerOptions) {
angular.forEach([
'formatDay',
'formatDayHeader',
'formatDayTitle',
'formatMonth',
'formatMonthTitle',
'formatYear',
'initDate',
'maxDate',
'maxMode',
'minDate',
'minMode',
'showWeeks',
'shortcutPropagation',
'startingDay',
'yearColumns',
'yearRows'
], function(key) {
switch (key) {
case 'formatDay':
case 'formatDayHeader':
case 'formatDayTitle':
case 'formatMonth':
case 'formatMonthTitle':
case 'formatYear':
self[key] = angular.isDefined($scope.datepickerOptions[key]) ? $interpolate($scope.datepickerOptions[key])($scope.$parent) : datepickerConfig[key];
break;
case 'showWeeks':
case 'shortcutPropagation':
case 'yearColumns':
case 'yearRows':
self[key] = angular.isDefined($scope.datepickerOptions[key]) ?
$scope.datepickerOptions[key] : datepickerConfig[key];
break;
case 'startingDay':
if (angular.isDefined($scope.datepickerOptions.startingDay)) {
self.startingDay = $scope.datepickerOptions.startingDay;
} else if (angular.isNumber(datepickerConfig.startingDay)) {
self.startingDay = datepickerConfig.startingDay;
} else {
self.startingDay = ($locale.DATETIME_FORMATS.FIRSTDAYOFWEEK + 8) % 7;
}

// Evaled configuration attributes
angular.forEach(['showWeeks', 'yearRows', 'yearColumns', 'shortcutPropagation'], function(key) {
self[key] = angular.isDefined($attrs[key]) ?
$scope.$parent.$eval($attrs[key]) : datepickerConfig[key];
});
break;
case 'maxDate':
case 'minDate':
if ($scope.datepickerOptions[key]) {
$scope.$watch(function() { return $scope.datepickerOptions[key]; }, function(value) {
if (value) {
if (angular.isDate(value)) {
self[key] = dateParser.fromTimezone(new Date(value), ngModelOptions.timezone);
} else {
self[key] = new Date(dateFilter(value, 'medium'));
}
} else {
self[key] = null;
}

self.refreshView();
});
} else {
self[key] = datepickerConfig[key] ? dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.timezone) : null;
}

if (angular.isDefined($attrs.startingDay)) {
self.startingDay = $scope.$parent.$eval($attrs.startingDay);
} else if (angular.isNumber(datepickerConfig.startingDay)) {
self.startingDay = datepickerConfig.startingDay;
break;
case 'maxMode':
case 'minMode':
if ($scope.datepickerOptions[key]) {
$scope.$watch(function() { return $scope.datepickerOptions[key]; }, function(value) {
self[key] = $scope[key] = angular.isDefined(value) ? value : datepickerOptions[key];
if (key === 'minMode' && self.modes.indexOf($scope.datepickerMode) < self.modes.indexOf(self[key]) ||
key === 'maxMode' && self.modes.indexOf($scope.datepickerMode) > self.modes.indexOf(self[key])) {
$scope.datepickerMode = self[key];
}
});
} else {
self[key] = $scope[key] = datepickerConfig[key] || null;
}

break;
case 'initDate':
if ($scope.datepickerOptions.initDate) {
this.activeDate = dateParser.fromTimezone($scope.datepickerOptions.initDate, ngModelOptions.timezone) || new Date();
$scope.$watch(function() { return $scope.datepickerOptions.initDate; }, function(initDate) {
if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) {
self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.timezone);
self.refreshView();
}
});
} else {
this.activeDate = new Date();
}
}
});
} else {
self.startingDay = ($locale.DATETIME_FORMATS.FIRSTDAYOFWEEK + 8) % 7;
}
// Interpolated configuration attributes
angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle'], function(key) {
self[key] = angular.isDefined($attrs[key]) ? $interpolate($attrs[key])($scope.$parent) : datepickerConfig[key];
});

// Watchable date attributes
angular.forEach(['minDate', 'maxDate'], function(key) {
if ($attrs[key]) {
watchListeners.push($scope.$parent.$watch($attrs[key], function(value) {
self[key] = value ? angular.isDate(value) ? dateParser.fromTimezone(new Date(value), ngModelOptions.timezone) : new Date(dateFilter(value, 'medium')) : null;
self.refreshView();
}));
// Evaled configuration attributes
angular.forEach(['showWeeks', 'yearRows', 'yearColumns', 'shortcutPropagation'], function(key) {
self[key] = angular.isDefined($attrs[key]) ?
$scope.$parent.$eval($attrs[key]) : datepickerConfig[key];
});

if (angular.isDefined($attrs.startingDay)) {
self.startingDay = $scope.$parent.$eval($attrs.startingDay);
} else if (angular.isNumber(datepickerConfig.startingDay)) {
self.startingDay = datepickerConfig.startingDay;
} else {
self[key] = datepickerConfig[key] ? dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.timezone) : null;
self.startingDay = ($locale.DATETIME_FORMATS.FIRSTDAYOFWEEK + 8) % 7;
}
});

angular.forEach(['minMode', 'maxMode'], function(key) {
if ($attrs[key]) {
watchListeners.push($scope.$parent.$watch($attrs[key], function(value) {
self[key] = $scope[key] = angular.isDefined(value) ? value : $attrs[key];
if (key === 'minMode' && self.modes.indexOf($scope.datepickerMode) < self.modes.indexOf(self[key]) ||
key === 'maxMode' && self.modes.indexOf($scope.datepickerMode) > self.modes.indexOf(self[key])) {
$scope.datepickerMode = self[key];
// Watchable date attributes
angular.forEach(['minDate', 'maxDate'], function(key) {
if ($attrs[key]) {
watchListeners.push($scope.$parent.$watch($attrs[key], function(value) {
if (value) {
if (angular.isDate(value)) {
self[key] = dateParser.fromTimezone(new Date(value), ngModelOptions.timezone);
} else {
self[key] = new Date(dateFilter(value, 'medium'));
}
} else {
self[key] = null;
}

self.refreshView();
}));
} else {
self[key] = datepickerConfig[key] ? dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.timezone) : null;
}
});

angular.forEach(['minMode', 'maxMode'], function(key) {
if ($attrs[key]) {
watchListeners.push($scope.$parent.$watch($attrs[key], function(value) {
self[key] = $scope[key] = angular.isDefined(value) ? value : $attrs[key];
if (key === 'minMode' && self.modes.indexOf($scope.datepickerMode) < self.modes.indexOf(self[key]) ||
key === 'maxMode' && self.modes.indexOf($scope.datepickerMode) > self.modes.indexOf(self[key])) {
$scope.datepickerMode = self[key];
}
}));
} else {
self[key] = $scope[key] = datepickerConfig[key] || null;
}
});

if (angular.isDefined($attrs.initDate)) {
this.activeDate = dateParser.fromTimezone($scope.$parent.$eval($attrs.initDate), ngModelOptions.timezone) || new Date();
watchListeners.push($scope.$parent.$watch($attrs.initDate, function(initDate) {
if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) {
self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.timezone);
self.refreshView();
}
}));
} else {
self[key] = $scope[key] = datepickerConfig[key] || null;
this.activeDate = new Date();
}
});
}

$scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode;
$scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);

if (angular.isDefined($attrs.initDate)) {
this.activeDate = dateParser.fromTimezone($scope.$parent.$eval($attrs.initDate), ngModelOptions.timezone) || new Date();
watchListeners.push($scope.$parent.$watch($attrs.initDate, function(initDate) {
if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) {
self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.timezone);
self.refreshView();
}
}));
} else {
this.activeDate = new Date();
}

$scope.disabled = angular.isDefined($attrs.disabled) || false;
if (angular.isDefined($attrs.ngDisabled)) {
watchListeners.push($scope.$parent.$watch($attrs.ngDisabled, function(disabled) {
Expand Down Expand Up @@ -501,6 +607,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
},
scope: {
datepickerMode: '=?',
datepickerOptions: '=?',
dateDisabled: '&',
customClass: '&',
shortcutPropagation: '&?'
Expand Down
23 changes: 23 additions & 0 deletions src/datepicker/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,29 @@ The datepicker has 3 modes:
_(Default: `day`)_ -
Current mode of the datepicker _(day|month|year)_. Can be used to initialize the datepicker in a specific mode.

* `datepicker-options`
<small class="badge">$</small> -
An optional object to configure the datepicker in one place. If this attribute is used, all supported options must be specified instead of the attributes.

The supported options are:

- formatDay
- formatDayHeader
- formatDayTitle
- formatMonth
- formatMonthTitle
- formatYear
- initDate
- maxDate
- maxMode
- minDate
- minMode
- shortcutPropagation
- showWeeks
- startingDay
- yearColumns
- yearRows

* `format-day`
<small class="badge">C</small>
_(Default: `dd`)_ -
Expand Down
Loading

0 comments on commit e58c42c

Please sign in to comment.