Compare commits

..

58 Commits

Author SHA1 Message Date
Dave Conway-Jones
6ac0c0a367 fix 2nd output when in rate limit per topic modes
to fix issue found in #3260
2021-11-15 14:05:16 +00:00
Nick O'Leary
3e0f080ea7 Merge pull request #3242 from node-red/inject-fix
Do not modify inject node props in oneditprepare
2021-11-01 21:40:47 +00:00
Nick O'Leary
679e07189d Do not modify inject node props in oneditprepare
Fixes #3241
2021-11-01 20:10:52 +00:00
Nick O'Leary
d3efb9d7cc Merge pull request #3238 from node-red/treeLister-gutter-fix
Fix treeList gutter calculation to handle floating gutters
2021-10-28 10:46:04 +01:00
Nick O'Leary
84a237d3f5 Fix treeList gutter calculation to handle floating gutters
Fixes #3234
2021-10-28 10:44:50 +01:00
Nick O'Leary
e6de52eede Merge pull request #3236 from hardillb/http-basic-username-only
HTTP Basic Auth should always add : between username and password even if empty
2021-10-28 10:14:02 +01:00
Nick O'Leary
98aee964d7 Merge pull request #3237 from node-red/remove-de-style
Remove styling from de locale files
2021-10-28 10:11:54 +01:00
Nick O'Leary
570e5442e0 Remove styling from de locale files
Fixes #3230
2021-10-28 10:10:22 +01:00
Ben Hardill
b77a2dc353 Better fix 2021-10-28 10:08:28 +01:00
Ben Hardill
87af31de20 HTTP Basic Auth should always add : to username
fix for #3235
2021-10-28 09:18:17 +01:00
Nick O'Leary
cfe201dbe1 Bump for 2.1.3 2021-10-26 10:42:53 +01:00
Nick O'Leary
6ccdab35e0 Merge pull request #3227 from node-red/reload-node-settings
Refresh editor settings whenever a node is added or enabled
2021-10-26 09:51:41 +01:00
Nick O'Leary
55b9f36b45 Merge pull request #3229 from node-red/spinner-css
Revert spinner css change that made it shrink in some cases
2021-10-26 09:51:31 +01:00
Nick O'Leary
fbcb1130c9 Merge pull request #3221 from hardillb/disable-tours
Add environment variable to enable/disable tours
2021-10-26 09:47:17 +01:00
Nick O'Leary
d4f7a6d2bc Revert spinner css change that made it shrink in some cases 2021-10-26 09:44:32 +01:00
Nick O'Leary
8a19f71abe Refresh editor settings whenever a node is added or enabled
Fixes #3217

This ensures any node-provided settings are loaded and ready
for use by the nodes
2021-10-25 20:48:01 +01:00
Nick O'Leary
fb153757b5 Merge pull request #3225 from node-red/i18n-fix
Fix loading non-default language files leaving runtime in wrong locale
2021-10-25 16:06:12 +01:00
Nick O'Leary
4f175fc93e Fix loading non-default language files leaving runtime in wrong locale 2021-10-25 15:58:07 +01:00
Nick O'Leary
2d4ca7cec0 Merge pull request #3224 from node-red/import-msg-fix
Fix import notification message when importing config nodes
2021-10-25 15:12:46 +01:00
Nick O'Leary
bf0ea89969 Fix import notification message when importing config nodes 2021-10-25 15:08:30 +01:00
Nick O'Leary
073f0c2a20 Merge pull request #3223 from node-red/ti-fix
Handle changing types of TypedInput repeatedly
2021-10-25 13:55:38 +01:00
Nick O'Leary
ba83be9062 Handle changing types of TypedInput repeatedly
Fixes #3222
2021-10-25 13:54:42 +01:00
Ben Hardill
2e7188ea4f Add environment variable to enable/disable tours
NODE_RED_ENABLE_TOURS

Also had to patch editor-api/lib/editor/themes.js to pass
`editorTheme.tours` to the editor.
2021-10-25 11:25:31 +01:00
Nick O'Leary
5a012182d9 Update gen-publish script to update 'next' tag for main releases 2021-10-25 10:05:23 +01:00
Nick O'Leary
b855438af6 Fix changelog 2021-10-25 09:42:44 +01:00
Nick O'Leary
2ffea143e7 Bump for 2.1.2 2021-10-25 09:38:32 +01:00
Duncan Bellamy
61d85b49e6 Remove bash dependency (#3216)
Change backticks to dollar sign and parentheses
2021-10-25 08:44:49 +01:00
Nick O'Leary
35f617e96c Merge pull request #3213 from GerwinvBeek/markdown-regex
Improved regex for markdown renderer
2021-10-24 23:04:20 +01:00
Nick O'Leary
6b6ad47c35 Merge pull request #3220 from node-red/ti-fixes
Fix TypedInput initialisation
2021-10-24 22:58:55 +01:00
Nick O'Leary
e57183ed0e Merge pull request #3219 from Steve-Mcl/mqtt-use-datatype
fix datatype in node config not used. fixes #3215
2021-10-24 22:58:36 +01:00
Nick O'Leary
ecfd61a822 Fix TypedInput initialisation handle 2021-10-24 22:53:22 +01:00
Steve-Mcl
153f87704b fix datatype in node config not used. fixes #3215 2021-10-24 22:21:44 +01:00
Gerwin van Beek
836f7d2163 Improved regex for markdown renderer 2021-10-22 17:05:37 +02:00
Nick O'Leary
d4d6f71cf4 Bump for 2.1.1 2021-10-22 09:27:52 +01:00
Nick O'Leary
42a9da006e Merge pull request #3212 from node-red/fix-tour-guide-width
Ensure tourGuide popover doesn't fall offscreen
2021-10-22 09:26:31 +01:00
Nick O'Leary
2bd5c4f527 Ensure tourGuide popover doesn't fall offscreen
Only handles the left hand edge - will need expanding to cover
the other edges as needed
2021-10-22 09:24:40 +01:00
Nick O'Leary
6a49b5c106 Merge pull request #3210 from node-red/fix-old-inject-migration
Fix issue with old inject nodes that migrated topic to 'string' type
2021-10-22 09:16:54 +01:00
Nick O'Leary
23e14d1b72 Merge pull request #3211 from node-red/cache-bust
Add cache-busting query params to index.mst
2021-10-22 09:16:45 +01:00
Nick O'Leary
f4f11c8884 Add cache-busting query params to index.mst 2021-10-22 09:14:01 +01:00
Nick O'Leary
2b220abdb7 Fix issue with old inject nodes that migrated topic to 'string' type 2021-10-22 09:01:24 +01:00
Nick O'Leary
c1d947ebe3 Merge pull request #3207 from node-red/fix-debug-all
Fix TypedInput validation of type without options
2021-10-21 14:45:09 +01:00
Nick O'Leary
d695cf392e Fix TypedInput validation of type without options
Fixes #3206
2021-10-21 14:44:15 +01:00
Nick O'Leary
21304a695c Fix tcprequest deprecation warnings 2021-10-21 09:40:25 +01:00
Nick O'Leary
fa51b06c46 Merge pull request #3205 from node-red/dev
Node-RED 2.1.0
2021-10-21 09:13:09 +01:00
Nick O'Leary
7560bb8d7b Bump for 2.1.0 2021-10-21 09:08:35 +01:00
Nick O'Leary
fc9d65abcc Merge pull request #3204 from node-red/tcp-req-text-output
Add string option to TCP request node output
2021-10-20 09:40:44 +01:00
Dave Conway-Jones
a7413cccd0 reuse existing labels for tcp request buffer/string option 2021-10-20 09:36:08 +01:00
Nick O'Leary
7610353f07 Position popover properly on a scrolled page
Not needed in the core editor, but needed in the docs pages that can scroll
2021-10-19 22:22:53 +01:00
Dave Conway-Jones
d3f978c90c Add optional string type output to tcp request node
to be similar to tcp in. node
2021-10-19 21:34:23 +01:00
Nick O'Leary
8d79deffb5 Merge pull request #3202 from node-red/tour-guide-fix
Fixes from 2.1.0-beta.2
2021-10-19 10:20:24 +01:00
Nick O'Leary
8158487c3e Reduce churn in setting Switch rule typedInput type 2021-10-19 10:12:13 +01:00
Nick O'Leary
0cc061196d Handle changing value before type without reseting TypedInput 2021-10-19 10:11:37 +01:00
Nick O'Leary
d0ec055222 Fix Inject/Change node restoring typedInput options 2021-10-18 21:23:42 +01:00
Nick O'Leary
ae12ddd32b Change node: Fix deepCopy checkbox spacing on Safari 2021-10-18 20:38:46 +01:00
Nick O'Leary
31da3adaa9 Fix hide/show of palette in tour and add MQTT nodes 2021-10-18 20:29:37 +01:00
Nick O'Leary
9fd5213f13 Merge pull request #3201 from node-red/link-fixes
Fix saving link out node links
2021-10-18 09:43:30 +01:00
Nick O'Leary
de882f5849 Fix saving link out node links 2021-10-18 09:32:00 +01:00
Nick O'Leary
fded1e0021 Refix #3170 - copy switch rule type when adding new rule 2021-10-14 21:47:49 +01:00
52 changed files with 507 additions and 337 deletions

View File

@@ -1,3 +1,57 @@
#### 2.1.3: Maintenance Release
Runtime
- Update gen-publish script to update 'next' tag for main releases
- Add environment variable to enable/disable tours (#3221) @hardillb
- Fix loading non-default language files leaving runtime in wrong locale (#3225) @knolleary
Editor
- Refresh editor settings whenever a node is added or enabled (#3227) @knolleary
- Revert spinner css change that made it shrink in some cases (#3229) @knolleary
- Fix import notification message when importing config nodes (#3224) @knolleary
- Handle changing types of TypedInput repeatedly (#3223) @knolleary
#### 2.1.2: Maintenance Release
Runtime
- node-red-pi: Remove bash dependency (#3216) @a16bitsysop
Editor
- Improved regex for markdown renderer (#3213) @GerwinvBeek
- Fix TypedInput initialisation (#3220) @knolleary
Nodes
- MQTT: fix datatype in node config not used. fixes #3215 (#3219) @Steve-Mcl
#### 2.1.1: Maintenance Release
Editor
- Ensure tourGuide popover doesn't fall offscreen (#3212) @knolleary
- Fix issue with old inject nodes that migrated topic to 'string' type (#3210) @knolleary
- Add cache-busting query params to index.mst (#3211) @knolleary
- Fix TypedInput validation of type without options (#3207) @knolleary
#### 2.1.0: Milestone Release
Editor
- Position popover properly on a scrolled page
- Fixes from 2.1.0-beta.2 (#3202) @knolleary
Nodes
- Link Out: Fix saving link out node links (#3201) @knolleary
- Switch: Refix #3170 - copy switch rule type when adding new rule
- TCP Request: Add string option to TCP request node output (#3204) @dceejay
#### 2.1.0-beta.2: Beta Release
Editor
@@ -26,8 +80,6 @@ Nodes
- Inject: Widen Inject interval box for >1 digit (#3184) @knolleary
- Switch: Fix rule focus when switch 'otherwise' rule is used (#3185) @knolleary
#### 2.1.0-beta.1: Beta Release
Editor

View File

@@ -583,7 +583,7 @@ module.exports = function(grunt) {
grunt.registerMultiTask('attachCopyright', function() {
var files = this.data.src;
var copyright = "/**\n"+
" * Copyright JS Foundation and other contributors, http://js.foundation\n"+
" * Copyright OpenJS Foundation and other contributors, https://openjsf.org/\n"+
" *\n"+
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+
" * you may not use this file except in compliance with the License.\n"+

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "2.1.0-beta.2",
"version": "2.1.3",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",

View File

@@ -48,9 +48,10 @@ module.exports = {
var prevLang = i18n.i.language;
// Trigger a load from disk of the language if it is not the default
i18n.i.changeLanguage(lang, function(){
var catalog = loadResource(lang, namespace);
res.json(catalog||{});
i18n.i.changeLanguage(prevLang, function() {
var catalog = loadResource(lang, namespace);
res.json(catalog||{});
});
});
i18n.i.changeLanguage(prevLang);
}
}

View File

@@ -27,7 +27,8 @@ var defaultContext = {
tabicon: {
icon: "red/images/node-red-icon-black.svg",
colour: "#8f0000"
}
},
version: require(path.join(__dirname,"../../package.json")).version
},
header: {
title: "Node-RED",
@@ -227,6 +228,11 @@ module.exports = {
if (theme.theme) {
themeSettings.theme = theme.theme;
}
if (theme.hasOwnProperty("tours")) {
themeSettings.tours = theme.tours;
}
return themeApp;
},
context: async function() {

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "2.1.0-beta.2",
"version": "2.1.3",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/util": "2.1.0-beta.2",
"@node-red/editor-client": "2.1.0-beta.2",
"@node-red/util": "2.1.3",
"@node-red/editor-client": "2.1.3",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"clone": "2.1.2",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "2.1.0-beta.2",
"version": "2.1.3",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -475,31 +475,33 @@ var RED = (function() {
var typeList;
var info;
if (topic == "notification/node/added") {
var addedTypes = [];
msg.forEach(function(m) {
var id = m.id;
RED.nodes.addNodeSet(m);
addedTypes = addedTypes.concat(m.types);
RED.i18n.loadNodeCatalog(id, function() {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'nodes/'+id,
success: function(data) {
appendNodeConfig(data);
}
RED.settings.refreshSettings(function(err, data) {
var addedTypes = [];
msg.forEach(function(m) {
var id = m.id;
RED.nodes.addNodeSet(m);
addedTypes = addedTypes.concat(m.types);
RED.i18n.loadNodeCatalog(id, function() {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'nodes/'+id,
success: function(data) {
appendNodeConfig(data);
}
});
});
});
});
if (addedTypes.length) {
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
}
loadIconList();
if (addedTypes.length) {
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
}
loadIconList();
})
} else if (topic == "notification/node/removed") {
for (i=0;i<msg.length;i++) {
m = msg[i];
@@ -512,27 +514,29 @@ var RED = (function() {
loadIconList();
} else if (topic == "notification/node/enabled") {
if (msg.types) {
info = RED.nodes.getNodeSet(msg.id);
if (info.added) {
RED.nodes.enableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'nodes/'+msg.id,
success: function(data) {
appendNodeConfig(data);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
}
});
}
RED.settings.refreshSettings(function(err, data) {
info = RED.nodes.getNodeSet(msg.id);
if (info.added) {
RED.nodes.enableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'nodes/'+msg.id,
success: function(data) {
appendNodeConfig(data);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
}
});
}
});
}
} else if (topic == "notification/node/disabled") {
if (msg.types) {

View File

@@ -125,7 +125,7 @@ RED.settings = (function () {
load(done);
}
var load = function(done) {
var refreshSettings = function(done) {
$.ajax({
headers: {
"Accept": "application/json"
@@ -135,6 +135,23 @@ RED.settings = (function () {
url: 'settings',
success: function (data) {
setProperties(data);
done(null, data);
},
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status === 401) {
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
window.location.search = "";
}
RED.user.login(function() { refreshSettings(done); });
} else {
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
}
}
});
}
var load = function(done) {
refreshSettings(function(err, data) {
if (!err) {
if (!RED.settings.user || RED.settings.user.anonymous) {
RED.settings.remove("auth-tokens");
}
@@ -147,18 +164,8 @@ RED.settings = (function () {
console.log("D3",d3.version);
console.groupEnd();
loadUserSettings(done);
},
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status === 401) {
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
window.location.search = "";
}
RED.user.login(function() { load(done); });
} else {
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
}
}
});
})
};
function loadUserSettings(done) {
@@ -234,6 +241,7 @@ RED.settings = (function () {
init: init,
load: load,
loadUserSettings: loadUserSettings,
refreshSettings: refreshSettings,
set: set,
get: get,
remove: remove,

View File

@@ -603,7 +603,7 @@ RED.popover = (function() {
var panelWidth = panel.width();
var top = (targetHeight+pos.top) + offset[1];
if (top+panelHeight > $(window).height()) {
if (top+panelHeight-$(document).scrollTop() > $(window).height()) {
top -= (top+panelHeight)-$(window).height() + 5;
}
if (top < 0) {

View File

@@ -118,6 +118,9 @@
switch(evt.keyCode) {
case 32: // SPACE
case 13: // ENTER
if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) {
return
}
evt.preventDefault();
evt.stopPropagation();
if (focussed.checkbox) {
@@ -337,7 +340,7 @@
if (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.hasClass("red-ui-treeList-gutter-float"))?child.gutter.width()+2:0)+(child.depth*20));
child.treeList.labelPadding.width(labelPaddingWidth+'px');
if (child.element) {
$(child.element).css({
@@ -559,8 +562,9 @@
}).appendTo(label)
}
// var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20);
var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (depth * 20)
var labelPaddingWidth = ((item.gutter&&!item.gutter.hasClass("red-ui-treeList-gutter-float"))?item.gutter.width()+2:0)+(depth*20);
item.treeList.labelPadding = $('<span>').css({
display: "inline-block",
"flex-shrink": 0,

View File

@@ -345,6 +345,47 @@
}
}
};
// For a type with options, check value is a valid selection
// If !opt.multiple, returns the valid option object
// if opt.multiple, returns an array of valid option objects
// If not valid, returns null;
function isOptionValueValid(opt, currentVal) {
if (!opt.multiple) {
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
if (typeof op === "string" && op === currentVal) {
return {value:currentVal}
} else if (op.value === currentVal) {
return op;
}
}
} else {
// Check to see if value is a valid csv of
// options.
var currentValues = {};
var selected = [];
currentVal.split(",").forEach(function(v) {
if (v) {
currentValues[v] = true;
}
});
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
var val = typeof op === "string" ? op : op.value;
if (currentValues.hasOwnProperty(val)) {
delete currentValues[val];
selected.push(typeof op === "string" ? {value:op} : op.value)
}
}
if (!$.isEmptyObject(currentValues)) {
return null;
}
return selected
}
}
var nlsd = false;
$.widget( "nodered.typedInput", {
@@ -378,7 +419,8 @@
}
nlsd = true;
var that = this;
this.identifier = this.element.attr('id') || "TypedInput-"+Math.floor(Math.random()*100);
if (this.options.debug) { console.log(this.identifier,"Create",{defaultType:this.options.default, value:this.element.val()}) }
this.disarmClick = false;
this.input = $('<input class="red-ui-typedInput-input" type="text"></input>');
this.input.insertAfter(this.element);
@@ -408,6 +450,8 @@
});
this.defaultInputType = this.input.attr('type');
// Used to remember selections per-type to restore them when switching between types
this.oldValues = {};
this.uiSelect.addClass("red-ui-typedInput-container");
@@ -490,9 +534,9 @@
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
RED.popover.tooltip(this.optionSelectLabel,function() {
return that.optionValue;
});
// RED.popover.tooltip(this.optionSelectLabel,function() {
// return that.optionValue;
// });
this.optionSelectTrigger.on("click", function(event) {
event.preventDefault();
event.stopPropagation();
@@ -512,10 +556,8 @@
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton);
// Used to remember selections per-type to restore them when switching between types
this.oldValues = {};
this.type(this.options.default||this.typeList[0].value);
this.typeChanged = !!this.options.default;
}catch(err) {
console.log(err.stack);
}
@@ -806,7 +848,10 @@
},
value: function(value) {
var that = this;
var opt = this.typeMap[this.propertyType];
// If the default type has been set to an invalid type, then on first
// creation, the current propertyType will not exist. Default to an
// empty object on the assumption the corrent type will be set shortly
var opt = this.typeMap[this.propertyType] || {};
if (!arguments.length) {
var v = this.input.val();
if (opt.export) {
@@ -814,27 +859,38 @@
}
return v;
} else {
if (this.options.debug) { console.log(this.identifier,"----- SET VALUE ------",value) }
var selectedOption = [];
var valueToCheck = value;
if (opt.options) {
var checkValues = [value];
if (opt.hasValue && opt.parse) {
var parts = opt.parse(value);
if (this.options.debug) { console.log(this.identifier,"new parse",parts) }
value = parts.value;
valueToCheck = parts.option || parts.value;
}
var checkValues = [valueToCheck];
if (opt.multiple) {
selectedOption = [];
checkValues = value.split(",");
checkValues = valueToCheck.split(",");
}
checkValues.forEach(function(value) {
checkValues.forEach(function(valueToCheck) {
for (var i=0;i<opt.options.length;i++) {
var op = opt.options[i];
if (typeof op === "string") {
if (op === value || op === ""+value) {
if (op === valueToCheck || op === ""+valueToCheck) {
selectedOption.push(that.activeOptions[op]);
break;
}
} else if (op.value === value) {
} else if (op.value === valueToCheck) {
selectedOption.push(op);
break;
}
}
})
if (this.options.debug) { console.log(this.identifier,"set value to",value) }
this.input.val(value);
if (!opt.multiple) {
if (selectedOption.length === 0) {
@@ -859,23 +915,56 @@
return this.propertyType;
} else {
var that = this;
if (this.options.debug) { console.log(this.identifier,"----- SET TYPE -----",type) }
var previousValue = null;
var opt = this.typeMap[type];
if (opt && this.propertyType !== type) {
// If previousType is !null, then this is a change of the type, rather than the initialisation
var previousType = this.typeMap[this.propertyType];
var typeChanged = !!previousType;
previousValue = this.input.val();
if (typeChanged) {
if (previousType && this.typeChanged) {
if (this.options.debug) { console.log(this.identifier,"typeChanged",{previousType,previousValue}) }
if (previousType.options && opt.hasValue !== true) {
this.oldValues[previousType.value] = this.input.val();
this.oldValues[previousType.value] = previousValue;
} else if (previousType.hasValue === false) {
this.oldValues[previousType.value] = this.input.val();
this.oldValues[previousType.value] = previousValue;
} else {
this.oldValues["_"] = this.input.val();
this.oldValues["_"] = previousValue;
}
if ((opt.options && opt.hasValue !== true) || opt.hasValue === false) {
this.input.val(this.oldValues.hasOwnProperty(opt.value)?this.oldValues[opt.value]:(opt.default||[]).join(","))
if (this.oldValues.hasOwnProperty(opt.value)) {
if (this.options.debug) { console.log(this.identifier,"restored previous (1)",this.oldValues[opt.value]) }
this.input.val(this.oldValues[opt.value]);
} else if (opt.options) {
// No old value for the option type.
// It is possible code has called 'value' then 'type'
// to set the selected option. This is what the Inject/Switch/Change
// nodes did before 2.1.
// So we need to be careful to not reset the value if it is a valid option.
var validOptions = isOptionValueValid(opt,previousValue);
if (this.options.debug) { console.log(this.identifier,{previousValue,opt,validOptions}) }
if ((previousValue || previousValue === '') && validOptions) {
if (this.options.debug) { console.log(this.identifier,"restored previous (2)") }
this.input.val(previousValue);
} else {
if (typeof opt.default === "string") {
if (this.options.debug) { console.log(this.identifier,"restored previous (3)",opt.default) }
this.input.val(opt.default);
} else if (Array.isArray(opt.default)) {
if (this.options.debug) { console.log(this.identifier,"restored previous (4)",opt.default.join(",")) }
this.input.val(opt.default.join(","))
} else {
if (this.options.debug) { console.log(this.identifier,"restored previous (5)") }
this.input.val("");
}
}
} else {
if (this.options.debug) { console.log(this.identifier,"restored default/blank",opt.default||"") }
this.input.val(opt.default||"")
}
} else {
if (this.options.debug) { console.log(this.identifier,"restored old/default/blank") }
this.input.val(this.oldValues.hasOwnProperty("_")?this.oldValues["_"]:(opt.default||""))
}
if (previousType.autoComplete) {
@@ -883,6 +972,7 @@
}
}
this.propertyType = type;
this.typeChanged = true;
if (this.typeField) {
this.typeField.val(type);
}
@@ -951,22 +1041,12 @@
var op;
if (!opt.hasValue) {
var validValue = false;
var currentVal = this.input.val();
// Check the value is valid for the available options
var validValues = isOptionValueValid(opt,this.input.val());
if (!opt.multiple) {
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
if (typeof op === "string" && op === currentVal) {
that._updateOptionSelectLabel({value:currentVal});
validValue = true;
break;
} else if (op.value === currentVal) {
that._updateOptionSelectLabel(op);
validValue = true;
break;
}
}
if (!validValue) {
if (validValues) {
that._updateOptionSelectLabel(validValues)
} else {
op = opt.options[0];
if (typeof op === "string") {
this.value(op);
@@ -977,31 +1057,19 @@
}
}
} else {
// Check to see if value is a valid csv of
// options.
var currentValues = {};
var selected = [];
currentVal.split(",").forEach(function(v) {
if (v) {
selected.push(v);
currentValues[v] = true;
}
});
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
delete currentValues[op.value||op];
if (!validValues) {
validValues = (opt.default || []).map(function(v) {
return typeof v === "string"?v:v.value
});
this.value(validValues.join(","));
}
if (!$.isEmptyObject(currentValues)) {
selected = opt.default || [];
// Invalid, set to default/empty
this.value(selected.join(","));
}
that._updateOptionSelectLabel(selected);
that._updateOptionSelectLabel(validValues);
}
} else {
var selectedOption = this.optionValue||opt.options[0];
if (opt.parse) {
var parts = opt.parse(this.input.val(),selectedOption);
var selectedOptionObj = typeof selectedOption === "string"?{value:selectedOption}:selectedOption
var parts = opt.parse(this.input.val(),selectedOptionObj);
if (parts.option) {
selectedOption = parts.option;
if (!this.activeOptions.hasOwnProperty(selectedOption)) {
@@ -1025,6 +1093,7 @@
this._updateOptionSelectLabel(this.activeOptions[selectedOption]);
}
} else if (selectedOption) {
if (this.options.debug) { console.log(this.identifier,"HERE",{optionValue:selectedOption.value}) }
this.optionValue = selectedOption.value;
this._updateOptionSelectLabel(selectedOption);
} else {

View File

@@ -563,7 +563,7 @@ RED.sidebar.info.outliner = (function() {
}
}
function getGutter(n) {
var span = $("<span>",{class:"red-ui-info-outline-gutter"});
var span = $("<span>",{class:"red-ui-info-outline-gutter red-ui-treeList-gutter-float"});
var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();

View File

@@ -348,7 +348,12 @@ RED.tourGuide = (function() {
maxWidth: maxWidth+"px",
direction: direction,
})
setTimeout(function() {
var pos = popover.element.position()
if (pos.left < 0) {
popover.element.css({left: 0});
}
},100);
if (nextButton) {
setTimeout(function() {
nextButton.focus();

View File

@@ -27,7 +27,7 @@ RED.utils = (function() {
level: 'block', // Is this a block-level or inline-level tokenizer?
start(src) {
if (!src) { return null; }
let m = src.match(/:[^:\n]/);
let m = src.match(/:[^:\n]/g);
return m && m.index; // Hint to Marked.js to stop and check for a match
},
tokenizer(src, tokens) {
@@ -53,7 +53,7 @@ RED.utils = (function() {
level: 'inline', // Is this a block-level or inline-level tokenizer?
start(src) {
if (!src) { return null; }
let m = src.match(/:/);
let m = src.match(/:/g);
return m && m.index; // Hint to Marked.js to stop and check for a match
},
tokenizer(src, tokens) {

View File

@@ -4957,7 +4957,7 @@ RED.view = (function() {
counts.push(RED._("clipboard.group",{count:newGroupCount}));
}
if (newConfigNodeCount > 0) {
counts.push(RED._("clipboard.configNode",{count:newNodeCount}));
counts.push(RED._("clipboard.configNode",{count:newConfigNodeCount}));
}
if (new_subflows.length > 0) {
counts.push(RED._("clipboard.subflow",{count:new_subflows.length}));

View File

@@ -137,10 +137,10 @@
padding: 0;
border: 1px solid $form-input-border-color;
}
.ui-spinner input[type=text] {
.ui-spinner input {
background: $form-input-background;
margin: 0 17px 0 0;
padding: 8px;
padding: 6px;
border: none;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;

View File

@@ -93,6 +93,8 @@ export default {
{
title: {"en-US":"Link Call node added"},
prepare(done) {
this.paletteWasClosed = $("#red-ui-main-container").hasClass("red-ui-palette-closed");
RED.actions.invoke("core:toggle-palette",true)
$('[data-palette-type="link call"]')[0].scrollIntoView({block:"center"})
setTimeout(done,100);
},
@@ -100,13 +102,27 @@ export default {
direction: "right",
description: { "en-US": '<p>The <code>Link Call</code> node lets you call another flow that begins with a <code>Link In</code> node and get the result back when the message reaches a <code>Link Out</code> node.</p>' },
},
{
title: {"en-US":"MQTT nodes support dynamic connections"},
prepare(done) {
$('[data-palette-type="mqtt out"]')[0].scrollIntoView({block:"center"})
setTimeout(done,100);
},
element: '[data-palette-type="mqtt out"]',
direction: "right",
description: { "en-US": '<p>The <code>MQTT</code> nodes now support creating their connections and subscriptions dynamically.</p>' },
},
{
title: {"en-US":"File nodes renamed"},
prepare(done) {
$('[data-palette-type="file"]')[0].scrollIntoView({block:"center"})
setTimeout(done,100);
},
complete() {
if (this.paletteWasClosed) {
RED.actions.invoke("core:toggle-palette",false)
}
},
element: '[data-palette-type="file"]',
direction: "right",
description: { "en-US": '<p>The file nodes have been renamed to make it clearer which node does what.</p>' },

View File

@@ -7,7 +7,7 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -24,24 +24,24 @@
<title>{{ page.title }}</title>
<link rel="icon" type="image/png" href="{{ page.favicon }}">
<link rel="mask-icon" href="{{ page.tabicon.icon }}" color="{{ page.tabicon.colour }}">
<link rel="stylesheet" href="vendor/jquery/css/base/jquery-ui.min.css">
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="red/style.min.css">
<link rel="stylesheet" href="vendor/jquery/css/base/jquery-ui.min.css?v={{ page.version }}">
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css?v={{ page.version }}">
<link rel="stylesheet" href="red/style.min.css?v={{ page.version }}">
{{#page.css}}
<link rel="stylesheet" href="{{.}}">
{{/page.css}}
{{#asset.vendorMonaco}}
<link rel="stylesheet" href="vendor/monaco/style.css">
<link rel="stylesheet" href="vendor/monaco/style.css?v={{ page.version }}">
{{/asset.vendorMonaco}}
</head>
<body spellcheck="false">
<div id="red-ui-editor"></div>
<script src="vendor/vendor.js"></script>
<script src="vendor/vendor.js?v={{ page.version }}"></script>
{{#asset.vendorMonaco}}
<script src="{{ asset.vendorMonaco }}"></script>
<script src="{{ asset.vendorMonaco }}?v={{ page.version }}"></script>
{{/asset.vendorMonaco}}
<script src="{{ asset.red }}"></script>
<script src="{{ asset.main }}"></script>
<script src="{{ asset.red }}?v={{ page.version }}"></script>
<script src="{{ asset.main }}?v={{ page.version }}"></script>
{{# page.scripts }}
<script src="{{.}}"></script>
{{/ page.scripts }}

View File

@@ -353,14 +353,16 @@
},
oneditprepare: function() {
var node = this;
var payloadType = node.payloadType;
if (node.payloadType == null) {
if (node.payload == "") {
node.payloadType = "date";
payloadType = "date";
} else {
node.payloadType = "str";
payloadType = "str";
}
} else if (node.payloadType === 'string' || node.payloadType === 'none') {
node.payloadType = "str";
payloadType = "str";
}
$("#inject-time-type-select").on("change", function() {
@@ -539,12 +541,10 @@
var propertyValue = $('<input/>',{class:"node-input-prop-property-value",type:"text"})
.css("width","calc(70% - 30px)")
.appendTo(row)
.typedInput({default:'str',types:['flow','global','str','num','bool','json','bin','date','jsonata','env','msg']});
.typedInput({default:prop.vt || 'str',types:['flow','global','str','num','bool','json','bin','date','jsonata','env','msg']});
propertyName.typedInput('value',prop.p);
propertyValue.typedInput('value',prop.v);
propertyValue.typedInput('type',prop.vt);
},
removable: true,
sortable: true
@@ -559,12 +559,12 @@
var payload = {
p:'payload',
v: node.payload ? node.payload : '',
vt:node.payloadType ? node.payloadType : 'date'
vt:payloadType ? payloadType : 'date'
};
var topic = {
p:'topic',
v: node.topic ? node.topic : '',
vt:'string'
vt:'str'
}
node.props = [payload,topic];
}
@@ -575,11 +575,16 @@
if (newProp.v === undefined) {
if (prop.p === 'payload') {
newProp.v = node.payload ? node.payload : '';
newProp.vt = node.payloadType ? node.payloadType : 'date';
newProp.vt = payloadType ? payloadType : 'date';
} else if (prop.p === 'topic' && prop.vt === "str") {
newProp.v = node.topic ? node.topic : '';
}
}
if (newProp.vt === "string") {
// Fix bug in pre 2.1 where an old Inject node might have
// a migrated rule with type 'string' not 'str'
newProp.vt = "str";
}
eList.editableList('addItem',newProp);
}

View File

@@ -52,7 +52,7 @@
treeList = $("<div>")
.css({width: "100%", height: "100%"})
.appendTo(".node-input-link-row")
.treeList({})
.treeList({autoSelect:false})
.on('treelistitemmouseover',function(e,item) {
if (item.node) {
item.node.highlighted = true;
@@ -157,7 +157,7 @@
function onEditSave(node) {
var flows = treeList.treeList('data');
node.links = [];
if (node.type !== "link out" || $("node-input-mode").val() === 'link') {
if (node.type !== "link out" || $("#node-input-mode").val() === 'link') {
flows.forEach(function(f) {
f.children.forEach(function(n) {
if (n.selected) {

View File

@@ -117,30 +117,35 @@
return r;
}
function createValueField(row){
return $('<input/>',{class:"node-input-rule-value",type:"text",style:"width: 100%;"}).appendTo(row).typedInput({default:'str',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
function createValueField(row, defaultType){
return $('<input/>',{class:"node-input-rule-value",type:"text",style:"width: 100%;"}).appendTo(row)
.typedInput({default:defaultType||'str',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
}
function createNumValueField(row){
return $('<input/>',{class:"node-input-rule-num-value",type:"text",style:"width: 100%;"}).appendTo(row).typedInput({default:'num',types:['flow','global','num','jsonata','env']});
function createNumValueField(row, defaultType){
return $('<input/>',{class:"node-input-rule-num-value",type:"text",style:"width: 100%;"}).appendTo(row)
.typedInput({default:defaultType||'num',types:['flow','global','num','jsonata','env']});
}
function createExpValueField(row){
return $('<input/>',{class:"node-input-rule-exp-value",type:"text",style:"width: 100%;"}).appendTo(row).typedInput({default:'jsonata',types:['jsonata']});
return $('<input/>',{class:"node-input-rule-exp-value",type:"text",style:"width: 100%;"}).appendTo(row)
.typedInput({default:'jsonata',types:['jsonata']});
}
function createBtwnValueField(row){
return $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"width: 100%;"}).appendTo(row).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
function createBtwnValueField(row, defaultType){
return $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"width: 100%;"}).appendTo(row)
.typedInput({default:defaultType||'num',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
}
function createBtwnValue2Field(row3, andLabel){
function createBtwnValue2Field(row3, andLabel, defaultType){
$('<div/>',{class:"node-input-rule-btwn-label", style:"width: 120px; text-align: right;"}).text(" "+andLabel+" ").appendTo(row3);
var row3InputCell = $('<div/>',{style:"flex-grow:1; margin-left: 5px;"}).appendTo(row3);
return $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"width: 100%"}).appendTo(row3InputCell).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
return $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"width: 100%"}).appendTo(row3InputCell)
.typedInput({default:defaultType||'num',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
}
function createTypeValueField(){
return $('<input/>',{class:"node-input-rule-type-value",type:"text",style:"width: 100%;"}).appendTo(row).typedInput({default:'string',types:[
function createTypeValueField(row, defaultType){
return $('<input/>',{class:"node-input-rule-type-value",type:"text",style:"width: 100%;"}).appendTo(row).typedInput({default:defaultType || 'string',types:[
{value:"string",label:RED._("common.type.string"),hasValue:false,icon:"red/images/typedInput/az.png"},
{value:"number",label:RED._("common.type.number"),hasValue:false,icon:"red/images/typedInput/09.png"},
{value:"boolean",label:RED._("common.type.boolean"),hasValue:false,icon:"red/images/typedInput/bool.png"},
@@ -211,6 +216,7 @@
var lastRule = $("#node-input-rule-container").editableList('getItemAt',i-1);
var exportedRule = exportRule(lastRule.element);
opt.r.vt = exportedRule.vt;
opt.r.v = "";
// We could copy the value over as well and preselect it (see the 'activeElement' code below)
// But not sure that feels right. Is copying over the last value 'expected' behaviour?
// It would make sense for an explicit 'copy' action, but not sure where the copy button would
@@ -278,24 +284,12 @@
selectField.on("change", function() {
var fieldToFocus;
var type = selectField.val();
if (valueField){
valueField.typedInput('hide');
}
if (expValueField){
expValueField.typedInput('hide');
}
if (numValueField){
numValueField.typedInput('hide');
}
if (typeValueField){
typeValueField.typedInput('hide');
}
if (btwnValueField){
btwnValueField.typedInput('hide');
}
if (btwnValue2Field){
btwnValue2Field.typedInput('hide');
}
if (valueField) { valueField.typedInput('hide'); }
if (expValueField) { expValueField.typedInput('hide'); }
if (numValueField) { numValueField.typedInput('hide'); }
if (typeValueField) { typeValueField.typedInput('hide'); }
if (btwnValueField) { btwnValueField.typedInput('hide'); }
if (btwnValue2Field) { btwnValue2Field.typedInput('hide'); }
if ((type === "btwn") || (type === "index")) {
if (!btwnValueField){
@@ -318,7 +312,7 @@
} else if (type === "istype") {
if (!typeValueField){
typeValueField = createTypeValueField();
typeValueField = createTypeValueField(rowInputCell);
}
typeValueField.typedInput('show');
fieldToFocus = typeValueField;
@@ -361,48 +355,26 @@
// }
});
selectField.val(rule.t);
if ((rule.t == "btwn") || (rule.t == "index")) {
if (!btwnValueField){
btwnValueField = createBtwnValueField(rowInputCell);
}
btwnValueField.typedInput('value',rule.v);
btwnValueField.typedInput('type',rule.vt||'num');
if (!btwnValue2Field){
btwnValue2Field = createBtwnValue2Field(row3, andLabel);
}
if ((rule.t == "btwn") || (rule.t == "index")) {
btwnValueField = createBtwnValueField(rowInputCell,rule.vt||'num');
btwnValueField.typedInput('value',rule.v);
btwnValue2Field = createBtwnValue2Field(row3, andLabel,rule.v2t||'num');
btwnValue2Field.typedInput('value',rule.v2);
btwnValue2Field.typedInput('type',rule.v2t||'num');
} else if ((rule.t === "head") || (rule.t === "tail")) {
if (!numValueField){
numValueField = createNumValueField(row);
}
numValueField = createNumValueField(rowInputCell,rule.vt||'num');
numValueField.typedInput('value',rule.v);
numValueField.typedInput('type',rule.vt||'num');
} else if (rule.t === "istype") {
if (!typeValueField){
typeValueField =createTypeValueField();
}
typeValueField = createTypeValueField(rowInputCell,rule.vt);
typeValueField.typedInput('value',rule.vt);
typeValueField.typedInput('type',rule.vt);
} else if (rule.t === "jsonata_exp") {
if (!expValueField){
expValueField = createExpValueField(row);
}
expValueField = createExpValueField(rowInputCell,rule.vt||'jsonata');
expValueField.typedInput('value',rule.v);
expValueField.typedInput('type',rule.vt||'jsonata');
} else if (typeof rule.v != "undefined") {
if (!valueField){
valueField = createValueField(rowInputCell);
}
valueField = createValueField(rowInputCell,rule.vt||'str');
valueField.typedInput('value',rule.v);
valueField.typedInput('type',rule.vt||'str');
}
if (rule.case) {
caseSensitive.prop('checked',true);
} else {
caseSensitive.prop('checked',false);
}
caseSensitive.prop('checked',!!rule.case);
selectField.change();
var currentOutputs = JSON.parse(outputCount.val()||"{}");

View File

@@ -115,12 +115,12 @@
var regex = this._("change.label.regex");
var deepCopyLabel = this._("change.label.deepCopy");
function createPropertyValue(row2_1,row2_2) {
function createPropertyValue(row2_1, row2_2, defaultType) {
var propValInput = $('<input/>',{class:"node-input-rule-property-value",type:"text"})
.appendTo(row2_1)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
.typedInput({default:defaultType||'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
var dcLabel = $('<label style="padding-left: 130px; display: flex; align-items: center "></label>').appendTo(row2_2);
var dcLabel = $('<label style="padding-left: 130px;"></label>').appendTo(row2_2);
var deepCopy = $('<input type="checkbox" class="node-input-rule-property-deepCopy" style="width: auto; margin: 0 6px 0 0">').appendTo(dcLabel)
$('<span>').text(deepCopyLabel).appendTo(dcLabel)
@@ -129,20 +129,20 @@
})
return [propValInput, deepCopy];
}
function createFromValue(row3_1) {
function createFromValue(row3_1, defaultType) {
return $('<input/>',{class:"node-input-rule-property-search-value",type:"text"})
.appendTo(row3_1)
.typedInput({default:'str',types:['msg','flow','global','str','re','num','bool','env']});
.typedInput({default:defaultType||'str',types:['msg','flow','global','str','re','num','bool','env']});
}
function createToValue(row3_2) {
function createToValue(row3_2, defaultType) {
return $('<input/>',{class:"node-input-rule-property-replace-value",type:"text"})
.appendTo(row3_2)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','env']});
.typedInput({default:defaultType||'str',types:['msg','flow','global','str','num','bool','json','bin','env']});
}
function createMoveValue(row4) {
function createMoveValue(row4, defaultType) {
return $('<input/>',{class:"node-input-rule-property-move-value",type:"text"})
.appendTo(row4)
.typedInput({default:'msg',types:['msg','flow','global']});
.typedInput({default:defaultType||'msg',types:['msg','flow','global']});
}
$('#node-input-rule-container').css('min-height','150px').css('min-width','450px').editableList({
@@ -268,33 +268,22 @@
propertyName.typedInput('value',rule.p);
propertyName.typedInput('type',rule.pt);
if (rule.t == "set") {
if(!propertyValue) {
var parts = createPropertyValue(row2_1, row2_2);
propertyValue = parts[0];
deepCopy = parts[1];
}
var parts = createPropertyValue(row2_1, row2_2, rule.tot);
propertyValue = parts[0];
deepCopy = parts[1];
propertyValue.typedInput('value',rule.to);
propertyValue.typedInput('type',rule.tot);
deepCopy.prop("checked", !!rule.dc);
}
if (rule.t == "move") {
if(!moveValue) {
moveValue = createMoveValue(row4);
}
moveValue = createMoveValue(row4,rule.tot);
moveValue.typedInput('value',rule.to);
moveValue.typedInput('type',rule.tot);
}
if (rule.t == "change") {
if(!fromValue) {
fromValue = createFromValue(row3_1);
}
fromValue = createFromValue(row3_1, rule.fromt);
fromValue.typedInput('value',rule.from);
fromValue.typedInput('type',rule.fromt);
if (!toValue) {
toValue = createToValue(row3_2);
}
toValue = createToValue(row3_2,rule.tot);
toValue.typedInput('value',rule.to);
toValue.typedInput('type',rule.tot);
}
selectField.change();
container[0].appendChild(fragment);

View File

@@ -372,6 +372,7 @@ module.exports = function(RED) {
hit = false;
for (var b in node.buffer) { // check if already in queue
if (msg.topic === node.buffer[b].msg.topic) {
if (node.outputs === 2) { send([null,node.buffer[b].msg]) }
node.buffer[b].done();
node.buffer[b] = {msg, send, done}; // if so - replace existing entry
hit = true;

View File

@@ -1040,7 +1040,7 @@ module.exports = function(RED) {
//subscribe to sub.topic & hook up subscriptionHandler
node.brokerConn.subscribe(sub.topic, options, function (topic, payload, packet) {
subscriptionHandler(node, sub.datatype, topic, payload, packet);
subscriptionHandler(node, sub.datatype || node.datatype, topic, payload, packet);
}, node.id);
node.dynamicSubs[sub.topic] = sub; //save for later unsubscription & 'list' action
})

View File

@@ -298,18 +298,14 @@ in your Node-RED user directory (${RED.settings.userDir}).
}
if (Object.keys(this.credentials).length != 0) {
if (this.authType === "basic") {
// Workaround for https://github.com/sindresorhus/got/issues/1169
var cred = ""
if (this.credentials.user) {
// opts.username = this.credentials.user;
cred = this.credentials.user
}
if (this.credentials.password) {
// opts.password = this.credentials.password;
cred += ":" + this.credentials.password
// Workaround for https://github.com/sindresorhus/got/issues/1169 (fixed in got v12)
// var cred = ""
if (this.credentials.user || this.credentials.password) {
// cred = `${this.credentials.user}:${this.credentials.password}`;
opts.headers.Authorization = "Basic " + Buffer.from(`${this.credentials.user}:${this.credentials.password}`).toString("base64");
}
// build own basic auth header
opts.headers.Authorization = "Basic " + Buffer.from(cred).toString("base64");
// opts.headers.Authorization = "Basic " + Buffer.from(cred).toString("base64");
} else if (this.authType === "digest") {
let digestCreds = this.credentials;
let sentCreds = false;

View File

@@ -196,6 +196,13 @@
</div>
<div class="form-row">
<label for="node-input-out"><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.return"></span></label>
<select type="text" id="node-input-ret" style="width:54%;">
<option value="buffer" data-i18n="tcpin.output.buffer"></option>
<option value="string" data-i18n="tcpin.output.string"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-out"> </label>
<select type="text" id="node-input-out" style="width:54%;">
<option value="time" data-i18n="tcpin.return.timeout"></option>
<option value="char" data-i18n="tcpin.return.character"></option>
@@ -220,6 +227,7 @@
server: {value:""},
port: {value:"",validate:RED.validators.regex(/^(\d*|)$/)},
out: {value:"time",required:true},
ret: {value:"buffer"},
splitc: {value:"0",required:true},
name: {value:""}
},
@@ -234,6 +242,10 @@
},
oneditprepare: function() {
var previous = null;
if ($("#node-input-ret").val() == undefined) {
$("#node-input-ret").val("buffer");
this.ret = "buffer";
}
$("#node-input-out").on('focus', function () { previous = this.value; }).on("change", function() {
$("#node-input-splitc").show();
if (previous === null) { previous = $("#node-input-out").val(); }

View File

@@ -311,7 +311,7 @@ module.exports = function(RED) {
}
setupTcpClient();
node.on("input", function(msg,nodeSend,nodeDone) {
node.on("input", function(msg, nodeSend, nodeDone) {
if (node.connected && msg.payload != null) {
if (Buffer.isBuffer(msg.payload)) {
client.write(msg.payload);
@@ -444,6 +444,7 @@ module.exports = function(RED) {
this.server = n.server;
this.port = Number(n.port);
this.out = n.out;
this.ret = n.ret || "buffer";
this.splitc = n.splitc;
if (this.out === "immed") { this.splitc = -1; this.out = "time"; }
@@ -488,7 +489,7 @@ module.exports = function(RED) {
connected: false,
connecting: false
};
enqueue(clients[connection_id].msgQueue, {msg:msg,nodeSend:nodeSend, nodeDone: nodeDone});
enqueue(clients[connection_id].msgQueue, {msg:msg, nodeSend:nodeSend, nodeDone:nodeDone});
clients[connection_id].lastMsg = msg;
if (!clients[connection_id].connecting && !clients[connection_id].connected) {
@@ -532,8 +533,12 @@ module.exports = function(RED) {
if (node.out === "sit") { // if we are staying connected just send the buffer
if (clients[connection_id]) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = data;
nodeSend(RED.util.cloneMessage(msg));
msg.payload = RED.util.cloneMessage(data);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
nodeSend(msg);
}
}
// else if (node.splitc === 0) {
@@ -556,6 +561,10 @@ module.exports = function(RED) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i+1);
buf.copy(msg.payload,0,0,i+1);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});
@@ -578,6 +587,10 @@ module.exports = function(RED) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i);
buf.copy(msg.payload,0,0,i);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});
@@ -597,6 +610,10 @@ module.exports = function(RED) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i);
buf.copy(msg.payload,0,0,i);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});

View File

@@ -25,7 +25,7 @@
<dd>Optional nutzbare Nachrichten-Eigenschaft.</dd>
</dl>
<h3>Details</h3>
<p>Der <span style="background-color:Gainsboro">inject</span>-Node kann einen Flow mit einstellbaren Nutzdaten (Payload) starten.
<p>Der inject-Node kann einen Flow mit einstellbaren Nutzdaten (Payload) starten.
Der voreingestellte Payload ist die aktuelle Zeit als Zeitstempel in Millisekunden
seit Beginn der Unix-Zeitrechnung (1. Januar 1970 UTC).</p>
<p>Der Node unterstützt auch die Injektion von Zeichenfolgen, Zahlenwerten, Booleschen Werten,
@@ -34,7 +34,7 @@
Er kann auch in regelmäßigen Intervallen oder nach einem Zeitplan injizieren.</p>
<p>Er kann auch so eingestellt werden, dass er jedes Mal einen Wert injiziert, wenn der Flow gestartet wird.</p>
<p>Das maximal einstellbare Intervall beträgt etwa 596 Stunden bzw. 24 Tage.
Wenn jedoch Intervalle größer als 24h benötigt werden, sollte ein <span style="background-color:Gainsboro">scheduler</span>-Node verwendet werden,
Wenn jedoch Intervalle größer als 24h benötigt werden, sollte ein scheduler-Node verwendet werden,
der mit Stromausfällen und Neustarts besser umgehen kann.</p>
<p><b>Hinweis</b>: Die Optionen <i>"Intervall zwischen Uhrzeiten"</i> und <i>"Täglicher Zeitpunkt"</i>
verwenden das Standard-Cron-System.</p>

View File

@@ -23,10 +23,10 @@
<p>JavaScript-Objekte und -Arrays können nach Bedarf ein- und ausgeblendet werden.
Binäre Puffer-Objekte (buffer objects) können nach Möglichkeit als Rohdaten oder als Zeichenfolge (string) angezeigt werden.</p>
<p>Neben der eigentlichen Nachricht werden im Debug-Tab auch der Empfangszeitpunkt,
der empfangende <span style="background-color:Gainsboro">debug</span>-Node, sowie Name und Typ der Nachricht protokolliert.
Durch Klicken auf die Node-ID wird der entsprechende <span style="background-color:Gainsboro">debug</span>-Node im Arbeitsbereich angezeigt.</p>
<p>Die Schaltfläche des <span style="background-color:Gainsboro">debug</span>-Nodes kann verwendet werden, um die Debug-Ausgabe ein- und auszuschalten.
Es ist empfehlenswert, alle nicht verwendeten <span style="background-color:Gainsboro">debug</span>-Nodes zu deaktivieren oder gleich zu entfernen.</p>
<p>Der <span style="background-color:Gainsboro">debug</span>-Node kann auch so eingestellt werden, dass außerdem alle Nachrichten in der Systemkonsole ausgegeben und/oder
als kurze Statustexte (max. 32 Zeichen) unter dem <span style="background-color:Gainsboro">debug</span>-Node angezeigt werden.</p>
der empfangende debug-Node, sowie Name und Typ der Nachricht protokolliert.
Durch Klicken auf die Node-ID wird der entsprechende debug-Node im Arbeitsbereich angezeigt.</p>
<p>Die Schaltfläche des debug-Nodes kann verwendet werden, um die Debug-Ausgabe ein- und auszuschalten.
Es ist empfehlenswert, alle nicht verwendeten debug-Nodes zu deaktivieren oder gleich zu entfernen.</p>
<p>Der debug-Node kann auch so eingestellt werden, dass außerdem alle Nachrichten in der Systemkonsole ausgegeben und/oder
als kurze Statustexte (max. 32 Zeichen) unter dem debug-Node angezeigt werden.</p>
</script>

View File

@@ -18,11 +18,11 @@
<p>Anstoß eines weiteren Flows, wenn ein anderer Node seine Nachrichtenbearbeitung abgeschlossen hat.</p>
<h3>Details</h3>
<p>Wenn ein Node die Bearbeitung seiner Nachrichten abgeschlossen hat,
kann der <span style="background-color:Gainsboro">complete</span>-Node dazu benutzt werden, einen weiteren Flow anzustoßen.</p>
kann der complete-Node dazu benutzt werden, einen weiteren Flow anzustoßen.</p>
<p>Der Node kann z.B. mit einem anderen Node ohne Ausgang verknüpft werden
(z.B. E-Mail-Sende-Node), um den Flow fortzusetzen.</p>
<p>Im Node werden dazu die zu überwachenden Nodes des selben Flows ausgewählt.
Im Gegensatz zum <span style="background-color:Gainsboro">catch</span>-Node besteht hier jedoch nicht die Auswahlmöglichkeit aller Nodes des Flows.</p>
Im Gegensatz zum catch-Node besteht hier jedoch nicht die Auswahlmöglichkeit aller Nodes des Flows.</p>
<p>Nicht alle Nodes können diesen Node anstoßen.
Es hängt davon ab, ob die auslösenden Knoten diese Funktion unterstützen,
welche erst mit Node-RED 1.0 eingeführt wurde.</p>

View File

@@ -29,13 +29,13 @@
</dl>
<h3>Details</h3>
<p>Wenn ein Node bei der Verarbeitung einer Nachricht einen Fehler verursacht, wird der Flow in der Regel angehalten.
Der <span style="background-color:Gainsboro">catch</span>-Node kann verwendet werden, um diese Fehler abzufangen und sie mit einem dedizierten Flow zu bearbeiten.</p>
Der catch-Node kann verwendet werden, um diese Fehler abzufangen und sie mit einem dedizierten Flow zu bearbeiten.</p>
<p>Der Node fängt standardmäßig die Fehler aller Nodes im selben Flow ab.
Alternativ kann er auch an bestimmte Nodes gebunden werden.</p>
<p>Wenn ein Fehler ausgelöst wird, empfangen alle angebundenen <span style="background-color:Gainsboro">catch</span>-Nodes die Fehlermeldung.</p>
<p>Wenn ein Fehler in einem Subflow ausgelöst wird, wird der Fehler von einem <span style="background-color:Gainsboro">catch</span>-Node
<p>Wenn ein Fehler ausgelöst wird, empfangen alle angebundenen catch-Nodes die Fehlermeldung.</p>
<p>Wenn ein Fehler in einem Subflow ausgelöst wird, wird der Fehler von einem catch-Node
innerhalb des Subflows abgefangen.
Wenn im Subflow keine <span style="background-color:Gainsboro">catch</span>-Nodes vorhanden sind, wird die Fehlermeldung eine Ebene höher zum Flow weitergereicht,
Wenn im Subflow keine catch-Nodes vorhanden sind, wird die Fehlermeldung eine Ebene höher zum Flow weitergereicht,
in der sich die Subflow-Instanz befindet.</p>
<p>Wenn die Nachricht bereits über eine <code>error</code>-Eigenschaft verfügt, wird sie nach <code>_error</code> kopiert.</p>
</script>

View File

@@ -17,7 +17,7 @@
<script type="text/html" data-help-name="link in">
<p>Erstellung virtueller Verbindungen (Links) zwischen Flows.</p>
<h3>Details</h3>
<p>Der Node kann mit jedem beliebigen <span style="background-color:Gainsboro">link&nbsp;out</span>-Node in einen beliebigen Flow-Tab verlinkt werden.
<p>Der Node kann mit jedem beliebigen link&nbsp;out-Node in einen beliebigen Flow-Tab verlinkt werden.
Sobald sie verlinkt sind, verhalten sie sich so, als wären sie direkt miteinander verbunden.</p>
<p>Die Links zwischen Link-Nodes werden nur angezeigt, wenn ein Link-Node ausgewählt ist.
Wenn Links zu anderen Flow-Tabs vorhanden sind, werden virtuelle Link-Nodes als Gegenparts angezeigt,
@@ -28,7 +28,7 @@
<script type="text/html" data-help-name="link out">
<p>Erstellung virtueller Verbindungen (Links) zwischen Flows.</p>
<h3>Details</h3>
<p>Der Node kann mit jedem beliebigen <span style="background-color:Gainsboro">link&nbsp;in</span>-Node in einen beliebigen Flow-Tab verlinkt werden.
<p>Der Node kann mit jedem beliebigen link&nbsp;in-Node in einen beliebigen Flow-Tab verlinkt werden.
Sobald sie verlinkt sind, verhalten sie sich so, als wären sie direkt miteinander verbunden.</p>
<p>Die Links zwischen Link-Nodes werden nur angezeigt, wenn ein Link-Node ausgewählt ist.
Wenn Links zu anderen Flow-Tabs vorhanden sind, werden virtuelle Link-Nodes als Gegenparts angezeigt,

View File

@@ -47,7 +47,7 @@
<li><code>node.error("Fehlermeldungstext")</code></li>
</ul>
</p>
<p>Der <span style="background-color:Gainsboro">catch</span>-Node kann auch zur Bearbeitung von Fehlern verwendet werden.
<p>Der catch-Node kann auch zur Bearbeitung von Fehlern verwendet werden.
Er wird aufgerufen, indem <code>msg</code> als zweites Argument an <code>node.error</code> übergeben wird:</p>
<pre>node.error("Fehlermeldungstext" ,msg);</pre>
<h4><b>Zugriff auf Node-Informationen</b></h4>

View File

@@ -27,7 +27,7 @@
<ol>
<li><b>value rules</b>: Regeln werden hinsichtlich einer eingestellten Eigenschaft ausgewertet</li>
<li><b>sequence rules</b>: Regeln beziehen sich auf Nachrichtensequenzen,
wie sie beispielsweise durch den <span style="background-color:Gainsboro">split</span>-Node erzeugt werden</li>
wie sie beispielsweise durch den split-Node erzeugt werden</li>
<li>Ein <b>JSONata-Ausdruck</b> kann die gesamte Eingangsnachricht auswerten und einen <code>true</code>-Wert zurückliefern,
um eine Regelerfüllung zu signalisieren</li>
<li>Die <b>ansonsten</b>-Regel wird angewendet, wenn keine vorhergehende Regel übereinstimmt</li>

View File

@@ -25,9 +25,9 @@
<dt class="optional">payload <span class="property-type">string</span></dt>
<dd>Wird an auszuführenden Befehl angehängt, sofern im Node aktiviert.</dd>
<dt class="optional">kill <span class="property-type">string</span></dt>
<dd>Typ des Kill-Signals, das an den zu beendenden <span style="background-color:Gainsboro">exec</span>-Node-Prozess gesendet wird.</dd>
<dd>Typ des Kill-Signals, das an den zu beendenden exec-Node-Prozess gesendet wird.</dd>
<dt class="optional">pid <span class="property-type">number | string</span></dt>
<dd>Prozess-ID des zu beendenden <span style="background-color:Gainsboro">exec</span>-Node-Prozesses.</dd>
<dd>Prozess-ID des zu beendenden exec-Node-Prozesses.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<ol class="node-ports">
@@ -75,7 +75,7 @@
<p>Die zurückgegebenen Daten (Payload) sind in der Regel eine <i>Zeichenfolge (string)</i>,
außer es werden nicht UTF-8-Zeichen wie bei einem <i>binären Puffer (buffer)</i> erkannt.</p>
<p>Bei einem aktiven Node werden Status und die PID angezeigt.
Änderungen können mittels <span style="background-color:Gainsboro">status</span>-Node gelesen werden.</p>
Änderungen können mittels status-Node gelesen werden.</p>
<h4><b>Prozesse beenden</b></h4>
<p>Durch Senden von <code>msg.kill</code> wird ein einzelner aktiver Prozess beendet.
<code>msg.kill</code> sollte als Zeichenfolge (string) den Signaltyp enthalten,

View File

@@ -94,7 +94,7 @@
"label": {
"source": "Fehler abfangen von",
"selectAll": "Alles auswählen",
"uncaught": "Fehler ignorieren, die von anderen <span style=\"background-color:Gainsboro\">catch</span>-Nodes behandelt wurden"
"uncaught": "Fehler ignorieren, die von anderen catch-Nodes behandelt wurden"
},
"scope": {
"all": "allen Nodes",
@@ -475,12 +475,12 @@
"json": "Ein parsed JSON-Objekt",
"tip": {
"in": "Die URL ist relativ zu ",
"res": "Die an diesen Node gesendeten Nachrichten <b>müssen</b> von einem <span style=\"background-color:Gainsboro\">http&nbsp;in</span>-Node stammen",
"res": "Die an diesen Node gesendeten Nachrichten <b>müssen</b> von einem http&nbsp;in-Node stammen",
"req": "Tipp: Wenn die JSON-Syntax-Analyse fehlschlägt, wird die abgerufene Zeichenfolge zurückgegeben, wie sie ist."
},
"httpreq": "http request",
"errors": {
"not-created": "<span style=\"background-color:Gainsboro\">http in</span>-Node kann nicht erstellt werden, wenn httpNodeRoot auf 'false' gesetzt ist.",
"not-created": "http in-Node kann nicht erstellt werden, wenn httpNodeRoot auf 'false' gesetzt ist.",
"missing-path": "Fehlender Pfad",
"no-response": "Kein Antwort-Objekt",
"json-error": "JSON-Parse-Fehler",
@@ -684,7 +684,7 @@
},
"errors": {
"invalid-expr": "Ungültiger JSONata-Ausdruck: __error__",
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">switch</span>-Node"
"too-many": "Zu viele anstehende Nachrichten im switch-Node"
}
},
"change": {
@@ -940,8 +940,8 @@
"afterTimeout": "Bei Zeitablauf nach erster Nachricht von",
"seconds": "Sekunden",
"complete": "Nach Nachricht mit <code>msg.complete</code>-Eigenschaft",
"tip": "Dieser Modus setzt voraus, dass dieser Node entweder mit einem <span style=\"background-color:Gainsboro\">split</span>-Node kombiniert ist oder dass die empfangenen Nachrichten über eine ordnungsgemäß konfigurierte <code>msg.parts</code>-Eigenschaft verfügen.",
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">join</span>-Node",
"tip": "Dieser Modus setzt voraus, dass dieser Node entweder mit einem split-Node kombiniert ist oder dass die empfangenen Nachrichten über eine ordnungsgemäß konfigurierte <code>msg.parts</code>-Eigenschaft verfügen.",
"too-many": "Zu viele anstehende Nachrichten im join-Node",
"merge": {
"topics-label": "Zusammengeführte Topics",
"topics": "Topics",
@@ -970,9 +970,9 @@
"ascending": "aufsteigend",
"descending": "absteigend",
"as-number": "als Zahlenwert",
"invalid-exp": "Ungültiger JSONata-Ausdruck in <span style=\"background-color:Gainsboro\">sort</span>-Node: __message__",
"too-many": "Zu viele anstehende Nachrichten in <span style=\"background-color:Gainsboro\">sort</span>-Node",
"clear": "Anstehende Nachricht in <span style=\"background-color:Gainsboro\">sort</span>-Node löschen"
"invalid-exp": "Ungültiger JSONata-Ausdruck in sort-Node: __message__",
"too-many": "Zu viele anstehende Nachrichten in sort-Node",
"clear": "Anstehende Nachricht in sort-Node löschen"
},
"batch": {
"batch": "batch",
@@ -997,7 +997,7 @@
"topics-label": "Topics",
"topic": "Topic"
},
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">batch</span>-Node",
"too-many": "Zu viele anstehende Nachrichten im batch-Node",
"unexpected": "Unerwarteter Modus",
"no-parts": "Keine parts-Eigenschaft in Nachricht"
},

View File

@@ -94,8 +94,8 @@
<script type="text/html" data-help-name="mqtt-broker">
<p>Konfiguration der Verbindung zu einem MQTT-Broker.</p>
<p>Diese Konfiguration erstellt eine einzelne Verbindung zu einem Broker,
welche anschließend von den <span style="background-color:Gainsboro">mqtt&nbsp;in</span>- und
<span style="background-color:Gainsboro">mqtt out</span>-Nodes verwendet werden.</p>
welche anschließend von den mqtt&nbsp;in- und
mqtt out-Nodes verwendet werden.</p>
<p>Der Node generiert eine beliebige Client-ID, falls sie nicht vorgegeben ist und der
Node eine bereinigte Sitzung (clean session) verwenden soll.
Wenn eine Client-ID vorgegeben wird, muss sie für den Broker eindeutig sein, zu dem die Verbindung hergestellt werden soll.</p>

View File

@@ -36,7 +36,7 @@
<dt>res <span class="property-type">object</span></dt>
<dd>HTTP-Antwortobjekt.<br/>
Diese Eigenschaft sollte nicht direkt verwendet werden.
Im <span style="background-color:Gainsboro">http&nbsp;response</span>-Node ist dokumentiert, wie auf eine Anforderung reagiert wird.
Im http&nbsp;response-Node ist dokumentiert, wie auf eine Anforderung reagiert wird.
Diese Eigenschaft muss an der Nachricht angehängt bleiben, die an den Antwort-Node übergeben wird.</dd>
</dl>
<h3>Details</h3>
@@ -50,12 +50,12 @@
<p>Wenn der Inhaltstyp der Anforderung ermittelt werden kann, wird der Hauptteil als passender Typ analysiert.
Z.B. <code>application/json</code> wird zu einem JavaScript-Objekt analysiert.</p>
<p><b>Hinweis</b>: Dieser Node sendet keine Antwort an die Anforderung.
Der Flow muss einen <span style="background-color:Gainsboro">http&nbsp;response</span>-Node enthalten,
Der Flow muss einen http&nbsp;response-Node enthalten,
um die Anforderung zu vervollständigen.</p>
</script>
<script type="text/html" data-help-name="http response">
<p>Senden von Antworten auf Anforderungen, die von einem <span style="background-color:Gainsboro">http&nbsp;in</span>-Node empfangen wurden.</p>
<p>Senden von Antworten auf Anforderungen, die von einem http&nbsp;in-Node empfangen wurden.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">string</span></dt>

View File

@@ -34,17 +34,17 @@
</ul>
</dd>
<dt>schemaError <span class="property-type">array</span></dt>
<dd>Wenn die JSON-Schema-Validierung fehlschlägt, wird für den <span style="background-color:Gainsboro">catch</span>-Node eine <code>schemaError</code>-Eigenschaft erstellt,
<dd>Wenn die JSON-Schema-Validierung fehlschlägt, wird für den catch-Node eine <code>schemaError</code>-Eigenschaft erstellt,
die ein Array von Fehlern enthält.</dd>
</dl>
<h3>Details</h3>
<p>Standardmäßig verarbeitet der Node <code>msg.payload</code>,
kann aber auch eine beliebige Nachrichteneigenschaft konvertieren.</p>
<p>Die Konvertierungsrichtung kann im Node auch vorgegeben werden, um eine bestimmte Ziel-Kodierung sicherzustellen.
Dies kann z.B. zusammen mit dem <span style="background-color:Gainsboro">http&nbsp;in</span>-Node benutzt werden, um sicherzustellen,
Dies kann z.B. zusammen mit dem http&nbsp;in-Node benutzt werden, um sicherzustellen,
dass die Nutzdaten (Payload) ein analysiertes (parsed) Objekt ist,
auch wenn eine eingehende Anfrage seinen Inhaltstyp nicht korrekt eingestellt hat,
damit der <span style="background-color:Gainsboro">http&nbsp;in</span>-Node die Konvertierung durchführen kann.</p>
damit der http&nbsp;in-Node die Konvertierung durchführen kann.</p>
<p>Wenn der Node auf Zeichenfolgen-Eingang (string) eingestellt ist und es einen String empfängt,
werden keine weiteren Prüfungen der Eigenschaft durchgeführt.
Der Node prüft weder, ob die Zeichenfolge (string) ein gültiges JSON enthält, noch wird er ihn neu formatieren,

View File

@@ -32,7 +32,7 @@
<dl class="message-properties">
<dt>parts <span class="property-type">object</span></dt>
<dd>Diese Eigenschaft enthält Informationen darüber, wie die Nachricht von der ursprünglichen Nachricht abgeteilt wurde.
Bei Übergabe an ein <span style="background-color:Gainsboro">join</span>-Node kann die Sequenz wieder zu einer einzigen Nachricht zusammengeführt werden.
Bei Übergabe an ein join-Node kann die Sequenz wieder zu einer einzigen Nachricht zusammengeführt werden.
Diese Eigenschaft hat die folgenden Eigenschaften:
<ul>
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
@@ -48,7 +48,7 @@
</dl>
<h3>Details</h3>
<p>Dieser Node macht es einfach, einen Flow zu erstellen, der gemeinsame Aktionen über eine Sequenz von Nachrichten ausführt,
bevor die Sequenz mittels <span style="background-color:Gainsboro">join</span>-Node wieder zu einer einzigen Nachricht neu kombiniert wird.</p>
bevor die Sequenz mittels join-Node wieder zu einer einzigen Nachricht neu kombiniert wird.</p>
<p>Der Node verwendet die <code>msg.parts</code>-Eigenschaft, um die einzelnen Sequenzteile nachzuverfolgen.</p>
<h4><b>Streaming-Modus</b></h4>
<p>Der Node kann auch zum Aufbereiten eines Nachrichtenstroms verwendet werden.
@@ -59,7 +59,7 @@
so wird es im Node aufbewahrt und der nächsten empfangenen Nachricht vorangestellt.</p>
<p>In diesem Modus wird die <code>msg.parts.count</code>-Eigenschaft nicht gesetzt,
da die Anzahl der zu erwartenden Nachrichten im Stream unbekannt ist.
Das bedeutet, dass ein nachfolgender <span style="background-color:Gainsboro">join</span>-Node nicht im Automatikmodus verwendet werden kann.</p>
Das bedeutet, dass ein nachfolgender join-Node nicht im Automatikmodus verwendet werden kann.</p>
</script>
<script type="text/html" data-help-name="join">
@@ -67,7 +67,7 @@
<p>Es sind drei Modi verfügbar:</p>
<dl>
<dt>Automatisch</dt>
<dd>In Kombination mit dem <span style="background-color:Gainsboro">split</span>-Node verbindet es automatisch die Nachrichten, um die zuvor durchgeführte Aufteilung rückgängig zu machen.</dd>
<dd>In Kombination mit dem split-Node verbindet es automatisch die Nachrichten, um die zuvor durchgeführte Aufteilung rückgängig zu machen.</dd>
<dt>Manuell</dt>
<dd>Die Nachrichtensequenzen können auf verschiedene Weisen verbunden werden.</dd>
<dt>Sequenz reduzieren</dt>
@@ -77,7 +77,7 @@
<dl class="message-properties">
<dt class="optional">parts <span class="property-type">object</span></dt>
<dd>Zur automatischen Verbindung einer Nachrichtensequenz sollten alle über diese Eigenschaft verfügen.
Der <span style="background-color:Gainsboro">split</span>-Node erzeugt diese Eigenschaft, sie kann aber auch manuell erstellt werden.
Der split-Node erzeugt diese Eigenschaft, sie kann aber auch manuell erstellt werden.
Sie hat die folgenden Eigenschaften:
<ul>
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
@@ -98,7 +98,7 @@
<h4><b>Automatischer Modus</b></h4>
<p>Der automatische Modus verwendet die <code>parts</code>-Eigenschaften der eingehenden Nachrichten,
um die Sequenz in richtiger Reihenfolge zu verknüpften.
Dies ermöglicht die Aufteilung des <span style="background-color:Gainsboro">split</span>-Nodes automatisch rückgängig zu machen.</p>
Dies ermöglicht die Aufteilung des split-Nodes automatisch rückgängig zu machen.</p>
<h4><b>Manueller Modus</b></h4>
<p>Im manuellen Modus werden Nachrichtensequenzen auf verschiedenen Arten zusammengefügt:</p>

View File

@@ -26,8 +26,8 @@
<p>Für Zahlenwerte kann die numerische Sortierreihenfolge festgelegt werden.</p>
<p>Der Sortierschlüssel kann ein Elementwert oder ein JSONata-Ausdruck beim Sortieren einer Nachrichteneigenschaft
bzw. eine Nachrichteneigenschaft oder ein JSONata-Ausdruck beim Sortieren einer Nachrichtensequenz sein.<p>
<p>Zum Sortieren einer Nachrichtensequenz benötigt der <span style="background-color:Gainsboro">sort</span>-Node die gesetzte <code>msg.parts</code>-Eigenschaft bei den empfangenen Nachrichten.
Diese Eigenschaft wird vom <span style="background-color:Gainsboro">split</span>-Node erzeugt und kann aber auch manuell erzeugt werden.
<p>Zum Sortieren einer Nachrichtensequenz benötigt der sort-Node die gesetzte <code>msg.parts</code>-Eigenschaft bei den empfangenen Nachrichten.
Diese Eigenschaft wird vom split-Node erzeugt und kann aber auch manuell erzeugt werden.
Sie hat die folgenden Eigenschaften:</p>
<p>
<ul>

View File

@@ -58,5 +58,5 @@
aber typischerweise 64k (Linux/Mac) oder 41k (Windows).</p>
<p>Bei Aufteilung in mehrere Nachrichten besitzt jede eine <code>parts</code>-Eigenschaft,
welche eine komplette Nachrichten-Sequenz bildet.</p>
<p>Fehler sollten mittels <span style="background-color:Gainsboro">catch</span>-Nodes abgefangen und behandelt werden.</p>
<p>Fehler sollten mittels catch-Nodes abgefangen und behandelt werden.</p>
</script>

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/nodes",
"version": "2.1.0-beta.2",
"version": "2.1.3",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/registry",
"version": "2.1.0-beta.2",
"version": "2.1.3",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,7 +16,7 @@
}
],
"dependencies": {
"@node-red/util": "2.1.0-beta.2",
"@node-red/util": "2.1.3",
"clone": "2.1.2",
"fs-extra": "10.0.0",
"semver": "7.3.5",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/runtime",
"version": "2.1.0-beta.2",
"version": "2.1.3",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/registry": "2.1.0-beta.2",
"@node-red/util": "2.1.0-beta.2",
"@node-red/registry": "2.1.3",
"@node-red/util": "2.1.3",
"async-mutex": "0.3.2",
"clone": "2.1.2",
"express": "4.17.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/util",
"version": "2.1.0-beta.2",
"version": "2.1.3",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
#
# Copyright JS Foundation and other contributors, http://js.foundation
#
@@ -29,15 +29,16 @@ do
done
# Find the real location of this script
CURRENT_PATH=`pwd`
SCRIPT_PATH="${BASH_SOURCE[0]}";
CURRENT_PATH=$(pwd)
SCRIPT_PATH=$(readlink -f "$0")
while [ -h "${SCRIPT_PATH}" ]; do
cd "`dirname "${SCRIPT_PATH}"`"
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
cd "$(dirname "${SCRIPT_PATH}")" || exit 1
P=$(basename "${SCRIPT_PATH}")
SCRIPT_PATH=$(readlink "${P}")
done
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
SCRIPT_PATH="`pwd`";
cd $CURRENT_PATH
cd "$(dirname "${SCRIPT_PATH}")" > /dev/null || exit 1
SCRIPT_PATH=$(pwd)
cd "$CURRENT_PATH" || exit 1
# Run Node-RED
exec /usr/bin/env node $OPTIONS $SCRIPT_PATH/../red.js $ARGS
exec /usr/bin/env node ${OPTIONS} ${SCRIPT_PATH}/../red.js ${ARGS}

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "2.1.0-beta.2",
"version": "2.1.3",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -31,10 +31,10 @@
"flow"
],
"dependencies": {
"@node-red/editor-api": "2.1.0-beta.2",
"@node-red/runtime": "2.1.0-beta.2",
"@node-red/util": "2.1.0-beta.2",
"@node-red/nodes": "2.1.0-beta.2",
"@node-red/editor-api": "2.1.3",
"@node-red/runtime": "2.1.3",
"@node-red/util": "2.1.3",
"@node-red/nodes": "2.1.3",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"express": "4.17.1",

View File

@@ -194,6 +194,11 @@ if (process.env.NODE_RED_ENABLE_PROJECTS) {
settings.editorTheme.projects.enabled = !/^false$/i.test(process.env.NODE_RED_ENABLE_PROJECTS);
}
if (process.env.NODE_RED_ENABLE_TOURS) {
settings.editorTheme = settings.editorTheme || {};
settings.editorTheme.tours = !/^false$/i.test(process.env.NODE_RED_ENABLE_TOURS);
}
var defaultServerSettings = {
"x-powered-by": false

View File

@@ -9,29 +9,36 @@ const LATEST = "2";
function generateScript() {
return new Promise((resolve, reject) => {
const packages = [
"node-red-util",
"node-red-runtime",
"node-red-registry",
"node-red-nodes",
"node-red-editor-client",
"node-red-editor-api",
"@node-red/util",
"@node-red/runtime",
"@node-red/registry",
"@node-red/nodes",
"@node-red/editor-client",
"@node-red/editor-api",
"node-red"
];
const rootPackage = require(path.join(__dirname,"..","package.json"));
const version = rootPackage.version;
const versionParts = version.split(".");
let updateNextToLatest = false;
let tagArg = "";
if (versionParts[0] !== LATEST) {
tagArg = `--tag v${versionParts[0]}-maintenance`
} else if (/-/.test(version)) {
tagArg = "--tag next"
} else {
updateNextToLatest = true;
}
const lines = [];
packages.forEach(name => {
lines.push(`npm publish ${name}-${version}.tgz ${tagArg}\n`);
const tarName = name.replace(/@/,"").replace(/\//,"-")
lines.push(`npm publish ${tarName}-${version}.tgz ${tagArg}\n`);
if (updateNextToLatest) {
lines.push(`npm dist-tag add ${name}@${version} next\n`);
}
})
resolve(lines.join(""))
});

View File

@@ -60,9 +60,9 @@ describe('TCP Request Node', function() {
n2.on("input", function(msg) {
try {
if (typeof val1 === 'object') {
msg.should.have.properties(Object.assign({}, val1, {payload: Buffer(val1.payload)}));
msg.should.have.properties(Object.assign({}, val1, {payload: Buffer.from(val1.payload)}));
} else {
msg.should.have.property('payload', Buffer(val1));
msg.should.have.property('payload', Buffer.from(val1));
}
done();
} catch(err) {
@@ -84,9 +84,9 @@ describe('TCP Request Node', function() {
n2.on("input", msg => {
try {
if (typeof result === 'object') {
msg.should.have.properties(Object.assign({}, result, {payload: Buffer(result.payload)}));
msg.should.have.properties(Object.assign({}, result, {payload: Buffer.from(result.payload)}));
} else {
msg.should.have.property('payload', Buffer(result));
msg.should.have.property('payload', Buffer.from(result));
}
done();
} catch(err) {