Compare commits
299 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2b9aca0c56 | ||
|
3a17c3ee6d | ||
|
df09252ee0 | ||
|
f51778d417 | ||
|
119fc63794 | ||
|
ee3425d3be | ||
|
31c979f30f | ||
|
89f2c26cd6 | ||
|
0dbf43d0aa | ||
|
8a6d11b191 | ||
|
d8eb926e2c | ||
|
21d0adbdae | ||
|
c5fd3a5753 | ||
|
eae4e3d983 | ||
|
bb1fe8daef | ||
|
c5d8e09b41 | ||
|
369eae3d92 | ||
|
e2fa457ca2 | ||
|
871f764e98 | ||
|
f8853af902 | ||
|
4248d20f39 | ||
|
5cda08e7b0 | ||
|
7e9d96ee87 | ||
|
974ac31d33 | ||
|
0658b70631 | ||
|
53258eeede | ||
|
4f174308b9 | ||
|
98c9e40349 | ||
|
3a4756bd83 | ||
|
6ccb05cb2c | ||
|
3c2d32b867 | ||
|
956050434f | ||
|
38ab1550d2 | ||
|
e852d1e57c | ||
|
7de0216976 | ||
|
911288e695 | ||
|
72e1f20383 | ||
|
d28a6eaf9d | ||
|
17f3366556 | ||
|
0bef04ae0a | ||
|
f11b906fd9 | ||
|
518358d9dc | ||
|
5ffde21d83 | ||
|
052302b3e7 | ||
|
fe1ce21114 | ||
|
ce5c9da107 | ||
|
cf25b2866e | ||
|
07fd5a5f5f | ||
|
913fdac671 | ||
|
7dc838dea6 | ||
|
7112fd2a22 | ||
|
56e8c143dd | ||
|
7b4cbbe816 | ||
|
8f8ee4662d | ||
|
86013c7db4 | ||
|
01aa3324f8 | ||
|
b9cfeee965 | ||
|
b3684a70b5 | ||
|
51fce9343b | ||
|
0c5c3448d0 | ||
|
deaef3ab86 | ||
|
a443491c0c | ||
|
276d893198 | ||
|
653d0e71e4 | ||
|
faa7d948a7 | ||
|
771342989e | ||
|
e9ce519e4b | ||
|
c016b102eb | ||
|
0583c60837 | ||
|
1c1a85dcef | ||
|
c71e76335b | ||
|
c1a32c4eb9 | ||
|
9ad1f769d3 | ||
|
87f8fd34b8 | ||
|
e206d2919e | ||
|
9d809aa2ba | ||
|
8f744794e4 | ||
|
78ab4217be | ||
|
d090df94c5 | ||
|
937f26da41 | ||
|
98e3ff014e | ||
|
6f84526364 | ||
|
105d38c885 | ||
|
d7bdcd69fc | ||
|
87e537da90 | ||
|
8f16695f06 | ||
|
8403f6291f | ||
|
5af6ac3e80 | ||
|
0d557094b2 | ||
|
a2aa78afd4 | ||
|
b0de8abb63 | ||
|
6ff540ed08 | ||
|
2b8ed9850b | ||
|
dcd579b5e3 | ||
|
c9d2d301aa | ||
|
1aaef598a5 | ||
|
73d1f3d0e8 | ||
|
e369ded6c5 | ||
|
269846c587 | ||
|
8dc98420db | ||
|
1014abe92f | ||
|
6927f10f8f | ||
|
49d3a7190a | ||
|
a2e65b0018 | ||
|
f48ee01a03 | ||
|
0e926c566b | ||
|
d2c4c2c34c | ||
|
c2253d1e25 | ||
|
eae16b6e8c | ||
|
868ae5b5dd | ||
|
1406503e10 | ||
|
9ca9d88546 | ||
|
203d3f672c | ||
|
698b2688f6 | ||
|
be1620dd07 | ||
|
e1f0969957 | ||
|
e1dd8cf2ab | ||
|
8ee90777ee | ||
|
2fe9c1e55f | ||
|
9dd7e2e43d | ||
|
5efbdf5d04 | ||
|
5be3472413 | ||
|
a9a0953653 | ||
|
d4ac4c44d0 | ||
|
f459ff8ad0 | ||
|
b96ea36b70 | ||
|
e543cc0fed | ||
|
0b1b4df210 | ||
|
e59ffb0b19 | ||
|
120c8f2c28 | ||
|
fbfc5c8a2d | ||
|
31b018c80e | ||
|
255d708fb6 | ||
|
78d1da5fbc | ||
|
9c22a770ef | ||
|
b201828236 | ||
|
2a8a885271 | ||
|
7adefd6ee0 | ||
|
f967a5ecdc | ||
|
c8d6dc2531 | ||
|
216b5fba7a | ||
|
f4ec9a72d5 | ||
|
cf0c2825eb | ||
|
be46c419dc | ||
|
62c68d06fe | ||
|
4f4d8419bc | ||
|
16e17954b4 | ||
|
cc1d080a5a | ||
|
dd7f4f6752 | ||
|
9daeba02b5 | ||
|
8a96dbd121 | ||
|
2a57d0b6d0 | ||
|
8a5c1bade5 | ||
|
fcc6943f98 | ||
|
72a9de058d | ||
|
8748be28b7 | ||
|
20bdea7ae0 | ||
|
e19b8d35a9 | ||
|
81df74dfc8 | ||
|
153fa7478f | ||
|
500e9a4010 | ||
|
5352fc87ee | ||
|
f07fd64ffb | ||
|
36f299c031 | ||
|
78cf310c58 | ||
|
18a3d71024 | ||
|
26db1048f9 | ||
|
b61a250d58 | ||
|
1d10eba0cc | ||
|
35042132fa | ||
|
57c049b49f | ||
|
7a0ce0c957 | ||
|
eb4cadb0b5 | ||
|
ac0ca083c0 | ||
|
9afb4a9315 | ||
|
df065e94b7 | ||
|
a9789697e7 | ||
|
2d91be8814 | ||
|
5c58b0c2f4 | ||
|
f0139f9808 | ||
|
5610a3184e | ||
|
b202c73708 | ||
|
dd4cec84bf | ||
|
a1dac1e290 | ||
|
e199d6725e | ||
|
aef38b945d | ||
|
cd5eac2cbb | ||
|
8fea443e71 | ||
|
2a47951e46 | ||
|
5234fda266 | ||
|
e63067cd9f | ||
|
be61cf6a88 | ||
|
5efc89d514 | ||
|
9c104faff3 | ||
|
cf8fe16b09 | ||
|
71db193675 | ||
|
9952d9451e | ||
|
fb738ad9fa | ||
|
46f2f752b0 | ||
|
42730b8fce | ||
|
1c2be579d9 | ||
|
51e891ff88 | ||
|
731efe1c01 | ||
|
f77dd06e65 | ||
|
af20f3df64 | ||
|
4078212089 | ||
|
7bdb3181e2 | ||
|
933608aec1 | ||
|
1d7f06bbba | ||
|
f26cadab7f | ||
|
eacf41a4f6 | ||
|
ab3e64271b | ||
|
e26ea14104 | ||
|
3967e23828 | ||
|
1f8c6f87c9 | ||
|
f6203fe60a | ||
|
06bf710515 | ||
|
0f3cc3196c | ||
|
4403a00651 | ||
|
9c46feb22b | ||
|
10277aa956 | ||
|
ff093d98c6 | ||
|
acc0e0875b | ||
|
69f85bd688 | ||
|
910d983b82 | ||
|
128415bc9e | ||
|
082ce798d8 | ||
|
234abd82a2 | ||
|
3cbc1bbb1b | ||
|
0ed9f6cc4f | ||
|
10b092a9a7 | ||
|
444a897410 | ||
|
e013afb053 | ||
|
34364f5627 | ||
|
cef378d820 | ||
|
a27353c166 | ||
|
bbd197c71d | ||
|
fabf013714 | ||
|
81dcfecb4e | ||
|
971a62ebc9 | ||
|
04f2c92ba6 | ||
|
00d0f8cfc7 | ||
|
c5c404ea05 | ||
|
c80a44933c | ||
|
5599b999ec | ||
|
172cbdaa84 | ||
|
a3c4f12764 | ||
|
bf1cd457cd | ||
|
8af50a51ba | ||
|
ddf31e87b2 | ||
|
5adbc012f3 | ||
|
393fc349b9 | ||
|
dfed4963ed | ||
|
131adb6f4e | ||
|
a8b3cbb683 | ||
|
e97d5c7354 | ||
|
061c44f958 | ||
|
f5d8433341 | ||
|
f78a71e8ed | ||
|
4d48c72146 | ||
|
71ff828947 | ||
|
b6245bdef7 | ||
|
ce1cd1ab9c | ||
|
54b0debb3b | ||
|
1876b56022 | ||
|
d148a23ed6 | ||
|
049a5f1be6 | ||
|
f3880b7601 | ||
|
fbb45a8961 | ||
|
b8c460b825 | ||
|
63191bc641 | ||
|
9f012c261a | ||
|
dc7701ad70 | ||
|
e8666827e6 | ||
|
5e2c51a741 | ||
|
51421ce657 | ||
|
339e6039e1 | ||
|
43054906dc | ||
|
57dedcf816 | ||
|
4dc21c43fa | ||
|
1c86908b90 | ||
|
9b26973883 | ||
|
2585e983a5 | ||
|
a808cb44c2 | ||
|
edd9d2cb9c | ||
|
33d24f79ce | ||
|
cc095e4edf | ||
|
07641d57ab | ||
|
5643c51507 | ||
|
ad6254c0b8 | ||
|
d6ca421d59 | ||
|
79bd01f810 | ||
|
e357352240 | ||
|
0accfade02 | ||
|
00b7afe3ae | ||
|
2e76541fa5 | ||
|
e2911078e3 | ||
|
c6157687c9 | ||
|
87a1818486 |
19
.gitignore
vendored
@@ -1,9 +1,16 @@
|
||||
node_modules
|
||||
.config.json
|
||||
.dist
|
||||
.jshintignore
|
||||
.npm
|
||||
.project
|
||||
.sessions.json
|
||||
.settings
|
||||
.tern-project
|
||||
*.backup
|
||||
*_cred*
|
||||
coverage
|
||||
credentials.json
|
||||
flows*.json
|
||||
flows.backup
|
||||
*_cred*
|
||||
nodes/node-red-nodes/
|
||||
.npm
|
||||
/coverage
|
||||
.config.json
|
||||
node_modules
|
||||
public
|
||||
|
13
.jshintrc
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"asi": true, // allow missing semicolons
|
||||
"curly": true, // require braces
|
||||
"eqnull": true, // ignore ==null
|
||||
"forin": true, // require property filtering in "for in" loops
|
||||
"immed": true, // require immediate functions to be wrapped in ( )
|
||||
"nonbsp": true, // warn on unexpected whitespace breaking chars
|
||||
//"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
|
||||
//"unused": true, // Check for unused functions and variables
|
||||
"loopfunc": true, // allow functions to be defined in loops
|
||||
//"expr": true, // allow ternery operator syntax...
|
||||
"sub": true // don't warn that foo['bar'] should be written as foo.bar
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
.git/*
|
||||
/Gruntfile.js
|
||||
/.git/*
|
||||
*.json
|
||||
lib/*
|
||||
/lib/*
|
||||
*.backup
|
||||
/public/*
|
||||
|
7
.npmignore
Normal file
@@ -0,0 +1,7 @@
|
||||
.settings
|
||||
.jshintignore
|
||||
.jshintrc
|
||||
.project
|
||||
.tern-project
|
||||
.travis.yml
|
||||
.git
|
@@ -3,7 +3,6 @@ before_install:
|
||||
- npm install -g npm@~1.4.18
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
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:
|
||||
|
@@ -6,11 +6,10 @@ We welcome contributions, but request you follow these guidelines.
|
||||
- [Feature requests](#feature-requests)
|
||||
- [Pull-Requests](#pull-requests)
|
||||
- [Contributor License Agreement](#contributor-license-agreement)
|
||||
|
||||
|
||||
## Raising issues
|
||||
|
||||
Please raise any bug reports on the project's
|
||||
[issue tracker](https://github.com/node-red/node-red/issues?state=open). Be sure to
|
||||
Please raise any bug reports on the relevant project's issue tracker. Be sure to
|
||||
search the list to see if your issue has already been raised.
|
||||
|
||||
A good bug report is one that make it easy for us to understand what you were
|
||||
@@ -25,7 +24,6 @@ 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?
|
||||
|
||||
|
||||
## Feature requests
|
||||
|
||||
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
@@ -33,15 +31,15 @@ For feature requests, please raise them on the [mailing list](https://groups.goo
|
||||
## 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
|
||||
of existing code, it may well get rejected if you haven't discussed it on
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
|
||||
|
||||
### Contributor License Agreement
|
||||
|
||||
In order for us to accept pull-requests, the contributor must first complete
|
||||
a Contributor License Agreement (CLA). This clarifies the intellectual
|
||||
property license granted with any contribution. It is for your protection as a
|
||||
Contributor as well as the protection of IBM and its customers; it does not
|
||||
a Contributor License Agreement (CLA). This clarifies the intellectual
|
||||
property license granted with any contribution. It is for your protection as a
|
||||
Contributor as well as the protection of IBM and its customers; it does not
|
||||
change your rights to use your own Contributions for any other purpose.
|
||||
|
||||
You can download the CLAs here:
|
||||
@@ -59,13 +57,5 @@ code base. Some basic rules include:
|
||||
|
||||
- all files must have the Apache license in the header.
|
||||
- indent with 4-spaces, no tabs. No arguments.
|
||||
- opening brace on same line as `if`/`for`/`function`/etc, closing brace on its
|
||||
own line.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- opening brace on same line as `if`/`for`/`function` and so on, closing brace
|
||||
on its own line.
|
||||
|
419
Gruntfile.js
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013, 2014 IBM Corp.
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,78 +14,365 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var path = require("path");
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
// Project configuration.
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
simplemocha: {
|
||||
options: {
|
||||
globals: ['expect'],
|
||||
timeout: 3000,
|
||||
ignoreLeaks: false,
|
||||
ui: 'bdd',
|
||||
reporter: 'spec'
|
||||
},
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
paths: {
|
||||
dist: ".dist"
|
||||
},
|
||||
simplemocha: {
|
||||
options: {
|
||||
globals: ['expect'],
|
||||
timeout: 3000,
|
||||
ignoreLeaks: false,
|
||||
ui: 'bdd',
|
||||
reporter: 'spec'
|
||||
},
|
||||
jshint: {
|
||||
options: {
|
||||
// http://www.jshint.com/docs/options/
|
||||
"asi": true, // allow missing semicolons
|
||||
"curly": true, // require braces
|
||||
"eqnull": true, // ignore ==null
|
||||
"forin": true, // require property filtering in "for in" loops
|
||||
"immed": true, // require immediate functions to be wrapped in ( )
|
||||
"nonbsp": true, // warn on unexpected whitespace breaking chars
|
||||
//"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
|
||||
"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',
|
||||
'red/**/*.js',
|
||||
'nodes/**/*.js',
|
||||
'public/red/**/*.js'
|
||||
],
|
||||
|
||||
core: {
|
||||
files: {
|
||||
src: [
|
||||
'Gruntfile.js',
|
||||
'red.js',
|
||||
'red/**/*.js'
|
||||
]
|
||||
}
|
||||
},
|
||||
nodes: {
|
||||
files: {
|
||||
src: [ 'nodes/**/*.js' ]
|
||||
}
|
||||
},
|
||||
editor: {
|
||||
files: {
|
||||
src: [ 'public/red/**/*.js' ]
|
||||
}
|
||||
},
|
||||
tests: {
|
||||
files: {
|
||||
src: ['test/**/*.js']
|
||||
},
|
||||
options: {
|
||||
"expr": true
|
||||
}
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc:true
|
||||
// http://www.jshint.com/docs/options/
|
||||
//"asi": true, // allow missing semicolons
|
||||
//"curly": true, // require braces
|
||||
//"eqnull": true, // ignore ==null
|
||||
//"forin": true, // require property filtering in "for in" loops
|
||||
//"immed": true, // require immediate functions to be wrapped in ( )
|
||||
//"nonbsp": true, // warn on unexpected whitespace breaking chars
|
||||
////"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
|
||||
//"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',
|
||||
'red/**/*.js',
|
||||
'nodes/core/*/*.js',
|
||||
'editor/js/**/*.js'
|
||||
],
|
||||
core: {
|
||||
files: {
|
||||
src: [
|
||||
'Gruntfile.js',
|
||||
'red.js',
|
||||
'red/**/*.js'
|
||||
]
|
||||
}
|
||||
},
|
||||
nodes: {
|
||||
files: {
|
||||
src: [ 'nodes/core/*/*.js' ]
|
||||
}
|
||||
},
|
||||
editor: {
|
||||
files: {
|
||||
src: [ 'editor/js/**/*.js' ]
|
||||
}
|
||||
},
|
||||
tests: {
|
||||
files: {
|
||||
src: ['test/**/*.js']
|
||||
},
|
||||
options: {
|
||||
"expr": true
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
concat: {
|
||||
options: {
|
||||
separator: ";",
|
||||
},
|
||||
build: {
|
||||
src: [
|
||||
// Ensure editor source files are concatenated in
|
||||
// the right order
|
||||
"editor/js/main.js",
|
||||
"editor/js/settings.js",
|
||||
"editor/js/user.js",
|
||||
"editor/js/comms.js",
|
||||
"editor/js/ui/state.js",
|
||||
"editor/js/nodes.js",
|
||||
"editor/js/history.js",
|
||||
"editor/js/validators.js",
|
||||
"editor/js/ui/deploy.js",
|
||||
"editor/js/ui/menu.js",
|
||||
"editor/js/ui/keyboard.js",
|
||||
"editor/js/ui/tabs.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/editor.js",
|
||||
"editor/js/ui/clipboard.js",
|
||||
"editor/js/ui/library.js",
|
||||
"editor/js/ui/notifications.js",
|
||||
"editor/js/ui/subflow.js",
|
||||
"editor/js/ui/touch/radialMenu.js"
|
||||
],
|
||||
dest: "public/red/red.js"
|
||||
},
|
||||
vendor: {
|
||||
files: {
|
||||
"public/vendor/vendor.js": [
|
||||
"editor/vendor/jquery/js/jquery-1.11.1.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/orion/built-editor.min.js",
|
||||
"editor/vendor/d3/d3.v3.min.js"
|
||||
],
|
||||
"public/vendor/vendor.css": [
|
||||
"editor/vendor/orion/built-editor.css"
|
||||
// TODO: resolve relative resource paths in
|
||||
// bootstrap/FA/jquery
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
build: {
|
||||
files: {
|
||||
'public/red/red.min.js': 'public/red/red.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
sass: {
|
||||
build: {
|
||||
options: {
|
||||
outputStyle: 'compressed'
|
||||
},
|
||||
files: [{
|
||||
dest: 'public/red/style.min.css',
|
||||
src: 'editor/sass/style.scss'
|
||||
}]
|
||||
}
|
||||
},
|
||||
attachCopyright: {
|
||||
js: {
|
||||
src: [
|
||||
'public/red/red.min.js'
|
||||
]
|
||||
},
|
||||
css: {
|
||||
src: [
|
||||
'public/red/style.min.css'
|
||||
]
|
||||
}
|
||||
},
|
||||
clean: {
|
||||
build: {
|
||||
src: [
|
||||
"public/red",
|
||||
"public/index.html",
|
||||
"public/favicon.ico",
|
||||
"public/icons",
|
||||
"public/vendor"
|
||||
]
|
||||
},
|
||||
release: {
|
||||
src: [
|
||||
'<%= paths.dist %>'
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
js: {
|
||||
files: [
|
||||
'editor/js/**/*.js'
|
||||
],
|
||||
tasks: ['concat','uglify','attachCopyright:js']
|
||||
},
|
||||
sass: {
|
||||
files: [
|
||||
'editor/sass/**/*.scss'
|
||||
],
|
||||
tasks: ['sass','attachCopyright:css']
|
||||
}
|
||||
},
|
||||
|
||||
nodemon: {
|
||||
/* uses .nodemonignore */
|
||||
dev: {
|
||||
script: 'red.js',
|
||||
options: {
|
||||
args:['-v'],
|
||||
ext: 'js,html',
|
||||
watch: [
|
||||
'red','nodes'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
concurrent: {
|
||||
dev: {
|
||||
tasks: ['nodemon', 'watch'],
|
||||
options: {
|
||||
logConcurrentOutput: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
copy: {
|
||||
build: {
|
||||
files:[{
|
||||
cwd: 'editor/images',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'public/red/images/'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/vendor',
|
||||
src: [
|
||||
'ace/**',
|
||||
'bootstrap/css/**',
|
||||
'bootstrap/img/**',
|
||||
'jquery/css/**',
|
||||
'font-awesome/**'
|
||||
],
|
||||
expand: true,
|
||||
dest: 'public/vendor/'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/icons',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'public/icons/'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
src: ['editor/index.html','editor/favicon.ico'],
|
||||
dest: 'public/',
|
||||
flatten: true
|
||||
}]
|
||||
},
|
||||
release: {
|
||||
files: [{
|
||||
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 %>')
|
||||
}]
|
||||
}
|
||||
},
|
||||
|
||||
compress: {
|
||||
release: {
|
||||
options: {
|
||||
archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip'
|
||||
},
|
||||
expand: true,
|
||||
cwd: '<%= paths.dist %>/',
|
||||
src: ['node-red-<%= pkg.version %>/**']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
grunt.loadNpmTasks('grunt-simple-mocha');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-concurrent');
|
||||
grunt.loadNpmTasks('grunt-sass');
|
||||
grunt.loadNpmTasks('grunt-nodemon');
|
||||
grunt.loadNpmTasks('grunt-contrib-compress');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
|
||||
grunt.registerTask('default', ['jshint:core','jshint:tests','jshint:editor','simplemocha:core','simplemocha:nodes']);
|
||||
|
||||
grunt.registerMultiTask('attachCopyright', function() {
|
||||
var files = this.data.src;
|
||||
var copyright = "/**\n"+
|
||||
" * Copyright 2013, 2015 IBM Corp.\n"+
|
||||
" *\n"+
|
||||
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+
|
||||
" * you may not use this file except in compliance with the License.\n"+
|
||||
" * You may obtain a copy of the License at\n"+
|
||||
" *\n"+
|
||||
" * http://www.apache.org/licenses/LICENSE-2.0\n"+
|
||||
" *\n"+
|
||||
" * Unless required by applicable law or agreed to in writing, software\n"+
|
||||
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"+
|
||||
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"+
|
||||
" * See the License for the specific language governing permissions and\n"+
|
||||
" * limitations under the License.\n"+
|
||||
" **/\n";
|
||||
|
||||
if (files) {
|
||||
for (var i=0;i<files.length;i++) {
|
||||
var file = files[i];
|
||||
if (!grunt.file.exists(file)) {
|
||||
grunt.log.warn('File '+ file + ' not found');
|
||||
return false;
|
||||
} else {
|
||||
var content = grunt.file.read(file);
|
||||
if (content.indexOf(copyright) == -1) {
|
||||
content = copyright+content;
|
||||
if (!grunt.file.write(file, content)) {
|
||||
return false;
|
||||
}
|
||||
grunt.log.writeln("Attached copyright to "+file);
|
||||
} else {
|
||||
grunt.log.writeln("Copyright already on "+file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('setDevEnv',
|
||||
'Sets NODE_ENV=development so non-minified assets are used',
|
||||
function () {
|
||||
process.env.NODE_ENV = 'development';
|
||||
});
|
||||
|
||||
grunt.registerTask('default',
|
||||
'Builds editor content then runs code style checks and unit tests on all components',
|
||||
['build','test-core','test-editor','test-nodes']);
|
||||
|
||||
grunt.registerTask('test-core',
|
||||
'Runs code style check and unit tests on core runtime code',
|
||||
['jshint:core','simplemocha:core']);
|
||||
|
||||
grunt.registerTask('test-editor',
|
||||
'Runs code style check on editor code',
|
||||
['jshint:editor']);
|
||||
|
||||
grunt.registerTask('test-nodes',
|
||||
'Runs unit tests on core nodes',
|
||||
['simplemocha:nodes']);
|
||||
|
||||
grunt.registerTask('build',
|
||||
'Builds editor content',
|
||||
['clean:build','concat:build','concat:vendor','uglify:build','sass:build','copy:build','attachCopyright']);
|
||||
|
||||
grunt.registerTask('dev',
|
||||
'Developer mode: run node-red, watch for source changes and build/restart',
|
||||
['build','setDevEnv','concurrent:dev']);
|
||||
|
||||
grunt.registerTask('release',
|
||||
'Create distribution zip file',
|
||||
['build','clean:release','copy:release','compress:release']);
|
||||
|
||||
};
|
||||
|
57
INSTALL.md
@@ -1,57 +0,0 @@
|
||||
Node-RED Install
|
||||
================
|
||||
|
||||
## Install node.js
|
||||
|
||||
You can get the latest version from <http://nodejs.org/download/>.
|
||||
|
||||
Or, you may want to use a version from your operating system's package manager:
|
||||
<https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager>
|
||||
|
||||
## Get Node-RED
|
||||
|
||||
Clone the repository from GitHub:
|
||||
|
||||
$ git clone git@github.com:node-red/node-red.git
|
||||
|
||||
## Install the pre-requisite modules
|
||||
|
||||
From the top-level directory of Node-RED, run:
|
||||
|
||||
$ npm install
|
||||
|
||||
This will install the core pre-requisite modules.
|
||||
|
||||
## Run Node-RED
|
||||
|
||||
From the top-level directory, run:
|
||||
|
||||
$ node red.js
|
||||
|
||||
You can then access Node-RED at <http://localhost:1880>.
|
||||
|
||||
Online documentation is available at <http://nodered.org/docs>.
|
||||
|
||||
## Installing individual node dependencies
|
||||
|
||||
When Node-RED starts, it attempts to load the nodes from the `nodes/` directory.
|
||||
Each will have its own set of dependencies that will need to be installed before
|
||||
the node is available in the palette.
|
||||
|
||||
To help identify the dependencies, Node-RED logs any modules it fails to find
|
||||
for a particular node. You don't have to install these unless you want or need
|
||||
that node to appear.
|
||||
|
||||
Alternatively, a node's `.js` file can be examined to identify the modules it
|
||||
explicitly requires. For example, the Twitter node is defined in
|
||||
`nodes/social/27-twitter.js` and contains:
|
||||
|
||||
var RED = require("../../red/red");
|
||||
var ntwitter = require('ntwitter');
|
||||
var OAuth= require('oauth').OAuth;
|
||||
|
||||
Of these, `ntwitter` and `oauth` are neither built-in modules nor ones provided
|
||||
by Node-RED itself. They can subsequently be installed by running:
|
||||
|
||||
$ npm install ntwitter oauth
|
||||
|
50
README.md
@@ -2,39 +2,58 @@
|
||||
|
||||
http://nodered.org
|
||||
|
||||
[](https://travis-ci.org/node-red/node-red) [](https://coveralls.io/r/node-red/node-red?branch=master)
|
||||
|
||||
[](https://travis-ci.org/node-red/node-red)
|
||||
[](https://coveralls.io/r/node-red/node-red?branch=master)
|
||||
|
||||
A visual tool for wiring the Internet of Things.
|
||||
|
||||

|
||||

|
||||
|
||||
## Quick Start
|
||||
|
||||
Check out [INSTALL](INSTALL.md) for full instructions on getting started.
|
||||
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
started.
|
||||
|
||||
1. download the zip and unzip, or git clone
|
||||
2. cd node-red
|
||||
3. npm install
|
||||
4. node red.js
|
||||
5. Open <http://localhost:1880>
|
||||
1. `sudo npm install -g node-red`
|
||||
2. `node-red`
|
||||
3. Open <http://localhost:1880>
|
||||
|
||||
## Getting Help
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, please use the [mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
For further help, or general discussion, please use the
|
||||
[mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
|
||||
## Browser Support
|
||||
## Developers
|
||||
|
||||
The Node-RED editor runs in the browser. We routinely develop and test using
|
||||
Chrome and Firefox. We have anecdotal evidence that it works in recent versions of IE.
|
||||
If you want to run the latest code from git, here's how to get started:
|
||||
|
||||
We have basic support for using in mobile/tablet browsers.
|
||||
1. Install grunt, the build tool
|
||||
|
||||
npm install -g grunt-cli
|
||||
|
||||
2. Clone the code:
|
||||
|
||||
git clone https://github.com/node-red/node-red.git
|
||||
cd node-red
|
||||
|
||||
3. Install the node-red dependencies
|
||||
|
||||
npm install
|
||||
|
||||
4. Build the code
|
||||
|
||||
grunt build
|
||||
|
||||
5. Run
|
||||
|
||||
node red.js
|
||||
|
||||
## Contributing
|
||||
|
||||
Before raising a pull-request, please read our [contributing guide](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md).
|
||||
Before raising a pull-request, please read our
|
||||
[contributing guide](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md).
|
||||
|
||||
## Authors
|
||||
|
||||
@@ -48,3 +67,4 @@ For more open-source projects from IBM, head over [here](http://ibm.github.io).
|
||||
## Copyright and license
|
||||
|
||||
Copyright 2013, 2015 IBM Corp. under [the Apache 2.0 license](LICENSE).
|
||||
|
||||
|
43
bin/node-red-pi
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2015 IBM Corp.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Separate out node/v8 options from node-red ones
|
||||
OPTIONS=""
|
||||
ARGS=""
|
||||
|
||||
for arg in "$@"
|
||||
do
|
||||
case $arg in
|
||||
--userDir|--settings|--help) ARGS="$ARGS $arg";;
|
||||
--*) OPTIONS="$OPTIONS $arg";;
|
||||
*) ARGS="$ARGS $arg";;
|
||||
esac
|
||||
done
|
||||
|
||||
# Find the real location of this script
|
||||
CURRENT_PATH=`pwd`
|
||||
SCRIPT_PATH="${BASH_SOURCE[0]}";
|
||||
while([ -h "${SCRIPT_PATH}" ]); do
|
||||
cd "`dirname "${SCRIPT_PATH}"`"
|
||||
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
|
||||
done
|
||||
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
|
||||
SCRIPT_PATH="`pwd`";
|
||||
cd $CURRENT_PATH
|
||||
|
||||
# Run Node-RED
|
||||
/usr/bin/env node $OPTIONS $SCRIPT_PATH/../red.js $ARGS
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 308 B After Width: | Height: | Size: 308 B |
Before Width: | Height: | Size: 603 B After Width: | Height: | Size: 603 B |
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 393 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 609 B |
Before Width: | Height: | Size: 575 B After Width: | Height: | Size: 575 B |
Before Width: | Height: | Size: 601 B After Width: | Height: | Size: 601 B |
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 218 B After Width: | Height: | Size: 218 B |
Before Width: | Height: | Size: 324 B After Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 378 B After Width: | Height: | Size: 378 B |
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 457 B |
Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 502 B |
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 639 B After Width: | Height: | Size: 639 B |
Before Width: | Height: | Size: 414 B After Width: | Height: | Size: 414 B |
Before Width: | Height: | Size: 671 B After Width: | Height: | Size: 671 B |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 386 B |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 386 B |
Before Width: | Height: | Size: 360 B After Width: | Height: | Size: 360 B |
Before Width: | Height: | Size: 736 B After Width: | Height: | Size: 736 B |
Before Width: | Height: | Size: 482 B After Width: | Height: | Size: 482 B |
Before Width: | Height: | Size: 273 B After Width: | Height: | Size: 273 B |
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 439 B |
Before Width: | Height: | Size: 592 B After Width: | Height: | Size: 592 B |
Before Width: | Height: | Size: 509 B After Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 488 B |
Before Width: | Height: | Size: 628 B After Width: | Height: | Size: 628 B |
Before Width: | Height: | Size: 258 B After Width: | Height: | Size: 258 B |
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 404 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 707 B |
Before Width: | Height: | Size: 291 B After Width: | Height: | Size: 291 B |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 386 B |
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 368 B |
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 223 B After Width: | Height: | Size: 223 B |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 1019 B After Width: | Height: | Size: 1019 B |
Before Width: | Height: | Size: 600 B After Width: | Height: | Size: 600 B |
@@ -4,9 +4,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
|
||||
<!--
|
||||
Copyright 2013, 2014 IBM Corp.
|
||||
Copyright 2013, 2015 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -22,27 +21,22 @@
|
||||
-->
|
||||
<head>
|
||||
<title>Node-RED</title>
|
||||
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<link href="jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="orion/built-editor.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="font-awesome/css/font-awesome.min.css"/>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<link href="vendor/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="vendor/vendor.css">
|
||||
<link rel="stylesheet" href="red/style.min.css">
|
||||
</head>
|
||||
<body spellcheck="false">
|
||||
<div id="header">
|
||||
<span class="logo"><img src="node-red.png"> <span>Node-RED</span></span>
|
||||
<span class="logo"><img src="red/images/node-red.png"> <span>Node-RED</span></span>
|
||||
<ul class="header-toolbar hide">
|
||||
<li><span class="deploy-button-group button-group">
|
||||
<a id="btn-deploy" class="action-deploy disabled" href="#"><img id="btn-icn-deploy" src="images/deploy-full-o.png"> <span>Deploy</span></a>
|
||||
<a id="btn-deploy-options" data-toggle="dropdown" class="" href="#"><i class="fa fa-caret-down"></i></a>
|
||||
</span></li>
|
||||
<li><a id="btn-usermenu" class="button hide" data-toggle="dropdown" href="#"><i class="fa fa-user"></i></a></li>
|
||||
<li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li>
|
||||
<ul>
|
||||
</div>
|
||||
<div id="main-container" class="sidebar-closed hide">
|
||||
<div id="palette">
|
||||
<img src="spin.svg" class="palette-spinner hide"/>
|
||||
<img src="red/images/spin.svg" class="palette-spinner hide"/>
|
||||
<div id="palette-container" class="palette-scroll">
|
||||
</div>
|
||||
<div id="palette-search">
|
||||
@@ -81,7 +75,6 @@
|
||||
|
||||
<div id="notifications"></div>
|
||||
<div id="dropTarget"><div>Drop the flow here<br/><i class="fa fa-download"></i></div></div>
|
||||
<div id="shade"></div>
|
||||
|
||||
<div id="dialog" class="hide"><form id="dialog-form" class="form-horizontal"></form></div>
|
||||
<div id="node-config-dialog" class="hide"><form id="dialog-config-form" class="form-horizontal"></form><div class="form-tips" id="node-config-dialog-user-count"></div></div>
|
||||
@@ -107,57 +100,6 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="node-help" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="node-help-label" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<h5 id="node-help-label">Keyboard Shortcuts <span style="float: right;"><a href="http://nodered.org/docs" target="_blank">Open help in new window »</a></span></h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table>
|
||||
<tr>
|
||||
<td><span class="help-key">?</span></td><td>Help</td>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">a</span></td><td>Select all nodes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">Space</span></td><td>Toggle sidebar</td>
|
||||
<td><span class="help-key">Shift</span> <span class="help-key">Click</span></td><td>Select all connected nodes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">z</span></td><td>Undo</td>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">Click</span></td><td>Add/remove node from selection</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td></td>
|
||||
<td><span class="help-key">Delete</span></td><td>Delete selected nodes or link</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">x</span></td><td>Cut selected nodes</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">c</span></td><td>Copy selected nodes</td>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">v</span></td><td>Paste nodes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">i</span></td><td>Import nodes</td>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">e</span></td><td>Export selected nodes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">+</span></td><td>Zoom in</td>
|
||||
<td><span class="help-key">Ctrl</span> <span class="help-key">-</span></td><td>Zoom out</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4">Mac users can use the <b>⌘ - Cmd</b> key rather than Ctrl key.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-save-confirm" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div style="text-align: center; padding-top: 30px;">
|
||||
@@ -211,27 +153,13 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script type="text/x-red" data-template-name="export-clipboard-dialog">
|
||||
<div class="form-row">
|
||||
<label for="node-input-export" style="display: block; width:100%;"><i class="fa fa-clipboard"></i> Nodes:</label>
|
||||
<textarea readonly style="font-family: monospace; font-size: 12px; background:rgb(226, 229, 255); padding-left: 0.5em;" class="input-block-level" id="node-input-export" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
Select the text above and copy to the clipboard with Ctrl-A Ctrl-C.
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="export-library-dialog">
|
||||
<div class="form-row">
|
||||
<label for="node-input-filename" ><i class="fa fa-file"></i> Filename:</label>
|
||||
<input type="text" id="node-input-filename" placeholder="Filename">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="import-dialog">
|
||||
<div class="form-row">
|
||||
<label for="node-input-import"><i class="fa fa-clipboard"></i> Nodes:</label>
|
||||
<textarea style="font-family: monospace; font-size: 12px; background:rgb(226, 229, 255); padding-left: 0.5em;" class="input-block-level" id="node-input-import" rows="5" placeholder="Paste nodes here"></textarea>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="subflow">
|
||||
<div class="form-row">
|
||||
@@ -240,33 +168,10 @@
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script src="jquery/js/jquery-1.11.1.min.js"></script>
|
||||
<script src="bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="jquery/js/jquery-ui-1.10.3.custom.min.js"></script>
|
||||
<script src="jquery/js/jquery.ui.touch-punch.min.js"></script>
|
||||
<script src="marked/marked.min.js"></script>
|
||||
<script src="orion/built-editor.min.js"></script>
|
||||
<script src="d3.v3.min.js"></script>
|
||||
<script src="red/main.js"></script>
|
||||
<script src="red/settings.js"></script>
|
||||
<script src="red/user.js"></script>
|
||||
<script src="red/comms.js"></script>
|
||||
<script src="red/ui/state.js"></script>
|
||||
<script src="red/nodes.js"></script>
|
||||
<script src="red/history.js"></script>
|
||||
<script src="red/validators.js"></script>
|
||||
<script src="red/ui/menu.js"></script>
|
||||
<script src="red/ui/keyboard.js"></script>
|
||||
<script src="red/ui/tabs.js"></script>
|
||||
<script src="red/ui/view.js"></script>
|
||||
<script src="red/ui/sidebar.js"></script>
|
||||
<script src="red/ui/palette.js"></script>
|
||||
<script src="red/ui/tab-info.js"></script>
|
||||
<script src="red/ui/tab-config.js"></script>
|
||||
<script src="red/ui/editor.js"></script>
|
||||
<script src="red/ui/library.js"></script>
|
||||
<script src="red/ui/notifications.js"></script>
|
||||
<script src="red/ui/touch/radialMenu.js"></script>
|
||||
<script src="vendor/vendor.js"></script>
|
||||
<script src="vendor/ace/ace.js"></script>
|
||||
<script src="vendor/ace/ext-language_tools.js"></script>
|
||||
<script src="red/red.min.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -95,15 +95,15 @@ RED.comms = (function() {
|
||||
}
|
||||
|
||||
function unsubscribe(topic,callback) {
|
||||
if (subscriptions.topic) {
|
||||
for (var i=0;i<subscriptions.topic.length;i++) {
|
||||
if (subscriptions.topic[i] === callback) {
|
||||
subscriptions.topic.splice(i,1);
|
||||
if (subscriptions[topic]) {
|
||||
for (var i=0;i<subscriptions[topic].length;i++) {
|
||||
if (subscriptions[topic][i] === callback) {
|
||||
subscriptions[topic].splice(i,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (subscriptions.topic.length === 0) {
|
||||
delete subscriptions.topic;
|
||||
if (subscriptions[topic].length === 0) {
|
||||
delete subscriptions[topic];
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,10 +32,16 @@ RED.history = (function() {
|
||||
pop: function() {
|
||||
var ev = undo_history.pop();
|
||||
var i;
|
||||
var node;
|
||||
var modifiedTabs = {};
|
||||
if (ev) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@@ -47,20 +53,20 @@ RED.history = (function() {
|
||||
if (ev.workspaces) {
|
||||
for (i=0;i<ev.workspaces.length;i++) {
|
||||
RED.nodes.removeWorkspace(ev.workspaces[i].id);
|
||||
RED.view.removeWorkspace(ev.workspaces[i]);
|
||||
RED.workspaces.remove(ev.workspaces[i]);
|
||||
}
|
||||
}
|
||||
if (ev.subflows) {
|
||||
for (i=0;i<ev.subflows.length;i++) {
|
||||
RED.nodes.removeSubflow(ev.subflows[i]);
|
||||
RED.view.removeWorkspace(ev.subflows[i]);
|
||||
RED.workspaces.remove(ev.subflows[i]);
|
||||
}
|
||||
}
|
||||
} else if (ev.t == "delete") {
|
||||
if (ev.workspaces) {
|
||||
for (i=0;i<ev.workspaces.length;i++) {
|
||||
RED.nodes.addWorkspace(ev.workspaces[i]);
|
||||
RED.view.addWorkspace(ev.workspaces[i]);
|
||||
RED.workspaces.add(ev.workspaces[i]);
|
||||
}
|
||||
}
|
||||
if (ev.subflow) {
|
||||
@@ -92,22 +98,21 @@ RED.history = (function() {
|
||||
}
|
||||
}
|
||||
if (subflow) {
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type == "subflow:"+subflow.id) {
|
||||
n.changed = true;
|
||||
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;
|
||||
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
|
||||
n.changed = true;
|
||||
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) {
|
||||
@@ -143,13 +148,11 @@ RED.history = (function() {
|
||||
ev.node.out = ev.node.out.concat(ev.subflow.outputs);
|
||||
}
|
||||
}
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type == "subflow:"+ev.node.id) {
|
||||
n.changed = ev.changed;
|
||||
n.inputs = ev.node.in.length;
|
||||
n.outputs = ev.node.out.length;
|
||||
RED.editor.updateNodeProperties(n);
|
||||
}
|
||||
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
|
||||
n.changed = ev.changed;
|
||||
n.inputs = ev.node.in.length;
|
||||
n.outputs = ev.node.out.length;
|
||||
RED.editor.updateNodeProperties(n);
|
||||
});
|
||||
|
||||
RED.palette.refresh();
|
||||
@@ -166,11 +169,9 @@ RED.history = (function() {
|
||||
ev.node.changed = ev.changed;
|
||||
} else if (ev.t == "createSubflow") {
|
||||
if (ev.nodes) {
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.z === ev.subflow.id) {
|
||||
n.z = ev.activeWorkspace;
|
||||
n.dirty = true;
|
||||
}
|
||||
RED.nodes.filterNodes({z:ev.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]);
|
||||
@@ -183,7 +184,7 @@ RED.history = (function() {
|
||||
}
|
||||
|
||||
RED.nodes.removeSubflow(ev.subflow);
|
||||
RED.view.removeWorkspace(ev.subflow);
|
||||
RED.workspaces.remove(ev.subflow);
|
||||
|
||||
if (ev.removedLinks) {
|
||||
for (i=0;i<ev.removedLinks.length;i++) {
|
||||
@@ -191,8 +192,17 @@ RED.history = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
RED.view.dirty(ev.dirty);
|
||||
RED.view.redraw();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
210
editor/js/main.js
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
var RED = (function() {
|
||||
|
||||
|
||||
function loadSettings() {
|
||||
RED.settings.init(loadNodeList);
|
||||
}
|
||||
|
||||
function loadNodeList() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"application/json"
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes',
|
||||
success: function(data) {
|
||||
RED.nodes.setNodeList(data);
|
||||
loadNodes();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadNodes() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html"
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes',
|
||||
success: function(data) {
|
||||
$("body").append(data);
|
||||
$(".palette-spinner").hide();
|
||||
$(".palette-scroll").show();
|
||||
$("#palette-search").show();
|
||||
loadFlows();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadFlows() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"application/json"
|
||||
},
|
||||
cache: false,
|
||||
url: 'flows',
|
||||
success: function(nodes) {
|
||||
RED.nodes.import(nodes);
|
||||
RED.nodes.dirty(false);
|
||||
RED.view.redraw(true);
|
||||
RED.comms.subscribe("status/#",function(topic,msg) {
|
||||
var parts = topic.split("/");
|
||||
var node = RED.nodes.node(parts[1]);
|
||||
if (node) {
|
||||
node.status = msg;
|
||||
if (statusEnabled) {
|
||||
node.dirty = true;
|
||||
RED.view.redraw();
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.comms.subscribe("node/#",function(topic,msg) {
|
||||
var i,m;
|
||||
var typeList;
|
||||
var info;
|
||||
|
||||
if (topic == "node/added") {
|
||||
var addedTypes = [];
|
||||
for (i=0;i<msg.length;i++) {
|
||||
m = msg[i];
|
||||
var id = m.id;
|
||||
RED.nodes.addNodeSet(m);
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
$.get('nodes/'+id, function(data) {
|
||||
$("body").append(data);
|
||||
});
|
||||
}
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(addedTypes.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
|
||||
}
|
||||
} else if (topic == "node/removed") {
|
||||
for (i=0;i<msg.length;i++) {
|
||||
m = msg[i];
|
||||
info = RED.nodes.removeNodeSet(m.id);
|
||||
if (info.added) {
|
||||
typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(m.types.length!=1 ? "s":"")+" removed from palette:"+typeList,"success");
|
||||
}
|
||||
}
|
||||
} else if (topic == "node/enabled") {
|
||||
if (msg.types) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" enabled:"+typeList,"success");
|
||||
} else {
|
||||
$.get('nodes/'+msg.id, function(data) {
|
||||
$("body").append(data);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (topic == "node/disabled") {
|
||||
if (msg.types) {
|
||||
RED.nodes.disableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" disabled:"+typeList,"success");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var statusEnabled = false;
|
||||
function toggleStatus(state) {
|
||||
statusEnabled = state;
|
||||
RED.view.status(statusEnabled);
|
||||
}
|
||||
|
||||
function loadEditor() {
|
||||
RED.menu.init({id:"btn-sidemenu",
|
||||
options: [
|
||||
{id:"menu-item-sidebar",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
|
||||
{id:"menu-item-status",label:"Display node status",toggle:true,onselect:toggleStatus, selected: true},
|
||||
null,
|
||||
{id:"menu-item-import",label:"Import",options:[
|
||||
{id:"menu-item-import-clipboard",label:"Clipboard",onselect:RED.clipboard.import},
|
||||
{id:"menu-item-import-library",label:"Library",options:[]}
|
||||
]},
|
||||
{id:"menu-item-export",label:"Export",disabled:true,options:[
|
||||
{id:"menu-item-export-clipboard",label:"Clipboard",disabled:true,onselect:RED.clipboard.export},
|
||||
{id:"menu-item-export-library",label:"Library",disabled:true,onselect:RED.library.export}
|
||||
]},
|
||||
null,
|
||||
{id:"menu-item-config-nodes",label:"Configuration nodes",onselect:RED.sidebar.config.show},
|
||||
null,
|
||||
{id:"menu-item-subflow",label:"Subflows", options: [
|
||||
{id:"menu-item-subflow-create",label:"Create subflow",onselect:RED.subflow.createSubflow},
|
||||
{id:"menu-item-subflow-convert",label:"Selection to subflow",disabled:true,onselect:RED.subflow.convertToSubflow},
|
||||
]},
|
||||
null,
|
||||
{id:"menu-item-workspace",label:"Workspaces",options:[
|
||||
{id:"menu-item-workspace-add",label:"Add",onselect:RED.workspaces.add},
|
||||
{id:"menu-item-workspace-edit",label:"Rename",onselect:RED.workspaces.edit},
|
||||
{id:"menu-item-workspace-delete",label:"Delete",onselect:RED.workspaces.remove},
|
||||
null
|
||||
]},
|
||||
null,
|
||||
{id:"menu-item-keyboard-shortcuts",label:"Keyboard Shortcuts",onselect:RED.keyboard.showHelp},
|
||||
{id:"menu-item-help",
|
||||
label: RED.settings.theme("menu.menu-item-help.label","Node-RED Website"),
|
||||
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
RED.user.init();
|
||||
|
||||
RED.library.init();
|
||||
RED.palette.init();
|
||||
RED.sidebar.init();
|
||||
RED.subflow.init();
|
||||
RED.workspaces.init();
|
||||
RED.clipboard.init();
|
||||
RED.view.init();
|
||||
|
||||
RED.deploy.init(RED.settings.theme("deployButton",null));
|
||||
|
||||
RED.keyboard.add(/* ? */ 191,{shift:true},function(){RED.keyboard.showHelp();d3.event.preventDefault();});
|
||||
RED.comms.connect();
|
||||
|
||||
$("#main-container").show();
|
||||
$(".header-toolbar").show();
|
||||
|
||||
loadNodeList();
|
||||
}
|
||||
|
||||
$(function() {
|
||||
|
||||
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
|
||||
document.title = document.title+" : "+window.location.hostname;
|
||||
}
|
||||
|
||||
ace.require("ace/ext/language_tools");
|
||||
|
||||
RED.settings.init(loadEditor);
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
};
|
||||
})();
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,13 @@ RED.nodes = (function() {
|
||||
var workspaces = {};
|
||||
var subflows = {};
|
||||
|
||||
var dirty = false;
|
||||
|
||||
function setDirty(d) {
|
||||
dirty = d;
|
||||
eventHandler.emit("change",{dirty:dirty});
|
||||
}
|
||||
|
||||
var registry = (function() {
|
||||
var nodeList = [];
|
||||
var nodeSets = {};
|
||||
@@ -160,13 +167,13 @@ RED.nodes = (function() {
|
||||
}
|
||||
nodes.push(n);
|
||||
}
|
||||
if (n._def.onadd) {
|
||||
n._def.onadd.call(n);
|
||||
}
|
||||
}
|
||||
function addLink(l) {
|
||||
links.push(l);
|
||||
}
|
||||
function addConfig(c) {
|
||||
configNodes[c.id] = c;
|
||||
}
|
||||
|
||||
function getNode(id) {
|
||||
if (id in configNodes) {
|
||||
@@ -183,11 +190,13 @@ RED.nodes = (function() {
|
||||
|
||||
function removeNode(id) {
|
||||
var removedLinks = [];
|
||||
var node;
|
||||
if (id in configNodes) {
|
||||
node = configNodes[id];
|
||||
delete configNodes[id];
|
||||
RED.sidebar.config.refresh();
|
||||
} else {
|
||||
var node = getNode(id);
|
||||
node = getNode(id);
|
||||
if (node) {
|
||||
nodes.splice(nodes.indexOf(node),1);
|
||||
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
|
||||
@@ -214,6 +223,9 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node._def.onremove) {
|
||||
node._def.onremove.call(n);
|
||||
}
|
||||
return removedLinks;
|
||||
}
|
||||
|
||||
@@ -224,12 +236,6 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function refreshValidation() {
|
||||
for (var n=0;n<nodes.length;n++) {
|
||||
RED.editor.validateNode(nodes[n]);
|
||||
}
|
||||
}
|
||||
|
||||
function addWorkspace(ws) {
|
||||
workspaces[ws.id] = ws;
|
||||
}
|
||||
@@ -254,7 +260,24 @@ RED.nodes = (function() {
|
||||
return {nodes:removedNodes,links:removedLinks};
|
||||
}
|
||||
|
||||
function addSubflow(sf) {
|
||||
function addSubflow(sf, createNewIds) {
|
||||
if (createNewIds) {
|
||||
var subflowNames = Object.keys(subflows).map(function(sfid) {
|
||||
return subflows[sfid].name;
|
||||
});
|
||||
|
||||
subflowNames.sort();
|
||||
var copyNumber = 1;
|
||||
var subflowName = sf.name;
|
||||
subflowNames.forEach(function(name) {
|
||||
if (subflowName == name) {
|
||||
copyNumber++;
|
||||
subflowName = sf.name+" ("+copyNumber+")";
|
||||
}
|
||||
});
|
||||
sf.name = subflowName;
|
||||
}
|
||||
|
||||
subflows[sf.id] = sf;
|
||||
RED.nodes.registerType("subflow:"+sf.id, {
|
||||
defaults:{name:{value:""}},
|
||||
@@ -424,16 +447,16 @@ RED.nodes = (function() {
|
||||
var exportedConfigNodes = {};
|
||||
var exportedSubflows = {};
|
||||
for (var n=0;n<set.length;n++) {
|
||||
var node = set[n].n;
|
||||
var node = set[n];
|
||||
if (node.type.substring(0,8) == "subflow:") {
|
||||
var subflowId = node.type.substring(8);
|
||||
if (!exportedSubflows[subflowId]) {
|
||||
exportedSubflows[subflowId] = true;
|
||||
var subflow = getSubflow(subflowId);
|
||||
var subflowSet = [{n:subflow}];
|
||||
var subflowSet = [subflow];
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.z == subflowId) {
|
||||
subflowSet.push({n:n});
|
||||
subflowSet.push(n);
|
||||
}
|
||||
});
|
||||
var exportableSubflow = createExportableNodeSet(subflowSet);
|
||||
@@ -494,279 +517,340 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
function importNodes(newNodesObj,createNewIds) {
|
||||
try {
|
||||
var i;
|
||||
var n;
|
||||
var newNodes;
|
||||
if (typeof newNodesObj === "string") {
|
||||
if (newNodesObj === "") {
|
||||
return;
|
||||
}
|
||||
var i;
|
||||
var n;
|
||||
var newNodes;
|
||||
if (typeof newNodesObj === "string") {
|
||||
if (newNodesObj === "") {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
newNodes = JSON.parse(newNodesObj);
|
||||
} else {
|
||||
newNodes = newNodesObj;
|
||||
} catch(err) {
|
||||
var e = new Error("Invalid flow: "+err.message);
|
||||
e.code = "NODE_RED";
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
newNodes = newNodesObj;
|
||||
}
|
||||
|
||||
if (!$.isArray(newNodes)) {
|
||||
newNodes = [newNodes];
|
||||
}
|
||||
var unknownTypes = [];
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type != "workspace" &&
|
||||
n.type != "tab" &&
|
||||
n.type != "subflow" &&
|
||||
!registry.getNodeType(n.type) &&
|
||||
n.type.substring(0,8) != "subflow:") {
|
||||
// TODO: get this UI thing out of here! (see below as well)
|
||||
|
||||
if (unknownTypes.indexOf(n.type)==-1) {
|
||||
unknownTypes.push(n.type);
|
||||
}
|
||||
//if (n.x == null && n.y == null) {
|
||||
// // config node - remove it
|
||||
// newNodes.splice(i,1);
|
||||
// i--;
|
||||
//}
|
||||
}
|
||||
}
|
||||
if (unknownTypes.length > 0) {
|
||||
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
|
||||
var type = "type"+(unknownTypes.length > 1?"s":"");
|
||||
RED.notify("<strong>Imported unrecognised "+type+":</strong>"+typeList,"error",false,10000);
|
||||
//"DO NOT DEPLOY while in this state.<br/>Either, add missing types to Node-RED, restart and then reload page,<br/>or delete unknown "+n.name+", rewire as required, and then deploy.","error");
|
||||
}
|
||||
|
||||
var activeWorkspace = RED.view.getWorkspace();
|
||||
var activeSubflow = getSubflow(activeWorkspace);
|
||||
if (activeSubflow) {
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
var m = /^subflow:(.+)$/.exec(newNodes[i].type);
|
||||
if (m) {
|
||||
var subflowId = m[1];
|
||||
var err;
|
||||
if (subflowId === activeSubflow.id) {
|
||||
err = new Error("Cannot add subflow to itself");
|
||||
}
|
||||
if (subflowContains(m[1],activeSubflow.id)) {
|
||||
err = new Error("Cannot add subflow - circular reference detected");
|
||||
}
|
||||
if (err) {
|
||||
// TODO: standardise error codes
|
||||
err.code = "NODE_RED";
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$.isArray(newNodes)) {
|
||||
newNodes = [newNodes];
|
||||
}
|
||||
var unknownTypes = [];
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type != "workspace" &&
|
||||
n.type != "tab" &&
|
||||
n.type != "subflow" &&
|
||||
!registry.getNodeType(n.type) &&
|
||||
n.type.substring(0,8) != "subflow:" &&
|
||||
unknownTypes.indexOf(n.type)==-1) {
|
||||
|
||||
var new_workspaces = [];
|
||||
var workspace_map = {};
|
||||
var new_subflows = [];
|
||||
var subflow_map = {};
|
||||
var nid;
|
||||
unknownTypes.push(n.type);
|
||||
}
|
||||
}
|
||||
if (unknownTypes.length > 0) {
|
||||
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
|
||||
var type = "type"+(unknownTypes.length > 1?"s":"");
|
||||
RED.notify("<strong>Imported unrecognised "+type+":</strong>"+typeList,"error",false,10000);
|
||||
//"DO NOT DEPLOY while in this state.<br/>Either, add missing types to Node-RED, restart and then reload page,<br/>or delete unknown "+n.name+", rewire as required, and then deploy.","error");
|
||||
}
|
||||
|
||||
var activeWorkspace = RED.workspaces.active();
|
||||
var activeSubflow = getSubflow(activeWorkspace);
|
||||
if (activeSubflow) {
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type === "workspace" || n.type === "tab") {
|
||||
if (n.type === "workspace") {
|
||||
n.type = "tab";
|
||||
var m = /^subflow:(.+)$/.exec(newNodes[i].type);
|
||||
if (m) {
|
||||
var subflowId = m[1];
|
||||
var err;
|
||||
if (subflowId === activeSubflow.id) {
|
||||
err = new Error("Cannot add subflow to itself");
|
||||
}
|
||||
if (defaultWorkspace == null) {
|
||||
defaultWorkspace = n;
|
||||
if (subflowContains(m[1],activeSubflow.id)) {
|
||||
err = new Error("Cannot add subflow - circular reference detected");
|
||||
}
|
||||
if (createNewIds) {
|
||||
nid = getID();
|
||||
workspace_map[n.id] = nid;
|
||||
n.id = nid;
|
||||
if (err) {
|
||||
// TODO: standardise error codes
|
||||
err.code = "NODE_RED";
|
||||
throw err;
|
||||
}
|
||||
addWorkspace(n);
|
||||
RED.view.addWorkspace(n);
|
||||
new_workspaces.push(n);
|
||||
} else if (n.type === "subflow") {
|
||||
subflow_map[n.id] = n;
|
||||
if (createNewIds) {
|
||||
nid = getID();
|
||||
n.id = nid;
|
||||
}
|
||||
// TODO: handle createNewIds - map old to new subflow ids
|
||||
n.in.forEach(function(input,i) {
|
||||
input.type = "subflow";
|
||||
input.direction = "in";
|
||||
input.z = n.id;
|
||||
input.i = i;
|
||||
input.id = getID();
|
||||
});
|
||||
n.out.forEach(function(output,i) {
|
||||
output.type = "subflow";
|
||||
output.direction = "out";
|
||||
output.z = n.id;
|
||||
output.i = i;
|
||||
output.id = getID();
|
||||
});
|
||||
new_subflows.push(n);
|
||||
addSubflow(n);
|
||||
|
||||
}
|
||||
}
|
||||
if (defaultWorkspace == null) {
|
||||
defaultWorkspace = { type:"tab", id:getID(), label:"Sheet 1" };
|
||||
addWorkspace(defaultWorkspace);
|
||||
RED.view.addWorkspace(defaultWorkspace);
|
||||
new_workspaces.push(defaultWorkspace);
|
||||
}
|
||||
|
||||
var node_map = {};
|
||||
var new_nodes = [];
|
||||
var new_links = [];
|
||||
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type !== "workspace" && n.type !== "tab" && n.type !== "subflow") {
|
||||
var def = registry.getNodeType(n.type);
|
||||
if (def && def.category == "config") {
|
||||
if (!RED.nodes.node(n.id)) {
|
||||
var configNode = {id:n.id,type:n.type,users:[]};
|
||||
for (var d in def.defaults) {
|
||||
if (def.defaults.hasOwnProperty(d)) {
|
||||
configNode[d] = n[d];
|
||||
}
|
||||
}
|
||||
|
||||
var new_workspaces = [];
|
||||
var workspace_map = {};
|
||||
var new_subflows = [];
|
||||
var subflow_map = {};
|
||||
var nid;
|
||||
var def;
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type === "workspace" || n.type === "tab") {
|
||||
if (n.type === "workspace") {
|
||||
n.type = "tab";
|
||||
}
|
||||
if (defaultWorkspace == null) {
|
||||
defaultWorkspace = n;
|
||||
}
|
||||
if (createNewIds) {
|
||||
nid = getID();
|
||||
workspace_map[n.id] = nid;
|
||||
n.id = nid;
|
||||
}
|
||||
addWorkspace(n);
|
||||
RED.workspaces.add(n);
|
||||
new_workspaces.push(n);
|
||||
} else if (n.type === "subflow") {
|
||||
subflow_map[n.id] = n;
|
||||
if (createNewIds) {
|
||||
nid = getID();
|
||||
n.id = nid;
|
||||
}
|
||||
// TODO: handle createNewIds - map old to new subflow ids
|
||||
n.in.forEach(function(input,i) {
|
||||
input.type = "subflow";
|
||||
input.direction = "in";
|
||||
input.z = n.id;
|
||||
input.i = i;
|
||||
input.id = getID();
|
||||
});
|
||||
n.out.forEach(function(output,i) {
|
||||
output.type = "subflow";
|
||||
output.direction = "out";
|
||||
output.z = n.id;
|
||||
output.i = i;
|
||||
output.id = getID();
|
||||
});
|
||||
new_subflows.push(n);
|
||||
addSubflow(n,createNewIds);
|
||||
} else {
|
||||
def = registry.getNodeType(n.type);
|
||||
if (def && def.category == "config") {
|
||||
if (!RED.nodes.node(n.id)) {
|
||||
var configNode = {id:n.id,type:n.type,users:[]};
|
||||
for (var d in def.defaults) {
|
||||
if (def.defaults.hasOwnProperty(d)) {
|
||||
configNode[d] = n[d];
|
||||
}
|
||||
configNode.label = def.label;
|
||||
configNode._def = def;
|
||||
RED.nodes.add(configNode);
|
||||
}
|
||||
} else {
|
||||
var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false};
|
||||
if (createNewIds) {
|
||||
if (subflow_map[node.z]) {
|
||||
node.z = subflow_map[node.z].id;
|
||||
} else {
|
||||
node.z = workspace_map[node.z];
|
||||
if (!workspaces[node.z]) {
|
||||
node.z = activeWorkspace;
|
||||
}
|
||||
}
|
||||
node.id = getID();
|
||||
configNode.label = def.label;
|
||||
configNode._def = def;
|
||||
RED.nodes.add(configNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (defaultWorkspace == null) {
|
||||
defaultWorkspace = { type:"tab", id:getID(), label:"Sheet 1" };
|
||||
addWorkspace(defaultWorkspace);
|
||||
RED.workspaces.add(defaultWorkspace);
|
||||
new_workspaces.push(defaultWorkspace);
|
||||
activeWorkspace = RED.workspaces.active();
|
||||
}
|
||||
|
||||
var node_map = {};
|
||||
var new_nodes = [];
|
||||
var new_links = [];
|
||||
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type !== "workspace" && n.type !== "tab" && n.type !== "subflow") {
|
||||
def = registry.getNodeType(n.type);
|
||||
if (!def || def.category != "config") {
|
||||
var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false};
|
||||
if (createNewIds) {
|
||||
if (subflow_map[node.z]) {
|
||||
node.z = subflow_map[node.z].id;
|
||||
} else {
|
||||
node.id = n.id;
|
||||
if (node.z == null || (!workspaces[node.z] && !subflow_map[node.z])) {
|
||||
node.z = workspace_map[node.z];
|
||||
if (!workspaces[node.z]) {
|
||||
node.z = activeWorkspace;
|
||||
}
|
||||
}
|
||||
node.type = n.type;
|
||||
node._def = def;
|
||||
if (n.type.substring(0,7) === "subflow") {
|
||||
var parentId = n.type.split(":")[1];
|
||||
var subflow = subflow_map[parentId]||getSubflow(parentId);
|
||||
if (createNewIds) {
|
||||
parentId = subflow.id;
|
||||
node.type = "subflow:"+parentId;
|
||||
node._def = registry.getNodeType(node.type);
|
||||
delete node.i;
|
||||
}
|
||||
node.name = n.name;
|
||||
node.outputs = subflow.out.length;
|
||||
node.inputs = subflow.in.length;
|
||||
} else {
|
||||
if (!node._def) {
|
||||
if (node.x && node.y) {
|
||||
node._def = {
|
||||
color:"#fee",
|
||||
defaults: {},
|
||||
label: "unknown: "+n.type,
|
||||
labelStyle: "node_label_italic",
|
||||
outputs: n.outputs||n.wires.length
|
||||
}
|
||||
} else {
|
||||
node._def = {
|
||||
category:"config"
|
||||
};
|
||||
node.users = [];
|
||||
}
|
||||
var orig = {};
|
||||
for (var p in n) {
|
||||
if (n.hasOwnProperty(p) && p!="x" && p!="y" && p!="z" && p!="id" && p!="wires") {
|
||||
orig[p] = n[p];
|
||||
}
|
||||
}
|
||||
node._orig = orig;
|
||||
node.name = n.type;
|
||||
node.type = "unknown";
|
||||
}
|
||||
if (node._def.category != "config") {
|
||||
node.inputs = n.inputs||node._def.inputs;
|
||||
node.outputs = n.outputs||node._def.outputs;
|
||||
for (var d2 in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d2)) {
|
||||
node[d2] = n[d2];
|
||||
}
|
||||
}
|
||||
}
|
||||
node.id = getID();
|
||||
} else {
|
||||
node.id = n.id;
|
||||
if (node.z == null || (!workspaces[node.z] && !subflow_map[node.z])) {
|
||||
node.z = activeWorkspace;
|
||||
}
|
||||
}
|
||||
node.type = n.type;
|
||||
node._def = def;
|
||||
if (n.type.substring(0,7) === "subflow") {
|
||||
var parentId = n.type.split(":")[1];
|
||||
var subflow = subflow_map[parentId]||getSubflow(parentId);
|
||||
if (createNewIds) {
|
||||
parentId = subflow.id;
|
||||
node.type = "subflow:"+parentId;
|
||||
node._def = registry.getNodeType(node.type);
|
||||
delete node.i;
|
||||
}
|
||||
node.name = n.name;
|
||||
node.outputs = subflow.out.length;
|
||||
node.inputs = subflow.in.length;
|
||||
} else {
|
||||
if (!node._def) {
|
||||
if (node.x && node.y) {
|
||||
node._def = {
|
||||
color:"#fee",
|
||||
defaults: {},
|
||||
label: "unknown: "+n.type,
|
||||
labelStyle: "node_label_italic",
|
||||
outputs: n.outputs||n.wires.length
|
||||
}
|
||||
} else {
|
||||
node._def = {
|
||||
category:"config"
|
||||
};
|
||||
node.users = [];
|
||||
}
|
||||
var orig = {};
|
||||
for (var p in n) {
|
||||
if (n.hasOwnProperty(p) && p!="x" && p!="y" && p!="z" && p!="id" && p!="wires") {
|
||||
orig[p] = n[p];
|
||||
}
|
||||
}
|
||||
node._orig = orig;
|
||||
node.name = n.type;
|
||||
node.type = "unknown";
|
||||
}
|
||||
addNode(node);
|
||||
RED.editor.validateNode(node);
|
||||
node_map[n.id] = node;
|
||||
if (node._def.category != "config") {
|
||||
new_nodes.push(node);
|
||||
node.inputs = n.inputs||node._def.inputs;
|
||||
node.outputs = n.outputs||node._def.outputs;
|
||||
for (var d2 in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d2)) {
|
||||
node[d2] = n[d2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
addNode(node);
|
||||
RED.editor.validateNode(node);
|
||||
node_map[n.id] = node;
|
||||
if (node._def.category != "config") {
|
||||
new_nodes.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0;i<new_nodes.length;i++) {
|
||||
n = new_nodes[i];
|
||||
for (var w1=0;w1<n.wires.length;w1++) {
|
||||
var wires = (n.wires[w1] instanceof Array)?n.wires[w1]:[n.wires[w1]];
|
||||
for (var w2=0;w2<wires.length;w2++) {
|
||||
if (wires[w2] in node_map) {
|
||||
var link = {source:n,sourcePort:w1,target:node_map[wires[w2]]};
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete n.wires;
|
||||
}
|
||||
for (i=0;i<new_subflows.length;i++) {
|
||||
n = new_subflows[i];
|
||||
n.in.forEach(function(input) {
|
||||
input.wires.forEach(function(wire) {
|
||||
var link = {source:input, sourcePort:0, target:node_map[wire.id]};
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
});
|
||||
delete input.wires;
|
||||
});
|
||||
n.out.forEach(function(output) {
|
||||
output.wires.forEach(function(wire) {
|
||||
var link;
|
||||
if (wire.id == n.id) {
|
||||
link = {source:n.in[wire.port], sourcePort:wire.port,target:output};
|
||||
} else {
|
||||
link = {source:node_map[wire.id], sourcePort:wire.port,target:output};
|
||||
}
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
});
|
||||
delete output.wires;
|
||||
});
|
||||
}
|
||||
return [new_nodes,new_links,new_workspaces,new_subflows];
|
||||
} catch(error) {
|
||||
if (error.code != "NODE_RED") {
|
||||
console.log(error.stack);
|
||||
RED.notify("<strong>Error</strong>: "+error,"error");
|
||||
} else {
|
||||
RED.notify("<strong>Error</strong>: "+error.message,"error");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
for (i=0;i<new_nodes.length;i++) {
|
||||
n = new_nodes[i];
|
||||
for (var w1=0;w1<n.wires.length;w1++) {
|
||||
var wires = (n.wires[w1] instanceof Array)?n.wires[w1]:[n.wires[w1]];
|
||||
for (var w2=0;w2<wires.length;w2++) {
|
||||
if (wires[w2] in node_map) {
|
||||
var link = {source:n,sourcePort:w1,target:node_map[wires[w2]]};
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete n.wires;
|
||||
}
|
||||
for (i=0;i<new_subflows.length;i++) {
|
||||
n = new_subflows[i];
|
||||
n.in.forEach(function(input) {
|
||||
input.wires.forEach(function(wire) {
|
||||
var link = {source:input, sourcePort:0, target:node_map[wire.id]};
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
});
|
||||
delete input.wires;
|
||||
});
|
||||
n.out.forEach(function(output) {
|
||||
output.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:output};
|
||||
} else {
|
||||
link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:output};
|
||||
}
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
});
|
||||
delete output.wires;
|
||||
});
|
||||
}
|
||||
|
||||
return [new_nodes,new_links,new_workspaces,new_subflows];
|
||||
}
|
||||
|
||||
|
||||
// TODO: supports filter.z|type
|
||||
function filterNodes(filter) {
|
||||
var result = [];
|
||||
|
||||
for (var n=0;n<nodes.length;n++) {
|
||||
var node = nodes[n];
|
||||
if (filter.hasOwnProperty("z") && node.z !== filter.z) {
|
||||
continue;
|
||||
}
|
||||
if (filter.hasOwnProperty("type") && node.type !== filter.type) {
|
||||
continue;
|
||||
}
|
||||
result.push(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function filterLinks(filter) {
|
||||
var result = [];
|
||||
|
||||
for (var n=0;n<links.length;n++) {
|
||||
var link = links[n];
|
||||
if (filter.source) {
|
||||
if (filter.source.hasOwnProperty("id") && link.source.id !== filter.source.id) {
|
||||
continue;
|
||||
}
|
||||
if (filter.source.hasOwnProperty("z") && link.source.z !== filter.source.z) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (filter.target) {
|
||||
if (filter.target.hasOwnProperty("id") && link.target.id !== filter.target.id) {
|
||||
continue;
|
||||
}
|
||||
if (filter.target.hasOwnProperty("z") && link.target.z !== filter.target.z) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (filter.hasOwnProperty("sourcePort") && link.sourcePort !== filter.sourcePort) {
|
||||
continue;
|
||||
}
|
||||
result.push(link);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: DRY
|
||||
var eventHandler = (function() {
|
||||
var handlers = {};
|
||||
|
||||
return {
|
||||
on: function(evt,func) {
|
||||
handlers[evt] = handlers[evt]||[];
|
||||
handlers[evt].push(func);
|
||||
},
|
||||
emit: function(evt,arg) {
|
||||
if (handlers[evt]) {
|
||||
for (var i=0;i<handlers[evt].length;i++) {
|
||||
handlers[evt][i](arg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
on: eventHandler.on,
|
||||
|
||||
registry:registry,
|
||||
setNodeList: registry.setNodeList,
|
||||
|
||||
@@ -819,14 +903,24 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
node: getNode,
|
||||
|
||||
filterNodes: filterNodes,
|
||||
filterLinks: filterLinks,
|
||||
|
||||
import: importNodes,
|
||||
refreshValidation: refreshValidation,
|
||||
|
||||
getAllFlowNodes: getAllFlowNodes,
|
||||
createExportableNodeSet: createExportableNodeSet,
|
||||
createCompleteNodeSet: createCompleteNodeSet,
|
||||
id: getID,
|
||||
nodes: nodes, // TODO: exposed for d3 vis
|
||||
links: links // TODO: exposed for d3 vis
|
||||
dirty: function(d) {
|
||||
if (d == null) {
|
||||
return dirty;
|
||||
} else {
|
||||
setDirty(d);
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
@@ -68,13 +68,20 @@ RED.settings = (function () {
|
||||
};
|
||||
|
||||
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 = "";
|
||||
}
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(jqXHR,settings) {
|
||||
// Only attach auth header for requests to relative paths
|
||||
if (!/^\s*(https?:|\/|\.)/.test(settings.url)) {
|
||||
var auth_tokens = RED.settings.get("auth-tokens");
|
||||
if (auth_tokens) {
|
||||
jqXHR.setRequestHeader("authorization","bearer "+auth_tokens.access_token);
|
||||
jqXHR.setRequestHeader("Authorization","Bearer "+auth_tokens.access_token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +91,6 @@ RED.settings = (function () {
|
||||
}
|
||||
|
||||
var load = function(done) {
|
||||
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
@@ -102,6 +108,9 @@ RED.settings = (function () {
|
||||
},
|
||||
error: function(jqXHR,textStatus,errorThrown) {
|
||||
if (jqXHR.status === 401) {
|
||||
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
|
||||
window.location.search = "";
|
||||
}
|
||||
RED.user.login(function() { load(done); });
|
||||
} else {
|
||||
console.log("Unexpected error:",jqXHR.status,textStatus);
|
||||
@@ -110,13 +119,30 @@ RED.settings = (function () {
|
||||
});
|
||||
};
|
||||
|
||||
function theme(property,defaultValue) {
|
||||
if (!RED.settings.editorTheme) {
|
||||
return defaultValue;
|
||||
}
|
||||
var parts = property.split(".");
|
||||
var v = RED.settings.editorTheme;
|
||||
try {
|
||||
for (var i=0;i<parts.length;i++) {
|
||||
v = v[parts[i]];
|
||||
}
|
||||
return v;
|
||||
} catch(err) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
load: load,
|
||||
set: set,
|
||||
get: get,
|
||||
remove: remove
|
||||
remove: remove,
|
||||
|
||||
theme: theme
|
||||
}
|
||||
})
|
||||
();
|
178
editor/js/ui/clipboard.js
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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 = $('<div id="clipboard-dialog" class="hide"><form class="dialog-form form-horizontal"></form></div>')
|
||||
.appendTo("body")
|
||||
.dialog({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 500,
|
||||
resizable: false,
|
||||
buttons: [
|
||||
{
|
||||
id: "clipboard-dialog-ok",
|
||||
text: "Ok",
|
||||
click: function() {
|
||||
if (/Import/.test(dialog.dialog("option","title"))) {
|
||||
RED.view.importNodes($("#clipboard-import").val());
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "clipboard-dialog-cancel",
|
||||
text: "Cancel",
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "clipboard-dialog-close",
|
||||
text: "Close",
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
],
|
||||
open: function(e) {
|
||||
$(this).parent().find(".ui-dialog-titlebar-close").hide();
|
||||
RED.keyboard.disable();
|
||||
},
|
||||
close: function(e) {
|
||||
RED.keyboard.enable();
|
||||
}
|
||||
});
|
||||
|
||||
var dialogContainer = dialog.children(".dialog-form");
|
||||
|
||||
var exportNodesDialog = '<div class="form-row">'+
|
||||
'<label for="node-input-export" style="display: block; width:100%;"><i class="fa fa-clipboard"></i> Nodes:</label>'+
|
||||
'<textarea readonly 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-export" rows="5"></textarea>'+
|
||||
'</div>'+
|
||||
'<div class="form-tips">'+
|
||||
'Select the text above and copy to the clipboard with Ctrl-C.'+
|
||||
'</div>';
|
||||
|
||||
var 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="Paste nodes here"></textarea>'+
|
||||
'</div>';
|
||||
|
||||
|
||||
function importNodes() {
|
||||
dialogContainer.empty();
|
||||
dialogContainer.append($(importNodesDialog));
|
||||
$("#clipboard-dialog-ok").show();
|
||||
$("#clipboard-dialog-cancel").show();
|
||||
$("#clipboard-dialog-close").hide();
|
||||
$("#clipboard-dialog-ok").button("disable");
|
||||
$("#clipboard-import").keyup(function() {
|
||||
var v = $(this).val();
|
||||
try {
|
||||
JSON.parse(v);
|
||||
$(this).removeClass("input-error");
|
||||
$("#clipboard-dialog-ok").button("enable");
|
||||
} catch(err) {
|
||||
if (v !== "") {
|
||||
$(this).addClass("input-error");
|
||||
}
|
||||
$("#clipboard-dialog-ok").button("disable");
|
||||
}
|
||||
});
|
||||
dialog.dialog("option","title","Import nodes").dialog("open");
|
||||
}
|
||||
|
||||
function exportNodes() {
|
||||
dialogContainer.empty();
|
||||
dialogContainer.append($(exportNodesDialog));
|
||||
$("#clipboard-dialog-ok").hide();
|
||||
$("#clipboard-dialog-cancel").hide();
|
||||
$("#clipboard-dialog-close").show();
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var nns = RED.nodes.createExportableNodeSet(selection.nodes);
|
||||
$("#clipboard-export")
|
||||
.val(JSON.stringify(nns))
|
||||
.focus(function() {
|
||||
var textarea = $(this);
|
||||
textarea.select();
|
||||
textarea.mouseup(function() {
|
||||
textarea.unbind("mouseup");
|
||||
return false;
|
||||
})
|
||||
});
|
||||
dialog.dialog("option","title","Export nodes to clipboard").dialog( "open" );
|
||||
}
|
||||
}
|
||||
|
||||
function hideDropTarget() {
|
||||
$("#dropTarget").hide();
|
||||
RED.keyboard.remove(/* ESCAPE */ 27);
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
RED.view.on("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.keyboard.add(/* e */ 69,{ctrl:true},function(){exportNodes();d3.event.preventDefault();});
|
||||
RED.keyboard.add(/* i */ 73,{ctrl:true},function(){importNodes();d3.event.preventDefault();});
|
||||
|
||||
|
||||
|
||||
$('#chart').on("dragenter",function(event) {
|
||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
||||
$("#dropTarget").css({display:'table'});
|
||||
RED.keyboard.add(/* ESCAPE */ 27,hideDropTarget);
|
||||
}
|
||||
});
|
||||
|
||||
$('#dropTarget').on("dragover",function(event) {
|
||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
||||
.on("dragleave",function(event) {
|
||||
hideDropTarget();
|
||||
})
|
||||
.on("drop",function(event) {
|
||||
var data = event.originalEvent.dataTransfer.getData("text/plain");
|
||||
hideDropTarget();
|
||||
RED.view.importNodes(data);
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
import: importNodes,
|
||||
export: exportNodes
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
})();
|
253
editor/js/ui/deploy.js
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.deploy = (function() {
|
||||
|
||||
var deploymentTypes = {
|
||||
"full":{img:"red/images/deploy-full-o.png"},
|
||||
"nodes":{img:"red/images/deploy-nodes-o.png"},
|
||||
"flows":{img:"red/images/deploy-flows-o.png"}
|
||||
}
|
||||
|
||||
var ignoreDeployWarnings = {
|
||||
unknown: false,
|
||||
unusedConfig: false,
|
||||
invalid: false
|
||||
}
|
||||
|
||||
var deploymentType = "full";
|
||||
|
||||
function changeDeploymentType(type) {
|
||||
deploymentType = type;
|
||||
$("#btn-deploy img").attr("src",deploymentTypes[type].img);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* options:
|
||||
* type: "default" - Button with drop-down options - no further customisation available
|
||||
* type: "simple" - Button without dropdown. Customisations:
|
||||
* label: the text to display - default: "Deploy"
|
||||
* icon : the icon to use. Null removes the icon. default: "red/images/deploy-full-o.png"
|
||||
*/
|
||||
function init(options) {
|
||||
options = options || {};
|
||||
var type = options.type || "default";
|
||||
|
||||
if (type == "default") {
|
||||
$('<li><span class="deploy-button-group button-group">'+
|
||||
'<a id="btn-deploy" class="deploy-button disabled" href="#"><img id="btn-deploy-icon" src="red/images/deploy-full-o.png"> <span>Deploy</span></a>'+
|
||||
'<a id="btn-deploy-options" data-toggle="dropdown" class="deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+
|
||||
'</span></li>').prependTo(".header-toolbar");
|
||||
RED.menu.init({id:"btn-deploy-options",
|
||||
options: [
|
||||
{id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.png",label:"Full",sublabel:"Deploys everything in the workspace",selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
|
||||
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.png",label:"Modified Flows",sublabel:"Only deploys flows that contain changed nodes", onselect:function(s) {if(s){changeDeploymentType("flows")}}},
|
||||
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.png",label:"Modified Nodes",sublabel:"Only deploys nodes that have changed",onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
|
||||
]
|
||||
});
|
||||
} else if (type == "simple") {
|
||||
var label = options.label || "Deploy";
|
||||
var icon = 'red/images/deploy-full-o.png';
|
||||
if (options.hasOwnProperty('icon')) {
|
||||
icon = options.icon;
|
||||
}
|
||||
|
||||
$('<li><span class="deploy-button-group button-group">'+
|
||||
'<a id="btn-deploy" class="deploy-button disabled" href="#">'+
|
||||
(icon?'<img id="btn-deploy-icon" src="'+icon+'"> ':'')+
|
||||
'<span>'+label+'</span></a>'+
|
||||
'</span></li>').prependTo(".header-toolbar");
|
||||
}
|
||||
|
||||
$('#btn-deploy').click(function() { save(); });
|
||||
|
||||
$( "#node-dialog-confirm-deploy" ).dialog({
|
||||
title: "Confirm deploy",
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 550,
|
||||
height: "auto",
|
||||
buttons: [
|
||||
{
|
||||
text: "Confirm deploy",
|
||||
click: function() {
|
||||
|
||||
var ignoreChecked = $( "#node-dialog-confirm-deploy-hide" ).prop("checked");
|
||||
if (ignoreChecked) {
|
||||
ignoreDeployWarnings[$( "#node-dialog-confirm-deploy-type" ).val()] = true;
|
||||
}
|
||||
save(true);
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Cancel",
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
],
|
||||
create: function() {
|
||||
$("#node-dialog-confirm-deploy").parent().find("div.ui-dialog-buttonpane")
|
||||
.append('<div style="height:0; vertical-align: middle; display:inline-block;">'+
|
||||
'<input style="vertical-align:top;" type="checkbox" id="node-dialog-confirm-deploy-hide">'+
|
||||
'<label style="display:inline;" for="node-dialog-confirm-deploy-hide"> do not warn about this again</label>'+
|
||||
'<input type="hidden" id="node-dialog-confirm-deploy-type">'+
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
RED.nodes.on('change',function(state) {
|
||||
if (state.dirty) {
|
||||
window.onbeforeunload = function() {
|
||||
return "You have undeployed changes.\n\nLeaving this page will lose these changes.";
|
||||
}
|
||||
$("#btn-deploy").removeClass("disabled");
|
||||
} else {
|
||||
window.onbeforeunload = null;
|
||||
$("#btn-deploy").addClass("disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function save(force) {
|
||||
if (RED.nodes.dirty()) {
|
||||
//$("#debug-tab-clear").click(); // uncomment this to auto clear debug on deploy
|
||||
|
||||
if (!force) {
|
||||
var hasUnknown = false;
|
||||
var hasInvalid = false;
|
||||
var hasUnusedConfig = false;
|
||||
|
||||
var unknownNodes = [];
|
||||
RED.nodes.eachNode(function(node) {
|
||||
hasInvalid = hasInvalid || !node.valid;
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
hasUnknown = unknownNodes.length > 0;
|
||||
|
||||
var unusedConfigNodes = {};
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
if (node.users.length === 0) {
|
||||
var label = "";
|
||||
if (typeof node._def.label == "function") {
|
||||
label = node._def.label.call(node);
|
||||
} else {
|
||||
label = node._def.label;
|
||||
}
|
||||
label = label || node.id;
|
||||
unusedConfigNodes[node.type] = unusedConfigNodes[node.type] || [];
|
||||
unusedConfigNodes[node.type].push(label);
|
||||
hasUnusedConfig = true;
|
||||
}
|
||||
});
|
||||
|
||||
$( "#node-dialog-confirm-deploy-config" ).hide();
|
||||
$( "#node-dialog-confirm-deploy-unknown" ).hide();
|
||||
$( "#node-dialog-confirm-deploy-unused" ).hide();
|
||||
|
||||
var showWarning = false;
|
||||
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
$( "#node-dialog-confirm-deploy-type" ).val("unknown");
|
||||
$( "#node-dialog-confirm-deploy-unknown" ).show();
|
||||
$( "#node-dialog-confirm-deploy-unknown-list" )
|
||||
.html("<li>"+unknownNodes.join("</li><li>")+"</li>");
|
||||
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
|
||||
showWarning = true;
|
||||
$( "#node-dialog-confirm-deploy-type" ).val("invalid");
|
||||
$( "#node-dialog-confirm-deploy-config" ).show();
|
||||
} else if (hasUnusedConfig && !ignoreDeployWarnings.unusedConfig) {
|
||||
showWarning = true;
|
||||
$( "#node-dialog-confirm-deploy-type" ).val("unusedConfig");
|
||||
$( "#node-dialog-confirm-deploy-unused" ).show();
|
||||
var unusedNodeLabels = [];
|
||||
var unusedTypes = Object.keys(unusedConfigNodes).sort();
|
||||
unusedTypes.forEach(function(type) {
|
||||
unusedConfigNodes[type].forEach(function(label) {
|
||||
unusedNodeLabels.push(type+": "+label);
|
||||
});
|
||||
});
|
||||
$( "#node-dialog-confirm-deploy-unused-list" )
|
||||
.html("<li>"+unusedNodeLabels.join("</li><li>")+"</li>");
|
||||
}
|
||||
if (showWarning) {
|
||||
$( "#node-dialog-confirm-deploy-hide" ).prop("checked",false);
|
||||
$( "#node-dialog-confirm-deploy" ).dialog( "open" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var nns = RED.nodes.createCompleteNodeSet();
|
||||
|
||||
$("#btn-deploy-icon").removeClass('fa-download');
|
||||
$("#btn-deploy-icon").addClass('spinner');
|
||||
RED.nodes.dirty(false);
|
||||
|
||||
$.ajax({
|
||||
url:"flows",
|
||||
type: "POST",
|
||||
data: JSON.stringify(nns),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
headers: {
|
||||
"Node-RED-Deployment-Type":deploymentType
|
||||
}
|
||||
}).done(function(data,textStatus,xhr) {
|
||||
RED.notify("Successfully deployed","success");
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
}
|
||||
if(node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
if (confNode.credentials) {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
// Once deployed, cannot undo back to a clean state
|
||||
RED.history.markAllDirty();
|
||||
RED.view.redraw();
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
RED.nodes.dirty(true);
|
||||
if (xhr.responseText) {
|
||||
RED.notify("<strong>Error</strong>: "+xhr.responseJSON.message,"error");
|
||||
} else {
|
||||
RED.notify("<strong>Error</strong>: no response from server","error");
|
||||
}
|
||||
}).always(function() {
|
||||
$("#btn-deploy-icon").removeClass('spinner');
|
||||
$("#btn-deploy-icon").addClass('fa-download');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: init
|
||||
}
|
||||
})();
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013, 2014 IBM Corp.
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,7 +15,6 @@
|
||||
**/
|
||||
RED.editor = (function() {
|
||||
var editing_node = null;
|
||||
// TODO: should IMPORT/EXPORT get their own dialogs?
|
||||
|
||||
function getCredentialsURL(nodeType, nodeID) {
|
||||
var dashedType = nodeType.replace(/\s+/g, '-');
|
||||
@@ -23,21 +22,70 @@ RED.editor = (function() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a node
|
||||
* Validate a node
|
||||
* @param node - the node being validated
|
||||
* @returns {boolean} whether the node is valid. Sets node.dirty if needed
|
||||
*/
|
||||
function validateNode(node) {
|
||||
var oldValue = node.valid;
|
||||
node.valid = validateNodeProperties(node, node._def.defaults, node);
|
||||
if (node._def._creds) {
|
||||
node.valid = node.valid && validateNodeProperties(node, node._def.credentials, node._def._creds);
|
||||
var oldChanged = node.changed;
|
||||
node.valid = true;
|
||||
var subflow;
|
||||
var isValid;
|
||||
var hasChanged;
|
||||
|
||||
if (node.type.indexOf("subflow:")===0) {
|
||||
subflow = RED.nodes.subflow(node.type.substring(8));
|
||||
isValid = subflow.valid;
|
||||
hasChanged = subflow.changed;
|
||||
if (isValid === undefined) {
|
||||
isValid = validateNode(subflow);
|
||||
hasChanged = subflow.changed;
|
||||
}
|
||||
node.valid = isValid;
|
||||
node.changed = hasChanged;
|
||||
} else if (node._def) {
|
||||
node.valid = validateNodeProperties(node, node._def.defaults, node);
|
||||
if (node._def._creds) {
|
||||
node.valid = node.valid && validateNodeProperties(node, node._def.credentials, node._def._creds);
|
||||
}
|
||||
} else if (node.type == "subflow") {
|
||||
var subflowNodes = RED.nodes.filterNodes({z:node.id});
|
||||
for (var i=0;i<subflowNodes.length;i++) {
|
||||
isValid = subflowNodes[i].valid;
|
||||
hasChanged = subflowNodes[i].changed;
|
||||
if (isValid === undefined) {
|
||||
isValid = validateNode(subflowNodes[i]);
|
||||
hasChanged = subflowNodes[i].changed;
|
||||
}
|
||||
node.valid = node.valid && isValid;
|
||||
node.changed = node.changed || hasChanged;
|
||||
}
|
||||
var subflowInstances = RED.nodes.filterNodes({type:"subflow:"+node.id});
|
||||
var modifiedTabs = {};
|
||||
for (i=0;i<subflowInstances.length;i++) {
|
||||
subflowInstances[i].valid = node.valid;
|
||||
subflowInstances[i].changed = node.changed;
|
||||
subflowInstances[i].dirty = true;
|
||||
modifiedTabs[subflowInstances[i].z] = true;
|
||||
}
|
||||
Object.keys(modifiedTabs).forEach(function(id) {
|
||||
var subflow = RED.nodes.subflow(id);
|
||||
if (subflow) {
|
||||
validateNode(subflow);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (oldValue != node.valid) {
|
||||
if (oldValue !== node.valid || oldChanged !== node.changed) {
|
||||
node.dirty = true;
|
||||
subflow = RED.nodes.subflow(node.z);
|
||||
if (subflow) {
|
||||
validateNode(subflow);
|
||||
}
|
||||
}
|
||||
return node.valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate a node's properties for the given set of property definitions
|
||||
* @param node - the node being validated
|
||||
@@ -75,7 +123,7 @@ RED.editor = (function() {
|
||||
}
|
||||
if (valid && definition[property].type && RED.nodes.getType(definition[property].type) && !("validate" in definition[property])) {
|
||||
if (!value || value == "_ADD_") {
|
||||
valid = false;
|
||||
valid = definition[property].hasOwnProperty("required") && !definition[property].required;
|
||||
} else {
|
||||
var v = RED.nodes.node(value).valid;
|
||||
valid = (v==null || v);
|
||||
@@ -112,11 +160,7 @@ RED.editor = (function() {
|
||||
}
|
||||
}
|
||||
if (node.inputs === 0) {
|
||||
RED.nodes.eachLink(function(l) {
|
||||
if (l.target === node) {
|
||||
removedLinks.push(l);
|
||||
}
|
||||
});
|
||||
removedLinks.concat(RED.nodes.filterLinks({target:node}));
|
||||
}
|
||||
for (var l=0;l<removedLinks.length;l++) {
|
||||
RED.nodes.removeLink(removedLinks[l]);
|
||||
@@ -124,13 +168,13 @@ RED.editor = (function() {
|
||||
return removedLinks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$( "#dialog" ).dialog({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
dialogClass: "ui-dialog-no-close",
|
||||
closeOnEscape: false,
|
||||
width: 500,
|
||||
minWidth: 500,
|
||||
width: 'auto',
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
@@ -139,7 +183,7 @@ RED.editor = (function() {
|
||||
if (editing_node) {
|
||||
var changes = {};
|
||||
var changed = false;
|
||||
var wasDirty = RED.view.dirty();
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
var d;
|
||||
|
||||
if (editing_node._def.oneditsave) {
|
||||
@@ -173,8 +217,6 @@ RED.editor = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (editing_node._def.defaults) {
|
||||
@@ -204,7 +246,6 @@ RED.editor = (function() {
|
||||
configNode.users.push(editing_node);
|
||||
}
|
||||
}
|
||||
|
||||
changes[d] = editing_node[d];
|
||||
editing_node[d] = newValue;
|
||||
changed = true;
|
||||
@@ -220,35 +261,30 @@ RED.editor = (function() {
|
||||
changed = changed || credsChanged;
|
||||
}
|
||||
|
||||
|
||||
var removedLinks = updateNodeProperties(editing_node);
|
||||
if (changed) {
|
||||
var wasChanged = editing_node.changed;
|
||||
editing_node.changed = true;
|
||||
RED.view.dirty(true);
|
||||
RED.nodes.dirty(true);
|
||||
RED.history.push({t:'edit',node:editing_node,changes:changes,links:removedLinks,dirty:wasDirty,changed:wasChanged});
|
||||
}
|
||||
editing_node.dirty = true;
|
||||
validateNode(editing_node);
|
||||
RED.view.redraw();
|
||||
} else if (RED.view.state() == RED.state.EXPORT) {
|
||||
if (/library/.test($( "#dialog" ).dialog("option","title"))) {
|
||||
//TODO: move this to RED.library
|
||||
var flowName = $("#node-input-filename").val();
|
||||
if (!/^\s*$/.test(flowName)) {
|
||||
$.ajax({
|
||||
url:'library/flows/'+flowName,
|
||||
type: "POST",
|
||||
data: $("#node-input-filename").attr('nodes'),
|
||||
contentType: "application/json; charset=utf-8"
|
||||
}).done(function() {
|
||||
RED.library.loadFlowLibrary();
|
||||
RED.notify("Saved nodes","success");
|
||||
});
|
||||
}
|
||||
} else if (/Export nodes to library/.test($( "#dialog" ).dialog("option","title"))) {
|
||||
//TODO: move this to RED.library
|
||||
var flowName = $("#node-input-filename").val();
|
||||
if (!/^\s*$/.test(flowName)) {
|
||||
$.ajax({
|
||||
url:'library/flows/'+flowName,
|
||||
type: "POST",
|
||||
data: $("#node-input-filename").attr('nodes'),
|
||||
contentType: "application/json; charset=utf-8"
|
||||
}).done(function() {
|
||||
RED.library.loadFlowLibrary();
|
||||
RED.notify("Saved nodes","success");
|
||||
});
|
||||
}
|
||||
} else if (RED.view.state() == RED.state.IMPORT) {
|
||||
RED.view.importNodes($("#node-input-import").val());
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
@@ -257,6 +293,11 @@ RED.editor = (function() {
|
||||
id: "node-dialog-cancel",
|
||||
text: "Cancel",
|
||||
click: function() {
|
||||
if (editing_node && editing_node._def) {
|
||||
if (editing_node._def.oneditcancel) {
|
||||
editing_node._def.oneditcancel.call(editing_node);
|
||||
}
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
@@ -267,6 +308,12 @@ RED.editor = (function() {
|
||||
}
|
||||
},
|
||||
open: function(e) {
|
||||
var minWidth = $(this).dialog('option','minWidth');
|
||||
if ($(this).outerWidth() < minWidth) {
|
||||
$(this).dialog('option','width',minWidth);
|
||||
} else {
|
||||
$(this).dialog('option','width',$(this).outerWidth());
|
||||
}
|
||||
RED.keyboard.disable();
|
||||
if (editing_node) {
|
||||
var size = $(this).dialog('option','sizeCache-'+editing_node.type);
|
||||
@@ -283,12 +330,12 @@ RED.editor = (function() {
|
||||
RED.view.state(RED.state.DEFAULT);
|
||||
}
|
||||
$( this ).dialog('option','height','auto');
|
||||
$( this ).dialog('option','width','500');
|
||||
$( this ).dialog('option','width','auto');
|
||||
if (editing_node) {
|
||||
RED.sidebar.info.refresh(editing_node);
|
||||
}
|
||||
RED.sidebar.config.refresh();
|
||||
|
||||
|
||||
var buttons = $( this ).dialog("option","buttons");
|
||||
if (buttons.length == 3) {
|
||||
$( this ).dialog("option","buttons",buttons.splice(1));
|
||||
@@ -327,6 +374,32 @@ RED.editor = (function() {
|
||||
input.val(label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a config-node button for this property
|
||||
* @param node - the node being edited
|
||||
* @param property - the name of the field
|
||||
* @param type - the type of the config-node
|
||||
*/
|
||||
function prepareConfigNodeButton(node,property,type) {
|
||||
var input = $("#node-input-"+property);
|
||||
input.val(node[property]);
|
||||
input.attr("type","hidden");
|
||||
|
||||
var button = $("<a>",{id:"node-input-edit-"+property, class:"btn"});
|
||||
input.after(button);
|
||||
|
||||
if (node[property]) {
|
||||
button.text("edit");
|
||||
} else {
|
||||
button.text("add");
|
||||
}
|
||||
|
||||
button.click(function(e) {
|
||||
showEditConfigNodeDialog(property,type,input.val()||"_ADD_");
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the editor dialog input field for this property
|
||||
* @param node - the node being edited
|
||||
@@ -395,7 +468,7 @@ RED.editor = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the node credentials from the edit form
|
||||
* @param node - the node containing the credentials
|
||||
@@ -419,7 +492,7 @@ RED.editor = (function() {
|
||||
continue;
|
||||
}
|
||||
changed = true;
|
||||
|
||||
|
||||
}
|
||||
node.credentials[cred] = value;
|
||||
if (value != node.credentials._[cred]) {
|
||||
@@ -440,7 +513,11 @@ RED.editor = (function() {
|
||||
for (var d in definition.defaults) {
|
||||
if (definition.defaults.hasOwnProperty(d)) {
|
||||
if (definition.defaults[d].type) {
|
||||
prepareConfigNodeSelect(node,d,definition.defaults[d].type);
|
||||
if (definition.defaults[d].exclusive) {
|
||||
prepareConfigNodeButton(node,d,definition.defaults[d].type);
|
||||
} else {
|
||||
prepareConfigNodeSelect(node,d,definition.defaults[d].type);
|
||||
}
|
||||
} else {
|
||||
preparePropertyEditor(node,d,prefix);
|
||||
}
|
||||
@@ -457,7 +534,7 @@ RED.editor = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (definition.credentials) {
|
||||
if (node.credentials) {
|
||||
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
|
||||
@@ -487,7 +564,7 @@ RED.editor = (function() {
|
||||
class: 'leftButton',
|
||||
text: "Edit flow",
|
||||
click: function() {
|
||||
RED.view.showSubflow(id);
|
||||
RED.workspaces.show(id);
|
||||
$("#node-dialog-ok").click();
|
||||
}
|
||||
});
|
||||
@@ -496,11 +573,11 @@ RED.editor = (function() {
|
||||
$("#dialog-form").html($("script[data-template-name='"+type+"']").html());
|
||||
$('<input type="text" style="display: none;" />').appendTo("#dialog-form");
|
||||
prepareEditDialog(node,node._def,"node-input");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$( "#dialog" ).dialog("option","title","Edit "+type+" node").dialog( "open" );
|
||||
}
|
||||
|
||||
@@ -547,6 +624,9 @@ RED.editor = (function() {
|
||||
if (configTypeDef.ondelete) {
|
||||
configTypeDef.ondelete.call(RED.nodes.node(configId));
|
||||
}
|
||||
if (configTypeDef.oneditdelete) {
|
||||
configTypeDef.oneditdelete.call(RED.nodes.node(configId));
|
||||
}
|
||||
RED.nodes.remove(configId);
|
||||
for (var i=0;i<configNode.users.length;i++) {
|
||||
var user = configNode.users[i];
|
||||
@@ -558,7 +638,7 @@ RED.editor = (function() {
|
||||
validateNode(user);
|
||||
}
|
||||
updateConfigNodeSelect(configProperty,configType,"");
|
||||
RED.view.dirty(true);
|
||||
RED.nodes.dirty(true);
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.redraw();
|
||||
}
|
||||
@@ -579,29 +659,42 @@ RED.editor = (function() {
|
||||
}
|
||||
|
||||
function updateConfigNodeSelect(name,type,value) {
|
||||
var select = $("#node-input-"+name);
|
||||
var node_def = RED.nodes.getType(type);
|
||||
select.children().remove();
|
||||
RED.nodes.eachConfig(function(config) {
|
||||
if (config.type == type) {
|
||||
var label = "";
|
||||
if (typeof node_def.label == "function") {
|
||||
label = node_def.label.call(config);
|
||||
} else {
|
||||
label = node_def.label;
|
||||
}
|
||||
select.append('<option value="'+config.id+'"'+(value==config.id?" selected":"")+'>'+label+'</option>');
|
||||
var button = $("#node-input-edit-"+name);
|
||||
if (button.length) {
|
||||
if (value) {
|
||||
button.text("edit");
|
||||
} else {
|
||||
button.text("add");
|
||||
}
|
||||
});
|
||||
$("#node-input-"+name).val(value);
|
||||
} else {
|
||||
|
||||
select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>Add new '+type+'...</option>');
|
||||
window.setTimeout(function() { select.change();},50);
|
||||
var select = $("#node-input-"+name);
|
||||
var node_def = RED.nodes.getType(type);
|
||||
select.children().remove();
|
||||
RED.nodes.eachConfig(function(config) {
|
||||
if (config.type == type) {
|
||||
var label = "";
|
||||
if (typeof node_def.label == "function") {
|
||||
label = node_def.label.call(config);
|
||||
} else {
|
||||
label = node_def.label;
|
||||
}
|
||||
select.append('<option value="'+config.id+'"'+(value==config.id?" selected":"")+'>'+label+'</option>');
|
||||
}
|
||||
});
|
||||
|
||||
select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>Add new '+type+'...</option>');
|
||||
window.setTimeout(function() { select.change();},50);
|
||||
}
|
||||
}
|
||||
|
||||
$( "#node-config-dialog" ).dialog({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 500,
|
||||
dialogClass: "ui-dialog-no-close",
|
||||
minWidth: 500,
|
||||
width: 'auto',
|
||||
closeOnEscape: false,
|
||||
buttons: [
|
||||
{
|
||||
@@ -615,12 +708,18 @@ RED.editor = (function() {
|
||||
var configTypeDef = RED.nodes.getType(configType);
|
||||
var configNode;
|
||||
var d;
|
||||
|
||||
var input;
|
||||
|
||||
if (configAdding) {
|
||||
configNode = {type:configType,id:configId,users:[]};
|
||||
for (d in configTypeDef.defaults) {
|
||||
if (configTypeDef.defaults.hasOwnProperty(d)) {
|
||||
configNode[d] = $("#node-config-input-"+d).val();
|
||||
input = $("#node-config-input-"+d);
|
||||
if (input.attr('type') === "checkbox") {
|
||||
configNode[d] = input.prop('checked');
|
||||
} else {
|
||||
configNode[d] = input.val();
|
||||
}
|
||||
}
|
||||
}
|
||||
configNode.label = configTypeDef.label;
|
||||
@@ -631,7 +730,7 @@ RED.editor = (function() {
|
||||
configNode = RED.nodes.node(configId);
|
||||
for (d in configTypeDef.defaults) {
|
||||
if (configTypeDef.defaults.hasOwnProperty(d)) {
|
||||
var input = $("#node-config-input-"+d);
|
||||
input = $("#node-config-input-"+d);
|
||||
if (input.attr('type') === "checkbox") {
|
||||
configNode[d] = input.prop('checked');
|
||||
} else {
|
||||
@@ -648,8 +747,12 @@ RED.editor = (function() {
|
||||
configTypeDef.oneditsave.call(RED.nodes.node(configId));
|
||||
}
|
||||
validateNode(configNode);
|
||||
for (var i=0;i<configNode.users.length;i++) {
|
||||
var user = configNode.users[i];
|
||||
validateNode(user);
|
||||
}
|
||||
|
||||
RED.view.dirty(true);
|
||||
RED.nodes.dirty(true);
|
||||
$(this).dialog("close");
|
||||
|
||||
}
|
||||
@@ -681,11 +784,17 @@ RED.editor = (function() {
|
||||
resize: function(e,ui) {
|
||||
},
|
||||
open: function(e) {
|
||||
var minWidth = $(this).dialog('option','minWidth');
|
||||
if ($(this).outerWidth() < minWidth) {
|
||||
$(this).dialog('option','width',minWidth);
|
||||
}
|
||||
if (RED.view.state() != RED.state.EDITING) {
|
||||
RED.keyboard.disable();
|
||||
}
|
||||
},
|
||||
close: function(e) {
|
||||
$(this).dialog('option','width','auto');
|
||||
$(this).dialog('option','height','auto');
|
||||
$("#dialog-config-form").html("");
|
||||
if (RED.view.state() != RED.state.EDITING) {
|
||||
RED.keyboard.enable();
|
||||
@@ -697,8 +806,10 @@ RED.editor = (function() {
|
||||
$( "#subflow-dialog" ).dialog({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
dialogClass: "ui-dialog-no-close",
|
||||
closeOnEscape: false,
|
||||
width: 500,
|
||||
minWidth: 500,
|
||||
width: 'auto',
|
||||
buttons: [
|
||||
{
|
||||
id: "subflow-dialog-ok",
|
||||
@@ -708,19 +819,19 @@ RED.editor = (function() {
|
||||
var i;
|
||||
var changes = {};
|
||||
var changed = false;
|
||||
var wasDirty = RED.view.dirty();
|
||||
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
|
||||
var newName = $("#subflow-input-name").val();
|
||||
|
||||
if (newName != editing_node.name) {
|
||||
changes['name'] = editing_node.name;
|
||||
editing_node.name = newName;
|
||||
changed = true;
|
||||
$("#btn-workspace-menu-"+editing_node.id.replace(".","-")).text("Subflow: "+newName);
|
||||
$("#menu-item-workspace-menu-"+editing_node.id.replace(".","-")).text("Subflow: "+newName);
|
||||
}
|
||||
|
||||
RED.palette.refresh();
|
||||
|
||||
|
||||
if (changed) {
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type == "subflow:"+editing_node.id) {
|
||||
@@ -730,7 +841,7 @@ RED.editor = (function() {
|
||||
});
|
||||
var wasChanged = editing_node.changed;
|
||||
editing_node.changed = true;
|
||||
RED.view.dirty(true);
|
||||
RED.nodes.dirty(true);
|
||||
var historyEvent = {
|
||||
t:'edit',
|
||||
node:editing_node,
|
||||
@@ -738,7 +849,7 @@ RED.editor = (function() {
|
||||
dirty:wasDirty,
|
||||
changed:wasChanged
|
||||
};
|
||||
|
||||
|
||||
RED.history.push(historyEvent);
|
||||
}
|
||||
editing_node.dirty = true;
|
||||
@@ -758,6 +869,10 @@ RED.editor = (function() {
|
||||
],
|
||||
open: function(e) {
|
||||
RED.keyboard.disable();
|
||||
var minWidth = $(this).dialog('option','minWidth');
|
||||
if ($(this).outerWidth() < minWidth) {
|
||||
$(this).dialog('option','width',minWidth);
|
||||
}
|
||||
},
|
||||
close: function(e) {
|
||||
RED.keyboard.enable();
|
||||
@@ -769,31 +884,60 @@ RED.editor = (function() {
|
||||
editing_node = null;
|
||||
}
|
||||
});
|
||||
|
||||
$("#subflow-dialog form" ).submit(function(e) { e.preventDefault();});
|
||||
|
||||
|
||||
function showEditSubflowDialog(subflow) {
|
||||
editing_node = subflow;
|
||||
RED.view.state(RED.state.EDITING);
|
||||
$("#subflow-input-name").val(subflow.name);
|
||||
var userCount = 0;
|
||||
var subflowType = "subflow:"+editing_node.id;
|
||||
|
||||
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type === subflowType) {
|
||||
userCount++;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$("#subflow-dialog-user-count").html("There "+(userCount==1?"is":"are")+" "+userCount+" instance"+(userCount==1?" ":"s")+" of this subflow").show();
|
||||
$("#subflow-dialog").dialog("option","title","Edit flow "+subflow.name).dialog( "open" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return {
|
||||
edit: showEditDialog,
|
||||
editConfig: showEditConfigNodeDialog,
|
||||
editSubflow: showEditSubflowDialog,
|
||||
validateNode: validateNode,
|
||||
updateNodeProperties: updateNodeProperties // TODO: only exposed for edit-undo
|
||||
updateNodeProperties: updateNodeProperties, // TODO: only exposed for edit-undo
|
||||
|
||||
createEditor: function(options) {
|
||||
var editor = ace.edit(options.id);
|
||||
editor.setTheme("ace/theme/tomorrow");
|
||||
var session = editor.getSession();
|
||||
if (options.mode) {
|
||||
session.setMode(options.mode);
|
||||
}
|
||||
if (options.foldStyle) {
|
||||
session.setFoldStyle(options.foldStyle);
|
||||
} else {
|
||||
session.setFoldStyle('markbeginend');
|
||||
}
|
||||
if (options.options) {
|
||||
editor.setOptions(options.options);
|
||||
} else {
|
||||
editor.setOptions({
|
||||
enableBasicAutocompletion:true,
|
||||
enableSnippets:true
|
||||
});
|
||||
}
|
||||
editor.$blockScrolling = Infinity;
|
||||
if (options.value) {
|
||||
session.setValue(options.value,-1);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
})();
|
121
editor/js/ui/keyboard.js
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
*
|
||||
* 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.keyboard = (function() {
|
||||
|
||||
var active = true;
|
||||
var handlers = {};
|
||||
|
||||
d3.select(window).on("keydown",function() {
|
||||
if (!active) { return; }
|
||||
var handler = handlers[d3.event.keyCode];
|
||||
if (handler && handler.ondown) {
|
||||
if (!handler.modifiers ||
|
||||
((!handler.modifiers.shift || d3.event.shiftKey) &&
|
||||
(!handler.modifiers.ctrl || d3.event.ctrlKey || d3.event.metaKey) &&
|
||||
(!handler.modifiers.alt || d3.event.altKey) )) {
|
||||
handler.ondown();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
d3.select(window).on("keyup",function() {
|
||||
if (!active) { return; }
|
||||
var handler = handlers[d3.event.keyCode];
|
||||
if (handler && handler.onup) {
|
||||
if (!handler.modifiers ||
|
||||
((!handler.modifiers.shift || d3.event.shiftKey) &&
|
||||
(!handler.modifiers.ctrl || d3.event.ctrlKey || d3.event.metaKey) &&
|
||||
(!handler.modifiers.alt || d3.event.altKey) )) {
|
||||
handler.onup();
|
||||
}
|
||||
}
|
||||
});
|
||||
function addHandler(key,modifiers,ondown,onup) {
|
||||
var mod = modifiers;
|
||||
var cbdown = ondown;
|
||||
var cbup = onup;
|
||||
if (typeof modifiers == "function") {
|
||||
mod = {};
|
||||
cbdown = modifiers;
|
||||
cbup = ondown;
|
||||
}
|
||||
handlers[key] = {modifiers:mod, ondown:cbdown, onup:cbup};
|
||||
}
|
||||
function removeHandler(key) {
|
||||
delete handlers[key];
|
||||
}
|
||||
|
||||
|
||||
var dialog = null;
|
||||
|
||||
function showKeyboardHelp() {
|
||||
if (!RED.settings.theme("menu.menu-item-keyboard-shortcuts",true)) {
|
||||
return;
|
||||
}
|
||||
if (!dialog) {
|
||||
dialog = $('<div id="keyboard-help-dialog" class="hide">'+
|
||||
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
|
||||
'<table class="keyboard-shortcuts">'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">a</span></td><td>Select all nodes</td></tr>'+
|
||||
'<tr><td><span class="help-key">Shift</span> + <span class="help-key">Click</span></td><td>Select all connected nodes</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Click</span></td><td>Add/remove node from selection</td></tr>'+
|
||||
'<tr><td><span class="help-key">Delete</span></td><td>Delete selected nodes or link</td></tr>'+
|
||||
'<tr><td> </td><td></td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">i</span></td><td>Import nodes</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">e</span></td><td>Export selected nodes</td></tr>'+
|
||||
'</table>'+
|
||||
'</div>'+
|
||||
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
|
||||
'<table class="keyboard-shortcuts">'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Space</span></td><td>Toggle sidebar</td></tr>'+
|
||||
'<tr><td></td><td></td></tr>'+
|
||||
'<tr><td><span class="help-key">Delete</span></td><td>Delete selected nodes or link</td></tr>'+
|
||||
'<tr><td></td><td></td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">c</span></td><td>Copy selected nodes</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">x</span></td><td>Cut selected nodes</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">v</span></td><td>Paste nodes</td></tr>'+
|
||||
'</table>'+
|
||||
'</div>'+
|
||||
'</div>')
|
||||
.appendTo("body")
|
||||
.dialog({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: "800",
|
||||
title:"Keyboard shortcuts",
|
||||
resizable: false,
|
||||
open: function() {
|
||||
RED.keyboard.disable();
|
||||
},
|
||||
close: function() {
|
||||
RED.keyboard.enable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dialog.dialog("open");
|
||||
}
|
||||
|
||||
return {
|
||||
add: addHandler,
|
||||
remove: removeHandler,
|
||||
disable: function(){ active = false;},
|
||||
enable: function(){ active = true; },
|
||||
|
||||
showHelp: showKeyboardHelp
|
||||
}
|
||||
|
||||
})();
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,7 @@ RED.library = (function() {
|
||||
var li;
|
||||
var a;
|
||||
var ul = document.createElement("ul");
|
||||
ul.id = "btn-import-library-submenu";
|
||||
ul.id = "menu-item-import-library-submenu";
|
||||
ul.className = "dropdown-menu";
|
||||
if (data.d) {
|
||||
for (i in data.d) {
|
||||
@@ -63,7 +63,7 @@ RED.library = (function() {
|
||||
};
|
||||
var menu = buildMenu(data,"");
|
||||
//TODO: need an api in RED.menu for this
|
||||
$("#btn-import-library-submenu").replaceWith(menu);
|
||||
$("#menu-item-import-library-submenu").replaceWith(menu);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,6 +72,19 @@ RED.library = (function() {
|
||||
var selectedLibraryItem = null;
|
||||
var libraryEditor = null;
|
||||
|
||||
// Orion editor has set/getText
|
||||
// ACE editor has set/getValue
|
||||
// normalise to set/getValue
|
||||
if (options.editor.setText) {
|
||||
// Orion doesn't like having pos passed in, so proxy the call to drop it
|
||||
options.editor.setValue = function(text,pos) {
|
||||
options.editor.setText.call(options.editor,text);
|
||||
}
|
||||
}
|
||||
if (options.editor.getText) {
|
||||
options.editor.getValue = options.editor.getText;
|
||||
}
|
||||
|
||||
function buildFileListItem(item) {
|
||||
var li = document.createElement("li");
|
||||
li.onmouseover = function(e) { $(this).addClass("list-hover"); };
|
||||
@@ -119,7 +132,7 @@ RED.library = (function() {
|
||||
$(this).addClass("list-selected");
|
||||
$.get("library/"+options.url+root+item.fn, function(data) {
|
||||
selectedLibraryItem = item;
|
||||
libraryEditor.setText(data);
|
||||
libraryEditor.setValue(data,-1);
|
||||
});
|
||||
}
|
||||
})();
|
||||
@@ -144,7 +157,7 @@ RED.library = (function() {
|
||||
$("#node-select-library").children().remove();
|
||||
var bc = $("#node-dialog-library-breadcrumbs");
|
||||
bc.children().first().nextAll().remove();
|
||||
libraryEditor.setText('');
|
||||
libraryEditor.setValue('',-1);
|
||||
|
||||
$.getJSON("library/"+options.url,function(data) {
|
||||
$("#node-select-library").append(buildFileList("/",data));
|
||||
@@ -205,14 +218,18 @@ RED.library = (function() {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
require(["orion/editor/edit"], function(edit) {
|
||||
libraryEditor = edit({
|
||||
parent:document.getElementById('node-select-library-text'),
|
||||
lang:"js",
|
||||
readonly: true
|
||||
});
|
||||
libraryEditor = ace.edit('node-select-library-text');
|
||||
libraryEditor.setTheme("ace/theme/tomorrow");
|
||||
if (options.mode) {
|
||||
libraryEditor.getSession().setMode(options.mode);
|
||||
}
|
||||
libraryEditor.setOptions({
|
||||
readOnly: true,
|
||||
highlightActiveLine: false,
|
||||
highlightGutterLine: false
|
||||
});
|
||||
|
||||
libraryEditor.renderer.$cursorLayer.element.style.opacity=0;
|
||||
libraryEditor.$blockScrolling = Infinity;
|
||||
|
||||
$( "#node-dialog-library-lookup" ).dialog({
|
||||
title: options.type+" library",
|
||||
@@ -229,7 +246,7 @@ RED.library = (function() {
|
||||
var field = options.fields[i];
|
||||
$("#node-input-"+field).val(selectedLibraryItem[field]);
|
||||
}
|
||||
options.editor.setText(libraryEditor.getText());
|
||||
options.editor.setValue(libraryEditor.getValue(),-1);
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
@@ -294,19 +311,26 @@ RED.library = (function() {
|
||||
//}
|
||||
}
|
||||
var queryArgs = [];
|
||||
var data = {};
|
||||
for (var i=0;i<options.fields.length;i++) {
|
||||
var field = options.fields[i];
|
||||
if (field == "name") {
|
||||
queryArgs.push("name="+encodeURIComponent(name));
|
||||
data.name = name;
|
||||
} else {
|
||||
queryArgs.push(encodeURIComponent(field)+"="+encodeURIComponent($("#node-input-"+field).val()));
|
||||
data[field] = $("#node-input-"+field).val();
|
||||
}
|
||||
}
|
||||
var queryString = queryArgs.join("&");
|
||||
|
||||
var text = options.editor.getText();
|
||||
$.post("library/"+options.url+'/'+fullpath+"?"+queryString,text,function() {
|
||||
RED.notify("Saved "+options.type,"success");
|
||||
data.text = options.editor.getValue();
|
||||
$.ajax({
|
||||
url:"library/"+options.url+'/'+fullpath,
|
||||
type: "POST",
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json; charset=utf-8"
|
||||
}).done(function(data,textStatus,xhr) {
|
||||
RED.notify("Saved "+options.type,"success");
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
RED.notify("Saved failed: "+xhr.responseJSON.message,"error");
|
||||
});
|
||||
}
|
||||
$( "#node-dialog-library-save-confirm" ).dialog({
|
||||
@@ -356,12 +380,36 @@ RED.library = (function() {
|
||||
|
||||
}
|
||||
|
||||
function exportFlow() {
|
||||
//TODO: don't rely on the main dialog
|
||||
var nns = RED.nodes.createExportableNodeSet(RED.view.selection().nodes);
|
||||
$("#dialog-form").html($("script[data-template-name='export-library-dialog']").html());
|
||||
$("#node-input-filename").attr('nodes',JSON.stringify(nns));
|
||||
$( "#dialog" ).dialog("option","title","Export nodes to library").dialog( "open" );
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
loadFlowLibrary();
|
||||
RED.view.on("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);
|
||||
}
|
||||
});
|
||||
|
||||
if (RED.settings.theme("menu.menu-item-import-library") !== false) {
|
||||
loadFlowLibrary();
|
||||
}
|
||||
},
|
||||
create: createUI,
|
||||
loadFlowLibrary: loadFlowLibrary
|
||||
loadFlowLibrary: loadFlowLibrary,
|
||||
|
||||
export: exportFlow
|
||||
}
|
||||
})();
|
||||
|
@@ -23,7 +23,14 @@ RED.menu = (function() {
|
||||
function createMenuItem(opt) {
|
||||
var item;
|
||||
|
||||
function setState() {
|
||||
if (opt !== null && opt.id) {
|
||||
var themeSetting = RED.settings.theme("menu."+opt.id);
|
||||
if (themeSetting === false) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function setInitialState() {
|
||||
var savedStateActive = isSavedStateActive(opt.id);
|
||||
if (savedStateActive) {
|
||||
link.addClass("active");
|
||||
@@ -99,7 +106,7 @@ RED.menu = (function() {
|
||||
opt.onselect.call(opt);
|
||||
}
|
||||
});
|
||||
setState();
|
||||
setInitialState();
|
||||
} else if (opt.href) {
|
||||
link.attr("target","_blank").attr("href",opt.href);
|
||||
} else if (!opt.options) {
|
||||
@@ -113,7 +120,10 @@ RED.menu = (function() {
|
||||
var submenu = $('<ul id="'+opt.id+'-submenu" class="dropdown-menu"></ul>').appendTo(item);
|
||||
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
createMenuItem(opt.options[i]).appendTo(submenu);
|
||||
var li = createMenuItem(opt.options[i]);
|
||||
if (li) {
|
||||
li.appendTo(submenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opt.disabled) {
|
||||
@@ -148,9 +158,16 @@ RED.menu = (function() {
|
||||
|
||||
var topMenu = $("<ul/>",{id:options.id+"-submenu", class:"dropdown-menu pull-right"}).insertAfter(button);
|
||||
|
||||
var lastAddedSeparator = false;
|
||||
for (var i=0;i<options.options.length;i++) {
|
||||
var opt = options.options[i];
|
||||
createMenuItem(opt).appendTo(topMenu);
|
||||
if (opt !== null || !lastAddedSeparator) {
|
||||
var li = createMenuItem(opt);
|
||||
if (li) {
|
||||
li.appendTo(topMenu);
|
||||
lastAddedSeparator = (opt === null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +193,7 @@ RED.menu = (function() {
|
||||
} else {
|
||||
$("#"+id).removeClass("active");
|
||||
}
|
||||
if (opt.onselect) {
|
||||
if (opt && opt.onselect) {
|
||||
opt.onselect.call(opt,state);
|
||||
}
|
||||
setSavedState(id, state);
|
||||
@@ -198,17 +215,20 @@ RED.menu = (function() {
|
||||
}
|
||||
|
||||
function setAction(id,action) {
|
||||
menuItems[id].onselect = action;
|
||||
$("#"+id).click(function() {
|
||||
if ($(this).parent().hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
if (menuItems[id].toggle) {
|
||||
setSelected(id,!isSelected(id));
|
||||
} else {
|
||||
menuItems[id].onselect.call(menuItems[id]);
|
||||
}
|
||||
});
|
||||
var opt = menuItems[id];
|
||||
if (opt) {
|
||||
opt.onselect = action;
|
||||
$("#"+id).click(function() {
|
||||
if ($(this).parent().hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
if (menuItems[id].toggle) {
|
||||
setSelected(id,!isSelected(id));
|
||||
} else {
|
||||
menuItems[id].onselect.call(menuItems[id]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,7 @@
|
||||
RED.palette = (function() {
|
||||
|
||||
var exclusion = ['config','unknown','deprecated'];
|
||||
var core = ['input', 'output', 'function', 'subflows', 'social', 'storage', 'analysis', 'advanced'];
|
||||
var core = ['subflows', 'input', 'output', 'function', 'social', 'storage', 'analysis', 'advanced'];
|
||||
|
||||
function createCategoryContainer(category){
|
||||
var escapedCategory = category.replace(" ","_");
|
||||
@@ -98,7 +98,6 @@ RED.palette = (function() {
|
||||
}
|
||||
|
||||
function addNodeType(nt,def) {
|
||||
|
||||
var nodeTypeId = escapeNodeType(nt);
|
||||
if ($("#palette_node_"+nodeTypeId).length) {
|
||||
return;
|
||||
@@ -121,17 +120,16 @@ RED.palette = (function() {
|
||||
label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
|
||||
}
|
||||
|
||||
d.innerHTML = '<div class="palette_label"></div>';
|
||||
|
||||
$('<div/>',{class:"palette_label"+(def.align=="right"?" palette_label_right":"")}).appendTo(d);
|
||||
|
||||
d.className="palette_node";
|
||||
|
||||
|
||||
if (def.icon) {
|
||||
d.style.backgroundImage = "url(icons/"+def.icon+")";
|
||||
d.style.backgroundSize = "18px 27px";
|
||||
if (def.align == "right") {
|
||||
d.style.backgroundPosition = "95% 50%";
|
||||
} else if (def.inputs > 0) {
|
||||
d.style.backgroundPosition = "10% 50%";
|
||||
}
|
||||
var icon_url = (typeof def.icon === "function" ? def.icon.call({}) : def.icon);
|
||||
var iconContainer = $('<div/>',{class:"palette_icon_container"+(def.align=="right"?" palette_icon_container_right":"")}).appendTo(d);
|
||||
$('<div/>',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer);
|
||||
}
|
||||
|
||||
d.style.backgroundColor = def.color;
|
||||
@@ -169,6 +167,7 @@ RED.palette = (function() {
|
||||
container:'body'
|
||||
});
|
||||
$(d).click(function() {
|
||||
RED.view.focus();
|
||||
var help = '<div class="node-help">'+($("script[data-help-name|='"+d.type+"']").html()||"")+"</div>";
|
||||
$("#tab-info").html(help);
|
||||
});
|
||||
@@ -176,16 +175,41 @@ RED.palette = (function() {
|
||||
helper: 'clone',
|
||||
appendTo: 'body',
|
||||
revert: true,
|
||||
revertDuration: 50
|
||||
revertDuration: 50,
|
||||
start: function() {RED.view.focus();}
|
||||
});
|
||||
|
||||
if (def.category == "subflows") {
|
||||
$(d).dblclick(function(e) {
|
||||
RED.workspaces.show(nt.substring(8));
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
setLabel(nt,$(d),label);
|
||||
|
||||
var categoryNode = $("#palette-container-"+category);
|
||||
if (categoryNode.find(".palette_node").length === 1) {
|
||||
if (!categoryNode.find("i").hasClass("expanded")) {
|
||||
categoryNode.find(".palette-content").slideToggle();
|
||||
categoryNode.find("i").toggleClass("expanded");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function removeNodeType(nt) {
|
||||
var nodeTypeId = escapeNodeType(nt);
|
||||
$("#palette_node_"+nodeTypeId).remove();
|
||||
var paletteNode = $("#palette_node_"+nodeTypeId);
|
||||
var categoryNode = paletteNode.closest(".palette-category");
|
||||
paletteNode.remove();
|
||||
if (categoryNode.find(".palette_node").length === 0) {
|
||||
if (categoryNode.find("i").hasClass("expanded")) {
|
||||
categoryNode.find(".palette-content").slideToggle();
|
||||
categoryNode.find("i").toggleClass("expanded");
|
||||
}
|
||||
}
|
||||
}
|
||||
function hideNodeType(nt) {
|
||||
var nodeTypeId = escapeNodeType(nt);
|
||||
@@ -232,7 +256,8 @@ RED.palette = (function() {
|
||||
|
||||
var re = new RegExp(val,'i');
|
||||
$(".palette_node").each(function(i,el) {
|
||||
if (val === "" || re.test(el.id)) {
|
||||
var currentLabel = $(el).find(".palette_label").text();
|
||||
if (val === "" || re.test(el.id) || re.test(currentLabel)) {
|
||||
$(this).show();
|
||||
} else {
|
||||
$(this).hide();
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -51,18 +51,16 @@ RED.sidebar = (function() {
|
||||
sidebarSeparator.chartRight = winWidth-$("#workspace").width()-$("#workspace").offset().left-2;
|
||||
|
||||
|
||||
if (!RED.menu.isSelected("btn-sidebar")) {
|
||||
if (!RED.menu.isSelected("menu-item-sidebar")) {
|
||||
sidebarSeparator.opening = true;
|
||||
var newChartRight = 15;
|
||||
$("#sidebar").addClass("closing");
|
||||
$("#workspace").css("right",newChartRight);
|
||||
$("#chart-zoom-controls").css("right",newChartRight+20);
|
||||
$("#sidebar").width(0);
|
||||
RED.menu.setSelected("btn-sidebar",true);
|
||||
RED.view.resize();
|
||||
RED.menu.setSelected("menu-item-sidebar",true);
|
||||
eventHandler.emit("resize");
|
||||
}
|
||||
|
||||
|
||||
sidebarSeparator.width = $("#sidebar").width();
|
||||
},
|
||||
drag: function(event,ui) {
|
||||
@@ -101,14 +99,12 @@ RED.sidebar = (function() {
|
||||
$("#sidebar").width(newSidebarWidth);
|
||||
|
||||
sidebar_tabs.resize();
|
||||
RED.view.resize();
|
||||
|
||||
eventHandler.emit("resize");
|
||||
},
|
||||
stop:function(event,ui) {
|
||||
RED.view.resize();
|
||||
if (sidebarSeparator.closing) {
|
||||
$("#sidebar").removeClass("closing");
|
||||
RED.menu.setSelected("btn-sidebar",false);
|
||||
RED.menu.setSelected("menu-item-sidebar",false);
|
||||
if ($("#sidebar").width() < 180) {
|
||||
$("#sidebar").width(180);
|
||||
$("#workspace").css("right",208);
|
||||
@@ -117,6 +113,7 @@ RED.sidebar = (function() {
|
||||
}
|
||||
$("#sidebar-separator").css("left","auto");
|
||||
$("#sidebar-separator").css("right",($("#sidebar").width()+13)+"px");
|
||||
eventHandler.emit("resize");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -127,6 +124,7 @@ RED.sidebar = (function() {
|
||||
$("#main-container").removeClass("sidebar-closed");
|
||||
sidebar_tabs.resize();
|
||||
}
|
||||
eventHandler.emit("resize");
|
||||
}
|
||||
|
||||
function showSidebar(id) {
|
||||
@@ -140,18 +138,40 @@ RED.sidebar = (function() {
|
||||
}
|
||||
|
||||
function init () {
|
||||
RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("btn-sidebar",!RED.menu.isSelected("btn-sidebar"));d3.event.preventDefault();});
|
||||
RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("menu-item-sidebar",!RED.menu.isSelected("menu-item-sidebar"));d3.event.preventDefault();});
|
||||
showSidebar();
|
||||
RED.sidebar.info.show();
|
||||
// hide info bar at start if screen rather narrow...
|
||||
if ($(window).width() < 600) { toggleSidebar(); }
|
||||
}
|
||||
|
||||
var eventHandler = (function() {
|
||||
var handlers = {};
|
||||
|
||||
return {
|
||||
on: function(evt,func) {
|
||||
handlers[evt] = handlers[evt]||[];
|
||||
handlers[evt].push(func);
|
||||
},
|
||||
emit: function(evt,arg) {
|
||||
if (handlers[evt]) {
|
||||
for (var i=0;i<handlers[evt].length;i++) {
|
||||
handlers[evt][i](arg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
init: init,
|
||||
addTab: addTab,
|
||||
removeTab: removeTab,
|
||||
show: showSidebar,
|
||||
containsTab: containsTab,
|
||||
toggleSidebar: toggleSidebar
|
||||
toggleSidebar: toggleSidebar,
|
||||
on: eventHandler.on
|
||||
}
|
||||
|
||||
})();
|
402
editor/js/ui/subflow.js
Normal file
@@ -0,0 +1,402 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.subflow = (function() {
|
||||
|
||||
|
||||
function getSubflow() {
|
||||
return RED.nodes.subflow(RED.workspaces.active());
|
||||
}
|
||||
|
||||
function findAvailableSubflowIOPosition(subflow) {
|
||||
var pos = {x:70,y:70};
|
||||
for (var i=0;i<subflow.out.length+subflow.in.length;i++) {
|
||||
var port;
|
||||
if (i < subflow.out.length) {
|
||||
port = subflow.out[i];
|
||||
} else {
|
||||
port = subflow.in[i-subflow.out.length];
|
||||
}
|
||||
if (port.x == pos.x && port.y == pos.y) {
|
||||
pos.x += 55;
|
||||
i=0;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
function addSubflowInput() {
|
||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
var position = findAvailableSubflowIOPosition(subflow);
|
||||
var newInput = {
|
||||
type:"subflow",
|
||||
direction:"in",
|
||||
z:subflow.id,
|
||||
i:subflow.in.length,
|
||||
x:position.x,
|
||||
y:position.y,
|
||||
id:RED.nodes.id()
|
||||
};
|
||||
var oldInCount = subflow.in.length;
|
||||
subflow.in.push(newInput);
|
||||
subflow.dirty = true;
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
var wasChanged = subflow.changed;
|
||||
subflow.changed = true;
|
||||
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type == "subflow:"+subflow.id) {
|
||||
n.changed = true;
|
||||
n.inputs = subflow.in.length;
|
||||
RED.editor.updateNodeProperties(n);
|
||||
}
|
||||
});
|
||||
var historyEvent = {
|
||||
t:'edit',
|
||||
node:subflow,
|
||||
dirty:wasDirty,
|
||||
changed:wasChanged,
|
||||
subflow: {
|
||||
inputCount: oldInCount
|
||||
}
|
||||
};
|
||||
RED.history.push(historyEvent);
|
||||
$("#workspace-subflow-add-input").toggleClass("disabled",true);
|
||||
RED.view.select();
|
||||
}
|
||||
|
||||
function addSubflowOutput(id) {
|
||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
var position = findAvailableSubflowIOPosition(subflow);
|
||||
|
||||
var newOutput = {
|
||||
type:"subflow",
|
||||
direction:"out",
|
||||
z:subflow.id,
|
||||
i:subflow.out.length,
|
||||
x:position.x,
|
||||
y:position.y,
|
||||
id:RED.nodes.id()
|
||||
};
|
||||
var oldOutCount = subflow.out.length;
|
||||
subflow.out.push(newOutput);
|
||||
subflow.dirty = true;
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
var wasChanged = subflow.changed;
|
||||
subflow.changed = true;
|
||||
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type == "subflow:"+subflow.id) {
|
||||
n.changed = true;
|
||||
n.outputs = subflow.out.length;
|
||||
RED.editor.updateNodeProperties(n);
|
||||
}
|
||||
});
|
||||
var historyEvent = {
|
||||
t:'edit',
|
||||
node:subflow,
|
||||
dirty:wasDirty,
|
||||
changed:wasChanged,
|
||||
subflow: {
|
||||
outputCount: oldOutCount
|
||||
}
|
||||
};
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select();
|
||||
}
|
||||
|
||||
function init() {
|
||||
$("#workspace-subflow-edit").click(function(event) {
|
||||
RED.editor.editSubflow(RED.nodes.subflow(RED.workspaces.active()));
|
||||
event.preventDefault();
|
||||
});
|
||||
$("#workspace-subflow-add-input").click(function(event) {
|
||||
event.preventDefault();
|
||||
if ($(this).hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
addSubflowInput();
|
||||
});
|
||||
$("#workspace-subflow-add-output").click(function(event) {
|
||||
event.preventDefault();
|
||||
if ($(this).hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
addSubflowOutput();
|
||||
});
|
||||
|
||||
$("#workspace-subflow-delete").click(function(event) {
|
||||
event.preventDefault();
|
||||
var removedNodes = [];
|
||||
var removedLinks = [];
|
||||
var startDirty = RED.nodes.dirty();
|
||||
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type == "subflow:"+getSubflow().id) {
|
||||
removedNodes.push(n);
|
||||
}
|
||||
if (n.z == getSubflow().id) {
|
||||
removedNodes.push(n);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i=0;i<removedNodes.length;i++) {
|
||||
var rmlinks = RED.nodes.remove(removedNodes[i].id);
|
||||
removedLinks = removedLinks.concat(rmlinks);
|
||||
}
|
||||
|
||||
var activeSubflow = getSubflow();
|
||||
|
||||
RED.nodes.removeSubflow(activeSubflow);
|
||||
|
||||
RED.history.push({
|
||||
t:'delete',
|
||||
nodes:removedNodes,
|
||||
links:removedLinks,
|
||||
subflow: activeSubflow,
|
||||
dirty:startDirty
|
||||
});
|
||||
|
||||
RED.workspaces.remove(activeSubflow);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
});
|
||||
|
||||
RED.view.on("selection-changed",function(selection) {
|
||||
if (!selection.nodes) {
|
||||
RED.menu.setDisabled("menu-item-subflow-convert",true);
|
||||
} else {
|
||||
RED.menu.setDisabled("menu-item-subflow-convert",false);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function createSubflow() {
|
||||
var lastIndex = 0;
|
||||
RED.nodes.eachSubflow(function(sf) {
|
||||
var m = (new RegExp("^Subflow (\\d+)$")).exec(sf.name);
|
||||
if (m) {
|
||||
lastIndex = Math.max(lastIndex,m[1]);
|
||||
}
|
||||
});
|
||||
|
||||
var name = "Subflow "+(lastIndex+1);
|
||||
|
||||
var subflowId = RED.nodes.id();
|
||||
var subflow = {
|
||||
type:"subflow",
|
||||
id:subflowId,
|
||||
name:name,
|
||||
in: [],
|
||||
out: []
|
||||
};
|
||||
RED.nodes.addSubflow(subflow);
|
||||
RED.history.push({
|
||||
t:'createSubflow',
|
||||
subflow: subflow,
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
RED.workspaces.show(subflowId);
|
||||
}
|
||||
|
||||
function convertToSubflow() {
|
||||
var selection = RED.view.selection();
|
||||
if (!selection.nodes) {
|
||||
RED.notify("<strong>Cannot create subflow</strong>: no nodes selected","error");
|
||||
return;
|
||||
}
|
||||
var i;
|
||||
var nodes = {};
|
||||
var new_links = [];
|
||||
var removedLinks = [];
|
||||
|
||||
var candidateInputs = [];
|
||||
var candidateOutputs = [];
|
||||
|
||||
var boundingBox = [selection.nodes[0].x,
|
||||
selection.nodes[0].y,
|
||||
selection.nodes[0].x,
|
||||
selection.nodes[0].y];
|
||||
|
||||
for (i=0;i<selection.nodes.length;i++) {
|
||||
var n = selection.nodes[i];
|
||||
nodes[n.id] = {n:n,outputs:{}};
|
||||
boundingBox = [
|
||||
Math.min(boundingBox[0],n.x),
|
||||
Math.min(boundingBox[1],n.y),
|
||||
Math.max(boundingBox[2],n.x),
|
||||
Math.max(boundingBox[3],n.y)
|
||||
]
|
||||
}
|
||||
|
||||
var center = [(boundingBox[2]+boundingBox[0]) / 2,(boundingBox[3]+boundingBox[1]) / 2];
|
||||
|
||||
RED.nodes.eachLink(function(link) {
|
||||
if (nodes[link.source.id] && nodes[link.target.id]) {
|
||||
// A link wholely within the selection
|
||||
}
|
||||
|
||||
if (nodes[link.source.id] && !nodes[link.target.id]) {
|
||||
// An outbound link from the selection
|
||||
candidateOutputs.push(link);
|
||||
removedLinks.push(link);
|
||||
}
|
||||
if (!nodes[link.source.id] && nodes[link.target.id]) {
|
||||
// An inbound link
|
||||
candidateInputs.push(link);
|
||||
removedLinks.push(link);
|
||||
}
|
||||
});
|
||||
|
||||
var outputs = {};
|
||||
candidateOutputs = candidateOutputs.filter(function(v) {
|
||||
if (outputs[v.source.id+":"+v.sourcePort]) {
|
||||
outputs[v.source.id+":"+v.sourcePort].targets.push(v.target);
|
||||
return false;
|
||||
}
|
||||
v.targets = [];
|
||||
v.targets.push(v.target);
|
||||
outputs[v.source.id+":"+v.sourcePort] = v;
|
||||
return true;
|
||||
});
|
||||
candidateOutputs.sort(function(a,b) { return a.source.y-b.source.y});
|
||||
|
||||
if (candidateInputs.length > 1) {
|
||||
RED.notify("<strong>Cannot create subflow</strong>: multiple inputs to selection","error");
|
||||
return;
|
||||
}
|
||||
//if (candidateInputs.length == 0) {
|
||||
// RED.notify("<strong>Cannot create subflow</strong>: no input to selection","error");
|
||||
// return;
|
||||
//}
|
||||
|
||||
|
||||
var lastIndex = 0;
|
||||
RED.nodes.eachSubflow(function(sf) {
|
||||
var m = (new RegExp("^Subflow (\\d+)$")).exec(sf.name);
|
||||
if (m) {
|
||||
lastIndex = Math.max(lastIndex,m[1]);
|
||||
}
|
||||
});
|
||||
|
||||
var name = "Subflow "+(lastIndex+1);
|
||||
|
||||
var subflowId = RED.nodes.id();
|
||||
var subflow = {
|
||||
type:"subflow",
|
||||
id:subflowId,
|
||||
name:name,
|
||||
in: candidateInputs.map(function(v,i) { var index = i; return {
|
||||
type:"subflow",
|
||||
direction:"in",
|
||||
x:v.target.x-(v.target.w/2)-80,
|
||||
y:v.target.y,
|
||||
z:subflowId,
|
||||
i:index,
|
||||
id:RED.nodes.id(),
|
||||
wires:[{id:v.target.id}]
|
||||
}}),
|
||||
out: candidateOutputs.map(function(v,i) { var index = i; return {
|
||||
type:"subflow",
|
||||
direction:"in",
|
||||
x:v.source.x+(v.source.w/2)+80,
|
||||
y:v.source.y,
|
||||
z:subflowId,
|
||||
i:index,
|
||||
id:RED.nodes.id(),
|
||||
wires:[{id:v.source.id,port:v.sourcePort}]
|
||||
}})
|
||||
};
|
||||
RED.nodes.addSubflow(subflow);
|
||||
|
||||
var subflowInstance = {
|
||||
id:RED.nodes.id(),
|
||||
type:"subflow:"+subflow.id,
|
||||
x: center[0],
|
||||
y: center[1],
|
||||
z: RED.workspaces.active(),
|
||||
inputs: subflow.in.length,
|
||||
outputs: subflow.out.length,
|
||||
h: Math.max(30/*node_height*/,(subflow.out.length||0) * 15),
|
||||
changed:true
|
||||
}
|
||||
subflowInstance._def = RED.nodes.getType(subflowInstance.type);
|
||||
RED.editor.validateNode(subflowInstance);
|
||||
RED.nodes.add(subflowInstance);
|
||||
|
||||
candidateInputs.forEach(function(l) {
|
||||
var link = {source:l.source, sourcePort:l.sourcePort, target: subflowInstance};
|
||||
new_links.push(link);
|
||||
RED.nodes.addLink(link);
|
||||
});
|
||||
|
||||
candidateOutputs.forEach(function(output,i) {
|
||||
output.targets.forEach(function(target) {
|
||||
var link = {source:subflowInstance, sourcePort:i, target: target};
|
||||
new_links.push(link);
|
||||
RED.nodes.addLink(link);
|
||||
});
|
||||
});
|
||||
|
||||
subflow.in.forEach(function(input) {
|
||||
input.wires.forEach(function(wire) {
|
||||
var link = {source: input, sourcePort: 0, target: RED.nodes.node(wire.id) }
|
||||
new_links.push(link);
|
||||
RED.nodes.addLink(link);
|
||||
});
|
||||
});
|
||||
subflow.out.forEach(function(output,i) {
|
||||
output.wires.forEach(function(wire) {
|
||||
var link = {source: RED.nodes.node(wire.id), sourcePort: wire.port , target: output }
|
||||
new_links.push(link);
|
||||
RED.nodes.addLink(link);
|
||||
});
|
||||
});
|
||||
|
||||
for (i=0;i<removedLinks.length;i++) {
|
||||
RED.nodes.removeLink(removedLinks[i]);
|
||||
}
|
||||
|
||||
for (i=0;i<selection.nodes.length;i++) {
|
||||
selection.nodes[i].z = subflow.id;
|
||||
}
|
||||
|
||||
RED.history.push({
|
||||
t:'createSubflow',
|
||||
nodes:[subflowInstance.id],
|
||||
links:new_links,
|
||||
subflow: subflow,
|
||||
|
||||
activeWorkspace: RED.workspaces.active(),
|
||||
removedLinks: removedLinks,
|
||||
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
|
||||
RED.editor.validateNode(subflow);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
init: init,
|
||||
createSubflow: createSubflow,
|
||||
convertToSubflow: convertToSubflow
|
||||
}
|
||||
})();
|
191
editor/js/ui/tab-info.js
Normal file
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.sidebar.info = (function() {
|
||||
|
||||
marked.setOptions({
|
||||
renderer: new marked.Renderer(),
|
||||
gfm: true,
|
||||
tables: true,
|
||||
breaks: false,
|
||||
pedantic: false,
|
||||
sanitize: true,
|
||||
smartLists: true,
|
||||
smartypants: false
|
||||
});
|
||||
|
||||
var content = document.createElement("div");
|
||||
content.id = "tab-info";
|
||||
content.style.paddingTop = "4px";
|
||||
content.style.paddingLeft = "4px";
|
||||
content.style.paddingRight = "4px";
|
||||
|
||||
var propertiesExpanded = false;
|
||||
|
||||
function show() {
|
||||
if (!RED.sidebar.containsTab("info")) {
|
||||
RED.sidebar.addTab("info",content,false);
|
||||
}
|
||||
RED.sidebar.show("info");
|
||||
}
|
||||
|
||||
function jsonFilter(key,value) {
|
||||
if (key === "") {
|
||||
return value;
|
||||
}
|
||||
var t = typeof value;
|
||||
if ($.isArray(value)) {
|
||||
return "[array:"+value.length+"]";
|
||||
} else if (t === "object") {
|
||||
return "[object]"
|
||||
} else if (t === "string") {
|
||||
if (value.length > 30) {
|
||||
return value.substring(0,30)+" ...";
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function refresh(node) {
|
||||
var table = '<table class="node-info"><tbody>';
|
||||
table += '<tr class="blank"><td colspan="2">Node</td></tr>';
|
||||
if (node.type != "subflow" && node.name) {
|
||||
table += "<tr><td>Name</td><td> "+node.name+"</td></tr>";
|
||||
}
|
||||
table += "<tr><td>Type</td><td> "+node.type+"</td></tr>";
|
||||
table += "<tr><td>ID</td><td> "+node.id+"</td></tr>";
|
||||
|
||||
var m = /^subflow(:(.+))?$/.exec(node.type);
|
||||
if (m) {
|
||||
var subflowNode;
|
||||
if (m[2]) {
|
||||
subflowNode = RED.nodes.subflow(m[2]);
|
||||
} else {
|
||||
subflowNode = node;
|
||||
}
|
||||
|
||||
table += '<tr class="blank"><td colspan="2">Subflow</td></tr>';
|
||||
|
||||
var userCount = 0;
|
||||
var subflowType = "subflow:"+subflowNode.id;
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type === subflowType) {
|
||||
userCount++;
|
||||
}
|
||||
});
|
||||
table += "<tr><td>name</td><td>"+subflowNode.name+"</td></tr>";
|
||||
table += "<tr><td>instances</td><td>"+userCount+"</td></tr>";
|
||||
}
|
||||
|
||||
if (!m && node.type != "subflow" && node.type != "comment") {
|
||||
table += '<tr class="blank"><td colspan="2"><a href="#" class="node-info-property-header"><i style="width: 10px; text-align: center;" class="fa fa-caret-'+(propertiesExpanded?"down":"right")+'"></i> Properties</a></td></tr>';
|
||||
if (node._def) {
|
||||
for (var n in node._def.defaults) {
|
||||
if (n != "name" && node._def.defaults.hasOwnProperty(n)) {
|
||||
var val = node[n]||"";
|
||||
var type = typeof val;
|
||||
if (type === "string") {
|
||||
if (val.length === 0) {
|
||||
val += '<span style="font-style: italic; color: #ccc;">blank</span>';
|
||||
} else {
|
||||
if (val.length > 30) {
|
||||
val = val.substring(0,30)+" ...";
|
||||
}
|
||||
val = val.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
|
||||
}
|
||||
} else if (type === "number") {
|
||||
val = val.toString();
|
||||
} else if ($.isArray(val)) {
|
||||
val = "[<br/>";
|
||||
for (var i=0;i<Math.min(node[n].length,10);i++) {
|
||||
var vv = JSON.stringify(node[n][i],jsonFilter," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
|
||||
val += " "+i+": "+vv+"<br/>";
|
||||
}
|
||||
if (node[n].length > 10) {
|
||||
val += " ... "+node[n].length+" items<br/>";
|
||||
}
|
||||
val += "]";
|
||||
} else {
|
||||
val = JSON.stringify(val,jsonFilter," ");
|
||||
val = val.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
|
||||
}
|
||||
|
||||
table += '<tr class="node-info-property-row'+(propertiesExpanded?"":" hide")+'"><td>'+n+"</td><td>"+val+"</td></tr>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
table += "</tbody></table><hr/>";
|
||||
if (node.type != "comment") {
|
||||
var helpText = $("script[data-help-name|='"+node.type+"']").html()||"";
|
||||
table += '<div class="node-help">'+helpText+"</div>";
|
||||
}
|
||||
|
||||
if (node._def && node._def.info) {
|
||||
var info = node._def.info;
|
||||
table += '<div class="node-help">'+marked(typeof info === "function" ? info.call(node) : info)+'</div>';
|
||||
//table += '<div class="node-help">'+(typeof info === "function" ? info.call(node) : info)+'</div>';
|
||||
}
|
||||
|
||||
$("#tab-info").html(table);
|
||||
|
||||
$(".node-info-property-header").click(function(e) {
|
||||
var icon = $(this).find("i");
|
||||
if (icon.hasClass("fa-caret-right")) {
|
||||
icon.removeClass("fa-caret-right");
|
||||
icon.addClass("fa-caret-down");
|
||||
$(".node-info-property-row").show();
|
||||
propertiesExpanded = true;
|
||||
} else {
|
||||
icon.addClass("fa-caret-right");
|
||||
icon.removeClass("fa-caret-down");
|
||||
$(".node-info-property-row").hide();
|
||||
propertiesExpanded = false;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
$("#tab-info").html("");
|
||||
}
|
||||
|
||||
RED.view.on("selection-changed",function(selection) {
|
||||
if (selection.nodes) {
|
||||
if (selection.nodes.length == 1) {
|
||||
var node = selection.nodes[0];
|
||||
if (node.type === "subflow" && node.direction) {
|
||||
refresh(RED.nodes.subflow(node.z));
|
||||
} else {
|
||||
refresh(node);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
if (subflow) {
|
||||
refresh(subflow);
|
||||
} else {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
show: show,
|
||||
refresh:refresh,
|
||||
clear: clear
|
||||
}
|
||||
})();
|
270
editor/js/ui/workspaces.js
Normal file
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.workspaces = (function() {
|
||||
|
||||
var activeWorkspace = 0;
|
||||
var workspaceIndex = 0;
|
||||
|
||||
function addWorkspace(ws) {
|
||||
if (ws) {
|
||||
workspace_tabs.addTab(ws);
|
||||
workspace_tabs.resize();
|
||||
} else {
|
||||
var tabId = RED.nodes.id();
|
||||
do {
|
||||
workspaceIndex += 1;
|
||||
} while($("#workspace-tabs a[title='Sheet "+workspaceIndex+"']").size() !== 0);
|
||||
|
||||
ws = {type:"tab",id:tabId,label:"Sheet "+workspaceIndex};
|
||||
RED.nodes.addWorkspace(ws);
|
||||
workspace_tabs.addTab(ws);
|
||||
workspace_tabs.activateTab(tabId);
|
||||
RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()});
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
function deleteWorkspace(ws,force) {
|
||||
if (workspace_tabs.count() == 1) {
|
||||
return;
|
||||
}
|
||||
var nodes = [];
|
||||
if (!force) {
|
||||
nodes = RED.nodes.filterNodes({z:ws.id});
|
||||
}
|
||||
if (force || nodes.length === 0) {
|
||||
removeWorkspace(ws);
|
||||
var historyEvent = RED.nodes.removeWorkspace(ws.id);
|
||||
historyEvent.t = 'delete';
|
||||
historyEvent.dirty = RED.nodes.dirty();
|
||||
historyEvent.workspaces = [ws];
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
} else {
|
||||
$( "#node-dialog-delete-workspace" ).dialog('option','workspace',ws);
|
||||
$( "#node-dialog-delete-workspace-name" ).text(ws.label);
|
||||
$( "#node-dialog-delete-workspace" ).dialog('open');
|
||||
}
|
||||
}
|
||||
function showRenameWorkspaceDialog(id) {
|
||||
var ws = RED.nodes.workspace(id);
|
||||
$( "#node-dialog-rename-workspace" ).dialog("option","workspace",ws);
|
||||
|
||||
if (workspace_tabs.count() == 1) {
|
||||
$( "#node-dialog-rename-workspace").next().find(".leftButton")
|
||||
.prop('disabled',true)
|
||||
.addClass("ui-state-disabled");
|
||||
} else {
|
||||
$( "#node-dialog-rename-workspace").next().find(".leftButton")
|
||||
.prop('disabled',false)
|
||||
.removeClass("ui-state-disabled");
|
||||
}
|
||||
|
||||
$( "#node-input-workspace-name" ).val(ws.label);
|
||||
$( "#node-dialog-rename-workspace" ).dialog("open");
|
||||
}
|
||||
|
||||
var workspace_tabs = RED.tabs.create({
|
||||
id: "workspace-tabs",
|
||||
onchange: function(tab) {
|
||||
if (tab.type == "subflow") {
|
||||
$("#workspace-toolbar").show();
|
||||
} else {
|
||||
$("#workspace-toolbar").hide();
|
||||
}
|
||||
var event = {
|
||||
old: activeWorkspace
|
||||
}
|
||||
activeWorkspace = tab.id;
|
||||
event.workspace = activeWorkspace;
|
||||
|
||||
eventHandler.emit("change",event);
|
||||
},
|
||||
ondblclick: function(tab) {
|
||||
if (tab.type != "subflow") {
|
||||
showRenameWorkspaceDialog(tab.id);
|
||||
} else {
|
||||
RED.editor.editSubflow(RED.nodes.subflow(tab.id));
|
||||
}
|
||||
},
|
||||
onadd: function(tab) {
|
||||
RED.menu.addItem("menu-item-workspace",{
|
||||
id:"menu-item-workspace-menu-"+tab.id.replace(".","-"),
|
||||
label:tab.label,
|
||||
onselect:function() {
|
||||
workspace_tabs.activateTab(tab.id);
|
||||
}
|
||||
});
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
||||
},
|
||||
onremove: function(tab) {
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
||||
RED.menu.removeItem("menu-item-workspace-menu-"+tab.id.replace(".","-"));
|
||||
}
|
||||
});
|
||||
|
||||
$("#node-dialog-rename-workspace form" ).submit(function(e) { e.preventDefault();});
|
||||
$( "#node-dialog-rename-workspace" ).dialog({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 500,
|
||||
title: "Rename sheet",
|
||||
buttons: [
|
||||
{
|
||||
class: 'leftButton',
|
||||
text: "Delete",
|
||||
click: function() {
|
||||
var workspace = $(this).dialog('option','workspace');
|
||||
$( this ).dialog( "close" );
|
||||
deleteWorkspace(workspace);
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Ok",
|
||||
click: function() {
|
||||
var workspace = $(this).dialog('option','workspace');
|
||||
var label = $( "#node-input-workspace-name" ).val();
|
||||
if (workspace.label != label) {
|
||||
workspace_tabs.renameTab(workspace.id,label);
|
||||
RED.nodes.dirty(true);
|
||||
$("#menu-item-workspace-menu-"+workspace.id.replace(".","-")).text(label);
|
||||
// TODO: update entry in menu
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Cancel",
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
],
|
||||
open: function(e) {
|
||||
RED.keyboard.disable();
|
||||
},
|
||||
close: function(e) {
|
||||
RED.keyboard.enable();
|
||||
}
|
||||
});
|
||||
$( "#node-dialog-delete-workspace" ).dialog({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 500,
|
||||
title: "Confirm delete",
|
||||
buttons: [
|
||||
{
|
||||
text: "Ok",
|
||||
click: function() {
|
||||
var workspace = $(this).dialog('option','workspace');
|
||||
deleteWorkspace(workspace,true);
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Cancel",
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
],
|
||||
open: function(e) {
|
||||
RED.keyboard.disable();
|
||||
},
|
||||
close: function(e) {
|
||||
RED.keyboard.enable();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function init() {
|
||||
$('#btn-workspace-add-tab').on("click",function(e) {addWorkspace(); e.preventDefault()});
|
||||
RED.sidebar.on("resize",workspace_tabs.resize);
|
||||
|
||||
RED.menu.setAction('menu-item-workspace-delete',function() {
|
||||
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: DRY
|
||||
var eventHandler = (function() {
|
||||
var handlers = {};
|
||||
|
||||
return {
|
||||
on: function(evt,func) {
|
||||
handlers[evt] = handlers[evt]||[];
|
||||
handlers[evt].push(func);
|
||||
},
|
||||
emit: function(evt,arg) {
|
||||
if (handlers[evt]) {
|
||||
for (var i=0;i<handlers[evt].length;i++) {
|
||||
handlers[evt][i](arg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
function removeWorkspace(ws) {
|
||||
if (!ws) {
|
||||
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
||||
} else {
|
||||
if (workspace_tabs.contains(ws.id)) {
|
||||
workspace_tabs.removeTab(ws.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
on: eventHandler.on,
|
||||
add: addWorkspace,
|
||||
remove: removeWorkspace,
|
||||
|
||||
edit: function(id) {
|
||||
showRenameWorkspaceDialog(id||activeWorkspace);
|
||||
},
|
||||
contains: function(id) {
|
||||
return workspace_tabs.contains(id);
|
||||
},
|
||||
count: function() {
|
||||
return workspace_tabs.count();
|
||||
},
|
||||
active: function() {
|
||||
return activeWorkspace
|
||||
},
|
||||
show: function(id) {
|
||||
if (!workspace_tabs.contains(id)) {
|
||||
var sf = RED.nodes.subflow(id);
|
||||
if (sf) {
|
||||
addWorkspace({type:"subflow",id:id,label:"Subflow: "+sf.name, closeable: true});
|
||||
}
|
||||
}
|
||||
workspace_tabs.activateTab(id);
|
||||
},
|
||||
refresh: function() {
|
||||
RED.nodes.eachSubflow(function(sf) {
|
||||
if (workspace_tabs.contains(sf.id)) {
|
||||
workspace_tabs.renameTab(sf.id,"Subflow: "+sf.name);
|
||||
}
|
||||
});
|
||||
},
|
||||
resize: function() {
|
||||
workspace_tabs.resize();
|
||||
}
|
||||
}
|
||||
})();
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Copyright 2014, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,7 @@ RED.user = (function() {
|
||||
}
|
||||
|
||||
var dialog = $('<div id="node-dialog-login" class="hide">'+
|
||||
'<div style="display: inline-block;width: 250px; vertical-align: top; margin-right: 10px; margin-bottom: 20px;"><img src="node-red-256.png"/></div>'+
|
||||
'<div style="display: inline-block;width: 250px; vertical-align: top; margin-right: 10px; margin-bottom: 20px;"><img id="node-dialog-login-image" src=""/></div>'+
|
||||
'<div style="display: inline-block; width: 250px; vertical-align: bottom; margin-left: 10px; margin-bottom: 20px;">'+
|
||||
'<form id="node-dialog-login-fields" class="form-horizontal" style="margin-bottom: 0px;"></form>'+
|
||||
'</div>'+
|
||||
@@ -45,17 +45,40 @@ RED.user = (function() {
|
||||
success: function(data) {
|
||||
if (data.type == "credentials") {
|
||||
var i=0;
|
||||
|
||||
if (data.image) {
|
||||
$("#node-dialog-login-image").attr("src",data.image);
|
||||
} else {
|
||||
$("#node-dialog-login-image").attr("src","red/images/node-red-256.png");
|
||||
}
|
||||
for (;i<data.prompts.length;i++) {
|
||||
var field = data.prompts[i];
|
||||
var row = $("<div/>",{class:"form-row"});
|
||||
var row = $("<div/>",{id:"rrr"+i,class:"form-row"});
|
||||
$('<label for="node-dialog-login-'+field.id+'">'+field.label+':</label><br/>').appendTo(row);
|
||||
$('<input style="width: 100%" id="node-dialog-login-'+field.id+'" type="'+field.type+'" tabIndex="'+(i+1)+'"/>').appendTo(row);
|
||||
var input = $('<input style="width: 100%" id="node-dialog-login-'+field.id+'" type="'+field.type+'" tabIndex="'+(i+1)+'"/>').appendTo(row);
|
||||
|
||||
if (i<data.prompts.length-1) {
|
||||
input.keypress(
|
||||
(function() {
|
||||
var r = row;
|
||||
return function(event) {
|
||||
if (event.keyCode == 13) {
|
||||
r.next("div").find("input").focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
||||
row.appendTo("#node-dialog-login-fields");
|
||||
}
|
||||
$('<div class="form-row" style="text-align: right; margin-top: 10px;"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;" class="hide">Login failed</span><img src="spin.svg" style="height: 30px; margin-right: 10px; " class="login-spinner hide"/>'+
|
||||
$('<div class="form-row" style="text-align: right; margin-top: 10px;"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;" class="hide">Login failed</span><img src="red/images/spin.svg" style="height: 30px; margin-right: 10px; " class="login-spinner hide"/>'+
|
||||
(opts.cancelable?'<a href="#" id="node-dialog-login-cancel" style="margin-right: 20px;" tabIndex="'+(i+1)+'">Cancel</a>':'')+
|
||||
'<a href="#" id="node-dialog-login-submit" tabIndex="'+(i+2)+'">Login</a></div>').appendTo("#node-dialog-login-fields");
|
||||
$("#node-dialog-login-submit").button().click(function( event ) {
|
||||
'<input type="submit" id="node-dialog-login-submit" style="width: auto;" tabIndex="'+(i+2)+'" value="Login"></div>').appendTo("#node-dialog-login-fields");
|
||||
|
||||
|
||||
$("#node-dialog-login-submit").button();
|
||||
$("#node-dialog-login-fields").submit(function(event) {
|
||||
$("#node-dialog-login-submit").button("option","disabled",true);
|
||||
$("#node-dialog-login-failed").hide();
|
||||
$(".login-spinner").show();
|
||||
@@ -109,7 +132,56 @@ RED.user = (function() {
|
||||
})
|
||||
}
|
||||
|
||||
function updateUserMenu() {
|
||||
$("#usermenu-submenu li").remove();
|
||||
if (RED.settings.user.anonymous) {
|
||||
RED.menu.addItem("btn-usermenu",{
|
||||
id:"usermenu-item-login",
|
||||
label:"Login",
|
||||
onselect: function() {
|
||||
RED.user.login({cancelable:true},function() {
|
||||
RED.settings.load(function() {
|
||||
RED.notify("Logged in as "+RED.settings.user.username,"success");
|
||||
updateUserMenu();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
RED.menu.addItem("btn-usermenu",{
|
||||
id:"usermenu-item-username",
|
||||
label:"<b>"+RED.settings.user.username+"</b>"
|
||||
});
|
||||
RED.menu.addItem("btn-usermenu",{
|
||||
id:"usermenu-item-logout",
|
||||
label:"Logout",
|
||||
onselect: function() {
|
||||
RED.user.logout();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function init() {
|
||||
if (RED.settings.user) {
|
||||
if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu")) {
|
||||
|
||||
$('<li><a id="btn-usermenu" class="button hide" data-toggle="dropdown" href="#"><i class="fa fa-user"></i></a></li>')
|
||||
.prependTo(".header-toolbar");
|
||||
|
||||
RED.menu.init({id:"btn-usermenu",
|
||||
options: []
|
||||
});
|
||||
updateUserMenu();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
login: login,
|
||||
logout: logout
|
||||
}
|
21
editor/sass/bootstrap.scss
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
.popover-title { display: none; }
|
||||
|
||||
div.btn-group, a.btn {
|
||||
@include disable-selection;
|
||||
}
|
37
editor/sass/dragdrop.scss
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
#dropTarget {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
left: 0; right: 0;
|
||||
background: rgba(0,0,0,0.1);
|
||||
display:table;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none;
|
||||
}
|
||||
#dropTarget div {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-size: 40px;
|
||||
color: #fff;
|
||||
}
|
||||
#dropTarget div i {
|
||||
font-size: 80px;
|
||||
}
|
||||
|
84
editor/sass/dropdownMenu.scss
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
|
||||
.dropdown-menu>li>a:hover, .dropdown-menu>li>a:focus, .dropdown-submenu:hover>a, .dropdown-submenu:focus>a {
|
||||
background: #999;
|
||||
}
|
||||
|
||||
.dropdown-menu * .fa-check-square {
|
||||
display: none;
|
||||
color: #e0e0e0;
|
||||
margin-left: -25px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
.dropdown-menu * a.active > .fa-check-square {
|
||||
display: inline-block;
|
||||
}
|
||||
.dropdown-menu * .fa-square {
|
||||
display: inline-block;
|
||||
color: #e0e0e0;
|
||||
margin-left: -25px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
.dropdown-menu * a.active > .fa-square {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.dropdown-menu>li.disabled>a:hover>[class^="icon-"] {
|
||||
background-image: url("vendor/bootstrap/img/glyphicons-halflings.png") !important;
|
||||
}
|
||||
/** Fix for unreachable dropdown menu **/
|
||||
.dropdown-menu {
|
||||
border-radius: 0;
|
||||
width: 200px !important;
|
||||
margin-left: 0px !important;
|
||||
}
|
||||
.dropdown-menu > li > a > i {
|
||||
width: 10px;
|
||||
text-align: center;
|
||||
margin-left: -8px;
|
||||
}
|
||||
.dropdown-menu > li > a {
|
||||
padding-left: 38px ;
|
||||
text-indent: -8px ;
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-submenu>a:after {
|
||||
display: none;
|
||||
}
|
||||
.dropdown-submenu>a:before {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-top: 5px;
|
||||
margin-left: -30px;
|
||||
border-color: transparent;
|
||||
border-right-color: #e0e0e0;
|
||||
border-style: solid;
|
||||
border-width: 5px 5px 5px 0;
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.dropdown-submenu.disabled > a:before {
|
||||
border-right-color: #444;
|
||||
}
|
||||
.dropdown-submenu.pull-left>.dropdown-menu {
|
||||
border-radius: 0;
|
||||
}
|
76
editor/sass/editor.scss
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
.dialog-form, #dialog-form, #dialog-config-form {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.input-error {
|
||||
border-color: rgb(214, 97, 95) !important;
|
||||
}
|
||||
|
||||
.leftButton {
|
||||
margin-right: 200px !important;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
clear: both;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
.form-row label {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
.form-row input {
|
||||
width:70%;
|
||||
}
|
||||
|
||||
input.input-append-left {
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
button.input-append-right {
|
||||
border-top-left-radius: 0px !important;
|
||||
border-bottom-left-radius: 0px !important;
|
||||
border-top-right-radius: 4px !important;
|
||||
border-bottom-right-radius: 4px !important;
|
||||
margin-left: -1px !important;
|
||||
padding-left: 4px !important;
|
||||
padding-right: 4px !important;
|
||||
}
|
||||
|
||||
.form-tips {
|
||||
background: lightgoldenrodyellow;
|
||||
font-size: 12px;
|
||||
padding: 8px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #999;
|
||||
max-width: 450px;
|
||||
}
|
||||
.form-tips code {
|
||||
border: none;
|
||||
padding: auto;
|
||||
}
|
||||
|
||||
.node-text-editor {
|
||||
border:1px solid #ccc;
|
||||
border-radius:5px;
|
||||
overflow: hidden;
|
||||
font-size: 14px !important;
|
||||
font-family: monospace !important;
|
||||
}
|
||||
|
231
editor/sass/flow.scss
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lasso {
|
||||
stroke-width: 2px;
|
||||
stroke: #ff7f0e;
|
||||
fill: rgba(20,125,255,0.1);
|
||||
stroke-dasharray: 10 5;
|
||||
}
|
||||
|
||||
.group-box {
|
||||
stroke-width: 1px;
|
||||
stroke: #aaaaaa;
|
||||
fill: rgba(208, 211, 238, 0.1);
|
||||
stroke-dasharray: 3 3;
|
||||
}
|
||||
.group-box-active {
|
||||
fill: #fff;
|
||||
stroke: #ff7f0e;
|
||||
}
|
||||
|
||||
.group_label {
|
||||
stroke-width: 0;
|
||||
fill: #999;
|
||||
font-size: 11px;
|
||||
pointer-events: none;
|
||||
-webkit-touch-callout: none;
|
||||
@include disable-selection;
|
||||
}
|
||||
|
||||
.pull-right {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#workspace {
|
||||
@include component-border;
|
||||
}
|
||||
|
||||
.node_label_italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.node_label_unknown {
|
||||
font-style: italic;
|
||||
fill: #e00 !important;
|
||||
}
|
||||
.node_label_white {
|
||||
fill: #eee !important;
|
||||
}
|
||||
.node_label {
|
||||
stroke-width: 0;
|
||||
fill: #333;
|
||||
font-size: 14px;
|
||||
pointer-events: none;
|
||||
-webkit-touch-callout: none;
|
||||
@include disable-selection;
|
||||
}
|
||||
|
||||
.port_label {
|
||||
stroke-width: 0;
|
||||
fill: #888;
|
||||
font-size: 16px;
|
||||
alignment-baseline: middle;
|
||||
text-anchor: middle;
|
||||
pointer-events: none;
|
||||
-webkit-touch-callout: none;
|
||||
@include disable-selection;
|
||||
}
|
||||
|
||||
|
||||
.function_label {
|
||||
font-size: 12px;
|
||||
}
|
||||
.node {
|
||||
stroke: #999;
|
||||
cursor: move;
|
||||
stroke-width: 2;
|
||||
}
|
||||
.node_unknown {
|
||||
stroke-dasharray:10,4;
|
||||
stroke: #f33;
|
||||
}
|
||||
.tool_arrow {
|
||||
stroke-width: 1;
|
||||
stroke: #999;
|
||||
fill: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
.node_tools {
|
||||
fill: #ddd;
|
||||
stroke: #999;
|
||||
cursor: move;
|
||||
stroke-width: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.node_tools_hovered {
|
||||
stroke: #ff7f0e;
|
||||
fill: #eee;
|
||||
}
|
||||
|
||||
.node_button {
|
||||
fill: inherit;
|
||||
|
||||
}
|
||||
.port {
|
||||
stroke: #999;
|
||||
stroke-width: 2;
|
||||
fill: #ddd;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.port_highlight {
|
||||
stroke: #6DA332;
|
||||
stroke-width: 3;
|
||||
fill: #fff;
|
||||
pointer-events:none;
|
||||
fill-opacity: 0.5;
|
||||
}
|
||||
|
||||
|
||||
.node_error {
|
||||
stroke: #ff0000;
|
||||
stroke-width: 2;
|
||||
fill: #ff7f0e;
|
||||
}
|
||||
|
||||
.node_badge {
|
||||
stroke: rgb(93, 114, 145);
|
||||
stroke-width: 1;
|
||||
fill: rgb(190, 209, 255);
|
||||
}
|
||||
.node_badge_label {
|
||||
stroke-width:0;
|
||||
fill: #fff;
|
||||
font-size: 11px;
|
||||
pointer-events: none;
|
||||
-webkit-touch-callout: none;
|
||||
@include disable-selection;
|
||||
|
||||
}
|
||||
.node_invalid {
|
||||
stroke: #ff0000;
|
||||
}
|
||||
.node_selected {
|
||||
stroke: #ff7f0e !important;
|
||||
}
|
||||
.node_highlighted {
|
||||
stroke: #dd1616;
|
||||
stroke-width: 3;
|
||||
stroke-dasharray: 10, 4;
|
||||
}
|
||||
.node_hovered {
|
||||
}
|
||||
|
||||
.port_hovered {
|
||||
stroke: #ff7f0e;
|
||||
fill: #ff7f0e;
|
||||
}
|
||||
.subflowport {
|
||||
stroke-dasharray: 5,5;
|
||||
fill: #eee;
|
||||
stroke: #999;
|
||||
}
|
||||
|
||||
.drag_line {
|
||||
stroke: #ff7f0e;
|
||||
stroke-width: 5;
|
||||
fill: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.drag_line_hidden {
|
||||
stroke: #ff7f0e;
|
||||
stroke-width: 0;
|
||||
pointer-events: none;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.link_line {
|
||||
stroke: #7f7f7f;
|
||||
stroke-width: 4;
|
||||
fill: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.link_subflow {
|
||||
stroke: #bbb;
|
||||
stroke-dasharray: 10,5;
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
.link_outline {
|
||||
stroke: #fff;
|
||||
stroke-width: 6;
|
||||
cursor: crosshair;
|
||||
fill: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
.link_background {
|
||||
stroke: #fff;
|
||||
opacity: 0;
|
||||
stroke-width: 25;
|
||||
cursor: crosshair;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
g.link_selected path.link_line {
|
||||
stroke: #ff7f0e;
|
||||
}
|
||||
g.link_unknown path.link_line {
|
||||
stroke: #f00;
|
||||
stroke-width: 2;
|
||||
stroke-dasharray: 10, 4;
|
||||
}
|
||||
|
267
editor/sass/header.scss
Normal file
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
$activeButton: #121212;
|
||||
|
||||
$deployButton: #8C101C;
|
||||
$deployButtonHover: #6E0A1E;
|
||||
$deployButtonActive: #4C0A17;
|
||||
|
||||
$deployDisabledButton: #444;
|
||||
$deployDisabledButtonHover: #555;
|
||||
$deployDisabledButtonActive: #444;
|
||||
|
||||
$headerMenuBackground: #121212;
|
||||
$headerMenuItemHover: #323232;
|
||||
$headerMenuItemDivider: #464646;
|
||||
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background: #000;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 0px 0px 20px;
|
||||
color: #C7C7C7;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
span.logo {
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
font-size: 30px;
|
||||
line-height: 30px;
|
||||
text-decoration: none;
|
||||
|
||||
span {
|
||||
vertical-align: middle;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
img {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.header-toolbar {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
float: right;
|
||||
|
||||
> li {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
@include disable-selection;
|
||||
}
|
||||
|
||||
#header .button {
|
||||
min-width: 20px;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
padding: 0px 12px;
|
||||
text-decoration: none;
|
||||
color: #C7C7C7;
|
||||
margin: auto 5px;
|
||||
vertical-align: middle;
|
||||
border-left: 2px solid #000;
|
||||
border-right: 2px solid #000;
|
||||
|
||||
&:hover {
|
||||
border-color: $headerMenuItemHover;
|
||||
}
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: inline-block;
|
||||
margin: auto 15px;
|
||||
vertical-align: middle;
|
||||
clear: both;
|
||||
}
|
||||
.button-group > a {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
line-height: 22px;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
padding: 4px 8px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.deploy-button {
|
||||
background: $deployButton;
|
||||
color: #eee !important;
|
||||
|
||||
&:hover {
|
||||
background: $deployButtonHover;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: $deployButtonActive;
|
||||
color: #ccc !important;
|
||||
}
|
||||
}
|
||||
|
||||
#btn-deploy {
|
||||
|
||||
padding: 4px 12px;
|
||||
|
||||
&.disabled {
|
||||
cursor: default;
|
||||
background: $deployDisabledButton;
|
||||
color: #999 !important;
|
||||
|
||||
img {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&+ #btn-deploy-options {
|
||||
background: $deployDisabledButton;
|
||||
color: #ddd;
|
||||
}
|
||||
&+ #btn-deploy-options:hover {
|
||||
background: $deployDisabledButtonHover;
|
||||
}
|
||||
&+ #btn-deploy-options:active {
|
||||
background: $deployDisabledButton;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.deploy-button-group.open {
|
||||
#btn-deploy-options {
|
||||
background: $activeButton !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#header .button {
|
||||
&:active, &.active {
|
||||
background: $activeButton;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
#header li.open .button {
|
||||
background: $activeButton;
|
||||
border-color: $activeButton;
|
||||
}
|
||||
|
||||
|
||||
#header ul.dropdown-menu {
|
||||
background: $headerMenuBackground;
|
||||
width: 250px !important;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#header ul.dropdown-menu li a {
|
||||
color: #C7C7C7;
|
||||
padding: 3px 40px;
|
||||
}
|
||||
|
||||
#header ul.dropdown-menu li a img {
|
||||
margin-right: 10px;
|
||||
padding: 4px;
|
||||
border: 3px solid rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
#header ul.dropdown-menu li a.active img {
|
||||
border: 3px solid #777677;
|
||||
}
|
||||
|
||||
#header ul.dropdown-menu li a span.menu-label-container {
|
||||
width: 180px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
text-indent: 0px;
|
||||
}
|
||||
#header ul.dropdown-menu li a span.menu-label {
|
||||
font-size: 14px;
|
||||
display: inline-block;
|
||||
text-indent: 0px;
|
||||
}
|
||||
#header ul.dropdown-menu li a span.menu-sublabel {
|
||||
color: #aeaeae;
|
||||
font-size: 13px;
|
||||
display: inline-block;
|
||||
text-indent: 0px;
|
||||
}
|
||||
|
||||
#header ul.dropdown-menu > li:hover > a,
|
||||
#header ul.dropdown-menu > li:focus > a {
|
||||
background: $headerMenuItemHover !important;
|
||||
}
|
||||
|
||||
#header ul.dropdown-menu li.divider {
|
||||
background: $headerMenuItemDivider;
|
||||
border-bottom-color: $headerMenuItemHover;
|
||||
}
|
||||
#header ul.dropdown-menu li.disabled a {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#header ul.dropdown-menu > li.disabled:hover > a,
|
||||
#header ul.dropdown-menu > li.disabled:focus > a {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
/* Deploy menu customisations */
|
||||
#header ul#btn-deploy-options-submenu {
|
||||
width: 300px !important;
|
||||
}
|
||||
#header ul#btn-deploy-options-submenu li a span.menu-label {
|
||||
font-size: 16px;
|
||||
display: inline-block;
|
||||
text-indent: 0px;
|
||||
}
|
||||
#header ul#btn-deploy-options-submenu li a {
|
||||
padding: 10px 30px;
|
||||
color: #fff;
|
||||
}
|
||||
#header ul#btn-deploy-options-submenu li a > i.fa {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* User menu customisations */
|
||||
#header ul#btn-usermenu-submenu li a#btn-username > .menu-label {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
|
53
editor/sass/jquery.scss
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
/* jQuery Theme overrides */
|
||||
.ui-tabs .ui-tabs-panel {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.ui-autocomplete {
|
||||
max-height: 250px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.ui-dialog {
|
||||
border-radius: 1px;
|
||||
border: 1px solid #eee;
|
||||
background: #fff;
|
||||
padding: 0;
|
||||
box-shadow: 2px 2px 12px rgba(0,0,0,0.2);
|
||||
}
|
||||
.ui-dialog .ui-dialog-content {
|
||||
padding: 25px 25px 10px 25px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-titlebar {
|
||||
padding: 10px;
|
||||
background: #f0f0f0;
|
||||
border: none;
|
||||
border-bottom: 2px solid #888;
|
||||
border-radius: 0;
|
||||
}
|
||||
.ui-corner-all {
|
||||
border-radius: 2px;
|
||||
}
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
.ui-dialog-no-close .ui-dialog-titlebar-close {
|
||||
display: none;
|
||||
}
|
40
editor/sass/keyboard.scss
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
#keyboard-help-dialog {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.keyboard-shortcuts {
|
||||
padding: 10px;
|
||||
}
|
||||
.keyboard-shortcuts td {
|
||||
padding: 7px 5px;
|
||||
margin-bottom: 10px;
|
||||
white-space: pre;
|
||||
}
|
||||
.keyboard-shortcuts td:first-child {
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.help-key {
|
||||
border: 1px solid #ddd;
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
background: #f6f6f6;
|
||||
font-family: Courier, monospace;
|
||||
box-shadow: #999 1px 1px 1px;
|
||||
}
|
||||
|
33
editor/sass/library.scss
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
#node-select-library {
|
||||
overflow: hidden;
|
||||
}
|
||||
#node-select-library ul {
|
||||
list-style: none;
|
||||
padding: 0px;
|
||||
margin: 2px;
|
||||
}
|
||||
#node-select-library li {
|
||||
cursor: pointer;
|
||||
}
|
||||
#node-select-library li.list-selected {
|
||||
background: #eee;
|
||||
}
|
||||
#node-select-library li.list-hover {
|
||||
background: #ffffd0;
|
||||
}
|
29
editor/sass/mixins.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
@mixin disable-selection {
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@mixin component-border {
|
||||
border: 1px solid #000;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
32
editor/sass/notifications.scss
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
|
||||
.notification {
|
||||
position: absolute;
|
||||
}
|
||||
#notifications {
|
||||
z-index: 10000;
|
||||
width: 500px;
|
||||
margin-left: -250px;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
}
|
||||
#notifications .alert {
|
||||
box-shadow: 0 0 1px 1px;
|
||||
margin-bottom: 5px;
|
||||
}
|
200
editor/sass/palette.scss
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
|
||||
#palette {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
bottom: 10px;
|
||||
left:10px;
|
||||
background: #f3f3f3;
|
||||
width: 170px;
|
||||
text-align: center;
|
||||
@include disable-selection;
|
||||
@include component-border;
|
||||
|
||||
}
|
||||
.palette-scroll {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 35px;
|
||||
left:0;
|
||||
padding: 5px;
|
||||
overflow-y: auto;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
.palette-spinner {
|
||||
padding-top: 40px;
|
||||
}
|
||||
#palette-search {
|
||||
position: absolute;
|
||||
display: none;
|
||||
bottom: 0;
|
||||
left:0;
|
||||
right:0;
|
||||
overflow: hidden;
|
||||
background: #f3f3f3;
|
||||
text-align: center;
|
||||
height: 35px;
|
||||
padding: 3px;
|
||||
border-top: 1px solid #999;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
#palette-search i.fa-search {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
left: 4px;
|
||||
top: 10px;
|
||||
}
|
||||
#palette-search i.fa-times {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
#palette-search-clear {
|
||||
display: none;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#palette-search input {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
width: 100%;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
padding: 3px 17px;
|
||||
margin: 0px;
|
||||
height: 30px;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
|
||||
#palette-search input:focus {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
|
||||
.palette-category {
|
||||
border: 1px solid #999;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.palette-content {
|
||||
background: #fff;
|
||||
border-top: 1px solid #aaa;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.palette-header {
|
||||
background: #f3f3f3;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
padding: 1px;
|
||||
}
|
||||
.palette-header i {
|
||||
margin: 3px 4px 3px 3px;
|
||||
-webkit-transition: all 0.2s ease-in-out;
|
||||
-moz-transition: all 0.2s ease-in-out;
|
||||
-o-transition: all 0.2s ease-in-out;
|
||||
-webkit-transform: rotate(-90deg);
|
||||
-moz-transform: rotate(-90deg);
|
||||
-o-transform: rotate(-90deg);
|
||||
}
|
||||
.palette-header i.expanded {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
}
|
||||
.palette-header span {
|
||||
clear: both;
|
||||
}
|
||||
.palette_label {
|
||||
margin: 4px 0 4px 28px;
|
||||
line-height: 20px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
.palette_label_right {
|
||||
margin: 4px 28px 4px 0;
|
||||
}
|
||||
|
||||
.palette_node {
|
||||
cursor:move;
|
||||
font-size:13px;
|
||||
background: #ddd;
|
||||
margin: 10px auto;
|
||||
height: 25px;
|
||||
border-radius: 6px;
|
||||
border: 2px solid #999;
|
||||
background-position: 5% 50%;
|
||||
background-repeat: no-repeat;
|
||||
width: 120px;
|
||||
background-size: contain;
|
||||
position: relative;
|
||||
}
|
||||
.palette_node:hover {
|
||||
border-color: #ff7f0e;
|
||||
background-color: #eee;
|
||||
}
|
||||
.palette_port {
|
||||
position: absolute;
|
||||
top:8px;
|
||||
left: -5px;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
background:#d9d9d9;
|
||||
border-radius: 3px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
.palette_port_output {
|
||||
left:auto;
|
||||
right: -6px;
|
||||
}
|
||||
|
||||
.palette_node:hover .palette_port {
|
||||
border-color: #999;
|
||||
background-color: #eee;
|
||||
}
|
||||
.palette_icon_container {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top:0;
|
||||
bottom:0;
|
||||
left:0;
|
||||
width: 30px;
|
||||
border-right: 2px solid rgba(0,0,0,0.1);
|
||||
background-color: rgba(0,0,0,0.05);
|
||||
}
|
||||
.palette_icon_container_right {
|
||||
left: auto;
|
||||
right: 0;
|
||||
border-right: none;
|
||||
border-left: 2px solid rgba(0,0,0,0.1);
|
||||
}
|
||||
.palette_icon {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 100%;
|
||||
background-position: 50% 50%;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
60
editor/sass/sidebar.scss
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
|
||||
|
||||
#sidebar {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
width: 305px;
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
@include component-border;
|
||||
}
|
||||
|
||||
#sidebar.closing {
|
||||
background: #eee;
|
||||
border-color: #900;
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
#sidebar-content {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
right: 0;
|
||||
bottom: 1px;
|
||||
left: 0px;
|
||||
font-size: 1.2em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#sidebar-separator {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 316px;
|
||||
bottom:10px;
|
||||
width: 15px;
|
||||
background: url(images/grip.png) no-repeat 50% 50%;
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
.sidebar-closed > #sidebar { display: none; }
|
||||
.sidebar-closed > #sidebar-separator { right: 0px !important; }
|
||||
.sidebar-closed > #workspace { right: 15px !important; }
|
||||
.sidebar-closed > #chart-zoom-controls { right: 35px !important; }
|
||||
|
70
editor/sass/style.scss
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
@import "mixins";
|
||||
|
||||
@import "jquery";
|
||||
@import "bootstrap";
|
||||
|
||||
@import "dropdownMenu";
|
||||
|
||||
@import "header";
|
||||
@import "palette";
|
||||
@import "sidebar";
|
||||
@import "workspace";
|
||||
@import "workspaceToolbar";
|
||||
|
||||
@import "notifications";
|
||||
|
||||
@import "editor";
|
||||
@import "library";
|
||||
|
||||
@import "tabs";
|
||||
@import "tab-config";
|
||||
@import "tab-info";
|
||||
|
||||
@import "flow";
|
||||
|
||||
@import "dragdrop";
|
||||
|
||||
@import "keyboard";
|
||||
|
||||
|
||||
body {
|
||||
font: 13px "Helvetica" !important;
|
||||
padding-top: 100px;
|
||||
background: url("images/pw_maze_white.png");
|
||||
}
|
||||
|
||||
#main-container {
|
||||
position: absolute;
|
||||
top:50px; left:0; bottom: 0; right:0;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
i.spinner {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
line-height: 14px;
|
||||
vertical-align: text-top;
|
||||
margin-top: 0px;
|
||||
background: url(images/spin.svg) no-repeat 50% 50%;
|
||||
background-size: contain
|
||||
}
|
||||
|
||||
|
||||
|
63
editor/sass/tab-config.scss
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
ul.tab-config-list {
|
||||
list-style-type: none;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
@include disable-selection;
|
||||
}
|
||||
|
||||
ul.tab-config-list li {
|
||||
max-width: 400px;
|
||||
font-size: 13px;
|
||||
background: #f3f3f3;
|
||||
margin: 10px auto;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 3px 8px;
|
||||
}
|
||||
div.tab-config-list-type {
|
||||
}
|
||||
|
||||
div.tab-config-list-entry {
|
||||
position: relative;
|
||||
margin: 4px 0;
|
||||
padding: 8px 4px 8px 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
div.tab-config-list-entry:hover {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
div.tab-config-list-label {
|
||||
}
|
||||
div.tab-config-list-users {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 3px;
|
||||
bottom: 3px;
|
||||
line-height: 27px;
|
||||
font-size: 11px;
|
||||
background: #f6f6f6;
|
||||
float: right;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 3px;
|
||||
padding: 1px 5px;
|
||||
}
|
77
editor/sass/tab-info.scss
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
table.node-info {
|
||||
font-size: 14px;
|
||||
margin: 5px;
|
||||
width: 97%;
|
||||
}
|
||||
table.node-info tr {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
table.node-info tr.blank {
|
||||
border: none;
|
||||
}
|
||||
table.node-info tr.blank td {
|
||||
padding-top: 8px;
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
padding-left: 0px;
|
||||
}
|
||||
table.node-info td:first-child{
|
||||
color: #000;
|
||||
vertical-align: top;
|
||||
width: 90px;
|
||||
padding: 3px;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
table.node-info td:last-child{
|
||||
padding-left: 5px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
div.node-info {
|
||||
margin: 5px;
|
||||
}
|
||||
.node-info-property-header {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.node-info-property-header:hover,
|
||||
.node-info-property-header:focus {
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
}
|
||||
.node-help {
|
||||
font-size: 16px;
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
font-size: 1.953em;
|
||||
margin: 8px auto;
|
||||
}
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
font-size: 1.563em;
|
||||
margin: 8px auto;
|
||||
}
|
||||
h3,
|
||||
h4,
|
||||
h5 {
|
||||
font-weight: normal;
|
||||
font-size: 1.25em;
|
||||
margin: 8px auto;
|
||||
}
|
||||
}
|
101
editor/sass/tabs.scss
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
ul.red-ui-tabs {
|
||||
list-style-type: none;
|
||||
padding:5px 2px 0px 5px;
|
||||
margin: 0;
|
||||
display: block;
|
||||
height: 24px;
|
||||
border-bottom: 1px solid #999;
|
||||
background: #e3e3e3;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
ul.red-ui-tabs li {
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
display: inline-block;
|
||||
border-left: 1px solid #999;
|
||||
border-top: 1px solid #999;
|
||||
border-right: 1px solid #999;
|
||||
border-bottom: 1px solid #999;
|
||||
background: #e3e3e3;
|
||||
margin: 0 5px 0 0;
|
||||
height: 23px;
|
||||
line-height: 17px;
|
||||
max-width: 200px;
|
||||
width: 14%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
ul.red-ui-tabs li a.red-ui-tab-label {
|
||||
display: block;
|
||||
padding: 3px 16px;
|
||||
color: #666;
|
||||
}
|
||||
ul.red-ui-tabs li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ul.red-ui-tabs li a.red-ui-tab-close {
|
||||
background: rgba(227,227,227,0.8);
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
padding: 0px;
|
||||
border-radius: 5px;
|
||||
color: #666;
|
||||
}
|
||||
ul.red-ui-tabs li a.red-ui-tab-close:hover {
|
||||
background: #bbb !important;
|
||||
}
|
||||
ul.red-ui-tabs li a:hover {
|
||||
text-decoration: none;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
ul.red-ui-tabs li.active {
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
ul.red-ui-tabs li.active a {
|
||||
color: #333;
|
||||
}
|
||||
ul.red-ui-tabs li.active a.red-ui-tab-close {
|
||||
background: rgba(255,255,255,0.8);
|
||||
}
|
||||
ul.red-ui-tabs li.active a.red-ui-tab-label:hover {
|
||||
background: #fff;
|
||||
}
|
||||
ul.red-ui-tabs li.red-ui-add-tab {
|
||||
width: 25px;
|
||||
border-top-right-radius: 15px;
|
||||
line-height: 22px;
|
||||
}
|
||||
ul.red-ui-tabs li.red-ui-add-tab a {
|
||||
padding: 2px 4px;
|
||||
}
|
76
editor/sass/workspace.scss
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
|
||||
#chart {
|
||||
overflow: auto;
|
||||
background: #e3e3e3;
|
||||
position: absolute;
|
||||
bottom:0px;
|
||||
top: 30px;
|
||||
left:0px;
|
||||
right:0px;
|
||||
}
|
||||
#chart svg:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#workspace {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
top:5px;
|
||||
left:190px;
|
||||
bottom: 10px;
|
||||
right: 330px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#chart-zoom-controls {
|
||||
position: absolute;
|
||||
bottom:30px; right: 350px;
|
||||
}
|
||||
|
||||
#chart-zoom-controls {
|
||||
padding-top: 3px;
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#workspace-tabs {
|
||||
margin-right: 28px;
|
||||
}
|
||||
#workspace-add-tab {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 29px;
|
||||
width: 28px;
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
|
||||
#btn-workspace-add-tab {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
background: #e3e3e3;
|
||||
height: 100%;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
color: #000;
|
||||
}
|
||||
#btn-workspace-add-tab:hover {
|
||||
background: #efefef;
|
||||
}
|
||||
|
54
editor/sass/workspaceToolbar.scss
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
|
||||
#workspace-toolbar {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left:0;
|
||||
right: 20px;
|
||||
padding: 7px;
|
||||
border-bottom-right-radius: 5px;
|
||||
background: #f3f3f3;
|
||||
}
|
||||
|
||||
#workspace-toolbar .button {
|
||||
line-height: 18px;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
color: #666;
|
||||
background: #f6f6f6;
|
||||
vertical-align: middle;
|
||||
box-shadow: 0 0 2px #888;
|
||||
margin-right: 5px;
|
||||
}
|
||||
#workspace-toolbar .button.disabled {
|
||||
box-shadow: 0 0 2px #bbb;
|
||||
color: #aaa;
|
||||
cursor: default;
|
||||
}
|
||||
#workspace-toolbar .button:not(.disabled):hover {
|
||||
background: #e6e6e6;
|
||||
box-shadow: 0 0 2px #666;
|
||||
}
|
||||
#workspace-toolbar .button:not(.disabled):active {
|
||||
background: #e0e0e0;
|
||||
box-shadow: 0 0 2px #444;
|
||||
}
|