This is a rather hackish solution, but here goes the temporary fix which I just found. edit: after having finished the 1st cross-browser solution below, it is not so hackish at all. The #1, #4 and #2 solution listed below should be usable.
jQuery Event objects have a hidden originalEvent
property, which in the question's case is a references a native mouseover
event. Therefore event.originalEvent.target
can be used for both Chrome and Firefox.
open: function(e, ui) {
var el = e.originalEvent.target;
if (el.offsetWidth === el.scrollWidth) {
ui.tooltip.hide();
}
}
Bin
When old IE support is concerned, you will have to use event.srcElement
when event.target
is not present.
var el = e.originalEvent.target || e.originalEvent.srcElement;
Bin
#1 Cross-browser solution
Finally, when there are nested elements inside of an element that triggers the tooltip, you will have to monkeypatch it by using the .closest()
method passing in the same filter as your tooltip's delegation selector (items
option, default to [title]:not([disabled])
as of UI 1.10.2):
var el = $(e.originalEvent.target || e.originalEvent.srcElement).closest($(this).tooltip('option', 'items'))[0];
Bin
This is basically what the Tooltip Widget does internally as shown here.
#2 Alternative cross-browser solution
Alternative solution that doesn't require so many workarounds by using a simple DOM query:
var el = $('[aria-describedby="'+ui.tooltip[0].id+'"]')[0];
Bin
#3 Internal methods abuse
This should not be used, but by overriding the internal _open
method you get access to a target
jQuery object which contains the event's target element passed as parameter to it. Problem is, then you don't have access to its tooltip
widget not even through .tooltip('widget')
as it is "not created" yet though already present in the DOM. You can work around it using the internal _find
method which will perform a DOM query by ID and thus you can hide
it right after the show
animation would kick in, while its live cycle is not affected - it will be there and removed on mouseleave
as usual, but will have display:none
along all this cycle.
var bk_open = $.ui.tooltip.prototype._open;
$.ui.tooltip.prototype._open = function(event, target, content) {
bk_open.apply(this, arguments);
if (target[0].offsetWidth === target[0].scrollWidth) {
this._find(target).hide();
}
};
$(document).tooltip();
Bin
That DOM query with _find
is rather unnecessary, so we can also extend the internal _tooltip
method which returns a jQuery object containing the tooltip
element so we can use JS's lexical scope to save a reference to the tooltip element before our overridden _open
executes:
var tooltipproto = $.ui.tooltip.prototype,
bk_open = tooltipproto._open,
bk_tooltip = tooltipproto._tooltip,
$tooltip;
tooltipproto._open = function(event, target, content) {
bk_open.apply(this, arguments);
if (target[0].offsetWidth === target[0].scrollWidth) {
$tooltip.hide();
}
};
tooltipproto._tooltip = function(element) {
return ($tooltip = bk_tooltip.apply(this, arguments));
};
$(document).tooltip();
Bin
Of course, as the _tooltip
internal methods receives the target
as parameter and returns the tooltip
, one could do the entire operation just overriding this method, but as the tooltip
is show
n after this method returns, this would require a setTimeout(fn, 0)
possibly causing an undesirable flicker effect.
This is overly hackish, cumbersome and verbose for something so simple though.
#4 Clean solution
"Clean" as in not using undocumented methods nor attributes nor prototype overriding nor DOM queries. Back to the first snippet, all we needed was a reference to the element that triggered the tooltip. This element is referenced by the this
inside of the content
function which is called prior to the open
handler, thus we can use lexical scope to store that reference a level above:
var el;
$(document).tooltip({
content: function() {
el = this;
return this.title;
},
open: function(e, ui) {
if (el.offsetWidth === el.scrollWidth) {
ui.tooltip.hide();
}
}
});
Bin
Note that my custom content
function in the snippet above removes jQuery's default HTML tags stripping (because I like using HTML inside the tooltips), but this may be an issue if you're dynamically populating the title attribute with user-inputted data, so in case you want to keep the original content
handler's functionality:
var el,
bk_content = $.ui.tooltip.prototype.options.content;
$(document).tooltip({
content: function() {
el = this;
return bk_content.apply(this, arguments);
},
open: function(e, ui) {
if (el.offsetWidth === el.scrollWidth) {
ui.tooltip.hide();
}
}
});
Bin
I'll open a ticket on jQuery UI bugtracker requesting this feature to be implemented meanwhile. Here's it:
Tooltip: Expose element which triggered the tooltip inside open/close handlers