wiki.techinc.nl/resources/lib/jquery.ui/jquery.ui.tooltip.js
Timo Tijhof 3cb2ccd878 Upgrade jQuery UI from 1.8.24 to 1.9.2
jQuery UI 1.10 has already been released, and 1.11 is on the
horizon (1.9 is marked "legacy" as of writing). 1.10 drops the
compatibility layer for 1.8 API. So, users should definitely be
encouraged to upgrade their code to move away from the deprecated
1.8 APIs. However, to take it one step at a time, this commit
upgrades us to 1.9 first. That way we're at least not using an
unsupported code base anymore, while at the same time not rolling
out breaking changes.

jQuery UI has redesigned many of its APIs[1], but compatibility
with the jQuery UI 1.8 API is maintained throughout 1.9.x.

* Base theme is now called "Smoothness".

* Sorting the entries in Resources.php alphabetically to make it
  easier to ensure all files are listed when comparing them
  side-by-side.

* Update dependencies to match the "Depends:" header inside
  the javascript files.

* In jQuery UI 1.9, effect files were renamed to match the
  jquery.ui.*.js naming pattern.

* New modules:
  - jquery.ui.menu
  - jquery.ui.spinner
  - jquery.ui.tooltip

* Release notes:
  - http://blog.jqueryui.com/2012/10/jquery-ui-1-9-0/
    - http://jqueryui.com/upgrade-guide/1.9/
    - http://jqueryui.com/changelog/1.9.0/
  - http://blog.jqueryui.com/2012/10/jquery-ui-1-9-1/
    - http://jqueryui.com/changelog/1.9.1/
  - http://blog.jqueryui.com/2012/11/jquery-ui-1-9-2/

[1] http://blog.jqueryui.com/2011/03/api-redesigns-the-past-present-and-future/

Bug: 47076
Change-Id: I0e10b42fb7c25b9d4704719f21c44c08f36ddfa7
2014-06-05 00:29:23 +02:00

398 lines
10 KiB
JavaScript

/*!
* jQuery UI Tooltip 1.9.2
* http://jqueryui.com
*
* Copyright 2012 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.9.2",
options: {
content: function() {
return $( this ).attr( "title" );
},
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 ).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" ) );
}
});
},
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 = 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;
}
// 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 );
if ( $.fn.bgiframe ) {
tooltip.bgiframe();
}
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 ) );