From f02a24d2323b75cc35c014919ebe0a03be548c7a Mon Sep 17 00:00:00 2001 From: Robin van Baalen Date: Sun, 7 Jun 2015 22:33:31 -0400 Subject: [PATCH 0001/1156] chore(readme): make main title fit on one line --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a4d595d91..028c59551b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# UI Bootstrap - [AngularJS](http://angularjs.org/) directives specific to [Bootstrap](http://getbootstrap.com) +### UI Bootstrap - [AngularJS](http://angularjs.org/) directives specific to [Bootstrap](http://getbootstrap.com) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular-ui/bootstrap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://secure.travis-ci.org/angular-ui/bootstrap.svg)](http://travis-ci.org/angular-ui/bootstrap) From 115d490a251a557828ecc24e12367abc5ef009c5 Mon Sep 17 00:00:00 2001 From: Wesley Cho Date: Tue, 9 Jun 2015 23:23:11 -0700 Subject: [PATCH 0002/1156] fix(carousel): ensure there are slides present - Ensure there are slides present before calling `$scope.next` in timer Fixes #3755 --- src/carousel/carousel.js | 2 +- src/carousel/test/carousel.spec.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/carousel/carousel.js b/src/carousel/carousel.js index ce50c9429a..8fc66e5ef8 100644 --- a/src/carousel/carousel.js +++ b/src/carousel/carousel.js @@ -113,7 +113,7 @@ angular.module('ui.bootstrap.carousel', []) function timerFn() { var interval = +$scope.interval; - if (isPlaying && !isNaN(interval) && interval > 0) { + if (isPlaying && !isNaN(interval) && interval > 0 && slides.length) { $scope.next(); } else { $scope.pause(); diff --git a/src/carousel/test/carousel.spec.js b/src/carousel/test/carousel.spec.js index 86e5a0735a..82a878d659 100644 --- a/src/carousel/test/carousel.spec.js +++ b/src/carousel/test/carousel.spec.js @@ -146,7 +146,7 @@ describe('carousel', function() { testSlideActive(1); }); - it('shouldnt go forward if interval is NaN or negative', function() { + it('shouldnt go forward if interval is NaN or negative or has no slides', function() { testSlideActive(0); var previousInterval = scope.interval; scope.$apply('interval = -1'); @@ -161,6 +161,9 @@ describe('carousel', function() { scope.$apply('interval = 1000'); $interval.flush(1000); testSlideActive(2); + scope.$apply('slides = []'); + $interval.flush(1000); + testSlideActive(2); }); it('should bind the content to slides', function() { From 0d96221fa32794deb702d1b923ae38f11f5b66a4 Mon Sep 17 00:00:00 2001 From: Wesley Cho Date: Wed, 10 Jun 2015 06:48:49 -0700 Subject: [PATCH 0003/1156] fix(typeahead): do not execute unnecessary $digest - If in a $digest, do not execute `scope.$digest` Fixes #2652 Closes #3791 --- src/typeahead/typeahead.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/typeahead/typeahead.js b/src/typeahead/typeahead.js index 1fe28401ab..994a7b2e79 100644 --- a/src/typeahead/typeahead.js +++ b/src/typeahead/typeahead.js @@ -29,8 +29,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap }; }]) - .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser', - function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) { + .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$rootScope', '$position', 'typeaheadParser', + function ($compile, $parse, $q, $timeout, $document, $rootScope, $position, typeaheadParser) { var HOT_KEYS = [9, 13, 27, 38, 40]; @@ -318,7 +318,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap var dismissClickHandler = function (evt) { if (element[0] !== evt.target) { resetMatches(); - scope.$digest(); + if (!$rootScope.$$phase) { + scope.$digest(); + } } }; From 988336ccff6efccc88bd26b8015d79d4a82c229c Mon Sep 17 00:00:00 2001 From: Thomas Haukland Date: Mon, 11 May 2015 23:46:50 +0200 Subject: [PATCH 0004/1156] fix(modal): focus on body if element disappears - Change to focus on `document.body` instead if element is not present Closes #3653 Fixes #3639 --- src/modal/modal.js | 15 ++++++++++----- src/modal/test/modal.spec.js | 26 +++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/modal/modal.js b/src/modal/modal.js index 9470f62d5c..c6215f4a11 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -195,7 +195,7 @@ angular.module('ui.bootstrap.modal', []) } }); - function removeModalWindow(modalInstance) { + function removeModalWindow(modalInstance, elementToReceiveFocus) { var body = $document.find('body').eq(0); var modalWindow = openedWindows.get(modalInstance).value; @@ -208,6 +208,13 @@ angular.module('ui.bootstrap.modal', []) body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0); checkRemoveBackdrop(); }); + + //move focus to specified element if available, or else to body + if (elementToReceiveFocus && elementToReceiveFocus.focus) { + elementToReceiveFocus.focus(); + } else { + body.focus(); + } } function checkRemoveBackdrop() { @@ -318,8 +325,7 @@ angular.module('ui.bootstrap.modal', []) var modalWindow = openedWindows.get(modalInstance); if (modalWindow && broadcastClosing(modalWindow, result, true)) { modalWindow.value.deferred.resolve(result); - removeModalWindow(modalInstance); - modalWindow.value.modalOpener.focus(); + removeModalWindow(modalInstance, modalWindow.value.modalOpener); return true; } return !modalWindow; @@ -329,8 +335,7 @@ angular.module('ui.bootstrap.modal', []) var modalWindow = openedWindows.get(modalInstance); if (modalWindow && broadcastClosing(modalWindow, reason, false)) { modalWindow.value.deferred.reject(reason); - removeModalWindow(modalInstance); - modalWindow.value.modalOpener.focus(); + removeModalWindow(modalInstance, modalWindow.value.modalOpener); return true; } return !modalWindow; diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index c1d5fe4c29..0afe94ab8d 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -250,7 +250,7 @@ describe('$modal', function () { expect($document).toHaveModalsOpen(0); }); - it('should return to the element which had focus before the dialog is invoked', function () { + it('should return to the element which had focus before the dialog was invoked', function () { var link = 'Link'; var element = angular.element(link); angular.element(document.body).append(element); @@ -272,6 +272,30 @@ describe('$modal', function () { element.remove(); }); + it('should return to document.body if element which had focus before the dialog was invoked is gone, or is missing focus function', function () { + var link = 'Link'; + var element = angular.element(link); + angular.element(document.body).append(element); + element.focus(); + expect(document.activeElement.tagName).toBe('A'); + + var modal = open({template: '
Content
'}); + $timeout.flush(); + expect(document.activeElement.tagName).toBe('DIV'); + expect($document).toHaveModalsOpen(1); + + // Fake undefined focus function, happening in IE in certain + // iframe conditions. See issue 3639 + element[0].focus = undefined; + triggerKeyDown($document, 27); + $timeout.flush(); + $rootScope.$digest(); + + expect(document.activeElement.tagName).toBe('BODY'); + expect($document).toHaveModalsOpen(0); + element.remove(); + }); + it('should resolve returned promise on close', function () { var modal = open({template: '
Content
'}); close(modal, 'closed ok'); From a5a25141fc88e642b84e135796daaf77dc653273 Mon Sep 17 00:00:00 2001 From: Joe Ibershoff Date: Wed, 29 Apr 2015 20:26:56 -0400 Subject: [PATCH 0005/1156] feat(typeahead): handles min-length of 0 Closes #3600 --- src/typeahead/test/typeahead.spec.js | 9 +++++++++ src/typeahead/typeahead.js | 7 +++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/typeahead/test/typeahead.spec.js b/src/typeahead/test/typeahead.spec.js index 741621e65c..a86dcedd7e 100644 --- a/src/typeahead/test/typeahead.spec.js +++ b/src/typeahead/test/typeahead.spec.js @@ -842,4 +842,13 @@ describe('typeahead tests', function () { expect($scope.select_count).toEqual(1); }); + describe('minLength set to 0', function () { + it('should open typeahead if input is changed to empty string if defined threshold is 0', function () { + var element = prepareInputEl('
'); + changeInputValueTo(element, ''); + + expect(element).toBeOpenWithActive(3, 0); + }); + }); + }); diff --git a/src/typeahead/typeahead.js b/src/typeahead/typeahead.js index 994a7b2e79..b1efde2409 100644 --- a/src/typeahead/typeahead.js +++ b/src/typeahead/typeahead.js @@ -41,7 +41,10 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap //SUPPORTED ATTRIBUTES (OPTIONS) //minimal no of characters that needs to be entered before typeahead kicks-in - var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1; + var minLength = originalScope.$eval(attrs.typeaheadMinLength); + if (!minLength && minLength !== 0) { + minLength = 1; + } //minimal wait time after last character typed before typeahead kicks-in var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0; @@ -193,7 +196,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap hasFocus = true; - if (inputValue && inputValue.length >= minSearch) { + if (minLength === 0 || inputValue && inputValue.length >= minLength) { if (waitTime > 0) { cancelPreviousTimeout(); scheduleSearchWithTimeout(inputValue); From ca07ad7c72faa9672376aaebc38d4b15ef436e9a Mon Sep 17 00:00:00 2001 From: Wesley Cho Date: Wed, 10 Jun 2015 09:35:16 -0700 Subject: [PATCH 0006/1156] fix(carousel): change to avoid references to debug info - Change usage of `.scope()` and `.isolateScope()` to grab metadata from elements Closes #3795 Fixes #3794 --- src/carousel/carousel.js | 20 +++++++++++++++----- src/carousel/test/carousel.spec.js | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/carousel/carousel.js b/src/carousel/carousel.js index 8fc66e5ef8..3b99a20052 100644 --- a/src/carousel/carousel.js +++ b/src/carousel/carousel.js @@ -7,9 +7,11 @@ * */ angular.module('ui.bootstrap.carousel', []) -.controller('CarouselController', ['$scope', '$interval', '$animate', function ($scope, $interval, $animate) { +.controller('CarouselController', ['$scope', '$element', '$interval', '$animate', function ($scope, $element, $interval, $animate) { var self = this, slides = self.slides = $scope.slides = [], + NO_TRANSITION = 'uib-noTransition', + SLIDE_DIRECTION = 'uib-slideDirection', currentIndex = -1, currentInterval, isPlaying; self.currentSlide = null; @@ -36,6 +38,7 @@ angular.module('ui.bootstrap.carousel', []) angular.extend(self.currentSlide || {}, {direction: direction, active: false}); if ($animate.enabled() && !$scope.noTransition && !$scope.$currentTransition && slide.$element) { + slide.$element.data(SLIDE_DIRECTION, slide.direction); $scope.$currentTransition = true; slide.$element.one('$animate:close', function closeFn() { $scope.$currentTransition = null; @@ -167,6 +170,10 @@ angular.module('ui.bootstrap.carousel', []) } }; + $scope.$watch('noTransition', function(noTransition) { + $element.data(NO_TRANSITION, noTransition); + }); + }]) /** @@ -295,13 +302,16 @@ function CarouselDemoCtrl($scope) { .animation('.item', [ '$animate', function ($animate) { + var NO_TRANSITION = 'uib-noTransition', + SLIDE_DIRECTION = 'uib-slideDirection'; + return { beforeAddClass: function (element, className, done) { // Due to transclusion, noTransition property is on parent's scope if (className == 'active' && element.parent() && - !element.parent().scope().noTransition) { + !element.parent().data(NO_TRANSITION)) { var stopped = false; - var direction = element.isolateScope().direction; + var direction = element.data(SLIDE_DIRECTION); var directionClass = direction == 'next' ? 'left' : 'right'; element.addClass(direction); $animate.addClass(element, directionClass).then(function () { @@ -320,9 +330,9 @@ function ($animate) { beforeRemoveClass: function (element, className, done) { // Due to transclusion, noTransition property is on parent's scope if (className == 'active' && element.parent() && - !element.parent().scope().noTransition) { + !element.parent().data(NO_TRANSITION)) { var stopped = false; - var direction = element.isolateScope().direction; + var direction = element.data(SLIDE_DIRECTION); var directionClass = direction == 'next' ? 'left' : 'right'; $animate.addClass(element, directionClass).then(function () { if (!stopped) { diff --git a/src/carousel/test/carousel.spec.js b/src/carousel/test/carousel.spec.js index 82a878d659..69babfc071 100644 --- a/src/carousel/test/carousel.spec.js +++ b/src/carousel/test/carousel.spec.js @@ -349,7 +349,7 @@ describe('carousel', function() { beforeEach(function() { scope = $rootScope.$new(); - ctrl = $controller('CarouselController', {$scope: scope, $element: null}); + ctrl = $controller('CarouselController', {$scope: scope, $element: angular.element('
')}); for(var i = 0;i < slides.length;i++){ ctrl.addSlide(slides[i]); } From 49e73a89f36b1c44d7547b8910bcb17e96135294 Mon Sep 17 00:00:00 2001 From: Wesley Cho Date: Thu, 11 Jun 2015 09:47:28 -0700 Subject: [PATCH 0007/1156] chore(typeahead): change to one-way binding for position - Change position to one-way binding to reduce an unnecessary $watch chore(typeahead): add bind once to id attr --- src/typeahead/typeahead.js | 2 +- template/typeahead/typeahead-popup.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/typeahead/typeahead.js b/src/typeahead/typeahead.js index b1efde2409..10b7778cf7 100644 --- a/src/typeahead/typeahead.js +++ b/src/typeahead/typeahead.js @@ -357,7 +357,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap matches:'=', query:'=', active:'=', - position:'=', + position:'&', select:'&' }, replace:true, diff --git a/template/typeahead/typeahead-popup.html b/template/typeahead/typeahead-popup.html index e1bd0c1c47..9760c154b5 100644 --- a/template/typeahead/typeahead-popup.html +++ b/template/typeahead/typeahead-popup.html @@ -1,5 +1,5 @@ -