Compare commits

..

1 Commits

Author SHA1 Message Date
Dave Conway-Jones
499d22daca Add start script to default project package 2018-04-05 11:30:16 +01:00
1081 changed files with 40427 additions and 95081 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
/packages/node_modules/** linguist-generated=false

View File

@@ -8,9 +8,7 @@ If your issue is:
- a feature request or suggestion for a change,
- or problems with 3rd party (`node-red-contrib-`) nodes
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
please use the [mailing list](https://groups.google.com/forum/#!forum/node-red), [slack team](https://nodered.org/slack) or ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
That way the whole Node-RED user community can help, rather than rely on the core development team.
@@ -28,7 +26,7 @@ To help us understand the issue, please fill-in as much of the following informa
### Please tell us about your environment:
- [ ] Node-RED version:
- [ ] Node.js version:
- [ ] node.js version:
- [ ] npm version:
- [ ] Platform/OS:
- [ ] Browser:

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ Put an `x` in the boxes that apply
<!--
If you want to raise a pull-request with a new feature, or a refactoring
of existing code, it **may well get rejected** if it hasn't been discussed on
the [forum](https://discourse.nodered.org) or
the [mailing list](https://groups.google.com/forum/#!forum/node-red) or
[slack team](https://nodered.org/slack) first.
-->
@@ -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

6
.gitignore vendored
View File

@@ -17,9 +17,3 @@ node_modules
public
locales/zz-ZZ
nodes/core/locales/zz-ZZ
!packages/node_modules
packages/node_modules/@node-red/editor-client/public
!test/**/node_modules
docs
!packages/node_modules/**/docs
.vscode

View File

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

7
.npmignore Normal file
View File

@@ -0,0 +1,7 @@
.settings
.jshintignore
.jshintrc
.project
.tern-project
.travis.yml
.git

View File

@@ -1,11 +1,20 @@
sudo: false
language: node_js
matrix:
include:
- 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
before_script:
- npm install -g istanbul coveralls
- node_js: "8"
env:
- CXX="g++-4.8"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
- gcc-4.8
node_js:
- "8"
- "6"
- "4"
script:
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage
before_script:
- npm install -g istanbul
- npm install coveralls

15
API.md
View File

@@ -1,15 +0,0 @@
Node-RED Modules
---
Node-RED provides a set of node modules that implement different parts of the
application.
Module | Description
-------|-------
[node-red](node-red.html) | the main module that pulls together all of the internal modules and provides the executable version of Node-RED
[@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API
[@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED
[@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules
@node-red/registry | the internal node registry
@node-red/nodes | the default set of core nodes
@node-red/editor-client | the client-side resources of the Node-RED editor application

File diff suppressed because it is too large Load Diff

View File

@@ -26,17 +26,17 @@ relevant nodes, press Ctrl-E and copy the flow data from the Export dialog.
At a minimum, please include:
- Version of Node-RED - either release number if you downloaded a zip, or the first few lines of `git log` if you are cloning the repository directly.
- Version of Node.js - what does `node -v` say?
- Version of node.js - what does `node -v` say?
## Feature requests
For feature requests, please raise them on the [forum](https://discourse.nodered.org).
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
## Pull-Requests
If you want to raise a pull-request with a new feature, or a refactoring
of existing code, it may well get rejected if you haven't discussed it on
the [forum](https://discourse.nodered.org) first.
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
All contributors need to sign the JS Foundation's Contributor License Agreement.
It is an online process and quick to do. You can read the details of the agreement

View File

@@ -15,8 +15,6 @@
**/
var path = require("path");
var fs = require("fs-extra");
var sass = require("node-sass");
module.exports = function(grunt) {
@@ -26,14 +24,6 @@ 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;
}
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
paths: {
@@ -48,7 +38,7 @@ module.exports = function(grunt) {
reporter: 'spec'
},
all: { src: ['test/**/*_spec.js'] },
core: { src: ["test/_spec.js","test/unit/**/*_spec.js"]},
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]}
},
webdriver: {
@@ -63,11 +53,10 @@ module.exports = function(grunt) {
ignoreLeaks: false,
ui: 'bdd',
reportFormats: ['lcov','html'],
print: 'both',
istanbulOptions: ['--no-default-excludes', '-i','**/packages/node_modules/**']
print: 'both'
},
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
all: { src: ['test/**/*_spec.js'] },
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]}
},
jshint: {
@@ -84,20 +73,22 @@ 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',
'red/**/*.js',
'nodes/core/*/*.js',
'editor/js/**/*.js'
],
core: {
files: {
src: [
'Gruntfile.js',
'red.js',
'red/**/*.js'
]
}
},
nodes: {
files: {
src: [ 'nodes/core/*/*.js' ]
@@ -105,7 +96,7 @@ module.exports = function(grunt) {
},
editor: {
files: {
src: [ 'packages/node_modules/@node-red/editor-client/src/js/**/*.js' ]
src: [ 'editor/js/**/*.js' ]
}
},
tests: {
@@ -125,92 +116,78 @@ module.exports = function(grunt) {
src: [
// Ensure editor source files are concatenated in
// the right order
"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",
"packages/node_modules/@node-red/editor-client/src/js/i18n.js",
"packages/node_modules/@node-red/editor-client/src/js/settings.js",
"packages/node_modules/@node-red/editor-client/src/js/user.js",
"packages/node_modules/@node-red/editor-client/src/js/comms.js",
"packages/node_modules/@node-red/editor-client/src/js/text/bidi.js",
"packages/node_modules/@node-red/editor-client/src/js/text/format.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/state.js",
"packages/node_modules/@node-red/editor-client/src/js/nodes.js",
"packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
"packages/node_modules/@node-red/editor-client/src/js/history.js",
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/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",
"packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/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-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",
"packages/node_modules/@node-red/editor-client/src/js/ui/editor.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tray.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/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",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js"
"editor/js/red.js",
"editor/js/events.js",
"editor/js/i18n.js",
"editor/js/settings.js",
"editor/js/user.js",
"editor/js/comms.js",
"editor/js/text/bidi.js",
"editor/js/text/format.js",
"editor/js/ui/state.js",
"editor/js/nodes.js",
"editor/js/history.js",
"editor/js/validators.js",
"editor/js/ui/utils.js",
"editor/js/ui/common/editableList.js",
"editor/js/ui/common/checkboxSet.js",
"editor/js/ui/common/menu.js",
"editor/js/ui/common/panels.js",
"editor/js/ui/common/popover.js",
"editor/js/ui/common/searchBox.js",
"editor/js/ui/common/tabs.js",
"editor/js/ui/common/stack.js",
"editor/js/ui/common/typedInput.js",
"editor/js/ui/actions.js",
"editor/js/ui/deploy.js",
"editor/js/ui/diff.js",
"editor/js/ui/keyboard.js",
"editor/js/ui/workspaces.js",
"editor/js/ui/view.js",
"editor/js/ui/sidebar.js",
"editor/js/ui/palette.js",
"editor/js/ui/tab-info.js",
"editor/js/ui/tab-config.js",
"editor/js/ui/palette-editor.js",
"editor/js/ui/editor.js",
"editor/js/ui/tray.js",
"editor/js/ui/clipboard.js",
"editor/js/ui/library.js",
"editor/js/ui/notifications.js",
"editor/js/ui/search.js",
"editor/js/ui/typeSearch.js",
"editor/js/ui/subflow.js",
"editor/js/ui/userSettings.js",
"editor/js/ui/projects/projects.js",
"editor/js/ui/projects/projectSettings.js",
"editor/js/ui/projects/projectUserSettings.js",
"editor/js/ui/projects/tab-versionControl.js",
"editor/js/ui/touch/radialMenu.js"
],
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
dest: "public/red/red.js"
},
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.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/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",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js",
"public/vendor/vendor.js": [
"editor/vendor/jquery/js/jquery-1.11.3.min.js",
"editor/vendor/bootstrap/js/bootstrap.min.js",
"editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
"editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"editor/vendor/marked/marked.min.js",
"editor/vendor/d3/d3.v3.min.js",
"editor/vendor/i18next/i18next.min.js"
],
// "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
// // TODO: resolve relative resource paths in
// // bootstrap/FA/jquery
// ],
"packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
"public/vendor/vendor.css": [
// TODO: resolve relative resource paths in
// bootstrap/FA/jquery
],
"public/vendor/jsonata/jsonata.min.js": [
"node_modules/jsonata/jsonata-es5.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
"editor/vendor/jsonata/formatter.js"
],
"public/vendor/ace/worker-jsonata.js": [
"node_modules/jsonata/jsonata-es5.min.js",
"editor/vendor/jsonata/worker-jsonata.js"
]
}
}
@@ -218,60 +195,63 @@ module.exports = function(grunt) {
uglify: {
build: {
files: {
'packages/node_modules/@node-red/editor-client/public/red/red.min.js': 'packages/node_modules/@node-red/editor-client/public/red/red.js',
'packages/node_modules/@node-red/editor-client/public/red/main.min.js': 'packages/node_modules/@node-red/editor-client/public/red/main.js',
'packages/node_modules/@node-red/editor-client/public/vendor/ace/mode-jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/mode-jsonata.js',
'packages/node_modules/@node-red/editor-client/public/vendor/ace/snippets/jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/snippets-jsonata.js'
'public/red/red.min.js': 'public/red/red.js',
'public/red/main.min.js': 'public/red/main.js',
'public/vendor/ace/mode-jsonata.js': 'editor/vendor/jsonata/mode-jsonata.js',
'public/vendor/ace/snippets/jsonata.js': 'editor/vendor/jsonata/snippets-jsonata.js'
}
}
},
sass: {
build: {
options: {
implementation: sass,
outputStyle: 'compressed'
},
files: [{
dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css',
src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss'
dest: 'public/red/style.min.css',
src: 'editor/sass/style.scss'
},
{
dest: 'public/vendor/bootstrap/css/bootstrap.min.css',
src: 'editor/vendor/bootstrap/css/bootstrap.css'
}]
}
},
jsonlint: {
messages: {
src: [
'packages/node_modules/@node-red/nodes/locales/**/*.json',
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
'packages/node_modules/@node-red/runtime/locales/**/*.json'
'nodes/core/locales/en-US/messages.json',
'red/api/locales/en-US/editor.json',
'red/runtime/locales/en-US/runtime.json'
]
},
keymaps: {
src: [
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
'editor/js/keymap.json'
]
}
},
attachCopyright: {
js: {
src: [
'packages/node_modules/@node-red/editor-client/public/red/red.min.js',
'packages/node_modules/@node-red/editor-client/public/red/main.min.js'
'public/red/red.min.js',
'public/red/main.min.js'
]
},
css: {
src: [
'packages/node_modules/@node-red/editor-client/public/red/style.min.css'
'public/red/style.min.css'
]
}
},
clean: {
build: {
src: [
"packages/node_modules/@node-red/editor-client/public/red",
"packages/node_modules/@node-red/editor-client/public/index.html",
"packages/node_modules/@node-red/editor-client/public/favicon.ico",
"packages/node_modules/@node-red/editor-client/public/icons",
"packages/node_modules/@node-red/editor-client/public/vendor"
"public/red",
"public/index.html",
"public/favicon.ico",
"public/icons",
"public/vendor"
]
},
release: {
@@ -283,27 +263,27 @@ module.exports = function(grunt) {
watch: {
js: {
files: [
'packages/node_modules/@node-red/editor-client/src/js/**/*.js'
'editor/js/**/*.js'
],
tasks: ['copy:build','concat',/*'uglify',*/ 'attachCopyright:js']
tasks: ['copy:build','concat','uglify','attachCopyright:js']
},
sass: {
files: [
'packages/node_modules/@node-red/editor-client/src/sass/**/*.scss'
'editor/sass/**/*.scss'
],
tasks: ['sass','attachCopyright:css']
},
json: {
files: [
'packages/node_modules/@node-red/nodes/locales/**/*.json',
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
'packages/node_modules/@node-red/runtime/locales/**/*.json'
'nodes/core/locales/en-US/messages.json',
'red/api/locales/en-US/editor.json',
'red/runtime/locales/en-US/runtime.json'
],
tasks: ['jsonlint:messages']
},
keymaps: {
files: [
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
'editor/js/keymap.json'
],
tasks: ['jsonlint:keymaps','copy:build']
},
@@ -318,13 +298,12 @@ module.exports = function(grunt) {
nodemon: {
/* uses .nodemonignore */
dev: {
script: 'packages/node_modules/node-red/red.js',
script: 'red.js',
options: {
args: nodemonArgs,
ext: 'js,html,json',
watch: [
'packages/node_modules',
'!packages/node_modules/@node-red/editor-client'
'red','nodes'
]
}
}
@@ -343,56 +322,69 @@ module.exports = function(grunt) {
build: {
files:[
{
src: 'packages/node_modules/@node-red/editor-client/src/js/main.js',
dest: 'packages/node_modules/@node-red/editor-client/public/red/main.js'
src: 'editor/js/main.js',
dest: 'public/red/main.js'
},
{
src: 'packages/node_modules/@node-red/editor-client/src/js/keymap.json',
dest: 'packages/node_modules/@node-red/editor-client/public/red/keymap.json'
src: 'editor/js/keymap.json',
dest: 'public/red/keymap.json'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/images',
cwd: 'editor/images',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/red/images/'
dest: 'public/red/images/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/vendor',
cwd: 'editor/vendor',
src: [
'ace/**',
'jquery/css/base/**',
//'bootstrap/css/**',
'bootstrap/img/**',
'jquery/css/**',
'font-awesome/**'
],
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/'
dest: 'public/vendor/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/icons',
cwd: 'editor/icons',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/icons/'
dest: 'public/icons/'
},
{
expand: true,
src: ['packages/node_modules/@node-red/editor-client/src/index.html','packages/node_modules/@node-red/editor-client/src/favicon.ico'],
dest: 'packages/node_modules/@node-red/editor-client/public/',
src: ['editor/index.html','editor/favicon.ico'],
dest: 'public/',
flatten: true
},
{
src: 'CHANGELOG.md',
dest: 'packages/node_modules/@node-red/editor-client/public/red/about'
},
{
src: 'CHANGELOG.md',
dest: 'packages/node_modules/node-red/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/ace/bin/',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/'
dest: 'public/red/about'
}
]
},
release: {
files: [{
mode: true,
expand: true,
src: [
'*.md',
'LICENSE',
'package.json',
'settings.js',
'red.js',
'lib/.gitignore',
'nodes/*.demo',
'nodes/core/**',
'red/**',
'public/**',
'editor/templates/**',
'bin/**'
],
dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>')
}]
}
},
chmod: {
@@ -401,92 +393,19 @@ module.exports = function(grunt) {
},
release: {
src: [
"packages/node_modules/@node-red/nodes/core/hardware/nrgpio",
"packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/node-red-*sh"
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*'),
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/red/runtime/storage/localfilesystem/projects/git/node-red-*sh')
]
}
},
'npm-command': {
options: {
cmd: "pack",
cwd: "<%= paths.dist %>/modules"
},
'node-red': { options: { args: [__dirname+'/packages/node_modules/node-red'] } },
'@node-red/editor-api': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-api'] } },
'@node-red/editor-client': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-client'] } },
'@node-red/nodes': { options: { args: [__dirname+'/packages/node_modules/@node-red/nodes'] } },
'@node-red/registry': { options: { args: [__dirname+'/packages/node_modules/@node-red/registry'] } },
'@node-red/runtime': { options: { args: [__dirname+'/packages/node_modules/@node-red/runtime'] } },
'@node-red/util': { options: { args: [__dirname+'/packages/node_modules/@node-red/util'] } }
},
mkdir: {
release: {
options: {
create: ['<%= paths.dist %>/modules']
},
},
},
compress: {
release: {
options: {
archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip'
},
expand: true,
cwd: 'packages/node_modules/',
src: [
'**',
'!@node-red/editor-client/src/**'
]
}
},
jsdoc : {
modules: {
src: [
'API.md',
'packages/node_modules/node-red/lib/red.js',
'packages/node_modules/@node-red/runtime/lib/index.js',
'packages/node_modules/@node-red/runtime/lib/api/*.js',
'packages/node_modules/@node-red/runtime/lib/events.js',
'packages/node_modules/@node-red/util/**/*.js',
'packages/node_modules/@node-red/editor-api/lib/index.js',
'packages/node_modules/@node-red/editor-api/lib/auth/index.js'
],
options: {
destination: 'docs',
configure: './jsdoc.json'
}
},
_editor: {
src: [
'packages/node_modules/@node-red/editor-client/src/js'
],
options: {
destination: 'packages/node_modules/@node-red/editor-client/docs',
configure: './jsdoc.json'
}
}
},
jsdoc2md: {
runtimeAPI: {
options: {
separators: true
},
src: [
'packages/node_modules/@node-red/runtime/lib/index.js',
'packages/node_modules/@node-red/runtime/lib/api/*.js',
'packages/node_modules/@node-red/runtime/lib/events.js'
],
dest: 'packages/node_modules/@node-red/runtime/docs/api.md'
},
nodeREDUtil: {
options: {
separators: true
},
src: 'packages/node_modules/@node-red/util/**/*.js',
dest: 'packages/node_modules/@node-red/util/docs/api.md'
cwd: '<%= paths.dist %>/',
src: ['node-red-<%= pkg.version %>/**']
}
}
});
@@ -505,13 +424,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-chmod');
grunt.loadNpmTasks('grunt-jsonlint');
grunt.loadNpmTasks('grunt-mocha-istanbul');
if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.loadNpmTasks('grunt-webdriver');
}
grunt.loadNpmTasks('grunt-jsdoc');
grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
grunt.loadNpmTasks('grunt-npm-command');
grunt.loadNpmTasks('grunt-mkdir');
grunt.loadNpmTasks('grunt-webdriver');
grunt.registerMultiTask('attachCopyright', function() {
var files = this.data.src;
@@ -553,38 +466,6 @@ module.exports = function(grunt) {
}
});
grunt.registerTask('verifyPackageDependencies', function() {
var done = this.async();
var verifyDependencies = require("./scripts/verify-package-dependencies.js");
verifyDependencies().then(function(failures) {
if (failures.length > 0) {
failures.forEach(f => grunt.log.error(f));
grunt.fail.fatal("Failed to verify package dependencies");
}
done();
});
});
grunt.registerTask('verifyUiTestDependencies', function() {
if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.fail.fatal('You need to install the UI test dependencies first.\nUse the script in "scripts/install-ui-test-dependencies.sh"');
return false;
}
});
grunt.registerTask('generatePublishScript',
'Generates a script to publish build output to npm',
function () {
const done = this.async();
const generatePublishScript = require("./scripts/generate-publish-script.js");
generatePublishScript().then(function(output) {
grunt.log.writeln(output);
const filePath = path.join(grunt.config.get('paths.dist'),"modules","publish.sh");
grunt.file.write(filePath,output);
done();
});
});
grunt.registerTask('setDevEnv',
'Sets NODE_ENV=development so non-minified assets are used',
function () {
@@ -593,7 +474,7 @@ module.exports = function(grunt) {
grunt.registerTask('default',
'Builds editor content then runs code style checks and unit tests on all components',
['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']);
['build','test-core','test-editor','test-nodes']);
grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code',
@@ -603,15 +484,9 @@ module.exports = function(grunt) {
'Runs code style check on editor code',
['jshint:editor']);
if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.registerTask('test-ui',
'Builds editor content then runs unit tests on editor ui',
['verifyUiTestDependencies']);
} else {
grunt.registerTask('test-ui',
'Builds editor content then runs unit tests on editor ui',
['verifyUiTestDependencies','build','jshint:editor','webdriver:all']);
}
grunt.registerTask('test-ui',
'Builds editor content then runs unit tests on editor ui',
['build','jshint:editor','webdriver:all']);
grunt.registerTask('test-nodes',
'Runs unit tests on core nodes',
@@ -627,18 +502,9 @@ module.exports = function(grunt) {
grunt.registerTask('release',
'Create distribution zip file',
['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules','generatePublishScript']);
grunt.registerTask('pack-modules',
'Create module pack files for release',
['mkdir:release','npm-command']);
['build','clean:release','copy:release','chmod:release','compress:release']);
grunt.registerTask('coverage',
'Run Istanbul code test coverage task',
['build','mocha_istanbul:all']);
grunt.registerTask('docs',
'Generates API documentation',
['jsdoc']);
};

View File

@@ -2,12 +2,12 @@
http://nodered.org
[![Build Status](https://travis-ci.org/node-red/node-red.svg?branch=master)](https://travis-ci.org/node-red/node-red)
[![Build Status](https://travis-ci.org/node-red/node-red.svg)](https://travis-ci.org/node-red/node-red)
[![Coverage Status](https://coveralls.io/repos/node-red/node-red/badge.svg?branch=master)](https://coveralls.io/r/node-red/node-red?branch=master)
Low-code programming for event-driven applications.
A visual tool for wiring the Internet of Things.
![Node-RED: Low-code programming for event-driven applications](http://nodered.org/images/node-red-screenshot.png)
![Node-RED: A visual tool for wiring the Internet of Things](http://nodered.org/images/node-red-screenshot.png)
## Quick Start
@@ -22,7 +22,8 @@ started.
More documentation can be found [here](http://nodered.org/docs).
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
For further help, or general discussion, please use the
[mailing list](https://groups.google.com/forum/#!forum/node-red).
## Developers
@@ -44,6 +45,9 @@ If you want to run the latest code from git, here's how to get started:
4. Run
npm start
or
node red.js
## Contributing
@@ -56,7 +60,7 @@ This project adheres to the [Contributor Covenant 1.4](http://contributor-covena
## Authors
Node-RED is a project of the [OpenJS Foundation](https://openjsf.org).
Node-RED is a project of the [JS Foundation](http://js.foundation).
It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
@@ -67,4 +71,4 @@ It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-t
## Copyright and license
Copyright JS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE).
Copyright JS Foundation and other contributors, http://js.foundation under [the Apache 2.0 license](LICENSE).

View File

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

View File

@@ -31,7 +31,7 @@ done
# Find the real location of this script
CURRENT_PATH=`pwd`
SCRIPT_PATH="${BASH_SOURCE[0]}";
while [ -h "${SCRIPT_PATH}" ]; do
while([ -h "${SCRIPT_PATH}" ]); do
cd "`dirname "${SCRIPT_PATH}"`"
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
done

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

BIN
editor/icons/alert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

View File

Before

Width:  |  Height:  |  Size: 603 B

After

Width:  |  Height:  |  Size: 603 B

View File

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 393 B

BIN
editor/icons/batch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

BIN
editor/icons/bridge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

BIN
editor/icons/cog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

BIN
editor/icons/comment.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
editor/icons/db.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

BIN
editor/icons/debug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

BIN
editor/icons/envelope.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

BIN
editor/icons/feed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

BIN
editor/icons/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

BIN
editor/icons/function.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

BIN
editor/icons/hash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

BIN
editor/icons/inject.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

BIN
editor/icons/join.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
editor/icons/light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

BIN
editor/icons/link-out.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

View File

Before

Width:  |  Height:  |  Size: 414 B

After

Width:  |  Height:  |  Size: 414 B

View File

Before

Width:  |  Height:  |  Size: 671 B

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

BIN
editor/icons/node-error.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

BIN
editor/icons/parser-csv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

BIN
editor/icons/parser-xml.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

BIN
editor/icons/range.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

View File

Before

Width:  |  Height:  |  Size: 736 B

After

Width:  |  Height:  |  Size: 736 B

BIN
editor/icons/rpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

BIN
editor/icons/serial.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

BIN
editor/icons/sort.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

BIN
editor/icons/split.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

BIN
editor/icons/subflow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

BIN
editor/icons/swap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

BIN
editor/icons/switch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

BIN
editor/icons/template.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

BIN
editor/icons/timer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

BIN
editor/icons/trigger.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

BIN
editor/icons/twitter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

BIN
editor/icons/watch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

View File

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 192 B

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
editor/images/node-red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

View File

@@ -28,24 +28,14 @@ RED.comms = (function() {
function connectWS() {
active = true;
var wspath;
if (RED.settings.apiRootUrl) {
var m = /^(https?):\/\/(.*)$/.exec(RED.settings.apiRootUrl);
if (m) {
console.log(m);
wspath = "ws"+(m[1]==="https"?"s":"")+"://"+m[2]+"comms";
}
} else {
var path = location.hostname;
var port = location.port;
if (port.length !== 0) {
path = path+":"+port;
}
path = path+document.location.pathname;
path = path+(path.slice(-1) == "/"?"":"/")+"comms";
wspath = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
var path = location.hostname;
var port = location.port;
if (port.length !== 0) {
path = path+":"+port;
}
path = path+document.location.pathname;
path = path+(path.slice(-1) == "/"?"":"/")+"comms";
path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
var auth_tokens = RED.settings.get("auth-tokens");
pendingAuth = (auth_tokens!=null);
@@ -58,7 +48,7 @@ RED.comms = (function() {
}
}
ws = new WebSocket(wspath);
ws = new WebSocket(path);
ws.onopen = function() {
reconnectAttempts = 0;
if (errornotification) {
@@ -75,39 +65,29 @@ RED.comms = (function() {
}
ws.onmessage = function(event) {
var message = JSON.parse(event.data);
if (message.auth) {
if (pendingAuth) {
if (message.auth === "ok") {
for (var m = 0; m < message.length; m++) {
var msg = message[m];
if (pendingAuth && msg.auth) {
if (msg.auth === "ok") {
pendingAuth = false;
completeConnection();
} else if (message.auth === "fail") {
} else if (msg.auth === "fail") {
// anything else is an error...
active = false;
RED.user.login({updateMenu:true},function() {
connectWS();
})
}
} else if (message.auth === "fail") {
// Our current session has expired
active = false;
RED.user.login({updateMenu:true},function() {
connectWS();
})
}
} else {
// Otherwise, 'message' is an array of actual comms messages
for (var m = 0; m < message.length; m++) {
var msg = message[m];
if (msg.topic) {
for (var t in subscriptions) {
if (subscriptions.hasOwnProperty(t)) {
var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
if (re.test(msg.topic)) {
var subscribers = subscriptions[t];
if (subscribers) {
for (var i=0;i<subscribers.length;i++) {
subscribers[i](msg.topic,msg.data);
}
else if (msg.topic) {
for (var t in subscriptions) {
if (subscriptions.hasOwnProperty(t)) {
var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
if (re.test(msg.topic)) {
var subscribers = subscriptions[t];
if (subscribers) {
for (var i=0;i<subscribers.length;i++) {
subscribers[i](msg.topic,msg.data);
}
}
}
@@ -142,10 +122,10 @@ RED.comms = (function() {
connectWS();
} else {
var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>';
errornotification.update(msg,{silent:true});
$(errornotification).find("a").on("click", function(e) {
errornotification.update(msg);
$(errornotification).find("a").click(function(e) {
e.preventDefault();
errornotification.update(RED._("notification.errors.lostConnection"),{silent:true});
errornotification.update(RED._("notification.errors.lostConnection"));
clearInterval(connectCountdownTimer);
connectWS();
})

332
editor/js/history.js Normal file
View File

@@ -0,0 +1,332 @@
/**
* 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.history = (function() {
var undo_history = [];
function undoEvent(ev) {
var i;
var len;
var node;
var subflow;
var modifiedTabs = {};
if (ev) {
if (ev.t == 'multi') {
len = ev.events.length;
for (i=len-1;i>=0;i--) {
undoEvent(ev.events[i]);
}
} else if (ev.t == 'replace') {
RED.nodes.clear();
var imported = RED.nodes.import(ev.config);
imported[0].forEach(function(n) {
if (ev.changed[n.id]) {
n.changed = true;
}
})
RED.nodes.version(ev.rev);
} else if (ev.t == 'add') {
if (ev.nodes) {
for (i=0;i<ev.nodes.length;i++) {
node = RED.nodes.node(ev.nodes[i]);
if (node.z) {
modifiedTabs[node.z] = true;
}
RED.nodes.remove(ev.nodes[i]);
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.removeLink(ev.links[i]);
}
}
if (ev.workspaces) {
for (i=0;i<ev.workspaces.length;i++) {
RED.nodes.removeWorkspace(ev.workspaces[i].id);
RED.workspaces.remove(ev.workspaces[i]);
}
}
if (ev.subflows) {
for (i=0;i<ev.subflows.length;i++) {
RED.nodes.removeSubflow(ev.subflows[i]);
RED.workspaces.remove(ev.subflows[i]);
}
}
if (ev.subflow) {
if (ev.subflow.instances) {
ev.subflow.instances.forEach(function(n) {
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
node.dirty = true;
}
});
}
if (ev.subflow.hasOwnProperty('changed')) {
subflow = RED.nodes.subflow(ev.subflow.id);
if (subflow) {
subflow.changed = ev.subflow.changed;
}
}
}
if (ev.removedLinks) {
for (i=0;i<ev.removedLinks.length;i++) {
RED.nodes.addLink(ev.removedLinks[i]);
}
}
} else if (ev.t == "delete") {
if (ev.workspaces) {
for (i=0;i<ev.workspaces.length;i++) {
RED.nodes.addWorkspace(ev.workspaces[i]);
RED.workspaces.add(ev.workspaces[i]);
}
}
if (ev.subflow && ev.subflow.subflow) {
RED.nodes.addSubflow(ev.subflow.subflow);
}
if (ev.subflowInputs && ev.subflowInputs.length > 0) {
subflow = RED.nodes.subflow(ev.subflowInputs[0].z);
subflow.in.push(ev.subflowInputs[0]);
subflow.in[0].dirty = true;
}
if (ev.subflowOutputs && ev.subflowOutputs.length > 0) {
subflow = RED.nodes.subflow(ev.subflowOutputs[0].z);
ev.subflowOutputs.sort(function(a,b) { return a.i-b.i});
for (i=0;i<ev.subflowOutputs.length;i++) {
var output = ev.subflowOutputs[i];
subflow.out.splice(output.i,0,output);
for (var j=output.i+1;j<subflow.out.length;j++) {
subflow.out[j].i++;
subflow.out[j].dirty = true;
}
RED.nodes.eachLink(function(l) {
if (l.source.type == "subflow:"+subflow.id) {
if (l.sourcePort >= output.i) {
l.sourcePort++;
}
}
});
}
}
if (ev.subflow && ev.subflow.hasOwnProperty('instances')) {
ev.subflow.instances.forEach(function(n) {
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
node.dirty = true;
}
});
}
if (subflow) {
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.nodes) {
for (i=0;i<ev.nodes.length;i++) {
RED.nodes.add(ev.nodes[i]);
modifiedTabs[ev.nodes[i].z] = true;
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.addLink(ev.links[i]);
}
}
if (ev.changes) {
for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) {
node = RED.nodes.node(i);
if (node) {
for (var d in ev.changes[i]) {
if (ev.changes[i].hasOwnProperty(d)) {
node[d] = ev.changes[i][d];
}
}
node.dirty = true;
}
}
}
}
} else if (ev.t == "move") {
for (i=0;i<ev.nodes.length;i++) {
var n = ev.nodes[i];
n.n.x = n.ox;
n.n.y = n.oy;
n.n.dirty = true;
n.n.moved = n.moved;
}
// A move could have caused a link splice
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.removeLink(ev.links[i]);
}
}
if (ev.removedLinks) {
for (i=0;i<ev.removedLinks.length;i++) {
RED.nodes.addLink(ev.removedLinks[i]);
}
}
} else if (ev.t == "edit") {
for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) {
if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
// This is a config node property
var currentConfigNode = RED.nodes.node(ev.node[i]);
if (currentConfigNode) {
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
}
var newConfigNode = RED.nodes.node(ev.changes[i]);
if (newConfigNode) {
newConfigNode.users.push(ev.node);
}
}
ev.node[i] = ev.changes[i];
}
}
if (ev.subflow) {
if (ev.subflow.hasOwnProperty('inputCount')) {
if (ev.node.in.length > ev.subflow.inputCount) {
ev.node.in.splice(ev.subflow.inputCount);
} else if (ev.subflow.inputs.length > 0) {
ev.node.in = ev.node.in.concat(ev.subflow.inputs);
}
}
if (ev.subflow.hasOwnProperty('outputCount')) {
if (ev.node.out.length > ev.subflow.outputCount) {
ev.node.out.splice(ev.subflow.outputCount);
} else if (ev.subflow.outputs.length > 0) {
ev.node.out = ev.node.out.concat(ev.subflow.outputs);
}
}
if (ev.subflow.hasOwnProperty('instances')) {
ev.subflow.instances.forEach(function(n) {
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
node.dirty = true;
}
});
}
RED.editor.validateNode(ev.node);
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
n.inputs = ev.node.in.length;
n.outputs = ev.node.out.length;
RED.editor.updateNodeProperties(n);
RED.editor.validateNode(n);
});
} else {
var outputMap;
if (ev.outputMap) {
outputMap = {};
for (var port in ev.outputMap) {
if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== "-1") {
outputMap[ev.outputMap[port]] = port;
}
}
}
RED.editor.updateNodeProperties(ev.node,outputMap);
RED.editor.validateNode(ev.node);
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.addLink(ev.links[i]);
}
}
ev.node.dirty = true;
ev.node.changed = ev.changed;
} else if (ev.t == "createSubflow") {
if (ev.nodes) {
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) {
n.z = ev.activeWorkspace;
n.dirty = true;
});
for (i=0;i<ev.nodes.length;i++) {
RED.nodes.remove(ev.nodes[i]);
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.removeLink(ev.links[i]);
}
}
RED.nodes.removeSubflow(ev.subflow.subflow);
RED.workspaces.remove(ev.subflow.subflow);
if (ev.removedLinks) {
for (i=0;i<ev.removedLinks.length;i++) {
RED.nodes.addLink(ev.removedLinks[i]);
}
}
} else if (ev.t == "reorder") {
if (ev.order) {
RED.workspaces.order(ev.order);
}
}
Object.keys(modifiedTabs).forEach(function(id) {
var subflow = RED.nodes.subflow(id);
if (subflow) {
RED.editor.validateNode(subflow);
}
});
RED.nodes.dirty(ev.dirty);
RED.view.redraw(true);
RED.palette.refresh();
RED.workspaces.refresh();
RED.sidebar.config.refresh();
}
}
return {
//TODO: this function is a placeholder until there is a 'save' event that can be listened to
markAllDirty: function() {
for (var i=0;i<undo_history.length;i++) {
undo_history[i].dirty = true;
}
},
list: function() {
return undo_history
},
depth: function() {
return undo_history.length;
},
push: function(ev) {
undo_history.push(ev);
},
pop: function() {
var ev = undo_history.pop();
undoEvent(ev);
},
peek: function() {
return undo_history[undo_history.length-1];
},
clear: function() {
undo_history = [];
}
}
})();

View File

@@ -16,14 +16,10 @@
RED.i18n = (function() {
var apiRootUrl;
return {
init: function(options, done) {
apiRootUrl = options.apiRootUrl||"";
var preferredLanguage = localStorage.getItem("editor-language");
var opts = {
resGetPath: apiRootUrl+'locales/__ns__?lng=__lng__',
init: function(done) {
i18n.init({
resGetPath: 'locales/__ns__?lng=__lng__',
dynamicLoad: false,
load:'current',
ns: {
@@ -31,40 +27,17 @@ RED.i18n = (function() {
defaultNs: "editor"
},
fallbackLng: ['en-US'],
useCookie: false,
returnObjectTrees: true
};
if (preferredLanguage) {
opts.lng = preferredLanguage;
}
i18n.init(opts,function() {
useCookie: false
},function() {
done();
});
RED["_"] = function() {
var v = i18n.t.apply(null,arguments);
if (typeof v === 'string') {
return v;
} else {
return arguments[0];
}
return i18n.t.apply(null,arguments);
}
},
lang: function() {
// Gets the active message catalog language. This is based on what
// locale the editor is using and what languages are available.
//
var preferredLangs = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var knownLangs = RED.settings.theme("languages")||["en-US"];
for (var i=0;i<preferredLangs.length;i++) {
if (knownLangs.indexOf(preferredLangs[i]) > -1) {
return preferredLangs[i]
}
}
return 'end-US'
},
loadNodeCatalog: function(namespace,done) {
var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
loadCatalog: function(namespace,done) {
var languageList = i18n.functions.toLanguages(i18n.detectLanguage());
var toLoad = languageList.length;
languageList.forEach(function(lang) {
$.ajax({
@@ -72,7 +45,7 @@ RED.i18n = (function() {
"Accept":"application/json"
},
cache: false,
url: apiRootUrl+'nodes/'+namespace+'/messages?lng='+lang,
url: 'locales/'+namespace+'?lng='+lang,
success: function(data) {
i18n.addResourceBundle(lang,namespace,data);
toLoad--;
@@ -86,7 +59,7 @@ RED.i18n = (function() {
},
loadNodeCatalogs: function(done) {
var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var languageList = i18n.functions.toLanguages(i18n.detectLanguage());
var toLoad = languageList.length;
languageList.forEach(function(lang) {
@@ -95,7 +68,7 @@ RED.i18n = (function() {
"Accept":"application/json"
},
cache: false,
url: apiRootUrl+'nodes/messages?lng='+lang,
url: 'locales/nodes?lng='+lang,
success: function(data) {
var namespaces = Object.keys(data);
namespaces.forEach(function(ns) {

View File

@@ -1,39 +1,25 @@
{
"*": {
"alt-shift-p":"core:manage-palette",
"ctrl-shift-p":"core:manage-palette",
"ctrl-f": "core:search",
"ctrl-shift-f": "core:list-flows",
"ctrl-=": "core:zoom-in",
"ctrl--": "core:zoom-out",
"ctrl-0": "core:zoom-reset",
"ctrl-enter": "core:confirm-edit-tray",
"ctrl-escape": "core:cancel-edit-tray",
"ctrl-d": "core:deploy-flows",
"ctrl-g i": "core:show-info-tab",
"ctrl-g d": "core:show-debug-tab",
"ctrl-g c": "core:show-config-tab",
"ctrl-g x": "core:show-context-tab",
"ctrl-e": "core:show-export-dialog",
"ctrl-i": "core:show-import-dialog",
"ctrl-space": "core:toggle-sidebar",
"ctrl-p": "core:toggle-palette",
"ctrl-,": "core:show-user-settings",
"ctrl-alt-l": "core:clear-debug-messages",
"ctrl-alt-r": "core:show-remote-diff",
"ctrl-alt-n": "core:new-project",
"ctrl-alt-o": "core:open-project",
"ctrl-g v": "core:show-version-control-tab",
"ctrl-shift-l": "core:show-event-log",
"ctrl-shift-p":"core:show-action-list"
"ctrl-g v": "core:show-version-control-tab"
},
"red-ui-sidebar-node-config": {
"backspace": "core:delete-config-selection",
"delete": "core:delete-config-selection",
"ctrl-a": "core:select-all-config-nodes",
"ctrl-z": "core:undo",
"ctrl-y": "core:redo"
},
"red-ui-workspace": {
"workspace": {
"backspace": "core:delete-selection",
"delete": "core:delete-selection",
"enter": "core:edit-selected-node",
@@ -41,17 +27,8 @@
"ctrl-x": "core:cut-selection-to-internal-clipboard",
"ctrl-v": "core:paste-from-internal-clipboard",
"ctrl-z": "core:undo",
"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",
@@ -61,10 +38,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

@@ -13,66 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var RED = (function() {
function appendNodeConfig(nodeConfig,done) {
done = done || function(){};
var m = /<!-- --- \[red-module:(\S+)\] --- -->/.exec(nodeConfig.trim());
var moduleId;
if (m) {
moduleId = m[1];
} else {
moduleId = "unknown";
}
try {
var hasDeferred = false;
var nodeConfigEls = $("<div>"+nodeConfig+"</div>");
var scripts = nodeConfigEls.find("script");
var scriptCount = scripts.length;
scripts.each(function(i,el) {
var srcUrl = $(el).attr('src');
if (srcUrl && !/^\s*(https?:|\/|\.)/.test(srcUrl)) {
$(el).remove();
var newScript = document.createElement("script");
newScript.onload = function() {
scriptCount--;
if (scriptCount === 0) {
$("#red-ui-editor-node-configs").append(nodeConfigEls);
done()
}
}
if ($(el).attr('type') === "module") {
newScript.type = "module";
}
$("#red-ui-editor-node-configs").append(newScript);
newScript.src = RED.settings.apiRootUrl+srcUrl;
hasDeferred = true;
} else {
if (/\/ace.js$/.test(srcUrl) || /\/ext-language_tools.js$/.test(srcUrl)) {
// Block any attempts to load ace.js from a CDN - this will
// break the version of ace included in the editor.
// At the time of commit, the contrib-python nodes did this.
// This is a crude fix until the python nodes are fixed.
console.warn("Blocked attempt to load",srcUrl,"by",moduleId)
$(el).remove();
}
scriptCount--;
}
})
if (!hasDeferred) {
$("#red-ui-editor-node-configs").append(nodeConfigEls);
done();
}
} catch(err) {
RED.notify(RED._("notification.errors.failedToAppendNode",{module:moduleId, error:err.toString()}),{
type: "error",
timeout: 10000
});
console.log("["+moduleId+"] "+err.toString());
done();
}
}
(function() {
function loadNodeList() {
$.ajax({
@@ -107,51 +48,40 @@ var RED = (function() {
}
function loadNodes() {
var lang = localStorage.getItem("editor-language")||i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
"Accept":"text/html"
},
cache: false,
url: 'nodes',
success: function(data) {
var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/);
var stepConfig = function() {
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");
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
RED.menu.setDisabled('menu-item-projects-open',true);
RED.menu.setDisabled('menu-item-projects-settings',true);
if (activeProject === false) {
// User previously decline the migration to projects.
} else { // null/undefined
RED.projects.showStartup();
}
}
completeLoad();
});
} else {
// Projects disabled by the user
RED.sidebar.info.refresh()
completeLoad();
$("body").append(data);
$("body").i18n();
$("#palette > .palette-spinner").hide();
$(".palette-scroll").removeClass("hide");
$("#palette-search").removeClass("hide");
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
RED.menu.setDisabled('menu-item-projects-open',true);
RED.menu.setDisabled('menu-item-projects-settings',true);
if (activeProject === false) {
// User previously decline the migration to projects.
} else { // null/undefined
RED.projects.showStartup();
}
}
completeLoad();
});
} else {
var config = configs.shift();
appendNodeConfig(config,stepConfig);
// Projects disabled by the user
RED.sidebar.info.refresh()
completeLoad();
}
}
stepConfig();
});
}
});
}
@@ -200,13 +130,13 @@ var RED = (function() {
loadFlows(function() {
var project = RED.projects.getActiveProject();
var message = {
"change-branch": RED._("notification.project.change-branch", {project: project.git.branches.local}),
"merge-abort": RED._("notification.project.merge-abort"),
"loaded": RED._("notification.project.loaded", {project: msg.project}),
"updated": RED._("notification.project.updated", {project: msg.project}),
"pull": RED._("notification.project.pull", {project: msg.project}),
"revert": RED._("notification.project.revert", {project: msg.project}),
"merge-complete": RED._("notification.project.merge-complete")
"change-branch":"Change to local branch '"+project.git.branches.local+"'",
"merge-abort":"Git merge aborted",
"loaded":"Project '"+msg.project+"' loaded",
"updated":"Project '"+msg.project+"' updated",
"pull":"Project '"+msg.project+"' reloaded",
"revert": "Project '"+msg.project+"' reloaded",
"merge-complete":"Git merge completed"
}[msg.action];
RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh()
@@ -225,32 +155,23 @@ var RED = (function() {
id: notificationId
}
if (notificationId === "runtime-state") {
if (msg.error === "safe-mode") {
options.buttons = [
{
text: RED._("common.label.close"),
click: function() {
persistentNotifications[notificationId].hideNotification();
}
}
]
} else if (msg.error === "missing-types") {
text+="<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
if (msg.error === "missing-types") {
text+="<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
if (!!RED.projects.getActiveProject()) {
options.buttons = [
{
text: RED._("notification.label.manage-project-dep"),
text: "Manage project dependencies",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.settings.show('deps');
}
}
]
// } else if (RED.settings.theme('palette.editable') !== false) {
// } else if (RED.settings.theme('palette.editable') !== false) {
} else {
options.buttons = [
{
text: RED._("common.label.close"),
text: "Close",
click: function() {
persistentNotifications[notificationId].hideNotification();
}
@@ -258,25 +179,13 @@ var RED = (function() {
]
}
} else if (msg.error === "credentials_load_failed") {
if (RED.settings.theme("projects.enabled",false)) {
// projects enabled
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: RED._("notification.project.setupCredentials"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showCredentialsPrompt();
}
}
]
}
} else {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: RED._("common.label.close"),
text: "Setup credentials",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showCredentialsPrompt();
}
}
]
@@ -285,19 +194,7 @@ var RED = (function() {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: RED._("notification.project.setupProjectFiles"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showFilesPrompt();
}
}
]
}
} else if (msg.error === "missing_package_file") {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: RED._("notification.project.setupProjectFiles"),
text: "Setup project files",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showFilesPrompt();
@@ -309,13 +206,13 @@ var RED = (function() {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: RED._("notification.project.no"),
text: "No thanks",
click: function() {
persistentNotifications[notificationId].hideNotification();
}
},
{
text: RED._("notification.project.createDefault"),
text: "Create default project files",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.createDefaultFileSet();
@@ -329,7 +226,7 @@ var RED = (function() {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: RED._("notification.project.mergeConflict"),
text: "Show merge conflicts",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.sidebar.versionControl.showLocalChanges();
@@ -353,11 +250,12 @@ var RED = (function() {
var parts = topic.split("/");
var node = RED.nodes.node(parts[1]);
if (node) {
if (msg.hasOwnProperty("text") && /^[a-zA-Z]/.test(msg.text)) {
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
if (msg.hasOwnProperty("text")) {
if (msg.text[0] !== ".") {
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
}
}
node.status = msg;
node.dirtyStatus = true;
node.dirty = true;
RED.view.redraw();
}
@@ -372,9 +270,9 @@ var RED = (function() {
var id = m.id;
RED.nodes.addNodeSet(m);
addedTypes = addedTypes.concat(m.types);
RED.i18n.loadNodeCatalog(id, function() {
RED.i18n.loadCatalog(id, function() {
$.get('nodes/'+id, function(data) {
appendNodeConfig(data);
$("body").append(data);
});
});
});
@@ -402,7 +300,7 @@ var RED = (function() {
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
$.get('nodes/'+msg.id, function(data) {
appendNodeConfig(data);
$("body").append(data);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
});
@@ -414,51 +312,61 @@ var RED = (function() {
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success");
}
} else if (topic == "notification/node/upgraded") {
} else if (topic == "node/upgraded") {
RED.notify(RED._("palette.event.nodeUpgraded", {module:msg.module,version:msg.version}),"success");
RED.nodes.registry.setModulePendingUpdated(msg.module,msg.version);
}
});
RED.comms.subscribe("event-log/#", function(topic,payload) {
var id = topic.substring(9);
RED.eventLog.log(id,payload);
// Refresh flow library to ensure any examples are updated
RED.library.loadFlowLibrary();
});
}
function showAbout() {
$.get('red/about', function(data) {
var aboutHeader = '<div style="text-align:center;">'+
'<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>';
'<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>';
RED.sidebar.info.set(aboutHeader+RED.utils.renderMarkdown(data));
RED.sidebar.info.set(aboutHeader+marked(data));
RED.sidebar.info.show();
});
}
function buildMainMenu() {
function loadEditor() {
var menuOptions = [];
if (RED.settings.theme("projects.enabled",false)) {
menuOptions.push({id:"menu-item-projects-menu",label:RED._("menu.label.projects"),options:[
{id:"menu-item-projects-new",label:RED._("menu.label.projects-new"),disabled:false,onselect:"core:new-project"},
{id:"menu-item-projects-open",label:RED._("menu.label.projects-open"),disabled:false,onselect:"core:open-project"},
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
menuOptions.push({id:"menu-item-projects-menu",label:"Projects",options:[
{id:"menu-item-projects-new",label:"New",disabled:false,onselect:"core:new-project"},
{id:"menu-item-projects-open",label:"Open",disabled:false,onselect:"core:open-project"},
{id:"menu-item-projects-settings",label:"Project Settings",disabled:false,onselect:"core:show-project-settings"}
]});
}
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
{id:"menu-item-palette",label:RED._("menu.label.palette.show"),toggle:true,onselect:"core:toggle-palette", selected: true},
// {id:"menu-item-view-show-grid",setting:"view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:"core:toggle-show-grid"},
// {id:"menu-item-view-snap-grid",setting:"view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:"core:toggle-snap-grid"},
// {id:"menu-item-status",setting:"node-show-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:"core:toggle-status", selected: true},
//null,
// {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[
// {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}},
// {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}},
// {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}},
// {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}}
// ]},
// null,
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true},
{id:"menu-item-event-log",label:RED._("eventLog.title"),onselect:"core:show-event-log"},
{id:"menu-item-action-list",label:RED._("keyboard.actionList"),onselect:"core:show-action-list"},
null
]});
menuOptions.push(null);
if (RED.settings.theme("menu.menu-item-import-library", true)) {
menuOptions.push({id: "menu-item-import", label: RED._("menu.label.import"), onselect: "core:show-import-dialog"});
}
if (RED.settings.theme("menu.menu-item-export-library", true)) {
menuOptions.push({id: "menu-item-export", label: RED._("menu.label.export"), onselect: "core:show-export-dialog"});
}
menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"},
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
]});
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:"core:show-export-dialog"},
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"}
]});
menuOptions.push(null);
menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"});
menuOptions.push(null);
@@ -472,14 +380,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"});
@@ -489,9 +389,7 @@ var RED = (function() {
menuOptions.push({id:"menu-item-user-settings",label:RED._("menu.label.settings"),onselect:"core:show-user-settings"});
menuOptions.push(null);
if (RED.settings.theme("menu.menu-item-keyboard-shortcuts", true)) {
menuOptions.push({id: "menu-item-keyboard-shortcuts", label: RED._("menu.label.keyboardShortcuts"), onselect: "core:show-help"});
}
menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:"core:show-help"});
menuOptions.push({id:"menu-item-help",
label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
@@ -499,24 +397,12 @@ var RED = (function() {
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });
$('<li><a id="red-ui-header-button-sidemenu" class="button" href="#"><i class="fa fa-bars"></i></a></li>').appendTo(".red-ui-header-toolbar")
RED.menu.init({id:"red-ui-header-button-sidemenu",options: menuOptions});
}
function loadEditor() {
RED.workspaces.init();
RED.statusBar.init();
RED.view.init();
RED.userSettings.init();
RED.user.init();
RED.notifications.init();
RED.library.init();
RED.keyboard.init();
RED.palette.init();
RED.eventLog.init();
if (RED.settings.theme('palette.editable') !== false) {
RED.palette.editor.init();
} else {
@@ -532,81 +418,37 @@ var RED = (function() {
}
RED.subflow.init();
RED.group.init();
RED.workspaces.init();
RED.clipboard.init();
RED.search.init();
RED.actionList.init();
RED.editor.init();
RED.diff.init();
RED.menu.init({id:"btn-sidemenu",options: menuOptions});
RED.deploy.init(RED.settings.theme("deployButton",null));
RED.notifications.init();
buildMainMenu();
RED.actions.add("core:show-about", showAbout);
RED.nodes.init();
RED.comms.connect();
$("#red-ui-main-container").show();
$(".red-ui-header-toolbar").show();
RED.actions.add("core:show-about", showAbout);
$("#main-container").show();
$(".header-toolbar").show();
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);
$('<ul class="red-ui-header-toolbar hide"></ul>').appendTo(header);
$('<div id="red-ui-header-shade" class="hide"></div>').appendTo(header);
$('<div id="red-ui-main-container" class="red-ui-sidebar-closed hide">'+
'<div id="red-ui-workspace"></div>'+
'<div id="red-ui-editor-stack"></div>'+
'<div id="red-ui-palette"></div>'+
'<div id="red-ui-sidebar"></div>'+
'<div id="red-ui-sidebar-separator"></div>'+
'</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);
$.getJSON(options.apiRootUrl+"theme", function(theme) {
if (theme.header) {
if (theme.header.url) {
logo = $("<a>",{href:theme.header.url}).appendTo(logo);
}
if (theme.header.image) {
$('<img>',{src:theme.header.image}).appendTo(logo);
}
if (theme.header.title) {
$('<span>').html(theme.header.title).appendTo(logo);
}
}
});
}
$(function() {
var initialised = false;
function init(options) {
if (initialised) {
throw new Error("RED already initialised");
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
document.title = document.title+" : "+window.location.hostname;
}
initialised = true;
ace.require("ace/ext/language_tools");
options = options || {};
options.apiRootUrl = options.apiRootUrl || "";
if (options.apiRootUrl && !/\/$/.test(options.apiRootUrl)) {
options.apiRootUrl = options.apiRootUrl+"/";
}
options.target = $("#red-ui-editor");
options.target.addClass("red-ui-editor");
buildEditor(options);
RED.i18n.init(options, function() {
RED.settings.init(options, loadEditor);
RED.i18n.init(function() {
RED.settings.init(loadEditor);
})
}
return {
init: init
}
});
})();

View File

@@ -17,8 +17,6 @@ RED.nodes = (function() {
var node_defs = {};
var nodes = [];
var nodeTabMap = {};
var configNodes = {};
var links = [];
var defaultWorkspace;
@@ -27,9 +25,6 @@ RED.nodes = (function() {
var subflows = {};
var loadedFlowVersion = null;
var groups = {};
var groupsByZ = {};
var initialLoad;
var dirty = false;
@@ -138,7 +133,7 @@ RED.nodes = (function() {
registerNodeType: function(nt,def) {
nodeDefinitions[nt] = def;
def.type = nt;
if (nt.substring(0,8) != "subflow:") {
if (def.category != "subflows") {
def.set = nodeSets[typeToId[nt]];
nodeSets[typeToId[nt]].added = true;
nodeSets[typeToId[nt]].enabled = true;
@@ -179,7 +174,6 @@ RED.nodes = (function() {
},
setIconSets: function(sets) {
iconSets = sets;
iconSets["font-awesome"] = RED.nodes.fontAwesome.getIconList();
},
getIconSets: function() {
return iconSets;
@@ -218,11 +212,6 @@ RED.nodes = (function() {
n.i = nextId+1;
}
nodes.push(n);
if (nodeTabMap[n.z]) {
nodeTabMap[n.z][n.id] = n;
} else {
console.warn("Node added to unknown tab/subflow:",n);
}
}
RED.events.emit('nodes:add',n);
}
@@ -256,9 +245,6 @@ RED.nodes = (function() {
node = getNode(id);
if (node) {
nodes.splice(nodes.indexOf(node),1);
if (nodeTabMap[node.z]) {
delete nodeTabMap[node.z][node.id];
}
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
removedLinks.forEach(function(l) {links.splice(links.indexOf(l), 1); });
var updatedConfigNode = false;
@@ -304,28 +290,6 @@ RED.nodes = (function() {
return {links:removedLinks,nodes:removedNodes};
}
function moveNodeToTab(node, z) {
if (node.type === "group") {
moveGroupToTab(node,z);
return;
}
if (nodeTabMap[node.z]) {
delete nodeTabMap[node.z][node.id];
}
if (!nodeTabMap[z]) {
nodeTabMap[z] = {};
}
nodeTabMap[z][node.id] = node;
node.z = z;
}
function moveGroupToTab(group, z) {
var index = groupsByZ[group.z].indexOf(group);
groupsByZ[group.z].splice(index,1);
groupsByZ[z] = groupsByZ[z] || [];
groupsByZ[z].push(group);
group.z = z;
}
function removeLink(l) {
var index = links.indexOf(l);
if (index != -1) {
@@ -333,28 +297,20 @@ RED.nodes = (function() {
}
}
function addWorkspace(ws,targetIndex) {
function addWorkspace(ws) {
workspaces[ws.id] = ws;
nodeTabMap[ws.id] = {};
ws._def = RED.nodes.getType('tab');
if (targetIndex === undefined) {
workspacesOrder.push(ws.id);
} else {
workspacesOrder.splice(targetIndex,0,ws.id);
}
workspacesOrder.push(ws.id);
}
function getWorkspace(id) {
return workspaces[id];
}
function removeWorkspace(id) {
delete workspaces[id];
delete nodeTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var removedNodes = [];
var removedLinks = [];
var removedGroups = [];
var n;
var node;
for (n=0;n<nodes.length;n++) {
@@ -371,17 +327,11 @@ RED.nodes = (function() {
}
}
}
removedGroups = groupsByZ[id] || [];
removedGroups.forEach(function(g) {
delete groups[g.id]
})
delete groupsByZ[id];
for (n=0;n<removedNodes.length;n++) {
var result = removeNode(removedNodes[n].id);
removedLinks = removedLinks.concat(result.links);
}
return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
return {nodes:removedNodes,links:removedLinks};
}
function addSubflow(sf, createNewIds) {
@@ -402,37 +352,19 @@ RED.nodes = (function() {
sf.name = subflowName;
}
subflows[sf.id] = sf;
nodeTabMap[sf.id] = {};
RED.nodes.registerType("subflow:"+sf.id, {
defaults:{
name:{value:""},
env:{value:[]}
},
icon: function() { return sf.icon||"subflow.svg" },
category: sf.category || "subflows",
defaults:{name:{value:""}},
info: sf.info,
icon: function() { return sf.icon||"subflow.png" },
category: "subflows",
inputs: sf.in.length,
outputs: sf.out.length,
color: sf.color || "#DDAA99",
color: "#da9",
label: function() { return this.name||RED.nodes.subflow(sf.id).name },
labelStyle: function() { return this.name?"red-ui-flow-node-label-italic":""; },
labelStyle: function() { return this.name?"node_label_italic":""; },
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;
// for (var i=0; i<rows.size(); i++) {
// height -= $(rows[i]).outerHeight(true);
// }
// var editorRow = $("#dialog-form>div.node-input-env-container-row");
// height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$("ol.red-ui-editor-subflow-env-list").editableList('height',height);
},
set:{
module: "node-red"
}
@@ -444,7 +376,6 @@ RED.nodes = (function() {
}
function removeSubflow(sf) {
delete subflows[sf.id];
delete nodeTabMap[sf.id];
registry.removeNodeType("subflow:"+sf.id);
}
@@ -515,12 +446,7 @@ RED.nodes = (function() {
node.id = n.id;
node.type = n.type;
node.z = n.z;
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)) {
@@ -533,33 +459,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];
}
}
}
@@ -568,13 +480,6 @@ RED.nodes = (function() {
}
}
}
if (n.type === "group") {
node.x = n.x;
node.y = n.y;
node.w = n.w;
node.h = n.h;
node.nodes = node.nodes.map(function(n) { return n.id });
}
if (n._def.category != "config") {
node.x = n.x;
node.y = n.y;
@@ -586,9 +491,7 @@ RED.nodes = (function() {
for (var j=0;j<wires.length;j++) {
var w = wires[j];
if (w.target.type != "subflow") {
if (w.sourcePort < node.wires.length) {
node.wires[w.sourcePort].push(w.target.id);
}
node.wires[w.sourcePort].push(w.target.id);
}
}
@@ -604,48 +507,18 @@ RED.nodes = (function() {
node.icon = n.icon;
}
}
if ((!n._def.defaults || !n._def.defaults.hasOwnProperty("l")) && n.hasOwnProperty('l')) {
var isLink = /^link (in|out)$/.test(node.type);
if (isLink == n.l) {
node.l = n.l;
}
}
}
if (n.info) {
node.info = n.info;
}
return node;
}
function convertSubflow(n, exportCreds) {
function convertSubflow(n) {
var node = {};
node.id = n.id;
node.type = n.type;
node.name = n.name;
node.info = n.info;
node.category = n.category;
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) {
var nIn = {x:p.x,y:p.y,wires:[]};
@@ -678,40 +551,18 @@ RED.nodes = (function() {
node.outputLabels = n.outputLabels.slice();
}
if (n.icon) {
if (n.icon !== "node-red/subflow.svg") {
if (n.icon !== "node-red/subflow.png") {
node.icon = n.icon;
}
}
if (n.status) {
node.status = {x: n.status.x, y: n.status.y, wires:[]};
links.forEach(function(d) {
if (d.target === n.status) {
if (d.source.type != "subflow") {
node.status.wires.push({id:d.source.id, port:d.sourcePort})
} else {
node.status.wires.push({id:n.id, port:0})
}
}
});
}
return node;
}
/**
* 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++) {
@@ -727,11 +578,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) {
@@ -748,9 +599,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);
@@ -773,12 +621,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) {
@@ -794,39 +637,42 @@ RED.nodes = (function() {
}
function checkForMatchingSubflow(subflow,subflowNodes) {
subflowNodes = subflowNodes || [];
var i;
var match = null;
RED.nodes.eachSubflow(function(sf) {
if (sf.name != subflow.name ||
sf.info != subflow.info ||
sf.in.length != subflow.in.length ||
sf.out.length != subflow.out.length) {
try {
RED.nodes.eachSubflow(function(sf) {
if (sf.name != subflow.name ||
sf.info != subflow.info ||
sf.in.length != subflow.in.length ||
sf.out.length != subflow.out.length) {
return;
}
var sfNodes = RED.nodes.filterNodes({z:sf.id});
if (sfNodes.length != subflowNodes.length) {
return;
}
var sfNodes = RED.nodes.filterNodes({z:sf.id});
if (sfNodes.length != subflowNodes.length) {
return;
}
}
var subflowNodeSet = [subflow].concat(subflowNodes);
var sfNodeSet = [sf].concat(sfNodes);
var subflowNodeSet = [subflow].concat(subflowNodes);
var sfNodeSet = [sf].concat(sfNodes);
var exportableSubflowNodes = JSON.stringify(subflowNodeSet);
var exportableSFNodes = JSON.stringify(createExportableNodeSet(sfNodeSet));
var nodeMap = {};
for (i=0;i<sfNodes.length;i++) {
exportableSubflowNodes = exportableSubflowNodes.replace(new RegExp("\""+subflowNodes[i].id+"\"","g"),'"'+sfNodes[i].id+'"');
}
exportableSubflowNodes = exportableSubflowNodes.replace(new RegExp("\""+subflow.id+"\"","g"),'"'+sf.id+'"');
var exportableSubflowNodes = JSON.stringify(subflowNodeSet);
var exportableSFNodes = JSON.stringify(createExportableNodeSet(sfNodeSet));
var nodeMap = {};
for (i=0;i<sfNodes.length;i++) {
exportableSubflowNodes = exportableSubflowNodes.replace(new RegExp("\""+subflowNodes[i].id+"\"","g"),'"'+sfNodes[i].id+'"');
}
exportableSubflowNodes = exportableSubflowNodes.replace(new RegExp("\""+subflow.id+"\"","g"),'"'+sf.id+'"');
if (exportableSubflowNodes !== exportableSFNodes) {
return;
}
if (exportableSubflowNodes !== exportableSFNodes) {
return;
}
match = sf;
return false;
});
match = sf;
throw new Error();
});
} catch(err) {
console.log(err.stack);
}
return match;
}
function compareNodes(nodeA,nodeB,idMustMatch) {
@@ -881,20 +727,6 @@ RED.nodes = (function() {
if (!$.isArray(newNodes)) {
newNodes = [newNodes];
}
// Scan for any duplicate nodes and remove them. This is a temporary
// fix to help resolve corrupted flows caused by 0.20.0 where multiple
// copies of the flow would get loaded at the same time.
// If the user hit deploy they would have saved those duplicates.
var seenIds = {};
newNodes = newNodes.filter(function(n) {
if (seenIds[n.id]) {
return false;
}
seenIds[n.id] = true;
return true;
})
var isInitialLoad = false;
if (!initialLoad) {
isInitialLoad = true;
@@ -907,7 +739,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) {
@@ -921,7 +752,8 @@ RED.nodes = (function() {
}
if (!isInitialLoad && unknownTypes.length > 0) {
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
RED.notify("<p>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</p>"+typeList,"error",false,10000);
var type = "type"+(unknownTypes.length > 1?"s":"");
RED.notify("<strong>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</strong>"+typeList,"error",false,10000);
}
var activeWorkspace = RED.workspaces.active();
@@ -931,7 +763,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) {
@@ -957,7 +789,6 @@ RED.nodes = (function() {
var node_map = {};
var new_nodes = [];
var new_links = [];
var new_groups = [];
var nid;
var def;
var configNode;
@@ -1008,12 +839,6 @@ RED.nodes = (function() {
output.i = i;
output.id = getID();
});
if (n.status) {
n.status.type = "subflow";
n.status.direction = "status";
n.status.z = n.id;
n.status.id = getID();
}
new_subflows.push(n);
addSubflow(n,createNewIds);
}
@@ -1076,17 +901,7 @@ RED.nodes = (function() {
}
if (!existingConfigNode || existingConfigNode._def.exclusive) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode.z !== n.z) {
configNode = {
id:n.id,
z:n.z,
type:n.type,
info: n.info,
users:[],
_config:{}
};
if (n.hasOwnProperty('d')) {
configNode.d = n.d;
}
configNode = {id:n.id, z:n.z, type:n.type, users:[], _config:{}};
for (d in def.defaults) {
if (def.defaults.hasOwnProperty(d)) {
configNode[d] = n[d];
@@ -1121,29 +936,17 @@ RED.nodes = (function() {
def = registry.getNodeType(n.type);
if (!def || def.category != "config") {
var node = {
x:parseFloat(n.x || 0),
y:parseFloat(n.y || 0),
x:n.x,
y:n.y,
z:n.z,
type:0,
info: n.info,
wires:n.wires,
inputLabels: n.inputLabels,
outputLabels: n.outputLabels,
icon: n.icon,
changed:false,
_config:{}
}
if (n.type !== "group") {
node.wires = n.wires||[];
node.inputLabels = n.inputLabels;
node.outputLabels = n.outputLabels;
node.icon = n.icon;
}
if (n.hasOwnProperty('l')) {
node.l = n.l;
}
if (n.hasOwnProperty('d')) {
node.d = n.d;
}
if (n.hasOwnProperty('g')) {
node.g = n.g;
}
};
if (createNewIds) {
if (subflow_blacklist[n.z]) {
continue;
@@ -1180,17 +983,7 @@ 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_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId);
if (createNewIds) {
@@ -1202,7 +995,6 @@ RED.nodes = (function() {
node.name = n.name;
node.outputs = subflow.out.length;
node.inputs = subflow.in.length;
node.env = n.env;
} else {
if (!node._def) {
if (node.x && node.y) {
@@ -1210,7 +1002,7 @@ RED.nodes = (function() {
color:"#fee",
defaults: {},
label: "unknown: "+n.type,
labelStyle: "red-ui-flow-node-label-italic",
labelStyle: "node_label_italic",
outputs: n.outputs||n.wires.length,
set: registry.getNodeSet("node-red/unknown")
}
@@ -1220,13 +1012,6 @@ RED.nodes = (function() {
set: registry.getNodeSet("node-red/unknown")
};
node.users = [];
// This is a config node, so delete the default
// non-config node properties
delete node.x;
delete node.y;
delete node.wires;
delete node.inputLabels;
delete node.outputLabels;
}
var orig = {};
for (var p in n) {
@@ -1239,31 +1024,10 @@ RED.nodes = (function() {
node.type = "unknown";
}
if (node._def.category != "config") {
if (n.hasOwnProperty('inputs')) {
node.inputs = n.inputs;
node._config.inputs = JSON.stringify(n.inputs);
} else {
node.inputs = node._def.inputs;
}
if (n.hasOwnProperty('outputs')) {
node.outputs = n.outputs;
node._config.outputs = JSON.stringify(n.outputs);
} else {
node.outputs = node._def.outputs;
}
if (node.hasOwnProperty('wires') && node.wires.length > node.outputs) {
if (!node._def.defaults.hasOwnProperty("outputs") || !isNaN(parseInt(n.outputs))) {
// If 'wires' is longer than outputs, clip wires
console.log("Warning: node.wires longer than node.outputs - trimming wires:",node.id," wires:",node.wires.length," outputs:",node.outputs);
node.wires = node.wires.slice(0,node.outputs);
} else {
// The node declares outputs in its defaults, but has not got a valid value
// Defer to the length of the wires array
node.outputs = node.wires.length;
}
}
node.inputs = n.inputs||node._def.inputs;
node.outputs = n.outputs||node._def.outputs;
for (d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
if (node._def.defaults.hasOwnProperty(d)) {
node[d] = n[d];
node._config[d] = JSON.stringify(n[d]);
}
@@ -1280,19 +1044,11 @@ RED.nodes = (function() {
}
}
}
if (node.type !== "group") {
addNode(node);
RED.editor.validateNode(node);
} else {
addGroup(node);
}
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") {
if (node._def.category != "config") {
new_nodes.push(node);
} else if (node.type === "group") {
new_groups.push(node);
}
}
}
@@ -1302,7 +1058,6 @@ RED.nodes = (function() {
var nodeTypeArrayReferences = {
"catch":"scope",
"status":"scope",
"complete": "scope",
"link in":"links",
"link out":"links"
}
@@ -1327,11 +1082,6 @@ 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]]) {
@@ -1386,55 +1136,22 @@ RED.nodes = (function() {
});
delete output.wires;
});
if (n.status) {
n.status.wires.forEach(function(wire) {
var link;
if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) {
link = {source:n.in[wire.port], sourcePort:wire.port,target:n.status};
} else {
link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:n.status};
}
addLink(link);
new_links.push(link);
});
delete n.status.wires;
}
}
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
if (n.g && node_map[n.g]) {
n.g = node_map[n.g].id;
} else {
delete n.g;
}
n.nodes = n.nodes.map(function(id) {
return node_map[id];
})
}
RED.workspaces.refresh();
return [new_nodes,new_links,new_groups,new_workspaces,new_subflows,missingWorkspace];
return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace];
}
// TODO: supports filter.z|type
function filterNodes(filter) {
var result = [];
var searchSet = nodes;
var doZFilter = false;
if (filter.hasOwnProperty("z")) {
if (Object.hasOwnProperty("values") && nodeTabMap.hasOwnProperty(filter.z) ) {
searchSet = Object.values(nodeTabMap[filter.z]);
} else {
doZFilter = true;
}
}
for (var n=0;n<searchSet.length;n++) {
var node = searchSet[n];
if (filter.hasOwnProperty("type") && node.type !== filter.type) {
for (var n=0;n<nodes.length;n++) {
var node = nodes[n];
if (filter.hasOwnProperty("z") && node.z !== filter.z) {
continue;
}
if (doZFilter && node.z !== filter.z) {
if (filter.hasOwnProperty("type") && node.type !== filter.type) {
continue;
}
result.push(node);
@@ -1501,12 +1218,8 @@ RED.nodes = (function() {
function clear() {
nodes = [];
links = [];
nodeTabMap = {};
configNodes = {};
workspacesOrder = [];
groups = {};
groupsByZ = {};
var subflowIds = Object.keys(subflows);
subflowIds.forEach(function(id) {
RED.subflow.removeSubflow(id)
@@ -1535,73 +1248,34 @@ RED.nodes = (function() {
// var loadedFlowVersion = null;
}
function addGroup(group) {
groupsByZ[group.z] = groupsByZ[group.z] || [];
groupsByZ[group.z].push(group);
groups[group.id] = group;
}
function removeGroup(group) {
var i = groupsByZ[group.z].indexOf(group);
groupsByZ[group.z].splice(i,1);
if (group.g) {
if (groups[group.g]) {
var index = groups[group.g].nodes.indexOf(group);
groups[group.g].nodes.splice(index,1);
}
}
RED.group.markDirty(group);
delete groups[group.id];
}
return {
init: function() {
RED.events.on("registry:node-type-added",function(type) {
var def = registry.getNodeType(type);
var replaced = false;
var replaceNodes = {};
var replaceNodes = [];
RED.nodes.eachNode(function(n) {
if (n.type === "unknown" && n.name === type) {
replaceNodes[n.id] = n;
replaceNodes.push(n);
}
});
RED.nodes.eachConfig(function(n) {
if (n.type === "unknown" && n.name === type) {
replaceNodes[n.id] = n;
replaceNodes.push(n);
}
});
var replaceNodeIds = Object.keys(replaceNodes);
if (replaceNodeIds.length > 0) {
if (replaceNodes.length > 0) {
var reimportList = [];
replaceNodeIds.forEach(function(id) {
var n = replaceNodes[id];
replaceNodes.forEach(function(n) {
if (configNodes.hasOwnProperty(n.id)) {
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));
});
// Remove any links between nodes that are going to be reimported.
// This prevents a duplicate link from being added.
var removeLinks = [];
RED.nodes.eachLink(function(l) {
if (replaceNodes.hasOwnProperty(l.source.id) && replaceNodes.hasOwnProperty(l.target.id)) {
removeLinks.push(l);
}
});
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) {
@@ -1639,8 +1313,6 @@ RED.nodes = (function() {
remove: removeNode,
clear: clear,
moveNodeToTab: moveNodeToTab,
addLink: addLink,
removeLink: removeLink,
@@ -1655,48 +1327,33 @@ 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) {
break;
}
cb(nodes[n]);
}
},
eachLink: function(cb) {
for (var l=0;l<links.length;l++) {
if (cb(links[l]) === false) {
break;
}
cb(links[l]);
}
},
eachConfig: function(cb) {
for (var id in configNodes) {
if (configNodes.hasOwnProperty(id)) {
if (cb(configNodes[id]) === false) {
break;
}
cb(configNodes[id]);
}
}
},
eachSubflow: function(cb) {
for (var id in subflows) {
if (subflows.hasOwnProperty(id)) {
if (cb(subflows[id]) === false) {
break;
}
cb(subflows[id]);
}
}
},
eachWorkspace: function(cb) {
for (var i=0;i<workspacesOrder.length;i++) {
if (cb(workspaces[workspacesOrder[i]]) === false) {
break;
}
cb(workspaces[workspacesOrder[i]]);
}
},

View File

@@ -13,5 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
module.exports = false
var RED = {};

View File

@@ -37,7 +37,7 @@ RED.settings = (function () {
if (key === "auth-tokens") {
localStorage.setItem(key, JSON.stringify(value));
} else {
RED.utils.setMessageProperty(userSettings,key,value);
userSettings[key] = value;
saveUserSettings();
}
};
@@ -46,26 +46,16 @@ RED.settings = (function () {
* If the key is not set in the localStorage it returns <i>undefined</i>
* Else return the JSON parsed value
* @param key
* @param defaultIfUndefined
* @returns {*}
*/
var get = function (key,defaultIfUndefined) {
var get = function (key) {
if (!hasLocalStorage()) {
return undefined;
}
if (key === "auth-tokens") {
return JSON.parse(localStorage.getItem(key));
} else {
var v;
try {
v = RED.utils.getMessageProperty(userSettings,key);
if (v === undefined) {
v = defaultIfUndefined;
}
} catch(err) {
v = defaultIfUndefined;
}
return v;
return userSettings[key];
}
};
@@ -99,22 +89,18 @@ RED.settings = (function () {
userSettings = data;
}
var init = function (options, done) {
var init = function (done) {
var accessTokenMatch = /[?&]access_token=(.*?)(?:$|&)/.exec(window.location.search);
if (accessTokenMatch) {
var accessToken = accessTokenMatch[1];
RED.settings.set("auth-tokens",{access_token: accessToken});
window.location.search = "";
}
RED.settings.apiRootUrl = options.apiRootUrl;
$.ajaxSetup({
beforeSend: function(jqXHR,settings) {
// Only attach auth header for requests to relative paths
if (!/^\s*(https?:|\/|\.)/.test(settings.url)) {
if (options.apiRootUrl) {
settings.url = options.apiRootUrl+settings.url;
}
var auth_tokens = RED.settings.get("auth-tokens");
if (auth_tokens) {
jqXHR.setRequestHeader("Authorization","Bearer "+auth_tokens.access_token);
@@ -141,12 +127,6 @@ RED.settings = (function () {
RED.settings.remove("auth-tokens");
}
console.log("Node-RED: " + data.version);
console.groupCollapsed("Versions");
console.log("jQuery",$().jquery)
console.log("jQuery UI",$.ui.version);
console.log("ACE",ace.version);
console.log("D3",d3.version);
console.groupEnd();
loadUserSettings(done);
},
error: function(jqXHR,textStatus,errorThrown) {

View File

@@ -97,14 +97,14 @@ RED.text.bidi = (function() {
}
/**
* Enforces the text direction for all the spans with style red-ui-text-bidi-aware under
* Enforces the text direction for all the spans with style bidiAware under
* workspace or sidebar div
*/
function enforceTextDirectionOnPage() {
$("#red-ui-workspace").find('span.red-ui-text-bidi-aware').each(function() {
$("#workspace").find('span.bidiAware').each(function() {
$(this).attr("dir", resolveBaseTextDir($(this).html()));
});
$("#red-ui-sidebar").find('span.red-ui-text-bidi-aware').each(function() {
$("#sidebar").find('span.bidiAware').each(function() {
$(this).attr("dir", resolveBaseTextDir($(this).text()));
});
}

View File

@@ -1242,7 +1242,7 @@ RED.text.format = (function() {
element.dispatchEvent(event);
return;
}
var range = selection.getRangeAt(0);
var tempRange = range.cloneRange(), startNode, startOffset;
startNode = range.startContainer;
@@ -1304,7 +1304,7 @@ RED.text.format = (function() {
}
return {
/*!
/**
* Returns the HTML representation of a given structured text
* @param text - the structured text
* @param type - could be one of filepath, url, email
@@ -1315,7 +1315,7 @@ RED.text.format = (function() {
getHtml: function (text, type, args, isRtl, locale) {
return getHandler(type).format(text, args, isRtl, true, locale);
},
/*!
/**
* Handle Structured text correct display for a given HTML element.
* @param element - the element : should be of type div contenteditable=true
* @param type - could be one of filepath, url, email

View File

@@ -12,9 +12,9 @@ RED.actions = (function() {
function getAction(name) {
return actions[name];
}
function invokeAction(name,args) {
function invokeAction(name) {
if (actions.hasOwnProperty(name)) {
actions[name](args);
actions[name]();
}
}
function listActions() {

380
editor/js/ui/clipboard.js Normal file
View File

@@ -0,0 +1,380 @@
/**
* 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.clipboard = (function() {
var dialog;
var dialogContainer;
var exportNodesDialog;
var importNodesDialog;
var disabled = false;
function setupDialogs() {
dialog = $('<div id="clipboard-dialog" class="hide node-red-dialog"><form class="dialog-form form-horizontal"></form></div>')
.appendTo("body")
.dialog({
modal: true,
autoOpen: false,
width: 500,
resizable: false,
buttons: [
{
id: "clipboard-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-close",
class: "primary",
text: RED._("common.label.close"),
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-copy",
class: "primary",
text: RED._("clipboard.export.copy"),
click: function() {
$("#clipboard-export").select();
document.execCommand("copy");
document.getSelection().removeAllRanges();
RED.notify(RED._("clipboard.nodesExported"));
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-ok",
class: "primary",
text: RED._("common.label.import"),
click: function() {
RED.view.importNodes($("#clipboard-import").val(),$("#import-tab > a.selected").attr('id') === 'import-tab-new');
$( this ).dialog( "close" );
}
}
],
open: function(e) {
$(this).parent().find(".ui-dialog-titlebar-close").hide();
},
close: function(e) {
}
});
dialogContainer = dialog.children(".dialog-form");
exportNodesDialog =
'<div class="form-row">'+
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.export.copy"></label>'+
'<span id="export-range-group" class="button-group">'+
'<a id="export-range-selected" class="editor-button toggle" href="#" data-i18n="clipboard.export.selected"></a>'+
'<a id="export-range-flow" class="editor-button toggle" href="#" data-i18n="clipboard.export.current"></a>'+
'<a id="export-range-full" class="editor-button toggle" href="#" data-i18n="clipboard.export.all"></a>'+
'</span>'+
'</div>'+
'<div class="form-row">'+
'<textarea readonly style="resize: none; width: 100%; border-radius: 4px;font-family: monospace; font-size: 12px; background:#f3f3f3; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-export" rows="5"></textarea>'+
'</div>'+
'<div class="form-row" style="text-align: right;">'+
'<span id="export-format-group" class="button-group">'+
'<a id="export-format-mini" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+
'<a id="export-format-full" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+
'</span>'+
'</div>';
importNodesDialog = '<div class="form-row">'+
'<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5" placeholder="'+
RED._("clipboard.pasteNodes")+
'"></textarea>'+
'</div>'+
'<div class="form-row">'+
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+
'<span id="import-tab" class="button-group">'+
'<a id="import-tab-current" class="editor-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+
'<a id="import-tab-new" class="editor-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+
'</span>'+
'</div>';
}
function validateImport() {
var importInput = $("#clipboard-import");
var v = importInput.val();
v = v.substring(v.indexOf('['),v.lastIndexOf(']')+1);
try {
JSON.parse(v);
importInput.removeClass("input-error");
importInput.val(v);
$("#clipboard-dialog-ok").button("enable");
} catch(err) {
if (v !== "") {
importInput.addClass("input-error");
}
$("#clipboard-dialog-ok").button("disable");
}
}
function importNodes() {
if (disabled) {
return;
}
dialogContainer.empty();
dialogContainer.append($(importNodesDialog));
dialogContainer.i18n();
$("#clipboard-dialog-ok").show();
$("#clipboard-dialog-cancel").show();
$("#clipboard-dialog-close").hide();
$("#clipboard-dialog-copy").hide();
$("#clipboard-dialog-ok").button("disable");
$("#clipboard-import").keyup(validateImport);
$("#clipboard-import").on('paste',function() { setTimeout(validateImport,10)});
$("#import-tab > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
});
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
}
function exportNodes() {
if (disabled) {
return;
}
dialogContainer.empty();
dialogContainer.append($(exportNodesDialog));
dialogContainer.i18n();
var format = RED.settings.flowFilePretty ? "export-format-full" : "export-format-mini";
$("#export-format-group > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
$("#clipboard-export").focus();
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
var flow = $("#clipboard-export").val();
if (flow.length > 0) {
var nodes = JSON.parse(flow);
format = $(this).attr('id');
if (format === 'export-format-full') {
flow = JSON.stringify(nodes,null,4);
} else {
flow = JSON.stringify(nodes);
}
$("#clipboard-export").val(flow);
$("#clipboard-export").focus();
}
});
$("#export-range-group > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
$("#clipboard-export").focus();
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
var type = $(this).attr('id');
var flow = "";
var nodes = null;
if (type === 'export-range-selected') {
var selection = RED.view.selection();
// Don't include the subflow meta-port nodes in the exported selection
nodes = RED.nodes.createExportableNodeSet(selection.nodes.filter(function(n) { return n.type !== 'subflow'}));
} else if (type === 'export-range-flow') {
var activeWorkspace = RED.workspaces.active();
nodes = RED.nodes.filterNodes({z:activeWorkspace});
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
nodes.unshift(parentNode);
nodes = RED.nodes.createExportableNodeSet(nodes);
} else if (type === 'export-range-full') {
nodes = RED.nodes.createCompleteNodeSet(false);
}
if (nodes !== null) {
if (format === "export-format-full") {
flow = JSON.stringify(nodes,null,4);
} else {
flow = JSON.stringify(nodes);
}
}
if (flow.length > 0) {
$("#export-copy").removeClass('disabled');
} else {
$("#export-copy").addClass('disabled');
}
$("#clipboard-export").val(flow);
$("#clipboard-export").focus();
})
$("#clipboard-dialog-ok").hide();
$("#clipboard-dialog-cancel").hide();
$("#clipboard-dialog-copy").hide();
$("#clipboard-dialog-close").hide();
var selection = RED.view.selection();
if (selection.nodes) {
$("#export-range-selected").click();
} else {
$("#export-range-selected").addClass('disabled').removeClass('selected');
$("#export-range-flow").click();
}
if (format === "export-format-full") {
$("#export-format-full").click();
} else {
$("#export-format-mini").click();
}
$("#clipboard-export")
.focus(function() {
var textarea = $(this);
textarea.select();
textarea.mouseup(function() {
textarea.unbind("mouseup");
return false;
})
});
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
$("#clipboard-export").focus();
if (!document.queryCommandSupported("copy")) {
$("#clipboard-dialog-cancel").hide();
$("#clipboard-dialog-close").show();
} else {
$("#clipboard-dialog-cancel").show();
$("#clipboard-dialog-copy").show();
}
}
function hideDropTarget() {
$("#dropTarget").hide();
RED.keyboard.remove("escape");
}
function copyText(value,element,msg) {
var truncated = false;
if (typeof value !== "string" ) {
value = JSON.stringify(value, function(key,value) {
if (value !== null && typeof value === 'object') {
if (value.__encoded__ && value.hasOwnProperty('data') && value.hasOwnProperty('length')) {
truncated = value.data.length !== value.length;
return value.data;
}
}
return value;
});
}
if (truncated) {
msg += "_truncated";
}
$("#clipboard-hidden").val(value).select();
var result = document.execCommand("copy");
if (result && element) {
var popover = RED.popover.create({
target: element,
direction: 'left',
size: 'small',
content: RED._(msg)
});
setTimeout(function() {
popover.close();
},1000);
popover.open();
}
return result;
}
return {
init: function() {
setupDialogs();
$('<input type="text" id="clipboard-hidden">').appendTo("body");
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true);
RED.menu.setDisabled("menu-item-export-clipboard",true);
RED.menu.setDisabled("menu-item-export-library",true);
} else {
RED.menu.setDisabled("menu-item-export",false);
RED.menu.setDisabled("menu-item-export-clipboard",false);
RED.menu.setDisabled("menu-item-export-library",false);
}
});
RED.actions.add("core:show-export-dialog",exportNodes);
RED.actions.add("core:show-import-dialog",importNodes);
RED.events.on("editor:open",function() { disabled = true; });
RED.events.on("editor:close",function() { disabled = false; });
RED.events.on("search:open",function() { disabled = true; });
RED.events.on("search:close",function() { disabled = false; });
RED.events.on("type-search:open",function() { disabled = true; });
RED.events.on("type-search:close",function() { disabled = false; });
$('#chart').on("dragenter",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
$("#dropTarget").css({display:'table'});
RED.keyboard.add("*", "escape" ,hideDropTarget);
}
});
$('#dropTarget').on("dragover",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
event.preventDefault();
}
})
.on("dragleave",function(event) {
hideDropTarget();
})
.on("drop",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
var data = event.originalEvent.dataTransfer.getData("text/plain");
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
RED.view.importNodes(data);
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
var files = event.originalEvent.dataTransfer.files;
if (files.length === 1) {
var file = files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
RED.view.importNodes(e.target.result);
};
})(file);
reader.readAsText(file);
}
}
hideDropTarget();
event.preventDefault();
});
},
import: importNodes,
export: exportNodes,
copyText: copyText
}
})();

View File

@@ -38,7 +38,7 @@
this.options[0].show();
}
this.element.on("change", function() {
this.element.change(function() {
if (this.checked) {
that.options[0].hide();
that.options[1].show();
@@ -53,7 +53,7 @@
child.checkboxSet('state',isChecked,false,true);
})
})
this.uiElement.on("click", function(e) {
this.uiElement.click(function(e) {
e.stopPropagation();
// state returns null for a partial state. Clicking on that should
// result in false.

View File

@@ -32,10 +32,7 @@
* - scrollOnAdd : boolean - whether to scroll to newly added items
* methods:
* - addItem(itemData)
* - insertItemAt : function(data,index) - add an item at the specified index
* - removeItem(itemData)
* - getItemAt(index)
* - indexOf(itemData)
* - width(width)
* - height(height)
* - items()
@@ -78,9 +75,9 @@
addLabel = 'add';
}
}
$('<a href="#" class="red-ui-button red-ui-button-small red-ui-editableList-addButton" style="margin-top: 4px;"><i class="fa fa-plus"></i> '+addLabel+'</a>')
$('<a href="#" class="editor-button editor-button-small red-ui-editableList-addButton" style="margin-top: 4px;"><i class="fa fa-plus"></i> '+addLabel+'</a>')
.appendTo(this.topContainer)
.on("click", function(evt) {
.click(function(evt) {
evt.preventDefault();
that.addItem({});
});
@@ -188,11 +185,6 @@
}
},
_destroy: function() {
if (this.topContainer) {
var tc = this.topContainer;
delete this.topContainer;
tc.remove();
}
},
_refreshFilter: function() {
var that = this;
@@ -238,24 +230,7 @@
this.uiHeight = desiredHeight;
this._resize();
},
getItemAt: function(index) {
var items = this.items();
if (index >= 0 && index < items.length) {
return $(items[index]).data('data');
} else {
return;
}
},
indexOf: function(data) {
var items = this.items();
for (var i=0;i<items.length;i++) {
if ($(items[i]).data('data') === data) {
return i
}
}
return -1
},
insertItemAt: function(data,index) {
addItem: function(data) {
var that = this;
data = data || {};
var li = $('<li>');
@@ -273,13 +248,7 @@
});
}
if (!added) {
if (index <= 0) {
li.prependTo(this.element);
} else if (index > that.element.children().length-1) {
li.appendTo(this.element);
} else {
li.insertBefore(this.element.children().eq(index));
}
li.appendTo(this.element);
}
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
row.data('data',data);
@@ -288,10 +257,10 @@
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);
var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove editor-button editor-button-small"}).appendTo(li);
$('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
li.addClass("red-ui-editableList-item-removable");
deleteButton.on("click", function(evt) {
deleteButton.click(function(evt) {
evt.preventDefault();
var data = row.data('data');
li.addClass("red-ui-editableList-item-deleting")
@@ -324,9 +293,6 @@
},0);
}
},
addItem: function(data) {
this.insertItemAt(data,this.element.children().length)
},
addItems: function(items) {
for (var i=0; i<items.length;i++) {
this.addItem(items[i]);
@@ -346,7 +312,6 @@
},
empty: function() {
this.element.empty();
this.uiContainer.scrollTop(0);
},
filter: function(filter) {
if (filter !== undefined) {
@@ -362,22 +327,6 @@
},
length: function() {
return this.element.children().length;
},
show: function(item) {
var items = this.element.children().filter(function(f) {
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.find(".red-ui-editableList-item-content");
if (el.length) {
return el.data('data');
} else {
return null;
}
}
});
})(jQuery);

View File

@@ -56,12 +56,12 @@ RED.menu = (function() {
}
if (opt === null) {
item = $('<li class="red-ui-menu-divider"></li>');
item = $('<li class="divider"></li>');
} else {
item = $('<li></li>');
if (opt.group) {
item.addClass("red-ui-menu-group-"+opt.group);
item.addClass("menu-group-"+opt.group);
}
var linkContent = '<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">';
@@ -71,7 +71,7 @@ RED.menu = (function() {
}
if (opt.icon !== undefined) {
if (/\.(png|svg)/.test(opt.icon)) {
if (/\.png/.test(opt.icon)) {
linkContent += '<img src="'+opt.icon+'"/> ';
} else {
linkContent += '<i class="'+(opt.icon?opt.icon:'" style="display: inline-block;"')+'"></i> ';
@@ -79,10 +79,10 @@ RED.menu = (function() {
}
if (opt.sublabel) {
linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+opt.label+'</span>'+
'<span class="red-ui-menu-sublabel">'+opt.sublabel+'</span></span>'
linkContent += '<span class="menu-label-container"><span class="menu-label">'+opt.label+'</span>'+
'<span class="menu-sublabel">'+opt.sublabel+'</span></span>'
} else {
linkContent += '<span class="red-ui-menu-label">'+opt.label+'</span>'
linkContent += '<span class="menu-label">'+opt.label+'</span>'
}
linkContent += '</a>';
@@ -92,16 +92,27 @@ RED.menu = (function() {
menuItems[opt.id] = opt;
if (opt.onselect) {
link.on("click", function(e) {
link.click(function(e) {
e.preventDefault();
if ($(this).parent().hasClass("disabled")) {
return;
}
if (opt.toggle) {
if (opt.toggle === true) {
setSelected(opt.id, !isSelected(opt.id));
var selected = isSelected(opt.id);
if (typeof opt.toggle === "string") {
if (!selected) {
for (var m in menuItems) {
if (menuItems.hasOwnProperty(m)) {
var mi = menuItems[m];
if (mi.id != opt.id && opt.toggle == mi.toggle) {
setSelected(mi.id,false);
}
}
}
setSelected(opt.id,true);
}
} else {
setSelected(opt.id, true);
setSelected(opt.id, !selected);
}
} else {
triggerAction(opt.id);
@@ -114,13 +125,13 @@ RED.menu = (function() {
link.attr("target","_blank").attr("href",opt.href);
} else if (!opt.options) {
item.addClass("disabled");
link.on("click", function(event) {
link.click(function(event) {
event.preventDefault();
});
}
if (opt.options) {
item.addClass("red-ui-menu-dropdown-submenu pull-left");
var submenu = $('<ul id="'+opt.id+'-submenu" class="red-ui-menu-dropdown"></ul>').appendTo(item);
item.addClass("dropdown-submenu pull-left");
var submenu = $('<ul id="'+opt.id+'-submenu" class="dropdown-menu"></ul>').appendTo(item);
for (var i=0;i<opt.options.length;i++) {
var li = createMenuItem(opt.options[i]);
@@ -139,30 +150,13 @@ RED.menu = (function() {
}
function createMenu(options) {
var topMenu = $("<ul/>",{class:"red-ui-menu red-ui-menu-dropdown pull-right"});
if (options.id) {
topMenu.attr({id:options.id+"-submenu"});
var menuParent = $("#"+options.id);
if (menuParent.length === 1) {
topMenu.insertAfter(menuParent);
menuParent.on("click", function(evt) {
evt.stopPropagation();
evt.preventDefault();
if (topMenu.is(":visible")) {
$(document).off("click.red-ui-menu");
topMenu.hide();
} else {
$(document).on("click.red-ui-menu", function(evt) {
$(document).off("click.red-ui-menu");
activeMenu = null;
topMenu.hide();
});
$(".red-ui-menu").hide();
topMenu.show();
}
})
}
var menuParent = $("#"+options.id);
var topMenu = $("<ul/>",{id:options.id+"-submenu", class:"dropdown-menu pull-right"});
if (menuParent.length === 1) {
topMenu.insertAfter(menuParent);
}
var lastAddedSeparator = false;
@@ -198,9 +192,8 @@ RED.menu = (function() {
}
function setSelected(id,state) {
var alreadySet = false;
if (isSelected(id) == state) {
alreadySet = true;
return;
}
var opt = menuItems[id];
if (state) {
@@ -208,26 +201,10 @@ RED.menu = (function() {
} else {
$("#"+id).removeClass("active");
}
if (opt) {
if (opt.toggle && typeof opt.toggle === "string") {
if (state) {
for (var m in menuItems) {
if (menuItems.hasOwnProperty(m)) {
var mi = menuItems[m];
if (mi.id != opt.id && opt.toggle == mi.toggle) {
setSelected(mi.id,false);
}
}
}
}
}
if (!alreadySet && opt.onselect) {
triggerAction(opt.id,state);
}
if (!opt.local && !alreadySet) {
RED.settings.set(opt.setting||("menu-"+opt.id), state);
}
if (opt && opt.onselect) {
triggerAction(opt.id,state);
}
RED.settings.set(opt.setting||("menu-"+opt.id), state);
}
function toggleSelected(id) {
@@ -244,14 +221,14 @@ RED.menu = (function() {
function addItem(id,opt) {
var item = createMenuItem(opt);
if (opt !== null && opt.group) {
var groupItems = $("#"+id+"-submenu").children(".red-ui-menu-group-"+opt.group);
if (opt.group) {
var groupItems = $("#"+id+"-submenu").children(".menu-group-"+opt.group);
if (groupItems.length === 0) {
item.appendTo("#"+id+"-submenu");
} else {
for (var i=0;i<groupItems.length;i++) {
var groupItem = groupItems[i];
var label = $(groupItem).find(".red-ui-menu-label").html();
var label = $(groupItem).find(".menu-label").html();
if (opt.label < label) {
$(groupItem).before(item);
break;
@@ -285,5 +262,6 @@ RED.menu = (function() {
addItem: addItem,
removeItem: removeItem,
setAction: setAction
//TODO: add an api for replacing a submenu - see library.js:loadFlowLibrary
}
})();

View File

@@ -0,0 +1,81 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.panels = (function() {
function createPanel(options) {
var container = options.container || $("#"+options.id);
var children = container.children();
if (children.length !== 2) {
throw new Error("Container must have exactly two children");
}
container.addClass("red-ui-panels");
var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
var startPosition;
var panelHeights = [];
var modifiedHeights = false;
var panelRatio;
separator.draggable({
axis: "y",
containment: container,
scroll: false,
start:function(event,ui) {
var height = container.height();
startPosition = ui.position.top;
panelHeights = [$(children[0]).height(),$(children[1]).height()];
},
drag: function(event,ui) {
var height = container.height();
var delta = ui.position.top-startPosition;
var newHeights = [panelHeights[0]+delta,panelHeights[1]-delta];
$(children[0]).height(newHeights[0]);
$(children[1]).height(newHeights[1]);
if (options.resize) {
options.resize(newHeights[0],newHeights[1]);
}
ui.position.top -= delta;
panelRatio = newHeights[0]/height;
},
stop:function(event,ui) {
modifiedHeights = true;
}
});
return {
resize: function(height) {
var panelHeights = [$(children[0]).height(),$(children[1]).height()];
container.height(height);
if (modifiedHeights) {
var topPanelHeight = panelRatio*height;
var bottomPanelHeight = height - topPanelHeight - 48;
panelHeights = [topPanelHeight,bottomPanelHeight];
$(children[0]).height(panelHeights[0]);
$(children[1]).height(panelHeights[1]);
}
if (options.resize) {
options.resize(panelHeights[0],panelHeights[1]);
}
}
}
}
return {
create: createPanel
}
})();

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