Skip to content

Commit

Permalink
fix(tooltip): popup close delay not respected
Browse files Browse the repository at this point in the history
Under PR angular-ui#4455 the timeout for the popup close delay
was impacted by the evalAsync for setting the isOpen
value. Moved the popup close delay timeout to the
hideTooltipBind method so the hide method will now
get called after the close popup delay. This will
also ensure if the show method is called and the
close timeout is cancelled, the isOpen property
will not get toggled.

Closes angular-ui#4597
Fixes angular-ui#4567
  • Loading branch information
RobJacobs authored and aroop committed Oct 16, 2015
1 parent f8e80ee commit 385a20a
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 40 deletions.
2 changes: 2 additions & 0 deletions src/popover/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ will display:
- `popover-animation`: Should it fade in and out? Defaults to "true".
- `popover-popup-delay`: For how long should the user have to have the mouse
over the element before the popover shows (in milliseconds)? Defaults to 0.
- `popover-close-popup-delay`: For how long should the popover remain open
after the close trigger event? Defaults to 0.
- `popover-trigger`: What should trigger the show of the popover? See the
`tooltip` directive for supported values.
- `popover-append-to-body`: Should the tooltip be appended to `$body` instead of
Expand Down
4 changes: 3 additions & 1 deletion src/tooltip/docs/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
pharetra convallis posuere morbi leo urna,
<a href="#" tooltip-animation="false" uib-tooltip="I don't fade. :-(">fading</a>
at elementum eu, facilisis sed odio morbi quis commodo odio. In cursus
<a href="#" tooltip-popup-delay='1000' uib-tooltip='appears with delay'>delayed</a> turpis massa tincidunt dui ut.
<a href="#" tooltip-popup-delay='1000' uib-tooltip='appears with delay'>show delay</a>
turpis massa tincidunt dui ut. In cursus
<a href="#" tooltip-popup-close-delay='1000' uib-tooltip='hides with delay'>hide delay</a>
<a href="#" uib-tooltip-template="'myTooltipTemplate.html'">Custom template</a>
nunc sed velit dignissim sodales ut eu sem integer vitae. Turpis egestas
</p>
Expand Down
3 changes: 2 additions & 1 deletion src/tooltip/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ 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-close-popup-delay`: For how long should the tooltip remain open
after the close trigger event? Defaults to 0.
- `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
Expand Down
4 changes: 2 additions & 2 deletions src/tooltip/test/tooltip.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,11 +386,11 @@ describe('tooltip', function() {
expect(tooltipScope.isOpen).toBe(false);
});

it('should use default popup close delay if specified delay is not a number and close after delay', function() {
it('should use default popup close delay if specified delay is not a number and close immediately', function() {
scope.delay = 'text1000';
scope.$digest();
trigger(elm, 'mouseenter');
expect(tooltipScope.popupCloseDelay).toBe(500);
expect(tooltipScope.popupCloseDelay).toBe(0);
expect(tooltipScope.isOpen).toBe(true);
trigger(elm, 'mouseleave');
$timeout.flush();
Expand Down
87 changes: 51 additions & 36 deletions src/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
placement: 'top',
animation: true,
popupDelay: 0,
popupCloseDelay: 500,
popupCloseDelay: 0,
useContentExp: false
};

Expand Down Expand Up @@ -135,7 +135,8 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
var tooltip;
var tooltipLinkedScope;
var transitionTimeout;
var popupTimeout;
var showTimeout;
var hideTimeout;
var positionTimeout;
var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
var triggers = getTriggers(undefined);
Expand Down Expand Up @@ -196,27 +197,35 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
if (ttScope.popupDelay) {
// Do nothing if the tooltip was already scheduled to pop-up.
// This happens if show is triggered multiple times before any hide is triggered.
if (!popupTimeout) {
popupTimeout = $timeout(show, ttScope.popupDelay, false);
if (!showTimeout) {
showTimeout = $timeout(show, ttScope.popupDelay, false);
}
} else {
show();
}
}

function hideTooltipBind() {
hide();
if (ttScope.popupCloseDelay) {
hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
} else {
hide();
}
}

// Show the tooltip popup element.
function show() {
if (popupTimeout) {
$timeout.cancel(popupTimeout);
popupTimeout = null;
if (showTimeout) {
$timeout.cancel(showTimeout);
showTimeout = null;
}

// If there is a pending remove transition, we must cancel it, lest the
// tooltip be mysteriously removed.
if (hideTimeout) {
$timeout.cancel(hideTimeout);
hideTimeout = null;
}
if (transitionTimeout) {
$timeout.cancel(transitionTimeout);
transitionTimeout = null;
Expand All @@ -232,10 +241,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
// And show the tooltip.
ttScope.$evalAsync(function() {
ttScope.isOpen = true;
if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
isOpenParse.assign(ttScope.origScope, ttScope.isOpen);
}

assignIsOpen(true);
positionTooltip();
});
}
Expand All @@ -246,31 +252,33 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
return;
}

//if tooltip is going to be shown after delay, we must cancel this
if (showTimeout) {
$timeout.cancel(showTimeout);
showTimeout = null;
}

if (positionTimeout) {
$timeout.cancel(positionTimeout);
positionTimeout = null;
}

// First things first: we don't show it anymore.
ttScope.$evalAsync(function() {
ttScope.isOpen = false;
if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
isOpenParse.assign(ttScope.origScope, ttScope.isOpen);
assignIsOpen(false);
// And now we remove it from the DOM. However, if we have animation, we
// need to wait for it to expire beforehand.
// FIXME: this is a placeholder for a port of the transitions library.
// The fade transition in TWBS is 150ms.
if (ttScope.animation) {
if (!transitionTimeout) {
transitionTimeout = $timeout(removeTooltip, 150, false);
}
} else {
removeTooltip();
}
});

//if tooltip is going to be shown after delay, we must cancel this
$timeout.cancel(popupTimeout);
popupTimeout = null;

$timeout.cancel(positionTimeout);
positionTimeout = null;

// And now we remove it from the DOM. However, if we have animation, we
// need to wait for it to expire beforehand.
// FIXME: this is a placeholder for a port of the transitions library.
if (ttScope.animation) {
if (!transitionTimeout) {
transitionTimeout = $timeout(removeTooltip, ttScope.popupCloseDelay);
}
} else {
removeTooltip();
}
}

function createTooltip() {
Expand Down Expand Up @@ -327,6 +335,12 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay;
}

function assignIsOpen(isOpen) {
if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
isOpenParse.assign(scope, isOpen);
}
}

ttScope.contentExp = function() {
return ttScope.content;
};
Expand All @@ -335,9 +349,9 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
* Observe the relevant attributes.
*/
attrs.$observe('disabled', function(val) {
if (popupTimeout && val) {
$timeout.cancel(popupTimeout);
popupTimeout = null;
if (showTimeout && val) {
$timeout.cancel(showTimeout);
showTimeout = null;
}

if (val && ttScope.isOpen) {
Expand Down Expand Up @@ -482,7 +496,8 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
// Make sure tooltip is destroyed and removed.
scope.$on('$destroy', function onDestroyTooltip() {
$timeout.cancel(transitionTimeout);
$timeout.cancel(popupTimeout);
$timeout.cancel(showTimeout);
$timeout.cancel(hideTimeout);
$timeout.cancel(positionTimeout);
unregisterTriggers();
removeTooltip();
Expand Down

0 comments on commit 385a20a

Please sign in to comment.