[ Index ]

PHP Cross Reference of WordPress

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


Generated: Fri Dec 6 01:00:02 2024 Cross-referenced by PHPXref 0.7.1