mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge branch 'dev' into pr_2971
This commit is contained in:
commit
a9164e63ab
@ -4,6 +4,9 @@ addons:
|
|||||||
language: node_js
|
language: node_js
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- node_js: "16"
|
||||||
|
script:
|
||||||
|
- ./node_modules/.bin/grunt no-coverage
|
||||||
- node_js: "14"
|
- node_js: "14"
|
||||||
script:
|
script:
|
||||||
- ./node_modules/.bin/grunt && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
|
- ./node_modules/.bin/grunt && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
|
||||||
|
66
CHANGELOG.md
66
CHANGELOG.md
@ -1,3 +1,69 @@
|
|||||||
|
### 1.3.4 Maintenance Release
|
||||||
|
|
||||||
|
Editor
|
||||||
|
- Allow nodes to access resolved theme files Fixes #2968
|
||||||
|
- Fix importing node to currently flow rather than match its old z value
|
||||||
|
- Don't let 'escape' whilst moving nodes interrupt things Fixes #2960
|
||||||
|
- Sort context stores in TypedInput and ensure default first Fixes #2954
|
||||||
|
- Fix margin between nodes on palette (#2947) @kazuhitoyokoi
|
||||||
|
- Ensure typedInput option is selected in dropdown menu Part of #2945
|
||||||
|
- Ensure typedInput without value has focus class removed Closes #2945
|
||||||
|
- TreeList: Fix remove item when depth=0 and wrong gutter calc (#2967) @hanc2006
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
- Handle subflow modules that contain subflows
|
||||||
|
- Timeout http upgrade requests that are not otherwise handled Fixes #2956
|
||||||
|
- Fix error on auto commit for no flow change (#2957) @HiroyasuNishiyama
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- CSV: Fix CSV handling of special chars as separators
|
||||||
|
- Delay: Give delay node random mina nd max more space so you can see complete value
|
||||||
|
- Exec: fix grunt fail on exec node test (#2964) @HiroyasuNishiyama
|
||||||
|
- Function: Ensure function expand button is above vertical scrollbar Fixes #2955
|
||||||
|
- Inject: Fix inject node output tooltip extra property count
|
||||||
|
|
||||||
|
|
||||||
|
### 1.3.3: Maintenance Release
|
||||||
|
|
||||||
|
Editor
|
||||||
|
|
||||||
|
- Fix package semver comparison to allow >1 version increment
|
||||||
|
- Prevent TypedInput label overflowing element Fixes #2941
|
||||||
|
- Remove TypedInput from tab focus when only one type available
|
||||||
|
- Make typedInput.disable more consistent in behaviour Fixes #2942
|
||||||
|
- Fix project credential secret reset handling Part of #2868
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
|
||||||
|
- Export package version in Grunt file so docs template can access
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- CSV: ensure CSV node can send false as string
|
||||||
|
- HTTPIn: handle application/x-protobuf as Buffer type (#2935 #2938) @hardillb
|
||||||
|
- MQTT: Ensure mqtt-close message is published when closing mqtt nodes
|
||||||
|
|
||||||
|
|
||||||
|
### 1.3.2: Maintenance Release
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
- Handle package.json without dependencies section
|
||||||
|
|
||||||
|
Editor
|
||||||
|
|
||||||
|
- Fix variable reference error in editableList Fixes #2933
|
||||||
|
- Fix handling of user-provided keymap Fixes #2926
|
||||||
|
- Ensure theme login image is passed through to api response Fixes #2929
|
||||||
|
- Add Japanese translations for Node-RED v1.3.1 (#2930) @kazuhitoyokoi
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- CSV: Fix CSV parsing with other than , separator
|
||||||
|
- File out: Fix timing of msg.send to be after close
|
||||||
|
- Function: describe `node.outputCount` in help text
|
||||||
|
- MQTT: Fix MQTT Broker TLS config row layout Fixes #2927
|
||||||
|
- Split: add comment to info re $N being number of messages arriving
|
||||||
|
|
||||||
### 1.3.1: Maintenance Release
|
### 1.3.1: Maintenance Release
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var fs = require("fs-extra");
|
var fs = require("fs-extra");
|
||||||
var sass = require("node-sass");
|
var sass = require("sass");
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
|
|
||||||
@ -137,6 +137,7 @@ module.exports = function(grunt) {
|
|||||||
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
|
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/red.js",
|
"packages/node_modules/@node-red/editor-client/src/js/red.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/events.js",
|
"packages/node_modules/@node-red/editor-client/src/js/events.js",
|
||||||
|
"packages/node_modules/@node-red/editor-client/src/js/hooks.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/i18n.js",
|
"packages/node_modules/@node-red/editor-client/src/js/i18n.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/settings.js",
|
"packages/node_modules/@node-red/editor-client/src/js/settings.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/user.js",
|
"packages/node_modules/@node-red/editor-client/src/js/user.js",
|
||||||
@ -487,7 +488,8 @@ module.exports = function(grunt) {
|
|||||||
],
|
],
|
||||||
options: {
|
options: {
|
||||||
destination: 'docs',
|
destination: 'docs',
|
||||||
configure: './jsdoc.json'
|
configure: './jsdoc.json',
|
||||||
|
fred: "hi there"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_editor: {
|
_editor: {
|
||||||
|
@ -106,8 +106,8 @@
|
|||||||
"minami": "1.2.3",
|
"minami": "1.2.3",
|
||||||
"mocha": "8.3.2",
|
"mocha": "8.3.2",
|
||||||
"node-red-node-test-helper": "^0.2.7",
|
"node-red-node-test-helper": "^0.2.7",
|
||||||
"node-sass": "^5.0.0",
|
|
||||||
"nodemon": "2.0.7",
|
"nodemon": "2.0.7",
|
||||||
|
"sass": "1.32.12",
|
||||||
"should": "13.2.3",
|
"should": "13.2.3",
|
||||||
"sinon": "10.0.1",
|
"sinon": "10.0.1",
|
||||||
"stoppable": "^1.1.0",
|
"stoppable": "^1.1.0",
|
||||||
|
@ -17,9 +17,8 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
|
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
|
||||||
if (/[^a-z\-\*]/i.test(opts.lang)) {
|
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
|
||||||
res.json({});
|
opts.lang = "en-US";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
runtimeAPI.plugins.getPluginConfigs(opts).then(function(configs) {
|
runtimeAPI.plugins.getPluginConfigs(opts).then(function(configs) {
|
||||||
res.send(configs);
|
res.send(configs);
|
||||||
@ -32,9 +31,8 @@ module.exports = {
|
|||||||
lang: req.query.lng,
|
lang: req.query.lng,
|
||||||
req: apiUtils.getRequestLogObject(req)
|
req: apiUtils.getRequestLogObject(req)
|
||||||
}
|
}
|
||||||
if (/[^a-z\-\*]/i.test(opts.lang)) {
|
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
|
||||||
res.json({});
|
opts.lang = "en-US";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
runtimeAPI.plugins.getPluginCatalogs(opts).then(function(result) {
|
runtimeAPI.plugins.getPluginCatalogs(opts).then(function(result) {
|
||||||
res.json(result);
|
res.json(result);
|
||||||
|
@ -90,7 +90,7 @@ function getToken(req,res,next) {
|
|||||||
return server.token()(req,res,next);
|
return server.token()(req,res,next);
|
||||||
}
|
}
|
||||||
|
|
||||||
function login(req,res) {
|
async function login(req,res) {
|
||||||
var response = {};
|
var response = {};
|
||||||
if (settings.adminAuth) {
|
if (settings.adminAuth) {
|
||||||
var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module);
|
var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module);
|
||||||
@ -116,8 +116,9 @@ function login(req,res) {
|
|||||||
response.prompts[0].image = theme.serveFile('/login/',mergedAdminAuth.strategy.image);
|
response.prompts[0].image = theme.serveFile('/login/',mergedAdminAuth.strategy.image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (theme.context().login && theme.context().login.image) {
|
let themeContext = await theme.context();
|
||||||
response.image = theme.context().login.image;
|
if (themeContext.login && themeContext.login.image) {
|
||||||
|
response.image = themeContext.login.image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.json(response);
|
res.json(response);
|
||||||
|
@ -130,6 +130,14 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
themeContext.page.title = theme.page.title || themeContext.page.title;
|
themeContext.page.title = theme.page.title || themeContext.page.title;
|
||||||
|
|
||||||
|
// Store the resolved urls to these resources so nodes (such as Debug)
|
||||||
|
// can access them
|
||||||
|
theme.page._ = {
|
||||||
|
css: themeContext.page.css,
|
||||||
|
scripts: themeContext.page.scripts,
|
||||||
|
favicon: themeContext.page.favicon
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theme.header) {
|
if (theme.header) {
|
||||||
@ -224,6 +232,8 @@ module.exports = {
|
|||||||
themePlugin.path
|
themePlugin.path
|
||||||
);
|
);
|
||||||
themeContext.page.css = cssFiles.concat(themeContext.page.css || [])
|
themeContext.page.css = cssFiles.concat(themeContext.page.css || [])
|
||||||
|
theme.page = theme.page || {_:{}}
|
||||||
|
theme.page._.css = cssFiles.concat(theme.page._.css || [])
|
||||||
}
|
}
|
||||||
if (themePlugin.scripts) {
|
if (themePlugin.scripts) {
|
||||||
const scriptFiles = serveFilesFromTheme(
|
const scriptFiles = serveFilesFromTheme(
|
||||||
@ -233,6 +243,8 @@ module.exports = {
|
|||||||
themePlugin.path
|
themePlugin.path
|
||||||
)
|
)
|
||||||
themeContext.page.scripts = scriptFiles.concat(themeContext.page.scripts || [])
|
themeContext.page.scripts = scriptFiles.concat(themeContext.page.scripts || [])
|
||||||
|
theme.page = theme.page || {_:{}}
|
||||||
|
theme.page._.scripts = cssFiles.concat(theme.page._.scripts || [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activeThemeInitialised = true;
|
activeThemeInitialised = true;
|
||||||
|
@ -524,8 +524,8 @@
|
|||||||
"title": "パレットの管理",
|
"title": "パレットの管理",
|
||||||
"palette": "パレット",
|
"palette": "パレット",
|
||||||
"times": {
|
"times": {
|
||||||
"seconds": "秒前",
|
"seconds": "数秒前",
|
||||||
"minutes": "分前",
|
"minutes": "数分前",
|
||||||
"minutesV": "__count__ 分前",
|
"minutesV": "__count__ 分前",
|
||||||
"hoursV": "__count__ 時間前",
|
"hoursV": "__count__ 時間前",
|
||||||
"hoursV_plural": "__count__ 時間前",
|
"hoursV_plural": "__count__ 時間前",
|
||||||
|
156
packages/node_modules/@node-red/editor-client/src/js/hooks.js
vendored
Normal file
156
packages/node_modules/@node-red/editor-client/src/js/hooks.js
vendored
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
RED.hooks = (function() {
|
||||||
|
|
||||||
|
var VALID_HOOKS = [
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
var hooks = { }
|
||||||
|
var labelledHooks = { }
|
||||||
|
|
||||||
|
function add(hookId, callback) {
|
||||||
|
var parts = hookId.split(".");
|
||||||
|
var id = parts[0], label = parts[1];
|
||||||
|
|
||||||
|
// if (VALID_HOOKS.indexOf(id) === -1) {
|
||||||
|
// throw new Error("Invalid hook '"+id+"'");
|
||||||
|
// }
|
||||||
|
if (label && labelledHooks[label] && labelledHooks[label][id]) {
|
||||||
|
throw new Error("Hook "+hookId+" already registered")
|
||||||
|
}
|
||||||
|
var hookItem = {cb:callback, previousHook: null, nextHook: null }
|
||||||
|
|
||||||
|
var tailItem = hooks[id];
|
||||||
|
if (tailItem === undefined) {
|
||||||
|
hooks[id] = hookItem;
|
||||||
|
} else {
|
||||||
|
while(tailItem.nextHook !== null) {
|
||||||
|
tailItem = tailItem.nextHook
|
||||||
|
}
|
||||||
|
tailItem.nextHook = hookItem;
|
||||||
|
hookItem.previousHook = tailItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (label) {
|
||||||
|
labelledHooks[label] = labelledHooks[label]||{};
|
||||||
|
labelledHooks[label][id] = hookItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function remove(hookId) {
|
||||||
|
var parts = hookId.split(".");
|
||||||
|
var id = parts[0], label = parts[1];
|
||||||
|
if ( !label) {
|
||||||
|
throw new Error("Cannot remove hook without label: "+hookId)
|
||||||
|
}
|
||||||
|
if (labelledHooks[label]) {
|
||||||
|
if (id === "*") {
|
||||||
|
// Remove all hooks for this label
|
||||||
|
var hookList = Object.keys(labelledHooks[label]);
|
||||||
|
for (var i=0;i<hookList.length;i++) {
|
||||||
|
removeHook(hookList[i],labelledHooks[label][hookList[i]])
|
||||||
|
}
|
||||||
|
delete labelledHooks[label];
|
||||||
|
} else if (labelledHooks[label][id]) {
|
||||||
|
removeHook(id,labelledHooks[label][id])
|
||||||
|
delete labelledHooks[label][id];
|
||||||
|
if (Object.keys(labelledHooks[label]).length === 0){
|
||||||
|
delete labelledHooks[label];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeHook(id,hookItem) {
|
||||||
|
var previousHook = hookItem.previousHook;
|
||||||
|
var nextHook = hookItem.nextHook;
|
||||||
|
|
||||||
|
if (previousHook) {
|
||||||
|
previousHook.nextHook = nextHook;
|
||||||
|
} else {
|
||||||
|
hooks[id] = nextHook;
|
||||||
|
}
|
||||||
|
if (nextHook) {
|
||||||
|
nextHook.previousHook = previousHook;
|
||||||
|
}
|
||||||
|
hookItem.removed = true;
|
||||||
|
if (!previousHook && !nextHook) {
|
||||||
|
delete hooks[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function trigger(hookId, payload, done) {
|
||||||
|
var hookItem = hooks[hookId];
|
||||||
|
if (!hookItem) {
|
||||||
|
if (done) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
function callNextHook(err) {
|
||||||
|
if (!hookItem || err) {
|
||||||
|
if (done) { done(err) }
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (hookItem.removed) {
|
||||||
|
hookItem = hookItem.nextHook;
|
||||||
|
return callNextHook();
|
||||||
|
}
|
||||||
|
var callback = hookItem.cb;
|
||||||
|
if (callback.length === 1) {
|
||||||
|
try {
|
||||||
|
let result = callback(payload);
|
||||||
|
if (result === false) {
|
||||||
|
// Halting the flow
|
||||||
|
if (done) { done(false) }
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
hookItem = hookItem.nextHook;
|
||||||
|
return callNextHook();
|
||||||
|
} catch(e) {
|
||||||
|
console.warn(e);
|
||||||
|
if (done) { done(e);}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// There is a done callback
|
||||||
|
try {
|
||||||
|
callback(payload,function(result) {
|
||||||
|
if (result === undefined) {
|
||||||
|
hookItem = hookItem.nextHook;
|
||||||
|
callNextHook();
|
||||||
|
} else {
|
||||||
|
if (done) { done(result)}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch(e) {
|
||||||
|
console.warn(e);
|
||||||
|
if (done) { done(e) }
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return callNextHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
hooks = {}
|
||||||
|
labelledHooks = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function has(hookId) {
|
||||||
|
var parts = hookId.split(".");
|
||||||
|
var id = parts[0], label = parts[1];
|
||||||
|
if (label) {
|
||||||
|
return !!(labelledHooks[label] && labelledHooks[label][id])
|
||||||
|
}
|
||||||
|
return !!hooks[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
has: has,
|
||||||
|
clear: clear,
|
||||||
|
add: add,
|
||||||
|
remove: remove,
|
||||||
|
trigger: trigger
|
||||||
|
}
|
||||||
|
})();
|
@ -86,6 +86,10 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
addNodeSet: function(ns) {
|
addNodeSet: function(ns) {
|
||||||
|
if (!ns.types) {
|
||||||
|
// A node has been loaded without any types. Ignore it.
|
||||||
|
return;
|
||||||
|
}
|
||||||
ns.added = false;
|
ns.added = false;
|
||||||
nodeSets[ns.id] = ns;
|
nodeSets[ns.id] = ns;
|
||||||
for (var j=0;j<ns.types.length;j++) {
|
for (var j=0;j<ns.types.length;j++) {
|
||||||
@ -1424,6 +1428,8 @@ RED.nodes = (function() {
|
|||||||
nid = getID();
|
nid = getID();
|
||||||
workspace_map[n.id] = nid;
|
workspace_map[n.id] = nid;
|
||||||
n.id = nid;
|
n.id = nid;
|
||||||
|
} else {
|
||||||
|
workspace_map[n.id] = n.id;
|
||||||
}
|
}
|
||||||
addWorkspace(n);
|
addWorkspace(n);
|
||||||
RED.workspaces.add(n);
|
RED.workspaces.add(n);
|
||||||
@ -1523,7 +1529,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (n.z && !workspaces[n.z] && !subflow_map[n.z]) {
|
if (n.z && !workspace_map[n.z] && !subflow_map[n.z]) {
|
||||||
n.z = activeWorkspace;
|
n.z = activeWorkspace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1621,7 +1627,7 @@ RED.nodes = (function() {
|
|||||||
node.id = getID();
|
node.id = getID();
|
||||||
} else {
|
} else {
|
||||||
node.id = n.id;
|
node.id = n.id;
|
||||||
if (node.z == null || (!workspaces[node.z] && !subflow_map[node.z])) {
|
if (node.z == null || (!workspace_map[node.z] && !subflow_map[node.z])) {
|
||||||
if (createMissingWorkspace) {
|
if (createMissingWorkspace) {
|
||||||
if (missingWorkspace === null) {
|
if (missingWorkspace === null) {
|
||||||
missingWorkspace = RED.workspaces.add(null,true);
|
missingWorkspace = RED.workspaces.add(null,true);
|
||||||
|
@ -1186,22 +1186,6 @@ RED.clipboard = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeLabelText(n) {
|
|
||||||
var label = n.name || n.type+": "+n.id;
|
|
||||||
if (n._def.label) {
|
|
||||||
try {
|
|
||||||
label = (typeof n._def.label === "function" ? n._def.label.call(n) : n._def.label)||"";
|
|
||||||
} catch(err) {
|
|
||||||
console.log("Definition error: "+n.type+".label",err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var newlineIndex = label.indexOf("\\n");
|
|
||||||
if (newlineIndex > -1) {
|
|
||||||
label = label.substring(0,newlineIndex)+"...";
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFlowLabel(n) {
|
function getFlowLabel(n) {
|
||||||
n = JSON.parse(JSON.stringify(n));
|
n = JSON.parse(JSON.stringify(n));
|
||||||
n._def = RED.nodes.getType(n.type) || {};
|
n._def = RED.nodes.getType(n.type) || {};
|
||||||
@ -1227,16 +1211,8 @@ RED.clipboard = (function() {
|
|||||||
if (n._def) {
|
if (n._def) {
|
||||||
n._ = n._def._;
|
n._ = n._def._;
|
||||||
}
|
}
|
||||||
var div = $('<div>',{class:"red-ui-info-outline-item"});
|
var div = $('<div>',{class:"red-ui-node-list-item"});
|
||||||
RED.utils.createNodeIcon(n).appendTo(div);
|
RED.utils.createNodeIcon(n,true).appendTo(div);
|
||||||
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
|
||||||
var labelText = getNodeLabelText(n);
|
|
||||||
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
|
|
||||||
if (labelText) {
|
|
||||||
label.text(labelText)
|
|
||||||
} else {
|
|
||||||
label.html(n.type)
|
|
||||||
}
|
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1284,22 +1260,27 @@ RED.clipboard = (function() {
|
|||||||
hideDropTarget();
|
hideDropTarget();
|
||||||
})
|
})
|
||||||
.on("drop",function(event) {
|
.on("drop",function(event) {
|
||||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
try {
|
||||||
var data = event.originalEvent.dataTransfer.getData("text/plain");
|
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
||||||
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
|
var data = event.originalEvent.dataTransfer.getData("text/plain");
|
||||||
importNodes(data);
|
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
|
||||||
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
|
importNodes(data);
|
||||||
var files = event.originalEvent.dataTransfer.files;
|
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
|
||||||
if (files.length === 1) {
|
var files = event.originalEvent.dataTransfer.files;
|
||||||
var file = files[0];
|
if (files.length === 1) {
|
||||||
var reader = new FileReader();
|
var file = files[0];
|
||||||
reader.onload = (function(theFile) {
|
var reader = new FileReader();
|
||||||
return function(e) {
|
reader.onload = (function(theFile) {
|
||||||
importNodes(e.target.result);
|
return function(e) {
|
||||||
};
|
importNodes(e.target.result);
|
||||||
})(file);
|
};
|
||||||
reader.readAsText(file);
|
})(file);
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch(err) {
|
||||||
|
// Ensure any errors throw above doesn't stop the drop target from
|
||||||
|
// being hidden.
|
||||||
}
|
}
|
||||||
hideDropTarget();
|
hideDropTarget();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
var buttons = this.options.buttons || [];
|
var buttons = this.options.buttons || [];
|
||||||
|
|
||||||
if (this.options.addButton !== false) {
|
if (this.options.addButton !== false) {
|
||||||
var addLabel, addTittle;
|
var addLabel, addTitle;
|
||||||
if (typeof this.options.addButton === 'string') {
|
if (typeof this.options.addButton === 'string') {
|
||||||
addLabel = this.options.addButton
|
addLabel = this.options.addButton
|
||||||
} else {
|
} else {
|
||||||
@ -102,7 +102,7 @@
|
|||||||
button.click(evt);
|
button.click(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (button.title) {
|
if (button.title) {
|
||||||
element.attr("title", button.title);
|
element.attr("title", button.title);
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@
|
|||||||
element.append($("<span></span>").text(" " + button.label));
|
element.append($("<span></span>").text(" " + button.label));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.element.css("position") === "absolute") {
|
if (this.element.css("position") === "absolute") {
|
||||||
["top","left","bottom","right"].forEach(function(s) {
|
["top","left","bottom","right"].forEach(function(s) {
|
||||||
var v = that.element.css(s);
|
var v = that.element.css(s);
|
||||||
|
@ -100,7 +100,22 @@ RED.tabs = (function() {
|
|||||||
if (options.scrollable) {
|
if (options.scrollable) {
|
||||||
wrapper.addClass("red-ui-tabs-scrollable");
|
wrapper.addClass("red-ui-tabs-scrollable");
|
||||||
scrollContainer.addClass("red-ui-tabs-scroll-container");
|
scrollContainer.addClass("red-ui-tabs-scroll-container");
|
||||||
scrollContainer.on("scroll",updateScroll);
|
scrollContainer.on("scroll",function(evt) {
|
||||||
|
// Generated by trackpads - not mousewheel
|
||||||
|
updateScroll(evt);
|
||||||
|
});
|
||||||
|
scrollContainer.on("wheel", function(evt) {
|
||||||
|
if (evt.originalEvent.deltaX === 0) {
|
||||||
|
// Prevent the scroll event from firing
|
||||||
|
evt.preventDefault();
|
||||||
|
|
||||||
|
// Assume this is wheel event which might not trigger
|
||||||
|
// the scroll event, so do things manually
|
||||||
|
var sl = scrollContainer.scrollLeft();
|
||||||
|
sl -= evt.originalEvent.deltaY;
|
||||||
|
scrollContainer.scrollLeft(sl);
|
||||||
|
}
|
||||||
|
})
|
||||||
scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a");
|
scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a");
|
||||||
scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();});
|
scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||||
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
|
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
|
||||||
@ -770,6 +785,9 @@ RED.tabs = (function() {
|
|||||||
count: function() {
|
count: function() {
|
||||||
return ul.find("li.red-ui-tab").length;
|
return ul.find("li.red-ui-tab").length;
|
||||||
},
|
},
|
||||||
|
activeIndex: function() {
|
||||||
|
return ul.find("li.active").index()
|
||||||
|
},
|
||||||
contains: function(id) {
|
contains: function(id) {
|
||||||
return ul.find("a[href='#"+id+"']").length > 0;
|
return ul.find("a[href='#"+id+"']").length > 0;
|
||||||
},
|
},
|
||||||
|
@ -312,6 +312,7 @@
|
|||||||
}
|
}
|
||||||
if (child.depth !== parent.depth+1) {
|
if (child.depth !== parent.depth+1) {
|
||||||
child.depth = parent.depth+1;
|
child.depth = parent.depth+1;
|
||||||
|
// var labelPaddingWidth = ((child.gutter ? child.gutter[0].offsetWidth + 2 : 0) + (child.depth * 20));
|
||||||
var labelPaddingWidth = ((child.gutter?child.gutter.width()+2:0)+(child.depth*20));
|
var labelPaddingWidth = ((child.gutter?child.gutter.width()+2:0)+(child.depth*20));
|
||||||
child.treeList.labelPadding.width(labelPaddingWidth+'px');
|
child.treeList.labelPadding.width(labelPaddingWidth+'px');
|
||||||
if (child.element) {
|
if (child.element) {
|
||||||
@ -348,6 +349,18 @@
|
|||||||
that._selected.delete(item);
|
that._selected.delete(item);
|
||||||
delete item.treeList;
|
delete item.treeList;
|
||||||
delete that._items[item.id];
|
delete that._items[item.id];
|
||||||
|
if(item.depth === 0) {
|
||||||
|
for(var key in that._items) {
|
||||||
|
if (that._items.hasOwnProperty(key)) {
|
||||||
|
var child = that._items[key];
|
||||||
|
if(child.parent && child.parent.id === item.id) {
|
||||||
|
delete that._items[key].treeList;
|
||||||
|
delete that._items[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
that._data = that._data.filter(function(data) { return data.id !== item.id})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
item.treeList.insertChildAt = function(newItem,position,select) {
|
item.treeList.insertChildAt = function(newItem,position,select) {
|
||||||
newItem.parent = item;
|
newItem.parent = item;
|
||||||
@ -480,7 +493,10 @@
|
|||||||
if (item.treeList.container) {
|
if (item.treeList.container) {
|
||||||
$(item.element).remove();
|
$(item.element).remove();
|
||||||
$(element).appendTo(item.treeList.label);
|
$(element).appendTo(item.treeList.label);
|
||||||
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(item.depth*20);
|
// using the JQuery Object, the gutter width will
|
||||||
|
// be wrong when the element is reattached the second time
|
||||||
|
var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (item.depth * 20);
|
||||||
|
|
||||||
$(element).css({
|
$(element).css({
|
||||||
width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
|
width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
|
||||||
})
|
})
|
||||||
@ -517,6 +533,7 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20);
|
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20);
|
||||||
|
// var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (depth * 20)
|
||||||
item.treeList.labelPadding = $('<span>').css({
|
item.treeList.labelPadding = $('<span>').css({
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
width: labelPaddingWidth+'px'
|
width: labelPaddingWidth+'px'
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
**/
|
**/
|
||||||
(function($) {
|
(function($) {
|
||||||
var contextParse = function(v,defaultStore) {
|
var contextParse = function(v,defaultStore) {
|
||||||
var parts = RED.utils.parseContextKey(v, defaultStore);
|
var parts = RED.utils.parseContextKey(v, defaultStore&&defaultStore.value);
|
||||||
return {
|
return {
|
||||||
option: parts.store,
|
option: parts.store,
|
||||||
value: parts.key
|
value: parts.key
|
||||||
@ -279,6 +279,14 @@
|
|||||||
var contextStores = RED.settings.context.stores;
|
var contextStores = RED.settings.context.stores;
|
||||||
var contextOptions = contextStores.map(function(store) {
|
var contextOptions = contextStores.map(function(store) {
|
||||||
return {value:store,label: store, icon:'<i class="red-ui-typedInput-icon fa fa-database"></i>'}
|
return {value:store,label: store, icon:'<i class="red-ui-typedInput-icon fa fa-database"></i>'}
|
||||||
|
}).sort(function(A,B) {
|
||||||
|
if (A.value === RED.settings.context.default) {
|
||||||
|
return -1;
|
||||||
|
} else if (B.value === RED.settings.context.default) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return A.value.localeCompare(B.value);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if (contextOptions.length < 2) {
|
if (contextOptions.length < 2) {
|
||||||
allOptions.flow.options = [];
|
allOptions.flow.options = [];
|
||||||
@ -389,6 +397,11 @@
|
|||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
}).on('focus', function() {
|
}).on('focus', function() {
|
||||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||||
|
}).on('blur', function() {
|
||||||
|
var opt = that.typeMap[that.propertyType];
|
||||||
|
if (opt.hasValue === false) {
|
||||||
|
that.uiSelect.removeClass('red-ui-typedInput-focus');
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
|
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
|
||||||
@ -438,7 +451,11 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._showMenu(this.optionMenu,this.optionSelectTrigger);
|
this._showMenu(this.optionMenu,this.optionSelectTrigger);
|
||||||
var selectedOption = this.optionMenu.find("[value='"+this.optionValue+"']");
|
var targetValue = this.optionValue;
|
||||||
|
if (this.optionValue === null || this.optionValue === undefined) {
|
||||||
|
targetValue = this.value();
|
||||||
|
}
|
||||||
|
var selectedOption = this.optionMenu.find("[value='"+targetValue+"']");
|
||||||
if (selectedOption.length === 0) {
|
if (selectedOption.length === 0) {
|
||||||
selectedOption = this.optionMenu.children(":first");
|
selectedOption = this.optionMenu.children(":first");
|
||||||
}
|
}
|
||||||
@ -669,6 +686,11 @@
|
|||||||
that.typeMap[result.value] = result;
|
that.typeMap[result.value] = result;
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
if (this.typeList.length < 2) {
|
||||||
|
this.selectTrigger.attr("tabindex", -1)
|
||||||
|
} else {
|
||||||
|
this.selectTrigger.attr("tabindex", 0)
|
||||||
|
}
|
||||||
this.selectTrigger.toggleClass("disabled", this.typeList.length === 1);
|
this.selectTrigger.toggleClass("disabled", this.typeList.length === 1);
|
||||||
this.selectTrigger.find(".fa-caret-down").toggle(this.typeList.length > 1)
|
this.selectTrigger.find(".fa-caret-down").toggle(this.typeList.length > 1)
|
||||||
if (this.menu) {
|
if (this.menu) {
|
||||||
@ -768,6 +790,11 @@
|
|||||||
if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) {
|
if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) {
|
||||||
this.selectLabel.text(opt.label);
|
this.selectLabel.text(opt.label);
|
||||||
}
|
}
|
||||||
|
if (opt.label) {
|
||||||
|
this.selectTrigger.attr("title",opt.label);
|
||||||
|
} else {
|
||||||
|
this.selectTrigger.attr("title","");
|
||||||
|
}
|
||||||
if (opt.hasValue === false) {
|
if (opt.hasValue === false) {
|
||||||
this.selectTrigger.addClass("red-ui-typedInput-full-width");
|
this.selectTrigger.addClass("red-ui-typedInput-full-width");
|
||||||
} else {
|
} else {
|
||||||
@ -1004,16 +1031,17 @@
|
|||||||
this.uiSelect.hide();
|
this.uiSelect.hide();
|
||||||
},
|
},
|
||||||
disable: function(val) {
|
disable: function(val) {
|
||||||
if(val === true) {
|
if(val === undefined || !!val ) {
|
||||||
this.uiSelect.attr("disabled", "disabled");
|
this.uiSelect.attr("disabled", "disabled");
|
||||||
} else if (val === false) {
|
|
||||||
this.uiSelect.attr("disabled", null); //remove attr
|
|
||||||
} else {
|
} else {
|
||||||
this.uiSelect.attr("disabled", val); //user value
|
this.uiSelect.attr("disabled", null); //remove attr
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
enable: function() {
|
||||||
|
this.uiSelect.attr("disabled", null); //remove attr
|
||||||
|
},
|
||||||
disabled: function() {
|
disabled: function() {
|
||||||
return this.uiSelect.attr("disabled");
|
return this.uiSelect.attr("disabled") === "disabled";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
@ -119,7 +119,7 @@ RED.keyboard = (function() {
|
|||||||
} else {
|
} else {
|
||||||
mergedKeymap[action] = [{
|
mergedKeymap[action] = [{
|
||||||
scope: themeKeymap[action].scope || "*",
|
scope: themeKeymap[action].scope || "*",
|
||||||
key: [themeKeymap[action].key],
|
key: themeKeymap[action].key,
|
||||||
user: false
|
user: false
|
||||||
}]
|
}]
|
||||||
if (mergedKeymap[action][0].scope === "workspace") {
|
if (mergedKeymap[action][0].scope === "workspace") {
|
||||||
|
@ -331,7 +331,7 @@ RED.palette.editor = (function() {
|
|||||||
nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow)
|
nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow)
|
||||||
nodeEntry.updateButton.text(RED._('palette.editor.updated')).addClass('disabled').css('display', 'inline-block');
|
nodeEntry.updateButton.text(RED._('palette.editor.updated')).addClass('disabled').css('display', 'inline-block');
|
||||||
} else if (loadedIndex.hasOwnProperty(module)) {
|
} else if (loadedIndex.hasOwnProperty(module)) {
|
||||||
if (semVerCompare(loadedIndex[module].version,moduleInfo.version) === 1) {
|
if (semVerCompare(loadedIndex[module].version,moduleInfo.version) > 0) {
|
||||||
nodeEntry.updateButton.show();
|
nodeEntry.updateButton.show();
|
||||||
nodeEntry.updateButton.text(RED._('palette.editor.update',{version:loadedIndex[module].version}));
|
nodeEntry.updateButton.text(RED._('palette.editor.update',{version:loadedIndex[module].version}));
|
||||||
} else {
|
} else {
|
||||||
|
@ -320,12 +320,12 @@ RED.palette = (function() {
|
|||||||
var paletteNode = getPaletteNode(nt);
|
var paletteNode = getPaletteNode(nt);
|
||||||
ui.originalPosition.left = paletteNode.offset().left;
|
ui.originalPosition.left = paletteNode.offset().left;
|
||||||
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
|
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
|
||||||
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop();
|
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop() + 10;
|
||||||
if (!groupTimer) {
|
if (!groupTimer) {
|
||||||
groupTimer = setTimeout(function() {
|
groupTimer = setTimeout(function() {
|
||||||
mouseX /= RED.view.scale();
|
var mx = mouseX / RED.view.scale();
|
||||||
mouseY /= RED.view.scale();
|
var my = mouseY / RED.view.scale();
|
||||||
var group = RED.view.getGroupAtPoint(mouseX,mouseY);
|
var group = RED.view.getGroupAtPoint(mx,my);
|
||||||
if (group !== hoverGroup) {
|
if (group !== hoverGroup) {
|
||||||
if (hoverGroup) {
|
if (hoverGroup) {
|
||||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||||
@ -357,23 +357,20 @@ RED.palette = (function() {
|
|||||||
svgRect.width = 1;
|
svgRect.width = 1;
|
||||||
svgRect.height = 1;
|
svgRect.height = 1;
|
||||||
nodes = chartSVG.getIntersectionList(svgRect,chartSVG);
|
nodes = chartSVG.getIntersectionList(svgRect,chartSVG);
|
||||||
mouseX /= RED.view.scale();
|
|
||||||
mouseY /= RED.view.scale();
|
|
||||||
} else {
|
} else {
|
||||||
// Firefox doesn't do getIntersectionList and that
|
// Firefox doesn't do getIntersectionList and that
|
||||||
// makes us sad
|
// makes us sad
|
||||||
mouseX /= RED.view.scale();
|
|
||||||
mouseY /= RED.view.scale();
|
|
||||||
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
|
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
|
||||||
}
|
}
|
||||||
|
var mx = mouseX / RED.view.scale();
|
||||||
|
var my = mouseY / RED.view.scale();
|
||||||
for (var i=0;i<nodes.length;i++) {
|
for (var i=0;i<nodes.length;i++) {
|
||||||
var node = d3.select(nodes[i]);
|
var node = d3.select(nodes[i]);
|
||||||
if (node.classed('red-ui-flow-link-background') && !node.classed('red-ui-flow-link-link')) {
|
if (node.classed('red-ui-flow-link-background') && !node.classed('red-ui-flow-link-link')) {
|
||||||
var length = nodes[i].getTotalLength();
|
var length = nodes[i].getTotalLength();
|
||||||
for (var j=0;j<length;j+=10) {
|
for (var j=0;j<length;j+=10) {
|
||||||
var p = nodes[i].getPointAtLength(j);
|
var p = nodes[i].getPointAtLength(j);
|
||||||
var d2 = ((p.x-mouseX)*(p.x-mouseX))+((p.y-mouseY)*(p.y-mouseY));
|
var d2 = ((p.x-mx)*(p.x-mx))+((p.y-my)*(p.y-my));
|
||||||
if (d2 < 200 && d2 < bestDistance) {
|
if (d2 < 200 && d2 < bestDistance) {
|
||||||
bestDistance = d2;
|
bestDistance = d2;
|
||||||
bestLink = nodes[i];
|
bestLink = nodes[i];
|
||||||
|
@ -928,11 +928,11 @@ RED.projects.settings = (function() {
|
|||||||
|
|
||||||
saveDisabled = isFlowInvalid || credFileLabelText.text()==="";
|
saveDisabled = isFlowInvalid || credFileLabelText.text()==="";
|
||||||
|
|
||||||
if (credentialSecretExistingInput.is(":visible")) {
|
if (credentialSecretExistingRow.is(":visible")) {
|
||||||
credentialSecretExistingInput.toggleClass("input-error", credentialSecretExistingInput.val() === "");
|
credentialSecretExistingInput.toggleClass("input-error", credentialSecretExistingInput.val() === "");
|
||||||
saveDisabled = saveDisabled || credentialSecretExistingInput.val() === "";
|
saveDisabled = saveDisabled || credentialSecretExistingInput.val() === "";
|
||||||
}
|
}
|
||||||
if (credentialSecretNewInput.is(":visible")) {
|
if (credentialSecretNewRow.is(":visible")) {
|
||||||
credentialSecretNewInput.toggleClass("input-error", credentialSecretNewInput.val() === "");
|
credentialSecretNewInput.toggleClass("input-error", credentialSecretNewInput.val() === "");
|
||||||
saveDisabled = saveDisabled || credentialSecretNewInput.val() === "";
|
saveDisabled = saveDisabled || credentialSecretNewInput.val() === "";
|
||||||
}
|
}
|
||||||
@ -1130,7 +1130,7 @@ RED.projects.settings = (function() {
|
|||||||
}
|
}
|
||||||
if (credentialSecretResetButton.hasClass('selected') || credentialSecretEditButton.hasClass('selected')) {
|
if (credentialSecretResetButton.hasClass('selected') || credentialSecretEditButton.hasClass('selected')) {
|
||||||
payload.credentialSecret = credentialSecretNewInput.val();
|
payload.credentialSecret = credentialSecretNewInput.val();
|
||||||
if (credentialSecretExistingInput.is(":visible")) {
|
if (credentialSecretExistingRow.is(":visible")) {
|
||||||
payload.currentCredentialSecret = credentialSecretExistingInput.val();
|
payload.currentCredentialSecret = credentialSecretExistingInput.val();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ RED.sidebar = (function() {
|
|||||||
id = RED.settings.get("editor.sidebar.order",["info", "help", "version-control", "debug"])[0]
|
id = RED.settings.get("editor.sidebar.order",["info", "help", "version-control", "debug"])[0]
|
||||||
}
|
}
|
||||||
if (id) {
|
if (id) {
|
||||||
if (!containsTab(id)) {
|
if (!containsTab(id) && knownTabs[id]) {
|
||||||
sidebar_tabs.addTab(knownTabs[id]);
|
sidebar_tabs.addTab(knownTabs[id]);
|
||||||
}
|
}
|
||||||
sidebar_tabs.activateTab(id);
|
sidebar_tabs.activateTab(id);
|
||||||
|
@ -230,10 +230,17 @@ RED.sidebar.help = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getNodeLabel(n) {
|
function getNodeLabel(n) {
|
||||||
var div = $('<div>',{class:"red-ui-info-outline-item"});
|
var div = $('<div>',{class:"red-ui-node-list-item"});
|
||||||
RED.utils.createNodeIcon(n).appendTo(div);
|
RED.utils.createNodeIcon(n).appendTo(div);
|
||||||
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
var label = n.name;
|
||||||
$('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).text(n.name||n._def.paletteLabel||n.type).appendTo(contentDiv);
|
if (!label && n._def.paletteLabel) {
|
||||||
|
try {
|
||||||
|
label = (typeof n._def.paletteLabel === "function" ? n._def.paletteLabel.call(n._def) : n._def.paletteLabel)||"";
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label = label || n.type;
|
||||||
|
$('<div>',{class:"red-ui-node-label"}).text(n.name||n.type).appendTo(div);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,6 +257,13 @@ RED.sidebar.help = (function() {
|
|||||||
helpText = RED.nodes.getNodeHelp(nodeType)||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
|
helpText = RED.nodes.getNodeHelp(nodeType)||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
|
||||||
var _def = RED.nodes.registry.getNodeType(nodeType);
|
var _def = RED.nodes.registry.getNodeType(nodeType);
|
||||||
title = (_def && _def.paletteLabel)?_def.paletteLabel:nodeType;
|
title = (_def && _def.paletteLabel)?_def.paletteLabel:nodeType;
|
||||||
|
if (typeof title === "function") {
|
||||||
|
try {
|
||||||
|
title = _def.paletteLabel.call(_def);
|
||||||
|
} catch(err) {
|
||||||
|
title = nodeType;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setInfoText(title, helpText, helpSection);
|
setInfoText(title, helpText, helpSection);
|
||||||
|
|
||||||
|
@ -73,36 +73,11 @@ RED.sidebar.info.outliner = (function() {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeLabelText(n) {
|
|
||||||
var label = n.name || n.type+": "+n.id;
|
|
||||||
if (n._def.label) {
|
|
||||||
try {
|
|
||||||
label = (typeof n._def.label === "function" ? n._def.label.call(n) : n._def.label)||"";
|
|
||||||
} catch(err) {
|
|
||||||
console.log("Definition error: "+n.type+".label",err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var newlineIndex = label.indexOf("\\n");
|
|
||||||
if (newlineIndex > -1) {
|
|
||||||
label = label.substring(0,newlineIndex)+"...";
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNodeLabel(n) {
|
function getNodeLabel(n) {
|
||||||
var div = $('<div>',{class:"red-ui-info-outline-item"});
|
var div = $('<div>',{class:"red-ui-node-list-item red-ui-info-outline-item"});
|
||||||
RED.utils.createNodeIcon(n).appendTo(div);
|
RED.utils.createNodeIcon(n, true).appendTo(div);
|
||||||
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
div.find(".red-ui-node-label").addClass("red-ui-info-outline-item-label")
|
||||||
var labelText = getNodeLabelText(n);
|
|
||||||
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
|
|
||||||
if (labelText) {
|
|
||||||
label.text(labelText)
|
|
||||||
} else {
|
|
||||||
label.html(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
addControls(n, div);
|
addControls(n, div);
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,7 +405,7 @@ RED.sidebar.info.outliner = (function() {
|
|||||||
var existingObject = objects[n.id];
|
var existingObject = objects[n.id];
|
||||||
var parent = n.g||n.z||"__global__";
|
var parent = n.g||n.z||"__global__";
|
||||||
|
|
||||||
var nodeLabelText = getNodeLabelText(n);
|
var nodeLabelText = RED.utils.getNodeLabel(n,n.name || (n.type+": "+n.id));
|
||||||
if (nodeLabelText) {
|
if (nodeLabelText) {
|
||||||
existingObject.element.find(".red-ui-info-outline-item-label").text(nodeLabelText);
|
existingObject.element.find(".red-ui-info-outline-item-label").text(nodeLabelText);
|
||||||
} else {
|
} else {
|
||||||
|
@ -477,7 +477,7 @@ RED.sidebar.info = (function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while ((m=/(\[(.*?)\])/.exec(tip))) {
|
while ((m=/(\[([a-z]*?)\])/.exec(tip))) {
|
||||||
tip = tip.replace(m[1],RED.keyboard.formatKey(m[2]));
|
tip = tip.replace(m[1],RED.keyboard.formatKey(m[2]));
|
||||||
}
|
}
|
||||||
tipBox.html(tip).fadeIn(200);
|
tipBox.html(tip).fadeIn(200);
|
||||||
|
@ -178,8 +178,14 @@ RED.utils = (function() {
|
|||||||
RED.popover.tooltip(pinPath,RED._("node-red:debug.sidebar.pinPath"));
|
RED.popover.tooltip(pinPath,RED._("node-red:debug.sidebar.pinPath"));
|
||||||
}
|
}
|
||||||
if (extraTools) {
|
if (extraTools) {
|
||||||
extraTools.addClass("red-ui-debug-msg-tools-other");
|
var t = extraTools;
|
||||||
extraTools.appendTo(tools);
|
if (typeof t === 'function') {
|
||||||
|
t = t(key,msg);
|
||||||
|
}
|
||||||
|
if (t) {
|
||||||
|
t.addClass("red-ui-debug-msg-tools-other");
|
||||||
|
t.appendTo(tools);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function checkExpanded(strippedKey,expandPaths,minRange,maxRange) {
|
function checkExpanded(strippedKey,expandPaths,minRange,maxRange) {
|
||||||
@ -476,7 +482,8 @@ RED.utils = (function() {
|
|||||||
rootPath: rootPath,
|
rootPath: rootPath,
|
||||||
expandPaths: expandPaths,
|
expandPaths: expandPaths,
|
||||||
ontoggle: ontoggle,
|
ontoggle: ontoggle,
|
||||||
exposeApi: exposeApi
|
exposeApi: exposeApi,
|
||||||
|
tools: tools
|
||||||
}
|
}
|
||||||
).appendTo(row);
|
).appendTo(row);
|
||||||
}
|
}
|
||||||
@ -504,8 +511,8 @@ RED.utils = (function() {
|
|||||||
rootPath: rootPath,
|
rootPath: rootPath,
|
||||||
expandPaths: expandPaths,
|
expandPaths: expandPaths,
|
||||||
ontoggle: ontoggle,
|
ontoggle: ontoggle,
|
||||||
exposeApi: exposeApi
|
exposeApi: exposeApi,
|
||||||
|
tools: tools
|
||||||
}
|
}
|
||||||
).appendTo(row);
|
).appendTo(row);
|
||||||
}
|
}
|
||||||
@ -553,8 +560,8 @@ RED.utils = (function() {
|
|||||||
rootPath: rootPath,
|
rootPath: rootPath,
|
||||||
expandPaths: expandPaths,
|
expandPaths: expandPaths,
|
||||||
ontoggle: ontoggle,
|
ontoggle: ontoggle,
|
||||||
exposeApi: exposeApi
|
exposeApi: exposeApi,
|
||||||
|
tools: tools
|
||||||
}
|
}
|
||||||
).appendTo(row);
|
).appendTo(row);
|
||||||
}
|
}
|
||||||
@ -875,6 +882,7 @@ RED.utils = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultNodeIcon(def,node) {
|
function getDefaultNodeIcon(def,node) {
|
||||||
|
def = def || {};
|
||||||
var icon_url;
|
var icon_url;
|
||||||
if (node && node.type === "subflow") {
|
if (node && node.type === "subflow") {
|
||||||
icon_url = "node-red/subflow.svg";
|
icon_url = "node-red/subflow.svg";
|
||||||
@ -912,6 +920,7 @@ RED.utils = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getNodeIcon(def,node) {
|
function getNodeIcon(def,node) {
|
||||||
|
def = def || {};
|
||||||
if (node && node.type === '_selection_') {
|
if (node && node.type === '_selection_') {
|
||||||
return "font-awesome/fa-object-ungroup";
|
return "font-awesome/fa-object-ungroup";
|
||||||
} else if (node && node.type === 'group') {
|
} else if (node && node.type === 'group') {
|
||||||
@ -999,6 +1008,7 @@ RED.utils = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getNodeColor(type, def) {
|
function getNodeColor(type, def) {
|
||||||
|
def = def || {};
|
||||||
var result = def.color;
|
var result = def.color;
|
||||||
var paletteTheme = RED.settings.theme('palette.theme') || [];
|
var paletteTheme = RED.settings.theme('palette.theme') || [];
|
||||||
if (paletteTheme.length > 0) {
|
if (paletteTheme.length > 0) {
|
||||||
@ -1125,9 +1135,11 @@ RED.utils = (function() {
|
|||||||
imageIconElement.css("backgroundImage", "url("+iconUrl+")");
|
imageIconElement.css("backgroundImage", "url("+iconUrl+")");
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNodeIcon(node) {
|
function createNodeIcon(node, includeLabel) {
|
||||||
|
var container = $('<span class="red-ui-node-icon-container">');
|
||||||
|
|
||||||
var def = node._def;
|
var def = node._def;
|
||||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"})
|
var nodeDiv = $('<div>',{class:"red-ui-node-icon"})
|
||||||
if (node.type === "_selection_") {
|
if (node.type === "_selection_") {
|
||||||
nodeDiv.addClass("red-ui-palette-icon-selection");
|
nodeDiv.addClass("red-ui-palette-icon-selection");
|
||||||
} else if (node.type === "group") {
|
} else if (node.type === "group") {
|
||||||
@ -1147,9 +1159,20 @@ RED.utils = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var icon_url = RED.utils.getNodeIcon(def,node);
|
var icon_url = RED.utils.getNodeIcon(def,node);
|
||||||
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
|
RED.utils.createIconElement(icon_url, nodeDiv, true);
|
||||||
RED.utils.createIconElement(icon_url, iconContainer, true);
|
|
||||||
return nodeDiv;
|
nodeDiv.appendTo(container);
|
||||||
|
|
||||||
|
if (includeLabel) {
|
||||||
|
var labelText = RED.utils.getNodeLabel(node,node.name || (node.type+": "+node.id));
|
||||||
|
var label = $('<div>',{class:"red-ui-node-label"}).appendTo(container);
|
||||||
|
if (labelText) {
|
||||||
|
label.text(labelText)
|
||||||
|
} else {
|
||||||
|
label.html(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDarkerColor(c) {
|
function getDarkerColor(c) {
|
||||||
|
@ -1476,15 +1476,15 @@ RED.view = (function() {
|
|||||||
var mouseY = node.n.y;
|
var mouseY = node.n.y;
|
||||||
if (outer[0][0].getIntersectionList) {
|
if (outer[0][0].getIntersectionList) {
|
||||||
var svgRect = outer[0][0].createSVGRect();
|
var svgRect = outer[0][0].createSVGRect();
|
||||||
svgRect.x = mouseX;
|
svgRect.x = mouseX*scaleFactor;
|
||||||
svgRect.y = mouseY;
|
svgRect.y = mouseY*scaleFactor;
|
||||||
svgRect.width = 1;
|
svgRect.width = 1;
|
||||||
svgRect.height = 1;
|
svgRect.height = 1;
|
||||||
nodes = outer[0][0].getIntersectionList(svgRect, outer[0][0]);
|
nodes = outer[0][0].getIntersectionList(svgRect, outer[0][0]);
|
||||||
} else {
|
} else {
|
||||||
// Firefox doesn"t do getIntersectionList and that
|
// Firefox doesn"t do getIntersectionList and that
|
||||||
// makes us sad
|
// makes us sad
|
||||||
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
|
nodes = RED.view.getLinksAtPoint(mouseX*scaleFactor,mouseY*scaleFactor);
|
||||||
}
|
}
|
||||||
for (var i=0;i<nodes.length;i++) {
|
for (var i=0;i<nodes.length;i++) {
|
||||||
if (d3.select(nodes[i]).classed("red-ui-flow-link-background")) {
|
if (d3.select(nodes[i]).classed("red-ui-flow-link-background")) {
|
||||||
@ -1751,7 +1751,6 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
|
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
|
||||||
RED.keyboard.remove("escape");
|
|
||||||
updateActiveNodes();
|
updateActiveNodes();
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
@ -1786,6 +1785,9 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectNone() {
|
function selectNone() {
|
||||||
|
if (mouse_mode === RED.state.MOVING || mouse_mode === RED.state.MOVING_ACTIVE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (mouse_mode === RED.state.IMPORT_DRAGGING) {
|
if (mouse_mode === RED.state.IMPORT_DRAGGING) {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
RED.history.pop();
|
RED.history.pop();
|
||||||
@ -3443,6 +3445,7 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function getGroupAt(x,y) {
|
function getGroupAt(x,y) {
|
||||||
|
// x,y expected to be in node-co-ordinate space
|
||||||
var candidateGroups = {};
|
var candidateGroups = {};
|
||||||
for (var i=0;i<activeGroups.length;i++) {
|
for (var i=0;i<activeGroups.length;i++) {
|
||||||
var g = activeGroups[i];
|
var g = activeGroups[i];
|
||||||
@ -3786,7 +3789,9 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var node = nodeLayer.selectAll(".red-ui-flow-node-group").data(activeNodes,function(d){return d.id});
|
var node = nodeLayer.selectAll(".red-ui-flow-node-group").data(activeNodes,function(d){return d.id});
|
||||||
node.exit().remove();
|
node.exit().each(function(d,i) {
|
||||||
|
RED.hooks.trigger("viewRemoveNode",{node:d,el:this})
|
||||||
|
}).remove();
|
||||||
|
|
||||||
var nodeEnter = node.enter().insert("svg:g")
|
var nodeEnter = node.enter().insert("svg:g")
|
||||||
.attr("class", "red-ui-flow-node red-ui-flow-node-group")
|
.attr("class", "red-ui-flow-node red-ui-flow-node-group")
|
||||||
@ -3960,6 +3965,7 @@ RED.view = (function() {
|
|||||||
});
|
});
|
||||||
node.each(function(d,i) {
|
node.each(function(d,i) {
|
||||||
if (d.dirty) {
|
if (d.dirty) {
|
||||||
|
var self = this;
|
||||||
var thisNode = d3.select(this);
|
var thisNode = d3.select(this);
|
||||||
|
|
||||||
var isLink = (d.type === "link in" || d.type === "link out")
|
var isLink = (d.type === "link in" || d.type === "link out")
|
||||||
@ -4070,7 +4076,15 @@ RED.view = (function() {
|
|||||||
|
|
||||||
var inputPorts = thisNode.selectAll(".red-ui-flow-port-input");
|
var inputPorts = thisNode.selectAll(".red-ui-flow-port-input");
|
||||||
if ((!isLink || (showAllLinkPorts === -1 && !activeLinkNodes[d.id])) && d.inputs === 0 && !inputPorts.empty()) {
|
if ((!isLink || (showAllLinkPorts === -1 && !activeLinkNodes[d.id])) && d.inputs === 0 && !inputPorts.empty()) {
|
||||||
inputPorts.remove();
|
inputPorts.each(function(d,i) {
|
||||||
|
RED.hooks.trigger("viewRemovePort",{
|
||||||
|
node:d,
|
||||||
|
el:self,
|
||||||
|
port:d3.select(this)[0][0],
|
||||||
|
portType: "input",
|
||||||
|
portIndex: 0
|
||||||
|
})
|
||||||
|
}).remove();
|
||||||
} else if (((isLink && (showAllLinkPorts===PORT_TYPE_INPUT||activeLinkNodes[d.id]))|| d.inputs === 1) && inputPorts.empty()) {
|
} else if (((isLink && (showAllLinkPorts===PORT_TYPE_INPUT||activeLinkNodes[d.id]))|| d.inputs === 1) && inputPorts.empty()) {
|
||||||
var inputGroup = thisNode.append("g").attr("class","red-ui-flow-port-input");
|
var inputGroup = thisNode.append("g").attr("class","red-ui-flow-port-input");
|
||||||
var inputGroupPorts;
|
var inputGroupPorts;
|
||||||
@ -4083,12 +4097,17 @@ RED.view = (function() {
|
|||||||
} else {
|
} else {
|
||||||
inputGroupPorts = inputGroup.append("rect").attr("class","red-ui-flow-port").attr("rx",3).attr("ry",3).attr("width",10).attr("height",10)
|
inputGroupPorts = inputGroup.append("rect").attr("class","red-ui-flow-port").attr("rx",3).attr("ry",3).attr("width",10).attr("height",10)
|
||||||
}
|
}
|
||||||
|
inputGroup[0][0].__port__ = inputGroupPorts[0][0];
|
||||||
|
inputGroupPorts[0][0].__data__ = this.__data__;
|
||||||
|
inputGroupPorts[0][0].__portType__ = PORT_TYPE_INPUT;
|
||||||
|
inputGroupPorts[0][0].__portIndex__ = 0;
|
||||||
inputGroupPorts.on("mousedown",function(d){portMouseDown(d,PORT_TYPE_INPUT,0);})
|
inputGroupPorts.on("mousedown",function(d){portMouseDown(d,PORT_TYPE_INPUT,0);})
|
||||||
.on("touchstart",function(d){portMouseDown(d,PORT_TYPE_INPUT,0);d3.event.preventDefault();})
|
.on("touchstart",function(d){portMouseDown(d,PORT_TYPE_INPUT,0);d3.event.preventDefault();})
|
||||||
.on("mouseup",function(d){portMouseUp(d,PORT_TYPE_INPUT,0);} )
|
.on("mouseup",function(d){portMouseUp(d,PORT_TYPE_INPUT,0);} )
|
||||||
.on("touchend",function(d){portMouseUp(d,PORT_TYPE_INPUT,0);d3.event.preventDefault();} )
|
.on("touchend",function(d){portMouseUp(d,PORT_TYPE_INPUT,0);d3.event.preventDefault();} )
|
||||||
.on("mouseover",function(d){portMouseOver(d3.select(this),d,PORT_TYPE_INPUT,0);})
|
.on("mouseover",function(d){portMouseOver(d3.select(this),d,PORT_TYPE_INPUT,0);})
|
||||||
.on("mouseout",function(d) {portMouseOut(d3.select(this),d,PORT_TYPE_INPUT,0);});
|
.on("mouseout",function(d) {portMouseOut(d3.select(this),d,PORT_TYPE_INPUT,0);});
|
||||||
|
RED.hooks.trigger("viewAddPort",{node:d,el: this, port: inputGroup[0][0], portType: "input", portIndex: 0})
|
||||||
}
|
}
|
||||||
var numOutputs = d.outputs;
|
var numOutputs = d.outputs;
|
||||||
if (isLink && d.type === "link out") {
|
if (isLink && d.type === "link out") {
|
||||||
@ -4103,6 +4122,13 @@ RED.view = (function() {
|
|||||||
// Remove extra ports
|
// Remove extra ports
|
||||||
while (this.__outputs__.length > numOutputs) {
|
while (this.__outputs__.length > numOutputs) {
|
||||||
var port = this.__outputs__.pop();
|
var port = this.__outputs__.pop();
|
||||||
|
RED.hooks.trigger("viewRemovePort",{
|
||||||
|
node:d,
|
||||||
|
el:this,
|
||||||
|
port:port,
|
||||||
|
portType: "output",
|
||||||
|
portIndex: this.__outputs__.length
|
||||||
|
})
|
||||||
port.remove();
|
port.remove();
|
||||||
}
|
}
|
||||||
for(var portIndex = 0; portIndex < numOutputs; portIndex++ ) {
|
for(var portIndex = 0; portIndex < numOutputs; portIndex++ ) {
|
||||||
@ -4126,6 +4152,7 @@ RED.view = (function() {
|
|||||||
portPort.setAttribute("class","red-ui-flow-port");
|
portPort.setAttribute("class","red-ui-flow-port");
|
||||||
}
|
}
|
||||||
portGroup.appendChild(portPort);
|
portGroup.appendChild(portPort);
|
||||||
|
portGroup.__port__ = portPort;
|
||||||
portPort.__data__ = this.__data__;
|
portPort.__data__ = this.__data__;
|
||||||
portPort.__portType__ = PORT_TYPE_OUTPUT;
|
portPort.__portType__ = PORT_TYPE_OUTPUT;
|
||||||
portPort.__portIndex__ = portIndex;
|
portPort.__portIndex__ = portIndex;
|
||||||
@ -4138,6 +4165,7 @@ RED.view = (function() {
|
|||||||
|
|
||||||
this.appendChild(portGroup);
|
this.appendChild(portGroup);
|
||||||
this.__outputs__.push(portGroup);
|
this.__outputs__.push(portGroup);
|
||||||
|
RED.hooks.trigger("viewAddPort",{node:d,el: this, port: portGroup, portType: "output", portIndex: portIndex})
|
||||||
} else {
|
} else {
|
||||||
portGroup = this.__outputs__[portIndex];
|
portGroup = this.__outputs__[portIndex];
|
||||||
}
|
}
|
||||||
@ -4226,6 +4254,8 @@ RED.view = (function() {
|
|||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RED.hooks.trigger("viewAddNode",{node:d,el:this})
|
||||||
|
|
||||||
if (d.dirtyStatus) {
|
if (d.dirtyStatus) {
|
||||||
redrawStatus(d,this);
|
redrawStatus(d,this);
|
||||||
}
|
}
|
||||||
@ -5079,6 +5109,9 @@ RED.view = (function() {
|
|||||||
return scaleFactor;
|
return scaleFactor;
|
||||||
},
|
},
|
||||||
getLinksAtPoint: function(x,y) {
|
getLinksAtPoint: function(x,y) {
|
||||||
|
// x,y must be in SVG co-ordinate space
|
||||||
|
// if they come from a node.x/y, they will need to be scaled using
|
||||||
|
// scaleFactor first.
|
||||||
var result = [];
|
var result = [];
|
||||||
var links = outer.selectAll(".red-ui-flow-link-background")[0];
|
var links = outer.selectAll(".red-ui-flow-link-background")[0];
|
||||||
for (var i=0;i<links.length;i++) {
|
for (var i=0;i<links.length;i++) {
|
||||||
|
@ -493,7 +493,11 @@ RED.workspaces = (function() {
|
|||||||
if (!workspace_tabs.contains(id)) {
|
if (!workspace_tabs.contains(id)) {
|
||||||
var sf = RED.nodes.subflow(id);
|
var sf = RED.nodes.subflow(id);
|
||||||
if (sf) {
|
if (sf) {
|
||||||
addWorkspace({type:"subflow",id:id,icon:"red/images/subflow_tab.svg",label:sf.name, closeable: true});
|
addWorkspace(
|
||||||
|
{type:"subflow",id:id,icon:"red/images/subflow_tab.svg",label:sf.name, closeable: true},
|
||||||
|
null,
|
||||||
|
workspace_tabs.activeIndex()+1
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -255,11 +255,11 @@ g.red-ui-flow-node-selected {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@each $current-color in red green yellow blue grey gray {
|
@each $current-color in red green yellow blue grey gray {
|
||||||
.red-ui-flow-node-status-dot-#{$current-color} {
|
.red-ui-flow-node-status-dot-#{""+$current-color} {
|
||||||
fill: map-get($node-status-colors,$current-color);
|
fill: map-get($node-status-colors,$current-color);
|
||||||
stroke: map-get($node-status-colors,$current-color);
|
stroke: map-get($node-status-colors,$current-color);
|
||||||
}
|
}
|
||||||
.red-ui-flow-node-status-ring-#{$current-color} {
|
.red-ui-flow-node-status-ring-#{""+$current-color} {
|
||||||
fill: $view-background;
|
fill: $view-background;
|
||||||
stroke: map-get($node-status-colors,$current-color);
|
stroke: map-get($node-status-colors,$current-color);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
.red-ui-notification {
|
.red-ui-notification {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 14px 18px;
|
padding: 8px 18px 0px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
box-shadow: 0 1px 1px 1px $shadow;
|
box-shadow: 0 1px 1px 1px $shadow;
|
||||||
background-color: $secondary-background;
|
background-color: $secondary-background;
|
||||||
@ -35,6 +35,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
.ui-dialog-buttonset {
|
.ui-dialog-buttonset {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.red-ui-notification p:first-child {
|
.red-ui-notification p:first-child {
|
||||||
|
@ -134,7 +134,7 @@
|
|||||||
&:not(.red-ui-palette-node-config):not(.red-ui-palette-node-small):first-child {
|
&:not(.red-ui-palette-node-config):not(.red-ui-palette-node-small):first-child {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
&:not(.red-ui-palette-node-config):not(.red-ui-palette-node-small):first-child {
|
&:not(.red-ui-palette-node-config):not(.red-ui-palette-node-small):last-child {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,3 +229,65 @@
|
|||||||
left: 1px;
|
left: 1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
.red-ui-node-list-item {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.red-ui-node-icon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 24px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
margin-top: 1px;
|
||||||
|
// width: 30px;
|
||||||
|
// height: 25px;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid $node-border;
|
||||||
|
background-position: 5% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
position: relative;
|
||||||
|
background-color: $node-icon-background-color;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.red-ui-palette-icon {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-ui-palette-icon-fa {
|
||||||
|
font-size: 14px;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.red-ui-node-icon-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.red-ui-node-icon-container.red-ui-node-icon-small {
|
||||||
|
.red-ui-node-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 15px;
|
||||||
|
line-height: 15px;
|
||||||
|
.red-ui-palette-icon {
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
.red-ui-palette-icon-fa {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.red-ui-node-label {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-ui-node-label {
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 4px;
|
||||||
|
color: $secondary-text-color;
|
||||||
|
}
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
left: -1px;
|
left: -1px;
|
||||||
}
|
}
|
||||||
.red-ui-search-result-description {
|
.red-ui-search-result-description {
|
||||||
margin-left:28px;
|
margin-left:8px;
|
||||||
}
|
}
|
||||||
.red-ui-search-result-node-label {
|
.red-ui-search-result-node-label {
|
||||||
color: $secondary-text-color;
|
color: $secondary-text-color;
|
||||||
@ -133,7 +133,8 @@
|
|||||||
}
|
}
|
||||||
.red-ui-search-result {
|
.red-ui-search-result {
|
||||||
padding: 8px 2px 8px 5px;
|
padding: 8px 2px 8px 5px;
|
||||||
display: block;
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: $list-item-color;
|
color: $list-item-color;
|
||||||
background: $list-item-background;
|
background: $list-item-background;
|
||||||
@ -156,12 +157,7 @@
|
|||||||
display: table;
|
display: table;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
.red-ui-palette-icon-fa {
|
|
||||||
top: 6px;
|
|
||||||
left: 3px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.red-ui-search-result-node {
|
.red-ui-search-result-node {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
@ -180,8 +176,9 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
.red-ui-search-result-node-description {
|
.red-ui-search-result-node-description {
|
||||||
margin-left: 40px;
|
margin-left: 10px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
.red-ui-search-result-node-label {
|
.red-ui-search-result-node-label {
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
|
@ -326,13 +326,17 @@ div.red-ui-info-table {
|
|||||||
border-bottom: 1px solid $secondary-border-color;
|
border-bottom: 1px solid $secondary-border-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.red-ui-info-outline,.red-ui-sidebar-help-toc, #red-ui-clipboard-dialog-import-conflicts-list, #red-ui-clipboard-dialog-export-tab-clipboard-preview {
|
.red-ui-info-outline,
|
||||||
|
// TODO: remove these classes for 2.0. Keeping in 1.x for backwards compatibility
|
||||||
|
// of theme generators.
|
||||||
|
.red-ui-sidebar-help-toc, #red-ui-clipboard-dialog-import-conflicts-list, #red-ui-clipboard-dialog-export-tab-clipboard-preview
|
||||||
|
{
|
||||||
.red-ui-info-outline-item {
|
.red-ui-info-outline-item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
border: none;
|
border: none;
|
||||||
.red-ui-palette-icon-fa {
|
&:not(.red-ui-node-list-item) .red-ui-palette-icon-fa {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 1px;
|
top: 1px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow:visible;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
&[disabled] {
|
&[disabled] {
|
||||||
input, button {
|
input, button {
|
||||||
@ -33,7 +33,7 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.red-ui-typedInput-input-wrap {
|
.red-ui-typedInput-input-wrap {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@
|
|||||||
for (var i=0,l=props.length; i<l; i++) {
|
for (var i=0,l=props.length; i<l; i++) {
|
||||||
if (i > 0) lab += "\n";
|
if (i > 0) lab += "\n";
|
||||||
if (i === 5) {
|
if (i === 5) {
|
||||||
lab += " + "+(props.length-4);
|
lab += "... +"+(props.length-5);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lab += props[i].p+": ";
|
lab += props[i].p+": ";
|
||||||
@ -636,7 +636,7 @@
|
|||||||
url: "inject/"+this.id,
|
url: "inject/"+this.id,
|
||||||
type:"POST",
|
type:"POST",
|
||||||
success: function(resp) {
|
success: function(resp) {
|
||||||
RED.notify(node._("inject.success",{label:label}),{type:"success",id:"inject"});
|
RED.notify(node._("inject.success",{label:label}),{type:"success",id:"inject", timeout: 2000});
|
||||||
},
|
},
|
||||||
error: function(jqXHR,textStatus,errorThrown) {
|
error: function(jqXHR,textStatus,errorThrown) {
|
||||||
if (jqXHR.status == 404) {
|
if (jqXHR.status == 404) {
|
||||||
|
@ -129,9 +129,9 @@
|
|||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
RED.view.redraw();
|
RED.view.redraw();
|
||||||
if (xhr.status == 200) {
|
if (xhr.status == 200) {
|
||||||
RED.notify(node._("debug.notification.activated",{label:label}),"success");
|
RED.notify(node._("debug.notification.activated",{label:label}),{type: "success", timeout: 2000});
|
||||||
} else if (xhr.status == 201) {
|
} else if (xhr.status == 201) {
|
||||||
RED.notify(node._("debug.notification.deactivated",{label:label}),"success");
|
RED.notify(node._("debug.notification.deactivated",{label:label}),{type: "success", timeout: 2000});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ module.exports = function(RED) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
var util = require("util");
|
var util = require("util");
|
||||||
var events = require("events");
|
var events = require("events");
|
||||||
//var path = require("path");
|
const fs = require("fs-extra");
|
||||||
|
const path = require("path");
|
||||||
var debuglength = RED.settings.debugMaxLength || 1000;
|
var debuglength = RED.settings.debugMaxLength || 1000;
|
||||||
var useColors = RED.settings.debugUseColors || false;
|
var useColors = RED.settings.debugUseColors || false;
|
||||||
util.inspect.styles.boolean = "red";
|
util.inspect.styles.boolean = "red";
|
||||||
@ -249,11 +250,34 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let cachedDebugView;
|
||||||
|
RED.httpAdmin.get("/debug/view/view.html", function(req,res) {
|
||||||
|
if (!cachedDebugView) {
|
||||||
|
fs.readFile(path.join(__dirname,"lib","debug","view.html")).then(data => {
|
||||||
|
let customStyles = "";
|
||||||
|
try {
|
||||||
|
let customStyleList = RED.settings.editorTheme.page._.css || [];
|
||||||
|
customStyleList.forEach(style => {
|
||||||
|
customStyles += `<link rel="stylesheet" href="../../${style}">\n`
|
||||||
|
})
|
||||||
|
} catch(err) {}
|
||||||
|
cachedDebugView = data.toString().replace("<!-- INSERT-THEME-CSS -->",customStyles)
|
||||||
|
res.set('Content-Type', 'text/html');
|
||||||
|
res.send(cachedDebugView).end();
|
||||||
|
}).catch(err => {
|
||||||
|
res.sendStatus(404);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
res.send(cachedDebugView).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
// As debug/view/debug-utils.js is loaded via <script> tag, it won't get
|
// As debug/view/debug-utils.js is loaded via <script> tag, it won't get
|
||||||
// the auth header attached. So do not use RED.auth.needsPermission here.
|
// the auth header attached. So do not use RED.auth.needsPermission here.
|
||||||
RED.httpAdmin.get("/debug/view/*",function(req,res) {
|
RED.httpAdmin.get("/debug/view/*",function(req,res) {
|
||||||
var options = {
|
var options = {
|
||||||
root: __dirname + '/lib/debug/',
|
root: path.join(__dirname,"lib","debug"),
|
||||||
dotfiles: 'deny'
|
dotfiles: 'deny'
|
||||||
};
|
};
|
||||||
res.sendFile(req.params[0], options);
|
res.sendFile(req.params[0], options);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" href="../../red/style.min.css">
|
<link rel="stylesheet" href="../../red/style.min.css">
|
||||||
<link rel="stylesheet" href="../../vendor/font-awesome/css/font-awesome.min.css">
|
<link rel="stylesheet" href="../../vendor/font-awesome/css/font-awesome.min.css">
|
||||||
|
<!-- INSERT-THEME-CSS -->
|
||||||
<title>Node-RED Debug Tools</title>
|
<title>Node-RED Debug Tools</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="red-ui-editor red-ui-debug-window">
|
<body class="red-ui-editor red-ui-debug-window">
|
||||||
|
@ -74,21 +74,21 @@
|
|||||||
<div id="func-tab-init" style="display:none">
|
<div id="func-tab-init" style="display:none">
|
||||||
<div class="form-row node-text-editor-row" style="position:relative">
|
<div class="form-row node-text-editor-row" style="position:relative">
|
||||||
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-init-editor" ></div>
|
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-init-editor" ></div>
|
||||||
<div style="position: absolute; right:0; bottom: calc(100% - 20px);"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
|
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="func-tab-body" style="display:none">
|
<div id="func-tab-body" style="display:none">
|
||||||
<div class="form-row node-text-editor-row" style="position:relative">
|
<div class="form-row node-text-editor-row" style="position:relative">
|
||||||
<div style="height: 220px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
|
<div style="height: 220px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
|
||||||
<div style="position: absolute; right:0; bottom: calc(100% - 20px);"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
|
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="func-tab-finalize" style="display:none">
|
<div id="func-tab-finalize" style="display:none">
|
||||||
<div class="form-row node-text-editor-row" style="position:relative">
|
<div class="form-row node-text-editor-row" style="position:relative">
|
||||||
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
|
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
|
||||||
<div style="position: absolute; right:0; bottom: calc(100% - 20px);"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
|
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -302,7 +302,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (moduleErrors) {
|
if (moduleErrors) {
|
||||||
throw new Error("Function node failed to load external modules");
|
throw new Error(RED._("function.error.externalModuleLoadError"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +366,8 @@ module.exports = function(RED) {
|
|||||||
__node__.error("Cannot send from close function");
|
__node__.error("Cannot send from close function");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
`+node.fin +`})();`;
|
`+node.fin +`
|
||||||
|
})();`;
|
||||||
finOpt = createVMOpt(node, " cleanup");
|
finOpt = createVMOpt(node, " cleanup");
|
||||||
finScript = new vm.Script(finText, finOpt);
|
finScript = new vm.Script(finText, finOpt);
|
||||||
}
|
}
|
||||||
@ -489,4 +490,3 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
RED.library.register("functions");
|
RED.library.register("functions");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,9 +45,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="random-details" class="form-row">
|
<div id="random-details" class="form-row">
|
||||||
<label for="node-input-randomFirst"><i class="fa fa-clock-o"></i> <span data-i18n="delay.between"></span></label>
|
<label for="node-input-randomFirst"><i class="fa fa-clock-o"></i> <span data-i18n="delay.between"></span></label>
|
||||||
<input type="text" id="node-input-randomFirst" placeholder="" style="text-align:end; width:30px !important">
|
<input type="text" id="node-input-randomFirst" placeholder="" style="text-align:end; width:50px !important">
|
||||||
<span data-i18n="delay.and"></span>
|
<span data-i18n="delay.and"></span>
|
||||||
<input type="text" id="node-input-randomLast" placeholder="" style="text-align:end; width:30px !important">
|
<input type="text" id="node-input-randomLast" placeholder="" style="text-align:end; width:50px !important">
|
||||||
<select id="node-input-randomUnits" style="width:140px !important">
|
<select id="node-input-randomUnits" style="width:140px !important">
|
||||||
<option value="milliseconds" data-i18n="delay.milisecs"></option>
|
<option value="milliseconds" data-i18n="delay.milisecs"></option>
|
||||||
<option value="seconds" data-i18n="delay.secs"></option>
|
<option value="seconds" data-i18n="delay.secs"></option>
|
||||||
|
@ -186,8 +186,8 @@
|
|||||||
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:55px">
|
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:55px">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row" style="height: 34px;">
|
<div class="form-row" style="height: 34px;">
|
||||||
<input type="checkbox" id="node-config-input-usetls" style="height: 34px; margin: 0 0 0 104px; display: inline-block; width: auto; vertical-align: top;">
|
<input type="checkbox" id="node-config-input-usetls" style="height: 34px; margin: 0 5px 0 104px; display: inline-block; width: auto; vertical-align: top;">
|
||||||
<label for="node-config-input-usetls" style="width: 80px; line-height: 34px;"><span data-i18n="mqtt.label.use-tls"></span></label>
|
<label for="node-config-input-usetls" style="width: 100px; line-height: 34px;"><span data-i18n="mqtt.label.use-tls"></span></label>
|
||||||
<span id="node-config-row-tls" class="hide"><input style="width: 320px;" type="text" id="node-config-input-tls"></span>
|
<span id="node-config-row-tls" class="hide"><input style="width: 320px;" type="text" id="node-config-input-tls"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
|
@ -400,7 +400,15 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
if (Object.keys(node.users).length === 0) {
|
if (Object.keys(node.users).length === 0) {
|
||||||
if (node.client && node.client.connected) {
|
if (node.client && node.client.connected) {
|
||||||
return node.client.end(done);
|
// Send close message
|
||||||
|
if (node.closeMessage) {
|
||||||
|
node.publish(node.closeMessage,function(err) {
|
||||||
|
node.client.end(done);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
node.client.end(done);
|
||||||
|
}
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
node.client.end();
|
node.client.end();
|
||||||
return done();
|
return done();
|
||||||
@ -639,10 +647,6 @@ module.exports = function(RED) {
|
|||||||
this.on('close', function(done) {
|
this.on('close', function(done) {
|
||||||
this.closing = true;
|
this.closing = true;
|
||||||
if (this.connected) {
|
if (this.connected) {
|
||||||
// Send close message
|
|
||||||
if (node.closeMessage) {
|
|
||||||
node.publish(node.closeMessage);
|
|
||||||
}
|
|
||||||
this.client.once('close', function() {
|
this.client.once('close', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -873,4 +877,4 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
RED.nodes.registerType("mqtt out",MQTTOutNode);
|
RED.nodes.registerType("mqtt out",MQTTOutNode);
|
||||||
};
|
};
|
||||||
|
@ -46,7 +46,9 @@ module.exports = function(RED) {
|
|||||||
isText = true;
|
isText = true;
|
||||||
} else if (parsedType.type !== "application") {
|
} else if (parsedType.type !== "application") {
|
||||||
isText = false;
|
isText = false;
|
||||||
} else if ((parsedType.subtype !== "octet-stream") && (parsedType.subtype !== "cbor")) {
|
} else if ((parsedType.subtype !== "octet-stream")
|
||||||
|
&& (parsedType.subtype !== "cbor")
|
||||||
|
&& (parsedType.subtype !== "x-protobuf")) {
|
||||||
checkUTF = true;
|
checkUTF = true;
|
||||||
} else {
|
} else {
|
||||||
// application/octet-stream or application/cbor
|
// application/octet-stream or application/cbor
|
||||||
|
@ -38,17 +38,18 @@ module.exports = function(RED) {
|
|||||||
if (this.hdrout === true) { this.hdrout = "all"; }
|
if (this.hdrout === true) { this.hdrout = "all"; }
|
||||||
var tmpwarn = true;
|
var tmpwarn = true;
|
||||||
var node = this;
|
var node = this;
|
||||||
var re = new RegExp(',(?=(?:(?:[^"]*"){2})*[^"]*$)','g');
|
var re = new RegExp(node.sep.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g,'\\$&') + '(?=(?:(?:[^"]*"){2})*[^"]*$)','g');
|
||||||
|
|
||||||
// pass in an array of column names to be trimed, de-quoted and retrimed
|
// pass in an array of column names to be trimmed, de-quoted and retrimmed
|
||||||
var clean = function(col) {
|
var clean = function(col,sep) {
|
||||||
|
if (sep) { re = new RegExp(sep.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g,'\\$&') +'(?=(?:(?:[^"]*"){2})*[^"]*$)','g'); }
|
||||||
col = col.trim().split(re) || [""];
|
col = col.trim().split(re) || [""];
|
||||||
col = col.map(x => x.replace(/"/g,'').trim());
|
col = col.map(x => x.replace(/"/g,'').trim());
|
||||||
if ((col.length === 1) && (col[0] === "")) { node.goodtmpl = false; }
|
if ((col.length === 1) && (col[0] === "")) { node.goodtmpl = false; }
|
||||||
else { node.goodtmpl = true; }
|
else { node.goodtmpl = true; }
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
var template = clean(node.template);
|
var template = clean(node.template,',');
|
||||||
var notemplate = template.length === 1 && template[0] === '';
|
var notemplate = template.length === 1 && template[0] === '';
|
||||||
node.hdrSent = false;
|
node.hdrSent = false;
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ module.exports = function(RED) {
|
|||||||
if (node.hdrout !== "none" && node.hdrSent === false) {
|
if (node.hdrout !== "none" && node.hdrSent === false) {
|
||||||
if ((template.length === 1) && (template[0] === '')) {
|
if ((template.length === 1) && (template[0] === '')) {
|
||||||
if (msg.hasOwnProperty("columns")) {
|
if (msg.hasOwnProperty("columns")) {
|
||||||
template = clean(msg.columns || "");
|
template = clean(msg.columns || "",",");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
template = Object.keys(msg.payload[0]);
|
template = Object.keys(msg.payload[0]);
|
||||||
@ -80,7 +81,7 @@ module.exports = function(RED) {
|
|||||||
if ((Array.isArray(msg.payload[s])) || (typeof msg.payload[s] !== "object")) {
|
if ((Array.isArray(msg.payload[s])) || (typeof msg.payload[s] !== "object")) {
|
||||||
if (typeof msg.payload[s] !== "object") { msg.payload = [ msg.payload ]; }
|
if (typeof msg.payload[s] !== "object") { msg.payload = [ msg.payload ]; }
|
||||||
for (var t = 0; t < msg.payload[s].length; t++) {
|
for (var t = 0; t < msg.payload[s].length; t++) {
|
||||||
if (!msg.payload[s][t] && (msg.payload[s][t] !== 0)) { msg.payload[s][t] = ""; }
|
if (msg.payload[s][t] === undefined) { msg.payload[s][t] = ""; }
|
||||||
if (msg.payload[s][t].toString().indexOf(node.quo) !== -1) { // add double quotes if any quotes
|
if (msg.payload[s][t].toString().indexOf(node.quo) !== -1) { // add double quotes if any quotes
|
||||||
msg.payload[s][t] = msg.payload[s][t].toString().replace(/"/g, '""');
|
msg.payload[s][t] = msg.payload[s][t].toString().replace(/"/g, '""');
|
||||||
msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
|
msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
|
||||||
@ -93,7 +94,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((template.length === 1) && (template[0] === '') && (msg.hasOwnProperty("columns"))) {
|
if ((template.length === 1) && (template[0] === '') && (msg.hasOwnProperty("columns"))) {
|
||||||
template = clean(msg.columns || "");
|
template = clean(msg.columns || "",",");
|
||||||
}
|
}
|
||||||
if ((template.length === 1) && (template[0] === '')) {
|
if ((template.length === 1) && (template[0] === '')) {
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
@ -184,7 +185,7 @@ module.exports = function(RED) {
|
|||||||
if ((node.hdrin === true) && first) { // if the template is in the first line
|
if ((node.hdrin === true) && first) { // if the template is in the first line
|
||||||
if ((line[i] === "\n")||(line[i] === "\r")||(line.length - i === 1)) { // look for first line break
|
if ((line[i] === "\n")||(line[i] === "\r")||(line.length - i === 1)) { // look for first line break
|
||||||
if (line.length - i === 1) { tmp += line[i]; }
|
if (line.length - i === 1) { tmp += line[i]; }
|
||||||
template = clean(tmp);
|
template = clean(tmp,node.sep);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
else { tmp += line[i]; }
|
else { tmp += line[i]; }
|
||||||
|
@ -219,6 +219,10 @@
|
|||||||
value: "none",
|
value: "none",
|
||||||
label: label
|
label: label
|
||||||
}).text(label).appendTo(encSel);
|
}).text(label).appendTo(encSel);
|
||||||
|
$("<option/>", {
|
||||||
|
value: "setbymsg",
|
||||||
|
label: node._("file.encoding.setbymsg")
|
||||||
|
}).text(label).appendTo(encSel);
|
||||||
encodings.forEach(function(item) {
|
encodings.forEach(function(item) {
|
||||||
if(Array.isArray(item)) {
|
if(Array.isArray(item)) {
|
||||||
var group = $("<optgroup/>", {
|
var group = $("<optgroup/>", {
|
||||||
|
@ -69,7 +69,8 @@ module.exports = function(RED) {
|
|||||||
fs.unlink(fullFilename, function (err) {
|
fs.unlink(fullFilename, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
node.error(RED._("file.errors.deletefail",{error:err.toString()}),msg);
|
node.error(RED._("file.errors.deletefail",{error:err.toString()}),msg);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (RED.settings.verbose) {
|
if (RED.settings.verbose) {
|
||||||
node.log(RED._("file.status.deletedfile",{file:filename}));
|
node.log(RED._("file.status.deletedfile",{file:filename}));
|
||||||
}
|
}
|
||||||
@ -82,7 +83,8 @@ module.exports = function(RED) {
|
|||||||
if (node.createDir) {
|
if (node.createDir) {
|
||||||
try {
|
try {
|
||||||
fs.ensureDirSync(dir);
|
fs.ensureDirSync(dir);
|
||||||
} catch(err) {
|
}
|
||||||
|
catch(err) {
|
||||||
node.error(RED._("file.errors.createfail",{error:err.toString()}),msg);
|
node.error(RED._("file.errors.createfail",{error:err.toString()}),msg);
|
||||||
done();
|
done();
|
||||||
return;
|
return;
|
||||||
@ -96,7 +98,11 @@ module.exports = function(RED) {
|
|||||||
if (typeof data === "boolean") { data = data.toString(); }
|
if (typeof data === "boolean") { data = data.toString(); }
|
||||||
if (typeof data === "number") { data = data.toString(); }
|
if (typeof data === "number") { data = data.toString(); }
|
||||||
if ((node.appendNewline) && (!Buffer.isBuffer(data))) { data += os.EOL; }
|
if ((node.appendNewline) && (!Buffer.isBuffer(data))) { data += os.EOL; }
|
||||||
var buf = encode(data, node.encoding);
|
var buf;
|
||||||
|
if (node.encoding === "setbymsg") {
|
||||||
|
buf = encode(data, msg.encoding || "none");
|
||||||
|
}
|
||||||
|
else { buf = encode(data, node.encoding); }
|
||||||
if (node.overwriteFile === "true") {
|
if (node.overwriteFile === "true") {
|
||||||
var wstream = fs.createWriteStream(fullFilename, { encoding:'binary', flags:'w', autoClose:true });
|
var wstream = fs.createWriteStream(fullFilename, { encoding:'binary', flags:'w', autoClose:true });
|
||||||
node.wstream = wstream;
|
node.wstream = wstream;
|
||||||
@ -105,10 +111,11 @@ module.exports = function(RED) {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
wstream.on("open", function() {
|
wstream.on("open", function() {
|
||||||
wstream.end(buf, function() {
|
wstream.once("close", function() {
|
||||||
nodeSend(msg);
|
nodeSend(msg);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
wstream.end(buf);
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -130,7 +137,8 @@ module.exports = function(RED) {
|
|||||||
delete node.wstream;
|
delete node.wstream;
|
||||||
delete node.wstreamIno;
|
delete node.wstreamIno;
|
||||||
}
|
}
|
||||||
} catch(err) {
|
}
|
||||||
|
catch(err) {
|
||||||
// File does not exist
|
// File does not exist
|
||||||
recreateStream = true;
|
recreateStream = true;
|
||||||
node.wstream.end();
|
node.wstream.end();
|
||||||
@ -158,14 +166,16 @@ module.exports = function(RED) {
|
|||||||
nodeSend(msg);
|
nodeSend(msg);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// Dynamic filename - write and close the stream
|
// Dynamic filename - write and close the stream
|
||||||
node.wstream.end(buf, function() {
|
node.wstream.once("close", function() {
|
||||||
nodeSend(msg);
|
nodeSend(msg);
|
||||||
delete node.wstream;
|
delete node.wstream;
|
||||||
delete node.wstreamIno;
|
delete node.wstreamIno;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
node.wstream.end(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,7 +294,6 @@ module.exports = function(RED) {
|
|||||||
ch = "\n";
|
ch = "\n";
|
||||||
type = "string";
|
type = "string";
|
||||||
}
|
}
|
||||||
var hwm;
|
|
||||||
var getout = false;
|
var getout = false;
|
||||||
|
|
||||||
var rs = fs.createReadStream(fullFilename)
|
var rs = fs.createReadStream(fullFilename)
|
||||||
@ -348,16 +357,17 @@ module.exports = function(RED) {
|
|||||||
nodeSend(msg);
|
nodeSend(msg);
|
||||||
}
|
}
|
||||||
else if (node.format === "lines") {
|
else if (node.format === "lines") {
|
||||||
var m = { payload: spare,
|
var m = {
|
||||||
topic:msg.topic,
|
payload: spare,
|
||||||
parts: {
|
topic:msg.topic,
|
||||||
index: count,
|
parts: {
|
||||||
count: count+1,
|
index: count,
|
||||||
ch: ch,
|
count: count+1,
|
||||||
type: type,
|
ch: ch,
|
||||||
id: msg._msgid
|
type: type,
|
||||||
}
|
id: msg._msgid
|
||||||
};
|
}
|
||||||
|
};
|
||||||
nodeSend(m);
|
nodeSend(m);
|
||||||
}
|
}
|
||||||
else if (getout) { // last chunk same size as high water mark - have to send empty extra packet.
|
else if (getout) { // last chunk same size as high water mark - have to send empty extra packet.
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "2ebdd51e.c5d17a",
|
"id": "b05816ab.7f2b08",
|
||||||
"type": "comment",
|
"type": "comment",
|
||||||
"z": "4b63452d.672afc",
|
"z": "c6ffdacd.d887e8",
|
||||||
"name": "Convert array of JavaScript objects to CSV with column name header",
|
"name": "Specify column names in input message",
|
||||||
"info": "CSV node can convert an array of JavaScript objects to multi-line CSV text with column name header at first line.",
|
"info": "Column names can be specified by `columns` property of incoming message.\n",
|
||||||
"x": 390,
|
"x": 240,
|
||||||
"y": 1200,
|
"y": 200,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2b4d538d.ada07c",
|
"id": "39205b5c.690684",
|
||||||
"type": "inject",
|
"type": "inject",
|
||||||
"z": "4b63452d.672afc",
|
"z": "c6ffdacd.d887e8",
|
||||||
"name": "",
|
"name": "",
|
||||||
"props": [
|
"props": [
|
||||||
{
|
{
|
||||||
@ -30,41 +30,41 @@
|
|||||||
"topic": "",
|
"topic": "",
|
||||||
"payload": "",
|
"payload": "",
|
||||||
"payloadType": "date",
|
"payloadType": "date",
|
||||||
"x": 260,
|
"x": 200,
|
||||||
"y": 1260,
|
"y": 260,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"3e5c9e8.5065b62"
|
"526b59ba.2fa068"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "db02c7be.0984e8",
|
"id": "b78a407e.2d083",
|
||||||
"type": "csv",
|
"type": "csv",
|
||||||
"z": "4b63452d.672afc",
|
"z": "c6ffdacd.d887e8",
|
||||||
"name": "",
|
"name": "",
|
||||||
"sep": ",",
|
"sep": ",",
|
||||||
"hdrin": false,
|
"hdrin": false,
|
||||||
"hdrout": "all",
|
"hdrout": "all",
|
||||||
"multi": "one",
|
"multi": "one",
|
||||||
"ret": "\\n",
|
"ret": "\\n",
|
||||||
"temp": "kind,price",
|
"temp": "",
|
||||||
"skip": "0",
|
"skip": "0",
|
||||||
"strings": true,
|
"strings": true,
|
||||||
"include_empty_strings": "",
|
"include_empty_strings": "",
|
||||||
"include_null_values": "",
|
"include_null_values": "",
|
||||||
"x": 600,
|
"x": 750,
|
||||||
"y": 1260,
|
"y": 260,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"61f8b772.ddb1f8"
|
"8b7084dd.986f68"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "3e5c9e8.5065b62",
|
"id": "526b59ba.2fa068",
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"z": "4b63452d.672afc",
|
"z": "c6ffdacd.d887e8",
|
||||||
"name": "JS object",
|
"name": "JS object",
|
||||||
"field": "payload",
|
"field": "payload",
|
||||||
"fieldType": "msg",
|
"fieldType": "msg",
|
||||||
@ -72,18 +72,18 @@
|
|||||||
"syntax": "plain",
|
"syntax": "plain",
|
||||||
"template": "[\n {\n \"kind\": \"Apple\",\n \"price\": 100,\n \"origin\": \"Canada\"\n },\n {\n \"kind\": \"Orange\",\n \"price\": 120,\n \"origin\": \"USA\"\n },\n {\n \"kind\": \"Banana\",\n \"price\": 80,\n \"origin\": \"Philippines\"\n }\n]",
|
"template": "[\n {\n \"kind\": \"Apple\",\n \"price\": 100,\n \"origin\": \"Canada\"\n },\n {\n \"kind\": \"Orange\",\n \"price\": 120,\n \"origin\": \"USA\"\n },\n {\n \"kind\": \"Banana\",\n \"price\": 80,\n \"origin\": \"Philippines\"\n }\n]",
|
||||||
"output": "json",
|
"output": "json",
|
||||||
"x": 430,
|
"x": 370,
|
||||||
"y": 1260,
|
"y": 260,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"db02c7be.0984e8"
|
"b204077a.227778"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "61f8b772.ddb1f8",
|
"id": "8b7084dd.986f68",
|
||||||
"type": "debug",
|
"type": "debug",
|
||||||
"z": "4b63452d.672afc",
|
"z": "c6ffdacd.d887e8",
|
||||||
"name": "",
|
"name": "",
|
||||||
"active": true,
|
"active": true,
|
||||||
"tosidebar": true,
|
"tosidebar": true,
|
||||||
@ -92,8 +92,35 @@
|
|||||||
"complete": "false",
|
"complete": "false",
|
||||||
"statusVal": "",
|
"statusVal": "",
|
||||||
"statusType": "auto",
|
"statusType": "auto",
|
||||||
"x": 780,
|
"x": 930,
|
||||||
"y": 1260,
|
"y": 260,
|
||||||
"wires": []
|
"wires": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b204077a.227778",
|
||||||
|
"type": "change",
|
||||||
|
"z": "c6ffdacd.d887e8",
|
||||||
|
"name": "",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"t": "set",
|
||||||
|
"p": "columns",
|
||||||
|
"pt": "msg",
|
||||||
|
"to": "kind,price",
|
||||||
|
"tot": "str"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"action": "",
|
||||||
|
"property": "",
|
||||||
|
"from": "",
|
||||||
|
"to": "",
|
||||||
|
"reg": false,
|
||||||
|
"x": 570,
|
||||||
|
"y": 260,
|
||||||
|
"wires": [
|
||||||
|
[
|
||||||
|
"b78a407e.2d083"
|
||||||
|
]
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -363,7 +363,7 @@
|
|||||||
"keepalive": "Keep-Alive",
|
"keepalive": "Keep-Alive",
|
||||||
"cleansession": "Bereinigte Sitzung (clean session) verwenden",
|
"cleansession": "Bereinigte Sitzung (clean session) verwenden",
|
||||||
"cleanstart": "Verwende bereinigten Start",
|
"cleanstart": "Verwende bereinigten Start",
|
||||||
"use-tls": "Sichere Verbindung (SSL/TLS) verwenden",
|
"use-tls": "TLS",
|
||||||
"tls-config": "TLS-Konfiguration",
|
"tls-config": "TLS-Konfiguration",
|
||||||
"verify-server-cert": "Server-Zertifikat überprüfen",
|
"verify-server-cert": "Server-Zertifikat überprüfen",
|
||||||
"compatmode": "MQTT 3.1 unterstützen",
|
"compatmode": "MQTT 3.1 unterstützen",
|
||||||
|
@ -21,9 +21,10 @@
|
|||||||
the body of the message.</p>
|
the body of the message.</p>
|
||||||
<p>The function is expected to return a message object (or multiple message objects), but can choose
|
<p>The function is expected to return a message object (or multiple message objects), but can choose
|
||||||
to return nothing in order to halt a flow.</p>
|
to return nothing in order to halt a flow.</p>
|
||||||
<p>The <b>Setup</b> tab contains code that will be run whenever the node is started.
|
<p>The <b>On Start</b> tab contains code that will be run whenever the node is started.
|
||||||
The <b>Close</b> tab contains code that will be run when the node is stopped.</p>
|
The <b>On Stop</b> tab contains code that will be run when the node is stopped.</p>
|
||||||
<p>If an promise object is returned from the setup code, input message processing starts after its completion.</p>
|
<p>If the On Start code returns a Promise object, the node will not start handling messages
|
||||||
|
until the promise is resolved.</p>
|
||||||
<h3>Details</h3>
|
<h3>Details</h3>
|
||||||
<p>See the <a target="_blank" href="http://nodered.org/docs/writing-functions.html">online documentation</a>
|
<p>See the <a target="_blank" href="http://nodered.org/docs/writing-functions.html">online documentation</a>
|
||||||
for more information on writing functions.</p>
|
for more information on writing functions.</p>
|
||||||
@ -52,10 +53,11 @@
|
|||||||
pass <code>msg</code> as a second argument to <code>node.error</code>:</p>
|
pass <code>msg</code> as a second argument to <code>node.error</code>:</p>
|
||||||
<pre>node.error("Error",msg);</pre>
|
<pre>node.error("Error",msg);</pre>
|
||||||
<h4>Accessing Node Information</h4>
|
<h4>Accessing Node Information</h4>
|
||||||
<p>In the function block, id and name of the node can be referenced using the following properties:</p>
|
<p>The following properties are available to access information about the node:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>node.id</code> - id of the node</li>
|
<li><code>node.id</code> - id of the node</li>
|
||||||
<li><code>node.name</code> - name of the node</li>
|
<li><code>node.name</code> - name of the node</li>
|
||||||
|
<li><code>node.outputCount</code> - number of node outputs</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h4>Using environment variables</h4>
|
<h4>Using environment variables</h4>
|
||||||
<p>Environment variables can be accessed using <code>env.get("MY_ENV_VAR")</code>.</p>
|
<p>Environment variables can be accessed using <code>env.get("MY_ENV_VAR")</code>.</p>
|
||||||
|
@ -227,6 +227,7 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"externalModuleNotAllowed": "Function node not allowed to load external modules",
|
"externalModuleNotAllowed": "Function node not allowed to load external modules",
|
||||||
"moduleNotAllowed": "Module __module__ not allowed",
|
"moduleNotAllowed": "Module __module__ not allowed",
|
||||||
|
"externalModuleLoadError": "Function node failed to load external modules",
|
||||||
"moduleLoadError": "Failed to load module __module__: __error__",
|
"moduleLoadError": "Failed to load module __module__: __error__",
|
||||||
"moduleNameError": "Invalid module variable name: __name__",
|
"moduleNameError": "Invalid module variable name: __name__",
|
||||||
"moduleNameReserved": "Reserved variable name: __name__",
|
"moduleNameReserved": "Reserved variable name: __name__",
|
||||||
@ -877,6 +878,7 @@
|
|||||||
},
|
},
|
||||||
"encoding": {
|
"encoding": {
|
||||||
"none": "default",
|
"none": "default",
|
||||||
|
"setbymsg": "set by msg.encoding",
|
||||||
"native": "Native",
|
"native": "Native",
|
||||||
"unicode": "Unicode",
|
"unicode": "Unicode",
|
||||||
"japanese": "Japanese",
|
"japanese": "Japanese",
|
||||||
|
@ -91,7 +91,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="optional">complete</dt>
|
<dt class="optional">complete</dt>
|
||||||
<dd>If set, the node will append the payload, and then send the output message in its current state.
|
<dd>If set, the node will append the payload, and then send the output message in its current state.
|
||||||
If you don't wish to append the payload, delete it from the msg.</dd>
|
If you don't wish to append the payload, delete it from the msg.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Details</h3>
|
<h3>Details</h3>
|
||||||
@ -150,6 +150,7 @@
|
|||||||
<p>By default, the reduce expression is applied in order, from the first
|
<p>By default, the reduce expression is applied in order, from the first
|
||||||
to the last message of the sequence. It can optionally be applied in
|
to the last message of the sequence. It can optionally be applied in
|
||||||
reverse order.</p>
|
reverse order.</p>
|
||||||
|
<p>$N is the number of messages that arrive - even if they are identical.</p>
|
||||||
</dl>
|
</dl>
|
||||||
<p><b>Example:</b> the following settings, given a sequence of numeric values,
|
<p><b>Example:</b> the following settings, given a sequence of numeric values,
|
||||||
calculates the average value:
|
calculates the average value:
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt class="optional">filename <span class="property-type">string</span></dt>
|
<dt class="optional">filename <span class="property-type">string</span></dt>
|
||||||
<dd>If not configured in the node, this optional property sets the name of the file to be updated.</dd>
|
<dd>If not configured in the node, this optional property sets the name of the file to be updated.</dd>
|
||||||
|
<dt class="optional">encoding <span class="property-type">string</span></dt>
|
||||||
|
<dd>If encoding is configured to be set by msg, then this optional property can set the encoding.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Output</h3>
|
<h3>Output</h3>
|
||||||
<p>On completion of write, input message is sent to output port.</p>
|
<p>On completion of write, input message is sent to output port.</p>
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
<p>入力メッセージは<code>msg</code>という名称のJavaScriptオブジェクトで受け渡されます。</p>
|
<p>入力メッセージは<code>msg</code>という名称のJavaScriptオブジェクトで受け渡されます。</p>
|
||||||
<p><code>msg</code>オブジェクトは<code>msg.payload</code>プロパティにメッセージ本体を保持するのが慣例です。</p>
|
<p><code>msg</code>オブジェクトは<code>msg.payload</code>プロパティにメッセージ本体を保持するのが慣例です。</p>
|
||||||
<p>通常、コードはメッセージオブジェクト(もしくは複数のメッセージオブジェクト)を返却します。後続フローの実行を停止したい場合は、オブジェクトを返却しなくてもかまいません。</p>
|
<p>通常、コードはメッセージオブジェクト(もしくは複数のメッセージオブジェクト)を返却します。後続フローの実行を停止したい場合は、オブジェクトを返却しなくてもかまいません。</p>
|
||||||
<p>Node-REDの開始時もしくはフローの設定をデプロイした際実行される初期化コードを<b>初期化処理</b>タブに、ノードの停止もしくは再デプロイ時に実行される終了処理コードを<b>終了処理</b>タブに指定できます。</p>
|
<p><b>初期化処理</b>タブにはノードの開始時に実行されるコードを、<b>終了処理</b>タブにはノードの終了時に実行されるコードを指定します。</p>
|
||||||
<p>初期化処理タブの返却値としてPromiseを返却すると、入力メッセージの処理を開始する前にその完了を待ちます。</p>
|
<p>初期化処理タブの返却値としてPromiseオブジェクトを返却すると、入力メッセージの処理を開始する前にその完了を待ちます。</p>
|
||||||
<h3>詳細</h3>
|
<h3>詳細</h3>
|
||||||
<p>コードの書き方の詳細については、<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a>を参照してください。</p>
|
<p>コードの書き方の詳細については、<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a>を参照してください。</p>
|
||||||
<h4>メッセージの送信</h4>
|
<h4>メッセージの送信</h4>
|
||||||
@ -44,10 +44,11 @@
|
|||||||
<p>catchノードを用いてエラー処理が可能です。catchノードで処理させるためには、<code>msg</code>を<code>node.error</code>の第二引数として渡します:</p>
|
<p>catchノードを用いてエラー処理が可能です。catchノードで処理させるためには、<code>msg</code>を<code>node.error</code>の第二引数として渡します:</p>
|
||||||
<pre>node.error("エラー",msg);</pre>
|
<pre>node.error("エラー",msg);</pre>
|
||||||
<h4>ノード情報の参照</h4>
|
<h4>ノード情報の参照</h4>
|
||||||
<p>コード中ではノードのIDおよび名前を以下のプロパティで参照できます:</p>
|
<p>ノードに関する情報を参照するための以下のプロパティを利用できます:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>node.id</code> - ノードのID</li>
|
<li><code>node.id</code> - ノードのID</li>
|
||||||
<li><code>node.name</code> - ノードの名称</li>
|
<li><code>node.name</code> - ノードの名称</li>
|
||||||
|
<li><code>node.outputCount</code> - ノードの出力数</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h4>環境変数の利用</h4>
|
<h4>環境変数の利用</h4>
|
||||||
<p>環境変数は<code>env.get("MY_ENV_VAR")</code>により参照できます。</p>
|
<p>環境変数は<code>env.get("MY_ENV_VAR")</code>により参照できます。</p>
|
||||||
|
@ -227,6 +227,7 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"externalModuleNotAllowed": "Functionノードは、外部モジュールを読み込みできません",
|
"externalModuleNotAllowed": "Functionノードは、外部モジュールを読み込みできません",
|
||||||
"moduleNotAllowed": "モジュール __module__ は利用できません",
|
"moduleNotAllowed": "モジュール __module__ は利用できません",
|
||||||
|
"externalModuleLoadError": "Functionノードは、外部モジュールの読み込みに失敗しました",
|
||||||
"moduleLoadError": "モジュール __module__ の読み込みに失敗しました: __error__",
|
"moduleLoadError": "モジュール __module__ の読み込みに失敗しました: __error__",
|
||||||
"moduleNameError": "モジュール変数名が不正です: __name__",
|
"moduleNameError": "モジュール変数名が不正です: __name__",
|
||||||
"moduleNameReserved": "予約された変数名です: __name__",
|
"moduleNameReserved": "予約された変数名です: __name__",
|
||||||
@ -875,6 +876,7 @@
|
|||||||
},
|
},
|
||||||
"encoding": {
|
"encoding": {
|
||||||
"none": "デフォルト",
|
"none": "デフォルト",
|
||||||
|
"setbymsg": "msg.encodingで設定",
|
||||||
"native": "ネイティブ",
|
"native": "ネイティブ",
|
||||||
"unicode": "UNICODE",
|
"unicode": "UNICODE",
|
||||||
"japanese": "日本",
|
"japanese": "日本",
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt class="optional">filename <span class="property-type">文字列</span></dt>
|
<dt class="optional">filename <span class="property-type">文字列</span></dt>
|
||||||
<dd>対象ファイル名をノードに設定していない場合、このプロパティでファイルを指定できます</dd>
|
<dd>対象ファイル名をノードに設定していない場合、このプロパティでファイルを指定できます</dd>
|
||||||
|
<dt class="optional">encoding <span class="property-type">文字列</span></dt>
|
||||||
|
<dd>エンコーディングをmsgで設定する構成にした際は、この任意のプロパティでエンコーディングを設定できます。</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>出力</h3>
|
<h3>出力</h3>
|
||||||
<p>書き込みの完了時、入力メッセージを出力端子に送出します。</p>
|
<p>書き込みの完了時、入力メッセージを出力端子に送出します。</p>
|
||||||
|
@ -329,7 +329,7 @@
|
|||||||
"port": "포트",
|
"port": "포트",
|
||||||
"keepalive": "킵 얼라이브 시간",
|
"keepalive": "킵 얼라이브 시간",
|
||||||
"cleansession": "세션 초기화",
|
"cleansession": "세션 초기화",
|
||||||
"use-tls": "SSL/TLS접속을 사용",
|
"use-tls": "사용TLS",
|
||||||
"tls-config": "TLS설정",
|
"tls-config": "TLS설정",
|
||||||
"verify-server-cert": "서버인증서를 확인",
|
"verify-server-cert": "서버인증서를 확인",
|
||||||
"compatmode": "구 MQTT 3.1서포트"
|
"compatmode": "구 MQTT 3.1서포트"
|
||||||
|
@ -352,7 +352,7 @@
|
|||||||
"port": "Порт",
|
"port": "Порт",
|
||||||
"keepalive": "Keep-alive время (сек)",
|
"keepalive": "Keep-alive время (сек)",
|
||||||
"cleansession": "Использовать чистую сессию",
|
"cleansession": "Использовать чистую сессию",
|
||||||
"use-tls": "Включить безопасное (SSL/TLS) соединение",
|
"use-tls": "TLS",
|
||||||
"tls-config":"Конфигурация TLS",
|
"tls-config":"Конфигурация TLS",
|
||||||
"verify-server-cert":"Проверить сертификат сервера",
|
"verify-server-cert":"Проверить сертификат сервера",
|
||||||
"compatmode": "Использовать устаревшую поддержку MQTT 3.1"
|
"compatmode": "Использовать устаревшую поддержку MQTT 3.1"
|
||||||
|
@ -349,7 +349,7 @@
|
|||||||
"port": "端口",
|
"port": "端口",
|
||||||
"keepalive": "Keepalive计时(秒)",
|
"keepalive": "Keepalive计时(秒)",
|
||||||
"cleansession": "使用新的会话",
|
"cleansession": "使用新的会话",
|
||||||
"use-tls": "使用安全连接 (SSL/TLS)",
|
"use-tls": "使用 TLS",
|
||||||
"tls-config": "TLS 设置",
|
"tls-config": "TLS 设置",
|
||||||
"verify-server-cert": "验证服务器证书",
|
"verify-server-cert": "验证服务器证书",
|
||||||
"compatmode": "使用旧式MQTT 3.1支持"
|
"compatmode": "使用旧式MQTT 3.1支持"
|
||||||
|
@ -353,7 +353,7 @@
|
|||||||
"port": "埠",
|
"port": "埠",
|
||||||
"keepalive": "Keepalive計時(秒)",
|
"keepalive": "Keepalive計時(秒)",
|
||||||
"cleansession": "使用新的會話",
|
"cleansession": "使用新的會話",
|
||||||
"use-tls": "使用安全連接 (SSL/TLS)",
|
"use-tls": "使用 TLS",
|
||||||
"tls-config": "TLS 設置",
|
"tls-config": "TLS 設置",
|
||||||
"verify-server-cert": "驗證伺服器憑證",
|
"verify-server-cert": "驗證伺服器憑證",
|
||||||
"compatmode": "使用舊式MQTT 3.1支援"
|
"compatmode": "使用舊式MQTT 3.1支援"
|
||||||
|
@ -472,7 +472,7 @@ function getPackageList() {
|
|||||||
try {
|
try {
|
||||||
var userPackage = path.join(settings.userDir,"package.json");
|
var userPackage = path.join(settings.userDir,"package.json");
|
||||||
var pkg = JSON.parse(fs.readFileSync(userPackage,"utf-8"));
|
var pkg = JSON.parse(fs.readFileSync(userPackage,"utf-8"));
|
||||||
return pkg.dependencies;
|
return pkg.dependencies || {};
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
log.error(err);
|
log.error(err);
|
||||||
}
|
}
|
||||||
|
@ -272,7 +272,7 @@ var api = module.exports = {
|
|||||||
} catch(error) {
|
} catch(error) {
|
||||||
runtime.log.audit({event: "nodes.remove",module:opts.module,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
|
runtime.log.audit({event: "nodes.remove",module:opts.module,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
|
||||||
error.status = 400;
|
error.status = 400;
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -319,7 +319,7 @@ var api = module.exports = {
|
|||||||
} catch(error) {
|
} catch(error) {
|
||||||
runtime.log.audit({event: "nodes.module.set",module:mod,enabled:opts.enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
|
runtime.log.audit({event: "nodes.module.set",module:mod,enabled:opts.enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
|
||||||
error.status = 400;
|
error.status = 400;
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ var api = module.exports = {
|
|||||||
} catch(error) {
|
} catch(error) {
|
||||||
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
|
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
|
||||||
error.status = 400;
|
error.status = 400;
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ var api = module.exports = {
|
|||||||
* @memberof @node-red/runtime_plugins
|
* @memberof @node-red/runtime_plugins
|
||||||
*/
|
*/
|
||||||
getPluginConfigs: async function(opts) {
|
getPluginConfigs: async function(opts) {
|
||||||
if (/[^a-z\-]/i.test(opts.lang)) {
|
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
|
||||||
throw new Error("Invalid language: "+opts.lang)
|
throw new Error("Invalid language: "+opts.lang)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,9 @@ function createNode(flow,config) {
|
|||||||
} else if (nodeTypeConstructor) {
|
} else if (nodeTypeConstructor) {
|
||||||
// console.log(nodeTypeConstructor)
|
// console.log(nodeTypeConstructor)
|
||||||
var subflowConfig = parseConfig([nodeTypeConstructor.subflow].concat(nodeTypeConstructor.subflow.flow));
|
var subflowConfig = parseConfig([nodeTypeConstructor.subflow].concat(nodeTypeConstructor.subflow.flow));
|
||||||
|
var subflowInstanceConfig = subflowConfig.subflows[nodeTypeConstructor.subflow.id];
|
||||||
|
delete subflowConfig.subflows[nodeTypeConstructor.subflow.id];
|
||||||
|
subflowInstanceConfig.subflows = subflowConfig.subflows;
|
||||||
var instanceConfig = clone(config);
|
var instanceConfig = clone(config);
|
||||||
instanceConfig.env = clone(nodeTypeConstructor.subflow.env);
|
instanceConfig.env = clone(nodeTypeConstructor.subflow.env);
|
||||||
|
|
||||||
@ -124,7 +127,7 @@ function createNode(flow,config) {
|
|||||||
nodeTypeConstructor.type,
|
nodeTypeConstructor.type,
|
||||||
flow,
|
flow,
|
||||||
flow.global,
|
flow.global,
|
||||||
subflowConfig.subflows[nodeTypeConstructor.subflow.id],
|
subflowInstanceConfig,
|
||||||
instanceConfig
|
instanceConfig
|
||||||
);
|
);
|
||||||
subflow.start();
|
subflow.start();
|
||||||
|
@ -63,6 +63,27 @@ var server;
|
|||||||
*/
|
*/
|
||||||
function init(userSettings,httpServer,_adminApi) {
|
function init(userSettings,httpServer,_adminApi) {
|
||||||
server = httpServer;
|
server = httpServer;
|
||||||
|
|
||||||
|
if (server && server.on) {
|
||||||
|
// Add a listener to the upgrade event so that we can properly timeout connection
|
||||||
|
// attempts that do not get handled by any nodes in the user's flow.
|
||||||
|
// See #2956
|
||||||
|
server.on('upgrade',(request, socket, head) => {
|
||||||
|
// Add a no-op handler to the error event in case nothing upgrades this socket
|
||||||
|
// before the remote end closes it. This ensures we don't get as uncaughtException
|
||||||
|
socket.on("error", err => {})
|
||||||
|
setTimeout(function() {
|
||||||
|
// If this request has been handled elsewhere, the upgrade will have
|
||||||
|
// been completed and bytes written back to the client.
|
||||||
|
// If nothing has been written on the socket, nothing has handled the
|
||||||
|
// upgrade, so we can consider this an unhandled upgrade.
|
||||||
|
if (socket.bytesWritten === 0) {
|
||||||
|
socket.destroy();
|
||||||
|
}
|
||||||
|
},userSettings.inboundWebSocketTimeout || 5000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
userSettings.version = getVersion();
|
userSettings.version = getVersion();
|
||||||
settings.init(userSettings);
|
settings.init(userSettings);
|
||||||
|
|
||||||
@ -199,7 +220,7 @@ var reinstallTimeout;
|
|||||||
function reinstallModules(moduleList) {
|
function reinstallModules(moduleList) {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
const reinstallList = [];
|
const reinstallList = [];
|
||||||
const installRetry = 30000;
|
var installRetry = 30000;
|
||||||
if (settings.hasOwnProperty('autoInstallModulesRetry')) {
|
if (settings.hasOwnProperty('autoInstallModulesRetry')) {
|
||||||
log.warn(log._("server.deprecatedOption",{old:"autoInstallModulesRetry", new:"externalModules.autoInstallRetry"}));
|
log.warn(log._("server.deprecatedOption",{old:"autoInstallModulesRetry", new:"externalModules.autoInstallRetry"}));
|
||||||
installRetry = settings.autoInstallModulesRetry;
|
installRetry = settings.autoInstallModulesRetry;
|
||||||
|
@ -338,12 +338,14 @@ Node.prototype.close = function(removed) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (promises.length > 0) {
|
if (promises.length > 0) {
|
||||||
return Promise.all(promises).then(function() {
|
return Promise.all(promises).then(() => {
|
||||||
|
this.removeAllListeners("input")
|
||||||
if (this._context) {
|
if (this._context) {
|
||||||
return context.delete(this._alias||this.id,this.z);
|
return context.delete(this._alias||this.id,this.z);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
this.removeAllListeners("input")
|
||||||
if (this._context) {
|
if (this._context) {
|
||||||
return context.delete(this._alias||this.id,this.z);
|
return context.delete(this._alias||this.id,this.z);
|
||||||
}
|
}
|
||||||
|
@ -343,7 +343,11 @@ var api = module.exports = {
|
|||||||
if (newCreds) {
|
if (newCreds) {
|
||||||
delete node.credentials;
|
delete node.credentials;
|
||||||
var savedCredentials = credentialCache[nodeID] || {};
|
var savedCredentials = credentialCache[nodeID] || {};
|
||||||
if (/^subflow(:|$)/.test(nodeType)) {
|
// Need to check the type of constructor for this node.
|
||||||
|
// - Function : regular node
|
||||||
|
// - !Function: subflow module
|
||||||
|
|
||||||
|
if (/^subflow(:|$)/.test(nodeType) || typeof runtime.nodes.getType(nodeType) !== 'function') {
|
||||||
for (cred in newCreds) {
|
for (cred in newCreds) {
|
||||||
if (newCreds.hasOwnProperty(cred)) {
|
if (newCreds.hasOwnProperty(cred)) {
|
||||||
if (newCreds[cred] === "__PWRD__") {
|
if (newCreds[cred] === "__PWRD__") {
|
||||||
|
@ -612,8 +612,15 @@ async function saveFlows(flows, user) {
|
|||||||
var workflowMode = (gitSettings.workflow||{}).mode || settings.editorTheme.projects.workflow.mode;
|
var workflowMode = (gitSettings.workflow||{}).mode || settings.editorTheme.projects.workflow.mode;
|
||||||
if (workflowMode === 'auto') {
|
if (workflowMode === 'auto') {
|
||||||
return activeProject.stageFile([flowsFullPath, credentialsFile]).then(() => {
|
return activeProject.stageFile([flowsFullPath, credentialsFile]).then(() => {
|
||||||
return activeProject.commit(user,{message:"Update flow files"})
|
return activeProject.status(user, false).then((result) => {
|
||||||
})
|
const items = Object.values(result.files || {});
|
||||||
|
// check if saved flow make modification to repository
|
||||||
|
if (items.findIndex((item) => (item.status === "M ")) < 0) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return activeProject.commit(user,{message:"Update flow files"})
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -101,7 +101,7 @@ function add(hookId, callback) {
|
|||||||
function remove(hookId) {
|
function remove(hookId) {
|
||||||
let [id,label] = hookId.split(".");
|
let [id,label] = hookId.split(".");
|
||||||
if ( !label) {
|
if ( !label) {
|
||||||
throw new Error("Cannot remove hook without label: ",hookId)
|
throw new Error("Cannot remove hook without label: "+hookId)
|
||||||
}
|
}
|
||||||
Log.debug(`Removing hook '${hookId}'`);
|
Log.debug(`Removing hook '${hookId}'`);
|
||||||
if (labelledHooks[label]) {
|
if (labelledHooks[label]) {
|
||||||
|
@ -872,7 +872,7 @@ function encodeObject(msg,opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}," ");
|
});
|
||||||
} else {
|
} else {
|
||||||
try { msg.msg = msg.msg.toString(); }
|
try { msg.msg = msg.msg.toString(); }
|
||||||
catch(e) { msg.msg = "[Type not printable]" + util.inspect(msg.msg); }
|
catch(e) { msg.msg = "[Type not printable]" + util.inspect(msg.msg); }
|
||||||
|
5
packages/node_modules/node-red/settings.js
vendored
5
packages/node_modules/node-red/settings.js
vendored
@ -57,6 +57,11 @@ module.exports = {
|
|||||||
// defaults to the working directory of the Node-RED process.
|
// defaults to the working directory of the Node-RED process.
|
||||||
//fileWorkingDirectory: "",
|
//fileWorkingDirectory: "",
|
||||||
|
|
||||||
|
// Timeout in milliseconds for inbound WebSocket connections that do not
|
||||||
|
// match any configured node.
|
||||||
|
// defaults to 5000
|
||||||
|
//inboundWebSocketTimeout: 5000,
|
||||||
|
|
||||||
// The maximum length, in characters, of any message sent to the debug sidebar tab
|
// The maximum length, in characters, of any message sent to the debug sidebar tab
|
||||||
debugMaxLength: 1000,
|
debugMaxLength: 1000,
|
||||||
|
|
||||||
|
@ -22,10 +22,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const os = require("os");
|
||||||
const nopt = require("nopt");
|
const nopt = require("nopt");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fs = require("fs")
|
const fs = require("fs-extra");
|
||||||
const sass = require("node-sass");
|
const sass = require("sass");
|
||||||
|
|
||||||
const knownOpts = {
|
const knownOpts = {
|
||||||
"help": Boolean,
|
"help": Boolean,
|
||||||
@ -73,58 +74,58 @@ while((match = ruleRegex.exec(colorsFile)) !== null) {
|
|||||||
updatedColors.push(match[1]+": "+(customColors[match[1]]||match[2])+";")
|
updatedColors.push(match[1]+": "+(customColors[match[1]]||match[2])+";")
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = sass.renderSync({
|
|
||||||
outputStyle: "expanded",
|
(async function() {
|
||||||
file: path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/style.scss"),
|
const tmpDir = os.tmpdir();
|
||||||
importer: function(url, prev, done){
|
const workingDir = await fs.mkdtemp(`${tmpDir}${path.sep}`);
|
||||||
if (url === 'colors') {
|
await fs.copy(path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/"),workingDir)
|
||||||
return {
|
await fs.writeFile(path.join(workingDir,"colors.scss"),updatedColors.join("\n"))
|
||||||
contents: updatedColors.join("\n")
|
|
||||||
|
const result = sass.renderSync({
|
||||||
|
outputStyle: "expanded",
|
||||||
|
file: path.join(workingDir,"style.scss"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const css = result.css.toString()
|
||||||
|
const lines = css.split("\n");
|
||||||
|
const colorCSS = []
|
||||||
|
const nonColorCSS = [];
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
return {file:path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/"+url+".scss")}
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const css = result.css.toString()
|
const nrPkg = require("../package.json");
|
||||||
const lines = css.split("\n");
|
const now = new Date().toISOString();
|
||||||
const colorCSS = []
|
|
||||||
const nonColorCSS = [];
|
|
||||||
|
|
||||||
let inKeyFrameBlock = false;
|
const header = `/*
|
||||||
|
* Theme generated with Node-RED ${nrPkg.version} on ${now}
|
||||||
|
*/`;
|
||||||
|
|
||||||
lines.forEach(l => {
|
var output = sass.renderSync({outputStyle: parsedArgs.long?"expanded":"compressed",data:colorCSS.join("\n")});
|
||||||
if (inKeyFrameBlock) {
|
if (parsedArgs.out) {
|
||||||
nonColorCSS.push(l);
|
|
||||||
if (/^}/.test(l)) {
|
await fs.writeFile(parsedArgs.out,header+"\n"+output.css);
|
||||||
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 {
|
} else {
|
||||||
nonColorCSS.push(l);
|
console.log(header);
|
||||||
|
console.log(output.css.toString());
|
||||||
}
|
}
|
||||||
});
|
await fs.remove(workingDir);
|
||||||
|
})()
|
||||||
|
|
||||||
const nrPkg = require("../package.json");
|
|
||||||
const now = new Date().toISOString();
|
|
||||||
|
|
||||||
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) {
|
|
||||||
|
|
||||||
fs.writeFileSync(parsedArgs.out,header+"\n"+output.css);
|
|
||||||
} else {
|
|
||||||
console.log(header);
|
|
||||||
console.log(output.css.toString());
|
|
||||||
}
|
|
||||||
|
@ -104,7 +104,7 @@ describe('debug node', function() {
|
|||||||
}, function(msg) {
|
}, function(msg) {
|
||||||
JSON.parse(msg).should.eql([{
|
JSON.parse(msg).should.eql([{
|
||||||
topic:"debug",
|
topic:"debug",
|
||||||
data:{id:"n1",msg:'{\n "payload": "test"\n}',format:"Object",path:"global"}
|
data:{id:"n1",msg:'{"payload":"test"}',format:"Object",path:"global"}
|
||||||
}]);
|
}]);
|
||||||
}, done);
|
}, done);
|
||||||
});
|
});
|
||||||
@ -119,7 +119,7 @@ describe('debug node', function() {
|
|||||||
}, function(msg) {
|
}, function(msg) {
|
||||||
JSON.parse(msg).should.eql([{
|
JSON.parse(msg).should.eql([{
|
||||||
topic:"debug",
|
topic:"debug",
|
||||||
data:{id:"n1",msg:'{\n "payload": "test"\n}',format:"Object",path:"global"}
|
data:{id:"n1",msg:'{"payload":"test"}',format:"Object",path:"global"}
|
||||||
}]);
|
}]);
|
||||||
}, function() {
|
}, function() {
|
||||||
try {
|
try {
|
||||||
@ -259,7 +259,7 @@ describe('debug node', function() {
|
|||||||
}, function(msg) {
|
}, function(msg) {
|
||||||
JSON.parse(msg).should.eql([{
|
JSON.parse(msg).should.eql([{
|
||||||
topic:"debug",
|
topic:"debug",
|
||||||
data:{id:"n1",msg:'{\n "type": "foo"\n}',property:"payload",format:"Object",path:"global"}
|
data:{id:"n1",msg:'{"type":"foo"}',property:"payload",format:"Object",path:"global"}
|
||||||
}]);
|
}]);
|
||||||
}, done);
|
}, done);
|
||||||
});
|
});
|
||||||
@ -274,7 +274,7 @@ describe('debug node', function() {
|
|||||||
}, function(msg) {
|
}, function(msg) {
|
||||||
JSON.parse(msg).should.eql([{
|
JSON.parse(msg).should.eql([{
|
||||||
topic:"debug",
|
topic:"debug",
|
||||||
data:{id:"n1",msg: '[\n 0,\n 1,\n 2,\n 3\n]',format:"array[4]",
|
data:{id:"n1",msg: '[0,1,2,3]',format:"array[4]",
|
||||||
property:"payload",path:"global"}
|
property:"payload",path:"global"}
|
||||||
}]);
|
}]);
|
||||||
}, done);
|
}, done);
|
||||||
@ -294,7 +294,7 @@ describe('debug node', function() {
|
|||||||
topic:"debug",
|
topic:"debug",
|
||||||
data:{
|
data:{
|
||||||
id:"n1",
|
id:"n1",
|
||||||
msg:'{\n "name": "bar",\n "o": "[Circular ~]"\n}',
|
msg:'{"name":"bar","o":"[Circular ~]"}',
|
||||||
property:"payload",format:"Object",path:"global"
|
property:"payload",format:"Object",path:"global"
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
@ -310,7 +310,7 @@ describe('debug node', function() {
|
|||||||
n1.emit("input", {payload: {type:'foo'}});
|
n1.emit("input", {payload: {type:'foo'}});
|
||||||
}, function(msg) {
|
}, function(msg) {
|
||||||
JSON.parse(msg).should.eql([{
|
JSON.parse(msg).should.eql([{
|
||||||
topic:"debug",data:{id:"n1",msg:'{\n "type": "foo"\n}',property:"payload",format:"Object",path:"global"}
|
topic:"debug",data:{id:"n1",msg:'{"type":"foo"}',property:"payload",format:"Object",path:"global"}
|
||||||
}]);
|
}]);
|
||||||
}, function() {
|
}, function() {
|
||||||
try {
|
try {
|
||||||
@ -406,7 +406,7 @@ describe('debug node', function() {
|
|||||||
topic:"debug",
|
topic:"debug",
|
||||||
data:{
|
data:{
|
||||||
id:"n1",
|
id:"n1",
|
||||||
msg:'{\n "foo": "'+Array(1001).join("X")+'..."\n}',
|
msg:'{"foo":"'+Array(1001).join("X")+'..."}',
|
||||||
property:"payload",
|
property:"payload",
|
||||||
format:"Object",
|
format:"Object",
|
||||||
path:"global"
|
path:"global"
|
||||||
@ -433,7 +433,7 @@ describe('debug node', function() {
|
|||||||
type: "array",
|
type: "array",
|
||||||
data: Array(1000).fill("X"),
|
data: Array(1000).fill("X"),
|
||||||
length: 1001
|
length: 1001
|
||||||
},null," "),
|
}),
|
||||||
property:"payload",
|
property:"payload",
|
||||||
format:"array[1001]",
|
format:"array[1001]",
|
||||||
path:"global"
|
path:"global"
|
||||||
@ -462,7 +462,7 @@ describe('debug node', function() {
|
|||||||
data: Array(1000).fill("X"),
|
data: Array(1000).fill("X"),
|
||||||
length: 1001
|
length: 1001
|
||||||
}
|
}
|
||||||
},null," "),
|
}),
|
||||||
property:"payload",
|
property:"payload",
|
||||||
format:"Object",
|
format:"Object",
|
||||||
path:"global"
|
path:"global"
|
||||||
@ -513,7 +513,7 @@ describe('debug node', function() {
|
|||||||
__enc__: true,
|
__enc__: true,
|
||||||
length: 1001
|
length: 1001
|
||||||
}
|
}
|
||||||
},null," "),
|
}),
|
||||||
property:"payload",
|
property:"payload",
|
||||||
format:"Object",
|
format:"Object",
|
||||||
path:"global"
|
path:"global"
|
||||||
|
@ -541,13 +541,17 @@ describe('exec node', function() {
|
|||||||
var n2 = helper.getNode("n2");
|
var n2 = helper.getNode("n2");
|
||||||
var n3 = helper.getNode("n3");
|
var n3 = helper.getNode("n3");
|
||||||
var n4 = helper.getNode("n4");
|
var n4 = helper.getNode("n4");
|
||||||
|
var payload = "";
|
||||||
n2.on("input", function(msg) {
|
n2.on("input", function(msg) {
|
||||||
//console.log(msg);
|
//console.log(msg);
|
||||||
try {
|
try {
|
||||||
msg.should.have.property("payload");
|
msg.should.have.property("payload");
|
||||||
msg.payload.should.be.a.String();
|
msg.payload.should.be.a.String();
|
||||||
msg.payload.should.equal(expected);
|
payload += msg.payload;
|
||||||
done();
|
if (payload.endsWith("\n")) {
|
||||||
|
payload.should.equal(expected);
|
||||||
|
done();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(err) { done(err); }
|
catch(err) { done(err); }
|
||||||
});
|
});
|
||||||
@ -567,6 +571,7 @@ describe('exec node', function() {
|
|||||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||||
expected = "12345 deg C\n";
|
expected = "12345 deg C\n";
|
||||||
}
|
}
|
||||||
|
var payload = "";
|
||||||
|
|
||||||
helper.load(execNode, flow, function() {
|
helper.load(execNode, flow, function() {
|
||||||
var n1 = helper.getNode("n1");
|
var n1 = helper.getNode("n1");
|
||||||
@ -578,8 +583,11 @@ describe('exec node', function() {
|
|||||||
try {
|
try {
|
||||||
msg.should.have.property("payload");
|
msg.should.have.property("payload");
|
||||||
msg.payload.should.be.a.String();
|
msg.payload.should.be.a.String();
|
||||||
msg.payload.should.equal(expected);
|
payload += msg.payload;
|
||||||
done();
|
if (payload.endsWith("\n")) {
|
||||||
|
payload.should.equal(expected);
|
||||||
|
done();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(err) { done(err); }
|
catch(err) { done(err); }
|
||||||
});
|
});
|
||||||
@ -661,8 +669,16 @@ describe('exec node', function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
n2.on("input", function(msg) {
|
n2.on("input", function(msg) {
|
||||||
messages[0] = msg;
|
var payload = msg.payload;
|
||||||
completeTest();
|
if (messages[0]) {
|
||||||
|
messages[0].payload += payload;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
messages[0] = msg;
|
||||||
|
}
|
||||||
|
if (payload.endsWith("\n")) {
|
||||||
|
completeTest();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
n4.on("input", function(msg) {
|
n4.on("input", function(msg) {
|
||||||
messages[1] = msg;
|
messages[1] = msg;
|
||||||
@ -869,8 +885,16 @@ describe('exec node', function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
n2.on("input", function(msg) {
|
n2.on("input", function(msg) {
|
||||||
messages[0] = msg;
|
var payload = msg.payload;
|
||||||
completeTest();
|
if (messages[0]) {
|
||||||
|
messages[0].payload += payload;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
messages[0] = msg;
|
||||||
|
}
|
||||||
|
if (payload.endsWith("\n")) {
|
||||||
|
completeTest();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
n4.on("input", function(msg) {
|
n4.on("input", function(msg) {
|
||||||
messages[1] = msg;
|
messages[1] = msg;
|
||||||
|
@ -87,6 +87,57 @@ describe('CSV node', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should convert a simple string to a javascript object with | separator (no template)', function(done) {
|
||||||
|
var flow = [ { id:"n1", type:"csv", sep:"|", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
helper.load(csvNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property('payload', { col1: 1, col2: 2, col3: 3, col4: 4 });
|
||||||
|
msg.should.have.property('columns', "col1,col2,col3,col4");
|
||||||
|
check_parts(msg, 0, 1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
var testString = "1|2|3|4"+String.fromCharCode(10);
|
||||||
|
n1.emit("input", {payload:testString});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert a simple string to a javascript object with tab separator (with template)', function(done) {
|
||||||
|
var flow = [ { id:"n1", type:"csv", sep:"\t", temp:"A,B,,D", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
helper.load(csvNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property('payload', { A: 1, B: 2, D: 4 });
|
||||||
|
msg.should.have.property('columns', "A,B,D");
|
||||||
|
check_parts(msg, 0, 1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
var testString = "1\t2\t3\t4"+String.fromCharCode(10);
|
||||||
|
n1.emit("input", {payload:testString});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert a simple string to a javascript object with space separator (with spaced template)', function(done) {
|
||||||
|
var flow = [ { id:"n1", type:"csv", sep:" ", temp:"A, B, , D", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
helper.load(csvNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property('payload', { A: 1, B: 2, D: 4 });
|
||||||
|
msg.should.have.property('columns', "A,B,D");
|
||||||
|
check_parts(msg, 0, 1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
var testString = "1 2 3 4"+String.fromCharCode(10);
|
||||||
|
n1.emit("input", {payload:testString});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should remove quotes and whitespace from template', function(done) {
|
it('should remove quotes and whitespace from template', function(done) {
|
||||||
var flow = [ { id:"n1", type:"csv", temp:'"a", "b" , " c "," d " ', wires:[["n2"]] },
|
var flow = [ { id:"n1", type:"csv", temp:'"a", "b" , " c "," d " ', wires:[["n2"]] },
|
||||||
{id:"n2", type:"helper"} ];
|
{id:"n2", type:"helper"} ];
|
||||||
@ -170,6 +221,58 @@ describe('CSV node', function() {
|
|||||||
n1.emit("input", {payload:testString});
|
n1.emit("input", {payload:testString});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow passing in a template as first line of CSV (not comma)', function(done) {
|
||||||
|
var flow = [ { id:"n1", type:"csv", temp:"", hdrin:true, sep:";", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
helper.load(csvNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property('payload', { a: 1, "b b":2, "c;c":3, "d, d": 4 });
|
||||||
|
msg.should.have.property('columns', 'a,b b,c;c,"d, d"');
|
||||||
|
check_parts(msg, 0, 1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
var testString = 'a;b b;"c;c";" d, d "'+"\n"+"1;2;3;4"+String.fromCharCode(10);
|
||||||
|
n1.emit("input", {payload:testString});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow passing in a template as first line of CSV (special char /)', function(done) {
|
||||||
|
var flow = [ { id:"n1", type:"csv", temp:"", hdrin:true, sep:"/", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
helper.load(csvNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property('payload', { a: 1, "b b":2, "c/c":3, "d, d": 4 });
|
||||||
|
msg.should.have.property('columns', 'a,b b,c/c,"d, d"');
|
||||||
|
check_parts(msg, 0, 1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
var testString = 'a/b b/"c/c"/" d, d "'+"\n"+"1/2/3/4"+String.fromCharCode(10);
|
||||||
|
n1.emit("input", {payload:testString});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow passing in a template as first line of CSV (special char \\)', function(done) {
|
||||||
|
var flow = [ { id:"n1", type:"csv", temp:"", hdrin:true, sep:"\\", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
helper.load(csvNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property('payload', { a: 1, "b b":2, "c\\c":3, "d, d": 4 });
|
||||||
|
msg.should.have.property('columns', 'a,b b,c\\c,"d, d"');
|
||||||
|
check_parts(msg, 0, 1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
var testString = 'a\\b b\\"c\\c"\\" d, d "'+"\n"+"1\\2\\3\\4"+String.fromCharCode(10);
|
||||||
|
n1.emit("input", {payload:testString});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should leave numbers starting with 0, e and + as strings (except 0.)', function(done) {
|
it('should leave numbers starting with 0, e and + as strings (except 0.)', function(done) {
|
||||||
var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g", wires:[["n2"]] },
|
var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g", wires:[["n2"]] },
|
||||||
{id:"n2", type:"helper"} ];
|
{id:"n2", type:"helper"} ];
|
||||||
@ -609,6 +712,24 @@ describe('CSV node', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should convert a simple object back to a tsv using a tab as a separator', function(done) {
|
||||||
|
var flow = [ { id:"n1", type:"csv", temp:"", sep:"\t", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
helper.load(csvNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property('payload', '1\tfoo\t"ba""r"\tdi,ng\n');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
catch(e) { done(e); }
|
||||||
|
});
|
||||||
|
var testJson = { d:1, b:"foo", c:"ba\"r", a:"di,ng" };
|
||||||
|
n1.emit("input", {payload:testJson});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle a template with spaces in the property names', function(done) {
|
it('should handle a template with spaces in the property names', function(done) {
|
||||||
var flow = [ { id:"n1", type:"csv", temp:"a,b o,c p,,e", wires:[["n2"]] },
|
var flow = [ { id:"n1", type:"csv", temp:"a,b o,c p,,e", wires:[["n2"]] },
|
||||||
{id:"n2", type:"helper"} ];
|
{id:"n2", type:"helper"} ];
|
||||||
|
@ -36,102 +36,96 @@ describe('red/runtime/nodes/credentials', function() {
|
|||||||
index.clearRegistry();
|
index.clearRegistry();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loads provided credentials',function(done) {
|
it('loads provided credentials',function() {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings
|
||||||
});
|
});
|
||||||
|
|
||||||
credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
return credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
||||||
|
|
||||||
credentials.get("a").should.have.property('b',1);
|
credentials.get("a").should.have.property('b',1);
|
||||||
credentials.get("a").should.have.property('c',2);
|
credentials.get("a").should.have.property('c',2);
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('adds a new credential',function(done) {
|
it('adds a new credential',function() {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings
|
||||||
});
|
});
|
||||||
credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
return credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
||||||
credentials.dirty().should.be.false();
|
credentials.dirty().should.be.false();
|
||||||
should.not.exist(credentials.get("b"));
|
should.not.exist(credentials.get("b"));
|
||||||
credentials.add("b",{"foo":"bar"}).then(function() {
|
return credentials.add("b",{"foo":"bar"}).then(function() {
|
||||||
credentials.get("b").should.have.property("foo","bar");
|
credentials.get("b").should.have.property("foo","bar");
|
||||||
credentials.dirty().should.be.true();
|
credentials.dirty().should.be.true();
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('deletes an existing credential',function(done) {
|
it('deletes an existing credential',function() {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings
|
||||||
});
|
});
|
||||||
credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
return credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
||||||
credentials.dirty().should.be.false();
|
credentials.dirty().should.be.false();
|
||||||
credentials.delete("a");
|
credentials.delete("a");
|
||||||
should.not.exist(credentials.get("a"));
|
should.not.exist(credentials.get("a"));
|
||||||
credentials.dirty().should.be.true();
|
credentials.dirty().should.be.true();
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports the credentials, clearing dirty flag', function(done) {
|
it('exports the credentials, clearing dirty flag', function() {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings
|
||||||
});
|
});
|
||||||
var creds = {"a":{"b":1,"c":2}};
|
var creds = {"a":{"b":1,"c":2}};
|
||||||
credentials.load(creds).then(function() {
|
return credentials.load(creds).then(function() {
|
||||||
credentials.add("b",{"foo":"bar"}).then(function() {
|
return credentials.add("b",{"foo":"bar"})
|
||||||
credentials.dirty().should.be.true();
|
}).then(function() {
|
||||||
credentials.export().then(function(exported) {
|
credentials.dirty().should.be.true();
|
||||||
exported.should.eql(creds);
|
return credentials.export().then(function(exported) {
|
||||||
credentials.dirty().should.be.false();
|
exported.should.eql(creds);
|
||||||
done();
|
credentials.dirty().should.be.false();
|
||||||
})
|
})
|
||||||
});
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("#clean",function() {
|
describe("#clean",function() {
|
||||||
it("removes credentials of unknown nodes",function(done) {
|
it("removes credentials of unknown nodes",function() {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings,
|
||||||
|
nodes: { getType: () => function(){} }
|
||||||
});
|
});
|
||||||
var creds = {"a":{"b":1,"c":2},"b":{"d":3}};
|
var creds = {"a":{"b":1,"c":2},"b":{"d":3}};
|
||||||
credentials.load(creds).then(function() {
|
return credentials.load(creds).then(function() {
|
||||||
credentials.dirty().should.be.false();
|
credentials.dirty().should.be.false();
|
||||||
should.exist(credentials.get("a"));
|
should.exist(credentials.get("a"));
|
||||||
should.exist(credentials.get("b"));
|
should.exist(credentials.get("b"));
|
||||||
credentials.clean([{id:"b"}]).then(function() {
|
return credentials.clean([{id:"b"}]).then(function() {
|
||||||
credentials.dirty().should.be.true();
|
credentials.dirty().should.be.true();
|
||||||
should.not.exist(credentials.get("a"));
|
should.not.exist(credentials.get("a"));
|
||||||
should.exist(credentials.get("b"));
|
should.exist(credentials.get("b"));
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("extracts credentials of known nodes",function(done) {
|
it("extracts credentials of known nodes",function() {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings,
|
||||||
|
nodes: { getType: () => function(){} }
|
||||||
});
|
});
|
||||||
credentials.register("testNode",{"b":"text","c":"password"})
|
credentials.register("testNode",{"b":"text","c":"password"})
|
||||||
var creds = {"a":{"b":1,"c":2}};
|
var creds = {"a":{"b":1,"c":2}};
|
||||||
var newConfig = [{id:"a",type:"testNode",credentials:{"b":"newBValue","c":"newCValue"}}];
|
var newConfig = [{id:"a",type:"testNode",credentials:{"b":"newBValue","c":"newCValue"}}];
|
||||||
credentials.load(creds).then(function() {
|
return credentials.load(creds).then(function() {
|
||||||
credentials.dirty().should.be.false();
|
credentials.dirty().should.be.false();
|
||||||
credentials.clean(newConfig).then(function() {
|
return credentials.clean(newConfig).then(function() {
|
||||||
credentials.dirty().should.be.true();
|
credentials.dirty().should.be.true();
|
||||||
credentials.get("a").should.have.property('b',"newBValue");
|
credentials.get("a").should.have.property('b',"newBValue");
|
||||||
credentials.get("a").should.have.property('c',"newCValue");
|
credentials.get("a").should.have.property('c',"newCValue");
|
||||||
should.not.exist(newConfig[0].credentials);
|
should.not.exist(newConfig[0].credentials);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -139,12 +133,13 @@ describe('red/runtime/nodes/credentials', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('warns if a node has no credential definition', function(done) {
|
it('warns if a node has no credential definition', function() {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings,
|
||||||
|
nodes: { getType: () => function(){} }
|
||||||
});
|
});
|
||||||
credentials.load({}).then(function() {
|
return credentials.load({}).then(function() {
|
||||||
var node = {id:"node",type:"test",credentials:{
|
var node = {id:"node",type:"test",credentials:{
|
||||||
user1:"newUser",
|
user1:"newUser",
|
||||||
password1:"newPassword"
|
password1:"newPassword"
|
||||||
@ -154,14 +149,14 @@ describe('red/runtime/nodes/credentials', function() {
|
|||||||
log.warn.called.should.be.true();
|
log.warn.called.should.be.true();
|
||||||
should.not.exist(node.credentials);
|
should.not.exist(node.credentials);
|
||||||
log.warn.restore();
|
log.warn.restore();
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
it('extract credential updates in the provided node', function(done) {
|
it('extract credential updates in the provided node', function(done) {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings,
|
||||||
|
nodes: { getType: () => function(){} }
|
||||||
});
|
});
|
||||||
var defintion = {
|
var defintion = {
|
||||||
user1:{type:"text"},
|
user1:{type:"text"},
|
||||||
@ -205,7 +200,8 @@ describe('red/runtime/nodes/credentials', function() {
|
|||||||
it('extract ignores node without credentials', function(done) {
|
it('extract ignores node without credentials', function(done) {
|
||||||
credentials.init({
|
credentials.init({
|
||||||
log: log,
|
log: log,
|
||||||
settings: encryptionDisabledSettings
|
settings: encryptionDisabledSettings,
|
||||||
|
nodes: { getType: () => function(){} }
|
||||||
});
|
});
|
||||||
credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() {
|
credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() {
|
||||||
var node = {id:"node",type:"test"};
|
var node = {id:"node",type:"test"};
|
||||||
@ -233,7 +229,8 @@ describe('red/runtime/nodes/credentials', function() {
|
|||||||
delete settings[key];
|
delete settings[key];
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
nodes: { getType: () => function(){} }
|
||||||
}
|
}
|
||||||
it('migrates to encrypted and generates default key', function(done) {
|
it('migrates to encrypted and generates default key', function(done) {
|
||||||
settings = {};
|
settings = {};
|
||||||
@ -341,7 +338,7 @@ describe('red/runtime/nodes/credentials', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('migrates from default key to user key', function(done) {
|
it('migrates from default key to user key', function() {
|
||||||
settings = {
|
settings = {
|
||||||
_credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a",
|
_credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a",
|
||||||
credentialSecret: "aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccccccccccddddddddddddeeeee"
|
credentialSecret: "aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccccccccccddddddddddddeeeee"
|
||||||
@ -349,21 +346,20 @@ describe('red/runtime/nodes/credentials', function() {
|
|||||||
// {"node":{user1:"abc",password1:"123"}}
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
||||||
credentials.init(runtime);
|
credentials.init(runtime);
|
||||||
credentials.load(cryptedFlows).then(function() {
|
return credentials.load(cryptedFlows).then(function() {
|
||||||
credentials.dirty().should.be.true();
|
credentials.dirty().should.be.true();
|
||||||
should.exist(credentials.get("node"));
|
should.exist(credentials.get("node"));
|
||||||
credentials.export().then(function(result) {
|
return credentials.export().then(function(result) {
|
||||||
result.should.have.a.property("$");
|
result.should.have.a.property("$");
|
||||||
settings.should.not.have.a.property("_credentialSecret");
|
settings.should.not.have.a.property("_credentialSecret");
|
||||||
|
|
||||||
// reset everything - but with _credentialSecret still set
|
// reset everything - but with _credentialSecret still set
|
||||||
credentials.init(runtime);
|
credentials.init(runtime);
|
||||||
// load the freshly encrypted version
|
// load the freshly encrypted version
|
||||||
credentials.load(result).then(function() {
|
return credentials.load(result).then(function() {
|
||||||
should.exist(credentials.get("node"));
|
should.exist(credentials.get("node"));
|
||||||
credentials.get("node").should.have.a.property("user1","abc");
|
credentials.get("node").should.have.a.property("user1","abc");
|
||||||
credentials.get("node").should.have.a.property("password1","123");
|
credentials.get("node").should.have.a.property("password1","123");
|
||||||
done();
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -459,7 +455,8 @@ describe('red/runtime/nodes/credentials', function() {
|
|||||||
set: function(key,value) {
|
set: function(key,value) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
nodes: { getType: () => function(){} }
|
||||||
}
|
}
|
||||||
// {"node":{user1:"abc",password1:"123"}}
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
credentials.init(runtime);
|
credentials.init(runtime);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user