Compare commits

..

22 Commits

Author SHA1 Message Date
Nick O'Leary
81387396c0 Move vertical ports off the node to prevent crowding 2019-12-04 16:06:53 +00:00
Nick O'Leary
e2b7377ab7 Better vertical path routing 2019-11-25 11:15:48 +00:00
Nick O'Leary
fb1918d839 Update quick-add dialog handling for vertical flow 2019-11-22 22:09:09 +00:00
Nick O'Leary
5d5a112c2b Move node state icons to left edge 2019-11-22 20:51:06 +00:00
Nick O'Leary
4a6941a0d2 Various vertical flow layout tweaks
- ports are set off the node a bit more, with a bigger
   gap between them
 - status has moved to the top edge next to the input
 - change/error icons moved to top-left corner
2019-11-22 17:12:51 +00:00
Nick O'Leary
8e8cac60b0 Simplify vertical wire path 2019-11-22 15:40:59 +00:00
Nick O'Leary
61f42f9efa Align centre of nodes in vertical flow view 2019-11-21 22:08:24 +00:00
Nick O'Leary
fc590c66c0 Merge pull request #2386 from sakazuki/vertical-view
Vertical flow view
2019-11-21 22:06:55 +00:00
sakazuki
45a6348669 change default vertical option to false 2019-11-09 11:14:45 +09:00
sakazuki
981a9c4f8f fix hideLabel handling 2019-11-03 10:29:17 +09:00
sakazuki
22dd2cd084 fix position of status text, change & error mark 2019-11-02 16:44:51 +09:00
sakazuki
69d5ffe1ed adjust source position of link to draw 2019-11-02 13:52:58 +09:00
sakazuki
d3afa8fd47 bump to v1.0.2. wip 2019-11-02 11:57:13 +09:00
sakazuki
8b8bd83ec2 hand merge master 2019-04-30 16:14:58 +09:00
sakazuki
9f1ad64f5d bumpup to v0.20 2019-04-30 15:30:59 +09:00
sakazuki
c3bc3f3780 fix typo 2018-12-03 20:30:29 +09:00
sakazuki
43a07301fd fix scss 2018-12-02 14:42:14 +09:00
sakazuki
6de8b33769 fix typo 2018-12-02 14:27:48 +09:00
sakazuki
0950041d26 Add: user settings to switch flow view horizontal and vertical 2018-12-01 23:01:55 +09:00
sakazuki
cc584331ed add user settings and toggle virtical view 2018-12-01 22:54:14 +09:00
sakazuki
8c64b2a898 change flow view from horizontal to vertical 2018-12-01 13:29:38 +09:00
sakazuki
842e9d761e baseline 2018-12-01 13:28:19 +09:00
560 changed files with 6894 additions and 23091 deletions

View File

@@ -32,4 +32,3 @@ To help us understand the issue, please fill-in as much of the following informa
- [ ] npm version:
- [ ] Platform/OS:
- [ ] Browser:
- [ ] running in Docker:

View File

@@ -1,6 +1,6 @@
---
name: Bug report
about: Reproducible software issues in the core of Node-RED
about: Reproducable software issues in the core of Node-RED
title: ''
labels: ''
assignees: ''

View File

@@ -29,6 +29,6 @@ the [forum](https://discourse.nodered.org) or
<!-- Put an `x` in the boxes that apply -->
- [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
- [ ] For non-bugfix PRs, I have discussed this change on the forum/slack team.
- [ ] For non-bugfix PRs, I have discussed this change on the mailing list/slack team.
- [ ] I have run `grunt` to verify the unit tests pass
- [ ] I have added suitable unit tests to cover the new/changed functionality

View File

@@ -1,29 +0,0 @@
const fs = require("fs");
const newVersion = require("../../package.json").version;
if (process.env.GITHUB_REF !== "refs/tags/"+newVersion) {
console.log(`GITHUB_REF doesn't match the package.json version: ${process.env.GITHUB_REF} !== ${newVersion}`);
process.exit(0);
}
if (!/^\d+\.\d+\.\d+$/.test(newVersion)) {
console.log(`Not updating for a non-stable release - ${newVersion}`);
process.exit(0);
}
const currentVersion = require("../../../node-red-docker/package.json").version;
console.log(`Update from ${currentVersion} to ${newVersion}`)
updateFile(__dirname+"/../../../node-red-docker/package.json", currentVersion, newVersion);
updateFile(__dirname+"/../../../node-red-docker/docker-custom/package.json", currentVersion, newVersion);
updateFile(__dirname+"/../../../node-red-docker/README.md", currentVersion, newVersion);
console.log(`::set-env name=newVersion::${newVersion}`);
function updateFile(path,from,to) {
let contents = fs.readFileSync(path,"utf8");
contents = contents.replace(new RegExp(from.replace(/\./g,"\\."),"g"), to);
fs.writeFileSync(path, contents);
}

View File

@@ -1,18 +0,0 @@
const fs = require("fs");
const newVersion = require("../../package.json").version;
if (process.env.GITHUB_REF !== "refs/tags/"+newVersion) {
console.log(`GITHUB_REF doesn't match the package.json version: ${process.env.GITHUB_REF} !== ${newVersion}`);
process.exit(0);
}
if (!/^\d+\.\d+\.\d+$/.test(newVersion)) {
console.log(`Not updating for a non-stable release - ${newVersion}`);
process.exit(0);
}
const path = __dirname+"/../../../node-red.github.io/index.html";
let contents = fs.readFileSync(path, "utf8");
contents = contents.replace(/<span class="node-red-latest-version">v\d+\.\d+\.\d+<\/span>/, `<span class="node-red-latest-version">v${newVersion}<\/span>` );
fs.writeFileSync(path, contents);

View File

@@ -1,58 +0,0 @@
name: PublishDockerImage
on:
release:
types: [published]
jobs:
generate:
name: 'Update node-red-docker image'
runs-on: ubuntu-latest
steps:
- name: Check out node-red repository
uses: actions/checkout@v2
with:
path: 'node-red'
- name: Check out node-red-docker repository
uses: actions/checkout@v2
with:
repository: 'node-red/node-red-docker'
path: 'node-red-docker'
- name: Check out node-red.github.io repository
uses: actions/checkout@v2
with:
repository: 'node-red/node-red.github.io'
path: 'node-red.github.io'
- uses: actions/setup-node@v1
with:
node-version: '12'
- run: node ./node-red/.github/scripts/update-node-red-docker.js
- name: Create Docker Pull Request
uses: peter-evans/create-pull-request@v2
with:
token: ${{ secrets.NR_REPO_TOKEN }}
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
path: 'node-red-docker'
commit-message: 'Bump to ${{ env.newVersion }}'
title: '🚀 Update to Node-RED ${{ env.newVersion }} release'
body: |
Updates the Node-RED Docker repo for the ${{ env.newVersion }} release.
Once this is merged, you will need to create a new release with the tag `v${{ env.newVersion }}`.
This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary
- run: node ./node-red/.github/scripts/update-node-red-website.js
- name: Create Website Pull Request
uses: peter-evans/create-pull-request@v2
with:
token: ${{ secrets.NR_REPO_TOKEN }}
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
path: 'node-red.github.io'
commit-message: 'Bump to ${{ env.newVersion }}'
title: '🚀 Update to Node-RED ${{ env.newVersion }} release'
body: |
Updates the Node-RED Website repo for the ${{ env.newVersion }} release.
This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary

1
.gitignore vendored
View File

@@ -22,4 +22,3 @@ packages/node_modules/@node-red/editor-client/public
!test/**/node_modules
docs
!packages/node_modules/**/docs
.vscode

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,6 @@
var path = require("path");
var fs = require("fs-extra");
var sass = require("node-sass");
module.exports = function(grunt) {
@@ -26,13 +25,9 @@ module.exports = function(grunt) {
nodemonArgs.push(flowFile);
}
var browserstack = grunt.option('browserstack');
if (browserstack) {
process.env.BROWSERSTACK = true;
}
var nonHeadless = grunt.option('non-headless');
if (nonHeadless) {
process.env.NODE_RED_NON_HEADLESS = true;
process.env.NODE_RED_NON_HEADLESS = 'true';
}
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
@@ -84,20 +79,20 @@ module.exports = function(grunt) {
//"loopfunc": true, // allow functions to be defined in loops
//"sub": true // don't warn that foo['bar'] should be written as foo.bar
},
// all: [
// 'Gruntfile.js',
// 'red.js',
// 'packages/**/*.js'
// ],
// core: {
// files: {
// src: [
// 'Gruntfile.js',
// 'red.js',
// 'packages/**/*.js',
// ]
// }
// },
all: [
'Gruntfile.js',
'red.js',
'packages/**/*.js'
],
core: {
files: {
src: [
'Gruntfile.js',
'red.js',
'packages/**/*.js',
]
}
},
nodes: {
files: {
src: [ 'nodes/core/*/*.js' ]
@@ -105,7 +100,7 @@ module.exports = function(grunt) {
},
editor: {
files: {
src: [ 'packages/node_modules/@node-red/editor-client/src/js/**/*.js' ]
src: [ 'editor/js/**/*.js' ]
}
},
tests: {
@@ -125,7 +120,6 @@ module.exports = function(grunt) {
src: [
// Ensure editor source files are concatenated in
// the right order
"packages/node_modules/@node-red/editor-client/src/js/polyfills.js",
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
"packages/node_modules/@node-red/editor-client/src/js/red.js",
"packages/node_modules/@node-red/editor-client/src/js/events.js",
@@ -152,7 +146,6 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
@@ -165,8 +158,6 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
@@ -181,7 +172,6 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/group.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
@@ -194,12 +184,11 @@ module.exports = function(grunt) {
vendor: {
files: {
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.4.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.0.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"node_modules/marked/marked.min.js",
"node_modules/dompurify/dist/purify.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js",
"node_modules/jsonata/jsonata-es5.min.js",
@@ -231,7 +220,6 @@ module.exports = function(grunt) {
sass: {
build: {
options: {
implementation: sass,
outputStyle: 'compressed'
},
files: [{
@@ -623,10 +611,6 @@ module.exports = function(grunt) {
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']);
grunt.registerTask('dev',
'Developer mode: run node-red, watch for source changes and build/restart',

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "1.1.3",
"version": "1.0.2",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -13,8 +13,6 @@
"start": "node packages/node_modules/node-red/red.js",
"test": "grunt",
"build": "grunt build",
"dev": "grunt dev",
"build-dev": "grunt build-dev",
"docs": "grunt docs"
},
"contributors": [
@@ -26,62 +24,57 @@
}
],
"dependencies": {
"ajv": "6.12.3",
"ajv": "6.10.2",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"cheerio": "0.22.0",
"clone": "2.1.2",
"content-type": "1.0.4",
"cookie": "0.4.1",
"cookie-parser": "1.4.5",
"cookie": "0.4.0",
"cookie-parser": "1.4.4",
"cors": "2.8.5",
"cron": "1.7.2",
"cron": "1.7.1",
"denque": "1.4.1",
"express": "4.17.1",
"express-session": "1.17.1",
"express-session": "1.16.2",
"fs-extra": "8.1.0",
"fs.notify": "0.0.4",
"hash-sum": "2.0.0",
"https-proxy-agent": "5.0.0",
"https-proxy-agent": "2.2.2",
"i18next": "15.1.2",
"iconv-lite": "0.6.2",
"iconv-lite": "0.5.0",
"is-utf8": "0.2.1",
"js-yaml": "3.14.0",
"js-yaml": "3.13.1",
"json-stringify-safe": "5.0.1",
"jsonata": "1.8.3",
"lodash.clonedeep": "^4.5.0",
"jsonata": "1.6.5",
"media-typer": "1.1.0",
"memorystore": "1.6.2",
"mime": "2.4.6",
"moment-timezone": "^0.5.31",
"memorystore": "1.6.1",
"mime": "2.4.4",
"mqtt": "2.18.8",
"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",
"mustache": "3.0.2",
"node-red-node-rbe": "^0.2.5",
"node-red-node-sentiment": "^0.1.4",
"node-red-node-tail": "^0.0.3",
"nopt": "4.0.1",
"oauth2orize": "1.11.0",
"on-headers": "1.0.2",
"passport": "0.4.1",
"passport": "0.4.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"raw-body": "2.4.1",
"request": "2.88.0",
"semver": "6.3.0",
"uglify-js": "3.10.0",
"uglify-js": "3.6.0",
"when": "3.7.8",
"ws": "6.2.1",
"xml2js": "0.4.23"
"xml2js": "0.4.19"
},
"optionalDependencies": {
"bcrypt": "3.0.8"
"bcrypt": "3.0.6"
},
"devDependencies": {
"marked": "0.8.2",
"dompurify": "2.0.12",
"grunt": "~1.0.4",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.3.2",
@@ -100,20 +93,19 @@
"grunt-mocha-istanbul": "5.0.2",
"grunt-nodemon": "~0.4.2",
"grunt-npm-command": "~0.1.2",
"grunt-sass": "~3.1.0",
"grunt-sass": "~2.0.0",
"grunt-simple-mocha": "~0.4.1",
"http-proxy": "1.18.1",
"http-proxy": "^1.16.2",
"istanbul": "0.4.5",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"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",
"sinon": "1.17.7",
"stoppable": "^1.1.0",
"supertest": "3.4.2"
"supertest": "3.4.2",
"node-red-node-test-helper": "^0.2.3",
"jsdoc-nr-template": "node-red/jsdoc-nr-template"
},
"engines": {
"node": ">=8"

View File

@@ -21,17 +21,15 @@ var flows = require("./flows");
var flow = require("./flow");
var context = require("./context");
var auth = require("../auth");
var info = require("./settings");
var apiUtil = require("../util");
module.exports = {
init: function(settings,runtimeAPI) {
init: function(runtimeAPI) {
flows.init(runtimeAPI);
flow.init(runtimeAPI);
nodes.init(runtimeAPI);
context.init(runtimeAPI);
info.init(settings,runtimeAPI);
var needsPermission = auth.needsPermission;
@@ -69,8 +67,6 @@ module.exports = {
// adminApp.delete("/context/:scope(node|flow)/:id",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
adminApp.delete("/context/:scope(node|flow)/:id/*",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
adminApp.get("/settings",needsPermission("settings.read"),info.runtimeSettings,apiUtil.errorHandler);
return adminApp;
}
}

View File

@@ -44,7 +44,6 @@ module.exports = {
user: req.user,
module: req.body.module,
version: req.body.version,
url: req.body.url,
req: apiUtils.getRequestLogObject(req)
}
runtimeAPI.nodes.addModule(opts).then(function(info) {

View File

@@ -1,72 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var apiUtils = require("../util");
var runtimeAPI;
var settings;
var theme = require("../editor/theme");
var clone = require("clone");
var i18n = require("@node-red/util").i18n
function extend(target, source) {
var keys = Object.keys(source);
var i = keys.length;
while(i--) {
var value = source[keys[i]]
var type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) {
target[keys[i]] = value;
} else if (value === null) {
if (target.hasOwnProperty(keys[i])) {
delete target[keys[i]];
}
} else {
// Object
if (target.hasOwnProperty(keys[i])) {
target[keys[i]] = extend(target[keys[i]],value);
} else {
target[keys[i]] = value;
}
}
}
return target;
}
module.exports = {
init: function(_settings,_runtimeAPI) {
runtimeAPI = _runtimeAPI;
settings = _settings;
},
runtimeSettings: function(req,res) {
var opts = {
user: req.user
}
runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) {
if (!settings.disableEditor) {
result.editorTheme = result.editorTheme||{};
var themeSettings = theme.settings();
if (themeSettings) {
// result.editorTheme may already exist with the palette
// disabled. Need to merge that into the receive settings
result.editorTheme = extend(clone(themeSettings),result.editorTheme);
}
result.editorTheme.languages = i18n.availableLanguages("editor");
}
res.json(result);
});
},
}

View File

@@ -36,7 +36,6 @@ var log = require("@node-red/util").log; // TODO: separate module
passport.use(strategies.bearerStrategy.BearerStrategy);
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
passport.use(strategies.anonymousStrategy);
passport.use(strategies.tokensStrategy);
var server = oauth2orize.createServer();
@@ -61,7 +60,7 @@ function init(_settings,storage) {
function needsPermission(permission) {
return function(req,res,next) {
if (settings && settings.adminAuth) {
return passport.authenticate(['bearer','tokens','anon'],{ session: false })(req,res,function() {
return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() {
if (!req.user) {
return next();
}
@@ -101,10 +100,7 @@ function login(req,res) {
}
} else if (mergedAdminAuth.type === "strategy") {
var urlPrefix = (settings.httpAdminRoot||"").replace(/\/$/,"");
if (urlPrefix.length > 0) {
urlPrefix += "/";
}
var urlPrefix = (settings.httpAdminRoot==='/')?"":settings.httpAdminRoot;
response = {
"type":"strategy",
"prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]

View File

@@ -123,57 +123,9 @@ AnonymousStrategy.prototype.authenticate = function(req) {
});
}
function authenticateUserToken(req) {
return new Promise( (resolve,reject) => {
var token = null;
var tokenHeader = Users.tokenHeader();
if (Users.tokenHeader() === null) {
// No custom user token provided. Fail the request
reject();
return;
} else if (Users.tokenHeader() === 'authorization') {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
token = req.headers.authorization.split(' ')[1];
}
} else {
token = req.headers[Users.tokenHeader()];
}
if (token) {
Users.tokens(token).then(function(user) {
if (user) {
resolve(user);
} else {
reject();
}
});
} else {
reject();
}
});
}
function TokensStrategy() {
passport.Strategy.call(this);
this.name = 'tokens';
}
util.inherits(TokensStrategy, passport.Strategy);
TokensStrategy.prototype.authenticate = function(req) {
authenticateUserToken(req).then(user => {
this.success(user,{scope:user.permissions});
}).catch(err => {
this.fail(401);
});
}
module.exports = {
bearerStrategy: bearerStrategy,
clientPasswordStrategy: clientPasswordStrategy,
passwordTokenExchange: passwordTokenExchange,
anonymousStrategy: new AnonymousStrategy(),
tokensStrategy: new TokensStrategy(),
authenticateUserToken: authenticateUserToken
anonymousStrategy: new AnonymousStrategy()
}

View File

@@ -59,9 +59,7 @@ function getDefaultUser() {
var api = {
get: get,
authenticate: authenticate,
default: getDefaultUser,
tokens: getDefaultUser,
tokenHeader: null
default: getDefaultUser
}
function init(config) {
@@ -107,14 +105,6 @@ function init(config) {
} else {
api.default = getDefaultUser;
}
if (config.tokens && typeof config.tokens === "function") {
api.tokens = config.tokens;
if (config.tokenHeader && typeof config.tokenHeader === "string") {
api.tokenHeader = config.tokenHeader.toLowerCase();
} else {
api.tokenHeader = "authorization";
}
}
}
function cleanUser(user) {
if (user && user.hasOwnProperty('password')) {
@@ -128,7 +118,5 @@ module.exports = {
init: init,
get: function(username) { return api.get(username).then(cleanUser)},
authenticate: function() { return api.authenticate.apply(null, arguments) },
default: function() { return api.default(); },
tokens: function(token) { return api.tokens(token); },
tokenHeader: function() { return api.tokenHeader }
default: function() { return api.default(); }
};

View File

@@ -21,7 +21,6 @@ var log = require("@node-red/util").log; // TODO: separate module
var Tokens;
var Users;
var Permissions;
var Strategies;
var server;
var settings;
@@ -45,7 +44,6 @@ function init(_server,_settings,_runtimeAPI) {
Tokens.onSessionExpiry(handleSessionExpiry);
Users = require("../auth/users");
Permissions = require("../auth/permissions");
Strategies = require("../auth/strategies");
}
function handleSessionExpiry(session) {
@@ -65,18 +63,17 @@ function generateSession(length) {
return token.join("");
}
function CommsConnection(ws, user) {
function CommsConnection(ws) {
this.session = generateSession(32);
this.ws = ws;
this.stack = [];
this.user = user;
this.user = null;
this.lastSentTime = 0;
var self = this;
log.audit({event: "comms.open"});
log.trace("comms.open "+self.session);
var preAuthed = !!user;
var pendingAuth = !this.user && (settings.adminAuth != null);
var pendingAuth = (settings.adminAuth != null);
if (!pendingAuth) {
addActiveConnection(self);
@@ -133,16 +130,8 @@ function CommsConnection(ws, user) {
}
});
} else {
Users.tokens(msg.auth).then(function(user) {
if (user) {
self.user = user;
log.audit({event: "comms.auth",user:self.user});
completeConnection(user.permissions,msg.auth,true);
} else {
log.audit({event: "comms.auth.fail"});
completeConnection(null,null,false);
}
});
log.audit({event: "comms.auth.fail"});
completeConnection(null,null,false);
}
});
} else {
@@ -202,8 +191,8 @@ function start() {
var commsPath = settings.httpAdminRoot || "/";
commsPath = (commsPath.slice(0,1) != "/" ? "/":"") + commsPath + (commsPath.slice(-1) == "/" ? "":"/") + "comms";
wsServer = new ws.Server({ noServer: true });
wsServer.on('connection',function(ws, request, user) {
var commsConnection = new CommsConnection(ws, user);
wsServer.on('connection',function(ws) {
var commsConnection = new CommsConnection(ws);
});
wsServer.on('error', function(err) {
log.warn(log._("comms.error-server",{message:err.toString()}));
@@ -212,26 +201,8 @@ function start() {
server.on('upgrade', function upgrade(request, socket, head) {
const pathname = url.parse(request.url).pathname;
if (pathname === commsPath) {
if (Users.tokenHeader() !== null && request.headers[Users.tokenHeader()]) {
// The user has provided custom token handling. For the websocket,
// the token could be provided in two ways:
// - as an http header (only possible with a reverse proxy setup)
// - passed over the connected websock in an auth packet
// If the header is present, verify the token. If not, use the auth
// packet over the connected socket
//
Strategies.authenticateUserToken(request).then(user => {
wsServer.handleUpgrade(request, socket, head, function done(ws) {
wsServer.emit('connection', ws, request, user);
});
}).catch(err => {
log.audit({event: "comms.auth.fail"});
socket.destroy();
})
return
}
wsServer.handleUpgrade(request, socket, head, function done(ws) {
wsServer.emit('connection', ws, request, null);
wsServer.emit('connection', ws, request);
});
}
// Don't destroy the socket as other listeners may want to handle the

View File

@@ -88,13 +88,13 @@ module.exports = {
// Locales
var locales = require("./locales");
locales.init(runtimeAPI);
editorApp.get(/^\/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler);
editorApp.get(/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler);
// Library
var library = require("./library");
library.init(runtimeAPI);
editorApp.get(/^\/library\/([^\/]+)\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry);
editorApp.post(/^\/library\/([^\/]+)\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry);
editorApp.get(/library\/([^\/]+)\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry);
editorApp.post(/library\/([^\/]+)\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry);
// Credentials
@@ -103,7 +103,7 @@ module.exports = {
editorApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,apiUtil.errorHandler);
// Settings
// Main /settings route is an admin route - see lib/admin/settings.js
editorApp.get("/settings",needsPermission("settings.read"),info.runtimeSettings,apiUtil.errorHandler);
// User Settings
editorApp.get("/settings/user",needsPermission("settings.read"),info.userSettings,apiUtil.errorHandler);
// User Settings

View File

@@ -15,7 +15,7 @@
**/
var fs = require('fs');
var path = require('path');
// var apiUtil = require('../util');
//var apiUtil = require('../util');
var i18n = require("@node-red/util").i18n; // TODO: separate module
@@ -41,7 +41,7 @@ module.exports = {
var namespace = req.params[0];
var lngs = req.query.lng;
namespace = namespace.replace(/\.json$/,"");
var lang = req.query.lng || i18n.defaultLang; //apiUtil.determineLangFromHeaders(req.acceptsLanguages() || []);
var lang = req.query.lng; //apiUtil.determineLangFromHeaders(req.acceptsLanguages() || []);
var prevLang = i18n.i.language;
// Trigger a load from disk of the language if it is not the default
i18n.i.changeLanguage(lang, function(){

View File

@@ -16,12 +16,56 @@
var apiUtils = require("../util");
var runtimeAPI;
var sshkeys = require("./sshkeys");
var theme = require("./theme");
var clone = require("clone");
var i18n = require("@node-red/util").i18n
function extend(target, source) {
var keys = Object.keys(source);
var i = keys.length;
while(i--) {
var value = source[keys[i]]
var type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) {
target[keys[i]] = value;
} else if (value === null) {
if (target.hasOwnProperty(keys[i])) {
delete target[keys[i]];
}
} else {
// Object
if (target.hasOwnProperty(keys[i])) {
target[keys[i]] = extend(target[keys[i]],value);
} else {
target[keys[i]] = value;
}
}
}
return target;
}
module.exports = {
init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI;
sshkeys.init(runtimeAPI);
},
runtimeSettings: function(req,res) {
var opts = {
user: req.user
}
runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) {
result.editorTheme = result.editorTheme||{};
var themeSettings = theme.settings();
if (themeSettings) {
// result.editorTheme may already exist with the palette
// disabled. Need to merge that into the receive settings
result.editorTheme = extend(clone(themeSettings),result.editorTheme);
}
result.editorTheme.languages = i18n.availableLanguages("editor");
res.json(result);
});
},
userSettings: function(req, res) {
var opts = {
user: req.user

View File

@@ -42,7 +42,7 @@ var editor;
/**
* Initialise the module.
* @param {Object} settings The runtime settings
* @param {HTTPServer} _server An instance of HTTP Server
* @param {HTTPServer} server An instance of HTTP Server
* @param {Storage} storage An instance of Node-RED Storage
* @param {Runtime} runtimeAPI An instance of Node-RED Runtime
* @memberof @node-red/editor-api
@@ -59,12 +59,6 @@ function init(settings,_server,storage,runtimeAPI) {
});
adminApp.use(corsHandler);
if (settings.httpAdminMiddleware) {
if (typeof settings.httpAdminMiddleware === "function") {
adminApp.use(settings.httpAdminMiddleware)
}
}
auth.init(settings,storage);
var maxApiRequestSize = settings.apiMaxLength || '5mb';
@@ -99,7 +93,7 @@ function init(settings,_server,storage,runtimeAPI) {
adminApp.use(corsHandler);
}
var adminApiApp = require("./admin").init(settings, runtimeAPI);
var adminApiApp = require("./admin").init(runtimeAPI);
adminApp.use(adminApiApp);
} else {
adminApp = null;

View File

@@ -43,16 +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);
var response = {
res.status(err.status||400).json({
code: err.code||"unexpected_error",
message: err.message||err.toString()
};
// Handle auth failures on a specific remote
// TODO: don't hardcode this here - allow users of rejectHandler to identify extra props to send
if (err.remote) {
response.remote = err.remote;
}
res.status(err.status||400).json(response);
});
},
getRequestLogObject: function(req) {
return {

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "1.1.3",
"version": "1.0.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,21 +16,21 @@
}
],
"dependencies": {
"@node-red/util": "1.1.3",
"@node-red/editor-client": "1.1.3",
"@node-red/util": "1.0.2",
"@node-red/editor-client": "1.0.2",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"clone": "2.1.2",
"cors": "2.8.5",
"express-session": "1.17.1",
"express-session": "1.16.2",
"express": "4.17.1",
"memorystore": "1.6.2",
"mime": "2.4.6",
"mustache": "4.0.1",
"memorystore": "1.6.1",
"mime": "2.4.4",
"mustache": "3.0.2",
"oauth2orize": "1.11.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"passport": "0.4.1",
"passport": "0.4.0",
"when": "3.7.8",
"ws": "6.2.1"
},

View File

@@ -34,11 +34,11 @@
"view" : "Ansicht",
"grid" : "Gitter",
"showGrid" : "Raster anzeigen",
"snapGrid" : "Am Raster ausrichten",
"snapGrid" : "Einrasten am Raster",
"gridSize" : "Rastergröße",
"textDir" : "Textrichtung",
"defaultDir" : "Standard",
"ltr" : "Von links nach rechts",
"ltr" : "Links-nach-rechts",
"rtl" : "Von rechts nach links",
"auto" : "Kontextuell"
},
@@ -53,15 +53,15 @@
"import" : "Import",
"export" : "Exportieren",
"search" : "Flows durchsuchen",
"searchInput" : "Flows durchsuchen",
"searchInput" : "durchsuchen Sie Ihre Flows",
"subflows" : "Subflow",
"createSubflow" : "Subflow erstellen",
"selectionToSubflow" : "Auswahl zu Subflow",
"selectionToSubflow" : "Auswahl für Subflow",
"flows" : "Flows",
"add" : "Hinzufügen",
"rename" : "Umbenennen",
"delete" : "Löschen",
"keyboardShortcuts" : "Tastenkürzel",
"keyboardShortcuts" : "Tastaturkurzbefehle",
"login" : "Anmelden",
"logout" : "Abmelden",
"editPalette" : "Palette verwalten",
@@ -217,7 +217,7 @@
"remote" : "Ferne Änderungen",
"reviewChanges" : "Änderungen prüfen",
"noBinaryFileShowed" : "Der Inhalt der Binärdatei kann nicht angezeigt",
"viewCommitDiff" : "Änderungen committen",
"viewCommitDiff" : "Änderungen festschreiben",
"compareChanges" : "Änderungen vergleichen",
"saveConflict" : "Konfliktlösung speichern",
"conflictHeader" : "<span> __resolved__ </span> von <span> __unresolved__ </span> -Konflikten behoben",
@@ -226,8 +226,8 @@
"newVersionError" : "Neue Version enthält keine gültige JSON-Datei:"
},
"subflow" : {
"editSubflow" : "Subflow bearbeiten: __name__",
"edit" : "Subflow bearbeiten",
"editSubflow" : "Flowschablone bearbeiten: __name__",
"edit" : "Flowsschablone bearbeiten",
"subflowInstances" : "Es ist __count__ Instanz dieser Subflow-Vorlage vorhanden.",
"subflowInstances_plural" : "Es gibt __count__ Instanzen dieser Subflow-Vorlage.",
"editSubflowProperties" : "Eigenschaften bearbeiten",
@@ -266,7 +266,7 @@
}
},
"keyboard" : {
"title" : "Tastenkürzel",
"title" : "Tastaturkurzbefehle",
"keyboard" : "Tastatur",
"filterActions" : "Filteraktionen",
"shortcut" : "Direktaufruf",
@@ -283,7 +283,7 @@
"exportNode" : "Node exportieren",
"nudgeNode" : "Ausgewählte Nodes verschieben (1px)",
"moveNode" : "Ausgewählte Nodes verschieben (20px)",
"toggleSidebar" : "Seitenleiste ein-/ausblenden",
"toggleSidebar" : "Seitenleiste ein-/ausschalten",
"copyNode" : "Ausgewählte Nodes kopieren",
"cutNode" : "Ausgewählte Nodes ausschneiden",
"pasteNode" : "Node einfügen",
@@ -308,7 +308,7 @@
},
"palette" : {
"noInfo" : "Keine Informationen verfügbar",
"filter" : "Nodes filtern",
"filter" : "Filter Nodes",
"search" : "Suchmodule",
"addCategory" : "Neu hinzufügen ...",
"label" : {
@@ -366,11 +366,11 @@
"remove" : "entfernen",
"update" : "Update auf __version__",
"updated" : "aktualisiert",
"install" : "Installieren",
"installed" : "Installiert",
"install" : "installieren",
"installed" : "installiert",
"loading" : "Kataloge werden geladen ...",
"tab-nodes" : "Nodes",
"tab-install" : "Installieren",
"tab-install" : "installieren",
"sort" : "Sortierung:",
"sortAZ" : "a-z",
"sortRecent" : "kürzlich",
@@ -452,7 +452,7 @@
"name" : "Kontextdaten",
"label" : "Kontext",
"none" : "keine ausgewählt",
"refresh" : "Zum Aktualisieren neu laden",
"refresh" : "Aktualisierung zum Laden",
"empty" : "leer",
"node" : "Node",
"flow" : "Flow",
@@ -477,7 +477,7 @@
"none" : "Keine",
"install" : "installieren",
"removeFromProject" : "Aus Projekt entfernen",
"addToProject" : "Zu Projekt hinzufügen",
"addToProject" : "zu Projekt hinzufügen",
"files" : "Dateien",
"flow" : "Flow",
"credentials" : "Berechtigungsnachweis",
@@ -510,7 +510,7 @@
},
"userSettings" : {
"committerDetail" : "Committer-Details",
"committerTip" : "Leer lassen für Systemstandard",
"committerTip" : "Leer Wert für Systemstandardwert belassen",
"userName" : "Benutzername",
"email" : "E-Mail",
"sshKeys" : "SSH-Schlüssel",
@@ -544,7 +544,7 @@
"revertChanges" : "Änderungen zurücksetzen",
"localChanges" : "Lokale Änderungen",
"none" : "Keine",
"conflictResolve" : "Alle Konflikte wurden aufgelöst. Committe die Änderungen, um den Merge Request abzuschließen.",
"conflictResolve" : "Alle Konflikte wurden aufgelöst. Festschreiben der Änderungen, um den Mischvorgang abzuschließen.",
"localFiles" : "Lokale Dateien",
"all" : "alle",
"unmergedChanges" : "Nicht zusammengeführte Änderungen",

View File

@@ -14,35 +14,9 @@
"back": "Back",
"next": "Next",
"clone": "Clone project",
"cont": "Continue",
"style": "Style",
"line": "Outline",
"fill": "Fill",
"label": "Label",
"color": "Color",
"position": "Position",
"enable": "Enable",
"disable": "Disable"
},
"type": {
"string": "string",
"number": "number",
"boolean": "boolean",
"array": "array",
"buffer": "buffer",
"object": "object",
"jsonString": "JSON string",
"undefined": "undefined",
"null": "null"
"cont": "Continue"
}
},
"event": {
"loadPalette": "Loading Palette",
"loadNodeCatalogs": "Loading Node catalogs",
"loadNodes": "Loading Nodes __count__",
"loadFlows": "Loading Flows",
"importFlows": "Adding Flows to workspace"
},
"workspace": {
"defaultName": "Flow __number__",
"editFlow": "Edit flow: __name__",
@@ -71,7 +45,8 @@
"rtl": "Right-to-left",
"auto": "Contextual",
"language": "Language",
"browserDefault": "Browser default"
"browserDefault": "Browser default",
"flowVertical": "Vertical flow"
},
"sidebar": {
"show": "Show sidebar"
@@ -106,12 +81,7 @@
"projects-new": "New",
"projects-open": "Open",
"projects-settings": "Project Settings",
"showNodeLabelDefault": "Show label of newly added nodes",
"groups": "Groups",
"groupSelection": "Group selection",
"ungroupSelection": "Ungroup selection",
"groupMergeSelection": "Merge selection",
"groupRemoveSelection": "Remove from group"
"showNodeLabelDefault": "Show label of newly added nodes"
}
},
"actions": {
@@ -191,8 +161,6 @@
"node_plural": "__count__ nodes",
"configNode": "__count__ configuration node",
"configNode_plural": "__count__ configuration nodes",
"group": "__count__ group",
"group_plural": "__count__ groups",
"flow": "__count__ flow",
"flow_plural": "__count__ flows",
"subflow": "__count__ subflow",
@@ -208,9 +176,6 @@
"nodesImported": "Imported:",
"nodeCopied": "__count__ node copied",
"nodeCopied_plural": "__count__ nodes copied",
"groupCopied": "__count__ group copied",
"groupCopied_plural": "__count__ groups copied",
"groupStyleCopied": "Group style copied",
"invalidFlow": "Invalid flow: __message__",
"export": {
"selected":"selected nodes",
@@ -333,13 +298,6 @@
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
}
},
"group": {
"editGroup": "Edit group: __name__",
"errors": {
"cannotCreateDiffGroups": "Cannot create group using nodes from different groups",
"cannotAddSubflowPorts": "Cannot add subflow ports to a group"
}
},
"editor": {
"configEdit": "Edit",
"configAdd": "Add",
@@ -369,7 +327,6 @@
"locale": "Select UI Language",
"icon": "Icon",
"inputType": "Input type",
"selectType": "select types...",
"inputs" : {
"input": "input",
"select": "select",
@@ -384,8 +341,7 @@
"bool": "bool",
"json": "JSON",
"bin": "buffer",
"env": "env variable",
"cred": "credential"
"env": "env variable"
},
"menu": {
"input": "input",
@@ -567,12 +523,11 @@
},
"sidebar": {
"info": {
"name": "Information",
"name": "Node information",
"tabName": "Name",
"label": "info",
"node": "Node",
"type": "Type",
"group": "Group",
"module": "Module",
"id": "ID",
"status": "Status",
@@ -595,29 +550,7 @@
"nodeHelp": "Node Help",
"none":"None",
"arrayItems": "__count__ items",
"showTips":"You can open the tips from the settings panel",
"outline": "Outline",
"empty": "empty",
"globalConfig": "Global Configuration Nodes",
"triggerAction": "Trigger action",
"find": "Find in workspace",
"search": {
"configNodes": "Configuration nodes",
"unusedConfigNodes": "Unused configuration nodes",
"invalidNodes": "Invalid nodes",
"uknownNodes": "Unknown nodes",
"unusedSubflows": "Unused subflows"
}
},
"help": {
"name": "Help",
"label": "help",
"search": "Search help",
"nodeHelp": "Node Help",
"showHelp": "Show help",
"showInOutline": "Show in outline",
"showTopics": "Show topics",
"noHelp": "No help topic selected"
"showTips":"You can open the tips from the settings panel"
},
"config": {
"name": "Configuration nodes",
@@ -670,6 +603,7 @@
"removeFromProject": "remove from project",
"addToProject": "add to project",
"files": "Files",
"package": "Package",
"flow": "Flow",
"credentials": "Credentials",
"package":"Package",
@@ -813,8 +747,7 @@
"bin": "buffer",
"date": "timestamp",
"jsonata": "expression",
"env": "env variable",
"cred": "credential"
"env": "env variable"
}
},
"editableList": {
@@ -860,14 +793,10 @@
"copyPath": "Copy path to item",
"expandItems": "Expand items",
"collapseItems": "Collapse items",
"duplicate": "Duplicate",
"error": {
"invalidJSON": "Invalid JSON: "
}
"duplicate": "Duplicate"
},
"markdownEditor": {
"title": "Markdown editor",
"expand": "Expand",
"format": "Formatted with markdown",
"heading1": "Heading 1",
"heading2": "Heading 2",
@@ -1034,8 +963,7 @@
"passphrase": "Passphrase",
"retry": "Retry",
"update-failed": "Failed to update auth",
"unhandled": "Unhandled error response",
"host-key-verify-failed": "<p>Host key verification failed.</p><p>The repository host key could not be verified. Please update your <code>known_hosts</code> file and try again.</p>"
"unhandled": "Unhandled error response"
},
"create-branch-list": {
"invalid": "Invalid branch",
@@ -1066,7 +994,6 @@
"en-US": "English",
"ja": "Japanese",
"ko": "Korean",
"zh-CN": "Chinese(Simplified)",
"zh-TW": "Chinese(Traditional)"
"zh-CN": "Chinese(Simplified)"
}
}

View File

@@ -1,7 +1,7 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "Casts the `arg` parameter to a string using the following casting rules:\n\n - Strings are unchanged\n - Functions are converted to an empty string\n - Numeric infinity and NaN throw an error because they cannot be represented as a JSON number\n - All other values are converted to a JSON string using the `JSON.stringify` function. If `prettify` is true, then \"prettified\" JSON is produced. i.e One line per field and lines will be indented based on the field depth."
"args": "arg",
"desc": "Casts the *arg* parameter to a string using the following casting rules:\n\n - Strings are unchanged\n - Functions are converted to an empty string\n - Numeric infinity and NaN throw an error because they cannot be represented as a JSON number\n - All other values are converted to a JSON string using the `JSON.stringify` function"
},
"$length": {
"args": "str",
@@ -185,7 +185,7 @@
},
"$reduce": {
"args":"array, function [, init]",
"desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`. The signature of `function` must be of the form: `myfunc($accumulator, $value[, $index[, $array]])`\n\nThe optional `init` parameter is used as the initial value in the aggregation."
"desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`.\n\nThe optional `init` parameter is used as the initial value in the aggregation."
},
"$flowContext": {
"args": "string[, string]",
@@ -230,45 +230,6 @@
"$parseInteger": {
"args": "string, picture",
"desc": "Parses the contents of the `string` parameter to an integer (as a JSON number) using the format specified by the `picture` string. The `picture` string parameter has the same format as `$formatInteger`."
},
"$error": {
"args": "[str]",
"desc": "Throws an error with a message. The optional `str` will replace the default message of `$error() function evaluated`"
},
"$assert": {
"args": "arg, str",
"desc": "If `arg` is true the function returns undefined. If `arg` is false an exception is thrown with `str` as the message of the exception."
},
"$single": {
"args": "array, function",
"desc": "Returns the one and only value in the `array` parameter that satisfies the `function` predicate (i.e. the `function` returns Boolean `true` when passed the value). Throws an exception if the number of matching values is not exactly one.\n\nThe function should be supplied in the following signature: `function(value [, index [, array]])` where value is each input of the array, index is the position of that value and the whole array is passed as the third argument"
},
"$encodeUrl": {
"args": "str",
"desc": "Encodes a Uniform Resource Locator (URL) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character.\n\nExample: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Encodes a Uniform Resource Locator (URL) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character. \n\nExample: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "Decodes a Uniform Resource Locator (URL) component previously created by encodeUrlComponent. \n\nExample: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "Decodes a Uniform Resource Locator (URL) previously created by encodeUrl. \n\nExample: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "Returns an array with duplicate values removed from `array`"
},
"$type": {
"args": "value",
"desc": "Returns the type of `value` as a string. If `value` is undefined, this will return `undefined`"
},
"$moment": {
"args": "[str]",
"desc": "Gets a date object using the Moment library."
}
}

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

@@ -14,35 +14,9 @@
"back": "戻る",
"next": "進む",
"clone": "プロジェクトをクローン",
"cont": "続ける",
"style": "形式",
"line": "線",
"fill": "塗りつぶし",
"label": "ラベル",
"color": "色",
"position": "配置",
"enable": "有効",
"disable": "無効"
},
"type": {
"string": "文字列",
"number": "数値",
"boolean": "真偽値",
"array": "配列",
"buffer": "バッファ",
"object": "オブジェクト",
"jsonString": "JSON文字列",
"undefined": "undefined",
"null": "null"
"cont": "続ける"
}
},
"event": {
"loadPalette": "パレットを読み込み中",
"loadNodeCatalogs": "ノードカタログを読み込み中",
"loadNodes": "ノードを読み込み中 __count__",
"loadFlows": "フローを読み込み中",
"importFlows": "ワークスペースにフローを追加中"
},
"workspace": {
"defaultName": "フロー __number__",
"editFlow": "フローを編集: __name__",
@@ -71,7 +45,8 @@
"rtl": "右から左",
"auto": "文脈",
"language": "表示言語",
"browserDefault": "ブラウザのデフォルト"
"browserDefault": "ブラウザのデフォルト",
"flowVertical": "縦フロー"
},
"sidebar": {
"show": "サイドバーを表示"
@@ -82,7 +57,7 @@
"settings": "設定",
"userSettings": "ユーザ設定",
"nodes": "ノード",
"displayStatus": "ノードのステータスを表示",
"displayStatus": "ノードの状態を表示",
"displayConfig": "ノードの設定",
"import": "読み込み",
"export": "書き出し",
@@ -106,12 +81,7 @@
"projects-new": "新規",
"projects-open": "開く",
"projects-settings": "設定",
"showNodeLabelDefault": "追加したノードのラベルを表示",
"groups": "グループ",
"groupSelection": "選択部分をグループ化",
"ungroupSelection": "選択部分をグループ解除",
"groupMergeSelection": "選択部分をマージ",
"groupRemoveSelection": "グループから削除"
"showNodeLabelDefault": "追加したノードのラベルを表示"
}
},
"actions": {
@@ -191,8 +161,6 @@
"node_plural": "__count__ 個のノード",
"configNode": "__count__ 個の設定ノード",
"configNode_plural": "__count__ 個の設定ノード",
"group": "__count__ 個のグループ",
"group_plural": "__count__ 個のグループ",
"flow": "__count__ 個のフロー",
"flow_plural": "__count__ 個のフロー",
"subflow": "__count__ 個のサブフロー",
@@ -208,9 +176,6 @@
"nodesImported": "読み込みました:",
"nodeCopied": "__count__ 個のノードをコピーしました",
"nodeCopied_plural": "__count__ 個のノードをコピーしました",
"groupCopied": "__count__ 個のグループをコピーしました",
"groupCopied_plural": "__count__ 個のグループをコピーしました",
"groupStyleCopied": "グループの形式をコピーしました",
"invalidFlow": "不正なフロー: __message__",
"export": {
"selected": "選択したフロー",
@@ -333,13 +298,6 @@
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"
}
},
"group": {
"editGroup": "__name__ グループを編集",
"errors": {
"cannotCreateDiffGroups": "異なるグループのノードを使用してグループを作成することはできません",
"cannotAddSubflowPorts": "グループにサブフローの端子を追加できません"
}
},
"editor": {
"configEdit": "編集",
"configAdd": "追加",
@@ -369,7 +327,6 @@
"locale": "UI言語の選択",
"icon": "記号",
"inputType": "入力形式",
"selectType": "形式選択...",
"inputs": {
"input": "入力",
"select": "メニュー",
@@ -384,8 +341,7 @@
"bool": "真偽",
"json": "JSON",
"bin": "バッファ",
"env": "環境変数",
"cred": "認証情報"
"env": "環境変数"
},
"menu": {
"input": "入力",
@@ -572,7 +528,6 @@
"label": "情報",
"node": "ノード",
"type": "型",
"group": "グループ",
"module": "モジュール",
"id": "ID",
"status": "状態",
@@ -595,29 +550,7 @@
"nodeHelp": "ノードのヘルプ",
"none": "なし",
"arrayItems": "__count__ 要素",
"showTips": "設定からヒントを表示できます",
"outline": "アウトライン",
"empty": "空",
"globalConfig": "グローバル設定ノード",
"triggerAction": "アクションを実行",
"find": "ワークスペース内を検索",
"search": {
"configNodes": "設定ノード",
"unusedConfigNodes": "未使用の設定ノード",
"invalidNodes": "不正なノード",
"uknownNodes": "未知のノード",
"unusedSubflows": "未使用のサブフロー"
}
},
"help": {
"name": "ヘルプ",
"label": "ヘルプ",
"search": "ヘルプを検索",
"nodeHelp": "ノードヘルプ",
"showHelp": "ヘルプを表示",
"showInOutline": "アウトラインに表示",
"showTopics": "トピックを表示",
"noHelp": "ヘルプのトピックが未選択"
"showTips": "設定からヒントを表示できます"
},
"config": {
"name": "ノードの設定を表示",
@@ -670,9 +603,9 @@
"removeFromProject": "プロジェクトから削除",
"addToProject": "プロジェクトへ追加",
"files": "ファイル",
"package": "パッケージ",
"flow": "フロー",
"credentials": "認証情報",
"package": "パッケージ",
"packageCreate": "変更が保存された時にファイルが作成されます",
"fileNotExist": "ファイルが存在しません",
"selectFile": "ファイルを選択",
@@ -813,8 +746,7 @@
"bin": "バッファ",
"date": "日時",
"jsonata": "JSONata式",
"env": "環境変数",
"cred": "認証情報"
"env": "環境変数"
}
},
"editableList": {
@@ -860,14 +792,10 @@
"copyPath": "要素のパスをコピー",
"expandItems": "要素を展開",
"collapseItems": "要素を折り畳む",
"duplicate": "複製",
"error": {
"invalidJSON": "不正なJSON: "
}
"duplicate": "複製"
},
"markdownEditor": {
"title": "マークダウンエディタ",
"expand": "拡大",
"format": "マークダウン形式で記述",
"heading1": "見出しレベル1",
"heading2": "見出しレベル2",
@@ -1034,8 +962,7 @@
"passphrase": "パスフレーズ",
"retry": "リトライ",
"update-failed": "認証の更新に失敗しました",
"unhandled": "エラー応答が処理されませんでした",
"host-key-verify-failed": "<p>ホストキーの検証に失敗</p><p>リポジトリのホストキーを検証できませんでした。<code>known_hosts</code>ファイルを更新して、もう一度試してください。</p>"
"unhandled": "エラー応答が処理されませんでした"
},
"create-branch-list": {
"invalid": "不正なブランチ",
@@ -1066,7 +993,6 @@
"en-US": "英語",
"ja": "日本語",
"ko": "韓国語",
"zh-CN": "中国語(簡体)",
"zh-TW": "中国語(繁体)"
"zh-CN": "中国語(簡体)"
}
}

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

@@ -1,7 +1,7 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "以下の型変換ルールを用いて、引数 *arg* を文字列へ型変換します。:\n\n - 文字列は変換しません。\n - 関数は空の文字列に変換します。\n - JSONの数値として表現できないため、無限大やNaNはエラーになります。\n - 他の値は `JSON.stringify` 関数を用いて、JSONの文字列へ変換します。`prettify`が真の場合、JSONを整形出力します。フィールドを1行毎に出力。フィールドのネスト深さによってインデントを行います。"
"args": "arg",
"desc": "以下の型変換ルールを用いて、引数 *arg* を文字列へ型変換します。:\n\n - 文字列は変換しません。\n - 関数は空の文字列に変換します。\n - JSONの数値として表現できないため、無限大やNaNはエラーになります。\n - 他の値は `JSON.stringify` 関数を用いて、JSONの文字列へ変換します。"
},
"$length": {
"args": "str",
@@ -185,7 +185,7 @@
},
"$reduce": {
"args": "array, function [, init]",
"desc": "配列の各要素値に関数 `function` を連続的に適用して得られる集約値を返します。 `function` の適用の際には、直前の `function` の適用結果と要素値が引数として与えられます。\n\n関数 `function` は引数を2つ取り、配列の各要素の間に配置する中置演算子のように作用しなくてはなりません。関数`function`のシグネチャは`myfunc($accumulator, $value[, $index[, $array]])`という形式でなければなりません。\n\n任意の引数 `init` には、集約時の初期値を設定します。"
"desc": "配列の各要素値に関数 `function` を連続的に適用して得られる集約値を返します。 `function` の適用の際には、直前の `function` の適用結果と要素値が引数として与えられます。\n\n関数 `function` は引数を2つ取り、配列の各要素の間に配置する中置演算子のように作用しなくてはなりません。\n\n任意の引数 `init` には、集約時の初期値を設定します。"
},
"$flowContext": {
"args": "string",
@@ -230,45 +230,5 @@
"$parseInteger": {
"args": "string, picture",
"desc": "`picture`文字列の指定に従って、`string`パラメータを整数(JSON数値)に変換します。`picture`文字列は`$formatInteger`と同じ形式です。"
},
"$error": {
"args": "[str]",
"desc": "メッセージを指定して例外を送出します。メッセージ`str`を省略した場合は`$error() function evaluated`をメッセージとします。"
},
"$assert": {
"args": "arg, str",
"desc": "`arg`が真の場合、undefinedを返します。偽の場合、`str`をメッセージとする例外を送出します。"
},
"$single": {
"args": "array, function",
"desc": "`array`の要素のうち、条件判定関数`function`を満たす(`function`に与えた場合に真偽値`true`を返す)要素が1つのみである場合、それを返します。マッチする要素が1つのみでない場合、例外を送出します。\n\n指定する関数は`function(value [, index [, array]])`というシグネチャでなければなりません。ここで、`value`は`array`の要素値、`index`は要素の添字、第三引数には配列全体を渡します。"
},
"$encodeUrl": {
"args": "str",
"desc": "Uniform Resource Locator (URL)を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Uniform Resource Locator (URL)要素を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "encodeUrlComponentで置換したUniform Resource Locator (URL)をデコードします。\n\n例: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "encodeUrlで置換したUniform Resource Locator (URL)要素をデコードします。 \n\n例: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "配列`array`から重複要素を削除した配列を返します。"
},
"$type": {
"args": "value",
"desc": "`value` の型を文字列として返します。もし `value` が未定義の場合、 `undefined` が返されます。"
},
"$moment": {
"args": "[str]",
"desc": "Momentライブラリを使用して日付オブジェクトを取得します。"
}
}

View File

@@ -10,52 +10,19 @@
"load": "读取",
"save": "保存",
"import": "导入",
"export": "导出",
"back": "后退",
"next": "下一个",
"clone": "克隆项目",
"cont": "继续",
"style": "风格",
"line": "大纲",
"fill": "填充",
"label": "标签",
"color": "颜色",
"position": "位置",
"enable": "启用",
"disable": "禁用"
},
"type": {
"string": "字符串",
"number": "数字",
"boolean": "布尔值",
"array": "数组",
"buffer": "buffer",
"object": "对象",
"jsonString": "JSON字符串",
"undefined": "未定义",
"null": "空"
"export": "导出"
}
},
"event": {
"loadPalette": "加载控制板",
"loadNodeCatalogs": "加载节点目录",
"loadNodes": "加载 __count__ 个节点",
"loadFlows": "加载流程",
"importFlows": "往工作区中加载流程"
},
"workspace": {
"defaultName": "流程 __number__",
"defaultName": "流程__number__",
"editFlow": "编辑流程: __name__",
"confirmDelete": "确认删除",
"delete": "你确定删除 __label__ ?",
"delete": "你确定删除 '__label__'?",
"dropFlowHere": "把流程放到这里",
"addFlow": "添加流程",
"listFlows": "流程一览",
"status": "状态",
"enabled": "有效",
"disabled": "无效",
"info": "详细描述",
"selectNodes": "点击节点来选择"
"info": "详细描述"
},
"menu": {
"label": {
@@ -70,15 +37,11 @@
"ltr": "从左到右",
"rtl": "从右到左",
"auto": "上下文",
"language": "语言",
"browserDefault": "浏览器默认"
"flowVertical": "Vertical flow"
},
"sidebar": {
"show": "显示侧边栏"
},
"palette": {
"show": "显示控制板"
},
"settings": "设置",
"userSettings": "用户设置",
"nodes": "节点",
@@ -98,30 +61,13 @@
"keyboardShortcuts": "键盘快捷方式",
"login": "登陆",
"logout": "退出",
"editPalette": "节点管理",
"editPalette":"节点管理",
"other": "其他",
"showTips": "显示小提示",
"help": "Node-RED网页",
"projects": "项目",
"projects-new": "新建",
"projects-open": "打开",
"projects-settings": "项目设定",
"showNodeLabelDefault": "显示新添加的节点的标签",
"groups": "组",
"groupSelection": "选择组",
"ungroupSelection": "取消选择组",
"groupMergeSelection": "合并选择",
"groupRemoveSelection": "从组中移除"
"showTips": "显示小提示"
}
},
"actions": {
"toggle-navigator": "切换导航器",
"zoom-out": "缩小",
"zoom-reset": "重设缩放",
"zoom-in": "放大"
},
"user": {
"loggedInAs": "作为 __name__ 登陆",
"loggedInAs": "作为__name__登陆",
"username": "账号",
"password": "密码",
"login": "登陆",
@@ -137,80 +83,31 @@
"warning": "<strong>警告</strong>: __message__",
"warnings": {
"undeployedChanges": "节点中存在未部署的更改",
"nodeActionDisabled": "节点操作已禁用",
"nodeActionDisabledSubflow": "节点动作在子流程中被禁用",
"missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息",
"safe-mode": "<p>流程以安全模式停止。</p><p>您可以修改流程并部署更改以重新启动。</p>",
"restartRequired": "Node-RED必须重新启动以启用升级的模块",
"credentials_load_failed": "<p>由于无法解密凭据,因此流程停止。</p><p>流程凭据文件已加密,但是项目的加密密钥丢失或无效。</p>",
"credentials_load_failed_reset": "<p>凭据无法解密</p><p>流凭据文件已加密,但是项目的加密密钥丢失或无效。</p><p>流凭据文件将在下一次部署时重置。任何现有的流凭证将被清除。</p>",
"missing_flow_file": "<p>找不到项目流程文件。</p><p>该项目未配置流程文件。</p>",
"missing_package_file": "<p>找不到项目包文件。</p><p>项目缺少package.json文件。</p>",
"project_empty": "<p>该项目为空。</p><p>是否要创建一组默认的项目文件?<br/>否则,您将必须在编辑器外部手动将文件添加到项目中。</p>",
"project_not_found": "<p>未找到项目 __project__ 。</p>",
"git_merge_conflict": "<p>自动合并更改失败。</p><p>修复未合并的冲突,然后提交结果。</p>"
"restartRequired": "Node-RED必须重新启动以启用升级的模块"
},
"error": "<strong>错误</strong>: __message__",
"error": "<strong>Error</strong>: __message__",
"errors": {
"lostConnection": "丢失与服务器的连接,重新连接...",
"lostConnectionReconnect": "丢失与服务器的连接, __time__ 秒后重新连接",
"lostConnectionReconnect": "丢失与服务器的连接__time__秒后重新连接",
"lostConnectionTry": "现在尝试",
"cannotAddSubflowToItself": "无法向其自身添加子流程",
"cannotAddCircularReference": "无法添加子流程 - 循环引用",
"unsupportedVersion": "您正在使用不受支持的Node.js版本<br/>请升级到最新版本的Node.js LTS",
"failedToAppendNode": "<p>'__module__'加载失败</p><p>__error__</p>"
},
"project": {
"change-branch": "转到本地分支'__project__'",
"merge-abort": "Git合并中止",
"loaded": "项目'__project__'已加载",
"updated": "项目'__project__'已更新",
"pull": "项目'__project__'已重新加载",
"revert": "项目 '__project__'已还原",
"merge-complete": "Git合并完成",
"setupCredentials": "设定证书",
"setupProjectFiles": "设置项目文件",
"no": "不了,谢谢",
"createDefault": "创建默认项目文件",
"mergeConflict": "显示合并冲突"
},
"label": {
"manage-project-dep": "管理项目依赖性",
"setup-cred": "设定证书",
"setup-project": "设置项目文件",
"create-default-package": "创建默认的包文件",
"no-thanks": "不了,谢谢",
"create-default-project": "创建默认项目文件",
"show-merge-conflicts": "显示合并冲突"
"unsupportedVersion": "您正在使用不受支持的Node.js版本<br/>请升级到最新版本的Node.js LTS"
}
},
"clipboard": {
"clipboard": "剪贴板",
"nodes": "节点",
"node": "__count__ 个节点",
"node_plural": "__count__ 个节点",
"configNode": "__count__ 个配置节点",
"configNode_plural": "__count__ 个配置节点",
"group": "__count__ 个组",
"group_plural": "__count__ 个组",
"flow": "__count__ 个流程",
"flow_plural": "__count__ 个流程",
"subflow": "__count__ 个子流程",
"subflow_plural": "__count__ 子流程",
"pasteNodes": "在这里粘贴节点",
"selectFile": "选择要导入的文件",
"importNodes": "导入节点",
"exportNodes": "导出节点至剪贴板",
"download": "下载",
"importUnrecognised": "导入了无法识别的类型:",
"importUnrecognised_plural": "导入了无法识别的类型:",
"nodesExported": "节点导出到了剪贴板",
"nodesImported": "导入:",
"nodeCopied": "已复制 __count__ 个节点",
"nodeCopied_plural": "已复制 __count__ 个节点",
"groupCopied": "复制 __count__ 个组",
"groupCopied_plural": "已复制 __count__ 个groups",
"groupStyleCopied": "已复制组风格",
"nodeCopied": "已复制__count__个节点",
"nodeCopied_plural": "已复制__count__个节点",
"invalidFlow": "无效的流程: __message__",
"export": {
"selected": "已选择的节点",
@@ -218,21 +115,11 @@
"all": "所有流程",
"compact": "紧凑",
"formatted": "已格式化",
"copy": "导出到剪贴板",
"export": "到处到库",
"exportAs": "导出为",
"overwrite": "替换",
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"
"copy": "导出到剪贴板"
},
"import": {
"import": "导入到",
"newFlow": "新流程",
"errors": {
"notArray": "输入的不是JSON数组",
"itemNotObject": "输入的流无效 - 项目 __index__ 不是节点对象",
"missingId": "输入的流无效-项 __index__ 缺少'id'属性",
"missingType": "输入的流程无效-项 __index__ 缺少'类型'属性"
}
"newFlow": "新流程"
},
"copyMessagePath": "已复制路径",
"copyMessageValue": "已复制数值",
@@ -246,10 +133,7 @@
"modifiedFlowsDesc": "只部署包含已更改节点的流",
"modifiedNodes": "已更改的节点",
"modifiedNodesDesc": "只部署已经更改的节点",
"restartFlows": "重启流程",
"restartFlowsDesc": "重新启动当前部署的流程",
"successfulDeploy": "部署成功",
"successfulRestart": "成功重启流程",
"deployFailed": "部署失败: __message__",
"unusedConfigNodes": "您有一些未使用的配置节点",
"unusedConfigNodesLink": "点击此处查看它们",
@@ -269,24 +153,16 @@
"improperlyConfigured": "工作区包含一些未正确配置的节点:",
"unknown": "工作区包含一些未知的节点类型:",
"confirm": "你确定要部署吗?",
"doNotWarn": "不要再对此发出警告",
"conflict": "服务器正在运行较新的一组流程。",
"backgroundUpdate": "服务器上的流程已更新。",
"conflictChecking": "检查是否可以自动合并更改",
"conflictAutoMerge": "此更改不包括冲突,可以自动合并",
"conflictManualMerge": "这些更改包括了在部署之前必须解决的冲突。",
"plusNMore": "+ __count__ 更多"
"conflictManualMerge": "这些更改包括了在部署之前必须解决的冲突。"
}
},
"eventLog": {
"title": "事件记录日志",
"view": "查看日志"
},
"diff": {
"unresolvedCount": "__count__个未解决的冲突",
"unresolvedCount_plural": "__count__个未解决的冲突",
"globalNodes": "全局节点",
"flowProperties": "流程属性",
"type": {
"added": "已添加",
"changed": "已更改",
@@ -300,122 +176,47 @@
"nodeCount": "__count__个节点",
"nodeCount_plural": "__count__个节点",
"local": "本地",
"remote": "远程",
"reviewChanges": "查看变更",
"noBinaryFileShowed": "无法显示二进制文件内容",
"viewCommitDiff": "查看提交更改",
"compareChanges": "比较变更",
"saveConflict": "保存冲突解决",
"conflictHeader": "已解决<span>__unresolved__</span>中的<span>__resolved__</span>个冲突",
"commonVersionError": "通用版本不包含有效的JSON",
"oldVersionError": "旧版本不包含有效的JSON",
"newVersionError": "新版本不包含有效的JSON"
"remote": "远程"
},
"subflow": {
"editSubflowInstance": "编辑子流实例: __name__",
"editSubflow": "编辑流程模板: __name__",
"editSubflow": "编辑流程模板: __name__",
"edit": "编辑流程模板",
"subflowInstances": "这个子流程模板有 __count__ 个实例",
"subflowInstances_plural": "这个子流程模板有 __count__ 个实例",
"subflowInstances": "这个子流程模板有__count__个实例",
"subflowInstances_plural": "这个子流程模板有__count__个实例",
"editSubflowProperties": "编辑属性",
"input": "输入:",
"output": "输出:",
"status": "状态节点",
"deleteSubflow": "删除子流程",
"info": "详细描述",
"category": "类别",
"env": {
"restore": "恢复为默认子流",
"remove": "删除环境变量"
},
"errors": {
"noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点",
"multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择"
}
},
"group": {
"editGroup": "编辑组: __name__",
"errors": {
"cannotCreateDiffGroups": "无法使用来自不同组的节点创建组",
"cannotAddSubflowPorts": "无法将子流程的端口添加到组"
}
},
"editor": {
"configEdit": "编辑",
"configAdd": "添加",
"configUpdate": "更新",
"configDelete": "删除",
"nodesUse": "__count__ 个节点使用此配置",
"nodesUse_plural": "__count__ 个节点使用此配置",
"addNewConfig": "添加新的 __type__ 配置",
"editNode": "编辑 __type__ 节点",
"editConfig": "编辑 __type__ 配置",
"addNewType": "添加新的 __type__ 节点",
"nodesUse": "__count__个节点使用此配置",
"nodesUse_plural": "__count__个节点使用此配置",
"addNewConfig": "添加新的__type__配置",
"editNode": "编辑__type__节点",
"editConfig": "编辑__type__配置",
"addNewType": "添加新的__type__节点",
"nodeProperties": "节点属性",
"label": "标签",
"color": "颜色",
"portLabels": "端口标签",
"labelInputs": "输入",
"labelOutputs": "输出",
"settingIcon": "图标",
"default": "默认",
"noDefaultLabel": "无",
"defaultLabel": "使用默认标签",
"searchIcons": "搜索图标",
"useDefault": "使用默认",
"description": "描述",
"show": "显示",
"hide": "隐藏",
"locale": "选择界面语言",
"icon": "图标",
"inputType": "输入类型",
"selectType": "选择类型...",
"inputs": {
"input": "输入",
"select": "选择",
"checkbox": "复选框",
"spinner": "微调器",
"none": "空",
"hidden": "隐藏属性"
},
"types": {
"str": "字符串",
"num": "数字",
"bool": "布尔",
"json": "JSON",
"bin": "buffer",
"env": "环境变量",
"cred": "证书"
},
"menu": {
"input": "输入",
"select": "选择",
"checkbox": "复选框",
"spinner": "微调器",
"hidden": "仅标签"
},
"select": {
"label": "标签",
"value": "值"
},
"spinner": {
"min": "最小值",
"max": "最大值"
},
"errors": {
"scopeChange": "更改范围将使其他流中的节点无法使用",
"invalidProperties": "无效的属性:"
"scopeChange": "更改范围将使其他流中的节点无法使用"
}
},
"keyboard": {
"title": "键盘快捷键",
"keyboard": "键盘",
"filterActions": "筛选动作",
"shortcut": "快捷键",
"scope": "范围",
"unassigned": "未分配",
"global": "全局",
"workspace": "工作区",
"selectAll": "选择所有节点",
"selectAllConnected": "选择所有连接的节点",
"addRemoveNode": "从选择中添加/删除节点",
@@ -426,14 +227,12 @@
"nudgeNode": "移动所选节点(1px)",
"moveNode": "移动所选节点(20px)",
"toggleSidebar": "切换侧边栏",
"togglePalette": "切换控制板",
"copyNode": "复制所选节点",
"cutNode": "剪切所选节点",
"pasteNode": "粘贴节点",
"undoChange": "撤消上次执行的更改",
"searchBox": "打开搜索框",
"managePalette": "管理面板",
"actionList": "动作列表"
"managePalette": "管理面板"
},
"library": {
"library": "库",
@@ -441,42 +240,30 @@
"saveToLibrary": "保存到库...",
"typeLibrary": "__type__类型库",
"unnamedType": "无名__type__",
"exportedToLibrary": "节点导出到库",
"exportToLibrary": "节点导出到库",
"dialogSaveOverwrite": "一个叫做__libraryName__的__libraryType__已经存在您需要覆盖么",
"invalidFilename": "无效的文件名",
"savedNodes": "保存的节点",
"savedType": "已保存__type__",
"saveFailed": "保存失败: __message__",
"newFolder": "新文件夹",
"types": {
"local": "本地的",
"examples": "例子"
},
"exportToLibrary": "将节点导出到库"
}
},
"palette": {
"noInfo": "无可用信息",
"filter": "过滤节点",
"search": "搜索模块",
"addCategory": "添加新的...",
"label": {
"subflows": "子流程",
"network": "网络",
"common": "共通",
"input": "输入",
"output": "输出",
"function": "功能",
"sequence": "序列",
"parser": "解析",
"social": "社交",
"storage": "存储",
"analysis": "分析",
"advanced": "高级"
},
"actions": {
"collapse-all": "收起所有类别",
"expand-all": "展开所有类别"
},
"event": {
"nodeAdded": "添加到面板中的节点:",
"nodeAdded_plural": "添加到面板中的多个节点",
@@ -490,49 +277,46 @@
},
"editor": {
"title": "面板管理",
"palette": "控制板",
"times": {
"seconds": "秒前",
"minutes": "分前",
"minutesV": "__count__ 分前",
"hoursV": "__count__ 小时前",
"hoursV_plural": "__count__ 小时前",
"daysV": "__count__ 天前",
"daysV_plural": "__count__ 天前",
"weeksV": "__count__ 周前",
"weeksV_plural": "__count__ 周前",
"monthsV": "__count__ 月前",
"monthsV_plural": "__count__ 月前",
"yearsV": "__count__ 年前",
"yearsV_plural": "__count__ 年前",
"yearMonthsV": "__y__ 年, __count__ 月前",
"yearMonthsV_plural": "__y__ 年, __count__ 月前",
"yearsMonthsV": "__y__ 年, __count__ 月前",
"yearsMonthsV_plural": "__y__ 年, __count__ 月前"
"minutesV": "__count__分前",
"hoursV": "__count__小时前",
"hoursV_plural": "__count__小时前",
"daysV": "__count__天前",
"daysV_plural": "__count__天前",
"weeksV": "__count__周前",
"weeksV_plural": "__count__周前",
"monthsV": "__count__月前",
"monthsV_plural": "__count__月前",
"yearsV": "__count__年前",
"yearsV_plural": "__count__年前",
"yearMonthsV": "__y__年, __count__月前",
"yearMonthsV_plural": "__y__年, __count__月前",
"yearsMonthsV": "__y__年, __count__月前",
"yearsMonthsV_plural": "__y__年, __count__月前"
},
"nodeCount": "__label__ 个节点",
"nodeCount_plural": "__label__ 个节点",
"moduleCount": "__count__ 个可用模块",
"moduleCount_plural": "__count__ 个可用模块",
"nodeCount": "__label__个节点",
"nodeCount_plural": "__label__个节点",
"moduleCount": "__count__个可用模块",
"moduleCount_plural": "__count__个可用模块",
"inuse": "使用中",
"enableall": "全部启用",
"disableall": "全部禁用",
"enable": "启用",
"disable": "禁用",
"remove": "移除",
"update": "更新至 __version__ 版本",
"update": "更新至__version__版本",
"updated": "已更新",
"install": "安装",
"installed": "已安装",
"conflict": "冲突",
"conflictTip": "<p>无法安装此模块,因为它包含已安装的<br/>节点类型</p><p>与<code>__module__</code>冲突</p>",
"loading": "加载目录...",
"tab-nodes": "节点",
"tab-install": "安装",
"sort": "排序:",
"sortAZ": "a-z顺序",
"sortRecent": "日期顺序",
"more": "增加 __count__ 个",
"more": "增加__count__个",
"errors": {
"catalogLoadFailed": "无法加载节点目录。<br>查看浏览器控制台了解更多信息",
"installFailed": "无法安装: __module__<br>__message__<br>查看日志了解更多信息",
@@ -573,8 +357,6 @@
"label": "信息",
"node": "节点",
"type": "类型",
"group": "组",
"module": "模组",
"id": "ID",
"status": "状态",
"enabled": "启用",
@@ -583,42 +365,19 @@
"instances": "实例",
"properties": "属性",
"info": "信息",
"desc": "描述",
"blank": "空白",
"null": "空",
"showMore": "展开",
"showLess": "收起",
"flow": "流程",
"selection": "选择",
"nodes": "__count__ 个节点",
"selection":"选择",
"nodes":"__count__ 个节点",
"flowDesc": "流程描述",
"subflowDesc": "子流程描述",
"nodeHelp": "节点帮助",
"none": "无",
"arrayItems": "__count__ 个项目",
"showTips": "您可以从设置面板启用提示信息",
"outline": "大纲",
"empty": "空的",
"globalConfig": "全局配置节点",
"triggerAction": "触发动作",
"find": "在工作区中查找",
"search": {
"configNodes": "配置节点",
"unusedConfigNodes": "未使用的配置节点",
"invalidNodes": "无效的节点",
"uknownNodes": "未知的节点",
"unusedSubflows": "未使用的子流程"
}
},
"help": {
"name": "帮助",
"label": "帮助",
"search": "搜索帮助",
"nodeHelp": "节点帮助",
"showHelp": "显示帮助",
"showInOutline": "在大纲中显示",
"showTopics": "显示主题",
"noHelp": "未选择帮助主题"
"none":"无",
"arrayItems": "__count__个项目",
"showTips": "您可以从设置面板启用提示信息"
},
"config": {
"name": "配置节点",
@@ -628,25 +387,9 @@
"subflows": "子流程",
"flows": "流程",
"filterAll": "所有",
"showAllConfigNodes": "显示所有配置节点",
"filterUnused": "未使用",
"showAllUnusedConfigNodes": "显示所有未使用的配置节点",
"filtered": "__count__ 个隐藏"
},
"context": {
"name": "上下文数据",
"label": "上下午",
"none": "未选择",
"refresh": "刷新以加载",
"empty": "空",
"node": "节点",
"flow": "流程",
"global": "全局",
"deleteConfirm": "你确定要删除这个项目吗?",
"autoRefresh": "刷新选择更改",
"refrsh": "刷新",
"delete": "删除"
},
"palette": {
"name": "节点管理",
"label": "节点"
@@ -657,151 +400,8 @@
"description": "描述",
"dependencies": "依赖",
"settings": "设置",
"noSummaryAvailable": "无可用摘要",
"editDescription": "编辑项目描述",
"editDependencies": "编辑项目依赖",
"noDescriptionAvailable": "没有可用的描述",
"editReadme": "编辑README.md",
"showProjectSettings": "显示项目设置",
"projectSettings": {
"title": "项目设置",
"edit": "编辑",
"none": "空",
"install": "安装",
"removeFromProject": "从项目中删除",
"addToProject": "添加到项目",
"files": "文件",
"flow": "流程",
"credentials": "证书",
"package": "包",
"packageCreate": "保存更改后将创建文件",
"fileNotExist": "文件不存在",
"selectFile": "选择文件",
"invalidEncryptionKey": "无效的加密密钥",
"encryptionEnabled": "启用加密",
"encryptionDisabled": "加密已禁用",
"setTheEncryptionKey": "设置加密密钥",
"resetTheEncryptionKey": "重置加密密钥",
"changeTheEncryptionKey": "更改加密密钥",
"currentKey": "当前密钥",
"newKey": "新密钥",
"credentialsAlert": "这将删除所有现有证书",
"versionControl": "版本控制",
"branches": "分支",
"noBranches": "没有分支",
"deleteConfirm": "您确定要删除本地分支'__name__'吗? 这不能被撤消。",
"unmergedConfirm": "本地分支'__name__'具有未合并的更改,这些更改将丢失。你确定要删除吗?",
"deleteUnmergedBranch": "删除未合并的分支",
"gitRemotes": "Git远程仓库",
"addRemote": "添加远程仓库",
"addRemote2": "添加远程仓库",
"remoteName": "远程仓库名",
"nameRule": "只能包含A-Z 0-9 _ -",
"url": "URL",
"urlRule": "https://, ssh:// or file://",
"urlRule2": "网址中不能包含用户名/密码",
"noRemotes": "没有远程仓库",
"deleteRemoteConfrim": "您确定要删除远程仓库'__name__'吗?",
"deleteRemote": "删除远程仓库"
},
"userSettings": {
"committerDetail": "提交者详细信息",
"committerTip": "保留空白以使用系统默认值",
"userName": "用户名",
"email": "电子邮件",
"sshKeys": "SSH密钥",
"sshKeysTip": "允许您创建到远程git存储库的安全连接。",
"add": "添加密钥",
"addSshKey": "添加SSH密钥",
"addSshKeyTip": "生成新的公钥/私钥对",
"name": "名字",
"nameRule": "只能包含A-Z 0-9 _ -",
"passphrase": "密码短语",
"passphraseShort": "密码短语过短",
"optional": "可选的",
"cancel": "取消",
"generate": "生成密钥",
"noSshKeys": "没有SSH密钥",
"copyPublicKey": "将公钥复制到剪贴板",
"delete": "删除密钥",
"gitConfig": "Git配置",
"deleteConfirm": "您确定要删除SSH密钥 __name__ 吗?这不能被撤消。"
},
"versionControl": {
"unstagedChanges": "未暂存的变更",
"stagedChanges": "暂存的变更",
"unstageChange": "取消变更的暂存",
"stageChange": "暂存变更",
"unstageAllChange": "取消所有变更的暂存",
"stageAllChange": "暂存所有变更",
"commitChanges": "提交变更",
"resolveConflicts": "解决冲突",
"head": "HEAD",
"staged": "暂存的",
"unstaged": "未暂存的",
"local": "本地的",
"remote": "远程的",
"revert": "您确定要将更改恢复为'__file__'吗?这不能被撤消。",
"revertChanges": "还原变更",
"localChanges": "本地变更",
"none": "None",
"conflictResolve": "解决所有冲突。提交更改以完成合并。",
"localFiles": "本地文件",
"all": "所有的",
"unmergedChanges": "未合并的更改",
"abortMerge": "中止合并",
"commit": "提交",
"changeToCommit": "提交变更",
"commitPlaceholder": "输入您的提交信息",
"cancelCapital": "取消",
"commitCapital": "提交",
"commitHistory": "提交历史",
"branch": "分支:",
"moreCommits": "更多提交",
"changeLocalBranch": "变更本地分支",
"createBranchPlaceholder": "查找或创建分支",
"upstream": "上游",
"localOverwrite": "切换分支会覆盖您现有的本地更改。您必须先提交或撤消那些更改。",
"manageRemoteBranch": "管理远程分支",
"unableToAccess": "无法访问远程存储库",
"retry": "重试",
"setUpstreamBranch": "设置为上游分支",
"createRemoteBranchPlaceholder": "查找或创建远程分支",
"trackedUpstreamBranch": "创建的分支将被设置为跟踪的上游分支。",
"selectUpstreamBranch": "分支将被创建。 在下面选择以将其设置为被跟踪的上游分支。",
"pushFailed": "推送失败,因为远程具有更多的最新提交。请先拉取并合并,然后再尝试推送。",
"push": "推送",
"pull": "拉取",
"unablePull": "<p>无法提取远程更改;您未暂存的本地更改将被覆盖。</p><p>请先提交更改,然后重试。</p>",
"showUnstagedChanges": "显示未暂存的更改",
"connectionFailed": "无法连接到远程存储库:",
"pullUnrelatedHistory": "<p>远程有无关的提交历史</p><p>您确定要将这些更改拉入本地仓库吗?</p>",
"pullChanges": "拉取更改",
"history": "历史",
"projectHistory": "项目历史",
"daysAgo": "__count__ 天前",
"daysAgo_plural": "__count__ 天前",
"hoursAgo": "__count__ 小时前",
"hoursAgo_plural": "__count__ 小时前",
"minsAgo": "__count__ 分钟前",
"minsAgo_plural": "__count__ 分钟前",
"secondsAgo": "秒前",
"notTracking": "您的本地分支当前未跟踪一个远程分支。",
"statusUnmergedChanged": "您的仓库中有未合并的更改。您需要解决冲突并提交结果。",
"repositoryUpToDate": "您的仓库是最新的。",
"commitsAhead": "您的存储库领先远程仓库 __count__ 次提交。您现在可以推送这些提交。",
"commitsAhead_plural": "您的存储库领先远程仓库 __count__ 次提交。您现在可以推送这些提交。",
"commitsBehind": "您的存储库落后远程仓库 __count__ 次提交。您现在可以拉取这些提交。",
"commitsBehind_plural": "您的存储库落后远程仓库 __count__ 次提交。您现在可以拉取这些提交。",
"commitsAheadAndBehind1": "您的存储库落后远程仓库 __count__ 次提交",
"commitsAheadAndBehind1_plural": "您的存储库落后远程仓库 __count__ 次提交",
"commitsAheadAndBehind2": "领先远程仓库 __count__ 次提交。",
"commitsAheadAndBehind2_plural": "领先远程仓库 __count__ 次提交。",
"commitsAheadAndBehind3": "您必须先拉取远程提交,然后才能进行推送。",
"commitsAheadAndBehind3_plural": "您必须先拉取远程提交,然后才能进行推送。",
"refreshCommitHistory": "刷新提交历史",
"refreshChanges": "刷新更改"
}
"editDependencies": "编辑项目依赖"
}
},
"typedInput": {
@@ -809,13 +409,10 @@
"str": "文字列",
"num": "数字",
"re": "正则表达式",
"bool": "布尔",
"bool": "布尔",
"json": "JSON",
"bin": "二进制流",
"date": "时间戳",
"jsonata": "表达式",
"env": "环境变量",
"cred": "证书"
"date": "时间戳"
}
},
"editableList": {
@@ -827,10 +424,8 @@
},
"expressionEditor": {
"functions": "功能",
"functionReference": "功能reference",
"insert": "插入",
"title": "JSONata表达式编辑器",
"test": "测试",
"data": "示例消息",
"result": "结果",
"format": "格式表达方法",
@@ -844,230 +439,14 @@
"eval": "评估表达式错误:\n __message__"
}
},
"jsEditor": {
"title": "JavaScript编辑器"
},
"textEditor": {
"title": "文本编辑器"
},
"jsonEditor": {
"title": "JSON编辑器",
"format": "格式化JSON",
"rawMode": "编辑 JSON",
"uiMode": "Visual编辑器",
"insertAbove": "在上方插入",
"insertBelow": "在下方插入",
"addItem": "添加项目",
"copyPath": "复制路径到项目",
"expandItems": "展开项目",
"collapseItems": "收合项目",
"duplicate": "重复",
"error": {
"invalidJSON": "无效的JSON: "
}
},
"markdownEditor": {
"title": "Markdown编辑器",
"expand": "展开",
"format": "格式化为markdown",
"heading1": "标题 1",
"heading2": "标题 2",
"heading3": "标题 3",
"bold": "粗体",
"italic": "斜体",
"code": "代码",
"ordered-list": "排序的列表",
"unordered-list": "非排序的列表",
"quote": "引用",
"link": "链接",
"horizontal-rule": "水平线",
"toggle-preview": "切换预览"
"format": "格式化JSON"
},
"bufferEditor": {
"title": "缓冲区编辑器",
"modeString": "作为UTF-8字符串处理",
"modeArray": "作为JSON数组处理",
"modeDesc": "<h3>缓冲区编辑器</h3><p>缓冲区类型被存储为字节值的JSON数组。编辑器将尝试将输入的数值解析为JSON数组。如果它不是有效的JSON它将被视为UTF-8字符串并被转换为单个字符代码点的数组。</p><p>例如,<code>Hello World</code>的值会被转换为JSON数组<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
},
"projects": {
"config-git": "配置Git客户端",
"welcome": {
"hello": "你好! 我们已经将“项目”引入了Node-RED。",
"desc0": "这是一种用于管理流程文件的新方法,并且包括对流程的版本控制。",
"desc1": "首先您可以创建您的第一个项目或从git存储库克隆现有项目。",
"desc2": "如果不确定,可以暂时跳过此步骤。您仍然可以随时通过“项目”菜单创建第一个项目。",
"create": "建立专案",
"clone": "克隆仓库",
"openExistingProject": "打开现有项目",
"not-right-now": "不是现在"
},
"git-config": {
"setup": "设置您的版本控制客户端",
"desc0": "Node-RED使用开源工具Git进行版本控制。它跟踪对项目文件的更改并允许您将其推送到远程存储库。",
"desc1": "提交一组更改时Git会使用用户名和电子邮件地址记录谁进行了更改。用户名可以是您想要的任何名称-不必是您的真实姓名。",
"desc2": "您的Git客户端已经配置了以下详细信息。",
"desc3": "您可以稍后在设置对话框的'Git config'标签下更改这些设置。",
"username": "用户名",
"email": "电子邮件"
},
"project-details": {
"create": "创建你的项目",
"desc0": "项目被维护为Git仓库。与他人一起共享您的流程",
"desc1": "您可以创建多个项目,并通过编辑器在它们之间快速切换。",
"desc2": "首先,您的项目需要一个名称和一个可选的描述。",
"already-exists": "项目已存在",
"must-contain": "只能包含A-Z 0-9 _ -",
"project-name": "项目名",
"desc": "描述",
"opt": "可选的"
},
"clone-project": {
"clone": "克隆一个项目",
"desc0": "如果您已经有一个包含项目的git仓库则可以对其进行克隆以开始使用。",
"already-exists": "项目已存在",
"must-contain": "只能包含A-Z 0-9 _ -",
"project-name": "项目名",
"no-info-in-url": "网址中不要包含用户名/密码",
"git-url": "Git仓库的url",
"protocols": "https://, ssh:// or file://",
"auth-failed": "认证失败",
"username": "用户名",
"passwd": "秘密啊",
"ssh-key": "SSH密钥",
"passphrase": "密码短语",
"ssh-key-desc": "在通过ssh克隆仓库之前必须添加SSH密钥才能访问它。",
"ssh-key-add": "添加一个ssh密钥",
"credential-key": "证书加密密钥",
"cant-get-ssh-key": "错误! 无法获取所选的SSH密钥路径。",
"already-exists2": "已存在",
"git-error": "git错误",
"connection-failed": "连接失败",
"not-git-repo": "不是一个git仓库",
"repo-not-found": "未发现仓库"
},
"default-files": {
"create": "创建您的项目文件",
"desc0": "一个包含您的流程文件Readme文件和package.json文件的项目。",
"desc1": "它可以包含您要在Git仓库中维护的任何其他文件。",
"desc2": "您现有的流程和凭证文件将被复制到项目中。",
"flow-file": "流程文件",
"credentials-file": "证书文件"
},
"encryption-config": {
"setup": "设置证书文件的加密",
"desc0": "您的流程证书文件可以被加密以确保其内容安全。",
"desc1": "如果要将这些证书存储在公共Git存储库中则必须通过提供密钥短语来对它们进行加密。",
"desc2": "您的流程证书文件当前未加密。",
"desc3": "这意味着任何有权访问该文件的人都可以读取其内容,例如密码和访问令牌。",
"desc4": "如果要将这些证书存储在公共Git仓库中则必须通过提供密钥短语来对它们进行加密。",
"desc5": "当前使用设置文件中的credentialSecret属性作为密钥来加密流程证书文件。",
"desc6": "您的流程证书文件当前使用系统生成的密钥加密。您应该为此项目提供一个新的密钥。",
"desc7": "密钥将与项目文件分开存储。您将需要提供在另一个Node-RED实例中使用该项目的密钥。",
"credentials": "证书",
"enable": "启用加密",
"disable": "禁用加密",
"disabled": "禁用的",
"copy": "复制现有密钥",
"use-custom": "使用自定义密钥",
"desc8": "证书文件不会被加密,其内容很容易阅读",
"create-project-files": "创建项目文件",
"create-project": "创建项目",
"already-exists": "已存在",
"git-error": "git错误",
"git-auth-error": "git认证错误"
},
"create-success": {
"success": "您已经成功创建了第一个项目!",
"desc0": "现在您可以像往常一样继续使用Node-RED。",
"desc1": "侧栏中的“信息”标签显示了您当前的活动项目。名称旁边的按钮可用于访问项目设置视图。",
"desc2": "侧栏中的“历史记录”标签可用于查看项目中已更改的文件并提交。它向您显示了提交的完整历史记录,并允许您将更改推送到远程存储库。"
},
"create": {
"projects": "项目",
"already-exists": "项目已存在",
"must-contain": "只能包含A-Z 0-9 _ -",
"no-info-in-url": "网址中不要包含用户名/密码",
"open": "打开项目",
"create": "创建项目",
"clone": "克隆仓库",
"project-name": "项目名",
"desc": "描述",
"opt": "可选的",
"flow-file": "流程文件",
"credentials": "证书",
"enable-encryption": "启用加密",
"disable-encryption": "禁用加密",
"encryption-key": "加密密钥",
"desc0": "用来保护您的凭证的短语",
"desc1": "凭证文件不会被加密,其内容很容易阅读",
"git-url": "Git存储库URL",
"protocols": "https://, ssh:// or file://",
"auth-failed": "验证失败",
"username": "用户名",
"password": "密码",
"ssh-key": "SSH密钥",
"passphrase": "密码短语",
"desc2": "在通过ssh克隆存储库之前必须添加SSH密钥才能访问它。",
"add-ssh-key": "添加一个ssh密钥",
"credentials-encryption-key": "证书加密密钥",
"already-exists-2": "已存在",
"git-error": "git错误",
"con-failed": "连接失败",
"not-git": "不是git仓库",
"no-resource": "找不到存储库",
"cant-get-ssh-key-path": "错误无法获取所选的SSH密钥路径。",
"unexpected_error": "意外的错误"
},
"delete": {
"confirm": "您确定要删除此项目吗?"
},
"create-project-list": {
"search": "搜索您的项目",
"current": "当前的"
},
"require-clean": {
"confirm": "<p>您有未部署的更改,这些更改将丢失。</p><p>您要继续吗?</p>"
},
"send-req": {
"auth-req": "存储库需要认证",
"username": "用户名",
"password": "秘密",
"passphrase": "密码短语",
"retry": "重试",
"update-failed": "无法更新身份验证",
"unhandled": "未处理的错误响应",
"host-key-verify-failed": "<p>主机密钥验证失败。</p><p>无法验证存储库主机密钥。请更新您的<code>known_hosts</code>文件,然后重试。</p>"
},
"create-branch-list": {
"invalid": "无效的分支",
"create": "创建分支",
"current": "当前的"
},
"create-default-file-set": {
"no-active": "没有活动项目就无法创建默认文件集",
"no-empty": "无法在非空项目上创建默认文件集",
"git-error": "git错误"
},
"errors": {
"no-username-email": "您的Git客户端未配置用户名/电子邮件。",
"unexpected": "发生了一个意料之外的问题",
"code": "代码"
}
},
"editor-tab": {
"properties": "属性",
"envProperties": "环境变量",
"description": "描述",
"appearance": "外观",
"preview": "UI预览",
"defaultValue": "默认值"
},
"languages": {
"de": "德语",
"en-US": "英文",
"ja": "日语",
"ko": "韩文",
"zh-CN": "简体中文",
"zh-TW": "繁体中文"
}
}

View File

@@ -1,15 +1,15 @@
{
"$string": {
"args": "arg",
"desc": "通过以下的类型转换规则将参数 *arg* 转换成字符串:\n\n - 字符串不转换。\n -函数转换成空的字符串。\n - JSON的值无法用数字表示所以用无限大或者NaN非数表示。\n - 用 `JSON.stringify` 函数将其他值转换成JSON字符串。"
"desc": "通过以下的类型转换规则将参数*arg*转换成字符串:\n\n - 字符串不转换。\n -函数转换成空的字符串。\n - JSON的值无法用数字表示所以用无限大或者NaN非数表示。\n - 用JSON.stringify函数将其他值转换成JSON字符串。"
},
"$length": {
"args": "str",
"desc": "输出字符串 `str` 的字数。如果 `str` 不是字符串,抛出错误。"
"desc": "输出字符串str的字数。如果str不是字符串,抛出错误。"
},
"$substring": {
"args": "str, start[, length]",
"desc": "输出 `start` 位置后的的首次出现的包括 `str` 的子字符串。 如果 `length` 被指定,那么的字符串中将只包括前 `length` 个文字。如果 `start` 是负数则输出从 `str` 末尾开始的 `length` 个文字"
"desc": "输出`start`位置后的的首次出现的包括`str`的子字符串。 如果`length`被指定,那么的字符串中将只包括前`length`个文字。如果`start`是负数则输出从`str`末尾开始的`length`个文字"
},
"$substringBefore": {
"args": "str, chars",
@@ -17,11 +17,11 @@
},
"$substringAfter": {
"args": "str, chars",
"desc": "输出 `str` 中首次出现的 `chars` 之后的子字符串,如果 `str` 中不包括 `chars` 则输出 `str` 。"
"desc": "输出str中首次出现的chars之后的子字符串,如果str中不包括chars则输出str。"
},
"$uppercase": {
"args": "str",
"desc": "将 `str` 中的所有字母变为大写后输出。"
"desc": "`将’str中的所有字母变为大写后输出。"
},
"$lowercase": {
"args": "str",
@@ -29,27 +29,27 @@
},
"$trim": {
"args": "str",
"desc": "将以下步骤应用于 `str` 来去除所有空白文字并实现标准化。\n\n 将全部tab制表符、回车键、换行字符用空白代替。\n- 将连续的空白文字变成一个空白文字。\n- 消除开头和末尾的空白文字。\n\n如果 `str` 没有被指定(即在无输入参数的情况下调用本函数),将上下文的值作为 `str` 来使用。 如果 `str` 不是字符串则抛出错误。"
"desc": "将以下步骤应用于`str`来去除所有空白文字并实现标准化。\n\n 将全部tab制表符、回车键、换行字符用空白代替。\n- 将连续的空白文字变成一个空白文字。\n- 消除开头和末尾的空白文字。\n\n如果`str`没有被指定(即在无输入参数的情况下调用本函数),将上下文的值作为`str`来使用。 如果`str` 不是字符串则抛出错误。"
},
"$contains": {
"args": "str, pattern",
"desc": "字符串 `str` 和 `pattern` 匹配的话输出 `true` ,不匹配的情况下输出 `false` 。 不指定 `str` 的情况下(比如用一个参数调用本函数时)、将上下文的值作为 `str` 来使用。参数 `pattern` 可以为字符串或正则表达。"
"desc": "字符串`str` 和 `pattern`匹配的话输出`true`,不匹配的情况下输出 `false`。 不指定`str`的情况下(比如用一个参数调用本函数时)、将上下文的值作为`str`来使用。参数 `pattern`可以为字符串或正则表达。"
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "将参数 `str` 分解成由子字符串组成的数组。 如果 `str` 不是字符串抛出错误。可以省略的参数 `separator` 中指定字符串 `str` 的分隔符。分隔符可以是文字或正则表达式。在不指定 `separator` 的情况下、将分隔符看作空的字符串并把 `str` 拆分成由单个字母组成的数组。如果 `separator` 不是字符串则抛出错误。在可省略的参数 `limit` 中指定分割后的子字符串的最大个数。超出个数的子字符串将被舍弃。如果 `limit` 没有被指定,`str` 将不考虑子字符串的个数而将字符串完全分隔。如果 `limit` 是负数则抛出错误。"
"desc": "将参数`str`分解成由子字符串组成的数组。 如果`str`不是字符串抛出错误。可以省略的参数 `separator`中指定字符串`str`的分隔符。分隔符可以是文字或正则表达式。在不指定`separator`的情况下、将分隔符看作空的字符串并把`str`拆分成由单个字母组成的数组。如果`separator`不是字符串则抛出错误。在可省略的参数`limit`中指定分割后的子字符串的最大个数。超出个数的子字符串将被舍弃。如果`limit`没有被指定,`str` 将不考虑子字符串的个数而将字符串完全分隔。如果`limit`是负数则抛出错误。"
},
"$join": {
"args": "array[, separator]",
"desc": "用可以省略的参数 `separator` 来把多个字符串连接。如果 `array` 不是字符串则抛出错误。 如果没有指定 `separator` ,则用空字符串来连接字符(即字符串之间没有 `separator` )。 如果 `separator` 不是字符则抛出错误。"
"desc": "用可以省略的参数 `separator`来把多个字符串连接。如果`array`不是字符串则抛出错误。 如果没有指定`separator`,则用空字符串来连接字符(即字符串之间没有`separator`)。 如果`separator`不是字符则抛出错误。"
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "对字符串 `str` 使用正则表达式 `pattern` 并输出与 `str` 相匹配的部分信息。"
"desc": "对字符串`str`使用正则表达式`pattern`并输出与`str`相匹配的部分信息。"
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "在字符串 `str` 中搜索 `pattern` 并用 `replacement` 来替换。\n\n可选参数 `limit` 用来指定替换次数的上限。"
"desc": "在字符串`str`中搜索`pattern`并用`replacement`来替换。\n\n可选参数`limit`用来指定替换次数的上限。"
},
"$now": {
"args": "",
@@ -65,31 +65,31 @@
},
"$number": {
"args": "arg",
"desc": "用下述的规则将参数 `arg` 转换为数值。:\n\n 数值不做转换。\n 将字符串中合法的JSON数値表示转换成数値。\n 其他形式的值则抛出错误。"
"desc": "用下述的规则将参数 `arg`转换为数值。:\n\n 数值不做转换。\n 将字符串中合法的JSON数値表示转换成数値。\n 其他形式的值则抛出错误。"
},
"$abs": {
"args": "number",
"desc": "输出参数 `number` 的绝对值。"
"desc": "输出参数`number`的绝对值。"
},
"$floor": {
"args": "number",
"desc": "输出比 `number` 的值小的最大整数。"
"desc": "输出比`number`的值小的最大整数。"
},
"$ceil": {
"args": "number",
"desc": "输出比 `number` 的值大的最小整数。"
"desc": "输出比`number`的值大的最小整数。"
},
"$round": {
"args": "number [, precision]",
"desc": "输出四舍五入后的参数 `number` 。可省略的参数 `precision` 指定四舍五入后小数点下的位数。"
"desc": "输出四舍五入后的参数`number`。可省略的参数 `precision`指定四舍五入后小数点下的位数。"
},
"$power": {
"args": "base, exponent",
"desc": "输出底数 `base``exponent` 次幂。"
"desc": "输出底数`base``exponent`次幂。"
},
"$sqrt": {
"args": "number",
"desc": "输出参数 `number` 的平方根。"
"desc": "输出参数 `number`的平方根。"
},
"$random": {
"args": "",
@@ -97,35 +97,35 @@
},
"$millis": {
"args": "",
"desc": "返回从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。在同一个表达式的测试中所有对 `$millis()` 的调用将会返回相同的值。"
"desc": "返回从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。在同一个表达式的测试中所有对`$millis()`的调用将会返回相同的值。"
},
"$sum": {
"args": "array",
"desc": "输出数组 `array` 的总和。如果 `array` 不是数值则抛出错误。"
"desc": "输出数组`array`的总和。如果`array`不是数值则抛出错误。"
},
"$max": {
"args": "array",
"desc": "输出数组 `array` 的最大值。如果 `array` 不是数值则抛出错误。"
"desc": "输出数组`array`的最大值。如果`array`不是数值则抛出错误。"
},
"$min": {
"args": "array",
"desc": "输出数组 `array` 的最小值。如果 `array` 不是数值则抛出错误。。"
"desc": "输出数组`array`的最小值。如果`array`不是数值则抛出错误。。"
},
"$average": {
"args": "array",
"desc": "输出数组 `array` 的平均数。如果 `array` 不是数值则抛出错误。。"
"desc": "输出数组`array`的平均数。如果`array`不是数值则抛出错误。。"
},
"$boolean": {
"args": "arg",
"desc": "用下述规则将数据转换成布尔值。:\n\n - 不转换布尔值 `Boolean` 。\n 将空的字符串 `string` 转换为 `false` \n 将不为空的字符串 `string` 转换为 `true` \n 将为0的数字 `number` 转换成 `false` \n 将不为0的数字 `number` 转换成 `true` \n –将 `null` 转换成 `false` \n –将空的数组 `array` 转换成 `false` \n –如果数组 `array` 中含有可以转换成 `true` 的要素则转换成 `true` \n –如果 `array` 中没有可转换成 `true` 的要素则转换成 `false` \n 空的对象 `object` 转换成 `false` \n 非空的对象 `object` 转换成 `true` \n –将函数 `function` 转换成 `false` "
"desc": "用下述规则将数据转换成布尔值。:\n\n - 不转换布尔值`Boolean`。\n 将空的字符串`string`转换为`false`\n 将不为空的字符串`string`转换为`true`\n 将为0的数字`number`转换成`false`\n 将不为0的数字`number`转换成`true`\n –将`null`转换成`false`\n –将空的数组`array`转换成`false`\n –如果数组`array`中含有可以转换成`true`的要素则转换成`true`\n –如果`array`中没有可转换成`true`的要素则转换成`false`\n 空的对象`object`转换成`false`\n 非空的对象`object`转换成`true`\n –将函数`function`转换成`false`"
},
"$not": {
"args": "arg",
"desc": "输出做取反运算后的布尔值。首先将 `arg` 转换为布尔值。"
"desc": "输出做取反运算后的布尔值。首先将`arg`转换为布尔值。"
},
"$exists": {
"args": "arg",
"desc": "如果算式 `arg` 的值存在则输出 `true` 。如果算式的值不存在(比如指向不存在区域的引用)则输出 `false` 。"
"desc": "如果算式`arg`的值存在则输出`true`。如果算式的值不存在(比如指向不存在区域的引用)则输出`false`。"
},
"$count": {
"args": "array",
@@ -137,15 +137,15 @@
},
"$sort": {
"args": "array [, function]",
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)` \n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。"
"desc": "输出排序后的数组`array`。\n\n如果使用了比较函数`function`,则下述两个参数需要被指定。\n\n`function(left, right)`\n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后那么该函数必须输出布尔值`true`来表示位置交换。而在不需要位置交换时函数必须输出`false`。"
},
"$reverse": {
"args": "array",
"desc": "输出倒序后的数组 `array` 。"
"desc": "输出倒序后的数组`array`。"
},
"$shuffle": {
"args": "array",
"desc": "输出随机排序后的数组 `array` 。"
"desc": "输出随机排序后的数组 `array`。"
},
"$zip": {
"args": "array, ...",
@@ -157,35 +157,35 @@
},
"$lookup": {
"args": "object, key",
"desc": "输出对象中与参数 `key` 对应的值。如果第一个参数 `object` 是数组,那么数组中所有的对象都将被搜索并输出这些对象中与参数 `key` 对应的值。"
"desc": "输出对象中与参数`key`对应的值。如果第一个参数`object`是数组,那么数组中所有的对象都将被搜索并输出这些对象中与参数`key`对应的值。"
},
"$spread": {
"args": "object",
"desc": "将对象中的键值对分隔成每个要素中只含有一个键值对的数组。如果参数 `object` 是数组,那么返回值的数组中包含所有对象中的键值对。"
"desc": "将对象中的键值对分隔成每个要素中只含有一个键值对的数组。如果参数`object`是数组,那么返回值的数组中包含所有对象中的键值对。"
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "将输入数组 `objects` 中所有的键值对合并到一个 `object` 中并返回。如果输入数组的要素中含有重复的键,则返回的 `object` 中将只包含数组中最后出现要素的值。如果输入数组中包括对象以外的元素,则抛出错误。"
"desc": "将输入数组`objects`中所有的键值对合并到一个`object`中并返回。如果输入数组的要素中含有重复的键,则返回的`object`中将只包含数组中最后出现要素的值。如果输入数组中包括对象以外的元素,则抛出错误。"
},
"$sift": {
"args": "object, function",
"desc": "输出参数 `object` 中符合 `function` 的键值对。\n\n `function` 必须含有下述参数。\n\n `function(value [, key [, object]])` "
"desc": "输出参数`object`中符合`function`的键值对。\n\n`function`必须含有下述参数。\n\n`function(value [, key [, object]])`"
},
"$each": {
"args": "object, function",
"desc": "将函数 `function` 应用于 `object` 中的所有键值对并输出由所有返回值组成的数组。"
"desc": "将函数`function`应用于`object`中的所有键值对并输出由所有返回值组成的数组。"
},
"$map": {
"args": "array, function",
"desc": "将函数 `function` 应用于数组 `array` 中所有的值并输出由返回值组成的数组。\n\n `function` 中必须含有下述参数。\n\n`function(value [, index [, array]])` "
"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]])`"
"desc": "输出数组`array`中符合函数`function`条件的值组成的数组。\n\n`function`必须包括下述参数。\n\n`function(value [, index [, array]])`"
},
"$reduce": {
"args": "array, function [, init]",
"desc": "将 `function` 依次应用于数组中的各要素值。 其中,前一个要素值的计算结果将参与到下一次的函数运算中。。\n\n函数 `function` 接受两个参数并作为中缀表示法中的操作符。\n\n可省略的参数 `init` 将作为运算的初始值。"
"desc": "将`function`依次应用于数组中的各要素值。 其中,前一个要素值的计算结果将参与到下一次的函数运算中。。\n\n函数`function`接受两个参数并作为中缀表示法中的操作符。\n\n可省略的参数`init`将作为运算的初始值。"
},
"$flowContext": {
"args": "string",
@@ -197,7 +197,7 @@
},
"$pad": {
"args": "string, width [, char]",
"desc": "根据需要,向字符串 `string` 的副本中填充文字使该字符串的字数达到 `width` 的绝对值并返回填充文字后的字符串。\n\n如果 `width` 的值为正,则向字符串 `string` 的右侧填充文字,如果 `width` 为负,则向字符串 `string` 的左侧填充文字。\n\n可选参数 `char` 用来指定填充的文字。如果未指定该参数,则填充空白文字。"
"desc": "根据需要,向字符串`string`的副本中填充文字使该字符串的字数达到`width`的绝对值并返回填充文字后的字符串。\n\n如果`width`的值为正,则向字符串`string`的右侧填充文字,如果`width`为负,则向字符串`string`的左侧填充文字。\n\n可选参数`char`用来指定填充的文字。如果未指定该参数,则填充空白文字。"
},
"$fromMillis": {
"args": "number",
@@ -205,70 +205,14 @@
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "将 `number` 转换成具有 `picture` 所指定的数值格式的字符串。\n\n此函数的功能与XPath F&O 3.1规格中定义的XPath/XQuery函数的fn:format-number功能相一致。参数 `picture` 用于指定数值的转换格式其语法与fn:format-number中的定义一致。\n\n可选的第三参数 `options` 用来覆盖默认的局部环境格式如小数点分隔符。如果指定该参数那么该参数必须是包含name/value对的对象并且name/value对必须符合XPath F&O 3.1规格中记述的数值格式。"
"desc": "将`number`转换成具有`picture`所指定的数值格式的字符串。\n\n此函数的功能与XPath F&O 3.1规格中定义的XPath/XQuery函数的fn:format-number功能相一致。参数`picture`用于指定数值的转换格式其语法与fn:format-number中的定义一致。\n\n可选的第三参数`options`用来覆盖默认的局部环境格式如小数点分隔符。如果指定该参数那么该参数必须是包含name/value对的对象并且name/value对必须符合XPath F&O 3.1规格中记述的数值格式。"
},
"$formatBase": {
"args": "number [, radix]",
"desc": "将 `number` 变换为以参数 `radix` 的值为基数形式的字符串。如果不指定 `radix` 的值则默认基数为10。指定的 `radix` 值必须在236之间否则抛出错误。"
"desc": "将`number`变换为以参数`radix`的值为基数形式的字符串。如果不指定`radix`的值则默认基数为10。指定的`radix`值必须在236之间否则抛出错误。"
},
"$toMillis": {
"args": "timestamp",
"desc": "将ISO 8601格式的字符串 `timestamp` 转换为从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。如果该字符串的格式不正确则抛出错误。"
},
"$env": {
"args": "arg",
"desc": "返回环境变量的值。\n\n这是Node-RED定义的函数。"
},
"$eval": {
"args": "expr [, context]",
"desc": "使用当前上下文来作为评估依据,分析并评估字符串 `expr` 其中包含文字JSON或JSONata表达式。"
},
"$formatInteger": {
"args": "number, picture",
"desc": "将“数字”转换为字符串并将其格式化为“图片”字符串指定的整数表示形式。图片字符串参数定义了数字的格式并具有与XPath F&O 3.1 规范中的fnformat-integer相同的语法。"
},
"$parseInteger": {
"args": "string, picture",
"desc": "使用“图片”字符串指定的格式将“字符串”参数的内容解析为整数作为JSON数字。图片字符串参数与$formatInteger格式相同。."
},
"$error": {
"args": "[str]",
"desc": "引发错误并显示一条消息。 可选的 `str` 将替代$error()函数评估的默认消息。"
},
"$assert": {
"args": "arg, str",
"desc": "如果 `arg` 为真,则该函数返回。 如果arg为假则抛出带有str的异常作为异常消息。"
},
"$single": {
"args": "array, function",
"desc": "返回满足参数function谓语的array参数中的唯一值 (比如传递值时函数返回布尔值“true”)。如果匹配值的数量不唯一时,则抛出异常。\n\n应在以下签名中提供函数 `functionvalue [index [array []]]` 其中value是数组的每个输入index是该值的位置整个数组作为第三个参数传递。"
},
"$encodeUrl": {
"args": "str",
"desc": "通过用表示字符的UTF-8编码的一个两个三个或四个转义序列替换某些字符的每个实例对统一资源定位符URL组件进行编码。\n\n示例 `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "通过用表示字符的UTF-8编码的一个两个三个或四个转义序列替换某些字符的每个实例对统一资源定位符URL进行编码。\n\n示例 `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "解码以前由encodeUrlComponent创建的统一资源定位器URL组件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "解码先前由encodeUrl创建的统一资源定位符URL。 \n\n示例 `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "返回一个数组,其中重复的值已从 `数组` 中删除"
},
"$type": {
"args": "value",
"desc": "以字符串形式返回 `值` 的类型。 如果该 `值` 未定义,则将返回 `未定义` "
},
"$moment": {
"args": "[str]",
"desc": "使用Moment库获取日期对象。"
"desc": "将ISO 8601格式的字符串`timestamp`转换为从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。如果该字符串的格式不正确则抛出错误。"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +0,0 @@
{
"info": {
"tip0" : "您可以用 {{core:delete-selection}} 刪除選擇的節點或連結。",
"tip1" : "{{core:search}} 可以在流程內搜索節點。",
"tip2": "{{core:toggle-sidebar}} 可以顯示或隱藏邊側欄。",
"tip3": "您可以在 {{core:manage-palette}} 中管理節點的控制台。",
"tip4": "側邊欄中會列出流程中所有的配置節點。您可以通過功能表或者 {{core:show-config-tab}} 來訪問這些節點。",
"tip5": "您可以在設定中選擇顯示或隱藏這些提示。",
"tip6": "您可以用[left] [up] [down] [right]鍵來移動被選中的節點。按住[shift]可以更快地移動節點。",
"tip7": "把節點拖到連接上可以向連接中插入節點。",
"tip8": "您可以用 {{core:show-export-dialog}} 來匯出被選中的節點或標籤頁中的流程。",
"tip9": "您可以將流程的json文字檔拖入編輯方塊或 {{core:show-import-dialog}} 來導入流程。",
"tip10": "按住[shift]後按一下並拖動節點可以將該節點的多個連接一併移動到其他節點的埠。",
"tip11": "{{core:show-info-tab}} 可以顯示「資訊」標籤頁。 {{core:show-debug-tab}} 可以顯示「調試」標籤頁。",
"tip12": "按住[ctrl]的同時點擊工作介面可以在節點的對話欄中快速添加節點。",
"tip13": "按住[ctrl]的同時點擊節點的埠或後續節點可以快速連接多個節點。",
"tip14": "按住[shift]的同時點擊節點會選中所有被連接的節點。",
"tip15": "按住[ctrl]的同時點擊節點可以在選中或取消選中節點。",
"tip16": "{{core:show-previous-tab}} 和 {{core:show-next-tab}} 可以切換標籤頁。",
"tip17": "您可以在節點的屬性配置畫面中通過 {{core:confirm-edit-tray}} 來更改設置,或者用 {{core:cancel-edit-tray}} 來取消更改。",
"tip18": "您可以通過點擊 {{core:edit-selected-node}} 來顯示被選中節點的屬性設置畫面。"
}
}

View File

@@ -1,274 +0,0 @@
{
"$string": {
"args": "arg",
"desc": "通過以下的類型轉換規則將參數*arg*轉換成字串:\n\n - 字串不轉換。\n -函數轉換成空的字串。\n - JSON的值無法用數字表示所以用無限大或者NaN非數表示。\n - 用JSON.stringify函數將其他值轉換成JSON字串。"
},
"$length": {
"args": "str",
"desc": "輸出字串str的字數。如果str不是字串拋出錯誤。"
},
"$substring": {
"args": "str, start[, length]",
"desc": "輸出`start`位置後的的首次出現的包括`str`的子字串。 如果`length`被指定,那麼的字串中將只包括前`length`個文字。如果`start`是負數則輸出從`str`末尾開始的`length`個文字"
},
"$substringBefore": {
"args": "str, chars",
"desc": "輸出str中首次出現的chars之前的子字串如果str中不包括chars則輸出str。"
},
"$substringAfter": {
"args": "str, chars",
"desc": "輸出str中首次出現的chars之後的子字串如果str中不包括chars則輸出str。"
},
"$uppercase": {
"args": "str",
"desc": "`將str中的所有字母變為大寫後輸出。"
},
"$lowercase": {
"args": "str",
"desc": "將str中的所有字母變為小寫後輸出。"
},
"$trim": {
"args": "str",
"desc": "將以下步驟應用於`str`來去除所有空白文字並實現標準化。\n\n 將全部tab定位字元、Enter鍵、換行字元用空白代替。\n- 將連續的空白文字變成一個空白文字。\n- 消除開頭和末尾的空白文字。\n\n如果`str`沒有被指定(即在無輸入參數的情況下調用本函數),將上下文的值作為`str`來使用。 如果`str` 不是字串則拋出錯誤。"
},
"$contains": {
"args": "str, pattern",
"desc": "字串`str` 和 `pattern`匹配的話輸出`true`,不匹配的情況下輸出 `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`來把多個字元串連接。如果`array`不是字串則拋出錯誤。 如果沒有指定`separator`,則用空字串來連接字元(即字串之間沒有`separator`)。 如果`separator`不是字元則拋出錯誤。"
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "對字串`str`使用規則運算式`pattern`並輸出與`str`相匹配的部分資訊。"
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "在字串`str`中搜索`pattern`並用`replacement`來替換。\n\n可選參數`limit`用來指定替換次數的上限。"
},
"$now": {
"args": "",
"desc": "生成ISO 8601互換格式的時刻並作為字串輸出。"
},
"$base64encode": {
"args": "string",
"desc": "將ASCII格式的字串轉換為Base 64格式。將字串中的文字視作二進位形式的資料處理。包含URI編碼在內的字串文字必須在0x00到0xFF的範圍內否則不會被支持。"
},
"$base64decode": {
"args": "string",
"desc": "用UTF-8內碼表將Base 64形式二進位值轉換為字串。"
},
"$number": {
"args": "arg",
"desc": "用下述的規則將參數 `arg`轉換為數值。:\n\n 數值不做轉換。\n 將字串中合法的JSON數値表示轉換成數値。\n 其他形式的值則拋出錯誤。"
},
"$abs": {
"args": "number",
"desc": "輸出參數`number`的絕對值。"
},
"$floor": {
"args": "number",
"desc": "輸出比`number`的值小的最大整數。"
},
"$ceil": {
"args": "number",
"desc": "輸出比`number`的值大的最小整數。"
},
"$round": {
"args": "number [, precision]",
"desc": "輸出四捨五入後的參數`number`。可省略的參數 `precision`指定四捨五入後小數點下的位數。"
},
"$power": {
"args": "base, exponent",
"desc": "輸出底數`base`的`exponent`次冪。"
},
"$sqrt": {
"args": "number",
"desc": "輸出參數 `number`的平方根。"
},
"$random": {
"args": "",
"desc": "輸出比0大比1小的偽亂數。"
},
"$millis": {
"args": "",
"desc": "返回從UNIX時間 (1970年1月1日 UTC/GMT的午夜開始到現在的毫秒數。在同一個運算式的測試中所有對`$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 - 不轉換布林值`Boolean`。\n 將空的字串`string`轉換為`false`\n 將不為空的字串`string`轉換為`true`\n 將為0的數位`number`轉換成`false`\n 將不為0的數位`number`轉換成`true`\n –將`null`轉換成`false`\n –將空的陣列`array`轉換成`false`\n –如果陣列`array`中含有可以轉換成`true`的要素則轉換成`true`\n –如果`array`中沒有可轉換成`true`的要素則轉換成`false`\n 空的物件`object`轉換成`false`\n 非空的物件`object`轉換成`true`\n –將函數`function`轉換成`false`"
},
"$not": {
"args": "arg",
"desc": "輸出做反轉運算後的布林值。首先將`arg`轉換為布林值。"
},
"$exists": {
"args": "arg",
"desc": "如果算式`arg`的值存在則輸出`true`。如果算式的值不存在(比如指向不存在區域的引用)則輸出`false`。"
},
"$count": {
"args": "array",
"desc": "輸出陣列中的元素數。"
},
"$append": {
"args": "array, array",
"desc": "將兩個陣列連接。"
},
"$sort": {
"args": "array [, function]",
"desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較left和right兩個值而被排序演算法調用的。如果使用者希望left的值被置於right的值之後那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。"
},
"$reverse": {
"args": "array",
"desc": "輸出倒序後的陣列`array`。"
},
"$shuffle": {
"args": "array",
"desc": "輸出隨機排序後的陣列 `array`。"
},
"$zip": {
"args": "array, ...",
"desc": "將陣列中的值按索引順序打包後輸出。"
},
"$keys": {
"args": "object",
"desc": "輸出由物件內的鍵組成的陣列。如果參數是物件的陣列則輸出由所有物件中的鍵去重後組成的佇列。"
},
"$lookup": {
"args": "object, key",
"desc": "輸出對象中與參數`key`對應的值。如果第一個參數`object`是陣列,那麼陣列中所有的物件都將被搜索並輸出這些物件中與參數`key`對應的值。"
},
"$spread": {
"args": "object",
"desc": "將物件中的鍵值對分隔成每個要素中只含有一個鍵值對的陣列。如果參數`object`是陣列,那麼返回值的陣列中包含所有物件中的鍵值對。"
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "將輸入陣列`objects`中所有的鍵值對合併到一個`object`中並返回。如果輸入陣列的要素中含有重複的鍵,則返回的`object`中將只包含陣列中最後出現要素的值。如果輸入陣列中包括物件以外的元素,則拋出錯誤。"
},
"$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函數`function`接受兩個參數並作為中綴標記法中的操作符。\n\n可省略的參數`init`將作為運算的初始值。"
},
"$flowContext": {
"args": "string",
"desc": "獲取流上下文(流等級的上下文,可以讓所有節點共用)的屬性。"
},
"$globalContext": {
"args": "string",
"desc": "獲取全域上下文的屬性。"
},
"$pad": {
"args": "string, width [, char]",
"desc": "根據需要,向字串`string`的副本中填充文字使該字串的字數達到`width`的絕對值並返回填充文字後的字串。\n\n如果`width`的值為正,則向字串`string`的右側填充文字,如果`width`為負,則向字串`string`的左側填充文字。\n\n可選參數`char`用來指定填充的文字。如果未指定該參數,則填充空白文字。"
},
"$fromMillis": {
"args": "number",
"desc": "將表示從UNIX時間 (1970年1月1日 UTC/GMT的午夜開始到現在的毫秒數的數值轉換成ISO 8601形式時間戳記的字串。"
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "將`number`轉換成具有`picture`所指定的數值格式的字串。\n\n此函數的功能與XPath F&O 3.1規格中定義的XPath/XQuery函數的fn:format-number功能相一致。參數`picture`用於指定數值的轉換格式其語法與fn:format-number中的定義一致。\n\n可選的第三參數`options`用來覆蓋預設的局部環境格式如小數點分隔符號。如果指定該參數那麼該參數必須是包含name/value對的物件並且name/value對必須符合XPath F&O 3.1規格中記述的數值格式。"
},
"$formatBase": {
"args": "number [, radix]",
"desc": "將`number`變換為以參數`radix`的值為基數形式的字串。如果不指定`radix`的值則默認基數為10。指定的`radix`值必須在236之間否則拋出錯誤。"
},
"$toMillis": {
"args": "timestamp",
"desc": "將ISO 8601格式的字串`timestamp`轉換為從UNIX時間 (1970年1月1日 UTC/GMT的午夜開始到現在的毫秒數。如果該字串的格式不正確則拋出錯誤。"
},
"$env": {
"args": "arg",
"desc": "返回環境變量的值。\n\n這是Node-RED定義的函數。"
},
"$eval": {
"args": "expr [, context]",
"desc": "使用當前上下文來作為評估依據,分析並評估字符串`expr`其中包含文字JSON或JSONata表達式。"
},
"$formatInteger": {
"args": "number, picture",
"desc": "將“數字”轉換為字符串並將其格式化為“圖片”字符串指定的整數表示形式。圖片字符串參數定義了數字的格式並具有與XPath F&O 3.1 規範中的fnformat-integer相同的語法。"
},
"$parseInteger": {
"args": "string, picture",
"desc": "使用“圖片”字符串指定的格式將“字符串”參數的內容解析為整數作為JSON數字。圖片字符串參數與$formatInteger格式相同。."
},
"$error": {
"args": "[str]",
"desc": "引發錯誤並顯示一條消息。 可選的`str`將替代$error()函數評估的默認消息。"
},
"$assert": {
"args": "arg, str",
"desc": "如果`arg`為真,則該函數返回。 如果arg為假則拋出帶有str的異常作為異常消息。"
},
"$single": {
"args": "array, function",
"desc": "返回滿足參數function謂語的array參數中的唯一值 (比如傳遞值時函數返回布林值“true”)。如果匹配值的數量不唯一時,則拋出異常。\n\n應在以下簽名中提供函數`functionvalue [index [array []]]`其中value是數組的每個輸入index是該值的位置整個數組作為第三個參數傳遞。"
},
"$encodeUrl": {
"args": "str",
"desc": "通過用表示字符的UTF-8編碼的一個兩個三個或四個轉義序列替換某些字符的每個實例對統一資源定位符URL組件進行編碼。\n\n示例`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "通過用表示字符的UTF-8編碼的一個兩個三個或四個轉義序列替換某些字符的每個實例對統一資源定位符URL進行編碼。\n\n示例 `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "解碼以前由encodeUrlComponent創建的統一資源定位器URL組件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "解碼先前由encodeUrl創建的統一資源定位符URL。 \n\n示例 `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "返回一個數組,其中重復的值已從`數組`中刪除"
},
"$type": {
"args": "value",
"desc": "以字符串形式返回`值`的類型。 如果該`值`未定義,則將返回`未定義`"
},
"$moment": {
"args": "[str]",
"desc": "使用Moment庫獲取日期對象。"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "1.1.3",
"version": "1.0.2",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -1,4 +1,4 @@
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"});
ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="nrjavascript"});
(function() {
ace.require(["ace/snippets/nrjavascript"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
@@ -6,3 +6,4 @@ ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippet
}
});
})();

View File

@@ -32,19 +32,14 @@
}
}
}
function emit() {
var evt = arguments[0]
var args = Array.prototype.slice.call(arguments,1);
if (RED.events.DEBUG) {
console.warn(evt,args);
}
function emit(evt,arg) {
if (handlers[evt]) {
for (var i=0;i<handlers[evt].length;i++) {
try {
handlers[evt][i].apply(null, args);
handlers[evt][i](arg);
} catch(err) {
console.warn("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.warn(err);
console.log("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.log(err);
}
}

View File

@@ -808,7 +808,17 @@ RED.nodes.fontAwesome = (function() {
"fa-youtube": "\uf167",
};
var iconList = Object.keys(iconMap);
var iconList = [];
var isUsed = {};
Object.keys(iconMap).forEach(function(icon) {
var unicode = iconMap[icon];
// skip icons with a same unicode
if (isUsed[unicode] !== true) {
iconList.push(icon);
isUsed[unicode] = true;
}
});
isUsed = undefined;
return {
getIconUnicode: function(name) {

View File

@@ -21,7 +21,6 @@ RED.history = (function() {
var i;
var len;
var node;
var group;
var subflow;
var modifiedTabs = {};
var inverseEv;
@@ -40,7 +39,7 @@ RED.history = (function() {
inverseEv = {
t: 'replace',
config: RED.nodes.createCompleteNodeSet(),
changed: {},
changed: [],
rev: RED.nodes.version()
};
RED.nodes.clear();
@@ -66,14 +65,6 @@ RED.history = (function() {
}
inverseEv.nodes.push(node);
RED.nodes.remove(ev.nodes[i]);
if (node.g) {
var group = RED.nodes.group(node.g);
var index = group.nodes.indexOf(node);
if (index !== -1) {
group.nodes.splice(index,1);
RED.group.markDirty(group);
}
}
}
}
if (ev.links) {
@@ -83,17 +74,6 @@ RED.history = (function() {
RED.nodes.removeLink(ev.links[i]);
}
}
if (ev.groups) {
inverseEv.groups = [];
for (i = ev.groups.length - 1;i>=0;i--) {
group = ev.groups[i];
modifiedTabs[group.z] = true;
// The order of groups is important
// - to invert the action, the order is reversed
inverseEv.groups.unshift(group);
RED.nodes.removeGroup(group);
}
}
if (ev.workspaces) {
inverseEv.workspaces = [];
for (i=0;i<ev.workspaces.length;i++) {
@@ -206,46 +186,19 @@ RED.history = (function() {
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
n.inputs = subflow.in.length;
n.outputs = subflow.out.length;
while (n.outputs > n.ports.length) {
n.ports.push(n.ports.length);
}
n.resize = true;
n.dirty = true;
});
}
if (ev.groups) {
inverseEv.groups = [];
var groupsToAdd = {};
ev.groups.forEach(function(g) { groupsToAdd[g.id] = g; });
for (i = ev.groups.length - 1;i>=0;i--) {
RED.nodes.addGroup(ev.groups[i])
modifiedTabs[ev.groups[i].z] = true;
// The order of groups is important
// - to invert the action, the order is reversed
inverseEv.groups.unshift(ev.groups[i]);
if (ev.groups[i].g) {
if (!groupsToAdd[ev.groups[i].g]) {
group = RED.nodes.group(ev.groups[i].g);
} else {
group = groupsToAdd[ev.groups[i].g];
}
if (group.nodes.indexOf(ev.groups[i]) === -1) {
group.nodes.push(ev.groups[i]);
}
RED.group.markDirty(ev.groups[i])
}
}
}
if (ev.nodes) {
inverseEv.nodes = [];
for (i=0;i<ev.nodes.length;i++) {
RED.nodes.add(ev.nodes[i]);
modifiedTabs[ev.nodes[i].z] = true;
inverseEv.nodes.push(ev.nodes[i].id);
if (ev.nodes[i].g) {
group = RED.nodes.group(ev.nodes[i].g);
if (group.nodes.indexOf(ev.nodes[i]) === -1) {
group.nodes.push(ev.nodes[i]);
}
RED.group.markDirty(group)
}
}
}
if (ev.links) {
@@ -274,12 +227,9 @@ RED.history = (function() {
}
node.dirty = true;
}
RED.events.emit("nodes:change",node);
}
}
}
if (subflow) {
RED.events.emit("subflows:change", subflow);
}
} else if (ev.t == "move") {
inverseEv = {
@@ -310,13 +260,6 @@ RED.history = (function() {
RED.nodes.addLink(ev.removedLinks[i]);
}
}
if (ev.addToGroup) {
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false);
inverseEv.removeFromGroup = ev.addToGroup;
} else if (ev.removeFromGroup) {
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
inverseEv.addToGroup = ev.removeFromGroup;
}
} else if (ev.t == "edit") {
inverseEv = {
t: "edit",
@@ -331,28 +274,15 @@ RED.history = (function() {
var currentConfigNode = RED.nodes.node(ev.node[i]);
if (currentConfigNode) {
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
RED.events.emit("nodes:change",currentConfigNode);
}
var newConfigNode = RED.nodes.node(ev.changes[i]);
if (newConfigNode) {
newConfigNode.users.push(ev.node);
RED.events.emit("nodes:change",newConfigNode);
}
}
ev.node[i] = ev.changes[i];
}
}
var eventType;
switch(ev.node.type) {
case 'tab': eventType = "flows"; break;
case 'group': eventType = "groups"; break;
case 'subflow': eventType = "subflows"; break;
default: eventType = "nodes"; break;
}
eventType += ":change";
RED.events.emit(eventType,ev.node);
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled);
@@ -412,7 +342,6 @@ RED.history = (function() {
}
}
}
ev.node.__outputs = inverseEv.changes.outputs;
RED.editor.updateNodeProperties(ev.node,outputMap);
RED.editor.validateNode(ev.node);
}
@@ -441,9 +370,7 @@ RED.history = (function() {
if (ev.nodes) {
inverseEv.movedNodes = [];
var z = ev.activeWorkspace;
var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
fullNodeList.forEach(function(n) {
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) {
n.x += ev.subflow.offsetX;
n.y += ev.subflow.offsetY;
n.dirty = true;
@@ -484,9 +411,6 @@ RED.history = (function() {
if (ev.subflow) {
RED.nodes.addSubflow(ev.subflow.subflow);
inverseEv.subflow = ev.subflow;
if (ev.subflow.subflow.g) {
RED.group.addToGroup(RED.nodes.group(ev.subflow.subflow.g),ev.subflow.subflow);
}
}
if (ev.subflows) {
inverseEv.nodes = [];
@@ -498,9 +422,6 @@ RED.history = (function() {
if (ev.movedNodes) {
ev.movedNodes.forEach(function(nid) {
nn = RED.nodes.node(nid);
if (!nn) {
nn = RED.nodes.group(nid);
}
nn.x -= ev.subflow.offsetX;
nn.y -= ev.subflow.offsetY;
nn.dirty = true;
@@ -514,7 +435,7 @@ RED.history = (function() {
RED.nodes.addLink(ev.links[i]);
}
}
if (ev.createdLinks) {
if (ev.createdLinks) {
inverseEv.removedLinks = [];
for (i=0;i<ev.createdLinks.length;i++) {
inverseEv.removedLinks.push(ev.createdLinks[i]);
@@ -529,60 +450,6 @@ RED.history = (function() {
if (ev.order) {
RED.workspaces.order(ev.order);
}
} else if (ev.t == "createGroup") {
inverseEv = {
t: "ungroup",
dirty: RED.nodes.dirty(),
groups: []
}
if (ev.groups) {
for (i=0;i<ev.groups.length;i++) {
inverseEv.groups.push(ev.groups[i]);
RED.group.ungroup(ev.groups[i]);
}
}
} else if (ev.t == "ungroup") {
inverseEv = {
t: "createGroup",
dirty: RED.nodes.dirty(),
groups: []
}
if (ev.groups) {
for (i=0;i<ev.groups.length;i++) {
inverseEv.groups.push(ev.groups[i]);
var nodes = ev.groups[i].nodes.slice();
ev.groups[i].nodes = [];
RED.nodes.addGroup(ev.groups[i]);
RED.group.addToGroup(ev.groups[i],nodes);
}
}
} else if (ev.t == "addToGroup") {
inverseEv = {
t: "removeFromGroup",
dirty: RED.nodes.dirty(),
group: ev.group,
nodes: ev.nodes,
reparent: ev.reparent
}
if (ev.nodes) {
RED.group.removeFromGroup(ev.group,ev.nodes,(ev.hasOwnProperty('reparent')&&ev.hasOwnProperty('reparent')!==undefined)?ev.reparent:true);
}
} else if (ev.t == "removeFromGroup") {
inverseEv = {
t: "addToGroup",
dirty: RED.nodes.dirty(),
group: ev.group,
nodes: ev.nodes,
reparent: ev.reparent
}
if (ev.nodes) {
RED.group.addToGroup(ev.group,ev.nodes);
}
}
if(ev.callback && typeof ev.callback === 'function') {
inverseEv.callback = ev.callback;
ev.callback(ev);
}
Object.keys(modifiedTabs).forEach(function(id) {
@@ -593,8 +460,9 @@ RED.history = (function() {
});
RED.nodes.dirty(ev.dirty);
RED.view.updateActive();
RED.view.select(null);
RED.view.redraw(true);
RED.palette.refresh();
RED.workspaces.refresh();
RED.sidebar.config.refresh();
RED.subflow.refresh();
@@ -614,9 +482,6 @@ RED.history = (function() {
list: function() {
return undoHistory;
},
listRedo: function() {
return redoHistory;
},
depth: function() {
return undoHistory.length;
},

View File

@@ -10,7 +10,6 @@
"ctrl-escape": "core:cancel-edit-tray",
"ctrl-d": "core:deploy-flows",
"ctrl-g i": "core:show-info-tab",
"ctrl-g h": "core:show-help-tab",
"ctrl-g d": "core:show-debug-tab",
"ctrl-g c": "core:show-config-tab",
"ctrl-g x": "core:show-context-tab",
@@ -45,14 +44,6 @@
"ctrl-y": "core:redo",
"ctrl-a": "core:select-all-nodes",
"shift-?": "core:show-help",
"w": "core:scroll-view-up",
"d": "core:scroll-view-right",
"s": "core:scroll-view-down",
"a": "core:scroll-view-left",
"shift-w": "core:step-view-up",
"shift-d": "core:step-view-right",
"shift-s": "core:step-view-down",
"shift-a": "core:step-view-left",
"up": "core:move-selection-up",
"right": "core:move-selection-right",
"down": "core:move-selection-down",
@@ -62,10 +53,6 @@
"shift-down": "core:step-selection-down",
"shift-left": "core:step-selection-left",
"ctrl-shift-j": "core:show-previous-tab",
"ctrl-shift-k": "core:show-next-tab",
"ctrl-shift-g": "core:group-selection",
"ctrl-shift-u": "core:ungroup-selection",
"ctrl-shift-c": "core:copy-group-style",
"ctrl-shift-v": "core:paste-group-style"
"ctrl-shift-k": "core:show-next-tab"
}
}

View File

@@ -27,16 +27,13 @@ RED.nodes = (function() {
var subflows = {};
var loadedFlowVersion = null;
var groups = {};
var groupsByZ = {};
var initialLoad;
var dirty = false;
function setDirty(d) {
dirty = d;
RED.events.emit("workspace:dirty",{dirty:dirty});
RED.events.emit("nodes:change",{dirty:dirty});
}
var registry = (function() {
@@ -196,17 +193,18 @@ RED.nodes = (function() {
if (n.type.indexOf("subflow") !== 0) {
n["_"] = n._def._;
} else {
var subflowId = n.type.substring(8);
var sf = RED.nodes.subflow(subflowId);
if (sf) {
sf.instances.push(sf);
}
n["_"] = RED._;
}
if (n._def.category == "config") {
configNodes[n.id] = n;
} else {
n.ports = [];
if (n.wires && (n.wires.length > n.outputs)) { n.outputs = n.wires.length; }
if (n.outputs) {
for (var i=0;i<n.outputs;i++) {
n.ports.push(i);
}
}
n.dirty = true;
updateConfigNodeUsers(n);
if (n._def.category == "subflows" && typeof n.i === "undefined") {
@@ -227,7 +225,6 @@ RED.nodes = (function() {
}
function addLink(l) {
links.push(l);
RED.events.emit("links:add",l);
}
function getNode(id) {
@@ -260,7 +257,7 @@ RED.nodes = (function() {
delete nodeTabMap[node.z][node.id];
}
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
removedLinks.forEach(removeLink);
removedLinks.forEach(function(l) {links.splice(links.indexOf(l), 1); });
var updatedConfigNode = false;
for (var d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d)) {
@@ -283,15 +280,6 @@ RED.nodes = (function() {
}
}
}
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();
}
@@ -305,9 +293,6 @@ RED.nodes = (function() {
RED.events.emit('nodes:remove',node);
}
}
if (node && node._def.onremove) {
// Deprecated: never documented but used by some early nodes
console.log("Deprecated API warning: node type ",node.type," has an onremove function - should be oneditremove - please report");
@@ -317,10 +302,6 @@ RED.nodes = (function() {
}
function moveNodeToTab(node, z) {
if (node.type === "group") {
moveGroupToTab(node,z);
return;
}
if (nodeTabMap[node.z]) {
delete nodeTabMap[node.z][node.id];
}
@@ -329,15 +310,6 @@ RED.nodes = (function() {
}
nodeTabMap[z][node.id] = node;
node.z = z;
RED.events.emit("nodes:change",node);
}
function moveGroupToTab(group, z) {
var index = groupsByZ[group.z].indexOf(group);
groupsByZ[group.z].splice(index,1);
groupsByZ[z] = groupsByZ[z] || [];
groupsByZ[z].push(group);
group.z = z;
RED.events.emit("groups:change",group);
}
function removeLink(l) {
@@ -345,7 +317,6 @@ RED.nodes = (function() {
if (index != -1) {
links.splice(index,1);
}
RED.events.emit("links:remove",l);
}
function addWorkspace(ws,targetIndex) {
@@ -358,63 +329,38 @@ RED.nodes = (function() {
} else {
workspacesOrder.splice(targetIndex,0,ws.id);
}
RED.events.emit('flows:add',ws);
if (targetIndex !== undefined) {
RED.events.emit('flows:reorder',workspacesOrder)
}
}
function getWorkspace(id) {
return workspaces[id];
}
function removeWorkspace(id) {
var ws = workspaces[id];
delete workspaces[id];
delete nodeTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var removedNodes = [];
var removedLinks = [];
var removedGroups = [];
if (ws) {
delete workspaces[id];
delete nodeTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var i;
var node;
for (i=0;i<nodes.length;i++) {
node = nodes[i];
var n;
var node;
for (n=0;n<nodes.length;n++) {
node = nodes[n];
if (node.z == id) {
removedNodes.push(node);
}
}
for(n in configNodes) {
if (configNodes.hasOwnProperty(n)) {
node = configNodes[n];
if (node.z == id) {
removedNodes.push(node);
}
}
for(i in configNodes) {
if (configNodes.hasOwnProperty(i)) {
node = configNodes[i];
if (node.z == id) {
removedNodes.push(node);
}
}
}
for (i=0;i<removedNodes.length;i++) {
var result = removeNode(removedNodes[i].id);
removedLinks = removedLinks.concat(result.links);
}
// Must get 'removedGroups' in the right order.
// - start with the top-most groups
// - then recurse into them
removedGroups = (groupsByZ[id] || []).filter(function(g) { return !g.g; });
for (i=0;i<removedGroups.length;i++) {
removedGroups[i].nodes.forEach(function(n) {
if (n.type === "group") {
removedGroups.push(n);
}
});
}
// Now remove them in the reverse order
for (i=removedGroups.length-1; i>=0; i--) {
removeGroup(removedGroups[i]);
}
RED.events.emit('flows:remove',ws);
}
return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
for (n=0;n<removedNodes.length;n++) {
var result = removeNode(removedNodes[n].id);
removedLinks = removedLinks.concat(result.links);
}
return {nodes:removedNodes,links:removedLinks};
}
function addSubflow(sf, createNewIds) {
@@ -452,10 +398,6 @@ RED.nodes = (function() {
paletteLabel: function() { return RED.nodes.subflow(sf.id).name },
inputLabels: function(i) { return sf.inputLabels?sf.inputLabels[i]:null },
outputLabels: function(i) { return sf.outputLabels?sf.outputLabels[i]:null },
oneditprepare: function() {
RED.subflow.buildEditForm("subflow",this);
RED.subflow.buildPropertiesForm(this);
},
oneditresize: function(size) {
// var rows = $(".dialog-form>div:not(.node-input-env-container-row)");
var height = size.height;
@@ -470,20 +412,15 @@ RED.nodes = (function() {
module: "node-red"
}
});
sf.instances = [];
sf._def = RED.nodes.getType("subflow:"+sf.id);
RED.events.emit("subflows:add",sf);
}
function getSubflow(id) {
return subflows[id];
}
function removeSubflow(sf) {
if (subflows[sf.id]) {
delete subflows[sf.id];
delete nodeTabMap[sf.id];
registry.removeNodeType("subflow:"+sf.id);
RED.events.emit("subflows:remove",sf);
}
delete subflows[sf.id];
delete nodeTabMap[sf.id];
registry.removeNodeType("subflow:"+sf.id);
}
function subflowContains(sfid,nodeid) {
@@ -556,9 +493,6 @@ RED.nodes = (function() {
if (n.d === true) {
node.d = true;
}
if (n.g) {
node.g = n.g;
}
if (node.type == "unknown") {
for (var p in n._orig) {
if (n._orig.hasOwnProperty(p)) {
@@ -571,33 +505,19 @@ RED.nodes = (function() {
node[d] = n[d];
}
}
if (exportCreds) {
if(exportCreds && n.credentials) {
var credentialSet = {};
if (/^subflow:/.test(node.type) && n.credentials) {
// A subflow instance node can have arbitrary creds
for (var sfCred in n.credentials) {
if (n.credentials.hasOwnProperty(sfCred)) {
node.credentials = {};
for (var cred in n._def.credentials) {
if (n._def.credentials.hasOwnProperty(cred)) {
if (n._def.credentials[cred].type == 'password') {
if (!n.credentials._ ||
n.credentials["has_"+sfCred] != n.credentials._["has_"+sfCred] ||
(n.credentials["has_"+sfCred] && n.credentials[sfCred])) {
credentialSet[sfCred] = n.credentials[sfCred];
}
}
}
} else if (n.credentials) {
node.credentials = {};
// All other nodes have a well-defined list of possible credentials
for (var cred in n._def.credentials) {
if (n._def.credentials.hasOwnProperty(cred)) {
if (n._def.credentials[cred].type == 'password') {
if (!n.credentials._ ||
n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
(n.credentials["has_"+cred] && n.credentials[cred])) {
credentialSet[cred] = n.credentials[cred];
}
} else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) {
n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
(n.credentials["has_"+cred] && n.credentials[cred])) {
credentialSet[cred] = n.credentials[cred];
}
} else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) {
credentialSet[cred] = n.credentials[cred];
}
}
}
@@ -606,15 +526,6 @@ RED.nodes = (function() {
}
}
}
if (n.type === "group") {
node.x = n.x;
node.y = n.y;
node.w = n.w;
node.h = n.h;
// In 1.1.0, we have seen an instance of this array containing `undefined`
// Until we know how that can happen, add a filter here to remove them
node.nodes = node.nodes.filter(function(n) { return !!n }).map(function(n) { return n.id });
}
if (n._def.category != "config") {
node.x = n.x;
node.y = n.y;
@@ -657,7 +568,7 @@ RED.nodes = (function() {
return node;
}
function convertSubflow(n, exportCreds) {
function convertSubflow(n) {
var node = {};
node.id = n.id;
node.type = n.type;
@@ -667,24 +578,6 @@ RED.nodes = (function() {
node.in = [];
node.out = [];
node.env = n.env;
if (exportCreds) {
var credentialSet = {};
// A subflow node can have arbitrary creds
for (var sfCred in n.credentials) {
if (n.credentials.hasOwnProperty(sfCred)) {
if (!n.credentials._ ||
n.credentials["has_"+sfCred] != n.credentials._["has_"+sfCred] ||
(n.credentials["has_"+sfCred] && n.credentials[sfCred])) {
credentialSet[sfCred] = n.credentials[sfCred];
}
}
}
if (Object.keys(credentialSet).length > 0) {
node.credentials = credentialSet;
}
}
node.color = n.color;
n.in.forEach(function(p) {
@@ -740,18 +633,8 @@ RED.nodes = (function() {
/**
* Converts the current node selection to an exportable JSON Object
**/
function createExportableNodeSet(set, exportedIds, exportedSubflows, exportedConfigNodes) {
function createExportableNodeSet(set, exportedSubflows, exportedConfigNodes) {
var nns = [];
exportedIds = exportedIds || {};
set = set.filter(function(n) {
if (exportedIds[n.id]) {
return false;
}
exportedIds[n.id] = true;
return true;
})
exportedConfigNodes = exportedConfigNodes || {};
exportedSubflows = exportedSubflows || {};
for (var n=0;n<set.length;n++) {
@@ -767,11 +650,11 @@ RED.nodes = (function() {
subflowSet.push(n);
}
});
var exportableSubflow = createExportableNodeSet(subflowSet, exportedIds, exportedSubflows, exportedConfigNodes);
var exportableSubflow = createExportableNodeSet(subflowSet, exportedSubflows, exportedConfigNodes);
nns = exportableSubflow.concat(nns);
}
}
if (node.type !== "subflow") {
if (node.type != "subflow") {
var convertedNode = RED.nodes.convertNode(node);
for (var d in node._def.defaults) {
if (node._def.defaults[d].type && node[d] in configNodes) {
@@ -788,9 +671,6 @@ RED.nodes = (function() {
}
}
nns.push(convertedNode);
if (node.type === "group") {
nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes));
}
} else {
var convertedSubflow = convertSubflow(node);
nns.push(convertedSubflow);
@@ -813,12 +693,7 @@ RED.nodes = (function() {
}
for (i in subflows) {
if (subflows.hasOwnProperty(i)) {
nns.push(convertSubflow(subflows[i], exportCredentials));
}
}
for (i in groups) {
if (groups.hasOwnProperty(i)) {
nns.push(convertNode(groups[i]));
nns.push(convertSubflow(subflows[i]));
}
}
for (i in configNodes) {
@@ -947,7 +822,6 @@ RED.nodes = (function() {
if (n.type != "workspace" &&
n.type != "tab" &&
n.type != "subflow" &&
n.type != "group" &&
!registry.getNodeType(n.type) &&
n.type.substring(0,8) != "subflow:" &&
unknownTypes.indexOf(n.type)==-1) {
@@ -971,7 +845,7 @@ RED.nodes = (function() {
var m = /^subflow:(.+)$/.exec(newNodes[i].type);
if (m) {
var subflowId = m[1];
var parent = getSubflow(activeWorkspace);
var parent = getSubflow(newNodes[i].z || activeWorkspace);
if (parent) {
var err;
if (subflowId === parent.id) {
@@ -993,12 +867,10 @@ RED.nodes = (function() {
var workspace_map = {};
var new_subflows = [];
var subflow_map = {};
var subflow_denylist = {};
var subflow_blacklist = {};
var node_map = {};
var new_nodes = [];
var new_links = [];
var new_groups = [];
var new_group_set = new Set();
var nid;
var def;
var configNode;
@@ -1027,7 +899,7 @@ RED.nodes = (function() {
} else if (n.type === "subflow") {
var matchingSubflow = checkForMatchingSubflow(n,nodeZmap[n.id]);
if (matchingSubflow) {
subflow_denylist[n.id] = matchingSubflow;
subflow_blacklist[n.id] = matchingSubflow;
} else {
subflow_map[n.id] = n;
if (createNewIds) {
@@ -1078,7 +950,7 @@ RED.nodes = (function() {
var existingConfigNode = null;
if (createNewIds) {
if (n.z) {
if (subflow_denylist[n.z]) {
if (subflow_blacklist[n.z]) {
continue;
} else if (subflow_map[n.z]) {
n.z = subflow_map[n.z].id;
@@ -1149,6 +1021,7 @@ RED.nodes = (function() {
}
node_map[n.id] = configNode;
new_nodes.push(configNode);
RED.nodes.add(configNode);
}
}
}
@@ -1165,27 +1038,22 @@ RED.nodes = (function() {
y:parseFloat(n.y || 0),
z:n.z,
type:0,
wires:n.wires||[],
inputLabels: n.inputLabels,
outputLabels: n.outputLabels,
icon: n.icon,
info: n.info,
changed:false,
_config:{}
}
if (n.type !== "group") {
node.wires = n.wires||[];
node.inputLabels = n.inputLabels;
node.outputLabels = n.outputLabels;
node.icon = n.icon;
}
};
if (n.hasOwnProperty('l')) {
node.l = n.l;
}
if (n.hasOwnProperty('d')) {
node.d = n.d;
}
if (n.hasOwnProperty('g')) {
node.g = n.g;
}
if (createNewIds) {
if (subflow_denylist[n.z]) {
if (subflow_blacklist[n.z]) {
continue;
} else if (subflow_map[node.z]) {
node.z = subflow_map[node.z].id;
@@ -1220,19 +1088,9 @@ RED.nodes = (function() {
}
node.type = n.type;
node._def = def;
if (node.type === "group") {
node._def = RED.group.def;
for (d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
node[d] = n[d];
node._config[d] = JSON.stringify(n[d]);
}
}
node._config.x = node.x;
node._config.y = node.y;
} else if (n.type.substring(0,7) === "subflow") {
if (n.type.substring(0,7) === "subflow") {
var parentId = n.type.split(":")[1];
var subflow = subflow_denylist[parentId]||subflow_map[parentId]||getSubflow(parentId);
var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId);
if (createNewIds) {
parentId = subflow.id;
node.type = "subflow:"+parentId;
@@ -1251,7 +1109,7 @@ RED.nodes = (function() {
defaults: {},
label: "unknown: "+n.type,
labelStyle: "red-ui-flow-node-label-italic",
outputs: n.outputs|| (n.wires && n.wires.length) || 0,
outputs: n.outputs||n.wires.length,
set: registry.getNodeSet("node-red/unknown")
}
} else {
@@ -1320,14 +1178,13 @@ RED.nodes = (function() {
}
}
}
addNode(node);
RED.editor.validateNode(node);
node_map[n.id] = node;
// If an 'unknown' config node, it will not have been caught by the
// proper config node handling, so needs adding to new_nodes here
if (node.type === "unknown" || node._def.category !== "config") {
new_nodes.push(node);
} else if (node.type === "group") {
new_groups.push(node);
new_group_set.add(node.id);
}
}
}
@@ -1362,17 +1219,12 @@ RED.nodes = (function() {
}
delete n.wires;
}
if (n.g && node_map[n.g]) {
n.g = node_map[n.g].id;
} else {
delete n.g
}
for (var d3 in n._def.defaults) {
if (n._def.defaults.hasOwnProperty(d3)) {
if (n._def.defaults[d3].type && node_map[n[d3]]) {
configNode = node_map[n[d3]];
n[d3] = configNode.id;
if (configNode.users.indexOf(n) === -1) {
n[d3] = node_map[n[d3]].id;
configNode = RED.nodes.node(n[d3]);
if (configNode && configNode.users.indexOf(n) === -1) {
configNode.users.push(n);
}
} else if (nodeTypeArrayReferences.hasOwnProperty(n.type) && nodeTypeArrayReferences[n.type] === d3 && n[d3] !== undefined && n[d3] !== null) {
@@ -1393,6 +1245,10 @@ RED.nodes = (function() {
return (otherNode && otherNode.z === activeWorkspace)
});
}
// With all properties now remapped to point at valid nodes,
// we can validate the node
RED.editor.validateNode(n);
}
for (i=0;i<new_subflows.length;i++) {
n = new_subflows[i];
@@ -1431,68 +1287,9 @@ RED.nodes = (function() {
delete n.status.wires;
}
}
// Order the groups to ensure they are outer-most to inner-most
var groupDepthMap = {};
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
if (n.g && !new_group_set.has(n.g)) {
delete n.g;
}
n.nodes = n.nodes.map(function(id) {
return node_map[id];
})
// Just in case the group references a node that doesn't exist for some reason
n.nodes = n.nodes.filter(function(v) {
if (v) {
// Repair any nodes that have forgotten they are in this group
if (v.g !== n.id) {
v.g = n.id;
}
}
return !!v
});
if (!n.g) {
groupDepthMap[n.id] = 0;
}
}
var changedDepth;
do {
changedDepth = false;
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
if (n.g) {
if (groupDepthMap[n.id] !== groupDepthMap[n.g] + 1) {
groupDepthMap[n.id] = groupDepthMap[n.g] + 1;
changedDepth = true;
}
}
}
} while(changedDepth);
new_groups.sort(function(A,B) {
return groupDepthMap[A.id] - groupDepthMap[B.id];
});
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
addGroup(n);
}
// Now the nodes have been fully updated, add them.
for (i=0;i<new_nodes.length;i++) {
var node = new_nodes[i];
addNode(node);
}
// Finally validate them all.
// This has to be done after everything is added so that any checks for
// dependent config nodes will pass
for (i=0;i<new_nodes.length;i++) {
var node = new_nodes[i];
RED.editor.validateNode(node);
}
RED.workspaces.refresh();
return [new_nodes,new_links,new_groups,new_workspaces,new_subflows,missingWorkspace];
return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace];
}
// TODO: supports filter.z|type
@@ -1583,9 +1380,6 @@ RED.nodes = (function() {
nodeTabMap = {};
configNodes = {};
workspacesOrder = [];
groups = {};
groupsByZ = {};
var subflowIds = Object.keys(subflows);
subflowIds.forEach(function(id) {
RED.subflow.removeSubflow(id)
@@ -1597,14 +1391,12 @@ RED.nodes = (function() {
defaultWorkspace = null;
initialLoad = null;
RED.nodes.dirty(false);
RED.view.redraw(true, true);
RED.view.redraw(true);
RED.palette.refresh();
RED.workspaces.refresh();
RED.sidebar.config.refresh();
RED.sidebar.info.refresh();
RED.events.emit("workspace:clear");
// var node_defs = {};
// var nodes = [];
// var configNodes = {};
@@ -1616,31 +1408,6 @@ RED.nodes = (function() {
// var loadedFlowVersion = null;
}
function addGroup(group) {
groupsByZ[group.z] = groupsByZ[group.z] || [];
groupsByZ[group.z].push(group);
groups[group.id] = group;
RED.events.emit("groups:add",group);
}
function removeGroup(group) {
var i = groupsByZ[group.z].indexOf(group);
groupsByZ[group.z].splice(i,1);
if (groupsByZ[group.z].length === 0) {
delete groupsByZ[group.z];
}
if (group.g) {
if (groups[group.g]) {
var index = groups[group.g].nodes.indexOf(group);
groups[group.g].nodes.splice(index,1);
}
}
RED.group.markDirty(group);
delete groups[group.id];
RED.events.emit("groups:remove",group);
}
return {
init: function() {
RED.events.on("registry:node-type-added",function(type) {
@@ -1667,12 +1434,8 @@ RED.nodes = (function() {
delete configNodes[n.id];
} else {
nodes.splice(nodes.indexOf(n),1);
if (nodeTabMap[n.z]) {
delete nodeTabMap[n.z][n.id];
}
}
reimportList.push(convertNode(n));
RED.events.emit('nodes:remove',n);
});
// Remove any links between nodes that are going to be reimported.
@@ -1685,9 +1448,8 @@ RED.nodes = (function() {
});
removeLinks.forEach(removeLink);
// Force the redraw to be synchronous so the view updates
// *now* and removes the unknown node
RED.view.redraw(true, true);
RED.view.redraw(true);
var result = importNodes(reimportList,false);
var newNodeMap = {};
result[0].forEach(function(n) {
@@ -1741,11 +1503,6 @@ RED.nodes = (function() {
subflow: getSubflow,
subflowContains: subflowContains,
addGroup: addGroup,
removeGroup: removeGroup,
group: function(id) { return groups[id] },
groups: function(z) { return groupsByZ[z]||[] },
eachNode: function(cb) {
for (var n=0;n<nodes.length;n++) {
if (cb(nodes[n]) === false) {

View File

@@ -1,57 +0,0 @@
(function() {
var isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
if (isIE11) {
// IE11 DOMTokenList.toggle does not support the two-argument variety
window.DOMTokenList.prototype.toggle = function(cl,bo) {
if (arguments.length === 1) {
bo = !this.contains(cl);
}
this[!!bo?"add":"remove"](cl);
}
// IE11 does not provide classList on SVGElements
if (! ("classList" in SVGElement.prototype)) {
Object.defineProperty(SVGElement.prototype, 'classList', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'classList'));
}
// IE11 does not provide children on SVGElements
if (! ("children" in SVGElement.prototype)) {
Object.defineProperty(SVGElement.prototype, 'children', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'children'));
}
Array.from = function() {
if (arguments.length > 1) {
throw new Error("Node-RED's IE11 Array.from polyfill doesn't support multiple arguments");
}
var arrayLike = arguments[0]
var result = [];
if (arrayLike.forEach) {
arrayLike.forEach(function(i) {
result.push(i);
})
} else {
for (var i=0;i<arrayLike.length;i++) {
result.push(arrayList[i]);
}
}
return result;
}
if (new Set([0]).size === 0) {
// IE does not support passing an iterable to Set constructor
var _Set = Set;
/*global Set:true */
Set = function Set(iterable) {
var set = new _Set();
if (iterable) {
iterable.forEach(set.add, set);
}
return set;
};
Set.prototype = _Set.prototype;
Set.prototype.constructor = Set;
}
}
})();

View File

@@ -75,7 +75,6 @@ var RED = (function() {
}
function loadNodeList() {
loader.reportProgress(RED._("event.loadPalette"), 20)
$.ajax({
headers: {
"Accept":"application/json"
@@ -84,7 +83,6 @@ var RED = (function() {
url: 'nodes',
success: function(data) {
RED.nodes.setNodeList(data);
loader.reportProgress(RED._("event.loadNodeCatalogs"), 25)
RED.i18n.loadNodeCatalogs(function() {
loadIconList(loadNodes);
});
@@ -109,7 +107,6 @@ var RED = (function() {
}
function loadNodes() {
loader.reportProgress(RED._("event.loadNodes",{count:""}), 30)
var lang = localStorage.getItem("editor-language")||i18n.detectLanguage();
$.ajax({
@@ -121,19 +118,15 @@ var RED = (function() {
url: 'nodes',
success: function(data) {
var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/);
var totalCount = configs.length;
var stepConfig = function() {
loader.reportProgress(RED._("event.loadNodes",{count:(totalCount-configs.length)+"/"+totalCount}), 30 + ((totalCount-configs.length)/totalCount)*40 )
if (configs.length === 0) {
$("#red-ui-editor").i18n();
$("#red-ui-palette > .red-ui-palette-spinner").hide();
$(".red-ui-palette-scroll").removeClass("hide");
$("#red-ui-palette-search").removeClass("hide");
if (RED.settings.theme("projects.enabled",false)) {
RED.projects.refresh(function(activeProject) {
loadFlows(function() {
loadFlows(function() {
if (RED.settings.theme("projects.enabled",false)) {
RED.projects.refresh(function(activeProject) {
RED.sidebar.info.refresh()
if (!activeProject) {
// Projects enabled but no active project
@@ -147,14 +140,12 @@ var RED = (function() {
}
completeLoad();
});
});
} else {
loadFlows(function() {
} else {
// Projects disabled by the user
RED.sidebar.info.refresh()
completeLoad();
});
}
}
});
} else {
var config = configs.shift();
appendNodeConfig(config,stepConfig);
@@ -166,7 +157,6 @@ var RED = (function() {
}
function loadFlows(done) {
loader.reportProgress(RED._("event.loadFlows"),80 )
$.ajax({
headers: {
"Accept":"application/json",
@@ -177,7 +167,6 @@ var RED = (function() {
if (nodes) {
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);
@@ -204,7 +193,6 @@ var RED = (function() {
return;
}
if (notificationId === "project-update") {
loader.start("Loading project",0)
RED.nodes.clear();
RED.history.clear();
RED.view.redraw(true);
@@ -220,7 +208,6 @@ var RED = (function() {
"revert": RED._("notification.project.revert", {project: msg.project}),
"merge-complete": RED._("notification.project.merge-complete")
}[msg.action];
loader.end()
RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh()
});
@@ -366,13 +353,13 @@ var RED = (function() {
var parts = topic.split("/");
var node = RED.nodes.node(parts[1]);
if (node) {
if (msg.hasOwnProperty("text") && msg.text !== null && /^[a-zA-Z]/.test(msg.text)) {
if (msg.hasOwnProperty("text") && /^[a-zA-Z]/.test(msg.text)) {
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
}
node.status = msg;
node.dirtyStatus = true;
node.dirty = true;
RED.view.redrawStatus(node);
RED.view.redraw();
}
});
RED.comms.subscribe("notification/node/#",function(topic,msg) {
@@ -431,17 +418,13 @@ var RED = (function() {
RED.notify(RED._("palette.event.nodeUpgraded", {module:msg.module,version:msg.version}),"success");
RED.nodes.registry.setModulePendingUpdated(msg.module,msg.version);
}
// Refresh flow library to ensure any examples are updated
RED.library.loadFlowLibrary();
});
RED.comms.subscribe("event-log/#", function(topic,payload) {
var id = topic.substring(9);
RED.eventLog.log(id,payload);
});
$(".red-ui-header-toolbar").show();
setTimeout(function() {
loader.end();
},100);
}
function showAbout() {
@@ -450,7 +433,8 @@ var RED = (function() {
'<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>';
RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data));
RED.sidebar.info.set(aboutHeader+marked(data));
RED.sidebar.info.show();
});
}
@@ -490,14 +474,6 @@ var RED = (function() {
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:"core:create-subflow"},
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:"core:convert-to-subflow"},
]});
menuOptions.push({id:"menu-item-group",label:RED._("menu.label.groups"), options: [
{id:"menu-item-group-group",label:RED._("menu.label.groupSelection"),disabled:true,onselect:"core:group-selection"},
{id:"menu-item-group-ungroup",label:RED._("menu.label.ungroupSelection"),disabled:true,onselect:"core:ungroup-selection"},
null,
{id:"menu-item-group-merge",label:RED._("menu.label.groupMergeSelection"),disabled:true,onselect:"core:merge-selection-to-group"},
{id:"menu-item-group-remove",label:RED._("menu.label.groupRemoveSelection"),disabled:true,onselect:"core:remove-selection-from-group"}
]});
menuOptions.push(null);
if (RED.settings.theme('palette.editable') !== false) {
menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"});
@@ -523,6 +499,7 @@ var RED = (function() {
}
function loadEditor() {
RED.workspaces.init();
RED.statusBar.init();
RED.view.init();
@@ -549,7 +526,6 @@ var RED = (function() {
}
RED.subflow.init();
RED.group.init();
RED.clipboard.init();
RED.search.init();
RED.actionList.init();
@@ -565,14 +541,13 @@ var RED = (function() {
RED.comms.connect();
$("#red-ui-main-container").show();
$(".red-ui-header-toolbar").show();
RED.actions.add("core:show-about", showAbout);
loadNodeList();
}
function buildEditor(options) {
var header = $('<div id="red-ui-header"></div>').appendTo(options.target);
var logo = $('<span class="red-ui-header-logo"></span>').appendTo(header);
@@ -587,10 +562,6 @@ var RED = (function() {
'</div>').appendTo(options.target);
$('<div id="red-ui-editor-node-configs"></div>').appendTo(options.target);
$('<div id="red-ui-full-shade" class="hide"></div>').appendTo(options.target);
loader.init().appendTo("#red-ui-main-container");
loader.start("...",0);
$.getJSON(options.apiRootUrl+"theme", function(theme) {
if (theme.header) {
if (theme.header.url) {
@@ -623,39 +594,12 @@ var RED = (function() {
options.target.addClass("red-ui-editor");
buildEditor(options);
RED.i18n.init(options, function() {
RED.settings.init(options, loadEditor);
})
}
var loader = {
init: function() {
var wrapper = $('<div id="red-ui-loading-progress"></div>').hide();
var container = $('<div>').appendTo(wrapper);
var label = $('<div>',{class:"red-ui-loading-bar-label"}).appendTo(container);
var bar = $('<div>',{class:"red-ui-loading-bar"}).appendTo(container);
var fill =$('<span>').appendTo(bar);
return wrapper;
},
start: function(text, prcnt) {
if (text) {
loader.reportProgress(text,prcnt)
}
$("#red-ui-loading-progress").show();
},
reportProgress: function(text, prcnt) {
$(".red-ui-loading-bar-label").text(text);
$(".red-ui-loading-bar span").width(prcnt+"%")
},
end: function() {
$("#red-ui-loading-progress").hide();
loader.reportProgress("",0);
}
}
return {
init: init,
loader: loader
init: init
}
})();

View File

@@ -56,9 +56,8 @@ RED.settings = (function () {
if (key === "auth-tokens") {
return JSON.parse(localStorage.getItem(key));
} else {
var v;
try {
v = RED.utils.getMessageProperty(userSettings,key);
var v = RED.utils.getMessageProperty(userSettings,key);
if (v === undefined) {
v = defaultIfUndefined;
}

View File

@@ -159,11 +159,7 @@ RED.clipboard = (function() {
}
}
],
open: function( event, ui ) {
RED.keyboard.disable();
},
close: function(e) {
RED.keyboard.enable();
if (popover) {
popover.close(true);
currentPopoverError = null;
@@ -188,7 +184,7 @@ RED.clipboard = (function() {
'</div>'+
'<div id="red-ui-clipboard-dialog-export-tabs-content" class="red-ui-clipboard-dialog-tabs-content">'+
'<div id="red-ui-clipboard-dialog-export-tab-clipboard" class="red-ui-clipboard-dialog-tab-clipboard">'+
'<div class="form-row" style="height:calc(100% - 30px)">'+
'<div class="form-row">'+
'<textarea readonly id="red-ui-clipboard-dialog-export-text"></textarea>'+
'</div>'+
'<div class="form-row" style="text-align: right;">'+
@@ -220,7 +216,7 @@ RED.clipboard = (function() {
' <a class="red-ui-button" id="red-ui-clipboard-dialog-import-file-upload-btn"><i class="fa fa-upload"></i> <span data-i18n="clipboard.selectFile"></span></a>'+
'<input type="file" id="red-ui-clipboard-dialog-import-file-upload" accept=".json" style="display:none">'+
'</div>'+
'<div class="form-row" style="height:calc(100% - 47px)">'+
'<div class="form-row">'+
'<textarea id="red-ui-clipboard-dialog-import-text"></textarea>'+
'</div>'+
'</div>'+
@@ -478,12 +474,6 @@ RED.clipboard = (function() {
},100)
}
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 600) {
dialogHeight = 400 - (600 - winHeight);
}
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
popover = RED.popover.create({
@@ -593,7 +583,6 @@ RED.clipboard = (function() {
nodes = [];
selection.forEach(function(n) {
nodes.push(n);
nodes = nodes.concat(RED.nodes.groups(n.id));
nodes = nodes.concat(RED.nodes.filterNodes({z:n.id}));
});
} else {
@@ -603,8 +592,7 @@ RED.clipboard = (function() {
nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'}));
} else if (type === 'red-ui-clipboard-dialog-export-rng-flow') {
var activeWorkspace = RED.workspaces.active();
nodes = RED.nodes.groups(activeWorkspace);
nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace}));
nodes = RED.nodes.filterNodes({z:activeWorkspace});
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
nodes.unshift(parentNode);
nodes = RED.nodes.createExportableNodeSet(nodes);
@@ -649,14 +637,6 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
}
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode);
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 600) {
dialogHeight = 400 - (600 - winHeight);
}
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
$("#red-ui-clipboard-dialog-export-text").trigger("focus");
@@ -758,8 +738,6 @@ RED.clipboard = (function() {
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-examples-import-dialog",function() { importNodes('examples') });
RED.events.on("editor:open",function() { disabled = true; });
RED.events.on("editor:close",function() { disabled = false; });
RED.events.on("search:open",function() { disabled = true; });

View File

@@ -1,209 +0,0 @@
RED.colorPicker = (function() {
function create(options) {
var color = options.value;
var id = options.id;
var colorPalette = options.palette || [];
var width = options.cellWidth || 30;
var height = options.cellHeight || 30;
var margin = options.cellMargin || 2;
var perRow = options.cellPerRow || 6;
var container = $("<div>",{style:"display:inline-block"});
var colorHiddenInput = $("<input/>", { id: id, type: "hidden", value: color }).appendTo(container);
var opacityHiddenInput = $("<input/>", { id: id+"-opacity", type: "hidden", value: options.hasOwnProperty('opacity')?options.opacity:"1" }).appendTo(container);
var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container);
$('<i class="fa fa-caret-down"></i>').appendTo(colorButton);
var colorDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton);
$('<div>',{class:"red-ui-color-picker-cell-none"}).appendTo(colorDispContainer);
var colorDisp = $('<div>',{class:"red-ui-color-picker-swatch"}).appendTo(colorDispContainer);
var refreshDisplay = function(color) {
if (color === "none") {
colorDisp.addClass('red-ui-color-picker-cell-none').css({
"background-color": "",
opacity: 1
});
colorDispContainer.css({
"border-color":""
})
} else {
var opacity = parseFloat(opacityHiddenInput.val())
colorDisp.removeClass('red-ui-color-picker-cell-none').css({
"background-color": color,
"opacity": opacity
});
var border = RED.utils.getDarkerColor(color);
if (border[0] === '#') {
border += Math.round(255*Math.floor(opacity*100)/100).toString(16);
} else {
border = "";
}
colorDispContainer.css({
"border-color": border
})
}
if (options.hasOwnProperty('opacity')) {
$(".red-ui-color-picker-opacity-slider-overlay").css({
"background-image": "linear-gradient(90deg, transparent 0%, "+color+" 100%)"
})
}
}
colorButton.on("click", function (e) {
var numColors = colorPalette.length;
var picker = $("<div/>", {
class: "red-ui-color-picker"
}).css({
width: ((width+margin+margin)*perRow)+"px",
height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px"
});
var count = 0;
var row = null;
row = $("<div/>").appendTo(picker);
var colorInput = $('<input>',{
type:"text",
value:colorHiddenInput.val()
}).appendTo(row);
var focusTarget = colorInput;
colorInput.on("change", function (e) {
var color = colorInput.val();
colorHiddenInput.val(color).trigger('change');
refreshDisplay(color);
});
// if (options.hasOwnProperty('opacity')) {
// var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider"
// }
if (options.none) {
row = $("<div/>").appendTo(picker);
var button = $("<button/>", {
class:"red-ui-color-picker-cell red-ui-color-picker-cell-none"
}).css({
width: width+"px",
height: height+"px",
margin: margin+"px"
}).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
colorInput.val("none");
colorInput.trigger("change");
});
}
colorPalette.forEach(function (col) {
if ((count % perRow) == 0) {
row = $("<div/>").appendTo(picker);
}
var button = $("<button/>", {
class:"red-ui-color-picker-cell"
}).css({
width: width+"px",
height: height+"px",
margin: margin+"px",
backgroundColor: col,
"border-color": RED.utils.getDarkerColor(col)
}).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
// colorPanel.hide();
colorInput.val(col);
colorInput.trigger("change");
});
count++;
});
if (options.none || options.hasOwnProperty('opacity')) {
row = $("<div/>").appendTo(picker);
// if (options.none) {
// var button = $("<button/>", {
// class:"red-ui-color-picker-cell red-ui-color-picker-cell-none"
// }).css({
// width: width+"px",
// height: height+"px",
// margin: margin+"px"
// }).appendTo(row);
// button.on("click", function (e) {
// e.preventDefault();
// colorPanel.hide();
// selector.val("none");
// selector.trigger("change");
// });
// }
if (options.hasOwnProperty('opacity')) {
var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider"}).appendTo(row);
sliderContainer.on("mousedown", function(evt) {
if (evt.target === sliderHandle[0]) {
return;
}
var v = evt.offsetX/sliderContainer.width();
sliderHandle.css({
left: ( v*(sliderContainer.width() - sliderHandle.outerWidth()))+"px"
});
v = Math.floor(100*v)
opacityHiddenInput.val(v/100)
opacityLabel.text(v+"%");
refreshDisplay(colorHiddenInput.val());
})
$("<div>",{class:"red-ui-color-picker-opacity-slider-overlay"}).appendTo(sliderContainer);
var sliderHandle = $("<div>",{class:"red-ui-color-picker-opacity-slider-handle red-ui-button red-ui-button-small"}).appendTo(sliderContainer).draggable({
containment: "parent",
axis: "x",
drag: function( event, ui ) {
var v = Math.max(0,ui.position.left/($(this).parent().width()-$(this).outerWidth()));
// Odd bug that if it is loaded with a non-0 value, the first time
// it is dragged it ranges -1 to 99. But every other time, its 0 to 100.
// The Math.max above makes the -1 disappear. The follow hack ensures
// it always maxes out at a 100, at the cost of not allowing 99% exactly.
v = Math.floor(100*v)
if ( v === 99 ) {
v = 100;
}
// console.log("uip",ui.position.left);
opacityHiddenInput.val(v/100)
opacityLabel.text(v+"%");
refreshDisplay(colorHiddenInput.val());
}
});
var opacityLabel = $('<small></small>').appendTo(row);
setTimeout(function() {
sliderHandle.css({
left: (parseFloat(opacityHiddenInput.val())*(sliderContainer.width() - sliderHandle.outerWidth()))+"px"
})
opacityLabel.text(Math.floor(opacityHiddenInput.val()*100)+"%");
},50);
}
}
var colorPanel = RED.popover.panel(picker);
setTimeout(function() {
refreshDisplay(colorHiddenInput.val())
},50);
colorPanel.show({
target: colorButton,
onclose: function() {
colorButton.focus();
}
})
if (focusTarget) {
focusTarget.focus();
}
});
setTimeout(function() {
refreshDisplay(colorHiddenInput.val())
},50);
return container;
}
return {
create: create
}
})();

View File

@@ -33,7 +33,7 @@
* methods:
* - addItem(itemData)
* - insertItemAt : function(data,index) - add an item at the specified index
* - removeItem(itemData, detach) - remove the item. Optionally detach to preserve any event handlers on the item's label
* - removeItem(itemData)
* - getItemAt(index)
* - indexOf(itemData)
* - width(width)
@@ -183,7 +183,7 @@
if (this.options.resizeItem) {
var that = this;
this.element.children().each(function(i) {
that.options.resizeItem($(this).children(".red-ui-editableList-item-content"),i);
that.options.resizeItem($(this).find(".red-ui-editableList-item-content"),i);
});
}
},
@@ -223,7 +223,7 @@
var items = this.element.children();
var that = this;
items.sort(function(A,B) {
return that.activeSort($(A).children(".red-ui-editableList-item-content").data('data'),$(B).children(".red-ui-editableList-item-content").data('data'));
return that.activeSort($(A).find(".red-ui-editableList-item-content").data('data'),$(B).find(".red-ui-editableList-item-content").data('data'));
});
$.each(items,function(idx,li) {
that.element.append(li);
@@ -259,28 +259,6 @@
var that = this;
data = data || {};
var li = $('<li>');
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
row.data('data',data);
if (this.options.sortable === true) {
$('<i class="red-ui-editableList-item-handle fa fa-bars"></i>').appendTo(li);
li.addClass("red-ui-editableList-item-sortable");
}
if (this.options.removable) {
var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(li);
$('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
li.addClass("red-ui-editableList-item-removable");
deleteButton.on("click", function(evt) {
evt.preventDefault();
var data = row.data('data');
li.addClass("red-ui-editableList-item-deleting")
li.fadeOut(300, function() {
$(this).remove();
if (that.options.removeItem) {
that.options.removeItem(data);
}
});
});
}
var added = false;
if (this.activeSort) {
var items = this.items();
@@ -303,9 +281,31 @@
li.insertBefore(this.element.children().eq(index));
}
}
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
row.data('data',data);
if (this.options.sortable === true) {
$('<i class="red-ui-editableList-item-handle fa fa-bars"></i>').appendTo(li);
li.addClass("red-ui-editableList-item-sortable");
}
if (this.options.removable) {
var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(li);
$('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
li.addClass("red-ui-editableList-item-removable");
deleteButton.on("click", function(evt) {
evt.preventDefault();
var data = row.data('data');
li.addClass("red-ui-editableList-item-deleting")
li.fadeOut(300, function() {
$(this).remove();
if (that.options.removeItem) {
that.options.removeItem(data);
}
});
});
}
if (this.options.addItem) {
var index = that.element.children().length-1;
// setTimeout(function() {
setTimeout(function() {
that.options.addItem(row,index,data);
if (that.activeFilter) {
try {
@@ -321,7 +321,7 @@
that.uiContainer.scrollTop(that.element.height());
},0);
}
// },0);
},0);
}
},
addItem: function(data) {
@@ -332,21 +332,17 @@
this.addItem(items[i]);
}
},
removeItem: function(data,detach) {
removeItem: function(data) {
var items = this.element.children().filter(function(f) {
return data === $(this).children(".red-ui-editableList-item-content").data('data');
return data === $(this).find(".red-ui-editableList-item-content").data('data');
});
if (detach) {
items.detach();
} else {
items.remove();
}
items.remove();
if (this.options.removeItem) {
this.options.removeItem(data);
}
},
items: function() {
return this.element.children().map(function(i) { return $(this).children(".red-ui-editableList-item-content"); });
return this.element.children().map(function(i) { return $(this).find(".red-ui-editableList-item-content"); });
},
empty: function() {
this.element.empty();
@@ -369,14 +365,14 @@
},
show: function(item) {
var items = this.element.children().filter(function(f) {
return item === $(this).children(".red-ui-editableList-item-content").data('data');
return item === $(this).find(".red-ui-editableList-item-content").data('data');
});
if (items.length > 0) {
this.uiContainer.scrollTop(this.uiContainer.scrollTop()+items.position().top)
}
},
getItem: function(li) {
var el = li.children(".red-ui-editableList-item-content");
var el = li.find(".red-ui-editableList-item-content");
if (el.length) {
return el.data('data');
} else {

View File

@@ -158,7 +158,7 @@ RED.menu = (function() {
activeMenu = null;
topMenu.hide();
});
$(".red-ui-menu.red-ui-menu-dropdown").hide();
$(".red-ui-menu").hide();
topMenu.show();
}
})

View File

@@ -29,10 +29,6 @@ RED.panels = (function() {
if (!vertical) {
container.addClass("red-ui-panels-horizontal");
}
$(children[0]).addClass("red-ui-panel");
$(children[1]).addClass("red-ui-panel");
var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
var startPosition;
var panelSizes = [];
@@ -56,11 +52,11 @@ RED.panels = (function() {
var newSizes = [panelSizes[0]+delta,panelSizes[1]-delta];
if (vertical) {
$(children[0]).height(newSizes[0]);
// $(children[1]).height(newSizes[1]);
$(children[1]).height(newSizes[1]);
ui.position.top -= delta;
} else {
$(children[0]).width(newSizes[0]);
// $(children[1]).width(newSizes[1]);
$(children[1]).width(newSizes[1]);
ui.position.left -= delta;
}
if (options.resize) {
@@ -75,9 +71,6 @@ RED.panels = (function() {
var panel = {
ratio: function(ratio) {
if (ratio === undefined) {
return panelRatio;
}
panelRatio = ratio;
modifiedSizes = true;
if (ratio === 0 || ratio === 1) {
@@ -106,10 +99,10 @@ RED.panels = (function() {
panelSizes = [topPanelSize,bottomPanelSize];
if (vertical) {
$(children[0]).outerHeight(panelSizes[0]);
// $(children[1]).outerHeight(panelSizes[1]);
$(children[1]).outerHeight(panelSizes[1]);
} else {
$(children[0]).outerWidth(panelSizes[0]);
// $(children[1]).outerWidth(panelSizes[1]);
$(children[1]).outerWidth(panelSizes[1]);
}
}
if (options.resize) {

View File

@@ -136,23 +136,6 @@ RED.popover = (function() {
closePopup(true);
});
}
if (trigger === 'hover' && options.interactive) {
div.on('mouseenter', function(e) {
clearTimeout(timer);
active = true;
})
div.on('mouseleave', function(e) {
if (timer) {
clearTimeout(timer);
}
if (active) {
timer = setTimeout(function() {
active = false;
closePopup();
},delay.hide);
}
})
}
if (instant) {
div.show();
} else {
@@ -180,10 +163,8 @@ RED.popover = (function() {
if (trigger === 'hover') {
target.on('mouseenter',function(e) {
clearTimeout(timer);
if (!active) {
active = true;
timer = setTimeout(openPopup,delay.show);
}
active = true;
timer = setTimeout(openPopup,delay.show);
});
target.on('mouseleave disabled', function(e) {
if (timer) {
@@ -278,85 +259,6 @@ RED.popover = (function() {
delay: { show: 750, hide: 50 }
});
},
menu: function(options) {
var list = $('<ul class="red-ui-menu"></ul>');
if (options.style === 'compact') {
list.addClass("red-ui-menu-compact");
}
var menuOptions = options.options || [];
var first;
menuOptions.forEach(function(opt) {
var item = $('<li>').appendTo(list);
var link = $('<a href="#"></a>').text(opt.label).appendTo(item);
link.on("click", function(evt) {
evt.preventDefault();
if (opt.onselect) {
opt.onselect();
}
menu.hide();
})
if (!first) { first = link}
})
var container = RED.popover.panel(list);
var menu = {
show: function(opts) {
$(document).on("keydown.red-ui-menu", function(evt) {
var currentItem = list.find(":focus").parent();
if (evt.keyCode === 40) {
evt.preventDefault();
// DOWN
if (currentItem.length > 0) {
if (currentItem.index() === menuOptions.length-1) {
console.log("WARP TO TOP")
// Wrap to top of list
list.children().first().children().first().focus();
} else {
console.log("GO DOWN ONE")
currentItem.next().children().first().focus();
}
} else {
list.children().first().children().first().focus();
}
} else if (evt.keyCode === 38) {
evt.preventDefault();
// UP
if (currentItem.length > 0) {
if (currentItem.index() === 0) {
console.log("WARP TO BOTTOM")
// Wrap to bottom of list
list.children().last().children().first().focus();
} else {
console.log("GO UP ONE")
currentItem.prev().children().first().focus();
}
} else {
list.children().last().children().first().focus();
}
} else if (evt.keyCode === 27) {
// ESCAPE
evt.preventDefault();
menu.hide(true);
}
evt.stopPropagation();
})
opts.onclose = function() {
$(document).off("keydown.red-ui-menu");
if (options.onclose) {
options.onclose(true);
}
}
container.show(opts);
},
hide: function(cancelled) {
$(document).off("keydown.red-ui-menu");
container.hide(options.disposeOnClose);
if (options.onclose) {
options.onclose(cancelled);
}
}
}
return menu;
},
panel: function(content) {
var panel = $('<div class="red-ui-editor-dialog red-ui-popover-panel"></div>');
panel.css({ display: "none" });
@@ -364,22 +266,18 @@ RED.popover = (function() {
content.appendTo(panel);
var closeCallback;
function hide(dispose) {
function hide() {
$(document).off("mousedown.red-ui-popover-panel-close");
$(document).off("keydown.red-ui-popover-panel-close");
panel.hide();
panel.css({
height: "auto"
});
if (dispose !== false) {
panel.remove();
}
panel.remove();
}
function show(options) {
var closeCallback = options.onclose;
var target = options.target;
var align = options.align || "right";
var offset = options.offset || [0,0];
var align = options.align || "left";
var pos = target.offset();
var targetWidth = target.width();
@@ -387,7 +285,7 @@ RED.popover = (function() {
var panelHeight = panel.height();
var panelWidth = panel.width();
var top = (targetHeight+pos.top) + offset[1];
var top = (targetHeight+pos.top);
if (top+panelHeight > $(window).height()) {
top -= (top+panelHeight)-$(window).height() + 5;
}
@@ -395,35 +293,25 @@ RED.popover = (function() {
panelHeight.height(panelHeight+top)
top = 0;
}
if (align === "right") {
if (align === "left") {
panel.css({
top: top+"px",
left: (pos.left+offset[0])+"px",
left: (pos.left)+"px",
});
} else if (align === "left") {
} else if(align === "right") {
panel.css({
top: top+"px",
left: (pos.left-panelWidth+offset[0])+"px",
left: (pos.left-panelWidth)+"px",
});
}
panel.slideDown(100);
$(document).on("keydown.red-ui-popover-panel-close", function(event) {
if (event.keyCode === 27) {
// ESCAPE
if (closeCallback) {
closeCallback();
}
hide(options.dispose);
}
});
$(document).on("mousedown.red-ui-popover-panel-close", function(event) {
if(!$(event.target).closest(panel).length && !$(event.target).closest(".red-ui-editor-dialog").length) {
if (closeCallback) {
closeCallback();
}
hide(options.dispose);
hide();
}
// if ($(event.target).closest(target).length) {
// event.preventDefault();

View File

@@ -39,16 +39,8 @@
this.uiContainer = this.element.wrap("<div>").parent();
this.uiContainer.addClass("red-ui-searchBox-container");
if (this.options.style === "compact") {
this.uiContainer.addClass("red-ui-searchBox-compact");
}
if (this.element.parents("form").length === 0) {
var form = this.element.wrap("<form>").parent();
form.addClass("red-ui-searchBox-form");
}
$('<i class="fa fa-search"></i>').prependTo(this.uiContainer);
this.clearButton = $('<a class="red-ui-searchBox-clear" href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer);
this.clearButton = $('<a href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer);
this.clearButton.on("click",function(e) {
e.preventDefault();
that.element.val("");
@@ -56,62 +48,6 @@
that.element.trigger("focus");
});
if (this.options.options) {
this.uiContainer.addClass("red-ui-searchBox-has-options");
this.optsButton = $('<a class="red-ui-searchBox-opts" href="#"><i class="fa fa-caret-down"></i></a>').appendTo(this.uiContainer);
var menuShown = false;
this.optsMenu = RED.popover.menu({
style: this.options.style,
options: this.options.options.map(function(opt) {
return {
label: opt.label,
onselect: function() {
that.element.val(opt.value+" ");
that._change(opt.value,true);
}
}
}),
onclose: function(cancelled) {
menuShown = false;
that.element.trigger("focus");
},
disposeOnClose: false
});
var showMenu = function() {
menuShown = true;
that.optsMenu.show({
target: that.optsButton,
align: "left",
offset: [that.optsButton.width()-2,-1],
dispose: false
})
}
this.optsButton.on("click",function(e) {
e.preventDefault();
if (!menuShown) {
showMenu();
} else {
// TODO: This doesn't quite work because the panel's own
// mousedown handler triggers a close before this click
// handler fires.
that.optsMenu.hide(true);
}
});
this.optsButton.on("keydown",function(e) {
if (!menuShown && e.keyCode === 40) {
//DOWN
showMenu();
}
});
this.element.on("keydown",function(e) {
if (!menuShown && e.keyCode === 40) {
//DOWN
showMenu();
}
});
}
this.resultCount = $('<span>',{class:"red-ui-searchBox-resultCount hide"}).appendTo(this.uiContainer);
this.element.val("");

View File

@@ -153,7 +153,7 @@ RED.tabs = (function() {
if (collapsibleMenu.is(":visible")) {
$(document).off("click.red-ui-tabmenu");
} else {
$(".red-ui-menu.red-ui-menu-dropdown").hide();
$(".red-ui-menu").hide();
$(document).on("click.red-ui-tabmenu", function(evt) {
$(document).off("click.red-ui-tabmenu");
collapsibleMenu.hide();
@@ -218,7 +218,7 @@ RED.tabs = (function() {
var thisTab = $(this).parent();
var fireSelectionChanged = false;
if (options.onselect) {
if (evt.metaKey || evt.ctrlKey) {
if (evt.metaKey) {
if (thisTab.hasClass("selected")) {
thisTab.removeClass("selected");
if (thisTab[0] !== currentTab[0]) {

View File

@@ -27,8 +27,7 @@
*
* methods:
* - data(items) - clears existing items and replaces with new data
* - clearSelection - clears the selected items
* - filter(filterFunc) - filters the tree using the provided function
*
* events:
* - treelistselect : function(event, item) {}
* - treelistconfirm : function(event,item) {}
@@ -40,8 +39,7 @@
* label: 'Local', // label for the item
* sublabel: 'Local', // a sub-label for the item
* icon: 'fa fa-rocket', // (optional) icon for the item
* checkbox: true/false, // (optional) if present, display checkbox accordingly
* selected: true/false, // (optional) whether the item is selected or not
* selected: true/false, // (optional) if present, display checkbox accordingly
* children: [] | function(done,item) // (optional) an array of child items, or a function
* // that will call the `done` callback with an array
* // of child items
@@ -61,11 +59,11 @@
* properties and functions:
*
* item.parent - set to the parent item
* item.depth - the depth in the tree (0 == root)
* item.treeList.container
* item.treeList.label - the label element for the item
* item.treeList.depth - the depth in the tree (0 == root)
* item.treeList.parentList - the editableList instance this item is in
* item.treeList.remove(detach) - removes the item from the tree. Optionally detach to preserve any event handlers on the item's label
* item.treeList.remove() - removes the item from the tree
* item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node,
* removing the UI decoration etc.
* detachChildElements - any children with custom
@@ -80,8 +78,8 @@
* Optionally selects the item after adding.
* item.treeList.expand(done) - expands the parent item to show children. Optional 'done' callback.
* item.treeList.collapse() - collapse the parent item to hide children.
* item.treeList.sortChildren(sortFunction) - does a one-time sort of the children using sortFunction
* item.treeList.replaceElement(element) - replace the custom element for the item
*
*
*
*
*/
@@ -102,8 +100,6 @@
var target;
switch(evt.keyCode) {
case 13: // ENTER
evt.preventDefault();
evt.stopPropagation();
if (selected.children) {
if (selected.treeList.container.hasClass("expanded")) {
selected.treeList.collapse()
@@ -116,8 +112,6 @@
break;
case 37: // LEFT
evt.preventDefault();
evt.stopPropagation();
if (selected.children&& selected.treeList.container.hasClass("expanded")) {
selected.treeList.collapse()
} else if (selected.parent) {
@@ -125,8 +119,6 @@
}
break;
case 38: // UP
evt.preventDefault();
evt.stopPropagation();
target = that._getPreviousSibling(selected);
if (target) {
target = that._getLastDescendant(target);
@@ -136,8 +128,6 @@
}
break;
case 39: // RIGHT
evt.preventDefault();
evt.stopPropagation();
if (selected.children) {
if (!selected.treeList.container.hasClass("expanded")) {
selected.treeList.expand()
@@ -145,8 +135,6 @@
}
break
case 40: //DOWN
evt.preventDefault();
evt.stopPropagation();
if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) {
target = selected.children[0];
} else {
@@ -163,8 +151,7 @@
}
});
this._data = [];
this._items = {};
this._selected = new Set();
this._topList = $('<ol class="red-ui-treeList-list">').css({
position:'absolute',
top: 0,
@@ -228,7 +215,7 @@
return candidates[index+1];
}
},
_addChildren: function(container,parent,children,depth,onCompleteChildren) {
_addChildren: function(container,parent,children,depth) {
var that = this;
var subtree = $('<ol class="red-ui-treeList-list">').appendTo(container).editableList({
connectWith: ".red-ui-treeList-sortable",
@@ -257,38 +244,15 @@
that._trigger("changeparent",null,evt);
});
that._trigger("sort",null,parent);
},
filter: parent.treeList.childFilter
}
});
if (!!that.options.sortable) {
subtree.addClass('red-ui-treeList-sortable');
}
var sliceSize = 30;
var index = 0;
var addSlice = function() {
var start = index;
for (var i=0;i<sliceSize;i++) {
index = start+i;
if (index === children.length) {
setTimeout(function() {
if (onCompleteChildren) {
onCompleteChildren();
}
},10);
return;
}
children[index].parent = parent;
subtree.editableList('addItem',children[index])
}
index++;
if (index < children.length) {
setTimeout(function() {
addSlice();
},10);
}
for (var i=0;i<children.length;i++) {
children[i].parent = parent;
subtree.editableList('addItem',children[i])
}
addSlice();
subtree.hide()
return subtree;
},
_fixDepths: function(parent,child) {
@@ -325,184 +289,23 @@
}
return reparentedEvent;
},
_initItem: function(item,depth) {
if (item.treeList) {
return;
}
_addSubtree: function(parentList, container, item, depth) {
var that = this;
this._items[item.id] = item;
item.treeList = {};
item.depth = depth;
item.treeList.remove = function(detach) {
if (item.treeList.parentList) {
item.treeList.parentList.editableList('removeItem',item,detach);
}
item.treeList.depth = depth;
item.treeList.container = container;
item.treeList.parentList = parentList;
item.treeList.remove = function() {
parentList.editableList('removeItem',item);
if (item.parent) {
var index = item.parent.children.indexOf(item);
item.parent.children.splice(index,1)
that._trigger("sort",null,item.parent);
}
that._selected.delete(item);
delete item.treeList;
delete that._items[item.id];
}
item.treeList.insertChildAt = function(newItem,position,select) {
newItem.parent = item;
item.children.splice(position,0,newItem);
var processChildren = function(parent,i) {
that._initItem(i,parent.depth+1)
i.parent = parent;
if (i.children && typeof i.children !== 'function') {
i.children.forEach(function(item) {
processChildren(i, item, parent.depth+2)
});
}
}
processChildren(item,newItem);
if (!item.deferBuild && item.treeList.childList) {
item.treeList.childList.editableList('insertItemAt',newItem,position)
if (select) {
setTimeout(function() {
that.select(newItem)
},100);
}
that._trigger("sort",null,item);
if (that.activeFilter) {
that.filter(that.activeFilter);
}
}
}
item.treeList.addChild = function(newItem,select) {
item.treeList.insertChildAt(newItem,item.children.length,select);
}
item.treeList.expand = function(done) {
if (!item.children) {
if (done) { done(false) }
return;
}
if (!item.treeList.container) {
item.expanded = true;
if (done) { done(false) }
return;
}
var container = item.treeList.container;
if (container.hasClass("expanded")) {
if (done) { done(false) }
return;
}
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
container.addClass('built');
var childrenAdded = false;
var spinner;
var startTime = 0;
var started = Date.now();
var completeBuild = function(children) {
childrenAdded = true;
item.treeList.childList = that._addChildren(container,item,children,depth, function() {
if (done) { done(true) }
that._trigger("childrenloaded",null,item)
});
var delta = Date.now() - startTime;
if (delta < 400) {
setTimeout(function() {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
},400-delta);
} else {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
}
item.expanded = true;
}
if (typeof item.children === 'function') {
item.children(completeBuild,item);
} else {
delete item.deferBuild;
completeBuild(item.children);
}
if (!childrenAdded) {
startTime = Date.now();
spinner = $('<div class="red-ui-treeList-spinner">').css({
"background-position": (35+depth*20)+'px 50%'
}).appendTo(container);
}
} else {
if (that._loadingData || item.children.length > 20) {
item.treeList.childList.show();
} else {
item.treeList.childList.slideDown('fast');
}
item.expanded = true;
if (done) { done(!that._loadingData) }
}
container.addClass("expanded");
}
item.treeList.collapse = function() {
if (!item.children) {
return;
}
item.expanded = false;
if (item.treeList.container) {
if (item.children.length < 20) {
item.treeList.childList.slideUp('fast');
} else {
item.treeList.childList.hide();
}
item.treeList.container.removeClass("expanded");
}
}
item.treeList.sortChildren = function(sortFunc) {
if (!item.children) {
return;
}
item.children.sort(sortFunc);
if (item.treeList.childList) {
// Do a one-off sort of the list, which means calling sort twice:
// 1. first with the desired sort function
item.treeList.childList.editableList('sort',sortFunc);
// 2. and then with null to remove it
item.treeList.childList.editableList('sort',null);
}
}
item.treeList.replaceElement = function (element) {
if (item.element) {
if (item.treeList.container) {
$(item.element).remove();
$(element).appendTo(item.treeList.label);
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(item.depth*20);
$(element).css({
width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
})
}
item.element = element;
}
}
if (item.children && typeof item.children !== "function") {
item.children.forEach(function(i) {
that._initItem(i,depth+1);
})
}
},
_addSubtree: function(parentList, container, item, depth) {
var that = this;
this._initItem(item,depth);
// item.treeList = {};
// item.treeList.depth = depth;
item.treeList.container = container;
item.treeList.parentList = parentList;
var label = $("<div>",{class:"red-ui-treeList-label"});
label.appendTo(container);
var label = $("<div>",{class:"red-ui-treeList-label"}).appendTo(container);
item.treeList.label = label;
if (item.class) {
label.addClass(item.class);
@@ -554,7 +357,6 @@
treeListIcon.off("click.red-ui-treeList-expand");
delete item.children;
container.removeClass("expanded");
delete item.expanded;
}
item.treeList.makeParent = function(children) {
if (treeListIcon.children().length) {
@@ -583,28 +385,104 @@
})
if (!item.children) {
item.children = children||[];
item.treeList.childList = that._addChildren(container,item,item.children,depth);
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
}
}
item.treeList.insertChildAt = function(newItem,position,select) {
newItem.parent = item;
item.children.splice(position,0,newItem);
if (!item.deferBuild) {
item.treeList.childList.editableList('insertItemAt',newItem,position)
if (select) {
setTimeout(function() {
that.select(newItem)
},100);
}
that._trigger("sort",null,item);
}
}
item.treeList.addChild = function(newItem,select) {
item.treeList.insertChildAt(newItem,item.children.length,select);
}
item.treeList.expand = function(done) {
if (!item.children) {
return;
}
if (container.hasClass("expanded")) {
done && done();
return;
}
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
container.addClass('built');
var childrenAdded = false;
var spinner;
var startTime = 0;
var completeBuild = function(children) {
childrenAdded = true;
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
var delta = Date.now() - startTime;
if (delta < 400) {
setTimeout(function() {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
},400-delta);
} else {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
}
done && done();
that._trigger("childrenloaded",null,item)
}
if (typeof item.children === 'function') {
item.children(completeBuild,item);
} else {
delete item.deferBuild;
completeBuild(item.children);
}
if (!childrenAdded) {
startTime = Date.now();
spinner = $('<div class="red-ui-treeList-spinner">').css({
"background-position": (35+depth*20)+'px 50%'
}).appendTo(container);
}
} else {
if (that._loadingData) {
item.treeList.childList.show();
} else {
item.treeList.childList.slideDown('fast');
}
done && done();
}
container.addClass("expanded");
}
item.treeList.collapse = function() {
if (!item.children) {
return;
}
item.treeList.childList.slideUp('fast');
container.removeClass("expanded");
}
var treeListIcon = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
if (item.children) {
item.treeList.makeParent();
}
if (item.checkbox) {
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>');
if (item.hasOwnProperty('selected')) {
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
var cb = $('<input class="red-ui-treeList-checkbox" type="checkbox">').prop('checked',item.selected).appendTo(selectWrapper);
label.toggleClass("selected",item.selected);
cb.on('click', function(e) {
e.stopPropagation();
});
cb.on('change', function(e) {
item.selected = this.checked;
if (item.selected) {
that._selected.add(item);
} else {
that._selected.delete(item);
}
label.toggleClass("selected",this.checked);
that._trigger("select",e,item);
})
@@ -619,15 +497,10 @@
cb.trigger("click");
}
}
selectWrapper.appendTo(label)
} else {
label.on("click", function(e) {
if (!that.options.multi) {
that.clearSelection();
}
that._topList.find(".selected").removeClass("selected");
label.addClass("selected");
that._selected.add(item);
that._trigger("select",e,item)
})
label.on("dblclick", function(e) {
@@ -635,30 +508,9 @@
that._trigger("confirm",e,item);
}
})
item.treeList.select = function(v) {
if (!that.options.multi) {
that.clearSelection();
}
label.toggleClass("selected",v);
if (v) {
that._selected.add(item);
that._trigger("select",null,item)
} else {
that._selected.delete(item);
}
that.reveal(item);
}
}
label.toggleClass("selected",!!item.selected);
if (item.selected) {
that._selected.add(item);
}
if (item.icon) {
if (typeof item.icon === "string") {
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
} else {
$('<span class="red-ui-treeList-icon">').appendTo(label).append(item.icon);
}
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
}
if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) {
if (item.hasOwnProperty('label')) {
@@ -676,13 +528,12 @@
}
if (item.children) {
if (Array.isArray(item.children) && !item.deferBuild) {
item.treeList.childList = that._addChildren(container,item,item.children,depth);
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
}
if (item.expanded) {
item.treeList.expand();
}
}
// label.appendTo(container);
},
empty: function() {
this._topList.editableList('empty');
@@ -691,7 +542,6 @@
var that = this;
if (items !== undefined) {
this._data = items;
this._items = {};
this._topList.editableList('empty');
this._loadingData = true;
for (var i=0; i<items.length;i++) {
@@ -706,149 +556,33 @@
return this._data;
}
},
show: function(item, done) {
if (typeof item === "string") {
item = this._items[item]
}
if (!item) {
return;
}
var that = this;
var stack = [];
var i = item;
while(i) {
stack.unshift(i);
i = i.parent;
}
var isOpening = false;
var handleStack = function(opening) {
isOpening = isOpening ||opening
var item = stack.shift();
if (stack.length === 0) {
setTimeout(function() {
that.reveal(item);
if (done) { done(); }
},isOpening?200:0);
} else {
item.treeList.expand(handleStack)
show: function(id) {
for (var i=0;i<this._data.length;i++) {
if (this._data[i].id === id) {
this._topList.editableList('show',this._data[i]);
}
}
handleStack();
},
reveal: function(item) {
if (typeof item === "string") {
item = this._items[item]
}
if (!item) {
return;
}
var listOffset = this._topList.offset().top;
var itemOffset = item.treeList.label.offset().top;
var scrollTop = this._topList.parent().scrollTop();
itemOffset -= listOffset+scrollTop;
var treeHeight = this._topList.parent().height();
var itemHeight = item.treeList.label.outerHeight();
if (itemOffset < itemHeight/2) {
this._topList.parent().scrollTop(scrollTop+itemOffset-itemHeight/2-itemHeight)
} else if (itemOffset+itemHeight > treeHeight) {
this._topList.parent().scrollTop(scrollTop+((itemOffset+2.5*itemHeight)-treeHeight));
}
},
select: function(item, triggerEvent, deselectExisting) {
var that = this;
if (!this.options.multi && deselectExisting !== false) {
this.clearSelection();
}
if (Array.isArray(item)) {
item.forEach(function(i) {
that.select(i,triggerEvent,false);
})
return;
}
if (typeof item === "string") {
item = this._items[item]
}
if (!item) {
return;
}
// this.show(item.id);
item.selected = true;
this._selected.add(item);
select: function(item) {
this._topList.find(".selected").removeClass("selected");
item.treeList.label.addClass("selected");
this._trigger("select",null,item)
if (item.treeList.label) {
item.treeList.label.addClass("selected");
}
if (triggerEvent !== false) {
this._trigger("select",null,item)
}
},
clearSelection: function() {
this._selected.forEach(function(item) {
item.selected = false;
if (item.treeList.label) {
item.treeList.label.removeClass("selected")
}
});
this._selected.clear();
},
selected: function() {
var selected = [];
this._selected.forEach(function(item) {
selected.push(item);
})
var s = this._topList.find(".selected");
if (this.options.multi) {
return selected;
var res = [];
s.each(function() {
res.push($(this).parent().data('data'));
})
return res;
}
if (selected.length) {
return selected[0]
if (s.length) {
return s.parent().data('data');
} else {
// TODO: This may be a bug.. it causes the call to return itself
// not undefined.
return undefined;
}
},
filter: function(filterFunc) {
this.activeFilter = filterFunc;
var totalCount = 0;
var filter = function(item) {
var matchCount = 0;
if (filterFunc && filterFunc(item)) {
matchCount++;
totalCount++;
}
var childCount = 0;
if (item.children && typeof item.children !== "function") {
if (item.treeList.childList) {
childCount = item.treeList.childList.editableList('filter', filter);
} else {
item.treeList.childFilter = filter;
if (filterFunc) {
item.children.forEach(function(i) {
if (filter(i)) {
childCount++;
}
})
}
}
matchCount += childCount;
if (filterFunc && childCount > 0) {
setTimeout(function() {
item.treeList.expand();
},10);
}
}
if (!filterFunc) {
totalCount++;
return true
}
return matchCount > 0
}
this._topList.editableList('filter', filter);
return totalCount;
},
get: function(id) {
return this._items[id] || null;
}
});

View File

@@ -164,84 +164,6 @@
}
})
}
},
cred:{
value:"cred",
label:"credential",
icon:"fa fa-lock",
inputType: "password",
valueLabel: function(container,value) {
var that = this;
container.css("pointer-events","none");
this.elementDiv.hide();
var buttons = $('<div>').css({
position: "absolute",
right:"6px",
top: "6px",
"pointer-events":"all"
}).appendTo(container);
var eyeButton = $('<button type="button" class="red-ui-button red-ui-button-small"></button>').css({
width:"20px"
}).appendTo(buttons).on("click", function(evt) {
evt.preventDefault();
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();
},50);
} else {
that.input.attr("type","text");
eyeCon.removeClass("fa-eye").addClass("fa-eye-slash");
setTimeout(function() {
that.input.focus();
},50);
}
}).hide();
var eyeCon = $('<i class="fa fa-eye"></i>').css("margin-left","-1px").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({
padding:"6px 6px",
borderRadius:"4px"
}).addClass("red-ui-typedInput-value-label-inactive").appendTo(container);
var editButton = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-pencil"></i></button>').appendTo(buttons).on("click", function(evt) {
evt.preventDefault();
innerContainer.hide();
container.css("background","none");
container.css("pointer-events","none");
that.input.val("");
that.element.val("");
that.elementDiv.show();
editButton.hide();
cancelButton.show();
eyeButton.show();
setTimeout(function() {
that.input.focus();
},50);
});
var cancelButton = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-times"></i></button>').css("margin-left","3px").appendTo(buttons).on("click", function(evt) {
evt.preventDefault();
innerContainer.show();
container.css("background","");
that.input.val("__PWRD__");
that.element.val("__PWRD__");
that.elementDiv.hide();
editButton.show();
cancelButton.hide();
eyeButton.hide();
that.input.attr("type","password");
eyeCon.removeClass("fa-eye-slash").addClass("fa-eye");
}).hide();
} else {
container.css("background","none");
container.css("pointer-events","none");
this.elementDiv.show();
eyeButton.show();
}
}
}
};
var nlsd = false;
@@ -298,8 +220,6 @@
that.input.attr(d,m);
});
this.defaultInputType = this.input.attr('type');
this.uiSelect.addClass("red-ui-typedInput-container");
this.element.attr('type','hidden');
@@ -449,9 +369,6 @@
if (opt.label) {
op.text(opt.label);
}
if (opt.title) {
op.prop('title', opt.title)
}
if (opt.icon) {
if (opt.icon.indexOf("<") === 0) {
$(opt.icon).prependTo(op);
@@ -571,6 +488,56 @@
done(labelWidth);
}
},
_resize: function() {
var that = this;
if (this.uiWidth !== null) {
this.uiSelect.width(this.uiWidth);
}
var type = this.typeMap[this.propertyType];
if (type && type.hasValue === false) {
this.selectTrigger.addClass("red-ui-typedInput-full-width");
} else {
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
this._getLabelWidth(this.selectTrigger, function(labelWidth) {
that.elementDiv.css('left',labelWidth+"px");
that.valueLabelContainer.css('left',labelWidth+"px");
if (that.optionExpandButton.shown) {
that.elementDiv.css('right',"22px");
that.valueLabelContainer.css('right',"22px");
} else {
that.elementDiv.css('right','0');
that.valueLabelContainer.css('right','0');
that.input.css({
'border-top-right-radius': '4px',
'border-bottom-right-radius': '4px'
});
}
if (that.optionSelectTrigger) {
if (type && type.options && type.hasValue === true) {
that.optionSelectLabel.css({'left':'auto'})
that._getLabelWidth(that.optionSelectLabel, function(lw) {
that.optionSelectTrigger.css({'width':(23+lw)+"px"});
that.elementDiv.css('right',(23+lw)+"px");
that.input.css({
'border-top-right-radius': 0,
'border-bottom-right-radius': 0
});
});
} else {
that.optionSelectLabel.css({'left':'0'})
that.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'});
if (!that.optionExpandButton.shown) {
that.elementDiv.css({'right':0});
that.input.css({
'border-top-right-radius': '4px',
'border-bottom-right-radius': '4px'
});
}
}
}
});
}
},
_updateOptionSelectLabel: function(o) {
var opt = this.typeMap[this.propertyType];
this.optionSelectLabel.empty();
@@ -598,6 +565,7 @@
}
if (opt.hasValue) {
this.optionValue = o.value;
this._resize();
this.input.trigger('change',this.propertyType,this.value());
}
} else {
@@ -637,12 +605,11 @@
this.propertyType = null;
this.type(currentType);
}
setTimeout(function() {that._resize();},0);
},
width: function(desiredWidth) {
this.uiWidth = desiredWidth;
if (this.uiWidth !== null) {
this.uiSelect.width(this.uiWidth);
}
this._resize();
},
value: function(value) {
var that = this;
@@ -713,23 +680,19 @@
}
else if (opt.icon.indexOf("/") !== -1) {
image = new Image();
image.onload = function() { that._resize(); }
image.onerror = function() { that._resize(); }
image.name = opt.icon;
image.src = mapDeprecatedIcon(opt.icon);
$('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel);
}
else {
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon,style:"min-width: 13px; margin-right: 4px;"}).prependTo(this.selectLabel);
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon}).prependTo(this.selectLabel);
}
}
if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) {
this.selectLabel.text(opt.label);
}
if (opt.hasValue === false) {
this.selectTrigger.addClass("red-ui-typedInput-full-width");
} else {
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
}
if (this.optionMenu) {
this.optionMenu.remove();
this.optionMenu = null;
@@ -740,13 +703,11 @@
this.optionExpandButton.shown = false;
}
if (this.optionSelectTrigger) {
this.optionSelectTrigger.css({"display":"inline-flex"});
this.optionSelectTrigger.show();
if (!opt.hasValue) {
this.optionSelectTrigger.css({"flex-grow":1})
this.elementDiv.hide();
this.valueLabelContainer.hide();
} else {
this.optionSelectTrigger.css({"flex-grow":0})
this.elementDiv.show();
this.valueLabelContainer.hide();
}
@@ -861,11 +822,6 @@
if (this.optionSelectTrigger) {
this.optionSelectTrigger.hide();
}
if (opt.inputType) {
this.input.attr('type',opt.inputType)
} else {
this.input.attr('type',this.defaultInputType)
}
if (opt.hasValue === false) {
this.oldValue = this.input.val();
this.input.val("");
@@ -874,8 +830,8 @@
} else if (opt.valueLabel) {
this.valueLabelContainer.show();
this.valueLabelContainer.empty();
this.elementDiv.hide();
opt.valueLabel.call(this,this.valueLabelContainer,this.input.val());
this.elementDiv.hide();
} else {
if (this.oldValue !== undefined) {
this.input.val(this.oldValue);
@@ -913,7 +869,7 @@
panel.show({
target:that.optionExpandButton,
onclose:content.onclose,
align: "left"
align: "right"
});
}
})
@@ -925,6 +881,9 @@
this._trigger("typechange",null,this.propertyType);
this.input.trigger('change',this.propertyType,this.value());
}
if (!image) {
this._resize();
}
}
}
},
@@ -951,6 +910,7 @@
},
show: function() {
this.uiSelect.show();
this._resize();
},
hide: function() {
this.uiSelect.hide();

View File

@@ -108,7 +108,7 @@ RED.deploy = (function() {
RED.events.on('workspace:dirty',function(state) {
RED.events.on('nodes:change',function(state) {
if (state.dirty) {
window.onbeforeunload = function() {
return RED._("deploy.confirm.undeployedChanges");
@@ -334,7 +334,8 @@ RED.deploy = (function() {
var invalidNodes = [];
RED.nodes.eachNode(function(node) {
if (!node.valid && !node.d) {
hasInvalid = hasInvalid || !node.valid;
if (!node.valid) {
invalidNodes.push(getNodeInfo(node));
}
if (node.type === "unknown") {
@@ -344,7 +345,6 @@ RED.deploy = (function() {
}
});
hasUnknown = unknownNodes.length > 0;
hasInvalid = invalidNodes.length > 0;
var unusedConfigNodes = [];
RED.nodes.eachConfig(function(node) {

View File

@@ -1029,9 +1029,9 @@ RED.diff = (function() {
}
var localSelectDiv = $('<label>',{class:"red-ui-diff-selectbox",for:safeNodeId+"-local"}).on("click", function(e) { e.stopPropagation();}).appendTo(localDiv);
var localRadio = $('<input>',{class:"red-ui-diff-selectbox-input "+className+"-local",id:safeNodeId+"-local",type:'radio',value:"local",name:safeNodeId}).data('node-id',node.id).on("change", changeHandler).appendTo(localSelectDiv);
var localRadio = $('<input>',{class:"red-ui-diff-selectbox-input",id:safeNodeId+"-local",type:'radio',value:"local",name:safeNodeId,class:className+"-local"}).data('node-id',node.id).on("change", changeHandler).appendTo(localSelectDiv);
var remoteSelectDiv = $('<label>',{class:"red-ui-diff-selectbox",for:safeNodeId+"-remote"}).on("click", function(e) { e.stopPropagation();}).appendTo(remoteDiv);
var remoteRadio = $('<input>',{class:"red-ui-diff-selectbox-input "+className+"-remote",id:safeNodeId+"-remote",type:'radio',value:"remote",name:safeNodeId}).data('node-id',node.id).on("change", changeHandler).appendTo(remoteSelectDiv);
var remoteRadio = $('<input>',{class:"red-ui-diff-selectbox-input",id:safeNodeId+"-remote",type:'radio',value:"remote",name:safeNodeId,class:className+"-remote"}).data('node-id',node.id).on("change", changeHandler).appendTo(remoteSelectDiv);
if (state === 'local') {
localRadio.prop('checked',true);
} else if (state === 'remote') {

View File

@@ -204,28 +204,32 @@ RED.editor = (function() {
node.dirty = true;
node.dirtyStatus = true;
var removedLinks = [];
if (outputMap) {
RED.nodes.eachLink(function(l) {
if (l.source === node) {
if (outputMap.hasOwnProperty(l.sourcePort)) {
if (node.ports) {
if (outputMap) {
RED.nodes.eachLink(function(l) {
if (l.source === node && outputMap.hasOwnProperty(l.sourcePort)) {
if (outputMap[l.sourcePort] === "-1") {
removedLinks.push(l);
} else {
l.sourcePort = outputMap[l.sourcePort];
}
}
});
}
if (node.outputs < node.ports.length) {
while (node.outputs < node.ports.length) {
node.ports.pop();
}
});
}
if (node.hasOwnProperty("__outputs")) {
if (node.outputs < node.__outputs) {
RED.nodes.eachLink(function(l) {
if (l.source === node && l.sourcePort >= node.outputs && removedLinks.indexOf(l) === -1) {
removedLinks.push(l);
}
});
} else if (node.outputs > node.ports.length) {
while (node.outputs > node.ports.length) {
node.ports.push(node.ports.length);
}
}
delete node.__outputs;
}
node.inputs = Math.min(1,Math.max(0,parseInt(node.inputs)));
if (isNaN(node.inputs)) {
@@ -486,7 +490,8 @@ RED.editor = (function() {
done();
}
}
if (definition.credentials || /^subflow:/.test(definition.type)) {
if (definition.credentials) {
if (node.credentials) {
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
completePrepare();
@@ -494,9 +499,7 @@ RED.editor = (function() {
$.getJSON(getCredentialsURL(node.type, node.id), function (data) {
node.credentials = data;
node.credentials._ = $.extend(true,{},data);
if (!/^subflow:/.test(definition.type)) {
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
}
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
completePrepare();
});
}
@@ -510,9 +513,7 @@ RED.editor = (function() {
for (var i=editStack.length-1;i<editStack.length;i++) {
var node = editStack[i];
label = node.type;
if (node.type === 'group') {
label = RED._("group.editGroup",{name:RED.utils.sanitize(node.name||node.id)});
} else if (node.type === '_expression') {
if (node.type === '_expression') {
label = RED._("expressionEditor.title");
} else if (node.type === '_js') {
label = RED._("jsEditor.title");
@@ -575,22 +576,17 @@ RED.editor = (function() {
$(this).attr("data-i18n",keys.join(";"));
});
if (type === "subflow-template") {
// This is the 'edit properties' dialog for a subflow template
// TODO: this needs to happen later in the dialog open sequence
// so that credentials can be loaded prior to building the form
RED.subflow.buildEditForm(type,node);
if (type === "subflow-template" || type === "subflow") {
RED.subflow.buildEditForm(dialogForm,type,node);
}
// Add dummy fields to prevent 'Enter' submitting the form in some
// cases, and also prevent browser auto-fill of password
// - the elements cannot be hidden otherwise Chrome will ignore them.
// - the elements need to have id's that imply password/username
$('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-password" type="password"/></span>').prependTo(dialogForm);
$('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-username" type="text"/></span>').prependTo(dialogForm);
$('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-user" type="text"/></span>').prependTo(dialogForm);
// Add in reverse order as they are prepended...
$('<input type="password" style="display: none;" />').prependTo(dialogForm);
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
dialogForm.on("submit", function(e) { e.preventDefault();});
dialogForm.find('input').attr("autocomplete","off");
dialogForm.find('input').attr("autocomplete","disable");
return dialogForm;
}
@@ -787,11 +783,6 @@ RED.editor = (function() {
nodeDiv.css({
'backgroundColor': backgroundColor
});
var borderColor = RED.utils.getDarkerColor(backgroundColor);
if (borderColor !== backgroundColor) {
nodeDiv.css('border-color',borderColor)
}
}
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
@@ -827,6 +818,99 @@ RED.editor = (function() {
searchInput.trigger("focus");
}
function createColorPicker(colorRow, color) {
var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(colorRow);
$('<i class="fa fa-caret-down"></i>').appendTo(colorButton);
var colorDisp = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton);
var selector = $("<input/>", {
id: "red-ui-editor-node-color",
type: "text",
value: color
}).css({
marginLeft: "10px",
width: "150px",
}).appendTo(colorRow);
selector.on("change", function (e) {
var color = selector.val();
$(".red-ui-editor-node-appearance-button .red-ui-search-result-node").css({
"background-color": color
});
});
selector.trigger("change");
colorButton.on("click", function (e) {
var recommendedColors = [
"#DDAA99",
"#3FADB5", "#87A980", "#A6BBCF",
"#AAAA66", "#C0C0C0", "#C0DEED",
"#C7E9C0", "#D7D7A0", "#D8BFD8",
"#DAC4B4", "#DEB887", "#DEBD5C",
"#E2D96E", "#E6E0F8", "#E7E7AE",
"#E9967A", "#F3B567", "#FDD0A2",
"#FDF0C2", "#FFAAAA", "#FFCC66",
"#FFF0F0", "#FFFFFF"
].map(function(c) {
var r = parseInt(c.substring(1, 3), 16) / 255;
var g = parseInt(c.substring(3, 5), 16) / 255;
var b = parseInt(c.substring(5, 7), 16) / 255;
return {
hex: c,
r: r,
g: g,
b: b,
l: 0.3 * r + 0.59 * g + 0.11 * b
}
});
// Sort by luminosity.
recommendedColors.sort(function (a, b) {
return a.l - b.l;
});
var numColors = recommendedColors.length;
var width = 30;
var height = 30;
var margin = 2;
var perRow = 6;
var picker = $("<div/>", {
class: "red-ui-color-picker"
}).css({
width: ((width+margin+margin)*perRow)+"px",
height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px"
});
var count = 0;
var row = null;
recommendedColors.forEach(function (col) {
if ((count % perRow) == 0) {
row = $("<div/>").appendTo(picker);
}
var button = $("<button/>", {
}).css({
width: width+"px",
height: height+"px",
margin: margin+"px",
backgroundColor: col.hex,
"border-style": "solid",
"border-width": "1px",
"border-color": col.luma<0.92?col.hex:'#ccc'
}).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
colorPanel.hide();
selector.val(col.hex);
selector.trigger("change");
});
count++;
});
var colorPanel = RED.popover.panel(picker);
colorPanel.show({
target: colorButton
})
});
}
function buildAppearanceForm(container,node) {
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
@@ -879,13 +963,13 @@ RED.editor = (function() {
var userCount = 0;
var subflowType = "subflow:"+node.id;
// RED.nodes.eachNode(function(n) {
// if (n.type === subflowType) {
// userCount++;
// }
// });
RED.nodes.eachNode(function(n) {
if (n.type === subflowType) {
userCount++;
}
});
$("#red-ui-editor-subflow-user-count")
.text(RED._("subflow.subflowInstances", {count:node.instances.length})).show();
.text(RED._("subflow.subflowInstances", {count:userCount})).show();
}
$('<div class="form-row">'+
@@ -912,35 +996,7 @@ RED.editor = (function() {
class: "form-row"
}).appendTo(dialogForm);
$("<label/>").text(RED._("editor.color")).appendTo(colorRow);
var recommendedColors = [
"#DDAA99",
"#3FADB5", "#87A980", "#A6BBCF",
"#AAAA66", "#C0C0C0", "#C0DEED",
"#C7E9C0", "#D7D7A0", "#D8BFD8",
"#DAC4B4", "#DEB887", "#DEBD5C",
"#E2D96E", "#E6E0F8", "#E7E7AE",
"#E9967A", "#F3B567", "#FDD0A2",
"#FDF0C2", "#FFAAAA", "#FFCC66",
"#FFF0F0", "#FFFFFF"
]
RED.colorPicker.create({
id: "red-ui-editor-node-color",
value: color,
palette: recommendedColors,
sortPalette: function (a, b) {return a.l - b.l;}
}).appendTo(colorRow);
$("#red-ui-editor-node-color").on('change', function(ev) {
// Horribly out of scope...
var colour = $(this).val();
nodeDiv.css('backgroundColor',colour);
var borderColor = RED.utils.getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
})
createColorPicker(colorRow, color);
}
@@ -955,11 +1011,6 @@ RED.editor = (function() {
var colour = RED.utils.getNodeColor(node.type, node._def);
var icon_url = RED.utils.getNodeIcon(node._def,node);
nodeDiv.css('backgroundColor',colour);
var borderColor = RED.utils.getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
@@ -1080,17 +1131,15 @@ RED.editor = (function() {
if (node.info) {
nodeInfoEditor.getSession().setValue(node.info, -1);
}
node.infoEditor = nodeInfoEditor;
return nodeInfoEditor;
}
function showEditDialog(node, defaultTab) {
function showEditDialog(node) {
var editing_node = node;
var isDefaultIcon;
var defaultIcon;
var nodeInfoEditor;
var finishedBuilding = false;
var skipInfoRefreshOnClose = false;
editStack.push(node);
RED.view.state(RED.state.EDITING);
@@ -1271,24 +1320,20 @@ RED.editor = (function() {
newValue = parseInt(newValue);
}
}
if (editing_node._def.defaults[d].type) {
if (newValue == "_ADD_") {
newValue = "";
}
}
if (editing_node[d] != newValue) {
if (editing_node._def.defaults[d].type) {
if (newValue == "_ADD_") {
newValue = "";
}
// Change to a related config node
var configNode = RED.nodes.node(editing_node[d]);
if (configNode) {
var users = configNode.users;
users.splice(users.indexOf(editing_node),1);
RED.events.emit("nodes:change",configNode);
}
configNode = RED.nodes.node(newValue);
if (configNode) {
configNode.users.push(editing_node);
RED.events.emit("nodes:change",configNode);
}
}
changes[d] = editing_node[d];
@@ -1423,19 +1468,6 @@ RED.editor = (function() {
if (type === "subflow") {
var old_env = editing_node.env;
var new_env = RED.subflow.exportSubflowInstanceEnv(editing_node);
if (new_env && new_env.length > 0) {
new_env.forEach(function(prop) {
if (prop.type === "cred") {
editing_node.credentials = editing_node.credentials || {_:{}};
editing_node.credentials[prop.name] = prop.value;
editing_node.credentials['has_'+prop.name] = (prop.value !== "");
if (prop.value !== '__PWRD__') {
changed = true;
}
delete prop.value;
}
});
}
if (!isSameObj(old_env, new_env)) {
editing_node.env = new_env;
changes.env = editing_node.env;
@@ -1485,7 +1517,6 @@ RED.editor = (function() {
editing_node.dirty = true;
validateNode(editing_node);
RED.events.emit("editor:save",editing_node);
RED.events.emit("nodes:change",editing_node);
RED.tray.close();
}
}
@@ -1503,10 +1534,6 @@ RED.editor = (function() {
}
},
open: function(tray, done) {
if (editing_node.hasOwnProperty('outputs')) {
editing_node.__outputs = editing_node.outputs;
}
var trayFooter = tray.find(".red-ui-tray-footer");
var trayBody = tray.find('.red-ui-tray-body');
trayBody.parent().css('overflow','hidden');
@@ -1537,6 +1564,9 @@ RED.editor = (function() {
collapsible: true,
menu: false
});
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
}
var ns;
if (node._def.set.module === "node-red") {
ns = "node-red";
@@ -1566,13 +1596,12 @@ RED.editor = (function() {
id: "editor-subflow-envProperties",
label: RED._("editor-tab.envProperties"),
name: RED._("editor-tab.envProperties"),
content: $('<div>', {id:"editor-subflow-envProperties-content",class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
iconClass: "fa fa-list"
};
RED.subflow.buildPropertiesForm(subflowPropertiesTab.content,node);
editorTabs.addTab(subflowPropertiesTab);
// This tab is populated by the oneditprepare function of this
// subflow. That ensures it is done *after* any credentials
// have been loaded for the instance.
}
if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
@@ -1606,9 +1635,6 @@ RED.editor = (function() {
prepareEditDialog(node,node._def,"node-input", function() {
trayBody.i18n();
finishedBuilding = true;
if (defaultTab) {
editorTabs.activateTab(defaultTab);
}
done();
});
},
@@ -1616,7 +1642,7 @@ RED.editor = (function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
if (editing_node && !skipInfoRefreshOnClose) {
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
}
RED.workspaces.refresh();
@@ -1630,7 +1656,6 @@ RED.editor = (function() {
show: function() {
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
RED.sidebar.help.show(editing_node.type, false);
}
}
}
@@ -1645,7 +1670,6 @@ RED.editor = (function() {
text: RED._("subflow.edit"),
click: function() {
RED.workspaces.show(id);
skipInfoRefreshOnClose = true;
$("#node-dialog-ok").trigger("click");
}
});
@@ -1837,7 +1861,6 @@ RED.editor = (function() {
show: function() {
if (editing_config_node) {
RED.sidebar.info.refresh(editing_config_node);
RED.sidebar.help.show(type, false);
}
}
}
@@ -1915,12 +1938,10 @@ RED.editor = (function() {
if (configNode) {
var users = configNode.users;
users.splice(users.indexOf(editing_config_node),1);
RED.events.emit("nodes:change",configNode);
}
configNode = RED.nodes.node(newValue);
if (configNode) {
configNode.users.push(editing_config_node);
RED.events.emit("nodes:change",configNode);
}
}
editing_config_node[d] = newValue;
@@ -2015,7 +2036,6 @@ RED.editor = (function() {
RED.view.redraw(true);
if (!configAdding) {
RED.events.emit("editor:save",editing_config_node);
RED.events.emit("nodes:change",editing_config_node);
}
RED.tray.close(function() {
updateConfigNodeSelect(configProperty,configType,editing_config_node.id,prefix);
@@ -2229,26 +2249,12 @@ RED.editor = (function() {
var old_env = editing_node.env;
var new_env = RED.subflow.exportSubflowTemplateEnv($("#node-input-env-container").editableList("items"));
if (new_env && new_env.length > 0) {
new_env.forEach(function(prop) {
if (prop.type === "cred") {
editing_node.credentials = editing_node.credentials || {_:{}};
editing_node.credentials[prop.name] = prop.value;
editing_node.credentials['has_'+prop.name] = (prop.value !== "");
if (prop.value !== '__PWRD__') {
changed = true;
}
delete prop.value;
}
});
}
if (!isSameObj(old_env, new_env)) {
editing_node.env = new_env;
changes.env = editing_node.env;
changed = true;
}
RED.palette.refresh();
if (changed) {
var wasChanged = editing_node.changed;
@@ -2268,7 +2274,6 @@ RED.editor = (function() {
validateNode(n);
}
});
RED.events.emit("subflows:change",editing_node);
RED.nodes.dirty(true);
var historyEvent = {
t:'edit',
@@ -2303,7 +2308,7 @@ RED.editor = (function() {
$("#node-input-env-container").editableList('height',height-95);
}
},
open: function(tray, done) {
open: function(tray) {
var trayFooter = tray.find(".red-ui-tray-footer");
var trayFooterLeft = $("<div/>", {
class: "red-ui-tray-footer-left"
@@ -2354,6 +2359,7 @@ RED.editor = (function() {
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
iconClass: "fa fa-cog"
};
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
editorTabs.addTab(nodePropertiesTab);
var descriptionTab = {
@@ -2382,19 +2388,11 @@ RED.editor = (function() {
buildAppearanceForm(appearanceTab.content,editing_node);
editorTabs.addTab(appearanceTab);
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
$("#subflow-input-name").val(subflow.name);
RED.text.bidi.prepareInput($("#subflow-input-name"));
trayBody.i18n();
$.getJSON(getCredentialsURL("subflow", subflow.id), function (data) {
subflow.credentials = data;
subflow.credentials._ = $.extend(true,{},data);
$("#subflow-input-name").val(subflow.name);
RED.text.bidi.prepareInput($("#subflow-input-name"));
finishedBuilding = true;
done();
});
finishedBuilding = true;
},
close: function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
@@ -2413,253 +2411,6 @@ RED.editor = (function() {
RED.tray.show(trayOptions);
}
function showEditGroupDialog(group) {
var editing_node = group;
editStack.push(group);
RED.view.state(RED.state.EDITING);
var nodeInfoEditor;
var finishedBuilding = false;
var trayOptions = {
title: getEditStackTitle(),
buttons: [
{
id: "node-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
RED.tray.close();
}
},
{
id: "node-dialog-ok",
class: "primary",
text: RED._("common.label.done"),
click: function() {
var changes = {};
var changed = false;
var wasDirty = RED.nodes.dirty();
var d;
var outputMap;
if (editing_node._def.oneditsave) {
var oldValues = {};
for (d in editing_node._def.defaults) {
if (editing_node._def.defaults.hasOwnProperty(d)) {
if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
oldValues[d] = editing_node[d];
} else {
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
}
}
}
try {
var rc = editing_node._def.oneditsave.call(editing_node);
if (rc === true) {
changed = true;
}
} catch(err) {
console.log("oneditsave",editing_node.id,editing_node.type,err.toString());
}
for (d in editing_node._def.defaults) {
if (editing_node._def.defaults.hasOwnProperty(d)) {
if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") {
if (oldValues[d] !== editing_node[d]) {
changes[d] = oldValues[d];
changed = true;
}
} else if (d !== "nodes") {
if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) {
changes[d] = oldValues[d];
changed = true;
}
}
}
}
}
var newValue;
if (editing_node._def.defaults) {
for (d in editing_node._def.defaults) {
if (editing_node._def.defaults.hasOwnProperty(d)) {
var input = $("#node-input-"+d);
if (input.attr('type') === "checkbox") {
newValue = input.prop('checked');
} else if (input.prop("nodeName") === "select" && input.attr("multiple") === "multiple") {
// An empty select-multiple box returns null.
// Need to treat that as an empty array.
newValue = input.val();
if (newValue == null) {
newValue = [];
}
} else if ("format" in editing_node._def.defaults[d] && editing_node._def.defaults[d].format !== "" && input[0].nodeName === "DIV") {
newValue = input.text();
} else {
newValue = input.val();
}
if (newValue != null) {
if (editing_node._def.defaults[d].type) {
if (newValue == "_ADD_") {
newValue = "";
}
}
if (editing_node[d] != newValue) {
if (editing_node._def.defaults[d].type) {
// Change to a related config node
var configNode = RED.nodes.node(editing_node[d]);
if (configNode) {
var users = configNode.users;
users.splice(users.indexOf(editing_node),1);
RED.events.emit("nodes:change",configNode);
}
configNode = RED.nodes.node(newValue);
if (configNode) {
configNode.users.push(editing_node);
RED.events.emit("nodes:change",configNode);
}
}
changes[d] = editing_node[d];
editing_node[d] = newValue;
changed = true;
}
}
}
}
}
var oldInfo = editing_node.info;
if (nodeInfoEditor) {
var newInfo = nodeInfoEditor.getValue();
if (!!oldInfo) {
// Has existing info property
if (newInfo.trim() === "") {
// New value is blank - remove the property
changed = true;
changes.info = oldInfo;
delete editing_node.info;
} else if (newInfo !== oldInfo) {
// New value is different
changed = true;
changes.info = oldInfo;
editing_node.info = newInfo;
}
} else {
// No existing info
if (newInfo.trim() !== "") {
// New value is not blank
changed = true;
changes.info = undefined;
editing_node.info = newInfo;
}
}
}
if (changed) {
var wasChanged = editing_node.changed;
editing_node.changed = true;
RED.nodes.dirty(true);
var historyEvent = {
t:'edit',
node:editing_node,
changes:changes,
dirty:wasDirty,
changed:wasChanged
};
RED.history.push(historyEvent);
RED.events.emit("groups:change",editing_node);
}
editing_node.dirty = true;
RED.tray.close();
RED.view.redraw(true);
}
}
],
resize: function(size) {
editTrayWidthCache['group'] = size.width;
$(".red-ui-tray-content").height(size.height - 50);
// var form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40);
// if (editing_node && editing_node._def.oneditresize) {
// try {
// editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()});
// } catch(err) {
// console.log("oneditresize",editing_node.id,editing_node.type,err.toString());
// }
// }
},
open: function(tray, done) {
var trayFooter = tray.find(".red-ui-tray-footer");
var trayFooterLeft = $("<div/>", {
class: "red-ui-tray-footer-left"
}).appendTo(trayFooter)
var trayBody = tray.find('.red-ui-tray-body');
trayBody.parent().css('overflow','hidden');
var editorTabEl = $('<ul></ul>').appendTo(trayBody);
var editorContent = $('<div></div>').appendTo(trayBody);
var editorTabs = RED.tabs.create({
element:editorTabEl,
onchange:function(tab) {
editorContent.children().hide();
if (tab.onchange) {
tab.onchange.call(tab);
}
tab.content.show();
if (finishedBuilding) {
RED.tray.resize();
}
},
collapsible: true,
menu: false
});
var nodePropertiesTab = {
id: "editor-tab-properties",
label: RED._("editor-tab.properties"),
name: RED._("editor-tab.properties"),
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
iconClass: "fa fa-cog"
};
buildEditForm(nodePropertiesTab.content,"dialog-form","group","node-red",group);
editorTabs.addTab(nodePropertiesTab);
var descriptionTab = {
id: "editor-tab-description",
label: RED._("editor-tab.description"),
name: RED._("editor-tab.description"),
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
iconClass: "fa fa-file-text-o",
onchange: function() {
nodeInfoEditor.focus();
}
};
editorTabs.addTab(descriptionTab);
nodeInfoEditor = buildDescriptionForm(descriptionTab.content,editing_node);
prepareEditDialog(group,group._def,"node-input", function() {
trayBody.i18n();
finishedBuilding = true;
done();
});
},
close: function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
RED.sidebar.info.refresh(editing_node);
nodeInfoEditor.destroy();
nodeInfoEditor = null;
editStack.pop();
editing_node = null;
},
show: function() {
}
}
if (editTrayWidthCache.hasOwnProperty('group')) {
trayOptions.width = editTrayWidthCache['group'];
}
RED.tray.show(trayOptions);
}
function showTypeEditor(type, options) {
if (customEditTypes.hasOwnProperty(type)) {
if (editStack.length > 0) {
@@ -2733,7 +2484,7 @@ RED.editor = (function() {
editor.toolbar = customEditTypes['_markdown'].buildToolbar(toolbarRow,editor);
if (options.expandable !== false) {
var expandButton = $('<button type="button" class="red-ui-button" style="float: right;"><i class="fa fa-expand"></i></button>').appendTo(editor.toolbar);
RED.popover.tooltip(expandButton, RED._("markdownEditor.expand"));
expandButton.on("click", function(e) {
e.preventDefault();
var value = editor.getValue();
@@ -2783,7 +2534,6 @@ RED.editor = (function() {
edit: showEditDialog,
editConfig: showEditConfigNodeDialog,
editSubflow: showEditSubflowDialog,
editGroup: showEditGroupDialog,
editJavaScript: function(options) { showTypeEditor("_js",options) },
editExpression: function(options) { showTypeEditor("_expression", options) },
editJSON: function(options) { showTypeEditor("_json", options) },
@@ -2808,7 +2558,7 @@ RED.editor = (function() {
/**
* Register a type editor.
* @param {string} type - the type name
* @param {object} definition - the editor definition
* @param {object} options - the editor definition
* @function
* @memberof RED.editor
*/

View File

@@ -15,7 +15,7 @@
**/
(function() {
var template = '<script type="text/x-red" data-template-name="_buffer"><div id="red-ui-editor-type-buffer-panels"><div id="red-ui-editor-type-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button class="red-ui-editor-type-buffer-type red-ui-button red-ui-button-small"><i class="fa fa-exclamation-circle"></i> <span id="red-ui-editor-type-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="red-ui-editor-type-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></button></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="red-ui-editor-type-buffer-str"></div></div></div><div id="red-ui-editor-type-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px; margin-bottom:0;"><div class="node-text-editor" id="red-ui-editor-type-buffer-bin"></div></div></div></div></script>';
var template = '<script type="text/x-red" data-template-name="_buffer"><div id="red-ui-editor-type-buffer-panels"><div id="red-ui-editor-type-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button class="red-ui-editor-type-buffer-type red-ui-button red-ui-button-small"><i class="fa fa-exclamation-circle"></i> <span id="red-ui-editor-type-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="red-ui-editor-type-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></button></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="red-ui-editor-type-buffer-str"></div></div></div><div id="red-ui-editor-type-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px"><div class="node-text-editor" id="red-ui-editor-type-buffer-bin"></div></div></div></div></script>';
function stringToUTF8Array(str) {
var data = [];
@@ -187,7 +187,8 @@
$(".red-ui-editor-type-buffer-type").on("click", function(e) {
e.preventDefault();
RED.sidebar.help.set(RED._("bufferEditor.modeDesc"));
RED.sidebar.info.set(RED._("bufferEditor.modeDesc"));
RED.sidebar.info.show();
})

View File

@@ -102,7 +102,7 @@
var f = $(this).val();
var args = RED._('jsonata:'+f+".args",{defaultValue:''});
var title = "<h5>"+f+"("+args+")</h5>";
var body = RED.utils.renderMarkdown(RED._('jsonata:'+f+'.desc',{defaultValue:''}));
var body = marked(RED._('jsonata:'+f+'.desc',{defaultValue:''}));
$("#red-ui-editor-type-expression-help").html(title+"<p>"+body+"</p>");
})
@@ -207,7 +207,6 @@
}
expressionEditor.getSession().setValue(v||"",-1);
});
funcSelect.change();
var tabs = RED.tabs.create({
element: $("#red-ui-editor-type-expression-tabs"),
@@ -237,7 +236,8 @@
var changeTimer;
$(".red-ui-editor-type-expression-legacy").on("click", function(e) {
e.preventDefault();
RED.sidebar.help.set(RED._("expressionEditor.compatModeDesc"));
RED.sidebar.info.set(RED._("expressionEditor.compatModeDesc"));
RED.sidebar.info.show();
})
var testExpression = function() {
var value = testDataEditor.getValue();
@@ -317,9 +317,9 @@
var p2 = $("#red-ui-editor-type-expression-panel-info > .form-row > div:first-child");
p2Height -= p2.outerHeight(true) + 20;
$(".red-ui-editor-type-expression-tab-content").height(p2Height);
$("#red-ui-editor-type-expression-test-data").css("height",(p2Height-25)+"px");
$("#red-ui-editor-type-expression-test-data").css("height",(p2Height-5)+"px");
testDataEditor.resize();
$("#red-ui-editor-type-expression-test-result").css("height",(p2Height-25)+"px");
$("#red-ui-editor-type-expression-test-result").css("height",(p2Height-5)+"px");
testResultEditor.resize();
}
});

View File

@@ -87,9 +87,6 @@
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
}
dialogForm.i18n();
setTimeout(function() {
expressionEditor.focus();
},300);
},
close: function() {
expressionEditor.destroy();

View File

@@ -106,7 +106,7 @@
options.push({id:"red-ui-editor-type-json-menu-duplicate", icon:"fa fa-copy", label:RED._("jsonEditor.duplicate"),onselect:function(){
var newKey = item.key;
if (item.parent.type === 'array') {
newKey = item.parent.children.length;
newKey = parent.children.length;
} else {
var m = /^(.*?)(-(\d+))?$/.exec(newKey);
var usedKeys = {};
@@ -301,9 +301,9 @@
var val = $('<input type="text" class="red-ui-editor-type-json-editor-value">').css({width:w+"px"}).val(""+valValue).insertAfter(valueLabel).typedInput({
types:[
'str','num','bool',
{value:"null",label:RED._("common.type.null"),hasValue:false},
{value:"array",label:RED._("common.type.array"),hasValue:false,icon:"red/images/typedInput/json.png"},
{value:"object",label:RED._("common.type.object"),hasValue:false,icon:"red/images/typedInput/json.png"}
{value:"null",label:"null",hasValue:false},
{value:"array",label:"array",hasValue:false},
{value:"object",label:"object",hasValue:false}
],
default: valType
});
@@ -327,10 +327,10 @@
item.value = valValue;
var valClass;
switch(valType) {
case 'str': if (item.children) { orphanedChildren = item.children } item.treeList.makeLeaf(true); item.type = "string"; valClass = "red-ui-debug-msg-type-string"; valValue = '"'+valValue+'"'; break;
case 'num': if (item.children) { orphanedChildren = item.children } item.treeList.makeLeaf(true); item.type = "number"; valClass = "red-ui-debug-msg-type-number"; break;
case 'bool': if (item.children) { orphanedChildren = item.children } item.treeList.makeLeaf(true); item.type = "boolean"; valClass = "red-ui-debug-msg-type-other"; item.value = (valValue === "true"); break;
case 'null': if (item.children) { orphanedChildren = item.children } item.treeList.makeLeaf(true); item.type = "null"; valClass = "red-ui-debug-msg-type-null"; item.value = valValue = "null"; break;
case 'str': item.children && (orphanedChildren = item.children); item.treeList.makeLeaf(true); item.type = "string"; valClass = "red-ui-debug-msg-type-string"; valValue = '"'+valValue+'"'; break;
case 'num': item.children && (orphanedChildren = item.children); item.treeList.makeLeaf(true); item.type = "number"; valClass = "red-ui-debug-msg-type-number"; break;
case 'bool': item.children && (orphanedChildren = item.children); item.treeList.makeLeaf(true); item.type = "boolean"; valClass = "red-ui-debug-msg-type-other"; item.value = (valValue === "true"); break;
case 'null': item.children && (orphanedChildren = item.children); item.treeList.makeLeaf(true); item.type = "null"; valClass = "red-ui-debug-msg-type-null"; item.value = valValue = "null"; break;
case 'object':
item.treeList.makeParent(orphanedChildren);
item.type = "object";
@@ -485,7 +485,7 @@
} else if (activeTab === "json-raw") {
result = expressionEditor.getValue();
}
if (onComplete) { onComplete(result) }
onComplete && onComplete(result);
RED.tray.close();
}
}
@@ -577,7 +577,7 @@
} catch(err) {
rootNode = null;
list.treeList('data',[{
label: RED._("jsonEditor.error.invalidJSON")+err.toString()
label: "Invalid JSON: "+err.toString()
}]);
}
}

View File

@@ -32,7 +32,7 @@
'<button type="button" class="red-ui-button" data-style="bq"><i class="fa fa-quote-left"></i></button>'+
'<button type="button" class="red-ui-button" data-style="hr"><i class="fa fa-minus"></i></button>'+
'<button type="button" class="red-ui-button" data-style="link"><i class="fa fa-link"></i></button>'+
'</span>'+
'</span>'
'</div>';
var template = '<script type="text/x-red" data-template-name="_markdown">'+
@@ -107,7 +107,7 @@
clearTimeout(changeTimer);
changeTimer = setTimeout(function() {
var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop();
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
$(".red-ui-editor-type-markdown-panel-preview").html(marked(expressionEditor.getValue()));
$(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop);
},200);
})
@@ -116,7 +116,7 @@
}
if (value) {
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
$(".red-ui-editor-type-markdown-panel-preview").html(marked(expressionEditor.getValue()));
}
panels = RED.panels.create({
id:"red-ui-editor-type-markdown-panels",

View File

@@ -1,689 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.group = (function() {
var _groupEditTemplate = '<script type="text/x-red" data-template-name="group">'+
'<div class="form-row">'+
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
'<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">'+
'</div>'+
// '<div class="node-input-group-style-tools"><span class="button-group"><button class="red-ui-button red-ui-button-small">Use default style</button><button class="red-ui-button red-ui-button-small">Set as default style</button></span></div>'+
'<div class="form-row" id="node-input-row-style-stroke">'+
'<label data-i18n="editor:common.label.style"></label>'+
'<label style="width: 70px;margin-right:10px" for="node-input-style-stroke" data-i18n="editor:common.label.line"></label>'+
'</div>'+
'<div class="form-row" style="padding-left: 100px;" id="node-input-row-style-fill">'+
'<label style="width: 70px;margin-right: 10px " for="node-input-style-fill" data-i18n="editor:common.label.fill"></label>'+
'</div>'+
'<div class="form-row">'+
'<label for="node-input-style-label" data-i18n="editor:common.label.label"></label>'+
'<input type="checkbox" id="node-input-style-label"/>'+
'</div>'+
'<div class="form-row" id="node-input-row-style-label-options">'+
'<div style="margin-left: 100px; display: inline-block">'+
'<div class="form-row">'+
'<span style="display: inline-block; min-width: 140px" id="node-input-row-style-label-color">'+
'<label style="width: 70px;margin-right: 10px" for="node-input-style-fill" data-i18n="editor:common.label.color"></label>'+
'</span>'+
'</div>'+
'<div class="form-row">'+
'<span style="display: inline-block; min-width: 140px;" id="node-input-row-style-label-position">'+
'<label style="width: 70px;margin-right: 10px " for="node-input-style-label-position" data-i18n="editor:common.label.position"></label>'+
'</span>'+
'</div>'+
'</div>'+
'</div>'+
'</script>';
var colorPalette = [
"#ff0000",
"#ffC000",
"#ffff00",
"#92d04f",
"#0070c0",
"#001f60",
"#6f2fa0",
"#000000",
"#777777"
]
var colorSteps = 3;
var colorCount = colorPalette.length;
for (var i=0,len=colorPalette.length*colorSteps;i<len;i++) {
var ci = i%colorCount;
var j = Math.floor(i/colorCount)+1;
var c = colorPalette[ci];
var r = parseInt(c.substring(1, 3), 16);
var g = parseInt(c.substring(3, 5), 16);
var b = parseInt(c.substring(5, 7), 16);
var dr = (255-r)/(colorSteps+((ci===colorCount-1) ?0:1));
var dg = (255-g)/(colorSteps+((ci===colorCount-1) ?0:1));
var db = (255-b)/(colorSteps+((ci===colorCount-1) ?0:1));
r = Math.min(255,Math.floor(r+j*dr));
g = Math.min(255,Math.floor(g+j*dg));
b = Math.min(255,Math.floor(b+j*db));
var s = ((r<<16) + (g<<8) + b).toString(16);
colorPalette.push('#'+'000000'.slice(0, 6-s.length)+s);
}
var defaultGroupStyle = {
label: true,
"label-position": "nw"
};
var groupDef = {
defaults:{
name:{value:""},
style:{value:{label:true}},
nodes:{value:[]}
},
category: "config",
oneditprepare: function() {
var style = this.style || {};
RED.colorPicker.create({
id:"node-input-style-stroke",
value: style.stroke || defaultGroupStyle.stroke || "#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
cellHeight: 16,
cellMargin: 3,
none: true,
opacity: style.hasOwnProperty('stroke-opacity')?style['stroke-opacity']:(defaultGroupStyle.hasOwnProperty('stroke-opacity')?defaultGroupStyle['stroke-opacity']:1.0)
}).appendTo("#node-input-row-style-stroke");
RED.colorPicker.create({
id:"node-input-style-fill",
value: style.fill || defaultGroupStyle.fill ||"none",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
cellHeight: 16,
cellMargin: 3,
none: true,
opacity: style.hasOwnProperty('fill-opacity')?style['fill-opacity']:(defaultGroupStyle.hasOwnProperty('fill-opacity')?defaultGroupStyle['fill-opacity']:1.0)
}).appendTo("#node-input-row-style-fill");
createLayoutPicker({
id:"node-input-style-label-position",
value:style["label-position"] || "nw"
}).appendTo("#node-input-row-style-label-position");
RED.colorPicker.create({
id:"node-input-style-color",
value: style.color || defaultGroupStyle.color ||"#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
cellHeight: 16,
cellMargin: 3
}).appendTo("#node-input-row-style-label-color");
$("#node-input-style-label").toggleButton({
enabledLabel: RED._("editor.show"),
disabledLabel: RED._("editor.show"),
})
$("#node-input-style-label").on("change", function(evt) {
$("#node-input-row-style-label-options").toggle($(this).prop("checked"));
})
$("#node-input-style-label").prop("checked", this.style.label)
$("#node-input-style-label").trigger("change");
},
oneditresize: function(size) {
},
oneditsave: function() {
this.style.stroke = $("#node-input-style-stroke").val();
this.style.fill = $("#node-input-style-fill").val();
this.style["stroke-opacity"] = $("#node-input-style-stroke-opacity").val();
this.style["fill-opacity"] = $("#node-input-style-fill-opacity").val();
this.style.label = $("#node-input-style-label").prop("checked");
if (this.style.label) {
this.style["label-position"] = $("#node-input-style-label-position").val();
this.style.color = $("#node-input-style-color").val();
} else {
delete this.style["label-position"];
delete this.style.color;
}
var node = this;
['stroke','fill','stroke-opacity','fill-opacity','color','label-position'].forEach(function(prop) {
if (node.style[prop] === defaultGroupStyle[prop]) {
delete node.style[prop]
}
})
this.resize = true;
},
set:{
module: "node-red"
}
}
function init() {
RED.events.on("view:selection-changed",function(selection) {
var activateGroup = !!selection.nodes;
var activateUngroup = false;
var activateMerge = false;
var activateRemove = false;
if (activateGroup) {
selection.nodes.forEach(function (n) {
if (n.type === "group") {
activateUngroup = true;
}
if (!!n.g) {
activateRemove = true;
}
});
if (activateUngroup) {
activateMerge = (selection.nodes.length > 1);
}
}
RED.menu.setDisabled("menu-item-group-group", !activateGroup);
RED.menu.setDisabled("menu-item-group-ungroup", !activateUngroup);
RED.menu.setDisabled("menu-item-group-merge", !activateMerge);
RED.menu.setDisabled("menu-item-group-remove", !activateRemove);
});
RED.actions.add("core:group-selection", function() { groupSelection() })
RED.actions.add("core:ungroup-selection", function() { ungroupSelection() })
RED.actions.add("core:merge-selection-to-group", function() { mergeSelection() })
RED.actions.add("core:remove-selection-from-group", function() { removeSelection() })
RED.actions.add("core:copy-group-style", function() { copyGroupStyle() });
RED.actions.add("core:paste-group-style", function() { pasteGroupStyle() });
$(_groupEditTemplate).appendTo("#red-ui-editor-node-configs");
var groupStyleDiv = $("<div>",{
class:"red-ui-flow-group-body",
style: "position: absolute; top: -1000px;"
}).appendTo(document.body);
var groupStyle = getComputedStyle(groupStyleDiv[0]);
defaultGroupStyle = {
stroke: convertColorToHex(groupStyle.stroke),
"stroke-opacity": groupStyle.strokeOpacity,
fill: convertColorToHex(groupStyle.fill),
"fill-opacity": groupStyle.fillOpacity,
label: true,
"label-position": "nw"
}
groupStyleDiv.remove();
groupStyleDiv = $("<div>",{
class:"red-ui-flow-group-label",
style: "position: absolute; top: -1000px;"
}).appendTo(document.body);
groupStyle = getComputedStyle(groupStyleDiv[0]);
defaultGroupStyle.color = convertColorToHex(groupStyle.fill);
groupStyleDiv.remove();
}
function convertColorToHex(c) {
var m = /^rgb\((\d+), (\d+), (\d+)\)$/.exec(c);
if (m) {
var s = ((parseInt(m[1])<<16) + (parseInt(m[2])<<8) + parseInt(m[3])).toString(16)
return '#'+'000000'.slice(0, 6-s.length)+s;
}
return c;
}
var groupStyleClipboard;
function copyGroupStyle() {
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].type === 'group') {
groupStyleClipboard = JSON.parse(JSON.stringify(selection.nodes[0].style));
RED.notify(RED._("clipboard.groupStyleCopied"),{id:"clipboard"})
}
}
function pasteGroupStyle() {
if (groupStyleClipboard) {
var selection = RED.view.selection();
if (selection.nodes) {
var historyEvent = {
t:'multi',
events:[],
dirty: RED.nodes.dirty()
}
selection.nodes.forEach(function(n) {
if (n.type === 'group') {
historyEvent.events.push({
t: "edit",
node: n,
changes: {
style: JSON.parse(JSON.stringify(n.style))
},
dirty: RED.nodes.dirty()
});
n.style = JSON.parse(JSON.stringify(groupStyleClipboard));
n.dirty = true;
}
})
if (historyEvent.events.length > 0) {
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.view.redraw();
}
}
}
}
function groupSelection() {
var selection = RED.view.selection();
if (selection.nodes) {
var group = createGroup(selection.nodes);
if (group) {
var historyEvent = {
t:"createGroup",
groups: [ group ],
dirty: RED.nodes.dirty()
}
RED.history.push(historyEvent);
RED.view.select({nodes:[group]});
RED.nodes.dirty(true);
}
}
}
function ungroupSelection() {
var selection = RED.view.selection();
if (selection.nodes) {
var newSelection = [];
groups = selection.nodes.filter(function(n) { return n.type === "group" });
var historyEvent = {
t:"ungroup",
groups: [ ],
dirty: RED.nodes.dirty()
}
RED.history.push(historyEvent);
groups.forEach(function(g) {
newSelection = newSelection.concat(ungroup(g))
historyEvent.groups.push(g);
})
RED.history.push(historyEvent);
RED.view.select({nodes:newSelection})
RED.nodes.dirty(true);
}
}
function ungroup(g) {
var nodes = [];
var parentGroup = RED.nodes.group(g.g);
g.nodes.forEach(function(n) {
nodes.push(n);
if (parentGroup) {
// Move nodes to parent group
n.g = parentGroup.id;
parentGroup.nodes.push(n);
parentGroup.dirty = true;
n.dirty = true;
} else {
delete n.g;
}
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
})
RED.nodes.removeGroup(g);
return nodes;
}
function mergeSelection() {
// TODO: this currently creates an entirely new group. Need to merge properties
// of any existing group
var selection = RED.view.selection();
if (selection.nodes) {
var nodes = [];
var historyEvent = {
t: "multi",
events: []
}
var ungroupHistoryEvent = {
t: "ungroup",
groups: []
}
var n;
var parentGroup;
// First pass, check they are all in the same parent
// TODO: DRY mergeSelection,removeSelection,...
for (var i=0; i<selection.nodes.length; i++) {
n = selection.nodes[i];
if (i === 0) {
parentGroup = n.g;
} else if (n.g !== parentGroup) {
RED.notify(RED._("group.errors.cannotCreateDiffGroups"),"error");
return;
}
}
// Second pass, ungroup any groups in the selection and add their contents
// to the selection
for (var i=0; i<selection.nodes.length; i++) {
n = selection.nodes[i];
if (n.type === "group") {
ungroupHistoryEvent.groups.push(n);
nodes = nodes.concat(ungroup(n));
} else {
nodes.push(n);
}
n.dirty = true;
}
if (ungroupHistoryEvent.groups.length > 0) {
historyEvent.events.push(ungroupHistoryEvent);
}
// Finally, create the new group
var group = createGroup(nodes);
if (group) {
RED.view.select({nodes:[group]})
}
historyEvent.events.push({
t:"createGroup",
groups: [ group ],
dirty: RED.nodes.dirty()
});
RED.history.push(historyEvent);
RED.nodes.dirty(true);
}
}
function removeSelection() {
var selection = RED.view.selection();
if (selection.nodes) {
var nodes = [];
var n;
var parentGroup = RED.nodes.group(selection.nodes[0].g);
if (parentGroup) {
try {
removeFromGroup(parentGroup,selection.nodes,true);
var historyEvent = {
t: "removeFromGroup",
dirty: RED.nodes.dirty(),
group: parentGroup,
nodes: selection.nodes
}
RED.history.push(historyEvent);
RED.nodes.dirty(true);
} catch(err) {
RED.notify(err,"error");
return;
}
}
RED.view.select({nodes:selection.nodes})
}
}
function createGroup(nodes) {
if (nodes.length === 0) {
return;
}
if (nodes.filter(function(n) { return n.type === "subflow" }).length > 0) {
RED.notify(RED._("group.errors.cannotAddSubflowPorts"),"error");
return;
}
// nodes is an array
// each node must be on the same tab (z)
var group = {
id: RED.nodes.id(),
type: 'group',
nodes: [],
style: JSON.parse(JSON.stringify(defaultGroupStyle)),
x: Number.POSITIVE_INFINITY,
y: Number.POSITIVE_INFINITY,
w: 0,
h: 0,
_def: RED.group.def
}
group.z = nodes[0].z;
RED.nodes.addGroup(group);
try {
addToGroup(group,nodes);
} catch(err) {
RED.notify(err,"error");
return;
}
return group;
}
function addToGroup(group,nodes) {
if (!Array.isArray(nodes)) {
nodes = [nodes];
}
var i,n,z;
var g;
// First pass - validate we can safely add these nodes to the group
for (i=0;i<nodes.length;i++) {
n = nodes[i]
if (!n.z) {
throw new Error("Cannot add node without a z property to a group")
}
if (!z) {
z = n.z;
} else if (z !== n.z) {
throw new Error("Cannot add nooes with different z properties")
}
if (n.g) {
// This is already in a group.
// - check they are all in the same group
if (!g) {
if (i!==0) {
// TODO: this might be ok when merging groups
throw new Error(RED._("group.errors.cannotCreateDiffGroups"))
}
g = n.g
}
}
if (g !== n.g) {
throw new Error(RED._("group.errors.cannotCreateDiffGroups"))
}
}
// The nodes are already in a group. The assumption is they should be
// wrapped in the newly provided group, and that group added to in their
// place to the existing containing group.
if (g) {
g = RED.nodes.group(g);
g.nodes.push(group);
g.dirty = true;
group.g = g.id;
}
// Second pass - add them to the group
for (i=0;i<nodes.length;i++) {
n = nodes[i];
if (n.type !== "subflow") {
if (g && n.g === g.id) {
var ni = g.nodes.indexOf(n);
if (ni > -1) {
g.nodes.splice(ni,1)
}
}
n.g = group.id;
n.dirty = true;
group.nodes.push(n);
group.x = Math.min(group.x,n.x-n.w/2-25-((n._def.button && n._def.align!=="right")?20:0));
group.y = Math.min(group.y,n.y-n.h/2-25);
group.w = Math.max(group.w,n.x+n.w/2+25+((n._def.button && n._def.align=="right")?20:0) - group.x);
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
}
}
if (g) {
RED.events.emit("groups:change",group)
}
markDirty(group);
}
function removeFromGroup(group, nodes, reparent) {
if (!Array.isArray(nodes)) {
nodes = [nodes];
}
var n;
// First pass, check they are all in the same parent
// TODO: DRY mergeSelection,removeSelection,...
for (var i=0; i<nodes.length; i++) {
if (nodes[i].g !== group.id) {
return;
}
}
var parentGroup = RED.nodes.group(group.g);
for (var i=0; i<nodes.length; i++) {
n = nodes[i];
n.dirty = true;
var index = group.nodes.indexOf(n);
group.nodes.splice(index,1);
if (reparent && group.g) {
n.g = group.g
parentGroup.nodes.push(n);
} else {
delete n.g;
}
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
}
markDirty(group);
}
function getNodes(group,recursive) {
var nodes = [];
group.nodes.forEach(function(n) {
nodes.push(n);
if (recursive && n.type === 'group') {
nodes = nodes.concat(getNodes(n,recursive))
}
})
return nodes;
}
function groupContains(group,item) {
if (item.g === group.id) {
return true;
}
for (var i=0;i<group.nodes.length;i++) {
if (group.nodes[i].type === "group") {
if (groupContains(group.nodes[i],item)) {
return true;
}
}
}
return false;
}
function getRootGroup(group) {
if (!group.g) {
return group;
}
return getRootGroup(RED.nodes.group(group.g))
}
function createLayoutPicker(options) {
var container = $("<div>",{style:"display:inline-block"});
var layoutHiddenInput = $("<input/>", { id: options.id, type: "hidden", value: options.value }).appendTo(container);
var layoutButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container);
$('<i class="fa fa-caret-down"></i>').appendTo(layoutButton);
var layoutDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(layoutButton);
var layoutDisp = $('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"}).appendTo(layoutDispContainer);
var refreshDisplay = function() {
var val = layoutHiddenInput.val();
layoutDisp.removeClass().addClass("red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val)
}
layoutButton.on("click", function(e) {
var picker = $("<div/>", {
class: "red-ui-group-layout-picker"
}).css({
width: "126px"
});
var row = null;
row = $("<div/>").appendTo(picker);
var currentButton;
for (var y=0;y<2;y++) { //red-ui-group-layout-text-pos
var yComponent= "ns"[y];
row = $("<div/>").appendTo(picker);
for (var x=0;x<3;x++) {
var xComponent = ["w","","e"][x];
var val = yComponent+xComponent;
var button = $("<button/>", { class:"red-ui-search-result-node red-ui-button","data-pos":val }).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
layoutHiddenInput.val($(this).data("pos"));
layoutPanel.hide()
refreshDisplay();
});
$('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val}).appendTo(button);
if (val === layoutHiddenInput.val()) {
currentButton = button;
}
}
}
refreshDisplay();
var layoutPanel = RED.popover.panel(picker);
layoutPanel.show({
target: layoutButton,
onclose: function() {
layoutButton.focus();
}
});
if (currentButton) {
currentButton.focus();
}
})
refreshDisplay();
return container;
}
function markDirty(group) {
group.dirty = true;
while(group) {
group.dirty = true;
group = RED.nodes.group(group.g);
}
}
return {
def: groupDef,
init: init,
createGroup: createGroup,
ungroup: ungroup,
addToGroup: addToGroup,
removeFromGroup: removeFromGroup,
getNodes: getNodes,
contains: groupContains,
markDirty: markDirty
}
})();

View File

@@ -17,8 +17,6 @@ RED.keyboard = (function() {
var isMac = /Mac/i.test(window.navigator.platform);
var handlersActive = true;
var handlers = {};
var partialState;
@@ -227,9 +225,6 @@ RED.keyboard = (function() {
}
}
d3.select(window).on("keydown",function() {
if (!handlersActive) {
return;
}
if (metaKeyCodes[d3.event.keyCode]) {
return;
}
@@ -529,12 +524,12 @@ RED.keyboard = (function() {
var pane = $('<div id="red-ui-settings-tab-keyboard"></div>');
$('<div class="keyboard-shortcut-entry keyboard-shortcut-list-header">'+
'<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input autocomplete="off" name="keyboard-filter" id="red-ui-settings-tab-keyboard-filter" type="text" data-i18n="[placeholder]keyboard.filterActions"></div>'+
'<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input id="red-ui-settings-tab-keyboard-filter" type="text" data-i18n="[placeholder]keyboard.filterActions"></div>'+
'<div class="keyboard-shortcut-entry-key" data-i18n="keyboard.shortcut"></div>'+
'<div class="keyboard-shortcut-entry-scope" data-i18n="keyboard.scope"></div>'+
'</div>').appendTo(pane);
pane.find("#red-ui-settings-tab-keyboard-filter").searchBox({
pane.find("input").searchBox({
delay: 100,
change: function() {
var filterValue = $(this).val().trim();
@@ -575,13 +570,6 @@ RED.keyboard = (function() {
return pane;
}
function enable() {
handlersActive = true;
}
function disable() {
handlersActive = false;
}
return {
init: init,
add: addHandler,
@@ -591,9 +579,7 @@ RED.keyboard = (function() {
},
revertToDefault: revertToDefault,
formatKey: formatKey,
validateKey: validateKey,
disable: disable,
enable: enable
validateKey: validateKey
}
})();

View File

@@ -22,7 +22,7 @@ RED.library = (function() {
var _libraryLookup = '<div id="red-ui-library-dialog-load" class="hide">'+
'<form class="form-horizontal">'+
'<div class="red-ui-library-dialog-box" style="height: 400px; position:relative; ">'+
'<div style="height: 400px; position:relative; ">'+
'<div id="red-ui-library-dialog-load-panes">'+
'<div class="red-ui-panel" id="red-ui-library-dialog-load-browser"></div>'+
'<div class="red-ui-panel">'+
@@ -41,7 +41,7 @@ RED.library = (function() {
var _librarySave = '<div id="red-ui-library-dialog-save" class="hide">'+
'<form class="form-horizontal">'+
'<div class="red-ui-library-dialog-box" style="height: 400px; position:relative; ">'+
'<div style="height: 400px; position:relative; ">'+
'<div id="red-ui-library-dialog-save-browser"></div>'+
'<div class="form-row">'+
'<label data-i18n="clipboard.export.exportAs"></label><input id="red-ui-library-dialog-save-filename" type="text">'+
@@ -64,14 +64,12 @@ RED.library = (function() {
var queryArgs = [];
var data = {};
for (var i=0; i < activeLibrary.fields.length; i++) {
for (var i=0; i<activeLibrary.fields.length; i++) {
var field = activeLibrary.fields[i];
if (field === "name") {
if (field == "name") {
data.name = name;
} else if (typeof(field) === 'object') {
data[field.name] = field.get();
} else {
data[field] = $("#" + elementPrefix + field).val();
data[field] = $("#"+elementPrefix+field).val();
}
}
data.text = activeLibrary.editor.getValue();
@@ -256,13 +254,6 @@ RED.library = (function() {
libraryEditor.renderer.$cursorLayer.element.style.opacity=0;
libraryEditor.$blockScrolling = Infinity;
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 570) {
dialogHeight = 400 - (570 - winHeight);
}
$("#red-ui-library-dialog-load .red-ui-library-dialog-box").height(dialogHeight);
$( "#red-ui-library-dialog-load" ).dialog("option","title",RED._("library.typeLibrary", {type:options.type})).dialog( "open" );
}
},
@@ -302,15 +293,6 @@ RED.library = (function() {
saveLibraryBrowser.select(listing[0].children[0]);
},200);
});
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 570) {
dialogHeight = 400 - (570 - winHeight);
}
$("#red-ui-library-dialog-save .red-ui-library-dialog-box").height(dialogHeight);
$( "#red-ui-library-dialog-save" ).dialog( "open" );
}
}
@@ -472,8 +454,6 @@ RED.library = (function() {
autoOpen: false,
width: 800,
resizable: false,
open: function( event, ui ) { RED.keyboard.disable() },
close: function( event, ui ) { RED.keyboard.enable() },
classes: {
"ui-dialog": "red-ui-editor-dialog",
"ui-dialog-titlebar-close": "hide",
@@ -538,31 +518,23 @@ RED.library = (function() {
{
text: RED._("common.label.load"),
class: "primary",
click: function () {
click: function() {
if (selectedLibraryItem) {
var elementPrefix = activeLibrary.elementPrefix || "node-input-";
for (var i = 0; i < activeLibrary.fields.length; i++) {
for (var i=0; i<activeLibrary.fields.length; i++) {
var field = activeLibrary.fields[i];
if (typeof(field) === 'object') {
var val = selectedLibraryItem[field.name];
field.set(val);
}
else {
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
}
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
}
activeLibrary.editor.setValue(libraryEditor.getValue(), -1);
activeLibrary.editor.setValue(libraryEditor.getValue(),-1);
}
$( this ).dialog( "close" );
}
}
],
open: function(e) {
RED.keyboard.disable();
$(this).parent().find(".ui-dialog-titlebar-close").hide();
},
close: function(e) {
RED.keyboard.enable();
if (libraryEditor) {
libraryEditor.destroy();
libraryEditor = null;

View File

@@ -75,16 +75,13 @@ RED.palette.editor = (function() {
});
})
}
function installNodeModule(id,version,url,callback) {
function installNodeModule(id,version,callback) {
var requestBody = {
module: id
};
if (version) {
requestBody.version = version;
}
if (url) {
requestBody.url = url;
}
$.ajax({
url:"nodes",
type: "POST",
@@ -223,11 +220,7 @@ RED.palette.editor = (function() {
var setElements = nodeEntry.sets[setName];
if (set.err) {
errorCount++;
var errMessage = set.err;
if (set.err.message) {
errMessage = set.err.message;
}
$("<li>").text(errMessage).appendTo(nodeEntry.errorList);
$("<li>").text(set.err).appendTo(nodeEntry.errorList);
}
if (set.enabled) {
activeTypeCount += set.types.length;
@@ -388,7 +381,6 @@ RED.palette.editor = (function() {
handleCatalogResponse(null,catalog,index,v);
refreshNodeModuleList();
}).fail(function(jqxhr, textStatus, error) {
console.warn("Error loading catalog",catalog,":",error);
handleCatalogResponse(jqxhr,catalog,index);
}).always(function() {
handled++;
@@ -630,7 +622,7 @@ RED.palette.editor = (function() {
if ($(this).hasClass('disabled')) {
return;
}
update(entry,loadedIndex[entry.name].version,loadedIndex[entry.name].pkg_url,container,function(err){});
update(entry,loadedIndex[entry.name].version,container,function(err){});
})
@@ -796,7 +788,7 @@ RED.palette.editor = (function() {
initInstallTab();
})
packageList = $('<ol>',{style:"position: absolute;top: 79px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({
packageList = $('<ol>',{style:"position: absolute;top: 78px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({
addButton: false,
scrollOnAdd: false,
addItem: function(container,i,object) {
@@ -880,7 +872,7 @@ RED.palette.editor = (function() {
$('<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) {
function update(entry,version,container,done) {
if (RED.settings.theme('palette.editable') === false) {
done(new Error('Palette not editable'));
return;
@@ -906,7 +898,7 @@ RED.palette.editor = (function() {
RED.actions.invoke("core:show-event-log");
});
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.name+" "+version);
installNodeModule(entry.name,version,url,function(xhr) {
installNodeModule(entry.name,version,function(xhr) {
spinner.remove();
if (xhr) {
if (xhr.responseJSON) {
@@ -1031,7 +1023,7 @@ RED.palette.editor = (function() {
RED.actions.invoke("core:show-event-log");
});
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.id+" "+entry.version);
installNodeModule(entry.id,entry.version,entry.pkg_url,function(xhr) {
installNodeModule(entry.id,entry.version,function(xhr) {
spinner.remove();
if (xhr) {
if (xhr.responseJSON) {

View File

@@ -92,11 +92,8 @@ RED.palette = (function() {
var lineHeight = 20;
var portHeight = 10;
el.attr("data-palette-label",label);
label = RED.utils.sanitize(label);
var words = label.split(/[ -]/);
var displayLines = [];
@@ -105,7 +102,7 @@ RED.palette = (function() {
for (var i=0;i<words.length;i++) {
var word = words[i];
var sep = (i == 0) ? "" : " ";
var newWidth = RED.view.calculateTextWidth(currentLine+sep+word, "red-ui-palette-label");
var newWidth = RED.view.calculateTextWidth(currentLine+sep+word, "red-ui-palette-label", 0);
if (newWidth < nodeWidth) {
currentLine += sep +word;
} else {
@@ -113,12 +110,12 @@ RED.palette = (function() {
displayLines.push(currentLine);
}
while (true) {
var wordWidth = RED.view.calculateTextWidth(word, "red-ui-palette-label");
var wordWidth = RED.view.calculateTextWidth(word, "red-ui-palette-label", 0);
if (wordWidth >= nodeWidth) {
// break word if too wide
for(var j = word.length; j > 0; j--) {
var s = word.substring(0, j);
var width = RED.view.calculateTextWidth(s, "red-ui-palette-label");
var width = RED.view.calculateTextWidth(s, "red-ui-palette-label", 0);
if (width < nodeWidth) {
displayLines.push(s);
word = word.substring(j);
@@ -142,7 +139,14 @@ RED.palette = (function() {
var labelElement = el.find(".red-ui-palette-label");
labelElement.html(lines).attr('dir', RED.text.bidi.resolveBaseTextDir(lines));
el.find(".red-ui-palette-port").css({top:(multiLineNodeHeight/2-5)+"px"});
if (RED.view.vertical()) {
// el.find(".red-ui-palette-port").css({top:(multiLineNodeHeight/2-5)+"px", left: "55px"});
// el.find(".red-ui-palette-port-output").css({top:(multiLineNodeHeight-5)+"px", right: "55px"});
// el.find(".red-ui-palette-port-input").css({top: "-5px"});
}else{
el.find(".red-ui-palette-port").css({top:(multiLineNodeHeight/2-5)+"px"});
// el.find(".palette_port_output").css({top:(multiLineNodeHeight/2-5)+"px", right: "-6px", left: "auto"});
}
var popOverContent;
try {
@@ -165,7 +169,6 @@ RED.palette = (function() {
metaData = typeInfo.set.module+" : ";
}
metaData += type;
$('<button type="button" onclick="RED.sidebar.help.show(\''+type+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
}
} catch(err) {
@@ -182,11 +185,7 @@ RED.palette = (function() {
function setIcon(element,sf) {
var icon_url = RED.utils.getNodeIcon(sf._def);
var iconContainer = element.find(".red-ui-palette-icon-container");
var currentIcon = iconContainer.attr("data-palette-icon");
if (currentIcon !== icon_url) {
iconContainer.attr("data-palette-icon", icon_url);
RED.utils.createIconElement(icon_url, iconContainer, true);
}
RED.utils.createIconElement(icon_url, iconContainer, true);
}
function getPaletteNode(type) {
@@ -220,31 +219,35 @@ RED.palette = (function() {
}
$('<div/>', {
class: "red-ui-palette-label"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-label-right" : "")
class: "red-ui-palette-label"
+ (((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-label-right" : "")
}).appendTo(d);
if (def.icon) {
var icon_url = RED.utils.getNodeIcon(def);
var iconContainer = $('<div/>', {
class: "red-ui-palette-icon-container"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-icon-container-right" : "")
class: "red-ui-palette-icon-container"
+ (((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-icon-container-right" : "")
}).appendTo(d);
iconContainer.attr("data-palette-icon", icon_url);
RED.utils.createIconElement(icon_url, iconContainer, true);
}
d.css("backgroundColor", RED.utils.getNodeColor(nt,def));
if (def.outputs > 0) {
var portOut = document.createElement("div");
portOut.className = "red-ui-palette-port red-ui-palette-port-output";
d.append(portOut);
}
if (!RED.view.vertical()) {
if (def.inputs > 0) {
var portIn = document.createElement("div");
portIn.className = "red-ui-palette-port red-ui-palette-port-input";
d.append(portIn);
if (def.outputs > 0) {
var portOut = document.createElement("div");
portOut.className = "red-ui-palette-port red-ui-palette-port-output";
d.append(portOut);
}
if (def.inputs > 0) {
var portIn = document.createElement("div");
portIn.className = "red-ui-palette-port red-ui-palette-port-input";
d.append(portIn);
}
}
createCategory(nodeCategory,rootCategory,category,(coreCategories.indexOf(rootCategory) !== -1)?"node-red":def.set.id);
@@ -256,7 +259,6 @@ RED.palette = (function() {
var popover = RED.popover.create({
target:d,
trigger: "hover",
interactive: true,
width: "300px",
content: "hi",
delay: { show: 750, hide: 50 }
@@ -272,28 +274,25 @@ RED.palette = (function() {
// html: true,
// container:'body'
// });
// d.on("click", function() {
// RED.view.focus();
// var helpText;
// if (nt.indexOf("subflow:") === 0) {
// helpText = RED.utils.renderMarkdown(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
// } else {
// helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
// }
// // Don't look too closely. RED.sidebar.info.set will set the 'Description'
// // section of the sidebar. Pass in the title of the Help section so it looks
// // right.
// RED.sidebar.type.show(helpText,RED._("sidebar.info.nodeHelp"));
// });
d.on("click", function() {
RED.view.focus();
var helpText;
if (nt.indexOf("subflow:") === 0) {
helpText = marked(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
} else {
helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
}
// Don't look too closely. RED.sidebar.info.set will set the 'Description'
// section of the sidebar. Pass in the title of the Help section so it looks
// right.
RED.sidebar.info.set(helpText,RED._("sidebar.info.nodeHelp"));
});
var chart = $("#red-ui-workspace-chart");
var chartSVG = $("#red-ui-workspace-chart>svg").get(0);
var activeSpliceLink;
var mouseX;
var mouseY;
var spliceTimer;
var groupTimer;
var activeGroup;
var hoverGroup;
var paletteWidth;
var paletteTop;
$(d).draggable({
@@ -305,53 +304,16 @@ RED.palette = (function() {
start: function() {
paletteWidth = $("#red-ui-palette").width();
paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top;
hoverGroup = null;
activeGroup = RED.view.getActiveGroup();
if (activeGroup) {
document.getElementById("group_select_"+activeGroup.id).classList.add("red-ui-flow-group-active-hovered");
}
RED.view.focus();
},
stop: function() {
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
if (hoverGroup) {
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
}
if (activeGroup) {
document.getElementById("group_select_"+activeGroup.id).classList.remove("red-ui-flow-group-active-hovered");
}
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
},
stop: function() { d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}},
drag: function(e,ui) {
var paletteNode = getPaletteNode(nt);
ui.originalPosition.left = paletteNode.offset().left;
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop();
if (!groupTimer) {
groupTimer = setTimeout(function() {
mouseX /= RED.view.scale();
mouseY /= RED.view.scale();
var group = RED.view.getGroupAtPoint(mouseX,mouseY);
if (group !== hoverGroup) {
if (hoverGroup) {
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
}
if (group) {
document.getElementById("group_select_"+group.id).classList.add("red-ui-flow-group-hovered");
}
hoverGroup = group;
if (hoverGroup) {
$(ui.helper).data('group',hoverGroup);
} else {
$(ui.helper).removeData('group');
}
}
groupTimer = null;
},200)
}
if (def.inputs > 0 && def.outputs > 0) {
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop();
if (!spliceTimer) {
spliceTimer = setTimeout(function() {
var nodes = [];
@@ -417,7 +379,7 @@ RED.palette = (function() {
RED.workspaces.show(nt.substring(8));
e.preventDefault();
});
nodeInfo = RED.utils.renderMarkdown(def.info||"");
nodeInfo = marked(def.info||"");
}
setLabel(nt,d,label,nodeInfo);
@@ -459,73 +421,71 @@ RED.palette = (function() {
categoryNode.show();
paletteNode.show();
}
function refreshNodeTypes() {
RED.nodes.eachSubflow(refreshSubflow)
}
function refreshSubflow(sf) {
var paletteNode = getPaletteNode('subflow:'+sf.id);
var portInput = paletteNode.find(".red-ui-palette-port-input");
var portOutput = paletteNode.find(".red-ui-palette-port-output");
RED.nodes.eachSubflow(function(sf) {
var paletteNode = getPaletteNode('subflow:'+sf.id);
var portInput = paletteNode.find(".red-ui-palette-port-input");
var portOutput = paletteNode.find(".red-ui-palette-port-output");
var paletteLabel = paletteNode.find(".red-ui-palette-label");
paletteLabel.attr("class","red-ui-palette-label" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-label-right" : ""));
var paletteLabel = paletteNode.find(".red-ui-palette-label");
paletteLabel.attr("class","red-ui-palette-label"
+ (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-label-right" : "")
);
var paletteIconContainer = paletteNode.find(".red-ui-palette-icon-container");
paletteIconContainer.attr("class","red-ui-palette-icon-container" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-icon-container-right" : ""));
var paletteIconContainer = paletteNode.find(".red-ui-palette-icon-container");
paletteIconContainer.attr("class","red-ui-palette-icon-container"
+ (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-icon-container-right" : "")
);
if (portInput.length === 0 && sf.in.length > 0) {
var portIn = document.createElement("div");
portIn.className = "red-ui-palette-port red-ui-palette-port-input";
paletteNode.append(portIn);
} else if (portInput.length !== 0 && sf.in.length === 0) {
portInput.remove();
}
if (portOutput.length === 0 && sf.out.length > 0) {
var portOut = document.createElement("div");
portOut.className = "red-ui-palette-port red-ui-palette-port-output";
paletteNode.append(portOut);
} else if (portOutput.length !== 0 && sf.out.length === 0) {
portOutput.remove();
}
var currentLabel = paletteNode.attr("data-palette-label");
var currentInfo = paletteNode.attr("data-palette-info");
if (currentLabel !== sf.name || currentInfo !== sf.info) {
paletteNode.attr("data-palette-info",sf.info);
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,RED.utils.renderMarkdown(sf.info||""));
}
setIcon(paletteNode,sf);
var currentCategory = paletteNode.data('category');
var newCategory = (sf.category||"subflows");
if (currentCategory !== newCategory) {
var category = escapeCategory(newCategory);
createCategory(newCategory,category,category,"node-red");
var currentCategoryNode = paletteNode.closest(".red-ui-palette-category");
var newCategoryNode = $("#red-ui-palette-"+category);
newCategoryNode.append(paletteNode);
if (newCategoryNode.find(".red-ui-palette-node").length === 1) {
categoryContainers[category].open();
if (portInput.length === 0 && sf.in.length > 0) {
var portIn = document.createElement("div");
portIn.className = "red-ui-palette-port red-ui-palette-port-input";
paletteNode.append(portIn);
} else if (portInput.length !== 0 && sf.in.length === 0) {
portInput.remove();
}
paletteNode.data('category',newCategory);
if (currentCategoryNode.find(".red-ui-palette-node").length === 0) {
if (currentCategoryNode.find("i").hasClass("expanded")) {
currentCategoryNode.find(".red-ui-palette-content").slideToggle();
currentCategoryNode.find("i").toggleClass("expanded");
if (portOutput.length === 0 && sf.out.length > 0) {
var portOut = document.createElement("div");
portOut.className = "red-ui-palette-port red-ui-palette-port-output";
paletteNode.append(portOut);
} else if (portOutput.length !== 0 && sf.out.length === 0) {
portOutput.remove();
}
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||""));
setIcon(paletteNode,sf);
var currentCategory = paletteNode.data('category');
var newCategory = (sf.category||"subflows");
if (currentCategory !== newCategory) {
var category = escapeCategory(newCategory);
createCategory(newCategory,category,category,"node-red");
var currentCategoryNode = paletteNode.closest(".red-ui-palette-category");
var newCategoryNode = $("#red-ui-palette-"+category);
newCategoryNode.append(paletteNode);
if (newCategoryNode.find(".red-ui-palette-node").length === 1) {
categoryContainers[category].open();
}
paletteNode.data('category',newCategory);
if (currentCategoryNode.find(".red-ui-palette-node").length === 0) {
if (currentCategoryNode.find("i").hasClass("expanded")) {
currentCategoryNode.find(".red-ui-palette-content").slideToggle();
currentCategoryNode.find("i").toggleClass("expanded");
}
}
}
}
paletteNode.css("backgroundColor", sf.color);
paletteNode.css("backgroundColor", sf.color);
});
}
function filterChange(val) {
var re = new RegExp(val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),'i');
$("#red-ui-palette-container .red-ui-palette-node").each(function(i,el) {
var currentLabel = $(el).attr("data-palette-label");
var currentLabel = $(el).find(".red-ui-palette-label").text();
var type = $(el).attr("data-palette-type");
if (val === "" || re.test(type) || re.test(currentLabel)) {
$(this).show();
@@ -557,8 +517,6 @@ RED.palette = (function() {
$('<div class="red-ui-component-footer"></div>').appendTo("#red-ui-palette");
$('<div id="red-ui-palette-shade" class="hide"></div>').appendTo("#red-ui-palette");
$("#red-ui-palette > .red-ui-palette-spinner").show();
RED.events.on('registry:node-type-added', function(nodeType) {
var def = RED.nodes.getType(nodeType);
@@ -600,8 +558,7 @@ RED.palette = (function() {
}
});
RED.events.on("subflows:change",refreshSubflow);
$("#red-ui-palette > .red-ui-palette-spinner").show();
$("#red-ui-palette-search input").searchBox({

View File

@@ -158,7 +158,7 @@ RED.projects.settings = (function() {
container.empty();
var desc;
if (activeProject.description) {
desc = RED.utils.renderMarkdown(activeProject.description);
desc = marked(activeProject.description);
} else {
desc = '<span class="red-ui-help-info-none">' + RED._("sidebar.project.noDescriptionAvailable") + '</span>';
}

View File

@@ -30,13 +30,13 @@ RED.projects.userSettings = (function() {
$('<div class="red-ui-settings-section-description"></div>').appendTo(gitconfigContainer).text(RED._("editor:sidebar.project.userSettings.committerTip"));
var row = $('<div class="red-ui-settings-row"></div>').appendTo(gitconfigContainer);
$('<label for="user-settings-gitconfig-username"></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row);
gitUsernameInput = $('<input type="text" id="user-settings-gitconfig-username">').appendTo(row);
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row);
gitUsernameInput = $('<input type="text">').appendTo(row);
gitUsernameInput.val(currentGitSettings.user.name||"");
row = $('<div class="red-ui-settings-row"></div>').appendTo(gitconfigContainer);
$('<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);
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row);
gitEmailInput = $('<input type="text">').appendTo(row);
gitEmailInput.val(currentGitSettings.user.email||"");
}

View File

@@ -685,8 +685,6 @@ RED.projects = (function() {
}
}
},projectData).then(function() {
RED.menu.setDisabled('menu-item-projects-open',false);
RED.menu.setDisabled('menu-item-projects-settings',false);
RED.events.emit("project:change", {name:name});
}).always(function() {
setTimeout(function() {
@@ -1497,6 +1495,7 @@ RED.projects = (function() {
}
} else if (projectType === 'open') {
return switchProject(selectedProject.name,function(err,data) {
dialog.dialog( "close" );
if (err) {
if (err.code !== 'credentials_load_failed') {
console.log(RED._("projects.create.unexpected_error"),err)
@@ -1605,7 +1604,6 @@ RED.projects = (function() {
},
}
},{active:true}).then(function() {
dialog.dialog( "close" );
RED.events.emit("project:change", {name:name});
}).always(function() {
setTimeout(function() {
@@ -1615,16 +1613,25 @@ 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>')
var cover = $('<div>').css({
background:"white",
position:"absolute",
top:0,right:0,bottom:0,left:"100%",
overflow:"hidden",
padding: "5px 20px",
transition: "left 0.4s",
whitespace: "nowrap",
width:"1000px"
}).on("click", function(evt) { evt.stopPropagation(); }).appendTo(row);
$('<span>').css({"lineHeight":"40px"}).text(RED._("projects.delete.confirm")).appendTo(cover);
$('<button style="margin-left:20px" class="red-ui-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 style="margin-left:20px" class="red-ui-button primary">'+RED._("common.label.delete")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
@@ -1664,27 +1671,16 @@ RED.projects = (function() {
if (typeof buttons === 'function') {
buttons = buttons(options||{});
}
dialog.dialog('option','buttons',buttons);
dialogBody.append(container);
var dialogHeight = 590;
var winHeight = $(window).height();
if (winHeight < 750) {
dialogHeight = 590 - (750 - winHeight);
}
$(".red-ui-projects-dialog-box").height(dialogHeight);
$(".red-ui-projects-dialog-project-list-inner-container").height(Math.max(500,dialogHeight) - 180);
dialog.dialog('option','title',screen.title||"");
dialog.dialog("open");
dialog.dialog({position: { 'my': 'center top', 'at': 'center top+20', 'of': window }});
}
function createProjectList(options) {
options = options||{};
var height = options.height || "200px";
var height = options.height || "300px";
var container = $('<div></div>',{class:"red-ui-projects-dialog-project-list-container" });
var filterTerm = "";
@@ -1942,122 +1938,100 @@ RED.projects = (function() {
resultCallbackArgs = data;
}
}).fail(function(xhr,textStatus,err) {
var responses;
if (options.responses && options.responses[xhr.status]) {
responses = options.responses[xhr.status];
var responses = options.responses[xhr.status];
if (typeof responses === 'function') {
resultCallback = responses;
resultCallbackArgs = {error:responses.statusText};
return;
} else if (options.handleAuthFail !== false && (xhr.responseJSON.code === 'git_auth_failed' || xhr.responseJSON.code === 'git_host_key_verification_failed')) {
if (xhr.responseJSON.code === 'git_auth_failed') {
var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch;
} else if (options.handleAuthFail !== false && xhr.responseJSON.code === 'git_auth_failed') {
var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch;
var message = $('<div>'+
var message = $('<div>'+
'<div class="form-row">'+RED._("projects.send-req.auth-req")+':</div>'+
'<div class="form-row"><div style="margin-left: 20px;">'+url+'</div></div>'+
'</div>');
var isSSH = false;
if (/^https?:\/\//.test(url)) {
$('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+
'<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
} else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
isSSH = true;
var row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-key">SSH Key</label>').appendTo(row);
var projectRepoSSHKeySelect = $('<select id="projects-user-auth-key">').width('70%').appendTo(row);
$.getJSON("settings/user/keys", function(data) {
var count = 0;
data.keys.forEach(function(key) {
projectRepoSSHKeySelect.append($("<option></option>").val(key.name).text(key.name));
count++;
});
if (count === 0) {
//TODO: handle no keys yet setup
}
var isSSH = false;
if (/^https?:\/\//.test(url)) {
$('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+
'<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
} else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
isSSH = true;
var row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-key">SSH Key</label>').appendTo(row);
var projectRepoSSHKeySelect = $('<select id="projects-user-auth-key">').width('70%').appendTo(row);
$.getJSON("settings/user/keys", function(data) {
var count = 0;
data.keys.forEach(function(key) {
projectRepoSSHKeySelect.append($("<option></option>").val(key.name).text(key.name));
count++;
});
row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row);
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row);
}
var notification = RED.notify(message,{
type:"error",
fixed: true,
modal: true,
buttons: [
{
//id: "node-dialog-delete",
//class: 'leftButton',
text: RED._("common.label.cancel"),
click: function() {
notification.close();
}
},{
text: '<span><i class="fa fa-refresh"></i> ' +RED._("projects.send-req.retry") +'</span>',
click: function() {
body = body || {};
var authBody = {};
if (isSSH) {
authBody.keyFile = $('#projects-user-auth-key').val();
authBody.passphrase = $('#projects-user-auth-passphrase').val();
} else {
authBody.username = $('#projects-user-auth-username').val();
authBody.password = $('#projects-user-auth-password').val();
}
var done = function(err) {
if (err) {
console.log(RED._("projects.send-req.update-failed"));
console.log(err);
} else {
sendRequest(options,body);
notification.close();
}
}
sendRequest({
url: "projects/"+activeProject.name+"/remotes/"+(xhr.responseJSON.remote||options.remote||'origin'),
type: "PUT",
responses: {
0: function(error) {
done(error,null);
},
200: function(data) {
done(null,data);
},
400: {
'unexpected_error': function(error) {
done(error,null);
}
},
}
},{auth:authBody});
}
}
]
if (count === 0) {
//TODO: handle no keys yet setup
}
});
return;
} else if (xhr.responseJSON.code === 'git_host_key_verification_failed') {
var message = $('<div>'+
'<div class="form-row">'+RED._("projects.send-req.host-key-verify-failed")+'</div>'+
'</div>');
var notification = RED.notify(message,{
type:"error",
fixed: true,
modal: true,
buttons: [
{
text: RED._("common.label.close"),
click: function() {
notification.close();
}
}
]
});
return;
row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row);
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row);
}
var notification = RED.notify(message,{
type:"error",
fixed: true,
modal: true,
buttons: [
{
//id: "node-dialog-delete",
//class: 'leftButton',
text: RED._("common.label.cancel"),
click: function() {
notification.close();
}
},{
text: '<span><i class="fa fa-refresh"></i> ' +RED._("projects.send-req.retry") +'</span>',
click: function() {
body = body || {};
var authBody = {};
if (isSSH) {
authBody.keyFile = $('#projects-user-auth-key').val();
authBody.passphrase = $('#projects-user-auth-passphrase').val();
} else {
authBody.username = $('#projects-user-auth-username').val();
authBody.password = $('#projects-user-auth-password').val();
}
var done = function(err) {
if (err) {
console.log(RED._("projects.send-req.update-failed"));
console.log(err);
} else {
sendRequest(options,body);
notification.close();
}
}
sendRequest({
url: "projects/"+activeProject.name+"/remotes/"+(xhr.responseJSON.remote||options.remote||'origin'),
type: "PUT",
responses: {
0: function(error) {
done(error,null);
},
200: function(data) {
done(null,data);
},
400: {
'unexpected_error': function(error) {
done(error,null);
}
},
}
},{auth:authBody});
}
}
]
});
return;
} else if (responses[xhr.responseJSON.code]) {
resultCallback = responses[xhr.responseJSON.code];
resultCallbackArgs = xhr.responseJSON;
@@ -2091,8 +2065,6 @@ RED.projects = (function() {
var branchFilterTerm = "";
var branchFilterCreateItem;
var branches = [];
var branchNames = new Set();
var remotes = [];
var branchPrefix = "";
var container = $('<div class="red-ui-projects-branch-list">').appendTo(options.container);
@@ -2100,30 +2072,18 @@ RED.projects = (function() {
delay: 200,
change: function() {
branchFilterTerm = $(this).val();
// if there is a / then
// - check what preceeds it is a known remote
var valid = false;
var hasRemote = false;
var m = /^([^/]+)\/[^/.~*?\[]/.exec(branchFilterTerm);
if (m && remotes.indexOf(m[1]) > -1) {
valid = true;
hasRemote = true;
}
if (!valid && /(\.\.|\/\.|[?*[~^: \\]|\/\/|\/.$|\/$)/.test(branchFilterTerm)) {
if (/(\.\.|\/\.|[?*[~^: \\]|\/\/|\/.$|\/$)/.test(branchFilterTerm)) {
if (!branchFilterCreateItem.hasClass("input-error")) {
branchFilterCreateItem.addClass("input-error");
branchFilterCreateItem.find("i").addClass("fa-warning").removeClass("fa-code-fork");
}
branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.invalid")+": "+(hasRemote?"":branchPrefix)+branchFilterTerm);
branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.invalid")+": "+branchPrefix+branchFilterTerm);
} else {
if (branchFilterCreateItem.hasClass("input-error")) {
branchFilterCreateItem.removeClass("input-error");
branchFilterCreateItem.find("i").removeClass("fa-warning").addClass("fa-code-fork");
}
branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.create")+":");
branchFilterCreateItem.find(".red-ui-sidebar-vc-branch-list-entry-create-name").text((hasRemote?"":branchPrefix)+branchFilterTerm);
branchFilterCreateItem.find(".red-ui-sidebar-vc-branch-list-entry-create-name").text(branchPrefix+branchFilterTerm);
}
branchList.editableList("filter");
}
@@ -2156,12 +2116,8 @@ RED.projects = (function() {
if (!entry.hasOwnProperty('commit')) {
body.name = branchFilter.val();
body.create = true;
if (options.remotes) {
var m = /^([^/]+)\/[^/.~*?\[]/.exec(body.name);
if (!m || remotes.indexOf(m[1]) === -1) {
body.name = remotes[0]+"/"+body.name;
}
if (options.remote) {
body.name = options.remote()+"/"+body.name;
}
} else {
if ($(this).hasClass('selected')) {
@@ -2176,17 +2132,11 @@ RED.projects = (function() {
},
filter: function(data) {
var isCreateEntry = (!data.hasOwnProperty('commit'));
var filterTerm = branchFilterTerm;
if (remotes.length > 0) {
var m = /^([^/]+)\/[^/.~*?\[]/.exec(filterTerm);
if (filterTerm !== "" && (!m || remotes.indexOf(m[1]) == -1)) {
filterTerm = remotes[0]+"/"+filterTerm;
}
}
return (
isCreateEntry &&
(
filterTerm !== "" && !branchNames.has(filterTerm)
branchFilterTerm !== "" &&
branches.indexOf(branchPrefix+branchFilterTerm) === -1
)
) ||
(
@@ -2201,14 +2151,12 @@ RED.projects = (function() {
branchList.editableList('empty');
var start = Date.now();
var spinner = addSpinnerOverlay(container).addClass("red-ui-component-spinner-contain");
if (options.remotes) {
remotes = options.remotes();
branchPrefix = remotes[0]+"/";
if (options.remote) {
branchPrefix = options.remote()+"/";
} else {
branchPrefix = "";
remotes = [];
}
branchNames = new Set();
sendRequest({
url: url,
type: "GET",
@@ -2220,7 +2168,6 @@ RED.projects = (function() {
branches = result.branches;
result.branches.forEach(function(b) {
branchList.editableList('addItem',b);
branchNames.add(b.name);
});
branchList.editableList('addItem',{});
setTimeout(function() {
@@ -2256,19 +2203,13 @@ RED.projects = (function() {
}
function init() {
dialog = $('<div id="red-ui-projects-dialog" class="hide red-ui-projects-edit-form"><div class="red-ui-projects-dialog-box"><form class="form-horizontal"></form><div class="red-ui-component-spinner hide"><img src="red/images/spin.svg"/></div></div></div>')
dialog = $('<div id="red-ui-projects-dialog" class="hide red-ui-projects-edit-form"><form class="form-horizontal"></form><div class="red-ui-component-spinner hide"><img src="red/images/spin.svg"/></div></div>')
.appendTo("#red-ui-editor")
.dialog({
modal: true,
autoOpen: false,
width: 600,
resizable: false,
open: function(e) {
RED.keyboard.disable();
},
close: function(e) {
RED.keyboard.enable();
},
classes: {
"ui-dialog": "red-ui-editor-dialog",
"ui-dialog-titlebar-close": "hide",
@@ -2349,7 +2290,6 @@ RED.projects = (function() {
if (data.active) {
$.getJSON("projects/"+data.active, function(project) {
activeProject = project;
RED.events.emit("projects:load",activeProject);
RED.sidebar.versionControl.refresh(true);
if (done) {
done(activeProject);

View File

@@ -336,7 +336,7 @@ RED.sidebar.versionControl = (function() {
var unstagedContent = $('<div class="red-ui-sidebar-vc-change-container"></div>').appendTo(localChanges.content);
var header = $('<div class="red-ui-sidebar-vc-change-header">'+RED._("sidebar.project.versionControl.localFiles")+'</div>').appendTo(unstagedContent);
stageAllButton = $('<button class="red-ui-button red-ui-button-small" style="position: absolute; right: 5px; top: 5px;"><i class="fa fa-plus"></i> '+RED._("sidebar.project.versionControl.all")+'</button>')
stageAllButton = $('<button class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-plus"></i> '+RED._("sidebar.project.versionControl.all")+'</button>')
.appendTo(header)
.on("click", function(evt) {
evt.preventDefault();
@@ -368,7 +368,7 @@ RED.sidebar.versionControl = (function() {
unmergedContent = $('<div class="red-ui-sidebar-vc-change-container"></div>').appendTo(localChanges.content);
header = $('<div class="red-ui-sidebar-vc-change-header">'+RED._("sidebar.project.versionControl.unmergedChanges")+'</div>').appendTo(unmergedContent);
bg = $('<div style="position: absolute; right: 5px; top: 5px;"></div>').appendTo(header);
bg = $('<div style="float: right"></div>').appendTo(header);
var abortMergeButton = $('<button class="red-ui-button red-ui-button-small" style="margin-right: 5px;">'+RED._("sidebar.project.versionControl.abortMerge")+'</button>')
.appendTo(bg)
.on("click", function(evt) {
@@ -433,7 +433,7 @@ RED.sidebar.versionControl = (function() {
header = $('<div class="red-ui-sidebar-vc-change-header">'+RED._("sidebar.project.versionControl.changeToCommit")+'</div>').appendTo(stagedContent);
bg = $('<div style="position: absolute; right: 5px; top: 5px;"></div>').appendTo(header);
bg = $('<div style="float: right"></div>').appendTo(header);
var showCommitBox = function() {
commitMessage.val("");
submitCommitButton.prop("disabled",true);
@@ -830,9 +830,10 @@ RED.sidebar.versionControl = (function() {
var remoteBranchList = utils.createBranchList({
placeholder: RED._("sidebar.project.versionControl.createRemoteBranchPlaceholder"),
currentLabel: RED._("sidebar.project.versionControl.upstream"),
remotes: function() {
remote: function() {
var project = RED.projects.getActiveProject();
return Object.keys(project.git.remotes);
var remotes = Object.keys(project.git.remotes);
return remotes[0];
},
container: remoteBranchSubRow,
onselect: function(body) {

View File

@@ -23,9 +23,11 @@ RED.search = (function() {
var visible = false;
var index = {};
var currentResults = [];
var keys = [];
var results = [];
var previousActiveElement;
function indexProperty(node,label,property) {
if (typeof property === 'string' || typeof property === 'number') {
property = (""+property).toLowerCase();
@@ -59,110 +61,53 @@ RED.search = (function() {
}
for (var i=0;i<properties.length;i++) {
if (n.hasOwnProperty(properties[i])) {
if (n.type === "group" && properties[i] === "nodes") {
continue;
}
indexProperty(n, l, n[properties[i]]);
}
}
}
function extractFlag(val, flagName, flags) {
// is:XYZ
var regEx = new RegExp("(?:^| )is:"+flagName+"(?: |$)");
var m = regEx.exec(val);
if (m) {
val = val.replace(regEx," ").trim();
flags[flagName] = true;
}
return val;
}
function extractValue(val, flagName, flags) {
// flagName:XYZ
var regEx = new RegExp("(?:^| )"+flagName+":([^ ]+)(?: |$)");
var m
while(!!(m = regEx.exec(val))) {
val = val.replace(regEx," ").trim();
flags[flagName] = flags[flagName] || [];
flags[flagName].push(m[1]);
}
return val;
function indexWorkspace() {
index = {};
RED.nodes.eachWorkspace(indexNode);
RED.nodes.eachSubflow(indexNode);
RED.nodes.eachConfig(indexNode);
RED.nodes.eachNode(indexNode);
keys = Object.keys(index);
keys.sort();
keys.forEach(function(key) {
index[key] = Object.keys(index[key]).map(function(id) {
return index[key][id];
})
})
}
function search(val) {
var results = [];
var keys = [];
searchResults.editableList('empty');
var typeFilter;
var m = /(?:^| )type:([^ ]+)/.exec(val);
if (m) {
val = val.replace(/(?:^| )type:[^ ]+/,"");
typeFilter = m[1];
}
var flags = {};
val = extractFlag(val,"invalid",flags);
val = extractFlag(val,"unused",flags);
val = extractFlag(val,"config",flags);
val = extractFlag(val,"subflow",flags);
// uses:<node-id>
val = extractValue(val,"uses",flags);
var hasFlags = Object.keys(flags).length > 0;
val = val.trim();
if (val.length > 0 || typeFilter || hasFlags) {
selected = -1;
results = [];
if (val.length > 0 || typeFilter) {
val = val.toLowerCase();
var i;
var j;
var list = [];
var nodes = {};
if (flags.uses) {
keys = flags.uses;
} else {
keys = Object.keys(index);
}
for (i=0;i<keys.length;i++) {
var key = keys[i];
var kpos = keys[i].indexOf(val);
if (kpos > -1) {
var ids = Object.keys(index[key]);
for (j=0;j<ids.length;j++) {
var node = index[key][ids[j]];
var isConfigNode = node.node._def.category === "config" && node.node.type !== 'group';
if (flags.uses && key === node.node.id) {
continue;
}
if (flags.hasOwnProperty("invalid")) {
var nodeIsValid = !node.node.hasOwnProperty("valid") || node.node.valid;
if (flags.invalid === nodeIsValid) {
continue;
}
}
if (flags.hasOwnProperty("config")) {
if (flags.config !== isConfigNode) {
continue;
}
}
if (flags.hasOwnProperty("subflow")) {
if (flags.subflow !== (node.node.type === 'subflow')) {
continue;
}
}
if (flags.hasOwnProperty("unused")) {
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
(isConfigNode && node.node.users.length === 0)
if (flags.unused !== isUnused) {
continue;
}
}
for (j=0;j<index[key].length;j++) {
var node = index[key][j];
if (!typeFilter || node.node.type === typeFilter) {
nodes[node.node.id] = nodes[node.node.id] = {
node: node.node,
label: node.label
};
nodes[node.node.id] = nodes[node.node.id] = node;
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
}
}
@@ -176,8 +121,22 @@ RED.search = (function() {
for (i=0;i<list.length;i++) {
results.push(nodes[list[i]]);
}
if (results.length > 0) {
for (i=0;i<Math.min(results.length,25);i++) {
searchResults.editableList('addItem',results[i])
}
if (results.length > 25) {
searchResults.editableList('addItem', {
more: {
results: results,
start: 25
}
})
}
} else {
searchResults.editableList('addItem',{});
}
}
return results;
}
function ensureSelectedIsVisible() {
@@ -202,37 +161,13 @@ RED.search = (function() {
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.searchInput">').appendTo(searchDiv).searchBox({
delay: 200,
change: function() {
searchResults.editableList('empty');
selected = -1;
currentResults = search($(this).val());
if (currentResults.length > 0) {
for (i=0;i<Math.min(currentResults.length,25);i++) {
searchResults.editableList('addItem',currentResults[i])
}
if (currentResults.length > 25) {
searchResults.editableList('addItem', {
more: {
results: currentResults,
start: 25
}
})
}
} else {
searchResults.editableList('addItem',{});
}
search($(this).val());
}
});
var copySearchContainer = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-caret-right"></button>').appendTo(searchDiv).on('click', function(evt) {
evt.preventDefault();
RED.sidebar.info.outliner.search(searchInput.val())
hide();
});
searchInput.on('keydown',function(evt) {
var children;
if (currentResults.length > 0) {
if (results.length > 0) {
if (evt.keyCode === 40) {
// Down
children = searchResults.children();
@@ -264,21 +199,21 @@ RED.search = (function() {
var object = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
if (object) {
searchResults.editableList('removeItem',object);
for (i=object.more.start;i<Math.min(currentResults.length,object.more.start+25);i++) {
searchResults.editableList('addItem',currentResults[i])
for (i=object.more.start;i<Math.min(results.length,object.more.start+25);i++) {
searchResults.editableList('addItem',results[i])
}
if (currentResults.length > object.more.start+25) {
if (results.length > object.more.start+25) {
searchResults.editableList('addItem', {
more: {
results: currentResults,
results: results,
start: object.more.start+25
}
})
}
}
} else {
if (currentResults.length > 0) {
reveal(currentResults[Math.max(0,selected)].node);
if (results.length > 0) {
reveal(results[Math.max(0,selected)].node);
}
}
}
@@ -299,13 +234,13 @@ RED.search = (function() {
div.on("click", function(evt) {
evt.preventDefault();
searchResults.editableList('removeItem',object);
for (i=object.more.start;i<Math.min(currentResults.length,object.more.start+25);i++) {
searchResults.editableList('addItem',currentResults[i])
for (i=object.more.start;i<Math.min(results.length,object.more.start+25);i++) {
searchResults.editableList('addItem',results[i])
}
if (currentResults.length > object.more.start+25) {
if (results.length > object.more.start+25) {
searchResults.editableList('addItem', {
more: {
results: currentResults,
results: results,
start: object.more.start+25
}
})
@@ -318,7 +253,17 @@ RED.search = (function() {
var def = node._def;
div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
RED.utils.createNodeIcon(node).appendTo(div);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
var colour = RED.utils.getNodeColor(node.type,def);
var icon_url = RED.utils.getNodeIcon(def,node);
if (node.type === 'tab') {
colour = "#C0DEED";
}
nodeDiv.css('backgroundColor',colour);
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
var contentDiv = $('<div>',{class:"red-ui-search-result-node-description"}).appendTo(div);
if (node.z) {
var workspace = RED.nodes.workspace(node.z);
@@ -363,7 +308,7 @@ RED.search = (function() {
$("#red-ui-palette-shade").show();
$("#red-ui-sidebar-shade").show();
$("#red-ui-sidebar-separator").hide();
indexWorkspace();
if (dialog === null) {
createDialog();
}
@@ -397,28 +342,6 @@ RED.search = (function() {
}
}
function clearIndex() {
index = {};
}
function addItemToIndex(item) {
indexNode(item);
}
function removeItemFromIndex(item) {
var keys = Object.keys(index);
for (var i=0,l=keys.length;i<l;i++) {
delete index[keys[i]][item.id];
if (Object.keys(index[keys[i]]).length === 0) {
delete index[keys[i]];
}
}
}
function updateItemOnIndex(item) {
removeItemFromIndex(item);
addItemToIndex(item);
}
function init() {
RED.actions.add("core:search",show);
@@ -435,33 +358,12 @@ RED.search = (function() {
$("#red-ui-editor-shade").on('mousedown',hide);
$("#red-ui-palette-shade").on('mousedown',hide);
$("#red-ui-sidebar-shade").on('mousedown',hide);
RED.events.on("workspace:clear", clearIndex);
RED.events.on("flows:add", addItemToIndex);
RED.events.on("flows:remove", removeItemFromIndex);
RED.events.on("flows:change", updateItemOnIndex);
RED.events.on("subflows:add", addItemToIndex);
RED.events.on("subflows:remove", removeItemFromIndex);
RED.events.on("subflows:change", updateItemOnIndex);
RED.events.on("nodes:add",addItemToIndex);
RED.events.on("nodes:remove",removeItemFromIndex);
RED.events.on("nodes:change",updateItemOnIndex);
RED.events.on("groups:add",addItemToIndex);
RED.events.on("groups:remove",removeItemFromIndex);
RED.events.on("groups:change",updateItemOnIndex);
}
return {
init: init,
show: show,
hide: hide,
search: search
hide: hide
};
})();

View File

@@ -250,7 +250,6 @@ RED.sidebar = (function() {
RED.popover.tooltip($("#red-ui-sidebar-separator").find(".red-ui-sidebar-control-right"),RED._("keyboard.toggleSidebar"),"core:toggle-sidebar");
showSidebar();
RED.sidebar.info.init();
RED.sidebar.help.init();
RED.sidebar.config.init();
RED.sidebar.context.init();
// hide info bar at start if screen rather narrow...

View File

@@ -25,7 +25,5 @@ RED.state = {
IMPORT_DRAGGING: 8,
QUICK_JOINING: 9,
PANNING: 10,
SELECTING_NODE: 11,
GROUP_DRAGGING: 12,
GROUP_RESIZE: 13
SELECTING_NODE: 11
}

File diff suppressed because it is too large Load Diff

View File

@@ -231,8 +231,7 @@ RED.sidebar.context = (function() {
RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), {
typeHint: data.format,
sourceId: id+"."+k,
tools: tools,
path: ""
tools: tools
}).appendTo(propRow.children()[1]);
}
})
@@ -276,8 +275,7 @@ RED.sidebar.context = (function() {
RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), {
typeHint: data.format,
sourceId: id+"."+k,
tools: tools,
path: ""
tools: tools
}).appendTo(propRow.children()[1]);
}
});
@@ -297,8 +295,7 @@ RED.sidebar.context = (function() {
RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), {
typeHint: v.format,
sourceId: id+"."+k,
tools: tools,
path: ""
tools: tools
}).appendTo(propRow.children()[1]);
if (contextStores.length > 1) {
$("<span>",{class:"red-ui-sidebar-context-property-storename"}).text(v.store).appendTo($(propRow.children()[0]))

View File

@@ -1,336 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.sidebar.help = (function() {
var content;
var toolbar;
var helpSection;
var panels;
var panelRatio;
var helpTopics = [];
var treeList;
var tocPanel;
var helpIndex = {};
function resizeStack() {
var h = $(content).parent().height() - toolbar.outerHeight();
panels.resize(h)
}
function init() {
content = document.createElement("div");
content.className = "red-ui-sidebar-info"
toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(content);
$('<span class="button-group"><a id="red-ui-sidebar-help-show-toc" class="red-ui-button red-ui-button-small selected" href="#"><i class="fa fa-list-ul"></i></a></span>').appendTo(toolbar)
var showTOCButton = toolbar.find('#red-ui-sidebar-help-show-toc')
RED.popover.tooltip(showTOCButton,RED._("sidebar.help.showTopics"));
showTOCButton.on("click",function(e) {
e.preventDefault();
if ($(this).hasClass('selected')) {
hideTOC();
} else {
showTOC();
}
});
var stackContainer = $("<div>",{class:"red-ui-sidebar-help-stack"}).appendTo(content);
tocPanel = $("<div>", {class: "red-ui-sidebar-help-toc"}).appendTo(stackContainer);
var helpPanel = $("<div>").css({
"overflow-y": "scroll"
}).appendTo(stackContainer);
panels = RED.panels.create({
container: stackContainer
})
panels.ratio(0.3);
helpSearch = $('<input type="text" data-i18n="[placeholder]sidebar.help.search">').appendTo(toolbar).searchBox({
style: "compact",
delay: 100,
change: function() {
var val = $(this).val().toLowerCase();
if (val) {
showTOC();
var c = treeList.treeList('filter',function(item) {
if (item.depth === 0) {
return true;
}
return (item.nodeType && item.nodeType.indexOf(val) > -1) ||
(item.subflowLabel && item.subflowLabel.indexOf(val) > -1)
},true)
} else {
treeList.treeList('filter',null);
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected.id);
}
}
}
})
helpSection = $("<div>",{class:"red-ui-help"}).css({
"padding":"6px",
}).appendTo(helpPanel)
$('<span class="red-ui-help-info-none">'+RED._("sidebar.help.noHelp")+'</span>').appendTo(helpSection);
treeList = $("<div>").css({width: "100%"}).appendTo(tocPanel).treeList({data: []})
treeList.on('treelistselect', function(e,item) {
if (item.nodeType) {
showHelp(item.nodeType);
}
})
RED.sidebar.addTab({
id: "help",
label: RED._("sidebar.help.label"),
name: RED._("sidebar.help.name"),
iconClass: "fa fa-book",
action:"core:show-help-tab",
content: content,
pinned: true,
enableOnEdit: true,
onchange: function() {
resizeStack()
}
});
$(window).on("resize", resizeStack);
$(window).on("focus", resizeStack);
RED.events.on('registry:node-type-added', queueRefresh);
RED.events.on('registry:node-type-removed', queueRefresh);
RED.events.on('subflows:change', refreshSubflow);
RED.actions.add("core:show-help-tab",show);
}
var refreshTimer;
function queueRefresh() {
if (!refreshTimer) {
refreshTimer = setTimeout(function() {
refreshTimer = null;
refreshHelpIndex();
},500);
}
}
function refreshSubflow(sf) {
var item = treeList.treeList('get',"node-type:subflow:"+sf.id);
item.subflowLabel = sf._def.label().toLowerCase();
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()}));
}
function hideTOC() {
var tocButton = $('#red-ui-sidebar-help-show-toc')
if (tocButton.hasClass('selected')) {
tocButton.removeClass('selected');
panelRatio = panels.ratio();
tocPanel.css({"transition":"height 0.2s"})
panels.ratio(0)
setTimeout(function() {
tocPanel.css({"transition":""})
},250);
}
}
function showTOC() {
var tocButton = $('#red-ui-sidebar-help-show-toc')
if (!tocButton.hasClass('selected')) {
tocButton.addClass('selected');
tocPanel.css({"transition":"height 0.2s"})
panels.ratio(Math.max(0.3,Math.min(panelRatio,0.7)));
setTimeout(function() {
tocPanel.css({"transition":""})
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected);
}
},250);
}
}
function refreshHelpIndex() {
helpTopics = [];
var modules = RED.nodes.registry.getModuleList();
var moduleNames = Object.keys(modules);
moduleNames.sort();
var helpData = [{
label: RED._("sidebar.help.nodeHelp"),
children: [],
expanded: true
}]
var subflows = RED.nodes.registry.getNodeTypes().filter(function(t) {return /subflow/.test(t)});
if (subflows.length > 0) {
helpData[0].children.push({
label: RED._("menu.label.subflows"),
children: []
})
subflows.forEach(function(nodeType) {
var sf = RED.nodes.getType(nodeType);
helpData[0].children[0].children.push({
id:"node-type:"+nodeType,
nodeType: nodeType,
subflowLabel: sf.label().toLowerCase(),
element: getNodeLabel({_def:sf,type:sf.label()})
})
})
}
moduleNames.forEach(function(moduleName) {
var module = modules[moduleName];
var nodeTypes = [];
var setNames = Object.keys(module.sets);
setNames.forEach(function(setName) {
module.sets[setName].types.forEach(function(nodeType) {
if ($("script[data-help-name='"+nodeType+"']").length) {
nodeTypes.push({
id: "node-type:"+nodeType,
nodeType: nodeType,
element:getNodeLabel({_def:RED.nodes.getType(nodeType),type:nodeType})
})
}
})
})
if (nodeTypes.length > 0) {
nodeTypes.sort(function(A,B) {
return A.nodeType.localeCompare(B.nodeType)
})
helpData[0].children.push({
id: moduleName,
icon: "fa fa-cube",
label: moduleName,
children: nodeTypes
})
}
});
treeList.treeList("data",helpData);
}
function getNodeLabel(n) {
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);
$('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).text(n.name||n.type).appendTo(contentDiv);
return div;
}
function showHelp(nodeType) {
helpSection.empty();
var helpText;
var title;
var m = /^subflow(:(.+))?$/.exec(nodeType);
if (m && m[2]) {
var subflowNode = RED.nodes.subflow(m[2]);
helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
title = subflowNode.name || nodeType;
} else {
helpText = $("script[data-help-name='"+nodeType+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
title = nodeType;
}
setInfoText(title, helpText, helpSection);
var ratio = panels.ratio();
if (ratio > 0.7) {
panels.ratio(0.7)
}
treeList.treeList("show","node-type:"+nodeType)
treeList.treeList("select","node-type:"+nodeType, false);
}
function show(type, bringToFront) {
if (bringToFront !== false) {
RED.sidebar.show("help");
}
if (type) {
// hideTOC();
showHelp(type);
}
resizeStack();
}
// TODO: DRY - projects.js
function addTargetToExternalLinks(el) {
$(el).find("a").each(function(el) {
var href = $(this).attr('href');
if (/^https?:/.test(href)) {
$(this).attr('target','_blank');
}
});
return el;
}
function setInfoText(title, infoText,target) {
if (title) {
$("<h1>",{class:"red-ui-help-title"}).text(title).appendTo(target);
}
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(target);
info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
var foldingHeader = "H3";
info.find(foldingHeader).wrapInner('<a class="red-ui-help-info-header expanded" href="#"></a>')
.find("a").prepend('<i class="fa fa-angle-right">').on("click", function(e) {
e.preventDefault();
var isExpanded = $(this).hasClass('expanded');
var el = $(this).parent().next();
while(el.length === 1 && el[0].nodeName !== foldingHeader) {
el.toggle(!isExpanded);
el = el.next();
}
$(this).toggleClass('expanded',!isExpanded);
})
target.parent().scrollTop(0);
}
function set(html,title) {
$(helpSection).empty();
setInfoText(title,html,helpSection);
hideTOC();
show();
}
function refreshSelection(selection) {
if (selection === undefined) {
selection = RED.view.selection();
}
if (selection.nodes) {
if (selection.nodes.length == 1) {
var node = selection.nodes[0];
if (node.type === "subflow" && node.direction) {
// ignore subflow virtual ports
} else if (node.type !== 'group'){
showHelp(node.type);
}
}
}
}
RED.events.on("view:selection-changed",refreshSelection);
return {
init: init,
show: show,
set: set
}
})();

View File

@@ -1,629 +0,0 @@
RED.sidebar.info.outliner = (function() {
var treeList;
var searchInput;
var activeSearch;
var projectInfo;
var projectInfoLabel;
var flowList;
var subflowList;
var globalConfigNodes;
var objects = {};
var missingParents = {};
var configNodeTypes;
function getFlowData() {
var flowData = [
{
label: RED._("menu.label.flows"),
expanded: true,
children: []
},
{
id: "__subflow__",
label: RED._("menu.label.subflows"),
children: [
getEmptyItem("__subflow__")
]
},
{
id: "__global__",
flow: "__global__",
label: RED._("sidebar.info.globalConfig"),
types: {},
children: [
getEmptyItem("__global__")
]
}
]
flowList = flowData[0];
subflowList = flowData[1];
globalConfigNodes = flowData[2];
configNodeTypes = { __global__: globalConfigNodes};
return flowData;
}
function getProjectLabel(p) {
var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
div.css("width", "calc(100% - 40px)");
var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
contentDiv.text(p.name);
var controls = $('<div>',{class:"red-ui-info-outline-item-controls"}).appendTo(div);
var editProjectButton = $('<button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;top: 3px;"><i class="fa fa-ellipsis-h"></i></button>')
.appendTo(controls)
.on("click", function(evt) {
evt.preventDefault();
RED.projects.editProject();
});
RED.popover.tooltip(editProjectButton,RED._('sidebar.project.showProjectSettings'));
return div;
}
var empties = {};
function getEmptyItem(id) {
var item = {
empty: true,
element: $('<div class="red-ui-info-outline-item red-ui-info-outline-item-empty">').text(RED._("sidebar.info.empty")),
}
empties[id] = item;
return item;
}
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: "+type+".label",err);
}
}
var newlineIndex = label.indexOf("\\n");
if (newlineIndex > -1) {
label = label.substring(0,newlineIndex)+"...";
}
return label;
}
function getNodeLabel(n) {
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("&nbsp;")
}
addControls(n, div);
return div;
}
function getFlowLabel(n) {
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);
addControls(n, div);
return div;
}
function getSubflowLabel(n) {
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("&nbsp;")
}
addControls(n, div);
return div;
// 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);
// contentDiv.text(n.name || n.id);
// addControls(n, div);
// return div;
}
function addControls(n,div) {
var controls = $('<div>',{class:"red-ui-info-outline-item-controls red-ui-info-outline-item-hover-controls"}).appendTo(div);
if (n._def.category === "config" && n.type !== "group") {
var userCountBadge = $('<button type="button" class="red-ui-info-outline-item-control-users red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').text(n.users.length).appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.search.show("uses:"+n.id);
})
RED.popover.tooltip(userCountBadge,function() { return RED._('editor.nodesUse',{count:n.users.length})});
}
if (n._def.button) {
var triggerButton = $('<button type="button" class="red-ui-info-outline-item-control-action red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.view.clickNodeButton(n);
})
RED.popover.tooltip(triggerButton,RED._("sidebar.info.triggerAction"));
}
// $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-eye"></i></button>').appendTo(controls).on("click",function(evt) {
// evt.preventDefault();
// evt.stopPropagation();
// RED.view.reveal(n.id);
// })
if (n.type !== 'group' && n.type !== 'subflow') {
var toggleButton = $('<button type="button" class="red-ui-info-outline-item-control-disable red-ui-button red-ui-button-small"><i class="fa fa-circle-thin"></i><i class="fa fa-ban"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (n.type === 'tab') {
if (n.disabled) {
RED.workspaces.enable(n.id)
} else {
RED.workspaces.disable(n.id)
}
} else {
// TODO: this ought to be a utility function in RED.nodes
var historyEvent = {
t: "edit",
node: n,
changed: n.changed,
changes: {
d: n.d
},
dirty:RED.nodes.dirty()
}
if (n.d) {
delete n.d;
} else {
n.d = true;
}
n.dirty = true;
n.changed = true;
RED.events.emit("nodes:change",n);
RED.nodes.dirty(true)
RED.view.redraw();
}
});
RED.popover.tooltip(toggleButton,function() {
return RED._("common.label."+(((n.type==='tab' && n.disabled) || (n.type!=='tab' && n.d))?"enable":"disable"));
});
} else {
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
}
controls.find("button").on("dblclick", function(evt) {
evt.preventDefault();
evt.stopPropagation();
})
}
function onProjectLoad(activeProject) {
objects = {};
var newFlowData = getFlowData();
projectInfoLabel.empty();
getProjectLabel(activeProject).appendTo(projectInfoLabel);
projectInfo.show();
treeList.treeList('data',newFlowData);
}
function build() {
var container = $("<div>", {class:"red-ui-info-outline"}).css({'height': '100%'});
var toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(container);
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.search">').appendTo(toolbar).searchBox({
style: "compact",
delay: 500,
change: function() {
var val = $(this).val();
var searchResults = RED.search.search(val);
if (val) {
activeSearch = val;
var resultMap = {};
for (var i=0,l=searchResults.length;i<l;i++) {
resultMap[searchResults[i].node.id] = true;
}
var c = treeList.treeList('filter',function(item) {
if (item.depth === 0) {
return true;
}
return item.id && objects[item.id] && resultMap[item.id]
},true)
} else {
activeSearch = null;
treeList.treeList('filter',null);
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected.id);
}
}
},
options: [
{label:RED._("sidebar.info.search.configNodes"), value:"is:config"},
{label:RED._("sidebar.info.search.unusedConfigNodes"), value:"is:config is:unused"},
{label:RED._("sidebar.info.search.invalidNodes"), value: "is:invalid"},
{label:RED._("sidebar.info.search.uknownNodes"), value: "type:unknown"},
{label:RED._("sidebar.info.search.unusedSubflows"), value:"is:subflow is:unused"},
]
});
projectInfo = $('<div class="red-ui-treeList-label red-ui-info-outline-project"><span class="red-ui-treeList-icon"><i class="fa fa-archive"></i></span></div>').hide().appendTo(container)
projectInfoLabel = $('<span>').appendTo(projectInfo);
// <div class="red-ui-info-outline-item red-ui-info-outline-item-flow" style=";"><div class="red-ui-search-result-description red-ui-info-outline-item-label">Space Monkey</div><div class="red-ui-info-outline-item-controls"><button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;"><i class="fa fa-ellipsis-h"></i></button></div></div></div>').appendTo(container)
treeList = $("<div>").css({width: "100%"}).appendTo(container).treeList({
data:getFlowData()
})
treeList.on('treelistselect', function(e,item) {
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id);
if (node) {
if (node.type === 'group' || node._def.category !== "config") {
RED.view.select({nodes:[node]})
} else {
RED.view.select({nodes:[]})
}
}
})
treeList.on('treelistconfirm', function(e,item) {
var node = RED.nodes.node(item.id);
if (node) {
if (node._def.category === "config") {
RED.editor.editConfig("", node.type, node.id);
} else {
RED.editor.edit(node);
}
}
})
RED.events.on("projects:load", onProjectLoad)
RED.events.on("flows:add", onFlowAdd)
RED.events.on("flows:remove", onObjectRemove)
RED.events.on("flows:change", onFlowChange)
RED.events.on("flows:reorder", onFlowsReorder)
RED.events.on("subflows:add", onSubflowAdd)
RED.events.on("subflows:remove", onObjectRemove)
RED.events.on("subflows:change", onSubflowChange)
RED.events.on("nodes:add",onNodeAdd);
RED.events.on("nodes:remove",onObjectRemove);
RED.events.on("nodes:change",onNodeChange);
RED.events.on("groups:add",onNodeAdd);
RED.events.on("groups:remove",onObjectRemove);
RED.events.on("groups:change",onNodeChange);
RED.events.on("workspace:clear", onWorkspaceClear)
return container;
}
function onWorkspaceClear() {
treeList.treeList('data',getFlowData());
}
function onFlowAdd(ws) {
objects[ws.id] = {
id: ws.id,
element: getFlowLabel(ws),
children:[],
deferBuild: true,
icon: "red-ui-icons red-ui-icons-flow",
gutter: getGutter(ws)
}
if (missingParents[ws.id]) {
objects[ws.id].children = missingParents[ws.id];
delete missingParents[ws.id]
} else {
objects[ws.id].children.push(getEmptyItem(ws.id));
}
flowList.treeList.addChild(objects[ws.id])
objects[ws.id].element.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
updateSearch();
}
function onFlowChange(n) {
var existingObject = objects[n.id];
var label = n.label || n.id;
var newlineIndex = label.indexOf("\\n");
if (newlineIndex > -1) {
label = label.substring(0,newlineIndex)+"...";
}
existingObject.element.find(".red-ui-info-outline-item-label").text(label);
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
existingObject.treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
updateSearch();
}
function onFlowsReorder(order) {
var indexMap = {};
order.forEach(function(id,index) {
indexMap[id] = index;
})
flowList.treeList.sortChildren(function(A,B) {
if (A.id === "__global__") { return -1 }
if (B.id === "__global__") { return 1 }
return indexMap[A.id] - indexMap[B.id]
})
}
function onSubflowAdd(sf) {
objects[sf.id] = {
id: sf.id,
element: getNodeLabel(sf),
children:[],
deferBuild: true,
gutter: getGutter(sf)
}
if (missingParents[sf.id]) {
objects[sf.id].children = missingParents[sf.id];
delete missingParents[sf.id]
} else {
objects[sf.id].children.push(getEmptyItem(sf.id));
}
if (empties["__subflow__"]) {
empties["__subflow__"].treeList.remove();
delete empties["__subflow__"];
}
subflowList.treeList.addChild(objects[sf.id])
updateSearch();
}
function onSubflowChange(sf) {
var existingObject = objects[sf.id];
existingObject.treeList.replaceElement(getNodeLabel(sf));
// existingObject.element.find(".red-ui-info-outline-item-label").text(n.name || n.id);
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+sf.id) {
var sfInstance = objects[n.id];
sfInstance.treeList.replaceElement(getNodeLabel(n));
}
});
updateSearch();
}
function onNodeChange(n) {
var existingObject = objects[n.id];
var parent = n.g||n.z||"__global__";
var nodeLabelText = getNodeLabelText(n);
if (nodeLabelText) {
existingObject.element.find(".red-ui-info-outline-item-label").text(nodeLabelText);
} else {
existingObject.element.find(".red-ui-info-outline-item-label").html("&nbsp;");
}
var existingParent = existingObject.parent.id;
if (!existingParent) {
existingParent = existingObject.parent.parent.flow
}
if (parent !== existingParent) {
var parentItem = existingObject.parent;
existingObject.treeList.remove(true);
if (parentItem.children.length === 0) {
if (parentItem.config) {
// this is a config
parentItem.treeList.remove();
// console.log("Removing",n.type,"from",parentItem.parent.id||parentItem.parent.parent.id)
delete configNodeTypes[parentItem.parent.id||parentItem.parent.parent.id].types[n.type];
if (parentItem.parent.children.length === 0) {
if (parentItem.parent.id === "__global__") {
parentItem.parent.treeList.addChild(getEmptyItem(parentItem.parent.id));
} else {
delete configNodeTypes[parentItem.parent.parent.id];
parentItem.parent.treeList.remove();
if (parentItem.parent.parent.children.length === 0) {
parentItem.parent.parent.treeList.addChild(getEmptyItem(parentItem.parent.parent.id));
}
}
}
} else {
parentItem.treeList.addChild(getEmptyItem(parentItem.id));
}
}
if (n._def.category === 'config' && n.type !== 'group') {
// This must be a config node that has been rescoped
createFlowConfigNode(parent,n.type);
configNodeTypes[parent].types[n.type].treeList.addChild(objects[n.id]);
} else {
// This is a node that has moved groups
if (empties[parent]) {
empties[parent].treeList.remove();
delete empties[parent];
}
objects[parent].treeList.addChild(existingObject)
}
// if (parent === "__global__") {
// // Global always exists here
// if (!configNodeTypes[parent][n.type]) {
// configNodeTypes[parent][n.type] = {
// config: true,
// label: n.type,
// children: []
// }
// globalConfigNodes.treeList.addChild(configNodeTypes[parent][n.type])
// }
// configNodeTypes[parent][n.type].treeList.addChild(existingObject);
// } else {
// if (empties[parent]) {
// empties[parent].treeList.remove();
// delete empties[parent];
// }
// objects[parent].treeList.addChild(existingObject)
// }
}
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
if (n._def.category === "config" && n.type !== 'group') {
existingObject.element.find(".red-ui-info-outline-item-control-users").text(n.users.length);
}
updateSearch();
}
function onObjectRemove(n) {
var existingObject = objects[n.id];
existingObject.treeList.remove();
delete objects[n.id]
// If this is a group being removed, it may have an empty item
if (empties[n.id]) {
delete empties[n.id];
}
var parent = existingObject.parent;
if (parent.children.length === 0) {
if (parent.config) {
// this is a config
parent.treeList.remove();
delete configNodeTypes[parent.parent.id||n.z].types[n.type];
if (parent.parent.children.length === 0) {
if (parent.parent.id === "__global__") {
parent.parent.treeList.addChild(getEmptyItem(parent.parent.id));
} else {
delete configNodeTypes[n.z];
parent.parent.treeList.remove();
if (parent.parent.parent.children.length === 0) {
parent.parent.parent.treeList.addChild(getEmptyItem(parent.parent.parent.id));
}
}
}
} else {
parent.treeList.addChild(getEmptyItem(parent.id));
}
}
}
function getGutter(n) {
var span = $("<span>",{class:"red-ui-info-outline-gutter"});
var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.view.reveal(n.id);
})
RED.popover.tooltip(revealButton,RED._("sidebar.info.find"));
return span;
}
function createFlowConfigNode(parent,type) {
// console.log("createFlowConfig",parent,type,configNodeTypes[parent]);
if (empties[parent]) {
empties[parent].treeList.remove();
delete empties[parent];
}
if (!configNodeTypes[parent]) {
// There is no 'config nodes' item in the parent flow
configNodeTypes[parent] = {
config: true,
flow: parent,
types: {},
label: RED._("menu.label.displayConfig"),
children: []
}
objects[parent].treeList.insertChildAt(configNodeTypes[parent],0);
// console.log("CREATED", parent)
}
if (!configNodeTypes[parent].types[type]) {
configNodeTypes[parent].types[type] = {
config: true,
label: type,
children: []
}
configNodeTypes[parent].treeList.addChild(configNodeTypes[parent].types[type]);
// console.log("CREATED", parent,type)
}
}
function onNodeAdd(n) {
objects[n.id] = {
id: n.id,
element: getNodeLabel(n),
gutter: getGutter(n)
}
if (n.type === "group") {
objects[n.id].children = [];
objects[n.id].deferBuild = true;
if (missingParents[n.id]) {
objects[n.id].children = missingParents[n.id];
delete missingParents[n.id]
}
}
var parent = n.g||n.z||"__global__";
if (n._def.category !== "config" || n.type === 'group') {
if (objects[parent]) {
if (empties[parent]) {
empties[parent].treeList.remove();
delete empties[parent];
}
if (objects[parent].treeList) {
objects[parent].treeList.addChild(objects[n.id]);
} else {
objects[parent].children.push(objects[n.id])
}
} else {
missingParents[parent] = missingParents[parent]||[];
missingParents[parent].push(objects[n.id])
}
} else {
createFlowConfigNode(parent,n.type);
configNodeTypes[parent].types[n.type].treeList.addChild(objects[n.id]);
}
objects[n.id].element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
updateSearch();
}
var updateSearchTimer;
function updateSearch() {
if (updateSearchTimer) {
clearTimeout(updateSearchTimer)
}
if (activeSearch) {
updateSearchTimer = setTimeout(function() {
searchInput.searchBox("change");
},100);
}
}
function onSelectionChanged(selection) {
// treeList.treeList('clearSelection');
}
return {
build: build,
search: function(val) {
searchInput.searchBox('value',val)
},
select: function(node) {
if (node) {
if (Array.isArray(node)) {
treeList.treeList('select', node.map(function(n) { return objects[n.id] }), false)
} else {
treeList.treeList('select', objects[node.id], false)
}
} else {
treeList.treeList('clearSelection')
}
},
reveal: function(node) {
treeList.treeList('show', objects[node.id])
}
}
})();

View File

@@ -15,33 +15,28 @@
**/
RED.sidebar.info = (function() {
marked.setOptions({
renderer: new marked.Renderer(),
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: true,
smartLists: true,
smartypants: false
});
var content;
var panels;
var sections;
var propertiesSection;
var infoSection;
var propertiesPanelContent;
var propertiesPanelHeader;
var propertiesPanelHeaderIcon;
var propertiesPanelHeaderLabel;
var propertiesPanelHeaderReveal;
var propertiesPanelHeaderHelp;
var selectedObject;
var tipContainer;
var helpSection;
var tipBox;
// TODO: remove this
var expandedSections = {
"property": false
};
function resizeStack() {
if (panels) {
var h = $(content).parent().height() - tipContainer.outerHeight();
panels.resize(h)
}
}
function init() {
content = document.createElement("div");
@@ -51,81 +46,31 @@ RED.sidebar.info = (function() {
var stackContainer = $("<div>",{class:"red-ui-sidebar-info-stack"}).appendTo(content);
var outlinerPanel = $("<div>").css({
"overflow": "hidden",
"height": "calc(70%)"
}).appendTo(stackContainer);
var propertiesPanel = $("<div>").css({
"overflow":"hidden",
"height":"100%",
"display": "flex",
"flex-direction": "column"
}).appendTo(stackContainer);
propertiesPanelHeader = $("<div>", {class:"red-ui-palette-header red-ui-info-header"}).css({
"flex":"0 0 auto"
}).appendTo(propertiesPanel);
sections = RED.stack.create({
container: stackContainer
}).hide();
propertiesPanelHeaderIcon = $("<span>").appendTo(propertiesPanelHeader);
propertiesPanelHeaderLabel = $("<span>").appendTo(propertiesPanelHeader);
propertiesPanelHeaderHelp = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
position: 'absolute',
top: '12px',
right: '32px'
}).on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (selectedObject) {
RED.sidebar.help.show(selectedObject.type);
}
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp"));
propertiesPanelHeaderReveal = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
position: 'absolute',
top: '12px',
right: '8px'
}).on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (selectedObject) {
RED.sidebar.info.outliner.reveal(selectedObject);
RED.view.reveal(selectedObject.id);
}
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderReveal,RED._("sidebar.help.showInOutline"));
propertiesPanelContent = $("<div>").css({
"flex":"1 1 auto",
"overflow-y":"scroll",
}).appendTo(propertiesPanel);
panels = RED.panels.create({container: stackContainer})
panels.ratio(0.6);
RED.sidebar.info.outliner.build().appendTo(outlinerPanel);
RED.sidebar.addTab({
id: "info",
label: RED._("sidebar.info.label"),
name: RED._("sidebar.info.name"),
iconClass: "fa fa-info",
action:"core:show-info-tab",
content: content,
pinned: true,
enableOnEdit: true
propertiesSection = sections.add({
title: RED._("sidebar.info.info"),
collapsible: true
});
propertiesSection.expand();
RED.events.on("sidebar:resize", resizeStack);
infoSection = sections.add({
title: RED._("sidebar.info.desc"),
collapsible: true
});
infoSection.expand();
infoSection.content.css("padding","6px");
$(window).on("resize", resizeStack);
$(window).on("focus", resizeStack);
helpSection = sections.add({
title: RED._("sidebar.info.nodeHelp"),
collapsible: true
});
helpSection.expand();
helpSection.content.css("padding","6px");
// Tip Box
tipContainer = $('<div class="red-ui-help-tips"></div>').appendTo(content);
var tipContainer = $('<div class="red-ui-help-tips"></div>').appendTo(content);
tipBox = $('<div class="red-ui-help-tip"></div>').appendTo(tipContainer);
var tipButtons = $('<div class="red-ui-help-tips-buttons"></div>').appendTo(tipContainer);
@@ -141,6 +86,17 @@ RED.sidebar.info = (function() {
RED.actions.invoke("core:toggle-show-tips");
RED.notify(RED._("sidebar.info.showTips"));
});
RED.sidebar.addTab({
id: "info",
label: RED._("sidebar.info.label"),
name: RED._("sidebar.info.name"),
iconClass: "fa fa-info",
action:"core:show-info-tab",
content: content,
pinned: true,
enableOnEdit: true
});
if (tips.enabled()) {
tips.start();
} else {
@@ -168,36 +124,46 @@ RED.sidebar.info = (function() {
refreshSelection();
return;
}
$(propertiesPanelContent).empty();
sections.show();
$(propertiesSection.content).empty();
$(infoSection.content).empty();
$(helpSection.content).empty();
infoSection.title.text(RED._("sidebar.info.desc"));
var propRow;
var table = $('<table class="red-ui-info-table"></table>').appendTo(propertiesPanelContent);
var table = $('<table class="red-ui-info-table"></table>').appendTo(propertiesSection.content);
var tableBody = $('<tbody>').appendTo(table);
var subflowNode;
var subflowUserCount;
var activeProject = RED.projects.getActiveProject();
if (activeProject) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+ RED._("sidebar.project.name") + '</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).text(activeProject.name||"");
$('<tr class="red-ui-help-property-expand blank"><td colspan="2"></td></tr>').appendTo(tableBody);
var editProjectButton = $('<button class="red-ui-button red-ui-button-small" style="position:absolute;right:2px;"><i class="fa fa-ellipsis-h"></i></button>')
.appendTo(propRow.children()[1])
.on("click", function(evt) {
evt.preventDefault();
RED.projects.editProject();
});
RED.popover.tooltip(editProjectButton,RED._('sidebar.project.showProjectSettings'));
}
propertiesSection.container.show();
infoSection.container.show();
helpSection.container.show();
if (node === null) {
RED.sidebar.info.outliner.select(null);
return;
} else if (Array.isArray(node)) {
// Multiple things selected
// - hide help and info sections
RED.sidebar.info.outliner.select(node);
propertiesPanelHeaderIcon.empty();
RED.utils.createNodeIcon({type:"_selection_"}).appendTo(propertiesPanelHeaderIcon);
propertiesPanelHeaderLabel.text("Selection");
propertiesPanelHeaderReveal.hide();
propertiesPanelHeaderHelp.hide();
selectedObject = null;
var types = {
nodes:0,
flows:0,
subflows:0,
groups: 0
subflows:0
}
node.forEach(function(n) {
if (n.type === 'tab') {
@@ -205,13 +171,12 @@ RED.sidebar.info = (function() {
types.nodes += RED.nodes.filterNodes({z:n.id}).length;
} else if (n.type === 'subflow') {
types.subflows++;
} else if (n.type === 'group') {
types.groups++;
} else {
types.nodes++;
}
});
// infoSection.container.hide();
helpSection.container.hide();
infoSection.container.hide();
// - show the count of selected nodes
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.selection")+"</td><td></td></tr>").appendTo(tableBody);
@@ -225,96 +190,53 @@ RED.sidebar.info = (function() {
if (types.nodes > 0) {
$('<div>').text(RED._("clipboard.node",{count:types.nodes})).appendTo(counts);
}
if (types.groups > 0) {
$('<div>').text(RED._("clipboard.group",{count:types.groups})).appendTo(counts);
}
} else {
// A single 'thing' selected.
RED.sidebar.info.outliner.select(node);
// Check to see if this is a subflow or subflow instance
var subflowRegex = /^subflow(:(.+))?$/.exec(node.type);
if (subflowRegex) {
if (subflowRegex[2]) {
subflowNode = RED.nodes.subflow(subflowRegex[2]);
var m = /^subflow(:(.+))?$/.exec(node.type);
if (m) {
if (m[2]) {
subflowNode = RED.nodes.subflow(m[2]);
} else {
subflowNode = node;
}
subflowUserCount = 0;
var subflowType = "subflow:"+subflowNode.id;
subflowUserCount = subflowNode.instances.length;
}
propertiesPanelHeaderIcon.empty();
RED.utils.createNodeIcon(node).appendTo(propertiesPanelHeaderIcon);
var objectLabel = RED.utils.getNodeLabel(node, node.type+": "+node.id)
var newlineIndex = objectLabel.indexOf("\\n");
if (newlineIndex > -1) {
objectLabel = objectLabel.substring(0,newlineIndex)+"...";
}
propertiesPanelHeaderLabel.text(objectLabel);
propertiesPanelHeaderReveal.show();
selectedObject = node;
propRow = $('<tr class="red-ui-help-info-row"><td></td><td></td></tr>').appendTo(tableBody);
var objectType = "node";
if (node.type === "subflow" || subflowRegex) {
objectType = "subflow";
} else if (node.type === "tab") {
objectType = "flow";
}else if (node.type === "group") {
objectType = "group";
}
$(propRow.children()[0]).text(RED._("sidebar.info."+objectType))
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
if (node.type === "tab" || node.type === "subflow") {
// If nothing is selected, but we're on a flow or subflow tab.
propertiesPanelHeaderHelp.hide();
} else if (node.type === "group") {
propertiesPanelHeaderHelp.hide();
propRow = $('<tr class="red-ui-help-info-row"><td>&nbsp;</td><td></td></tr>').appendTo(tableBody);
var typeCounts = {
nodes:0,
groups: 0
}
var allNodes = RED.group.getNodes(node,true);
allNodes.forEach(function(n) {
if (n.type === "group") {
typeCounts.groups++;
} else {
typeCounts.nodes++
RED.nodes.eachNode(function(n) {
if (n.type === subflowType) {
subflowUserCount++;
}
});
var counts = $('<div>').appendTo($(propRow.children()[1]));
if (typeCounts.nodes > 0) {
$('<div>').text(RED._("clipboard.node",{count:typeCounts.nodes})).appendTo(counts);
}
if (node.type === "tab" || node.type === "subflow") {
// If nothing is selected, but we're on a flow or subflow tab.
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info."+(node.type==='tab'?'flow':'subflow'))+'</td><td></td></tr>').appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.tabName")+"</td><td></td></tr>").appendTo(tableBody);
$(propRow.children()[1]).text(node.label||node.name||"");
if (node.type === "tab") {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).text((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
}
if (typeCounts.groups > 0) {
$('<div>').text(RED._("clipboard.group",{count:typeCounts.groups})).appendTo(counts);
}
} else {
propertiesPanelHeaderHelp.show();
if (!subflowRegex) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+'</td><td></td></tr>').appendTo(tableBody);
// An actual node is selected in the editor - build up its properties table
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
if (node.type !== "subflow" && node.type !== "unknown" && node.name) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody);
$('<span class="red-ui-text-bidi-aware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]);
}
if (!m) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+"</td><td></td></tr>").appendTo(tableBody);
$(propRow.children()[1]).text((node.type === "unknown")?node._orig.type:node.type);
if (node.type === "unknown") {
$('<span style="float: right; font-size: 0.8em"><i class="fa fa-warning"></i></span>').prependTo($(propRow.children()[1]))
}
}
var count = 0;
if (!subflowRegex && node.type != "subflow" && node.type != "group") {
var blankRow = $('<tr class="red-ui-help-property-expand blank"><td colspan="2"></td></tr>').appendTo(tableBody);
if (!m && node.type != "subflow") {
var defaults;
if (node.type === 'unknown') {
defaults = {};
@@ -329,6 +251,7 @@ RED.sidebar.info = (function() {
$(propRow.children()[1]).text(RED.nodes.getType(node.type).set.module);
count++;
}
$('<tr class="red-ui-help-property-expand red-ui-help-info-property-row blank'+(expandedSections.property?"":" hide")+'"><td colspan="2"></td></tr>').appendTo(tableBody);
if (defaults) {
for (var n in defaults) {
@@ -336,8 +259,7 @@ RED.sidebar.info = (function() {
var val = node[n];
var type = typeof val;
count++;
propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td></td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[0]).text(n);
propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td>'+n+"</td><td></td></tr>").appendTo(tableBody);
if (defaults[n].type) {
var configNode = RED.nodes.node(val);
if (!configNode) {
@@ -367,66 +289,49 @@ RED.sidebar.info = (function() {
}
}
if (count > 0) {
$('<a href="#" class="node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="red-ui-help-property-more">'+RED._("sidebar.info.showMore")+'</span><span class="red-ui-help-property-less">'+RED._("sidebar.info.showLess")+'</span> <i class="fa fa-caret-down"></i></a>').appendTo(blankRow.children()[0]);
$('<tr class="red-ui-help-property-expand blank"><td colspan="2"><a href="#" class="node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="red-ui-help-property-more">'+RED._("sidebar.info.showMore")+'</span><span class="red-ui-help-property-less">'+RED._("sidebar.info.showLess")+'</span> <i class="fa fa-caret-down"></i></a></td></tr>').appendTo(tableBody);
}
}
if (node.type !== 'tab') {
if (subflowRegex) {
if (m) {
$('<tr class="blank"><th colspan="2">'+RED._("sidebar.info.subflow")+'</th></tr>').appendTo(tableBody);
$('<tr class="node-info-subflow-row"><td>'+RED._("common.label.name")+'</td><td><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+RED.utils.sanitize(subflowNode.name)+'</span></td></tr>').appendTo(tableBody);
}
}
}
if (subflowRegex) {
if (m) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("subflow.category")+'</td><td></td></tr>').appendTo(tableBody);
var category = subflowNode.category||"subflows";
$(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category}))
$('<tr class="node-info-subflow-row"><td>'+RED._("sidebar.info.instances")+"</td><td>"+subflowUserCount+'</td></tr>').appendTo(tableBody);
}
// var helpText = "";
// if (node.type === "tab" || node.type === "subflow") {
// } else {
// if (subflowNode && node.type !== "subflow") {
// // Selected a subflow instance node.
// // - The subflow template info goes into help
// helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
// } else {
// helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
// }
// setInfoText(helpText, helpSection.content);
// }
var helpText = "";
if (node.type === "tab" || node.type === "subflow") {
$(helpSection.container).hide();
} else {
$(helpSection.container).show();
if (subflowNode && node.type !== "subflow") {
// Selected a subflow instance node.
// - The subflow template info goes into help
helpText = (marked(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
} else {
helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
}
setInfoText(helpText, helpSection.content);
}
var infoText = "";
if (node._def && node._def.info) {
var info = node._def.info;
var textInfo = (typeof info === "function" ? info.call(node) : info);
infoText = infoText + RED.utils.renderMarkdown(textInfo);
infoText = infoText + marked(textInfo);
}
if (node.info) {
infoText = infoText + RED.utils.renderMarkdown(node.info || "")
infoText = infoText + marked(node.info || "")
}
var infoSectionContainer = $("<div>").css("padding","0 6px 6px").appendTo(propertiesPanelContent)
// var editInfo = $('<button class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-file-text-o"></button>').appendTo(infoSectionContainer).on("click", function(evt) {
// //.text(RED._("sidebar.info.editDescription"))
// evt.preventDefault();
// evt.stopPropagation();
// if (node.type === 'tab') {
//
// } else if (node.type === 'subflow') {
//
// } else if (node.type === 'group') {
//
// } else if (node._def.category !== 'config') {
// RED.editor.edit(node,"editor-tab-description");
// } else {
//
// }
// })
setInfoText(infoText, infoSectionContainer);
setInfoText(infoText, infoSection.content);
$(".red-ui-sidebar-info-stack").scrollTop(0);
$(".node-info-property-header").on("click", function(e) {
@@ -442,7 +347,7 @@ RED.sidebar.info = (function() {
// propRow = $('<tr class="red-ui-help-info-row"><td>Actions</td><td></td></tr>').appendTo(tableBody);
// var actionBar = $(propRow.children()[1]);
//
// // var actionBar = $('<div>',{style:"background: #fefefe; padding: 3px;"}).appendTo(propertiesPanel);
// // var actionBar = $('<div>',{style:"background: #fefefe; padding: 3px;"}).appendTo(propertiesSection.content);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
@@ -517,7 +422,6 @@ RED.sidebar.info = (function() {
}
function startTips() {
$(".red-ui-sidebar-info").addClass('show-tips');
resizeStack();
if (enabled) {
if (!startTimeout && !refreshTimeout) {
if (tipCount === -1) {
@@ -531,7 +435,6 @@ RED.sidebar.info = (function() {
}
function stopTips() {
$(".red-ui-sidebar-info").removeClass('show-tips');
resizeStack();
clearInterval(refreshTimeout);
clearTimeout(startTimeout);
refreshTimeout = null;
@@ -556,8 +459,15 @@ RED.sidebar.info = (function() {
}
function set(html,title) {
console.warn("Deprecated use of RED.sidebar.info.set - use RED.sidebar.help.set instead")
RED.sidebar.help.set(html,title);
// tips.stop();
// sections.show();
refresh(null);
propertiesSection.container.hide();
helpSection.container.hide();
infoSection.container.show();
infoSection.title.text(title||RED._("sidebar.info.desc"));
setInfoText(html,infoSection.content);
$(".red-ui-sidebar-info-stack").scrollTop(0);
}
function refreshSelection(selection) {

View File

@@ -112,14 +112,14 @@ RED.touch.radialMenu = (function() {
if (!opt.disabled) {
if (p[0]>opt.x-30 && p[0]<opt.x+30 && p[1]>opt.y-30 && p[1]<opt.y+30) {
if (opt !== activeOption) {
opt.el.classed("selected",true);
opt.el.style("background","#999");
activeOption = opt;
}
} else if (opt === activeOption) {
opt.el.style("background","#fff");
activeOption = null;
} else {
if (opt === activeOption) {
activeOption = null;
}
opt.el.classed("selected",false);
opt.el.style("background","#fff");
}
}
}

View File

@@ -241,13 +241,10 @@ RED.typeSearch = (function() {
$(document).off('mousedown.red-ui-type-search');
$(document).off('mouseup.red-ui-type-search');
$(document).off('click.red-ui-type-search');
$(document).off('touchstart.red-ui-type-search');
$(document).off('mousedown.red-ui-type-search');
setTimeout(function() {
$(document).on('mousedown.red-ui-type-search',handleMouseActivity);
$(document).on('mouseup.red-ui-type-search',handleMouseActivity);
$(document).on('click.red-ui-type-search',handleMouseActivity);
$(document).on('touchstart.red-ui-type-search',handleMouseActivity);
},200);
refreshTypeList(opts);
@@ -263,9 +260,7 @@ RED.typeSearch = (function() {
searchResultsDiv.slideDown(300);
setTimeout(function() {
searchResultsDiv.find(".red-ui-editableList-container").scrollTop(0);
if (!opts.disableFocus) {
searchInput.trigger("focus");
}
searchInput.trigger("focus");
},100);
}
function hide(fast) {
@@ -284,7 +279,6 @@ RED.typeSearch = (function() {
$(document).off('mousedown.red-ui-type-search');
$(document).off('mouseup.red-ui-type-search');
$(document).off('click.red-ui-type-search');
$(document).off('touchstart.red-ui-type-search');
}
}
function getTypeLabel(type, def) {
@@ -390,7 +384,17 @@ RED.typeSearch = (function() {
return {
show: show,
refresh: refreshTypeList,
refresh: function(opts) {
if (opts.x && opts.y) {
if ($("#red-ui-main-container").height() - opts.y - 150 < 0) {
opts.y = opts.y - 235;
}
dialog.css({left:opts.x+"px",top:opts.y+"px"}).show();
}
if (opts.filter) {
refreshTypeList(opts);
}
},
hide: hide
};

View File

@@ -133,7 +133,8 @@ RED.userSettings = (function() {
{
title: "menu.label.other",
options: [
{setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"}
{setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"},
{setting:"view-flow-vertical",label:"menu.label.view.flowVertical",toggle:true,default:false,onchange:RED.view.vertical}
]
}
];

View File

@@ -16,28 +16,6 @@
RED.utils = (function() {
window._marked = window.marked;
window.marked = function(txt) {
console.warn("Use of 'marked()' is deprecated. Use RED.utils.renderMarkdown() instead");
return renderMarkdown(txt);
}
_marked.setOptions({
renderer: new _marked.Renderer(),
gfm: true,
tables: true,
breaks: false,
pedantic: false,
smartLists: true,
smartypants: false
});
function renderMarkdown(txt) {
var rendered = _marked(txt);
var cleaned = DOMPurify.sanitize(rendered, {SAFE_FOR_JQUERY: true})
return cleaned;
}
function formatString(str) {
return str.replace(/\r?\n/g,"&crarr;").replace(/\t/g,"&rarr;");
}
@@ -806,9 +784,9 @@ RED.utils = (function() {
function separateIconPath(icon) {
var result = {module: "", file: ""};
if (icon) {
var index = icon.indexOf(RED.settings.apiRootUrl+'icons/');
if (index === 0) {
icon = icon.substring((RED.settings.apiRootUrl+'icons/').length);
var index = icon.indexOf('icons/');
if (index !== -1) {
icon = icon.substring(index+6);
}
index = icon.indexOf('/');
if (index !== -1) {
@@ -859,15 +837,10 @@ RED.utils = (function() {
}
function getNodeIcon(def,node) {
if (node && node.type === '_selection_') {
return "font-awesome/fa-object-ungroup";
} else if (node && node.type === 'group') {
return "font-awesome/fa-object-group"
} else if (def.category === 'config') {
if (def.category === 'config') {
return RED.settings.apiRootUrl+"icons/node-red/cog.svg"
} else if (node && node.type === 'tab') {
return "red-ui-icons/red-ui-icons-flow"
// return RED.settings.apiRootUrl+"images/subflow_tab.svg"
return RED.settings.apiRootUrl+"icons/node-red/subflow.svg"
} else if (node && node.type === 'unknown') {
return RED.settings.apiRootUrl+"icons/node-red/alert.svg"
} else if (node && node.icon) {
@@ -926,8 +899,6 @@ RED.utils = (function() {
var l;
if (node.type === 'tab') {
l = node.label || defaultLabel
} else if (node.type === 'group') {
l = node.name || defaultLabel
} else {
l = node._def.label;
try {
@@ -1061,63 +1032,11 @@ RED.utils = (function() {
}
// If the specified name is not defined in font-awesome, show arrow-in icon.
iconUrl = RED.settings.apiRootUrl+"icons/node-red/arrow-in.svg"
} else if (iconPath.module === "red-ui-icons") {
var redIconElement = $('<i/>').appendTo(iconContainer);
redIconElement.addClass("red-ui-palette-icon red-ui-icons " + iconPath.file);
return;
}
var imageIconElement = $('<div/>',{class:"red-ui-palette-icon"}).appendTo(iconContainer);
imageIconElement.css("backgroundImage", "url("+iconUrl+")");
}
function createNodeIcon(node) {
var def = node._def;
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"})
if (node.type === "_selection_") {
nodeDiv.addClass("red-ui-palette-icon-selection");
} else if (node.type === "group") {
nodeDiv.addClass("red-ui-palette-icon-group");
} else if (node.type === 'tab') {
nodeDiv.addClass("red-ui-palette-icon-flow");
} else {
var colour = RED.utils.getNodeColor(node.type,def);
// if (node.type === 'tab') {
// colour = "#C0DEED";
// }
nodeDiv.css('backgroundColor',colour);
var borderColor = getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
}
var icon_url = RED.utils.getNodeIcon(def,node);
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
return nodeDiv;
}
function getDarkerColor(c) {
var r,g,b;
if (/^#[a-f0-9]{6}$/i.test(c)) {
r = parseInt(c.substring(1, 3), 16);
g = parseInt(c.substring(3, 5), 16);
b = parseInt(c.substring(5, 7), 16);
} else if (/^#[a-f0-9]{3}$/i.test(c)) {
r = parseInt(c.substring(1, 2)+c.substring(1, 2), 16);
g = parseInt(c.substring(2, 3)+c.substring(2, 3), 16);
b = parseInt(c.substring(3, 4)+c.substring(3, 4), 16);
} else {
return c;
}
var l = 0.3 * r/255 + 0.59 * g/255 + 0.11 * b/255 ;
r = Math.max(0,r-50);
g = Math.max(0,g-50);
b = Math.max(0,b-50);
var s = ((r<<16) + (g<<8) + b).toString(16);
return '#'+'000000'.slice(0, 6-s.length)+s;
}
return {
createObjectElement: buildMessageElement,
getMessageProperty: getMessageProperty,
@@ -1134,9 +1053,6 @@ RED.utils = (function() {
decodeObject: decodeObject,
parseContextKey: parseContextKey,
createIconElement: createIconElement,
sanitize: sanitize,
renderMarkdown: renderMarkdown,
createNodeIcon: createNodeIcon,
getDarkerColor: getDarkerColor
sanitize: sanitize
}
})();

View File

@@ -67,16 +67,9 @@ RED.view.tools = (function() {
function moveSelection(dx,dy) {
if (moving_set === null) {
moving_set = [];
var selection = RED.view.selection();
if (selection.nodes) {
while (selection.nodes.length > 0) {
var n = selection.nodes.shift();
moving_set.push({n:n});
if (n.type === "group") {
selection.nodes = selection.nodes.concat(n.nodes);
}
}
moving_set = selection.nodes.map(function(n) { return {n:n}});
}
}
if (moving_set && moving_set.length > 0) {
@@ -100,15 +93,10 @@ RED.view.tools = (function() {
node.n.x += dx;
node.n.y += dy;
node.n.dirty = true;
if (node.n.type === "group") {
RED.group.markDirty(node.n);
minX = Math.min(node.n.x - 5,minX);
minY = Math.min(node.n.y - 5,minY);
} else {
minX = Math.min(node.n.x-node.n.w/2-5,minX);
minY = Math.min(node.n.y-node.n.h/2-5,minY);
}
minX = Math.min(node.n.x-node.n.w/2-5,minX);
minY = Math.min(node.n.y-node.n.h/2-5,minY);
}
if (minX !== 0 || minY !== 0) {
for (var n = 0; n<moving_set.length; n++) {
node = moving_set[n];
@@ -117,86 +105,13 @@ RED.view.tools = (function() {
}
}
RED.view.redraw();
} else {
RED.view.scroll(dx*10,dy*10);
}
}
function setSelectedNodeLabelState(labelShown) {
var selection = RED.view.selection();
var historyEvents = [];
var nodes = [];
if (selection.nodes) {
selection.nodes.forEach(function(n) {
if (n.type !== 'subflow' && n.type !== 'group') {
nodes.push(n);
} else if (n.type === 'group') {
nodes = nodes.concat( RED.group.getNodes(n,true));
}
});
}
nodes.forEach(function(n) {
var modified = false;
var oldValue = n.l === undefined?true:n.l;
var isLink = /^link (in|out)$/.test(n._def.type);
if (labelShown) {
if (n.l === false || (isLink && !n.hasOwnProperty('l'))) {
n.l = true;
modified = true;
}
} else {
if ((!isLink && (!n.hasOwnProperty('l') || n.l === true)) || (isLink && n.l === true) ) {
n.l = false;
modified = true;
}
}
if (modified) {
historyEvents.push({
t: "edit",
node: n,
changed: n.changed,
changes: {
l: oldValue
}
})
n.changed = true;
n.dirty = true;
n.resize = true;
}
})
if (historyEvents.length > 0) {
RED.history.push({
t: "multi",
events: historyEvents,
dirty: RED.nodes.dirty()
})
RED.nodes.dirty(true);
}
RED.view.redraw();
}
return {
init: function() {
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
RED.actions.add("core:hide-selected-node-labels", function() { setSelectedNodeLabelState(false); })
RED.actions.add("core:align-selection-to-grid", alignToGrid);
RED.actions.add("core:scroll-view-up", function() { RED.view.scroll(0,-RED.view.gridSize());});
RED.actions.add("core:scroll-view-right", function() { RED.view.scroll(RED.view.gridSize(),0);});
RED.actions.add("core:scroll-view-down", function() { RED.view.scroll(0,RED.view.gridSize());});
RED.actions.add("core:scroll-view-left", function() { RED.view.scroll(-RED.view.gridSize(),0);});
RED.actions.add("core:step-view-up", function() { RED.view.scroll(0,-5*RED.view.gridSize());});
RED.actions.add("core:step-view-right", function() { RED.view.scroll(5*RED.view.gridSize(),0);});
RED.actions.add("core:step-view-down", function() { RED.view.scroll(0,5*RED.view.gridSize());});
RED.actions.add("core:step-view-left", function() { RED.view.scroll(-5*RED.view.gridSize(),0);});
RED.actions.add("core:move-selection-up", function() { moveSelection(0,-1);});
RED.actions.add("core:move-selection-right", function() { moveSelection(1,0);});
RED.actions.add("core:move-selection-down", function() { moveSelection(0,1);});

3337
packages/node_modules/@node-red/editor-client/src/js/ui/view.js vendored Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -128,6 +128,10 @@ RED.workspaces = (function() {
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.sidebar.config.refresh();
var selection = RED.view.selection();
if (!selection.nodes && !selection.links) {
RED.sidebar.info.refresh(workspace);
}
if (changes.hasOwnProperty('disabled')) {
RED.nodes.eachNode(function(n) {
if (n.z === workspace.id) {
@@ -136,7 +140,6 @@ RED.workspaces = (function() {
});
RED.view.redraw();
}
RED.events.emit("flows:change",workspace);
}
RED.tray.close();
}
@@ -161,7 +164,7 @@ RED.workspaces = (function() {
var dialogForm = $('<form id="dialog-form" class="form-horizontal"></form>').appendTo(trayBody);
$('<div class="form-row">'+
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
'<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">'+
'<input type="text" id="node-input-name">'+
'</div>').appendTo(dialogForm);
@@ -216,10 +219,7 @@ RED.workspaces = (function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
var selection = RED.view.selection();
if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
RED.sidebar.info.refresh(workspace);
}
RED.sidebar.info.refresh(workspace);
tabflowEditor.destroy();
}
}
@@ -371,9 +371,7 @@ RED.workspaces = (function() {
var changes = { disabled: workspace.disabled };
workspace.disabled = disabled;
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
if (id === activeWorkspace) {
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
}
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
var historyEvent = {
t: "edit",
changes:changes,
@@ -382,11 +380,10 @@ RED.workspaces = (function() {
}
workspace.changed = true;
RED.history.push(historyEvent);
RED.events.emit("flows:change",workspace);
RED.nodes.dirty(true);
RED.sidebar.config.refresh();
var selection = RED.view.selection();
if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
if (!selection.nodes && !selection.links) {
RED.sidebar.info.refresh(workspace);
}
if (changes.hasOwnProperty('disabled')) {
@@ -415,14 +412,9 @@ RED.workspaces = (function() {
}
function setWorkspaceOrder(order) {
var newOrder = order.filter(function(id) {
RED.nodes.setWorkspaceOrder(order.filter(function(id) {
return RED.nodes.workspace(id) !== undefined;
})
var currentOrder = RED.nodes.getWorkspaceOrder();
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
RED.nodes.setWorkspaceOrder(newOrder);
RED.events.emit("flows:reorder",newOrder);
}
}));
workspace_tabs.order(order);
}

View File

@@ -39,11 +39,7 @@ RED.user = (function() {
closeOnEscape: !!opts.cancelable,
width: 600,
resizable: false,
draggable: false,
close: function( event, ui ) {
$("#node-dialog-login").dialog('destroy').remove();
RED.keyboard.enable()
}
draggable: false
});
$("#node-dialog-login-fields").empty();
@@ -102,10 +98,10 @@ RED.user = (function() {
data: body
}).done(function(data,textStatus,xhr) {
RED.settings.set("auth-tokens",data);
$("#node-dialog-login").dialog('destroy').remove();
if (opts.updateMenu) {
updateUserMenu();
}
$("#node-dialog-login").dialog("close");
done();
}).fail(function(jqXHR,textStatus,errorThrown) {
RED.settings.remove("auth-tokens");
@@ -147,8 +143,7 @@ RED.user = (function() {
}
if (opts.cancelable) {
$("#node-dialog-login-cancel").button().on("click", function( event ) {
$("#node-dialog-login").dialog('close');
$("#node-dialog-login").dialog('destroy').remove();
});
}
@@ -157,7 +152,8 @@ RED.user = (function() {
$("#node-dialog-login-image").load(function() {
dialog.dialog("open");
}).attr("src",loginImageSrc);
RED.keyboard.disable();
}
});
}

View File

@@ -9,15 +9,19 @@
color: transparent !important;
}
}
.ace_gutter {
background: $text-editor-gutter-background;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.ace_scroller {
background: $text-editor-background;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.ace_scroller {
background: $text-editor-background;
color: $text-editor-color;
}
.ace_marker-layer .ace_active-line {
@@ -33,6 +37,9 @@
.ace_gutter-active-line {
background: $text-editor-gutter-active-line-background;
}
.ace_gutter {
background: $text-editor-gutter-background;
}
.ace_tooltip {
font-family: $primary-font;
line-height: 1.4em;
@@ -45,13 +52,6 @@
@include component-shadow;
border-color: $popover-background;
}
.ace_content {
line-height: 1;
}
textarea.ace_text-input {
overflow: hidden;
padding: 0px 1px !important;
}
#red-ui-event-log-editor {
.ace_scroller {

View File

@@ -67,9 +67,6 @@
text-decoration: none;
color: $primary-text-color;
}
a:focus {
outline: 1px solid $form-input-focus-color;
}
p {
margin: 0 0 10px;

View File

@@ -23,7 +23,7 @@ $primary-background: #f3f3f3;//#0ff;
$secondary-background: #fff;//#ff0;
$secondary-background-selected: #efefef;//#e9e900;
$secondary-background-inactive: #f0f0f0;//#f0f000;
$secondary-background-hover: #e6e6e6;//#dd0;
$secondary-background-hover: #ddd;//#dd0;
$secondary-background-disabled: #f9f9f9;//#fafa0;
$tertiary-background: #f7f7f7;//#f0f;
@@ -94,7 +94,7 @@ $list-item-secondary-color: $secondary-text-color;
$list-item-background: $secondary-background;
$list-item-background-disabled: $secondary-background-inactive;
$list-item-background-hover: $secondary-background-hover;
$list-item-background-selected: #ffebc7; // #fff1e5;
$list-item-background-selected: $secondary-background-selected;
$list-item-border-selected: $secondary-text-color-selected;
$tab-text-color-active: $header-text-color;
@@ -129,7 +129,7 @@ $workspace-button-color-primary: #eee;
$workspace-button-background-primary: #AD1625;
$workspace-button-background-primary-hover: #6E0A1E;
$workspace-button-color-focus-outline: $form-input-focus-color;
$workspace-button-color-focus-outline: $form-input-border-color;
$shade-color: rgba(160,160,160,0.5);
@@ -284,9 +284,3 @@ $debug-message-border: #eee;
$debug-message-border-hover: #999;
$debug-message-border-warning: #ffdf9d;
$debug-message-border-error: #f99;
$group-default-fill: none;
$group-default-fill-opacity: 1;
$group-default-stroke: #999;
$group-default-stroke-opacity: 1;
$group-default-label-color: #a4a4a4;

View File

@@ -160,7 +160,6 @@
.red-ui-debug-msg-element {
color: $debug-message-text-color;
line-height: 1.3em;
overflow-wrap: break-word;
}
.red-ui-debug-msg-object-key {
color: $debug-message-text-color-object-key;
@@ -217,10 +216,6 @@
.red-ui-debug-msg-type-number { color: $debug-message-text-color-msg-type-number; };
.red-ui-debug-msg-type-number-toggle { cursor: pointer;}
.red-ui-debug-msg-type-string {
white-space: pre-wrap;
}
.red-ui-debug-msg-row {
display: block;
padding: 4px 2px 2px;

View File

@@ -175,38 +175,3 @@
.red-ui-menu-dropdown-submenu.disabled > a:before {
border-right-color: $menuCaret;
}
// Menu NG
ul.red-ui-menu:not(.red-ui-menu-dropdown) {
font-family: $primary-font;
font-size: 12px;
list-style-type: none;
padding: 0;
margin: 0;
li a {
display: block;
padding: 4px 8px 4px 16px;
clear: both;
font-weight: normal;
line-height: 20px;
color: $menuColor;
white-space: nowrap;
text-decoration: none;
&:hover,&:focus {
color: $menuHoverColor;
text-decoration: none;
background-color: $menuHoverBackground;
border: none;
outline: none;
}
}
&.red-ui-menu-compact {
font-size: 12px;
li a {
line-height: 16px;
}
}
}

View File

@@ -304,6 +304,9 @@ button.red-ui-button-small
&:first-child {
padding: 20px 20px 0;
}
&:last-child {
padding-bottom: 20px;
}
}
}
.red-ui-editor-type-expression-tab-content {
@@ -408,133 +411,6 @@ button.red-ui-button.red-ui-editor-node-appearance-button {
}
}
.red-ui-group-layout-picker {
padding: 5px;
background: $secondary-background;
}
.red-ui-group-layout-picker-cell-text {
position: absolute;
width: 14px;
height: 2px;
border-top: 2px solid $secondary-text-color;
border-bottom: 2px solid $secondary-text-color;
margin: 2px;
&.red-ui-group-layout-text-pos-nw { top: 0; left: 0; }
&.red-ui-group-layout-text-pos-n { top: 0; left: calc(50% - 9px); }
&.red-ui-group-layout-text-pos-ne { top: 0; right: 0; }
&.red-ui-group-layout-text-pos-sw { bottom: 0; left: 0; }
&.red-ui-group-layout-text-pos-s { bottom: 0; left: calc(50% - 9px); }
&.red-ui-group-layout-text-pos-se { bottom: 0; right: 0; }
&.red-ui-group-layout-text-pos- {
width: 100%;
height: 100%;
border-radius: 5px;
margin: 0;
background-color: #FFF;
background-size: 100% 100%;
background-position: 0 0, 50% 50%;
background-image: linear-gradient(45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent),linear-gradient(-45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent);
border: none;
}
}
.red-ui-group-layout-picker button.red-ui-search-result-node {
float: none;
position: relative;
padding: 0;
margin: 5px;
width: 32px;
height: 27px;
}
button.red-ui-group-layout-picker-none {
width: 100%;
}
.red-ui-color-picker {
input[type="text"] {
border-radius:0;
width: 100%;
margin-bottom: 0;
border: none;
border-bottom: 1px solid $form-input-border-color;
}
small {
color: $secondary-text-color;
margin-left: 5px;
margin-right: 4px;
display: inline-block;
min-width: 35px;
text-align: right;
}
background: $primary-background;
}
.red-ui-editor-node-appearance-button {
.red-ui-search-result-node {
overflow: hidden
}
}
.red-ui-color-picker-cell {
padding: 0;
border-style: solid;
border-width: 1px;
border-color: $secondary-border-color;
}
.red-ui-color-picker-swatch {
position: absolute;
top:-1px;right:-1px;left:-1px;bottom:-1px;
border-radius: 4px;
}
.red-ui-color-picker-cell-none {
height: 100%;
background-color: #FFF;
background-size: 100% 100%;
background-position: 0 0, 50% 50%;
background-image: linear-gradient(45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent),linear-gradient(-45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent)
}
.red-ui-search-result-node .red-ui-color-picker-cell-none {
border-radius: 4px;
background-size: 50% 50%;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee), linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
}
.red-ui-color-picker-opacity-slider {
position:relative;
vertical-align: middle;
display: inline-block;
width: calc(100% - 50px);
height: 14px;
margin: 6px 3px 8px;
box-sizing: border-box;
background-color: white;
background-image:
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 25%),
linear-gradient(-45deg, #eee 25%, transparent 25%, transparent 75%, #eee 25%);
background-size: 6px 6px;
}
.red-ui-color-picker-opacity-slider-overlay {
position: absolute;
top:0;right:0;left:0;bottom:0;
background-image:linear-gradient(90deg, transparent 0%, #f00 100%);
background-size: 100% 100%;
border: 1px solid $primary-border-color;
}
div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle {
z-Index: 10;
top: -4px;
cursor: pointer;
min-width: 0;
width: 10px;
height: 22px;
padding: 0;
border: 1px solid $primary-border-color;
border-radius: 1px;
background: $secondary-background;
box-sizing: border-box;
}
.red-ui-icon-picker {
select {
box-sizing: border-box;
@@ -597,7 +473,6 @@ div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle {
padding: 4px;
color: $secondary-text-color;
font-size: 0.9em;
line-height: 24px;
}
button {
float: right;
@@ -716,9 +591,6 @@ div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle {
button.red-ui-toggleButton.toggle {
text-align: left;
i {
min-width: 15px;
}
}
@@ -761,7 +633,7 @@ button.red-ui-toggleButton.toggle {
.red-ui-typedInput-value-label,.red-ui-typedInput-option-label {
select,.placeholder-input {
margin: 3px;
height: 24px;
height: 26px;
width: calc(100% - 10px);
padding-left: 3px;
}
@@ -832,18 +704,8 @@ span.red-ui-editor-subflow-env-lang-icon {
right: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.red-ui-editor-subflow-env-input-type {
background: $secondary-background;
height: 100%;
box-sizing: border-box;
}
.red-ui-editor-subflow-env-input-type-placeholder {
color: $tertiary-text-color;
padding-left: 4px;
}
// .red-ui-editor-subflow-ui-grid {
// width: 100%;
// .red-ui-editableList-container {

View File

@@ -35,21 +35,13 @@
pointer-events: none;
-webkit-touch-callout: none;
@include disable-selection;
.red-ui-flow-node-label-text {
dominant-baseline: middle;
}
&.red-ui-flow-node-label-right .red-ui-flow-node-label-text {
text-anchor: end;
}
}
.red-ui-flow-port-label {
stroke-width: 0;
fill: $secondary-text-color;
font-size: 16px;
dominant-baseline: middle;
alignment-baseline: middle;
text-anchor: middle;
pointer-events: none;
-webkit-touch-callout: none;
@@ -79,54 +71,6 @@
}
}
.red-ui-flow-group {
&.red-ui-flow-group-hovered {
.red-ui-flow-group-outline-select {
stroke-opacity: 0.8 !important;
stroke-dasharray: 10 4 !important;
}
}
&.red-ui-flow-group-active-hovered:not(.red-ui-flow-group-hovered) {
.red-ui-flow-group-outline-select {
stroke: $link-link-color;
}
}
}
.red-ui-flow-group-outline {
fill: none;
stroke: $node-selected-color;
stroke-opacity: 0;
stroke-width: 12;
pointer-events: stroke;
}
.red-ui-flow-group-outline-select {
fill: none;
stroke: $node-selected-color;
pointer-events: stroke;
stroke-opacity: 0;
stroke-width: 3;
&.red-ui-flow-group-outline-select-background {
stroke: $view-background;
stroke-width: 6;
}
}
.red-ui-flow-group-body {
pointer-events: none;
fill: $group-default-fill;
fill-opacity: $group-default-fill-opacity;
stroke-width: 2;
stroke: $group-default-stroke;
stroke-opacity: $group-default-stroke-opacity;
}
.red-ui-flow-group-label {
@include disable-selection;
fill: $group-default-label-color;
}
.red-ui-flow-node-unknown {
stroke-dasharray:10,4;
stroke: $node-border-unknown;
@@ -159,15 +103,6 @@
.red-ui-flow-node-button {
fill: inherit;
&.red-ui-flow-node-button-disabled {
opacity: 0.4;
.red-ui-flow-node-button-button {
cursor: default;
}
}
}
.red-ui-flow-node-button-button {
cursor: pointer;
}
.red-ui-flow-node-button-background {
fill: $node-background-placeholder;
@@ -210,8 +145,8 @@ g.red-ui-flow-node-selected {
border-color: $node-selected-color !important;
border-style: dashed !important;
stroke: $node-selected-color;
stroke-width: 3;
stroke-dasharray: 8, 4;
stroke-width: 2;
stroke-dasharray: 8, 3;
}
.red-ui-flow-subflow .red-ui-flow-node {
@@ -231,9 +166,6 @@ g.red-ui-flow-node-selected {
fill-opacity: 1;
stroke-dasharray: none;
}
.red-ui-flow-group, .red-ui-flow-group-body {
stroke-dasharray: 8, 3;
}
}
.red-ui-flow-node-disabled {
&.red-ui-flow-node, .red-ui-flow-node {
@@ -316,7 +248,6 @@ g.red-ui-flow-node-selected {
.red-ui-flow-link-outline {
stroke: $view-background;
stroke-opacity: 0.4;
stroke-width: 5;
cursor: crosshair;
fill: none;
@@ -342,10 +273,7 @@ g.red-ui-flow-link-unknown path.red-ui-flow-link-line {
stroke-dasharray: 10, 4;
}
// @keyframes *must* be on multiple lines so build-custom-theme can filter them out
@keyframes red-ui-flow-port-tooltip-fadeIn {
from { opacity:0; } to { opacity:1; }
}
@keyframes red-ui-flow-port-tooltip-fadeIn { from { opacity:0; } to { opacity:1; } }
.red-ui-flow-port-tooltip {
opacity:0;

View File

@@ -37,7 +37,7 @@
border-radius: 4px;
font-family: $monospace-font !important;
font-size: 13px !important;
height: 100%;
height: 300px;
line-height: 1.3em;
padding: 6px 10px;
background: $clipboard-textarea-background;
@@ -62,7 +62,6 @@
background: $form-input-background;
&>div {
height: 100%;
box-sizing: border-box;
}
}
.red-ui-clipboard-dialog-box {

View File

@@ -71,9 +71,38 @@
}
.red-ui-notification-shake-horizontal {
animation: red-ui-notification-shake-horizontal 0.3s steps(2, end) both;
-webkit-animation: red-ui-notification-shake-horizontal 0.3s steps(2, end) both;
animation: red-ui-notification-shake-horizontal 0.3s steps(2, end) both;
}
@-webkit-keyframes red-ui-notification-shake-horizontal {
0%,
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
10%,
30%,
50%,
70% {
-webkit-transform: translateX(-1px);
transform: translateX(-1px);
}
20%,
40%,
60% {
-webkit-transform: translateX(1px);
transform: translateX(1px);
}
// 80% {
// -webkit-transform: translateX(1px);
// transform: translateX(1px);
// }
// 90% {
// -webkit-transform: translateX(-1px);
// transform: translateX(-1px);
// }
}
// @keyframes *must* be on multiple lines so build-custom-theme can filter them out
@keyframes red-ui-notification-shake-horizontal {
0%,
100% {
@@ -93,4 +122,12 @@
-webkit-transform: translateX(1px);
transform: translateX(1px);
}
// 80% {
// -webkit-transform: translateX(1px);
// transform: translateX(1px);
// }
// 90% {
// -webkit-transform: translateX(-1px);
// transform: translateX(-1px);
// }
}

View File

@@ -186,25 +186,10 @@
background-size: contain;
background-repeat: no-repeat;
}
.red-ui-search-result-node {
&.red-ui-palette-icon-flow,
&.red-ui-palette-icon-group,
&.red-ui-palette-icon-selection {
background: none;
border-color: transparent;
.red-ui-palette-icon-container {
background: none;
}
.red-ui-palette-icon-fa {
color: $secondary-text-color;
font-size: 18px;
}
}
}
.red-ui-palette-icon-fa {
color: white;
position: absolute;
top: calc(50% - 7px);
top: 7px;
left: 3px;
}
.red-ui-palette-node-small {

View File

@@ -22,19 +22,9 @@
// border: 1px solid red;
box-sizing: border-box;
}
display: flex;
flex-direction: column;
>.red-ui-panel:first-child {
flex: 0 0 auto;
}
>.red-ui-panel:last-child {
flex: 1 1 auto;
}
}
.red-ui-panels-separator {
flex: 0 0 auto;
border-top: 1px solid $secondary-border-color;
border-bottom: 1px solid $secondary-border-color;
height: 7px;
@@ -47,13 +37,10 @@
.red-ui-panel {
overflow: auto;
height: calc(50% - 4px);
position: relative;
}
.red-ui-panels.red-ui-panels-horizontal {
height: 100%;
flex-direction: row;
&>.red-ui-panel {
vertical-align: top;
display: inline-block;

View File

@@ -150,16 +150,6 @@
.red-ui-popover a.red-ui-button,
.red-ui-popover button.red-ui-button {
&:not(.primary) {
border-color: $popover-button-border-color;
background: $popover-background;
color: $popover-color !important;
}
&:not(.primary):not(.disabled):not(.ui-button-disabled):hover {
border-color: $popover-button-border-color-hover;
}
&.primary {
border-color: $popover-button-border-color;
}

View File

@@ -18,12 +18,7 @@
.red-ui-editableList-container {
padding: 0px;
}
padding: 0;
.red-ui-projects-dialog-box {
box-sizing: border-box;
overflow-y: auto;
padding: 25px 25px 10px 25px;
}
}
#red-ui-project-settings-tab-settings {
overflow-y: scroll;
@@ -104,7 +99,6 @@
.red-ui-projects-dialog-screen-create {
min-height: 500px;
button.red-ui-projects-dialog-screen-create-type {
position: relative;
height: auto;
padding: 10px;
}
@@ -175,14 +169,9 @@
.red-ui-projects-dialog-project-list-container {
border: 1px solid $secondary-border-color;
border-radius: 2px;
display: flex;
flex-direction: column;
.red-ui-search-container {
flex-grow: 0;
}
}
.red-ui-projects-dialog-project-list-inner-container {
flex-grow: 1 ;
height: 300px;
overflow-y: scroll;
position:relative;
.red-ui-editableList-border {
@@ -265,29 +254,6 @@
}
}
}
.red-ui-projects-dialog-project-list-entry-delete-confirm {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 100%;
width: 1000px;
overflow: hidden;
padding: 5px 20px;
background: $secondary-background;
transition: left 0.4s;
white-space: nowrap;
> span {
line-height: 40px;
}
button {
margin-left: 20px;
}
}
.red-ui-projects-dialog-screen-create-type {
position: relative;
}
.red-ui-projects-dialog-screen-create-type.red-ui-button.toggle.selected:not(.disabled):not(:disabled) {
color: $secondary-text-color-active !important;
}

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