[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/jquery/ui/ -> tooltip.js (source)

   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  } );


Generated : Thu Jul 23 08:20:17 2026 Cross-referenced by PHPXref