mhsdesign/liveinspectorjsevents

在 Inspector 变化时发送 JsEvents 到 iframe

安装次数: 2,537

依赖项: 2

建议者: 0

安全性: 0

星标: 5

关注者: 1

分支: 2

开放问题: 2

语言:JavaScript

类型:neos-package

2.0.3 2024-07-29 09:20 UTC

This package is auto-updated.

Last update: 2024-08-29 09:33:23 UTC


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);