From 1d95f57bc43885e3ed3d36eefca1bf283130516e Mon Sep 17 00:00:00 2001 From: bartbutenaers Date: Thu, 9 Jan 2025 22:35:06 +0100 Subject: [PATCH] ui-switch sync issue --- docs/contributing/guides/registration.md | 11 +++++++++-- nodes/config/ui_base.js | 4 ++-- nodes/widgets/ui_switch.js | 8 ++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/contributing/guides/registration.md b/docs/contributing/guides/registration.md index 4ba9d8516..103975cc7 100644 --- a/docs/contributing/guides/registration.md +++ b/docs/contributing/guides/registration.md @@ -100,7 +100,8 @@ Similar to `onAction`, when used as a boolean, this flag will trigger the defaul 2. Appends any `msg.topic` defined on the node config 3. Runs `evts.beforeSend()` _(if provided)_ 4. Store the most recent message on the widget under the `._msg` property which will contain the latest state/value of the widget -5. Sends the `msg` onwards to any connected nodes +5. Pushes a `widget-sync` event to synchronize the widgets in all clients. +6. Sends the `msg` onwards to any connected nodes #### Custom `onChange` Handler @@ -111,8 +112,10 @@ Alternatively, you can override this default behaviour by providing a custom `on * Handle the input from the widget * @param {object} msg - the last known msg received (prior to this new value) * @param {boolean} value - the updated value sent by the widget + * @param {Socket} conn - socket.io socket connecting to the server + * @param {String} id - widget id sending the action */ -onChange: async function (msg, value) { +onChange: async function (msg, value, conn, id) { // ensure we have latest instance of the widget's node const wNode = RED.nodes.getNode(node.id) @@ -127,6 +130,10 @@ onChange: async function (msg, value) { const off = RED.util.evaluateNodeProperty(config.offvalue, config.offvalueType, wNode) msg.payload = value ? on : off + // sync this change to all clients with the same widget + const exclude = [conn.id] + base.emit('widget-sync:' + id, msg, node, exclude) + // simulate Node-RED node receiving an input wNode.send(msg) } diff --git a/nodes/config/ui_base.js b/nodes/config/ui_base.js index 97dd6f4e9..c5c655bbd 100644 --- a/nodes/config/ui_base.js +++ b/nodes/config/ui_base.js @@ -639,7 +639,7 @@ module.exports = function (RED) { msg = addConnectionCredentials(RED, msg, conn, n) - async function defaultHandler (msg, value) { + async function defaultHandler (msg, value, conn, id) { if (typeof (value) === 'object' && value !== null && hasProperty(value, 'payload')) { msg.payload = value.payload } else { @@ -662,7 +662,7 @@ module.exports = function (RED) { // Most of the time, we can just use this default handler, // but sometimes a node needs to do something specific (e.g. ui-switch) const handler = typeof (widgetEvents.onChange) === 'function' ? widgetEvents.onChange : defaultHandler - await handler(msg, value) + await handler(msg, value, conn, id) } catch (error) { console.log(error) let errorHandler = typeof (widgetEvents.onError) === 'function' ? widgetEvents.onError : null diff --git a/nodes/widgets/ui_switch.js b/nodes/widgets/ui_switch.js index 988ce659b..577a570b3 100644 --- a/nodes/widgets/ui_switch.js +++ b/nodes/widgets/ui_switch.js @@ -14,6 +14,7 @@ module.exports = function (RED) { // which group are we rendering this widget const group = RED.nodes.getNode(config.group) + const base = group.getBase() // retrieve the assigned on/off values const on = RED.util.evaluateNodeProperty(config.onvalue, config.onvalueType, node) @@ -27,7 +28,7 @@ module.exports = function (RED) { const evts = { // runs on UI interaction // value = true | false from the ui-switch - onChange: async function (msg, value) { + onChange: async function (msg, value, conn, id) { msg.payload = value ? on : off if (config.topic || config.topicType) { @@ -42,7 +43,10 @@ module.exports = function (RED) { shape: 'ring', text: value ? states[1] : states[0] }) - datastore.save(group.getBase(), node, msg) + datastore.save(base, node, msg) + + const exclude = [conn.id] // sync this change to all clients with the same widget + base.emit('widget-sync:' + id, msg, node, exclude) // let all other connect clients now about the value change // simulate Node-RED node receiving an input node.send(msg)