Skip to content

Commit 56f0302

Browse files
RobJacobsaroop
authored andcommitted
fix(tooltip): delay timeouts
The show and hide delay timeouts where not getting cancelled correctly resulting in tooltips staying open when both popup and popup-close delays were in use. Closes angular-ui#4621 Fixes angular-ui#4618
1 parent 4525f3a commit 56f0302

File tree

2 files changed

+57
-30
lines changed

2 files changed

+57
-30
lines changed

src/tooltip/test/tooltip.spec.js

+23
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,29 @@ describe('tooltip', function() {
419419
});
420420
});
421421

422+
describe('with specified popup and popup close delay', function() {
423+
var $timeout;
424+
beforeEach(inject(function($compile, _$timeout_) {
425+
$timeout = _$timeout_;
426+
scope.delay = '1000';
427+
elm = $compile(angular.element(
428+
'<span uib-tooltip="tooltip text" tooltip-popup-close-delay="{{delay}}" tooltip-popup-close-delay="{{delay}}" ng-disabled="disabled">Selector Text</span>'
429+
))(scope);
430+
elmScope = elm.scope();
431+
tooltipScope = elmScope.$$childTail;
432+
scope.$digest();
433+
}));
434+
435+
it('should not open if mouseleave before timeout', function() {
436+
trigger(elm, 'mouseenter');
437+
$timeout.flush(500);
438+
trigger(elm, 'mouseleave');
439+
$timeout.flush();
440+
441+
expect(tooltipScope.isOpen).toBe(false);
442+
});
443+
});
444+
422445
describe('with an is-open attribute', function() {
423446
beforeEach(inject(function ($compile) {
424447
scope.isOpen = false;

src/tooltip/tooltip.js

+34-30
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
192192
return;
193193
}
194194

195+
cancelHide();
195196
prepareTooltip();
196197

197198
if (ttScope.popupDelay) {
@@ -206,30 +207,21 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
206207
}
207208

208209
function hideTooltipBind() {
210+
cancelShow();
211+
209212
if (ttScope.popupCloseDelay) {
210-
hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
213+
if (!hideTimeout) {
214+
hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
215+
}
211216
} else {
212217
hide();
213218
}
214219
}
215220

216221
// Show the tooltip popup element.
217222
function show() {
218-
if (showTimeout) {
219-
$timeout.cancel(showTimeout);
220-
showTimeout = null;
221-
}
222-
223-
// If there is a pending remove transition, we must cancel it, lest the
224-
// tooltip be mysteriously removed.
225-
if (hideTimeout) {
226-
$timeout.cancel(hideTimeout);
227-
hideTimeout = null;
228-
}
229-
if (transitionTimeout) {
230-
$timeout.cancel(transitionTimeout);
231-
transitionTimeout = null;
232-
}
223+
cancelShow();
224+
cancelHide();
233225

234226
// Don't show empty tooltips.
235227
if (!ttScope.content) {
@@ -246,13 +238,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
246238
});
247239
}
248240

249-
// Hide the tooltip popup element.
250-
function hide() {
251-
if (!ttScope) {
252-
return;
253-
}
254-
255-
//if tooltip is going to be shown after delay, we must cancel this
241+
function cancelShow() {
256242
if (showTimeout) {
257243
$timeout.cancel(showTimeout);
258244
showTimeout = null;
@@ -262,6 +248,16 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
262248
$timeout.cancel(positionTimeout);
263249
positionTimeout = null;
264250
}
251+
}
252+
253+
// Hide the tooltip popup element.
254+
function hide() {
255+
cancelShow();
256+
cancelHide();
257+
258+
if (!ttScope) {
259+
return;
260+
}
265261

266262
// First things first: we don't show it anymore.
267263
ttScope.$evalAsync(function() {
@@ -281,6 +277,17 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
281277
});
282278
}
283279

280+
function cancelHide() {
281+
if (hideTimeout) {
282+
$timeout.cancel(hideTimeout);
283+
hideTimeout = null;
284+
}
285+
if (transitionTimeout) {
286+
$timeout.cancel(transitionTimeout);
287+
transitionTimeout = null;
288+
}
289+
}
290+
284291
function createTooltip() {
285292
// There can only be one tooltip element per directive shown at once.
286293
if (tooltip) {
@@ -349,9 +356,8 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
349356
* Observe the relevant attributes.
350357
*/
351358
attrs.$observe('disabled', function(val) {
352-
if (showTimeout && val) {
353-
$timeout.cancel(showTimeout);
354-
showTimeout = null;
359+
if (val) {
360+
cancelShow();
355361
}
356362

357363
if (val && ttScope.isOpen) {
@@ -495,10 +501,8 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.s
495501

496502
// Make sure tooltip is destroyed and removed.
497503
scope.$on('$destroy', function onDestroyTooltip() {
498-
$timeout.cancel(transitionTimeout);
499-
$timeout.cancel(showTimeout);
500-
$timeout.cancel(hideTimeout);
501-
$timeout.cancel(positionTimeout);
504+
cancelShow();
505+
cancelHide();
502506
unregisterTriggers();
503507
removeTooltip();
504508
openedTooltips.remove(ttScope);

0 commit comments

Comments
 (0)