PluginProbe
Extendify / 3.2.2
Extendify v3.2.2
3.2.2 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 All 128 releases
← All changes | src/Agent/lib/subtree-manifest.js +45 -2 3.2.1 → 3.2.2 View file →
@@ -30,8 +30,18 @@
30 30 delete styles.backgroundColor;
31 31 return styles && Object.keys(styles).length ? styles : null;
32 32 };
33 33
34 +// "A bit smaller" needs the picture's rendered width; the wrapper's is the row's.
35 +const PICTURE_TYPES = new Set(['core/image', 'core/site-logo']);
36 +
37 +const pictureWidth = (el) => {
38 + const img = el.matches?.('img') ? el : el.querySelector?.('img');
39 + if (!img) return null;
40 + const width = img.ownerDocument.defaultView.getComputedStyle(img).width;
41 + return width && width !== 'auto' && width !== '0px' ? width : null;
42 +};
43 +
34 44 // style.css lives in a scoped `wp-custom-css-*` rule, invisible in the block code.
35 45 const customCss = (el) => {
36 46 const cls = [...(el.classList ?? [])].find((c) =>
37 47 c.startsWith('wp-custom-css-'),
@@ -67,9 +77,13 @@
67 77 return clone;
68 78 };
69 79
70 80 const ownText = (clone) => {
71 - const text = (clone.textContent || '').replace(/\s+/g, ' ').trim();
81 + const readable = clone.cloneNode(true);
82 + for (const hidden of readable.querySelectorAll('[aria-hidden="true"]')) {
83 + hidden.remove();
84 + }
85 + const text = (readable.textContent || '').replace(/\s+/g, ' ').trim();
72 86 return text.length > 80 ? `${text.slice(0, 80)}…` : text;
73 87 };
74 88
75 89 const colorSlugs = (clone) => {
@@ -87,8 +101,34 @@
87 101 }
88 102 return out;
89 103 };
90 104
105 +// Menu and icon colours live on the container, never the link that was clicked.
106 +// detectBlockType refuses these types so a click can't select the wrapper.
107 +const STYLE_OWNERS = [
108 + { selector: '.wp-block-navigation', type: 'core/navigation' },
109 + { selector: '.wp-block-social-links', type: 'core/social-links' },
110 +];
111 +
112 +export const ownerAncestorFor = (root) => {
113 + if (!root?.parentElement) return null;
114 + const inScope = partScope(root);
115 + for (const { selector, type } of STYLE_OWNERS) {
116 + const el = root.parentElement.closest(selector);
117 + if (!el || !inScope(el)) continue;
118 + const blockId = blockIdOf(el);
119 + if (!blockId) continue;
120 + const styles = renderedStyles(el);
121 + return {
122 + blockId,
123 + type,
124 + ...colorSlugs(ownSubtree(el)),
125 + ...(styles && { styles }),
126 + };
127 + }
128 + return null;
129 +};
130 +
91 131 // Per-block summary of the selection — enough context for the agent to pick
92 132 // targets ("the red button"); schemas + full code are fetched after the pick.
93 133 export const buildSubtreeManifest = (root) => {
94 134 if (!root) return [];
@@ -112,9 +152,12 @@
112 152 !colors.backgroundColor &&
113 153 !colors.textColor
114 154 )
115 155 continue;
116 - const styles = renderedStyles(el);
156 + const width = PICTURE_TYPES.has(type) ? pictureWidth(el) : null;
157 + const styles = width
158 + ? { ...renderedStyles(el), width }
159 + : renderedStyles(el);
117 160 const css = customCss(el);
118 161 manifest.push({
119 162 blockId,
120 163 type,