@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
823 lines (707 loc) • 23 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.setupEditor = setupEditor;
exports.__experimentalTearDownEditor = __experimentalTearDownEditor;
exports.resetPost = resetPost;
exports.resetAutosave = resetAutosave;
exports.__experimentalRequestPostUpdateStart = __experimentalRequestPostUpdateStart;
exports.__experimentalRequestPostUpdateFinish = __experimentalRequestPostUpdateFinish;
exports.updatePost = updatePost;
exports.setupEditorState = setupEditorState;
exports.editPost = editPost;
exports.savePost = savePost;
exports.refreshPost = refreshPost;
exports.trashPost = trashPost;
exports.autosave = autosave;
exports.redo = redo;
exports.undo = undo;
exports.createUndoLevel = createUndoLevel;
exports.updatePostLock = updatePostLock;
exports.enablePublishSidebar = enablePublishSidebar;
exports.disablePublishSidebar = disablePublishSidebar;
exports.lockPostSaving = lockPostSaving;
exports.unlockPostSaving = unlockPostSaving;
exports.lockPostAutosaving = lockPostAutosaving;
exports.unlockPostAutosaving = unlockPostAutosaving;
exports.resetEditorBlocks = resetEditorBlocks;
exports.updateEditorSettings = updateEditorSettings;
exports.updateBlockListSettings = exports.insertDefaultBlock = exports.exitFormattedText = exports.enterFormattedText = exports.stopTyping = exports.startTyping = exports.toggleBlockMode = exports.removeBlock = exports.removeBlocks = exports.mergeBlocks = exports.synchronizeTemplate = exports.setTemplateValidity = exports.hideInsertionPoint = exports.showInsertionPoint = exports.insertBlocks = exports.insertBlock = exports.moveBlockToPosition = exports.moveBlocksUp = exports.moveBlocksDown = exports.replaceBlock = exports.replaceBlocks = exports.toggleSelection = exports.clearSelectedBlock = exports.multiSelect = exports.stopMultiSelect = exports.startMultiSelect = exports.selectBlock = exports.updateBlockAttributes = exports.updateBlock = exports.receiveBlocks = exports.resetBlocks = void 0;
var _lodash = require("lodash");
var _deprecated = _interopRequireDefault(require("@wordpress/deprecated"));
var _data = require("@wordpress/data");
var _dataControls = require("@wordpress/data-controls");
var _blocks = require("@wordpress/blocks");
var _notices = require("@wordpress/notices");
var _constants = require("./constants");
var _noticeBuilder = require("./utils/notice-builder");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
/**
* Returns an action generator used in signalling that editor has initialized with
* the specified post object and editor settings.
*
* @param {Object} post Post object.
* @param {Object} edits Initial edited attributes object.
* @param {Array?} template Block Template.
*/
function* setupEditor(post, edits, template) {
// In order to ensure maximum of a single parse during setup, edits are
// included as part of editor setup action. Assume edited content as
// canonical if provided, falling back to post.
let content;
if ((0, _lodash.has)(edits, ['content'])) {
content = edits.content;
} else {
content = post.content.raw;
}
let blocks = (0, _blocks.parse)(content); // Apply a template for new posts only, if exists.
const isNewPost = post.status === 'auto-draft';
if (isNewPost && template) {
blocks = (0, _blocks.synchronizeBlocksWithTemplate)(blocks, template);
}
yield resetPost(post);
yield {
type: 'SETUP_EDITOR',
post,
edits,
template
};
yield resetEditorBlocks(blocks, {
__unstableShouldCreateUndoLevel: false
});
yield setupEditorState(post);
if (edits && Object.keys(edits).some(key => edits[key] !== ((0, _lodash.has)(post, [key, 'raw']) ? post[key].raw : post[key]))) {
yield editPost(edits);
}
}
/**
* Returns an action object signalling that the editor is being destroyed and
* that any necessary state or side-effect cleanup should occur.
*
* @return {Object} Action object.
*/
function __experimentalTearDownEditor() {
return {
type: 'TEAR_DOWN_EDITOR'
};
}
/**
* Returns an action object used in signalling that the latest version of the
* post has been received, either by initialization or save.
*
* @param {Object} post Post object.
*
* @return {Object} Action object.
*/
function resetPost(post) {
return {
type: 'RESET_POST',
post
};
}
/**
* Returns an action object used in signalling that the latest autosave of the
* post has been received, by initialization or autosave.
*
* @deprecated since 5.6. Callers should use the `receiveAutosaves( postId, autosave )`
* selector from the '@wordpress/core-data' package.
*
* @param {Object} newAutosave Autosave post object.
*
* @return {Object} Action object.
*/
function* resetAutosave(newAutosave) {
(0, _deprecated.default)('resetAutosave action (`core/editor` store)', {
since: '5.3',
alternative: 'receiveAutosaves action (`core` store)'
});
const postId = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPostId');
yield _data.controls.dispatch('core', 'receiveAutosaves', postId, newAutosave);
return {
type: '__INERT__'
};
}
/**
* Action for dispatching that a post update request has started.
*
* @param {Object} options
*
* @return {Object} An action object
*/
function __experimentalRequestPostUpdateStart(options = {}) {
return {
type: 'REQUEST_POST_UPDATE_START',
options
};
}
/**
* Action for dispatching that a post update request has finished.
*
* @param {Object} options
*
* @return {Object} An action object
*/
function __experimentalRequestPostUpdateFinish(options = {}) {
return {
type: 'REQUEST_POST_UPDATE_FINISH',
options
};
}
/**
* Returns an action object used in signalling that a patch of updates for the
* latest version of the post have been received.
*
* @return {Object} Action object.
* @deprecated since Gutenberg 9.7.0.
*/
function updatePost() {
(0, _deprecated.default)("wp.data.dispatch( 'core/editor' ).updatePost", {
since: '5.7',
alternative: 'User the core entitires store instead'
});
return {
type: 'DO_NOTHING'
};
}
/**
* Returns an action object used to setup the editor state when first opening
* an editor.
*
* @param {Object} post Post object.
*
* @return {Object} Action object.
*/
function setupEditorState(post) {
return {
type: 'SETUP_EDITOR_STATE',
post
};
}
/**
* Returns an action object used in signalling that attributes of the post have
* been edited.
*
* @param {Object} edits Post attributes to edit.
* @param {Object} options Options for the edit.
*
* @yield {Object} Action object or control.
*/
function* editPost(edits, options) {
const {
id,
type
} = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPost');
yield _data.controls.dispatch('core', 'editEntityRecord', 'postType', type, id, edits, options);
}
/**
* Action generator for saving the current post in the editor.
*
* @param {Object} options
*/
function* savePost(options = {}) {
if (!(yield _data.controls.select(_constants.STORE_NAME, 'isEditedPostSaveable'))) {
return;
}
let edits = {
content: yield _data.controls.select(_constants.STORE_NAME, 'getEditedPostContent')
};
if (!options.isAutosave) {
yield _data.controls.dispatch(_constants.STORE_NAME, 'editPost', edits, {
undoIgnore: true
});
}
yield __experimentalRequestPostUpdateStart(options);
const previousRecord = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPost');
edits = {
id: previousRecord.id,
...(yield _data.controls.select('core', 'getEntityRecordNonTransientEdits', 'postType', previousRecord.type, previousRecord.id)),
...edits
};
yield _data.controls.dispatch('core', 'saveEntityRecord', 'postType', previousRecord.type, edits, options);
yield __experimentalRequestPostUpdateFinish(options);
const error = yield _data.controls.select('core', 'getLastEntitySaveError', 'postType', previousRecord.type, previousRecord.id);
if (error) {
const args = (0, _noticeBuilder.getNotificationArgumentsForSaveFail)({
post: previousRecord,
edits,
error
});
if (args.length) {
yield _data.controls.dispatch(_notices.store, 'createErrorNotice', ...args);
}
} else {
const updatedRecord = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPost');
const args = (0, _noticeBuilder.getNotificationArgumentsForSaveSuccess)({
previousPost: previousRecord,
post: updatedRecord,
postType: yield _data.controls.resolveSelect('core', 'getPostType', updatedRecord.type),
options
});
if (args.length) {
yield _data.controls.dispatch(_notices.store, 'createSuccessNotice', ...args);
} // Make sure that any edits after saving create an undo level and are
// considered for change detection.
if (!options.isAutosave) {
yield _data.controls.dispatch('core/block-editor', '__unstableMarkLastChangeAsPersistent');
}
}
}
/**
* Action generator for handling refreshing the current post.
*/
function* refreshPost() {
const post = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPost');
const postTypeSlug = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPostType');
const postType = yield _data.controls.resolveSelect('core', 'getPostType', postTypeSlug);
const newPost = yield (0, _dataControls.apiFetch)({
// Timestamp arg allows caller to bypass browser caching, which is
// expected for this specific function.
path: `/wp/v2/${postType.rest_base}/${post.id}` + `?context=edit&_timestamp=${Date.now()}`
});
yield _data.controls.dispatch(_constants.STORE_NAME, 'resetPost', newPost);
}
/**
* Action generator for trashing the current post in the editor.
*/
function* trashPost() {
const postTypeSlug = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPostType');
const postType = yield _data.controls.resolveSelect('core', 'getPostType', postTypeSlug);
yield _data.controls.dispatch(_notices.store, 'removeNotice', _constants.TRASH_POST_NOTICE_ID);
try {
const post = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPost');
yield (0, _dataControls.apiFetch)({
path: `/wp/v2/${postType.rest_base}/${post.id}`,
method: 'DELETE'
});
yield _data.controls.dispatch(_constants.STORE_NAME, 'savePost');
} catch (error) {
yield _data.controls.dispatch(_notices.store, 'createErrorNotice', ...(0, _noticeBuilder.getNotificationArgumentsForTrashFail)({
error
}));
}
}
/**
* Action generator used in signalling that the post should autosave. This
* includes server-side autosaving (default) and client-side (a.k.a. local)
* autosaving (e.g. on the Web, the post might be committed to Session
* Storage).
*
* @param {Object?} options Extra flags to identify the autosave.
*/
function* autosave({
local = false,
...options
} = {}) {
if (local) {
const post = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPost');
const isPostNew = yield _data.controls.select(_constants.STORE_NAME, 'isEditedPostNew');
const title = yield _data.controls.select(_constants.STORE_NAME, 'getEditedPostAttribute', 'title');
const content = yield _data.controls.select(_constants.STORE_NAME, 'getEditedPostAttribute', 'content');
const excerpt = yield _data.controls.select(_constants.STORE_NAME, 'getEditedPostAttribute', 'excerpt');
yield {
type: 'LOCAL_AUTOSAVE_SET',
postId: post.id,
isPostNew,
title,
content,
excerpt
};
} else {
yield _data.controls.dispatch(_constants.STORE_NAME, 'savePost', {
isAutosave: true,
...options
});
}
}
/**
* Returns an action object used in signalling that undo history should
* restore last popped state.
*
* @yield {Object} Action object.
*/
function* redo() {
yield _data.controls.dispatch('core', 'redo');
}
/**
* Returns an action object used in signalling that undo history should pop.
*
* @yield {Object} Action object.
*/
function* undo() {
yield _data.controls.dispatch('core', 'undo');
}
/**
* Returns an action object used in signalling that undo history record should
* be created.
*
* @return {Object} Action object.
*/
function createUndoLevel() {
return {
type: 'CREATE_UNDO_LEVEL'
};
}
/**
* Returns an action object used to lock the editor.
*
* @param {Object} lock Details about the post lock status, user, and nonce.
*
* @return {Object} Action object.
*/
function updatePostLock(lock) {
return {
type: 'UPDATE_POST_LOCK',
lock
};
}
/**
* Returns an action object used in signalling that the user has enabled the
* publish sidebar.
*
* @return {Object} Action object
*/
function enablePublishSidebar() {
return {
type: 'ENABLE_PUBLISH_SIDEBAR'
};
}
/**
* Returns an action object used in signalling that the user has disabled the
* publish sidebar.
*
* @return {Object} Action object
*/
function disablePublishSidebar() {
return {
type: 'DISABLE_PUBLISH_SIDEBAR'
};
}
/**
* Returns an action object used to signal that post saving is locked.
*
* @param {string} lockName The lock name.
*
* @example
* ```
* const { subscribe } = wp.data;
*
* const initialPostStatus = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'status' );
*
* // Only allow publishing posts that are set to a future date.
* if ( 'publish' !== initialPostStatus ) {
*
* // Track locking.
* let locked = false;
*
* // Watch for the publish event.
* let unssubscribe = subscribe( () => {
* const currentPostStatus = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'status' );
* if ( 'publish' !== currentPostStatus ) {
*
* // Compare the post date to the current date, lock the post if the date isn't in the future.
* const postDate = new Date( wp.data.select( 'core/editor' ).getEditedPostAttribute( 'date' ) );
* const currentDate = new Date();
* if ( postDate.getTime() <= currentDate.getTime() ) {
* if ( ! locked ) {
* locked = true;
* wp.data.dispatch( 'core/editor' ).lockPostSaving( 'futurelock' );
* }
* } else {
* if ( locked ) {
* locked = false;
* wp.data.dispatch( 'core/editor' ).unlockPostSaving( 'futurelock' );
* }
* }
* }
* } );
* }
* ```
*
* @return {Object} Action object
*/
function lockPostSaving(lockName) {
return {
type: 'LOCK_POST_SAVING',
lockName
};
}
/**
* Returns an action object used to signal that post saving is unlocked.
*
* @param {string} lockName The lock name.
*
* @example
* ```
* // Unlock post saving with the lock key `mylock`:
* wp.data.dispatch( 'core/editor' ).unlockPostSaving( 'mylock' );
* ```
*
* @return {Object} Action object
*/
function unlockPostSaving(lockName) {
return {
type: 'UNLOCK_POST_SAVING',
lockName
};
}
/**
* Returns an action object used to signal that post autosaving is locked.
*
* @param {string} lockName The lock name.
*
* @example
* ```
* // Lock post autosaving with the lock key `mylock`:
* wp.data.dispatch( 'core/editor' ).lockPostAutosaving( 'mylock' );
* ```
*
* @return {Object} Action object
*/
function lockPostAutosaving(lockName) {
return {
type: 'LOCK_POST_AUTOSAVING',
lockName
};
}
/**
* Returns an action object used to signal that post autosaving is unlocked.
*
* @param {string} lockName The lock name.
*
* @example
* ```
* // Unlock post saving with the lock key `mylock`:
* wp.data.dispatch( 'core/editor' ).unlockPostAutosaving( 'mylock' );
* ```
*
* @return {Object} Action object
*/
function unlockPostAutosaving(lockName) {
return {
type: 'UNLOCK_POST_AUTOSAVING',
lockName
};
}
/**
* Returns an action object used to signal that the blocks have been updated.
*
* @param {Array} blocks Block Array.
* @param {?Object} options Optional options.
*
* @yield {Object} Action object
*/
function* resetEditorBlocks(blocks, options = {}) {
const {
__unstableShouldCreateUndoLevel,
selection
} = options;
const edits = {
blocks,
selection
};
if (__unstableShouldCreateUndoLevel !== false) {
const {
id,
type
} = yield _data.controls.select(_constants.STORE_NAME, 'getCurrentPost');
const noChange = (yield _data.controls.select('core', 'getEditedEntityRecord', 'postType', type, id)).blocks === edits.blocks;
if (noChange) {
return yield _data.controls.dispatch('core', '__unstableCreateUndoLevel', 'postType', type, id);
} // We create a new function here on every persistent edit
// to make sure the edit makes the post dirty and creates
// a new undo level.
edits.content = ({
blocks: blocksForSerialization = []
}) => (0, _blocks.__unstableSerializeAndClean)(blocksForSerialization);
}
yield* editPost(edits);
}
/*
* Returns an action object used in signalling that the post editor settings have been updated.
*
* @param {Object} settings Updated settings
*
* @return {Object} Action object
*/
function updateEditorSettings(settings) {
return {
type: 'UPDATE_EDITOR_SETTINGS',
settings
};
}
/**
* Backward compatibility
*/
const getBlockEditorAction = name => function* (...args) {
(0, _deprecated.default)("`wp.data.dispatch( 'core/editor' )." + name + '`', {
since: '5.3',
alternative: "`wp.data.dispatch( 'core/block-editor' )." + name + '`'
});
yield _data.controls.dispatch('core/block-editor', name, ...args);
};
/**
* @see resetBlocks in core/block-editor store.
*/
const resetBlocks = getBlockEditorAction('resetBlocks');
/**
* @see receiveBlocks in core/block-editor store.
*/
exports.resetBlocks = resetBlocks;
const receiveBlocks = getBlockEditorAction('receiveBlocks');
/**
* @see updateBlock in core/block-editor store.
*/
exports.receiveBlocks = receiveBlocks;
const updateBlock = getBlockEditorAction('updateBlock');
/**
* @see updateBlockAttributes in core/block-editor store.
*/
exports.updateBlock = updateBlock;
const updateBlockAttributes = getBlockEditorAction('updateBlockAttributes');
/**
* @see selectBlock in core/block-editor store.
*/
exports.updateBlockAttributes = updateBlockAttributes;
const selectBlock = getBlockEditorAction('selectBlock');
/**
* @see startMultiSelect in core/block-editor store.
*/
exports.selectBlock = selectBlock;
const startMultiSelect = getBlockEditorAction('startMultiSelect');
/**
* @see stopMultiSelect in core/block-editor store.
*/
exports.startMultiSelect = startMultiSelect;
const stopMultiSelect = getBlockEditorAction('stopMultiSelect');
/**
* @see multiSelect in core/block-editor store.
*/
exports.stopMultiSelect = stopMultiSelect;
const multiSelect = getBlockEditorAction('multiSelect');
/**
* @see clearSelectedBlock in core/block-editor store.
*/
exports.multiSelect = multiSelect;
const clearSelectedBlock = getBlockEditorAction('clearSelectedBlock');
/**
* @see toggleSelection in core/block-editor store.
*/
exports.clearSelectedBlock = clearSelectedBlock;
const toggleSelection = getBlockEditorAction('toggleSelection');
/**
* @see replaceBlocks in core/block-editor store.
*/
exports.toggleSelection = toggleSelection;
const replaceBlocks = getBlockEditorAction('replaceBlocks');
/**
* @see replaceBlock in core/block-editor store.
*/
exports.replaceBlocks = replaceBlocks;
const replaceBlock = getBlockEditorAction('replaceBlock');
/**
* @see moveBlocksDown in core/block-editor store.
*/
exports.replaceBlock = replaceBlock;
const moveBlocksDown = getBlockEditorAction('moveBlocksDown');
/**
* @see moveBlocksUp in core/block-editor store.
*/
exports.moveBlocksDown = moveBlocksDown;
const moveBlocksUp = getBlockEditorAction('moveBlocksUp');
/**
* @see moveBlockToPosition in core/block-editor store.
*/
exports.moveBlocksUp = moveBlocksUp;
const moveBlockToPosition = getBlockEditorAction('moveBlockToPosition');
/**
* @see insertBlock in core/block-editor store.
*/
exports.moveBlockToPosition = moveBlockToPosition;
const insertBlock = getBlockEditorAction('insertBlock');
/**
* @see insertBlocks in core/block-editor store.
*/
exports.insertBlock = insertBlock;
const insertBlocks = getBlockEditorAction('insertBlocks');
/**
* @see showInsertionPoint in core/block-editor store.
*/
exports.insertBlocks = insertBlocks;
const showInsertionPoint = getBlockEditorAction('showInsertionPoint');
/**
* @see hideInsertionPoint in core/block-editor store.
*/
exports.showInsertionPoint = showInsertionPoint;
const hideInsertionPoint = getBlockEditorAction('hideInsertionPoint');
/**
* @see setTemplateValidity in core/block-editor store.
*/
exports.hideInsertionPoint = hideInsertionPoint;
const setTemplateValidity = getBlockEditorAction('setTemplateValidity');
/**
* @see synchronizeTemplate in core/block-editor store.
*/
exports.setTemplateValidity = setTemplateValidity;
const synchronizeTemplate = getBlockEditorAction('synchronizeTemplate');
/**
* @see mergeBlocks in core/block-editor store.
*/
exports.synchronizeTemplate = synchronizeTemplate;
const mergeBlocks = getBlockEditorAction('mergeBlocks');
/**
* @see removeBlocks in core/block-editor store.
*/
exports.mergeBlocks = mergeBlocks;
const removeBlocks = getBlockEditorAction('removeBlocks');
/**
* @see removeBlock in core/block-editor store.
*/
exports.removeBlocks = removeBlocks;
const removeBlock = getBlockEditorAction('removeBlock');
/**
* @see toggleBlockMode in core/block-editor store.
*/
exports.removeBlock = removeBlock;
const toggleBlockMode = getBlockEditorAction('toggleBlockMode');
/**
* @see startTyping in core/block-editor store.
*/
exports.toggleBlockMode = toggleBlockMode;
const startTyping = getBlockEditorAction('startTyping');
/**
* @see stopTyping in core/block-editor store.
*/
exports.startTyping = startTyping;
const stopTyping = getBlockEditorAction('stopTyping');
/**
* @see enterFormattedText in core/block-editor store.
*/
exports.stopTyping = stopTyping;
const enterFormattedText = getBlockEditorAction('enterFormattedText');
/**
* @see exitFormattedText in core/block-editor store.
*/
exports.enterFormattedText = enterFormattedText;
const exitFormattedText = getBlockEditorAction('exitFormattedText');
/**
* @see insertDefaultBlock in core/block-editor store.
*/
exports.exitFormattedText = exitFormattedText;
const insertDefaultBlock = getBlockEditorAction('insertDefaultBlock');
/**
* @see updateBlockListSettings in core/block-editor store.
*/
exports.insertDefaultBlock = insertDefaultBlock;
const updateBlockListSettings = getBlockEditorAction('updateBlockListSettings');
exports.updateBlockListSettings = updateBlockListSettings;
//# sourceMappingURL=actions.js.map