diff --git a/src/tooltip/docs/readme.md b/src/tooltip/docs/readme.md index 0da8848f9a..5b7e993325 100644 --- a/src/tooltip/docs/readme.md +++ b/src/tooltip/docs/readme.md @@ -20,6 +20,7 @@ will display: - `tooltip-animation`: Should it fade in and out? Defaults to "true". - `tooltip-popup-delay`: For how long should the user have to have the mouse over the element before the tooltip shows (in milliseconds)? Defaults to 0. +- `tooltip--close-popup-delay`: For how long should the tooltip remained open? - `tooltip-trigger`: What should trigger a show of the tooltip? Supports a space separated list of event names. Note: this attribute is no longer observable. See `tooltip-enable`. - `tooltip-enable`: Is it enabled? It will enable or disable the configured @@ -63,6 +64,7 @@ methods are available: placement: 'top', animation: true, popupDelay: 0, + popupCloseDelay: 500, appendToBody: false diff --git a/src/tooltip/test/tooltip.spec.js b/src/tooltip/test/tooltip.spec.js index a8c731a42f..018c848cb2 100644 --- a/src/tooltip/test/tooltip.spec.js +++ b/src/tooltip/test/tooltip.spec.js @@ -365,6 +365,60 @@ describe('tooltip', function() { })); }); + describe('with specified popup close delay', function() { + var $timeout; + beforeEach(inject(function($compile, _$timeout_) { + $timeout = _$timeout_; + scope.delay = '1000'; + elm = $compile(angular.element( + 'Selector Text' + ))(scope); + elmScope = elm.scope(); + tooltipScope = elmScope.$$childTail; + scope.$digest(); + })); + + it('should close after timeout', function() { + trigger(elm, 'mouseenter'); + expect(tooltipScope.isOpen).toBe(true); + trigger(elm, 'mouseleave'); + $timeout.flush(); + expect(tooltipScope.isOpen).toBe(false); + }); + // + it('should use default popup close delay if specified delay is not a number and close after delay', function() { + scope.delay = 'text1000'; + scope.$digest(); + trigger(elm, 'mouseenter'); + expect(tooltipScope.popupCloseDelay).toBe(500); + expect(tooltipScope.isOpen).toBe(true); + trigger(elm, 'mouseleave'); + $timeout.flush(); + expect(tooltipScope.isOpen).toBe(false); + }); + + it('should open when not disabled after being disabled and close after delay - issue #4204', function() { + trigger(elm, 'mouseenter'); + expect(tooltipScope.isOpen).toBe(true); + + elmScope.disabled = true; + elmScope.$digest(); + + $timeout.flush(500); + expect(tooltipScope.isOpen).toBe(false); + + elmScope.disabled = false; + elmScope.$digest(); + + trigger(elm, 'mouseenter'); + + expect(tooltipScope.isOpen).toBe(true); + trigger(elm, 'mouseleave'); + $timeout.flush(); + expect(tooltipScope.isOpen).toBe(false); + }); + }); + describe('with an is-open attribute', function() { beforeEach(inject(function ($compile) { scope.isOpen = false; diff --git a/src/tooltip/tooltip.js b/src/tooltip/tooltip.js index bc8c12e23d..d3baaf0797 100644 --- a/src/tooltip/tooltip.js +++ b/src/tooltip/tooltip.js @@ -15,6 +15,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s placement: 'top', animation: true, popupDelay: 0, + popupCloseDelay: 500, useContentExp: false }; @@ -265,7 +266,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s // FIXME: this is a placeholder for a port of the transitions library. if (ttScope.animation) { if (!transitionTimeout) { - transitionTimeout = $timeout(removeTooltip, 500); + transitionTimeout = $timeout(removeTooltip, ttScope.popupCloseDelay); } } else { removeTooltip(); @@ -321,7 +322,9 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s ttScope.placement = angular.isDefined(attrs[prefix + 'Placement']) ? attrs[prefix + 'Placement'] : options.placement; var delay = parseInt(attrs[prefix + 'PopupDelay'], 10); + var closeDelay = parseInt(attrs[prefix + 'PopupCloseDelay'], 10); ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay; + ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay; } ttScope.contentExp = function() {