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 (106 loc) • 4.29 kB
JavaScript
/* eslint-disable class-methods-use-this */
/** Build UI elements by output of low-code JSON
*
* Copyright (c) 2023-2023 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.
*/
// 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').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} 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('[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