[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/tinymce/plugins/wordpress/ -> plugin.js (source)

   1  /* global getUserSetting, setUserSetting */
   2  ( function( tinymce ) {
   3  // Set the minimum value for the modals z-index higher than #wpadminbar (100000).
   4  if ( ! tinymce.ui.FloatPanel.zIndex || tinymce.ui.FloatPanel.zIndex < 100100 ) {
   5      tinymce.ui.FloatPanel.zIndex = 100100;
   6  }
   7  
   8  tinymce.PluginManager.add( 'wordpress', function( editor ) {
   9      var wpAdvButton, style,
  10          DOM = tinymce.DOM,
  11          each = tinymce.each,
  12          __ = editor.editorManager.i18n.translate,
  13          $ = window.jQuery,
  14          wp = window.wp,
  15          hasWpautop = ( wp && wp.editor && wp.editor.autop && editor.getParam( 'wpautop', true ) ),
  16          wpTooltips = false;
  17  
  18      if ( $ ) {
  19          // Runs as soon as TinyMCE has started initializing, while plugins are loading.
  20          // Handlers attached after the `tinymce.init()` call may not get triggered for this instance.
  21          $( document ).triggerHandler( 'tinymce-editor-setup', [ editor ] );
  22      }
  23  
  24  	function toggleToolbars( state ) {
  25          var initial, toolbars, iframeHeight,
  26              pixels = 0,
  27              classicBlockToolbar = tinymce.$( '.block-library-classic__toolbar' );
  28  
  29          if ( state === 'hide' ) {
  30              initial = true;
  31          } else if ( classicBlockToolbar.length && ! classicBlockToolbar.hasClass( 'has-advanced-toolbar' ) ) {
  32              // Show the second, third, etc. toolbar rows in the Classic block instance.
  33              classicBlockToolbar.addClass( 'has-advanced-toolbar' );
  34              state = 'show';
  35          }
  36  
  37          if ( editor.theme.panel ) {
  38              toolbars = editor.theme.panel.find('.toolbar:not(.menubar)');
  39          }
  40  
  41          if ( toolbars && toolbars.length > 1 ) {
  42              if ( ! state && toolbars[1].visible() ) {
  43                  state = 'hide';
  44              }
  45  
  46              each( toolbars, function( toolbar, i ) {
  47                  if ( i > 0 ) {
  48                      if ( state === 'hide' ) {
  49                          toolbar.hide();
  50                          pixels += 34;
  51                      } else {
  52                          toolbar.show();
  53                          pixels -= 34;
  54                      }
  55                  }
  56              });
  57          }
  58  
  59          // Resize editor iframe, not needed for iOS and inline instances.
  60          // Don't resize if the editor is in a hidden container.
  61          if ( pixels && ! tinymce.Env.iOS && editor.iframeElement && editor.iframeElement.clientHeight ) {
  62              iframeHeight = editor.iframeElement.clientHeight + pixels;
  63  
  64              // Keep min-height.
  65              if ( iframeHeight > 50  ) {
  66                  DOM.setStyle( editor.iframeElement, 'height', iframeHeight );
  67              }
  68          }
  69  
  70          if ( ! initial ) {
  71              if ( state === 'hide' ) {
  72                  setUserSetting( 'hidetb', '0' );
  73                  wpAdvButton && wpAdvButton.active( false );
  74              } else {
  75                  setUserSetting( 'hidetb', '1' );
  76                  wpAdvButton && wpAdvButton.active( true );
  77              }
  78          }
  79  
  80          editor.fire( 'wp-toolbar-toggle' );
  81      }
  82  
  83      // Add the kitchen sink button :)
  84      editor.addButton( 'wp_adv', {
  85          tooltip: 'Toolbar Toggle',
  86          cmd: 'WP_Adv',
  87          onPostRender: function() {
  88              wpAdvButton = this;
  89              wpAdvButton.active( getUserSetting( 'hidetb' ) === '1' );
  90          }
  91      });
  92  
  93      // Hide the toolbars after loading.
  94      editor.on( 'PostRender', function() {
  95          if ( editor.getParam( 'wordpress_adv_hidden', true ) && getUserSetting( 'hidetb', '0' ) === '0' ) {
  96              toggleToolbars( 'hide' );
  97          } else {
  98              tinymce.$( '.block-library-classic__toolbar' ).addClass( 'has-advanced-toolbar' );
  99          }
 100      });
 101  
 102      editor.addCommand( 'WP_Adv', function() {
 103          toggleToolbars();
 104      });
 105  
 106      editor.on( 'focus', function() {
 107          window.wpActiveEditor = editor.id;
 108      });
 109  
 110      editor.on( 'BeforeSetContent', function( event ) {
 111          var title;
 112  
 113          if ( event.content ) {
 114              if ( event.content.indexOf( '<!--more' ) !== -1 ) {
 115                  title = __( 'Read more...' );
 116  
 117                  event.content = event.content.replace( /<!--more(.*?)-->/g, function( match, moretext ) {
 118                      return '<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="more" data-wp-more-text="' + moretext + '" ' +
 119                          'class="wp-more-tag mce-wp-more" alt="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />';
 120                  });
 121              }
 122  
 123              if ( event.content.indexOf( '<!--nextpage-->' ) !== -1 ) {
 124                  title = __( 'Page break' );
 125  
 126                  event.content = event.content.replace( /<!--nextpage-->/g,
 127                      '<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="nextpage" class="wp-more-tag mce-wp-nextpage" ' +
 128                          'alt="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />' );
 129              }
 130  
 131              if ( event.load && event.format !== 'raw' ) {
 132                  if ( hasWpautop ) {
 133                      event.content = wp.editor.autop( event.content );
 134                  } else {
 135                      // Prevent creation of paragraphs out of multiple HTML comments.
 136                      event.content = event.content.replace( /-->\s+<!--/g, '--><!--' );
 137                  }
 138              }
 139  
 140              if ( event.content.indexOf( '<script' ) !== -1 || event.content.indexOf( '<style' ) !== -1 ) {
 141                  event.content = event.content.replace( /<(script|style)[^>]*>[\s\S]*?<\/\1>/g, function( match, tag ) {
 142                      return '<img ' +
 143                          'src="' + tinymce.Env.transparentSrc + '" ' +
 144                          'data-wp-preserve="' + encodeURIComponent( match ) + '" ' +
 145                          'data-mce-resize="false" ' +
 146                          'data-mce-placeholder="1" '+
 147                          'class="mce-object mce-object-' + tag + '" ' +
 148                          'width="20" height="20" '+
 149                          'alt="&lt;' + tag + '&gt;" ' +
 150                      '/>';
 151                  } );
 152              }
 153          }
 154      });
 155  
 156      editor.on( 'setcontent', function() {
 157          // Remove spaces from empty paragraphs.
 158          editor.$( 'p' ).each( function( i, node ) {
 159              if ( node.innerHTML && node.innerHTML.length < 10 ) {
 160                  var html = tinymce.trim( node.innerHTML );
 161  
 162                  if ( ! html || html === '&nbsp;' ) {
 163                      node.innerHTML = ( tinymce.Env.ie && tinymce.Env.ie < 11 ) ? '' : '<br data-mce-bogus="1">';
 164                  }
 165              }
 166          } );
 167      });
 168  
 169      editor.on( 'PostProcess', function( event ) {
 170          if ( event.get ) {
 171              event.content = event.content.replace(/<img[^>]+>/g, function( image ) {
 172                  var match,
 173                      string,
 174                      moretext = '';
 175  
 176                  if ( image.indexOf( 'data-wp-more="more"' ) !== -1 ) {
 177                      if ( match = image.match( /data-wp-more-text="([^"]+)"/ ) ) {
 178                          moretext = match[1];
 179                      }
 180  
 181                      string = '<!--more' + moretext + '-->';
 182                  } else if ( image.indexOf( 'data-wp-more="nextpage"' ) !== -1 ) {
 183                      string = '<!--nextpage-->';
 184                  } else if ( image.indexOf( 'data-wp-preserve' ) !== -1 ) {
 185                      if ( match = image.match( / data-wp-preserve="([^"]+)"/ ) ) {
 186                          string = decodeURIComponent( match[1] );
 187                      }
 188                  }
 189  
 190                  return string || image;
 191              });
 192          }
 193      });
 194  
 195      // Display the tag name instead of img in element path.
 196      editor.on( 'ResolveName', function( event ) {
 197          var attr;
 198  
 199          if ( event.target.nodeName === 'IMG' && ( attr = editor.dom.getAttrib( event.target, 'data-wp-more' ) ) ) {
 200              event.name = attr;
 201          }
 202      });
 203  
 204      // Register commands.
 205      editor.addCommand( 'WP_More', function( tag ) {
 206          var parent, html, title,
 207              classname = 'wp-more-tag',
 208              dom = editor.dom,
 209              node = editor.selection.getNode(),
 210              rootNode = editor.getBody();
 211  
 212          tag = tag || 'more';
 213          classname += ' mce-wp-' + tag;
 214          title = tag === 'more' ? 'Read more...' : 'Next page';
 215          title = __( title );
 216          html = '<img src="' + tinymce.Env.transparentSrc + '" alt="' + title + '" class="' + classname + '" ' +
 217              'data-wp-more="' + tag + '" data-mce-resize="false" data-mce-placeholder="1" />';
 218  
 219          // Most common case.
 220          if ( node === rootNode || ( node.nodeName === 'P' && node.parentNode === rootNode ) ) {
 221              editor.insertContent( html );
 222              return;
 223          }
 224  
 225          // Get the top level parent node.
 226          parent = dom.getParent( node, function( found ) {
 227              if ( found.parentNode && found.parentNode === rootNode ) {
 228                  return true;
 229              }
 230  
 231              return false;
 232          }, editor.getBody() );
 233  
 234          if ( parent ) {
 235              if ( parent.nodeName === 'P' ) {
 236                  parent.appendChild( dom.create( 'p', null, html ).firstChild );
 237              } else {
 238                  dom.insertAfter( dom.create( 'p', null, html ), parent );
 239              }
 240  
 241              editor.nodeChanged();
 242          }
 243      });
 244  
 245      editor.addCommand( 'WP_Code', function() {
 246          editor.formatter.toggle('code');
 247      });
 248  
 249      editor.addCommand( 'WP_Page', function() {
 250          editor.execCommand( 'WP_More', 'nextpage' );
 251      });
 252  
 253      editor.addCommand( 'WP_Help', function() {
 254          var access = tinymce.Env.mac ? __( 'Ctrl + Alt + letter:' ) : __( 'Shift + Alt + letter:' ),
 255              meta = tinymce.Env.mac ? __( '⌘ + letter:' ) : __( 'Ctrl + letter:' ),
 256              table1 = [],
 257              table2 = [],
 258              row1 = {},
 259              row2 = {},
 260              i1 = 0,
 261              i2 = 0,
 262              labels = editor.settings.wp_shortcut_labels,
 263              header, html, dialog, $wrap;
 264  
 265          if ( ! labels ) {
 266              return;
 267          }
 268  
 269          function tr( row, columns ) {
 270              var out = '<tr>';
 271              var i = 0;
 272  
 273              columns = columns || 1;
 274  
 275              each( row, function( text, key ) {
 276                  out += '<td><kbd>' + key + '</kbd></td><td>' + __( text ) + '</td>';
 277                  i++;
 278              });
 279  
 280              while ( i < columns ) {
 281                  out += '<td></td><td></td>';
 282                  i++;
 283              }
 284  
 285              return out + '</tr>';
 286          }
 287  
 288          each ( labels, function( label, name ) {
 289              var letter;
 290  
 291              if ( label.indexOf( 'meta' ) !== -1 ) {
 292                  i1++;
 293                  letter = label.replace( 'meta', '' ).toLowerCase();
 294  
 295                  if ( letter ) {
 296                      row1[ letter ] = name;
 297  
 298                      if ( i1 % 2 === 0 ) {
 299                          table1.push( tr( row1, 2 ) );
 300                          row1 = {};
 301                      }
 302                  }
 303              } else if ( label.indexOf( 'access' ) !== -1 ) {
 304                  i2++;
 305                  letter = label.replace( 'access', '' ).toLowerCase();
 306  
 307                  if ( letter ) {
 308                      row2[ letter ] = name;
 309  
 310                      if ( i2 % 2 === 0 ) {
 311                          table2.push( tr( row2, 2 ) );
 312                          row2 = {};
 313                      }
 314                  }
 315              }
 316          } );
 317  
 318          // Add remaining single entries.
 319          if ( i1 % 2 > 0 ) {
 320              table1.push( tr( row1, 2 ) );
 321          }
 322  
 323          if ( i2 % 2 > 0 ) {
 324              table2.push( tr( row2, 2 ) );
 325          }
 326  
 327          header = [ __( 'Letter' ), __( 'Action' ), __( 'Letter' ), __( 'Action' ) ];
 328          header = '<tr><th>' + header.join( '</th><th>' ) + '</th></tr>';
 329  
 330          html = '<div class="wp-editor-help">';
 331  
 332          // Main section, default and additional shortcuts.
 333          html = html +
 334              '<h2>' + __( 'Default shortcuts,' ) + ' ' + meta + '</h2>' +
 335              '<table class="wp-help-th-center fixed">' +
 336                  header +
 337                  table1.join('') +
 338              '</table>' +
 339              '<h2>' + __( 'Additional shortcuts,' ) + ' ' + access + '</h2>' +
 340              '<table class="wp-help-th-center fixed">' +
 341                  header +
 342                  table2.join('') +
 343              '</table>';
 344  
 345          if ( editor.plugins.wptextpattern && ( ! tinymce.Env.ie || tinymce.Env.ie > 8 ) ) {
 346              // Text pattern section.
 347              html = html +
 348                  '<h2>' + __( 'When starting a new paragraph with one of these formatting shortcuts followed by a space, the formatting will be applied automatically. Press Backspace or Escape to undo.' ) + '</h2>' +
 349                  '<table class="wp-help-th-center fixed">' +
 350                      tr({ '*':  'Bullet list', '1.':  'Numbered list' }) +
 351                      tr({ '-':  'Bullet list', '1)':  'Numbered list' }) +
 352                  '</table>';
 353  
 354              html = html +
 355                  '<h2>' + __( 'The following formatting shortcuts are replaced when pressing Enter. Press Escape or the Undo button to undo.' ) + '</h2>' +
 356                  '<table class="wp-help-single">' +
 357                      tr({ '>': 'Blockquote' }) +
 358                      tr({ '##': 'Heading 2' }) +
 359                      tr({ '###': 'Heading 3' }) +
 360                      tr({ '####': 'Heading 4' }) +
 361                      tr({ '#####': 'Heading 5' }) +
 362                      tr({ '######': 'Heading 6' }) +
 363                      tr({ '---': 'Horizontal line' }) +
 364                  '</table>';
 365          }
 366  
 367          // Focus management section.
 368          html = html +
 369              '<h2>' + __( 'Focus shortcuts:' ) + '</h2>' +
 370              '<table class="wp-help-single">' +
 371                  tr({ 'Alt + F8':  'Inline toolbar (when an image, link or preview is selected)' }) +
 372                  tr({ 'Alt + F9':  'Editor menu (when enabled)' }) +
 373                  tr({ 'Alt + F10': 'Editor toolbar' }) +
 374                  tr({ 'Alt + F11': 'Elements path' }) +
 375              '</table>' +
 376              '<p>' + __( 'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' ) + '</p>';
 377  
 378          html += '</div>';
 379  
 380          dialog = editor.windowManager.open( {
 381              title: editor.settings.classic_block_editor ? 'Classic Block Keyboard Shortcuts' : 'Keyboard Shortcuts',
 382              items: {
 383                  type: 'container',
 384                  classes: 'wp-help',
 385                  html: html
 386              },
 387              buttons: {
 388                  text: 'Close',
 389                  onclick: 'close'
 390              }
 391          } );
 392  
 393          if ( dialog.$el ) {
 394              dialog.$el.find( 'div[role="application"]' ).attr( 'role', 'document' );
 395              $wrap = dialog.$el.find( '.mce-wp-help' );
 396  
 397              if ( $wrap[0] ) {
 398                  $wrap.attr( 'tabindex', '0' );
 399                  $wrap[0].focus();
 400                  $wrap.on( 'keydown', function( event ) {
 401                      // Prevent use of: page up, page down, end, home, left arrow, up arrow, right arrow, down arrow
 402                      // in the dialog keydown handler.
 403                      if ( event.keyCode >= 33 && event.keyCode <= 40 ) {
 404                          event.stopPropagation();
 405                      }
 406                  });
 407              }
 408          }
 409      } );
 410  
 411      editor.addCommand( 'WP_Medialib', function() {
 412          if ( wp && wp.media && wp.media.editor ) {
 413              wp.media.editor.open( editor.id );
 414          }
 415      });
 416  
 417      // Register buttons.
 418      editor.addButton( 'wp_more', {
 419          tooltip: 'Insert Read More tag',
 420          onclick: function() {
 421              editor.execCommand( 'WP_More', 'more' );
 422          }
 423      });
 424  
 425      editor.addButton( 'wp_page', {
 426          tooltip: 'Page break',
 427          onclick: function() {
 428              editor.execCommand( 'WP_More', 'nextpage' );
 429          }
 430      });
 431  
 432      editor.addButton( 'wp_help', {
 433          tooltip: 'Keyboard Shortcuts',
 434          cmd: 'WP_Help'
 435      });
 436  
 437      editor.addButton( 'wp_code', {
 438          tooltip: 'Code',
 439          cmd: 'WP_Code',
 440          stateSelector: 'code'
 441      });
 442  
 443      // Insert->Add Media.
 444      if ( wp && wp.media && wp.media.editor ) {
 445          editor.addButton( 'wp_add_media', {
 446              tooltip: 'Add Media',
 447              icon: 'dashicon dashicons-admin-media',
 448              cmd: 'WP_Medialib'
 449          } );
 450  
 451          editor.addMenuItem( 'add_media', {
 452              text: 'Add Media',
 453              icon: 'wp-media-library',
 454              context: 'insert',
 455              cmd: 'WP_Medialib'
 456          });
 457      }
 458  
 459      // Insert "Read More...".
 460      editor.addMenuItem( 'wp_more', {
 461          text: 'Insert Read More tag',
 462          icon: 'wp_more',
 463          context: 'insert',
 464          onclick: function() {
 465              editor.execCommand( 'WP_More', 'more' );
 466          }
 467      });
 468  
 469      // Insert "Next Page".
 470      editor.addMenuItem( 'wp_page', {
 471          text: 'Page break',
 472          icon: 'wp_page',
 473          context: 'insert',
 474          onclick: function() {
 475              editor.execCommand( 'WP_More', 'nextpage' );
 476          }
 477      });
 478  
 479      editor.on( 'BeforeExecCommand', function(e) {
 480          if ( tinymce.Env.webkit && ( e.command === 'InsertUnorderedList' || e.command === 'InsertOrderedList' ) ) {
 481              if ( ! style ) {
 482                  style = editor.dom.create( 'style', {'type': 'text/css'},
 483                      '#tinymce,#tinymce span,#tinymce li,#tinymce li>span,#tinymce p,#tinymce p>span{font:medium sans-serif;color:#000;line-height:normal;}');
 484              }
 485  
 486              editor.getDoc().head.appendChild( style );
 487          }
 488      });
 489  
 490      editor.on( 'ExecCommand', function( e ) {
 491          if ( tinymce.Env.webkit && style &&
 492              ( 'InsertUnorderedList' === e.command || 'InsertOrderedList' === e.command ) ) {
 493  
 494              editor.dom.remove( style );
 495          }
 496      });
 497  
 498      editor.on( 'init', function() {
 499          var env = tinymce.Env,
 500              bodyClass = ['mceContentBody'], // Back-compat for themes that use this in editor-style.css...
 501              doc = editor.getDoc(),
 502              dom = editor.dom;
 503  
 504          if ( env.iOS ) {
 505              dom.addClass( doc.documentElement, 'ios' );
 506          }
 507  
 508          if ( editor.getParam( 'directionality' ) === 'rtl' ) {
 509              bodyClass.push('rtl');
 510              dom.setAttrib( doc.documentElement, 'dir', 'rtl' );
 511          }
 512  
 513          dom.setAttrib( doc.documentElement, 'lang', editor.getParam( 'wp_lang_attr' ) );
 514  
 515          if ( env.ie ) {
 516              if ( parseInt( env.ie, 10 ) === 9 ) {
 517                  bodyClass.push('ie9');
 518              } else if ( parseInt( env.ie, 10 ) === 8 ) {
 519                  bodyClass.push('ie8');
 520              } else if ( env.ie < 8 ) {
 521                  bodyClass.push('ie7');
 522              }
 523          } else if ( env.webkit ) {
 524              bodyClass.push('webkit');
 525          }
 526  
 527          bodyClass.push('wp-editor');
 528  
 529          each( bodyClass, function( cls ) {
 530              if ( cls ) {
 531                  dom.addClass( doc.body, cls );
 532              }
 533          });
 534  
 535          // Remove invalid parent paragraphs when inserting HTML.
 536          editor.on( 'BeforeSetContent', function( event ) {
 537              if ( event.content ) {
 538                  event.content = event.content.replace( /<p>\s*<(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre)( [^>]*)?>/gi, '<$1$2>' )
 539                      .replace( /<\/(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre)>\s*<\/p>/gi, '</$1>' );
 540              }
 541          });
 542  
 543          if ( $ ) {
 544              // Run on DOM ready. Otherwise TinyMCE may initialize earlier and handlers attached
 545              // on DOM ready of after the `tinymce.init()` call may not get triggered.
 546              $( function() {
 547                  $( document ).triggerHandler( 'tinymce-editor-init', [editor] );
 548              });
 549          }
 550  
 551          if ( window.tinyMCEPreInit && window.tinyMCEPreInit.dragDropUpload ) {
 552              dom.bind( doc, 'dragstart dragend dragover drop', function( event ) {
 553                  if ( $ ) {
 554                      // Trigger the jQuery handlers.
 555                      $( document ).trigger( new $.Event( event ) );
 556                  }
 557              });
 558          }
 559  
 560          if ( editor.getParam( 'wp_paste_filters', true ) ) {
 561              editor.on( 'PastePreProcess', function( event ) {
 562                  // Remove trailing <br> added by WebKit browsers to the clipboard.
 563                  event.content = event.content.replace( /<br class="?Apple-interchange-newline"?>/gi, '' );
 564  
 565                  // In WebKit this is handled by removeWebKitStyles().
 566                  if ( ! tinymce.Env.webkit ) {
 567                      // Remove all inline styles.
 568                      event.content = event.content.replace( /(<[^>]+) style="[^"]*"([^>]*>)/gi, '$1$2' );
 569  
 570                      // Put back the internal styles.
 571                      event.content = event.content.replace(/(<[^>]+) data-mce-style=([^>]+>)/gi, '$1 style=$2' );
 572                  }
 573              });
 574  
 575              editor.on( 'PastePostProcess', function( event ) {
 576                  // Remove empty paragraphs.
 577                  editor.$( 'p', event.node ).each( function( i, node ) {
 578                      if ( dom.isEmpty( node ) ) {
 579                          dom.remove( node );
 580                      }
 581                  });
 582  
 583                  if ( tinymce.isIE ) {
 584                      editor.$( 'a', event.node ).find( 'font, u' ).each( function( i, node ) {
 585                          dom.remove( node, true );
 586                      });
 587                  }
 588              });
 589          }
 590      });
 591  
 592      editor.on( 'SaveContent', function( event ) {
 593          // If editor is hidden, we just want the textarea's value to be saved.
 594          if ( ! editor.inline && editor.isHidden() ) {
 595              event.content = event.element.value;
 596              return;
 597          }
 598  
 599          // Keep empty paragraphs :(
 600          event.content = event.content.replace( /<p>(?:<br ?\/?>|\u00a0|\uFEFF| )*<\/p>/g, '<p>&nbsp;</p>' );
 601  
 602          if ( hasWpautop ) {
 603              event.content = wp.editor.removep( event.content );
 604          } else {
 605              // Restore formatting of block boundaries.
 606              event.content = event.content.replace( /-->\s*<!-- wp:/g, '-->\n\n<!-- wp:' );
 607          }
 608      });
 609  
 610      editor.on( 'preInit', function() {
 611          var validElementsSetting = '@[id|accesskey|class|dir|lang|style|tabindex|' +
 612              'title|contenteditable|draggable|dropzone|hidden|spellcheck|translate],' + // Global attributes.
 613              'i,' + // Don't replace <i> with <em> and <b> with <strong> and don't remove them when empty.
 614              'b,' +
 615              'script[src|async|defer|type|charset|crossorigin|integrity]'; // Add support for <script>.
 616  
 617          editor.schema.addValidElements( validElementsSetting );
 618  
 619          if ( tinymce.Env.iOS ) {
 620              editor.settings.height = 300;
 621          }
 622  
 623          each( {
 624              c: 'JustifyCenter',
 625              r: 'JustifyRight',
 626              l: 'JustifyLeft',
 627              j: 'JustifyFull',
 628              q: 'mceBlockQuote',
 629              u: 'InsertUnorderedList',
 630              o: 'InsertOrderedList',
 631              m: 'WP_Medialib',
 632              t: 'WP_More',
 633              d: 'Strikethrough',
 634              p: 'WP_Page',
 635              x: 'WP_Code'
 636          }, function( command, key ) {
 637              editor.shortcuts.add( 'access+' + key, '', command );
 638          } );
 639  
 640          editor.addShortcut( 'meta+s', '', function() {
 641              if ( wp && wp.autosave ) {
 642                  wp.autosave.server.triggerSave();
 643              }
 644          } );
 645  
 646          // Alt+Shift+Z removes a block in the block editor, don't add it to the Classic block.
 647          if ( ! editor.settings.classic_block_editor ) {
 648              editor.addShortcut( 'access+z', '', 'WP_Adv' );
 649          }
 650  
 651          // Workaround for not triggering the global help modal in the block editor by the Classic block shortcut.
 652          editor.on( 'keydown', function( event ) {
 653              var match;
 654  
 655              if ( tinymce.Env.mac ) {
 656                  match = event.ctrlKey && event.altKey && event.code === 'KeyH';
 657              } else {
 658                  match = event.shiftKey && event.altKey && event.code === 'KeyH';
 659              }
 660  
 661              if ( match ) {
 662                  editor.execCommand( 'WP_Help' );
 663                  event.stopPropagation();
 664                  event.stopImmediatePropagation();
 665                  return false;
 666              }
 667  
 668              return true;
 669          });
 670  
 671          if ( window.getUserSetting( 'editor_plain_text_paste_warning' ) > 1 ) {
 672              editor.settings.paste_plaintext_inform = false;
 673          }
 674  
 675          // Change the editor iframe title on MacOS, add the correct help shortcut.
 676          if ( tinymce.Env.mac ) {
 677              tinymce.$( editor.iframeElement ).attr( 'title', __( 'Rich Text Area. Press Control-Option-H for help.' ) );
 678          }
 679      } );
 680  
 681      editor.on( 'PastePlainTextToggle', function( event ) {
 682          // Warn twice, then stop.
 683          if ( event.state === true ) {
 684              var times = parseInt( window.getUserSetting( 'editor_plain_text_paste_warning' ), 10 ) || 0;
 685  
 686              if ( times < 2 ) {
 687                  window.setUserSetting( 'editor_plain_text_paste_warning', ++times );
 688              }
 689          }
 690      });
 691  
 692      editor.on( 'beforerenderui', function() {
 693          if ( editor.theme.panel ) {
 694              each( [ 'button', 'colorbutton', 'splitbutton' ], function( buttonType ) {
 695                  replaceButtonsTooltips( editor.theme.panel.find( buttonType ) );
 696              } );
 697  
 698              addShortcutsToListbox();
 699          }
 700      } );
 701  
 702  	function prepareTooltips() {
 703          var access = 'Shift+Alt+';
 704          var meta = 'Ctrl+';
 705  
 706          wpTooltips = {};
 707  
 708          // For MacOS: ctrl = \u2303, cmd = \u2318, alt = \u2325.
 709          if ( tinymce.Env.mac ) {
 710              access = '\u2303\u2325';
 711              meta = '\u2318';
 712          }
 713  
 714          // Some tooltips are translated, others are not...
 715          if ( editor.settings.wp_shortcut_labels ) {
 716              each( editor.settings.wp_shortcut_labels, function( value, tooltip ) {
 717                  var translated = editor.translate( tooltip );
 718  
 719                  value = value.replace( 'access', access ).replace( 'meta', meta );
 720                  wpTooltips[ tooltip ] = value;
 721  
 722                  // Add the translated so we can match all of them.
 723                  if ( tooltip !== translated ) {
 724                      wpTooltips[ translated ] = value;
 725                  }
 726              } );
 727          }
 728      }
 729  
 730  	function getTooltip( tooltip ) {
 731          var translated = editor.translate( tooltip );
 732          var label;
 733  
 734          if ( ! wpTooltips ) {
 735              prepareTooltips();
 736          }
 737  
 738          if ( wpTooltips.hasOwnProperty( translated ) ) {
 739              label = wpTooltips[ translated ];
 740          } else if ( wpTooltips.hasOwnProperty( tooltip ) ) {
 741              label = wpTooltips[ tooltip ];
 742          }
 743  
 744          return label ? translated + ' (' + label + ')' : translated;
 745      }
 746  
 747  	function replaceButtonsTooltips( buttons ) {
 748  
 749          if ( ! buttons ) {
 750              return;
 751          }
 752  
 753          each( buttons, function( button ) {
 754              var tooltip;
 755  
 756              if ( button && button.settings.tooltip ) {
 757                  tooltip = getTooltip( button.settings.tooltip );
 758                  button.settings.tooltip = tooltip;
 759  
 760                  // Override the aria label with the translated tooltip + shortcut.
 761                  if ( button._aria && button._aria.label ) {
 762                      button._aria.label = tooltip;
 763                  }
 764              }
 765          } );
 766      }
 767  
 768  	function addShortcutsToListbox() {
 769          // listbox for the "blocks" drop-down.
 770          each( editor.theme.panel.find( 'listbox' ), function( listbox ) {
 771              if ( listbox && listbox.settings.text === 'Paragraph' ) {
 772                  each( listbox.settings.values, function( item ) {
 773                      if ( item.text && wpTooltips.hasOwnProperty( item.text ) ) {
 774                          item.shortcut = '(' + wpTooltips[ item.text ] + ')';
 775                      }
 776                  } );
 777              }
 778          } );
 779      }
 780  
 781      /**
 782       * Experimental: create a floating toolbar.
 783       * This functionality will change in the next releases. Not recommended for use by plugins.
 784       */
 785      editor.on( 'preinit', function() {
 786          var Factory = tinymce.ui.Factory,
 787              settings = editor.settings,
 788              activeToolbar,
 789              currentSelection,
 790              timeout,
 791              container = editor.getContainer(),
 792              wpAdminbar = document.getElementById( 'wpadminbar' ),
 793              mceIframe = document.getElementById( editor.id + '_ifr' ),
 794              mceToolbar,
 795              mceStatusbar,
 796              wpStatusbar,
 797              cachedWinSize;
 798  
 799              if ( container ) {
 800                  mceToolbar = tinymce.$( '.mce-toolbar-grp', container )[0];
 801                  mceStatusbar = tinymce.$( '.mce-statusbar', container )[0];
 802              }
 803  
 804              if ( editor.id === 'content' ) {
 805                  wpStatusbar = document.getElementById( 'post-status-info' );
 806              }
 807  
 808  		function create( buttons, bottom ) {
 809              var toolbar,
 810                  toolbarItems = [],
 811                  buttonGroup;
 812  
 813              each( buttons, function( item ) {
 814                  var itemName;
 815                  var tooltip;
 816  
 817  				function bindSelectorChanged() {
 818                      var selection = editor.selection;
 819  
 820                      if ( itemName === 'bullist' ) {
 821                          selection.selectorChanged( 'ul > li', function( state, args ) {
 822                              var i = args.parents.length,
 823                                  nodeName;
 824  
 825                              while ( i-- ) {
 826                                  nodeName = args.parents[ i ].nodeName;
 827  
 828                                  if ( nodeName === 'OL' || nodeName == 'UL' ) {
 829                                      break;
 830                                  }
 831                              }
 832  
 833                              item.active( state && nodeName === 'UL' );
 834                          } );
 835                      }
 836  
 837                      if ( itemName === 'numlist' ) {
 838                          selection.selectorChanged( 'ol > li', function( state, args ) {
 839                              var i = args.parents.length,
 840                                  nodeName;
 841  
 842                              while ( i-- ) {
 843                                  nodeName = args.parents[ i ].nodeName;
 844  
 845                                  if ( nodeName === 'OL' || nodeName === 'UL' ) {
 846                                      break;
 847                                  }
 848                              }
 849  
 850                              item.active( state && nodeName === 'OL' );
 851                          } );
 852                      }
 853  
 854                      if ( item.settings.stateSelector ) {
 855                          selection.selectorChanged( item.settings.stateSelector, function( state ) {
 856                              item.active( state );
 857                          }, true );
 858                      }
 859  
 860                      if ( item.settings.disabledStateSelector ) {
 861                          selection.selectorChanged( item.settings.disabledStateSelector, function( state ) {
 862                              item.disabled( state );
 863                          } );
 864                      }
 865                  }
 866  
 867                  if ( item === '|' ) {
 868                      buttonGroup = null;
 869                  } else {
 870                      if ( Factory.has( item ) ) {
 871                          item = {
 872                              type: item
 873                          };
 874  
 875                          if ( settings.toolbar_items_size ) {
 876                              item.size = settings.toolbar_items_size;
 877                          }
 878  
 879                          toolbarItems.push( item );
 880  
 881                          buttonGroup = null;
 882                      } else {
 883                          if ( ! buttonGroup ) {
 884                              buttonGroup = {
 885                                  type: 'buttongroup',
 886                                  items: []
 887                              };
 888  
 889                              toolbarItems.push( buttonGroup );
 890                          }
 891  
 892                          if ( editor.buttons[ item ] ) {
 893                              itemName = item;
 894                              item = editor.buttons[ itemName ];
 895  
 896                              if ( typeof item === 'function' ) {
 897                                  item = item();
 898                              }
 899  
 900                              item.type = item.type || 'button';
 901  
 902                              if ( settings.toolbar_items_size ) {
 903                                  item.size = settings.toolbar_items_size;
 904                              }
 905  
 906                              tooltip = item.tooltip || item.title;
 907  
 908                              if ( tooltip ) {
 909                                  item.tooltip = getTooltip( tooltip );
 910                              }
 911  
 912                              item = Factory.create( item );
 913  
 914                              buttonGroup.items.push( item );
 915  
 916                              if ( editor.initialized ) {
 917                                  bindSelectorChanged();
 918                              } else {
 919                                  editor.on( 'init', bindSelectorChanged );
 920                              }
 921                          }
 922                      }
 923                  }
 924              } );
 925  
 926              toolbar = Factory.create( {
 927                  type: 'panel',
 928                  layout: 'stack',
 929                  classes: 'toolbar-grp inline-toolbar-grp',
 930                  ariaRoot: true,
 931                  ariaRemember: true,
 932                  items: [ {
 933                      type: 'toolbar',
 934                      layout: 'flow',
 935                      items: toolbarItems
 936                  } ]
 937              } );
 938  
 939              toolbar.bottom = bottom;
 940  
 941  			function reposition() {
 942                  if ( ! currentSelection ) {
 943                      return this;
 944                  }
 945  
 946                  var scrollX = window.pageXOffset || document.documentElement.scrollLeft,
 947                      scrollY = window.pageYOffset || document.documentElement.scrollTop,
 948                      windowWidth = window.innerWidth,
 949                      windowHeight = window.innerHeight,
 950                      iframeRect = mceIframe ? mceIframe.getBoundingClientRect() : {
 951                          top: 0,
 952                          right: windowWidth,
 953                          bottom: windowHeight,
 954                          left: 0,
 955                          width: windowWidth,
 956                          height: windowHeight
 957                      },
 958                      toolbar = this.getEl(),
 959                      toolbarWidth = toolbar.offsetWidth,
 960                      toolbarHeight = toolbar.clientHeight,
 961                      selection = currentSelection.getBoundingClientRect(),
 962                      selectionMiddle = ( selection.left + selection.right ) / 2,
 963                      buffer = 5,
 964                      spaceNeeded = toolbarHeight + buffer,
 965                      wpAdminbarBottom = wpAdminbar ? wpAdminbar.getBoundingClientRect().bottom : 0,
 966                      mceToolbarBottom = mceToolbar ? mceToolbar.getBoundingClientRect().bottom : 0,
 967                      mceStatusbarTop = mceStatusbar ? windowHeight - mceStatusbar.getBoundingClientRect().top : 0,
 968                      wpStatusbarTop = wpStatusbar ? windowHeight - wpStatusbar.getBoundingClientRect().top : 0,
 969                      blockedTop = Math.max( 0, wpAdminbarBottom, mceToolbarBottom, iframeRect.top ),
 970                      blockedBottom = Math.max( 0, mceStatusbarTop, wpStatusbarTop, windowHeight - iframeRect.bottom ),
 971                      spaceTop = selection.top + iframeRect.top - blockedTop,
 972                      spaceBottom = windowHeight - iframeRect.top - selection.bottom - blockedBottom,
 973                      editorHeight = windowHeight - blockedTop - blockedBottom,
 974                      className = '',
 975                      iosOffsetTop = 0,
 976                      iosOffsetBottom = 0,
 977                      top, left;
 978  
 979                  if ( spaceTop >= editorHeight || spaceBottom >= editorHeight ) {
 980                      this.scrolling = true;
 981                      this.hide();
 982                      this.scrolling = false;
 983                      return this;
 984                  }
 985  
 986                  // Add offset in iOS to move the menu over the image, out of the way of the default iOS menu.
 987                  if ( tinymce.Env.iOS && currentSelection.nodeName === 'IMG' ) {
 988                      iosOffsetTop = 54;
 989                      iosOffsetBottom = 46;
 990                  }
 991  
 992                  if ( this.bottom ) {
 993                      if ( spaceBottom >= spaceNeeded ) {
 994                          className = ' mce-arrow-up';
 995                          top = selection.bottom + iframeRect.top + scrollY - iosOffsetBottom;
 996                      } else if ( spaceTop >= spaceNeeded ) {
 997                          className = ' mce-arrow-down';
 998                          top = selection.top + iframeRect.top + scrollY - toolbarHeight + iosOffsetTop;
 999                      }
1000                  } else {
1001                      if ( spaceTop >= spaceNeeded ) {
1002                          className = ' mce-arrow-down';
1003                          top = selection.top + iframeRect.top + scrollY - toolbarHeight + iosOffsetTop;
1004                      } else if ( spaceBottom >= spaceNeeded && editorHeight / 2 > selection.bottom + iframeRect.top - blockedTop ) {
1005                          className = ' mce-arrow-up';
1006                          top = selection.bottom + iframeRect.top + scrollY - iosOffsetBottom;
1007                      }
1008                  }
1009  
1010                  if ( typeof top === 'undefined' ) {
1011                      top = scrollY + blockedTop + buffer + iosOffsetBottom;
1012                  }
1013  
1014                  left = selectionMiddle - toolbarWidth / 2 + iframeRect.left + scrollX;
1015  
1016                  if ( selection.left < 0 || selection.right > iframeRect.width ) {
1017                      left = iframeRect.left + scrollX + ( iframeRect.width - toolbarWidth ) / 2;
1018                  } else if ( toolbarWidth >= windowWidth ) {
1019                      className += ' mce-arrow-full';
1020                      left = 0;
1021                  } else if ( ( left < 0 && selection.left + toolbarWidth > windowWidth ) || ( left + toolbarWidth > windowWidth && selection.right - toolbarWidth < 0 ) ) {
1022                      left = ( windowWidth - toolbarWidth ) / 2;
1023                  } else if ( left < iframeRect.left + scrollX ) {
1024                      className += ' mce-arrow-left';
1025                      left = selection.left + iframeRect.left + scrollX;
1026                  } else if ( left + toolbarWidth > iframeRect.width + iframeRect.left + scrollX ) {
1027                      className += ' mce-arrow-right';
1028                      left = selection.right - toolbarWidth + iframeRect.left + scrollX;
1029                  }
1030  
1031                  // No up/down arrows on the menu over images in iOS.
1032                  if ( tinymce.Env.iOS && currentSelection.nodeName === 'IMG' ) {
1033                      className = className.replace( / ?mce-arrow-(up|down)/g, '' );
1034                  }
1035  
1036                  toolbar.className = toolbar.className.replace( / ?mce-arrow-[\w]+/g, '' ) + className;
1037  
1038                  DOM.setStyles( toolbar, {
1039                      'left': left,
1040                      'top': top
1041                  } );
1042  
1043                  return this;
1044              }
1045  
1046              toolbar.on( 'show', function() {
1047                  this.reposition();
1048              } );
1049  
1050              toolbar.on( 'keydown', function( event ) {
1051                  if ( event.keyCode === 27 ) {
1052                      this.hide();
1053                      editor.focus();
1054                  }
1055              } );
1056  
1057              editor.on( 'remove', function() {
1058                  toolbar.remove();
1059              } );
1060  
1061              toolbar.reposition = reposition;
1062              toolbar.hide().renderTo( document.body );
1063  
1064              return toolbar;
1065          }
1066  
1067          editor.shortcuts.add( 'alt+119', '', function() {
1068              var node;
1069  
1070              if ( activeToolbar ) {
1071                  node = activeToolbar.find( 'toolbar' )[0];
1072                  node && node.focus( true );
1073              }
1074          } );
1075  
1076          editor.on( 'nodechange', function( event ) {
1077              var collapsed = editor.selection.isCollapsed();
1078  
1079              var args = {
1080                  element: event.element,
1081                  parents: event.parents,
1082                  collapsed: collapsed
1083              };
1084  
1085              editor.fire( 'wptoolbar', args );
1086  
1087              currentSelection = args.selection || args.element;
1088  
1089              if ( activeToolbar && activeToolbar !== args.toolbar ) {
1090                  activeToolbar.hide();
1091              }
1092  
1093              if ( args.toolbar ) {
1094                  activeToolbar = args.toolbar;
1095  
1096                  if ( activeToolbar.visible() ) {
1097                      activeToolbar.reposition();
1098                  } else {
1099                      activeToolbar.show();
1100                  }
1101              } else {
1102                  activeToolbar = false;
1103              }
1104          } );
1105  
1106          editor.on( 'focus', function() {
1107              if ( activeToolbar ) {
1108                  activeToolbar.show();
1109              }
1110          } );
1111  
1112  		function hide( event ) {
1113              var win;
1114              var size;
1115  
1116              if ( activeToolbar ) {
1117                  if ( activeToolbar.tempHide || event.type === 'hide' || event.type === 'blur' ) {
1118                      activeToolbar.hide();
1119                      activeToolbar = false;
1120                  } else if ( (
1121                      event.type === 'resizewindow' ||
1122                      event.type === 'scrollwindow' ||
1123                      event.type === 'resize' ||
1124                      event.type === 'scroll'
1125                  ) && ! activeToolbar.blockHide ) {
1126                      /*
1127                       * Showing a tooltip may trigger a `resize` event in Chromium browsers.
1128                       * That results in a flicketing inline menu; tooltips are shown on hovering over a button,
1129                       * which then hides the toolbar on `resize`, then it repeats as soon as the toolbar is shown again.
1130                       */
1131                      if ( event.type === 'resize' || event.type === 'resizewindow' ) {
1132                          win = editor.getWin();
1133                          size = win.innerHeight + win.innerWidth;
1134  
1135                          // Reset old cached size.
1136                          if ( cachedWinSize && ( new Date() ).getTime() - cachedWinSize.timestamp > 2000 ) {
1137                              cachedWinSize = null;
1138                          }
1139  
1140                          if ( cachedWinSize ) {
1141                              if ( size && Math.abs( size - cachedWinSize.size ) < 2 ) {
1142                                  // `resize` fired but the window hasn't been resized. Bail.
1143                                  return;
1144                              }
1145                          } else {
1146                              // First of a new series of `resize` events. Store the cached size and bail.
1147                              cachedWinSize = {
1148                                  timestamp: ( new Date() ).getTime(),
1149                                  size: size,
1150                              };
1151  
1152                              return;
1153                          }
1154                      }
1155  
1156                      clearTimeout( timeout );
1157  
1158                      timeout = setTimeout( function() {
1159                          if ( activeToolbar && typeof activeToolbar.show === 'function' ) {
1160                              activeToolbar.scrolling = false;
1161                              activeToolbar.show();
1162                          }
1163                      }, 250 );
1164  
1165                      activeToolbar.scrolling = true;
1166                      activeToolbar.hide();
1167                  }
1168              }
1169          }
1170  
1171          if ( editor.inline ) {
1172              editor.on( 'resizewindow', hide );
1173  
1174              // Enable `capture` for the event.
1175              // This will hide/reposition the toolbar on any scrolling in the document.
1176              document.addEventListener( 'scroll', hide, true );
1177          } else {
1178              // Bind to the editor iframe and to the parent window.
1179              editor.dom.bind( editor.getWin(), 'resize scroll', hide );
1180              editor.on( 'resizewindow scrollwindow', hide );
1181          }
1182  
1183          editor.on( 'remove', function() {
1184              document.removeEventListener( 'scroll', hide, true );
1185              editor.off( 'resizewindow scrollwindow', hide );
1186              editor.dom.unbind( editor.getWin(), 'resize scroll', hide );
1187          } );
1188  
1189          editor.on( 'blur hide', hide );
1190  
1191          editor.wp = editor.wp || {};
1192          editor.wp._createToolbar = create;
1193      }, true );
1194  
1195  	function noop() {}
1196  
1197      // Expose some functions (back-compat).
1198      return {
1199          _showButtons: noop,
1200          _hideButtons: noop,
1201          _setEmbed: noop,
1202          _getEmbed: noop
1203      };
1204  });
1205  
1206  }( window.tinymce ));


Generated : Sat Apr 12 08:20:01 2025 Cross-referenced by PHPXref