You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
402 lines
11 KiB
402 lines
11 KiB
/*! |
|
* jQuery UI Tooltip 1.10.3 |
|
* http://jqueryui.com |
|
* |
|
* Copyright 2013 jQuery Foundation and other contributors |
|
* Released under the MIT license. |
|
* http://jquery.org/license |
|
* |
|
* http://api.jqueryui.com/tooltip/ |
|
* |
|
* Depends: |
|
* jquery.ui.core.js |
|
* jquery.ui.widget.js |
|
* jquery.ui.position.js |
|
*/ |
|
(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" ); |
|
} |
|
} |
|
|
|
$.widget( "ui.tooltip", { |
|
version: "1.10.3", |
|
options: { |
|
content: function() { |
|
// support: IE<9, Opera in jQuery <1.7 |
|
// .text() can't accept undefined, so coerce to a string |
|
var title = $( this ).attr( "title" ) || ""; |
|
// Escape title, since we're going from an attribute to raw HTML |
|
return $( "<a>" ).text( title ).html(); |
|
}, |
|
hide: true, |
|
// Disabled elements have inconsistent behavior across browsers (#8661) |
|
items: "[title]:not([disabled])", |
|
position: { |
|
my: "left top+15", |
|
at: "left bottom", |
|
collision: "flipfit flip" |
|
}, |
|
show: true, |
|
tooltipClass: null, |
|
track: false, |
|
|
|
// callbacks |
|
close: null, |
|
open: null |
|
}, |
|
|
|
_create: function() { |
|
this._on({ |
|
mouseover: "open", |
|
focusin: "open" |
|
}); |
|
|
|
// IDs of generated tooltips, needed for destroy |
|
this.tooltips = {}; |
|
// IDs of parent tooltips where we removed the title attribute |
|
this.parents = {}; |
|
|
|
if ( this.options.disabled ) { |
|
this._disable(); |
|
} |
|
}, |
|
|
|
_setOption: function( key, value ) { |
|
var that = this; |
|
|
|
if ( key === "disabled" ) { |
|
this[ value ? "_disable" : "_enable" ](); |
|
this.options[ key ] = value; |
|
// disable element style changes |
|
return; |
|
} |
|
|
|
this._super( key, value ); |
|
|
|
if ( key === "content" ) { |
|
$.each( this.tooltips, function( id, element ) { |
|
that._updateContent( element ); |
|
}); |
|
} |
|
}, |
|
|
|
_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 ).addBack().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 ).addBack().each(function() { |
|
var element = $( this ); |
|
if ( element.data( "ui-tooltip-title" ) ) { |
|
element.attr( "title", element.data( "ui-tooltip-title" ) ); |
|
} |
|
}); |
|
}, |
|
|
|
open: function( event ) { |
|
var that = this, |
|
target = $( event ? event.target : this.element ) |
|
// we need closest here due to mouseover bubbling, |
|
// but always pointing at the same event target |
|
.closest( this.options.items ); |
|
|
|
// No element to show a tooltip for or the tooltip is already open |
|
if ( !target.length || target.data( "ui-tooltip-id" ) ) { |
|
return; |
|
} |
|
|
|
if ( target.attr( "title" ) ) { |
|
target.data( "ui-tooltip-title", target.attr( "title" ) ); |
|
} |
|
|
|
target.data( "ui-tooltip-open", true ); |
|
|
|
// kill parent tooltips, custom or native, for hover |
|
if ( event && event.type === "mouseover" ) { |
|
target.parents().each(function() { |
|
var parent = $( this ), |
|
blurEvent; |
|
if ( parent.data( "ui-tooltip-open" ) ) { |
|
blurEvent = $.Event( "blur" ); |
|
blurEvent.target = blurEvent.currentTarget = this; |
|
that.close( blurEvent, true ); |
|
} |
|
if ( parent.attr( "title" ) ) { |
|
parent.uniqueId(); |
|
that.parents[ this.id ] = { |
|
element: this, |
|
title: parent.attr( "title" ) |
|
}; |
|
parent.attr( "title", "" ); |
|
} |
|
}); |
|
} |
|
|
|
this._updateContent( target, event ); |
|
}, |
|
|
|
_updateContent: function( target, event ) { |
|
var content, |
|
contentOption = this.options.content, |
|
that = this, |
|
eventType = event ? event.type : null; |
|
|
|
if ( typeof contentOption === "string" ) { |
|
return this._open( event, target, contentOption ); |
|
} |
|
|
|
content = contentOption.call( target[0], function( response ) { |
|
// ignore async response if tooltip was closed already |
|
if ( !target.data( "ui-tooltip-open" ) ) { |
|
return; |
|
} |
|
// IE may instantly serve a cached response for ajax requests |
|
// delay this call to _open so the other call to _open runs first |
|
that._delay(function() { |
|
// jQuery creates a special event for focusin when it doesn't |
|
// exist natively. To improve performance, the native event |
|
// object is reused and the type is changed. Therefore, we can't |
|
// rely on the type being correct after the event finished |
|
// bubbling, so we set it back to the previous value. (#8740) |
|
if ( event ) { |
|
event.type = eventType; |
|
} |
|
this._open( event, target, response ); |
|
}); |
|
}); |
|
if ( content ) { |
|
this._open( event, target, content ); |
|
} |
|
}, |
|
|
|
_open: function( event, target, content ) { |
|
var tooltip, events, delayedShow, |
|
positionOption = $.extend( {}, this.options.position ); |
|
|
|
if ( !content ) { |
|
return; |
|
} |
|
|
|
// Content can be updated multiple times. If the tooltip already |
|
// exists, then just update the content and bail. |
|
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]) |
|
// |
|
// 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" ) ); |
|
tooltip.find( ".ui-tooltip-content" ).html( content ); |
|
|
|
function position( event ) { |
|
positionOption.of = event; |
|
if ( tooltip.is( ":hidden" ) ) { |
|
return; |
|
} |
|
tooltip.position( positionOption ); |
|
} |
|
if ( this.options.track && event && /^mouse/.test( event.type ) ) { |
|
this._on( this.document, { |
|
mousemove: position |
|
}); |
|
// trigger once to override element-relative positioning |
|
position( event ); |
|
} else { |
|
tooltip.position( $.extend({ |
|
of: target |
|
}, this.options.position ) ); |
|
} |
|
|
|
tooltip.hide(); |
|
|
|
this._show( tooltip, this.options.show ); |
|
// Handle tracking tooltips that are shown with a delay (#8644). As soon |
|
// as the tooltip is visible, position the tooltip using the most recent |
|
// event. |
|
if ( this.options.show && this.options.show.delay ) { |
|
delayedShow = this.delayedShow = setInterval(function() { |
|
if ( tooltip.is( ":visible" ) ) { |
|
position( positionOption.of ); |
|
clearInterval( delayedShow ); |
|
} |
|
}, $.fx.interval ); |
|
} |
|
|
|
this._trigger( "open", event, { tooltip: tooltip } ); |
|
|
|
events = { |
|
keyup: function( event ) { |
|
if ( event.keyCode === $.ui.keyCode.ESCAPE ) { |
|
var fakeEvent = $.Event(event); |
|
fakeEvent.currentTarget = target[0]; |
|
this.close( fakeEvent, true ); |
|
} |
|
}, |
|
remove: function() { |
|
this._removeTooltip( tooltip ); |
|
} |
|
}; |
|
if ( !event || event.type === "mouseover" ) { |
|
events.mouseleave = "close"; |
|
} |
|
if ( !event || event.type === "focusin" ) { |
|
events.focusout = "close"; |
|
} |
|
this._on( true, target, events ); |
|
}, |
|
|
|
close: function( event ) { |
|
var that = this, |
|
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; |
|
} |
|
|
|
// Clear the interval for delayed tracking tooltips |
|
clearInterval( this.delayedShow ); |
|
|
|
// 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 ); |
|
|
|
tooltip.stop( true ); |
|
this._hide( tooltip, this.options.hide, function() { |
|
that._removeTooltip( $( this ) ); |
|
}); |
|
|
|
target.removeData( "ui-tooltip-open" ); |
|
this._off( target, "mouseleave focusout keyup" ); |
|
// Remove 'remove' binding only on delegated targets |
|
if ( target[0] !== this.element[0] ) { |
|
this._off( target, "remove" ); |
|
} |
|
this._off( this.document, "mousemove" ); |
|
|
|
if ( event && event.type === "mouseleave" ) { |
|
$.each( this.parents, function( id, parent ) { |
|
$( parent.element ).attr( "title", parent.title ); |
|
delete that.parents[ id ]; |
|
}); |
|
} |
|
|
|
this.closing = true; |
|
this._trigger( "close", event, { tooltip: tooltip } ); |
|
this.closing = false; |
|
}, |
|
|
|
_tooltip: function( element ) { |
|
var id = "ui-tooltip-" + increments++, |
|
tooltip = $( "<div>" ) |
|
.attr({ |
|
id: id, |
|
role: "tooltip" |
|
}) |
|
.addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + |
|
( this.options.tooltipClass || "" ) ); |
|
$( "<div>" ) |
|
.addClass( "ui-tooltip-content" ) |
|
.appendTo( tooltip ); |
|
tooltip.appendTo( this.document[0].body ); |
|
this.tooltips[ id ] = element; |
|
return tooltip; |
|
}, |
|
|
|
_find: function( target ) { |
|
var id = target.data( "ui-tooltip-id" ); |
|
return id ? $( "#" + id ) : $(); |
|
}, |
|
|
|
_removeTooltip: function( tooltip ) { |
|
tooltip.remove(); |
|
delete this.tooltips[ tooltip.attr( "id" ) ]; |
|
}, |
|
|
|
_destroy: function() { |
|
var that = this; |
|
|
|
// close open tooltips |
|
$.each( this.tooltips, function( id, element ) { |
|
// Delegate to close method to handle common cleanup |
|
var event = $.Event( "blur" ); |
|
event.target = event.currentTarget = element[0]; |
|
that.close( event, true ); |
|
|
|
// Remove immediately; destroying an open tooltip doesn't use the |
|
// hide animation |
|
$( "#" + id ).remove(); |
|
|
|
// Restore the title |
|
if ( element.data( "ui-tooltip-title" ) ) { |
|
element.attr( "title", element.data( "ui-tooltip-title" ) ); |
|
element.removeData( "ui-tooltip-title" ); |
|
} |
|
}); |
|
} |
|
}); |
|
|
|
}( jQuery ) );
|
|
|