mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge remote-tracking branch 'upstream/master' into stop-start-flows
This commit is contained in:
commit
3cef2bb7e0
39
CHANGELOG.md
39
CHANGELOG.md
@ -1,3 +1,42 @@
|
|||||||
|
#### 3.0.0-beta.3: Beta Release
|
||||||
|
|
||||||
|
Editor
|
||||||
|
|
||||||
|
- Add Right-Click content menu (#3678) @knolleary
|
||||||
|
- Fix disable junction (#3671) @HiroyasuNishiyama
|
||||||
|
- Add Japanese translations for v2.2.3 (#3672) @kazuhitoyokoi
|
||||||
|
- Reset mouse state when switching tabs (#3643) @knolleary
|
||||||
|
- Fix uncorrect fix of junction to subflow conversion (#3666) @HiroyasuNishiyama
|
||||||
|
- Fix undoing junction to subflow (#3653) @HiroyasuNishiyama
|
||||||
|
- Fix conversion of junction to subflow (#3652) @HiroyasuNishiyama
|
||||||
|
- Fix to include junction to exported nodes (#3650) @HiroyasuNishiyama
|
||||||
|
- Fix z-index value for shade to cover nodes in palette (#3649) @kazuhitoyokoi
|
||||||
|
- Fix to extend escaped subflow category characters (#3647) @HiroyasuNishiyama
|
||||||
|
- Fix to sanitize tab name (#3646) @HiroyasuNishiyama
|
||||||
|
- Fix selector placement (#3644) @bonanitech
|
||||||
|
- Add Japanese translations for v3.0-beta.2 (#3622) @kazuhitoyokoi
|
||||||
|
- Fix new folder menu of save to library dialog (#3633) @HiroyasuNishiyama
|
||||||
|
- Fix layer of palette node (#3638) @HiroyasuNishiyama
|
||||||
|
- Fix to place a node dragged from palette within the workspace (#3637) @HiroyasuNishiyama
|
||||||
|
- Fix typo in CSS (#3628) @bonanitech
|
||||||
|
- Use the correct variable for the gutter text color (#3615) @bonanitech
|
||||||
|
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
|
||||||
|
- Support loading node modules from `nodesdir` (#3676) @Steve-Mcl
|
||||||
|
- fix buffer parse error message of evaluateNodeProperty (#3624) @HiroyasuNishiyama
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- File: Further simplify file node filename entry UX (v3) (#3677) @Steve-Mcl
|
||||||
|
- Function: Fix initial cursor position of init/finalize tab of function node (#3674) @HiroyasuNishiyama
|
||||||
|
- Function: Fix ESM module loading in Function node (#3645) @knolleary
|
||||||
|
- Inject: Fix JSONata evaluation of inject button (#3632) @HiroyasuNishiyama
|
||||||
|
- TCP: Dont delete TCP socket twice (#3630) @Steve-Mcl
|
||||||
|
- MQTT Node: define noproxy variable (#3626) @Steve-Mcl
|
||||||
|
- Debug: i18n debug sidebar node label (#3623) @HiroyasuNishiyama
|
||||||
|
|
||||||
#### 3.0.0-beta.2: Beta Release
|
#### 3.0.0-beta.2: Beta Release
|
||||||
|
|
||||||
**Migration from 2.x**
|
**Migration from 2.x**
|
||||||
|
@ -193,6 +193,7 @@ module.exports = function(grunt) {
|
|||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
|
||||||
|
"packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js",
|
"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/typeSearch.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
|
||||||
|
14
package.json
14
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red",
|
"name": "node-red",
|
||||||
"version": "3.0.0-beta.2",
|
"version": "3.0.0-beta.3",
|
||||||
"description": "Low-code programming for event-driven applications",
|
"description": "Low-code programming for event-driven applications",
|
||||||
"homepage": "http://nodered.org",
|
"homepage": "http://nodered.org",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@ -49,7 +49,7 @@
|
|||||||
"hash-sum": "2.0.0",
|
"hash-sum": "2.0.0",
|
||||||
"hpagent": "1.0.0",
|
"hpagent": "1.0.0",
|
||||||
"https-proxy-agent": "5.0.1",
|
"https-proxy-agent": "5.0.1",
|
||||||
"i18next": "21.8.2",
|
"i18next": "21.8.10",
|
||||||
"iconv-lite": "0.6.3",
|
"iconv-lite": "0.6.3",
|
||||||
"is-utf8": "0.2.1",
|
"is-utf8": "0.2.1",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
@ -62,7 +62,7 @@
|
|||||||
"moment": "2.29.3",
|
"moment": "2.29.3",
|
||||||
"moment-timezone": "0.5.34",
|
"moment-timezone": "0.5.34",
|
||||||
"mqtt": "4.3.7",
|
"mqtt": "4.3.7",
|
||||||
"multer": "1.4.4",
|
"multer": "1.4.5-lts.1",
|
||||||
"mustache": "4.2.0",
|
"mustache": "4.2.0",
|
||||||
"node-red-admin": "^3.0.0",
|
"node-red-admin": "^3.0.0",
|
||||||
"node-watch": "0.7.3",
|
"node-watch": "0.7.3",
|
||||||
@ -76,7 +76,7 @@
|
|||||||
"semver": "7.3.7",
|
"semver": "7.3.7",
|
||||||
"tar": "6.1.11",
|
"tar": "6.1.11",
|
||||||
"tough-cookie": "4.0.0",
|
"tough-cookie": "4.0.0",
|
||||||
"uglify-js": "3.15.5",
|
"uglify-js": "3.16.0",
|
||||||
"uuid": "8.3.2",
|
"uuid": "8.3.2",
|
||||||
"ws": "7.5.6",
|
"ws": "7.5.6",
|
||||||
"xml2js": "0.4.23"
|
"xml2js": "0.4.23"
|
||||||
@ -105,16 +105,16 @@
|
|||||||
"grunt-sass": "~3.1.0",
|
"grunt-sass": "~3.1.0",
|
||||||
"grunt-simple-mocha": "~0.4.1",
|
"grunt-simple-mocha": "~0.4.1",
|
||||||
"grunt-simple-nyc": "^3.0.1",
|
"grunt-simple-nyc": "^3.0.1",
|
||||||
"i18next-http-backend": "1.4.0",
|
"i18next-http-backend": "1.4.1",
|
||||||
"jquery-i18next": "1.2.1",
|
"jquery-i18next": "1.2.1",
|
||||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||||
"marked": "4.0.15",
|
"marked": "4.0.17",
|
||||||
"minami": "1.2.3",
|
"minami": "1.2.3",
|
||||||
"mocha": "9.2.2",
|
"mocha": "9.2.2",
|
||||||
"node-red-node-test-helper": "^0.2.7",
|
"node-red-node-test-helper": "^0.2.7",
|
||||||
"nodemon": "2.0.16",
|
"nodemon": "2.0.16",
|
||||||
"proxy": "^1.0.2",
|
"proxy": "^1.0.2",
|
||||||
"sass": "1.51.0",
|
"sass": "1.52.3",
|
||||||
"should": "13.2.3",
|
"should": "13.2.3",
|
||||||
"sinon": "11.1.2",
|
"sinon": "11.1.2",
|
||||||
"stoppable": "^1.1.0",
|
"stoppable": "^1.1.0",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/editor-api",
|
"name": "@node-red/editor-api",
|
||||||
"version": "3.0.0-beta.2",
|
"version": "3.0.0-beta.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -16,8 +16,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/util": "3.0.0-beta.2",
|
"@node-red/util": "3.0.0-beta.3",
|
||||||
"@node-red/editor-client": "3.0.0-beta.2",
|
"@node-red/editor-client": "3.0.0-beta.3",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"body-parser": "1.20.0",
|
"body-parser": "1.20.0",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
@ -26,7 +26,7 @@
|
|||||||
"express": "4.18.1",
|
"express": "4.18.1",
|
||||||
"memorystore": "1.6.7",
|
"memorystore": "1.6.7",
|
||||||
"mime": "3.0.0",
|
"mime": "3.0.0",
|
||||||
"multer": "1.4.4",
|
"multer": "1.4.5-lts.1",
|
||||||
"mustache": "4.2.0",
|
"mustache": "4.2.0",
|
||||||
"oauth2orize": "1.11.1",
|
"oauth2orize": "1.11.1",
|
||||||
"passport-http-bearer": "1.0.1",
|
"passport-http-bearer": "1.0.1",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"label": {
|
"label": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"ok": "Ok",
|
"ok": "Ok",
|
||||||
"done":"Done",
|
"done": "Done",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"listSubflows": "List subflows",
|
"listSubflows": "List subflows",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"disabled":"Disabled",
|
"disabled": "Disabled",
|
||||||
"info": "Description",
|
"info": "Description",
|
||||||
"selectNodes": "Click nodes to select"
|
"selectNodes": "Click nodes to select"
|
||||||
},
|
},
|
||||||
@ -114,7 +114,7 @@
|
|||||||
"keyboardShortcuts": "Keyboard shortcuts",
|
"keyboardShortcuts": "Keyboard shortcuts",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"editPalette":"Manage palette",
|
"editPalette": "Manage palette",
|
||||||
"other": "Other",
|
"other": "Other",
|
||||||
"showTips": "Show tips",
|
"showTips": "Show tips",
|
||||||
"showWelcomeTours": "Show guided tours for new versions",
|
"showWelcomeTours": "Show guided tours for new versions",
|
||||||
@ -130,19 +130,19 @@
|
|||||||
"ungroupSelection": "Ungroup selection",
|
"ungroupSelection": "Ungroup selection",
|
||||||
"groupMergeSelection": "Merge selection",
|
"groupMergeSelection": "Merge selection",
|
||||||
"groupRemoveSelection": "Remove from group",
|
"groupRemoveSelection": "Remove from group",
|
||||||
"arrange":"Arrange",
|
"arrange": "Arrange",
|
||||||
"alignLeft":"Align to left",
|
"alignLeft": "Align to left",
|
||||||
"alignCenter":"Align to center",
|
"alignCenter": "Align to center",
|
||||||
"alignRight":"Align to right",
|
"alignRight": "Align to right",
|
||||||
"alignTop":"Align to top",
|
"alignTop": "Align to top",
|
||||||
"alignMiddle":"Align to middle",
|
"alignMiddle": "Align to middle",
|
||||||
"alignBottom":"Align to bottom",
|
"alignBottom": "Align to bottom",
|
||||||
"distributeHorizontally":"Distribute horizontally",
|
"distributeHorizontally": "Distribute horizontally",
|
||||||
"distributeVertically":"Distribute vertically",
|
"distributeVertically": "Distribute vertically",
|
||||||
"moveToBack":"Move to back",
|
"moveToBack": "Move to back",
|
||||||
"moveToFront":"Move to front",
|
"moveToFront": "Move to front",
|
||||||
"moveBackwards":"Move backwards",
|
"moveBackwards": "Move backwards",
|
||||||
"moveForwards":"Move forwards"
|
"moveForwards": "Move forwards"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
@ -176,10 +176,10 @@
|
|||||||
"nodeActionDisabledSubflow": "node actions disabled within subflow",
|
"nodeActionDisabledSubflow": "node actions disabled within subflow",
|
||||||
"missing-types": "<p>Flows stopped due to missing node types.</p>",
|
"missing-types": "<p>Flows stopped due to missing node types.</p>",
|
||||||
"missing-modules": "<p>Flows stopped due to missing modules.</p>",
|
"missing-modules": "<p>Flows stopped due to missing modules.</p>",
|
||||||
"safe-mode":"<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>",
|
"safe-mode": "<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>",
|
||||||
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
||||||
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
|
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
|
||||||
"credentials_load_failed_reset":"<p>Credentials could not be decrypted</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p><p>The flow credential file will be reset on the next deployment. Any existing flow credentials will be cleared.</p>",
|
"credentials_load_failed_reset": "<p>Credentials could not be decrypted</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p><p>The flow credential file will be reset on the next deployment. Any existing flow credentials will be cleared.</p>",
|
||||||
"missing_flow_file": "<p>Project flow file not found.</p><p>The project is not configured with a flow file.</p>",
|
"missing_flow_file": "<p>Project flow file not found.</p><p>The project is not configured with a flow file.</p>",
|
||||||
"missing_package_file": "<p>Project package file not found.</p><p>The project is missing a package.json file.</p>",
|
"missing_package_file": "<p>Project package file not found.</p><p>The project is missing a package.json file.</p>",
|
||||||
"project_empty": "<p>The project is empty.</p><p>Do you want to create a default set of project files?<br/>Otherwise, you will have to manually add files to the project outside of the editor.</p>",
|
"project_empty": "<p>The project is empty.</p><p>Do you want to create a default set of project files?<br/>Otherwise, you will have to manually add files to the project outside of the editor.</p>",
|
||||||
@ -257,11 +257,11 @@
|
|||||||
"recoveredNodesInfo": "The nodes on this flow were missing a valid flow id when they were imported. They have been added to this flow so you can either restore or delete them.",
|
"recoveredNodesInfo": "The nodes on this flow were missing a valid flow id when they were imported. They have been added to this flow so you can either restore or delete them.",
|
||||||
"recoveredNodesNotification": "<p>Imported nodes without a valid flow id</p><p>They have been added to a new flow called '__flowName__'.</p>",
|
"recoveredNodesNotification": "<p>Imported nodes without a valid flow id</p><p>They have been added to a new flow called '__flowName__'.</p>",
|
||||||
"export": {
|
"export": {
|
||||||
"selected":"selected nodes",
|
"selected": "selected nodes",
|
||||||
"current":"current flow",
|
"current": "current flow",
|
||||||
"all":"all flows",
|
"all": "all flows",
|
||||||
"compact":"compact",
|
"compact": "compact",
|
||||||
"formatted":"formatted",
|
"formatted": "formatted",
|
||||||
"copy": "Copy to clipboard",
|
"copy": "Copy to clipboard",
|
||||||
"export": "Export to library",
|
"export": "Export to library",
|
||||||
"exportAs": "Export as",
|
"exportAs": "Export as",
|
||||||
@ -301,10 +301,10 @@
|
|||||||
"successfulDeploy": "Successfully deployed",
|
"successfulDeploy": "Successfully deployed",
|
||||||
"successfulRestart": "Successfully restarted flows",
|
"successfulRestart": "Successfully restarted flows",
|
||||||
"deployFailed": "Deploy failed: __message__",
|
"deployFailed": "Deploy failed: __message__",
|
||||||
"unusedConfigNodes":"You have some unused configuration nodes.",
|
"unusedConfigNodes": "You have some unused configuration nodes.",
|
||||||
"unusedConfigNodesButton":"Search unused config nodes",
|
"unusedConfigNodesButton": "Search unused config nodes",
|
||||||
"unknownNodesButton":"Search for unknown nodes",
|
"unknownNodesButton": "Search for unknown nodes",
|
||||||
"invalidNodesButton":"Search for invalid nodes",
|
"invalidNodesButton": "Search for invalid nodes",
|
||||||
"errors": {
|
"errors": {
|
||||||
"noResponse": "no response from server"
|
"noResponse": "no response from server"
|
||||||
},
|
},
|
||||||
@ -351,8 +351,8 @@
|
|||||||
},
|
},
|
||||||
"nodeCount": "__count__ node",
|
"nodeCount": "__count__ node",
|
||||||
"nodeCount_plural": "__count__ nodes",
|
"nodeCount_plural": "__count__ nodes",
|
||||||
"local":"Local changes",
|
"local": "Local changes",
|
||||||
"remote":"Remote changes",
|
"remote": "Remote changes",
|
||||||
"reviewChanges": "Review Changes",
|
"reviewChanges": "Review Changes",
|
||||||
"noBinaryFileShowed": "Cannot show binary file contents",
|
"noBinaryFileShowed": "Cannot show binary file contents",
|
||||||
"viewCommitDiff": "View Commit Changes",
|
"viewCommitDiff": "View Commit Changes",
|
||||||
@ -436,7 +436,7 @@
|
|||||||
"inputType": "Input type",
|
"inputType": "Input type",
|
||||||
"selectType": "select types...",
|
"selectType": "select types...",
|
||||||
"loadCredentials": "Loading node credentials",
|
"loadCredentials": "Loading node credentials",
|
||||||
"inputs" : {
|
"inputs": {
|
||||||
"input": "input",
|
"input": "input",
|
||||||
"select": "select",
|
"select": "select",
|
||||||
"checkbox": "checkbox",
|
"checkbox": "checkbox",
|
||||||
@ -617,19 +617,19 @@
|
|||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"install": {
|
"install": {
|
||||||
"body":"<p>Installing '__module__'</p><p>Before installing, please read the node's documentation. Some nodes have dependencies that cannot be automatically resolved and can require a restart of Node-RED.</p>",
|
"body": "<p>Installing '__module__'</p><p>Before installing, please read the node's documentation. Some nodes have dependencies that cannot be automatically resolved and can require a restart of Node-RED.</p>",
|
||||||
"title": "Install nodes"
|
"title": "Install nodes"
|
||||||
},
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"body":"<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>",
|
"body": "<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>",
|
||||||
"title": "Remove nodes"
|
"title": "Remove nodes"
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"body":"<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>",
|
"body": "<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>",
|
||||||
"title": "Update nodes"
|
"title": "Update nodes"
|
||||||
},
|
},
|
||||||
"cannotUpdate": {
|
"cannotUpdate": {
|
||||||
"body":"An update for this node is available, but it is not installed in a location that the palette manager can update.<br/><br/>Please refer to the documentation for how to update this node."
|
"body": "An update for this node is available, but it is not installed in a location that the palette manager can update.<br/><br/>Please refer to the documentation for how to update this node."
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
"review": "Open node information",
|
"review": "Open node information",
|
||||||
@ -663,14 +663,14 @@
|
|||||||
"showMore": "show more",
|
"showMore": "show more",
|
||||||
"showLess": "show less",
|
"showLess": "show less",
|
||||||
"flow": "Flow",
|
"flow": "Flow",
|
||||||
"selection":"Selection",
|
"selection": "Selection",
|
||||||
"nodes":"__count__ nodes",
|
"nodes": "__count__ nodes",
|
||||||
"flowDesc": "Flow Description",
|
"flowDesc": "Flow Description",
|
||||||
"subflowDesc": "Subflow Description",
|
"subflowDesc": "Subflow Description",
|
||||||
"nodeHelp": "Node Help",
|
"nodeHelp": "Node Help",
|
||||||
"none":"None",
|
"none": "None",
|
||||||
"arrayItems": "__count__ items",
|
"arrayItems": "__count__ items",
|
||||||
"showTips":"You can open the tips from the settings panel",
|
"showTips": "You can open the tips from the settings panel",
|
||||||
"outline": "Outline",
|
"outline": "Outline",
|
||||||
"empty": "empty",
|
"empty": "empty",
|
||||||
"globalConfig": "Global Configuration Nodes",
|
"globalConfig": "Global Configuration Nodes",
|
||||||
@ -701,8 +701,8 @@
|
|||||||
"filtered": "__count__ hidden"
|
"filtered": "__count__ hidden"
|
||||||
},
|
},
|
||||||
"context": {
|
"context": {
|
||||||
"name":"Context Data",
|
"name": "Context Data",
|
||||||
"label":"context",
|
"label": "context",
|
||||||
"none": "none selected",
|
"none": "none selected",
|
||||||
"refresh": "refresh to load",
|
"refresh": "refresh to load",
|
||||||
"empty": "empty",
|
"empty": "empty",
|
||||||
@ -740,9 +740,9 @@
|
|||||||
"files": "Files",
|
"files": "Files",
|
||||||
"flow": "Flow",
|
"flow": "Flow",
|
||||||
"credentials": "Credentials",
|
"credentials": "Credentials",
|
||||||
"package":"Package",
|
"package": "Package",
|
||||||
"packageCreate":"File will be created when changes are saved",
|
"packageCreate": "File will be created when changes are saved",
|
||||||
"fileNotExist":"File does not exist",
|
"fileNotExist": "File does not exist",
|
||||||
"selectFile": "Select File",
|
"selectFile": "Select File",
|
||||||
"invalidEncryptionKey": "Invalid encryption key",
|
"invalidEncryptionKey": "Invalid encryption key",
|
||||||
"encryptionEnabled": "Encryption enabled",
|
"encryptionEnabled": "Encryption enabled",
|
||||||
@ -978,7 +978,7 @@
|
|||||||
"title": "Buffer editor",
|
"title": "Buffer editor",
|
||||||
"modeString": "Handle as UTF-8 String",
|
"modeString": "Handle as UTF-8 String",
|
||||||
"modeArray": "Handle as JSON array",
|
"modeArray": "Handle as JSON array",
|
||||||
"modeDesc":"<h3>Buffer editor</h3><p>The Buffer type is stored as a JSON array of byte values. The editor will attempt to parse the entered value as a JSON array. If it is not valid JSON, it will be treated as a UTF-8 String and converted to an array of the individual character code points.</p><p>For example, a value of <code>Hello World</code> will be converted to the JSON array:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
|
"modeDesc": "<h3>Buffer editor</h3><p>The Buffer type is stored as a JSON array of byte values. The editor will attempt to parse the entered value as a JSON array. If it is not valid JSON, it will be treated as a UTF-8 String and converted to an array of the individual character code points.</p><p>For example, a value of <code>Hello World</code> will be converted to the JSON array:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
|
||||||
},
|
},
|
||||||
"projects": {
|
"projects": {
|
||||||
"config-git": "Configure Git client",
|
"config-git": "Configure Git client",
|
||||||
@ -1140,7 +1140,7 @@
|
|||||||
"no-empty": "Cannot create default file set on a non-empty project",
|
"no-empty": "Cannot create default file set on a non-empty project",
|
||||||
"git-error": "git error"
|
"git-error": "git error"
|
||||||
},
|
},
|
||||||
"errors" : {
|
"errors": {
|
||||||
"no-username-email": "Your Git client is not configured with a username/email.",
|
"no-username-email": "Your Git client is not configured with a username/email.",
|
||||||
"unexpected": "An unexpected error occurred",
|
"unexpected": "An unexpected error occurred",
|
||||||
"code": "code"
|
"code": "code"
|
||||||
@ -1163,7 +1163,7 @@
|
|||||||
"diagnostics": {
|
"diagnostics": {
|
||||||
"title": "System Info"
|
"title": "System Info"
|
||||||
},
|
},
|
||||||
"languages" : {
|
"languages": {
|
||||||
"de": "German",
|
"de": "German",
|
||||||
"en-US": "English",
|
"en-US": "English",
|
||||||
"ja": "Japanese",
|
"ja": "Japanese",
|
||||||
@ -1187,5 +1187,11 @@
|
|||||||
"missing-config": "__prop__: missing configuration node",
|
"missing-config": "__prop__: missing configuration node",
|
||||||
"validation-error": "__prop__: validation error: __node__, __id__: __error__"
|
"validation-error": "__prop__: validation error: __node__, __id__: __error__"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"contextMenu": {
|
||||||
|
"insert": "Insert",
|
||||||
|
"node": "Node",
|
||||||
|
"junction": "Junction",
|
||||||
|
"linkNodes": "Link Nodes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
{
|
{
|
||||||
"info": {
|
"info": {
|
||||||
"tip0" : "You can remove the selected nodes or links with {{core:delete-selection}}",
|
"tip0": "You can remove the selected nodes or links with {{core:delete-selection}}",
|
||||||
"tip1" : "Search for nodes using {{core:search}}",
|
"tip1": "Search for nodes using {{core:search}}",
|
||||||
"tip2" : "{{core:toggle-sidebar}} will toggle the view of this sidebar",
|
"tip2": "{{core:toggle-sidebar}} will toggle the view of this sidebar",
|
||||||
"tip3" : "You can manage your palette of nodes with {{core:manage-palette}}",
|
"tip3": "You can manage your palette of nodes with {{core:manage-palette}}",
|
||||||
"tip4" : "Your flow configuration nodes are listed in the sidebar panel. It can be accessed from the menu or with {{core:show-config-tab}}",
|
"tip4": "Your flow configuration nodes are listed in the sidebar panel. It can be accessed from the menu or with {{core:show-config-tab}}",
|
||||||
"tip5" : "Enable or disable these tips from the option in the settings",
|
"tip5": "Enable or disable these tips from the option in the settings",
|
||||||
"tip6" : "Move the selected nodes using the [left] [up] [down] and [right] keys. Hold [shift] to nudge them further",
|
"tip6": "Move the selected nodes using the [left] [up] [down] and [right] keys. Hold [shift] to nudge them further",
|
||||||
"tip7" : "Dragging a node onto a wire will splice it into the link",
|
"tip7": "Dragging a node onto a wire will splice it into the link",
|
||||||
"tip8" : "Export the selected nodes, or the current tab with {{core:show-export-dialog}}",
|
"tip8": "Export the selected nodes, or the current tab with {{core:show-export-dialog}}",
|
||||||
"tip9" : "Import a flow by dragging its JSON into the editor, or with {{core:show-import-dialog}}",
|
"tip9": "Import a flow by dragging its JSON into the editor, or with {{core:show-import-dialog}}",
|
||||||
"tip10" : "[shift] [click] and drag on a node port to move all of the attached wires or just the selected one",
|
"tip10": "[shift] [click] and drag on a node port to move all of the attached wires or just the selected one",
|
||||||
"tip11" : "Show the Info tab with {{core:show-info-tab}} or the Debug tab with {{core:show-debug-tab}}",
|
"tip11": "Show the Info tab with {{core:show-info-tab}} or the Debug tab with {{core:show-debug-tab}}",
|
||||||
"tip12" : "[ctrl] [click] in the workspace to open the quick-add dialog",
|
"tip12": "[ctrl] [click] in the workspace to open the quick-add dialog",
|
||||||
"tip13" : "Hold down [ctrl] when you [click] on a node port to enable quick-wiring",
|
"tip13": "Hold down [ctrl] when you [click] on a node port to enable quick-wiring",
|
||||||
"tip14" : "Hold down [shift] when you [click] on a node to also select all of its connected nodes",
|
"tip14": "Hold down [shift] when you [click] on a node to also select all of its connected nodes",
|
||||||
"tip15" : "Hold down [ctrl] when you [click] on a node to add or remove it from the current selection",
|
"tip15": "Hold down [ctrl] when you [click] on a node to add or remove it from the current selection",
|
||||||
"tip16" : "Switch flow tabs with {{core:show-previous-tab}} and {{core:show-next-tab}}",
|
"tip16": "Switch flow tabs with {{core:show-previous-tab}} and {{core:show-next-tab}}",
|
||||||
"tip17" : "You can confirm your changes in the node edit tray with {{core:confirm-edit-tray}} or cancel them with {{core:cancel-edit-tray}}",
|
"tip17": "You can confirm your changes in the node edit tray with {{core:confirm-edit-tray}} or cancel them with {{core:cancel-edit-tray}}",
|
||||||
"tip18" : "Pressing {{core:edit-selected-node}} will edit the first node in the current selection"
|
"tip18": "Pressing {{core:edit-selected-node}} will edit the first node in the current selection"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,52 +52,52 @@
|
|||||||
"desc": "Finds occurrences of `pattern` within `str` and replaces them with `replacement`.\n\nThe optional `limit` parameter is the maximum number of replacements."
|
"desc": "Finds occurrences of `pattern` within `str` and replaces them with `replacement`.\n\nThe optional `limit` parameter is the maximum number of replacements."
|
||||||
},
|
},
|
||||||
"$now": {
|
"$now": {
|
||||||
"args":"$[picture [, timezone]]",
|
"args": "$[picture [, timezone]]",
|
||||||
"desc":"Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional picture and timezone parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function"
|
"desc": "Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional picture and timezone parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function"
|
||||||
},
|
},
|
||||||
"$base64encode": {
|
"$base64encode": {
|
||||||
"args":"string",
|
"args": "string",
|
||||||
"desc":"Converts an ASCII string to a base 64 representation. Each character in the string is treated as a byte of binary data. This requires that all characters in the string are in the 0x00 to 0xFF range, which includes all characters in URI encoded strings. Unicode characters outside of that range are not supported."
|
"desc": "Converts an ASCII string to a base 64 representation. Each character in the string is treated as a byte of binary data. This requires that all characters in the string are in the 0x00 to 0xFF range, which includes all characters in URI encoded strings. Unicode characters outside of that range are not supported."
|
||||||
},
|
},
|
||||||
"$base64decode": {
|
"$base64decode": {
|
||||||
"args":"string",
|
"args": "string",
|
||||||
"desc":"Converts base 64 encoded bytes to a string, using a UTF-8 Unicode codepage."
|
"desc": "Converts base 64 encoded bytes to a string, using a UTF-8 Unicode codepage."
|
||||||
},
|
},
|
||||||
"$number": {
|
"$number": {
|
||||||
"args": "arg",
|
"args": "arg",
|
||||||
"desc": "Casts the `arg` parameter to a number using the following casting rules:\n\n - Numbers are unchanged\n - Strings that contain a sequence of characters that represent a legal JSON number are converted to that number\n - All other values cause an error to be thrown."
|
"desc": "Casts the `arg` parameter to a number using the following casting rules:\n\n - Numbers are unchanged\n - Strings that contain a sequence of characters that represent a legal JSON number are converted to that number\n - All other values cause an error to be thrown."
|
||||||
},
|
},
|
||||||
"$abs": {
|
"$abs": {
|
||||||
"args":"number",
|
"args": "number",
|
||||||
"desc":"Returns the absolute value of the `number` parameter."
|
"desc": "Returns the absolute value of the `number` parameter."
|
||||||
},
|
},
|
||||||
"$floor": {
|
"$floor": {
|
||||||
"args":"number",
|
"args": "number",
|
||||||
"desc":"Returns the value of `number` rounded down to the nearest integer that is smaller or equal to `number`."
|
"desc": "Returns the value of `number` rounded down to the nearest integer that is smaller or equal to `number`."
|
||||||
},
|
},
|
||||||
"$ceil": {
|
"$ceil": {
|
||||||
"args":"number",
|
"args": "number",
|
||||||
"desc":"Returns the value of `number` rounded up to the nearest integer that is greater than or equal to `number`."
|
"desc": "Returns the value of `number` rounded up to the nearest integer that is greater than or equal to `number`."
|
||||||
},
|
},
|
||||||
"$round": {
|
"$round": {
|
||||||
"args":"number [, precision]",
|
"args": "number [, precision]",
|
||||||
"desc":"Returns the value of the `number` parameter rounded to the number of decimal places specified by the optional `precision` parameter."
|
"desc": "Returns the value of the `number` parameter rounded to the number of decimal places specified by the optional `precision` parameter."
|
||||||
},
|
},
|
||||||
"$power": {
|
"$power": {
|
||||||
"args":"base, exponent",
|
"args": "base, exponent",
|
||||||
"desc":"Returns the value of `base` raised to the power of `exponent`."
|
"desc": "Returns the value of `base` raised to the power of `exponent`."
|
||||||
},
|
},
|
||||||
"$sqrt": {
|
"$sqrt": {
|
||||||
"args":"number",
|
"args": "number",
|
||||||
"desc":"Returns the square root of the value of the `number` parameter."
|
"desc": "Returns the square root of the value of the `number` parameter."
|
||||||
},
|
},
|
||||||
"$random": {
|
"$random": {
|
||||||
"args":"",
|
"args": "",
|
||||||
"desc":"Returns a pseudo random number greater than or equal to zero and less than one."
|
"desc": "Returns a pseudo random number greater than or equal to zero and less than one."
|
||||||
},
|
},
|
||||||
"$millis": {
|
"$millis": {
|
||||||
"args":"",
|
"args": "",
|
||||||
"desc":"Returns the number of milliseconds since the Unix Epoch (1 January, 1970 UTC) as a number. All invocations of `$millis()` within an evaluation of an expression will all return the same value."
|
"desc": "Returns the number of milliseconds since the Unix Epoch (1 January, 1970 UTC) as a number. All invocations of `$millis()` within an evaluation of an expression will all return the same value."
|
||||||
},
|
},
|
||||||
"$sum": {
|
"$sum": {
|
||||||
"args": "array",
|
"args": "array",
|
||||||
@ -136,20 +136,20 @@
|
|||||||
"desc": "Appends two arrays"
|
"desc": "Appends two arrays"
|
||||||
},
|
},
|
||||||
"$sort": {
|
"$sort": {
|
||||||
"args":"array [, function]",
|
"args": "array [, function]",
|
||||||
"desc":"Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values left and right. If the value of left should be placed after the value of right in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
|
"desc": "Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values left and right. If the value of left should be placed after the value of right in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
|
||||||
},
|
},
|
||||||
"$reverse": {
|
"$reverse": {
|
||||||
"args":"array",
|
"args": "array",
|
||||||
"desc":"Returns an array containing all the values from the `array` parameter, but in reverse order."
|
"desc": "Returns an array containing all the values from the `array` parameter, but in reverse order."
|
||||||
},
|
},
|
||||||
"$shuffle": {
|
"$shuffle": {
|
||||||
"args":"array",
|
"args": "array",
|
||||||
"desc":"Returns an array containing all the values from the `array` parameter, but shuffled into random order."
|
"desc": "Returns an array containing all the values from the `array` parameter, but shuffled into random order."
|
||||||
},
|
},
|
||||||
"$zip": {
|
"$zip": {
|
||||||
"args":"array, ...",
|
"args": "array, ...",
|
||||||
"desc":"Returns a convolved (zipped) array containing grouped arrays of values from the `array1` … `arrayN` arguments from index 0, 1, 2...."
|
"desc": "Returns a convolved (zipped) array containing grouped arrays of values from the `array1` … `arrayN` arguments from index 0, 1, 2...."
|
||||||
},
|
},
|
||||||
"$keys": {
|
"$keys": {
|
||||||
"args": "object",
|
"args": "object",
|
||||||
@ -168,24 +168,24 @@
|
|||||||
"desc": "Merges an array of `objects` into a single `object` containing all the key/value pairs from each of the objects in the input array. If any of the input objects contain the same key, then the returned `object` will contain the value of the last one in the array. It is an error if the input array contains an item that is not an object."
|
"desc": "Merges an array of `objects` into a single `object` containing all the key/value pairs from each of the objects in the input array. If any of the input objects contain the same key, then the returned `object` will contain the value of the last one in the array. It is an error if the input array contains an item that is not an object."
|
||||||
},
|
},
|
||||||
"$sift": {
|
"$sift": {
|
||||||
"args":"object, function",
|
"args": "object, function",
|
||||||
"desc":"Returns an object that contains only the key/value pairs from the `object` parameter that satisfy the predicate `function` passed in as the second parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, key [, object]])`"
|
"desc": "Returns an object that contains only the key/value pairs from the `object` parameter that satisfy the predicate `function` passed in as the second parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, key [, object]])`"
|
||||||
},
|
},
|
||||||
"$each": {
|
"$each": {
|
||||||
"args":"object, function",
|
"args": "object, function",
|
||||||
"desc":"Returns an array containing the values return by the `function` when applied to each key/value pair in the `object`."
|
"desc": "Returns an array containing the values return by the `function` when applied to each key/value pair in the `object`."
|
||||||
},
|
},
|
||||||
"$map": {
|
"$map": {
|
||||||
"args":"array, function",
|
"args": "array, function",
|
||||||
"desc":"Returns an array containing the results of applying the `function` parameter to each value in the `array` parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, index [, array]])`"
|
"desc": "Returns an array containing the results of applying the `function` parameter to each value in the `array` parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, index [, array]])`"
|
||||||
},
|
},
|
||||||
"$filter": {
|
"$filter": {
|
||||||
"args":"array, function",
|
"args": "array, function",
|
||||||
"desc":"Returns an array containing only the values in the `array` parameter that satisfy the `function` predicate.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, index [, array]])`"
|
"desc": "Returns an array containing only the values in the `array` parameter that satisfy the `function` predicate.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, index [, array]])`"
|
||||||
},
|
},
|
||||||
"$reduce": {
|
"$reduce": {
|
||||||
"args":"array, function [, init]",
|
"args": "array, function [, init]",
|
||||||
"desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`. The signature of `function` must be of the form: `myfunc($accumulator, $value[, $index[, $array]])`\n\nThe optional `init` parameter is used as the initial value in the aggregation."
|
"desc": "Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`. The signature of `function` must be of the form: `myfunc($accumulator, $value[, $index[, $array]])`\n\nThe optional `init` parameter is used as the initial value in the aggregation."
|
||||||
},
|
},
|
||||||
"$flowContext": {
|
"$flowContext": {
|
||||||
"args": "string[, string]",
|
"args": "string[, string]",
|
||||||
|
@ -907,7 +907,8 @@
|
|||||||
"uknownNodes": "未知のノード",
|
"uknownNodes": "未知のノード",
|
||||||
"unusedSubflows": "未使用のサブフロー",
|
"unusedSubflows": "未使用のサブフロー",
|
||||||
"hiddenFlows": "非表示のフロー",
|
"hiddenFlows": "非表示のフロー",
|
||||||
"modifiedNodes": "修正したノードやフロー"
|
"modifiedNodes": "修正したノードやフロー",
|
||||||
|
"thisFlow": "現在のフロー"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"expressionEditor": {
|
"expressionEditor": {
|
||||||
@ -1187,6 +1188,12 @@
|
|||||||
"validation-error": "__prop__: チェックエラー: __node__, __id__: __error__"
|
"validation-error": "__prop__: チェックエラー: __node__, __id__: __error__"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"contextMenu": {
|
||||||
|
"insert": "挿入",
|
||||||
|
"node": "ノード",
|
||||||
|
"junction": "分岐点",
|
||||||
|
"linkNodes": "Linkノード"
|
||||||
|
},
|
||||||
"action-list": {
|
"action-list": {
|
||||||
"toggle-show-tips": "ヒント表示切替",
|
"toggle-show-tips": "ヒント表示切替",
|
||||||
"show-about": "Node-REDの説明を表示",
|
"show-about": "Node-REDの説明を表示",
|
||||||
@ -1301,7 +1308,7 @@
|
|||||||
"search": "検索",
|
"search": "検索",
|
||||||
"search-previous": "前を検索",
|
"search-previous": "前を検索",
|
||||||
"search-next": "次を検索",
|
"search-next": "次を検索",
|
||||||
"show-action-list": "アクション一覧を表示",
|
"show-action-list": "動作一覧を表示",
|
||||||
"confirm-edit-tray": "編集を完了",
|
"confirm-edit-tray": "編集を完了",
|
||||||
"cancel-edit-tray": "編集をキャンセル",
|
"cancel-edit-tray": "編集をキャンセル",
|
||||||
"show-remote-diff": "リモートとの変更差分を表示",
|
"show-remote-diff": "リモートとの変更差分を表示",
|
||||||
@ -1323,6 +1330,11 @@
|
|||||||
"zoom-out": "ズームアウト",
|
"zoom-out": "ズームアウト",
|
||||||
"zoom-reset": "ズームリセット",
|
"zoom-reset": "ズームリセット",
|
||||||
"toggle-navigator": "ナビゲータ表示切替",
|
"toggle-navigator": "ナビゲータ表示切替",
|
||||||
"show-system-info": "システムインフォメーション"
|
"show-system-info": "システム情報",
|
||||||
|
"split-wires-with-junctions": "分岐点によりワイヤーを分割",
|
||||||
|
"new-project": "新しいプロジェクト",
|
||||||
|
"open-project": "プロジェクトを開く",
|
||||||
|
"show-project-settings": "プロジェクト設定を表示",
|
||||||
|
"show-version-control-tab": "バージョンコントロールタブを表示"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
"tip14": "[shift] を押しながらノードを [click] すると、接続された全てのノードを選択できます。",
|
"tip14": "[shift] を押しながらノードを [click] すると、接続された全てのノードを選択できます。",
|
||||||
"tip15": "[ctrl] を押しながらノードを [click] すると、選択/非選択を切り替えできます。",
|
"tip15": "[ctrl] を押しながらノードを [click] すると、選択/非選択を切り替えできます。",
|
||||||
"tip16": "{{core:show-previous-tab}} や {{core:show-next-tab}} で、タブの切り替えができます。",
|
"tip16": "{{core:show-previous-tab}} や {{core:show-next-tab}} で、タブの切り替えができます。",
|
||||||
"tip17": "ノードのプロバティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
|
"tip17": "ノードのプロパティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
|
||||||
"tip18": "ノードを選択し、 {{core:edit-selected-node}} を押すとプロパティ設定画面が表示されます。"
|
"tip18": "ノードを選択し、 {{core:edit-selected-node}} を押すとプロパティ設定画面が表示されます。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/editor-client",
|
"name": "@node-red/editor-client",
|
||||||
"version": "3.0.0-beta.2",
|
"version": "3.0.0-beta.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -22,6 +22,14 @@ RED.history = (function() {
|
|||||||
var undoHistory = [];
|
var undoHistory = [];
|
||||||
var redoHistory = [];
|
var redoHistory = [];
|
||||||
|
|
||||||
|
function nodeOrJunction(id) {
|
||||||
|
var node = RED.nodes.node(id);
|
||||||
|
if (node) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
return RED.nodes.junction(id);
|
||||||
|
}
|
||||||
|
|
||||||
function undoEvent(ev) {
|
function undoEvent(ev) {
|
||||||
var i;
|
var i;
|
||||||
var len;
|
var len;
|
||||||
@ -514,6 +522,7 @@ RED.history = (function() {
|
|||||||
var z = ev.activeWorkspace;
|
var z = ev.activeWorkspace;
|
||||||
var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
|
var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
|
||||||
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
|
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
|
||||||
|
fullNodeList = fullNodeList.concat(RED.nodes.junctions(ev.subflow.subflow.id))
|
||||||
fullNodeList.forEach(function(n) {
|
fullNodeList.forEach(function(n) {
|
||||||
n.x += ev.subflow.offsetX;
|
n.x += ev.subflow.offsetX;
|
||||||
n.y += ev.subflow.offsetY;
|
n.y += ev.subflow.offsetY;
|
||||||
@ -523,7 +532,7 @@ RED.history = (function() {
|
|||||||
});
|
});
|
||||||
inverseEv.subflows = [];
|
inverseEv.subflows = [];
|
||||||
for (i=0;i<ev.nodes.length;i++) {
|
for (i=0;i<ev.nodes.length;i++) {
|
||||||
inverseEv.subflows.push(RED.nodes.node(ev.nodes[i]));
|
inverseEv.subflows.push(nodeOrJunction(ev.nodes[i]));
|
||||||
RED.nodes.remove(ev.nodes[i]);
|
RED.nodes.remove(ev.nodes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -738,6 +738,10 @@ RED.nodes = (function() {
|
|||||||
moveGroupToTab(node,z);
|
moveGroupToTab(node,z);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (node.type === "junction") {
|
||||||
|
moveJunctionToTab(node,z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
var oldZ = node.z;
|
var oldZ = node.z;
|
||||||
allNodes.moveNode(node,z);
|
allNodes.moveNode(node,z);
|
||||||
var nl = nodeLinks[node.id];
|
var nl = nodeLinks[node.id];
|
||||||
@ -772,6 +776,39 @@ RED.nodes = (function() {
|
|||||||
RED.events.emit("groups:change",group);
|
RED.events.emit("groups:change",group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moveJunctionToTab(junction, z) {
|
||||||
|
var index = junctionsByZ[junction.z].indexOf(junction);
|
||||||
|
junctionsByZ[junction.z].splice(index,1);
|
||||||
|
junctionsByZ[z] = junctionsByZ[z] || [];
|
||||||
|
junctionsByZ[z].push(junction);
|
||||||
|
|
||||||
|
var oldZ = junction.z;
|
||||||
|
junction.z = z;
|
||||||
|
|
||||||
|
var nl = nodeLinks[junction.id];
|
||||||
|
if (nl) {
|
||||||
|
nl.in.forEach(function(l) {
|
||||||
|
var idx = linkTabMap[oldZ].indexOf(l);
|
||||||
|
if (idx != -1) {
|
||||||
|
linkTabMap[oldZ].splice(idx, 1);
|
||||||
|
}
|
||||||
|
if ((l.source.z === z) && linkTabMap[z]) {
|
||||||
|
linkTabMap[z].push(l);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nl.out.forEach(function(l) {
|
||||||
|
var idx = linkTabMap[oldZ].indexOf(l);
|
||||||
|
if (idx != -1) {
|
||||||
|
linkTabMap[oldZ].splice(idx, 1);
|
||||||
|
}
|
||||||
|
if ((l.target.z === z) && linkTabMap[z]) {
|
||||||
|
linkTabMap[z].push(l);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RED.events.emit("junctions:change",junction);
|
||||||
|
}
|
||||||
|
|
||||||
function removeLink(l) {
|
function removeLink(l) {
|
||||||
var index = links.indexOf(l);
|
var index = links.indexOf(l);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
|
@ -21,28 +21,12 @@ RED.actions = (function() {
|
|||||||
function getAction(name) {
|
function getAction(name) {
|
||||||
return actions[name].handler;
|
return actions[name].handler;
|
||||||
}
|
}
|
||||||
function invokeAction() {
|
function getActionLabel(name) {
|
||||||
var args = Array.prototype.slice.call(arguments);
|
let def = actions[name]
|
||||||
var name = args.shift();
|
if (!def) {
|
||||||
if (actions.hasOwnProperty(name)) {
|
return ''
|
||||||
var handler = actions[name].handler;
|
|
||||||
handler.apply(null, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function listActions() {
|
|
||||||
var result = [];
|
|
||||||
var missing = [];
|
|
||||||
Object.keys(actions).forEach(function(action) {
|
|
||||||
var def = actions[action];
|
|
||||||
var shortcut = RED.keyboard.getShortcut(action);
|
|
||||||
var isUser = false;
|
|
||||||
if (shortcut) {
|
|
||||||
isUser = shortcut.user;
|
|
||||||
} else {
|
|
||||||
isUser = !!RED.keyboard.getUserShortcut(action);
|
|
||||||
}
|
}
|
||||||
if (!def.label) {
|
if (!def.label) {
|
||||||
var name = action;
|
|
||||||
var options = def.options;
|
var options = def.options;
|
||||||
var key = options ? options.label : undefined;
|
var key = options ? options.label : undefined;
|
||||||
if (!key) {
|
if (!key) {
|
||||||
@ -58,12 +42,36 @@ RED.actions = (function() {
|
|||||||
return " "+arguments[4].toUpperCase();
|
return " "+arguments[4].toUpperCase();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
missing.push(key);
|
|
||||||
}
|
}
|
||||||
def.label = label;
|
def.label = label;
|
||||||
}
|
}
|
||||||
//console.log("; missing:", missing);
|
return def.label
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function invokeAction() {
|
||||||
|
var args = Array.prototype.slice.call(arguments);
|
||||||
|
var name = args.shift();
|
||||||
|
if (actions.hasOwnProperty(name)) {
|
||||||
|
var handler = actions[name].handler;
|
||||||
|
handler.apply(null, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function listActions() {
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
Object.keys(actions).forEach(function(action) {
|
||||||
|
var def = actions[action];
|
||||||
|
var shortcut = RED.keyboard.getShortcut(action);
|
||||||
|
var isUser = false;
|
||||||
|
if (shortcut) {
|
||||||
|
isUser = shortcut.user;
|
||||||
|
} else {
|
||||||
|
isUser = !!RED.keyboard.getUserShortcut(action);
|
||||||
|
}
|
||||||
|
if (!def.label) {
|
||||||
|
def.label = getActionLabel(action)
|
||||||
|
}
|
||||||
result.push({
|
result.push({
|
||||||
id:action,
|
id:action,
|
||||||
scope:shortcut?shortcut.scope:undefined,
|
scope:shortcut?shortcut.scope:undefined,
|
||||||
@ -79,6 +87,7 @@ RED.actions = (function() {
|
|||||||
add: addAction,
|
add: addAction,
|
||||||
remove: removeAction,
|
remove: removeAction,
|
||||||
get: getAction,
|
get: getAction,
|
||||||
|
getLabel: getActionLabel,
|
||||||
invoke: invokeAction,
|
invoke: invokeAction,
|
||||||
list: listActions
|
list: listActions
|
||||||
}
|
}
|
||||||
|
@ -709,6 +709,7 @@ RED.clipboard = (function() {
|
|||||||
} else if (type === 'flow') {
|
} else if (type === 'flow') {
|
||||||
var activeWorkspace = RED.workspaces.active();
|
var activeWorkspace = RED.workspaces.active();
|
||||||
nodes = RED.nodes.groups(activeWorkspace);
|
nodes = RED.nodes.groups(activeWorkspace);
|
||||||
|
nodes = nodes.concat(RED.nodes.junctions(activeWorkspace));
|
||||||
nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace}));
|
nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace}));
|
||||||
RED.nodes.eachConfig(function(n) {
|
RED.nodes.eachConfig(function(n) {
|
||||||
if (n.z === RED.workspaces.active() && n._def.hasUsers === false) {
|
if (n.z === RED.workspaces.active() && n._def.hasUsers === false) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
RED.menu = (function() {
|
RED.menu = (function() {
|
||||||
|
|
||||||
var menuItems = {};
|
var menuItems = {};
|
||||||
|
let menuItemCount = 0
|
||||||
|
|
||||||
function createMenuItem(opt) {
|
function createMenuItem(opt) {
|
||||||
var item;
|
var item;
|
||||||
@ -59,15 +60,16 @@ RED.menu = (function() {
|
|||||||
item = $('<li class="red-ui-menu-divider"></li>');
|
item = $('<li class="red-ui-menu-divider"></li>');
|
||||||
} else {
|
} else {
|
||||||
item = $('<li></li>');
|
item = $('<li></li>');
|
||||||
|
if (!opt.id) {
|
||||||
|
opt.id = 'red-ui-menu-item-'+(menuItemCount++)
|
||||||
|
}
|
||||||
if (opt.group) {
|
if (opt.group) {
|
||||||
item.addClass("red-ui-menu-group-"+opt.group);
|
item.addClass("red-ui-menu-group-"+opt.group);
|
||||||
|
|
||||||
}
|
}
|
||||||
var linkContent = '<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">';
|
var linkContent = '<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">';
|
||||||
if (opt.toggle) {
|
if (opt.toggle) {
|
||||||
linkContent += '<i class="fa fa-square pull-left"></i>';
|
linkContent += '<i class="fa fa-square'+(opt.direction!=='right'?" pull-left":"")+'"></i>';
|
||||||
linkContent += '<i class="fa fa-check-square pull-left"></i>';
|
linkContent += '<i class="fa fa-check-square'+(opt.direction!=='right'?" pull-left":"")+'"></i>';
|
||||||
|
|
||||||
}
|
}
|
||||||
if (opt.icon !== undefined) {
|
if (opt.icon !== undefined) {
|
||||||
@ -77,12 +79,15 @@ RED.menu = (function() {
|
|||||||
linkContent += '<i class="'+(opt.icon?opt.icon:'" style="display: inline-block;"')+'"></i> ';
|
linkContent += '<i class="'+(opt.icon?opt.icon:'" style="display: inline-block;"')+'"></i> ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let label = opt.label
|
||||||
|
if (!opt.label && typeof opt.onselect === 'string') {
|
||||||
|
label = RED.actions.getLabel(opt.onselect)
|
||||||
|
}
|
||||||
if (opt.sublabel) {
|
if (opt.sublabel) {
|
||||||
linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+opt.label+'</span>'+
|
linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+label+'</span>'+
|
||||||
'<span class="red-ui-menu-sublabel">'+opt.sublabel+'</span></span>'
|
'<span class="red-ui-menu-sublabel">'+opt.sublabel+'</span></span>'
|
||||||
} else {
|
} else {
|
||||||
linkContent += '<span class="red-ui-menu-label"><span>'+opt.label+'</span></span>'
|
linkContent += '<span class="red-ui-menu-label"><span>'+label+'</span></span>'
|
||||||
}
|
}
|
||||||
|
|
||||||
linkContent += '</a>';
|
linkContent += '</a>';
|
||||||
@ -126,15 +131,38 @@ RED.menu = (function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (opt.options) {
|
if (opt.options) {
|
||||||
item.addClass("red-ui-menu-dropdown-submenu pull-left");
|
item.addClass("red-ui-menu-dropdown-submenu"+(opt.direction!=='right'?" pull-left":""));
|
||||||
var submenu = $('<ul id="'+opt.id+'-submenu" class="red-ui-menu-dropdown"></ul>').appendTo(item);
|
var submenu = $('<ul id="'+opt.id+'-submenu" class="red-ui-menu-dropdown"></ul>').appendTo(item);
|
||||||
|
var hasIcons = false
|
||||||
|
var hasSubmenus = false
|
||||||
|
|
||||||
for (var i=0;i<opt.options.length;i++) {
|
for (var i=0;i<opt.options.length;i++) {
|
||||||
|
|
||||||
|
if (opt.options[i]) {
|
||||||
|
if (opt.onpreselect && opt.options[i].onpreselect === undefined) {
|
||||||
|
opt.options[i].onpreselect = opt.onpreselect
|
||||||
|
}
|
||||||
|
if (opt.onpostselect && opt.options[i].onpostselect === undefined) {
|
||||||
|
opt.options[i].onpostselect = opt.onpostselect
|
||||||
|
}
|
||||||
|
opt.options[i].direction = opt.direction
|
||||||
|
hasIcons = hasIcons || (opt.options[i].icon);
|
||||||
|
hasSubmenus = hasSubmenus || (opt.options[i].options);
|
||||||
|
}
|
||||||
|
|
||||||
var li = createMenuItem(opt.options[i]);
|
var li = createMenuItem(opt.options[i]);
|
||||||
if (li) {
|
if (li) {
|
||||||
li.appendTo(submenu);
|
li.appendTo(submenu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!hasIcons) {
|
||||||
|
submenu.addClass("red-ui-menu-dropdown-noicons")
|
||||||
|
}
|
||||||
|
if (hasSubmenus) {
|
||||||
|
submenu.addClass("red-ui-menu-dropdown-submenus")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if (opt.disabled) {
|
if (opt.disabled) {
|
||||||
item.addClass("disabled");
|
item.addClass("disabled");
|
||||||
@ -150,7 +178,9 @@ RED.menu = (function() {
|
|||||||
}
|
}
|
||||||
function createMenu(options) {
|
function createMenu(options) {
|
||||||
var topMenu = $("<ul/>",{class:"red-ui-menu red-ui-menu-dropdown pull-right"});
|
var topMenu = $("<ul/>",{class:"red-ui-menu red-ui-menu-dropdown pull-right"});
|
||||||
|
if (options.direction) {
|
||||||
|
topMenu.addClass("red-ui-menu-dropdown-direction-"+options.direction)
|
||||||
|
}
|
||||||
if (options.id) {
|
if (options.id) {
|
||||||
topMenu.attr({id:options.id+"-submenu"});
|
topMenu.attr({id:options.id+"-submenu"});
|
||||||
var menuParent = $("#"+options.id);
|
var menuParent = $("#"+options.id);
|
||||||
@ -176,9 +206,22 @@ RED.menu = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lastAddedSeparator = false;
|
var lastAddedSeparator = false;
|
||||||
|
var hasSubmenus = false;
|
||||||
|
var hasIcons = false;
|
||||||
for (var i=0;i<options.options.length;i++) {
|
for (var i=0;i<options.options.length;i++) {
|
||||||
var opt = options.options[i];
|
var opt = options.options[i];
|
||||||
|
if (opt) {
|
||||||
|
if (options.onpreselect && opt.onpreselect === undefined) {
|
||||||
|
opt.onpreselect = options.onpreselect
|
||||||
|
}
|
||||||
|
if (options.onpostselect && opt.onpostselect === undefined) {
|
||||||
|
opt.onpostselect = options.onpostselect
|
||||||
|
}
|
||||||
|
opt.direction = options.direction || 'left'
|
||||||
|
}
|
||||||
if (opt !== null || !lastAddedSeparator) {
|
if (opt !== null || !lastAddedSeparator) {
|
||||||
|
hasIcons = hasIcons || (opt && opt.icon);
|
||||||
|
hasSubmenus = hasSubmenus || (opt && opt.options);
|
||||||
var li = createMenuItem(opt);
|
var li = createMenuItem(opt);
|
||||||
if (li) {
|
if (li) {
|
||||||
li.appendTo(topMenu);
|
li.appendTo(topMenu);
|
||||||
@ -186,13 +229,21 @@ RED.menu = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!hasIcons) {
|
||||||
|
topMenu.addClass("red-ui-menu-dropdown-noicons")
|
||||||
|
}
|
||||||
|
if (hasSubmenus) {
|
||||||
|
topMenu.addClass("red-ui-menu-dropdown-submenus")
|
||||||
|
}
|
||||||
return topMenu;
|
return topMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerAction(id, args) {
|
function triggerAction(id, args) {
|
||||||
var opt = menuItems[id];
|
var opt = menuItems[id];
|
||||||
var callback = opt.onselect;
|
var callback = opt.onselect;
|
||||||
|
if (opt.onpreselect) {
|
||||||
|
opt.onpreselect.call(opt,args)
|
||||||
|
}
|
||||||
if (typeof opt.onselect === 'string') {
|
if (typeof opt.onselect === 'string') {
|
||||||
callback = RED.actions.get(opt.onselect);
|
callback = RED.actions.get(opt.onselect);
|
||||||
}
|
}
|
||||||
@ -201,6 +252,9 @@ RED.menu = (function() {
|
|||||||
} else {
|
} else {
|
||||||
console.log("No callback for",id,opt.onselect);
|
console.log("No callback for",id,opt.onselect);
|
||||||
}
|
}
|
||||||
|
if (opt.onpostselect) {
|
||||||
|
opt.onpostselect.call(opt,args)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSelected(id) {
|
function isSelected(id) {
|
||||||
|
@ -610,10 +610,13 @@ RED.popover = (function() {
|
|||||||
var target = options.target;
|
var target = options.target;
|
||||||
var align = options.align || "right";
|
var align = options.align || "right";
|
||||||
var offset = options.offset || [0,0];
|
var offset = options.offset || [0,0];
|
||||||
|
var xPos = options.x;
|
||||||
|
var yPos = options.y;
|
||||||
|
var isAbsolutePosition = (xPos !== undefined && yPos !== undefined)
|
||||||
|
|
||||||
var pos = target.offset();
|
var pos = isAbsolutePosition?{left:xPos, top: yPos}:target.offset();
|
||||||
var targetWidth = target.width();
|
var targetWidth = isAbsolutePosition?0:target.width();
|
||||||
var targetHeight = target.outerHeight();
|
var targetHeight = isAbsolutePosition?0:target.outerHeight();
|
||||||
var panelHeight = panel.height();
|
var panelHeight = panel.height();
|
||||||
var panelWidth = panel.width();
|
var panelWidth = panel.width();
|
||||||
|
|
||||||
|
@ -828,7 +828,7 @@ RED.tabs = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// link.attr("title",tab.label);
|
// link.attr("title",tab.label);
|
||||||
RED.popover.tooltip(link,function() { return tab.label})
|
RED.popover.tooltip(link,function() { return RED.utils.sanitize(tab.label); });
|
||||||
|
|
||||||
if (options.onadd) {
|
if (options.onadd) {
|
||||||
options.onadd(tab);
|
options.onadd(tab);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
* - multi : boolean - if true, .selected will return an array of results
|
* - multi : boolean - if true, .selected will return an array of results
|
||||||
* otherwise, returns the first selected item
|
* otherwise, returns the first selected item
|
||||||
* - sortable: boolean/string - TODO: see editableList
|
* - sortable: boolean/string - TODO: see editableList
|
||||||
|
* - selectable: boolean - default true - whether individual items can be selected
|
||||||
* - rootSortable: boolean - if 'sortable' is set, then setting this to
|
* - rootSortable: boolean - if 'sortable' is set, then setting this to
|
||||||
* false, prevents items being sorted to the
|
* false, prevents items being sorted to the
|
||||||
* top level of the tree
|
* top level of the tree
|
||||||
@ -118,6 +119,7 @@
|
|||||||
switch(evt.keyCode) {
|
switch(evt.keyCode) {
|
||||||
case 32: // SPACE
|
case 32: // SPACE
|
||||||
case 13: // ENTER
|
case 13: // ENTER
|
||||||
|
if (!that.options.selectable) { return }
|
||||||
if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) {
|
if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
176
packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js
vendored
Normal file
176
packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js
vendored
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
RED.contextMenu = (function() {
|
||||||
|
|
||||||
|
let menu;
|
||||||
|
function createMenu() {
|
||||||
|
// menu = RED.popover.menu({
|
||||||
|
// options: [
|
||||||
|
// {
|
||||||
|
// label: 'delete selection',
|
||||||
|
// onselect: function() {
|
||||||
|
// RED.actions.invoke('core:delete-selection')
|
||||||
|
// RED.view.focus()
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// { label: 'world' }
|
||||||
|
// ],
|
||||||
|
// width: 200,
|
||||||
|
// })
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function disposeMenu() {
|
||||||
|
$(document).off("mousedown.red-ui-workspace-context-menu");
|
||||||
|
if (menu) {
|
||||||
|
menu.remove();
|
||||||
|
}
|
||||||
|
menu = null;
|
||||||
|
}
|
||||||
|
function show(options) {
|
||||||
|
if (menu) {
|
||||||
|
menu.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
const selection = RED.view.selection()
|
||||||
|
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||||
|
const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
|
||||||
|
const hasLinks = selection.links && selection.links.length > 0;
|
||||||
|
const isSingleLink = !hasSelection && hasLinks && selection.links.length === 1
|
||||||
|
const isMultipleLinks = !hasSelection && hasLinks && selection.links.length > 1
|
||||||
|
const canDelete = hasSelection || hasLinks
|
||||||
|
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
|
||||||
|
|
||||||
|
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
|
||||||
|
|
||||||
|
|
||||||
|
const menuItems = [
|
||||||
|
{ onselect: 'core:show-action-list', onpostselect: function() {} },
|
||||||
|
{
|
||||||
|
label: RED._("contextMenu.insert"),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: RED._("contextMenu.node"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.view.showQuickAddDialog({
|
||||||
|
position: [ options.x - offset.left, options.y - offset.top ],
|
||||||
|
touchTrigger: true,
|
||||||
|
splice: isSingleLink?selection.links[0]:undefined,
|
||||||
|
// spliceMultiple: isMultipleLinks
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: RED._("contextMenu.junction"),
|
||||||
|
onselect: 'core:split-wires-with-junctions',
|
||||||
|
disabled: hasSelection || !hasLinks
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: RED._("contextMenu.linkNodes"),
|
||||||
|
onselect: 'core:split-wire-with-link-nodes',
|
||||||
|
disabled: hasSelection || !hasLinks
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
// menuItems.push(
|
||||||
|
// {
|
||||||
|
// label: (isSingleLink || isMultipleLinks)?'Insert into wire...':'Add node...',
|
||||||
|
// onselect: function() {
|
||||||
|
// RED.view.showQuickAddDialog({
|
||||||
|
// position: [ options.x - offset.left, options.y - offset.top ],
|
||||||
|
// touchTrigger: true,
|
||||||
|
// splice: isSingleLink?selection.links[0]:undefined,
|
||||||
|
// spliceMultiple: isMultipleLinks
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// )
|
||||||
|
// if (hasLinks && !hasSelection) {
|
||||||
|
// menuItems.push({ onselect: 'core:split-wires-with-junctions', label: 'Insert junction'})
|
||||||
|
// }
|
||||||
|
menuItems.push(
|
||||||
|
null,
|
||||||
|
{ onselect: 'core:undo', disabled: RED.history.list().length === 0 },
|
||||||
|
{ onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
|
||||||
|
null,
|
||||||
|
{ onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection},
|
||||||
|
{ onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection },
|
||||||
|
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !RED.view.clipboard() },
|
||||||
|
{ onselect: 'core:delete-selection', disabled: !canDelete },
|
||||||
|
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
|
||||||
|
{ onselect: 'core:select-all-nodes' }
|
||||||
|
)
|
||||||
|
|
||||||
|
if (hasSelection) {
|
||||||
|
menuItems.push(
|
||||||
|
null,
|
||||||
|
isGroup ?
|
||||||
|
{ onselect: 'core:ungroup-selection', disabled: !isGroup }
|
||||||
|
: { onselect: 'core:group-selection', disabled: !hasSelection }
|
||||||
|
)
|
||||||
|
if (canRemoveFromGroup) {
|
||||||
|
menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") })
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
const offset = $("#red-ui-workspace-chart").offset()
|
||||||
|
menu = RED.menu.init({
|
||||||
|
direction: 'right',
|
||||||
|
onpreselect: function() {
|
||||||
|
disposeMenu()
|
||||||
|
},
|
||||||
|
onpostselect: function() {
|
||||||
|
RED.view.focus()
|
||||||
|
},
|
||||||
|
options: menuItems
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.attr("id","red-ui-workspace-context-menu");
|
||||||
|
menu.css({
|
||||||
|
position: "absolute"
|
||||||
|
})
|
||||||
|
menu.appendTo("body");
|
||||||
|
|
||||||
|
// TODO: prevent the menu from overflowing the window.
|
||||||
|
|
||||||
|
var top = options.y
|
||||||
|
var left = options.x
|
||||||
|
|
||||||
|
if (top+menu.height()-$(document).scrollTop() > $(window).height()) {
|
||||||
|
top -= (top+menu.height())-$(window).height() + 22;
|
||||||
|
}
|
||||||
|
if (left+menu.width()-$(document).scrollLeft() > $(window).width()) {
|
||||||
|
left -= (left+menu.width())-$(window).width() + 18;
|
||||||
|
}
|
||||||
|
menu.css({
|
||||||
|
top: top+"px",
|
||||||
|
left: left+"px"
|
||||||
|
})
|
||||||
|
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
||||||
|
$(document).on("mousedown.red-ui-workspace-context-menu", function(evt) {
|
||||||
|
if (menu && menu[0].contains(evt.target)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
disposeMenu()
|
||||||
|
});
|
||||||
|
menu.show();
|
||||||
|
|
||||||
|
// menu.show({
|
||||||
|
// target: $('#red-ui-main-container'),
|
||||||
|
// x: options.x,
|
||||||
|
// y: options.y
|
||||||
|
// })
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: show,
|
||||||
|
hide: disposeMenu
|
||||||
|
}
|
||||||
|
})()
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
const MONACO = "monaco";
|
const MONACO = "monaco";
|
||||||
const ACE = "ace";
|
const ACE = "ace";
|
||||||
const defaultEditor = ACE;
|
const defaultEditor = MONACO;
|
||||||
const DEFAULT_SETTINGS = { lib: defaultEditor, options: {} };
|
const DEFAULT_SETTINGS = { lib: defaultEditor, options: {} };
|
||||||
var selectedCodeEditor = null;
|
var selectedCodeEditor = null;
|
||||||
var initialised = false;
|
var initialised = false;
|
||||||
|
@ -534,6 +534,7 @@
|
|||||||
var container = $("#red-ui-editor-type-json-tab-ui-container").css({"height":"100%"});
|
var container = $("#red-ui-editor-type-json-tab-ui-container").css({"height":"100%"});
|
||||||
var filterDepth = Infinity;
|
var filterDepth = Infinity;
|
||||||
var list = $('<div class="red-ui-debug-msg-payload red-ui-editor-type-json-editor">').appendTo(container).treeList({
|
var list = $('<div class="red-ui-debug-msg-payload red-ui-editor-type-json-editor">').appendTo(container).treeList({
|
||||||
|
selectable: false,
|
||||||
rootSortable: false,
|
rootSortable: false,
|
||||||
sortable: ".red-ui-editor-type-json-editor-item-handle",
|
sortable: ".red-ui-editor-type-json-editor-item-handle",
|
||||||
}).on("treelistchangeparent", function(event, evt) {
|
}).on("treelistchangeparent", function(event, evt) {
|
||||||
|
@ -363,14 +363,22 @@ RED.library = (function() {
|
|||||||
options.onconfirm(item);
|
options.onconfirm(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
|
var itemTools = null;
|
||||||
|
if (options.folderTools) {
|
||||||
|
dirList.on('treelistselect', function(event, item) {
|
||||||
|
if (item.writable !== false && item.treeList) {
|
||||||
|
if (itemTools) {
|
||||||
|
itemTools.remove();
|
||||||
|
}
|
||||||
|
itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
|
||||||
var menuButton = $('<button class="red-ui-button red-ui-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
|
var menuButton = $('<button class="red-ui-button red-ui-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
|
||||||
.on("click", function(evt) {
|
.on("click", function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
var elementPos = menuButton.offset();
|
var elementPos = menuButton.offset();
|
||||||
|
|
||||||
var menuOptionMenu = RED.menu.init({id:"red-ui-library-browser-menu",
|
var menuOptionMenu
|
||||||
|
= RED.menu.init({id:"red-ui-library-browser-menu",
|
||||||
options: [
|
options: [
|
||||||
{id:"red-ui-library-browser-menu-addFolder",label:RED._("library.newFolder"), onselect: function() {
|
{id:"red-ui-library-browser-menu-addFolder",label:RED._("library.newFolder"), onselect: function() {
|
||||||
var defaultFolderName = "new-folder";
|
var defaultFolderName = "new-folder";
|
||||||
@ -460,9 +468,7 @@ RED.library = (function() {
|
|||||||
}).show();
|
}).show();
|
||||||
|
|
||||||
}).appendTo(itemTools);
|
}).appendTo(itemTools);
|
||||||
if (options.folderTools) {
|
|
||||||
dirList.on('treelistselect', function(event, item) {
|
|
||||||
if (item.writable !== false && item.treeList) {
|
|
||||||
itemTools.appendTo(item.treeList.label);
|
itemTools.appendTo(item.treeList.label);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -208,7 +208,7 @@ RED.palette = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function escapeCategory(category) {
|
function escapeCategory(category) {
|
||||||
return category.replace(/[ /.]/g,"_");
|
return category.replace(/[\x00-\x2c\x2e-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]/g,"_");
|
||||||
}
|
}
|
||||||
function addNodeType(nt,def) {
|
function addNodeType(nt,def) {
|
||||||
if (getPaletteNode(nt).length) {
|
if (getPaletteNode(nt).length) {
|
||||||
|
@ -604,6 +604,14 @@ RED.subflow = (function() {
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nodeOrJunction(id) {
|
||||||
|
var node = RED.nodes.node(id);
|
||||||
|
if (node) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
return RED.nodes.junction(id);
|
||||||
|
}
|
||||||
|
|
||||||
function convertToSubflow() {
|
function convertToSubflow() {
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (!selection.nodes) {
|
if (!selection.nodes) {
|
||||||
@ -792,14 +800,15 @@ RED.subflow = (function() {
|
|||||||
|
|
||||||
subflow.in.forEach(function(input) {
|
subflow.in.forEach(function(input) {
|
||||||
input.wires.forEach(function(wire) {
|
input.wires.forEach(function(wire) {
|
||||||
var link = {source: input, sourcePort: 0, target: RED.nodes.node(wire.id) }
|
var link = {source: input, sourcePort: 0, target: nodeOrJunction(wire.id) }
|
||||||
new_links.push(link);
|
new_links.push(link);
|
||||||
RED.nodes.addLink(link);
|
RED.nodes.addLink(link);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
subflow.out.forEach(function(output,i) {
|
subflow.out.forEach(function(output,i) {
|
||||||
output.wires.forEach(function(wire) {
|
output.wires.forEach(function(wire) {
|
||||||
var link = {source: RED.nodes.node(wire.id), sourcePort: wire.port , target: output }
|
var link = {source: nodeOrJunction(wire.id), sourcePort: wire.port , target: output }
|
||||||
new_links.push(link);
|
new_links.push(link);
|
||||||
RED.nodes.addLink(link);
|
RED.nodes.addLink(link);
|
||||||
});
|
});
|
||||||
@ -815,7 +824,7 @@ RED.subflow = (function() {
|
|||||||
n.links = n.links.filter(function(id) {
|
n.links = n.links.filter(function(id) {
|
||||||
var isLocalLink = nodes.hasOwnProperty(id);
|
var isLocalLink = nodes.hasOwnProperty(id);
|
||||||
if (!isLocalLink) {
|
if (!isLocalLink) {
|
||||||
var otherNode = RED.nodes.node(id);
|
var otherNode = nodeOrJunction(id);
|
||||||
if (otherNode && otherNode.links) {
|
if (otherNode && otherNode.links) {
|
||||||
var i = otherNode.links.indexOf(n.id);
|
var i = otherNode.links.indexOf(n.id);
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
@ -831,7 +840,6 @@ RED.subflow = (function() {
|
|||||||
RED.nodes.moveNodeToTab(n, subflow.id);
|
RED.nodes.moveNodeToTab(n, subflow.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var historyEvent = {
|
var historyEvent = {
|
||||||
t:'createSubflow',
|
t:'createSubflow',
|
||||||
nodes:[subflowInstance.id],
|
nodes:[subflowInstance.id],
|
||||||
|
@ -104,7 +104,9 @@ RED.typeSearch = (function() {
|
|||||||
var index = Math.max(0,selected);
|
var index = Math.max(0,selected);
|
||||||
if (index < children.length) {
|
if (index < children.length) {
|
||||||
var n = $(children[index]).find(".red-ui-editableList-item-content").data('data');
|
var n = $(children[index]).find(".red-ui-editableList-item-content").data('data');
|
||||||
|
if (!/^_action_:/.test(n.type)) {
|
||||||
typesUsed[n.type] = Date.now();
|
typesUsed[n.type] = Date.now();
|
||||||
|
}
|
||||||
if (n.def.outputs === 0) {
|
if (n.def.outputs === 0) {
|
||||||
confirm(n);
|
confirm(n);
|
||||||
} else {
|
} else {
|
||||||
@ -173,6 +175,8 @@ RED.typeSearch = (function() {
|
|||||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
|
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
|
||||||
if (object.type === "junction") {
|
if (object.type === "junction") {
|
||||||
nodeDiv.addClass("red-ui-palette-icon-junction");
|
nodeDiv.addClass("red-ui-palette-icon-junction");
|
||||||
|
} else if (/^_action_:/.test(object.type)) {
|
||||||
|
nodeDiv.addClass("red-ui-palette-icon-junction")
|
||||||
} else {
|
} else {
|
||||||
var colour = RED.utils.getNodeColor(object.type,def);
|
var colour = RED.utils.getNodeColor(object.type,def);
|
||||||
nodeDiv.css('backgroundColor',colour);
|
nodeDiv.css('backgroundColor',colour);
|
||||||
@ -182,12 +186,15 @@ RED.typeSearch = (function() {
|
|||||||
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
|
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
|
||||||
RED.utils.createIconElement(icon_url, iconContainer, false);
|
RED.utils.createIconElement(icon_url, iconContainer, false);
|
||||||
|
|
||||||
if (object.type !== "junction" && def.inputs > 0) {
|
|
||||||
|
if (!/^_action_:/.test(object.type) && object.type !== "junction") {
|
||||||
|
if (def.inputs > 0) {
|
||||||
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
|
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
|
||||||
}
|
}
|
||||||
if (object.type !== "junction" && def.outputs > 0) {
|
if (def.outputs > 0) {
|
||||||
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
|
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
||||||
|
|
||||||
@ -207,7 +214,9 @@ RED.typeSearch = (function() {
|
|||||||
}
|
}
|
||||||
function confirm(def) {
|
function confirm(def) {
|
||||||
hide();
|
hide();
|
||||||
|
if (!/^_action_:/.test(def.type)) {
|
||||||
typesUsed[def.type] = Date.now();
|
typesUsed[def.type] = Date.now();
|
||||||
|
}
|
||||||
addCallback(def.type);
|
addCallback(def.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,6 +325,7 @@ RED.typeSearch = (function() {
|
|||||||
function applyFilter(filter,type,def) {
|
function applyFilter(filter,type,def) {
|
||||||
return !filter ||
|
return !filter ||
|
||||||
(
|
(
|
||||||
|
(!filter.spliceMultiple) &&
|
||||||
(!filter.type || type === filter.type) &&
|
(!filter.type || type === filter.type) &&
|
||||||
(!filter.input || type === 'junction' || def.inputs > 0) &&
|
(!filter.input || type === 'junction' || def.inputs > 0) &&
|
||||||
(!filter.output || type === 'junction' || def.outputs > 0)
|
(!filter.output || type === 'junction' || def.outputs > 0)
|
||||||
@ -330,6 +340,13 @@ RED.typeSearch = (function() {
|
|||||||
'inject','debug','function','change','switch','junction'
|
'inject','debug','function','change','switch','junction'
|
||||||
].filter(function(t) { return applyFilter(opts.filter,t,RED.nodes.getType(t)); });
|
].filter(function(t) { return applyFilter(opts.filter,t,RED.nodes.getType(t)); });
|
||||||
|
|
||||||
|
// if (opts.filter && opts.filter.input && opts.filter.output && !opts.filter.type) {
|
||||||
|
// if (opts.filter.spliceMultiple) {
|
||||||
|
// common.push('_action_:core:split-wires-with-junctions')
|
||||||
|
// }
|
||||||
|
// common.push('_action_:core:split-wire-with-link-nodes')
|
||||||
|
// }
|
||||||
|
|
||||||
var recentlyUsed = Object.keys(typesUsed);
|
var recentlyUsed = Object.keys(typesUsed);
|
||||||
recentlyUsed.sort(function(a,b) {
|
recentlyUsed.sort(function(a,b) {
|
||||||
return typesUsed[b]-typesUsed[a];
|
return typesUsed[b]-typesUsed[a];
|
||||||
@ -354,6 +371,8 @@ RED.typeSearch = (function() {
|
|||||||
var itemDef = RED.nodes.getType(common[i]);
|
var itemDef = RED.nodes.getType(common[i]);
|
||||||
if (common[i] === 'junction') {
|
if (common[i] === 'junction') {
|
||||||
itemDef = { inputs:1, outputs: 1, label: 'junction', type: 'junction'}
|
itemDef = { inputs:1, outputs: 1, label: 'junction', type: 'junction'}
|
||||||
|
} else if (/^_action_:/.test(common[i]) ) {
|
||||||
|
itemDef = { inputs:1, outputs: 1, label: common[i], type: common[i]}
|
||||||
}
|
}
|
||||||
if (itemDef) {
|
if (itemDef) {
|
||||||
item = {
|
item = {
|
||||||
|
@ -1032,6 +1032,8 @@ RED.utils = (function() {
|
|||||||
return "font-awesome/fa-circle-o"
|
return "font-awesome/fa-circle-o"
|
||||||
} else if (def.category === 'config') {
|
} else if (def.category === 'config') {
|
||||||
return RED.settings.apiRootUrl+"icons/node-red/cog.svg"
|
return RED.settings.apiRootUrl+"icons/node-red/cog.svg"
|
||||||
|
} else if ((node && /^_action_:/.test(node.type)) || /^_action_:/.test(def.type)) {
|
||||||
|
return "font-awesome/fa-cogs"
|
||||||
} else if (node && node.type === 'tab') {
|
} else if (node && node.type === 'tab') {
|
||||||
return "red-ui-icons/red-ui-icons-flow"
|
return "red-ui-icons/red-ui-icons-flow"
|
||||||
// return RED.settings.apiRootUrl+"images/subflow_tab.svg"
|
// return RED.settings.apiRootUrl+"images/subflow_tab.svg"
|
||||||
|
@ -336,17 +336,17 @@ RED.view.tools = (function() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNode() {
|
// function addNode() {
|
||||||
var selection = RED.view.selection();
|
// var selection = RED.view.selection();
|
||||||
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].outputs > 0) {
|
// if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].outputs > 0) {
|
||||||
var selectedNode = selection.nodes[0];
|
// var selectedNode = selection.nodes[0];
|
||||||
RED.view.showQuickAddDialog([
|
// RED.view.showQuickAddDialog([
|
||||||
selectedNode.x + selectedNode.w + 50,selectedNode.y
|
// selectedNode.x + selectedNode.w + 50,selectedNode.y
|
||||||
])
|
// ])
|
||||||
} else {
|
// } else {
|
||||||
RED.view.showQuickAddDialog();
|
// RED.view.showQuickAddDialog();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
function gotoNearestNode(direction) {
|
function gotoNearestNode(direction) {
|
||||||
@ -815,6 +815,9 @@ RED.view.tools = (function() {
|
|||||||
*/
|
*/
|
||||||
function splitWiresWithLinkNodes(wires) {
|
function splitWiresWithLinkNodes(wires) {
|
||||||
let wiresToSplit = wires || RED.view.selection().links;
|
let wiresToSplit = wires || RED.view.selection().links;
|
||||||
|
if (!wiresToSplit) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!Array.isArray(wiresToSplit)) {
|
if (!Array.isArray(wiresToSplit)) {
|
||||||
wiresToSplit = [wiresToSplit];
|
wiresToSplit = [wiresToSplit];
|
||||||
}
|
}
|
||||||
@ -1047,6 +1050,135 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addJunctionsToWires(wires) {
|
||||||
|
let wiresToSplit = wires || RED.view.selection().links;
|
||||||
|
if (!wiresToSplit) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!Array.isArray(wiresToSplit)) {
|
||||||
|
wiresToSplit = [wiresToSplit];
|
||||||
|
}
|
||||||
|
if (wiresToSplit.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var removedLinks = new Set()
|
||||||
|
var addedLinks = []
|
||||||
|
var addedJunctions = []
|
||||||
|
|
||||||
|
var groupedLinks = {}
|
||||||
|
wiresToSplit.forEach(function(l) {
|
||||||
|
var sourceId = l.source.id+":"+l.sourcePort
|
||||||
|
groupedLinks[sourceId] = groupedLinks[sourceId] || []
|
||||||
|
groupedLinks[sourceId].push(l)
|
||||||
|
|
||||||
|
groupedLinks[l.target.id] = groupedLinks[l.target.id] || []
|
||||||
|
groupedLinks[l.target.id].push(l)
|
||||||
|
});
|
||||||
|
var linkGroups = Object.keys(groupedLinks)
|
||||||
|
linkGroups.sort(function(A,B) {
|
||||||
|
return groupedLinks[B].length - groupedLinks[A].length
|
||||||
|
})
|
||||||
|
linkGroups.forEach(function(gid) {
|
||||||
|
var links = groupedLinks[gid]
|
||||||
|
var junction = {
|
||||||
|
_def: {defaults:{}},
|
||||||
|
type: 'junction',
|
||||||
|
z: RED.workspaces.active(),
|
||||||
|
id: RED.nodes.id(),
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
w: 0, h: 0,
|
||||||
|
outputs: 1,
|
||||||
|
inputs: 1,
|
||||||
|
dirty: true
|
||||||
|
}
|
||||||
|
links = links.filter(function(l) { return !removedLinks.has(l) })
|
||||||
|
if (links.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let pointCount = 0
|
||||||
|
links.forEach(function(l) {
|
||||||
|
if (l._sliceLocation) {
|
||||||
|
junction.x += l._sliceLocation.x
|
||||||
|
junction.y += l._sliceLocation.y
|
||||||
|
delete l._sliceLocation
|
||||||
|
pointCount++
|
||||||
|
} else {
|
||||||
|
junction.x += l.source.x + l.source.w/2 + l.target.x - l.target.w/2
|
||||||
|
junction.y += l.source.y + l.target.y
|
||||||
|
pointCount += 2
|
||||||
|
}
|
||||||
|
})
|
||||||
|
junction.x = Math.round(junction.x/pointCount)
|
||||||
|
junction.y = Math.round(junction.y/pointCount)
|
||||||
|
if (RED.view.snapGrid) {
|
||||||
|
let gridSize = RED.view.gridSize()
|
||||||
|
junction.x = (gridSize*Math.round(junction.x/gridSize));
|
||||||
|
junction.y = (gridSize*Math.round(junction.y/gridSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodeGroups = new Set()
|
||||||
|
|
||||||
|
RED.nodes.addJunction(junction)
|
||||||
|
addedJunctions.push(junction)
|
||||||
|
let newLink
|
||||||
|
if (gid === links[0].source.id+":"+links[0].sourcePort) {
|
||||||
|
newLink = {
|
||||||
|
source: links[0].source,
|
||||||
|
sourcePort: links[0].sourcePort,
|
||||||
|
target: junction
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newLink = {
|
||||||
|
source: junction,
|
||||||
|
sourcePort: 0,
|
||||||
|
target: links[0].target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addedLinks.push(newLink)
|
||||||
|
RED.nodes.addLink(newLink)
|
||||||
|
links.forEach(function(l) {
|
||||||
|
removedLinks.add(l)
|
||||||
|
RED.nodes.removeLink(l)
|
||||||
|
let newLink
|
||||||
|
if (gid === l.target.id) {
|
||||||
|
newLink = {
|
||||||
|
source: l.source,
|
||||||
|
sourcePort: l.sourcePort,
|
||||||
|
target: junction
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newLink = {
|
||||||
|
source: junction,
|
||||||
|
sourcePort: 0,
|
||||||
|
target: l.target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addedLinks.push(newLink)
|
||||||
|
RED.nodes.addLink(newLink)
|
||||||
|
nodeGroups.add(l.source.g || "__NONE__")
|
||||||
|
nodeGroups.add(l.target.g || "__NONE__")
|
||||||
|
})
|
||||||
|
if (nodeGroups.size === 1) {
|
||||||
|
var group = nodeGroups.values().next().value
|
||||||
|
if (group !== "__NONE__") {
|
||||||
|
RED.group.addToGroup(RED.nodes.group(group), junction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (addedJunctions.length > 0) {
|
||||||
|
RED.history.push({
|
||||||
|
t: 'add',
|
||||||
|
links: addedLinks,
|
||||||
|
junctions: addedJunctions,
|
||||||
|
removedLinks: Array.from(removedLinks)
|
||||||
|
})
|
||||||
|
RED.nodes.dirty(true)
|
||||||
|
}
|
||||||
|
RED.view.redraw(true);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: function() {
|
init: function() {
|
||||||
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
|
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
|
||||||
@ -1109,6 +1241,7 @@ RED.view.tools = (function() {
|
|||||||
RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
|
RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
|
||||||
|
|
||||||
RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
|
RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
|
||||||
|
RED.actions.add("core:split-wires-with-junctions", function () { addJunctionsToWires() });
|
||||||
|
|
||||||
RED.actions.add("core:generate-node-names", generateNodeNames )
|
RED.actions.add("core:generate-node-names", generateNodeNames )
|
||||||
|
|
||||||
|
@ -206,7 +206,15 @@ RED.view = (function() {
|
|||||||
function init() {
|
function init() {
|
||||||
|
|
||||||
chart = $("#red-ui-workspace-chart");
|
chart = $("#red-ui-workspace-chart");
|
||||||
|
chart.on('contextmenu', function(evt) {
|
||||||
|
evt.preventDefault()
|
||||||
|
evt.stopPropagation()
|
||||||
|
RED.contextMenu.show({
|
||||||
|
x:evt.clientX-5,
|
||||||
|
y:evt.clientY-5
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
})
|
||||||
outer = d3.select("#red-ui-workspace-chart")
|
outer = d3.select("#red-ui-workspace-chart")
|
||||||
.append("svg:svg")
|
.append("svg:svg")
|
||||||
.attr("width", space_width)
|
.attr("width", space_width)
|
||||||
@ -230,6 +238,7 @@ RED.view = (function() {
|
|||||||
.on("mousedown", canvasMouseDown)
|
.on("mousedown", canvasMouseDown)
|
||||||
.on("mouseup", canvasMouseUp)
|
.on("mouseup", canvasMouseUp)
|
||||||
.on("mouseenter", function() {
|
.on("mouseenter", function() {
|
||||||
|
d3.select(document).on('mouseup.red-ui-workspace-tracker', null)
|
||||||
if (lasso) {
|
if (lasso) {
|
||||||
if (d3.event.buttons !== 1) {
|
if (d3.event.buttons !== 1) {
|
||||||
lasso.remove();
|
lasso.remove();
|
||||||
@ -245,6 +254,7 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.on("mouseleave", canvasMouseLeave)
|
||||||
.on("touchend", function() {
|
.on("touchend", function() {
|
||||||
d3.event.preventDefault();
|
d3.event.preventDefault();
|
||||||
clearTimeout(touchStartTime);
|
clearTimeout(touchStartTime);
|
||||||
@ -385,6 +395,9 @@ RED.view = (function() {
|
|||||||
drag_lines = [];
|
drag_lines = [];
|
||||||
|
|
||||||
RED.events.on("workspace:change",function(event) {
|
RED.events.on("workspace:change",function(event) {
|
||||||
|
// Just in case the mouse left the workspace whilst doing an action,
|
||||||
|
// put us back into default mode so the refresh works
|
||||||
|
mouse_mode = 0
|
||||||
if (event.old !== 0) {
|
if (event.old !== 0) {
|
||||||
workspaceScrollPositions[event.old] = {
|
workspaceScrollPositions[event.old] = {
|
||||||
left:chart.scrollLeft(),
|
left:chart.scrollLeft(),
|
||||||
@ -526,6 +539,23 @@ RED.view = (function() {
|
|||||||
nn.x = mousePos[0];
|
nn.x = mousePos[0];
|
||||||
nn.y = mousePos[1];
|
nn.y = mousePos[1];
|
||||||
|
|
||||||
|
var minX = nn.w/2 -5;
|
||||||
|
if (nn.x < minX) {
|
||||||
|
nn.x = minX;
|
||||||
|
}
|
||||||
|
var minY = nn.h/2 -5;
|
||||||
|
if (nn.y < minY) {
|
||||||
|
nn.y = minY;
|
||||||
|
}
|
||||||
|
var maxX = space_width -nn.w/2 +5;
|
||||||
|
if (nn.x > maxX) {
|
||||||
|
nn.x = maxX;
|
||||||
|
}
|
||||||
|
var maxY = space_height -nn.h +5;
|
||||||
|
if (nn.y > maxY) {
|
||||||
|
nn.y = maxY;
|
||||||
|
}
|
||||||
|
|
||||||
if (snapGrid) {
|
if (snapGrid) {
|
||||||
var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn);
|
var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn);
|
||||||
nn.x -= gridOffset.x;
|
nn.x -= gridOffset.x;
|
||||||
@ -958,6 +988,7 @@ RED.view = (function() {
|
|||||||
if (RED.view.DEBUG) {
|
if (RED.view.DEBUG) {
|
||||||
console.warn("canvasMouseDown", { mouse_mode, point: d3.mouse(this), event: d3.event });
|
console.warn("canvasMouseDown", { mouse_mode, point: d3.mouse(this), event: d3.event });
|
||||||
}
|
}
|
||||||
|
RED.contextMenu.hide();
|
||||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||||
d3.event.stopPropagation();
|
d3.event.stopPropagation();
|
||||||
return;
|
return;
|
||||||
@ -970,7 +1001,10 @@ RED.view = (function() {
|
|||||||
scroll_position = [chart.scrollLeft(),chart.scrollTop()];
|
scroll_position = [chart.scrollLeft(),chart.scrollTop()];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!mousedown_node && !mousedown_link && !mousedown_group) {
|
if (d3.event.button === 2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!mousedown_node && !mousedown_link && !mousedown_group && !d3.event.shiftKey) {
|
||||||
selectedLinks.clear();
|
selectedLinks.clear();
|
||||||
updateSelection();
|
updateSelection();
|
||||||
}
|
}
|
||||||
@ -1024,6 +1058,7 @@ RED.view = (function() {
|
|||||||
options = options || {};
|
options = options || {};
|
||||||
var point = options.position || lastClickPosition;
|
var point = options.position || lastClickPosition;
|
||||||
var spliceLink = options.splice;
|
var spliceLink = options.splice;
|
||||||
|
var spliceMultipleLinks = options.spliceMultiple
|
||||||
var targetGroup = options.group;
|
var targetGroup = options.group;
|
||||||
var touchTrigger = options.touchTrigger;
|
var touchTrigger = options.touchTrigger;
|
||||||
|
|
||||||
@ -1036,6 +1071,10 @@ RED.view = (function() {
|
|||||||
var ox = point[0];
|
var ox = point[0];
|
||||||
var oy = point[1];
|
var oy = point[1];
|
||||||
|
|
||||||
|
const offset = $("#red-ui-workspace-chart").offset()
|
||||||
|
var clientX = ox + offset.left - $("#red-ui-workspace-chart").scrollLeft()
|
||||||
|
var clientY = oy + offset.top - $("#red-ui-workspace-chart").scrollTop()
|
||||||
|
|
||||||
if (RED.settings.get("editor").view['view-snap-grid']) {
|
if (RED.settings.get("editor").view['view-snap-grid']) {
|
||||||
// eventLayer.append("circle").attr("cx",point[0]).attr("cy",point[1]).attr("r","2").attr('fill','red')
|
// eventLayer.append("circle").attr("cx",point[0]).attr("cy",point[1]).attr("r","2").attr('fill','red')
|
||||||
point[0] = Math.round(point[0] / gridSize) * gridSize;
|
point[0] = Math.round(point[0] / gridSize) * gridSize;
|
||||||
@ -1087,8 +1126,12 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
hideDragLines();
|
hideDragLines();
|
||||||
}
|
}
|
||||||
if (spliceLink) {
|
if (spliceLink || spliceMultipleLinks) {
|
||||||
filter = {input:true, output:true}
|
filter = {
|
||||||
|
input:true,
|
||||||
|
output:true,
|
||||||
|
spliceMultiple: spliceMultipleLinks
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rebuildQuickAddLink = function() {
|
var rebuildQuickAddLink = function() {
|
||||||
@ -1113,8 +1156,8 @@ RED.view = (function() {
|
|||||||
var lastAddedWidth;
|
var lastAddedWidth;
|
||||||
|
|
||||||
RED.typeSearch.show({
|
RED.typeSearch.show({
|
||||||
x:d3.event.clientX-mainPos.left-node_width/2 - (ox-point[0]),
|
x:clientX-mainPos.left-node_width/2 - (ox-point[0]),
|
||||||
y:d3.event.clientY-mainPos.top+ node_height/2 + 5 - (oy-point[1]),
|
y:clientY-mainPos.top+ node_height/2 + 5 - (oy-point[1]),
|
||||||
disableFocus: touchTrigger,
|
disableFocus: touchTrigger,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
move: function(dx,dy) {
|
move: function(dx,dy) {
|
||||||
@ -1142,7 +1185,7 @@ RED.view = (function() {
|
|||||||
hideDragLines();
|
hideDragLines();
|
||||||
redraw();
|
redraw();
|
||||||
},
|
},
|
||||||
add: function(type,keepAdding) {
|
add: function(type, keepAdding) {
|
||||||
if (touchTrigger) {
|
if (touchTrigger) {
|
||||||
keepAdding = false;
|
keepAdding = false;
|
||||||
resetMouseVars();
|
resetMouseVars();
|
||||||
@ -1150,7 +1193,13 @@ RED.view = (function() {
|
|||||||
|
|
||||||
var nn;
|
var nn;
|
||||||
var historyEvent;
|
var historyEvent;
|
||||||
if (type === 'junction') {
|
if (/^_action_:/.test(type)) {
|
||||||
|
const actionName = type.substring(9)
|
||||||
|
quickAddActive = false;
|
||||||
|
ghostNode.remove();
|
||||||
|
RED.actions.invoke(actionName)
|
||||||
|
return
|
||||||
|
} else if (type === 'junction') {
|
||||||
nn = {
|
nn = {
|
||||||
_def: {defaults:{}},
|
_def: {defaults:{}},
|
||||||
type: 'junction',
|
type: 'junction',
|
||||||
@ -1716,7 +1765,14 @@ RED.view = (function() {
|
|||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function canvasMouseLeave() {
|
||||||
|
if (mouse_mode !== 0 && d3.event.buttons !== 0) {
|
||||||
|
d3.select(document).on('mouseup.red-ui-workspace-tracker', function() {
|
||||||
|
d3.select(document).on('mouseup.red-ui-workspace-tracker', null)
|
||||||
|
canvasMouseUp.call(this)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
function canvasMouseUp() {
|
function canvasMouseUp() {
|
||||||
lastClickPosition = [d3.event.offsetX/scaleFactor,d3.event.offsetY/scaleFactor];
|
lastClickPosition = [d3.event.offsetX/scaleFactor,d3.event.offsetY/scaleFactor];
|
||||||
if (RED.view.DEBUG) {
|
if (RED.view.DEBUG) {
|
||||||
@ -1724,6 +1780,9 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
var i;
|
var i;
|
||||||
var historyEvent;
|
var historyEvent;
|
||||||
|
if (d3.event.button === 2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (mouse_mode === RED.state.PANNING) {
|
if (mouse_mode === RED.state.PANNING) {
|
||||||
resetMouseVars();
|
resetMouseVars();
|
||||||
return
|
return
|
||||||
@ -1815,8 +1874,20 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
activeLinks.forEach(function(link) {
|
||||||
|
if (!link.selected) {
|
||||||
|
var sourceY = link.source.y
|
||||||
|
var targetY = link.target.y
|
||||||
|
var sourceX = link.source.x+(link.source.w/2) + 10
|
||||||
|
var targetX = link.target.x-(link.target.w/2) - 10
|
||||||
|
if (
|
||||||
|
sourceX > x && sourceX < x2 && sourceY > y && sourceY < y2 &&
|
||||||
|
targetX > x && targetX < x2 && targetY > y && targetY < y2
|
||||||
|
) {
|
||||||
|
selectedLinks.add(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// var selectionChanged = false;
|
// var selectionChanged = false;
|
||||||
// do {
|
// do {
|
||||||
@ -1864,114 +1935,118 @@ RED.view = (function() {
|
|||||||
slicePath = null;
|
slicePath = null;
|
||||||
RED.view.redraw(true);
|
RED.view.redraw(true);
|
||||||
} else if (mouse_mode == RED.state.SLICING_JUNCTION) {
|
} else if (mouse_mode == RED.state.SLICING_JUNCTION) {
|
||||||
var removedLinks = new Set()
|
RED.actions.invoke("core:split-wires-with-junctions")
|
||||||
var addedLinks = []
|
|
||||||
var addedJunctions = []
|
|
||||||
|
|
||||||
var groupedLinks = {}
|
|
||||||
selectedLinks.forEach(function(l) {
|
|
||||||
var sourceId = l.source.id+":"+l.sourcePort
|
|
||||||
groupedLinks[sourceId] = groupedLinks[sourceId] || []
|
|
||||||
groupedLinks[sourceId].push(l)
|
|
||||||
|
|
||||||
groupedLinks[l.target.id] = groupedLinks[l.target.id] || []
|
|
||||||
groupedLinks[l.target.id].push(l)
|
|
||||||
});
|
|
||||||
var linkGroups = Object.keys(groupedLinks)
|
|
||||||
linkGroups.sort(function(A,B) {
|
|
||||||
return groupedLinks[B].length - groupedLinks[A].length
|
|
||||||
})
|
|
||||||
linkGroups.forEach(function(gid) {
|
|
||||||
var links = groupedLinks[gid]
|
|
||||||
var junction = {
|
|
||||||
_def: {defaults:{}},
|
|
||||||
type: 'junction',
|
|
||||||
z: RED.workspaces.active(),
|
|
||||||
id: RED.nodes.id(),
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
w: 0, h: 0,
|
|
||||||
outputs: 1,
|
|
||||||
inputs: 1,
|
|
||||||
dirty: true
|
|
||||||
}
|
|
||||||
links = links.filter(function(l) { return !removedLinks.has(l) })
|
|
||||||
if (links.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
links.forEach(function(l) {
|
|
||||||
junction.x += l._sliceLocation.x
|
|
||||||
junction.y += l._sliceLocation.y
|
|
||||||
})
|
|
||||||
junction.x = Math.round(junction.x/links.length)
|
|
||||||
junction.y = Math.round(junction.y/links.length)
|
|
||||||
if (snapGrid) {
|
|
||||||
junction.x = (gridSize*Math.round(junction.x/gridSize));
|
|
||||||
junction.y = (gridSize*Math.round(junction.y/gridSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
var nodeGroups = new Set()
|
|
||||||
|
|
||||||
RED.nodes.addJunction(junction)
|
|
||||||
addedJunctions.push(junction)
|
|
||||||
let newLink
|
|
||||||
if (gid === links[0].source.id+":"+links[0].sourcePort) {
|
|
||||||
newLink = {
|
|
||||||
source: links[0].source,
|
|
||||||
sourcePort: links[0].sourcePort,
|
|
||||||
target: junction
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newLink = {
|
|
||||||
source: junction,
|
|
||||||
sourcePort: 0,
|
|
||||||
target: links[0].target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addedLinks.push(newLink)
|
|
||||||
RED.nodes.addLink(newLink)
|
|
||||||
links.forEach(function(l) {
|
|
||||||
removedLinks.add(l)
|
|
||||||
RED.nodes.removeLink(l)
|
|
||||||
let newLink
|
|
||||||
if (gid === l.target.id) {
|
|
||||||
newLink = {
|
|
||||||
source: l.source,
|
|
||||||
sourcePort: l.sourcePort,
|
|
||||||
target: junction
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newLink = {
|
|
||||||
source: junction,
|
|
||||||
sourcePort: 0,
|
|
||||||
target: l.target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addedLinks.push(newLink)
|
|
||||||
RED.nodes.addLink(newLink)
|
|
||||||
nodeGroups.add(l.source.g || "__NONE__")
|
|
||||||
nodeGroups.add(l.target.g || "__NONE__")
|
|
||||||
})
|
|
||||||
if (nodeGroups.size === 1) {
|
|
||||||
var group = nodeGroups.values().next().value
|
|
||||||
if (group !== "__NONE__") {
|
|
||||||
RED.group.addToGroup(RED.nodes.group(group), junction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
slicePath.remove();
|
slicePath.remove();
|
||||||
slicePath = null;
|
slicePath = null;
|
||||||
|
|
||||||
if (addedJunctions.length > 0) {
|
// var removedLinks = new Set()
|
||||||
RED.history.push({
|
// var addedLinks = []
|
||||||
t: 'add',
|
// var addedJunctions = []
|
||||||
links: addedLinks,
|
//
|
||||||
junctions: addedJunctions,
|
// var groupedLinks = {}
|
||||||
removedLinks: Array.from(removedLinks)
|
// selectedLinks.forEach(function(l) {
|
||||||
})
|
// var sourceId = l.source.id+":"+l.sourcePort
|
||||||
RED.nodes.dirty(true)
|
// groupedLinks[sourceId] = groupedLinks[sourceId] || []
|
||||||
}
|
// groupedLinks[sourceId].push(l)
|
||||||
RED.view.redraw(true);
|
//
|
||||||
|
// groupedLinks[l.target.id] = groupedLinks[l.target.id] || []
|
||||||
|
// groupedLinks[l.target.id].push(l)
|
||||||
|
// });
|
||||||
|
// var linkGroups = Object.keys(groupedLinks)
|
||||||
|
// linkGroups.sort(function(A,B) {
|
||||||
|
// return groupedLinks[B].length - groupedLinks[A].length
|
||||||
|
// })
|
||||||
|
// linkGroups.forEach(function(gid) {
|
||||||
|
// var links = groupedLinks[gid]
|
||||||
|
// var junction = {
|
||||||
|
// _def: {defaults:{}},
|
||||||
|
// type: 'junction',
|
||||||
|
// z: RED.workspaces.active(),
|
||||||
|
// id: RED.nodes.id(),
|
||||||
|
// x: 0,
|
||||||
|
// y: 0,
|
||||||
|
// w: 0, h: 0,
|
||||||
|
// outputs: 1,
|
||||||
|
// inputs: 1,
|
||||||
|
// dirty: true
|
||||||
|
// }
|
||||||
|
// links = links.filter(function(l) { return !removedLinks.has(l) })
|
||||||
|
// if (links.length === 0) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// links.forEach(function(l) {
|
||||||
|
// junction.x += l._sliceLocation.x
|
||||||
|
// junction.y += l._sliceLocation.y
|
||||||
|
// })
|
||||||
|
// junction.x = Math.round(junction.x/links.length)
|
||||||
|
// junction.y = Math.round(junction.y/links.length)
|
||||||
|
// if (snapGrid) {
|
||||||
|
// junction.x = (gridSize*Math.round(junction.x/gridSize));
|
||||||
|
// junction.y = (gridSize*Math.round(junction.y/gridSize));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var nodeGroups = new Set()
|
||||||
|
//
|
||||||
|
// RED.nodes.addJunction(junction)
|
||||||
|
// addedJunctions.push(junction)
|
||||||
|
// let newLink
|
||||||
|
// if (gid === links[0].source.id+":"+links[0].sourcePort) {
|
||||||
|
// newLink = {
|
||||||
|
// source: links[0].source,
|
||||||
|
// sourcePort: links[0].sourcePort,
|
||||||
|
// target: junction
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// newLink = {
|
||||||
|
// source: junction,
|
||||||
|
// sourcePort: 0,
|
||||||
|
// target: links[0].target
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// addedLinks.push(newLink)
|
||||||
|
// RED.nodes.addLink(newLink)
|
||||||
|
// links.forEach(function(l) {
|
||||||
|
// removedLinks.add(l)
|
||||||
|
// RED.nodes.removeLink(l)
|
||||||
|
// let newLink
|
||||||
|
// if (gid === l.target.id) {
|
||||||
|
// newLink = {
|
||||||
|
// source: l.source,
|
||||||
|
// sourcePort: l.sourcePort,
|
||||||
|
// target: junction
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// newLink = {
|
||||||
|
// source: junction,
|
||||||
|
// sourcePort: 0,
|
||||||
|
// target: l.target
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// addedLinks.push(newLink)
|
||||||
|
// RED.nodes.addLink(newLink)
|
||||||
|
// nodeGroups.add(l.source.g || "__NONE__")
|
||||||
|
// nodeGroups.add(l.target.g || "__NONE__")
|
||||||
|
// })
|
||||||
|
// if (nodeGroups.size === 1) {
|
||||||
|
// var group = nodeGroups.values().next().value
|
||||||
|
// if (group !== "__NONE__") {
|
||||||
|
// RED.group.addToGroup(RED.nodes.group(group), junction)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// slicePath.remove();
|
||||||
|
// slicePath = null;
|
||||||
|
//
|
||||||
|
// if (addedJunctions.length > 0) {
|
||||||
|
// RED.history.push({
|
||||||
|
// t: 'add',
|
||||||
|
// links: addedLinks,
|
||||||
|
// junctions: addedJunctions,
|
||||||
|
// removedLinks: Array.from(removedLinks)
|
||||||
|
// })
|
||||||
|
// RED.nodes.dirty(true)
|
||||||
|
// }
|
||||||
|
// RED.view.redraw(true);
|
||||||
}
|
}
|
||||||
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||||
if (movingSet.length() > 0) {
|
if (movingSet.length() > 0) {
|
||||||
@ -2832,6 +2907,7 @@ RED.view = (function() {
|
|||||||
|
|
||||||
function portMouseDown(d,portType,portIndex, evt) {
|
function portMouseDown(d,portType,portIndex, evt) {
|
||||||
if (RED.view.DEBUG) { console.warn("portMouseDown", mouse_mode,d,portType,portIndex); }
|
if (RED.view.DEBUG) { console.warn("portMouseDown", mouse_mode,d,portType,portIndex); }
|
||||||
|
RED.contextMenu.hide();
|
||||||
evt = evt || d3.event;
|
evt = evt || d3.event;
|
||||||
if (evt === 1) {
|
if (evt === 1) {
|
||||||
return;
|
return;
|
||||||
@ -3340,6 +3416,7 @@ RED.view = (function() {
|
|||||||
function nodeMouseDown(d) {
|
function nodeMouseDown(d) {
|
||||||
if (RED.view.DEBUG) { console.warn("nodeMouseDown", mouse_mode,d); }
|
if (RED.view.DEBUG) { console.warn("nodeMouseDown", mouse_mode,d); }
|
||||||
focusView();
|
focusView();
|
||||||
|
RED.contextMenu.hide();
|
||||||
if (d3.event.button === 1) {
|
if (d3.event.button === 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3722,6 +3799,7 @@ RED.view = (function() {
|
|||||||
if (RED.view.DEBUG) {
|
if (RED.view.DEBUG) {
|
||||||
console.warn("linkMouseDown", { mouse_mode, point: d3.mouse(this), event: d3.event });
|
console.warn("linkMouseDown", { mouse_mode, point: d3.mouse(this), event: d3.event });
|
||||||
}
|
}
|
||||||
|
RED.contextMenu.hide();
|
||||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||||
d3.event.stopPropagation();
|
d3.event.stopPropagation();
|
||||||
return;
|
return;
|
||||||
@ -3781,6 +3859,9 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function groupMouseUp(g) {
|
function groupMouseUp(g) {
|
||||||
|
if (RED.view.DEBUG) {
|
||||||
|
console.warn("groupMouseUp", { mouse_mode, event: d3.event });
|
||||||
|
}
|
||||||
if (dblClickPrimed && mousedown_group == g && clickElapsed > 0 && clickElapsed < dblClickInterval) {
|
if (dblClickPrimed && mousedown_group == g && clickElapsed > 0 && clickElapsed < dblClickInterval) {
|
||||||
mouse_mode = RED.state.DEFAULT;
|
mouse_mode = RED.state.DEFAULT;
|
||||||
RED.editor.editGroup(g);
|
RED.editor.editGroup(g);
|
||||||
@ -3796,6 +3877,10 @@ RED.view = (function() {
|
|||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if (RED.view.DEBUG) {
|
||||||
|
console.warn("groupMouseDown", { mouse_mode, point: mouse, event: d3.event });
|
||||||
|
}
|
||||||
|
RED.contextMenu.hide();
|
||||||
focusView();
|
focusView();
|
||||||
if (d3.event.button === 1) {
|
if (d3.event.button === 1) {
|
||||||
return;
|
return;
|
||||||
@ -5722,10 +5807,15 @@ RED.view = (function() {
|
|||||||
node.dirty = true;
|
node.dirty = true;
|
||||||
node.dirtyStatus = true;
|
node.dirtyStatus = true;
|
||||||
node.changed = true;
|
node.changed = true;
|
||||||
|
if (node.type === "junction") {
|
||||||
|
RED.events.emit("junctions:change",node);
|
||||||
|
}
|
||||||
|
else {
|
||||||
RED.events.emit("nodes:change",node);
|
RED.events.emit("nodes:change",node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (historyEvents.length > 0) {
|
if (historyEvents.length > 0) {
|
||||||
RED.history.push({
|
RED.history.push({
|
||||||
t:"multi",
|
t:"multi",
|
||||||
|
@ -44,7 +44,7 @@ body {
|
|||||||
|
|
||||||
#red-ui-palette-shade, #red-ui-editor-shade, #red-ui-header-shade, #red-ui-sidebar-shade {
|
#red-ui-palette-shade, #red-ui-editor-shade, #red-ui-header-shade, #red-ui-sidebar-shade {
|
||||||
@include shade;
|
@include shade;
|
||||||
z-index: 2;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
#red-ui-sidebar-shade {
|
#red-ui-sidebar-shade {
|
||||||
left: -8px;
|
left: -8px;
|
||||||
|
@ -54,6 +54,21 @@
|
|||||||
white-space: normal !important;
|
white-space: normal !important;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
& > li.pull-left > a,
|
||||||
|
& > li.pull-left > a:focus {
|
||||||
|
padding: 4px 12px 4px 32px;
|
||||||
|
}
|
||||||
|
&.red-ui-menu-dropdown-noicons > li > a,
|
||||||
|
&.red-ui-menu-dropdown-noicons > li > a:focus {
|
||||||
|
padding: 4px 12px 4px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.red-ui-menu-dropdown-submenus > li > a,
|
||||||
|
&.red-ui-menu-dropdown-submenus > li > a:focus {
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
& > .active > a,
|
& > .active > a,
|
||||||
& > .active > a:hover,
|
& > .active > a:hover,
|
||||||
@ -145,8 +160,8 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
& > .red-ui-menu-dropdown {
|
& > .red-ui-menu-dropdown {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 100%;
|
left: calc(100% - 5px);
|
||||||
margin-top: -6px;
|
margin-top: 0;
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
}
|
}
|
||||||
&.open > .red-ui-menu-dropdown,
|
&.open > .red-ui-menu-dropdown,
|
||||||
@ -175,10 +190,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.red-ui-menu-dropdown-submenu>a:after {
|
.red-ui-menu-dropdown-submenu.pull-left>a:after {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.red-ui-menu-dropdown-submenu>a:before {
|
.red-ui-menu-dropdown-submenu.pull-left>a:before {
|
||||||
display: block;
|
display: block;
|
||||||
float: left;
|
float: left;
|
||||||
width: 0;
|
width: 0;
|
||||||
@ -192,7 +207,25 @@
|
|||||||
border-width: 5px 5px 5px 0;
|
border-width: 5px 5px 5px 0;
|
||||||
content: " ";
|
content: " ";
|
||||||
}
|
}
|
||||||
|
.red-ui-menu-dropdown-direction-right {
|
||||||
|
.red-ui-menu-dropdown-submenu>a:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.red-ui-menu-dropdown-submenu>a:before {
|
||||||
|
display: block;
|
||||||
|
float: right;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-right: -15px;
|
||||||
|
/* Caret Arrow */
|
||||||
|
border-color: transparent;
|
||||||
|
border-left-color: $menuCaret;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 5px 0 5px 5px;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
.red-ui-menu-dropdown-submenu.disabled > a:before {
|
.red-ui-menu-dropdown-submenu.disabled > a:before {
|
||||||
border-right-color: $menuCaret;
|
border-right-color: $menuCaret;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,7 @@
|
|||||||
width: 120px;
|
width: 120px;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 4;
|
||||||
&:not(.red-ui-palette-node-config):not(.red-ui-palette-node-small):first-child {
|
&:not(.red-ui-palette-node-config):not(.red-ui-palette-node-small):first-child {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,6 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: ew-resize;
|
cursor: ew-resize;
|
||||||
background-color: $primary-background;
|
background-color: $primary-background;
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
content: '';
|
content: '';
|
||||||
@ -104,4 +103,5 @@
|
|||||||
mask-repeat: no-repeat;
|
mask-repeat: no-repeat;
|
||||||
background-color: $grip-color;
|
background-color: $grip-color;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
packages/node_modules/@node-red/editor-client/src/tours/images/context-menu.png
vendored
Normal file
BIN
packages/node_modules/@node-red/editor-client/src/tours/images/context-menu.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
@ -1,15 +1,30 @@
|
|||||||
export default {
|
export default {
|
||||||
version: "3.0.0-beta.1",
|
version: "3.0.0-beta.3",
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
titleIcon: "fa fa-map-o",
|
titleIcon: "fa fa-map-o",
|
||||||
title: {
|
title: {
|
||||||
"en-US": "Welcome to Node-RED 3.0 Beta 1!",
|
"en-US": "Welcome to Node-RED 3.0 Beta 3!",
|
||||||
"ja": "Node-RED 3.0 ベータ1へようこそ!"
|
"ja": "Node-RED 3.0 ベータ3へようこそ!"
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
"en-US": "<p>This is the first Beta release of Node-RED 3.0. It contains just about everything we have planned for the final release.</p><p>Let's take a moment to discover the new features in this release.</p>",
|
"en-US": "<p>This is the final beta release of Node-RED 3.0.</p><p>Let's take a moment to discover the new features in this release.</p>",
|
||||||
"ja": "<p>これはNode-RED 3.0の最初のベータリリースです。これには、最終リリースで計画しているほぼ全ての機能が含まれています。</p><p>本リリースの新機能を見つけてみましょう。</p>"
|
"ja": "<p>これはNode-RED 3.0の最後のベータリリースです。</p><p>本リリースの新機能を見つけてみましょう。</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Context Menu",
|
||||||
|
"ja": "コンテキストメニュー"
|
||||||
|
},
|
||||||
|
image: 'images/context-menu.png',
|
||||||
|
description: {
|
||||||
|
"en-US": `<p>The editor now has its own context menu when you
|
||||||
|
right-click in the workspace.</p>
|
||||||
|
<p>This makes many of the built-in actions much easier
|
||||||
|
to access.</p>`,
|
||||||
|
"ja": `<p>ワークスペースで右クリックすると、エディタに独自のコンテキストメニューが表示されるようになりました。</p>
|
||||||
|
<p>これによって多くの組み込み動作を、より簡単に利用できます。</p>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -19,12 +34,13 @@ export default {
|
|||||||
},
|
},
|
||||||
image: 'images/junction-slice.gif',
|
image: 'images/junction-slice.gif',
|
||||||
description: {
|
description: {
|
||||||
"en-US": `<p>To make it easier to route wires around your flows, it is now possible to
|
"en-US": `<p>To make it easier to route wires around your flows,
|
||||||
add junction nodes that give you more control.</p>
|
it is now possible to add junction nodes that give
|
||||||
<p>Junctions can be added to wires by holding the Shift key, then click and drag with
|
you more control.</p>
|
||||||
the right-hand mouse button across the wires.</p>`,
|
<p>Junctions can be added to wires by holding both the Alt key and the Shift key
|
||||||
|
then click and drag the mouse across the wires.</p>`,
|
||||||
"ja": `<p>フローのワイヤーの経路をより制御しやすくするために、分岐点ノードを追加できるようになりました。</p>
|
"ja": `<p>フローのワイヤーの経路をより制御しやすくするために、分岐点ノードを追加できるようになりました。</p>
|
||||||
<p>シフトキーを押しながら、マウスの右ボタンをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。</p>`
|
<p>Altキーとシフトキーを押しながらマウスをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。</p>`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -109,9 +109,10 @@ module.exports = function(RED) {
|
|||||||
if (!property) return;
|
if (!property) return;
|
||||||
|
|
||||||
if (valueType === "jsonata") {
|
if (valueType === "jsonata") {
|
||||||
if (p.exp) {
|
if (p.v) {
|
||||||
try {
|
try {
|
||||||
var val = RED.util.evaluateJSONataExpression(p.exp, msg);
|
var exp = RED.util.prepareJSONataExpression(p.v, node);
|
||||||
|
var val = RED.util.evaluateJSONataExpression(exp, msg);
|
||||||
RED.util.setMessageProperty(msg, property, val, true);
|
RED.util.setMessageProperty(msg, property, val, true);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
|
@ -460,7 +460,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs) {
|
var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs, offset) {
|
||||||
var editor = RED.editor.createEditor({
|
var editor = RED.editor.createEditor({
|
||||||
id: id,
|
id: id,
|
||||||
mode: 'ace/mode/nrjavascript',
|
mode: 'ace/mode/nrjavascript',
|
||||||
@ -484,14 +484,14 @@
|
|||||||
extraLibs: extraLibs
|
extraLibs: extraLibs
|
||||||
});
|
});
|
||||||
if (defaultValue && value === "") {
|
if (defaultValue && value === "") {
|
||||||
editor.moveCursorTo(defaultValue.split("\n").length - 1, 0);
|
editor.moveCursorTo(defaultValue.split("\n").length +offset, 0);
|
||||||
}
|
}
|
||||||
editor.__stateId = stateId;
|
editor.__stateId = stateId;
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
this.initEditor = buildEditor('node-input-init-editor', this.id + "/" + "initEditor", false, $("#node-input-initialize").val(), RED._("node-red:function.text.initialize"))
|
this.initEditor = buildEditor('node-input-init-editor', this.id + "/" + "initEditor", false, $("#node-input-initialize").val(), RED._("node-red:function.text.initialize"), undefined, 0);
|
||||||
this.editor = buildEditor('node-input-func-editor', this.id + "/" + "editor", true, $("#node-input-func").val(), undefined, that.libs || [])
|
this.editor = buildEditor('node-input-func-editor', this.id + "/" + "editor", true, $("#node-input-func").val(), undefined, that.libs || [], undefined, -1);
|
||||||
this.finalizeEditor = buildEditor('node-input-finalize-editor', this.id + "/" + "finalizeEditor", false, $("#node-input-finalize").val(), RED._("node-red:function.text.finalize"))
|
this.finalizeEditor = buildEditor('node-input-finalize-editor', this.id + "/" + "finalizeEditor", false, $("#node-input-finalize").val(), RED._("node-red:function.text.finalize"), undefined, 0);
|
||||||
|
|
||||||
RED.library.create({
|
RED.library.create({
|
||||||
url:"functions", // where to get the data from
|
url:"functions", // where to get the data from
|
||||||
|
@ -198,8 +198,8 @@
|
|||||||
category: 'storage',
|
category: 'storage',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
filename: {value:"filename"},
|
filename: {value:""},
|
||||||
filenameType: {value:"msg"},
|
filenameType: {value:"str"},
|
||||||
appendNewline: {value:true},
|
appendNewline: {value:true},
|
||||||
createDir: {value:false},
|
createDir: {value:false},
|
||||||
overwriteFile: {value:"false"},
|
overwriteFile: {value:"false"},
|
||||||
@ -236,8 +236,8 @@
|
|||||||
label: node._("file.encoding.setbymsg")
|
label: node._("file.encoding.setbymsg")
|
||||||
}).text(label).appendTo(encSel);
|
}).text(label).appendTo(encSel);
|
||||||
$("#node-input-filename").typedInput({
|
$("#node-input-filename").typedInput({
|
||||||
default: "msg",
|
default: "str",
|
||||||
types:[{ value: "str", label:"", icon:"red/images/typedInput/az.svg"}, "msg", "jsonata", "env"],
|
types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
|
||||||
typeField: $("#node-input-filenameType")
|
typeField: $("#node-input-filenameType")
|
||||||
});
|
});
|
||||||
if(typeof node.filenameType == 'undefined') {
|
if(typeof node.filenameType == 'undefined') {
|
||||||
@ -297,8 +297,8 @@
|
|||||||
category: 'storage',
|
category: 'storage',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
filename: {value:"filename"},
|
filename: {value:""},
|
||||||
filenameType: {value:"msg"},
|
filenameType: {value:"str"},
|
||||||
format: {value:"utf8"},
|
format: {value:"utf8"},
|
||||||
chunk: {value:false},
|
chunk: {value:false},
|
||||||
sendError: {value: false},
|
sendError: {value: false},
|
||||||
@ -341,8 +341,8 @@
|
|||||||
label: label
|
label: label
|
||||||
}).text(label).appendTo(encSel);
|
}).text(label).appendTo(encSel);
|
||||||
$("#node-input-filename").typedInput({
|
$("#node-input-filename").typedInput({
|
||||||
default: "msg",
|
default: "str",
|
||||||
types:[{ value: "str", label:"", icon:"red/images/typedInput/az.svg"}, "msg", "jsonata", "env"],
|
types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
|
||||||
typeField: $("#node-input-filenameType")
|
typeField: $("#node-input-filenameType")
|
||||||
});
|
});
|
||||||
if(typeof node.filenameType == 'undefined') {
|
if(typeof node.filenameType == 'undefined') {
|
||||||
|
137
packages/node_modules/@node-red/nodes/locales/en-US/messages.json
vendored
Executable file → Normal file
137
packages/node_modules/@node-red/nodes/locales/en-US/messages.json
vendored
Executable file → Normal file
@ -194,17 +194,17 @@
|
|||||||
"key": "Private Key",
|
"key": "Private Key",
|
||||||
"passphrase": "Passphrase",
|
"passphrase": "Passphrase",
|
||||||
"ca": "CA Certificate",
|
"ca": "CA Certificate",
|
||||||
"verify-server-cert":"Verify server certificate",
|
"verify-server-cert": "Verify server certificate",
|
||||||
"servername": "Server Name",
|
"servername": "Server Name",
|
||||||
"alpnprotocol": "ALPN Protocol"
|
"alpnprotocol": "ALPN Protocol"
|
||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"cert":"path to certificate (PEM format)",
|
"cert": "path to certificate (PEM format)",
|
||||||
"key":"path to private key (PEM format)",
|
"key": "path to private key (PEM format)",
|
||||||
"ca":"path to CA certificate (PEM format)",
|
"ca": "path to CA certificate (PEM format)",
|
||||||
"passphrase":"private key passphrase (optional)",
|
"passphrase": "private key passphrase (optional)",
|
||||||
"servername":"for use with SNI",
|
"servername": "for use with SNI",
|
||||||
"alpnprotocol":"for use with ALPN"
|
"alpnprotocol": "for use with ALPN"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"missing-file": "No certificate/key file provided",
|
"missing-file": "No certificate/key file provided",
|
||||||
@ -263,8 +263,8 @@
|
|||||||
"moduleLoadError": "Failed to load module __module__: __error__",
|
"moduleLoadError": "Failed to load module __module__: __error__",
|
||||||
"moduleNameError": "Invalid module variable name: __name__",
|
"moduleNameError": "Invalid module variable name: __name__",
|
||||||
"moduleNameReserved": "Reserved variable name: __name__",
|
"moduleNameReserved": "Reserved variable name: __name__",
|
||||||
"inputListener":"Cannot add listener to 'input' event within Function",
|
"inputListener": "Cannot add listener to 'input' event within Function",
|
||||||
"non-message-returned":"Function tried to send a message of type __type__",
|
"non-message-returned": "Function tried to send a message of type __type__",
|
||||||
"invalid-js": "Error in JavaScript code",
|
"invalid-js": "Error in JavaScript code",
|
||||||
"missing-module": "Module __module__ missing"
|
"missing-module": "Module __module__ missing"
|
||||||
}
|
}
|
||||||
@ -323,27 +323,27 @@
|
|||||||
"rate": "rate",
|
"rate": "rate",
|
||||||
"random-first": "first random value",
|
"random-first": "first random value",
|
||||||
"random-last": "last random value",
|
"random-last": "last random value",
|
||||||
"units" : {
|
"units": {
|
||||||
"second": {
|
"second": {
|
||||||
"plural" : "Seconds",
|
"plural": "Seconds",
|
||||||
"singular": "Second"
|
"singular": "Second"
|
||||||
},
|
},
|
||||||
"minute": {
|
"minute": {
|
||||||
"plural" : "Minutes",
|
"plural": "Minutes",
|
||||||
"singular": "Minute"
|
"singular": "Minute"
|
||||||
},
|
},
|
||||||
"hour": {
|
"hour": {
|
||||||
"plural" : "Hours",
|
"plural": "Hours",
|
||||||
"singular": "Hour"
|
"singular": "Hour"
|
||||||
},
|
},
|
||||||
"day": {
|
"day": {
|
||||||
"plural" : "Days",
|
"plural": "Days",
|
||||||
"singular": "Day"
|
"singular": "Day"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"too-many" : "too many pending messages in delay node",
|
"too-many": "too many pending messages in delay node",
|
||||||
"invalid-timeout": "Invalid delay value",
|
"invalid-timeout": "Invalid delay value",
|
||||||
"invalid-rate": "Invalid rate value",
|
"invalid-rate": "Invalid rate value",
|
||||||
"invalid-rate-unit": "Invalid rate unit value",
|
"invalid-rate-unit": "Invalid rate unit value",
|
||||||
@ -383,8 +383,8 @@
|
|||||||
"trigger-block": "trigger & block",
|
"trigger-block": "trigger & block",
|
||||||
"trigger-loop": "resend every",
|
"trigger-loop": "resend every",
|
||||||
"reset": "Reset the trigger if:",
|
"reset": "Reset the trigger if:",
|
||||||
"resetMessage":"msg.reset is set",
|
"resetMessage": "msg.reset is set",
|
||||||
"resetPayload":"msg.payload equals",
|
"resetPayload": "msg.payload equals",
|
||||||
"resetprompt": "optional",
|
"resetprompt": "optional",
|
||||||
"duration": "duration",
|
"duration": "duration",
|
||||||
"topic": "topic"
|
"topic": "topic"
|
||||||
@ -412,8 +412,8 @@
|
|||||||
"cleansession": "Use clean session",
|
"cleansession": "Use clean session",
|
||||||
"cleanstart": "Use clean start",
|
"cleanstart": "Use clean start",
|
||||||
"use-tls": "Use TLS",
|
"use-tls": "Use TLS",
|
||||||
"tls-config":"TLS Configuration",
|
"tls-config": "TLS Configuration",
|
||||||
"verify-server-cert":"Verify server certificate",
|
"verify-server-cert": "Verify server certificate",
|
||||||
"compatmode": "Use legacy MQTT 3.1 support",
|
"compatmode": "Use legacy MQTT 3.1 support",
|
||||||
"userProperties": "User Properties",
|
"userProperties": "User Properties",
|
||||||
"subscriptionIdentifier": "Subscription ID",
|
"subscriptionIdentifier": "Subscription ID",
|
||||||
@ -448,10 +448,10 @@
|
|||||||
"auto-connect": "Connect automatically",
|
"auto-connect": "Connect automatically",
|
||||||
"auto-mode-depreciated": "This option is depreciated. Please use the new auto-detect mode."
|
"auto-mode-depreciated": "This option is depreciated. Please use the new auto-detect mode."
|
||||||
},
|
},
|
||||||
"sections-label":{
|
"sections-label": {
|
||||||
"birth-message": "Message sent on connection (birth message)",
|
"birth-message": "Message sent on connection (birth message)",
|
||||||
"will-message":"Message sent on an unexpected disconnection (will message)",
|
"will-message": "Message sent on an unexpected disconnection (will message)",
|
||||||
"close-message":"Message sent before disconnecting (close message)"
|
"close-message": "Message sent before disconnecting (close message)"
|
||||||
},
|
},
|
||||||
"tabs-label": {
|
"tabs-label": {
|
||||||
"connection": "Connection",
|
"connection": "Connection",
|
||||||
@ -460,7 +460,7 @@
|
|||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"clientid": "Leave blank for auto generated",
|
"clientid": "Leave blank for auto generated",
|
||||||
"clientid-nonclean":"Must be set for non-clean sessions",
|
"clientid-nonclean": "Must be set for non-clean sessions",
|
||||||
"will-topic": "Leave blank to disable will message",
|
"will-topic": "Leave blank to disable will message",
|
||||||
"birth-topic": "Leave blank to disable birth message",
|
"birth-topic": "Leave blank to disable birth message",
|
||||||
"close-topic": "Leave blank to disable close message"
|
"close-topic": "Leave blank to disable close message"
|
||||||
@ -494,7 +494,6 @@
|
|||||||
"invalid-action-alreadyconnected": "Disconnect from broker before connecting",
|
"invalid-action-alreadyconnected": "Disconnect from broker before connecting",
|
||||||
"invalid-action-badsubscription": "msg.topic is missing or invalid",
|
"invalid-action-badsubscription": "msg.topic is missing or invalid",
|
||||||
"invalid-client-id": "Missing Client ID"
|
"invalid-client-id": "Missing Client ID"
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"httpin": {
|
"httpin": {
|
||||||
@ -507,7 +506,7 @@
|
|||||||
"status": "Status code",
|
"status": "Status code",
|
||||||
"headers": "Headers",
|
"headers": "Headers",
|
||||||
"other": "other",
|
"other": "other",
|
||||||
"paytoqs" : {
|
"paytoqs": {
|
||||||
"ignore": "Ignore",
|
"ignore": "Ignore",
|
||||||
"query": "Append to query-string parameters",
|
"query": "Append to query-string parameters",
|
||||||
"body": "Send as request body"
|
"body": "Send as request body"
|
||||||
@ -521,7 +520,7 @@
|
|||||||
"setby": "- set by msg.method -",
|
"setby": "- set by msg.method -",
|
||||||
"basicauth": "Use authentication",
|
"basicauth": "Use authentication",
|
||||||
"use-tls": "Enable secure (SSL/TLS) connection",
|
"use-tls": "Enable secure (SSL/TLS) connection",
|
||||||
"tls-config":"TLS Configuration",
|
"tls-config": "TLS Configuration",
|
||||||
"basic": "basic authentication",
|
"basic": "basic authentication",
|
||||||
"digest": "digest authentication",
|
"digest": "digest authentication",
|
||||||
"bearer": "bearer authentication",
|
"bearer": "bearer authentication",
|
||||||
@ -546,8 +545,8 @@
|
|||||||
"no-response": "No response object",
|
"no-response": "No response object",
|
||||||
"json-error": "JSON parse error",
|
"json-error": "JSON parse error",
|
||||||
"no-url": "No url specified",
|
"no-url": "No url specified",
|
||||||
"deprecated-call":"Deprecated call to __method__",
|
"deprecated-call": "Deprecated call to __method__",
|
||||||
"invalid-transport":"non-http transport requested",
|
"invalid-transport": "non-http transport requested",
|
||||||
"timeout-isnan": "Timeout value is not a valid number, ignoring",
|
"timeout-isnan": "Timeout value is not a valid number, ignoring",
|
||||||
"timeout-isnegative": "Timeout value is negative, ignoring",
|
"timeout-isnegative": "Timeout value is negative, ignoring",
|
||||||
"invalid-payload": "Invalid payload",
|
"invalid-payload": "Invalid payload",
|
||||||
@ -646,7 +645,6 @@
|
|||||||
"connection-closed": "connection closed from __host__:__port__",
|
"connection-closed": "connection closed from __host__:__port__",
|
||||||
"connections": "__count__ connection",
|
"connections": "__count__ connection",
|
||||||
"connections_plural": "__count__ connections"
|
"connections_plural": "__count__ connections"
|
||||||
|
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"connection-lost": "connection lost to __host__:__port__",
|
"connection-lost": "connection lost to __host__:__port__",
|
||||||
@ -902,8 +900,8 @@
|
|||||||
"property": "Property",
|
"property": "Property",
|
||||||
"actions": {
|
"actions": {
|
||||||
"toggle": "Convert between JSON String & Object",
|
"toggle": "Convert between JSON String & Object",
|
||||||
"str":"Always convert to JSON String",
|
"str": "Always convert to JSON String",
|
||||||
"obj":"Always convert to JavaScript Object"
|
"obj": "Always convert to JavaScript Object"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -930,6 +928,7 @@
|
|||||||
"write": "write file",
|
"write": "write file",
|
||||||
"read": "read file",
|
"read": "read file",
|
||||||
"filename": "Filename",
|
"filename": "Filename",
|
||||||
|
"path": "path",
|
||||||
"action": "Action",
|
"action": "Action",
|
||||||
"addnewline": "Add newline (\\n) to each payload?",
|
"addnewline": "Add newline (\\n) to each payload?",
|
||||||
"createdir": "Create directory if it doesn't exist?",
|
"createdir": "Create directory if it doesn't exist?",
|
||||||
@ -989,15 +988,15 @@
|
|||||||
},
|
},
|
||||||
"split": {
|
"split": {
|
||||||
"split": "split",
|
"split": "split",
|
||||||
"intro":"Split <code>msg.payload</code> based on type:",
|
"intro": "Split <code>msg.payload</code> based on type:",
|
||||||
"object":"<b>Object</b>",
|
"object": "<b>Object</b>",
|
||||||
"objectSend":"Send a message for each key/value pair",
|
"objectSend": "Send a message for each key/value pair",
|
||||||
"strBuff":"<b>String</b> / <b>Buffer</b>",
|
"strBuff": "<b>String</b> / <b>Buffer</b>",
|
||||||
"array":"<b>Array</b>",
|
"array": "<b>Array</b>",
|
||||||
"splitUsing":"Split using",
|
"splitUsing": "Split using",
|
||||||
"splitLength":"Fixed length of",
|
"splitLength": "Fixed length of",
|
||||||
"stream":"Handle as a stream of messages",
|
"stream": "Handle as a stream of messages",
|
||||||
"addname":" Copy key to "
|
"addname": " Copy key to "
|
||||||
},
|
},
|
||||||
"join": {
|
"join": {
|
||||||
"join": "join",
|
"join": "join",
|
||||||
@ -1049,46 +1048,46 @@
|
|||||||
"invalid-type": "Cannot join __error__ to buffer"
|
"invalid-type": "Cannot join __error__ to buffer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sort" : {
|
"sort": {
|
||||||
"sort": "sort",
|
"sort": "sort",
|
||||||
"target" : "Sort",
|
"target": "Sort",
|
||||||
"seq" : "message sequence",
|
"seq": "message sequence",
|
||||||
"key" : "Key",
|
"key": "Key",
|
||||||
"elem" : "element value",
|
"elem": "element value",
|
||||||
"order" : "Order",
|
"order": "Order",
|
||||||
"ascending" : "ascending",
|
"ascending": "ascending",
|
||||||
"descending" : "descending",
|
"descending": "descending",
|
||||||
"as-number" : "as number",
|
"as-number": "as number",
|
||||||
"invalid-exp" : "Invalid JSONata expression in sort node: __message__",
|
"invalid-exp": "Invalid JSONata expression in sort node: __message__",
|
||||||
"too-many" : "Too many pending messages in sort node",
|
"too-many": "Too many pending messages in sort node",
|
||||||
"clear" : "clear pending message in sort node"
|
"clear": "clear pending message in sort node"
|
||||||
},
|
},
|
||||||
"batch" : {
|
"batch": {
|
||||||
"batch": "batch",
|
"batch": "batch",
|
||||||
"mode": {
|
"mode": {
|
||||||
"label" : "Mode",
|
"label": "Mode",
|
||||||
"num-msgs" : "Group by number of messages",
|
"num-msgs": "Group by number of messages",
|
||||||
"interval" : "Group by time interval",
|
"interval": "Group by time interval",
|
||||||
"concat" : "Concatenate sequences"
|
"concat": "Concatenate sequences"
|
||||||
},
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"label" : "Number of messages",
|
"label": "Number of messages",
|
||||||
"overlap" : "Overlap",
|
"overlap": "Overlap",
|
||||||
"count" : "count",
|
"count": "count",
|
||||||
"invalid" : "Invalid count and overlap"
|
"invalid": "Invalid count and overlap"
|
||||||
},
|
},
|
||||||
"interval": {
|
"interval": {
|
||||||
"label" : "Interval",
|
"label": "Interval",
|
||||||
"seconds" : "seconds",
|
"seconds": "seconds",
|
||||||
"empty" : "send empty message when no message arrives"
|
"empty": "send empty message when no message arrives"
|
||||||
},
|
},
|
||||||
"concat": {
|
"concat": {
|
||||||
"topics-label": "Topics",
|
"topics-label": "Topics",
|
||||||
"topic" : "topic"
|
"topic": "topic"
|
||||||
},
|
},
|
||||||
"too-many" : "too many pending messages in batch node",
|
"too-many": "too many pending messages in batch node",
|
||||||
"unexpected" : "unexpected mode",
|
"unexpected": "unexpected mode",
|
||||||
"no-parts" : "no parts property in message",
|
"no-parts": "no parts property in message",
|
||||||
"error": {
|
"error": {
|
||||||
"invalid-count": "Invalid count",
|
"invalid-count": "Invalid count",
|
||||||
"invalid-overlap": "Invalid overlap",
|
"invalid-overlap": "Invalid overlap",
|
||||||
@ -1107,7 +1106,7 @@
|
|||||||
"property": "property",
|
"property": "property",
|
||||||
"topic": "topic"
|
"topic": "topic"
|
||||||
},
|
},
|
||||||
"placeholder":{
|
"placeholder": {
|
||||||
"bandgap": "e.g. 10 or 5%",
|
"bandgap": "e.g. 10 or 5%",
|
||||||
"start": "leave blank to use first data received"
|
"start": "leave blank to use first data received"
|
||||||
},
|
},
|
||||||
|
@ -928,6 +928,7 @@
|
|||||||
"write": "write file",
|
"write": "write file",
|
||||||
"read": "read file",
|
"read": "read file",
|
||||||
"filename": "ファイル名",
|
"filename": "ファイル名",
|
||||||
|
"path": "パス",
|
||||||
"action": "動作",
|
"action": "動作",
|
||||||
"addnewline": "メッセージの入力のたびに改行を追加",
|
"addnewline": "メッセージの入力のたびに改行を追加",
|
||||||
"createdir": "ディレクトリが存在しない場合は作成",
|
"createdir": "ディレクトリが存在しない場合は作成",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/nodes",
|
"name": "@node-red/nodes",
|
||||||
"version": "3.0.0-beta.2",
|
"version": "3.0.0-beta.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -36,7 +36,7 @@
|
|||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"media-typer": "1.1.0",
|
"media-typer": "1.1.0",
|
||||||
"mqtt": "4.3.7",
|
"mqtt": "4.3.7",
|
||||||
"multer": "1.4.4",
|
"multer": "1.4.5-lts.1",
|
||||||
"mustache": "4.2.0",
|
"mustache": "4.2.0",
|
||||||
"node-watch": "0.7.3",
|
"node-watch": "0.7.3",
|
||||||
"on-headers": "1.0.2",
|
"on-headers": "1.0.2",
|
||||||
|
@ -11,6 +11,7 @@ const exec = require("@node-red/util").exec;
|
|||||||
const log = require("@node-red/util").log;
|
const log = require("@node-red/util").log;
|
||||||
const hooks = require("@node-red/util").hooks;
|
const hooks = require("@node-red/util").hooks;
|
||||||
const url = require("url");
|
const url = require("url");
|
||||||
|
const { createRequire } = require("module");
|
||||||
|
|
||||||
const BUILTIN_MODULES = require('module').builtinModules;
|
const BUILTIN_MODULES = require('module').builtinModules;
|
||||||
|
|
||||||
@ -139,10 +140,15 @@ function importModule(module) {
|
|||||||
}
|
}
|
||||||
const externalModuleDir = getInstallDir();
|
const externalModuleDir = getInstallDir();
|
||||||
const moduleDir = path.join(externalModuleDir,"node_modules",module);
|
const moduleDir = path.join(externalModuleDir,"node_modules",module);
|
||||||
|
// To handle both CJS and ESM we need to resolve the module to the
|
||||||
|
// specific file that is loaded when the module is required/imported
|
||||||
|
// As this won't be on the natural module search path, we use createRequire
|
||||||
|
// to access the module
|
||||||
|
const modulePath = createRequire(moduleDir).resolve(module)
|
||||||
// Import needs the full path to the module's main .js file
|
// Import needs the full path to the module's main .js file
|
||||||
// It also needs to be a file:// url for Windows
|
// It also needs to be a file:// url for Windows
|
||||||
const moduleFile = url.pathToFileURL(require.resolve(moduleDir));
|
const moduleUrl = url.pathToFileURL(modulePath);
|
||||||
return import(moduleFile);
|
return import(moduleUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseModuleName(module) {
|
function parseModuleName(module) {
|
||||||
|
@ -88,9 +88,10 @@ function getLocalFile(file) {
|
|||||||
/**
|
/**
|
||||||
* Synchronously walks the directory looking for node files.
|
* Synchronously walks the directory looking for node files.
|
||||||
* @param dir the directory to search
|
* @param dir the directory to search
|
||||||
|
* @param skipValidNodeRedModules a flag to skip lading icons & files if the directory a valid node-red module
|
||||||
* @return an array of fully-qualified paths to .js files
|
* @return an array of fully-qualified paths to .js files
|
||||||
*/
|
*/
|
||||||
function getLocalNodeFiles(dir) {
|
function getLocalNodeFiles(dir, skipValidNodeRedModules) {
|
||||||
dir = path.resolve(dir);
|
dir = path.resolve(dir);
|
||||||
|
|
||||||
var result = [];
|
var result = [];
|
||||||
@ -102,6 +103,14 @@ function getLocalNodeFiles(dir) {
|
|||||||
return {files: [], icons: []};
|
return {files: [], icons: []};
|
||||||
}
|
}
|
||||||
files.sort();
|
files.sort();
|
||||||
|
// when loading local files, if the path is a valid node-red module
|
||||||
|
// dont include it (will be picked up in scanTreeForNodesModules)
|
||||||
|
if(skipValidNodeRedModules && files.indexOf("package.json") >= 0) {
|
||||||
|
const package = getPackageDetails(dir)
|
||||||
|
if(package.isNodeRedModule) {
|
||||||
|
return {files: [], icons: []};
|
||||||
|
}
|
||||||
|
}
|
||||||
files.forEach(function(fn) {
|
files.forEach(function(fn) {
|
||||||
var stats = fs.statSync(path.join(dir,fn));
|
var stats = fs.statSync(path.join(dir,fn));
|
||||||
if (stats.isFile()) {
|
if (stats.isFile()) {
|
||||||
@ -114,7 +123,7 @@ function getLocalNodeFiles(dir) {
|
|||||||
} else if (stats.isDirectory()) {
|
} else if (stats.isDirectory()) {
|
||||||
// Ignore /.dirs/, /lib/ /node_modules/
|
// Ignore /.dirs/, /lib/ /node_modules/
|
||||||
if (!/^(\..*|lib|icons|node_modules|test|locales)$/.test(fn)) {
|
if (!/^(\..*|lib|icons|node_modules|test|locales)$/.test(fn)) {
|
||||||
var subDirResults = getLocalNodeFiles(path.join(dir,fn));
|
var subDirResults = getLocalNodeFiles(path.join(dir,fn), skipValidNodeRedModules);
|
||||||
result = result.concat(subDirResults.files);
|
result = result.concat(subDirResults.files);
|
||||||
icons = icons.concat(subDirResults.icons);
|
icons = icons.concat(subDirResults.icons);
|
||||||
} else if (fn === "icons") {
|
} else if (fn === "icons") {
|
||||||
@ -126,11 +135,19 @@ function getLocalNodeFiles(dir) {
|
|||||||
return {files: result, icons: icons}
|
return {files: result, icons: icons}
|
||||||
}
|
}
|
||||||
|
|
||||||
function scanDirForNodesModules(dir,moduleName) {
|
function scanDirForNodesModules(dir,moduleName,package) {
|
||||||
var results = [];
|
let results = [];
|
||||||
var scopeName;
|
let scopeName;
|
||||||
|
let files
|
||||||
try {
|
try {
|
||||||
var files = fs.readdirSync(dir);
|
let isNodeRedModule = false
|
||||||
|
if(package) {
|
||||||
|
dir = path.join(package.moduleDir,'..')
|
||||||
|
files = [path.basename(package.moduleDir)]
|
||||||
|
moduleName = (package.package ? package.package.name : null) || moduleName
|
||||||
|
isNodeRedModule = package.isNodeRedModule
|
||||||
|
} else {
|
||||||
|
files = fs.readdirSync(dir);
|
||||||
if (moduleName) {
|
if (moduleName) {
|
||||||
var m = /^(?:(@[^/]+)[/])?([^@/]+)/.exec(moduleName);
|
var m = /^(?:(@[^/]+)[/])?([^@/]+)/.exec(moduleName);
|
||||||
if (m) {
|
if (m) {
|
||||||
@ -138,9 +155,10 @@ function scanDirForNodesModules(dir,moduleName) {
|
|||||||
moduleName = m[2];
|
moduleName = m[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var i=0;i<files.length;i++) {
|
}
|
||||||
var fn = files[i];
|
for (let i=0;i<files.length;i++) {
|
||||||
if (/^@/.test(fn)) {
|
let fn = files[i];
|
||||||
|
if (!isNodeRedModule && /^@/.test(fn)) {
|
||||||
if (scopeName && scopeName === fn) {
|
if (scopeName && scopeName === fn) {
|
||||||
// Looking for a specific scope/module
|
// Looking for a specific scope/module
|
||||||
results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
|
results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
|
||||||
@ -149,16 +167,18 @@ function scanDirForNodesModules(dir,moduleName) {
|
|||||||
results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
|
results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isIncluded(fn) && !isExcluded(fn) && (!moduleName || fn == moduleName)) {
|
if ((isNodeRedModule || (!moduleName || fn == moduleName)) && (isIncluded(fn) && !isExcluded(fn))) {
|
||||||
var pkgfn = path.join(dir,fn,"package.json");
|
|
||||||
try {
|
try {
|
||||||
var pkg = require(pkgfn);
|
const moduleDir = isNodeRedModule ? package.moduleDir : path.join(dir,fn);
|
||||||
if (pkg['node-red']) {
|
const pkg = package || getPackageDetails(moduleDir)
|
||||||
if (!registryUtil.checkModuleAllowed(pkg.name,pkg.version,loadAllowList,loadDenyList)) {
|
if(pkg.error) {
|
||||||
log.debug("! Module: "+pkg.name+" "+pkg.version+ " *ignored due to denyList*");
|
throw pkg.error
|
||||||
|
}
|
||||||
|
if (pkg.isNodeRedModule) {
|
||||||
|
if (!pkg.allowed) {
|
||||||
|
log.debug("! Module: "+pkg.package.name+" "+pkg.package.version+ " *ignored due to denyList*");
|
||||||
} else {
|
} else {
|
||||||
var moduleDir = path.join(dir,fn);
|
results.push({dir:moduleDir,package:pkg.package});
|
||||||
results.push({dir:moduleDir,package:pkg});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
@ -182,11 +202,14 @@ function scanDirForNodesModules(dir,moduleName) {
|
|||||||
* @param moduleName the name of the module to be found
|
* @param moduleName the name of the module to be found
|
||||||
* @return a list of node modules: {dir,package}
|
* @return a list of node modules: {dir,package}
|
||||||
*/
|
*/
|
||||||
function scanTreeForNodesModules(moduleName) {
|
function scanTreeForNodesModules(moduleName) {
|
||||||
var dir = settings.coreNodesDir;
|
let coreNodesDir = settings.coreNodesDir;
|
||||||
var results = [];
|
let results = [];
|
||||||
var userDir;
|
let userDir;
|
||||||
|
let nodesDir;
|
||||||
|
if(settings.nodesDir) {
|
||||||
|
nodesDir = Array.isArray(settings.nodesDir) ? settings.nodesDir : [settings.nodesDir]
|
||||||
|
}
|
||||||
if (settings.userDir) {
|
if (settings.userDir) {
|
||||||
packageList = getPackageList();
|
packageList = getPackageList();
|
||||||
userDir = path.join(settings.userDir,"node_modules");
|
userDir = path.join(settings.userDir,"node_modules");
|
||||||
@ -201,15 +224,46 @@ function scanTreeForNodesModules(moduleName) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir) {
|
if (coreNodesDir) {
|
||||||
var up = path.resolve(path.join(dir,".."));
|
var up = path.resolve(path.join(coreNodesDir,".."));
|
||||||
while (up !== dir) {
|
while (up !== coreNodesDir) {
|
||||||
var pm = path.join(dir,"node_modules");
|
var pm = path.join(coreNodesDir,"node_modules");
|
||||||
if (pm != userDir) {
|
if (pm != userDir) {
|
||||||
results = results.concat(scanDirForNodesModules(pm,moduleName));
|
results = results.concat(scanDirForNodesModules(pm,moduleName));
|
||||||
}
|
}
|
||||||
dir = up;
|
coreNodesDir = up;
|
||||||
up = path.resolve(path.join(dir,".."));
|
up = path.resolve(path.join(coreNodesDir,".."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan nodesDir for any node-red modules
|
||||||
|
/*
|
||||||
|
1. if !exist(package.json) || !package.json.has(node-red) => look for node_modules
|
||||||
|
2. exist(package.json) && package.json.has(node-red) => load this only
|
||||||
|
3. in original scan of nodesDir, ignore if:(exist(package.json) && package.json.has(node-red))
|
||||||
|
*/
|
||||||
|
if (nodesDir) {
|
||||||
|
for (let dirIndex = 0; dirIndex < nodesDir.length; dirIndex++) {
|
||||||
|
const nodeDir = nodesDir[dirIndex];
|
||||||
|
const packageDetails = getPackageDetails(nodeDir)
|
||||||
|
if(packageDetails.isNodeRedModule) {
|
||||||
|
//we have found a node-red module, scan it
|
||||||
|
const nrModules = scanDirForNodesModules(nodeDir, packageDetails.package.name, packageDetails);
|
||||||
|
results = results.concat(nrModules);
|
||||||
|
|
||||||
|
} else if (packageDetails.has_node_modules) {
|
||||||
|
//If this dir has a `node_modues` dir, scan it
|
||||||
|
const nodeModulesDir = path.join(nodeDir, 'node_modules')
|
||||||
|
const nrModules = scanDirForNodesModules(nodeModulesDir, moduleName );
|
||||||
|
results = results.concat(nrModules);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//If this is not a node-red module AND it does NOT have a node_modules dir,
|
||||||
|
//it may be a directory of project directories or a node_modules dir?
|
||||||
|
//scan this instead
|
||||||
|
const nrModules = scanDirForNodesModules(nodeDir, moduleName);
|
||||||
|
results = results.concat(nrModules);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
@ -274,24 +328,26 @@ function getModuleNodeFiles(module) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getNodeFiles(disableNodePathScan) {
|
function getNodeFiles(disableNodePathScan) {
|
||||||
var dir;
|
|
||||||
// Find all of the nodes to load
|
// Find all of the nodes to load
|
||||||
var nodeFiles = [];
|
let results;
|
||||||
var results;
|
let nodesDir;
|
||||||
|
if(settings.nodesDir) {
|
||||||
var dir;
|
nodesDir = Array.isArray(settings.nodesDir) ? settings.nodesDir : [settings.nodesDir]
|
||||||
var iconList = [];
|
}
|
||||||
|
let dir;
|
||||||
|
let nodeFiles = [];
|
||||||
|
let iconList = [];
|
||||||
if (settings.coreNodesDir) {
|
if (settings.coreNodesDir) {
|
||||||
results = getLocalNodeFiles(path.resolve(settings.coreNodesDir));
|
results = getLocalNodeFiles(path.resolve(settings.coreNodesDir));
|
||||||
nodeFiles = nodeFiles.concat(results.files);
|
nodeFiles = nodeFiles.concat(results.files);
|
||||||
iconList = iconList.concat(results.icons);
|
iconList = iconList.concat(results.icons);
|
||||||
var defaultLocalesPath = path.join(settings.coreNodesDir,"locales");
|
let defaultLocalesPath = path.join(settings.coreNodesDir,"locales");
|
||||||
i18n.registerMessageCatalog("node-red",defaultLocalesPath,"messages.json");
|
i18n.registerMessageCatalog("node-red",defaultLocalesPath,"messages.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.userDir) {
|
if (settings.userDir) {
|
||||||
dir = path.join(settings.userDir,"lib","icons");
|
dir = path.join(settings.userDir,"lib","icons");
|
||||||
var icons = scanIconDir(dir);
|
let icons = scanIconDir(dir);
|
||||||
if (icons.length > 0) {
|
if (icons.length > 0) {
|
||||||
iconList.push({path:dir,icons:icons});
|
iconList.push({path:dir,icons:icons});
|
||||||
}
|
}
|
||||||
@ -301,13 +357,9 @@ function getNodeFiles(disableNodePathScan) {
|
|||||||
nodeFiles = nodeFiles.concat(results.files);
|
nodeFiles = nodeFiles.concat(results.files);
|
||||||
iconList = iconList.concat(results.icons);
|
iconList = iconList.concat(results.icons);
|
||||||
}
|
}
|
||||||
if (settings.nodesDir) {
|
if (nodesDir) {
|
||||||
dir = settings.nodesDir;
|
for (let i = 0; i < nodesDir.length; i++) {
|
||||||
if (typeof settings.nodesDir == "string") {
|
results = getLocalNodeFiles(nodesDir[i], true);
|
||||||
dir = [dir];
|
|
||||||
}
|
|
||||||
for (var i=0;i<dir.length;i++) {
|
|
||||||
results = getLocalNodeFiles(dir[i]);
|
|
||||||
nodeFiles = nodeFiles.concat(results.files);
|
nodeFiles = nodeFiles.concat(results.files);
|
||||||
iconList = iconList.concat(results.icons);
|
iconList = iconList.concat(results.icons);
|
||||||
}
|
}
|
||||||
@ -479,7 +531,52 @@ function getPackageList() {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Gets the package json object for the supplied `dir`.
|
||||||
|
* If there is no package.json or the `node-red` section is missing, `result.isNodeRedModule` will be `false`.
|
||||||
|
* If there is no package.json `isPackage` will be `false`.
|
||||||
|
* If an error occurs, `result.error` will contain the error.
|
||||||
|
* @param {string} dir The directory to inspect
|
||||||
|
*/
|
||||||
|
function getPackageDetails(dir) {
|
||||||
|
const result = {
|
||||||
|
/** @type {string} The package directory */
|
||||||
|
moduleDir: dir,
|
||||||
|
/** @type {string} The full file path of package.json for this package */
|
||||||
|
packageFile: null,
|
||||||
|
/** @type {boolean} True if this is a valid node-red module */
|
||||||
|
isNodeRedModule: false,
|
||||||
|
/** @type {boolean} True if a package.json file is present */
|
||||||
|
isPackage: false,
|
||||||
|
/** @type {boolean} True if this a node-red module and passes the checks */
|
||||||
|
allowed: false,
|
||||||
|
/** @type {object} The contents of package.json */
|
||||||
|
package: null,
|
||||||
|
}
|
||||||
|
if (!dir) { return result }
|
||||||
|
try {
|
||||||
|
const packagefile = path.join(dir,'package.json')
|
||||||
|
result.has_node_modules = fs.existsSync(path.join(dir,'node_modules'))
|
||||||
|
if(!fs.existsSync(packagefile)) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
result.packageFile = packagefile
|
||||||
|
const pkg = require(packagefile)
|
||||||
|
result.package = pkg
|
||||||
|
if(result.package) {
|
||||||
|
result.allowed = true
|
||||||
|
result.isPackage = true
|
||||||
|
result.isNodeRedModule = typeof result.package['node-red'] === 'object'
|
||||||
|
if(result.isNodeRedModule) {
|
||||||
|
result.isNodeRedModule = true;
|
||||||
|
result.allowed = registryUtil.checkModuleAllowed(pkg.name,pkg.version,loadAllowList,loadDenyList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
result.error = err; // this is not a package we are interested in!
|
||||||
|
}
|
||||||
|
return result || result;
|
||||||
|
}
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: init,
|
init: init,
|
||||||
getNodeFiles: getNodeFiles,
|
getNodeFiles: getNodeFiles,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/registry",
|
"name": "@node-red/registry",
|
||||||
"version": "3.0.0-beta.2",
|
"version": "3.0.0-beta.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -16,11 +16,11 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/util": "3.0.0-beta.2",
|
"@node-red/util": "3.0.0-beta.3",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
"fs-extra": "10.1.0",
|
"fs-extra": "10.1.0",
|
||||||
"semver": "7.3.7",
|
"semver": "7.3.7",
|
||||||
"tar": "6.1.11",
|
"tar": "6.1.11",
|
||||||
"uglify-js": "3.15.5"
|
"uglify-js": "3.16.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ var api = module.exports = {
|
|||||||
safeSettings.context = runtime.nodes.listContextStores();
|
safeSettings.context = runtime.nodes.listContextStores();
|
||||||
if (runtime.settings.editorTheme && runtime.settings.editorTheme.codeEditor) {
|
if (runtime.settings.editorTheme && runtime.settings.editorTheme.codeEditor) {
|
||||||
safeSettings.codeEditor = runtime.settings.editorTheme.codeEditor || {};
|
safeSettings.codeEditor = runtime.settings.editorTheme.codeEditor || {};
|
||||||
safeSettings.codeEditor.lib = safeSettings.codeEditor.lib || "ace";
|
safeSettings.codeEditor.lib = safeSettings.codeEditor.lib || "monaco";
|
||||||
safeSettings.codeEditor.options = safeSettings.codeEditor.options || {};
|
safeSettings.codeEditor.options = safeSettings.codeEditor.options || {};
|
||||||
}
|
}
|
||||||
safeSettings.libraries = runtime.library.getLibraries();
|
safeSettings.libraries = runtime.library.getLibraries();
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
"httpStatic": "HTTP Static : __path__"
|
"httpStatic": "HTTP Static : __path__"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"server": {
|
"server": {
|
||||||
"loading": "Loading palette nodes",
|
"loading": "Loading palette nodes",
|
||||||
"palette-editor": {
|
"palette-editor": {
|
||||||
@ -61,7 +60,6 @@
|
|||||||
"function-required": "httpsRefreshInterval requires https property to be a function"
|
"function-required": "httpsRefreshInterval requires https property to be a function"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"api": {
|
"api": {
|
||||||
"flows": {
|
"flows": {
|
||||||
"error-save": "Error saving flows: __message__",
|
"error-save": "Error saving flows: __message__",
|
||||||
@ -79,18 +77,16 @@
|
|||||||
"error-enable": "Failed to enable node:"
|
"error-enable": "Failed to enable node:"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"comms": {
|
"comms": {
|
||||||
"error": "Communication channel error: __message__",
|
"error": "Communication channel error: __message__",
|
||||||
"error-server": "Communication server error: __message__",
|
"error-server": "Communication server error: __message__",
|
||||||
"error-send": "Communication send error: __message__"
|
"error-send": "Communication send error: __message__"
|
||||||
},
|
},
|
||||||
|
|
||||||
"settings": {
|
"settings": {
|
||||||
"user-not-available": "Cannot save user settings: __message__",
|
"user-not-available": "Cannot save user settings: __message__",
|
||||||
"not-available": "Settings not available",
|
"not-available": "Settings not available",
|
||||||
"property-read-only": "Property '__prop__' is read-only",
|
"property-read-only": "Property '__prop__' is read-only",
|
||||||
"readonly-mode" : "Runtime in read-only mode. Changes will not be saved."
|
"readonly-mode": "Runtime in read-only mode. Changes will not be saved."
|
||||||
},
|
},
|
||||||
"library": {
|
"library": {
|
||||||
"unknownLibrary": "Unknown library: __library__",
|
"unknownLibrary": "Unknown library: __library__",
|
||||||
@ -101,12 +97,12 @@
|
|||||||
},
|
},
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"credentials": {
|
"credentials": {
|
||||||
"error":"Error loading credentials: __message__",
|
"error": "Error loading credentials: __message__",
|
||||||
"error-saving":"Error saving credentials: __message__",
|
"error-saving": "Error saving credentials: __message__",
|
||||||
"not-registered": "Credential type '__type__' is not registered",
|
"not-registered": "Credential type '__type__' is not registered",
|
||||||
"system-key-warning": "\n\n---------------------------------------------------------------------\nYour flow credentials file is encrypted using a system-generated key.\n\nIf the system-generated key is lost for any reason, your credentials\nfile will not be recoverable, you will have to delete it and re-enter\nyour credentials.\n\nYou should set your own key using the 'credentialSecret' option in\nyour settings file. Node-RED will then re-encrypt your credentials\nfile using your chosen key the next time you deploy a change.\n---------------------------------------------------------------------\n",
|
"system-key-warning": "\n\n---------------------------------------------------------------------\nYour flow credentials file is encrypted using a system-generated key.\n\nIf the system-generated key is lost for any reason, your credentials\nfile will not be recoverable, you will have to delete it and re-enter\nyour credentials.\n\nYou should set your own key using the 'credentialSecret' option in\nyour settings file. Node-RED will then re-encrypt your credentials\nfile using your chosen key the next time you deploy a change.\n---------------------------------------------------------------------\n",
|
||||||
"unencrypted" : "Using unencrypted credentials",
|
"unencrypted": "Using unencrypted credentials",
|
||||||
"encryptedNotFound" : "Encrypted credentials not found"
|
"encryptedNotFound": "Encrypted credentials not found"
|
||||||
},
|
},
|
||||||
"flows": {
|
"flows": {
|
||||||
"safe-mode": "Flows stopped in safe mode. Deploy to start.",
|
"safe-mode": "Flows stopped in safe mode. Deploy to start.",
|
||||||
@ -150,7 +146,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"storage": {
|
"storage": {
|
||||||
"index": {
|
"index": {
|
||||||
"forbidden-flow-name": "forbidden flow name"
|
"forbidden-flow-name": "forbidden flow name"
|
||||||
@ -180,7 +175,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"context": {
|
"context": {
|
||||||
"log-store-init": "Context store : '__name__' [__info__]",
|
"log-store-init": "Context store : '__name__' [__info__]",
|
||||||
"error-loading-module": "Error loading context store: __message__",
|
"error-loading-module": "Error loading context store: __message__",
|
||||||
@ -195,5 +189,4 @@
|
|||||||
"error-write": "Error writing context: __message__"
|
"error-write": "Error writing context: __message__"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/runtime",
|
"name": "@node-red/runtime",
|
||||||
"version": "3.0.0-beta.2",
|
"version": "3.0.0-beta.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -16,8 +16,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/registry": "3.0.0-beta.2",
|
"@node-red/registry": "3.0.0-beta.3",
|
||||||
"@node-red/util": "3.0.0-beta.2",
|
"@node-red/util": "3.0.0-beta.3",
|
||||||
"async-mutex": "0.3.2",
|
"async-mutex": "0.3.2",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
"express": "4.18.1",
|
"express": "4.18.1",
|
||||||
|
@ -641,7 +641,12 @@ function evaluateNodeProperty(value, type, node, msg, callback) {
|
|||||||
result = Date.now();
|
result = Date.now();
|
||||||
} else if (type === 'bin') {
|
} else if (type === 'bin') {
|
||||||
var data = JSON.parse(value);
|
var data = JSON.parse(value);
|
||||||
|
if (Array.isArray(data) || (typeof(data) === "string")) {
|
||||||
result = Buffer.from(data);
|
result = Buffer.from(data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw createError("INVALID_BUFFER_DATA", "Not string or array");
|
||||||
|
}
|
||||||
} else if (type === 'msg' && msg) {
|
} else if (type === 'msg' && msg) {
|
||||||
try {
|
try {
|
||||||
result = getMessageProperty(msg,value);
|
result = getMessageProperty(msg,value);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/util",
|
"name": "@node-red/util",
|
||||||
"version": "3.0.0-beta.2",
|
"version": "3.0.0-beta.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -16,7 +16,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs-extra": "10.1.0",
|
"fs-extra": "10.1.0",
|
||||||
"i18next": "21.8.2",
|
"i18next": "21.8.10",
|
||||||
"json-stringify-safe": "5.0.1",
|
"json-stringify-safe": "5.0.1",
|
||||||
"jsonata": "1.8.6",
|
"jsonata": "1.8.6",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
10
packages/node_modules/node-red/package.json
vendored
10
packages/node_modules/node-red/package.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red",
|
"name": "node-red",
|
||||||
"version": "3.0.0-beta.2",
|
"version": "3.0.0-beta.3",
|
||||||
"description": "Low-code programming for event-driven applications",
|
"description": "Low-code programming for event-driven applications",
|
||||||
"homepage": "http://nodered.org",
|
"homepage": "http://nodered.org",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@ -31,10 +31,10 @@
|
|||||||
"flow"
|
"flow"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/editor-api": "3.0.0-beta.2",
|
"@node-red/editor-api": "3.0.0-beta.3",
|
||||||
"@node-red/runtime": "3.0.0-beta.2",
|
"@node-red/runtime": "3.0.0-beta.3",
|
||||||
"@node-red/util": "3.0.0-beta.2",
|
"@node-red/util": "3.0.0-beta.3",
|
||||||
"@node-red/nodes": "3.0.0-beta.2",
|
"@node-red/nodes": "3.0.0-beta.3",
|
||||||
"basic-auth": "2.0.1",
|
"basic-auth": "2.0.1",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"express": "4.18.1",
|
"express": "4.18.1",
|
||||||
|
21
packages/node_modules/node-red/settings.js
vendored
21
packages/node_modules/node-red/settings.js
vendored
@ -302,6 +302,27 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** Configure the logging output */
|
||||||
|
logging: {
|
||||||
|
/** Only console logging is currently supported */
|
||||||
|
console: {
|
||||||
|
/** Level of logging to be recorded. Options are:
|
||||||
|
* fatal - only those errors which make the application unusable should be recorded
|
||||||
|
* error - record errors which are deemed fatal for a particular request + fatal errors
|
||||||
|
* warn - record problems which are non fatal + errors + fatal errors
|
||||||
|
* info - record information about the general running of the application + warn + error + fatal errors
|
||||||
|
* debug - record information which is more verbose than info + info + warn + error + fatal errors
|
||||||
|
* trace - record very detailed logging + debug + info + warn + error + fatal errors
|
||||||
|
* off - turn off all logging (doesn't affect metrics or audit)
|
||||||
|
*/
|
||||||
|
level: "info",
|
||||||
|
/** Whether or not to include metric events in the log output */
|
||||||
|
metrics: false,
|
||||||
|
/** Whether or not to include audit events in the log output */
|
||||||
|
audit: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/** Context Storage
|
/** Context Storage
|
||||||
* The following property can be used to enable context storage. The configuration
|
* The following property can be used to enable context storage. The configuration
|
||||||
* provided here will enable file-based context that flushes to disk every 30 seconds.
|
* provided here will enable file-based context that flushes to disk every 30 seconds.
|
||||||
|
@ -906,6 +906,7 @@ describe('inject node', function() {
|
|||||||
msg.should.have.property("str1", "1"); //injected prop
|
msg.should.have.property("str1", "1"); //injected prop
|
||||||
msg.should.have.property("num1", 1); //injected prop
|
msg.should.have.property("num1", 1); //injected prop
|
||||||
msg.should.have.property("bool1", true); //injected prop
|
msg.should.have.property("bool1", true); //injected prop
|
||||||
|
msg.should.have.property("jsonata1", "AB"); //injected prop
|
||||||
|
|
||||||
helper.clearFlows().then(function() {
|
helper.clearFlows().then(function() {
|
||||||
done();
|
done();
|
||||||
@ -919,6 +920,7 @@ describe('inject node', function() {
|
|||||||
{p:"str1", v:"1", vt:"str"}, //new prop
|
{p:"str1", v:"1", vt:"str"}, //new prop
|
||||||
{p:"num1", v:"1", vt:"num"}, //new prop
|
{p:"num1", v:"1", vt:"num"}, //new prop
|
||||||
{p:"bool1", v:"true", vt:"bool"}, //new prop
|
{p:"bool1", v:"true", vt:"bool"}, //new prop
|
||||||
|
{p:"jsonata1", v:'"A" & "B"', vt:"jsonata"}, //new prop
|
||||||
]})
|
]})
|
||||||
.expect(200).end(function(err) {
|
.expect(200).end(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -14,26 +14,41 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
var should = require("should");
|
const should = require("should");
|
||||||
var sinon = require("sinon");
|
const sinon = require("sinon");
|
||||||
var path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
var NR_TEST_UTILS = require("nr-test-utils");
|
const NR_TEST_UTILS = require("nr-test-utils");
|
||||||
|
|
||||||
var localfilesystem = NR_TEST_UTILS.require("@node-red/registry/lib/localfilesystem");
|
const localfilesystem = NR_TEST_UTILS.require("@node-red/registry/lib/localfilesystem");
|
||||||
|
|
||||||
var resourcesDir = path.resolve(path.join(__dirname,"resources","local"));
|
const resourcesDir = path.resolve(path.join(__dirname,"resources","local"));
|
||||||
var userDir = path.resolve(path.join(__dirname,"resources","userDir"));
|
const userDir = path.resolve(path.join(__dirname,"resources","userDir"));
|
||||||
var moduleDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule"));
|
|
||||||
|
|
||||||
var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
|
const nodesDir1 = path.resolve(path.join(__dirname,"resources","nodesDir1"))
|
||||||
|
const nodesDir2 = path.resolve(path.join(__dirname,"resources","nodesDir2"))
|
||||||
|
const nodesDir3 =path.resolve(path.join(__dirname,"resources","nodesDir3"))
|
||||||
|
|
||||||
|
const moduleDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule"));
|
||||||
|
|
||||||
|
const i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
|
||||||
|
|
||||||
describe("red/nodes/registry/localfilesystem",function() {
|
describe("red/nodes/registry/localfilesystem",function() {
|
||||||
|
var stubs = [];
|
||||||
|
function stubPathJoin() {
|
||||||
|
var _join = path.join;
|
||||||
|
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
||||||
|
if (arguments[0] == resourcesDir) {
|
||||||
|
// This stops the module tree scan from going any higher
|
||||||
|
// up the tree than resourcesDir.
|
||||||
|
return arguments[0];
|
||||||
|
}
|
||||||
|
return _join.apply(null,arguments);
|
||||||
|
}));
|
||||||
|
}
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
stubs.push(sinon.stub(i18n,"registerMessageCatalog").callsFake(function() { return Promise.resolve(); }));
|
stubs.push(sinon.stub(i18n,"registerMessageCatalog").callsFake(function() { return Promise.resolve(); }));
|
||||||
})
|
})
|
||||||
|
|
||||||
var stubs = [];
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
while(stubs.length) {
|
while(stubs.length) {
|
||||||
stubs.pop().restore();
|
stubs.pop().restore();
|
||||||
@ -129,16 +144,76 @@ describe("red/nodes/registry/localfilesystem",function() {
|
|||||||
checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
|
checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
it("Finds nodes module path",function(done) {
|
it("Finds nodes and icons only in nodesDir with files, icons and valid node-red packages",function(done) {
|
||||||
var _join = path.join;
|
localfilesystem.init({nodesDir:nodesDir1});
|
||||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
const nodeList = localfilesystem.getNodeFiles(true);
|
||||||
if (arguments[0] == resourcesDir) {
|
nodeList.should.have.a.property("node-red");
|
||||||
// This stops the module tree scan from going any higher
|
const nm = nodeList['node-red'];
|
||||||
// up the tree than resourcesDir.
|
nm.should.have.a.property('name','node-red');
|
||||||
return arguments[0];
|
nm.should.have.a.property("nodes");
|
||||||
|
nm.should.have.a.property("icons");
|
||||||
|
checkNodes(nm.nodes,['loose1', 'loose2'], []);
|
||||||
|
//1 icon in nodesDir1/icons/ - should be found
|
||||||
|
//2 icons in nodesDir1/loose2/icons/ - should be found
|
||||||
|
//1 icons in nodesDir1/node-red-node-testnode/icons/ - should be found
|
||||||
|
//1 icons in nodesDir1/regular_module/icons/ - should NOT be found
|
||||||
|
//total icon sets 3, total icons 4
|
||||||
|
nm.icons.should.have.a.property("length", 3);
|
||||||
|
nm.icons[0].should.have.a.property("path")
|
||||||
|
nm.icons[0].should.have.a.property("icons", ['loose1.svg'])
|
||||||
|
nm.icons[1].should.have.a.property("path")
|
||||||
|
nm.icons[1].should.have.a.property("icons", ['loose2.svg', 'loose2b.svg'])
|
||||||
|
nm.icons[2].should.have.a.property("path")
|
||||||
|
nm.icons[2].should.have.a.property("icons", ['test.svg'])
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
it("Should not find node-red node in nodesDir with files, icons and valid node-red packages",function(done) {
|
||||||
|
// path contains a regular node module and a node-red node module
|
||||||
|
localfilesystem.init({nodesDir:path.join(nodesDir1)});
|
||||||
|
const nodeList = localfilesystem.getNodeFiles(true);
|
||||||
|
nodeList.should.have.a.property("node-red");
|
||||||
|
const nm = nodeList['node-red'];
|
||||||
|
nm.should.have.a.property('name','node-red');
|
||||||
|
nm.should.have.a.property("nodes");
|
||||||
|
nm.nodes.should.have.a.property("loose1");
|
||||||
|
nm.nodes.should.have.a.property("loose2");
|
||||||
|
nm.nodes.should.not.have.a.property("regular_module");
|
||||||
|
nm.nodes.should.not.have.a.property("node-red-node-testnode");
|
||||||
|
for (let key of Object.keys(nm.nodes)) {
|
||||||
|
const n = nm.nodes[key];
|
||||||
|
n.file.indexOf("regular_module").should.eql(-1, `found icons in a node-red module`)
|
||||||
|
n.file.indexOf("node-red-node-testnode").should.eql(-1, `found icons in a node-red module`)
|
||||||
}
|
}
|
||||||
return _join.apply(null,arguments);
|
//1 icon in nodesDir1/icons/ - should be found
|
||||||
}));
|
//2 icons in nodesDir1/loose2/icons/ - should be found
|
||||||
|
//1 icons in nodesDir1/node-red-node-testnode/icons/ - should be found
|
||||||
|
//1 icons in nodesDir1/regular_module/icons/ - should NOT be found
|
||||||
|
//total icon sets 3, total icons 4
|
||||||
|
nm.should.have.a.property("icons");
|
||||||
|
nm.icons.should.have.a.property("length", 3);
|
||||||
|
let iconCount = 0;
|
||||||
|
for (let index = 0; index < nm.icons.length; index++) {
|
||||||
|
const iconDir = nm.icons[index];
|
||||||
|
iconCount += iconDir.icons.length
|
||||||
|
iconDir.path.indexOf("node-red-node-testnode").should.eql(-1, `should not find icons in a node-red module`)
|
||||||
|
}
|
||||||
|
should(iconCount).eql(4, "Should find only 4 icons")
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
it("Should not find node-red node in nodesDir when regular package and valid node-red packages",function(done) {
|
||||||
|
localfilesystem.init({nodesDir:path.join(nodesDir1,"regular_module")});
|
||||||
|
const nodeList = localfilesystem.getNodeFiles(true);
|
||||||
|
nodeList.should.have.a.property("node-red");
|
||||||
|
const nm = nodeList['node-red'];
|
||||||
|
nm.should.have.a.property('name','node-red');
|
||||||
|
nm.should.have.a.property("nodes", {});
|
||||||
|
nm.should.have.a.property("icons");
|
||||||
|
nm.icons.should.have.a.property("length", 1); //should find 1 icons folder
|
||||||
|
nm.icons[0].should.have.a.property("icons", [ 'test.svg' ]); //should find 1 icon in regular package
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
it("Finds nodes module path",function(done) {
|
||||||
|
stubPathJoin()
|
||||||
localfilesystem.init({coreNodesDir:moduleDir});
|
localfilesystem.init({coreNodesDir:moduleDir});
|
||||||
var nodeList = localfilesystem.getNodeFiles();
|
var nodeList = localfilesystem.getNodeFiles();
|
||||||
nodeList.should.have.a.property("node-red");
|
nodeList.should.have.a.property("node-red");
|
||||||
@ -166,8 +241,6 @@ describe("red/nodes/registry/localfilesystem",function() {
|
|||||||
i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(moduleDir,"locales")));
|
i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(moduleDir,"locales")));
|
||||||
i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');
|
i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
it.skip("finds locales directory");
|
it.skip("finds locales directory");
|
||||||
@ -205,15 +278,7 @@ describe("red/nodes/registry/localfilesystem",function() {
|
|||||||
});
|
});
|
||||||
describe("#getModuleFiles",function() {
|
describe("#getModuleFiles",function() {
|
||||||
it("gets a nodes module files",function(done) {
|
it("gets a nodes module files",function(done) {
|
||||||
var _join = path.join;
|
stubPathJoin()
|
||||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
|
||||||
if (arguments[0] == resourcesDir) {
|
|
||||||
// This stops the module tree scan from going any higher
|
|
||||||
// up the tree than resourcesDir.
|
|
||||||
return arguments[0];
|
|
||||||
}
|
|
||||||
return _join.apply(null,arguments);
|
|
||||||
}));
|
|
||||||
localfilesystem.init({coreNodesDir:moduleDir});
|
localfilesystem.init({coreNodesDir:moduleDir});
|
||||||
var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
|
var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
|
||||||
nodeModule.should.have.a.property('TestNodeModule');
|
nodeModule.should.have.a.property('TestNodeModule');
|
||||||
@ -230,16 +295,87 @@ describe("red/nodes/registry/localfilesystem",function() {
|
|||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
it("Finds only 1 node-red node in nodesDir amongst legacy nodes and regular nodes",function(done) {
|
||||||
|
stubPathJoin()
|
||||||
|
localfilesystem.init({nodesDir:[path.join(nodesDir1,"node-red-node-testnode")]});
|
||||||
|
const nodeModule = localfilesystem.getModuleFiles();
|
||||||
|
const loaded = Object.keys(nodeModule)
|
||||||
|
loaded.should.have.a.property("length", 1)
|
||||||
|
loaded.indexOf('node-red-node-testnode').should.greaterThan(-1, "Should load node-red-node-testnode")
|
||||||
|
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('name','node-red-node-testnode');
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('version','1.0.0');
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('nodes');
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('path');
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('user', false);
|
||||||
|
checkNodes(nodeModule['node-red-node-testnode'].nodes,['testnode'],[],'node-red-node-testnode');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
it("Finds a node-red node in nodesDir with a sub dir containing valid node-red package",function(done) {
|
||||||
|
stubPathJoin()
|
||||||
|
localfilesystem.init({nodesDir:[path.join(nodesDir1,"node-red-node-testnode")]});
|
||||||
|
const nodeModule = localfilesystem.getModuleFiles();
|
||||||
|
const loaded = Object.keys(nodeModule)
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('name','node-red-node-testnode');
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('version','1.0.0');
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('nodes');
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('path');
|
||||||
|
nodeModule['node-red-node-testnode'].should.have.a.property('user', false);
|
||||||
|
checkNodes(nodeModule['node-red-node-testnode'].nodes,['testnode'],[],'node-red-node-testnode');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
it("Finds 2 node-red modules and 1 plugin in nodesDir (in root of dir)",function(done) {
|
||||||
|
stubPathJoin()
|
||||||
|
localfilesystem.init({nodesDir:[nodesDir2]});
|
||||||
|
const nodeModule = localfilesystem.getModuleFiles();
|
||||||
|
const loaded = Object.keys(nodeModule)
|
||||||
|
loaded.should.have.a.property("length", 3)
|
||||||
|
loaded.indexOf('@test/testnode').should.greaterThan(-1, "Should load @test/testnode")
|
||||||
|
loaded.indexOf('testnode2').should.greaterThan(-1, "Should load testnode2")
|
||||||
|
loaded.indexOf('test-theme2').should.greaterThan(-1, "Should load test-theme2")
|
||||||
|
|
||||||
|
nodeModule['@test/testnode'].should.have.a.property('name','@test/testnode');
|
||||||
|
nodeModule['@test/testnode'].should.have.a.property('version','1.0.0');
|
||||||
|
nodeModule['@test/testnode'].should.have.a.property('nodes');
|
||||||
|
nodeModule['@test/testnode'].should.have.a.property('path');
|
||||||
|
nodeModule['@test/testnode'].should.have.a.property('user', false);
|
||||||
|
|
||||||
|
nodeModule['testnode2'].should.have.a.property('name','testnode2');
|
||||||
|
nodeModule['testnode2'].should.have.a.property('version','1.0.0');
|
||||||
|
nodeModule['testnode2'].should.have.a.property('nodes');
|
||||||
|
nodeModule['testnode2'].should.have.a.property('path');
|
||||||
|
nodeModule['testnode2'].should.have.a.property('user', false);
|
||||||
|
|
||||||
|
nodeModule['test-theme2'].should.have.a.property('name','test-theme2');
|
||||||
|
|
||||||
|
nodeModule['test-theme2'].should.have.a.property('version','0.0.1');
|
||||||
|
nodeModule['test-theme2'].should.have.a.property('nodes', {});
|
||||||
|
nodeModule['test-theme2'].should.have.a.property('path');
|
||||||
|
nodeModule['test-theme2'].should.have.a.property('user', false);
|
||||||
|
nodeModule['test-theme2'].should.have.a.property('plugins');
|
||||||
|
nodeModule['test-theme2'].plugins.should.have.a.property('test-theme2');
|
||||||
|
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('name','test-theme2');
|
||||||
|
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('module','test-theme2');
|
||||||
|
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('version', '0.0.1');
|
||||||
|
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('file');
|
||||||
|
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('local', false);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
it("Finds 2 node-red modules and 1 plugin in nodesDir pointing to a node_modules dir",function(done) {
|
||||||
|
stubPathJoin()
|
||||||
|
localfilesystem.init({nodesDir:[path.join(nodesDir3, "node_modules")]});
|
||||||
|
const nodeModule = localfilesystem.getModuleFiles();
|
||||||
|
const loaded = Object.keys(nodeModule)
|
||||||
|
loaded.should.have.a.property("length", 3)
|
||||||
|
|
||||||
|
loaded.indexOf('@test/testnode').should.greaterThan(-1, "Should load @test/testnode")
|
||||||
|
loaded.indexOf('@test/test-theme3').should.greaterThan(-1, "Should load test-theme3")
|
||||||
|
loaded.indexOf('testnode3').should.greaterThan(-1, "Should load testnode3")
|
||||||
|
done();
|
||||||
|
});
|
||||||
it("throws an error if a node isn't found",function(done) {
|
it("throws an error if a node isn't found",function(done) {
|
||||||
var _join = path.join;
|
stubPathJoin()
|
||||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
|
||||||
if (arguments[0] == resourcesDir) {
|
|
||||||
// This stops the module tree scan from going any higher
|
|
||||||
// up the tree than resourcesDir.
|
|
||||||
return arguments[0];
|
|
||||||
}
|
|
||||||
return _join.apply(null,arguments);
|
|
||||||
}));
|
|
||||||
localfilesystem.init({coreNodesDir:moduleDir});
|
localfilesystem.init({coreNodesDir:moduleDir});
|
||||||
/*jshint immed: false */
|
/*jshint immed: false */
|
||||||
(function(){
|
(function(){
|
||||||
@ -250,15 +386,7 @@ describe("red/nodes/registry/localfilesystem",function() {
|
|||||||
it.skip("finds locales directory");
|
it.skip("finds locales directory");
|
||||||
it.skip("finds icon path directory");
|
it.skip("finds icon path directory");
|
||||||
it("scans icon files with a module file",function(done) {
|
it("scans icon files with a module file",function(done) {
|
||||||
var _join = path.join;
|
stubPathJoin()
|
||||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
|
||||||
if (arguments[0] == resourcesDir) {
|
|
||||||
// This stops the module tree scan from going any higher
|
|
||||||
// up the tree than resourcesDir.
|
|
||||||
return arguments[0];
|
|
||||||
}
|
|
||||||
return _join.apply(null,arguments);
|
|
||||||
}));
|
|
||||||
localfilesystem.init({
|
localfilesystem.init({
|
||||||
coreNodesDir: moduleDir
|
coreNodesDir: moduleDir
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M10.004 14.499h20M10.004 46.503h20M10.004 22.5h20M10.004 30.501h20M10.004 38.502h20" stroke="#fff" stroke-width="2.9997000000000003"/></svg>
|
After Width: | Height: | Size: 236 B |
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
console.log("hello from loose1.html")
|
||||||
|
})()
|
||||||
|
</script>
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
console.log("hello from loose1.js")
|
||||||
|
})()
|
@ -0,0 +1 @@
|
|||||||
|
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M30.999 31.005v-3h-6.762s.812-12.397 1.162-14 .597-3.35 2.628-3.103 1.971 3.103 1.971 3.103l4.862-.016s-.783-3.984-2.783-5.984-7.946-1.7-9.633.03c-1.687 1.73-2.302 5.065-2.597 6.422-.588 4.5-.854 9.027-1.248 13.547h-8.6v3H18.1s-.812 12.398-1.162 14-.597 3.35-2.628 3.103-1.972-3.102-1.972-3.102l-4.862.015s.783 3.985 2.783 5.985c2 2 7.946 1.699 9.634-.031 1.687-1.73 2.302-5.065 2.597-6.422.587-4.5.854-9.027 1.248-13.547z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 539 B |
@ -0,0 +1 @@
|
|||||||
|
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M7 38.98v3.983h11v12l13-23H19l-.463.017c-1.28 4.048-5.066 6.983-9.537 6.983zm12-11.017h12l-13-23v12H7V20.9l2 .064c4.467 0 8.25 2.93 9.534 6.972zM6.95 24.22a6 6 0 1 1-.083 11.456" fill="#fff" style="isolation:auto;mix-blend-mode:normal"/></svg>
|
After Width: | Height: | Size: 339 B |
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
console.log("hello from loose2.html")
|
||||||
|
})()
|
||||||
|
</script>
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
console.log("hello from loose2.js")
|
||||||
|
})()
|
@ -0,0 +1 @@
|
|||||||
|
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M30.999 31.005v-3h-6.762s.812-12.397 1.162-14 .597-3.35 2.628-3.103 1.971 3.103 1.971 3.103l4.862-.016s-.783-3.984-2.783-5.984-7.946-1.7-9.633.03c-1.687 1.73-2.302 5.065-2.597 6.422-.588 4.5-.854 9.027-1.248 13.547h-8.6v3H18.1s-.812 12.398-1.162 14-.597 3.35-2.628 3.103-1.972-3.102-1.972-3.102l-4.862.015s.783 3.985 2.783 5.985c2 2 7.946 1.699 9.634-.031 1.687-1.73 2.302-5.065 2.597-6.422.587-4.5.854-9.027 1.248-13.547z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 539 B |
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
console.log("hello from regular module main.js")
|
||||||
|
})()
|
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "node-red-node-testnode",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A node-red node that does nothing other than exist",
|
||||||
|
"main": "main.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node-red"
|
||||||
|
],
|
||||||
|
"node-red": {
|
||||||
|
"nodes": {
|
||||||
|
"testnode": "index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"author": "@testyMcTersterson",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M30.999 31.005v-3h-6.762s.812-12.397 1.162-14 .597-3.35 2.628-3.103 1.971 3.103 1.971 3.103l4.862-.016s-.783-3.984-2.783-5.984-7.946-1.7-9.633.03c-1.687 1.73-2.302 5.065-2.597 6.422-.588 4.5-.854 9.027-1.248 13.547h-8.6v3H18.1s-.812 12.398-1.162 14-.597 3.35-2.628 3.103-1.972-3.102-1.972-3.102l-4.862.015s.783 3.985 2.783 5.985c2 2 7.946 1.699 9.634-.031 1.687-1.73 2.302-5.065 2.597-6.422.587-4.5.854-9.027 1.248-13.547z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 539 B |
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
console.log("hello from regular module main.js")
|
||||||
|
})()
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "regular_node",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A regular node that does nothing other than exist",
|
||||||
|
"main": "main.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
"author": "@testyMcTersterson",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
console.log("hello from @test/testnode index.html")
|
||||||
|
})()
|
||||||
|
</script>
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
console.log("hello from @test/testnode index.js")
|
||||||
|
})()
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "@test/testnode",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A test node that does nothing other than exist",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node-red",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
"node-red": {
|
||||||
|
"nodes": {
|
||||||
|
"testnode": "index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"author": "@testyMcTersterson",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
console.log("hello from testnode2 index.js")
|
||||||
|
})()
|
||||||
|
</script>
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
console.log("hello from testnode2 index.js")
|
||||||
|
})()
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "testnode2",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A test node that does nothing other than exist",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node-red",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
"node-red": {
|
||||||
|
"nodes": {
|
||||||
|
"testnode2": "index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"author": "@testyMcTersterson",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
(function() {
|
||||||
|
console.log("Hi from test plugin client side")
|
||||||
|
})()
|
@ -0,0 +1,14 @@
|
|||||||
|
module.exports = function (RED) {
|
||||||
|
RED.plugins.registerPlugin('test-theme', {
|
||||||
|
type: 'node-red-theme',
|
||||||
|
scripts: [
|
||||||
|
'files/clientside.js'
|
||||||
|
],
|
||||||
|
css: [
|
||||||
|
'files/theme.css',
|
||||||
|
],
|
||||||
|
monacoOptions: {
|
||||||
|
theme: "vs"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
:root{--red-ui-primary-background: #f2f3fb;}
|
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "test-theme2",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "test theme for Node-RED",
|
||||||
|
|
||||||
|
"keywords": [
|
||||||
|
"node-red",
|
||||||
|
"plugin",
|
||||||
|
"theme"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "testy-McTesterson"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"node-red": {
|
||||||
|
"version": ">=2.2.0",
|
||||||
|
"plugins": {
|
||||||
|
"test-theme2": "files/plugin.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.x"
|
||||||
|
}
|
||||||
|
}
|
5
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/index.html
generated
vendored
Normal file
5
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/index.html
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
console.log("hello from @test/testnode index.html")
|
||||||
|
})()
|
||||||
|
</script>
|
4
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/index.js
generated
vendored
Normal file
4
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/index.js
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
console.log("hello from @test/testnode index.js")
|
||||||
|
})()
|
20
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/package.json
generated
vendored
Normal file
20
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/package.json
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "@test/testnode",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A test node that does nothing other than exist",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node-red",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
"node-red": {
|
||||||
|
"nodes": {
|
||||||
|
"testnode": "index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"author": "@testyMcTersterson",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
3
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/clientside.js
generated
vendored
Normal file
3
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/clientside.js
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
(function() {
|
||||||
|
console.log("Hi from test plugin client side")
|
||||||
|
})()
|
14
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/plugin.js
generated
vendored
Normal file
14
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/plugin.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module.exports = function (RED) {
|
||||||
|
RED.plugins.registerPlugin('test-theme', {
|
||||||
|
type: 'node-red-theme',
|
||||||
|
scripts: [
|
||||||
|
'files/clientside.js'
|
||||||
|
],
|
||||||
|
css: [
|
||||||
|
'files/theme.css',
|
||||||
|
],
|
||||||
|
monacoOptions: {
|
||||||
|
theme: "vs"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
1
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/theme.css
generated
vendored
Normal file
1
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/theme.css
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
:root{--red-ui-primary-background: #f2f3fb;}
|
24
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/package.json
generated
vendored
Normal file
24
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/package.json
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@test/test-theme3",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "test theme for Node-RED",
|
||||||
|
|
||||||
|
"keywords": [
|
||||||
|
"node-red",
|
||||||
|
"plugin",
|
||||||
|
"theme"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "testy-McTesterson"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"node-red": {
|
||||||
|
"version": ">=2.2.0",
|
||||||
|
"plugins": {
|
||||||
|
"test-theme3": "files/plugin.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.x"
|
||||||
|
}
|
||||||
|
}
|
5
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/index.html
generated
vendored
Normal file
5
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/index.html
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
console.log("hello from testnode3 index.js")
|
||||||
|
})()
|
||||||
|
</script>
|
4
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/index.js
generated
vendored
Normal file
4
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/index.js
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
console.log("hello from testnode3 index.js")
|
||||||
|
})()
|
20
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/package.json
generated
vendored
Normal file
20
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/package.json
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "testnode3",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A test node that does nothing other than exist",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node-red",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
"node-red": {
|
||||||
|
"nodes": {
|
||||||
|
"testnode3": "index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"author": "@testyMcTersterson",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
@ -388,6 +388,19 @@ describe("@node-red/util/util", function() {
|
|||||||
result[0].should.eql(1);
|
result[0].should.eql(1);
|
||||||
result[1].should.eql(2);
|
result[1].should.eql(2);
|
||||||
});
|
});
|
||||||
|
it('throws an error if buffer data is not array or string', function (done) {
|
||||||
|
try {
|
||||||
|
var result = util.evaluateNodeProperty('12','bin');
|
||||||
|
done("should throw an error");
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code === "INVALID_BUFFER_DATA") {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
done("should throw an error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
it('returns msg property',function() {
|
it('returns msg property',function() {
|
||||||
var result = util.evaluateNodeProperty('foo.bar','msg',{},{foo:{bar:"123"}});
|
var result = util.evaluateNodeProperty('foo.bar','msg',{},{foo:{bar:"123"}});
|
||||||
result.should.eql("123");
|
result.should.eql("123");
|
||||||
|
Loading…
Reference in New Issue
Block a user