[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/ -> wplink.js (source)

   1  /**
   2   * @output wp-includes/js/wplink.js
   3   */
   4  
   5  /* global wpLink */
   6  
   7  /**
   8   * The WordPress Link Modal dialog.
   9   *
  10   * @param {JQueryStatic} $          The jQuery object.
  11   * @param {Object}       wpLinkL10n The WordPress Link localization object.
  12   * @param {Object}       wp         The WordPress global object.
  13   */
  14  ( function( $, wpLinkL10n, wp ) {
  15      var editor, searchTimer, River, Query, correctedURL,
  16          emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,63}$/i,
  17          urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,63}[^ "]*$/i,
  18          inputs = {},
  19          rivers = {},
  20          isTouch = ( 'ontouchend' in document );
  21  
  22      /**
  23       * Gets the currently selected link in the editor.
  24       *
  25       * @return {JQuery} The currently selected link element.
  26       */
  27  	function getLink() {
  28          if ( editor ) {
  29              return editor.$( 'a[data-wplink-edit="true"]' );
  30          }
  31  
  32          return null;
  33      }
  34  
  35      window.wpLink = {
  36          timeToTriggerRiver: 150,
  37          minRiverAJAXDuration: 200,
  38          riverBottomThreshold: 5,
  39          keySensitivity: 100,
  40          lastSearch: '',
  41          textarea: '',
  42          modalOpen: false,
  43  
  44          init: function() {
  45              inputs.wrap = $('#wp-link-wrap');
  46              inputs.dialog = $( '#wp-link' );
  47              inputs.backdrop = $( '#wp-link-backdrop' );
  48              inputs.submit = $( '#wp-link-submit' );
  49              inputs.close = $( '#wp-link-close' );
  50  
  51              // Input.
  52              inputs.text = $( '#wp-link-text' );
  53              inputs.url = $( '#wp-link-url' );
  54              inputs.nonce = $( '#_ajax_linking_nonce' );
  55              inputs.openInNewTab = $( '#wp-link-target' );
  56              inputs.search = $( '#wp-link-search' );
  57  
  58              // Build rivers.
  59              rivers.search = new River( $( '#search-results' ) );
  60              rivers.recent = new River( $( '#most-recent-results' ) );
  61              rivers.elements = inputs.dialog.find( '.query-results' );
  62  
  63              // Get search notice text.
  64              inputs.queryNotice = $( '#query-notice-message' );
  65              inputs.queryNoticeTextDefault = inputs.queryNotice.find( '.query-notice-default' );
  66              inputs.queryNoticeTextHint = inputs.queryNotice.find( '.query-notice-hint' );
  67  
  68              // Bind event handlers.
  69              inputs.dialog.on( 'keydown', wpLink.keydown );
  70              inputs.dialog.on( 'keyup', wpLink.keyup );
  71              inputs.submit.on( 'click', function( event ) {
  72                  event.preventDefault();
  73                  wpLink.update();
  74              });
  75  
  76              inputs.close.add( inputs.backdrop ).add( '#wp-link-cancel button' ).on( 'click', function( event ) {
  77                  event.preventDefault();
  78                  wpLink.close();
  79              });
  80  
  81              rivers.elements.on( 'river-select', wpLink.updateFields );
  82  
  83              // Display 'hint' message when search field or 'query-results' box are focused.
  84              inputs.search.on( 'focus.wplink', function() {
  85                  inputs.queryNoticeTextDefault.hide();
  86                  inputs.queryNoticeTextHint.removeClass( 'screen-reader-text' ).show();
  87              } ).on( 'blur.wplink', function() {
  88                  inputs.queryNoticeTextDefault.show();
  89                  inputs.queryNoticeTextHint.addClass( 'screen-reader-text' ).hide();
  90              } );
  91  
  92              inputs.search.on( 'keyup input', function() {
  93                  window.clearTimeout( searchTimer );
  94                  searchTimer = window.setTimeout( function() {
  95                      wpLink.searchInternalLinks();
  96                  }, 500 );
  97              });
  98  
  99              inputs.url.on( 'paste', function() {
 100                  setTimeout( wpLink.correctURL, 0 );
 101              } );
 102  
 103              inputs.url.on( 'blur', wpLink.correctURL );
 104          },
 105  
 106          // If URL wasn't corrected last time and doesn't start with http:, https:, ? # or /, prepend http://.
 107          correctURL: function () {
 108              var url = inputs.url.val().trim();
 109  
 110              if ( url && correctedURL !== url && ! /^(?:[a-z]+:|#|\?|\.|\/)/.test( url ) ) {
 111                  inputs.url.val( 'http://' + url );
 112                  correctedURL = url;
 113              }
 114          },
 115  
 116          open: function( editorId, url, text ) {
 117              var ed,
 118                  $body = $( document.body );
 119  
 120              $( '#wpwrap' ).attr( 'aria-hidden', 'true' );
 121              $body.addClass( 'modal-open' );
 122              wpLink.modalOpen = true;
 123  
 124              wpLink.range = null;
 125  
 126              if ( editorId ) {
 127                  window.wpActiveEditor = editorId;
 128              }
 129  
 130              if ( ! window.wpActiveEditor ) {
 131                  return;
 132              }
 133  
 134              this.textarea = $( '#' + window.wpActiveEditor ).get( 0 );
 135  
 136              if ( typeof window.tinymce !== 'undefined' ) {
 137                  // Make sure the link wrapper is the last element in the body,
 138                  // or the inline editor toolbar may show above the backdrop.
 139                  $body.append( inputs.backdrop, inputs.wrap );
 140  
 141                  ed = window.tinymce.get( window.wpActiveEditor );
 142  
 143                  if ( ed && ! ed.isHidden() ) {
 144                      editor = ed;
 145                  } else {
 146                      editor = null;
 147                  }
 148              }
 149  
 150              if ( ! wpLink.isMCE() && document.selection ) {
 151                  this.textarea.focus();
 152                  this.range = document.selection.createRange();
 153              }
 154  
 155              inputs.wrap.show();
 156              inputs.backdrop.show();
 157  
 158              wpLink.refresh( url, text );
 159  
 160              $( document ).trigger( 'wplink-open', inputs.wrap );
 161          },
 162  
 163          isMCE: function() {
 164              return editor && ! editor.isHidden();
 165          },
 166  
 167          refresh: function( url, text ) {
 168              var linkText = '';
 169  
 170              // Refresh rivers (clear links, check visibility).
 171              rivers.search.refresh();
 172              rivers.recent.refresh();
 173  
 174              if ( wpLink.isMCE() ) {
 175                  wpLink.mceRefresh( url, text );
 176              } else {
 177                  // For the Code editor the "Link text" field is always shown.
 178                  if ( ! inputs.wrap.hasClass( 'has-text-field' ) ) {
 179                      inputs.wrap.addClass( 'has-text-field' );
 180                  }
 181  
 182                  if ( document.selection ) {
 183                      // Old IE.
 184                      linkText = document.selection.createRange().text || text || '';
 185                  } else if ( typeof this.textarea.selectionStart !== 'undefined' &&
 186                      ( this.textarea.selectionStart !== this.textarea.selectionEnd ) ) {
 187                      // W3C.
 188                      text = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd ) || text || '';
 189                  }
 190  
 191                  inputs.text.val( text );
 192                  wpLink.setDefaultValues();
 193              }
 194  
 195              if ( isTouch ) {
 196                  // Close the onscreen keyboard.
 197                  inputs.url.trigger( 'focus' ).trigger( 'blur' );
 198              } else {
 199                  /*
 200                   * Focus the URL field and highlight its contents.
 201                   * If this is moved above the selection changes,
 202                   * IE will show a flashing cursor over the dialog.
 203                   */
 204                  window.setTimeout( function() {
 205                      inputs.url[0].select();
 206                      inputs.url.trigger( 'focus' );
 207                  } );
 208              }
 209  
 210              // Load the most recent results if this is the first time opening the panel.
 211              if ( ! rivers.recent.ul.children().length ) {
 212                  rivers.recent.ajax();
 213              }
 214  
 215              correctedURL = inputs.url.val().replace( /^http:\/\//, '' );
 216          },
 217  
 218          hasSelectedText: function( linkNode ) {
 219              var node, nodes, i, html = editor.selection.getContent();
 220  
 221              // Partial html and not a fully selected anchor element.
 222              if ( /</.test( html ) && ( ! /^<a [^>]+>[^<]+<\/a>$/.test( html ) || html.indexOf('href=') === -1 ) ) {
 223                  return false;
 224              }
 225  
 226              if ( linkNode.length ) {
 227                  nodes = linkNode[0].childNodes;
 228  
 229                  if ( ! nodes || ! nodes.length ) {
 230                      return false;
 231                  }
 232  
 233                  for ( i = nodes.length - 1; i >= 0; i-- ) {
 234                      node = nodes[i];
 235  
 236                      if ( node.nodeType != 3 && ! window.tinymce.dom.BookmarkManager.isBookmarkNode( node ) ) {
 237                          return false;
 238                      }
 239                  }
 240              }
 241  
 242              return true;
 243          },
 244  
 245          mceRefresh: function( searchStr, text ) {
 246              var linkText, href,
 247                  linkNode = getLink(),
 248                  onlyText = this.hasSelectedText( linkNode );
 249  
 250              if ( linkNode.length ) {
 251                  linkText = linkNode.text();
 252                  href = linkNode.attr( 'href' );
 253  
 254                  if ( ! linkText.trim() ) {
 255                      linkText = text || '';
 256                  }
 257  
 258                  if ( searchStr && ( urlRegexp.test( searchStr ) || emailRegexp.test( searchStr ) ) ) {
 259                      href = searchStr;
 260                  }
 261  
 262                  if ( href !== '_wp_link_placeholder' ) {
 263                      inputs.url.val( href );
 264                      inputs.openInNewTab.prop( 'checked', '_blank' === linkNode.attr( 'target' ) );
 265                      inputs.submit.val( wpLinkL10n.update );
 266                  } else {
 267                      this.setDefaultValues( linkText );
 268                  }
 269  
 270                  if ( searchStr && searchStr !== href ) {
 271                      // The user has typed something in the inline dialog. Trigger a search with it.
 272                      inputs.search.val( searchStr );
 273                  } else {
 274                      inputs.search.val( '' );
 275                  }
 276  
 277                  // Always reset the search.
 278                  window.setTimeout( function() {
 279                      wpLink.searchInternalLinks();
 280                  } );
 281              } else {
 282                  linkText = editor.selection.getContent({ format: 'text' }) || text || '';
 283                  this.setDefaultValues( linkText );
 284              }
 285  
 286              if ( onlyText ) {
 287                  inputs.text.val( linkText );
 288                  inputs.wrap.addClass( 'has-text-field' );
 289              } else {
 290                  inputs.text.val( '' );
 291                  inputs.wrap.removeClass( 'has-text-field' );
 292              }
 293          },
 294  
 295          close: function( reset ) {
 296              $( document.body ).removeClass( 'modal-open' );
 297              $( '#wpwrap' ).removeAttr( 'aria-hidden' );
 298              wpLink.modalOpen = false;
 299  
 300              if ( reset !== 'noReset' ) {
 301                  if ( ! wpLink.isMCE() ) {
 302                      wpLink.textarea.focus();
 303  
 304                      if ( wpLink.range ) {
 305                          wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
 306                          wpLink.range.select();
 307                      }
 308                  } else {
 309                      if ( editor.plugins.wplink ) {
 310                          editor.plugins.wplink.close();
 311                      }
 312  
 313                      editor.focus();
 314                  }
 315              }
 316  
 317              inputs.backdrop.hide();
 318              inputs.wrap.hide();
 319  
 320              correctedURL = false;
 321  
 322              $( document ).trigger( 'wplink-close', inputs.wrap );
 323          },
 324  
 325          getAttrs: function() {
 326              wpLink.correctURL();
 327  
 328              return {
 329                  href: inputs.url.val().trim(),
 330                  target: inputs.openInNewTab.prop( 'checked' ) ? '_blank' : null
 331              };
 332          },
 333  
 334          buildHtml: function(attrs) {
 335              var html = '<a href="' + attrs.href + '"';
 336  
 337              if ( attrs.target ) {
 338                  html += ' target="' + attrs.target + '"';
 339              }
 340  
 341              return html + '>';
 342          },
 343  
 344          update: function() {
 345              if ( wpLink.isMCE() ) {
 346                  wpLink.mceUpdate();
 347              } else {
 348                  wpLink.htmlUpdate();
 349              }
 350          },
 351  
 352          htmlUpdate: function() {
 353              var attrs, text, html, begin, end, cursor, selection,
 354                  textarea = wpLink.textarea;
 355  
 356              if ( ! textarea ) {
 357                  return;
 358              }
 359  
 360              attrs = wpLink.getAttrs();
 361              text = inputs.text.val();
 362  
 363              var parser = document.createElement( 'a' );
 364              parser.href = attrs.href;
 365  
 366              if ( 'javascript:' === parser.protocol || 'data:' === parser.protocol ) { // jshint ignore:line
 367                  attrs.href = '';
 368              }
 369  
 370              // If there's no href, return.
 371              if ( ! attrs.href ) {
 372                  return;
 373              }
 374  
 375              html = wpLink.buildHtml(attrs);
 376  
 377              // Insert HTML.
 378              if ( document.selection && wpLink.range ) {
 379                  // IE.
 380                  // Note: If no text is selected, IE will not place the cursor
 381                  // inside the closing tag.
 382                  textarea.focus();
 383                  wpLink.range.text = html + ( text || wpLink.range.text ) + '</a>';
 384                  wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
 385                  wpLink.range.select();
 386  
 387                  wpLink.range = null;
 388              } else if ( typeof textarea.selectionStart !== 'undefined' ) {
 389                  // W3C.
 390                  begin = textarea.selectionStart;
 391                  end = textarea.selectionEnd;
 392                  selection = text || textarea.value.substring( begin, end );
 393                  html = html + selection + '</a>';
 394                  cursor = begin + html.length;
 395  
 396                  // If no text is selected, place the cursor inside the closing tag.
 397                  if ( begin === end && ! selection ) {
 398                      cursor -= 4;
 399                  }
 400  
 401                  textarea.value = (
 402                      textarea.value.substring( 0, begin ) +
 403                      html +
 404                      textarea.value.substring( end, textarea.value.length )
 405                  );
 406  
 407                  // Update cursor position.
 408                  textarea.selectionStart = textarea.selectionEnd = cursor;
 409              }
 410  
 411              wpLink.close();
 412              textarea.focus();
 413              $( textarea ).trigger( 'change' );
 414  
 415              // Audible confirmation message when a link has been inserted in the Editor.
 416              wp.a11y.speak( wpLinkL10n.linkInserted );
 417          },
 418  
 419          mceUpdate: function() {
 420              var attrs = wpLink.getAttrs(),
 421                  $link, text, hasText;
 422  
 423              var parser = document.createElement( 'a' );
 424              parser.href = attrs.href;
 425  
 426              if ( 'javascript:' === parser.protocol || 'data:' === parser.protocol ) { // jshint ignore:line
 427                  attrs.href = '';
 428              }
 429  
 430              if ( ! attrs.href ) {
 431                  editor.execCommand( 'unlink' );
 432                  wpLink.close();
 433                  return;
 434              }
 435  
 436              $link = getLink();
 437  
 438              editor.undoManager.transact( function() {
 439                  if ( ! $link.length ) {
 440                      editor.execCommand( 'mceInsertLink', false, { href: '_wp_link_placeholder', 'data-wp-temp-link': 1 } );
 441                      $link = editor.$( 'a[data-wp-temp-link="1"]' ).removeAttr( 'data-wp-temp-link' );
 442                      hasText = $link.text().trim();
 443                  }
 444  
 445                  if ( ! $link.length ) {
 446                      editor.execCommand( 'unlink' );
 447                  } else {
 448                      if ( inputs.wrap.hasClass( 'has-text-field' ) ) {
 449                          text = inputs.text.val();
 450  
 451                          if ( text ) {
 452                              $link.text( text );
 453                          } else if ( ! hasText ) {
 454                              $link.text( attrs.href );
 455                          }
 456                      }
 457  
 458                      attrs['data-wplink-edit'] = null;
 459                      attrs['data-mce-href'] = attrs.href;
 460                      $link.attr( attrs );
 461                  }
 462              } );
 463  
 464              wpLink.close( 'noReset' );
 465              editor.focus();
 466  
 467              if ( $link.length ) {
 468                  editor.selection.select( $link[0] );
 469  
 470                  if ( editor.plugins.wplink ) {
 471                      editor.plugins.wplink.checkLink( $link[0] );
 472                  }
 473              }
 474  
 475              editor.nodeChanged();
 476  
 477              // Audible confirmation message when a link has been inserted in the Editor.
 478              wp.a11y.speak( wpLinkL10n.linkInserted );
 479          },
 480  
 481          updateFields: function( e, li ) {
 482              inputs.url.val( li.children( '.item-permalink' ).val() );
 483  
 484              if ( inputs.wrap.hasClass( 'has-text-field' ) && ! inputs.text.val() ) {
 485                  inputs.text.val( li.children( '.item-title' ).text() );
 486              }
 487          },
 488  
 489          getUrlFromSelection: function( selection ) {
 490              if ( ! selection ) {
 491                  if ( this.isMCE() ) {
 492                      selection = editor.selection.getContent({ format: 'text' });
 493                  } else if ( document.selection && wpLink.range ) {
 494                      selection = wpLink.range.text;
 495                  } else if ( typeof this.textarea.selectionStart !== 'undefined' ) {
 496                      selection = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd );
 497                  }
 498              }
 499  
 500              selection = selection || '';
 501              selection = selection.trim();
 502  
 503              if ( selection && emailRegexp.test( selection ) ) {
 504                  // Selection is email address.
 505                  return 'mailto:' + selection;
 506              } else if ( selection && urlRegexp.test( selection ) ) {
 507                  // Selection is URL.
 508                  return selection.replace( /&amp;|&#0?38;/gi, '&' );
 509              }
 510  
 511              return '';
 512          },
 513  
 514          setDefaultValues: function( selection ) {
 515              inputs.url.val( this.getUrlFromSelection( selection ) );
 516  
 517              // Empty the search field and swap the "rivers".
 518              inputs.search.val('');
 519              wpLink.searchInternalLinks();
 520  
 521              // Update save prompt.
 522              inputs.submit.val( wpLinkL10n.save );
 523          },
 524  
 525          searchInternalLinks: function() {
 526              var waiting,
 527                  search = inputs.search.val() || '',
 528                  minInputLength = parseInt( wpLinkL10n.minInputLength, 10 ) || 3;
 529  
 530              if ( search.length >= minInputLength ) {
 531                  rivers.recent.hide();
 532                  rivers.search.show();
 533  
 534                  // Don't search if the keypress didn't change the title.
 535                  if ( wpLink.lastSearch == search )
 536                      return;
 537  
 538                  wpLink.lastSearch = search;
 539                  waiting = inputs.search.parent().find( '.spinner' ).addClass( 'is-active' );
 540  
 541                  rivers.search.change( search );
 542                  rivers.search.ajax( function() {
 543                      waiting.removeClass( 'is-active' );
 544                  });
 545              } else {
 546                  rivers.search.hide();
 547                  rivers.recent.show();
 548              }
 549          },
 550  
 551          next: function() {
 552              rivers.search.next();
 553              rivers.recent.next();
 554          },
 555  
 556          prev: function() {
 557              rivers.search.prev();
 558              rivers.recent.prev();
 559          },
 560  
 561          keydown: function( event ) {
 562              var fn, id;
 563  
 564              // Escape key.
 565              if ( 27 === event.keyCode ) {
 566                  wpLink.close();
 567                  event.stopImmediatePropagation();
 568              // Tab key.
 569              } else if ( 9 === event.keyCode ) {
 570                  id = event.target.id;
 571  
 572                  // wp-link-submit must always be the last focusable element in the dialog.
 573                  // Following focusable elements will be skipped on keyboard navigation.
 574                  if ( id === 'wp-link-submit' && ! event.shiftKey ) {
 575                      inputs.close.trigger( 'focus' );
 576                      event.preventDefault();
 577                  } else if ( id === 'wp-link-close' && event.shiftKey ) {
 578                      inputs.submit.trigger( 'focus' );
 579                      event.preventDefault();
 580                  }
 581              }
 582  
 583              // Up Arrow and Down Arrow keys.
 584              if ( event.shiftKey || ( 38 !== event.keyCode && 40 !== event.keyCode ) ) {
 585                  return;
 586              }
 587  
 588              if ( document.activeElement &&
 589                  ( document.activeElement.id === 'link-title-field' || document.activeElement.id === 'url-field' ) ) {
 590                  return;
 591              }
 592  
 593              // Up Arrow key.
 594              fn = 38 === event.keyCode ? 'prev' : 'next';
 595              clearInterval( wpLink.keyInterval );
 596              wpLink[ fn ]();
 597              wpLink.keyInterval = setInterval( wpLink[ fn ], wpLink.keySensitivity );
 598              event.preventDefault();
 599          },
 600  
 601          keyup: function( event ) {
 602              // Up Arrow and Down Arrow keys.
 603              if ( 38 === event.keyCode || 40 === event.keyCode ) {
 604                  clearInterval( wpLink.keyInterval );
 605                  event.preventDefault();
 606              }
 607          },
 608  
 609          delayedCallback: function( func, delay ) {
 610              var timeoutTriggered, funcTriggered, funcArgs, funcContext;
 611  
 612              if ( ! delay )
 613                  return func;
 614  
 615              setTimeout( function() {
 616                  if ( funcTriggered )
 617                      return func.apply( funcContext, funcArgs );
 618                  // Otherwise, wait.
 619                  timeoutTriggered = true;
 620              }, delay );
 621  
 622              return function() {
 623                  if ( timeoutTriggered )
 624                      return func.apply( this, arguments );
 625                  // Otherwise, wait.
 626                  funcArgs = arguments;
 627                  funcContext = this;
 628                  funcTriggered = true;
 629              };
 630          }
 631      };
 632  
 633      River = function( element, search ) {
 634          var self = this;
 635          this.element = element;
 636          this.ul = element.children( 'ul' );
 637          this.contentHeight = element.children( '#link-selector-height' );
 638          this.waiting = element.find('.river-waiting');
 639  
 640          this.change( search );
 641          this.refresh();
 642  
 643          $( '#wp-link .query-results, #wp-link #link-selector' ).on( 'scroll', function() {
 644              self.maybeLoad();
 645          });
 646          element.on( 'click', 'li', function( event ) {
 647              self.select( $( this ), event );
 648          });
 649      };
 650  
 651      $.extend( River.prototype, {
 652          refresh: function() {
 653              this.deselect();
 654              this.visible = this.element.is( ':visible' );
 655          },
 656          show: function() {
 657              if ( ! this.visible ) {
 658                  this.deselect();
 659                  this.element.show();
 660                  this.visible = true;
 661              }
 662          },
 663          hide: function() {
 664              this.element.hide();
 665              this.visible = false;
 666          },
 667          // Selects a list item and triggers the river-select event.
 668          select: function( li, event ) {
 669              var liHeight, elHeight, liTop, elTop;
 670  
 671              if ( li.hasClass( 'unselectable' ) || li == this.selected )
 672                  return;
 673  
 674              this.deselect();
 675              this.selected = li.addClass( 'selected' );
 676              // Make sure the element is visible.
 677              liHeight = li.outerHeight();
 678              elHeight = this.element.height();
 679              liTop = li.position().top;
 680              elTop = this.element.scrollTop();
 681  
 682              if ( liTop < 0 ) // Make first visible element.
 683                  this.element.scrollTop( elTop + liTop );
 684              else if ( liTop + liHeight > elHeight ) // Make last visible element.
 685                  this.element.scrollTop( elTop + liTop - elHeight + liHeight );
 686  
 687              // Trigger the river-select event.
 688              this.element.trigger( 'river-select', [ li, event, this ] );
 689          },
 690          deselect: function() {
 691              if ( this.selected )
 692                  this.selected.removeClass( 'selected' );
 693              this.selected = false;
 694          },
 695          prev: function() {
 696              if ( ! this.visible )
 697                  return;
 698  
 699              var to;
 700              if ( this.selected ) {
 701                  to = this.selected.prev( 'li' );
 702                  if ( to.length )
 703                      this.select( to );
 704              }
 705          },
 706          next: function() {
 707              if ( ! this.visible )
 708                  return;
 709  
 710              var to = this.selected ? this.selected.next( 'li' ) : $( 'li:not(.unselectable):first', this.element );
 711              if ( to.length )
 712                  this.select( to );
 713          },
 714          ajax: function( callback ) {
 715              var self = this,
 716                  delay = this.query.page == 1 ? 0 : wpLink.minRiverAJAXDuration,
 717                  response = wpLink.delayedCallback( function( results, params ) {
 718                      self.process( results, params );
 719                      if ( callback )
 720                          callback( results, params );
 721                  }, delay );
 722  
 723              this.query.ajax( response );
 724          },
 725          change: function( search ) {
 726              if ( this.query && this._search == search )
 727                  return;
 728  
 729              this._search = search;
 730              this.query = new Query( search );
 731              this.element.scrollTop( 0 );
 732          },
 733          process: function( results, params ) {
 734              var list = '', alt = true, classes = '',
 735                  firstPage = params.page == 1;
 736  
 737              if ( ! results ) {
 738                  if ( firstPage ) {
 739                      list += '<li class="unselectable no-matches-found"><span class="item-title"><em>' +
 740                          wpLinkL10n.noMatchesFound + '</em></span></li>';
 741                  }
 742              } else {
 743                  $.each( results, function() {
 744                      classes = alt ? 'alternate' : '';
 745                      classes += this.title ? '' : ' no-title';
 746                      list += classes ? '<li class="' + classes + '">' : '<li>';
 747                      list += '<input type="hidden" class="item-permalink" value="' + this.permalink + '" />';
 748                      list += '<span class="item-title">';
 749                      list += this.title ? this.title : wpLinkL10n.noTitle;
 750                      list += '</span><span class="item-info">' + this.info + '</span></li>';
 751                      alt = ! alt;
 752                  });
 753              }
 754  
 755              this.ul[ firstPage ? 'html' : 'append' ]( list );
 756          },
 757          maybeLoad: function() {
 758              var self = this,
 759                  el = this.element,
 760                  bottom = el.scrollTop() + el.height();
 761  
 762              if ( ! this.query.ready() || bottom < this.contentHeight.height() - wpLink.riverBottomThreshold )
 763                  return;
 764  
 765              setTimeout(function() {
 766                  var newTop = el.scrollTop(),
 767                      newBottom = newTop + el.height();
 768  
 769                  if ( ! self.query.ready() || newBottom < self.contentHeight.height() - wpLink.riverBottomThreshold )
 770                      return;
 771  
 772                  self.waiting.addClass( 'is-active' );
 773                  el.scrollTop( newTop + self.waiting.outerHeight() );
 774  
 775                  self.ajax( function() {
 776                      self.waiting.removeClass( 'is-active' );
 777                  });
 778              }, wpLink.timeToTriggerRiver );
 779          }
 780      });
 781  
 782      Query = function( search ) {
 783          this.page = 1;
 784          this.allLoaded = false;
 785          this.querying = false;
 786          this.search = search;
 787      };
 788  
 789      $.extend( Query.prototype, {
 790          ready: function() {
 791              return ! ( this.querying || this.allLoaded );
 792          },
 793          ajax: function( callback ) {
 794              var self = this,
 795                  query = {
 796                      action : 'wp-link-ajax',
 797                      page : this.page,
 798                      '_ajax_linking_nonce' : inputs.nonce.val()
 799                  };
 800  
 801              if ( this.search )
 802                  query.search = this.search;
 803  
 804              this.querying = true;
 805  
 806              $.post( window.ajaxurl, query, function( r ) {
 807                  self.page++;
 808                  self.querying = false;
 809                  self.allLoaded = ! r;
 810                  callback( r, query );
 811              }, 'json' );
 812          }
 813      });
 814  
 815      $( wpLink.init );
 816  })( jQuery, window.wpLinkL10n, window.wp );


Generated : Sat Sep 19 08:20:30 2026 Cross-referenced by PHPXref