UNPKG

node-red-contrib-uibuilder

Version:

Easily create data-driven web UI's for Node-RED. Single- & Multi-page. Multiple UI's. Work with existing web development workflows or mix and match with no-code/low-code features.

125 lines (107 loc) 4.38 kB
/* eslint-disable jsdoc/valid-types */ /** Build UI elements by output of low-code JSON * * Copyright (c) 2023-2025 Julian Knight (Totally Information) * https://it.knightnet.org.uk, https://github.com/TotallyInformation/node-red-contrib-uibuilder * * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict' // REFERENCES // /** --- Type Defs --- * @typedef {import('../../typedefs.js').runtimeRED} runtimeRED * @typedef {import('../../typedefs.js').runtimeNode} runtimeNode * @typedef {import('../../typedefs.js').uibNode} uibNode * @typedef {import('../../typedefs.js').LibLowCodeNode} LibLowCodeNode * @typedef {import('../../typedefs.js').uibConfig} uibConfig * @typedef {import('../../typedefs.js').uibPackageJson} uibPackageJson */ class UibLowCode { /** PRIVATE Flag to indicate whether setup() has been run (ignore the false eslint error) * @type {boolean} */ #isConfigured = false // constructor() {} // ---- End of constructor ---- // /** Configure this class with uibuilder module specifics * @param {runtimeRED} RED uibuilder module-level configuration */ setup( RED ) { if ( !RED ) throw new Error('[uibuilder:UibLowCode:setup] RED is not defined') // Prevent setup from being called more than once if ( this.#isConfigured === true ) { RED.log.warn('🌐⚠️[uibuilder:UibLowCode:setup] Setup has already been called, it cannot be called again.') return } this.RED = RED this.log = RED.log this.#isConfigured = true } // ---- End of setup ---- // // #region --- Modes --- // remove // removeAll // replace // update // #endregion --- Modes --- /** Create/update the _ui object and retain for replay * @param {*} msg incoming msg * @param {runtimeNode & LibLowCodeNode} node reference to node instance */ async buildUi(msg, node) { // Allow combination of msg._ui and this node allowing chaining of the nodes if ( msg._ui ) { if (!Array.isArray(msg._ui)) msg._ui = [msg._ui] node._ui = msg._ui } else node._ui = [] // If no mode specified, we assume the desire is to update (since a removal attempt with nothing to remove is safe) if ( msg.mode ) msg.mode = msg.mode.toLowerCase() else msg.mode = 'replace' // If mode is remove, then simply do that and return if ( msg.mode === 'delete' || msg.mode === 'remove' ) { if (!node.elementId) { node.warn('🌐⚠️[ubuilder:low-code:buildUi] Cannot remove element as no HTML ID provided') return } node._ui.push( { method: 'remove', components: [ `#${node.elementId}`, ], } ) return } // If no HMTL ID is specified & not removing, then always ADD if (!node.elementId) msg.mode = 'add' node._ui.push({ method: msg.mode === 'add' ? 'add' : 'replace', components: [ { type: node.tag, id: node.elementId, parent: node.parent, position: node.position, slot: node.slotPropMarkdown === false ? node.slotContent : undefined, slotMarkdown: node.slotPropMarkdown === true ? node.slotContent : undefined, attributes: node.attribs, }, ], }) } // -- end of buildUI -- // } // ----- End of Class ----- // /** Singleton model. Only 1 instance of UibWeb should ever exist. * Use as: `const packageMgt = require('./package-mgt.js')` */ // @ts-ignore const uibLowCode = new UibLowCode() module.exports = uibLowCode // EOF