Compare commits

..

No commits in common. "master" and "1.1.3" have entirely different histories.

1078 changed files with 25634 additions and 213506 deletions

35
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,35 @@
<!--
## Before you hit that Submit button....
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
If your issue is:
- a general 'how-to' type question,
- a feature request or suggestion for a change,
- or problems with 3rd party (`node-red-contrib-`) nodes
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
That way the whole Node-RED user community can help, rather than rely on the core development team.
## So you have a real issue to raise...
To help us understand the issue, please fill-in as much of the following information as you can:
-->
### What are the steps to reproduce?
### What happens?
### What do you expect to happen?
### Please tell us about your environment:
- [ ] Node-RED version:
- [ ] Node.js version:
- [ ] npm version:
- [ ] Platform/OS:
- [ ] Browser:
- [ ] running in Docker:

39
.github/ISSUE_TEMPLATE/--bug_report.md vendored Normal file
View File

@ -0,0 +1,39 @@
---
name: Bug report
about: Reproducible software issues in the core of Node-RED
title: ''
labels: ''
assignees: ''
---
<!--
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
If your issue is:
- a general 'how-to' type question,
- a feature request or suggestion for a change,
- or problems with 3rd party (`node-red-contrib-`) nodes
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
That way the whole Node-RED user community can help, rather than rely on the core development team.
To help us understand the issue, please fill-in as much of the following information as you can:
-->
### What are the steps to reproduce?
### What happens?
### What do you expect to happen?
### Please tell us about your environment:
- [ ] Node-RED version:
- [ ] Node.js version:
- [ ] npm version:
- [ ] Platform/OS:
- [ ] Browser:

View File

@ -0,0 +1,17 @@
---
name: Anything Else
about: Something that is not a bug report
title: ''
labels: ''
assignees: ''
---
Please DO NOT raise an issue.
We DO NOT use the issue tracker for general support or feature requests. Only bug reports should be raised here using the 'Bug report' template.
For general support, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack). You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
That way the whole Node-RED user community can help, rather than rely on the core development team.
For feature requests, please use the Node-RED Forum](https://discourse.nodered.org). Many ideas have already been discussed there and you should search that for your request before starting a new discussion.

View File

@ -1,61 +0,0 @@
name: 🐞 Report a bug
description: File a bug/issue on the core of Node-RED
labels: [needs-triage]
body:
- type: markdown
attributes:
value: |
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
If your issue is:
- a general 'how-to' type question,
- a feature request or suggestion for a change,
- or problems with 3rd party (`node-red-contrib-`) nodes
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
That way the whole Node-RED user community can help, rather than rely on the core development team.
To help us understand the issue, please fill-in as much of the following information as you can:
- type: textarea
attributes:
label: Current Behavior
description: A clear & concise description of what you're experiencing.
validations:
required: false
- type: textarea
attributes:
label: Expected Behavior
description: A clear & concise description of what you expected to happen.
validations:
required: false
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
validations:
required: false
- type: textarea
attributes:
label: Example flow
description: If you have a minimal example flow that demonstrates the issue, share it here.
value: |
```
paste your flow here
```
validations:
required: false
- type: textarea
attributes:
label: Environment
description: Please tell us about your environment. Include any relevant information on how you are running Node-RED.
value: |
- Node-RED version:
- Node.js version:
- npm version:
- Platform/OS:
- Browser:
validations:
required: false

View File

@ -1,14 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: ❓ Questions
url: https://discourse.nodered.org
about: Ask your question on the Node-RED forum
- name: ⭐️ Feature Request
url: https://discourse.nodered.org/c/development/feature-requests
about: Discuss your request with the community
- name: 🗂 Documentation
url: https://nodered.org/docs
about: Go straight to the documentation
- name: 💬 Slack
url: https://nodered.org/slack
about: Chat about the project on our slack team

View File

@ -30,5 +30,5 @@ the [forum](https://discourse.nodered.org) or
- [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md) - [ ] 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 forum/slack team. - [ ] For non-bugfix PRs, I have discussed this change on the forum/slack team.
- [ ] I have run `npm run test` to verify the unit tests pass - [ ] I have run `grunt` to verify the unit tests pass
- [ ] I have added suitable unit tests to cover the new/changed functionality - [ ] I have added suitable unit tests to cover the new/changed functionality

View File

@ -1,15 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "monthly"
groups:
github-actions:
patterns:
- "*"

View File

@ -1,38 +1,34 @@
name: Publish Release name: PublishDockerImage
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
on: on:
release: release:
types: [published] types: [published]
permissions:
contents: read
jobs: jobs:
generate: generate:
name: 'Update node-red-docker image' name: 'Update node-red-docker image'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out node-red repository - name: Check out node-red repository
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
path: 'node-red' path: 'node-red'
- name: Check out node-red-docker repository - name: Check out node-red-docker repository
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
repository: 'node-red/node-red-docker' repository: 'node-red/node-red-docker'
path: 'node-red-docker' path: 'node-red-docker'
- name: Check out node-red.github.io repository - name: Check out node-red.github.io repository
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
repository: 'node-red/node-red.github.io' repository: 'node-red/node-red.github.io'
path: 'node-red.github.io' path: 'node-red.github.io'
- uses: actions/setup-node@v4 - uses: actions/setup-node@v1
with: with:
node-version: '16' node-version: '12'
- run: node ./node-red/.github/scripts/update-node-red-docker.js - run: node ./node-red/.github/scripts/update-node-red-docker.js
- name: Create Docker Pull Request - name: Create Docker Pull Request
uses: peter-evans/create-pull-request@v6 uses: peter-evans/create-pull-request@v2
with: with:
token: ${{ secrets.NR_REPO_TOKEN }} token: ${{ secrets.NR_REPO_TOKEN }}
committer: GitHub <noreply@github.com> committer: GitHub <noreply@github.com>
@ -48,7 +44,7 @@ jobs:
This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary
- run: node ./node-red/.github/scripts/update-node-red-website.js - run: node ./node-red/.github/scripts/update-node-red-website.js
- name: Create Website Pull Request - name: Create Website Pull Request
uses: peter-evans/create-pull-request@v6 uses: peter-evans/create-pull-request@v2
with: with:
token: ${{ secrets.NR_REPO_TOKEN }} token: ${{ secrets.NR_REPO_TOKEN }}
committer: GitHub <noreply@github.com> committer: GitHub <noreply@github.com>

View File

@ -1,30 +0,0 @@
name: Run tests
on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]
permissions:
contents: read
jobs:
build:
permissions:
contents: read # for actions/checkout to fetch code
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
run: npm install
- name: Run tests
run: |
npm run test

6
.gitignore vendored
View File

@ -7,9 +7,7 @@
.sessions.json .sessions.json
.settings .settings
.tern-project .tern-project
.i18n-editor-metadata
*.backup *.backup
*.bak
*_cred* *_cred*
coverage coverage
credentials.json credentials.json
@ -25,7 +23,3 @@ packages/node_modules/@node-red/editor-client/public
docs docs
!packages/node_modules/**/docs !packages/node_modules/**/docs
.vscode .vscode
.nyc_output
sync.ffs_db
package-lock.json
.editorconfig

View File

@ -15,5 +15,5 @@
"shadow": true, // allow variable shadowing (re-use of names...) "shadow": true, // allow variable shadowing (re-use of names...)
"sub": true, // don't warn that foo['bar'] should be written as foo.bar "sub": true, // don't warn that foo['bar'] should be written as foo.bar
"proto": true, // allow setting of __proto__ in node < v0.12, "proto": true, // allow setting of __proto__ in node < v0.12,
"esversion": 11 // allow es11(ES2020) "esversion": 6 // allow es6
} }

4
.nodemonignore Normal file
View File

@ -0,0 +1,4 @@
/Gruntfile.js
/.git/*
*.backup
/public/*

15
.travis.yml Normal file
View File

@ -0,0 +1,15 @@
sudo: false
addons:
chrome: stable
language: node_js
matrix:
include:
- node_js: "14"
- node_js: "12"
- node_js: "10"
script:
- ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
- scripts/install-ui-test-dependencies.sh && grunt test-ui
before_script:
- npm install -g istanbul coveralls
- node_js: "8"

16
API.md
View File

@ -1,12 +1,8 @@
Node-RED consists of 6 node modules under the `@node-red` scope, which are pulled together Node-RED Modules
by the top-level `node-red` module. The typical scenario is where you are embedding Node-RED into your ---
own application, in which case you would use the `node-red` module rather than any of the
internal modules directly.
```javascript
let RED = require("node-red");
```
Node-RED provides a set of node modules that implement different parts of the
application.
Module | Description Module | Description
-------|------- -------|-------
@ -14,6 +10,6 @@ Module | Description
[@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API [@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API
[@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED [@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED
[@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules [@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules
[@node-red/registry](@node-red_registry.html) | the internal node registry @node-red/registry | the internal node registry
@node-red/nodes | the default set of core nodes. This module only contains the Node-RED nodes - it does not expose any APIs. @node-red/nodes | the default set of core nodes
@node-red/editor-client | the client-side resources of the Node-RED editor application @node-red/editor-client | the client-side resources of the Node-RED editor application

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
title: "Node-RED"
authors:
- family-names: "OpenJS Foundation"
- family-names: "Contributors"
url: "https://nodered.org"

View File

@ -16,9 +16,6 @@ behavior to the project's core team at team@nodered.org.
Please raise any bug reports on the relevant project's issue tracker. Be sure to Please raise any bug reports on the relevant project's issue tracker. Be sure to
search the list to see if your issue has already been raised. search the list to see if your issue has already been raised.
If your issue is more of a question on how to do something with Node-RED, please
consider using the [community forum](https://discourse.nodered.org/).
A good bug report is one that make it easy for us to understand what you were A good bug report is one that make it easy for us to understand what you were
trying to do and what went wrong. trying to do and what went wrong.
@ -38,25 +35,16 @@ For feature requests, please raise them on the [forum](https://discourse.nodered
## Pull-Requests ## Pull-Requests
If you want to raise a pull-request with a new feature, or a refactoring If you want to raise a pull-request with a new feature, or a refactoring
of existing code, please come and discuss it with us first. We prefer to of existing code, it may well get rejected if you haven't discussed it on
do it that way to make sure your time and effort is well spent on something the [forum](https://discourse.nodered.org) first.
that fits with our goals.
If you've got a bug-fix or similar for us, then you are most welcome to All contributors need to sign the JS Foundation's Contributor License Agreement.
get it raised - just make sure you link back to the issue it's fixing and It is an online process and quick to do. You can read the details of the agreement
try to include some tests! here: https://cla.js.foundation/node-red/node-red.
All contributors need to sign the OpenJS Foundation's Contributor License Agreement. If you raise a pull-request without having signed the CLA, you will be prompted
It is an online process and quick to do. If you raise a pull-request without to do so automatically.
having signed the CLA, you will be prompted to do so automatically.
### Code Branches
When raising a PR for a fix or a new feature, it is important to target the right branch.
- `master` - this is the main branch for the latest stable release of Node-RED. All bug fixes for that release should target this branch.
- `v1.x` - this is the maintenance branch for the 1.x stream. If a fix *only* applies to 1.x, then it should target this branch. If it applies to the current stable release as well, target `master` first. We will then decide if it needs to be back ported to the 1.x stream.
- `dev` - this is the branch for new feature development targeting the next milestone release.
### Coding standards ### Coding standards

View File

@ -16,20 +16,14 @@
var path = require("path"); var path = require("path");
var fs = require("fs-extra"); var fs = require("fs-extra");
var sass = require("sass"); var sass = require("node-sass");
module.exports = function(grunt) { module.exports = function(grunt) {
var nodemonArgs = ["-V"]; var nodemonArgs = ["-v"];
var flowFile = grunt.option('flowFile'); var flowFile = grunt.option('flowFile');
if (flowFile) { if (flowFile) {
nodemonArgs.push(flowFile); nodemonArgs.push(flowFile);
process.env.NODE_RED_ENABLE_PROJECTS=false;
}
var userDir = grunt.option('userDir');
if (userDir) {
nodemonArgs.push("-u");
nodemonArgs.push(userDir);
} }
var browserstack = grunt.option('browserstack'); var browserstack = grunt.option('browserstack');
@ -40,10 +34,8 @@ module.exports = function(grunt) {
if (nonHeadless) { if (nonHeadless) {
process.env.NODE_RED_NON_HEADLESS = true; process.env.NODE_RED_NON_HEADLESS = true;
} }
const pkg = grunt.file.readJSON('package.json');
process.env.NODE_RED_PACKAGE_VERSION = pkg.version;
grunt.initConfig({ grunt.initConfig({
pkg: pkg, pkg: grunt.file.readJSON('package.json'),
paths: { paths: {
dist: ".dist" dist: ".dist"
}, },
@ -55,8 +47,8 @@ module.exports = function(grunt) {
ui: 'bdd', ui: 'bdd',
reporter: 'spec' reporter: 'spec'
}, },
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] }, all: { src: ['test/**/*_spec.js'] },
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]}, core: { src: ["test/_spec.js","test/unit/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]} nodes: { src: ["test/nodes/**/*_spec.js"]}
}, },
webdriver: { webdriver: {
@ -64,19 +56,19 @@ module.exports = function(grunt) {
configFile: 'test/editor/wdio.conf.js' configFile: 'test/editor/wdio.conf.js'
} }
}, },
nyc: { mocha_istanbul: {
options: { options: {
cwd: '.', globals: ['expect'],
include: ['packages/node_modules/**'], timeout: 3000,
excludeNodeModules: false, ignoreLeaks: false,
exclude: ['packages/node_modules/@node-red/editor-client/**'], ui: 'bdd',
reporter: ['lcov', 'html','text-summary'], reportFormats: ['lcov','html'],
reportDir: 'coverage', print: 'both',
all: true istanbulOptions: ['--no-default-excludes', '-i','**/packages/node_modules/**']
}, },
all: { cmd: false, args: ['grunt', 'simplemocha:all'] }, all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
core: { options: { exclude:['packages/node_modules/@node-red/editor-client/**', 'packages/node_modules/@node-red/nodes/**']},cmd: false, args: ['grunt', 'simplemocha:core'] }, core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
nodes: { cmd: false, args: ['grunt', 'simplemocha:nodes'] } nodes: { src: ["test/nodes/**/*_spec.js"]}
}, },
jshint: { jshint: {
options: { options: {
@ -137,17 +129,13 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js", "packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
"packages/node_modules/@node-red/editor-client/src/js/red.js", "packages/node_modules/@node-red/editor-client/src/js/red.js",
"packages/node_modules/@node-red/editor-client/src/js/events.js", "packages/node_modules/@node-red/editor-client/src/js/events.js",
"packages/node_modules/@node-red/editor-client/src/js/hooks.js",
"packages/node_modules/@node-red/editor-client/src/js/i18n.js", "packages/node_modules/@node-red/editor-client/src/js/i18n.js",
"packages/node_modules/@node-red/editor-client/src/js/settings.js", "packages/node_modules/@node-red/editor-client/src/js/settings.js",
"packages/node_modules/@node-red/editor-client/src/js/user.js", "packages/node_modules/@node-red/editor-client/src/js/user.js",
"packages/node_modules/@node-red/editor-client/src/js/comms.js", "packages/node_modules/@node-red/editor-client/src/js/comms.js",
"packages/node_modules/@node-red/editor-client/src/js/runtime.js",
"packages/node_modules/@node-red/editor-client/src/js/multiplayer.js",
"packages/node_modules/@node-red/editor-client/src/js/text/bidi.js", "packages/node_modules/@node-red/editor-client/src/js/text/bidi.js",
"packages/node_modules/@node-red/editor-client/src/js/text/format.js", "packages/node_modules/@node-red/editor-client/src/js/text/format.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/state.js", "packages/node_modules/@node-red/editor-client/src/js/ui/state.js",
"packages/node_modules/@node-red/editor-client/src/js/plugins.js",
"packages/node_modules/@node-red/editor-client/src/js/nodes.js", "packages/node_modules/@node-red/editor-client/src/js/nodes.js",
"packages/node_modules/@node-red/editor-client/src/js/font-awesome.js", "packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
"packages/node_modules/@node-red/editor-client/src/js/history.js", "packages/node_modules/@node-red/editor-client/src/js/history.js",
@ -164,17 +152,14 @@ 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/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/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/toggleButton.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.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/actions.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js", "packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js", "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js", "packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js", "packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js", "packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js", "packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js", "packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js", "packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js", "packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
@ -186,16 +171,13 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js", "packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js", "packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editor.js", "packages/node_modules/@node-red/editor-client/src/js/ui/editor.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js", "packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js", "packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tray.js", "packages/node_modules/@node-red/editor-client/src/js/ui/tray.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js", "packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js", "packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js", "packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js", "packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js", "packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js", "packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js", "packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
@ -205,16 +187,13 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js", "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js", "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js", "packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js", "packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js"
"packages/node_modules/@node-red/editor-client/src/js/ui/tour/*.js"
], ],
nonull: true,
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js" dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
}, },
vendor: { vendor: {
files: [ files: {
{ "packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
src: [
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.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.min.js",
@ -222,39 +201,22 @@ module.exports = function(grunt) {
"node_modules/marked/marked.min.js", "node_modules/marked/marked.min.js",
"node_modules/dompurify/dist/purify.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/d3/d3.v3.min.js",
"node_modules/i18next/i18next.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js",
"node_modules/i18next-http-backend/i18nextHttpBackend.min.js",
"node_modules/jquery-i18next/jquery-i18next.min.js",
"node_modules/jsonata/jsonata-es5.min.js", "node_modules/jsonata/jsonata-es5.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js", "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js", "packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js" "packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js",
], ],
nonull: true, // "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
dest: "packages/node_modules/@node-red/editor-client/public/vendor/vendor.js"
},
// {
// src: [
// // TODO: resolve relative resource paths in // // TODO: resolve relative resource paths in
// // bootstrap/FA/jquery // // bootstrap/FA/jquery
// ], // ],
// dest: "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css" "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
// },
{
src: [
"node_modules/jsonata/jsonata-es5.min.js", "node_modules/jsonata/jsonata-es5.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js" "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
],
nonull: true,
dest: "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js",
},
{
src: "node_modules/mermaid/dist/mermaid.min.js",
nonull: true,
dest: "packages/node_modules/@node-red/editor-client/public/vendor/mermaid/mermaid.min.js",
},
] ]
} }
}
}, },
uglify: { uglify: {
build: { build: {
@ -312,9 +274,7 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/public/index.html", "packages/node_modules/@node-red/editor-client/public/index.html",
"packages/node_modules/@node-red/editor-client/public/favicon.ico", "packages/node_modules/@node-red/editor-client/public/favicon.ico",
"packages/node_modules/@node-red/editor-client/public/icons", "packages/node_modules/@node-red/editor-client/public/icons",
"packages/node_modules/@node-red/editor-client/public/vendor", "packages/node_modules/@node-red/editor-client/public/vendor"
"packages/node_modules/@node-red/editor-client/public/types/node",
"packages/node_modules/@node-red/editor-client/public/types/node-red",
] ]
}, },
release: { release: {
@ -350,12 +310,6 @@ module.exports = function(grunt) {
], ],
tasks: ['jsonlint:keymaps','copy:build'] tasks: ['jsonlint:keymaps','copy:build']
}, },
tours: {
files: [
'packages/node_modules/@node-red/editor-client/src/tours/**/*.js'
],
tasks: ['copy:build']
},
misc: { misc: {
files: [ files: [
'CHANGELOG.md' 'CHANGELOG.md'
@ -410,24 +364,11 @@ module.exports = function(grunt) {
src: [ src: [
'ace/**', 'ace/**',
'jquery/css/base/**', 'jquery/css/base/**',
'font-awesome/**', 'font-awesome/**'
'monaco/dist/**',
'monaco/types/extraLibs.js',
'monaco/style.css',
'monaco/monaco-bootstrap.js'
], ],
expand: true, expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/' dest: 'packages/node_modules/@node-red/editor-client/public/vendor/'
}, },
{
cwd: 'packages/node_modules/@node-red/editor-client/src',
src: [
'types/node/**/*.ts',
'types/node-red/*.ts',
],
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/'
},
{ {
cwd: 'packages/node_modules/@node-red/editor-client/src/icons', cwd: 'packages/node_modules/@node-red/editor-client/src/icons',
src: '**', src: '**',
@ -453,12 +394,6 @@ module.exports = function(grunt) {
src: '**', src: '**',
expand: true, expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/' dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/tours',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/red/tours/'
} }
] ]
} }
@ -517,16 +452,13 @@ module.exports = function(grunt) {
'packages/node_modules/@node-red/runtime/lib/index.js', 'packages/node_modules/@node-red/runtime/lib/index.js',
'packages/node_modules/@node-red/runtime/lib/api/*.js', 'packages/node_modules/@node-red/runtime/lib/api/*.js',
'packages/node_modules/@node-red/runtime/lib/events.js', 'packages/node_modules/@node-red/runtime/lib/events.js',
'packages/node_modules/@node-red/runtime/lib/hooks.js',
'packages/node_modules/@node-red/util/**/*.js', 'packages/node_modules/@node-red/util/**/*.js',
'packages/node_modules/@node-red/editor-api/lib/index.js', 'packages/node_modules/@node-red/editor-api/lib/index.js',
'packages/node_modules/@node-red/editor-api/lib/auth/index.js', 'packages/node_modules/@node-red/editor-api/lib/auth/index.js'
'packages/node_modules/@node-red/registry/lib/index.js'
], ],
options: { options: {
destination: 'docs', destination: 'docs',
configure: './jsdoc.json', configure: './jsdoc.json'
fred: "hi there"
} }
}, },
_editor: { _editor: {
@ -570,10 +502,12 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-concurrent'); grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-sass'); grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-nodemon');
grunt.loadNpmTasks('grunt-contrib-compress'); grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-chmod'); grunt.loadNpmTasks('grunt-chmod');
grunt.loadNpmTasks('grunt-jsonlint'); grunt.loadNpmTasks('grunt-jsonlint');
grunt.loadNpmTasks('grunt-mocha-istanbul');
if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) { if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.loadNpmTasks('grunt-webdriver'); grunt.loadNpmTasks('grunt-webdriver');
} }
@ -581,31 +515,11 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-jsdoc-to-markdown'); grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
grunt.loadNpmTasks('grunt-npm-command'); grunt.loadNpmTasks('grunt-npm-command');
grunt.loadNpmTasks('grunt-mkdir'); grunt.loadNpmTasks('grunt-mkdir');
grunt.loadNpmTasks('grunt-simple-nyc');
grunt.registerMultiTask('nodemon', 'Runs a nodemon monitor of your node.js server.', function () {
const nodemon = require('nodemon');
this.async();
const options = this.options();
options.script = this.data.script;
let callback;
if (options.callback) {
callback = options.callback;
delete options.callback;
} else {
callback = function(nodemonApp) {
nodemonApp.on('log', function (event) {
console.log(event.colour);
});
};
}
callback(nodemon(options));
});
grunt.registerMultiTask('attachCopyright', function() { grunt.registerMultiTask('attachCopyright', function() {
var files = this.data.src; var files = this.data.src;
var copyright = "/**\n"+ var copyright = "/**\n"+
" * Copyright OpenJS Foundation and other contributors, https://openjsf.org/\n"+ " * Copyright JS Foundation and other contributors, http://js.foundation\n"+
" *\n"+ " *\n"+
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+ " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+
" * you may not use this file except in compliance with the License.\n"+ " * you may not use this file except in compliance with the License.\n"+
@ -682,16 +596,11 @@ module.exports = function(grunt) {
grunt.registerTask('default', grunt.registerTask('default',
'Builds editor content then runs code style checks and unit tests on all components', 'Builds editor content then runs code style checks and unit tests on all components',
['build','verifyPackageDependencies','jshint:editor','nyc:all']); ['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']);
grunt.registerTask('no-coverage',
'Builds editor content then runs code style checks and unit tests on all components without code coverage',
['build','verifyPackageDependencies','jshint:editor','simplemocha:all']);
grunt.registerTask('test-core', grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code', 'Runs code style check and unit tests on core runtime code',
['build','nyc:core']); ['build','mocha_istanbul:core']);
grunt.registerTask('test-editor', grunt.registerTask('test-editor',
'Runs code style check on editor code', 'Runs code style check on editor code',
@ -709,7 +618,7 @@ module.exports = function(grunt) {
grunt.registerTask('test-nodes', grunt.registerTask('test-nodes',
'Runs unit tests on core nodes', 'Runs unit tests on core nodes',
['build','nyc:nodes']); ['build','mocha_istanbul:nodes']);
grunt.registerTask('build', grunt.registerTask('build',
'Builds editor content', 'Builds editor content',
@ -734,7 +643,7 @@ module.exports = function(grunt) {
grunt.registerTask('coverage', grunt.registerTask('coverage',
'Run Istanbul code test coverage task', 'Run Istanbul code test coverage task',
['build','nyc:all']); ['build','mocha_istanbul:all']);
grunt.registerTask('docs', grunt.registerTask('docs',
'Generates API documentation', 'Generates API documentation',

View File

@ -1,4 +1,4 @@
Copyright OpenJS Foundation and other contributors, https://openjsf.org/ Copyright JS Foundation and other contributors, http://js.foundation
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004

View File

@ -1,16 +1,17 @@
# Node-RED # Node-RED
https://nodered.org http://nodered.org
[![Build Status](https://github.com/node-red/node-red/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/node-red/node-red/actions?query=branch%3Amaster) [![Build Status](https://travis-ci.org/node-red/node-red.svg?branch=master)](https://travis-ci.org/node-red/node-red)
[![Coverage Status](https://coveralls.io/repos/node-red/node-red/badge.svg?branch=master)](https://coveralls.io/r/node-red/node-red?branch=master)
Low-code programming for event-driven applications. Low-code programming for event-driven applications.
![Node-RED: Low-code programming for event-driven applications](https://nodered.org/images/node-red-screenshot.png) ![Node-RED: Low-code programming for event-driven applications](http://nodered.org/images/node-red-screenshot.png)
## Quick Start ## Quick Start
Check out https://nodered.org/docs/getting-started/ for full instructions on getting Check out http://nodered.org/docs/getting-started/ for full instructions on getting
started. started.
1. `sudo npm install -g --unsafe-perm node-red` 1. `sudo npm install -g --unsafe-perm node-red`
@ -19,7 +20,7 @@ started.
## Getting Help ## Getting Help
More documentation can be found [here](https://nodered.org/docs). More documentation can be found [here](http://nodered.org/docs).
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack). For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
@ -55,15 +56,15 @@ This project adheres to the [Contributor Covenant 1.4](http://contributor-covena
## Authors ## Authors
Node-RED is a project of the [OpenJS Foundation](http://openjsf.org). Node-RED is a project of the [OpenJS Foundation](https://openjsf.org).
It is maintained by: It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
* Nick O'Leary [@knolleary](http://twitter.com/knolleary) * Nick O'Leary [@knolleary](http://twitter.com/knolleary)
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay) * Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
* And many others...
## Copyright and license ## Copyright and license
Copyright OpenJS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE). Copyright JS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE).

View File

@ -1,5 +1,13 @@
# Security Policy # Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 1.0.0 | :white_check_mark: |
| 0.20.x | :white_check_mark: |
## Reporting a Vulnerability ## Reporting a Vulnerability
Please report any potential security issues to `team@nodered.org`. This will notify the core project team who will respond accordingly. Please report any potential security issues to `team@nodered.org`. This will notify the core project team who will respond accordingly.

View File

@ -1,16 +0,0 @@
{
"ignoreRoot": [
".git",
".nyc_output",
".sass-cache",
"bower-components",
"coverage"
],
"ignore": [
"/Gruntfile.js",
"/.git/*",
"*.backup",
"/public/*"
]
}

View File

@ -1,8 +1,8 @@
{ {
"name": "node-red", "name": "node-red",
"version": "4.0.9", "version": "1.1.3",
"description": "Low-code programming for event-driven applications", "description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org", "homepage": "http://nodered.org",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",
@ -26,103 +26,96 @@
} }
], ],
"dependencies": { "dependencies": {
"acorn": "8.12.1", "ajv": "6.12.3",
"acorn-walk": "8.3.4",
"ajv": "8.17.1",
"async-mutex": "0.5.0",
"basic-auth": "2.0.1", "basic-auth": "2.0.1",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "1.20.3", "body-parser": "1.19.0",
"cheerio": "1.0.0-rc.10", "cheerio": "0.22.0",
"clone": "2.1.2", "clone": "2.1.2",
"content-type": "1.0.5", "content-type": "1.0.4",
"cookie": "0.7.2", "cookie": "0.4.1",
"cookie-parser": "1.4.7", "cookie-parser": "1.4.5",
"cors": "2.8.5", "cors": "2.8.5",
"cronosjs": "1.7.1", "cron": "1.7.2",
"denque": "2.1.0", "denque": "1.4.1",
"express": "4.21.2", "express": "4.17.1",
"express-session": "1.18.1", "express-session": "1.17.1",
"form-data": "4.0.0", "fs-extra": "8.1.0",
"fs-extra": "11.2.0", "fs.notify": "0.0.4",
"got": "12.6.1",
"hash-sum": "2.0.0", "hash-sum": "2.0.0",
"hpagent": "1.2.0", "https-proxy-agent": "5.0.0",
"https-proxy-agent": "5.0.1", "i18next": "15.1.2",
"i18next": "21.10.0", "iconv-lite": "0.6.2",
"iconv-lite": "0.6.3",
"is-utf8": "0.2.1", "is-utf8": "0.2.1",
"js-yaml": "4.1.0", "js-yaml": "3.14.0",
"json-stringify-safe": "5.0.1", "json-stringify-safe": "5.0.1",
"jsonata": "2.0.5", "jsonata": "1.8.3",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0", "media-typer": "1.1.0",
"memorystore": "1.6.7", "memorystore": "1.6.2",
"mime": "3.0.0", "mime": "2.4.6",
"moment": "2.30.1", "moment-timezone": "^0.5.31",
"moment-timezone": "0.5.46", "mqtt": "2.18.8",
"mqtt": "5.7.0", "multer": "1.4.2",
"multer": "1.4.5-lts.1", "mustache": "4.0.1",
"mustache": "4.2.0", "node-red-admin": "^0.2.6",
"node-red-admin": "^4.0.1", "node-red-node-rbe": "^0.2.9",
"node-watch": "0.7.4", "node-red-node-sentiment": "^0.1.6",
"nopt": "5.0.0", "node-red-node-tail": "^0.1.0",
"oauth2orize": "1.12.0", "nopt": "4.0.3",
"oauth2orize": "1.11.0",
"on-headers": "1.0.2", "on-headers": "1.0.2",
"passport": "0.7.0", "passport": "0.4.1",
"passport-http-bearer": "1.0.1", "passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"raw-body": "3.0.0", "raw-body": "2.4.1",
"rfdc": "^1.3.1", "request": "2.88.0",
"semver": "7.6.3", "semver": "6.3.0",
"tar": "7.4.3", "uglify-js": "3.10.0",
"tough-cookie": "^5.0.0", "when": "3.7.8",
"uglify-js": "3.17.4", "ws": "6.2.1",
"uuid": "9.0.1", "xml2js": "0.4.23"
"ws": "7.5.10",
"xml2js": "0.6.2"
}, },
"optionalDependencies": { "optionalDependencies": {
"@node-rs/bcrypt": "1.10.4" "bcrypt": "3.0.8"
}, },
"devDependencies": { "devDependencies": {
"dompurify": "2.5.7", "marked": "0.8.2",
"grunt": "1.6.1", "dompurify": "2.0.12",
"grunt": "~1.0.4",
"grunt-chmod": "~1.1.1", "grunt-chmod": "~1.1.1",
"grunt-cli": "~1.5.0", "grunt-cli": "~1.3.2",
"grunt-concurrent": "3.0.0", "grunt-concurrent": "~2.3.1",
"grunt-contrib-clean": "2.0.1", "grunt-contrib-clean": "~2.0.0",
"grunt-contrib-compress": "2.0.0", "grunt-contrib-compress": "~1.5.0",
"grunt-contrib-concat": "2.1.0", "grunt-contrib-concat": "~1.0.1",
"grunt-contrib-copy": "1.0.0", "grunt-contrib-copy": "~1.0.0",
"grunt-contrib-jshint": "3.2.0", "grunt-contrib-jshint": "~2.1.0",
"grunt-contrib-uglify": "5.2.2", "grunt-contrib-uglify": "~4.0.1",
"grunt-contrib-watch": "1.1.0", "grunt-contrib-watch": "~1.1.0",
"grunt-jsdoc": "2.4.1", "grunt-jsdoc": "^2.2.1",
"grunt-jsdoc-to-markdown": "6.0.0", "grunt-jsdoc-to-markdown": "^4.0.0",
"grunt-jsonlint": "3.0.0", "grunt-jsonlint": "~2.0.0",
"grunt-mkdir": "~1.1.0", "grunt-mkdir": "~1.0.0",
"grunt-mocha-istanbul": "5.0.2",
"grunt-nodemon": "~0.4.2",
"grunt-npm-command": "~0.1.2", "grunt-npm-command": "~0.1.2",
"grunt-sass": "~3.1.0", "grunt-sass": "~3.1.0",
"grunt-simple-mocha": "~0.4.1", "grunt-simple-mocha": "~0.4.1",
"grunt-simple-nyc": "^3.0.1", "http-proxy": "1.18.1",
"i18next-http-backend": "1.4.1", "istanbul": "0.4.5",
"jquery-i18next": "1.2.1",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template", "jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "4.3.0",
"mermaid": "11.3.0",
"minami": "1.2.3", "minami": "1.2.3",
"mocha": "9.2.2", "mocha": "^5.2.0",
"node-red-node-test-helper": "^0.3.3", "mosca": "^2.8.3",
"nodemon": "3.1.7", "node-red-node-test-helper": "^0.2.5",
"proxy": "^1.0.2", "node-sass": "^4.14.1",
"sass": "1.62.1", "should": "^8.4.0",
"should": "13.2.3", "sinon": "1.17.7",
"sinon": "11.1.2",
"stoppable": "^1.1.0", "stoppable": "^1.1.0",
"supertest": "6.3.3" "supertest": "3.4.2"
}, },
"engines": { "engines": {
"node": ">=18.5" "node": ">=8"
} }
} }

View File

@ -1,4 +1,4 @@
Copyright OpenJS Foundation and other contributors, https://openjsf.org/ Copyright JS Foundation and other contributors, http://js.foundation
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004

View File

@ -33,9 +33,6 @@ module.exports = {
store: req.query['store'], store: req.query['store'],
req: apiUtils.getRequestLogObject(req) req: apiUtils.getRequestLogObject(req)
} }
if (req.query['keysOnly'] !== undefined) {
opts.keysOnly = true
}
runtimeAPI.context.getValue(opts).then(function(result) { runtimeAPI.context.getValue(opts).then(function(result) {
res.json(result); res.json(result);
}).catch(function(err) { }).catch(function(err) {

View File

@ -1,23 +0,0 @@
let runtimeAPI;
let settings;
const apiUtil = require("../util");
module.exports = {
init: function(_settings, _runtimeAPI) {
settings = _settings;
runtimeAPI = _runtimeAPI;
},
getReport: function(req, res) {
const diagnosticsOpts = settings.diagnostics || {};
const opts = {
user: req.user,
scope: diagnosticsOpts.level || "basic"
}
if(diagnosticsOpts.enabled === false || diagnosticsOpts.enabled === "false") {
apiUtil.rejectHandler(req, res, {message: "diagnostics are disabled", status: 403, code: "diagnostics.disabled" })
} else {
runtimeAPI.diagnostics.get(opts)
.then(function(result) { res.json(result); })
.catch(err => apiUtil.rejectHandler(req, res, err))
}
}
}

View File

@ -68,28 +68,5 @@ module.exports = {
}).catch(function(err) { }).catch(function(err) {
apiUtils.rejectHandler(req,res,err); apiUtils.rejectHandler(req,res,err);
}) })
},
getState: function(req,res) {
const opts = {
user: req.user,
req: apiUtils.getRequestLogObject(req)
}
runtimeAPI.flows.getState(opts).then(function(result) {
res.json(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
},
postState: function(req,res) {
const opts = {
user: req.user,
state: req.body.state || "",
req: apiUtils.getRequestLogObject(req)
}
runtimeAPI.flows.setState(opts).then(function(result) {
res.json(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
} }
} }

View File

@ -14,14 +14,14 @@
* limitations under the License. * limitations under the License.
**/ **/
var express = require("express");
var nodes = require("./nodes"); var nodes = require("./nodes");
var flows = require("./flows"); var flows = require("./flows");
var flow = require("./flow"); var flow = require("./flow");
var context = require("./context"); var context = require("./context");
var auth = require("../auth"); var auth = require("../auth");
var info = require("./settings"); var info = require("./settings");
var plugins = require("./plugins");
var diagnostics = require("./diagnostics");
var apiUtil = require("../util"); var apiUtil = require("../util");
@ -32,23 +32,15 @@ module.exports = {
nodes.init(runtimeAPI); nodes.init(runtimeAPI);
context.init(runtimeAPI); context.init(runtimeAPI);
info.init(settings,runtimeAPI); info.init(settings,runtimeAPI);
plugins.init(runtimeAPI);
diagnostics.init(settings, runtimeAPI);
const needsPermission = auth.needsPermission; var needsPermission = auth.needsPermission;
const adminApp = apiUtil.createExpressApp(settings) var adminApp = express();
// Flows // Flows
adminApp.get("/flows",needsPermission("flows.read"),flows.get,apiUtil.errorHandler); adminApp.get("/flows",needsPermission("flows.read"),flows.get,apiUtil.errorHandler);
adminApp.post("/flows",needsPermission("flows.write"),flows.post,apiUtil.errorHandler); adminApp.post("/flows",needsPermission("flows.write"),flows.post,apiUtil.errorHandler);
// Flows/state
adminApp.get("/flows/state", needsPermission("flows.read"), flows.getState, apiUtil.errorHandler);
if (settings.runtimeState && settings.runtimeState.enabled === true) {
adminApp.post("/flows/state", needsPermission("flows.write"), flows.postState, apiUtil.errorHandler);
}
// Flow // Flow
adminApp.get("/flow/:id",needsPermission("flows.read"),flow.get,apiUtil.errorHandler); adminApp.get("/flow/:id",needsPermission("flows.read"),flow.get,apiUtil.errorHandler);
adminApp.post("/flow",needsPermission("flows.write"),flow.post,apiUtil.errorHandler); adminApp.post("/flow",needsPermission("flows.write"),flow.post,apiUtil.errorHandler);
@ -57,16 +49,7 @@ module.exports = {
// Nodes // Nodes
adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler); adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler);
if (!settings.externalModules || !settings.externalModules.palette || settings.externalModules.palette.allowInstall !== false) {
if (!settings.externalModules || !settings.externalModules.palette || settings.externalModules.palette.allowUpload !== false) {
const multer = require('multer');
const upload = multer({ storage: multer.memoryStorage() });
adminApp.post("/nodes",needsPermission("nodes.write"),upload.single("tarball"),nodes.post,apiUtil.errorHandler);
} else {
adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler); adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler);
}
}
adminApp.get(/^\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler); adminApp.get(/^\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler);
adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler); adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler);
adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler); adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler);
@ -88,13 +71,6 @@ module.exports = {
adminApp.get("/settings",needsPermission("settings.read"),info.runtimeSettings,apiUtil.errorHandler); adminApp.get("/settings",needsPermission("settings.read"),info.runtimeSettings,apiUtil.errorHandler);
// Plugins
adminApp.get("/plugins", needsPermission("plugins.read"), plugins.getAll, apiUtil.errorHandler);
adminApp.get("/plugins/messages", needsPermission("plugins.read"), plugins.getCatalogs, apiUtil.errorHandler);
adminApp.get(/^\/plugins\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("plugins.read"),plugins.getConfig,apiUtil.errorHandler);
adminApp.get("/diagnostics", needsPermission("diagnostics.read"), diagnostics.getReport, apiUtil.errorHandler);
return adminApp; return adminApp;
} }
} }

View File

@ -33,9 +33,6 @@ module.exports = {
}) })
} else { } else {
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages()); opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
opts.lang = "en-US";
}
runtimeAPI.nodes.getNodeConfigs(opts).then(function(configs) { runtimeAPI.nodes.getNodeConfigs(opts).then(function(configs) {
res.send(configs); res.send(configs);
}) })
@ -48,22 +45,11 @@ module.exports = {
module: req.body.module, module: req.body.module,
version: req.body.version, version: req.body.version,
url: req.body.url, url: req.body.url,
tarball: undefined,
req: apiUtils.getRequestLogObject(req) req: apiUtils.getRequestLogObject(req)
} }
if (!runtimeAPI.settings.editorTheme || !runtimeAPI.settings.editorTheme.palette || runtimeAPI.settings.editorTheme.palette.upload !== false) {
if (req.file) {
opts.tarball = {
name: req.file.originalname,
size: req.file.size,
buffer: req.file.buffer
}
}
}
runtimeAPI.nodes.addModule(opts).then(function(info) { runtimeAPI.nodes.addModule(opts).then(function(info) {
res.json(info); res.json(info);
}).catch(function(err) { }).catch(function(err) {
console.log(err.stack);
apiUtils.rejectHandler(req,res,err); apiUtils.rejectHandler(req,res,err);
}) })
}, },
@ -95,9 +81,6 @@ module.exports = {
}) })
} else { } else {
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages()); opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
opts.lang = "en-US";
}
runtimeAPI.nodes.getNodeConfig(opts).then(function(result) { runtimeAPI.nodes.getNodeConfig(opts).then(function(result) {
return res.send(result); return res.send(result);
}).catch(function(err) { }).catch(function(err) {
@ -167,9 +150,6 @@ module.exports = {
lang: req.query.lng, lang: req.query.lng,
req: apiUtils.getRequestLogObject(req) req: apiUtils.getRequestLogObject(req)
} }
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
opts.lang = "en-US";
}
runtimeAPI.nodes.getModuleCatalog(opts).then(function(result) { runtimeAPI.nodes.getModuleCatalog(opts).then(function(result) {
res.json(result); res.json(result);
}).catch(function(err) { }).catch(function(err) {
@ -184,9 +164,6 @@ module.exports = {
lang: req.query.lng, lang: req.query.lng,
req: apiUtils.getRequestLogObject(req) req: apiUtils.getRequestLogObject(req)
} }
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
opts.lang = "en-US";
}
runtimeAPI.nodes.getModuleCatalogs(opts).then(function(result) { runtimeAPI.nodes.getModuleCatalogs(opts).then(function(result) {
res.json(result); res.json(result);
}).catch(function(err) { }).catch(function(err) {

View File

@ -1,70 +0,0 @@
var apiUtils = require("../util");
var runtimeAPI;
module.exports = {
init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI;
},
getAll: function(req,res) {
var opts = {
user: req.user,
req: apiUtils.getRequestLogObject(req)
}
if (req.get("accept") == "application/json") {
runtimeAPI.plugins.getPluginList(opts).then(function(list) {
res.json(list);
})
} else {
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
opts.lang = "en-US";
}
runtimeAPI.plugins.getPluginConfigs(opts).then(function(configs) {
res.send(configs);
})
}
},
getCatalogs: function(req,res) {
var opts = {
user: req.user,
lang: req.query.lng,
req: apiUtils.getRequestLogObject(req)
}
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
opts.lang = "en-US";
}
runtimeAPI.plugins.getPluginCatalogs(opts).then(function(result) {
res.json(result);
}).catch(function(err) {
console.log(err.stack);
apiUtils.rejectHandler(req,res,err);
})
},
getConfig: function(req, res) {
let opts = {
user: req.user,
module: req.params[0],
req: apiUtils.getRequestLogObject(req)
}
if (req.get("accept") === "application/json") {
runtimeAPI.nodes.getNodeInfo(opts.module).then(function(result) {
res.send(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
} else {
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
opts.lang = "en-US";
}
runtimeAPI.plugins.getPluginConfig(opts).then(function(result) {
return res.send(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
}
}
};

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
var apiUtils = require("../util");
var runtimeAPI; var runtimeAPI;
var settings; var settings;
var theme = require("../editor/theme"); var theme = require("../editor/theme");

View File

@ -90,7 +90,7 @@ function getToken(req,res,next) {
return server.token()(req,res,next); return server.token()(req,res,next);
} }
async function login(req,res) { function login(req,res) {
var response = {}; var response = {};
if (settings.adminAuth) { if (settings.adminAuth) {
var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module); var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module);
@ -106,15 +106,9 @@ async function login(req,res) {
urlPrefix += "/"; urlPrefix += "/";
} }
response = { response = {
"type":"strategy" "type":"strategy",
"prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]
} }
if (mergedAdminAuth.strategy.autoLogin) {
response.autoLogin = true
response.loginRedirect = urlPrefix + "auth/strategy"
}
response.prompts = [
{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}
]
if (mergedAdminAuth.strategy.icon) { if (mergedAdminAuth.strategy.icon) {
response.prompts[0].icon = mergedAdminAuth.strategy.icon; response.prompts[0].icon = mergedAdminAuth.strategy.icon;
} }
@ -122,17 +116,8 @@ async function login(req,res) {
response.prompts[0].image = theme.serveFile('/login/',mergedAdminAuth.strategy.image); response.prompts[0].image = theme.serveFile('/login/',mergedAdminAuth.strategy.image);
} }
} }
let themeContext = await theme.context(); if (theme.context().login && theme.context().login.image) {
if (themeContext.login && themeContext.login.image) { response.image = theme.context().login.image;
response.image = themeContext.login.image;
}
if (themeContext.login?.message) {
response.loginMessage = themeContext.login?.message
}
if (themeContext.login?.button) {
response.prompts = [
{ type: "button", ...themeContext.login.button }
]
} }
} }
res.json(response); res.json(response);
@ -155,7 +140,7 @@ function completeVerify(profile,done) {
Users.authenticate(profile).then(function(user) { Users.authenticate(profile).then(function(user) {
if (user) { if (user) {
Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) { Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) {
log.audit({event: "auth.login",user,username:user.username,scope:user.permissions}); log.audit({event: "auth.login",username:user.username,scope:user.permissions});
user.tokens = tokens; user.tokens = tokens;
done(null,user); done(null,user);
}); });
@ -168,11 +153,11 @@ function completeVerify(profile,done) {
function genericStrategy(adminApp,strategy) { function genericStrategy(adminApp,strategy) {
const crypto = require("crypto") var crypto = require("crypto")
const session = require('express-session') var session = require('express-session')
const MemoryStore = require('memorystore')(session) var MemoryStore = require('memorystore')(session)
const sessionOptions = { adminApp.use(session({
// As the session is only used across the life-span of an auth // As the session is only used across the life-span of an auth
// hand-shake, we can use a instance specific random string // hand-shake, we can use a instance specific random string
secret: crypto.randomBytes(20).toString('hex'), secret: crypto.randomBytes(20).toString('hex'),
@ -181,27 +166,15 @@ function genericStrategy(adminApp,strategy) {
store: new MemoryStore({ store: new MemoryStore({
checkPeriod: 86400000 // prune expired entries every 24h checkPeriod: 86400000 // prune expired entries every 24h
}) })
} }));
if (settings.httpAdminCookieOptions) {
sessionOptions.cookie = {
path: '/',
httpOnly: true,
secure: false,
maxAge: null,
...settings.httpAdminCookieOptions
}
if (sessionOptions.cookie.name){
sessionOptions.name = sessionOptions.cookie.name
delete sessionOptions.cookie.name
}
}
adminApp.use(session(sessionOptions));
//TODO: all passport references ought to be in ./auth //TODO: all passport references ought to be in ./auth
adminApp.use(passport.initialize()); adminApp.use(passport.initialize());
adminApp.use(passport.session()); adminApp.use(passport.session());
var options = strategy.options; var options = strategy.options;
var verify = function() {
passport.use(new strategy.strategy(options,
function() {
var originalDone = arguments[arguments.length-1]; var originalDone = arguments[arguments.length-1];
if (options.verify) { if (options.verify) {
var args = Array.from(arguments); var args = Array.from(arguments);
@ -212,28 +185,18 @@ function genericStrategy(adminApp,strategy) {
return completeVerify(profile,originalDone); return completeVerify(profile,originalDone);
} }
}; };
options.verify.apply(null,args);
options.verify.apply(this,args);
} else { } else {
var profile = arguments[arguments.length - 2]; var profile = arguments[arguments.length - 2];
return completeVerify(profile,originalDone); return completeVerify(profile,originalDone);
} }
};
// Give our callback the same arity as the original one from options
if (options.verify) {
Object.defineProperty(verify, "length", { value: options.verify.length })
}
passport.use(new strategy.strategy(options, verify)); }
));
adminApp.get('/auth/strategy', adminApp.get('/auth/strategy',
passport.authenticate(strategy.name, { passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
session:false, completeGenerateStrategyAuth
failWithError: true,
failureMessage: true
}),
completeGenericStrategyAuth,
handleStrategyError
); );
var callbackMethodFunc = adminApp.get; var callbackMethodFunc = adminApp.get;
@ -241,31 +204,17 @@ function genericStrategy(adminApp,strategy) {
callbackMethodFunc = adminApp.post; callbackMethodFunc = adminApp.post;
} }
callbackMethodFunc.call(adminApp,'/auth/strategy/callback', callbackMethodFunc.call(adminApp,'/auth/strategy/callback',
passport.authenticate(strategy.name, { passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
session:false, completeGenerateStrategyAuth
failureMessage: true,
failWithError: true
}),
completeGenericStrategyAuth,
handleStrategyError
); );
} }
function completeGenericStrategyAuth(req,res) { function completeGenerateStrategyAuth(req,res) {
var tokens = req.user.tokens; var tokens = req.user.tokens;
delete req.user.tokens; delete req.user.tokens;
// Successful authentication, redirect home. // Successful authentication, redirect home.
res.redirect(settings.httpAdminRoot + '?access_token='+tokens.accessToken); res.redirect(settings.httpAdminRoot + '?access_token='+tokens.accessToken);
} }
function handleStrategyError(err, req, res, next) {
if (res.headersSent) {
return next(err)
}
// Remove the header that passport auto-adds as we don't need it
res.removeHeader('WWW-Authenticate')
log.audit({event: "auth.login.fail.oauth",error:err.toString()});
res.redirect(settings.httpAdminRoot + '?session_message='+err.toString());
}
module.exports = { module.exports = {
init: init, init: init,

View File

@ -25,7 +25,7 @@ function hasPermission(userScope,permission) {
} }
var i; var i;
if (Array.isArray(permission)) { if (util.isArray(permission)) {
// Multiple permissions requested - check each one // Multiple permissions requested - check each one
for (i=0;i<permission.length;i++) { for (i=0;i<permission.length;i++) {
if (!hasPermission(userScope,permission[i])) { if (!hasPermission(userScope,permission[i])) {
@ -36,7 +36,7 @@ function hasPermission(userScope,permission) {
return true; return true;
} }
if (Array.isArray(userScope)) { if (util.isArray(userScope)) {
if (userScope.length === 0) { if (userScope.length === 0) {
return false; return false;
} }

View File

@ -18,6 +18,7 @@ var BearerStrategy = require('passport-http-bearer').Strategy;
var ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy; var ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy;
var passport = require("passport"); var passport = require("passport");
var crypto = require("crypto");
var util = require("util"); var util = require("util");
var Tokens = require("./tokens"); var Tokens = require("./tokens");
@ -91,16 +92,10 @@ var passwordTokenExchange = function(client, username, password, scope, done) {
loginAttempts = loginAttempts.filter(function(logEntry) { loginAttempts = loginAttempts.filter(function(logEntry) {
return logEntry.user !== username; return logEntry.user !== username;
}); });
// Check if the user contains a user defined token and use it
// instead of generating a new token
if(user.token){
done(null,user.token,null,null);
} else {
Tokens.create(username,client.id,scope).then(function(tokens) { Tokens.create(username,client.id,scope).then(function(tokens) {
log.audit({event: "auth.login",user,username:username,client:client.id,scope:scope}); log.audit({event: "auth.login",username:username,client:client.id,scope:scope});
done(null,tokens.accessToken,null,{expires_in:tokens.expires_in}); done(null,tokens.accessToken,null,{expires_in:tokens.expires_in});
}); });
}
} else { } else {
log.audit({event: "auth.login.fail.permissions",username:username,client:client.id,scope:scope}); log.audit({event: "auth.login.fail.permissions",username:username,client:client.id,scope:scope});
done(null,false); done(null,false);
@ -151,7 +146,7 @@ function authenticateUserToken(req) {
} else { } else {
reject(); reject();
} }
}).catch(reject); });
} else { } else {
reject(); reject();
} }
@ -168,9 +163,6 @@ TokensStrategy.prototype.authenticate = function(req) {
authenticateUserToken(req).then(user => { authenticateUserToken(req).then(user => {
this.success(user,{scope:user.permissions}); this.success(user,{scope:user.permissions});
}).catch(err => { }).catch(err => {
if (err) {
log.trace("token authentication failure: "+err.stack?err.stack:err)
}
this.fail(401); this.fail(401);
}); });
} }

View File

@ -14,7 +14,15 @@
* limitations under the License. * limitations under the License.
**/ **/
const crypto = require("crypto"); function generateToken(length) {
var c = "ABCDEFGHIJKLMNOPQRSTUZWXYZabcdefghijklmnopqrstuvwxyz1234567890";
var token = [];
for (var i=0;i<length;i++) {
token.push(c[Math.floor(Math.random()*c.length)]);
}
return token.join("");
}
var storage; var storage;
var sessionExpiryTime var sessionExpiryTime
@ -107,7 +115,7 @@ module.exports = {
}, },
create: function(user,client,scope) { create: function(user,client,scope) {
return loadSessions().then(function() { return loadSessions().then(function() {
var accessToken = crypto.randomBytes(128).toString('base64'); var accessToken = generateToken(128);
var accessTokenExpiresAt = Date.now() + (sessionExpiryTime*1000); var accessTokenExpiresAt = Date.now() + (sessionExpiryTime*1000);

View File

@ -17,7 +17,7 @@
var util = require("util"); var util = require("util");
var clone = require("clone"); var clone = require("clone");
var bcrypt; var bcrypt;
try { bcrypt = require('@node-rs/bcrypt'); } try { bcrypt = require('bcrypt'); }
catch(e) { bcrypt = require('bcryptjs'); } catch(e) { bcrypt = require('bcryptjs'); }
var users = {}; var users = {};
var defaultUser = null; var defaultUser = null;
@ -33,11 +33,11 @@ function authenticate() {
if (args.length === 2) { if (args.length === 2) {
// Username/password authentication // Username/password authentication
var password = args[1]; var password = args[1];
return bcrypt.compare(password, user.password).then(res => { return new Promise(function(resolve,reject) {
return res ? cleanUser(user) : null bcrypt.compare(password, user.password, function(err, res) {
}).catch(err => { resolve(res?cleanUser(user):null);
return null });
}) });
} else { } else {
// Try to extract common profile information // Try to extract common profile information
if (args[0].hasOwnProperty('photos') && args[0].photos.length > 0) { if (args[0].hasOwnProperty('photos') && args[0].photos.length > 0) {
@ -74,7 +74,7 @@ function init(config) {
} else { } else {
var us = config.users; var us = config.users;
/* istanbul ignore else */ /* istanbul ignore else */
if (!Array.isArray(us)) { if (!util.isArray(us)) {
us = [us]; us = [us];
} }
for (var i=0;i<us.length;i++) { for (var i=0;i<us.length;i++) {

View File

@ -16,7 +16,6 @@
var ws = require("ws"); var ws = require("ws");
var url = require("url"); var url = require("url");
const crypto = require("crypto");
var log = require("@node-red/util").log; // TODO: separate module var log = require("@node-red/util").log; // TODO: separate module
var Tokens; var Tokens;
@ -33,6 +32,8 @@ var activeConnections = [];
var anonymousUser; var anonymousUser;
var retained = {};
var heartbeatTimer; var heartbeatTimer;
var lastSentTime; var lastSentTime;
@ -55,9 +56,17 @@ function handleSessionExpiry(session) {
} }
}) })
} }
function generateSession(length) {
var c = "ABCDEFGHIJKLMNOPQRSTUZWXYZabcdefghijklmnopqrstuvwxyz1234567890";
var token = [];
for (var i=0;i<length;i++) {
token.push(c[Math.floor(Math.random()*c.length)]);
}
return token.join("");
}
function CommsConnection(ws, user) { function CommsConnection(ws, user) {
this.session = crypto.randomBytes(32).toString('base64'); this.session = generateSession(32);
this.ws = ws; this.ws = ws;
this.stack = []; this.stack = [];
this.user = user; this.user = user;
@ -77,35 +86,21 @@ function CommsConnection(ws, user) {
log.trace("comms.close "+self.session); log.trace("comms.close "+self.session);
removeActiveConnection(self); removeActiveConnection(self);
}); });
ws.on('message', function(data,flags) {
const handleAuthPacket = function(msg) { var msg = null;
Tokens.get(msg.auth).then(function(client) { try {
if (client) { msg = JSON.parse(data);
Users.get(client.user).then(function(user) { } catch(err) {
if (user) { log.trace("comms received malformed message : "+err.toString());
self.user = user; return;
log.audit({event: "comms.auth",user:self.user}); }
completeConnection(msg, client.scope,msg.auth,true); if (!pendingAuth) {
if (msg.subscribe) {
self.subscribe(msg.subscribe);
// handleRemoteSubscription(ws,msg.subscribe);
}
} else { } else {
log.audit({event: "comms.auth.fail"}); var completeConnection = function(userScope,session,sendAck) {
completeConnection(msg, null,null,false);
}
});
} else {
Users.tokens(msg.auth).then(function(user) {
if (user) {
self.user = user;
log.audit({event: "comms.auth",user:self.user});
completeConnection(msg, user.permissions,msg.auth,true);
} else {
log.audit({event: "comms.auth.fail"});
completeConnection(msg, null,null,false);
}
});
}
});
}
const completeConnection = function(msg, userScope, session, sendAck) {
try { try {
if (!userScope || !Permissions.hasPermission(userScope,"status.read")) { if (!userScope || !Permissions.hasPermission(userScope,"status.read")) {
ws.send(JSON.stringify({auth:"fail"})); ws.send(JSON.stringify({auth:"fail"}));
@ -124,43 +119,44 @@ function CommsConnection(ws, user) {
// to send anything. // to send anything.
} }
} }
ws.on('message', function(data,flags) {
var msg = null;
try {
msg = JSON.parse(data);
} catch(err) {
log.trace("comms received malformed message : "+err.toString());
return;
}
if (!pendingAuth) {
if (msg.auth) { if (msg.auth) {
handleAuthPacket(msg) Tokens.get(msg.auth).then(function(client) {
} else if (msg.subscribe) { if (client) {
self.subscribe(msg.subscribe); Users.get(client.user).then(function(user) {
// handleRemoteSubscription(ws,msg.subscribe); if (user) {
} else if (msg.topic) { self.user = user;
runtimeAPI.comms.receive({ log.audit({event: "comms.auth",user:self.user});
user: self.user, completeConnection(client.scope,msg.auth,true);
client: self,
topic: msg.topic,
data: msg.data
})
}
} else { } else {
if (msg.auth) { log.audit({event: "comms.auth.fail"});
handleAuthPacket(msg) completeConnection(null,null,false);
}
});
} else {
Users.tokens(msg.auth).then(function(user) {
if (user) {
self.user = user;
log.audit({event: "comms.auth",user:self.user});
completeConnection(user.permissions,msg.auth,true);
} else {
log.audit({event: "comms.auth.fail"});
completeConnection(null,null,false);
}
});
}
});
} else { } else {
if (anonymousUser) { if (anonymousUser) {
log.audit({event: "comms.auth",user:anonymousUser}); log.audit({event: "comms.auth",user:anonymousUser});
self.user = anonymousUser; self.user = anonymousUser;
completeConnection(msg, anonymousUser.permissions, null, false); completeConnection(anonymousUser.permissions,null,false);
//TODO: duplicated code - pull non-auth message handling out //TODO: duplicated code - pull non-auth message handling out
if (msg.subscribe) { if (msg.subscribe) {
self.subscribe(msg.subscribe); self.subscribe(msg.subscribe);
} }
} else { } else {
log.audit({event: "comms.auth.fail"}); log.audit({event: "comms.auth.fail"});
completeConnection(msg, null,null,false); completeConnection(null,null,false);
} }
} }
} }
@ -171,31 +167,25 @@ function CommsConnection(ws, user) {
} }
CommsConnection.prototype.send = function(topic,data) { CommsConnection.prototype.send = function(topic,data) {
var self = this;
if (topic && data) { if (topic && data) {
this.stack.push({topic:topic,data:data}); this.stack.push({topic:topic,data:data});
} }
this._queueSend();
}
CommsConnection.prototype._queueSend = function() {
var self = this;
if (!this._xmitTimer) { if (!this._xmitTimer) {
this._xmitTimer = setTimeout(function() { this._xmitTimer = setTimeout(function() {
try { try {
self.ws.send(JSON.stringify(self.stack.splice(0,50))); self.ws.send(JSON.stringify(self.stack));
self.lastSentTime = Date.now(); self.lastSentTime = Date.now();
} catch(err) { } catch(err) {
removeActiveConnection(self); removeActiveConnection(self);
log.warn(log._("comms.error-send",{message:err.toString()})); log.warn(log._("comms.error-send",{message:err.toString()}));
} }
delete self._xmitTimer; delete self._xmitTimer;
if (self.stack.length > 0) { self.stack = [];
self._queueSend();
}
},50); },50);
} }
} }
CommsConnection.prototype.subscribe = function(topic) { CommsConnection.prototype.subscribe = function(topic) {
runtimeAPI.comms.subscribe({ runtimeAPI.comms.subscribe({
user: this.user, user: this.user,

View File

@ -14,9 +14,11 @@
* limitations under the License. * limitations under the License.
**/ **/
var express = require("express");
var path = require('path'); var path = require('path');
var comms = require("./comms"); var comms = require("./comms");
var library = require("./library");
var info = require("./settings"); var info = require("./settings");
var auth = require("../auth"); var auth = require("../auth");
@ -44,15 +46,14 @@ module.exports = {
runtimeAPI = _runtimeAPI; runtimeAPI = _runtimeAPI;
needsPermission = auth.needsPermission; needsPermission = auth.needsPermission;
if (!settings.disableEditor) { if (!settings.disableEditor) {
info.init(settings, runtimeAPI); info.init(runtimeAPI);
comms.init(server,settings,runtimeAPI); comms.init(server,settings,runtimeAPI);
var ui = require("./ui"); var ui = require("./ui");
ui.init(settings, runtimeAPI); ui.init(runtimeAPI);
const editorApp = apiUtil.createExpressApp(settings)
var editorApp = express();
if (settings.requireHttps === true) { if (settings.requireHttps === true) {
editorApp.enable('trust proxy'); editorApp.enable('trust proxy');
editorApp.use(function (req, res, next) { editorApp.use(function (req, res, next) {
@ -63,12 +64,10 @@ module.exports = {
} }
}); });
} }
var defaultServerSettings = { if (settings.httpServerOptions) {
"x-powered-by": false for (var eOption in settings.httpServerOptions) {
editorApp.set(eOption, settings.httpServerOptions[eOption]);
} }
var serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{});
for (var eOption in serverSettings) {
editorApp.set(eOption, serverSettings[eOption]);
} }
editorApp.get("/",ensureRuntimeStarted,ui.ensureSlash,ui.editor); editorApp.get("/",ensureRuntimeStarted,ui.ensureSlash,ui.editor);
@ -76,16 +75,14 @@ module.exports = {
editorApp.get("/icons/:module/:icon",ui.icon); editorApp.get("/icons/:module/:icon",ui.icon);
editorApp.get("/icons/:scope/:module/:icon",ui.icon); editorApp.get("/icons/:scope/:module/:icon",ui.icon);
editorApp.get(/^\/resources\/((?:@[^\/]+\/)?[^\/]+)\/(.+)$/,ui.moduleResource);
var theme = require("./theme"); var theme = require("./theme");
theme.init(settings, runtimeAPI); theme.init(settings);
editorApp.use("/theme",theme.app()); editorApp.use("/theme",theme.app());
editorApp.use("/",ui.editorResources); editorApp.use("/",ui.editorResources);
//Projects //Projects
var projects = require("./projects"); var projects = require("./projects");
projects.init(settings, runtimeAPI); projects.init(runtimeAPI);
editorApp.use("/projects",projects.app()); editorApp.use("/projects",projects.app());
// Locales // Locales
@ -96,7 +93,6 @@ module.exports = {
// Library // Library
var library = require("./library"); var library = require("./library");
library.init(runtimeAPI); library.init(runtimeAPI);
// editorApp.get("/library/:id",needsPermission("library.read"),library.getLibraryConfig);
editorApp.get(/^\/library\/([^\/]+)\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry); editorApp.get(/^\/library\/([^\/]+)\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry);
editorApp.post(/^\/library\/([^\/]+)\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry); editorApp.post(/^\/library\/([^\/]+)\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry);

View File

@ -15,6 +15,9 @@
**/ **/
var apiUtils = require("../util"); var apiUtils = require("../util");
var fs = require('fs');
var fspath = require('path');
var when = require('when');
var runtimeAPI; var runtimeAPI;
@ -22,17 +25,6 @@ module.exports = {
init: function(_runtimeAPI) { init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI; runtimeAPI = _runtimeAPI;
}, },
// getLibraryConfig: function(req,res) {
// var opts = {
// user: req.user,
// library: req.params.id
// }
// runtimeAPI.library.getConfig(opts).then(function(result) {
// res.json(result);
// }).catch(function(err) {
// apiUtils.rejectHandler(req,res,err);
// });
// },
getEntry: function(req,res) { getEntry: function(req,res) {
var opts = { var opts = {
user: req.user, user: req.user,

View File

@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
var fs = require('fs');
var path = require('path');
// var apiUtil = require('../util');
var i18n = require("@node-red/util").i18n; // TODO: separate module var i18n = require("@node-red/util").i18n; // TODO: separate module
@ -36,19 +39,15 @@ module.exports = {
}, },
get: function(req,res) { get: function(req,res) {
var namespace = req.params[0]; var namespace = req.params[0];
var lngs = req.query.lng;
namespace = namespace.replace(/\.json$/,""); namespace = namespace.replace(/\.json$/,"");
var lang = req.query.lng || i18n.defaultLang; //apiUtil.determineLangFromHeaders(req.acceptsLanguages() || []); var lang = req.query.lng || i18n.defaultLang; //apiUtil.determineLangFromHeaders(req.acceptsLanguages() || []);
if (/[^0-9a-z=\-\*]/i.test(lang)) {
res.json({});
return;
}
var prevLang = i18n.i.language; var prevLang = i18n.i.language;
// Trigger a load from disk of the language if it is not the default // Trigger a load from disk of the language if it is not the default
i18n.i.changeLanguage(lang, function(){ i18n.i.changeLanguage(lang, function(){
i18n.i.changeLanguage(prevLang, function() {
var catalog = loadResource(lang, namespace); var catalog = loadResource(lang, namespace);
res.json(catalog||{}); res.json(catalog||{});
}); });
}); i18n.i.changeLanguage(prevLang);
} }
} }

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
**/ **/
var express = require("express");
var apiUtils = require("../util"); var apiUtils = require("../util");
var settings;
var runtimeAPI; var runtimeAPI;
var needsPermission = require("../auth").needsPermission; var needsPermission = require("../auth").needsPermission;
@ -77,12 +77,11 @@ function getProjectRemotes(req,res) {
}) })
} }
module.exports = { module.exports = {
init: function(_settings, _runtimeAPI) { init: function(_runtimeAPI) {
settings = _settings;
runtimeAPI = _runtimeAPI; runtimeAPI = _runtimeAPI;
}, },
app: function() { app: function() {
var app = apiUtils.createExpressApp(settings) var app = express();
app.use(function(req,res,next) { app.use(function(req,res,next) {
runtimeAPI.projects.available().then(function(available) { runtimeAPI.projects.available().then(function(available) {
@ -123,7 +122,6 @@ module.exports = {
} }
if (req.body.active) { if (req.body.active) {
opts.clearContext = req.body.hasOwnProperty('clearContext')?req.body.clearContext:true
runtimeAPI.projects.setActiveProject(opts).then(function() { runtimeAPI.projects.setActiveProject(opts).then(function() {
listProjects(req,res); listProjects(req,res);
}).catch(function(err) { }).catch(function(err) {
@ -139,7 +137,6 @@ module.exports = {
req.body.hasOwnProperty('description') || req.body.hasOwnProperty('description') ||
req.body.hasOwnProperty('dependencies')|| req.body.hasOwnProperty('dependencies')||
req.body.hasOwnProperty('summary') || req.body.hasOwnProperty('summary') ||
req.body.hasOwnProperty('version') ||
req.body.hasOwnProperty('files') || req.body.hasOwnProperty('files') ||
req.body.hasOwnProperty('git')) { req.body.hasOwnProperty('git')) {
runtimeAPI.projects.updateProject(opts).then(function() { runtimeAPI.projects.updateProject(opts).then(function() {

View File

@ -18,9 +18,9 @@ var runtimeAPI;
var sshkeys = require("./sshkeys"); var sshkeys = require("./sshkeys");
module.exports = { module.exports = {
init: function(settings, _runtimeAPI) { init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI; runtimeAPI = _runtimeAPI;
sshkeys.init(settings, runtimeAPI); sshkeys.init(runtimeAPI);
}, },
userSettings: function(req, res) { userSettings: function(req, res) {
var opts = { var opts = {

View File

@ -15,16 +15,23 @@
**/ **/
var apiUtils = require("../util"); var apiUtils = require("../util");
var express = require("express");
var runtimeAPI; var runtimeAPI;
var settings;
function getUsername(userObj) {
var username = '__default';
if ( userObj && userObj.name ) {
username = userObj.name;
}
return username;
}
module.exports = { module.exports = {
init: function(_settings, _runtimeAPI) { init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI; runtimeAPI = _runtimeAPI;
settings = _settings;
}, },
app: function() { app: function() {
const app = apiUtils.createExpressApp(settings); var app = express();
// List all SSH keys // List all SSH keys
app.get("/", function(req,res) { app.get("/", function(req,res) {

View File

@ -14,41 +14,33 @@
* limitations under the License. * limitations under the License.
**/ **/
var express = require("express");
var util = require("util"); var util = require("util");
var path = require("path"); var path = require("path");
var fs = require("fs"); var fs = require("fs");
var clone = require("clone"); var clone = require("clone");
const apiUtil = require("../util")
var defaultContext = { var defaultContext = {
page: { page: {
title: "Node-RED", title: "Node-RED",
favicon: "favicon.ico", favicon: "favicon.ico",
tabicon: { tabicon: "red/images/node-red-icon-black.svg"
icon: "red/images/node-red-icon-black.svg",
colour: "#8f0000"
}
}, },
header: { header: {
title: "Node-RED", title: "Node-RED",
image: "red/images/node-red.svg" image: "red/images/node-red.svg"
}, },
asset: { asset: {
red: "red/red.min.js", red: (process.env.NODE_ENV == "development")? "red/red.js":"red/red.min.js",
main: "red/main.min.js", main: (process.env.NODE_ENV == "development")? "red/main.js":"red/main.min.js",
vendorMonaco: ""
} }
}; };
var settings;
var theme = null; var theme = null;
var themeContext = clone(defaultContext); var themeContext = clone(defaultContext);
var themeSettings = null; var themeSettings = null;
var activeTheme = null;
var activeThemeInitialised = false;
var runtimeAPI;
var themeApp; var themeApp;
function serveFile(app,baseUrl,file) { function serveFile(app,baseUrl,file) {
@ -66,23 +58,16 @@ function serveFile(app,baseUrl,file) {
} }
} }
function serveFilesFromTheme(themeValue, themeApp, directory, baseDirectory) { function serveFilesFromTheme(themeValue, themeApp, directory) {
var result = []; var result = [];
if (themeValue) { if (themeValue) {
var array = themeValue; var array = themeValue;
if (!Array.isArray(array)) { if (!util.isArray(array)) {
array = [array]; array = [array];
} }
for (var i=0;i<array.length;i++) { for (var i=0;i<array.length;i++) {
let fullPath = array[i]; var url = serveFile(themeApp,directory,array[i]);
if (baseDirectory) {
fullPath = path.resolve(baseDirectory,array[i]);
if (fullPath.indexOf(path.resolve(baseDirectory)) !== 0) {
continue;
}
}
var url = serveFile(themeApp,directory,fullPath);
if (url) { if (url) {
result.push(url); result.push(url);
} }
@ -92,21 +77,10 @@ function serveFilesFromTheme(themeValue, themeApp, directory, baseDirectory) {
} }
module.exports = { module.exports = {
init: function(_settings, _runtimeAPI) { init: function(settings) {
settings = _settings;
runtimeAPI = _runtimeAPI;
themeContext = clone(defaultContext); themeContext = clone(defaultContext);
if (process.env.NODE_ENV == "development") {
themeContext.asset.red = "red/red.js";
themeContext.asset.main = "red/main.js";
}
themeSettings = null; themeSettings = null;
theme = settings.editorTheme || {}; theme = settings.editorTheme || {};
themeContext.asset.vendorMonaco = "vendor/monaco/monaco-bootstrap.js"
if (theme.codeEditor && theme.codeEditor.lib === 'ace') {
themeContext.asset.vendorMonaco = ''
}
activeTheme = theme.theme;
}, },
app: function() { app: function() {
@ -114,15 +88,7 @@ module.exports = {
var url; var url;
themeSettings = {}; themeSettings = {};
themeApp = apiUtil.createExpressApp(settings); themeApp = express();
const defaultServerSettings = {
"x-powered-by": false
}
const serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{});
for (const eOption in serverSettings) {
themeApp.set(eOption, serverSettings[eOption]);
}
if (theme.page) { if (theme.page) {
@ -143,25 +109,13 @@ module.exports = {
} }
if (theme.page.tabicon) { if (theme.page.tabicon) {
let icon = theme.page.tabicon.icon || theme.page.tabicon url = serveFile(themeApp,"/tabicon/",theme.page.tabicon)
url = serveFile(themeApp,"/tabicon/", icon)
if (url) { if (url) {
themeContext.page.tabicon.icon = url; themeContext.page.tabicon = url;
}
if (theme.page.tabicon.colour) {
themeContext.page.tabicon.colour = theme.page.tabicon.colour
} }
} }
themeContext.page.title = theme.page.title || themeContext.page.title; themeContext.page.title = theme.page.title || themeContext.page.title;
// Store the resolved urls to these resources so nodes (such as Debug)
// can access them
theme.page._ = {
css: themeContext.page.css,
scripts: themeContext.page.scripts,
favicon: themeContext.page.favicon
}
} }
if (theme.header) { if (theme.header) {
@ -185,12 +139,13 @@ module.exports = {
} }
if (theme.deployButton) { if (theme.deployButton) {
themeSettings.deployButton = {}; if (theme.deployButton.type == "simple") {
themeSettings.deployButton = {
type: "simple"
}
if (theme.deployButton.label) { if (theme.deployButton.label) {
themeSettings.deployButton.label = theme.deployButton.label; themeSettings.deployButton.label = theme.deployButton.label;
} }
if (theme.deployButton.type == "simple") {
themeSettings.deployButton.type = theme.deployButton.type;
if (theme.deployButton.icon) { if (theme.deployButton.icon) {
url = serveFile(themeApp,"/deploy/",theme.deployButton.icon); url = serveFile(themeApp,"/deploy/",theme.deployButton.icon);
if (url) { if (url) {
@ -205,30 +160,16 @@ module.exports = {
} }
if (theme.login) { if (theme.login) {
let themeContextLogin = {}
let hasLoginTheme = false
if (theme.login.image) { if (theme.login.image) {
url = serveFile(themeApp,"/login/",theme.login.image); url = serveFile(themeApp,"/login/",theme.login.image);
if (url) { if (url) {
themeContextLogin.image = url themeContext.login = {
hasLoginTheme = true image: url
} }
} }
if (theme.login.message) {
themeContextLogin.message = theme.login.message
hasLoginTheme = true
}
if (theme.login.button) {
themeContextLogin.button = theme.login.button
hasLoginTheme = true
}
if (hasLoginTheme) {
themeContext.login = themeContextLogin
} }
} }
themeApp.get("/", async function(req,res) { themeApp.get("/", function(req,res) {
const themePluginList = await runtimeAPI.plugins.getPluginsByType({type:"node-red-theme"});
themeContext.themes = themePluginList.map(theme => theme.id);
res.json(themeContext); res.json(themeContext);
}) })
@ -244,120 +185,10 @@ module.exports = {
themeSettings.projects = theme.projects; themeSettings.projects = theme.projects;
} }
if (theme.hasOwnProperty("multiplayer")) {
themeSettings.multiplayer = theme.multiplayer;
}
if (theme.hasOwnProperty("keymap")) {
themeSettings.keymap = theme.keymap;
}
if (theme.theme) {
themeSettings.theme = theme.theme;
}
if (theme.hasOwnProperty("tours")) {
themeSettings.tours = theme.tours;
}
return themeApp; return themeApp;
}, },
context: async function() { context: function() {
if (activeTheme && !activeThemeInitialised) {
const themePlugin = await runtimeAPI.plugins.getPlugin({
id:activeTheme
});
if (themePlugin) {
if (themePlugin.css) {
const cssFiles = serveFilesFromTheme(
themePlugin.css,
themeApp,
"/css/",
themePlugin.path
);
themeContext.page.css = cssFiles.concat(themeContext.page.css || [])
theme.page = theme.page || {_:{}}
theme.page._.css = cssFiles.concat(theme.page._.css || [])
}
if (themePlugin.scripts) {
const scriptFiles = serveFilesFromTheme(
themePlugin.scripts,
themeApp,
"/scripts/",
themePlugin.path
)
themeContext.page.scripts = scriptFiles.concat(themeContext.page.scripts || [])
theme.page = theme.page || {_:{}}
theme.page._.scripts = scriptFiles.concat(theme.page._.scripts || [])
}
// check and load page settings from theme
if (themePlugin.page) {
if (themePlugin.page.favicon && !theme.page.favicon) {
const result = serveFilesFromTheme(
[themePlugin.page.favicon],
themeApp,
"/",
themePlugin.path
)
if(result && result.length > 0) {
// update themeContext page favicon
themeContext.page.favicon = result[0]
theme.page = theme.page || {_:{}}
theme.page._.favicon = result[0]
}
}
if (themePlugin.page.tabicon && themePlugin.page.tabicon.icon && !theme.page.tabicon) {
const result = serveFilesFromTheme(
[themePlugin.page.tabicon.icon],
themeApp,
"/page/",
themePlugin.path
)
if(result && result.length > 0) {
// update themeContext page tabicon
themeContext.page.tabicon.icon = result[0]
themeContext.page.tabicon.colour = themeContext.page.tabicon.colour || themeContext.page.tabicon.colour
theme.page = theme.page || {_:{}}
theme.page._.tabicon = theme.page._.tabicon || {}
theme.page._.tabicon.icon = themeContext.page.tabicon.icon
theme.page._.tabicon.colour = themeContext.page.tabicon.colour
}
}
// if the plugin has a title AND the users settings.js does NOT
if (themePlugin.page.title && !theme.page.title) {
themeContext.page.title = themePlugin.page.title || themeContext.page.title
}
}
// check and load header settings from theme
if (themePlugin.header) {
if (themePlugin.header.image && !theme.header.image) {
const result = serveFilesFromTheme(
[themePlugin.header.image],
themeApp,
"/header/",
themePlugin.path
)
if(result && result.length > 0) {
// update themeContext header image
themeContext.header.image = result[0]
}
}
// if the plugin has a title AND the users settings.js does NOT have a title
if (themePlugin.header.title && !theme.header.title) {
themeContext.header.title = themePlugin.header.title || themeContext.header.title
}
// if the plugin has a header url AND the users settings.js does NOT
if (themePlugin.header.url && !theme.header.url) {
themeContext.header.url = themePlugin.header.url || themeContext.header.url
}
}
theme.codeEditor = theme.codeEditor || {}
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
theme.mermaid = Object.assign({}, themePlugin.mermaid, theme.mermaid)
}
activeThemeInitialised = true;
}
return themeContext; return themeContext;
}, },
settings: function() { settings: function() {

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
const crypto = require('crypto')
var express = require('express'); var express = require('express');
var fs = require("fs"); var fs = require("fs");
var path = require("path"); var path = require("path");
@ -25,16 +24,13 @@ var apiUtils = require("../util");
var theme = require("./theme"); var theme = require("./theme");
var runtimeAPI; var runtimeAPI;
let settings;
var editorClientDir = path.dirname(require.resolve("@node-red/editor-client")); var editorClientDir = path.dirname(require.resolve("@node-red/editor-client"));
var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.svg"); var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.svg");
var editorTemplatePath = path.join(editorClientDir,"templates","index.mst"); var editorTemplatePath = path.join(editorClientDir,"templates","index.mst");
var editorTemplate; var editorTemplate;
let cacheBuster
module.exports = { module.exports = {
init: function(_settings, _runtimeAPI) { init: function(_runtimeAPI) {
settings = _settings;
runtimeAPI = _runtimeAPI; runtimeAPI = _runtimeAPI;
editorTemplate = fs.readFileSync(editorTemplatePath,"utf8"); editorTemplate = fs.readFileSync(editorTemplatePath,"utf8");
Mustache.parse(editorTemplate); Mustache.parse(editorTemplate);
@ -72,46 +68,8 @@ module.exports = {
apiUtils.rejectHandler(req,res,err); apiUtils.rejectHandler(req,res,err);
}) })
}, },
editor: function(req,res) {
moduleResource: function(req, res) { res.send(Mustache.render(editorTemplate,theme.context()));
let resourcePath = req.params[1];
let opts = {
user: req.user,
module: req.params[0],
path: resourcePath
}
runtimeAPI.nodes.getModuleResource(opts).then(function(data) {
if (data) {
var contentType = mime.getType(resourcePath);
res.set("Content-Type", contentType);
res.send(data);
} else {
res.status(404).end()
}
}).catch(function(err) {
console.log(err.stack);
apiUtils.rejectHandler(req,res,err);
})
},
editor: async function(req,res) {
if (!cacheBuster) {
// settings.instanceId is set asynchronously to the editor-api
// being initiaised. So we defer calculating the cacheBuster hash
// until the first load of the editor
cacheBuster = crypto.createHash('sha1').update(`${settings.version || 'version'}-${settings.instanceId || 'instanceId'}`).digest("hex").substring(0,12)
}
let sessionMessages;
if (req.session && req.session.messages) {
sessionMessages = JSON.stringify(req.session.messages);
delete req.session.messages
}
res.send(Mustache.render(editorTemplate,{
sessionMessages,
cacheBuster,
...await theme.context()
}));
}, },
editorResources: express.static(path.join(editorClientDir,'public')) editorResources: express.static(path.join(editorClientDir,'public'))
}; };

View File

@ -24,8 +24,12 @@
* @namespace @node-red/editor-api * @namespace @node-red/editor-api
*/ */
var express = require("express");
var bodyParser = require("body-parser"); var bodyParser = require("body-parser");
var util = require('util');
var passport = require('passport'); var passport = require('passport');
var when = require('when');
var cors = require('cors');
var auth = require("./auth"); var auth = require("./auth");
var apiUtil = require("./util"); var apiUtil = require("./util");
@ -34,6 +38,7 @@ var adminApp;
var server; var server;
var editor; var editor;
/** /**
* Initialise the module. * Initialise the module.
* @param {Object} settings The runtime settings * @param {Object} settings The runtime settings
@ -45,7 +50,7 @@ var editor;
function init(settings,_server,storage,runtimeAPI) { function init(settings,_server,storage,runtimeAPI) {
server = _server; server = _server;
if (settings.httpAdminRoot !== false) { if (settings.httpAdminRoot !== false) {
adminApp = apiUtil.createExpressApp(settings); adminApp = express();
var cors = require('cors'); var cors = require('cors');
var corsHandler = cors({ var corsHandler = cors({
@ -55,8 +60,8 @@ function init(settings,_server,storage,runtimeAPI) {
adminApp.use(corsHandler); adminApp.use(corsHandler);
if (settings.httpAdminMiddleware) { if (settings.httpAdminMiddleware) {
if (typeof settings.httpAdminMiddleware === "function" || Array.isArray(settings.httpAdminMiddleware)) { if (typeof settings.httpAdminMiddleware === "function") {
adminApp.use(settings.httpAdminMiddleware); adminApp.use(settings.httpAdminMiddleware)
} }
} }
@ -78,8 +83,6 @@ function init(settings,_server,storage,runtimeAPI) {
auth.getToken, auth.getToken,
auth.errorHandler auth.errorHandler
); );
} else if (settings.adminAuth.tokens) {
adminApp.use(passport.initialize());
} }
adminApp.post("/auth/revoke",auth.needsPermission(""),auth.revoke,apiUtil.errorHandler); adminApp.post("/auth/revoke",auth.needsPermission(""),auth.revoke,apiUtil.errorHandler);
} }
@ -108,9 +111,11 @@ function init(settings,_server,storage,runtimeAPI) {
* @return {Promise} resolves when the application is ready to handle requests * @return {Promise} resolves when the application is ready to handle requests
* @memberof @node-red/editor-api * @memberof @node-red/editor-api
*/ */
async function start() { function start() {
if (editor) { if (editor) {
return editor.start(); return editor.start();
} else {
return when.resolve();
} }
} }
@ -119,16 +124,16 @@ async function start() {
* @return {Promise} resolves when the application is stopped * @return {Promise} resolves when the application is stopped
* @memberof @node-red/editor-api * @memberof @node-red/editor-api
*/ */
async function stop() { function stop() {
if (editor) { if (editor) {
editor.stop(); editor.stop();
} }
return when.resolve();
} }
module.exports = { module.exports = {
init, init: init,
start, start: start,
stop, stop: stop,
/** /**
* @memberof @node-red/editor-api * @memberof @node-red/editor-api

View File

@ -14,9 +14,10 @@
* limitations under the License. * limitations under the License.
**/ **/
const express = require("express");
const { log, i18n } = require("@node-red/util"); var log = require("@node-red/util").log; // TODO: separate module
var i18n = require("@node-red/util").i18n; // TODO: separate module
module.exports = { module.exports = {
errorHandler: function(err,req,res,next) { errorHandler: function(err,req,res,next) {
@ -42,10 +43,6 @@ module.exports = {
rejectHandler: function(req,res,err) { rejectHandler: function(req,res,err) {
//TODO: why this when errorHandler also?! //TODO: why this when errorHandler also?!
log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req); log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req);
if (!err.code) {
// by definition, an unexpected_error to log
log.error(err);
}
var response = { var response = {
code: err.code||"unexpected_error", code: err.code||"unexpected_error",
message: err.message||err.toString() message: err.message||err.toString()
@ -63,17 +60,5 @@ module.exports = {
path: req.path, path: req.path,
ip: (req.headers && req.headers['x-forwarded-for']) || (req.connection && req.connection.remoteAddress) || undefined ip: (req.headers && req.headers['x-forwarded-for']) || (req.connection && req.connection.remoteAddress) || undefined
} }
},
createExpressApp: function(settings) {
const app = express();
const defaultServerSettings = {
"x-powered-by": false
}
const serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{});
for (let eOption in serverSettings) {
app.set(eOption, serverSettings[eOption]);
}
return app
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@node-red/editor-api", "name": "@node-red/editor-api",
"version": "4.0.9", "version": "1.1.3",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@ -16,25 +16,25 @@
} }
], ],
"dependencies": { "dependencies": {
"@node-red/util": "4.0.9", "@node-red/util": "1.1.3",
"@node-red/editor-client": "4.0.9", "@node-red/editor-client": "1.1.3",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "1.20.3", "body-parser": "1.19.0",
"clone": "2.1.2", "clone": "2.1.2",
"cors": "2.8.5", "cors": "2.8.5",
"express-session": "1.18.1", "express-session": "1.17.1",
"express": "4.21.2", "express": "4.17.1",
"memorystore": "1.6.7", "memorystore": "1.6.2",
"mime": "3.0.0", "mime": "2.4.6",
"multer": "1.4.5-lts.1", "mustache": "4.0.1",
"mustache": "4.2.0", "oauth2orize": "1.11.0",
"oauth2orize": "1.12.0",
"passport-http-bearer": "1.0.1", "passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"passport": "0.7.0", "passport": "0.4.1",
"ws": "7.5.10" "when": "3.7.8",
"ws": "6.2.1"
}, },
"optionalDependencies": { "optionalDependencies": {
"@node-rs/bcrypt": "1.10.4" "bcrypt": "3.0.6"
} }
} }

View File

@ -1,4 +1,4 @@
Copyright OpenJS Foundation and other contributors, https://openjsf.org/ Copyright JS Foundation and other contributors, http://js.foundation
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004

1109
packages/node_modules/@node-red/editor-client/locales/de/editor.json vendored Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,23 @@
{ {
"info" : { "info" : {
"tip0": "Sie können die ausgewählten Nodes oder Verbindungen mit {{ core:delete-selection }} entfernen", "tip0" : "Sie können die ausgewählten Nodes oder Verbindungen mit {{ core:delete-selection }} entfernen.",
"tip1": "Sie können nach Nodes mit {{ core:search }} suchen", "tip1" : "Suche nach Nodes mit {{ core:search }}",
"tip2": "{{ core:toggle-sidebar }} blendet die Seitenleiste ein/aus", "tip2" : "{{ core:toggle-sidebar }} schaltet die Ansicht dieser Seitenleiste ein.",
"tip3": "Sie können Ihre Node-Palette mit {{ core:manage-palette }} verwalten", "tip3" : "Sie können Ihre Palette von Nodes mit {{ core:manage-palette }} verwalten.",
"tip4": "Ihre Flow-Konfigurationsnodes werden in der Seitenleiste angezeigt, die über das Menü oder mit {{ core:show-config-tab }} angezeigt werden kann", "tip4" : "Ihre Flow-Konfigurations-Nodes werden in der Seitenleiste angezeigt. Es kann über das Menü oder mit {{ core:show-config-tab }} aufgerufen werden.",
"tip5": "Aktiviere oder deaktiviere diese Tipps in den Einstellungen im Tab 'Ansicht'", "tip5" : "Aktiviert oder inaktiviert diese Tipps von der Option in den Einstellungen",
"tip6": "Sie können die ausgewählten Nodes mit den [left]/[up]/[down]/[right]-Tasten verschieben. Wenn Sie dabei [Shift] gedrückt halten, können Sie den Fensterausschnitt verschieben.", "tip6" : "Verschieben Sie die ausgewählten Nodes mit Hilfe der [left] [up] [down] und [right] Tasten. Halten Sie [Shift] gedrückt, um das Fenster weiter zu schieben",
"tip7": "Wenn Sie ein Node auf eine Verbindung ziehen, wird es in die Verbindung eingefügt", "tip7" : "Wenn Sie einen Node auf eine Verbindung ziehen, wird er in die Verbindung eingefügt.",
"tip8": "Sie können die ausgewählten Nodes oder den aktuellen Flow-Tab mit {{ core:show-export-dialog }} exportieren", "tip8" : "Die ausgewählten Nodes exportieren oder die aktuelle Registerkarte mit {{ core:show-export-dialog }}",
"tip9": "Sie können einen Flow importieren, indem Sie sein JSON in den Editor ziehen oder mittels {{ core:show-import-dialog }}", "tip9" : "Importieren Sie einen Flow, indem Sie sein JSON in den Editor ziehen oder mit {{ core:show-import-dialog }}.",
"tip10": "Halten Sie [Shift] beim [Klicken] auf ein Node gedrückt, um auch alle verbundenen Nodes mit zu verschieben", "tip10" : "[Umschalt] [Klicken] und ziehen Sie auf einen Node-Anschluss, um alle angeschlossenen Verbindungen oder nur die ausgewählte zu verschieben.",
"tip11": "Sie können den Tab 'Info' mit {{ core:show-info-tab }} oder den Tab 'Debug' mit {{ core:show-debug-tab }} anzeigen lassen", "tip11" : "Die Registerkarte \"Info\" mit {{ core:show-info-tab }} oder der Registerkarte \"Debug\" mit {{ core:show-debug-tab }} anzeigen",
"tip12": "Halten Sie [Strg] beim [Klicken] in den Arbeitsbereich gedrückt, um den Schnellhinzufügedialog öffnen", "tip12" : "[ctrl] [Klicken] in den Arbeitsbereich, um den Schnellhinzufügedialog zu öffnen.",
"tip13": "Halten Sie [Strg] beim [Klicken] auf einen Node-Anschluss gedrückt, um eine Verbindung nur durch kurzes [Klicken] (ohne Halten) zu verlegen", "tip13" : "Halten Sie [ctrl] gedrückt, wenn Sie auf einem Node-Anschluss klicken, um eine Schnellverbindung zu aktivieren.",
"tip14": "Halten Sie [Shift] beim [Klicken] auf ein Node gedrückt, um auch alle verbundenen Nodes mit auszuwählen", "tip14" : "Halten Sie [Umschalt] gedrückt, wenn Sie auf einen Node klicken, um auch alle verbundenen Nodes auszuwählen.",
"tip15": "Halten Sie [Strg] beim [Klicken] auf ein Node gedrückt, um es zu der aktuellen Auswahl hinzuzufügen oder aus ihr zu entfernen", "tip15" : "Halten Sie [ctrl] gedrückt, wenn Sie auf einen Node klicken, um ihn aus der aktuellen Auswahl hinzuzufügen oder zu entfernen.",
"tip16": "Sie können die Flow-Tabs mit {{ core:show-previous-tab }} und {{ core:show-next-tab }} wechseln", "tip16" : "Indexzungen wechseln mit {{ core:show-previous-tab }} und {{ core:show-next-tab }}",
"tip17": "Sie können die Änderungen im Node-Editor mit {{ core:confirm-edit-tray }} bestätigen oder sie mit {{ core:cancel-edit-tray }} verwerfen", "tip17" : "Sie können die Änderungen im Editierrahmen des Nodes mit {{ core:confirm-edit-tray }} bestätigen oder sie mit {{ core:cancel-edit-tray }} abbrechen.",
"tip18": "Sie können mit {{ core:edit-selected-node }} den ersten Node in der aktuellen Auswahl bearbeiten" "tip18" : "Durch Drücken von {{ core:edit-selected-node }} wird der erste Node in der aktuellen Auswahl bearbeitet."
} }
} }

234
packages/node_modules/@node-red/editor-client/locales/de/jsonata.json vendored Normal file → Executable file
View File

@ -1,95 +1,95 @@
{ {
"$string" : { "$string" : {
"args": "arg[, prettify]", "args" : "arg",
"desc": "Wandelt `arg` in eine Zeichenfolge um gemäß der folgenden Regeln:\n\n- Zeichenfolgen (string) bleiben unverändert\n- Funktionen werden in eine leere Zeichenfolge konvertiert\n- Numerische Unendlichkeit und NaN lösen einen Fehler aus, da sie nicht als JSON-Zahlenwert dargestellt werden können.\n- Alle anderen Werte werden mit Hilfe der Funktion `JSON.stringify` in eine JSON-Zeichenfolge konvertiert. Wenn `prettify` `true` ist, wird \"prettified\" JSON erzeugt. Z.B. Eine Zeile pro Feld und Zeilen werden eingeschoben basierend auf der Feldtiefe." "desc" : "Transformiert den Parameter *arg* in eine Zeichenfolge mit den folgenden Transformationsregeln:\n\n -Zeichenfolgen bleiben unverändert\n -Funktionen werden in eine leere Zeichenfolge konvertiert\n -Numerische Unendlichkeit und NaN lösen einen Fehler aus, da sie nicht als JSON-Nummer dargestellt werden können.\n -Alle anderen Werte werden mit Hilfe der Funktion 'JSON.stringify' in eine JSON-Zeichenfolge konvertiert."
}, },
"$length" : { "$length" : {
"args" : "str", "args" : "str",
"desc": "Gibt die Zeichenanzahl von `str` zurück. Es wird ein Fehler ausgelöst, wenn `str` keine Zeichenfolge ist." "desc" : "Gibt die Anzahl der Zeichen in der Zeichenfolge `str` zurück. Es wird ein Fehler ausgelöst, wenn `str` keine Zeichenfolge ist."
}, },
"$substring" : { "$substring" : {
"args": "str, start [, length]", "args" : "str, start [, länge]",
"desc": "Gibt eine Teilzeichenfolge zurück, die die Zeichen in `str` beginnend bei Position `start` (Null-Offset) enthält. Wenn `length` vorgegeben ist, enthält die rückgegebene Zeichenfolge maximal die in `length` vorgegebene Zeichenanzahl. Wenn `start` negativ ist, werden die Zeichen vom Ende aus gezählt von `str` zurückgegeben." "desc" : "Gibt eine Zeichenfolge zurück, die die Zeichen im ersten Parameter `str` beginnend bei Position `start` (Null-Offset) enthält. Wenn \"length\" angegeben ist, enthält die Unterzeichenfolge maximal \"Länge\" Zeichen. Wenn `start` negativ ist, gibt es die Anzahl der Zeichen am Ende von `str` an."
}, },
"$substringBefore" : { "$substringBefore" : {
"args" : "str, chars", "args" : "str, chars",
"desc": "Gibt die Teilzeichenfolge vor dem ersten Auftreten der Zeichenfolge `chars` in `str` zurück. Falls `str` nicht `chars` enthält, wird `str` zurückgegeben." "desc" : "Gibt die Unterzeichenfolge vor dem ersten Auftreten der Zeichenfolge `chars` in `str` zurück. Falls `str` nicht `chars` enthält, gibt es `str` zurück."
}, },
"$substringAfter" : { "$substringAfter" : {
"args" : "str, chars", "args" : "str, chars",
"desc": "Gibt die Teilzeichenfolge nach dem ersten Auftreten der Zeichenfolge `chars` in `str` zurück. Falls `str` nicht `chars` enthält, wird `str` zurückgegeben." "desc" : "Gibt die Unterzeichenfolge nach dem ersten Auftreten der Zeichenfolge `chars` in `str` zurück. Falls `str` nicht `chars` enthält, gibt es `str` zurück."
}, },
"$uppercase" : { "$uppercase" : {
"args" : "str", "args" : "str",
"desc": "Gibt veränderten `str` zurück, bei dem allen Zeichen in Großbuchstaben umgewandelt wurden." "desc" : "Gibt eine Zeichenfolge mit allen Zeichen von `str` zurück, die in Großbuchstaben konvertiert werden."
}, },
"$lowercase" : { "$lowercase" : {
"args" : "str", "args" : "str",
"desc": "Gibt veränderten `str` zurück, bei dem allen Zeichen in Kleinbuchstaben umgewandelt wurden." "desc" : "Gibt eine Zeichenfolge mit allen Zeichen von `str` in Kleinbuchstaben zurück."
}, },
"$trim" : { "$trim" : {
"args": "[str]", "args" : "str",
"desc": "Normalisiert und trimmt alle Leerzeichen in `str` durch Anwenden der folgenden Schritte:\n\n- Alle Tabulatoren, Wagenrückläufe (returns) und Zeilenvorschübe (line feeds) werden durch Leerzeichen ersetzt.\n- Zusammenhängende Folgen von Leerzeichen werden auf ein einzelnes Leerzeichen reduziert.\n- Leerzeichen am Anfang und am Ende werden entfernt.\n\nWenn `str` nicht vorgegeben ist (d.h. diese Funktion wird ohne Parameter aufgerufen), dann wird der Kontextwert als Wert von `str` verwendet. Es wird ein Fehler ausgelöst, wenn `str` keine Zeichenfolge ist." "desc" : "Normalisiert und trimmt alle Leerzeichen in `str` durch Anwenden der folgenden Schritte:\n\n -Alle Tabulatorstopps, Wagenrückläufe und Zeilenvorschübe werden durch Leerzeichen ersetzt.\n-Zusammenhängende Folgen von Räumen werden auf einen einzigen Raum reduziert.\n-Trailing und führende Plätze werden entfernt.\n\n Wenn 'str' nicht angegeben ist (d. h. Diese Funktion wird ohne Argumente aufgerufen), dann wird der Kontextwert als Wert von `str` verwendet. Es wird ein Fehler ausgelöst, wenn `str` keine Zeichenfolge ist."
}, },
"$contains" : { "$contains" : {
"args": "str, pattern", "args" : "str, Muster",
"desc": "Gibt `false` zurück, wenn `pattern` als Teilzeichenfolge in `str` enthalten ist, sonst gibt sie `false` zurück. Wenn `str` nicht vorgegeben ist (d. h. Diese Funktion wird mit einem Parameter aufgerufen), dann wird der Kontextwert als Wert von `str` verwendet. `pattern` kann entweder eine Zeichenfolge oder ein regulärer Ausdruck sein." "desc" : "Gibt `true` zurück, wenn `str` durch `Muster` abgeglichen wird, sonst gibt es `false` zurück. Wenn 'str' nicht angegeben ist (d. h. Diese Funktion wird mit einem Argument aufgerufen), dann wird der Kontextwert als Wert von `str` verwendet. Der Parameter 'Muster' kann entweder eine Zeichenfolge oder ein regulärer Ausdruck sein."
}, },
"$split" : { "$split" : {
"args": "str [, separator] [, limit]", "args" : "str [, Trennzeichen] [, Grenzwert]",
"desc": "Teilt `str` in einem Array mit Teilzeichenfolgen. Es ergibt einen Fehler, wenn `str` keine Zeichenfolge ist.\n\nDer optionale Parameter `separator` gibt die Zeichen in der `str` an, anhand dem, vorgegeben entweder als Zeichenfolge oder als regulärer Ausdruck, `str` geteilt werden soll. Wenn `separator` nicht vorgegeben wird, wird ein leerer String als `separator` angenommen und `str` wird in ein Array aus einzelnen Zeichen aufgeteilt. Es handelt sich um einen Fehler, wenn `separator` leer ist.\n\nDer optionale Parameter `limit` ist eine Zahl, die die maximale Anzahl von Teilzeichenfolgen angibt, die in dem rückzugebenen Array enthalten sein sollen. Alle zusätzlichen Teilzeichenfolgen werden verworfen. Wenn `limit` nicht vorgegeben wird, wird `str` vollständig geteilt, wobei die Größe des resultierenden Arrays nicht begrenzt ist. Es handelt sich um einen Fehler, wenn `limit` eine negative Zahl ist." "desc" : "Teilt den Parameter 'str' in einem Array mit Unterzeichenfolgen. Es ist ein Fehler, wenn `str` keine Zeichenfolge ist. Der optionale Parameter 'Trennzeichen' gibt die Zeichen in der `str` an, um die es entweder als Zeichenfolge oder als regulärer Ausdruck geteilt werden soll. Wenn 'Trennzeichen' nicht angegeben wird, wird die leere Zeichenfolge angenommen, und `str` wird in ein Array aus einzelnen Zeichen aufgeteilt. Es handelt sich um einen Fehler, wenn `Trennzeichen' keine Zeichenfolge ist. Der optionale Parameter 'Grenzwert' ist eine Zahl, die die maximale Anzahl von Unterzeichenfolgen angibt, die in das resultierende Array eingeschlossen werden sollen. Alle zusätzlichen Unterzeichenfolgen werden gelöscht. Wenn 'Grenzwert' nicht angegeben wird, wird ' str ` vollständig geteilt, wobei die Größe des resultierenden Arrays nicht begrenzt ist. Es handelt sich um einen Fehler, wenn `Grenzwert' keine nicht negative Zahl ist."
}, },
"$join" : { "$join" : {
"args": "array [, separator]", "args" : "array [, Trennzeichen]",
"desc": "Verkettet ein Array von Zeichenfolgen zu einer einzigen Zeichenfolge, wobei die einzelnen Zeichenfolgen durch den optionalen Trennzeichen-Parameter `separator` getrennt sind. Es ergibt einen Fehler, wenn das `array` ein Element enthält, das keine Zeichenfolge ist. Wenn `separator` nicht vorgegeben wird, wird davon ausgegangen, dass es sich um eine leere Zeichenfolge handelt, d.h. zwischen den einzelnen Zeichenfolgen wird kein Trennzeichen eingefügt. Es handelt sich um einen Fehler, wenn `separator` keine Zeichenfolge ist." "desc" : "Verkettet ein Array von Komponentenzeichenfolgen in eine einzelne verkettete Zeichenfolge mit jeder Komponentenzeichenfolge, die durch den optionalen Parameter 'separator' getrennt ist. Es ist ein Fehler, wenn die Eingabe `Array` ein Element enthält, das keine Zeichenfolge ist. Wenn 'Trennzeichen' nicht angegeben wird, wird davon ausgegangen, dass es sich um eine leere Zeichenfolge handelt, d. h. Zwischen den Komponentenzeichenfolgen ist kein Trennzeichen vorhanden. Es handelt sich um einen Fehler, wenn `Trennzeichen' keine Zeichenfolge ist."
}, },
"$match" : { "$match" : {
"args": "str, pattern [, limit]", "args" : "str, Muster [, Grenzwert]",
"desc": "Wendet den regulären Ausdruck `pattern` auf die Zeichenfolge `str` an und gibt ein Array von Objekten zurück, die Informationen zu jedem Vorkommen von `pattern` in `str` enthält." "desc" : "Wendet die Zeichenfolge `str` an den regulären Ausdruck `Muster` an und gibt ein Array von Objekten zurück, wobei jedes Objekt Informationen zu jedem Vorkommen einer Übereinstimmung in `str` enthält."
}, },
"$replace" : { "$replace" : {
"args": "str, pattern, replacement [, limit]", "args" : "str, Muster, Ersatz [, Grenzwert]",
"desc": "Findet Vorkommen von `pattern` in `str` und ersetzt sie durch `replacement`.\n\nDer optionale Parameter `limit` ist die maximale Anzahl an Ersetzungen." "desc" : "Findet Vorkommen von `Muster` in `str` und ersetzt sie durch `Ersatz`.\n\nDer optionale Parameter 'Grenzwert' ist die maximale Anzahl an Ersetzungen."
}, },
"$now" : { "$now" : {
"args" : "", "args" : "",
"desc" : "Generiert einen Zeitstempel im ISO-8601-kompatiblen Format und gibt sie als Zeichenfolge zurück." "desc" : "Generiert einen Zeitstempel im ISO-8601-kompatiblen Format und gibt sie als Zeichenfolge zurück."
}, },
"$base64encode" : { "$base64encode" : {
"args": "str", "args" : "Zeichenfolge",
"desc": "Konvertiert eine ASCII-Zeichenfolge `str` in eine Basis-64-Darstellung. Jedes Zeichen in `str` wird als Byte mit binären Daten behandelt. Dies setzt voraus, dass alle Zeichen in der Zeichenfolge im Bereich von 0x00 bis 0xFF liegen, der alle Zeichen in URI-codierten Zeichenfolgen enthält. Unicode-Zeichen außerhalb dieses Bereichs werden nicht unterstützt." "desc" : "Konvertiert eine ASCII-Zeichenfolge in eine Basis-64-Darstellung. Jedes Zeichen in der Zeichenfolge wird als Byte mit binären Daten behandelt. Dies setzt voraus, dass alle Zeichen in der Zeichenfolge im Bereich von 0x00 bis 0xFF liegen, der alle Zeichen in URI-codierten Zeichenfolgen enthält. Unicode-Zeichen außerhalb dieses Bereichs werden nicht unterstützt."
}, },
"$base64decode" : { "$base64decode" : {
"args": "str", "args" : "Zeichenfolge",
"desc": "Konvertiert den Basis-64-codierten `str` in eine Zeichenfolge unter Verwendung einer UTF-8-Unicode-Codepage." "desc" : "Konvertiert die Basis-64-codierten Byte in eine Zeichenfolge unter Verwendung einer UTF-8-Unicode-Codepage."
}, },
"$number" : { "$number" : {
"args" : "arg", "args" : "arg",
"desc": "Wandelt `arg` unter Verwendung der folgenden Regeln in eine Zahl um:\n\n- Zahlen bleiben unverändert\n- Zeichenfolgen, die eine Folge von Zeichen enthalten, die einen echten JSON-Zahlenwert darstellen, werden in die entsprechende Zahl konvertiert.\n- Alle anderen Werte bewirken, dass ein Fehler ausgelöst wird." "desc" : "Der Parameter 'arg' wird unter Verwendung der folgenden Regeln für das Casting in eine Zahl verwendet:\n\n -Zahlen bleiben unverändert\n -Zeichenfolgen, die eine Folge von Zeichen enthalten, die eine rechtliche JSON-Nummer darstellen, werden in diese Zahl konvertiert.\n -Alle anderen Werte bewirken, dass ein Fehler ausgelöst wird."
}, },
"$abs" : { "$abs" : {
"args": "number", "args" : "Anzahl",
"desc": "Gibt den absoluten Wert von `number` zurück." "desc" : "Gibt den absoluten Wert des Parameters 'Zahl' zurück."
}, },
"$floor" : { "$floor" : {
"args": "number", "args" : "Anzahl",
"desc": "Gibt `number` abgerundet auf die nächste ganze Zahl zurück, die kleiner oder gleich `number` ist." "desc" : "Gibt den Wert von 'Zahl' auf die nächste ganze Zahl zurück, die kleiner oder gleich 'Zahl' ist."
}, },
"$ceil" : { "$ceil" : {
"args": "number", "args" : "Anzahl",
"desc": "Gibt `number` aufgerundet auf die nächste ganze Zahl zurück, die größer oder gleich `number` ist." "desc" : "Gibt den Wert von 'Zahl' auf die nächste ganze Zahl zurück, die größer oder gleich 'Zahl' ist."
}, },
"$round" : { "$round" : {
"args": "number [, precision]", "args" : "Zahl [, Genauigkeit]",
"desc": "Gibt `number` gerundet auf die Anzahl der Nachkommastellen zurück, welche durch den optionalen Parameter `precision` vorgegeben ist." "desc" : "Gibt den Wert des Parameters `Zahl` zurück, der auf die Anzahl der Dezimalstellen gerundet wird, die durch den optionalen Parameter 'Genauigkeit' angegeben wird."
}, },
"$power" : { "$power" : {
"args": "base, exponent", "args" : "Basis, Exponent",
"desc": "Gibt `base` potenziert mit `exponent` zurück." "desc" : "Gibt den Wert von `Basis` potenziert mit `Exponent` zurück."
}, },
"$sqrt" : { "$sqrt" : {
"args": "number", "args" : "Zahl",
"desc": "Gibt die Quadratwurzel von `number` zurück." "desc" : "Gibt die Quadratwurzel des Werts des Parameters 'Zahl' zurück."
}, },
"$random" : { "$random" : {
"args" : "", "args" : "",
@ -97,178 +97,126 @@
}, },
"$millis" : { "$millis" : {
"args" : "", "args" : "",
"desc": "Gibt die aktuelle Anzahl der Millisekunden seit Beginn der Unix-Zeitrechnung (1. Januar 1970 UTC) als Zahl zurück. Alle Aufrufe von `$millis()` innerhalb der Auswertung eines Ausdrucks geben alle denselben Wert zurück." "desc" : "Gibt die Anzahl der Millisekunden seit der Unix-Epoche (1. Januar 1970 (UTC)) als Zahl zurück. Alle Invocationen von `$millis ()` innerhalb einer Auswertung eines Ausdrucks geben alle denselben Wert zurück."
}, },
"$sum" : { "$sum" : {
"args": "array", "args" : "Array",
"desc": "Gibt die arithmetische Summe eines `array` von Zahlen zurück. Es ergibt einen Fehler, wenn `array` ein Element enthält, das keine Zahl ist." "desc" : "Gibt die arithmetische Summe eines `Array` von Zahlen zurück. Es ist ein Fehler, wenn die Eingabe `Array` ein Element enthält, das keine Zahl ist."
}, },
"$max" : { "$max" : {
"args": "array", "args" : "Array",
"desc": "Gibt die größte Zahl von einem `array` von Zahlen zurück. Es ergibt einen Fehler, wenn `array` ein Element enthält, das keine Zahl ist." "desc" : "Gibt die maximale Anzahl in einem `Array` von Zahlen zurück. Es ist ein Fehler, wenn die Eingabe `Array` ein Element enthält, das keine Zahl ist."
}, },
"$min" : { "$min" : {
"args": "array", "args" : "Array",
"desc": "Gibt die kleinste Zahl von einem `array` von Zahlen zurück. Es ergibt einen Fehler, wenn `array` ein Element enthält, das keine Zahl ist." "desc" : "Gibt die minimale Zahl in einem `Array` von Zahlen zurück. Es ist ein Fehler, wenn die Eingabe `Array` ein Element enthält, das keine Zahl ist."
}, },
"$average" : { "$average" : {
"args": "array", "args" : "Array",
"desc": "Gibt den Mittelwert eines `array` von Zahlen zurück. Es ergibt einen Fehler, wenn `array` ein Element enthält, das keine Zahl ist." "desc" : "Gibt den Mittelwert eines `Array` von Zahlen zurück. Es ist ein Fehler, wenn die Eingabe `Array` ein Element enthält, das keine Zahl ist."
}, },
"$boolean" : { "$boolean" : {
"args" : "arg", "args" : "arg",
"desc": "Wandelt `arg` gemäß folgender Regeln in einen booleschen Wert um:\n\n- `Boolean`: unverändert\n- `string`: leer → `false`, nicht leer → `true`\n- `Zahl`: `0` → `falsch`, Nicht-Null → `true`\n- `null` → `false`\n- `array`: leer → `false`, enthält mindestens ein Element, das `true` ist → `true`, alle Elemente sind `false` → `false`\n- `object`: leer → `false`, nicht leer → `true`\n- `function`: `false`" "desc" : "Castet das Argument mit den folgenden Regeln in einen Booleschen Wert:\n\n -` Boolean ': nicht geändert\n -` string `: leer: `false`\n -` string `: nicht leer: `true`\n -` Zahl `: ` 0 `: ` falsch `\n -` Zahl `: Nicht-Null: `true`\n -` null `: `false`\n -` array `: leer: `false`\n -` array `: enthält ein Mitglied, das auf `true` setzt: `true`\n -` array `: alle Member werden in `false` umgesetzt: `false`\n -` object `: empty: `false`\n -` object `: non-empty: `true`\n -` Funktion `: ` falsch `"
}, },
"$not" : { "$not" : {
"args" : "arg", "args" : "arg",
"desc": "Gibt den invertierten booleschen Wert von `arg` zurück. `arg` wird zuerst in einen booleschen Wert umgesetzt." "desc" : "Gibt den Booleschen Wert NOT für das Argument zurück. `arg` wird zuerst in einen Booleschen Wert umgesetzt."
}, },
"$exists" : { "$exists" : {
"args" : "arg", "args" : "arg",
"desc": "Gibt den booleschen Wert `true` zurück, wenn der Ausdruck `arg` zu einem Wert ausgewertet wird, oder `false`, wenn der Ausdruck nicht mit einem anderen Ausdruck übereinstimmt (z.B. ein Pfad zu einer nicht vorhandenen Feldreferenz)." "desc" : "Gibt den Booleschen Wert 'true' zurück, wenn der Ausdruck `arg` als Wert ausgewertet wird, oder 'false', wenn der Ausdruck nicht mit einem anderen Ausdruck übereinstimmt (z. B. ein Pfad zu einer nicht vorhandenen Feldreferenz)."
}, },
"$count" : { "$count" : {
"args": "array", "args" : "Array",
"desc": "Gibt die Anzahl der Elemente in dem Array `array` zurück." "desc" : "Gibt die Anzahl der Elemente in dem Array zurück."
}, },
"$append" : { "$append" : {
"args": "array, array", "args" : "Array, Array",
"desc": "Verkettet zwei Arrays miteinander." "desc" : "Hängen Sie zwei Arrays an."
}, },
"$sort" : { "$sort" : {
"args": "array [, function]", "args" : "array [, Funktion]",
"desc": "Gibt ein Array zurück, das alle Elemente vom `array` in sortierter Reihenfolge enthält.\n\nWenn ein Vergleichsoperator `function` vorgegeben wird, muss es sich um eine Funktion handeln, die zwei Parameter benötigt:\n\n`function(left, right)`\n\nDiese Funktion wird durch den Sortieralgorithmus aufgerufen, um zwei Elemente links und rechts zu vergleichen. Wenn das linke Element nach dem rechten in der gewünschten Sortierreihenfolge platziert werden soll, muss die Funktion den booleschen Wert `true` zurückgeben, um eine Vertauschung anzuzeigen. Andernfalls muss `false` zurückgegeben werden." "desc" : "Gibt ein Array zurück, das alle Werte im Parameter 'array' enthält, aber in der Reihenfolge sortiert wird.\n\nWenn ein Vergleichsoperator 'function' angegeben wird, muss es sich um eine Funktion handeln, die zwei Parameter benötigt:\n\n` Funktion (links, rechts) `\n\nDiese Funktion wird durch den Sortieralgorithmus aufgerufen, um zwei Werte links und rechts zu vergleichen. Wenn der Wert von links nach dem Wert von rechts in der gewünschten Sortierreihenfolge platziert werden soll, muss die Funktion den Booleschen Wert 'true' zurückgeben, um einen Auslagerungsspeicher anzuzeigen. Andernfalls muss 'false' zurückgegeben werden."
}, },
"$reverse" : { "$reverse" : {
"args": "array", "args" : "Array",
"desc": "Gibt ein Array zurück, das alle Elemente vom `array` in umgekehrter Reihenfolge enthält." "desc" : "Gibt ein Array zurück, das alle Werte aus dem Parameter 'array' enthält, aber in umgekehrter Reihenfolge."
}, },
"$shuffle" : { "$shuffle" : {
"args": "array", "args" : "Array",
"desc": "Gibt ein Array zurück, das alle Elemente vom `array` in zufälliger Reihenfolge enthält." "desc" : "Gibt ein Array zurück, das alle Werte aus dem Parameter ` array ` enthält, aber in zufälliger Reihenfolge geschattiert ist."
}, },
"$zip" : { "$zip" : {
"args": "array, ...", "args" : "Array, ...",
"desc": "Gibt ein gepacktes (geziptes) Array zurück, das gruppierte Arrays der Elemente von `array1` ... `arrayN` aus Index 0, 1, 2 ... enthält." "desc" : "Gibt ein konvolviertes (gezipptes) Array zurück, das gruppierte Arrays von Werten aus den Argumenten ` array1 ` ... ` arrayN ' aus Index 0, 1, 2 ... enthält."
}, },
"$keys" : { "$keys" : {
"args": "object", "args" : "Objekt",
"desc": "Gibt ein Array zurück, das die Schlüssel in dem Objekt `object` enthält. Wenn es sich bei dem Parameter um ein Array von Objekten handelt, enthält das zurückgegebene Array eine deduplizierte Liste aller Schlüssel in allen Objekten." "desc" : "Gibt ein Array zurück, das die Schlüssel in dem Objekt enthält. Wenn es sich bei dem Argument um ein Array von Objekten handelt, enthält das zurückgegebene Array eine deduplizierte Liste aller Schlüssel in allen Objekten."
}, },
"$lookup" : { "$lookup" : {
"args": "object, key", "args" : "Objekt, Schlüssel",
"desc": "Gibt den Wert zurück, der dem Schlüssel `key` im Objekt `object` zugeordnet ist. Wenn es sich bei dem ersten Parameter um ein Array von Objekten handelt, werden alle Objekte im Array durchsucht, und die Werte, die mit allen Vorkommen des Schlüssels verknüpft sind, werden zurückgegeben." "desc" : "Gibt den Wert zurück, der dem Schlüssel im Objekt zugeordnet ist. Wenn es sich bei dem ersten Argument um ein Array von Objekten handelt, werden alle Objekte im Array durchsucht, und die Werte, die mit allen Vorkommen des Schlüssels verknüpft sind, werden zurückgegeben."
}, },
"$spread" : { "$spread" : {
"args": "object", "args" : "Objekt",
"desc": "Teilt ein Objekt `object`, das Schlüssel/Wert-Paare enthält, in ein Array von Objekten, von denen jedes ein einzelnes Schlüssel/Wert-Paar aus dem Eingabeobjekt hat. Wenn es sich bei dem Parameter um ein Array von Objekten handelt, enthält die resultierende Feldgruppe ein Objekt für jedes Schlüssel/Wert-Paar in jedem Objekt in der vorgegebenen Feldgruppe." "desc" : "Teilt ein Objekt, das Schlüssel/Wert-Paare enthält, in ein Array von Objekten, von denen jedes ein einzelnes Schlüssel/Wert-Paar aus dem Eingabeobjekt hat. Wenn es sich bei dem Parameter um ein Array von Objekten handelt, enthält die resultierende Feldgruppe ein Objekt für jedes Schlüssel/Wert-Paar in jedem Objekt in der angegebenen Feldgruppe."
}, },
"$merge" : { "$merge" : {
"args" : "array &lt;object&gt;", "args" : "array &lt;object&gt;",
"desc": "Fügt ein Array von Objekt-Elementen `object` in ein einzelnes Objekt `object` zusammen, das alle Schlüssel/Wert-Paare aus jedem der Objekte in dem Ausgangs-Array enthält. Wenn eines der Ausgangs-Objekte denselben Schlüssel enthält, enthält das zurückgegebene Objekt den Wert des letzten Objekts des Arrays. Es handelt sich um einen Fehler, wenn das Ausgangs-Array ein Element enthält, das kein Objekt ist." "desc" : "Mischt ein Array von ` Objekten ` in ein einzelnes ` Objekt `, das alle Schlüssel/Wert-Paare aus jedem der Objekte in dem Eingabe-Array enthält. Wenn eines der Eingabeobjekte denselben Schlüssel enthält, enthält das zurückgegebene Objekt den Wert des letzten Objekts in der Feldgruppe. Es handelt sich um einen Fehler, wenn das Eingabe-Array ein Element enthält, das kein Objekt ist."
}, },
"$sift" : { "$sift" : {
"args": "object, function", "args" : "Objekt, Funktion",
"desc": "Gibt ein Objekt zurück, das nur die Schlüssel/Wert-Paare aus dem Parameter `object` enthält, die die Prädikat `function` erfüllen, die als zweiter Parameter übergeben wird.\n\nDie Funktion `function`, die als zweiter Parameter vorgegeben wird, muss die folgende Signatur aufweisen:\n\n`function(value [, key [, object]])`" "desc" : "Gibt ein Objekt zurück, das nur die Schlüssel/Wert-Paare aus dem Parameter 'object' enthält, die die Prädikat ` funktion ' erfüllen, die als zweiter Parameter übergeben wird.\n\nDie Funktion ` function `, die als zweiter Parameter angegeben wird, muss die folgende Signatur aufweisen:\n\n` function (value [, key [, object]]) `"
}, },
"$each" : { "$each" : {
"args": "object, function", "args" : "Objekt, Funktion",
"desc" : "Gibt ein Array zurück, das die Werte enthält, die von der Funktion ` function ` zurückgegeben werden, wenn sie auf jedes Schlüssel/Wert-Paar im ` object ` angewendet werden." "desc" : "Gibt ein Array zurück, das die Werte enthält, die von der Funktion ` function ` zurückgegeben werden, wenn sie auf jedes Schlüssel/Wert-Paar im ` object ` angewendet werden."
}, },
"$map" : { "$map" : {
"args": "array, function", "args" : "Array, Funktion",
"desc": "Gibt ein Array zurück, das die Ergebnisse von `function`, angewendet auf jedes Element von `array`, enthält.\n\nDie Funktion `function`, die als zweiter Parameter vorgegeben wird, muss die folgende Signatur aufweisen:\n\n`function(value [, index [, array]])`" "desc" : "Gibt ein Array zurück, das die Ergebnisse der Anwendung des Parameters ` function ` auf jeden Wert im Parameter 'array' enthält.\n\nDie Funktion ` function `, die als zweiter Parameter angegeben wird, muss die folgende Signatur aufweisen:\n\n` function (value [, index [, array]]) `"
}, },
"$filter" : { "$filter" : {
"args": "array, function", "args" : "Array, Funktion",
"desc": "Gibt ein Array zurück, das nur die Elemente von `array` enthält, die das Eigenschaft `function` erfüllen.\n\nDie Funktion `function`, die als zweiter Parameter vorgegeben wird, muss die folgende Signatur aufweisen:\n\n`function(value [, index [, array]])`" "desc" : "Gibt ein Array zurück, das nur die Werte im Parameter 'array' enthält, die das Prädikat ` funktion ` erfüllen.\n\nDie Funktion ` function `, die als zweiter Parameter angegeben wird, muss die folgende Signatur aufweisen:\n\n` function (value [, index [, array]]) `"
}, },
"$reduce" : { "$reduce" : {
"args" : "array, function [, init]", "args" : "array, function [, init]",
"desc": "Gibt einen aggregierten Wert zurück, der aus der Anwendung des Parameters `function` nacheinander auf jedes Element in `array` in Kombination mit dem Ergebnis der vorherigen Anwendung der Funktion angewendet wurde.\n\nDie Funktion muss zwei Parameter akzeptieren und verhält sich wie ein Infix-Operator zwischen jedem Element innerhalb des `array`.\n\nDer optionale Parameter `init` wird als Anfangswert in der Aggregation verwendet." "desc" : "Gibt einen aggregierten Wert zurück, der aus der Anwendung des Parameters ` function 'nacheinander auf jeden Wert in' array ` in Kombination mit dem Ergebnis der vorherigen Anwendung der Funktion angewendet wurde.\n\nDie Funktion muss zwei Argumente akzeptieren und verhält sich wie ein Infix-Operator zwischen jedem Wert innerhalb des ` Array `.\n\nDer optionale Parameter 'init' wird als Anfangswert in der Aggregation verwendet."
}, },
"$flowContext" : { "$flowContext" : {
"args": "str [, str]", "args" : "Zeichenfolge [, Zeichenfolge]",
"desc": "Ruft eine Flow-Kontexteigenschaft ab.\n\nDies ist eine definierte Funktion vom Typ `Node-RED`." "desc" : "Ruft eine Flusskontexteigenschaft ab.\n\nDies ist eine definierte Funktion vom Typ \"Node-RED\"."
}, },
"$globalContext" : { "$globalContext" : {
"args": "str [, str]", "args" : "Zeichenfolge [, Zeichenfolge]",
"desc": "Ruft eine globale Kontexteigenschaft ab.\n\nDies ist eine definierte Funktion vom Typ `Node-RED`." "desc" : "Ruft eine globale Kontexteigenschaft ab.\n\nDies ist eine definierte Funktion vom Typ \"Node-RED\"."
}, },
"$pad" : { "$pad" : {
"args": "str, width [, char]", "args" : "string, width [, char]",
"desc": "Gibt eine aufgefüllte Kopie von `str` zurück, so dass (falls erforderlich) die Gesamtzahl der Zeichen mindestens dem absoluten Wert von `width` entspricht.\n\nWenn `width` eine positive Zahl ist, wird die Zeichenfolge nach rechts aufgefüllt. Wenn sie negativ ist, wird sie nach links aufgefüllt.\n\nDer optionale Parameter `char` gibt die Auffüll-Zeichen an, die verwendet werden sollen. Wenn keine Angabe gemacht wird, wird standardmäßig mit Leerzeichen aufgefüllt." "desc" : "Gibt eine Kopie der ` Zeichenfolge ` mit zusätzlichen Aufenthalten zurück, falls erforderlich, so dass die Gesamtzahl der Zeichen mindestens der absolute Wert des Parameters 'width' ist.\n\nWenn ` width ` eine positive Zahl ist, wird die Zeichenfolge nach rechts aufgefüllt. Wenn sie negativ ist, wird sie nach links geplisften.\n\nDas optionale Argument 'char' gibt die Padding-Zeichen an, die verwendet werden sollen. Wenn keine Angabe gemacht wird, wird standardmäßig der Wert für das Leerzeichen angenommen."
}, },
"$fromMillis" : { "$fromMillis" : {
"args": "number", "args" : "Anzahl",
"desc": "Konvertiert `number`, die die Millisekunden seit Beginn der Unix-Zeitrechnung (1. Januar 1970 UTC) enthält, in eine Zeitangabe im ISO 8601-Format." "desc" : "Konvertieren Sie eine Zahl, die Millisekunden seit der Unix-Epoche (1. Januar 1970 (UTC)) enthält in eine Zeitangabe im ISO 8601-Format."
}, },
"$formatNumber" : { "$formatNumber" : {
"args": "number, picture [, options]", "args" : "Zahl, Bild [, Optionen]",
"desc": "Wandelt `number` in eine Zeichenfolge um und formatiert sie in eine dezimale Darstellung, wie im `picture`-String-Parameter vorgegeben.\n\nDas Verhalten dieser Funktion ist mit der XPath/XQuery-Funktion `fn:formatnummer` konsistent, wie sie in der XPath F&O 3.1-Spezifikation definiert ist. Der `picture`-String-Parameter definiert, wie die Zahl formatiert ist und hat die gleiche Syntax wie `fn:format-number`.\n\nDer optionale dritte Parameter `options` wird verwendet, um die standardmäßigen länderspezifischen Formatierungszeichen, wie z.B. das Dezimaltrennzeichen, zu überschreiben. Wenn dieser Parameter vorgegeben wird, muss es sich um ein Objekt handeln, das Name/Wert-Paare enthält, die im Abschnitt mit dem Dezimalformat der XPath F&O 3.1-Spezifikation vorgegeben sind." "desc" : "Transformiere die `Zahl` an eine Zeichenfolge und formatiert sie in eine dezimale Darstellung, wie in der 'Bild' -Zeichenfolge angegeben.\n\n Das Verhalten dieser Funktion ist mit der XPath/XQuery-Funktion fn:formatnummer konsistent, wie sie in der XPath F&O 3.1-Spezifikation definiert ist. Der Parameter für die Bildzeichenfolge definiert, wie die Zahl formatiert ist und hat die gleiche Syntax wie fn:format-number.\n\nDas optionale dritte Argument ` Optionen ` wird verwendet, um die standardmäßigen länderspezifischen Formatierungszeichen, wie z. B. das Dezimaltrennzeichen, zu überschreiben. Wenn dieses Argument angegeben wird, muss es sich um ein Objekt handeln, das Name/Wert-Paare enthält, die im Abschnitt mit dem Dezimalformat der XPath F&O 3.1-Spezifikation angegeben sind."
}, },
"$formatBase" : { "$formatBase" : {
"args": "number [, radix]", "args" : "Zahl [, Radix]",
"desc": "Wandelt `number` in eine Zeichenfolge um und formatiert sie in eine ganze Zahl, die in der durch den `radix`-Parameter vorgegebenen Zahlenbasis dargestellt wird. Wenn `radix` nicht vorgegeben wird, wird standardmäßig die Basis 10 verwendet. `radix` kann zwischen 2 und 36 liegen, andernfalls wird ein Fehler ausgelöst." "desc" : "Transformiere die `Zahl` in eine Zeichenfolge und formatiert sie in eine ganze Zahl, die in der durch das `radix` -Argument angegebenen Zahlenbasis dargestellt wird. Wenn 'radix' nicht angegeben wird, wird standardmäßig die Basis 10 verwendet. 'radix` kann zwischen 2 und 36 liegen, andernfalls wird ein Fehler ausgelöst."
}, },
"$toMillis" : { "$toMillis" : {
"args" : "timestamp", "args" : "timestamp",
"desc": "Konvertiert eine Zeitangabe `timestamp` im ISO 8601-Format in die Anzahl der Millisekunden seit Beginn der Unix-Zeitrechnung (1. Januar 1970 UTC). Es wird ein Fehler ausgelöst, wenn die Zeichenfolge nicht das richtige Format hat." "desc" : "Konvertieren Sie eine Zeitangabe im ISO 8601-Format in die Anzahl der Millisekunden seit der Unix-Epoche (1. Januar 1970 (UTC)) als Zahl. Es wird ein Fehler ausgelöst, wenn die Zeichenfolge nicht das richtige Format hat."
}, },
"$env" : { "$env" : {
"args" : "arg", "args" : "arg",
"desc": "Gibt den Wert einer Umgebungsvariablen zurück.\n\nDies ist eine definierte Funktion vom Typ `Node-RED`." "desc" : "Gibt den Wert einer Umgebungsvariablen zurück.\n\nDies ist eine definierte Funktion vom Typ \"Node-RED\"."
},
"$eval": {
"args": "expr [, context]",
"desc": "Analysiert (parse) und evaluiert den String `expr`, welcher JSON or a JSONata Ausdrücke enthält, unter Benutzung des aktuellen Kontextes für die Evaluierung."
},
"$formatInteger": {
"args": "number, picture",
"desc": "Wandelt `number` in eine Zeichenfolge um und formatiert sie in einer Ganzzahl-Darstellung, spezifiziert durch den `picture`-String-Parameter. Der `picture`-String-Parameter definiert, wie die Zahl `number` formatiert werden soll und hat den selben Syntax wie `fn:format-integer` der XPath F&O 3.1 Spezifikation."
},
"$parseInteger": {
"args": "str, picture",
"desc": "Wandelt den Inhalt von `str` in eine Ganzzahl `integer` (als JSON Zahl), spezifiziert durch den `picture`-String-Parameter. Der `picture`-String-Parameter hat das selbe Format wie `$formatInteger`."
},
"$error": {
"args": "[str]",
"desc": "Erzeugt eine Fehlermeldung. Der optionale String `str` ersetzt die Standardmeldung `$error() function evaluated`."
},
"$assert": {
"args": "arg, str",
"desc": "Wenn `arg` gleich `true` ist, liefert die Function `undefined` zurück. Wenn `arg` gleich `false` ist, wird ein Ausnahmefehler gemeldet mit dem String_Parameter `str` als Meldetext."
},
"$single": {
"args": "array, function",
"desc": "Gibt ein einziges Element aus `array` zurück, welches die Bedingung `function` erfüllt (d.h. die Funktion `function` gibt den booleschen Wert `true` zurück, wenn das Element übergeben werden soll). Sie meldet einen Ausnahmefehler, wenn die Anzahl der Elemente mit erfüllter Bedingung (`function` ist `true`) nicht genau eins ist.\n\nDie Funktion `function` sollte in der folgenden Art vorgegeben werden: `function(value [, index [, array]])` wobei `value` für jedes Element des Arrays gilt, `index` ist die Position dieses Elements und das gesamte Array `array` wird als dritter Parameter übergeben."
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Kodiert eine URL-Komponente (Uniform Resource Locator), indem jedes Vorkommen bestimmter Zeichen durch eine, zwei, drei oder vier Escape-Sequenzen ersetzt wird, die die UTF-8-Kodierung des Zeichens darstellen.\n\nBeispiel: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrl": {
"args": "str",
"desc": "Kodiert eine URL (Uniform Resource Locator), indem jedes Vorkommen bestimmter Zeichen durch eine, zwei, drei oder vier Escape-Sequenzen ersetzt wird, die die UTF-8-Kodierung des Zeichens darstellen.\n\nBeispiel: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "Dekodiert eine URL-Komponente (Uniform Resource Locator) zuvor erzeugt von encodeUrlComponent.\n\nBeispiel: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "Dekodiert eine URL (Uniform Resource Locator) zuvor erzeugt von encodeUrl.\n\nBeispiel: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "Liefert ein `array` zurück, bei dem doppelte Elemente entfernt wurden."
},
"$type": {
"args": "value",
"desc": "Liefert den Typ von `value` als String. When `value` undefiniert ist, wird `undefined` zurückgeliefert."
},
"$moment": {
"args": "[str]",
"desc": "Liefert ein `date` Objekt unter Benutzung der Moment Library."
} }
} }

View File

@ -22,13 +22,7 @@
"color": "Color", "color": "Color",
"position": "Position", "position": "Position",
"enable": "Enable", "enable": "Enable",
"disable": "Disable", "disable": "Disable"
"upload": "Upload",
"lock": "Lock",
"unlock": "Unlock",
"locked": "Locked",
"unlocked": "Unlocked",
"format": "Format"
}, },
"type": { "type": {
"string": "string", "string": "string",
@ -43,14 +37,11 @@
} }
}, },
"event": { "event": {
"loadPlugins": "Loading Plugins",
"loadPalette": "Loading Palette", "loadPalette": "Loading Palette",
"loadNodeCatalogs": "Loading Node catalogs", "loadNodeCatalogs": "Loading Node catalogs",
"loadNodes": "Loading Nodes __count__", "loadNodes": "Loading Nodes __count__",
"loadFlows": "Loading Flows", "loadFlows": "Loading Flows",
"importFlows": "Adding Flows to workspace", "importFlows": "Adding Flows to workspace"
"importError": "<p>Error adding flows</p><p>__message__</p>",
"loadingProject": "Loading project"
}, },
"workspace": { "workspace": {
"defaultName": "Flow __number__", "defaultName": "Flow __number__",
@ -58,38 +49,19 @@
"confirmDelete": "Confirm delete", "confirmDelete": "Confirm delete",
"delete": "Are you sure you want to delete '__label__'?", "delete": "Are you sure you want to delete '__label__'?",
"dropFlowHere": "Drop the flow here", "dropFlowHere": "Drop the flow here",
"dropImageHere": "Drop the image here", "addFlow": "Add Flow",
"addFlow": "Add flow", "listFlows": "List Flows",
"addFlowToRight": "Add flow to the right",
"closeFlow": "Close flow",
"hideFlow": "Hide flow",
"hideOtherFlows": "Hide other flows",
"showAllFlows": "Show all flows (__count__ hidden)",
"hideAllFlows": "Hide all flows",
"hiddenFlows": "List __count__ hidden flow",
"hiddenFlows_plural": "List __count__ hidden flows",
"showLastHiddenFlow": "Reopen hidden flow",
"listFlows": "List flows",
"listSubflows": "List subflows",
"status": "Status", "status": "Status",
"enabled": "Enabled", "enabled": "Enabled",
"disabled":"Disabled", "disabled":"Disabled",
"info": "Description", "info": "Description",
"selectNodes": "Click nodes to select", "selectNodes": "Click nodes to select"
"enableFlow": "Enable flow",
"disableFlow": "Disable flow",
"lockFlow": "Lock flow",
"unlockFlow": "Unlock flow",
"moveToStart": "Move flow to start",
"moveToEnd": "Move flow to end"
}, },
"menu": { "menu": {
"label": { "label": {
"view": { "view": {
"view": "View", "view": "View",
"grid": "Grid", "grid": "Grid",
"storeZoom": "Restore zoom level on load",
"storePosition": "Restore scroll position on load",
"showGrid": "Show grid", "showGrid": "Show grid",
"snapGrid": "Snap to grid", "snapGrid": "Snap to grid",
"gridSize": "Grid size", "gridSize": "Grid size",
@ -107,14 +79,12 @@
"palette": { "palette": {
"show": "Show palette" "show": "Show palette"
}, },
"edit": "Edit",
"settings": "Settings", "settings": "Settings",
"userSettings": "User Settings", "userSettings": "User Settings",
"nodes": "Nodes", "nodes": "Nodes",
"displayStatus": "Show node status", "displayStatus": "Show node status",
"displayConfig": "Configuration nodes", "displayConfig": "Configuration nodes",
"import": "Import", "import": "Import",
"importExample": "Import example flow",
"export": "Export", "export": "Export",
"search": "Search flows", "search": "Search flows",
"searchInput": "search your flows", "searchInput": "search your flows",
@ -123,6 +93,7 @@
"selectionToSubflow": "Selection to Subflow", "selectionToSubflow": "Selection to Subflow",
"flows": "Flows", "flows": "Flows",
"add": "Add", "add": "Add",
"rename": "Rename",
"delete": "Delete", "delete": "Delete",
"keyboardShortcuts": "Keyboard shortcuts", "keyboardShortcuts": "Keyboard shortcuts",
"login": "Login", "login": "Login",
@ -130,48 +101,24 @@
"editPalette":"Manage palette", "editPalette":"Manage palette",
"other": "Other", "other": "Other",
"showTips": "Show tips", "showTips": "Show tips",
"showNodeHelp": "Show node help",
"enableSelectedNodes": "Enable selected nodes",
"disableSelectedNodes": "Disable selected nodes",
"showSelectedNodeLabels": "Show selected node labels",
"hideSelectedNodeLabels": "Hide selected node labels",
"showWelcomeTours": "Show guided tours for new versions",
"help": "Node-RED website", "help": "Node-RED website",
"projects": "Projects", "projects": "Projects",
"projects-new": "New", "projects-new": "New",
"projects-open": "Open", "projects-open": "Open",
"projects-settings": "Project Settings", "projects-settings": "Project Settings",
"showNodeLabelDefault": "Show label of newly added nodes", "showNodeLabelDefault": "Show label of newly added nodes",
"codeEditor": "Code Editor",
"groups": "Groups", "groups": "Groups",
"groupSelection": "Group selection", "groupSelection": "Group selection",
"ungroupSelection": "Ungroup selection", "ungroupSelection": "Ungroup selection",
"groupMergeSelection": "Merge selection", "groupMergeSelection": "Merge selection",
"groupRemoveSelection": "Remove from group", "groupRemoveSelection": "Remove from group"
"arrange": "Arrange",
"alignLeft": "Align to left",
"alignCenter": "Align to center",
"alignRight": "Align to right",
"alignTop": "Align to top",
"alignMiddle": "Align to middle",
"alignBottom": "Align to bottom",
"distributeHorizontally": "Distribute horizontally",
"distributeVertically": "Distribute vertically",
"moveToBack": "Move to back",
"moveToFront": "Move to front",
"moveBackwards": "Move backwards",
"moveForwards": "Move forwards"
} }
}, },
"actions": { "actions": {
"toggle-navigator": "Toggle navigator", "toggle-navigator": "Toggle navigator",
"zoom-out": "Zoom out", "zoom-out": "Zoom out",
"zoom-reset": "Reset zoom", "zoom-reset": "Reset zoom",
"zoom-in": "Zoom in", "zoom-in": "Zoom in"
"search-flows": "Search flows",
"search-prev": "Previous",
"search-next": "Next",
"search-counter": "\"__term__\" __result__ of __count__"
}, },
"user": { "user": {
"loggedInAs": "Logged in as __name__", "loggedInAs": "Logged in as __name__",
@ -187,17 +134,12 @@
} }
}, },
"notification": { "notification": {
"state": {
"flowsStopped": "Flows stopped",
"flowsStarted": "Flows started"
},
"warning": "<strong>Warning</strong>: __message__", "warning": "<strong>Warning</strong>: __message__",
"warnings": { "warnings": {
"undeployedChanges": "node has undeployed changes", "undeployedChanges": "node has undeployed changes",
"nodeActionDisabled": "node actions disabled", "nodeActionDisabled": "node actions disabled",
"nodeActionDisabledSubflow": "node actions disabled within subflow", "nodeActionDisabledSubflow": "node actions disabled within subflow",
"missing-types": "<p>Flows stopped due to missing node types.</p>", "missing-types": "<p>Flows stopped due to missing node types.</p>",
"missing-modules": "<p>Flows stopped due to missing modules.</p>",
"safe-mode":"<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>", "safe-mode":"<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>",
"restartRequired": "Node-RED must be restarted to enable upgraded modules", "restartRequired": "Node-RED must be restarted to enable upgraded modules",
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>", "credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
@ -239,8 +181,7 @@
"create-default-package": "Create default package file", "create-default-package": "Create default package file",
"no-thanks": "No thanks", "no-thanks": "No thanks",
"create-default-project": "Create default project files", "create-default-project": "Create default project files",
"show-merge-conflicts": "Show merge conflicts", "show-merge-conflicts": "Show merge conflicts"
"unknownNodesButton": "Search for unknown nodes"
} }
}, },
"clipboard": { "clipboard": {
@ -256,8 +197,6 @@
"flow_plural": "__count__ flows", "flow_plural": "__count__ flows",
"subflow": "__count__ subflow", "subflow": "__count__ subflow",
"subflow_plural": "__count__ subflows", "subflow_plural": "__count__ subflows",
"replacedNodes": "__count__ node replaced",
"replacedNodes_plural": "__count__ nodes replaced",
"pasteNodes": "Paste flow json or", "pasteNodes": "Paste flow json or",
"selectFile": "select a file to import", "selectFile": "select a file to import",
"importNodes": "Import nodes", "importNodes": "Import nodes",
@ -265,8 +204,6 @@
"download": "Download", "download": "Download",
"importUnrecognised": "Imported unrecognised type:", "importUnrecognised": "Imported unrecognised type:",
"importUnrecognised_plural": "Imported unrecognised types:", "importUnrecognised_plural": "Imported unrecognised types:",
"importDuplicate": "Imported duplicate node:",
"importDuplicate_plural": "Imported duplicate nodes:",
"nodesExported": "Nodes exported to clipboard", "nodesExported": "Nodes exported to clipboard",
"nodesImported": "Imported:", "nodesImported": "Imported:",
"nodeCopied": "__count__ node copied", "nodeCopied": "__count__ node copied",
@ -275,9 +212,6 @@
"groupCopied_plural": "__count__ groups copied", "groupCopied_plural": "__count__ groups copied",
"groupStyleCopied": "Group style copied", "groupStyleCopied": "Group style copied",
"invalidFlow": "Invalid flow: __message__", "invalidFlow": "Invalid flow: __message__",
"recoveredNodes": "Recovered Nodes",
"recoveredNodesInfo": "The nodes on this flow were missing a valid flow id when they were imported. They have been added to this flow so you can either restore or delete them.",
"recoveredNodesNotification": "<p>Imported nodes without a valid flow id</p><p>They have been added to a new flow called '__flowName__'.</p>",
"export": { "export": {
"selected":"selected nodes", "selected":"selected nodes",
"current":"current flow", "current":"current flow",
@ -292,20 +226,13 @@
}, },
"import": { "import": {
"import": "Import to", "import": "Import to",
"importSelected": "Import selected",
"importCopy": "Import copy",
"viewNodes": "View nodes...",
"newFlow": "new flow", "newFlow": "new flow",
"replace": "replace",
"errors": { "errors": {
"notArray": "Input not a JSON Array", "notArray": "Input not a JSON Array",
"itemNotObject": "Input not a valid flow - item __index__ not a node object", "itemNotObject": "Input not a valid flow - item __index__ not a node object",
"missingId": "Input not a valid flow - item __index__ missing 'id' property", "missingId": "Input not a valid flow - item __index__ missing 'id' property",
"missingType": "Input not a valid flow - item __index__ missing 'type' property" "missingType": "Input not a valid flow - item __index__ missing 'type' property"
}, }
"conflictNotification1": "Some of the nodes you are importing already exist in your workspace.",
"conflictNotification2": "Select which nodes to import and whether to replace the existing nodes, or to import a copy of them.",
"alreadyExists": "This node already exists"
}, },
"copyMessagePath": "Path copied", "copyMessagePath": "Path copied",
"copyMessageValue": "Value copied", "copyMessageValue": "Value copied",
@ -319,19 +246,13 @@
"modifiedFlowsDesc": "Only deploys flows that contain changed nodes", "modifiedFlowsDesc": "Only deploys flows that contain changed nodes",
"modifiedNodes": "Modified Nodes", "modifiedNodes": "Modified Nodes",
"modifiedNodesDesc": "Only deploys nodes that have changed", "modifiedNodesDesc": "Only deploys nodes that have changed",
"startFlows": "Start",
"startFlowsDesc": "Start Flows",
"stopFlows": "Stop",
"stopFlowsDesc": "Stop Flows",
"restartFlows": "Restart Flows", "restartFlows": "Restart Flows",
"restartFlowsDesc": "Restarts the current deployed flows", "restartFlowsDesc": "Restarts the current deployed flows",
"successfulDeploy": "Successfully deployed", "successfulDeploy": "Successfully deployed",
"successfulRestart": "Successfully restarted flows", "successfulRestart": "Successfully restarted flows",
"deployFailed": "Deploy failed: __message__", "deployFailed": "Deploy failed: __message__",
"unusedConfigNodes":"You have some unused configuration nodes.", "unusedConfigNodes":"You have some unused configuration nodes.",
"unusedConfigNodesButton": "Search unused config nodes", "unusedConfigNodesLink":"Click here to see them",
"unknownNodesButton": "Search for unknown nodes",
"invalidNodesButton": "Search for invalid nodes",
"errors": { "errors": {
"noResponse": "no response from server" "noResponse": "no response from server"
}, },
@ -373,12 +294,8 @@
"deleted": "deleted", "deleted": "deleted",
"flowDeleted": "flow deleted", "flowDeleted": "flow deleted",
"flowAdded": "flow added", "flowAdded": "flow added",
"moved": "moved",
"movedTo": "moved to __id__", "movedTo": "moved to __id__",
"movedFrom": "moved from __id__", "movedFrom": "moved from __id__"
"none": "none",
"position": "position",
"wires": "wires"
}, },
"nodeCount": "__count__ node", "nodeCount": "__count__ node",
"nodeCount_plural": "__count__ nodes", "nodeCount_plural": "__count__ nodes",
@ -387,14 +304,9 @@
"reviewChanges": "Review Changes", "reviewChanges": "Review Changes",
"noBinaryFileShowed": "Cannot show binary file contents", "noBinaryFileShowed": "Cannot show binary file contents",
"viewCommitDiff": "View Commit Changes", "viewCommitDiff": "View Commit Changes",
"commit": "Commit",
"compareChanges": "Compare Changes", "compareChanges": "Compare Changes",
"saveConflict": "Save conflict resolution", "saveConflict": "Save conflict resolution",
"conflictHeader": "<span>__resolved__</span> of <span>__unresolved__</span> conflicts resolved", "conflictHeader": "<span>__resolved__</span> of <span>__unresolved__</span> conflicts resolved",
"localChanges": "Local Changes",
"remoteChanges": "Remote Changes",
"useLocalChanges": "use local changes",
"useRemoteChanges": "use remote changes",
"commonVersionError": "Common Version doesn't contain valid JSON:", "commonVersionError": "Common Version doesn't contain valid JSON:",
"oldVersionError": "Old Version doesn't contain valid JSON:", "oldVersionError": "Old Version doesn't contain valid JSON:",
"newVersionError": "New Version doesn't contain valid JSON:" "newVersionError": "New Version doesn't contain valid JSON:"
@ -410,28 +322,14 @@
"output": "outputs:", "output": "outputs:",
"status": "status node", "status": "status node",
"deleteSubflow": "delete subflow", "deleteSubflow": "delete subflow",
"confirmDelete": "Are you sure you want to delete this subflow?",
"info": "Description", "info": "Description",
"category": "Category", "category": "Category",
"module": "Module",
"license": "License",
"licenseNone": "none",
"licenseOther": "Other",
"type": "Node Type",
"version": "Version",
"versionPlaceholder": "x.y.z",
"keys": "Keywords",
"keysPlaceholder": "Comma-separated keywords",
"author": "Author",
"authorPlaceholder": "Your Name <email@example.com>",
"desc": "Description",
"env": { "env": {
"restore": "Restore to subflow default", "restore": "Restore to subflow default",
"remove": "Remove environment variable" "remove": "Remove environment variable"
}, },
"errors": { "errors": {
"noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected", "noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected",
"acrossMultipleGroups": "Cannot create subflow across multiple groups",
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection" "multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
} }
}, },
@ -472,7 +370,6 @@
"icon": "Icon", "icon": "Icon",
"inputType": "Input type", "inputType": "Input type",
"selectType": "select types...", "selectType": "select types...",
"loadCredentials": "Loading node credentials",
"inputs" : { "inputs" : {
"input": "input", "input": "input",
"select": "select", "select": "select",
@ -507,8 +404,7 @@
}, },
"errors": { "errors": {
"scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it", "scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it",
"invalidProperties": "Invalid properties:", "invalidProperties": "Invalid properties:"
"credentialLoadFailed": "Failed to load node credentials"
} }
}, },
"keyboard": { "keyboard": {
@ -520,14 +416,11 @@
"unassigned": "Unassigned", "unassigned": "Unassigned",
"global": "global", "global": "global",
"workspace": "workspace", "workspace": "workspace",
"editor": "edit dialog", "selectAll": "Select all nodes",
"selectAll": "Select all", "selectAllConnected": "Select all connected nodes",
"selectNone": "Select none",
"selectAllConnected": "Select connected",
"addRemoveNode": "Add/remove node from selection", "addRemoveNode": "Add/remove node from selection",
"editSelected": "Edit selected node", "editSelected": "Edit selected node",
"deleteSelected": "Delete selection", "deleteSelected": "Delete selected nodes or link",
"deleteReconnect": "Delete and reconnect",
"importNode": "Import nodes", "importNode": "Import nodes",
"exportNode": "Export nodes", "exportNode": "Export nodes",
"nudgeNode": "Move selected nodes (1px)", "nudgeNode": "Move selected nodes (1px)",
@ -537,14 +430,10 @@
"copyNode": "Copy selected nodes", "copyNode": "Copy selected nodes",
"cutNode": "Cut selected nodes", "cutNode": "Cut selected nodes",
"pasteNode": "Paste nodes", "pasteNode": "Paste nodes",
"copyGroupStyle": "Copy group style", "undoChange": "Undo the last change performed",
"pasteGroupStyle": "Paste group style",
"undoChange": "Undo",
"redoChange": "Redo",
"searchBox": "Open search box", "searchBox": "Open search box",
"managePalette": "Manage palette", "managePalette": "Manage palette",
"actionList": "Action list", "actionList":"Action list"
"splitWireWithLinks": "Split selection with Link nodes"
}, },
"library": { "library": {
"library": "Library", "library": "Library",
@ -562,9 +451,7 @@
"types": { "types": {
"local": "Local", "local": "Local",
"examples": "Examples" "examples": "Examples"
}, }
"type": "Type",
"name": "Name"
}, },
"palette": { "palette": {
"noInfo": "no information available", "noInfo": "no information available",
@ -598,13 +485,11 @@
"nodeEnabled_plural": "Nodes enabled:", "nodeEnabled_plural": "Nodes enabled:",
"nodeDisabled": "Node disabled:", "nodeDisabled": "Node disabled:",
"nodeDisabled_plural": "Nodes disabled:", "nodeDisabled_plural": "Nodes disabled:",
"nodeUpgraded": "Node module __module__ upgraded to version __version__", "nodeUpgraded": "Node module __module__ upgraded to version __version__"
"unknownNodeRegistered": "Error loading node: <ul><li>__type__<br>__error__</li></ul>"
}, },
"editor": { "editor": {
"title": "Manage palette", "title": "Manage palette",
"palette": "Palette", "palette": "Palette",
"allCatalogs": "All Catalogs",
"times": { "times": {
"seconds": "seconds ago", "seconds": "seconds ago",
"minutes": "minutes ago", "minutes": "minutes ago",
@ -626,8 +511,6 @@
}, },
"nodeCount": "__label__ node", "nodeCount": "__label__ node",
"nodeCount_plural": "__label__ nodes", "nodeCount_plural": "__label__ nodes",
"pluginCount": "__count__ plugin",
"pluginCount_plural": "__count__ plugins",
"moduleCount": "__count__ module available", "moduleCount": "__count__ module available",
"moduleCount_plural": "__count__ modules available", "moduleCount_plural": "__count__ modules available",
"inuse": "in use", "inuse": "in use",
@ -646,16 +529,12 @@
"tab-nodes": "Nodes", "tab-nodes": "Nodes",
"tab-install": "Install", "tab-install": "Install",
"sort": "sort:", "sort": "sort:",
"sortRelevance": "relevance",
"sortAZ": "a-z", "sortAZ": "a-z",
"sortRecent": "recent", "sortRecent": "recent",
"more": "+ __count__ more", "more": "+ __count__ more",
"upload": "Upload module tgz file",
"refresh": "Refresh module list",
"errors": { "errors": {
"catalogLoadFailed": "<p>Failed to load node catalogue.</p><p>Check the browser console for more information</p>", "catalogLoadFailed": "<p>Failed to load node catalogue.</p><p>Check the browser console for more information</p>",
"installFailed": "<p>Failed to install: __module__</p><p>__message__</p><p>Check the log for more information</p>", "installFailed": "<p>Failed to install: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"installTimeout": "<p>Install continuing the background.</p><p>Nodes will appear in palette when complete. Check the log for more information.</p>",
"removeFailed": "<p>Failed to remove: __module__</p><p>__message__</p><p>Check the log for more information</p>", "removeFailed": "<p>Failed to remove: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"updateFailed": "<p>Failed to update: __module__</p><p>__message__</p><p>Check the log for more information</p>", "updateFailed": "<p>Failed to update: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"enableFailed": "<p>Failed to enable: __module__</p><p>__message__</p><p>Check the log for more information</p>", "enableFailed": "<p>Failed to enable: __module__</p><p>__message__</p><p>Check the log for more information</p>",
@ -670,9 +549,6 @@
"body":"<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>", "body":"<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>",
"title": "Remove nodes" "title": "Remove nodes"
}, },
"removePlugin": {
"body": "<p>Removed plugin __module__. Please reload the editor to clear left-overs.</p>"
},
"update": { "update": {
"body":"<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>", "body":"<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>",
"title": "Update nodes" "title": "Update nodes"
@ -684,8 +560,7 @@
"review": "Open node information", "review": "Open node information",
"install": "Install", "install": "Install",
"remove": "Remove", "remove": "Remove",
"update": "Update", "update": "Update"
"understood": "Understood"
} }
} }
} }
@ -726,10 +601,13 @@
"globalConfig": "Global Configuration Nodes", "globalConfig": "Global Configuration Nodes",
"triggerAction": "Trigger action", "triggerAction": "Trigger action",
"find": "Find in workspace", "find": "Find in workspace",
"copyItemUrl": "Copy item url", "search": {
"copyURL2Clipboard": "Copied url to clipboard", "configNodes": "Configuration nodes",
"showFlow": "Show", "unusedConfigNodes": "Unused configuration nodes",
"hideFlow": "Hide" "invalidNodes": "Invalid nodes",
"uknownNodes": "Unknown nodes",
"unusedSubflows": "Unused subflows"
}
}, },
"help": { "help": {
"name": "Help", "name": "Help",
@ -738,10 +616,8 @@
"nodeHelp": "Node Help", "nodeHelp": "Node Help",
"showHelp": "Show help", "showHelp": "Show help",
"showInOutline": "Show in outline", "showInOutline": "Show in outline",
"hideTopics": "Hide topics",
"showTopics": "Show topics", "showTopics": "Show topics",
"noHelp": "No help topic selected", "noHelp": "No help topic selected"
"changeLog": "Change Log"
}, },
"config": { "config": {
"name": "Configuration nodes", "name": "Configuration nodes",
@ -813,7 +689,6 @@
"branches": "Branches", "branches": "Branches",
"noBranches": "No branches", "noBranches": "No branches",
"deleteConfirm": "Are you sure you want to delete the local branch '__name__'? This cannot be undone.", "deleteConfirm": "Are you sure you want to delete the local branch '__name__'? This cannot be undone.",
"deleteBranch": "Delete branch",
"unmergedConfirm": "The local branch '__name__' has unmerged changes that will be lost. Are you sure you want to delete it?", "unmergedConfirm": "The local branch '__name__' has unmerged changes that will be lost. Are you sure you want to delete it?",
"deleteUnmergedBranch": "Delete unmerged branch", "deleteUnmergedBranch": "Delete unmerged branch",
"gitRemotes": "Git remotes", "gitRemotes": "Git remotes",
@ -833,12 +708,6 @@
"committerTip": "Leave blank to use system default", "committerTip": "Leave blank to use system default",
"userName": "Username", "userName": "Username",
"email": "Email", "email": "Email",
"workflow": "Workflow",
"workfowTip": "Choose your preferred git workflow",
"workflowManual": "Manual",
"workflowManualTip": "All changes must be manually committed under the 'history' sidebar",
"workflowAuto": "Automatic",
"workflowAutoTip": "Changes are committed automatically with every deploy",
"sshKeys": "SSH Keys", "sshKeys": "SSH Keys",
"sshKeysTip": "Allows you to create secure connections to remote git repositories.", "sshKeysTip": "Allows you to create secure connections to remote git repositories.",
"add": "add key", "add": "add key",
@ -935,8 +804,6 @@
} }
}, },
"typedInput": { "typedInput": {
"selected": "__count__ selected",
"selected_plural": "__count__ selected",
"type": { "type": {
"str": "string", "str": "string",
"num": "number", "num": "number",
@ -947,35 +814,15 @@
"date": "timestamp", "date": "timestamp",
"jsonata": "expression", "jsonata": "expression",
"env": "env variable", "env": "env variable",
"cred": "credential", "cred": "credential"
"conf-types": "config node"
},
"date": {
"format": {
"timestamp": "milliseconds since epoch",
"object": "JavaScript Date Object"
}
} }
}, },
"editableList": { "editableList": {
"add": "add", "add": "add"
"addTitle": "add an item"
}, },
"search": { "search": {
"history": "Search history",
"clear": "clear all",
"empty": "No matches found", "empty": "No matches found",
"addNode": "add a node...", "addNode": "add a node..."
"options": {
"configNodes": "Configuration nodes",
"unusedConfigNodes": "Unused configuration nodes",
"invalidNodes": "Invalid nodes",
"uknownNodes": "Unknown nodes",
"unusedSubflows": "Unused subflows",
"hiddenFlows": "Hidden flows",
"modifiedNodes": "Modified nodes and flows",
"thisFlow": "Current flow"
}
}, },
"expressionEditor": { "expressionEditor": {
"functions": "Functions", "functions": "Functions",
@ -993,15 +840,9 @@
"invalid-expr": "Invalid JSONata expression:\n __message__", "invalid-expr": "Invalid JSONata expression:\n __message__",
"invalid-msg": "Invalid example JSON message:\n __message__", "invalid-msg": "Invalid example JSON message:\n __message__",
"context-unsupported": "Cannot test context functions\n $flowContext or $globalContext", "context-unsupported": "Cannot test context functions\n $flowContext or $globalContext",
"env-unsupported": "Cannot test $env function",
"moment-unsupported": "Cannot test $moment function",
"clone-unsupported": "Cannot test $clone function",
"eval": "Error evaluating expression:\n __message__" "eval": "Error evaluating expression:\n __message__"
} }
}, },
"monaco": {
"setTheme": "Set theme"
},
"jsEditor": { "jsEditor": {
"title": "JavaScript editor" "title": "JavaScript editor"
}, },
@ -1013,8 +854,6 @@
"format": "format JSON", "format": "format JSON",
"rawMode": "Edit JSON", "rawMode": "Edit JSON",
"uiMode": "Visual editor", "uiMode": "Visual editor",
"rawMode-readonly": "JSON",
"uiMode-readonly": "Visual",
"insertAbove": "Insert above", "insertAbove": "Insert above",
"insertBelow": "Insert below", "insertBelow": "Insert below",
"addItem": "Add item", "addItem": "Add item",
@ -1041,10 +880,7 @@
"quote": "Quote", "quote": "Quote",
"link": "Link", "link": "Link",
"horizontal-rule": "Horizontal rule", "horizontal-rule": "Horizontal rule",
"toggle-preview": "Toggle preview", "toggle-preview": "Toggle preview"
"mermaid": {
"summary": "Mermaid Diagram"
}
}, },
"bufferEditor": { "bufferEditor": {
"title": "Buffer editor", "title": "Buffer editor",
@ -1179,8 +1015,7 @@
"not-git": "Not a git repository", "not-git": "Not a git repository",
"no-resource": "Repository not found", "no-resource": "Repository not found",
"cant-get-ssh-key-path": "Error! Can't get selected SSH key path.", "cant-get-ssh-key-path": "Error! Can't get selected SSH key path.",
"unexpected_error": "unexpected_error", "unexpected_error": "unexpected_error"
"clearContext": "Clear context when switching projects"
}, },
"delete": { "delete": {
"confirm": "Are you sure you want to delete this project?" "confirm": "Are you sure you want to delete this project?"
@ -1221,58 +1056,17 @@
"editor-tab": { "editor-tab": {
"properties": "Properties", "properties": "Properties",
"envProperties": "Environment Variables", "envProperties": "Environment Variables",
"module": "Module Properties",
"description": "Description", "description": "Description",
"appearance": "Appearance", "appearance": "Appearance",
"preview": "UI Preview", "preview": "UI Preview",
"defaultValue": "Default value" "defaultValue": "Default value"
}, },
"tourGuide": {
"takeATour": "Take a tour",
"start": "Start",
"next": "Next",
"welcomeTours": "Welcome Tours"
},
"diagnostics": {
"title": "System Info"
},
"languages" : { "languages" : {
"de": "Deutsch", "de": "German",
"en-US": "English", "en-US": "English",
"es-ES": "Español (España)", "ja": "Japanese",
"fr": "Français",
"ja": "日本語",
"ko": "Korean", "ko": "Korean",
"pt-BR": "Português (Brasil)", "zh-CN": "Chinese(Simplified)",
"ru": "Русский", "zh-TW": "Chinese(Traditional)"
"zh-CN": "简体中文",
"zh-TW": "繁體中文"
},
"validator": {
"errors": {
"invalid-json": "Invalid JSON data: __error__",
"invalid-expr": "Invalid JSONata expression: __error__",
"invalid-prop": "Invalid property expression",
"invalid-num": "Invalid number",
"invalid-num-prop": "__prop__: invalid number",
"invalid-regexp": "Invalid input pattern",
"invalid-regex-prop": "__prop__: invalid input pattern",
"missing-required-prop": "__prop__: property value missing",
"invalid-config": "__prop__: invalid configuration node",
"missing-config": "__prop__: missing configuration node",
"validation-error": "__prop__: validation error: __node__, __id__: __error__"
}
},
"contextMenu": {
"showActionList": "Show action list",
"insert": "Insert",
"node": "Node",
"junction": "Junction",
"linkNodes": "Link Nodes"
},
"env-var": {
"environment": "Environment",
"header": "Global Environment Variables",
"revert": "Revert"
} }
} }

View File

View File

@ -52,8 +52,8 @@
"desc": "Finds occurrences of `pattern` within `str` and replaces them with `replacement`.\n\nThe optional `limit` parameter is the maximum number of replacements." "desc": "Finds occurrences of `pattern` within `str` and replaces them with `replacement`.\n\nThe optional `limit` parameter is the maximum number of replacements."
}, },
"$now": { "$now": {
"args": "$[picture [, timezone]]", "args":"",
"desc": "Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional `picture` and `timezone` parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function" "desc":"Generates a timestamp in ISO 8601 compatible format and returns it as a string."
}, },
"$base64encode": { "$base64encode": {
"args":"string", "args":"string",
@ -137,7 +137,7 @@
}, },
"$sort": { "$sort": {
"args":"array [, function]", "args":"array [, function]",
"desc": "Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values `left` and `right`. If the value of `left` should be placed after the value of `right` in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`." "desc":"Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values left and right. If the value of left should be placed after the value of right in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
}, },
"$reverse": { "$reverse": {
"args":"array", "args":"array",
@ -200,12 +200,12 @@
"desc": "Returns a copy of the `string` with extra padding, if necessary, so that its total number of characters is at least the absolute value of the `width` parameter.\n\nIf `width` is a positive number, then the string is padded to the right; if negative, it is padded to the left.\n\nThe optional `char` argument specifies the padding character(s) to use. If not specified, it defaults to the space character." "desc": "Returns a copy of the `string` with extra padding, if necessary, so that its total number of characters is at least the absolute value of the `width` parameter.\n\nIf `width` is a positive number, then the string is padded to the right; if negative, it is padded to the left.\n\nThe optional `char` argument specifies the padding character(s) to use. If not specified, it defaults to the space character."
}, },
"$fromMillis": { "$fromMillis": {
"args": "number, [, picture [, timezone]]", "args": "number",
"desc": "Convert the `number` representing milliseconds since the Unix Epoch (1 January, 1970 UTC) to a formatted string representation of the timestamp as specified by the picture string.\n\nIf the optional `picture` parameter is omitted, then the timestamp is formatted in the ISO 8601 format.\n\nIf the optional `picture` string is supplied, then the timestamp is formatted according to the representation specified in that string. The behaviour of this function is consistent with the two-argument version of the XPath/XQuery function `format-dateTime` as defined in the XPath F&O 3.1 specification. The picture string parameter defines how the timestamp is formatted and has the same syntax as `format-dateTime`.\n\nIf the optional `timezone` string is supplied, then the formatted timestamp will be in that timezone. The `timezone` string should be in the format '±HHMM', where ± is either the plus or minus sign and HHMM is the offset in hours and minutes from UTC. Positive offset for timezones east of UTC, negative offset for timezones west of UTC." "desc": "Convert a number representing milliseconds since the Unix Epoch (1 January, 1970 UTC) to a timestamp string in the ISO 8601 format."
}, },
"$formatNumber": { "$formatNumber": {
"args": "number, picture [, options]", "args": "number, picture [, options]",
"desc": "Casts the `number` to a string and formats it to a decimal representation as specified by the `picture` string.\n\n The behaviour of this function is consistent with the XPath/XQuery function `fn:format-number` as defined in the XPath F&O 3.1 specification. The `picture` string parameter defines how the number is formatted and has the same syntax as `fn:format-number`.\n\nThe optional third argument `options` is used to override the default locale specific formatting characters such as the decimal separator. If supplied, this argument must be an object containing name/value pairs specified in the decimal format section of the XPath F&O 3.1 specification." "desc": "Casts the `number` to a string and formats it to a decimal representation as specified by the `picture` string.\n\n The behaviour of this function is consistent with the XPath/XQuery function fn:format-number as defined in the XPath F&O 3.1 specification. The picture string parameter defines how the number is formatted and has the same syntax as fn:format-number.\n\nThe optional third argument `options` is used to override the default locale specific formatting characters such as the decimal separator. If supplied, this argument must be an object containing name/value pairs specified in the decimal format section of the XPath F&O 3.1 specification."
}, },
"$formatBase": { "$formatBase": {
"args": "number [, radix]", "args": "number [, radix]",
@ -237,25 +237,25 @@
}, },
"$assert": { "$assert": {
"args": "arg, str", "args": "arg, str",
"desc": "If `arg` is `true` the function returns `undefined`. If `arg` is `false` an exception is thrown with `str` as the message of the exception." "desc": "If `arg` is true the function returns undefined. If `arg` is false an exception is thrown with `str` as the message of the exception."
}, },
"$single": { "$single": {
"args": "array, function", "args": "array, function",
"desc": "Returns the one and only value in the `array` parameter that satisfies the `function` predicate (i.e. the `function` returns Boolean `true` when passed the value). Throws an exception if the number of matching values is not exactly one.\n\nThe function should be supplied in the following signature: `function(value [, index [, array]])` where value is each input of the array, index is the position of that value and the whole array is passed as the third argument" "desc": "Returns the one and only value in the `array` parameter that satisfies the `function` predicate (i.e. the `function` returns Boolean `true` when passed the value). Throws an exception if the number of matching values is not exactly one.\n\nThe function should be supplied in the following signature: `function(value [, index [, array]])` where value is each input of the array, index is the position of that value and the whole array is passed as the third argument"
}, },
"$encodeUrlComponent": { "$encodeUrl": {
"args": "str", "args": "str",
"desc": "Encodes a Uniform Resource Locator (URL) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character.\n\nExample: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" "desc": "Encodes a Uniform Resource Locator (URL) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character.\n\nExample: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
}, },
"$encodeUrl": { "$encodeUrlComponent": {
"args": "str", "args": "str",
"desc": "Encodes a Uniform Resource Locator (URL) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character. \n\nExample: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" "desc": "Encodes a Uniform Resource Locator (URL) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character. \n\nExample: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
}, },
"$decodeUrlComponent": { "$decodeUrl": {
"args": "str", "args": "str",
"desc": "Decodes a Uniform Resource Locator (URL) component previously created by encodeUrlComponent. \n\nExample: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" "desc": "Decodes a Uniform Resource Locator (URL) component previously created by encodeUrlComponent. \n\nExample: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
}, },
"$decodeUrl": { "$decodeUrlComponent": {
"args": "str", "args": "str",
"desc": "Decodes a Uniform Resource Locator (URL) previously created by encodeUrl. \n\nExample: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" "desc": "Decodes a Uniform Resource Locator (URL) previously created by encodeUrl. \n\nExample: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
}, },
@ -270,9 +270,5 @@
"$moment": { "$moment": {
"args": "[str]", "args": "[str]",
"desc": "Gets a date object using the Moment library." "desc": "Gets a date object using the Moment library."
},
"$clone": {
"args": "value",
"desc": "Safely clone an object."
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +0,0 @@
{
"info": {
"tip0": "Puedes eliminar los nodos o enlaces seleccionados con {{core:delete-selection}}",
"tip1": "Busca nodos con {{core:search}}",
"tip2": "{{core:toggle-sidebar}} alternará la vista de esta barra lateral",
"tip3": "Puedes gestionar tu paleta de nodos con {{core:manage-palette}}",
"tip4": "Tus nodos de configuración de flujo aparecen en el panel de la barra lateral. Se puede acceder desde el menú o con {{core:show-config-tab}}",
"tip5": "Activa o desactiva estos consejos desde la opción en la configuración",
"tip6": "Mueve los nodos seleccionados usando las teclas [izquierda] [arriba] [abajo] y [derecha]. Mantén pulsada [Mayús] para desplazarlos más",
"tip7": "Arrastrar un nodo a un cable lo insertará en el enlace",
"tip8": "Exporta los nodos seleccionados, o la pestaña actual con {{core:show-export-dialog}}",
"tip9": "Importa un flujo arrastrando su JSON al editor, o con {{core:show-import-dialog}}",
"tip10": "[shift][clic] y arrastrar en un puerto de nodo para mover todos los cables conectados o sólo el seleccionado",
"tip11": "Mostrar la pestaña Información con {{core:show-info-tab}} o la pestaña Depuración con {{core:show-debug-tab}}",
"tip12": "[ctrl] [clic] en el área de trabajo para abrir el diálogo de adición rápida",
"tip13": "Mantén pulsada [ctrl] cuando [haces clic] en un puerto de nodo para habilitar el enlazado rápido",
"tip14": "Mantén pulsada [shift] cuando [haces clic] en un nodo para seleccionar también todos sus nodos conectados",
"tip15": "Mantén pulsada [ctrl] cuando [haces clic] en un nodo para añadirlo o eliminarlo de la selección actual",
"tip16": "Cambia de pestaña de flujo con {{core:show-previous-tab}} y {{core:show-next-tab}}",
"tip17": "Puedes confirmar tus cambios en la bandeja de edición de nodos con {{core:confirm-edit-tray}} o cancelarlos con {{core:cancel-edit-tray}}",
"tip18": "Al pulsar {{core:edit-selected-node}} se editará el primer nodo de la selección actual"
}
}

View File

@ -1,278 +0,0 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "Convierte el parámetro `arg` a una cadena usando las siguientes reglas de conversión:\n\n - Las cadenas no cambian\n - Las funciones se convierten en una cadena vacía\n - El infinito numérico y NaN arrojan un error porque no se pueden representar como un número JSON\n: todos los demás valores se convierten a una cadena JSON usando la función `JSON.stringify`. Si `prettify` es verdadero, entonces se produce JSON \"prettified\". es decir, una línea por campo y las líneas se indentarán según la profundidad del campo."
},
"$length": {
"args": "str",
"desc": "Devuelve el número de caracteres de la cadena `str`. Se genera un error si `str` no es una cadena."
},
"$substring": {
"args": "str, start[, length]",
"desc": "Devuelve una cadena que contiene los caracteres del primer parámetro `str` comenzando en la posición `start` (desplazamiento cero). Si se especifica 'longitud', la subcadena contendrá el máximo de caracteres de 'longitud'. Si 'inicio' es negativo, indica el número de caracteres desde el final de 'cadena'."
},
"$substringBefore": {
"args": "str, chars",
"desc": "Devuelve la subcadena antes de la primera aparición de la secuencia de caracteres `chars` en `str`. Si `str` no contiene `caracteres`, entonces devuelve `str`."
},
"$substringAfter": {
"args": "str, chars",
"desc": "Devuelve la subcadena después de la primera aparición de la secuencia de caracteres `chars` en `str`. Si `str` no contiene `caracteres`, entonces devuelve `str`."
},
"$uppercase": {
"args": "str",
"desc": "Devuelve una cadena con todos los caracteres de `str` convertidos a mayúsculas."
},
"$lowercase": {
"args": "str",
"desc": "Devuelve una cadena con todos los caracteres de `str` convertidos a minúsculas."
},
"$trim": {
"args": "str",
"desc": "Normaliza y recorta todos los caracteres de espacio en blanco en `str` aplicando los siguientes pasos:\n\n - Todas las tabulaciones, retornos de carro y avances de línea se reemplazan con espacios.\n- Las secuencias contiguas de espacios se reducen a un solo espacio.\n- Se eliminan los espacios iniciales y finales.\n\n Si no se especifica `str` (es decir, esta función se invoca sin argumentos), entonces el valor de contexto se utiliza como el valor de `str`. Se genera un error si `str` no es una cadena."
},
"$contains": {
"args": "str, pattern",
"desc": "Devuelve 'verdadero' si 'cadena' coincide con 'patrón', de lo contrario, devuelve 'falso'. Si no se especifica `str` (es decir, esta función se invoca con un argumento), entonces el valor del contexto se utiliza como valor de `str`. El parámetro `patrón` puede ser una cadena o una expresión regular."
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "Divide el parámetro `str` en una matriz de subcadenas. Es un error si `str` no es una cadena. El parámetro opcional `separador` especifica los caracteres dentro de la `cadena` sobre los cuales se debe dividir como una cadena o una expresión regular. Si no se especifica 'separador', se supone que la cadena está vacía y 'cadena' se dividirá en una matriz de caracteres individuales. Es un error si el 'separador' no es una cadena. El parámetro opcional 'límite' es un número que especifica el número máximo de subcadenas que se incluirán en la matriz resultante. Cualquier subcadena adicional se descarta. Si no se especifica `límite`, entonces `str` se divide completamente sin límite para el tamaño de la matriz resultante. Es un error si 'límite' no es un número positivo."
},
"$join": {
"args": "array[, separator]",
"desc": "Une una matriz de cadenas de componentes en una única cadena concatenada con cada cadena de componentes separada por el parámetro 'separador' opcional. Es un error si la 'matriz' de entrada contiene un elemento que no es una cadena. Si no se especifica 'separador', se supone que es una cadena vacía, es decir, que no hay 'separador' entre las cadenas componentes. Es un error si el 'separador' no es una cadena."
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "Aplica la cadena `str` a la expresión regular `pattern` y devuelve una matriz de objetos, cada objeto contiene información sobre cada aparición de una coincidencia dentro de `str`."
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "Encuentra apariciones de `patrón` dentro de `str` y las reemplaza con `reemplazo`.\n\nEl parámetro opcional `límite` es el número máximo de reemplazos."
},
"$now": {
"args": "$[picture [, timezone]]",
"desc": "Genera una marca de tiempo en formato compatible con ISO 8601 y la devuelve como una cadena. Si se proporcionan los parámetros opcionales `picture` y `zona horaria`, entonces la marca de tiempo actual se formatea como se describe en la función `$fromMillis()`"
},
"$base64encode": {
"args": "string",
"desc": "Convierte una cadena ASCII a una representación base 64. Cada carácter de la cadena se trata como un byte de datos binarios. Esto requiere que todos los caracteres de la cadena estén en el rango de 0x00 a 0xFF, que incluye todos los caracteres de las cadenas codificadas con URI. No se admiten caracteres Unicode fuera de ese rango."
},
"$base64decode": {
"args": "string",
"desc": "Convierte bytes codificados en base 64 en una cadena, utilizando una página de códigos Unicode UTF-8."
},
"$number": {
"args": "arg",
"desc": "Convierte el parámetro `arg` a un número usando las siguientes reglas de conversión:\n\n - Los números no cambian\n - Las cadenas que contienen una secuencia de caracteres que representan un número JSON legal se convierten a ese número\n - Todos los demás valores provocar que se arroje un error."
},
"$abs": {
"args": "number",
"desc": "Devuelve el valor absoluto del parámetro 'número'."
},
"$floor": {
"args": "number",
"desc": "Devuelve el valor de 'número' redondeado hacia abajo al entero más cercano que sea menor o igual a 'número'."
},
"$ceil": {
"args": "number",
"desc": "Devuelve el valor de 'número' redondeado al número entero más cercano que sea mayor o igual a 'número'."
},
"$round": {
"args": "number [, precision]",
"desc": "Devuelve el valor del parámetro 'número' redondeado al número de decimales especificado por el parámetro opcional 'precisión'."
},
"$power": {
"args": "base, exponent",
"desc": "Devuelve el valor de 'base' elevado a la potencia de 'exponente'."
},
"$sqrt": {
"args": "number",
"desc": "Devuelve la raíz cuadrada del valor del parámetro 'número'."
},
"$random": {
"args": "",
"desc": "Devuelve un número pseudoaleatorio mayor o igual a cero y menor que uno."
},
"$millis": {
"args": "",
"desc": "Devuelve el número de milisegundos desde la época Unix (1 de enero de 1970 UTC) como un número. Todas las invocaciones de `$millis()` dentro de una evaluación de una expresión devolverán el mismo valor."
},
"$sum": {
"args": "array",
"desc": "Devuelve la suma aritmética de una 'matriz' de números. Es un error si la 'matriz' de entrada contiene un elemento que no es un número."
},
"$max": {
"args": "array",
"desc": "Devuelve el número máximo en una 'matriz' de números. Es un error si la 'matriz' de entrada contiene un elemento que no es un número."
},
"$min": {
"args": "array",
"desc": "Devuelve el número mínimo en una 'matriz' de números. Es un error si la 'matriz' de entrada contiene un elemento que no es un número."
},
"$average": {
"args": "array",
"desc": "Devuelve el valor medio de una 'matriz' de números. Es un error si la 'matriz' de entrada contiene un elemento que no es un número."
},
"$boolean": {
"args": "arg",
"desc": "Convierte el argumento a un booleano usando las siguientes reglas:\n\n - `Booleano`: sin cambios\n - `cadena`: vacía: `falso`\n - `cadena`: no vacía: `verdadero`\n - `número`: `0`: `falso`\n - `número`: distinto de cero: `verdadero`\n - `nulo`: `falso`\n - `matriz`: vacía: `falso`\n - `array`: contiene un miembro que se convierte en `true`: `true`\n - `array`: todos los miembros se convierten en `false`: `false`\n - `object`: vacío: `false`\n - `objeto`: no vacío: `verdadero`\n - `función`: `falso`"
},
"$not": {
"args": "arg",
"desc": "Devuelve booleano NEGADO del argumento. `arg` se convierte antes en un booleano"
},
"$exists": {
"args": "arg",
"desc": "Devuelve booleano 'verdadero' si la expresión 'arg' se evalúa como un valor, o 'falso' si la expresión no coincide con nada (por ejemplo, una ruta a una referencia de campo inexistente)."
},
"$count": {
"args": "array",
"desc": "Devuelve el número de elementos de la matriz."
},
"$append": {
"args": "array, array",
"desc": "Agrega dos matrices"
},
"$sort": {
"args": "array [, function]",
"desc": "Devuelve una matriz que contiene todos los valores en el parámetro `array`, pero ordenados.\n\nSi se proporciona una `función` de comparador, entonces debe ser una función que toma dos parámetros:\n\n`function(left , derecha)`\n\nEsta función es invocada por el algoritmo de clasificación para comparar dos valores `izquierda` y `derecha`. Si el valor de `izquierda` debe colocarse después del valor de `derecha` en el orden de clasificación deseado, entonces la función debe devolver un valor booleano 'verdadero' para indicar un intercambio. De lo contrario debe devolver 'falso'."
},
"$reverse": {
"args": "array",
"desc": "Devuelve una matriz que contiene todos los valores del parámetro `matriz`, pero en orden inverso."
},
"$shuffle": {
"args": "array",
"desc": "Devuelve una matriz que contiene todos los valores del parámetro `array`, pero mezclados en orden aleatorio."
},
"$zip": {
"args": "array, ...",
"desc": "Devuelve una matriz convolucionada (comprimida) que contiene matrices agrupadas de valores de los argumentos `matriz1`... `matrizN` del índice 0, 1, 2...."
},
"$keys": {
"args": "object",
"desc": "Devuelve una matriz que contiene las claves del objeto. Si el argumento es una matriz de objetos, entonces la matriz devuelta contiene una lista deduplicada de todas las claves de todos los objetos."
},
"$lookup": {
"args": "object, key",
"desc": "Devuelve el valor asociado con la clave en el objeto. Si el primer argumento es una matriz de objetos, entonces se buscan todos los objetos de la matriz y se devuelven los valores asociados con todas las apariciones de la clave."
},
"$spread": {
"args": "object",
"desc": "Divide un objeto que contiene pares clave/valor en una matriz de objetos, cada uno de los cuales tiene un único par clave/valor del objeto de entrada. Si el parámetro es una matriz de objetos, entonces la matriz resultante contiene un objeto para cada par clave/valor en cada objeto de la matriz proporcionada."
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "Fusiona una matriz de objetos en un único objeto que contiene todos los pares clave/valor de cada uno de los objetos en la matriz de entrada. Si alguno de los objetos de entrada contiene la misma clave, entonces el objeto devuelto contendrá el valor del último en la matriz. Es un error si la matriz de entrada contiene un elemento que no es un objeto."
},
"$sift": {
"args": "object, function",
"desc": "Devuelve un objeto que contiene solo los pares clave/valor del parámetro `objeto` que satisfacen el predicado `función` pasado como segundo parámetro.\n\nLa `función` que se proporciona como segundo parámetro debe tener la siguiente firma:\n\n`función(valor [, clave [, objeto]])`"
},
"$each": {
"args": "object, function",
"desc": "Devuelve una matriz que contiene los valores devueltos por la función cuando se aplica a cada par clave/valor en el objeto."
},
"$map": {
"args": "array, function",
"desc": "Devuelve una matriz que contiene los resultados de aplicar el parámetro `función` a cada valor en el parámetro `matriz`.\n\nLa `función` que se proporciona como segundo parámetro debe tener la siguiente firma:\n\n`función( valor [, índice [, matriz]])`"
},
"$filter": {
"args": "array, function",
"desc": "Devuelve una matriz que contiene solo los valores en el parámetro `matriz` que satisfacen el predicado `función`.\n\nLa `función` que se proporciona como segundo parámetro debe tener la siguiente firma:\n\n`función(valor [ , índice [, matriz]])`"
},
"$reduce": {
"args": "array, function [, init]",
"desc": "Devuelve un valor agregado derivado de aplicar el parámetro `función` sucesivamente a cada valor en `matriz` en combinación con el resultado de la aplicación anterior de la función.\n\nLa función debe aceptar dos argumentos y se comporta como un operador infijo entre cada valor dentro de la matriz. La firma de la `función` debe tener la forma: `myfunc($accumulator, $value[, $index[, $array]])`\n\nEl parámetro opcional `init` se utiliza como valor inicial en la agregación."
},
"$flowContext": {
"args": "string[, string]",
"desc": "Recupera una propiedad de contexto de flujo.\n\nEsta es una función definida por Node-RED."
},
"$globalContext": {
"args": "string[, string]",
"desc": "Recupera una propiedad de contexto global.\n\nEsta es una función definida por Node-RED."
},
"$pad": {
"args": "string, width [, char]",
"desc": "Devuelve una copia de la `cadena` con relleno adicional, si es necesario, de modo que su número total de caracteres sea al menos el valor absoluto del parámetro `ancho`.\n\nSi `ancho` es un número positivo, entonces la cadena está acolchado hacia la derecha; si es negativo, se rellena hacia la izquierda.\n\nEl argumento opcional `char` especifica los caracteres de relleno que se utilizarán. Si no se especifica, el valor predeterminado es el carácter de espacio."
},
"$fromMillis": {
"args": "number, [, picture [, timezone]]",
"desc": "Convierte el `número` que representa milisegundos desde la época Unix (1 de enero de 1970 UTC) en una representación de cadena formateada según la plantilla en picture.\n\nSi se omite el parámetro opcional `picture`, entonces la marca de tiempo es formateado en el formato ISO 8601.\n\nSi se proporciona la cadena opcional `picture`, entonces la marca de tiempo se formatea de acuerdo con la representación especificada en esa cadena. El comportamiento de esta función es consistente con la versión de dos argumentos de la función XPath/XQuery `format-dateTime` tal como se define en la especificación XPath F&O 3.1. El parámetro de plantilla define cómo se formatea la marca de tiempo y tiene la misma sintaxis que `format-dateTime`.\n\nSi se proporciona la cadena opcional `timezone`, entonces la marca de tiempo formateada estará en esa zona horaria. La cadena `timezone` debe tener el formato '±HHMM', donde ± es el signo más o menos y HHMM es el desplazamiento en horas y minutos desde UTC. Desplazamiento positivo para zonas horarias al este de UTC, desplazamiento negativo para zonas horarias al oeste de UTC."
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "Convierte el `número` en una cadena y lo formatea en una representación decimal según lo especificado en la cadena `picture`.\n\n El comportamiento de esta función es coherente con la función XPath/XQuery `fn:format-number` tal como se define en la especificación XPath F&O 3.1. El parámetro de cadena `picture` define cómo se formatea el número y tiene la misma sintaxis que `fn:formato-número`.\n\nEl tercer argumento opcional `opciones` se utiliza para anular los caracteres de formato específicos de la configuración regional predeterminada, como el decimal. separador. Si se proporciona, este argumento debe ser un objeto que contenga pares de nombre/valor especificados en la sección de formato decimal de la especificación XPath F&O 3.1."
},
"$formatBase": {
"args": "number [, radix]",
"desc": "Convierte el número en una cadena y lo formatea como un número entero representado en la base numérica especificada por el argumento `radix`. Si no se especifica `radix`, el valor predeterminado es la base 10. `radix` puede estar entre 2 y 36; de lo contrario, se genera un error."
},
"$toMillis": {
"args": "timestamp",
"desc": "Convierte una cadena de `marca de tiempo` en el formato ISO 8601 al número de milisegundos desde la época Unix (1 de enero de 1970 UTC) como un número. Se genera un error si la cadena no tiene el formato correcto."
},
"$env": {
"args": "arg",
"desc": "Devuelve el valor de una variable de entorno.\n\nEsta es una función definida por Node-RED."
},
"$eval": {
"args": "expr [, context]",
"desc": "Analiza y evalúa la cadena `expr` que contiene JSON literal o una expresión JSONata utilizando el contexto actual como contexto para la evaluación."
},
"$formatInteger": {
"args": "number, picture",
"desc": "Convierte el número en una cadena y lo formatea en una representación entera como lo especifica la cadena `picture`. El parámetro de define cómo se formatea el número y tiene la misma sintaxis que `fn:format-integer` de la especificación XPath F&O 3.1."
},
"$parseInteger": {
"args": "string, picture",
"desc": "Analiza el contenido del parámetro cadena en un número entero (como un número JSON) utilizando el formato especificado por la cadena `picture`. El parámetro tiene el mismo formato que `$formatInteger`."
},
"$error": {
"args": "[str]",
"desc": "Lanza un error con un mensaje. El parámetro `str` opcional reemplazará el mensaje predeterminado de `$error() función evaluada`"
},
"$assert": {
"args": "arg, str",
"desc": "Si `arg` es `verdadero`, la función devuelve indefinido. Si `arg` es `falso`, se lanza una excepción con `str` como mensaje de excepción."
},
"$single": {
"args": "array, function",
"desc": "Devuelve el único valor en el parámetro `array` que satisface el predicado de `función` (es decir, la `función` devuelve booleano `verdadero` cuando se pasa el valor). Lanza una excepción si el número de valores coincidentes no es exactamente uno.\n\nLa función debe proporcionarse con la siguiente firma: `función(valor [, índice [, matriz]])` donde el valor es cada entrada de la matriz. El índice es la posición de ese valor y toda la matriz se pasa como tercer argumento."
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Codifica un componente de URL reemplazando cada instancia de ciertos caracteres por una, dos, tres o cuatro secuencias de escape que representan la codificación UTF-8 del carácter.\n\nEjemplo: `$encodeUrlComponent(\"?x=prueba\")` => `\"%3Fx%3Dprueba\"`"
},
"$encodeUrl": {
"args": "str",
"desc": "Codifica una URL reemplazando cada instancia de ciertos caracteres por una, dos, tres o cuatro secuencias de escape que representan la codificación UTF-8 del carácter.\n\nEjemplo: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "Decodifica un componente de URL creado previamente por encodeUrlComponent.\n\nEjemplo: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "Decodifica una URL creado previamente por encodeUrl.\n\nEjemplo: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "Devuelve una matriz con valores duplicados eliminados de `matriz`"
},
"$type": {
"args": "value",
"desc": "Devuelve el tipo de `valor` como una cadena. Si `valor` no está definido, esto devolverá indefinido."
},
"$moment": {
"args": "[str]",
"desc": "Obtiene un objeto de fecha usando la biblioteca Moment."
},
"$clone": {
"args": "value",
"desc": "Clona un objeto de forma segura."
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
{
"info": {
"tip0": "Vous pouvez supprimer les noeuds ou les liens sélectionnés avec {{core:delete-selection}}",
"tip1": "Rechercher des noeuds à l'aide de {{core:search}}",
"tip2": "{{core:toggle-sidebar}} basculera l'affichage de cette barre latérale",
"tip3": "Vous pouvez gérer votre palette de noeuds avec {{core:manage-palette}}",
"tip4": "Vos noeuds de configuration de flux sont répertoriés dans le panneau de la barre latérale. Ils sont accessibles depuis le menu ou avec {{core:show-config-tab}}",
"tip5": "Activer ou désactiver ces conseils à partir de l'option dans les paramètres",
"tip6": "Déplacer les noeuds sélectionnés à l'aide des touches [gauche] [haut] [bas] et [droite]. Maintenir la touche [shift] enfoncée pour les pousser plus loin",
"tip7": "Faire glisser un noeud sur un fil le raccordera au lien",
"tip8": "Exporter les noeuds sélectionnés, ou l'onglet actuel avec {{core:show-export-dialog}}",
"tip9": "Importer un flux en faisant glisser son JSON dans l'éditeur, ou avec {{core:show-import-dialog}}",
"tip10": "[majuscule] [clic] et faites glisser sur un port de noeud pour déplacer tous les fils attachés ou seulement celui sélectionné",
"tip11": "Afficher l'onglet Infos avec {{core:show-info-tab}} ou l'onglet Débogage avec {{core:show-debug-tab}}",
"tip12": "[ctrl] [clic] dans l'espace de travail pour ouvrir la boîte de dialogue d'ajout rapide",
"tip13": "Maintenir la touche [ctrl] enfoncée lorsque vous [cliquez] sur un port de noeud pour activer le câblage rapide",
"tip14": "Maintenir la touche [shift] enfoncée lorsque vous [cliquez] sur un noeud pour sélectionner également tous ses noeuds connectés",
"tip15": "Maintenir la touche [ctrl] enfoncée lorsque vous [cliquez] sur un noeud pour l'ajouter ou le supprimer de la sélection actuelle",
"tip16": "Changer d'onglet de flux avec {{core:show-previous-tab}} et {{core:show-next-tab}}",
"tip17": "Vous pouvez confirmer vos modifications dans le panneau d'édition du noeud avec {{core:confirm-edit-tray}} ou les annuler avec {{core:cancel-edit-tray}}",
"tip18": "Appuyer sur {{core:edit-selected-node}} modifiera le premier noeud de la sélection actuelle"
}
}

View File

@ -1,278 +0,0 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "Convertit le paramètre `arg` en une chaîne de caractères en utilisant les règles de typage suivantes :\n\n - Les chaînes de caractères sont inchangées\n - Les fonctions sont converties en une chaîne vide\n - L'infini numérique et NaN renvoient une erreur car ils ne peuvent pas être représentés comme un Numéro JSON\n - Toutes les autres valeurs sont converties en une chaîne JSON à l'aide de la fonction `JSON.stringify`. Si `prettify` est vrai, alors le JSON \"prettified\" est produit. c'est-à-dire une ligne par champ et les lignes seront en retrait en fonction de la profondeur du champ."
},
"$length": {
"args": "str",
"desc": "Renvoie le nombre de caractères dans la chaîne `str`. Une erreur est renvoyée si `str` n'est pas une chaîne de caractères."
},
"$substring": {
"args": "str, start[, length]",
"desc": "Renvoie une chaîne contenant les caractères du premier paramètre `str` commençant à la position `start` (pas de décalage). Si `length` est spécifié, alors la sous-chaîne contiendra un maximum de caractères `length`. Si `start` est négatif alors il indique le nombre de caractères à partir de la fin de `str`."
},
"$substringBefore": {
"args": "str, chars",
"desc": "Renvoie la sous-chaîne avant la première occurrence de la séquence de caractères `chars` dans `str`. Si `str` ne contient pas `chars`, alors il renvoie `str`."
},
"$substringAfter": {
"args": "str, chars",
"desc": "Renvoie la sous-chaîne après la première occurrence de la séquence de caractères `chars` dans `str`. Si `str` ne contient pas `chars`, alors il renvoie `str`."
},
"$uppercase": {
"args": "str",
"desc": "Renvoie une chaîne avec tous les caractères de `str` convertis en majuscules."
},
"$lowercase": {
"args": "str",
"desc": "Renvoie une chaîne avec tous les caractères de `str` convertis en minuscules."
},
"$trim": {
"args": "str",
"desc": "Normalise et supprime tous les caractères d'espacement dans `str` en appliquant les étapes suivantes :\n\n - Toutes les tabulations, retours à la ligne et sauts de ligne sont remplacés par des espaces.\n- Les séquences contiguës d'espaces sont réduites à un seul espace.\n- Les espaces de fin et de début sont supprimés.\n\n Si `str` n'est pas spécifié (c'est-à-dire que cette fonction est invoquée sans argument), alors la valeur de contexte est utilisée comme valeur de `str`. Une erreur est renvoyée si `str` n'est pas une chaîne."
},
"$contains": {
"args": "str, pattern",
"desc": "Renvoie `true` si `str` correspond à `pattern`, sinon il renvoie `false`. Si `str` n'est pas spécifié (c'est-à-dire que cette fonction est invoquée avec un argument), alors la valeur de contexte est utilisée comme valeur de `str`. Le paramètre `pattern` peut être une chaîne ou une expression régulière."
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "Divise le paramètre `str` en un tableau de sous-chaînes. C'est une erreur si `str` n'est pas une chaîne. Le paramètre facultatif `separator` spécifie les caractères à l'intérieur de `str` à propos desquels il doit être divisé en chaîne ou en expression régulière. Si `separator` n'est pas spécifié, la chaîne vide est supposée et `str` sera divisé en un tableau de caractères uniques. C'est une erreur si `separator` n'est pas une chaîne. Le paramètre facultatif `limit` est un nombre qui spécifie le nombre maximum de sous-chaînes à inclure dans le tableau résultant. Toutes les sous-chaînes supplémentaires sont ignorées. Si `limit` n'est pas spécifié, alors `str` est entièrement divisé sans limite à la taille du tableau résultant. C'est une erreur si `limit` n'est pas un nombre non négatif."
},
"$join": {
"args": "array[, separator]",
"desc": "Joint un tableau de chaînes de composants en une seule chaîne concaténée, chaque chaîne de composants étant séparée par le paramètre facultatif `separator`. C'est une erreur si l'entrée `array` contient un élément qui n'est pas une chaîne. Si `séparateur` n'est pas spécifié, il est supposé être la chaîne vide, c'est-à-dire qu'il n'y a pas de `séparateur` entre les chaînes de composants. C'est une erreur si `separator` n'est pas une chaîne."
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "Applique la chaîne `str` à l'expression régulière `pattern` et renvoie un tableau d'objets, chaque objet contenant des informations sur chaque occurrence d'une correspondance dans `str`."
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "Trouve les occurrences de `pattern` dans `str` et les remplace par `replacement`.\n\nLe paramètre facultatif `limit` est le nombre maximum de remplacements."
},
"$now": {
"args": "$[picture [, timezone]]",
"desc": "Génère un horodatage au format compatible ISO 8601 et le renvoie sous forme de chaîne. Si les paramètres optionnels d'image et de fuseau horaire sont fournis, alors l'horodatage actuel est formaté comme décrit par la fonction `$fromMillis()`"
},
"$base64encode": {
"args": "string",
"desc": "Convertit une chaîne ASCII en une représentation en base 64. Chaque caractère de la chaîne est traité comme un octet de données binaires. Cela nécessite que tous les caractères de la chaîne se trouvent dans la plage 0x00 à 0xFF, qui inclut tous les caractères des chaînes encodées en URI. Les caractères Unicode en dehors de cette plage ne sont pas pris en charge."
},
"$base64decode": {
"args": "string",
"desc": "Convertit les octets encodés en base 64 en une chaîne, à l'aide d'une page de codes Unicode UTF-8."
},
"$number": {
"args": "arg",
"desc": "Convertit le paramètre `arg` en un nombre en utilisant les règles de conversion suivantes :\n\n - Les nombres sont inchangés\n - Les chaînes qui contiennent une séquence de caractères représentant un nombre JSON légal sont converties en ce nombre\n - Toutes les autres valeurs provoquer l'envoi d'une erreur."
},
"$abs": {
"args": "number",
"desc": "Renvoie la valeur absolue du paramètre `nombre`."
},
"$floor": {
"args": "number",
"desc": "Renvoie la valeur de `number` arrondie à l'entier le plus proche inférieur ou égal à `number`."
},
"$ceil": {
"args": "number",
"desc": "Renvoie la valeur de `number` arrondie à l'entier le plus proche supérieur ou égal à `number`."
},
"$round": {
"args": "number [, precision]",
"desc": "Renvoie la valeur du paramètre `number` arrondie au nombre de décimales spécifié par le paramètre facultatif `precision`."
},
"$power": {
"args": "base, exponent",
"desc": "Renvoie la valeur de `base` élevée à la puissance de `exponent`."
},
"$sqrt": {
"args": "number",
"desc": "Renvoie la racine carrée de la valeur du paramètre `number`."
},
"$random": {
"args": "",
"desc": "Renvoie un nombre pseudo-aléatoire supérieur ou égal à zéro et inférieur à un."
},
"$millis": {
"args": "",
"desc": "Renvoie le nombre de millisecondes depuis l'époque Unix (1er janvier 1970 UTC) sous forme de nombre. Tous les appels de `$millis()` dans une évaluation d'une expression renverront toutes la même valeur."
},
"$sum": {
"args": "array",
"desc": "Renvoie la somme arithmétique d'un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre."
},
"$max": {
"args": "array",
"desc": "Renvoie le nombre maximal dans un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre."
},
"$min": {
"args": "array",
"desc": "Renvoie le nombre minimum dans un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre."
},
"$average": {
"args": "array",
"desc": "Renvoie la valeur moyenne d'un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre."
},
"$boolean": {
"args": "arg",
"desc": "Transforme l'argument en booléen en utilisant les règles suivantes :\n\n - `Boolean` : inchangé\n - `string` : vide : `false`\n - `string` : non vide : `true`\n - `number` : `0` : `false`\n - `number` : non nul : `true`\n - `null` : `false`\n - `array` : vide : `false`\n - `array` : contient un membre qui convertit en `true` : `true`\n - `array` : tous les membres sont transformés en `false` : `false`\n - `object` : vide : `false`\n - `object` : non vide : `true`\n - `function` : `false`"
},
"$not": {
"args": "arg",
"desc": "Renvoie un booléen résultat de la négation logique de l'argument"
},
"$exists": {
"args": "arg",
"desc": "Renvoie la valeur booléenne `true` si l'expression `arg` est évaluée à une valeur, ou `false` si l'expression ne correspond à rien (par exemple, un chemin vers une référence de champ inexistante)."
},
"$count": {
"args": "array",
"desc": "Renvoie le nombre d'éléments du tableau"
},
"$append": {
"args": "array, array",
"desc": "Combine deux tableaux"
},
"$sort": {
"args": "array [, function]",
"desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais triées dans l'ordre.\n\nSi un comparateur `function` est fourni, alors il doit s'agir d'une fonction qui prend deux paramètres :\n\n`function(left , droite)`\n\nCette fonction est invoquée par l'algorithme de tri pour comparer deux valeurs à gauche et à droite. Si la valeur de `left` doit être placée après la valeur de `right` dans l'ordre de tri souhaité, la fonction doit renvoyer un booléen `true` pour indiquer un échange. Sinon, il doit renvoyer `false`."
},
"$reverse": {
"args": "array",
"desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais dans l'ordre inverse."
},
"$shuffle": {
"args": "array",
"desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais mélangées dans un ordre aléatoire."
},
"$zip": {
"args": "array, ...",
"desc": "Renvoie un tableau convolué (zippé) contenant des tableaux groupés de valeurs des arguments `array1`...`arrayN` d'index 0, 1, 2...."
},
"$keys": {
"args": "object",
"desc": "Renvoie un tableau contenant les clés de l'objet. Si l'argument est un tableau d'objets, le tableau renvoyé contient une liste dédupliquée de toutes les clés de tous les objets."
},
"$lookup": {
"args": "object, key",
"desc": "Renvoie la valeur associée à la clé dans l'objet. Si le premier argument est un tableau d'objets, tous les objets du tableau sont recherchés et les valeurs associées à toutes les occurrences de key sont renvoyées."
},
"$spread": {
"args": "object",
"desc": "Divise un objet contenant des paires clé/valeur en un tableau d'objets, chacun ayant une seule paire clé/valeur de l'objet d'entrée. Si le paramètre est un tableau d'objets, alors le tableau résultant contient un objet pour chaque paire clé/valeur dans chaque objet du tableau fourni."
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "Fusionne un tableau d'`objets` en un seul `objet` contenant toutes les paires clé/valeur de chacun des objets du tableau d'entrée. Si l'un des objets d'entrée contient la même clé, alors l'`objet` renvoyé contiendra la valeur du dernier dans le tableau. C'est une erreur si le tableau d'entrée contient un élément qui n'est pas un objet."
},
"$sift": {
"args": "object, function",
"desc": "Renvoie un objet qui contient uniquement les paires clé/valeur du paramètre `object` qui satisfont le prédicat `function` transmis comme second paramètre.\n\nLa `function` qui est fournie comme second paramètre doit avoir la signature suivante :\n\n`fonction(valeur [, clé [, objet]])`"
},
"$each": {
"args": "object, function",
"desc": "Renvoie un tableau contenant les valeurs renvoyées par la `fonction` lorsqu'elle est appliquée à chaque paire clé/valeur dans l'`objet`."
},
"$map": {
"args": "array, function",
"desc": "Renvoie un tableau contenant les résultats de l'application du paramètre `function` à chaque valeur du paramètre `array`.\n\nLa `function` fournie comme second paramètre doit avoir la signature suivante :\n\n`function( valeur [, indice [, tableau]])`"
},
"$filter": {
"args": "array, function",
"desc": "Renvoie un tableau contenant uniquement les valeurs du paramètre `array` qui satisfont le prédicat `function`.\n\nLa `function` fournie comme second paramètre doit avoir la signature suivante :\n\n`function(value [ , indice [, tableau]])`"
},
"$reduce": {
"args": "array, function [, init]",
"desc": "Renvoie une valeur agrégée dérivée de l'application successive du paramètre `function` à chaque valeur de `array` en combinaison avec le résultat de l'application précédente de la fonction.\n\nLa fonction doit accepter deux arguments et se comporte comme un opérateur infixe entre chaque valeur dans le `tableau`. La signature de `function` doit être de la forme : `myfunc($accumulator, $value[, $index[, $array]])`\n\nLe paramètre facultatif `init` est utilisé comme valeur initiale dans l'agrégation ."
},
"$flowContext": {
"args": "string[, string]",
"desc": "Récupère une propriété de contexte de flux.\n\nCeci est une fonction définie par Node-RED."
},
"$globalContext": {
"args": "string[, string]",
"desc": "Récupère une propriété de contexte globale.\n\nCeci est une fonction définie par Node-RED."
},
"$pad": {
"args": "string, width [, char]",
"desc": "Renvoie une copie de la `chaîne` avec un rembourrage supplémentaire, si nécessaire, de sorte que son nombre total de caractères corresponde au moins à la valeur absolue du paramètre `width`.\n\nSi `width` est un nombre positif, alors la chaîne est rembourré à droite; s'il est négatif, il est rempli vers la gauche.\n\nL'argument optionnel `char` spécifie le(s) caractère(s) de remplissage à utiliser. S'il n'est pas spécifié, la valeur par défaut est le caractère espace."
},
"$fromMillis": {
"args": "number, [, picture [, timezone]]",
"desc": "Convertisser le « nombre » représentant les millisecondes depuis l'époque Unix (1er janvier 1970 UTC) en une représentation sous forme de chaîne formatée de l'horodatage tel que spécifié par la chaîne d'image.\n\nSi le paramètre facultatif « image » est omis, l'horodatage est formaté au format ISO 8601.\n\nSi la chaîne facultative `image` est fournie, l'horodatage est formaté selon la représentation spécifiée dans cette chaîne. Le comportement de cette fonction est cohérent avec la version à deux arguments de la fonction XPath/XQuery `format-dateTime` telle que définie dans la spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont l'horodatage est formaté et a la même syntaxe que `format-dateTime`.\n\nSi la chaîne facultative `timezone` est fournie, alors l'horodatage formaté sera dans ce fuseau horaire. La chaîne `timezone` doit être au format '±HHMM', où ± est le signe plus ou moins et HHMM est le décalage en heures et minutes par rapport à UTC. Décalage positif pour les fuseaux horaires à l'est de UTC, décalage négatif pour les fuseaux horaires à l'ouest de UTC."
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "Convertit le `number` en une chaîne et le formate en une représentation décimale comme spécifié par la chaîne `picture`.\n\n Le comportement de cette fonction est cohérent avec la fonction XPath/XQuery `fn:format-number` telle que définie dans le Spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que `fn:format-number`.\n\nLe troisième argument facultatif `options` est utilisé pour remplacer les caractères de formatage spécifiques aux paramètres régionaux par défaut, tels que le séparateur décimal. S'il est fourni, cet argument doit être un objet contenant des paires nom/valeur spécifiées dans la section de format décimal de la spécification XPath F&O 3.1."
},
"$formatBase": {
"args": "number [, radix]",
"desc": "Convertit le `number` en une chaîne et le formate en un entier représenté dans la base numérique spécifiée par l'argument `radix`. Si `radix` n'est pas spécifié, la valeur par défaut est la base 10. `radix` peut être compris entre 2 et 36, sinon une erreur est renvoyée."
},
"$toMillis": {
"args": "timestamp",
"desc": "Convertit une chaîne `timestamp` au format ISO 8601 en nombre de millisecondes depuis l'époque Unix (1er janvier 1970 UTC) sous forme de nombre. Une erreur est renvoyée si la chaîne n'est pas au format correct."
},
"$env": {
"args": "arg",
"desc": "Renvoie la valeur d'une variable d'environnement.\n\nCeci est une fonction définie par Node-RED."
},
"$eval": {
"args": "expr [, context]",
"desc": "Analyse et évalue la chaîne `expr` qui contient un JSON littéral ou une expression JSONata en utilisant le contexte actuel comme contexte d'évaluation."
},
"$formatInteger": {
"args": "number, picture",
"desc": "Transforme le `nombre` en une chaîne et le formate en une représentation entière comme spécifié par la chaîne `image`. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que `fn:format-integer` de la spécification XPath F&O 3.1."
},
"$parseInteger": {
"args": "string, picture",
"desc": "Analyse le contenu du paramètre `string` en un entier (comme un nombre JSON) en utilisant le format spécifié par la chaîne `picture`. Le paramètre de chaîne `picture` a le même format que `$formatInteger`."
},
"$error": {
"args": "[str]",
"desc": "Génère une erreur avec un message. Le `str` facultatif remplacera le message par défaut de la fonction `$error() évaluée`"
},
"$assert": {
"args": "arg, str",
"desc": "Si `arg` est vrai, la fonction renvoie undefined. Si `arg` est faux, une exception est lancée avec `str` comme message de l'exception."
},
"$single": {
"args": "array, function",
"desc": "Renvoie la seule et unique valeur du paramètre `array` qui satisfait le prédicat `function` (c'est-à-dire que la `function` renvoie la valeur booléenne `true` lorsqu'elle est transmise à la valeur). Lève une exception si le nombre de valeurs correspondantes n'est pas exactement un.\n\nLa fonction doit être fournie dans la signature suivante : `function(value [, index [, array]])` où value est chaque entrée du tableau, index est la position de cette valeur et le tableau entier est passé comme troisième argument"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Encode un composant URL (Uniform Resource Locator) en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant l'encodage UTF-8 du caractère.\n\nExemple : `$encodeUrlComponent(\"?x =test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrl": {
"args": "str",
"desc": "Encode une URL (Uniform Resource Locator) en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant l'encodage UTF-8 du caractère.\n\nExemple : `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0% B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "Décode un composant URL (Uniform Resource Locator) précédemment créé par encodeUrlComponent.\n\nExemple : `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "Décode une URL (Uniform Resource Locator) précédemment créée par encodeUrl.\n\nExemple : `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "Renvoie un tableau avec les valeurs en double supprimées de `array`"
},
"$type": {
"args": "value",
"desc": "Renvoie le type de `value` sous forme de chaîne. Si `value` n'est pas défini, cela renverra `undefined`"
},
"$moment": {
"args": "[str]",
"desc": "Obtient un objet de date à l'aide de la bibliothèque Moment."
},
"$clone": {
"args": "valeur",
"desc": "Cloner un objet en toute sécurité."
}
}

View File

@ -22,13 +22,7 @@
"color": "色", "color": "色",
"position": "配置", "position": "配置",
"enable": "有効", "enable": "有効",
"disable": "無効", "disable": "無効"
"upload": "アップロード",
"lock": "固定",
"unlock": "固定を解除",
"locked": "固定済み",
"unlocked": "固定なし",
"format": "形式"
}, },
"type": { "type": {
"string": "文字列", "string": "文字列",
@ -43,14 +37,11 @@
} }
}, },
"event": { "event": {
"loadPlugins": "プラグインを読み込み中",
"loadPalette": "パレットを読み込み中", "loadPalette": "パレットを読み込み中",
"loadNodeCatalogs": "ノードカタログを読み込み中", "loadNodeCatalogs": "ノードカタログを読み込み中",
"loadNodes": "ノードを読み込み中 __count__", "loadNodes": "ノードを読み込み中 __count__",
"loadFlows": "フローを読み込み中", "loadFlows": "フローを読み込み中",
"importFlows": "ワークスペースにフローを追加中", "importFlows": "ワークスペースにフローを追加中"
"importError": "<p>フロー追加エラー</p><p>__message__</p>",
"loadingProject": "プロジェクトを読み込み中"
}, },
"workspace": { "workspace": {
"defaultName": "フロー __number__", "defaultName": "フロー __number__",
@ -58,38 +49,19 @@
"confirmDelete": "削除の確認", "confirmDelete": "削除の確認",
"delete": "本当に '__label__' を削除しますか?", "delete": "本当に '__label__' を削除しますか?",
"dropFlowHere": "ここにフローをドロップしてください", "dropFlowHere": "ここにフローをドロップしてください",
"dropImageHere": "ここに画像ファイルをドロップしてください",
"addFlow": "フローの追加", "addFlow": "フローの追加",
"addFlowToRight": "右側にフローを追加",
"closeFlow": "フローを閉じる",
"hideFlow": "フローを非表示",
"hideOtherFlows": "他のフローを非表示",
"showAllFlows": "全てのフローを表示",
"hideAllFlows": "全てのフローを非表示",
"hiddenFlows": "__count__ 個の非表示のフロー一覧",
"hiddenFlows_plural": "__count__ 個の非表示のフロー一覧",
"showLastHiddenFlow": "最後に非表示にしたフローを表示",
"listFlows": "フロー一覧", "listFlows": "フロー一覧",
"listSubflows": "サブフロー一覧",
"status": "状態", "status": "状態",
"enabled": "有効", "enabled": "有効",
"disabled": "無効", "disabled": "無効",
"info": "詳細", "info": "詳細",
"selectNodes": "ノードをクリックして選択", "selectNodes": "ノードをクリックして選択"
"enableFlow": "フローを有効化",
"disableFlow": "フローを無効化",
"lockFlow": "フローを固定",
"unlockFlow": "フローの固定を解除",
"moveToStart": "フローを先頭へ移動",
"moveToEnd": "フローを最後へ移動"
}, },
"menu": { "menu": {
"label": { "label": {
"view": { "view": {
"view": "表示", "view": "表示",
"grid": "グリッド", "grid": "グリッド",
"storeZoom": "読み込み時に拡大/縮小のレベルを復元",
"storePosition": "読み込み時にスクロール位置を復元",
"showGrid": "グリッドを表示", "showGrid": "グリッドを表示",
"snapGrid": "ノードの配置を補助", "snapGrid": "ノードの配置を補助",
"gridSize": "グリッドの大きさ", "gridSize": "グリッドの大きさ",
@ -107,14 +79,12 @@
"palette": { "palette": {
"show": "パレットを表示" "show": "パレットを表示"
}, },
"edit": "編集",
"settings": "設定", "settings": "設定",
"userSettings": "ユーザ設定", "userSettings": "ユーザ設定",
"nodes": "ノード", "nodes": "ノード",
"displayStatus": "ノードのステータスを表示", "displayStatus": "ノードのステータスを表示",
"displayConfig": "設定ノード", "displayConfig": "ノードの設定",
"import": "読み込み", "import": "読み込み",
"importExample": "フロー例を読み込み",
"export": "書き出し", "export": "書き出し",
"search": "ノードを検索", "search": "ノードを検索",
"searchInput": "ノードを検索", "searchInput": "ノードを検索",
@ -123,6 +93,7 @@
"selectionToSubflow": "選択部分をサブフロー化", "selectionToSubflow": "選択部分をサブフロー化",
"flows": "フロー", "flows": "フロー",
"add": "フローを新規追加", "add": "フローを新規追加",
"rename": "フロー名を変更",
"delete": "フローを削除", "delete": "フローを削除",
"keyboardShortcuts": "ショートカットキーの説明", "keyboardShortcuts": "ショートカットキーの説明",
"login": "ログイン", "login": "ログイン",
@ -130,48 +101,24 @@
"editPalette": "パレットの管理", "editPalette": "パレットの管理",
"other": "その他", "other": "その他",
"showTips": "ヒントを表示", "showTips": "ヒントを表示",
"showNodeHelp": "ノードのヘルプを表示",
"enableSelectedNodes": "選択したノードを有効化",
"disableSelectedNodes": "選択したノードを無効化",
"showSelectedNodeLabels": "選択したノードのラベル表示",
"hideSelectedNodeLabels": "選択したノードのラベル非表示",
"showWelcomeTours": "新バージョンのガイドツアーを表示",
"help": "Node-REDウェブサイト", "help": "Node-REDウェブサイト",
"projects": "プロジェクト", "projects": "プロジェクト",
"projects-new": "新規", "projects-new": "新規",
"projects-open": "開く", "projects-open": "開く",
"projects-settings": "設定", "projects-settings": "設定",
"showNodeLabelDefault": "追加したノードのラベルを表示", "showNodeLabelDefault": "追加したノードのラベルを表示",
"codeEditor": "コードエディタ",
"groups": "グループ", "groups": "グループ",
"groupSelection": "選択部分をグループ化", "groupSelection": "選択部分をグループ化",
"ungroupSelection": "選択部分をグループ解除", "ungroupSelection": "選択部分をグループ解除",
"groupMergeSelection": "選択部分をマージ", "groupMergeSelection": "選択部分をマージ",
"groupRemoveSelection": "グループから削除", "groupRemoveSelection": "グループから削除"
"arrange": "配置",
"alignLeft": "左揃え",
"alignCenter": "左右中央揃え",
"alignRight": "右揃え",
"alignTop": "上揃え",
"alignMiddle": "上下中央揃え",
"alignBottom": "下揃え",
"distributeHorizontally": "左右に整列",
"distributeVertically": "上下に整列",
"moveToBack": "最背面へ移動",
"moveToFront": "最前面へ移動",
"moveBackwards": "背面へ移動",
"moveForwards": "前面へ移動"
} }
}, },
"actions": { "actions": {
"toggle-navigator": "ナビゲータの表示/非表示を切替", "toggle-navigator": "ナビゲータの表示/非表示を切替",
"zoom-out": "縮小", "zoom-out": "縮小",
"zoom-reset": "拡大/縮小を初期化", "zoom-reset": "拡大/縮小を初期化",
"zoom-in": "拡大", "zoom-in": "拡大"
"search-flows": "フローを検索",
"search-prev": "前へ",
"search-next": "次へ",
"search-counter": "\"__term__\" __count__ 件中の __result__ 件目"
}, },
"user": { "user": {
"loggedInAs": "__name__ としてログインしました", "loggedInAs": "__name__ としてログインしました",
@ -187,17 +134,12 @@
} }
}, },
"notification": { "notification": {
"state": {
"flowsStopped": "フローを停止しました",
"flowsStarted": "フローを開始しました"
},
"warning": "<strong>警告</strong>: __message__", "warning": "<strong>警告</strong>: __message__",
"warnings": { "warnings": {
"undeployedChanges": "ノードの変更をデプロイしていません", "undeployedChanges": "ノードの変更をデプロイしていません",
"nodeActionDisabled": "ノードのアクションは無効になっています", "nodeActionDisabled": "ノードのアクションは無効になっています",
"nodeActionDisabledSubflow": "ノードのアクションは、サブフロー内で無効になっています", "nodeActionDisabledSubflow": "ノードのアクションは、サブフロー内で無効になっています",
"missing-types": "<p>不明なノードが存在するため、フローを停止しました。</p>", "missing-types": "<p>不明なノードが存在するため、フローを停止しました。</p>",
"missing-modules": "<p>不明なモジュールが存在するため、フローを停止しました。</p>",
"safe-mode": "<p>セーフモードでフローを停止しました</p><p>フローを変更し、再起動するために変更をデプロイできます</p>", "safe-mode": "<p>セーフモードでフローを停止しました</p><p>フローを変更し、再起動するために変更をデプロイできます</p>",
"restartRequired": "更新されたモジュールを有効化するため、Node-REDを再起動する必要があります", "restartRequired": "更新されたモジュールを有効化するため、Node-REDを再起動する必要があります",
"credentials_load_failed": "<p>認証情報を復号できないため、フローを停止しました</p><p>フローの認証情報ファイルは暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です</p>", "credentials_load_failed": "<p>認証情報を復号できないため、フローを停止しました</p><p>フローの認証情報ファイルは暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です</p>",
@ -239,8 +181,7 @@
"create-default-package": "デフォルトパッケージファイルの作成", "create-default-package": "デフォルトパッケージファイルの作成",
"no-thanks": "不要", "no-thanks": "不要",
"create-default-project": "デフォルトプロジェクトファイルの作成", "create-default-project": "デフォルトプロジェクトファイルの作成",
"show-merge-conflicts": "マージ競合を表示", "show-merge-conflicts": "マージ競合を表示"
"unknownNodesButton": "不明なノードを検索する"
} }
}, },
"clipboard": { "clipboard": {
@ -256,17 +197,13 @@
"flow_plural": "__count__ 個のフロー", "flow_plural": "__count__ 個のフロー",
"subflow": "__count__ 個のサブフロー", "subflow": "__count__ 個のサブフロー",
"subflow_plural": "__count__ 個のサブフロー", "subflow_plural": "__count__ 個のサブフロー",
"replacedNodes": "置換された __count__ 個のノード", "pasteNodes": "JSON形式のフローデータを貼り付けてください",
"replacedNodes_plural": "置換された __count__ 個のノード", "selectFile": "読み込むファイルを選択してください",
"pasteNodes": "JSON形式のフローデータを貼り付け", "importNodes": "フローをクリップボートから読み込み",
"selectFile": "読み込むファイルを選択", "exportNodes": "フローをクリップボードへ書き出し",
"importNodes": "フローを読み込み",
"exportNodes": "フローを書き出し",
"download": "ダウンロード", "download": "ダウンロード",
"importUnrecognised": "認識できない型が読み込まれました:", "importUnrecognised": "認識できない型が読み込まれました:",
"importUnrecognised_plural": "認識できない型が読み込まれました:", "importUnrecognised_plural": "認識できない型が読み込まれました:",
"importDuplicate": "重複したノードを読み込みました:",
"importDuplicate_plural": "重複したノードを読み込みました:",
"nodesExported": "クリップボードへフローを書き出しました", "nodesExported": "クリップボードへフローを書き出しました",
"nodesImported": "読み込みました:", "nodesImported": "読み込みました:",
"nodeCopied": "__count__ 個のノードをコピーしました", "nodeCopied": "__count__ 個のノードをコピーしました",
@ -275,15 +212,12 @@
"groupCopied_plural": "__count__ 個のグループをコピーしました", "groupCopied_plural": "__count__ 個のグループをコピーしました",
"groupStyleCopied": "グループの形式をコピーしました", "groupStyleCopied": "グループの形式をコピーしました",
"invalidFlow": "不正なフロー: __message__", "invalidFlow": "不正なフロー: __message__",
"recoveredNodes": "復旧したノード",
"recoveredNodesInfo": "このフロー内のードは読み込み時に、有効なフローIDがありませんでした。これらフローIDは、フローに追加されているため、復元または削除できます。",
"recoveredNodesNotification": "<p>有効なフローIDを持たないードが読み込まれました</p><p>これらノードは '__flowName__' という新しいフローへ追加されました。</p>",
"export": { "export": {
"selected": "選択したフロー", "selected": "選択したフロー",
"current": "現在のタブ", "current": "現在のタブ",
"all": "全てのタブ", "all": "全てのタブ",
"compact": "インデントなし", "compact": "インデントのないJSONフォーマット",
"formatted": "インデント付き", "formatted": "インデント付きのJSONフォーマット",
"copy": "書き出し", "copy": "書き出し",
"export": "ライブラリに書き出し", "export": "ライブラリに書き出し",
"exportAs": "書き出し先", "exportAs": "書き出し先",
@ -292,20 +226,13 @@
}, },
"import": { "import": {
"import": "読み込み先", "import": "読み込み先",
"importSelected": "選択したノードを読み込み",
"importCopy": "コピーを読み込み",
"viewNodes": "ノードを参照...",
"newFlow": "新規のタブ", "newFlow": "新規のタブ",
"replace": "置換",
"errors": { "errors": {
"notArray": "JSON形式の配列ではありません", "notArray": "JSON形式の配列ではありません",
"itemNotObject": "不正なフロー - __index__ 番目の要素はノードオブジェクトではありません", "itemNotObject": "不正なフロー - __index__ 番目の要素はノードオブジェクトではありません",
"missingId": "不正なフロー - __index__ 番目の要素に'id'プロパティがありません", "missingId": "不正なフロー - __index__ 番目の要素に'id'プロパティがありません",
"missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません" "missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません"
}, }
"conflictNotification1": "読み込もうとしているノードのいくつかは、既にワークスペース内に存在しています。",
"conflictNotification2": "読み込むノードを選択し、また既存のノードを置き換えるか、もしくはそれらのコピーを読み込むかも選択してください。",
"alreadyExists": "本ノードは既に存在"
}, },
"copyMessagePath": "パスをコピーしました", "copyMessagePath": "パスをコピーしました",
"copyMessageValue": "値をコピーしました", "copyMessageValue": "値をコピーしました",
@ -319,19 +246,13 @@
"modifiedFlowsDesc": "変更したノードを含むフローのみデプロイ", "modifiedFlowsDesc": "変更したノードを含むフローのみデプロイ",
"modifiedNodes": "変更したノード", "modifiedNodes": "変更したノード",
"modifiedNodesDesc": "変更したノードのみデプロイ", "modifiedNodesDesc": "変更したノードのみデプロイ",
"startFlows": "開始",
"startFlowsDesc": "フローを開始",
"stopFlows": "停止",
"stopFlowsDesc": "フローを停止",
"restartFlows": "フローを再起動", "restartFlows": "フローを再起動",
"restartFlowsDesc": "デプロイされた現在のフローを再起動", "restartFlowsDesc": "デプロイされた現在のフローを再起動",
"successfulDeploy": "デプロイが成功しました", "successfulDeploy": "デプロイが成功しました",
"successfulRestart": "フローの再起動が成功しました", "successfulRestart": "フローの再起動が成功しました",
"deployFailed": "デプロイが失敗しました: __message__", "deployFailed": "デプロイが失敗しました: __message__",
"unusedConfigNodes": "使われていない設定ノードがあります。", "unusedConfigNodes": "使われていない「ノードの設定」があります。",
"unusedConfigNodesButton": "未使用の構成ノードを検索", "unusedConfigNodesLink": "設定を参照する",
"unknownNodesButton": "不明なノードを検索する",
"invalidNodesButton": "無効なノードを検索する",
"errors": { "errors": {
"noResponse": "サーバの応答がありません" "noResponse": "サーバの応答がありません"
}, },
@ -373,12 +294,8 @@
"deleted": "削除", "deleted": "削除",
"flowDeleted": "削除されたフロー", "flowDeleted": "削除されたフロー",
"flowAdded": "追加されたフロー", "flowAdded": "追加されたフロー",
"moved": "移動",
"movedTo": "__id__ へ移動", "movedTo": "__id__ へ移動",
"movedFrom": "__id__ から移動", "movedFrom": "__id__ から移動"
"none": "なし",
"position": "位置",
"wires": "ワイヤー"
}, },
"nodeCount": "__count__ 個のノード", "nodeCount": "__count__ 個のノード",
"nodeCount_plural": "__count__ 個のノード", "nodeCount_plural": "__count__ 個のノード",
@ -387,14 +304,9 @@
"reviewChanges": "変更を表示", "reviewChanges": "変更を表示",
"noBinaryFileShowed": "バイナリファイルの中身は表示することができません", "noBinaryFileShowed": "バイナリファイルの中身は表示することができません",
"viewCommitDiff": "コミットの内容を表示", "viewCommitDiff": "コミットの内容を表示",
"commit": "コミット",
"compareChanges": "変更を比較", "compareChanges": "変更を比較",
"saveConflict": "解決して保存", "saveConflict": "解決して保存",
"conflictHeader": "<span>__unresolved__</span> 個中 <span>__resolved__</span> 個のコンフリクトを解決", "conflictHeader": "<span>__unresolved__</span> 個中 <span>__resolved__</span> 個のコンフリクトを解決",
"localChanges": "ローカルの変更",
"remoteChanges": "リモートの変更",
"useLocalChanges": "ローカルの変更を使用",
"useRemoteChanges": "リモートの変更を使用",
"commonVersionError": "共通バージョンは正しいJSON形式ではありません:", "commonVersionError": "共通バージョンは正しいJSON形式ではありません:",
"oldVersionError": "古いバージョンは正しいJSON形式ではありません:", "oldVersionError": "古いバージョンは正しいJSON形式ではありません:",
"newVersionError": "新しいバージョンは正しいJSON形式ではありません:" "newVersionError": "新しいバージョンは正しいJSON形式ではありません:"
@ -410,28 +322,14 @@
"output": "出力:", "output": "出力:",
"status": "ステータスノード", "status": "ステータスノード",
"deleteSubflow": "サブフローを削除", "deleteSubflow": "サブフローを削除",
"confirmDelete": "このサブフローを削除しても良いですか?",
"info": "詳細", "info": "詳細",
"category": "カテゴリ", "category": "カテゴリ",
"module": "モジュール",
"license": "ライセンス",
"licenseNone": "なし",
"licenseOther": "その他",
"type": "ノードの型",
"version": "バージョン",
"versionPlaceholder": "x.y.z",
"keys": "キーワード",
"keysPlaceholder": "カンマ区切りのキーワード",
"author": "作者",
"authorPlaceholder": "名前 <email@example.com>",
"desc": "説明",
"env": { "env": {
"restore": "デフォルト値に戻す", "restore": "デフォルト値に戻す",
"remove": "環境変数を削除" "remove": "環境変数を削除"
}, },
"errors": { "errors": {
"noNodesSelected": "<strong>サブフローを作成できません</strong>: ノードが選択されていません", "noNodesSelected": "<strong>サブフローを作成できません</strong>: ノードが選択されていません",
"acrossMultipleGroups": "複数のグループをまたがるサブフローは作成できません",
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています" "multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"
} }
}, },
@ -449,9 +347,9 @@
"configDelete": "削除", "configDelete": "削除",
"nodesUse": "__count__ 個のノードが、この設定を使用しています", "nodesUse": "__count__ 個のノードが、この設定を使用しています",
"nodesUse_plural": "__count__ 個のノードが、この設定を使用しています", "nodesUse_plural": "__count__ 個のノードが、この設定を使用しています",
"addNewConfig": "新規に __type__ 設定ノードを追加", "addNewConfig": "新規に __type__ ノードの設定を追加",
"editNode": "__type__ ノードを編集", "editNode": "__type__ ノードを編集",
"editConfig": "__type__ 設定ノードを編集", "editConfig": "__type__ ノードの設定を編集",
"addNewType": "新規に __type__ を追加...", "addNewType": "新規に __type__ を追加...",
"nodeProperties": "プロパティ", "nodeProperties": "プロパティ",
"label": "ラベル", "label": "ラベル",
@ -472,7 +370,6 @@
"icon": "記号", "icon": "記号",
"inputType": "入力形式", "inputType": "入力形式",
"selectType": "形式選択...", "selectType": "形式選択...",
"loadCredentials": "ノードの認証情報を読み込み中",
"inputs": { "inputs": {
"input": "入力", "input": "入力",
"select": "メニュー", "select": "メニュー",
@ -507,8 +404,7 @@
}, },
"errors": { "errors": {
"scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします", "scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします",
"invalidProperties": "プロパティが不正です:", "invalidProperties": "プロパティが不正です:"
"credentialLoadFailed": "ノードの認証情報の読み込みに失敗"
} }
}, },
"keyboard": { "keyboard": {
@ -520,31 +416,24 @@
"unassigned": "未割当", "unassigned": "未割当",
"global": "グローバル", "global": "グローバル",
"workspace": "ワークスペース", "workspace": "ワークスペース",
"editor": "編集ダイアログ",
"selectAll": "全てのノードを選択", "selectAll": "全てのノードを選択",
"selectNone": "選択を外す", "selectAllConnected": "接続された全てのノードを選択",
"selectAllConnected": "接続されたノードを選択",
"addRemoveNode": "ノードの選択、選択解除", "addRemoveNode": "ノードの選択、選択解除",
"editSelected": "選択したノードを編集", "editSelected": "選択したノードを編集",
"deleteSelected": "選択部分を削除", "deleteSelected": "選択したノードや接続を削除",
"deleteReconnect": "削除と再接続",
"importNode": "フローの読み込み", "importNode": "フローの読み込み",
"exportNode": "フローの書き出し", "exportNode": "フローの書き出し",
"nudgeNode": "選択したノードを移動(移動量小)", "nudgeNode": "選択したノードを移動(移動量小)",
"moveNode": "選択したノードを移動(移動量大)", "moveNode": "選択したノードを移動(移動量大)",
"toggleSidebar": "サイドバーの表示/非表示", "toggleSidebar": "サイドバーの表示/非表示",
"togglePalette": "パレットの表示/非表示", "togglePalette": "パレットの表示/非表示",
"copyNode": "ノードをコピー", "copyNode": "選択したノードをコピー",
"cutNode": "ノードを切り取り", "cutNode": "選択したノードを切り取り",
"pasteNode": "ノードを貼り付け", "pasteNode": "ノードを貼り付け",
"copyGroupStyle": "グループ様式をコピー",
"pasteGroupStyle": "グループ様式を貼り付け",
"undoChange": "変更操作を戻す", "undoChange": "変更操作を戻す",
"redoChange": "変更操作をやり直し",
"searchBox": "ノードを検索", "searchBox": "ノードを検索",
"managePalette": "パレットの管理", "managePalette": "パレットの管理",
"actionList": "動作一覧", "actionList": "動作一覧"
"splitWireWithLinks": "選択したワイヤーをlinkードで分離"
}, },
"library": { "library": {
"library": "ライブラリ", "library": "ライブラリ",
@ -562,9 +451,7 @@
"types": { "types": {
"local": "ローカル", "local": "ローカル",
"examples": "サンプル" "examples": "サンプル"
}, }
"type": "型",
"name": "名前"
}, },
"palette": { "palette": {
"noInfo": "情報がありません", "noInfo": "情報がありません",
@ -598,16 +485,14 @@
"nodeEnabled_plural": "ノードを有効化しました:", "nodeEnabled_plural": "ノードを有効化しました:",
"nodeDisabled": "ノードを無効化しました:", "nodeDisabled": "ノードを無効化しました:",
"nodeDisabled_plural": "ノードを無効化しました:", "nodeDisabled_plural": "ノードを無効化しました:",
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました", "nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました"
"unknownNodeRegistered": "ノードの読み込みエラー: <ul><li>__type__<br>__error__</li></ul>"
}, },
"editor": { "editor": {
"title": "パレットの管理", "title": "パレットの管理",
"palette": "パレット", "palette": "パレット",
"allCatalogs": "全カタログ",
"times": { "times": {
"seconds": "秒前", "seconds": "秒前",
"minutes": "分前", "minutes": "分前",
"minutesV": "__count__ 分前", "minutesV": "__count__ 分前",
"hoursV": "__count__ 時間前", "hoursV": "__count__ 時間前",
"hoursV_plural": "__count__ 時間前", "hoursV_plural": "__count__ 時間前",
@ -626,8 +511,6 @@
}, },
"nodeCount": "__label__ 個のノード", "nodeCount": "__label__ 個のノード",
"nodeCount_plural": "__label__ 個のノード", "nodeCount_plural": "__label__ 個のノード",
"pluginCount": "__count__ 個のプラグイン",
"pluginCount_plural": "__count__ 個のプラグイン",
"moduleCount": "__count__ 個のモジュール", "moduleCount": "__count__ 個のモジュール",
"moduleCount_plural": "__count__ 個のモジュール", "moduleCount_plural": "__count__ 個のモジュール",
"inuse": "使用中", "inuse": "使用中",
@ -646,16 +529,12 @@
"tab-nodes": "現在のノード", "tab-nodes": "現在のノード",
"tab-install": "ノードを追加", "tab-install": "ノードを追加",
"sort": "並べ替え:", "sort": "並べ替え:",
"sortRelevance": "関連順",
"sortAZ": "辞書順", "sortAZ": "辞書順",
"sortRecent": "日付順", "sortRecent": "日付順",
"more": "+ さらに __count__ 個", "more": "+ さらに __count__ 個",
"upload": "モジュールのtgzファイルをアップロード",
"refresh": "モジュールリスト更新",
"errors": { "errors": {
"catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>", "catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>",
"installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", "installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
"installTimeout": "<p>バックグラウンドでインストールが継続されます。</p><p>完了した時にノードが表示されます。詳細はログを確認してください。</p>",
"removeFailed": "<p>削除処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", "removeFailed": "<p>削除処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
"updateFailed": "<p>更新処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", "updateFailed": "<p>更新処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
"enableFailed": "<p>有効化処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>", "enableFailed": "<p>有効化処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
@ -670,9 +549,6 @@
"body": "<p>__module__ を削除します。</p><p>Node-REDからードを削除します。ードはNode-REDが再起動されるまで、リソースを使い続ける可能性があります。</p>", "body": "<p>__module__ を削除します。</p><p>Node-REDからードを削除します。ードはNode-REDが再起動されるまで、リソースを使い続ける可能性があります。</p>",
"title": "ノードを削除" "title": "ノードを削除"
}, },
"removePlugin": {
"body": "<p>プラグイン __module__ を削除しました。ブラウザを再読み込みして残った表示を消してください。</p>"
},
"update": { "update": {
"body": "<p>__module__ を更新します。</p><p>更新を完了するには手動でNode-REDを再起動する必要があります。</p>", "body": "<p>__module__ を更新します。</p><p>更新を完了するには手動でNode-REDを再起動する必要があります。</p>",
"title": "ノードの更新" "title": "ノードの更新"
@ -684,8 +560,7 @@
"review": "ノードの情報を参照", "review": "ノードの情報を参照",
"install": "追加", "install": "追加",
"remove": "削除", "remove": "削除",
"update": "更新", "update": "更新"
"understood": "了解"
} }
} }
} }
@ -726,10 +601,13 @@
"globalConfig": "グローバル設定ノード", "globalConfig": "グローバル設定ノード",
"triggerAction": "アクションを実行", "triggerAction": "アクションを実行",
"find": "ワークスペース内を検索", "find": "ワークスペース内を検索",
"copyItemUrl": "要素のURLをコピー", "search": {
"copyURL2Clipboard": "URLをクリップボードにコピーしました", "configNodes": "設定ノード",
"showFlow": "表示", "unusedConfigNodes": "未使用の設定ノード",
"hideFlow": "非表示" "invalidNodes": "不正なノード",
"uknownNodes": "未知のノード",
"unusedSubflows": "未使用のサブフロー"
}
}, },
"help": { "help": {
"name": "ヘルプ", "name": "ヘルプ",
@ -738,14 +616,12 @@
"nodeHelp": "ノードヘルプ", "nodeHelp": "ノードヘルプ",
"showHelp": "ヘルプを表示", "showHelp": "ヘルプを表示",
"showInOutline": "アウトラインに表示", "showInOutline": "アウトラインに表示",
"hideTopics": "トピックを非表示",
"showTopics": "トピックを表示", "showTopics": "トピックを表示",
"noHelp": "ヘルプのトピックが未選択", "noHelp": "ヘルプのトピックが未選択"
"changeLog": "更新履歴"
}, },
"config": { "config": {
"name": "設定ノードを表示", "name": "ノードの設定を表示",
"label": "設定ノード", "label": "ノードの設定",
"global": "全てのフロー上", "global": "全てのフロー上",
"none": "なし", "none": "なし",
"subflows": "サブフロー", "subflows": "サブフロー",
@ -813,7 +689,6 @@
"branches": "ブランチ", "branches": "ブランチ",
"noBranches": "ブランチなし", "noBranches": "ブランチなし",
"deleteConfirm": "本当にローカルブランチ'__name__'を削除しますか?削除すると元に戻すことはできません。", "deleteConfirm": "本当にローカルブランチ'__name__'を削除しますか?削除すると元に戻すことはできません。",
"deleteBranch": "ブランチを削除",
"unmergedConfirm": "ローカルブランチ'__name__'にはマージされていない変更があります。この変更は削除されます。本当に削除しますか?", "unmergedConfirm": "ローカルブランチ'__name__'にはマージされていない変更があります。この変更は削除されます。本当に削除しますか?",
"deleteUnmergedBranch": "マージされていないブランチを削除", "deleteUnmergedBranch": "マージされていないブランチを削除",
"gitRemotes": "Gitリモート", "gitRemotes": "Gitリモート",
@ -833,12 +708,6 @@
"committerTip": "システムのデフォルトを使用する場合、空白のままにしてください", "committerTip": "システムのデフォルトを使用する場合、空白のままにしてください",
"userName": "ユーザ名", "userName": "ユーザ名",
"email": "メールアドレス", "email": "メールアドレス",
"workflow": "ワークフロー",
"workfowTip": "望ましいgitワークフローを選択してください",
"workflowManual": "手動",
"workflowManualTip": "全ての変更は「履歴」サイドバー内で手動でコミットする必要があります",
"workflowAuto": "自動",
"workflowAutoTip": "変更はデプロイの度に自動的にコミットされます",
"sshKeys": "SSH キー", "sshKeys": "SSH キー",
"sshKeysTip": "gitリポジトリへのセキュアな接続を作成できます。", "sshKeysTip": "gitリポジトリへのセキュアな接続を作成できます。",
"add": "キーを追加", "add": "キーを追加",
@ -902,7 +771,7 @@
"pushFailed": "リモートに新しいコミットがあるため、プッシュに失敗しました。プルしてマージしてから、再度プッシュしてください。", "pushFailed": "リモートに新しいコミットがあるため、プッシュに失敗しました。プルしてマージしてから、再度プッシュしてください。",
"push": "プッシュ", "push": "プッシュ",
"pull": "プル", "pull": "プル",
"unablePull": "<p>リモートの変更のプル失敗:ステージングされていないローカルの変更上書きされてしまいます。</p><p>変更をコミットしてから再度実行してください。</p>", "unablePull": "<p>リモートの変更のプル失敗:ステージングされていないローカルの変更上書きされてしまいます。</p><p>変更をコミットしてから再度実行してください。</p>",
"showUnstagedChanges": "ステージングされていない変更を表示", "showUnstagedChanges": "ステージングされていない変更を表示",
"connectionFailed": "リモートリポジトリに接続できません: ", "connectionFailed": "リモートリポジトリに接続できません: ",
"pullUnrelatedHistory": "<p>リモートに関連のないコミット履歴があります。</p><p>本当に変更をプルしてローカルリポジトリに反映しますか?</p>", "pullUnrelatedHistory": "<p>リモートに関連のないコミット履歴があります。</p><p>本当に変更をプルしてローカルリポジトリに反映しますか?</p>",
@ -935,8 +804,6 @@
} }
}, },
"typedInput": { "typedInput": {
"selected": "__count__個を選択",
"selected_plural": "__count__個を選択",
"type": { "type": {
"str": "文字列", "str": "文字列",
"num": "数値", "num": "数値",
@ -947,35 +814,15 @@
"date": "日時", "date": "日時",
"jsonata": "JSONata式", "jsonata": "JSONata式",
"env": "環境変数", "env": "環境変数",
"cred": "認証情報", "cred": "認証情報"
"conf-types": "設定ノード"
},
"date": {
"format": {
"timestamp": "エポックからの経過ミリ秒",
"object": "JavaScript日付オブジェクト"
}
} }
}, },
"editableList": { "editableList": {
"add": "追加", "add": "追加"
"addTitle": "要素を追加"
}, },
"search": { "search": {
"history": "検索履歴",
"clear": "全て削除",
"empty": "一致したものが見つかりませんでした", "empty": "一致したものが見つかりませんでした",
"addNode": "ノードを追加...", "addNode": "ノードを追加..."
"options": {
"configNodes": "設定ノード",
"unusedConfigNodes": "未使用の設定ノード",
"invalidNodes": "不正なノード",
"uknownNodes": "未知のノード",
"unusedSubflows": "未使用のサブフロー",
"hiddenFlows": "非表示のフロー",
"modifiedNodes": "修正したノードやフロー",
"thisFlow": "現在のフロー"
}
}, },
"expressionEditor": { "expressionEditor": {
"functions": "関数", "functions": "関数",
@ -992,16 +839,10 @@
"errors": { "errors": {
"invalid-expr": "不正なJSONata式:\n __message__", "invalid-expr": "不正なJSONata式:\n __message__",
"invalid-msg": "不正なJSONメッセージ例:\n __message__", "invalid-msg": "不正なJSONメッセージ例:\n __message__",
"context-unsupported": "$flowContext や $globalContextの\nコンテキスト関数をテストできません", "context-unsupported": "$flowContext や $globalContextの\nコンテキスト機能をテストできません",
"env-unsupported": "$env関数はテストできません", "eval": "表現評価エラー:\n __message__"
"moment-unsupported": "$moment関数はテストできません",
"clone-unsupported": "$clone関数はテストできません",
"eval": "式評価エラー:\n __message__"
} }
}, },
"monaco": {
"setTheme": "テーマを設定:"
},
"jsEditor": { "jsEditor": {
"title": "JavaScriptエディタ" "title": "JavaScriptエディタ"
}, },
@ -1013,8 +854,6 @@
"format": "JSONフォーマット", "format": "JSONフォーマット",
"rawMode": "JSONを編集", "rawMode": "JSONを編集",
"uiMode": "ビジュアルエディタ", "uiMode": "ビジュアルエディタ",
"rawMode-readonly": "JSON",
"uiMode-readonly": "ビジュアル",
"insertAbove": "上に挿入", "insertAbove": "上に挿入",
"insertBelow": "下に挿入", "insertBelow": "下に挿入",
"addItem": "要素を追加", "addItem": "要素を追加",
@ -1041,10 +880,7 @@
"quote": "引用", "quote": "引用",
"link": "リンク", "link": "リンク",
"horizontal-rule": "区切り線", "horizontal-rule": "区切り線",
"toggle-preview": "プレビュー表示切替え", "toggle-preview": "プレビュー表示切替え"
"mermaid": {
"summary": "Mermaid図"
}
}, },
"bufferEditor": { "bufferEditor": {
"title": "バッファエディタ", "title": "バッファエディタ",
@ -1179,8 +1015,7 @@
"not-git": "Gitリポジトリではありません", "not-git": "Gitリポジトリではありません",
"no-resource": "リポジトリが見つかりません", "no-resource": "リポジトリが見つかりません",
"cant-get-ssh-key-path": "エラー! 選択したSSHキーのパスを取得できません。", "cant-get-ssh-key-path": "エラー! 選択したSSHキーのパスを取得できません。",
"unexpected_error": "予期しないエラー", "unexpected_error": "予期しないエラー"
"clearContext": "プロジェクトを切り替る際にコンテキストを初期化"
}, },
"delete": { "delete": {
"confirm": "プロジェクトを削除しても良いですか?" "confirm": "プロジェクトを削除しても良いですか?"
@ -1221,200 +1056,17 @@
"editor-tab": { "editor-tab": {
"properties": "プロパティ", "properties": "プロパティ",
"envProperties": "環境変数", "envProperties": "環境変数",
"module": "モジュールプロパティ",
"description": "説明", "description": "説明",
"appearance": "外観", "appearance": "外観",
"preview": "UIプレビュー", "preview": "UIプレビュー",
"defaultValue": "デフォルト値" "defaultValue": "デフォルト値"
}, },
"tourGuide": { "languages": {
"takeATour": "ツアーを開始", "de": "ドイツ語",
"start": "開始", "en-US": "英語",
"next": "次へ", "ja": "日本語",
"welcomeTours": "ウェルカムツアー" "ko": "韓国語",
}, "zh-CN": "中国語(簡体)",
"diagnostics": { "zh-TW": "中国語(繁体)"
"title": "システム情報"
},
"validator": {
"errors": {
"invalid-json": "JSONデータが不正: __error__",
"invalid-expr": "不正なJSONata式: __error__",
"invalid-prop": "プロパティ式が不正",
"invalid-num": "数値が不正",
"invalid-num-prop": "__prop__: 数値が不正",
"invalid-regexp": "入力パターンが不正",
"invalid-regex-prop": "__prop__: 入力パターンが不正",
"missing-required-prop": "__prop__: プロパティが未設定",
"invalid-config": "__prop__: 設定ノードが不正",
"missing-config": "__prop__: 設定ノードが存在しません",
"validation-error": "__prop__: チェックエラー: __node__, __id__: __error__"
}
},
"contextMenu": {
"showActionList": "動作一覧を表示",
"insert": "挿入",
"node": "ノード",
"junction": "分岐点",
"linkNodes": "Linkード"
},
"env-var": {
"environment": "環境変数",
"header": "グローバル環境変数",
"revert": "破棄"
},
"action-list": {
"toggle-show-tips": "ヒント表示切替",
"show-about": "Node-REDの説明を表示",
"show-welcome-tour": "ウェルカムツアー表示",
"show-next-tab": "次のタブを表示",
"show-previous-tab": "前のタブを表示",
"add-flow": "フローを追加",
"add-flow-to-right": "フローを右に追加",
"edit-flow": "フローを編集",
"remove-flow": "フローを削除",
"enable-flow": "フローを有効化",
"disable-flow": "フローを無効化",
"hide-flow": "フローを隠す",
"hide-other-flows": "他のフローを非表示",
"hide-all-flows": "全てのフローを非表示",
"show-all-flows": "全てのフローを表示",
"show-last-hidden-flow": "最後に非表示にしたフローを表示",
"list-modified-nodes": "修正したフローを表示",
"list-hidden-flows": "非表示フローを表示",
"list-flows": "フロー一覧",
"list-subflows": "サブフロー一覧",
"go-to-previous-location": "前の位置に移動",
"go-to-next-location": "次の位置に移動",
"copy-selection-to-internal-clipboard": "選択をクリップボードにコピー",
"cut-selection-to-internal-clipboard": "選択をクリップボードに切り取り",
"paste-from-internal-clipboard": "クリップボードから貼り付け",
"detach-selected-nodes": "選択ノードを接続から外す",
"delete-selection": "選択を削除",
"delete-selection-and-reconnect": "選択を削除し再接続",
"edit-selected-node": "選択したノードを編集",
"go-to-selection": "選択に移動",
"undo": "変更操作を戻す",
"redo": "変更操作をやり直し",
"select-all-nodes": "全てのノードを選択",
"select-none": "ノードを選択",
"enable-selected-nodes": "選択ノードを有効化",
"disable-selected-nodes": "選択ノードを無効化",
"toggle-show-grid": "グリッド表示切替",
"toggle-snap-grid": "ノードの配置補助切替",
"toggle-status": "ステータス表示切替",
"show-selected-node-labels": "選択したノードのラベルを表示",
"hide-selected-node-labels": "選択したノードのラベルを非表示",
"scroll-view-up": "上スクロール",
"scroll-view-right": "右スクロール",
"scroll-view-down": "下スクロール",
"scroll-view-left": "左スクロール",
"step-view-up": "一単位上スクロール",
"step-view-right": "一単位右スクロール",
"step-view-down": "一単位下スクロール",
"step-view-left": "一単位左スクロール",
"move-selection-up": "選択を上移動",
"move-selection-right": "選択を右移動",
"move-selection-down": "選択を下移動",
"move-selection-left": "選択を左移動",
"move-selection-forwards": "選択を前面に移動",
"move-selection-backwards": "選択を背面に移動",
"move-selection-to-front": "選択を最前面に移動",
"move-selection-to-back": "選択を最背面に移動",
"step-selection-up": "選択を一単位上移動",
"step-selection-right": "選択を一単位右移動",
"step-selection-down": "選択を一単位下移動",
"step-selection-left": "選択を一単位左移動",
"select-connected-nodes": "接続されたノードを選択",
"select-downstream-nodes": "後方に接続されたノードを選択",
"select-upstream-nodes": "前方に接続されたノードを選択",
"go-to-next-node": "次のノードに移動",
"go-to-previous-node": "前のノードに移動",
"go-to-next-sibling": "次の兄弟ノードに移動",
"go-to-previous-sibling": "前の兄弟ノードに移動",
"go-to-nearest-node-on-left": "最も近い左側ノードに移動",
"go-to-nearest-node-on-right": "最も近い右側ノードに移動",
"go-to-nearest-node-above": "最も近い上側ノードに移動",
"go-to-nearest-node-below": "最も近い下側ノードに移動",
"align-selection-to-grid": "選択を整列",
"align-selection-to-left": "選択を左揃え",
"align-selection-to-right": "選択を右揃え",
"align-selection-to-top": "選択を上揃え",
"align-selection-to-bottom": "選択を下揃え",
"align-selection-to-middle": "選択を上下中央揃え",
"align-selection-to-center": "選択を左右中央揃え",
"distribute-selection-horizontally": "選択を左右に整列",
"distribute-selection-vertically": "選択を上下に整列",
"wire-series-of-nodes": "ノードを一続きに接続",
"wire-node-to-multiple": "ノードを複数に接続",
"wire-multiple-to-node": "複数からノードへ接続",
"split-wire-with-link-nodes": "ワイヤーをlinkードで分割",
"generate-node-names": "ノード名を生成",
"show-user-settings": "ユーザ設定を表示",
"show-help": "ヘルプを表示",
"toggle-palette": "パレットの表示切替",
"show-event-log": "イベントログを表示",
"manage-palette": "パレットの管理",
"toggle-sidebar": "サイドバーの表示切替",
"show-info-tab": "ノード情報タブの表示",
"show-help-tab": "ノードヘルプタブの表示",
"show-config-tab": "設定ノードタブの表示",
"select-all-config-nodes": "全ての設定ノードを選択",
"delete-config-selection": "選択した設定ノードを削除",
"show-context-tab": "コンテキストデータタブを表示",
"create-subflow": "サブフローを作成",
"convert-to-subflow": "選択をサブフローに変換",
"group-selection": "選択をグループ化",
"ungroup-selection": "選択をグループ解除",
"merge-selection-to-group": "選択をグループにマージ",
"remove-selection-from-group": "選択をグループから削除",
"copy-group-style": "グループのスタイルをコピー",
"paste-group-style": "グループのスタイルを貼り付け",
"show-export-dialog": "書き出しダイアログを表示",
"show-import-dialog": "読み込みダイアログを表示",
"show-library-export-dialog": "ライブラリ書き出しダイアログを表示",
"show-library-import-dialog": "ライブラリ読み込みダイアログを表示",
"show-examples-import-dialog": "サンプル読み込みダイアログを表示",
"search": "検索",
"search-previous": "前を検索",
"search-next": "次を検索",
"show-action-list": "動作一覧を表示",
"confirm-edit-tray": "編集を完了",
"cancel-edit-tray": "編集をキャンセル",
"show-remote-diff": "リモートとの変更差分を表示",
"deploy-flows": "フローをデプロイ",
"restart-flows": "フローを再起動",
"set-deploy-type-to-full": "デプロイを「全て」に設定",
"set-deploy-type-to-modified-flows": "デプロイを「変更したフロー」に設定",
"set-deploy-type-to-modified-nodes": "デプロイを「変更したノード」に設定",
"show-debug-tab": "デバッグタブを表示",
"clear-debug-messages": "デバッグメッセージを削除",
"clear-filtered-debug-messages": "フィルタしたデバッグメッセージを削除",
"activate-selected-debug-nodes": "選択したデバッグノードを有効化",
"activate-all-debug-nodes": "全てのデバッグノードを有効化",
"activate-all-flow-debug-nodes": "フロー内の全デバッグノードを有効化",
"deactivate-selected-debug-nodes": "選択したデバッグノードを無効化",
"deactivate-all-debug-nodes": "全てのデバッグノードを無効化",
"deactivate-all-flow-debug-nodes": "フロー内の全デバッグノードを無効化",
"zoom-in": "ズームイン",
"zoom-out": "ズームアウト",
"zoom-reset": "ズームリセット",
"toggle-navigator": "ナビゲータ表示切替",
"show-system-info": "システム情報",
"split-wires-with-junctions": "分岐点によりワイヤーを分割",
"new-project": "新しいプロジェクト",
"open-project": "プロジェクトを開く",
"show-project-settings": "プロジェクト設定を表示",
"show-version-control-tab": "バージョンコントロールタブを表示",
"start-flows": "フローを開始",
"stop-flows": "フローを停止",
"copy-item-url": "要素のURLをコピー",
"copy-item-edit-url": "要素の編集URLをコピー",
"move-flow-to-start": "フローを先頭に移動",
"move-flow-to-end": "フローを末尾に移動",
"show-global-env": "グローバル環境変数を表示",
"lock-flow": "フローを固定",
"unlock-flow": "フローの固定を解除",
"show-node-help": "ノードのヘルプを表示"
} }
} }

View File

@ -17,7 +17,7 @@
"tip14": "[shift] を押しながらノードを [click] すると、接続された全てのノードを選択できます。", "tip14": "[shift] を押しながらノードを [click] すると、接続された全てのノードを選択できます。",
"tip15": "[ctrl] を押しながらノードを [click] すると、選択/非選択を切り替えできます。", "tip15": "[ctrl] を押しながらノードを [click] すると、選択/非選択を切り替えできます。",
"tip16": "{{core:show-previous-tab}} や {{core:show-next-tab}} で、タブの切り替えができます。", "tip16": "{{core:show-previous-tab}} や {{core:show-next-tab}} で、タブの切り替えができます。",
"tip17": "ノードのプロティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。", "tip17": "ノードのプロティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
"tip18": "ノードを選択し、 {{core:edit-selected-node}} を押すとプロパティ設定画面が表示されます。" "tip18": "ノードを選択し、 {{core:edit-selected-node}} を押すとプロパティ設定画面が表示されます。"
} }
} }

View File

@ -52,8 +52,8 @@
"desc": "文字列 `str` からパターン `pattern` を検索し、置換文字列 `replacement` に置き換えます。\n\n任意の引数 `limit` には、置換回数の上限値を指定します。" "desc": "文字列 `str` からパターン `pattern` を検索し、置換文字列 `replacement` に置き換えます。\n\n任意の引数 `limit` には、置換回数の上限値を指定します。"
}, },
"$now": { "$now": {
"args": "$[picture [, timezone]]", "args": "",
"desc": "ISO 8601互換形式の時刻を生成し、文字列として返します。`picture` および `timezone` パラメータが指定されている場合、現在時刻を `$fromMillis()` 関数の説明に従ってフォーマットします。" "desc": "ISO 8601互換形式の時刻を生成し、文字列として返します。"
}, },
"$base64encode": { "$base64encode": {
"args": "string", "args": "string",
@ -117,11 +117,11 @@
}, },
"$boolean": { "$boolean": {
"args": "arg", "args": "arg",
"desc": "以下のルールを用いて、真偽型へ型変換します。:\n\n - `Boolean` : 変換しない\n - `string`: 空 : `false`\n - `string`: 空でない : `true`\n - `number`: `0` : `false`\n - `number`: 0でない : `true`\n - `null` : `false`\n - `array`: 空 : `false`\n - `array`: `true` に型変換された要素を持つ: `true`\n - `array`: 全ての要素が `false` に型変換: `false`\n - `object`: 空 : `false`\n - `object`: 空でない : `true`\n - `function` : `false`" "desc": "以下のルールを用いて、ブーリアン型へ型変換します。:\n\n - `Boolean` : 変換しない\n - `string`: 空 : `false`\n - `string`: 空でない : `true`\n - `number`: `0` : `false`\n - `number`: 0でない : `true`\n - `null` : `false`\n - `array`: 空 : `false`\n - `array`: `true` に型変換された要素を持つ: `true`\n - `array`: 全ての要素が `false` に型変換: `false`\n - `object`: 空 : `false`\n - `object`: 空でない : `true`\n - `function` : `false`"
}, },
"$not": { "$not": {
"args": "arg", "args": "arg",
"desc": "引数の否定を真偽型で返します。 `arg` は最初に真偽型に型変換されます。" "desc": "引数の否定をブーリアン型で返します。 `arg` は最初にブーリアン型に型変換されます。"
}, },
"$exists": { "$exists": {
"args": "arg", "args": "arg",
@ -137,7 +137,7 @@
}, },
"$sort": { "$sort": {
"args": "array [, function]", "args": "array [, function]",
"desc": "配列 `array` 内の値を並び変えた配列を返します。\n\n比較関数 `function` を用いる場合、比較関数は以下のとおり2つの引数を持つ必要があります。\n\n`function(left, right)`\n\n比較関数は、`left` `right` の2つの値を比較するために、値を並び替える処理で呼び出されます。もし、求められる並び順にて `left` の値を `right` の値より後ろに置きたい場合は、比較関数は置き換えを表す真偽型の `true` を返す必要があります。一方、置き換えが不要の場合は `false` を返す必要があります。" "desc": "配列 `array` 内の値を並び変えた配列を返します。\n\n比較関数 `function` を用いる場合、比較関数は以下のとおり2つの引数を持つ必要があります。\n\n`function(left, right)`\n\n比較関数は、leftとrightの2つの値を比較するために、値を並び替える処理で呼び出されます。もし、求められる並び順にてleftの値をrightの値より後ろに置きたい場合は、比較関数は置き換えを表すブーリアン型の `true` を返す必要があります。一方、置き換えが不要の場合は `false` を返す必要があります。"
}, },
"$reverse": { "$reverse": {
"args": "array", "args": "array",
@ -200,12 +200,12 @@
"desc": "文字数が引数 `width` の絶対値以上となるよう、必要に応じて追加文字を付け足した `string` のコピーを返します。\n\n`width` が正の値の場合、文字列の右側に追加文字を付け足します。もし負の値の場合、文字列の左側に追加文字を付け足します。\n\n任意の引数 `char` には、本関数で用いる追加文字を指定します。もし追加文字を指定しない場合は、既定値として空白文字を使用します。" "desc": "文字数が引数 `width` の絶対値以上となるよう、必要に応じて追加文字を付け足した `string` のコピーを返します。\n\n`width` が正の値の場合、文字列の右側に追加文字を付け足します。もし負の値の場合、文字列の左側に追加文字を付け足します。\n\n任意の引数 `char` には、本関数で用いる追加文字を指定します。もし追加文字を指定しない場合は、既定値として空白文字を使用します。"
}, },
"$fromMillis": { "$fromMillis": {
"args": "number, [, picture [, timezone]]", "args": "number",
"desc": "Unixエポック(1 January, 1970 UTC)からの経過ミリ秒を表す数値を、`picture`の指定に従ってタイムスタンプの文字列に変換します。\n\n`picture`パラメータが指定されない場合、ISO 8601形式に変換します。\n\n`picture`を指定すると、指定した文字列に従って変換を行います。この変換はXPath F&O 3.1仕様におけるXPath/XQueryの2引数形式`format-dateTime`と同様です。`picture`パラメータはタイムスタンプの変換形式を定義し、その書式は`format-dateTime`と同じです。\n\n`timezone`を指定すると、指定タイムゾーンで変換します。`timezone`は'±HHMM'という形式で指定します。ここで、±は+もしくは-記号を表し、HHMMはUTCからの差分時間と分を表します。正の差分はUTCの東、負の差分は西のタイムゾーンとなります。" "desc": "Unixエポック(1 January, 1970 UTC)からの経過ミリ秒を表す数値を、ISO 8601形式のタイムスタンプの文字列に変換します。"
}, },
"$formatNumber": { "$formatNumber": {
"args": "number, picture [, options]", "args": "number, picture [, options]",
"desc": "`number` を文字列へ変換し、文字列 `picture` に指定した数値表現になるよう書式を変更します。\n\nこの関数の動作は、XPath F&O 3.1の仕様に定義されているXPath/XQuery関数の `fn:format-number` の動作と同じです。引数の文字列 `picture` は、 `fn:format-number` と同じ構文で数値の書式を定義します。\n\n任意の第三引数 `options` は、小数点記号の様な既定のロケール固有の書式設定文字を上書きするために使用します。この引数を指定する場合、XPath F&O 3.1の仕様の数値形式の項に記述されているname/valueペアを含むオブジェクトでなければなりません。" "desc": "`number` を文字列へ変換し、文字列 `picture` に指定した数値表現になるよう書式を変更します。\n\nこの関数の動作は、XPath F&O 3.1の仕様に定義されているXPath/XQuery関数のfn:format-numberの動作と同じです。引数の文字列 picture は、fn:format-numberと同じ構文で数値の書式を定義します。\n\n任意の第三引数 `options` は、小数点記号の様な既定のロケール固有の書式設定文字を上書きするために使用します。この引数を指定する場合、XPath F&O 3.1の仕様の数値形式の項に記述されているname/valueペアを含むオブジェクトでなければなりません。"
}, },
"$formatBase": { "$formatBase": {
"args": "number [, radix]", "args": "number [, radix]",
@ -237,25 +237,25 @@
}, },
"$assert": { "$assert": {
"args": "arg, str", "args": "arg, str",
"desc": "`arg`が真の場合、`undefined`を返します。偽の場合、`str`をメッセージとする例外を送出します。" "desc": "`arg`が真の場合、undefinedを返します。偽の場合、`str`をメッセージとする例外を送出します。"
}, },
"$single": { "$single": {
"args": "array, function", "args": "array, function",
"desc": "`array`の要素のうち、条件判定関数`function`を満たす(`function`に与えた場合に真偽値`true`を返す)要素が1つのみである場合、それを返します。マッチする要素が1つのみでない場合、例外を送出します。\n\n指定する関数は`function(value [, index [, array]])`というシグネチャでなければなりません。ここで、`value`は`array`の要素値、`index`は要素の添字、第三引数には配列全体を渡します。" "desc": "`array`の要素のうち、条件判定関数`function`を満たす(`function`に与えた場合に真偽値`true`を返す)要素が1つのみである場合、それを返します。マッチする要素が1つのみでない場合、例外を送出します。\n\n指定する関数は`function(value [, index [, array]])`というシグネチャでなければなりません。ここで、`value`は`array`の要素値、`index`は要素の添字、第三引数には配列全体を渡します。"
}, },
"$encodeUrlComponent": { "$encodeUrl": {
"args": "str", "args": "str",
"desc": "Uniform Resource Locator (URL)を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" "desc": "Uniform Resource Locator (URL)を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
}, },
"$encodeUrl": { "$encodeUrlComponent": {
"args": "str", "args": "str",
"desc": "Uniform Resource Locator (URL)要素を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" "desc": "Uniform Resource Locator (URL)要素を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
}, },
"$decodeUrlComponent": { "$decodeUrl": {
"args": "str", "args": "str",
"desc": "encodeUrlComponentで置換したUniform Resource Locator (URL)をデコードします。\n\n例: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" "desc": "encodeUrlComponentで置換したUniform Resource Locator (URL)をデコードします。\n\n例: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
}, },
"$decodeUrl": { "$decodeUrlComponent": {
"args": "str", "args": "str",
"desc": "encodeUrlで置換したUniform Resource Locator (URL)要素をデコードします。 \n\n例: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" "desc": "encodeUrlで置換したUniform Resource Locator (URL)要素をデコードします。 \n\n例: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
}, },
@ -270,9 +270,5 @@
"$moment": { "$moment": {
"args": "[str]", "args": "[str]",
"desc": "Momentライブラリを使用して日付オブジェクトを取得します。" "desc": "Momentライブラリを使用して日付オブジェクトを取得します。"
},
"$clone": {
"args": "value",
"desc": "オブジェクトを安全に複製します。"
} }
} }

264
packages/node_modules/@node-red/editor-client/locales/ko/editor.json vendored Normal file → Executable file
View File

@ -24,29 +24,16 @@
"delete": "정말로 '__label__' 을(를) 삭제하시겠습니까?", "delete": "정말로 '__label__' 을(를) 삭제하시겠습니까?",
"dropFlowHere": "플로우를 이곳에 가져오세요", "dropFlowHere": "플로우를 이곳에 가져오세요",
"addFlow": "플로우 추가", "addFlow": "플로우 추가",
"addFlowToRight": "오른쪽에 플로우 추가",
"hideFlow": "플로우 숨기기",
"hideOtherFlows": "다른 플로우 숨기기",
"showAllFlows": "모든 플로우 보기",
"hideAllFlows": "모든 플로우 숨기기",
"hiddenFlows": "__count__개의 숨겨진 플로우 보기",
"hiddenFlows_plural": "__count__개의 숨겨진 플로우 보기",
"showLastHiddenFlow": "마지막으로 숨겨진 플로우 보기",
"listFlows": "플로우 리스트",
"listSubflows": "서브 플로우 리스트",
"status": "상태", "status": "상태",
"enabled": "사용가능", "enabled": "사용가능",
"disabled": "사용불가능", "disabled": "사용불가능",
"info": "상세내역", "info": "상세내역"
"selectNodes": "선택할 노드 클릭"
}, },
"menu": { "menu": {
"label": { "label": {
"view": { "view": {
"view": "창", "view": "창",
"grid": "눈금선", "grid": "눈금선",
"storeZoom": "불러오기 시 확대/축소 복원",
"storePosition": "불러오기 시 스크롤 위치 복원",
"showGrid": "눈금선 보이기", "showGrid": "눈금선 보이기",
"snapGrid": "노드 배치 보조 켜기", "snapGrid": "노드 배치 보조 켜기",
"gridSize": "눈금선 크기", "gridSize": "눈금선 크기",
@ -54,9 +41,7 @@
"defaultDir": "기본", "defaultDir": "기본",
"ltr": "왼쪽 -> 오른쪽", "ltr": "왼쪽 -> 오른쪽",
"rtl": "오른쪽 -> 왼쪽", "rtl": "오른쪽 -> 왼쪽",
"auto": "자동배분", "auto": "자동배분"
"language": "언어",
"browserDefault": "브라우저 기본값"
}, },
"sidebar": { "sidebar": {
"show": "우측사이드바 보이기" "show": "우측사이드바 보이기"
@ -64,7 +49,6 @@
"palette": { "palette": {
"show": "팔렛트 보이기" "show": "팔렛트 보이기"
}, },
"edit": "수정",
"settings": "설정", "settings": "설정",
"userSettings": "사용자 설정", "userSettings": "사용자 설정",
"nodes": "노드설정", "nodes": "노드설정",
@ -72,13 +56,14 @@
"displayConfig": "설정노드 보기", "displayConfig": "설정노드 보기",
"import": "가져오기", "import": "가져오기",
"export": "내보내기", "export": "내보내기",
"search": "플로우 색", "search": "플로우 색",
"searchInput": "플로우 검색", "searchInput": "플로우 검색",
"subflows": "서브 플로우", "subflows": "보조 플로우",
"createSubflow": "서브 플로우 생성", "createSubflow": "보조 플로우 생성",
"selectionToSubflow": "서브 플로우 선택", "selectionToSubflow": "보조 플로우 선택",
"flows": "플로우", "flows": "플로우",
"add": "추가", "add": "추가",
"rename": "이름변경",
"delete": "삭제", "delete": "삭제",
"keyboardShortcuts": "단축키", "keyboardShortcuts": "단축키",
"login": "로그인", "login": "로그인",
@ -86,43 +71,19 @@
"editPalette": "팔렛트 관리", "editPalette": "팔렛트 관리",
"other": "기타", "other": "기타",
"showTips": "Tip 보기", "showTips": "Tip 보기",
"showWelcomeTours": "새 버전에 대한 가이드 보기 표시",
"help": "Node-RED 웹사이트", "help": "Node-RED 웹사이트",
"projects": "프로젝트", "projects": "프로젝트",
"projects-new": "신규", "projects-new": "신규",
"projects-open": "열기", "projects-open": "열기",
"projects-settings": "프로젝트 설정", "projects-settings": "프로젝트 설정",
"showNodeLabelDefault": "새로 추가된 노드의 라벨 보이기", "showNodeLabelDefault": "새로 추가된 노드의 라벨 보이기"
"codeEditor": "Code Editor",
"groups": "그룹",
"groupSelection": "그룹 선택",
"ungroupSelection": "그룹 선택 해제",
"groupMergeSelection": "선택 항목 병합",
"groupRemoveSelection": "선택 그룹 제거",
"arrange": "배치",
"alignLeft": "왼쪽으로 정렬",
"alignCenter": "가운데 정렬",
"alignRight": "오른쪽으로 정렬",
"alignTop": "맨 위에 정렬",
"alignMiddle": "맨 위에 정렬",
"alignBottom": "맨 아래 정렬",
"distributeHorizontally": "수평으로 배치",
"distributeVertically": "수직으로 배치",
"moveToBack": "맨 뒤로 이동",
"moveToFront": "맨 앞으로 이동",
"moveBackwards": "뒤로 이동",
"moveForwards": "앞으로 이동"
} }
}, },
"actions": { "actions": {
"toggle-navigator": "네비게이터 표시/비표시", "toggle-navigator": "네비게이터 표시/비표시",
"zoom-out": "축소하기", "zoom-out": "축소하기",
"zoom-reset": "확대/축소 초기화", "zoom-reset": "확대/축소 초기화",
"zoom-in": "확대하기", "zoom-in": "확대하기"
"search-flows": "플로우 찾기",
"search-prev": "이전",
"search-next": "다음",
"search-counter": "\"__term__\" __result__ of __count__"
}, },
"user": { "user": {
"loggedInAs": "__name__ 에 로그인됨", "loggedInAs": "__name__ 에 로그인됨",
@ -138,17 +99,12 @@
} }
}, },
"notification": { "notification": {
"state": {
"flowsStopped": "플로우 중지됨",
"flowsStarted": "플로우 시작됨"
},
"warning": "<strong>경고</strong>: __message__", "warning": "<strong>경고</strong>: __message__",
"warnings": { "warnings": {
"undeployedChanges": "변경사항 배포가 취소되었습니다", "undeployedChanges": "변경사항 배포가 취소되었습니다",
"nodeActionDisabled": "노드 실행이 비활성화 되었습니다", "nodeActionDisabled": "노드 실행이 비활성화 되었습니다",
"nodeActionDisabledSubflow": "보조 플로우에서 노드 실행이 비활성화 되었습니다", "nodeActionDisabledSubflow": "보조 플로우에서 노드 실행이 비활성화 되었습니다",
"missing-types": "<p>타입이 없는 노드로인해 플로우가 중지되었습니다</p>", "missing-types": "<p>타입이 없는 노드로인해 플로우가 중지되었습니다</p>",
"missing-modules": "<p>누락된 모듈로 인해 플로우가 중지되었습니다.</p>",
"safe-mode": "<p>[안전모드] 플로우가 정지되었습니다.</p><p>플로우의 수정과 배포가 가능합니다. 다시 배포버튼을 누르세요.</p>", "safe-mode": "<p>[안전모드] 플로우가 정지되었습니다.</p><p>플로우의 수정과 배포가 가능합니다. 다시 배포버튼을 누르세요.</p>",
"restartRequired": "업그레이드한 모듈을 유효화하기 위해 Node-RED를 재시작 합니다 ", "restartRequired": "업그레이드한 모듈을 유효화하기 위해 Node-RED를 재시작 합니다 ",
"credentials_load_failed": "<p>인증정보 복호화에 실패하여 플로우가 멈췄습니다. </p><p>인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.</p>", "credentials_load_failed": "<p>인증정보 복호화에 실패하여 플로우가 멈췄습니다. </p><p>인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.</p>",
@ -176,12 +132,7 @@
"updated": "'__project__'가 변경 되었습니다", "updated": "'__project__'가 변경 되었습니다",
"pull": "'__project__'를 다시 가져왔습니다", "pull": "'__project__'를 다시 가져왔습니다",
"revert": "'__project__'를 취소했습니다", "revert": "'__project__'를 취소했습니다",
"merge-complete": "Git 병합이 완료되었습니다", "merge-complete": "Git 병합이 완료되었습니다"
"setupCredentials": "자격 증명 설정",
"setupProjectFiles": "프로젝트 파일 설정",
"no": "취소",
"createDefault": "기본 프로젝트 파일 만들기",
"mergeConflict": "병합 충돌 표시"
}, },
"label": { "label": {
"manage-project-dep": "프로젝트 의존성 관리", "manage-project-dep": "프로젝트 의존성 관리",
@ -190,8 +141,7 @@
"create-default-package": "기본 패키지 파일 생성", "create-default-package": "기본 패키지 파일 생성",
"no-thanks": "괜찮습니다", "no-thanks": "괜찮습니다",
"create-default-project": "기본 프로젝트 파일 생성", "create-default-project": "기본 프로젝트 파일 생성",
"show-merge-conflicts": "병합 충돌 보여주기", "show-merge-conflicts": "병합 충돌 보여주기"
"unknownNodesButton": "알 수 없는 노드 검색"
} }
}, },
"clipboard": { "clipboard": {
@ -201,14 +151,10 @@
"node_plural": "__count__ 개의 노드", "node_plural": "__count__ 개의 노드",
"configNode": "__count__ 개의 설정 노드", "configNode": "__count__ 개의 설정 노드",
"configNode_plural": "__count__ 개의 설정 노드", "configNode_plural": "__count__ 개의 설정 노드",
"group": "__count__ 개의 그룹",
"group_plural": "__count__ 개의 그룹",
"flow": "__count__ 개의 플로우", "flow": "__count__ 개의 플로우",
"flow_plural": "__count__ 개의 플로우", "flow_plural": "__count__ 개의 플로우",
"subflow": "__count__ 개의 서브 플로우", "subflow": "__count__ 개의 서브 플로우",
"subflow_plural": "__count__ 개의 서브 플로우", "subflow_plural": "__count__ 개의 서브 플로우",
"replacedNodes": "__count__ 개의 교체된 노드",
"replacedNodes_plural": "__count__ 개의 교체된 노드",
"pasteNodes": "여기에 노드를 붙여넣기 하세요", "pasteNodes": "여기에 노드를 붙여넣기 하세요",
"selectFile": "불러올 파일을 선택하세요", "selectFile": "불러올 파일을 선택하세요",
"importNodes": "노드 불러오기", "importNodes": "노드 불러오기",
@ -216,46 +162,28 @@
"download": "다운로드", "download": "다운로드",
"importUnrecognised": "알 수 없는 형식 :", "importUnrecognised": "알 수 없는 형식 :",
"importUnrecognised_plural": "알 수 없는 형식 :", "importUnrecognised_plural": "알 수 없는 형식 :",
"importDuplicate": "가져온 중복 노드:",
"importDuplicate_plural": "가져온 중복 노드:",
"nodesExported": "클립보드에 노드 내보내기", "nodesExported": "클립보드에 노드 내보내기",
"nodesImported": "불러오기 : ", "nodesImported": "불러오기 : ",
"nodeCopied": "__count__개의 노드가 복사 되었습니다", "nodeCopied": "__count__개의 노드가 복사 되었습니다",
"nodeCopied_plural": "__count__개의 노드가 복사 되었습니다", "nodeCopied_plural": "__count__개의 노드가 복사 되었습니다",
"groupCopied": "__count__ 개의 그룹이 복사되었습니다",
"groupCopied_plural": "__count__ 개의 그룹이 복사되었습니다",
"groupStyleCopied": "그룹 스타일이 복사되었습니다",
"invalidFlow": "정상적지 않은 플로우 : __message__", "invalidFlow": "정상적지 않은 플로우 : __message__",
"recoveredNodes": "복구된 노드",
"recoveredNodesInfo": "이 플로우의 노드를 가져올 때 유효한 플로우 ID가 누락되었습니다. 해당 플로우에 추가되었으므로 복원하거나 삭제할 수 있습니다.",
"recoveredNodesNotification": "<p>유효하지 않은 플로우 ID를 가진 노드입니다.</p><p>'__flowName__' 라는 플로우에 추가되었습니다.</p>",
"export": { "export": {
"selected": "선택된 노드", "selected": "선택된 노드",
"current": "현재 플로우", "current": "현재 플로우",
"all": "모든 플로우", "all": "모든 플로우",
"compact": "압축형식", "compact": "압축형식",
"formatted": "서식유지", "formatted": "서식유지",
"copy": "클립보드로 내보내기", "copy": "클립보드로 내보내기"
"export": "라이브러리로 내보내기",
"exportAs": "내보내기",
"overwrite": "확인",
"exists": "<p><b>\"__file__\"</b> 이미 존재합니다.</p><p>교체하시겠습니까?</p>"
}, },
"import": { "import": {
"import": "가져올 위치 : ", "import": "가져올 위치 : ",
"importSelected": "선택 항목 가져오기",
"importCopy": "사본 가져오기",
"viewNodes": "노드 보기...",
"newFlow": "새로운 플로우", "newFlow": "새로운 플로우",
"replace": "교체",
"errors": { "errors": {
"notArray": "입력이 JSON 배열이 아닙니다", "notArray": "입력이 JSON 배열이 아닙니다",
"itemNotObject": "입력이 올바른 플로우가 아닙니다 - __index__는 노드 오브젝트가 아닙니다", "itemNotObject": "입력이 올바른 플로우가 아닙니다 - __index__는 노드 오브젝트가 아닙니다",
"missingId": "입력이 올바른 플로우가 아닙니다 - __index__의 'id' 속성이 없습니다", "missingId": "입력이 올바른 플로우가 아닙니다 - __index__의 'id' 속성이 없습니다",
"missingType": "입력이 올바른 플로우가 아닙니다 - __index__의 'type' 속성이 없습니다" "missingType": "입력이 올바른 플로우가 아닙니다 - __index__의 'type' 속성이 없습니다"
}, }
"conflictNotification1": "가져오는 노드 중 일부가 이미 작업 공간에 있습니다..",
"conflictNotification2": "가져올 노드와 기존 노드를 바꿀지 아니면 복사본을 가져올지 선택합니다."
}, },
"copyMessagePath": "Path가 복사 되었습니다", "copyMessagePath": "Path가 복사 되었습니다",
"copyMessageValue": "Value가 복사 되었습니다", "copyMessageValue": "Value가 복사 되었습니다",
@ -269,19 +197,13 @@
"modifiedFlowsDesc": "변경사항이 있는 플로우만 배포합니다", "modifiedFlowsDesc": "변경사항이 있는 플로우만 배포합니다",
"modifiedNodes": "변경된 노드", "modifiedNodes": "변경된 노드",
"modifiedNodesDesc": "변경사항이 있는 노드만 배포합니다", "modifiedNodesDesc": "변경사항이 있는 노드만 배포합니다",
"startFlows": "시작",
"startFlowsDesc": "플로우를 시작합니다",
"stopFlows": "중지",
"stopFlowsDesc": "플로우를 중지합니다",
"restartFlows": "플로우 재시작", "restartFlows": "플로우 재시작",
"restartFlowsDesc": "현재 배포된 플로우를 재시작합니다", "restartFlowsDesc": "현재 배포된 플로우를 재시작합니다",
"successfulDeploy": "배포가 성공했습니다", "successfulDeploy": "배포가 성공했습니다",
"successfulRestart": "플로우 재시작을 성공했습니다", "successfulRestart": "플로우 재시작을 성공했습니다",
"deployFailed": "배포 실패 : __message__", "deployFailed": "배포 실패 : __message__",
"unusedConfigNodes": "사용되지 않는 설정노드가 있습니다", "unusedConfigNodes": "사용되지 않는 설정노드가 있습니다",
"unusedConfigNodesButton": "사용하지 않는 구성 노드 검색", "unusedConfigNodesLink": "여기를 클릭하면 볼 수 있습니다",
"unknownNodesButton": "알 수 없는 노드 검색",
"invalidNodesButton": "잘못된 노드 검색",
"errors": { "errors": {
"noResponse": "서버의 응답이 없습니다" "noResponse": "서버의 응답이 없습니다"
}, },
@ -341,7 +263,6 @@
"newVersionError": "New Version의 JSON 형식이 올바르지 않습니다 :" "newVersionError": "New Version의 JSON 형식이 올바르지 않습니다 :"
}, },
"subflow": { "subflow": {
"editSubflowInstance": "서브 플로우 인스턴스 수정: __name__",
"editSubflow": "플로우 템플릿 수정 : __name__", "editSubflow": "플로우 템플릿 수정 : __name__",
"edit": "플로우 템플릿 수정", "edit": "플로우 템플릿 수정",
"subflowInstances": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다", "subflowInstances": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다",
@ -349,39 +270,14 @@
"editSubflowProperties": "속성 수정", "editSubflowProperties": "속성 수정",
"input": "입력:", "input": "입력:",
"output": "출력:", "output": "출력:",
"status": "상태 노드",
"deleteSubflow": "서브 플로우 삭제", "deleteSubflow": "서브 플로우 삭제",
"confirmDelete": "서브 플로우를 삭제하시겠습니까?",
"info": "상세내역", "info": "상세내역",
"category": "카테고리", "category": "카테고리",
"module": "모듈",
"license": "라이선스",
"licenseNone": "없음",
"licenseOther": "Other",
"type": "노드",
"version": "버전",
"versionPlaceholder": "x.y.z",
"keys": "키워드",
"keysPlaceholder": "키워드(쉼표로 구분)를 입력해주세요",
"author": "이름",
"authorPlaceholder": "이름 또는 이메일을 입력해주세요",
"desc": "설명",
"env": {
"restore": "서브 플로우 기본값으로 복원",
"remove": "환경 변수 제거"
},
"errors": { "errors": {
"noNodesSelected": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 노드가 선택되지 않았습니다", "noNodesSelected": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 노드가 선택되지 않았습니다",
"multipleInputsToSelection": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 복수의 입력이 선택되었습니다" "multipleInputsToSelection": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 복수의 입력이 선택되었습니다"
} }
}, },
"group": {
"editGroup": "그룹 수정: __name__",
"errors": {
"cannotCreateDiffGroups": "다른 그룹의 노드를 사용하여 그룹을 생성할 수 없습니다",
"cannotAddSubflowPorts": "그룹에 서브 플로우 포트를 추가할 수 없습니다"
}
},
"editor": { "editor": {
"configEdit": "수정", "configEdit": "수정",
"configAdd": "추가", "configAdd": "추가",
@ -395,20 +291,19 @@
"addNewType": "__type__의 노드타입 추가 ...", "addNewType": "__type__의 노드타입 추가 ...",
"nodeProperties": "노드 속성", "nodeProperties": "노드 속성",
"label": "명칭", "label": "명칭",
"color": "Color",
"portLabels": "포트 설정", "portLabels": "포트 설정",
"labelInputs": "입력", "labelInputs": "입력",
"labelOutputs": "출력", "labelOutputs": "출력",
"settingIcon": "아이콘", "settingIcon": "아이콘",
"default": "default",
"noDefaultLabel": "없음", "noDefaultLabel": "없음",
"defaultLabel": "기본 명칭", "defaultLabel": "기본 명칭",
"searchIcons": "아이콘 조회", "searchIcons": "아이콘 조회",
"useDefault": "기본설정 사용", "useDefault": "기본설정 사용",
"description": "상세 내역", "description": "상세 내역",
"show": "보이기",
"hide": "숨기기",
"errors": { "errors": {
"scopeChange": "범위를 변경하게 되면 다른 플로우의 노드가 사용이 불가능해 집니다.", "scopeChange": "범위를 변경하게 되면 다른 플로우의 노드가 사용이 불가능해 집니다."
"invalidProperties": "유효하지 않은 속성:"
} }
}, },
"keyboard": { "keyboard": {
@ -421,11 +316,10 @@
"global": "글로벌", "global": "글로벌",
"workspace": "작업공간", "workspace": "작업공간",
"selectAll": "모든 노드 선택", "selectAll": "모든 노드 선택",
"selectNone": "노드 선택 취소", "selectAllConnected": "모든 연결된 노드 선택",
"selectAllConnected": "연결된 모든 노드 선택",
"addRemoveNode": "노드 추가/삭제", "addRemoveNode": "노드 추가/삭제",
"editSelected": "선택된 노드 수정", "editSelected": "선택된 노드 수정",
"deleteSelected": "선택된 노드 또는 링크 삭제", "deleteSelected": "선택된 노드나 링크를 삭제",
"importNode": "노드 불러오기", "importNode": "노드 불러오기",
"exportNode": "노드 내보내기", "exportNode": "노드 내보내기",
"nudgeNode": "선택된 노드 이동 (1px)", "nudgeNode": "선택된 노드 이동 (1px)",
@ -435,14 +329,9 @@
"copyNode": "선택된 노드 복사", "copyNode": "선택된 노드 복사",
"cutNode": "선택된 노드 잘라내기", "cutNode": "선택된 노드 잘라내기",
"pasteNode": "노드 붙여넣기", "pasteNode": "노드 붙여넣기",
"copyGroupStyle": "그룹 스타일 복사하기",
"pasteGroupStyle": "그룹 스타일 붙여넣기",
"undoChange": "마지막 변경 되돌리기", "undoChange": "마지막 변경 되돌리기",
"redoChange": "다시 실행하기",
"searchBox": "검색창 열기", "searchBox": "검색창 열기",
"managePalette": "팔렛트 관리", "managePalette": "팔렛트 관리"
"actionList": "액션 목록",
"splitWireWithLinks": "링크 노드로 선택 항목 분할"
}, },
"library": { "library": {
"library": "라이브러리", "library": "라이브러리",
@ -450,15 +339,12 @@
"saveToLibrary": "라이브러리로 저장...", "saveToLibrary": "라이브러리로 저장...",
"typeLibrary": "__type__ 라이브러리", "typeLibrary": "__type__ 라이브러리",
"unnamedType": "이름없는 __type__", "unnamedType": "이름없는 __type__",
"exportedToLibrary": "노드를 라이브러리로 내보냈습니다.",
"dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?", "dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?",
"invalidFilename": "파일명이 올바르지 않습니다", "invalidFilename": "파일명이 올바르지 않습니다",
"savedNodes": "저장된 노드", "savedNodes": "저장된 노드",
"savedType": "저장된 __type__", "savedType": "저장된 __type__",
"saveFailed": "저장 실패 : __message__", "saveFailed": "저장 실패 : __message__",
"newFolder": "새로운 폴더",
"types": { "types": {
"local": "로컬",
"examples": "예시" "examples": "예시"
} }
}, },
@ -469,13 +355,9 @@
"addCategory": "추가 ...", "addCategory": "추가 ...",
"label": { "label": {
"subflows": "서브 플로우", "subflows": "서브 플로우",
"network": "네트워크",
"common": "일반",
"input": "입력", "input": "입력",
"output": "출력", "output": "출력",
"function": "기능", "function": "기능",
"sequence": "sequence",
"parser": "parser",
"social": "소셜", "social": "소셜",
"storage": "저장", "storage": "저장",
"analysis": "분석", "analysis": "분석",
@ -494,8 +376,7 @@
"nodeEnabled_plural": "노드가 활성화 되었습니다:", "nodeEnabled_plural": "노드가 활성화 되었습니다:",
"nodeDisabled": "노드가 비활성화 되었습니다:", "nodeDisabled": "노드가 비활성화 되었습니다:",
"nodeDisabled_plural": "노드가 비활성화 되었습니다:", "nodeDisabled_plural": "노드가 비활성화 되었습니다:",
"nodeUpgraded": "__module__ 노드모듈이 __version__으로 업그레이드 되었습니다", "nodeUpgraded": "__module__ 노드모듈이 __version__으로 업그레이드 되었습니다"
"unknownNodeRegistered": "Error loading node: <ul><li>__type__<br>__error__</li></ul>"
}, },
"editor": { "editor": {
"title": "팔렛트 관리", "title": "팔렛트 관리",
@ -542,8 +423,6 @@
"sortAZ": "a-z", "sortAZ": "a-z",
"sortRecent": "최근", "sortRecent": "최근",
"more": "+ __count__ 개 더 보기", "more": "+ __count__ 개 더 보기",
"upload": "Upload module tgz file",
"refresh": "모듈 목록 새로 고침",
"errors": { "errors": {
"catalogLoadFailed": "<p>노드 카탈로그를 설치하지 못했습니다.</p><p>브라우저 콘솔로그를 참고하세요.</p>", "catalogLoadFailed": "<p>노드 카탈로그를 설치하지 못했습니다.</p><p>브라우저 콘솔로그를 참고하세요.</p>",
"installFailed": "<p>설치 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>", "installFailed": "<p>설치 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>",
@ -584,7 +463,6 @@
"label": "정보", "label": "정보",
"node": "노드", "node": "노드",
"type": "타입", "type": "타입",
"group": "Group",
"module": "모듈", "module": "모듈",
"id": "ID", "id": "ID",
"status": "상태", "status": "상태",
@ -607,23 +485,7 @@
"nodeHelp": "노드 도움말", "nodeHelp": "노드 도움말",
"none": "없음", "none": "없음",
"arrayItems": "__count__ 개의 항목", "arrayItems": "__count__ 개의 항목",
"showTips": "설정에서 도움말을 열 수 있습니다. ", "showTips": "설정에서 도움말을 열 수 있습니다. "
"outline": "개요",
"empty": "비우기",
"globalConfig": "전역 설정 노드",
"triggerAction": "트리거 작업",
"find": "작업 공간에서 찾기"
},
"help": {
"name": "도움말",
"label": "도움말",
"search": "도움말 검색",
"nodeHelp": "노드 도움말 보기",
"showHelp": "도움말 보기",
"showInOutline": "요약 보기",
"showTopics": "토픽 보기",
"noHelp": "선택한 도움말 항목이 없습니다",
"changeLog": "릴리즈 정보"
}, },
"config": { "config": {
"name": "노드 설정", "name": "노드 설정",
@ -633,9 +495,7 @@
"subflows": "보조 플로우", "subflows": "보조 플로우",
"flows": "플로우", "flows": "플로우",
"filterAll": "전체", "filterAll": "전체",
"showAllConfigNodes": "모든 설정 노드 보기",
"filterUnused": "미사용", "filterUnused": "미사용",
"showAllUnusedConfigNodes": "사용하지 않는 모든 설정 노드 보기",
"filtered": "__count__ 개 숨김" "filtered": "__count__ 개 숨김"
}, },
"context": { "context": {
@ -646,11 +506,8 @@
"empty": "공백", "empty": "공백",
"node": "노드", "node": "노드",
"flow": "플로우", "flow": "플로우",
"global": "글로벌", "global": "Global",
"deleteConfirm": "정말로 이 아이템을 지우시겠습니까?", "deleteConfirm": "정말로 이 아이템을 지우시겠습니까?"
"autoRefresh": "선택 변경 시 새로 고침",
"refrsh": "새로고침",
"delete": "삭제"
}, },
"palette": { "palette": {
"name": "팔레트 관리", "name": "팔레트 관리",
@ -665,7 +522,6 @@
"noSummaryAvailable": "요약 없음", "noSummaryAvailable": "요약 없음",
"editDescription": "프로젝트 상세내역 수정", "editDescription": "프로젝트 상세내역 수정",
"editDependencies": "프로젝트 의존성 수정", "editDependencies": "프로젝트 의존성 수정",
"noDescriptionAvailable": "설명 없음",
"editReadme": "README.md 수정", "editReadme": "README.md 수정",
"showProjectSettings": "프로젝트 설정 보이기", "showProjectSettings": "프로젝트 설정 보이기",
"projectSettings": { "projectSettings": {
@ -678,10 +534,6 @@
"files": "파일", "files": "파일",
"flow": "플로우", "flow": "플로우",
"credentials": "인증정보", "credentials": "인증정보",
"package": "Package",
"packageCreate": "변경 내용이 저장될 때 파일이 생성됩니다",
"fileNotExist": "파일이 존재하지 않습니다",
"selectFile": "파일 선택",
"invalidEncryptionKey": "잘못된 암호화 키", "invalidEncryptionKey": "잘못된 암호화 키",
"encryptionEnabled": "암호화 활성화", "encryptionEnabled": "암호화 활성화",
"encryptionDisabled": "암호화 비활성화", "encryptionDisabled": "암호화 비활성화",
@ -819,29 +671,15 @@
"bin": "buffer", "bin": "buffer",
"date": "timestamp", "date": "timestamp",
"jsonata": "expression", "jsonata": "expression",
"env": "env variable", "env": "env variable"
"cred": "credential"
} }
}, },
"editableList": { "editableList": {
"add": "추가", "add": "추가"
"addTitle": "add an item"
}, },
"search": { "search": {
"history": "Search history",
"clear": "clear all",
"empty": "결과 없음", "empty": "결과 없음",
"addNode": "노드 추가 ...", "addNode": "노드 추가 ..."
"options": {
"configNodes": "설정 노드",
"unusedConfigNodes": "사용되지 않는 설정 노드",
"invalidNodes": "잘못된 노드",
"uknownNodes": "알 수 없는 노드",
"unusedSubflows": "사용되지 않는 서브 플로우",
"hiddenFlows": "숨겨진 플로우",
"modifiedNodes": "수정된 노드 및 플로우",
"thisFlow": "현재 플로우"
}
}, },
"expressionEditor": { "expressionEditor": {
"functions": "기능", "functions": "기능",
@ -862,36 +700,15 @@
"eval": "형식 오류 :\n __message__" "eval": "형식 오류 :\n __message__"
} }
}, },
"monaco": {
"setTheme": "테마 설정"
},
"jsEditor": { "jsEditor": {
"title": "자바스크립트 에디터" "title": "자바스크립트 에디터"
}, },
"textEditor": {
"title": "텍스트 에디터"
},
"jsonEditor": { "jsonEditor": {
"title": "JSON 에디터", "title": "JSON 에디터",
"format": "JSON 형식", "format": "JSON 형식"
"rawMode": "JSON 수정",
"uiMode": "비주얼 편집기",
"rawMode-readonly": "JSON",
"uiMode-readonly": "비주얼",
"insertAbove": "위로 삽입",
"insertBelow": "아래로 삽입",
"addItem": "속성 추가",
"copyPath": "속성의 키값 복사",
"expandItems": "속성 펼치기",
"collapseItems": "속성 접기",
"duplicate": "복사",
"error": {
"invalidJSON": "비유효한 JSON: "
}
}, },
"markdownEditor": { "markdownEditor": {
"title": "Markdown 에디터", "title": "Markdown 에디터",
"expand": "Expand",
"format": "Markdown 형식", "format": "Markdown 형식",
"heading1": "제목 레벨1", "heading1": "제목 레벨1",
"heading2": "제목 레벨2", "heading2": "제목 레벨2",
@ -921,7 +738,6 @@
"desc2": "이 기능을 건너뛰어도 상관없습니다. 언제든지 프로젝트 메뉴에서 첫번째 프로젝트를 만들 수 있습니다.", "desc2": "이 기능을 건너뛰어도 상관없습니다. 언제든지 프로젝트 메뉴에서 첫번째 프로젝트를 만들 수 있습니다.",
"create": "프로젝트 생성", "create": "프로젝트 생성",
"clone": "프로젝트 복제", "clone": "프로젝트 복제",
"openExistingProject": "기존 프로젝트 열기",
"not-right-now": "나중에" "not-right-now": "나중에"
}, },
"git-config": { "git-config": {
@ -1039,8 +855,7 @@
"not-git": "git 저장소가 아닙니다", "not-git": "git 저장소가 아닙니다",
"no-resource": "저장소아 없습니다", "no-resource": "저장소아 없습니다",
"cant-get-ssh-key-path": "에러! 선택한 SSH키 경로를 가져올 수 없습니다.", "cant-get-ssh-key-path": "에러! 선택한 SSH키 경로를 가져올 수 없습니다.",
"unexpected_error": "예기치 않은 에러", "unexpected_error": "예기치 않은 에러"
"clearContext": "프로젝트 전환 시 context 삭제"
}, },
"delete": { "delete": {
"confirm": "프로젝트를 정말 지우시겠습니까?" "confirm": "프로젝트를 정말 지우시겠습니까?"
@ -1079,26 +894,7 @@
}, },
"editor-tab": { "editor-tab": {
"properties": "속성", "properties": "속성",
"envProperties": "환경 변수",
"module": "모듈 속성",
"description": "상세 내역", "description": "상세 내역",
"appearance": "모양", "appearance": "모양"
"preview": "UI 프리뷰",
"defaultValue": "기본값"
},
"tourGuide": {
"takeATour": "둘러보기",
"start": "시작",
"next": "다음",
"welcomeTours": "버전 별 릴리즈 정보"
},
"diagnostics": {
"title": "시스템 정보"
},
"contextMenu": {
"insert": "삽입",
"node": "노드",
"junction": "접합",
"linkNodes": "링크 노드"
} }
} }

View File

View File

@ -137,7 +137,7 @@
}, },
"$sort": { "$sort": {
"args": "array [, function]", "args": "array [, function]",
"desc": "배열 `array`의 모든 값을 순서대로 정렬하여 반환합니다.\n\n 비교함수 `function`을 이용하는 경우, 비교함수는 아래와 같은 두개의 인수를 가져야 합니다.\n\n `function(left,right)`\n\n 비교함수는 `left``right`의 두개의 값을 비교하기에, 값을 정렬하는 처리에서 호출됩니다. 만약 요구되는 정렬에서 left값을 `right`값보다 뒤로 두고싶은 경우에는, 비교함수는 치환을 나타내는 Boolean형의 `true`를, 그렇지 않은 경우에는 `false`를 반환해야 합니다." "desc": "배열 `array`의 모든 값을 순서대로 정렬하여 반환합니다. \n\n 비교함수 `function`을 이용하는 경우, 비교함수는 아래와 같은 두개의 인수를 가져야 합니다. \n\n `function(left,right)` \n\n 비교함수는 left와 right의 두개의 값을 비교하기에, 값을 정렬하는 처리에서 호출됩니다. 만약 요구되는 정렬에서 left값을 right값보다 뒤로 두고싶은 경우에는, 비교함수는 치환을 나타내는 Boolean형의 ``true`를, 그렇지 않은 경우에는 `false`를 반환해야 합니다."
}, },
"$reverse": { "$reverse": {
"args": "array", "args": "array",
@ -205,7 +205,7 @@
}, },
"$formatNumber": { "$formatNumber": {
"args": "number, picture [, options]", "args": "number, picture [, options]",
"desc": "`number`를 문자열로 변환하고 `picture` 문자열에 지정된 표현으로 서식을 변경합니다.\n\n 이 함수의 동작은 XPath F&O 3.1사양에 정의된 XPath/XQuery함수의 `fn:format-number`의 동작과 같습니다. 인수의 문자열 `picture``fn:format-number` 과 같은 구문으로 수치의 서식을 정의합니다.\n\n 임의의 제3 인수 `option`은 소수점기호와 같은 기본 로케일 고유의 서식설정문자를 덮어쓰는데에 사용됩니다. 이 인수를 지정할 경우, XPath F&O 3.1사양의 수치형식에 기술되어있는 name/value 쌍을 포함하는 오브젝트여야 합니다." "desc": "`number`를 문자열로 변환하고 `picture` 문자열에 지정된 표현으로 서식을 변경합니다. \n\n 이 함수의 동작은 XPath F&O 3.1사양에 정의된 XPath/XQuery함수의 fn:format-number의 동작과 같습니다. 인수의 문자열 picture은 fn:format-number 과 같은 구문으로 수치의 서식을 정의합니다. \n\n 임의의 제3 인수 `option`은 소수점기호와 같은 기본 로케일 고유의 서식설정문자를 덮어쓰는데에 사용됩니다. 이 인수를 지정할 경우, XPath F&O 3.1사양의 수치형식에 기술되어있는 name/value 쌍을 포함하는 오브젝트여야 합니다."
}, },
"$formatBase": { "$formatBase": {
"args": "number [, radix]", "args": "number [, radix]",

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
{
"info": {
"tip0": "Você pode remover os nós ou links selecionados com {{core:delete-selection}}",
"tip1": "Procure por nós usando {{core:search}}",
"tip2": "{{core:toggle-sidebar}} irá alternar a visualização desta barra lateral",
"tip3": "Você pode gerenciar sua paleta de nós com {{core:manage-palette}}",
"tip4": "Seus nós de configuração de fluxo são listados no painel da barra lateral. Pode ser acessado a partir do menu ou com{{core:show-config-tab}}",
"tip5": "Habilite ou desabilite essas dicas na opção nas configurações",
"tip6": "Mova os nós selecionados usando o [left] [up] [down] e [right] chaves. Segure [shift] para empurrá-los ainda mais",
"tip7": "Arrastar um nó para um fio o unirá no link",
"tip8": "Exporte os nós selecionados ou a guia atual com {{core:show-export-dialog}}",
"tip9": "Importe um fluxo arrastando seu JSON para o editor ou com {{core:show-import-dialog}}",
"tip10": "[shift] [click] e arraste em uma porta de nó para mover todos os fios conectados ou apenas o selecionado",
"tip11": "Mostre a guia Informações com {{core:show-info-tab}} ou a guia Depurar com {{core:show-debug-tab}}",
"tip12": "[ctrl] [click] na área de trabalho para abrir a caixa de diálogo de adição rápida",
"tip13": "Mantenha pressionado [ctrl] enquanto você [click] em uma porta de nó para habilitar a ligação rápida",
"tip14": "Mantenha pressionado [shift] enquanto você [click] em um nó para também selecionar todos os seus nós conectados",
"tip15": "Mantenha pressionado [ctrl] enquanto você [click] em um nó para adicioná-lo ou removê-lo da seleção atual",
"tip16": "Alternar guias de fluxo com {{core:show-previous-tab}} e {{core:show-next-tab}}",
"tip17": "Você pode confirmar suas alterações na bandeja de edição do nó com {{core:confirm-edit-tray}} ou cancele-os com {{core:cancel-edit-tray}}",
"tip18": "Pressionando {{core:edit-selected-node}} irá editar o primeiro nó na seleção atual"
}
}

View File

@ -1,274 +0,0 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "Converte o tipo do parâmetro `arg` em uma cadeia de caracteres usando as seguintes regras de conversão de tipo:\n\n - Cadeia de caracteres não são alteradas\n - As funções são convertidas para uma cadeia de caracteres vazia\n - os tipos numérico infinito e NaN geram um erro porque não podem ser representados como um número JSON\n - Todos os outros valores são convertidos para uma cadeia de caracteres JSON usando a função `JSON.stringify`. Se `prettify` for verdadeira, então o JSON \"prettified\" é produzido. Isto é, uma linha por campo e as linhas serão indentadas com base na profundidade do campo."
},
"$length": {
"args": "str",
"desc": "Retorna o número de caracteres na cadeia de caracteres `str`. Um erro é gerado se `str` não for uma cadeia de caracteres."
},
"$substring": {
"args": "str, start[, length]",
"desc": "Retorna uma cadeia de caracteres contendo os caracteres no primeiro parâmetro `str` começando na posição `start` (deslocamento zero). Se` length` for especificado, então a sub cadeia de caracteres conterá o máximo `length` de caracteres. Se` start` for negativo isso indica o número de caracteres a partir do fim de `str`."
},
"$substringBefore": {
"args": "str, chars",
"desc": "Retorna a sub cadeia de caracteres antes da primeira ocorrência da sequência de caracteres `chars` em `string`. Se` string` não contiver `chars`, então retorna `str`."
},
"$substringAfter": {
"args": "str, chars",
"desc": "Retorna a sub cadeia de caracteres após a primeira ocorrência da sequência de caracteres `chars` em `string`. Se `string` não contiver `chars`, então retorna `str`."
},
"$uppercase": {
"args": "str",
"desc": "Retorna uma cadeia de caracteres com todos os caracteres de `string` convertidos em maiúsculas."
},
"$lowercase": {
"args": "str",
"desc": "Retorna uma cadeia de caracteres com todos os caracteres de `string` convertidos em minúsculas."
},
"$trim": {
"args": "str",
"desc": "Normaliza e retira todos os caracteres de espaço em branco em `str` aplicando as seguintes etapas:\n\n - Todas as tabulações, retornos de carro e avanços de linha são substituídos por espaços.\n- Sequências contíguas de espaços são reduzidas a um único espaço.\n- Espaços à direita e à esquerda são removidos.\n\n Se `str` não for especificado (isto é, esta função é chamada sem argumentos), então o valor do contexto é usado como o valor de `str`. Um erro é gerado se `str` não for uma cadeia de caracteres."
},
"$contains": {
"args": "str, pattern",
"desc": "Retorna `true` se `str` tiver correspondente em `pattern`, caso contrário, retorna `false`. Se `str` não for especificado (isto é, esta função é chamada com um argumento), então o valor do contexto é usado como o valor de `str`. O parâmetro `pattern` pode ser uma cadeia de caracteres ou uma expressão regular."
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "Divide o parâmetro `str` em uma matriz de sub cadeia de caracteres. É um erro se `str` não for uma cadeia de caracteres. O parâmetro opcional `separator` especifica os caracteres dentro de `str` sobre os quais devem ser divididos como uma cadeia de caracteres ou expressão regular. Se `separator` não for especificado, a cadeia de caracteres vazia será assumida e `str` será dividido em uma matriz de caracteres únicos. É um erro se `separador` não for uma cadeia de caracteres. O parâmetro opcional `limit` é um número que especifica o número máximo de sub cadeia de caracteres a serem incluídas na matriz resultante. Quaisquer sub cadeia de caracteres adicionais são descartadas. Se `limit` não for especificado, então `str` será totalmente dividido sem limite para o tamanho da matriz resultante . É um erro se `limit` não for um número não negativo."
},
"$join": {
"args": "array[, separator]",
"desc": "Une uma matriz de cadeias de caracteres de componentes em uma única cadeia de caracteres concatenada com cada cadeia de caracteres de componente separada pelo parâmetro opcional `separator`. É um erro se a `matriz` de entrada contiver um item que não seja uma cadeia de caracteres. Se `separator` for não especificado, assume-se que é uma cadeia de caracteres vazia, ou seja, nenhum `separator` entre as cadeias de caracteres do componente. É um erro se `separator` não for uma cadeia de caracteres."
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "Aplica a cadeia de caracteres `str` à expressão regular `pattern` e retorna uma matriz de objetos, com cada objeto contendo informações sobre cada ocorrência de uma correspondência dentro de `str`."
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "Encontra ocorrências de `pattern` dentro de `str` e as substitui por `replacement`.\n\nO parâmetro opcional `limit` é o número máximo de substituições."
},
"$now": {
"args": "$[picture [, timezone]]",
"desc": "Gera um carimbo de data/hora em formato compatível com ISO 8601 e o retorna como uma cadeia de caracteres. Se os parâmetros opcionais de imagem e fuso horário forem fornecidos, o carimbo de data/hora atual é formatado conforme descrito pela função `$fromMillis()`"
},
"$base64encode": {
"args": "string",
"desc": "Converte uma cadeia de caracteres ASCII em uma representação de base 64. Cada caractere na cadeia de caracteres é tratado como um byte de dados binários. Isso requer que todos os caracteres na cadeia de caracteres estejam no intervalo de 0x00 a 0xFF, o que inclui todos os caracteres em cadeias de caracteres codificadas em URI. Caracteres Unicode fora desse intervalo não são suportados."
},
"$base64decode": {
"args": "string",
"desc": "Converte bytes codificados de base 64 em uma cadeia de caracteres, usando uma página de código UTF-8 Unicode."
},
"$number": {
"args": "arg",
"desc": "Converte o parâmetro `arg` em um número usando as seguintes regras de conversão:\n\n - Os números permanecem inalterados\n - Cadeias de caracteres que contêm uma sequência de caracteres que representam um número JSON válido são convertidos para esse número\n - Todos os outros valores causam a geração de um erro."
},
"$abs": {
"args": "number",
"desc": "Retorna o valor absoluto do parâmetro `number`."
},
"$floor": {
"args": "number",
"desc": "Retorna o valor de `number` arredondado para baixo para o inteiro mais próximo que seja menor ou igual a `number`."
},
"$ceil": {
"args": "number",
"desc": "Retorna o valor de `number` arredondado para o número inteiro mais próximo que é maior ou igual a `number`."
},
"$round": {
"args": "number [, precision]",
"desc": "Retorna o valor do parâmetro `number` arredondado para o número de casas decimais especificado pelo parâmetro opcional `precision`."
},
"$power": {
"args": "base, exponent",
"desc": "Retorna o valor de `base` elevado à potência de `exponent`."
},
"$sqrt": {
"args": "number",
"desc": "Retorna a raiz quadrada do valor do parâmetro `number`."
},
"$random": {
"args": "",
"desc": "Retorna um número pseudoaleatório maior ou igual a zero e menor que um."
},
"$millis": {
"args": "",
"desc": "Retorna o número de milissegundos desde o Unix Epoch (1º de janeiro de 1970 UTC) como um número. Todas as invocações de `$millis()` dentro de uma avaliação de uma expressão retornarão todas o mesmo valor."
},
"$sum": {
"args": "array",
"desc": "Retorna a soma aritmética de uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número."
},
"$max": {
"args": "array",
"desc": "Retorna o número máximo em uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número."
},
"$min": {
"args": "array",
"desc": "Retorna o número mínimo em uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número."
},
"$average": {
"args": "array",
"desc": "Retorna o valor médio de uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número."
},
"$boolean": {
"args": "arg",
"desc": "Converte o argumento em um booliano usando as seguintes regras:\n\n - `Boolean` : inalterado\n - `string`: vazio : `false`\n - `string`: não-vazio : `true`\n - `number`: `0` : `false`\n - `number`: não-zero : `true`\n - `null` : `false`\n - `array`: vazio : `false`\n - `array`: contém um membro que converte de tipo para `true` : `true`\n - `array`: todos os membros convertidos de tipo para `false` : `false`\n - `object`: vazio : `false`\n - `object`: não-vazio : `true`\n - `function` : `false`"
},
"$not": {
"args": "arg",
"desc": "Retorna booliano NOT no argumento. `Arg` é convertido de tipo primeiro para um booliano"
},
"$exists": {
"args": "arg",
"desc": "Retorna booliano `true` se a expressão `arg` for avaliada como um valor, ou `false` se a expressão não corresponder a nada (por exemplo, um caminho para uma referência de campo inexistente)."
},
"$count": {
"args": "array",
"desc": "Retorna o número de itens na matriz"
},
"$append": {
"args": "array, array",
"desc": "Anexa duas matrizes"
},
"$sort": {
"args": "array [, function]",
"desc": "Retorna uma matriz contendo todos os valores no parâmetro `array`, mas classificados em ordem.\n\nSe um comparador `function` for fornecido, então deve ser uma função que leva dois parâmetros:\n\n`function(left, right)`\n\nEsta função é invocada pelo algoritmo de classificação para comparar dois valores à esquerda e à direita. Se o valor de esquerda deve ser colocado após o valor de direita na ordem de classificação desejada, a função deve retornar o booliano `true` para indicar uma troca. Caso contrário, deve retornar `false`."
},
"$reverse": {
"args": "array",
"desc": "Retorna uma matriz contendo todos os valores do parâmetro `array`, mas na ordem reversa."
},
"$shuffle": {
"args": "array",
"desc": "Retorna uma matriz contendo todos os valores do parâmetro `array`, mas misturados em ordem aleatória."
},
"$zip": {
"args": "array, ...",
"desc": "Retorna uma matriz convolucional (compactada) contendo matrizes agrupadas de valores dos argumentos `array1`… `arrayN` do índice 0, 1, 2 ...."
},
"$keys": {
"args": "object",
"desc": "Retorna uma matriz contendo as chaves do objeto. Se o argumento for uma matriz de objetos, então a matriz retornada contém uma lista não duplicada de todas as chaves em todos os objetos."
},
"$lookup": {
"args": "object, key",
"desc": "Retorna o valor associado à chave no objeto. Se o primeiro argumento for uma matriz de objetos, todos os objetos na matriz são pesquisados e os valores associados a todas as ocorrências da chave são retornados."
},
"$spread": {
"args": "object",
"desc": "Divide um objeto que contém pares de chave/valor em uma matriz de objetos, cada um com um único par de chave/valor do objeto de entrada. Se o parâmetro for uma matriz de objetos, a matriz resultante conterá um objeto para cada par de chave/valor em todo objeto na matriz fornecida."
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "Mescla uma matriz de `objects` em um único `object` contendo todos os pares de chave/valor de cada um dos objetos na matriz de entrada. Se qualquer um dos objetos de entrada contiver a mesma chave, então o `object` retornado conterá o valor do último na matriz. É um erro se a matriz de entrada contiver um item que não seja um objeto."
},
"$sift": {
"args": "object, function",
"desc": "Retorna um objeto que contém apenas os pares de chave/valor do parâmetro `object` que satisfazem o predicado `function` passado como o segundo parâmetro.\n\nA `function` que é fornecida como o segundo parâmetro deve ter o seguinte assinatura:\n\n`function(value [, key [, object]])`"
},
"$each": {
"args": "object, function",
"desc": "Retorna uma matriz contendo os valores retornados por `function` quando aplicado a cada par chave/valor no `object`."
},
"$map": {
"args": "array, function",
"desc": "Retorna uma matriz contendo os resultados da aplicação do parâmetro `function` a cada valor no parâmetro `array`.\n\nA `function` que é fornecido como o segundo parâmetro deve ter a seguinte assinatura:\n\n`function(value [, index [, array]])`"
},
"$filter": {
"args": "array, function",
"desc": "Retorna uma matriz contendo apenas os valores no parâmetro `array` que satisfazem o predicado `function`.\n\nThe `function` que é fornecido como o segundo parâmetro deve ter a seguinte assinatura:\n\n`function(value [, index [, array]])`"
},
"$reduce": {
"args": "array, function [, init]",
"desc": "Retorna um valor agregado derivado da aplicação do parâmetro `function` sucessivamente a cada valor em `array` em combinação com o resultado da aplicação anterior da função.\n\nA função deve aceitar dois argumentos e se comportar como um operador inserido entre cada valor dentro de `array`. A assinatura da `function` deve estar no formato: `myfunc($accumulator, $value[, $index[, $array]])`\n\nO parâmetro opcional `init` é usado como o valor inicial na agregação."
},
"$flowContext": {
"args": "string[, string]",
"desc": "Recupera uma propriedade de contexto de fluxo.\n\nEsta é uma função definida pelo Node-RED."
},
"$globalContext": {
"args": "string[, string]",
"desc": "Recupera uma propriedade de contexto global.\n\nEsta é uma função definida pelo Node-RED."
},
"$pad": {
"args": "string, width [, char]",
"desc": "Retorna uma cópia da `string` com preenchimento extra, se necessário, de forma que seu número total de caracteres seja pelo menos o valor absoluto do parâmetro `width`.\n\nSe `width` for um número positivo, a cadeia de caracteres será preenchida à direita; se negativo, é preenchida à esquerda.\n\nO argumento opcional `char` especifica os caracteres de preenchimento a serem usados. Se não for especificado, o padrão é o caractere de espaço."
},
"$fromMillis": {
"args": "number, [, picture [, timezone]]",
"desc": "Converta o `number` que representa os milissegundos desde a época do Unix (1 January, 1970 UTC) em uma representação de cadeia de caracteres formatada do carimbo de data/hora conforme especificado pela cadeia de caracteres de imagem.\n\nSe o parâmetro opcional `image` for omitido, o carimbo de data/hora será formatado no formato ISO 8601.\n\nSe a cadeia de caracteresopcional `picture` for fornecida, o carimbo de data/hora é formatado de acordo com a representação especificada nessa cadeia de caracteres. O comportamento desta função é consistente com a versão de dois argumentos da função XPath/XQuery `format-dateTime` conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o carimbo de data/hora é formatado e tem a mesma sintaxe de `format-dateTime`.\n\nSe a cadeia de caracteres opcional `timezone` for fornecida, o carimbo de data/hora formatado estará nesse fuso horário. A cadeia de caracteres `timezone` deve estar no formato '± HHMM', onde ± é o sinal de mais ou menos e HHMM é o deslocamento em horas e minutos do UTC. Deslocamento positivo para fusos horários a leste do UTC, deslocamento negativo para fusos horários a oeste do UTC."
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação decimal conforme especificado pela cadeia de caracteres `picture`.\n\n O comportamento desta função é consistente com a função XPath/XQuery `fn:format-number` conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de `fn:format-number`.\n\nO terceiro argumento opcional `options` é usado para substituir os caracteres de formatação específicos da localidade padrão, como o separador decimal. Se fornecido, este argumento deve ser um objeto contendo pares de nome/valor especificados na seção de formato decimal da especificação XPath F&O 3.1."
},
"$formatBase": {
"args": "number [, radix]",
"desc": "Converte o `number` em uma cadeia de caracteres e o formata em um inteiro representado na base do número especificada pelo argumento `radix`. Se `radix` não for especificado, o padrão é a base 10. `radix` pode estar entre 2 e 36, caso contrário, um erro será gerado."
},
"$toMillis": {
"args": "timestamp",
"desc": "Converta o tipo de uma cadeia de caracteres `timestamp` no formato ISO 8601 para o número de milissegundos desde a época do Unix (1 January, 1970 UTC) como um número. Um erro é gerado se a cadeia de caracteres não estiver no formato correto."
},
"$env": {
"args": "arg",
"desc": "Retorna o valor de uma variável de ambiente.\n\nEsta é uma função definida pelo Node-RED."
},
"$eval": {
"args": "expr [, context]",
"desc": "Analisa e avalia a cadeia de caracteres `expr` que contém um JSON literal ou uma expressão JSONata usando o contexto atual como o contexto para avaliação."
},
"$formatInteger": {
"args": "number, picture",
"desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação inteira conforme especificado pela cadeia de caracteres `picture`. O parâmetro da cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de `fn:format-integer` do Especificação XPath F&O 3.1."
},
"$parseInteger": {
"args": "string, picture",
"desc": "Examina e troca o conteúdo do parâmetro `string` para um inteiro (como um número JSON) usando o formato especificado pela cadeia de caracteres `picture`. O parâmetro da cadeia de caracteres `picture` tem o mesmo formato que `$formatInteger`."
},
"$error": {
"args": "[str]",
"desc": "Gera um erro com uma mensagem. O (parâmetro) opcional `str` substituirá a mensagem padrão de `$error() function evaluated`"
},
"$assert": {
"args": "arg, str",
"desc": "Se `arg` for verdadeiro, a função retorna indefinido. Se `arg` for falso, uma exceção é gerada com `str` como a mensagem da exceção."
},
"$single": {
"args": "array, function",
"desc": "Retorna o único valor no parâmetro `array` que satisfaz o predicado `function` (isto é, O (parâmetro) `function` retorna o booliano `true` quando passado o valor). Gera uma exceção se o número de valores correspondentes não for exatamente um .\n\nA função deve ser fornecida na seguinte assinatura: `function(value [, index [, array]])` onde 'value' é cada entrada da matriz, 'index' é a posição desse valor e toda a matriz é passada como o terceiro argumento"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Codifica um componente Localizador Uniforme de Recursos (URL) substituindo cada instância de certos caracteres por uma, duas, três ou quatro sequências de escape que representam a codificação UTF-8 do caractere.\n\nExemplo: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrl": {
"args": "str",
"desc": "Codifica um Localizador Uniforme de Recursos (URL) substituindo cada instância de certos caracteres por uma, duas, três ou quatro sequências de escape que representam a codificação UTF-8 do caractere.\n\nExemplo: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "Decodifica um componente Localizador Uniforme de Recursos (URL) criado anteriormente por encodeUrlComponent.\n\nExemplo: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "Decodifica um Localizador Uniforme de Recursos (URL) criado anteriormente por encodeUrl.\n\nExemplo: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "Retorna uma matriz com valores duplicados removidos da `array`"
},
"$type": {
"args": "value",
"desc": "Retorna o tipo de `value` como uma cadeia de caracteres. Se `value` for indefinido, retornará `undefined`"
},
"$moment": {
"args": "[str]",
"desc": "Obtém um objeto de dados usando a biblioteca 'Moment'."
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
{
"info": {
"tip0" : "Вы можете удалить выбранные узлы или провода с {{core:delete-selection}}",
"tip1" : "Ищите узлы с {{core:search}}",
"tip2" : "{{core:toggle-sidebar}} показывает/скрывает эту боковою панель",
"tip3" : "Вы можете управлять палитрой узлов с помощью {{core:manage-palette}}",
"tip4" : "Узлы конфигурации потока перечисляются на боковой панели. Доступ к списку можно получить из меню или с помощью {{core:show-config-tab}}",
"tip5" : "Эти советы можно включить/выключить через настройки",
"tip6" : "Перемещайте выбранные узлы клавишами [влево] [вверх] [вниз] и [вправо]. Удерживайте [Shift], чтобы увеличить шаг",
"tip7" : "Перетаскивание узла на провод соединит его с обеих сторон",
"tip8" : "Экспортируйте выбранные узлы или текущую вкладку с {{core:show-export-dialog}}",
"tip9" : "Импортируйте поток, перетаскивая его JSON в редактор или с помощью {{core:show-import-dialog}}",
"tip10" : "Нажмите [Shift], [кликните] по порту узла и перетаскивайте подключенные провода на другой узел",
"tip11" : "Открывайте вкладку Информация с {{core:show-info-tab}} или вкладку Отладка с {{core:show-debug-tab}}",
"tip12" : "Нажмите [ctrl] и [кликните] в рабочей области, чтобы открыть диалог быстрого добавления",
"tip13" : "Нажмите [ctrl] и [кликните] по порту узла, чтобы начать быстрое подключение",
"tip14" : "Нажмите [Shift] и [кликните] по узлу, чтобы выбрать все соединенные узлы",
"tip15" : "Нажмите [ctrl] и [кликните] по узлу, чтобы добавить или убрать его из текущего выбора",
"tip16" : "Переключайте вкладки потока с помощью {{core:show-previous-tab}} и {{core:show-next-tab}}",
"tip17" : "Вы можете подтвердить изменения в редакторе узла с {{core:confirm-edit-tray}} или отменить их с {{core:cancel-edit-tray}}",
"tip18" : "Нажатие {{core:edit-selected-node}} откроет редактор первого узла в текущем выборе"
}
}

View File

@ -1,274 +0,0 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "Преобразует параметр `arg` в строку, используя следующие правила приведения:\n\n - Строки возвращаются как есть\n - Функции преобразуются в пустую строку\n - Числовая бесконечность и NaN выдают ошибку, поскольку они не могут быть представлены числом в JSON\n - Все остальные значения преобразуются в строку JSON с помощью функции `JSON.stringify`. Если значение `prettify` равно true, тогда будет сгенерирован \"отформатированный\" JSON. То есть каждое поле будет в отдельной строке, а строки будут иметь отступ в зависимости от глубины поля."
},
"$length": {
"args": "str",
"desc": "Возвращает количество символов в строке `str`. Выдается ошибка, если `str` не является строкой."
},
"$substring": {
"args": "str, start[, length]",
"desc": "Возвращает строку, содержащую символы из первого параметра `str`, начиная с позиции `start` (отсчет с нуля). Если указан `length`, то подстрока будет содержать максимум `length` символов. Если `start` отрицателен, то это означает количество символов с конца `str`."
},
"$substringBefore": {
"args": "str, chars",
"desc": "Возвращает подстроку перед первым вхождением последовательности символов `chars` в строке `str`. Если `str` не содержит `chars`, то он возвращает `str`."
},
"$substringAfter": {
"args": "str, chars",
"desc": "Возвращает подстроку после первого вхождения последовательности символов `chars` в строке `str`. Если `str` не содержит `chars`, то он возвращает `str`."
},
"$uppercase": {
"args": "str",
"desc": "Возвращает строку со всеми символами `str`, преобразованными в верхний регистр."
},
"$lowercase": {
"args": "str",
"desc": "Возвращает строку со всеми символами `str`, преобразованными в нижний регистр."
},
"$trim": {
"args": "str",
"desc": "Нормализует и обрезает все пробельные символы в строке `str`, выполняя следующие шаги:\n\n - Все символы табуляции, возврата каретки и перевода строки заменяются пробелами.\n- Последовательности пробелов сокращаются до одного пробела.\n- Пробелы в начале и конце `str` удаляются.\n\n Если `str` не указан (то есть эта функция вызывается без аргументов), тогда значение контекста используется в качестве значения `str`. Выдается ошибка, если `str` не является строкой."
},
"$contains": {
"args": "str, pattern",
"desc": "Возвращает `true`, если строка `str` соответствует шаблону `pattern`, в противном случае возвращает `false`. Если `str` не указан (то есть эта функция вызывается с одним аргументом), то значение контекста используется как значение `str`. Параметр `pattern` может быть либо строкой, либо регулярным выражением."
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "Разбивает строку `str` на массив подстрок. Выдает ошибку, если `str` не является строкой. Необязательный параметр `separator` (строка или регулярное выражение) указывает символы внутри строки `str`, относительно которых она должна быть разделена. Если `separator` не указан, то предполагается пустая строка, и `str` будет разбит на массив из отдельных символов. Выдает ошибку, если `separator` не является строкой. Необязательный параметр `limit` - это число, указывающее максимальное количество подстрок для включения в результирующий массив. Любые дополнительные подстроки отбрасываются. Если `limit` не указан, то весь `str` разделяется без ограничения размера результирующего массива. Выдает ошибку, если `limit` не является положительным числом."
},
"$join": {
"args": "array[, separator]",
"desc": "Объединяет массив подстрок в одну объединенную строку, в которой каждая подстрока отделена необязательным параметром `separator`. Выдает ошибку, если входной массив содержит элемент, который не является строкой. Если `separator` не указан, то предполагается, что это пустая строка, то есть нет `separator` между подстроками. Выдает ошибку, если `separator` не является строкой."
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "Применяет строку `str` к регулярному выражению `pattern` и возвращает массив объектов, каждый из которых содержит информацию о каждом совпадении внутри `str`."
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "Находит вхождения шаблона `pattern` в строке `str` и заменяет их на строку `replacement`.\n\nНеобязательный параметр `limit` - это максимальное количество замен."
},
"$now": {
"args": "",
"desc": "Создает отметку времени в формате, совместимом с ISO 8601, и возвращает ее как строку."
},
"$base64encode": {
"args": "string",
"desc": "Преобразует ASCII-строку в base-64 кодировку. Каждый символ в строке обрабатывается как байт двоичных данных. Для этого необходимо, чтобы все символы в строке находились в диапазоне от 0x00 до 0xFF, который включает все символы строк в URI-кодировке. Символы Юникода за пределами этого диапазона не поддерживаются."
},
"$base64decode": {
"args": "string",
"desc": "Преобразует байты в кодировке base-64 в строку, используя кодовую страницу Юникод UTF-8."
},
"$number": {
"args": "arg",
"desc": "Преобразует параметр `arg` в число с использованием следующих правил приведения:\n\n - Числа возвращаются как есть\n - Строки, которые содержат последовательность символов, представляющих допустимое в JSON число, преобразуются в это число\n - Все остальные значения вызывают ошибку."
},
"$abs": {
"args": "number",
"desc": "Возвращает абсолютное значение числа `number`."
},
"$floor": {
"args": "number",
"desc": "Возвращает значение числа `number`, округленное до ближайшего целого числа, которое меньше или равно `number`."
},
"$ceil": {
"args": "number",
"desc": "Возвращает значение числа `number`, округленное до ближайшего целого числа, которое больше или равно `number`."
},
"$round": {
"args": "number [, precision]",
"desc": "Возвращает значение числа `number`, округленное до количества десятичных знаков, указанных необязательным параметром `precision`."
},
"$power": {
"args": "base, exponent",
"desc": "Возвращает значение числа `base`, возведенное в степень `exponent`."
},
"$sqrt": {
"args": "number",
"desc": "Возвращает квадратный корень из значения числа `number`."
},
"$random": {
"args": "",
"desc": "Возвращает псевдослучайное число, которе больше или равно нулю и меньше единицы."
},
"$millis": {
"args": "",
"desc": "Возвращает число миллисекунд с начала Unix-эпохи (1 января 1970 года по Гринвичу) в виде числа. Все вызовы `$millis()` в пределах выполнения выражения будут возвращать одно и то же значение."
},
"$sum": {
"args": "array",
"desc": "Возвращает арифметическую сумму массива чисел `array`. Вызывает ошибку, если входной массив `array` содержит элемент, который не является числом."
},
"$max": {
"args": "array",
"desc": "Возвращает максимальное число в массиве чисел `array`. Вызывает ошибку, если входной массив `array` содержит элемент, который не является числом."
},
"$min": {
"args": "array",
"desc": "Возвращает минимальное число в массиве чисел `array`. Вызывает ошибку, если входной массив `array` содержит элемент, который не является числом."
},
"$average": {
"args": "array",
"desc": "Возвращает среднее значение массива чисел `array`. Вызывает ошибку, если входной массив `array` содержит элемент, который не является числом."
},
"$boolean": {
"args": "arg",
"desc": "Приводит аргумент к логическому значению, используя следующие правила:\n\n - Логические значения возвращаются как есть\n - пустая строка: `false`\n - непустая строка: `true`\n - число равное `0`: `false`\n - ненулевое число: `true`\n - `null` : `false`\n - пустой массив: `false`\n - массив, который содержит хотя бы один элемент, приводимый к `true`: `true`\n - массив, все элементы которого приводятся к `false`: `false`\n - пустой объект: `false`\n - непустой объект: `true`\n - функция: `false`"
},
"$not": {
"args": "arg",
"desc": "Возвращает логическое НЕ для аргумента. `arg` сначала приводится к логическому значению"
},
"$exists": {
"args": "arg",
"desc": "Возвращает логическое `true`, если выполнение выражения `arg` возвращает значение, или `false`, если выражение ничему не соответствует (например, путь к несуществующему полю)."
},
"$count": {
"args": "array",
"desc": "Возвращает количество элементов в массиве"
},
"$append": {
"args": "array, array",
"desc": "Присоединяет один массив к другому"
},
"$sort": {
"args": "array [, function]",
"desc": "Возвращает массив, содержащий все значения параметра `array`, но отсортированные по порядку.\n\nЕсли указан компаратор `function`, то это должна быть функция, которая принимает два параметра:\n\n`function(val1, val2)`\n\nЭту функцию вызывает алгоритм сортировки для сравнения двух значений: val1 и val2. Если значение val1 следует поместить после значения val2 в желаемом порядке сортировки, то функция должна возвращать логическое значение `true`, чтобы обозначить замену. В противном случае она должна вернуть `false`."
},
"$reverse": {
"args": "array",
"desc": "Возвращает массив, содержащий все значения из параметра `array`, но в обратном порядке."
},
"$shuffle": {
"args": "array",
"desc": "Возвращает массив, содержащий все значения из параметра `array`, но перемешанный в случайном порядке."
},
"$zip": {
"args": "array, ...",
"desc": "Возвращает свернутый (сжатый) массив, содержащий сгруппированные массивы значений из аргументов `array1` … `arrayN` по индексам 0, 1, 2...."
},
"$keys": {
"args": "object",
"desc": "Возвращает массив, содержащий ключи объекта. Если аргумент является массивом объектов, то возвращаемый массив содержит недублированный список всех ключей из всех объектов."
},
"$lookup": {
"args": "object, key",
"desc": "Возвращает значение, связанное с ключом в объекте. Если первый аргумент является массивом объектов, то просходит поиск по всем объектам в массиве, и возвращаются значения, связанные со всеми вхождениями ключа."
},
"$spread": {
"args": "object",
"desc": "Разбивает объект, содержащий пары ключ / значение, на массив объектов, каждый из которых имеет одну пару ключ / значение из входного объекта. Если параметр является массивом объектов, то результирующий массив содержит объект для каждой пары ключ / значение из каждого объекта предоставленного массива."
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "Объединяет массив объектов в один объект, содержащий все пары ключ / значение каждого из объектов входного массива. Если какой-либо из входных объектов содержит один и тот же ключ, возвращаемый объект будет содержать значение последнего в массиве. Вызывает ошибку, если входной массив содержит элемент, который не является объектом."
},
"$sift": {
"args": "object, function",
"desc": "Возвращает объект, который содержит только пары ключ / значение из параметра `object`, которые удовлетворяют предикату `function`, переданному в качестве второго параметра.\n\n`function`, которая передается в качестве второго параметра, должна иметь следующую сигнатуру:\n\n`function(value [, key [, object]])`"
},
"$each": {
"args": "object, function",
"desc": "Возвращает массив, который содержит значения, возвращаемые функцией `function` при применении к каждой паре ключ/значение из объекта `object`."
},
"$map": {
"args": "array, function",
"desc": "Возвращает массив, содержащий результаты применения функции `function` к каждому значению массива `array`.\n\nФункция `function`, указанная в качестве второго параметра, должна иметь следующую сигнатуру:\n\n`function(value [, index [, array]])`"
},
"$filter": {
"args": "array, function",
"desc": "Возвращает массив, содержащий только те значения из массива `array`, которые удовлетворяют предикату `function`.\n\nФункция `function`, указанная в качестве второго параметра, должна иметь следующую сигнатуру:\n\n`function(value [, index [, array]])`"
},
"$reduce": {
"args": "array, function [, init]",
"desc": "Возвращает агрегированное значение, полученное в результате последовательного применения функции `function` к каждому значению в массиве в сочетании с результатом от предыдущего применения функции.\n\nФункция должна принимать два аргумента и вести себя как инфиксный оператор между каждым значением в массиве `array`. Сигнатура `function` должна иметь форму: `myfunc($accumulator, $value[, $index[, $array]])`\n\nНеобязательный параметр `init` используется в качестве начального значения в агрегации."
},
"$flowContext": {
"args": "string[, string]",
"desc": "Извлекает свойство контекста потока.\n\nЭто функция от Node-RED."
},
"$globalContext": {
"args": "string[, string]",
"desc": "Извлекает свойство глобального контекста.\n\nЭто функция от Node-RED."
},
"$pad": {
"args": "string, width [, char]",
"desc": "Возвращает копию строки `string` с дополнительным заполнением, если необходимо, чтобы общее количество символов как минимум соответствовало абсолютному значению параметра `width`.\n\nЕсли `width` является положительным числом, то строка дополняется справа; если отрицательным, то дополняется слева.\n\nНеобязательный аргумент `char` указывает символ(ы) для заполнения. Если не указано, по умолчанию используется пробел."
},
"$fromMillis": {
"args": "number",
"desc": "Преобразует число, представляющее миллисекунды с начала Unix-эпохи (1 января 1970 года по Гринвичу), в строку отметки времени в формате ISO 8601."
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "Преобразует число `number` в строку и форматирует ее в десятичное представление, как указано в строке `picture`.\n\nПоведение этой функции соответствует XPath/XQuery-функции fn:format-number, как определено в спецификация XPath F&O 3.1. Строка `picture` определяет, как форматируется число и имеет тот же синтаксис, что и fn:format-number.\n\nНеобязательный третий аргумент `options` используется для переопределения символов форматирования, специфичных для локали по умолчанию, таких как десятичный разделитель. Если аргумент указан, то это должен быть объект, содержащий пары имя/значение, указанные в разделе десятичного формата спецификации XPath F&O 3.1."
},
"$formatBase": {
"args": "number [, radix]",
"desc": "Преобразует число `number` в строку и форматирует ее в целое число, представленное в системе счисления, указанной аргументом `radix`. Если `radix` не указан, то по умолчанию используется десятичная. Значение 'radix` может быть от 2 до 36, в противном случае выдается ошибка."
},
"$toMillis": {
"args": "timestamp",
"desc": "Преобразует строку `timestamp` в формате ISO 8601 в число миллисекунд с начала Unix-эпохи (1 января 1970 года по Гринвичу). Вызывает ошибку, если строка в неправильном формате."
},
"$env": {
"args": "arg",
"desc": "Возвращает значение переменной среды.\n\nЭто функция от Node-RED."
},
"$eval": {
"args": "expr [, context]",
"desc": "Анализирует и исполняет строку `expr`, которая содержит JSON или выражение JSONata, используя текущий контекст в качестве контекста для исполнения."
},
"$formatInteger": {
"args": "number, picture",
"desc": "Преобразует число `number` в строку и форматирует ее в целочисленное представление, как указано в строке `picture`. Строка `picture` определяет, как форматируется число и имеет тот же синтаксис, что и `fn:format-integer` из спецификации XPath F&O 3.1."
},
"$parseInteger": {
"args": "string, picture",
"desc": "Разбирает содержимое строки `string` в целое число (как число JSON), используя формат, указанный в строке `picture`. Строковый параметр `picture` имеет тот же формат, что и `$formatInteger`."
},
"$error": {
"args": "[str]",
"desc": "Вызывает ошибку с сообщением. Необязательная строка `str` заменяет сообщение по умолчанию $error() function evaluated`"
},
"$assert": {
"args": "arg, str",
"desc": "Если значение `arg` равно `true`, функция возвращает значение undefined. Если значение `arg` равно `false`, генерируется исключение с `str` в качестве сообщения об исключении."
},
"$single": {
"args": "array, function",
"desc": "Возвращает одно-единственное значение из массива `array`, которое удовлетворяет предикату `function` (то есть когда `function` возвращает логическое `true` при передаче значения). Выдает исключение, если число подходящих значений не одно.\n\nФункция должна соответствовать следующей сигнатуре: `function(value [, index [, array]])` где value - элемент массива, index - позиция этого значения, а весь массив передается в качестве третьего аргумента"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Кодирует компонент Uniform Resource Locator (URL), заменяя каждый экземпляр определенных символов одной, двумя, тремя или четырьмя escape-последовательностями, представляющими кодировку UTF-8 символа.\n\nПример: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrl": {
"args": "str",
"desc": "Кодирует Uniform Resource Locator (URL), заменяя каждый экземпляр определенных символов одной, двумя, тремя или четырьмя escape-последовательностями, представляющими кодировку UTF-8 символа.\n\nПример: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "Декодирует компонент Uniform Resource Locator (URL), ранее созданный с помощью encodeUrlComponent.\n\nПример: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "Декодирует компонент Uniform Resource Locator (URL), ранее созданный с помощью encodeUrl.\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": "Возвращает массив содержащий все элементы из массива `array`, с удаленными дупликатами"
},
"$type": {
"args": "value",
"desc": "Возвращает тип значения `value` в виде строки. Если `value` не определено, то будет возвращено `undefined`"
},
"$moment": {
"args": "[str]",
"desc": "Получает date объект, используя библиотеку Moment."
}
}

View File

@ -1,7 +1,7 @@
{ {
"common": { "common": {
"label": { "label": {
"name": "", "name": "名",
"ok": "确认", "ok": "确认",
"done": "完成", "done": "完成",
"cancel": "取消", "cancel": "取消",
@ -15,19 +15,14 @@
"next": "下一个", "next": "下一个",
"clone": "克隆项目", "clone": "克隆项目",
"cont": "继续", "cont": "继续",
"style": "样式", "style": "风格",
"line": "大纲", "line": "大纲",
"fill": "填充", "fill": "填充",
"label": "标签", "label": "标签",
"color": "颜色", "color": "颜色",
"position": "位置", "position": "位置",
"enable": "启用", "enable": "启用",
"disable": "禁用", "disable": "禁用"
"upload": "上传",
"lock": "锁定",
"unlock": "解锁",
"locked": "锁定",
"unlocked": "解锁"
}, },
"type": { "type": {
"string": "字符串", "string": "字符串",
@ -42,14 +37,11 @@
} }
}, },
"event": { "event": {
"loadPlugins": "加载插件",
"loadPalette": "加载控制板", "loadPalette": "加载控制板",
"loadNodeCatalogs": "加载节点目录", "loadNodeCatalogs": "加载节点目录",
"loadNodes": "加载 __count__ 个节点", "loadNodes": "加载 __count__ 个节点",
"loadFlows": "加载流程", "loadFlows": "加载流程",
"importFlows": "往工作区中加载流程", "importFlows": "往工作区中加载流程"
"importError": "<p>加载流程错误</p><p>__message__</p>",
"loadingProject": "加载项目"
}, },
"workspace": { "workspace": {
"defaultName": "流程 __number__", "defaultName": "流程 __number__",
@ -58,35 +50,18 @@
"delete": "你确定要删除 __label__ ?", "delete": "你确定要删除 __label__ ?",
"dropFlowHere": "把流程放到这里", "dropFlowHere": "把流程放到这里",
"addFlow": "添加流程", "addFlow": "添加流程",
"addFlowToRight": "在右侧新增流程",
"hideFlow": "隐藏流程",
"hideOtherFlows": "隐藏其它流程",
"showAllFlows": "显示所有流程",
"hideAllFlows": "隐藏所有流程",
"hiddenFlows": "列出 __count__ 个隐藏流程",
"hiddenFlows_plural": "列出 __count__ 个隐藏流程",
"showLastHiddenFlow": "显示最后一个隐藏流程",
"listFlows": "流程一览", "listFlows": "流程一览",
"listSubflows": "列出子流程",
"status": "状态", "status": "状态",
"enabled": "有效", "enabled": "有效",
"disabled": "无效", "disabled": "无效",
"info": "详细描述", "info": "详细描述",
"selectNodes": "点击节点来选择", "selectNodes": "点击节点来选择"
"enableFlow": "启用流程",
"disableFlow": "禁用流程",
"lockFlow": "锁定流程",
"unlockFlow": "解除锁定",
"moveToStart": "移动到起始",
"moveToEnd": "移动到末尾"
}, },
"menu": { "menu": {
"label": { "label": {
"view": { "view": {
"view": "显示", "view": "显示",
"grid": "网格", "grid": "网格",
"storeZoom": "加载时还原缩放尺寸",
"storePosition": "加载时还原滚动位置",
"showGrid": "显示网格", "showGrid": "显示网格",
"snapGrid": "对齐网格", "snapGrid": "对齐网格",
"gridSize": "网格尺寸", "gridSize": "网格尺寸",
@ -104,14 +79,12 @@
"palette": { "palette": {
"show": "显示控制板" "show": "显示控制板"
}, },
"edit": "编辑",
"settings": "设置", "settings": "设置",
"userSettings": "用户设置", "userSettings": "用户设置",
"nodes": "节点", "nodes": "节点",
"displayStatus": "显示节点状态", "displayStatus": "显示节点状态",
"displayConfig": "修改节点配置", "displayConfig": "修改节点配置",
"import": "导入", "import": "导入",
"importExample": "导入示例流程",
"export": "导出", "export": "导出",
"search": "查找流程", "search": "查找流程",
"searchInput": "查找流程", "searchInput": "查找流程",
@ -120,81 +93,53 @@
"selectionToSubflow": "将选择部分更改为子流程", "selectionToSubflow": "将选择部分更改为子流程",
"flows": "流程", "flows": "流程",
"add": "增加", "add": "增加",
"rename": "重命名",
"delete": "删除", "delete": "删除",
"keyboardShortcuts": "键盘快捷方式", "keyboardShortcuts": "键盘快捷方式",
"login": "登录", "login": "登陆",
"logout": "退出", "logout": "退出",
"editPalette": "节点管理", "editPalette": "节点管理",
"other": "其他", "other": "其他",
"showTips": "显示小提示", "showTips": "显示小提示",
"showWelcomeTours": "显示新版本向导", "help": "Node-RED网页",
"help": "Node-RED 文档主页",
"projects": "项目", "projects": "项目",
"projects-new": "新建", "projects-new": "新建",
"projects-open": "打开", "projects-open": "打开",
"projects-settings": "项目设定", "projects-settings": "项目设定",
"showNodeLabelDefault": "显示新添加的节点的标签", "showNodeLabelDefault": "显示新添加的节点的标签",
"codeEditor": "代码编辑器",
"groups": "组", "groups": "组",
"groupSelection": "选择组", "groupSelection": "选择组",
"ungroupSelection": "取消选择组", "ungroupSelection": "取消选择组",
"groupMergeSelection": "合并选择", "groupMergeSelection": "合并选择",
"groupRemoveSelection": "从组中移除", "groupRemoveSelection": "从组中移除"
"arrange": "布局",
"alignLeft": "左对齐",
"alignCenter": "居中对齐",
"alignRight": "右对齐",
"alignTop": "顶部对齐",
"alignMiddle": "垂直居中对齐",
"alignBottom": "底部对齐",
"distributeHorizontally": "横向分布",
"distributeVertically": "垂直分布",
"moveToBack": "置于底层",
"moveToFront": "置于顶层",
"moveBackwards": "向后移动",
"moveForwards": "向前移动",
"showNodeHelp":"显示节点帮助",
"enableSelectedNodes":"启用当前选中节点",
"disableSelectedNodes":"禁用当前选中节点",
"showSelectedNodeLabels":"显示选中的节点标签",
"hideSelectedNodeLabels":"隐藏选中的节点标签"
} }
}, },
"actions": { "actions": {
"toggle-navigator": "切换导航器", "toggle-navigator": "切换导航器",
"zoom-out": "缩小", "zoom-out": "缩小",
"zoom-reset": "重设缩放", "zoom-reset": "重设缩放",
"zoom-in": "放大", "zoom-in": "放大"
"search-flows": "搜索流程",
"search-prev": "上一个",
"search-next": "下一个",
"search-counter": "\"__term__\" __result__ of __count__"
}, },
"user": { "user": {
"loggedInAs": "作为 __name__ 登", "loggedInAs": "作为 __name__ 登陆",
"username": "账号", "username": "账号",
"password": "密码", "password": "密码",
"login": "登录", "login": "登陆",
"loginFailed": "登失败", "loginFailed": "登陆失败",
"notAuthorized": "未授权", "notAuthorized": "未授权",
"errors": { "errors": {
"settings": "设置信息需要登后才能访问", "settings": "设置信息需要登陆后才能访问",
"deploy": "改动需要登后才能部署", "deploy": "改动需要登陆后才能部署",
"notAuthorized": "此操作需要登后才能执行" "notAuthorized": "此操作需要登后才能执行"
} }
}, },
"notification": { "notification": {
"state": {
"flowsStopped": "流程已停止",
"flowsStarted": "流程已启动"
},
"warning": "<strong>警告</strong>: __message__", "warning": "<strong>警告</strong>: __message__",
"warnings": { "warnings": {
"undeployedChanges": "节点中存在未部署的更改", "undeployedChanges": "节点中存在未部署的更改",
"nodeActionDisabled": "节点操作已禁用", "nodeActionDisabled": "节点操作已禁用",
"nodeActionDisabledSubflow": "节点动作在子流程中被禁用", "nodeActionDisabledSubflow": "节点动作在子流程中被禁用",
"missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息", "missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息",
"missing-modules": "<p>流程因缺少模块而停止。</p>",
"safe-mode": "<p>流程以安全模式停止。</p><p>您可以修改流程并部署更改以重新启动。</p>", "safe-mode": "<p>流程以安全模式停止。</p><p>您可以修改流程并部署更改以重新启动。</p>",
"restartRequired": "Node-RED必须重新启动以启用升级的模块", "restartRequired": "Node-RED必须重新启动以启用升级的模块",
"credentials_load_failed": "<p>由于无法解密凭据,因此流程停止。</p><p>流程凭据文件已加密,但是项目的加密密钥丢失或无效。</p>", "credentials_load_failed": "<p>由于无法解密凭据,因此流程停止。</p><p>流程凭据文件已加密,但是项目的加密密钥丢失或无效。</p>",
@ -236,8 +181,7 @@
"create-default-package": "创建默认的包文件", "create-default-package": "创建默认的包文件",
"no-thanks": "不了,谢谢", "no-thanks": "不了,谢谢",
"create-default-project": "创建默认项目文件", "create-default-project": "创建默认项目文件",
"show-merge-conflicts": "显示合并冲突", "show-merge-conflicts": "显示合并冲突"
"unknownNodesButton": "搜索未知节点"
} }
}, },
"clipboard": { "clipboard": {
@ -253,17 +197,13 @@
"flow_plural": "__count__ 个流程", "flow_plural": "__count__ 个流程",
"subflow": "__count__ 个子流程", "subflow": "__count__ 个子流程",
"subflow_plural": "__count__ 子流程", "subflow_plural": "__count__ 子流程",
"replacedNodes": "__count__ 个节点被置换", "pasteNodes": "在这里粘贴节点",
"replacedNodes_plural": "__count__ 个节点被置换", "selectFile": "选择要导入的文件",
"pasteNodes": "在下方粘贴节点 ",
"selectFile": "导入节点文件",
"importNodes": "导入节点", "importNodes": "导入节点",
"exportNodes": "导出节点至剪贴板", "exportNodes": "导出节点至剪贴板",
"download": "下载", "download": "下载",
"importUnrecognised": "导入了无法识别的类型:", "importUnrecognised": "导入了无法识别的类型:",
"importUnrecognised_plural": "导入了无法识别的类型:", "importUnrecognised_plural": "导入了无法识别的类型:",
"importDuplicate": "导入了重复节点:",
"importDuplicate_plural": "导入了重复节点:",
"nodesExported": "节点导出到了剪贴板", "nodesExported": "节点导出到了剪贴板",
"nodesImported": "导入:", "nodesImported": "导入:",
"nodeCopied": "已复制 __count__ 个节点", "nodeCopied": "已复制 __count__ 个节点",
@ -272,36 +212,27 @@
"groupCopied_plural": "已复制 __count__ 个groups", "groupCopied_plural": "已复制 __count__ 个groups",
"groupStyleCopied": "已复制组风格", "groupStyleCopied": "已复制组风格",
"invalidFlow": "无效的流程: __message__", "invalidFlow": "无效的流程: __message__",
"recoveredNodes": "复原的节点",
"recoveredNodesInfo": "导入节点时此流上的节点缺少有效的流ID。 它们已被添加到此流中,您可以复原或删除它们。",
"recoveredNodesNotification": "<p>导入的节点缺少有效的流ID</p><p>已将它们添加到名为 '__flowName__'的新流中。</p>",
"export": { "export": {
"selected": "已选择的节点", "selected": "已选择的节点",
"current": "当前节点", "current": "现在的节点",
"all": "所有流程", "all": "所有流程",
"compact": "紧凑", "compact": "紧凑",
"formatted": "已格式化", "formatted": "已格式化",
"copy": "导出到剪贴板", "copy": "导出到剪贴板",
"export": "导出到库", "export": "到处到库",
"exportAs": "导出为", "exportAs": "导出为",
"overwrite": "替换", "overwrite": "替换",
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>" "exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"
}, },
"import": { "import": {
"import": "导入到", "import": "导入到",
"importSelected": "导入所选项",
"importCopy": "导入副本",
"viewNodes": "查看节点",
"newFlow": "新流程", "newFlow": "新流程",
"replace": "置换",
"errors": { "errors": {
"notArray": "输入的不是JSON数组", "notArray": "输入的不是JSON数组",
"itemNotObject": "输入的流无效 - 项目 __index__ 不是节点对象", "itemNotObject": "输入的流无效 - 项目 __index__ 不是节点对象",
"missingId": "输入的流无效-项 __index__ 缺少'id'属性", "missingId": "输入的流无效-项 __index__ 缺少'id'属性",
"missingType": "输入的流程无效-项 __index__ 缺少'类型'属性" "missingType": "输入的流程无效-项 __index__ 缺少'类型'属性"
}, }
"conflictNotification1": "您要导入的某些节点已经存在于工作空间中。",
"conflictNotification2": "选择要导入的节点,并确认要替换现有的节点还是导入它们的副本"
}, },
"copyMessagePath": "已复制路径", "copyMessagePath": "已复制路径",
"copyMessageValue": "已复制数值", "copyMessageValue": "已复制数值",
@ -309,25 +240,19 @@
}, },
"deploy": { "deploy": {
"deploy": "部署", "deploy": "部署",
"full": "全部", "full": "全面",
"fullDesc": "在工作区中部署所有内容", "fullDesc": "在工作区中部署所有内容",
"modifiedFlows": "已修改的流程", "modifiedFlows": "已修改的流程",
"modifiedFlowsDesc": "只部署包含已更改节点的流", "modifiedFlowsDesc": "只部署包含已更改节点的流",
"modifiedNodes": "已更改的节点", "modifiedNodes": "已更改的节点",
"modifiedNodesDesc": "只部署已经更改的节点", "modifiedNodesDesc": "只部署已经更改的节点",
"startFlows": "启动",
"startFlowsDesc": "启动流程",
"stopFlows": "停止",
"stopFlowsDesc": "停止流程",
"restartFlows": "重启流程", "restartFlows": "重启流程",
"restartFlowsDesc": "重新启动当前部署的流程", "restartFlowsDesc": "重新启动当前部署的流程",
"successfulDeploy": "部署成功", "successfulDeploy": "部署成功",
"successfulRestart": "成功重启流程", "successfulRestart": "成功重启流程",
"deployFailed": "部署失败: __message__", "deployFailed": "部署失败: __message__",
"unusedConfigNodes": "您有一些未使用的配置节点", "unusedConfigNodes": "您有一些未使用的配置节点",
"unusedConfigNodesButton": "搜索未使用的配置节点", "unusedConfigNodesLink": "点击此处查看它们",
"unknownNodesButton": "查找未知节点",
"invalidNodesButton": "查找无效节点",
"errors": { "errors": {
"noResponse": "服务器没有响应" "noResponse": "服务器没有响应"
}, },
@ -397,28 +322,14 @@
"output": "输出:", "output": "输出:",
"status": "状态节点", "status": "状态节点",
"deleteSubflow": "删除子流程", "deleteSubflow": "删除子流程",
"confirmDelete": "您确定要删除此子流程?",
"info": "详细描述", "info": "详细描述",
"category": "类别", "category": "类别",
"module": "模块",
"license": "许可",
"licenseNone": "无",
"licenseOther": "其它",
"type": "节点类型",
"version": "版本",
"versionPlaceholder": "x.y.z",
"keys": "关键字",
"keysPlaceholder": "使用英文逗号分隔关键字",
"author": "作者",
"authorPlaceholder": "名字 <email@example.com>",
"desc": "描述",
"env": { "env": {
"restore": "恢复为默认子流", "restore": "恢复为默认子流",
"remove": "删除环境变量" "remove": "删除环境变量"
}, },
"errors": { "errors": {
"noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点", "noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点",
"acrossMultipleGroups": "无法跨多个组创建子流",
"multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择" "multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择"
} }
}, },
@ -459,7 +370,6 @@
"icon": "图标", "icon": "图标",
"inputType": "输入类型", "inputType": "输入类型",
"selectType": "选择类型...", "selectType": "选择类型...",
"loadCredentials": "加载节点凭证",
"inputs": { "inputs": {
"input": "输入", "input": "输入",
"select": "选择", "select": "选择",
@ -494,8 +404,7 @@
}, },
"errors": { "errors": {
"scopeChange": "更改范围将使其他流中的节点无法使用", "scopeChange": "更改范围将使其他流中的节点无法使用",
"invalidProperties": "无效的属性:", "invalidProperties": "无效的属性:"
"credentialLoadFailed": "无法加载节点凭据"
} }
}, },
"keyboard": { "keyboard": {
@ -507,14 +416,11 @@
"unassigned": "未分配", "unassigned": "未分配",
"global": "全局", "global": "全局",
"workspace": "工作区", "workspace": "工作区",
"editor": "编辑对话框",
"selectAll": "选择所有节点", "selectAll": "选择所有节点",
"selectNone": "取消所有选择",
"selectAllConnected": "选择所有连接的节点", "selectAllConnected": "选择所有连接的节点",
"addRemoveNode": "从选择中添加/删除节点", "addRemoveNode": "从选择中添加/删除节点",
"editSelected": "编辑选定节点", "editSelected": "编辑选定节点",
"deleteSelected": "删除选定节点或链接", "deleteSelected": "删除选定节点或链接",
"deleteReconnect": "删除并重新连接",
"importNode": "导入节点", "importNode": "导入节点",
"exportNode": "导出节点", "exportNode": "导出节点",
"nudgeNode": "移动所选节点(1px)", "nudgeNode": "移动所选节点(1px)",
@ -524,14 +430,10 @@
"copyNode": "复制所选节点", "copyNode": "复制所选节点",
"cutNode": "剪切所选节点", "cutNode": "剪切所选节点",
"pasteNode": "粘贴节点", "pasteNode": "粘贴节点",
"copyGroupStyle": "复制组样式", "undoChange": "撤消上次执行的更改",
"pasteGroupStyle": "粘贴组样式",
"undoChange": "撤消",
"redoChange": "重做",
"searchBox": "打开搜索框", "searchBox": "打开搜索框",
"managePalette": "管理面板", "managePalette": "管理面板",
"actionList": "动作列表", "actionList": "动作列表"
"splitWireWithLinks": "使用Link节点拆分已选项"
}, },
"library": { "library": {
"library": "库", "library": "库",
@ -547,23 +449,24 @@
"saveFailed": "保存失败: __message__", "saveFailed": "保存失败: __message__",
"newFolder": "新文件夹", "newFolder": "新文件夹",
"types": { "types": {
"local": "本地存储", "local": "本地的",
"examples": "示例" "examples": "例子"
} },
"exportToLibrary": "将节点导出到库"
}, },
"palette": { "palette": {
"noInfo": "无可用信息", "noInfo": "无可用信息",
"filter": "过滤已安装模块", "filter": "过滤节点",
"search": "搜索模块", "search": "搜索模块",
"addCategory": "添加新的...", "addCategory": "添加新的...",
"label": { "label": {
"subflows": "子流程", "subflows": "子流程",
"network": "网络", "network": "网络",
"common": "", "common": "通",
"input": "输入", "input": "输入",
"output": "输出", "output": "输出",
"function": "功能", "function": "功能",
"sequence": "序列", "sequence": "序列",
"parser": "解析", "parser": "解析",
"social": "社交", "social": "社交",
"storage": "存储", "storage": "存储",
@ -583,13 +486,11 @@
"nodeEnabled_plural": "启用多个节点:", "nodeEnabled_plural": "启用多个节点:",
"nodeDisabled": "禁用节点:", "nodeDisabled": "禁用节点:",
"nodeDisabled_plural": "禁用多个节点:", "nodeDisabled_plural": "禁用多个节点:",
"nodeUpgraded": "节点模块__module__升级到__version__版本", "nodeUpgraded": "节点模块__module__升级到__version__版本"
"unknownNodeRegistered": "加载节点错误: <ul><li>__type__<br>__error__</li></ul>"
}, },
"editor": { "editor": {
"title": "面板管理", "title": "面板管理",
"palette": "控制板", "palette": "控制板",
"allCatalogs": "所有目录",
"times": { "times": {
"seconds": "秒前", "seconds": "秒前",
"minutes": "分前", "minutes": "分前",
@ -629,12 +530,9 @@
"tab-nodes": "节点", "tab-nodes": "节点",
"tab-install": "安装", "tab-install": "安装",
"sort": "排序:", "sort": "排序:",
"sortRelevance": "关联",
"sortAZ": "a-z顺序", "sortAZ": "a-z顺序",
"sortRecent": "日期顺序", "sortRecent": "日期顺序",
"more": "增加 __count__ 个", "more": "增加 __count__ 个",
"upload": "上传模块tgz文件",
"refresh": "更新模块列表",
"errors": { "errors": {
"catalogLoadFailed": "无法加载节点目录。<br>查看浏览器控制台了解更多信息", "catalogLoadFailed": "无法加载节点目录。<br>查看浏览器控制台了解更多信息",
"installFailed": "无法安装: __module__<br>__message__<br>查看日志了解更多信息", "installFailed": "无法安装: __module__<br>__message__<br>查看日志了解更多信息",
@ -704,10 +602,13 @@
"globalConfig": "全局配置节点", "globalConfig": "全局配置节点",
"triggerAction": "触发动作", "triggerAction": "触发动作",
"find": "在工作区中查找", "find": "在工作区中查找",
"copyItemUrl": "复制地址", "search": {
"copyURL2Clipboard": "复制地址到剪贴板", "configNodes": "配置节点",
"showFlow": "显示流程", "unusedConfigNodes": "未使用的配置节点",
"hideFlow": "隐藏流程" "invalidNodes": "无效的节点",
"uknownNodes": "未知的节点",
"unusedSubflows": "未使用的子流程"
}
}, },
"help": { "help": {
"name": "帮助", "name": "帮助",
@ -717,8 +618,7 @@
"showHelp": "显示帮助", "showHelp": "显示帮助",
"showInOutline": "在大纲中显示", "showInOutline": "在大纲中显示",
"showTopics": "显示主题", "showTopics": "显示主题",
"noHelp": "未选择帮助主题", "noHelp": "未选择帮助主题"
"changeLog": "更新日志"
}, },
"config": { "config": {
"name": "配置节点", "name": "配置节点",
@ -735,21 +635,21 @@
}, },
"context": { "context": {
"name": "上下文数据", "name": "上下文数据",
"label": "上下", "label": "上下",
"none": "未选择", "none": "未选择",
"refresh": "刷新以加载", "refresh": "刷新以加载",
"empty": "空", "empty": "空",
"node": "节点", "node": "节点",
"flow": "流程", "flow": "流程",
"global": "全局", "global": "全局",
"deleteConfirm": "确定要删除这个项目吗?", "deleteConfirm": "确定要删除这个项目吗?",
"autoRefresh": "刷新选择更改", "autoRefresh": "刷新选择更改",
"refrsh": "刷新", "refrsh": "刷新",
"delete": "删除" "delete": "删除"
}, },
"palette": { "palette": {
"name": "模块管理", "name": "节点管理",
"label": "模块" "label": "节点"
}, },
"project": { "project": {
"label": "项目", "label": "项目",
@ -785,7 +685,7 @@
"changeTheEncryptionKey": "更改加密密钥", "changeTheEncryptionKey": "更改加密密钥",
"currentKey": "当前密钥", "currentKey": "当前密钥",
"newKey": "新密钥", "newKey": "新密钥",
"credentialsAlert": "将删除所有现有证书", "credentialsAlert": "将删除所有现有证书",
"versionControl": "版本控制", "versionControl": "版本控制",
"branches": "分支", "branches": "分支",
"noBranches": "没有分支", "noBranches": "没有分支",
@ -798,7 +698,7 @@
"remoteName": "远程仓库名", "remoteName": "远程仓库名",
"nameRule": "只能包含A-Z 0-9 _ -", "nameRule": "只能包含A-Z 0-9 _ -",
"url": "URL", "url": "URL",
"urlRule": "https://, ssh:// file://", "urlRule": "https://, ssh:// or file://",
"urlRule2": "网址中不能包含用户名/密码", "urlRule2": "网址中不能包含用户名/密码",
"noRemotes": "没有远程仓库", "noRemotes": "没有远程仓库",
"deleteRemoteConfrim": "您确定要删除远程仓库'__name__'吗?", "deleteRemoteConfrim": "您确定要删除远程仓库'__name__'吗?",
@ -809,12 +709,6 @@
"committerTip": "保留空白以使用系统默认值", "committerTip": "保留空白以使用系统默认值",
"userName": "用户名", "userName": "用户名",
"email": "电子邮件", "email": "电子邮件",
"workflow": "工作流",
"workfowTip": "选择您偏好的工作流",
"workflowManual": "手动",
"workflowManualTip": "所有更改都必须在“历史记录”侧边栏中手动提交",
"workflowAuto": "自动",
"workflowAutoTip": "每次部署后都会自动提交更改",
"sshKeys": "SSH密钥", "sshKeys": "SSH密钥",
"sshKeysTip": "允许您创建到远程git存储库的安全连接。", "sshKeysTip": "允许您创建到远程git存储库的安全连接。",
"add": "添加密钥", "add": "添加密钥",
@ -912,7 +806,7 @@
}, },
"typedInput": { "typedInput": {
"type": { "type": {
"str": "文本", "str": "文字列",
"num": "数字", "num": "数字",
"re": "正则表达式", "re": "正则表达式",
"bool": "布尔值", "bool": "布尔值",
@ -925,34 +819,21 @@
} }
}, },
"editableList": { "editableList": {
"add": "添加", "add": "添加"
"addTitle": "添加项"
}, },
"search": { "search": {
"history": "搜索历史", "empty": "找不到匹配",
"clear": "清除所有", "addNode": "添加一个节点..."
"empty": "找不到匹配项",
"addNode": "添加节点...",
"options": {
"configNodes": "配置节点",
"unusedConfigNodes": "未使用的配置节点",
"invalidNodes": "无效的节点",
"uknownNodes": "未知的节点",
"unusedSubflows": "未使用的子流程",
"hiddenFlows": "隐藏的流程",
"modifiedNodes": "已修改的节点或流程",
"thisFlow": "当前流程"
}
}, },
"expressionEditor": { "expressionEditor": {
"functions": "函数", "functions": "功能",
"functionReference": "函数引用", "functionReference": "功能reference",
"insert": "插入", "insert": "插入",
"title": "JSONata表达式编辑器", "title": "JSONata表达式编辑器",
"test": "测试", "test": "测试",
"data": "示例消息", "data": "示例消息",
"result": "结果", "result": "结果",
"format": "格式表达", "format": "格式表达方法",
"compatMode": "兼容模式启用", "compatMode": "兼容模式启用",
"compatModeDesc": "<h3>JSONata的兼容模式</h3><p> 目前的表达式仍然参考<code>msg</code>,所以将以兼容性模式进行评估。请更新表达式,使其不使用<code>msg</code>,因为此模式将在将来删除。</p><p> 当JSONata支持首次添加到Node-RED时它需要表达式引用<code>msg</code>对象。例如<code>msg.payload</code>将用于访问有效负载。</p><p> 这样便不再需要表达式直接针对消息进行评估。要访问有效负载,表达式应该只是<code>payload</code>.</p>", "compatModeDesc": "<h3>JSONata的兼容模式</h3><p> 目前的表达式仍然参考<code>msg</code>,所以将以兼容性模式进行评估。请更新表达式,使其不使用<code>msg</code>,因为此模式将在将来删除。</p><p> 当JSONata支持首次添加到Node-RED时它需要表达式引用<code>msg</code>对象。例如<code>msg.payload</code>将用于访问有效负载。</p><p> 这样便不再需要表达式直接针对消息进行评估。要访问有效负载,表达式应该只是<code>payload</code>.</p>",
"noMatch": "无匹配结果", "noMatch": "无匹配结果",
@ -960,15 +841,9 @@
"invalid-expr": "无效的JSONata表达式:\n __message__", "invalid-expr": "无效的JSONata表达式:\n __message__",
"invalid-msg": "无效的示例JSON消息:\n __message__", "invalid-msg": "无效的示例JSON消息:\n __message__",
"context-unsupported": "无法测试上下文函数\n $flowContext 或 $globalContext", "context-unsupported": "无法测试上下文函数\n $flowContext 或 $globalContext",
"env-unsupported": "无法测试 $env 函数", "eval": "评估表达式错误:\n __message__"
"moment-unsupported": "无法测试 $moment 函数",
"clone-unsupported": "无法测试 $clone 函数",
"eval": "计算表达式错误:\n __message__"
} }
}, },
"monaco": {
"setTheme": "设置主题"
},
"jsEditor": { "jsEditor": {
"title": "JavaScript编辑器" "title": "JavaScript编辑器"
}, },
@ -979,15 +854,13 @@
"title": "JSON编辑器", "title": "JSON编辑器",
"format": "格式化JSON", "format": "格式化JSON",
"rawMode": "编辑 JSON", "rawMode": "编辑 JSON",
"uiMode": "可视化编辑器", "uiMode": "Visual编辑器",
"rawMode-readonly": "原始JSON",
"uiMode-readonly": "可视化",
"insertAbove": "在上方插入", "insertAbove": "在上方插入",
"insertBelow": "在下方插入", "insertBelow": "在下方插入",
"addItem": "添加项目", "addItem": "添加项目",
"copyPath": "复制路径到项目", "copyPath": "复制路径到项目",
"expandItems": "展开项目", "expandItems": "展开项目",
"collapseItems": "折叠项目", "collapseItems": "收合项目",
"duplicate": "重复", "duplicate": "重复",
"error": { "error": {
"invalidJSON": "无效的JSON: " "invalidJSON": "无效的JSON: "
@ -1008,16 +881,13 @@
"quote": "引用", "quote": "引用",
"link": "链接", "link": "链接",
"horizontal-rule": "水平线", "horizontal-rule": "水平线",
"toggle-preview": "切换预览", "toggle-preview": "切换预览"
"mermaid": {
"summary": "美人鱼图"
}
}, },
"bufferEditor": { "bufferEditor": {
"title": "Buffer 编辑器", "title": "缓冲区编辑器",
"modeString": "作为UTF-8字符串处理", "modeString": "作为UTF-8字符串处理",
"modeArray": "作为JSON数组处理", "modeArray": "作为JSON数组处理",
"modeDesc": "<h3>Buffer 编辑器</h3><p>Buffer类型被存储为字节值的JSON数组。编辑器将尝试将输入的数值解析为JSON数组。如果它不是有效的JSON它将被视为UTF-8字符串并被转换为单个字符代码点的数组。</p><p>例如,<code>Hello World</code>的值会被转换为JSON数组<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>" "modeDesc": "<h3>缓冲区编辑器</h3><p>缓冲区类型被存储为字节值的JSON数组。编辑器将尝试将输入的数值解析为JSON数组。如果它不是有效的JSON它将被视为UTF-8字符串并被转换为单个字符代码点的数组。</p><p>例如,<code>Hello World</code>的值会被转换为JSON数组<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
}, },
"projects": { "projects": {
"config-git": "配置Git客户端", "config-git": "配置Git客户端",
@ -1029,7 +899,7 @@
"create": "建立专案", "create": "建立专案",
"clone": "克隆仓库", "clone": "克隆仓库",
"openExistingProject": "打开现有项目", "openExistingProject": "打开现有项目",
"not-right-now": "稍后" "not-right-now": "不是现在"
}, },
"git-config": { "git-config": {
"setup": "设置您的版本控制客户端", "setup": "设置您的版本控制客户端",
@ -1131,7 +1001,7 @@
"desc0": "用来保护您的凭证的短语", "desc0": "用来保护您的凭证的短语",
"desc1": "凭证文件不会被加密,其内容很容易阅读", "desc1": "凭证文件不会被加密,其内容很容易阅读",
"git-url": "Git存储库URL", "git-url": "Git存储库URL",
"protocols": "https://, ssh:// file://", "protocols": "https://, ssh:// or file://",
"auth-failed": "验证失败", "auth-failed": "验证失败",
"username": "用户名", "username": "用户名",
"password": "密码", "password": "密码",
@ -1146,8 +1016,7 @@
"not-git": "不是git仓库", "not-git": "不是git仓库",
"no-resource": "找不到存储库", "no-resource": "找不到存储库",
"cant-get-ssh-key-path": "错误无法获取所选的SSH密钥路径。", "cant-get-ssh-key-path": "错误无法获取所选的SSH密钥路径。",
"unexpected_error": "意外的错误", "unexpected_error": "意外的错误"
"clearContext": "更改项目时清除上下文"
}, },
"delete": { "delete": {
"confirm": "您确定要删除此项目吗?" "confirm": "您确定要删除此项目吗?"
@ -1188,46 +1057,17 @@
"editor-tab": { "editor-tab": {
"properties": "属性", "properties": "属性",
"envProperties": "环境变量", "envProperties": "环境变量",
"module": "模块属性",
"description": "描述", "description": "描述",
"appearance": "外观", "appearance": "外观",
"preview": "UI预览", "preview": "UI预览",
"defaultValue": "默认值" "defaultValue": "默认值"
}, },
"tourGuide": { "languages": {
"takeATour": "查看更新内容", "de": "德语",
"start": "开始", "en-US": "英文",
"next": "下一个", "ja": "日语",
"welcomeTours": "欢迎使用 Node-RED" "ko": "韩文",
}, "zh-CN": "简体中文",
"diagnostics": { "zh-TW": "繁体中文"
"title": "系统信息"
},
"validator": {
"errors": {
"invalid-json": "无效的 JSON 数据: __error__",
"invalid-expr": "无效的 JSONata 表达式: __error__",
"invalid-prop": "无效的属性表达式",
"invalid-num": "无效的数字",
"invalid-num-prop": "__prop__: 无效的数字",
"invalid-regexp": "输入格式无效",
"invalid-regex-prop": "__prop__: 输入格式无效",
"missing-required-prop": "__prop__: 缺少属性值",
"invalid-config": "__prop__: 无效的配置节点",
"missing-config": "__prop__: 缺少配置节点",
"validation-error": "__prop__: 验证错误: __node__, __id__: __error__"
}
},
"contextMenu": {
"showActionList":"显示动作列表",
"insert": "插入",
"node": "节点",
"junction": "连接点",
"linkNodes": "链接节点"
},
"env-var": {
"environment": "环境配置",
"header": "全局环境变量",
"revert": "重置"
} }
} }

View File

@ -137,7 +137,7 @@
}, },
"$sort": { "$sort": {
"args": "array [, function]", "args": "array [, function]",
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)`\n\n该比较函数是为了比较`left``right`两个值而被排序算法调用的。如果用户希望`left`的值被置于`right`的值之后,那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。" "desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)` \n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。"
}, },
"$reverse": { "$reverse": {
"args": "array", "args": "array",
@ -237,25 +237,25 @@
}, },
"$assert": { "$assert": {
"args": "arg, str", "args": "arg, str",
"desc": "如果 `arg` 为真,则该函数返回。 如果`arg`为假,则抛出带有`str`的异常作为异常消息。" "desc": "如果 `arg` 为真,则该函数返回。 如果arg为假则抛出带有str的异常作为异常消息。"
}, },
"$single": { "$single": {
"args": "array, function", "args": "array, function",
"desc": "返回满足参数function谓语的array参数中的唯一值 (比如传递值时函数返回布尔值“true”)。如果匹配值的数量不唯一时,则抛出异常。\n\n应在以下签名中提供函数 `functionvalue [index [array []]]` 其中value是数组的每个输入index是该值的位置整个数组作为第三个参数传递。" "desc": "返回满足参数function谓语的array参数中的唯一值 (比如传递值时函数返回布尔值“true”)。如果匹配值的数量不唯一时,则抛出异常。\n\n应在以下签名中提供函数 `functionvalue [index [array []]]` 其中value是数组的每个输入index是该值的位置整个数组作为第三个参数传递。"
}, },
"$encodeUrlComponent": { "$encodeUrl": {
"args": "str", "args": "str",
"desc": "通过用表示字符的UTF-8编码的一个两个三个或四个转义序列替换某些字符的每个实例对统一资源定位符URL组件进行编码。\n\n示例 `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" "desc": "通过用表示字符的UTF-8编码的一个两个三个或四个转义序列替换某些字符的每个实例对统一资源定位符URL组件进行编码。\n\n示例 `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
}, },
"$encodeUrl": { "$encodeUrlComponent": {
"args": "str", "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\"`" "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\"`"
}, },
"$decodeUrlComponent": { "$decodeUrl": {
"args": "str", "args": "str",
"desc": "解码以前由encodeUrlComponent创建的统一资源定位器URL组件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" "desc": "解码以前由encodeUrlComponent创建的统一资源定位器URL组件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
}, },
"$decodeUrl": { "$decodeUrlComponent": {
"args": "str", "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=шеллы\"`" "desc": "解码先前由encodeUrl创建的统一资源定位符URL。 \n\n示例 `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
}, },
@ -270,9 +270,5 @@
"$moment": { "$moment": {
"args": "[str]", "args": "[str]",
"desc": "使用Moment库获取日期对象。" "desc": "使用Moment库获取日期对象。"
},
"$clone": {
"args": "value",
"desc": "安全克隆对象."
} }
} }

View File

@ -22,12 +22,7 @@
"color": "顏色", "color": "顏色",
"position": "位置", "position": "位置",
"enable": "啟用", "enable": "啟用",
"disable": "禁用", "disable": "禁用"
"upload": "上傳",
"lock": "鎖定",
"unlock": "解鎖",
"locked": "鎖定",
"unlocked": "解鎖"
}, },
"type": { "type": {
"string": "字符串", "string": "字符串",
@ -42,14 +37,11 @@
} }
}, },
"event": { "event": {
"loadPlugins": "加載插件",
"loadPalette": "加載控制板", "loadPalette": "加載控制板",
"loadNodeCatalogs": "加載節點目錄", "loadNodeCatalogs": "加載節點目錄",
"loadNodes": "加載 __count__ 個節點", "loadNodes": "加載 __count__ 個節點",
"loadFlows": "加載流程", "loadFlows": "加載流程",
"importFlows": "往工作區中加載流程", "importFlows": "往工作區中加載流程"
"importError": "<p>加載流程錯誤</p><p>__message__</p>",
"loadingProject": "加載項目"
}, },
"workspace": { "workspace": {
"defaultName": "流程__number__", "defaultName": "流程__number__",
@ -58,35 +50,18 @@
"delete": "確定想要刪除 '__label__'?", "delete": "確定想要刪除 '__label__'?",
"dropFlowHere": "把流程放到這裡", "dropFlowHere": "把流程放到這裡",
"addFlow": "新增流程", "addFlow": "新增流程",
"addFlowToRight": "在右側新增流程", "listFlows": "流程列表",
"hideFlow": "隱藏流程",
"hideOtherFlows": "隱藏其它流程",
"showAllFlows": "顯示所有流程",
"hideAllFlows": "隱藏所有流程",
"hiddenFlows": "列出 __count__ 個隱藏流程",
"hiddenFlows_plural": "列出 __count__ 個隱藏流程",
"showLastHiddenFlow": "顯示最後一個隱藏流程",
" ": "流程列表",
"listSubflows": "列出子流程",
"status": "狀態", "status": "狀態",
"enabled": "有效", "enabled": "有效",
"disabled": "無效", "disabled": "無效",
"info": "詳細描述", "info": "詳細描述",
"selectNodes": "點擊節點用於選擇", "selectNodes": "點擊節點用於選擇"
"enableFlow": "啟用流程",
"disableFlow": "禁用流程",
"lockFlow": "鎖定流程",
"unlockFlow": "解除鎖定",
"moveToStart": "移動到起始",
"moveToEnd": "移動到末尾"
}, },
"menu": { "menu": {
"label": { "label": {
"view": { "view": {
"view": "顯示", "view": "顯示",
"grid": "格線", "grid": "格線",
"storeZoom": "加載時還原縮放尺寸",
"storePosition": "加載時還原滾動位置",
"showGrid": "顯示格線", "showGrid": "顯示格線",
"snapGrid": "對齊格線", "snapGrid": "對齊格線",
"gridSize": "格線尺寸", "gridSize": "格線尺寸",
@ -104,14 +79,12 @@
"palette": { "palette": {
"show": "顯示控制板" "show": "顯示控制板"
}, },
"edit": "編輯",
"settings": "設置", "settings": "設置",
"userSettings": "使用者設置", "userSettings": "使用者設置",
"nodes": "節點", "nodes": "節點",
"displayStatus": "顯示節點狀態", "displayStatus": "顯示節點狀態",
"displayConfig": "修改節點配置", "displayConfig": "修改節點配置",
"import": "匯入", "import": "匯入",
"importExample": "導入示例流程",
"export": "匯出", "export": "匯出",
"search": "搜尋流程", "search": "搜尋流程",
"searchInput": "搜尋流程", "searchInput": "搜尋流程",
@ -120,6 +93,7 @@
"selectionToSubflow": "將選擇部分更改為子流程", "selectionToSubflow": "將選擇部分更改為子流程",
"flows": "流程", "flows": "流程",
"add": "增加", "add": "增加",
"rename": "重新命名",
"delete": "刪除", "delete": "刪除",
"keyboardShortcuts": "鍵盤快速鍵", "keyboardShortcuts": "鍵盤快速鍵",
"login": "登入", "login": "登入",
@ -127,48 +101,24 @@
"editPalette": "節點管理", "editPalette": "節點管理",
"other": "其他", "other": "其他",
"showTips": "顯示小提示", "showTips": "顯示小提示",
"showWelcomeTours": "顯示新版本向導", "help": "Node-RED website",
"help": "Node-RED 文檔主頁",
"projects": "專案", "projects": "專案",
"projects-new": "新專案", "projects-new": "新專案",
"projects-open": "開啟專案", "projects-open": "開啟專案",
"projects-settings": "專案設定", "projects-settings": "專案設定",
"showNodeLabelDefault": "顯示新添加節點的標籤", "showNodeLabelDefault": "顯示新添加節點的標籤",
"codeEditor": "代碼編輯器",
"groups": "組", "groups": "組",
"groupSelection": "選擇組", "groupSelection": "選擇組",
"ungroupSelection": "取消選擇組", "ungroupSelection": "取消選擇組",
"groupMergeSelection": "合并選擇", "groupMergeSelection": "合并選擇",
"groupRemoveSelection": "從組中移除", "groupRemoveSelection": "從組中移除"
"arrange": "布局",
"alignLeft": "左對齊",
"alignCenter": "居中對齊",
"alignRight": "右對齊",
"alignTop": "頂部對齊",
"alignMiddle": "垂直居中對齊",
"alignBottom": "底部對齊",
"distributeHorizontally": "横向分布",
"distributeVertically": "垂直分布",
"moveToBack": "置於底層",
"moveToFront": "置於頂層",
"moveBackwards": "向後移動",
"moveForwards": "向前移動",
"showNodeHelp":"顯示節點幫助",
"enableSelectedNodes":"啟用當前選中節點",
"disableSelectedNodes":"禁用當前選中節點",
"showSelectedNodeLabels":"顯示選中的節點標簽",
"hideSelectedNodeLabels":"隱藏選中的節點標簽"
} }
}, },
"actions": { "actions": {
"toggle-navigator": "切換導航器", "toggle-navigator": "切換導航器",
"zoom-out": "縮小", "zoom-out": "縮小",
"zoom-reset": "重置縮放", "zoom-reset": "重置縮放",
"zoom-in": "放大", "zoom-in": "放大"
"search-flows": "搜索流程",
"search-prev": "上一個",
"search-next": "下一個",
"search-counter": "\"__term__\" __result__ of __count__"
}, },
"user": { "user": {
"loggedInAs": "作為 __name__ 登入", "loggedInAs": "作為 __name__ 登入",
@ -184,17 +134,12 @@
} }
}, },
"notification": { "notification": {
"state": {
"flowsStopped": "流程已停止",
"flowsStarted": "流程已啟動"
},
"warning": "<strong>警告</strong>: __message__", "warning": "<strong>警告</strong>: __message__",
"warnings": { "warnings": {
"undeployedChanges": "節點中存在未部署的更改", "undeployedChanges": "節點中存在未部署的更改",
"nodeActionDisabled": "節點動作在子流程中被禁用", "nodeActionDisabled": "節點動作在子流程中被禁用",
"nodeActionDisabledSubflow": "子流程中禁用了節點操作", "nodeActionDisabledSubflow": "子流程中禁用了節點操作",
"missing-types": "流程由於缺少節點類型而停止。請檢查日誌的詳細資訊", "missing-types": "流程由於缺少節點類型而停止。請檢查日誌的詳細資訊",
"missing-modules": "<p>流程因缺少模塊而停止。</p>",
"safe-mode": "<p>流程在安全模式下停止。</p><p>您可以修改流程並部署更改以重新啟動。</p>", "safe-mode": "<p>流程在安全模式下停止。</p><p>您可以修改流程並部署更改以重新啟動。</p>",
"restartRequired": "Node-RED必須重新啟動以啟用升級的模組", "restartRequired": "Node-RED必須重新啟動以啟用升級的模組",
"credentials_load_failed": "<p>流程由於無法解密證書而停止。</p> <p>流程證書文件已加密,但是項目的加密密鑰丟失或無效。</p>", "credentials_load_failed": "<p>流程由於無法解密證書而停止。</p> <p>流程證書文件已加密,但是項目的加密密鑰丟失或無效。</p>",
@ -205,7 +150,7 @@
"project_not_found": "<p>找不到項目的'__project__'</p>", "project_not_found": "<p>找不到項目的'__project__'</p>",
"git_merge_conflict": "<p>自動合併更改失敗。</p><p>修復未合併的衝突,然後提交結果。</p>" "git_merge_conflict": "<p>自動合併更改失敗。</p><p>修復未合併的衝突,然後提交結果。</p>"
}, },
"error": "<strong>錯誤</strong>: __message__", "error": "<strong>Error</strong>: __message__",
"errors": { "errors": {
"lostConnection": "丟失與伺服器的連接,重新連接...", "lostConnection": "丟失與伺服器的連接,重新連接...",
"lostConnectionReconnect": "丟失與伺服器的連接__time__ 秒後重新連接", "lostConnectionReconnect": "丟失與伺服器的連接__time__ 秒後重新連接",
@ -236,8 +181,7 @@
"create-default-package": "創建默認的包文件", "create-default-package": "創建默認的包文件",
"no-thanks": "不了,謝謝", "no-thanks": "不了,謝謝",
"create-default-project": "創建默認項目文件", "create-default-project": "創建默認項目文件",
"show-merge-conflicts": "顯示合併衝突", "show-merge-conflicts": "顯示合併衝突"
"unknownNodesButton": "搜索未知節點"
} }
}, },
"clipboard": { "clipboard": {
@ -253,8 +197,6 @@
"flow_plural": "__count__ 多流程", "flow_plural": "__count__ 多流程",
"subflow": "__count__ 子流程", "subflow": "__count__ 子流程",
"subflow_plural": "__count__ 多子流程", "subflow_plural": "__count__ 多子流程",
"replacedNodes": "__count__ 個節點被置換",
"replacedNodes_plural": "__count__ 個節點被置換",
"pasteNodes": "在這裡粘貼節點", "pasteNodes": "在這裡粘貼節點",
"selectFile": "匯入所選檔案", "selectFile": "匯入所選檔案",
"importNodes": "匯入節點", "importNodes": "匯入節點",
@ -262,8 +204,6 @@
"download": "下載", "download": "下載",
"importUnrecognised": "匯入了無法識別的類型:", "importUnrecognised": "匯入了無法識別的類型:",
"importUnrecognised_plural": "匯入了無法識別的類型:", "importUnrecognised_plural": "匯入了無法識別的類型:",
"importDuplicate": "導入了重復節點:",
"importDuplicate_plural": "導入了重復節點:",
"nodesExported": "節點匯出到了剪貼簿", "nodesExported": "節點匯出到了剪貼簿",
"nodesImported": "已匯入:", "nodesImported": "已匯入:",
"nodeCopied": "已複製 __count__ 個節點", "nodeCopied": "已複製 __count__ 個節點",
@ -272,9 +212,6 @@
"groupCopied_plural": "已複製 __count__ 個groups", "groupCopied_plural": "已複製 __count__ 個groups",
"groupStyleCopied": "已複製組風格", "groupStyleCopied": "已複製組風格",
"invalidFlow": "無效的流程: __message__", "invalidFlow": "無效的流程: __message__",
"recoveredNodes": "復原的節點",
"recoveredNodesInfo": "導入節點時此流上的節點缺少有效的流ID。它們已被添加到此流中您可以復原或刪除它們。",
"recoveredNodesNotification": "<p>導入的節點缺少有效的流ID</p><p>已將它們添加到名為 '__flowName__'的新流中。</p>",
"export": { "export": {
"selected": "已選擇的節點", "selected": "已選擇的節點",
"current": "現在的節點", "current": "現在的節點",
@ -289,19 +226,13 @@
}, },
"import": { "import": {
"import": "匯入到", "import": "匯入到",
"importSelected": "導入所選項",
"importCopy": "導入副本",
"viewNodes": "查看節點",
"newFlow": "新流程", "newFlow": "新流程",
"replace": "置換",
"errors": { "errors": {
"notArray": "輸入的不是JSON數組", "notArray": "輸入的不是JSON數組",
"itemNotObject": "輸入的流程無效-項目 __index__ 不是節點對象", "itemNotObject": "輸入的流程無效-項目 __index__ 不是節點對象",
"missingId": "輸入的流程無效-項 __index__ 缺少“ id”屬性", "missingId": "輸入的流程無效-項 __index__ 缺少“ id”屬性",
"missingType": "輸入的流程無效-項 __index__ 缺少“類型”屬性" "missingType": "輸入的流程無效-項 __index__ 缺少“類型”屬性"
}, }
"conflictNotification1": "您要導入的某些節點已經存在於工作空間中。",
"conflictNotification2": "選擇要導入的節點,並確認要替換現有的節點還是導入它們的副本"
}, },
"copyMessagePath": "已複製路徑", "copyMessagePath": "已複製路徑",
"copyMessageValue": "已複製數值", "copyMessageValue": "已複製數值",
@ -315,19 +246,13 @@
"modifiedFlowsDesc": "只部署包含已更改節點的流程", "modifiedFlowsDesc": "只部署包含已更改節點的流程",
"modifiedNodes": "已更改的節點", "modifiedNodes": "已更改的節點",
"modifiedNodesDesc": "只部署已經更改的節點", "modifiedNodesDesc": "只部署已經更改的節點",
"startFlows": "啟動",
"startFlowsDesc": "啟動流程",
"stopFlows": "停止",
"stopFlowsDesc": "停止流程",
"restartFlows": "重新啟動流程", "restartFlows": "重新啟動流程",
"restartFlowsDesc": "重新啟動當前部署的流程", "restartFlowsDesc": "重新啟動當前部署的流程",
"successfulDeploy": "部署成功", "successfulDeploy": "部署成功",
"successfulRestart": "成功重啟流程", "successfulRestart": "成功重啟流程",
"deployFailed": "部署失敗: __message__", "deployFailed": "部署失敗: __message__",
"unusedConfigNodes": "您有一些未使用的配置節點", "unusedConfigNodes": "您有一些未使用的配置節點",
"unusedConfigNodesButton":"搜索未使用的配置節點", "unusedConfigNodesLink": "點擊此處查看它們",
"unknownNodesButton":"搜索未知節點",
"invalidNodesButton":"搜索無效節點",
"errors": { "errors": {
"noResponse": "伺服器沒有回應" "noResponse": "伺服器沒有回應"
}, },
@ -397,28 +322,14 @@
"output": "輸出:", "output": "輸出:",
"status": "狀態節點", "status": "狀態節點",
"deleteSubflow": "刪除子流程", "deleteSubflow": "刪除子流程",
"confirmDelete": "您確定要刪除此子流程?",
"info": "詳細描述", "info": "詳細描述",
"category": "類別", "category": "類別",
"module": "模塊",
"license": "許可",
"licenseNone": "無",
"licenseOther": "其它",
"type": "節點類型",
"version": "版本",
"versionPlaceholder": "x.y.z",
"keys": "關鍵字",
"keysPlaceholder": "使用英文逗號分隔關鍵字",
"author": "作者",
"authorPlaceholder": "名字 <email@example.com>",
"desc": "描述",
"env": { "env": {
"restore": "恢復為默認子流程", "restore": "恢復為默認子流程",
"remove": "類別刪除環境變量" "remove": "類別刪除環境變量"
}, },
"errors": { "errors": {
"noNodesSelected": "<strong>無法創建子流程</strong>: 未選擇節點", "noNodesSelected": "<strong>無法創建子流程</strong>: 未選擇節點",
"acrossMultipleGroups": "無法跨多個組創建子流",
"multipleInputsToSelection": "<strong>無法創建子流程</strong>: 多個輸入到了選擇" "multipleInputsToSelection": "<strong>無法創建子流程</strong>: 多個輸入到了選擇"
} }
}, },
@ -441,12 +352,12 @@
"editConfig": "編輯 __type__ 配置", "editConfig": "編輯 __type__ 配置",
"addNewType": "添加新的 __type__ 節點", "addNewType": "添加新的 __type__ 節點",
"nodeProperties": "節點屬性", "nodeProperties": "節點屬性",
"label": "標簽", "label": "Label",
"color": "顏色", "color": "顏色",
"portLabels": "埠標籤", "portLabels": "埠標籤",
"labelInputs": "輸入", "labelInputs": "輸入",
"labelOutputs": "輸出", "labelOutputs": "輸出",
"settingIcon": "圖標", "settingIcon": "Icon",
"default": "默認", "default": "默認",
"noDefaultLabel": "無", "noDefaultLabel": "無",
"defaultLabel": "使用默認標籤", "defaultLabel": "使用默認標籤",
@ -459,7 +370,6 @@
"icon": "圖標", "icon": "圖標",
"inputType": "輸入類型", "inputType": "輸入類型",
"selectType": "選擇類型...", "selectType": "選擇類型...",
"loadCredentials": "加載節點憑證",
"inputs": { "inputs": {
"input": "輸入", "input": "輸入",
"select": "選擇", "select": "選擇",
@ -494,8 +404,7 @@
}, },
"errors": { "errors": {
"scopeChange": "更改範圍將使其他流程中的節點無法使用", "scopeChange": "更改範圍將使其他流程中的節點無法使用",
"invalidProperties": "無效的屬性:", "invalidProperties": "無效的屬性:"
"credentialLoadFailed": "無法加載節點憑據"
} }
}, },
"keyboard": { "keyboard": {
@ -507,14 +416,11 @@
"unassigned": "未分配", "unassigned": "未分配",
"global": "全局", "global": "全局",
"workspace": "工作區", "workspace": "工作區",
"editor": "編輯對話框",
"selectAll": "選擇所有節點", "selectAll": "選擇所有節點",
"selectNone": "取消所有選擇",
"selectAllConnected": "選擇所有連接的節點", "selectAllConnected": "選擇所有連接的節點",
"addRemoveNode": "從選擇中添加/刪除節點", "addRemoveNode": "從選擇中添加/刪除節點",
"editSelected": "編輯選定節點", "editSelected": "編輯選定節點",
"deleteSelected": "刪除選定節點或連結", "deleteSelected": "刪除選定節點或連結",
"deleteReconnect": "刪除並重新連接",
"importNode": "匯入節點", "importNode": "匯入節點",
"exportNode": "匯出節點", "exportNode": "匯出節點",
"nudgeNode": "移動所選節點(1px)", "nudgeNode": "移動所選節點(1px)",
@ -524,14 +430,10 @@
"copyNode": "複製所選節點", "copyNode": "複製所選節點",
"cutNode": "剪切所選節點", "cutNode": "剪切所選節點",
"pasteNode": "粘貼節點", "pasteNode": "粘貼節點",
"copyGroupStyle": "復製組樣式",
"pasteGroupStyle": "粘貼組樣式",
"undoChange": "撤銷上次執行的更改", "undoChange": "撤銷上次執行的更改",
"redoChange": "重做",
"searchBox": "打開搜尋框", "searchBox": "打開搜尋框",
"managePalette": "管理面板", "managePalette": "管理面板",
"actionList": "動作列表", "actionList": "動作列表"
"splitWireWithLinks": "使用Link節點拆分已選項"
}, },
"library": { "library": {
"library": "庫", "library": "庫",
@ -549,11 +451,12 @@
"types": { "types": {
"local": "本地", "local": "本地",
"examples": "例子" "examples": "例子"
} },
"exportToLibrary": "將節點匯出到庫"
}, },
"palette": { "palette": {
"noInfo": "無可用資訊", "noInfo": "無可用資訊",
"filter": "過濾已安裝模組", "filter": "過濾節點",
"search": "搜尋模組", "search": "搜尋模組",
"addCategory": "添加新的...", "addCategory": "添加新的...",
"label": { "label": {
@ -583,13 +486,11 @@
"nodeEnabled_plural": "啟用多個節點:", "nodeEnabled_plural": "啟用多個節點:",
"nodeDisabled": "禁用節點:", "nodeDisabled": "禁用節點:",
"nodeDisabled_plural": "禁用多個節點:", "nodeDisabled_plural": "禁用多個節點:",
"nodeUpgraded": "節點模組__module__升級到__version__版本", "nodeUpgraded": "節點模組__module__升級到__version__版本"
"unknownNodeRegistered": "加載節點錯誤: <ul><li>__type__<br>__error__</li></ul>"
}, },
"editor": { "editor": {
"title": "面板管理", "title": "面板管理",
"palette": "控製板", "palette": "Palette",
"allCatalogs": "所有目錄",
"times": { "times": {
"seconds": "秒前", "seconds": "秒前",
"minutes": "分前", "minutes": "分前",
@ -629,12 +530,9 @@
"tab-nodes": "節點", "tab-nodes": "節點",
"tab-install": "安裝", "tab-install": "安裝",
"sort": "排序:", "sort": "排序:",
"sortRelevance": "關聯",
"sortAZ": "a-z順序", "sortAZ": "a-z順序",
"sortRecent": "日期順序", "sortRecent": "日期順序",
"more": "增加 __count__ 個", "more": "增加 __count__ 個",
"upload": "上傳模塊tgz文件",
"refresh": "更新模塊列表",
"errors": { "errors": {
"catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制臺瞭解更多資訊", "catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制臺瞭解更多資訊",
"installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊", "installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊",
@ -704,10 +602,13 @@
"globalConfig": "全局配置節點", "globalConfig": "全局配置節點",
"triggerAction": "觸發動作", "triggerAction": "觸發動作",
"find": "在工作區中查找", "find": "在工作區中查找",
"copyItemUrl": "復製地址", "search": {
"copyURL2Clipboard": "復製地址到剪貼板", "configNodes": "配置節點",
"showFlow": "顯示流程", "unusedConfigNodes": "未使用的配置節點",
"hideFlow": "隱藏流程" "invalidNodes": "無效的節點",
"uknownNodes": "未知的節點",
"unusedSubflows": "未使用的子流程"
}
}, },
"help": { "help": {
"name": "幫助", "name": "幫助",
@ -717,8 +618,7 @@
"showHelp": "顯示幫助", "showHelp": "顯示幫助",
"showInOutline": "在大綱中顯示", "showInOutline": "在大綱中顯示",
"showTopics": "顯示主題", "showTopics": "顯示主題",
"noHelp": "未選擇幫助主題", "noHelp": "未選擇幫助主題"
"changeLog": "更新日誌"
}, },
"config": { "config": {
"name": "配置節點", "name": "配置節點",
@ -809,12 +709,6 @@
"committerTip": "保留空白以使用系統默認值", "committerTip": "保留空白以使用系統默認值",
"userName": "用戶名", "userName": "用戶名",
"email": "電子郵件", "email": "電子郵件",
"workflow": "工作流",
"workfowTip": "選擇您偏好的工作流",
"workflowManual": "手動",
"workflowManualTip": "所有更改都必須在“歷史記錄”側邊欄中手動提交",
"workflowAuto": "自動",
"workflowAutoTip": "每次部署後都會自動提交更改",
"sshKeys": "SSH密鑰", "sshKeys": "SSH密鑰",
"sshKeysTip": "允許您創建到遠程git存儲庫的安全連接。", "sshKeysTip": "允許您創建到遠程git存儲庫的安全連接。",
"add": "添加密鑰", "add": "添加密鑰",
@ -919,37 +813,24 @@
"json": "JSON", "json": "JSON",
"bin": "二進位流", "bin": "二進位流",
"date": "時間戳記", "date": "時間戳記",
"jsonata": "表達式", "jsonata": "expression",
"env": "環境變量", "env": "env variable",
"cred": "證書" "cred": "證書"
} }
}, },
"editableList": { "editableList": {
"add": "添加", "add": "添加"
"addTitle": "添加項"
}, },
"search": { "search": {
"history": "搜索歷史", "empty": "找不到匹配",
"clear": "清除所有", "addNode": "添加一個節點..."
"empty": "找不到匹配項",
"addNode": "添加一個節點...",
"options": {
"configNodes": "配置節點",
"unusedConfigNodes": "未使用的配置節點",
"invalidNodes": "無效的節點",
"uknownNodes": "未知的節點",
"unusedSubflows": "未使用的子流程",
"hiddenFlows": "隱藏的流程",
"modifiedNodes": "已修改的節點或流程",
"thisFlow": "當前流程"
}
}, },
"expressionEditor": { "expressionEditor": {
"functions": "功能", "functions": "功能",
"functionReference": "功能參考", "functionReference": "Function reference",
"insert": "插入", "insert": "插入",
"title": "JSONata運算式編輯器", "title": "JSONata運算式編輯器",
"test": "測試", "test": "Test",
"data": "示例消息", "data": "示例消息",
"result": "結果", "result": "結果",
"format": "格式表達方法", "format": "格式表達方法",
@ -960,28 +841,20 @@
"invalid-expr": "無效的JSONata運算式:\n __message__", "invalid-expr": "無效的JSONata運算式:\n __message__",
"invalid-msg": "無效的示例JSON消息:\n __message__", "invalid-msg": "無效的示例JSON消息:\n __message__",
"context-unsupported": "無法測試上下文函數\n $flowContext 或 $globalContext", "context-unsupported": "無法測試上下文函數\n $flowContext 或 $globalContext",
"env-unsupported": "無法測試 $env 函數",
"moment-unsupported": "無法測試 $moment 函數",
"clone-unsupported": "無法測試 $clone 函數",
"eval": "評估運算式錯誤:\n __message__" "eval": "評估運算式錯誤:\n __message__"
} }
}, },
"monaco": {
"setTheme": "設置主題"
},
"jsEditor": { "jsEditor": {
"title": "JavaScript 編輯器" "title": "JavaScript 編輯器"
}, },
"textEditor": { "textEditor": {
"title": "文本編輯器" "title": "Text 編輯器"
}, },
"jsonEditor": { "jsonEditor": {
"title": "JSON編輯器", "title": "JSON編輯器",
"format": "格式化JSON", "format": "格式化JSON",
"rawMode": "編輯 JSON", "rawMode": "編輯 JSON",
"uiMode": "可視化編輯器", "uiMode": "Visual編輯器",
"rawMode-readonly": "原始JSON",
"uiMode-readonly": "可視化",
"insertAbove": "在上方插入", "insertAbove": "在上方插入",
"insertBelow": "在下方插入", "insertBelow": "在下方插入",
"addItem": "添加項目", "addItem": "添加項目",
@ -997,9 +870,9 @@
"title": "Markdown 編輯器", "title": "Markdown 編輯器",
"expand": "展開", "expand": "展開",
"format": "F使用markdown格式化", "format": "F使用markdown格式化",
"heading1": "標題 1", "heading1": "Heading 1",
"heading2": "標題 2", "heading2": "Heading 2",
"heading3": "標題 3", "heading3": "Heading 3",
"bold": "粗體", "bold": "粗體",
"italic": "斜體", "italic": "斜體",
"code": "程式碼", "code": "程式碼",
@ -1008,10 +881,7 @@
"quote": "引用", "quote": "引用",
"link": "連結", "link": "連結",
"horizontal-rule": "分隔線", "horizontal-rule": "分隔線",
"toggle-preview": "切換預覽", "toggle-preview": "預覽"
"mermaid": {
"summary": "美人魚圖"
}
}, },
"bufferEditor": { "bufferEditor": {
"title": "緩衝區編輯器", "title": "緩衝區編輯器",
@ -1146,8 +1016,7 @@
"not-git": "不是git倉庫", "not-git": "不是git倉庫",
"no-resource": "找不到存儲庫", "no-resource": "找不到存儲庫",
"cant-get-ssh-key-path": "錯誤! 無法獲取所選的SSH密鑰路徑。", "cant-get-ssh-key-path": "錯誤! 無法獲取所選的SSH密鑰路徑。",
"unexpected_error": "意外的錯誤", "unexpected_error": "意外的錯誤"
"clearContext": "更改項目時清除上下文"
}, },
"delete": { "delete": {
"confirm": "您確定要刪除此項目嗎?" "confirm": "您確定要刪除此項目嗎?"
@ -1177,7 +1046,7 @@
"create-default-file-set": { "create-default-file-set": {
"no-active": "沒有活動項目就無法創建默認文件集", "no-active": "沒有活動項目就無法創建默認文件集",
"no-empty": "無法在非空項目上創建默認文件集", "no-empty": "無法在非空項目上創建默認文件集",
"git-error": "git錯誤" "git-error": "git error"
}, },
"errors": { "errors": {
"no-username-email": "您的Git客戶端未配置用戶名/電子郵件。", "no-username-email": "您的Git客戶端未配置用戶名/電子郵件。",
@ -1188,45 +1057,18 @@
"editor-tab": { "editor-tab": {
"properties": "屬性", "properties": "屬性",
"envProperties": "環境變量", "envProperties": "環境變量",
"module": "模塊屬性",
"description": "描述", "description": "描述",
"appearance": "外觀", "appearance": "外觀",
"preview": "UI預覽", "preview": "UI預覽",
"defaultValue": "默認值" "defaultValue": "默認值",
"env": "環境變量"
}, },
"tourGuide": { "languages": {
"takeATour": "查看更新內容", "de": "德語",
"start": "開始", "en-US": "英語",
"next": "下一個", "ja": "日語",
"welcomeTours": "歡迎使用 Node-RED" "ko": "韓語",
}, "zh-CN": "簡體中文",
"diagnostics": { "zh-TW": "繁體中文"
"title": "系统信息"
},
"validator": {
"errors": {
"invalid-json": "無效的 JSON 數據: __error__",
"invalid-expr": "無效的 JSONata 表達式: __error__",
"invalid-prop": "無效的屬性表達式",
"invalid-num": "無效的數字",
"invalid-regexp": "輸入格式無效",
"invalid-regex-prop": "__prop__: 輸入格式無效",
"missing-required-prop": "__prop__: 缺少屬性值",
"invalid-config": "__prop__: 無效的配置節點",
"missing-config": "__prop__: 缺少配置節點",
"validation-error": "__prop__: 驗證錯誤: __node__, __id__: __error__"
}
},
"contextMenu": {
"showActionList":"顯示動作列表",
"insert": "插入",
"node": "節點",
"junction": "連接點",
"linkNodes": "鏈接節點"
},
"env-var": {
"environment": "環境配置",
"header": "全局環境變量",
"revert": "重置"
} }
} }

View File

@ -137,7 +137,7 @@
}, },
"$sort": { "$sort": {
"args": "array [, function]", "args": "array [, function]",
"desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較`left``right`兩個值而被排序演算法調用的。如果使用者希望left的值被置於`right`的值之後,那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。" "desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較left和right兩個值而被排序演算法調用的。如果使用者希望left的值被置於right的值之後那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。"
}, },
"$reverse": { "$reverse": {
"args": "array", "args": "array",
@ -237,25 +237,25 @@
}, },
"$assert": { "$assert": {
"args": "arg, str", "args": "arg, str",
"desc": "如果`arg`為真,則該函數返回。 如果`arg`為假,則拋出帶有`str`的異常作為異常消息。" "desc": "如果`arg`為真,則該函數返回。 如果arg為假則拋出帶有str的異常作為異常消息。"
}, },
"$single": { "$single": {
"args": "array, function", "args": "array, function",
"desc": "返回滿足參數function謂語的array參數中的唯一值 (比如傳遞值時函數返回布林值“true”)。如果匹配值的數量不唯一時,則拋出異常。\n\n應在以下簽名中提供函數`functionvalue [index [array []]]`其中value是數組的每個輸入index是該值的位置整個數組作為第三個參數傳遞。" "desc": "返回滿足參數function謂語的array參數中的唯一值 (比如傳遞值時函數返回布林值“true”)。如果匹配值的數量不唯一時,則拋出異常。\n\n應在以下簽名中提供函數`functionvalue [index [array []]]`其中value是數組的每個輸入index是該值的位置整個數組作為第三個參數傳遞。"
}, },
"$encodeUrlComponent": { "$encodeUrl": {
"args": "str", "args": "str",
"desc": "通過用表示字符的UTF-8編碼的一個兩個三個或四個轉義序列替換某些字符的每個實例對統一資源定位符URL組件進行編碼。\n\n示例`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" "desc": "通過用表示字符的UTF-8編碼的一個兩個三個或四個轉義序列替換某些字符的每個實例對統一資源定位符URL組件進行編碼。\n\n示例`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
}, },
"$encodeUrl": { "$encodeUrlComponent": {
"args": "str", "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\"`" "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\"`"
}, },
"$decodeUrlComponent": { "$decodeUrl": {
"args": "str", "args": "str",
"desc": "解碼以前由encodeUrlComponent創建的統一資源定位器URL組件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" "desc": "解碼以前由encodeUrlComponent創建的統一資源定位器URL組件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
}, },
"$decodeUrl": { "$decodeUrlComponent": {
"args": "str", "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=шеллы\"`" "desc": "解碼先前由encodeUrl創建的統一資源定位符URL。 \n\n示例 `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
}, },
@ -270,9 +270,5 @@
"$moment": { "$moment": {
"args": "[str]", "args": "[str]",
"desc": "使用Moment庫獲取日期對象。" "desc": "使用Moment庫獲取日期對象。"
},
"$clone": {
"args": "value",
"desc": "安全克隆對象."
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@node-red/editor-client", "name": "@node-red/editor-client",
"version": "4.0.9", "version": "1.1.3",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",
@ -14,5 +14,5 @@
"name": "Dave Conway-Jones" "name": "Dave Conway-Jones"
} }
], ],
"main": "./index.js" "main": "./lib/index.js"
} }

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,8 @@
; (function() { ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippetText='# Prototype\nsnippet proto\n ${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n ${4:// body...}\n };\n# Function\nsnippet fun\n function ${1?:function_name}(${2:argument}) {\n ${3:// body...}\n }\n# Anonymous Function\nregex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\nsnippet f\n function${M1?: ${1:functionName}}($2) {\n ${0:$TM_SELECTED_TEXT}\n }${M2?;}${M3?,}${M4?)}\n# Immediate function\ntrigger \\(?f\\(\nendTrigger \\)?\nsnippet f(\n (function(${1}) {\n ${0:${TM_SELECTED_TEXT:/* code */}}\n }(${1}));\n# if\nsnippet if\n if (${1:true}) {\n ${0}\n }\n# if ... else\nsnippet ife\n if (${1:true}) {\n ${2}\n } else {\n ${0}\n }\n# tertiary conditional\nsnippet ter\n ${1:/* condition */} ? ${2:a} : ${3:b}\n# switch\nsnippet switch\n switch (${1:expression}) {\n case \'${3:case}\':\n ${4:// code}\n break;\n ${5}\n default:\n ${2:// code}\n }\n# case\nsnippet case\n case \'${1:case}\':\n ${2:// code}\n break;\n ${3}\n\n# while (...) {...}\nsnippet wh\n while (${1:/* condition */}) {\n ${0:/* code */}\n }\n# try\nsnippet try\n try {\n ${0:/* code */}\n } catch (e) {}\n# do...while\nsnippet do\n do {\n ${2:/* code */}\n } while (${1:/* condition */});\n# Object Method\nsnippet :f\nregex /([,{[])|^\\s*/:f/\n ${1:method_name}: function(${2:attribute}) {\n ${0}\n }${3:,}\n# setTimeout function\nsnippet setTimeout\nregex /\\b/st|timeout|setTimeo?u?t?/\n setTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n# console.log (Firebug)\nsnippet cl\n console.log(${1});\n# return\nsnippet ret\n return ${1:result}\n# for (property in object ) { ... }\nsnippet fori\n for (var ${1:prop} in ${2:Things}) {\n ${0:$2[$1]}\n }\n# hasOwnProperty\nsnippet has\n hasOwnProperty(${1})\n# docstring\nsnippet /**\n /**\n * ${1:description}\n *\n */\nsnippet @par\nregex /^\\s*\\*\\s*/@(para?m?)?/\n @param {${1:type}} ${2:name} ${3:description}\nsnippet @ret\n @return {${1:type}} ${2:description}\n# JSON.parse\nsnippet jsonp\n JSON.parse(${1:jstr});\n# JSON.stringify\nsnippet jsons\n JSON.stringify(${1:object});\n# self-defining function\nsnippet sdf\n var ${1:function_name} = function(${2:argument}) {\n ${3:// initial code ...}\n\n $1 = function($2) {\n ${4:// main code}\n };\n }\n# \nsnippet for-\n for (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n ${0:${2:Things}[${1:i}];}\n }\n# for (...) {...}\nsnippet for\n for (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n ${3:$2[$1]}$0\n }\n# for (...) {...} (Improved Native For-Loop)\nsnippet forr\n for (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n ${3:$2[$1]}$0\n }\n# Node-RED Specific Funcs\nsnippet nodes\n node.send(${1:msg})\nsnippet clone\n RED.util.cloneMessage(${1:msg})\nsnippet nodel\n node.log($1)\nsnippet nodew\n node.warn($1)\nsnippet nodee\n node.error($1)\nsnippet noded\n node.debug($1)\nsnippet done\n node.done($1)\nsnippet flowg\n flow.get($1)\nsnippet flows\n flow.set($1, $2)\nsnippet globalg\n global.get($1)\nsnippet globals\n global.set($1, $2)\n',t.scope="nrjavascript"});
(function() {
ace.require(["ace/snippets/nrjavascript"], function(m) { ace.require(["ace/snippets/nrjavascript"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) { if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m; module.exports = m;
} }
}); });
})(); })();

File diff suppressed because one or more lines are too long

View File

@ -76,12 +76,13 @@ oop.inherits(NRJavaScriptWorker, Mirror);
(function() { (function() {
this.setOptions = function(options) { this.setOptions = function(options) {
o.options = { this.options = options || {
// undef: true, // undef: true,
// unused: true, // unused: true,
esversion: 9, esnext: true,
moz: true,
devel: true, devel: true,
browser: false, browser: true,
node: true, node: true,
laxcomma: true, laxcomma: true,
laxbreak: true, laxbreak: true,
@ -91,17 +92,8 @@ oop.inherits(NRJavaScriptWorker, Mirror);
maxerr: 100, maxerr: 100,
expr: true, expr: true,
multistr: true, multistr: true,
strict: false, globalstrict: true
sub: true,
asi: true
}; };
if (options) {
for (var opt in options) {
if (options.hasOwnProperty(opt)) {
o.options[opt] = options[opt];
}
}
}
this.doc.getValue() && this.deferredUpdate.schedule(100); this.doc.getValue() && this.deferredUpdate.schedule(100);
}; };
@ -127,8 +119,6 @@ oop.inherits(NRJavaScriptWorker, Mirror);
if (!value) if (!value)
return this.sender.emit("annotate", []); return this.sender.emit("annotate", []);
var originalValue = value;
// [Node-RED] wrap the code in a function // [Node-RED] wrap the code in a function
value = "async function __nodered__(msg) {\n"+value+"\n}"; value = "async function __nodered__(msg) {\n"+value+"\n}";
@ -148,7 +138,6 @@ oop.inherits(NRJavaScriptWorker, Mirror);
continue; continue;
var raw = error.raw; var raw = error.raw;
var type = "warning"; var type = "warning";
var line = error.line - 2;
if (raw == "Missing semicolon.") { if (raw == "Missing semicolon.") {
var str = error.evidence.substr(error.character); var str = error.evidence.substr(error.character);
@ -177,62 +166,9 @@ oop.inherits(NRJavaScriptWorker, Mirror);
type = "info"; type = "info";
} }
if (raw === "Unmatched '{a}'." && line === -1) {
// This is an unmatched { error. It has incorrectly matched it
// against the { in the added line. Need to find the next valid {
// This code scans through the original code looking for the first '{'
// that is not in a comment or string.
// It will incorrectly find a '{' if it is inside a regex... but
// at least the error will be shown somwhere. There are only
// so many hours in the day to fix every tiny edge case of an
// edge case.
var inSingleComment = false;
var inMultiComment = false;
var inString = false;
var stringQ;
var lineNumber = 0;
for (var pos = 0;pos<originalValue.length;pos++) {
var c = originalValue[pos];
if (c === "\\") {
pos++;
} else if (inSingleComment) {
if (c === "\n") {
lineNumber++;
inSingleComment = false;
}
} else if (inMultiComment) {
if (c === "*" && originalValue[pos+1] === "/") {
pos++;
inMultiComment = false;
} else if (c === "\n") {
lineNumber++;
}
} else if (inString) {
if (c === stringQ) {
inString = false;
}
} else if (c === "'" || c === "\"") {
inString = true;
stringQ = c;
} else if (c === "/") {
if (originalValue[pos+1] === "/") {
inSingleComment = true;
} else if (originalValue[pos+1] === "*") {
inMultiComment = true;
}
} else if (c === "\n") {
lineNumber++;
} else if (c === "{") {
// found it!
break;
}
}
line = lineNumber;
}
errors.push({ errors.push({
// [Node-RED] offset the row for the added line // [Node-RED] offset the row for the added line
row: Math.max(0,line), row: error.line-2,
column: error.character-1, column: error.character-1,
text: error.reason, text: error.reason,
type: type, type: type,

View File

@ -1 +0,0 @@
<svg width="50" height="5" viewBox="0, 0, 50, 5" xmlns="http://www.w3.org/2000/svg"><path d="M0 1H50V4H0Z" fill="#CCC"/></svg>

Before

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

View File

@ -1 +0,0 @@
<svg width="5" height="50" viewBox="0, 0, 5, 50" xmlns="http://www.w3.org/2000/svg"><path d="M1 0H4V50H1Z" fill="#CCC"/></svg>

Before

Width:  |  Height:  |  Size: 127 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="512" width="512"><g transform="translate(0 -540.36)"><path fill="#8f0000" color="#000" d="M0 540.36h512v392H0z"/><rect ry="0" height="108.23" width="500.23" stroke="#fff" y="938.25" x="5.89" stroke-width="11.77" fill="#fff"/><path style="text-decoration-color:#000;isolation:auto;mix-blend-mode:normal;solid-color:#000;block-progression:tb;text-decoration-line:none;white-space:normal;text-indent:0;text-transform:none;text-decoration-style:solid" d="M122.88 305.82a4.46 4.46 0 0 0-4.38 4.42v.78c-2.23.1-4.04.54-5.33 1.43a10.5 10.5 0 0 0-3.18 3.87c-.71 1.3-1.3 2.41-2.15 3.2-.72.66-1.8 1.12-3.45 1.32a4.37 4.37 0 0 0-4.3-3.95H82.91a4.43 4.43 0 0 0-4.42 4.35v4.24a4.43 4.43 0 0 0 4.42 4.36h17.16a4.4 4.4 0 0 0 4.4-4.36v-1.6c9.72.14 12.46 2.6 15.59 5.33 3 2.62 6.66 5.38 15.43 5.5v.73a4.49 4.49 0 0 0 4.46 4.38h17.09c2.38 0 4.45-2 4.45-4.38v-4.24a4.49 4.49 0 0 0-4.45-4.38h-17.1c-2.38 0-4.45 2-4.45 4.38v.58c-8.1-.06-10.48-2.15-13.5-4.79-2.5-2.19-5.64-4.58-11.94-5.58 1.17-1.18 1.88-2.52 2.51-3.66.68-1.23 1.29-2.2 2.27-2.88.76-.52 1.98-.84 3.66-.94v.55c0 2.39 2 4.34 4.38 4.34h17.24a4.39 4.39 0 0 0 4.38-4.34v-4.24c0-2.38-2-4.42-4.38-4.42zm0 3h17.24c.8 0 1.38.62 1.38 1.42v4.24c0 .81-.57 1.34-1.38 1.34h-17.24c-.8 0-1.38-.53-1.38-1.34v-4.24c0-.8.57-1.42 1.38-1.42zm-39.96 11.02h17.16c.81 0 1.42.6 1.42 1.4v4.24c0 .81-.61 1.41-1.42 1.41H82.92c-.8 0-1.42-.6-1.42-1.4v-4.25c0-.8.61-1.4 1.42-1.4zm57.04 9.98h17.09c.8 0 1.45.57 1.45 1.38v4.17c0 .8-.65 1.45-1.45 1.45h-17.1c-.8 0-1.45-.65-1.45-1.45v-4.17c0-.8.65-1.38 1.46-1.38z" fill="#fff" color="#000" transform="matrix(4 0 0 4 -162 -450.91)"/><g fill="#8f0000"><path d="M91 954.34v8.45l-8 1.45v60.07H69.03l-28.53-47.1-.5.05v37.2l8 1.44v8.41H19v-8.4l7.45-1.45v-50.22L19 962.79v-8.46h21.48l28.37 47.1.15-.04v-37.15l-7-1.45v-8.45h29zM95 997.83q0-11.63 6.49-19.03 6.53-7.45 18.02-7.45 11.53 0 18.02 7.4 6.54 7.4 6.54 19.08v1q0 11.74-6.54 19.14-6.49 7.35-17.93 7.35-11.58 0-18.11-7.35-6.5-7.4-6.5-19.13v-1.01zm14.03 1q0 7.12 2.5 11.45 2.5 4.28 8.08 4.28 5.43 0 7.93-4.33 2.54-4.33 2.54-11.4v-1q0-6.92-2.54-11.3-2.55-4.37-8.03-4.37t-7.98 4.37-2.5 11.3v1zM184.48 1017.96a17.15 17.15 0 0 1-5.82 5.48 15.17 15.17 0 0 1-7.59 1.88c-6.4 0-11.4-2.35-14.95-7.03-3.52-4.67-5.13-10.86-5.13-18.55v-1c0-8.21 1.62-14.83 5.18-19.86 3.56-5.03 8.56-7.54 15-7.54 2.6 0 4.93.57 7.01 1.73a17.94 17.94 0 0 1 5.81 4.8v-18.64l-8-1.45v-8.46h22v65.13l6 1.44v8.43h-18.45l-1.06-6.36zm-19.49-18.22c0 4.55.63 8.14 2.14 10.77 1.54 2.6 4.04 3.9 7.5 3.9 2.05 0 3.83-.43 5.33-1.26 1.5-.83 3.07-2.03 4.03-3.6v-22.06a11.27 11.27 0 0 0-4.03-3.85 9.62 9.62 0 0 0-5.24-1.4c-3.43 0-5.92 1.53-7.5 4.57s-2.23 7.02-2.23 11.92v1.01zM233.7 1025.28c-7.5 0-13.5-2.4-17.98-7.21-4.48-4.81-6.73-10.91-6.73-18.32v-1.92c0-7.72 2.12-14.08 6.35-19.08 4.26-5 9.96-7.46 17.1-7.43 7.03 0 12.47 2.1 16.35 6.33a23.46 23.46 0 0 1 6.2 17.15v7.52h-31.43l-.1.41c.26 3.43 1.4 6.25 3.41 8.46 2.05 2.21 4.83 3.32 8.32 3.32 3.1 0 5.69-.3 7.74-.91 2.05-.64 4.29-1.64 6.73-2.98l3.8 8.65a27.59 27.59 0 0 1-8.37 4.28 35.28 35.28 0 0 1-11.4 1.73zm-1.25-43.16c-2.6 0-4.65.99-6.15 2.98s-2.44 4.6-2.8 7.83l.15.4H241v-1.41c0-2.98-.84-5.35-2.25-7.11-1.37-1.8-3.47-2.7-6.3-2.7zM291.99 1000.32h-27v-11h27zM331.88 954.34c7.95 0 14.18 1.82 18.7 5.47 4.52 3.63 6.4 8.64 6.4 15.05 0 3.52-.57 6.58-2.46 9.18-1.89 2.6-4.66 4.7-8.31 6.3 4.13 1.21 7.1 3.25 8.89 6.1a19.02 19.02 0 0 1 2.89 10.52v3.56c0 1.54.15 2.74.76 3.6.6.84 1.62 1.34 3.03 1.5l1.2.24v8.46h-6.73c-4.58 0-7.8-1.24-9.66-3.7s-2.6-5.66-2.6-9.57v-3.99c0-3.4-1.1-6.05-2.93-7.98-1.8-1.95-4.34-2.98-7.64-3.07H322v18.45l7 1.44v8.42h-29v-8.42l8-1.44v-50.22l-8-1.44v-8.46h31.89zm-9.95 30.85h9.71c3.91 0 6.84-.83 8.8-2.5s2.93-4.07 2.93-7.2c0-3.15-.98-5.65-2.93-7.5-1.92-1.9-4.78-2.84-8.56-2.84h-9.9v20.04zM412.99 993.32h-23v20h22.21l.63-8h10.2v18.99H368v-8.42l8-1.44v-50.22l-8-1.44v-8.47h54.95v19h-10.3l-.63-8H390v17h23v11zM462.48 954.36c8.55 0 15.6 2.71 21.14 8.19 5.55 5.45 8.36 12.42 8.36 20.98v11.58c0 8.59-2.81 15.63-8.36 21.08-5.54 5.41-12.59 8.12-21.14 8.12h-31.5v-8.41l7-1.52v-50.22l-7-1.37v-8.43l7.46-.08 24.04.08zm-10.5 10.76v48.4l9.77.02c5.03.02 8.98-1.7 11.83-5.1 2.85-3.39 4.4-7.8 4.4-13.28v-11.68c0-5.42-1.55-9.84-4.4-13.24-2.85-3.4-6.8-5.1-11.83-5.1l-9.77-.02z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,4 +0,0 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg">
<path color="#000" fill="#8c101c" d="M0 0h32v32H0z"></path>
<path style="fill:#ffffff;stroke:#000000;stroke-width:0" d="M 24,16 8,24 8,8 Z" fill="none" stroke="#000" stroke-width="1.5"></path>
</svg>

Before

Width:  |  Height:  |  Size: 271 B

View File

@ -1,4 +0,0 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg">
<path color="#000" fill="#8c101c" d="M0 0h32v32H0z"></path>
<rect style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0;" width="15" height="15" x="8" y="8.5"></rect>
</svg>

Before

Width:  |  Height:  |  Size: 256 B

View File

@ -26,15 +26,6 @@ RED.comms = (function() {
var reconnectAttempts = 0; var reconnectAttempts = 0;
var active = false; var active = false;
RED.events.on('login', function(username) {
// User has logged in
// Need to upgrade the connection to be authenticated
if (ws && ws.readyState == 1) {
const auth_tokens = RED.settings.get("auth-tokens");
ws.send(JSON.stringify({auth:auth_tokens.access_token}))
}
})
function connectWS() { function connectWS() {
active = true; active = true;
var wspath; var wspath;
@ -65,7 +56,6 @@ RED.comms = (function() {
ws.send(JSON.stringify({subscribe:t})); ws.send(JSON.stringify({subscribe:t}));
} }
} }
emit('connect')
} }
ws = new WebSocket(wspath); ws = new WebSocket(wspath);
@ -190,53 +180,9 @@ RED.comms = (function() {
} }
} }
function send(topic, msg) {
if (ws && ws.readyState == 1) {
ws.send(JSON.stringify({
topic,
data: msg
}))
}
}
const eventHandlers = {};
function on(evt,func) {
eventHandlers[evt] = eventHandlers[evt]||[];
eventHandlers[evt].push(func);
}
function off(evt,func) {
const handler = eventHandlers[evt];
if (handler) {
for (let i=0;i<handler.length;i++) {
if (handler[i] === func) {
handler.splice(i,1);
return;
}
}
}
}
function emit() {
const evt = arguments[0]
const args = Array.prototype.slice.call(arguments,1);
if (eventHandlers[evt]) {
let cpyHandlers = [...eventHandlers[evt]];
for (let i=0;i<cpyHandlers.length;i++) {
try {
cpyHandlers[i].apply(null, args);
} catch(err) {
console.warn("RED.comms.emit error: ["+evt+"] "+(err.toString()));
console.warn(err);
}
}
}
}
return { return {
connect: connectWS, connect: connectWS,
subscribe: subscribe, subscribe: subscribe,
unsubscribe:unsubscribe, unsubscribe:unsubscribe
on,
off,
send
} }
})(); })();

View File

@ -39,16 +39,15 @@
console.warn(evt,args); console.warn(evt,args);
} }
if (handlers[evt]) { if (handlers[evt]) {
let cpyHandlers = [...handlers[evt]]; for (var i=0;i<handlers[evt].length;i++) {
for (var i=0;i<cpyHandlers.length;i++) {
try { try {
cpyHandlers[i].apply(null, args); handlers[evt][i].apply(null, args);
} catch(err) { } catch(err) {
console.warn("RED.events.emit error: ["+evt+"] "+(err.toString())); console.warn("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.warn(err); console.warn(err);
} }
} }
} }
} }
return { return {

View File

@ -13,30 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
/**
* An API for undo / redo history buffer
* @namespace RED.history
*/
RED.history = (function() { RED.history = (function() {
var undoHistory = []; var undoHistory = [];
var redoHistory = []; var redoHistory = [];
function nodeOrJunction(id) {
var node = RED.nodes.node(id);
if (node) {
return node;
}
return RED.nodes.junction(id);
}
function ensureUnlocked(id, flowsToLock) {
const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null);
const isLocked = flow ? flow.locked : false;
if (flow && isLocked) {
flow.locked = false;
flowsToLock.add(flow)
}
}
function undoEvent(ev) { function undoEvent(ev) {
var i; var i;
var len; var len;
@ -57,71 +37,25 @@ RED.history = (function() {
inverseEv.events.push(r); inverseEv.events.push(r);
} }
} else if (ev.t == 'replace') { } else if (ev.t == 'replace') {
if (ev.complete) {
// This is a replace of everything. We can short-cut
// the logic by clearing everyting first, then importing
// the ev.config.
// Used by RED.diff.mergeDiff
inverseEv = { inverseEv = {
t: 'replace', t: 'replace',
config: RED.nodes.createCompleteNodeSet(), config: RED.nodes.createCompleteNodeSet(),
changed: {}, changed: {},
moved: {}, rev: RED.nodes.version()
complete: true,
rev: RED.nodes.version(),
dirty: RED.nodes.dirty()
}; };
var selectedTab = RED.workspaces.active();
inverseEv.config.forEach(n => {
const node = RED.nodes.node(n.id)
if (node) {
inverseEv.changed[n.id] = node.changed
inverseEv.moved[n.id] = node.moved
}
})
RED.nodes.clear(); RED.nodes.clear();
var imported = RED.nodes.import(ev.config); var imported = RED.nodes.import(ev.config);
// Clear all change flags from the import imported[0].forEach(function(n) {
RED.nodes.dirty(false);
const flowsToLock = new Set()
imported.nodes.forEach(function(n) {
if (ev.changed[n.id]) { if (ev.changed[n.id]) {
ensureUnlocked(n.z, flowsToLock)
n.changed = true; n.changed = true;
inverseEv.changed[n.id] = true;
} }
if (ev.moved[n.id]) {
ensureUnlocked(n.z, flowsToLock)
n.moved = true;
}
})
flowsToLock.forEach(flow => {
flow.locked = true
}) })
RED.nodes.version(ev.rev); RED.nodes.version(ev.rev);
RED.view.redraw(true);
RED.palette.refresh();
RED.workspaces.refresh();
RED.workspaces.show(selectedTab, true);
RED.sidebar.config.refresh();
} else {
var importMap = {};
ev.config.forEach(function(n) {
importMap[n.id] = "replace";
})
var importedResult = RED.nodes.import(ev.config,{importMap: importMap})
inverseEv = {
t: 'replace',
config: importedResult.removedNodes,
dirty: RED.nodes.dirty()
}
}
} else if (ev.t == 'add') { } else if (ev.t == 'add') {
inverseEv = { inverseEv = {
t: "delete", t: "delete",
dirty: RED.nodes.dirty()
}; };
if (ev.nodes) { if (ev.nodes) {
inverseEv.nodes = []; inverseEv.nodes = [];
@ -149,23 +83,6 @@ RED.history = (function() {
RED.nodes.removeLink(ev.links[i]); RED.nodes.removeLink(ev.links[i]);
} }
} }
if (ev.junctions) {
inverseEv.junctions = [];
for (i=0;i<ev.junctions.length;i++) {
inverseEv.junctions.push(ev.junctions[i]);
RED.nodes.removeJunction(ev.junctions[i]);
if (ev.junctions[i].g) {
var group = RED.nodes.group(ev.junctions[i].g);
var index = group.nodes.indexOf(ev.junctions[i]);
if (index !== -1) {
group.nodes.splice(index,1);
RED.group.markDirty(group);
}
}
}
}
if (ev.groups) { if (ev.groups) {
inverseEv.groups = []; inverseEv.groups = [];
for (i = ev.groups.length - 1;i>=0;i--) { for (i = ev.groups.length - 1;i>=0;i--) {
@ -225,8 +142,7 @@ RED.history = (function() {
} else if (ev.t == "delete") { } else if (ev.t == "delete") {
inverseEv = { inverseEv = {
t: "add", t: "add"
dirty: RED.nodes.dirty()
}; };
if (ev.workspaces) { if (ev.workspaces) {
inverseEv.workspaces = []; inverseEv.workspaces = [];
@ -332,21 +248,6 @@ RED.history = (function() {
} }
} }
} }
if (ev.junctions) {
inverseEv.junctions = [];
for (i=0;i<ev.junctions.length;i++) {
inverseEv.junctions.push(ev.junctions[i]);
RED.nodes.addJunction(ev.junctions[i]);
if (ev.junctions[i].g) {
group = RED.nodes.group(ev.junctions[i].g);
if (group.nodes.indexOf(ev.junctions[i]) === -1) {
group.nodes.push(ev.junctions[i]);
}
RED.group.markDirty(group)
}
}
}
if (ev.links) { if (ev.links) {
inverseEv.links = []; inverseEv.links = [];
for (i=0;i<ev.links.length;i++) { for (i=0;i<ev.links.length;i++) {
@ -383,12 +284,11 @@ RED.history = (function() {
} else if (ev.t == "move") { } else if (ev.t == "move") {
inverseEv = { inverseEv = {
t: 'move', t: 'move',
nodes: [], nodes: []
dirty: RED.nodes.dirty()
}; };
for (i=0;i<ev.nodes.length;i++) { for (i=0;i<ev.nodes.length;i++) {
var n = ev.nodes[i]; var n = ev.nodes[i];
var rn = {n: n.n, ox: n.n.x, oy: n.n.y, dirty: true, moved: n.n.moved}; var rn = {n: n.n, ox: n.n.x, oy: n.n.y, dirty: true, moved: n.moved};
inverseEv.nodes.push(rn); inverseEv.nodes.push(rn);
n.n.x = n.ox; n.n.x = n.ox;
n.n.y = n.oy; n.n.y = n.oy;
@ -413,104 +313,35 @@ RED.history = (function() {
if (ev.addToGroup) { if (ev.addToGroup) {
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false); RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false);
inverseEv.removeFromGroup = ev.addToGroup; inverseEv.removeFromGroup = ev.addToGroup;
} } else if (ev.removeFromGroup) {
if (ev.removeFromGroup) {
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n })); RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
inverseEv.addToGroup = ev.removeFromGroup; inverseEv.addToGroup = ev.removeFromGroup;
} }
} else if (ev.t == "edit") { } else if (ev.t == "edit") {
inverseEv = { inverseEv = {
t: "edit", t: "edit",
changes: {}, changes: {}
changed: ev.node.changed,
dirty: RED.nodes.dirty()
}; };
inverseEv.node = ev.node; inverseEv.node = ev.node;
for (i in ev.changes) { for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) { if (ev.changes.hasOwnProperty(i)) {
inverseEv.changes[i] = ev.node[i]; inverseEv.changes[i] = ev.node[i];
if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) { if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
// This property is a reference to another node or nodes. // This is a config node property
var nodeList = ev.node[i]; var currentConfigNode = RED.nodes.node(ev.node[i]);
if (!Array.isArray(nodeList)) { if (currentConfigNode) {
nodeList = [nodeList];
}
nodeList.forEach(function(id) {
var currentConfigNode = RED.nodes.node(id);
if (currentConfigNode && currentConfigNode._def.category === "config") {
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1); currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
RED.events.emit("nodes:change",currentConfigNode); RED.events.emit("nodes:change",currentConfigNode);
} }
}); var newConfigNode = RED.nodes.node(ev.changes[i]);
nodeList = ev.changes[i]; if (newConfigNode) {
if (!Array.isArray(nodeList)) {
nodeList = [nodeList];
}
nodeList.forEach(function(id) {
var newConfigNode = RED.nodes.node(id);
if (newConfigNode && newConfigNode._def.category === "config") {
newConfigNode.users.push(ev.node); newConfigNode.users.push(ev.node);
RED.events.emit("nodes:change",newConfigNode); RED.events.emit("nodes:change",newConfigNode);
} }
});
} else if (i === "env" && ev.node.type.indexOf("subflow:") === 0) {
// Subflow can have config node in node.env
let nodeList = ev.node.env || [];
nodeList = nodeList.reduce((list, prop) => {
if (prop.type === "conf-type" && prop.value) {
list.push(prop.value);
} }
return list;
}, []);
nodeList.forEach(function(id) {
const configNode = RED.nodes.node(id);
if (configNode) {
if (configNode.users.indexOf(ev.node) !== -1) {
configNode.users.splice(configNode.users.indexOf(ev.node), 1);
RED.events.emit("nodes:change", configNode);
}
}
});
nodeList = ev.changes.env || [];
nodeList = nodeList.reduce((list, prop) => {
if (prop.type === "conf-type" && prop.value) {
list.push(prop.value);
}
return list;
}, []);
nodeList.forEach(function(id) {
const configNode = RED.nodes.node(id);
if (configNode) {
if (configNode.users.indexOf(ev.node) === -1) {
configNode.users.push(ev.node);
RED.events.emit("nodes:change", configNode);
}
}
});
}
if (i === "credentials" && ev.changes[i]) {
// Reset - Only want to keep the changes
inverseEv.changes[i] = {};
for (const [key, value] of Object.entries(ev.changes[i])) {
// Edge case: node.credentials is cleared after a deploy, so we can't
// capture values for the inverse event when undoing past a deploy
if (ev.node.credentials) {
inverseEv.changes[i][key] = ev.node.credentials[key];
}
ev.node.credentials[key] = value;
}
} else {
ev.node[i] = ev.changes[i]; ev.node[i] = ev.changes[i];
} }
} }
}
ev.node.dirty = true;
ev.node.changed = ev.changed;
var eventType; var eventType;
switch(ev.node.type) { switch(ev.node.type) {
case 'tab': eventType = "flows"; break; case 'tab': eventType = "flows"; break;
@ -524,9 +355,7 @@ RED.history = (function() {
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) { if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled); $("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled);
} $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled);
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('locked')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!ev.node.locked);
} }
if (ev.subflow) { if (ev.subflow) {
inverseEv.subflow = {}; inverseEv.subflow = {};
@ -587,24 +416,6 @@ RED.history = (function() {
RED.editor.updateNodeProperties(ev.node,outputMap); RED.editor.updateNodeProperties(ev.node,outputMap);
RED.editor.validateNode(ev.node); RED.editor.validateNode(ev.node);
} }
// If it's a Config Node, validate user nodes too.
// NOTE: The Config Node must be validated before validating users.
if (ev.node.users) {
const validatedNodes = new Set();
const userStack = ev.node.users.slice();
validatedNodes.add(ev.node.id);
while (userStack.length) {
const node = userStack.pop();
if (!validatedNodes.has(node.id)) {
validatedNodes.add(node.id);
if (node.users) {
userStack.push(...node.users);
}
RED.editor.validateNode(node);
}
}
}
if (ev.links) { if (ev.links) {
inverseEv.createdLinks = []; inverseEv.createdLinks = [];
for (i=0;i<ev.links.length;i++) { for (i=0;i<ev.links.length;i++) {
@ -619,6 +430,8 @@ RED.history = (function() {
inverseEv.links.push(ev.createdLinks[i]); inverseEv.links.push(ev.createdLinks[i]);
} }
} }
ev.node.dirty = true;
ev.node.changed = ev.changed;
} else if (ev.t == "createSubflow") { } else if (ev.t == "createSubflow") {
inverseEv = { inverseEv = {
t: "deleteSubflow", t: "deleteSubflow",
@ -630,7 +443,6 @@ RED.history = (function() {
var z = ev.activeWorkspace; var z = ev.activeWorkspace;
var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id}); var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id)) fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
fullNodeList = fullNodeList.concat(RED.nodes.junctions(ev.subflow.subflow.id))
fullNodeList.forEach(function(n) { fullNodeList.forEach(function(n) {
n.x += ev.subflow.offsetX; n.x += ev.subflow.offsetX;
n.y += ev.subflow.offsetY; n.y += ev.subflow.offsetY;
@ -640,7 +452,7 @@ RED.history = (function() {
}); });
inverseEv.subflows = []; inverseEv.subflows = [];
for (i=0;i<ev.nodes.length;i++) { for (i=0;i<ev.nodes.length;i++) {
inverseEv.subflows.push(nodeOrJunction(ev.nodes[i])); inverseEv.subflows.push(RED.nodes.node(ev.nodes[i]));
RED.nodes.remove(ev.nodes[i]); RED.nodes.remove(ev.nodes[i]);
} }
} }
@ -712,22 +524,10 @@ RED.history = (function() {
} else if (ev.t == "reorder") { } else if (ev.t == "reorder") {
inverseEv = { inverseEv = {
t: 'reorder', t: 'reorder',
dirty: RED.nodes.dirty() order: RED.nodes.getWorkspaceOrder()
}; };
if (ev.workspaces) { if (ev.order) {
inverseEv.workspaces = { RED.workspaces.order(ev.order);
from: ev.workspaces.to,
to: ev.workspaces.from
}
RED.workspaces.order(ev.workspaces.from);
}
if (ev.nodes) {
inverseEv.nodes = {
z: ev.nodes.z,
from: ev.nodes.to,
to: ev.nodes.from
}
RED.nodes.setNodeOrder(ev.nodes.z,ev.nodes.from);
} }
} else if (ev.t == "createGroup") { } else if (ev.t == "createGroup") {
inverseEv = { inverseEv = {
@ -754,12 +554,6 @@ RED.history = (function() {
ev.groups[i].nodes = []; ev.groups[i].nodes = [];
RED.nodes.addGroup(ev.groups[i]); RED.nodes.addGroup(ev.groups[i]);
RED.group.addToGroup(ev.groups[i],nodes); RED.group.addToGroup(ev.groups[i],nodes);
if (ev.groups[i].g) {
const parentGroup = RED.nodes.group(ev.groups[i].g)
if (parentGroup) {
RED.group.addToGroup(parentGroup, ev.groups[i])
}
}
} }
} }
} else if (ev.t == "addToGroup") { } else if (ev.t == "addToGroup") {
@ -829,8 +623,6 @@ RED.history = (function() {
push: function(ev) { push: function(ev) {
undoHistory.push(ev); undoHistory.push(ev);
redoHistory = []; redoHistory = [];
RED.menu.setDisabled("menu-item-edit-undo", false);
RED.menu.setDisabled("menu-item-edit-redo", true);
}, },
pop: function() { pop: function() {
var ev = undoHistory.pop(); var ev = undoHistory.pop();
@ -838,24 +630,13 @@ RED.history = (function() {
if (rev) { if (rev) {
redoHistory.push(rev); redoHistory.push(rev);
} }
RED.menu.setDisabled("menu-item-edit-undo", undoHistory.length === 0);
RED.menu.setDisabled("menu-item-edit-redo", redoHistory.length === 0);
}, },
peek: function() { peek: function() {
return undoHistory[undoHistory.length-1]; return undoHistory[undoHistory.length-1];
}, },
replace: function(ev) {
if (undoHistory.length === 0) {
RED.history.push(ev);
} else {
undoHistory[undoHistory.length-1] = ev;
}
},
clear: function() { clear: function() {
undoHistory = []; undoHistory = [];
redoHistory = []; redoHistory = [];
RED.menu.setDisabled("menu-item-edit-undo", true);
RED.menu.setDisabled("menu-item-edit-redo", true);
}, },
redo: function() { redo: function() {
var ev = redoHistory.pop(); var ev = redoHistory.pop();
@ -865,8 +646,6 @@ RED.history = (function() {
undoHistory.push(uev); undoHistory.push(uev);
} }
} }
RED.menu.setDisabled("menu-item-edit-undo", undoHistory.length === 0);
RED.menu.setDisabled("menu-item-edit-redo", redoHistory.length === 0);
} }
} }

View File

@ -1,156 +0,0 @@
RED.hooks = (function() {
var VALID_HOOKS = [
]
var hooks = { }
var labelledHooks = { }
function add(hookId, callback) {
var parts = hookId.split(".");
var id = parts[0], label = parts[1];
// if (VALID_HOOKS.indexOf(id) === -1) {
// throw new Error("Invalid hook '"+id+"'");
// }
if (label && labelledHooks[label] && labelledHooks[label][id]) {
throw new Error("Hook "+hookId+" already registered")
}
var hookItem = {cb:callback, previousHook: null, nextHook: null }
var tailItem = hooks[id];
if (tailItem === undefined) {
hooks[id] = hookItem;
} else {
while(tailItem.nextHook !== null) {
tailItem = tailItem.nextHook
}
tailItem.nextHook = hookItem;
hookItem.previousHook = tailItem;
}
if (label) {
labelledHooks[label] = labelledHooks[label]||{};
labelledHooks[label][id] = hookItem;
}
}
function remove(hookId) {
var parts = hookId.split(".");
var id = parts[0], label = parts[1];
if ( !label) {
throw new Error("Cannot remove hook without label: "+hookId)
}
if (labelledHooks[label]) {
if (id === "*") {
// Remove all hooks for this label
var hookList = Object.keys(labelledHooks[label]);
for (var i=0;i<hookList.length;i++) {
removeHook(hookList[i],labelledHooks[label][hookList[i]])
}
delete labelledHooks[label];
} else if (labelledHooks[label][id]) {
removeHook(id,labelledHooks[label][id])
delete labelledHooks[label][id];
if (Object.keys(labelledHooks[label]).length === 0){
delete labelledHooks[label];
}
}
}
}
function removeHook(id,hookItem) {
var previousHook = hookItem.previousHook;
var nextHook = hookItem.nextHook;
if (previousHook) {
previousHook.nextHook = nextHook;
} else {
hooks[id] = nextHook;
}
if (nextHook) {
nextHook.previousHook = previousHook;
}
hookItem.removed = true;
if (!previousHook && !nextHook) {
delete hooks[id];
}
}
function trigger(hookId, payload, done) {
var hookItem = hooks[hookId];
if (!hookItem) {
if (done) {
done();
}
return;
}
function callNextHook(err) {
if (!hookItem || err) {
if (done) { done(err) }
return err;
}
if (hookItem.removed) {
hookItem = hookItem.nextHook;
return callNextHook();
}
var callback = hookItem.cb;
if (callback.length === 1) {
try {
let result = callback(payload);
if (result === false) {
// Halting the flow
if (done) { done(false) }
return result;
}
hookItem = hookItem.nextHook;
return callNextHook();
} catch(e) {
console.warn(e);
if (done) { done(e);}
return e;
}
} else {
// There is a done callback
try {
callback(payload,function(result) {
if (result === undefined) {
hookItem = hookItem.nextHook;
callNextHook();
} else {
if (done) { done(result)}
}
})
} catch(e) {
console.warn(e);
if (done) { done(e) }
return e;
}
}
}
return callNextHook();
}
function clear() {
hooks = {}
labelledHooks = {}
}
function has(hookId) {
var parts = hookId.split(".");
var id = parts[0], label = parts[1];
if (label) {
return !!(labelledHooks[label] && labelledHooks[label][id])
}
return !!hooks[id]
}
return {
has: has,
clear: clear,
add: add,
remove: remove,
trigger: trigger
}
})();

View File

@ -18,69 +18,53 @@ RED.i18n = (function() {
var apiRootUrl; var apiRootUrl;
function detectLanguage() {
return navigator.language
}
return { return {
init: function(options, done) { init: function(options, done) {
apiRootUrl = options.apiRootUrl||""; apiRootUrl = options.apiRootUrl||"";
var preferredLanguage = localStorage.getItem("editor-language") || detectLanguage(); var preferredLanguage = localStorage.getItem("editor-language");
var opts = { var opts = {
compatibilityJSON: 'v3', resGetPath: apiRootUrl+'locales/__ns__?lng=__lng__',
backend: { dynamicLoad: false,
loadPath: apiRootUrl+'locales/__ns__?lng=__lng__', load:'current',
ns: {
namespaces: ["editor","node-red","jsonata","infotips"],
defaultNs: "editor"
}, },
lng: 'en-US',
// debug: true,
preload:['en-US'],
ns: ["editor","node-red","jsonata","infotips"],
defaultNS: "editor",
fallbackLng: ['en-US'], fallbackLng: ['en-US'],
returnObjects: true, useCookie: false,
keySeparator: ".", returnObjectTrees: true
nsSeparator: ":",
interpolation: {
unescapeSuffix: 'HTML',
escapeValue: false,
prefix: '__',
suffix: '__'
}
}; };
if (preferredLanguage) { if (preferredLanguage) {
opts.lng = preferredLanguage; opts.lng = preferredLanguage;
} }
i18n.init(opts,function() {
i18next.use(i18nextHttpBackend).init(opts,function() {
done(); done();
}); });
jqueryI18next.init(i18next, $, { handleName: 'i18n' });
RED["_"] = function() { RED["_"] = function() {
var v = i18next.t.apply(i18next,arguments); var v = i18n.t.apply(null,arguments);
if (typeof v === 'string') { if (typeof v === 'string') {
return v; return v;
} else { } else {
return arguments[0]; return arguments[0];
} }
} }
}, },
lang: function() { lang: function() {
// Gets the active message catalog language. This is based on what // Gets the active message catalog language. This is based on what
// locale the editor is using and what languages are available. // locale the editor is using and what languages are available.
// //
var preferredLangs = [localStorage.getItem("editor-language")|| detectLanguage()].concat(i18next.languages); var preferredLangs = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var knownLangs = RED.settings.theme("languages")||["en-US"]; var knownLangs = RED.settings.theme("languages")||["en-US"];
for (var i=0;i<preferredLangs.length;i++) { for (var i=0;i<preferredLangs.length;i++) {
if (knownLangs.indexOf(preferredLangs[i]) > -1) { if (knownLangs.indexOf(preferredLangs[i]) > -1) {
return preferredLangs[i] return preferredLangs[i]
} }
} }
return 'en-US' return 'end-US'
}, },
loadNodeCatalog: function(namespace,done) { loadNodeCatalog: function(namespace,done) {
var languageList = [localStorage.getItem("editor-language")|| detectLanguage()].concat(i18next.languages); var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var toLoad = languageList.length; var toLoad = languageList.length;
languageList.forEach(function(lang) { languageList.forEach(function(lang) {
$.ajax({ $.ajax({
@ -90,7 +74,7 @@ RED.i18n = (function() {
cache: false, cache: false,
url: apiRootUrl+'nodes/'+namespace+'/messages?lng='+lang, url: apiRootUrl+'nodes/'+namespace+'/messages?lng='+lang,
success: function(data) { success: function(data) {
i18next.addResourceBundle(lang,namespace,data); i18n.addResourceBundle(lang,namespace,data);
toLoad--; toLoad--;
if (toLoad === 0) { if (toLoad === 0) {
done(); done();
@ -102,7 +86,7 @@ RED.i18n = (function() {
}, },
loadNodeCatalogs: function(done) { loadNodeCatalogs: function(done) {
var languageList = [localStorage.getItem("editor-language")|| detectLanguage()].concat(i18next.languages); var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var toLoad = languageList.length; var toLoad = languageList.length;
languageList.forEach(function(lang) { languageList.forEach(function(lang) {
@ -115,7 +99,7 @@ RED.i18n = (function() {
success: function(data) { success: function(data) {
var namespaces = Object.keys(data); var namespaces = Object.keys(data);
namespaces.forEach(function(ns) { namespaces.forEach(function(ns) {
i18next.addResourceBundle(lang,ns,data[ns]); i18n.addResourceBundle(lang,ns,data[ns]);
}); });
toLoad--; toLoad--;
if (toLoad === 0) { if (toLoad === 0) {
@ -124,32 +108,6 @@ RED.i18n = (function() {
} }
}); });
}) })
},
loadPluginCatalogs: function(done) {
var languageList = [localStorage.getItem("editor-language")|| detectLanguage()].concat(i18next.languages);
var toLoad = languageList.length;
languageList.forEach(function(lang) {
$.ajax({
headers: {
"Accept":"application/json"
},
cache: false,
url: apiRootUrl+'plugins/messages?lng='+lang,
success: function(data) {
var namespaces = Object.keys(data);
namespaces.forEach(function(ns) {
i18next.addResourceBundle(lang,ns,data[ns]);
});
toLoad--;
if (toLoad === 0) {
done();
} }
} }
});
})
},
detectLanguage: detectLanguage
}
})(); })();

View File

@ -3,12 +3,16 @@
"alt-shift-p":"core:manage-palette", "alt-shift-p":"core:manage-palette",
"ctrl-f": "core:search", "ctrl-f": "core:search",
"ctrl-shift-f": "core:list-flows", "ctrl-shift-f": "core:list-flows",
"ctrl-=": "core:zoom-in",
"ctrl--": "core:zoom-out",
"ctrl-0": "core:zoom-reset",
"ctrl-enter": "core:confirm-edit-tray",
"ctrl-escape": "core:cancel-edit-tray",
"ctrl-d": "core:deploy-flows", "ctrl-d": "core:deploy-flows",
"ctrl-g c": "core:show-config-tab",
"ctrl-g d": "core:show-debug-tab",
"ctrl-g h": "core:show-help-tab",
"ctrl-g i": "core:show-info-tab", "ctrl-g i": "core:show-info-tab",
"ctrl-g v": "core:show-version-control-tab", "ctrl-g h": "core:show-help-tab",
"ctrl-g d": "core:show-debug-tab",
"ctrl-g c": "core:show-config-tab",
"ctrl-g x": "core:show-context-tab", "ctrl-g x": "core:show-context-tab",
"ctrl-e": "core:show-export-dialog", "ctrl-e": "core:show-export-dialog",
"ctrl-i": "core:show-import-dialog", "ctrl-i": "core:show-import-dialog",
@ -19,6 +23,7 @@
"ctrl-alt-r": "core:show-remote-diff", "ctrl-alt-r": "core:show-remote-diff",
"ctrl-alt-n": "core:new-project", "ctrl-alt-n": "core:new-project",
"ctrl-alt-o": "core:open-project", "ctrl-alt-o": "core:open-project",
"ctrl-g v": "core:show-version-control-tab",
"ctrl-shift-l": "core:show-event-log", "ctrl-shift-l": "core:show-event-log",
"ctrl-shift-p":"core:show-action-list" "ctrl-shift-p":"core:show-action-list"
}, },
@ -31,21 +36,14 @@
}, },
"red-ui-workspace": { "red-ui-workspace": {
"backspace": "core:delete-selection", "backspace": "core:delete-selection",
"ctrl-backspace": "core:delete-selection-and-reconnect",
"delete": "core:delete-selection", "delete": "core:delete-selection",
"ctrl-delete": "core:delete-selection-and-reconnect",
"enter": "core:edit-selected-node", "enter": "core:edit-selected-node",
"ctrl-enter": "core:go-to-selection",
"ctrl-c": "core:copy-selection-to-internal-clipboard", "ctrl-c": "core:copy-selection-to-internal-clipboard",
"ctrl-x": "core:cut-selection-to-internal-clipboard", "ctrl-x": "core:cut-selection-to-internal-clipboard",
"ctrl-v": "core:paste-from-internal-clipboard", "ctrl-v": "core:paste-from-internal-clipboard",
"ctrl-z": "core:undo", "ctrl-z": "core:undo",
"ctrl-y": "core:redo", "ctrl-y": "core:redo",
"ctrl-a": "core:select-all-nodes", "ctrl-a": "core:select-all-nodes",
"escape": "core:select-none",
"alt-s u": "core:select-upstream-nodes",
"alt-s d": "core:select-downstream-nodes",
"alt-s c": "core:select-connected-nodes",
"shift-?": "core:show-help", "shift-?": "core:show-help",
"w": "core:scroll-view-up", "w": "core:scroll-view-up",
"d": "core:scroll-view-right", "d": "core:scroll-view-right",
@ -55,47 +53,19 @@
"shift-d": "core:step-view-right", "shift-d": "core:step-view-right",
"shift-s": "core:step-view-down", "shift-s": "core:step-view-down",
"shift-a": "core:step-view-left", "shift-a": "core:step-view-left",
"ctrl-up": "core:move-selection-up", "up": "core:move-selection-up",
"ctrl-right": "core:move-selection-right", "right": "core:move-selection-right",
"ctrl-down": "core:move-selection-down", "down": "core:move-selection-down",
"ctrl-left": "core:move-selection-left", "left": "core:move-selection-left",
"shift-up": "core:step-selection-up", "shift-up": "core:step-selection-up",
"shift-right": "core:step-selection-right", "shift-right": "core:step-selection-right",
"shift-down": "core:step-selection-down", "shift-down": "core:step-selection-down",
"shift-left": "core:step-selection-left", "shift-left": "core:step-selection-left",
"ctrl-[": "core:show-previous-tab", "ctrl-shift-j": "core:show-previous-tab",
"ctrl-]": "core:show-next-tab", "ctrl-shift-k": "core:show-next-tab",
"ctrl-shift-left": "core:go-to-previous-location",
"ctrl-shift-right": "core:go-to-next-location",
"ctrl-shift-g": "core:group-selection", "ctrl-shift-g": "core:group-selection",
"ctrl-shift-u": "core:ungroup-selection", "ctrl-shift-u": "core:ungroup-selection",
"ctrl-shift-c": "core:copy-group-style", "ctrl-shift-c": "core:copy-group-style",
"ctrl-shift-v": "core:paste-group-style", "ctrl-shift-v": "core:paste-group-style"
"right": "core:go-to-nearest-node-on-right",
"left": "core:go-to-nearest-node-on-left",
"up": "core:go-to-nearest-node-above",
"down": "core:go-to-nearest-node-below",
"alt-a g": "core:align-selection-to-grid",
"alt-a l": "core:align-selection-to-left",
"alt-a r": "core:align-selection-to-right",
"alt-a t": "core:align-selection-to-top",
"alt-a b": "core:align-selection-to-bottom",
"alt-a m": "core:align-selection-to-middle",
"alt-a c": "core:align-selection-to-center",
"alt-a h": "core:distribute-selection-horizontally",
"alt-a v": "core:distribute-selection-vertically",
"shift-f": "core:search-previous",
"f": "core:search-next",
"alt-l l": "core:split-wire-with-link-nodes",
"alt-w": "core:hide-flow",
"alt-shift-w": "core:show-last-hidden-flow",
"ctrl-+": "core:zoom-in",
"ctrl--": "core:zoom-out",
"ctrl-0": "core:zoom-reset"
},
"red-ui-editor-stack": {
"ctrl-enter": "core:confirm-edit-tray",
"ctrl-escape": "core:cancel-edit-tray"
} }
} }

View File

@ -1,560 +0,0 @@
RED.multiplayer = (function () {
// activeSessionId - used to identify sessions across websocket reconnects
let activeSessionId
let headerWidget
// Map of session id to { session:'', user:{}, location:{}}
let sessions = {}
// Map of username to { user:{}, sessions:[] }
let users = {}
function addUserSession (session) {
if (sessions[session.session]) {
// This is an existing connection that has been authenticated
const existingSession = sessions[session.session]
if (existingSession.user.username !== session.user.username) {
removeUserHeaderButton(users[existingSession.user.username])
}
}
sessions[session.session] = session
const user = users[session.user.username] = users[session.user.username] || {
user: session.user,
sessions: []
}
if (session.user.profileColor === undefined) {
session.user.profileColor = (1 + Math.floor(Math.random() * 5))
}
session.location = session.location || {}
user.sessions.push(session)
if (session.session === activeSessionId) {
// This is the current user session - do not add a extra button for them
} else {
if (user.sessions.length === 1) {
if (user.button) {
clearTimeout(user.inactiveTimeout)
clearTimeout(user.removeTimeout)
user.button.removeClass('inactive')
} else {
addUserHeaderButton(user)
}
}
sessions[session.session].location = session.location
updateUserLocation(session.session)
}
}
function removeUserSession (sessionId, isDisconnected) {
removeUserLocation(sessionId)
const session = sessions[sessionId]
delete sessions[sessionId]
const user = users[session.user.username]
const i = user.sessions.indexOf(session)
user.sessions.splice(i, 1)
if (isDisconnected) {
removeUserHeaderButton(user)
} else {
if (user.sessions.length === 0) {
// Give the user 5s to reconnect before marking inactive
user.inactiveTimeout = setTimeout(() => {
user.button.addClass('inactive')
// Give the user further 20 seconds to reconnect before removing them
// from the user toolbar entirely
user.removeTimeout = setTimeout(() => {
removeUserHeaderButton(user)
}, 20000)
}, 5000)
}
}
}
function addUserHeaderButton (user) {
user.button = $('<li class="red-ui-multiplayer-user"><button type="button" class="red-ui-multiplayer-user-icon"></button></li>')
.attr('data-username', user.user.username)
.prependTo("#red-ui-multiplayer-user-list");
var button = user.button.find("button")
RED.popover.tooltip(button, user.user.username)
button.on('click', function () {
const location = user.sessions[0].location
revealUser(location)
})
const userProfile = RED.user.generateUserIcon(user.user)
userProfile.appendTo(button)
}
function removeUserHeaderButton (user) {
user.button.remove()
delete user.button
}
function getLocation () {
const location = {
workspace: RED.workspaces.active()
}
const editStack = RED.editor.getEditStack()
for (let i = editStack.length - 1; i >= 0; i--) {
if (editStack[i].id) {
location.node = editStack[i].id
break
}
}
if (isInWorkspace) {
const chart = $('#red-ui-workspace-chart')
const chartOffset = chart.offset()
const scaleFactor = RED.view.scale()
location.cursor = {
x: (lastPosition[0] - chartOffset.left + chart.scrollLeft()) / scaleFactor,
y: (lastPosition[1] - chartOffset.top + chart.scrollTop()) / scaleFactor
}
}
return location
}
let publishLocationTimeout
let lastPosition = [0,0]
let isInWorkspace = false
function publishLocation () {
if (!publishLocationTimeout) {
publishLocationTimeout = setTimeout(() => {
const location = getLocation()
if (location.workspace !== 0) {
log('send', 'multiplayer/location', location)
RED.comms.send('multiplayer/location', location)
}
publishLocationTimeout = null
}, 100)
}
}
function revealUser(location, skipWorkspace) {
if (location.node) {
// Need to check if this is a known node, so we can fall back to revealing
// the workspace instead
const node = RED.nodes.node(location.node)
if (node) {
RED.view.reveal(location.node)
} else if (!skipWorkspace && location.workspace) {
RED.view.reveal(location.workspace)
}
} else if (!skipWorkspace && location.workspace) {
RED.view.reveal(location.workspace)
}
}
const workspaceTrays = {}
function getWorkspaceTray(workspaceId) {
// console.log('get tray for',workspaceId)
if (!workspaceTrays[workspaceId]) {
const tray = $('<div class="red-ui-multiplayer-users-tray"></div>')
const users = []
const userIcons = {}
const userCountIcon = $(`<div class="red-ui-multiplayer-user-location"><span class="red-ui-user-profile red-ui-multiplayer-user-count"><span></span></span></div>`)
const userCountSpan = userCountIcon.find('span span')
userCountIcon.hide()
userCountSpan.text('')
userCountIcon.appendTo(tray)
const userCountTooltip = RED.popover.tooltip(userCountIcon, function () {
const content = $('<div>')
users.forEach(sessionId => {
$('<div>').append($('<a href="#">').text(sessions[sessionId].user.username).on('click', function (evt) {
evt.preventDefault()
revealUser(sessions[sessionId].location, true)
userCountTooltip.close()
})).appendTo(content)
})
return content
},
null,
true
)
const updateUserCount = function () {
const maxShown = 2
const children = tray.children()
children.each(function (index, element) {
const i = users.length - index
if (i > maxShown) {
$(this).hide()
} else if (i >= 0) {
$(this).show()
}
})
if (users.length < maxShown + 1) {
userCountIcon.hide()
} else {
userCountSpan.text('+'+(users.length - maxShown))
userCountIcon.show()
}
}
workspaceTrays[workspaceId] = {
attached: false,
tray,
users,
userIcons,
addUser: function (sessionId) {
if (users.indexOf(sessionId) === -1) {
// console.log(`addUser ws:${workspaceId} session:${sessionId}`)
users.push(sessionId)
const userLocationId = `red-ui-multiplayer-user-location-${sessionId}`
const userLocationIcon = $(`<div class="red-ui-multiplayer-user-location" id="${userLocationId}"></div>`)
RED.user.generateUserIcon(sessions[sessionId].user).appendTo(userLocationIcon)
userLocationIcon.prependTo(tray)
RED.popover.tooltip(userLocationIcon, sessions[sessionId].user.username)
userIcons[sessionId] = userLocationIcon
updateUserCount()
}
},
removeUser: function (sessionId) {
// console.log(`removeUser ws:${workspaceId} session:${sessionId}`)
const userLocationId = `red-ui-multiplayer-user-location-${sessionId}`
const index = users.indexOf(sessionId)
if (index > -1) {
users.splice(index, 1)
userIcons[sessionId].remove()
delete userIcons[sessionId]
}
updateUserCount()
},
updateUserCount
}
}
const trayDef = workspaceTrays[workspaceId]
if (!trayDef.attached) {
const workspaceTab = $(`#red-ui-tab-${workspaceId}`)
if (workspaceTab.length > 0) {
trayDef.attached = true
trayDef.tray.appendTo(workspaceTab)
trayDef.users.forEach(sessionId => {
trayDef.userIcons[sessionId].on('click', function (evt) {
revealUser(sessions[sessionId].location, true)
})
})
}
}
return workspaceTrays[workspaceId]
}
function attachWorkspaceTrays () {
let viewTouched = false
for (let sessionId of Object.keys(sessions)) {
const location = sessions[sessionId].location
if (location) {
if (location.workspace) {
getWorkspaceTray(location.workspace).updateUserCount()
}
if (location.node) {
addUserToNode(sessionId, location.node)
viewTouched = true
}
}
}
if (viewTouched) {
RED.view.redraw()
}
}
function addUserToNode(sessionId, nodeId) {
const node = RED.nodes.node(nodeId)
if (node) {
if (!node._multiplayer) {
node._multiplayer = {
users: [sessionId]
}
node._multiplayer_refresh = true
} else {
if (node._multiplayer.users.indexOf(sessionId) === -1) {
node._multiplayer.users.push(sessionId)
node._multiplayer_refresh = true
}
}
}
}
function removeUserFromNode(sessionId, nodeId) {
const node = RED.nodes.node(nodeId)
if (node && node._multiplayer) {
const i = node._multiplayer.users.indexOf(sessionId)
if (i > -1) {
node._multiplayer.users.splice(i, 1)
}
if (node._multiplayer.users.length === 0) {
delete node._multiplayer
} else {
node._multiplayer_refresh = true
}
}
}
function removeUserLocation (sessionId) {
updateUserLocation(sessionId, {})
removeUserCursor(sessionId)
}
function removeUserCursor (sessionId) {
// return
if (sessions[sessionId]?.cursor) {
sessions[sessionId].cursor.parentNode.removeChild(sessions[sessionId].cursor)
delete sessions[sessionId].cursor
}
}
function updateUserLocation (sessionId, location) {
let viewTouched = false
const oldLocation = sessions[sessionId].location
if (location) {
if (oldLocation.workspace !== location.workspace) {
// console.log('removing', sessionId, oldLocation.workspace)
workspaceTrays[oldLocation.workspace]?.removeUser(sessionId)
}
if (oldLocation.node !== location.node) {
removeUserFromNode(sessionId, oldLocation.node)
viewTouched = true
}
sessions[sessionId].location = location
} else {
location = sessions[sessionId].location
}
// console.log(`updateUserLocation sessionId:${sessionId} oldWS:${oldLocation?.workspace} newWS:${location.workspace}`)
if (location.workspace) {
getWorkspaceTray(location.workspace).addUser(sessionId)
if (location.cursor && location.workspace === RED.workspaces.active()) {
if (!sessions[sessionId].cursor) {
const user = sessions[sessionId].user
const cursorIcon = document.createElementNS("http://www.w3.org/2000/svg","g");
cursorIcon.setAttribute("class", "red-ui-multiplayer-annotation")
cursorIcon.appendChild(createAnnotationUser(user, true))
$(cursorIcon).css({
transform: `translate( ${location.cursor.x}px, ${location.cursor.y}px)`,
transition: 'transform 0.1s linear'
})
$("#red-ui-workspace-chart svg").append(cursorIcon)
sessions[sessionId].cursor = cursorIcon
} else {
const cursorIcon = sessions[sessionId].cursor
$(cursorIcon).css({
transform: `translate( ${location.cursor.x}px, ${location.cursor.y}px)`
})
}
} else if (sessions[sessionId].cursor) {
removeUserCursor(sessionId)
}
}
if (location.node) {
addUserToNode(sessionId, location.node)
viewTouched = true
}
if (viewTouched) {
RED.view.redraw()
}
}
// function refreshUserLocations () {
// for (const session of Object.keys(sessions)) {
// if (session !== activeSessionId) {
// updateUserLocation(session)
// }
// }
// }
function createAnnotationUser(user, pointer = false) {
const radius = 20
const halfRadius = radius/2
const group = document.createElementNS("http://www.w3.org/2000/svg","g");
const badge = document.createElementNS("http://www.w3.org/2000/svg","path");
let shapePath
if (!pointer) {
shapePath = `M 0 ${halfRadius} a ${halfRadius} ${halfRadius} 0 1 1 ${radius} 0 a ${halfRadius} ${halfRadius} 0 1 1 -${radius} 0 z`
} else {
shapePath = `M 0 0 h ${halfRadius} a ${halfRadius} ${halfRadius} 0 1 1 -${halfRadius} ${halfRadius} z`
}
badge.setAttribute('d', shapePath)
badge.setAttribute("class", "red-ui-multiplayer-annotation-background")
group.appendChild(badge)
if (user && user.profileColor !== undefined) {
badge.setAttribute("class", "red-ui-multiplayer-annotation-background red-ui-user-profile-color-" + user.profileColor)
}
if (user && user.image) {
const image = document.createElementNS("http://www.w3.org/2000/svg","image");
image.setAttribute("width", radius)
image.setAttribute("height", radius)
image.setAttribute("href", user.image)
image.setAttribute("clip-path", "circle("+Math.floor(radius/2)+")")
group.appendChild(image)
} else if (user && user.anonymous) {
const anonIconHead = document.createElementNS("http://www.w3.org/2000/svg","circle");
anonIconHead.setAttribute("cx", radius/2)
anonIconHead.setAttribute("cy", radius/2 - 2)
anonIconHead.setAttribute("r", 2.4)
anonIconHead.setAttribute("class","red-ui-multiplayer-annotation-anon-label");
group.appendChild(anonIconHead)
const anonIconBody = document.createElementNS("http://www.w3.org/2000/svg","path");
anonIconBody.setAttribute("class","red-ui-multiplayer-annotation-anon-label");
// anonIconBody.setAttribute("d",`M ${radius/2 - 4} ${radius/2 + 1} h 8 v4 h -8 z`);
anonIconBody.setAttribute("d",`M ${radius/2} ${radius/2 + 5} h -2.5 c -2 1 -2 -5 0.5 -4.5 c 2 1 2 1 4 0 c 2.5 -0.5 2.5 5.5 0 4.5 z`);
group.appendChild(anonIconBody)
} else {
const label = document.createElementNS("http://www.w3.org/2000/svg","text");
if (user.username || user.email) {
label.setAttribute("class","red-ui-multiplayer-annotation-label");
label.textContent = (user.username || user.email).substring(0,2)
} else {
label.setAttribute("class","red-ui-multiplayer-annotation-label red-ui-multiplayer-user-count")
label.textContent = 'nr'
}
label.setAttribute("text-anchor", "middle")
label.setAttribute("x",radius/2);
label.setAttribute("y",radius/2 + 3);
group.appendChild(label)
}
const border = document.createElementNS("http://www.w3.org/2000/svg","path");
border.setAttribute('d', shapePath)
border.setAttribute("class", "red-ui-multiplayer-annotation-border")
group.appendChild(border)
return group
}
return {
init: function () {
RED.view.annotations.register("red-ui-multiplayer",{
type: 'badge',
align: 'left',
class: "red-ui-multiplayer-annotation",
show: "_multiplayer",
refresh: "_multiplayer_refresh",
element: function(node) {
const containerGroup = document.createElementNS("http://www.w3.org/2000/svg","g");
containerGroup.setAttribute("transform","translate(0,-4)")
if (node._multiplayer) {
let y = 0
for (let i = Math.min(1, node._multiplayer.users.length - 1); i >= 0; i--) {
const user = sessions[node._multiplayer.users[i]].user
const group = createAnnotationUser(user)
group.setAttribute("transform","translate("+y+",0)")
y += 15
containerGroup.appendChild(group)
}
if (node._multiplayer.users.length > 2) {
const group = createAnnotationUser('+'+(node._multiplayer.users.length - 2))
group.setAttribute("transform","translate("+y+",0)")
y += 12
containerGroup.appendChild(group)
}
}
return containerGroup;
},
tooltip: node => { return node._multiplayer.users.map(u => sessions[u].user.username).join('\n') }
});
// activeSessionId = RED.settings.getLocal('multiplayer:sessionId')
// if (!activeSessionId) {
activeSessionId = RED.nodes.id()
// RED.settings.setLocal('multiplayer:sessionId', activeSessionId)
// log('Session ID (new)', activeSessionId)
// } else {
log('Session ID', activeSessionId)
// }
headerWidget = $('<li><ul id="red-ui-multiplayer-user-list"></ul></li>').prependTo('.red-ui-header-toolbar')
RED.comms.on('connect', () => {
const location = getLocation()
const connectInfo = {
session: activeSessionId
}
if (location.workspace !== 0) {
connectInfo.location = location
}
RED.comms.send('multiplayer/connect', connectInfo)
})
RED.comms.subscribe('multiplayer/#', (topic, msg) => {
log('recv', topic, msg)
if (topic === 'multiplayer/init') {
// We have just reconnected, runtime has sent state to
// initialise the world
sessions = {}
users = {}
$('#red-ui-multiplayer-user-list').empty()
msg.sessions.forEach(session => {
addUserSession(session)
})
} else if (topic === 'multiplayer/connection-added') {
addUserSession(msg)
} else if (topic === 'multiplayer/connection-removed') {
removeUserSession(msg.session, msg.disconnected)
} else if (topic === 'multiplayer/location') {
const session = msg.session
delete msg.session
updateUserLocation(session, msg)
}
})
RED.events.on('workspace:change', (event) => {
getWorkspaceTray(event.workspace)
publishLocation()
})
RED.events.on('editor:open', () => {
publishLocation()
})
RED.events.on('editor:close', () => {
publishLocation()
})
RED.events.on('editor:change', () => {
publishLocation()
})
RED.events.on('login', () => {
publishLocation()
})
RED.events.on('flows:loaded', () => {
attachWorkspaceTrays()
})
RED.events.on('workspace:close', (event) => {
// A subflow tab has been closed. Need to mark its tray as detached
if (workspaceTrays[event.workspace]) {
workspaceTrays[event.workspace].attached = false
}
})
RED.events.on('logout', () => {
const disconnectInfo = {
session: activeSessionId
}
RED.comms.send('multiplayer/disconnect', disconnectInfo)
RED.settings.removeLocal('multiplayer:sessionId')
})
const chart = $('#red-ui-workspace-chart')
chart.on('mousemove', function (evt) {
lastPosition[0] = evt.clientX
lastPosition[1] = evt.clientY
publishLocation()
})
chart.on('scroll', function (evt) {
publishLocation()
})
chart.on('mouseenter', function () {
isInWorkspace = true
publishLocation()
})
chart.on('mouseleave', function () {
isInWorkspace = false
publishLocation()
})
}
}
function log() {
if (RED.multiplayer.DEBUG) {
console.log('[multiplayer]', ...arguments)
}
}
})();

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +0,0 @@
RED.plugins = (function() {
var plugins = {};
var pluginsByType = {};
var moduleList = {};
function registerPlugin(id,definition) {
plugins[id] = definition;
if (definition.type) {
pluginsByType[definition.type] = pluginsByType[definition.type] || [];
pluginsByType[definition.type].push(definition);
}
if (RED._loadingModule) {
definition.module = RED._loadingModule;
definition["_"] = function() {
var args = Array.prototype.slice.call(arguments);
var originalKey = args[0];
if (!/:/.test(args[0])) {
args[0] = definition.module+":"+args[0];
}
var result = RED._.apply(null,args);
if (result === args[0]) {
return originalKey;
}
return result;
}
} else {
definition["_"] = RED["_"]
}
if (definition.onadd && typeof definition.onadd === 'function') {
definition.onadd();
}
RED.events.emit("registry:plugin-added",id);
}
function getPlugin(id) {
return plugins[id]
}
function getPluginsByType(type) {
return pluginsByType[type] || [];
}
function setPluginList(list) {
for(let i=0;i<list.length;i++) {
let p = list[i];
addPlugin(p);
}
}
function addPlugin(p) {
moduleList[p.module] = moduleList[p.module] || {
name:p.module,
version:p.version,
local:p.local,
sets:{},
plugin: true,
id: p.id
};
if (p.pending_version) {
moduleList[p.module].pending_version = p.pending_version;
}
moduleList[p.module].sets[p.name] = p;
RED.events.emit("registry:plugin-module-added",p.module);
}
function getModule(module) {
return moduleList[module];
}
return {
registerPlugin: registerPlugin,
getPlugin: getPlugin,
getPluginsByType: getPluginsByType,
setPluginList: setPluginList,
addPlugin: addPlugin,
getModule: getModule
}
})();

View File

@ -52,5 +52,6 @@
Set.prototype = _Set.prototype; Set.prototype = _Set.prototype;
Set.prototype.constructor = Set; Set.prototype.constructor = Set;
} }
} }
})(); })();

View File

@ -15,66 +15,19 @@
**/ **/
var RED = (function() { var RED = (function() {
function appendNodeConfig(nodeConfig,done) {
function loadPluginList() {
loader.reportProgress(RED._("event.loadPlugins"), 10)
$.ajax({
headers: {
"Accept":"application/json"
},
cache: false,
url: 'plugins',
success: function(data) {
RED.plugins.setPluginList(data);
loader.reportProgress(RED._("event.loadPlugins"), 13)
RED.i18n.loadPluginCatalogs(function() {
loadPlugins(function() {
loadNodeList();
});
});
}
});
}
function loadPlugins(done) {
loader.reportProgress(RED._("event.loadPlugins",{count:""}), 17)
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'plugins',
success: function(data) {
var configs = data.trim().split(/(?=<!-- --- \[red-plugin:\S+\] --- -->)/);
var totalCount = configs.length;
var stepConfig = function() {
// loader.reportProgress(RED._("event.loadNodes",{count:(totalCount-configs.length)+"/"+totalCount}), 30 + ((totalCount-configs.length)/totalCount)*40 )
if (configs.length === 0) {
done();
} else {
var config = configs.shift();
appendPluginConfig(config,stepConfig);
}
}
stepConfig();
}
});
}
function appendConfig(config, moduleIdMatch, targetContainer, done) {
done = done || function(){}; done = done || function(){};
var m = /<!-- --- \[red-module:(\S+)\] --- -->/.exec(nodeConfig.trim());
var moduleId; var moduleId;
if (moduleIdMatch) { if (m) {
moduleId = moduleIdMatch[1]; moduleId = m[1];
RED._loadingModule = moduleId;
} else { } else {
moduleId = "unknown"; moduleId = "unknown";
} }
try { try {
var hasDeferred = false; var hasDeferred = false;
var nodeConfigEls = $("<div>"+config+"</div>");
var nodeConfigEls = $("<div>"+nodeConfig+"</div>");
var scripts = nodeConfigEls.find("script"); var scripts = nodeConfigEls.find("script");
var scriptCount = scripts.length; var scriptCount = scripts.length;
scripts.each(function(i,el) { scripts.each(function(i,el) {
@ -85,15 +38,14 @@ var RED = (function() {
newScript.onload = function() { newScript.onload = function() {
scriptCount--; scriptCount--;
if (scriptCount === 0) { if (scriptCount === 0) {
$(targetContainer).append(nodeConfigEls); $("#red-ui-editor-node-configs").append(nodeConfigEls);
delete RED._loadingModule;
done() done()
} }
} }
if ($(el).attr('type') === "module") { if ($(el).attr('type') === "module") {
newScript.type = "module"; newScript.type = "module";
} }
$(targetContainer).append(newScript); $("#red-ui-editor-node-configs").append(newScript);
newScript.src = RED.settings.apiRootUrl+srcUrl; newScript.src = RED.settings.apiRootUrl+srcUrl;
hasDeferred = true; hasDeferred = true;
} else { } else {
@ -109,8 +61,7 @@ var RED = (function() {
} }
}) })
if (!hasDeferred) { if (!hasDeferred) {
$(targetContainer).append(nodeConfigEls); $("#red-ui-editor-node-configs").append(nodeConfigEls);
delete RED._loadingModule;
done(); done();
} }
} catch(err) { } catch(err) {
@ -119,27 +70,9 @@ var RED = (function() {
timeout: 10000 timeout: 10000
}); });
console.log("["+moduleId+"] "+err.toString()); console.log("["+moduleId+"] "+err.toString());
delete RED._loadingModule;
done(); done();
} }
} }
function appendPluginConfig(pluginConfig,done) {
appendConfig(
pluginConfig,
/<!-- --- \[red-plugin:(\S+)\] --- -->/.exec(pluginConfig.trim()),
"#red-ui-editor-plugin-configs",
done
);
}
function appendNodeConfig(nodeConfig,done) {
appendConfig(
nodeConfig,
/<!-- --- \[red-module:(\S+)\] --- -->/.exec(nodeConfig.trim()),
"#red-ui-editor-node-configs",
done
);
}
function loadNodeList() { function loadNodeList() {
loader.reportProgress(RED._("event.loadPalette"), 20) loader.reportProgress(RED._("event.loadPalette"), 20)
@ -177,7 +110,7 @@ var RED = (function() {
function loadNodes() { function loadNodes() {
loader.reportProgress(RED._("event.loadNodes",{count:""}), 30) loader.reportProgress(RED._("event.loadNodes",{count:""}), 30)
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage(); var lang = localStorage.getItem("editor-language")||i18n.detectLanguage();
$.ajax({ $.ajax({
headers: { headers: {
@ -202,7 +135,6 @@ var RED = (function() {
RED.projects.refresh(function(activeProject) { RED.projects.refresh(function(activeProject) {
loadFlows(function() { loadFlows(function() {
RED.sidebar.info.refresh() RED.sidebar.info.refresh()
var showProjectWelcome = false;
if (!activeProject) { if (!activeProject) {
// Projects enabled but no active project // Projects enabled but no active project
RED.menu.setDisabled('menu-item-projects-open',true); RED.menu.setDisabled('menu-item-projects-open',true);
@ -210,10 +142,10 @@ var RED = (function() {
if (activeProject === false) { if (activeProject === false) {
// User previously decline the migration to projects. // User previously decline the migration to projects.
} else { // null/undefined } else { // null/undefined
showProjectWelcome = true; RED.projects.showStartup();
} }
} }
completeLoad(showProjectWelcome); completeLoad();
}); });
}); });
} else { } else {
@ -246,68 +178,11 @@ var RED = (function() {
var currentHash = window.location.hash; var currentHash = window.location.hash;
RED.nodes.version(nodes.rev); RED.nodes.version(nodes.rev);
loader.reportProgress(RED._("event.importFlows"),90 ) loader.reportProgress(RED._("event.importFlows"),90 )
try {
RED.nodes.import(nodes.flows); RED.nodes.import(nodes.flows);
RED.nodes.dirty(false); RED.nodes.dirty(false);
RED.view.redraw(true); RED.view.redraw(true);
if (/^#(flow|node|group)\/.+$/.test(currentHash)) { if (/^#flow\/.+$/.test(currentHash)) {
const hashParts = currentHash.split('/') RED.workspaces.show(currentHash.substring(6));
const showEditDialog = hashParts.length > 2 && hashParts[2] === 'edit'
if (hashParts[0] === '#flow') {
RED.workspaces.show(hashParts[1], true);
if (showEditDialog) {
RED.workspaces.edit()
}
} else if (hashParts[0] === '#node') {
const nodeToShow = RED.nodes.node(hashParts[1])
if (nodeToShow) {
setTimeout(() => {
RED.view.reveal(nodeToShow.id)
window.location.hash = currentHash
RED.view.select(nodeToShow.id)
if (showEditDialog) {
RED.editor.edit(nodeToShow)
}
}, 50)
}
} else if (hashParts[0] === '#group') {
const nodeToShow = RED.nodes.group(hashParts[1])
if (nodeToShow) {
RED.view.reveal(nodeToShow.id)
window.location.hash = currentHash
RED.view.select(nodeToShow.id)
if (showEditDialog) {
RED.editor.editGroup(nodeToShow)
}
}
}
}
if (RED.workspaces.count() > 0) {
const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
const workspaces = RED.nodes.getWorkspaceOrder();
if (RED.workspaces.active() === 0) {
for (let index = 0; index < workspaces.length; index++) {
const ws = workspaces[index];
if (!hiddenTabs[ws]) {
RED.workspaces.show(ws);
break;
}
}
}
if (RED.workspaces.active() === 0) {
RED.workspaces.show(workspaces[0]);
}
}
RED.events.emit('flows:loaded')
} catch(err) {
console.warn(err);
RED.notify(
RED._("event.importError", {message: err.message}),
{
fixed: true,
type: 'error'
}
);
} }
} }
done(); done();
@ -315,7 +190,7 @@ var RED = (function() {
}); });
} }
function completeLoad(showProjectWelcome) { function completeLoad() {
var persistentNotifications = {}; var persistentNotifications = {};
RED.comms.subscribe("notification/#",function(topic,msg) { RED.comms.subscribe("notification/#",function(topic,msg) {
var parts = topic.split("/"); var parts = topic.split("/");
@ -328,12 +203,8 @@ var RED = (function() {
// handled below // handled below
return; return;
} }
if (notificationId === "flows-run-state") {
// handled in editor-client/src/js/runtime.js
return;
}
if (notificationId === "project-update") { if (notificationId === "project-update") {
loader.start(RED._("event.loadingProject"), 0); loader.start("Loading project",0)
RED.nodes.clear(); RED.nodes.clear();
RED.history.clear(); RED.history.clear();
RED.view.redraw(true); RED.view.redraw(true);
@ -350,10 +221,8 @@ var RED = (function() {
"merge-complete": RED._("notification.project.merge-complete") "merge-complete": RED._("notification.project.merge-complete")
}[msg.action]; }[msg.action];
loader.end() loader.end()
RED.notify($("<p>").text(message)); RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh() RED.sidebar.info.refresh()
RED.menu.setDisabled('menu-item-projects-open',false);
RED.menu.setDisabled('menu-item-projects-settings',false);
}); });
}); });
return; return;
@ -390,18 +259,10 @@ var RED = (function() {
} }
} }
] ]
// } else if (RED.settings.get('externalModules.palette.allowInstall', true) !== false) { // } else if (RED.settings.theme('palette.editable') !== false) {
} else { } else {
options.buttons = [ options.buttons = [
{ {
text: RED._("notification.label.unknownNodesButton"),
class: "pull-left",
click: function() {
RED.actions.invoke("core:search", "type:unknown ");
}
},
{
class: "primary",
text: RED._("common.label.close"), text: RED._("common.label.close"),
click: function() { click: function() {
persistentNotifications[notificationId].hideNotification(); persistentNotifications[notificationId].hideNotification();
@ -409,16 +270,6 @@ var RED = (function() {
} }
] ]
} }
} else if (msg.error === "missing-modules") {
text+="<ul><li>"+msg.modules.map(function(m) { return RED.utils.sanitize(m.module)+(m.error?(" - <small>"+RED.utils.sanitize(""+m.error)+"</small>"):"")}).join("</li><li>")+"</li></ul>";
options.buttons = [
{
text: RED._("common.label.close"),
click: function() {
persistentNotifications[notificationId].hideNotification();
}
}
]
} else if (msg.error === "credentials_load_failed") { } else if (msg.error === "credentials_load_failed") {
if (RED.settings.theme("projects.enabled",false)) { if (RED.settings.theme("projects.enabled",false)) {
// projects enabled // projects enabled
@ -500,15 +351,6 @@ var RED = (function() {
] ]
} }
} }
} else if (notificationId === 'restart-required') {
options.buttons = [
{
text: RED._("common.label.close"),
click: function() {
persistentNotifications[notificationId].hideNotification();
}
}
]
} }
if (!persistentNotifications.hasOwnProperty(notificationId)) { if (!persistentNotifications.hasOwnProperty(notificationId)) {
persistentNotifications[notificationId] = RED.notify(text,options); persistentNotifications[notificationId] = RED.notify(text,options);
@ -519,15 +361,12 @@ var RED = (function() {
persistentNotifications[notificationId].close(); persistentNotifications[notificationId].close();
delete persistentNotifications[notificationId]; delete persistentNotifications[notificationId];
} }
if (notificationId === 'runtime-state') {
RED.events.emit("runtime-state",msg);
}
}); });
RED.comms.subscribe("status/#",function(topic,msg) { RED.comms.subscribe("status/#",function(topic,msg) {
var parts = topic.split("/"); var parts = topic.split("/");
var node = RED.nodes.node(parts[1]); var node = RED.nodes.node(parts[1]);
if (node) { if (node) {
if (msg.hasOwnProperty("text") && msg.text !== null && /^[@a-zA-Z]/.test(msg.text)) { if (msg.hasOwnProperty("text") && msg.text !== null && /^[a-zA-Z]/.test(msg.text)) {
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()}); msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
} }
node.status = msg; node.status = msg;
@ -536,124 +375,56 @@ var RED = (function() {
RED.view.redrawStatus(node); RED.view.redrawStatus(node);
} }
}); });
RED.comms.subscribe("notification/plugin/#",function(topic,msg) {
if (topic == "notification/plugin/added") {
RED.settings.refreshSettings(function(err, data) {
let addedPlugins = [];
msg.forEach(function(m) {
let id = m.id;
RED.plugins.addPlugin(m);
m.plugins.forEach((p) => {
addedPlugins.push(p.id);
})
RED.i18n.loadNodeCatalog(id, function() {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'plugins/'+id,
success: function(data) {
appendPluginConfig(data);
}
});
});
});
if (addedPlugins.length) {
let pluginList = "<ul><li>"+addedPlugins.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
// ToDo: Adapt notification (node -> plugin)
RED.notify(RED._("palette.event.nodeAdded", {count:addedPlugins.length})+pluginList,"success");
}
})
}
});
let pendingNodeRemovedNotifications = []
let pendingNodeRemovedTimeout
RED.comms.subscribe("notification/node/#",function(topic,msg) { RED.comms.subscribe("notification/node/#",function(topic,msg) {
var i,m; var i,m;
var typeList; var typeList;
var info; var info;
if (topic == "notification/node/added") { if (topic == "notification/node/added") {
RED.settings.refreshSettings(function(err, data) {
var addedTypes = []; var addedTypes = [];
msg.forEach(function(m) { msg.forEach(function(m) {
var id = m.id; var id = m.id;
RED.nodes.addNodeSet(m); RED.nodes.addNodeSet(m);
addedTypes = addedTypes.concat(m.types); addedTypes = addedTypes.concat(m.types);
RED.i18n.loadNodeCatalog(id, function() { RED.i18n.loadNodeCatalog(id, function() {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage(); $.get('nodes/'+id, function(data) {
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'nodes/'+id,
success: function(data) {
appendNodeConfig(data); appendNodeConfig(data);
}
}); });
}); });
}); });
if (addedTypes.length) { if (addedTypes.length) {
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>"; typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success"); RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
} }
loadIconList(); loadIconList();
})
} else if (topic == "notification/node/removed") { } else if (topic == "notification/node/removed") {
for (i=0;i<msg.length;i++) { for (i=0;i<msg.length;i++) {
m = msg[i]; m = msg[i];
info = RED.nodes.removeNodeSet(m.id); info = RED.nodes.removeNodeSet(m.id);
if (info.added) { if (info.added) {
pendingNodeRemovedNotifications = pendingNodeRemovedNotifications.concat(m.types.map(RED.utils.sanitize)) typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
if (pendingNodeRemovedTimeout) { RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success");
clearTimeout(pendingNodeRemovedTimeout)
}
pendingNodeRemovedTimeout = setTimeout(function () {
typeList = "<ul><li>"+pendingNodeRemovedNotifications.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeRemoved", {count:pendingNodeRemovedNotifications.length})+typeList,"success");
pendingNodeRemovedNotifications = []
}, 200)
} }
} }
loadIconList(); loadIconList();
} else if (topic == "notification/node/enabled") { } else if (topic == "notification/node/enabled") {
if (msg.types) { if (msg.types) {
RED.settings.refreshSettings(function(err, data) {
info = RED.nodes.getNodeSet(msg.id); info = RED.nodes.getNodeSet(msg.id);
if (info.added) { if (info.added) {
RED.nodes.enableNodeSet(msg.id); RED.nodes.enableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>"; typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success"); RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else { } else {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage(); $.get('nodes/'+msg.id, function(data) {
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'nodes/'+msg.id,
success: function(data) {
appendNodeConfig(data); appendNodeConfig(data);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>"; typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success"); RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
}
}); });
} }
});
} }
} else if (topic == "notification/node/disabled") { } else if (topic == "notification/node/disabled") {
if (msg.types) { if (msg.types) {
RED.nodes.disableNodeSet(msg.id); RED.nodes.disableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>"; typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success"); RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success");
} }
} else if (topic == "notification/node/upgraded") { } else if (topic == "notification/node/upgraded") {
@ -668,28 +439,19 @@ var RED = (function() {
$(".red-ui-header-toolbar").show(); $(".red-ui-header-toolbar").show();
RED.sidebar.show(":first", true);
setTimeout(function() { setTimeout(function() {
loader.end(); loader.end();
checkFirstRun(function() {
if (showProjectWelcome) {
RED.projects.showStartup();
}
});
},100); },100);
} }
function checkFirstRun(done) { function showAbout() {
if (RED.settings.theme("tours") === false) { $.get('red/about', function(data) {
done(); var aboutHeader = '<div style="text-align:center;">'+
return; '<img width="50px" src="red/images/node-red-icon.svg" />'+
} '</div>';
if (!RED.settings.get("editor.view.view-show-welcome-tours", true)) {
done(); RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data));
return; });
}
RED.actions.invoke("core:show-welcome-tour", RED.settings.get("editor.tours.welcome"), done);
} }
function buildMainMenu() { function buildMainMenu() {
@ -701,25 +463,6 @@ var RED = (function() {
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"} {id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
]}); ]});
} }
menuOptions.push({id:"menu-item-edit-menu", label:RED._("menu.label.edit"), options: [
{id: "menu-item-edit-undo", label:RED._("keyboard.undoChange"), disabled: true, onselect: "core:undo"},
{id: "menu-item-edit-redo", label:RED._("keyboard.redoChange"), disabled: true, onselect: "core:redo"},
null,
{id: "menu-item-edit-cut", label:RED._("keyboard.cutNode"), onselect: "core:cut-selection-to-internal-clipboard"},
{id: "menu-item-edit-copy", label:RED._("keyboard.copyNode"), onselect: "core:copy-selection-to-internal-clipboard"},
{id: "menu-item-edit-paste", label:RED._("keyboard.pasteNode"), disabled: true, onselect: "core:paste-from-internal-clipboard"},
null,
{id: "menu-item-edit-copy-group-style", label:RED._("keyboard.copyGroupStyle"), onselect: "core:copy-group-style"},
{id: "menu-item-edit-paste-group-style", label:RED._("keyboard.pasteGroupStyle"), disabled: true, onselect: "core:paste-group-style"},
null,
{id: "menu-item-edit-select-all", label:RED._("keyboard.selectAll"), onselect: "core:select-all-nodes"},
{id: "menu-item-edit-select-connected", label:RED._("keyboard.selectAllConnected"), onselect: "core:select-connected-nodes"},
{id: "menu-item-edit-select-none", label:RED._("keyboard.selectNone"), onselect: "core:select-none"},
null,
{id: "menu-item-edit-split-wire-with-links", label:RED._("keyboard.splitWireWithLinks"), onselect: "core:split-wire-with-link-nodes"},
]});
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[ menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
{id:"menu-item-palette",label:RED._("menu.label.palette.show"),toggle:true,onselect:"core:toggle-palette", selected: true}, {id:"menu-item-palette",label:RED._("menu.label.palette.show"),toggle:true,onselect:"core:toggle-palette", selected: true},
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true}, {id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true},
@ -727,25 +470,6 @@ var RED = (function() {
{id:"menu-item-action-list",label:RED._("keyboard.actionList"),onselect:"core:show-action-list"}, {id:"menu-item-action-list",label:RED._("keyboard.actionList"),onselect:"core:show-action-list"},
null null
]}); ]});
menuOptions.push({id:"menu-item-arrange-menu", label:RED._("menu.label.arrange"), options: [
{id: "menu-item-view-tools-align-left", label:RED._("menu.label.alignLeft"), disabled: true, onselect: "core:align-selection-to-left"},
{id: "menu-item-view-tools-align-center", label:RED._("menu.label.alignCenter"), disabled: true, onselect: "core:align-selection-to-center"},
{id: "menu-item-view-tools-align-right", label:RED._("menu.label.alignRight"), disabled: true, onselect: "core:align-selection-to-right"},
null,
{id: "menu-item-view-tools-align-top", label:RED._("menu.label.alignTop"), disabled: true, onselect: "core:align-selection-to-top"},
{id: "menu-item-view-tools-align-middle", label:RED._("menu.label.alignMiddle"), disabled: true, onselect: "core:align-selection-to-middle"},
{id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"},
null,
{id: "menu-item-view-tools-distribute-horizontally", label:RED._("menu.label.distributeHorizontally"), disabled: true, onselect: "core:distribute-selection-horizontally"},
{id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"},
null,
{id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"},
{id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"},
{id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"},
{id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"}
]});
menuOptions.push(null); menuOptions.push(null);
if (RED.settings.theme("menu.menu-item-import-library", true)) { if (RED.settings.theme("menu.menu-item-import-library", true)) {
menuOptions.push({id: "menu-item-import", label: RED._("menu.label.import"), onselect: "core:show-import-dialog"}); menuOptions.push({id: "menu-item-import", label: RED._("menu.label.import"), onselect: "core:show-import-dialog"});
@ -759,7 +483,7 @@ var RED = (function() {
menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:"core:show-config-tab"}); menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:"core:show-config-tab"});
menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[ menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:"core:add-flow"}, {id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:"core:add-flow"},
{id:"menu-item-workspace-edit",label:RED._("menu.label.edit"),onselect:"core:edit-flow"}, {id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:"core:edit-flow"},
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:"core:remove-flow"} {id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:"core:remove-flow"}
]}); ]});
menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [ menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
@ -775,7 +499,7 @@ var RED = (function() {
]}); ]});
menuOptions.push(null); menuOptions.push(null);
if (RED.settings.get('externalModules.palette.allowInstall', true) !== false) { if (RED.settings.theme('palette.editable') !== false) {
menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"}); menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"});
menuOptions.push(null); menuOptions.push(null);
} }
@ -788,7 +512,7 @@ var RED = (function() {
} }
menuOptions.push({id:"menu-item-help", menuOptions.push({id:"menu-item-help",
label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")), label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
href: RED.settings.theme("menu.menu-item-help.url","https://nodered.org/docs") href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
}); });
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" }); menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });
@ -806,10 +530,11 @@ var RED = (function() {
RED.user.init(); RED.user.init();
RED.notifications.init(); RED.notifications.init();
RED.library.init(); RED.library.init();
RED.keyboard.init();
RED.palette.init(); RED.palette.init();
RED.eventLog.init(); RED.eventLog.init();
if (RED.settings.get('externalModules.palette.allowInstall', true) !== false) { if (RED.settings.theme('palette.editable') !== false) {
RED.palette.editor.init(); RED.palette.editor.init();
} else { } else {
console.log("Palette editor disabled"); console.log("Palette editor disabled");
@ -829,26 +554,22 @@ var RED = (function() {
RED.search.init(); RED.search.init();
RED.actionList.init(); RED.actionList.init();
RED.editor.init(); RED.editor.init();
RED.diagnostics.init();
RED.diff.init(); RED.diff.init();
RED.deploy.init(RED.settings.theme("deployButton",null)); RED.deploy.init(RED.settings.theme("deployButton",null));
RED.keyboard.init(buildMainMenu); buildMainMenu();
RED.envVar.init();
RED.nodes.init(); RED.nodes.init();
RED.runtime.init()
if (RED.settings.theme("multiplayer.enabled",false)) {
RED.multiplayer.init()
}
RED.comms.connect(); RED.comms.connect();
$("#red-ui-main-container").show(); $("#red-ui-main-container").show();
loadPluginList();
RED.actions.add("core:show-about", showAbout);
loadNodeList();
} }
@ -859,12 +580,11 @@ var RED = (function() {
$('<div id="red-ui-header-shade" class="hide"></div>').appendTo(header); $('<div id="red-ui-header-shade" class="hide"></div>').appendTo(header);
$('<div id="red-ui-main-container" class="red-ui-sidebar-closed hide">'+ $('<div id="red-ui-main-container" class="red-ui-sidebar-closed hide">'+
'<div id="red-ui-workspace"></div>'+ '<div id="red-ui-workspace"></div>'+
'<div id="red-ui-editor-stack" tabindex="-1"></div>'+ '<div id="red-ui-editor-stack"></div>'+
'<div id="red-ui-palette"></div>'+ '<div id="red-ui-palette"></div>'+
'<div id="red-ui-sidebar"></div>'+ '<div id="red-ui-sidebar"></div>'+
'<div id="red-ui-sidebar-separator"></div>'+ '<div id="red-ui-sidebar-separator"></div>'+
'</div>').appendTo(options.target); '</div>').appendTo(options.target);
$('<div id="red-ui-editor-plugin-configs"></div>').appendTo(options.target);
$('<div id="red-ui-editor-node-configs"></div>').appendTo(options.target); $('<div id="red-ui-editor-node-configs"></div>').appendTo(options.target);
$('<div id="red-ui-full-shade" class="hide"></div>').appendTo(options.target); $('<div id="red-ui-full-shade" class="hide"></div>').appendTo(options.target);
@ -883,12 +603,9 @@ var RED = (function() {
$('<span>').html(theme.header.title).appendTo(logo); $('<span>').html(theme.header.title).appendTo(logo);
} }
} }
if (theme.themes) {
knownThemes = theme.themes;
}
}); });
} }
var knownThemes = null;
var initialised = false; var initialised = false;
function init(options) { function init(options) {
@ -896,7 +613,7 @@ var RED = (function() {
throw new Error("RED already initialised"); throw new Error("RED already initialised");
} }
initialised = true; initialised = true;
if(window.ace) { window.ace.require("ace/ext/language_tools"); } ace.require("ace/ext/language_tools");
options = options || {}; options = options || {};
options.apiRootUrl = options.apiRootUrl || ""; options.apiRootUrl = options.apiRootUrl || "";
if (options.apiRootUrl && !/\/$/.test(options.apiRootUrl)) { if (options.apiRootUrl && !/\/$/.test(options.apiRootUrl)) {
@ -908,13 +625,7 @@ var RED = (function() {
buildEditor(options); buildEditor(options);
RED.i18n.init(options, function() { RED.i18n.init(options, function() {
RED.settings.init(options, function() { RED.settings.init(options, loadEditor);
if (knownThemes) {
RED.settings.editorTheme = RED.settings.editorTheme || {};
RED.settings.editorTheme.themes = knownThemes;
}
loadEditor();
});
}) })
} }

View File

@ -1,36 +0,0 @@
RED.runtime = (function() {
let state = ""
let settings = { ui: false, enabled: false };
const STOPPED = "stop"
const STARTED = "start"
const SAFE = "safe"
return {
init: function() {
// refresh the current runtime status from server
settings = Object.assign({}, settings, RED.settings.runtimeState);
RED.events.on("runtime-state", function(msg) {
if (msg.state) {
const currentState = state
state = msg.state
$(".red-ui-flow-node-button").toggleClass("red-ui-flow-node-button-stopped", state !== STARTED)
if(settings.enabled === true && settings.ui === true) {
RED.menu.setVisible("deploymenu-item-runtime-stop", state === STARTED)
RED.menu.setVisible("deploymenu-item-runtime-start", state !== STARTED)
}
// Do not notify the user about this event if:
// - This is the very first event we've received after loading the editor (currentState = '')
// - The state matches what we already thought was the case (state === currentState)
// - The event was triggered by a deploy (msg.deploy === true)
// - The event is a safe mode event - that gets notified separately
if (currentState !== '' && state !== currentState && !msg.deploy && state !== SAFE) {
RED.notify(RED._("notification.state.flows"+(state === STOPPED?'Stopped':'Started'), msg), "success")
}
}
});
},
get started() {
return state === STARTED
}
}
})()

Some files were not shown because too many files have changed in this diff Show More