123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- const statestore = require('../store/state.js')
-
- const { addConnectionCredentials } = require('../utils/index.js')
-
- module.exports = function (RED) {
- function UiControlNode (config) {
- const node = this
- RED.nodes.createNode(this, config)
-
- // which ui does this widget belong to
- const ui = RED.nodes.getNode(config.ui)
-
- function updateStore (all, items, msg, prop, value) {
- items.forEach(function (item) {
- const i = all[item]
- if (i) {
- // update the state store for each page
- statestore.set(ui, i, msg, prop, value)
- } else {
- node.error("No item with the name '" + item + "' found", msg)
- }
- })
- }
-
- function emit (msg) {
- ui.emit('ui-control:' + node.id, msg, node)
- }
-
- const evts = {
- onInput: function (msg, send, done) {
- const wNode = RED.nodes.getNode(node.id)
- // handle the logic here of what to do when input is received
-
- if (typeof msg.payload !== 'object') {
- msg.payload = { page: msg.payload }
- }
-
- // switch to tab name (or number)
- if ('tab' in msg.payload || 'page' in msg.payload) {
- let page = msg.payload.page || msg.payload.tab
-
- page = (page === undefined) ? '' : page
-
- if (page === '-1' || page === '+1' || typeof (page) === 'number' || page === '') {
- // special case for -1 and +1 to switch to previous/next tab
- // number to pick specific index
- // "" to refresh the page
- // ensure consistency in payload format
- msg.payload.page = page
- emit(msg)
- } else {
- let pageFound = false
- // check we have a valid tab/page name
- RED.nodes.eachNode(function (n) {
- if (n.type === 'ui-page') {
- if (n.name === page) {
- // ensure consistency in payload format
- msg.payload.page = page
- // send a message to the ui to switch to this tab
- emit(msg)
- pageFound = true
- }
- }
- })
- if (!pageFound) {
- node.error("No page with the name '" + page + "' found")
- }
- }
- }
-
- // show/hide or enable/disable tabs
- if ('tabs' in msg.payload || 'pages' in msg.payload) {
- const pages = msg.payload.pages || msg.payload.tabs
- // get a map of page name to page object
- const allPages = {}
- RED.nodes.eachNode((n) => {
- if (n.type === 'ui-page') {
- allPages[n.name] = n
- }
- })
-
- // const pMap = RED.nodes.forEach
- if ('show' in pages) {
- updateStore(allPages, pages.show, msg, 'visible', true)
- }
- if ('hide' in pages) {
- updateStore(allPages, pages.hide, msg, 'visible', false)
- }
- if ('enable' in pages) {
- updateStore(allPages, pages.enable, msg, 'disabled', false)
- }
- if ('disable' in pages) {
- updateStore(allPages, pages.disable, msg, 'disabled', false)
- }
-
- // ensure consistency in payload format
- msg.payload.pages = pages
- // send to front end in order to action there too
- emit(msg)
- }
-
- // show or hide ui groups
- if ('groups' in msg.payload || 'group' in msg.payload) {
- const groups = msg.payload.groups || msg.payload.group
- // get a map of group name to group object
- const allGroups = {}
- RED.nodes.eachNode((n) => {
- if (n.type === 'ui-group') {
- allGroups[n.name] = n
- }
- })
- if ('show' in groups) {
- const gs = groups.show.map((g) => {
- const levels = g.split(':')
- return levels.length > 1 ? levels[1] : g
- })
- updateStore(allGroups, gs, msg, 'visible', true)
- }
- if ('hide' in groups) {
- const gh = groups.hide.map((g) => {
- const levels = g.split(':')
- return levels.length > 1 ? levels[1] : g
- })
- updateStore(allGroups, gh, msg, 'visible', false)
- }
- if ('enable' in groups) {
- const ge = groups.enable.map((g) => {
- const levels = g.split(':')
- return levels.length > 1 ? levels[1] : g
- })
- updateStore(allGroups, ge, msg, 'disabled', false)
- }
- if ('disable' in groups) {
- const gd = groups.disable.map((g) => {
- const levels = g.split(':')
- return levels.length > 1 ? levels[1] : g
- })
- updateStore(allGroups, gd, msg, 'disabled', true)
- }
- // ensure consistency in payload format
- msg.payload.groups = groups
- emit(msg)
-
- // send specific visible/hidden commands via SocketIO here,
- // so all logic stays server-side
-
- wNode.send({ payload: 'input' })
- }
-
- if ('url' in msg.payload) {
- emit(msg)
- }
- },
- onSocket: {
- connection: function (conn) {
- if (config.events === 'all' || config.events === 'connect') {
- const wNode = RED.nodes.getNode(node.id)
- let msg = {
- payload: 'connect'
- }
- msg = addConnectionCredentials(RED, msg, conn, ui)
- wNode.send(msg)
- }
- },
- disconnect: function (conn) {
- if (config.events === 'all' || config.events === 'connect') {
- const wNode = RED.nodes.getNode(node.id)
- let msg = {
- payload: 'lost'
- }
- msg = addConnectionCredentials(RED, msg, conn, ui)
- wNode.send(msg)
- }
- },
- 'ui-control': function (conn, id, evt, payload) {
- if (id === node.id && (config.events === 'all' || config.events === 'change')) {
- // this message was sent by this particular node
- if (evt === 'change') {
- const wNode = RED.nodes.getNode(node.id)
- let msg = {
- payload: 'change',
- tab: payload.page, // index of tab
- name: payload.name // page name
- }
- msg = addConnectionCredentials(RED, msg, conn, ui)
- wNode.send(msg)
- }
- }
- }
- }
- }
-
- // inform the dashboard UI that we are adding this node
- ui.register(null, null, node, config, evts)
-
- node.on('close', function (removed, done) {
- if (removed) {
- // handle node being removed
- ui?.deregister(null, null, node)
- }
- done()
- })
- }
- RED.nodes.registerType('ui-control', UiControlNode)
- }
|