@wordpress/block-library
Version:
Block library for the WordPress editor.
206 lines (174 loc) • 5.57 kB
JavaScript
/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { __, _x } from '@wordpress/i18n';
import { BACKSPACE, DELETE, F10 } from '@wordpress/keycodes';
const { wp } = window;
function isTmceEmpty( editor ) {
// When tinyMce is empty the content seems to be:
// <p><br data-mce-bogus="1"></p>
// avoid expensive checks for large documents
const body = editor.getBody();
if ( body.childNodes.length > 1 ) {
return false;
} else if ( body.childNodes.length === 0 ) {
return true;
}
if ( body.childNodes[ 0 ].childNodes.length > 1 ) {
return false;
}
return /^\n?$/.test( body.innerText || body.textContent );
}
export default class ClassicEdit extends Component {
constructor( props ) {
super( props );
this.initialize = this.initialize.bind( this );
this.onSetup = this.onSetup.bind( this );
this.focus = this.focus.bind( this );
}
componentDidMount() {
const { baseURL, suffix } = window.wpEditorL10n.tinymce;
window.tinymce.EditorManager.overrideDefaults( {
base_url: baseURL,
suffix,
} );
if ( document.readyState === 'complete' ) {
this.initialize();
} else {
window.addEventListener( 'DOMContentLoaded', this.initialize );
}
}
componentWillUnmount() {
window.addEventListener( 'DOMContentLoaded', this.initialize );
wp.oldEditor.remove( `editor-${ this.props.clientId }` );
}
componentDidUpdate( prevProps ) {
const { clientId, attributes: { content } } = this.props;
const editor = window.tinymce.get( `editor-${ clientId }` );
if ( prevProps.attributes.content !== content ) {
editor.setContent( content || '' );
}
}
initialize() {
const { clientId } = this.props;
const { settings } = window.wpEditorL10n.tinymce;
wp.oldEditor.initialize( `editor-${ clientId }`, {
tinymce: {
...settings,
inline: true,
content_css: false,
fixed_toolbar_container: `#toolbar-${ clientId }`,
setup: this.onSetup,
},
} );
}
onSetup( editor ) {
const { attributes: { content }, setAttributes } = this.props;
const { ref } = this;
let bookmark;
this.editor = editor;
if ( content ) {
editor.on( 'loadContent', () => editor.setContent( content ) );
}
editor.on( 'blur', () => {
bookmark = editor.selection.getBookmark( 2, true );
setAttributes( {
content: editor.getContent(),
} );
editor.once( 'focus', () => {
if ( bookmark ) {
editor.selection.moveToBookmark( bookmark );
}
} );
return false;
} );
editor.on( 'mousedown touchstart', () => {
bookmark = null;
} );
editor.on( 'keydown', ( event ) => {
if ( ( event.keyCode === BACKSPACE || event.keyCode === DELETE ) && isTmceEmpty( editor ) ) {
// delete the block
this.props.onReplace( [] );
event.preventDefault();
event.stopImmediatePropagation();
}
const { altKey } = event;
/*
* Prevent Mousetrap from kicking in: TinyMCE already uses its own
* `alt+f10` shortcut to focus its toolbar.
*/
if ( altKey && event.keyCode === F10 ) {
event.stopPropagation();
}
} );
// TODO: the following is for back-compat with WP 4.9, not needed in WP 5.0. Remove it after the release.
editor.addButton( 'kitchensink', {
tooltip: _x( 'More', 'button to expand options' ),
icon: 'dashicon dashicons-editor-kitchensink',
onClick() {
const button = this;
const active = ! button.active();
button.active( active );
editor.dom.toggleClass( ref, 'has-advanced-toolbar', active );
},
} );
// Show the second, third, etc. toolbars when the `kitchensink` button is removed by a plugin.
editor.on( 'init', function() {
if ( editor.settings.toolbar1 && editor.settings.toolbar1.indexOf( 'kitchensink' ) === -1 ) {
editor.dom.addClass( ref, 'has-advanced-toolbar' );
}
} );
editor.addButton( 'wp_add_media', {
tooltip: __( 'Insert Media' ),
icon: 'dashicon dashicons-admin-media',
cmd: 'WP_Medialib',
} );
// End TODO.
editor.on( 'init', () => {
const rootNode = this.editor.getBody();
// Create the toolbar by refocussing the editor.
if ( document.activeElement === rootNode ) {
rootNode.blur();
this.editor.focus();
}
} );
}
focus() {
if ( this.editor ) {
this.editor.focus();
}
}
onToolbarKeyDown( event ) {
// Prevent WritingFlow from kicking in and allow arrows navigation on the toolbar.
event.stopPropagation();
// Prevent Mousetrap from moving focus to the top toolbar when pressing `alt+f10` on this block toolbar.
event.nativeEvent.stopImmediatePropagation();
}
render() {
const { clientId } = this.props;
// Disable reason: the toolbar itself is non-interactive, but must capture
// events from the KeyboardShortcuts component to stop their propagation.
/* eslint-disable jsx-a11y/no-static-element-interactions */
return [
// Disable reason: Clicking on this visual placeholder should create
// the toolbar, it can also be created by focussing the field below.
/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
<div
key="toolbar"
id={ `toolbar-${ clientId }` }
ref={ ( ref ) => this.ref = ref }
className="block-library-classic__toolbar"
onClick={ this.focus }
data-placeholder={ __( 'Classic' ) }
onKeyDown={ this.onToolbarKeyDown }
/>,
<div
key="editor"
id={ `editor-${ clientId }` }
className="wp-block-freeform block-library-rich-text__tinymce"
/>,
];
/* eslint-enable jsx-a11y/no-static-element-interactions */
}
}