[ Index ]

WordPress Cross Reference

title

Body

[close]

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

   1  /* global ajaxurl, tinymce, wpLinkL10n, tinyMCEPopup, setUserSetting, wpActiveEditor */
   2  var wpLink;
   3  
   4  (function($){
   5      var inputs = {}, rivers = {}, ed, River, Query;
   6  
   7      wpLink = {
   8          timeToTriggerRiver: 150,
   9          minRiverAJAXDuration: 200,
  10          riverBottomThreshold: 5,
  11          keySensitivity: 100,
  12          lastSearch: '',
  13          textarea: '',
  14  
  15          init : function() {
  16              inputs.dialog = $('#wp-link');
  17              inputs.submit = $('#wp-link-submit');
  18              // URL
  19              inputs.url = $('#url-field');
  20              inputs.nonce = $('#_ajax_linking_nonce');
  21              // Secondary options
  22              inputs.title = $('#link-title-field');
  23              // Advanced Options
  24              inputs.openInNewTab = $('#link-target-checkbox');
  25              inputs.search = $('#search-field');
  26              // Build Rivers
  27              rivers.search = new River( $('#search-results') );
  28              rivers.recent = new River( $('#most-recent-results') );
  29              rivers.elements = $('.query-results', inputs.dialog);
  30  
  31              // Bind event handlers
  32              inputs.dialog.keydown( wpLink.keydown );
  33              inputs.dialog.keyup( wpLink.keyup );
  34              inputs.submit.click( function(e){
  35                  e.preventDefault();
  36                  wpLink.update();
  37              });
  38              $('#wp-link-cancel').click( function(e){
  39                  e.preventDefault();
  40                  wpLink.close();
  41              });
  42              $('#internal-toggle').click( wpLink.toggleInternalLinking );
  43  
  44              rivers.elements.bind('river-select', wpLink.updateFields );
  45  
  46              inputs.search.keyup( wpLink.searchInternalLinks );
  47  
  48              inputs.dialog.bind('wpdialogrefresh', wpLink.refresh);
  49              inputs.dialog.bind('wpdialogbeforeopen', wpLink.beforeOpen);
  50              inputs.dialog.bind('wpdialogclose', wpLink.onClose);
  51          },
  52  
  53          beforeOpen : function() {
  54              wpLink.range = null;
  55  
  56              if ( ! wpLink.isMCE() && document.selection ) {
  57                  wpLink.textarea.focus();
  58                  wpLink.range = document.selection.createRange();
  59              }
  60          },
  61  
  62          open : function() {
  63              if ( !wpActiveEditor )
  64                  return;
  65  
  66              this.textarea = $('#'+wpActiveEditor).get(0);
  67  
  68              // Initialize the dialog if necessary (html mode).
  69              if ( ! inputs.dialog.data('wpdialog') ) {
  70                  inputs.dialog.wpdialog({
  71                      title: wpLinkL10n.title,
  72                      width: 480,
  73                      height: 'auto',
  74                      modal: true,
  75                      dialogClass: 'wp-dialog'
  76                  });
  77              }
  78  
  79              inputs.dialog.wpdialog('open');
  80          },
  81  
  82          isMCE : function() {
  83              return tinyMCEPopup && ( ed = tinyMCEPopup.editor ) && ! ed.isHidden();
  84          },
  85  
  86          refresh : function() {
  87              // Refresh rivers (clear links, check visibility)
  88              rivers.search.refresh();
  89              rivers.recent.refresh();
  90  
  91              if ( wpLink.isMCE() )
  92                  wpLink.mceRefresh();
  93              else
  94                  wpLink.setDefaultValues();
  95  
  96              // Focus the URL field and highlight its contents.
  97              //     If this is moved above the selection changes,
  98              //     IE will show a flashing cursor over the dialog.
  99              inputs.url.focus()[0].select();
 100              // Load the most recent results if this is the first time opening the panel.
 101              if ( ! rivers.recent.ul.children().length )
 102                  rivers.recent.ajax();
 103          },
 104  
 105          mceRefresh : function() {
 106              var e;
 107              ed = tinyMCEPopup.editor;
 108  
 109              tinyMCEPopup.restoreSelection();
 110  
 111              // If link exists, select proper values.
 112              if ( e = ed.dom.getParent(ed.selection.getNode(), 'A') ) {
 113                  // Set URL and description.
 114                  inputs.url.val( ed.dom.getAttrib(e, 'href') );
 115                  inputs.title.val( ed.dom.getAttrib(e, 'title') );
 116                  // Set open in new tab.
 117                  inputs.openInNewTab.prop('checked', ( '_blank' == ed.dom.getAttrib( e, 'target' ) ) );
 118                  // Update save prompt.
 119                  inputs.submit.val( wpLinkL10n.update );
 120  
 121              // If there's no link, set the default values.
 122              } else {
 123                  wpLink.setDefaultValues();
 124              }
 125          },
 126  
 127          close : function() {
 128              if ( wpLink.isMCE() )
 129                  tinyMCEPopup.close();
 130              else
 131                  inputs.dialog.wpdialog('close');
 132          },
 133  
 134          onClose: function() {
 135              if ( ! wpLink.isMCE() ) {
 136                  wpLink.textarea.focus();
 137                  if ( wpLink.range ) {
 138                      wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
 139                      wpLink.range.select();
 140                  }
 141              }
 142          },
 143  
 144          getAttrs : function() {
 145              return {
 146                  href : inputs.url.val(),
 147                  title : inputs.title.val(),
 148                  target : inputs.openInNewTab.prop('checked') ? '_blank' : ''
 149              };
 150          },
 151  
 152          update : function() {
 153              if ( wpLink.isMCE() )
 154                  wpLink.mceUpdate();
 155              else
 156                  wpLink.htmlUpdate();
 157          },
 158  
 159          htmlUpdate : function() {
 160              var attrs, html, begin, end, cursor, selection,
 161                  textarea = wpLink.textarea;
 162  
 163              if ( ! textarea )
 164                  return;
 165  
 166              attrs = wpLink.getAttrs();
 167  
 168              // If there's no href, return.
 169              if ( ! attrs.href || attrs.href == 'http://' )
 170                  return;
 171  
 172              // Build HTML
 173              html = '<a href="' + attrs.href + '"';
 174  
 175              if ( attrs.title )
 176                  html += ' title="' + attrs.title + '"';
 177              if ( attrs.target )
 178                  html += ' target="' + attrs.target + '"';
 179  
 180              html += '>';
 181  
 182              // Insert HTML
 183              if ( document.selection && wpLink.range ) {
 184                  // IE
 185                  // Note: If no text is selected, IE will not place the cursor
 186                  //       inside the closing tag.
 187                  textarea.focus();
 188                  wpLink.range.text = html + wpLink.range.text + '</a>';
 189                  wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
 190                  wpLink.range.select();
 191  
 192                  wpLink.range = null;
 193              } else if ( typeof textarea.selectionStart !== 'undefined' ) {
 194                  // W3C
 195                  begin       = textarea.selectionStart;
 196                  end         = textarea.selectionEnd;
 197                  selection   = textarea.value.substring( begin, end );
 198                  html        = html + selection + '</a>';
 199                  cursor      = begin + html.length;
 200  
 201                  // If no text is selected, place the cursor inside the closing tag.
 202                  if ( begin == end )
 203                      cursor -= '</a>'.length;
 204  
 205                  textarea.value = textarea.value.substring( 0, begin ) + html +
 206                      textarea.value.substring( end, textarea.value.length );
 207  
 208                  // Update cursor position
 209                  textarea.selectionStart = textarea.selectionEnd = cursor;
 210              }
 211  
 212              wpLink.close();
 213              textarea.focus();
 214          },
 215  
 216          mceUpdate : function() {
 217              var ed = tinyMCEPopup.editor,
 218                  attrs = wpLink.getAttrs(),
 219                  e, b;
 220  
 221              tinyMCEPopup.restoreSelection();
 222              e = ed.dom.getParent(ed.selection.getNode(), 'A');
 223  
 224              // If the values are empty, unlink and return
 225              if ( ! attrs.href || attrs.href == 'http://' ) {
 226                  if ( e ) {
 227                      b = ed.selection.getBookmark();
 228                      ed.dom.remove(e, 1);
 229                      ed.selection.moveToBookmark(b);
 230                      tinyMCEPopup.execCommand('mceEndUndoLevel');
 231                      wpLink.close();
 232                  }
 233                  return;
 234              }
 235  
 236              if (e == null) {
 237                  ed.getDoc().execCommand('unlink', false, null);
 238                  tinyMCEPopup.execCommand('mceInsertLink', false, '#mce_temp_url#', {skip_undo : 1});
 239  
 240                  tinymce.each(ed.dom.select('a'), function(n) {
 241                      if (ed.dom.getAttrib(n, 'href') == '#mce_temp_url#') {
 242                          e = n;
 243                          ed.dom.setAttribs(e, attrs);
 244                      }
 245                  });
 246  
 247                  // Sometimes WebKit lets a user create a link where
 248                  // they shouldn't be able to. In this case, CreateLink
 249                  // injects "#mce_temp_url#" into their content. Fix it.
 250                  if ( tinymce.isWebKit && $(e).text() == '#mce_temp_url#' ) {
 251                      ed.dom.remove(e);
 252                      e = null;
 253                  }
 254              } else {
 255                  ed.dom.setAttribs(e, attrs);
 256              }
 257  
 258              // Move the caret if selection was not an image.
 259              if ( e && (e.childNodes.length != 1 || e.firstChild.nodeName != 'IMG') ) {
 260                  ed.selection.select(e);
 261                  ed.selection.collapse(0);
 262                  tinyMCEPopup.storeSelection();
 263              }
 264  
 265              ed.execCommand('mceEndUndoLevel');
 266              wpLink.close();
 267              ed.focus();
 268          },
 269  
 270          updateFields : function( e, li, originalEvent ) {
 271              inputs.url.val( li.children('.item-permalink').val() );
 272              inputs.title.val( li.hasClass('no-title') ? '' : li.children('.item-title').text() );
 273              if ( originalEvent && originalEvent.type == 'click' )
 274                  inputs.url.focus();
 275          },
 276          setDefaultValues : function() {
 277              // Set URL and description to defaults.
 278              // Leave the new tab setting as-is.
 279              inputs.url.val('http://');
 280              inputs.title.val('');
 281  
 282              // Update save prompt.
 283              inputs.submit.val( wpLinkL10n.save );
 284          },
 285  
 286          searchInternalLinks : function() {
 287              var t = $(this), waiting,
 288                  search = t.val();
 289  
 290              if ( search.length > 2 ) {
 291                  rivers.recent.hide();
 292                  rivers.search.show();
 293  
 294                  // Don't search if the keypress didn't change the title.
 295                  if ( wpLink.lastSearch == search )
 296                      return;
 297  
 298                  wpLink.lastSearch = search;
 299                  waiting = t.parent().find('.spinner').show();
 300  
 301                  rivers.search.change( search );
 302                  rivers.search.ajax( function(){ waiting.hide(); });
 303              } else {
 304                  rivers.search.hide();
 305                  rivers.recent.show();
 306              }
 307          },
 308  
 309          next : function() {
 310              rivers.search.next();
 311              rivers.recent.next();
 312          },
 313          prev : function() {
 314              rivers.search.prev();
 315              rivers.recent.prev();
 316          },
 317  
 318          keydown : function( event ) {
 319              var fn, key = $.ui.keyCode;
 320  
 321              if ( event.which !== key.UP && event.which !== key.DOWN ) {
 322                  return;
 323              }
 324  
 325              fn = event.which === key.UP ? 'prev' : 'next';
 326              clearInterval( wpLink.keyInterval );
 327              wpLink[ fn ]();
 328              wpLink.keyInterval = setInterval( wpLink[ fn ], wpLink.keySensitivity );
 329              event.preventDefault();
 330          },
 331  
 332          keyup: function( event ) {
 333              var key = $.ui.keyCode;
 334  
 335              if ( event.which === key.ESCAPE ) {
 336                  event.stopImmediatePropagation();
 337                  if ( ! $(document).triggerHandler( 'wp_CloseOnEscape', [{ event: event, what: 'wplink', cb: wpLink.close }] ) )
 338                      wpLink.close();
 339                  return false;
 340              }
 341  
 342              if ( event.which === key.UP || event.which === key.DOWN ) {
 343                  clearInterval( wpLink.keyInterval );
 344                  event.preventDefault();
 345              }
 346          },
 347  
 348          delayedCallback : function( func, delay ) {
 349              var timeoutTriggered, funcTriggered, funcArgs, funcContext;
 350  
 351              if ( ! delay )
 352                  return func;
 353  
 354              setTimeout( function() {
 355                  if ( funcTriggered )
 356                      return func.apply( funcContext, funcArgs );
 357                  // Otherwise, wait.
 358                  timeoutTriggered = true;
 359              }, delay);
 360  
 361              return function() {
 362                  if ( timeoutTriggered )
 363                      return func.apply( this, arguments );
 364                  // Otherwise, wait.
 365                  funcArgs = arguments;
 366                  funcContext = this;
 367                  funcTriggered = true;
 368              };
 369          },
 370  
 371          toggleInternalLinking : function( event ) {
 372              var panel = $('#search-panel'),
 373                  widget = inputs.dialog.wpdialog('widget'),
 374                  // We're about to toggle visibility; it's currently the opposite
 375                  visible = !panel.is(':visible'),
 376                  win = $(window);
 377  
 378              $(this).toggleClass('toggle-arrow-active', visible);
 379  
 380              inputs.dialog.height('auto');
 381              panel.slideToggle( 300, function() {
 382                  setUserSetting('wplink', visible ? '1' : '0');
 383                  inputs[ visible ? 'search' : 'url' ].focus();
 384  
 385                  // Move the box if the box is now expanded, was opened in a collapsed state,
 386                  // and if it needs to be moved. (Judged by bottom not being positive or
 387                  // bottom being smaller than top.)
 388                  var scroll = win.scrollTop(),
 389                      top = widget.offset().top,
 390                      bottom = top + widget.outerHeight(),
 391                      diff = bottom - win.height();
 392  
 393                  if ( diff > scroll ) {
 394                      widget.animate({'top': diff < top ?  top - diff : scroll }, 200);
 395                  }
 396              });
 397              event.preventDefault();
 398          }
 399      };
 400  
 401      River = function( element, search ) {
 402          var self = this;
 403          this.element = element;
 404          this.ul = element.children('ul');
 405          this.waiting = element.find('.river-waiting');
 406  
 407          this.change( search );
 408          this.refresh();
 409  
 410          element.scroll( function(){ self.maybeLoad(); });
 411          element.delegate('li', 'click', function(e){ self.select( $(this), e ); });
 412      };
 413  
 414      $.extend( River.prototype, {
 415          refresh: function() {
 416              this.deselect();
 417              this.visible = this.element.is(':visible');
 418          },
 419          show: function() {
 420              if ( ! this.visible ) {
 421                  this.deselect();
 422                  this.element.show();
 423                  this.visible = true;
 424              }
 425          },
 426          hide: function() {
 427              this.element.hide();
 428              this.visible = false;
 429          },
 430          // Selects a list item and triggers the river-select event.
 431          select: function( li, event ) {
 432              var liHeight, elHeight, liTop, elTop;
 433  
 434              if ( li.hasClass('unselectable') || li == this.selected )
 435                  return;
 436  
 437              this.deselect();
 438              this.selected = li.addClass('selected');
 439              // Make sure the element is visible
 440              liHeight = li.outerHeight();
 441              elHeight = this.element.height();
 442              liTop = li.position().top;
 443              elTop = this.element.scrollTop();
 444  
 445              if ( liTop < 0 ) // Make first visible element
 446                  this.element.scrollTop( elTop + liTop );
 447              else if ( liTop + liHeight > elHeight ) // Make last visible element
 448                  this.element.scrollTop( elTop + liTop - elHeight + liHeight );
 449  
 450              // Trigger the river-select event
 451              this.element.trigger('river-select', [ li, event, this ]);
 452          },
 453          deselect: function() {
 454              if ( this.selected )
 455                  this.selected.removeClass('selected');
 456              this.selected = false;
 457          },
 458          prev: function() {
 459              if ( ! this.visible )
 460                  return;
 461  
 462              var to;
 463              if ( this.selected ) {
 464                  to = this.selected.prev('li');
 465                  if ( to.length )
 466                      this.select( to );
 467              }
 468          },
 469          next: function() {
 470              if ( ! this.visible )
 471                  return;
 472  
 473              var to = this.selected ? this.selected.next('li') : $('li:not(.unselectable):first', this.element);
 474              if ( to.length )
 475                  this.select( to );
 476          },
 477          ajax: function( callback ) {
 478              var self = this,
 479                  delay = this.query.page == 1 ? 0 : wpLink.minRiverAJAXDuration,
 480                  response = wpLink.delayedCallback( function( results, params ) {
 481                      self.process( results, params );
 482                      if ( callback )
 483                          callback( results, params );
 484                  }, delay );
 485  
 486              this.query.ajax( response );
 487          },
 488          change: function( search ) {
 489              if ( this.query && this._search == search )
 490                  return;
 491  
 492              this._search = search;
 493              this.query = new Query( search );
 494              this.element.scrollTop(0);
 495          },
 496          process: function( results, params ) {
 497              var list = '', alt = true, classes = '',
 498                  firstPage = params.page == 1;
 499  
 500              if ( !results ) {
 501                  if ( firstPage ) {
 502                      list += '<li class="unselectable"><span class="item-title"><em>' +
 503                          wpLinkL10n.noMatchesFound + '</em></span></li>';
 504                  }
 505              } else {
 506                  $.each( results, function() {
 507                      classes = alt ? 'alternate' : '';
 508                      classes += this.title ? '' : ' no-title';
 509                      list += classes ? '<li class="' + classes + '">' : '<li>';
 510                      list += '<input type="hidden" class="item-permalink" value="' + this.permalink + '" />';
 511                      list += '<span class="item-title">';
 512                      list += this.title ? this.title : wpLinkL10n.noTitle;
 513                      list += '</span><span class="item-info">' + this.info + '</span></li>';
 514                      alt = ! alt;
 515                  });
 516              }
 517  
 518              this.ul[ firstPage ? 'html' : 'append' ]( list );
 519          },
 520          maybeLoad: function() {
 521              var self = this,
 522                  el = this.element,
 523                  bottom = el.scrollTop() + el.height();
 524  
 525              if ( ! this.query.ready() || bottom < this.ul.height() - wpLink.riverBottomThreshold )
 526                  return;
 527  
 528              setTimeout(function() {
 529                  var newTop = el.scrollTop(),
 530                      newBottom = newTop + el.height();
 531  
 532                  if ( ! self.query.ready() || newBottom < self.ul.height() - wpLink.riverBottomThreshold )
 533                      return;
 534  
 535                  self.waiting.show();
 536                  el.scrollTop( newTop + self.waiting.outerHeight() );
 537  
 538                  self.ajax( function() { self.waiting.hide(); });
 539              }, wpLink.timeToTriggerRiver );
 540          }
 541      });
 542  
 543      Query = function( search ) {
 544          this.page = 1;
 545          this.allLoaded = false;
 546          this.querying = false;
 547          this.search = search;
 548      };
 549  
 550      $.extend( Query.prototype, {
 551          ready: function() {
 552              return !( this.querying || this.allLoaded );
 553          },
 554          ajax: function( callback ) {
 555              var self = this,
 556                  query = {
 557                      action : 'wp-link-ajax',
 558                      page : this.page,
 559                      '_ajax_linking_nonce' : inputs.nonce.val()
 560                  };
 561  
 562              if ( this.search )
 563                  query.search = this.search;
 564  
 565              this.querying = true;
 566  
 567              $.post( ajaxurl, query, function(r) {
 568                  self.page++;
 569                  self.querying = false;
 570                  self.allLoaded = !r;
 571                  callback( r, query );
 572              }, 'json' );
 573          }
 574      });
 575  
 576      $(document).ready( wpLink.init );
 577  })(jQuery);


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu