mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/--bug_report.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/--bug_report.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| --- | ||||
| name: Bug report | ||||
| about: Reproducable software issues in the core of Node-RED | ||||
| about: Reproducible software issues in the core of Node-RED | ||||
| title: '' | ||||
| labels: '' | ||||
| assignees: '' | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							| @@ -29,6 +29,6 @@ the [forum](https://discourse.nodered.org) or | ||||
| <!-- Put an `x` in the boxes that apply --> | ||||
|  | ||||
| - [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md) | ||||
| - [ ] For non-bugfix PRs, I have discussed this change on the mailing list/slack team. | ||||
| - [ ] For non-bugfix PRs, I have discussed this change on the forum/slack team. | ||||
| - [ ] I have run `grunt` to verify the unit tests pass | ||||
| - [ ] I have added suitable unit tests to cover the new/changed functionality | ||||
|   | ||||
							
								
								
									
										490
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										490
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -151,6 +151,7 @@ module.exports = function(grunt) { | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/actions.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js", | ||||
| @@ -177,6 +178,7 @@ module.exports = function(grunt) { | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/group.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js", | ||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js", | ||||
| @@ -193,7 +195,8 @@ module.exports = function(grunt) { | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.0.1.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js", | ||||
|                         "node_modules/marked/marked.min.js", | ||||
|                         "node_modules/dompurify/dist/purify.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js", | ||||
|                         "packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js", | ||||
|                         "node_modules/jsonata/jsonata-es5.min.js", | ||||
|   | ||||
							
								
								
									
										26
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "node-red", | ||||
|     "version": "1.0.3", | ||||
|     "version": "1.0.4", | ||||
|     "description": "Low-code programming for event-driven applications", | ||||
|     "homepage": "http://nodered.org", | ||||
|     "license": "Apache-2.0", | ||||
| @@ -24,7 +24,7 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "ajv": "6.10.2", | ||||
|         "ajv": "6.12.0", | ||||
|         "basic-auth": "2.0.1", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "body-parser": "1.19.0", | ||||
| @@ -34,47 +34,49 @@ | ||||
|         "cookie": "0.4.0", | ||||
|         "cookie-parser": "1.4.4", | ||||
|         "cors": "2.8.5", | ||||
|         "cron": "1.7.2", | ||||
|         "cron": "1.8.2", | ||||
|         "denque": "1.4.1", | ||||
|         "express": "4.17.1", | ||||
|         "express-session": "1.17.0", | ||||
|         "fs-extra": "8.1.0", | ||||
|         "fs.notify": "0.0.4", | ||||
|         "hash-sum": "2.0.0", | ||||
|         "https-proxy-agent": "2.2.4", | ||||
|         "https-proxy-agent": "5.0.0", | ||||
|         "i18next": "15.1.2", | ||||
|         "iconv-lite": "0.5.0", | ||||
|         "iconv-lite": "0.5.1", | ||||
|         "is-utf8": "0.2.1", | ||||
|         "js-yaml": "3.13.1", | ||||
|         "json-stringify-safe": "5.0.1", | ||||
|         "jsonata": "1.8.0", | ||||
|         "jsonata": "1.8.1", | ||||
|         "media-typer": "1.1.0", | ||||
|         "memorystore": "1.6.1", | ||||
|         "memorystore": "1.6.2", | ||||
|         "mime": "2.4.4", | ||||
|         "mqtt": "2.18.8", | ||||
|         "multer": "1.4.2", | ||||
|         "mustache": "3.0.2", | ||||
|         "mustache": "4.0.0", | ||||
|         "node-red-node-rbe": "^0.2.6", | ||||
|         "node-red-node-sentiment": "^0.1.6", | ||||
|         "node-red-node-tail": "^0.1.0", | ||||
|         "nopt": "4.0.1", | ||||
|         "oauth2orize": "1.11.0", | ||||
|         "on-headers": "1.0.2", | ||||
|         "passport": "0.4.0", | ||||
|         "passport": "0.4.1", | ||||
|         "passport-http-bearer": "1.0.1", | ||||
|         "passport-oauth2-client-password": "0.1.2", | ||||
|         "raw-body": "2.4.1", | ||||
|         "request": "2.88.0", | ||||
|         "semver": "6.3.0", | ||||
|         "uglify-js": "3.6.9", | ||||
|         "uglify-js": "3.8.0", | ||||
|         "when": "3.7.8", | ||||
|         "ws": "6.2.1", | ||||
|         "xml2js": "0.4.22" | ||||
|         "xml2js": "0.4.23" | ||||
|     }, | ||||
|     "optionalDependencies": { | ||||
|         "bcrypt": "3.0.6" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "marked": "0.8.0", | ||||
|         "dompurify": "2.0.8", | ||||
|         "grunt": "~1.0.4", | ||||
|         "grunt-chmod": "~1.1.1", | ||||
|         "grunt-cli": "~1.3.2", | ||||
| @@ -102,7 +104,7 @@ | ||||
|         "mocha": "^5.2.0", | ||||
|         "mosca": "^2.8.3", | ||||
|         "node-red-node-test-helper": "^0.2.3", | ||||
|         "node-sass": "^4.13.0", | ||||
|         "node-sass": "^4.13.1", | ||||
|         "should": "^8.4.0", | ||||
|         "sinon": "1.17.7", | ||||
|         "stoppable": "^1.1.0", | ||||
|   | ||||
| @@ -101,7 +101,10 @@ function login(req,res) { | ||||
|             } | ||||
|         } else if (mergedAdminAuth.type === "strategy") { | ||||
|  | ||||
|             var urlPrefix = (settings.httpAdminRoot==='/')?"":settings.httpAdminRoot; | ||||
|             var urlPrefix = (settings.httpAdminRoot||"").replace(/\/$/,""); | ||||
|             if (urlPrefix.length > 0) { | ||||
|                 urlPrefix += "/"; | ||||
|             } | ||||
|             response = { | ||||
|                 "type":"strategy", | ||||
|                 "prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}] | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-api", | ||||
|     "version": "1.0.3", | ||||
|     "version": "1.0.4", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,21 +16,21 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/util": "1.0.3", | ||||
|         "@node-red/editor-client": "1.0.3", | ||||
|         "@node-red/util": "1.0.4", | ||||
|         "@node-red/editor-client": "1.0.4", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "body-parser": "1.19.0", | ||||
|         "clone": "2.1.2", | ||||
|         "cors": "2.8.5", | ||||
|         "express-session": "1.17.0", | ||||
|         "express": "4.17.1", | ||||
|         "memorystore": "1.6.1", | ||||
|         "memorystore": "1.6.2", | ||||
|         "mime": "2.4.4", | ||||
|         "mustache": "3.0.2", | ||||
|         "mustache": "4.0.0", | ||||
|         "oauth2orize": "1.11.0", | ||||
|         "passport-http-bearer": "1.0.1", | ||||
|         "passport-oauth2-client-password": "0.1.2", | ||||
|         "passport": "0.4.0", | ||||
|         "passport": "0.4.1", | ||||
|         "when": "3.7.8", | ||||
|         "ws": "6.2.1" | ||||
|     }, | ||||
|   | ||||
| @@ -34,11 +34,11 @@ | ||||
|         "view" : "Ansicht", | ||||
|         "grid" : "Gitter", | ||||
|         "showGrid" : "Raster anzeigen", | ||||
|         "snapGrid" : "Einrasten am Raster", | ||||
|         "snapGrid" : "Am Raster ausrichten", | ||||
|         "gridSize" : "Rastergröße", | ||||
|         "textDir" : "Textrichtung", | ||||
|         "defaultDir" : "Standard", | ||||
|         "ltr" : "Links-nach-rechts", | ||||
|         "ltr" : "Von links nach rechts", | ||||
|         "rtl" : "Von rechts nach links", | ||||
|         "auto" : "Kontextuell" | ||||
|       }, | ||||
| @@ -53,15 +53,15 @@ | ||||
|       "import" : "Import", | ||||
|       "export" : "Exportieren", | ||||
|       "search" : "Flows durchsuchen", | ||||
|       "searchInput" : "durchsuchen Sie Ihre Flows", | ||||
|       "searchInput" : "Flows durchsuchen", | ||||
|       "subflows" : "Subflow", | ||||
|       "createSubflow" : "Subflow erstellen", | ||||
|       "selectionToSubflow" : "Auswahl für Subflow", | ||||
|       "selectionToSubflow" : "Auswahl zu Subflow", | ||||
|       "flows" : "Flows", | ||||
|       "add" : "Hinzufügen", | ||||
|       "rename" : "Umbenennen", | ||||
|       "delete" : "Löschen", | ||||
|       "keyboardShortcuts" : "Tastaturkurzbefehle", | ||||
|       "keyboardShortcuts" : "Tastenkürzel", | ||||
|       "login" : "Anmelden", | ||||
|       "logout" : "Abmelden", | ||||
|       "editPalette" : "Palette verwalten", | ||||
| @@ -217,7 +217,7 @@ | ||||
|     "remote" : "Ferne Änderungen", | ||||
|     "reviewChanges" : "Änderungen prüfen", | ||||
|     "noBinaryFileShowed" : "Der Inhalt der Binärdatei kann nicht angezeigt", | ||||
|     "viewCommitDiff" : "Änderungen festschreiben", | ||||
|     "viewCommitDiff" : "Änderungen committen", | ||||
|     "compareChanges" : "Änderungen vergleichen", | ||||
|     "saveConflict" : "Konfliktlösung speichern", | ||||
|     "conflictHeader" : "<span> __resolved__ </span>  von  <span> __unresolved__ </span>  -Konflikten behoben", | ||||
| @@ -226,8 +226,8 @@ | ||||
|     "newVersionError" : "Neue Version enthält keine gültige JSON-Datei:" | ||||
|   }, | ||||
|   "subflow" : { | ||||
|     "editSubflow" : "Flowschablone bearbeiten: __name__", | ||||
|     "edit" : "Flowsschablone bearbeiten", | ||||
|     "editSubflow" : "Subflow bearbeiten: __name__", | ||||
|     "edit" : "Subflow bearbeiten", | ||||
|     "subflowInstances" : "Es ist __count__ Instanz dieser Subflow-Vorlage vorhanden.", | ||||
|     "subflowInstances_plural" : "Es gibt __count__ Instanzen dieser Subflow-Vorlage.", | ||||
|     "editSubflowProperties" : "Eigenschaften bearbeiten", | ||||
| @@ -266,7 +266,7 @@ | ||||
|     } | ||||
|   }, | ||||
|   "keyboard" : { | ||||
|     "title" : "Tastaturkurzbefehle", | ||||
|     "title" : "Tastenkürzel", | ||||
|     "keyboard" : "Tastatur", | ||||
|     "filterActions" : "Filteraktionen", | ||||
|     "shortcut" : "Direktaufruf", | ||||
| @@ -283,7 +283,7 @@ | ||||
|     "exportNode" : "Node exportieren", | ||||
|     "nudgeNode" : "Ausgewählte Nodes verschieben (1px)", | ||||
|     "moveNode" : "Ausgewählte Nodes verschieben (20px)", | ||||
|     "toggleSidebar" : "Seitenleiste ein-/ausschalten", | ||||
|     "toggleSidebar" : "Seitenleiste ein-/ausblenden", | ||||
|     "copyNode" : "Ausgewählte Nodes kopieren", | ||||
|     "cutNode" : "Ausgewählte Nodes ausschneiden", | ||||
|     "pasteNode" : "Node einfügen", | ||||
| @@ -308,7 +308,7 @@ | ||||
|   }, | ||||
|   "palette" : { | ||||
|     "noInfo" : "Keine Informationen verfügbar", | ||||
|     "filter" : "Filter Nodes", | ||||
|     "filter" : "Nodes filtern", | ||||
|     "search" : "Suchmodule", | ||||
|     "addCategory" : "Neu hinzufügen ...", | ||||
|     "label" : { | ||||
| @@ -366,11 +366,11 @@ | ||||
|       "remove" : "entfernen", | ||||
|       "update" : "Update auf __version__", | ||||
|       "updated" : "aktualisiert", | ||||
|       "install" : "installieren", | ||||
|       "installed" : "installiert", | ||||
|       "install" : "Installieren", | ||||
|       "installed" : "Installiert", | ||||
|       "loading" : "Kataloge werden geladen ...", | ||||
|       "tab-nodes" : "Nodes", | ||||
|       "tab-install" : "installieren", | ||||
|       "tab-install" : "Installieren", | ||||
|       "sort" : "Sortierung:", | ||||
|       "sortAZ" : "a-z", | ||||
|       "sortRecent" : "kürzlich", | ||||
| @@ -452,7 +452,7 @@ | ||||
|       "name" : "Kontextdaten", | ||||
|       "label" : "Kontext", | ||||
|       "none" : "keine ausgewählt", | ||||
|       "refresh" : "Aktualisierung zum Laden", | ||||
|       "refresh" : "Zum Aktualisieren neu laden", | ||||
|       "empty" : "leer", | ||||
|       "node" : "Node", | ||||
|       "flow" : "Flow", | ||||
| @@ -477,7 +477,7 @@ | ||||
|         "none" : "Keine", | ||||
|         "install" : "installieren", | ||||
|         "removeFromProject" : "Aus Projekt entfernen", | ||||
|         "addToProject" : "zu Projekt hinzufügen", | ||||
|         "addToProject" : "Zu Projekt hinzufügen", | ||||
|         "files" : "Dateien", | ||||
|         "flow" : "Flow", | ||||
|         "credentials" : "Berechtigungsnachweis", | ||||
| @@ -510,7 +510,7 @@ | ||||
|       }, | ||||
|       "userSettings" : { | ||||
|         "committerDetail" : "Committer-Details", | ||||
|         "committerTip" : "Leer Wert für Systemstandardwert belassen", | ||||
|         "committerTip" : "Leer lassen für Systemstandard", | ||||
|         "userName" : "Benutzername", | ||||
|         "email" : "E-Mail", | ||||
|         "sshKeys" : "SSH-Schlüssel", | ||||
| @@ -544,7 +544,7 @@ | ||||
|         "revertChanges" : "Änderungen zurücksetzen", | ||||
|         "localChanges" : "Lokale Änderungen", | ||||
|         "none" : "Keine", | ||||
|         "conflictResolve" : "Alle Konflikte wurden aufgelöst. Festschreiben der Änderungen, um den Mischvorgang abzuschließen.", | ||||
|         "conflictResolve" : "Alle Konflikte wurden aufgelöst. Committe die Änderungen, um den Merge Request abzuschließen.", | ||||
|         "localFiles" : "Lokale Dateien", | ||||
|         "all" : "alle", | ||||
|         "unmergedChanges" : "Nicht zusammengeführte Änderungen", | ||||
|   | ||||
| @@ -14,7 +14,11 @@ | ||||
|             "back": "Back", | ||||
|             "next": "Next", | ||||
|             "clone": "Clone project", | ||||
|             "cont": "Continue" | ||||
|             "cont": "Continue", | ||||
|             "line": "Outline", | ||||
|             "fill": "Fill", | ||||
|             "color": "Color", | ||||
|             "position": "Position" | ||||
|         }, | ||||
|         "type": { | ||||
|             "string": "string", | ||||
| @@ -91,7 +95,12 @@ | ||||
|             "projects-new": "New", | ||||
|             "projects-open": "Open", | ||||
|             "projects-settings": "Project Settings", | ||||
|             "showNodeLabelDefault": "Show label of newly added nodes" | ||||
|             "showNodeLabelDefault": "Show label of newly added nodes", | ||||
|             "groups": "Groups", | ||||
|             "groupSelection": "Group selection", | ||||
|             "ungroupSelection": "Ungroup selection", | ||||
|             "groupMergeSelection": "Merge selection", | ||||
|             "groupRemoveSelection": "Remove from group" | ||||
|         } | ||||
|     }, | ||||
|     "actions": { | ||||
| @@ -171,6 +180,8 @@ | ||||
|         "node_plural": "__count__ nodes", | ||||
|         "configNode": "__count__ configuration node", | ||||
|         "configNode_plural": "__count__ configuration nodes", | ||||
|         "group": "__count__ group", | ||||
|         "group_plural": "__count__ groups", | ||||
|         "flow": "__count__ flow", | ||||
|         "flow_plural": "__count__ flows", | ||||
|         "subflow": "__count__ subflow", | ||||
| @@ -186,6 +197,9 @@ | ||||
|         "nodesImported": "Imported:", | ||||
|         "nodeCopied": "__count__ node copied", | ||||
|         "nodeCopied_plural": "__count__ nodes copied", | ||||
|         "groupCopied": "__count__ group copied", | ||||
|         "groupCopied_plural": "__count__ groups copied", | ||||
|         "groupStyleCopied": "Group style copied", | ||||
|         "invalidFlow": "Invalid flow: __message__", | ||||
|         "export": { | ||||
|             "selected":"selected nodes", | ||||
| @@ -308,6 +322,13 @@ | ||||
|             "multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection" | ||||
|         } | ||||
|     }, | ||||
|     "group": { | ||||
|         "editGroup": "Edit group: __name__", | ||||
|         "errors": { | ||||
|             "cannotCreateDiffGroups": "Cannot create group using nodes from different groups", | ||||
|             "cannotAddSubflowPorts": "Cannot add subflow ports to a group" | ||||
|         } | ||||
|     }, | ||||
|     "editor": { | ||||
|         "configEdit": "Edit", | ||||
|         "configAdd": "Add", | ||||
| @@ -539,6 +560,7 @@ | ||||
|             "label": "info", | ||||
|             "node": "Node", | ||||
|             "type": "Type", | ||||
|             "group": "Group", | ||||
|             "module": "Module", | ||||
|             "id": "ID", | ||||
|             "status": "Status", | ||||
| @@ -978,7 +1000,8 @@ | ||||
|             "passphrase": "Passphrase", | ||||
|             "retry": "Retry", | ||||
|             "update-failed": "Failed to update auth", | ||||
|             "unhandled": "Unhandled error response" | ||||
|             "unhandled": "Unhandled error response", | ||||
|             "host-key-verify-failed": "<p>Host key verification failed.</p><p>The repository host key could not be verified. Please update your <code>known_hosts</code> file and try again." | ||||
|         }, | ||||
|         "create-branch-list": { | ||||
|             "invalid": "Invalid branch", | ||||
|   | ||||
| @@ -24,7 +24,7 @@ | ||||
|             "buffer": "buffer", | ||||
|             "object": "对象", | ||||
|             "jsonString": "JSON字符串", | ||||
|             "undefined": "为定义", | ||||
|             "undefined": "未定义", | ||||
|             "null": "空" | ||||
|         } | ||||
|     }, | ||||
| @@ -1008,6 +1008,7 @@ | ||||
|         "en-US": "英文", | ||||
|         "ja": "日语", | ||||
|         "ko": "韩文", | ||||
|         "zh-CN": "简体中文" | ||||
|         "zh-CN": "简体中文", | ||||
|         "zh-TW": "繁体中文" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -262,5 +262,9 @@ | ||||
|     "$distinct": { | ||||
|         "args": "array", | ||||
|         "desc": "返回一个数组,其中重复的值已从`数组`中删除" | ||||
|     }, | ||||
|     "$type": { | ||||
|         "args": "value", | ||||
|         "desc": "以字符串形式返回`值`的类型。 如果该`值`未定义,则将返回`未定义`" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,17 @@ | ||||
|             "next": "下一步", | ||||
|             "clone": "複製專案", | ||||
|             "cont": "Continue" | ||||
|         }, | ||||
|         "type": { | ||||
|             "string": "字符串", | ||||
|             "number": "數值", | ||||
|             "boolean": "布林", | ||||
|             "array": "數組", | ||||
|             "buffer": "buffer", | ||||
|             "object": "對象", | ||||
|             "jsonString": "JSON字符串", | ||||
|             "undefined": "未定義", | ||||
|             "null": "空" | ||||
|         } | ||||
|     }, | ||||
|     "workspace": { | ||||
| @@ -29,8 +40,7 @@ | ||||
|         "enabled": "有效", | ||||
|         "disabled": "無效", | ||||
|         "info": "詳細描述", | ||||
|         "selectNodes": "點擊節點用於選擇", | ||||
|         "tip": "詳細描述支援Markdown羽量級標記語言,並將出現在資訊標籤中。" | ||||
|         "selectNodes": "點擊節點用於選擇" | ||||
|     }, | ||||
|     "menu": { | ||||
|         "label": { | ||||
| @@ -45,14 +55,14 @@ | ||||
|                 "ltr": "從左到右", | ||||
|                 "rtl": "從右到左", | ||||
|                 "auto": "上下文", | ||||
|                 "language": "Language", | ||||
|                 "browserDefault": "Browser default" | ||||
|                 "language": "語言", | ||||
|                 "browserDefault": "瀏覽器默認" | ||||
|             }, | ||||
|             "sidebar": { | ||||
|                 "show": "顯示側邊欄" | ||||
|             }, | ||||
|             "palette": { | ||||
|                 "show": "Show palette" | ||||
|                 "show": "顯示控制板" | ||||
|             }, | ||||
|             "settings": "設置", | ||||
|             "userSettings": "使用者設置", | ||||
| @@ -81,10 +91,7 @@ | ||||
|             "projects-new": "新專案", | ||||
|             "projects-open": "開啟專案", | ||||
|             "projects-settings": "專案設定", | ||||
|             "showNodeLabelDefault": "顯示新添加節點的標籤", | ||||
|             "clipboard": "剪貼簿", | ||||
|             "library": "庫", | ||||
|             "examples": "範例" | ||||
|             "showNodeLabelDefault": "顯示新添加節點的標籤" | ||||
|         } | ||||
|     }, | ||||
|     "actions": { | ||||
| @@ -204,8 +211,7 @@ | ||||
|         }, | ||||
|         "copyMessagePath": "已複製路徑", | ||||
|         "copyMessageValue": "已複製數值", | ||||
|         "copyMessageValue_truncated": "已複製捨棄的數值", | ||||
|         "selectNodes": "選擇上面的文本並複製到剪貼簿" | ||||
|         "copyMessageValue_truncated": "已複製捨棄的數值" | ||||
|     }, | ||||
|     "deploy": { | ||||
|         "deploy": "部署", | ||||
| @@ -237,7 +243,7 @@ | ||||
|             "undeployedChanges": "您有未部署的更改。\n\n離開此頁面將丟失這些更改。", | ||||
|             "improperlyConfigured": "工作區包含一些未正確配置的節點:", | ||||
|             "unknown": "工作區包含一些未知的節點類型:", | ||||
|             "confirm": "你確定要部署嗎?", | ||||
|             "confirm": "確定要部署嗎?", | ||||
|             "doNotWarn": "不要再對此發出警告", | ||||
|             "conflict": "伺服器正在運行較新的一組流程。", | ||||
|             "backgroundUpdate": "伺服器上的流程已更新。", | ||||
| @@ -300,8 +306,7 @@ | ||||
|         "errors": { | ||||
|             "noNodesSelected": "<strong>無法創建子流程</strong>: 未選擇節點", | ||||
|             "multipleInputsToSelection": "<strong>無法創建子流程</strong>: 多個輸入到了選擇" | ||||
|         }, | ||||
|         "format": "標記格式" | ||||
|         } | ||||
|     }, | ||||
|     "editor": { | ||||
|         "configEdit": "編輯", | ||||
| @@ -316,17 +321,53 @@ | ||||
|         "addNewType": "添加新的__type__節點", | ||||
|         "nodeProperties": "節點屬性", | ||||
|         "label": "Label", | ||||
|         "color": "顏色", | ||||
|         "portLabels": "埠標籤", | ||||
|         "labelInputs": "輸入", | ||||
|         "labelOutputs": "輸出", | ||||
|         "settingIcon": "Icon", | ||||
|         "default": "默認", | ||||
|         "noDefaultLabel": "無", | ||||
|         "defaultLabel": "使用默認標籤", | ||||
|         "searchIcons": "搜尋 icons", | ||||
|         "searchIcons": "搜尋圖標", | ||||
|         "useDefault": "使用默認", | ||||
|         "description": "描述", | ||||
|         "show": "顯示", | ||||
|         "hide": "隱藏", | ||||
|         "locale": "選擇界面語言", | ||||
|         "icon": "圖標", | ||||
|         "inputType": "輸入類型", | ||||
|         "inputs": { | ||||
|             "input": "輸入", | ||||
|             "select": "選擇", | ||||
|             "checkbox": "復選框", | ||||
|             "spinner": "微調器", | ||||
|             "none": "空", | ||||
|             "hidden": "隱藏屬性" | ||||
|         }, | ||||
|         "types": { | ||||
|             "str": "字符串", | ||||
|             "num": "數字", | ||||
|             "bool": "布爾", | ||||
|             "json": "JSON", | ||||
|             "bin": "buffer", | ||||
|             "env": "環境變量" | ||||
|         }, | ||||
|         "menu": { | ||||
|             "input": "輸入", | ||||
|             "select": "選擇", | ||||
|             "checkbox": "復選框", | ||||
|             "spinner": "微調器", | ||||
|             "hidden": "僅標簽" | ||||
|         }, | ||||
|         "select": { | ||||
|             "label": "標簽", | ||||
|             "value": "值" | ||||
|         }, | ||||
|         "spinner": { | ||||
|             "min": "最小值", | ||||
|             "max": "最大值" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "scopeChange": "更改範圍將使其他流程中的節點無法使用", | ||||
|             "invalidProperties": "無效的屬性:" | ||||
| @@ -356,8 +397,9 @@ | ||||
|         "cutNode": "剪切所選節點", | ||||
|         "pasteNode": "粘貼節點", | ||||
|         "undoChange": "撤銷上次執行的更改", | ||||
|         "searchBox": "打開搜索框", | ||||
|         "managePalette": "管理面板" | ||||
|         "searchBox": "打開搜尋框", | ||||
|         "managePalette": "管理面板", | ||||
|         "actionList": "動作列表" | ||||
|     }, | ||||
|     "library": { | ||||
|         "library": "庫", | ||||
| @@ -371,28 +413,27 @@ | ||||
|         "savedNodes": "保存的節點", | ||||
|         "savedType": "已保存__type__", | ||||
|         "saveFailed": "保存失敗: __message__", | ||||
|         "newFolder": "新文件夾", | ||||
|         "types": { | ||||
|             "local": "本地", | ||||
|             "examples": "例子" | ||||
|         }, | ||||
|         "exportToLibrary": "將節點匯出到庫", | ||||
|         "filename": "檔案名", | ||||
|         "folder": "資料夾", | ||||
|         "filenamePlaceholder": "文件", | ||||
|         "fullFilenamePlaceholder": "a/b/文件", | ||||
|         "folderPlaceholder": "a/b", | ||||
|         "breadcrumb": "庫" | ||||
|         "exportToLibrary": "將節點匯出到庫" | ||||
|     }, | ||||
|     "palette": { | ||||
|         "noInfo": "無可用資訊", | ||||
|         "filter": "過濾節點", | ||||
|         "search": "搜索模組", | ||||
|         "search": "搜尋模組", | ||||
|         "addCategory": "添加新的...", | ||||
|         "label": { | ||||
|             "subflows": "子流程", | ||||
|             "network": "網絡", | ||||
|             "common": "共通", | ||||
|             "input": "輸入", | ||||
|             "output": "輸出", | ||||
|             "function": "功能", | ||||
|             "sequence": "序列", | ||||
|             "parser": "解析", | ||||
|             "social": "社交", | ||||
|             "storage": "存儲", | ||||
|             "analysis": "分析", | ||||
| @@ -459,7 +500,7 @@ | ||||
|             "sortRecent": "日期順序", | ||||
|             "more": "增加__count__個", | ||||
|             "errors": { | ||||
|                 "catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制台瞭解更多資訊", | ||||
|                 "catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制臺瞭解更多資訊", | ||||
|                 "installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊", | ||||
|                 "removeFailed": "無法刪除: __module__<br>__message__<br>查看日誌瞭解更多資訊", | ||||
|                 "updateFailed": "無法更新: __module__<br>__message__<br>查看日誌瞭解更多資訊", | ||||
| @@ -529,8 +570,10 @@ | ||||
|             "none": "無", | ||||
|             "subflows": "子流程", | ||||
|             "flows": "流程", | ||||
|             "filterUnused": "未使用", | ||||
|             "filterAll": "所有", | ||||
|             "showAllConfigNodes": "顯示所有配置節點", | ||||
|             "filterUnused": "未使用", | ||||
|             "showAllUnusedConfigNodes": "顯示所有未使用的配置節點", | ||||
|             "filtered": "__count__ 個隱藏" | ||||
|         }, | ||||
|         "context": { | ||||
| @@ -543,7 +586,9 @@ | ||||
|             "flow": "流程", | ||||
|             "global": "全局的", | ||||
|             "deleteConfirm": "你確定要刪除這個項目嗎?", | ||||
|             "autoRefresh": "自動刷新" | ||||
|             "autoRefresh": "自動刷新", | ||||
|             "refrsh": "刷新", | ||||
|             "delete": "刪除" | ||||
|         }, | ||||
|         "palette": { | ||||
|             "name": "節點管理", | ||||
| @@ -558,6 +603,7 @@ | ||||
|             "noSummaryAvailable": "無可用摘要", | ||||
|             "editDescription": "編輯專案描述", | ||||
|             "editDependencies": "編輯項目依賴", | ||||
|             "noDescriptionAvailable": "沒有可用的描述", | ||||
|             "editReadme": "Edit README.md", | ||||
|             "showProjectSettings": "顯示項目設置", | ||||
|             "projectSettings": { | ||||
| @@ -657,15 +703,15 @@ | ||||
|                 "moreCommits": "更多提交", | ||||
|                 "changeLocalBranch": "變更當地分支", | ||||
|                 "createBranchPlaceholder": "查找或創建分支", | ||||
|                 "upstream": "上游的", | ||||
|                 "localOverwrite": "您有可通过切换分支覆盖的本地更改。您必须先提交或撤销那些更改。", | ||||
|                 "upstream": "上遊的", | ||||
|                 "localOverwrite": "您有可通過切換分支覆蓋的本地更改。您必須先提交或撤銷那些更改。", | ||||
|                 "manageRemoteBranch": "管理遠程分支", | ||||
|                 "unableToAccess": "無法訪問遠程存儲庫", | ||||
|                 "retry": "重試", | ||||
|                 "setUpstreamBranch": "設置為上游分支", | ||||
|                 "setUpstreamBranch": "設置為上遊分支", | ||||
|                 "createRemoteBranchPlaceholder": "查找或創建遠程分支", | ||||
|                 "trackedUpstreamBranch": "創建的分支將被設置為跟踪的上游分支。", | ||||
|                 "selectUpstreamBranch": "分支將被創建。 在下面選擇以將其設置為被跟踪的上游分支。", | ||||
|                 "trackedUpstreamBranch": "創建的分支將被設置為跟蹤的上遊分支。", | ||||
|                 "selectUpstreamBranch": "分支將被創建。 在下面選擇以將其設置為被跟蹤的上遊分支。", | ||||
|                 "pushFailed": "Push失敗,因為遠程具有更多的最新提交。請先進行pull與merge,然後再嘗試push。", | ||||
|                 "push": "push", | ||||
|                 "pull": "pull", | ||||
| @@ -683,7 +729,7 @@ | ||||
|                 "minsAgo": "__count__分鐘前", | ||||
|                 "minsAgo_plural": "__count__分鐘前", | ||||
|                 "secondsAgo": "秒前", | ||||
|                 "notTracking": "您的本地分支當前未跟踪遠程分支。", | ||||
|                 "notTracking": "您的本地分支當前未跟蹤遠程分支。", | ||||
|                 "statusUnmergedChanged": "您的存儲庫中有未合併的更改。您需要解決衝突並提交結果。", | ||||
|                 "repositoryUpToDate": "您的存儲庫是最新的。", | ||||
|                 "commitsAhead": "您的倉庫領先遠程倉庫__count__次提交。您現在可以push這些提交。", | ||||
| @@ -748,10 +794,23 @@ | ||||
|     }, | ||||
|     "jsonEditor": { | ||||
|         "title": "JSON編輯器", | ||||
|         "format": "格式化JSON" | ||||
|         "format": "格式化JSON", | ||||
|         "rawMode": "編輯 JSON", | ||||
|         "uiMode": "Visual編輯器", | ||||
|         "insertAbove": "在上方插入", | ||||
|         "insertBelow": "在下方插入", | ||||
|         "addItem": "添加項目", | ||||
|         "copyPath": "復制路徑到項目", | ||||
|         "expandItems": "展開項目", | ||||
|         "collapseItems": "收合項目", | ||||
|         "duplicate": "重復", | ||||
|         "error": { | ||||
|             "invalidJSON": "無效的JSON: " | ||||
|         } | ||||
|     }, | ||||
|     "markdownEditor": { | ||||
|         "title": "Markdown 編輯器", | ||||
|         "expand": "展開", | ||||
|         "format": "F使用markdown格式化", | ||||
|         "heading1": "Heading 1", | ||||
|         "heading2": "Heading 2", | ||||
| @@ -786,7 +845,7 @@ | ||||
|         }, | ||||
|         "git-config": { | ||||
|             "setup": "設置您的版本控制客戶端", | ||||
|             "desc0": "Node-RED使用開源工具Git進行版本控制。 它跟踪對項目文件的更改,並允許您將其推送到遠程存儲庫。", | ||||
|             "desc0": "Node-RED使用開源工具Git進行版本控制。 它跟蹤對項目文件的更改,並允許您將其推送到遠程存儲庫。", | ||||
|             "desc1": "提交一組更改時,Git會使用用戶名和電子郵件地址記錄誰進行了更改。 用戶名可以是您想要的任何名稱-不必是您的真實姓名。", | ||||
|             "desc2": "您的Git客戶端已經配置了以下詳細信息。", | ||||
|             "desc3": "您可以稍後在設置對話框的“ Git config”標籤下更改這些設置。", | ||||
| @@ -905,7 +964,7 @@ | ||||
|             "confirm": "您確定要刪除此項目嗎?" | ||||
|         }, | ||||
|         "create-project-list": { | ||||
|             "search": "搜索您的項目", | ||||
|             "search": "搜尋您的項目", | ||||
|             "current": "當前的" | ||||
|         }, | ||||
|         "require-clean": { | ||||
| @@ -938,8 +997,19 @@ | ||||
|     }, | ||||
|     "editor-tab": { | ||||
|         "properties": "屬性", | ||||
|         "envProperties": "環境變量", | ||||
|         "description": "描述", | ||||
|         "appearance": "外觀", | ||||
|         "preview": "UI預覽", | ||||
|         "defaultValue": "默認值", | ||||
|         "env": "環境變量" | ||||
|     }, | ||||
|     "languages": { | ||||
|         "de": "德語", | ||||
|         "en-US": "英語", | ||||
|         "ja": "日語", | ||||
|         "ko": "韓語", | ||||
|         "zh-CN": "簡體中文", | ||||
|         "zh-TW": "繁體中文" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -214,5 +214,57 @@ | ||||
|     "$toMillis": { | ||||
|         "args": "timestamp", | ||||
|         "desc": "將ISO 8601格式的字串`timestamp`轉換為從UNIX時間 (1970年1月1日 UTC/GMT的午夜)開始到現在的毫秒數。如果該字串的格式不正確,則拋出錯誤。" | ||||
|     }, | ||||
|     "$env": { | ||||
|         "args": "arg", | ||||
|         "desc": "返回環境變量的值。\n\n這是Node-RED定義的函數。" | ||||
|     }, | ||||
|     "$eval": { | ||||
|         "args": "expr [, context]", | ||||
|         "desc": "使用當前上下文來作為評估依據,分析並評估字符串`expr`,其中包含文字JSON或JSONata表達式。" | ||||
|     }, | ||||
|     "$formatInteger": { | ||||
|         "args": "number, picture", | ||||
|         "desc": "將“數字”轉換為字符串,並將其格式化為“圖片”字符串指定的整數表示形式。圖片字符串參數定義了數字的格式,並具有與XPath F&O 3.1 規範中的fn:format-integer相同的語法。" | ||||
|     }, | ||||
|     "$parseInteger": { | ||||
|         "args": "string, picture", | ||||
|         "desc": "使用“圖片”字符串指定的格式將“字符串”參數的內容解析為整數(作為JSON數字)。圖片字符串參數與$formatInteger格式相同。." | ||||
|     }, | ||||
|     "$error": { | ||||
|         "args": "[str]", | ||||
|         "desc": "引發錯誤並顯示一條消息。 可選的`str`將替代$error()函數評估的默認消息。" | ||||
|     }, | ||||
|     "$assert": { | ||||
|         "args": "arg, str", | ||||
|         "desc": "如果`arg`為真,則該函數返回。 如果arg為假,則拋出帶有str的異常作為異常消息。" | ||||
|     }, | ||||
|     "$single": { | ||||
|         "args": "array, function", | ||||
|         "desc": "返回滿足參數function謂語的array參數中的唯一值 (比如:傳遞值時,函數返回布林值“true”)。如果匹配值的數量不唯一時,則拋出異常。\n\n應在以下簽名中提供函數:`function(value [,index [,array []]])`其中value是數組的每個輸入,index是該值的位置,整個數組作為第三個參數傳遞。" | ||||
|     }, | ||||
|     "$encodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "通過用表示字符的UTF-8編碼的一個,兩個,三個或四個轉義序列替換某些字符的每個實例,對統一資源定位符(URL)組件進行編碼。\n\n示例:`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" | ||||
|     }, | ||||
|     "$encodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "通過用表示字符的UTF-8編碼的一個,兩個,三個或四個轉義序列替換某些字符的每個實例,對統一資源定位符(URL)進行編碼。\n\n示例: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" | ||||
|     }, | ||||
|     "$decodeUrl": { | ||||
|         "args": "str", | ||||
|         "desc": "解碼以前由encodeUrlComponent創建的統一資源定位器(URL)組件。 \n\n示例: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" | ||||
|     }, | ||||
|     "$decodeUrlComponent": { | ||||
|         "args": "str", | ||||
|         "desc": "解碼先前由encodeUrl創建的統一資源定位符(URL)。 \n\n示例: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" | ||||
|     }, | ||||
|     "$distinct": { | ||||
|         "args": "array", | ||||
|         "desc": "返回一個數組,其中重復的值已從`數組`中刪除" | ||||
|     }, | ||||
|     "$type": { | ||||
|         "args": "value", | ||||
|         "desc": "以字符串形式返回`值`的類型。 如果該`值`未定義,則將返回`未定義`" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-client", | ||||
|     "version": "1.0.3", | ||||
|     "version": "1.0.4", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
| @@ -21,6 +21,7 @@ RED.history = (function() { | ||||
|         var i; | ||||
|         var len; | ||||
|         var node; | ||||
|         var group; | ||||
|         var subflow; | ||||
|         var modifiedTabs = {}; | ||||
|         var inverseEv; | ||||
| @@ -74,6 +75,15 @@ RED.history = (function() { | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.groups) { | ||||
|                     inverseEv.groups = []; | ||||
|                     for (i=0;i<ev.groups.length;i++) { | ||||
|                         group = ev.groups[i]; | ||||
|                         modifiedTabs[group.z] = true; | ||||
|                         inverseEv.groups.push(group); | ||||
|                         RED.nodes.removeGroup(group); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.workspaces) { | ||||
|                     inverseEv.workspaces = []; | ||||
|                     for (i=0;i<ev.workspaces.length;i++) { | ||||
| @@ -193,12 +203,35 @@ RED.history = (function() { | ||||
|                         n.dirty = true; | ||||
|                     }); | ||||
|                 } | ||||
|                 if (ev.groups) { | ||||
|                     inverseEv.groups = []; | ||||
|                     var groupsToAdd = new Set(ev.groups.map(function(g) { return g.id })); | ||||
|                     for (i=0;i<ev.groups.length;i++) { | ||||
|                         RED.nodes.addGroup(ev.groups[i]) | ||||
|                         modifiedTabs[ev.groups[i].z] = true; | ||||
|                         inverseEv.groups.push(ev.groups[i]); | ||||
|                         if (ev.groups[i].g && !groupsToAdd.has(ev.groups[i].g)) { | ||||
|                             group = RED.nodes.group(ev.groups[i].g); | ||||
|                             if (group.nodes.indexOf(ev.groups[i]) === -1) { | ||||
|                                 group.nodes.push(ev.groups[i]); | ||||
|                             } | ||||
|                             RED.group.markDirty(ev.groups[i]) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.nodes) { | ||||
|                     inverseEv.nodes = []; | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         RED.nodes.add(ev.nodes[i]); | ||||
|                         modifiedTabs[ev.nodes[i].z] = true; | ||||
|                         inverseEv.nodes.push(ev.nodes[i].id); | ||||
|                         if (ev.nodes[i].g) { | ||||
|                             group = RED.nodes.group(ev.nodes[i].g); | ||||
|                             if (group.nodes.indexOf(ev.nodes[i]) === -1) { | ||||
|                                 group.nodes.push(ev.nodes[i]); | ||||
|                             } | ||||
|                             RED.group.markDirty(group) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
| @@ -260,6 +293,13 @@ RED.history = (function() { | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.addToGroup) { | ||||
|                     RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),true); | ||||
|                     inverseEv.removeFromGroup = ev.addToGroup; | ||||
|                 } else if (ev.removeFromGroup) { | ||||
|                     RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n })); | ||||
|                     inverseEv.addToGroup = ev.removeFromGroup; | ||||
|                 } | ||||
|             } else if (ev.t == "edit") { | ||||
|                 inverseEv = { | ||||
|                     t: "edit", | ||||
| @@ -370,7 +410,9 @@ RED.history = (function() { | ||||
|                 if (ev.nodes) { | ||||
|                     inverseEv.movedNodes = []; | ||||
|                     var z = ev.activeWorkspace; | ||||
|                     RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) { | ||||
|                     var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id}); | ||||
|                     fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id)) | ||||
|                     fullNodeList.forEach(function(n) { | ||||
|                         n.x += ev.subflow.offsetX; | ||||
|                         n.y += ev.subflow.offsetY; | ||||
|                         n.dirty = true; | ||||
| @@ -411,6 +453,9 @@ RED.history = (function() { | ||||
|                 if (ev.subflow) { | ||||
|                     RED.nodes.addSubflow(ev.subflow.subflow); | ||||
|                     inverseEv.subflow = ev.subflow; | ||||
|                     if (ev.subflow.subflow.g) { | ||||
|                         RED.group.addToGroup(RED.nodes.group(ev.subflow.subflow.g),ev.subflow.subflow); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflows) { | ||||
|                     inverseEv.nodes = []; | ||||
| @@ -422,6 +467,9 @@ RED.history = (function() { | ||||
|                 if (ev.movedNodes) { | ||||
|                     ev.movedNodes.forEach(function(nid) { | ||||
|                         nn = RED.nodes.node(nid); | ||||
|                         if (!nn) { | ||||
|                             nn = RED.nodes.group(nid); | ||||
|                         } | ||||
|                         nn.x -= ev.subflow.offsetX; | ||||
|                         nn.y -= ev.subflow.offsetY; | ||||
|                         nn.dirty = true; | ||||
| @@ -435,7 +483,7 @@ RED.history = (function() { | ||||
|                         RED.nodes.addLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if  (ev.createdLinks) { | ||||
|                 if (ev.createdLinks) { | ||||
|                     inverseEv.removedLinks = []; | ||||
|                     for (i=0;i<ev.createdLinks.length;i++) { | ||||
|                         inverseEv.removedLinks.push(ev.createdLinks[i]); | ||||
| @@ -450,6 +498,55 @@ RED.history = (function() { | ||||
|                 if (ev.order) { | ||||
|                     RED.workspaces.order(ev.order); | ||||
|                 } | ||||
|             } else if (ev.t == "createGroup") { | ||||
|                 inverseEv = { | ||||
|                     t: "ungroup", | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                     groups: [] | ||||
|                 } | ||||
|                 if (ev.groups) { | ||||
|                     for (i=0;i<ev.groups.length;i++) { | ||||
|                         inverseEv.groups.push(ev.groups[i]); | ||||
|                         RED.group.ungroup(ev.groups[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "ungroup") { | ||||
|                 inverseEv = { | ||||
|                     t: "createGroup", | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                     groups: [] | ||||
|                 } | ||||
|                 if (ev.groups) { | ||||
|                     for (i=0;i<ev.groups.length;i++) { | ||||
|                         inverseEv.groups.push(ev.groups[i]); | ||||
|                         var nodes = ev.groups[i].nodes.slice(); | ||||
|                         ev.groups[i].nodes = []; | ||||
|                         RED.nodes.addGroup(ev.groups[i]); | ||||
|                         RED.group.addToGroup(ev.groups[i],nodes); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "addToGroup") { | ||||
|                 inverseEv = { | ||||
|                     t: "removeFromGroup", | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                     group: ev.group, | ||||
|                     nodes: ev.nodes, | ||||
|                     reparent: ev.reparent | ||||
|                 } | ||||
|                 if (ev.nodes) { | ||||
|                     RED.group.removeFromGroup(ev.group,ev.nodes,(ev.hasOwnProperty('reparent')&&ev.hasOwnProperty('reparent')!==undefined)?ev.reparent:true); | ||||
|                 } | ||||
|             } else if (ev.t == "removeFromGroup") { | ||||
|                 inverseEv = { | ||||
|                     t: "addToGroup", | ||||
|                     dirty: RED.nodes.dirty(), | ||||
|                     group: ev.group, | ||||
|                     nodes: ev.nodes, | ||||
|                     reparent: ev.reparent | ||||
|                 } | ||||
|                 if (ev.nodes) { | ||||
|                     RED.group.addToGroup(ev.group,ev.nodes); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             Object.keys(modifiedTabs).forEach(function(id) { | ||||
| @@ -460,8 +557,8 @@ RED.history = (function() { | ||||
|             }); | ||||
|  | ||||
|             RED.nodes.dirty(ev.dirty); | ||||
|             RED.view.updateActive(); | ||||
|             RED.view.select(null); | ||||
|             RED.view.redraw(true); | ||||
|             RED.palette.refresh(); | ||||
|             RED.workspaces.refresh(); | ||||
|             RED.sidebar.config.refresh(); | ||||
| @@ -482,6 +579,9 @@ RED.history = (function() { | ||||
|         list: function() { | ||||
|             return undoHistory; | ||||
|         }, | ||||
|         listRedo: function() { | ||||
|             return redoHistory; | ||||
|         }, | ||||
|         depth: function() { | ||||
|             return undoHistory.length; | ||||
|         }, | ||||
|   | ||||
| @@ -61,6 +61,10 @@ | ||||
|         "shift-down": "core:step-selection-down", | ||||
|         "shift-left": "core:step-selection-left", | ||||
|         "ctrl-shift-j": "core:show-previous-tab", | ||||
|         "ctrl-shift-k": "core:show-next-tab" | ||||
|         "ctrl-shift-k": "core:show-next-tab", | ||||
|         "ctrl-shift-g": "core:group-selection", | ||||
|         "ctrl-shift-u": "core:ungroup-selection", | ||||
|         "ctrl-shift-c": "core:copy-group-style", | ||||
|         "ctrl-shift-v": "core:paste-group-style" | ||||
|      } | ||||
| } | ||||
|   | ||||
| @@ -27,6 +27,9 @@ RED.nodes = (function() { | ||||
|     var subflows = {}; | ||||
|     var loadedFlowVersion = null; | ||||
|  | ||||
|     var groups = {}; | ||||
|     var groupsByZ = {}; | ||||
|  | ||||
|     var initialLoad; | ||||
|  | ||||
|     var dirty = false; | ||||
| @@ -302,6 +305,10 @@ RED.nodes = (function() { | ||||
|     } | ||||
|  | ||||
|     function moveNodeToTab(node, z) { | ||||
|         if (node.type === "group") { | ||||
|             moveGroupToTab(node,z); | ||||
|             return; | ||||
|         } | ||||
|         if (nodeTabMap[node.z]) { | ||||
|             delete nodeTabMap[node.z][node.id]; | ||||
|         } | ||||
| @@ -311,6 +318,13 @@ RED.nodes = (function() { | ||||
|         nodeTabMap[z][node.id] = node; | ||||
|         node.z = z; | ||||
|     } | ||||
|     function moveGroupToTab(group, z) { | ||||
|         var index = groupsByZ[group.z].indexOf(group); | ||||
|         groupsByZ[group.z].splice(index,1); | ||||
|         groupsByZ[z] = groupsByZ[z] || []; | ||||
|         groupsByZ[z].push(group); | ||||
|         group.z = z; | ||||
|     } | ||||
|  | ||||
|     function removeLink(l) { | ||||
|         var index = links.indexOf(l); | ||||
| @@ -340,6 +354,7 @@ RED.nodes = (function() { | ||||
|  | ||||
|         var removedNodes = []; | ||||
|         var removedLinks = []; | ||||
|         var removedGroups = []; | ||||
|         var n; | ||||
|         var node; | ||||
|         for (n=0;n<nodes.length;n++) { | ||||
| @@ -356,11 +371,17 @@ RED.nodes = (function() { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         removedGroups = groupsByZ[id] || []; | ||||
|         removedGroups.forEach(function(g) { | ||||
|             delete groups[g.id] | ||||
|         }) | ||||
|         delete groupsByZ[id]; | ||||
|  | ||||
|         for (n=0;n<removedNodes.length;n++) { | ||||
|             var result = removeNode(removedNodes[n].id); | ||||
|             removedLinks = removedLinks.concat(result.links); | ||||
|         } | ||||
|         return {nodes:removedNodes,links:removedLinks}; | ||||
|         return {nodes:removedNodes,links:removedLinks, groups: removedGroups}; | ||||
|     } | ||||
|  | ||||
|     function addSubflow(sf, createNewIds) { | ||||
| @@ -497,6 +518,9 @@ RED.nodes = (function() { | ||||
|         if (n.d === true) { | ||||
|             node.d = true; | ||||
|         } | ||||
|         if (n.g) { | ||||
|             node.g = n.g; | ||||
|         } | ||||
|         if (node.type == "unknown") { | ||||
|             for (var p in n._orig) { | ||||
|                 if (n._orig.hasOwnProperty(p)) { | ||||
| @@ -544,6 +568,13 @@ RED.nodes = (function() { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (n.type === "group") { | ||||
|             node.x = n.x; | ||||
|             node.y = n.y; | ||||
|             node.w = n.w; | ||||
|             node.h = n.h; | ||||
|             node.nodes = node.nodes.map(function(n) { return n.id }); | ||||
|         } | ||||
|         if (n._def.category != "config") { | ||||
|             node.x = n.x; | ||||
|             node.y = n.y; | ||||
| @@ -669,8 +700,18 @@ RED.nodes = (function() { | ||||
|     /** | ||||
|      * Converts the current node selection to an exportable JSON Object | ||||
|      **/ | ||||
|     function createExportableNodeSet(set, exportedSubflows, exportedConfigNodes) { | ||||
|     function createExportableNodeSet(set, exportedIds, exportedSubflows, exportedConfigNodes) { | ||||
|         var nns = []; | ||||
|  | ||||
|         exportedIds = exportedIds || {}; | ||||
|         set = set.filter(function(n) { | ||||
|             if (exportedIds[n.id]) { | ||||
|                 return false; | ||||
|             } | ||||
|             exportedIds[n.id] = true; | ||||
|             return true; | ||||
|         }) | ||||
|  | ||||
|         exportedConfigNodes = exportedConfigNodes || {}; | ||||
|         exportedSubflows = exportedSubflows || {}; | ||||
|         for (var n=0;n<set.length;n++) { | ||||
| @@ -686,11 +727,11 @@ RED.nodes = (function() { | ||||
|                             subflowSet.push(n); | ||||
|                         } | ||||
|                     }); | ||||
|                     var exportableSubflow = createExportableNodeSet(subflowSet, exportedSubflows, exportedConfigNodes); | ||||
|                     var exportableSubflow = createExportableNodeSet(subflowSet, exportedIds, exportedSubflows, exportedConfigNodes); | ||||
|                     nns = exportableSubflow.concat(nns); | ||||
|                 } | ||||
|             } | ||||
|             if (node.type != "subflow") { | ||||
|             if (node.type !== "subflow") { | ||||
|                 var convertedNode = RED.nodes.convertNode(node); | ||||
|                 for (var d in node._def.defaults) { | ||||
|                     if (node._def.defaults[d].type && node[d] in configNodes) { | ||||
| @@ -707,6 +748,9 @@ RED.nodes = (function() { | ||||
|                     } | ||||
|                 } | ||||
|                 nns.push(convertedNode); | ||||
|                 if (node.type === "group") { | ||||
|                     nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes)); | ||||
|                 } | ||||
|             } else { | ||||
|                 var convertedSubflow = convertSubflow(node); | ||||
|                 nns.push(convertedSubflow); | ||||
| @@ -732,6 +776,11 @@ RED.nodes = (function() { | ||||
|                 nns.push(convertSubflow(subflows[i], exportCredentials)); | ||||
|             } | ||||
|         } | ||||
|         for (i in groups) { | ||||
|             if (groups.hasOwnProperty(i)) { | ||||
|                 nns.push(convertNode(groups[i])); | ||||
|             } | ||||
|         } | ||||
|         for (i in configNodes) { | ||||
|             if (configNodes.hasOwnProperty(i)) { | ||||
|                 nns.push(convertNode(configNodes[i], exportCredentials)); | ||||
| @@ -858,6 +907,7 @@ RED.nodes = (function() { | ||||
|             if (n.type != "workspace" && | ||||
|                 n.type != "tab" && | ||||
|                 n.type != "subflow" && | ||||
|                 n.type != "group" && | ||||
|                 !registry.getNodeType(n.type) && | ||||
|                 n.type.substring(0,8) != "subflow:" && | ||||
|                 unknownTypes.indexOf(n.type)==-1) { | ||||
| @@ -907,6 +957,7 @@ RED.nodes = (function() { | ||||
|         var node_map = {}; | ||||
|         var new_nodes = []; | ||||
|         var new_links = []; | ||||
|         var new_groups = []; | ||||
|         var nid; | ||||
|         var def; | ||||
|         var configNode; | ||||
| @@ -1074,20 +1125,25 @@ RED.nodes = (function() { | ||||
|                         y:parseFloat(n.y || 0), | ||||
|                         z:n.z, | ||||
|                         type:0, | ||||
|                         wires:n.wires||[], | ||||
|                         inputLabels: n.inputLabels, | ||||
|                         outputLabels: n.outputLabels, | ||||
|                         icon: n.icon, | ||||
|                         info: n.info, | ||||
|                         changed:false, | ||||
|                         _config:{} | ||||
|                     }; | ||||
|                     } | ||||
|                     if (n.type !== "group") { | ||||
|                         node.wires = n.wires||[]; | ||||
|                         node.inputLabels = n.inputLabels; | ||||
|                         node.outputLabels = n.outputLabels; | ||||
|                         node.icon = n.icon; | ||||
|                     } | ||||
|                     if (n.hasOwnProperty('l')) { | ||||
|                         node.l = n.l; | ||||
|                     } | ||||
|                     if (n.hasOwnProperty('d')) { | ||||
|                         node.d = n.d; | ||||
|                     } | ||||
|                     if (n.hasOwnProperty('g')) { | ||||
|                         node.g = n.g; | ||||
|                     } | ||||
|                     if (createNewIds) { | ||||
|                         if (subflow_blacklist[n.z]) { | ||||
|                             continue; | ||||
| @@ -1124,7 +1180,17 @@ RED.nodes = (function() { | ||||
|                     } | ||||
|                     node.type = n.type; | ||||
|                     node._def = def; | ||||
|                     if (n.type.substring(0,7) === "subflow") { | ||||
|                     if (node.type === "group") { | ||||
|                         node._def = RED.group.def; | ||||
|                         for (d in node._def.defaults) { | ||||
|                             if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') { | ||||
|                                 node[d] = n[d]; | ||||
|                                 node._config[d] = JSON.stringify(n[d]); | ||||
|                             } | ||||
|                         } | ||||
|                         node._config.x = node.x; | ||||
|                         node._config.y = node.y; | ||||
|                     } else if (n.type.substring(0,7) === "subflow") { | ||||
|                         var parentId = n.type.split(":")[1]; | ||||
|                         var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId); | ||||
|                         if (createNewIds) { | ||||
| @@ -1214,13 +1280,19 @@ RED.nodes = (function() { | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     addNode(node); | ||||
|                     RED.editor.validateNode(node); | ||||
|                     if (node.type !== "group") { | ||||
|                         addNode(node); | ||||
|                         RED.editor.validateNode(node); | ||||
|                     } else { | ||||
|                         addGroup(node); | ||||
|                     } | ||||
|                     node_map[n.id] = node; | ||||
|                     // If an 'unknown' config node, it will not have been caught by the | ||||
|                     // proper config node handling, so needs adding to new_nodes here | ||||
|                     if (node.type === "unknown" || node._def.category !== "config") { | ||||
|                         new_nodes.push(node); | ||||
|                     } else if (node.type === "group") { | ||||
|                         new_groups.push(node); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| @@ -1255,6 +1327,11 @@ RED.nodes = (function() { | ||||
|                 } | ||||
|                 delete n.wires; | ||||
|             } | ||||
|             if (n.g && node_map[n.g]) { | ||||
|                 n.g = node_map[n.g].id; | ||||
|             } else { | ||||
|                 delete n.g | ||||
|             } | ||||
|             for (var d3 in n._def.defaults) { | ||||
|                 if (n._def.defaults.hasOwnProperty(d3)) { | ||||
|                     if (n._def.defaults[d3].type && node_map[n[d3]]) { | ||||
| @@ -1323,9 +1400,20 @@ RED.nodes = (function() { | ||||
|                 delete n.status.wires; | ||||
|             } | ||||
|         } | ||||
|         for (i=0;i<new_groups.length;i++) { | ||||
|             n = new_groups[i]; | ||||
|             if (n.g && node_map[n.g]) { | ||||
|                 n.g = node_map[n.g].id; | ||||
|             } else { | ||||
|                 delete n.g; | ||||
|             } | ||||
|             n.nodes = n.nodes.map(function(id) { | ||||
|                 return node_map[id]; | ||||
|             }) | ||||
|         } | ||||
|  | ||||
|         RED.workspaces.refresh(); | ||||
|         return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace]; | ||||
|         return [new_nodes,new_links,new_groups,new_workspaces,new_subflows,missingWorkspace]; | ||||
|     } | ||||
|  | ||||
|     // TODO: supports filter.z|type | ||||
| @@ -1416,6 +1504,9 @@ RED.nodes = (function() { | ||||
|         nodeTabMap = {}; | ||||
|         configNodes = {}; | ||||
|         workspacesOrder = []; | ||||
|         groups = {}; | ||||
|         groupsByZ = {}; | ||||
|  | ||||
|         var subflowIds = Object.keys(subflows); | ||||
|         subflowIds.forEach(function(id) { | ||||
|             RED.subflow.removeSubflow(id) | ||||
| @@ -1444,6 +1535,27 @@ RED.nodes = (function() { | ||||
|         // var loadedFlowVersion = null; | ||||
|     } | ||||
|  | ||||
|     function addGroup(group) { | ||||
|         groupsByZ[group.z] = groupsByZ[group.z] || []; | ||||
|         groupsByZ[group.z].push(group); | ||||
|         groups[group.id] = group; | ||||
|     } | ||||
|     function removeGroup(group) { | ||||
|         var i = groupsByZ[group.z].indexOf(group); | ||||
|         groupsByZ[group.z].splice(i,1); | ||||
|  | ||||
|         if (group.g) { | ||||
|             if (groups[group.g]) { | ||||
|                 var index = groups[group.g].nodes.indexOf(group); | ||||
|                 groups[group.g].nodes.splice(index,1); | ||||
|             } | ||||
|         } | ||||
|         RED.group.markDirty(group); | ||||
|  | ||||
|         delete groups[group.id]; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     return { | ||||
|         init: function() { | ||||
|             RED.events.on("registry:node-type-added",function(type) { | ||||
| @@ -1539,6 +1651,11 @@ RED.nodes = (function() { | ||||
|         subflow: getSubflow, | ||||
|         subflowContains: subflowContains, | ||||
|  | ||||
|         addGroup: addGroup, | ||||
|         removeGroup: removeGroup, | ||||
|         group: function(id) { return groups[id] }, | ||||
|         groups: function(z) { return groupsByZ[z]||[] }, | ||||
|  | ||||
|         eachNode: function(cb) { | ||||
|             for (var n=0;n<nodes.length;n++) { | ||||
|                 if (cb(nodes[n]) === false) { | ||||
|   | ||||
| @@ -431,7 +431,7 @@ var RED = (function() { | ||||
|             '<img width="50px" src="red/images/node-red-icon.svg" />'+ | ||||
|             '</div>'; | ||||
|  | ||||
|             RED.sidebar.info.set(aboutHeader+marked(data)); | ||||
|             RED.sidebar.info.set(aboutHeader+RED.utils.renderMarkdown(data)); | ||||
|             RED.sidebar.info.show(); | ||||
|         }); | ||||
|     } | ||||
| @@ -472,6 +472,14 @@ var RED = (function() { | ||||
|             {id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:"core:create-subflow"}, | ||||
|             {id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:"core:convert-to-subflow"}, | ||||
|         ]}); | ||||
|         menuOptions.push({id:"menu-item-group",label:RED._("menu.label.groups"), options: [ | ||||
|             {id:"menu-item-group-group",label:RED._("menu.label.groupSelection"),disabled:true,onselect:"core:group-selection"}, | ||||
|             {id:"menu-item-group-ungroup",label:RED._("menu.label.ungroupSelection"),disabled:true,onselect:"core:ungroup-selection"}, | ||||
|             null, | ||||
|             {id:"menu-item-group-merge",label:RED._("menu.label.groupMergeSelection"),disabled:true,onselect:"core:merge-selection-to-group"}, | ||||
|             {id:"menu-item-group-remove",label:RED._("menu.label.groupRemoveSelection"),disabled:true,onselect:"core:remove-selection-from-group"} | ||||
|         ]}); | ||||
|  | ||||
|         menuOptions.push(null); | ||||
|         if (RED.settings.theme('palette.editable') !== false) { | ||||
|             menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"}); | ||||
| @@ -524,6 +532,7 @@ var RED = (function() { | ||||
|         } | ||||
|  | ||||
|         RED.subflow.init(); | ||||
|         RED.group.init(); | ||||
|         RED.clipboard.init(); | ||||
|         RED.search.init(); | ||||
|         RED.actionList.init(); | ||||
|   | ||||
| @@ -583,6 +583,7 @@ RED.clipboard = (function() { | ||||
|                     nodes = []; | ||||
|                     selection.forEach(function(n) { | ||||
|                         nodes.push(n); | ||||
|                         nodes = nodes.concat(RED.nodes.groups(n.id)); | ||||
|                         nodes = nodes.concat(RED.nodes.filterNodes({z:n.id})); | ||||
|                     }); | ||||
|                 } else { | ||||
| @@ -592,7 +593,8 @@ RED.clipboard = (function() { | ||||
|                 nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'})); | ||||
|             } else if (type === 'red-ui-clipboard-dialog-export-rng-flow') { | ||||
|                 var activeWorkspace = RED.workspaces.active(); | ||||
|                 nodes = RED.nodes.filterNodes({z:activeWorkspace}); | ||||
|                 nodes = RED.nodes.groups(activeWorkspace); | ||||
|                 nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace})); | ||||
|                 var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace); | ||||
|                 nodes.unshift(parentNode); | ||||
|                 nodes = RED.nodes.createExportableNodeSet(nodes); | ||||
|   | ||||
							
								
								
									
										223
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,223 @@ | ||||
| RED.colorPicker = (function() { | ||||
|  | ||||
|     function getDarkerColor(c) { | ||||
|         var r,g,b; | ||||
|         if (/^#[a-f0-9]{6}$/i.test(c)) { | ||||
|             r = parseInt(c.substring(1, 3), 16); | ||||
|             g = parseInt(c.substring(3, 5), 16); | ||||
|             b = parseInt(c.substring(5, 7), 16); | ||||
|         } else if (/^#[a-f0-9]{3}$/i.test(c)) { | ||||
|             r = parseInt(c.substring(1, 2)+c.substring(1, 2), 16); | ||||
|             g = parseInt(c.substring(2, 3)+c.substring(2, 3), 16); | ||||
|             b = parseInt(c.substring(3, 4)+c.substring(3, 4), 16); | ||||
|         } else { | ||||
|             return c; | ||||
|         } | ||||
|         var l = 0.3 * r/255 + 0.59 * g/255 + 0.11 * b/255 ; | ||||
|         r = Math.max(0,r-50); | ||||
|         g = Math.max(0,g-50); | ||||
|         b = Math.max(0,b-50); | ||||
|         return '#'+((r<<16) + (g<<8) + b).toString(16).padStart(6,'0') | ||||
|     } | ||||
|  | ||||
|     function create(options) { | ||||
|         var color = options.value; | ||||
|         var id = options.id; | ||||
|         var colorPalette = options.palette || []; | ||||
|         var width = options.cellWidth || 30; | ||||
|         var height = options.cellHeight || 30; | ||||
|         var margin = options.cellMargin || 2; | ||||
|         var perRow = options.cellPerRow || 6; | ||||
|  | ||||
|         var container = $("<div>",{style:"display:inline-block"}); | ||||
|         var colorHiddenInput = $("<input/>", { id: id, type: "hidden", value: color }).appendTo(container); | ||||
|         var opacityHiddenInput = $("<input/>", { id: id+"-opacity", type: "hidden", value: options.hasOwnProperty('opacity')?options.opacity:"1" }).appendTo(container); | ||||
|  | ||||
|         var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container); | ||||
|         $('<i class="fa fa-caret-down"></i>').appendTo(colorButton); | ||||
|  | ||||
|         var colorDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton); | ||||
|         $('<div>',{class:"red-ui-color-picker-cell-none"}).appendTo(colorDispContainer); | ||||
|         var colorDisp = $('<div>',{class:"red-ui-color-picker-swatch"}).appendTo(colorDispContainer); | ||||
|  | ||||
|  | ||||
|         var refreshDisplay = function(color) { | ||||
|             if (color === "none") { | ||||
|                 colorDisp.addClass('red-ui-color-picker-cell-none').css({ | ||||
|                     "background-color": "", | ||||
|                     opacity: 1 | ||||
|                 }); | ||||
|                 colorDispContainer.css({ | ||||
|                     "border-color":"" | ||||
|                 }) | ||||
|             } else { | ||||
|                 var opacity = parseFloat(opacityHiddenInput.val()) | ||||
|                 colorDisp.removeClass('red-ui-color-picker-cell-none').css({ | ||||
|                     "background-color": color, | ||||
|                     "opacity": opacity | ||||
|                 }); | ||||
|                 var border = getDarkerColor(color); | ||||
|                 if (border[0] === '#') { | ||||
|                     border += Math.round(255*Math.floor(opacity*100)/100).toString(16); | ||||
|                 } else { | ||||
|                     border = ""; | ||||
|                 } | ||||
|  | ||||
|                 colorDispContainer.css({ | ||||
|                     "border-color": border | ||||
|                 }) | ||||
|             } | ||||
|             if (options.hasOwnProperty('opacity')) { | ||||
|                 $(".red-ui-color-picker-opacity-slider-overlay").css({ | ||||
|                     "background-image": "linear-gradient(90deg, transparent 0%, "+color+" 100%)" | ||||
|                 }) | ||||
|             } | ||||
|  | ||||
|  | ||||
|         } | ||||
|  | ||||
|         colorButton.on("click", function (e) { | ||||
|             var numColors = colorPalette.length; | ||||
|  | ||||
|             var picker = $("<div/>", { | ||||
|                 class: "red-ui-color-picker" | ||||
|             }).css({ | ||||
|                 width: ((width+margin+margin)*perRow)+"px", | ||||
|                 height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px" | ||||
|             }); | ||||
|             var count = 0; | ||||
|             var row = null; | ||||
|             row = $("<div/>").appendTo(picker); | ||||
|  | ||||
|             var colorInput = $('<input>',{ | ||||
|                 type:"text", | ||||
|                 value:colorHiddenInput.val() | ||||
|             }).appendTo(row); | ||||
|  | ||||
|             colorInput.on("change", function (e) { | ||||
|                 var color = colorInput.val(); | ||||
|                 colorHiddenInput.val(color).trigger('change'); | ||||
|                 refreshDisplay(color); | ||||
|             }); | ||||
|             // if (options.hasOwnProperty('opacity')) { | ||||
|             //     var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider" | ||||
|             // } | ||||
|  | ||||
|             if (options.none) { | ||||
|                 row = $("<div/>").appendTo(picker); | ||||
|                 var button = $("<button/>", { | ||||
|                     class:"red-ui-color-picker-cell red-ui-color-picker-cell-none" | ||||
|                 }).css({ | ||||
|                     width: width+"px", | ||||
|                     height: height+"px", | ||||
|                     margin: margin+"px" | ||||
|                 }).appendTo(row); | ||||
|                 button.on("click",  function (e) { | ||||
|                     e.preventDefault(); | ||||
|                     colorInput.val("none"); | ||||
|                     colorInput.trigger("change"); | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|  | ||||
|             colorPalette.forEach(function (col) { | ||||
|                 if ((count % perRow) == 0) { | ||||
|                     row = $("<div/>").appendTo(picker); | ||||
|                 } | ||||
|                 var button = $("<button/>", { | ||||
|                     class:"red-ui-color-picker-cell" | ||||
|                 }).css({ | ||||
|                     width: width+"px", | ||||
|                     height: height+"px", | ||||
|                     margin: margin+"px", | ||||
|                     backgroundColor: col, | ||||
|                     "border-color": getDarkerColor(col) | ||||
|                 }).appendTo(row); | ||||
|                 button.on("click",  function (e) { | ||||
|                     e.preventDefault(); | ||||
|                     // colorPanel.hide(); | ||||
|                     colorInput.val(col); | ||||
|                     colorInput.trigger("change"); | ||||
|                 }); | ||||
|                 count++; | ||||
|             }); | ||||
|             if (options.none || options.hasOwnProperty('opacity')) { | ||||
|                 row = $("<div/>").appendTo(picker); | ||||
|                 // if (options.none) { | ||||
|                 //     var button = $("<button/>", { | ||||
|                 //         class:"red-ui-color-picker-cell red-ui-color-picker-cell-none" | ||||
|                 //     }).css({ | ||||
|                 //         width: width+"px", | ||||
|                 //         height: height+"px", | ||||
|                 //         margin: margin+"px" | ||||
|                 //     }).appendTo(row); | ||||
|                 //     button.on("click",  function (e) { | ||||
|                 //         e.preventDefault(); | ||||
|                 //         colorPanel.hide(); | ||||
|                 //         selector.val("none"); | ||||
|                 //         selector.trigger("change"); | ||||
|                 //     }); | ||||
|                 // } | ||||
|                 if (options.hasOwnProperty('opacity')) { | ||||
|                     var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider"}).appendTo(row); | ||||
|                     sliderContainer.on("mousedown", function(evt) { | ||||
|                         if (evt.target === sliderHandle[0]) { | ||||
|                             return; | ||||
|                         } | ||||
|                         var v = evt.offsetX/sliderContainer.width(); | ||||
|                         sliderHandle.css({ | ||||
|                             left: ( v*(sliderContainer.width() - sliderHandle.outerWidth()))+"px" | ||||
|                         }); | ||||
|                         v = Math.floor(100*v) | ||||
|                         opacityHiddenInput.val(v/100) | ||||
|                         opacityLabel.text(v+"%"); | ||||
|                         refreshDisplay(colorHiddenInput.val()); | ||||
|                     }) | ||||
|                      $("<div>",{class:"red-ui-color-picker-opacity-slider-overlay"}).appendTo(sliderContainer); | ||||
|                     var sliderHandle = $("<div>",{class:"red-ui-color-picker-opacity-slider-handle red-ui-button red-ui-button-small"}).appendTo(sliderContainer).draggable({ | ||||
|                         containment: "parent", | ||||
|                         axis: "x", | ||||
|                         drag: function( event, ui ) { | ||||
|                             var v = Math.max(0,ui.position.left/($(this).parent().width()-$(this).outerWidth())); | ||||
|                             // Odd bug that if it is loaded with a non-0 value, the first time | ||||
|                             // it is dragged it ranges -1 to 99. But every other time, its 0 to 100. | ||||
|                             // The Math.max above makes the -1 disappear. The follow hack ensures | ||||
|                             // it always maxes out at a 100, at the cost of not allowing 99% exactly. | ||||
|                             v = Math.floor(100*v) | ||||
|                             if ( v === 99 ) { | ||||
|                                 v = 100; | ||||
|                             } | ||||
|                             // console.log("uip",ui.position.left); | ||||
|                             opacityHiddenInput.val(v/100) | ||||
|                             opacityLabel.text(v+"%"); | ||||
|                             refreshDisplay(colorHiddenInput.val()); | ||||
|                         } | ||||
|                     }); | ||||
|                     var opacityLabel = $('<small></small>').appendTo(row); | ||||
|                     setTimeout(function() { | ||||
|                         sliderHandle.css({ | ||||
|                             left: (parseFloat(opacityHiddenInput.val())*(sliderContainer.width() - sliderHandle.outerWidth()))+"px" | ||||
|                         }) | ||||
|                         opacityLabel.text(Math.floor(opacityHiddenInput.val()*100)+"%"); | ||||
|                     },50); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             var colorPanel = RED.popover.panel(picker); | ||||
|             setTimeout(function() { | ||||
|                 refreshDisplay(colorHiddenInput.val()) | ||||
|             },50); | ||||
|             colorPanel.show({ | ||||
|                 target: colorButton | ||||
|             }) | ||||
|         }); | ||||
|         setTimeout(function() { | ||||
|             refreshDisplay(colorHiddenInput.val()) | ||||
|         },50); | ||||
|         return container; | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         create: create | ||||
|     } | ||||
| })(); | ||||
| @@ -38,7 +38,10 @@ | ||||
|             this.element.addClass("red-ui-searchBox-input"); | ||||
|             this.uiContainer = this.element.wrap("<div>").parent(); | ||||
|             this.uiContainer.addClass("red-ui-searchBox-container"); | ||||
|  | ||||
|             if (this.element.parents("form").length === 0) { | ||||
|                 var form = this.element.wrap("<form>").parent(); | ||||
|                 form.addClass("red-ui-searchBox-form"); | ||||
|             } | ||||
|             $('<i class="fa fa-search"></i>').prependTo(this.uiContainer); | ||||
|             this.clearButton = $('<a href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer); | ||||
|             this.clearButton.on("click",function(e) { | ||||
|   | ||||
| @@ -514,7 +514,9 @@ RED.editor = (function() { | ||||
|         for (var i=editStack.length-1;i<editStack.length;i++) { | ||||
|             var node = editStack[i]; | ||||
|             label = node.type; | ||||
|             if (node.type === '_expression') { | ||||
|             if (node.type === 'group') { | ||||
|                 label = RED._("group.editGroup",{name:RED.utils.sanitize(node.name||node.id)}); | ||||
|             } else if (node.type === '_expression') { | ||||
|                 label = RED._("expressionEditor.title"); | ||||
|             } else if (node.type === '_js') { | ||||
|                 label = RED._("jsEditor.title"); | ||||
| @@ -588,8 +590,8 @@ RED.editor = (function() { | ||||
|         // cases, and also prevent browser auto-fill of password | ||||
|         //  - the elements cannot be hidden otherwise Chrome will ignore them. | ||||
|         //  - the elements need to have id's that imply password/username | ||||
|         $('<div style="position: absolute; top: -2000px;"><input id="red-ui-trap-password" type="password"/></div>').prependTo(dialogForm); | ||||
|         $('<div style="position: absolute; top: -2000px;"><input id="red-ui-trap-username"  type="text"/></div>').prependTo(dialogForm); | ||||
|         $('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-password" type="password"/></span>').prependTo(dialogForm); | ||||
|         $('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-username"  type="text"/></span>').prependTo(dialogForm); | ||||
|         dialogForm.on("submit", function(e) { e.preventDefault();}); | ||||
|         dialogForm.find('input').attr("autocomplete","off"); | ||||
|         return dialogForm; | ||||
| @@ -823,99 +825,6 @@ RED.editor = (function() { | ||||
|         searchInput.trigger("focus"); | ||||
|     } | ||||
|  | ||||
|     function createColorPicker(colorRow, color) { | ||||
|  | ||||
|         var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(colorRow); | ||||
|         $('<i class="fa fa-caret-down"></i>').appendTo(colorButton); | ||||
|  | ||||
|         var colorDisp = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton); | ||||
|  | ||||
|         var selector = $("<input/>", { | ||||
|             id: "red-ui-editor-node-color", | ||||
|             type: "text", | ||||
|             value: color | ||||
|         }).css({ | ||||
|             marginLeft: "10px", | ||||
|             width: "150px", | ||||
|         }).appendTo(colorRow); | ||||
|  | ||||
|         selector.on("change", function (e) { | ||||
|             var color = selector.val(); | ||||
|             $(".red-ui-editor-node-appearance-button .red-ui-search-result-node").css({ | ||||
|                 "background-color": color | ||||
|             }); | ||||
|         }); | ||||
|         selector.trigger("change"); | ||||
|         colorButton.on("click", function (e) { | ||||
|             var recommendedColors = [ | ||||
|                 "#DDAA99", | ||||
|                 "#3FADB5", "#87A980", "#A6BBCF", | ||||
|                 "#AAAA66", "#C0C0C0", "#C0DEED", | ||||
|                 "#C7E9C0", "#D7D7A0", "#D8BFD8", | ||||
|                 "#DAC4B4", "#DEB887", "#DEBD5C", | ||||
|                 "#E2D96E", "#E6E0F8", "#E7E7AE", | ||||
|                 "#E9967A", "#F3B567", "#FDD0A2", | ||||
|                 "#FDF0C2", "#FFAAAA", "#FFCC66", | ||||
|                 "#FFF0F0", "#FFFFFF" | ||||
|             ].map(function(c) { | ||||
|                 var r = parseInt(c.substring(1, 3), 16) / 255; | ||||
|                 var g = parseInt(c.substring(3, 5), 16) / 255; | ||||
|                 var b = parseInt(c.substring(5, 7), 16) / 255; | ||||
|                 return { | ||||
|                     hex: c, | ||||
|                     r: r, | ||||
|                     g: g, | ||||
|                     b: b, | ||||
|                     l: 0.3 * r + 0.59 * g + 0.11 * b | ||||
|                 } | ||||
|             }); | ||||
|             // Sort by luminosity. | ||||
|             recommendedColors.sort(function (a, b) { | ||||
|                 return a.l - b.l; | ||||
|             }); | ||||
|  | ||||
|             var numColors = recommendedColors.length; | ||||
|             var width = 30; | ||||
|             var height = 30; | ||||
|             var margin = 2; | ||||
|             var perRow = 6; | ||||
|             var picker = $("<div/>", { | ||||
|                 class: "red-ui-color-picker" | ||||
|             }).css({ | ||||
|                 width: ((width+margin+margin)*perRow)+"px", | ||||
|                 height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px" | ||||
|             }); | ||||
|             var count = 0; | ||||
|             var row = null; | ||||
|             recommendedColors.forEach(function (col) { | ||||
|                 if ((count % perRow) == 0) { | ||||
|                     row = $("<div/>").appendTo(picker); | ||||
|                 } | ||||
|                 var button = $("<button/>", { | ||||
|                 }).css({ | ||||
|                     width: width+"px", | ||||
|                     height: height+"px", | ||||
|                     margin: margin+"px", | ||||
|                     backgroundColor: col.hex, | ||||
|                     "border-style": "solid", | ||||
|                     "border-width": "1px", | ||||
|                     "border-color": col.luma<0.92?col.hex:'#ccc' | ||||
|                 }).appendTo(row); | ||||
|                 button.on("click",  function (e) { | ||||
|                     e.preventDefault(); | ||||
|                     colorPanel.hide(); | ||||
|                     selector.val(col.hex); | ||||
|                     selector.trigger("change"); | ||||
|                 }); | ||||
|                 count++; | ||||
|             }); | ||||
|             var colorPanel = RED.popover.panel(picker); | ||||
|             colorPanel.show({ | ||||
|                 target: colorButton | ||||
|             }) | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function buildAppearanceForm(container,node) { | ||||
|         var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container); | ||||
|  | ||||
| @@ -1001,7 +910,30 @@ RED.editor = (function() { | ||||
|                 class: "form-row" | ||||
|             }).appendTo(dialogForm); | ||||
|             $("<label/>").text(RED._("editor.color")).appendTo(colorRow); | ||||
|             createColorPicker(colorRow, color); | ||||
|  | ||||
|             var recommendedColors = [ | ||||
|                 "#DDAA99", | ||||
|                 "#3FADB5", "#87A980", "#A6BBCF", | ||||
|                 "#AAAA66", "#C0C0C0", "#C0DEED", | ||||
|                 "#C7E9C0", "#D7D7A0", "#D8BFD8", | ||||
|                 "#DAC4B4", "#DEB887", "#DEBD5C", | ||||
|                 "#E2D96E", "#E6E0F8", "#E7E7AE", | ||||
|                 "#E9967A", "#F3B567", "#FDD0A2", | ||||
|                 "#FDF0C2", "#FFAAAA", "#FFCC66", | ||||
|                 "#FFF0F0", "#FFFFFF" | ||||
|             ] | ||||
|  | ||||
|             RED.colorPicker.create({ | ||||
|                 id: "red-ui-editor-node-color", | ||||
|                 value: color, | ||||
|                 palette: recommendedColors, | ||||
|                 sortPalette: function (a, b) {return a.l - b.l;} | ||||
|             }).appendTo(colorRow); | ||||
|  | ||||
|             $("#red-ui-editor-node-color").on('change', function(ev) { | ||||
|                 // Horribly out of scope... | ||||
|                 nodeDiv.css('backgroundColor',$(this).val()); | ||||
|             }) | ||||
|         } | ||||
|  | ||||
|  | ||||
| @@ -2454,6 +2386,249 @@ RED.editor = (function() { | ||||
|         RED.tray.show(trayOptions); | ||||
|     } | ||||
|  | ||||
|     function showEditGroupDialog(group) { | ||||
|         var editing_node = group; | ||||
|         editStack.push(group); | ||||
|         RED.view.state(RED.state.EDITING); | ||||
|         var nodeInfoEditor; | ||||
|         var finishedBuilding = false; | ||||
|         var trayOptions = { | ||||
|             title: getEditStackTitle(), | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     id: "node-dialog-cancel", | ||||
|                     text: RED._("common.label.cancel"), | ||||
|                     click: function() { | ||||
|                         RED.tray.close(); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     id: "node-dialog-ok", | ||||
|                     class: "primary", | ||||
|                     text: RED._("common.label.done"), | ||||
|                     click: function() { | ||||
|                         var changes = {}; | ||||
|                         var changed = false; | ||||
|                         var wasDirty = RED.nodes.dirty(); | ||||
|                         var d; | ||||
|                         var outputMap; | ||||
|  | ||||
|                         if (editing_node._def.oneditsave) { | ||||
|                             var oldValues = {}; | ||||
|                             for (d in editing_node._def.defaults) { | ||||
|                                 if (editing_node._def.defaults.hasOwnProperty(d)) { | ||||
|                                     if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") { | ||||
|                                         oldValues[d] = editing_node[d]; | ||||
|                                     } else { | ||||
|                                         oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v; | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                             try { | ||||
|                                 var rc = editing_node._def.oneditsave.call(editing_node); | ||||
|                                 if (rc === true) { | ||||
|                                     changed = true; | ||||
|                                 } | ||||
|                             } catch(err) { | ||||
|                                 console.log("oneditsave",editing_node.id,editing_node.type,err.toString()); | ||||
|                             } | ||||
|  | ||||
|                             for (d in editing_node._def.defaults) { | ||||
|                                 if (editing_node._def.defaults.hasOwnProperty(d)) { | ||||
|                                     if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") { | ||||
|                                         if (oldValues[d] !== editing_node[d]) { | ||||
|                                             changes[d] = oldValues[d]; | ||||
|                                             changed = true; | ||||
|                                         } | ||||
|                                     } else { | ||||
|                                         if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) { | ||||
|                                             changes[d] = oldValues[d]; | ||||
|                                             changed = true; | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                         var newValue; | ||||
|                         if (editing_node._def.defaults) { | ||||
|                             for (d in editing_node._def.defaults) { | ||||
|                                 if (editing_node._def.defaults.hasOwnProperty(d)) { | ||||
|                                     var input = $("#node-input-"+d); | ||||
|                                     if (input.attr('type') === "checkbox") { | ||||
|                                         newValue = input.prop('checked'); | ||||
|                                     } else if (input.prop("nodeName") === "select" && input.attr("multiple") === "multiple") { | ||||
|                                         // An empty select-multiple box returns null. | ||||
|                                         // Need to treat that as an empty array. | ||||
|                                         newValue = input.val(); | ||||
|                                         if (newValue == null) { | ||||
|                                             newValue = []; | ||||
|                                         } | ||||
|                                     } else if ("format" in editing_node._def.defaults[d] && editing_node._def.defaults[d].format !== "" && input[0].nodeName === "DIV") { | ||||
|                                         newValue = input.text(); | ||||
|                                     } else { | ||||
|                                         newValue = input.val(); | ||||
|                                     } | ||||
|                                     if (newValue != null) { | ||||
|                                         if (editing_node._def.defaults[d].type) { | ||||
|                                             if (newValue == "_ADD_") { | ||||
|                                                 newValue = ""; | ||||
|                                             } | ||||
|                                         } | ||||
|                                         if (editing_node[d] != newValue) { | ||||
|                                             if (editing_node._def.defaults[d].type) { | ||||
|                                                 // Change to a related config node | ||||
|                                                 var configNode = RED.nodes.node(editing_node[d]); | ||||
|                                                 if (configNode) { | ||||
|                                                     var users = configNode.users; | ||||
|                                                     users.splice(users.indexOf(editing_node),1); | ||||
|                                                 } | ||||
|                                                 configNode = RED.nodes.node(newValue); | ||||
|                                                 if (configNode) { | ||||
|                                                     configNode.users.push(editing_node); | ||||
|                                                 } | ||||
|                                             } | ||||
|                                             changes[d] = editing_node[d]; | ||||
|                                             editing_node[d] = newValue; | ||||
|                                             changed = true; | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                         var oldInfo = editing_node.info; | ||||
|                         if (nodeInfoEditor) { | ||||
|                             var newInfo = nodeInfoEditor.getValue(); | ||||
|                             if (!!oldInfo) { | ||||
|                                 // Has existing info property | ||||
|                                 if (newInfo.trim() === "") { | ||||
|                                     // New value is blank - remove the property | ||||
|                                     changed = true; | ||||
|                                     changes.info = oldInfo; | ||||
|                                     delete editing_node.info; | ||||
|                                 } else if (newInfo !== oldInfo) { | ||||
|                                     // New value is different | ||||
|                                     changed = true; | ||||
|                                     changes.info = oldInfo; | ||||
|                                     editing_node.info = newInfo; | ||||
|                                 } | ||||
|                             } else { | ||||
|                                 // No existing info | ||||
|                                 if (newInfo.trim() !== "") { | ||||
|                                     // New value is not blank | ||||
|                                     changed = true; | ||||
|                                     changes.info = undefined; | ||||
|                                     editing_node.info = newInfo; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         if (changed) { | ||||
|                             var wasChanged = editing_node.changed; | ||||
|                             editing_node.changed = true; | ||||
|                             RED.nodes.dirty(true); | ||||
|                             var historyEvent = { | ||||
|                                 t:'edit', | ||||
|                                 node:editing_node, | ||||
|                                 changes:changes, | ||||
|                                 dirty:wasDirty, | ||||
|                                 changed:wasChanged | ||||
|                             }; | ||||
|                             RED.history.push(historyEvent); | ||||
|                         } | ||||
|                         editing_node.dirty = true; | ||||
|                         RED.tray.close(); | ||||
|                         RED.view.redraw(true); | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             resize: function(size) { | ||||
|                 editTrayWidthCache['group'] = size.width; | ||||
|                 $(".red-ui-tray-content").height(size.height - 50); | ||||
|                 // var form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40); | ||||
|                 // if (editing_node && editing_node._def.oneditresize) { | ||||
|                 //     try { | ||||
|                 //         editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()}); | ||||
|                 //     } catch(err) { | ||||
|                 //         console.log("oneditresize",editing_node.id,editing_node.type,err.toString()); | ||||
|                 //     } | ||||
|                 // } | ||||
|             }, | ||||
|             open: function(tray, done) { | ||||
|                 var trayFooter = tray.find(".red-ui-tray-footer"); | ||||
|                 var trayFooterLeft = $("<div/>", { | ||||
|                     class: "red-ui-tray-footer-left" | ||||
|                 }).appendTo(trayFooter) | ||||
|                 var trayBody = tray.find('.red-ui-tray-body'); | ||||
|                 trayBody.parent().css('overflow','hidden'); | ||||
|  | ||||
|                 var editorTabEl = $('<ul></ul>').appendTo(trayBody); | ||||
|                 var editorContent = $('<div></div>').appendTo(trayBody); | ||||
|  | ||||
|                 var editorTabs = RED.tabs.create({ | ||||
|                     element:editorTabEl, | ||||
|                     onchange:function(tab) { | ||||
|                         editorContent.children().hide(); | ||||
|                         if (tab.onchange) { | ||||
|                             tab.onchange.call(tab); | ||||
|                         } | ||||
|                         tab.content.show(); | ||||
|                         if (finishedBuilding) { | ||||
|                             RED.tray.resize(); | ||||
|                         } | ||||
|                     }, | ||||
|                     collapsible: true, | ||||
|                     menu: false | ||||
|                 }); | ||||
|  | ||||
|                 var nodePropertiesTab = { | ||||
|                     id: "editor-tab-properties", | ||||
|                     label: RED._("editor-tab.properties"), | ||||
|                     name: RED._("editor-tab.properties"), | ||||
|                     content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(), | ||||
|                     iconClass: "fa fa-cog" | ||||
|                 }; | ||||
|                 buildEditForm(nodePropertiesTab.content,"dialog-form","group","node-red",group); | ||||
|  | ||||
|                 editorTabs.addTab(nodePropertiesTab); | ||||
|  | ||||
|                 var descriptionTab = { | ||||
|                     id: "editor-tab-description", | ||||
|                     label: RED._("editor-tab.description"), | ||||
|                     name: RED._("editor-tab.description"), | ||||
|                     content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(), | ||||
|                     iconClass: "fa fa-file-text-o", | ||||
|                     onchange: function() { | ||||
|                         nodeInfoEditor.focus(); | ||||
|                     } | ||||
|                 }; | ||||
|                 editorTabs.addTab(descriptionTab); | ||||
|                 nodeInfoEditor = buildDescriptionForm(descriptionTab.content,editing_node); | ||||
|                 prepareEditDialog(group,group._def,"node-input", function() { | ||||
|                     trayBody.i18n(); | ||||
|                     finishedBuilding = true; | ||||
|                     done(); | ||||
|                 }); | ||||
|             }, | ||||
|             close: function() { | ||||
|                 if (RED.view.state() != RED.state.IMPORT_DRAGGING) { | ||||
|                     RED.view.state(RED.state.DEFAULT); | ||||
|                 } | ||||
|                 nodeInfoEditor.destroy(); | ||||
|                 nodeInfoEditor = null; | ||||
|                 editStack.pop(); | ||||
|                 editing_node = null; | ||||
|             }, | ||||
|             show: function() { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (editTrayWidthCache.hasOwnProperty('group')) { | ||||
|             trayOptions.width = editTrayWidthCache['group']; | ||||
|         } | ||||
|         RED.tray.show(trayOptions); | ||||
|     } | ||||
|  | ||||
|     function showTypeEditor(type, options) { | ||||
|         if (customEditTypes.hasOwnProperty(type)) { | ||||
|             if (editStack.length > 0) { | ||||
| @@ -2577,6 +2752,7 @@ RED.editor = (function() { | ||||
|         edit: showEditDialog, | ||||
|         editConfig: showEditConfigNodeDialog, | ||||
|         editSubflow: showEditSubflowDialog, | ||||
|         editGroup: showEditGroupDialog, | ||||
|         editJavaScript: function(options) { showTypeEditor("_js",options) }, | ||||
|         editExpression: function(options) { showTypeEditor("_expression", options) }, | ||||
|         editJSON: function(options) { showTypeEditor("_json", options) }, | ||||
|   | ||||
| @@ -102,7 +102,7 @@ | ||||
|                         var f = $(this).val(); | ||||
|                         var args = RED._('jsonata:'+f+".args",{defaultValue:''}); | ||||
|                         var title = "<h5>"+f+"("+args+")</h5>"; | ||||
|                         var body = marked(RED._('jsonata:'+f+'.desc',{defaultValue:''})); | ||||
|                         var body = RED.utils.renderMarkdown(RED._('jsonata:'+f+'.desc',{defaultValue:''})); | ||||
|                         $("#red-ui-editor-type-expression-help").html(title+"<p>"+body+"</p>"); | ||||
|  | ||||
|                     }) | ||||
|   | ||||
| @@ -107,7 +107,7 @@ | ||||
|                         clearTimeout(changeTimer); | ||||
|                         changeTimer = setTimeout(function() { | ||||
|                             var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop(); | ||||
|                             $(".red-ui-editor-type-markdown-panel-preview").html(marked(expressionEditor.getValue())); | ||||
|                             $(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue())); | ||||
|                             $(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop); | ||||
|                         },200); | ||||
|                     }) | ||||
| @@ -116,7 +116,7 @@ | ||||
|                     } | ||||
|  | ||||
|                     if (value) { | ||||
|                         $(".red-ui-editor-type-markdown-panel-preview").html(marked(expressionEditor.getValue())); | ||||
|                         $(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue())); | ||||
|                     } | ||||
|                     panels = RED.panels.create({ | ||||
|                         id:"red-ui-editor-type-markdown-panels", | ||||
|   | ||||
							
								
								
									
										633
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/group.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										633
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/group.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,633 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| RED.group = (function() { | ||||
|  | ||||
|     var _groupEditTemplate = '<script type="text/x-red" data-template-name="group">'+ | ||||
|         '<div class="form-row">'+ | ||||
|             '<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+ | ||||
|             '<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">'+ | ||||
|         '</div>'+ | ||||
|  | ||||
|         // '<div class="node-input-group-style-tools"><span class="button-group"><button class="red-ui-button red-ui-button-small">Use default style</button><button class="red-ui-button red-ui-button-small">Set as default style</button></span></div>'+ | ||||
|  | ||||
|         '<div class="form-row" id="node-input-row-style-stroke">'+ | ||||
|             '<label>Style</label>'+ | ||||
|             '<label style="width: 70px;margin-right:10px" for="node-input-style-stroke" data-i18n="editor:common.label.line"></label>'+ | ||||
|         '</div>'+ | ||||
|         '<div class="form-row" style="padding-left: 100px;" id="node-input-row-style-fill">'+ | ||||
|             '<label style="width: 70px;margin-right: 10px "  for="node-input-style-fill" data-i18n="editor:common.label.fill"></label>'+ | ||||
|         '</div>'+ | ||||
|         '<div class="form-row">'+ | ||||
|             '<label for="node-input-style-label">Label</label>'+ | ||||
|             '<input type="checkbox" id="node-input-style-label"/>'+ | ||||
|         '</div>'+ | ||||
|         '<div class="form-row" id="node-input-row-style-label-options">'+ | ||||
|             '<div style="margin-left: 100px; display: inline-block">'+ | ||||
|                 '<div class="form-row">'+ | ||||
|                     '<span style="display: inline-block; min-width: 140px"  id="node-input-row-style-label-color">'+ | ||||
|                         '<label style="width: 70px;margin-right: 10px" for="node-input-style-fill" data-i18n="editor:common.label.color"></label>'+ | ||||
|                     '</span>'+ | ||||
|                 '</div>'+ | ||||
|                 '<div class="form-row">'+ | ||||
|                     '<span style="display: inline-block; min-width: 140px;" id="node-input-row-style-label-position">'+ | ||||
|                         '<label style="width: 70px;margin-right: 10px " for="node-input-style-label-position" data-i18n="editor:common.label.position"></label>'+ | ||||
|                     '</span>'+ | ||||
|                 '</div>'+ | ||||
|             '</div>'+ | ||||
|         '</div>'+ | ||||
|  | ||||
|         '</script>'; | ||||
|  | ||||
|     var colorPalette = [ | ||||
|         "#ff0000", | ||||
|         "#ffC000", | ||||
|         "#ffff00", | ||||
|         "#92d04f", | ||||
|         "#0070c0", | ||||
|         "#001f60", | ||||
|         "#6f2fa0", | ||||
|         "#000000", | ||||
|         "#777777" | ||||
|     ] | ||||
|     var colorSteps = 3; | ||||
|     var colorCount = colorPalette.length; | ||||
|     for (var i=0,len=colorPalette.length*colorSteps;i<len;i++) { | ||||
|         var ci = i%colorCount; | ||||
|         var j = Math.floor(i/colorCount)+1; | ||||
|         var c = colorPalette[ci]; | ||||
|         var r = parseInt(c.substring(1, 3), 16); | ||||
|         var g = parseInt(c.substring(3, 5), 16); | ||||
|         var b = parseInt(c.substring(5, 7), 16); | ||||
|         var dr = (255-r)/(colorSteps+((ci===colorCount-1) ?0:1)); | ||||
|         var dg = (255-g)/(colorSteps+((ci===colorCount-1) ?0:1)); | ||||
|         var db = (255-b)/(colorSteps+((ci===colorCount-1) ?0:1)); | ||||
|         r = Math.min(255,Math.floor(r+j*dr)); | ||||
|         g = Math.min(255,Math.floor(g+j*dg)); | ||||
|         b = Math.min(255,Math.floor(b+j*db)); | ||||
|         colorPalette.push('#'+((r<<16) + (g<<8) + b).toString(16).padStart(6,'0')); | ||||
|     } | ||||
|  | ||||
|     var defaultGroupStyle = {}; | ||||
|  | ||||
|     var groupDef = { | ||||
|         defaults:{ | ||||
|             name:{value:""}, | ||||
|             style:{value:{}}, | ||||
|             nodes:{value:[]} | ||||
|         }, | ||||
|         category: "config", | ||||
|         oneditprepare: function() { | ||||
|             var style = this.style || {}; | ||||
|             RED.colorPicker.create({ | ||||
|                 id:"node-input-style-stroke", | ||||
|                 value: style.stroke || "#a4a4a4", | ||||
|                 palette: colorPalette, | ||||
|                 cellPerRow: colorCount, | ||||
|                 cellWidth: 16, | ||||
|                 cellHeight: 16, | ||||
|                 cellMargin: 3, | ||||
|                 none: true, | ||||
|                 opacity: style['stroke-opacity'] || 1.0 | ||||
|             }).appendTo("#node-input-row-style-stroke"); | ||||
|             RED.colorPicker.create({ | ||||
|                 id:"node-input-style-fill", | ||||
|                 value: style.fill || "none", | ||||
|                 palette: colorPalette, | ||||
|                 cellPerRow: colorCount, | ||||
|                 cellWidth: 16, | ||||
|                 cellHeight: 16, | ||||
|                 cellMargin: 3, | ||||
|                 none: true, | ||||
|                 opacity: style['fill-opacity'] || 1.0 | ||||
|             }).appendTo("#node-input-row-style-fill"); | ||||
|  | ||||
|             createLayoutPicker({ | ||||
|                 id:"node-input-style-label-position", | ||||
|                 value:style["label-position"] || "nw" | ||||
|             }).appendTo("#node-input-row-style-label-position"); | ||||
|  | ||||
|             RED.colorPicker.create({ | ||||
|                 id:"node-input-style-color", | ||||
|                 value: style.color || "#a4a4a4", | ||||
|                 palette: colorPalette, | ||||
|                 cellPerRow: colorCount, | ||||
|                 cellWidth: 16, | ||||
|                 cellHeight: 16, | ||||
|                 cellMargin: 3 | ||||
|             }).appendTo("#node-input-row-style-label-color"); | ||||
|  | ||||
|             $("#node-input-style-label").toggleButton({ | ||||
|                 enabledLabel: RED._("editor.show"), | ||||
|                 disabledLabel: RED._("editor.hide") | ||||
|             }) | ||||
|  | ||||
|  | ||||
|             $("#node-input-style-label").on("change", function(evt) { | ||||
|                 $("#node-input-row-style-label-options").toggle($(this).prop("checked")); | ||||
|             }) | ||||
|             $("#node-input-style-label").prop("checked", this.style.label) | ||||
|             $("#node-input-style-label").trigger("change"); | ||||
|  | ||||
|         }, | ||||
|         oneditresize: function(size) { | ||||
|         }, | ||||
|         oneditsave: function() { | ||||
|             this.style.stroke = $("#node-input-style-stroke").val(); | ||||
|             this.style.fill = $("#node-input-style-fill").val(); | ||||
|             this.style["stroke-opacity"] = $("#node-input-style-stroke-opacity").val(); | ||||
|             this.style["fill-opacity"] = $("#node-input-style-fill-opacity").val(); | ||||
|             this.style.label = $("#node-input-style-label").prop("checked"); | ||||
|             if (this.style.label) { | ||||
|                 this.style["label-position"] = $("#node-input-style-label-position").val(); | ||||
|                 this.style.color = $("#node-input-style-color").val(); | ||||
|             } else { | ||||
|                 delete this.style["label-position"]; | ||||
|                 delete this.style.color; | ||||
|             } | ||||
|  | ||||
|             if (this.style["stroke-opacity"] === "1") { | ||||
|                 delete this.style["stroke-opacity"] | ||||
|             } | ||||
|             if (this.style["fill-opacity"] === "1") { | ||||
|                 delete this.style["fill-opacity"] | ||||
|             } | ||||
|             this.resize = true; | ||||
|         }, | ||||
|         set:{ | ||||
|             module: "node-red" | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function init() { | ||||
|  | ||||
|         RED.events.on("view:selection-changed",function(selection) { | ||||
|             RED.menu.setDisabled("menu-item-group-group",!!!selection.nodes); | ||||
|             RED.menu.setDisabled("menu-item-group-ungroup",!!!selection.nodes || selection.nodes.filter(function(n) { return n.type==='group'}).length === 0); | ||||
|             RED.menu.setDisabled("menu-item-group-merge",!!!selection.nodes); | ||||
|             RED.menu.setDisabled("menu-item-group-remove",!!!selection.nodes || selection.nodes.filter(function(n) { return !!n.g }).length === 0); | ||||
|         }); | ||||
|  | ||||
|         RED.actions.add("core:group-selection", function() { groupSelection() }) | ||||
|         RED.actions.add("core:ungroup-selection", function() { ungroupSelection() }) | ||||
|         RED.actions.add("core:merge-selection-to-group", function() { mergeSelection() }) | ||||
|         RED.actions.add("core:remove-selection-from-group", function() { removeSelection() }) | ||||
|         RED.actions.add("core:copy-group-style", function() { copyGroupStyle() }); | ||||
|         RED.actions.add("core:paste-group-style", function() { pasteGroupStyle() }); | ||||
|  | ||||
|         $(_groupEditTemplate).appendTo("#red-ui-editor-node-configs"); | ||||
|  | ||||
|         var groupStyleDiv = $("<div>",{ | ||||
|             class:"red-ui-flow-group-body", | ||||
|             style: "position: absolute; top: -1000px;" | ||||
|         }).appendTo(document.body); | ||||
|         var groupStyle = getComputedStyle(groupStyleDiv[0]); | ||||
|         defaultGroupStyle = { | ||||
|             stroke: convertColorToHex(groupStyle.stroke), | ||||
|             "stroke-opacity": groupStyle.strokeOpacity, | ||||
|             fill: convertColorToHex(groupStyle.fill), | ||||
|             "fill-opacity": groupStyle.fillOpacity | ||||
|         } | ||||
|         groupStyleDiv.remove(); | ||||
|     } | ||||
|  | ||||
|     function convertColorToHex(c) { | ||||
|         var m = /^rgb\((\d+), (\d+), (\d+)\)$/.exec(c); | ||||
|         if (m) { | ||||
|             return "#"+(((parseInt(m[1])<<16) + (parseInt(m[2])<<8) + parseInt(m[3])).toString(16).padStart(6,'0')) | ||||
|         } | ||||
|         return c; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     var groupStyleClipboard; | ||||
|  | ||||
|     function copyGroupStyle() { | ||||
|         var selection = RED.view.selection(); | ||||
|         if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].type === 'group') { | ||||
|             groupStyleClipboard = JSON.parse(JSON.stringify(selection.nodes[0].style)); | ||||
|             RED.notify(RED._("clipboard.groupStyleCopied"),{id:"clipboard"}) | ||||
|         } | ||||
|     } | ||||
|     function pasteGroupStyle() { | ||||
|         if (groupStyleClipboard) { | ||||
|             var selection = RED.view.selection(); | ||||
|             if (selection.nodes) { | ||||
|                 var historyEvent = { | ||||
|                     t:'multi', | ||||
|                     events:[], | ||||
|                     dirty: RED.nodes.dirty() | ||||
|                 } | ||||
|                 selection.nodes.forEach(function(n) { | ||||
|                     if (n.type === 'group') { | ||||
|                         historyEvent.events.push({ | ||||
|                             t: "edit", | ||||
|                             node: n, | ||||
|                             changes: { | ||||
|                                 style: JSON.parse(JSON.stringify(n.style)) | ||||
|                             }, | ||||
|                             dirty: RED.nodes.dirty() | ||||
|                         }); | ||||
|                         n.style = JSON.parse(JSON.stringify(groupStyleClipboard)); | ||||
|                         n.dirty = true; | ||||
|  | ||||
|                     } | ||||
|                 }) | ||||
|                 if (historyEvent.events.length > 0) { | ||||
|                     RED.history.push(historyEvent); | ||||
|                     RED.nodes.dirty(true); | ||||
|                     RED.view.redraw(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function groupSelection() { | ||||
|         var selection = RED.view.selection(); | ||||
|         if (selection.nodes) { | ||||
|             var group = createGroup(selection.nodes); | ||||
|             if (group) { | ||||
|                 var historyEvent = { | ||||
|                     t:"createGroup", | ||||
|                     groups: [ group ], | ||||
|                     dirty: RED.nodes.dirty() | ||||
|                 } | ||||
|                 RED.history.push(historyEvent); | ||||
|                 RED.view.select({nodes:[group]}); | ||||
|                 RED.nodes.dirty(true); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     function ungroupSelection() { | ||||
|         var selection = RED.view.selection(); | ||||
|         if (selection.nodes) { | ||||
|             var newSelection = []; | ||||
|             groups = selection.nodes.filter(function(n) { return n.type === "group" }); | ||||
|  | ||||
|             var historyEvent = { | ||||
|                 t:"ungroup", | ||||
|                 groups: [ ], | ||||
|                 dirty: RED.nodes.dirty() | ||||
|             } | ||||
|             RED.history.push(historyEvent); | ||||
|  | ||||
|  | ||||
|             groups.forEach(function(g) { | ||||
|                 newSelection = newSelection.concat(ungroup(g)) | ||||
|                 historyEvent.groups.push(g); | ||||
|             }) | ||||
|             RED.history.push(historyEvent); | ||||
|             RED.view.select({nodes:newSelection}) | ||||
|             RED.nodes.dirty(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function ungroup(g) { | ||||
|         var nodes = []; | ||||
|         var parentGroup = RED.nodes.group(g.g); | ||||
|         g.nodes.forEach(function(n) { | ||||
|             nodes.push(n); | ||||
|             if (parentGroup) { | ||||
|                 // Move nodes to parent group | ||||
|                 n.g = parentGroup.id; | ||||
|                 parentGroup.nodes.push(n); | ||||
|                 parentGroup.dirty = true; | ||||
|                 n.dirty = true; | ||||
|             } else { | ||||
|                 delete n.g; | ||||
|             } | ||||
|         }) | ||||
|         RED.nodes.removeGroup(g); | ||||
|         return nodes; | ||||
|     } | ||||
|  | ||||
|     function mergeSelection() { | ||||
|         // TODO: this currently creates an entirely new group. Need to merge properties | ||||
|         //       of any existing group | ||||
|         var selection = RED.view.selection(); | ||||
|         if (selection.nodes) { | ||||
|             var nodes = []; | ||||
|  | ||||
|             var historyEvent = { | ||||
|                 t: "multi", | ||||
|                 events: [] | ||||
|             } | ||||
|             var ungroupHistoryEvent = { | ||||
|                 t: "ungroup", | ||||
|                 groups: [] | ||||
|             } | ||||
|  | ||||
|  | ||||
|             var n; | ||||
|             var parentGroup; | ||||
|             // First pass, check they are all in the same parent | ||||
|             // TODO: DRY mergeSelection,removeSelection,... | ||||
|             for (var i=0; i<selection.nodes.length; i++) { | ||||
|                 n = selection.nodes[i]; | ||||
|                 if (i === 0) { | ||||
|                     parentGroup = n.g; | ||||
|                 } else if (n.g !== parentGroup) { | ||||
|                     RED.notify(RED._("group.errors.cannotCreateDiffGroups"),"error"); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             // Second pass, ungroup any groups in the selection and add their contents | ||||
|             // to the selection | ||||
|             for (var i=0; i<selection.nodes.length; i++) { | ||||
|                 n = selection.nodes[i]; | ||||
|                 if (n.type === "group") { | ||||
|                     ungroupHistoryEvent.groups.push(n); | ||||
|                     nodes = nodes.concat(ungroup(n)); | ||||
|                 } else { | ||||
|                     nodes.push(n); | ||||
|                 } | ||||
|                 n.dirty = true; | ||||
|             } | ||||
|             if (ungroupHistoryEvent.groups.length > 0) { | ||||
|                 historyEvent.events.push(ungroupHistoryEvent); | ||||
|             } | ||||
|             // Finally, create the new group | ||||
|             var group = createGroup(nodes); | ||||
|             if (group) { | ||||
|                 RED.view.select({nodes:[group]}) | ||||
|             } | ||||
|             historyEvent.events.push({ | ||||
|                 t:"createGroup", | ||||
|                 groups: [ group ], | ||||
|                 dirty: RED.nodes.dirty() | ||||
|             }); | ||||
|             RED.history.push(historyEvent); | ||||
|             RED.nodes.dirty(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function removeSelection() { | ||||
|         var selection = RED.view.selection(); | ||||
|         if (selection.nodes) { | ||||
|             var nodes = []; | ||||
|             var n; | ||||
|             var parentGroup = RED.nodes.group(selection.nodes[0].g); | ||||
|             if (parentGroup) { | ||||
|                 try { | ||||
|                     removeFromGroup(parentGroup,selection.nodes,true); | ||||
|                     var historyEvent = { | ||||
|                         t: "removeFromGroup", | ||||
|                         dirty: RED.nodes.dirty(), | ||||
|                         group: parentGroup, | ||||
|                         nodes: selection.nodes | ||||
|                     } | ||||
|                     RED.history.push(historyEvent); | ||||
|                     RED.nodes.dirty(true); | ||||
|                 } catch(err) { | ||||
|                     RED.notify(err,"error"); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             RED.view.select({nodes:selection.nodes}) | ||||
|         } | ||||
|     } | ||||
|     function createGroup(nodes) { | ||||
|         if (nodes.length === 0) { | ||||
|             return; | ||||
|         } | ||||
|         if (nodes.filter(function(n) { return n.type === "subflow" }).length > 0) { | ||||
|             RED.notify(RED._("group.errors.cannotAddSubflowPorts"),"error"); | ||||
|             return; | ||||
|         } | ||||
|         // nodes is an array | ||||
|         // each node must be on the same tab (z) | ||||
|         var group = { | ||||
|             id: RED.nodes.id(), | ||||
|             type: 'group', | ||||
|             nodes: [], | ||||
|             style: JSON.parse(JSON.stringify(defaultGroupStyle)), | ||||
|             x: Number.POSITIVE_INFINITY, | ||||
|             y: Number.POSITIVE_INFINITY, | ||||
|             w: 0, | ||||
|             h: 0, | ||||
|             _def: RED.group.def | ||||
|         } | ||||
|         try { | ||||
|             addToGroup(group,nodes); | ||||
|         } catch(err) { | ||||
|             RED.notify(err,"error"); | ||||
|             return; | ||||
|         } | ||||
|         group.z = nodes[0].z; | ||||
|  | ||||
|         RED.nodes.addGroup(group); | ||||
|         return group; | ||||
|     } | ||||
|     function addToGroup(group,nodes) { | ||||
|         if (!Array.isArray(nodes)) { | ||||
|             nodes = [nodes]; | ||||
|         } | ||||
|         var i,n,z; | ||||
|         var g; | ||||
|         // First pass - validate we can safely add these nodes to the group | ||||
|         for (i=0;i<nodes.length;i++) { | ||||
|             n = nodes[i] | ||||
|             if (!n.z) { | ||||
|                 throw new Error("Cannot add node without a z property to a group") | ||||
|             } | ||||
|             if (!z) { | ||||
|                 z = n.z; | ||||
|             } else if (z !== n.z) { | ||||
|                 throw new Error("Cannot add nooes with different z properties") | ||||
|             } | ||||
|             if (n.g) { | ||||
|                 // This is already in a group. | ||||
|                 //  - check they are all in the same group | ||||
|                 if (!g) { | ||||
|                     if (i!==0) { | ||||
|                         // TODO: this might be ok when merging groups | ||||
|                         throw new Error(RED._("group.errors.cannotCreateDiffGroups")) | ||||
|                     } | ||||
|                     g = n.g | ||||
|                 } | ||||
|             } | ||||
|             if (g !== n.g) { | ||||
|                 throw new Error(RED._("group.errors.cannotCreateDiffGroups")) | ||||
|             } | ||||
|         } | ||||
|         // The nodes are already in a group. The assumption is they should be | ||||
|         // wrapped in the newly provided group, and that group added to in their | ||||
|         // place to the existing containing group. | ||||
|         if (g) { | ||||
|             g = RED.nodes.group(g); | ||||
|             g.nodes.push(group); | ||||
|             g.dirty = true; | ||||
|             group.g = g.id; | ||||
|         } | ||||
|         // Second pass - add them to the group | ||||
|         for (i=0;i<nodes.length;i++) { | ||||
|             n = nodes[i]; | ||||
|             if (n.type !== "subflow") { | ||||
|                 if (g && n.g === g.id) { | ||||
|                     var ni = g.nodes.indexOf(n); | ||||
|                     if (ni > -1) { | ||||
|                         g.nodes.splice(ni,1) | ||||
|                     } | ||||
|                 } | ||||
|                 n.g = group.id; | ||||
|                 n.dirty = true; | ||||
|                 group.nodes.push(n); | ||||
|                 group.x = Math.min(group.x,n.x-n.w/2-25-((n._def.button && n._def.align!=="right")?20:0)); | ||||
|                 group.y = Math.min(group.y,n.y-n.h/2-25); | ||||
|                 group.w = Math.max(group.w,n.x+n.w/2+25+((n._def.button && n._def.align=="right")?20:0) - group.x); | ||||
|                 group.h = Math.max(group.h,n.y+n.h/2+25-group.y); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         markDirty(group); | ||||
|     } | ||||
|     function removeFromGroup(group, nodes, reparent) { | ||||
|         if (!Array.isArray(nodes)) { | ||||
|             nodes = [nodes]; | ||||
|         } | ||||
|         var n; | ||||
|         // First pass, check they are all in the same parent | ||||
|         // TODO: DRY mergeSelection,removeSelection,... | ||||
|         for (var i=0; i<nodes.length; i++) { | ||||
|             if (nodes[i].g !== group.id) { | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         var parentGroup = RED.nodes.group(group.g); | ||||
|         for (var i=0; i<nodes.length; i++) { | ||||
|             n = nodes[i]; | ||||
|             n.dirty = true; | ||||
|             var index = group.nodes.indexOf(n); | ||||
|             group.nodes.splice(index,1); | ||||
|             if (reparent && group.g) { | ||||
|                 n.g = group.g | ||||
|                 parentGroup.nodes.push(n); | ||||
|             } else { | ||||
|                 delete n.g; | ||||
|             } | ||||
|         } | ||||
|         markDirty(group); | ||||
|     } | ||||
|  | ||||
|     function getNodes(group,recursive) { | ||||
|         var nodes = []; | ||||
|         group.nodes.forEach(function(n) { | ||||
|             nodes.push(n); | ||||
|             if (recursive && n.type === 'group') { | ||||
|                 nodes = nodes.concat(getNodes(n,recursive)) | ||||
|             } | ||||
|         }) | ||||
|         return nodes; | ||||
|     } | ||||
|  | ||||
|     function groupContains(group,item) { | ||||
|         if (item.g === group.id) { | ||||
|             return true; | ||||
|         } | ||||
|         for (var i=0;i<group.nodes.length;i++) { | ||||
|             if (group.nodes[i].type === "group") { | ||||
|                 if (groupContains(group.nodes[i],item)) { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     function getRootGroup(group) { | ||||
|         if (!group.g) { | ||||
|             return group; | ||||
|         } | ||||
|         return getRootGroup(RED.nodes.group(group.g)) | ||||
|     } | ||||
|  | ||||
|     function createLayoutPicker(options) { | ||||
|  | ||||
|         var container = $("<div>",{style:"display:inline-block"}); | ||||
|         var layoutHiddenInput = $("<input/>", { id: options.id, type: "hidden", value: options.value }).appendTo(container); | ||||
|  | ||||
|         var layoutButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container); | ||||
|         $('<i class="fa fa-caret-down"></i>').appendTo(layoutButton); | ||||
|  | ||||
|         var layoutDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(layoutButton); | ||||
|         var layoutDisp = $('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"}).appendTo(layoutDispContainer); | ||||
|  | ||||
|         var refreshDisplay = function() { | ||||
|             var val = layoutHiddenInput.val(); | ||||
|             layoutDisp.removeClass().addClass("red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val) | ||||
|         } | ||||
|         layoutButton.on("click", function(e) { | ||||
|             var picker = $("<div/>", { | ||||
|                 class: "red-ui-group-layout-picker" | ||||
|             }).css({ | ||||
|                 width: "126px" | ||||
|             }); | ||||
|  | ||||
|             var row = null; | ||||
|  | ||||
|             row = $("<div/>").appendTo(picker); | ||||
|  | ||||
|             for (var y=0;y<2;y++) { //red-ui-group-layout-text-pos | ||||
|                 var yComponent= "ns"[y]; | ||||
|                 row = $("<div/>").appendTo(picker); | ||||
|                 for (var x=0;x<3;x++) { | ||||
|                     var xComponent = ["w","","e"][x]; | ||||
|                     var val = yComponent+xComponent; | ||||
|                     var button = $("<button/>", { class:"red-ui-search-result-node","data-pos":val }).appendTo(row); | ||||
|                     button.on("click",  function (e) { | ||||
|                         e.preventDefault(); | ||||
|                         layoutHiddenInput.val($(this).data("pos")); | ||||
|                         layoutPanel.hide() | ||||
|                         refreshDisplay(); | ||||
|                     }); | ||||
|                     $('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val}).appendTo(button); | ||||
|  | ||||
|  | ||||
|                 } | ||||
|             } | ||||
|             refreshDisplay(); | ||||
|             var layoutPanel = RED.popover.panel(picker); | ||||
|             layoutPanel.show({ | ||||
|                 target: layoutButton | ||||
|             }) | ||||
|         }) | ||||
|  | ||||
|         refreshDisplay(); | ||||
|  | ||||
|         return container; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function markDirty(group) { | ||||
|         group.dirty = true; | ||||
|         while(group) { | ||||
|             group.dirty = true; | ||||
|             group = RED.nodes.group(group.g); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     return { | ||||
|         def: groupDef, | ||||
|         init: init, | ||||
|         createGroup: createGroup, | ||||
|         ungroup: ungroup, | ||||
|         addToGroup: addToGroup, | ||||
|         removeFromGroup: removeFromGroup, | ||||
|         getNodes: getNodes, | ||||
|         contains: groupContains, | ||||
|         markDirty: markDirty | ||||
|     } | ||||
| })(); | ||||
| @@ -524,12 +524,12 @@ RED.keyboard = (function() { | ||||
|         var pane = $('<div id="red-ui-settings-tab-keyboard"></div>'); | ||||
|  | ||||
|         $('<div class="keyboard-shortcut-entry keyboard-shortcut-list-header">'+ | ||||
|         '<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input id="red-ui-settings-tab-keyboard-filter" type="text" data-i18n="[placeholder]keyboard.filterActions"></div>'+ | ||||
|         '<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input autocomplete="off" name="keyboard-filter" id="red-ui-settings-tab-keyboard-filter" type="text" data-i18n="[placeholder]keyboard.filterActions"></div>'+ | ||||
|         '<div class="keyboard-shortcut-entry-key" data-i18n="keyboard.shortcut"></div>'+ | ||||
|         '<div class="keyboard-shortcut-entry-scope" data-i18n="keyboard.scope"></div>'+ | ||||
|         '</div>').appendTo(pane); | ||||
|  | ||||
|         pane.find("input").searchBox({ | ||||
|         pane.find("#red-ui-settings-tab-keyboard-filter").searchBox({ | ||||
|             delay: 100, | ||||
|             change: function() { | ||||
|                 var filterValue = $(this).val().trim(); | ||||
|   | ||||
| @@ -384,6 +384,7 @@ RED.palette.editor = (function() { | ||||
|                     handleCatalogResponse(null,catalog,index,v); | ||||
|                     refreshNodeModuleList(); | ||||
|                 }).fail(function(jqxhr, textStatus, error) { | ||||
|                     console.warn("Error loading catalog",catalog,":",error); | ||||
|                     handleCatalogResponse(jqxhr,catalog,index); | ||||
|                 }).always(function() { | ||||
|                     handled++; | ||||
|   | ||||
| @@ -269,7 +269,7 @@ RED.palette = (function() { | ||||
|                 RED.view.focus(); | ||||
|                 var helpText; | ||||
|                 if (nt.indexOf("subflow:") === 0) { | ||||
|                     helpText = marked(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'); | ||||
|                     helpText = RED.utils.renderMarkdown(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'); | ||||
|                 } else { | ||||
|                     helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'); | ||||
|                 } | ||||
| @@ -284,6 +284,9 @@ RED.palette = (function() { | ||||
|             var mouseX; | ||||
|             var mouseY; | ||||
|             var spliceTimer; | ||||
|             var groupTimer; | ||||
|             var activeGroup; | ||||
|             var hoverGroup; | ||||
|             var paletteWidth; | ||||
|             var paletteTop; | ||||
|             $(d).draggable({ | ||||
| @@ -295,16 +298,51 @@ RED.palette = (function() { | ||||
|                 start: function() { | ||||
|                     paletteWidth = $("#red-ui-palette").width(); | ||||
|                     paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top; | ||||
|                     hoverGroup = null; | ||||
|                     activeGroup = RED.view.getActiveGroup(); | ||||
|                     if (activeGroup) { | ||||
|                         document.getElementById(activeGroup.id).classList.add("red-ui-flow-group-active-hovered"); | ||||
|                     } | ||||
|                     RED.view.focus(); | ||||
|                 }, | ||||
|                 stop: function() { d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}}, | ||||
|                 stop: function() { | ||||
|                     d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false); | ||||
|                     if (hoverGroup) { | ||||
|                         document.getElementById(hoverGroup.id).classList.remove("red-ui-flow-group-hovered"); | ||||
|                     } | ||||
|                     if (activeGroup) { | ||||
|                         document.getElementById(activeGroup.id).classList.remove("red-ui-flow-group-active-hovered"); | ||||
|                     } | ||||
|                     if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; } | ||||
|                     if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; } | ||||
|                 }, | ||||
|                 drag: function(e,ui) { | ||||
|                     var paletteNode = getPaletteNode(nt); | ||||
|                     ui.originalPosition.left = paletteNode.offset().left; | ||||
|                     mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft(); | ||||
|                     mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop(); | ||||
|                     if (!groupTimer) { | ||||
|                         groupTimer = setTimeout(function() { | ||||
|                             var group = RED.view.getGroupAtPoint(mouseX,mouseY); | ||||
|                             if (group !== hoverGroup) { | ||||
|                                 if (hoverGroup) { | ||||
|                                     document.getElementById(hoverGroup.id).classList.remove("red-ui-flow-group-hovered"); | ||||
|                                 } | ||||
|                                 if (group) { | ||||
|                                     document.getElementById(group.id).classList.add("red-ui-flow-group-hovered"); | ||||
|                                 } | ||||
|                                 hoverGroup = group; | ||||
|                                 if (hoverGroup) { | ||||
|                                     $(ui.helper).data('group',hoverGroup); | ||||
|                                 } else { | ||||
|                                     $(ui.helper).removeData('group'); | ||||
|                                 } | ||||
|                             } | ||||
|                             groupTimer = null; | ||||
|  | ||||
|                         },200) | ||||
|                     } | ||||
|                     if (def.inputs > 0 && def.outputs > 0) { | ||||
|                         mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft(); | ||||
|                         mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop(); | ||||
|                         if (!spliceTimer) { | ||||
|                             spliceTimer = setTimeout(function() { | ||||
|                                 var nodes = []; | ||||
| @@ -370,7 +408,7 @@ RED.palette = (function() { | ||||
|                     RED.workspaces.show(nt.substring(8)); | ||||
|                     e.preventDefault(); | ||||
|                 }); | ||||
|                 nodeInfo = marked(def.info||""); | ||||
|                 nodeInfo = RED.utils.renderMarkdown(def.info||""); | ||||
|             } | ||||
|             setLabel(nt,d,label,nodeInfo); | ||||
|  | ||||
| @@ -440,7 +478,7 @@ RED.palette = (function() { | ||||
|             } else if (portOutput.length !== 0 && sf.out.length === 0) { | ||||
|                 portOutput.remove(); | ||||
|             } | ||||
|             setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||"")); | ||||
|             setLabel(sf.type+":"+sf.id,paletteNode,sf.name,RED.utils.renderMarkdown(sf.info||"")); | ||||
|             setIcon(paletteNode,sf); | ||||
|  | ||||
|             var currentCategory = paletteNode.data('category'); | ||||
|   | ||||
| @@ -158,7 +158,7 @@ RED.projects.settings = (function() { | ||||
|         container.empty(); | ||||
|         var desc; | ||||
|         if (activeProject.description) { | ||||
|             desc = marked(activeProject.description); | ||||
|             desc = RED.utils.renderMarkdown(activeProject.description); | ||||
|         } else { | ||||
|             desc = '<span class="red-ui-help-info-none">' + RED._("sidebar.project.noDescriptionAvailable") + '</span>'; | ||||
|         } | ||||
|   | ||||
| @@ -30,13 +30,13 @@ RED.projects.userSettings = (function() { | ||||
|         $('<div class="red-ui-settings-section-description"></div>').appendTo(gitconfigContainer).text(RED._("editor:sidebar.project.userSettings.committerTip")); | ||||
|  | ||||
|         var row = $('<div class="red-ui-settings-row"></div>').appendTo(gitconfigContainer); | ||||
|         $('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row); | ||||
|         gitUsernameInput = $('<input type="text">').appendTo(row); | ||||
|         $('<label for="user-settings-gitconfig-username"></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row); | ||||
|         gitUsernameInput = $('<input type="text" id="user-settings-gitconfig-username">').appendTo(row); | ||||
|         gitUsernameInput.val(currentGitSettings.user.name||""); | ||||
|  | ||||
|         row = $('<div class="red-ui-settings-row"></div>').appendTo(gitconfigContainer); | ||||
|         $('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row); | ||||
|         gitEmailInput = $('<input type="text">').appendTo(row); | ||||
|         $('<label for="user-settings-gitconfig-email"></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row); | ||||
|         gitEmailInput = $('<input type="text" id="user-settings-gitconfig-email">').appendTo(row); | ||||
|         gitEmailInput.val(currentGitSettings.user.email||""); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1939,100 +1939,121 @@ RED.projects = (function() { | ||||
|             } | ||||
|         }).fail(function(xhr,textStatus,err) { | ||||
|             var responses; | ||||
|  | ||||
|             if (options.responses && options.responses[xhr.status]) { | ||||
|                 responses = options.responses[xhr.status]; | ||||
|                 if (typeof responses === 'function') { | ||||
|                     resultCallback = responses; | ||||
|                     resultCallbackArgs = {error:responses.statusText}; | ||||
|                     return; | ||||
|                 } else if (options.handleAuthFail !== false && xhr.responseJSON.code === 'git_auth_failed') { | ||||
|                     var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch; | ||||
|                 } else if (options.handleAuthFail !== false && (xhr.responseJSON.code === 'git_auth_failed' || xhr.responseJSON.code === 'git_host_key_verification_failed')) { | ||||
|                     if (xhr.responseJSON.code === 'git_auth_failed') { | ||||
|                         var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch; | ||||
|  | ||||
|                     var message = $('<div>'+ | ||||
|                         var message = $('<div>'+ | ||||
|                         '<div class="form-row">'+RED._("projects.send-req.auth-req")+':</div>'+ | ||||
|                         '<div class="form-row"><div style="margin-left: 20px;">'+url+'</div></div>'+ | ||||
|                         '</div>'); | ||||
|  | ||||
|                     var isSSH = false; | ||||
|                     if (/^https?:\/\//.test(url)) { | ||||
|                         $('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+ | ||||
|                           '<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message); | ||||
|                     } else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) { | ||||
|                         isSSH = true; | ||||
|                         var row = $('<div class="form-row"></div>').appendTo(message); | ||||
|                         $('<label for="projects-user-auth-key">SSH Key</label>').appendTo(row); | ||||
|                         var projectRepoSSHKeySelect = $('<select id="projects-user-auth-key">').width('70%').appendTo(row); | ||||
|                         $.getJSON("settings/user/keys", function(data) { | ||||
|                             var count = 0; | ||||
|                             data.keys.forEach(function(key) { | ||||
|                                 projectRepoSSHKeySelect.append($("<option></option>").val(key.name).text(key.name)); | ||||
|                                 count++; | ||||
|                         var isSSH = false; | ||||
|                         if (/^https?:\/\//.test(url)) { | ||||
|                             $('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+ | ||||
|                             '<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message); | ||||
|                         } else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) { | ||||
|                             isSSH = true; | ||||
|                             var row = $('<div class="form-row"></div>').appendTo(message); | ||||
|                             $('<label for="projects-user-auth-key">SSH Key</label>').appendTo(row); | ||||
|                             var projectRepoSSHKeySelect = $('<select id="projects-user-auth-key">').width('70%').appendTo(row); | ||||
|                             $.getJSON("settings/user/keys", function(data) { | ||||
|                                 var count = 0; | ||||
|                                 data.keys.forEach(function(key) { | ||||
|                                     projectRepoSSHKeySelect.append($("<option></option>").val(key.name).text(key.name)); | ||||
|                                     count++; | ||||
|                                 }); | ||||
|                                 if (count === 0) { | ||||
|                                     //TODO: handle no keys yet setup | ||||
|                                 } | ||||
|                             }); | ||||
|                             if (count === 0) { | ||||
|                                 //TODO: handle no keys yet setup | ||||
|                             } | ||||
|                         }); | ||||
|                         row = $('<div class="form-row"></div>').appendTo(message); | ||||
|                         $('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row); | ||||
|                         $('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row); | ||||
|                     } | ||||
|                             row = $('<div class="form-row"></div>').appendTo(message); | ||||
|                             $('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row); | ||||
|                             $('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row); | ||||
|                         } | ||||
|  | ||||
|                     var notification = RED.notify(message,{ | ||||
|                         type:"error", | ||||
|                         fixed: true, | ||||
|                         modal: true, | ||||
|                         buttons: [ | ||||
|                             { | ||||
|                                 //id: "node-dialog-delete", | ||||
|                                 //class: 'leftButton', | ||||
|                                 text: RED._("common.label.cancel"), | ||||
|                                 click: function() { | ||||
|                                     notification.close(); | ||||
|                                 } | ||||
|                             },{ | ||||
|                                 text: '<span><i class="fa fa-refresh"></i> ' +RED._("projects.send-req.retry") +'</span>', | ||||
|                                 click: function() { | ||||
|                                     body = body || {}; | ||||
|                                     var authBody = {}; | ||||
|                                     if (isSSH) { | ||||
|                                         authBody.keyFile = $('#projects-user-auth-key').val(); | ||||
|                                         authBody.passphrase = $('#projects-user-auth-passphrase').val(); | ||||
|                                     } else { | ||||
|                                         authBody.username = $('#projects-user-auth-username').val(); | ||||
|                                         authBody.password = $('#projects-user-auth-password').val(); | ||||
|                         var notification = RED.notify(message,{ | ||||
|                             type:"error", | ||||
|                             fixed: true, | ||||
|                             modal: true, | ||||
|                             buttons: [ | ||||
|                                 { | ||||
|                                     //id: "node-dialog-delete", | ||||
|                                     //class: 'leftButton', | ||||
|                                     text: RED._("common.label.cancel"), | ||||
|                                     click: function() { | ||||
|                                         notification.close(); | ||||
|                                     } | ||||
|                                     var done = function(err) { | ||||
|                                         if (err) { | ||||
|                                             console.log(RED._("projects.send-req.update-failed")); | ||||
|                                             console.log(err); | ||||
|                                 },{ | ||||
|                                     text: '<span><i class="fa fa-refresh"></i> ' +RED._("projects.send-req.retry") +'</span>', | ||||
|                                     click: function() { | ||||
|                                         body = body || {}; | ||||
|                                         var authBody = {}; | ||||
|                                         if (isSSH) { | ||||
|                                             authBody.keyFile = $('#projects-user-auth-key').val(); | ||||
|                                             authBody.passphrase = $('#projects-user-auth-passphrase').val(); | ||||
|                                         } else { | ||||
|                                             sendRequest(options,body); | ||||
|                                             notification.close(); | ||||
|                                             authBody.username = $('#projects-user-auth-username').val(); | ||||
|                                             authBody.password = $('#projects-user-auth-password').val(); | ||||
|                                         } | ||||
|                                         var done = function(err) { | ||||
|                                             if (err) { | ||||
|                                                 console.log(RED._("projects.send-req.update-failed")); | ||||
|                                                 console.log(err); | ||||
|                                             } else { | ||||
|                                                 sendRequest(options,body); | ||||
|                                                 notification.close(); | ||||
|                                             } | ||||
|  | ||||
|                                     } | ||||
|                                     sendRequest({ | ||||
|                                         url: "projects/"+activeProject.name+"/remotes/"+(xhr.responseJSON.remote||options.remote||'origin'), | ||||
|                                         type: "PUT", | ||||
|                                         responses: { | ||||
|                                             0: function(error) { | ||||
|                                                 done(error,null); | ||||
|                                             }, | ||||
|                                             200: function(data) { | ||||
|                                                 done(null,data); | ||||
|                                             }, | ||||
|                                             400: { | ||||
|                                                 'unexpected_error': function(error) { | ||||
|                                                     done(error,null); | ||||
|                                                 } | ||||
|                                             }, | ||||
|                                         } | ||||
|                                     },{auth:authBody}); | ||||
|                                         sendRequest({ | ||||
|                                             url: "projects/"+activeProject.name+"/remotes/"+(xhr.responseJSON.remote||options.remote||'origin'), | ||||
|                                             type: "PUT", | ||||
|                                             responses: { | ||||
|                                                 0: function(error) { | ||||
|                                                     done(error,null); | ||||
|                                                 }, | ||||
|                                                 200: function(data) { | ||||
|                                                     done(null,data); | ||||
|                                                 }, | ||||
|                                                 400: { | ||||
|                                                     'unexpected_error': function(error) { | ||||
|                                                         done(error,null); | ||||
|                                                     } | ||||
|                                                 }, | ||||
|                                             } | ||||
|                                         },{auth:authBody}); | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                         ] | ||||
|                     }); | ||||
|                     return; | ||||
|                             ] | ||||
|                         }); | ||||
|                         return; | ||||
|                     } else if (xhr.responseJSON.code === 'git_host_key_verification_failed') { | ||||
|                         var message = $('<div>'+ | ||||
|                             '<div class="form-row">'+RED._("projects.send-req.host-key-verify-failed")+'</div>'+ | ||||
|                             '</div>'); | ||||
|                         var notification = RED.notify(message,{ | ||||
|                             type:"error", | ||||
|                             fixed: true, | ||||
|                             modal: true, | ||||
|                             buttons: [ | ||||
|                                 { | ||||
|                                     text: RED._("common.label.close"), | ||||
|                                     click: function() { | ||||
|                                         notification.close(); | ||||
|                                     } | ||||
|                                 } | ||||
|                             ] | ||||
|                         }); | ||||
|                         return; | ||||
|                     } | ||||
|                 } else if (responses[xhr.responseJSON.code]) { | ||||
|                     resultCallback = responses[xhr.responseJSON.code]; | ||||
|                     resultCallbackArgs = xhr.responseJSON; | ||||
|   | ||||
| @@ -25,5 +25,7 @@ RED.state = { | ||||
|     IMPORT_DRAGGING: 8, | ||||
|     QUICK_JOINING: 9, | ||||
|     PANNING: 10, | ||||
|     SELECTING_NODE: 11 | ||||
|     SELECTING_NODE: 11, | ||||
|     GROUP_DRAGGING: 12, | ||||
|     GROUP_RESIZE: 13 | ||||
| } | ||||
|   | ||||
| @@ -567,6 +567,34 @@ RED.subflow = (function() { | ||||
|             return; | ||||
|         } | ||||
|         var i,n; | ||||
|         var nodeList = new Set(); | ||||
|         var tmplist = selection.nodes.slice(); | ||||
|         var includedGroups = new Set(); | ||||
|         while(tmplist.length > 0) { | ||||
|             n = tmplist.shift(); | ||||
|             if (n.type === "group") { | ||||
|                 includedGroups.add(n.id); | ||||
|                 tmplist = tmplist.concat(n.nodes); | ||||
|             } | ||||
|             nodeList.add(n); | ||||
|         } | ||||
|  | ||||
|         nodeList = Array.from(nodeList); | ||||
|  | ||||
|         var containingGroup = nodeList[0].g; | ||||
|         var nodesMovedFromGroup = []; | ||||
|  | ||||
|         for (i=0; i<nodeList.length;i++) { | ||||
|             if (nodeList[i].g && !includedGroups.has(nodeList[i].g)) { | ||||
|                 if (containingGroup !== nodeList[i].g) { | ||||
|                     RED.notify("Cannot create subflow across multiple groups","error"); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (containingGroup) { | ||||
|             containingGroup = RED.nodes.group(containingGroup); | ||||
|         } | ||||
|         var nodes = {}; | ||||
|         var new_links = []; | ||||
|         var removedLinks = []; | ||||
| @@ -575,13 +603,13 @@ RED.subflow = (function() { | ||||
|         var candidateOutputs = []; | ||||
|         var candidateInputNodes = {}; | ||||
|  | ||||
|         var boundingBox = [selection.nodes[0].x, | ||||
|             selection.nodes[0].y, | ||||
|             selection.nodes[0].x, | ||||
|             selection.nodes[0].y]; | ||||
|         var boundingBox = [nodeList[0].x, | ||||
|             nodeList[0].y, | ||||
|             nodeList[0].x, | ||||
|             nodeList[0].y]; | ||||
|  | ||||
|         for (i=0;i<selection.nodes.length;i++) { | ||||
|             n = selection.nodes[i]; | ||||
|         for (i=0;i<nodeList.length;i++) { | ||||
|             n = nodeList[i]; | ||||
|             nodes[n.id] = {n:n,outputs:{}}; | ||||
|             boundingBox = [ | ||||
|                 Math.min(boundingBox[0],n.x), | ||||
| @@ -690,6 +718,20 @@ RED.subflow = (function() { | ||||
|         RED.editor.validateNode(subflowInstance); | ||||
|         RED.nodes.add(subflowInstance); | ||||
|  | ||||
|         if (containingGroup) { | ||||
|             RED.group.addToGroup(containingGroup, subflowInstance); | ||||
|             nodeList.forEach(function(nl) { | ||||
|                 if (nl.g === containingGroup.id) { | ||||
|                     delete nl.g; | ||||
|                     var index = containingGroup.nodes.indexOf(nl); | ||||
|                     containingGroup.nodes.splice(index,1); | ||||
|                     nodesMovedFromGroup.push(nl); | ||||
|                 } | ||||
|             }) | ||||
|             containingGroup.dirty = true; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         candidateInputs.forEach(function(l) { | ||||
|             var link = {source:l.source, sourcePort:l.sourcePort, target: subflowInstance}; | ||||
|             new_links.push(link); | ||||
| @@ -723,8 +765,8 @@ RED.subflow = (function() { | ||||
|             RED.nodes.removeLink(removedLinks[i]); | ||||
|         } | ||||
|  | ||||
|         for (i=0;i<selection.nodes.length;i++) { | ||||
|             n = selection.nodes[i]; | ||||
|         for (i=0;i<nodeList.length;i++) { | ||||
|             n = nodeList[i]; | ||||
|             if (/^link /.test(n.type)) { | ||||
|                 n.links = n.links.filter(function(id) { | ||||
|                     var isLocalLink = nodes.hasOwnProperty(id); | ||||
| @@ -745,7 +787,8 @@ RED.subflow = (function() { | ||||
|             RED.nodes.moveNodeToTab(n, subflow.id); | ||||
|         } | ||||
|  | ||||
|         RED.history.push({ | ||||
|  | ||||
|         var historyEvent = { | ||||
|             t:'createSubflow', | ||||
|             nodes:[subflowInstance.id], | ||||
|             links:new_links, | ||||
| @@ -759,11 +802,29 @@ RED.subflow = (function() { | ||||
|             removedLinks: removedLinks, | ||||
|  | ||||
|             dirty:RED.nodes.dirty() | ||||
|         }); | ||||
|         RED.view.select(null); | ||||
|         } | ||||
|         if (containingGroup) { | ||||
|             historyEvent = { | ||||
|                 t:'multi', | ||||
|                 events: [ historyEvent ] | ||||
|             } | ||||
|             historyEvent.events.push({ | ||||
|                 t:'addToGroup', | ||||
|                 group: containingGroup, | ||||
|                 nodes: [subflowInstance] | ||||
|             }) | ||||
|             historyEvent.events.push({ | ||||
|                 t:'removeFromGroup', | ||||
|                 group: containingGroup, | ||||
|                 nodes: nodesMovedFromGroup, | ||||
|                 reparent: false | ||||
|             }) | ||||
|         } | ||||
|         RED.history.push(historyEvent); | ||||
|         RED.editor.validateNode(subflow); | ||||
|         RED.nodes.dirty(true); | ||||
|         RED.view.redraw(true); | ||||
|         RED.view.updateActive(); | ||||
|         RED.view.select(null); | ||||
|     } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -231,7 +231,8 @@ RED.sidebar.context = (function() { | ||||
|                                 RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), { | ||||
|                                     typeHint: data.format, | ||||
|                                     sourceId: id+"."+k, | ||||
|                                     tools: tools | ||||
|                                     tools: tools, | ||||
|                                     path: "" | ||||
|                                 }).appendTo(propRow.children()[1]); | ||||
|                             } | ||||
|                         }) | ||||
| @@ -275,7 +276,8 @@ RED.sidebar.context = (function() { | ||||
|                                                 RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), { | ||||
|                                                     typeHint: data.format, | ||||
|                                                     sourceId: id+"."+k, | ||||
|                                                     tools: tools | ||||
|                                                     tools: tools, | ||||
|                                                     path: "" | ||||
|                                                 }).appendTo(propRow.children()[1]); | ||||
|                                             } | ||||
|                                         }); | ||||
| @@ -295,7 +297,8 @@ RED.sidebar.context = (function() { | ||||
|                     RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), { | ||||
|                         typeHint: v.format, | ||||
|                         sourceId: id+"."+k, | ||||
|                         tools: tools | ||||
|                         tools: tools, | ||||
|                         path: "" | ||||
|                     }).appendTo(propRow.children()[1]); | ||||
|                     if (contextStores.length > 1) { | ||||
|                         $("<span>",{class:"red-ui-sidebar-context-property-storename"}).text(v.store).appendTo($(propRow.children()[0])) | ||||
|   | ||||
| @@ -15,17 +15,6 @@ | ||||
|  **/ | ||||
| RED.sidebar.info = (function() { | ||||
|  | ||||
|     marked.setOptions({ | ||||
|         renderer: new marked.Renderer(), | ||||
|         gfm: true, | ||||
|         tables: true, | ||||
|         breaks: false, | ||||
|         pedantic: false, | ||||
|         sanitize: true, | ||||
|         smartLists: true, | ||||
|         smartypants: false | ||||
|     }); | ||||
|  | ||||
|     var content; | ||||
|     var sections; | ||||
|     var propertiesSection; | ||||
| @@ -163,7 +152,8 @@ RED.sidebar.info = (function() { | ||||
|             var types = { | ||||
|                 nodes:0, | ||||
|                 flows:0, | ||||
|                 subflows:0 | ||||
|                 subflows:0, | ||||
|                 groups: 0 | ||||
|             } | ||||
|             node.forEach(function(n) { | ||||
|                 if (n.type === 'tab') { | ||||
| @@ -171,6 +161,8 @@ RED.sidebar.info = (function() { | ||||
|                     types.nodes += RED.nodes.filterNodes({z:n.id}).length; | ||||
|                 } else if (n.type === 'subflow') { | ||||
|                     types.subflows++; | ||||
|                 } else if (n.type === 'group') { | ||||
|                     types.groups++; | ||||
|                 } else { | ||||
|                     types.nodes++; | ||||
|                 } | ||||
| @@ -190,6 +182,9 @@ RED.sidebar.info = (function() { | ||||
|             if (types.nodes > 0) { | ||||
|                 $('<div>').text(RED._("clipboard.node",{count:types.nodes})).appendTo(counts); | ||||
|             } | ||||
|             if (types.groups > 0) { | ||||
|                 $('<div>').text(RED._("clipboard.group",{count:types.groups})).appendTo(counts); | ||||
|             } | ||||
|         } else { | ||||
|             // A single 'thing' selected. | ||||
|  | ||||
| @@ -220,6 +215,36 @@ RED.sidebar.info = (function() { | ||||
|                     propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody); | ||||
|                     $(propRow.children()[1]).text((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled")) | ||||
|                 } | ||||
|             } else if (node.type === "group") { | ||||
|                 // An actual node is selected in the editor - build up its properties table | ||||
|                 propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.group")+"</td><td></td></tr>").appendTo(tableBody); | ||||
|                 RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]); | ||||
|                 if (node.name) { | ||||
|                     propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody); | ||||
|                     $('<span class="red-ui-text-bidi-aware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]); | ||||
|                 } | ||||
|                 propRow = $('<tr class="red-ui-help-info-row"><td> </td><td></td></tr>').appendTo(tableBody); | ||||
|                 var typeCounts = { | ||||
|                     nodes:0, | ||||
|                     groups: 0 | ||||
|                 } | ||||
|                 var allNodes = RED.group.getNodes(node,true); | ||||
|                 allNodes.forEach(function(n) { | ||||
|                     if (n.type === "group") { | ||||
|                         typeCounts.groups++; | ||||
|                     } else { | ||||
|                         typeCounts.nodes++ | ||||
|                     } | ||||
|                 }); | ||||
|                 var counts = $('<div>').appendTo($(propRow.children()[1])); | ||||
|                 if (typeCounts.nodes > 0) { | ||||
|                     $('<div>').text(RED._("clipboard.node",{count:typeCounts.nodes})).appendTo(counts); | ||||
|                 } | ||||
|                 if (typeCounts.groups > 0) { | ||||
|                     $('<div>').text(RED._("clipboard.group",{count:typeCounts.groups})).appendTo(counts); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|             } else { | ||||
|                 // An actual node is selected in the editor - build up its properties table | ||||
|                 propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody); | ||||
| @@ -236,7 +261,7 @@ RED.sidebar.info = (function() { | ||||
|                     } | ||||
|                 } | ||||
|                 var count = 0; | ||||
|                 if (!m && node.type != "subflow") { | ||||
|                 if (!m && node.type != "subflow" && node.type != "group") { | ||||
|                     var defaults; | ||||
|                     if (node.type === 'unknown') { | ||||
|                         defaults = {}; | ||||
| @@ -314,7 +339,7 @@ RED.sidebar.info = (function() { | ||||
|                 if (subflowNode && node.type !== "subflow") { | ||||
|                     // Selected a subflow instance node. | ||||
|                     // - The subflow template info goes into help | ||||
|                     helpText = (marked(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>')); | ||||
|                     helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>')); | ||||
|                 } else { | ||||
|                     helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'); | ||||
|                 } | ||||
| @@ -326,10 +351,10 @@ RED.sidebar.info = (function() { | ||||
|             if (node._def && node._def.info) { | ||||
|                 var info = node._def.info; | ||||
|                 var textInfo = (typeof info === "function" ? info.call(node) : info); | ||||
|                 infoText = infoText + marked(textInfo); | ||||
|                 infoText = infoText + RED.utils.renderMarkdown(textInfo); | ||||
|             } | ||||
|             if (node.info) { | ||||
|                 infoText = infoText + marked(node.info || "") | ||||
|                 infoText = infoText + RED.utils.renderMarkdown(node.info || "") | ||||
|             } | ||||
|             setInfoText(infoText, infoSection.content); | ||||
|  | ||||
|   | ||||
| @@ -16,6 +16,28 @@ | ||||
|  | ||||
| RED.utils = (function() { | ||||
|  | ||||
|     window._marked = window.marked; | ||||
|     window.marked = function(txt) { | ||||
|         console.warn("Use of 'marked()' is deprecated. Use RED.utils.renderMarkdown() instead"); | ||||
|         return renderMarkdown(txt); | ||||
|     } | ||||
|  | ||||
|     _marked.setOptions({ | ||||
|         renderer: new _marked.Renderer(), | ||||
|         gfm: true, | ||||
|         tables: true, | ||||
|         breaks: false, | ||||
|         pedantic: false, | ||||
|         smartLists: true, | ||||
|         smartypants: false | ||||
|     }); | ||||
|  | ||||
|     function renderMarkdown(txt) { | ||||
|         var rendered = _marked(txt); | ||||
|         var cleaned = DOMPurify.sanitize(rendered, {SAFE_FOR_JQUERY: true}) | ||||
|         return cleaned; | ||||
|     } | ||||
|  | ||||
|     function formatString(str) { | ||||
|         return str.replace(/\r?\n/g,"↵").replace(/\t/g,"→"); | ||||
|     } | ||||
| @@ -1053,6 +1075,7 @@ RED.utils = (function() { | ||||
|         decodeObject: decodeObject, | ||||
|         parseContextKey: parseContextKey, | ||||
|         createIconElement: createIconElement, | ||||
|         sanitize: sanitize | ||||
|         sanitize: sanitize, | ||||
|         renderMarkdown: renderMarkdown | ||||
|     } | ||||
| })(); | ||||
|   | ||||
| @@ -67,9 +67,16 @@ RED.view.tools = (function() { | ||||
|  | ||||
|     function moveSelection(dx,dy) { | ||||
|         if (moving_set === null) { | ||||
|             moving_set = []; | ||||
|             var selection = RED.view.selection(); | ||||
|             if (selection.nodes) { | ||||
|                 moving_set = selection.nodes.map(function(n) { return {n:n}}); | ||||
|                 while (selection.nodes.length > 0) { | ||||
|                     var n = selection.nodes.shift(); | ||||
|                     moving_set.push({n:n}); | ||||
|                     if (n.type === "group") { | ||||
|                         selection.nodes = selection.nodes.concat(n.nodes); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (moving_set && moving_set.length > 0) { | ||||
| @@ -93,6 +100,9 @@ RED.view.tools = (function() { | ||||
|                 node.n.x += dx; | ||||
|                 node.n.y += dy; | ||||
|                 node.n.dirty = true; | ||||
|                 if (node.n.type === "group") { | ||||
|                     RED.group.markDirty(node.n); | ||||
|                 } | ||||
|                 minX = Math.min(node.n.x-node.n.w/2-5,minX); | ||||
|                 minY = Math.min(node.n.y-node.n.h/2-5,minY); | ||||
|             } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -284,3 +284,8 @@ $debug-message-border: #eee; | ||||
| $debug-message-border-hover: #999; | ||||
| $debug-message-border-warning: #ffdf9d; | ||||
| $debug-message-border-error: #f99; | ||||
|  | ||||
| $group-default-fill: none; | ||||
| $group-default-fill-opacity: 1; | ||||
| $group-default-stroke: #999; | ||||
| $group-default-stroke-opacity: 1; | ||||
|   | ||||
| @@ -411,6 +411,133 @@ button.red-ui-button.red-ui-editor-node-appearance-button { | ||||
|     } | ||||
| } | ||||
|  | ||||
| .red-ui-group-layout-picker { | ||||
|     padding: 5px; | ||||
|     background: $primary-background; | ||||
| } | ||||
| .red-ui-group-layout-picker-cell-text { | ||||
|     position: absolute; | ||||
|     width: 14px; | ||||
|     height: 2px; | ||||
|     border-top: 2px solid $secondary-text-color; | ||||
|     border-bottom: 2px solid $secondary-text-color; | ||||
|     margin: 2px; | ||||
|  | ||||
|     &.red-ui-group-layout-text-pos-nw { top: 0; left: 0; } | ||||
|     &.red-ui-group-layout-text-pos-n  { top: 0; left: calc(50% - 9px); } | ||||
|     &.red-ui-group-layout-text-pos-ne { top: 0; right: 0; } | ||||
|     &.red-ui-group-layout-text-pos-sw { bottom: 0; left: 0; } | ||||
|     &.red-ui-group-layout-text-pos-s { bottom: 0; left: calc(50% - 9px); } | ||||
|     &.red-ui-group-layout-text-pos-se { bottom: 0; right: 0; } | ||||
|     &.red-ui-group-layout-text-pos- { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         border-radius: 5px; | ||||
|         margin: 0; | ||||
|         background-color: #FFF; | ||||
|         background-size: 100% 100%; | ||||
|         background-position: 0 0, 50% 50%; | ||||
|         background-image: linear-gradient(45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%,  transparent 55%, transparent),linear-gradient(-45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%,  transparent 55%, transparent); | ||||
|         border: none; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .red-ui-group-layout-picker button.red-ui-search-result-node { | ||||
|     float: none; | ||||
|     position: relative; | ||||
|     padding: 0; | ||||
|     margin: 5px; | ||||
|     width: 32px; | ||||
|     height: 27px; | ||||
| } | ||||
|  | ||||
| button.red-ui-group-layout-picker-none { | ||||
|     width: 100%; | ||||
| } | ||||
|  | ||||
| .red-ui-color-picker { | ||||
|     input[type="text"] { | ||||
|         border-radius:0; | ||||
|         width: 100%; | ||||
|         margin-bottom: 0; | ||||
|         border: none; | ||||
|         border-bottom: 1px solid $form-input-border-color; | ||||
|     } | ||||
|     small { | ||||
|         color: $secondary-text-color; | ||||
|         margin-left: 5px; | ||||
|         margin-right: 4px; | ||||
|         display: inline-block; | ||||
|         min-width: 35px; | ||||
|         text-align: right; | ||||
|     } | ||||
|     background: $primary-background; | ||||
| } | ||||
| .red-ui-editor-node-appearance-button { | ||||
|     .red-ui-search-result-node { | ||||
|         overflow: hidden | ||||
|     } | ||||
| } | ||||
| .red-ui-color-picker-cell { | ||||
|     padding: 0; | ||||
|     border-style: solid; | ||||
|     border-width: 1px; | ||||
|     border-color: $secondary-border-color; | ||||
| } | ||||
| .red-ui-color-picker-swatch { | ||||
|     position: absolute; | ||||
|     top:-1px;right:-1px;left:-1px;bottom:-1px; | ||||
|     border-radius: 4px; | ||||
| } | ||||
|  | ||||
| .red-ui-color-picker-cell-none { | ||||
|     height: 100%; | ||||
|     background-color: #FFF; | ||||
|     background-size: 100% 100%; | ||||
|     background-position: 0 0, 50% 50%; | ||||
|     background-image: linear-gradient(45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%,  transparent 55%, transparent),linear-gradient(-45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%,  transparent 55%, transparent) | ||||
| } | ||||
| .red-ui-search-result-node .red-ui-color-picker-cell-none { | ||||
|     border-radius: 4px; | ||||
|     background-size: 50% 50%; | ||||
|     background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee), linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee); | ||||
| } | ||||
|  | ||||
| .red-ui-color-picker-opacity-slider { | ||||
|     position:relative; | ||||
|     vertical-align: middle; | ||||
|     display: inline-block; | ||||
|     width: calc(100% - 50px); | ||||
|     height: 14px; | ||||
|     margin: 6px 3px 8px; | ||||
|     box-sizing: border-box; | ||||
|     background-color: white; | ||||
|     background-image: | ||||
|         linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 25%), | ||||
|         linear-gradient(-45deg, #eee 25%, transparent 25%, transparent 75%, #eee 25%); | ||||
|     background-size: 6px 6px; | ||||
| } | ||||
| .red-ui-color-picker-opacity-slider-overlay { | ||||
|     position: absolute; | ||||
|     top:0;right:0;left:0;bottom:0; | ||||
|     background-image:linear-gradient(90deg, transparent 0%, #f00 100%); | ||||
|     background-size: 100% 100%; | ||||
|     border: 1px solid $primary-border-color; | ||||
| } | ||||
|  | ||||
| div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle { | ||||
|     z-Index: 10; | ||||
|     top: -4px; | ||||
|     cursor: pointer; | ||||
|     min-width: 0; | ||||
|     width: 10px; | ||||
|     height: 22px; | ||||
|     padding: 0; | ||||
|     border: 1px solid $primary-border-color; | ||||
|     border-radius: 1px; | ||||
|     background: $secondary-background; | ||||
|     box-sizing: border-box; | ||||
| } | ||||
| .red-ui-icon-picker { | ||||
|     select { | ||||
|         box-sizing: border-box; | ||||
|   | ||||
| @@ -71,6 +71,48 @@ | ||||
|     } | ||||
| } | ||||
|  | ||||
| .red-ui-flow-group { | ||||
|     &.red-ui-flow-group-hovered { | ||||
|         .red-ui-flow-group-outline-select { | ||||
|             stroke-opacity: 0.8 !important; | ||||
|             stroke-dasharray: 10 4 !important; | ||||
|         } | ||||
|     } | ||||
|     &.red-ui-flow-group-active-hovered:not(.red-ui-flow-group-hovered) { | ||||
|         .red-ui-flow-group-outline-select { | ||||
|             stroke: $link-link-color; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .red-ui-flow-group-outline { | ||||
|     fill: none; | ||||
|     stroke: $node-selected-color; | ||||
|     stroke-opacity: 0; | ||||
|     stroke-width: 12; | ||||
|     pointer-events: stroke; | ||||
| } | ||||
| .red-ui-flow-group-outline-select { | ||||
|     fill: none; | ||||
|     stroke: $node-selected-color; | ||||
|     pointer-events: stroke; | ||||
|     stroke-opacity: 0; | ||||
|     stroke-width: 3; | ||||
| } | ||||
| .red-ui-flow-group-body { | ||||
|     pointer-events: none; | ||||
|     fill: $group-default-fill; | ||||
|     fill-opacity: $group-default-fill-opacity; | ||||
|     stroke-width: 2; | ||||
|     stroke: $group-default-stroke; | ||||
|     stroke-opacity: $group-default-stroke-opacity; | ||||
| } | ||||
| .red-ui-flow-group-label { | ||||
|     @include disable-selection; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| .red-ui-flow-node-unknown { | ||||
|     stroke-dasharray:10,4; | ||||
|     stroke: $node-border-unknown; | ||||
| @@ -248,6 +290,7 @@ g.red-ui-flow-node-selected { | ||||
|  | ||||
| .red-ui-flow-link-outline { | ||||
|     stroke: $view-background; | ||||
|     stroke-opacity: 0.4; | ||||
|     stroke-width: 5; | ||||
|     cursor: crosshair; | ||||
|     fill: none; | ||||
|   | ||||
| @@ -32,6 +32,9 @@ | ||||
|         right: 5px; | ||||
|         top: 9px; | ||||
|     } | ||||
|     form.red-ui-searchBox-form { | ||||
|         margin: 0; | ||||
|     } | ||||
|     input.red-ui-searchBox-input { | ||||
|         border-radius: 0; | ||||
|         border: none; | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
|         var length = str.length; | ||||
|         var start = 0; | ||||
|         var inString = false; | ||||
|         var inRegex = false; | ||||
|         var inBox = false; | ||||
|         var quoteChar; | ||||
|         var list = []; | ||||
| @@ -24,8 +25,13 @@ | ||||
|         } | ||||
|         for (var i=0;i<length;i++) { | ||||
|             var c = str[i]; | ||||
|             if (!inString) { | ||||
|                 if (c === "'" || c === '"') { | ||||
|             if (!inString && !inRegex) { | ||||
|                 if (c === "/") { | ||||
|                     inRegex = true; | ||||
|                     frame = {type:"regex",pos:i}; | ||||
|                     list.push(frame); | ||||
|                     stack.push(frame); | ||||
|                 } else if (c === "'" || c === '"') { | ||||
|                     inString = true; | ||||
|                     quoteChar = c; | ||||
|                     frame = {type:"string",pos:i}; | ||||
| @@ -37,6 +43,9 @@ | ||||
|                 } else if (c === ",") { | ||||
|                     frame = {type:",",pos:i}; | ||||
|                     list.push(frame); | ||||
|                 } else if (c === "&") { | ||||
|                     frame = {type:"&",pos:i}; | ||||
|                     list.push(frame); | ||||
|                 } else if (/[\(\[\{]/.test(c)) { | ||||
|                     frame = {type:"open-block",char:c,pos:i}; | ||||
|                     list.push(frame); | ||||
| @@ -44,7 +53,8 @@ | ||||
|                 } else if (/[\}\)\]]/.test(c)) { | ||||
|                     var oldFrame = stack.pop(); | ||||
|                     if (matchingBrackets[oldFrame.char] !== c) { | ||||
|                         //console.log("Stack frame mismatch",c,"at",i,"expected",matchingBrackets[oldFrame.char],"from",oldFrame.pos); | ||||
|                         // console.log("Stack frame mismatch",c,"at",i,"expected",matchingBrackets[oldFrame.char],"from",oldFrame.pos); | ||||
|                         // console.log(list); | ||||
|                         return str; | ||||
|                     } | ||||
|                     //console.log("Closing",c,"at",i,"compare",oldFrame.type,oldFrame.pos); | ||||
| @@ -53,19 +63,32 @@ | ||||
|                     list.push(frame); | ||||
|                 } | ||||
|             } else { | ||||
|                 if (c === quoteChar) { | ||||
|                     // Next char must be a ] | ||||
|                     inString = false; | ||||
|                     stack.pop(); | ||||
|                 if (c === "\\") { | ||||
|                     // an escaped char - stay in current mode and skip the next char | ||||
|                     i++; | ||||
|                 } | ||||
|                 if (inString) { | ||||
|                     if (c === quoteChar) { | ||||
|                         // Next char must be a ] | ||||
|                         inString = false; | ||||
|                         var f = stack.pop(); | ||||
|                         f.end = i; | ||||
|                     } | ||||
|                 } else if (inRegex) { | ||||
|                     if (c === "/") { | ||||
|                         inRegex = false; | ||||
|                         var f = stack.pop(); | ||||
|                         f.end = i; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         // console.log(stack); | ||||
|         // console.log("list",list); | ||||
|  | ||||
|         var result = str; | ||||
|         var indent = 0; | ||||
|         var offset = 0; | ||||
|         var pre,post,indented; | ||||
|         var pre,post,indented,hasNewline; | ||||
|         var longStack = []; | ||||
|         list.forEach(function(f) { | ||||
|             if (f.type === ";" || f.type === ",") { | ||||
| @@ -73,29 +96,51 @@ | ||||
|                     pre = result.substring(0,offset+f.pos+1); | ||||
|                     post = result.substring(offset+f.pos+1); | ||||
|                     indented = indentLine(post,indent); | ||||
|                     result = pre+"\n"+indented; | ||||
|                     offset += indented.length-post.length+1; | ||||
|                     hasNewline = /\n$/.test(pre); | ||||
|                     // console.log("A§"+pre+"§\n§"+indented+"§",hasNewline); | ||||
|                     result = pre+(hasNewline?"":"\n")+indented; | ||||
|                     offset += indented.length-post.length+(hasNewline?0:1); | ||||
|                 } | ||||
|             } else if (f.type === "&") { | ||||
|                 pre = result.substring(0,offset+f.pos+1); | ||||
|                 var lastLineBreak = pre.lastIndexOf("\n"); | ||||
|                 var lineLength = pre.length - lastLineBreak; | ||||
|                 if (lineLength > 70) { | ||||
|                     post = result.substring(offset+f.pos+1); | ||||
|                     if (!/^\n/.test(post)) { | ||||
|                         indented = indentLine(post,indent); | ||||
|                         hasNewline = /\n$/.test(pre); | ||||
|                         result = pre+(hasNewline?"":"\n")+indented; | ||||
|                         offset += indented.length-post.length+(hasNewline?0:1); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             } else if (f.type === "open-block") { | ||||
|                 if (f.width > 30) { | ||||
|                 if (f.width > 40) { | ||||
|                     longStack.push(true); | ||||
|                     indent += 4; | ||||
|                     pre = result.substring(0,offset+f.pos+1); | ||||
|                     post = result.substring(offset+f.pos+1); | ||||
|                     hasNewline = /\n$/.test(pre); | ||||
|                     indented = indentLine(post,indent); | ||||
|                     result = pre+"\n"+indented; | ||||
|                     offset += indented.length-post.length+1; | ||||
|                     result = pre+(hasNewline?"":"\n")+indented; | ||||
|                     offset += indented.length-post.length+(hasNewline?0:1); | ||||
|                 } else { | ||||
|                     longStack.push(false); | ||||
|                 } | ||||
|             } else if (f.type === "close-block") { | ||||
|                 if (f.width > 30) { | ||||
|                 if (f.width > 40) { | ||||
|                     indent -= 4; | ||||
|                     pre = result.substring(0,offset+f.pos); | ||||
|                     post = result.substring(offset+f.pos); | ||||
|                     indented = indentLine(post,indent); | ||||
|                     result = pre+"\n"+indented; | ||||
|                     offset += indented.length-post.length+1; | ||||
|                     hasNewline = /\n *$/.test(pre); | ||||
|                     if (hasNewline) { | ||||
|                         result = pre + post; | ||||
|                     } else { | ||||
|                         result = pre+"\n"+indented; | ||||
|                         offset += indented.length-post.length+1; | ||||
|                     } | ||||
|                 } | ||||
|                 longStack.pop(); | ||||
|             } | ||||
|   | ||||
| @@ -28,6 +28,11 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m | ||||
|         }, "identifier"); | ||||
|         this.$rules = { | ||||
|             "start" : [ | ||||
|                 { | ||||
|                     token: "string.regexp", | ||||
|                     regex: "\\/", | ||||
|                     next: "regex" | ||||
|                 }, | ||||
|                 { | ||||
|                     token : "string", | ||||
|                     regex : "'(?=.)", | ||||
| @@ -46,34 +51,35 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m | ||||
|                     token : "constant.numeric", // float | ||||
|                     regex : /[+-]?\d[\d_]*(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/ | ||||
|                 }, | ||||
|                 {   token: "keyword", | ||||
|                 regex: /λ/ | ||||
|             }, | ||||
|             { | ||||
|                 token: "keyword", | ||||
|                 regex: jsonataFunctions | ||||
|             }, | ||||
|             { | ||||
|                 token : keywordMapper, | ||||
|                 regex : "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*" | ||||
|             }, | ||||
|             { | ||||
|                 token : "punctuation.operator", | ||||
|                 regex : /[.](?![.])/ | ||||
|             }, | ||||
|             { | ||||
|                 token : "keyword.operator", | ||||
|                 regex : /\|\||<=|>=|\.\.|\*\*|!=|:=|[=<>`!$%&*+\-~\/^]/, | ||||
|                 next  : "start" | ||||
|             }, | ||||
|             { | ||||
|                 token : "punctuation.operator", | ||||
|                 regex : /[?:,;.]/, | ||||
|                 next  : "start" | ||||
|             }, | ||||
|             { | ||||
|                 token : "paren.lparen", | ||||
|                 regex : /[\[({]/, | ||||
|                 { | ||||
|                     token: "keyword", | ||||
|                     regex: /λ/ | ||||
|                 }, | ||||
|                 { | ||||
|                     token: "keyword", | ||||
|                     regex: jsonataFunctions | ||||
|                 }, | ||||
|                 { | ||||
|                     token : keywordMapper, | ||||
|                     regex : "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*" | ||||
|                 }, | ||||
|                 { | ||||
|                     token : "punctuation.operator", | ||||
|                     regex : /[.](?![.])/ | ||||
|                 }, | ||||
|                 { | ||||
|                     token : "keyword.operator", | ||||
|                     regex : /\|\||<=|>=|\.\.|\*\*|!=|:=|[=<>`!$%&*+\-~\/^]/, | ||||
|                     next  : "start" | ||||
|                 }, | ||||
|                 { | ||||
|                     token : "punctuation.operator", | ||||
|                     regex : /[?:,;.]/, | ||||
|                     next  : "start" | ||||
|                 }, | ||||
|                 { | ||||
|                     token : "paren.lparen", | ||||
|                     regex : /[\[({]/, | ||||
|                     next  : "start" | ||||
|                 }, | ||||
|                 { | ||||
| @@ -86,7 +92,8 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m | ||||
|                     token : "string", | ||||
|                     regex : '"|$', | ||||
|                     next  : "start" | ||||
|                 }, { | ||||
|                 }, | ||||
|                 { | ||||
|                     defaultToken: "string" | ||||
|                 } | ||||
|             ], | ||||
| @@ -95,9 +102,24 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m | ||||
|                     token : "string", | ||||
|                     regex : "'|$", | ||||
|                     next  : "start" | ||||
|                 }, { | ||||
|                 }, | ||||
|                 { | ||||
|                     defaultToken: "string" | ||||
|                 } | ||||
|             ], | ||||
|             "regex" : [ | ||||
|                 { | ||||
|                     token: "string.regexp", | ||||
|                     regex: "\\\\/" | ||||
|                 }, | ||||
|                 { | ||||
|                     token: "string.regexp", | ||||
|                     regex: "/[sxngimy]*", | ||||
|                     next: "start" | ||||
|                 }, | ||||
|                 { | ||||
|                     defaultToken: "string.regexp" | ||||
|                 } | ||||
|             ] | ||||
|         }; | ||||
|     }; | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -457,7 +457,7 @@ RED.debug = (function() { | ||||
|         var metaRow = $('<div class="red-ui-debug-msg-meta"></div>').appendTo(msg); | ||||
|         $('<span class="red-ui-debug-msg-date">'+ getTimestamp()+'</span>').appendTo(metaRow); | ||||
|         if (sourceNode) { | ||||
|             $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text('node: '+sanitize(o.name||sourceNode.name||sourceNode.id)) | ||||
|             $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text('node: '+(o.name||sourceNode.name||sourceNode.id)) | ||||
|             .appendTo(metaRow) | ||||
|             .on("click", function(evt) { | ||||
|                 evt.preventDefault(); | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
|     <div class="form-row"> | ||||
|         <label data-i18n="trigger.send" for="node-input-op1"></label> | ||||
|         <input type="hidden" id="node-input-op1type"> | ||||
|         <input style="width: 70%" type="text" id="node-input-op1" placeholder="1"> | ||||
|         <input style="width:70%" type="text" id="node-input-op1" placeholder="1"> | ||||
|     </div> | ||||
|     <div class="form-row"> | ||||
|         <label data-i18n="trigger.then"></label> | ||||
| @@ -40,12 +40,12 @@ | ||||
|     </div> | ||||
|     <div class="form-row node-type-wait"> | ||||
|     <label></label> | ||||
|         <input type="checkbox" id="node-input-extend" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;" for="node-input-extend" data-i18n="trigger.extend"></label> | ||||
|         <input type="checkbox" id="node-input-extend" style="margin-left:0px; vertical-align:top; width:auto !important;"> <label style="width:auto !important;" for="node-input-extend" data-i18n="trigger.extend"></label> | ||||
|     </div> | ||||
|     <div class="form-row node-type-wait"> | ||||
|         <label data-i18n="trigger.then-send"></label> | ||||
|         <input type="hidden" id="node-input-op2type"> | ||||
|         <input style="width: 70%" type="text" id="node-input-op2" placeholder="0"> | ||||
|         <input style="width:70%" type="text" id="node-input-op2" placeholder="0"> | ||||
|     </div> | ||||
|     <div class="form-row"> | ||||
|         <label data-i18n="trigger.label.reset" style="width:auto"></label> | ||||
| @@ -109,9 +109,11 @@ | ||||
|                     $(".node-type-duration").hide(); | ||||
|                 } | ||||
|                 else if ($(this).val() == "loop") { | ||||
|                     if ($("#node-input-duration").val() == 0) { $("#node-input-duration").val(250); } | ||||
|                     $(".node-type-wait").hide(); | ||||
|                     $(".node-type-duration").show(); | ||||
|                 } else { | ||||
|                     if ($("#node-input-duration").val() == 0) { $("#node-input-duration").val(250); } | ||||
|                     $(".node-type-wait").show(); | ||||
|                     $(".node-type-duration").show(); | ||||
|                 } | ||||
| @@ -175,9 +177,7 @@ | ||||
|             } | ||||
|             if ($("#node-then-type").val() == "loop") { | ||||
|                 $("#node-input-duration").val($("#node-input-duration").val() * -1); | ||||
|             } | ||||
|  | ||||
|  | ||||
|             }     | ||||
|         } | ||||
|     }); | ||||
| </script> | ||||
|   | ||||
| @@ -76,6 +76,7 @@ module.exports = function(RED) { | ||||
|         var node = this; | ||||
|         node.topics = {}; | ||||
|  | ||||
|         var npay = {}; | ||||
|         var pendingMessages = []; | ||||
|         var activeMessagePromise = null; | ||||
|         var processMessageQueue = function(msg) { | ||||
| @@ -124,6 +125,7 @@ module.exports = function(RED) { | ||||
|                 node.status({}); | ||||
|             } | ||||
|             else { | ||||
|                 if (node.op2type === "payl") { npay[topic] = RED.util.cloneMessage(msg); } | ||||
|                 if (((!node.topics[topic].tout) && (node.topics[topic].tout !== 0)) || (node.loop === true)) { | ||||
|                     promise = Promise.resolve(); | ||||
|                     if (node.op2type === "pay") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); } | ||||
| @@ -188,7 +190,14 @@ module.exports = function(RED) { | ||||
|                                                 }); | ||||
|                                             } | ||||
|                                             promise.then(() => { | ||||
|                                                 msg2.payload = node.topics[topic].m2; | ||||
|                                                 if (node.op2type === "payl") { | ||||
|                                                     node.send(npay[topic]); | ||||
|                                                     delete npay[topic]; | ||||
|                                                 } | ||||
|                                                 else { | ||||
|                                                     msg2.payload = node.topics[topic].m2; | ||||
|                                                     node.send(msg2); | ||||
|                                                 } | ||||
|                                                 delete node.topics[topic]; | ||||
|                                                 if (node.op2type === "payl") { node.send(npay); } | ||||
|                                                 else { node.send(msg2); } | ||||
|   | ||||
| @@ -145,7 +145,7 @@ module.exports = function(RED) { | ||||
|                             if (error.signal) { msg3.payload.signal = error.signal; } | ||||
|                             if (error.code === null) { node.status({fill:"red",shape:"dot",text:"killed"}); } | ||||
|                             else { node.status({fill:"red",shape:"dot",text:"error:"+error.code}); } | ||||
|                             node.log('error:' + error); | ||||
|                             if (RED.settings.verbose) { node.log('error:' + error); } | ||||
|                         } | ||||
|                         else if (node.oldrc === "false") { | ||||
|                             msg3 = RED.util.cloneMessage(msg); | ||||
|   | ||||
| @@ -153,7 +153,12 @@ module.exports = function(RED) { | ||||
|                     this.brokerurl="mqtt://"; | ||||
|                 } | ||||
|                 if (this.broker !== "") { | ||||
|                     this.brokerurl = this.brokerurl+this.broker+":"; | ||||
|                     //Check for an IPv6 address | ||||
|                     if (/(?:^|(?<=\s))(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(?=\s|$)/.test(this.broker)) { | ||||
|                         this.brokerurl = this.brokerurl+"["+this.broker+"]:"; | ||||
|                     } else { | ||||
|                         this.brokerurl = this.brokerurl+this.broker+":"; | ||||
|                     } | ||||
|                     // port now defaults to 1883 if unset. | ||||
|                     if (!this.port){ | ||||
|                         this.brokerurl = this.brokerurl+"1883"; | ||||
| @@ -464,6 +469,7 @@ module.exports = function(RED) { | ||||
|         this.broker = n.broker; | ||||
|         this.brokerConn = RED.nodes.getNode(this.broker); | ||||
|         var node = this; | ||||
|         var chk = /[\+#]/; | ||||
|  | ||||
|         if (this.brokerConn) { | ||||
|             this.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"}); | ||||
| @@ -482,6 +488,7 @@ module.exports = function(RED) { | ||||
|                 } | ||||
|                 if ( msg.hasOwnProperty("payload")) { | ||||
|                     if (msg.hasOwnProperty("topic") && (typeof msg.topic === "string") && (msg.topic !== "")) { // topic must exist | ||||
|                         if (chk.test(msg.topic)) { node.warn(RED._("mqtt.errors.invalid-topic")); } | ||||
|                         this.brokerConn.publish(msg, done);  // send the message | ||||
|                     } else { | ||||
|                         node.warn(RED._("mqtt.errors.invalid-topic")); | ||||
|   | ||||
| @@ -163,7 +163,7 @@ | ||||
|             if (root === "") { | ||||
|                 $("#node-config-ws-tip").hide(); | ||||
|             } else { | ||||
|                 $("#node-config-ws-path").html(root); | ||||
|                 $("#node-config-ws-path").html(RED._("node-red:websocket.tip.path2", { path: root })); | ||||
|                 $("#node-config-ws-tip").show(); | ||||
|             } | ||||
|         } | ||||
| @@ -235,7 +235,7 @@ | ||||
|     </div> | ||||
|     <div class="form-tips"> | ||||
|         <span data-i18n="[html]websocket.tip.path1"></span> | ||||
|         <p id="node-config-ws-tip"><span data-i18n="[html]websocket.tip.path2"></span><code><span id="node-config-ws-path"></span></code>.</p> | ||||
|         <p id="node-config-ws-tip"><span id="node-config-ws-path"></span></p> | ||||
|     </div> | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -292,7 +292,6 @@ module.exports = function(RED) { | ||||
|                 reduceMessageGroup(node,msgs,exp,fixup,count,result,done); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     } | ||||
|     function reduceAndSendGroup(node, group, done) { | ||||
|         var is_right = node.reduce_right; | ||||
| @@ -331,7 +330,7 @@ module.exports = function(RED) { | ||||
|             var pending_count = node.pending_count; | ||||
|             var gid = msg.parts.id; | ||||
|             var count; | ||||
|             if(!pending.hasOwnProperty(gid)) { | ||||
|             if (!pending.hasOwnProperty(gid)) { | ||||
|                 if(parts.hasOwnProperty('count')) { | ||||
|                     count = msg.parts.count; | ||||
|                 } | ||||
| @@ -361,7 +360,6 @@ module.exports = function(RED) { | ||||
|                 } | ||||
|                 return done(); | ||||
|             } | ||||
|  | ||||
|             if (msgs.length === group.count) { | ||||
|                 delete pending[gid]; | ||||
|                 pending_count -= msgs.length; | ||||
| @@ -408,7 +406,7 @@ module.exports = function(RED) { | ||||
|         if (this.joinerType === "str") { | ||||
|             this.joiner = this.joiner.replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\t/g,"\t").replace(/\\e/g,"\e").replace(/\\f/g,"\f").replace(/\\0/g,"\0"); | ||||
|         } else if (this.joinerType === "bin") { | ||||
|             var joinArray = JSON.parse(n.joiner) | ||||
|             var joinArray = JSON.parse(n.joiner || "[]"); | ||||
|             if (Array.isArray(joinArray)) { | ||||
|                 this.joiner = Buffer.from(joinArray); | ||||
|             } else { | ||||
| @@ -429,7 +427,7 @@ module.exports = function(RED) { | ||||
|  | ||||
|         var completeSend = function(partId) { | ||||
|             var group = inflight[partId]; | ||||
|             clearTimeout(group.timeout); | ||||
|             if (group.timeout) { clearTimeout(group.timeout); } | ||||
|             if ((node.accumulate !== true) || group.msg.hasOwnProperty("complete")) { delete inflight[partId]; } | ||||
|             if (group.type === 'array' && group.arrayLen > 1) { | ||||
|                 var newArray = []; | ||||
| @@ -448,6 +446,9 @@ module.exports = function(RED) { | ||||
|                             buffers.push(joinBuffer); | ||||
|                             bufferLen += joinBuffer.length; | ||||
|                         } | ||||
|                         if (!Buffer.isBuffer(group.payload[i])) {  | ||||
|                             group.payload[i] = Buffer.from(group.payload[i]); | ||||
|                         } | ||||
|                         buffers.push(group.payload[i]); | ||||
|                         bufferLen += group.payload[i].length; | ||||
|                     } | ||||
| @@ -629,7 +630,13 @@ module.exports = function(RED) { | ||||
|                 var group = inflight[partId]; | ||||
|                 if (payloadType === 'buffer') { | ||||
|                     if (property !== undefined) { | ||||
|                         inflight[partId].bufferLen += property.length; | ||||
|                         if (Buffer.isBuffer(property) || (typeof property === "string") || Array.isArray(property)) { | ||||
|                             inflight[partId].bufferLen += property.length; | ||||
|                         } | ||||
|                         else { | ||||
|                             node.error(RED._("join.errors.invalid-type",{error:(typeof property)}),msg); | ||||
|                             return; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if (payloadType === 'object') { | ||||
|   | ||||
| @@ -397,7 +397,7 @@ | ||||
|     "message" : "gesamte Nachricht", | ||||
|     "tip" : { | ||||
|       "path1" : "Standardmäßig enthält  <code> Nutzdaten </code>  die Daten, die über einen Websocket gesendet oder von einem Websocket empfangen werden. Der Listener kann so konfiguriert werden, dass er das gesamte Nachrichtenobjekt als eine JSON-formatierte Zeichenfolge sendet oder empfängt.", | ||||
|       "path2" : "Dieser Pfad ist relativ zu ", | ||||
|       "path2" : "Dieser Pfad ist relativ zu <code>__path__</code>.", | ||||
|       "url1" : "URL sollte ws: / & #47; oder wss: / & #47; Schema verwenden und auf einen vorhandenen Websocket-Listener verweisen.", | ||||
|       "url2" : "Standardmäßig enthält  <code> Nutzdaten </code>  die Daten, die über einen Websocket gesendet oder von einem Websocket empfangen werden. Der Client kann so konfiguriert werden, dass er das gesamte Nachrichtenobjekt als eine JSON-formatierte Zeichenfolge sendet oder empfängt." | ||||
|     }, | ||||
|   | ||||
| @@ -23,13 +23,13 @@ | ||||
|  | ||||
| <script type="text/html" data-help-name="websocket out"> | ||||
|     <p>WebSocket Ausgabe-Node.</p> | ||||
|     <p>Standardmäßig wird <code>msg.payload</code> über den WebSocket gesendet.  | ||||
|     <p>Standardmäßig wird <code>msg.payload</code> über den WebSocket gesendet. | ||||
|        Der Socket kann so konfiguriert werden, dass er das gesamte <code>msg</code> Objekt als JSON-String kodiert und über den WebSocket sendet.</p> | ||||
|  | ||||
|     <p>Wenn die an diesem Node ankommende Nachricht an einem WebSocket-Eingangs-Node begann, | ||||
|         wird die Nachricht an den Client zurückgesendet, der den Flow ausgelöst hat.  | ||||
|         wird die Nachricht an den Client zurückgesendet, der den Flow ausgelöst hat. | ||||
|         Andernfalls wird die Nachricht an alle verbundenen Clients gesendet..</p> | ||||
|     <p>Wenn eine Nachricht, die an einem WebSocket-Eingangsnoten gestartet wurde, an alle verbunden Clients gesendet werden soll,  | ||||
|     <p>Wenn eine Nachricht, die an einem WebSocket-Eingangsnoten gestartet wurde, an alle verbunden Clients gesendet werden soll, | ||||
|         muss die Eigenschaft <code>msg._session</code> innerhalb des Flow gelöscht werden.</p> | ||||
| </script> | ||||
|  | ||||
| @@ -37,30 +37,6 @@ | ||||
|    <p>Dieser Konfigurations-Node erstellt einen WebSocket Server-Endpunkt unter Verwendung des angegebenen Pfades.</p> | ||||
| </script> | ||||
|  | ||||
| <!-- WebSocket Client configuration node --> | ||||
| <script type="text/html" data-template-name="websocket-client"> | ||||
|     <div class="form-row"> | ||||
|         <label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label> | ||||
|         <input id="node-config-input-path" type="text" placeholder="ws://example.com/ws"> | ||||
|     </div> | ||||
|     <div class="form-row node-config-row-tls hide"> | ||||
|         <label for="node-config-input-tls" data-i18n="httpin.tls-config"></label> | ||||
|         <input type="text" id="node-config-input-tls"> | ||||
|     </div> | ||||
|  | ||||
|     <div class="form-row"> | ||||
|         <label for="node-config-input-wholemsg" data-i18n="websocket.sendrec"></label> | ||||
|         <select type="text" id="node-config-input-wholemsg" style="width: 70%;"> | ||||
|             <option value="false" data-i18n="websocket.payload"></option> | ||||
|             <option value="true" data-i18n="websocket.message"></option> | ||||
|         </select> | ||||
|     </div> | ||||
|     <div class="form-tips"> | ||||
|         <p><span data-i18n="[html]websocket.tip.url1"></span></p> | ||||
|         <span data-i18n="[html]websocket.tip.url2"></span> | ||||
|     </div> | ||||
| </script> | ||||
|  | ||||
| <script type="text/html" data-help-name="websocket-client"> | ||||
|    <p>Dieser Konfigurations-Node verbindet einen WebSocket-Client mit der angegebenen URL.</p> | ||||
| </script> | ||||
|   | ||||
| @@ -455,7 +455,7 @@ | ||||
|         "message": "entire message", | ||||
|         "tip": { | ||||
|             "path1": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The listener can be configured to send or receive the entire message object as a JSON formatted string.", | ||||
|             "path2": "This path will be relative to ", | ||||
|             "path2": "This path will be relative to <code>__path__</code>.", | ||||
|             "url1": "URL should use ws:// or wss:// scheme and point to an existing websocket listener.", | ||||
|             "url2": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The client can be configured to send or receive the entire message object as a JSON formatted string." | ||||
|         }, | ||||
|   | ||||
| @@ -41,5 +41,5 @@ | ||||
|     wait a fixed timeout from first reply and then return, sit and wait for data, or send then close the connection | ||||
|     immediately, without waiting for a reply.</p> | ||||
|     <p>The response will be output in <code>msg.payload</code> as a buffer, so you may want to .toString() it.</p> | ||||
|     <p>If you leave tcp host or port blank they must be set by using the <code>msg.host</code> and <code>msg.port</code> properties.</p> | ||||
|     <p>If you leave tcp host or port blank they must be set by using the <code>msg.host</code> and <code>msg.port</code> properties in every message sent to the node.</p> | ||||
| </script> | ||||
|   | ||||
| @@ -91,7 +91,8 @@ | ||||
|         </ul> | ||||
|         </dd> | ||||
|         <dt class="optional">complete</dt> | ||||
|         <dd>If set, the node will send its output message in its current state.</dd> | ||||
|         <dd>If set, the node will append the payload, and then send the output message in its current state.  | ||||
|             If you don't wish to append the payload, delete it from the msg.</dd> | ||||
|     </dl> | ||||
|     <h3>Details</h3> | ||||
|  | ||||
|   | ||||
| @@ -49,12 +49,6 @@ | ||||
|         <dd>The contents of the file as either a string or binary buffer.</dd> | ||||
|         <dt class="optional">filename <span class="property-type">string</span></dt> | ||||
|         <dd>If not configured in the node, this optional property sets the name of the file to be read.</dd> | ||||
|         <dt class="optional">error <span class="property-type">object</span></dt> | ||||
|         <dd><i>deprecated</i>: If enabled in the node, when the node hits an error | ||||
|             reading the file, it will send a message with no <code>payload</code> | ||||
|             and this <code>error</code> property set to the error details. This | ||||
|             mode of behaviour is deprecated and not enabled by default for new | ||||
|             instances of the node. See below for more information.</dd> | ||||
|     </dl> | ||||
|     <h3>Details</h3> | ||||
|     <p>The filename should be an absolute path, otherwise it will be relative to | ||||
| @@ -65,11 +59,5 @@ | ||||
|     <p>When split into multiple messages, each message will have a <code>parts</code> | ||||
|     property set, forming a complete message sequence.</p> | ||||
|     <p>Encoding of input data can be specified from list of encodings if output format is string.</p> | ||||
|     <h4>Legacy error handling</h4> | ||||
|     <p>Before Node-RED 0.17, if this node hit an error whilst reading the file, it would | ||||
|     send a message with no <code>msg.payload</code> and <code>msg.error</code> set to the | ||||
|     details of the error. This is a deprecated mode of behaviour for the node that new | ||||
|     instances will not do. If required, this mode can be re-enabled within the node | ||||
|     configuration.</p> | ||||
|     <p>Errors should be caught and handled using a Catch node.</p> | ||||
| </script> | ||||
|   | ||||
| @@ -455,7 +455,7 @@ | ||||
|         "message": "メッセージ全体を送信/受信", | ||||
|         "tip": { | ||||
|             "path1": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。", | ||||
|             "path2": "This path will be relative to ", | ||||
|             "path2": "このパスは <code>__path__</code> の相対パスになります。", | ||||
|             "url1": "URLには ws:// または wss:// スキーマを使用して、存在するwebsocketリスナを設定してください。", | ||||
|             "url2": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。" | ||||
|         }, | ||||
| @@ -892,7 +892,8 @@ | ||||
|             "fixup": "最終調整式" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "invalid-expr": "JSONata式が不正: __error__" | ||||
|             "invalid-expr": "JSONata式が不正: __error__", | ||||
|             "invalid-type": "__error__ をバッファに連結できません" | ||||
|         } | ||||
|     }, | ||||
|     "sort": { | ||||
|   | ||||
| @@ -79,7 +79,7 @@ | ||||
|         </ul> | ||||
|         </dd> | ||||
|         <dt class="optional">complete</dt> | ||||
|         <dd>設定されている場合、保持しているメッセージを結合して送信します。</dd> | ||||
|         <dd>設定されている場合、本ノードはペイロードを追加し、保持しているメッセージを送信します。ペイロードを追加したくない場合は、msgから削除してください。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|  | ||||
|   | ||||
| @@ -44,8 +44,6 @@ | ||||
|         <dd>ファイルの内容を文字列もしくはバッファで表現します</dd> | ||||
|         <dt class="optional">filename <span class="property-type">文字列</span></dt> | ||||
|         <dd>読み出し対象のファイル名をノードに設定していない場合、このプロパティでファイルを指定します</dd> | ||||
|         <dt class="optional">error <span class="property-type">オブジェクト</span></dt> | ||||
|         <dd><i>非推奨</i>: 設定で有効にした場合、ファイルの読み込み時にエラーが発生すると<code>payload</code>を持たず<code>error</code>プロパティにエラーの詳細情報を設定したメッセージを送信します。この動作モードは非推奨であり、新しいノード実装ではデフォルトでは無効としています。詳細については、以下を参照してください。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>ファイルネームは絶対パスでの指定を推奨します。絶対パスを指定しない場合は、Node-REDプロセスのワーキングディレクトリからの相対パスとして扱います。</p> | ||||
| @@ -53,7 +51,5 @@ | ||||
|     <p>テキストファイルの場合、行毎に分割して各々メッセージを送信することができます。また、バイナリファイルの場合、小さな塊のバッファに分割して送信できます。バッファの分割単位はオペレーティングシステム依存ですが、一般に64k(Linux/Mac)もしくは41k(Windows)です。</p> | ||||
|     <p>複数のメッセージに分割する場合、各メッセージには<code>parts</code>プロパティが設定され、メッセージ列を構成します。</p> | ||||
|     <p>出力形式が文字列の場合、入力データのエンコーディングをエンコーディングリストから選択できます。</p> | ||||
|     <h4>旧式のエラー処理</h4> | ||||
|     <p>Node-RED 0.17より前の版では、ファイルの読み込み時にエラーが発生すると<code>payload</code>を持たず<code>error</code>プロパティにエラーの詳細情報を設定したメッセージを送信します。この動作モードは非推奨であり、新しいノード実装ではデフォルトでは無効としています。ノードの設定により、必要に応じてこのモードを有効にできます。</p> | ||||
|     <p>エラーはcatchノードで補足して処理することを推奨します。</p> | ||||
| </script> | ||||
|   | ||||
| @@ -446,7 +446,7 @@ | ||||
|         "message": "메세지 전체를 송신/수신", | ||||
|         "tip": { | ||||
|             "path1": "표준으로는 <code>payload</code> 가 websocket에서 송신, 수신된 데이터를 기다립니다. 클라이언트는 JSON형식의 문자열로 메세지전체를 송신, 수신하도록 설정할 수 있습니다.", | ||||
|             "path2": "This path will be relative to ", | ||||
|             "path2": "This path will be relative to <code>__path__</code>.", | ||||
|             "url1": "URL에는 ws:// 또는 wss:// 스키마를 사용하여, 존재하는 websocket리스너를 설정해 주세요.", | ||||
|             "url2": "표준으로는 <code>payload</code> 가 websocket에서 송신,수신될 데이터를 기다립니다.클라이언트는 JSON형식의 문자열로 메세지전체를 송신, 수신하도록 설정할 수 있습니다." | ||||
|         }, | ||||
|   | ||||
| @@ -455,7 +455,7 @@ | ||||
|         "message": "完整信息", | ||||
|         "tip": { | ||||
|             "path1": "默认情况下,<code>payload</code>将包含要发送或从Websocket接收的数据。侦听器可以配置为以JSON格式的字符串发送或接收整个消息对象.", | ||||
|             "path2": "这条路径将相对于 ", | ||||
|             "path2": "这条路径将相对于 <code>__path__</code>.", | ||||
|             "url1": "URL 应该使用ws://或者wss://方案并指向现有的websocket侦听器.", | ||||
|             "url2": "默认情况下,<code>payload</code> 将包含要发送或从Websocket接收的数据。可以将客户端配置为以JSON格式的字符串发送或接收整个消息对象." | ||||
|         }, | ||||
| @@ -698,7 +698,7 @@ | ||||
|             "output": "输出", | ||||
|             "includerow": "包含列名行", | ||||
|             "newline": "换行符", | ||||
|             "usestrings": "parse numerical values" | ||||
|             "usestrings": "解析数值" | ||||
|         }, | ||||
|         "placeholder": { | ||||
|             "columns": "用逗号分割列名" | ||||
| @@ -898,7 +898,7 @@ | ||||
|         } | ||||
|     }, | ||||
|     "sort" : { | ||||
|         "sort": "sort", | ||||
|         "sort": "排序", | ||||
|         "target" : "排序属性", | ||||
|         "seq" : "信息队列", | ||||
|         "key" : "键值", | ||||
| @@ -907,9 +907,9 @@ | ||||
|         "ascending" : "升序", | ||||
|         "descending" : "降序", | ||||
|         "as-number" : "作为数值", | ||||
|         "invalid-exp" : "sort节点中存在无效的JSONata表达式", | ||||
|         "too-many" : "sort节点中有太多待定信息", | ||||
|         "clear" : "清空sort节点中的待定信息" | ||||
|         "invalid-exp" : "排序节点中存在无效的JSONata表达式", | ||||
|         "too-many" : "排序节点中有太多待定信息", | ||||
|         "clear" : "清空排序节点中的待定信息" | ||||
|     }, | ||||
|     "batch" : { | ||||
|         "batch": "batch", | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="file"> | ||||
| <script type="text/html" data-help-name="file"> | ||||
|     <p>将<code>msg.payload</code>写入文件,添加到末尾或替换现有内容。或者,它也可以删除文件。</p> | ||||
|     <h3>输入</h3> | ||||
|     <dl class="message-properties"> | ||||
| @@ -31,7 +31,7 @@ | ||||
|     <p>您可以将此节点配置为删除文件。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="file in"> | ||||
| <script type="text/html" data-help-name="file in"> | ||||
|     <p>以字符串或二进制缓冲区的形式读取文件的内容。</p> | ||||
|     <h3>输入</h3> | ||||
|     <dl class="message-properties"> | ||||
| @@ -44,8 +44,6 @@ | ||||
|         <dd>文件的内容可以是字符串,也可以是二进制的buffer。</dd> | ||||
|         <dt class="optional">filename <span class="property-type">字符串</span></dt> | ||||
|         <dd>如果未在节点配置中设置,该属性可以选择要读取的文件名。</dd> | ||||
|         <dt class="optional">error <span class="property-type">object</span></dt> | ||||
|         <dd><i>已不推荐使用</i>: 如果在节点中启用,则当节点在读取文件时遇到错误时,它将发送一条没有<code>有效荷载</code>的消息,且将消息的<code>error</code>属性设置为错误的详细信息。在默认情况下,此行为模式已弃用且未启用。 请参阅下面的详细信息。</dd> | ||||
|     </dl> | ||||
|     <h3>详细</h3> | ||||
|     <p>文件名应该是绝对路径,否则将相对于Node-RED进程的工作目录。</p> | ||||
| @@ -53,7 +51,5 @@ | ||||
|     <p>可以选择将文本文件拆分为几行,每行输出一条消息,或者将二进制文件拆分为较小的buffer块-块大小取决于操作系统,但通常为64k(Linux/Mac)或41k(Windows)。</p> | ||||
|     <p>当拆分为多条消息时,每条消息将具有<code>parts</code>属性集,从而形成完整的消息序列。</p> | ||||
|     <p>如果输出格式为字符串,则可以从编码列表中指定输入数据的编码。</p> | ||||
|     <h4>旧版的错误处理</h4> | ||||
|     <p>在Node-RED 0.17之前,如果此节点在读取文件时遇到错误,它将发送一条不包含<code>msg.payload</code>,但包含<code>msg.error</code>的消息。在<code>msg.error</code>中记录详细的错误内容。但这是模式已被弃用,默认未启用。如有需要,您可以在节点配置中重新启用该模式。</p> | ||||
|     <p>应该使用Catch节点来捕获并处理错误。</p> | ||||
| </script> | ||||
|   | ||||
							
								
								
									
										35
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/20-inject.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/20-inject.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="inject"> | ||||
|   <p>手動或定期得將消息注入流程中。消息的有效荷載可以為多種類型,包括字符串,JavaScript對象或當前時間。</p> | ||||
|   <h3>輸出</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt>payload<span class="property-type">various</span></dt> | ||||
|       <dd>指定的消息的有效荷載。</dd> | ||||
|       <dt class="optional">topic <span class="property-type">字符串</span></dt> | ||||
|       <dd>可以在節點中配置的可選屬性。</dd> | ||||
|   </dl> | ||||
|   <h3>詳細</h3> | ||||
|   <p>通過使用特定的有效荷載,注入節點可以啟動流程。默認有效荷載是當前時間的時間戳(以毫秒為單位,自1970年1月1日起)。</p> | ||||
|   <p>該節點還支持注入字符串,數字,布林值,JavaScript對象或流程/全局上下文值。</p> | ||||
|   <p>默認情況下,節點可以通過在編輯器中單擊節點按鈕來手動觸發。同時也可以被設置為定期或按計劃注入。</p> | ||||
|   <p>另一個可選的設置是在每次啟動流程時注入一次。</p> | ||||
|   <p>可以指定的最大<i>間隔</i>約為596小時/24天。 但是,如果對於間隔超過一天的那些間隔,建議您使用scheduler節點來應對斷電或重啟。</p> | ||||
|   <p><b>注意</b>:選項<i>“時間間隔” </i>和<i>“特定時間” </i>使用了標準cron系統。這意味著因此“20分鐘”並不表示在此之後20分鐘,而是每小時的20分鐘,40分鐘。如果您希望設定為從現在開始的每20分鐘,那麽請使用<i>“間隔” </i>選項。</p> | ||||
|   <p><b>注意</b>: 如果您想在字符串中包含換行符,必須使用“功能”節點創建有效荷載。</p> | ||||
|   </script> | ||||
|    | ||||
							
								
								
									
										25
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/21-debug.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/21-debug.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="debug"> | ||||
|   <p>在“調試”側邊欄選項卡和運行時日志中顯示選定的消息屬性。 默認情況下,它會顯示<code>msg.payload</code>的值,但您也可以將其設置成顯示任意屬性,完整消息或JSONata表達式的結果。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>調試側邊欄會提供已發消息的結構化視圖,方便您查詢消息的結構。</p> | ||||
|   <p>JavaScript對象和數組可以根據需要來折疊或擴展。緩衝區對象可以顯示爲原始數據,也可以顯示爲字符串。</p> | ||||
|   <p>對任意條消息,調試側邊欄還會顯示接收消息的時間,發送消息的節點以及消息類型等信息。單擊源節點ID將在工作區中顯示該節點。</p> | ||||
|   <p>節點上的按鈕可用于啓用或禁用其輸出。建議禁用或刪除所有未使用的調試節點。</p> | ||||
|   <p>還可以通過配置節點,將所有消息發送到運行時的日志,或將簡短的數據(32個字符內)在調試節點下的狀態文本上顯示。</p> | ||||
| </script> | ||||
							
								
								
									
										24
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/24-complete.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/24-complete.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="complete"> | ||||
|   <p>當另一個節點完成對消息的處理時觸發流程。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>如果一個節點通知運行時它已完成消息的處理,該節點可用于觸發第二個流程。</p> | ||||
|   <p>這個節點可以與沒有輸出端口的節點一起使用,例如在使用電子郵件發送節點來發送郵件後觸發一個流程。</p> | ||||
|   <p>此節點只能被設置爲處理流程中某個所選節點的事件。與Catch節點不同,您不能指定“所有節點”模式並以流程中的所有節點爲目標。</p> | ||||
|   <p>並非所有節點都會觸發此事件。這取決于它們是否支持于Node-RED 1.0中引入的此功能。</p> | ||||
| </script> | ||||
							
								
								
									
										36
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/25-catch.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/25-catch.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="catch"> | ||||
|   <p>捕獲由同一標簽頁上的節點引發的錯誤。</p> | ||||
|   <h3>輸出</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt>error.message <span class="property-type">字符串</span></dt> | ||||
|       <dd>錯誤消息。</dd> | ||||
|       <dt>error.source.id <span class="property-type">字符串</span></dt> | ||||
|       <dd>引發錯誤的節點的ID。</dd> | ||||
|       <dt>error.source.type <span class="property-type">字符串</span></dt> | ||||
|       <dd>引發錯誤的節點的類型。</dd> | ||||
|       <dt>error.source.name <span class="property-type">字符串</span></dt> | ||||
|       <dd>引發錯誤的節點的名稱。(如果已設置)</dd> | ||||
|   </dl> | ||||
|   <h3>詳細</h3> | ||||
|   <p>如果節點在處理消息時抛出錯誤,則流程通常會停止。該節點可用于捕獲那些錯誤並通過專用流程進行處理。</p> | ||||
|   <p>默認情況下,該節點將捕獲同一標簽頁上任何節點抛出的錯誤。或者,它可以針對特定節點,或配置爲僅捕獲另一個“目標”捕獲節點尚未捕獲的錯誤。</p> | ||||
|   <p>當錯誤發生時,所有匹配的catch節點都會收到錯誤消息。</p> | ||||
|   <p>如果在子流程中發送了錯誤,則該錯誤將由子流程中的任意捕獲節點處理。如果子流程中不存在捕獲節點,則那錯誤將被傳播到子流程實例所在的標簽頁。</p> | ||||
|   <p>如果消息已經具有<code>error</code>屬性,則將該<code>error</code>複制爲<code>_error</code>。</p> | ||||
| </script> | ||||
							
								
								
									
										33
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/25-status.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/25-status.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="status"> | ||||
|   <p>獲取在同一標簽頁上的其他節點的狀態消息。</p> | ||||
|   <h3>輸出</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt>status.text <span class="property-type">字符串</span></dt> | ||||
|       <dd>狀態文本。</dd> | ||||
|       <dt>status.source.type <span class="property-type">字符串</span></dt> | ||||
|       <dd>報告狀態的節點的類型。</dd> | ||||
|       <dt>status.source.id <span class="property-type">字符串</span></dt> | ||||
|       <dd>報告狀態的節點的ID。</dd> | ||||
|       <dt>status.source.name <span class="property-type">字符串</span></dt> | ||||
|       <dd>報告狀態的節點的名稱(如果已設置)。</dd> | ||||
|   </dl> | ||||
|   <h3>詳細</h3> | ||||
|  <p>該節點不包含<code>有效荷載</code>。</p> | ||||
|  <p>默認情況下,節點會獲取同一工作空間標簽頁上報告所有節點的狀態。可以通過配置來設定目標節點。</p> | ||||
| </script> | ||||
							
								
								
									
										31
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/60-link.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/60-link.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="link in"> | ||||
|   <p>在流程之間創建虛擬連線。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>該節點可以連接到任何標簽頁上存在的任何<code>link out</code>節點。連接後,它們的行爲就像連接在一起。</p> | ||||
|   <p>僅當選擇鏈接節點時,才會顯示鏈接節點之間的鏈接。如果有指向另一個選項卡的鏈接,則顯示一個虛擬節點。單擊該虛擬節點將帶您到相應的選項卡。</p> | ||||
|   <p><b>注意:</b>無法創建進入或離開子流程的鏈接。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="link out"> | ||||
|   <p>在流程之間創建虛擬連線。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>該節點可以連接到任何標簽頁上存在的任何<code>link in</code>節點。連接後,它們的行爲就像連接在一起。</p> | ||||
|   <p>僅當選擇鏈接節點時,才會顯示鏈接節點之間的鏈接。如果有指向另一個選項卡的鏈接,則顯示一個虛擬節點。單擊該虛擬節點將帶您到相應的選項卡。</p> | ||||
|   <p><b>注意:</b>無法創建進入或離開子流程的鏈接。</p> | ||||
| </script> | ||||
							
								
								
									
										21
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/90-comment.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/90-comment.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="comment"> | ||||
|   <p>可用于向流程添加注釋的節點。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>編輯面板接受Markdown語法。輸入的文本將在信息側面板中顯示。</p> | ||||
| </script> | ||||
							
								
								
									
										24
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/98-unknown.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/common/98-unknown.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="unknown"> | ||||
|   <p>您安裝的Node-RED無法識別該節點的類型。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p><i>如果在此狀態下部署節點,其配置會被保存。但是在安裝缺少的類型之前,流程不會開始。</i></p> | ||||
|   <p>使用<code> Menu-Manage Palette </code>選項來搜索並安裝節點,或者使用<b>npm install <module></b>來安裝所有缺少的節點,並重新啓動Node-Red來導入這些節點。</p> | ||||
|   <p>另一種可能是,您已經安裝了此節點類型,但是缺少必須的依賴項。您應檢查Node-RED的啓動日志中是否有與缺少節點有關的錯誤消息。</p> | ||||
|   <p>以上方法都不適用時,您可以聯系該流程的作者以獲取缺少的節點類型的副本。</p> | ||||
| </script> | ||||
							
								
								
									
										51
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/10-function.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/10-function.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="function"> | ||||
|   <p>定義對接收到的消息進行處理的JavaScript代碼(函數的主體)。</p> | ||||
|   <p>輸入消息在名爲<code>msg</code>的JavaScript對象中傳遞。</p> | ||||
|   <p>通常,<code>msg</code>對象將消息正文保留在<code>msg.payload</code>屬性中。</p> | ||||
|   <p>該函數一般會返回一個消息對象(或多個消息對象),但也可以爲了停止流程而什麽都不返回。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>請參見<a target="_blank" href="http://nodered.org/docs/writing-functions.html">在線文檔</a>來獲得更多有關編寫函數的信息。</p> | ||||
|   <h4>傳送消息</h4> | ||||
|   <p>要將消息傳遞到流程中的下一個節點,請返回消息或調用<code>node.send(messages)</code>。</p> | ||||
|   <p>它將返回/send:</p> | ||||
|   <ul> | ||||
|     <li>單個消息對象 - 傳遞給連接到第一個輸出的節點</li> | ||||
|     <li>消息對象數組,傳遞給連接到相應輸出的節點</li> | ||||
|   </ul> | ||||
|   <p>如果數組元素是數組,則將多個消息發送到相應的輸出。</p> | ||||
|   <p>無論return方法是單個值還是數組元素,如果返回值爲null,則不會發送任何消息。</p> | ||||
|   <h4>日志輸出和錯誤處理</h4> | ||||
|   <p>使用以下功能輸出日志信息和輸出錯誤:</p> | ||||
|     <ul> | ||||
|         <li><code>node.log("Log message")</code></li> | ||||
|         <li><code>node.warn("Warning")</code></li> | ||||
|         <li><code>node.error("Error")</code></li> | ||||
|     </ul> | ||||
|   </p> | ||||
|   <p>使用catch節點可以進行錯誤處理。 要由catch節點處理,請將<code>msg</code>作爲<code>node.error</code>的第二個參數傳遞:</p> | ||||
|   <pre>node.error("Error",msg);</pre> | ||||
|   <h4>訪問節點信息</h4> | ||||
|   <p>您可以使用以下屬性來在代碼中引用節點ID和名稱:</p> | ||||
|   <ul> | ||||
|       <li><code>node.id</code> - 節點的ID</li> | ||||
|       <li><code>node.name</code> - 節點的名稱</li> | ||||
|   </ul> | ||||
|   <h4>使用環境變量</h4> | ||||
|   <p>環境變量可以通過<code>env.get("MY_ENV_VAR")</code>來進行訪問。</p> | ||||
| </script> | ||||
							
								
								
									
										37
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/10-switch.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/10-switch.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="switch"> | ||||
|   <p>按屬性值來分配消息的傳送路線。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>根據接收到的消息評估指定的規則,然後將消息發送到與匹配的規則相對應的輸出端口。</p> | ||||
|   <p>可以將節點設置爲一旦發現一個匹配的規則,則停止後續的匹配。</p> | ||||
|   <p>對于評估規則,可以使用消息屬性,流程上下文/全局上下文屬性,環境變量和JSONata表達式的評估結果。</p> | ||||
|   <h4>規則</h4> | ||||
|   <p>有四種規則:</p> | ||||
|   <ol> | ||||
|       <li><b>值</b>根據配置的屬性評估規則</li> | ||||
|       <li><b>順序</b>可用于消息序列的規則,例如由“拆分”節點生成的規則</li> | ||||
|       <li><b>JSONata表達式</b>評估整個消息,如果結果爲真,則匹配。</li> | ||||
|       <li><b>其他</b>上述規則都不匹配時適用</li> | ||||
|   </ol> | ||||
|   <h4>注釋</h4> | ||||
|   <p><code>is true/false</code>與<code>is null</code> 規則將對類型進行嚴格的匹配。匹配之前的類型轉化不會發生。</p> | ||||
|   <p><code>is empty</code>規則與零字節的字符串,數組,緩衝區或沒有屬性的對象相匹配。與<code>null</code>或者<code>undefined</code>等不匹配。</p> | ||||
|   <h4>處理消息序列</h4> | ||||
|   <p>默認情況下,節點不會修改<code>msg.parts</code>屬性。</p> | ||||
|   <p>可以啓用<b>重建消息序列</b>選項來爲每條匹配的規則生成新的消息序列。在這種模式下,節點將在發送新序列之前對整個傳入序列進行緩存。運行時的設定<code>nodeMessageBufferMaxLength</code>可以用來限制可緩存的消息數目。</p> | ||||
| </script> | ||||
							
								
								
									
										33
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/15-change.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/15-change.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="change"> | ||||
|   <p>設置,更改,刪除或移動消息,流程上下文或全局上下文的屬性。</p> | ||||
|   <p>如果指定了多個規則,則將按定義的順序來應用它們。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>可用的操作有:</p> | ||||
|   <dl class="message-properties"> | ||||
|   <dt>設置</dt> | ||||
|   <dd>設置一個屬性。該值可以是多種不同類型,也可以從現有消息或上下文屬性中獲取。</dd> | ||||
|   <dt>置換</dt> | ||||
|   <dd>搜索並替換屬性。 如果啓用了正則表達式,則可以爲“replace with”屬性指定捕獲組,例如<code>$1</code>。 在替換過程中,僅當規則完全匹配時才能更改屬性類型。</dd> | ||||
|   <dt>刪除</dt> | ||||
|   <dd>刪除一個屬性</dd> | ||||
|   <dt>移動</dt> | ||||
|   <dd>移動或者重命名一個屬性</dd> | ||||
|   </dl> | ||||
|   <p>類型"expression"使用<a href="http://jsonata.org/" target="_new">JSONata</a>語言。</p> | ||||
| </script> | ||||
							
								
								
									
										40
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/16-range.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/16-range.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="range"> | ||||
|     <p>將數值映射爲另一個區間的數值</p> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">數值</span></dt> | ||||
|         <dd>有效荷載<i>一定</i>得是一個數值. 否則則會映射失敗。</dd> | ||||
|     </dl> | ||||
|     <h3>輸出</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">數值</span></dt> | ||||
|         <dd>被映射到新區間的數值。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>該節點將線性縮放所接收到的數值。在默認情況下,結果不限于節點中定義的範圍。</p> | ||||
|     <p><i>縮放並限制到目標範圍</i>表示結果永遠不會超出目標範圍內指定的範圍。</p> | ||||
|     <p><i>在目標範圍內縮放並折疊</i>表示結果將會被限制(折疊)在目標範圍內。</p> | ||||
|     <p>例如,輸入0-10映射到0-100。</p> | ||||
|     <table style="outline-width:#888 solid thin"> | ||||
|         <tr><th width="80px">模式</th><th width="80px">輸入</th><th width="80px">輸出</th></tr> | ||||
|         <tr><td><center>scale</center></td><td><center>12</center></td><td><center>120</center></td></tr> | ||||
|         <tr><td><center>limit</center></td><td><center>12</center></td><td><center>100</center></td></tr> | ||||
|         <tr><td><center>wrap</center></td><td><center>12</center></td><td><center>20</center></td></tr> | ||||
|     </table> | ||||
| </script> | ||||
							
								
								
									
										46
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/80-template.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/80-template.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="template"> | ||||
|   <p>根據提供的模板設置屬性。</p> | ||||
|   <h3>輸入</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt>msg <span class="property-type">object</span></dt> | ||||
|       <dd>一個msg對象,其中包含著用于填充模板的信息。</dd> | ||||
|       <dt class="optional">template <span class="property-type">string</span></dt> | ||||
|       <dd>由<code>msg.payload</code>填充的模板。如果未在編輯面板中配置,則可以將設爲msg的屬性。</dd> | ||||
|   </dl> | ||||
|   <h3>Outputs</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt>msg <span class="property-type">object</span></dt> | ||||
|       <dd>由來自傳入msg的屬性來填充已配置的模板後輸出的帶有屬性的msg。</dd> | ||||
|   </dl> | ||||
|   <h3>詳細</h3> | ||||
|   <p>默認情況下使用<i><a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache</a></i>格式。如有需要也可以切換其他格式。</p> | ||||
|   <p>例如: | ||||
|   <pre>Hello {{payload.name}}. Today is {{date}}</pre> | ||||
|   <p>receives a message containing: | ||||
|   <pre>{ | ||||
| date: "Monday", | ||||
| payload: { | ||||
|   name: "Fred" | ||||
| } | ||||
| }</pre> | ||||
|   <p>輸出的消息將會是: | ||||
|   <pre>Hello Fred. Today is Monday</pre> | ||||
|   <p>也可以使用流程上下文或全局上下文中的屬性:<code>{{flow.name}}</code>或者<code>{{global.name}}</code>,或者爲了持久儲存<code>store</code>,可以使用<code>{{flow[store].name}}</code>或<code>{{global[store].name}}</code>。 | ||||
|   <p><b>注意:</b>默認情況下,<i>mustache</i>將在其替換的值中轉義任何非字母數字或HTML實體。爲了防止這種情況,請使用<code>{{{triple}}}</code>大括號。 | ||||
| </script> | ||||
							
								
								
									
										32
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/89-delay.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/89-delay.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="delay"> | ||||
|   <p>對通過節點的消息進行延遲發送或限制。</p> | ||||
|   <h3>輸入</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt class="optional">delay <span class="property-type">數值</span></dt> | ||||
|       <dd>設置要應用于消息的延遲(以毫秒爲單位)。僅當節點配置爲允許消息去覆蓋配置的默認延遲間隔時,此選項才適用。</dd> | ||||
|       <dt class="optional">reset</dt> | ||||
|       <dd>如果接收到的消息將此屬性設置爲任何值,則將清空該節點保留的所有的未發送消息。</dd> | ||||
|       <dt class="optional">flush</dt> | ||||
|       <dd>如果接收到的消息的此屬性設置爲任何值,則將立即發送該節點保留的所有未發送消息。</dd> | ||||
|   </dl> | ||||
|   <h3>詳細</h3> | ||||
|   <p>當配置爲延遲發送消息時,延遲間隔可以是一個固定值,一個範圍內的隨機值或爲每個消息動態設置。</p> | ||||
|   <p>當配置爲對消息進行限制時,它們的傳遞將分散在配置的時間段內。狀態顯示隊列中當前的消息數。可以選擇在中間消息到達時丟棄它們。</p> | ||||
|   <p>速率限制可以應用于所有消息,也可以根據<code>msg.topic</code>的值來進行分組。分組時,中間消息將會被自動刪除。在每個時間間隔,節點可以釋放所有主題的最新消息,或釋放下一個主題的最新消息。</p> | ||||
| </script> | ||||
							
								
								
									
										33
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/89-trigger.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/89-trigger.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="trigger"> | ||||
|   <p>触发后,将会发送一条消息。如果被拓展或重置,则可以选择发送第二条消息。</p> | ||||
|  | ||||
|   <h3>输入</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt class="optional">reset</dt> | ||||
|       <dd>如果收到带有此属性的消息,则将清除当前正在进行的任何超时或重复,且不会触发任何消息。</dd> | ||||
|   </dl> | ||||
|  | ||||
|   <h3>详细</h3> | ||||
|   <p>该节点可用于在流程中创建一个超时。 默认情况下,当它收到一条消息时,它将发送一条带有<code>1</code>的有效荷载的消息。然后它将等待250毫秒,再发送第二条消息,其有效荷载为<code>0</code>。这可以用于使连接到Raspberry Pi GPIO引脚的LED闪烁等例子上。</p> | ||||
|   <p>可以将发送的每个消息的有效荷载配置为各种值,包括不发送任何内容的选项。例如,将初始消息设置为<i>nothing</i>,然后选择将计时器与每个收到的消息一起扩展的选项,则该节点将充当看门狗计时器;仅在设置的间隔内未收到任何消息时才发送消息。</p> | ||||
|   <p>如果设置为<i>字符串</i>类型,则该节点支持<i>mustache</i>模板语法。</p> | ||||
|   <p>如果节点收到具有<code>reset</code>属性或与节点中配置的匹配的<code>有效荷载</code>的消息,则将清除当前正在进行的任何超时或重复,并且不会触发任何消息。</p> | ||||
|   <p>可以将节点配置为以固定的时间间隔重新发送消息,直到被收到的消息重置为止。</p> | ||||
|   <p>(可选)可以将节点配置为将带有<code>msg.topic</code>的消息视为独立的流程。</p> | ||||
| </script> | ||||
							
								
								
									
										74
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/90-exec.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/function/90-exec.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="exec"> | ||||
|     <p>運行系統命令並返回其輸出。</p> | ||||
|     <p>可以將節點配置爲等待命令完成,或者在命令生成時發送其輸出。</p> | ||||
|     <p>運行的命令可以在節點中配置,也可以由收到的消息提供。</p> | ||||
|  | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt class="optional">payload <span class="property-type">字符串</span></dt> | ||||
|         <dd>如果這樣配置,則將被附加到執行命令中。</dd> | ||||
|         <dt class="optional">kill <span class="property-type">字符串</span></dt> | ||||
|         <dd>指定發送到現有的exec節點進程的kill信號類型。</dd> | ||||
|         <dt class="optional">pid <span class="property-type">數值|字符串</span></dt> | ||||
|         <dd>要殺死的現有exec節點進程的進程ID</dd> | ||||
|     </dl> | ||||
|  | ||||
|     <h3>輸出</h3> | ||||
|     <ol class="node-ports"> | ||||
|         <li>標准輸出(stdout) | ||||
|             <dl class="message-properties"> | ||||
|                 <dt>payload <span class="property-type">字符串</span></dt> | ||||
|                 <dd>命令的標准輸出。</dd> | ||||
|             </dl> | ||||
|             <dl class="message-properties"> | ||||
|                 <dt>rc <span class="property-type">object</span></dt> | ||||
|                 <dd>(僅執行模式)一個返回代碼對象的副本(在端口3上也可用)</dd> | ||||
|             </dl> | ||||
|         </li> | ||||
|         <li>標准error輸出(stderr) | ||||
|             <dl class="message-properties"> | ||||
|                 <dt>payload <span class="property-type">字符串</span></dt> | ||||
|                 <dd>命令的標准錯誤輸出。</dd> | ||||
|             </dl> | ||||
|             <dl class="message-properties"> | ||||
|                 <dt>rc <span class="property-type">object</span></dt> | ||||
|                 <dd>(僅執行模式)一個返回代碼對象的副本(在端口3上也可用)</dd> | ||||
|             </dl> | ||||
|         </li> | ||||
|         <li>返回代碼 | ||||
|             <dl class="message-properties"> | ||||
|                 <dt>payload <span class="property-type">object</span></dt> | ||||
|                 <dd>一個包含返回代碼以及<code>message</code>,<code>signal</code>屬性的對象。</dd> | ||||
|             </dl> | ||||
|         </li> | ||||
|     </ol> | ||||
|     <h3>詳細</h3> | ||||
|     <p>默認情況下,使用<code>exec</code>系統調用來調用命令,等待命令完成,然後返回輸出。例如,成功的命令的返回碼應爲<code>{code:0}</code>。</p> | ||||
|     <p>(可選)可以選擇使用<code>spawn</code>代替,它會在命令運行時從stdout和stderr返回輸出,通常一次一行。完成後,它將在第三個端口上返回一個對象。例如,成功的命令應返回<code>{code:0}</code>。</p> | ||||
|     <p>錯誤可能會在第三個端口<code>msg.payload</code>上返回額外的信息,例如<code>message</code>字符串,<code>signal</code>字符串。</p> | ||||
|     <p>運行的命令是在節點內定義的,帶有附加<code>msg.payload</code>的選項和另外一組參數。</p> | ||||
|     <p>帶空格的命令或參數應該用引號引起來:<code>“這是一個參數”</code></p> | ||||
|     <p>返回的<code>有效荷載</code>通常是<i>字符串</i>類型,除非檢測到非UTF8字符,在這種情況下,它會是<i>buffer</i>類型。</p> | ||||
|     <p>節點處于活動狀態時,該節點的狀態圖標和PID將可見。對此更改可以通過<code>Status</code>節點讀取。</p> | ||||
|     <h4>殺死進程</h4> | ||||
|     <p>發送<code>msg.kill</code>將殺死一個活動進程。<code>msg.kill</code>應該是包含要發送的信號類型的字符串,例如<code>SIGINT</code>,<code>SIGQUIT</code>或<code>SIGHUP</code>。如果設置爲空字符串,則默認爲<code>SIGTERM</code>。</p> | ||||
|     <p>如果節點有多個進程在運行,則還必須設置<code>msg.pid</code>並設置要殺死的PID的值。</p> | ||||
|     <p>如果<code>超時</code>字段提供了一個值,則如果在指定的秒數過去後進程尚未完成,則該進程將自動終止。</p> | ||||
|     <p>提示:如果運行Python應用程序,則可能需要使用<code>-u</code>參數來停止對輸出進行緩存。</p> | ||||
| </script> | ||||
| @@ -6,7 +6,9 @@ | ||||
|             "name": "名稱", | ||||
|             "username": "使用者名稱", | ||||
|             "password": "密碼", | ||||
|             "property": "屬性" | ||||
|             "property": "屬性", | ||||
|             "selectNodes": "選擇節點...", | ||||
|             "expand": "擴展" | ||||
|         }, | ||||
|         "status": { | ||||
|             "connected": "已連接", | ||||
| @@ -35,7 +37,22 @@ | ||||
|         "stopped": "停止", | ||||
|         "failed": "注入失敗: __error__", | ||||
|         "label": { | ||||
|             "repeat": "重複" | ||||
|             "repeat": "重複", | ||||
|             "flow": "流上下午", | ||||
|             "global": "全局上下文", | ||||
|             "str": "字符串", | ||||
|             "num": "數值", | ||||
|             "bool": "布爾值", | ||||
|             "json": "JSON對象", | ||||
|             "bin": "buffer", | ||||
|             "date": "時間戳", | ||||
|             "env": "環境變量", | ||||
|             "object": "對象", | ||||
|             "string": "字符串", | ||||
|             "boolean": "布爾值", | ||||
|             "number": "數值", | ||||
|             "Array": "數組", | ||||
|             "invalid": "無效的JSON對象" | ||||
|         }, | ||||
|         "timestamp": "時間戳記", | ||||
|         "none": "無", | ||||
| @@ -72,13 +89,11 @@ | ||||
|     "catch": { | ||||
|         "catch": "監測所有節點", | ||||
|         "catchNodes": "監測__number__個節點", | ||||
|         "catchUncaught": "捕獲:未捕獲", | ||||
|         "label": { | ||||
|             "source": "監測範圍", | ||||
|             "node": "節點", | ||||
|             "type": "類型", | ||||
|             "selectAll": "全選", | ||||
|             "sortByLabel": "按名稱排序", | ||||
|             "sortByType": "按類型排序" | ||||
|             "uncaught": "忽略其他捕獲節點處理的錯誤" | ||||
|         }, | ||||
|         "scope": { | ||||
|             "all": "所有節點", | ||||
| @@ -90,10 +105,6 @@ | ||||
|         "statusNodes": "報告__number__個節點狀態", | ||||
|         "label": { | ||||
|             "source": "報告狀態範圍", | ||||
|             "node": "節點", | ||||
|             "type": "類型", | ||||
|             "selectAll": "全選", | ||||
|             "sortByLabel": "按名稱排序", | ||||
|             "sortByType": "按類型排序" | ||||
|         }, | ||||
|         "scope": { | ||||
| @@ -101,8 +112,13 @@ | ||||
|             "selected": "指定節點" | ||||
|         } | ||||
|     }, | ||||
|     "complete": { | ||||
|         "completeNodes": "完成: __number__個節點" | ||||
|     }, | ||||
|     "debug": { | ||||
|         "output": "輸出", | ||||
|         "none": "None", | ||||
|         "invalid-exp": "無效的JSONata表達式: __error__", | ||||
|         "msgprop": "資訊屬性", | ||||
|         "msgobj": "完整資訊", | ||||
|         "to": "目標", | ||||
| @@ -124,7 +140,11 @@ | ||||
|             "filterCurrent": "當前流程", | ||||
|             "debugNodes": "除錯節點", | ||||
|             "clearLog": "清空日誌", | ||||
|             "openWindow": "在新視窗打開" | ||||
|             "filterLog": "過濾日誌", | ||||
|             "openWindow": "在新視窗打開", | ||||
|             "copyPath": "復制路徑", | ||||
|             "copyPayload": "復制值", | ||||
|             "pinPath": "固定展開" | ||||
|         }, | ||||
|         "messageMenu": { | ||||
|             "collapseAll": "折疊所有路徑", | ||||
| @@ -146,26 +166,33 @@ | ||||
|             "key": "私密金鑰", | ||||
|             "passphrase": "密碼", | ||||
|             "ca": "CA證書", | ||||
|             "verify-server-cert":"驗證伺服器憑證" | ||||
|             "verify-server-cert": "驗證伺服器憑證", | ||||
|             "servername": "服務器名" | ||||
|         }, | ||||
|         "placeholder": { | ||||
|             "cert":"憑證路徑 (PEM 格式)", | ||||
|             "key":"私密金鑰路徑 (PEM 格式)", | ||||
|             "ca":"CA憑證路徑 (PEM 格式)", | ||||
|             "passphrase":"私密金鑰密碼 (可選)" | ||||
|             "cert": "憑證路徑 (PEM 格式)", | ||||
|             "key": "私密金鑰路徑 (PEM 格式)", | ||||
|             "ca": "CA憑證路徑 (PEM 格式)", | ||||
|             "passphrase": "私密金鑰密碼 (可選)", | ||||
|             "servername": "用於SNI" | ||||
|         }, | ||||
|         "error": { | ||||
|             "missing-file": "未提供證書/金鑰檔案" | ||||
|         } | ||||
|     }, | ||||
|     "exec": { | ||||
|         "exec": "exec", | ||||
|         "spawn": "spawn", | ||||
|         "label": { | ||||
|             "command": "命令", | ||||
|             "append": "追加", | ||||
|             "timeout": "超時", | ||||
|             "timeoutplace": "可選填", | ||||
|             "return": "輸出", | ||||
|             "seconds": "秒" | ||||
|             "seconds": "秒", | ||||
|             "stdout": "標準輸出", | ||||
|             "stderr": "標準錯誤輸出", | ||||
|             "retcode": "返回碼" | ||||
|         }, | ||||
|         "placeholder": { | ||||
|             "extraparams": "額外的輸入參數" | ||||
| @@ -177,16 +204,18 @@ | ||||
|         "oldrc": "使用舊式輸出 (相容模式)" | ||||
|     }, | ||||
|     "function": { | ||||
|         "function": "函數", | ||||
|         "label": { | ||||
|             "function": "函數", | ||||
|             "outputs": "輸出" | ||||
|         }, | ||||
|         "error": { | ||||
|             "inputListener":"無法在函數中監聽對'注入'事件", | ||||
|             "non-message-returned":"函數節點嘗試返回類型為 __type__ 的資訊" | ||||
|             "inputListener": "無法在函數中監聽對'注入'事件", | ||||
|             "non-message-returned": "函數節點嘗試返回類型為 __type__ 的資訊" | ||||
|         } | ||||
|     }, | ||||
|     "template": { | ||||
|         "template": "模板", | ||||
|         "label": { | ||||
|             "template": "模版", | ||||
|             "property": "屬性", | ||||
| @@ -233,21 +262,21 @@ | ||||
|             "limit": "限制", | ||||
|             "limitTopic": "限制主題", | ||||
|             "random": "隨機", | ||||
|             "units" : { | ||||
|             "units": { | ||||
|                 "second": { | ||||
|                     "plural" : "秒", | ||||
|                     "plural": "秒", | ||||
|                     "singular": "秒" | ||||
|                 }, | ||||
|                 "minute": { | ||||
|                     "plural" : "分鐘", | ||||
|                     "plural": "分鐘", | ||||
|                     "singular": "分鐘" | ||||
|                 }, | ||||
|                 "hour": { | ||||
|                     "plural" : "小時", | ||||
|                     "plural": "小時", | ||||
|                     "singular": "小時" | ||||
|                 }, | ||||
|                 "day": { | ||||
|                     "plural" : "天", | ||||
|                     "plural": "天", | ||||
|                     "singular": "天" | ||||
|                 } | ||||
|             } | ||||
| @@ -272,6 +301,9 @@ | ||||
|         "wait-reset": "等待被重置", | ||||
|         "wait-for": "等待", | ||||
|         "wait-loop": "週期性重發", | ||||
|         "for": "處理", | ||||
|         "bytopics": "每個msg.topic", | ||||
|         "alltopics": "所有消息", | ||||
|         "duration": { | ||||
|             "ms": "毫秒", | ||||
|             "s": "秒", | ||||
| @@ -284,12 +316,13 @@ | ||||
|             "trigger-block": "觸發並阻止", | ||||
|             "trigger-loop": "週期性重發", | ||||
|             "reset": "重置觸發節點條件 如果:", | ||||
|             "resetMessage":"msg.reset已設置", | ||||
|             "resetPayload":"msg.payload等於", | ||||
|             "resetMessage": "msg.reset已設置", | ||||
|             "resetPayload": "msg.payload等於", | ||||
|             "resetprompt": "可選填" | ||||
|         } | ||||
|     }, | ||||
|     "comment": { | ||||
|         "comment": "注釋" | ||||
|     }, | ||||
|     "unknown": { | ||||
|         "label": { | ||||
| @@ -303,26 +336,32 @@ | ||||
|             "example": "e.g. localhost", | ||||
|             "output": "輸出", | ||||
|             "qos": "QoS", | ||||
|             "retain": "保持", | ||||
|             "clientid": "使用者端ID", | ||||
|             "port": "埠", | ||||
|             "keepalive": "Keepalive計時(秒)", | ||||
|             "cleansession": "使用新的會話", | ||||
|             "use-tls": "使用安全連接 (SSL/TLS)", | ||||
|             "tls-config":"TLS 設置", | ||||
|             "verify-server-cert":"驗證伺服器憑證", | ||||
|             "tls-config": "TLS 設置", | ||||
|             "verify-server-cert": "驗證伺服器憑證", | ||||
|             "compatmode": "使用舊式MQTT 3.1支援" | ||||
|         }, | ||||
|         "sections-label": { | ||||
|             "birth-message": "連接時發送的消息(出生消息)", | ||||
|             "will-message": "意外斷開連接時的發送消息(Will消息)", | ||||
|             "close-message": "斷開連接前發送的消息(關閉消息)" | ||||
|         }, | ||||
|         "tabs-label": { | ||||
|             "connection": "連接", | ||||
|             "security": "安全", | ||||
|             "will": "Will信息", | ||||
|             "birth": "Birth信息" | ||||
|             "messages": "消息" | ||||
|         }, | ||||
|         "placeholder": { | ||||
|             "clientid": "留白則自動隨機生成", | ||||
|             "clientid-nonclean":"如非新會話,必須設置使用者端ID", | ||||
|             "clientid-nonclean": "如非新會話,必須設置使用者端ID", | ||||
|             "will-topic": "留白將禁止Will資訊", | ||||
|             "birth-topic": "留白將禁止Birth資訊" | ||||
|             "birth-topic": "留白將禁止Birth資訊", | ||||
|             "close-topic": "留白以禁用關閉消息" | ||||
|         }, | ||||
|         "state": { | ||||
|             "connected": "已連接到服務端: __broker__", | ||||
| @@ -333,7 +372,9 @@ | ||||
|         "output": { | ||||
|             "buffer": "Buffer", | ||||
|             "string": "字串", | ||||
|             "base64": "Base64編碼字串" | ||||
|             "base64": "Base64編碼字串", | ||||
|             "auto": "自動檢測 (字符串或buffer)", | ||||
|             "json": "解析的JSON對象" | ||||
|         }, | ||||
|         "true": "是", | ||||
|         "false": "否", | ||||
| @@ -342,7 +383,9 @@ | ||||
|             "not-defined": "主題未設置", | ||||
|             "missing-config": "未設置服務端", | ||||
|             "invalid-topic": "主題無效", | ||||
|             "nonclean-missingclientid": "使用者端ID未設定,使用新會話" | ||||
|             "nonclean-missingclientid": "使用者端ID未設定,使用新會話", | ||||
|             "invalid-json-string": "無效的JSON字符串", | ||||
|             "invalid-json-parse": "無法解析JSON字符串" | ||||
|         } | ||||
|     }, | ||||
|     "httpin": { | ||||
| @@ -354,12 +397,26 @@ | ||||
|             "upload": "接受檔案上傳?", | ||||
|             "status": "狀態碼", | ||||
|             "headers": "Header", | ||||
|             "other": "其他" | ||||
|             "other": "其他", | ||||
|             "paytoqs": "將msg.payload附加為查詢字符串參數", | ||||
|             "utf8String": "UTF8格式的字符串", | ||||
|             "binaryBuffer": "二進制buffer", | ||||
|             "jsonObject": "解析的JSON對象", | ||||
|             "authType": "類型", | ||||
|             "bearerToken": "Token" | ||||
|         }, | ||||
|         "setby": "- 用 msg.method 設定 -", | ||||
|         "basicauth": "基本認證", | ||||
|         "use-tls": "使用安全連接 (SSL/TLS) ", | ||||
|         "tls-config":"TLS 設置", | ||||
|         "tls-config": "TLS 設置", | ||||
|         "basic": "基本認證", | ||||
|         "digest": "摘要認證", | ||||
|         "bearer": "bearer認證", | ||||
|         "use-proxy": "使用代理服務器", | ||||
|         "persist": "對連接啟用keep-alive", | ||||
|         "proxy-config": "代理服務器設置", | ||||
|         "use-proxyauth": "使用代理身份驗證", | ||||
|         "noproxy-hosts": "代理例外", | ||||
|         "utf8": "UTF-8 字串", | ||||
|         "binary": "二進位資料", | ||||
|         "json": "JSON對象", | ||||
| @@ -375,8 +432,11 @@ | ||||
|             "no-response": "無響應物件", | ||||
|             "json-error": "JSON 解析錯誤", | ||||
|             "no-url": "未設定 URL", | ||||
|             "deprecated-call":"__method__方法已棄用", | ||||
|             "invalid-transport":"非HTTP傳輸請求" | ||||
|             "deprecated-call": "__method__方法已棄用", | ||||
|             "invalid-transport": "非HTTP傳輸請求", | ||||
|             "timeout-isnan": "超時值不是有效數字,忽略", | ||||
|             "timeout-isnegative": "超時值為負,忽略", | ||||
|             "invalid-payload": "無效的有效載荷" | ||||
|         }, | ||||
|         "status": { | ||||
|             "requesting": "請求中" | ||||
| @@ -395,17 +455,23 @@ | ||||
|         "message": "完整資訊", | ||||
|         "tip": { | ||||
|             "path1": "預設情況下,<code>payload</code>將包含要發送或從Websocket接收的資料。偵聽器可以配置為以JSON格式的字串發送或接收整個消息物件.", | ||||
|             "path2": "這條路徑將相對於 ", | ||||
|             "path2": "這條路徑將相對於 <code>__path__</code>.", | ||||
|             "url1": "URL 應該使用ws://或者wss://方案並指向現有的websocket監聽器.", | ||||
|             "url2": "預設情況下,<code>payload</code> 將包含要發送或從Websocket接收的資料。可以將使用者端配置為以JSON格式的字串發送或接收整個消息物件." | ||||
|         }, | ||||
|         "status": { | ||||
|             "connected": "連接數 __count__", | ||||
|             "connected_plural": "連接數 __count__" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "connect-error": "ws連接發生了錯誤: ", | ||||
|             "send-error": "發送時發生了錯誤: ", | ||||
|             "missing-conf": "未設置伺服器" | ||||
|             "missing-conf": "未設置伺服器", | ||||
|             "duplicate-path": "同一路徑上不能有兩個WebSocket偵聽器: __path__" | ||||
|         } | ||||
|     }, | ||||
|     "watch": { | ||||
|         "watch": "watch", | ||||
|         "label": { | ||||
|             "files": "文件", | ||||
|             "recursive": "遞迴所有子資料夾" | ||||
| @@ -458,14 +524,12 @@ | ||||
|             "connection-closed": "連接已關閉 __host__:__port__", | ||||
|             "connections": "__count__ 個連接", | ||||
|             "connections_plural": "__count__ 個連接" | ||||
|  | ||||
|         }, | ||||
|         "errors": { | ||||
|             "connection-lost": "連接中斷 __host__:__port__", | ||||
|             "timeout": "超時關閉通訊端連接,埠 __port__", | ||||
|             "cannot-listen": "無法監聽埠 __port__, 錯誤: __error__", | ||||
|             "error": "錯誤: __error__", | ||||
|  | ||||
|             "socket-error": "通訊端連接錯誤來自 __host__:__port__", | ||||
|             "no-host": "主機位址或埠未設定", | ||||
|             "connect-timeout": "連接逾時", | ||||
| @@ -480,14 +544,15 @@ | ||||
|             "output": "輸出", | ||||
|             "group": "組", | ||||
|             "interface": "本地IP", | ||||
|             "interfaceprompt": "(可選)本地 IP 綁定到", | ||||
|             "send": "發送一個", | ||||
|             "toport": "到埠", | ||||
|             "address": "地址", | ||||
|             "decode-base64": "是否解碼Base64編碼的資訊?" | ||||
|             "decode-base64": "是否解碼Base64編碼的資訊?", | ||||
|             "interfaceprompt": "(可選)本地 IP 綁定到" | ||||
|         }, | ||||
|         "placeholder": { | ||||
|             "interface": "(可選)eth0的IP地址", | ||||
|             "interfaceprompt": "(可選) 要綁定的本地接口或地址", | ||||
|             "address": "目標IP位址" | ||||
|         }, | ||||
|         "udpmsgs": "udp信息", | ||||
| @@ -529,36 +594,43 @@ | ||||
|             "ip-notset": "udp: IP地址未設定", | ||||
|             "port-notset": "udp: 埠未設定", | ||||
|             "port-invalid": "udp: 無效埠號碼", | ||||
|             "alreadyused": "udp: 埠已被佔用" | ||||
|             "alreadyused": "udp: 埠已被佔用", | ||||
|             "ifnotfound": "udp: 接口 __iface__ 未發現" | ||||
|         } | ||||
|     }, | ||||
|     "switch": { | ||||
|         "switch": "switch", | ||||
|         "label": { | ||||
|             "property": "屬性", | ||||
|             "rule": "規則", | ||||
|             "repair" : "重建資訊佇列" | ||||
|             "repair": "重建資訊佇列" | ||||
|         }, | ||||
|         "previous": "先前值", | ||||
|         "and": "與", | ||||
|         "checkall": "全選所有規則", | ||||
|         "stopfirst": "接受第一條匹配資訊後停止", | ||||
|         "ignorecase": "忽略大小寫", | ||||
|         "rules": { | ||||
|             "btwn":"在之間", | ||||
|             "cont":"包含", | ||||
|             "regex":"匹配規則運算式", | ||||
|             "true":"為真", | ||||
|             "false":"為假", | ||||
|             "null":"為空", | ||||
|             "nnull":"非空", | ||||
|             "head":"head", | ||||
|             "tail":"tail", | ||||
|             "index":"index between", | ||||
|             "exp":"JSONata運算式", | ||||
|             "else":"除此以外" | ||||
|             "btwn": "在之間", | ||||
|             "cont": "包含", | ||||
|             "regex": "匹配規則運算式", | ||||
|             "true": "為真", | ||||
|             "false": "為假", | ||||
|             "null": "為空", | ||||
|             "nnull": "非空", | ||||
|             "istype": "類型是", | ||||
|             "empty": "為空", | ||||
|             "nempty": "非空", | ||||
|             "head": "head", | ||||
|             "tail": "tail", | ||||
|             "index": "index between", | ||||
|             "exp": "JSONata運算式", | ||||
|             "else": "除此以外", | ||||
|             "hask": "擁有鍵" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "invalid-expr": "無效的JSONata運算式: __error__", | ||||
|             "too-many" : "Switch節點中有太多待定信息" | ||||
|             "too-many": "Switch節點中有太多待定信息" | ||||
|         } | ||||
|     }, | ||||
|     "change": { | ||||
| @@ -588,6 +660,7 @@ | ||||
|         } | ||||
|     }, | ||||
|     "range": { | ||||
|         "range": "range", | ||||
|         "label": { | ||||
|             "action": "操作", | ||||
|             "inputrange": "映射輸入資料", | ||||
| @@ -623,7 +696,8 @@ | ||||
|             "firstrow": "第一行包含列名", | ||||
|             "output": "輸出", | ||||
|             "includerow": "包含列名行", | ||||
|             "newline": "分行符號" | ||||
|             "newline": "分行符號", | ||||
|             "usestrings": "解析數值" | ||||
|         }, | ||||
|         "placeholder": { | ||||
|             "columns": "用逗號分割列名" | ||||
| @@ -654,7 +728,8 @@ | ||||
|     "html": { | ||||
|         "label": { | ||||
|             "select": "選取項", | ||||
|             "output": "輸出" | ||||
|             "output": "輸出", | ||||
|             "in": "in" | ||||
|         }, | ||||
|         "output": { | ||||
|             "html": "選定元素的html內容", | ||||
| @@ -670,7 +745,9 @@ | ||||
|         "errors": { | ||||
|             "dropped-object": "忽略非物件格式的有效負載", | ||||
|             "dropped": "忽略不支援格式的有效負載類型", | ||||
|             "dropped-error": "轉換有效負載失敗" | ||||
|             "dropped-error": "轉換有效負載失敗", | ||||
|             "schema-error": "JSON架構錯誤", | ||||
|             "schema-error-compile": "JSON架構錯誤: 未能編譯架構" | ||||
|         }, | ||||
|         "label": { | ||||
|             "o2j": "對象至JSON", | ||||
| @@ -679,8 +756,8 @@ | ||||
|             "property": "屬性", | ||||
|             "actions": { | ||||
|                 "toggle": "JSON字串與物件互轉", | ||||
|                 "str":"總是轉為JSON字串", | ||||
|                 "obj":"總是轉為JS對象" | ||||
|                 "str": "總是轉為JSON字串", | ||||
|                 "obj": "總是轉為JS對象" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
| @@ -702,76 +779,6 @@ | ||||
|             "xml_js": "此節點僅處理XML字串或JS物件." | ||||
|         } | ||||
|     }, | ||||
|     "rpi-gpio": { | ||||
|         "label": { | ||||
|             "gpiopin": "GPIO", | ||||
|             "selectpin": "選擇引腳", | ||||
|             "resistor": "電阻?", | ||||
|             "readinitial": "在部署/重啟時讀取引腳的初始狀態?", | ||||
|             "type": "類型", | ||||
|             "initpin": "初始化引腳狀態?", | ||||
|             "debounce": "去抖動", | ||||
|             "freq": "頻率", | ||||
|             "button": "按鈕", | ||||
|             "pimouse": "Pi滑鼠", | ||||
|             "pikeyboard": "Pi鍵盤", | ||||
|             "left": "左", | ||||
|             "right": "右", | ||||
|             "middle": "中" | ||||
|         }, | ||||
|         "resistor": { | ||||
|             "none": "無", | ||||
|             "pullup": "上拉電阻", | ||||
|             "pulldown": "下拉電阻" | ||||
|         }, | ||||
|         "digout": "數位輸出", | ||||
|         "pwmout": "PWM輸出", | ||||
|         "servo": "伺服輸出", | ||||
|         "initpin0": "初始引腳電平 - 低(0)", | ||||
|         "initpin1": "初始引腳電平 - 高(1)", | ||||
|         "left": "左", | ||||
|         "right": "右", | ||||
|         "middle": "中", | ||||
|         "any": "任何", | ||||
|         "pinname": "引腳", | ||||
|         "alreadyuse": "已被使用", | ||||
|         "alreadyset": "已被設為", | ||||
|         "tip": { | ||||
|             "pin": "<b>正在使用引腳</b>: ", | ||||
|             "in": "提示: 僅接受數位輸入 - 輸出必須為0或1.", | ||||
|             "dig": "提示: 如用數位輸出 - 輸入必須為0或1.", | ||||
|             "pwm": "提示: 如用PWM輸出 - 輸入必須為0至100之間; 如用高頻率可能會比預期佔用更多CPU資源.", | ||||
|             "ser": "<b>提示</b>: 如用伺服輸出 - 輸入必須為0至100之間. 50為中間值." | ||||
|         }, | ||||
|         "types": { | ||||
|             "digout": "數位輸出", | ||||
|             "input": "輸入", | ||||
|             "pullup": "含有上拉電阻的輸入", | ||||
|             "pulldown": "含有下拉電阻的輸入", | ||||
|             "pwmout": "PWM輸出", | ||||
|             "servo": "伺服輸出" | ||||
|         }, | ||||
|         "status": { | ||||
|             "stopped": "已停止", | ||||
|             "closed": "已關閉", | ||||
|             "not-running": "不運行" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "ignorenode": "忽略樹莓派的特定節點", | ||||
|             "version": "版本命令失敗", | ||||
|             "sawpitype": "查看Pi類型", | ||||
|             "libnotfound": "找不到樹莓派RPi.GPIO的python庫", | ||||
|             "alreadyset": "GPIO引腳 __pin__ 已經被設定為類型: __type__", | ||||
|             "invalidpin": "無效GPIO引腳", | ||||
|             "invalidinput": "無效輸入", | ||||
|             "needtobeexecutable": "__command__須為可運行命令", | ||||
|             "mustbeexecutable": "nrgpio須為可運行", | ||||
|             "commandnotfound": "nrgpio命令不存在", | ||||
|             "commandnotexecutable": "nrgpio命令不可運行", | ||||
|             "error": "錯誤: __error__", | ||||
|             "pythoncommandnotfound": "nrpgio python命令未處於運行狀態" | ||||
|         } | ||||
|     }, | ||||
|     "file": { | ||||
|         "label": { | ||||
|             "filename": "檔案名", | ||||
| @@ -783,7 +790,10 @@ | ||||
|             "breaklines": "分拆成行", | ||||
|             "filelabel": "文件", | ||||
|             "sendError": "發生錯誤時發送消息(傳統模式)", | ||||
|             "deletelabel": "刪除 __file__" | ||||
|             "deletelabel": "刪除 __file__", | ||||
|             "encoding": "編碼", | ||||
|             "utf8String": "UTF8字符串", | ||||
|             "binaryBuffer": "二進制buffer" | ||||
|         }, | ||||
|         "action": { | ||||
|             "append": "追加至文件", | ||||
| @@ -801,6 +811,21 @@ | ||||
|             "deletedfile": "刪除檔: __file__", | ||||
|             "appendedfile": "追加至文件: __file__" | ||||
|         }, | ||||
|         "encoding": { | ||||
|             "none": "默認", | ||||
|             "native": "Native", | ||||
|             "unicode": "Unicode", | ||||
|             "japanese": "日本", | ||||
|             "chinese": "中國", | ||||
|             "korean": "韓國", | ||||
|             "taiwan": "臺灣/香港", | ||||
|             "windows": "Windows代碼頁", | ||||
|             "iso": "ISO代碼頁", | ||||
|             "ibm": "IBM代碼頁", | ||||
|             "mac": "Mac代碼頁", | ||||
|             "koi8": "KOI8代碼頁", | ||||
|             "misc": "其它" | ||||
|         }, | ||||
|         "errors": { | ||||
|             "nofilename": "未指定檔案名", | ||||
|             "invaliddelete": "警告:無效刪除。請在配置對話方塊中使用特定的刪除選項", | ||||
| @@ -812,50 +837,53 @@ | ||||
|         "tip": "提示: 檔案名應該是絕對路徑,否則它將相對於Node-RED進程的工作目錄。" | ||||
|     }, | ||||
|     "split": { | ||||
|         "intro":"基於以下類型拆分<code>msg.payload</code>:", | ||||
|         "object":"<b>對象</b>", | ||||
|         "objectSend":"每個鍵值對作為單個消息發送", | ||||
|         "strBuff":"<b>字串</b> / <b>Buffer</b>", | ||||
|         "array":"<b>陣列</b>", | ||||
|         "splitUsing":"拆分使用", | ||||
|         "splitLength":"固定長度", | ||||
|         "stream":"作為消息流處理", | ||||
|         "addname":" 複製鍵到 " | ||||
|         "split": "split", | ||||
|         "intro": "基於以下類型拆分<code>msg.payload</code>:", | ||||
|         "object": "<b>對象</b>", | ||||
|         "objectSend": "每個鍵值對作為單個消息發送", | ||||
|         "strBuff": "<b>字串</b> / <b>Buffer</b>", | ||||
|         "array": "<b>陣列</b>", | ||||
|         "splitUsing": "拆分使用", | ||||
|         "splitLength": "固定長度", | ||||
|         "stream": "作為消息流處理", | ||||
|         "addname": " 複製鍵到 " | ||||
|     }, | ||||
|     "join":{ | ||||
|         "mode":{ | ||||
|             "mode":"模式", | ||||
|             "auto":"自動", | ||||
|             "merge":"合併序列", | ||||
|             "reduce":"縮減序列", | ||||
|             "custom":"手動" | ||||
|     "join": { | ||||
|         "join": "join", | ||||
|         "mode": { | ||||
|             "mode": "模式", | ||||
|             "auto": "自動", | ||||
|             "merge": "合併序列", | ||||
|             "reduce": "縮減序列", | ||||
|             "custom": "手動" | ||||
|         }, | ||||
|         "combine":"合併每個", | ||||
|         "create":"輸出為", | ||||
|         "type":{ | ||||
|             "string":"字串", | ||||
|             "array":"陣列", | ||||
|             "buffer":"Buffer", | ||||
|             "object":"鍵值對對象", | ||||
|             "merged":"合併對象" | ||||
|         "combine": "合併每個", | ||||
|         "completeMessage": "完整的消息", | ||||
|         "create": "輸出為", | ||||
|         "type": { | ||||
|             "string": "字串", | ||||
|             "array": "陣列", | ||||
|             "buffer": "Buffer", | ||||
|             "object": "鍵值對對象", | ||||
|             "merged": "合併對象" | ||||
|         }, | ||||
|         "using":"使用此值", | ||||
|         "key":"作為鍵", | ||||
|         "joinedUsing":"合併符號", | ||||
|         "send":"發送資訊:", | ||||
|         "afterCount":"達到一定數量的資訊時", | ||||
|         "count":"數量", | ||||
|         "subsequent":"和每個後續的消息", | ||||
|         "afterTimeout":"第一條消息的若干時間後", | ||||
|         "seconds":"秒", | ||||
|         "complete":"在收到存在<code>msg.complete</code>的消息後", | ||||
|         "tip":"此模式假定此節點與<i>split</i>相連, 或者接收到的消息有正確配置的<code>msg.parts</code>屬性.", | ||||
|         "too-many" : "join節點中有太多待定信息", | ||||
|         "using": "使用此值", | ||||
|         "key": "作為鍵", | ||||
|         "joinedUsing": "合併符號", | ||||
|         "send": "發送資訊:", | ||||
|         "afterCount": "達到一定數量的資訊時", | ||||
|         "count": "數量", | ||||
|         "subsequent": "和每個後續的消息", | ||||
|         "afterTimeout": "第一條消息的若幹時間後", | ||||
|         "seconds": "秒", | ||||
|         "complete": "在收到存在<code>msg.complete</code>的消息後", | ||||
|         "tip": "此模式假定此節點與<i>split</i>相連, 或者接收到的消息有正確配置的<code>msg.parts</code>屬性.", | ||||
|         "too-many": "join節點中有太多待定信息", | ||||
|         "merge": { | ||||
|             "topics-label":"合併主題", | ||||
|             "topics":"主題", | ||||
|             "topic" : "主題", | ||||
|             "on-change":"當收到一個新主題時發送已合併資訊" | ||||
|             "topics-label": "合併主題", | ||||
|             "topics": "主題", | ||||
|             "topic": "主題", | ||||
|             "on-change": "當收到一個新主題時發送已合併資訊" | ||||
|         }, | ||||
|         "reduce": { | ||||
|             "exp": "Reduce運算式", | ||||
| @@ -868,43 +896,45 @@ | ||||
|             "invalid-expr": "無效的JSONata運算式: __error__" | ||||
|         } | ||||
|     }, | ||||
|     "sort" : { | ||||
|         "target" : "排序屬性", | ||||
|         "seq" : "資訊佇列", | ||||
|         "key" : "鍵值", | ||||
|         "elem" : "元素值", | ||||
|         "order" : "順序", | ||||
|         "ascending" : "昇冪", | ||||
|         "descending" : "降冪", | ||||
|         "as-number" : "作為數值", | ||||
|         "invalid-exp" : "sort節點中存在無效的JSONata運算式", | ||||
|         "too-many" : "sort節點中有太多待定信息", | ||||
|         "clear" : "清空sort節點中的待定資訊" | ||||
|     "sort": { | ||||
|         "sort": "排序", | ||||
|         "target": "排序屬性", | ||||
|         "seq": "資訊佇列", | ||||
|         "key": "鍵值", | ||||
|         "elem": "元素值", | ||||
|         "order": "順序", | ||||
|         "ascending": "昇冪", | ||||
|         "descending": "降冪", | ||||
|         "as-number": "作為數值", | ||||
|         "invalid-exp": "排序節點中存在無效的JSONata運算式", | ||||
|         "too-many": "排序節點中有太多待定信息", | ||||
|         "clear": "清空排序節點中的待定資訊" | ||||
|     }, | ||||
|     "batch" : { | ||||
|     "batch": { | ||||
|         "batch": "batch", | ||||
|         "mode": { | ||||
|             "label" : "模式", | ||||
|             "num-msgs" : "按指定數量分組", | ||||
|             "interval" : "按時間間隔分組", | ||||
|             "concat" : "按主題分組" | ||||
|             "label": "模式", | ||||
|             "num-msgs": "按指定數量分組", | ||||
|             "interval": "按時間間隔分組", | ||||
|             "concat": "按主題分組" | ||||
|         }, | ||||
|         "count": { | ||||
|             "label" : "分組數量", | ||||
|             "overlap" : "隊末隊首重疊數量", | ||||
|             "count" : "數量", | ||||
|             "invalid" : "無效的分組數量或重疊數量" | ||||
|             "label": "分組數量", | ||||
|             "overlap": "隊末隊首重疊數量", | ||||
|             "count": "數量", | ||||
|             "invalid": "無效的分組數量或重疊數量" | ||||
|         }, | ||||
|         "interval": { | ||||
|             "label" : "時間間隔", | ||||
|             "seconds" : "秒", | ||||
|             "empty" : "無數據到達時發送空資訊" | ||||
|             "label": "時間間隔", | ||||
|             "seconds": "秒", | ||||
|             "empty": "無數據到達時發送空資訊" | ||||
|         }, | ||||
|         "concat": { | ||||
|             "topics-label": "主題", | ||||
|             "topic" : "主題" | ||||
|             "topic": "主題" | ||||
|         }, | ||||
|         "too-many" : "batch節點中有太多待定信息", | ||||
|         "unexpected" : "未知模式", | ||||
|         "no-parts" : "資訊中沒有parts屬性" | ||||
|         "too-many": "batch節點中有太多待定信息", | ||||
|         "unexpected": "未知模式", | ||||
|         "no-parts": "資訊中沒有parts屬性" | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										19
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/05-tls.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/05-tls.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="tls-config"> | ||||
|     <p>TLS連接的配置選項。</p> | ||||
| </script> | ||||
							
								
								
									
										22
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/06-httpproxy.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/06-httpproxy.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="http proxy"> | ||||
|   <p>HTTP代理的配置選項。</p> | ||||
|  | ||||
|   <h3>詳細</h3> | ||||
|   <p>訪問代理例外列表中的主機時,將不使用任何代理。</p> | ||||
| </script> | ||||
							
								
								
									
										70
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/10-mqtt.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/10-mqtt.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="mqtt in"> | ||||
|     <p>連接到MQTT代理並訂閱來自指定主題的消息。</p> | ||||
|     <h3>輸出</h3> | ||||
|     <dl class="message-properties"> | ||||
|        <dt>payload <span class="property-type">字符串 | buffer</span></dt> | ||||
|        <dd>如果不是二進制buffer的話就是字符串</dd> | ||||
|        <dt>topic <span class="property-type">字符串</span></dt> | ||||
|        <dd>MQTT主題,使用<code>/</code>作爲層次結構分隔符。</dd> | ||||
|        <dt>qos <span class="property-type">數值</span> </dt> | ||||
|        <dd>QoS服務質量:0, 最多一次; 1, 最少一次; 2, 只一次。</dd> | ||||
|        <dt>retain <span class="property-type">布爾值</span></dt> | ||||
|        <dd>值爲true時表示消息已保留且可能是舊的。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>訂閱主題可以包括MQTT通配符(+:一個級別,#:多個級別)。</p> | ||||
|     <p>使用該節點您首先需要建立與MQTT代理的連接。通過單擊鉛筆圖標來進行配置。</p> | ||||
|     <p>如有需要,幾個MQTT節點(輸入或輸出)可以共享相同的代理連接。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="mqtt out"> | ||||
|     <p>連接到MQTT代理並發布消息。</p> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|        <dt>payload <span class="property-type">字符串 | buffer</span></dt> | ||||
|        <dd>要發布的有效負載。如果未設置此屬性,則不會發送任何消息。要發送空白消息,請將此屬性設置爲空字符串。</dd> | ||||
|  | ||||
|        <dt class="optional">topic <span class="property-type">字符串</span></dt> | ||||
|        <dd>要發布的MQTT主題。</dd> | ||||
|  | ||||
|        <dt class="optional">qos <span class="property-type">number</span></dt> | ||||
|        <dd>QoS服務質量:0, 最多一次; 1, 最少一次; 2, 只一次。默認值爲0。</dd> | ||||
|  | ||||
|        <dt class="optional">retain <span class="property-type">布爾值</span></dt> | ||||
|        <dd>設置爲<code>true</code>來將消息保留在代理上。默認值爲<code>false</code>。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p><code>msg.payload</code>用作已發布消息的有效載荷。如果包含Object,則會在發送之前將其轉換爲JSON字符串。如果它包含二進制buffer,則消息將按原樣發布。</p> | ||||
|     <p>可以在節點中配置所使用的主題,或者如果留爲空白,則可以通過<code>msg.topic</code>進行設置。</p> | ||||
|     <p>同樣,可以在節點中配置QoS和保留值,或者如果保留空白,則分別由<code>msg.qos</code>和<code>msg.retain</code>設置。要清除先前存儲在代理中的主題,請設置保留標志並向該主題發布空消息。</p> | ||||
|     <p>該節點需要與要配置的MQTT代理的連接。通過單擊鉛筆圖標進行配置。</p> | ||||
|     <p>如果需要,幾個MQTT節點(輸入或輸出)可以共享相同的代理連接。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="mqtt-broker"> | ||||
|     <p>與MQTT代理的連接設置。</p> | ||||
|     <p>創建與代理的連接設置。可以在<code>MQTT In</code>和<code>MQTT Out</code>節點中重複利用這些設置。</p> | ||||
|     <p>如果未爲該節點設置客戶端ID,並且設置了會話初始化,則將生成一個隨機客戶端ID。設置客戶端ID時,請確保它對于連接目標處的代理是唯一的。</p> | ||||
|     <h4>Birth Message</h4> | ||||
|     <p>建立連接後發布在以配置主題中的消息。</p> | ||||
|     <h4>Close Message</h4> | ||||
|     <p>在連接正常結束之前重新部署或者關閉了節點時,發布在以配置主題中的消息。</p> | ||||
|     <h4>Will Message</h4> | ||||
|     <p>當節點意外丟失連接時由代理發布的消息</p> | ||||
|     <h4>WebSockets</h4> | ||||
|     <p>可以將節點配置成使用WebSocket連接。使用WebSocket時,請在服務器字段中以完整格式描述連接目標的URI。 例如:</p> | ||||
|     <pre>ws://example.com:4000/mqtt</pre> | ||||
| </script> | ||||
							
								
								
									
										81
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/21-httpin.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/21-httpin.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="http in"> | ||||
|     <p>創建用于創建Web服務的HTTP端點。</p> | ||||
|     <h3>輸出</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload</dt> | ||||
|         <dd>GET請求包含任何查詢字符串參數的對象。或者包含HTTP請求正文。</dd> | ||||
|         <dt>req<span class="property-type">object</span></dt> | ||||
|         <dd>HTTP請求對象。該對象包含有關請求信息的多個屬性。 | ||||
|             <ul> | ||||
|              <li><code>body</code> - 傳入請求的正文。格式將取決于請求。</li> | ||||
|              <li><code>headers</code> - 包含HTTP請求標頭的對象。</li> | ||||
|              <li><code>query</code> - 包含任何查詢字符串參數的對象。</li> | ||||
|              <li><code>params</code> - 包含任何路由參數的對象。</li> | ||||
|              <li><code>cookies</code> - 包含請求cookie的對象。</li> | ||||
|              <li><code>files</code> - 如果節點啓用了文件上傳,則爲包含了上傳的文件的對象。</li> | ||||
|             </ul> | ||||
|         </dd> | ||||
|         <dt>res<span class="property-type">object</span></dt> | ||||
|         <dd>HTTP響應對象。此屬性不應直接使用;<code>HTTP Response</code>節點記錄了如何響應請求。該屬性必須保留在傳遞給響應節點的消息上。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>節點將在配置的路徑上監聽特定類型的請求。路徑可以完全指定,例如<code>/user</code>,或包括可以接受任何值的命名參數,例如<code>/user/:name</code>。 使用命名參數時,可以在<code>msg.req.params</code>下訪問其在請求中的實際值。</p> | ||||
|     <p>對于包含正文的請求(例如POST或PUT),請求的內容將作爲<code>msg.payload</code>提供。</p> | ||||
|     <p>如果可以確定請求的內容類型,則正文將被解析爲任何適當的類型。例如,<code>application/json</code>將被解析爲其JavaScript對象表示。</p> | ||||
|     <p><b>注意:</b>該節點不發送對請求的任何響應。該流程必須包含HTTP響應節點才能完成請求。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="http response"> | ||||
|     <p>將響應發送回從HTTP輸入節點接收的請求。</p> | ||||
|  | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload <span class="property-type">string</span></dt> | ||||
|         <dd>響應的正文。</dd> | ||||
|         <dt class="optional">statusCode <span class="property-type">數值</span></dt> | ||||
|         <dd>如果設置,則用作響應狀態代碼。默認值:200。</dd> | ||||
|         <dt class="optional">headers <span class="property-type">object</span></dt> | ||||
|         <dd>如果設置,則提供HTTP頭以包含在響應中。</dd> | ||||
|         <dt class="optional">cookies <span class="property-type">object</span></dt> | ||||
|         <dd>如果設置,則可用于設置或刪除cookie。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>還可以在節點本身內設置<code>statusCode</code>和<code>headers</code>。如果在節點內設置了屬性,則不能被相應的message屬性覆蓋。</p> | ||||
|     <h4>Cookie處理</h4> | ||||
|     <p><code>cookies</code>屬性必須是名稱/值對的對象。該值可以是使用默認選項設置cookie值的字符串,也可以是options對象。<p> | ||||
|     <p>下面的示例設置兩個cookie-一個名爲<code>name</code>的值爲<code>nick</code>,另一個名爲<code>session</code>的值爲<code>1234</code>,並且有效期設置爲15分鍾。</p> | ||||
|     <pre> | ||||
| msg.cookies = { | ||||
|     name: 'nick', | ||||
|     session: { | ||||
|         value: '1234', | ||||
|         maxAge: 900000 | ||||
|     } | ||||
| }</pre> | ||||
|     <p>有效選項包括:</p> | ||||
|     <ul> | ||||
|     <li><code>domain</code> - (字符串) Cookie的域名</li> | ||||
|     <li><code>expires</code> - (日期) GMT標准時間的到期日。如果未指定或設置爲0,則創建會話cookie</li> | ||||
|     <li><code>maxAge</code> - (字符串) 相對于當前時間的到期日期(以毫秒爲單位)</li> | ||||
|     <li><code>path</code> - (字符串) Cookie的路徑。默認爲/</li> | ||||
|     <li><code>value</code> - (字符串) Cookie使用的值</li> | ||||
|     </ul> | ||||
|     <p>要刪除Cookie,請將其<code>value</code>設置爲<code>null</code>。</p> | ||||
|  | ||||
| </script> | ||||
							
								
								
									
										78
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/21-httprequest.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/21-httprequest.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="http request"> | ||||
|     <p>發送HTTP請求並返回響應。</p> | ||||
|  | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt class="optional">url <span class="property-type">字符串</span></dt> | ||||
|         <dd>如果未在節點中配置,則此可選屬性設置請求的url。</dd> | ||||
|         <dt class="optional">method <span class="property-type">字符串</span></dt> | ||||
|         <dd>如果未在節點中配置,則此可選屬性設置請求的HTTP方法。必須是<code>GET</code>,<code>PUT</code>,<code>POST</code>,<code>PATCH</code>或<code>DELETE</code>之一。</dd> | ||||
|         <dt class="optional">headers <span class="property-type">object</span></dt> | ||||
|         <dd>設置請求的HTTP頭。</dd> | ||||
|         <dt class="optional">cookies <span class="property-type">object</span></dt> | ||||
|         <dd>如果設置,則可用于發送帶有請求的cookie。</dd> | ||||
|         <dt class="optional">payload</dt> | ||||
|         <dd>發送爲請求的正文。</dd> | ||||
|         <dt class="optional">rejectUnauthorized</dt> | ||||
|         <dd>如果設置爲<code>false</code>,則允許對使用自簽名證書的https站點進行請求。</dd> | ||||
|         <dt class="optional">followRedirects</dt> | ||||
|         <dd>如果設置爲<code>false</code>,則阻止遵循重定向(HTTP 301)。默認情況下爲<code>true</code></dd> | ||||
|         <dt class="optional">requestTimeout</dt> | ||||
|         <dd>如果設置爲正數毫秒,將覆蓋全局設置的<code>httpRequestTimeout</code>參數。</dd> | ||||
|     </dl> | ||||
|     <h3>輸出</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload <span class="property-type">字符串 | object | buffer</span></dt> | ||||
|         <dd>響應的正文。可以將節點配置爲以字符串形式返回主體,嘗試將其解析爲JSON字符串或將其保留爲二進制buffer。</dd> | ||||
|         <dt>statusCode <span class="property-type">數值</span></dt> | ||||
|         <dd>響應的狀態碼,如果請求無法完成,則返回錯誤碼。</dd> | ||||
|         <dt>headers <span class="property-type">object</span></dt> | ||||
|         <dd>包含響應頭的對象。</dd> | ||||
|         <dt>responseUrl <span class="property-type">字符串</span></dt> | ||||
|         <dd>如果在處理請求時發生任何重定向,則此屬性爲最終重定向的URL。否則則爲原始請求的URL。</dd> | ||||
|         <dt>responseCookies <span class="property-type">object</span></dt> | ||||
|         <dd>如果響應包含cookie,則此屬性是每個cookie的‘名稱/值’鍵值對的對象。</dd> | ||||
|         <dt>redirectList <span class="property-type">數組</span></dt> | ||||
|         <dd>如果請求被重定向了一次或多次,則累積的信息將被添加到此屬性。“location”是下一個重定向目標。cookie是從重定向源返回的cookie。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>在節點內配置後,URL屬性可以包含<a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache樣式</a>標簽。 這些標簽允許使用傳入消息的值來構造url。例如,如果url設置爲<code>example.com/{{{{topic}}}</code>,它將自動插入<code>msg.topic</code>的值。使用{{{...}}}可以防止mustache轉義/ &等字符。</p> | ||||
|     <p>節點可以選擇自動將<code>msg.payload</code>編碼爲GET請求的查詢字符串參數,在這種情況下,<code>msg.payload</code>必須是一個對象。</p> | ||||
|     <p><b>注意:</b>如果使用了代理,則應設置<code>http_proxy=...</code>環境變量並重新啓動Node-RED,或使用“代理配置”。如果設置了代理配置,則配置優先于環境變量。</p> | ||||
|     <h4>使用多個HTTP請求節點</h4> | ||||
|     <p>爲了在一個流程中多次使用該節點,必須要注意<code>msg.headers</code>屬性的處理。通常在第一個節點在響應頭中設置此屬性,而不期望在下一個節點的請求頭中使用此屬性。如果節點之間的<code>msg.headers</code>屬性保持不變,則第二個節點將忽略它。要設置自定義標題,首先應刪除<code>msg.headers</code>或將其重置爲空對象:<code>{}</code>。</p> | ||||
|     <h4>Cookie處理</h4> | ||||
|     <p>傳遞給節點的<code>cookies</code>屬性必須是‘名稱/值’鍵值對的對象。該值可以是設置cookie值的字符串,也可以是具有單個<code>value</code>屬性的對象。</p> | ||||
|     <p>請求返回的所有cookie都將在<code>responseCookies</code>屬性下傳遞回去。</p> | ||||
|     <h4>內容類型處理</h4> | ||||
|     <p>如果<code>msg.payload</code>是一個對象,則節點將自動將請求的內容類型設置爲<code>application/json</code>並對其進行編碼。</p> | ||||
|     <p>要將請求編碼爲表單數據,應將<code>msg.headers[“content-type”]</code>設置爲<code>application/x-www-form-urlencoded</code>。</p> | ||||
|     <h4>文件上傳</h4> | ||||
|     <p>要執行文件上傳,應將<code>msg.headers["content-type"]</code>設置爲<code>multipart/form-data</code>和<code>msg.payload</code>傳遞給節點的必須是具有以下結構的對象:</p> | ||||
|     <pre><code>{ | ||||
|     "KEY": { | ||||
|         "value": FILE_CONTENTS, | ||||
|         "options": { | ||||
|             "filename": "FILENAME" | ||||
|         } | ||||
|     } | ||||
| }</code></pre> | ||||
|     <p><code>KEY</code>,<code>FILE_CONTENTS</code>和<code>FILENAME</code>的值應設置爲適當的值。</p> | ||||
|      | ||||
| </script> | ||||
							
								
								
									
										35
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/22-websocket.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/22-websocket.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="websocket in"> | ||||
|   <p>WebSocket輸入節點。</p> | ||||
|   <p>默認情況下,從WebSocket接收的數據將位于<code>msg.payload</code>中。可以將套接字配置爲期望格式正確的JSON字符串,在這種情況下,它將解析JSON並將結果對象作爲整個消息發送。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="websocket out"> | ||||
|   <p>WebSocket輸出節點。</p> | ||||
|   <p>默認情況下,<code>msg.payload</code>將通過WebSocket發送。可以將套接字配置爲將整個<code>msg</code>對象編碼爲JSON字符串,然後通過WebSocket發送。</p> | ||||
|   <p>如果到達此節點的消息是從WebSocket In節點開始的,則該消息將發送回觸發流程的客戶端。否則,消息將廣播給所有連接的客戶端。</p> | ||||
|   <p>如果要廣播從“WebSocket輸入”節點開始的消息,則可以應該刪除流中的<code>msg._session</code>屬性。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="websocket-listener"> | ||||
|  <p>此配置節點使用指定的路徑創建WebSocket服務器端點。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="websocket-client"> | ||||
|  <p>此配置節點將WebSocket客戶端連接到指定的URL。</p> | ||||
| </script> | ||||
							
								
								
									
										35
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/31-tcpin.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/31-tcpin.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="tcp in"> | ||||
|     <p>提供TCP輸入選擇。可以連接到遠程TCP端口,或接受傳入連接。</p> | ||||
|     <p><b>注意:</b>在某些系統上,您可能需要root或管理員權限來訪問低于1024的端口。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="tcp out"> | ||||
|     <p>提供TCP輸出的選擇。可以連接到遠程TCP端口,接受傳入的連接,或回複從TCP In節點收到的消息。</p> | ||||
|     <p>僅發送<code>msg.payload</code>。</p> | ||||
|     <p>如果<code>msg.payload</code>是包含二進制數據的Base64編碼的字符串,則Base64解碼選項將導致它在發送之前先轉換回二進制。</p> | ||||
|     <p>如果不存在<code>msg._session</code>,則有效負載將發送到<b>所有</b>連接的客戶端。</p> | ||||
|     <p><b>注意:</b>在某些系統上,您可能需要root或管理員權限來訪問低于1024的端口。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="tcp request"> | ||||
|     <p>一個簡單的TCP請求節點。將<code>msg.payload</code>發送到服務器tcp端口,並期望得到響應。</p> | ||||
|     <p>連接到服務器,發送“請求”並接收“響應”。 可以從固定數量的字符,與指定字符匹配的字符中選擇操作,從第一個答複到達起等待指定的時間,等待數據到達,發送數據並立即取消連接而無需等待答複等操作中進行選擇。</p> | ||||
|     <p>響應將在<code>msg.payload</code>中作爲buffer輸出,因此您可能需要對它進行<code>.toString()</code>操作。</p> | ||||
|     <p>如果將tcp主機或端口留空,則必須使用<code>msg.host</code>和<code>msg.port</code>屬性進行設置。</p> | ||||
| </script> | ||||
							
								
								
									
										28
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/32-udp.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/network/32-udp.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="udp in"> | ||||
|   <p>UDP輸入節點。在<code>msg.payload</code>中生成Buffer,字符串或Base64編碼的字符串。支持組播。</p> | ||||
|   <p>在<code>msg.ip</code>和<code>msg.port</code>中設置接收到的消息的IP地址和端口。</p> | ||||
|   <p><b>注意:</b>在某些系統上,您可能需要root或管理員權限才能使用低于1024的端口或廣播。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="udp out"> | ||||
|   <p>該節點將<code>msg.payload</code>發送到指定的UDP主機和端口。支持組播。</p> | ||||
|   <p>您也可以使用<code>msg.ip</code>和<code>msg.port</code>設置目標值,但是靜態配置的值具有優先權。</p> | ||||
|   <p>如果選擇廣播,則將地址設置爲本地廣播IP地址。或者也可以嘗試使用全局廣播地址255.255.255.255。</p> | ||||
|   <p><b>注意:</b>在某些系統上,您可能需要root或管理員權限才能使用低于1024的端口或廣播。</p> | ||||
| </script> | ||||
							
								
								
									
										43
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-CSV.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-CSV.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="csv"> | ||||
|     <p>在CSV格式的字符串及其JavaScript對象表示形式之間進行相互轉換。</p> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">object | 數組 | 字符串</span></dt> | ||||
|         <dd>JavaScript對象,數組或CSV字符串。</dd> | ||||
|     </dl> | ||||
|     <h3>輸出</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">object | 數組 | 字符串</span></dt> | ||||
|         <dd> | ||||
|         <ul> | ||||
|             <li>如果輸入是字符串,它將嘗試將其解析爲CSV,並爲每行創建鍵/值對的JavaScript對象。然後該節點將爲每行發送一條消息,或者發送一條包含對象數組的消息。</li> | ||||
|             <li>如果輸入是JavaScript對象,它將嘗試構建CSV字符串。</li> | ||||
|             <li>如果輸入是簡單值的數組,則將構建單行CSV字符串。</li> | ||||
|             <li>如果輸入是數組數組或對象數組,則會創建多行CSV字符串。</li> | ||||
|         </ul> | ||||
|         </dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>列模板可以包含列名稱的有序列表。將CSV轉換爲對象時,列名將用作屬性名稱。或者也可以從CSV的第一行中獲取列名稱。</p> | ||||
|     <p>轉換爲CSV時,列模板用于標識從對象中提取的屬性以及提取的順序。</p> | ||||
|     <p>如果輸入是數組,則列模板僅用于有選擇地生成一行列標題。</p> | ||||
|     <p>只要正確設置<code>parts</code>屬性,該節點就可以接受多部分輸入。</p> | ||||
|     <p>如果輸出多個消息,則將設置其<code>parts</code>屬性並形成完整的消息序列。</p> | ||||
|     <p><b>注意:</b>列模板必須用逗號分隔,即使數據中已有了其他分隔符。</p> | ||||
| </script> | ||||
							
								
								
									
										33
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-HTML.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-HTML.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="html"> | ||||
|     <p>使用CSS選擇器從<code>msg.payload</code>中保存的html文檔中提取元素。</p> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|     <dt>payload <span class="property-type">字符串</span></dt> | ||||
|     <dd>從中提取元素的html字符串。</dd> | ||||
|     <dt class="optional">select <span class="property-type">字符串</span></dt> | ||||
|     <dd>如果未在編輯面板中配置,則可以將選擇器設置爲msg的屬性。</dd> | ||||
| </dl> | ||||
|     <h3>Output</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload <span class="property-type">數組 | 字符串</span></dt> | ||||
|         <dd>結果可以是有效載荷中包含匹配元素的數組的單個消息;也可以是多條消息,每條消息都包含匹配元素。發送多條消息時,需要爲消息設置<code>parts</code>。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>該節點支持CSS和jQuery選擇器的組合。查看<a href="https://github.com/fb55/CSSselect#user-content-supported-selectors" target="_blank">css-select documentation</a> 來獲得更多信息。</p> | ||||
| </script> | ||||
							
								
								
									
										43
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-JSON.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-JSON.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="json"> | ||||
|     <p>在JSON字符串及其JavaScript對象表示形式之間相互轉換。</p> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">object | 字符串</span></dt> | ||||
|         <dd>JavaScript對象或JSON字符串。</dd> | ||||
|         <dt>schema<span class="property-type">object</span></dt> | ||||
|         <dd>可選的JSON Schema對象用于驗證有效負載。在將<code>msg</code>發送到下一個節點之前,將刪除該屬性。</dd> | ||||
|     </dl> | ||||
|     <h3>Outputs</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">object | 字符串</span></dt> | ||||
|         <dd> | ||||
|             <ul> | ||||
|                 <li>如果輸入是JSON字符串,它將嘗試將其解析爲JavaScript對象。</li> | ||||
|                 <li>如果輸入是JavaScript對象,它將創建一個JSON字符串。並可以選擇對此JSON字符串進行整形。</li> | ||||
|             </ul> | ||||
|         </dd> | ||||
|         <dt>schemaError<span class="property-type">數組</span></dt> | ||||
|         <dd>如果JSON模式驗證失敗,則catch節點將具有包含錯誤數組的<code>schemaError</code>屬性。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>默認的轉換目標是<code>msg.payload</code>,但是也可以轉換消息的其它屬性。</p> | ||||
|     <p>您可以將其設置爲僅執行特定的轉換,而不是自動選擇雙向轉換。例如,即使對<code>HTTP In</code>節點的請求未正確設置‘content-type’,也可以使用它來確保JSON節點的轉換結果是JavaScript對象</p> | ||||
|     <p>如果指定了轉換爲JSON字符串,則不會對收到的字符串進行進一步的檢查。也就是說,即使指定了格式化選項,它也不會檢查字符串是否正確爲JSON或對JSON執行整形。</p> | ||||
|     <p>有關JSON模式的更多詳細信息,請查閱<a href="http://json-schema.org/latest/json-schema-validation.html">規範</a>.</p> | ||||
| </script> | ||||
							
								
								
									
										48
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-XML.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-XML.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="xml"> | ||||
|   <p>在XML字符串及其JavaScript對象表示形式之間進行相互轉換。</p> | ||||
|   <h3>輸入</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt>payload<span class="property-type">object | 字符串</span></dt> | ||||
|       <dd>JavaScript對象或XML字符串。</dd> | ||||
|   </dl> | ||||
|   <h3>輸出</h3> | ||||
|   <dl class="message-properties"> | ||||
|       <dt>payload<span class="property-type">object | 字符串</span></dt> | ||||
|       <dd> | ||||
|           <ul> | ||||
|               <li>如果輸入是字符串,它將嘗試將其解析爲XML並創建一個JavaScript對象。</li> | ||||
|               <li>如果輸入是JavaScript對象,它將嘗試構建XML字符串。</li> | ||||
|           </ul> | ||||
|       </dd> | ||||
|       <dt class="optional">options <span class="property-type">object</span></dt> | ||||
|       <dd>可以將選項傳遞給內部使用的XML轉換庫。請參見<a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank"> xml2js文檔</a> 來獲取更多信息。</dd> | ||||
|   </dl> | ||||
|   <h3>詳細</h3> | ||||
|   <p>在XML和對象之間進行轉換時,默認情況下XML屬性會添加到名爲<code>$</code>的屬性中。將文本內容添加到名爲<code>_</code>的屬性中。這些屬性名稱可以在節點設置中更改。</p> | ||||
|   <p>例如,將如下所示轉換以下XML:</p> | ||||
|   <pre><p class="tag">Hello World</p></pre> | ||||
|   <pre>{ | ||||
| "p": { | ||||
|   "$": { | ||||
|     "class": "tag" | ||||
|   }, | ||||
|   "_": "Hello World" | ||||
| } | ||||
| }</pre> | ||||
| </script> | ||||
							
								
								
									
										34
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-YAML.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/parsers/70-YAML.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="yaml"> | ||||
|     <p>在YAML格式的字符串及其JavaScript對象表示形式之間相互轉換。</p> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">object | 字符串</span></dt> | ||||
|         <dd>JavaScript對象或YAML字符串。</dd> | ||||
|     </dl> | ||||
|     <h3>Outputs</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">object | 字符串</span></dt> | ||||
|         <dd> | ||||
|             <ul> | ||||
|                 <li>如果輸入是YAML字符串,它將嘗試將其解析爲JavaScript對象。</li> | ||||
|                 <li>如果輸入是JavaScript對象,它將創建一個YAML字符串。</li> | ||||
|             </ul> | ||||
|         </dd> | ||||
|     </dl> | ||||
| </script> | ||||
							
								
								
									
										133
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/sequence/17-split.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/sequence/17-split.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="split"> | ||||
|     <p>將一條消息拆分爲一系列消息。</p> | ||||
|  | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload<span class="property-type">object | 字符串 | 數組 | buffer</span></dt> | ||||
|         <dd>節點的行爲由<code>msg.payload</code>的類型決定: | ||||
|             <ul> | ||||
|                 <li><b>字符串</b>/<b>buffer</b> - 使用指定的字符(默認值:<code>\n</code>),緩衝區序列或固定長度將消息拆分。</li> | ||||
|                 <li><b>數組</b> - 消息被拆分爲單個數組元素或固定長度的數組。</li> | ||||
|                 <li><b>object</b> - 將爲對象的每個鍵/值對發送一條消息。</li> | ||||
|             </ul> | ||||
|         </dd> | ||||
|     </dl> | ||||
|     <h3>輸出</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>parts<span class="property-type">object</span></dt> | ||||
|         <dd>此屬性包含有關如何將消息與原始消息分開的信息。如果傳遞給<b>join</b>節點,則可以將序列重組爲單個消息。該屬性具有以下屬性: | ||||
|         <ul> | ||||
|             <li><code>id</code> - 一組消息的標識符</li> | ||||
|             <li><code>index</code> - 組中的位置</li> | ||||
|             <li><code>count</code> - 如果已知組中的郵件總數。請參閱下面的“流媒體模式”</li> | ||||
|             <li><code>type</code> - 消息的類型-字符串/數組/對象/buffer</li> | ||||
|             <li><code>ch</code> - 對于字符串或buffer,用于將消息拆分爲字符串或字節數組的數據</li> | ||||
|             <li><code>key</code> - 對于對象,創建此消息的屬性的鍵。可以將節點配置爲也將此值複制到另一個消息屬性,例如<code>msg.topic</code></li> | ||||
|             <li><code>len</code> - 使用固定長度值拆分消息時,每段子消息的長度</li> | ||||
|         </ul> | ||||
|         </dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>在使用<b>join</b>節點將序列重新組合爲單個消息之前,推薦使用此節點來輕松地創建跨消息序列,執行通用操作的流。</p> | ||||
|     <p>它使用<code>msg.parts</code>屬性跟蹤序列的各個部分。</p> | ||||
|     <h4>流媒體模式</h4> | ||||
|     <p>該節點還可以用于重排消息流。例如,發送換行符終止命令的串行設備可能會傳遞一條消息,並在其末尾帶有部分命令。 在“流模式”下,此節點將拆分一條消息並發送每個完整的段。如果末尾有部分片段,則該節點將保留該片段,並將其添加到收到的下一條消息之前。</p> | ||||
|     <p>在此模式下運行時,該節點將不會設置<code>msg.parts.count</code>屬性,因爲流中期望的消息數還是未知的。這意味著它不能在自動模式下與<b>join</b>節點一起使用。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="join"> | ||||
|     <p>將消息序列合並爲一條消息.</p> | ||||
|     <p>共有三種模式:</p> | ||||
|     <dl> | ||||
|         <dt>自動模式</dt> | ||||
|         <dd>與<b>split</b>節點配對時,它將自動將已被拆分的消息進行合並。</dd> | ||||
|         <dt>手動模式</dt> | ||||
|         <dd>手動地以各種方式合並消息序列。</dd> | ||||
|         <dt>列聚合模式</dt> | ||||
|         <dd>對消息列中的所有消息應用表達式以將其簡化爲單個消息。</dd> | ||||
|     </dl> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt class="optional">parts<span class="property-type">object</span></dt> | ||||
|         <dd>使用自動模式時,所有的消息都應包含此屬性。<b>split</b>節點會生成此屬性,但也可以手動進行設置。該屬性具有以下屬性: | ||||
|         <ul> | ||||
|             <li><code>id</code> - 消息組的標識符</li> | ||||
|             <li><code>index</code> - 組中的位置</li> | ||||
|             <li><code>count</code> - 如果已知組中的郵件總數。請參閱下面的“流媒體模式”</li> | ||||
|             <li><code>type</code> - 消息的類型-字符串/數組/對象/buffer</li> | ||||
|             <li><code>ch</code> - 對于字符串或buffer,用于將消息拆分爲字符串或字節數組的數據</li> | ||||
|             <li><code>key</code> - 對于對象,創建此消息的屬性的鍵。可以將節點配置爲也將此值複制到另一個消息屬性,例如<code>msg.topic</code>/li> | ||||
|             <li><code>len</code> - 使用固定長度值拆分消息時,每段子消息的長度</li> | ||||
|         </ul> | ||||
|         </dd> | ||||
|         <dt class="optional">complete</dt> | ||||
|         <dd>如果設置,則節點將以其當前狀態發送其輸出消息。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|  | ||||
|     <h4>自動模式</h4> | ||||
|     <p>自動模式使用傳入消息的<code>parts</code>屬性來確定應如何連接序列。這使它可以自動逆轉<b>split</b>節點的操作。</p> | ||||
|  | ||||
|     <h4>手動模式</h4> | ||||
|     <p>設置爲以手動模式時,該節點能以各種不同的方法來處理消息:</p> | ||||
|     <ul> | ||||
|         <li><b>字符串</b>或<b>緩衝區</b>-通過將每條消息的選定屬性與指定的連接字符或緩衝區連接起來。</li> | ||||
|         <li><b>數組</b> - 通過將每個選定的屬性或整個消息添加到輸出數組</li> | ||||
|         <li><b>鍵/值對象</b> - 通過使用每個消息的屬性來確定存儲所需值的鍵。</li> | ||||
|         <li><b>merged object</b> - 通過將每個消息的屬性合並到一個對象下。</li> | ||||
|     </ul> | ||||
|     <p>輸出消息的其他屬性都取自發送結果前的最後一條消息。</p> | ||||
|     <p>可以用<i>計數</i>來確定應接收多少條消息來進行合並。對于對象輸出,可以設置爲達到此計數後的每條後續消息都發送一條輸出。</p> | ||||
|     <p>可以用<i>超時</i>來設置發送新消息之前的等待時間。</p> | ||||
|     <p>如果收到設置了<b>msg.complete</b>屬性的消息時發送輸出消息並重置消息列數。</p> | ||||
|     <p>如果收到設置了<b>msg.reset</b>屬性的消息,則部分收到的消息將被刪除而不發送,同時重置消息列數。</p> | ||||
|  | ||||
|     <h4>列聚合模式</h4> | ||||
|     <p>選擇列聚合模式時,將表達式應用于組成消息列的每條消息,並使用聚合值組成一條消息。</p> | ||||
|  | ||||
|     <dl class="message-properties"> | ||||
|         <dt>初始值</dt> | ||||
|         <dd>累積值的初始值(<code>$A</code>)。</dd> | ||||
|         <dt>聚合表達式</dt> | ||||
|         <dd>序列中的每個消息調用的JSONata表達式。結果將作爲累加值傳遞到表達式的下一個調用。在表達式中,可以使用以下特殊變量: | ||||
|             <ul> | ||||
|                 <li><code>$A</code>: 累計值 </li> | ||||
|                 <li><code>$I</code>: 消息在序列中的索引</li> | ||||
|                 <li><code>$N</code>: 序列中的消息數</li> | ||||
|             </ul> | ||||
|         </dd> | ||||
|         <dt>最終調整式子</dt> | ||||
|         <dd>可選的JSONata表達式,在將聚合表達式應用于序列中的所有消息之後應用。在表達式中,可以使用以下特殊變量: | ||||
|             <ul> | ||||
|                 <li><code>$A</code>: 累計值</li> | ||||
|                 <li><code>$N</code>: 消息在序列中的索引</li> | ||||
|             </ul> | ||||
|         </dd> | ||||
|         <p>默認情況下,按順序從序列的第一條消息到最後一條消息應用聚合表達式。也可以選擇以相反的順序應用聚合表達式。</p> | ||||
|     </dl> | ||||
|     <p><b>例子:</b>給定一系列數字值,以下設置將計算平均值: | ||||
|         <ul> | ||||
|             <li><b>聚合表達式</b>: <code>$A+payload</code></li> | ||||
|             <li><b>初始值</b>: <code>0</code></li> | ||||
|             <li><b>最終調整式</b>: <code>$A/$N</code></li> | ||||
|         </ul> | ||||
|     </p> | ||||
|     <h4>儲存訊息</h4> | ||||
|     <p>該節點將在內部緩存消息,以便跨序列工作。運行時設置<code>nodeMessageBufferMaxLength</code>可用于設定緩存的消息數。</p> | ||||
| </script> | ||||
							
								
								
									
										41
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/sequence/18-sort.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/sequence/18-sort.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="sort"> | ||||
|     <p>對消息屬性或消息序列進行排序的函數。</p> | ||||
|     <p>當配置爲對消息屬性進行排序時,節點將對指定消息屬性所指向的數組數據進行排序。</p> | ||||
|     <p>當配置爲對消息序列排序時,它將對消息重新排序。</p> | ||||
|     <p>排序順序可以是:</p> | ||||
|     <ul> | ||||
|         <li><b>升序</b></li> | ||||
|         <li><b>降序</b></li> | ||||
|     </ul> | ||||
|     <p>對于數字,可以通過複選框指定數字順序。</p> | ||||
|     <p>排序鍵可以是元素值,也可以是JSONata表達式來對屬性值進行排序,還可以是message屬性或JSONata表達式來對消息序列進行排序。<p> | ||||
|     <p>在對消息序列進行排序時,排序節點依賴于接收到的消息來設置<code>msg.parts</code>。拆分節點將生成此屬性,但也可以手動創建。它具有以下屬性:</p> | ||||
|     <p> | ||||
|         <ul> | ||||
|             <li><code>id</code> - 消息組的標識符</li> | ||||
|             <li><code>index</code> - 組中的位置</li> | ||||
|             <li><code>count</code> - 群組中的郵件總數</li> | ||||
|         </ul> | ||||
|     </p> | ||||
|     <p><b>注意:</b>在此節點的處理中,消息在內部存儲。通過指定要累積的最大消息數,可以防止意外的高內存使用。默認設置是不限制消息數量。 | ||||
|         <ul> | ||||
|             <li><code>nodeMessageBufferMaxLength</code>屬性在<b>settings.js</b>中設置。</li> | ||||
|         </ul> | ||||
|     </p> | ||||
| </script> | ||||
							
								
								
									
										34
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/sequence/19-batch.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/sequence/19-batch.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="batch"> | ||||
|   <p>根據各種規則創建消息序列。</p> | ||||
|   <h3>詳細</h3> | ||||
|   <p>有三種創建消息序列的模式:</p> | ||||
|   <dl> | ||||
|       <dt>訊息數</dt> | ||||
|       <dd>將消息分組爲給定長度的序列。 <b>overlap</b>(重疊)選項指定在一個序列的末尾應重複多少消息。</dd> | ||||
|  | ||||
|       <dt>時間間隔</dt> | ||||
|       <dd>對在指定時間間隔內到達的郵件進行分組。如果在該時間間隔內沒有消息到達,則該節點可以選擇發送空消息。</dd> | ||||
|  | ||||
|       <dt>串聯序列</dt> | ||||
|       <dd>通過串聯輸入序列來創建消息序列。每條消息必須具有<code>msg.topic</code>屬性和標識其序列的<code>msg.parts</code>屬性。該節點配置有<code>topic</code>值列表,以標識所連接的順序序列。 | ||||
|       </dd> | ||||
|   </dl> | ||||
|   <h4>儲存訊息</h4> | ||||
|   <p>該節點將在內部緩衝消息,以便跨序列工作。運行時設置<code>nodeMessageBufferMaxLength</code>可用于限制節點將緩存多少消息。</p> | ||||
| </script> | ||||
							
								
								
									
										55
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/storage/10-file.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/storage/10-file.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/html" data-help-name="file"> | ||||
|     <p>將<code>msg.payload</code>寫入文件,添加到末尾或替換現有內容。或者,它也可以刪除文件。</p> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt class="optional">filename<span class="property-type">字符串</span></dt> | ||||
|         <dd>如果未在節點中配置,則此可選屬性可以設置文件名。</dd> | ||||
|     </dl> | ||||
|     <h3>輸出</h3> | ||||
|     <p>寫入完成後,輸入消息將發送到輸出端口。</p> | ||||
|     <h3>詳細</h3> | ||||
|     <p>每個消息的有效荷載將添加到文件的末尾,可以選擇在每個消息之間添加一個換行符(\n)。</p> | ||||
|     <p>如果使用<code>msg.filename</code>,則每次寫入後文件都會關閉。爲了獲得最佳體驗,請使用固定的文件名。</p> | ||||
|     <p>可以將其配置爲覆蓋整個文件,而不是在文件後添加段落。例如,在將二進制數據寫入文件(例如圖像)時,應使用此選項,並且應禁用添加換行符的選項。</p> | ||||
|     <p>可以從編碼列表中指定寫入文件的數據的編碼。</p> | ||||
|     <p>您可以將此節點配置爲刪除文件。</p> | ||||
| </script> | ||||
|  | ||||
| <script type="text/html" data-help-name="file in"> | ||||
|     <p>以字符串或二進制緩衝區的形式讀取文件的內容。</p> | ||||
|     <h3>輸入</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt class="optional">filename<span class="property-type">字符串</span></dt> | ||||
|         <dd>如果未在節點配置中設置,該屬性可以選擇要讀取的文件名。</dd> | ||||
|     </dl> | ||||
|     <h3>輸出</h3> | ||||
|     <dl class="message-properties"> | ||||
|         <dt>payload <span class="property-type">字符串 | buffer</span></dt> | ||||
|         <dd>文件的內容可以是字符串,也可以是二進制的buffer。</dd> | ||||
|         <dt class="optional">filename <span class="property-type">字符串</span></dt> | ||||
|         <dd>如果未在節點配置中設置,該屬性可以選擇要讀取的文件名。</dd> | ||||
|     </dl> | ||||
|     <h3>詳細</h3> | ||||
|     <p>文件名應該是絕對路徑,否則將相對于Node-RED進程的工作目錄。</p> | ||||
|     <p>在Windows上,可能需要使用轉義路徑分隔符,例如:<code>\\Users\\myUser</code>。</p> | ||||
|     <p>可以選擇將文本文件拆分爲幾行,每行輸出一條消息,或者將二進制文件拆分爲較小的buffer塊-塊大小取決于操作系統,但通常爲64k(Linux/Mac)或41k(Windows)。</p> | ||||
|     <p>當拆分爲多條消息時,每條消息將具有<code>parts</code>屬性集,從而形成完整的消息序列。</p> | ||||
|     <p>如果輸出格式爲字符串,則可以從編碼列表中指定輸入數據的編碼。</p> | ||||
|     <p>應該使用Catch節點來捕獲並處理錯誤。</p> | ||||
| </script> | ||||
							
								
								
									
										25
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/storage/23-watch.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								packages/node_modules/@node-red/nodes/locales/zh-TW/storage/23-watch.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| <!-- | ||||
|   Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
|  | ||||
| <script type="text/x-red" data-help-name="watch"> | ||||
|   <p>監視目錄或文件中的更改。</p> | ||||
|   <p>您可以輸入用逗號分隔的目錄和/或文件的列表。您需要在所有帶有空格的地方加上引號“...”。</p> | ||||
|   <p>在Windows上,必須在任何目錄名稱中使用雙反斜杠<code>\\</code>。</p> | ||||
|   <p>實際更改的文件的完整文件名將放入<code>msg.payload</code>和<code>msg.filename</code>中,而監視列表的字符串化版本將在<code>msg.topic</code>中返回。</p> | ||||
|   <p><code>msg.file</code>僅包含已更改文件的短文件名。<code>msg.type</code>更改了事物的類型,通常是<i>file</i>或<i>directory</i>,而<code>msg.size</code>保留了文件的大小(以字節爲單位)。</p> | ||||
|   <p>當然,在Linux中,<i>everything</i>也是一個文件,因此可以監視</p> | ||||
|   <p><b>注意:</b>該目錄或文件必須存在才能被監視。如果文件或目錄被刪除,即使重新創建它也可能不再被監視。</p> | ||||
| </script> | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/nodes", | ||||
|     "version": "1.0.3", | ||||
|     "version": "1.0.4", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
| @@ -15,30 +15,30 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "ajv": "6.10.2", | ||||
|         "ajv": "6.12.0", | ||||
|         "body-parser": "1.19.0", | ||||
|         "cheerio": "0.22.0", | ||||
|         "content-type": "1.0.4", | ||||
|         "cookie-parser": "1.4.4", | ||||
|         "cookie": "0.4.0", | ||||
|         "cors": "2.8.5", | ||||
|         "cron": "1.7.2", | ||||
|         "cron": "1.8.2", | ||||
|         "denque": "1.4.1", | ||||
|         "fs-extra": "8.1.0", | ||||
|         "fs.notify": "0.0.4", | ||||
|         "hash-sum": "2.0.0", | ||||
|         "https-proxy-agent": "2.2.4", | ||||
|         "https-proxy-agent": "5.0.0", | ||||
|         "is-utf8": "0.2.1", | ||||
|         "js-yaml": "3.13.1", | ||||
|         "media-typer": "1.1.0", | ||||
|         "mqtt": "2.18.8", | ||||
|         "multer": "1.4.2", | ||||
|         "mustache": "3.0.2", | ||||
|         "mustache": "4.0.0", | ||||
|         "on-headers": "1.0.2", | ||||
|         "raw-body": "2.4.1", | ||||
|         "request": "2.88.0", | ||||
|         "ws": "6.2.1", | ||||
|         "xml2js": "0.4.22", | ||||
|         "iconv-lite": "0.5.0" | ||||
|         "xml2js": "0.4.23", | ||||
|         "iconv-lite": "0.5.1" | ||||
|     } | ||||
| } | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user