From 88291ffc4d6a5f4762ae65e42de607f5588101dd Mon Sep 17 00:00:00 2001 From: Marco Ziech Date: Mon, 23 Feb 2015 19:33:01 -0500 Subject: [PATCH] Tooltip: Register event handlers before content is loaded Fixes #8740 Closes gh-1053 Closes gh-1456 (cherry picked from commit c4e367bb31c21d7c8b2701c626a92a2f13be5af4) --- tests/unit/tooltip/tooltip_options.js | 22 ++++++++++++++++++++++ ui/tooltip.js | 26 +++++++++++++++++++------- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/tests/unit/tooltip/tooltip_options.js b/tests/unit/tooltip/tooltip_options.js index 17f0a423775..a07f65199ab 100644 --- a/tests/unit/tooltip/tooltip_options.js +++ b/tests/unit/tooltip/tooltip_options.js @@ -71,6 +71,28 @@ asyncTest( "content: sync + async callback", function() { }).tooltip( "open" ); }); +// http://bugs.jqueryui.com/ticket/8740 +asyncTest( "content: async callback loses focus before load", function() { + expect( 1 ); + + var element = $( "#tooltipped1" ).tooltip({ + content: function( response ) { + setTimeout(function() { + element.trigger( "mouseleave" ); + setTimeout(function() { + response( "sometext" ); + setTimeout(function() { + ok( !$( "#" + element.data( "ui-tooltip-id" ) ).is( ":visible" ), + "Tooltip should not display" ); + start(); + }); + }); + }); + } + }); + element.trigger( "mouseover" ); +}); + test( "content: change while open", function() { expect( 2 ) ; var element = $( "#tooltipped1" ).tooltip({ diff --git a/ui/tooltip.js b/ui/tooltip.js index 73844c0eae3..8408f6781fb 100644 --- a/ui/tooltip.js +++ b/ui/tooltip.js @@ -194,6 +194,7 @@ return $.widget( "ui.tooltip", { }); } + this._registerCloseHandlers( event, target ); this._updateContent( target, event ); }, @@ -208,13 +209,16 @@ return $.widget( "ui.tooltip", { } content = contentOption.call( target[0], function( response ) { - // ignore async response if tooltip was closed already - if ( !target.data( "ui-tooltip-open" ) ) { - return; - } + // IE may instantly serve a cached response for ajax requests // delay this call to _open so the other call to _open runs first that._delay(function() { + + // Ignore async response if tooltip was closed already + if ( !target.data( "ui-tooltip-open" ) ) { + return; + } + // jQuery creates a special event for focusin when it doesn't // exist natively. To improve performance, the native event // object is reused and the type is changed. Therefore, we can't @@ -232,7 +236,7 @@ return $.widget( "ui.tooltip", { }, _open: function( event, target, content ) { - var tooltipData, tooltip, events, delayedShow, a11yContent, + var tooltipData, tooltip, delayedShow, a11yContent, positionOption = $.extend( {}, this.options.position ); if ( !content ) { @@ -314,8 +318,10 @@ return $.widget( "ui.tooltip", { } this._trigger( "open", event, { tooltip: tooltip } ); + }, - events = { + _registerCloseHandlers: function( event, target ) { + var events = { keyup: function( event ) { if ( event.keyCode === $.ui.keyCode.ESCAPE ) { var fakeEvent = $.Event(event); @@ -329,7 +335,7 @@ return $.widget( "ui.tooltip", { // tooltips will handle this in destroy. if ( target[ 0 ] !== this.element[ 0 ] ) { events.remove = function() { - this._removeTooltip( tooltip ); + this._removeTooltip( this._find( target ).tooltip ); }; } @@ -350,6 +356,12 @@ return $.widget( "ui.tooltip", { // The tooltip may already be closed if ( !tooltipData ) { + + // We set ui-tooltip-open immediately upon open (in open()), but only set the + // additional data once there's actually content to show (in _open()). So even if the + // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in + // the period between open() and _open(). + target.removeData( "ui-tooltip-open" ); return; }