[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
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="<' + tag + '>" ' + 150 'title="<' + tag + '>" ' + 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 === ' ' ) { 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> </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 ));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Dec 6 01:00:02 2024 | Cross-referenced by PHPXref 0.7.1 |