PluginProbe
Extendify / trunk
Extendify vtrunk
3.2.1 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 All 127 releases
← All changes | src/Agent/lib/subtree-manifest.js +27 -16 3.1.5 → trunk View file →
@@ -1,9 +1,8 @@
1 +import { BLOCK_ID_SEL, blockIdOf } from './block-el';
1 2 import { detectBlockType } from './block-type';
2 3 import { readComputedStyles } from './computed-styles';
3 4
4 -const BLOCK_ID_ATTR = 'data-extendify-agent-block-id';
5 -
6 5 // Signal-less but edit targets ("swap the columns", "round the image") — dropped, they're unaddressable.
7 6 const ALWAYS_KEPT_TYPES = new Set([
8 7 'core/column',
9 8 'core/columns',
@@ -51,13 +50,21 @@
51 50 }
52 51 return null;
53 52 };
54 53
54 +const PART_SLUG_ATTR = 'data-extendify-part-slug';
55 +
56 +// One request carries one partSlug, so a nested part's blocks would resolve
57 +// against the wrong post.
58 +const partScope = (root) => {
59 + const rootSlug = root?.getAttribute?.(PART_SLUG_ATTR) ?? null;
60 + return (el) => (el?.getAttribute?.(PART_SLUG_ATTR) ?? null) === rootSlug;
61 +};
62 +
55 63 // Stops at nested tagged blocks so a container's text never bleeds from its children.
56 64 const ownSubtree = (el) => {
57 65 const clone = el.cloneNode(true);
58 - for (const nested of clone.querySelectorAll(`[${BLOCK_ID_ATTR}]`))
59 - nested.remove();
66 + for (const nested of clone.querySelectorAll(BLOCK_ID_SEL)) nested.remove();
60 67 return clone;
61 68 };
62 69
63 70 const ownText = (clone) => {
@@ -85,12 +92,14 @@
85 92 // targets ("the red button"); schemas + full code are fetched after the pick.
86 93 export const buildSubtreeManifest = (root) => {
87 94 if (!root) return [];
88 95 const manifest = [];
96 + const inScope = partScope(root);
89 97 // A directly-selected block is its own (and only) target, so the root is included.
90 - const els = [root, ...root.querySelectorAll(`[${BLOCK_ID_ATTR}]`)];
98 + const els = [root, ...root.querySelectorAll(BLOCK_ID_SEL)].filter(inScope);
91 99 for (const [index, el] of els.entries()) {
92 - if (!el.getAttribute?.(BLOCK_ID_ATTR)) continue;
100 + const blockId = blockIdOf(el);
101 + if (!blockId) continue;
93 102 const type = detectBlockType(el);
94 103 if (!type) continue;
95 104 const clone = ownSubtree(el);
96 105 const text = ownText(clone);
@@ -106,9 +115,9 @@
106 115 continue;
107 116 const styles = renderedStyles(el);
108 117 const css = customCss(el);
109 118 manifest.push({
110 - blockId: el.getAttribute(BLOCK_ID_ATTR),
119 + blockId,
111 120 type,
112 121 ...(text && { text }),
113 122 ...colors,
114 123 ...(styles && { styles }),
@@ -118,26 +127,28 @@
118 127 return manifest;
119 128 };
120 129
121 130 // Tagged blocks directly beneath el, past any untagged wrappers.
122 -const childBlockEls = (el) => {
131 +const childBlockEls = (el, inScope) => {
123 132 const out = [];
124 133 for (const child of el.children ?? []) {
125 - if (child.getAttribute?.(BLOCK_ID_ATTR)) out.push(child);
126 - else out.push(...childBlockEls(child));
134 + if (!inScope(child)) continue;
135 + if (blockIdOf(child)) out.push(child);
136 + else out.push(...childBlockEls(child, inScope));
127 137 }
128 138 return out;
129 139 };
130 140
131 141 // Keeps every tagged block; the flat manifest drops signal-less ones.
132 -const treeNodesFor = (el) =>
133 - childBlockEls(el).flatMap((child) => {
142 +const treeNodesFor = (el, inScope) =>
143 + childBlockEls(el, inScope).flatMap((child) => {
134 144 const type = detectBlockType(child);
135 - const children = treeNodesFor(child);
136 - if (!type || !child.getAttribute?.(BLOCK_ID_ATTR)) return children;
145 + const children = treeNodesFor(child, inScope);
146 + const blockId = blockIdOf(child);
147 + if (!type || !blockId) return children;
137 148 return [
138 149 {
139 - blockId: child.getAttribute(BLOCK_ID_ATTR),
150 + blockId,
140 151 type,
141 152 ...(children.length && { children }),
142 153 },
143 154 ];
@@ -144,5 +155,5 @@
144 155 });
145 156
146 157 // Nested block structure for the selection.
147 158 export const buildSubtreeTree = (root) =>
148 - root ? treeNodesFor({ children: [root] }) : [];
159 + root ? treeNodesFor({ children: [root] }, partScope(root)) : [];