angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

plugin.js (34189B)


      1 /* global getUserSetting, setUserSetting */
      2 ( function( tinymce ) {
      3 // Set the minimum value for the modals z-index higher than #wpadminbar (100000).
      4 if ( ! tinymce.ui.FloatPanel.zIndex || tinymce.ui.FloatPanel.zIndex < 100100 ) {
      5 	tinymce.ui.FloatPanel.zIndex = 100100;
      6 }
      7 
      8 tinymce.PluginManager.add( 'wordpress', function( editor ) {
      9 	var wpAdvButton, style,
     10 		DOM = tinymce.DOM,
     11 		each = tinymce.each,
     12 		__ = editor.editorManager.i18n.translate,
     13 		$ = window.jQuery,
     14 		wp = window.wp,
     15 		hasWpautop = ( wp && wp.editor && wp.editor.autop && editor.getParam( 'wpautop', true ) ),
     16 		wpTooltips = false;
     17 
     18 	if ( $ ) {
     19 		// Runs as soon as TinyMCE has started initializing, while plugins are loading.
     20 		// Handlers attached after the `tinymce.init()` call may not get triggered for this instance.
     21 		$( document ).triggerHandler( 'tinymce-editor-setup', [ editor ] );
     22 	}
     23 
     24 	function toggleToolbars( state ) {
     25 		var initial, toolbars, iframeHeight,
     26 			pixels = 0,
     27 			classicBlockToolbar = tinymce.$( '.block-library-classic__toolbar' );
     28 
     29 		if ( state === 'hide' ) {
     30 			initial = true;
     31 		} else if ( classicBlockToolbar.length && ! classicBlockToolbar.hasClass( 'has-advanced-toolbar' ) ) {
     32 			// Show the second, third, etc. toolbar rows in the Classic block instance.
     33 			classicBlockToolbar.addClass( 'has-advanced-toolbar' );
     34 			state = 'show';
     35 		}
     36 
     37 		if ( editor.theme.panel ) {
     38 			toolbars = editor.theme.panel.find('.toolbar:not(.menubar)');
     39 		}
     40 
     41 		if ( toolbars && toolbars.length > 1 ) {
     42 			if ( ! state && toolbars[1].visible() ) {
     43 				state = 'hide';
     44 			}
     45 
     46 			each( toolbars, function( toolbar, i ) {
     47 				if ( i > 0 ) {
     48 					if ( state === 'hide' ) {
     49 						toolbar.hide();
     50 						pixels += 34;
     51 					} else {
     52 						toolbar.show();
     53 						pixels -= 34;
     54 					}
     55 				}
     56 			});
     57 		}
     58 
     59 		// Resize editor iframe, not needed for iOS and inline instances.
     60 		// Don't resize if the editor is in a hidden container.
     61 		if ( pixels && ! tinymce.Env.iOS && editor.iframeElement && editor.iframeElement.clientHeight ) {
     62 			iframeHeight = editor.iframeElement.clientHeight + pixels;
     63 
     64 			// Keep min-height.
     65 			if ( iframeHeight > 50  ) {
     66 				DOM.setStyle( editor.iframeElement, 'height', iframeHeight );
     67 			}
     68 		}
     69 
     70 		if ( ! initial ) {
     71 			if ( state === 'hide' ) {
     72 				setUserSetting( 'hidetb', '0' );
     73 				wpAdvButton && wpAdvButton.active( false );
     74 			} else {
     75 				setUserSetting( 'hidetb', '1' );
     76 				wpAdvButton && wpAdvButton.active( true );
     77 			}
     78 		}
     79 
     80 		editor.fire( 'wp-toolbar-toggle' );
     81 	}
     82 
     83 	// Add the kitchen sink button :)
     84 	editor.addButton( 'wp_adv', {
     85 		tooltip: 'Toolbar Toggle',
     86 		cmd: 'WP_Adv',
     87 		onPostRender: function() {
     88 			wpAdvButton = this;
     89 			wpAdvButton.active( getUserSetting( 'hidetb' ) === '1' );
     90 		}
     91 	});
     92 
     93 	// Hide the toolbars after loading.
     94 	editor.on( 'PostRender', function() {
     95 		if ( editor.getParam( 'wordpress_adv_hidden', true ) && getUserSetting( 'hidetb', '0' ) === '0' ) {
     96 			toggleToolbars( 'hide' );
     97 		} else {
     98 			tinymce.$( '.block-library-classic__toolbar' ).addClass( 'has-advanced-toolbar' );
     99 		}
    100 	});
    101 
    102 	editor.addCommand( 'WP_Adv', function() {
    103 		toggleToolbars();
    104 	});
    105 
    106 	editor.on( 'focus', function() {
    107         window.wpActiveEditor = editor.id;
    108     });
    109 
    110 	editor.on( 'BeforeSetContent', function( event ) {
    111 		var title;
    112 
    113 		if ( event.content ) {
    114 			if ( event.content.indexOf( '<!--more' ) !== -1 ) {
    115 				title = __( 'Read more...' );
    116 
    117 				event.content = event.content.replace( /<!--more(.*?)-->/g, function( match, moretext ) {
    118 					return '<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="more" data-wp-more-text="' + moretext + '" ' +
    119 						'class="wp-more-tag mce-wp-more" alt="" title="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />';
    120 				});
    121 			}
    122 
    123 			if ( event.content.indexOf( '<!--nextpage-->' ) !== -1 ) {
    124 				title = __( 'Page break' );
    125 
    126 				event.content = event.content.replace( /<!--nextpage-->/g,
    127 					'<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="nextpage" class="wp-more-tag mce-wp-nextpage" ' +
    128 						'alt="" title="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />' );
    129 			}
    130 
    131 			if ( event.load && event.format !== 'raw' ) {
    132 				if ( hasWpautop ) {
    133 					event.content = wp.editor.autop( event.content );
    134 				} else {
    135 					// Prevent creation of paragraphs out of multiple HTML comments.
    136 					event.content = event.content.replace( /-->\s+<!--/g, '--><!--' );
    137 				}
    138 			}
    139 
    140 			if ( event.content.indexOf( '<script' ) !== -1 || event.content.indexOf( '<style' ) !== -1 ) {
    141 				event.content = event.content.replace( /<(script|style)[^>]*>[\s\S]*?<\/\1>/g, function( match, tag ) {
    142 					return '<img ' +
    143 						'src="' + tinymce.Env.transparentSrc + '" ' +
    144 						'data-wp-preserve="' + encodeURIComponent( match ) + '" ' +
    145 						'data-mce-resize="false" ' +
    146 						'data-mce-placeholder="1" '+
    147 						'class="mce-object" ' +
    148 						'width="20" height="20" '+
    149 						'alt="&lt;' + tag + '&gt;" ' +
    150 						'title="&lt;' + tag + '&gt;" ' +
    151 					'/>';
    152 				} );
    153 			}
    154 		}
    155 	});
    156 
    157 	editor.on( 'setcontent', function() {
    158 		// Remove spaces from empty paragraphs.
    159 		editor.$( 'p' ).each( function( i, node ) {
    160 			if ( node.innerHTML && node.innerHTML.length < 10 ) {
    161 				var html = tinymce.trim( node.innerHTML );
    162 
    163 				if ( ! html || html === '&nbsp;' ) {
    164 					node.innerHTML = ( tinymce.Env.ie && tinymce.Env.ie < 11 ) ? '' : '<br data-mce-bogus="1">';
    165 				}
    166 			}
    167 		} );
    168 	});
    169 
    170 	editor.on( 'PostProcess', function( event ) {
    171 		if ( event.get ) {
    172 			event.content = event.content.replace(/<img[^>]+>/g, function( image ) {
    173 				var match,
    174 					string,
    175 					moretext = '';
    176 
    177 				if ( image.indexOf( 'data-wp-more="more"' ) !== -1 ) {
    178 					if ( match = image.match( /data-wp-more-text="([^"]+)"/ ) ) {
    179 						moretext = match[1];
    180 					}
    181 
    182 					string = '<!--more' + moretext + '-->';
    183 				} else if ( image.indexOf( 'data-wp-more="nextpage"' ) !== -1 ) {
    184 					string = '<!--nextpage-->';
    185 				} else if ( image.indexOf( 'data-wp-preserve' ) !== -1 ) {
    186 					if ( match = image.match( / data-wp-preserve="([^"]+)"/ ) ) {
    187 						string = decodeURIComponent( match[1] );
    188 					}
    189 				}
    190 
    191 				return string || image;
    192 			});
    193 		}
    194 	});
    195 
    196 	// Display the tag name instead of img in element path.
    197 	editor.on( 'ResolveName', function( event ) {
    198 		var attr;
    199 
    200 		if ( event.target.nodeName === 'IMG' && ( attr = editor.dom.getAttrib( event.target, 'data-wp-more' ) ) ) {
    201 			event.name = attr;
    202 		}
    203 	});
    204 
    205 	// Register commands.
    206 	editor.addCommand( 'WP_More', function( tag ) {
    207 		var parent, html, title,
    208 			classname = 'wp-more-tag',
    209 			dom = editor.dom,
    210 			node = editor.selection.getNode(),
    211 			rootNode = editor.getBody();
    212 
    213 		tag = tag || 'more';
    214 		classname += ' mce-wp-' + tag;
    215 		title = tag === 'more' ? 'Read more...' : 'Next page';
    216 		title = __( title );
    217 		html = '<img src="' + tinymce.Env.transparentSrc + '" alt="" title="' + title + '" class="' + classname + '" ' +
    218 			'data-wp-more="' + tag + '" data-mce-resize="false" data-mce-placeholder="1" />';
    219 
    220 		// Most common case.
    221 		if ( node === rootNode || ( node.nodeName === 'P' && node.parentNode === rootNode ) ) {
    222 			editor.insertContent( html );
    223 			return;
    224 		}
    225 
    226 		// Get the top level parent node.
    227 		parent = dom.getParent( node, function( found ) {
    228 			if ( found.parentNode && found.parentNode === rootNode ) {
    229 				return true;
    230 			}
    231 
    232 			return false;
    233 		}, editor.getBody() );
    234 
    235 		if ( parent ) {
    236 			if ( parent.nodeName === 'P' ) {
    237 				parent.appendChild( dom.create( 'p', null, html ).firstChild );
    238 			} else {
    239 				dom.insertAfter( dom.create( 'p', null, html ), parent );
    240 			}
    241 
    242 			editor.nodeChanged();
    243 		}
    244 	});
    245 
    246 	editor.addCommand( 'WP_Code', function() {
    247 		editor.formatter.toggle('code');
    248 	});
    249 
    250 	editor.addCommand( 'WP_Page', function() {
    251 		editor.execCommand( 'WP_More', 'nextpage' );
    252 	});
    253 
    254 	editor.addCommand( 'WP_Help', function() {
    255 		var access = tinymce.Env.mac ? __( 'Ctrl + Alt + letter:' ) : __( 'Shift + Alt + letter:' ),
    256 			meta = tinymce.Env.mac ? __( 'Cmd + letter:' ) : __( 'Ctrl + letter:' ),
    257 			table1 = [],
    258 			table2 = [],
    259 			row1 = {},
    260 			row2 = {},
    261 			i1 = 0,
    262 			i2 = 0,
    263 			labels = editor.settings.wp_shortcut_labels,
    264 			header, html, dialog, $wrap;
    265 
    266 		if ( ! labels ) {
    267 			return;
    268 		}
    269 
    270 		function tr( row, columns ) {
    271 			var out = '<tr>';
    272 			var i = 0;
    273 
    274 			columns = columns || 1;
    275 
    276 			each( row, function( text, key ) {
    277 				out += '<td><kbd>' + key + '</kbd></td><td>' + __( text ) + '</td>';
    278 				i++;
    279 			});
    280 
    281 			while ( i < columns ) {
    282 				out += '<td></td><td></td>';
    283 				i++;
    284 			}
    285 
    286 			return out + '</tr>';
    287 		}
    288 
    289 		each ( labels, function( label, name ) {
    290 			var letter;
    291 
    292 			if ( label.indexOf( 'meta' ) !== -1 ) {
    293 				i1++;
    294 				letter = label.replace( 'meta', '' ).toLowerCase();
    295 
    296 				if ( letter ) {
    297 					row1[ letter ] = name;
    298 
    299 					if ( i1 % 2 === 0 ) {
    300 						table1.push( tr( row1, 2 ) );
    301 						row1 = {};
    302 					}
    303 				}
    304 			} else if ( label.indexOf( 'access' ) !== -1 ) {
    305 				i2++;
    306 				letter = label.replace( 'access', '' ).toLowerCase();
    307 
    308 				if ( letter ) {
    309 					row2[ letter ] = name;
    310 
    311 					if ( i2 % 2 === 0 ) {
    312 						table2.push( tr( row2, 2 ) );
    313 						row2 = {};
    314 					}
    315 				}
    316 			}
    317 		} );
    318 
    319 		// Add remaining single entries.
    320 		if ( i1 % 2 > 0 ) {
    321 			table1.push( tr( row1, 2 ) );
    322 		}
    323 
    324 		if ( i2 % 2 > 0 ) {
    325 			table2.push( tr( row2, 2 ) );
    326 		}
    327 
    328 		header = [ __( 'Letter' ), __( 'Action' ), __( 'Letter' ), __( 'Action' ) ];
    329 		header = '<tr><th>' + header.join( '</th><th>' ) + '</th></tr>';
    330 
    331 		html = '<div class="wp-editor-help">';
    332 
    333 		// Main section, default and additional shortcuts.
    334 		html = html +
    335 			'<h2>' + __( 'Default shortcuts,' ) + ' ' + meta + '</h2>' +
    336 			'<table class="wp-help-th-center fixed">' +
    337 				header +
    338 				table1.join('') +
    339 			'</table>' +
    340 			'<h2>' + __( 'Additional shortcuts,' ) + ' ' + access + '</h2>' +
    341 			'<table class="wp-help-th-center fixed">' +
    342 				header +
    343 				table2.join('') +
    344 			'</table>';
    345 
    346 		if ( editor.plugins.wptextpattern && ( ! tinymce.Env.ie || tinymce.Env.ie > 8 ) ) {
    347 			// Text pattern section.
    348 			html = html +
    349 				'<h2>' + __( 'When starting a new paragraph with one of these formatting shortcuts followed by a space, the formatting will be applied automatically. Press Backspace or Escape to undo.' ) + '</h2>' +
    350 				'<table class="wp-help-th-center fixed">' +
    351 					tr({ '*':  'Bullet list', '1.':  'Numbered list' }) +
    352 					tr({ '-':  'Bullet list', '1)':  'Numbered list' }) +
    353 				'</table>';
    354 
    355 			html = html +
    356 				'<h2>' + __( 'The following formatting shortcuts are replaced when pressing Enter. Press Escape or the Undo button to undo.' ) + '</h2>' +
    357 				'<table class="wp-help-single">' +
    358 					tr({ '>': 'Blockquote' }) +
    359 					tr({ '##': 'Heading 2' }) +
    360 					tr({ '###': 'Heading 3' }) +
    361 					tr({ '####': 'Heading 4' }) +
    362 					tr({ '#####': 'Heading 5' }) +
    363 					tr({ '######': 'Heading 6' }) +
    364 					tr({ '---': 'Horizontal line' }) +
    365 				'</table>';
    366 		}
    367 
    368 		// Focus management section.
    369 		html = html +
    370 			'<h2>' + __( 'Focus shortcuts:' ) + '</h2>' +
    371 			'<table class="wp-help-single">' +
    372 				tr({ 'Alt + F8':  'Inline toolbar (when an image, link or preview is selected)' }) +
    373 				tr({ 'Alt + F9':  'Editor menu (when enabled)' }) +
    374 				tr({ 'Alt + F10': 'Editor toolbar' }) +
    375 				tr({ 'Alt + F11': 'Elements path' }) +
    376 			'</table>' +
    377 			'<p>' + __( 'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' ) + '</p>';
    378 
    379 		html += '</div>';
    380 
    381 		dialog = editor.windowManager.open( {
    382 			title: editor.settings.classic_block_editor ? 'Classic Block Keyboard Shortcuts' : 'Keyboard Shortcuts',
    383 			items: {
    384 				type: 'container',
    385 				classes: 'wp-help',
    386 				html: html
    387 			},
    388 			buttons: {
    389 				text: 'Close',
    390 				onclick: 'close'
    391 			}
    392 		} );
    393 
    394 		if ( dialog.$el ) {
    395 			dialog.$el.find( 'div[role="application"]' ).attr( 'role', 'document' );
    396 			$wrap = dialog.$el.find( '.mce-wp-help' );
    397 
    398 			if ( $wrap[0] ) {
    399 				$wrap.attr( 'tabindex', '0' );
    400 				$wrap[0].focus();
    401 				$wrap.on( 'keydown', function( event ) {
    402 					// Prevent use of: page up, page down, end, home, left arrow, up arrow, right arrow, down arrow
    403 					// in the dialog keydown handler.
    404 					if ( event.keyCode >= 33 && event.keyCode <= 40 ) {
    405 						event.stopPropagation();
    406 					}
    407 				});
    408 			}
    409 		}
    410 	} );
    411 
    412 	editor.addCommand( 'WP_Medialib', function() {
    413 		if ( wp && wp.media && wp.media.editor ) {
    414 			wp.media.editor.open( editor.id );
    415 		}
    416 	});
    417 
    418 	// Register buttons.
    419 	editor.addButton( 'wp_more', {
    420 		tooltip: 'Insert Read More tag',
    421 		onclick: function() {
    422 			editor.execCommand( 'WP_More', 'more' );
    423 		}
    424 	});
    425 
    426 	editor.addButton( 'wp_page', {
    427 		tooltip: 'Page break',
    428 		onclick: function() {
    429 			editor.execCommand( 'WP_More', 'nextpage' );
    430 		}
    431 	});
    432 
    433 	editor.addButton( 'wp_help', {
    434 		tooltip: 'Keyboard Shortcuts',
    435 		cmd: 'WP_Help'
    436 	});
    437 
    438 	editor.addButton( 'wp_code', {
    439 		tooltip: 'Code',
    440 		cmd: 'WP_Code',
    441 		stateSelector: 'code'
    442 	});
    443 
    444 	// Insert->Add Media.
    445 	if ( wp && wp.media && wp.media.editor ) {
    446 		editor.addButton( 'wp_add_media', {
    447 			tooltip: 'Add Media',
    448 			icon: 'dashicon dashicons-admin-media',
    449 			cmd: 'WP_Medialib'
    450 		} );
    451 
    452 		editor.addMenuItem( 'add_media', {
    453 			text: 'Add Media',
    454 			icon: 'wp-media-library',
    455 			context: 'insert',
    456 			cmd: 'WP_Medialib'
    457 		});
    458 	}
    459 
    460 	// Insert "Read More...".
    461 	editor.addMenuItem( 'wp_more', {
    462 		text: 'Insert Read More tag',
    463 		icon: 'wp_more',
    464 		context: 'insert',
    465 		onclick: function() {
    466 			editor.execCommand( 'WP_More', 'more' );
    467 		}
    468 	});
    469 
    470 	// Insert "Next Page".
    471 	editor.addMenuItem( 'wp_page', {
    472 		text: 'Page break',
    473 		icon: 'wp_page',
    474 		context: 'insert',
    475 		onclick: function() {
    476 			editor.execCommand( 'WP_More', 'nextpage' );
    477 		}
    478 	});
    479 
    480 	editor.on( 'BeforeExecCommand', function(e) {
    481 		if ( tinymce.Env.webkit && ( e.command === 'InsertUnorderedList' || e.command === 'InsertOrderedList' ) ) {
    482 			if ( ! style ) {
    483 				style = editor.dom.create( 'style', {'type': 'text/css'},
    484 					'#tinymce,#tinymce span,#tinymce li,#tinymce li>span,#tinymce p,#tinymce p>span{font:medium sans-serif;color:#000;line-height:normal;}');
    485 			}
    486 
    487 			editor.getDoc().head.appendChild( style );
    488 		}
    489 	});
    490 
    491 	editor.on( 'ExecCommand', function( e ) {
    492 		if ( tinymce.Env.webkit && style &&
    493 			( 'InsertUnorderedList' === e.command || 'InsertOrderedList' === e.command ) ) {
    494 
    495 			editor.dom.remove( style );
    496 		}
    497 	});
    498 
    499 	editor.on( 'init', function() {
    500 		var env = tinymce.Env,
    501 			bodyClass = ['mceContentBody'], // Back-compat for themes that use this in editor-style.css...
    502 			doc = editor.getDoc(),
    503 			dom = editor.dom;
    504 
    505 		if ( env.iOS ) {
    506 			dom.addClass( doc.documentElement, 'ios' );
    507 		}
    508 
    509 		if ( editor.getParam( 'directionality' ) === 'rtl' ) {
    510 			bodyClass.push('rtl');
    511 			dom.setAttrib( doc.documentElement, 'dir', 'rtl' );
    512 		}
    513 
    514 		dom.setAttrib( doc.documentElement, 'lang', editor.getParam( 'wp_lang_attr' ) );
    515 
    516 		if ( env.ie ) {
    517 			if ( parseInt( env.ie, 10 ) === 9 ) {
    518 				bodyClass.push('ie9');
    519 			} else if ( parseInt( env.ie, 10 ) === 8 ) {
    520 				bodyClass.push('ie8');
    521 			} else if ( env.ie < 8 ) {
    522 				bodyClass.push('ie7');
    523 			}
    524 		} else if ( env.webkit ) {
    525 			bodyClass.push('webkit');
    526 		}
    527 
    528 		bodyClass.push('wp-editor');
    529 
    530 		each( bodyClass, function( cls ) {
    531 			if ( cls ) {
    532 				dom.addClass( doc.body, cls );
    533 			}
    534 		});
    535 
    536 		// Remove invalid parent paragraphs when inserting HTML.
    537 		editor.on( 'BeforeSetContent', function( event ) {
    538 			if ( event.content ) {
    539 				event.content = event.content.replace( /<p>\s*<(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre)( [^>]*)?>/gi, '<$1$2>' )
    540 					.replace( /<\/(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre)>\s*<\/p>/gi, '</$1>' );
    541 			}
    542 		});
    543 
    544 		if ( $ ) {
    545 			// Run on DOM ready. Otherwise TinyMCE may initialize earlier and handlers attached
    546 			// on DOM ready of after the `tinymce.init()` call may not get triggered.
    547 			$( function() {
    548 				$( document ).triggerHandler( 'tinymce-editor-init', [editor] );
    549 			});
    550 		}
    551 
    552 		if ( window.tinyMCEPreInit && window.tinyMCEPreInit.dragDropUpload ) {
    553 			dom.bind( doc, 'dragstart dragend dragover drop', function( event ) {
    554 				if ( $ ) {
    555 					// Trigger the jQuery handlers.
    556 					$( document ).trigger( new $.Event( event ) );
    557 				}
    558 			});
    559 		}
    560 
    561 		if ( editor.getParam( 'wp_paste_filters', true ) ) {
    562 			editor.on( 'PastePreProcess', function( event ) {
    563 				// Remove trailing <br> added by WebKit browsers to the clipboard.
    564 				event.content = event.content.replace( /<br class="?Apple-interchange-newline"?>/gi, '' );
    565 
    566 				// In WebKit this is handled by removeWebKitStyles().
    567 				if ( ! tinymce.Env.webkit ) {
    568 					// Remove all inline styles.
    569 					event.content = event.content.replace( /(<[^>]+) style="[^"]*"([^>]*>)/gi, '$1$2' );
    570 
    571 					// Put back the internal styles.
    572 					event.content = event.content.replace(/(<[^>]+) data-mce-style=([^>]+>)/gi, '$1 style=$2' );
    573 				}
    574 			});
    575 
    576 			editor.on( 'PastePostProcess', function( event ) {
    577 				// Remove empty paragraphs.
    578 				editor.$( 'p', event.node ).each( function( i, node ) {
    579 					if ( dom.isEmpty( node ) ) {
    580 						dom.remove( node );
    581 					}
    582 				});
    583 
    584 				if ( tinymce.isIE ) {
    585 					editor.$( 'a', event.node ).find( 'font, u' ).each( function( i, node ) {
    586 						dom.remove( node, true );
    587 					});
    588 				}
    589 			});
    590 		}
    591 	});
    592 
    593 	editor.on( 'SaveContent', function( event ) {
    594 		// If editor is hidden, we just want the textarea's value to be saved.
    595 		if ( ! editor.inline && editor.isHidden() ) {
    596 			event.content = event.element.value;
    597 			return;
    598 		}
    599 
    600 		// Keep empty paragraphs :(
    601 		event.content = event.content.replace( /<p>(?:<br ?\/?>|\u00a0|\uFEFF| )*<\/p>/g, '<p>&nbsp;</p>' );
    602 
    603 		if ( hasWpautop ) {
    604 			event.content = wp.editor.removep( event.content );
    605 		} else {
    606 			// Restore formatting of block boundaries.
    607 			event.content = event.content.replace( /-->\s*<!-- wp:/g, '-->\n\n<!-- wp:' );
    608 		}
    609 	});
    610 
    611 	editor.on( 'preInit', function() {
    612 		var validElementsSetting = '@[id|accesskey|class|dir|lang|style|tabindex|' +
    613 			'title|contenteditable|draggable|dropzone|hidden|spellcheck|translate],' + // Global attributes.
    614 			'i,' + // Don't replace <i> with <em> and <b> with <strong> and don't remove them when empty.
    615 			'b,' +
    616 			'script[src|async|defer|type|charset|crossorigin|integrity]'; // Add support for <script>.
    617 
    618 		editor.schema.addValidElements( validElementsSetting );
    619 
    620 		if ( tinymce.Env.iOS ) {
    621 			editor.settings.height = 300;
    622 		}
    623 
    624 		each( {
    625 			c: 'JustifyCenter',
    626 			r: 'JustifyRight',
    627 			l: 'JustifyLeft',
    628 			j: 'JustifyFull',
    629 			q: 'mceBlockQuote',
    630 			u: 'InsertUnorderedList',
    631 			o: 'InsertOrderedList',
    632 			m: 'WP_Medialib',
    633 			t: 'WP_More',
    634 			d: 'Strikethrough',
    635 			p: 'WP_Page',
    636 			x: 'WP_Code'
    637 		}, function( command, key ) {
    638 			editor.shortcuts.add( 'access+' + key, '', command );
    639 		} );
    640 
    641 		editor.addShortcut( 'meta+s', '', function() {
    642 			if ( wp && wp.autosave ) {
    643 				wp.autosave.server.triggerSave();
    644 			}
    645 		} );
    646 
    647 		// Alt+Shift+Z removes a block in the block editor, don't add it to the Classic block.
    648 		if ( ! editor.settings.classic_block_editor ) {
    649 			editor.addShortcut( 'access+z', '', 'WP_Adv' );
    650 		}
    651 
    652 		// Workaround for not triggering the global help modal in the block editor by the Classic block shortcut.
    653 		editor.on( 'keydown', function( event ) {
    654 			var match;
    655 
    656 			if ( tinymce.Env.mac ) {
    657 				match = event.ctrlKey && event.altKey && event.code === 'KeyH';
    658 			} else {
    659 				match = event.shiftKey && event.altKey && event.code === 'KeyH';
    660 			}
    661 
    662 			if ( match ) {
    663 				editor.execCommand( 'WP_Help' );
    664 				event.stopPropagation();
    665 				event.stopImmediatePropagation();
    666 				return false;
    667 			}
    668 
    669 			return true;
    670 		});
    671 
    672 		if ( window.getUserSetting( 'editor_plain_text_paste_warning' ) > 1 ) {
    673 			editor.settings.paste_plaintext_inform = false;
    674 		}
    675 
    676 		// Change the editor iframe title on MacOS, add the correct help shortcut.
    677 		if ( tinymce.Env.mac ) {
    678 			tinymce.$( editor.iframeElement ).attr( 'title', __( 'Rich Text Area. Press Control-Option-H for help.' ) );
    679 		}
    680 	} );
    681 
    682 	editor.on( 'PastePlainTextToggle', function( event ) {
    683 		// Warn twice, then stop.
    684 		if ( event.state === true ) {
    685 			var times = parseInt( window.getUserSetting( 'editor_plain_text_paste_warning' ), 10 ) || 0;
    686 
    687 			if ( times < 2 ) {
    688 				window.setUserSetting( 'editor_plain_text_paste_warning', ++times );
    689 			}
    690 		}
    691 	});
    692 
    693 	editor.on( 'beforerenderui', function() {
    694 		if ( editor.theme.panel ) {
    695 			each( [ 'button', 'colorbutton', 'splitbutton' ], function( buttonType ) {
    696 				replaceButtonsTooltips( editor.theme.panel.find( buttonType ) );
    697 			} );
    698 
    699 			addShortcutsToListbox();
    700 		}
    701 	} );
    702 
    703 	function prepareTooltips() {
    704 		var access = 'Shift+Alt+';
    705 		var meta = 'Ctrl+';
    706 
    707 		wpTooltips = {};
    708 
    709 		// For MacOS: ctrl = \u2303, cmd = \u2318, alt = \u2325.
    710 		if ( tinymce.Env.mac ) {
    711 			access = '\u2303\u2325';
    712 			meta = '\u2318';
    713 		}
    714 
    715 		// Some tooltips are translated, others are not...
    716 		if ( editor.settings.wp_shortcut_labels ) {
    717 			each( editor.settings.wp_shortcut_labels, function( value, tooltip ) {
    718 				var translated = editor.translate( tooltip );
    719 
    720 				value = value.replace( 'access', access ).replace( 'meta', meta );
    721 				wpTooltips[ tooltip ] = value;
    722 
    723 				// Add the translated so we can match all of them.
    724 				if ( tooltip !== translated ) {
    725 					wpTooltips[ translated ] = value;
    726 				}
    727 			} );
    728 		}
    729 	}
    730 
    731 	function getTooltip( tooltip ) {
    732 		var translated = editor.translate( tooltip );
    733 		var label;
    734 
    735 		if ( ! wpTooltips ) {
    736 			prepareTooltips();
    737 		}
    738 
    739 		if ( wpTooltips.hasOwnProperty( translated ) ) {
    740 			label = wpTooltips[ translated ];
    741 		} else if ( wpTooltips.hasOwnProperty( tooltip ) ) {
    742 			label = wpTooltips[ tooltip ];
    743 		}
    744 
    745 		return label ? translated + ' (' + label + ')' : translated;
    746 	}
    747 
    748 	function replaceButtonsTooltips( buttons ) {
    749 
    750 		if ( ! buttons ) {
    751 			return;
    752 		}
    753 
    754 		each( buttons, function( button ) {
    755 			var tooltip;
    756 
    757 			if ( button && button.settings.tooltip ) {
    758 				tooltip = getTooltip( button.settings.tooltip );
    759 				button.settings.tooltip = tooltip;
    760 
    761 				// Override the aria label wiht 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 ));