@wordpress/editor 11.0.2 → 12.0.3
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 +7 -0
- package/README.md +1 -1
- package/build/components/autosave-monitor/index.js +5 -0
- package/build/components/autosave-monitor/index.js.map +1 -1
- package/build/components/character-count/index.js +1 -1
- package/build/components/character-count/index.js.map +1 -1
- package/build/components/editor-help/help-get-support-button.native.js +46 -0
- package/build/components/editor-help/help-get-support-button.native.js.map +1 -0
- package/build/components/editor-help/index.native.js +24 -5
- package/build/components/editor-help/index.native.js.map +1 -1
- package/build/components/entities-saved-states/entity-type-list.js +22 -13
- package/build/components/entities-saved-states/entity-type-list.js.map +1 -1
- package/build/components/entities-saved-states/index.js +23 -4
- package/build/components/entities-saved-states/index.js.map +1 -1
- package/build/components/global-keyboard-shortcuts/save-shortcut.js +12 -14
- package/build/components/global-keyboard-shortcuts/save-shortcut.js.map +1 -1
- package/build/components/global-keyboard-shortcuts/visual-editor-shortcuts.js +0 -4
- package/build/components/global-keyboard-shortcuts/visual-editor-shortcuts.js.map +1 -1
- package/build/components/post-format/index.js +3 -1
- 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-saved-state/index.js +37 -46
- package/build/components/post-saved-state/index.js.map +1 -1
- package/build/components/post-taxonomies/flat-term-selector.js +154 -211
- package/build/components/post-taxonomies/flat-term-selector.js.map +1 -1
- package/build/components/post-title/index.js +5 -3
- package/build/components/post-title/index.js.map +1 -1
- package/build/components/provider/index.native.js +3 -1
- package/build/components/provider/index.native.js.map +1 -1
- package/build/components/provider/use-block-editor-settings.js +32 -5
- package/build/components/provider/use-block-editor-settings.js.map +1 -1
- package/build/components/word-count/index.js +1 -1
- package/build/components/word-count/index.js.map +1 -1
- package/build/store/actions.js +0 -25
- package/build/store/actions.js.map +1 -1
- package/build/store/selectors.js +3 -84
- package/build/store/selectors.js.map +1 -1
- package/build/store/utils/notice-builder.js +15 -18
- package/build/store/utils/notice-builder.js.map +1 -1
- package/build/{store/utils → utils}/get-template-part-icon.js +1 -1
- package/build/utils/get-template-part-icon.js.map +1 -0
- package/build/utils/index.js +8 -0
- package/build/utils/index.js.map +1 -1
- package/build-module/components/autosave-monitor/index.js +5 -0
- package/build-module/components/autosave-monitor/index.js.map +1 -1
- package/build-module/components/character-count/index.js +1 -1
- package/build-module/components/character-count/index.js.map +1 -1
- package/build-module/components/editor-help/help-get-support-button.native.js +34 -0
- package/build-module/components/editor-help/help-get-support-button.native.js.map +1 -0
- package/build-module/components/editor-help/index.native.js +22 -6
- package/build-module/components/editor-help/index.native.js.map +1 -1
- package/build-module/components/entities-saved-states/entity-type-list.js +24 -13
- package/build-module/components/entities-saved-states/entity-type-list.js.map +1 -1
- package/build-module/components/entities-saved-states/index.js +23 -4
- package/build-module/components/entities-saved-states/index.js.map +1 -1
- package/build-module/components/global-keyboard-shortcuts/save-shortcut.js +12 -14
- package/build-module/components/global-keyboard-shortcuts/save-shortcut.js.map +1 -1
- package/build-module/components/global-keyboard-shortcuts/visual-editor-shortcuts.js +0 -4
- package/build-module/components/global-keyboard-shortcuts/visual-editor-shortcuts.js.map +1 -1
- package/build-module/components/post-format/index.js +4 -2
- 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-saved-state/index.js +38 -46
- package/build-module/components/post-saved-state/index.js.map +1 -1
- package/build-module/components/post-taxonomies/flat-term-selector.js +156 -214
- package/build-module/components/post-taxonomies/flat-term-selector.js.map +1 -1
- package/build-module/components/post-title/index.js +5 -3
- package/build-module/components/post-title/index.js.map +1 -1
- package/build-module/components/provider/index.native.js +3 -1
- package/build-module/components/provider/index.native.js.map +1 -1
- package/build-module/components/provider/use-block-editor-settings.js +31 -5
- package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
- package/build-module/components/word-count/index.js +1 -1
- package/build-module/components/word-count/index.js.map +1 -1
- package/build-module/store/actions.js +0 -23
- package/build-module/store/actions.js.map +1 -1
- package/build-module/store/selectors.js +3 -80
- package/build-module/store/selectors.js.map +1 -1
- package/build-module/store/utils/notice-builder.js +15 -18
- package/build-module/store/utils/notice-builder.js.map +1 -1
- package/build-module/{store/utils → utils}/get-template-part-icon.js +2 -2
- package/build-module/utils/get-template-part-icon.js.map +1 -0
- package/build-module/utils/index.js +1 -0
- package/build-module/utils/index.js.map +1 -1
- package/build-style/style-rtl.css +6 -1
- package/build-style/style.css +6 -1
- package/package.json +28 -28
- package/src/components/autosave-monitor/index.js +5 -0
- package/src/components/autosave-monitor/test/index.js +10 -4
- package/src/components/character-count/index.js +3 -2
- package/src/components/editor-help/help-get-support-button.native.js +38 -0
- package/src/components/editor-help/index.native.js +130 -80
- package/src/components/editor-help/style.android.scss +6 -0
- package/src/components/editor-help/style.ios.scss +6 -0
- package/src/components/editor-help/style.scss +25 -0
- package/src/components/editor-help/test/index.native.js +80 -0
- package/src/components/entities-saved-states/entity-type-list.js +29 -10
- package/src/components/entities-saved-states/index.js +38 -8
- package/src/components/global-keyboard-shortcuts/save-shortcut.js +34 -42
- package/src/components/global-keyboard-shortcuts/visual-editor-shortcuts.js +8 -16
- package/src/components/post-format/index.js +6 -2
- package/src/components/post-format/style.scss +1 -0
- package/src/components/post-locked-modal/index.js +1 -1
- package/src/components/post-saved-state/index.js +41 -55
- package/src/components/post-saved-state/style.scss +10 -1
- package/src/components/post-saved-state/test/__snapshots__/index.js.snap +20 -0
- package/src/components/post-saved-state/test/index.js +2 -2
- package/src/components/post-taxonomies/flat-term-selector.js +220 -254
- package/src/components/post-title/index.js +5 -3
- package/src/components/provider/index.native.js +2 -0
- package/src/components/provider/use-block-editor-settings.js +24 -2
- package/src/components/word-count/index.js +3 -2
- package/src/store/actions.js +0 -28
- package/src/store/selectors.js +2 -105
- package/src/store/test/actions.js +4 -2
- package/src/store/utils/notice-builder.js +17 -19
- package/src/store/utils/test/notice-builder.js +1 -1
- package/src/{store/utils → utils}/get-template-part-icon.js +2 -2
- package/src/utils/index.js +1 -0
- package/build/store/utils/get-template-part-icon.js.map +0 -1
- package/build-module/store/utils/get-template-part-icon.js.map +0 -1
|
@@ -1,31 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
debounce,
|
|
6
|
-
escape as escapeString,
|
|
7
|
-
find,
|
|
8
|
-
get,
|
|
9
|
-
invoke,
|
|
10
|
-
isEmpty,
|
|
11
|
-
uniqBy,
|
|
12
|
-
} from 'lodash';
|
|
4
|
+
import { escape as escapeString, find, get, uniqBy } from 'lodash';
|
|
13
5
|
|
|
14
6
|
/**
|
|
15
7
|
* WordPress dependencies
|
|
16
8
|
*/
|
|
17
9
|
import { __, _x, sprintf } from '@wordpress/i18n';
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
withFilters,
|
|
22
|
-
withSpokenMessages,
|
|
23
|
-
} from '@wordpress/components';
|
|
24
|
-
import { withSelect, withDispatch } from '@wordpress/data';
|
|
10
|
+
import { useEffect, useMemo, useState } from '@wordpress/element';
|
|
11
|
+
import { FormTokenField, withFilters } from '@wordpress/components';
|
|
12
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
25
13
|
import { store as coreStore } from '@wordpress/core-data';
|
|
26
|
-
import {
|
|
14
|
+
import { useDebounce } from '@wordpress/compose';
|
|
27
15
|
import apiFetch from '@wordpress/api-fetch';
|
|
28
16
|
import { addQueryArgs } from '@wordpress/url';
|
|
17
|
+
import { speak } from '@wordpress/a11y';
|
|
29
18
|
|
|
30
19
|
/**
|
|
31
20
|
* Internal dependencies
|
|
@@ -34,6 +23,14 @@ import { store as editorStore } from '../../store';
|
|
|
34
23
|
import { unescapeString, unescapeTerm, unescapeTerms } from '../../utils/terms';
|
|
35
24
|
import MostUsedTerms from './most-used-terms';
|
|
36
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Shared reference to an empty array for cases where it is important to avoid
|
|
28
|
+
* returning a new array reference on every invocation.
|
|
29
|
+
*
|
|
30
|
+
* @type {Array<any>}
|
|
31
|
+
*/
|
|
32
|
+
const EMPTY_ARRAY = [];
|
|
33
|
+
|
|
37
34
|
/**
|
|
38
35
|
* Module constants
|
|
39
36
|
*/
|
|
@@ -42,7 +39,8 @@ const DEFAULT_QUERY = {
|
|
|
42
39
|
per_page: MAX_TERMS_SUGGESTIONS,
|
|
43
40
|
orderby: 'count',
|
|
44
41
|
order: 'desc',
|
|
45
|
-
_fields: 'id,name
|
|
42
|
+
_fields: 'id,name',
|
|
43
|
+
context: 'view',
|
|
46
44
|
};
|
|
47
45
|
|
|
48
46
|
const isSameTermName = ( termA, termB ) =>
|
|
@@ -56,171 +54,195 @@ const termNamesToIds = ( names, terms ) => {
|
|
|
56
54
|
);
|
|
57
55
|
};
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.onChange = this.onChange.bind( this );
|
|
63
|
-
this.searchTerms = debounce( this.searchTerms.bind( this ), 500 );
|
|
64
|
-
this.findOrCreateTerm = this.findOrCreateTerm.bind( this );
|
|
65
|
-
this.appendTerm = this.appendTerm.bind( this );
|
|
66
|
-
this.state = {
|
|
67
|
-
loading: ! isEmpty( this.props.terms ),
|
|
68
|
-
availableTerms: [],
|
|
69
|
-
selectedTerms: [],
|
|
70
|
-
};
|
|
71
|
-
}
|
|
57
|
+
// Tries to create a term or fetch it if it already exists.
|
|
58
|
+
function findOrCreateTerm( termName, restBase ) {
|
|
59
|
+
const escapedTermName = escapeString( termName );
|
|
72
60
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
61
|
+
return apiFetch( {
|
|
62
|
+
path: `/wp/v2/${ restBase }`,
|
|
63
|
+
method: 'POST',
|
|
64
|
+
data: { name: escapedTermName },
|
|
65
|
+
} )
|
|
66
|
+
.catch( ( error ) => {
|
|
67
|
+
const errorCode = error.code;
|
|
68
|
+
if ( errorCode === 'term_exists' ) {
|
|
69
|
+
// If the terms exist, fetch it instead of creating a new one.
|
|
70
|
+
const addRequest = apiFetch( {
|
|
71
|
+
path: addQueryArgs( `/wp/v2/${ restBase }`, {
|
|
72
|
+
...DEFAULT_QUERY,
|
|
73
|
+
search: escapedTermName,
|
|
74
|
+
} ),
|
|
75
|
+
} ).then( unescapeTerms );
|
|
76
|
+
|
|
77
|
+
return addRequest.then( ( searchResult ) => {
|
|
78
|
+
return find( searchResult, ( result ) =>
|
|
79
|
+
isSameTermName( result.name, termName )
|
|
80
|
+
);
|
|
81
|
+
} );
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return Promise.reject( error );
|
|
85
|
+
} )
|
|
86
|
+
.then( unescapeTerm );
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function FlatTermSelector( { slug } ) {
|
|
90
|
+
const [ values, setValues ] = useState( [] );
|
|
91
|
+
const [ search, setSearch ] = useState( '' );
|
|
92
|
+
const debouncedSearch = useDebounce( setSearch, 500 );
|
|
93
|
+
|
|
94
|
+
const {
|
|
95
|
+
terms,
|
|
96
|
+
termIds,
|
|
97
|
+
taxonomy,
|
|
98
|
+
hasAssignAction,
|
|
99
|
+
hasCreateAction,
|
|
100
|
+
hasResolvedTerms,
|
|
101
|
+
} = useSelect(
|
|
102
|
+
( select ) => {
|
|
103
|
+
const { getCurrentPost, getEditedPostAttribute } = select(
|
|
104
|
+
editorStore
|
|
91
105
|
);
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
const {
|
|
107
|
+
getEntityRecords,
|
|
108
|
+
getTaxonomy,
|
|
109
|
+
hasFinishedResolution,
|
|
110
|
+
} = select( coreStore );
|
|
111
|
+
const post = getCurrentPost();
|
|
112
|
+
const _taxonomy = getTaxonomy( slug );
|
|
113
|
+
const _termIds = _taxonomy
|
|
114
|
+
? getEditedPostAttribute( _taxonomy.rest_base )
|
|
115
|
+
: EMPTY_ARRAY;
|
|
94
116
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
117
|
+
const query = {
|
|
118
|
+
...DEFAULT_QUERY,
|
|
119
|
+
include: _termIds.join( ',' ),
|
|
120
|
+
per_page: -1,
|
|
121
|
+
};
|
|
99
122
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
123
|
+
return {
|
|
124
|
+
hasCreateAction: _taxonomy
|
|
125
|
+
? get(
|
|
126
|
+
post,
|
|
127
|
+
[
|
|
128
|
+
'_links',
|
|
129
|
+
'wp:action-create-' + _taxonomy.rest_base,
|
|
130
|
+
],
|
|
131
|
+
false
|
|
132
|
+
)
|
|
133
|
+
: false,
|
|
134
|
+
hasAssignAction: _taxonomy
|
|
135
|
+
? get(
|
|
136
|
+
post,
|
|
137
|
+
[
|
|
138
|
+
'_links',
|
|
139
|
+
'wp:action-assign-' + _taxonomy.rest_base,
|
|
140
|
+
],
|
|
141
|
+
false
|
|
142
|
+
)
|
|
143
|
+
: false,
|
|
144
|
+
taxonomy: _taxonomy,
|
|
145
|
+
termIds: _termIds,
|
|
146
|
+
terms: _termIds.length
|
|
147
|
+
? getEntityRecords( 'taxonomy', slug, query )
|
|
148
|
+
: EMPTY_ARRAY,
|
|
149
|
+
hasResolvedTerms: hasFinishedResolution( 'getEntityRecords', [
|
|
150
|
+
'taxonomy',
|
|
151
|
+
slug,
|
|
152
|
+
query,
|
|
153
|
+
] ),
|
|
154
|
+
};
|
|
155
|
+
},
|
|
156
|
+
[ slug ]
|
|
157
|
+
);
|
|
105
158
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const request = apiFetch( {
|
|
110
|
-
path: addQueryArgs( `/wp/v2/${ taxonomy.rest_base }`, query ),
|
|
111
|
-
} );
|
|
112
|
-
request.then( unescapeTerms ).then( ( terms ) => {
|
|
113
|
-
this.setState( ( state ) => ( {
|
|
114
|
-
availableTerms: state.availableTerms.concat(
|
|
115
|
-
terms.filter(
|
|
116
|
-
( term ) =>
|
|
117
|
-
! find(
|
|
118
|
-
state.availableTerms,
|
|
119
|
-
( availableTerm ) =>
|
|
120
|
-
availableTerm.id === term.id
|
|
121
|
-
)
|
|
122
|
-
)
|
|
123
|
-
),
|
|
124
|
-
} ) );
|
|
125
|
-
this.updateSelectedTerms( this.props.terms );
|
|
126
|
-
} );
|
|
159
|
+
const { searchResults } = useSelect(
|
|
160
|
+
( select ) => {
|
|
161
|
+
const { getEntityRecords } = select( coreStore );
|
|
127
162
|
|
|
128
|
-
|
|
129
|
-
|
|
163
|
+
return {
|
|
164
|
+
searchResults: !! search
|
|
165
|
+
? getEntityRecords( 'taxonomy', slug, {
|
|
166
|
+
...DEFAULT_QUERY,
|
|
167
|
+
search,
|
|
168
|
+
} )
|
|
169
|
+
: EMPTY_ARRAY,
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
[ search ]
|
|
173
|
+
);
|
|
130
174
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
175
|
+
// Update terms state only after the selectors are resolved.
|
|
176
|
+
// We're using this to avoid terms temporarily disappearing on slow networks
|
|
177
|
+
// while core data makes REST API requests.
|
|
178
|
+
useEffect( () => {
|
|
179
|
+
if ( hasResolvedTerms ) {
|
|
180
|
+
const newValues = terms.map( ( term ) =>
|
|
181
|
+
unescapeString( term.name )
|
|
136
182
|
);
|
|
137
|
-
if ( termObject ) {
|
|
138
|
-
accumulator.push( termObject.name );
|
|
139
|
-
}
|
|
140
183
|
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
184
|
+
setValues( newValues );
|
|
185
|
+
}
|
|
186
|
+
}, [ terms, hasResolvedTerms ] );
|
|
187
|
+
|
|
188
|
+
const suggestions = useMemo( () => {
|
|
189
|
+
return ( searchResults ?? [] ).map( ( term ) =>
|
|
190
|
+
unescapeString( term.name )
|
|
191
|
+
);
|
|
192
|
+
}, [ searchResults ] );
|
|
193
|
+
|
|
194
|
+
const { editPost } = useDispatch( editorStore );
|
|
195
|
+
|
|
196
|
+
if ( ! hasAssignAction ) {
|
|
197
|
+
return null;
|
|
146
198
|
}
|
|
147
199
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const termNameEscaped = escapeString( termName );
|
|
151
|
-
// Tries to create a term or fetch it if it already exists.
|
|
152
|
-
return apiFetch( {
|
|
153
|
-
path: `/wp/v2/${ taxonomy.rest_base }`,
|
|
154
|
-
method: 'POST',
|
|
155
|
-
data: { name: termNameEscaped },
|
|
156
|
-
} )
|
|
157
|
-
.catch( ( error ) => {
|
|
158
|
-
const errorCode = error.code;
|
|
159
|
-
if ( errorCode === 'term_exists' ) {
|
|
160
|
-
// If the terms exist, fetch it instead of creating a new one.
|
|
161
|
-
this.addRequest = apiFetch( {
|
|
162
|
-
path: addQueryArgs( `/wp/v2/${ taxonomy.rest_base }`, {
|
|
163
|
-
...DEFAULT_QUERY,
|
|
164
|
-
search: termNameEscaped,
|
|
165
|
-
} ),
|
|
166
|
-
} ).then( unescapeTerms );
|
|
167
|
-
return this.addRequest.then( ( searchResult ) => {
|
|
168
|
-
return find( searchResult, ( result ) =>
|
|
169
|
-
isSameTermName( result.name, termName )
|
|
170
|
-
);
|
|
171
|
-
} );
|
|
172
|
-
}
|
|
173
|
-
return Promise.reject( error );
|
|
174
|
-
} )
|
|
175
|
-
.then( unescapeTerm );
|
|
200
|
+
function onUpdateTerms( newTermIds ) {
|
|
201
|
+
editPost( { [ taxonomy.rest_base ]: newTermIds } );
|
|
176
202
|
}
|
|
177
203
|
|
|
178
|
-
onChange( termNames ) {
|
|
204
|
+
function onChange( termNames ) {
|
|
205
|
+
const availableTerms = [ ...terms, ...( searchResults ?? [] ) ];
|
|
179
206
|
const uniqueTerms = uniqBy( termNames, ( term ) => term.toLowerCase() );
|
|
180
|
-
this.setState( { selectedTerms: uniqueTerms } );
|
|
181
207
|
const newTermNames = uniqueTerms.filter(
|
|
182
208
|
( termName ) =>
|
|
183
|
-
! find(
|
|
209
|
+
! find( availableTerms, ( term ) =>
|
|
184
210
|
isSameTermName( term.name, termName )
|
|
185
211
|
)
|
|
186
212
|
);
|
|
187
213
|
|
|
214
|
+
// Optimistically update term values.
|
|
215
|
+
// The selector will always re-fetch terms later.
|
|
216
|
+
setValues( uniqueTerms );
|
|
217
|
+
|
|
188
218
|
if ( newTermNames.length === 0 ) {
|
|
189
|
-
return
|
|
190
|
-
termNamesToIds( uniqueTerms,
|
|
191
|
-
this.props.taxonomy.rest_base
|
|
219
|
+
return onUpdateTerms(
|
|
220
|
+
termNamesToIds( uniqueTerms, availableTerms )
|
|
192
221
|
);
|
|
193
222
|
}
|
|
194
|
-
Promise.all( newTermNames.map( this.findOrCreateTerm ) ).then(
|
|
195
|
-
( newTerms ) => {
|
|
196
|
-
const newAvailableTerms = this.state.availableTerms.concat(
|
|
197
|
-
newTerms
|
|
198
|
-
);
|
|
199
|
-
this.setState( { availableTerms: newAvailableTerms } );
|
|
200
|
-
return this.props.onUpdateTerms(
|
|
201
|
-
termNamesToIds( uniqueTerms, newAvailableTerms ),
|
|
202
|
-
this.props.taxonomy.rest_base
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
223
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if ( search.length >= 3 ) {
|
|
211
|
-
this.searchRequest = this.fetchTerms( { search } );
|
|
224
|
+
if ( ! hasCreateAction ) {
|
|
225
|
+
return;
|
|
212
226
|
}
|
|
213
|
-
}
|
|
214
227
|
|
|
215
|
-
|
|
216
|
-
|
|
228
|
+
Promise.all(
|
|
229
|
+
newTermNames.map( ( termName ) =>
|
|
230
|
+
findOrCreateTerm( termName, taxonomy.rest_base )
|
|
231
|
+
)
|
|
232
|
+
).then( ( newTerms ) => {
|
|
233
|
+
const newAvailableTerms = availableTerms.concat( newTerms );
|
|
234
|
+
return onUpdateTerms(
|
|
235
|
+
termNamesToIds( uniqueTerms, newAvailableTerms )
|
|
236
|
+
);
|
|
237
|
+
} );
|
|
238
|
+
}
|
|
217
239
|
|
|
218
|
-
|
|
240
|
+
function appendTerm( newTerm ) {
|
|
241
|
+
if ( termIds.includes( newTerm.id ) ) {
|
|
219
242
|
return;
|
|
220
243
|
}
|
|
221
244
|
|
|
222
|
-
const
|
|
223
|
-
|
|
245
|
+
const newTermIds = [ ...termIds, newTerm.id ];
|
|
224
246
|
const termAddedMessage = sprintf(
|
|
225
247
|
/* translators: %s: term name. */
|
|
226
248
|
_x( '%s added', 'term' ),
|
|
@@ -232,109 +254,53 @@ class FlatTermSelector extends Component {
|
|
|
232
254
|
);
|
|
233
255
|
|
|
234
256
|
speak( termAddedMessage, 'assertive' );
|
|
235
|
-
|
|
236
|
-
this.setState( {
|
|
237
|
-
availableTerms: [ ...this.state.availableTerms, newTerm ],
|
|
238
|
-
} );
|
|
239
|
-
|
|
240
|
-
onUpdateTerms( newTerms, taxonomy.rest_base );
|
|
257
|
+
onUpdateTerms( newTermIds );
|
|
241
258
|
}
|
|
242
259
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
/* translators: %s: term name. */
|
|
269
|
-
_x( '%s removed', 'term' ),
|
|
270
|
-
singularName
|
|
271
|
-
);
|
|
272
|
-
const removeTermLabel = sprintf(
|
|
273
|
-
/* translators: %s: term name. */
|
|
274
|
-
_x( 'Remove %s', 'term' ),
|
|
275
|
-
singularName
|
|
276
|
-
);
|
|
260
|
+
const newTermLabel = get(
|
|
261
|
+
taxonomy,
|
|
262
|
+
[ 'labels', 'add_new_item' ],
|
|
263
|
+
slug === 'post_tag' ? __( 'Add new tag' ) : __( 'Add new Term' )
|
|
264
|
+
);
|
|
265
|
+
const singularName = get(
|
|
266
|
+
taxonomy,
|
|
267
|
+
[ 'labels', 'singular_name' ],
|
|
268
|
+
slug === 'post_tag' ? __( 'Tag' ) : __( 'Term' )
|
|
269
|
+
);
|
|
270
|
+
const termAddedLabel = sprintf(
|
|
271
|
+
/* translators: %s: term name. */
|
|
272
|
+
_x( '%s added', 'term' ),
|
|
273
|
+
singularName
|
|
274
|
+
);
|
|
275
|
+
const termRemovedLabel = sprintf(
|
|
276
|
+
/* translators: %s: term name. */
|
|
277
|
+
_x( '%s removed', 'term' ),
|
|
278
|
+
singularName
|
|
279
|
+
);
|
|
280
|
+
const removeTermLabel = sprintf(
|
|
281
|
+
/* translators: %s: term name. */
|
|
282
|
+
_x( 'Remove %s', 'term' ),
|
|
283
|
+
singularName
|
|
284
|
+
);
|
|
277
285
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
onSelect={ this.appendTerm }
|
|
297
|
-
/>
|
|
298
|
-
</>
|
|
299
|
-
);
|
|
300
|
-
}
|
|
286
|
+
return (
|
|
287
|
+
<>
|
|
288
|
+
<FormTokenField
|
|
289
|
+
value={ values }
|
|
290
|
+
suggestions={ suggestions }
|
|
291
|
+
onChange={ onChange }
|
|
292
|
+
onInputChange={ debouncedSearch }
|
|
293
|
+
maxSuggestions={ MAX_TERMS_SUGGESTIONS }
|
|
294
|
+
label={ newTermLabel }
|
|
295
|
+
messages={ {
|
|
296
|
+
added: termAddedLabel,
|
|
297
|
+
removed: termRemovedLabel,
|
|
298
|
+
remove: removeTermLabel,
|
|
299
|
+
} }
|
|
300
|
+
/>
|
|
301
|
+
<MostUsedTerms taxonomy={ taxonomy } onSelect={ appendTerm } />
|
|
302
|
+
</>
|
|
303
|
+
);
|
|
301
304
|
}
|
|
302
305
|
|
|
303
|
-
export default
|
|
304
|
-
withSelect( ( select, { slug } ) => {
|
|
305
|
-
const { getCurrentPost } = select( editorStore );
|
|
306
|
-
const { getTaxonomy } = select( coreStore );
|
|
307
|
-
const taxonomy = getTaxonomy( slug );
|
|
308
|
-
return {
|
|
309
|
-
hasCreateAction: taxonomy
|
|
310
|
-
? get(
|
|
311
|
-
getCurrentPost(),
|
|
312
|
-
[ '_links', 'wp:action-create-' + taxonomy.rest_base ],
|
|
313
|
-
false
|
|
314
|
-
)
|
|
315
|
-
: false,
|
|
316
|
-
hasAssignAction: taxonomy
|
|
317
|
-
? get(
|
|
318
|
-
getCurrentPost(),
|
|
319
|
-
[ '_links', 'wp:action-assign-' + taxonomy.rest_base ],
|
|
320
|
-
false
|
|
321
|
-
)
|
|
322
|
-
: false,
|
|
323
|
-
terms: taxonomy
|
|
324
|
-
? select( editorStore ).getEditedPostAttribute(
|
|
325
|
-
taxonomy.rest_base
|
|
326
|
-
)
|
|
327
|
-
: [],
|
|
328
|
-
taxonomy,
|
|
329
|
-
};
|
|
330
|
-
} ),
|
|
331
|
-
withDispatch( ( dispatch ) => {
|
|
332
|
-
return {
|
|
333
|
-
onUpdateTerms( terms, restBase ) {
|
|
334
|
-
dispatch( editorStore ).editPost( { [ restBase ]: terms } );
|
|
335
|
-
},
|
|
336
|
-
};
|
|
337
|
-
} ),
|
|
338
|
-
withSpokenMessages,
|
|
339
|
-
withFilters( 'editor.PostTaxonomyType' )
|
|
340
|
-
)( FlatTermSelector );
|
|
306
|
+
export default withFilters( 'editor.PostTaxonomyType' )( FlatTermSelector );
|
|
@@ -61,7 +61,7 @@ export default function PostTitle() {
|
|
|
61
61
|
isFocusMode: focusMode,
|
|
62
62
|
hasFixedToolbar: _hasFixedToolbar,
|
|
63
63
|
};
|
|
64
|
-
} );
|
|
64
|
+
}, [] );
|
|
65
65
|
|
|
66
66
|
useEffect( () => {
|
|
67
67
|
if ( ! ref.current ) {
|
|
@@ -199,7 +199,7 @@ export default function PostTitle() {
|
|
|
199
199
|
preserveWhiteSpace: true,
|
|
200
200
|
} );
|
|
201
201
|
|
|
202
|
-
/* eslint-disable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-
|
|
202
|
+
/* eslint-disable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
|
|
203
203
|
return (
|
|
204
204
|
<PostTypeSupportCheck supportKeys="title">
|
|
205
205
|
<h1
|
|
@@ -207,6 +207,8 @@ export default function PostTitle() {
|
|
|
207
207
|
contentEditable
|
|
208
208
|
className={ className }
|
|
209
209
|
aria-label={ decodedPlaceholder }
|
|
210
|
+
role="textbox"
|
|
211
|
+
aria-multiline="true"
|
|
210
212
|
onFocus={ onSelect }
|
|
211
213
|
onBlur={ onUnselect }
|
|
212
214
|
onKeyDown={ onKeyDown }
|
|
@@ -215,5 +217,5 @@ export default function PostTitle() {
|
|
|
215
217
|
/>
|
|
216
218
|
</PostTypeSupportCheck>
|
|
217
219
|
);
|
|
218
|
-
/* eslint-enable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-
|
|
220
|
+
/* eslint-enable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
|
|
219
221
|
}
|
|
@@ -92,6 +92,7 @@ class NativeEditorProvider extends Component {
|
|
|
92
92
|
componentDidMount() {
|
|
93
93
|
const {
|
|
94
94
|
capabilities,
|
|
95
|
+
locale,
|
|
95
96
|
updateSettings,
|
|
96
97
|
galleryWithImageBlocks,
|
|
97
98
|
} = this.props;
|
|
@@ -100,6 +101,7 @@ class NativeEditorProvider extends Component {
|
|
|
100
101
|
...capabilities,
|
|
101
102
|
...{ __unstableGalleryWithImageBlocks: galleryWithImageBlocks },
|
|
102
103
|
...this.getThemeColors( this.props ),
|
|
104
|
+
locale,
|
|
103
105
|
} );
|
|
104
106
|
|
|
105
107
|
this.subscriptionParentGetHtml = subscribeParentGetHtml( () => {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
__experimentalFetchLinkSuggestions as fetchLinkSuggestions,
|
|
14
14
|
__experimentalFetchUrlData as fetchUrlData,
|
|
15
15
|
} from '@wordpress/core-data';
|
|
16
|
+
import { __ } from '@wordpress/i18n';
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Internal dependencies
|
|
@@ -33,6 +34,7 @@ function useBlockEditorSettings( settings, hasTemplate ) {
|
|
|
33
34
|
reusableBlocks,
|
|
34
35
|
hasUploadPermissions,
|
|
35
36
|
canUseUnfilteredHTML,
|
|
37
|
+
userCanCreatePages,
|
|
36
38
|
} = useSelect( ( select ) => {
|
|
37
39
|
const { canUserUseUnfilteredHTML } = select( editorStore );
|
|
38
40
|
const isWeb = Platform.OS === 'web';
|
|
@@ -61,11 +63,30 @@ function useBlockEditorSettings( settings, hasTemplate ) {
|
|
|
61
63
|
),
|
|
62
64
|
hasResolvedLocalSiteData: hasFinishedResolvingSiteData,
|
|
63
65
|
baseUrl: siteData?.url || '',
|
|
66
|
+
userCanCreatePages: canUser( 'create', 'pages' ),
|
|
64
67
|
};
|
|
65
68
|
}, [] );
|
|
66
69
|
|
|
67
70
|
const { undo } = useDispatch( editorStore );
|
|
68
71
|
|
|
72
|
+
const { saveEntityRecord } = useDispatch( coreStore );
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates a Post entity.
|
|
76
|
+
* This is utilised by the Link UI to allow for on-the-fly creation of Posts/Pages.
|
|
77
|
+
*
|
|
78
|
+
* @param {Object} options parameters for the post being created. These mirror those used on 3rd param of saveEntityRecord.
|
|
79
|
+
* @return {Object} the post type object that was created.
|
|
80
|
+
*/
|
|
81
|
+
const createPageEntity = ( options ) => {
|
|
82
|
+
if ( ! userCanCreatePages ) {
|
|
83
|
+
return Promise.reject( {
|
|
84
|
+
message: __( 'You do not have permission to create Pages.' ),
|
|
85
|
+
} );
|
|
86
|
+
}
|
|
87
|
+
return saveEntityRecord( 'postType', 'page', options );
|
|
88
|
+
};
|
|
89
|
+
|
|
69
90
|
return useMemo(
|
|
70
91
|
() => ( {
|
|
71
92
|
...pick( settings, [
|
|
@@ -73,8 +94,6 @@ function useBlockEditorSettings( settings, hasTemplate ) {
|
|
|
73
94
|
'__experimentalBlockPatternCategories',
|
|
74
95
|
'__experimentalBlockPatterns',
|
|
75
96
|
'__experimentalFeatures',
|
|
76
|
-
'__experimentalGlobalStylesBaseStyles',
|
|
77
|
-
'__experimentalGlobalStylesUserEntityId',
|
|
78
97
|
'__experimentalPreferredStyleVariations',
|
|
79
98
|
'__experimentalSetIsInserterOpened',
|
|
80
99
|
'__unstableGalleryWithImageBlocks',
|
|
@@ -117,6 +136,8 @@ function useBlockEditorSettings( settings, hasTemplate ) {
|
|
|
117
136
|
__experimentalCanUserUseUnfilteredHTML: canUseUnfilteredHTML,
|
|
118
137
|
__experimentalUndo: undo,
|
|
119
138
|
outlineMode: hasTemplate,
|
|
139
|
+
__experimentalCreatePageEntity: createPageEntity,
|
|
140
|
+
__experimentalUserCanCreatePages: userCanCreatePages,
|
|
120
141
|
} ),
|
|
121
142
|
[
|
|
122
143
|
settings,
|
|
@@ -125,6 +146,7 @@ function useBlockEditorSettings( settings, hasTemplate ) {
|
|
|
125
146
|
canUseUnfilteredHTML,
|
|
126
147
|
undo,
|
|
127
148
|
hasTemplate,
|
|
149
|
+
userCanCreatePages,
|
|
128
150
|
]
|
|
129
151
|
);
|
|
130
152
|
}
|
|
@@ -11,8 +11,9 @@ import { count as wordCount } from '@wordpress/wordcount';
|
|
|
11
11
|
import { store as editorStore } from '../../store';
|
|
12
12
|
|
|
13
13
|
export default function WordCount() {
|
|
14
|
-
const content = useSelect(
|
|
15
|
-
select( editorStore ).getEditedPostAttribute( 'content' )
|
|
14
|
+
const content = useSelect(
|
|
15
|
+
( select ) => select( editorStore ).getEditedPostAttribute( 'content' ),
|
|
16
|
+
[]
|
|
16
17
|
);
|
|
17
18
|
|
|
18
19
|
/*
|