diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
index ab5ba95fb..128ab67aa 100644
--- a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
+++ b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
@@ -727,6 +727,7 @@
"nodeHelp": "Node Help",
"showHelp": "Show help",
"showInOutline": "Show in outline",
+ "hideTopics": "Hide topics",
"showTopics": "Show topics",
"noHelp": "No help topic selected",
"changeLog": "Change Log"
@@ -922,6 +923,8 @@
}
},
"typedInput": {
+ "selected": "__count__ selected",
+ "selected_plural": "__count__ selected",
"type": {
"str": "string",
"num": "number",
diff --git a/packages/node_modules/@node-red/editor-client/locales/fr/editor.json b/packages/node_modules/@node-red/editor-client/locales/fr/editor.json
index e0ebdbb2a..bacd5b70f 100644
--- a/packages/node_modules/@node-red/editor-client/locales/fr/editor.json
+++ b/packages/node_modules/@node-red/editor-client/locales/fr/editor.json
@@ -726,6 +726,7 @@
"nodeHelp": "Aide sur les noeuds",
"showHelp": "Afficher l'aide",
"showInOutline": "Afficher dans les grandes lignes",
+ "hideTopics": "Masquer les sujets",
"showTopics": "Afficher les sujets",
"noHelp": "Aucune rubrique d'aide sélectionnée",
"changeLog": "Journal des modifications"
@@ -921,6 +922,8 @@
}
},
"typedInput": {
+ "selected": "__count__ sélectionnée",
+ "selected_plural": "__count__ sélectionnées",
"type": {
"str": "chaîne de caractères",
"num": "nombre",
diff --git a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json
index 33e56f9ae..a2ee81767 100644
--- a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json
+++ b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json
@@ -727,6 +727,7 @@
"nodeHelp": "ノードヘルプ",
"showHelp": "ヘルプを表示",
"showInOutline": "アウトラインに表示",
+ "hideTopics": "トピックを非表示",
"showTopics": "トピックを表示",
"noHelp": "ヘルプのトピックが未選択",
"changeLog": "更新履歴"
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js
index 177c88356..7c4964ca8 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js
@@ -1009,12 +1009,12 @@
}
if (menu.opts.multiple) {
var selected = {};
- this.value().split(",").forEach(function(f) {
- selected[f] = true;
- })
+ this.value().split(",").forEach(function(f) {
+ selected[f] = true;
+ });
menu.find('input[type="checkbox"]').each(function() {
- $(this).prop("checked",selected[$(this).data('value')])
- })
+ $(this).prop("checked", selected[$(this).data('value')] || false);
+ });
}
@@ -1105,7 +1105,7 @@
this.input.trigger('change',[this.propertyType,this.value()]);
}
} else {
- this.optionSelectLabel.text(o.length+" selected");
+ this.optionSelectLabel.text(RED._("typedInput.selected", { count: o.length }));
}
}
},
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js
index 90857e865..25a67907c 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js
@@ -662,6 +662,7 @@ RED.deploy = (function() {
// Once deployed, cannot undo back to a clean state
RED.history.markAllDirty();
RED.view.redraw();
+ RED.sidebar.config.refresh();
RED.events.emit("deploy");
}).fail(function (xhr, textStatus, err) {
RED.nodes.dirty(true);
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
index 894ff3e0f..90570a969 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
@@ -248,6 +248,8 @@ RED.editor = (function() {
var value = input.val();
if (defaults[property].hasOwnProperty("format") && defaults[property].format !== "" && input[0].nodeName === "DIV") {
value = input.text();
+ } else if (input.attr("type") === "checkbox") {
+ value = input.prop("checked");
}
var valid = validateNodeProperty(node, defaults, property,value);
if (((typeof valid) === "string") || !valid) {
@@ -801,9 +803,16 @@ RED.editor = (function() {
}
try {
- var rc = editing_node._def.oneditsave.call(editing_node);
+ const rc = editing_node._def.oneditsave.call(editing_node);
if (rc === true) {
editState.changed = true;
+ } else if (typeof rc === 'object' && rc !== null ) {
+ if (rc.changed === true) {
+ editState.changed = true
+ }
+ if (Array.isArray(rc.history) && rc.history.length > 0) {
+ editState.history = rc.history
+ }
}
} catch(err) {
console.warn("oneditsave",editing_node.id,editing_node.type,err.toString());
@@ -1005,6 +1014,17 @@ RED.editor = (function() {
dirty: startDirty
}
+ if (editing_node.g) {
+ const group = RED.nodes.group(editing_node.g);
+ // Don't use RED.group.removeFromGroup as that emits
+ // a change event on the node - but we're deleting it
+ const index = group?.nodes.indexOf(editing_node) ?? -1;
+ if (index > -1) {
+ group.nodes.splice(index, 1);
+ RED.group.markDirty(group);
+ }
+ }
+
RED.nodes.dirty(true);
RED.view.redraw(true);
RED.history.push(historyEvent);
@@ -1106,7 +1126,7 @@ RED.editor = (function() {
}
});
}
- var historyEvent = {
+ let historyEvent = {
t:'edit',
node:editing_node,
changes:editState.changes,
@@ -1122,6 +1142,15 @@ RED.editor = (function() {
instances:subflowInstances
}
}
+
+ if (editState.history) {
+ historyEvent = {
+ t: 'multi',
+ events: [ historyEvent, ...editState.history ],
+ dirty: wasDirty
+ }
+ }
+
RED.history.push(historyEvent);
}
editing_node.dirty = true;
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js
index e2c8185cb..b8e3aa0ba 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js
@@ -382,9 +382,11 @@ RED.sidebar.config = (function() {
refreshConfigNodeList();
}
});
+
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllConfigNodes"));
RED.popover.tooltip($('#red-ui-sidebar-config-filter-unused'), RED._("sidebar.config.showAllUnusedConfigNodes"));
-
+ RED.popover.tooltip($('#red-ui-sidebar-config-collapse-all'), RED._("palette.actions.collapse-all"));
+ RED.popover.tooltip($('#red-ui-sidebar-config-expand-all'), RED._("palette.actions.expand-all"));
}
function flashConfigNode(el) {
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js
index 8bfc5526e..b3d06f701 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js
@@ -36,7 +36,13 @@ RED.sidebar.help = (function() {
toolbar = $("
", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(content);
$('').appendTo(toolbar)
var showTOCButton = toolbar.find('#red-ui-sidebar-help-show-toc')
- RED.popover.tooltip(showTOCButton,RED._("sidebar.help.showTopics"));
+ RED.popover.tooltip(showTOCButton, function () {
+ if ($(showTOCButton).hasClass('selected')) {
+ return RED._("sidebar.help.hideTopics");
+ } else {
+ return RED._("sidebar.help.showTopics");
+ }
+ });
showTOCButton.on("click",function(e) {
e.preventDefault();
if ($(this).hasClass('selected')) {
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js
index 87132afc1..e97e2e36e 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js
@@ -1190,6 +1190,7 @@ RED.view = (function() {
if (d3.event.button === 1) {
// Middle Click pan
+ d3.event.preventDefault();
mouse_mode = RED.state.PANNING;
mouse_position = [d3.event.pageX,d3.event.pageY]
scroll_position = [chart.scrollLeft(),chart.scrollTop()];
diff --git a/packages/node_modules/@node-red/editor-client/src/sass/tab-config.scss b/packages/node_modules/@node-red/editor-client/src/sass/tab-config.scss
index 9d678daa1..aed01240a 100644
--- a/packages/node_modules/@node-red/editor-client/src/sass/tab-config.scss
+++ b/packages/node_modules/@node-red/editor-client/src/sass/tab-config.scss
@@ -37,7 +37,6 @@ ul.red-ui-sidebar-node-config-list {
}
.red-ui-palette-node {
// overflow: hidden;
- cursor: default;
&.selected {
border-color: transparent;
box-shadow: 0 0 0 2px var(--red-ui-node-selected-color);
diff --git a/packages/node_modules/@node-red/nodes/core/common/60-link.html b/packages/node_modules/@node-red/nodes/core/common/60-link.html
index 73ce86ccf..748ccb42b 100644
--- a/packages/node_modules/@node-red/nodes/core/common/60-link.html
+++ b/packages/node_modules/@node-red/nodes/core/common/60-link.html
@@ -194,27 +194,46 @@
nodeMap[node.links[i]].new = true;
}
}
- var n;
- for (var id in nodeMap) {
+
+ let editHistories = []
+ let n;
+ for (let id in nodeMap) {
if (nodeMap.hasOwnProperty(id)) {
n = RED.nodes.node(id);
if (n) {
+ editHistories.push({
+ t:'edit',
+ node: n,
+ changes: {
+ links: [...n.links]
+ },
+ changed: n.changed
+ })
if (nodeMap[id].old && !nodeMap[id].new) {
// Removed id
i = n.links.indexOf(node.id);
if (i > -1) {
n.links.splice(i,1);
+ n.changed = true
+ n.dirty = true
}
} else if (!nodeMap[id].old && nodeMap[id].new) {
// Added id
i = n.links.indexOf(id);
if (i === -1) {
n.links.push(node.id);
+ n.changed = true
+ n.dirty = true
}
}
}
}
}
+ if (editHistories.length > 0) {
+ return {
+ history: editHistories
+ }
+ }
}
function onAdd() {
@@ -254,13 +273,14 @@
onEditPrepare(this,"link out");
},
oneditsave: function() {
- onEditSave(this);
+ const result = onEditSave(this);
// In case the name has changed, ensure any link call nodes on this
// tab are redrawn with the updated name
var localCallNodes = RED.nodes.filterNodes({z:RED.workspaces.active(), type:"link call"});
localCallNodes.forEach(function(node) {
node.dirty = true;
});
+ return result
},
onadd: onAdd,
oneditresize: resizeNodeList
@@ -329,7 +349,7 @@
onEditPrepare(this,"link in");
},
oneditsave: function() {
- onEditSave(this);
+ return onEditSave(this);
},
oneditresize: resizeNodeList
});
@@ -373,7 +393,7 @@
},
oneditsave: function() {
- onEditSave(this);
+ return onEditSave(this);
},
onadd: onAdd,
oneditresize: resizeNodeList
diff --git a/scripts/build-custom-theme.js b/scripts/build-custom-theme.js
index 3a904fea8..bb8451d57 100644
--- a/scripts/build-custom-theme.js
+++ b/scripts/build-custom-theme.js
@@ -13,7 +13,7 @@
// 4. Edit your settings file to set the theme:
// editorTheme: {
// page: {
-// css: "/path/to/file/generated/by/this/script"
+// css: '/path/to/file/generated/by/this/script'
// }
// }
//
@@ -22,110 +22,69 @@
-const os = require("os");
-const nopt = require("nopt");
-const path = require("path");
-const fs = require("fs-extra");
-const sass = require("sass");
+const os = require('os');
+const nopt = require('nopt');
+const path = require('path');
+const fs = require('fs-extra');
+const sass = require('sass');
const knownOpts = {
- "help": Boolean,
- "long": Boolean,
- "in": [path],
- "out": [path]
+ 'help': Boolean,
+ 'long': Boolean,
+ 'in': [path],
+ 'out': [path]
};
const shortHands = {
- "?":["--help"]
+ '?':['--help']
};
nopt.invalidHandler = function(k,v,t) {}
const parsedArgs = nopt(knownOpts,shortHands,process.argv,2)
if (parsedArgs.help) {
- console.log("Usage: build-custom-theme [-?] [--in FILE] [--out FILE]");
- console.log("");
- console.log("Options:");
- console.log(" --in FILE Custom colors sass file");
- console.log(" --out FILE Where you write the result");
- console.log(" --long Do not compress the output");
- console.log(" -?, --help Show this help");
- console.log("");
- process.exit();
+ showUsageAndExit(0)
}
-
-const ruleRegex = /(\$.*?) *: *(\S[\S\s]*?);/g;
-var match;
-
-const customColors = {};
-
-if (parsedArgs.in && fs.existsSync(parsedArgs.in)) {
- let customColorsFile = fs.readFileSync(parsedArgs.in,"utf-8");
- while((match = ruleRegex.exec(customColorsFile)) !== null) {
- customColors[match[1]] = match[2];
- }
+if (!parsedArgs.in) {
+ console.warn('Missing argument: in')
+ showUsageAndExit(1)
}
-// Load base colours
-let colorsFile = fs.readFileSync(path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/colors.scss"),"utf-8")
-let updatedColors = [];
-
-while((match = ruleRegex.exec(colorsFile)) !== null) {
- updatedColors.push(match[1]+": "+(customColors[match[1]]||match[2])+";")
-}
-
-
(async function() {
const tmpDir = os.tmpdir();
const workingDir = await fs.mkdtemp(`${tmpDir}${path.sep}`);
- await fs.copy(path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/"),workingDir)
- await fs.writeFile(path.join(workingDir,"colors.scss"),updatedColors.join("\n"))
- const result = sass.renderSync({
- outputStyle: "expanded",
- file: path.join(workingDir,"style-custom-theme.scss"),
- });
+ await fs.copy(path.join(__dirname, '../packages/node_modules/@node-red/editor-client/src/sass/'), workingDir);
+ await fs.copyFile(parsedArgs.in, path.join(workingDir,'colors.scss'));
- const css = result.css.toString()
- const lines = css.split("\n");
- const colorCSS = []
- const nonColorCSS = [];
+ const output = sass.compile(
+ path.join(workingDir, 'style-custom-theme.scss'),
+ {style: parsedArgs.long === true ? 'expanded' : 'compressed'}
+ );
- let inKeyFrameBlock = false;
-
- lines.forEach(l => {
- if (inKeyFrameBlock) {
- nonColorCSS.push(l);
- if (/^}/.test(l)) {
- inKeyFrameBlock = false;
- }
- } else if (/^@keyframes/.test(l)) {
- nonColorCSS.push(l);
- inKeyFrameBlock = true;
- } else if (!/^ /.test(l)) {
- colorCSS.push(l);
- nonColorCSS.push(l);
- } else if (/color|border|background|fill|stroke|outline|box-shadow/.test(l)) {
- colorCSS.push(l);
- } else {
- nonColorCSS.push(l);
- }
- });
-
- const nrPkg = require("../package.json");
+ const nrPkg = require('../package.json');
const now = new Date().toISOString();
+ const header = `/*\n* Theme generated with Node-RED ${nrPkg.version} on ${now}\n*/`;
- const header = `/*
- * Theme generated with Node-RED ${nrPkg.version} on ${now}
- */`;
-
- var output = sass.renderSync({outputStyle: parsedArgs.long?"expanded":"compressed",data:colorCSS.join("\n")});
if (parsedArgs.out) {
-
- await fs.writeFile(parsedArgs.out,header+"\n"+output.css);
+ await fs.writeFile(parsedArgs.out, header+'\n'+output.css);
} else {
console.log(header);
console.log(output.css.toString());
}
+
await fs.remove(workingDir);
})()
+
+function showUsageAndExit (exitCode) {
+ console.log('');
+ console.log('Usage: build-custom-theme [-?] [--in FILE] [--out FILE]');
+ console.log('');
+ console.log('Options:');
+ console.log(' --in FILE Custom colors sass file');
+ console.log(' --out FILE Where you write the result');
+ console.log(' --long Do not compress the output');
+ console.log(' -?, --help Show this help');
+ console.log('');
+ process.exit(exitCode);
+}
\ No newline at end of file