[ Index ]

WordPress Cross Reference

title

Body

[close]

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

   1  /* global adminpage, wpActiveEditor, quicktagsL10n, wpLink, fullscreen, prompt */
   2  /*
   3   * Quicktags
   4   *
   5   * This is the HTML editor in WordPress. It can be attached to any textarea and will
   6   * append a toolbar above it. This script is self-contained (does not require external libraries).
   7   *
   8   * Run quicktags(settings) to initialize it, where settings is an object containing up to 3 properties:
   9   * settings = {
  10   *   id : 'my_id',          the HTML ID of the textarea, required
  11   *   buttons: ''            Comma separated list of the names of the default buttons to show. Optional.
  12   *                          Current list of default button names: 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close';
  13   * }
  14   *
  15   * The settings can also be a string quicktags_id.
  16   *
  17   * quicktags_id string The ID of the textarea that will be the editor canvas
  18   * buttons string Comma separated list of the default buttons names that will be shown in that instance.
  19   */
  20  
  21  // new edit toolbar used with permission
  22  // by Alex King
  23  // http://www.alexking.org/
  24  
  25  var QTags, edCanvas,
  26      edButtons = [];
  27  
  28  /* jshint ignore:start */
  29  
  30  /**
  31   * Back-compat
  32   *
  33   * Define all former global functions so plugins that hack quicktags.js directly don't cause fatal errors.
  34   */
  35  var edAddTag = function(){},
  36  edCheckOpenTags = function(){},
  37  edCloseAllTags = function(){},
  38  edInsertImage = function(){},
  39  edInsertLink = function(){},
  40  edInsertTag = function(){},
  41  edLink = function(){},
  42  edQuickLink = function(){},
  43  edRemoveTag = function(){},
  44  edShowButton = function(){},
  45  edShowLinks = function(){},
  46  edSpell = function(){},
  47  edToolbar = function(){};
  48  
  49  /**
  50   * Initialize new instance of the Quicktags editor
  51   */
  52  function quicktags(settings) {
  53      return new QTags(settings);
  54  }
  55  
  56  /**
  57   * Inserts content at the caret in the active editor (textarea)
  58   *
  59   * Added for back compatibility
  60   * @see QTags.insertContent()
  61   */
  62  function edInsertContent(bah, txt) {
  63      return QTags.insertContent(txt);
  64  }
  65  
  66  /**
  67   * Adds a button to all instances of the editor
  68   *
  69   * Added for back compatibility, use QTags.addButton() as it gives more flexibility like type of button, button placement, etc.
  70   * @see QTags.addButton()
  71   */
  72  function edButton(id, display, tagStart, tagEnd, access) {
  73      return QTags.addButton( id, display, tagStart, tagEnd, access, '', -1 );
  74  }
  75  
  76  /* jshint ignore:end */
  77  
  78  (function(){
  79      // private stuff is prefixed with an underscore
  80      var _domReady = function(func) {
  81          var t, i, DOMContentLoaded, _tryReady;
  82  
  83          if ( typeof jQuery !== 'undefined' ) {
  84              jQuery(document).ready(func);
  85          } else {
  86              t = _domReady;
  87              t.funcs = [];
  88  
  89              t.ready = function() {
  90                  if ( ! t.isReady ) {
  91                      t.isReady = true;
  92                      for ( i = 0; i < t.funcs.length; i++ ) {
  93                          t.funcs[i]();
  94                      }
  95                  }
  96              };
  97  
  98              if ( t.isReady ) {
  99                  func();
 100              } else {
 101                  t.funcs.push(func);
 102              }
 103  
 104              if ( ! t.eventAttached ) {
 105                  if ( document.addEventListener ) {
 106                      DOMContentLoaded = function(){document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false);t.ready();};
 107                      document.addEventListener('DOMContentLoaded', DOMContentLoaded, false);
 108                      window.addEventListener('load', t.ready, false);
 109                  } else if ( document.attachEvent ) {
 110                      DOMContentLoaded = function(){if (document.readyState === 'complete'){ document.detachEvent('onreadystatechange', DOMContentLoaded);t.ready();}};
 111                      document.attachEvent('onreadystatechange', DOMContentLoaded);
 112                      window.attachEvent('onload', t.ready);
 113  
 114                      _tryReady = function() {
 115                          try {
 116                              document.documentElement.doScroll('left');
 117                          } catch(e) {
 118                              setTimeout(_tryReady, 50);
 119                              return;
 120                          }
 121  
 122                          t.ready();
 123                      };
 124                      _tryReady();
 125                  }
 126  
 127                  t.eventAttached = true;
 128              }
 129          }
 130      },
 131  
 132      _datetime = (function() {
 133          var now = new Date(), zeroise;
 134  
 135          zeroise = function(number) {
 136              var str = number.toString();
 137  
 138              if ( str.length < 2 ) {
 139                  str = '0' + str;
 140              }
 141  
 142              return str;
 143          };
 144  
 145          return now.getUTCFullYear() + '-' +
 146              zeroise( now.getUTCMonth() + 1 ) + '-' +
 147              zeroise( now.getUTCDate() ) + 'T' +
 148              zeroise( now.getUTCHours() ) + ':' +
 149              zeroise( now.getUTCMinutes() ) + ':' +
 150              zeroise( now.getUTCSeconds() ) +
 151              '+00:00';
 152      })(),
 153      qt;
 154  
 155      qt = QTags = function(settings) {
 156          if ( typeof(settings) === 'string' ) {
 157              settings = {id: settings};
 158          } else if ( typeof(settings) !== 'object' ) {
 159              return false;
 160          }
 161  
 162          var t = this,
 163              id = settings.id,
 164              canvas = document.getElementById(id),
 165              name = 'qt_' + id,
 166              tb, onclick, toolbar_id;
 167  
 168          if ( !id || !canvas ) {
 169              return false;
 170          }
 171  
 172          t.name = name;
 173          t.id = id;
 174          t.canvas = canvas;
 175          t.settings = settings;
 176  
 177          if ( id === 'content' && typeof(adminpage) === 'string' && ( adminpage === 'post-new-php' || adminpage === 'post-php' ) ) {
 178              // back compat hack :-(
 179              edCanvas = canvas;
 180              toolbar_id = 'ed_toolbar';
 181          } else {
 182              toolbar_id = name + '_toolbar';
 183          }
 184  
 185          tb = document.createElement('div');
 186          tb.id = toolbar_id;
 187          tb.className = 'quicktags-toolbar';
 188  
 189          canvas.parentNode.insertBefore(tb, canvas);
 190          t.toolbar = tb;
 191  
 192          // listen for click events
 193          onclick = function(e) {
 194              e = e || window.event;
 195              var target = e.target || e.srcElement, visible = target.clientWidth || target.offsetWidth, i;
 196  
 197              // don't call the callback on pressing the accesskey when the button is not visible
 198              if ( !visible ) {
 199                  return;
 200              }
 201  
 202              // as long as it has the class ed_button, execute the callback
 203              if ( / ed_button /.test(' ' + target.className + ' ') ) {
 204                  // we have to reassign canvas here
 205                  t.canvas = canvas = document.getElementById(id);
 206                  i = target.id.replace(name + '_', '');
 207  
 208                  if ( t.theButtons[i] ) {
 209                      t.theButtons[i].callback.call(t.theButtons[i], target, canvas, t);
 210                  }
 211              }
 212          };
 213  
 214          if ( tb.addEventListener ) {
 215              tb.addEventListener('click', onclick, false);
 216          } else if ( tb.attachEvent ) {
 217              tb.attachEvent('onclick', onclick);
 218          }
 219  
 220          t.getButton = function(id) {
 221              return t.theButtons[id];
 222          };
 223  
 224          t.getButtonElement = function(id) {
 225              return document.getElementById(name + '_' + id);
 226          };
 227  
 228          qt.instances[id] = t;
 229  
 230          if ( !qt.instances[0] ) {
 231              qt.instances[0] = qt.instances[id];
 232              _domReady( function(){ qt._buttonsInit(); } );
 233          }
 234      };
 235  
 236      qt.instances = {};
 237  
 238      qt.getInstance = function(id) {
 239          return qt.instances[id];
 240      };
 241  
 242      qt._buttonsInit = function() {
 243          var t = this, canvas, name, settings, theButtons, html, inst, ed, id, i, use,
 244              defaults = ',strong,em,link,block,del,ins,img,ul,ol,li,code,more,close,';
 245  
 246          for ( inst in t.instances ) {
 247              if ( inst === 0 ) {
 248                  continue;
 249              }
 250  
 251              ed = t.instances[inst];
 252              canvas = ed.canvas;
 253              name = ed.name;
 254              settings = ed.settings;
 255              html = '';
 256              theButtons = {};
 257              use = '';
 258  
 259              // set buttons
 260              if ( settings.buttons ) {
 261                  use = ','+settings.buttons+',';
 262              }
 263  
 264              for ( i in edButtons ) {
 265                  if ( !edButtons[i] ) {
 266                      continue;
 267                  }
 268  
 269                  id = edButtons[i].id;
 270                  if ( use && defaults.indexOf( ',' + id + ',' ) !== -1 && use.indexOf( ',' + id + ',' ) === -1 ) {
 271                      continue;
 272                  }
 273  
 274                  if ( !edButtons[i].instance || edButtons[i].instance === inst ) {
 275                      theButtons[id] = edButtons[i];
 276  
 277                      if ( edButtons[i].html ) {
 278                          html += edButtons[i].html(name + '_');
 279                      }
 280                  }
 281              }
 282  
 283              if ( use && use.indexOf(',fullscreen,') !== -1 ) {
 284                  theButtons.fullscreen = new qt.FullscreenButton();
 285                  html += theButtons.fullscreen.html(name + '_');
 286              }
 287  
 288  
 289              if ( 'rtl' === document.getElementsByTagName('html')[0].dir ) {
 290                  theButtons.textdirection = new qt.TextDirectionButton();
 291                  html += theButtons.textdirection.html(name + '_');
 292              }
 293  
 294              ed.toolbar.innerHTML = html;
 295              ed.theButtons = theButtons;
 296          }
 297          t.buttonsInitDone = true;
 298      };
 299  
 300      /**
 301       * Main API function for adding a button to Quicktags
 302       *
 303       * Adds qt.Button or qt.TagButton depending on the args. The first three args are always required.
 304       * To be able to add button(s) to Quicktags, your script should be enqueued as dependent
 305       * on "quicktags" and outputted in the footer. If you are echoing JS directly from PHP,
 306       * use add_action( 'admin_print_footer_scripts', 'output_my_js', 100 ) or add_action( 'wp_footer', 'output_my_js', 100 )
 307       *
 308       * Minimum required to add a button that calls an external function:
 309       *     QTags.addButton( 'my_id', 'my button', my_callback );
 310       *     function my_callback() { alert('yeah!'); }
 311       *
 312       * Minimum required to add a button that inserts a tag:
 313       *     QTags.addButton( 'my_id', 'my button', '<span>', '</span>' );
 314       *     QTags.addButton( 'my_id2', 'my button', '<br />' );
 315       *
 316       * @param string id Required. Button HTML ID
 317       * @param string display Required. Button's value="..."
 318       * @param string|function arg1 Required. Either a starting tag to be inserted like "<span>" or a callback that is executed when the button is clicked.
 319       * @param string arg2 Optional. Ending tag like "</span>"
 320       * @param string access_key Optional. Access key for the button.
 321       * @param string title Optional. Button's title="..."
 322       * @param int priority Optional. Number representing the desired position of the button in the toolbar. 1 - 9 = first, 11 - 19 = second, 21 - 29 = third, etc.
 323       * @param string instance Optional. Limit the button to a specifric instance of Quicktags, add to all instances if not present.
 324       * @return mixed null or the button object that is needed for back-compat.
 325       */
 326      qt.addButton = function( id, display, arg1, arg2, access_key, title, priority, instance ) {
 327          var btn;
 328  
 329          if ( !id || !display ) {
 330              return;
 331          }
 332  
 333          priority = priority || 0;
 334          arg2 = arg2 || '';
 335  
 336          if ( typeof(arg1) === 'function' ) {
 337              btn = new qt.Button(id, display, access_key, title, instance);
 338              btn.callback = arg1;
 339          } else if ( typeof(arg1) === 'string' ) {
 340              btn = new qt.TagButton(id, display, arg1, arg2, access_key, title, instance);
 341          } else {
 342              return;
 343          }
 344  
 345          if ( priority === -1 ) { // back-compat
 346              return btn;
 347          }
 348  
 349          if ( priority > 0 ) {
 350              while ( typeof(edButtons[priority]) !== 'undefined' ) {
 351                  priority++;
 352              }
 353  
 354              edButtons[priority] = btn;
 355          } else {
 356              edButtons[edButtons.length] = btn;
 357          }
 358  
 359          if ( this.buttonsInitDone ) {
 360              this._buttonsInit(); // add the button HTML to all instances toolbars if addButton() was called too late
 361          }
 362      };
 363  
 364      qt.insertContent = function(content) {
 365          var sel, startPos, endPos, scrollTop, text, canvas = document.getElementById(wpActiveEditor);
 366  
 367          if ( !canvas ) {
 368              return false;
 369          }
 370  
 371          if ( document.selection ) { //IE
 372              canvas.focus();
 373              sel = document.selection.createRange();
 374              sel.text = content;
 375              canvas.focus();
 376          } else if ( canvas.selectionStart || canvas.selectionStart === 0 ) { // FF, WebKit, Opera
 377              text = canvas.value;
 378              startPos = canvas.selectionStart;
 379              endPos = canvas.selectionEnd;
 380              scrollTop = canvas.scrollTop;
 381  
 382              canvas.value = text.substring(0, startPos) + content + text.substring(endPos, text.length);
 383  
 384              canvas.focus();
 385              canvas.selectionStart = startPos + content.length;
 386              canvas.selectionEnd = startPos + content.length;
 387              canvas.scrollTop = scrollTop;
 388          } else {
 389              canvas.value += content;
 390              canvas.focus();
 391          }
 392          return true;
 393      };
 394  
 395      // a plain, dumb button
 396      qt.Button = function(id, display, access, title, instance) {
 397          var t = this;
 398          t.id = id;
 399          t.display = display;
 400          t.access = access;
 401          t.title = title || '';
 402          t.instance = instance || '';
 403      };
 404      qt.Button.prototype.html = function(idPrefix) {
 405          var access = this.access ? ' accesskey="' + this.access + '"' : '';
 406          return '<input type="button" id="' + idPrefix + this.id + '"' + access + ' class="ed_button" title="' + this.title + '" value="' + this.display + '" />';
 407      };
 408      qt.Button.prototype.callback = function(){};
 409  
 410      // a button that inserts HTML tag
 411      qt.TagButton = function(id, display, tagStart, tagEnd, access, title, instance) {
 412          var t = this;
 413          qt.Button.call(t, id, display, access, title, instance);
 414          t.tagStart = tagStart;
 415          t.tagEnd = tagEnd;
 416      };
 417      qt.TagButton.prototype = new qt.Button();
 418      qt.TagButton.prototype.openTag = function(e, ed) {
 419          var t = this;
 420  
 421          if ( ! ed.openTags ) {
 422              ed.openTags = [];
 423          }
 424          if ( t.tagEnd ) {
 425              ed.openTags.push(t.id);
 426              e.value = '/' + e.value;
 427          }
 428      };
 429      qt.TagButton.prototype.closeTag = function(e, ed) {
 430          var t = this, i = t.isOpen(ed);
 431  
 432          if ( i !== false ) {
 433              ed.openTags.splice(i, 1);
 434          }
 435  
 436          e.value = t.display;
 437      };
 438      // whether a tag is open or not. Returns false if not open, or current open depth of the tag
 439      qt.TagButton.prototype.isOpen = function (ed) {
 440          var t = this, i = 0, ret = false;
 441          if ( ed.openTags ) {
 442              while ( ret === false && i < ed.openTags.length ) {
 443                  ret = ed.openTags[i] === t.id ? i : false;
 444                  i ++;
 445              }
 446          } else {
 447              ret = false;
 448          }
 449          return ret;
 450      };
 451      qt.TagButton.prototype.callback = function(element, canvas, ed) {
 452          var t = this, startPos, endPos, cursorPos, scrollTop, v = canvas.value, l, r, i, sel, endTag = v ? t.tagEnd : '';
 453  
 454          if ( document.selection ) { // IE
 455              canvas.focus();
 456              sel = document.selection.createRange();
 457              if ( sel.text.length > 0 ) {
 458                  if ( !t.tagEnd ) {
 459                      sel.text = sel.text + t.tagStart;
 460                  } else {
 461                      sel.text = t.tagStart + sel.text + endTag;
 462                  }
 463              } else {
 464                  if ( !t.tagEnd ) {
 465                      sel.text = t.tagStart;
 466                  } else if ( t.isOpen(ed) === false ) {
 467                      sel.text = t.tagStart;
 468                      t.openTag(element, ed);
 469                  } else {
 470                      sel.text = endTag;
 471                      t.closeTag(element, ed);
 472                  }
 473              }
 474              canvas.focus();
 475          } else if ( canvas.selectionStart || canvas.selectionStart === 0 ) { // FF, WebKit, Opera
 476              startPos = canvas.selectionStart;
 477              endPos = canvas.selectionEnd;
 478              cursorPos = endPos;
 479              scrollTop = canvas.scrollTop;
 480              l = v.substring(0, startPos); // left of the selection
 481              r = v.substring(endPos, v.length); // right of the selection
 482              i = v.substring(startPos, endPos); // inside the selection
 483              if ( startPos !== endPos ) {
 484                  if ( !t.tagEnd ) {
 485                      canvas.value = l + i + t.tagStart + r; // insert self closing tags after the selection
 486                      cursorPos += t.tagStart.length;
 487                  } else {
 488                      canvas.value = l + t.tagStart + i + endTag + r;
 489                      cursorPos += t.tagStart.length + endTag.length;
 490                  }
 491              } else {
 492                  if ( !t.tagEnd ) {
 493                      canvas.value = l + t.tagStart + r;
 494                      cursorPos = startPos + t.tagStart.length;
 495                  } else if ( t.isOpen(ed) === false ) {
 496                      canvas.value = l + t.tagStart + r;
 497                      t.openTag(element, ed);
 498                      cursorPos = startPos + t.tagStart.length;
 499                  } else {
 500                      canvas.value = l + endTag + r;
 501                      cursorPos = startPos + endTag.length;
 502                      t.closeTag(element, ed);
 503                  }
 504              }
 505  
 506              canvas.focus();
 507              canvas.selectionStart = cursorPos;
 508              canvas.selectionEnd = cursorPos;
 509              canvas.scrollTop = scrollTop;
 510          } else { // other browsers?
 511              if ( !endTag ) {
 512                  canvas.value += t.tagStart;
 513              } else if ( t.isOpen(ed) !== false ) {
 514                  canvas.value += t.tagStart;
 515                  t.openTag(element, ed);
 516              } else {
 517                  canvas.value += endTag;
 518                  t.closeTag(element, ed);
 519              }
 520              canvas.focus();
 521          }
 522      };
 523  
 524      // removed
 525      qt.SpellButton = function() {};
 526  
 527      // the close tags button
 528      qt.CloseButton = function() {
 529          qt.Button.call(this, 'close', quicktagsL10n.closeTags, '', quicktagsL10n.closeAllOpenTags);
 530      };
 531  
 532      qt.CloseButton.prototype = new qt.Button();
 533  
 534      qt._close = function(e, c, ed) {
 535          var button, element, tbo = ed.openTags;
 536  
 537          if ( tbo ) {
 538              while ( tbo.length > 0 ) {
 539                  button = ed.getButton(tbo[tbo.length - 1]);
 540                  element = document.getElementById(ed.name + '_' + button.id);
 541  
 542                  if ( e ) {
 543                      button.callback.call(button, element, c, ed);
 544                  } else {
 545                      button.closeTag(element, ed);
 546                  }
 547              }
 548          }
 549      };
 550  
 551      qt.CloseButton.prototype.callback = qt._close;
 552  
 553      qt.closeAllTags = function(editor_id) {
 554          var ed = this.getInstance(editor_id);
 555          qt._close('', ed.canvas, ed);
 556      };
 557  
 558      // the link button
 559      qt.LinkButton = function() {
 560          qt.TagButton.call(this, 'link', 'link', '', '</a>', 'a');
 561      };
 562      qt.LinkButton.prototype = new qt.TagButton();
 563      qt.LinkButton.prototype.callback = function(e, c, ed, defaultValue) {
 564          var URL, t = this;
 565  
 566          if ( typeof(wpLink) !== 'undefined' ) {
 567              wpLink.open();
 568              return;
 569          }
 570  
 571          if ( ! defaultValue ) {
 572              defaultValue = 'http://';
 573          }
 574  
 575          if ( t.isOpen(ed) === false ) {
 576              URL = prompt(quicktagsL10n.enterURL, defaultValue);
 577              if ( URL ) {
 578                  t.tagStart = '<a href="' + URL + '">';
 579                  qt.TagButton.prototype.callback.call(t, e, c, ed);
 580              }
 581          } else {
 582              qt.TagButton.prototype.callback.call(t, e, c, ed);
 583          }
 584      };
 585  
 586      // the img button
 587      qt.ImgButton = function() {
 588          qt.TagButton.call(this, 'img', 'img', '', '', 'm');
 589      };
 590      qt.ImgButton.prototype = new qt.TagButton();
 591      qt.ImgButton.prototype.callback = function(e, c, ed, defaultValue) {
 592          if ( ! defaultValue ) {
 593              defaultValue = 'http://';
 594          }
 595          var src = prompt(quicktagsL10n.enterImageURL, defaultValue), alt;
 596          if ( src ) {
 597              alt = prompt(quicktagsL10n.enterImageDescription, '');
 598              this.tagStart = '<img src="' + src + '" alt="' + alt + '" />';
 599              qt.TagButton.prototype.callback.call(this, e, c, ed);
 600          }
 601      };
 602  
 603      qt.FullscreenButton = function() {
 604          qt.Button.call(this, 'fullscreen', quicktagsL10n.fullscreen, 'f', quicktagsL10n.toggleFullscreen);
 605      };
 606      qt.FullscreenButton.prototype = new qt.Button();
 607      qt.FullscreenButton.prototype.callback = function(e, c) {
 608          if ( !c.id || typeof(fullscreen) === 'undefined' ) {
 609              return;
 610          }
 611  
 612          fullscreen.on();
 613      };
 614  
 615      qt.TextDirectionButton = function() {
 616          qt.Button.call(this, 'textdirection', quicktagsL10n.textdirection, '', quicktagsL10n.toggleTextdirection);
 617      };
 618      qt.TextDirectionButton.prototype = new qt.Button();
 619      qt.TextDirectionButton.prototype.callback = function(e, c) {
 620          var isRTL = ( 'rtl' === document.getElementsByTagName('html')[0].dir ),
 621              currentDirection = c.style.direction;
 622  
 623          if ( ! currentDirection ) {
 624              currentDirection = ( isRTL ) ? 'rtl' : 'ltr';
 625          }
 626  
 627          c.style.direction = ( 'rtl' === currentDirection ) ? 'ltr' : 'rtl';
 628          c.focus();
 629      };
 630  
 631      // ensure backward compatibility
 632      edButtons[10] = new qt.TagButton('strong','b','<strong>','</strong>','b');
 633      edButtons[20] = new qt.TagButton('em','i','<em>','</em>','i'),
 634      edButtons[30] = new qt.LinkButton(), // special case
 635      edButtons[40] = new qt.TagButton('block','b-quote','\n\n<blockquote>','</blockquote>\n\n','q'),
 636      edButtons[50] = new qt.TagButton('del','del','<del datetime="' + _datetime + '">','</del>','d'),
 637      edButtons[60] = new qt.TagButton('ins','ins','<ins datetime="' + _datetime + '">','</ins>','s'),
 638      edButtons[70] = new qt.ImgButton(), // special case
 639      edButtons[80] = new qt.TagButton('ul','ul','<ul>\n','</ul>\n\n','u'),
 640      edButtons[90] = new qt.TagButton('ol','ol','<ol>\n','</ol>\n\n','o'),
 641      edButtons[100] = new qt.TagButton('li','li','\t<li>','</li>\n','l'),
 642      edButtons[110] = new qt.TagButton('code','code','<code>','</code>','c'),
 643      edButtons[120] = new qt.TagButton('more','more','<!--more-->','','t'),
 644      edButtons[140] = new qt.CloseButton();
 645  
 646  })();


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