mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
merge upstream/dev
This commit is contained in:
commit
08ec04c889
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;
|
||||
@ -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() {
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
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 (!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) {
|
||||
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,13 +1939,15 @@ 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') {
|
||||
} 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>'+
|
||||
@ -2033,6 +2035,25 @@ RED.projects = (function() {
|
||||
]
|
||||
});
|
||||
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);
|
||||
@ -45,6 +54,7 @@
|
||||
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(list);
|
||||
return str;
|
||||
}
|
||||
//console.log("Closing",c,"at",i,"compare",oldFrame.type,oldFrame.pos);
|
||||
@ -53,19 +63,32 @@
|
||||
list.push(frame);
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
stack.pop();
|
||||
var f = stack.pop();
|
||||
f.end = i;
|
||||
}
|
||||
} else if (inRegex) {
|
||||
if (c === "/") {
|
||||
inRegex = false;
|
||||
var f = stack.pop();
|
||||
f.end = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// console.log("list",list);
|
||||
|
||||
}
|
||||
// console.log(stack);
|
||||
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,30 +96,52 @@
|
||||
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);
|
||||
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,7 +51,8 @@ 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",
|
||||
{
|
||||
token: "keyword",
|
||||
regex: /λ/
|
||||
},
|
||||
{
|
||||
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
@ -176,8 +178,6 @@
|
||||
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(() => {
|
||||
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 !== "") {
|
||||
//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;
|
||||
@ -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,8 +630,14 @@ module.exports = function(RED) {
|
||||
var group = inflight[partId];
|
||||
if (payloadType === 'buffer') {
|
||||
if (property !== undefined) {
|
||||
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') {
|
||||
group.payload[propertyKey] = property;
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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":"私密金鑰密碼 (可選)"
|
||||
"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,6 +204,7 @@
|
||||
"oldrc": "使用舊式輸出 (相容模式)"
|
||||
},
|
||||
"function": {
|
||||
"function": "函數",
|
||||
"label": {
|
||||
"function": "函數",
|
||||
"outputs": "輸出"
|
||||
@ -187,6 +215,7 @@
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"template": "模板",
|
||||
"label": {
|
||||
"template": "模版",
|
||||
"property": "屬性",
|
||||
@ -272,6 +301,9 @@
|
||||
"wait-reset": "等待被重置",
|
||||
"wait-for": "等待",
|
||||
"wait-loop": "週期性重發",
|
||||
"for": "處理",
|
||||
"bytopics": "每個msg.topic",
|
||||
"alltopics": "所有消息",
|
||||
"duration": {
|
||||
"ms": "毫秒",
|
||||
"s": "秒",
|
||||
@ -290,6 +322,7 @@
|
||||
}
|
||||
},
|
||||
"comment": {
|
||||
"comment": "注釋"
|
||||
},
|
||||
"unknown": {
|
||||
"label": {
|
||||
@ -303,6 +336,7 @@
|
||||
"example": "e.g. localhost",
|
||||
"output": "輸出",
|
||||
"qos": "QoS",
|
||||
"retain": "保持",
|
||||
"clientid": "使用者端ID",
|
||||
"port": "埠",
|
||||
"keepalive": "Keepalive計時(秒)",
|
||||
@ -312,17 +346,22 @@
|
||||
"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",
|
||||
"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 設置",
|
||||
"basic": "基本認證",
|
||||
"digest": "摘要認證",
|
||||
"bearer": "bearer認證",
|
||||
"use-proxy": "使用代理服務器",
|
||||
"persist": "對連接啟用keep-alive",
|
||||
"proxy-config": "代理服務器設置",
|
||||
"use-proxyauth": "使用代理身份驗證",
|
||||
"noproxy-hosts": "代理例外",
|
||||
"utf8": "UTF-8 字串",
|
||||
"binary": "二進位資料",
|
||||
"json": "JSON對象",
|
||||
@ -376,7 +433,10 @@
|
||||
"json-error": "JSON 解析錯誤",
|
||||
"no-url": "未設定 URL",
|
||||
"deprecated-call": "__method__方法已棄用",
|
||||
"invalid-transport":"非HTTP傳輸請求"
|
||||
"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,15 +594,18 @@
|
||||
"ip-notset": "udp: IP地址未設定",
|
||||
"port-notset": "udp: 埠未設定",
|
||||
"port-invalid": "udp: 無效埠號碼",
|
||||
"alreadyused": "udp: 埠已被佔用"
|
||||
"alreadyused": "udp: 埠已被佔用",
|
||||
"ifnotfound": "udp: 接口 __iface__ 未發現"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
"switch": "switch",
|
||||
"label": {
|
||||
"property": "屬性",
|
||||
"rule": "規則",
|
||||
"repair": "重建資訊佇列"
|
||||
},
|
||||
"previous": "先前值",
|
||||
"and": "與",
|
||||
"checkall": "全選所有規則",
|
||||
"stopfirst": "接受第一條匹配資訊後停止",
|
||||
@ -550,11 +618,15 @@
|
||||
"false": "為假",
|
||||
"null": "為空",
|
||||
"nnull": "非空",
|
||||
"istype": "類型是",
|
||||
"empty": "為空",
|
||||
"nempty": "非空",
|
||||
"head": "head",
|
||||
"tail": "tail",
|
||||
"index": "index between",
|
||||
"exp": "JSONata運算式",
|
||||
"else":"除此以外"
|
||||
"else": "除此以外",
|
||||
"hask": "擁有鍵"
|
||||
},
|
||||
"errors": {
|
||||
"invalid-expr": "無效的JSONata運算式: __error__",
|
||||
@ -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",
|
||||
@ -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,6 +837,7 @@
|
||||
"tip": "提示: 檔案名應該是絕對路徑,否則它將相對於Node-RED進程的工作目錄。"
|
||||
},
|
||||
"split": {
|
||||
"split": "split",
|
||||
"intro": "基於以下類型拆分<code>msg.payload</code>:",
|
||||
"object": "<b>對象</b>",
|
||||
"objectSend": "每個鍵值對作為單個消息發送",
|
||||
@ -823,6 +849,7 @@
|
||||
"addname": " 複製鍵到 "
|
||||
},
|
||||
"join": {
|
||||
"join": "join",
|
||||
"mode": {
|
||||
"mode": "模式",
|
||||
"auto": "自動",
|
||||
@ -831,6 +858,7 @@
|
||||
"custom": "手動"
|
||||
},
|
||||
"combine": "合併每個",
|
||||
"completeMessage": "完整的消息",
|
||||
"create": "輸出為",
|
||||
"type": {
|
||||
"string": "字串",
|
||||
@ -846,7 +874,7 @@
|
||||
"afterCount": "達到一定數量的資訊時",
|
||||
"count": "數量",
|
||||
"subsequent": "和每個後續的消息",
|
||||
"afterTimeout":"第一條消息的若干時間後",
|
||||
"afterTimeout": "第一條消息的若幹時間後",
|
||||
"seconds": "秒",
|
||||
"complete": "在收到存在<code>msg.complete</code>的消息後",
|
||||
"tip": "此模式假定此節點與<i>split</i>相連, 或者接收到的消息有正確配置的<code>msg.parts</code>屬性.",
|
||||
@ -869,6 +897,7 @@
|
||||
}
|
||||
},
|
||||
"sort": {
|
||||
"sort": "排序",
|
||||
"target": "排序屬性",
|
||||
"seq": "資訊佇列",
|
||||
"key": "鍵值",
|
||||
@ -877,11 +906,12 @@
|
||||
"ascending": "昇冪",
|
||||
"descending": "降冪",
|
||||
"as-number": "作為數值",
|
||||
"invalid-exp" : "sort節點中存在無效的JSONata運算式",
|
||||
"too-many" : "sort節點中有太多待定信息",
|
||||
"clear" : "清空sort節點中的待定資訊"
|
||||
"invalid-exp": "排序節點中存在無效的JSONata運算式",
|
||||
"too-many": "排序節點中有太多待定信息",
|
||||
"clear": "清空排序節點中的待定資訊"
|
||||
},
|
||||
"batch": {
|
||||
"batch": "batch",
|
||||
"mode": {
|
||||
"label": "模式",
|
||||
"num-msgs": "按指定數量分組",
|
||||
|
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
Loading…
Reference in New Issue
Block a user