| @@ -2,19 +2,44 @@ | ||
| 2 | 2 | // surfaces on blocks the agent's selector tool would have accepted — |
| 3 | 3 | // keeps the two selectors in lockstep until DOMHighlighter shrinks to |
| 4 | 4 | // a passive renderer. |
| 5 | 5 | const IGNORED_CLASS_RX = /^(wp-block-video|wp-block-spacer|wp-block-post-.*)$/; |
| 6 | -const TAGGED_INNER_SEL = | |
| 7 | - '[data-extendify-agent-block-id], [data-extendify-part-block-id], .wp-block-navigation'; | |
| 8 | -const MAX_INNER_TAGGED = 50; | |
| 6 | +// Self-rendering blocks: their inner tree is minted at render time (a loop per | |
| 7 | +// post, a cart drawer), so no id inside them exists in the tree a save walks. | |
| 8 | +// The server twin is TagTemplateParts::$ignored. | |
| 9 | +export const DYNAMIC_BLOCK_TYPES = new Set([ | |
| 10 | + 'core/query', | |
| 11 | + 'core/post-template', | |
| 12 | + 'core/post-content', | |
| 13 | + 'core/comments', | |
| 14 | + 'core/comment-template', | |
| 15 | + 'woocommerce/product-collection', | |
| 16 | + 'woocommerce/product-template', | |
| 17 | + 'woocommerce/mini-cart', | |
| 18 | + 'woocommerce/cart', | |
| 19 | + 'woocommerce/checkout', | |
| 20 | +]); | |
| 9 | 21 | |
| 22 | +// Core blocks drop their namespace in the rendered class; the rest keep it. | |
| 23 | +const classForBlock = (name) => | |
| 24 | + `wp-block-${name.startsWith('core/') ? name.slice(5) : name.replace('/', '-')}`; | |
| 25 | + | |
| 26 | +const DYNAMIC_BLOCK_SEL = [...DYNAMIC_BLOCK_TYPES] | |
| 27 | + .map((name) => `.${classForBlock(name)}`) | |
| 28 | + .join(', '); | |
| 29 | + | |
| 30 | +// Nothing in a loop item has an id, so the walk climbs out and hits the section. | |
| 31 | +export const escapesDynamicBlock = (fromEl, toEl) => { | |
| 32 | + const owner = fromEl?.closest?.(DYNAMIC_BLOCK_SEL); | |
| 33 | + return !!owner && !!toEl && !owner.contains(toEl); | |
| 34 | +}; | |
| 35 | + | |
| 10 | 36 | export const isAgentEligibleForTarget = (target) => { |
| 11 | 37 | const el = target?.el; |
| 12 | 38 | if (!el?.classList) return false; |
| 39 | + if (target?.dynamicInterior) return false; | |
| 40 | + if (DYNAMIC_BLOCK_TYPES.has(target?.blockType)) return false; | |
| 13 | 41 | for (const cls of el.classList) { |
| 14 | 42 | if (IGNORED_CLASS_RX.test(cls)) return false; |
| 15 | - } | |
| 16 | - if (el.querySelectorAll(TAGGED_INNER_SEL).length > MAX_INNER_TAGGED) { | |
| 17 | - return false; | |
| 18 | 43 | } |
| 19 | 44 | return true; |
| 20 | 45 | }; |