[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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


Generated: Fri May 25 03:56:23 2012 Hosted by follow the white rabbit.