UNPKG

smart-nodes

Version:

Controls light, shutters and more. Includes common used logic and statistic nodes to control your home.

304 lines (274 loc) 11 kB
<script type="text/javascript"> (function () { let treeList; // The tree control itself let candidateNodesCount = 0; // The total entries shown in the list, used for the search box as info let flows = []; // A List with all flow maps let flowMap = {}; // A key value list with all flow id => flow details and children function onEditPrepare(node, targetTypes) { if (!node.links) node.links = []; node.oldLinks = []; const activeSubflow = RED.nodes.subflow(node.z); // init tree list control treeList = $("<div>") .css({ width: "100%", height: "100%" }) .appendTo(".node-input-link-row") .treeList({ autoSelect: false }) .on("treelistitemmouseover", function (e, item) { if (item.node) { item.node.highlighted = true; item.node.dirty = true; RED.view.redraw(); } }) .on("treelistitemmouseout", function (e, item) { if (item.node) { item.node.highlighted = false; item.node.dirty = true; RED.view.redraw(); } }); // init search box const search = $("#node-input-link-target-filter").searchBox({ style: "compact", delay: 300, change: function () { var val = $(this).val().trim().toLowerCase(); if (val === "") { treeList.treeList("filter", null); search.searchBox("count", ""); } else { const count = treeList.treeList("filter", function (item) { return item.label.toLowerCase().indexOf(val) > -1 || (item.parent && item.parent.label.toLowerCase().indexOf(val) > -1) || (item.node && item.node.type.toLowerCase().indexOf(val) > -1); }); search.searchBox("count", count + " / " + candidateNodesCount); } }, }); // clear shown tree data flows = []; flowMap = {}; // Add all existing flows if (activeSubflow) { flowMap[activeSubflow.id] = { id: activeSubflow.id, class: "red-ui-palette-header", label: "Subflow : " + (activeSubflow.name || activeSubflow.id), expanded: true, children: [], }; flows.push(flowMap[activeSubflow.id]); } else { RED.nodes.eachWorkspace(function (ws) { if (!ws.disabled) { flowMap[ws.id] = { id: ws.id, class: "red-ui-palette-header", label: (ws.label || ws.id) + (node.z === ws.id ? " *" : ""), expanded: true, children: [], }; flows.push(flowMap[ws.id]); } }); } setTimeout(function () { treeList.treeList("show", node.z); }, 100); candidateNodesCount = 0; for (const key in flowMap) { flowMap[key].children = []; } let candidateNodes = []; targetTypes.forEach(function (targetType) { candidateNodes = candidateNodes.concat(RED.nodes.filterNodes({ type: targetType })); }); // Add all nodes, matching the given types candidateNodes.forEach(function (n) { if (flowMap[n.z]) { const isChecked = node.links.indexOf(n.id) !== -1 || (n.links || []).indexOf(node.id) !== -1; if (!n.exec_text_names) { // No exec name defined but checked, so remove it from the linked list. if (isChecked) { node.links.splice(node.links.indexOf(n.id), 1); console.log("Unchecked " + n.name); } return; } if (isChecked) node.oldLinks.push(n.id); flowMap[n.z].children.push({ id: n.id, node: n, label: n.type.replace("smart_", "").replace("-control", "").replace("-complex", "") + ": " + (n.name || n.id), selected: isChecked, checkbox: true, radio: false, }); candidateNodesCount++; } }); // Sort nodes by name for (const key in flowMap) { flowMap[key].children.sort((a, b) => a.label.localeCompare(b.label)); } // filter empty flows const flowsFiltered = flows.filter(function (f) { return f.children.length > 0; }); // clear list and refill it treeList.treeList("empty"); treeList.treeList("data", flowsFiltered); } function resizeNodeList() { // calculate new heigt if browser is beeing resized var rows = $("#dialog-form>div:not(.node-input-link-row)"); var height = $("#dialog-form").height(); for (var i = 0; i < rows.length; i++) { height -= $(rows[i]).outerHeight(true); } var editorRow = $("#dialog-form>div.node-input-link-row"); height -= parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")); $(".node-input-link-row").css("height", Math.max(height, 200) + "px"); } function onEditSave(node) { var flows = treeList.treeList("data"); node.links = []; // Set own links for selected nodes flows.forEach(function (f) { f.children.forEach(function (n) { if (n.selected) node.links.push(n.id); }); }); node.oldLinks.sort(); node.links.sort(); // Mark new and old links var nodeMap = {}; var length = Math.max(node.oldLinks.length, node.links.length); for (var i = 0; i < length; i++) { if (i < node.oldLinks.length) { nodeMap[node.oldLinks[i]] = nodeMap[node.oldLinks[i]] || {}; nodeMap[node.oldLinks[i]].old = true; } if (i < node.links.length) { nodeMap[node.links[i]] = nodeMap[node.links[i]] || {}; nodeMap[node.links[i]].new = true; } } // Remove own node from old linked nodes // Add own node to new linked nodes var n; for (var id in nodeMap) { if (nodeMap.hasOwnProperty(id)) { n = RED.nodes.node(id); if (n) { // init links and remove duplicate links if (!n.links) n.links = []; else n.links = n.links.filter((value, index, array) => array.indexOf(value) === index); if (nodeMap[id].old && !nodeMap[id].new) { // Removed id i = n.links.indexOf(node.id); if (i > -1) n.links.splice(i, 1); } else if (nodeMap[id].new) { // Added id i = n.links.indexOf(node.id); if (i === -1) n.links.push(node.id); } } } } } // This function is called, when copying and pasting central node function onAdd() { for (var i = 0; i < this.links.length; i++) { var n = RED.nodes.node(this.links[i]); if (n && n.links.indexOf(this.id) === -1) { n.links.push(this.id); } } } RED.nodes.registerType("smart_text-exec", { category: "Smart Nodes", paletteLabel: "Text exec control", color: "#E9967A", defaults: { name: { value: "" }, links: { value: [], type: "smart_shutter-complex-control[]" }, }, inputs: 1, outputs: 1, icon: "font-awesome/fa-cog", label: function () { return this.name || "Text exec control"; }, oneditprepare: function () { let node = this; onEditPrepare(this, ["smart_light-control", "smart_scene-control", "smart_shutter-complex-control", "smart_shutter-control"]); }, oneditsave: function () { let node = this; onEditSave(this); }, onadd: onAdd, oneditresize: resizeNodeList, }); })(); </script> <script type="text/html" data-template-name="smart_text-exec"> <div class="form-row"> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="text-exec.ui.name"></span></label> <input type="text" id="node-input-name" data-i18n="[placeholder]text-exec.ui.name" /> </div> <div class="node-input-link-rows" style="position:relative; height: 30px; text-align: right;"> <div style="display:inline-block"><input type="text" id="node-input-link-target-filter" /></div> </div> <div class="form-row node-input-link-row node-input-link-rows"></div> </script>