UNPKG

netlify-cms-core

Version:

Netlify CMS core application, see netlify-cms package for the main distribution.

562 lines (479 loc) 17.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.Editor = void 0; var _debounce2 = _interopRequireDefault(require("lodash/debounce")); var _propTypes = _interopRequireDefault(require("prop-types")); var _react = _interopRequireDefault(require("react")); var _reactImmutableProptypes = _interopRequireDefault(require("react-immutable-proptypes")); var _reactRedux = require("react-redux"); var _netlifyCmsUiDefault = require("netlify-cms-ui-default"); var _reactPolyglot = require("react-polyglot"); var _history = require("../../routing/history"); var _auth = require("../../actions/auth"); var _entries = require("../../actions/entries"); var _editorialWorkflow = require("../../actions/editorialWorkflow"); var _deploys = require("../../actions/deploys"); var _reducers = require("../../reducers"); var _collections = require("../../reducers/collections"); var _publishModes = require("../../constants/publishModes"); var _EditorInterface = _interopRequireDefault(require("./EditorInterface")); var _withWorkflow = _interopRequireDefault(require("./withWorkflow")); var _core = require("@emotion/core"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } class Editor extends _react.default.Component { constructor() { var _this; super(...arguments); _this = this; _defineProperty(this, "createBackup", (0, _debounce2.default)(function (entry, collection) { this.props.persistLocalBackup(entry, collection); }, 2000)); _defineProperty(this, "handleChangeDraftField", (field, value, metadata, i18n) => { const entries = [this.props.unPublishedEntry, this.props.publishedEntry].filter(Boolean); this.props.changeDraftField({ field, value, metadata, entries, i18n }); }); _defineProperty(this, "handleChangeStatus", newStatusName => { const { entryDraft, updateUnpublishedEntryStatus, collection, slug, currentStatus, t } = this.props; if (entryDraft.get('hasChanged')) { window.alert(t('editor.editor.onUpdatingWithUnsavedChanges')); return; } const newStatus = _publishModes.status.get(newStatusName); updateUnpublishedEntryStatus(collection.get('name'), slug, currentStatus, newStatus); }); _defineProperty(this, "handlePersistEntry", async function () { let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; const { createNew = false, duplicate = false } = opts; const { persistEntry, collection, currentStatus, hasWorkflow, loadEntry, slug, createDraftDuplicateFromEntry, entryDraft } = _this.props; await persistEntry(collection); _this.deleteBackup(); if (createNew) { (0, _history.navigateToNewEntry)(collection.get('name')); duplicate && createDraftDuplicateFromEntry(entryDraft.get('entry')); } else if (slug && hasWorkflow && !currentStatus) { loadEntry(collection, slug); } }); _defineProperty(this, "handlePublishEntry", async function () { let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; const { createNew = false, duplicate = false } = opts; const { publishUnpublishedEntry, createDraftDuplicateFromEntry, entryDraft, collection, slug, currentStatus, t } = _this.props; if (currentStatus !== _publishModes.status.last()) { window.alert(t('editor.editor.onPublishingNotReady')); return; } else if (entryDraft.get('hasChanged')) { window.alert(t('editor.editor.onPublishingWithUnsavedChanges')); return; } else if (!window.confirm(t('editor.editor.onPublishing'))) { return; } await publishUnpublishedEntry(collection.get('name'), slug); _this.deleteBackup(); if (createNew) { (0, _history.navigateToNewEntry)(collection.get('name')); } duplicate && createDraftDuplicateFromEntry(entryDraft.get('entry')); }); _defineProperty(this, "handleUnpublishEntry", async () => { const { unpublishPublishedEntry, collection, slug, t } = this.props; if (!window.confirm(t('editor.editor.onUnpublishing'))) return; await unpublishPublishedEntry(collection, slug); return (0, _history.navigateToCollection)(collection.get('name')); }); _defineProperty(this, "handleDuplicateEntry", () => { const { createDraftDuplicateFromEntry, collection, entryDraft } = this.props; (0, _history.navigateToNewEntry)(collection.get('name')); createDraftDuplicateFromEntry(entryDraft.get('entry')); }); _defineProperty(this, "handleDeleteEntry", () => { const { entryDraft, newEntry, collection, deleteEntry, slug, t } = this.props; if (entryDraft.get('hasChanged')) { if (!window.confirm(t('editor.editor.onDeleteWithUnsavedChanges'))) { return; } } else if (!window.confirm(t('editor.editor.onDeletePublishedEntry'))) { return; } if (newEntry) { return (0, _history.navigateToCollection)(collection.get('name')); } setTimeout(async () => { await deleteEntry(collection, slug); this.deleteBackup(); return (0, _history.navigateToCollection)(collection.get('name')); }, 0); }); _defineProperty(this, "handleDeleteUnpublishedChanges", async () => { const { entryDraft, collection, slug, deleteUnpublishedEntry, loadEntry, isModification, t } = this.props; if (entryDraft.get('hasChanged') && !window.confirm(t('editor.editor.onDeleteUnpublishedChangesWithUnsavedChanges'))) { return; } else if (!window.confirm(t('editor.editor.onDeleteUnpublishedChanges'))) { return; } await deleteUnpublishedEntry(collection.get('name'), slug); this.deleteBackup(); if (isModification) { loadEntry(collection, slug); } else { (0, _history.navigateToCollection)(collection.get('name')); } }); } componentDidMount() { const { newEntry, collection, slug, loadEntry, createEmptyDraft, loadEntries, retrieveLocalBackup, collectionEntriesLoaded, t } = this.props; retrieveLocalBackup(collection, slug); if (newEntry) { createEmptyDraft(collection, this.props.location.search); } else { loadEntry(collection, slug); } const leaveMessage = t('editor.editor.onLeavePage'); this.exitBlocker = event => { if (this.props.entryDraft.get('hasChanged')) { // This message is ignored in most browsers, but its presence // triggers the confirmation dialog event.returnValue = leaveMessage; return leaveMessage; } }; window.addEventListener('beforeunload', this.exitBlocker); const navigationBlocker = (location, action) => { /** * New entry being saved and redirected to it's new slug based url. */ const isPersisting = this.props.entryDraft.getIn(['entry', 'isPersisting']); const newRecord = this.props.entryDraft.getIn(['entry', 'newRecord']); const newEntryPath = `/collections/${collection.get('name')}/new`; if (isPersisting && newRecord && this.props.location.pathname === newEntryPath && action === 'PUSH') { return; } if (this.props.hasChanged) { return leaveMessage; } }; const unblock = _history.history.block(navigationBlocker); /** * This will run as soon as the location actually changes, unless creating * a new post. The confirmation above will run first. */ this.unlisten = _history.history.listen((location, action) => { const newEntryPath = `/collections/${collection.get('name')}/new`; const entriesPath = `/collections/${collection.get('name')}/entries/`; const { pathname } = location; if (pathname.startsWith(newEntryPath) || pathname.startsWith(entriesPath) && action === 'PUSH') { return; } this.deleteBackup(); unblock(); this.unlisten(); }); if (!collectionEntriesLoaded) { loadEntries(collection); } } componentDidUpdate(prevProps) { if (!prevProps.localBackup && this.props.localBackup) { const confirmLoadBackup = window.confirm(this.props.t('editor.editor.confirmLoadBackup')); if (confirmLoadBackup) { this.props.loadLocalBackup(); } else { this.deleteBackup(); } } if (this.props.hasChanged) { this.createBackup(this.props.entryDraft.get('entry'), this.props.collection); } if (prevProps.entry === this.props.entry) return; const { newEntry, collection } = this.props; if (newEntry) { prevProps.createEmptyDraft(collection, this.props.location.search); } } componentWillUnmount() { this.createBackup.flush(); this.props.discardDraft(); window.removeEventListener('beforeunload', this.exitBlocker); } deleteBackup() { const { deleteLocalBackup, collection, slug, newEntry } = this.props; this.createBackup.cancel(); deleteLocalBackup(collection, !newEntry && slug); } render() { const { entry, entryDraft, fields, collection, changeDraftFieldValidation, user, hasChanged, displayUrl, hasWorkflow, useOpenAuthoring, unpublishedEntry, newEntry, isModification, currentStatus, logoutUser, deployPreview, loadDeployPreview, draftKey, slug, t, editorBackLink } = this.props; const isPublished = !newEntry && !unpublishedEntry; if (entry && entry.get('error')) { return (0, _core.jsx)("div", null, (0, _core.jsx)("h3", null, entry.get('error'))); } else if (entryDraft == null || entryDraft.get('entry') === undefined || entry && entry.get('isFetching')) { return (0, _core.jsx)(_netlifyCmsUiDefault.Loader, { active: true }, t('editor.editor.loadingEntry')); } return (0, _core.jsx)(_EditorInterface.default, { draftKey: draftKey, entry: entryDraft.get('entry'), collection: collection, fields: fields, fieldsMetaData: entryDraft.get('fieldsMetaData'), fieldsErrors: entryDraft.get('fieldsErrors'), onChange: this.handleChangeDraftField, onValidate: changeDraftFieldValidation, onPersist: this.handlePersistEntry, onDelete: this.handleDeleteEntry, onDeleteUnpublishedChanges: this.handleDeleteUnpublishedChanges, onChangeStatus: this.handleChangeStatus, onPublish: this.handlePublishEntry, unPublish: this.handleUnpublishEntry, onDuplicate: this.handleDuplicateEntry, showDelete: this.props.showDelete, user: user, hasChanged: hasChanged, displayUrl: displayUrl, hasWorkflow: hasWorkflow, useOpenAuthoring: useOpenAuthoring, hasUnpublishedChanges: unpublishedEntry, isNewEntry: newEntry, isModification: isModification, currentStatus: currentStatus, onLogoutClick: logoutUser, deployPreview: deployPreview, loadDeployPreview: opts => loadDeployPreview(collection, slug, entry, isPublished, opts), editorBackLink: editorBackLink, t: t }); } } exports.Editor = Editor; _defineProperty(Editor, "propTypes", { changeDraftField: _propTypes.default.func.isRequired, changeDraftFieldValidation: _propTypes.default.func.isRequired, collection: _reactImmutableProptypes.default.map.isRequired, createDraftDuplicateFromEntry: _propTypes.default.func.isRequired, createEmptyDraft: _propTypes.default.func.isRequired, discardDraft: _propTypes.default.func.isRequired, entry: _reactImmutableProptypes.default.map, entryDraft: _reactImmutableProptypes.default.map.isRequired, loadEntry: _propTypes.default.func.isRequired, persistEntry: _propTypes.default.func.isRequired, deleteEntry: _propTypes.default.func.isRequired, showDelete: _propTypes.default.bool.isRequired, fields: _reactImmutableProptypes.default.list.isRequired, slug: _propTypes.default.string, newEntry: _propTypes.default.bool.isRequired, displayUrl: _propTypes.default.string, hasWorkflow: _propTypes.default.bool, useOpenAuthoring: _propTypes.default.bool, unpublishedEntry: _propTypes.default.bool, isModification: _propTypes.default.bool, collectionEntriesLoaded: _propTypes.default.bool, updateUnpublishedEntryStatus: _propTypes.default.func.isRequired, publishUnpublishedEntry: _propTypes.default.func.isRequired, deleteUnpublishedEntry: _propTypes.default.func.isRequired, logoutUser: _propTypes.default.func.isRequired, loadEntries: _propTypes.default.func.isRequired, deployPreview: _propTypes.default.object, loadDeployPreview: _propTypes.default.func.isRequired, currentStatus: _propTypes.default.string, user: _propTypes.default.object, location: _propTypes.default.shape({ pathname: _propTypes.default.string, search: _propTypes.default.string }), hasChanged: _propTypes.default.bool, t: _propTypes.default.func.isRequired, retrieveLocalBackup: _propTypes.default.func.isRequired, localBackup: _reactImmutableProptypes.default.map, loadLocalBackup: _propTypes.default.func, persistLocalBackup: _propTypes.default.func.isRequired, deleteLocalBackup: _propTypes.default.func }); function mapStateToProps(state, ownProps) { const { collections, entryDraft, auth, config, entries, globalUI } = state; const slug = ownProps.match.params[0]; const collection = collections.get(ownProps.match.params.name); const collectionName = collection.get('name'); const newEntry = ownProps.newRecord === true; const fields = (0, _collections.selectFields)(collection, slug); const entry = newEntry ? null : (0, _reducers.selectEntry)(state, collectionName, slug); const user = auth.user; const hasChanged = entryDraft.get('hasChanged'); const displayUrl = config.display_url; const hasWorkflow = config.publish_mode === _publishModes.EDITORIAL_WORKFLOW; const useOpenAuthoring = globalUI.useOpenAuthoring; const isModification = entryDraft.getIn(['entry', 'isModification']); const collectionEntriesLoaded = !!entries.getIn(['pages', collectionName]); const unPublishedEntry = (0, _reducers.selectUnpublishedEntry)(state, collectionName, slug); const publishedEntry = (0, _reducers.selectEntry)(state, collectionName, slug); const currentStatus = unPublishedEntry && unPublishedEntry.get('status'); const deployPreview = (0, _reducers.selectDeployPreview)(state, collectionName, slug); const localBackup = entryDraft.get('localBackup'); const draftKey = entryDraft.get('key'); let editorBackLink = `/collections/${collectionName}`; if (new URLSearchParams(ownProps.location.search).get('ref') === 'workflow') { editorBackLink = `/workflow`; } if (collection.has('nested') && slug) { const pathParts = slug.split('/'); if (pathParts.length > 2) { editorBackLink = `${editorBackLink}/filter/${pathParts.slice(0, -2).join('/')}`; } } return { collection, collections, newEntry, entryDraft, fields, slug, entry, user, hasChanged, displayUrl, hasWorkflow, useOpenAuthoring, isModification, collectionEntriesLoaded, currentStatus, deployPreview, localBackup, draftKey, publishedEntry, unPublishedEntry, editorBackLink }; } const mapDispatchToProps = { changeDraftField: _entries.changeDraftField, changeDraftFieldValidation: _entries.changeDraftFieldValidation, loadEntry: _entries.loadEntry, loadEntries: _entries.loadEntries, loadDeployPreview: _deploys.loadDeployPreview, loadLocalBackup: _entries.loadLocalBackup, retrieveLocalBackup: _entries.retrieveLocalBackup, persistLocalBackup: _entries.persistLocalBackup, deleteLocalBackup: _entries.deleteLocalBackup, createDraftDuplicateFromEntry: _entries.createDraftDuplicateFromEntry, createEmptyDraft: _entries.createEmptyDraft, discardDraft: _entries.discardDraft, persistEntry: _entries.persistEntry, deleteEntry: _entries.deleteEntry, updateUnpublishedEntryStatus: _editorialWorkflow.updateUnpublishedEntryStatus, publishUnpublishedEntry: _editorialWorkflow.publishUnpublishedEntry, unpublishPublishedEntry: _editorialWorkflow.unpublishPublishedEntry, deleteUnpublishedEntry: _editorialWorkflow.deleteUnpublishedEntry, logoutUser: _auth.logoutUser }; var _default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withWorkflow.default)((0, _reactPolyglot.translate)()(Editor))); exports.default = _default;