2 * jQuery UI Tooltip 1.9.0
5 * Copyright 2012 jQuery Foundation and other contributors
6 * Released under the MIT license.
7 * http://jquery.org/license
9 * http://api.jqueryui.com/tooltip/
14 * jquery.ui.position.js
20 function addDescribedBy( elem
, id
) {
21 var describedby
= (elem
.attr( "aria-describedby" ) || "").split( /\s+/ );
22 describedby
.push( id
);
24 .data( "ui-tooltip-id", id
)
25 .attr( "aria-describedby", $.trim( describedby
.join( " " ) ) );
28 function removeDescribedBy( elem
) {
29 var id
= elem
.data( "ui-tooltip-id" ),
30 describedby
= (elem
.attr( "aria-describedby" ) || "").split( /\s+/ ),
31 index
= $.inArray( id
, describedby
);
33 describedby
.splice( index
, 1 );
36 elem
.removeData( "ui-tooltip-id" );
37 describedby
= $.trim( describedby
.join( " " ) );
39 elem
.attr( "aria-describedby", describedby
);
41 elem
.removeAttr( "aria-describedby" );
45 $.widget( "ui.tooltip", {
49 return $( this ).attr( "title" );
56 collision
: "flipfit flipfit"
73 // IDs of generated tooltips, needed for destroy
77 _setOption: function( key
, value
) {
80 if ( key
=== "disabled" ) {
81 this[ value
? "_disable" : "_enable" ]();
82 this.options
[ key
] = value
;
83 // disable element style changes
87 this._super( key
, value
);
89 if ( key
=== "content" ) {
90 $.each( this.tooltips
, function( id
, element
) {
91 that
._updateContent( element
);
96 _disable: function() {
99 // close open tooltips
100 $.each( this.tooltips
, function( id
, element
) {
101 var event
= $.Event( "blur" );
102 event
.target
= event
.currentTarget
= element
[0];
103 that
.close( event
, true );
106 // remove title attributes to prevent native tooltips
107 this.element
.find( this.options
.items
).andSelf().each(function() {
108 var element
= $( this );
109 if ( element
.is( "[title]" ) ) {
111 .data( "ui-tooltip-title", element
.attr( "title" ) )
112 .attr( "title", "" );
117 _enable: function() {
118 // restore title attributes
119 this.element
.find( this.options
.items
).andSelf().each(function() {
120 var element
= $( this );
121 if ( element
.data( "ui-tooltip-title" ) ) {
122 element
.attr( "title", element
.data( "ui-tooltip-title" ) );
127 open: function( event
) {
128 var target
= $( event
? event
.target
: this.element
)
129 .closest( this.options
.items
);
131 // No element to show a tooltip for
132 if ( !target
.length
) {
136 // If the tooltip is open and we're tracking then reposition the tooltip.
137 // This makes sure that a tracking tooltip doesn't obscure a focused element
138 // if the user was hovering when the element gained focused.
139 if ( this.options
.track
&& target
.data( "ui-tooltip-id" ) ) {
140 this._find( target
).position( $.extend({
142 }, this.options
.position
) );
143 // Stop tracking (#8622)
144 this._off( this.document
, "mousemove" );
148 if ( target
.attr( "title" ) ) {
149 target
.data( "ui-tooltip-title", target
.attr( "title" ) );
152 target
.data( "tooltip-open", true );
154 this._updateContent( target
, event
);
157 _updateContent: function( target
, event
) {
159 contentOption
= this.options
.content
,
162 if ( typeof contentOption
=== "string" ) {
163 return this._open( event
, target
, contentOption
);
166 content
= contentOption
.call( target
[0], function( response
) {
167 // ignore async response if tooltip was closed already
168 if ( !target
.data( "tooltip-open" ) ) {
171 // IE may instantly serve a cached response for ajax requests
172 // delay this call to _open so the other call to _open runs first
173 that
._delay(function() {
174 this._open( event
, target
, response
);
178 this._open( event
, target
, content
);
182 _open: function( event
, target
, content
) {
183 var tooltip
, positionOption
;
188 // Content can be updated multiple times. If the tooltip already
189 // exists, then just update the content and bail.
190 tooltip
= this._find( target
);
191 if ( tooltip
.length
) {
192 tooltip
.find( ".ui-tooltip-content" ).html( content
);
196 // if we have a title, clear it to prevent the native tooltip
197 // we have to check first to avoid defining a title if none exists
198 // (we don't want to cause an element to start matching [title])
200 // We use removeAttr only for key events, to allow IE to export the correct
201 // accessible attributes. For mouse events, set to empty string to avoid
202 // native tooltip showing up (happens only when removing inside mouseover).
203 if ( target
.is( "[title]" ) ) {
204 if ( event
&& event
.type
=== "mouseover" ) {
205 target
.attr( "title", "" );
207 target
.removeAttr( "title" );
211 tooltip
= this._tooltip( target
);
212 addDescribedBy( target
, tooltip
.attr( "id" ) );
213 tooltip
.find( ".ui-tooltip-content" ).html( content
);
215 function position( event
) {
216 positionOption
.of = event
;
217 tooltip
.position( positionOption
);
219 if ( this.options
.track
&& event
&& /^mouse/.test( event
.originalEvent
.type
) ) {
220 positionOption
= $.extend( {}, this.options
.position
);
221 this._on( this.document
, {
224 // trigger once to override element-relative positioning
227 tooltip
.position( $.extend({
229 }, this.options
.position
) );
234 this._show( tooltip
, this.options
.show
);
236 this._trigger( "open", event
, { tooltip
: tooltip
} );
241 keyup: function( event
) {
242 if ( event
.keyCode
=== $.ui
.keyCode
.ESCAPE
) {
243 var fakeEvent
= $.Event(event
);
244 fakeEvent
.currentTarget
= target
[0];
245 this.close( fakeEvent
, true );
251 close: function( event
, force
) {
253 target
= $( event
? event
.currentTarget
: this.element
),
254 tooltip
= this._find( target
);
256 // disabling closes the tooltip, so we need to track when we're closing
257 // to avoid an infinite loop in case the tooltip becomes disabled on close
258 if ( this.closing
) {
262 // don't close if the element has focus
263 // this prevents the tooltip from closing if you hover while focused
265 // we have to check the event type because tabbing out of the document
266 // may leave the element as the activeElement
267 if ( !force
&& event
&& event
.type
!== "focusout" &&
268 this.document
[0].activeElement
=== target
[0] ) {
272 // only set title if we had one before (see comment in _open())
273 if ( target
.data( "ui-tooltip-title" ) ) {
274 target
.attr( "title", target
.data( "ui-tooltip-title" ) );
277 removeDescribedBy( target
);
279 tooltip
.stop( true );
280 this._hide( tooltip
, this.options
.hide
, function() {
282 delete that
.tooltips
[ this.id
];
285 target
.removeData( "tooltip-open" );
286 this._off( target
, "mouseleave focusout keyup" );
287 this._off( this.document
, "mousemove" );
290 this._trigger( "close", event
, { tooltip
: tooltip
} );
291 this.closing
= false;
294 _tooltip: function( element
) {
295 var id
= "ui-tooltip-" + increments
++,
296 tooltip
= $( "<div>" )
301 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
302 ( this.options
.tooltipClass
|| "" ) );
304 .addClass( "ui-tooltip-content" )
305 .appendTo( tooltip
);
306 tooltip
.appendTo( this.document
[0].body
);
307 if ( $.fn
.bgiframe
) {
310 this.tooltips
[ id
] = element
;
314 _find: function( target
) {
315 var id
= target
.data( "ui-tooltip-id" );
316 return id
? $( "#" + id
) : $();
319 _destroy: function() {
322 // close open tooltips
323 $.each( this.tooltips
, function( id
, element
) {
324 // Delegate to close method to handle common cleanup
325 var event
= $.Event( "blur" );
326 event
.target
= event
.currentTarget
= element
[0];
327 that
.close( event
, true );
329 // Remove immediately; destroying an open tooltip doesn't use the
331 $( "#" + id
).remove();
334 if ( element
.data( "ui-tooltip-title" ) ) {
335 element
.attr( "title", element
.data( "ui-tooltip-title" ) );
336 element
.removeData( "ui-tooltip-title" );