diff options
author | jzaefferer <joern.zaefferer@gmail.com> | 2011-04-13 14:01:46 +0200 |
---|---|---|
committer | jzaefferer <joern.zaefferer@gmail.com> | 2011-04-13 14:01:46 +0200 |
commit | 67d49f593bb34f10751421a51c8e13d42bc1b16e (patch) | |
tree | cca067334b672af9a8d1b85dbc008a04e0c8c63f | |
parent | bc65675330e758c406098e929ee8b4c1741c87fd (diff) | |
download | jquery-ui-67d49f593bb34f10751421a51c8e13d42bc1b16e.tar.gz jquery-ui-67d49f593bb34f10751421a51c8e13d42bc1b16e.zip |
Overhaul tooltip implementation. Avoid queuing and other problems by
creating the tooltip element on the fly, never reusing it.
Use aria-describedby attribute to find the associated tooltip again.
Allows customizing animations much easier (just replace fadeIn/fadeOut),
still open.
Updated demos and visual test to replace now-missing .widget() method.
Added tooltipClass for that.
-rw-r--r-- | demos/tooltip/custom-animation.html | 7 | ||||
-rw-r--r-- | demos/tooltip/index.html | 1 | ||||
-rw-r--r-- | demos/tooltip/tracking.html | 13 | ||||
-rw-r--r-- | tests/visual/tooltip/tooltip.html | 25 | ||||
-rw-r--r-- | ui/jquery.ui.tooltip.js | 130 |
5 files changed, 95 insertions, 81 deletions
diff --git a/demos/tooltip/custom-animation.html b/demos/tooltip/custom-animation.html index a9d0df66e..a9745a062 100644 --- a/demos/tooltip/custom-animation.html +++ b/demos/tooltip/custom-animation.html @@ -11,12 +11,15 @@ <link type="text/css" href="../demos.css" rel="stylesheet" /> <script type="text/javascript"> $(function() { + // TODO overhaul this with custom animation API $(".demo").tooltip({ open: function() { - $(this).tooltip("widget").stop(false, true).hide().slideDown(); + $(".ui-tooltip").stop(false, true).hide().slideDown(); }, close: function() { - $(this).tooltip("widget").stop(false, true).show().slideUp(); + $(".ui-tooltip").stop(false, false).show().slideUp(function() { + $(this).remove(); + }); } }); }); diff --git a/demos/tooltip/index.html b/demos/tooltip/index.html index 6bc9c1e5c..3563350c5 100644 --- a/demos/tooltip/index.html +++ b/demos/tooltip/index.html @@ -14,6 +14,7 @@ <li><a href="tracking.html">Track the mouse</a></li> <li><a href="custom-animation.html">Custom animation</a></li> <li><a href="delegation-mixbag.html">Delegation Mixbag</a></li> + <li><a href="lots.html">Lots</a></li> </ul> </div> diff --git a/demos/tooltip/tracking.html b/demos/tooltip/tracking.html index e3bb19e74..dd5dc9d92 100644 --- a/demos/tooltip/tracking.html +++ b/demos/tooltip/tracking.html @@ -13,12 +13,11 @@ $(function() { $(".demo").tooltip({ open: function() { - var tooltip = $(this).tooltip("widget"); - $(document).mousemove(function(event) { - tooltip.position({ - my: "left center", - at: "right center", - offset: "25 25", + var tooltip = $( ".ui-tooltip" ); + $(document).mousemove(function( event ) { + tooltip.position( { + my: "left+25 center", + at: "right+25 center", of: event }); }) @@ -26,7 +25,7 @@ .mousemove(); }, close: function() { - $(document).unbind("mousemove"); + $(document).unbind( "mousemove" ); } }); }); diff --git a/tests/visual/tooltip/tooltip.html b/tests/visual/tooltip/tooltip.html index 538b43804..70c850b60 100644 --- a/tests/visual/tooltip/tooltip.html +++ b/tests/visual/tooltip/tooltip.html @@ -10,7 +10,9 @@ <script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.button.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.tooltip.js"></script> + <!-- <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script> + --> <script type="text/javascript"> $(function() { $.fn.themeswitcher && $('<div/>').css({ @@ -18,20 +20,22 @@ right: 10, top: 10 }).appendTo(document.body).themeswitcher(); - + function enable() { // default $("#context1, form, #childish").tooltip(); // custom class, replaces ui-widget-content - $("#context2").tooltip().each(function() { - $(this).tooltip("widget").addClass("ui-widget-header"); - }) - $("#right1").tooltip().tooltip("widget").addClass("ui-state-error"); + $("#context2").tooltip({ + tooltipClass: "ui-widget-header" + }); + $("#right1").tooltip({ + tooltipClass: "ui-state-error" + }); // synchronous content $("#footnotes").tooltip({ - items: "[href^=#]", + items: "[href^='#']", content: function() { return $($(this).attr("href")).html(); } @@ -64,12 +68,13 @@ // custom position $("#right2").tooltip({ + tooltipClass: "ui-state-highlight", position: { my: "center top", at: "center bottom", offset: "0 10" } - }).tooltip("widget").addClass("ui-state-highlight"); + }); $("#button1").button(); $("#button2").button({ @@ -94,12 +99,12 @@ enable(); $("#disable").toggle(function() { - $("*").tooltip("disable"); + $(":ui-tooltip").tooltip("disable"); }, function() { - $("*").tooltip("enable"); + $(":ui-tooltip").tooltip("enable"); }); $("#toggle").toggle(function() { - $("*").tooltip("destroy"); + $(":ui-tooltip").tooltip("destroy"); }, function() { enable(); }); diff --git a/ui/jquery.ui.tooltip.js b/ui/jquery.ui.tooltip.js index 9b4d52bd1..534b3c947 100644 --- a/ui/jquery.ui.tooltip.js +++ b/ui/jquery.ui.tooltip.js @@ -18,9 +18,10 @@ var increments = 0; $.widget("ui.tooltip", { options: { + tooltipClass: null, items: "[title]", content: function() { - return $(this).attr("title"); + return $( this ).attr( "title" ); }, position: { my: "left center", @@ -29,25 +30,10 @@ $.widget("ui.tooltip", { } }, _create: function() { - var self = this; - this.tooltip = $("<div></div>") - .attr("id", "ui-tooltip-" + increments++) - .attr("role", "tooltip") - .attr("aria-hidden", "true") - .addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content") - .appendTo(document.body) - .hide(); - this.tooltipContent = $("<div></div>") - .addClass("ui-tooltip-content") - .appendTo(this.tooltip); - this.opacity = this.tooltip.css("opacity"); - this.element - .bind("focus.tooltip mouseover.tooltip", function(event) { - self.open( event ); - }) - .bind("blur.tooltip mouseout.tooltip", function(event) { - self.close( event ); - }); + this._bind( { + mouseover: "open", + focusin: "open" + }); }, enable: function() { @@ -55,34 +41,28 @@ $.widget("ui.tooltip", { }, disable: function() { + // only set option, disable element style changes this.options.disabled = true; }, - _destroy: function() { - this.tooltip.remove(); - }, - - widget: function() { - return this.element.pushStack(this.tooltip.get()); - }, - open: function(event) { var target = $(event && event.target || this.element).closest(this.options.items); if ( !target.length ) { return; } - // already visible? possible when both focus and mouseover events occur - if (this.current && this.current[0] == target[0]) - return; var self = this; - this.current = target; - this.currentTitle = target.attr("title"); + if ( !target.data("tooltip-title") ) { + target.data("tooltip-title", target.attr("title")); + } var content = this.options.content.call(target[0], function(response) { // IE may instantly serve a cached response, need to give it a chance to finish with _open before that setTimeout(function() { - // ignore async responses that come in after the tooltip is already hidden - if (self.current == target) + // when undefined, it got removeAttr, then ignore (ajax response) + // intially its an empty string, so not undefined + // TODO is there a better approach to enable ajax tooltips to have two updates? + if (target.attr( "aria-describedby" ) !== undefined) { self._open(event, target, response); + } }, 13); }); if (content) { @@ -90,48 +70,74 @@ $.widget("ui.tooltip", { } }, - _open: function(event, target, content) { - if (!content) + _open: function( event, target, content ) { + if ( !content ) return; - + target.attr("title", ""); - - if (this.options.disabled) + + if ( this.options.disabled ) return; - - this.tooltipContent.html(content); - this.tooltip.css({ - top: 0, - left: 0 - }).show().position( $.extend({ + + // ajaxy tooltip can update an existing one + var tooltip = this._find( target ); + if (!tooltip.length) { + tooltip = this._tooltip(); + target.attr( "aria-describedby", tooltip.attr( "id" ) ); + } + tooltip.find(".ui-tooltip-content").html( content ); + tooltip.position( $.extend({ of: target - }, this.options.position )).hide(); - - this.tooltip.attr("aria-hidden", "false"); - target.attr("aria-describedby", this.tooltip.attr("id")); + }, this.options.position ) ).hide(); + - this.tooltip.stop(false, true).fadeIn(); + tooltip.fadeIn(); this._trigger( "open", event ); + + this._bind( target, { + mouseleave: "close", + blur: "close" + }); }, - close: function(event) { - if (!this.current) - return; - - var current = this.current; - this.current = null; - current.attr("title", this.currentTitle); + close: function( event ) { + var target = $( event && event.currentTarget || this.element ); + target.attr( "title", target.data( "tooltip-title" ) ); - if (this.options.disabled) + if ( this.options.disabled ) return; + + var tooltip = this._find( target ); + target.removeAttr( "aria-describedby" ); - current.removeAttr("aria-describedby"); - this.tooltip.attr("aria-hidden", "true"); + tooltip.fadeOut( function() { + $( this ).remove(); + }); - this.tooltip.stop(false, true).fadeOut(); + target.unbind( "mouseleave.tooltip blur.tooltip" ); this._trigger( "close", event ); + }, + + _tooltip: function() { + var tooltip = $( "<div></div>" ) + .attr( "id", "ui-tooltip-" + increments++ ) + .attr( "role", "tooltip" ) + .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content" ); + if (this.options.tooltipClass) { + tooltip.addClass(this.options.tooltipClass); + } + $( "<div></div>" ) + .addClass( "ui-tooltip-content" ) + .appendTo( tooltip ); + tooltip.appendTo( document.body ); + return tooltip; + }, + + _find: function( target ) { + var id = target.attr( "aria-describedby" ); + return id ? $( document.getElementById( id ) ) : $(); } }); |