@wordpress/editor 14.47.0 → 14.48.1
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.
- package/CHANGELOG.md +26 -0
- package/build/components/block-removal-warnings/index.cjs +0 -3
- package/build/components/block-removal-warnings/index.cjs.map +2 -2
- package/build/components/collab-sidebar/note-indicator-toolbar.cjs +49 -43
- package/build/components/collab-sidebar/note-indicator-toolbar.cjs.map +3 -3
- package/build/components/collaborators-overlay/use-block-highlighting.cjs +1 -8
- package/build/components/collaborators-overlay/use-block-highlighting.cjs.map +3 -3
- package/build/components/collaborators-overlay/use-render-cursors.cjs +1 -7
- package/build/components/collaborators-overlay/use-render-cursors.cjs.map +3 -3
- package/build/components/more-menu/view-more-menu-group.cjs +1 -2
- package/build/components/more-menu/view-more-menu-group.cjs.map +2 -2
- package/build/components/page-attributes/parent.cjs +1 -0
- package/build/components/page-attributes/parent.cjs.map +2 -2
- package/build/components/post-publish-button/index.cjs +114 -157
- package/build/components/post-publish-button/index.cjs.map +3 -3
- package/build/components/post-revisions-preview/block-diff.cjs +21 -9
- package/build/components/post-revisions-preview/block-diff.cjs.map +2 -2
- package/build/components/post-revisions-preview/preserve-client-ids.cjs +2 -2
- package/build/components/post-revisions-preview/preserve-client-ids.cjs.map +2 -2
- package/build/components/provider/index.cjs +2 -0
- package/build/components/provider/index.cjs.map +3 -3
- package/build/components/provider/use-block-editor-settings.cjs +1 -1
- package/build/components/provider/use-block-editor-settings.cjs.map +2 -2
- package/build/components/provider/use-network-reconnect.cjs +51 -0
- package/build/components/provider/use-network-reconnect.cjs.map +7 -0
- package/build/components/revision-fields-diff/index.cjs +2 -2
- package/build/components/revision-fields-diff/index.cjs.map +2 -2
- package/build/components/sidebar/index.cjs +1 -4
- package/build/components/sidebar/index.cjs.map +2 -2
- package/build/components/template-actions-panel/block-theme-content.cjs +7 -1
- package/build/components/template-actions-panel/block-theme-content.cjs.map +2 -2
- package/build/components/upload-progress-snackbar/index.cjs +161 -0
- package/build/components/upload-progress-snackbar/index.cjs.map +7 -0
- package/build/components/upload-progress-snackbar/tracker.cjs +90 -0
- package/build/components/upload-progress-snackbar/tracker.cjs.map +7 -0
- package/build/private-apis.cjs +2 -0
- package/build/private-apis.cjs.map +3 -3
- package/build/store/selectors.cjs +1 -2
- package/build/store/selectors.cjs.map +2 -2
- package/build/utils/media-upload/index.cjs +16 -0
- package/build/utils/media-upload/index.cjs.map +3 -3
- package/build-module/components/block-removal-warnings/index.mjs +0 -3
- package/build-module/components/block-removal-warnings/index.mjs.map +2 -2
- package/build-module/components/collab-sidebar/note-indicator-toolbar.mjs +53 -44
- package/build-module/components/collab-sidebar/note-indicator-toolbar.mjs.map +2 -2
- package/build-module/components/collaborators-overlay/use-block-highlighting.mjs +1 -8
- package/build-module/components/collaborators-overlay/use-block-highlighting.mjs.map +2 -2
- package/build-module/components/collaborators-overlay/use-render-cursors.mjs +1 -7
- package/build-module/components/collaborators-overlay/use-render-cursors.mjs.map +2 -2
- package/build-module/components/more-menu/view-more-menu-group.mjs +1 -2
- package/build-module/components/more-menu/view-more-menu-group.mjs.map +2 -2
- package/build-module/components/page-attributes/parent.mjs +1 -0
- package/build-module/components/page-attributes/parent.mjs.map +2 -2
- package/build-module/components/post-publish-button/index.mjs +116 -159
- package/build-module/components/post-publish-button/index.mjs.map +2 -2
- package/build-module/components/post-revisions-preview/block-diff.mjs +20 -8
- package/build-module/components/post-revisions-preview/block-diff.mjs.map +2 -2
- package/build-module/components/post-revisions-preview/preserve-client-ids.mjs +1 -1
- package/build-module/components/post-revisions-preview/preserve-client-ids.mjs.map +1 -1
- package/build-module/components/provider/index.mjs +2 -0
- package/build-module/components/provider/index.mjs.map +2 -2
- package/build-module/components/provider/use-block-editor-settings.mjs +1 -1
- package/build-module/components/provider/use-block-editor-settings.mjs.map +2 -2
- package/build-module/components/provider/use-network-reconnect.mjs +30 -0
- package/build-module/components/provider/use-network-reconnect.mjs.map +7 -0
- package/build-module/components/revision-fields-diff/index.mjs +2 -2
- package/build-module/components/revision-fields-diff/index.mjs.map +2 -2
- package/build-module/components/sidebar/index.mjs +2 -11
- package/build-module/components/sidebar/index.mjs.map +2 -2
- package/build-module/components/template-actions-panel/block-theme-content.mjs +7 -1
- package/build-module/components/template-actions-panel/block-theme-content.mjs.map +2 -2
- package/build-module/components/upload-progress-snackbar/index.mjs +135 -0
- package/build-module/components/upload-progress-snackbar/index.mjs.map +7 -0
- package/build-module/components/upload-progress-snackbar/tracker.mjs +61 -0
- package/build-module/components/upload-progress-snackbar/tracker.mjs.map +7 -0
- package/build-module/private-apis.mjs +2 -0
- package/build-module/private-apis.mjs.map +2 -2
- package/build-module/store/selectors.mjs +1 -2
- package/build-module/store/selectors.mjs.map +2 -2
- package/build-module/utils/media-upload/index.mjs +19 -0
- package/build-module/utils/media-upload/index.mjs.map +2 -2
- package/build-style/style-rtl.css +479 -84
- package/build-style/style.css +479 -84
- package/build-types/components/block-removal-warnings/index.d.ts.map +1 -1
- package/build-types/components/collab-sidebar/add-comment.d.ts +6 -0
- package/build-types/components/collab-sidebar/add-comment.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comment-author-info.d.ts +8 -0
- package/build-types/components/collab-sidebar/comment-author-info.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comment-form.d.ts +9 -0
- package/build-types/components/collab-sidebar/comment-form.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts +6 -0
- package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comment-menu-item.d.ts +6 -0
- package/build-types/components/collab-sidebar/comment-menu-item.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comments.d.ts +10 -0
- package/build-types/components/collab-sidebar/comments.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/note-indicator-toolbar.d.ts.map +1 -1
- package/build-types/components/collaborators-overlay/use-block-highlighting.d.ts +0 -3
- package/build-types/components/collaborators-overlay/use-block-highlighting.d.ts.map +1 -1
- package/build-types/components/collaborators-overlay/use-render-cursors.d.ts.map +1 -1
- package/build-types/components/document-bar/index.d.ts +2 -2
- package/build-types/components/document-bar/index.d.ts.map +1 -1
- package/build-types/components/global-styles-provider/index.d.ts +16 -0
- package/build-types/components/global-styles-provider/index.d.ts.map +1 -0
- package/build-types/components/media/index.d.ts +3 -0
- package/build-types/components/media/index.d.ts.map +1 -0
- package/build-types/components/media/metadata-panel.d.ts +12 -0
- package/build-types/components/media/metadata-panel.d.ts.map +1 -0
- package/build-types/components/media/preview.d.ts +9 -0
- package/build-types/components/media/preview.d.ts.map +1 -0
- package/build-types/components/more-menu/view-more-menu-group.d.ts.map +1 -1
- package/build-types/components/page-attributes/parent.d.ts.map +1 -1
- package/build-types/components/post-locked-modal/index.d.ts +6 -1
- package/build-types/components/post-publish-button/index.d.ts +9 -9
- package/build-types/components/post-publish-button/index.d.ts.map +1 -1
- package/build-types/components/post-revisions-preview/block-diff.d.ts +3 -0
- package/build-types/components/post-revisions-preview/block-diff.d.ts.map +1 -1
- package/build-types/components/post-taxonomies/flat-term-selector.d.ts +6 -1
- package/build-types/components/post-taxonomies/hierarchical-term-selector.d.ts +6 -1
- package/build-types/components/post-text-editor/index.d.ts +1 -1
- package/build-types/components/post-text-editor/index.d.ts.map +1 -1
- package/build-types/components/post-text-editor/utils.d.ts +29 -0
- package/build-types/components/post-text-editor/utils.d.ts.map +1 -0
- package/build-types/components/provider/index.d.ts.map +1 -1
- package/build-types/components/provider/use-network-reconnect.d.ts +8 -0
- package/build-types/components/provider/use-network-reconnect.d.ts.map +1 -0
- package/build-types/components/revision-fields-diff/index.d.ts +3 -0
- package/build-types/components/revision-fields-diff/index.d.ts.map +1 -1
- package/build-types/components/sidebar/index.d.ts.map +1 -1
- package/build-types/components/template-actions-panel/block-theme-content.d.ts.map +1 -1
- package/build-types/components/upload-progress-snackbar/index.d.ts +19 -0
- package/build-types/components/upload-progress-snackbar/index.d.ts.map +1 -0
- package/build-types/components/upload-progress-snackbar/stories/index.story.d.ts +28 -0
- package/build-types/components/upload-progress-snackbar/stories/index.story.d.ts.map +1 -0
- package/build-types/components/upload-progress-snackbar/tracker.d.ts +41 -0
- package/build-types/components/upload-progress-snackbar/tracker.d.ts.map +1 -0
- package/build-types/private-apis.d.ts.map +1 -1
- package/build-types/store/selectors.d.ts.map +1 -1
- package/build-types/utils/get-template-part-icon.d.ts.map +1 -1
- package/build-types/utils/media-upload/index.d.ts.map +1 -1
- package/package.json +55 -52
- package/src/components/README.md +1 -1
- package/src/components/block-removal-warnings/index.js +0 -7
- package/src/components/collab-sidebar/note-indicator-toolbar.js +73 -60
- package/src/components/collaborators-overlay/use-block-highlighting.ts +0 -9
- package/src/components/collaborators-overlay/use-render-cursors.ts +0 -8
- package/src/components/collaborators-presence/avatar/test/index.tsx +8 -3
- package/src/components/more-menu/view-more-menu-group.js +1 -2
- package/src/components/page-attributes/parent.js +1 -0
- package/src/components/post-publish-button/index.js +143 -192
- package/src/components/post-publish-button/test/index.js +137 -114
- package/src/components/post-revisions-preview/block-diff.js +63 -19
- package/src/components/post-revisions-preview/preserve-client-ids.js +1 -1
- package/src/components/post-revisions-preview/test/block-diff.js +109 -6
- package/src/components/provider/index.js +4 -0
- package/src/components/provider/test/use-network-reconnect.js +137 -0
- package/src/components/provider/use-block-editor-settings.js +2 -2
- package/src/components/provider/use-network-reconnect.js +44 -0
- package/src/components/revision-fields-diff/index.js +7 -2
- package/src/components/sidebar/index.js +2 -11
- package/src/components/template-actions-panel/block-theme-content.js +10 -1
- package/src/components/upload-progress-snackbar/README.md +26 -0
- package/src/components/upload-progress-snackbar/index.js +216 -0
- package/src/components/upload-progress-snackbar/stories/index.story.tsx +85 -0
- package/src/components/upload-progress-snackbar/style.scss +30 -0
- package/src/components/upload-progress-snackbar/test/index.js +199 -0
- package/src/components/upload-progress-snackbar/tracker.js +105 -0
- package/src/private-apis.js +2 -0
- package/src/store/selectors.js +1 -3
- package/src/style.scss +1 -0
- package/src/utils/media-upload/index.js +27 -0
- package/src/components/commands/index.native.js +0 -2
- package/src/components/deprecated.native.js +0 -47
- package/src/components/editor-help/add-blocks.native.js +0 -40
- package/src/components/editor-help/customize-blocks.native.js +0 -40
- package/src/components/editor-help/help-detail-navigation-screen.native.js +0 -67
- package/src/components/editor-help/help-get-support-button.native.js +0 -38
- package/src/components/editor-help/help-section-title.native.js +0 -29
- package/src/components/editor-help/help-topic-row.native.js +0 -33
- package/src/components/editor-help/icon-move-blocks.native.js +0 -10
- package/src/components/editor-help/index.native.js +0 -208
- package/src/components/editor-help/intro-to-blocks.native.js +0 -91
- package/src/components/editor-help/move-blocks.native.js +0 -55
- package/src/components/editor-help/remove-blocks.native.js +0 -35
- package/src/components/editor-help/style.android.scss +0 -6
- package/src/components/editor-help/style.ios.scss +0 -6
- package/src/components/editor-help/test/index.native.js +0 -81
- package/src/components/editor-help/view-sections.native.js +0 -79
- package/src/components/error-boundary/index.native.js +0 -192
- package/src/components/error-boundary/style.native.scss +0 -116
- package/src/components/index.native.js +0 -15
- package/src/components/offline-status/index.native.js +0 -99
- package/src/components/offline-status/style.native.scss +0 -28
- package/src/components/offline-status/test/index.native.js +0 -108
- package/src/components/post-title/index.native.js +0 -282
- package/src/components/post-title/style.native.scss +0 -13
- package/src/components/post-title/test/__snapshots__/index.native.js.snap +0 -25
- package/src/components/post-title/test/index.native.js +0 -78
- package/src/components/provider/index.native.js +0 -497
- package/src/components/provider/use-block-editor-settings.native.js +0 -48
- package/src/components/template-part-menu-items/index.native.js +0 -3
- package/src/hooks/index.native.js +0 -0
- package/src/index.native.js +0 -16
- package/src/private-apis.native.js +0 -33
- package/src/store/actions.native.js +0 -27
- package/src/store/reducer.native.js +0 -94
- package/src/store/selectors.native.js +0 -57
- package/src/store/test/actions.native.js +0 -16
- package/src/store/test/reducer.native.js +0 -36
- package/src/store/test/selectors.native.js +0 -28
- package/src/utils/index.native.js +0 -6
- package/src/utils/media-sideload/index.native.js +0 -1
- package/src/utils/media-upload/index.native.js +0 -1
|
@@ -4,186 +4,209 @@
|
|
|
4
4
|
import { render, screen } from '@testing-library/react';
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* WordPress dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { dispatch, select } from '@wordpress/data';
|
|
11
|
+
|
|
7
12
|
/**
|
|
8
13
|
* Internal dependencies
|
|
9
14
|
*/
|
|
10
|
-
import
|
|
15
|
+
import PostPublishButton from '../';
|
|
16
|
+
import { store as editorStore } from '../../../store';
|
|
11
17
|
|
|
12
18
|
describe( 'PostPublishButton', () => {
|
|
19
|
+
beforeEach( () => {
|
|
20
|
+
jest.spyOn( select( editorStore ), 'getCurrentPost' ).mockReturnValue( {
|
|
21
|
+
_links: {},
|
|
22
|
+
} );
|
|
23
|
+
jest.spyOn( dispatch( editorStore ), 'editPost' ).mockReturnValue();
|
|
24
|
+
jest.spyOn( dispatch( editorStore ), 'savePost' ).mockReturnValue();
|
|
25
|
+
} );
|
|
26
|
+
|
|
27
|
+
afterEach( () => {
|
|
28
|
+
jest.restoreAllMocks();
|
|
29
|
+
} );
|
|
30
|
+
|
|
31
|
+
function mockSelector( name, value ) {
|
|
32
|
+
jest.spyOn( select( editorStore ), name ).mockReturnValue( value );
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mockHasPublishAction( hasPublishAction ) {
|
|
36
|
+
jest.spyOn( select( editorStore ), 'getCurrentPost' ).mockReturnValue( {
|
|
37
|
+
_links: hasPublishAction ? { 'wp:action-publish': true } : {},
|
|
38
|
+
} );
|
|
39
|
+
}
|
|
40
|
+
|
|
13
41
|
describe( 'aria-disabled', () => {
|
|
14
42
|
it( 'should be true if post is currently saving', () => {
|
|
15
|
-
|
|
43
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
44
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
45
|
+
mockSelector( 'isSavingPost', true );
|
|
46
|
+
|
|
47
|
+
render( <PostPublishButton /> );
|
|
16
48
|
|
|
17
|
-
expect(
|
|
18
|
-
|
|
19
|
-
|
|
49
|
+
expect( screen.getByRole( 'button' ) ).toHaveAttribute(
|
|
50
|
+
'aria-disabled',
|
|
51
|
+
'true'
|
|
52
|
+
);
|
|
20
53
|
} );
|
|
21
54
|
|
|
22
55
|
it( 'should be true if post is not publishable and not forceIsDirty', () => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
forceIsDirty={ false }
|
|
28
|
-
/>
|
|
29
|
-
);
|
|
56
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
57
|
+
mockSelector( 'isEditedPostPublishable', false );
|
|
58
|
+
|
|
59
|
+
render( <PostPublishButton forceIsDirty={ false } /> );
|
|
30
60
|
|
|
31
|
-
expect(
|
|
32
|
-
|
|
33
|
-
|
|
61
|
+
expect( screen.getByRole( 'button' ) ).toHaveAttribute(
|
|
62
|
+
'aria-disabled',
|
|
63
|
+
'true'
|
|
64
|
+
);
|
|
34
65
|
} );
|
|
35
66
|
|
|
36
67
|
it( 'should be true if post is not saveable', () => {
|
|
37
|
-
|
|
68
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
69
|
+
mockSelector( 'isEditedPostSaveable', false );
|
|
70
|
+
|
|
71
|
+
render( <PostPublishButton /> );
|
|
38
72
|
|
|
39
|
-
expect(
|
|
40
|
-
|
|
41
|
-
|
|
73
|
+
expect( screen.getByRole( 'button' ) ).toHaveAttribute(
|
|
74
|
+
'aria-disabled',
|
|
75
|
+
'true'
|
|
76
|
+
);
|
|
42
77
|
} );
|
|
43
78
|
|
|
44
79
|
it( 'should be true if post saving is locked', () => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
/>
|
|
51
|
-
);
|
|
80
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
81
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
82
|
+
mockSelector( 'isPostSavingLocked', true );
|
|
83
|
+
|
|
84
|
+
render( <PostPublishButton /> );
|
|
52
85
|
|
|
53
|
-
expect(
|
|
54
|
-
|
|
55
|
-
|
|
86
|
+
expect( screen.getByRole( 'button' ) ).toHaveAttribute(
|
|
87
|
+
'aria-disabled',
|
|
88
|
+
'true'
|
|
89
|
+
);
|
|
56
90
|
} );
|
|
57
91
|
|
|
58
92
|
it( 'should be false if post is saveable but not publishable and forceIsDirty is true', () => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
forceIsDirty
|
|
64
|
-
/>
|
|
65
|
-
);
|
|
93
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
94
|
+
mockSelector( 'isEditedPostPublishable', false );
|
|
95
|
+
|
|
96
|
+
render( <PostPublishButton forceIsDirty /> );
|
|
66
97
|
|
|
67
|
-
expect(
|
|
68
|
-
|
|
69
|
-
|
|
98
|
+
expect( screen.getByRole( 'button' ) ).toHaveAttribute(
|
|
99
|
+
'aria-disabled',
|
|
100
|
+
'false'
|
|
101
|
+
);
|
|
70
102
|
} );
|
|
71
103
|
|
|
72
104
|
it( 'should be false if post is publishave and saveable', () => {
|
|
73
|
-
|
|
105
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
106
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
74
107
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
108
|
+
render( <PostPublishButton /> );
|
|
109
|
+
|
|
110
|
+
expect( screen.getByRole( 'button' ) ).toHaveAttribute(
|
|
111
|
+
'aria-disabled',
|
|
112
|
+
'false'
|
|
113
|
+
);
|
|
78
114
|
} );
|
|
79
115
|
} );
|
|
80
116
|
|
|
81
117
|
describe( 'publish status', () => {
|
|
82
118
|
it( 'should be pending for contributor', async () => {
|
|
83
119
|
const user = userEvent.setup();
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
hasPublishAction={ false }
|
|
88
|
-
savePostStatus={ savePostStatus }
|
|
89
|
-
isSaveable
|
|
90
|
-
isPublishable
|
|
91
|
-
/>
|
|
92
|
-
);
|
|
120
|
+
mockHasPublishAction( false );
|
|
121
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
122
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
93
123
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
);
|
|
124
|
+
render( <PostPublishButton /> );
|
|
125
|
+
|
|
126
|
+
await user.click( screen.getByRole( 'button' ) );
|
|
97
127
|
|
|
98
|
-
expect(
|
|
128
|
+
expect( dispatch( editorStore ).editPost ).toHaveBeenCalledWith(
|
|
129
|
+
{ status: 'pending' },
|
|
130
|
+
{ undoIgnore: true }
|
|
131
|
+
);
|
|
99
132
|
} );
|
|
100
133
|
|
|
101
134
|
it( 'should be future for scheduled post', async () => {
|
|
102
135
|
const user = userEvent.setup();
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
savePostStatus={ savePostStatus }
|
|
108
|
-
isBeingScheduled
|
|
109
|
-
isSaveable
|
|
110
|
-
isPublishable
|
|
111
|
-
/>
|
|
112
|
-
);
|
|
136
|
+
mockHasPublishAction( true );
|
|
137
|
+
mockSelector( 'isEditedPostBeingScheduled', true );
|
|
138
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
139
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
113
140
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
);
|
|
141
|
+
render( <PostPublishButton /> );
|
|
142
|
+
|
|
143
|
+
await user.click( screen.getByRole( 'button' ) );
|
|
117
144
|
|
|
118
|
-
expect(
|
|
145
|
+
expect( dispatch( editorStore ).editPost ).toHaveBeenCalledWith(
|
|
146
|
+
{ status: 'future' },
|
|
147
|
+
{ undoIgnore: true }
|
|
148
|
+
);
|
|
119
149
|
} );
|
|
120
150
|
|
|
121
151
|
it( 'should be private for private visibility', async () => {
|
|
122
152
|
const user = userEvent.setup();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
savePostStatus={ savePostStatus }
|
|
128
|
-
visibility="private"
|
|
129
|
-
isSaveable
|
|
130
|
-
isPublishable
|
|
131
|
-
/>
|
|
132
|
-
);
|
|
153
|
+
mockHasPublishAction( true );
|
|
154
|
+
mockSelector( 'getEditedPostVisibility', 'private' );
|
|
155
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
156
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
133
157
|
|
|
134
|
-
|
|
135
|
-
screen.getByRole( 'button', { name: 'Submit for Review' } )
|
|
136
|
-
);
|
|
158
|
+
render( <PostPublishButton /> );
|
|
137
159
|
|
|
138
|
-
|
|
160
|
+
await user.click( screen.getByRole( 'button' ) );
|
|
161
|
+
|
|
162
|
+
expect( dispatch( editorStore ).editPost ).toHaveBeenCalledWith(
|
|
163
|
+
{ status: 'private' },
|
|
164
|
+
{ undoIgnore: true }
|
|
165
|
+
);
|
|
139
166
|
} );
|
|
140
167
|
|
|
141
168
|
it( 'should be publish otherwise', async () => {
|
|
142
169
|
const user = userEvent.setup();
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
hasPublishAction
|
|
147
|
-
savePostStatus={ savePostStatus }
|
|
148
|
-
isSaveable
|
|
149
|
-
isPublishable
|
|
150
|
-
/>
|
|
151
|
-
);
|
|
170
|
+
mockHasPublishAction( true );
|
|
171
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
172
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
152
173
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
);
|
|
174
|
+
render( <PostPublishButton /> );
|
|
175
|
+
|
|
176
|
+
await user.click( screen.getByRole( 'button' ) );
|
|
156
177
|
|
|
157
|
-
expect(
|
|
178
|
+
expect( dispatch( editorStore ).editPost ).toHaveBeenCalledWith(
|
|
179
|
+
{ status: 'publish' },
|
|
180
|
+
{ undoIgnore: true }
|
|
181
|
+
);
|
|
158
182
|
} );
|
|
159
183
|
} );
|
|
160
184
|
|
|
161
185
|
describe( 'click', () => {
|
|
162
186
|
it( 'should save with status', async () => {
|
|
163
187
|
const user = userEvent.setup();
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
hasPublishAction
|
|
168
|
-
savePostStatus={ savePostStatus }
|
|
169
|
-
isSaveable
|
|
170
|
-
isPublishable
|
|
171
|
-
/>
|
|
172
|
-
);
|
|
188
|
+
mockHasPublishAction( true );
|
|
189
|
+
mockSelector( 'isEditedPostSaveable', true );
|
|
190
|
+
mockSelector( 'isEditedPostPublishable', true );
|
|
173
191
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
);
|
|
192
|
+
render( <PostPublishButton /> );
|
|
193
|
+
|
|
194
|
+
await user.click( screen.getByRole( 'button' ) );
|
|
177
195
|
|
|
178
|
-
expect(
|
|
196
|
+
expect( dispatch( editorStore ).editPost ).toHaveBeenCalledWith(
|
|
197
|
+
{ status: 'publish' },
|
|
198
|
+
{ undoIgnore: true }
|
|
199
|
+
);
|
|
200
|
+
expect( dispatch( editorStore ).savePost ).toHaveBeenCalled();
|
|
179
201
|
} );
|
|
180
202
|
} );
|
|
181
203
|
|
|
182
204
|
it( 'should have save modifier class', () => {
|
|
183
|
-
|
|
205
|
+
mockSelector( 'isSavingPost', true );
|
|
206
|
+
mockSelector( 'isCurrentPostPublished', true );
|
|
207
|
+
|
|
208
|
+
render( <PostPublishButton /> );
|
|
184
209
|
|
|
185
|
-
expect(
|
|
186
|
-
screen.getByRole( 'button', { name: 'Submit for Review' } )
|
|
187
|
-
).toHaveClass( 'is-busy' );
|
|
210
|
+
expect( screen.getByRole( 'button' ) ).toHaveClass( 'is-busy' );
|
|
188
211
|
} );
|
|
189
212
|
} );
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/*
|
|
5
|
+
* `diffWordsWithSpace` preserves the v4-style per-word output. v6+
|
|
6
|
+
* stopped treating whitespace as a token in `diffWords`, which coalesces
|
|
7
|
+
* adjacent word changes into a single removed/added pair.
|
|
8
|
+
*/
|
|
9
|
+
import { diffArrays, diffWordsWithSpace } from 'diff';
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* WordPress dependencies
|
|
@@ -28,6 +32,26 @@ import { unlock } from '../../lock-unlock';
|
|
|
28
32
|
|
|
29
33
|
const { parseRawBlock } = unlock( blocksPrivateApis );
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Whether a grammar-parsed raw block is a whitespace-only freeform pseudo-block
|
|
37
|
+
* (the `\n\n` between block markers, etc). These are stripped from both arrays
|
|
38
|
+
* before LCS to keep the matching pivot stable: under `diff` v6's tie-breaker,
|
|
39
|
+
* a whitespace block could otherwise be selected as the LCS anchor in
|
|
40
|
+
* `[paragraph, whitespace, paragraph]` swaps, mis-pairing the surrounding
|
|
41
|
+
* paragraphs in `pairSimilarBlocks`. Whitespace pseudo-blocks don't render
|
|
42
|
+
* anyway (`parseRawBlock` returns undefined for them), so dropping them
|
|
43
|
+
* before the diff has no user-visible effect.
|
|
44
|
+
*
|
|
45
|
+
* @param {Object} rawBlock A raw block from `@wordpress/block-serialization-default-parser`.
|
|
46
|
+
* @return {boolean} True if the block should be excluded from LCS matching.
|
|
47
|
+
*/
|
|
48
|
+
function isWhitespaceRawBlock( rawBlock ) {
|
|
49
|
+
return (
|
|
50
|
+
rawBlock.blockName === null &&
|
|
51
|
+
( ! rawBlock.innerHTML || ! rawBlock.innerHTML.trim() )
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
31
55
|
/**
|
|
32
56
|
* Safely stringifies a value for display and comparison.
|
|
33
57
|
*
|
|
@@ -233,27 +257,34 @@ function pairSimilarBlocks( blocks ) {
|
|
|
233
257
|
};
|
|
234
258
|
|
|
235
259
|
// Decide where to place the modified block by checking
|
|
236
|
-
// what's between the removed and added positions.
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
260
|
+
// what's between the removed and added positions. If any
|
|
261
|
+
// block between them is in the current revision (an
|
|
262
|
+
// unchanged block, or an unpaired added block), placing
|
|
263
|
+
// the modification at the removed position would put it
|
|
264
|
+
// before content that already comes before it in the
|
|
265
|
+
// current revision — so use the added position instead.
|
|
266
|
+
// Otherwise, use the removed position to keep the previous
|
|
267
|
+
// revision's reading order intact.
|
|
268
|
+
//
|
|
269
|
+
// 'removed' blocks (and added blocks already absorbed via
|
|
270
|
+
// `pairedAdded`) aren't checked because they aren't in the
|
|
271
|
+
// current revision and so don't count as crossing it.
|
|
243
272
|
const lo = Math.min( rem.index, bestMatch.index );
|
|
244
273
|
const hi = Math.max( rem.index, bestMatch.index );
|
|
245
|
-
let
|
|
274
|
+
let crossesCurrentContent = false;
|
|
246
275
|
for ( let i = lo + 1; i < hi; i++ ) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
276
|
+
const status = blocks[ i ].__revisionDiffStatus?.status;
|
|
277
|
+
if ( status === undefined ) {
|
|
278
|
+
crossesCurrentContent = true;
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
if ( status === 'added' && ! pairedAdded.has( i ) ) {
|
|
282
|
+
crossesCurrentContent = true;
|
|
252
283
|
break;
|
|
253
284
|
}
|
|
254
285
|
}
|
|
255
286
|
|
|
256
|
-
if (
|
|
287
|
+
if ( crossesCurrentContent ) {
|
|
257
288
|
// Use the added position — don't jump before
|
|
258
289
|
// current-revision content.
|
|
259
290
|
modifications.set( bestMatch.index, modifiedBlock );
|
|
@@ -287,11 +318,21 @@ function pairSimilarBlocks( blocks ) {
|
|
|
287
318
|
* Detects modifications when exactly 1 block is removed and 1 is added
|
|
288
319
|
* with the same blockName (1:1 replacement = modification).
|
|
289
320
|
*
|
|
321
|
+
* Whitespace-only freeform pseudo-blocks are filtered at every recursive
|
|
322
|
+
* level so this function is safe to call directly with raw output from
|
|
323
|
+
* `@wordpress/block-serialization-default-parser`. The duplicate work for
|
|
324
|
+
* inner-block recursion is negligible and keeps the contract self-contained.
|
|
325
|
+
*
|
|
290
326
|
* @param {Array} currentRaw Current revision's raw blocks.
|
|
291
327
|
* @param {Array} previousRaw Previous revision's raw blocks.
|
|
292
328
|
* @return {Array} Merged raw blocks with diff status injected.
|
|
293
329
|
*/
|
|
294
330
|
function diffRawBlocks( currentRaw, previousRaw ) {
|
|
331
|
+
// Strip whitespace-only freeform pseudo-blocks before LCS — see
|
|
332
|
+
// `isWhitespaceRawBlock` for why.
|
|
333
|
+
currentRaw = currentRaw.filter( ( b ) => ! isWhitespaceRawBlock( b ) );
|
|
334
|
+
previousRaw = previousRaw.filter( ( b ) => ! isWhitespaceRawBlock( b ) );
|
|
335
|
+
|
|
295
336
|
const createBlockSignature = ( rawBlock ) =>
|
|
296
337
|
JSON.stringify( {
|
|
297
338
|
name: rawBlock.blockName,
|
|
@@ -502,8 +543,8 @@ function applyRichTextDiff( currentRichText, previousRichText ) {
|
|
|
502
543
|
const currentText = currentRichText.toPlainText();
|
|
503
544
|
const previousText = previousRichText.toPlainText();
|
|
504
545
|
|
|
505
|
-
// Diff the plain text (words for cleaner output)
|
|
506
|
-
const textDiff =
|
|
546
|
+
// Diff the plain text (words for cleaner output).
|
|
547
|
+
const textDiff = diffWordsWithSpace( previousText, currentText );
|
|
507
548
|
|
|
508
549
|
let result = create( { text: '' } );
|
|
509
550
|
let currentIdx = 0;
|
|
@@ -660,7 +701,10 @@ function applyDiffToBlock( currentBlock, previousBlock, diffStatus ) {
|
|
|
660
701
|
previousBlock.attributes[ attrName ]
|
|
661
702
|
);
|
|
662
703
|
if ( currStr !== prevStr ) {
|
|
663
|
-
changedAttributes[ attrName ] =
|
|
704
|
+
changedAttributes[ attrName ] = diffWordsWithSpace(
|
|
705
|
+
prevStr,
|
|
706
|
+
currStr
|
|
707
|
+
);
|
|
664
708
|
}
|
|
665
709
|
}
|
|
666
710
|
}
|
|
@@ -339,30 +339,32 @@ describe( 'diffRevisionContent', () => {
|
|
|
339
339
|
] );
|
|
340
340
|
const blocks = diffRevisionContent( current, previous );
|
|
341
341
|
|
|
342
|
-
// LCS matches one block ("
|
|
342
|
+
// LCS matches one block ("Second block content" at prev[1] -> curr[0]).
|
|
343
343
|
// The other block appears as removed + added (showing the reorder).
|
|
344
344
|
// We intentionally don't pair identical blocks as "modified" since
|
|
345
345
|
// there's no actual content change - just a position change.
|
|
346
|
+
// (Pre-v8, LCS matched the other block. Both are equally-valid
|
|
347
|
+
// choices for a pure swap.)
|
|
346
348
|
expect( normalizeBlockTree( blocks ) ).toMatchObject( [
|
|
347
349
|
{
|
|
348
350
|
name: 'core/paragraph',
|
|
349
351
|
attributes: {
|
|
350
|
-
content: '
|
|
351
|
-
__revisionDiffStatus: { status: '
|
|
352
|
+
content: 'First block content',
|
|
353
|
+
__revisionDiffStatus: { status: 'removed' },
|
|
352
354
|
},
|
|
353
355
|
},
|
|
354
356
|
{
|
|
355
357
|
name: 'core/paragraph',
|
|
356
358
|
attributes: {
|
|
357
|
-
content: '
|
|
359
|
+
content: 'Second block content',
|
|
358
360
|
__revisionDiffStatus: undefined,
|
|
359
361
|
},
|
|
360
362
|
},
|
|
361
363
|
{
|
|
362
364
|
name: 'core/paragraph',
|
|
363
365
|
attributes: {
|
|
364
|
-
content: '
|
|
365
|
-
__revisionDiffStatus: { status: '
|
|
366
|
+
content: 'First block content',
|
|
367
|
+
__revisionDiffStatus: { status: 'added' },
|
|
366
368
|
},
|
|
367
369
|
},
|
|
368
370
|
] );
|
|
@@ -441,6 +443,107 @@ describe( 'diffRevisionContent', () => {
|
|
|
441
443
|
] );
|
|
442
444
|
} );
|
|
443
445
|
|
|
446
|
+
it( 'filters whitespace-only freeform pseudo-blocks before LCS', () => {
|
|
447
|
+
/*
|
|
448
|
+
* Direct canary for the whitespace-pseudo-block filter in
|
|
449
|
+
* `diffRawBlocks`. The grammar parser emits
|
|
450
|
+
* `{ blockName: null, innerHTML: '\n\n' }` for the whitespace
|
|
451
|
+
* between block markers; under `diff` v6+'s LCS tie-breaker,
|
|
452
|
+
* those pseudo-blocks would otherwise be selected as the match
|
|
453
|
+
* anchor in [paragraph, whitespace, paragraph] swaps, leaving
|
|
454
|
+
* `pairSimilarBlocks` with two removed and two added paragraphs
|
|
455
|
+
* to mis-match by similarity. With the filter, the LCS picks a
|
|
456
|
+
* content block and the surrounding paragraphs pair cleanly.
|
|
457
|
+
*/
|
|
458
|
+
const previous = serialize( [
|
|
459
|
+
createBlock( 'core/paragraph', { content: 'Alpha content' } ),
|
|
460
|
+
createBlock( 'core/paragraph', { content: 'Beta content' } ),
|
|
461
|
+
] );
|
|
462
|
+
const current = serialize( [
|
|
463
|
+
createBlock( 'core/paragraph', {
|
|
464
|
+
content: 'Beta content modified',
|
|
465
|
+
} ),
|
|
466
|
+
createBlock( 'core/paragraph', { content: 'Alpha content' } ),
|
|
467
|
+
] );
|
|
468
|
+
const blocks = diffRevisionContent( current, previous );
|
|
469
|
+
const normalized = normalizeBlockTree( blocks );
|
|
470
|
+
|
|
471
|
+
const statuses = normalized.map(
|
|
472
|
+
( b ) => b.attributes.__revisionDiffStatus?.status
|
|
473
|
+
);
|
|
474
|
+
// Exactly one modified pair and one unchanged anchor — not the
|
|
475
|
+
// double-modified mis-pair that the unfiltered LCS would yield.
|
|
476
|
+
expect( statuses.filter( ( s ) => s === 'modified' ) ).toHaveLength(
|
|
477
|
+
1
|
|
478
|
+
);
|
|
479
|
+
expect( statuses.filter( ( s ) => s === undefined ) ).toHaveLength( 1 );
|
|
480
|
+
|
|
481
|
+
const unchanged = normalized.find(
|
|
482
|
+
( b ) => b.attributes.__revisionDiffStatus === undefined
|
|
483
|
+
);
|
|
484
|
+
expect( unchanged.attributes.content ).toBe( 'Alpha content' );
|
|
485
|
+
} );
|
|
486
|
+
|
|
487
|
+
it( 'places paired modification at current-revision position when only unchanged blocks sit between', () => {
|
|
488
|
+
/*
|
|
489
|
+
* Direct canary for the `crossesCurrentContent` "unchanged
|
|
490
|
+
* between removed and added" branch. The modified block crosses
|
|
491
|
+
* two unchanged paragraphs; the placement heuristic should
|
|
492
|
+
* anchor it at its current-revision position (index 0), not at
|
|
493
|
+
* the removed position (index 3) — otherwise the modified block
|
|
494
|
+
* would render after content that already comes before it in
|
|
495
|
+
* the current revision.
|
|
496
|
+
*/
|
|
497
|
+
const previous = serialize( [
|
|
498
|
+
createBlock( 'core/paragraph', {
|
|
499
|
+
content: 'Stays one anchor sentence',
|
|
500
|
+
} ),
|
|
501
|
+
createBlock( 'core/paragraph', {
|
|
502
|
+
content: 'Stays two anchor sentence',
|
|
503
|
+
} ),
|
|
504
|
+
createBlock( 'core/paragraph', {
|
|
505
|
+
content: 'Original tail content sentence',
|
|
506
|
+
} ),
|
|
507
|
+
] );
|
|
508
|
+
const current = serialize( [
|
|
509
|
+
createBlock( 'core/paragraph', {
|
|
510
|
+
content: 'Original tail content sentence rewritten',
|
|
511
|
+
} ),
|
|
512
|
+
createBlock( 'core/paragraph', {
|
|
513
|
+
content: 'Stays one anchor sentence',
|
|
514
|
+
} ),
|
|
515
|
+
createBlock( 'core/paragraph', {
|
|
516
|
+
content: 'Stays two anchor sentence',
|
|
517
|
+
} ),
|
|
518
|
+
] );
|
|
519
|
+
const blocks = diffRevisionContent( current, previous );
|
|
520
|
+
|
|
521
|
+
expect( normalizeBlockTree( blocks ) ).toMatchObject( [
|
|
522
|
+
{
|
|
523
|
+
name: 'core/paragraph',
|
|
524
|
+
attributes: {
|
|
525
|
+
content:
|
|
526
|
+
'Original tail content sentence<ins title="Added" class="revision-diff-added"> rewritten</ins>',
|
|
527
|
+
__revisionDiffStatus: { status: 'modified' },
|
|
528
|
+
},
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
name: 'core/paragraph',
|
|
532
|
+
attributes: {
|
|
533
|
+
content: 'Stays one anchor sentence',
|
|
534
|
+
__revisionDiffStatus: undefined,
|
|
535
|
+
},
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
name: 'core/paragraph',
|
|
539
|
+
attributes: {
|
|
540
|
+
content: 'Stays two anchor sentence',
|
|
541
|
+
__revisionDiffStatus: undefined,
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
] );
|
|
545
|
+
} );
|
|
546
|
+
|
|
444
547
|
describe( 'inner blocks', () => {
|
|
445
548
|
it( 'handles deeply nested inner blocks', () => {
|
|
446
549
|
const previous = serialize( [
|
|
@@ -36,6 +36,7 @@ import { useHideBlocksFromInserter } from './use-hide-blocks-from-inserter';
|
|
|
36
36
|
import { useRevisionBlocks } from './use-revision-blocks';
|
|
37
37
|
import useCommands from '../commands';
|
|
38
38
|
import useUploadSaveLock from './use-upload-save-lock';
|
|
39
|
+
import useNetworkReconnect from './use-network-reconnect';
|
|
39
40
|
import BlockRemovalWarnings from '../block-removal-warnings';
|
|
40
41
|
import StartPageOptions from '../start-page-options';
|
|
41
42
|
import KeyboardShortcutHelpModal from '../keyboard-shortcut-help-modal';
|
|
@@ -403,6 +404,9 @@ export const ExperimentalEditorProvider = withRegistryProvider(
|
|
|
403
404
|
// Lock post saving when media uploads are in progress (experimental feature).
|
|
404
405
|
useUploadSaveLock();
|
|
405
406
|
|
|
407
|
+
// Pause/resume media upload queue on network disconnect/reconnect.
|
|
408
|
+
useNetworkReconnect();
|
|
409
|
+
|
|
406
410
|
if ( ! isReady || ! mode ) {
|
|
407
411
|
return null;
|
|
408
412
|
}
|