-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
index.js
146 lines (135 loc) · 3.85 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* External dependencies
*/
import { find } from 'lodash';
/**
* WordPress dependencies
*/
import {
createBlock,
findTransform,
getBlockTransforms,
getBlockType,
hasBlockSupport,
} from '@wordpress/blocks';
import { Button } from '@wordpress/components';
import { withSelect, withDispatch } from '@wordpress/data';
import { Warning } from '@wordpress/block-editor';
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import { compose, createHigherOrderComponent } from '@wordpress/compose';
const enhance = compose(
/**
* For blocks whose block type doesn't support `multiple`, provides the
* wrapped component with `originalBlockClientId` -- a reference to the
* first block of the same type in the content -- if and only if that
* "original" block is not the current one. Thus, an inexisting
* `originalBlockClientId` prop signals that the block is valid.
*
* @param {WPComponent} WrappedBlockEdit A filtered BlockEdit instance.
*
* @return {WPComponent} Enhanced component with merged state data props.
*/
withSelect( ( select, block ) => {
const multiple = hasBlockSupport( block.name, 'multiple', true );
// For block types with `multiple` support, there is no "original
// block" to be found in the content, as the block itself is valid.
if ( multiple ) {
return {};
}
// Otherwise, only pass `originalBlockClientId` if it refers to a different
// block from the current one.
const blocks = select( 'core/block-editor' ).getBlocks();
const firstOfSameType = find(
blocks,
( { name } ) => block.name === name
);
const isInvalid =
firstOfSameType && firstOfSameType.clientId !== block.clientId;
return {
originalBlockClientId: isInvalid && firstOfSameType.clientId,
};
} ),
withDispatch( ( dispatch, { originalBlockClientId } ) => ( {
selectFirst: () =>
dispatch( 'core/block-editor' ).selectBlock(
originalBlockClientId
),
} ) )
);
const withMultipleValidation = createHigherOrderComponent( ( BlockEdit ) => {
return enhance( ( { originalBlockClientId, selectFirst, ...props } ) => {
if ( ! originalBlockClientId ) {
return <BlockEdit { ...props } />;
}
const blockType = getBlockType( props.name );
const outboundType = getOutboundType( props.name );
return [
<div key="invalid-preview" style={ { minHeight: '60px' } }>
<BlockEdit key="block-edit" { ...props } />
</div>,
<Warning
key="multiple-use-warning"
actions={ [
<Button
key="find-original"
isSecondary
onClick={ selectFirst }
>
{ __( 'Find original' ) }
</Button>,
<Button
key="remove"
isSecondary
onClick={ () => props.onReplace( [] ) }
>
{ __( 'Remove' ) }
</Button>,
outboundType && (
<Button
key="transform"
isSecondary
onClick={ () =>
props.onReplace(
createBlock(
outboundType.name,
props.attributes
)
)
}
>
{ __( 'Transform into:' ) } { outboundType.title }
</Button>
),
] }
>
<strong>{ blockType.title }: </strong>
{ __( 'This block can only be used once.' ) }
</Warning>,
];
} );
}, 'withMultipleValidation' );
/**
* Given a base block name, returns the default block type to which to offer
* transforms.
*
* @param {string} blockName Base block name.
*
* @return {?Object} The chosen default block type.
*/
function getOutboundType( blockName ) {
// Grab the first outbound transform
const transform = findTransform(
getBlockTransforms( 'to', blockName ),
( { type, blocks } ) => type === 'block' && blocks.length === 1 // What about when .length > 1?
);
if ( ! transform ) {
return null;
}
return getBlockType( transform.blocks[ 0 ] );
}
addFilter(
'editor.BlockEdit',
'core/edit-post/validate-multiple-use/with-multiple-validation',
withMultipleValidation
);