mhsdesign / liveinspectorjsevents
在 Inspector 变化时发送 JsEvents 到 iframe
2.0.3
2024-07-29 09:20 UTC
Requires
- neos/neos-ui: ^8.0
README
Neos UI 插件,用于在 iframe 中处理 Inspector 变化事件。
演示
demo-live-change-neos.mp4
安装
composer require "mhsdesign/liveinspectorjsevents:~2.0.0"
自实现实现的教程
更改间距的类到其属性值
你的 yaml
一个基本的(独立)nodeType yaml 配置,包含一个选择框
'MhsDesign.LiveInspectorDemo:Content.Spacer': superTypes: 'Neos.Neos:Content': true ui: icon: 'icon-internet-explorer' label: 'Example' # this will remove the Neos not inline editable overlay. inlineEditable: true inspector: groups: settings: label: 'Settings' properties: height: type: string ui: # not need to explicitly state it since its the default: # reloadIfChanged: false label: 'Height' inspector: group: settings editor: 'Neos.Neos/Inspector/Editors/SelectBoxEditor' editorOptions: allowEmpty: true values: # your css classes as key. height-sm: label: 'Small' height-md: label: 'Medium' height-lg: label: 'Large'
你的 fusion
prototype(MhsDesign.LiveInspectorDemo:Content.Spacer) < prototype(Neos.Neos:ContentComponent) {
height = ${q(node).property('height')}
renderer = afx`
<div class={['spacer', props.height]}></div>
`
}
你的 js
// all changers will be registered here: const changer = {} changer['MhsDesign.LiveInspectorDemo:Content.Spacer'] = (node, property) => { const {name, updated, previous} = property; /** type HTMLElement */ const el = neos.guestFrame.findElementByNode(node); switch (name) { case 'height': // sometimes the ui wraps an div around the html - sometimes not. const spacerDiv = querySelectClosest(el, '.spacer') if (previous !== '') { spacerDiv.classList.remove(previous) } if (updated !== '') { spacerDiv.classList.add(updated) } } } // call the changer defined for a node by nodeType const updateNode = (node, property) => { if (typeof changer[node.nodeType] !== "undefined") { changer[node.nodeType](node, property); } // alternative: // switch (node.nodeType) { // case 'MhsDesign.LiveInspectorDemo:Content.Spacer': // changeSpacer(node, property) // } } // register to the events document.addEventListener('Neos.NodeCommit', (event) => { const {node, property} = event.detail; updateNode(node, property) }) document.addEventListener('Neos.NodeDiscard', (event) => { const {node, properties} = event.detail; properties.forEach(property => { updateNode(node, property) }) }) // helper const querySelectClosest = (element, selector) => { if (element.matches(selector)) { return element; } return element.querySelector(selector) }
用法
监听事件(在 iframe 中)
document.addEventListener('Neos.NodeCommit', (event) => { const {node, property} = event.detail; // the updated property value and also the previous. // {name: 'title', updated: 'abcd', previous: 'abc'} console.log(property); // experimental: see below: console.log(neos.guestFrame.findElementByNode(node)); }) document.addEventListener('Neos.NodeDiscard', (event) => { const {node, properties} = event.detail; // all reset properties in a list. // [{name: 'title', updated: 'abc', previous: 'abcd'}] console.log(properties); })
Neos UI 中的 Javascript node
对象看起来像
node = { "identifier": "99257f0c-70f0-405b-a82b-fa8e375c23fb", "contextPath": "/sites/root/main/node-l461lxh2i1a77", "nodeType": "Vendor.Site:Content.Heading", ... "properties": { // also some private "_" properties ... like "_hidden" ... "title": "my String Old" } }
获取相应节点的 dom 元素
以下功能或处理方式是实验性的,可能会最终更改。
该包扩展了全局 window.neos
对象,并在 guestFrame
下公开此功能,这使得可以通过节点对象获取 dom 元素
neos.guestFrame.findElementByNode(node)
底层操作类似于:(但尽量避免直接使用以下片段,因为它最终使用的是纯内部知识。)
const findElementByNode = (node) => { const {contextPath} = node; // https://github.com/neos/neos-ui/blob/7ede460ec1bb8dd4455fc636b875c137d112e89d/packages/neos-ui-guest-frame/src/dom.js#L76 return document.querySelector(`[data-__neos-node-contextpath="${contextPath}"]`); }
内部
更多开发笔记(关于内部,而不是上面的事件)
有时安装 Redux DevTools 会很有帮助:https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=de
Neos UI 的 API。
// the commit action (when you change a property of a node) looks like: commitAction = { "type": "@neos/neos-ui/UI/Inspector/COMMIT", "payload": { "propertyId": "title", "value": "my String", ... "focusedNode": node, // we get something like in the node above } } } // when we dicard the changes, we wont know directly wich changes where made before. discardAction = { "type": "@neos/neos-ui/UI/Inspector/DISCARD", "payload": { "focusedNodeContextPath": "/sites/root/main/node-l461lxh2i1a77@user-mhs" // we can get all the node details from the CR via: // selectors.CR.Nodes.nodeByContextPath(state)(focusedNodeContextPath) } } // good to know, how to alway get the current node: const state = yield select(); const focusedNode = selectors.CR.Nodes.focusedSelector(state) // or const focusedNode = yield select(selectors.CR.Nodes.focusedSelector);