PluginProbe
Extendify / 3.1.4
Extendify v3.1.4
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / src / Agent / lib / insertable-blocks.js

insertable-blocks.js in Extendify 3.1.4, at src/Agent/lib/insertable-blocks.js

106 lines 3.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { applyBlockPatch } from '@agent/lib/block-patch';
2 import { createBlock, getBlockType, parse, serialize } from '@wordpress/blocks';
3
4 // The add catalog the backend prompt offers — the plugin constrains it, not
5 // the backend, so old fielded builds never see types they can't build.
6 export const INSERTABLE_BLOCK_TYPES = [
7 'core/button',
8 'core/heading',
9 'core/paragraph',
10 'core/list',
11 'core/quote',
12 'core/pullquote',
13 'core/code',
14 'core/preformatted',
15 'core/verse',
16 'core/group',
17 'core/column',
18 'core/spacer',
19 'core/separator',
20 ];
21
22 // One level of explicit children, on containers only.
23 const CHILD_BEARING_TYPES = ['core/group', 'core/column'];
24
25 // The model authors `text`; each type stores it under its own attribute.
26 const RICH_TEXT_ATTR = {
27 'core/button': 'text',
28 'core/heading': 'content',
29 'core/paragraph': 'content',
30 'core/pullquote': 'value',
31 'core/code': 'content',
32 'core/preformatted': 'content',
33 'core/verse': 'content',
34 };
35
36 const paragraphChildren = (text) =>
37 text ? [createBlock('core/paragraph', { content: text })] : [];
38
39 // A bare column is only valid inside core/columns, so it can't be a child.
40 const childBlocks = (children) =>
41 (children ?? [])
42 .filter(
43 ({ blockType }) =>
44 blockType !== 'core/column' &&
45 INSERTABLE_BLOCK_TYPES.includes(blockType) &&
46 getBlockType(blockType),
47 )
48 .map(({ blockType, text }) =>
49 blockType === 'core/button'
50 ? createBlock('core/buttons', {}, [freshBlock('core/button', text)])
51 : freshBlock(blockType, text),
52 );
53
54 const freshBlock = (blockType, text, children = []) => {
55 if (blockType === 'core/list') {
56 // The model sometimes authors <li> markup despite the plain-text
57 // instruction; splitting on it beats an empty leading item.
58 const items = String(text ?? '')
59 .replaceAll(/<\/?li[^>]*>/gi, '\n')
60 .split('\n')
61 .map((line) => line.trim())
62 .filter(Boolean);
63 return createBlock(
64 'core/list',
65 {},
66 items.map((content) => createBlock('core/list-item', { content })),
67 );
68 }
69 if (CHILD_BEARING_TYPES.includes(blockType)) {
70 const composed = childBlocks(children);
71 return createBlock(
72 blockType,
73 {},
74 composed.length ? composed : paragraphChildren(text),
75 );
76 }
77 // Quote holds its text as a paragraph child, not an attribute.
78 if (blockType === 'core/quote')
79 return createBlock(blockType, {}, paragraphChildren(text));
80 const attribute = RICH_TEXT_ATTR[blockType];
81 return createBlock(
82 blockType,
83 attribute && text != null ? { [attribute]: text } : {},
84 );
85 };
86
87 export const buildNewBlock = (
88 blockType,
89 patch = {},
90 clear = [],
91 presetSlugs = {},
92 ) => {
93 if (!INSERTABLE_BLOCK_TYPES.includes(blockType)) return null;
94 if (!getBlockType(blockType)) return null;
95 const { text, children, ...attributePatch } = patch ?? {};
96 const markup = applyBlockPatch(
97 serialize([freshBlock(blockType, text, children ?? [])]),
98 attributePatch,
99 clear ?? [],
100 presetSlugs,
101 );
102 if (blockType !== 'core/button') return markup;
103 // A lone button never exists in the editor; ship it inside its wrapper.
104 return serialize([createBlock('core/buttons', {}, parse(markup))]);
105 };
106