Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate block editor initializations #27954

Merged
merged 5 commits into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/blocks/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export {
getSaveElement,
getSaveContent,
getBlockProps as __unstableGetBlockProps,
__unstableSerializeAndClean,
} from './serializer';

// Validation is the process of comparing a block source with its output before
Expand Down
25 changes: 24 additions & 1 deletion packages/blocks/src/api/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { isEmpty, reduce, isObject, castArray, startsWith } from 'lodash';
import { Component, cloneElement, renderToString } from '@wordpress/element';
import { hasFilter, applyFilters } from '@wordpress/hooks';
import isShallowEqual from '@wordpress/is-shallow-equal';
import { removep } from '@wordpress/autop';

/**
* Internal dependencies
Expand All @@ -19,7 +20,7 @@ import {
getUnregisteredTypeHandlerName,
hasBlockSupport,
} from './registration';
import { normalizeBlockType } from './utils';
import { isUnmodifiedDefaultBlock, normalizeBlockType } from './utils';
import BlockContentProvider from '../block-content-provider';

/**
Expand Down Expand Up @@ -349,6 +350,28 @@ export function serializeBlock( block, { isInnerBlocks = false } = {} ) {
return getCommentDelimitedContent( blockName, saveAttributes, saveContent );
}

export function __unstableSerializeAndClean( blocks ) {
// A single unmodified default block is assumed to
// be equivalent to an empty post.
if ( blocks.length === 1 && isUnmodifiedDefaultBlock( blocks[ 0 ] ) ) {
blocks = [];
}

let content = serialize( blocks );

// For compatibility, treat a post consisting of a
// single freeform block as legacy content and apply
// pre-block-editor removep'd content formatting.
if (
blocks.length === 1 &&
blocks[ 0 ].name === getFreeformContentHandlerName()
) {
content = removep( content );
}

return content;
}

/**
* Takes a block or set of blocks and returns the serialized post content.
*
Expand Down
58 changes: 44 additions & 14 deletions packages/core-data/src/entity-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
useEffect,
} from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { parse, serialize } from '@wordpress/blocks';
import { parse, __unstableSerializeAndClean } from '@wordpress/blocks';

const EMPTY_ARRAY = [];

Expand Down Expand Up @@ -137,16 +137,26 @@ export function useEntityProp( kind, type, prop, _id ) {
export function useEntityBlockEditor( kind, type, { id: _id } = {} ) {
const providerId = useEntityId( kind, type );
const id = _id ?? providerId;
const { content, blocks } = useSelect(
( select ) => {
const { getEditedEntityRecord } = select( 'core' );
const editedEntity = getEditedEntityRecord( kind, type, id );
return {
blocks: editedEntity.blocks,
content: editedEntity.content,
};
},
[ kind, type, id ]
);
const { __unstableCreateUndoLevel, editEntityRecord } = useDispatch(
'core'
);

const [ content, setContent ] = useEntityProp( kind, type, 'content', id );
const [ blocks, onInput ] = useEntityProp( kind, type, 'blocks', id );

const { editEntityRecord } = useDispatch( 'core' );
useEffect( () => {
// Load the blocks from the content if not already in state
// Guard against other instances that might have
// set content to a function already.
if ( content && typeof content !== 'function' ) {
// set content to a function already or the blocks are already in state.
if ( content && typeof content !== 'function' && ! blocks ) {
const parsedContent = parse( content );
editEntityRecord(
kind,
Expand All @@ -161,14 +171,34 @@ export function useEntityBlockEditor( kind, type, { id: _id } = {} ) {
}, [ content ] );

const onChange = useCallback(
( nextBlocks ) => {
onInput( nextBlocks );
// Use a function edit to avoid serializing often.
setContent( ( { blocks: blocksToSerialize } ) =>
serialize( blocksToSerialize )
);
( newBlocks, options ) => {
const { selectionStart, selectionEnd } = options;
const edits = { blocks: newBlocks, selectionStart, selectionEnd };

const noChange = blocks === edits.blocks;
if ( noChange ) {
return __unstableCreateUndoLevel( kind, 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 = [] } ) =>
__unstableSerializeAndClean( blocksForSerialization );

editEntityRecord( kind, type, id, edits );
},
[ onInput, setContent ]
[ kind, type, id, blocks ]
);

const onInput = useCallback(
( newBlocks, options ) => {
const { selectionStart, selectionEnd } = options;
const edits = { blocks: newBlocks, selectionStart, selectionEnd };
editEntityRecord( kind, type, id, edits );
},
[ kind, type, id ]
);

return [ blocks ?? EMPTY_ARRAY, onInput, onChange ];
}
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ describe( 'Reusable blocks', () => {
);
paragraphBlock.focus();
await pressKeyWithModifier( 'primary', 'a' );
await page.keyboard.press( 'ArrowRight' );
await page.keyboard.press( 'End' );
await page.keyboard.type( ' modified' );

// Wait for async mode to dispatch the update.
Expand Down
21 changes: 9 additions & 12 deletions packages/editor/src/components/provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { useEffect, useLayoutEffect, useMemo } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { EntityProvider } from '@wordpress/core-data';
import { EntityProvider, useEntityBlockEditor } from '@wordpress/core-data';
import {
BlockEditorProvider,
BlockContextProvider,
Expand All @@ -17,7 +17,6 @@ import { store as noticesStore } from '@wordpress/notices';
*/
import withRegistryProvider from './with-registry-provider';
import ConvertToGroupButtons from '../convert-to-group-buttons';
import usePostContentEditor from './use-post-content-editor';
import { store as editorStore } from '../../store';
import useBlockEditorSettings from './use-block-editor-settings';

Expand Down Expand Up @@ -48,7 +47,11 @@ function EditorProvider( {
};
}, [] );
const { id, type } = __unstableTemplate ?? post;
const blockEditorProps = usePostContentEditor( type, id );
const [ blocks, onInput, onChange ] = useEntityBlockEditor(
'postType',
type,
{ id }
);
const editorSettings = useBlockEditorSettings(
settings,
!! __unstableTemplate
Expand All @@ -58,7 +61,6 @@ function EditorProvider( {
setupEditor,
updateEditorSettings,
__experimentalTearDownEditor,
__unstableSetupTemplate,
} = useDispatch( editorStore );
const { createWarningNotice } = useDispatch( noticesStore );

Expand Down Expand Up @@ -99,13 +101,6 @@ function EditorProvider( {
updateEditorSettings( settings );
}, [ settings ] );

// Synchronize the template as it changes
useEffect( () => {
if ( __unstableTemplate ) {
__unstableSetupTemplate( __unstableTemplate );
}
}, [ __unstableTemplate?.id ] );

if ( ! isReady ) {
return null;
}
Expand All @@ -115,7 +110,9 @@ function EditorProvider( {
<EntityProvider kind="postType" type={ post.type } id={ post.id }>
<BlockContextProvider value={ defaultBlockContext }>
<BlockEditorProvider
{ ...blockEditorProps }
value={ blocks }
onChange={ onChange }
onInput={ onInput }
selectionStart={ selectionStart }
selectionEnd={ selectionEnd }
settings={ editorSettings }
Expand Down
77 changes: 0 additions & 77 deletions packages/editor/src/components/provider/use-post-content-editor.js

This file was deleted.

30 changes: 6 additions & 24 deletions packages/editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { has } from 'lodash';
import deprecated from '@wordpress/deprecated';
import { controls } from '@wordpress/data';
import { apiFetch } from '@wordpress/data-controls';
import { parse, synchronizeBlocksWithTemplate } from '@wordpress/blocks';
import {
parse,
synchronizeBlocksWithTemplate,
__unstableSerializeAndClean,
} from '@wordpress/blocks';
import { store as noticesStore } from '@wordpress/notices';

/**
Expand All @@ -21,7 +25,6 @@ import {
getNotificationArgumentsForSaveFail,
getNotificationArgumentsForTrashFail,
} from './utils/notice-builder';
import serializeBlocks from './utils/serialize-blocks';

/**
* Returns an action generator used in signalling that editor has initialized with
Expand Down Expand Up @@ -73,27 +76,6 @@ export function* setupEditor( post, edits, template ) {
}
}

/**
* Initiliazes an FSE template into the core-data store.
* We could avoid this action entirely by having a fallback if the edit is undefined.
*
* @param {Object} template Template object.
*/
export function* __unstableSetupTemplate( template ) {
const blocks = parse( template.content.raw );
yield controls.dispatch(
'core',
'editEntityRecord',
'postType',
template.type,
template.id,
{
blocks,
},
{ undoIgnore: true }
);
}

/**
* Returns an action object signalling that the editor is being destroyed and
* that any necessary state or side-effect cleanup should occur.
Expand Down Expand Up @@ -645,7 +627,7 @@ export function* resetEditorBlocks( blocks, options = {} ) {
// to make sure the edit makes the post dirty and creates
// a new undo level.
edits.content = ( { blocks: blocksForSerialization = [] } ) =>
serializeBlocks( blocksForSerialization );
__unstableSerializeAndClean( blocksForSerialization );
}
yield* editPost( edits );
}
Expand Down
4 changes: 2 additions & 2 deletions packages/editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
getFreeformContentHandlerName,
getDefaultBlockName,
isUnmodifiedDefaultBlock,
__unstableSerializeAndClean,
} from '@wordpress/blocks';
import { isInTheFuture, getDate } from '@wordpress/date';
import { addQueryArgs } from '@wordpress/url';
Expand All @@ -38,7 +39,6 @@ import {
AUTOSAVE_PROPERTIES,
} from './constants';
import { getPostRawValue } from './reducer';
import serializeBlocks from './utils/serialize-blocks';
import { cleanForSlug } from '../utils/url';

/**
Expand Down Expand Up @@ -991,7 +991,7 @@ export const getEditedPostContent = createRegistrySelector(
if ( typeof record.content === 'function' ) {
return record.content( record );
} else if ( record.blocks ) {
return serializeBlocks( record.blocks );
return __unstableSerializeAndClean( record.blocks );
} else if ( record.content ) {
return record.content;
}
Expand Down
Loading