@wordpress/edit-post
Version:
Edit Post module for WordPress.
412 lines (368 loc) • 11.9 kB
JavaScript
/**
* External dependencies
*/
import { castArray, reduce } from 'lodash';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { apiFetch } from '@wordpress/data-controls';
import { store as interfaceStore } from '@wordpress/interface';
import { controls, dispatch, select, subscribe } from '@wordpress/data';
import { speak } from '@wordpress/a11y';
import { store as noticesStore } from '@wordpress/notices';
import { store as coreStore } from '@wordpress/core-data';
/**
* Internal dependencies
*/
import { getMetaBoxContainer } from '../utils/meta-boxes';
import { store as editPostStore } from '.';
/**
* Returns an action object used in signalling that the user opened an editor sidebar.
*
* @param {?string} name Sidebar name to be opened.
*
* @yield {Object} Action object.
*/
export function* openGeneralSidebar(name) {
yield controls.dispatch(interfaceStore.name, 'enableComplementaryArea', editPostStore.name, name);
}
/**
* Returns an action object signalling that the user closed the sidebar.
*
* @yield {Object} Action object.
*/
export function* closeGeneralSidebar() {
yield controls.dispatch(interfaceStore.name, 'disableComplementaryArea', editPostStore.name);
}
/**
* Returns an action object used in signalling that the user opened a modal.
*
* @param {string} name A string that uniquely identifies the modal.
*
* @return {Object} Action object.
*/
export function openModal(name) {
return {
type: 'OPEN_MODAL',
name
};
}
/**
* Returns an action object signalling that the user closed a modal.
*
* @return {Object} Action object.
*/
export function closeModal() {
return {
type: 'CLOSE_MODAL'
};
}
/**
* Returns an action object used in signalling that the user opened the publish
* sidebar.
*
* @return {Object} Action object
*/
export function openPublishSidebar() {
return {
type: 'OPEN_PUBLISH_SIDEBAR'
};
}
/**
* Returns an action object used in signalling that the user closed the
* publish sidebar.
*
* @return {Object} Action object.
*/
export function closePublishSidebar() {
return {
type: 'CLOSE_PUBLISH_SIDEBAR'
};
}
/**
* Returns an action object used in signalling that the user toggles the publish sidebar.
*
* @return {Object} Action object
*/
export function togglePublishSidebar() {
return {
type: 'TOGGLE_PUBLISH_SIDEBAR'
};
}
/**
* Returns an action object used to enable or disable a panel in the editor.
*
* @param {string} panelName A string that identifies the panel to enable or disable.
*
* @return {Object} Action object.
*/
export function toggleEditorPanelEnabled(panelName) {
return {
type: 'TOGGLE_PANEL_ENABLED',
panelName
};
}
/**
* Returns an action object used to open or close a panel in the editor.
*
* @param {string} panelName A string that identifies the panel to open or close.
*
* @return {Object} Action object.
*/
export function toggleEditorPanelOpened(panelName) {
return {
type: 'TOGGLE_PANEL_OPENED',
panelName
};
}
/**
* Returns an action object used to remove a panel from the editor.
*
* @param {string} panelName A string that identifies the panel to remove.
*
* @return {Object} Action object.
*/
export function removeEditorPanel(panelName) {
return {
type: 'REMOVE_PANEL',
panelName
};
}
/**
* Returns an action object used to toggle a feature flag.
*
* @param {string} feature Feature name.
*
* @return {Object} Action object.
*/
export function toggleFeature(feature) {
return {
type: 'TOGGLE_FEATURE',
feature
};
}
export function* switchEditorMode(mode) {
yield {
type: 'SWITCH_MODE',
mode
}; // Unselect blocks when we switch to the code editor.
if (mode !== 'visual') {
yield controls.dispatch('core/block-editor', 'clearSelectedBlock');
}
const message = mode === 'visual' ? __('Visual editor selected') : __('Code editor selected');
speak(message, 'assertive');
}
/**
* Returns an action object used to toggle a plugin name flag.
*
* @param {string} pluginName Plugin name.
*
* @return {Object} Action object.
*/
export function togglePinnedPluginItem(pluginName) {
return {
type: 'TOGGLE_PINNED_PLUGIN_ITEM',
pluginName
};
}
/**
* Returns an action object used in signalling that block types by the given
* name(s) should be hidden.
*
* @param {string[]} blockNames Names of block types to hide.
*
* @return {Object} Action object.
*/
export function hideBlockTypes(blockNames) {
return {
type: 'HIDE_BLOCK_TYPES',
blockNames: castArray(blockNames)
};
}
/**
* Returns an action object used in signaling that a style should be auto-applied when a block is created.
*
* @param {string} blockName Name of the block.
* @param {?string} blockStyle Name of the style that should be auto applied. If undefined, the "auto apply" setting of the block is removed.
*
* @return {Object} Action object.
*/
export function updatePreferredStyleVariations(blockName, blockStyle) {
return {
type: 'UPDATE_PREFERRED_STYLE_VARIATIONS',
blockName,
blockStyle
};
}
/**
* Returns an action object used in signalling that the editor should attempt
* to locally autosave the current post every `interval` seconds.
*
* @param {number} interval The new interval, in seconds.
* @return {Object} Action object.
*/
export function __experimentalUpdateLocalAutosaveInterval(interval) {
return {
type: 'UPDATE_LOCAL_AUTOSAVE_INTERVAL',
interval
};
}
/**
* Returns an action object used in signalling that block types by the given
* name(s) should be shown.
*
* @param {string[]} blockNames Names of block types to show.
*
* @return {Object} Action object.
*/
export function showBlockTypes(blockNames) {
return {
type: 'SHOW_BLOCK_TYPES',
blockNames: castArray(blockNames)
};
}
let saveMetaboxUnsubscribe;
/**
* Returns an action object used in signaling
* what Meta boxes are available in which location.
*
* @param {Object} metaBoxesPerLocation Meta boxes per location.
*
* @yield {Object} Action object.
*/
export function* setAvailableMetaBoxesPerLocation(metaBoxesPerLocation) {
yield {
type: 'SET_META_BOXES_PER_LOCATIONS',
metaBoxesPerLocation
};
const postType = yield controls.select('core/editor', 'getCurrentPostType');
if (window.postboxes.page !== postType) {
window.postboxes.add_postbox_toggles(postType);
}
let wasSavingPost = yield controls.select('core/editor', 'isSavingPost');
let wasAutosavingPost = yield controls.select('core/editor', 'isAutosavingPost'); // Meta boxes are initialized once at page load. It is not necessary to
// account for updates on each state change.
//
// See: https://github.com/WordPress/WordPress/blob/5.1.1/wp-admin/includes/post.php#L2307-L2309
const hasActiveMetaBoxes = yield controls.select(editPostStore.name, 'hasMetaBoxes'); // First remove any existing subscription in order to prevent multiple saves
if (!!saveMetaboxUnsubscribe) {
saveMetaboxUnsubscribe();
} // Save metaboxes when performing a full save on the post.
saveMetaboxUnsubscribe = subscribe(() => {
const isSavingPost = select('core/editor').isSavingPost();
const isAutosavingPost = select('core/editor').isAutosavingPost(); // Save metaboxes on save completion, except for autosaves that are not a post preview.
const shouldTriggerMetaboxesSave = hasActiveMetaBoxes && wasSavingPost && !isSavingPost && !wasAutosavingPost; // Save current state for next inspection.
wasSavingPost = isSavingPost;
wasAutosavingPost = isAutosavingPost;
if (shouldTriggerMetaboxesSave) {
dispatch(editPostStore.name).requestMetaBoxUpdates();
}
});
}
/**
* Returns an action object used to request meta box update.
*
* @yield {Object} Action object.
*/
export function* requestMetaBoxUpdates() {
yield {
type: 'REQUEST_META_BOX_UPDATES'
}; // Saves the wp_editor fields
if (window.tinyMCE) {
window.tinyMCE.triggerSave();
} // Additional data needed for backward compatibility.
// If we do not provide this data, the post will be overridden with the default values.
const post = yield controls.select('core/editor', 'getCurrentPost');
const additionalData = [post.comment_status ? ['comment_status', post.comment_status] : false, post.ping_status ? ['ping_status', post.ping_status] : false, post.sticky ? ['sticky', post.sticky] : false, post.author ? ['post_author', post.author] : false].filter(Boolean); // We gather all the metaboxes locations data and the base form data
const baseFormData = new window.FormData(document.querySelector('.metabox-base-form'));
const activeMetaBoxLocations = yield controls.select(editPostStore.name, 'getActiveMetaBoxLocations');
const formDataToMerge = [baseFormData, ...activeMetaBoxLocations.map(location => new window.FormData(getMetaBoxContainer(location)))]; // Merge all form data objects into a single one.
const formData = reduce(formDataToMerge, (memo, currentFormData) => {
for (const [key, value] of currentFormData) {
memo.append(key, value);
}
return memo;
}, new window.FormData());
additionalData.forEach(([key, value]) => formData.append(key, value)); // Save the metaboxes
yield apiFetch({
url: window._wpMetaBoxUrl,
method: 'POST',
body: formData,
parse: false
});
yield controls.dispatch(editPostStore.name, 'metaBoxUpdatesSuccess');
}
/**
* Returns an action object used signal a successful meta box update.
*
* @return {Object} Action object.
*/
export function metaBoxUpdatesSuccess() {
return {
type: 'META_BOX_UPDATES_SUCCESS'
};
}
/**
* Returns an action object used to toggle the width of the editing canvas.
*
* @param {string} deviceType
*
* @return {Object} Action object.
*/
export function __experimentalSetPreviewDeviceType(deviceType) {
return {
type: 'SET_PREVIEW_DEVICE_TYPE',
deviceType
};
}
/**
* Returns an action object used to open/close the inserter.
*
* @param {boolean|Object} value Whether the inserter should be
* opened (true) or closed (false).
* To specify an insertion point,
* use an object.
* @param {string} value.rootClientId The root client ID to insert at.
* @param {number} value.insertionIndex The index to insert at.
*
* @return {Object} Action object.
*/
export function setIsInserterOpened(value) {
return {
type: 'SET_IS_INSERTER_OPENED',
value
};
}
/**
* Returns an action object used to switch to template editing.
*
* @param {boolean} value Is editing template.
* @return {Object} Action object.
*/
export function setIsEditingTemplate(value) {
return {
type: 'SET_IS_EDITING_TEMPLATE',
value
};
}
/**
* Potentially create a block based template and switches to the template mode.
*
* @param {Object?} template template to create and assign before switching.
*/
export function* __unstableSwitchToTemplateMode(template) {
if (!!template) {
const savedTemplate = yield controls.dispatch(coreStore, 'saveEntityRecord', 'postType', 'wp_template', template);
const post = yield controls.select('core/editor', 'getCurrentPost');
yield controls.dispatch(coreStore, 'editEntityRecord', 'postType', post.type, post.id, {
template: savedTemplate.slug
});
}
yield setIsEditingTemplate(true);
const message = !!template ? __("Custom template created. You're in template mode now.") : __('Editing template. Changes made here affect all posts and pages that use the template.');
yield controls.dispatch(noticesStore, 'createSuccessNotice', message, {
type: 'snackbar'
});
}
//# sourceMappingURL=actions.js.map