From 34c0858a10f723b04057f78435d943aba17a9462 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 10:46:28 -0500 Subject: [PATCH 01/13] chore: bump angular version BREAKING CHANGE: Applications must being using Angular 1.6 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index d3794b1b7c..02a47bbd9e 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,9 @@ "url": "https://github.com/angular-ui/bootstrap.git" }, "devDependencies": { - "angular": "1.5.8", - "angular-mocks": "1.5.8", - "angular-sanitize": "1.5.8", + "angular": "1.6.0", + "angular-mocks": "1.6.0", + "angular-sanitize": "1.6.0", "grunt": "^0.4.5", "grunt-cli": "^1.2.0", "grunt-contrib-concat": "^1.0.0", From f75ac4e822dbcd69d1d49b8aeaadf92f566249fd Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 10:54:51 -0500 Subject: [PATCH 02/13] fix(accordion): transclusion no longer introduces span --- src/accordion/test/accordion.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/accordion/test/accordion.spec.js b/src/accordion/test/accordion.spec.js index 1879d6f9c4..bb64a4b2c6 100644 --- a/src/accordion/test/accordion.spec.js +++ b/src/accordion/test/accordion.spec.js @@ -551,7 +551,7 @@ describe('uib-accordion', function() { }); it('attaches the same scope to the transcluded heading and body', function() { - expect(findGroupLink(0).find('span.ng-scope').scope().$id).toBe(findGroupBody(0).find('span').scope().$id); + expect(findGroupLink(0).scope().$id).toBe(findGroupBody(0).scope().$id); }); it('should wrap the transcluded content in a span', function() { @@ -580,7 +580,7 @@ describe('uib-accordion', function() { }); it('attaches the same scope to the transcluded heading and body', function() { - expect(findGroupLink(0).find('span.ng-scope').scope().$id).toBe(findGroupBody(0).find('span').scope().$id); + expect(findGroupLink(0).scope().$id).toBe(findGroupBody(0).scope().$id); }); it('should have disabled styling when is-disabled is true', isDisabledStyleCheck); From faf7cb8512096a39edecdcd11f9567e4a08c4ef0 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 11:11:13 -0500 Subject: [PATCH 03/13] fix(modal): transclusion no longer introduces span --- src/modal/test/modal.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index 86f0a107c7..17d5589f49 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -1612,7 +1612,7 @@ describe('$uibModal', function() { var windowEl = $compile('
content
')($rootScope); $rootScope.$digest(); - expect(windowEl.html()).toBe('
content
'); + expect(windowEl.html()).toBe('
content
'); })); }); From 3a94ba42c4797cf3516ef74529dd1f4df65b5d18 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 11:12:19 -0500 Subject: [PATCH 04/13] fix(collapse): handle promise rejections --- src/collapse/collapse.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/collapse/collapse.js b/src/collapse/collapse.js index d809a1df91..7e605b641d 100644 --- a/src/collapse/collapse.js +++ b/src/collapse/collapse.js @@ -72,7 +72,7 @@ angular.module('ui.bootstrap.collapse', []) to: getScrollFromElement(element[0]) }).then(expandDone); } - }); + }, angular.noop); } function expandDone() { @@ -111,7 +111,7 @@ angular.module('ui.bootstrap.collapse', []) to: cssTo }).then(collapseDone); } - }); + }, angular.noop); } function collapseDone() { From bcec969c00fa0215e488ca5144658220727e6ddb Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 11:12:41 -0500 Subject: [PATCH 05/13] fix(modal): handle promise rejections --- src/modal/modal.js | 8 ++++---- src/modal/test/modal.spec.js | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/modal/modal.js b/src/modal/modal.js index eeb79c101e..679ff188e8 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -419,10 +419,6 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.multiMap', 'ui.bootstrap.sta var appendToElement = modal.appendTo, currBackdropIndex = backdropIndex(); - if (!appendToElement.length) { - throw new Error('appendTo element not found. Make sure that the element passed is in DOM.'); - } - if (currBackdropIndex >= 0 && !backdropDomEl) { backdropScope = $rootScope.$new(true); backdropScope.modalOptions = modal; @@ -699,6 +695,10 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.multiMap', 'ui.bootstrap.sta modalOptions.resolve = modalOptions.resolve || {}; modalOptions.appendTo = modalOptions.appendTo || $document.find('body').eq(0); + if (!modalOptions.appendTo.length) { + throw new Error('appendTo element not found. Make sure that the element passed is in DOM.'); + } + //verify options if (!modalOptions.component && !modalOptions.template && !modalOptions.templateUrl) { throw new Error('One of component or template or templateUrl options is required.'); diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index 17d5589f49..4bf85243da 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -296,6 +296,8 @@ describe('$uibModal', function() { function open(modalOptions, noFlush, noDigest) { var modal = $uibModal.open(modalOptions); + modal.opened['catch'](angular.noop); + modal.result['catch'](angular.noop); if (!noDigest) { $rootScope.$digest(); @@ -1736,16 +1738,19 @@ describe('$uibModal', function() { ds[x] = {index: i, deferred: $q.defer(), reject: reject}; var scope = $rootScope.$new(); + var failed = false; scope.index = i; open({ template: '
' + i + '
', scope: scope, resolve: { - x: function() { return ds[x].deferred.promise; } + x: function() { return ds[x].deferred.promise['catch'](function () { + failed = true; + }); } } }, true).opened.then(function() { expect($uibModalStack.getTop().value.modalScope.index).toEqual(i); - actual += i; + if (!failed) { actual += i; } }); }); From 5c086f8a38823991bc54d117ecfe1436d193eb6c Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 11:21:16 -0500 Subject: [PATCH 06/13] fix(alert): transclusion no longer introduces span --- src/alert/test/alert.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alert/test/alert.spec.js b/src/alert/test/alert.spec.js index d38b4fab60..bc87c7f7ad 100644 --- a/src/alert/test/alert.spec.js +++ b/src/alert/test/alert.spec.js @@ -36,7 +36,7 @@ describe('uib-alert', function() { } function findContent(index) { - return element.find('div[ng-transclude] span').eq(index); + return element.find('div[ng-transclude]').eq(index); } it('should expose the controller to the view', function() { From be7ad86c35003167001159a58e79a3fcdb4ef697 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 13:51:14 -0500 Subject: [PATCH 07/13] fix(datepicker): $options is always present; use $options.getOption() --- src/datepicker/datepicker.js | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/datepicker/datepicker.js b/src/datepicker/datepicker.js index ca21a459b7..cfe8b37368 100644 --- a/src/datepicker/datepicker.js +++ b/src/datepicker/datepicker.js @@ -104,7 +104,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst $scope.$watch('datepickerOptions.' + key, function(value) { if (value) { if (angular.isDate(value)) { - self[key] = dateParser.fromTimezone(new Date(value), ngModelOptions.timezone); + self[key] = dateParser.fromTimezone(new Date(value), ngModelOptions.getOption('timezone')); } else { if ($datepickerLiteralWarning) { $log.warn('Literal date support has been deprecated, please switch to date object usage'); @@ -114,7 +114,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst } } else { self[key] = datepickerConfig[key] ? - dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.timezone) : + dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.getOption('timezone')) : null; } @@ -161,14 +161,24 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst this.init = function(ngModelCtrl_) { ngModelCtrl = ngModelCtrl_; - ngModelOptions = ngModelCtrl_.$options || - $scope.datepickerOptions.ngModelOptions || - datepickerConfig.ngModelOptions; + + // grab any timezone value based on precedence + var timezone = ngModelCtrl_.$options.getOption('timezone') || + ($scope.datepickerOptions.ngModelOptions ? $scope.datepickerOptions.ngModelOptions.timezone : null) || + (datepickerConfig.ngModelOptions ? datepickerConfig.ngModelOptions.timezone : null); + + // need to start with existing ModelOptions but also give it greatest precedence minus its default of null timezone + ngModelOptions = ngModelCtrl_.$options + .createChild(datepickerConfig.ngModelOptions) + .createChild($scope.datepickerOptions.ngModelOptions) + .createChild(ngModelCtrl_.$options) + .createChild({timezone: timezone}); + if ($scope.datepickerOptions.initDate) { - self.activeDate = dateParser.fromTimezone($scope.datepickerOptions.initDate, ngModelOptions.timezone) || new Date(); + self.activeDate = dateParser.fromTimezone($scope.datepickerOptions.initDate, ngModelOptions.getOption('timezone')) || new Date(); $scope.$watch('datepickerOptions.initDate', function(initDate) { if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) { - self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.timezone); + self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.getOption('timezone')); self.refreshView(); } }); @@ -178,8 +188,8 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : new Date(); this.activeDate = !isNaN(date) ? - dateParser.fromTimezone(date, ngModelOptions.timezone) : - dateParser.fromTimezone(new Date(), ngModelOptions.timezone); + dateParser.fromTimezone(date, ngModelOptions.getOption('timezone')) : + dateParser.fromTimezone(new Date(), ngModelOptions.getOption('timezone')); ngModelCtrl.$render = function() { self.render(); @@ -192,7 +202,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst isValid = !isNaN(date); if (isValid) { - this.activeDate = dateParser.fromTimezone(date, ngModelOptions.timezone); + this.activeDate = dateParser.fromTimezone(date, ngModelOptions.getOption('timezone')); } else if (!$datepickerSuppressError) { $log.error('Datepicker directive: "ng-model" value must be a Date object'); } @@ -209,7 +219,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst } var date = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null; - date = dateParser.fromTimezone(date, ngModelOptions.timezone); + date = dateParser.fromTimezone(date, ngModelOptions.getOption('timezone')); ngModelCtrl.$setValidity('dateDisabled', !date || this.element && !this.isDisabled(date)); } @@ -217,9 +227,9 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst this.createDateObject = function(date, format) { var model = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null; - model = dateParser.fromTimezone(model, ngModelOptions.timezone); + model = dateParser.fromTimezone(model, ngModelOptions.getOption('timezone')); var today = new Date(); - today = dateParser.fromTimezone(today, ngModelOptions.timezone); + today = dateParser.fromTimezone(today, ngModelOptions.getOption('timezone')); var time = this.compare(date, today); var dt = { date: date, @@ -265,9 +275,9 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst $scope.select = function(date) { if ($scope.datepickerMode === self.minMode) { - var dt = ngModelCtrl.$viewValue ? dateParser.fromTimezone(new Date(ngModelCtrl.$viewValue), ngModelOptions.timezone) : new Date(0, 0, 0, 0, 0, 0, 0); + var dt = ngModelCtrl.$viewValue ? dateParser.fromTimezone(new Date(ngModelCtrl.$viewValue), ngModelOptions.getOption('timezone')) : new Date(0, 0, 0, 0, 0, 0, 0); dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); - dt = dateParser.toTimezone(dt, ngModelOptions.timezone); + dt = dateParser.toTimezone(dt, ngModelOptions.getOption('timezone')); ngModelCtrl.$setViewValue(dt); ngModelCtrl.$render(); } else { From 92f41803b4851fa7c11f824e29063298d37c4144 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 13:58:56 -0500 Subject: [PATCH 08/13] fix(datepickerPopup): $options is always present --- src/datepickerPopup/popup.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/datepickerPopup/popup.js b/src/datepickerPopup/popup.js index 0d03c4e73d..5c9c8b5714 100644 --- a/src/datepickerPopup/popup.js +++ b/src/datepickerPopup/popup.js @@ -32,11 +32,7 @@ function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $ this.init = function(_ngModel_) { ngModel = _ngModel_; - ngModelOptions = angular.isObject(_ngModel_.$options) ? - _ngModel_.$options : - { - timezone: null - }; + ngModelOptions = _ngModel_.$options; closeOnDateSelection = angular.isDefined($attrs.closeOnDateSelection) ? $scope.$parent.$eval($attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection; @@ -127,13 +123,13 @@ function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $ value = new Date(value); } - $scope.date = dateParser.fromTimezone(value, ngModelOptions.timezone); + $scope.date = dateParser.fromTimezone(value, ngModelOptions.getOption('timezone')); return dateParser.filter($scope.date, dateFormat); }); } else { ngModel.$formatters.push(function(value) { - $scope.date = dateParser.fromTimezone(value, ngModelOptions.timezone); + $scope.date = dateParser.fromTimezone(value, ngModelOptions.getOption('timezone')); return value; }); } @@ -185,7 +181,7 @@ function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $ $scope.isDisabled = function(date) { if (date === 'today') { - date = dateParser.fromTimezone(new Date(), ngModelOptions.timezone); + date = dateParser.fromTimezone(new Date(), ngModelOptions.getOption('timezone')); } var dates = {}; @@ -242,7 +238,7 @@ function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $ date = new Date($scope.date); date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate()); } else { - date = dateParser.fromTimezone(today, ngModelOptions.timezone); + date = dateParser.fromTimezone(today, ngModelOptions.getOption('timezone')); date.setHours(0, 0, 0, 0); } } @@ -333,11 +329,11 @@ function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $ if (angular.isString(viewValue)) { var date = parseDateString(viewValue); if (!isNaN(date)) { - return dateParser.toTimezone(date, ngModelOptions.timezone); + return dateParser.toTimezone(date, ngModelOptions.getOption('timezone')); } } - return ngModel.$options && ngModel.$options.allowInvalid ? viewValue : undefined; + return ngModel.$options.getOption('allowInvalid') ? viewValue : undefined; } function validator(modelValue, viewValue) { From b053fc9827c9c7cfae12b55817ad40d6b2feed19 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 24 Jan 2017 14:10:48 -0500 Subject: [PATCH 09/13] fix(typeahead): $options is always present; use $options.getOption() --- src/typeahead/typeahead.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/typeahead/typeahead.js b/src/typeahead/typeahead.js index 81492f03dc..4efbba49b1 100644 --- a/src/typeahead/typeahead.js +++ b/src/typeahead/typeahead.js @@ -30,7 +30,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap function(originalScope, element, attrs, $compile, $parse, $q, $timeout, $document, $window, $rootScope, $$debounce, $position, typeaheadParser) { var HOT_KEYS = [9, 13, 27, 38, 40]; var eventDebounceTime = 200; - var modelCtrl, ngModelOptions; + var modelCtrl; //SUPPORTED ATTRIBUTES (OPTIONS) //minimal no of characters that needs to be entered before typeahead kicks-in @@ -94,7 +94,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap var invokeModelSetter = $parse(attrs.ngModel + '($$$p)'); var $setModelValue = function(scope, newValue) { if (angular.isFunction(parsedModel(originalScope)) && - ngModelOptions && ngModelOptions.$options && ngModelOptions.$options.getterSetter) { + modelCtrl.$options.getOption('getterSetter')) { return invokeModelSetter(scope, {$$$p: newValue}); } @@ -507,11 +507,10 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap element.after($popup); } - this.init = function(_modelCtrl, _ngModelOptions) { + this.init = function(_modelCtrl) { modelCtrl = _modelCtrl; - ngModelOptions = _ngModelOptions; - scope.debounceUpdate = modelCtrl.$options && $parse(modelCtrl.$options.debounce)(originalScope); + scope.debounceUpdate = $parse(modelCtrl.$options.getOption('debounce'))(originalScope); //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue @@ -576,9 +575,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap .directive('uibTypeahead', function() { return { controller: 'UibTypeaheadController', - require: ['ngModel', '^?ngModelOptions', 'uibTypeahead'], + require: ['ngModel', 'uibTypeahead'], link: function(originalScope, element, attrs, ctrls) { - ctrls[2].init(ctrls[0], ctrls[1]); + ctrls[1].init(ctrls[0]); } }; }) From e99ce9e3e4780d9801a911c5d14e3276b500006a Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Thu, 26 Jan 2017 15:26:05 -0500 Subject: [PATCH 10/13] chore: bump angular to latest version of 1.6 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 02a47bbd9e..351c21cefa 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,9 @@ "url": "https://github.com/angular-ui/bootstrap.git" }, "devDependencies": { - "angular": "1.6.0", - "angular-mocks": "1.6.0", - "angular-sanitize": "1.6.0", + "angular": "1.6.1", + "angular-mocks": "1.6.1", + "angular-sanitize": "1.6.1", "grunt": "^0.4.5", "grunt-cli": "^1.2.0", "grunt-contrib-concat": "^1.0.0", From 35a9868a6477fa18403e4bd20a100e94944e2ea2 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Thu, 26 Jan 2017 15:27:27 -0500 Subject: [PATCH 11/13] fix(datepicker): handle $options for Angular 1.5 --- src/datepicker/datepicker.js | 44 ++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/datepicker/datepicker.js b/src/datepicker/datepicker.js index cfe8b37368..fd4e263660 100644 --- a/src/datepicker/datepicker.js +++ b/src/datepicker/datepicker.js @@ -161,18 +161,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst this.init = function(ngModelCtrl_) { ngModelCtrl = ngModelCtrl_; - - // grab any timezone value based on precedence - var timezone = ngModelCtrl_.$options.getOption('timezone') || - ($scope.datepickerOptions.ngModelOptions ? $scope.datepickerOptions.ngModelOptions.timezone : null) || - (datepickerConfig.ngModelOptions ? datepickerConfig.ngModelOptions.timezone : null); - - // need to start with existing ModelOptions but also give it greatest precedence minus its default of null timezone - ngModelOptions = ngModelCtrl_.$options - .createChild(datepickerConfig.ngModelOptions) - .createChild($scope.datepickerOptions.ngModelOptions) - .createChild(ngModelCtrl_.$options) - .createChild({timezone: timezone}); + ngModelOptions = extractOptions(ngModelCtrl); if ($scope.datepickerOptions.initDate) { self.activeDate = dateParser.fromTimezone($scope.datepickerOptions.initDate, ngModelOptions.getOption('timezone')) || new Date(); @@ -362,6 +351,37 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst $scope.datepickerMode = mode; $scope.datepickerOptions.datepickerMode = mode; } + + function extractOptions(ngModelCtrl) { + var ngModelOptions; + + if (angular.version.minor < 6) { // in angular < 1.6 $options could be missing + // guarantee a value + ngModelOptions = ngModelCtrl.$options || + $scope.datepickerOptions.ngModelOptions || + datepickerConfig.ngModelOptions || + {}; + + // mimic 1.6+ api + ngModelOptions.getOption = function (key) { + return ngModelOptions[key]; + }; + } else { // in angular >=1.6 $options is always present + // ng-model-options defaults timezone to null; don't let its precedence squash a non-null value + var timezone = ngModelCtrl.$options.getOption('timezone') || + ($scope.datepickerOptions.ngModelOptions ? $scope.datepickerOptions.ngModelOptions.timezone : null) || + (datepickerConfig.ngModelOptions ? datepickerConfig.ngModelOptions.timezone : null); + + // values passed to createChild override existing values + ngModelOptions = ngModelCtrl.$options // start with a ModelOptions instance + .createChild(datepickerConfig.ngModelOptions) // lowest precedence + .createChild($scope.datepickerOptions.ngModelOptions) + .createChild(ngModelCtrl.$options) // highest precedence + .createChild({timezone: timezone}); // to keep from squashing a non-null value + } + + return ngModelOptions; + } }]) .controller('UibDaypickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) { From ac901101727210bce8bd95f33b018f8115d19cf3 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Thu, 26 Jan 2017 15:27:40 -0500 Subject: [PATCH 12/13] fix(datepickerPopup): handle $options for Angular 1.5 --- src/datepickerPopup/popup.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/datepickerPopup/popup.js b/src/datepickerPopup/popup.js index 5c9c8b5714..02c0e88a1c 100644 --- a/src/datepickerPopup/popup.js +++ b/src/datepickerPopup/popup.js @@ -32,7 +32,7 @@ function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $ this.init = function(_ngModel_) { ngModel = _ngModel_; - ngModelOptions = _ngModel_.$options; + ngModelOptions = extractOptions(ngModel); closeOnDateSelection = angular.isDefined($attrs.closeOnDateSelection) ? $scope.$parent.$eval($attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection; @@ -333,7 +333,7 @@ function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $ } } - return ngModel.$options.getOption('allowInvalid') ? viewValue : undefined; + return ngModelOptions.getOption('allowInvalid') ? viewValue : undefined; } function validator(modelValue, viewValue) { @@ -408,6 +408,28 @@ function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $ } } + function extractOptions(ngModelCtrl) { + var ngModelOptions; + + if (angular.version.minor < 6) { // in angular < 1.6 $options could be missing + // guarantee a value + ngModelOptions = angular.isObject(ngModelCtrl.$options) ? + ngModelCtrl.$options : + { + timezone: null + }; + + // mimic 1.6+ api + ngModelOptions.getOption = function (key) { + return ngModelOptions[key]; + }; + } else { // in angular >=1.6 $options is always present + ngModelOptions = ngModelCtrl.$options; + } + + return ngModelOptions; + } + $scope.$on('uib:datepicker.mode', function() { $timeout(positionPopup, 0, false); }); From 6fe0362912c2fc20f9791493f44d570a6da0b945 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Thu, 26 Jan 2017 15:27:52 -0500 Subject: [PATCH 13/13] fix(typeahead): handle $options for Angular 1.5 --- src/typeahead/typeahead.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/typeahead/typeahead.js b/src/typeahead/typeahead.js index 4efbba49b1..71b807c817 100644 --- a/src/typeahead/typeahead.js +++ b/src/typeahead/typeahead.js @@ -30,7 +30,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap function(originalScope, element, attrs, $compile, $parse, $q, $timeout, $document, $window, $rootScope, $$debounce, $position, typeaheadParser) { var HOT_KEYS = [9, 13, 27, 38, 40]; var eventDebounceTime = 200; - var modelCtrl; + var modelCtrl, ngModelOptions; //SUPPORTED ATTRIBUTES (OPTIONS) //minimal no of characters that needs to be entered before typeahead kicks-in @@ -94,7 +94,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap var invokeModelSetter = $parse(attrs.ngModel + '($$$p)'); var $setModelValue = function(scope, newValue) { if (angular.isFunction(parsedModel(originalScope)) && - modelCtrl.$options.getOption('getterSetter')) { + ngModelOptions.getOption('getterSetter')) { return invokeModelSetter(scope, {$$$p: newValue}); } @@ -509,8 +509,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap this.init = function(_modelCtrl) { modelCtrl = _modelCtrl; + ngModelOptions = extractOptions(modelCtrl); - scope.debounceUpdate = $parse(modelCtrl.$options.getOption('debounce'))(originalScope); + scope.debounceUpdate = $parse(ngModelOptions.getOption('debounce'))(originalScope); //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue @@ -570,6 +571,24 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap return candidateViewValue !== emptyViewValue ? candidateViewValue : modelValue; }); }; + + function extractOptions(ngModelCtrl) { + var ngModelOptions; + + if (angular.version.minor < 6) { // in angular < 1.6 $options could be missing + // guarantee a value + ngModelOptions = ngModelCtrl.$options || {}; + + // mimic 1.6+ api + ngModelOptions.getOption = function (key) { + return ngModelOptions[key]; + }; + } else { // in angular >=1.6 $options is always present + ngModelOptions = ngModelCtrl.$options; + } + + return ngModelOptions; + } }]) .directive('uibTypeahead', function() {