mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
176 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e0b797fc7e | ||
|
795416a84d | ||
|
545dda166f | ||
|
f19ec5d9b6 | ||
|
6ea978d83d | ||
|
42f3b70a22 | ||
|
1cd10f074b | ||
|
bed1d31bc8 | ||
|
99478897c5 | ||
|
d79cd463a0 | ||
|
4023ab3f28 | ||
|
70f3b7450f | ||
|
ca4960e097 | ||
|
ebe604e1af | ||
|
f878ffc01b | ||
|
15b49f4db8 | ||
|
b1cc7b3296 | ||
|
65d90a6dff | ||
|
a58f4c2ec2 | ||
|
75d7ac2d8a | ||
|
6720c1aa46 | ||
|
280203e64e | ||
|
281d8b7cec | ||
|
2c6cda1f27 | ||
|
fa532da8c7 | ||
|
cbf84647de | ||
|
c38a490a6f | ||
|
9d7a450821 | ||
|
0ecd9673b8 | ||
|
97aa1230ef | ||
|
ff0be73b1f | ||
|
8049e44dec | ||
|
dc26022fb4 | ||
|
e8e44f9a32 | ||
|
12d56b8b03 | ||
|
e62fd7ed15 | ||
|
978eb95acd | ||
|
e34f4acb22 | ||
|
15a600c763 | ||
|
82ad5839fa | ||
|
9af883231d | ||
|
9bfe8ac007 | ||
|
f46367d77b | ||
|
eb2e1c0c45 | ||
|
baffc2d6ca | ||
|
96ab508c91 | ||
|
57e42659e3 | ||
|
f059e97697 | ||
|
516e6430eb | ||
|
f194a8ecf4 | ||
|
13f046f310 | ||
|
1edf5acb87 | ||
|
af636870d4 | ||
|
379b8ada61 | ||
|
5e63471983 | ||
|
086f0f8450 | ||
|
97a4b3dc2a | ||
|
4eb8d681c1 | ||
|
2066584164 | ||
|
a954c198fb | ||
|
bb1f8cd5e8 | ||
|
101e96dcb3 | ||
|
59adf82895 | ||
|
3b68f56b15 | ||
|
2962c4372c | ||
|
517e376582 | ||
|
7a90fe5aec | ||
|
ea45dde63a | ||
|
22a301b55e | ||
|
605177dcf0 | ||
|
460e1f5563 | ||
|
6f25337b99 | ||
|
08148a07b2 | ||
|
27c0e45940 | ||
|
bdd736315a | ||
|
d57ec0cd53 | ||
|
952c9d8bdb | ||
|
cf84ec78fa | ||
|
b595e84c30 | ||
|
6e5f115bd5 | ||
|
a1ab00c93e | ||
|
6e5c4e832e | ||
|
48ea487974 | ||
|
54dc98a90b | ||
|
c5bdd3d056 | ||
|
64d6e1f8e1 | ||
|
69d60ffb24 | ||
|
e6ffa3d143 | ||
|
bb4330e486 | ||
|
1a4d720978 | ||
|
91c2f479bb | ||
|
b61701fa17 | ||
|
cb9f910642 | ||
|
4b8d07f301 | ||
|
2db3a4f1ef | ||
|
ead1f65887 | ||
|
aae9866866 | ||
|
085ff84bc9 | ||
|
e12975cf0b | ||
|
a33cf6b532 | ||
|
5be25d9538 | ||
|
2b29eeb795 | ||
|
785561a0cc | ||
|
b46dc88346 | ||
|
96d81ef72b | ||
|
81dc3de26a | ||
|
4d0c572c2e | ||
|
fb2da0ee9e | ||
|
b8b0247717 | ||
|
103e212aee | ||
|
2f33575907 | ||
|
576c528573 | ||
|
3c444d3fb3 | ||
|
7cb499cde9 | ||
|
5a174ba014 | ||
|
041feb4e86 | ||
|
19726cf428 | ||
|
aaf134b1c5 | ||
|
9d5f5ee94b | ||
|
a48f0827ae | ||
|
5686158245 | ||
|
3824cdde68 | ||
|
e619b9bf7b | ||
|
b7243c2226 | ||
|
70b6674f44 | ||
|
ef67b8481e | ||
|
baffe4861c | ||
|
5cf489a270 | ||
|
44b1819926 | ||
|
d84c2b780b | ||
|
dc8991a1da | ||
|
7bd0ca2212 | ||
|
4dd619b8c6 | ||
|
3a86ab186c | ||
|
2f2a6367c2 | ||
|
be880c25f9 | ||
|
17812f0d77 | ||
|
0c5eae2349 | ||
|
3ad1803057 | ||
|
02c20e97b7 | ||
|
716dc781e4 | ||
|
d9900d8e4c | ||
|
3b9065b057 | ||
|
e73b748b95 | ||
|
b309161f00 | ||
|
b21667834e | ||
|
183fa59c83 | ||
|
0c5586ddfb | ||
|
33855bcb8b | ||
|
dc81b7a699 | ||
|
b0b2c32654 | ||
|
6f1ed76b4c | ||
|
f81cee0be2 | ||
|
bcd85b11a1 | ||
|
763f2bd5c5 | ||
|
1d250f7491 | ||
|
dd741ec6d8 | ||
|
e741af6d55 | ||
|
a004c61afc | ||
|
73d8dfe381 | ||
|
1177aa8aca | ||
|
0eda0a4935 | ||
|
a19dab0dc9 | ||
|
d8eb80b72e | ||
|
4f3a6821d1 | ||
|
77bd7541ca | ||
|
ca46bc5366 | ||
|
2e19bc07df | ||
|
3f4de43b67 | ||
|
0d0bf62fc4 | ||
|
3c8654fa25 | ||
|
756a6ec5aa | ||
|
410009dd61 | ||
|
0601833387 | ||
|
8b36279e52 | ||
|
5d7a625883 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -22,4 +22,5 @@ packages/node_modules/@node-red/editor-client/public
|
||||
!test/**/node_modules
|
||||
docs
|
||||
!packages/node_modules/**/docs
|
||||
.vscode
|
||||
.vscode
|
||||
.nyc_output
|
||||
|
10
.travis.yml
10
.travis.yml
@@ -5,11 +5,11 @@ language: node_js
|
||||
matrix:
|
||||
include:
|
||||
- node_js: "14"
|
||||
script:
|
||||
- ./node_modules/.bin/grunt && ( 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 coveralls
|
||||
- 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"
|
||||
|
125
CHANGELOG.md
125
CHANGELOG.md
@@ -1,3 +1,128 @@
|
||||
### 1.2.4: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Support bigint types in Debug sidebar
|
||||
- Clear retained status of deleted nodes
|
||||
- Prevent needless retention of node status messages
|
||||
- Update projects dialogs to use TypedInput-cred input
|
||||
- Restore cursor position in TypedInput cred-mode
|
||||
- Ensure config nodes with invalid z are imported somewhere
|
||||
- Ensure user keyboard shortcuts override defaults Fixes #2753
|
||||
|
||||
Runtime
|
||||
|
||||
- Disable projects when flowFile passed into grunt dev
|
||||
- Add Russian Locale (#2761) (#2531) (@alexk111)
|
||||
- Add Japanese translation for http-in node (#2758) (@kazuhitoyokoi)
|
||||
|
||||
Nodes
|
||||
|
||||
- CSV: Fix CSV node repeating array output
|
||||
|
||||
### 1.2.3: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Disable 'use strict' checking in Function node Fixes #2743
|
||||
- Add gray/grey alternate options for status
|
||||
- Handle import errors on initial load and report to user
|
||||
- Only apply recovery tab on initial load Fixes #2731
|
||||
- Reinstate coveralls reporting to travis build
|
||||
- Update Japanese message catalogue for 1.2.3 release #2747 (@HiroyasuNishiyama)
|
||||
|
||||
Runtime
|
||||
|
||||
- Modify default settings comment (#2739)
|
||||
- Add mutex lock to saveSettings storage call Fixes #2736 (#2737)
|
||||
- Migrate to nyc instead of istanbul for code coverage
|
||||
- Move mosca to ui-test-dependencies
|
||||
- Remove " from npm install prefix option
|
||||
|
||||
### 1.2.2: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Prevent node z property getting set to 0 or ""
|
||||
- Only apply z-recovery logic to flow nodes
|
||||
- Fix api call to reload flows Fixes #2726
|
||||
- Remove bad z property from import config nodes
|
||||
|
||||
### 1.2.1: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Fix race condition in .config file migration Fixes #2724
|
||||
|
||||
|
||||
### 1.2.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix selection of link node not existing within active workspace #2722 (@HiroyasuNishiyama)
|
||||
- Fix import of merged flow
|
||||
- Fix width of upload button in Safari #2718 (@HiroyasuNishiyama)
|
||||
- Update Chinese translations #2719 (@JiyeYu)
|
||||
- Update Japanese translations needed for 1.2 #2710 (@kazuhitoyokoi)
|
||||
- Fix unexpected line break of sidebar tab name popover #2716 (@HiroyasuNishiyama)
|
||||
- i18n module refresh tooltip #2717 (@HiroyasuNishiyama)
|
||||
- Add better error message if context file gets corrupted
|
||||
- Update info text of function node #2714 (@HiroyasuNishiyama)
|
||||
- Use markdown editor if editText called with md mode
|
||||
- Prevent group actions when in non-default mouse mode
|
||||
|
||||
### 1.2.0-beta.1: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Detect importing duplicate nodes and help user resolve #2698
|
||||
- Allow sidebar tabs to be reordered #2655
|
||||
- Add tgz upload button to palette manager #2682
|
||||
- Add 'automatic' git workflow for projects #2035
|
||||
- Allow project version string to be edited
|
||||
- Sanitize unknown node type when displaying
|
||||
- Handle nodes with invalid z property Closes #2170
|
||||
- Outline: Ensure sf instance nodes update in outliner when import-replace sf
|
||||
- Outline: Ensure recovered nodes tab is added to outliner properly
|
||||
- Groups: Only recalculate group label offsets when needed
|
||||
- Groups: Reuse first group name/style when merging elements Fixes #2680
|
||||
- Groups: Fix copy/paste of node into active group Fixes #2686
|
||||
- ACE: Update ACE to 1.4.12-src-min-noconflict Fixes #1988
|
||||
- ACE: Add comment highlighting to JSONata and fix regex handling Closes #2701
|
||||
- ACE: Ensure errors in ACE NRJavaScript mode are on valid lines
|
||||
- Prevent Enter on search box from reloading page Fixes #2678
|
||||
- Allow toggleButton icons to be optional
|
||||
- Allow treeList to have a header component
|
||||
- Disable selection of FA icons when dbl clicking node
|
||||
|
||||
Runtime
|
||||
|
||||
- Add RED.hooks API for pluggable routing #2665
|
||||
- Add flows:* events and deprecate nodes-* events
|
||||
- Split .config.json into separate files #2794
|
||||
- Add support for file upload in /nodes api #2682
|
||||
- Add 'done' metric log for message tracing #2685 (@k-toumura)
|
||||
- Add mutex locking around /flow apis #2679
|
||||
- Default flowFilePretty to true if projects enabled
|
||||
- Replace Math.random with crypto.getBytes for session tokens
|
||||
- Fix `this` context when calling multiple event listeners Fixes #2692. #2693 (@mgroenhoff)
|
||||
- Add --userDir=/tmp/foo support to grunt dev
|
||||
- Skip loading node html if disableEditor set #2684
|
||||
- Update util.writeFile to write to tmp file before rename #2683
|
||||
- Fix getModuleFiles function to include path property #2705 (@t-kawamorita)
|
||||
- Update nodemon to latest so grunt dev task behaves
|
||||
- Improve jsdoc of util.getObjectProperty to clarify thrown error See #2703
|
||||
|
||||
Nodes
|
||||
|
||||
- Trigger: allow msg.delay to be used to set delay/loop interval #2707
|
||||
- Function: allow to send & log in its initialize code #2644 (@cinhcet)
|
||||
- MQTT: Update to MQTT 4.2.1 Closes #2694
|
||||
- Debug: Handle undefined value in Debug view of Array and Object Fixes #2696
|
||||
- Switch: Clarify empty rules in switch node documentation #2649 (@natcl) #2669 (@kazuhitoyokoi)
|
||||
- Updated core nodes to use Done callback #2653 (@k-toumura)
|
||||
- yaml, xml, json, html, http, template, range, link, status, catch, complete, inject
|
||||
|
||||
### 1.1.3: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
67
Gruntfile.js
67
Gruntfile.js
@@ -20,10 +20,16 @@ var sass = require("node-sass");
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
var nodemonArgs = ["-v"];
|
||||
var nodemonArgs = ["-V"];
|
||||
var flowFile = grunt.option('flowFile');
|
||||
if (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');
|
||||
@@ -47,8 +53,8 @@ module.exports = function(grunt) {
|
||||
ui: 'bdd',
|
||||
reporter: 'spec'
|
||||
},
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
core: { src: ["test/_spec.js","test/unit/**/*_spec.js"]},
|
||||
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
webdriver: {
|
||||
@@ -56,19 +62,19 @@ module.exports = function(grunt) {
|
||||
configFile: 'test/editor/wdio.conf.js'
|
||||
}
|
||||
},
|
||||
mocha_istanbul: {
|
||||
nyc: {
|
||||
options: {
|
||||
globals: ['expect'],
|
||||
timeout: 3000,
|
||||
ignoreLeaks: false,
|
||||
ui: 'bdd',
|
||||
reportFormats: ['lcov','html'],
|
||||
print: 'both',
|
||||
istanbulOptions: ['--no-default-excludes', '-i','**/packages/node_modules/**']
|
||||
cwd: '.',
|
||||
include: ['packages/node_modules/**'],
|
||||
excludeNodeModules: false,
|
||||
exclude: ['packages/node_modules/@node-red/editor-client/**'],
|
||||
reporter: ['lcov', 'html','text-summary'],
|
||||
reportDir: 'coverage',
|
||||
all: true
|
||||
},
|
||||
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
all: { cmd: false, args: ['grunt', 'simplemocha:all'] },
|
||||
core: { options: { exclude:['packages/node_modules/@node-red/editor-client/**', 'packages/node_modules/@node-red/nodes/**']},cmd: false, args: ['grunt', 'simplemocha:core'] },
|
||||
nodes: { cmd: false, args: ['grunt', 'simplemocha:nodes'] }
|
||||
},
|
||||
jshint: {
|
||||
options: {
|
||||
@@ -452,6 +458,7 @@ module.exports = function(grunt) {
|
||||
'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/events.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/hooks.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/auth/index.js'
|
||||
@@ -502,12 +509,10 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-concurrent');
|
||||
grunt.loadNpmTasks('grunt-sass');
|
||||
grunt.loadNpmTasks('grunt-nodemon');
|
||||
grunt.loadNpmTasks('grunt-contrib-compress');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-chmod');
|
||||
grunt.loadNpmTasks('grunt-jsonlint');
|
||||
grunt.loadNpmTasks('grunt-mocha-istanbul');
|
||||
if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
|
||||
grunt.loadNpmTasks('grunt-webdriver');
|
||||
}
|
||||
@@ -515,6 +520,26 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
|
||||
grunt.loadNpmTasks('grunt-npm-command');
|
||||
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() {
|
||||
var files = this.data.src;
|
||||
@@ -596,11 +621,11 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('default',
|
||||
'Builds editor content then runs code style checks and unit tests on all components',
|
||||
['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']);
|
||||
['build','verifyPackageDependencies','jshint:editor','nyc:all']);
|
||||
|
||||
grunt.registerTask('test-core',
|
||||
'Runs code style check and unit tests on core runtime code',
|
||||
['build','mocha_istanbul:core']);
|
||||
['build','nyc:core']);
|
||||
|
||||
grunt.registerTask('test-editor',
|
||||
'Runs code style check on editor code',
|
||||
@@ -618,12 +643,12 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('test-nodes',
|
||||
'Runs unit tests on core nodes',
|
||||
['build','mocha_istanbul:nodes']);
|
||||
['build','nyc:nodes']);
|
||||
|
||||
grunt.registerTask('build',
|
||||
'Builds editor content',
|
||||
['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']);
|
||||
|
||||
|
||||
grunt.registerTask('build-dev',
|
||||
'Developer mode: build dev version',
|
||||
['clean:build','concat:build','concat:vendor','copy:build','sass:build','setDevEnv']);
|
||||
@@ -643,7 +668,7 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('coverage',
|
||||
'Run Istanbul code test coverage task',
|
||||
['build','mocha_istanbul:all']);
|
||||
['build','nyc:all']);
|
||||
|
||||
grunt.registerTask('docs',
|
||||
'Generates API documentation',
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
|
@@ -67,4 +67,4 @@ It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-t
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Copyright JS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE).
|
||||
Copyright OpenJS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE).
|
||||
|
@@ -1,13 +1,5 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 1.0.0 | :white_check_mark: |
|
||||
| 0.20.x | :white_check_mark: |
|
||||
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report any potential security issues to `team@nodered.org`. This will notify the core project team who will respond accordingly.
|
||||
|
44
package.json
44
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "1.1.3",
|
||||
"version": "1.2.4",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -26,7 +26,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "6.12.3",
|
||||
"ajv": "6.12.6",
|
||||
"async-mutex": "0.2.4",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
@@ -49,20 +50,20 @@
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.14.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.8.3",
|
||||
"jsonata": "1.8.4",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.2",
|
||||
"memorystore": "1.6.4",
|
||||
"mime": "2.4.6",
|
||||
"moment-timezone": "^0.5.31",
|
||||
"mqtt": "2.18.8",
|
||||
"moment-timezone": "0.5.32",
|
||||
"mqtt": "4.2.5",
|
||||
"multer": "1.4.2",
|
||||
"mustache": "4.0.1",
|
||||
"node-red-admin": "^0.2.6",
|
||||
"node-red-node-rbe": "^0.2.9",
|
||||
"node-red-node-sentiment": "^0.1.6",
|
||||
"node-red-node-tail": "^0.1.0",
|
||||
"nopt": "4.0.3",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.4.1",
|
||||
@@ -71,7 +72,8 @@
|
||||
"raw-body": "2.4.1",
|
||||
"request": "2.88.0",
|
||||
"semver": "6.3.0",
|
||||
"uglify-js": "3.10.0",
|
||||
"tar": "6.0.5",
|
||||
"uglify-js": "3.11.6",
|
||||
"when": "3.7.8",
|
||||
"ws": "6.2.1",
|
||||
"xml2js": "0.4.23"
|
||||
@@ -80,40 +82,38 @@
|
||||
"bcrypt": "3.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"marked": "0.8.2",
|
||||
"dompurify": "2.0.12",
|
||||
"grunt": "~1.0.4",
|
||||
"dompurify": "2.2.2",
|
||||
"grunt": "1.3.0",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.3.2",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-concurrent": "3.0.0",
|
||||
"grunt-contrib-clean": "~2.0.0",
|
||||
"grunt-contrib-compress": "~1.5.0",
|
||||
"grunt-contrib-compress": "1.6.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "~2.1.0",
|
||||
"grunt-contrib-uglify": "~4.0.1",
|
||||
"grunt-contrib-watch": "~1.1.0",
|
||||
"grunt-jsdoc": "^2.2.1",
|
||||
"grunt-jsdoc-to-markdown": "^4.0.0",
|
||||
"grunt-jsonlint": "~2.0.0",
|
||||
"grunt-jsdoc": "2.4.1",
|
||||
"grunt-jsdoc-to-markdown": "5.0.0",
|
||||
"grunt-jsonlint": "2.1.3",
|
||||
"grunt-mkdir": "~1.0.0",
|
||||
"grunt-mocha-istanbul": "5.0.2",
|
||||
"grunt-nodemon": "~0.4.2",
|
||||
"grunt-npm-command": "~0.1.2",
|
||||
"grunt-sass": "~3.1.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-simple-nyc": "^3.0.1",
|
||||
"http-proxy": "1.18.1",
|
||||
"istanbul": "0.4.5",
|
||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||
"marked": "1.2.4",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "^5.2.0",
|
||||
"mosca": "^2.8.3",
|
||||
"node-red-node-test-helper": "^0.2.5",
|
||||
"node-sass": "^4.14.1",
|
||||
"should": "^8.4.0",
|
||||
"nodemon": "2.0.6",
|
||||
"should": "13.2.3",
|
||||
"sinon": "1.17.7",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "3.4.2"
|
||||
"supertest": "5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
|
@@ -49,7 +49,14 @@ module.exports = {
|
||||
|
||||
// Nodes
|
||||
adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler);
|
||||
adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler);
|
||||
|
||||
if (!settings.editorTheme || !settings.editorTheme.palette || settings.editorTheme.palette.upload !== 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.get(/^\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler);
|
||||
adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler);
|
||||
adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler);
|
||||
|
@@ -45,8 +45,18 @@ module.exports = {
|
||||
module: req.body.module,
|
||||
version: req.body.version,
|
||||
url: req.body.url,
|
||||
tarball: undefined,
|
||||
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) {
|
||||
res.json(info);
|
||||
}).catch(function(err) {
|
||||
|
@@ -14,15 +14,7 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
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("");
|
||||
}
|
||||
|
||||
const crypto = require("crypto");
|
||||
|
||||
var storage;
|
||||
var sessionExpiryTime
|
||||
@@ -115,7 +107,7 @@ module.exports = {
|
||||
},
|
||||
create: function(user,client,scope) {
|
||||
return loadSessions().then(function() {
|
||||
var accessToken = generateToken(128);
|
||||
var accessToken = crypto.randomBytes(128).toString('base64');
|
||||
|
||||
var accessTokenExpiresAt = Date.now() + (sessionExpiryTime*1000);
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
var ws = require("ws");
|
||||
var url = require("url");
|
||||
const crypto = require("crypto");
|
||||
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
var Tokens;
|
||||
@@ -32,8 +33,6 @@ var activeConnections = [];
|
||||
|
||||
var anonymousUser;
|
||||
|
||||
var retained = {};
|
||||
|
||||
var heartbeatTimer;
|
||||
var lastSentTime;
|
||||
|
||||
@@ -56,17 +55,9 @@ 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) {
|
||||
this.session = generateSession(32);
|
||||
this.session = crypto.randomBytes(32).toString('base64');
|
||||
this.ws = ws;
|
||||
this.stack = [];
|
||||
this.user = user;
|
||||
|
@@ -137,6 +137,7 @@ module.exports = {
|
||||
req.body.hasOwnProperty('description') ||
|
||||
req.body.hasOwnProperty('dependencies')||
|
||||
req.body.hasOwnProperty('summary') ||
|
||||
req.body.hasOwnProperty('version') ||
|
||||
req.body.hasOwnProperty('files') ||
|
||||
req.body.hasOwnProperty('git')) {
|
||||
runtimeAPI.projects.updateProject(opts).then(function() {
|
||||
|
@@ -43,6 +43,10 @@ module.exports = {
|
||||
rejectHandler: function(req,res,err) {
|
||||
//TODO: why this when errorHandler also?!
|
||||
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 = {
|
||||
code: err.code||"unexpected_error",
|
||||
message: err.message||err.toString()
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "1.1.3",
|
||||
"version": "1.2.4",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,16 +16,17 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "1.1.3",
|
||||
"@node-red/editor-client": "1.1.3",
|
||||
"@node-red/util": "1.2.4",
|
||||
"@node-red/editor-client": "1.2.4",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
"clone": "2.1.2",
|
||||
"cors": "2.8.5",
|
||||
"express-session": "1.17.1",
|
||||
"express": "4.17.1",
|
||||
"memorystore": "1.6.2",
|
||||
"memorystore": "1.6.4",
|
||||
"mime": "2.4.6",
|
||||
"multer": "1.4.2",
|
||||
"mustache": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
|
@@ -22,7 +22,8 @@
|
||||
"color": "Color",
|
||||
"position": "Position",
|
||||
"enable": "Enable",
|
||||
"disable": "Disable"
|
||||
"disable": "Disable",
|
||||
"upload": "Upload"
|
||||
},
|
||||
"type": {
|
||||
"string": "string",
|
||||
@@ -41,7 +42,8 @@
|
||||
"loadNodeCatalogs": "Loading Node catalogs",
|
||||
"loadNodes": "Loading Nodes __count__",
|
||||
"loadFlows": "Loading Flows",
|
||||
"importFlows": "Adding Flows to workspace"
|
||||
"importFlows": "Adding Flows to workspace",
|
||||
"importError": "<p>Error adding flows</p><p>__message__</p>"
|
||||
},
|
||||
"workspace": {
|
||||
"defaultName": "Flow __number__",
|
||||
@@ -197,6 +199,8 @@
|
||||
"flow_plural": "__count__ flows",
|
||||
"subflow": "__count__ subflow",
|
||||
"subflow_plural": "__count__ subflows",
|
||||
"replacedNodes": "__count__ node replaced",
|
||||
"replacedNodes_plural": "__count__ nodes replaced",
|
||||
"pasteNodes": "Paste flow json or",
|
||||
"selectFile": "select a file to import",
|
||||
"importNodes": "Import nodes",
|
||||
@@ -204,6 +208,8 @@
|
||||
"download": "Download",
|
||||
"importUnrecognised": "Imported unrecognised type:",
|
||||
"importUnrecognised_plural": "Imported unrecognised types:",
|
||||
"importDuplicate": "Imported duplicate node:",
|
||||
"importDuplicate_plural": "Imported duplicate nodes:",
|
||||
"nodesExported": "Nodes exported to clipboard",
|
||||
"nodesImported": "Imported:",
|
||||
"nodeCopied": "__count__ node copied",
|
||||
@@ -212,6 +218,9 @@
|
||||
"groupCopied_plural": "__count__ groups copied",
|
||||
"groupStyleCopied": "Group style copied",
|
||||
"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": {
|
||||
"selected":"selected nodes",
|
||||
"current":"current flow",
|
||||
@@ -226,13 +235,19 @@
|
||||
},
|
||||
"import": {
|
||||
"import": "Import to",
|
||||
"importSelected": "Import selected",
|
||||
"importCopy": "Import copy",
|
||||
"viewNodes": "View nodes...",
|
||||
"newFlow": "new flow",
|
||||
"replace": "replace",
|
||||
"errors": {
|
||||
"notArray": "Input not a JSON Array",
|
||||
"itemNotObject": "Input not a valid flow - item __index__ not a node object",
|
||||
"missingId": "Input not a valid flow - item __index__ missing 'id' 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."
|
||||
},
|
||||
"copyMessagePath": "Path copied",
|
||||
"copyMessageValue": "Value copied",
|
||||
@@ -532,6 +547,8 @@
|
||||
"sortAZ": "a-z",
|
||||
"sortRecent": "recent",
|
||||
"more": "+ __count__ more",
|
||||
"upload": "Upload module tgz file",
|
||||
"refresh": "Refresh module list",
|
||||
"errors": {
|
||||
"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>",
|
||||
@@ -708,6 +725,12 @@
|
||||
"committerTip": "Leave blank to use system default",
|
||||
"userName": "Username",
|
||||
"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",
|
||||
"sshKeysTip": "Allows you to create secure connections to remote git repositories.",
|
||||
"add": "add key",
|
||||
@@ -1066,6 +1089,7 @@
|
||||
"en-US": "English",
|
||||
"ja": "Japanese",
|
||||
"ko": "Korean",
|
||||
"ru": "Russian",
|
||||
"zh-CN": "Chinese(Simplified)",
|
||||
"zh-TW": "Chinese(Traditional)"
|
||||
}
|
||||
|
@@ -22,7 +22,8 @@
|
||||
"color": "色",
|
||||
"position": "配置",
|
||||
"enable": "有効",
|
||||
"disable": "無効"
|
||||
"disable": "無効",
|
||||
"upload": "アップロード"
|
||||
},
|
||||
"type": {
|
||||
"string": "文字列",
|
||||
@@ -41,7 +42,8 @@
|
||||
"loadNodeCatalogs": "ノードカタログを読み込み中",
|
||||
"loadNodes": "ノードを読み込み中 __count__",
|
||||
"loadFlows": "フローを読み込み中",
|
||||
"importFlows": "ワークスペースにフローを追加中"
|
||||
"importFlows": "ワークスペースにフローを追加中",
|
||||
"importError": "<p>フロー追加エラー</p><p>__message__</p>"
|
||||
},
|
||||
"workspace": {
|
||||
"defaultName": "フロー __number__",
|
||||
@@ -197,13 +199,17 @@
|
||||
"flow_plural": "__count__ 個のフロー",
|
||||
"subflow": "__count__ 個のサブフロー",
|
||||
"subflow_plural": "__count__ 個のサブフロー",
|
||||
"pasteNodes": "JSON形式のフローデータを貼り付けてください",
|
||||
"selectFile": "読み込むファイルを選択してください",
|
||||
"importNodes": "フローをクリップボートから読み込み",
|
||||
"replacedNodes": "置換された __count__ 個のノード",
|
||||
"replacedNodes_plural": "置換された __count__ 個のノード",
|
||||
"pasteNodes": "JSON形式のフローデータを貼り付け",
|
||||
"selectFile": "読み込むファイルを選択",
|
||||
"importNodes": "フローをクリップボードから読み込み",
|
||||
"exportNodes": "フローをクリップボードへ書き出し",
|
||||
"download": "ダウンロード",
|
||||
"importUnrecognised": "認識できない型が読み込まれました:",
|
||||
"importUnrecognised_plural": "認識できない型が読み込まれました:",
|
||||
"importDuplicate": "重複したノードを読み込みました:",
|
||||
"importDuplicate_plural": "重複したノードを読み込みました:",
|
||||
"nodesExported": "クリップボードへフローを書き出しました",
|
||||
"nodesImported": "読み込みました:",
|
||||
"nodeCopied": "__count__ 個のノードをコピーしました",
|
||||
@@ -212,6 +218,9 @@
|
||||
"groupCopied_plural": "__count__ 個のグループをコピーしました",
|
||||
"groupStyleCopied": "グループの形式をコピーしました",
|
||||
"invalidFlow": "不正なフロー: __message__",
|
||||
"recoveredNodes": "復旧したノード",
|
||||
"recoveredNodesInfo": "このフロー内のノードは読み込み時に、有効なフローIDがありませんでした。これらフローIDは、フローに追加されているため、復元または削除できます。",
|
||||
"recoveredNodesNotification": "<p>有効なフローIDを持たないノードが読み込まれました</p><p>これらノードは '__flowName__' という新しいフローへ追加されました。</p>",
|
||||
"export": {
|
||||
"selected": "選択したフロー",
|
||||
"current": "現在のタブ",
|
||||
@@ -226,13 +235,19 @@
|
||||
},
|
||||
"import": {
|
||||
"import": "読み込み先",
|
||||
"importSelected": "選択したノードを読み込み",
|
||||
"importCopy": "コピーを読み込み",
|
||||
"viewNodes": "ノードを参照...",
|
||||
"newFlow": "新規のタブ",
|
||||
"replace": "置換",
|
||||
"errors": {
|
||||
"notArray": "JSON形式の配列ではありません",
|
||||
"itemNotObject": "不正なフロー - __index__ 番目の要素はノードオブジェクトではありません",
|
||||
"missingId": "不正なフロー - __index__ 番目の要素に'id'プロパティがありません",
|
||||
"missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません"
|
||||
}
|
||||
},
|
||||
"conflictNotification1": "読み込もうとしているノードのいくつかは、既にワークスペース内に存在しています。",
|
||||
"conflictNotification2": "読み込むノードを選択し、また既存のノードを置き換えるか、もしくはそれらのコピーを読み込むかも選択してください。"
|
||||
},
|
||||
"copyMessagePath": "パスをコピーしました",
|
||||
"copyMessageValue": "値をコピーしました",
|
||||
@@ -532,6 +547,8 @@
|
||||
"sortAZ": "辞書順",
|
||||
"sortRecent": "日付順",
|
||||
"more": "+ さらに __count__ 個",
|
||||
"upload": "モジュールのtgzファイルをアップロード",
|
||||
"refresh": "モジュールリスト更新",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>",
|
||||
"installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
@@ -708,6 +725,12 @@
|
||||
"committerTip": "システムのデフォルトを使用する場合、空白のままにしてください",
|
||||
"userName": "ユーザ名",
|
||||
"email": "メールアドレス",
|
||||
"workflow": "ワークフロー",
|
||||
"workfowTip": "望ましいgitワークフローを選択してください",
|
||||
"workflowManual": "手動",
|
||||
"workflowManualTip": "全ての変更は「履歴」サイドバー内で手動でコミットする必要があります",
|
||||
"workflowAuto": "自動",
|
||||
"workflowAutoTip": "変更はデプロイの度に自動的にコミットされます",
|
||||
"sshKeys": "SSH キー",
|
||||
"sshKeysTip": "gitリポジトリへのセキュアな接続を作成できます。",
|
||||
"add": "キーを追加",
|
||||
|
1139
packages/node_modules/@node-red/editor-client/locales/ru/editor.json
vendored
Executable file
1139
packages/node_modules/@node-red/editor-client/locales/ru/editor.json
vendored
Executable file
File diff suppressed because it is too large
Load Diff
23
packages/node_modules/@node-red/editor-client/locales/ru/infotips.json
vendored
Executable file
23
packages/node_modules/@node-red/editor-client/locales/ru/infotips.json
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"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}} откроет редактор первого узла в текущем выборе"
|
||||
}
|
||||
}
|
274
packages/node_modules/@node-red/editor-client/locales/ru/jsonata.json
vendored
Executable file
274
packages/node_modules/@node-red/editor-client/locales/ru/jsonata.json
vendored
Executable file
@@ -0,0 +1,274 @@
|
||||
{
|
||||
"$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<object>",
|
||||
"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 - позиция этого значения, а весь массив передается в качестве третьего аргумента"
|
||||
},
|
||||
"$encodeUrl": {
|
||||
"args": "str",
|
||||
"desc": "Кодирует компонент Uniform Resource Locator (URL), заменяя каждый экземпляр определенных символов одной, двумя, тремя или четырьмя escape-последовательностями, представляющими кодировку UTF-8 символа.\n\nПример: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
|
||||
},
|
||||
"$encodeUrlComponent": {
|
||||
"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\"`"
|
||||
},
|
||||
"$decodeUrl": {
|
||||
"args": "str",
|
||||
"desc": "Декодирует компонент Uniform Resource Locator (URL), ранее созданный с помощью encodeUrlComponent.\n\nПример: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
|
||||
},
|
||||
"$decodeUrlComponent": {
|
||||
"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."
|
||||
}
|
||||
}
|
@@ -22,7 +22,8 @@
|
||||
"color": "颜色",
|
||||
"position": "位置",
|
||||
"enable": "启用",
|
||||
"disable": "禁用"
|
||||
"disable": "禁用",
|
||||
"upload": "上传"
|
||||
},
|
||||
"type": {
|
||||
"string": "字符串",
|
||||
@@ -197,6 +198,8 @@
|
||||
"flow_plural": "__count__ 个流程",
|
||||
"subflow": "__count__ 个子流程",
|
||||
"subflow_plural": "__count__ 子流程",
|
||||
"replacedNodes": "__count__ 个节点被置换",
|
||||
"replacedNodes_plural": "__count__ 个节点被置换",
|
||||
"pasteNodes": "在这里粘贴节点",
|
||||
"selectFile": "选择要导入的文件",
|
||||
"importNodes": "导入节点",
|
||||
@@ -212,6 +215,9 @@
|
||||
"groupCopied_plural": "已复制 __count__ 个groups",
|
||||
"groupStyleCopied": "已复制组风格",
|
||||
"invalidFlow": "无效的流程: __message__",
|
||||
"recoveredNodes": "复原的节点",
|
||||
"recoveredNodesInfo": "导入节点时,此流上的节点缺少有效的流ID。 它们已被添加到此流中,您可以复原或删除它们。",
|
||||
"recoveredNodesNotification": "<p>导入的节点缺少有效的流ID</p><p>已将它们添加到名为 '__flowName__'的新流中。</p>",
|
||||
"export": {
|
||||
"selected": "已选择的节点",
|
||||
"current": "现在的节点",
|
||||
@@ -226,13 +232,19 @@
|
||||
},
|
||||
"import": {
|
||||
"import": "导入到",
|
||||
"importSelected": "导入所选项",
|
||||
"importCopy": "导入副本",
|
||||
"viewNodes": "查看节点",
|
||||
"newFlow": "新流程",
|
||||
"replace": "置换",
|
||||
"errors": {
|
||||
"notArray": "输入的不是JSON数组",
|
||||
"itemNotObject": "输入的流无效 - 项目 __index__ 不是节点对象",
|
||||
"missingId": "输入的流无效-项 __index__ 缺少'id'属性",
|
||||
"missingType": "输入的流程无效-项 __index__ 缺少'类型'属性"
|
||||
}
|
||||
},
|
||||
"conflictNotification1": "您要导入的某些节点已经存在于工作空间中。",
|
||||
"conflictNotification2": "选择要导入的节点,并确认要替换现有的节点还是导入它们的副本"
|
||||
},
|
||||
"copyMessagePath": "已复制路径",
|
||||
"copyMessageValue": "已复制数值",
|
||||
@@ -533,6 +545,7 @@
|
||||
"sortAZ": "a-z顺序",
|
||||
"sortRecent": "日期顺序",
|
||||
"more": "增加 __count__ 个",
|
||||
"upload": "上传模块tgz文件",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "无法加载节点目录。<br>查看浏览器控制台了解更多信息",
|
||||
"installFailed": "无法安装: __module__<br>__message__<br>查看日志了解更多信息",
|
||||
@@ -709,6 +722,12 @@
|
||||
"committerTip": "保留空白以使用系统默认值",
|
||||
"userName": "用户名",
|
||||
"email": "电子邮件",
|
||||
"workflow": "工作流",
|
||||
"workfowTip": "选择您偏好的工作流",
|
||||
"workflowManual": "手动",
|
||||
"workflowManualTip": "所有更改都必须在“历史记录”侧边栏中手动提交",
|
||||
"workflowAuto": "自动",
|
||||
"workflowAutoTip": "每次部署后都会自动提交更改",
|
||||
"sshKeys": "SSH密钥",
|
||||
"sshKeysTip": "允许您创建到远程git存储库的安全连接。",
|
||||
"add": "添加密钥",
|
||||
|
@@ -22,7 +22,8 @@
|
||||
"color": "顏色",
|
||||
"position": "位置",
|
||||
"enable": "啟用",
|
||||
"disable": "禁用"
|
||||
"disable": "禁用",
|
||||
"upload": "上傳"
|
||||
},
|
||||
"type": {
|
||||
"string": "字符串",
|
||||
@@ -197,6 +198,8 @@
|
||||
"flow_plural": "__count__ 多流程",
|
||||
"subflow": "__count__ 子流程",
|
||||
"subflow_plural": "__count__ 多子流程",
|
||||
"replacedNodes": "__count__ 個節點被置換",
|
||||
"replacedNodes_plural": "__count__ 個節點被置換",
|
||||
"pasteNodes": "在這裡粘貼節點",
|
||||
"selectFile": "匯入所選檔案",
|
||||
"importNodes": "匯入節點",
|
||||
@@ -212,6 +215,9 @@
|
||||
"groupCopied_plural": "已複製 __count__ 個groups",
|
||||
"groupStyleCopied": "已複製組風格",
|
||||
"invalidFlow": "無效的流程: __message__",
|
||||
"recoveredNodes": "復原的節點",
|
||||
"recoveredNodesInfo": "導入節點時,此流上的節點缺少有效的流ID。它們已被添加到此流中,您可以復原或刪除它們。",
|
||||
"recoveredNodesNotification": "<p>導入的節點缺少有效的流ID</p><p>已將它們添加到名為 '__flowName__'的新流中。</p>",
|
||||
"export": {
|
||||
"selected": "已選擇的節點",
|
||||
"current": "現在的節點",
|
||||
@@ -226,13 +232,19 @@
|
||||
},
|
||||
"import": {
|
||||
"import": "匯入到",
|
||||
"importSelected": "導入所選項",
|
||||
"importCopy": "導入副本",
|
||||
"viewNodes": "查看節點",
|
||||
"newFlow": "新流程",
|
||||
"replace": "置換",
|
||||
"errors": {
|
||||
"notArray": "輸入的不是JSON數組",
|
||||
"itemNotObject": "輸入的流程無效-項目 __index__ 不是節點對象",
|
||||
"missingId": "輸入的流程無效-項 __index__ 缺少“ id”屬性",
|
||||
"missingType": "輸入的流程無效-項 __index__ 缺少“類型”屬性"
|
||||
}
|
||||
},
|
||||
"conflictNotification1": "您要導入的某些節點已經存在於工作空間中。",
|
||||
"conflictNotification2": "選擇要導入的節點,並確認要替換現有的節點還是導入它們的副本"
|
||||
},
|
||||
"copyMessagePath": "已複製路徑",
|
||||
"copyMessageValue": "已複製數值",
|
||||
@@ -533,6 +545,7 @@
|
||||
"sortAZ": "a-z順序",
|
||||
"sortRecent": "日期順序",
|
||||
"more": "增加 __count__ 個",
|
||||
"upload": "上傳模塊tgz文件",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制臺瞭解更多資訊",
|
||||
"installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊",
|
||||
@@ -709,6 +722,12 @@
|
||||
"committerTip": "保留空白以使用系統默認值",
|
||||
"userName": "用戶名",
|
||||
"email": "電子郵件",
|
||||
"workflow": "工作流",
|
||||
"workfowTip": "選擇您偏好的工作流",
|
||||
"workflowManual": "手動",
|
||||
"workflowManualTip": "所有更改都必須在“歷史記錄”側邊欄中手動提交",
|
||||
"workflowAuto": "自動",
|
||||
"workflowAutoTip": "每次部署後都會自動提交更改",
|
||||
"sshKeys": "SSH密鑰",
|
||||
"sshKeysTip": "允許您創建到遠程git存儲庫的安全連接。",
|
||||
"add": "添加密鑰",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "1.1.3",
|
||||
"version": "1.2.4",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
File diff suppressed because one or more lines are too long
@@ -1,8 +1,8 @@
|
||||
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() {
|
||||
; (function() {
|
||||
ace.require(["ace/snippets/nrjavascript"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
File diff suppressed because one or more lines are too long
@@ -76,13 +76,12 @@ oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
|
||||
(function() {
|
||||
this.setOptions = function(options) {
|
||||
this.options = options || {
|
||||
this.options = {
|
||||
// undef: true,
|
||||
// unused: true,
|
||||
esnext: true,
|
||||
moz: true,
|
||||
esversion: 9,
|
||||
devel: true,
|
||||
browser: true,
|
||||
browser: false,
|
||||
node: true,
|
||||
laxcomma: true,
|
||||
laxbreak: true,
|
||||
@@ -92,8 +91,17 @@ oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
maxerr: 100,
|
||||
expr: true,
|
||||
multistr: true,
|
||||
globalstrict: true
|
||||
strict: false,
|
||||
sub: true,
|
||||
asi: true
|
||||
};
|
||||
if (options) {
|
||||
for (var opt in options) {
|
||||
if (options.hasOwnProperty(opt)) {
|
||||
this.options[opt] = options.opt;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.doc.getValue() && this.deferredUpdate.schedule(100);
|
||||
};
|
||||
|
||||
@@ -119,6 +127,8 @@ oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
if (!value)
|
||||
return this.sender.emit("annotate", []);
|
||||
|
||||
var originalValue = value;
|
||||
|
||||
// [Node-RED] wrap the code in a function
|
||||
value = "async function __nodered__(msg) {\n"+value+"\n}";
|
||||
|
||||
@@ -138,6 +148,7 @@ oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
continue;
|
||||
var raw = error.raw;
|
||||
var type = "warning";
|
||||
var line = error.line - 2;
|
||||
|
||||
if (raw == "Missing semicolon.") {
|
||||
var str = error.evidence.substr(error.character);
|
||||
@@ -166,9 +177,62 @@ oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
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({
|
||||
// [Node-RED] offset the row for the added line
|
||||
row: error.line-2,
|
||||
row: Math.max(0,line),
|
||||
column: error.character-1,
|
||||
text: error.reason,
|
||||
type: type,
|
||||
|
@@ -37,22 +37,38 @@ RED.history = (function() {
|
||||
inverseEv.events.push(r);
|
||||
}
|
||||
} else if (ev.t == 'replace') {
|
||||
inverseEv = {
|
||||
t: 'replace',
|
||||
config: RED.nodes.createCompleteNodeSet(),
|
||||
changed: {},
|
||||
rev: RED.nodes.version()
|
||||
};
|
||||
RED.nodes.clear();
|
||||
var imported = RED.nodes.import(ev.config);
|
||||
imported[0].forEach(function(n) {
|
||||
if (ev.changed[n.id]) {
|
||||
n.changed = true;
|
||||
inverseEv.changed[n.id] = true;
|
||||
}
|
||||
})
|
||||
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 = {
|
||||
t: 'replace',
|
||||
config: RED.nodes.createCompleteNodeSet(),
|
||||
changed: {},
|
||||
rev: RED.nodes.version()
|
||||
};
|
||||
RED.nodes.clear();
|
||||
var imported = RED.nodes.import(ev.config);
|
||||
imported.nodes.forEach(function(n) {
|
||||
if (ev.changed[n.id]) {
|
||||
n.changed = true;
|
||||
inverseEv.changed[n.id] = true;
|
||||
}
|
||||
})
|
||||
|
||||
RED.nodes.version(ev.rev);
|
||||
RED.nodes.version(ev.rev);
|
||||
} 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
|
||||
}
|
||||
}
|
||||
} else if (ev.t == 'add') {
|
||||
inverseEv = {
|
||||
t: "delete",
|
||||
|
@@ -16,7 +16,7 @@
|
||||
RED.nodes = (function() {
|
||||
|
||||
var node_defs = {};
|
||||
var nodes = [];
|
||||
var nodes = {};
|
||||
var nodeTabMap = {};
|
||||
|
||||
var configNodes = {};
|
||||
@@ -189,6 +189,7 @@ RED.nodes = (function() {
|
||||
})();
|
||||
|
||||
function getID() {
|
||||
// return Math.floor(Math.random()*15728640 + 1048576).toString(16)
|
||||
return (1+Math.random()*4294967295).toString(16);
|
||||
}
|
||||
|
||||
@@ -216,7 +217,7 @@ RED.nodes = (function() {
|
||||
});
|
||||
n.i = nextId+1;
|
||||
}
|
||||
nodes.push(n);
|
||||
nodes[n.id] = n;
|
||||
if (nodeTabMap[n.z]) {
|
||||
nodeTabMap[n.z][n.id] = n;
|
||||
} else {
|
||||
@@ -233,12 +234,8 @@ RED.nodes = (function() {
|
||||
function getNode(id) {
|
||||
if (id in configNodes) {
|
||||
return configNodes[id];
|
||||
} else {
|
||||
for (var n in nodes) {
|
||||
if (nodes[n].id == id) {
|
||||
return nodes[n];
|
||||
}
|
||||
}
|
||||
} else if (id in nodes) {
|
||||
return nodes[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -252,58 +249,56 @@ RED.nodes = (function() {
|
||||
delete configNodes[id];
|
||||
RED.events.emit('nodes:remove',node);
|
||||
RED.workspaces.refresh();
|
||||
} else {
|
||||
node = getNode(id);
|
||||
if (node) {
|
||||
nodes.splice(nodes.indexOf(node),1);
|
||||
if (nodeTabMap[node.z]) {
|
||||
delete nodeTabMap[node.z][node.id];
|
||||
}
|
||||
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
|
||||
removedLinks.forEach(removeLink);
|
||||
var updatedConfigNode = false;
|
||||
for (var d in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d)) {
|
||||
var property = node._def.defaults[d];
|
||||
if (property.type) {
|
||||
var type = registry.getNodeType(property.type);
|
||||
if (type && type.category == "config") {
|
||||
var configNode = configNodes[node[d]];
|
||||
if (configNode) {
|
||||
updatedConfigNode = true;
|
||||
if (configNode._def.exclusive) {
|
||||
removeNode(node[d]);
|
||||
removedNodes.push(configNode);
|
||||
} else {
|
||||
var users = configNode.users;
|
||||
users.splice(users.indexOf(node),1);
|
||||
}
|
||||
} else if (id in nodes) {
|
||||
node = nodes[id];
|
||||
delete nodes[id]
|
||||
if (nodeTabMap[node.z]) {
|
||||
delete nodeTabMap[node.z][node.id];
|
||||
}
|
||||
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
|
||||
removedLinks.forEach(removeLink);
|
||||
var updatedConfigNode = false;
|
||||
for (var d in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d)) {
|
||||
var property = node._def.defaults[d];
|
||||
if (property.type) {
|
||||
var type = registry.getNodeType(property.type);
|
||||
if (type && type.category == "config") {
|
||||
var configNode = configNodes[node[d]];
|
||||
if (configNode) {
|
||||
updatedConfigNode = true;
|
||||
if (configNode._def.exclusive) {
|
||||
removeNode(node[d]);
|
||||
removedNodes.push(configNode);
|
||||
} else {
|
||||
var users = configNode.users;
|
||||
users.splice(users.indexOf(node),1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.type.indexOf("subflow:") === 0) {
|
||||
var subflowId = node.type.substring(8);
|
||||
var sf = RED.nodes.subflow(subflowId);
|
||||
if (sf) {
|
||||
sf.instances.splice(sf.instances.indexOf(node),1);
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedConfigNode) {
|
||||
RED.workspaces.refresh();
|
||||
}
|
||||
try {
|
||||
if (node._def.oneditdelete) {
|
||||
node._def.oneditdelete.call(node);
|
||||
}
|
||||
} catch(err) {
|
||||
console.log("oneditdelete",node.id,node.type,err.toString());
|
||||
}
|
||||
RED.events.emit('nodes:remove',node);
|
||||
}
|
||||
|
||||
if (node.type.indexOf("subflow:") === 0) {
|
||||
var subflowId = node.type.substring(8);
|
||||
var sf = RED.nodes.subflow(subflowId);
|
||||
if (sf) {
|
||||
sf.instances.splice(sf.instances.indexOf(node),1);
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedConfigNode) {
|
||||
RED.workspaces.refresh();
|
||||
}
|
||||
try {
|
||||
if (node._def.oneditdelete) {
|
||||
node._def.oneditdelete.call(node);
|
||||
}
|
||||
} catch(err) {
|
||||
console.log("oneditdelete",node.id,node.type,err.toString());
|
||||
}
|
||||
RED.events.emit('nodes:remove',node);
|
||||
}
|
||||
|
||||
|
||||
@@ -377,10 +372,13 @@ RED.nodes = (function() {
|
||||
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
|
||||
var i;
|
||||
var node;
|
||||
for (i=0;i<nodes.length;i++) {
|
||||
node = nodes[i];
|
||||
if (node.z == id) {
|
||||
removedNodes.push(node);
|
||||
// TODO: this should use nodeTabMap
|
||||
for (i in nodes) {
|
||||
if (nodes.hasOwnProperty(i)) {
|
||||
node = nodes[i];
|
||||
if (node.z == id) {
|
||||
removedNodes.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i in configNodes) {
|
||||
@@ -487,17 +485,19 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
function subflowContains(sfid,nodeid) {
|
||||
for (var i=0;i<nodes.length;i++) {
|
||||
var node = nodes[i];
|
||||
if (node.z === sfid) {
|
||||
var m = /^subflow:(.+)$/.exec(node.type);
|
||||
if (m) {
|
||||
if (m[1] === nodeid) {
|
||||
return true;
|
||||
} else {
|
||||
var result = subflowContains(m[1],nodeid);
|
||||
if (result) {
|
||||
for (var i in nodes) {
|
||||
if (nodes.hasOwnProperty(i)) {
|
||||
var node = nodes[i];
|
||||
if (node.z === sfid) {
|
||||
var m = /^subflow:(.+)$/.exec(node.type);
|
||||
if (m) {
|
||||
if (m[1] === nodeid) {
|
||||
return true;
|
||||
} else {
|
||||
var result = subflowContains(m[1],nodeid);
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -553,6 +553,9 @@ RED.nodes = (function() {
|
||||
node.id = n.id;
|
||||
node.type = n.type;
|
||||
node.z = n.z;
|
||||
if (node.z === 0 || node.z === "") {
|
||||
delete node.z;
|
||||
}
|
||||
if (n.d === true) {
|
||||
node.d = true;
|
||||
}
|
||||
@@ -737,6 +740,16 @@ RED.nodes = (function() {
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function createExportableSubflow(id) {
|
||||
var sf = getSubflow(id);
|
||||
var nodeSet = [sf];
|
||||
var sfNodeIds = Object.keys(nodeTabMap[sf.id]||{});
|
||||
for (var i=0, l=sfNodeIds.length; i<l; i++) {
|
||||
nodeSet.push(nodeTabMap[sf.id][sfNodeIds[i]]);
|
||||
}
|
||||
return createExportableNodeSet(nodeSet);
|
||||
}
|
||||
/**
|
||||
* Converts the current node selection to an exportable JSON Object
|
||||
**/
|
||||
@@ -826,9 +839,10 @@ RED.nodes = (function() {
|
||||
nns.push(convertNode(configNodes[i], exportCredentials));
|
||||
}
|
||||
}
|
||||
for (i=0;i<nodes.length;i++) {
|
||||
var node = nodes[i];
|
||||
nns.push(convertNode(node, exportCredentials));
|
||||
for (i in nodes) {
|
||||
if (nodes.hasOwnProperty(i)) {
|
||||
nns.push(convertNode(nodes[i], exportCredentials));
|
||||
}
|
||||
}
|
||||
return nns;
|
||||
}
|
||||
@@ -898,11 +912,164 @@ RED.nodes = (function() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function importNodes(newNodesObj,createNewIds,createMissingWorkspace) {
|
||||
function identifyImportConflicts(importedNodes) {
|
||||
var imported = {
|
||||
tabs: {},
|
||||
subflows: {},
|
||||
groups: {},
|
||||
configs: {},
|
||||
nodes: {},
|
||||
all: [],
|
||||
conflicted: {},
|
||||
zMap: {},
|
||||
}
|
||||
|
||||
importedNodes.forEach(function(n) {
|
||||
imported.all.push(n);
|
||||
if (n.type === "tab") {
|
||||
imported.tabs[n.id] = n;
|
||||
} else if (n.type === "subflow") {
|
||||
imported.subflows[n.id] = n;
|
||||
} else if (n.type === "group") {
|
||||
imported.groups[n.id] = n;
|
||||
} else if (n.hasOwnProperty("x") && n.hasOwnProperty("y")) {
|
||||
imported.nodes[n.id] = n;
|
||||
} else {
|
||||
imported.configs[n.id] = n;
|
||||
}
|
||||
var nodeZ = n.z || "__global__";
|
||||
imported.zMap[nodeZ] = imported.zMap[nodeZ] || [];
|
||||
imported.zMap[nodeZ].push(n)
|
||||
if (nodes[n.id] || configNodes[n.id] || workspaces[n.id] || subflows[n.id] || groups[n.id]) {
|
||||
imported.conflicted[n.id] = n;
|
||||
}
|
||||
})
|
||||
return imported;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replace the provided nodes.
|
||||
* This must contain complete Subflow defs or complete Flow Tabs.
|
||||
* It does not replace an individual node in the middle of a flow.
|
||||
*/
|
||||
function replaceNodes(newNodes) {
|
||||
var zMap = {};
|
||||
var newSubflows = {};
|
||||
var newConfigNodes = {};
|
||||
var removedNodes = [];
|
||||
// Figure out what we're being asked to replace - subflows/configNodes
|
||||
// TODO: config nodes
|
||||
newNodes.forEach(function(n) {
|
||||
if (n.type === "subflow") {
|
||||
newSubflows[n.id] = n;
|
||||
} else if (!n.hasOwnProperty('x') && !n.hasOwnProperty('y')) {
|
||||
newConfigNodes[n.id] = n;
|
||||
}
|
||||
if (n.z) {
|
||||
zMap[n.z] = zMap[n.z] || [];
|
||||
zMap[n.z].push(n);
|
||||
}
|
||||
})
|
||||
|
||||
// Filter out config nodes inside a subflow def that is being replaced
|
||||
var configNodeIds = Object.keys(newConfigNodes);
|
||||
configNodeIds.forEach(function(id) {
|
||||
var n = newConfigNodes[id];
|
||||
if (newSubflows[n.z]) {
|
||||
// This config node is in a subflow to be replaced.
|
||||
// - remove from the list as it'll get handled with the subflow
|
||||
delete newConfigNodes[id];
|
||||
}
|
||||
});
|
||||
// Rebuild the list of ids
|
||||
configNodeIds = Object.keys(newConfigNodes);
|
||||
|
||||
// ------------------------------
|
||||
// Replace subflow definitions
|
||||
//
|
||||
// For each of the subflows to be replaced:
|
||||
var newSubflowIds = Object.keys(newSubflows);
|
||||
newSubflowIds.forEach(function(id) {
|
||||
var n = newSubflows[id];
|
||||
// Get a snapshot of the existing subflow definition
|
||||
removedNodes = removedNodes.concat(createExportableSubflow(id));
|
||||
// Remove the old subflow definition - but leave the instances in place
|
||||
var removalResult = RED.subflow.removeSubflow(n.id, true);
|
||||
// Create the list of nodes for the new subflow def
|
||||
var subflowNodes = [n].concat(zMap[n.id]);
|
||||
// Import the new subflow - no clashes should occur as we've removed
|
||||
// the old version
|
||||
var result = importNodes(subflowNodes);
|
||||
newSubflows[id] = getSubflow(id);
|
||||
})
|
||||
|
||||
// Having replaced the subflow definitions, now need to update the
|
||||
// instance nodes.
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (/^subflow:/.test(n.type)) {
|
||||
var sfId = n.type.substring(8);
|
||||
if (newSubflows[sfId]) {
|
||||
// This is an instance of one of the replaced subflows
|
||||
// - update the new def's instances array to include this one
|
||||
newSubflows[sfId].instances.push(n);
|
||||
// - update the instance's _def to point to the new def
|
||||
n._def = RED.nodes.getType(n.type);
|
||||
// - set all the flags so the view refreshes properly
|
||||
n.dirty = true;
|
||||
n.changed = true;
|
||||
n._colorChanged = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
newSubflowIds.forEach(function(id) {
|
||||
var n = newSubflows[id];
|
||||
RED.events.emit("subflows:change",n);
|
||||
})
|
||||
// Just in case the imported subflow changed color.
|
||||
RED.utils.clearNodeColorCache();
|
||||
|
||||
// ------------------------------
|
||||
// Replace config nodes
|
||||
//
|
||||
configNodeIds.forEach(function(id) {
|
||||
removedNodes = removedNodes.concat(convertNode(getNode(id)));
|
||||
removeNode(id);
|
||||
importNodes([newConfigNodes[id]])
|
||||
});
|
||||
|
||||
return {
|
||||
removedNodes: removedNodes
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Options:
|
||||
* - generateIds - whether to replace all node ids
|
||||
* - addFlow - whether to import nodes to a new tab
|
||||
* - importToCurrent
|
||||
* - importMap - how to resolve any conflicts.
|
||||
* - id:import - import as-is
|
||||
* - id:copy - import with new id
|
||||
* - id:replace - import over the top of existing
|
||||
*/
|
||||
function importNodes(newNodesObj,options) { // createNewIds,createMissingWorkspace) {
|
||||
options = options || {
|
||||
generateIds: false,
|
||||
addFlow: false,
|
||||
}
|
||||
options.importMap = options.importMap || {};
|
||||
|
||||
var createNewIds = options.generateIds;
|
||||
var createMissingWorkspace = options.addFlow;
|
||||
var i;
|
||||
var n;
|
||||
var newNodes;
|
||||
var nodeZmap = {};
|
||||
var recoveryWorkspace;
|
||||
if (typeof newNodesObj === "string") {
|
||||
if (newNodesObj === "") {
|
||||
return;
|
||||
@@ -927,14 +1094,59 @@ RED.nodes = (function() {
|
||||
// copies of the flow would get loaded at the same time.
|
||||
// If the user hit deploy they would have saved those duplicates.
|
||||
var seenIds = {};
|
||||
var existingNodes = [];
|
||||
var nodesToReplace = [];
|
||||
|
||||
newNodes = newNodes.filter(function(n) {
|
||||
var id = n.id;
|
||||
if (seenIds[n.id]) {
|
||||
return false;
|
||||
}
|
||||
seenIds[n.id] = true;
|
||||
|
||||
if (!options.generateIds) {
|
||||
if (!options.importMap[id]) {
|
||||
// No conflict resolution for this node
|
||||
var existing = nodes[id] || configNodes[id] || workspaces[id] || subflows[id] || groups[id];
|
||||
if (existing) {
|
||||
existingNodes.push({existing:existing, imported:n});
|
||||
}
|
||||
} else if (options.importMap[id] === "replace") {
|
||||
nodesToReplace.push(n);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
|
||||
if (existingNodes.length > 0) {
|
||||
var errorMessage = RED._("clipboard.importDuplicate",{count:existingNodes.length});
|
||||
var nodeList = $("<ul>");
|
||||
var existingNodesCount = Math.min(5,existingNodes.length);
|
||||
for (var i=0;i<existingNodesCount;i++) {
|
||||
var conflict = existingNodes[i];
|
||||
$("<li>").text(
|
||||
conflict.existing.id+
|
||||
" [ "+conflict.existing.type+ ((conflict.imported.type !== conflict.existing.type)?" | "+conflict.imported.type:"")+" ]").appendTo(nodeList)
|
||||
}
|
||||
if (existingNodesCount !== existingNodes.length) {
|
||||
$("<li>").text(RED._("deploy.confirm.plusNMore",{count:existingNodes.length-existingNodesCount})).appendTo(nodeList)
|
||||
}
|
||||
var wrapper = $("<p>").append(nodeList);
|
||||
|
||||
var existingNodesError = new Error(errorMessage+wrapper.html());
|
||||
existingNodesError.code = "import_conflict";
|
||||
existingNodesError.importConfig = identifyImportConflicts(newNodes);
|
||||
throw existingNodesError;
|
||||
}
|
||||
var removedNodes;
|
||||
if (nodesToReplace.length > 0) {
|
||||
var replaceResult = replaceNodes(nodesToReplace);
|
||||
removedNodes = replaceResult.removedNodes;
|
||||
}
|
||||
|
||||
|
||||
var isInitialLoad = false;
|
||||
if (!initialLoad) {
|
||||
isInitialLoad = true;
|
||||
@@ -943,6 +1155,7 @@ RED.nodes = (function() {
|
||||
var unknownTypes = [];
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
var id = n.id;
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type != "workspace" &&
|
||||
n.type != "tab" &&
|
||||
@@ -956,11 +1169,32 @@ RED.nodes = (function() {
|
||||
if (n.z) {
|
||||
nodeZmap[n.z] = nodeZmap[n.z] || [];
|
||||
nodeZmap[n.z].push(n);
|
||||
} else if (isInitialLoad && n.hasOwnProperty('x') && n.hasOwnProperty('y') && !n.z) {
|
||||
// Hit the rare issue where node z values get set to 0.
|
||||
// Repair the flow - but we really need to track that down.
|
||||
if (!recoveryWorkspace) {
|
||||
recoveryWorkspace = {
|
||||
id: RED.nodes.id(),
|
||||
type: "tab",
|
||||
disabled: false,
|
||||
label: RED._("clipboard.recoveredNodes"),
|
||||
info: RED._("clipboard.recoveredNodesInfo")
|
||||
}
|
||||
addWorkspace(recoveryWorkspace);
|
||||
RED.workspaces.add(recoveryWorkspace);
|
||||
nodeZmap[recoveryWorkspace.id] = [];
|
||||
}
|
||||
n.z = recoveryWorkspace.id;
|
||||
nodeZmap[recoveryWorkspace.id].push(n);
|
||||
}
|
||||
|
||||
}
|
||||
if (!isInitialLoad && unknownTypes.length > 0) {
|
||||
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
|
||||
var typeList = $("<ul>");
|
||||
unknownTypes.forEach(function(t) {
|
||||
$("<li>").text(t).appendTo(typeList);
|
||||
})
|
||||
typeList = typeList[0].outerHTML;
|
||||
RED.notify("<p>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</p>"+typeList,"error",false,10000);
|
||||
}
|
||||
|
||||
@@ -1005,6 +1239,10 @@ RED.nodes = (function() {
|
||||
var missingWorkspace = null;
|
||||
var d;
|
||||
|
||||
if (recoveryWorkspace) {
|
||||
new_workspaces.push(recoveryWorkspace);
|
||||
}
|
||||
|
||||
// Find all tabs and subflow templates
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
@@ -1016,7 +1254,10 @@ RED.nodes = (function() {
|
||||
if (defaultWorkspace == null) {
|
||||
defaultWorkspace = n;
|
||||
}
|
||||
if (createNewIds) {
|
||||
if (activeWorkspace === 0) {
|
||||
activeWorkspace = n.id;
|
||||
}
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
nid = getID();
|
||||
workspace_map[n.id] = nid;
|
||||
n.id = nid;
|
||||
@@ -1025,12 +1266,15 @@ RED.nodes = (function() {
|
||||
RED.workspaces.add(n);
|
||||
new_workspaces.push(n);
|
||||
} else if (n.type === "subflow") {
|
||||
var matchingSubflow = checkForMatchingSubflow(n,nodeZmap[n.id]);
|
||||
var matchingSubflow;
|
||||
if (!options.importMap[n.id]) {
|
||||
matchingSubflow = checkForMatchingSubflow(n,nodeZmap[n.id]);
|
||||
}
|
||||
if (matchingSubflow) {
|
||||
subflow_denylist[n.id] = matchingSubflow;
|
||||
} else {
|
||||
subflow_map[n.id] = n;
|
||||
if (createNewIds) {
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
nid = getID();
|
||||
n.id = nid;
|
||||
}
|
||||
@@ -1056,7 +1300,7 @@ RED.nodes = (function() {
|
||||
n.status.id = getID();
|
||||
}
|
||||
new_subflows.push(n);
|
||||
addSubflow(n,createNewIds);
|
||||
addSubflow(n,createNewIds || options.importMap[n.id] === "copy");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1076,7 +1320,7 @@ RED.nodes = (function() {
|
||||
def = registry.getNodeType(n.type);
|
||||
if (def && def.category == "config") {
|
||||
var existingConfigNode = null;
|
||||
if (createNewIds) {
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
if (n.z) {
|
||||
if (subflow_denylist[n.z]) {
|
||||
continue;
|
||||
@@ -1097,23 +1341,28 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
existingConfigNode = RED.nodes.node(n.id);
|
||||
if (existingConfigNode) {
|
||||
if (n.z && existingConfigNode.z !== n.z) {
|
||||
existingConfigNode = null;
|
||||
// Check the config nodes on n.z
|
||||
for (var cn in configNodes) {
|
||||
if (configNodes.hasOwnProperty(cn)) {
|
||||
if (configNodes[cn].z === n.z && compareNodes(configNodes[cn],n,false)) {
|
||||
existingConfigNode = configNodes[cn];
|
||||
node_map[n.id] = configNodes[cn];
|
||||
break;
|
||||
if (options.importMap[n.id] !== "copy") {
|
||||
existingConfigNode = RED.nodes.node(n.id);
|
||||
if (existingConfigNode) {
|
||||
if (n.z && existingConfigNode.z !== n.z) {
|
||||
existingConfigNode = null;
|
||||
// Check the config nodes on n.z
|
||||
for (var cn in configNodes) {
|
||||
if (configNodes.hasOwnProperty(cn)) {
|
||||
if (configNodes[cn].z === n.z && compareNodes(configNodes[cn],n,false)) {
|
||||
existingConfigNode = configNodes[cn];
|
||||
node_map[n.id] = configNodes[cn];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (n.z) {
|
||||
n.z = workspaces[n.z] || activeWorkspace;
|
||||
}
|
||||
}
|
||||
|
||||
if (!existingConfigNode || existingConfigNode._def.exclusive) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode.z !== n.z) {
|
||||
@@ -1125,6 +1374,9 @@ RED.nodes = (function() {
|
||||
users:[],
|
||||
_config:{}
|
||||
};
|
||||
if (!n.z) {
|
||||
delete configNode.z;
|
||||
}
|
||||
if (n.hasOwnProperty('d')) {
|
||||
configNode.d = n.d;
|
||||
}
|
||||
@@ -1144,7 +1396,7 @@ RED.nodes = (function() {
|
||||
}
|
||||
configNode.label = def.label;
|
||||
configNode._def = def;
|
||||
if (createNewIds) {
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
configNode.id = getID();
|
||||
}
|
||||
node_map[n.id] = configNode;
|
||||
@@ -1184,7 +1436,7 @@ RED.nodes = (function() {
|
||||
if (n.hasOwnProperty('g')) {
|
||||
node.g = n.g;
|
||||
}
|
||||
if (createNewIds) {
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
if (subflow_denylist[n.z]) {
|
||||
continue;
|
||||
} else if (subflow_map[node.z]) {
|
||||
@@ -1233,7 +1485,7 @@ RED.nodes = (function() {
|
||||
} else if (n.type.substring(0,7) === "subflow") {
|
||||
var parentId = n.type.split(":")[1];
|
||||
var subflow = subflow_denylist[parentId]||subflow_map[parentId]||getSubflow(parentId);
|
||||
if (createNewIds) {
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
parentId = subflow.id;
|
||||
node.type = "subflow:"+parentId;
|
||||
node._def = registry.getNodeType(node.type);
|
||||
@@ -1267,6 +1519,9 @@ RED.nodes = (function() {
|
||||
delete node.wires;
|
||||
delete node.inputLabels;
|
||||
delete node.outputLabels;
|
||||
if (!n.z) {
|
||||
delete node.z;
|
||||
}
|
||||
}
|
||||
var orig = {};
|
||||
for (var p in n) {
|
||||
@@ -1492,24 +1747,47 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
RED.workspaces.refresh();
|
||||
return [new_nodes,new_links,new_groups,new_workspaces,new_subflows,missingWorkspace];
|
||||
|
||||
|
||||
if (recoveryWorkspace) {
|
||||
var notification = RED.notify(RED._("clipboard.recoveredNodesNotification",{flowName:RED._("clipboard.recoveredNodes")}),{
|
||||
type:"warning",
|
||||
fixed:true,
|
||||
buttons: [
|
||||
{text: RED._("common.label.close"), click: function() { notification.close() }}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
nodes:new_nodes,
|
||||
links:new_links,
|
||||
groups:new_groups,
|
||||
workspaces:new_workspaces,
|
||||
subflows:new_subflows,
|
||||
missingWorkspace: missingWorkspace,
|
||||
removedNodes: removedNodes
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: supports filter.z|type
|
||||
function filterNodes(filter) {
|
||||
var result = [];
|
||||
var searchSet = nodes;
|
||||
var searchSet = null;
|
||||
var doZFilter = false;
|
||||
if (filter.hasOwnProperty("z")) {
|
||||
if (Object.hasOwnProperty("values") && nodeTabMap.hasOwnProperty(filter.z) ) {
|
||||
searchSet = Object.values(nodeTabMap[filter.z]);
|
||||
if (nodeTabMap.hasOwnProperty(filter.z)) {
|
||||
searchSet = Object.keys(nodeTabMap[filter.z]);
|
||||
} else {
|
||||
doZFilter = true;
|
||||
}
|
||||
}
|
||||
if (searchSet === null) {
|
||||
searchSet = Object.keys(nodes);
|
||||
}
|
||||
|
||||
for (var n=0;n<searchSet.length;n++) {
|
||||
var node = searchSet[n];
|
||||
var node = nodes[searchSet[n]];
|
||||
if (filter.hasOwnProperty("type") && node.type !== filter.type) {
|
||||
continue;
|
||||
}
|
||||
@@ -1578,7 +1856,7 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
function clear() {
|
||||
nodes = [];
|
||||
nodes = {};
|
||||
links = [];
|
||||
nodeTabMap = {};
|
||||
configNodes = {};
|
||||
@@ -1596,6 +1874,8 @@ RED.nodes = (function() {
|
||||
});
|
||||
defaultWorkspace = null;
|
||||
initialLoad = null;
|
||||
workspaces = {};
|
||||
|
||||
RED.nodes.dirty(false);
|
||||
RED.view.redraw(true, true);
|
||||
RED.palette.refresh();
|
||||
@@ -1606,7 +1886,7 @@ RED.nodes = (function() {
|
||||
RED.events.emit("workspace:clear");
|
||||
|
||||
// var node_defs = {};
|
||||
// var nodes = [];
|
||||
// var nodes = {};
|
||||
// var configNodes = {};
|
||||
// var links = [];
|
||||
// var defaultWorkspace;
|
||||
@@ -1666,7 +1946,7 @@ RED.nodes = (function() {
|
||||
if (configNodes.hasOwnProperty(n.id)) {
|
||||
delete configNodes[n.id];
|
||||
} else {
|
||||
nodes.splice(nodes.indexOf(n),1);
|
||||
delete nodes[n.id];
|
||||
if (nodeTabMap[n.z]) {
|
||||
delete nodeTabMap[n.z][n.id];
|
||||
}
|
||||
@@ -1688,9 +1968,9 @@ RED.nodes = (function() {
|
||||
// Force the redraw to be synchronous so the view updates
|
||||
// *now* and removes the unknown node
|
||||
RED.view.redraw(true, true);
|
||||
var result = importNodes(reimportList,false);
|
||||
var result = importNodes(reimportList,{generateIds:false});
|
||||
var newNodeMap = {};
|
||||
result[0].forEach(function(n) {
|
||||
result.nodes.forEach(function(n) {
|
||||
newNodeMap[n.id] = n;
|
||||
});
|
||||
RED.nodes.eachLink(function(l) {
|
||||
@@ -1747,9 +2027,11 @@ RED.nodes = (function() {
|
||||
groups: function(z) { return groupsByZ[z]||[] },
|
||||
|
||||
eachNode: function(cb) {
|
||||
for (var n=0;n<nodes.length;n++) {
|
||||
if (cb(nodes[n]) === false) {
|
||||
break;
|
||||
for (var id in nodes) {
|
||||
if (nodes.hasOwnProperty(id)) {
|
||||
if (cb(nodes[id]) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1802,6 +2084,8 @@ RED.nodes = (function() {
|
||||
|
||||
import: importNodes,
|
||||
|
||||
identifyImportConflicts: identifyImportConflicts,
|
||||
|
||||
getAllFlowNodes: getAllFlowNodes,
|
||||
createExportableNodeSet: createExportableNodeSet,
|
||||
createCompleteNodeSet: createCompleteNodeSet,
|
||||
|
@@ -178,11 +178,21 @@ var RED = (function() {
|
||||
var currentHash = window.location.hash;
|
||||
RED.nodes.version(nodes.rev);
|
||||
loader.reportProgress(RED._("event.importFlows"),90 )
|
||||
RED.nodes.import(nodes.flows);
|
||||
RED.nodes.dirty(false);
|
||||
RED.view.redraw(true);
|
||||
if (/^#flow\/.+$/.test(currentHash)) {
|
||||
RED.workspaces.show(currentHash.substring(6));
|
||||
try {
|
||||
RED.nodes.import(nodes.flows);
|
||||
RED.nodes.dirty(false);
|
||||
RED.view.redraw(true);
|
||||
if (/^#flow\/.+$/.test(currentHash)) {
|
||||
RED.workspaces.show(currentHash.substring(6));
|
||||
}
|
||||
} catch(err) {
|
||||
RED.notify(
|
||||
RED._("event.importError", {message: err.message}),
|
||||
{
|
||||
fixed: true,
|
||||
type: 'error'
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
done();
|
||||
|
@@ -21,7 +21,18 @@ RED.actions = (function() {
|
||||
var result = [];
|
||||
Object.keys(actions).forEach(function(action) {
|
||||
var shortcut = RED.keyboard.getShortcut(action);
|
||||
result.push({id:action,scope:shortcut?shortcut.scope:undefined,key:shortcut?shortcut.key:undefined,user:shortcut?shortcut.user:undefined})
|
||||
var isUser = false;
|
||||
if (shortcut) {
|
||||
isUser = shortcut.user;
|
||||
} else {
|
||||
isUser = !!RED.keyboard.getUserShortcut(action);
|
||||
}
|
||||
result.push({
|
||||
id:action,
|
||||
scope:shortcut?shortcut.scope:undefined,
|
||||
key:shortcut?shortcut.key:undefined,
|
||||
user:isUser
|
||||
})
|
||||
})
|
||||
return result;
|
||||
}
|
||||
|
@@ -28,6 +28,8 @@ RED.clipboard = (function() {
|
||||
var libraryBrowser;
|
||||
var examplesBrowser;
|
||||
|
||||
var pendingImportConfig;
|
||||
|
||||
function setupDialogs() {
|
||||
dialog = $('<div id="red-ui-clipboard-dialog" class="hide"><form class="dialog-form form-horizontal"></form></div>')
|
||||
.appendTo("#red-ui-editor")
|
||||
@@ -42,14 +44,14 @@ RED.clipboard = (function() {
|
||||
"ui-widget-overlay": "red-ui-editor-dialog"
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
{ // red-ui-clipboard-dialog-cancel
|
||||
id: "red-ui-clipboard-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{
|
||||
{ // red-ui-clipboard-dialog-download
|
||||
id: "red-ui-clipboard-dialog-download",
|
||||
class: "primary",
|
||||
text: RED._("clipboard.download"),
|
||||
@@ -64,7 +66,7 @@ RED.clipboard = (function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{
|
||||
{ // red-ui-clipboard-dialog-export
|
||||
id: "red-ui-clipboard-dialog-export",
|
||||
class: "primary",
|
||||
text: RED._("clipboard.export.copy"),
|
||||
@@ -134,14 +136,14 @@ RED.clipboard = (function() {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{ // red-ui-clipboard-dialog-ok
|
||||
id: "red-ui-clipboard-dialog-ok",
|
||||
class: "primary",
|
||||
text: RED._("common.label.import"),
|
||||
click: function() {
|
||||
var addNewFlow = ($("#red-ui-clipboard-dialog-import-opt > a.selected").attr('id') === 'red-ui-clipboard-dialog-import-opt-new');
|
||||
if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") {
|
||||
RED.view.importNodes($("#red-ui-clipboard-dialog-import-text").val(),addNewFlow);
|
||||
importNodes($("#red-ui-clipboard-dialog-import-text").val(),addNewFlow);
|
||||
} else {
|
||||
var selectedPath;
|
||||
if (activeTab === "red-ui-clipboard-dialog-import-tab-library") {
|
||||
@@ -151,12 +153,44 @@ RED.clipboard = (function() {
|
||||
}
|
||||
if (selectedPath.path) {
|
||||
$.get('library/'+selectedPath.library+'/'+selectedPath.type+'/'+selectedPath.path, function(data) {
|
||||
RED.view.importNodes(data,addNewFlow);
|
||||
importNodes(data,addNewFlow);
|
||||
});
|
||||
}
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{ // red-ui-clipboard-dialog-import-conflict
|
||||
id: "red-ui-clipboard-dialog-import-conflict",
|
||||
class: "primary",
|
||||
text: RED._("clipboard.import.importSelected"),
|
||||
click: function() {
|
||||
var importMap = {};
|
||||
$('#red-ui-clipboard-dialog-import-conflicts-list input[type="checkbox"]').each(function() {
|
||||
importMap[$(this).attr("data-node-id")] = this.checked?"import":"skip";
|
||||
})
|
||||
|
||||
$('.red-ui-clipboard-dialog-import-conflicts-controls input[type="checkbox"]').each(function() {
|
||||
if (!$(this).attr("disabled")) {
|
||||
importMap[$(this).attr("data-node-id")] = this.checked?"replace":"copy"
|
||||
}
|
||||
})
|
||||
// skip - don't import
|
||||
// import - import as-is
|
||||
// copy - import with new id
|
||||
// replace - import over the top of existing
|
||||
pendingImportConfig.importOptions.importMap = importMap;
|
||||
|
||||
var newNodes = pendingImportConfig.importNodes.filter(function(n) {
|
||||
if (!importMap[n.id] || importMap[n.z]) {
|
||||
importMap[n.id] = importMap[n.z];
|
||||
}
|
||||
return importMap[n.id] !== "skip"
|
||||
})
|
||||
// console.table(pendingImportConfig.importNodes.map(function(n) { return {id:n.id,type:n.type,result:importMap[n.id]}}))
|
||||
RED.view.importNodes(newNodes, pendingImportConfig.importOptions);
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
],
|
||||
open: function( event, ui ) {
|
||||
@@ -236,6 +270,14 @@ RED.clipboard = (function() {
|
||||
'</span>'+
|
||||
'</div>';
|
||||
|
||||
importConflictsDialog =
|
||||
'<div class="form-row">'+
|
||||
'<div class="form-row"><p data-i18n="clipboard.import.conflictNotification1"></p><p data-i18n="clipboard.import.conflictNotification2"></p></div>'+
|
||||
'<div class="red-ui-clipboard-dialog-import-conflicts-list-container">'+
|
||||
'<div id="red-ui-clipboard-dialog-import-conflicts-list"></div>'+
|
||||
'</div>'+
|
||||
'</div>';
|
||||
|
||||
}
|
||||
|
||||
var validateExportFilenameTimeout
|
||||
@@ -359,7 +401,7 @@ RED.clipboard = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function importNodes(mode) {
|
||||
function showImportNodes(mode) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
@@ -445,6 +487,8 @@ RED.clipboard = (function() {
|
||||
$("#red-ui-clipboard-dialog-cancel").show();
|
||||
$("#red-ui-clipboard-dialog-export").hide();
|
||||
$("#red-ui-clipboard-dialog-download").hide();
|
||||
$("#red-ui-clipboard-dialog-import-conflict").hide();
|
||||
|
||||
$("#red-ui-clipboard-dialog-ok").button("disable");
|
||||
$("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport);
|
||||
$("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)});
|
||||
@@ -485,7 +529,9 @@ RED.clipboard = (function() {
|
||||
}
|
||||
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
|
||||
|
||||
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
|
||||
dialog.dialog("option","title",RED._("clipboard.importNodes"))
|
||||
.dialog("option","width",700)
|
||||
.dialog("open");
|
||||
popover = RED.popover.create({
|
||||
target: $("#red-ui-clipboard-dialog-import-text"),
|
||||
trigger: "manual",
|
||||
@@ -494,7 +540,7 @@ RED.clipboard = (function() {
|
||||
});
|
||||
}
|
||||
|
||||
function exportNodes(mode) {
|
||||
function showExportNodes(mode) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
@@ -631,6 +677,8 @@ RED.clipboard = (function() {
|
||||
$("#red-ui-clipboard-dialog-ok").hide();
|
||||
$("#red-ui-clipboard-dialog-cancel").hide();
|
||||
$("#red-ui-clipboard-dialog-export").hide();
|
||||
$("#red-ui-clipboard-dialog-import-conflict").hide();
|
||||
|
||||
var selection = RED.workspaces.selection();
|
||||
if (selection.length > 0) {
|
||||
$("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
|
||||
@@ -657,12 +705,15 @@ RED.clipboard = (function() {
|
||||
}
|
||||
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
|
||||
|
||||
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
|
||||
dialog.dialog("option","title",RED._("clipboard.exportNodes"))
|
||||
.dialog("option","width",700)
|
||||
.dialog("open");
|
||||
|
||||
$("#red-ui-clipboard-dialog-export-text").trigger("focus");
|
||||
$("#red-ui-clipboard-dialog-cancel").show();
|
||||
$("#red-ui-clipboard-dialog-export").show();
|
||||
$("#red-ui-clipboard-dialog-download").show();
|
||||
$("#red-ui-clipboard-dialog-import-conflict").hide();
|
||||
|
||||
}
|
||||
|
||||
@@ -722,6 +773,12 @@ RED.clipboard = (function() {
|
||||
// representation or null
|
||||
return null;
|
||||
}
|
||||
if (value.type === 'bigint') {
|
||||
return value.data.toString();
|
||||
}
|
||||
if (value.type === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
@@ -746,19 +803,315 @@ RED.clipboard = (function() {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function importNodes(nodesStr,addFlow) {
|
||||
var newNodes = nodesStr;
|
||||
if (typeof nodesStr === 'string') {
|
||||
try {
|
||||
nodesStr = nodesStr.trim();
|
||||
if (nodesStr.length === 0) {
|
||||
return;
|
||||
}
|
||||
newNodes = JSON.parse(nodesStr);
|
||||
} catch(err) {
|
||||
var e = new Error(RED._("clipboard.invalidFlow",{message:err.message}));
|
||||
e.code = "NODE_RED";
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
var importOptions = {generateIds: false, addFlow: addFlow};
|
||||
try {
|
||||
RED.view.importNodes(newNodes, importOptions);
|
||||
} catch(error) {
|
||||
// Thrown for import_conflict
|
||||
confirmImport(error.importConfig, newNodes, importOptions);
|
||||
}
|
||||
}
|
||||
|
||||
function confirmImport(importConfig,importNodes,importOptions) {
|
||||
var notification = RED.notify("<p>"+RED._("clipboard.import.conflictNotification1")+"</p>",{
|
||||
type: "info",
|
||||
fixed: true,
|
||||
buttons: [
|
||||
{text: RED._("common.label.cancel"), click: function() { notification.close(); }},
|
||||
{text: RED._("clipboard.import.viewNodes"), click: function() {
|
||||
notification.close();
|
||||
showImportConflicts(importConfig,importNodes,importOptions);
|
||||
}},
|
||||
{text: RED._("clipboard.import.importCopy"), click: function() {
|
||||
notification.close();
|
||||
// generateIds=true to avoid conflicts
|
||||
// and default to the 'old' behaviour around matching
|
||||
// config nodes and subflows
|
||||
importOptions.generateIds = true;
|
||||
RED.view.importNodes(importNodes, importOptions);
|
||||
}}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function showImportConflicts(importConfig,importNodes,importOptions) {
|
||||
|
||||
pendingImportConfig = {
|
||||
importConfig: importConfig,
|
||||
importNodes: importNodes,
|
||||
importOptions: importOptions
|
||||
}
|
||||
|
||||
var id,node;
|
||||
var treeData = [];
|
||||
var container;
|
||||
var addedHeader = false;
|
||||
for (id in importConfig.subflows) {
|
||||
if (importConfig.subflows.hasOwnProperty(id)) {
|
||||
if (!addedHeader) {
|
||||
treeData.push({gutter:$('<span data-i18n="menu.label.subflows"></span>'), label: '', class:"red-ui-clipboard-dialog-import-conflicts-item-header"})
|
||||
addedHeader = true;
|
||||
}
|
||||
node = importConfig.subflows[id];
|
||||
var isConflicted = importConfig.conflicted[node.id];
|
||||
var isSelected = !isConflicted;
|
||||
var elements = getNodeElement(node, isConflicted, isSelected );
|
||||
container = {
|
||||
id: node.id,
|
||||
gutter: elements.gutter.element,
|
||||
element: elements.element,
|
||||
class: isSelected?"":"disabled",
|
||||
deferBuild: true,
|
||||
children: []
|
||||
}
|
||||
treeData.push(container);
|
||||
if (importConfig.zMap[id]) {
|
||||
importConfig.zMap[id].forEach(function(node) {
|
||||
var childElements = getNodeElement(node, importConfig.conflicted[node.id], isSelected, elements.gutter.cb);
|
||||
container.children.push({
|
||||
id: node.id,
|
||||
gutter: childElements.gutter.element,
|
||||
element: childElements.element,
|
||||
class: isSelected?"":"disabled"
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
addedHeader = false;
|
||||
for (id in importConfig.tabs) {
|
||||
if (importConfig.tabs.hasOwnProperty(id)) {
|
||||
if (!addedHeader) {
|
||||
treeData.push({gutter:$('<span data-i18n="menu.label.flows"></span>'), label: '', class:"red-ui-clipboard-dialog-import-conflicts-item-header"})
|
||||
addedHeader = true;
|
||||
}
|
||||
node = importConfig.tabs[id];
|
||||
var isConflicted = importConfig.conflicted[node.id];
|
||||
var isSelected = true;
|
||||
var elements = getNodeElement(node, isConflicted, isSelected);
|
||||
container = {
|
||||
id: node.id,
|
||||
gutter: elements.gutter.element,
|
||||
element: elements.element,
|
||||
icon: "red-ui-icons red-ui-icons-flow",
|
||||
deferBuild: true,
|
||||
class: isSelected?"":"disabled",
|
||||
children: []
|
||||
}
|
||||
treeData.push(container);
|
||||
if (importConfig.zMap[id]) {
|
||||
importConfig.zMap[id].forEach(function(node) {
|
||||
var childElements = getNodeElement(node, importConfig.conflicted[node.id], isSelected, elements.gutter.cb);
|
||||
container.children.push({
|
||||
id: node.id,
|
||||
gutter: childElements.gutter.element,
|
||||
element: childElements.element,
|
||||
class: isSelected?"":"disabled"
|
||||
})
|
||||
// console.log(" ["+(importConfig.conflicted[node.id]?"*":" ")+"] "+node.type+" "+node.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
addedHeader = false;
|
||||
var extraNodes = [];
|
||||
importConfig.all.forEach(function(node) {
|
||||
if (node.type !== "tab" && node.type !== "subflow" && !importConfig.tabs[node.z] && !importConfig.subflows[node.z]) {
|
||||
var isConflicted = importConfig.conflicted[node.id];
|
||||
var isSelected = !isConflicted || !importConfig.configs[node.id];
|
||||
var elements = getNodeElement(node, isConflicted, isSelected);
|
||||
var item = {
|
||||
id: node.id,
|
||||
gutter: elements.gutter.element,
|
||||
element: elements.element,
|
||||
class: isSelected?"":"disabled"
|
||||
}
|
||||
if (importConfig.configs[node.id]) {
|
||||
extraNodes.push(item);
|
||||
} else {
|
||||
if (!addedHeader) {
|
||||
treeData.push({gutter:$('<span data-i18n="menu.label.nodes"></span>'), label: '', class:"red-ui-clipboard-dialog-import-conflicts-item-header"})
|
||||
addedHeader = true;
|
||||
}
|
||||
treeData.push(item);
|
||||
}
|
||||
// console.log("["+(importConfig.conflicted[node.id]?"*":" ")+"] "+node.type+" "+node.id);
|
||||
}
|
||||
})
|
||||
if (extraNodes.length > 0) {
|
||||
treeData.push({gutter:$('<span data-i18n="menu.label.displayConfig"></span>'), label: '', class:"red-ui-clipboard-dialog-import-conflicts-item-header"})
|
||||
addedHeader = true;
|
||||
treeData = treeData.concat(extraNodes);
|
||||
|
||||
}
|
||||
dialogContainer.empty();
|
||||
dialogContainer.append($(importConflictsDialog));
|
||||
|
||||
|
||||
var nodeList = $("#red-ui-clipboard-dialog-import-conflicts-list").css({position:"absolute",top:0,right:0,bottom:0,left:0}).treeList({
|
||||
data: treeData
|
||||
})
|
||||
|
||||
dialogContainer.i18n();
|
||||
var dialogHeight = 400;
|
||||
var winHeight = $(window).height();
|
||||
if (winHeight < 600) {
|
||||
dialogHeight = 400 - (600 - winHeight);
|
||||
}
|
||||
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
|
||||
|
||||
$("#red-ui-clipboard-dialog-ok").hide();
|
||||
$("#red-ui-clipboard-dialog-cancel").show();
|
||||
$("#red-ui-clipboard-dialog-export").hide();
|
||||
$("#red-ui-clipboard-dialog-download").hide();
|
||||
$("#red-ui-clipboard-dialog-import-conflict").show();
|
||||
|
||||
|
||||
dialog.dialog("option","title",RED._("clipboard.importNodes"))
|
||||
.dialog("option","width",500)
|
||||
.dialog( "open" );
|
||||
|
||||
}
|
||||
|
||||
function getNodeElement(n, isConflicted, isSelected, parent) {
|
||||
var element;
|
||||
if (n.type === "tab") {
|
||||
element = getFlowLabel(n, isSelected);
|
||||
} else {
|
||||
element = getNodeLabel(n, isConflicted, isSelected);
|
||||
}
|
||||
var controls = $('<div>',{class:"red-ui-clipboard-dialog-import-conflicts-controls"}).appendTo(element);
|
||||
controls.on("click", function(evt) { evt.stopPropagation(); });
|
||||
if (isConflicted && !parent) {
|
||||
var cb = $('<label><input '+(isSelected?'':'disabled ')+'type="checkbox" data-node-id="'+n.id+'"> <span data-i18n="clipboard.import.replace"></span></label>').appendTo(controls);
|
||||
if (n.type === "tab" || (n.type !== "subflow" && n.hasOwnProperty("x") && n.hasOwnProperty("y"))) {
|
||||
cb.hide();
|
||||
}
|
||||
}
|
||||
return {
|
||||
element: element,
|
||||
gutter: getGutter(n, isSelected, parent)
|
||||
}
|
||||
}
|
||||
|
||||
function getGutter(n, isSelected, parent) {
|
||||
var span = $("<label>",{class:"red-ui-clipboard-dialog-import-conflicts-gutter"});
|
||||
var cb = $('<input data-node-id="'+n.id+'" type="checkbox" '+(isSelected?"checked":"")+'>').appendTo(span);
|
||||
|
||||
if (parent) {
|
||||
cb.attr("disabled",true);
|
||||
parent.addChild(cb);
|
||||
}
|
||||
span.on("click", function(evt) {
|
||||
evt.stopPropagation();
|
||||
})
|
||||
cb.on("change", function(evt) {
|
||||
var state = this.checked;
|
||||
span.parent().toggleClass("disabled",!!!state);
|
||||
span.parent().find('.red-ui-clipboard-dialog-import-conflicts-controls input[type="checkbox"]').attr("disabled",!!!state);
|
||||
childItems.forEach(function(c) {
|
||||
c.attr("checked",state);
|
||||
c.trigger("change");
|
||||
});
|
||||
})
|
||||
var childItems = [];
|
||||
|
||||
var checkbox = {
|
||||
addChild: function(c) {
|
||||
childItems.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
cb: checkbox,
|
||||
element: span
|
||||
}
|
||||
}
|
||||
|
||||
function getNodeLabelText(n) {
|
||||
var label = n.name || n.type+": "+n.id;
|
||||
if (n._def.label) {
|
||||
try {
|
||||
label = (typeof n._def.label === "function" ? n._def.label.call(n) : n._def.label)||"";
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+n.type+".label",err);
|
||||
}
|
||||
}
|
||||
var newlineIndex = label.indexOf("\\n");
|
||||
if (newlineIndex > -1) {
|
||||
label = label.substring(0,newlineIndex)+"...";
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
function getFlowLabel(n) {
|
||||
n = JSON.parse(JSON.stringify(n));
|
||||
n._def = RED.nodes.getType(n.type) || {};
|
||||
if (n._def) {
|
||||
n._ = n._def._;
|
||||
}
|
||||
|
||||
var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
|
||||
var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
|
||||
var label = (typeof n === "string")? n : n.label;
|
||||
var newlineIndex = label.indexOf("\\n");
|
||||
if (newlineIndex > -1) {
|
||||
label = label.substring(0,newlineIndex)+"...";
|
||||
}
|
||||
contentDiv.text(label);
|
||||
// A conflicted flow should not be imported by default.
|
||||
return div;
|
||||
}
|
||||
|
||||
function getNodeLabel(n, isConflicted) {
|
||||
n = JSON.parse(JSON.stringify(n));
|
||||
n._def = RED.nodes.getType(n.type) || {};
|
||||
if (n._def) {
|
||||
n._ = n._def._;
|
||||
}
|
||||
var div = $('<div>',{class:"red-ui-info-outline-item"});
|
||||
RED.utils.createNodeIcon(n).appendTo(div);
|
||||
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
||||
var labelText = getNodeLabelText(n);
|
||||
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
|
||||
if (labelText) {
|
||||
label.text(labelText)
|
||||
} else {
|
||||
label.html(n.type)
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
setupDialogs();
|
||||
|
||||
$('<input type="text" id="red-ui-clipboard-hidden" tabIndex="-1">').appendTo("#red-ui-editor");
|
||||
|
||||
RED.actions.add("core:show-export-dialog",exportNodes);
|
||||
RED.actions.add("core:show-import-dialog",importNodes);
|
||||
RED.actions.add("core:show-export-dialog",showExportNodes);
|
||||
RED.actions.add("core:show-import-dialog",showImportNodes);
|
||||
|
||||
RED.actions.add("core:show-library-export-dialog",function() { exportNodes('library') });
|
||||
RED.actions.add("core:show-library-import-dialog",function() { importNodes('library') });
|
||||
RED.actions.add("core:show-library-export-dialog",function() { showExportNodes('library') });
|
||||
RED.actions.add("core:show-library-import-dialog",function() { showImportNodes('library') });
|
||||
|
||||
RED.actions.add("core:show-examples-import-dialog",function() { importNodes('examples') });
|
||||
RED.actions.add("core:show-examples-import-dialog",function() { showImportNodes('examples') });
|
||||
|
||||
RED.events.on("editor:open",function() { disabled = true; });
|
||||
RED.events.on("editor:close",function() { disabled = false; });
|
||||
@@ -792,7 +1145,7 @@ RED.clipboard = (function() {
|
||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
||||
var data = event.originalEvent.dataTransfer.getData("text/plain");
|
||||
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
|
||||
RED.view.importNodes(data);
|
||||
importNodes(data);
|
||||
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
|
||||
var files = event.originalEvent.dataTransfer.files;
|
||||
if (files.length === 1) {
|
||||
@@ -800,7 +1153,7 @@ RED.clipboard = (function() {
|
||||
var reader = new FileReader();
|
||||
reader.onload = (function(theFile) {
|
||||
return function(e) {
|
||||
RED.view.importNodes(e.target.result);
|
||||
importNodes(e.target.result);
|
||||
};
|
||||
})(file);
|
||||
reader.readAsText(file);
|
||||
@@ -811,8 +1164,8 @@ RED.clipboard = (function() {
|
||||
});
|
||||
|
||||
},
|
||||
import: importNodes,
|
||||
export: exportNodes,
|
||||
import: showImportNodes,
|
||||
export: showExportNodes,
|
||||
copyText: copyText
|
||||
}
|
||||
})();
|
||||
|
@@ -27,26 +27,26 @@
|
||||
this.partialFlag = false;
|
||||
this.stateValue = 0;
|
||||
var initialState = this.element.prop('checked');
|
||||
this.options = [
|
||||
this.states = [
|
||||
$('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-square-o"></i></span>').appendTo(this.uiElement),
|
||||
$('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-check-square-o"></i></span>').appendTo(this.uiElement),
|
||||
$('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-minus-square-o"></i></span>').appendTo(this.uiElement)
|
||||
];
|
||||
if (initialState) {
|
||||
this.options[1].show();
|
||||
this.states[1].show();
|
||||
} else {
|
||||
this.options[0].show();
|
||||
this.states[0].show();
|
||||
}
|
||||
|
||||
this.element.on("change", function() {
|
||||
if (this.checked) {
|
||||
that.options[0].hide();
|
||||
that.options[1].show();
|
||||
that.options[2].hide();
|
||||
that.states[0].hide();
|
||||
that.states[1].show();
|
||||
that.states[2].hide();
|
||||
} else {
|
||||
that.options[1].hide();
|
||||
that.options[0].show();
|
||||
that.options[2].hide();
|
||||
that.states[1].hide();
|
||||
that.states[0].show();
|
||||
that.states[2].hide();
|
||||
}
|
||||
var isChecked = this.checked;
|
||||
that.children.forEach(function(child) {
|
||||
@@ -106,17 +106,17 @@
|
||||
var trueState = this.partialFlag||state;
|
||||
this.element.prop('checked',trueState);
|
||||
if (state === true) {
|
||||
this.options[0].hide();
|
||||
this.options[1].show();
|
||||
this.options[2].hide();
|
||||
this.states[0].hide();
|
||||
this.states[1].show();
|
||||
this.states[2].hide();
|
||||
} else if (state === false) {
|
||||
this.options[2].hide();
|
||||
this.options[1].hide();
|
||||
this.options[0].show();
|
||||
this.states[2].hide();
|
||||
this.states[1].hide();
|
||||
this.states[0].show();
|
||||
} else if (state === null) {
|
||||
this.options[0].hide();
|
||||
this.options[1].hide();
|
||||
this.options[2].show();
|
||||
this.states[0].hide();
|
||||
this.states[1].hide();
|
||||
this.states[2].show();
|
||||
}
|
||||
if (!suppressEvent) {
|
||||
this.element.trigger('change',null);
|
||||
|
@@ -91,6 +91,9 @@
|
||||
if (v!=="auto" && v!=="") {
|
||||
that.topContainer.css(s,v);
|
||||
that.uiContainer.css(s,"0");
|
||||
if (s === "top" && that.options.header) {
|
||||
that.uiContainer.css(s,"20px")
|
||||
}
|
||||
that.element.css(s,'auto');
|
||||
}
|
||||
})
|
||||
|
@@ -84,6 +84,7 @@ RED.popover = (function() {
|
||||
var targetHeight = target.outerHeight();
|
||||
var divHeight = div.height();
|
||||
var divWidth = div.width();
|
||||
var paddingRight = 10;
|
||||
|
||||
var viewportTop = $(window).scrollTop();
|
||||
var viewportLeft = $(window).scrollLeft();
|
||||
@@ -105,7 +106,7 @@ RED.popover = (function() {
|
||||
d = "right";
|
||||
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
|
||||
left = targetPos.left+targetWidth+deltaSizes[size].leftRight;
|
||||
} else if (left+divWidth > viewportRight) {
|
||||
} else if (left+divWidth+paddingRight > viewportRight) {
|
||||
d = "left";
|
||||
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
|
||||
left = targetPos.left-deltaSizes[size].leftLeft-divWidth;
|
||||
|
@@ -119,6 +119,9 @@
|
||||
if (evt.keyCode === 27) {
|
||||
that.element.val("");
|
||||
}
|
||||
if (evt.keyCode === 13) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
})
|
||||
this.element.on("keyup",function(evt) {
|
||||
that._change($(this).val());
|
||||
|
@@ -29,7 +29,7 @@ RED.tabs = (function() {
|
||||
var currentTabWidth;
|
||||
var currentActiveTabWidth = 0;
|
||||
var collapsibleMenu;
|
||||
|
||||
var preferredOrder = options.order;
|
||||
var ul = options.element || $("#"+options.id);
|
||||
var wrapper = ul.wrap( "<div>" ).parent();
|
||||
var scrollContainer = ul.wrap( "<div>" ).parent();
|
||||
@@ -132,11 +132,11 @@ RED.tabs = (function() {
|
||||
activateTab(id);
|
||||
}
|
||||
};
|
||||
if (tabs[id].pinned) {
|
||||
pinnedOptions.push(opt);
|
||||
} else {
|
||||
// if (tabs[id].pinned) {
|
||||
// pinnedOptions.push(opt);
|
||||
// } else {
|
||||
options.push(opt);
|
||||
}
|
||||
// }
|
||||
});
|
||||
options = pinnedOptions.concat(options);
|
||||
collapsibleMenu = RED.menu.init({options: options});
|
||||
@@ -363,23 +363,39 @@ RED.tabs = (function() {
|
||||
var tabWidth;
|
||||
|
||||
if (options.collapsible) {
|
||||
var availableCount = collapsedButtonsRow.children().length;
|
||||
var visibleCount = collapsedButtonsRow.children(":visible").length;
|
||||
tabWidth = width - collapsedButtonsRow.width()-10;
|
||||
if (tabWidth < 198) {
|
||||
var delta = 198 - tabWidth;
|
||||
var maxTabWidth = 198;
|
||||
var minTabWidth = 80;
|
||||
if (tabWidth <= minTabWidth || (tabWidth < maxTabWidth && visibleCount > 5)) {
|
||||
// The tab is too small. Hide the next button to make room
|
||||
// Start at the end of the button row, -1 for the menu button
|
||||
var b = collapsedButtonsRow.find("a:last").prev();
|
||||
var index = collapsedButtonsRow.children().length - 2;
|
||||
// Work backwards to find the first visible button
|
||||
while (b.is(":not(:visible)")) {
|
||||
b = b.prev();
|
||||
index--;
|
||||
}
|
||||
if (!b.hasClass("red-ui-tab-link-button-pinned")) {
|
||||
// If it isn't a pinned button, hide it to get the room
|
||||
if (tabWidth <= minTabWidth || visibleCount>6) {//}!b.hasClass("red-ui-tab-link-button-pinned")) {
|
||||
b.hide();
|
||||
}
|
||||
tabWidth = width - collapsedButtonsRow.width()-10;
|
||||
tabWidth = Math.max(minTabWidth,width - collapsedButtonsRow.width()-10);
|
||||
} else {
|
||||
var space = width - 198 - collapsedButtonsRow.width();
|
||||
if (visibleCount !== availableCount) {
|
||||
if (visibleCount < 6) {
|
||||
tabWidth = minTabWidth;
|
||||
} else {
|
||||
tabWidth = maxTabWidth;
|
||||
}
|
||||
}
|
||||
var space = width - tabWidth - collapsedButtonsRow.width();
|
||||
if (space > 40) {
|
||||
collapsedButtonsRow.find("a:not(:visible):first").show();
|
||||
tabWidth = width - collapsedButtonsRow.width()-10;
|
||||
}
|
||||
tabWidth = width - collapsedButtonsRow.width()-10;
|
||||
}
|
||||
tabs.css({width:tabWidth});
|
||||
|
||||
@@ -469,7 +485,7 @@ RED.tabs = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
var tabAPI = {
|
||||
addTab: function(tab,targetIndex) {
|
||||
if (options.onselect) {
|
||||
var selection = ul.find("li.red-ui-tab.selected");
|
||||
@@ -531,11 +547,93 @@ RED.tabs = (function() {
|
||||
evt.preventDefault();
|
||||
activateTab(tab.id);
|
||||
});
|
||||
pinnedLink.data("tabId",tab.id)
|
||||
if (tab.pinned) {
|
||||
pinnedLink.addClass("red-ui-tab-link-button-pinned");
|
||||
pinnedTabsCount++;
|
||||
}
|
||||
RED.popover.tooltip($(pinnedLink), tab.name, tab.action);
|
||||
if (options.onreorder) {
|
||||
var pinnedLinkIndex;
|
||||
var pinnedLinks = [];
|
||||
var startPinnedIndex;
|
||||
pinnedLink.draggable({
|
||||
distance: 10,
|
||||
axis:"x",
|
||||
containment: ".red-ui-tab-link-buttons",
|
||||
start: function(event,ui) {
|
||||
dragActive = true;
|
||||
$(".red-ui-tab-link-buttons").width($(".red-ui-tab-link-buttons").width());
|
||||
if (dblClickArmed) { dblClickArmed = false; return false }
|
||||
collapsedButtonsRow.children().each(function(i) {
|
||||
pinnedLinks[i] = {
|
||||
el:$(this),
|
||||
text: $(this).text(),
|
||||
left: $(this).position().left,
|
||||
width: $(this).width(),
|
||||
menu: $(this).hasClass("red-ui-tab-link-button-menu")
|
||||
};
|
||||
if ($(this).is(pinnedLink)) {
|
||||
pinnedLinkIndex = i;
|
||||
startPinnedIndex = i;
|
||||
}
|
||||
});
|
||||
collapsedButtonsRow.children().each(function(i) {
|
||||
if (i!==pinnedLinkIndex) {
|
||||
$(this).css({
|
||||
position: 'absolute',
|
||||
left: pinnedLinks[i].left+"px",
|
||||
width: pinnedLinks[i].width+2,
|
||||
transition: "left 0.3s"
|
||||
});
|
||||
}
|
||||
})
|
||||
if (!pinnedLink.hasClass('active')) {
|
||||
pinnedLink.css({'zIndex':1});
|
||||
}
|
||||
},
|
||||
drag: function(event,ui) {
|
||||
ui.position.left += pinnedLinks[pinnedLinkIndex].left;
|
||||
var tabCenter = ui.position.left + pinnedLinks[pinnedLinkIndex].width/2;
|
||||
for (var i=0;i<pinnedLinks.length;i++) {
|
||||
if (i === pinnedLinkIndex || pinnedLinks[i].menu || pinnedLinks[i].el.is(":not(:visible)")) {
|
||||
continue;
|
||||
}
|
||||
if (tabCenter > pinnedLinks[i].left && tabCenter < pinnedLinks[i].left+pinnedLinks[i].width) {
|
||||
if (i < pinnedLinkIndex) {
|
||||
pinnedLinks[i].left += pinnedLinks[pinnedLinkIndex].width+8;
|
||||
pinnedLinks[pinnedLinkIndex].el.detach().insertBefore(pinnedLinks[i].el);
|
||||
} else {
|
||||
pinnedLinks[i].left -= pinnedLinks[pinnedLinkIndex].width+8;
|
||||
pinnedLinks[pinnedLinkIndex].el.detach().insertAfter(pinnedLinks[i].el);
|
||||
}
|
||||
pinnedLinks[i].el.css({left:pinnedLinks[i].left+"px"});
|
||||
|
||||
pinnedLinks.splice(i, 0, pinnedLinks.splice(pinnedLinkIndex, 1)[0]);
|
||||
|
||||
pinnedLinkIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
stop: function(event,ui) {
|
||||
dragActive = false;
|
||||
collapsedButtonsRow.children().css({position:"relative",left:"",transition:""});
|
||||
$(".red-ui-tab-link-buttons").width('auto');
|
||||
pinnedLink.css({zIndex:""});
|
||||
updateTabWidths();
|
||||
if (startPinnedIndex !== pinnedLinkIndex) {
|
||||
if (collapsibleMenu) {
|
||||
collapsibleMenu.remove();
|
||||
collapsibleMenu = null;
|
||||
}
|
||||
var newOrder = $.makeArray(collapsedButtonsRow.children().map(function() { return $(this).data('tabId');}));
|
||||
tabAPI.order(newOrder);
|
||||
options.onreorder(newOrder);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
link.on("mouseup",onTabClick);
|
||||
@@ -565,7 +663,7 @@ RED.tabs = (function() {
|
||||
if (ul.find("li.red-ui-tab").length == 1) {
|
||||
activateTab(link);
|
||||
}
|
||||
if (options.onreorder) {
|
||||
if (options.onreorder && !options.collapsible) {
|
||||
var originalTabOrder;
|
||||
var tabDragIndex;
|
||||
var tabElements = [];
|
||||
@@ -652,6 +750,9 @@ RED.tabs = (function() {
|
||||
collapsibleMenu.remove();
|
||||
collapsibleMenu = null;
|
||||
}
|
||||
if (preferredOrder) {
|
||||
tabAPI.order(preferredOrder);
|
||||
}
|
||||
},
|
||||
removeTab: removeTab,
|
||||
activateTab: activateTab,
|
||||
@@ -673,10 +774,8 @@ RED.tabs = (function() {
|
||||
},
|
||||
selection: getSelection,
|
||||
order: function(order) {
|
||||
preferredOrder = order;
|
||||
var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));
|
||||
if (existingTabOrder.length !== order.length) {
|
||||
return
|
||||
}
|
||||
var i;
|
||||
var match = true;
|
||||
for (i=0;i<order.length;i++) {
|
||||
@@ -692,12 +791,41 @@ RED.tabs = (function() {
|
||||
var existingTabs = ul.children().detach().each(function() {
|
||||
existingTabMap[$(this).data("tabId")] = $(this);
|
||||
});
|
||||
var pinnedButtons = {};
|
||||
if (options.collapsible) {
|
||||
collapsedButtonsRow.children().detach().each(function() {
|
||||
var id = $(this).data("tabId");
|
||||
if (!id) {
|
||||
id = "__menu__"
|
||||
}
|
||||
pinnedButtons[id] = $(this);
|
||||
});
|
||||
}
|
||||
for (i=0;i<order.length;i++) {
|
||||
existingTabMap[order[i]].appendTo(ul);
|
||||
if (existingTabMap[order[i]]) {
|
||||
existingTabMap[order[i]].appendTo(ul);
|
||||
if (options.collapsible) {
|
||||
pinnedButtons[order[i]].appendTo(collapsedButtonsRow);
|
||||
}
|
||||
delete existingTabMap[order[i]];
|
||||
}
|
||||
}
|
||||
// Add any tabs that aren't known in the order
|
||||
for (i in existingTabMap) {
|
||||
if (existingTabMap.hasOwnProperty(i)) {
|
||||
existingTabMap[i].appendTo(ul);
|
||||
if (options.collapsible) {
|
||||
pinnedButtons[i].appendTo(collapsedButtonsRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (options.collapsible) {
|
||||
pinnedButtons["__menu__"].appendTo(collapsedButtonsRow);
|
||||
updateTabWidths();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return tabAPI;
|
||||
}
|
||||
|
||||
return {
|
||||
|
@@ -37,8 +37,8 @@
|
||||
invertState = this.options.invertState;
|
||||
}
|
||||
var baseClass = this.options.baseClass || "red-ui-button";
|
||||
var enabledIcon = this.options.enabledIcon || "fa-check-square-o";
|
||||
var disabledIcon = this.options.disabledIcon || "fa-square-o";
|
||||
var enabledIcon = this.options.hasOwnProperty('enabledIcon')?this.options.enabledIcon : "fa-check-square-o";
|
||||
var disabledIcon = this.options.hasOwnProperty('disabledIcon')?this.options.disabledIcon : "fa-square-o";
|
||||
var enabledLabel = this.options.hasOwnProperty('enabledLabel') ? this.options.enabledLabel : RED._("editor:workspace.enabled");
|
||||
var disabledLabel = this.options.hasOwnProperty('disabledLabel') ? this.options.disabledLabel : RED._("editor:workspace.disabled");
|
||||
|
||||
@@ -46,25 +46,41 @@
|
||||
this.element.on("focus", function() {
|
||||
that.button.focus();
|
||||
});
|
||||
this.button = $('<button type="button" class="red-ui-toggleButton '+baseClass+' toggle single"><i class="fa"></i> <span></span></button>');
|
||||
this.button = $('<button type="button" class="red-ui-toggleButton '+baseClass+' toggle single"></button>');
|
||||
if (enabledLabel || disabledLabel) {
|
||||
this.buttonLabel = $("<span>").appendTo(this.button);
|
||||
}
|
||||
|
||||
if (this.options.class) {
|
||||
this.button.addClass(this.options.class)
|
||||
}
|
||||
this.element.after(this.button);
|
||||
this.buttonIcon = this.button.find("i");
|
||||
this.buttonLabel = this.button.find("span");
|
||||
|
||||
if (enabledIcon && disabledIcon) {
|
||||
this.buttonIcon = $('<i class="fa"></i>').prependTo(this.button);
|
||||
}
|
||||
|
||||
// Quick hack to find the maximum width of the button
|
||||
this.button.addClass("selected");
|
||||
this.buttonIcon.addClass(enabledIcon);
|
||||
this.buttonLabel.text(enabledLabel);
|
||||
if (this.buttonIcon) {
|
||||
this.buttonIcon.addClass(enabledIcon);
|
||||
}
|
||||
if (this.buttonLabel) {
|
||||
this.buttonLabel.text(enabledLabel);
|
||||
}
|
||||
var width = this.button.width();
|
||||
this.button.removeClass("selected");
|
||||
this.buttonIcon.removeClass(enabledIcon);
|
||||
that.buttonIcon.addClass(disabledIcon);
|
||||
that.buttonLabel.text(disabledLabel);
|
||||
if (this.buttonIcon) {
|
||||
this.buttonIcon.removeClass(enabledIcon);
|
||||
that.buttonIcon.addClass(disabledIcon);
|
||||
}
|
||||
if (this.buttonLabel) {
|
||||
that.buttonLabel.text(disabledLabel);
|
||||
}
|
||||
width = Math.max(width,this.button.width());
|
||||
this.buttonIcon.removeClass(disabledIcon);
|
||||
if (this.buttonIcon) {
|
||||
this.buttonIcon.removeClass(disabledIcon);
|
||||
}
|
||||
|
||||
// Fix the width of the button so it doesn't jump around when toggled
|
||||
if (width > 0) {
|
||||
@@ -73,7 +89,7 @@
|
||||
|
||||
this.button.on("click",function(e) {
|
||||
e.stopPropagation();
|
||||
if (that.buttonIcon.hasClass(disabledIcon)) {
|
||||
if (!that.state) {
|
||||
that.element.prop("checked",!invertState);
|
||||
} else {
|
||||
that.element.prop("checked",invertState);
|
||||
@@ -84,14 +100,24 @@
|
||||
this.element.on("change", function(e) {
|
||||
if ($(this).prop("checked") !== invertState) {
|
||||
that.button.addClass("selected");
|
||||
that.buttonIcon.addClass(enabledIcon);
|
||||
that.buttonIcon.removeClass(disabledIcon);
|
||||
that.buttonLabel.text(enabledLabel);
|
||||
that.state = true;
|
||||
if (that.buttonIcon) {
|
||||
that.buttonIcon.addClass(enabledIcon);
|
||||
that.buttonIcon.removeClass(disabledIcon);
|
||||
}
|
||||
if (that.buttonLabel) {
|
||||
that.buttonLabel.text(enabledLabel);
|
||||
}
|
||||
} else {
|
||||
that.button.removeClass("selected");
|
||||
that.buttonIcon.addClass(disabledIcon);
|
||||
that.buttonIcon.removeClass(enabledIcon);
|
||||
that.buttonLabel.text(disabledLabel);
|
||||
that.state = false;
|
||||
if (that.buttonIcon) {
|
||||
that.buttonIcon.addClass(disabledIcon);
|
||||
that.buttonIcon.removeClass(enabledIcon);
|
||||
}
|
||||
if (that.buttonLabel) {
|
||||
that.buttonLabel.text(disabledLabel);
|
||||
}
|
||||
}
|
||||
})
|
||||
this.element.trigger("change");
|
||||
|
@@ -167,7 +167,7 @@
|
||||
this._selected = new Set();
|
||||
this._topList = $('<ol class="red-ui-treeList-list">').css({
|
||||
position:'absolute',
|
||||
top: 0,
|
||||
top:0,
|
||||
left:0,
|
||||
right:0,
|
||||
bottom:0
|
||||
@@ -181,6 +181,9 @@
|
||||
that._addSubtree(that._topList,container,item,0);
|
||||
}
|
||||
};
|
||||
if (this.options.header) {
|
||||
topListOptions.header = this.options.header;
|
||||
}
|
||||
if (this.options.rootSortable !== false && !!this.options.sortable) {
|
||||
topListOptions.sortable = this.options.sortable;
|
||||
topListOptions.connectWith = '.red-ui-treeList-sortable';
|
||||
|
@@ -173,6 +173,7 @@
|
||||
valueLabel: function(container,value) {
|
||||
var that = this;
|
||||
container.css("pointer-events","none");
|
||||
container.css("flex-grow",0);
|
||||
this.elementDiv.hide();
|
||||
var buttons = $('<div>').css({
|
||||
position: "absolute",
|
||||
@@ -184,22 +185,25 @@
|
||||
width:"20px"
|
||||
}).appendTo(buttons).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var cursorPosition = that.input[0].selectionStart;
|
||||
var currentType = that.input.attr("type");
|
||||
if (currentType === "text") {
|
||||
that.input.attr("type","password");
|
||||
eyeCon.removeClass("fa-eye-slash").addClass("fa-eye");
|
||||
setTimeout(function() {
|
||||
that.input.focus();
|
||||
that.input[0].setSelectionRange(cursorPosition, cursorPosition);
|
||||
},50);
|
||||
} else {
|
||||
that.input.attr("type","text");
|
||||
eyeCon.removeClass("fa-eye").addClass("fa-eye-slash");
|
||||
setTimeout(function() {
|
||||
that.input.focus();
|
||||
that.input[0].setSelectionRange(cursorPosition, cursorPosition);
|
||||
},50);
|
||||
}
|
||||
}).hide();
|
||||
var eyeCon = $('<i class="fa fa-eye"></i>').css("margin-left","-1px").appendTo(eyeButton);
|
||||
var eyeCon = $('<i class="fa fa-eye"></i>').css("margin-left","-2px").appendTo(eyeButton);
|
||||
|
||||
if (value === "__PWRD__") {
|
||||
var innerContainer = $('<div><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i></div>').css({
|
||||
@@ -284,7 +288,7 @@
|
||||
this.input.css('width','100%');
|
||||
this.uiSelect.width(m[1]);
|
||||
this.uiWidth = null;
|
||||
} else {
|
||||
} else if (this.uiWidth !== 0){
|
||||
this.uiSelect.width(this.uiWidth);
|
||||
}
|
||||
["Right","Left"].forEach(function(d) {
|
||||
@@ -304,7 +308,11 @@
|
||||
|
||||
this.element.attr('type','hidden');
|
||||
|
||||
this.options.types = this.options.types||Object.keys(allOptions);
|
||||
if (!this.options.types && this.options.type) {
|
||||
this.options.types = [this.options.type]
|
||||
} else {
|
||||
this.options.types = this.options.types||Object.keys(allOptions);
|
||||
}
|
||||
|
||||
this.selectTrigger = $('<button class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect);
|
||||
$('<i class="red-ui-typedInput-icon fa fa-caret-down"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger);
|
||||
@@ -872,6 +880,9 @@
|
||||
this.elementDiv.hide();
|
||||
this.valueLabelContainer.hide();
|
||||
} else if (opt.valueLabel) {
|
||||
// Reset any CSS the custom label may have set
|
||||
this.valueLabelContainer.css("pointer-events","");
|
||||
this.valueLabelContainer.css("flex-grow",1);
|
||||
this.valueLabelContainer.show();
|
||||
this.valueLabelContainer.empty();
|
||||
this.elementDiv.hide();
|
||||
|
@@ -1411,7 +1411,7 @@ RED.diff = (function() {
|
||||
// Restore the original flow so subsequent merge resolutions can properly
|
||||
// identify new-vs-old
|
||||
RED.nodes.originalFlow(originalFlow);
|
||||
imported[0].forEach(function(n) {
|
||||
imported.nodes.forEach(function(n) {
|
||||
if (nodeChangedStates[n.id] || localChangedStates[n.id]) {
|
||||
n.changed = true;
|
||||
}
|
||||
|
@@ -2724,7 +2724,7 @@ RED.editor = (function() {
|
||||
if (options.globals) {
|
||||
setTimeout(function() {
|
||||
if (!!session.$worker) {
|
||||
session.$worker.send("setOptions", [{globals: options.globals, esversion:6, sub:true, asi:true, maxerr:1000}]);
|
||||
session.$worker.send("setOptions", [{globals: options.globals, maxerr:1000}]);
|
||||
}
|
||||
},100);
|
||||
}
|
||||
@@ -2788,7 +2788,13 @@ RED.editor = (function() {
|
||||
editExpression: function(options) { showTypeEditor("_expression", options) },
|
||||
editJSON: function(options) { showTypeEditor("_json", options) },
|
||||
editMarkdown: function(options) { showTypeEditor("_markdown", options) },
|
||||
editText: function(options) { showTypeEditor("_text", options) },
|
||||
editText: function(options) {
|
||||
if (options.mode == "markdown") {
|
||||
showTypeEditor("_markdown", options)
|
||||
} else {
|
||||
showTypeEditor("_text", options)
|
||||
}
|
||||
},
|
||||
editBuffer: function(options) { showTypeEditor("_buffer", options) },
|
||||
buildEditForm: buildEditForm,
|
||||
validateNode: validateNode,
|
||||
|
@@ -247,6 +247,7 @@ RED.group = (function() {
|
||||
var groupStyleClipboard;
|
||||
|
||||
function copyGroupStyle() {
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].type === 'group') {
|
||||
groupStyleClipboard = JSON.parse(JSON.stringify(selection.nodes[0].style));
|
||||
@@ -254,6 +255,7 @@ RED.group = (function() {
|
||||
}
|
||||
}
|
||||
function pasteGroupStyle() {
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
if (groupStyleClipboard) {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
@@ -287,6 +289,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
function groupSelection() {
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var group = createGroup(selection.nodes);
|
||||
@@ -303,6 +306,7 @@ RED.group = (function() {
|
||||
}
|
||||
}
|
||||
function ungroupSelection() {
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var newSelection = [];
|
||||
@@ -351,8 +355,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
function mergeSelection() {
|
||||
// TODO: this currently creates an entirely new group. Need to merge properties
|
||||
// of any existing group
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var nodes = [];
|
||||
@@ -380,11 +383,16 @@ RED.group = (function() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var existingGroup;
|
||||
|
||||
// Second pass, ungroup any groups in the selection and add their contents
|
||||
// to the selection
|
||||
for (var i=0; i<selection.nodes.length; i++) {
|
||||
n = selection.nodes[i];
|
||||
if (n.type === "group") {
|
||||
if (!existingGroup) {
|
||||
existingGroup = n;
|
||||
}
|
||||
ungroupHistoryEvent.groups.push(n);
|
||||
nodes = nodes.concat(ungroup(n));
|
||||
} else {
|
||||
@@ -398,6 +406,10 @@ RED.group = (function() {
|
||||
// Finally, create the new group
|
||||
var group = createGroup(nodes);
|
||||
if (group) {
|
||||
if (existingGroup) {
|
||||
group.style = existingGroup.style;
|
||||
group.name = existingGroup.name;
|
||||
}
|
||||
RED.view.select({nodes:[group]})
|
||||
}
|
||||
historyEvent.events.push({
|
||||
@@ -411,6 +423,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
function removeSelection() {
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var nodes = [];
|
||||
|
@@ -70,6 +70,11 @@ RED.keyboard = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
function getUserKey(action) {
|
||||
var currentEditorSettings = RED.settings.get('editor') || {};
|
||||
var userKeymap = currentEditorSettings.keymap || {};
|
||||
return userKeymap[action];
|
||||
}
|
||||
function init() {
|
||||
// Migrate from pre-0.18
|
||||
migrateOldKeymap();
|
||||
@@ -255,6 +260,19 @@ RED.keyboard = (function() {
|
||||
var i=0;
|
||||
if (typeof key === 'string') {
|
||||
if (typeof cbdown === 'string') {
|
||||
if (!ondown && !defaultKeyMap.hasOwnProperty(cbdown)) {
|
||||
defaultKeyMap[cbdown] = {
|
||||
scope:scope,
|
||||
key:key,
|
||||
user:false
|
||||
}
|
||||
}
|
||||
if (!ondown) {
|
||||
var userAction = getUserKey(cbdown);
|
||||
if (userAction) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
actionToKeyMap[cbdown] = {scope:scope,key:key};
|
||||
if (typeof ondown === 'boolean') {
|
||||
actionToKeyMap[cbdown].user = ondown;
|
||||
@@ -417,11 +435,9 @@ RED.keyboard = (function() {
|
||||
});
|
||||
revertButton.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
RED.keyboard.revertToDefault(object.id);
|
||||
container.empty();
|
||||
container.removeClass('keyboard-shortcut-entry-expanded');
|
||||
var shortcut = RED.keyboard.getShortcut(object.id);
|
||||
var userKeymap = RED.settings.get('keymap') || {};
|
||||
// var userKeymap = RED.settings.get('keymap') || {};
|
||||
|
||||
var currentEditorSettings = RED.settings.get('editor') || {};
|
||||
var userKeymap = currentEditorSettings.keymap || {};
|
||||
@@ -429,6 +445,9 @@ RED.keyboard = (function() {
|
||||
currentEditorSettings.keymap = userKeymap;
|
||||
RED.settings.set('editor',currentEditorSettings);
|
||||
|
||||
RED.keyboard.revertToDefault(object.id);
|
||||
|
||||
var shortcut = RED.keyboard.getShortcut(object.id);
|
||||
var obj = {
|
||||
id:object.id,
|
||||
scope:shortcut?shortcut.scope:undefined,
|
||||
@@ -589,6 +608,7 @@ RED.keyboard = (function() {
|
||||
getShortcut: function(actionName) {
|
||||
return actionToKeyMap[actionName];
|
||||
},
|
||||
getUserShortcut: getUserKey,
|
||||
revertToDefault: revertToDefault,
|
||||
formatKey: formatKey,
|
||||
validateKey: validateKey,
|
||||
|
@@ -542,8 +542,6 @@ RED.palette.editor = (function() {
|
||||
return settingsPane;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function createSettingsPane() {
|
||||
settingsPane = $('<div id="red-ui-settings-tab-palette"></div>');
|
||||
var content = $('<div id="red-ui-palette-editor">'+
|
||||
@@ -574,7 +572,11 @@ RED.palette.editor = (function() {
|
||||
minimumActiveTabWidth: 110
|
||||
});
|
||||
|
||||
createNodeTab(content);
|
||||
createInstallTab(content);
|
||||
}
|
||||
|
||||
function createNodeTab(content) {
|
||||
var modulesTab = $('<div>',{class:"red-ui-palette-editor-tab"}).appendTo(content);
|
||||
|
||||
editorTabs.addTab({
|
||||
@@ -726,9 +728,9 @@ RED.palette.editor = (function() {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function createInstallTab(content) {
|
||||
var installTab = $('<div>',{class:"red-ui-palette-editor-tab hide"}).appendTo(content);
|
||||
|
||||
editorTabs.addTab({
|
||||
@@ -761,7 +763,6 @@ RED.palette.editor = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('<span>').text(RED._("palette.editor.sort")+' ').appendTo(toolBar);
|
||||
var sortGroup = $('<span class="button-group"></span>').appendTo(toolBar);
|
||||
var sortRelevance = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle selected"><i class="fa fa-sort-amount-desc"></i></a>').appendTo(sortGroup);
|
||||
@@ -795,6 +796,7 @@ RED.palette.editor = (function() {
|
||||
loadedIndex = {};
|
||||
initInstallTab();
|
||||
})
|
||||
RED.popover.tooltip(refreshButton,RED._("palette.editor.refresh"));
|
||||
|
||||
packageList = $('<ol>',{style:"position: absolute;top: 79px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({
|
||||
addButton: false,
|
||||
@@ -878,8 +880,87 @@ RED.palette.editor = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
if (RED.settings.theme('palette.upload') !== false) {
|
||||
var uploadSpan = $('<span class="button-group">').prependTo(toolBar);
|
||||
var uploadButton = $('<button type="button" class="red-ui-sidebar-header-button red-ui-palette-editor-upload-button"><label><i class="fa fa-upload"></i><form id="red-ui-palette-editor-upload-form" enctype="multipart/form-data"><input name="tarball" type="file" accept=".tgz"></label></button>').appendTo(uploadSpan);
|
||||
|
||||
var uploadInput = uploadButton.find('input[type="file"]');
|
||||
uploadInput.on("change", function(evt) {
|
||||
if (this.files.length > 0) {
|
||||
uploadFilenameLabel.text(this.files[0].name)
|
||||
uploadToolbar.slideDown(200);
|
||||
}
|
||||
})
|
||||
|
||||
var uploadToolbar = $('<div class="red-ui-palette-editor-upload"></div>').appendTo(installTab);
|
||||
var uploadForm = $('<div>').appendTo(uploadToolbar);
|
||||
var uploadFilename = $('<div class="placeholder-input"><i class="fa fa-upload"></i> </div>').appendTo(uploadForm);
|
||||
var uploadFilenameLabel = $('<span></span>').appendTo(uploadFilename);
|
||||
var uploadButtons = $('<div class="red-ui-palette-editor-upload-buttons"></div>').appendTo(uploadForm);
|
||||
$('<button class="editor-button"></button>').text(RED._("common.label.cancel")).appendTo(uploadButtons).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
uploadToolbar.slideUp(200);
|
||||
uploadInput.val("");
|
||||
});
|
||||
$('<button class="editor-button primary"></button>').text(RED._("common.label.upload")).appendTo(uploadButtons).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
var spinner = RED.utils.addSpinnerOverlay(uploadToolbar, true);
|
||||
var buttonRow = $('<div style="position: relative;bottom: calc(50% + 17px); padding-right: 10px;text-align: right;"></div>').appendTo(spinner);
|
||||
$('<button class="red-ui-button"></button>').text(RED._("eventLog.view")).appendTo(buttonRow).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
RED.actions.invoke("core:show-event-log");
|
||||
});
|
||||
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+uploadInput[0].files[0].name);
|
||||
|
||||
var data = new FormData();
|
||||
data.append("tarball",uploadInput[0].files[0]);
|
||||
var filename = uploadInput[0].files[0].name;
|
||||
$.ajax({
|
||||
url: 'nodes',
|
||||
data: data,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
method: 'POST',
|
||||
}).always(function(data,textStatus,xhr) {
|
||||
spinner.remove();
|
||||
uploadInput.val("");
|
||||
uploadToolbar.slideUp(200);
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
var message = textStatus;
|
||||
if (xhr.responseJSON) {
|
||||
message = xhr.responseJSON.message;
|
||||
}
|
||||
var notification = RED.notify(RED._('palette.editor.errors.installFailed',{module: filename,message:message}),{
|
||||
type: 'error',
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
}
|
||||
},{
|
||||
text: RED._("eventLog.view"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
RED.actions.invoke("core:show-event-log");
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
uploadInput.val("");
|
||||
uploadToolbar.slideUp(200);
|
||||
})
|
||||
})
|
||||
RED.popover.tooltip(uploadButton,RED._("palette.editor.upload"));
|
||||
}
|
||||
|
||||
$('<div id="red-ui-palette-module-install-shade" class="red-ui-palette-module-shade hide"><div class="red-ui-palette-module-shade-status"></div><img src="red/images/spin.svg" class="red-ui-palette-spinner"/></div>').appendTo(installTab);
|
||||
}
|
||||
|
||||
function update(entry,version,url,container,done) {
|
||||
if (RED.settings.theme('palette.editable') === false) {
|
||||
done(new Error('Palette not editable'));
|
||||
|
@@ -166,34 +166,42 @@ RED.projects.settings = (function() {
|
||||
description.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
|
||||
}
|
||||
|
||||
function editSummary(activeProject, summary, container) {
|
||||
function editSummary(activeProject, summary, container, version, versionContainer) {
|
||||
var editButton = container.prev();
|
||||
editButton.hide();
|
||||
container.empty();
|
||||
versionContainer.empty();
|
||||
var bg = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').appendTo(container);
|
||||
var input = $('<input type="text" style="width: calc(100% - 150px); margin-right: 10px;">').val(summary||"").appendTo(container);
|
||||
var versionInput = $('<input type="text" style="width: calc(100% - 150px); margin-right: 10px;">').val(version||"").appendTo(versionContainer);
|
||||
|
||||
$('<button class="red-ui-button">' + RED._("common.label.cancel") + '</button>')
|
||||
.appendTo(bg)
|
||||
.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
updateProjectSummary(activeProject.summary, container);
|
||||
updateProjectVersion(activeProject.version, versionContainer);
|
||||
editButton.show();
|
||||
});
|
||||
$('<button class="red-ui-button">' + RED._("common.label.save") + '</button>')
|
||||
.appendTo(bg)
|
||||
.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var v = input.val();
|
||||
updateProjectSummary(v, container);
|
||||
var spinner = utils.addSpinnerOverlay(container);
|
||||
var newSummary = input.val();
|
||||
var newVersion = versionInput.val();
|
||||
updateProjectSummary(newSummary, container);
|
||||
updateProjectVersion(newVersion, versionContainer);
|
||||
var spinner = utils.addSpinnerOverlay(container).addClass('red-ui-component-spinner-contain');
|
||||
var done = function(err,res) {
|
||||
if (err) {
|
||||
spinner.remove();
|
||||
return editSummary(activeProject, summary, container);
|
||||
return editSummary(activeProject, summary, container, version, versionContainer);
|
||||
}
|
||||
activeProject.summary = v;
|
||||
activeProject.summary = newSummary;
|
||||
activeProject.version = newVersion;
|
||||
spinner.remove();
|
||||
updateProjectSummary(activeProject.summary, container);
|
||||
updateProjectVersion(activeProject.version, versionContainer);
|
||||
editButton.show();
|
||||
}
|
||||
utils.sendRequest({
|
||||
@@ -214,31 +222,39 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
},
|
||||
}
|
||||
},{summary:v});
|
||||
},{summary:newSummary, version: newVersion});
|
||||
});
|
||||
}
|
||||
function updateProjectSummary(summary, container) {
|
||||
container.empty();
|
||||
if (summary) {
|
||||
container.text(summary).removeClass('node-info-node');
|
||||
container.text(summary).removeClass('red-ui-help-info-none');
|
||||
} else {
|
||||
container.text(RED._("sidebar.project.noSummaryAvailable")).addClass('red-ui-help-info-none');
|
||||
}
|
||||
}
|
||||
|
||||
function updateProjectVersion(version, container) {
|
||||
container.empty();
|
||||
if (version) {
|
||||
container.text(version);
|
||||
}
|
||||
}
|
||||
function createMainPane(activeProject) {
|
||||
|
||||
var pane = $('<div id="red-ui-project-settings-tab-main" class="red-ui-project-settings-tab-pane red-ui-help"></div>');
|
||||
$('<h1>').text(activeProject.name).appendTo(pane);
|
||||
var summary = $('<div style="position: relative">').appendTo(pane);
|
||||
var summaryContent = $('<div></div>').appendTo(summary);
|
||||
var versionContent = $('<div></div>').addClass('red-ui-help-info-none').appendTo(summary);
|
||||
updateProjectSummary(activeProject.summary, summaryContent);
|
||||
updateProjectVersion(activeProject.version, versionContent);
|
||||
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
$('<button class="red-ui-button red-ui-button-small" style="float: right;">' + RED._('sidebar.project.editDescription') + '</button>')
|
||||
.prependTo(summary)
|
||||
.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
editSummary(activeProject, activeProject.summary, summaryContent);
|
||||
editSummary(activeProject, activeProject.summary, summaryContent, activeProject.version, versionContent);
|
||||
});
|
||||
}
|
||||
$('<hr>').appendTo(pane);
|
||||
@@ -1017,7 +1033,7 @@ RED.projects.settings = (function() {
|
||||
|
||||
var credentialSecretExistingRow = $('<div class="red-ui-settings-row red-ui-settings-row-credentials"></div>').appendTo(credentialFormRows);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.currentKey")).appendTo(credentialSecretExistingRow);
|
||||
var credentialSecretExistingInput = $('<input type="password">').appendTo(credentialSecretExistingRow)
|
||||
var credentialSecretExistingInput = $('<input type="text">').appendTo(credentialSecretExistingRow).typedInput({type:"cred"})
|
||||
.on("change keyup paste",function() {
|
||||
if (popover) {
|
||||
popover.close();
|
||||
@@ -1030,7 +1046,7 @@ RED.projects.settings = (function() {
|
||||
|
||||
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.newKey")).appendTo(credentialSecretNewRow);
|
||||
var credentialSecretNewInput = $('<input type="password">').appendTo(credentialSecretNewRow).on("change keyup paste",checkFiles);
|
||||
var credentialSecretNewInput = $('<input type="text">').appendTo(credentialSecretNewRow).typedInput({type:"cred"}).on("change keyup paste",checkFiles);
|
||||
|
||||
var credentialResetWarning = $('<div class="form-tips form-warning" style="margin: 10px;"><i class="fa fa-warning"></i>' + RED._("sidebar.project.projectSettings.credentialsAlert") + '</div>').hide().appendTo(credentialFormRows);
|
||||
|
||||
@@ -1573,8 +1589,6 @@ RED.projects.settings = (function() {
|
||||
updateForm();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function createSettingsPane(activeProject) {
|
||||
var pane = $('<div id="red-ui-project-settings-tab-settings" class="red-ui-project-settings-tab-pane red-ui-help"></div>');
|
||||
createFilesSection(activeProject,pane);
|
||||
|
@@ -38,13 +38,34 @@ RED.projects.userSettings = (function() {
|
||||
$('<label for="user-settings-gitconfig-email"></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row);
|
||||
gitEmailInput = $('<input type="text" id="user-settings-gitconfig-email">').appendTo(row);
|
||||
gitEmailInput.val(currentGitSettings.user.email||"");
|
||||
|
||||
}
|
||||
|
||||
function createWorkflowSection(pane) {
|
||||
|
||||
var currentGitSettings = RED.settings.get('git') || {};
|
||||
currentGitSettings.workflow = currentGitSettings.workflow || {};
|
||||
currentGitSettings.workflow.mode = currentGitSettings.workflow.mode || "manual";
|
||||
|
||||
var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.workflow")).appendTo(pane);
|
||||
|
||||
var workflowContainer = $('<div class="red-ui-settings-section"></div>').appendTo(pane);
|
||||
$('<div class="red-ui-settings-section-description"></div>').appendTo(workflowContainer).text(RED._("editor:sidebar.project.userSettings.workfowTip"));
|
||||
|
||||
var row = $('<div class="red-ui-settings-row"></div>').appendTo(workflowContainer);
|
||||
$('<label><input type="radio" name="user-setting-gitworkflow" value="manual"> <div style="margin-left: 3px; display: inline-block"><div data-i18n="editor:sidebar.project.userSettings.workflowManual"></div><div style="color:#aaa;" data-i18n="editor:sidebar.project.userSettings.workflowManualTip"></div></div></label>').appendTo(row);
|
||||
row = $('<div class="red-ui-settings-row"></div>').appendTo(workflowContainer);
|
||||
$('<label><input type="radio" name="user-setting-gitworkflow" value="auto"> <div style="margin-left: 3px; display: inline-block"><div data-i18n="editor:sidebar.project.userSettings.workflowAuto"></div><div style="color:#aaa;" data-i18n="editor:sidebar.project.userSettings.workflowAutoTip"></div></div></label>').appendTo(row);
|
||||
|
||||
workflowContainer.find('[name="user-setting-gitworkflow"][type="radio"][value="'+currentGitSettings.workflow.mode+'"]').prop('checked',true)
|
||||
|
||||
}
|
||||
|
||||
|
||||
function createSSHKeySection(pane) {
|
||||
var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.sshKeys")).appendTo(pane);
|
||||
var container = $('<div class="red-ui-settings-section"></div>').appendTo(pane);
|
||||
var popover;
|
||||
var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.sshKeys")).appendTo(container);
|
||||
var subtitle = $('<div class="red-ui-settings-section-description"></div>').appendTo(container).text(RED._("editor:sidebar.project.userSettings.sshKeysTip"));
|
||||
|
||||
var addKeyButton = $('<button id="user-settings-gitconfig-add-key" class="red-ui-button red-ui-button-small" style="float: right; margin-right: 10px;">'+RED._("editor:sidebar.project.userSettings.add")+'</button>')
|
||||
@@ -391,6 +412,7 @@ RED.projects.userSettings = (function() {
|
||||
function createSettingsPane(activeProject) {
|
||||
var pane = $('<div id="red-ui-settings-tab-gitconfig" class="project-settings-tab-pane red-ui-help"></div>');
|
||||
createGitUserSection(pane);
|
||||
createWorkflowSection(pane);
|
||||
createSSHKeySection(pane);
|
||||
return pane;
|
||||
}
|
||||
@@ -407,6 +429,9 @@ RED.projects.userSettings = (function() {
|
||||
currentGitSettings.user = currentGitSettings.user || {};
|
||||
currentGitSettings.user.name = gitUsernameInput.val();
|
||||
currentGitSettings.user.email = gitEmailInput.val();
|
||||
currentGitSettings.workflow = currentGitSettings.workflow || {};
|
||||
currentGitSettings.workflow.mode = $('[name="user-setting-gitworkflow"][type="radio"]:checked').val()
|
||||
|
||||
RED.settings.set('git', currentGitSettings);
|
||||
}
|
||||
});
|
||||
|
@@ -81,8 +81,8 @@ RED.projects = (function() {
|
||||
$('<p>').text(RED._("projects.welcome.desc2")).appendTo(body);
|
||||
|
||||
var row = $('<div style="text-align: center"></div>').appendTo(body);
|
||||
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.welcome.create")+'</button>').appendTo(row);
|
||||
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.welcome.clone")+'</button>').appendTo(row);
|
||||
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.welcome.create")+'</button>').appendTo(row);
|
||||
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.welcome.clone")+'</button>').appendTo(row);
|
||||
|
||||
createAsEmpty.on("click", function(e) {
|
||||
e.preventDefault();
|
||||
@@ -511,7 +511,8 @@ RED.projects = (function() {
|
||||
|
||||
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
|
||||
$('<label for="red-ui-projects-dialog-screen-create-project-repo-pass">'+RED._("projects.clone-project.passwd")+'</label>').appendTo(subrow);
|
||||
projectRepoPasswordInput = $('<input id="red-ui-projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
|
||||
projectRepoPasswordInput = $('<input style="width:100%" id="red-ui-projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
|
||||
projectRepoPasswordInput.typedInput({type:"cred"});
|
||||
// -----------------------------------------------------
|
||||
|
||||
// Repo credentials - key/passphrase -------------------
|
||||
@@ -539,12 +540,12 @@ RED.projects = (function() {
|
||||
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
|
||||
$('<label for="red-ui-projects-dialog-screen-create-project-repo-passphrase">'+RED._("projects.clone-project.passphrase")+'</label>').appendTo(subrow);
|
||||
projectRepoPassphrase = $('<input id="red-ui-projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
|
||||
|
||||
projectRepoPassphrase.typedInput({type:"cred"});
|
||||
subrow = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows);
|
||||
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
|
||||
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.clone-project.ssh-key-desc")+'</div>').appendTo(sshwarningRow);
|
||||
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
|
||||
$('<button class="red-ui-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
|
||||
e.preventDefault();
|
||||
dialog.dialog( "close" );
|
||||
RED.userSettings.show('gitconfig');
|
||||
@@ -558,8 +559,8 @@ RED.projects = (function() {
|
||||
// Secret - clone
|
||||
row = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-clone"></div>').appendTo(body);
|
||||
$('<label>'+RED._("projects.clone-project.credential-key")+'</label>').appendTo(row);
|
||||
projectSecretInput = $('<input type="password"></input>').appendTo(row);
|
||||
|
||||
projectSecretInput = $('<input style="width: 100%" type="password"></input>').appendTo(row);
|
||||
projectSecretInput.typedInput({type:"cred"});
|
||||
|
||||
|
||||
return container;
|
||||
@@ -894,6 +895,7 @@ RED.projects = (function() {
|
||||
$('<label class="red-ui-projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" value="custom" name="projects-encryption-key"> <span style="vertical-align: middle;">'+RED._("projects.encryption-config.use-custom")+'</span></label>').appendTo(row);
|
||||
row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
|
||||
emptyProjectCredentialInput = $('<input disabled type="password" style="margin-left: 25px; width: calc(100% - 30px);"></input>').appendTo(row);
|
||||
emptyProjectCredentialInput.typedInput({type:"cred"});
|
||||
emptyProjectCredentialInput.on("change keyup paste", validateForm);
|
||||
|
||||
row = $('<div class="form-row projects-encryption-disabled-row"></div>').hide().appendTo(credentialsRightBox);
|
||||
@@ -1169,11 +1171,11 @@ RED.projects = (function() {
|
||||
|
||||
row = $('<div class="form-row button-group"></div>').appendTo(container);
|
||||
|
||||
var openProject = $('<button data-type="open" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
|
||||
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
|
||||
// var createAsCopy = $('<button data-type="copy" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
|
||||
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
|
||||
// var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
|
||||
var openProject = $('<button data-type="open" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
|
||||
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
|
||||
// var createAsCopy = $('<button data-type="copy" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
|
||||
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
|
||||
// var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
|
||||
row.find(".red-ui-projects-dialog-screen-create-type").on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
container.find(".red-ui-projects-dialog-screen-create-type").removeClass('selected');
|
||||
@@ -1298,6 +1300,7 @@ RED.projects = (function() {
|
||||
$('<label class="red-ui-projects-edit-form-inline-label">'+RED._("projects.create.encryption-key")+'</label>').appendTo(row);
|
||||
// row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
|
||||
emptyProjectCredentialInput = $('<input type="password"></input>').appendTo(row);
|
||||
emptyProjectCredentialInput.typedInput({type:"cred"});
|
||||
emptyProjectCredentialInput.on("change keyup paste", validateForm);
|
||||
$('<label class="red-ui-projects-edit-form-sublabel"><small>'+RED._("projects.create.desc0")+'</small></label>').appendTo(row);
|
||||
|
||||
@@ -1356,7 +1359,8 @@ RED.projects = (function() {
|
||||
|
||||
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
|
||||
$('<label for="red-ui-projects-dialog-screen-create-project-repo-pass">'+RED._("projects.create.password")+'</label>').appendTo(subrow);
|
||||
projectRepoPasswordInput = $('<input id="red-ui-projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
|
||||
projectRepoPasswordInput = $('<input style="width:100%" id="red-ui-projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
|
||||
projectRepoPasswordInput.typedInput({type:"cred"});
|
||||
// -----------------------------------------------------
|
||||
|
||||
// Repo credentials - key/passphrase -------------------
|
||||
@@ -1384,12 +1388,13 @@ RED.projects = (function() {
|
||||
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
|
||||
$('<label for="red-ui-projects-dialog-screen-create-project-repo-passphrase">'+RED._("projects.create.passphrase")+'</label>').appendTo(subrow);
|
||||
projectRepoPassphrase = $('<input id="red-ui-projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
|
||||
projectRepoPassphrase.typedInput({type:"cred"});
|
||||
|
||||
subrow = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows);
|
||||
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
|
||||
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.create.desc2")+'</div>').appendTo(sshwarningRow);
|
||||
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
|
||||
$('<button class="red-ui-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
|
||||
e.preventDefault();
|
||||
$('#red-ui-projects-dialog-cancel').trigger("click");
|
||||
RED.userSettings.show('gitconfig');
|
||||
@@ -1403,8 +1408,8 @@ RED.projects = (function() {
|
||||
// Secret - clone
|
||||
row = $('<div class="hide form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-clone"></div>').appendTo(container);
|
||||
$('<label>'+RED._("projects.create.credentials-encryption-key")+'</label>').appendTo(row);
|
||||
projectSecretInput = $('<input type="password"></input>').appendTo(row);
|
||||
|
||||
projectSecretInput = $('<input style="width:100%" type="password"></input>').appendTo(row);
|
||||
projectSecretInput.typedInput({type:"cred"});
|
||||
|
||||
switch(options.screen||"empty") {
|
||||
case "empty": createAsEmpty.trigger("click"); break;
|
||||
@@ -1617,14 +1622,14 @@ RED.projects = (function() {
|
||||
function deleteProject(row,name,done) {
|
||||
var cover = $('<div class="red-ui-projects-dialog-project-list-entry-delete-confirm"></div>').on("click", function(evt) { evt.stopPropagation(); }).appendTo(row);
|
||||
$('<span>').text(RED._("projects.delete.confirm")).appendTo(cover);
|
||||
$('<button class="red-ui-button">'+RED._("common.label.cancel")+'</button>')
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("common.label.cancel")+'</button>')
|
||||
.appendTo(cover)
|
||||
.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
cover.remove();
|
||||
done(true);
|
||||
});
|
||||
$('<button class="red-ui-button primary">'+RED._("common.label.delete")+'</button>')
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button primary">'+RED._("common.label.delete")+'</button>')
|
||||
.appendTo(cover)
|
||||
.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
@@ -1808,7 +1813,7 @@ RED.projects = (function() {
|
||||
header.addClass("selectable");
|
||||
|
||||
var tools = $('<div class="red-ui-projects-dialog-project-list-entry-tools"></div>').appendTo(header);
|
||||
$('<button class="red-ui-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
|
||||
.appendTo(tools)
|
||||
.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
@@ -1962,7 +1967,8 @@ RED.projects = (function() {
|
||||
var isSSH = false;
|
||||
if (/^https?:\/\//.test(url)) {
|
||||
$('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+
|
||||
'<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
|
||||
'<div class="form-row"><label for="projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
|
||||
message.find("#projects-user-auth-password").typedInput({type:"cred"})
|
||||
} else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
|
||||
isSSH = true;
|
||||
var row = $('<div class="form-row"></div>').appendTo(message);
|
||||
@@ -1980,7 +1986,7 @@ RED.projects = (function() {
|
||||
});
|
||||
row = $('<div class="form-row"></div>').appendTo(message);
|
||||
$('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row);
|
||||
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row);
|
||||
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row).typedInput({type:"cred"});
|
||||
}
|
||||
|
||||
var notification = RED.notify(message,{
|
||||
|
@@ -293,14 +293,20 @@ RED.sidebar.versionControl = (function() {
|
||||
if (activeProject) {
|
||||
// TODO: this is a full refresh of the files - should be able to
|
||||
// just do an incremental refresh
|
||||
allChanges = {};
|
||||
unstagedChangesList.editableList('empty');
|
||||
stagedChangesList.editableList('empty');
|
||||
unmergedChangesList.editableList('empty');
|
||||
|
||||
$.getJSON("projects/"+activeProject.name+"/status",function(result) {
|
||||
refreshFiles(result);
|
||||
});
|
||||
var workflowMode = ((RED.settings.get('git') || {}).workflow || {}).mode || "manual";
|
||||
if (workflowMode === 'auto') {
|
||||
refresh(true);
|
||||
} else {
|
||||
allChanges = {};
|
||||
unstagedChangesList.editableList('empty');
|
||||
stagedChangesList.editableList('empty');
|
||||
unmergedChangesList.editableList('empty');
|
||||
|
||||
$.getJSON("projects/"+activeProject.name+"/status",function(result) {
|
||||
refreshFiles(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.events.on("login",function() {
|
||||
|
@@ -232,7 +232,11 @@ RED.sidebar = (function() {
|
||||
}
|
||||
},
|
||||
// minimumActiveTabWidth: 70,
|
||||
collapsible: true
|
||||
collapsible: true,
|
||||
onreorder: function(order) {
|
||||
RED.settings.set("editor.sidebar.order",order);
|
||||
},
|
||||
order: RED.settings.get("editor.sidebar.order",["info", "help", "version-control", "debug"])
|
||||
// scrollable: true
|
||||
});
|
||||
|
||||
|
@@ -453,7 +453,7 @@ RED.subflow = (function() {
|
||||
$("#red-ui-workspace-chart").css({"margin-top": "0"});
|
||||
}
|
||||
|
||||
function removeSubflow(id) {
|
||||
function removeSubflow(id, keepInstanceNodes) {
|
||||
// TODO: A lot of this logic is common with RED.nodes.removeWorkspace
|
||||
var removedNodes = [];
|
||||
var removedLinks = [];
|
||||
@@ -462,7 +462,7 @@ RED.subflow = (function() {
|
||||
var activeSubflow = RED.nodes.subflow(id);
|
||||
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type == "subflow:"+id) {
|
||||
if (!keepInstanceNodes && n.type == "subflow:"+id) {
|
||||
removedNodes.push(n);
|
||||
}
|
||||
if (n.z == id) {
|
||||
|
@@ -79,7 +79,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
try {
|
||||
label = (typeof n._def.label === "function" ? n._def.label.call(n) : n._def.label)||"";
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+type+".label",err);
|
||||
console.log("Definition error: "+n.type+".label",err);
|
||||
}
|
||||
}
|
||||
var newlineIndex = label.indexOf("\\n");
|
||||
|
@@ -52,13 +52,15 @@ RED.utils = (function() {
|
||||
} else if (value === null) {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-null">null</span>');
|
||||
} else if (typeof value === 'object') {
|
||||
if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) {
|
||||
if (value.hasOwnProperty('type') && value.type === 'undefined') {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-null">undefined</span>');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('buffer['+value.length+']');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('array['+value.length+']');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'function') {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('function');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'number') {
|
||||
} else if (value.hasOwnProperty('type') && (value.type === 'number' || value.type === 'bigint')) {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>').text(value.data);
|
||||
} else {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>');
|
||||
@@ -348,7 +350,9 @@ RED.utils = (function() {
|
||||
}
|
||||
if (obj === null || obj === undefined) {
|
||||
$('<span class="red-ui-debug-msg-type-null">'+obj+'</span>').appendTo(entryObj);
|
||||
} else if (obj.__enc__ && obj.type === 'number') {
|
||||
} else if (obj.__enc__ && obj.type === 'undefined') {
|
||||
$('<span class="red-ui-debug-msg-type-null">undefined</span>').appendTo(entryObj);
|
||||
} else if (obj.__enc__ && (obj.type === 'number' || obj.type === 'bigint')) {
|
||||
e = $('<span class="red-ui-debug-msg-type-number red-ui-debug-msg-object-header"></span>').text(obj.data).appendTo(entryObj);
|
||||
} else if (typeHint === "function" || (obj.__enc__ && obj.type === 'function')) {
|
||||
e = $('<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>').text("function").appendTo(entryObj);
|
||||
|
@@ -98,7 +98,8 @@ RED.view = (function() {
|
||||
"green": "#5a8",
|
||||
"yellow": "#F9DF31",
|
||||
"blue": "#53A3F3",
|
||||
"grey": "#d3d3d3"
|
||||
"grey": "#d3d3d3",
|
||||
"gray": "#d3d3d3"
|
||||
}
|
||||
|
||||
var PORT_TYPE_INPUT = 1;
|
||||
@@ -499,7 +500,7 @@ RED.view = (function() {
|
||||
|
||||
RED.actions.add("core:copy-selection-to-internal-clipboard",copySelection);
|
||||
RED.actions.add("core:cut-selection-to-internal-clipboard",function(){copySelection();deleteSelection();});
|
||||
RED.actions.add("core:paste-from-internal-clipboard",function(){importNodes(clipboard);});
|
||||
RED.actions.add("core:paste-from-internal-clipboard",function(){importNodes(clipboard,{generateIds: true});});
|
||||
RED.actions.add("core:delete-selection",deleteSelection);
|
||||
RED.actions.add("core:edit-selected-node",editSelection);
|
||||
RED.actions.add("core:undo",RED.history.pop);
|
||||
@@ -1678,7 +1679,7 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
if (ns.length > 0) {
|
||||
if (ns.length > 0 && mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||
historyEvent = {t:"move",nodes:ns,dirty:RED.nodes.dirty()};
|
||||
if (activeSpliceLink) {
|
||||
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
|
||||
@@ -1892,7 +1893,8 @@ RED.view = (function() {
|
||||
activeLinkNodes = {};
|
||||
for (var i=0;i<movingSet.length();i++) {
|
||||
var msn = movingSet.get(i);
|
||||
if (msn.n.type === "link out" || msn.n.type === "link in") {
|
||||
if ((msn.n.type === "link out" || msn.n.type === "link in") &&
|
||||
(msn.n.z === activeWorkspace)) {
|
||||
var linkNode = msn.n;
|
||||
activeLinkNodes[linkNode.id] = linkNode;
|
||||
var offFlowLinks = {};
|
||||
@@ -2354,6 +2356,10 @@ RED.view = (function() {
|
||||
mousedown_port_type = null;
|
||||
activeSpliceLink = null;
|
||||
spliceActive = false;
|
||||
if (activeHoverGroup) {
|
||||
activeHoverGroup.hovered = false;
|
||||
activeHoverGroup = null;
|
||||
}
|
||||
d3.select(".red-ui-flow-link-splice").classed("red-ui-flow-link-splice",false);
|
||||
if (spliceTimer) {
|
||||
clearTimeout(spliceTimer);
|
||||
@@ -2869,7 +2875,7 @@ RED.view = (function() {
|
||||
//RED.touch.radialMenu.show(d3.select(this),pos);
|
||||
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
|
||||
RED.keyboard.remove("escape");
|
||||
|
||||
var historyEvent = RED.history.peek();
|
||||
if (activeSpliceLink) {
|
||||
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
|
||||
var spliceLink = d3.select(activeSpliceLink).data()[0];
|
||||
@@ -2886,12 +2892,27 @@ RED.view = (function() {
|
||||
};
|
||||
RED.nodes.addLink(link1);
|
||||
RED.nodes.addLink(link2);
|
||||
var historyEvent = RED.history.peek();
|
||||
|
||||
historyEvent.links = [link1,link2];
|
||||
historyEvent.removedLinks = [spliceLink];
|
||||
updateActiveNodes();
|
||||
}
|
||||
|
||||
if (activeHoverGroup) {
|
||||
for (var j=0;j<movingSet.length();j++) {
|
||||
var n = movingSet.get(j);
|
||||
RED.group.addToGroup(activeHoverGroup,n.n);
|
||||
}
|
||||
historyEvent.addedToGroup = activeHoverGroup;
|
||||
|
||||
activeHoverGroup.hovered = false;
|
||||
enterActiveGroup(activeHoverGroup)
|
||||
// TODO: check back whether this should add to moving_set
|
||||
activeGroup.selected = true;
|
||||
activeHoverGroup = null;
|
||||
}
|
||||
|
||||
|
||||
updateSelection();
|
||||
RED.nodes.dirty(true);
|
||||
redraw();
|
||||
@@ -3460,7 +3481,7 @@ RED.view = (function() {
|
||||
options.push({name:"delete",disabled:(movingSet.length()===0 && selected_link === null),onselect:function() {deleteSelection();}});
|
||||
options.push({name:"cut",disabled:(movingSet.length()===0),onselect:function() {copySelection();deleteSelection();}});
|
||||
options.push({name:"copy",disabled:(movingSet.length()===0),onselect:function() {copySelection();}});
|
||||
options.push({name:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard,false,true);}});
|
||||
options.push({name:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard, {generateIds: true, touchImport: true});}});
|
||||
options.push({name:"edit",disabled:(movingSet.length() != 1),onselect:function() { RED.editor.edit(mdn);}});
|
||||
options.push({name:"select",onselect:function() {selectAll();}});
|
||||
options.push({name:"undo",disabled:(RED.history.depth() === 0),onselect:function() {RED.history.pop();}});
|
||||
@@ -3929,7 +3950,14 @@ RED.view = (function() {
|
||||
}
|
||||
d.resize = false;
|
||||
}
|
||||
|
||||
if (d._colorChanged) {
|
||||
var newColor = RED.utils.getNodeColor(d.type,d._def);
|
||||
this.__mainRect__.setAttribute("fill",newColor);
|
||||
if (this.__buttonGroupButton__) {
|
||||
this.__buttonGroupButton__.settAttribute("fill",newColor);
|
||||
}
|
||||
delete d._colorChanged;
|
||||
}
|
||||
//thisNode.selectAll(".centerDot").attr({"cx":function(d) { return d.w/2;},"cy":function(d){return d.h/2}});
|
||||
this.setAttribute("transform", "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")");
|
||||
// This might be the first redraw after a node has been click-dragged to start a move.
|
||||
@@ -4418,6 +4446,7 @@ RED.view = (function() {
|
||||
}
|
||||
if (d.dirty || dirtyGroups[d.id]) {
|
||||
var g = d3.select(this);
|
||||
var recalculateLabelOffsets = false;
|
||||
if (d.nodes.length > 0) {
|
||||
// If the group was just moved, all of its contents was
|
||||
// also moved - so no need to recalculate its bounding box
|
||||
@@ -4446,6 +4475,7 @@ RED.view = (function() {
|
||||
d.y = minY;
|
||||
d.w = maxX - minX;
|
||||
d.h = maxY - minY;
|
||||
recalculateLabelOffsets = true;
|
||||
// if set explicitly to false, this group has just been
|
||||
// imported so needed this initial resize calculation.
|
||||
// Now that's done, delete the flag so the normal
|
||||
@@ -4459,28 +4489,31 @@ RED.view = (function() {
|
||||
} else {
|
||||
d.w = 40;
|
||||
d.h = 40;
|
||||
recalculateLabelOffsets = true;
|
||||
}
|
||||
if (!d.minWidth) {
|
||||
if (d.style.label && d.name) {
|
||||
var labelParts = getLabelParts(d.name||"","red-ui-flow-group-label");
|
||||
d.minWidth = labelParts.width + 8;
|
||||
d.labels = labelParts.lines;
|
||||
} else {
|
||||
d.minWidth = 40;
|
||||
d.labels = [];
|
||||
if (recalculateLabelOffsets) {
|
||||
if (!d.minWidth) {
|
||||
if (d.style.label && d.name) {
|
||||
var labelParts = getLabelParts(d.name||"","red-ui-flow-group-label");
|
||||
d.minWidth = labelParts.width + 8;
|
||||
d.labels = labelParts.lines;
|
||||
} else {
|
||||
d.minWidth = 40;
|
||||
d.labels = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
d.w = Math.max(d.minWidth,d.w);
|
||||
if (d.style.label && d.labels.length > 0) {
|
||||
var labelPos = d.style["label-position"] || "nw";
|
||||
var h = (d.labels.length-1) * 16;
|
||||
if (labelPos[0] === "s") {
|
||||
h += 8;
|
||||
}
|
||||
d.h += h;
|
||||
if (labelPos[0] === "n") {
|
||||
if (d.nodes.length > 0) {
|
||||
d.y -= h;
|
||||
d.w = Math.max(d.minWidth,d.w);
|
||||
if (d.style.label && d.labels.length > 0) {
|
||||
var labelPos = d.style["label-position"] || "nw";
|
||||
var h = (d.labels.length-1) * 16;
|
||||
if (labelPos[0] === "s") {
|
||||
h += 8;
|
||||
}
|
||||
d.h += h;
|
||||
if (labelPos[0] === "n") {
|
||||
if (d.nodes.length > 0) {
|
||||
d.y -= h;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4604,29 +4637,69 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Imports a new collection of nodes from a JSON String.
|
||||
*
|
||||
* - all get new IDs assigned
|
||||
* - all "selected"
|
||||
* - attached to mouse for placing - "IMPORT_DRAGGING"
|
||||
* @param {String/Array} newNodesObj nodes to import
|
||||
* @param {Object} options options object
|
||||
*
|
||||
* Options:
|
||||
* - addFlow - whether to import nodes to a new tab
|
||||
* - touchImport - whether this is a touch import. If not, imported nodes are
|
||||
* attachedto mouse for placing - "IMPORT_DRAGGING" state
|
||||
*/
|
||||
function importNodes(newNodesStr,addNewFlow,touchImport) {
|
||||
function importNodes(newNodesObj,options) {
|
||||
options = options || {
|
||||
addFlow: false,
|
||||
touchImport: false,
|
||||
generateIds: false
|
||||
}
|
||||
var addNewFlow = options.addFlow
|
||||
var touchImport = options.touchImport;
|
||||
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nodesToImport;
|
||||
if (typeof newNodesObj === "string") {
|
||||
if (newNodesObj === "") {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
nodesToImport = JSON.parse(newNodesObj);
|
||||
} catch(err) {
|
||||
var e = new Error(RED._("clipboard.invalidFlow",{message:err.message}));
|
||||
e.code = "NODE_RED";
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
nodesToImport = newNodesObj;
|
||||
}
|
||||
|
||||
if (!$.isArray(nodesToImport)) {
|
||||
nodesToImport = [nodesToImport];
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
var activeSubflowChanged;
|
||||
if (activeSubflow) {
|
||||
activeSubflowChanged = activeSubflow.changed;
|
||||
}
|
||||
var result = RED.nodes.import(newNodesStr,true,addNewFlow);
|
||||
var result = RED.nodes.import(nodesToImport,{generateIds:options.generateIds, addFlow: addNewFlow, importMap: options.importMap});
|
||||
if (result) {
|
||||
var new_nodes = result[0];
|
||||
var new_links = result[1];
|
||||
var new_groups = result[2];
|
||||
var new_workspaces = result[3];
|
||||
var new_subflows = result[4];
|
||||
var new_default_workspace = result[5];
|
||||
var new_nodes = result.nodes;
|
||||
var new_links = result.links;
|
||||
var new_groups = result.groups;
|
||||
var new_workspaces = result.workspaces;
|
||||
var new_subflows = result.subflows;
|
||||
var removedNodes = result.removedNodes;
|
||||
var new_default_workspace = result.missingWorkspace;
|
||||
if (addNewFlow && new_default_workspace) {
|
||||
RED.workspaces.show(new_default_workspace.id);
|
||||
}
|
||||
@@ -4736,6 +4809,20 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (removedNodes) {
|
||||
var replaceEvent = {
|
||||
t: "replace",
|
||||
config: removedNodes
|
||||
}
|
||||
historyEvent = {
|
||||
t:"multi",
|
||||
events: [
|
||||
replaceEvent,
|
||||
historyEvent
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
updateActiveNodes();
|
||||
@@ -4767,6 +4854,9 @@ RED.view = (function() {
|
||||
if (new_subflows.length > 0) {
|
||||
counts.push(RED._("clipboard.subflow",{count:new_subflows.length}));
|
||||
}
|
||||
if (removedNodes && removedNodes.length > 0) {
|
||||
counts.push(RED._("clipboard.replacedNodes",{count:removedNodes.length}));
|
||||
}
|
||||
if (counts.length > 0) {
|
||||
var countList = "<ul><li>"+counts.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("<p>"+RED._("clipboard.nodesImported")+"</p>"+countList,{id:"clipboard"});
|
||||
@@ -4774,7 +4864,10 @@ RED.view = (function() {
|
||||
|
||||
}
|
||||
} catch(error) {
|
||||
if (error.code != "NODE_RED") {
|
||||
if (error.code === "import_conflict") {
|
||||
// Pass this up for the called to resolve
|
||||
throw error;
|
||||
} else if (error.code != "NODE_RED") {
|
||||
console.log(error.stack);
|
||||
RED.notify(RED._("notification.error",{message:error.toString()}),"error");
|
||||
} else {
|
||||
|
@@ -140,6 +140,7 @@
|
||||
}
|
||||
.red-ui-flow-node-icon-group {
|
||||
.fa-lg {
|
||||
@include disable-selection;
|
||||
stroke: none;
|
||||
fill: $node-icon-color;
|
||||
text-anchor: middle;
|
||||
@@ -250,7 +251,7 @@ g.red-ui-flow-node-selected {
|
||||
stroke-dasharray: none;
|
||||
}
|
||||
}
|
||||
@each $current-color in red green yellow blue grey {
|
||||
@each $current-color in red green yellow blue grey gray {
|
||||
.red-ui-flow-node-status-dot-#{$current-color} {
|
||||
fill: map-get($node-status-colors,$current-color);
|
||||
stroke: map-get($node-status-colors,$current-color);
|
||||
|
@@ -153,3 +153,61 @@
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.red-ui-clipboard-dialog-import-conflicts-list-container {
|
||||
min-height: 300px;
|
||||
position: relative;
|
||||
|
||||
li:not(:first-child) .red-ui-clipboard-dialog-import-conflicts-item-header {
|
||||
// border-top: 1px solid $secondary-border-color;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.red-ui-clipboard-dialog-import-conflicts-item-header {
|
||||
background: $tertiary-background;
|
||||
& > span:first-child {
|
||||
color: $header-text-color;
|
||||
padding-left: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.red-ui-clipboard-dialog-import-conflicts-controls {
|
||||
position: absolute;
|
||||
top:0;
|
||||
bottom: 0;
|
||||
right: 0px;
|
||||
text-align: center;
|
||||
color: $form-text-color;
|
||||
.form-row & label {
|
||||
padding: 2px 0;
|
||||
line-height: 23px;
|
||||
margin-bottom: 0;
|
||||
width: 80px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
border-left: 1px solid $secondary-border-color;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
#red-ui-clipboard-dialog-import-conflicts-list .disabled .red-ui-info-outline-item {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.form-row label.red-ui-clipboard-dialog-import-conflicts-gutter {
|
||||
box-sizing: border-box;
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
.red-ui-editor-dialog & input[type="checkbox"] {
|
||||
width: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
@@ -237,3 +237,45 @@ ul.red-ui-palette-module-error-list {
|
||||
#red-ui-palette-module-install-shade {
|
||||
padding-top: 80px;
|
||||
}
|
||||
button.red-ui-palette-editor-upload-button {
|
||||
padding: 0;
|
||||
height: 25px;
|
||||
margin-top: -1px;
|
||||
|
||||
input[type="file"] {
|
||||
opacity: 0;
|
||||
margin: 0;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
.red-ui-settings-tabs-content & label {
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
form {
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
.red-ui-palette-editor-upload {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 44px;
|
||||
padding: 20px;
|
||||
background: $secondary-background;
|
||||
border-bottom: 1px $secondary-border-color solid;
|
||||
box-shadow: 1px 1px 4px $shadow;
|
||||
|
||||
.placeholder-input {
|
||||
width: calc(100% - 180px);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.red-ui-palette-editor-upload-buttons {
|
||||
float: right;
|
||||
button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
button.red-ui-button {
|
||||
button.red-ui-button.red-ui-projects-dialog-button {
|
||||
width: calc(50% - 80px);
|
||||
margin: 20px;
|
||||
height: auto;
|
||||
|
@@ -39,6 +39,13 @@
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
button.red-ui-toggleButton.toggle {
|
||||
text-align: center;
|
||||
i {
|
||||
min-width: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.red-ui-sidebar-context-property {
|
||||
|
@@ -321,15 +321,12 @@ div.red-ui-info-table {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
.red-ui-treeList-label {
|
||||
font-size: 13px;
|
||||
padding: 2px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.red-ui-info-outline-project {
|
||||
border-bottom: 1px solid $secondary-border-color;
|
||||
}
|
||||
|
||||
}
|
||||
.red-ui-info-outline,.red-ui-sidebar-help-toc, #red-ui-clipboard-dialog-import-conflicts-list {
|
||||
.red-ui-info-outline-item {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
@@ -366,6 +363,12 @@ div.red-ui-info-table {
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-treeList-label {
|
||||
font-size: 13px;
|
||||
padding: 2px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.red-ui-search-result-node {
|
||||
width: 24px;
|
||||
height: 20px;
|
||||
@@ -387,6 +390,7 @@ div.red-ui-info-table {
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-info-outline-item-control-spacer {
|
||||
display: inline-block;
|
||||
width: 23px;
|
||||
|
@@ -19,7 +19,7 @@
|
||||
color: $secondary-text-color;
|
||||
cursor: pointer;
|
||||
input {
|
||||
display:none;
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
|
@@ -18,6 +18,7 @@
|
||||
border: 1px solid $form-input-border-color;
|
||||
border-radius: 4px;
|
||||
height: 34px;
|
||||
line-height: 14px;
|
||||
display: inline-flex;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
@@ -79,7 +79,7 @@
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
.uneditable-input, input, textarea {
|
||||
.uneditable-input, input[type="text"],input[type="password"], textarea {
|
||||
width: calc(100% - 150px);
|
||||
}
|
||||
textarea {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/mode/sql_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|when|then|else|end|type|left|right|join|on|outer|desc|asc|union|create|table|primary|key|if|foreign|not|references|default|null|inner|cross|natural|database|drop|grant",t="true|false",n="avg|count|first|last|max|min|sum|ucase|lcase|mid|len|round|rank|now|format|coalesce|ifnull|isnull|nvl",r="int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp|money|real|number|integer",i=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t,"storage.type":r},"identifier",!0);this.$rules={start:[{token:"comment",regex:"--.*$"},{token:"comment",start:"/\\*",end:"\\*/"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.*?'"},{token:"string",regex:"`.*?`"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:i,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]},this.normalizeRules()};r.inherits(s,i),t.SqlHighlightRules=s}),ace.define("ace/mode/sql",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/sql_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./sql_highlight_rules").SqlHighlightRules,o=function(){this.HighlightRules=s,this.$behaviour=this.$defaultBehaviour};r.inherits(o,i),function(){this.lineCommentStart="--",this.$id="ace/mode/sql"}.call(o.prototype),t.Mode=o}); (function() {
|
||||
ace.define("ace/mode/sql_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|when|then|else|end|type|left|right|join|on|outer|desc|asc|union|create|table|primary|key|if|foreign|not|references|default|null|inner|cross|natural|database|drop|grant",t="true|false",n="avg|count|first|last|max|min|sum|ucase|lcase|mid|len|round|rank|now|format|coalesce|ifnull|isnull|nvl",r="int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp|money|real|number|integer",i=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t,"storage.type":r},"identifier",!0);this.$rules={start:[{token:"comment",regex:"--.*$"},{token:"comment",start:"/\\*",end:"\\*/"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.*?'"},{token:"string",regex:"`.*?`"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:i,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]},this.normalizeRules()};r.inherits(s,i),t.SqlHighlightRules=s}),ace.define("ace/mode/sql",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/sql_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./sql_highlight_rules").SqlHighlightRules,o=function(){this.HighlightRules=s,this.$behaviour=this.$defaultBehaviour};r.inherits(o,i),function(){this.lineCommentStart="--",this.$id="ace/mode/sql",this.snippetFileId="ace/snippets/sql"}.call(o.prototype),t.Mode=o}); (function() {
|
||||
ace.require(["ace/mode/sql"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/mode/yaml_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"list.markup",regex:/^(?:-{3}|\.{3})\s*(?=#|$)/},{token:"list.markup",regex:/^\s*[\-?](?:$|\s)/},{token:"constant",regex:"!![\\w//]+"},{token:"constant.language",regex:"[&\\*][a-zA-Z0-9-_]+"},{token:["meta.tag","keyword"],regex:/^(\s*\w.*?)(:(?=\s|$))/},{token:["meta.tag","keyword"],regex:/(\w+?)(\s*:(?=\s|$))/},{token:"keyword.operator",regex:"<<\\w*:\\w*"},{token:"keyword.operator",regex:"-\\s*(?=[{])"},{token:"string",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'},{token:"string",regex:/[|>][-+\d\s]*$/,onMatch:function(e,t,n,r){var i=/^\s*/.exec(r)[0];return n.length<1?n.push(this.next):n[0]="mlString",n.length<2?n.push(i.length):n[1]=i.length,this.token},next:"mlString"},{token:"string",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"constant.numeric",regex:/(\b|[+\-\.])[\d_]+(?:(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)(?=[^\d-\w]|$)/},{token:"constant.numeric",regex:/[+\-]?\.inf\b|NaN\b|0x[\dA-Fa-f_]+|0b[10_]+/},{token:"constant.language.boolean",regex:"\\b(?:true|false|TRUE|FALSE|True|False|yes|no)\\b"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:/[^\s,:\[\]\{\}]+/}],mlString:[{token:"indent",regex:/^\s*$/},{token:"indent",regex:/^\s*/,onMatch:function(e,t,n){var r=n[1];return r>=e.length?(this.next="start",n.splice(0)):this.next="mlString",this.token},next:"mlString"},{token:"string",regex:".+"}]},this.normalizeRules()};r.inherits(s,i),t.YamlHighlightRules=s}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++n<f){o=e.getLine(n);var h=o.search(i);if(h==-1)continue;if(o[h]!="#")break;c=n}if(c>l){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u<a?"start":"","";if(u==-1){if(i==a&&r[i]=="#"&&s[i]=="#")return e.foldWidgets[n-1]="",e.foldWidgets[n+1]="","start"}else if(u==i&&r[i]=="#"&&o[i]=="#"&&e.getLine(n-2).search(/\S/)==-1)return e.foldWidgets[n-1]="start",e.foldWidgets[n+1]="","";return u!=-1&&u<i?e.foldWidgets[n-1]="start":e.foldWidgets[n-1]="",i<a?"start":""}}.call(o.prototype)}),ace.define("ace/mode/yaml",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/yaml_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/coffee"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./yaml_highlight_rules").YamlHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./folding/coffee").FoldMode,a=function(){this.HighlightRules=s,this.$outdent=new o,this.foldingRules=new u,this.$behaviour=this.$defaultBehaviour};r.inherits(a,i),function(){this.lineCommentStart=["#"],this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);if(e=="start"){var i=t.match(/^.*[\{\(\[]\s*$/);i&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id="ace/mode/yaml"}.call(a.prototype),t.Mode=a}); (function() {
|
||||
ace.define("ace/mode/yaml_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"list.markup",regex:/^(?:-{3}|\.{3})\s*(?=#|$)/},{token:"list.markup",regex:/^\s*[\-?](?:$|\s)/},{token:"constant",regex:"!![\\w//]+"},{token:"constant.language",regex:"[&\\*][a-zA-Z0-9-_]+"},{token:["meta.tag","keyword"],regex:/^(\s*\w.*?)(:(?=\s|$))/},{token:["meta.tag","keyword"],regex:/(\w+?)(\s*:(?=\s|$))/},{token:"keyword.operator",regex:"<<\\w*:\\w*"},{token:"keyword.operator",regex:"-\\s*(?=[{])"},{token:"string",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'},{token:"string",regex:/[|>][-+\d]*(?:$|\s+(?:$|#))/,onMatch:function(e,t,n,r){r=r.replace(/ #.*/,"");var i=/^ *((:\s*)?-(\s*[^|>])?)?/.exec(r)[0].replace(/\S\s*$/,"").length,s=parseInt(/\d+[\s+-]*$/.exec(r));return s?(i+=s-1,this.next="mlString"):this.next="mlStringPre",n.length?(n[0]=this.next,n[1]=i):(n.push(this.next),n.push(i)),this.token},next:"mlString"},{token:"string",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"constant.numeric",regex:/(\b|[+\-\.])[\d_]+(?:(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)(?=[^\d-\w]|$)/},{token:"constant.numeric",regex:/[+\-]?\.inf\b|NaN\b|0x[\dA-Fa-f_]+|0b[10_]+/},{token:"constant.language.boolean",regex:"\\b(?:true|false|TRUE|FALSE|True|False|yes|no)\\b"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:/[^\s,:\[\]\{\}]+/}],mlStringPre:[{token:"indent",regex:/^ *$/},{token:"indent",regex:/^ */,onMatch:function(e,t,n){var r=n[1];return r>=e.length?(this.next="start",n.shift(),n.shift()):(n[1]=e.length-1,this.next=n[0]="mlString"),this.token},next:"mlString"},{defaultToken:"string"}],mlString:[{token:"indent",regex:/^ *$/},{token:"indent",regex:/^ */,onMatch:function(e,t,n){var r=n[1];return r>=e.length?(this.next="start",n.splice(0)):this.next="mlString",this.token},next:"mlString"},{token:"string",regex:".+"}]},this.normalizeRules()};r.inherits(s,i),t.YamlHighlightRules=s}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++n<f){o=e.getLine(n);var h=o.search(i);if(h==-1)continue;if(o[h]!="#")break;c=n}if(c>l){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u<a?"start":"","";if(u==-1){if(i==a&&r[i]=="#"&&s[i]=="#")return e.foldWidgets[n-1]="",e.foldWidgets[n+1]="","start"}else if(u==i&&r[i]=="#"&&o[i]=="#"&&e.getLine(n-2).search(/\S/)==-1)return e.foldWidgets[n-1]="start",e.foldWidgets[n+1]="","";return u!=-1&&u<i?e.foldWidgets[n-1]="start":e.foldWidgets[n-1]="",i<a?"start":""}}.call(o.prototype)}),ace.define("ace/mode/yaml",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/yaml_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/coffee"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./yaml_highlight_rules").YamlHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./folding/coffee").FoldMode,a=function(){this.HighlightRules=s,this.$outdent=new o,this.foldingRules=new u,this.$behaviour=this.$defaultBehaviour};r.inherits(a,i),function(){this.lineCommentStart=["#"],this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);if(e=="start"){var i=t.match(/^.*[\{\(\[]\s*$/);i&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id="ace/mode/yaml"}.call(a.prototype),t.Mode=a}); (function() {
|
||||
ace.require(["ace/mode/yaml"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/snippets/handlebars",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="handlebars"}); (function() {
|
||||
; (function() {
|
||||
ace.require(["ace/snippets/handlebars"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/snippets/json",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="json"}); (function() {
|
||||
; (function() {
|
||||
ace.require(["ace/snippets/json"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/snippets/properties",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="properties"}); (function() {
|
||||
; (function() {
|
||||
ace.require(["ace/snippets/properties"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/snippets/swift",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="swift"}); (function() {
|
||||
; (function() {
|
||||
ace.require(["ace/snippets/swift"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/snippets/text",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="text"}); (function() {
|
||||
; (function() {
|
||||
ace.require(["ace/snippets/text"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/snippets/xml",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="xml"}); (function() {
|
||||
; (function() {
|
||||
ace.require(["ace/snippets/xml"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
ace.define("ace/snippets/yaml",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="yaml"}); (function() {
|
||||
; (function() {
|
||||
ace.require(["ace/snippets/yaml"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -12,7 +12,7 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
|
||||
jsonataFunctions.sort(function(A,B) {
|
||||
return B.length-A.length;
|
||||
});
|
||||
jsonataFunctions = jsonataFunctions.join("|").replace(/\$/g,"\\$");
|
||||
jsonataFunctions = "("+jsonataFunctions.join("|").replace(/\$/g,"\\$")+")(\\b)";
|
||||
|
||||
var JSONataHighlightRules = function() {
|
||||
|
||||
@@ -27,12 +27,17 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
|
||||
"function"
|
||||
}, "identifier");
|
||||
this.$rules = {
|
||||
"start" : [
|
||||
"no_regex" : [
|
||||
{
|
||||
token: "string.regexp",
|
||||
regex: "\\/",
|
||||
next: "regex"
|
||||
token : "comment.doc", // doc comment
|
||||
regex : "\\/\\*",
|
||||
next : "comments"
|
||||
},
|
||||
// {
|
||||
// token: "string.regexp",
|
||||
// regex: "\\/",
|
||||
// next: "regex"
|
||||
// },
|
||||
{
|
||||
token : "string",
|
||||
regex : "'(?=.)",
|
||||
@@ -91,7 +96,7 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
|
||||
{
|
||||
token : "string",
|
||||
regex : '"|$',
|
||||
next : "start"
|
||||
next : "no_regex"
|
||||
},
|
||||
{
|
||||
defaultToken: "string"
|
||||
@@ -101,7 +106,7 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
|
||||
{
|
||||
token : "string",
|
||||
regex : "'|$",
|
||||
next : "start"
|
||||
next : "no_regex"
|
||||
},
|
||||
{
|
||||
defaultToken: "string"
|
||||
@@ -110,15 +115,37 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
|
||||
"regex" : [
|
||||
{
|
||||
token: "string.regexp",
|
||||
regex: "\\\\/"
|
||||
regex: "/[sxngimy]*",
|
||||
next: "start"
|
||||
}, {
|
||||
defaultToken: "string.regexp"
|
||||
}
|
||||
],
|
||||
"start": [
|
||||
{
|
||||
token : "comment.doc", // doc comment
|
||||
regex : "\\/\\*",
|
||||
next : "comments"
|
||||
},
|
||||
{
|
||||
token: "string.regexp",
|
||||
regex: "/[sxngimy]*",
|
||||
next: "start"
|
||||
regex: "\\/",
|
||||
next: "regex",
|
||||
},{
|
||||
// immediately return to the start mode without matching
|
||||
// anything
|
||||
token: "empty",
|
||||
regex: "",
|
||||
next: "no_regex"
|
||||
}],
|
||||
"comments": [
|
||||
{
|
||||
token : "comment.doc", // doc comment
|
||||
regex : "\\*\\/",
|
||||
next : "start"
|
||||
},
|
||||
{
|
||||
defaultToken: "string.regexp"
|
||||
defaultToken: "comment.doc"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@@ -98,7 +98,7 @@ module.exports = function(RED) {
|
||||
node.repeaterSetup();
|
||||
}
|
||||
|
||||
this.on("input", function(msg) {
|
||||
this.on("input", function(msg, send, done) {
|
||||
var errors = [];
|
||||
|
||||
this.props.forEach(p => {
|
||||
@@ -128,9 +128,10 @@ module.exports = function(RED) {
|
||||
});
|
||||
|
||||
if (errors.length) {
|
||||
node.error(errors.join('; '), msg);
|
||||
done(errors.join('; '));
|
||||
} else {
|
||||
node.send(msg);
|
||||
send(msg);
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -21,8 +21,11 @@ module.exports = function(RED) {
|
||||
this.tosidebar = n.tosidebar;
|
||||
if (this.tosidebar === undefined) { this.tosidebar = true; }
|
||||
this.active = (n.active === null || typeof n.active === "undefined") || n.active;
|
||||
if (this.tostatus) { this.status({fill:"grey", shape:"ring"}); }
|
||||
else { this.status({}); }
|
||||
if (this.tostatus) {
|
||||
this.status({fill:"grey", shape:"ring"});
|
||||
this.oldState = "{}";
|
||||
}
|
||||
|
||||
var hasStatExpression = (n.statusType === "jsonata");
|
||||
var statExpression = hasStatExpression ? n.statusVal : null;
|
||||
|
||||
@@ -97,7 +100,11 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.on("close", function() {
|
||||
if (this.oldState) {
|
||||
this.status({});
|
||||
}
|
||||
})
|
||||
this.on("input", function(msg, send, done) {
|
||||
if (msg.hasOwnProperty("status") && msg.status.hasOwnProperty("source") && msg.status.source.hasOwnProperty("id") && (msg.status.source.id === node.id)) {
|
||||
done();
|
||||
@@ -202,13 +209,8 @@ module.exports = function(RED) {
|
||||
function setNodeState(node,state) {
|
||||
if (state) {
|
||||
node.active = true;
|
||||
if (node.tostatus) { node.status({fill:"grey", shape:"dot"}); }
|
||||
} else {
|
||||
node.active = false;
|
||||
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
|
||||
node.oldStatus.shape = "dot";
|
||||
node.status(node.oldStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -21,8 +21,9 @@ module.exports = function(RED) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
this.scope = n.scope;
|
||||
this.on("input",function(msg) {
|
||||
this.send(msg);
|
||||
this.on("input",function(msg, send, done) {
|
||||
send(msg);
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -22,8 +22,9 @@ module.exports = function(RED) {
|
||||
var node = this;
|
||||
this.scope = n.scope;
|
||||
this.uncaught = n.uncaught;
|
||||
this.on("input",function(msg) {
|
||||
this.send(msg);
|
||||
this.on("input",function(msg, send, done) {
|
||||
send(msg);
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -21,8 +21,9 @@ module.exports = function(RED) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
this.scope = n.scope;
|
||||
this.on("input", function(msg) {
|
||||
this.send(msg);
|
||||
this.on("input", function(msg, send, done) {
|
||||
send(msg);
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -26,8 +26,9 @@ module.exports = function(RED) {
|
||||
node.receive(msg);
|
||||
}
|
||||
RED.events.on(event,handler);
|
||||
this.on("input", function(msg) {
|
||||
this.send(msg);
|
||||
this.on("input", function(msg, send, done) {
|
||||
send(msg);
|
||||
done();
|
||||
});
|
||||
this.on("close",function() {
|
||||
RED.events.removeListener(event,handler);
|
||||
@@ -40,10 +41,11 @@ module.exports = function(RED) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
var event = "node:"+n.id;
|
||||
this.on("input", function(msg) {
|
||||
this.on("input", function(msg, send, done) {
|
||||
msg._event = event;
|
||||
RED.events.emit(event,msg)
|
||||
this.send(msg);
|
||||
send(msg);
|
||||
done();
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("link out",LinkOutNode);
|
||||
|
@@ -121,12 +121,14 @@ module.exports = function(RED) {
|
||||
"done:__done__"+
|
||||
"};\n"+
|
||||
node.func+"\n"+
|
||||
"})(msg,send,done);";
|
||||
"})(msg,__send__,__done__);";
|
||||
var finScript = null;
|
||||
var finOpt = null;
|
||||
node.topic = n.topic;
|
||||
node.outstandingTimers = [];
|
||||
node.outstandingIntervals = [];
|
||||
node.clearStatus = false;
|
||||
|
||||
var sandbox = {
|
||||
console:console,
|
||||
util:util,
|
||||
@@ -163,6 +165,7 @@ module.exports = function(RED) {
|
||||
node.on.apply(node, arguments);
|
||||
},
|
||||
status: function() {
|
||||
node.clearStatus = true;
|
||||
node.status.apply(node, arguments);
|
||||
}
|
||||
},
|
||||
@@ -268,7 +271,23 @@ module.exports = function(RED) {
|
||||
var iniScript = null;
|
||||
var iniOpt = null;
|
||||
if (node.ini && (node.ini !== "")) {
|
||||
var iniText = "(async function () {\n"+node.ini +"\n})();";
|
||||
var iniText = `
|
||||
(async function(__send__) {
|
||||
var node = {
|
||||
id:__node__.id,
|
||||
name:__node__.name,
|
||||
log:__node__.log,
|
||||
error:__node__.error,
|
||||
warn:__node__.warn,
|
||||
debug:__node__.debug,
|
||||
trace:__node__.trace,
|
||||
status:__node__.status,
|
||||
send: function(msgs, cloneMsg) {
|
||||
__node__.send(__send__, RED.util.generateId(), msgs, cloneMsg);
|
||||
}
|
||||
};
|
||||
`+ node.ini +`
|
||||
})(__initSend__);`;
|
||||
iniOpt = createVMOpt(node, " setup");
|
||||
iniScript = new vm.Script(iniText, iniOpt);
|
||||
}
|
||||
@@ -280,14 +299,15 @@ module.exports = function(RED) {
|
||||
}
|
||||
var promise = Promise.resolve();
|
||||
if (iniScript) {
|
||||
context.__initSend__ = function(msgs) { node.send(msgs); };
|
||||
promise = iniScript.runInContext(context, iniOpt);
|
||||
}
|
||||
|
||||
function processMessage(msg, send, done) {
|
||||
var start = process.hrtime();
|
||||
context.msg = msg;
|
||||
context.send = send;
|
||||
context.done = done;
|
||||
context.__send__ = send;
|
||||
context.__done__ = done;
|
||||
|
||||
node.script.runInContext(context);
|
||||
context.results.then(function(results) {
|
||||
@@ -372,7 +392,9 @@ module.exports = function(RED) {
|
||||
while (node.outstandingIntervals.length > 0) {
|
||||
clearInterval(node.outstandingIntervals.pop());
|
||||
}
|
||||
node.status({});
|
||||
if (node.clearStatus) {
|
||||
node.status({});
|
||||
}
|
||||
});
|
||||
|
||||
promise.then(function (v) {
|
||||
|
@@ -27,7 +27,7 @@ module.exports = function(RED) {
|
||||
this.property = n.property||"payload";
|
||||
var node = this;
|
||||
|
||||
this.on('input', function (msg) {
|
||||
this.on('input', function (msg, send, done) {
|
||||
var value = RED.util.getMessageProperty(msg,node.property);
|
||||
if (value !== undefined) {
|
||||
var n = Number(value);
|
||||
@@ -43,11 +43,12 @@ module.exports = function(RED) {
|
||||
value = ((n - node.minin) / (node.maxin - node.minin) * (node.maxout - node.minout)) + node.minout;
|
||||
if (node.round) { value = Math.round(value); }
|
||||
RED.util.setMessageProperty(msg,node.property,value);
|
||||
node.send(msg);
|
||||
send(msg);
|
||||
}
|
||||
else { node.log(RED._("range.errors.notnumber")+": "+value); }
|
||||
}
|
||||
else { node.send(msg); } // If no payload - just pass it on.
|
||||
else { send(msg); } // If no payload - just pass it on.
|
||||
done();
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("range", RangeNode);
|
||||
|
@@ -107,7 +107,7 @@ module.exports = function(RED) {
|
||||
|
||||
var node = this;
|
||||
|
||||
function output(msg,value) {
|
||||
function output(msg,value,send,done) {
|
||||
/* istanbul ignore else */
|
||||
if (node.outputFormat === "json") {
|
||||
value = JSON.parse(value);
|
||||
@@ -119,22 +119,24 @@ module.exports = function(RED) {
|
||||
|
||||
if (node.fieldType === 'msg') {
|
||||
RED.util.setMessageProperty(msg, node.field, value);
|
||||
node.send(msg);
|
||||
send(msg);
|
||||
done();
|
||||
} else if ((node.fieldType === 'flow') ||
|
||||
(node.fieldType === 'global')) {
|
||||
var context = RED.util.parseContextStore(node.field);
|
||||
var target = node.context()[node.fieldType];
|
||||
target.set(context.key, value, context.store, function (err) {
|
||||
if (err) {
|
||||
node.error(err, msg);
|
||||
done(err);
|
||||
} else {
|
||||
node.send(msg);
|
||||
send(msg);
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
node.on("input", function(msg) {
|
||||
node.on("input", function(msg, send, done) {
|
||||
|
||||
try {
|
||||
/***
|
||||
@@ -179,16 +181,16 @@ module.exports = function(RED) {
|
||||
|
||||
Promise.all(promises).then(function() {
|
||||
var value = mustache.render(template, new NodeContext(msg, node.context(), null, is_json, resolvedTokens));
|
||||
output(msg, value);
|
||||
output(msg, value, send, done);
|
||||
}).catch(function (err) {
|
||||
node.error(err.message,msg);
|
||||
done(err.message);
|
||||
});
|
||||
} else {
|
||||
output(msg, template);
|
||||
output(msg, template, send, done);
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
node.error(err.message, msg);
|
||||
done(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -42,6 +42,10 @@
|
||||
<label></label>
|
||||
<input type="checkbox" id="node-input-extend" style="margin-left:0px; vertical-align:top; width:auto !important;"> <label style="width:auto !important;" for="node-input-extend" data-i18n="trigger.extend"></label>
|
||||
</div>
|
||||
<div class="form-row node-type-override">
|
||||
<label></label>
|
||||
<input type="checkbox" id="node-input-overrideDelay" style="margin-left:0px; vertical-align:top; width:auto !important;"> <label style="width:auto !important;" for="node-input-overrideDelay" data-i18n="trigger.override"></label>
|
||||
</div>
|
||||
<div class="form-row node-type-wait">
|
||||
<label data-i18n="trigger.then-send"></label>
|
||||
<input type="hidden" id="node-input-op2type">
|
||||
@@ -89,6 +93,7 @@
|
||||
op2type: {value:"val"},
|
||||
duration: {value:"250",required:true,validate:RED.validators.number()},
|
||||
extend: {value:"false"},
|
||||
overrideDelay: {value:"false"},
|
||||
units: {value:"ms"},
|
||||
reset: {value:""},
|
||||
bytopic: {value:"all"},
|
||||
@@ -126,7 +131,7 @@
|
||||
|
||||
if (this.outputs == 2) { $("#node-input-second").prop('checked', true) }
|
||||
else { $("#node-input-second").prop('checked', false) }
|
||||
|
||||
|
||||
$("#node-input-second").change(function() {
|
||||
if ($("#node-input-second").is(":checked")) {
|
||||
$("#node-input-outputs").val(2);
|
||||
@@ -138,6 +143,7 @@
|
||||
$("#node-then-type").on("change", function() {
|
||||
if ($(this).val() == "block") {
|
||||
$(".node-type-wait").hide();
|
||||
$(".node-type-override").hide();
|
||||
$(".node-type-duration").hide();
|
||||
$("#node-second-output").hide();
|
||||
$("#node-input-second").prop('checked', false);
|
||||
@@ -146,6 +152,7 @@
|
||||
else if ($(this).val() == "loop") {
|
||||
if ($("#node-input-duration").val() == 0) { $("#node-input-duration").val(250); }
|
||||
$(".node-type-wait").hide();
|
||||
$(".node-type-override").show();
|
||||
$(".node-type-duration").show();
|
||||
$("#node-second-output").hide();
|
||||
$("#node-input-second").prop('checked', false);
|
||||
@@ -153,6 +160,7 @@
|
||||
} else {
|
||||
if ($("#node-input-duration").val() == 0) { $("#node-input-duration").val(250); }
|
||||
$(".node-type-wait").show();
|
||||
$(".node-type-override").show();
|
||||
$(".node-type-duration").show();
|
||||
$("#node-second-output").show();
|
||||
}
|
||||
@@ -208,7 +216,11 @@
|
||||
} else {
|
||||
$("#node-input-extend").prop("checked",false);
|
||||
}
|
||||
|
||||
if (this.overrideDelay === "true" || this.overrideDelay === true) {
|
||||
$("#node-input-overrideDelay").prop("checked",true);
|
||||
} else {
|
||||
$("#node-input-overrideDelay").prop("checked",false);
|
||||
}
|
||||
},
|
||||
oneditsave: function() {
|
||||
if ($("#node-then-type").val() == "block") {
|
||||
|
@@ -48,6 +48,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
this.extend = n.extend || "false";
|
||||
this.overrideDelay = n.overrideDelay || false;
|
||||
this.units = n.units || "ms";
|
||||
this.reset = n.reset || '';
|
||||
this.duration = parseFloat(n.duration);
|
||||
@@ -117,12 +118,16 @@ module.exports = function(RED) {
|
||||
var l = Object.keys(node.topics).length;
|
||||
if (l === 0) { return {} }
|
||||
else if (l === 1) { return {fill:"blue",shape:"dot"} }
|
||||
else return {fill:"blue",shape:"dot",text:l};
|
||||
else return {fill:"blue",shape:"dot",text:l};
|
||||
}
|
||||
|
||||
var processMessage = function(msg) {
|
||||
var topic = RED.util.getMessageProperty(msg,node.topic) || "_none";
|
||||
var promise;
|
||||
var delayDuration = node.duration;
|
||||
if (node.overrideDelay && msg.hasOwnProperty("delay") && !isNaN(parseFloat(msg.delay))) {
|
||||
delayDuration = parseFloat(msg.delay);
|
||||
}
|
||||
if (node.bytopic === "all") { topic = "_none"; }
|
||||
node.topics[topic] = node.topics[topic] || {};
|
||||
if (msg.hasOwnProperty("reset") || ((node.reset !== '') && msg.hasOwnProperty("payload") && (msg.payload !== null) && msg.payload.toString && (msg.payload.toString() == node.reset)) ) {
|
||||
@@ -167,14 +172,14 @@ module.exports = function(RED) {
|
||||
});
|
||||
}
|
||||
return promise.then(() => {
|
||||
if (node.duration === 0) { node.topics[topic].tout = 0; }
|
||||
if (delayDuration === 0) { node.topics[topic].tout = 0; }
|
||||
else if (node.loop === true) {
|
||||
/* istanbul ignore else */
|
||||
if (node.topics[topic].tout) { clearInterval(node.topics[topic].tout); }
|
||||
/* istanbul ignore else */
|
||||
if (node.op1type !== "nul") {
|
||||
var msg2 = RED.util.cloneMessage(msg);
|
||||
node.topics[topic].tout = setInterval(function() { node.send(RED.util.cloneMessage(msg2)); }, node.duration);
|
||||
node.topics[topic].tout = setInterval(function() { node.send(RED.util.cloneMessage(msg2)); }, delayDuration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -217,7 +222,7 @@ module.exports = function(RED) {
|
||||
node.status(stat());
|
||||
}
|
||||
|
||||
}, node.duration);
|
||||
}, delayDuration);
|
||||
}
|
||||
}
|
||||
node.status(stat());
|
||||
@@ -225,7 +230,7 @@ module.exports = function(RED) {
|
||||
});
|
||||
});
|
||||
}
|
||||
else if ((node.extend === "true" || node.extend === true) && (node.duration > 0)) {
|
||||
else if ((node.extend === "true" || node.extend === true) && (delayDuration > 0)) {
|
||||
/* istanbul ignore else */
|
||||
if (node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
|
||||
/* istanbul ignore else */
|
||||
@@ -262,7 +267,7 @@ module.exports = function(RED) {
|
||||
}).catch(err => {
|
||||
node.error(err);
|
||||
});
|
||||
}, node.duration);
|
||||
}, delayDuration);
|
||||
}
|
||||
// else {
|
||||
// if (node.op2type === "payl") {node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
|
||||
|
@@ -281,7 +281,7 @@ module.exports = function(RED) {
|
||||
var node = this;
|
||||
this.headers = n.headers||{};
|
||||
this.statusCode = n.statusCode;
|
||||
this.on("input",function(msg) {
|
||||
this.on("input",function(msg,_send,done) {
|
||||
if (msg.res) {
|
||||
var headers = RED.util.cloneMessage(node.headers);
|
||||
if (msg.headers) {
|
||||
@@ -347,6 +347,7 @@ module.exports = function(RED) {
|
||||
} else {
|
||||
node.warn(RED._("httpin.errors.no-response"));
|
||||
}
|
||||
done();
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("http response",HTTPOut);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user