mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
95 Commits
1.0.5
...
enhance-cs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fda95dfc5d | ||
|
|
24eb78d137 | ||
|
|
e969a1c97c | ||
|
|
fbfc74e5ca | ||
|
|
1b5654001c | ||
|
|
e0f3e94e2b | ||
|
|
5da89892b4 | ||
|
|
04da13eaf9 | ||
|
|
7fa4df082e | ||
|
|
ae001c5e82 | ||
|
|
fa8236ee2c | ||
|
|
08ec04c889 | ||
|
|
e5150ea012 | ||
|
|
222ece2533 | ||
|
|
294696daf5 | ||
|
|
d099356207 | ||
|
|
05fc3c5eca | ||
|
|
b1d0013214 | ||
|
|
94ef25bbb9 | ||
|
|
13830ffc9c | ||
|
|
e0bef941b4 | ||
|
|
03e9522d98 | ||
|
|
1bdbd31b96 | ||
|
|
ef9db701f8 | ||
|
|
afb564a4fc | ||
|
|
3e7f58dedd | ||
|
|
2e364b6d9a | ||
|
|
b4177836a8 | ||
|
|
5b2ee21204 | ||
|
|
7c91c4ae5a | ||
|
|
7bc3b662e4 | ||
|
|
64af1f7e9b | ||
|
|
f0038e9796 | ||
|
|
768aa4ac92 | ||
|
|
f61c137ea3 | ||
|
|
20a8059758 | ||
|
|
58696c6ad4 | ||
|
|
b5ed018bae | ||
|
|
91b7dd988e | ||
|
|
5cd2791506 | ||
|
|
9b2e9ec41a | ||
|
|
a8bc753720 | ||
|
|
266df86d98 | ||
|
|
c4ca0b6e91 | ||
|
|
1bf3b3077e | ||
|
|
c9194c3635 | ||
|
|
27c462fee9 | ||
|
|
7886e5d57c | ||
|
|
6912dec166 | ||
|
|
0ef3471f8f | ||
|
|
fc3d0ab053 | ||
|
|
de971fa53f | ||
|
|
d005eb46cf | ||
|
|
d1dd7d1d51 | ||
|
|
9a0c843f29 | ||
|
|
4d96d95370 | ||
|
|
51ea5dc342 | ||
|
|
97d58e34f2 | ||
|
|
86ce5c591b | ||
|
|
8a82552bdc | ||
|
|
bd4fc2e5cc | ||
|
|
83942c2551 | ||
|
|
458d794f52 | ||
|
|
95982ad464 | ||
|
|
bba6855872 | ||
|
|
c9ad5bea93 | ||
|
|
a09b3bb6c7 | ||
|
|
8405826fab | ||
|
|
54978e4d64 | ||
|
|
2da1554caa | ||
|
|
4f9395e881 | ||
|
|
8035531a27 | ||
|
|
cc177533e8 | ||
|
|
cd210d9fbf | ||
|
|
87b9b56b65 | ||
|
|
bffcaa1c17 | ||
|
|
33cbb2ada8 | ||
|
|
d08e77cf36 | ||
|
|
1f8ed9dcb9 | ||
|
|
272fbc0cb0 | ||
|
|
36bf2a3c38 | ||
|
|
6b52206186 | ||
|
|
468beee045 | ||
|
|
70ad66bcff | ||
|
|
74a015c329 | ||
|
|
14c2005bbc | ||
|
|
d017dd75cd | ||
|
|
021df83c3f | ||
|
|
d45274494d | ||
|
|
f478afb58a | ||
|
|
a54ca699b5 | ||
|
|
ff96773295 | ||
|
|
7957ec4369 | ||
|
|
17653761b9 | ||
|
|
a42d7d867e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,3 +22,4 @@ packages/node_modules/@node-red/editor-client/public
|
||||
!test/**/node_modules
|
||||
docs
|
||||
!packages/node_modules/**/docs
|
||||
.vscode
|
||||
39
CHANGELOG.md
39
CHANGELOG.md
@@ -1,42 +1,3 @@
|
||||
#### 1.0.5: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- #2500 Support for context stores using JSONata and evaluateNodeProperty()
|
||||
- Add better handling of host-key-verify error with projects
|
||||
- #2517 Handle false values in $env() properly
|
||||
- #2514 Ensure complete node scope is remapped in subflows
|
||||
- #2513 Flows/subflows must preinitialise their context objects
|
||||
- Clear node.close timeout to avoid unnecessary work on restart
|
||||
- #2532 Set flow.disabled when disabled property is false
|
||||
- #2522 Ensure file context does not write 'undefined' to store
|
||||
|
||||
Editor
|
||||
|
||||
- #2489 Fix XPath in UI tests
|
||||
- #2504 Fix paletteCategories order
|
||||
- #2501 Add page objects for UI testing
|
||||
- #2494 Check node props when deciding if pasted node can splice links
|
||||
- #2521 Don't double-sanitize node name in debug sidebar
|
||||
- #2519 German i18n updates
|
||||
- #2523 Update nodeTabMap when replacing unknown nodes
|
||||
- Update TypedInput to use flexbox and remove resizing code
|
||||
- Handle nodes with no wires array
|
||||
- Do not collapse whitespace in Debug string messages
|
||||
|
||||
Nodes
|
||||
|
||||
- File: Remove old legacy wording from file node info to stop confusing users.
|
||||
- Join: Ensure join node handles missing buffer joiner when not in string mode
|
||||
- Exec: make exec node logging consistent with itself. (only be verbose when in verbose mode)
|
||||
- Trigger: reset default timeout value when switching away from wait for reset
|
||||
- Join: Fix join to not crash on appending invalid types to buffer.
|
||||
- MQTT out: Add warning if topic contains + or #
|
||||
- #2502 WebSocket i18n update
|
||||
- #2508 Add Japanese translation for join node
|
||||
- TCP out: tidy up select of which rows to display
|
||||
|
||||
|
||||
#### 1.0.4: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
@@ -151,6 +151,7 @@ module.exports = function(grunt) {
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
|
||||
@@ -177,6 +178,7 @@ module.exports = function(grunt) {
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/group.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
|
||||
|
||||
17
package.json
17
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.4",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -32,7 +32,7 @@
|
||||
"clone": "2.1.2",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.0",
|
||||
"cookie-parser": "1.4.5",
|
||||
"cookie-parser": "1.4.4",
|
||||
"cors": "2.8.5",
|
||||
"cron": "1.8.2",
|
||||
"denque": "1.4.1",
|
||||
@@ -47,17 +47,18 @@
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.13.1",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.8.2",
|
||||
"jsonata": "1.8.1",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.2",
|
||||
"mime": "2.4.4",
|
||||
"mqtt": "2.18.8",
|
||||
"multer": "1.4.2",
|
||||
"mustache": "4.0.1",
|
||||
"mustache": "4.0.0",
|
||||
"node-red-node-rbe": "^0.2.6",
|
||||
"node-red-node-sentiment": "^0.1.6",
|
||||
"node-red-node-tail": "^0.1.0",
|
||||
"nopt": "4.0.3",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.4.1",
|
||||
@@ -66,16 +67,16 @@
|
||||
"raw-body": "2.4.1",
|
||||
"request": "2.88.0",
|
||||
"semver": "6.3.0",
|
||||
"uglify-js": "3.8.1",
|
||||
"uglify-js": "3.8.0",
|
||||
"when": "3.7.8",
|
||||
"ws": "6.2.1",
|
||||
"xml2js": "0.4.23"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "3.0.8"
|
||||
"bcrypt": "3.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"marked": "0.8.2",
|
||||
"marked": "0.8.0",
|
||||
"dompurify": "2.0.8",
|
||||
"grunt": "~1.0.4",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
|
||||
@@ -44,6 +44,7 @@ module.exports = {
|
||||
user: req.user,
|
||||
module: req.body.module,
|
||||
version: req.body.version,
|
||||
url: req.body.url,
|
||||
req: apiUtils.getRequestLogObject(req)
|
||||
}
|
||||
runtimeAPI.nodes.addModule(opts).then(function(info) {
|
||||
|
||||
@@ -36,6 +36,7 @@ var log = require("@node-red/util").log; // TODO: separate module
|
||||
passport.use(strategies.bearerStrategy.BearerStrategy);
|
||||
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
|
||||
passport.use(strategies.anonymousStrategy);
|
||||
passport.use(strategies.tokensStrategy);
|
||||
|
||||
var server = oauth2orize.createServer();
|
||||
|
||||
@@ -60,7 +61,7 @@ function init(_settings,storage) {
|
||||
function needsPermission(permission) {
|
||||
return function(req,res,next) {
|
||||
if (settings && settings.adminAuth) {
|
||||
return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() {
|
||||
return passport.authenticate(['bearer','tokens','anon'],{ session: false })(req,res,function() {
|
||||
if (!req.user) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -123,9 +123,38 @@ AnonymousStrategy.prototype.authenticate = function(req) {
|
||||
});
|
||||
}
|
||||
|
||||
function TokensStrategy() {
|
||||
passport.Strategy.call(this);
|
||||
this.name = 'tokens';
|
||||
}
|
||||
util.inherits(TokensStrategy, passport.Strategy);
|
||||
TokensStrategy.prototype.authenticate = function(req) {
|
||||
var self = this;
|
||||
var token = null;
|
||||
if (Users.tokenHeader() === 'authorization') {
|
||||
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
|
||||
token = req.headers.authorization.split(' ')[1];
|
||||
}
|
||||
} else {
|
||||
token = req.headers[Users.tokenHeader()];
|
||||
}
|
||||
if (token) {
|
||||
Users.tokens(token).then(function(admin) {
|
||||
if (admin) {
|
||||
self.success(admin,{scope:admin.permissions});
|
||||
} else {
|
||||
self.fail(401);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.fail(401);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
bearerStrategy: bearerStrategy,
|
||||
clientPasswordStrategy: clientPasswordStrategy,
|
||||
passwordTokenExchange: passwordTokenExchange,
|
||||
anonymousStrategy: new AnonymousStrategy()
|
||||
anonymousStrategy: new AnonymousStrategy(),
|
||||
tokensStrategy: new TokensStrategy()
|
||||
}
|
||||
|
||||
@@ -59,7 +59,9 @@ function getDefaultUser() {
|
||||
var api = {
|
||||
get: get,
|
||||
authenticate: authenticate,
|
||||
default: getDefaultUser
|
||||
default: getDefaultUser,
|
||||
tokens: getDefaultUser,
|
||||
tokenHeader: "authorization"
|
||||
}
|
||||
|
||||
function init(config) {
|
||||
@@ -105,6 +107,12 @@ function init(config) {
|
||||
} else {
|
||||
api.default = getDefaultUser;
|
||||
}
|
||||
if (config.tokens && typeof config.tokens === "function") {
|
||||
api.tokens = config.tokens;
|
||||
if (config.tokenHeader && typeof config.tokenHeader === "string") {
|
||||
api.tokenHeader = config.tokenHeader.toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
function cleanUser(user) {
|
||||
if (user && user.hasOwnProperty('password')) {
|
||||
@@ -118,5 +126,7 @@ module.exports = {
|
||||
init: init,
|
||||
get: function(username) { return api.get(username).then(cleanUser)},
|
||||
authenticate: function() { return api.authenticate.apply(null, arguments) },
|
||||
default: function() { return api.default(); }
|
||||
default: function() { return api.default(); },
|
||||
tokens: function(token) { return api.tokens(token); },
|
||||
tokenHeader: function() { return api.tokenHeader }
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.4",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "1.0.5",
|
||||
"@node-red/editor-client": "1.0.5",
|
||||
"@node-red/util": "1.0.4",
|
||||
"@node-red/editor-client": "1.0.4",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
"clone": "2.1.2",
|
||||
@@ -26,7 +26,7 @@
|
||||
"express": "4.17.1",
|
||||
"memorystore": "1.6.2",
|
||||
"mime": "2.4.4",
|
||||
"mustache": "4.0.1",
|
||||
"mustache": "4.0.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
"back": "Back",
|
||||
"next": "Next",
|
||||
"clone": "Clone project",
|
||||
"cont": "Continue"
|
||||
"cont": "Continue",
|
||||
"line": "Outline",
|
||||
"fill": "Fill",
|
||||
"color": "Color",
|
||||
"position": "Position"
|
||||
},
|
||||
"type": {
|
||||
"string": "string",
|
||||
@@ -91,7 +95,12 @@
|
||||
"projects-new": "New",
|
||||
"projects-open": "Open",
|
||||
"projects-settings": "Project Settings",
|
||||
"showNodeLabelDefault": "Show label of newly added nodes"
|
||||
"showNodeLabelDefault": "Show label of newly added nodes",
|
||||
"groups": "Groups",
|
||||
"groupSelection": "Group selection",
|
||||
"ungroupSelection": "Ungroup selection",
|
||||
"groupMergeSelection": "Merge selection",
|
||||
"groupRemoveSelection": "Remove from group"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
@@ -171,6 +180,8 @@
|
||||
"node_plural": "__count__ nodes",
|
||||
"configNode": "__count__ configuration node",
|
||||
"configNode_plural": "__count__ configuration nodes",
|
||||
"group": "__count__ group",
|
||||
"group_plural": "__count__ groups",
|
||||
"flow": "__count__ flow",
|
||||
"flow_plural": "__count__ flows",
|
||||
"subflow": "__count__ subflow",
|
||||
@@ -186,6 +197,9 @@
|
||||
"nodesImported": "Imported:",
|
||||
"nodeCopied": "__count__ node copied",
|
||||
"nodeCopied_plural": "__count__ nodes copied",
|
||||
"groupCopied": "__count__ group copied",
|
||||
"groupCopied_plural": "__count__ groups copied",
|
||||
"groupStyleCopied": "Group style copied",
|
||||
"invalidFlow": "Invalid flow: __message__",
|
||||
"export": {
|
||||
"selected":"selected nodes",
|
||||
@@ -308,6 +322,13 @@
|
||||
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
|
||||
}
|
||||
},
|
||||
"group": {
|
||||
"editGroup": "Edit group: __name__",
|
||||
"errors": {
|
||||
"cannotCreateDiffGroups": "Cannot create group using nodes from different groups",
|
||||
"cannotAddSubflowPorts": "Cannot add subflow ports to a group"
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"configEdit": "Edit",
|
||||
"configAdd": "Add",
|
||||
@@ -351,7 +372,8 @@
|
||||
"bool": "bool",
|
||||
"json": "JSON",
|
||||
"bin": "buffer",
|
||||
"env": "env variable"
|
||||
"env": "env variable",
|
||||
"cred": "credential"
|
||||
},
|
||||
"menu": {
|
||||
"input": "input",
|
||||
@@ -538,6 +560,7 @@
|
||||
"label": "info",
|
||||
"node": "Node",
|
||||
"type": "Type",
|
||||
"group": "Group",
|
||||
"module": "Module",
|
||||
"id": "ID",
|
||||
"status": "Status",
|
||||
@@ -613,7 +636,6 @@
|
||||
"removeFromProject": "remove from project",
|
||||
"addToProject": "add to project",
|
||||
"files": "Files",
|
||||
"package": "Package",
|
||||
"flow": "Flow",
|
||||
"credentials": "Credentials",
|
||||
"package":"Package",
|
||||
@@ -757,7 +779,8 @@
|
||||
"bin": "buffer",
|
||||
"date": "timestamp",
|
||||
"jsonata": "expression",
|
||||
"env": "env variable"
|
||||
"env": "env variable",
|
||||
"cred": "credential"
|
||||
}
|
||||
},
|
||||
"editableList": {
|
||||
|
||||
@@ -351,7 +351,8 @@
|
||||
"bool": "真偽",
|
||||
"json": "JSON",
|
||||
"bin": "バッファ",
|
||||
"env": "環境変数"
|
||||
"env": "環境変数",
|
||||
"cred": "認証情報"
|
||||
},
|
||||
"menu": {
|
||||
"input": "入力",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.4",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -21,6 +21,7 @@ RED.history = (function() {
|
||||
var i;
|
||||
var len;
|
||||
var node;
|
||||
var group;
|
||||
var subflow;
|
||||
var modifiedTabs = {};
|
||||
var inverseEv;
|
||||
@@ -74,6 +75,15 @@ RED.history = (function() {
|
||||
RED.nodes.removeLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
if (ev.groups) {
|
||||
inverseEv.groups = [];
|
||||
for (i=0;i<ev.groups.length;i++) {
|
||||
group = ev.groups[i];
|
||||
modifiedTabs[group.z] = true;
|
||||
inverseEv.groups.push(group);
|
||||
RED.nodes.removeGroup(group);
|
||||
}
|
||||
}
|
||||
if (ev.workspaces) {
|
||||
inverseEv.workspaces = [];
|
||||
for (i=0;i<ev.workspaces.length;i++) {
|
||||
@@ -193,12 +203,35 @@ RED.history = (function() {
|
||||
n.dirty = true;
|
||||
});
|
||||
}
|
||||
if (ev.groups) {
|
||||
inverseEv.groups = [];
|
||||
var groupsToAdd = new Set(ev.groups.map(function(g) { return g.id }));
|
||||
for (i=0;i<ev.groups.length;i++) {
|
||||
RED.nodes.addGroup(ev.groups[i])
|
||||
modifiedTabs[ev.groups[i].z] = true;
|
||||
inverseEv.groups.push(ev.groups[i]);
|
||||
if (ev.groups[i].g && !groupsToAdd.has(ev.groups[i].g)) {
|
||||
group = RED.nodes.group(ev.groups[i].g);
|
||||
if (group.nodes.indexOf(ev.groups[i]) === -1) {
|
||||
group.nodes.push(ev.groups[i]);
|
||||
}
|
||||
RED.group.markDirty(ev.groups[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ev.nodes) {
|
||||
inverseEv.nodes = [];
|
||||
for (i=0;i<ev.nodes.length;i++) {
|
||||
RED.nodes.add(ev.nodes[i]);
|
||||
modifiedTabs[ev.nodes[i].z] = true;
|
||||
inverseEv.nodes.push(ev.nodes[i].id);
|
||||
if (ev.nodes[i].g) {
|
||||
group = RED.nodes.group(ev.nodes[i].g);
|
||||
if (group.nodes.indexOf(ev.nodes[i]) === -1) {
|
||||
group.nodes.push(ev.nodes[i]);
|
||||
}
|
||||
RED.group.markDirty(group)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ev.links) {
|
||||
@@ -260,6 +293,13 @@ RED.history = (function() {
|
||||
RED.nodes.addLink(ev.removedLinks[i]);
|
||||
}
|
||||
}
|
||||
if (ev.addToGroup) {
|
||||
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),true);
|
||||
inverseEv.removeFromGroup = ev.addToGroup;
|
||||
} else if (ev.removeFromGroup) {
|
||||
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
|
||||
inverseEv.addToGroup = ev.removeFromGroup;
|
||||
}
|
||||
} else if (ev.t == "edit") {
|
||||
inverseEv = {
|
||||
t: "edit",
|
||||
@@ -370,7 +410,9 @@ RED.history = (function() {
|
||||
if (ev.nodes) {
|
||||
inverseEv.movedNodes = [];
|
||||
var z = ev.activeWorkspace;
|
||||
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) {
|
||||
var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
|
||||
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
|
||||
fullNodeList.forEach(function(n) {
|
||||
n.x += ev.subflow.offsetX;
|
||||
n.y += ev.subflow.offsetY;
|
||||
n.dirty = true;
|
||||
@@ -411,6 +453,9 @@ RED.history = (function() {
|
||||
if (ev.subflow) {
|
||||
RED.nodes.addSubflow(ev.subflow.subflow);
|
||||
inverseEv.subflow = ev.subflow;
|
||||
if (ev.subflow.subflow.g) {
|
||||
RED.group.addToGroup(RED.nodes.group(ev.subflow.subflow.g),ev.subflow.subflow);
|
||||
}
|
||||
}
|
||||
if (ev.subflows) {
|
||||
inverseEv.nodes = [];
|
||||
@@ -422,6 +467,9 @@ RED.history = (function() {
|
||||
if (ev.movedNodes) {
|
||||
ev.movedNodes.forEach(function(nid) {
|
||||
nn = RED.nodes.node(nid);
|
||||
if (!nn) {
|
||||
nn = RED.nodes.group(nid);
|
||||
}
|
||||
nn.x -= ev.subflow.offsetX;
|
||||
nn.y -= ev.subflow.offsetY;
|
||||
nn.dirty = true;
|
||||
@@ -435,7 +483,7 @@ RED.history = (function() {
|
||||
RED.nodes.addLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
if (ev.createdLinks) {
|
||||
if (ev.createdLinks) {
|
||||
inverseEv.removedLinks = [];
|
||||
for (i=0;i<ev.createdLinks.length;i++) {
|
||||
inverseEv.removedLinks.push(ev.createdLinks[i]);
|
||||
@@ -450,6 +498,55 @@ RED.history = (function() {
|
||||
if (ev.order) {
|
||||
RED.workspaces.order(ev.order);
|
||||
}
|
||||
} else if (ev.t == "createGroup") {
|
||||
inverseEv = {
|
||||
t: "ungroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
groups: []
|
||||
}
|
||||
if (ev.groups) {
|
||||
for (i=0;i<ev.groups.length;i++) {
|
||||
inverseEv.groups.push(ev.groups[i]);
|
||||
RED.group.ungroup(ev.groups[i]);
|
||||
}
|
||||
}
|
||||
} else if (ev.t == "ungroup") {
|
||||
inverseEv = {
|
||||
t: "createGroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
groups: []
|
||||
}
|
||||
if (ev.groups) {
|
||||
for (i=0;i<ev.groups.length;i++) {
|
||||
inverseEv.groups.push(ev.groups[i]);
|
||||
var nodes = ev.groups[i].nodes.slice();
|
||||
ev.groups[i].nodes = [];
|
||||
RED.nodes.addGroup(ev.groups[i]);
|
||||
RED.group.addToGroup(ev.groups[i],nodes);
|
||||
}
|
||||
}
|
||||
} else if (ev.t == "addToGroup") {
|
||||
inverseEv = {
|
||||
t: "removeFromGroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
group: ev.group,
|
||||
nodes: ev.nodes,
|
||||
reparent: ev.reparent
|
||||
}
|
||||
if (ev.nodes) {
|
||||
RED.group.removeFromGroup(ev.group,ev.nodes,(ev.hasOwnProperty('reparent')&&ev.hasOwnProperty('reparent')!==undefined)?ev.reparent:true);
|
||||
}
|
||||
} else if (ev.t == "removeFromGroup") {
|
||||
inverseEv = {
|
||||
t: "addToGroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
group: ev.group,
|
||||
nodes: ev.nodes,
|
||||
reparent: ev.reparent
|
||||
}
|
||||
if (ev.nodes) {
|
||||
RED.group.addToGroup(ev.group,ev.nodes);
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(modifiedTabs).forEach(function(id) {
|
||||
@@ -460,8 +557,8 @@ RED.history = (function() {
|
||||
});
|
||||
|
||||
RED.nodes.dirty(ev.dirty);
|
||||
RED.view.updateActive();
|
||||
RED.view.select(null);
|
||||
RED.view.redraw(true);
|
||||
RED.palette.refresh();
|
||||
RED.workspaces.refresh();
|
||||
RED.sidebar.config.refresh();
|
||||
@@ -482,6 +579,9 @@ RED.history = (function() {
|
||||
list: function() {
|
||||
return undoHistory;
|
||||
},
|
||||
listRedo: function() {
|
||||
return redoHistory;
|
||||
},
|
||||
depth: function() {
|
||||
return undoHistory.length;
|
||||
},
|
||||
|
||||
@@ -44,6 +44,14 @@
|
||||
"ctrl-y": "core:redo",
|
||||
"ctrl-a": "core:select-all-nodes",
|
||||
"shift-?": "core:show-help",
|
||||
"w": "core:scroll-view-up",
|
||||
"d": "core:scroll-view-right",
|
||||
"s": "core:scroll-view-down",
|
||||
"a": "core:scroll-view-left",
|
||||
"shift-w": "core:step-view-up",
|
||||
"shift-d": "core:step-view-right",
|
||||
"shift-s": "core:step-view-down",
|
||||
"shift-a": "core:step-view-left",
|
||||
"up": "core:move-selection-up",
|
||||
"right": "core:move-selection-right",
|
||||
"down": "core:move-selection-down",
|
||||
@@ -53,6 +61,10 @@
|
||||
"shift-down": "core:step-selection-down",
|
||||
"shift-left": "core:step-selection-left",
|
||||
"ctrl-shift-j": "core:show-previous-tab",
|
||||
"ctrl-shift-k": "core:show-next-tab"
|
||||
"ctrl-shift-k": "core:show-next-tab",
|
||||
"ctrl-shift-g": "core:group-selection",
|
||||
"ctrl-shift-u": "core:ungroup-selection",
|
||||
"ctrl-shift-c": "core:copy-group-style",
|
||||
"ctrl-shift-v": "core:paste-group-style"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@ RED.nodes = (function() {
|
||||
var subflows = {};
|
||||
var loadedFlowVersion = null;
|
||||
|
||||
var groups = {};
|
||||
var groupsByZ = {};
|
||||
|
||||
var initialLoad;
|
||||
|
||||
var dirty = false;
|
||||
@@ -302,6 +305,10 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
function moveNodeToTab(node, z) {
|
||||
if (node.type === "group") {
|
||||
moveGroupToTab(node,z);
|
||||
return;
|
||||
}
|
||||
if (nodeTabMap[node.z]) {
|
||||
delete nodeTabMap[node.z][node.id];
|
||||
}
|
||||
@@ -311,6 +318,13 @@ RED.nodes = (function() {
|
||||
nodeTabMap[z][node.id] = node;
|
||||
node.z = z;
|
||||
}
|
||||
function moveGroupToTab(group, z) {
|
||||
var index = groupsByZ[group.z].indexOf(group);
|
||||
groupsByZ[group.z].splice(index,1);
|
||||
groupsByZ[z] = groupsByZ[z] || [];
|
||||
groupsByZ[z].push(group);
|
||||
group.z = z;
|
||||
}
|
||||
|
||||
function removeLink(l) {
|
||||
var index = links.indexOf(l);
|
||||
@@ -340,6 +354,7 @@ RED.nodes = (function() {
|
||||
|
||||
var removedNodes = [];
|
||||
var removedLinks = [];
|
||||
var removedGroups = [];
|
||||
var n;
|
||||
var node;
|
||||
for (n=0;n<nodes.length;n++) {
|
||||
@@ -356,11 +371,17 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
removedGroups = groupsByZ[id] || [];
|
||||
removedGroups.forEach(function(g) {
|
||||
delete groups[g.id]
|
||||
})
|
||||
delete groupsByZ[id];
|
||||
|
||||
for (n=0;n<removedNodes.length;n++) {
|
||||
var result = removeNode(removedNodes[n].id);
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
}
|
||||
return {nodes:removedNodes,links:removedLinks};
|
||||
return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
|
||||
}
|
||||
|
||||
function addSubflow(sf, createNewIds) {
|
||||
@@ -398,6 +419,10 @@ RED.nodes = (function() {
|
||||
paletteLabel: function() { return RED.nodes.subflow(sf.id).name },
|
||||
inputLabels: function(i) { return sf.inputLabels?sf.inputLabels[i]:null },
|
||||
outputLabels: function(i) { return sf.outputLabels?sf.outputLabels[i]:null },
|
||||
oneditprepare: function() {
|
||||
RED.subflow.buildEditForm("subflow",this);
|
||||
RED.subflow.buildPropertiesForm(this);
|
||||
},
|
||||
oneditresize: function(size) {
|
||||
// var rows = $(".dialog-form>div:not(.node-input-env-container-row)");
|
||||
var height = size.height;
|
||||
@@ -493,6 +518,9 @@ RED.nodes = (function() {
|
||||
if (n.d === true) {
|
||||
node.d = true;
|
||||
}
|
||||
if (n.g) {
|
||||
node.g = n.g;
|
||||
}
|
||||
if (node.type == "unknown") {
|
||||
for (var p in n._orig) {
|
||||
if (n._orig.hasOwnProperty(p)) {
|
||||
@@ -505,19 +533,33 @@ RED.nodes = (function() {
|
||||
node[d] = n[d];
|
||||
}
|
||||
}
|
||||
if(exportCreds && n.credentials) {
|
||||
if (exportCreds) {
|
||||
var credentialSet = {};
|
||||
node.credentials = {};
|
||||
for (var cred in n._def.credentials) {
|
||||
if (n._def.credentials.hasOwnProperty(cred)) {
|
||||
if (n._def.credentials[cred].type == 'password') {
|
||||
if (/^subflow:/.test(node.type) && n.credentials) {
|
||||
// A subflow instance node can have arbitrary creds
|
||||
for (var sfCred in n.credentials) {
|
||||
if (n.credentials.hasOwnProperty(sfCred)) {
|
||||
if (!n.credentials._ ||
|
||||
n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
|
||||
(n.credentials["has_"+cred] && n.credentials[cred])) {
|
||||
n.credentials["has_"+sfCred] != n.credentials._["has_"+sfCred] ||
|
||||
(n.credentials["has_"+sfCred] && n.credentials[sfCred])) {
|
||||
credentialSet[sfCred] = n.credentials[sfCred];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (n.credentials) {
|
||||
node.credentials = {};
|
||||
// All other nodes have a well-defined list of possible credentials
|
||||
for (var cred in n._def.credentials) {
|
||||
if (n._def.credentials.hasOwnProperty(cred)) {
|
||||
if (n._def.credentials[cred].type == 'password') {
|
||||
if (!n.credentials._ ||
|
||||
n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
|
||||
(n.credentials["has_"+cred] && n.credentials[cred])) {
|
||||
credentialSet[cred] = n.credentials[cred];
|
||||
}
|
||||
} else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) {
|
||||
credentialSet[cred] = n.credentials[cred];
|
||||
}
|
||||
} else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) {
|
||||
credentialSet[cred] = n.credentials[cred];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -526,6 +568,13 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n.type === "group") {
|
||||
node.x = n.x;
|
||||
node.y = n.y;
|
||||
node.w = n.w;
|
||||
node.h = n.h;
|
||||
node.nodes = node.nodes.map(function(n) { return n.id });
|
||||
}
|
||||
if (n._def.category != "config") {
|
||||
node.x = n.x;
|
||||
node.y = n.y;
|
||||
@@ -568,7 +617,7 @@ RED.nodes = (function() {
|
||||
return node;
|
||||
}
|
||||
|
||||
function convertSubflow(n) {
|
||||
function convertSubflow(n, exportCreds) {
|
||||
var node = {};
|
||||
node.id = n.id;
|
||||
node.type = n.type;
|
||||
@@ -578,6 +627,24 @@ RED.nodes = (function() {
|
||||
node.in = [];
|
||||
node.out = [];
|
||||
node.env = n.env;
|
||||
|
||||
if (exportCreds) {
|
||||
var credentialSet = {};
|
||||
// A subflow node can have arbitrary creds
|
||||
for (var sfCred in n.credentials) {
|
||||
if (n.credentials.hasOwnProperty(sfCred)) {
|
||||
if (!n.credentials._ ||
|
||||
n.credentials["has_"+sfCred] != n.credentials._["has_"+sfCred] ||
|
||||
(n.credentials["has_"+sfCred] && n.credentials[sfCred])) {
|
||||
credentialSet[sfCred] = n.credentials[sfCred];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(credentialSet).length > 0) {
|
||||
node.credentials = credentialSet;
|
||||
}
|
||||
}
|
||||
|
||||
node.color = n.color;
|
||||
|
||||
n.in.forEach(function(p) {
|
||||
@@ -633,8 +700,18 @@ RED.nodes = (function() {
|
||||
/**
|
||||
* Converts the current node selection to an exportable JSON Object
|
||||
**/
|
||||
function createExportableNodeSet(set, exportedSubflows, exportedConfigNodes) {
|
||||
function createExportableNodeSet(set, exportedIds, exportedSubflows, exportedConfigNodes) {
|
||||
var nns = [];
|
||||
|
||||
exportedIds = exportedIds || {};
|
||||
set = set.filter(function(n) {
|
||||
if (exportedIds[n.id]) {
|
||||
return false;
|
||||
}
|
||||
exportedIds[n.id] = true;
|
||||
return true;
|
||||
})
|
||||
|
||||
exportedConfigNodes = exportedConfigNodes || {};
|
||||
exportedSubflows = exportedSubflows || {};
|
||||
for (var n=0;n<set.length;n++) {
|
||||
@@ -650,11 +727,11 @@ RED.nodes = (function() {
|
||||
subflowSet.push(n);
|
||||
}
|
||||
});
|
||||
var exportableSubflow = createExportableNodeSet(subflowSet, exportedSubflows, exportedConfigNodes);
|
||||
var exportableSubflow = createExportableNodeSet(subflowSet, exportedIds, exportedSubflows, exportedConfigNodes);
|
||||
nns = exportableSubflow.concat(nns);
|
||||
}
|
||||
}
|
||||
if (node.type != "subflow") {
|
||||
if (node.type !== "subflow") {
|
||||
var convertedNode = RED.nodes.convertNode(node);
|
||||
for (var d in node._def.defaults) {
|
||||
if (node._def.defaults[d].type && node[d] in configNodes) {
|
||||
@@ -671,6 +748,9 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
nns.push(convertedNode);
|
||||
if (node.type === "group") {
|
||||
nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes));
|
||||
}
|
||||
} else {
|
||||
var convertedSubflow = convertSubflow(node);
|
||||
nns.push(convertedSubflow);
|
||||
@@ -693,7 +773,12 @@ RED.nodes = (function() {
|
||||
}
|
||||
for (i in subflows) {
|
||||
if (subflows.hasOwnProperty(i)) {
|
||||
nns.push(convertSubflow(subflows[i]));
|
||||
nns.push(convertSubflow(subflows[i], exportCredentials));
|
||||
}
|
||||
}
|
||||
for (i in groups) {
|
||||
if (groups.hasOwnProperty(i)) {
|
||||
nns.push(convertNode(groups[i]));
|
||||
}
|
||||
}
|
||||
for (i in configNodes) {
|
||||
@@ -822,6 +907,7 @@ RED.nodes = (function() {
|
||||
if (n.type != "workspace" &&
|
||||
n.type != "tab" &&
|
||||
n.type != "subflow" &&
|
||||
n.type != "group" &&
|
||||
!registry.getNodeType(n.type) &&
|
||||
n.type.substring(0,8) != "subflow:" &&
|
||||
unknownTypes.indexOf(n.type)==-1) {
|
||||
@@ -871,6 +957,7 @@ RED.nodes = (function() {
|
||||
var node_map = {};
|
||||
var new_nodes = [];
|
||||
var new_links = [];
|
||||
var new_groups = [];
|
||||
var nid;
|
||||
var def;
|
||||
var configNode;
|
||||
@@ -1038,20 +1125,25 @@ RED.nodes = (function() {
|
||||
y:parseFloat(n.y || 0),
|
||||
z:n.z,
|
||||
type:0,
|
||||
wires:n.wires||[],
|
||||
inputLabels: n.inputLabels,
|
||||
outputLabels: n.outputLabels,
|
||||
icon: n.icon,
|
||||
info: n.info,
|
||||
changed:false,
|
||||
_config:{}
|
||||
};
|
||||
}
|
||||
if (n.type !== "group") {
|
||||
node.wires = n.wires||[];
|
||||
node.inputLabels = n.inputLabels;
|
||||
node.outputLabels = n.outputLabels;
|
||||
node.icon = n.icon;
|
||||
}
|
||||
if (n.hasOwnProperty('l')) {
|
||||
node.l = n.l;
|
||||
}
|
||||
if (n.hasOwnProperty('d')) {
|
||||
node.d = n.d;
|
||||
}
|
||||
if (n.hasOwnProperty('g')) {
|
||||
node.g = n.g;
|
||||
}
|
||||
if (createNewIds) {
|
||||
if (subflow_blacklist[n.z]) {
|
||||
continue;
|
||||
@@ -1088,7 +1180,17 @@ RED.nodes = (function() {
|
||||
}
|
||||
node.type = n.type;
|
||||
node._def = def;
|
||||
if (n.type.substring(0,7) === "subflow") {
|
||||
if (node.type === "group") {
|
||||
node._def = RED.group.def;
|
||||
for (d in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
|
||||
node[d] = n[d];
|
||||
node._config[d] = JSON.stringify(n[d]);
|
||||
}
|
||||
}
|
||||
node._config.x = node.x;
|
||||
node._config.y = node.y;
|
||||
} else if (n.type.substring(0,7) === "subflow") {
|
||||
var parentId = n.type.split(":")[1];
|
||||
var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId);
|
||||
if (createNewIds) {
|
||||
@@ -1109,7 +1211,7 @@ RED.nodes = (function() {
|
||||
defaults: {},
|
||||
label: "unknown: "+n.type,
|
||||
labelStyle: "red-ui-flow-node-label-italic",
|
||||
outputs: n.outputs|| (n.wires && n.wires.length) || 0,
|
||||
outputs: n.outputs||n.wires.length,
|
||||
set: registry.getNodeSet("node-red/unknown")
|
||||
}
|
||||
} else {
|
||||
@@ -1178,13 +1280,19 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
addNode(node);
|
||||
RED.editor.validateNode(node);
|
||||
if (node.type !== "group") {
|
||||
addNode(node);
|
||||
RED.editor.validateNode(node);
|
||||
} else {
|
||||
addGroup(node);
|
||||
}
|
||||
node_map[n.id] = node;
|
||||
// If an 'unknown' config node, it will not have been caught by the
|
||||
// proper config node handling, so needs adding to new_nodes here
|
||||
if (node.type === "unknown" || node._def.category !== "config") {
|
||||
new_nodes.push(node);
|
||||
} else if (node.type === "group") {
|
||||
new_groups.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1219,6 +1327,11 @@ RED.nodes = (function() {
|
||||
}
|
||||
delete n.wires;
|
||||
}
|
||||
if (n.g && node_map[n.g]) {
|
||||
n.g = node_map[n.g].id;
|
||||
} else {
|
||||
delete n.g
|
||||
}
|
||||
for (var d3 in n._def.defaults) {
|
||||
if (n._def.defaults.hasOwnProperty(d3)) {
|
||||
if (n._def.defaults[d3].type && node_map[n[d3]]) {
|
||||
@@ -1287,9 +1400,20 @@ RED.nodes = (function() {
|
||||
delete n.status.wires;
|
||||
}
|
||||
}
|
||||
for (i=0;i<new_groups.length;i++) {
|
||||
n = new_groups[i];
|
||||
if (n.g && node_map[n.g]) {
|
||||
n.g = node_map[n.g].id;
|
||||
} else {
|
||||
delete n.g;
|
||||
}
|
||||
n.nodes = n.nodes.map(function(id) {
|
||||
return node_map[id];
|
||||
})
|
||||
}
|
||||
|
||||
RED.workspaces.refresh();
|
||||
return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace];
|
||||
return [new_nodes,new_links,new_groups,new_workspaces,new_subflows,missingWorkspace];
|
||||
}
|
||||
|
||||
// TODO: supports filter.z|type
|
||||
@@ -1380,6 +1504,9 @@ RED.nodes = (function() {
|
||||
nodeTabMap = {};
|
||||
configNodes = {};
|
||||
workspacesOrder = [];
|
||||
groups = {};
|
||||
groupsByZ = {};
|
||||
|
||||
var subflowIds = Object.keys(subflows);
|
||||
subflowIds.forEach(function(id) {
|
||||
RED.subflow.removeSubflow(id)
|
||||
@@ -1408,6 +1535,27 @@ RED.nodes = (function() {
|
||||
// var loadedFlowVersion = null;
|
||||
}
|
||||
|
||||
function addGroup(group) {
|
||||
groupsByZ[group.z] = groupsByZ[group.z] || [];
|
||||
groupsByZ[group.z].push(group);
|
||||
groups[group.id] = group;
|
||||
}
|
||||
function removeGroup(group) {
|
||||
var i = groupsByZ[group.z].indexOf(group);
|
||||
groupsByZ[group.z].splice(i,1);
|
||||
|
||||
if (group.g) {
|
||||
if (groups[group.g]) {
|
||||
var index = groups[group.g].nodes.indexOf(group);
|
||||
groups[group.g].nodes.splice(index,1);
|
||||
}
|
||||
}
|
||||
RED.group.markDirty(group);
|
||||
|
||||
delete groups[group.id];
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
RED.events.on("registry:node-type-added",function(type) {
|
||||
@@ -1451,8 +1599,9 @@ RED.nodes = (function() {
|
||||
});
|
||||
removeLinks.forEach(removeLink);
|
||||
|
||||
|
||||
RED.view.redraw(true);
|
||||
// Force the redraw to be synchronous so the view updates
|
||||
// *now* and removes the unknown node
|
||||
RED.view.redraw(true, true);
|
||||
var result = importNodes(reimportList,false);
|
||||
var newNodeMap = {};
|
||||
result[0].forEach(function(n) {
|
||||
@@ -1506,6 +1655,11 @@ RED.nodes = (function() {
|
||||
subflow: getSubflow,
|
||||
subflowContains: subflowContains,
|
||||
|
||||
addGroup: addGroup,
|
||||
removeGroup: removeGroup,
|
||||
group: function(id) { return groups[id] },
|
||||
groups: function(z) { return groupsByZ[z]||[] },
|
||||
|
||||
eachNode: function(cb) {
|
||||
for (var n=0;n<nodes.length;n++) {
|
||||
if (cb(nodes[n]) === false) {
|
||||
|
||||
@@ -472,6 +472,14 @@ var RED = (function() {
|
||||
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:"core:create-subflow"},
|
||||
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:"core:convert-to-subflow"},
|
||||
]});
|
||||
menuOptions.push({id:"menu-item-group",label:RED._("menu.label.groups"), options: [
|
||||
{id:"menu-item-group-group",label:RED._("menu.label.groupSelection"),disabled:true,onselect:"core:group-selection"},
|
||||
{id:"menu-item-group-ungroup",label:RED._("menu.label.ungroupSelection"),disabled:true,onselect:"core:ungroup-selection"},
|
||||
null,
|
||||
{id:"menu-item-group-merge",label:RED._("menu.label.groupMergeSelection"),disabled:true,onselect:"core:merge-selection-to-group"},
|
||||
{id:"menu-item-group-remove",label:RED._("menu.label.groupRemoveSelection"),disabled:true,onselect:"core:remove-selection-from-group"}
|
||||
]});
|
||||
|
||||
menuOptions.push(null);
|
||||
if (RED.settings.theme('palette.editable') !== false) {
|
||||
menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"});
|
||||
@@ -524,6 +532,7 @@ var RED = (function() {
|
||||
}
|
||||
|
||||
RED.subflow.init();
|
||||
RED.group.init();
|
||||
RED.clipboard.init();
|
||||
RED.search.init();
|
||||
RED.actionList.init();
|
||||
|
||||
@@ -583,6 +583,7 @@ RED.clipboard = (function() {
|
||||
nodes = [];
|
||||
selection.forEach(function(n) {
|
||||
nodes.push(n);
|
||||
nodes = nodes.concat(RED.nodes.groups(n.id));
|
||||
nodes = nodes.concat(RED.nodes.filterNodes({z:n.id}));
|
||||
});
|
||||
} else {
|
||||
@@ -592,7 +593,8 @@ RED.clipboard = (function() {
|
||||
nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'}));
|
||||
} else if (type === 'red-ui-clipboard-dialog-export-rng-flow') {
|
||||
var activeWorkspace = RED.workspaces.active();
|
||||
nodes = RED.nodes.filterNodes({z:activeWorkspace});
|
||||
nodes = RED.nodes.groups(activeWorkspace);
|
||||
nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace}));
|
||||
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
|
||||
nodes.unshift(parentNode);
|
||||
nodes = RED.nodes.createExportableNodeSet(nodes);
|
||||
|
||||
223
packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js
vendored
Normal file
223
packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
RED.colorPicker = (function() {
|
||||
|
||||
function getDarkerColor(c) {
|
||||
var r,g,b;
|
||||
if (/^#[a-f0-9]{6}$/i.test(c)) {
|
||||
r = parseInt(c.substring(1, 3), 16);
|
||||
g = parseInt(c.substring(3, 5), 16);
|
||||
b = parseInt(c.substring(5, 7), 16);
|
||||
} else if (/^#[a-f0-9]{3}$/i.test(c)) {
|
||||
r = parseInt(c.substring(1, 2)+c.substring(1, 2), 16);
|
||||
g = parseInt(c.substring(2, 3)+c.substring(2, 3), 16);
|
||||
b = parseInt(c.substring(3, 4)+c.substring(3, 4), 16);
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
var l = 0.3 * r/255 + 0.59 * g/255 + 0.11 * b/255 ;
|
||||
r = Math.max(0,r-50);
|
||||
g = Math.max(0,g-50);
|
||||
b = Math.max(0,b-50);
|
||||
return '#'+((r<<16) + (g<<8) + b).toString(16).padStart(6,'0')
|
||||
}
|
||||
|
||||
function create(options) {
|
||||
var color = options.value;
|
||||
var id = options.id;
|
||||
var colorPalette = options.palette || [];
|
||||
var width = options.cellWidth || 30;
|
||||
var height = options.cellHeight || 30;
|
||||
var margin = options.cellMargin || 2;
|
||||
var perRow = options.cellPerRow || 6;
|
||||
|
||||
var container = $("<div>",{style:"display:inline-block"});
|
||||
var colorHiddenInput = $("<input/>", { id: id, type: "hidden", value: color }).appendTo(container);
|
||||
var opacityHiddenInput = $("<input/>", { id: id+"-opacity", type: "hidden", value: options.hasOwnProperty('opacity')?options.opacity:"1" }).appendTo(container);
|
||||
|
||||
var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container);
|
||||
$('<i class="fa fa-caret-down"></i>').appendTo(colorButton);
|
||||
|
||||
var colorDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton);
|
||||
$('<div>',{class:"red-ui-color-picker-cell-none"}).appendTo(colorDispContainer);
|
||||
var colorDisp = $('<div>',{class:"red-ui-color-picker-swatch"}).appendTo(colorDispContainer);
|
||||
|
||||
|
||||
var refreshDisplay = function(color) {
|
||||
if (color === "none") {
|
||||
colorDisp.addClass('red-ui-color-picker-cell-none').css({
|
||||
"background-color": "",
|
||||
opacity: 1
|
||||
});
|
||||
colorDispContainer.css({
|
||||
"border-color":""
|
||||
})
|
||||
} else {
|
||||
var opacity = parseFloat(opacityHiddenInput.val())
|
||||
colorDisp.removeClass('red-ui-color-picker-cell-none').css({
|
||||
"background-color": color,
|
||||
"opacity": opacity
|
||||
});
|
||||
var border = getDarkerColor(color);
|
||||
if (border[0] === '#') {
|
||||
border += Math.round(255*Math.floor(opacity*100)/100).toString(16);
|
||||
} else {
|
||||
border = "";
|
||||
}
|
||||
|
||||
colorDispContainer.css({
|
||||
"border-color": border
|
||||
})
|
||||
}
|
||||
if (options.hasOwnProperty('opacity')) {
|
||||
$(".red-ui-color-picker-opacity-slider-overlay").css({
|
||||
"background-image": "linear-gradient(90deg, transparent 0%, "+color+" 100%)"
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
colorButton.on("click", function (e) {
|
||||
var numColors = colorPalette.length;
|
||||
|
||||
var picker = $("<div/>", {
|
||||
class: "red-ui-color-picker"
|
||||
}).css({
|
||||
width: ((width+margin+margin)*perRow)+"px",
|
||||
height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px"
|
||||
});
|
||||
var count = 0;
|
||||
var row = null;
|
||||
row = $("<div/>").appendTo(picker);
|
||||
|
||||
var colorInput = $('<input>',{
|
||||
type:"text",
|
||||
value:colorHiddenInput.val()
|
||||
}).appendTo(row);
|
||||
|
||||
colorInput.on("change", function (e) {
|
||||
var color = colorInput.val();
|
||||
colorHiddenInput.val(color).trigger('change');
|
||||
refreshDisplay(color);
|
||||
});
|
||||
// if (options.hasOwnProperty('opacity')) {
|
||||
// var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider"
|
||||
// }
|
||||
|
||||
if (options.none) {
|
||||
row = $("<div/>").appendTo(picker);
|
||||
var button = $("<button/>", {
|
||||
class:"red-ui-color-picker-cell red-ui-color-picker-cell-none"
|
||||
}).css({
|
||||
width: width+"px",
|
||||
height: height+"px",
|
||||
margin: margin+"px"
|
||||
}).appendTo(row);
|
||||
button.on("click", function (e) {
|
||||
e.preventDefault();
|
||||
colorInput.val("none");
|
||||
colorInput.trigger("change");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
colorPalette.forEach(function (col) {
|
||||
if ((count % perRow) == 0) {
|
||||
row = $("<div/>").appendTo(picker);
|
||||
}
|
||||
var button = $("<button/>", {
|
||||
class:"red-ui-color-picker-cell"
|
||||
}).css({
|
||||
width: width+"px",
|
||||
height: height+"px",
|
||||
margin: margin+"px",
|
||||
backgroundColor: col,
|
||||
"border-color": getDarkerColor(col)
|
||||
}).appendTo(row);
|
||||
button.on("click", function (e) {
|
||||
e.preventDefault();
|
||||
// colorPanel.hide();
|
||||
colorInput.val(col);
|
||||
colorInput.trigger("change");
|
||||
});
|
||||
count++;
|
||||
});
|
||||
if (options.none || options.hasOwnProperty('opacity')) {
|
||||
row = $("<div/>").appendTo(picker);
|
||||
// if (options.none) {
|
||||
// var button = $("<button/>", {
|
||||
// class:"red-ui-color-picker-cell red-ui-color-picker-cell-none"
|
||||
// }).css({
|
||||
// width: width+"px",
|
||||
// height: height+"px",
|
||||
// margin: margin+"px"
|
||||
// }).appendTo(row);
|
||||
// button.on("click", function (e) {
|
||||
// e.preventDefault();
|
||||
// colorPanel.hide();
|
||||
// selector.val("none");
|
||||
// selector.trigger("change");
|
||||
// });
|
||||
// }
|
||||
if (options.hasOwnProperty('opacity')) {
|
||||
var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider"}).appendTo(row);
|
||||
sliderContainer.on("mousedown", function(evt) {
|
||||
if (evt.target === sliderHandle[0]) {
|
||||
return;
|
||||
}
|
||||
var v = evt.offsetX/sliderContainer.width();
|
||||
sliderHandle.css({
|
||||
left: ( v*(sliderContainer.width() - sliderHandle.outerWidth()))+"px"
|
||||
});
|
||||
v = Math.floor(100*v)
|
||||
opacityHiddenInput.val(v/100)
|
||||
opacityLabel.text(v+"%");
|
||||
refreshDisplay(colorHiddenInput.val());
|
||||
})
|
||||
$("<div>",{class:"red-ui-color-picker-opacity-slider-overlay"}).appendTo(sliderContainer);
|
||||
var sliderHandle = $("<div>",{class:"red-ui-color-picker-opacity-slider-handle red-ui-button red-ui-button-small"}).appendTo(sliderContainer).draggable({
|
||||
containment: "parent",
|
||||
axis: "x",
|
||||
drag: function( event, ui ) {
|
||||
var v = Math.max(0,ui.position.left/($(this).parent().width()-$(this).outerWidth()));
|
||||
// Odd bug that if it is loaded with a non-0 value, the first time
|
||||
// it is dragged it ranges -1 to 99. But every other time, its 0 to 100.
|
||||
// The Math.max above makes the -1 disappear. The follow hack ensures
|
||||
// it always maxes out at a 100, at the cost of not allowing 99% exactly.
|
||||
v = Math.floor(100*v)
|
||||
if ( v === 99 ) {
|
||||
v = 100;
|
||||
}
|
||||
// console.log("uip",ui.position.left);
|
||||
opacityHiddenInput.val(v/100)
|
||||
opacityLabel.text(v+"%");
|
||||
refreshDisplay(colorHiddenInput.val());
|
||||
}
|
||||
});
|
||||
var opacityLabel = $('<small></small>').appendTo(row);
|
||||
setTimeout(function() {
|
||||
sliderHandle.css({
|
||||
left: (parseFloat(opacityHiddenInput.val())*(sliderContainer.width() - sliderHandle.outerWidth()))+"px"
|
||||
})
|
||||
opacityLabel.text(Math.floor(opacityHiddenInput.val()*100)+"%");
|
||||
},50);
|
||||
}
|
||||
}
|
||||
|
||||
var colorPanel = RED.popover.panel(picker);
|
||||
setTimeout(function() {
|
||||
refreshDisplay(colorHiddenInput.val())
|
||||
},50);
|
||||
colorPanel.show({
|
||||
target: colorButton
|
||||
})
|
||||
});
|
||||
setTimeout(function() {
|
||||
refreshDisplay(colorHiddenInput.val())
|
||||
},50);
|
||||
return container;
|
||||
}
|
||||
|
||||
return {
|
||||
create: create
|
||||
}
|
||||
})();
|
||||
@@ -164,6 +164,84 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
cred:{
|
||||
value:"cred",
|
||||
label:"credential",
|
||||
icon:"fa fa-lock",
|
||||
inputType: "password",
|
||||
valueLabel: function(container,value) {
|
||||
var that = this;
|
||||
container.css("pointer-events","none");
|
||||
this.elementDiv.hide();
|
||||
var buttons = $('<div>').css({
|
||||
position: "absolute",
|
||||
right:"6px",
|
||||
top: "6px",
|
||||
"pointer-events":"all"
|
||||
}).appendTo(container);
|
||||
var eyeButton = $('<button type="button" class="red-ui-button red-ui-button-small"></button>').css({
|
||||
width:"20px"
|
||||
}).appendTo(buttons).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var currentType = that.input.attr("type");
|
||||
if (currentType === "text") {
|
||||
that.input.attr("type","password");
|
||||
eyeCon.removeClass("fa-eye-slash").addClass("fa-eye");
|
||||
setTimeout(function() {
|
||||
that.input.focus();
|
||||
},50);
|
||||
} else {
|
||||
that.input.attr("type","text");
|
||||
eyeCon.removeClass("fa-eye").addClass("fa-eye-slash");
|
||||
setTimeout(function() {
|
||||
that.input.focus();
|
||||
},50);
|
||||
}
|
||||
}).hide();
|
||||
var eyeCon = $('<i class="fa fa-eye"></i>').css("margin-left","-1px").appendTo(eyeButton);
|
||||
|
||||
if (value === "__PWRD__") {
|
||||
var innerContainer = $('<div><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i></div>').css({
|
||||
padding:"6px 6px",
|
||||
borderRadius:"4px"
|
||||
}).addClass("red-ui-typedInput-value-label-inactive").appendTo(container);
|
||||
var editButton = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-pencil"></i></button>').appendTo(buttons).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
innerContainer.hide();
|
||||
container.css("background","none");
|
||||
container.css("pointer-events","none");
|
||||
that.input.val("");
|
||||
that.element.val("");
|
||||
that.elementDiv.show();
|
||||
editButton.hide();
|
||||
cancelButton.show();
|
||||
eyeButton.show();
|
||||
setTimeout(function() {
|
||||
that.input.focus();
|
||||
},50);
|
||||
});
|
||||
var cancelButton = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-times"></i></button>').css("margin-left","3px").appendTo(buttons).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
innerContainer.show();
|
||||
container.css("background","");
|
||||
that.input.val("__PWRD__");
|
||||
that.element.val("__PWRD__");
|
||||
that.elementDiv.hide();
|
||||
editButton.show();
|
||||
cancelButton.hide();
|
||||
eyeButton.hide();
|
||||
that.input.attr("type","password");
|
||||
eyeCon.removeClass("fa-eye-slash").addClass("fa-eye");
|
||||
|
||||
}).hide();
|
||||
} else {
|
||||
container.css("background","none");
|
||||
container.css("pointer-events","none");
|
||||
this.elementDiv.show();
|
||||
eyeButton.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
var nlsd = false;
|
||||
@@ -220,6 +298,8 @@
|
||||
that.input.attr(d,m);
|
||||
});
|
||||
|
||||
this.defaultInputType = this.input.attr('type');
|
||||
|
||||
this.uiSelect.addClass("red-ui-typedInput-container");
|
||||
|
||||
this.element.attr('type','hidden');
|
||||
@@ -488,6 +568,56 @@
|
||||
done(labelWidth);
|
||||
}
|
||||
},
|
||||
_resize: function() {
|
||||
var that = this;
|
||||
if (this.uiWidth !== null) {
|
||||
this.uiSelect.width(this.uiWidth);
|
||||
}
|
||||
var type = this.typeMap[this.propertyType];
|
||||
if (type && type.hasValue === false) {
|
||||
this.selectTrigger.addClass("red-ui-typedInput-full-width");
|
||||
} else {
|
||||
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
|
||||
this._getLabelWidth(this.selectTrigger, function(labelWidth) {
|
||||
that.elementDiv.css('left',labelWidth+"px");
|
||||
that.valueLabelContainer.css('left',labelWidth+"px");
|
||||
if (that.optionExpandButton.shown) {
|
||||
that.elementDiv.css('right',"22px");
|
||||
that.valueLabelContainer.css('right',"22px");
|
||||
} else {
|
||||
that.elementDiv.css('right','0');
|
||||
that.valueLabelContainer.css('right','0');
|
||||
that.input.css({
|
||||
'border-top-right-radius': '4px',
|
||||
'border-bottom-right-radius': '4px'
|
||||
});
|
||||
}
|
||||
if (that.optionSelectTrigger) {
|
||||
if (type && type.options && type.hasValue === true) {
|
||||
that.optionSelectLabel.css({'left':'auto'})
|
||||
that._getLabelWidth(that.optionSelectLabel, function(lw) {
|
||||
that.optionSelectTrigger.css({'width':(23+lw)+"px"});
|
||||
that.elementDiv.css('right',(23+lw)+"px");
|
||||
that.input.css({
|
||||
'border-top-right-radius': 0,
|
||||
'border-bottom-right-radius': 0
|
||||
});
|
||||
});
|
||||
} else {
|
||||
that.optionSelectLabel.css({'left':'0'})
|
||||
that.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'});
|
||||
if (!that.optionExpandButton.shown) {
|
||||
that.elementDiv.css({'right':0});
|
||||
that.input.css({
|
||||
'border-top-right-radius': '4px',
|
||||
'border-bottom-right-radius': '4px'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
_updateOptionSelectLabel: function(o) {
|
||||
var opt = this.typeMap[this.propertyType];
|
||||
this.optionSelectLabel.empty();
|
||||
@@ -515,6 +645,7 @@
|
||||
}
|
||||
if (opt.hasValue) {
|
||||
this.optionValue = o.value;
|
||||
this._resize();
|
||||
this.input.trigger('change',this.propertyType,this.value());
|
||||
}
|
||||
} else {
|
||||
@@ -554,12 +685,11 @@
|
||||
this.propertyType = null;
|
||||
this.type(currentType);
|
||||
}
|
||||
setTimeout(function() {that._resize();},0);
|
||||
},
|
||||
width: function(desiredWidth) {
|
||||
this.uiWidth = desiredWidth;
|
||||
if (this.uiWidth !== null) {
|
||||
this.uiSelect.width(this.uiWidth);
|
||||
}
|
||||
this._resize();
|
||||
},
|
||||
value: function(value) {
|
||||
var that = this;
|
||||
@@ -630,23 +760,19 @@
|
||||
}
|
||||
else if (opt.icon.indexOf("/") !== -1) {
|
||||
image = new Image();
|
||||
image.onload = function() { that._resize(); }
|
||||
image.onerror = function() { that._resize(); }
|
||||
image.name = opt.icon;
|
||||
image.src = mapDeprecatedIcon(opt.icon);
|
||||
$('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel);
|
||||
}
|
||||
else {
|
||||
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon}).prependTo(this.selectLabel);
|
||||
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon,style:"min-width: 13px; margin-right: 4px;"}).prependTo(this.selectLabel);
|
||||
}
|
||||
}
|
||||
if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) {
|
||||
this.selectLabel.text(opt.label);
|
||||
}
|
||||
if (opt.hasValue === false) {
|
||||
this.selectTrigger.addClass("red-ui-typedInput-full-width");
|
||||
} else {
|
||||
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
|
||||
}
|
||||
|
||||
if (this.optionMenu) {
|
||||
this.optionMenu.remove();
|
||||
this.optionMenu = null;
|
||||
@@ -657,13 +783,11 @@
|
||||
this.optionExpandButton.shown = false;
|
||||
}
|
||||
if (this.optionSelectTrigger) {
|
||||
this.optionSelectTrigger.css({"display":"inline-flex"});
|
||||
this.optionSelectTrigger.show();
|
||||
if (!opt.hasValue) {
|
||||
this.optionSelectTrigger.css({"flex-grow":1})
|
||||
this.elementDiv.hide();
|
||||
this.valueLabelContainer.hide();
|
||||
} else {
|
||||
this.optionSelectTrigger.css({"flex-grow":0})
|
||||
this.elementDiv.show();
|
||||
this.valueLabelContainer.hide();
|
||||
}
|
||||
@@ -778,6 +902,11 @@
|
||||
if (this.optionSelectTrigger) {
|
||||
this.optionSelectTrigger.hide();
|
||||
}
|
||||
if (opt.inputType) {
|
||||
this.input.attr('type',opt.inputType)
|
||||
} else {
|
||||
this.input.attr('type',this.defaultInputType)
|
||||
}
|
||||
if (opt.hasValue === false) {
|
||||
this.oldValue = this.input.val();
|
||||
this.input.val("");
|
||||
@@ -786,8 +915,8 @@
|
||||
} else if (opt.valueLabel) {
|
||||
this.valueLabelContainer.show();
|
||||
this.valueLabelContainer.empty();
|
||||
opt.valueLabel.call(this,this.valueLabelContainer,this.input.val());
|
||||
this.elementDiv.hide();
|
||||
opt.valueLabel.call(this,this.valueLabelContainer,this.input.val());
|
||||
} else {
|
||||
if (this.oldValue !== undefined) {
|
||||
this.input.val(this.oldValue);
|
||||
@@ -837,6 +966,9 @@
|
||||
this._trigger("typechange",null,this.propertyType);
|
||||
this.input.trigger('change',this.propertyType,this.value());
|
||||
}
|
||||
if (!image) {
|
||||
this._resize();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -863,6 +995,7 @@
|
||||
},
|
||||
show: function() {
|
||||
this.uiSelect.show();
|
||||
this._resize();
|
||||
},
|
||||
hide: function() {
|
||||
this.uiSelect.hide();
|
||||
|
||||
@@ -490,8 +490,7 @@ RED.editor = (function() {
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
if (definition.credentials) {
|
||||
if (definition.credentials || /^subflow:/.test(definition.type)) {
|
||||
if (node.credentials) {
|
||||
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
|
||||
completePrepare();
|
||||
@@ -499,7 +498,9 @@ RED.editor = (function() {
|
||||
$.getJSON(getCredentialsURL(node.type, node.id), function (data) {
|
||||
node.credentials = data;
|
||||
node.credentials._ = $.extend(true,{},data);
|
||||
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
|
||||
if (!/^subflow:/.test(definition.type)) {
|
||||
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
|
||||
}
|
||||
completePrepare();
|
||||
});
|
||||
}
|
||||
@@ -513,7 +514,9 @@ RED.editor = (function() {
|
||||
for (var i=editStack.length-1;i<editStack.length;i++) {
|
||||
var node = editStack[i];
|
||||
label = node.type;
|
||||
if (node.type === '_expression') {
|
||||
if (node.type === 'group') {
|
||||
label = RED._("group.editGroup",{name:RED.utils.sanitize(node.name||node.id)});
|
||||
} else if (node.type === '_expression') {
|
||||
label = RED._("expressionEditor.title");
|
||||
} else if (node.type === '_js') {
|
||||
label = RED._("jsEditor.title");
|
||||
@@ -576,8 +579,11 @@ RED.editor = (function() {
|
||||
$(this).attr("data-i18n",keys.join(";"));
|
||||
});
|
||||
|
||||
if (type === "subflow-template" || type === "subflow") {
|
||||
RED.subflow.buildEditForm(dialogForm,type,node);
|
||||
if (type === "subflow-template") {
|
||||
// This is the 'edit properties' dialog for a subflow template
|
||||
// TODO: this needs to happen later in the dialog open sequence
|
||||
// so that credentials can be loaded prior to building the form
|
||||
RED.subflow.buildEditForm(type,node);
|
||||
}
|
||||
|
||||
// Add dummy fields to prevent 'Enter' submitting the form in some
|
||||
@@ -819,99 +825,6 @@ RED.editor = (function() {
|
||||
searchInput.trigger("focus");
|
||||
}
|
||||
|
||||
function createColorPicker(colorRow, color) {
|
||||
|
||||
var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(colorRow);
|
||||
$('<i class="fa fa-caret-down"></i>').appendTo(colorButton);
|
||||
|
||||
var colorDisp = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton);
|
||||
|
||||
var selector = $("<input/>", {
|
||||
id: "red-ui-editor-node-color",
|
||||
type: "text",
|
||||
value: color
|
||||
}).css({
|
||||
marginLeft: "10px",
|
||||
width: "150px",
|
||||
}).appendTo(colorRow);
|
||||
|
||||
selector.on("change", function (e) {
|
||||
var color = selector.val();
|
||||
$(".red-ui-editor-node-appearance-button .red-ui-search-result-node").css({
|
||||
"background-color": color
|
||||
});
|
||||
});
|
||||
selector.trigger("change");
|
||||
colorButton.on("click", function (e) {
|
||||
var recommendedColors = [
|
||||
"#DDAA99",
|
||||
"#3FADB5", "#87A980", "#A6BBCF",
|
||||
"#AAAA66", "#C0C0C0", "#C0DEED",
|
||||
"#C7E9C0", "#D7D7A0", "#D8BFD8",
|
||||
"#DAC4B4", "#DEB887", "#DEBD5C",
|
||||
"#E2D96E", "#E6E0F8", "#E7E7AE",
|
||||
"#E9967A", "#F3B567", "#FDD0A2",
|
||||
"#FDF0C2", "#FFAAAA", "#FFCC66",
|
||||
"#FFF0F0", "#FFFFFF"
|
||||
].map(function(c) {
|
||||
var r = parseInt(c.substring(1, 3), 16) / 255;
|
||||
var g = parseInt(c.substring(3, 5), 16) / 255;
|
||||
var b = parseInt(c.substring(5, 7), 16) / 255;
|
||||
return {
|
||||
hex: c,
|
||||
r: r,
|
||||
g: g,
|
||||
b: b,
|
||||
l: 0.3 * r + 0.59 * g + 0.11 * b
|
||||
}
|
||||
});
|
||||
// Sort by luminosity.
|
||||
recommendedColors.sort(function (a, b) {
|
||||
return a.l - b.l;
|
||||
});
|
||||
|
||||
var numColors = recommendedColors.length;
|
||||
var width = 30;
|
||||
var height = 30;
|
||||
var margin = 2;
|
||||
var perRow = 6;
|
||||
var picker = $("<div/>", {
|
||||
class: "red-ui-color-picker"
|
||||
}).css({
|
||||
width: ((width+margin+margin)*perRow)+"px",
|
||||
height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px"
|
||||
});
|
||||
var count = 0;
|
||||
var row = null;
|
||||
recommendedColors.forEach(function (col) {
|
||||
if ((count % perRow) == 0) {
|
||||
row = $("<div/>").appendTo(picker);
|
||||
}
|
||||
var button = $("<button/>", {
|
||||
}).css({
|
||||
width: width+"px",
|
||||
height: height+"px",
|
||||
margin: margin+"px",
|
||||
backgroundColor: col.hex,
|
||||
"border-style": "solid",
|
||||
"border-width": "1px",
|
||||
"border-color": col.luma<0.92?col.hex:'#ccc'
|
||||
}).appendTo(row);
|
||||
button.on("click", function (e) {
|
||||
e.preventDefault();
|
||||
colorPanel.hide();
|
||||
selector.val(col.hex);
|
||||
selector.trigger("change");
|
||||
});
|
||||
count++;
|
||||
});
|
||||
var colorPanel = RED.popover.panel(picker);
|
||||
colorPanel.show({
|
||||
target: colorButton
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function buildAppearanceForm(container,node) {
|
||||
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
|
||||
|
||||
@@ -997,7 +910,30 @@ RED.editor = (function() {
|
||||
class: "form-row"
|
||||
}).appendTo(dialogForm);
|
||||
$("<label/>").text(RED._("editor.color")).appendTo(colorRow);
|
||||
createColorPicker(colorRow, color);
|
||||
|
||||
var recommendedColors = [
|
||||
"#DDAA99",
|
||||
"#3FADB5", "#87A980", "#A6BBCF",
|
||||
"#AAAA66", "#C0C0C0", "#C0DEED",
|
||||
"#C7E9C0", "#D7D7A0", "#D8BFD8",
|
||||
"#DAC4B4", "#DEB887", "#DEBD5C",
|
||||
"#E2D96E", "#E6E0F8", "#E7E7AE",
|
||||
"#E9967A", "#F3B567", "#FDD0A2",
|
||||
"#FDF0C2", "#FFAAAA", "#FFCC66",
|
||||
"#FFF0F0", "#FFFFFF"
|
||||
]
|
||||
|
||||
RED.colorPicker.create({
|
||||
id: "red-ui-editor-node-color",
|
||||
value: color,
|
||||
palette: recommendedColors,
|
||||
sortPalette: function (a, b) {return a.l - b.l;}
|
||||
}).appendTo(colorRow);
|
||||
|
||||
$("#red-ui-editor-node-color").on('change', function(ev) {
|
||||
// Horribly out of scope...
|
||||
nodeDiv.css('backgroundColor',$(this).val());
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1471,6 +1407,19 @@ RED.editor = (function() {
|
||||
if (type === "subflow") {
|
||||
var old_env = editing_node.env;
|
||||
var new_env = RED.subflow.exportSubflowInstanceEnv(editing_node);
|
||||
if (new_env && new_env.length > 0) {
|
||||
new_env.forEach(function(prop) {
|
||||
if (prop.type === "cred") {
|
||||
editing_node.credentials = editing_node.credentials || {_:{}};
|
||||
editing_node.credentials[prop.name] = prop.value;
|
||||
editing_node.credentials['has_'+prop.name] = (prop.value !== "");
|
||||
if (prop.value !== '__PWRD__') {
|
||||
changed = true;
|
||||
}
|
||||
delete prop.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!isSameObj(old_env, new_env)) {
|
||||
editing_node.env = new_env;
|
||||
changes.env = editing_node.env;
|
||||
@@ -1599,12 +1548,13 @@ RED.editor = (function() {
|
||||
id: "editor-subflow-envProperties",
|
||||
label: RED._("editor-tab.envProperties"),
|
||||
name: RED._("editor-tab.envProperties"),
|
||||
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||
content: $('<div>', {id:"editor-subflow-envProperties-content",class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||
iconClass: "fa fa-list"
|
||||
};
|
||||
|
||||
RED.subflow.buildPropertiesForm(subflowPropertiesTab.content,node);
|
||||
editorTabs.addTab(subflowPropertiesTab);
|
||||
// This tab is populated by the oneditprepare function of this
|
||||
// subflow. That ensures it is done *after* any credentials
|
||||
// have been loaded for the instance.
|
||||
}
|
||||
|
||||
if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
|
||||
@@ -2252,6 +2202,21 @@ RED.editor = (function() {
|
||||
|
||||
var old_env = editing_node.env;
|
||||
var new_env = RED.subflow.exportSubflowTemplateEnv($("#node-input-env-container").editableList("items"));
|
||||
|
||||
if (new_env && new_env.length > 0) {
|
||||
new_env.forEach(function(prop) {
|
||||
if (prop.type === "cred") {
|
||||
editing_node.credentials = editing_node.credentials || {_:{}};
|
||||
editing_node.credentials[prop.name] = prop.value;
|
||||
editing_node.credentials['has_'+prop.name] = (prop.value !== "");
|
||||
if (prop.value !== '__PWRD__') {
|
||||
changed = true;
|
||||
}
|
||||
delete prop.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!isSameObj(old_env, new_env)) {
|
||||
editing_node.env = new_env;
|
||||
changes.env = editing_node.env;
|
||||
@@ -2311,7 +2276,7 @@ RED.editor = (function() {
|
||||
$("#node-input-env-container").editableList('height',height-95);
|
||||
}
|
||||
},
|
||||
open: function(tray) {
|
||||
open: function(tray, done) {
|
||||
var trayFooter = tray.find(".red-ui-tray-footer");
|
||||
var trayFooterLeft = $("<div/>", {
|
||||
class: "red-ui-tray-footer-left"
|
||||
@@ -2362,7 +2327,6 @@ RED.editor = (function() {
|
||||
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||
iconClass: "fa fa-cog"
|
||||
};
|
||||
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
|
||||
editorTabs.addTab(nodePropertiesTab);
|
||||
|
||||
var descriptionTab = {
|
||||
@@ -2391,11 +2355,19 @@ RED.editor = (function() {
|
||||
buildAppearanceForm(appearanceTab.content,editing_node);
|
||||
editorTabs.addTab(appearanceTab);
|
||||
|
||||
$("#subflow-input-name").val(subflow.name);
|
||||
RED.text.bidi.prepareInput($("#subflow-input-name"));
|
||||
|
||||
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
|
||||
trayBody.i18n();
|
||||
finishedBuilding = true;
|
||||
|
||||
$.getJSON(getCredentialsURL("subflow", subflow.id), function (data) {
|
||||
subflow.credentials = data;
|
||||
subflow.credentials._ = $.extend(true,{},data);
|
||||
|
||||
$("#subflow-input-name").val(subflow.name);
|
||||
RED.text.bidi.prepareInput($("#subflow-input-name"));
|
||||
|
||||
finishedBuilding = true;
|
||||
done();
|
||||
});
|
||||
},
|
||||
close: function() {
|
||||
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
|
||||
@@ -2414,6 +2386,249 @@ RED.editor = (function() {
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
|
||||
function showEditGroupDialog(group) {
|
||||
var editing_node = group;
|
||||
editStack.push(group);
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var nodeInfoEditor;
|
||||
var finishedBuilding = false;
|
||||
var trayOptions = {
|
||||
title: getEditStackTitle(),
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
class: "primary",
|
||||
text: RED._("common.label.done"),
|
||||
click: function() {
|
||||
var changes = {};
|
||||
var changed = false;
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
var d;
|
||||
var outputMap;
|
||||
|
||||
if (editing_node._def.oneditsave) {
|
||||
var oldValues = {};
|
||||
for (d in editing_node._def.defaults) {
|
||||
if (editing_node._def.defaults.hasOwnProperty(d)) {
|
||||
if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
|
||||
oldValues[d] = editing_node[d];
|
||||
} else {
|
||||
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
var rc = editing_node._def.oneditsave.call(editing_node);
|
||||
if (rc === true) {
|
||||
changed = true;
|
||||
}
|
||||
} catch(err) {
|
||||
console.log("oneditsave",editing_node.id,editing_node.type,err.toString());
|
||||
}
|
||||
|
||||
for (d in editing_node._def.defaults) {
|
||||
if (editing_node._def.defaults.hasOwnProperty(d)) {
|
||||
if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") {
|
||||
if (oldValues[d] !== editing_node[d]) {
|
||||
changes[d] = oldValues[d];
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) {
|
||||
changes[d] = oldValues[d];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var newValue;
|
||||
if (editing_node._def.defaults) {
|
||||
for (d in editing_node._def.defaults) {
|
||||
if (editing_node._def.defaults.hasOwnProperty(d)) {
|
||||
var input = $("#node-input-"+d);
|
||||
if (input.attr('type') === "checkbox") {
|
||||
newValue = input.prop('checked');
|
||||
} else if (input.prop("nodeName") === "select" && input.attr("multiple") === "multiple") {
|
||||
// An empty select-multiple box returns null.
|
||||
// Need to treat that as an empty array.
|
||||
newValue = input.val();
|
||||
if (newValue == null) {
|
||||
newValue = [];
|
||||
}
|
||||
} else if ("format" in editing_node._def.defaults[d] && editing_node._def.defaults[d].format !== "" && input[0].nodeName === "DIV") {
|
||||
newValue = input.text();
|
||||
} else {
|
||||
newValue = input.val();
|
||||
}
|
||||
if (newValue != null) {
|
||||
if (editing_node._def.defaults[d].type) {
|
||||
if (newValue == "_ADD_") {
|
||||
newValue = "";
|
||||
}
|
||||
}
|
||||
if (editing_node[d] != newValue) {
|
||||
if (editing_node._def.defaults[d].type) {
|
||||
// Change to a related config node
|
||||
var configNode = RED.nodes.node(editing_node[d]);
|
||||
if (configNode) {
|
||||
var users = configNode.users;
|
||||
users.splice(users.indexOf(editing_node),1);
|
||||
}
|
||||
configNode = RED.nodes.node(newValue);
|
||||
if (configNode) {
|
||||
configNode.users.push(editing_node);
|
||||
}
|
||||
}
|
||||
changes[d] = editing_node[d];
|
||||
editing_node[d] = newValue;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var oldInfo = editing_node.info;
|
||||
if (nodeInfoEditor) {
|
||||
var newInfo = nodeInfoEditor.getValue();
|
||||
if (!!oldInfo) {
|
||||
// Has existing info property
|
||||
if (newInfo.trim() === "") {
|
||||
// New value is blank - remove the property
|
||||
changed = true;
|
||||
changes.info = oldInfo;
|
||||
delete editing_node.info;
|
||||
} else if (newInfo !== oldInfo) {
|
||||
// New value is different
|
||||
changed = true;
|
||||
changes.info = oldInfo;
|
||||
editing_node.info = newInfo;
|
||||
}
|
||||
} else {
|
||||
// No existing info
|
||||
if (newInfo.trim() !== "") {
|
||||
// New value is not blank
|
||||
changed = true;
|
||||
changes.info = undefined;
|
||||
editing_node.info = newInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
var wasChanged = editing_node.changed;
|
||||
editing_node.changed = true;
|
||||
RED.nodes.dirty(true);
|
||||
var historyEvent = {
|
||||
t:'edit',
|
||||
node:editing_node,
|
||||
changes:changes,
|
||||
dirty:wasDirty,
|
||||
changed:wasChanged
|
||||
};
|
||||
RED.history.push(historyEvent);
|
||||
}
|
||||
editing_node.dirty = true;
|
||||
RED.tray.close();
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(size) {
|
||||
editTrayWidthCache['group'] = size.width;
|
||||
$(".red-ui-tray-content").height(size.height - 50);
|
||||
// var form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40);
|
||||
// if (editing_node && editing_node._def.oneditresize) {
|
||||
// try {
|
||||
// editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()});
|
||||
// } catch(err) {
|
||||
// console.log("oneditresize",editing_node.id,editing_node.type,err.toString());
|
||||
// }
|
||||
// }
|
||||
},
|
||||
open: function(tray, done) {
|
||||
var trayFooter = tray.find(".red-ui-tray-footer");
|
||||
var trayFooterLeft = $("<div/>", {
|
||||
class: "red-ui-tray-footer-left"
|
||||
}).appendTo(trayFooter)
|
||||
var trayBody = tray.find('.red-ui-tray-body');
|
||||
trayBody.parent().css('overflow','hidden');
|
||||
|
||||
var editorTabEl = $('<ul></ul>').appendTo(trayBody);
|
||||
var editorContent = $('<div></div>').appendTo(trayBody);
|
||||
|
||||
var editorTabs = RED.tabs.create({
|
||||
element:editorTabEl,
|
||||
onchange:function(tab) {
|
||||
editorContent.children().hide();
|
||||
if (tab.onchange) {
|
||||
tab.onchange.call(tab);
|
||||
}
|
||||
tab.content.show();
|
||||
if (finishedBuilding) {
|
||||
RED.tray.resize();
|
||||
}
|
||||
},
|
||||
collapsible: true,
|
||||
menu: false
|
||||
});
|
||||
|
||||
var nodePropertiesTab = {
|
||||
id: "editor-tab-properties",
|
||||
label: RED._("editor-tab.properties"),
|
||||
name: RED._("editor-tab.properties"),
|
||||
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||
iconClass: "fa fa-cog"
|
||||
};
|
||||
buildEditForm(nodePropertiesTab.content,"dialog-form","group","node-red",group);
|
||||
|
||||
editorTabs.addTab(nodePropertiesTab);
|
||||
|
||||
var descriptionTab = {
|
||||
id: "editor-tab-description",
|
||||
label: RED._("editor-tab.description"),
|
||||
name: RED._("editor-tab.description"),
|
||||
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||
iconClass: "fa fa-file-text-o",
|
||||
onchange: function() {
|
||||
nodeInfoEditor.focus();
|
||||
}
|
||||
};
|
||||
editorTabs.addTab(descriptionTab);
|
||||
nodeInfoEditor = buildDescriptionForm(descriptionTab.content,editing_node);
|
||||
prepareEditDialog(group,group._def,"node-input", function() {
|
||||
trayBody.i18n();
|
||||
finishedBuilding = true;
|
||||
done();
|
||||
});
|
||||
},
|
||||
close: function() {
|
||||
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
|
||||
RED.view.state(RED.state.DEFAULT);
|
||||
}
|
||||
nodeInfoEditor.destroy();
|
||||
nodeInfoEditor = null;
|
||||
editStack.pop();
|
||||
editing_node = null;
|
||||
},
|
||||
show: function() {
|
||||
}
|
||||
}
|
||||
|
||||
if (editTrayWidthCache.hasOwnProperty('group')) {
|
||||
trayOptions.width = editTrayWidthCache['group'];
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
|
||||
function showTypeEditor(type, options) {
|
||||
if (customEditTypes.hasOwnProperty(type)) {
|
||||
if (editStack.length > 0) {
|
||||
@@ -2537,6 +2752,7 @@ RED.editor = (function() {
|
||||
edit: showEditDialog,
|
||||
editConfig: showEditConfigNodeDialog,
|
||||
editSubflow: showEditSubflowDialog,
|
||||
editGroup: showEditGroupDialog,
|
||||
editJavaScript: function(options) { showTypeEditor("_js",options) },
|
||||
editExpression: function(options) { showTypeEditor("_expression", options) },
|
||||
editJSON: function(options) { showTypeEditor("_json", options) },
|
||||
|
||||
633
packages/node_modules/@node-red/editor-client/src/js/ui/group.js
vendored
Normal file
633
packages/node_modules/@node-red/editor-client/src/js/ui/group.js
vendored
Normal file
@@ -0,0 +1,633 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
RED.group = (function() {
|
||||
|
||||
var _groupEditTemplate = '<script type="text/x-red" data-template-name="group">'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
|
||||
'<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">'+
|
||||
'</div>'+
|
||||
|
||||
// '<div class="node-input-group-style-tools"><span class="button-group"><button class="red-ui-button red-ui-button-small">Use default style</button><button class="red-ui-button red-ui-button-small">Set as default style</button></span></div>'+
|
||||
|
||||
'<div class="form-row" id="node-input-row-style-stroke">'+
|
||||
'<label>Style</label>'+
|
||||
'<label style="width: 70px;margin-right:10px" for="node-input-style-stroke" data-i18n="editor:common.label.line"></label>'+
|
||||
'</div>'+
|
||||
'<div class="form-row" style="padding-left: 100px;" id="node-input-row-style-fill">'+
|
||||
'<label style="width: 70px;margin-right: 10px " for="node-input-style-fill" data-i18n="editor:common.label.fill"></label>'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="node-input-style-label">Label</label>'+
|
||||
'<input type="checkbox" id="node-input-style-label"/>'+
|
||||
'</div>'+
|
||||
'<div class="form-row" id="node-input-row-style-label-options">'+
|
||||
'<div style="margin-left: 100px; display: inline-block">'+
|
||||
'<div class="form-row">'+
|
||||
'<span style="display: inline-block; min-width: 140px" id="node-input-row-style-label-color">'+
|
||||
'<label style="width: 70px;margin-right: 10px" for="node-input-style-fill" data-i18n="editor:common.label.color"></label>'+
|
||||
'</span>'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<span style="display: inline-block; min-width: 140px;" id="node-input-row-style-label-position">'+
|
||||
'<label style="width: 70px;margin-right: 10px " for="node-input-style-label-position" data-i18n="editor:common.label.position"></label>'+
|
||||
'</span>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
|
||||
'</script>';
|
||||
|
||||
var colorPalette = [
|
||||
"#ff0000",
|
||||
"#ffC000",
|
||||
"#ffff00",
|
||||
"#92d04f",
|
||||
"#0070c0",
|
||||
"#001f60",
|
||||
"#6f2fa0",
|
||||
"#000000",
|
||||
"#777777"
|
||||
]
|
||||
var colorSteps = 3;
|
||||
var colorCount = colorPalette.length;
|
||||
for (var i=0,len=colorPalette.length*colorSteps;i<len;i++) {
|
||||
var ci = i%colorCount;
|
||||
var j = Math.floor(i/colorCount)+1;
|
||||
var c = colorPalette[ci];
|
||||
var r = parseInt(c.substring(1, 3), 16);
|
||||
var g = parseInt(c.substring(3, 5), 16);
|
||||
var b = parseInt(c.substring(5, 7), 16);
|
||||
var dr = (255-r)/(colorSteps+((ci===colorCount-1) ?0:1));
|
||||
var dg = (255-g)/(colorSteps+((ci===colorCount-1) ?0:1));
|
||||
var db = (255-b)/(colorSteps+((ci===colorCount-1) ?0:1));
|
||||
r = Math.min(255,Math.floor(r+j*dr));
|
||||
g = Math.min(255,Math.floor(g+j*dg));
|
||||
b = Math.min(255,Math.floor(b+j*db));
|
||||
colorPalette.push('#'+((r<<16) + (g<<8) + b).toString(16).padStart(6,'0'));
|
||||
}
|
||||
|
||||
var defaultGroupStyle = {};
|
||||
|
||||
var groupDef = {
|
||||
defaults:{
|
||||
name:{value:""},
|
||||
style:{value:{}},
|
||||
nodes:{value:[]}
|
||||
},
|
||||
category: "config",
|
||||
oneditprepare: function() {
|
||||
var style = this.style || {};
|
||||
RED.colorPicker.create({
|
||||
id:"node-input-style-stroke",
|
||||
value: style.stroke || "#a4a4a4",
|
||||
palette: colorPalette,
|
||||
cellPerRow: colorCount,
|
||||
cellWidth: 16,
|
||||
cellHeight: 16,
|
||||
cellMargin: 3,
|
||||
none: true,
|
||||
opacity: style['stroke-opacity'] || 1.0
|
||||
}).appendTo("#node-input-row-style-stroke");
|
||||
RED.colorPicker.create({
|
||||
id:"node-input-style-fill",
|
||||
value: style.fill || "none",
|
||||
palette: colorPalette,
|
||||
cellPerRow: colorCount,
|
||||
cellWidth: 16,
|
||||
cellHeight: 16,
|
||||
cellMargin: 3,
|
||||
none: true,
|
||||
opacity: style['fill-opacity'] || 1.0
|
||||
}).appendTo("#node-input-row-style-fill");
|
||||
|
||||
createLayoutPicker({
|
||||
id:"node-input-style-label-position",
|
||||
value:style["label-position"] || "nw"
|
||||
}).appendTo("#node-input-row-style-label-position");
|
||||
|
||||
RED.colorPicker.create({
|
||||
id:"node-input-style-color",
|
||||
value: style.color || "#a4a4a4",
|
||||
palette: colorPalette,
|
||||
cellPerRow: colorCount,
|
||||
cellWidth: 16,
|
||||
cellHeight: 16,
|
||||
cellMargin: 3
|
||||
}).appendTo("#node-input-row-style-label-color");
|
||||
|
||||
$("#node-input-style-label").toggleButton({
|
||||
enabledLabel: RED._("editor.show"),
|
||||
disabledLabel: RED._("editor.hide")
|
||||
})
|
||||
|
||||
|
||||
$("#node-input-style-label").on("change", function(evt) {
|
||||
$("#node-input-row-style-label-options").toggle($(this).prop("checked"));
|
||||
})
|
||||
$("#node-input-style-label").prop("checked", this.style.label)
|
||||
$("#node-input-style-label").trigger("change");
|
||||
|
||||
},
|
||||
oneditresize: function(size) {
|
||||
},
|
||||
oneditsave: function() {
|
||||
this.style.stroke = $("#node-input-style-stroke").val();
|
||||
this.style.fill = $("#node-input-style-fill").val();
|
||||
this.style["stroke-opacity"] = $("#node-input-style-stroke-opacity").val();
|
||||
this.style["fill-opacity"] = $("#node-input-style-fill-opacity").val();
|
||||
this.style.label = $("#node-input-style-label").prop("checked");
|
||||
if (this.style.label) {
|
||||
this.style["label-position"] = $("#node-input-style-label-position").val();
|
||||
this.style.color = $("#node-input-style-color").val();
|
||||
} else {
|
||||
delete this.style["label-position"];
|
||||
delete this.style.color;
|
||||
}
|
||||
|
||||
if (this.style["stroke-opacity"] === "1") {
|
||||
delete this.style["stroke-opacity"]
|
||||
}
|
||||
if (this.style["fill-opacity"] === "1") {
|
||||
delete this.style["fill-opacity"]
|
||||
}
|
||||
this.resize = true;
|
||||
},
|
||||
set:{
|
||||
module: "node-red"
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
RED.events.on("view:selection-changed",function(selection) {
|
||||
RED.menu.setDisabled("menu-item-group-group",!!!selection.nodes);
|
||||
RED.menu.setDisabled("menu-item-group-ungroup",!!!selection.nodes || selection.nodes.filter(function(n) { return n.type==='group'}).length === 0);
|
||||
RED.menu.setDisabled("menu-item-group-merge",!!!selection.nodes);
|
||||
RED.menu.setDisabled("menu-item-group-remove",!!!selection.nodes || selection.nodes.filter(function(n) { return !!n.g }).length === 0);
|
||||
});
|
||||
|
||||
RED.actions.add("core:group-selection", function() { groupSelection() })
|
||||
RED.actions.add("core:ungroup-selection", function() { ungroupSelection() })
|
||||
RED.actions.add("core:merge-selection-to-group", function() { mergeSelection() })
|
||||
RED.actions.add("core:remove-selection-from-group", function() { removeSelection() })
|
||||
RED.actions.add("core:copy-group-style", function() { copyGroupStyle() });
|
||||
RED.actions.add("core:paste-group-style", function() { pasteGroupStyle() });
|
||||
|
||||
$(_groupEditTemplate).appendTo("#red-ui-editor-node-configs");
|
||||
|
||||
var groupStyleDiv = $("<div>",{
|
||||
class:"red-ui-flow-group-body",
|
||||
style: "position: absolute; top: -1000px;"
|
||||
}).appendTo(document.body);
|
||||
var groupStyle = getComputedStyle(groupStyleDiv[0]);
|
||||
defaultGroupStyle = {
|
||||
stroke: convertColorToHex(groupStyle.stroke),
|
||||
"stroke-opacity": groupStyle.strokeOpacity,
|
||||
fill: convertColorToHex(groupStyle.fill),
|
||||
"fill-opacity": groupStyle.fillOpacity
|
||||
}
|
||||
groupStyleDiv.remove();
|
||||
}
|
||||
|
||||
function convertColorToHex(c) {
|
||||
var m = /^rgb\((\d+), (\d+), (\d+)\)$/.exec(c);
|
||||
if (m) {
|
||||
return "#"+(((parseInt(m[1])<<16) + (parseInt(m[2])<<8) + parseInt(m[3])).toString(16).padStart(6,'0'))
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
var groupStyleClipboard;
|
||||
|
||||
function copyGroupStyle() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].type === 'group') {
|
||||
groupStyleClipboard = JSON.parse(JSON.stringify(selection.nodes[0].style));
|
||||
RED.notify(RED._("clipboard.groupStyleCopied"),{id:"clipboard"})
|
||||
}
|
||||
}
|
||||
function pasteGroupStyle() {
|
||||
if (groupStyleClipboard) {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var historyEvent = {
|
||||
t:'multi',
|
||||
events:[],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
selection.nodes.forEach(function(n) {
|
||||
if (n.type === 'group') {
|
||||
historyEvent.events.push({
|
||||
t: "edit",
|
||||
node: n,
|
||||
changes: {
|
||||
style: JSON.parse(JSON.stringify(n.style))
|
||||
},
|
||||
dirty: RED.nodes.dirty()
|
||||
});
|
||||
n.style = JSON.parse(JSON.stringify(groupStyleClipboard));
|
||||
n.dirty = true;
|
||||
|
||||
}
|
||||
})
|
||||
if (historyEvent.events.length > 0) {
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function groupSelection() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var group = createGroup(selection.nodes);
|
||||
if (group) {
|
||||
var historyEvent = {
|
||||
t:"createGroup",
|
||||
groups: [ group ],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select({nodes:[group]});
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
function ungroupSelection() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var newSelection = [];
|
||||
groups = selection.nodes.filter(function(n) { return n.type === "group" });
|
||||
|
||||
var historyEvent = {
|
||||
t:"ungroup",
|
||||
groups: [ ],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
|
||||
groups.forEach(function(g) {
|
||||
newSelection = newSelection.concat(ungroup(g))
|
||||
historyEvent.groups.push(g);
|
||||
})
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select({nodes:newSelection})
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
function ungroup(g) {
|
||||
var nodes = [];
|
||||
var parentGroup = RED.nodes.group(g.g);
|
||||
g.nodes.forEach(function(n) {
|
||||
nodes.push(n);
|
||||
if (parentGroup) {
|
||||
// Move nodes to parent group
|
||||
n.g = parentGroup.id;
|
||||
parentGroup.nodes.push(n);
|
||||
parentGroup.dirty = true;
|
||||
n.dirty = true;
|
||||
} else {
|
||||
delete n.g;
|
||||
}
|
||||
})
|
||||
RED.nodes.removeGroup(g);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function mergeSelection() {
|
||||
// TODO: this currently creates an entirely new group. Need to merge properties
|
||||
// of any existing group
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var nodes = [];
|
||||
|
||||
var historyEvent = {
|
||||
t: "multi",
|
||||
events: []
|
||||
}
|
||||
var ungroupHistoryEvent = {
|
||||
t: "ungroup",
|
||||
groups: []
|
||||
}
|
||||
|
||||
|
||||
var n;
|
||||
var parentGroup;
|
||||
// First pass, check they are all in the same parent
|
||||
// TODO: DRY mergeSelection,removeSelection,...
|
||||
for (var i=0; i<selection.nodes.length; i++) {
|
||||
n = selection.nodes[i];
|
||||
if (i === 0) {
|
||||
parentGroup = n.g;
|
||||
} else if (n.g !== parentGroup) {
|
||||
RED.notify(RED._("group.errors.cannotCreateDiffGroups"),"error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Second pass, ungroup any groups in the selection and add their contents
|
||||
// to the selection
|
||||
for (var i=0; i<selection.nodes.length; i++) {
|
||||
n = selection.nodes[i];
|
||||
if (n.type === "group") {
|
||||
ungroupHistoryEvent.groups.push(n);
|
||||
nodes = nodes.concat(ungroup(n));
|
||||
} else {
|
||||
nodes.push(n);
|
||||
}
|
||||
n.dirty = true;
|
||||
}
|
||||
if (ungroupHistoryEvent.groups.length > 0) {
|
||||
historyEvent.events.push(ungroupHistoryEvent);
|
||||
}
|
||||
// Finally, create the new group
|
||||
var group = createGroup(nodes);
|
||||
if (group) {
|
||||
RED.view.select({nodes:[group]})
|
||||
}
|
||||
historyEvent.events.push({
|
||||
t:"createGroup",
|
||||
groups: [ group ],
|
||||
dirty: RED.nodes.dirty()
|
||||
});
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
function removeSelection() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var nodes = [];
|
||||
var n;
|
||||
var parentGroup = RED.nodes.group(selection.nodes[0].g);
|
||||
if (parentGroup) {
|
||||
try {
|
||||
removeFromGroup(parentGroup,selection.nodes,true);
|
||||
var historyEvent = {
|
||||
t: "removeFromGroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
group: parentGroup,
|
||||
nodes: selection.nodes
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
} catch(err) {
|
||||
RED.notify(err,"error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
RED.view.select({nodes:selection.nodes})
|
||||
}
|
||||
}
|
||||
function createGroup(nodes) {
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (nodes.filter(function(n) { return n.type === "subflow" }).length > 0) {
|
||||
RED.notify(RED._("group.errors.cannotAddSubflowPorts"),"error");
|
||||
return;
|
||||
}
|
||||
// nodes is an array
|
||||
// each node must be on the same tab (z)
|
||||
var group = {
|
||||
id: RED.nodes.id(),
|
||||
type: 'group',
|
||||
nodes: [],
|
||||
style: JSON.parse(JSON.stringify(defaultGroupStyle)),
|
||||
x: Number.POSITIVE_INFINITY,
|
||||
y: Number.POSITIVE_INFINITY,
|
||||
w: 0,
|
||||
h: 0,
|
||||
_def: RED.group.def
|
||||
}
|
||||
try {
|
||||
addToGroup(group,nodes);
|
||||
} catch(err) {
|
||||
RED.notify(err,"error");
|
||||
return;
|
||||
}
|
||||
group.z = nodes[0].z;
|
||||
|
||||
RED.nodes.addGroup(group);
|
||||
return group;
|
||||
}
|
||||
function addToGroup(group,nodes) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
nodes = [nodes];
|
||||
}
|
||||
var i,n,z;
|
||||
var g;
|
||||
// First pass - validate we can safely add these nodes to the group
|
||||
for (i=0;i<nodes.length;i++) {
|
||||
n = nodes[i]
|
||||
if (!n.z) {
|
||||
throw new Error("Cannot add node without a z property to a group")
|
||||
}
|
||||
if (!z) {
|
||||
z = n.z;
|
||||
} else if (z !== n.z) {
|
||||
throw new Error("Cannot add nooes with different z properties")
|
||||
}
|
||||
if (n.g) {
|
||||
// This is already in a group.
|
||||
// - check they are all in the same group
|
||||
if (!g) {
|
||||
if (i!==0) {
|
||||
// TODO: this might be ok when merging groups
|
||||
throw new Error(RED._("group.errors.cannotCreateDiffGroups"))
|
||||
}
|
||||
g = n.g
|
||||
}
|
||||
}
|
||||
if (g !== n.g) {
|
||||
throw new Error(RED._("group.errors.cannotCreateDiffGroups"))
|
||||
}
|
||||
}
|
||||
// The nodes are already in a group. The assumption is they should be
|
||||
// wrapped in the newly provided group, and that group added to in their
|
||||
// place to the existing containing group.
|
||||
if (g) {
|
||||
g = RED.nodes.group(g);
|
||||
g.nodes.push(group);
|
||||
g.dirty = true;
|
||||
group.g = g.id;
|
||||
}
|
||||
// Second pass - add them to the group
|
||||
for (i=0;i<nodes.length;i++) {
|
||||
n = nodes[i];
|
||||
if (n.type !== "subflow") {
|
||||
if (g && n.g === g.id) {
|
||||
var ni = g.nodes.indexOf(n);
|
||||
if (ni > -1) {
|
||||
g.nodes.splice(ni,1)
|
||||
}
|
||||
}
|
||||
n.g = group.id;
|
||||
n.dirty = true;
|
||||
group.nodes.push(n);
|
||||
group.x = Math.min(group.x,n.x-n.w/2-25-((n._def.button && n._def.align!=="right")?20:0));
|
||||
group.y = Math.min(group.y,n.y-n.h/2-25);
|
||||
group.w = Math.max(group.w,n.x+n.w/2+25+((n._def.button && n._def.align=="right")?20:0) - group.x);
|
||||
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
|
||||
}
|
||||
}
|
||||
|
||||
markDirty(group);
|
||||
}
|
||||
function removeFromGroup(group, nodes, reparent) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
nodes = [nodes];
|
||||
}
|
||||
var n;
|
||||
// First pass, check they are all in the same parent
|
||||
// TODO: DRY mergeSelection,removeSelection,...
|
||||
for (var i=0; i<nodes.length; i++) {
|
||||
if (nodes[i].g !== group.id) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var parentGroup = RED.nodes.group(group.g);
|
||||
for (var i=0; i<nodes.length; i++) {
|
||||
n = nodes[i];
|
||||
n.dirty = true;
|
||||
var index = group.nodes.indexOf(n);
|
||||
group.nodes.splice(index,1);
|
||||
if (reparent && group.g) {
|
||||
n.g = group.g
|
||||
parentGroup.nodes.push(n);
|
||||
} else {
|
||||
delete n.g;
|
||||
}
|
||||
}
|
||||
markDirty(group);
|
||||
}
|
||||
|
||||
function getNodes(group,recursive) {
|
||||
var nodes = [];
|
||||
group.nodes.forEach(function(n) {
|
||||
nodes.push(n);
|
||||
if (recursive && n.type === 'group') {
|
||||
nodes = nodes.concat(getNodes(n,recursive))
|
||||
}
|
||||
})
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function groupContains(group,item) {
|
||||
if (item.g === group.id) {
|
||||
return true;
|
||||
}
|
||||
for (var i=0;i<group.nodes.length;i++) {
|
||||
if (group.nodes[i].type === "group") {
|
||||
if (groupContains(group.nodes[i],item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getRootGroup(group) {
|
||||
if (!group.g) {
|
||||
return group;
|
||||
}
|
||||
return getRootGroup(RED.nodes.group(group.g))
|
||||
}
|
||||
|
||||
function createLayoutPicker(options) {
|
||||
|
||||
var container = $("<div>",{style:"display:inline-block"});
|
||||
var layoutHiddenInput = $("<input/>", { id: options.id, type: "hidden", value: options.value }).appendTo(container);
|
||||
|
||||
var layoutButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container);
|
||||
$('<i class="fa fa-caret-down"></i>').appendTo(layoutButton);
|
||||
|
||||
var layoutDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(layoutButton);
|
||||
var layoutDisp = $('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"}).appendTo(layoutDispContainer);
|
||||
|
||||
var refreshDisplay = function() {
|
||||
var val = layoutHiddenInput.val();
|
||||
layoutDisp.removeClass().addClass("red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val)
|
||||
}
|
||||
layoutButton.on("click", function(e) {
|
||||
var picker = $("<div/>", {
|
||||
class: "red-ui-group-layout-picker"
|
||||
}).css({
|
||||
width: "126px"
|
||||
});
|
||||
|
||||
var row = null;
|
||||
|
||||
row = $("<div/>").appendTo(picker);
|
||||
|
||||
for (var y=0;y<2;y++) { //red-ui-group-layout-text-pos
|
||||
var yComponent= "ns"[y];
|
||||
row = $("<div/>").appendTo(picker);
|
||||
for (var x=0;x<3;x++) {
|
||||
var xComponent = ["w","","e"][x];
|
||||
var val = yComponent+xComponent;
|
||||
var button = $("<button/>", { class:"red-ui-search-result-node","data-pos":val }).appendTo(row);
|
||||
button.on("click", function (e) {
|
||||
e.preventDefault();
|
||||
layoutHiddenInput.val($(this).data("pos"));
|
||||
layoutPanel.hide()
|
||||
refreshDisplay();
|
||||
});
|
||||
$('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val}).appendTo(button);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
refreshDisplay();
|
||||
var layoutPanel = RED.popover.panel(picker);
|
||||
layoutPanel.show({
|
||||
target: layoutButton
|
||||
})
|
||||
})
|
||||
|
||||
refreshDisplay();
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
function markDirty(group) {
|
||||
group.dirty = true;
|
||||
while(group) {
|
||||
group.dirty = true;
|
||||
group = RED.nodes.group(group.g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
def: groupDef,
|
||||
init: init,
|
||||
createGroup: createGroup,
|
||||
ungroup: ungroup,
|
||||
addToGroup: addToGroup,
|
||||
removeFromGroup: removeFromGroup,
|
||||
getNodes: getNodes,
|
||||
contains: groupContains,
|
||||
markDirty: markDirty
|
||||
}
|
||||
})();
|
||||
@@ -75,13 +75,16 @@ RED.palette.editor = (function() {
|
||||
});
|
||||
})
|
||||
}
|
||||
function installNodeModule(id,version,callback) {
|
||||
function installNodeModule(id,version,url,callback) {
|
||||
var requestBody = {
|
||||
module: id
|
||||
};
|
||||
if (version) {
|
||||
requestBody.version = version;
|
||||
}
|
||||
if (url) {
|
||||
requestBody.url = url;
|
||||
}
|
||||
$.ajax({
|
||||
url:"nodes",
|
||||
type: "POST",
|
||||
@@ -623,7 +626,7 @@ RED.palette.editor = (function() {
|
||||
if ($(this).hasClass('disabled')) {
|
||||
return;
|
||||
}
|
||||
update(entry,loadedIndex[entry.name].version,container,function(err){});
|
||||
update(entry,loadedIndex[entry.name].version,loadedIndex[entry.name].pkg_url,container,function(err){});
|
||||
})
|
||||
|
||||
|
||||
@@ -873,7 +876,7 @@ RED.palette.editor = (function() {
|
||||
|
||||
$('<div id="red-ui-palette-module-install-shade" class="red-ui-palette-module-shade hide"><div class="red-ui-palette-module-shade-status"></div><img src="red/images/spin.svg" class="red-ui-palette-spinner"/></div>').appendTo(installTab);
|
||||
}
|
||||
function update(entry,version,container,done) {
|
||||
function update(entry,version,url,container,done) {
|
||||
if (RED.settings.theme('palette.editable') === false) {
|
||||
done(new Error('Palette not editable'));
|
||||
return;
|
||||
@@ -899,7 +902,7 @@ RED.palette.editor = (function() {
|
||||
RED.actions.invoke("core:show-event-log");
|
||||
});
|
||||
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.name+" "+version);
|
||||
installNodeModule(entry.name,version,function(xhr) {
|
||||
installNodeModule(entry.name,version,url,function(xhr) {
|
||||
spinner.remove();
|
||||
if (xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
@@ -1024,7 +1027,7 @@ RED.palette.editor = (function() {
|
||||
RED.actions.invoke("core:show-event-log");
|
||||
});
|
||||
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.id+" "+entry.version);
|
||||
installNodeModule(entry.id,entry.version,function(xhr) {
|
||||
installNodeModule(entry.id,entry.version,entry.pkg_url,function(xhr) {
|
||||
spinner.remove();
|
||||
if (xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
|
||||
@@ -284,6 +284,9 @@ RED.palette = (function() {
|
||||
var mouseX;
|
||||
var mouseY;
|
||||
var spliceTimer;
|
||||
var groupTimer;
|
||||
var activeGroup;
|
||||
var hoverGroup;
|
||||
var paletteWidth;
|
||||
var paletteTop;
|
||||
$(d).draggable({
|
||||
@@ -295,16 +298,53 @@ RED.palette = (function() {
|
||||
start: function() {
|
||||
paletteWidth = $("#red-ui-palette").width();
|
||||
paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top;
|
||||
hoverGroup = null;
|
||||
activeGroup = RED.view.getActiveGroup();
|
||||
if (activeGroup) {
|
||||
document.getElementById("group_select_"+activeGroup.id).classList.add("red-ui-flow-group-active-hovered");
|
||||
}
|
||||
RED.view.focus();
|
||||
},
|
||||
stop: function() { d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}},
|
||||
stop: function() {
|
||||
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
||||
if (hoverGroup) {
|
||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||
}
|
||||
if (activeGroup) {
|
||||
document.getElementById("group_select_"+activeGroup.id).classList.remove("red-ui-flow-group-active-hovered");
|
||||
}
|
||||
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
|
||||
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
|
||||
},
|
||||
drag: function(e,ui) {
|
||||
var paletteNode = getPaletteNode(nt);
|
||||
ui.originalPosition.left = paletteNode.offset().left;
|
||||
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
|
||||
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop();
|
||||
if (!groupTimer) {
|
||||
groupTimer = setTimeout(function() {
|
||||
mouseX /= RED.view.scale();
|
||||
mouseY /= RED.view.scale();
|
||||
var group = RED.view.getGroupAtPoint(mouseX,mouseY);
|
||||
if (group !== hoverGroup) {
|
||||
if (hoverGroup) {
|
||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||
}
|
||||
if (group) {
|
||||
document.getElementById("group_select_"+group.id).classList.add("red-ui-flow-group-hovered");
|
||||
}
|
||||
hoverGroup = group;
|
||||
if (hoverGroup) {
|
||||
$(ui.helper).data('group',hoverGroup);
|
||||
} else {
|
||||
$(ui.helper).removeData('group');
|
||||
}
|
||||
}
|
||||
groupTimer = null;
|
||||
|
||||
},200)
|
||||
}
|
||||
if (def.inputs > 0 && def.outputs > 0) {
|
||||
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
|
||||
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop();
|
||||
if (!spliceTimer) {
|
||||
spliceTimer = setTimeout(function() {
|
||||
var nodes = [];
|
||||
|
||||
@@ -25,5 +25,7 @@ RED.state = {
|
||||
IMPORT_DRAGGING: 8,
|
||||
QUICK_JOINING: 9,
|
||||
PANNING: 10,
|
||||
SELECTING_NODE: 11
|
||||
SELECTING_NODE: 11,
|
||||
GROUP_DRAGGING: 12,
|
||||
GROUP_RESIZE: 13
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -152,7 +152,8 @@ RED.sidebar.info = (function() {
|
||||
var types = {
|
||||
nodes:0,
|
||||
flows:0,
|
||||
subflows:0
|
||||
subflows:0,
|
||||
groups: 0
|
||||
}
|
||||
node.forEach(function(n) {
|
||||
if (n.type === 'tab') {
|
||||
@@ -160,6 +161,8 @@ RED.sidebar.info = (function() {
|
||||
types.nodes += RED.nodes.filterNodes({z:n.id}).length;
|
||||
} else if (n.type === 'subflow') {
|
||||
types.subflows++;
|
||||
} else if (n.type === 'group') {
|
||||
types.groups++;
|
||||
} else {
|
||||
types.nodes++;
|
||||
}
|
||||
@@ -179,6 +182,9 @@ RED.sidebar.info = (function() {
|
||||
if (types.nodes > 0) {
|
||||
$('<div>').text(RED._("clipboard.node",{count:types.nodes})).appendTo(counts);
|
||||
}
|
||||
if (types.groups > 0) {
|
||||
$('<div>').text(RED._("clipboard.group",{count:types.groups})).appendTo(counts);
|
||||
}
|
||||
} else {
|
||||
// A single 'thing' selected.
|
||||
|
||||
@@ -209,6 +215,36 @@ RED.sidebar.info = (function() {
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
$(propRow.children()[1]).text((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
|
||||
}
|
||||
} else if (node.type === "group") {
|
||||
// An actual node is selected in the editor - build up its properties table
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.group")+"</td><td></td></tr>").appendTo(tableBody);
|
||||
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
|
||||
if (node.name) {
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
$('<span class="red-ui-text-bidi-aware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]);
|
||||
}
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td> </td><td></td></tr>').appendTo(tableBody);
|
||||
var typeCounts = {
|
||||
nodes:0,
|
||||
groups: 0
|
||||
}
|
||||
var allNodes = RED.group.getNodes(node,true);
|
||||
allNodes.forEach(function(n) {
|
||||
if (n.type === "group") {
|
||||
typeCounts.groups++;
|
||||
} else {
|
||||
typeCounts.nodes++
|
||||
}
|
||||
});
|
||||
var counts = $('<div>').appendTo($(propRow.children()[1]));
|
||||
if (typeCounts.nodes > 0) {
|
||||
$('<div>').text(RED._("clipboard.node",{count:typeCounts.nodes})).appendTo(counts);
|
||||
}
|
||||
if (typeCounts.groups > 0) {
|
||||
$('<div>').text(RED._("clipboard.group",{count:typeCounts.groups})).appendTo(counts);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// An actual node is selected in the editor - build up its properties table
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody);
|
||||
@@ -225,7 +261,7 @@ RED.sidebar.info = (function() {
|
||||
}
|
||||
}
|
||||
var count = 0;
|
||||
if (!m && node.type != "subflow") {
|
||||
if (!m && node.type != "subflow" && node.type != "group") {
|
||||
var defaults;
|
||||
if (node.type === 'unknown') {
|
||||
defaults = {};
|
||||
|
||||
@@ -67,9 +67,16 @@ RED.view.tools = (function() {
|
||||
|
||||
function moveSelection(dx,dy) {
|
||||
if (moving_set === null) {
|
||||
moving_set = [];
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
moving_set = selection.nodes.map(function(n) { return {n:n}});
|
||||
while (selection.nodes.length > 0) {
|
||||
var n = selection.nodes.shift();
|
||||
moving_set.push({n:n});
|
||||
if (n.type === "group") {
|
||||
selection.nodes = selection.nodes.concat(n.nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (moving_set && moving_set.length > 0) {
|
||||
@@ -93,6 +100,9 @@ RED.view.tools = (function() {
|
||||
node.n.x += dx;
|
||||
node.n.y += dy;
|
||||
node.n.dirty = true;
|
||||
if (node.n.type === "group") {
|
||||
RED.group.markDirty(node.n);
|
||||
}
|
||||
minX = Math.min(node.n.x-node.n.w/2-5,minX);
|
||||
minY = Math.min(node.n.y-node.n.h/2-5,minY);
|
||||
}
|
||||
@@ -105,6 +115,8 @@ RED.view.tools = (function() {
|
||||
}
|
||||
}
|
||||
RED.view.redraw();
|
||||
} else {
|
||||
RED.view.scroll(dx*10,dy*10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +124,16 @@ RED.view.tools = (function() {
|
||||
init: function() {
|
||||
RED.actions.add("core:align-selection-to-grid", alignToGrid);
|
||||
|
||||
RED.actions.add("core:scroll-view-up", function() { RED.view.scroll(0,-RED.view.gridSize());});
|
||||
RED.actions.add("core:scroll-view-right", function() { RED.view.scroll(RED.view.gridSize(),0);});
|
||||
RED.actions.add("core:scroll-view-down", function() { RED.view.scroll(0,RED.view.gridSize());});
|
||||
RED.actions.add("core:scroll-view-left", function() { RED.view.scroll(-RED.view.gridSize(),0);});
|
||||
|
||||
RED.actions.add("core:step-view-up", function() { RED.view.scroll(0,-5*RED.view.gridSize());});
|
||||
RED.actions.add("core:step-view-right", function() { RED.view.scroll(5*RED.view.gridSize(),0);});
|
||||
RED.actions.add("core:step-view-down", function() { RED.view.scroll(0,5*RED.view.gridSize());});
|
||||
RED.actions.add("core:step-view-left", function() { RED.view.scroll(-5*RED.view.gridSize(),0);});
|
||||
|
||||
RED.actions.add("core:move-selection-up", function() { moveSelection(0,-1);});
|
||||
RED.actions.add("core:move-selection-right", function() { moveSelection(1,0);});
|
||||
RED.actions.add("core:move-selection-down", function() { moveSelection(0,1);});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,19 +9,15 @@
|
||||
color: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ace_gutter {
|
||||
background: $text-editor-gutter-background;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
.ace_scroller {
|
||||
background: $text-editor-background;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.ace_scroller {
|
||||
background: $text-editor-background;
|
||||
color: $text-editor-color;
|
||||
}
|
||||
.ace_marker-layer .ace_active-line {
|
||||
@@ -37,9 +33,6 @@
|
||||
.ace_gutter-active-line {
|
||||
background: $text-editor-gutter-active-line-background;
|
||||
}
|
||||
.ace_gutter {
|
||||
background: $text-editor-gutter-background;
|
||||
}
|
||||
.ace_tooltip {
|
||||
font-family: $primary-font;
|
||||
line-height: 1.4em;
|
||||
|
||||
@@ -284,3 +284,8 @@ $debug-message-border: #eee;
|
||||
$debug-message-border-hover: #999;
|
||||
$debug-message-border-warning: #ffdf9d;
|
||||
$debug-message-border-error: #f99;
|
||||
|
||||
$group-default-fill: none;
|
||||
$group-default-fill-opacity: 1;
|
||||
$group-default-stroke: #999;
|
||||
$group-default-stroke-opacity: 1;
|
||||
|
||||
@@ -217,10 +217,6 @@
|
||||
.red-ui-debug-msg-type-number { color: $debug-message-text-color-msg-type-number; };
|
||||
.red-ui-debug-msg-type-number-toggle { cursor: pointer;}
|
||||
|
||||
.red-ui-debug-msg-type-string {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.red-ui-debug-msg-row {
|
||||
display: block;
|
||||
padding: 4px 2px 2px;
|
||||
|
||||
@@ -411,6 +411,133 @@ button.red-ui-button.red-ui-editor-node-appearance-button {
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-group-layout-picker {
|
||||
padding: 5px;
|
||||
background: $primary-background;
|
||||
}
|
||||
.red-ui-group-layout-picker-cell-text {
|
||||
position: absolute;
|
||||
width: 14px;
|
||||
height: 2px;
|
||||
border-top: 2px solid $secondary-text-color;
|
||||
border-bottom: 2px solid $secondary-text-color;
|
||||
margin: 2px;
|
||||
|
||||
&.red-ui-group-layout-text-pos-nw { top: 0; left: 0; }
|
||||
&.red-ui-group-layout-text-pos-n { top: 0; left: calc(50% - 9px); }
|
||||
&.red-ui-group-layout-text-pos-ne { top: 0; right: 0; }
|
||||
&.red-ui-group-layout-text-pos-sw { bottom: 0; left: 0; }
|
||||
&.red-ui-group-layout-text-pos-s { bottom: 0; left: calc(50% - 9px); }
|
||||
&.red-ui-group-layout-text-pos-se { bottom: 0; right: 0; }
|
||||
&.red-ui-group-layout-text-pos- {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
margin: 0;
|
||||
background-color: #FFF;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0, 50% 50%;
|
||||
background-image: linear-gradient(45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent),linear-gradient(-45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent);
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-group-layout-picker button.red-ui-search-result-node {
|
||||
float: none;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 5px;
|
||||
width: 32px;
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
button.red-ui-group-layout-picker-none {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.red-ui-color-picker {
|
||||
input[type="text"] {
|
||||
border-radius:0;
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
border: none;
|
||||
border-bottom: 1px solid $form-input-border-color;
|
||||
}
|
||||
small {
|
||||
color: $secondary-text-color;
|
||||
margin-left: 5px;
|
||||
margin-right: 4px;
|
||||
display: inline-block;
|
||||
min-width: 35px;
|
||||
text-align: right;
|
||||
}
|
||||
background: $primary-background;
|
||||
}
|
||||
.red-ui-editor-node-appearance-button {
|
||||
.red-ui-search-result-node {
|
||||
overflow: hidden
|
||||
}
|
||||
}
|
||||
.red-ui-color-picker-cell {
|
||||
padding: 0;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: $secondary-border-color;
|
||||
}
|
||||
.red-ui-color-picker-swatch {
|
||||
position: absolute;
|
||||
top:-1px;right:-1px;left:-1px;bottom:-1px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.red-ui-color-picker-cell-none {
|
||||
height: 100%;
|
||||
background-color: #FFF;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0, 50% 50%;
|
||||
background-image: linear-gradient(45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent),linear-gradient(-45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent)
|
||||
}
|
||||
.red-ui-search-result-node .red-ui-color-picker-cell-none {
|
||||
border-radius: 4px;
|
||||
background-size: 50% 50%;
|
||||
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee), linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
|
||||
}
|
||||
|
||||
.red-ui-color-picker-opacity-slider {
|
||||
position:relative;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
width: calc(100% - 50px);
|
||||
height: 14px;
|
||||
margin: 6px 3px 8px;
|
||||
box-sizing: border-box;
|
||||
background-color: white;
|
||||
background-image:
|
||||
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 25%),
|
||||
linear-gradient(-45deg, #eee 25%, transparent 25%, transparent 75%, #eee 25%);
|
||||
background-size: 6px 6px;
|
||||
}
|
||||
.red-ui-color-picker-opacity-slider-overlay {
|
||||
position: absolute;
|
||||
top:0;right:0;left:0;bottom:0;
|
||||
background-image:linear-gradient(90deg, transparent 0%, #f00 100%);
|
||||
background-size: 100% 100%;
|
||||
border: 1px solid $primary-border-color;
|
||||
}
|
||||
|
||||
div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle {
|
||||
z-Index: 10;
|
||||
top: -4px;
|
||||
cursor: pointer;
|
||||
min-width: 0;
|
||||
width: 10px;
|
||||
height: 22px;
|
||||
padding: 0;
|
||||
border: 1px solid $primary-border-color;
|
||||
border-radius: 1px;
|
||||
background: $secondary-background;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.red-ui-icon-picker {
|
||||
select {
|
||||
box-sizing: border-box;
|
||||
@@ -633,7 +760,7 @@ button.red-ui-toggleButton.toggle {
|
||||
.red-ui-typedInput-value-label,.red-ui-typedInput-option-label {
|
||||
select,.placeholder-input {
|
||||
margin: 3px;
|
||||
height: 24px;
|
||||
height: 26px;
|
||||
width: calc(100% - 10px);
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-flow-group {
|
||||
&.red-ui-flow-group-hovered {
|
||||
.red-ui-flow-group-outline-select {
|
||||
stroke-opacity: 0.8 !important;
|
||||
stroke-dasharray: 10 4 !important;
|
||||
}
|
||||
}
|
||||
&.red-ui-flow-group-active-hovered:not(.red-ui-flow-group-hovered) {
|
||||
.red-ui-flow-group-outline-select {
|
||||
stroke: $link-link-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-flow-group-outline {
|
||||
fill: none;
|
||||
stroke: $node-selected-color;
|
||||
stroke-opacity: 0;
|
||||
stroke-width: 12;
|
||||
pointer-events: stroke;
|
||||
}
|
||||
.red-ui-flow-group-outline-select {
|
||||
fill: none;
|
||||
stroke: $node-selected-color;
|
||||
pointer-events: stroke;
|
||||
stroke-opacity: 0;
|
||||
stroke-width: 3;
|
||||
}
|
||||
.red-ui-flow-group-body {
|
||||
pointer-events: none;
|
||||
fill: $group-default-fill;
|
||||
fill-opacity: $group-default-fill-opacity;
|
||||
stroke-width: 2;
|
||||
stroke: $group-default-stroke;
|
||||
stroke-opacity: $group-default-stroke-opacity;
|
||||
}
|
||||
.red-ui-flow-group-label {
|
||||
@include disable-selection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.red-ui-flow-node-unknown {
|
||||
stroke-dasharray:10,4;
|
||||
stroke: $node-border-unknown;
|
||||
@@ -248,6 +290,7 @@ g.red-ui-flow-node-selected {
|
||||
|
||||
.red-ui-flow-link-outline {
|
||||
stroke: $view-background;
|
||||
stroke-opacity: 0.4;
|
||||
stroke-width: 5;
|
||||
cursor: crosshair;
|
||||
fill: none;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
border: 1px solid $form-input-border-color;
|
||||
border-radius: 4px;
|
||||
height: 34px;
|
||||
display: inline-flex;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
@@ -26,7 +26,12 @@
|
||||
overflow:visible;
|
||||
position: relative;
|
||||
.red-ui-typedInput-input-wrap {
|
||||
flex-grow: 1;
|
||||
position: absolute;
|
||||
left:0;
|
||||
right:0;
|
||||
top:0;
|
||||
bottom:0;
|
||||
outline: red;
|
||||
}
|
||||
input.red-ui-typedInput-input {
|
||||
width: 100%;
|
||||
@@ -44,14 +49,17 @@
|
||||
border-color: $form-input-focus-color !important;
|
||||
}
|
||||
.red-ui-typedInput-value-label {
|
||||
flex-grow: 1;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
.red-ui-typedInput-value-label-inactive {
|
||||
background: $secondary-background-disabled;
|
||||
color: $secondary-text-color-disabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
.red-ui-typedInput-options {
|
||||
@@ -99,11 +107,12 @@ button.red-ui-typedInput-option-trigger
|
||||
{
|
||||
text-align: left;
|
||||
border: none;
|
||||
flex-basis: auto;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
padding: 0 1px 0 5px;
|
||||
display:inline-block;
|
||||
background: $form-button-background;
|
||||
height: 32px;
|
||||
line-height: 30px;
|
||||
@@ -117,7 +126,7 @@ button.red-ui-typedInput-option-trigger
|
||||
}
|
||||
&.disabled {
|
||||
cursor: default;
|
||||
i.red-ui-typedInput-icon {
|
||||
> i.red-ui-typedInput-icon {
|
||||
color: $secondary-text-color-disabled;
|
||||
}
|
||||
}
|
||||
@@ -145,7 +154,7 @@ button.red-ui-typedInput-option-trigger
|
||||
text-decoration: none;
|
||||
}
|
||||
&.red-ui-typedInput-full-width {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
@@ -161,6 +170,7 @@ button.red-ui-typedInput-option-expand {
|
||||
border-bottom-right-radius: 4px;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
button.red-ui-typedInput-option-trigger {
|
||||
@@ -169,23 +179,27 @@ button.red-ui-typedInput-option-trigger {
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
padding: 0 0 0 0;
|
||||
position:relative;
|
||||
flex-grow: 1;
|
||||
line-height: 32px;
|
||||
display: inline-flex;
|
||||
position:absolute;
|
||||
right: 0;
|
||||
.red-ui-typedInput-option-label {
|
||||
background:$form-button-background;
|
||||
color: $form-text-color;
|
||||
flex-grow: 1;
|
||||
padding: 0 0 0 8px;
|
||||
display:inline-block;
|
||||
position:absolute;
|
||||
left:0;
|
||||
right:23px;
|
||||
top: 0;
|
||||
padding: 0 5px 0 8px;
|
||||
i.red-ui-typedInput-icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
.red-ui-typedInput-option-caret {
|
||||
flex-grow: 0;
|
||||
display:inline-block;
|
||||
width: 23px;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 17px;
|
||||
padding-left: 5px;
|
||||
&:before {
|
||||
content:'';
|
||||
display: inline-block;
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right:0;
|
||||
zIndex: 101;
|
||||
z-index: 101;
|
||||
border-left: 1px solid $primary-border-color;
|
||||
border-top: 1px solid $primary-border-color;
|
||||
background: $view-navigator-background;
|
||||
@@ -122,7 +122,7 @@
|
||||
stroke-dasharray: 5,5;
|
||||
pointer-events: none;
|
||||
stroke: $secondary-border-color;
|
||||
strokeWidth: 1;
|
||||
stroke-width: 1;
|
||||
fill: $view-background;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="inject">
|
||||
<script type="text/html" data-template-name="inject">
|
||||
<div class="form-row">
|
||||
<label for="node-input-payload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input type="text" id="node-input-payload" style="width:70%">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="debug">
|
||||
<script type="text/html" data-template-name="debug">
|
||||
<div class="form-row">
|
||||
<label for="node-input-typed-complete"><i class="fa fa-list"></i> <span data-i18n="debug.output"></span></label>
|
||||
<input id="node-input-typed-complete" type="text" style="width: 70%">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script type="text/x-red" data-template-name="complete">
|
||||
<script type="text/html" data-template-name="complete">
|
||||
<div class="form-row node-input-target-row">
|
||||
<button id="node-input-complete-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="catch">
|
||||
<script type="text/html" data-template-name="catch">
|
||||
<div class="form-row">
|
||||
<label style="width: auto" for="node-input-scope" data-i18n="catch.label.source"></label>
|
||||
<select id="node-input-scope-select">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="status">
|
||||
<script type="text/html" data-template-name="status">
|
||||
<div class="form-row">
|
||||
<label style="width: auto" for="node-input-scope" data-i18n="status.label.source"></label>
|
||||
<select id="node-input-scope-select">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="link in">
|
||||
<script type="text/html" data-template-name="link in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-row node-input-link-row"></div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="link out">
|
||||
<script type="text/html" data-template-name="link out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="comment">
|
||||
<script type="text/html" data-template-name="comment">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="unknown">
|
||||
<script type="text/html" data-template-name="unknown">
|
||||
<div class="form-tips"><span data-i18n="[html]unknown.tip"></span></div>
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="function">
|
||||
<script type="text/html" data-template-name="function">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div>
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
|
||||
<script type="text/html" data-template-name="change">
|
||||
<style>
|
||||
ol#node-input-rule-container .red-ui-typedInput-container {
|
||||
flex:1;
|
||||
}
|
||||
</style>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
@@ -81,6 +76,11 @@
|
||||
var replace = this._("change.action.replace");
|
||||
var regex = this._("change.label.regex");
|
||||
|
||||
function resizeRule(rule) {
|
||||
var newWidth = rule.width();
|
||||
rule.find('.red-ui-typedInput').typedInput("width",newWidth-130);
|
||||
|
||||
}
|
||||
$('#node-input-rule-container').css('min-height','150px').css('min-width','450px').editableList({
|
||||
addItem: function(container,i,opt) {
|
||||
var rule = opt;
|
||||
@@ -106,11 +106,10 @@
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap'
|
||||
});
|
||||
let fragment = document.createDocumentFragment();
|
||||
var row1 = $('<div/>',{style:"display:flex;"}).appendTo(fragment);
|
||||
var row2 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(fragment);
|
||||
var row3 = $('<div/>',{style:"margin-top:8px;"}).appendTo(fragment);
|
||||
var row4 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(fragment);
|
||||
var row1 = $('<div/>').appendTo(container);
|
||||
var row2 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container);
|
||||
var row3 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container);
|
||||
var row4 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container);
|
||||
|
||||
var selectField = $('<select/>',{class:"node-input-rule-type",style:"width:110px; margin-right:10px;"}).appendTo(row1);
|
||||
var selectOptions = [{v:"set",l:set},{v:"change",l:change},{v:"delete",l:del},{v:"move",l:move}];
|
||||
@@ -125,82 +124,41 @@
|
||||
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
|
||||
.text(to)
|
||||
.appendTo(row2);
|
||||
|
||||
function createPropertyValue() {
|
||||
return $('<input/>',{class:"node-input-rule-property-value",type:"text"})
|
||||
var propertyValue = $('<input/>',{class:"node-input-rule-property-value",type:"text"})
|
||||
.appendTo(row2)
|
||||
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
|
||||
}
|
||||
|
||||
var row3_1 = $('<div/>', {style:"display:flex;"}).appendTo(row3);
|
||||
var row3_1 = $('<div/>').appendTo(row3);
|
||||
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
|
||||
.text(search)
|
||||
.appendTo(row3_1);
|
||||
|
||||
function createFromValue() {
|
||||
return $('<input/>',{class:"node-input-rule-property-search-value",type:"text"})
|
||||
var fromValue = $('<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']});
|
||||
}
|
||||
|
||||
var row3_2 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(row3);
|
||||
var row3_2 = $('<div/>',{style:"margin-top:8px;"}).appendTo(row3);
|
||||
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
|
||||
.text(replace)
|
||||
.appendTo(row3_2);
|
||||
|
||||
function createToValue() {
|
||||
return $('<input/>',{class:"node-input-rule-property-replace-value",type:"text"})
|
||||
var toValue = $('<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']});
|
||||
}
|
||||
|
||||
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
|
||||
.text(to)
|
||||
.appendTo(row4);
|
||||
|
||||
function createMoveValue() {
|
||||
return $('<input/>',{class:"node-input-rule-property-move-value",type:"text"})
|
||||
var moveValue = $('<input/>',{class:"node-input-rule-property-move-value",type:"text"})
|
||||
.appendTo(row4)
|
||||
.typedInput({default:'msg',types:['msg','flow','global']});
|
||||
}
|
||||
|
||||
let propertyValue = null;
|
||||
let fromValue = null;
|
||||
let toValue = null;
|
||||
let moveValue = null;
|
||||
|
||||
selectField.on("change", function() {
|
||||
var width = $("#node-input-rule-container").width();
|
||||
var type = $(this).val();
|
||||
if (propertyValue) {
|
||||
propertyValue.typedInput('hide');
|
||||
}
|
||||
if (fromValue) {
|
||||
fromValue.typedInput('hide');
|
||||
}
|
||||
if (toValue) {
|
||||
toValue.typedInput('hide');
|
||||
}
|
||||
if (moveValue) {
|
||||
moveValue.typedInput('hide');
|
||||
}
|
||||
|
||||
if (type == "set") {
|
||||
if(!propertyValue) {
|
||||
propertyValue = createPropertyValue();
|
||||
}
|
||||
propertyValue.typedInput('show');
|
||||
row2.show();
|
||||
row3.hide();
|
||||
row4.hide();
|
||||
} else if (type == "change") {
|
||||
if(!fromValue) {
|
||||
fromValue = createFromValue();
|
||||
}
|
||||
fromValue.typedInput('show');
|
||||
if(!toValue) {
|
||||
toValue = createToValue();
|
||||
}
|
||||
toValue.typedInput('show');
|
||||
row2.hide();
|
||||
row3.show();
|
||||
row4.hide();
|
||||
@@ -209,48 +167,30 @@
|
||||
row3.hide();
|
||||
row4.hide();
|
||||
} else if (type == "move") {
|
||||
if(!moveValue) {
|
||||
moveValue = createMoveValue();
|
||||
}
|
||||
moveValue.typedInput('show');
|
||||
row2.hide();
|
||||
row3.hide();
|
||||
row4.show();
|
||||
}
|
||||
resizeRule(container);
|
||||
});
|
||||
|
||||
selectField.val(rule.t);
|
||||
propertyName.typedInput('value',rule.p);
|
||||
propertyName.typedInput('type',rule.pt);
|
||||
if (rule.t == "set") {
|
||||
if(!propertyValue) {
|
||||
propertyValue = createPropertyValue();
|
||||
}
|
||||
propertyValue.typedInput('value',rule.to);
|
||||
propertyValue.typedInput('type',rule.tot);
|
||||
}
|
||||
if (rule.t == "move") {
|
||||
if(!moveValue) {
|
||||
moveValue = createMoveValue();
|
||||
}
|
||||
moveValue.typedInput('value',rule.to);
|
||||
moveValue.typedInput('type',rule.tot);
|
||||
}
|
||||
if (rule.t == "change") {
|
||||
if(!fromValue) {
|
||||
fromValue = createFromValue();
|
||||
}
|
||||
fromValue.typedInput('value',rule.from);
|
||||
fromValue.typedInput('type',rule.fromt);
|
||||
if (!toValue) {
|
||||
toValue = createToValue();
|
||||
}
|
||||
toValue.typedInput('value',rule.to);
|
||||
toValue.typedInput('type',rule.tot);
|
||||
}
|
||||
propertyValue.typedInput('value',rule.to);
|
||||
propertyValue.typedInput('type',rule.tot);
|
||||
moveValue.typedInput('value',rule.to);
|
||||
moveValue.typedInput('type',rule.tot);
|
||||
fromValue.typedInput('value',rule.from);
|
||||
fromValue.typedInput('type',rule.fromt);
|
||||
toValue.typedInput('value',rule.to);
|
||||
toValue.typedInput('type',rule.tot);
|
||||
selectField.change();
|
||||
container[0].appendChild(fragment);
|
||||
|
||||
var newWidth = $("#node-input-rule-container").width();
|
||||
resizeRule(container);
|
||||
},
|
||||
resizeItem: resizeRule,
|
||||
removable: true,
|
||||
sortable: true
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="range">
|
||||
<script type="text/html" data-template-name="range">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:calc(70% - 1px)"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="template">
|
||||
<script type="text/html" data-template-name="template">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="delay">
|
||||
<script type="text/html" data-template-name="delay">
|
||||
<div class="form-row">
|
||||
<label for="node-input-delay-action"><i class="fa fa-tasks"></i> <span data-i18n="delay.action"></span></label>
|
||||
<select id="node-input-delay-action" style="width:270px !important">
|
||||
|
||||
@@ -107,7 +107,9 @@ module.exports = function(RED) {
|
||||
});
|
||||
}
|
||||
|
||||
var npay;
|
||||
this.on('input', function(msg) {
|
||||
if (node.op2type === "payl") { npay = RED.util.cloneMessage(msg); }
|
||||
processMessageQueue(msg);
|
||||
});
|
||||
|
||||
@@ -189,14 +191,16 @@ module.exports = function(RED) {
|
||||
}
|
||||
promise.then(() => {
|
||||
if (node.op2type === "payl") {
|
||||
node.send(npay[topic]);
|
||||
node.send(npay[topic]);
|
||||
delete npay[topic];
|
||||
}
|
||||
else {
|
||||
else {
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
node.send(msg2);
|
||||
node.send(msg2);
|
||||
}
|
||||
delete node.topics[topic];
|
||||
if (node.op2type === "payl") { node.send(npay); }
|
||||
else { node.send(msg2); }
|
||||
node.status({});
|
||||
}).catch(err => {
|
||||
node.error(err);
|
||||
@@ -252,6 +256,9 @@ module.exports = function(RED) {
|
||||
});
|
||||
}, node.duration);
|
||||
}
|
||||
// else {
|
||||
// if (node.op2type === "payl") {node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
|
||||
// }
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="exec">
|
||||
<script type="text/html" data-template-name="exec">
|
||||
<div class="form-row">
|
||||
<label for="node-input-command"><i class="fa fa-file"></i> <span data-i18n="exec.label.command"></span></label>
|
||||
<input type="text" id="node-input-command" data-i18n="[placeholder]exec.label.command">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="tls-config">
|
||||
<script type="text/html" data-template-name="tls-config">
|
||||
<div class="form-row" class="hide" id="node-config-row-uselocalfiles">
|
||||
<input type="checkbox" id="node-config-input-uselocalfiles" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-config-input-uselocalfiles" style="width: 70%;"><span data-i18n="tls.label.use-local-files"></label>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="http proxy">
|
||||
<script type="text/html" data-template-name="http proxy">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-config-input-name">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt in">
|
||||
<script type="text/html" data-template-name="mqtt in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
|
||||
<input type="text" id="node-input-broker">
|
||||
@@ -75,7 +75,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt out">
|
||||
<script type="text/html" data-template-name="mqtt out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
|
||||
<input type="text" id="node-input-broker">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="http in">
|
||||
<script type="text/html" data-template-name="http in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-method"><i class="fa fa-tasks"></i> <span data-i18n="httpin.label.method"></span></label>
|
||||
<select type="text" id="node-input-method" style="width:70%;">
|
||||
@@ -45,7 +45,7 @@
|
||||
<div id="node-input-tip" class="form-tips"><span data-i18n="httpin.tip.in"></span><code><span id="node-input-path"></span></code>.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="http response">
|
||||
<script type="text/html" data-template-name="http response">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="http request">
|
||||
<script type="text/html" data-template-name="http request">
|
||||
<div class="form-row">
|
||||
<label for="node-input-method"><i class="fa fa-tasks"></i> <span data-i18n="httpin.label.method"></span></label>
|
||||
<select type="text" id="node-input-method" style="width:70%;">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<!-- WebSocket Input Node -->
|
||||
<script type="text/x-red" data-template-name="websocket in">
|
||||
<script type="text/html" data-template-name="websocket in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-mode"><i class="fa fa-dot-circle-o"></i> <span data-i18n="websocket.label.type"></span></label>
|
||||
<select id="node-input-mode">
|
||||
@@ -198,7 +198,7 @@
|
||||
</script>
|
||||
|
||||
<!-- WebSocket out Node -->
|
||||
<script type="text/x-red" data-template-name="websocket out">
|
||||
<script type="text/html" data-template-name="websocket out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-mode"><i class="fa fa-dot-circle-o"></i> <span data-i18n="websocket.label.type"></span></label>
|
||||
<select id="node-input-mode">
|
||||
@@ -221,7 +221,7 @@
|
||||
</script>
|
||||
|
||||
<!-- WebSocket Server configuration node -->
|
||||
<script type="text/x-red" data-template-name="websocket-listener">
|
||||
<script type="text/html" data-template-name="websocket-listener">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
|
||||
<input id="node-config-input-path" type="text" placeholder="/ws/example">
|
||||
@@ -240,7 +240,7 @@
|
||||
</script>
|
||||
|
||||
<!-- WebSocket Client configuration node -->
|
||||
<script type="text/x-red" data-template-name="websocket-client">
|
||||
<script type="text/html" data-template-name="websocket-client">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
|
||||
<input id="node-config-input-path" type="text" placeholder="ws://example.com/ws">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="tcp in">
|
||||
<script type="text/html" data-template-name="tcp in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-server"><i class="fa fa-dot-circle-o"></i> <span data-i18n="tcpin.label.type"></span></label>
|
||||
<select id="node-input-server" style="width:120px; margin-right:5px;">
|
||||
@@ -108,7 +108,7 @@
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="tcp out">
|
||||
<script type="text/html" data-template-name="tcp out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-beserver"><i class="fa fa-dot-circle-o"></i> <span data-i18n="tcpin.label.type"></span></label>
|
||||
<select id="node-input-beserver" style="width:150px; margin-right:5px;">
|
||||
@@ -170,15 +170,16 @@
|
||||
$("#node-input-port-row").hide();
|
||||
$("#node-input-host-row").hide();
|
||||
$("#node-input-end-row").hide();
|
||||
} else if (sockettype == "client"){
|
||||
$("#node-input-port-row").show();
|
||||
$("#node-input-host-row").show();
|
||||
$("#node-input-end-row").show();
|
||||
} else {
|
||||
$("#node-input-port-row").show();
|
||||
$("#node-input-host-row").hide();
|
||||
$("#node-input-end-row").show();
|
||||
}
|
||||
|
||||
if (sockettype == "client") {
|
||||
$("#node-input-host-row").show();
|
||||
} else {
|
||||
$("#node-input-host-row").hide();
|
||||
}
|
||||
};
|
||||
updateOptions();
|
||||
$("#node-input-beserver").change(updateOptions);
|
||||
@@ -187,7 +188,7 @@
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="tcp request">
|
||||
<script type="text/html" data-template-name="tcp request">
|
||||
<div class="form-row">
|
||||
<label for="node-input-server"><i class="fa fa-globe"></i> <span data-i18n="tcpin.label.server"></span></label>
|
||||
<input type="text" id="node-input-server" placeholder="ip.address" style="width:45%">
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
-->
|
||||
|
||||
<!-- The Input Node -->
|
||||
<script type="text/x-red" data-template-name="udp in">
|
||||
<script type="text/html" data-template-name="udp in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.listen"></span></label>
|
||||
<select id="node-input-multicast" style='width:70%'>
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
|
||||
<!-- The Output Node -->
|
||||
<script type="text/x-red" data-template-name="udp out">
|
||||
<script type="text/html" data-template-name="udp out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="fa fa-envelope"></i> <span data-i18n="udp.label.send"></span></label>
|
||||
<select id="node-input-multicast" style="width:40%">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="csv">
|
||||
<script type="text/html" data-template-name="csv">
|
||||
<div class="form-row">
|
||||
<label for="node-input-temp"><i class="fa fa-list"></i> <span data-i18n="csv.label.columns"></span></label>
|
||||
<input type="text" id="node-input-temp" data-i18n="[placeholder]csv.placeholder.columns">
|
||||
@@ -28,11 +28,15 @@
|
||||
</div>
|
||||
<div class="form-row" style="padding-left:20px;">
|
||||
<label><i class="fa fa-sign-in"></i> <span data-i18n="csv.label.input"></span></label>
|
||||
<span data-i18n="csv.label.skip-s"></span> <input type="text" id="node-input-skip" style="width:30px; height:25px;"/> <span data-i18n="csv.label.skip-e"></span><br/>
|
||||
<span data-i18n="csv.label.skip-s"></span> <input type="text" id="node-input-skip" style="width:40px; height:25px;"/> <span data-i18n="csv.label.skip-e"></span><br/>
|
||||
<label> </label>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-hdrin"><label style="width:auto; margin-top:7px;" for="node-input-hdrin"><span data-i18n="csv.label.firstrow"></span></label><br/>
|
||||
<label> </label>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-strings"><label style="width:auto; margin-top:7px;" for="node-input-strings"><span data-i18n="csv.label.usestrings"></span></label><br/>
|
||||
<label> </label>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-include_empty_strings"><label style="width:auto; margin-top:7px;" for="node-input-include_empty_strings"><span data-i18n="csv.label.include_empty_strings"></span></label><br/>
|
||||
<label> </label>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-include_null_values"><label style="width:auto; margin-top:7px;" for="node-input-include_null_values"><span data-i18n="csv.label.include_null_values"></span></label><br/>
|
||||
</div>
|
||||
<div class="form-row" style="padding-left:20px;">
|
||||
<label><i class="fa fa-sign-out"></i> <span data-i18n="csv.label.output"></span></label>
|
||||
@@ -45,8 +49,13 @@
|
||||
<label style="width:100%;"><span data-i18n="csv.label.o2c"></span></label>
|
||||
</div>
|
||||
<div class="form-row" style="padding-left:20px;">
|
||||
<label><i class="fa fa-sign-in"></i> <span data-i18n="csv.label.output"></span></label>
|
||||
<input style="width:20px; vertical-align:top; margin-right:5px;" type="checkbox" id="node-input-hdrout"><label style="width:auto;" for="node-input-hdrout"><span data-i18n="csv.label.includerow"></span></span>
|
||||
<label><i class="fa fa-sign-out"></i> <span data-i18n="csv.label.output"></span></label>
|
||||
<!-- <input style="width:20px; vertical-align:top; margin-right:5px;" type="checkbox" id="node-input-hdrout"><label style="width:auto;" for="node-input-hdrout"><span data-i18n="csv.label.includerow"></span></span> -->
|
||||
<select style="width:60%" id="node-input-hdrout">
|
||||
<option value="none" data-i18n="csv.hdrout.none"></option>
|
||||
<option value="all" data-i18n="csv.hdrout.all"></option>
|
||||
<option value="once" data-i18n="csv.hdrout.once"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row" style="padding-left:20px;">
|
||||
<label></label>
|
||||
@@ -69,12 +78,14 @@
|
||||
sep: {value:',',required:true,validate:RED.validators.regex(/^.{1,2}$/)},
|
||||
//quo: {value:'"',required:true},
|
||||
hdrin: {value:""},
|
||||
hdrout: {value:""},
|
||||
hdrout: {value:"none"},
|
||||
multi: {value:"one",required:true},
|
||||
ret: {value:'\\n'},
|
||||
temp: {value:""},
|
||||
skip: {value:"0"},
|
||||
strings: {value:true}
|
||||
strings: {value:true},
|
||||
include_empty_strings: {value:""},
|
||||
include_null_values: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
@@ -86,6 +97,8 @@
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
if (this.hdrout === false) { this.hdrout = "none"; $("#node-input-hdrout").val("none"); }
|
||||
if (this.hdrout === true) { this.hdrout = "all"; $("#node-input-hdrout").val("all");}
|
||||
if (this.strings === undefined) { this.strings = true; $("#node-input-strings").prop('checked', true); }
|
||||
if (this.skip === undefined) { this.skip = 0; $("#node-input-skip").val("0");}
|
||||
$("#node-input-skip").spinner({ min:0 });
|
||||
|
||||
@@ -26,12 +26,16 @@ module.exports = function(RED) {
|
||||
this.lineend = "\n";
|
||||
this.multi = n.multi || "one";
|
||||
this.hdrin = n.hdrin || false;
|
||||
this.hdrout = n.hdrout || false;
|
||||
this.hdrout = n.hdrout || "none";
|
||||
this.goodtmpl = true;
|
||||
this.skip = parseInt(n.skip || 0);
|
||||
this.store = [];
|
||||
this.parsestrings = n.strings;
|
||||
this.include_empty_strings = n.include_empty_strings || false;
|
||||
this.include_null_values = n.include_null_values || false;
|
||||
if (this.parsestrings === undefined) { this.parsestrings = true; }
|
||||
if (this.hdrout === false) { this.hdrout = "none"; }
|
||||
if (this.hdrout === true) { this.hdrout = "all"; }
|
||||
var tmpwarn = true;
|
||||
var node = this;
|
||||
|
||||
@@ -49,14 +53,22 @@ module.exports = function(RED) {
|
||||
return col;
|
||||
}
|
||||
node.template = clean(node.template);
|
||||
node.hdrSent = false;
|
||||
|
||||
this.on("input", function(msg) {
|
||||
if (msg.hasOwnProperty("reset")) {
|
||||
node.hdrSent = false;
|
||||
}
|
||||
if (msg.hasOwnProperty("payload")) {
|
||||
if (typeof msg.payload == "object") { // convert object to CSV string
|
||||
try {
|
||||
var ou = "";
|
||||
if (node.hdrout) {
|
||||
if (node.hdrout !== "none" && node.hdrSent === false) {
|
||||
if ((node.template.length === 1) && (node.template[0] === '') && (msg.hasOwnProperty("columns"))) {
|
||||
node.template = clean((msg.columns || "").split(","));
|
||||
}
|
||||
ou += node.template.join(node.sep) + node.ret;
|
||||
if (node.hdrout === "once") { node.hdrSent = true; }
|
||||
}
|
||||
if (!Array.isArray(msg.payload)) { msg.payload = [ msg.payload ]; }
|
||||
for (var s = 0; s < msg.payload.length; s++) {
|
||||
@@ -75,13 +87,15 @@ module.exports = function(RED) {
|
||||
ou += msg.payload[s].join(node.sep) + node.ret;
|
||||
}
|
||||
else {
|
||||
if ((node.template.length === 1) && (node.template[0] === '') && (msg.hasOwnProperty("columns"))) {
|
||||
node.template = clean((msg.columns || "").split(","));
|
||||
}
|
||||
if ((node.template.length === 1) && (node.template[0] === '')) {
|
||||
/* istanbul ignore else */
|
||||
if (tmpwarn === true) { // just warn about missing template once
|
||||
node.warn(RED._("csv.errors.obj_csv"));
|
||||
tmpwarn = false;
|
||||
}
|
||||
ou = "";
|
||||
for (var p in msg.payload[0]) {
|
||||
/* istanbul ignore else */
|
||||
if (msg.payload[0].hasOwnProperty(p)) {
|
||||
@@ -125,6 +139,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
msg.payload = ou;
|
||||
msg.columns = node.template.join(',');
|
||||
if (msg.payload !== '') { node.send(msg); }
|
||||
}
|
||||
catch(e) { node.error(e,msg); }
|
||||
@@ -173,20 +188,29 @@ module.exports = function(RED) {
|
||||
}
|
||||
else if ((line[i] === node.sep) && f) { // if it is the end of the line then finish
|
||||
if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
|
||||
if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "" ) ) {
|
||||
if ( (node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
|
||||
o[node.template[j]] = k[j];
|
||||
if ( node.template[j] && (node.template[j] !== "") ) {
|
||||
// if no value between separators ('1,,"3"...') or if the line beings with separator (',1,"2"...') treat value as null
|
||||
if (line[i-1] === node.sep || line[i-1].includes('\n','\r')) k[j] = null;
|
||||
if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
|
||||
if (node.include_null_values && k[j] === null) o[node.template[j]] = k[j];
|
||||
if (node.include_empty_strings && k[j] === "") o[node.template[j]] = k[j];
|
||||
if (k[j] !== null && k[j] !== "") o[node.template[j]] = k[j];
|
||||
}
|
||||
j += 1;
|
||||
k[j] = "";
|
||||
// if separator is last char in processing string line (without end of line), add null value at the end - example: '1,2,3\n3,"3",'
|
||||
k[j] = line.length - 1 === i ? null : "";
|
||||
}
|
||||
else if ((line[i] === "\n") || (line[i] === "\r")) { // handle multiple lines
|
||||
else if (((line[i] === "\n") || (line[i] === "\r")) && f) { // handle multiple lines
|
||||
//console.log(j,k,o,k[j]);
|
||||
if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
|
||||
if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "") ) {
|
||||
if ( (node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
|
||||
else { k[j].replace(/\r$/,''); }
|
||||
o[node.template[j]] = k[j];
|
||||
if ( node.template[j] && (node.template[j] !== "") ) {
|
||||
// if separator before end of line, set null value ie. '1,2,"3"\n1,2,\n1,2,3'
|
||||
if (line[i-1] === node.sep) k[j] = null;
|
||||
if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
|
||||
else { if (k[j] !== null) k[j].replace(/\r$/,''); }
|
||||
if (node.include_null_values && k[j] === null) o[node.template[j]] = k[j];
|
||||
if (node.include_empty_strings && k[j] === "") o[node.template[j]] = k[j];
|
||||
if (k[j] !== null && k[j] !== "") o[node.template[j]] = k[j];
|
||||
}
|
||||
if (JSON.stringify(o) !== "{}") { // don't send empty objects
|
||||
a.push(o); // add to the array
|
||||
@@ -204,15 +228,19 @@ module.exports = function(RED) {
|
||||
// Finished so finalize and send anything left
|
||||
//console.log(j,k,o,k[j]);
|
||||
if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
|
||||
if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "") ) {
|
||||
if ( (node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
|
||||
else { k[j].replace(/\r$/,''); }
|
||||
o[node.template[j]] = k[j];
|
||||
|
||||
if ( node.template[j] && (node.template[j] !== "") ) {
|
||||
if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
|
||||
else { if (k[j] !== null) k[j].replace(/\r$/,''); }
|
||||
if (node.include_null_values && k[j] === null) o[node.template[j]] = k[j];
|
||||
if (node.include_empty_strings && k[j] === "") o[node.template[j]] = k[j];
|
||||
if (k[j] !== null && k[j] !== "") o[node.template[j]] = k[j];
|
||||
}
|
||||
if (JSON.stringify(o) !== "{}") { // don't send empty objects
|
||||
a.push(o); // add to the array
|
||||
}
|
||||
var has_parts = msg.hasOwnProperty("parts");
|
||||
|
||||
if (node.multi !== "one") {
|
||||
msg.payload = a;
|
||||
if (has_parts) {
|
||||
@@ -221,12 +249,14 @@ module.exports = function(RED) {
|
||||
}
|
||||
if (msg.parts.index + 1 === msg.parts.count) {
|
||||
msg.payload = node.store;
|
||||
msg.columns = node.template.filter(val => val).join(',');
|
||||
delete msg.parts;
|
||||
node.send(msg);
|
||||
node.store = [];
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.columns = node.template.filter(val => val).join(',');
|
||||
node.send(msg); // finally send the array
|
||||
}
|
||||
}
|
||||
@@ -234,6 +264,7 @@ module.exports = function(RED) {
|
||||
var len = a.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var newMessage = RED.util.cloneMessage(msg);
|
||||
newMessage.columns = node.template.filter(val => val).join(',');
|
||||
newMessage.payload = a[i];
|
||||
if (!has_parts) {
|
||||
newMessage.parts = {
|
||||
@@ -259,7 +290,11 @@ module.exports = function(RED) {
|
||||
}
|
||||
else { node.warn(RED._("csv.errors.csv_js")); }
|
||||
}
|
||||
else { node.send(msg); } // If no payload - just pass it on.
|
||||
else {
|
||||
if (!msg.hasOwnProperty("reset")) {
|
||||
node.send(msg); // If no payload and not reset - just pass it on.
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("csv",CSVNode);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="html">
|
||||
<script type="text/html" data-template-name="html">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="json">
|
||||
<script type="text/html" data-template-name="json">
|
||||
<div class="form-row">
|
||||
<label for="node-input-action"><i class="fa fa-dot-circle-o"></i> <span data-i18n="json.label.action"></span></label>
|
||||
<select style="width:70%" id="node-input-action">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="xml">
|
||||
<script type="text/html" data-template-name="xml">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="yaml">
|
||||
<script type="text/html" data-template-name="yaml">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="sort">
|
||||
<script type="text/html" data-template-name="sort">
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-target"><i class="fa fa-dot-circle-o"></i> <span data-i18n="sort.target"></span></label>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="watch">
|
||||
<script type="text/html" data-template-name="watch">
|
||||
<div class="form-row node-input-filename">
|
||||
<label for="node-input-files"><i class="fa fa-file"></i> <span data-i18n="watch.label.files"></span></label>
|
||||
<input id="node-input-files" type="text" tabindex="1" data-i18n="[placeholder]watch.placeholder.files">
|
||||
|
||||
1
packages/node_modules/@node-red/nodes/examples/batch/1_number-mode.json
vendored
Normal file
1
packages/node_modules/@node-red/nodes/examples/batch/1_number-mode.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"id":"bf16276d.2f1758","type":"tab","label":"Example: Number-based Group Mode","disabled":false,"info":"*Number-based Group mode* of batch node can be used to create new message sequences from incoming messages. Recently received *N*-messages are grouped to a sequence. Creating message sequences that has overwrap with adjacent message group is possible.\n"},{"id":"f5a82278.78d6c","type":"batch","z":"bf16276d.2f1758","name":"","mode":"count","count":"5","overlap":0,"interval":"5","allowEmptySequence":false,"topics":[],"x":370,"y":232,"wires":[["b1e514ed.44f328"]]},{"id":"43720065.2891d","type":"comment","z":"bf16276d.2f1758","name":"Group 5 consecutive messages","info":"","x":170,"y":60,"wires":[]},{"id":"b1e514ed.44f328","type":"join","z":"bf16276d.2f1758","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":510,"y":232,"wires":[["457e5970.8ceaa8"]]},{"id":"457e5970.8ceaa8","type":"debug","z":"bf16276d.2f1758","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":670,"y":232,"wires":[]},{"id":"8e3d3ceb.bd0fe","type":"comment","z":"bf16276d.2f1758","name":"↑ create message sequence with 5 messages","info":"","x":490,"y":272,"wires":[]},{"id":"fbe20ae3.cbb6f8","type":"comment","z":"bf16276d.2f1758","name":"↓ join sequence to array","info":"","x":560,"y":192,"wires":[]},{"id":"7ebafe58.2a112","type":"inject","z":"bf16276d.2f1758","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":152,"wires":[["589603c4.1cb5fc"]]},{"id":"589603c4.1cb5fc","type":"function","z":"bf16276d.2f1758","name":"send: 0-49","func":"for(var x = 0; x < 50; x++) {\n node.send({payload: x});\n}","outputs":1,"noerr":0,"x":310,"y":152,"wires":[["f5a82278.78d6c"]]},{"id":"9b59b72c.fcd8f8","type":"comment","z":"bf16276d.2f1758","name":"↓ send sequence: 0-49","info":"","x":340,"y":112,"wires":[]},{"id":"6421756f.6abd5c","type":"batch","z":"bf16276d.2f1758","name":"","mode":"count","count":"5","overlap":"1","interval":"5","allowEmptySequence":false,"topics":[],"x":370,"y":500,"wires":[["199cf232.743e7e"]]},{"id":"657b6a53.2a1fc4","type":"comment","z":"bf16276d.2f1758","name":"Group 5 consecutive messages with overlap of 1 msg","info":"","x":240,"y":328,"wires":[]},{"id":"199cf232.743e7e","type":"join","z":"bf16276d.2f1758","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":510,"y":500,"wires":[["91d29dda.d8a4f"]]},{"id":"91d29dda.d8a4f","type":"debug","z":"bf16276d.2f1758","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":670,"y":500,"wires":[]},{"id":"8bd4d407.aa2af8","type":"comment","z":"bf16276d.2f1758","name":"↑ create message sequence with 5 messages with overlap of 1 msg","info":"","x":560,"y":540,"wires":[]},{"id":"a49ea57d.8d2458","type":"comment","z":"bf16276d.2f1758","name":"↓ join sequence to array","info":"","x":560,"y":460,"wires":[]},{"id":"f689d1b3.90e4b","type":"inject","z":"bf16276d.2f1758","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":420,"wires":[["c021cf24.ad03e"]]},{"id":"c021cf24.ad03e","type":"function","z":"bf16276d.2f1758","name":"send: 0-49","func":"for(var x = 0; x < 50; x++) {\n node.send({payload: x});\n}","outputs":1,"noerr":0,"x":310,"y":420,"wires":[["6421756f.6abd5c"]]},{"id":"8da6e576.901a18","type":"comment","z":"bf16276d.2f1758","name":"↓ send sequence: 0-49","info":"","x":340,"y":380,"wires":[]}]
|
||||
1
packages/node_modules/@node-red/nodes/examples/batch/2_time-mode.json
vendored
Normal file
1
packages/node_modules/@node-red/nodes/examples/batch/2_time-mode.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"id":"82a01f29.86de","type":"tab","label":"Example: Time-based Group Mode","disabled":false,"info":"*Time-based Group mode* of batch node can be used to create new message sequences from incoming messages received within specified time range. \n"},{"id":"9a7f6539.6e36d8","type":"batch","z":"82a01f29.86de","name":"","mode":"interval","count":10,"overlap":0,"interval":"5","allowEmptySequence":false,"topics":[],"x":350,"y":260,"wires":[["e54a3b57.3677f8"]]},{"id":"71dc607e.98aab","type":"comment","z":"82a01f29.86de","name":"Group messages received within 5s","info":"","x":180,"y":80,"wires":[]},{"id":"e54a3b57.3677f8","type":"join","z":"82a01f29.86de","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":490,"y":260,"wires":[["1e263cac.6641f3"]]},{"id":"1e263cac.6641f3","type":"debug","z":"82a01f29.86de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":650,"y":260,"wires":[]},{"id":"324c7b93.0db734","type":"comment","z":"82a01f29.86de","name":"↑ create message sequence received within 5s","info":"","x":480,"y":300,"wires":[]},{"id":"fb112bae.fbe428","type":"comment","z":"82a01f29.86de","name":"↓ join sequence to array","info":"","x":540,"y":220,"wires":[]},{"id":"34f8dda5.2864c2","type":"inject","z":"82a01f29.86de","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":160,"wires":[["c9e23ee4.ce535"]]},{"id":"c9e23ee4.ce535","type":"function","z":"82a01f29.86de","name":"send: 0-49","func":"for(var x = 0; x < 100; x++) {\n node.send({payload: x});\n}","outputs":1,"noerr":0,"x":310,"y":160,"wires":[["7026e0cc.4e3c3"]]},{"id":"7026e0cc.4e3c3","type":"delay","z":"82a01f29.86de","name":"","pauseType":"rate","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":490,"y":160,"wires":[["9a7f6539.6e36d8"]]},{"id":"40f8c766.6ed198","type":"comment","z":"82a01f29.86de","name":"↓ send sequence: 0-49","info":"","x":340,"y":120,"wires":[]}]
|
||||
1
packages/node_modules/@node-red/nodes/examples/batch/3_concatenate-mode.json
vendored
Normal file
1
packages/node_modules/@node-red/nodes/examples/batch/3_concatenate-mode.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"id":"845b226d.a4b18","type":"tab","label":"Example: Concatenate Mode","disabled":false,"info":"*Concatenate mode* of batch node can be used to combine input message sequences to create a new message sequence. Order of the sequences can be specified using message topic assigned to each message in a sequence. Message sequence can be specified multiple times.\n"},{"id":"72afe7b0.38b9d8","type":"inject","z":"845b226d.a4b18","name":"","topic":"SEQ","payload":"[1,2,3,4,5]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":100,"wires":[["6dea90dd.c442c"]]},{"id":"6dea90dd.c442c","type":"split","z":"845b226d.a4b18","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":330,"y":100,"wires":[["3ac93a4b.ddbbc6"]]},{"id":"3ac93a4b.ddbbc6","type":"batch","z":"845b226d.a4b18","name":"","mode":"concat","count":10,"overlap":0,"interval":10,"allowEmptySequence":false,"topics":[{"topic":"SEQ"},{"topic":"SEQ"}],"x":470,"y":100,"wires":[["48ec7040.56f5f"]]},{"id":"48ec7040.56f5f","type":"join","z":"845b226d.a4b18","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":610,"y":100,"wires":[["902613c4.769b5"]]},{"id":"902613c4.769b5","type":"debug","z":"845b226d.a4b18","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":770,"y":100,"wires":[]},{"id":"a84cf2e1.65adc","type":"comment","z":"845b226d.a4b18","name":"Duplicate","info":"","x":100,"y":60,"wires":[]},{"id":"3256f015.45c36","type":"inject","z":"845b226d.a4b18","name":"","topic":"SEQ","payload":"[1,-6,-8,7,2,-3]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":220,"wires":[["c308dcb2.621da"]]},{"id":"c308dcb2.621da","type":"split","z":"845b226d.a4b18","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":330,"y":220,"wires":[["2222098b.7fd036"]]},{"id":"247a5fab.239cc","type":"comment","z":"845b226d.a4b18","name":"Filter & Concat","info":"","x":120,"y":180,"wires":[]},{"id":"2222098b.7fd036","type":"switch","z":"845b226d.a4b18","name":"","property":"payload","propertyType":"msg","rules":[{"t":"gt","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":true,"outputs":2,"x":390,"y":280,"wires":[["56e3a974.2bfde8"],["86a1b43a.ff4cb8"]]},{"id":"cd00a796.e4e478","type":"comment","z":"845b226d.a4b18","name":"↑ Duplicate SEQ","info":"","x":500,"y":140,"wires":[]},{"id":"56e3a974.2bfde8","type":"change","z":"845b226d.a4b18","name":"Topic←POS","rules":[{"t":"set","p":"topic","pt":"msg","to":"POS","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":240,"wires":[["fe90d65d.a6b548"]]},{"id":"86a1b43a.ff4cb8","type":"change","z":"845b226d.a4b18","name":"Topic←NEG","rules":[{"t":"set","p":"topic","pt":"msg","to":"NEG","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":300,"wires":[["fe90d65d.a6b548"]]},{"id":"fe90d65d.a6b548","type":"batch","z":"845b226d.a4b18","name":"","mode":"concat","count":10,"overlap":0,"interval":10,"allowEmptySequence":false,"topics":[{"topic":"NEG"},{"topic":"POS"}],"x":710,"y":280,"wires":[["5b089f16.62b96"]]},{"id":"2f46c0af.bff71","type":"debug","z":"845b226d.a4b18","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":930,"y":220,"wires":[]},{"id":"5b089f16.62b96","type":"join","z":"845b226d.a4b18","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":770,"y":220,"wires":[["2f46c0af.bff71"]]},{"id":"e069eb28.6eb358","type":"comment","z":"845b226d.a4b18","name":"↑ Order sequence: negative→positive","info":"","x":810,"y":320,"wires":[]},{"id":"aeae162b.efd118","type":"comment","z":"845b226d.a4b18","name":"Filter pos/neg and make separate sequence↑ (but not a simple sort) ","info":"","x":320,"y":340,"wires":[]}]
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="inject">
|
||||
<script type="text/html" data-help-name="inject">
|
||||
<p> Injiziert eine Nachricht manuell oder in regelmäßigen Intervallen in einen Nachrichtenflow.
|
||||
Bei den Nutzdaten kann es sich um eine Vielzahl von Typen handeln, einschließlich Zeichenfolgen, JavaScript-Objekte oder die aktuelle Zeit. </p>
|
||||
<h3> Ausgaben </h3>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="debug">
|
||||
<script type="text/html" data-help-name="debug">
|
||||
<p> Zeigt die ausgewählten Nachrichteneigenschaften auf der Registerkarte "Debug" und
|
||||
optional im Laufzeitprotokoll an. Standardmäßig wird <code>msg.payload</code> angezeigt. </p>
|
||||
<h3> Details </h3>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="catch">
|
||||
<script type="text/html" data-help-name="catch">
|
||||
<p> Fängt Fehler von Nodes auf derselben Registerkarte ab. </p>
|
||||
<h3> Ausgaben </h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="status">
|
||||
<script type="text/html" data-help-name="status">
|
||||
<p> Berichtet Statusnachrichten von anderen Node auf derselben Registerkarte. </p>
|
||||
<h3> Ausgaben </h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="link in">
|
||||
<script type="text/html" data-help-name="link in">
|
||||
<p> Erstellt virtuelle Verbindungen zwischen Flows. </p>
|
||||
<h3> Details </h3>
|
||||
<p> Der Node kann mit jedem beliebigen <code>Link-out</code> Node auf einer beliebigen Registerkarte verbunden werden.
|
||||
@@ -25,7 +25,7 @@
|
||||
<p> <b> Hinweis: </b> Links können nicht in einem Subflow erstellt oder aus einem Subflow heraus erstellt werden. </p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="link out">
|
||||
<script type="text/html" data-help-name="link out">
|
||||
<p> Erstellt virtuelle Verbindungen zwischen Flows. </p>
|
||||
<h3> Details </h3>
|
||||
<p> Der Node kann mit jedem beliebigen <code>Link-out</code> Node auf einer beliebigen Registerkarte verbunden werden.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="comment">
|
||||
<script type="text/html" data-help-name="comment">
|
||||
<p>Ein Node, der zur Kommentierung der Flows verwendet werden kann.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Das Textfeld des Node akzeptiert die Markdown Syntax. Der eingegebene Text wird dann in diesem Informations Panel angezeigt.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="unknown">
|
||||
<script type="text/html" data-help-name="unknown">
|
||||
<p>Dieser Node ist von einem Typ, der in der aktuellen Node-RED Installation unbekannt ist.</p>
|
||||
<h3>Details</h3>
|
||||
<p><i>Wenn der Flow im aktuellen Zustand eingesetzt wird, bleibt die Konfiguration erhalten
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="function">
|
||||
<script type="text/html" data-help-name="function">
|
||||
<p> Ein JavaScript-Funktionsblock, der für die Nachrichten ausgeführt werden soll, die vom Node empfangen werden. </p>
|
||||
<p> Die Nachrichten werden als JavaScript-Objekt mit dem Namen <code>msg</code> übergeben. </p>
|
||||
<p> Er erwartet eine Eigenschaft <code> msg.payload </code> , die den Hauptteil der Nachricht enthält. </p>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="switch">
|
||||
<script type="text/html" data-help-name="switch">
|
||||
<p>Weiterleitung von Nachrichten basierend auf den Werten ihrer Eigenschaften oder der Position der Sequenz.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Wenn eine Nachricht ankommt, wertet der Node jede der definierten Regeln aus
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="change">
|
||||
<script type="text/html" data-help-name="change">
|
||||
<p>Setzen, Ändern, Löschen oder Verschieben von Eigenschaften einer Nachricht, eines Flow-Kontextes oder eines globalen Kontextes.</p>
|
||||
<p>Der Node kann mehrere Regeln angeben, die in der Reihenfolge ihrer Definition angewendet werden.</p>
|
||||
<h3>Details</h3>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="range">
|
||||
<script type="text/html" data-help-name="range">
|
||||
<p>Ordnet einen numerischen Wert einem anderen Bereich zu..</p>
|
||||
<h3>Eingaben</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="template">
|
||||
<script type="text/html" data-help-name="template">
|
||||
<p> Legt eine Eigenschaft fest, die auf der bereitgestellten Vorlage basiert. </p>
|
||||
<h3> Eingaben </h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="delay">
|
||||
<script type="text/html" data-help-name="delay">
|
||||
<p> Verzögert jede Nachricht, die den Node durchläuft oder begrenzt die Geschwindigkeit, mit der sie übergeben werden können. </p>
|
||||
<h3> Eingaben </h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="trigger">
|
||||
<script type="text/html" data-help-name="trigger">
|
||||
<p> Wenn der Trigger ausgelöst wird, kann eine Nachricht gesendet werden und dann optional eine weitere Nachricht ,
|
||||
sofern der Trigger nicht verlängert oder zurückgesetzt wird. </p>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="exec">
|
||||
<script type="text/html" data-help-name="exec">
|
||||
<p> Führt einen Systembefehl aus und gibt seine Ausgabe zurück. </p>
|
||||
<p> Der Node kann so konfiguriert werden, dass er entweder wartet, bis der Befehl abgeschlossen ist,
|
||||
oder die Ausgabe so sendet wie der Befehl sie generiert. </p>
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="tls-config">
|
||||
<script type="text/html" data-help-name="tls-config">
|
||||
<p>Konfigurationsoptionen für TLS Verbindungen.</p>
|
||||
</script>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="http proxy">
|
||||
<script type="text/html" data-help-name="http proxy">
|
||||
<p>Konfigurationsoptionen für den HTTP Proxy.</p>
|
||||
|
||||
<h3>Details</h3>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt in">
|
||||
<script type="text/html" data-help-name="mqtt in">
|
||||
<p> Stellt eine Verbindung zu einem MQTT-Broker her und subskribiert Nachrichten zu dem angegebenen Topic. </p>
|
||||
<h3> Ausgaben </h3>
|
||||
<dl class="message-properties">
|
||||
@@ -31,7 +31,7 @@
|
||||
<p> Mehrere MQTT-Nodes (in oder out) können bei Bedarf dieselbe Brokerverbindung nutzen. </p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt out">
|
||||
<script type="text/html" data-help-name="mqtt out">
|
||||
<p>Stellt eine Verbindung zu einem MQTT-Broker her und publiziert Nachrichten.</p>
|
||||
<h3>Eingaben</h3>
|
||||
<dl class="message-properties">
|
||||
@@ -61,7 +61,7 @@
|
||||
<p>Mehrere MQTT-Nodes (in oder out) können bei Bedarf dieselbe Brokerverbindung nutzen.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt-broker">
|
||||
<script type="text/html" data-help-name="mqtt-broker">
|
||||
<p> Konfiguration für eine Verbindung zu einem MQTT-Broker. </p>
|
||||
<p> Diese Konfiguration erstellt eine Verbindung zu einem Broker, die anschließend von den
|
||||
Nodes <code>MQTT In</code> und <code>MQTT Out</code> verwendet werden. </p>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="http in">
|
||||
<script type="text/html" data-help-name="http in">
|
||||
<p>Erstellt einen HTTP Endpunkt zur Erzeugung von Web Services.</p>
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
@@ -53,7 +53,7 @@
|
||||
muss einen code>HTTP Response</code> Node enthalten, um die Anforderung abzuschließen. </p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="http response">
|
||||
<script type="text/html" data-help-name="http response">
|
||||
<p>Sendet Antworten auf Anforderungen, die von einem code>HTTP In</code> Node empfangen wurden. </p>
|
||||
<h3>Eingaben</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="http request">
|
||||
<script type="text/html" data-help-name="http request">
|
||||
<p>Sendet HTTP-Anforderungen und gibt die Antwort zurück.</p>
|
||||
|
||||
<h3>Eingaben</h3>
|
||||
|
||||
@@ -14,29 +14,29 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="websocket in">
|
||||
<script type="text/html" data-help-name="websocket in">
|
||||
<p>WebSocket Eingangs-Node.</p>
|
||||
<p>Standardmäßig befinden sich die vom WebSocket empfangenen Daten in <code>msg.payload</code>.
|
||||
Der Socket kann konfiguriert werden, um einen korrekt gebildeten JSON-String zu erwarten,
|
||||
in diesem Fall wird er das JSON analysieren und das resultierende Objekt als gesamte Nachricht senden.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="websocket out">
|
||||
<script type="text/html" data-help-name="websocket out">
|
||||
<p>WebSocket Ausgabe-Node.</p>
|
||||
<p>Standardmäßig wird <code>msg.payload</code> über den WebSocket gesendet.
|
||||
<p>Standardmäßig wird <code>msg.payload</code> über den WebSocket gesendet.
|
||||
Der Socket kann so konfiguriert werden, dass er das gesamte <code>msg</code> Objekt als JSON-String kodiert und über den WebSocket sendet.</p>
|
||||
|
||||
<p>Wenn die an diesem Node ankommende Nachricht an einem WebSocket-Eingangs-Node begann,
|
||||
wird die Nachricht an den Client zurückgesendet, der den Flow ausgelöst hat.
|
||||
wird die Nachricht an den Client zurückgesendet, der den Flow ausgelöst hat.
|
||||
Andernfalls wird die Nachricht an alle verbundenen Clients gesendet..</p>
|
||||
<p>Wenn eine Nachricht, die an einem WebSocket-Eingangsnoten gestartet wurde, an alle verbunden Clients gesendet werden soll,
|
||||
<p>Wenn eine Nachricht, die an einem WebSocket-Eingangsnoten gestartet wurde, an alle verbunden Clients gesendet werden soll,
|
||||
muss die Eigenschaft <code>msg._session</code> innerhalb des Flow gelöscht werden.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="websocket-listener">
|
||||
<script type="text/html" data-help-name="websocket-listener">
|
||||
<p>Dieser Konfigurations-Node erstellt einen WebSocket Server-Endpunkt unter Verwendung des angegebenen Pfades.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="websocket-client">
|
||||
<script type="text/html" data-help-name="websocket-client">
|
||||
<p>Dieser Konfigurations-Node verbindet einen WebSocket-Client mit der angegebenen URL.</p>
|
||||
</script>
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="tcp in">
|
||||
<script type="text/html" data-help-name="tcp in">
|
||||
<p>Bietet eine Auswahl an TCP-Eingängen. Kann sich entweder mit einem entfernten TCP-Port verbinden oder eingehende Verbindungen akzeptieren.</p>
|
||||
<p><b>Note: </b>Auf einigen Systemen benötigen Sie möglicherweise Root- oder Administratorzugriff, um
|
||||
Ports unter 1024 und/oder Broadcast nutzen zu können.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="tcp out">
|
||||
<script type="text/html" data-help-name="tcp out">
|
||||
<p>Bietet eine Auswahl an TCP-Ausgängen. Kann sich entweder mit einem entfernten TCP-Port verbinden,
|
||||
eingehende Verbindungen akzeptieren oder auf Nachrichten antworten, die von einem TCP-In-Node empfangen werden.</p>
|
||||
<p>Nur der Inhalt von <code>msg.payload</code> wird gesendet.</p>
|
||||
@@ -32,7 +32,7 @@
|
||||
Ports unter 1024 und/oder Broadcast nutzen zu können.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="tcp request">
|
||||
<script type="text/html" data-help-name="tcp request">
|
||||
<p>Ein einfacher TCP-Anforderungs-Node - sendet die <code>msg.payload</code> an einen Server-TCP-Port und erwartet eine Antwort.</p>
|
||||
<p>Verbindet sich, sendet die "Anforderung" und liest die "Antwort". Der Node wartet entweder auf eine vorgegebene Anzahl von
|
||||
Zeichen in einen festen Buffer, auf ein bestimmtes Zeichen oder einen festen Timeout ab der ersten Antwort,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="udp in">
|
||||
<script type="text/html" data-help-name="udp in">
|
||||
<p>Ein UDP-Eingangs-Node, der eine <code>msg.payload</code> erzeugt, die einen
|
||||
Buffer, Strings oder base64-kodierter String enthält. Multicast wird unterstützt.</p>
|
||||
<p>Über die Eigenschaften <code>msg.ip</code> und <code>msg.port</code> kann auf die Werte der
|
||||
@@ -23,7 +23,7 @@
|
||||
Ports unter 1024 und/oder Broadcast nutzen zu können.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="udp out">
|
||||
<script type="text/html" data-help-name="udp out">
|
||||
<p>Dieser Node sendet <code>msg.payload</code> an den angegebenen UDP-Host und Port. Multicast wird unterstützt.</p>
|
||||
<p>Sie können <code>msg.ip</code> und <code>msg.port</code> verwenden, um die Zielwerte festzulegen,
|
||||
aber die statisch im Node konfigurierten Werte haben Vorrang.</p>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="csv">
|
||||
<script type="text/html" data-help-name="csv">
|
||||
<p>Konvertiert zwischen einem CSV-formatierten String und ihrer JavaScript-Objektdarstellung in beide Richtungen.</p>
|
||||
<h3>Eingaben</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="html">
|
||||
<script type="text/html" data-help-name="html">
|
||||
<p>Extrahiert unter Verwendung eines CSS-Selektors Elemente aus einem HTML-Dokument, das sich in <code>msg.payload</code> befindet.</p>
|
||||
<h3>Eingaben</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="json">
|
||||
<script type="text/html" data-help-name="json">
|
||||
<p>Konvertiert zwischen einem JSON-String und seiner JavaScript-Objektdarstellung in beide Richtungen.</p>
|
||||
<h3>Eingaben</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="xml">
|
||||
<script type="text/html" data-help-name="xml">
|
||||
<p>Konvertiert zwischen einem XML-String und seiner JavaScript-Objektdarstellung - in beiden Richtungen.</p>
|
||||
<h3>Eingaben</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="yaml">
|
||||
<script type="text/html" data-help-name="yaml">
|
||||
<p>Konvertiert zwischen einer YAML-formatierten String und ihrer JavaScript-Objektdarstellung in beide Richtungen.</p>
|
||||
<h3>Eingaben</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="split">
|
||||
<script type="text/html" data-help-name="split">
|
||||
<p>Teilt eine Nachricht in eine Folge von Nachrichten auf.</p>
|
||||
|
||||
<h3>Eingaben</h3>
|
||||
@@ -62,7 +62,7 @@
|
||||
Das bedeutet, dass er nicht mit dem <b>join</b> Node im Automatikmodus verwendet werden kann.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="join">
|
||||
<script type="text/html" data-help-name="join">
|
||||
<p>Verbindet Sequenzen von Nachrichten zu einer einzigen Nachricht.</p>
|
||||
<p>Es sind drei Modi verfügbar:</p>
|
||||
<dl>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="sort">
|
||||
<script type="text/html" data-help-name="sort">
|
||||
<p>Eine Funktion, die die Nachrichteneigenschaft oder eine Folge von Nachrichten sortiert.</p>
|
||||
<p>Wenn der Node konfiguriert ist, um die Nachrichteneigenschaft zu sortieren,
|
||||
sortiert er Array-Daten, auf die von der angegebenen Nachrichteneigenschaft verwiesen wird.</p>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="batch">
|
||||
<script type="text/html" data-help-name="batch">
|
||||
<p>Erstellt Sequenzen von Nachrichten nach verschiedenen Regeln.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Es gibt drei Modi für die Erstellung von Nachrichtensequenzen:</p>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user