[ 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.13.3
   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.13.3",
  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              // IE may instantly serve a cached response for ajax requests
 231              // delay this call to _open so the other call to _open runs first
 232              that._delay( function() {
 233  
 234                  // Ignore async response if tooltip was closed already
 235                  if ( !target.data( "ui-tooltip-open" ) ) {
 236                      return;
 237                  }
 238  
 239                  // JQuery creates a special event for focusin when it doesn't
 240                  // exist natively. To improve performance, the native event
 241                  // object is reused and the type is changed. Therefore, we can't
 242                  // rely on the type being correct after the event finished
 243                  // bubbling, so we set it back to the previous value. (#8740)
 244                  if ( event ) {
 245                      event.type = eventType;
 246                  }
 247                  this._open( event, target, response );
 248              } );
 249          } );
 250          if ( content ) {
 251              this._open( event, target, content );
 252          }
 253      },
 254  
 255      _open: function( event, target, content ) {
 256          var tooltipData, tooltip, delayedShow, a11yContent,
 257              positionOption = $.extend( {}, this.options.position );
 258  
 259          if ( !content ) {
 260              return;
 261          }
 262  
 263          // Content can be updated multiple times. If the tooltip already
 264          // exists, then just update the content and bail.
 265          tooltipData = this._find( target );
 266          if ( tooltipData ) {
 267              tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
 268              return;
 269          }
 270  
 271          // If we have a title, clear it to prevent the native tooltip
 272          // we have to check first to avoid defining a title if none exists
 273          // (we don't want to cause an element to start matching [title])
 274          //
 275          // We use removeAttr only for key events, to allow IE to export the correct
 276          // accessible attributes. For mouse events, set to empty string to avoid
 277          // native tooltip showing up (happens only when removing inside mouseover).
 278          if ( target.is( "[title]" ) ) {
 279              if ( event && event.type === "mouseover" ) {
 280                  target.attr( "title", "" );
 281              } else {
 282                  target.removeAttr( "title" );
 283              }
 284          }
 285  
 286          tooltipData = this._tooltip( target );
 287          tooltip = tooltipData.tooltip;
 288          this._addDescribedBy( target, tooltip.attr( "id" ) );
 289          tooltip.find( ".ui-tooltip-content" ).html( content );
 290  
 291          // Support: Voiceover on OS X, JAWS on IE <= 9
 292          // JAWS announces deletions even when aria-relevant="additions"
 293          // Voiceover will sometimes re-read the entire log region's contents from the beginning
 294          this.liveRegion.children().hide();
 295          a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
 296          a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
 297          a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
 298          a11yContent.appendTo( this.liveRegion );
 299  
 300  		function position( event ) {
 301              positionOption.of = event;
 302              if ( tooltip.is( ":hidden" ) ) {
 303                  return;
 304              }
 305              tooltip.position( positionOption );
 306          }
 307          if ( this.options.track && event && /^mouse/.test( event.type ) ) {
 308              this._on( this.document, {
 309                  mousemove: position
 310              } );
 311  
 312              // trigger once to override element-relative positioning
 313              position( event );
 314          } else {
 315              tooltip.position( $.extend( {
 316                  of: target
 317              }, this.options.position ) );
 318          }
 319  
 320          tooltip.hide();
 321  
 322          this._show( tooltip, this.options.show );
 323  
 324          // Handle tracking tooltips that are shown with a delay (#8644). As soon
 325          // as the tooltip is visible, position the tooltip using the most recent
 326          // event.
 327          // Adds the check to add the timers only when both delay and track options are set (#14682)
 328          if ( this.options.track && this.options.show && this.options.show.delay ) {
 329              delayedShow = this.delayedShow = setInterval( function() {
 330                  if ( tooltip.is( ":visible" ) ) {
 331                      position( positionOption.of );
 332                      clearInterval( delayedShow );
 333                  }
 334              }, 13 );
 335          }
 336  
 337          this._trigger( "open", event, { tooltip: tooltip } );
 338      },
 339  
 340      _registerCloseHandlers: function( event, target ) {
 341          var events = {
 342              keyup: function( event ) {
 343                  if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
 344                      var fakeEvent = $.Event( event );
 345                      fakeEvent.currentTarget = target[ 0 ];
 346                      this.close( fakeEvent, true );
 347                  }
 348              }
 349          };
 350  
 351          // Only bind remove handler for delegated targets. Non-delegated
 352          // tooltips will handle this in destroy.
 353          if ( target[ 0 ] !== this.element[ 0 ] ) {
 354              events.remove = function() {
 355                  var targetElement = this._find( target );
 356                  if ( targetElement ) {
 357                      this._removeTooltip( targetElement.tooltip );
 358                  }
 359              };
 360          }
 361  
 362          if ( !event || event.type === "mouseover" ) {
 363              events.mouseleave = "close";
 364          }
 365          if ( !event || event.type === "focusin" ) {
 366              events.focusout = "close";
 367          }
 368          this._on( true, target, events );
 369      },
 370  
 371      close: function( event ) {
 372          var tooltip,
 373              that = this,
 374              target = $( event ? event.currentTarget : this.element ),
 375              tooltipData = this._find( target );
 376  
 377          // The tooltip may already be closed
 378          if ( !tooltipData ) {
 379  
 380              // We set ui-tooltip-open immediately upon open (in open()), but only set the
 381              // additional data once there's actually content to show (in _open()). So even if the
 382              // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
 383              // the period between open() and _open().
 384              target.removeData( "ui-tooltip-open" );
 385              return;
 386          }
 387  
 388          tooltip = tooltipData.tooltip;
 389  
 390          // Disabling closes the tooltip, so we need to track when we're closing
 391          // to avoid an infinite loop in case the tooltip becomes disabled on close
 392          if ( tooltipData.closing ) {
 393              return;
 394          }
 395  
 396          // Clear the interval for delayed tracking tooltips
 397          clearInterval( this.delayedShow );
 398  
 399          // Only set title if we had one before (see comment in _open())
 400          // If the title attribute has changed since open(), don't restore
 401          if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
 402              target.attr( "title", target.data( "ui-tooltip-title" ) );
 403          }
 404  
 405          this._removeDescribedBy( target );
 406  
 407          tooltipData.hiding = true;
 408          tooltip.stop( true );
 409          this._hide( tooltip, this.options.hide, function() {
 410              that._removeTooltip( $( this ) );
 411          } );
 412  
 413          target.removeData( "ui-tooltip-open" );
 414          this._off( target, "mouseleave focusout keyup" );
 415  
 416          // Remove 'remove' binding only on delegated targets
 417          if ( target[ 0 ] !== this.element[ 0 ] ) {
 418              this._off( target, "remove" );
 419          }
 420          this._off( this.document, "mousemove" );
 421  
 422          if ( event && event.type === "mouseleave" ) {
 423              $.each( this.parents, function( id, parent ) {
 424                  $( parent.element ).attr( "title", parent.title );
 425                  delete that.parents[ id ];
 426              } );
 427          }
 428  
 429          tooltipData.closing = true;
 430          this._trigger( "close", event, { tooltip: tooltip } );
 431          if ( !tooltipData.hiding ) {
 432              tooltipData.closing = false;
 433          }
 434      },
 435  
 436      _tooltip: function( element ) {
 437          var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
 438              content = $( "<div>" ).appendTo( tooltip ),
 439              id = tooltip.uniqueId().attr( "id" );
 440  
 441          this._addClass( content, "ui-tooltip-content" );
 442          this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
 443  
 444          tooltip.appendTo( this._appendTo( element ) );
 445  
 446          return this.tooltips[ id ] = {
 447              element: element,
 448              tooltip: tooltip
 449          };
 450      },
 451  
 452      _find: function( target ) {
 453          var id = target.data( "ui-tooltip-id" );
 454          return id ? this.tooltips[ id ] : null;
 455      },
 456  
 457      _removeTooltip: function( tooltip ) {
 458  
 459          // Clear the interval for delayed tracking tooltips
 460          clearInterval( this.delayedShow );
 461  
 462          tooltip.remove();
 463          delete this.tooltips[ tooltip.attr( "id" ) ];
 464      },
 465  
 466      _appendTo: function( target ) {
 467          var element = target.closest( ".ui-front, dialog" );
 468  
 469          if ( !element.length ) {
 470              element = this.document[ 0 ].body;
 471          }
 472  
 473          return element;
 474      },
 475  
 476      _destroy: function() {
 477          var that = this;
 478  
 479          // Close open tooltips
 480          $.each( this.tooltips, function( id, tooltipData ) {
 481  
 482              // Delegate to close method to handle common cleanup
 483              var event = $.Event( "blur" ),
 484                  element = tooltipData.element;
 485              event.target = event.currentTarget = element[ 0 ];
 486              that.close( event, true );
 487  
 488              // Remove immediately; destroying an open tooltip doesn't use the
 489              // hide animation
 490              $( "#" + id ).remove();
 491  
 492              // Restore the title
 493              if ( element.data( "ui-tooltip-title" ) ) {
 494  
 495                  // If the title attribute has changed since open(), don't restore
 496                  if ( !element.attr( "title" ) ) {
 497                      element.attr( "title", element.data( "ui-tooltip-title" ) );
 498                  }
 499                  element.removeData( "ui-tooltip-title" );
 500              }
 501          } );
 502          this.liveRegion.remove();
 503      }
 504  } );
 505  
 506  // DEPRECATED
 507  // TODO: Switch return back to widget declaration at top of file when this is removed
 508  if ( $.uiBackCompat !== false ) {
 509  
 510      // Backcompat for tooltipClass option
 511      $.widget( "ui.tooltip", $.ui.tooltip, {
 512          options: {
 513              tooltipClass: null
 514          },
 515          _tooltip: function() {
 516              var tooltipData = this._superApply( arguments );
 517              if ( this.options.tooltipClass ) {
 518                  tooltipData.tooltip.addClass( this.options.tooltipClass );
 519              }
 520              return tooltipData;
 521          }
 522      } );
 523  }
 524  
 525  return $.ui.tooltip;
 526  
 527  } );


Generated : Thu Nov 21 08:20:01 2024 Cross-referenced by PHPXref