UNPKG

@wordpress/editor

Version:
365 lines (354 loc) 14.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); var _exportNames = { setCurrentTemplateId: true, createTemplate: true, showBlockTypes: true, hideBlockTypes: true, saveDirtyEntities: true, revertTemplate: true, removeTemplates: true }; exports.saveDirtyEntities = exports.revertTemplate = exports.removeTemplates = exports.hideBlockTypes = exports.createTemplate = void 0; exports.setCurrentTemplateId = setCurrentTemplateId; exports.showBlockTypes = void 0; var _coreData = require("@wordpress/core-data"); var _i18n = require("@wordpress/i18n"); var _notices = require("@wordpress/notices"); var _blockEditor = require("@wordpress/block-editor"); var _preferences = require("@wordpress/preferences"); var _url = require("@wordpress/url"); var _apiFetch = _interopRequireDefault(require("@wordpress/api-fetch")); var _blocks = require("@wordpress/blocks"); var _htmlEntities = require("@wordpress/html-entities"); var _isTemplateRevertable = _interopRequireDefault(require("./utils/is-template-revertable")); var _privateActions = require("../dataviews/store/private-actions"); Object.keys(_privateActions).forEach(function (key) { if (key === "default" || key === "__esModule") return; if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; if (key in exports && exports[key] === _privateActions[key]) return; Object.defineProperty(exports, key, { enumerable: true, get: function () { return _privateActions[key]; } }); }); /** * WordPress dependencies */ /** * Internal dependencies */ /** * Returns an action object used to set which template is currently being used/edited. * * @param {string} id Template Id. * * @return {Object} Action object. */ function setCurrentTemplateId(id) { return { type: 'SET_CURRENT_TEMPLATE_ID', id }; } /** * Create a block based template. * * @param {Object?} template Template to create and assign. */ const createTemplate = template => async ({ select, dispatch, registry }) => { const savedTemplate = await registry.dispatch(_coreData.store).saveEntityRecord('postType', 'wp_template', template); registry.dispatch(_coreData.store).editEntityRecord('postType', select.getCurrentPostType(), select.getCurrentPostId(), { template: savedTemplate.slug }); registry.dispatch(_notices.store).createSuccessNotice((0, _i18n.__)("Custom template created. You're in template mode now."), { type: 'snackbar', actions: [{ label: (0, _i18n.__)('Go back'), onClick: () => dispatch.setRenderingMode(select.getEditorSettings().defaultRenderingMode) }] }); return savedTemplate; }; /** * Update the provided block types to be visible. * * @param {string[]} blockNames Names of block types to show. */ exports.createTemplate = createTemplate; const showBlockTypes = blockNames => ({ registry }) => { var _registry$select$get; const existingBlockNames = (_registry$select$get = registry.select(_preferences.store).get('core', 'hiddenBlockTypes')) !== null && _registry$select$get !== void 0 ? _registry$select$get : []; const newBlockNames = existingBlockNames.filter(type => !(Array.isArray(blockNames) ? blockNames : [blockNames]).includes(type)); registry.dispatch(_preferences.store).set('core', 'hiddenBlockTypes', newBlockNames); }; /** * Update the provided block types to be hidden. * * @param {string[]} blockNames Names of block types to hide. */ exports.showBlockTypes = showBlockTypes; const hideBlockTypes = blockNames => ({ registry }) => { var _registry$select$get2; const existingBlockNames = (_registry$select$get2 = registry.select(_preferences.store).get('core', 'hiddenBlockTypes')) !== null && _registry$select$get2 !== void 0 ? _registry$select$get2 : []; const mergedBlockNames = new Set([...existingBlockNames, ...(Array.isArray(blockNames) ? blockNames : [blockNames])]); registry.dispatch(_preferences.store).set('core', 'hiddenBlockTypes', [...mergedBlockNames]); }; /** * Save entity records marked as dirty. * * @param {Object} options Options for the action. * @param {Function} [options.onSave] Callback when saving happens. * @param {object[]} [options.dirtyEntityRecords] Array of dirty entities. * @param {object[]} [options.entitiesToSkip] Array of entities to skip saving. * @param {Function} [options.close] Callback when the actions is called. It should be consolidated with `onSave`. */ exports.hideBlockTypes = hideBlockTypes; const saveDirtyEntities = ({ onSave, dirtyEntityRecords = [], entitiesToSkip = [], close } = {}) => ({ registry }) => { const PUBLISH_ON_SAVE_ENTITIES = [{ kind: 'postType', name: 'wp_navigation' }]; const saveNoticeId = 'site-editor-save-success'; const homeUrl = registry.select(_coreData.store).getEntityRecord('root', '__unstableBase')?.home; registry.dispatch(_notices.store).removeNotice(saveNoticeId); const entitiesToSave = dirtyEntityRecords.filter(({ kind, name, key, property }) => { return !entitiesToSkip.some(elt => elt.kind === kind && elt.name === name && elt.key === key && elt.property === property); }); close?.(entitiesToSave); const siteItemsToSave = []; const pendingSavedRecords = []; entitiesToSave.forEach(({ kind, name, key, property }) => { if ('root' === kind && 'site' === name) { siteItemsToSave.push(property); } else { if (PUBLISH_ON_SAVE_ENTITIES.some(typeToPublish => typeToPublish.kind === kind && typeToPublish.name === name)) { registry.dispatch(_coreData.store).editEntityRecord(kind, name, key, { status: 'publish' }); } pendingSavedRecords.push(registry.dispatch(_coreData.store).saveEditedEntityRecord(kind, name, key)); } }); if (siteItemsToSave.length) { pendingSavedRecords.push(registry.dispatch(_coreData.store).__experimentalSaveSpecifiedEntityEdits('root', 'site', undefined, siteItemsToSave)); } registry.dispatch(_blockEditor.store).__unstableMarkLastChangeAsPersistent(); Promise.all(pendingSavedRecords).then(values => { return onSave ? onSave(values) : values; }).then(values => { if (values.some(value => typeof value === 'undefined')) { registry.dispatch(_notices.store).createErrorNotice((0, _i18n.__)('Saving failed.')); } else { registry.dispatch(_notices.store).createSuccessNotice((0, _i18n.__)('Site updated.'), { type: 'snackbar', id: saveNoticeId, actions: [{ label: (0, _i18n.__)('View site'), url: homeUrl }] }); } }).catch(error => registry.dispatch(_notices.store).createErrorNotice(`${(0, _i18n.__)('Saving failed.')} ${error}`)); }; /** * Reverts a template to its original theme-provided file. * * @param {Object} template The template to revert. * @param {Object} [options] * @param {boolean} [options.allowUndo] Whether to allow the user to undo * reverting the template. Default true. */ exports.saveDirtyEntities = saveDirtyEntities; const revertTemplate = (template, { allowUndo = true } = {}) => async ({ registry }) => { const noticeId = 'edit-site-template-reverted'; registry.dispatch(_notices.store).removeNotice(noticeId); if (!(0, _isTemplateRevertable.default)(template)) { registry.dispatch(_notices.store).createErrorNotice((0, _i18n.__)('This template is not revertable.'), { type: 'snackbar' }); return; } try { const templateEntityConfig = registry.select(_coreData.store).getEntityConfig('postType', template.type); if (!templateEntityConfig) { registry.dispatch(_notices.store).createErrorNotice((0, _i18n.__)('The editor has encountered an unexpected error. Please reload.'), { type: 'snackbar' }); return; } const fileTemplatePath = (0, _url.addQueryArgs)(`${templateEntityConfig.baseURL}/${template.id}`, { context: 'edit', source: template.origin }); const fileTemplate = await (0, _apiFetch.default)({ path: fileTemplatePath }); if (!fileTemplate) { registry.dispatch(_notices.store).createErrorNotice((0, _i18n.__)('The editor has encountered an unexpected error. Please reload.'), { type: 'snackbar' }); return; } const serializeBlocks = ({ blocks: blocksForSerialization = [] }) => (0, _blocks.__unstableSerializeAndClean)(blocksForSerialization); const edited = registry.select(_coreData.store).getEditedEntityRecord('postType', template.type, template.id); // We are fixing up the undo level here to make sure we can undo // the revert in the header toolbar correctly. registry.dispatch(_coreData.store).editEntityRecord('postType', template.type, template.id, { content: serializeBlocks, // Required to make the `undo` behave correctly. blocks: edited.blocks, // Required to revert the blocks in the editor. source: 'custom' // required to avoid turning the editor into a dirty state }, { undoIgnore: true // Required to merge this edit with the last undo level. }); const blocks = (0, _blocks.parse)(fileTemplate?.content?.raw); registry.dispatch(_coreData.store).editEntityRecord('postType', template.type, fileTemplate.id, { content: serializeBlocks, blocks, source: 'theme' }); if (allowUndo) { const undoRevert = () => { registry.dispatch(_coreData.store).editEntityRecord('postType', template.type, edited.id, { content: serializeBlocks, blocks: edited.blocks, source: 'custom' }); }; registry.dispatch(_notices.store).createSuccessNotice((0, _i18n.__)('Template reset.'), { type: 'snackbar', id: noticeId, actions: [{ label: (0, _i18n.__)('Undo'), onClick: undoRevert }] }); } } catch (error) { const errorMessage = error.message && error.code !== 'unknown_error' ? error.message : (0, _i18n.__)('Template revert failed. Please reload.'); registry.dispatch(_notices.store).createErrorNotice(errorMessage, { type: 'snackbar' }); } }; /** * Action that removes an array of templates, template parts or patterns. * * @param {Array} items An array of template,template part or pattern objects to remove. */ exports.revertTemplate = revertTemplate; const removeTemplates = items => async ({ registry }) => { const isResetting = items.every(item => item?.has_theme_file); const promiseResult = await Promise.allSettled(items.map(item => { return registry.dispatch(_coreData.store).deleteEntityRecord('postType', item.type, item.id, { force: true }, { throwOnError: true }); })); // If all the promises were fulfilled with sucess. if (promiseResult.every(({ status }) => status === 'fulfilled')) { let successMessage; if (items.length === 1) { // Depending on how the entity was retrieved its title might be // an object or simple string. let title; if (typeof items[0].title === 'string') { title = items[0].title; } else if (typeof items[0].title?.rendered === 'string') { title = items[0].title?.rendered; } else if (typeof items[0].title?.raw === 'string') { title = items[0].title?.raw; } successMessage = isResetting ? (0, _i18n.sprintf)( /* translators: The template/part's name. */ (0, _i18n.__)('"%s" reset.'), (0, _htmlEntities.decodeEntities)(title)) : (0, _i18n.sprintf)( /* translators: The template/part's name. */ (0, _i18n.__)('"%s" deleted.'), (0, _htmlEntities.decodeEntities)(title)); } else { successMessage = isResetting ? (0, _i18n.__)('Items reset.') : (0, _i18n.__)('Items deleted.'); } registry.dispatch(_notices.store).createSuccessNotice(successMessage, { type: 'snackbar', id: 'editor-template-deleted-success' }); } else { // If there was at lease one failure. let errorMessage; // If we were trying to delete a single template. if (promiseResult.length === 1) { if (promiseResult[0].reason?.message) { errorMessage = promiseResult[0].reason.message; } else { errorMessage = isResetting ? (0, _i18n.__)('An error occurred while reverting the item.') : (0, _i18n.__)('An error occurred while deleting the item.'); } // If we were trying to delete a multiple templates } else { const errorMessages = new Set(); const failedPromises = promiseResult.filter(({ status }) => status === 'rejected'); for (const failedPromise of failedPromises) { if (failedPromise.reason?.message) { errorMessages.add(failedPromise.reason.message); } } if (errorMessages.size === 0) { errorMessage = (0, _i18n.__)('An error occurred while deleting the items.'); } else if (errorMessages.size === 1) { errorMessage = isResetting ? (0, _i18n.sprintf)( /* translators: %s: an error message */ (0, _i18n.__)('An error occurred while reverting the items: %s'), [...errorMessages][0]) : (0, _i18n.sprintf)( /* translators: %s: an error message */ (0, _i18n.__)('An error occurred while deleting the items: %s'), [...errorMessages][0]); } else { errorMessage = isResetting ? (0, _i18n.sprintf)( /* translators: %s: a list of comma separated error messages */ (0, _i18n.__)('Some errors occurred while reverting the items: %s'), [...errorMessages].join(',')) : (0, _i18n.sprintf)( /* translators: %s: a list of comma separated error messages */ (0, _i18n.__)('Some errors occurred while deleting the items: %s'), [...errorMessages].join(',')); } } registry.dispatch(_notices.store).createErrorNotice(errorMessage, { type: 'snackbar' }); } }; exports.removeTemplates = removeTemplates; //# sourceMappingURL=private-actions.js.map