@wordpress/editor 12.10.0 → 12.13.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.
- package/CHANGELOG.md +6 -0
- package/build/components/document-outline/index.js +7 -9
- package/build/components/document-outline/index.js.map +1 -1
- package/build/components/error-boundary/index.js +3 -0
- package/build/components/error-boundary/index.js.map +1 -1
- package/build/components/index.js +61 -9
- package/build/components/index.js.map +1 -1
- package/build/components/local-autosave-monitor/index.js +24 -19
- package/build/components/local-autosave-monitor/index.js.map +1 -1
- package/build/components/page-attributes/order.js +3 -7
- package/build/components/page-attributes/order.js.map +1 -1
- package/build/components/page-attributes/parent.js +8 -4
- package/build/components/page-attributes/parent.js.map +1 -1
- package/build/components/post-format/index.js +5 -8
- package/build/components/post-format/index.js.map +1 -1
- package/build/components/post-locked-modal/index.js +1 -1
- package/build/components/post-locked-modal/index.js.map +1 -1
- package/build/components/post-publish-panel/maybe-category-panel.js +2 -4
- package/build/components/post-publish-panel/maybe-category-panel.js.map +1 -1
- package/build/components/post-schedule/label.js +93 -13
- package/build/components/post-schedule/label.js.map +1 -1
- package/build/components/post-slug/index.js +8 -13
- package/build/components/post-slug/index.js.map +1 -1
- package/build/components/post-taxonomies/flat-term-selector.js +8 -4
- package/build/components/post-taxonomies/flat-term-selector.js.map +1 -1
- package/build/components/post-taxonomies/hierarchical-term-selector.js +1 -0
- package/build/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
- package/build/components/post-taxonomies/index.js +3 -1
- package/build/components/post-taxonomies/index.js.map +1 -1
- package/build/components/post-template/index.js +1 -2
- package/build/components/post-template/index.js.map +1 -1
- package/build/components/post-title/index.js +8 -2
- package/build/components/post-title/index.js.map +1 -1
- package/build/components/post-url/check.js +54 -0
- package/build/components/post-url/check.js.map +1 -0
- package/build/components/post-url/index.js +115 -0
- package/build/components/post-url/index.js.map +1 -0
- package/build/components/post-url/label.js +30 -0
- package/build/components/post-url/label.js.map +1 -0
- package/build/components/post-visibility/index.js +3 -1
- package/build/components/post-visibility/index.js.map +1 -1
- package/build/components/post-visibility/label.js +5 -0
- package/build/components/post-visibility/label.js.map +1 -1
- package/build/components/provider/index.native.js +3 -2
- package/build/components/provider/index.native.js.map +1 -1
- package/build/components/provider/use-block-editor-settings.js +2 -2
- package/build/components/provider/use-block-editor-settings.js.map +1 -1
- package/build/components/table-of-contents/panel.js +5 -1
- package/build/components/table-of-contents/panel.js.map +1 -1
- package/build/components/time-to-read/index.js +60 -0
- package/build/components/time-to-read/index.js.map +1 -0
- package/build/store/actions.js +5 -1
- package/build/store/actions.js.map +1 -1
- package/build/store/reducer.js +1 -1
- package/build/store/reducer.js.map +1 -1
- package/build/store/selectors.js +3 -3
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/document-outline/index.js +7 -8
- package/build-module/components/document-outline/index.js.map +1 -1
- package/build-module/components/error-boundary/index.js +2 -0
- package/build-module/components/error-boundary/index.js.map +1 -1
- package/build-module/components/index.js +7 -4
- package/build-module/components/index.js.map +1 -1
- package/build-module/components/local-autosave-monitor/index.js +24 -18
- package/build-module/components/local-autosave-monitor/index.js.map +1 -1
- package/build-module/components/page-attributes/order.js +3 -6
- package/build-module/components/page-attributes/order.js.map +1 -1
- package/build-module/components/page-attributes/parent.js +6 -5
- package/build-module/components/page-attributes/parent.js.map +1 -1
- package/build-module/components/post-format/index.js +5 -8
- package/build-module/components/post-format/index.js.map +1 -1
- package/build-module/components/post-locked-modal/index.js +1 -1
- package/build-module/components/post-locked-modal/index.js.map +1 -1
- package/build-module/components/post-publish-panel/maybe-category-panel.js +2 -4
- package/build-module/components/post-publish-panel/maybe-category-panel.js.map +1 -1
- package/build-module/components/post-schedule/label.js +90 -13
- package/build-module/components/post-schedule/label.js.map +1 -1
- package/build-module/components/post-slug/index.js +8 -14
- package/build-module/components/post-slug/index.js.map +1 -1
- package/build-module/components/post-taxonomies/flat-term-selector.js +8 -6
- package/build-module/components/post-taxonomies/flat-term-selector.js.map +1 -1
- package/build-module/components/post-taxonomies/hierarchical-term-selector.js +1 -2
- package/build-module/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
- package/build-module/components/post-taxonomies/index.js +4 -1
- package/build-module/components/post-taxonomies/index.js.map +1 -1
- package/build-module/components/post-template/index.js +1 -2
- package/build-module/components/post-template/index.js.map +1 -1
- package/build-module/components/post-title/index.js +8 -2
- package/build-module/components/post-title/index.js.map +1 -1
- package/build-module/components/post-url/check.js +44 -0
- package/build-module/components/post-url/check.js.map +1 -0
- package/build-module/components/post-url/index.js +102 -0
- package/build-module/components/post-url/index.js.map +1 -0
- package/build-module/components/post-url/label.js +18 -0
- package/build-module/components/post-url/label.js.map +1 -0
- package/build-module/components/post-visibility/index.js +4 -2
- package/build-module/components/post-visibility/index.js.map +1 -1
- package/build-module/components/post-visibility/label.js +3 -0
- package/build-module/components/post-visibility/label.js.map +1 -1
- package/build-module/components/provider/index.native.js +3 -2
- package/build-module/components/provider/index.native.js.map +1 -1
- package/build-module/components/provider/use-block-editor-settings.js +2 -2
- package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
- package/build-module/components/table-of-contents/panel.js +4 -1
- package/build-module/components/table-of-contents/panel.js.map +1 -1
- package/build-module/components/time-to-read/index.js +50 -0
- package/build-module/components/time-to-read/index.js.map +1 -0
- package/build-module/store/actions.js +5 -1
- package/build-module/store/actions.js.map +1 -1
- package/build-module/store/reducer.js +2 -2
- package/build-module/store/reducer.js.map +1 -1
- package/build-module/store/selectors.js +4 -4
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +19 -18
- package/build-style/style.css +23 -18
- package/package.json +30 -29
- package/src/components/README.md +1 -1
- package/src/components/document-outline/index.js +9 -8
- package/src/components/error-boundary/index.js +3 -0
- package/src/components/index.js +13 -4
- package/src/components/local-autosave-monitor/index.js +24 -18
- package/src/components/page-attributes/order.js +1 -9
- package/src/components/page-attributes/parent.js +6 -13
- package/src/components/post-format/index.js +13 -19
- package/src/components/post-format/style.scss +2 -17
- package/src/components/post-locked-modal/index.js +1 -1
- package/src/components/post-publish-panel/maybe-category-panel.js +7 -6
- package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +1 -1
- package/src/components/post-schedule/label.js +111 -17
- package/src/components/post-schedule/test/label.js +127 -15
- package/src/components/post-slug/index.js +7 -13
- package/src/components/post-slug/test/index.js +7 -6
- package/src/components/post-taxonomies/flat-term-selector.js +6 -5
- package/src/components/post-taxonomies/hierarchical-term-selector.js +1 -1
- package/src/components/post-taxonomies/index.js +3 -1
- package/src/components/post-template/index.js +1 -1
- package/src/components/post-title/index.js +8 -2
- package/src/components/post-title/style.scss +1 -1
- package/src/components/post-trash/style.scss +3 -0
- package/src/components/post-url/check.js +38 -0
- package/src/components/post-url/index.js +122 -0
- package/src/components/post-url/label.js +22 -0
- package/src/components/post-url/style.scss +16 -0
- package/src/components/post-visibility/index.js +2 -2
- package/src/components/post-visibility/label.js +4 -0
- package/src/components/provider/index.native.js +4 -8
- package/src/components/provider/use-block-editor-settings.js +4 -1
- package/src/components/table-of-contents/panel.js +7 -2
- package/src/components/time-to-read/index.js +59 -0
- package/src/store/actions.js +3 -1
- package/src/store/reducer.js +2 -2
- package/src/store/selectors.js +5 -6
- package/src/store/test/selectors.js +8 -10
- package/src/style.scss +1 -0
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { countBy, flatMap, get } from 'lodash';
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* WordPress dependencies
|
|
8
3
|
*/
|
|
@@ -50,7 +45,7 @@ const multipleH1Headings = [
|
|
|
50
45
|
* @return {Array} An array of heading blocks enhanced with the properties described above.
|
|
51
46
|
*/
|
|
52
47
|
const computeOutlineHeadings = ( blocks = [] ) => {
|
|
53
|
-
return flatMap(
|
|
48
|
+
return blocks.flatMap( ( block = {} ) => {
|
|
54
49
|
if ( block.name === 'core/heading' ) {
|
|
55
50
|
return {
|
|
56
51
|
...block,
|
|
@@ -83,7 +78,13 @@ export const DocumentOutline = ( {
|
|
|
83
78
|
// Not great but it's the simplest way to locate the title right now.
|
|
84
79
|
const titleNode = document.querySelector( '.editor-post-title__input' );
|
|
85
80
|
const hasTitle = isTitleSupported && title && titleNode;
|
|
86
|
-
const countByLevel =
|
|
81
|
+
const countByLevel = headings.reduce(
|
|
82
|
+
( acc, heading ) => ( {
|
|
83
|
+
...acc,
|
|
84
|
+
[ heading.level ]: ( acc[ heading.level ] || 0 ) + 1,
|
|
85
|
+
} ),
|
|
86
|
+
{}
|
|
87
|
+
);
|
|
87
88
|
const hasMultipleH1 = countByLevel[ 1 ] > 1;
|
|
88
89
|
|
|
89
90
|
return (
|
|
@@ -155,7 +156,7 @@ export default compose(
|
|
|
155
156
|
return {
|
|
156
157
|
title: getEditedPostAttribute( 'title' ),
|
|
157
158
|
blocks: getBlocks(),
|
|
158
|
-
isTitleSupported:
|
|
159
|
+
isTitleSupported: postType?.supports?.title ?? false,
|
|
159
160
|
};
|
|
160
161
|
} )
|
|
161
162
|
)( DocumentOutline );
|
|
@@ -7,6 +7,7 @@ import { Button } from '@wordpress/components';
|
|
|
7
7
|
import { select } from '@wordpress/data';
|
|
8
8
|
import { Warning } from '@wordpress/block-editor';
|
|
9
9
|
import { useCopyToClipboard } from '@wordpress/compose';
|
|
10
|
+
import { doAction } from '@wordpress/hooks';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Internal dependencies
|
|
@@ -36,6 +37,8 @@ class ErrorBoundary extends Component {
|
|
|
36
37
|
|
|
37
38
|
componentDidCatch( error ) {
|
|
38
39
|
this.setState( { error } );
|
|
40
|
+
|
|
41
|
+
doAction( 'editor.ErrorBoundary.errorLogged', error );
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
reboot() {
|
package/src/components/index.js
CHANGED
|
@@ -41,23 +41,32 @@ export { default as PostPublishPanel } from './post-publish-panel';
|
|
|
41
41
|
export { default as PostSavedState } from './post-saved-state';
|
|
42
42
|
export { default as PostSchedule } from './post-schedule';
|
|
43
43
|
export { default as PostScheduleCheck } from './post-schedule/check';
|
|
44
|
-
export {
|
|
44
|
+
export {
|
|
45
|
+
default as PostScheduleLabel,
|
|
46
|
+
usePostScheduleLabel,
|
|
47
|
+
} from './post-schedule/label';
|
|
45
48
|
export { default as PostSlug } from './post-slug';
|
|
46
49
|
export { default as PostSlugCheck } from './post-slug/check';
|
|
47
50
|
export { default as PostSticky } from './post-sticky';
|
|
48
51
|
export { default as PostStickyCheck } from './post-sticky/check';
|
|
49
52
|
export { default as PostSwitchToDraftButton } from './post-switch-to-draft-button';
|
|
50
53
|
export { default as PostTaxonomies } from './post-taxonomies';
|
|
51
|
-
export {
|
|
52
|
-
export {
|
|
54
|
+
export { FlatTermSelector as PostTaxonomiesFlatTermSelector } from './post-taxonomies/flat-term-selector';
|
|
55
|
+
export { HierarchicalTermSelector as PostTaxonomiesHierarchicalTermSelector } from './post-taxonomies/hierarchical-term-selector';
|
|
53
56
|
export { default as PostTaxonomiesCheck } from './post-taxonomies/check';
|
|
54
57
|
export { default as PostTextEditor } from './post-text-editor';
|
|
55
58
|
export { default as PostTitle } from './post-title';
|
|
56
59
|
export { default as PostTrash } from './post-trash';
|
|
57
60
|
export { default as PostTrashCheck } from './post-trash/check';
|
|
58
61
|
export { default as PostTypeSupportCheck } from './post-type-support-check';
|
|
62
|
+
export { default as PostURL } from './post-url';
|
|
63
|
+
export { default as PostURLCheck } from './post-url/check';
|
|
64
|
+
export { default as PostURLLabel, usePostURLLabel } from './post-url/label';
|
|
59
65
|
export { default as PostVisibility } from './post-visibility';
|
|
60
|
-
export {
|
|
66
|
+
export {
|
|
67
|
+
default as PostVisibilityLabel,
|
|
68
|
+
usePostVisibilityLabel,
|
|
69
|
+
} from './post-visibility/label';
|
|
61
70
|
export { default as PostVisibilityCheck } from './post-visibility/check';
|
|
62
71
|
export { default as TableOfContents } from './table-of-contents';
|
|
63
72
|
export { default as ThemeSupportCheck } from './theme-support-check';
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { once, uniqueId, omit } from 'lodash';
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* WordPress dependencies
|
|
8
3
|
*/
|
|
@@ -27,23 +22,30 @@ const requestIdleCallback = window.requestIdleCallback
|
|
|
27
22
|
? window.requestIdleCallback
|
|
28
23
|
: window.requestAnimationFrame;
|
|
29
24
|
|
|
25
|
+
let hasStorageSupport;
|
|
26
|
+
let uniqueId = 0;
|
|
27
|
+
|
|
30
28
|
/**
|
|
31
29
|
* Function which returns true if the current environment supports browser
|
|
32
30
|
* sessionStorage, or false otherwise. The result of this function is cached and
|
|
33
31
|
* reused in subsequent invocations.
|
|
34
32
|
*/
|
|
35
|
-
const hasSessionStorageSupport =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
const hasSessionStorageSupport = () => {
|
|
34
|
+
if ( typeof hasStorageSupport === 'undefined' ) {
|
|
35
|
+
try {
|
|
36
|
+
// Private Browsing in Safari 10 and earlier will throw an error when
|
|
37
|
+
// attempting to set into sessionStorage. The test here is intentional in
|
|
38
|
+
// causing a thrown error as condition bailing from local autosave.
|
|
39
|
+
window.sessionStorage.setItem( '__wpEditorTestSessionStorage', '' );
|
|
40
|
+
window.sessionStorage.removeItem( '__wpEditorTestSessionStorage' );
|
|
41
|
+
hasStorageSupport = true;
|
|
42
|
+
} catch ( error ) {
|
|
43
|
+
hasStorageSupport = false;
|
|
44
|
+
}
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
|
|
47
|
+
return hasStorageSupport;
|
|
48
|
+
};
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
51
|
* Custom hook which manages the creation of a notice prompting the user to
|
|
@@ -98,7 +100,7 @@ function useAutosaveNotice() {
|
|
|
98
100
|
return;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
const noticeId = uniqueId
|
|
103
|
+
const noticeId = `wpEditorAutosaveRestore${ ++uniqueId }`;
|
|
102
104
|
createWarningNotice(
|
|
103
105
|
__(
|
|
104
106
|
'The backup of this post in your browser is different from the version below.'
|
|
@@ -109,7 +111,11 @@ function useAutosaveNotice() {
|
|
|
109
111
|
{
|
|
110
112
|
label: __( 'Restore the backup' ),
|
|
111
113
|
onClick() {
|
|
112
|
-
|
|
114
|
+
const {
|
|
115
|
+
content: editsContent,
|
|
116
|
+
...editsWithoutContent
|
|
117
|
+
} = edits;
|
|
118
|
+
editPost( editsWithoutContent );
|
|
113
119
|
resetEditorBlocks( parse( edits.content ) );
|
|
114
120
|
removeNotice( noticeId );
|
|
115
121
|
},
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { invoke } from 'lodash';
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* WordPress dependencies
|
|
8
3
|
*/
|
|
@@ -24,10 +19,7 @@ export const PageAttributesOrder = ( { onUpdateOrder, order = 0 } ) => {
|
|
|
24
19
|
const setUpdatedOrder = ( value ) => {
|
|
25
20
|
setOrderInput( value );
|
|
26
21
|
const newOrder = Number( value );
|
|
27
|
-
if (
|
|
28
|
-
Number.isInteger( newOrder ) &&
|
|
29
|
-
invoke( value, [ 'trim' ] ) !== ''
|
|
30
|
-
) {
|
|
22
|
+
if ( Number.isInteger( newOrder ) && value.trim?.() !== '' ) {
|
|
31
23
|
onUpdateOrder( Number( value ) );
|
|
32
24
|
}
|
|
33
25
|
};
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
unescape as unescapeString,
|
|
7
|
-
debounce,
|
|
8
|
-
repeat,
|
|
9
|
-
find,
|
|
10
|
-
flatten,
|
|
11
|
-
deburr,
|
|
12
|
-
} from 'lodash';
|
|
4
|
+
import { get, unescape as unescapeString, debounce, find } from 'lodash';
|
|
5
|
+
import removeAccents from 'remove-accents';
|
|
13
6
|
|
|
14
7
|
/**
|
|
15
8
|
* WordPress dependencies
|
|
@@ -34,8 +27,8 @@ function getTitle( post ) {
|
|
|
34
27
|
}
|
|
35
28
|
|
|
36
29
|
export const getItemPriority = ( name, searchValue ) => {
|
|
37
|
-
const normalizedName =
|
|
38
|
-
const normalizedSearch =
|
|
30
|
+
const normalizedName = removeAccents( name || '' ).toLowerCase();
|
|
31
|
+
const normalizedSearch = removeAccents( searchValue || '' ).toLowerCase();
|
|
39
32
|
if ( normalizedName === normalizedSearch ) {
|
|
40
33
|
return 0;
|
|
41
34
|
}
|
|
@@ -99,7 +92,7 @@ export function PageAttributesParent() {
|
|
|
99
92
|
{
|
|
100
93
|
value: treeNode.id,
|
|
101
94
|
label:
|
|
102
|
-
|
|
95
|
+
'— '.repeat( level ) + unescapeString( treeNode.name ),
|
|
103
96
|
rawName: treeNode.name,
|
|
104
97
|
},
|
|
105
98
|
...getOptionsFromTree( treeNode.children || [], level + 1 ),
|
|
@@ -111,7 +104,7 @@ export function PageAttributesParent() {
|
|
|
111
104
|
return priorityA >= priorityB ? 1 : -1;
|
|
112
105
|
} );
|
|
113
106
|
|
|
114
|
-
return
|
|
107
|
+
return sortedNodes.flat();
|
|
115
108
|
};
|
|
116
109
|
|
|
117
110
|
let tree = pageItems.map( ( item ) => ( {
|
|
@@ -81,24 +81,18 @@ export default function PostFormat() {
|
|
|
81
81
|
return (
|
|
82
82
|
<PostFormatCheck>
|
|
83
83
|
<div className="editor-post-format">
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
id
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
value: format.id,
|
|
95
|
-
} ) ) }
|
|
96
|
-
/>
|
|
97
|
-
</div>
|
|
98
|
-
|
|
84
|
+
<SelectControl
|
|
85
|
+
label={ __( 'Post Format' ) }
|
|
86
|
+
value={ postFormat }
|
|
87
|
+
onChange={ ( format ) => onUpdatePostFormat( format ) }
|
|
88
|
+
id={ postFormatSelectorId }
|
|
89
|
+
options={ formats.map( ( format ) => ( {
|
|
90
|
+
label: format.caption,
|
|
91
|
+
value: format.id,
|
|
92
|
+
} ) ) }
|
|
93
|
+
/>
|
|
99
94
|
{ suggestion && suggestion.id !== postFormat && (
|
|
100
|
-
<
|
|
101
|
-
{ __( 'Suggestion:' ) }{ ' ' }
|
|
95
|
+
<p className="editor-post-format__suggestion">
|
|
102
96
|
<Button
|
|
103
97
|
variant="link"
|
|
104
98
|
onClick={ () =>
|
|
@@ -107,11 +101,11 @@ export default function PostFormat() {
|
|
|
107
101
|
>
|
|
108
102
|
{ sprintf(
|
|
109
103
|
/* translators: %s: post format */
|
|
110
|
-
__( 'Apply format: %s' ),
|
|
104
|
+
__( 'Apply suggested format: %s' ),
|
|
111
105
|
suggestion.caption
|
|
112
106
|
) }
|
|
113
107
|
</Button>
|
|
114
|
-
</
|
|
108
|
+
</p>
|
|
115
109
|
) }
|
|
116
110
|
</div>
|
|
117
111
|
</PostFormatCheck>
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
.editor-post-
|
|
2
|
-
|
|
3
|
-
align-items: stretch;
|
|
4
|
-
width: 100%;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.editor-post-format__content {
|
|
8
|
-
display: inline-flex;
|
|
9
|
-
justify-content: space-between;
|
|
10
|
-
align-items: center;
|
|
11
|
-
width: 100%;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.editor-post-format__suggestion {
|
|
15
|
-
padding: $grid-unit-15 * 0.5;
|
|
16
|
-
text-align: right;
|
|
17
|
-
font-size: $default-font-size;
|
|
1
|
+
[class].editor-post-format__suggestion {
|
|
2
|
+
margin: $grid-unit-05 0 0 0;
|
|
18
3
|
}
|
|
@@ -197,7 +197,7 @@ export default function PostLockedModal() {
|
|
|
197
197
|
? sprintf(
|
|
198
198
|
/* translators: %s: user's display name */
|
|
199
199
|
__(
|
|
200
|
-
'<strong>%s</strong> now has editing control of this
|
|
200
|
+
'<strong>%s</strong> now has editing control of this post (<PreviewLink />). Don’t worry, your changes up to this moment have been saved.'
|
|
201
201
|
),
|
|
202
202
|
userDisplayName
|
|
203
203
|
)
|
|
@@ -23,14 +23,15 @@ function MaybeCategoryPanel() {
|
|
|
23
23
|
const postType = select( editorStore ).getCurrentPostType();
|
|
24
24
|
const categoriesTaxonomy =
|
|
25
25
|
select( coreStore ).getTaxonomy( 'category' );
|
|
26
|
-
const
|
|
27
|
-
|
|
26
|
+
const defaultCategoryId = select( coreStore ).getEntityRecord(
|
|
27
|
+
'root',
|
|
28
|
+
'site'
|
|
29
|
+
)?.default_category;
|
|
30
|
+
const defaultCategory = select( coreStore ).getEntityRecord(
|
|
28
31
|
'taxonomy',
|
|
29
32
|
'category',
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
)?.[ 0 ];
|
|
33
|
+
defaultCategoryId
|
|
34
|
+
);
|
|
34
35
|
const postTypeSupportsCategories =
|
|
35
36
|
categoriesTaxonomy &&
|
|
36
37
|
some( categoriesTaxonomy.types, ( type ) => type === postType );
|
|
@@ -184,7 +184,7 @@ exports[`PostPublishPanel should render the spinner if the post is being saved 1
|
|
|
184
184
|
<div
|
|
185
185
|
className="editor-post-publish-panel__content"
|
|
186
186
|
>
|
|
187
|
-
<
|
|
187
|
+
<ForwardRef(UnforwardedSpinner) />
|
|
188
188
|
</div>
|
|
189
189
|
<div
|
|
190
190
|
className="editor-post-publish-panel__footer"
|
|
@@ -1,28 +1,122 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { __ } from '@wordpress/i18n';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { __, _x, sprintf, isRTL } from '@wordpress/i18n';
|
|
5
|
+
import { __experimentalGetSettings, getDate, dateI18n } from '@wordpress/date';
|
|
6
|
+
import { useSelect } from '@wordpress/data';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Internal dependencies
|
|
10
10
|
*/
|
|
11
11
|
import { store as editorStore } from '../../store';
|
|
12
12
|
|
|
13
|
-
export function PostScheduleLabel(
|
|
14
|
-
|
|
15
|
-
return date && ! isFloating
|
|
16
|
-
? format(
|
|
17
|
-
`${ settings.formats.date } ${ settings.formats.time }`,
|
|
18
|
-
date
|
|
19
|
-
)
|
|
20
|
-
: __( 'Immediately' );
|
|
13
|
+
export default function PostScheduleLabel( props ) {
|
|
14
|
+
return usePostScheduleLabel( props );
|
|
21
15
|
}
|
|
22
16
|
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} )
|
|
17
|
+
export function usePostScheduleLabel( { full = false } = {} ) {
|
|
18
|
+
const { date, isFloating } = useSelect(
|
|
19
|
+
( select ) => ( {
|
|
20
|
+
date: select( editorStore ).getEditedPostAttribute( 'date' ),
|
|
21
|
+
isFloating: select( editorStore ).isEditedPostDateFloating(),
|
|
22
|
+
} ),
|
|
23
|
+
[]
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return full
|
|
27
|
+
? getFullPostScheduleLabel( date )
|
|
28
|
+
: getPostScheduleLabel( date, { isFloating } );
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getFullPostScheduleLabel( dateAttribute ) {
|
|
32
|
+
const date = getDate( dateAttribute );
|
|
33
|
+
|
|
34
|
+
const timezoneAbbreviation = getTimezoneAbbreviation();
|
|
35
|
+
const formattedDate = dateI18n(
|
|
36
|
+
// translators: If using a space between 'g:i' and 'a', use a non-breaking sapce.
|
|
37
|
+
_x( 'F j, Y g:i\xa0a', 'post schedule full date format' ),
|
|
38
|
+
date
|
|
39
|
+
);
|
|
40
|
+
return isRTL()
|
|
41
|
+
? `${ timezoneAbbreviation } ${ formattedDate }`
|
|
42
|
+
: `${ formattedDate } ${ timezoneAbbreviation }`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getPostScheduleLabel(
|
|
46
|
+
dateAttribute,
|
|
47
|
+
{ isFloating = false, now = new Date() } = {}
|
|
48
|
+
) {
|
|
49
|
+
if ( ! dateAttribute || isFloating ) {
|
|
50
|
+
return __( 'Immediately' );
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// If the user timezone does not equal the site timezone then using words
|
|
54
|
+
// like 'tomorrow' is confusing, so show the full date.
|
|
55
|
+
if ( ! isTimezoneSameAsSiteTimezone( now ) ) {
|
|
56
|
+
return getFullPostScheduleLabel( dateAttribute );
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const date = getDate( dateAttribute );
|
|
60
|
+
|
|
61
|
+
if ( isSameDay( date, now ) ) {
|
|
62
|
+
return sprintf(
|
|
63
|
+
// translators: %s: Time of day the post is scheduled for.
|
|
64
|
+
__( 'Today at %s' ),
|
|
65
|
+
// translators: If using a space between 'g:i' and 'a', use a non-breaking sapce.
|
|
66
|
+
dateI18n( _x( 'g:i\xa0a', 'post schedule time format' ), date )
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const tomorrow = new Date( now );
|
|
71
|
+
tomorrow.setDate( tomorrow.getDate() + 1 );
|
|
72
|
+
|
|
73
|
+
if ( isSameDay( date, tomorrow ) ) {
|
|
74
|
+
return sprintf(
|
|
75
|
+
// translators: %s: Time of day the post is scheduled for.
|
|
76
|
+
__( 'Tomorrow at %s' ),
|
|
77
|
+
// translators: If using a space between 'g:i' and 'a', use a non-breaking sapce.
|
|
78
|
+
dateI18n( _x( 'g:i\xa0a', 'post schedule time format' ), date )
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if ( date.getFullYear() === now.getFullYear() ) {
|
|
83
|
+
return dateI18n(
|
|
84
|
+
// translators: If using a space between 'g:i' and 'a', use a non-breaking sapce.
|
|
85
|
+
_x( 'F j g:i\xa0a', 'post schedule date format without year' ),
|
|
86
|
+
date
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return dateI18n(
|
|
91
|
+
// translators: Use a non-breaking space between 'g:i' and 'a' if appropriate.
|
|
92
|
+
_x( 'F j, Y g:i\xa0a', 'post schedule full date format' ),
|
|
93
|
+
date
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getTimezoneAbbreviation() {
|
|
98
|
+
const { timezone } = __experimentalGetSettings();
|
|
99
|
+
|
|
100
|
+
if ( timezone.abbr && isNaN( Number( timezone.abbr ) ) ) {
|
|
101
|
+
return timezone.abbr;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const symbol = timezone.offset < 0 ? '' : '+';
|
|
105
|
+
return `UTC${ symbol }${ timezone.offset }`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function isTimezoneSameAsSiteTimezone( date ) {
|
|
109
|
+
const { timezone } = __experimentalGetSettings();
|
|
110
|
+
|
|
111
|
+
const siteOffset = Number( timezone.offset );
|
|
112
|
+
const dateOffset = -1 * ( date.getTimezoneOffset() / 60 );
|
|
113
|
+
return siteOffset === dateOffset;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function isSameDay( left, right ) {
|
|
117
|
+
return (
|
|
118
|
+
left.getDate() === right.getDate() &&
|
|
119
|
+
left.getMonth() === right.getMonth() &&
|
|
120
|
+
left.getFullYear() === right.getFullYear()
|
|
121
|
+
);
|
|
122
|
+
}
|
|
@@ -1,32 +1,144 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { __experimentalGetSettings, setSettings } from '@wordpress/date';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Internal dependencies
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { getFullPostScheduleLabel, getPostScheduleLabel } from '../label';
|
|
10
10
|
|
|
11
|
-
describe( '
|
|
11
|
+
describe( 'getFullPostScheduleLabel', () => {
|
|
12
|
+
it( 'should show a date', () => {
|
|
13
|
+
const label = getFullPostScheduleLabel( '2022-04-28T15:30:00' );
|
|
14
|
+
expect( label ).toBe( 'April 28, 2022 3:30\xa0pm UTC+0' ); // Unused, for backwards compatibility.
|
|
15
|
+
} );
|
|
16
|
+
|
|
17
|
+
it( "should show site's timezone abbr", () => {
|
|
18
|
+
const settings = __experimentalGetSettings();
|
|
19
|
+
|
|
20
|
+
setSettings( {
|
|
21
|
+
...settings,
|
|
22
|
+
timezone: { offset: 10, string: 'Australia/Sydney', abbr: 'AEST' },
|
|
23
|
+
} );
|
|
24
|
+
|
|
25
|
+
const label = getFullPostScheduleLabel( '2022-04-28T15:30:00' );
|
|
26
|
+
expect( label ).toBe( 'April 28, 2022 3:30\xa0pm AEST' );
|
|
27
|
+
|
|
28
|
+
setSettings( settings );
|
|
29
|
+
} );
|
|
30
|
+
|
|
31
|
+
it( "should show site's timezone offset", () => {
|
|
32
|
+
const settings = __experimentalGetSettings();
|
|
33
|
+
|
|
34
|
+
setSettings( {
|
|
35
|
+
...settings,
|
|
36
|
+
timezone: { offset: 10 },
|
|
37
|
+
} );
|
|
38
|
+
|
|
39
|
+
const label = getFullPostScheduleLabel( '2022-04-28T15:30:00' );
|
|
40
|
+
expect( label ).toBe( 'April 28, 2022 3:30\xa0pm UTC+10' );
|
|
41
|
+
|
|
42
|
+
setSettings( settings );
|
|
43
|
+
} );
|
|
44
|
+
} );
|
|
45
|
+
|
|
46
|
+
describe( 'getPostScheduleLabel', () => {
|
|
12
47
|
it( 'should show the post will be published immediately if no publish date is set', () => {
|
|
13
|
-
const
|
|
14
|
-
expect(
|
|
48
|
+
const label = getPostScheduleLabel( undefined );
|
|
49
|
+
expect( label ).toBe( 'Immediately' );
|
|
15
50
|
} );
|
|
16
51
|
|
|
17
52
|
it( 'should show the post will be published immediately if it has a floating date', () => {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
53
|
+
const label = getPostScheduleLabel( '2022-04-28T15:30:00', {
|
|
54
|
+
isFloating: true,
|
|
55
|
+
} );
|
|
56
|
+
expect( label ).toBe( 'Immediately' );
|
|
57
|
+
} );
|
|
58
|
+
|
|
59
|
+
it( "should show full date if user timezone does not equal site's timezone", () => {
|
|
60
|
+
const now = new Date( '2022-04-28T13:00:00.000Z' );
|
|
61
|
+
jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
|
|
62
|
+
() => 10 * -60 // UTC+10
|
|
21
63
|
);
|
|
22
|
-
|
|
64
|
+
|
|
65
|
+
const label = getPostScheduleLabel( '2022-04-28T15:30:00', { now } );
|
|
66
|
+
expect( label ).toBe( 'April 28, 2022 3:30\xa0pm UTC+0' );
|
|
23
67
|
} );
|
|
24
68
|
|
|
25
|
-
it(
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
69
|
+
it( "should show today if date is same day as now and user timezone equals site's timezone", () => {
|
|
70
|
+
const settings = __experimentalGetSettings();
|
|
71
|
+
|
|
72
|
+
setSettings( {
|
|
73
|
+
...settings,
|
|
74
|
+
timezone: { offset: 10 },
|
|
75
|
+
} );
|
|
76
|
+
|
|
77
|
+
const now = new Date( '2022-04-28T03:00:00.000Z' );
|
|
78
|
+
jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
|
|
79
|
+
() => 10 * -60 // UTC+10
|
|
29
80
|
);
|
|
30
|
-
|
|
81
|
+
|
|
82
|
+
const label = getPostScheduleLabel( '2022-04-28T15:30:00', { now } );
|
|
83
|
+
expect( label ).toBe( 'Today at 3:30\xa0pm' );
|
|
84
|
+
|
|
85
|
+
setSettings( settings );
|
|
86
|
+
} );
|
|
87
|
+
|
|
88
|
+
it( "should show tomorrow if date is same day as now + 1 day and user timezone equals site's timezone", () => {
|
|
89
|
+
const settings = __experimentalGetSettings();
|
|
90
|
+
|
|
91
|
+
setSettings( {
|
|
92
|
+
...settings,
|
|
93
|
+
timezone: { offset: 10 },
|
|
94
|
+
} );
|
|
95
|
+
|
|
96
|
+
const now = new Date( '2022-04-28T03:00:00.000Z' );
|
|
97
|
+
jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
|
|
98
|
+
() => 10 * -60 // UTC+10
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const label = getPostScheduleLabel( '2022-04-29T15:30:00', { now } );
|
|
102
|
+
expect( label ).toBe( 'Tomorrow at 3:30\xa0pm' );
|
|
103
|
+
|
|
104
|
+
setSettings( settings );
|
|
105
|
+
} );
|
|
106
|
+
|
|
107
|
+
it( "should hide year if date is same year as now and user timezone equals site's timezone", () => {
|
|
108
|
+
const settings = __experimentalGetSettings();
|
|
109
|
+
|
|
110
|
+
setSettings( {
|
|
111
|
+
...settings,
|
|
112
|
+
timezone: { offset: 10 },
|
|
113
|
+
} );
|
|
114
|
+
|
|
115
|
+
const now = new Date( '2022-04-28T03:00:00.000Z' );
|
|
116
|
+
jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
|
|
117
|
+
() => 10 * -60 // UTC+10
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const label = getPostScheduleLabel( '2022-12-25T15:30:00', { now } );
|
|
121
|
+
expect( label ).toBe( 'December 25 3:30\xa0pm' );
|
|
122
|
+
|
|
123
|
+
setSettings( settings );
|
|
124
|
+
} );
|
|
125
|
+
|
|
126
|
+
it( "should show year if date is not same year as now and user timezone equals site's timezone", () => {
|
|
127
|
+
const settings = __experimentalGetSettings();
|
|
128
|
+
|
|
129
|
+
setSettings( {
|
|
130
|
+
...settings,
|
|
131
|
+
timezone: { offset: 10 },
|
|
132
|
+
} );
|
|
133
|
+
|
|
134
|
+
const now = new Date( '2022-04-28T03:00:00.000Z' );
|
|
135
|
+
jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
|
|
136
|
+
() => 10 * -60 // UTC+10
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const label = getPostScheduleLabel( '2023-04-28T15:30:00', { now } );
|
|
140
|
+
expect( label ).toBe( 'April 28, 2023 3:30\xa0pm' );
|
|
141
|
+
|
|
142
|
+
setSettings( settings );
|
|
31
143
|
} );
|
|
32
144
|
} );
|