@wordpress/block-library
Version:
Block library for the WordPress editor.
236 lines (202 loc) • 7.4 kB
JavaScript
import { createElement, Fragment } from "@wordpress/element";
/**
* WordPress dependencies
*/
import { BlockControls, useBlockProps, store as blockEditorStore } from '@wordpress/block-editor';
import { debounce } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { ToolbarGroup } from '@wordpress/components';
import { useEffect, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { BACKSPACE, DELETE, F10, isKeyboardEvent } from '@wordpress/keycodes';
/**
* Internal dependencies
*/
import ConvertToBlocksButton from './convert-to-blocks-button';
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 function ClassicEdit(_ref) {
let {
clientId,
attributes: {
content
},
setAttributes,
onReplace
} = _ref;
const {
getMultiSelectedBlockClientIds
} = useSelect(blockEditorStore);
const canRemove = useSelect(select => select(blockEditorStore).canRemoveBlock(clientId), [clientId]);
const didMount = useRef(false);
useEffect(() => {
if (!didMount.current) {
return;
}
const editor = window.tinymce.get(`editor-${clientId}`);
const currentContent = editor === null || editor === void 0 ? void 0 : editor.getContent();
if (currentContent !== content) {
editor.setContent(content || '');
}
}, [content]);
useEffect(() => {
const {
baseURL,
suffix
} = window.wpEditorL10n.tinymce;
didMount.current = true;
window.tinymce.EditorManager.overrideDefaults({
base_url: baseURL,
suffix
});
function onSetup(editor) {
let bookmark;
if (content) {
editor.on('loadContent', () => editor.setContent(content));
}
editor.on('blur', () => {
var _getMultiSelectedBloc;
bookmark = editor.selection.getBookmark(2, true); // There is an issue with Chrome and the editor.focus call in core at https://core.trac.wordpress.org/browser/trunk/src/js/_enqueues/lib/link.js#L451.
// This causes a scroll to the top of editor content on return from some content updating dialogs so tracking
// scroll position until this is fixed in core.
const scrollContainer = document.querySelector('.interface-interface-skeleton__content');
const scrollPosition = scrollContainer.scrollTop; // Only update attributes if we aren't multi-selecting blocks.
// Updating during multi-selection can overwrite attributes of other blocks.
if (!((_getMultiSelectedBloc = getMultiSelectedBlockClientIds()) !== null && _getMultiSelectedBloc !== void 0 && _getMultiSelectedBloc.length)) {
setAttributes({
content: editor.getContent()
});
}
editor.once('focus', () => {
if (bookmark) {
editor.selection.moveToBookmark(bookmark);
if (scrollContainer.scrollTop !== scrollPosition) {
scrollContainer.scrollTop = scrollPosition;
}
}
});
return false;
});
editor.on('mousedown touchstart', () => {
bookmark = null;
});
const debouncedOnChange = debounce(() => {
const value = editor.getContent();
if (value !== editor._lastChange) {
editor._lastChange = value;
setAttributes({
content: value
});
}
}, 250);
editor.on('Paste Change input Undo Redo', debouncedOnChange); // We need to cancel the debounce call because when we remove
// the editor (onUnmount) this callback is executed in
// another tick. This results in setting the content to empty.
editor.on('remove', debouncedOnChange.cancel);
editor.on('keydown', event => {
if (isKeyboardEvent.primary(event, 'z')) {
// Prevent the gutenberg undo kicking in so TinyMCE undo stack works as expected.
event.stopPropagation();
}
if ((event.keyCode === BACKSPACE || event.keyCode === DELETE) && isTmceEmpty(editor)) {
// Delete the block.
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();
}
});
editor.on('init', () => {
const rootNode = editor.getBody(); // Create the toolbar by refocussing the editor.
if (rootNode.ownerDocument.activeElement === rootNode) {
rootNode.blur();
editor.focus();
}
});
}
function initialize() {
const {
settings
} = window.wpEditorL10n.tinymce;
wp.oldEditor.initialize(`editor-${clientId}`, {
tinymce: { ...settings,
inline: true,
content_css: false,
fixed_toolbar_container: `#toolbar-${clientId}`,
setup: onSetup
}
});
}
function onReadyStateChange() {
if (document.readyState === 'complete') {
initialize();
}
}
if (document.readyState === 'complete') {
initialize();
} else {
document.addEventListener('readystatechange', onReadyStateChange);
}
return () => {
document.removeEventListener('readystatechange', onReadyStateChange);
wp.oldEditor.remove(`editor-${clientId}`);
};
}, []);
function focus() {
const editor = window.tinymce.get(`editor-${clientId}`);
if (editor) {
editor.focus();
}
}
function 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();
} // Disable reasons:
//
// jsx-a11y/no-static-element-interactions
// - 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 createElement(Fragment, null, canRemove && createElement(BlockControls, null, createElement(ToolbarGroup, null, createElement(ConvertToBlocksButton, {
clientId: clientId
}))), createElement("div", useBlockProps(), createElement("div", {
key: "toolbar",
id: `toolbar-${clientId}`,
className: "block-library-classic__toolbar",
onClick: focus,
"data-placeholder": __('Classic'),
onKeyDown: onToolbarKeyDown
}), createElement("div", {
key: "editor",
id: `editor-${clientId}`,
className: "wp-block-freeform block-library-rich-text__tinymce"
})));
/* eslint-enable jsx-a11y/no-static-element-interactions */
}
//# sourceMappingURL=edit.js.map