@wordpress/editor 13.14.0 → 13.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/components/entities-saved-states/entity-record-item.js +3 -37
  3. package/build/components/entities-saved-states/entity-record-item.js.map +1 -1
  4. package/build/components/entities-saved-states/entity-type-list.js +2 -4
  5. package/build/components/entities-saved-states/entity-type-list.js.map +1 -1
  6. package/build/components/entities-saved-states/index.js +0 -1
  7. package/build/components/entities-saved-states/index.js.map +1 -1
  8. package/build/components/global-keyboard-shortcuts/{save-shortcut.js → index.js} +13 -25
  9. package/build/components/global-keyboard-shortcuts/index.js.map +1 -0
  10. package/build/components/index.js +32 -19
  11. package/build/components/index.js.map +1 -1
  12. package/build/components/post-comments/index.js +12 -15
  13. package/build/components/post-comments/index.js.map +1 -1
  14. package/build/components/post-excerpt/index.js +9 -20
  15. package/build/components/post-excerpt/index.js.map +1 -1
  16. package/build/components/post-pingbacks/index.js +12 -15
  17. package/build/components/post-pingbacks/index.js.map +1 -1
  18. package/build/components/post-preview-button/index.js +62 -157
  19. package/build/components/post-preview-button/index.js.map +1 -1
  20. package/build/components/post-publish-button/index.js +4 -9
  21. package/build/components/post-publish-button/index.js.map +1 -1
  22. package/build/components/post-publish-button/label.js +2 -4
  23. package/build/components/post-publish-button/label.js.map +1 -1
  24. package/build/components/post-publish-panel/index.js +1 -3
  25. package/build/components/post-publish-panel/index.js.map +1 -1
  26. package/build/components/post-saved-state/index.js +2 -5
  27. package/build/components/post-saved-state/index.js.map +1 -1
  28. package/build/components/post-schedule/label.js +4 -4
  29. package/build/components/post-schedule/label.js.map +1 -1
  30. package/build/components/post-sync-status/index.js +84 -5
  31. package/build/components/post-sync-status/index.js.map +1 -1
  32. package/build/components/post-text-editor/index.js +51 -58
  33. package/build/components/post-text-editor/index.js.map +1 -1
  34. package/build/components/post-type-support-check/index.js +10 -14
  35. package/build/components/post-type-support-check/index.js.map +1 -1
  36. package/build/hooks/custom-sources-backwards-compatibility.js +1 -24
  37. package/build/hooks/custom-sources-backwards-compatibility.js.map +1 -1
  38. package/build/store/actions.js +37 -3
  39. package/build/store/actions.js.map +1 -1
  40. package/build/store/selectors.js +55 -63
  41. package/build/store/selectors.js.map +1 -1
  42. package/build-module/components/entities-saved-states/entity-record-item.js +6 -40
  43. package/build-module/components/entities-saved-states/entity-record-item.js.map +1 -1
  44. package/build-module/components/entities-saved-states/entity-type-list.js +2 -4
  45. package/build-module/components/entities-saved-states/entity-type-list.js.map +1 -1
  46. package/build-module/components/entities-saved-states/index.js +0 -1
  47. package/build-module/components/entities-saved-states/index.js.map +1 -1
  48. package/build-module/components/global-keyboard-shortcuts/{save-shortcut.js → index.js} +12 -23
  49. package/build-module/components/global-keyboard-shortcuts/index.js.map +1 -0
  50. package/build-module/components/index.js +9 -4
  51. package/build-module/components/index.js.map +1 -1
  52. package/build-module/components/post-comments/index.js +13 -14
  53. package/build-module/components/post-comments/index.js.map +1 -1
  54. package/build-module/components/post-excerpt/index.js +10 -19
  55. package/build-module/components/post-excerpt/index.js.map +1 -1
  56. package/build-module/components/post-pingbacks/index.js +13 -14
  57. package/build-module/components/post-pingbacks/index.js.map +1 -1
  58. package/build-module/components/post-preview-button/index.js +63 -149
  59. package/build-module/components/post-preview-button/index.js.map +1 -1
  60. package/build-module/components/post-publish-button/index.js +4 -9
  61. package/build-module/components/post-publish-button/index.js.map +1 -1
  62. package/build-module/components/post-publish-button/label.js +2 -4
  63. package/build-module/components/post-publish-button/label.js.map +1 -1
  64. package/build-module/components/post-publish-panel/index.js +1 -3
  65. package/build-module/components/post-publish-panel/index.js.map +1 -1
  66. package/build-module/components/post-saved-state/index.js +2 -5
  67. package/build-module/components/post-saved-state/index.js.map +1 -1
  68. package/build-module/components/post-schedule/label.js +4 -4
  69. package/build-module/components/post-schedule/label.js.map +1 -1
  70. package/build-module/components/post-sync-status/index.js +84 -8
  71. package/build-module/components/post-sync-status/index.js.map +1 -1
  72. package/build-module/components/post-text-editor/index.js +48 -56
  73. package/build-module/components/post-text-editor/index.js.map +1 -1
  74. package/build-module/components/post-type-support-check/index.js +11 -14
  75. package/build-module/components/post-type-support-check/index.js.map +1 -1
  76. package/build-module/hooks/custom-sources-backwards-compatibility.js +2 -24
  77. package/build-module/hooks/custom-sources-backwards-compatibility.js.map +1 -1
  78. package/build-module/store/actions.js +31 -1
  79. package/build-module/store/actions.js.map +1 -1
  80. package/build-module/store/selectors.js +48 -57
  81. package/build-module/store/selectors.js.map +1 -1
  82. package/build-style/style-rtl.css +0 -18
  83. package/build-style/style.css +0 -18
  84. package/package.json +30 -30
  85. package/src/components/entities-saved-states/entity-record-item.js +3 -61
  86. package/src/components/entities-saved-states/entity-type-list.js +0 -2
  87. package/src/components/entities-saved-states/index.js +0 -1
  88. package/src/components/entities-saved-states/style.scss +0 -15
  89. package/src/components/global-keyboard-shortcuts/index.js +49 -0
  90. package/src/components/index.js +12 -3
  91. package/src/components/post-author/test/check.js +18 -12
  92. package/src/components/post-comments/index.js +11 -17
  93. package/src/components/post-excerpt/index.js +10 -16
  94. package/src/components/post-pingbacks/index.js +11 -15
  95. package/src/components/post-preview-button/index.js +73 -156
  96. package/src/components/post-preview-button/test/index.js +94 -158
  97. package/src/components/post-publish-button/index.js +2 -7
  98. package/src/components/post-publish-button/label.js +2 -2
  99. package/src/components/post-publish-button/test/index.js +0 -10
  100. package/src/components/post-publish-panel/index.js +1 -3
  101. package/src/components/post-saved-state/index.js +2 -5
  102. package/src/components/post-schedule/label.js +4 -4
  103. package/src/components/post-sync-status/index.js +100 -7
  104. package/src/components/post-text-editor/index.js +34 -57
  105. package/src/components/post-title/style.native.scss +5 -5
  106. package/src/components/post-type-support-check/index.js +8 -10
  107. package/src/components/post-type-support-check/test/index.js +35 -19
  108. package/src/hooks/custom-sources-backwards-compatibility.js +1 -25
  109. package/src/store/actions.js +34 -2
  110. package/src/store/selectors.js +47 -43
  111. package/src/store/test/selectors.js +49 -38
  112. package/build/components/global-keyboard-shortcuts/save-shortcut.js.map +0 -1
  113. package/build/components/global-keyboard-shortcuts/text-editor-shortcuts.js +0 -22
  114. package/build/components/global-keyboard-shortcuts/text-editor-shortcuts.js.map +0 -1
  115. package/build/components/global-keyboard-shortcuts/visual-editor-shortcuts.js +0 -45
  116. package/build/components/global-keyboard-shortcuts/visual-editor-shortcuts.js.map +0 -1
  117. package/build-module/components/global-keyboard-shortcuts/save-shortcut.js.map +0 -1
  118. package/build-module/components/global-keyboard-shortcuts/text-editor-shortcuts.js +0 -12
  119. package/build-module/components/global-keyboard-shortcuts/text-editor-shortcuts.js.map +0 -1
  120. package/build-module/components/global-keyboard-shortcuts/visual-editor-shortcuts.js +0 -32
  121. package/build-module/components/global-keyboard-shortcuts/visual-editor-shortcuts.js.map +0 -1
  122. package/src/components/global-keyboard-shortcuts/save-shortcut.js +0 -55
  123. package/src/components/global-keyboard-shortcuts/text-editor-shortcuts.js +0 -8
  124. package/src/components/global-keyboard-shortcuts/visual-editor-shortcuts.js +0 -29
  125. package/src/components/post-text-editor/test/index.js +0 -156
@@ -7,8 +7,9 @@ import Textarea from 'react-autosize-textarea';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { __ } from '@wordpress/i18n';
10
- import { useEffect, useState, useRef } from '@wordpress/element';
11
- import { parse } from '@wordpress/blocks';
10
+ import { store as coreStore } from '@wordpress/core-data';
11
+ import { useMemo } from '@wordpress/element';
12
+ import { __unstableSerializeAndClean } from '@wordpress/blocks';
12
13
  import { useDispatch, useSelect } from '@wordpress/data';
13
14
  import { useInstanceId } from '@wordpress/compose';
14
15
  import { VisuallyHidden } from '@wordpress/components';
@@ -19,63 +20,34 @@ import { VisuallyHidden } from '@wordpress/components';
19
20
  import { store as editorStore } from '../../store';
20
21
 
21
22
  export default function PostTextEditor() {
22
- const postContent = useSelect(
23
- ( select ) => select( editorStore ).getEditedPostContent(),
24
- []
25
- );
26
-
27
- const { editPost, resetEditorBlocks } = useDispatch( editorStore );
28
-
29
- const [ value, setValue ] = useState( postContent );
30
- const [ isDirty, setIsDirty ] = useState( false );
31
23
  const instanceId = useInstanceId( PostTextEditor );
32
- const valueRef = useRef();
33
-
34
- if ( ! isDirty && value !== postContent ) {
35
- setValue( postContent );
36
- }
24
+ const { content, blocks, type, id } = useSelect( ( select ) => {
25
+ const { getEditedEntityRecord } = select( coreStore );
26
+ const { getCurrentPostType, getCurrentPostId } = select( editorStore );
27
+ const _type = getCurrentPostType();
28
+ const _id = getCurrentPostId();
29
+ const editedRecord = getEditedEntityRecord( 'postType', _type, _id );
37
30
 
38
- /**
39
- * Handles a textarea change event to notify the onChange prop callback and
40
- * reflect the new value in the component's own state. This marks the start
41
- * of the user's edits, if not already changed, preventing future props
42
- * changes to value from replacing the rendered value. This is expected to
43
- * be followed by a reset to dirty state via `stopEditing`.
44
- *
45
- * @see stopEditing
46
- *
47
- * @param {Event} event Change event.
48
- */
49
- const onChange = ( event ) => {
50
- const newValue = event.target.value;
51
- editPost( { content: newValue } );
52
- setValue( newValue );
53
- setIsDirty( true );
54
- valueRef.current = newValue;
55
- };
56
-
57
- /**
58
- * Function called when the user has completed their edits, responsible for
59
- * ensuring that changes, if made, are surfaced to the onPersist prop
60
- * callback and resetting dirty state.
61
- */
62
- const stopEditing = () => {
63
- if ( isDirty ) {
64
- const blocks = parse( value );
65
- resetEditorBlocks( blocks );
66
- setIsDirty( false );
67
- }
68
- };
69
-
70
- // Ensure changes aren't lost when component unmounts.
71
- useEffect( () => {
72
- return () => {
73
- if ( valueRef.current ) {
74
- const blocks = parse( valueRef.current );
75
- resetEditorBlocks( blocks );
76
- }
31
+ return {
32
+ content: editedRecord?.content,
33
+ blocks: editedRecord?.blocks,
34
+ type: _type,
35
+ id: _id,
77
36
  };
78
37
  }, [] );
38
+ const { editEntityRecord } = useDispatch( coreStore );
39
+ // Replicates the logic found in getEditedPostContent().
40
+ const value = useMemo( () => {
41
+ if ( content instanceof Function ) {
42
+ return content( { blocks } );
43
+ } else if ( blocks ) {
44
+ // If we have parsed blocks already, they should be our source of truth.
45
+ // Parsing applies block deprecations and legacy block conversions that
46
+ // unparsed content will not have.
47
+ return __unstableSerializeAndClean( blocks );
48
+ }
49
+ return content;
50
+ }, [ content, blocks ] );
79
51
 
80
52
  return (
81
53
  <>
@@ -89,8 +61,13 @@ export default function PostTextEditor() {
89
61
  autoComplete="off"
90
62
  dir="auto"
91
63
  value={ value }
92
- onChange={ onChange }
93
- onBlur={ stopEditing }
64
+ onChange={ ( event ) => {
65
+ editEntityRecord( 'postType', type, id, {
66
+ content: event.target.value,
67
+ blocks: undefined,
68
+ selection: undefined,
69
+ } );
70
+ } }
94
71
  className="editor-post-text-editor"
95
72
  id={ `post-content-${ instanceId }` }
96
73
  placeholder={ __( 'Start writing with text or HTML' ) }
@@ -1,10 +1,10 @@
1
1
 
2
2
  .titleContainer {
3
- padding-left: 12;
4
- padding-right: 16;
5
- padding-top: 12;
6
- padding-bottom: 12;
7
- margin-top: 24;
3
+ padding-left: $block-edge-to-content;
4
+ padding-right: $block-edge-to-content;
5
+ padding-top: 6;
6
+ padding-bottom: 6;
7
+ margin-top: 12;
8
8
  }
9
9
 
10
10
  .dimmed {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { withSelect } from '@wordpress/data';
4
+ import { useSelect } from '@wordpress/data';
5
5
  import { store as coreStore } from '@wordpress/core-data';
6
6
 
7
7
  /**
@@ -14,7 +14,6 @@ import { store as editorStore } from '../../store';
14
14
  * type supports one of the given `supportKeys` prop.
15
15
  *
16
16
  * @param {Object} props Props.
17
- * @param {string} [props.postType] Current post type.
18
17
  * @param {WPElement} props.children Children to be rendered if post
19
18
  * type supports.
20
19
  * @param {(string|string[])} props.supportKeys String or string array of keys
@@ -22,7 +21,12 @@ import { store as editorStore } from '../../store';
22
21
  *
23
22
  * @return {WPComponent} The component to be rendered.
24
23
  */
25
- export function PostTypeSupportCheck( { postType, children, supportKeys } ) {
24
+ export function PostTypeSupportCheck( { children, supportKeys } ) {
25
+ const postType = useSelect( ( select ) => {
26
+ const { getEditedPostAttribute } = select( editorStore );
27
+ const { getPostType } = select( coreStore );
28
+ return getPostType( getEditedPostAttribute( 'type' ) );
29
+ }, [] );
26
30
  let isSupported = true;
27
31
  if ( postType ) {
28
32
  isSupported = (
@@ -37,10 +41,4 @@ export function PostTypeSupportCheck( { postType, children, supportKeys } ) {
37
41
  return children;
38
42
  }
39
43
 
40
- export default withSelect( ( select ) => {
41
- const { getEditedPostAttribute } = select( editorStore );
42
- const { getPostType } = select( coreStore );
43
- return {
44
- postType: getPostType( getEditedPostAttribute( 'type' ) ),
45
- };
46
- } )( PostTypeSupportCheck );
44
+ export default PostTypeSupportCheck;
@@ -3,15 +3,37 @@
3
3
  */
4
4
  import { render } from '@testing-library/react';
5
5
 
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useSelect } from '@wordpress/data';
10
+
6
11
  /**
7
12
  * Internal dependencies
8
13
  */
9
14
  import { PostTypeSupportCheck } from '../';
10
15
 
16
+ jest.mock( '@wordpress/data/src/components/use-select', () => {
17
+ // This allows us to tweak the returned value on each test.
18
+ const mock = jest.fn();
19
+ return mock;
20
+ } );
21
+
22
+ function setupUseSelectMock( postType ) {
23
+ useSelect.mockImplementation( ( cb ) => {
24
+ return cb( () => ( {
25
+ getPostType: () => postType,
26
+ getEditedPostAttribute: () => 'post',
27
+ } ) );
28
+ } );
29
+ }
30
+
11
31
  describe( 'PostTypeSupportCheck', () => {
12
32
  it( 'renders its children when post type is not known', () => {
33
+ setupUseSelectMock( undefined );
34
+
13
35
  const { container } = render(
14
- <PostTypeSupportCheck postType={ undefined } supportKeys="title">
36
+ <PostTypeSupportCheck supportKeys="title">
15
37
  Supported
16
38
  </PostTypeSupportCheck>
17
39
  );
@@ -20,11 +42,11 @@ describe( 'PostTypeSupportCheck', () => {
20
42
  } );
21
43
 
22
44
  it( 'does not render its children when post type is known and not supports', () => {
23
- const postType = {
45
+ setupUseSelectMock( {
24
46
  supports: {},
25
- };
47
+ } );
26
48
  const { container } = render(
27
- <PostTypeSupportCheck postType={ postType } supportKeys="title">
49
+ <PostTypeSupportCheck supportKeys="title">
28
50
  Supported
29
51
  </PostTypeSupportCheck>
30
52
  );
@@ -33,13 +55,13 @@ describe( 'PostTypeSupportCheck', () => {
33
55
  } );
34
56
 
35
57
  it( 'renders its children when post type is known and supports', () => {
36
- const postType = {
58
+ setupUseSelectMock( {
37
59
  supports: {
38
60
  title: true,
39
61
  },
40
- };
62
+ } );
41
63
  const { container } = render(
42
- <PostTypeSupportCheck postType={ postType } supportKeys="title">
64
+ <PostTypeSupportCheck supportKeys="title">
43
65
  Supported
44
66
  </PostTypeSupportCheck>
45
67
  );
@@ -48,16 +70,13 @@ describe( 'PostTypeSupportCheck', () => {
48
70
  } );
49
71
 
50
72
  it( 'renders its children if some of keys supported', () => {
51
- const postType = {
73
+ setupUseSelectMock( {
52
74
  supports: {
53
75
  title: true,
54
76
  },
55
- };
77
+ } );
56
78
  const { container } = render(
57
- <PostTypeSupportCheck
58
- postType={ postType }
59
- supportKeys={ [ 'title', 'thumbnail' ] }
60
- >
79
+ <PostTypeSupportCheck supportKeys={ [ 'title', 'thumbnail' ] }>
61
80
  Supported
62
81
  </PostTypeSupportCheck>
63
82
  );
@@ -66,14 +85,11 @@ describe( 'PostTypeSupportCheck', () => {
66
85
  } );
67
86
 
68
87
  it( 'does not render its children if none of keys supported', () => {
69
- const postType = {
88
+ setupUseSelectMock( {
70
89
  supports: {},
71
- };
90
+ } );
72
91
  const { container } = render(
73
- <PostTypeSupportCheck
74
- postType={ postType }
75
- supportKeys={ [ 'title', 'thumbnail' ] }
76
- >
92
+ <PostTypeSupportCheck supportKeys={ [ 'title', 'thumbnail' ] }>
77
93
  Supported
78
94
  </PostTypeSupportCheck>
79
95
  );
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { store as blocksStore } from '@wordpress/blocks';
5
- import { select as globalSelect, useSelect } from '@wordpress/data';
4
+ import { useSelect } from '@wordpress/data';
6
5
  import { useEntityProp } from '@wordpress/core-data';
7
6
  import { useMemo } from '@wordpress/element';
8
7
  import { createHigherOrderComponent } from '@wordpress/compose';
@@ -124,26 +123,3 @@ addFilter(
124
123
  'core/editor/custom-sources-backwards-compatibility/shim-attribute-source',
125
124
  shimAttributeSource
126
125
  );
127
-
128
- // The above filter will only capture blocks registered after the filter was
129
- // added. There may already be blocks registered by this point, and those must
130
- // be updated to apply the shim.
131
- //
132
- // The following implementation achieves this, albeit with a couple caveats:
133
- // - Only blocks registered on the global store will be modified.
134
- // - The block settings are directly mutated, since there is currently no
135
- // mechanism to update an existing block registration. This is the reason for
136
- // `getBlockType` separate from `getBlockTypes`, since the latter returns a
137
- // _copy_ of the block registration (i.e. the mutation would not affect the
138
- // actual registered block settings).
139
- //
140
- // `getBlockTypes` or `getBlockType` implementation could change in the future
141
- // in regards to creating settings clones, but the corresponding end-to-end
142
- // tests for meta blocks should cover against any potential regressions.
143
- //
144
- // In the future, we could support updating block settings, at which point this
145
- // implementation could use that mechanism instead.
146
- globalSelect( blocksStore )
147
- .getBlockTypes()
148
- .map( ( { name } ) => globalSelect( blocksStore ).getBlockType( name ) )
149
- .forEach( shimAttributeSource );
@@ -11,6 +11,7 @@ import {
11
11
  import { store as noticesStore } from '@wordpress/notices';
12
12
  import { store as coreStore } from '@wordpress/core-data';
13
13
  import { store as blockEditorStore } from '@wordpress/block-editor';
14
+ import { applyFilters } from '@wordpress/hooks';
14
15
  import { store as preferencesStore } from '@wordpress/preferences';
15
16
 
16
17
  /**
@@ -177,15 +178,26 @@ export const savePost =
177
178
  edits,
178
179
  options
179
180
  );
180
- dispatch( { type: 'REQUEST_POST_UPDATE_FINISH', options } );
181
181
 
182
- const error = registry
182
+ let error = registry
183
183
  .select( coreStore )
184
184
  .getLastEntitySaveError(
185
185
  'postType',
186
186
  previousRecord.type,
187
187
  previousRecord.id
188
188
  );
189
+
190
+ if ( ! error ) {
191
+ await applyFilters(
192
+ 'editor.__unstableSavePost',
193
+ Promise.resolve(),
194
+ options
195
+ ).catch( ( err ) => {
196
+ error = err;
197
+ } );
198
+ }
199
+ dispatch( { type: 'REQUEST_POST_UPDATE_FINISH', options } );
200
+
189
201
  if ( error ) {
190
202
  const args = getNotificationArgumentsForSaveFail( {
191
203
  post: previousRecord,
@@ -289,6 +301,26 @@ export const autosave =
289
301
  }
290
302
  };
291
303
 
304
+ export const __unstableSaveForPreview =
305
+ ( { forceIsAutosaveable } = {} ) =>
306
+ async ( { select, dispatch } ) => {
307
+ if (
308
+ ( forceIsAutosaveable || select.isEditedPostAutosaveable() ) &&
309
+ ! select.isPostLocked()
310
+ ) {
311
+ const isDraft = [ 'draft', 'auto-draft' ].includes(
312
+ select.getEditedPostAttribute( 'status' )
313
+ );
314
+ if ( isDraft ) {
315
+ await dispatch.savePost( { isPreview: true } );
316
+ } else {
317
+ await dispatch.autosave( { isPreview: true } );
318
+ }
319
+ }
320
+
321
+ return select.getEditedPostPreviewLink();
322
+ };
323
+
292
324
  /**
293
325
  * Action that restores last popped state in undo history.
294
326
  */
@@ -10,6 +10,7 @@ import {
10
10
  getFreeformContentHandlerName,
11
11
  getDefaultBlockName,
12
12
  __unstableSerializeAndClean,
13
+ parse,
13
14
  } from '@wordpress/blocks';
14
15
  import { isInTheFuture, getDate } from '@wordpress/date';
15
16
  import { addQueryArgs, cleanForSlug } from '@wordpress/url';
@@ -42,15 +43,6 @@ import { getTemplatePartIcon } from '../utils/get-template-part-icon';
42
43
  */
43
44
  const EMPTY_OBJECT = {};
44
45
 
45
- /**
46
- * Shared reference to an empty array for cases where it is important to avoid
47
- * returning a new array reference on every invocation, as in a connected or
48
- * other pure component which performs `shouldComponentUpdate` check on props.
49
- * This should be used as a last resort, since the normalized data should be
50
- * maintained by the reducer result in state.
51
- */
52
- const EMPTY_ARRAY = [];
53
-
54
46
  /**
55
47
  * Returns true if any past editor history snapshots exist, or false otherwise.
56
48
  *
@@ -507,16 +499,31 @@ export function isEditedPostSaveable( state ) {
507
499
  *
508
500
  * @return {boolean} Whether post has content.
509
501
  */
510
- export function isEditedPostEmpty( state ) {
511
- // While the condition of truthy content string is sufficient to determine
512
- // emptiness, testing saveable blocks length is a trivial operation. Since
513
- // this function can be called frequently, optimize for the fast case as a
514
- // condition of the mere existence of blocks. Note that the value of edited
515
- // content takes precedent over block content, and must fall through to the
516
- // default logic.
517
- const blocks = getEditorBlocks( state );
502
+ export const isEditedPostEmpty = createRegistrySelector(
503
+ ( select ) => ( state ) => {
504
+ // While the condition of truthy content string is sufficient to determine
505
+ // emptiness, testing saveable blocks length is a trivial operation. Since
506
+ // this function can be called frequently, optimize for the fast case as a
507
+ // condition of the mere existence of blocks. Note that the value of edited
508
+ // content takes precedent over block content, and must fall through to the
509
+ // default logic.
510
+ const postId = getCurrentPostId( state );
511
+ const postType = getCurrentPostType( state );
512
+ const record = select( coreStore ).getEditedEntityRecord(
513
+ 'postType',
514
+ postType,
515
+ postId
516
+ );
517
+ if ( typeof record.content !== 'function' ) {
518
+ return ! record.content;
519
+ }
520
+
521
+ const blocks = getEditedPostAttribute( state, 'blocks' );
522
+
523
+ if ( blocks.length === 0 ) {
524
+ return true;
525
+ }
518
526
 
519
- if ( blocks.length ) {
520
527
  // Pierce the abstraction of the serializer in knowing that blocks are
521
528
  // joined with newlines such that even if every individual block
522
529
  // produces an empty save result, the serialized content is non-empty.
@@ -542,10 +549,10 @@ export function isEditedPostEmpty( state ) {
542
549
  ) {
543
550
  return false;
544
551
  }
545
- }
546
552
 
547
- return ! getEditedPostContent( state );
548
- }
553
+ return ! getEditedPostContent( state );
554
+ }
555
+ );
549
556
 
550
557
  /**
551
558
  * Returns true if the post can be autosaved, or false otherwise.
@@ -604,8 +611,8 @@ export const isEditedPostAutosaveable = createRegistrySelector(
604
611
  return true;
605
612
  }
606
613
 
607
- // If the title or excerpt has changed, the post is autosaveable.
608
- return [ 'title', 'excerpt' ].some(
614
+ // If title, excerpt, or meta have changed, the post is autosaveable.
615
+ return [ 'title', 'excerpt', 'meta' ].some(
609
616
  ( field ) =>
610
617
  getPostRawValue( autosave[ field ] ) !==
611
618
  getEditedPostAttribute( state, field )
@@ -681,15 +688,9 @@ export function isDeletingPost( state ) {
681
688
  *
682
689
  * @return {boolean} Whether post is being saved.
683
690
  */
684
- export const isSavingPost = createRegistrySelector( ( select ) => ( state ) => {
685
- const postType = getCurrentPostType( state );
686
- const postId = getCurrentPostId( state );
687
- return select( coreStore ).isSavingEntityRecord(
688
- 'postType',
689
- postType,
690
- postId
691
- );
692
- } );
691
+ export function isSavingPost( state ) {
692
+ return !! state.saving.pending;
693
+ }
693
694
 
694
695
  /**
695
696
  * Returns true if non-post entities are currently being saved, or false otherwise.
@@ -760,10 +761,7 @@ export const didPostSaveRequestFail = createRegistrySelector(
760
761
  * @return {boolean} Whether the post is autosaving.
761
762
  */
762
763
  export function isAutosavingPost( state ) {
763
- if ( ! isSavingPost( state ) ) {
764
- return false;
765
- }
766
- return Boolean( state.saving.options?.isAutosave );
764
+ return isSavingPost( state ) && Boolean( state.saving.options?.isAutosave );
767
765
  }
768
766
 
769
767
  /**
@@ -774,10 +772,7 @@ export function isAutosavingPost( state ) {
774
772
  * @return {boolean} Whether the post is being previewed.
775
773
  */
776
774
  export function isPreviewingPost( state ) {
777
- if ( ! isSavingPost( state ) ) {
778
- return false;
779
- }
780
- return Boolean( state.saving.options?.isPreview );
775
+ return isSavingPost( state ) && Boolean( state.saving.options?.isPreview );
781
776
  }
782
777
 
783
778
  /**
@@ -1100,9 +1095,18 @@ export const isPublishSidebarEnabled = createRegistrySelector(
1100
1095
  * @param {Object} state
1101
1096
  * @return {Array} Block list.
1102
1097
  */
1103
- export function getEditorBlocks( state ) {
1104
- return getEditedPostAttribute( state, 'blocks' ) || EMPTY_ARRAY;
1105
- }
1098
+ export const getEditorBlocks = createSelector(
1099
+ ( state ) => {
1100
+ return (
1101
+ getEditedPostAttribute( state, 'blocks' ) ||
1102
+ parse( getEditedPostContent( state ) )
1103
+ );
1104
+ },
1105
+ ( state ) => [
1106
+ getEditedPostAttribute( state, 'blocks' ),
1107
+ getEditedPostContent( state ),
1108
+ ]
1109
+ );
1106
1110
 
1107
1111
  /**
1108
1112
  * A block selection object.