UNPKG

@wordpress/editor

Version:
423 lines (413 loc) 14.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.ExperimentalEditorProvider = void 0; var _reactNative = require("react-native"); var _memize = _interopRequireDefault(require("memize")); var _reactNativeSafeAreaContext = require("react-native-safe-area-context"); var _reactNativeBridge = _interopRequireWildcard(require("@wordpress/react-native-bridge")); var _element = require("@wordpress/element"); var _wordcount = require("@wordpress/wordcount"); var _blocks = require("@wordpress/blocks"); var _data = require("@wordpress/data"); var _compose = require("@wordpress/compose"); var _hooks = require("@wordpress/hooks"); var _blockEditor = require("@wordpress/block-editor"); var _blockLibrary = require("@wordpress/block-library"); var _i18n = require("@wordpress/i18n"); var _editor = require("@wordpress/editor"); var _notices = require("@wordpress/notices"); var _coreData = require("@wordpress/core-data"); var _index = _interopRequireDefault(require("./index.js")); var _postTitle = require("../post-title"); var _jsxRuntime = require("react/jsx-runtime"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /** * External dependencies */ /** * WordPress dependencies */ const postTypeEntities = [{ name: 'post', baseURL: '/wp/v2/posts' }, { name: 'page', baseURL: '/wp/v2/pages' }, { name: 'attachment', baseURL: '/wp/v2/media' }, { name: 'wp_block', baseURL: '/wp/v2/blocks' }].map(postTypeEntity => ({ kind: 'postType', ...postTypeEntity, transientEdits: { blocks: true, selection: true }, mergedEdits: { meta: true }, rawAttributes: ['title', 'excerpt', 'content'] })); /** * Internal dependencies */ class NativeEditorProvider extends _element.Component { constructor() { super(...arguments); // Keep a local reference to `post` to detect changes. this.post = this.props.post; this.props.addEntities(postTypeEntities); this.props.receiveEntityRecords('postType', this.post.type, this.post); this.onHardwareBackPress = this.onHardwareBackPress.bind(this); this.onContentUpdate = this.onContentUpdate.bind(this); this.getEditorSettings = (0, _memize.default)((settings, capabilities) => ({ ...settings, capabilities }), { maxSize: 1 }); this.state = { isHelpVisible: false }; } componentDidMount() { const { capabilities, createErrorNotice, locale, hostAppNamespace, updateEditorSettings, updateBlockEditorSettings } = this.props; updateEditorSettings({ capabilities, ...this.getThemeColors(this.props), locale, hostAppNamespace }); this.subscriptionParentGetHtml = (0, _reactNativeBridge.subscribeParentGetHtml)(() => { this.serializeToNativeAction(); }); this.subscriptionParentToggleHTMLMode = (0, _reactNativeBridge.subscribeParentToggleHTMLMode)(() => { this.toggleMode(); }); this.subscriptionParentSetTitle = (0, _reactNativeBridge.subscribeSetTitle)(payload => { this.props.editTitle(payload.title); }); this.subscriptionParentUpdateHtml = (0, _reactNativeBridge.subscribeUpdateHtml)(payload => { this.updateHtmlAction(payload.html); }); this.subscriptionParentReplaceBlock = (0, _reactNativeBridge.subscribeReplaceBlock)(payload => { this.replaceBlockAction(payload.html, payload.clientId); }); this.subscriptionParentMediaAppend = (0, _reactNativeBridge.subscribeMediaAppend)(payload => { const blockName = 'core/' + payload.mediaType; const blockType = (0, _blocks.getBlockType)(blockName); if (blockType && blockType?.name) { const newBlock = (0, _blocks.createBlock)(blockType.name, { id: payload.mediaId, [payload.mediaType === 'image' ? 'url' : 'src']: payload.mediaUrl }); const indexAfterSelected = this.props.selectedBlockIndex + 1; const insertionIndex = indexAfterSelected || this.props.blockCount; this.props.insertBlock(newBlock, insertionIndex); } else { createErrorNotice((0, _i18n.__)('File type not supported as a media file.')); } }); this.subscriptionParentUpdateEditorSettings = (0, _reactNativeBridge.subscribeUpdateEditorSettings)(({ ...editorSettings }) => { updateEditorSettings(this.getThemeColors(editorSettings)); }); this.subscriptionParentUpdateCapabilities = (0, _reactNativeBridge.subscribeUpdateCapabilities)(payload => { this.updateCapabilitiesAction(payload); }); this.subscriptionParentShowNotice = (0, _reactNativeBridge.subscribeShowNotice)(payload => { this.props.createSuccessNotice(payload.message); }); this.subscriptionParentShowEditorHelp = (0, _reactNativeBridge.subscribeShowEditorHelp)(() => { this.setState({ isHelpVisible: true }); }); this.hardwareBackPressListener = _reactNative.BackHandler.addEventListener('hardwareBackPress', this.onHardwareBackPress); this.subscriptionOnContentUpdate = (0, _reactNativeBridge.subscribeToContentUpdate)(data => { this.onContentUpdate(data); }); // Request current block impressions from native app. (0, _reactNativeBridge.requestBlockTypeImpressions)(storedImpressions => { const impressions = { ..._blockLibrary.NEW_BLOCK_TYPES, ...storedImpressions }; // Persist impressions to JavaScript store. updateBlockEditorSettings({ impressions }); // Persist impressions to native store if they do not include latest // `NEW_BLOCK_TYPES` configuration. const storedImpressionKeys = Object.keys(storedImpressions); const storedImpressionsCurrent = Object.keys(_blockLibrary.NEW_BLOCK_TYPES).every(newKey => storedImpressionKeys.includes(newKey)); if (!storedImpressionsCurrent) { (0, _reactNativeBridge.setBlockTypeImpressions)(impressions); } }); } componentWillUnmount() { if (this.subscriptionParentGetHtml) { this.subscriptionParentGetHtml.remove(); } if (this.subscriptionParentToggleHTMLMode) { this.subscriptionParentToggleHTMLMode.remove(); } if (this.subscriptionParentSetTitle) { this.subscriptionParentSetTitle.remove(); } if (this.subscriptionParentUpdateHtml) { this.subscriptionParentUpdateHtml.remove(); } if (this.subscriptionParentReplaceBlock) { this.subscriptionParentReplaceBlock.remove(); } if (this.subscriptionParentMediaAppend) { this.subscriptionParentMediaAppend.remove(); } if (this.subscriptionParentUpdateEditorSettings) { this.subscriptionParentUpdateEditorSettings.remove(); } if (this.subscriptionParentUpdateCapabilities) { this.subscriptionParentUpdateCapabilities.remove(); } if (this.subscriptionParentShowNotice) { this.subscriptionParentShowNotice.remove(); } if (this.subscriptionParentShowEditorHelp) { this.subscriptionParentShowEditorHelp.remove(); } if (this.hardwareBackPressListener) { this.hardwareBackPressListener.remove(); } if (this.subscriptionOnContentUpdate) { this.subscriptionOnContentUpdate.remove(); } } getThemeColors({ rawStyles, rawFeatures }) { const { defaultEditorColors, defaultEditorGradients } = this.props; if (rawStyles && rawFeatures) { return (0, _blockEditor.getGlobalStyles)(rawStyles, rawFeatures); } return (0, _blockEditor.getColorsAndGradients)(defaultEditorColors, defaultEditorGradients, rawFeatures); } componentDidUpdate(prevProps) { if (!prevProps.isReady && this.props.isReady) { const blocks = this.props.blocks; const isUnsupportedBlock = ({ name }) => name === (0, _blocks.getUnregisteredTypeHandlerName)(); const unsupportedBlockNames = blocks.filter(isUnsupportedBlock).map(block => block.attributes.originalName); _reactNativeBridge.default.editorDidMount(unsupportedBlockNames); } } onHardwareBackPress() { const { clearSelectedBlock, selectedBlockIndex } = this.props; if (selectedBlockIndex !== -1) { clearSelectedBlock(); return true; } return false; } onContentUpdate({ content: rawContent }) { const { editTitle, onClearPostTitleSelection, onInsertBlockAfter: onInsertBlocks, title } = this.props; const content = (0, _blocks.pasteHandler)({ plainText: rawContent }); (0, _postTitle.insertContentWithTitle)(title, content, editTitle, onInsertBlocks); onClearPostTitleSelection(); } serializeToNativeAction() { const title = this.props.title; let html; if (this.props.mode === 'text') { // The HTMLTextInput component does not update the store when user is doing changes // Let's request the HTML from the component's state directly. html = (0, _hooks.applyFilters)('native.persist-html'); } else { html = (0, _blocks.serialize)(this.props.blocks); } const hasChanges = title !== this.post.title.raw || html !== this.post.content.raw; // Variable to store the content structure metrics. const contentInfo = {}; contentInfo.characterCount = (0, _wordcount.count)(html, 'characters_including_spaces'); contentInfo.wordCount = (0, _wordcount.count)(html, 'words'); contentInfo.paragraphCount = this.props.paragraphCount; contentInfo.blockCount = this.props.blockCount; _reactNativeBridge.default.provideToNative_Html(html, title, hasChanges, contentInfo); if (hasChanges) { this.post.title.raw = title; this.post.content.raw = html; } } updateHtmlAction(html) { const parsed = (0, _blocks.parse)(html); this.props.resetEditorBlocksWithoutUndoLevel(parsed); } replaceBlockAction(html, blockClientId) { const parsed = (0, _blocks.parse)(html); this.props.replaceBlock(blockClientId, parsed); } toggleMode() { const { mode, switchMode } = this.props; // Refresh html content first. this.serializeToNativeAction(); switchMode(mode === 'visual' ? 'text' : 'visual'); } updateCapabilitiesAction(capabilities) { this.props.updateEditorSettings({ capabilities }); } render() { const { children, post, capabilities, settings, ...props } = this.props; const editorSettings = this.getEditorSettings(settings, capabilities); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index.default, { post: this.post, settings: editorSettings, ...props, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSafeAreaContext.SafeAreaProvider, { children: children }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_editor.EditorHelpTopics, { isVisible: this.state.isHelpVisible, onClose: () => this.setState({ isHelpVisible: false }), close: () => this.setState({ isHelpVisible: false }), showSupport: capabilities?.supportSection === true })] }); } } const ComposedNativeProvider = exports.ExperimentalEditorProvider = (0, _compose.compose)([(0, _data.withSelect)(select => { var _settings$colors, _settings$gradients; const { __unstableIsEditorReady: isEditorReady, getEditorBlocks, getEditedPostAttribute, getEditedPostContent, getEditorSettings, getEditorMode } = select(_editor.store); const { getBlockIndex, getSelectedBlockClientId, getGlobalBlockCount } = select(_blockEditor.store); const settings = getEditorSettings(); const defaultEditorColors = (_settings$colors = settings?.colors) !== null && _settings$colors !== void 0 ? _settings$colors : []; const defaultEditorGradients = (_settings$gradients = settings?.gradients) !== null && _settings$gradients !== void 0 ? _settings$gradients : []; const selectedBlockClientId = getSelectedBlockClientId(); return { mode: getEditorMode(), isReady: isEditorReady(), blocks: getEditorBlocks(), title: getEditedPostAttribute('title'), getEditedPostContent, defaultEditorColors, defaultEditorGradients, selectedBlockIndex: getBlockIndex(selectedBlockClientId), blockCount: getGlobalBlockCount(), paragraphCount: getGlobalBlockCount('core/paragraph') }; }), (0, _data.withDispatch)(dispatch => { const { editPost, resetEditorBlocks, updateEditorSettings, switchEditorMode, togglePostTitleSelection } = dispatch(_editor.store); const { clearSelectedBlock, updateSettings, insertBlock, insertBlocks, replaceBlock } = dispatch(_blockEditor.store); const { addEntities, receiveEntityRecords } = dispatch(_coreData.store); const { createSuccessNotice, createErrorNotice } = dispatch(_notices.store); return { updateBlockEditorSettings: updateSettings, updateEditorSettings, addEntities, insertBlock, insertBlocks, createSuccessNotice, createErrorNotice, clearSelectedBlock, editTitle(title) { editPost({ title }); }, receiveEntityRecords, resetEditorBlocksWithoutUndoLevel(blocks) { resetEditorBlocks(blocks, { __unstableShouldCreateUndoLevel: false }); }, switchMode(mode) { switchEditorMode(mode); }, onInsertBlockAfter(blocks) { insertBlocks(blocks, undefined, undefined, false); }, onClearPostTitleSelection() { togglePostTitleSelection(false); }, replaceBlock }; })])(NativeEditorProvider); var _default = exports.default = ComposedNativeProvider; //# sourceMappingURL=index.native.js.map