aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjzaefferer <joern.zaefferer@gmail.com>2011-04-13 14:01:46 +0200
committerjzaefferer <joern.zaefferer@gmail.com>2011-04-13 14:01:46 +0200
commit67d49f593bb34f10751421a51c8e13d42bc1b16e (patch)
treecca067334b672af9a8d1b85dbc008a04e0c8c63f
parentbc65675330e758c406098e929ee8b4c1741c87fd (diff)
downloadjquery-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.html7
-rw-r--r--demos/tooltip/index.html1
-rw-r--r--demos/tooltip/tracking.html13
-rw-r--r--tests/visual/tooltip/tooltip.html25
-rw-r--r--ui/jquery.ui.tooltip.js130
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 ) ) : $();
}
});