[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[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 + '" 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="<' + tag + '>" ' + 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 === ' ' ) { 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> </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 ));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sat Apr 12 08:20:01 2025 | Cross-referenced by PHPXref |