| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 /*! 2 * jQuery UI Tooltip 1.14.2 3 * https://jqueryui.com 4 * 5 * Copyright OpenJS Foundation and other contributors 6 * Released under the MIT license. 7 * https://jquery.org/license 8 */ 9 10 //>>label: Tooltip 11 //>>group: Widgets 12 //>>description: Shows additional information for any element on hover or focus. 13 //>>docs: https://api.jqueryui.com/tooltip/ 14 //>>demos: https://jqueryui.com/tooltip/ 15 //>>css.structure: ../../themes/base/core.css 16 //>>css.structure: ../../themes/base/tooltip.css 17 //>>css.theme: ../../themes/base/theme.css 18 19 ( function( factory ) { 20 "use strict"; 21 22 if ( typeof define === "function" && define.amd ) { 23 24 // AMD. Register as an anonymous module. 25 define( [ 26 "jquery", 27 "../keycode", 28 "../position", 29 "../unique-id", 30 "../version", 31 "../widget" 32 ], factory ); 33 } else { 34 35 // Browser globals 36 factory( jQuery ); 37 } 38 } )( function( $ ) { 39 "use strict"; 40 41 $.widget( "ui.tooltip", { 42 version: "1.14.2", 43 options: { 44 classes: { 45 "ui-tooltip": "ui-corner-all ui-widget-shadow" 46 }, 47 content: function() { 48 var title = $( this ).attr( "title" ); 49 50 // Escape title, since we're going from an attribute to raw HTML 51 return $( "<a>" ).text( title ).html(); 52 }, 53 hide: true, 54 55 // Disabled elements have inconsistent behavior across browsers (#8661) 56 items: "[title]:not([disabled])", 57 position: { 58 my: "left top+15", 59 at: "left bottom", 60 collision: "flipfit flip" 61 }, 62 show: true, 63 track: false, 64 65 // Callbacks 66 close: null, 67 open: null 68 }, 69 70 _addDescribedBy: function( elem, id ) { 71 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ); 72 describedby.push( id ); 73 elem 74 .data( "ui-tooltip-id", id ) 75 .attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) ); 76 }, 77 78 _removeDescribedBy: function( elem ) { 79 var id = elem.data( "ui-tooltip-id" ), 80 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ), 81 index = $.inArray( id, describedby ); 82 83 if ( index !== -1 ) { 84 describedby.splice( index, 1 ); 85 } 86 87 elem.removeData( "ui-tooltip-id" ); 88 describedby = String.prototype.trim.call( describedby.join( " " ) ); 89 if ( describedby ) { 90 elem.attr( "aria-describedby", describedby ); 91 } else { 92 elem.removeAttr( "aria-describedby" ); 93 } 94 }, 95 96 _create: function() { 97 this._on( { 98 mouseover: "open", 99 focusin: "open" 100 } ); 101 102 // IDs of generated tooltips, needed for destroy 103 this.tooltips = {}; 104 105 // IDs of parent tooltips where we removed the title attribute 106 this.parents = {}; 107 108 // Append the aria-live region so tooltips announce correctly 109 this.liveRegion = $( "<div>" ) 110 .attr( { 111 role: "log", 112 "aria-live": "assertive", 113 "aria-relevant": "additions" 114 } ) 115 .appendTo( this.document[ 0 ].body ); 116 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 117 118 this.disabledTitles = $( [] ); 119 }, 120 121 _setOption: function( key, value ) { 122 var that = this; 123 124 this._super( key, value ); 125 126 if ( key === "content" ) { 127 $.each( this.tooltips, function( id, tooltipData ) { 128 that._updateContent( tooltipData.element ); 129 } ); 130 } 131 }, 132 133 _setOptionDisabled: function( value ) { 134 this[ value ? "_disable" : "_enable" ](); 135 }, 136 137 _disable: function() { 138 var that = this; 139 140 // Close open tooltips 141 $.each( this.tooltips, function( id, tooltipData ) { 142 var event = $.Event( "blur" ); 143 event.target = event.currentTarget = tooltipData.element[ 0 ]; 144 that.close( event, true ); 145 } ); 146 147 // Remove title attributes to prevent native tooltips 148 this.disabledTitles = this.disabledTitles.add( 149 this.element.find( this.options.items ).addBack() 150 .filter( function() { 151 var element = $( this ); 152 if ( element.is( "[title]" ) ) { 153 return element 154 .data( "ui-tooltip-title", element.attr( "title" ) ) 155 .removeAttr( "title" ); 156 } 157 } ) 158 ); 159 }, 160 161 _enable: function() { 162 163 // restore title attributes 164 this.disabledTitles.each( function() { 165 var element = $( this ); 166 if ( element.data( "ui-tooltip-title" ) ) { 167 element.attr( "title", element.data( "ui-tooltip-title" ) ); 168 } 169 } ); 170 this.disabledTitles = $( [] ); 171 }, 172 173 open: function( event ) { 174 var that = this, 175 target = $( event ? event.target : this.element ) 176 177 // we need closest here due to mouseover bubbling, 178 // but always pointing at the same event target 179 .closest( this.options.items ); 180 181 // No element to show a tooltip for or the tooltip is already open 182 if ( !target.length || target.data( "ui-tooltip-id" ) ) { 183 return; 184 } 185 186 if ( target.attr( "title" ) ) { 187 target.data( "ui-tooltip-title", target.attr( "title" ) ); 188 } 189 190 target.data( "ui-tooltip-open", true ); 191 192 // Kill parent tooltips, custom or native, for hover 193 if ( event && event.type === "mouseover" ) { 194 target.parents().each( function() { 195 var parent = $( this ), 196 blurEvent; 197 if ( parent.data( "ui-tooltip-open" ) ) { 198 blurEvent = $.Event( "blur" ); 199 blurEvent.target = blurEvent.currentTarget = this; 200 that.close( blurEvent, true ); 201 } 202 if ( parent.attr( "title" ) ) { 203 parent.uniqueId(); 204 that.parents[ this.id ] = { 205 element: this, 206 title: parent.attr( "title" ) 207 }; 208 parent.attr( "title", "" ); 209 } 210 } ); 211 } 212 213 this._registerCloseHandlers( event, target ); 214 this._updateContent( target, event ); 215 }, 216 217 _updateContent: function( target, event ) { 218 var content, 219 contentOption = this.options.content, 220 that = this, 221 eventType = event ? event.type : null; 222 223 if ( typeof contentOption === "string" || contentOption.nodeType || 224 contentOption.jquery ) { 225 return this._open( event, target, contentOption ); 226 } 227 228 content = contentOption.call( target[ 0 ], function( response ) { 229 230 // Ignore async response if tooltip was closed already 231 if ( !target.data( "ui-tooltip-open" ) ) { 232 return; 233 } 234 235 // JQuery creates a special event for focusin when it doesn't 236 // exist natively. To improve performance, the native event 237 // object is reused and the type is changed. Therefore, we can't 238 // rely on the type being correct after the event finished 239 // bubbling, so we set it back to the previous value. (#8740) 240 if ( event ) { 241 event.type = eventType; 242 } 243 that._open( event, target, response ); 244 } ); 245 if ( content ) { 246 this._open( event, target, content ); 247 } 248 }, 249 250 _open: function( event, target, content ) { 251 var tooltipData, tooltip, delayedShow, a11yContent, 252 positionOption = $.extend( {}, this.options.position ); 253 254 if ( !content ) { 255 return; 256 } 257 258 // Content can be updated multiple times. If the tooltip already 259 // exists, then just update the content and bail. 260 tooltipData = this._find( target ); 261 if ( tooltipData ) { 262 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); 263 return; 264 } 265 266 // If we have a title, clear it to prevent the native tooltip 267 // we have to check first to avoid defining a title if none exists 268 // (we don't want to cause an element to start matching [title]) 269 // 270 // We use removeAttr only for key events, to allow IE to export the correct 271 // accessible attributes. For mouse events, set to empty string to avoid 272 // native tooltip showing up (happens only when removing inside mouseover). 273 if ( target.is( "[title]" ) ) { 274 if ( event && event.type === "mouseover" ) { 275 target.attr( "title", "" ); 276 } else { 277 target.removeAttr( "title" ); 278 } 279 } 280 281 tooltipData = this._tooltip( target ); 282 tooltip = tooltipData.tooltip; 283 this._addDescribedBy( target, tooltip.attr( "id" ) ); 284 tooltip.find( ".ui-tooltip-content" ).html( content ); 285 286 // Support: Voiceover on OS X, JAWS on IE <= 9 287 // JAWS announces deletions even when aria-relevant="additions" 288 // Voiceover will sometimes re-read the entire log region's contents from the beginning 289 this.liveRegion.children().hide(); 290 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() ); 291 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" ); 292 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); 293 a11yContent.appendTo( this.liveRegion ); 294 295 function position( event ) { 296 positionOption.of = event; 297 if ( tooltip.is( ":hidden" ) ) { 298 return; 299 } 300 tooltip.position( positionOption ); 301 } 302 if ( this.options.track && event && /^mouse/.test( event.type ) ) { 303 this._on( this.document, { 304 mousemove: position 305 } ); 306 307 // trigger once to override element-relative positioning 308 position( event ); 309 } else { 310 tooltip.position( $.extend( { 311 of: target 312 }, this.options.position ) ); 313 } 314 315 tooltip.hide(); 316 317 this._show( tooltip, this.options.show ); 318 319 // Handle tracking tooltips that are shown with a delay (#8644). As soon 320 // as the tooltip is visible, position the tooltip using the most recent 321 // event. 322 // Adds the check to add the timers only when both delay and track options are set (#14682) 323 if ( this.options.track && this.options.show && this.options.show.delay ) { 324 delayedShow = this.delayedShow = setInterval( function() { 325 if ( tooltip.is( ":visible" ) ) { 326 position( positionOption.of ); 327 clearInterval( delayedShow ); 328 } 329 }, 13 ); 330 } 331 332 this._trigger( "open", event, { tooltip: tooltip } ); 333 }, 334 335 _registerCloseHandlers: function( event, target ) { 336 var events = { 337 keyup: function( event ) { 338 if ( event.keyCode === $.ui.keyCode.ESCAPE ) { 339 var fakeEvent = $.Event( event ); 340 fakeEvent.currentTarget = target[ 0 ]; 341 this.close( fakeEvent, true ); 342 } 343 } 344 }; 345 346 // Only bind remove handler for delegated targets. Non-delegated 347 // tooltips will handle this in destroy. 348 if ( target[ 0 ] !== this.element[ 0 ] ) { 349 events.remove = function() { 350 var targetElement = this._find( target ); 351 if ( targetElement ) { 352 this._removeTooltip( targetElement.tooltip ); 353 } 354 }; 355 } 356 357 if ( !event || event.type === "mouseover" ) { 358 events.mouseleave = "close"; 359 } 360 if ( !event || event.type === "focusin" ) { 361 events.focusout = "close"; 362 } 363 this._on( true, target, events ); 364 }, 365 366 close: function( event ) { 367 var tooltip, 368 that = this, 369 target = $( event ? event.currentTarget : this.element ), 370 tooltipData = this._find( target ); 371 372 // The tooltip may already be closed 373 if ( !tooltipData ) { 374 375 // We set ui-tooltip-open immediately upon open (in open()), but only set the 376 // additional data once there's actually content to show (in _open()). So even if the 377 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in 378 // the period between open() and _open(). 379 target.removeData( "ui-tooltip-open" ); 380 return; 381 } 382 383 tooltip = tooltipData.tooltip; 384 385 // Disabling closes the tooltip, so we need to track when we're closing 386 // to avoid an infinite loop in case the tooltip becomes disabled on close 387 if ( tooltipData.closing ) { 388 return; 389 } 390 391 // Clear the interval for delayed tracking tooltips 392 clearInterval( this.delayedShow ); 393 394 // Only set title if we had one before (see comment in _open()) 395 // If the title attribute has changed since open(), don't restore 396 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { 397 target.attr( "title", target.data( "ui-tooltip-title" ) ); 398 } 399 400 this._removeDescribedBy( target ); 401 402 tooltipData.hiding = true; 403 tooltip.stop( true ); 404 this._hide( tooltip, this.options.hide, function() { 405 that._removeTooltip( $( this ) ); 406 } ); 407 408 target.removeData( "ui-tooltip-open" ); 409 this._off( target, "mouseleave focusout keyup" ); 410 411 // Remove 'remove' binding only on delegated targets 412 if ( target[ 0 ] !== this.element[ 0 ] ) { 413 this._off( target, "remove" ); 414 } 415 this._off( this.document, "mousemove" ); 416 417 if ( event && event.type === "mouseleave" ) { 418 $.each( this.parents, function( id, parent ) { 419 $( parent.element ).attr( "title", parent.title ); 420 delete that.parents[ id ]; 421 } ); 422 } 423 424 tooltipData.closing = true; 425 this._trigger( "close", event, { tooltip: tooltip } ); 426 if ( !tooltipData.hiding ) { 427 tooltipData.closing = false; 428 } 429 }, 430 431 _tooltip: function( element ) { 432 var tooltip = $( "<div>" ).attr( "role", "tooltip" ), 433 content = $( "<div>" ).appendTo( tooltip ), 434 id = tooltip.uniqueId().attr( "id" ); 435 436 this._addClass( content, "ui-tooltip-content" ); 437 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" ); 438 439 tooltip.appendTo( this._appendTo( element ) ); 440 441 return this.tooltips[ id ] = { 442 element: element, 443 tooltip: tooltip 444 }; 445 }, 446 447 _find: function( target ) { 448 var id = target.data( "ui-tooltip-id" ); 449 return id ? this.tooltips[ id ] : null; 450 }, 451 452 _removeTooltip: function( tooltip ) { 453 454 // Clear the interval for delayed tracking tooltips 455 clearInterval( this.delayedShow ); 456 457 tooltip.remove(); 458 delete this.tooltips[ tooltip.attr( "id" ) ]; 459 }, 460 461 _appendTo: function( target ) { 462 var element = target.closest( ".ui-front, dialog" ); 463 464 if ( !element.length ) { 465 element = this.document[ 0 ].body; 466 } 467 468 return element; 469 }, 470 471 _destroy: function() { 472 var that = this; 473 474 // Close open tooltips 475 $.each( this.tooltips, function( id, tooltipData ) { 476 477 // Delegate to close method to handle common cleanup 478 var event = $.Event( "blur" ), 479 element = tooltipData.element; 480 event.target = event.currentTarget = element[ 0 ]; 481 that.close( event, true ); 482 483 // Remove immediately; destroying an open tooltip doesn't use the 484 // hide animation 485 $( "#" + id ).remove(); 486 487 // Restore the title 488 if ( element.data( "ui-tooltip-title" ) ) { 489 490 // If the title attribute has changed since open(), don't restore 491 if ( !element.attr( "title" ) ) { 492 element.attr( "title", element.data( "ui-tooltip-title" ) ); 493 } 494 element.removeData( "ui-tooltip-title" ); 495 } 496 } ); 497 this.liveRegion.remove(); 498 } 499 } ); 500 501 // DEPRECATED 502 // TODO: Switch return back to widget declaration at top of file when this is removed 503 if ( $.uiBackCompat === true ) { 504 505 // Backcompat for tooltipClass option 506 $.widget( "ui.tooltip", $.ui.tooltip, { 507 options: { 508 tooltipClass: null 509 }, 510 _tooltip: function() { 511 var tooltipData = this._superApply( arguments ); 512 if ( this.options.tooltipClass ) { 513 tooltipData.tooltip.addClass( this.options.tooltipClass ); 514 } 515 return tooltipData; 516 } 517 } ); 518 } 519 520 return $.ui.tooltip; 521 522 } );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Thu Jul 23 08:20:17 2026 | Cross-referenced by PHPXref |