diff --git a/nodes/core/io/05-tls.html b/nodes/core/io/05-tls.html
index b28ab7314..2ba0acc91 100644
--- a/nodes/core/io/05-tls.html
+++ b/nodes/core/io/05-tls.html
@@ -156,7 +156,7 @@
clearNameData("ca");
});
- if (RED.settings.tlsDisableLocalFiles) {
+ if (RED.settings.tlsConfigDisableLocalFiles) {
$("#node-config-row-uselocalfiles").hide();
} else {
$("#node-config-row-uselocalfiles").show();
@@ -178,7 +178,7 @@
} else {
$("#node-config-input-ca").val("");
$("#node-config-input-cert").val("");
- $("#node-config-input-key").val("");
+ $("#node-config-input-key").val("");
}
}
});
diff --git a/nodes/core/io/05-tls.js b/nodes/core/io/05-tls.js
index a93ed1b39..7ad71efda 100644
--- a/nodes/core/io/05-tls.js
+++ b/nodes/core/io/05-tls.js
@@ -48,13 +48,13 @@ module.exports = function(RED) {
this.valid = false;
this.error(err.toString());
return;
- }
+ }
} else {
if (this.credentials) {
var certData = this.credentials.certdata || "";
var keyData = this.credentials.keydata || "";
var caData = this.credentials.cadata || "";
-
+
if ((certData.length > 0) !== (keyData.length > 0)) {
this.valid = false;
this.error(RED._("tls.error.missing-file"));
@@ -78,6 +78,12 @@ module.exports = function(RED) {
certdata: {type:"text"},
keydata: {type:"text"},
cadata: {type:"text"}
+ },
+ settings: {
+ tlsConfigDisableLocalFiles: {
+ value: true,
+ exportable: false
+ }
}
});
diff --git a/red/api/info.js b/red/api/info.js
index 72ec52b93..a1f4ca310 100644
--- a/red/api/info.js
+++ b/red/api/info.js
@@ -52,6 +52,8 @@ module.exports = {
safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {};
safeSettings.editorTheme.palette.editable = false;
}
+
+ settings.exportNodeSettings(safeSettings);
res.json(safeSettings);
}
diff --git a/red/runtime/nodes/index.js b/red/runtime/nodes/index.js
index 4fd0d1128..5be548549 100644
--- a/red/runtime/nodes/index.js
+++ b/red/runtime/nodes/index.js
@@ -50,8 +50,13 @@ function registerType(nodeSet,type,constructor,opts) {
type = nodeSet;
nodeSet = "";
}
- if (opts && opts.credentials) {
- credentials.register(type,opts.credentials);
+ if (opts) {
+ if (opts.credentials) {
+ credentials.register(type,opts.credentials);
+ }
+ if (opts.settings) {
+ settings.registerNodeSettings(type,opts.settings);
+ }
}
registry.registerType(nodeSet,type,constructor);
}
diff --git a/red/runtime/nodes/registry/registry.js b/red/runtime/nodes/registry/registry.js
index fbba8d95e..5372d7be6 100644
--- a/red/runtime/nodes/registry/registry.js
+++ b/red/runtime/nodes/registry/registry.js
@@ -493,6 +493,7 @@ function enableNodeSet(typeOrId) {
delete config.err;
config.enabled = true;
nodeConfigCache = null;
+ settings.enableNodeSettings(config.types);
return saveNodeList().then(function() {
return filterNodeInfo(config);
});
@@ -515,6 +516,7 @@ function disableNodeSet(typeOrId) {
// TODO: persist setting
config.enabled = false;
nodeConfigCache = null;
+ settings.disableNodeSettings(config.types);
return saveNodeList().then(function() {
return filterNodeInfo(config);
});
diff --git a/red/runtime/settings.js b/red/runtime/settings.js
index bbb1031fd..cb7ae91bc 100644
--- a/red/runtime/settings.js
+++ b/red/runtime/settings.js
@@ -18,9 +18,12 @@ var when = require("when");
var clone = require("clone");
var assert = require("assert");
var log = require("./log");
+var util = require("./util");
var userSettings = null;
var globalSettings = null;
+var nodeSettings = null;
+var disableNodeSettings = null;
var storage = null;
var persistentSettings = {
@@ -38,6 +41,8 @@ var persistentSettings = {
}
}
globalSettings = null;
+ nodeSettings = {};
+ disableNodeSettings = {};
},
load: function(_storage) {
storage = _storage;
@@ -99,6 +104,53 @@ var persistentSettings = {
userSettings = null;
globalSettings = null;
storage = null;
+ },
+ registerNodeSettings: function(type, opts) {
+ try {
+ for (var property in opts) {
+ if (opts.hasOwnProperty(property)) {
+ var normalisedType = util.normaliseNodeTypeName(type);
+ if (!property.startsWith(normalisedType)) {
+ throw new Error("The name of node setting property " + property + " must start with \"" + normalisedType + "\" (case sensitive).");
+ }
+ }
+ }
+ nodeSettings[type] = opts;
+ } catch (err) {
+ console.log(err.toString());
+ }
+ },
+ exportNodeSettings: function(safeSettings) {
+ safeSettings["nodeSettings"] = {};
+ for (var type in nodeSettings) {
+ if (nodeSettings.hasOwnProperty(type) && !disableNodeSettings[type]) {
+ var nodeTypeSettings = nodeSettings[type];
+ for (var property in nodeTypeSettings) {
+ if (nodeTypeSettings.hasOwnProperty(property)) {
+ var setting = nodeTypeSettings[property];
+ if (setting.exportable) {
+ if (userSettings.hasOwnProperty(property)) {
+ safeSettings["nodeSettings"][property] = userSettings[property];
+ } else {
+ safeSettings["nodeSettings"][property] = setting.value;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return safeSettings;
+ },
+ enableNodeSettings: function(types) {
+ types.forEach(function(type) {
+ disableNodeSettings[type] = false;
+ });
+ },
+ disableNodeSettings: function(types) {
+ types.forEach(function(type) {
+ disableNodeSettings[type] = true;
+ });
}
}
diff --git a/red/runtime/util.js b/red/runtime/util.js
index cc3cff330..55c3d8a57 100644
--- a/red/runtime/util.js
+++ b/red/runtime/util.js
@@ -328,6 +328,18 @@ function evaluateNodeProperty(value, type, node, msg) {
return value;
}
+function normaliseNodeTypeName(name) {
+ var result = name.replace(/[^a-zA-Z0-9]/g, " ");
+ result = result.trim();
+ result = result.replace(/ +/g, " ");
+ result = result.replace(/ ./g,
+ function(s) {
+ return s.charAt(1).toUpperCase();
+ }
+ );
+ result = result.charAt(0).toLowerCase() + result.slice(1);
+ return result;
+}
module.exports = {
ensureString: ensureString,
@@ -338,5 +350,6 @@ module.exports = {
getMessageProperty: getMessageProperty,
setMessageProperty: setMessageProperty,
evaluateNodeProperty: evaluateNodeProperty,
- normalisePropertyExpression: normalisePropertyExpression
+ normalisePropertyExpression: normalisePropertyExpression,
+ normaliseNodeTypeName: normaliseNodeTypeName
};
diff --git a/settings.js b/settings.js
index 469ec56ea..5b6b582f0 100644
--- a/settings.js
+++ b/settings.js
@@ -49,7 +49,7 @@ module.exports = {
// To disable the option for using local files for storing keys and certificates in the TLS configuration
// node, set this to true
- //tlsDisableLocalFiles:true,
+ //tlsConfigDisableLocalFiles: true,
// Colourise the console output of the debug node
//debugUseColors: true,
diff --git a/test/red/api/index_spec.js b/test/red/api/index_spec.js
index 0b564da73..8edd737d6 100644
--- a/test/red/api/index_spec.js
+++ b/test/red/api/index_spec.js
@@ -29,7 +29,7 @@ describe("api index", function() {
describe("disables editor", function() {
before(function() {
api.init({},{
- settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:true},
+ settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:true, exportNodeSettings: function() {}},
events: {on:function(){},removeListener: function(){}},
log: {info:function(){},_:function(){}},
nodes: {paletteEditorEnabled: function(){return true}}
diff --git a/test/red/api/info_spec.js b/test/red/api/info_spec.js
index 70f477a35..c222aec5c 100644
--- a/test/red/api/info_spec.js
+++ b/test/red/api/info_spec.js
@@ -42,7 +42,10 @@ describe("info api", function() {
foo: 123,
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
- paletteCategories :["red","blue","green"]
+ paletteCategories :["red","blue","green"],
+ exportNodeSettings: function(obj) {
+ obj.testNodeSetting = "helloWorld";
+ }
},
nodes: {
paletteEditorEnabled: function() { return true; }
@@ -59,7 +62,9 @@ describe("info api", function() {
res.body.should.have.property("version","testVersion");
res.body.should.have.property("paletteCategories",["red","blue","green"]);
res.body.should.have.property("editorTheme",{test:456});
+ res.body.should.have.property("testNodeSetting","helloWorld");
res.body.should.not.have.property("foo",123);
+
done();
});
});
@@ -68,8 +73,8 @@ describe("info api", function() {
settings: {
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
- paletteCategories :["red","blue","green"]
-
+ paletteCategories :["red","blue","green"],
+ exportNodeSettings: function() {}
},
nodes: {
paletteEditorEnabled: function() { return false; }
diff --git a/test/red/runtime/settings_spec.js b/test/red/runtime/settings_spec.js
index 3ce086739..ec995155b 100644
--- a/test/red/runtime/settings_spec.js
+++ b/test/red/runtime/settings_spec.js
@@ -142,4 +142,87 @@ describe("red/settings", function() {
settings.should.not.have.property("c");
});
+
+ it('registers node settings and exports them', function() {
+ var userSettings = {};
+ settings.init(userSettings);
+ settings.registerNodeSettings("inject", {injectColor:{value:"red", exportable:true}, injectSize:{value:"100", exportable:true}} );
+ settings.registerNodeSettings("mqtt", {mqttColor:{value:"purple", exportable:false}, mqttSize:{value:"50", exportable:true}} );
+ settings.registerNodeSettings("http request", {httpRequest1:{value:"a1", exportable:true}} );
+ settings.registerNodeSettings(" http--request<> ", {httpRequest2:{value:"a2", exportable:true}} );
+ settings.registerNodeSettings("_http_request_", {httpRequest3:{value:"a3", exportable:true}} );
+ settings.registerNodeSettings("mQtT", {mQtTColor:{value:"purple", exportable:true}} );
+ settings.registerNodeSettings("abc123", {abc123:{value:"def456", exportable:true}} );
+ var safeSettings = {};
+ settings.exportNodeSettings(safeSettings);
+ safeSettings["nodeSettings"].should.have.property("injectColor", "red");
+ safeSettings["nodeSettings"].should.have.property("injectSize", "100");
+ safeSettings["nodeSettings"].should.not.have.property("mqttColor");
+ safeSettings["nodeSettings"].should.have.property("mqttSize", "50");
+ safeSettings["nodeSettings"].should.have.property("httpRequest1", "a1");
+ safeSettings["nodeSettings"].should.have.property("httpRequest2", "a2");
+ safeSettings["nodeSettings"].should.have.property("httpRequest3", "a3");
+ safeSettings["nodeSettings"].should.have.property("mQtTColor", "purple");
+ safeSettings["nodeSettings"].should.have.property("abc123", "def456");
+ });
+
+ it('prohibits registering the property whose name do not start with type name', function() {
+ var userSettings = {};
+ settings.init(userSettings);
+ settings.registerNodeSettings("inject", {color:{value:"red", exportable:true}} );
+ settings.registerNodeSettings("_a_b_1_", {ab1Color:{value:"red", exportable:true}} );
+ settings.registerNodeSettings("AB2", {AB2Color:{value:"red", exportable:true}} );
+ settings.registerNodeSettings("abcDef", {abcColor:{value:"red", exportable:true}} );
+ var safeSettings = {};
+ settings.exportNodeSettings(safeSettings);
+ safeSettings["nodeSettings"].should.not.have.property("color");
+ safeSettings["nodeSettings"].should.not.have.property("ab1Color", "blue");
+ safeSettings["nodeSettings"].should.not.have.property("AB2Color");
+ safeSettings["nodeSettings"].should.not.have.property("abcColor");
+ });
+
+ it('overwrites node settings with user settings', function() {
+ var userSettings = {
+ injectColor: "green",
+ mqttColor: "yellow",
+ abColor: [1,2,3]
+ }
+ settings.init(userSettings);
+ settings.registerNodeSettings("inject", {injectColor:{value:"red", exportable:true}} );
+ settings.registerNodeSettings("ab", {abColor:{value:"red", exportable:false}} );
+ var safeSettings = {};
+ settings.exportNodeSettings(safeSettings);
+ safeSettings["nodeSettings"].should.have.property("injectColor", "green");
+ safeSettings["nodeSettings"].should.not.have.property("mqttColor");
+ safeSettings["nodeSettings"].should.not.have.property("abColor");
+ });
+
+ it('disables/enables node settings', function() {
+ var userSettings = {};
+ settings.init(userSettings);
+
+ var safeSettings = {};
+ settings.registerNodeSettings("inject", {injectColor:{value:"red", exportable:true}} );
+ settings.registerNodeSettings("mqtt", {mqttColor:{value:"purple", exportable:true}} );
+ settings.registerNodeSettings("http request", {httpRequestColor:{value:"yellow", exportable:true}} );
+ settings.exportNodeSettings(safeSettings);
+ safeSettings["nodeSettings"].should.have.property("injectColor", "red");
+ safeSettings["nodeSettings"].should.have.property("mqttColor", "purple");
+ safeSettings["nodeSettings"].should.have.property("httpRequestColor", "yellow");
+
+ var types = ["inject", "mqtt"];
+ settings.disableNodeSettings(types);
+ settings.exportNodeSettings(safeSettings);
+ safeSettings["nodeSettings"].should.not.have.property("injectColor");
+ safeSettings["nodeSettings"].should.not.have.property("mqttColor");
+ safeSettings["nodeSettings"].should.have.property("httpRequestColor", "yellow");
+
+ types = ["inject"];
+ settings.enableNodeSettings(types);
+ settings.exportNodeSettings(safeSettings);
+ safeSettings["nodeSettings"].should.have.property("injectColor", "red");
+ safeSettings["nodeSettings"].should.not.have.property("mqttColor");
+ safeSettings["nodeSettings"].should.have.property("httpRequestColor", "yellow");
+ });
+
});
diff --git a/test/red/runtime/util_spec.js b/test/red/runtime/util_spec.js
index 64c1dc6db..ffec6ce0b 100644
--- a/test/red/runtime/util_spec.js
+++ b/test/red/runtime/util_spec.js
@@ -364,4 +364,21 @@ describe("red/util", function() {
it("fail ",function() { testInvalid("");})
});
+
+ describe('normaliseNodeTypeName', function() {
+ function normalise(input, expected) {
+ var result = util.normaliseNodeTypeName(input);
+ result.should.eql(expected);
+ }
+
+ it('pass blank',function() { normalise("", "") });
+ it('pass ab1',function() { normalise("ab1", "ab1") });
+ it('pass AB1',function() { normalise("AB1", "aB1") });
+ it('pass a b 1',function() { normalise("a b 1", "aB1") });
+ it('pass a-b-1',function() { normalise("a-b-1", "aB1") });
+ it('pass ab1 ',function() { normalise(" ab1 ", "ab1") });
+ it('pass _a_b_1_',function() { normalise("_a_b_1_", "aB1") });
+ it('pass http request',function() { normalise("http request", "httpRequest") });
+ it('pass HttpRequest',function() { normalise("HttpRequest", "httpRequest") });
+ });
});