jquery-ui/ui/jquery.ui.tooltip.js

295 lines
7.4 KiB
JavaScript
Raw Normal View History

/*!
* jQuery UI Tooltip @VERSION
*
2012-03-08 15:53:08 +00:00
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Depends:
* jquery.ui.core.js
* jquery.ui.widget.js
* jquery.ui.position.js
*/
2011-05-28 00:05:20 +00:00
(function( $ ) {
var increments = 0;
function addDescribedBy( elem, id ) {
var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
describedby.push( id );
elem
.data( "ui-tooltip-id", id )
.attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
}
function removeDescribedBy( elem ) {
var id = elem.data( "ui-tooltip-id" ),
describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
index = $.inArray( id, describedby );
if ( index !== -1 ) {
describedby.splice( index, 1 );
}
elem.removeData( "ui-tooltip-id" );
describedby = $.trim( describedby.join( " " ) );
if ( describedby ) {
elem.attr( "aria-describedby", describedby );
} else {
elem.removeAttr( "aria-describedby" );
}
}
2011-05-28 15:43:57 +00:00
$.widget( "ui.tooltip", {
version: "@VERSION",
options: {
content: function() {
return $( this ).attr( "title" );
},
hide: true,
2011-05-29 00:19:23 +00:00
items: "[title]",
position: {
my: "left+15 center",
at: "right center",
collision: "flipfit flipfit"
2011-05-29 00:19:23 +00:00
},
show: true,
tooltipClass: null,
2012-06-13 23:02:11 +00:00
track: false,
// callbacks
close: null,
open: null
},
2011-05-28 00:05:20 +00:00
2010-10-26 12:41:14 +00:00
_create: function() {
this._on({
mouseover: "open",
focusin: "open"
});
// IDs of generated tooltips, needed for destroy
this.tooltips = {};
},
2011-05-28 00:05:20 +00:00
_setOption: function( key, value ) {
if ( key === "disabled" ) {
this[ value ? "_disable" : "_enable" ]();
this.options[ key ] = value;
// disable element style changes
return;
}
this._super( key, value );
},
2011-05-28 00:05:20 +00:00
_disable: function() {
var that = this;
// close open tooltips
$.each( this.tooltips, function( id, element ) {
var event = $.Event( "blur" );
event.target = event.currentTarget = element[0];
that.close( event, true );
});
// remove title attributes to prevent native tooltips
this.element.find( this.options.items ).andSelf().each(function() {
var element = $( this );
if ( element.is( "[title]" ) ) {
element
.data( "ui-tooltip-title", element.attr( "title" ) )
.attr( "title", "" );
}
});
},
_enable: function() {
// restore title attributes
this.element.find( this.options.items ).andSelf().each(function() {
var element = $( this );
if ( element.data( "ui-tooltip-title" ) ) {
element.attr( "title", element.data( "ui-tooltip-title" ) );
}
});
},
2011-05-28 00:05:20 +00:00
open: function( event ) {
2011-05-29 00:30:14 +00:00
var content,
that = this,
target = $( event ? event.target : this.element )
.closest( this.options.items );
2012-05-22 16:34:00 +00:00
// if ui-tooltip-id exists, then the tooltip is already open
if ( !target.length || target.data( "ui-tooltip-id" ) ) {
return;
}
2011-05-28 00:05:20 +00:00
if ( target.attr( "title" ) ) {
target.data( "ui-tooltip-title", target.attr( "title" ) );
}
2011-05-29 00:30:14 +00:00
target.data( "tooltip-open", true );
2011-05-29 00:30:14 +00:00
content = this.options.content.call( target[0], function( response ) {
// ignore async response if tooltip was closed already
if ( !target.data( "tooltip-open" ) ) {
return;
}
2011-05-28 15:43:57 +00:00
// IE may instantly serve a cached response for ajax requests
// delay this call to _open so the other call to _open runs first
setTimeout(function() {
that._open( event, target, response );
2011-05-28 15:43:57 +00:00
}, 1 );
});
2011-05-28 00:05:20 +00:00
if ( content ) {
that._open( event, target, content );
}
},
2011-05-28 00:05:20 +00:00
_open: function( event, target, content ) {
2012-06-13 23:02:11 +00:00
var tooltip, positionOption;
2011-05-28 00:05:20 +00:00
if ( !content ) {
return;
2011-05-28 00:05:20 +00:00
}
// Content can be updated multiple times. If the tooltip already
// exists, then just update the content and bail.
2012-06-13 23:02:11 +00:00
tooltip = this._find( target );
if ( tooltip.length ) {
tooltip.find( ".ui-tooltip-content" ).html( content );
return;
}
// if we have a title, clear it to prevent the native tooltip
// we have to check first to avoid defining a title if none exists
// (we don't want to cause an element to start matching [title])
2012-05-22 16:34:00 +00:00
//
// We use removeAttr only for key events, to allow IE to export the correct
// accessible attributes. For mouse events, set to empty string to avoid
// native tooltip showing up (happens only when removing inside mouseover).
if ( target.is( "[title]" ) ) {
if ( event && event.type === "mouseover" ) {
target.attr( "title", "" );
} else {
target.removeAttr( "title" );
}
}
tooltip = this._tooltip( target );
addDescribedBy( target, tooltip.attr( "id" ) );
2011-05-28 00:05:20 +00:00
tooltip.find( ".ui-tooltip-content" ).html( content );
2012-06-13 23:02:11 +00:00
function position( event ) {
positionOption.of = event;
tooltip.position( positionOption );
}
if ( this.options.track && /^mouse/.test( event.originalEvent.type ) ) {
positionOption = $.extend( {}, this.options.position );
this._on( this.document, {
mousemove: position
});
// trigger once to override element-relative positioning
position( event );
} else {
tooltip.position( $.extend({
of: target
2012-06-13 23:02:11 +00:00
}, this.options.position ) );
}
tooltip.hide();
this._show( tooltip, this.options.show );
this._trigger( "open", event, { tooltip: tooltip } );
this._on( target, {
mouseleave: "close",
focusout: "close",
keyup: function( event ) {
2012-04-02 23:12:21 +00:00
if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
var fakeEvent = $.Event(event);
fakeEvent.currentTarget = target[0];
this.close( fakeEvent, true );
}
}
});
},
2011-05-28 00:05:20 +00:00
close: function( event, force ) {
var that = this,
2011-05-29 00:30:14 +00:00
target = $( event ? event.currentTarget : this.element ),
tooltip = this._find( target );
// disabling closes the tooltip, so we need to track when we're closing
// to avoid an infinite loop in case the tooltip becomes disabled on close
if ( this.closing ) {
return;
}
// don't close if the element has focus
// this prevents the tooltip from closing if you hover while focused
2012-05-22 16:34:00 +00:00
//
// we have to check the event type because tabbing out of the document
// may leave the element as the activeElement
if ( !force && event && event.type !== "focusout" &&
this.document[0].activeElement === target[0] ) {
return;
2011-05-28 00:05:20 +00:00
}
// only set title if we had one before (see comment in _open())
if ( target.data( "ui-tooltip-title" ) ) {
target.attr( "title", target.data( "ui-tooltip-title" ) );
}
removeDescribedBy( target );
2011-05-28 00:05:20 +00:00
tooltip.stop( true );
this._hide( tooltip, this.options.hide, function() {
$( this ).remove();
delete that.tooltips[ this.id ];
});
2011-05-28 00:05:20 +00:00
target.removeData( "tooltip-open" );
this._off( target, "mouseleave focusout keyup" );
2011-05-28 00:05:20 +00:00
2012-06-13 23:02:11 +00:00
// TODO use _off
this.document.unbind( "mousemove.tooltip" );
this.closing = true;
this._trigger( "close", event, { tooltip: tooltip } );
this.closing = false;
},
_tooltip: function( element ) {
var id = "ui-tooltip-" + increments++,
tooltip = $( "<div>" )
2011-05-29 00:30:14 +00:00
.attr({
id: id,
role: "tooltip"
})
.addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
( this.options.tooltipClass || "" ) );
2011-05-28 00:05:20 +00:00
$( "<div>" )
.addClass( "ui-tooltip-content" )
.appendTo( tooltip );
tooltip.appendTo( this.document[0].body );
2011-05-29 23:28:35 +00:00
if ( $.fn.bgiframe ) {
tooltip.bgiframe();
}
this.tooltips[ id ] = element;
return tooltip;
},
_find: function( target ) {
var id = target.data( "ui-tooltip-id" );
2011-05-28 15:43:57 +00:00
return id ? $( "#" + id ) : $();
},
_destroy: function() {
$.each( this.tooltips, function( id ) {
$( "#" + id ).remove();
});
}
});
2011-05-28 00:05:20 +00:00
}( jQuery ) );