diff --git a/src/tooltip/test/tooltip2.spec.js b/src/tooltip/test/tooltip2.spec.js
index fb5956e641..7162d23208 100644
--- a/src/tooltip/test/tooltip2.spec.js
+++ b/src/tooltip/test/tooltip2.spec.js
@@ -102,4 +102,35 @@ describe('tooltip directive', function () {
});
});
+
+ it('should show even after close trigger is called multiple times - issue #1847', function () {
+ var fragment = compileTooltip('Trigger here');
+
+ fragment.find('span').trigger( 'mouseenter' );
+ expect(fragment).toHaveOpenTooltips();
+
+ closeTooltip(fragment.find('span'), null, true);
+ // Close trigger is called again before timer completes
+ // The close trigger can be called any number of times (even after close has already been called)
+ // since users can trigger the hide triggers manually.
+ closeTooltip(fragment.find('span'), null, true);
+ expect(fragment).toHaveOpenTooltips();
+
+ fragment.find('span').trigger( 'mouseenter' );
+ expect(fragment).toHaveOpenTooltips();
+
+ $timeout.flush();
+ expect(fragment).toHaveOpenTooltips();
+ });
+
+ it('should hide even after show trigger is called multiple times', function () {
+ var fragment = compileTooltip('Trigger here');
+
+ fragment.find('span').trigger( 'mouseenter' );
+ fragment.find('span').trigger( 'mouseenter' );
+
+ closeTooltip(fragment.find('span'));
+ expect(fragment).not.toHaveOpenTooltips();
+ });
+
});
\ No newline at end of file
diff --git a/src/tooltip/tooltip.js b/src/tooltip/tooltip.js
index da1b356799..de6d66dc16 100644
--- a/src/tooltip/tooltip.js
+++ b/src/tooltip/tooltip.js
@@ -147,8 +147,12 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
return;
}
if ( scope.tt_popupDelay ) {
- popupTimeout = $timeout( show, scope.tt_popupDelay, false );
- popupTimeout.then(function(reposition){reposition();});
+ // 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, scope.tt_popupDelay, false );
+ popupTimeout.then(function(reposition){reposition();});
+ }
} else {
show()();
}
@@ -163,6 +167,14 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
// Show the tooltip popup element.
function show() {
+ popupTimeout = null;
+
+ // If there is a pending remove transition, we must cancel it, lest the
+ // tooltip be mysteriously removed.
+ if ( transitionTimeout ) {
+ $timeout.cancel( transitionTimeout );
+ transitionTimeout = null;
+ }
// Don't show empty tooltips.
if ( ! scope.tt_content ) {
@@ -171,12 +183,6 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
createTooltip();
- // If there is a pending remove transition, we must cancel it, lest the
- // tooltip be mysteriously removed.
- if ( transitionTimeout ) {
- $timeout.cancel( transitionTimeout );
- }
-
// Set the initial positioning.
tooltip.css({ top: 0, left: 0, display: 'block' });
@@ -206,12 +212,15 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
//if tooltip is going to be shown after delay, we must cancel this
$timeout.cancel( popupTimeout );
+ popupTimeout = 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 ( scope.tt_animation ) {
- transitionTimeout = $timeout(removeTooltip, 500);
+ if (!transitionTimeout) {
+ transitionTimeout = $timeout(removeTooltip, 500);
+ }
} else {
removeTooltip();
}
@@ -229,6 +238,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
}
function removeTooltip() {
+ transitionTimeout = null;
if (tooltip) {
tooltip.remove();
tooltip = null;