| 1 |
/** |
| 2 |
* ZipWP MCP — Vibe Editing v2: shared editor utilities. |
| 3 |
* |
| 4 |
* The ONE source of truth for helpers the editor handlers (get-context, |
| 5 |
* apply-change, get/set-scripts, get/set-styles) need identically — so they can |
| 6 |
* never drift: |
| 7 |
* - currentPostId: the live post id from the editor store, with the same |
| 8 |
* null-guard. apply-change uses it for the two-tab post_id guard; |
| 9 |
* get-context returns it in the response. |
| 10 |
* - editorSelect / editorDispatch: the null-guarded `core/editor` store |
| 11 |
* select/dispatch accessors. styles read the editing session through these |
| 12 |
* (getEditedPostAttribute / editPost). |
| 13 |
* - currentMeta: the live post meta object from the session (or {}), the |
| 14 |
* read side of the session-scoped styles write. |
| 15 |
* - blockEditorSelect / blockEditorDispatch / rootClientId: the null-guarded |
| 16 |
* `core/block-editor` store accessors + the page root container's clientId. |
| 17 |
* get/set-scripts read/patch a block's `spectraCustomJS` attribute through |
| 18 |
* these (getBlockAttributes / updateBlockAttributes). |
| 19 |
* - bannedVisualAttrs / isBannedVisualAttr: the 8 GBS-banned per-block visual |
| 20 |
* styling props (style, *Color(Hover), boxShadow(Hover), styleAttributes) — |
| 21 |
* styling lives in `className` ONLY (the Spectra GBS JIT grammar). apply-change |
| 22 |
* strips them from an incoming attrs write; get-context omits them from the |
| 23 |
* authorable attr-keys it advertises. ONE list so the two can never drift |
| 24 |
* (mirrors Laravel's StrictAttrValidator). The 8 props are a sanctioned |
| 25 |
* constant, not an allowlist — every OTHER attr is decided by the registry. |
| 26 |
* |
| 27 |
* Dual-mode: attaches to window.zipwpEditorShared in the browser; CommonJS |
| 28 |
* export for jest. |
| 29 |
* |
| 30 |
* Load order: enqueued before the editor handlers in source mode |
| 31 |
* (react-manager.php) and concatenated ahead of handler.js in the production |
| 32 |
* grunt bundle (matches the `tools/**\/*-utils.js` glob). The handlers also |
| 33 |
* resolve it lazily at call time, so a missing global degrades consistently |
| 34 |
* (post id -> null = the two-tab guard no-ops, exactly as a null |
| 35 |
* getCurrentPostId() would). |
| 36 |
* |
| 37 |
* @package zip-ai |
| 38 |
*/ |
| 39 |
(function () { |
| 40 |
'use strict'; |
| 41 |
|
| 42 |
function editorSelect() { |
| 43 |
return (typeof window !== 'undefined' && window.wp && window.wp.data && window.wp.data.select) |
| 44 |
? window.wp.data.select('core/editor') |
| 45 |
: null; |
| 46 |
} |
| 47 |
|
| 48 |
function editorDispatch() { |
| 49 |
return (typeof window !== 'undefined' && window.wp && window.wp.data && window.wp.data.dispatch) |
| 50 |
? window.wp.data.dispatch('core/editor') |
| 51 |
: null; |
| 52 |
} |
| 53 |
|
| 54 |
function currentPostId() { |
| 55 |
var editor = editorSelect(); |
| 56 |
return editor && typeof editor.getCurrentPostId === 'function' |
| 57 |
? editor.getCurrentPostId() |
| 58 |
: null; |
| 59 |
} |
| 60 |
|
| 61 |
// The live post meta object from the editing session (or {} when absent) — |
| 62 |
// the read side of the session-scoped scripts/styles write. |
| 63 |
function currentMeta(sel) { |
| 64 |
var meta = sel && sel.getEditedPostAttribute ? sel.getEditedPostAttribute('meta') : null; |
| 65 |
return meta && typeof meta === 'object' ? meta : {}; |
| 66 |
} |
| 67 |
|
| 68 |
// The null-guarded `core/block-editor` store — the read/write side of a |
| 69 |
// block's attributes (get/set-scripts operate on `spectraCustomJS`, an attr). |
| 70 |
// Edits through it are inherently session-scoped: in-memory now, persisted on |
| 71 |
// Save, discarded with the session (same model apply-change uses). |
| 72 |
function blockEditorSelect() { |
| 73 |
return (typeof window !== 'undefined' && window.wp && window.wp.data && window.wp.data.select) |
| 74 |
? window.wp.data.select('core/block-editor') |
| 75 |
: null; |
| 76 |
} |
| 77 |
function blockEditorDispatch() { |
| 78 |
return (typeof window !== 'undefined' && window.wp && window.wp.data && window.wp.data.dispatch) |
| 79 |
? window.wp.data.dispatch('core/block-editor') |
| 80 |
: null; |
| 81 |
} |
| 82 |
|
| 83 |
// The page root container's clientId — the first top-level block — the |
| 84 |
// default owner for page-wide JS when no clientId is passed. null when the |
| 85 |
// tree is empty or the store is absent. |
| 86 |
function rootClientId(sel) { |
| 87 |
var order = sel && sel.getBlockOrder ? sel.getBlockOrder() : null; |
| 88 |
return Array.isArray(order) && order.length > 0 ? order[0] : null; |
| 89 |
} |
| 90 |
|
| 91 |
// The 8 GBS-banned per-block visual styling props. Per-block styling lives in |
| 92 |
// `className` ONLY (the Spectra GBS JIT grammar); these are never authorable |
| 93 |
// attrs even when a block's registry declares them. A sanctioned constant — |
| 94 |
// every OTHER attribute's validity is decided by the registry (getBlockType). |
| 95 |
var bannedVisualAttrs = [ |
| 96 |
'style', 'styleAttributes', |
| 97 |
'backgroundColor', 'backgroundColorHover', |
| 98 |
'boxShadow', 'boxShadowHover', |
| 99 |
'textColor', 'textColorHover', |
| 100 |
]; |
| 101 |
function isBannedVisualAttr(key) { |
| 102 |
return bannedVisualAttrs.indexOf(key) !== -1; |
| 103 |
} |
| 104 |
|
| 105 |
if (typeof window !== 'undefined') { |
| 106 |
window.zipwpEditorShared = window.zipwpEditorShared || {}; |
| 107 |
window.zipwpEditorShared.currentPostId = currentPostId; |
| 108 |
window.zipwpEditorShared.editorSelect = editorSelect; |
| 109 |
window.zipwpEditorShared.editorDispatch = editorDispatch; |
| 110 |
window.zipwpEditorShared.currentMeta = currentMeta; |
| 111 |
window.zipwpEditorShared.blockEditorSelect = blockEditorSelect; |
| 112 |
window.zipwpEditorShared.blockEditorDispatch = blockEditorDispatch; |
| 113 |
window.zipwpEditorShared.rootClientId = rootClientId; |
| 114 |
window.zipwpEditorShared.bannedVisualAttrs = bannedVisualAttrs; |
| 115 |
window.zipwpEditorShared.isBannedVisualAttr = isBannedVisualAttr; |
| 116 |
} |
| 117 |
if (typeof module !== 'undefined' && module.exports) { |
| 118 |
module.exports = { |
| 119 |
currentPostId: currentPostId, |
| 120 |
editorSelect: editorSelect, |
| 121 |
editorDispatch: editorDispatch, |
| 122 |
currentMeta: currentMeta, |
| 123 |
blockEditorSelect: blockEditorSelect, |
| 124 |
blockEditorDispatch: blockEditorDispatch, |
| 125 |
rootClientId: rootClientId, |
| 126 |
bannedVisualAttrs: bannedVisualAttrs, |
| 127 |
isBannedVisualAttr: isBannedVisualAttr, |
| 128 |
}; |
| 129 |
} |
| 130 |
})(); |
| 131 |
|