@wordpress/editor 12.0.0 → 12.0.4
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/build/components/autosave-monitor/index.js +5 -0
- package/build/components/autosave-monitor/index.js.map +1 -1
- package/build/components/editor-help/index.native.js +4 -3
- 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/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 +4 -2
- package/build/components/post-title/index.js.map +1 -1
- package/build/components/provider/use-block-editor-settings.js +1 -1
- package/build/components/provider/use-block-editor-settings.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/utils/get-template-part-icon.js +1 -1
- package/build/utils/get-template-part-icon.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/editor-help/index.native.js +5 -4
- 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/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 +4 -2
- package/build-module/components/post-title/index.js.map +1 -1
- package/build-module/components/provider/use-block-editor-settings.js +1 -1
- package/build-module/components/provider/use-block-editor-settings.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/utils/get-template-part-icon.js +2 -2
- package/build-module/utils/get-template-part-icon.js.map +1 -1
- package/build-style/style-rtl.css +1 -1
- package/build-style/style.css +1 -1
- package/package.json +19 -19
- package/src/components/autosave-monitor/index.js +5 -0
- package/src/components/autosave-monitor/test/index.js +10 -4
- package/src/components/editor-help/index.native.js +116 -106
- package/src/components/editor-help/style.scss +4 -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/post-saved-state/style.scss +2 -0
- package/src/components/post-taxonomies/flat-term-selector.js +220 -254
- package/src/components/post-title/index.js +4 -2
- package/src/components/provider/use-block-editor-settings.js +0 -2
- 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/utils/get-template-part-icon.js +2 -2
|
@@ -19,7 +19,7 @@ import { close as closeIcon } from '@wordpress/icons';
|
|
|
19
19
|
*/
|
|
20
20
|
import EntityTypeList from './entity-type-list';
|
|
21
21
|
|
|
22
|
-
const
|
|
22
|
+
const TRANSLATED_SITE_PROPERTIES = {
|
|
23
23
|
title: __( 'Title' ),
|
|
24
24
|
description: __( 'Tagline' ),
|
|
25
25
|
site_logo: __( 'Logo' ),
|
|
@@ -27,6 +27,13 @@ const TRANSLATED_SITE_PROTPERTIES = {
|
|
|
27
27
|
page_on_front: __( 'Page on front' ),
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
const PUBLISH_ON_SAVE_ENTITIES = [
|
|
31
|
+
{
|
|
32
|
+
kind: 'postType',
|
|
33
|
+
name: 'wp_navigation',
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
30
37
|
export default function EntitiesSavedStates( { close } ) {
|
|
31
38
|
const saveButtonRef = useRef();
|
|
32
39
|
const { dirtyEntityRecords } = useSelect( ( select ) => {
|
|
@@ -49,7 +56,7 @@ export default function EntitiesSavedStates( { close } ) {
|
|
|
49
56
|
siteEditsAsEntities.push( {
|
|
50
57
|
kind: 'root',
|
|
51
58
|
name: 'site',
|
|
52
|
-
title:
|
|
59
|
+
title: TRANSLATED_SITE_PROPERTIES[ property ] || property,
|
|
53
60
|
property,
|
|
54
61
|
} );
|
|
55
62
|
}
|
|
@@ -63,14 +70,27 @@ export default function EntitiesSavedStates( { close } ) {
|
|
|
63
70
|
};
|
|
64
71
|
}, [] );
|
|
65
72
|
const {
|
|
73
|
+
editEntityRecord,
|
|
66
74
|
saveEditedEntityRecord,
|
|
67
75
|
__experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits,
|
|
68
76
|
} = useDispatch( coreStore );
|
|
69
77
|
|
|
70
78
|
// To group entities by type.
|
|
71
|
-
const partitionedSavables =
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
const partitionedSavables = groupBy( dirtyEntityRecords, 'name' );
|
|
80
|
+
|
|
81
|
+
// Sort entity groups.
|
|
82
|
+
const {
|
|
83
|
+
site: siteSavables,
|
|
84
|
+
wp_template: templateSavables,
|
|
85
|
+
wp_template_part: templatePartSavables,
|
|
86
|
+
...contentSavables
|
|
87
|
+
} = partitionedSavables;
|
|
88
|
+
const sortedPartitionedSavables = [
|
|
89
|
+
siteSavables,
|
|
90
|
+
templateSavables,
|
|
91
|
+
templatePartSavables,
|
|
92
|
+
...Object.values( contentSavables ),
|
|
93
|
+
].filter( Array.isArray );
|
|
74
94
|
|
|
75
95
|
// Unchecked entities to be ignored by save function.
|
|
76
96
|
const [ unselectedEntities, _setUnselectedEntities ] = useState( [] );
|
|
@@ -118,6 +138,16 @@ export default function EntitiesSavedStates( { close } ) {
|
|
|
118
138
|
if ( 'root' === kind && 'site' === name ) {
|
|
119
139
|
siteItemsToSave.push( property );
|
|
120
140
|
} else {
|
|
141
|
+
if (
|
|
142
|
+
PUBLISH_ON_SAVE_ENTITIES.some(
|
|
143
|
+
( typeToPublish ) =>
|
|
144
|
+
typeToPublish.kind === kind &&
|
|
145
|
+
typeToPublish.name === name
|
|
146
|
+
)
|
|
147
|
+
) {
|
|
148
|
+
editEntityRecord( kind, name, key, { status: 'publish' } );
|
|
149
|
+
}
|
|
150
|
+
|
|
121
151
|
saveEditedEntityRecord( kind, name, key );
|
|
122
152
|
}
|
|
123
153
|
} );
|
|
@@ -160,15 +190,15 @@ export default function EntitiesSavedStates( { close } ) {
|
|
|
160
190
|
</div>
|
|
161
191
|
|
|
162
192
|
<div className="entities-saved-states__text-prompt">
|
|
163
|
-
<strong>{ __( '
|
|
193
|
+
<strong>{ __( 'Are you ready to save?' ) }</strong>
|
|
164
194
|
<p>
|
|
165
195
|
{ __(
|
|
166
|
-
'
|
|
196
|
+
'The following changes have been made to your site, templates, and content.'
|
|
167
197
|
) }
|
|
168
198
|
</p>
|
|
169
199
|
</div>
|
|
170
200
|
|
|
171
|
-
{
|
|
201
|
+
{ sortedPartitionedSavables.map( ( list ) => {
|
|
172
202
|
return (
|
|
173
203
|
<EntityTypeList
|
|
174
204
|
key={ list[ 0 ].name }
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
white-space: nowrap;
|
|
9
9
|
|
|
10
10
|
// The disabled version of the save state should be legible as an indicator.
|
|
11
|
+
&.is-saving[aria-disabled="true"],
|
|
12
|
+
&.is-saving[aria-disabled="true"]:hover,
|
|
11
13
|
&.is-saved[aria-disabled="true"],
|
|
12
14
|
&.is-saved[aria-disabled="true"]:hover {
|
|
13
15
|
background: transparent;
|
|
@@ -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 );
|
|
@@ -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
|
}
|
|
@@ -94,8 +94,6 @@ function useBlockEditorSettings( settings, hasTemplate ) {
|
|
|
94
94
|
'__experimentalBlockPatternCategories',
|
|
95
95
|
'__experimentalBlockPatterns',
|
|
96
96
|
'__experimentalFeatures',
|
|
97
|
-
'__experimentalGlobalStylesBaseStyles',
|
|
98
|
-
'__experimentalGlobalStylesUserEntityId',
|
|
99
97
|
'__experimentalPreferredStyleVariations',
|
|
100
98
|
'__experimentalSetIsInserterOpened',
|
|
101
99
|
'__unstableGalleryWithImageBlocks',
|