home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / js / tinymce / plugins / wordpress / plugin.js next >
Encoding:
Text File  |  2017-10-24  |  29.1 KB  |  1,061 lines

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