diff --git a/src/datepicker/datepicker.js b/src/datepicker/datepicker.js index 5bdb8f7451..e1e62c6f16 100644 --- a/src/datepicker/datepicker.js +++ b/src/datepicker/datepicker.js @@ -225,21 +225,22 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst return { restrict: 'EA', replace: true, - templateUrl: 'template/datepicker/datepicker.html', + templateUrl: function(element, attrs) { + return attrs.templateUrl || 'template/datepicker/datepicker.html'; + }, scope: { datepickerMode: '=?', dateDisabled: '&', customClass: '&', shortcutPropagation: '&?' }, - require: ['datepicker', '?^ngModel'], + require: ['datepicker', '^ngModel'], controller: 'DatepickerController', + controllerAs: 'datepicker', link: function(scope, element, attrs, ctrls) { var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1]; - if ( ngModelCtrl ) { - datepickerCtrl.init( ngModelCtrl ); - } + datepickerCtrl.init(ngModelCtrl); } }; }) @@ -477,6 +478,8 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst .constant('datepickerPopupConfig', { datepickerPopup: 'yyyy-MM-dd', + datepickerPopupTemplateUrl: 'template/datepicker/popup.html', + datepickerTemplateUrl: 'template/datepicker/datepicker.html', html5Types: { date: 'yyyy-MM-dd', 'datetime-local': 'yyyy-MM-ddTHH:mm:ss.sss', @@ -506,7 +509,9 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa link: function(scope, element, attrs, ngModel) { var dateFormat, closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection, - appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody; + appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody, + datepickerPopupTemplateUrl = angular.isDefined(attrs.datepickerPopupTemplateUrl) ? attrs.datepickerPopupTemplateUrl : datepickerPopupConfig.datepickerPopupTemplateUrl, + datepickerTemplateUrl = angular.isDefined(attrs.datepickerTemplateUrl) ? attrs.datepickerTemplateUrl : datepickerPopupConfig.datepickerTemplateUrl; scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar; @@ -547,7 +552,8 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa var popupEl = angular.element('
'); popupEl.attr({ 'ng-model': 'date', - 'ng-change': 'dateSelection(date)' + 'ng-change': 'dateSelection(date)', + 'template-url': datepickerPopupTemplateUrl }); function cameltoDash( string ){ @@ -556,6 +562,8 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa // datepicker element var datepickerEl = angular.element(popupEl.children()[0]); + datepickerEl.attr('template-url', datepickerTemplateUrl); + if (isHtml5DateInput) { if (attrs.type == 'month') { datepickerEl.attr('datepicker-mode', '"month"'); @@ -785,6 +793,8 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa restrict:'EA', replace: true, transclude: true, - templateUrl: 'template/datepicker/popup.html' + templateUrl: function(element, attrs) { + return attrs.templateUrl || 'template/datepicker/popup.html'; + } }; }); diff --git a/src/datepicker/docs/readme.md b/src/datepicker/docs/readme.md index 0311b0596f..ecb665fb6f 100644 --- a/src/datepicker/docs/readme.md +++ b/src/datepicker/docs/readme.md @@ -80,10 +80,14 @@ All settings can be provided as attributes in the `datepicker` or globally confi * `year-range` _(Default: 20)_ : Number of years displayed in year selection. - + * `shortcut-propagation` - _(Default: false)_ : - An option to disable or enable shortcut's event propagation. + _(Default: false)_ : + An option to disable or enable shortcut's event propagation. + + * `template-url` + _(Default: 'template/datepicker/datepicker.html') : + Allows overriding of default template of the datepicker ### Popup Settings ### @@ -115,6 +119,14 @@ Specific settings for the `datepicker-popup`, that can globally configured throu _(Default: true)_ : Whether to close calendar when a date is chosen. + * `datepicker-popup-template-url` + _(Default: 'template/datepicker/popup.html') : + Allows overriding of default template of the popup + + * `datepicker-template-url` + _(Default: 'template/datepicker/popup.html') : + Allows overriding of default template of the datepicker used in popup + * `datepicker-append-to-body` _(Default: false)_: Append the datepicker popup element to `body`, rather than inserting after `datepicker-popup`. For global configuration, use `datepickerPopupConfig.appendToBody`. diff --git a/src/datepicker/test/datepicker.spec.js b/src/datepicker/test/datepicker.spec.js index c0342a8710..90602b3a4c 100644 --- a/src/datepicker/test/datepicker.spec.js +++ b/src/datepicker/test/datepicker.spec.js @@ -1,5 +1,5 @@ describe('datepicker directive', function () { - var $rootScope, $compile, element; + var $rootScope, $compile, $templateCache, element; beforeEach(module('ui.bootstrap.datepicker')); beforeEach(module('template/datepicker/datepicker.html')); beforeEach(module('template/datepicker/day.html')); @@ -198,10 +198,11 @@ describe('datepicker directive', function () { }); describe('', function () { - beforeEach(inject(function(_$compile_, _$rootScope_) { + beforeEach(inject(function(_$compile_, _$rootScope_, _$templateCache_) { $compile = _$compile_; $rootScope = _$rootScope_; $rootScope.date = new Date('September 30, 2010 15:30:00'); + $templateCache = _$templateCache_; })); @@ -352,6 +353,31 @@ describe('datepicker directive', function () { expect(getTitle()).toBe('January 2014'); }); + it('should support custom templates', function() { + $templateCache.put('foo/bar.html', '
baz
'); + + element = $compile('')($rootScope); + $rootScope.$digest(); + + expect(element.html()).toBe('baz'); + }); + + it('should expose the controller in the template', function() { + $templateCache.put('template/datepicker/datepicker.html', '
{{datepicker.text}}
'); + + element = $compile('')($rootScope); + $rootScope.$digest(); + + var ctrl = element.controller('datepicker'); + expect(ctrl).toBeDefined(); + expect(element.html()).toBe(''); + + ctrl.text = 'baz'; + $rootScope.$digest(); + + expect(element.html()).toBe('baz'); + }); + // issue #3079 describe('time zone bug', function () { @@ -2007,6 +2033,50 @@ describe('datepicker directive', function () { }); }); + describe('with datepicker-popup-template-url', function() { + beforeEach(function() { + $rootScope.date = new Date(); + }); + + afterEach(function () { + $document.find('body').find('.dropdown-menu').remove(); + }); + + it('should allow custom templates for the popup', function() { + $templateCache.put('foo/bar.html', '
baz
'); + + var elm = angular.element('
'); + + $compile(elm)($rootScope); + $rootScope.$digest(); + + expect(elm.children().eq(1).html()).toBe('baz'); + }); + }); + + describe('with datepicker-template-url', function() { + beforeEach(function() { + $rootScope.date = new Date(); + }); + + afterEach(function () { + $document.find('body').find('.dropdown-menu').remove(); + }); + + it('should allow custom templates for the datepicker', function() { + $templateCache.put('foo/bar.html', '
baz
'); + + var elm = angular.element('
'); + + $compile(elm)($rootScope); + $rootScope.$digest(); + + var datepicker = elm.find('[datepicker]'); + + expect(datepicker.html()).toBe('baz'); + }); + }); + describe('with an append-to-body attribute', function() { beforeEach(function() { $rootScope.date = new Date();