Compare commits

..

5 Commits

Author SHA1 Message Date
Nick O'Leary
3ca64057c3 Add breakpoint editing to debugger 2016-11-22 12:57:30 +00:00
Nick O'Leary
127b4f0226 Add RED.utils.getNodeLabel utility function 2016-11-22 12:57:08 +00:00
Nick O'Leary
629c63e0c9 Add initial debugger panel to debug tab 2016-11-18 12:53:05 +00:00
Nick O'Leary
416d5190bc Flow debugger initial pass 2016-11-16 15:12:30 +00:00
Nick O'Leary
cebddc0237 Add message router component 2016-11-16 15:12:30 +00:00
1700 changed files with 53739 additions and 287503 deletions

1
.gitattributes vendored
View File

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

View File

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

View File

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

View File

@@ -1,34 +0,0 @@
<!--
## Before you hit that Submit button....
Please read our [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
before submitting a pull-request.
## Types of changes
What types of changes does your code introduce?
Put an `x` in the boxes that apply
-->
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
<!--
If you want to raise a pull-request with a new feature, or a refactoring
of existing code, it **may well get rejected** if it hasn't been discussed on
the [forum](https://discourse.nodered.org) or
[slack team](https://nodered.org/slack) first.
-->
## Proposed changes
<!-- Describe the nature of this change. What problem does it address? -->
## Checklist
<!-- Put an `x` in the boxes that apply -->
- [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
- [ ] For non-bugfix PRs, I have discussed this change on the forum/slack team.
- [ ] I have run `npm run test` to verify the unit tests pass
- [ ] I have added suitable unit tests to cover the new/changed functionality

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,36 +0,0 @@
name: Run tests
on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]
permissions:
contents: read
jobs:
build:
permissions:
checks: write # for coverallsapp/github-action to create new checks
contents: read # for actions/checkout to fetch code
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
run: npm install
- name: Run tests
run: |
npm run test
# - name: Publish to coveralls.io
# if: ${{ matrix.node-version == 16 }}
# uses: coverallsapp/github-action@v1.1.2
# with:
# github-token: ${{ github.token }}

11
.gitignore vendored
View File

@@ -7,9 +7,7 @@
.sessions.json
.settings
.tern-project
.i18n-editor-metadata
*.backup
*.bak
*_cred*
coverage
credentials.json
@@ -19,12 +17,3 @@ node_modules
public
locales/zz-ZZ
nodes/core/locales/zz-ZZ
!packages/node_modules
packages/node_modules/@node-red/editor-client/public
!test/**/node_modules
docs
!packages/node_modules/**/docs
.vscode
.nyc_output
sync.ffs_db
package-lock.json

View File

@@ -2,9 +2,6 @@
"asi": true, // allow missing semicolons
"curly": true, // require braces
"eqnull": true, // ignore ==null
//"eqeqeq": true, // enforce ===
"freeze": true, // don't allow override
"indent": 4, // default indent of 4
"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
@@ -12,8 +9,6 @@
//"unused": true, // Check for unused functions and variables
"loopfunc": true, // allow functions to be defined in loops
//"expr": true, // allow ternery operator syntax...
"shadow": true, // allow variable shadowing (re-use of names...)
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
"proto": true, // allow setting of __proto__ in node < v0.12,
"esversion": 11 // allow es11(ES2020)
"proto": true // allow setting of __proto__ in node < v0.12
}

View File

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

7
.npmignore Normal file
View File

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

24
.travis.yml Normal file
View File

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

19
API.md
View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -9,16 +9,13 @@ We welcome contributions, but request you follow these guidelines.
This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/).
By participating, you are expected to uphold this code. Please report unacceptable
behavior to the project's core team at team@nodered.org.
behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core).
## Raising issues
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.
If your issue is more of a question on how to do something with Node-RED, please
consider using the [community forum](https://discourse.nodered.org/).
A good bug report is one that make it easy for us to understand what you were
trying to do and what went wrong.
@@ -29,34 +26,33 @@ relevant nodes, press Ctrl-E and copy the flow data from the Export dialog.
At a minimum, please include:
- Version of Node-RED - either release number if you downloaded a zip, or the first few lines of `git log` if you are cloning the repository directly.
- Version of Node.js - what does `node -v` say?
- Version of node.js - what does `node -v` say?
## Feature requests
For feature requests, please raise them on the [forum](https://discourse.nodered.org).
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
## Pull-Requests
If you want to raise a pull-request with a new feature, or a refactoring
of existing code, please come and discuss it with us first. We prefer to
do it that way to make sure your time and effort is well spent on something
that fits with our goals.
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.
If you've got a bug-fix or similar for us, then you are most welcome to
get it raised - just make sure you link back to the issue it's fixing and
try to include some tests!
### Contributor License Agreement
All contributors need to sign the OpenJS Foundation's Contributor License Agreement.
It is an online process and quick to do. If you raise a pull-request without
having signed the CLA, you will be prompted to do so automatically.
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
change your rights to use your own Contributions for any other purpose.
### Code Branches
You can download the CLAs here:
When raising a PR for a fix or a new feature, it is important to target the right branch.
- [individual](http://nodered.org/cla/node-red-cla-individual.pdf)
- [corporate](http://nodered.org/cla/node-red-cla-corporate.pdf)
- `master` - this is the main branch for the latest stable release of Node-RED. All bug fixes for that release should target this branch.
- `v1.x` - this is the maintenance branch for the 1.x stream. If a fix *only* applies to 1.x, then it should target this branch. If it applies to the current stable release as well, target `master` first. We will then decide if it needs to be back ported to the 1.x stream.
- `dev` - this is the branch for new feature development targeting the next milestone release.
If you are an IBMer, please contact us directly as the contribution process is
slightly different.
### Coding standards

View File

@@ -1,5 +1,5 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
* Copyright 2013, 2016 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,35 +15,17 @@
**/
var path = require("path");
var fs = require("fs-extra");
var sass = require("sass");
module.exports = function(grunt) {
var nodemonArgs = ["-V"];
var nodemonArgs = ["-v"];
var flowFile = grunt.option('flowFile');
if (flowFile) {
nodemonArgs.push(flowFile);
process.env.NODE_RED_ENABLE_PROJECTS=false;
}
var userDir = grunt.option('userDir');
if (userDir) {
nodemonArgs.push("-u");
nodemonArgs.push(userDir);
}
var browserstack = grunt.option('browserstack');
if (browserstack) {
process.env.BROWSERSTACK = true;
}
var nonHeadless = grunt.option('non-headless');
if (nonHeadless) {
process.env.NODE_RED_NON_HEADLESS = true;
}
const pkg = grunt.file.readJSON('package.json');
process.env.NODE_RED_PACKAGE_VERSION = pkg.version;
grunt.initConfig({
pkg: pkg,
pkg: grunt.file.readJSON('package.json'),
paths: {
dist: ".dist"
},
@@ -55,29 +37,10 @@ module.exports = function(grunt) {
ui: 'bdd',
reporter: 'spec'
},
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
all: { src: ['test/**/*_spec.js'] },
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]}
},
webdriver: {
all: {
configFile: 'test/editor/wdio.conf.js'
}
},
nyc: {
options: {
cwd: '.',
include: ['packages/node_modules/**'],
excludeNodeModules: false,
exclude: ['packages/node_modules/@node-red/editor-client/**'],
reporter: ['lcov', 'html','text-summary'],
reportDir: 'coverage',
all: true
},
all: { cmd: false, args: ['grunt', 'simplemocha:all'] },
core: { options: { exclude:['packages/node_modules/@node-red/editor-client/**', 'packages/node_modules/@node-red/nodes/**']},cmd: false, args: ['grunt', 'simplemocha:core'] },
nodes: { cmd: false, args: ['grunt', 'simplemocha:nodes'] }
},
jshint: {
options: {
jshintrc:true
@@ -92,20 +55,22 @@ module.exports = function(grunt) {
//"loopfunc": true, // allow functions to be defined in loops
//"sub": true // don't warn that foo['bar'] should be written as foo.bar
},
// all: [
// 'Gruntfile.js',
// 'red.js',
// 'packages/**/*.js'
// ],
// core: {
// files: {
// src: [
// 'Gruntfile.js',
// 'red.js',
// 'packages/**/*.js',
// ]
// }
// },
all: [
'Gruntfile.js',
'red.js',
'red/**/*.js',
'nodes/core/*/*.js',
'editor/js/**/*.js'
],
core: {
files: {
src: [
'Gruntfile.js',
'red.js',
'red/**/*.js'
]
}
},
nodes: {
files: {
src: [ 'nodes/core/*/*.js' ]
@@ -113,7 +78,7 @@ module.exports = function(grunt) {
},
editor: {
files: {
src: [ 'packages/node_modules/@node-red/editor-client/src/js/**/*.js' ]
src: [ 'editor/js/**/*.js' ]
}
},
tests: {
@@ -133,110 +98,61 @@ module.exports = function(grunt) {
src: [
// Ensure editor source files are concatenated in
// the right order
"packages/node_modules/@node-red/editor-client/src/js/polyfills.js",
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
"packages/node_modules/@node-red/editor-client/src/js/red.js",
"packages/node_modules/@node-red/editor-client/src/js/events.js",
"packages/node_modules/@node-red/editor-client/src/js/hooks.js",
"packages/node_modules/@node-red/editor-client/src/js/i18n.js",
"packages/node_modules/@node-red/editor-client/src/js/settings.js",
"packages/node_modules/@node-red/editor-client/src/js/user.js",
"packages/node_modules/@node-red/editor-client/src/js/comms.js",
"packages/node_modules/@node-red/editor-client/src/js/runtime.js",
"packages/node_modules/@node-red/editor-client/src/js/text/bidi.js",
"packages/node_modules/@node-red/editor-client/src/js/text/format.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/state.js",
"packages/node_modules/@node-red/editor-client/src/js/plugins.js",
"packages/node_modules/@node-red/editor-client/src/js/nodes.js",
"packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
"packages/node_modules/@node-red/editor-client/src/js/history.js",
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editor.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tray.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/group.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tour/*.js"
"editor/js/red.js",
"editor/js/events.js",
"editor/js/i18n.js",
"editor/js/settings.js",
"editor/js/user.js",
"editor/js/comms.js",
"editor/js/text/bidi.js",
"editor/js/text/format.js",
"editor/js/ui/state.js",
"editor/js/nodes.js",
"editor/js/history.js",
"editor/js/validators.js",
"editor/js/debugger.js",
"editor/js/ui/common/editableList.js",
"editor/js/ui/common/menu.js",
"editor/js/ui/common/popover.js",
"editor/js/ui/common/searchBox.js",
"editor/js/ui/common/tabs.js",
"editor/js/ui/common/typedInput.js",
"editor/js/ui/utils.js",
"editor/js/ui/deploy.js",
"editor/js/ui/keyboard.js",
"editor/js/ui/workspaces.js",
"editor/js/ui/view.js",
"editor/js/ui/sidebar.js",
"editor/js/ui/palette.js",
"editor/js/ui/tab-info.js",
"editor/js/ui/tab-config.js",
"editor/js/ui/palette-editor.js",
"editor/js/ui/editor.js",
"editor/js/ui/tray.js",
"editor/js/ui/clipboard.js",
"editor/js/ui/library.js",
"editor/js/ui/notifications.js",
"editor/js/ui/search.js",
"editor/js/ui/typeSearch.js",
"editor/js/ui/subflow.js",
"editor/js/ui/touch/radialMenu.js"
],
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
dest: "public/red/red.js"
},
vendor: {
files: {
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"node_modules/marked/marked.min.js",
"node_modules/dompurify/dist/purify.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
"node_modules/i18next/i18next.min.js",
"node_modules/i18next-http-backend/i18nextHttpBackend.min.js",
"node_modules/jquery-i18next/jquery-i18next.min.js",
"node_modules/jsonata/jsonata-es5.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js"
"public/vendor/vendor.js": [
"editor/vendor/jquery/js/jquery-1.11.3.min.js",
"editor/vendor/bootstrap/js/bootstrap.min.js",
"editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
"editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"editor/vendor/marked/marked.min.js",
"editor/vendor/d3/d3.v3.min.js",
"editor/vendor/i18next/i18next.min.js"
],
// "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
// // TODO: resolve relative resource paths in
// // bootstrap/FA/jquery
// ],
"packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
"node_modules/jsonata/jsonata-es5.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
],
"packages/node_modules/@node-red/editor-client/public/vendor/mermaid/mermaid.min.js": [
"node_modules/mermaid/dist/mermaid.min.js"
"public/vendor/vendor.css": [
// TODO: resolve relative resource paths in
// bootstrap/FA/jquery
]
}
}
@@ -244,62 +160,56 @@ module.exports = function(grunt) {
uglify: {
build: {
files: {
'packages/node_modules/@node-red/editor-client/public/red/red.min.js': 'packages/node_modules/@node-red/editor-client/public/red/red.js',
'packages/node_modules/@node-red/editor-client/public/red/main.min.js': 'packages/node_modules/@node-red/editor-client/public/red/main.js',
'packages/node_modules/@node-red/editor-client/public/vendor/ace/mode-jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/mode-jsonata.js',
'packages/node_modules/@node-red/editor-client/public/vendor/ace/snippets/jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/snippets-jsonata.js'
'public/red/red.min.js': 'public/red/red.js',
'public/red/main.min.js': 'public/red/main.js'
}
}
},
sass: {
build: {
options: {
implementation: sass,
outputStyle: 'compressed'
},
files: [{
dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css',
src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss'
dest: 'public/red/style.min.css',
src: 'editor/sass/style.scss'
},
{
dest: 'public/vendor/bootstrap/css/bootstrap.min.css',
src: 'editor/vendor/bootstrap/css/bootstrap.css'
}]
}
},
jsonlint: {
messages: {
src: [
'packages/node_modules/@node-red/nodes/locales/**/*.json',
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
'packages/node_modules/@node-red/runtime/locales/**/*.json'
]
},
keymaps: {
src: [
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
'nodes/core/locales/en-US/messages.json',
'red/api/locales/en-US/editor.json',
'red/runtime/locales/en-US/runtime.json'
]
}
},
attachCopyright: {
js: {
src: [
'packages/node_modules/@node-red/editor-client/public/red/red.min.js',
'packages/node_modules/@node-red/editor-client/public/red/main.min.js'
'public/red/red.min.js',
'public/red/main.min.js'
]
},
css: {
src: [
'packages/node_modules/@node-red/editor-client/public/red/style.min.css'
'public/red/style.min.css'
]
}
},
clean: {
build: {
src: [
"packages/node_modules/@node-red/editor-client/public/red",
"packages/node_modules/@node-red/editor-client/public/index.html",
"packages/node_modules/@node-red/editor-client/public/favicon.ico",
"packages/node_modules/@node-red/editor-client/public/icons",
"packages/node_modules/@node-red/editor-client/public/vendor",
"packages/node_modules/@node-red/editor-client/public/types/node",
"packages/node_modules/@node-red/editor-client/public/types/node-red",
"public/red",
"public/index.html",
"public/favicon.ico",
"public/icons",
"public/vendor"
]
},
release: {
@@ -311,36 +221,24 @@ module.exports = function(grunt) {
watch: {
js: {
files: [
'packages/node_modules/@node-red/editor-client/src/js/**/*.js'
'editor/js/**/*.js'
],
tasks: ['copy:build','concat',/*'uglify',*/ 'attachCopyright:js']
tasks: ['concat','uglify','attachCopyright:js']
},
sass: {
files: [
'packages/node_modules/@node-red/editor-client/src/sass/**/*.scss'
'editor/sass/**/*.scss'
],
tasks: ['sass','attachCopyright:css']
},
json: {
files: [
'packages/node_modules/@node-red/nodes/locales/**/*.json',
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
'packages/node_modules/@node-red/runtime/locales/**/*.json'
'nodes/core/locales/en-US/messages.json',
'red/api/locales/en-US/editor.json',
'red/runtime/locales/en-US/runtime.json'
],
tasks: ['jsonlint:messages']
},
keymaps: {
files: [
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
],
tasks: ['jsonlint:keymaps','copy:build']
},
tours: {
files: [
'packages/node_modules/@node-red/editor-client/src/tours/**/*.js'
],
tasks: ['copy:build']
},
misc: {
files: [
'CHANGELOG.md'
@@ -352,13 +250,12 @@ module.exports = function(grunt) {
nodemon: {
/* uses .nodemonignore */
dev: {
script: 'packages/node_modules/node-red/red.js',
script: 'red.js',
options: {
args: nodemonArgs,
ext: 'js,html,json',
watch: [
'packages/node_modules',
'!packages/node_modules/@node-red/editor-client'
'red','nodes'
]
}
}
@@ -377,75 +274,65 @@ module.exports = function(grunt) {
build: {
files:[
{
src: 'packages/node_modules/@node-red/editor-client/src/js/main.js',
dest: 'packages/node_modules/@node-red/editor-client/public/red/main.js'
src: 'editor/js/main.js',
dest: 'public/red/main.js'
},
{
src: 'packages/node_modules/@node-red/editor-client/src/js/keymap.json',
dest: 'packages/node_modules/@node-red/editor-client/public/red/keymap.json'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/images',
cwd: 'editor/images',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/red/images/'
dest: 'public/red/images/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/vendor',
cwd: 'editor/vendor',
src: [
'ace/**',
'jquery/css/base/**',
'font-awesome/**',
'monaco/dist/**',
'monaco/types/extraLibs.js',
'monaco/style.css',
'monaco/monaco-bootstrap.js'
//'bootstrap/css/**',
'bootstrap/img/**',
'jquery/css/**',
'font-awesome/**'
],
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/'
dest: 'public/vendor/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src',
src: [
'types/node/**/*.ts',
'types/node-red/*.ts',
],
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/icons',
cwd: 'editor/icons',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/icons/'
dest: 'public/icons/'
},
{
expand: true,
src: ['packages/node_modules/@node-red/editor-client/src/index.html','packages/node_modules/@node-red/editor-client/src/favicon.ico'],
dest: 'packages/node_modules/@node-red/editor-client/public/',
src: ['editor/index.html','editor/favicon.ico'],
dest: 'public/',
flatten: true
},
{
src: 'CHANGELOG.md',
dest: 'packages/node_modules/@node-red/editor-client/public/red/about'
},
{
src: 'CHANGELOG.md',
dest: 'packages/node_modules/node-red/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/ace/bin/',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/tours',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/red/tours/'
dest: 'public/red/about'
}
]
},
release: {
files: [{
mode: true,
expand: true,
src: [
'*.md',
'LICENSE',
'package.json',
'settings.js',
'red.js',
'lib/.gitignore',
'nodes/*.demo',
'nodes/core/**',
'red/**',
'public/**',
'editor/templates/**',
'bin/**'
],
dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>')
}]
}
},
chmod: {
@@ -453,96 +340,20 @@ module.exports = function(grunt) {
mode: '755'
},
release: {
// Target-specific file/dir lists and/or options go here.
src: [
"packages/node_modules/@node-red/nodes/core/hardware/nrgpio",
"packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/node-red-*sh"
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*')
]
}
},
'npm-command': {
options: {
cmd: "pack",
cwd: "<%= paths.dist %>/modules"
},
'node-red': { options: { args: [__dirname+'/packages/node_modules/node-red'] } },
'@node-red/editor-api': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-api'] } },
'@node-red/editor-client': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-client'] } },
'@node-red/nodes': { options: { args: [__dirname+'/packages/node_modules/@node-red/nodes'] } },
'@node-red/registry': { options: { args: [__dirname+'/packages/node_modules/@node-red/registry'] } },
'@node-red/runtime': { options: { args: [__dirname+'/packages/node_modules/@node-red/runtime'] } },
'@node-red/util': { options: { args: [__dirname+'/packages/node_modules/@node-red/util'] } }
},
mkdir: {
release: {
options: {
create: ['<%= paths.dist %>/modules']
},
},
},
compress: {
release: {
options: {
archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip'
},
expand: true,
cwd: 'packages/node_modules/',
src: [
'**',
'!@node-red/editor-client/src/**'
]
}
},
jsdoc : {
modules: {
src: [
'API.md',
'packages/node_modules/node-red/lib/red.js',
'packages/node_modules/@node-red/runtime/lib/index.js',
'packages/node_modules/@node-red/runtime/lib/api/*.js',
'packages/node_modules/@node-red/runtime/lib/events.js',
'packages/node_modules/@node-red/runtime/lib/hooks.js',
'packages/node_modules/@node-red/util/**/*.js',
'packages/node_modules/@node-red/editor-api/lib/index.js',
'packages/node_modules/@node-red/editor-api/lib/auth/index.js',
'packages/node_modules/@node-red/registry/lib/index.js'
],
options: {
destination: 'docs',
configure: './jsdoc.json',
fred: "hi there"
}
},
_editor: {
src: [
'packages/node_modules/@node-red/editor-client/src/js'
],
options: {
destination: 'packages/node_modules/@node-red/editor-client/docs',
configure: './jsdoc.json'
}
}
},
jsdoc2md: {
runtimeAPI: {
options: {
separators: true
},
src: [
'packages/node_modules/@node-red/runtime/lib/index.js',
'packages/node_modules/@node-red/runtime/lib/api/*.js',
'packages/node_modules/@node-red/runtime/lib/events.js'
],
dest: 'packages/node_modules/@node-red/runtime/docs/api.md'
},
nodeREDUtil: {
options: {
separators: true
},
src: 'packages/node_modules/@node-red/util/**/*.js',
dest: 'packages/node_modules/@node-red/util/docs/api.md'
cwd: '<%= paths.dist %>/',
src: ['node-red-<%= pkg.version %>/**']
}
}
});
@@ -555,42 +366,16 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-nodemon');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-chmod');
grunt.loadNpmTasks('grunt-jsonlint');
if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.loadNpmTasks('grunt-webdriver');
}
grunt.loadNpmTasks('grunt-jsdoc');
grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
grunt.loadNpmTasks('grunt-npm-command');
grunt.loadNpmTasks('grunt-mkdir');
grunt.loadNpmTasks('grunt-simple-nyc');
grunt.registerMultiTask('nodemon', 'Runs a nodemon monitor of your node.js server.', function () {
const nodemon = require('nodemon');
this.async();
const options = this.options();
options.script = this.data.script;
let callback;
if (options.callback) {
callback = options.callback;
delete options.callback;
} else {
callback = function(nodemonApp) {
nodemonApp.on('log', function (event) {
console.log(event.colour);
});
};
}
callback(nodemon(options));
});
grunt.registerMultiTask('attachCopyright', function() {
var files = this.data.src;
var copyright = "/**\n"+
" * Copyright OpenJS Foundation and other contributors, https://openjsf.org/\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"+
@@ -606,7 +391,7 @@ module.exports = function(grunt) {
" **/\n";
if (files) {
for (var i=0; i<files.length; i++) {
for (var i=0;i<files.length;i++) {
var file = files[i];
if (!grunt.file.exists(file)) {
grunt.log.warn('File '+ file + ' not found');
@@ -627,38 +412,6 @@ module.exports = function(grunt) {
}
});
grunt.registerTask('verifyPackageDependencies', function() {
var done = this.async();
var verifyDependencies = require("./scripts/verify-package-dependencies.js");
verifyDependencies().then(function(failures) {
if (failures.length > 0) {
failures.forEach(f => grunt.log.error(f));
grunt.fail.fatal("Failed to verify package dependencies");
}
done();
});
});
grunt.registerTask('verifyUiTestDependencies', function() {
if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.fail.fatal('You need to install the UI test dependencies first.\nUse the script in "scripts/install-ui-test-dependencies.sh"');
return false;
}
});
grunt.registerTask('generatePublishScript',
'Generates a script to publish build output to npm',
function () {
const done = this.async();
const generatePublishScript = require("./scripts/generate-publish-script.js");
generatePublishScript().then(function(output) {
grunt.log.writeln(output);
const filePath = path.join(grunt.config.get('paths.dist'),"modules","publish.sh");
grunt.file.write(filePath,output);
done();
});
});
grunt.registerTask('setDevEnv',
'Sets NODE_ENV=development so non-minified assets are used',
function () {
@@ -667,42 +420,23 @@ module.exports = function(grunt) {
grunt.registerTask('default',
'Builds editor content then runs code style checks and unit tests on all components',
['build','verifyPackageDependencies','jshint:editor','nyc:all']);
grunt.registerTask('no-coverage',
'Builds editor content then runs code style checks and unit tests on all components without code coverage',
['build','verifyPackageDependencies','jshint:editor','simplemocha:all']);
['build','test-core','test-editor','test-nodes']);
grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code',
['build','nyc:core']);
['jshint:core','simplemocha:core']);
grunt.registerTask('test-editor',
'Runs code style check on editor code',
['jshint:editor']);
if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.registerTask('test-ui',
'Builds editor content then runs unit tests on editor ui',
['verifyUiTestDependencies']);
} else {
grunt.registerTask('test-ui',
'Builds editor content then runs unit tests on editor ui',
['verifyUiTestDependencies','build','jshint:editor','webdriver:all']);
}
grunt.registerTask('test-nodes',
'Runs unit tests on core nodes',
['build','nyc:nodes']);
['simplemocha:nodes']);
grunt.registerTask('build',
'Builds editor content',
['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']);
grunt.registerTask('build-dev',
'Developer mode: build dev version',
['clean:build','concat:build','concat:vendor','copy:build','sass:build','setDevEnv']);
['clean:build','concat:build','concat:vendor','copy:build','uglify:build','sass:build','jsonlint:messages','attachCopyright']);
grunt.registerTask('dev',
'Developer mode: run node-red, watch for source changes and build/restart',
@@ -710,18 +444,6 @@ module.exports = function(grunt) {
grunt.registerTask('release',
'Create distribution zip file',
['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules','generatePublishScript']);
['build','clean:release','copy:release','chmod:release','compress:release']);
grunt.registerTask('pack-modules',
'Create module pack files for release',
['mkdir:release','npm-command']);
grunt.registerTask('coverage',
'Run Istanbul code test coverage task',
['build','nyc:all']);
grunt.registerTask('docs',
'Generates API documentation',
['jsdoc']);
};

View File

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

View File

@@ -1,27 +1,29 @@
# Node-RED
https://nodered.org
http://nodered.org
[![Build Status](https://github.com/node-red/node-red/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/node-red/node-red/actions?query=branch%3Amaster)
[![Build Status](https://travis-ci.org/node-red/node-red.svg)](https://travis-ci.org/node-red/node-red)
[![Coverage Status](https://coveralls.io/repos/node-red/node-red/badge.svg?branch=master)](https://coveralls.io/r/node-red/node-red?branch=master)
Low-code programming for event-driven applications.
A visual tool for wiring the Internet of Things.
![Node-RED: Low-code programming for event-driven applications](https://nodered.org/images/node-red-screenshot.png)
![Node-RED: A visual tool for wiring the Internet of Things](http://nodered.org/images/node-red-screenshot.png)
## Quick Start
Check out https://nodered.org/docs/getting-started/ for full instructions on getting
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
started.
1. `sudo npm install -g --unsafe-perm node-red`
1. `sudo npm install -g node-red`
2. `node-red`
3. Open <http://localhost:1880>
## Getting Help
More documentation can be found [here](https://nodered.org/docs).
More documentation can be found [here](http://nodered.org/docs).
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
For further help, or general discussion, please use the
[mailing list](https://groups.google.com/forum/#!forum/node-red).
## Developers
@@ -43,6 +45,9 @@ If you want to run the latest code from git, here's how to get started:
4. Run
npm start
or
node red.js
## Contributing
@@ -51,19 +56,17 @@ Before raising a pull-request, please read our
This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/).
By participating, you are expected to uphold this code. Please report unacceptable
behavior to any of the project's core team at team@nodered.org.
behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core).
## Authors
Node-RED is a project of the [OpenJS Foundation](http://openjsf.org).
Node-RED is a creation of [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
It is maintained by:
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
* And many others...
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
For more open-source projects from IBM, head over [here](http://ibm.github.io).
## Copyright and license
Copyright OpenJS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE).
Copyright 2013, 2016 IBM Corp. under [the Apache 2.0 license](LICENSE).

View File

@@ -1,5 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Please report any potential security issues to `team@nodered.org`. This will notify the core project team who will respond accordingly.

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#!/bin/bash
#
# Copyright JS Foundation and other contributors, http://js.foundation
# 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.
@@ -29,16 +29,15 @@ do
done
# Find the real location of this script
CURRENT_PATH=$(pwd)
SCRIPT_PATH=$(readlink -f "$0")
while [ -h "${SCRIPT_PATH}" ]; do
cd "$(dirname "${SCRIPT_PATH}")" || exit 1
P=$(basename "${SCRIPT_PATH}")
SCRIPT_PATH=$(readlink "${P}")
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 || exit 1
SCRIPT_PATH=$(pwd)
cd "$CURRENT_PATH" || exit 1
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
SCRIPT_PATH="`pwd`";
cd $CURRENT_PATH
# Run Node-RED
exec /usr/bin/env node ${OPTIONS} ${SCRIPT_PATH}/../red.js ${ARGS}
exec /usr/bin/env node $OPTIONS $SCRIPT_PATH/../red.js $ARGS

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

BIN
editor/icons/alert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

BIN
editor/icons/arduino.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

View File

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 393 B

BIN
editor/icons/bluetooth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

BIN
editor/icons/bridge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

BIN
editor/icons/cog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

BIN
editor/icons/comment.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
editor/icons/db.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

BIN
editor/icons/debug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

BIN
editor/icons/envelope.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

BIN
editor/icons/feed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

BIN
editor/icons/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

BIN
editor/icons/function.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

BIN
editor/icons/hash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

BIN
editor/icons/inject.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

BIN
editor/icons/join.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

BIN
editor/icons/leveldb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
editor/icons/light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

BIN
editor/icons/mongodb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

BIN
editor/icons/mouse.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

BIN
editor/icons/range.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

BIN
editor/icons/redis.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

BIN
editor/icons/rpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

BIN
editor/icons/serial.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

BIN
editor/icons/split.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

BIN
editor/icons/subflow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

BIN
editor/icons/swap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

BIN
editor/icons/switch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

BIN
editor/icons/template.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

BIN
editor/icons/timer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

BIN
editor/icons/trigger.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

BIN
editor/icons/twitter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

BIN
editor/icons/watch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

BIN
editor/images/grip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

View File

@@ -1,5 +1,5 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
* Copyright 2014, 2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,24 +28,14 @@ RED.comms = (function() {
function connectWS() {
active = true;
var wspath;
if (RED.settings.apiRootUrl) {
var m = /^(https?):\/\/(.*)$/.exec(RED.settings.apiRootUrl);
if (m) {
console.log(m);
wspath = "ws"+(m[1]==="https"?"s":"")+"://"+m[2]+"comms";
}
} else {
var path = location.hostname;
var port = location.port;
if (port.length !== 0) {
path = path+":"+port;
}
path = path+document.location.pathname;
path = path+(path.slice(-1) == "/"?"":"/")+"comms";
wspath = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
var path = location.hostname;
var port = location.port;
if (port.length !== 0) {
path = path+":"+port;
}
path = path+document.location.pathname;
path = path+(path.slice(-1) == "/"?"":"/")+"comms";
path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
var auth_tokens = RED.settings.get("auth-tokens");
pendingAuth = (auth_tokens!=null);
@@ -58,7 +48,7 @@ RED.comms = (function() {
}
}
ws = new WebSocket(wspath);
ws = new WebSocket(path);
ws.onopen = function() {
reconnectAttempts = 0;
if (errornotification) {
@@ -74,41 +64,27 @@ RED.comms = (function() {
}
}
ws.onmessage = function(event) {
var message = JSON.parse(event.data);
if (message.auth) {
if (pendingAuth) {
if (message.auth === "ok") {
pendingAuth = false;
completeConnection();
} else if (message.auth === "fail") {
// anything else is an error...
active = false;
RED.user.login({updateMenu:true},function() {
connectWS();
})
}
} else if (message.auth === "fail") {
// Our current session has expired
var msg = JSON.parse(event.data);
if (pendingAuth && msg.auth) {
if (msg.auth === "ok") {
pendingAuth = false;
completeConnection();
} else if (msg.auth === "fail") {
// anything else is an error...
active = false;
RED.user.login({updateMenu:true},function() {
connectWS();
})
}
} else {
// Otherwise, 'message' is an array of actual comms messages
for (var m = 0; m < message.length; m++) {
var msg = message[m];
if (msg.topic) {
for (var t in subscriptions) {
if (subscriptions.hasOwnProperty(t)) {
var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
if (re.test(msg.topic)) {
var subscribers = subscriptions[t];
if (subscribers) {
for (var i=0;i<subscribers.length;i++) {
subscribers[i](msg.topic,msg.data);
}
}
} else if (msg.topic) {
for (var t in subscriptions) {
if (subscriptions.hasOwnProperty(t)) {
var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
if (re.test(msg.topic)) {
var subscribers = subscriptions[t];
if (subscribers) {
for (var i=0;i<subscribers.length;i++) {
subscribers[i](msg.topic,msg.data);
}
}
}
@@ -142,10 +118,10 @@ RED.comms = (function() {
connectWS();
} else {
var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>';
errornotification.update(msg,{silent:true});
$(errornotification).find("a").on("click", function(e) {
errornotification.update(msg);
$(errornotification).find("a").click(function(e) {
e.preventDefault();
errornotification.update(RED._("notification.errors.lostConnection"),{silent:true});
errornotification.update(RED._("notification.errors.lostConnection"));
clearInterval(connectCountdownTimer);
connectWS();
})

4
editor/js/debugger.js Normal file
View File

@@ -0,0 +1,4 @@
RED.debugger = (function() {
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
* Copyright 2015, 2016 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,19 +32,14 @@
}
}
}
function emit() {
var evt = arguments[0]
var args = Array.prototype.slice.call(arguments,1);
if (RED.events.DEBUG) {
console.warn(evt,args);
}
function emit(evt,arg) {
if (handlers[evt]) {
for (var i=0;i<handlers[evt].length;i++) {
try {
handlers[evt][i].apply(null, args);
handlers[evt][i](arg);
} catch(err) {
console.warn("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.warn(err);
console.log("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.log(err);
}
}

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

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

43
editor/js/i18n.js Normal file
View File

@@ -0,0 +1,43 @@
/**
* 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.i18n = (function() {
return {
init: function(done) {
i18n.init({
resGetPath: 'locales/__ns__',
dynamicLoad: false,
load:'current',
ns: {
namespaces: ["editor","node-red"],
defaultNs: "editor"
},
fallbackLng: ['en-US'],
useCookie: false
},function() {
done();
});
RED["_"] = function() {
return i18n.t.apply(null,arguments);
}
},
loadCatalog: function(namespace,done) {
i18n.loadNamespace(namespace,done);
}
}
})();

264
editor/js/main.js Normal file
View File

@@ -0,0 +1,264 @@
/**
* Copyright 2013, 2016 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.
**/
(function() {
function loadNodeList() {
$.ajax({
headers: {
"Accept":"application/json"
},
cache: false,
url: 'nodes',
success: function(data) {
RED.nodes.setNodeList(data);
var nsCount = 0;
for (var i=0;i<data.length;i++) {
var ns = data[i];
if (ns.module != "node-red") {
nsCount++;
RED.i18n.loadCatalog(ns.id, function() {
nsCount--;
if (nsCount === 0) {
loadNodes();
}
});
}
}
if (nsCount === 0) {
loadNodes();
}
}
});
}
function loadNodes() {
$.ajax({
headers: {
"Accept":"text/html"
},
cache: false,
url: 'nodes',
success: function(data) {
$("body").append(data);
$("body").i18n();
$("#palette > .palette-spinner").hide();
$(".palette-scroll").removeClass("hide");
$("#palette-search").removeClass("hide");
loadFlows();
}
});
}
function loadFlows() {
$.ajax({
headers: {
"Accept":"application/json",
},
cache: false,
url: 'flows',
success: function(nodes) {
var currentHash = window.location.hash;
RED.nodes.version(nodes.rev);
RED.nodes.import(nodes.flows);
RED.nodes.dirty(false);
RED.view.redraw(true);
if (/^#flow\/.+$/.test(currentHash)) {
RED.workspaces.show(currentHash.substring(6));
}
RED.comms.subscribe("status/#",function(topic,msg) {
var parts = topic.split("/");
var node = RED.nodes.node(parts[1]);
if (node) {
if (msg.hasOwnProperty("text")) {
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
}
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);
RED.i18n.loadCatalog(id, function() {
$.get('nodes/'+id, function(data) {
$("body").append(data);
});
});
}
if (addedTypes.length) {
typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+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(RED._("palette.event.nodeRemoved", {count:m.types.length})+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(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
$.get('nodes/'+msg.id, function(data) {
$("body").append(data);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
});
}
}
} 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(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success");
}
}
// Refresh flow library to ensure any examples are updated
RED.library.loadFlowLibrary();
});
}
});
}
function showAbout() {
$.get('red/about', function(data) {
var aboutHeader = '<div style="text-align:center;">'+
'<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>';
RED.sidebar.info.set(aboutHeader+marked(data));
RED.sidebar.info.show();
});
}
var statusEnabled = false;
function toggleStatus(state) {
statusEnabled = state;
RED.view.status(statusEnabled);
}
function loadEditor() {
var menuOptions = [];
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
{id:"menu-item-view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:RED.view.toggleShowGrid},
{id:"menu-item-view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:RED.view.toggleSnapGrid},
{id:"menu-item-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:toggleStatus, selected: true},
null,
// {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[
// {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}},
// {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}},
// {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}},
// {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}}
// ]},
// null,
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true}
]});
menuOptions.push(null);
menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:RED.clipboard.import},
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
]});
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:RED.clipboard.export},
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:RED.library.export}
]});
menuOptions.push(null);
menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:RED.search.show});
menuOptions.push(null);
menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:function() {}});
menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:RED.workspaces.add},
{id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:RED.workspaces.edit},
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:RED.workspaces.remove}
]});
menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:RED.subflow.createSubflow},
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:RED.subflow.convertToSubflow},
]});
menuOptions.push(null);
if (RED.settings.theme('palette.editable') !== false) {
RED.palette.editor.init();
menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:RED.palette.editor.show});
menuOptions.push(null);
}
menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:RED.keyboard.showHelp});
menuOptions.push({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")
});
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: showAbout });
RED.menu.init({id:"btn-sidemenu",options: menuOptions});
RED.user.init();
RED.library.init();
RED.palette.init();
RED.sidebar.init();
RED.subflow.init();
RED.workspaces.init();
RED.clipboard.init();
RED.search.init();
RED.view.init();
RED.editor.init();
RED.deploy.init(RED.settings.theme("deployButton",null));
RED.keyboard.add("workspace", /* ? */ 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.i18n.init(function() {
RED.settings.init(loadEditor);
})
});
})();

1252
editor/js/nodes.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
* Copyright 2013, 2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,5 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
module.exports = false
var RED = {};

152
editor/js/settings.js Normal file
View File

@@ -0,0 +1,152 @@
/**
* Copyright 2014 IBM, Antoine Aflalo
*
* 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.settings = (function () {
var loadedSettings = {};
var hasLocalStorage = function () {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
};
var set = function (key, value) {
if (!hasLocalStorage()) {
return;
}
localStorage.setItem(key, JSON.stringify(value));
};
/**
* If the key is not set in the localStorage it returns <i>undefined</i>
* Else return the JSON parsed value
* @param key
* @returns {*}
*/
var get = function (key) {
if (!hasLocalStorage()) {
return undefined;
}
return JSON.parse(localStorage.getItem(key));
};
var remove = function (key) {
if (!hasLocalStorage()) {
return;
}
localStorage.removeItem(key);
};
var setProperties = function(data) {
for (var prop in loadedSettings) {
if (loadedSettings.hasOwnProperty(prop) && RED.settings.hasOwnProperty(prop)) {
delete RED.settings[prop];
}
}
for (prop in data) {
if (data.hasOwnProperty(prop)) {
RED.settings[prop] = data[prop];
}
}
loadedSettings = data;
};
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("Node-RED-API-Version","v2");
}
}
});
load(done);
}
var load = function(done) {
$.ajax({
headers: {
"Accept": "application/json"
},
dataType: "json",
cache: false,
url: 'settings',
success: function (data) {
setProperties(data);
if (RED.settings.user && RED.settings.user.anonymous) {
RED.settings.remove("auth-tokens");
}
console.log("Node-RED: " + data.version);
done();
},
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);
}
}
});
};
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]];
}
if (v === undefined) {
return defaultValue;
}
return v;
} catch(err) {
return defaultValue;
}
}
return {
init: init,
load: load,
set: set,
get: get,
remove: remove,
theme: theme
}
})
();

View File

@@ -1,5 +1,5 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
* Copyright 2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -97,14 +97,14 @@ RED.text.bidi = (function() {
}
/**
* Enforces the text direction for all the spans with style red-ui-text-bidi-aware under
* Enforces the text direction for all the spans with style bidiAware under
* workspace or sidebar div
*/
function enforceTextDirectionOnPage() {
$("#red-ui-workspace").find('span.red-ui-text-bidi-aware').each(function() {
$("#workspace").find('span.bidiAware').each(function() {
$(this).attr("dir", resolveBaseTextDir($(this).html()));
});
$("#red-ui-sidebar").find('span.red-ui-text-bidi-aware').each(function() {
$("#sidebar").find('span.bidiAware').each(function() {
$(this).attr("dir", resolveBaseTextDir($(this).text()));
});
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
* Copyright 2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1242,7 +1242,7 @@ RED.text.format = (function() {
element.dispatchEvent(event);
return;
}
var range = selection.getRangeAt(0);
var tempRange = range.cloneRange(), startNode, startOffset;
startNode = range.startContainer;
@@ -1304,7 +1304,7 @@ RED.text.format = (function() {
}
return {
/*!
/**
* Returns the HTML representation of a given structured text
* @param text - the structured text
* @param type - could be one of filepath, url, email
@@ -1315,7 +1315,7 @@ RED.text.format = (function() {
getHtml: function (text, type, args, isRtl, locale) {
return getHandler(type).format(text, args, isRtl, true, locale);
},
/*!
/**
* Handle Structured text correct display for a given HTML element.
* @param element - the element : should be of type div contenteditable=true
* @param type - could be one of filepath, url, email

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

@@ -0,0 +1,307 @@
/**
* 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;
var dialogContainer;
var exportNodesDialog;
var importNodesDialog;
function setupDialogs() {
dialog = $('<div id="clipboard-dialog" class="hide node-red-dialog"><form class="dialog-form form-horizontal"></form></div>')
.appendTo("body")
.dialog({
modal: true,
autoOpen: false,
width: 500,
resizable: false,
buttons: [
{
id: "clipboard-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-close",
class: "primary",
text: RED._("common.label.close"),
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-copy",
class: "primary",
text: RED._("clipboard.export.copy"),
click: function() {
$("#clipboard-export").select();
document.execCommand("copy");
document.getSelection().removeAllRanges();
RED.notify(RED._("clipboard.nodesExported"));
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-ok",
class: "primary",
text: RED._("common.label.import"),
click: function() {
RED.view.importNodes($("#clipboard-import").val(),$("#import-tab > a.selected").attr('id') === 'import-tab-new');
$( this ).dialog( "close" );
}
}
],
open: function(e) {
$(this).parent().find(".ui-dialog-titlebar-close").hide();
},
close: function(e) {
}
});
dialogContainer = dialog.children(".dialog-form");
exportNodesDialog =
'<div class="form-row">'+
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.export.copy"></label>'+
'<span id="export-range-group" class="button-group">'+
'<a id="export-range-selected" class="editor-button toggle" href="#" data-i18n="clipboard.export.selected"></a>'+
'<a id="export-range-flow" class="editor-button toggle" href="#" data-i18n="clipboard.export.current"></a>'+
'<a id="export-range-full" class="editor-button toggle" href="#" data-i18n="clipboard.export.all"></a>'+
'</span>'+
'</div>'+
'<div class="form-row">'+
'<textarea readonly style="resize: none; width: 100%; border-radius: 4px;font-family: monospace; font-size: 12px; background:#f3f3f3; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-export" rows="5"></textarea>'+
'</div>'+
'<div class="form-row" style="text-align: right;">'+
'<span id="export-format-group" class="button-group">'+
'<a id="export-format-mini" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+
'<a id="export-format-full" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+
'</span>'+
'</div>';
importNodesDialog = '<div class="form-row">'+
'<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5" placeholder="'+
RED._("clipboard.pasteNodes")+
'"></textarea>'+
'</div>'+
'<div class="form-row">'+
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+
'<span id="import-tab" class="button-group">'+
'<a id="import-tab-current" class="editor-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+
'<a id="import-tab-new" class="editor-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+
'</span>'+
'</div>';
}
function validateImport() {
var importInput = $("#clipboard-import");
var v = importInput.val();
v = v.substring(v.indexOf('['),v.lastIndexOf(']')+1);
try {
JSON.parse(v);
importInput.removeClass("input-error");
importInput.val(v);
$("#clipboard-dialog-ok").button("enable");
} catch(err) {
if (v !== "") {
importInput.addClass("input-error");
}
$("#clipboard-dialog-ok").button("disable");
}
}
function importNodes() {
dialogContainer.empty();
dialogContainer.append($(importNodesDialog));
dialogContainer.i18n();
$("#clipboard-dialog-ok").show();
$("#clipboard-dialog-cancel").show();
$("#clipboard-dialog-close").hide();
$("#clipboard-dialog-copy").hide();
$("#clipboard-dialog-ok").button("disable");
$("#clipboard-import").keyup(validateImport);
$("#clipboard-import").on('paste',function() { setTimeout(validateImport,10)});
$("#import-tab > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
});
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
}
function exportNodes() {
dialogContainer.empty();
dialogContainer.append($(exportNodesDialog));
dialogContainer.i18n();
$("#export-format-group > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
var flow = $("#clipboard-export").val();
if (flow.length > 0) {
var nodes = JSON.parse(flow);
var format = $(this).attr('id');
if (format === 'export-format-full') {
flow = JSON.stringify(nodes,null,4);
} else {
flow = JSON.stringify(nodes);
}
$("#clipboard-export").val(flow);
}
});
$("#export-range-group > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
var type = $(this).attr('id');
var flow = "";
var nodes = null;
if (type === 'export-range-selected') {
var selection = RED.view.selection();
nodes = RED.nodes.createExportableNodeSet(selection.nodes);
} else if (type === 'export-range-flow') {
var activeWorkspace = RED.workspaces.active();
nodes = RED.nodes.filterNodes({z:activeWorkspace});
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
nodes.unshift(parentNode);
nodes = RED.nodes.createExportableNodeSet(nodes);
} else if (type === 'export-range-full') {
nodes = RED.nodes.createCompleteNodeSet(false);
}
if (nodes !== null) {
if (RED.settings.flowFilePretty) {
flow = JSON.stringify(nodes,null,4);
} else {
flow = JSON.stringify(nodes);
}
}
if (flow.length > 0) {
$("#export-copy").removeClass('disabled');
} else {
$("#export-copy").addClass('disabled');
}
$("#clipboard-export").val(flow);
})
$("#clipboard-dialog-ok").hide();
$("#clipboard-dialog-cancel").hide();
$("#clipboard-dialog-copy").hide();
$("#clipboard-dialog-close").hide();
var selection = RED.view.selection();
if (selection.nodes) {
$("#export-range-selected").click();
} else {
$("#export-range-selected").addClass('disabled').removeClass('selected');
$("#export-range-flow").click();
}
if (RED.settings.flowFilePretty) {
$("#export-format-full").click();
} else {
$("#export-format-mini").click();
}
$("#clipboard-export")
.focus(function() {
var textarea = $(this);
textarea.select();
textarea.mouseup(function() {
textarea.unbind("mouseup");
return false;
})
});
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
setTimeout(function() {
$("#clipboard-export").focus();
if (!document.queryCommandEnabled("copy")) {
$("#clipboard-dialog-cancel").hide();
$("#clipboard-dialog-close").show();
} else {
$("#clipboard-dialog-cancel").show();
$("#clipboard-dialog-copy").show();
}
},0);
}
function hideDropTarget() {
$("#dropTarget").hide();
RED.keyboard.remove(/* ESCAPE */ 27);
}
return {
init: function() {
setupDialogs();
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true);
RED.menu.setDisabled("menu-item-export-clipboard",true);
RED.menu.setDisabled("menu-item-export-library",true);
} else {
RED.menu.setDisabled("menu-item-export",false);
RED.menu.setDisabled("menu-item-export-clipboard",false);
RED.menu.setDisabled("menu-item-export-library",false);
}
});
RED.keyboard.add("workspace", /* e */ 69,{ctrl:true},function(){exportNodes();d3.event.preventDefault();});
RED.keyboard.add("workspace", /* 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();
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
RED.view.importNodes(data);
event.preventDefault();
});
},
import: importNodes,
export: exportNodes
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
* Copyright 2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
/**
* options:
* - addButton : boolean|string - text for add label, default 'add'
* - buttons : array - list of custom buttons (objects with fields 'id', 'label', 'icon', 'title', 'click')
* - height : number|'auto'
* - resize : function - called when list as a whole is resized
* - resizeItem : function(item) - called to resize individual item
@@ -28,22 +27,13 @@
* - removable : boolean - whether to display delete button on items
* - addItem : function(row,index,itemData) - when an item is added
* - removeItem : function(itemData) - called when an item is removed
* - filter : function(itemData) - called for each item to determine if it should be shown
* - sort : function(itemDataA,itemDataB) - called to sort items
* - scrollOnAdd : boolean - whether to scroll to newly added items
* methods:
* - addItem(itemData)
* - insertItemAt : function(data,index) - add an item at the specified index
* - removeItem(itemData, detach) - remove the item. Optionally detach to preserve any event handlers on the item's label
* - getItemAt(index)
* - indexOf(itemData)
* - removeItem(itemData)
* - width(width)
* - height(height)
* - items()
* - empty()
* - filter(filter)
* - sort(sort)
* - length()
*/
$.widget( "nodered.editableList", {
_create: function() {
@@ -54,78 +44,34 @@
this.uiContainer = this.element
.wrap( "<div>" )
.parent();
this.topContainer = this.uiContainer.wrap("<div>").parent();
if (this.options.header) {
this.options.header.addClass("red-ui-editableList-header");
this.borderContainer = this.uiContainer.wrap("<div>").parent();
this.borderContainer.prepend(this.options.header);
this.topContainer = this.borderContainer.wrap("<div>").parent();
} else {
this.topContainer = this.uiContainer.wrap("<div>").parent();
}
this.topContainer.addClass('red-ui-editableList');
if (this.options.class) {
this.topContainer.addClass(this.options.class);
}
var buttons = this.options.buttons || [];
if (this.options.addButton !== false) {
var addLabel, addTitle;
var addLabel;
if (typeof this.options.addButton === 'string') {
addLabel = this.options.addButton
} else {
if (RED && RED._) {
addLabel = RED._("editableList.add");
addTitle = RED._("editableList.addTitle");
} else {
addLabel = 'add';
addTitle = 'add new item';
}
}
buttons.unshift({
label: addLabel,
icon: "fa fa-plus",
click: function(evt) {
that.addItem({});
},
title: addTitle
});
}
buttons.forEach(function(button) {
var element = $('<button type="button" class="red-ui-button red-ui-button-small red-ui-editableList-addButton" style="margin-top: 4px; margin-right: 5px;"></button>')
.appendTo(that.topContainer)
.on("click", function(evt) {
$('<a href="#" class="editor-button editor-button-small" style="margin-top: 4px;"><i class="fa fa-plus"></i> '+addLabel+'</a>')
.appendTo(this.topContainer)
.click(function(evt) {
evt.preventDefault();
if (button.click !== undefined) {
button.click(evt);
}
that.addItem({});
});
if (button.id) {
element.attr("id", button.id);
}
if (button.title) {
element.attr("title", button.title);
}
if (button.icon) {
element.append($("<i></i>").attr("class", button.icon));
}
if (button.label) {
element.append($("<span></span>").text(" " + button.label));
}
});
}
if (this.element.css("position") === "absolute") {
["top","left","bottom","right"].forEach(function(s) {
var v = that.element.css(s);
if (v!=="auto" && v!=="") {
if (s!=="auto" && s!=="") {
that.topContainer.css(s,v);
that.uiContainer.css(s,"0");
if (s === "top" && that.options.header) {
that.uiContainer.css(s,"20px")
}
that.element.css(s,'auto');
}
})
@@ -134,11 +80,6 @@
this.uiContainer.css("position","absolute");
}
if (this.options.header) {
this.borderContainer.addClass("red-ui-editableList-border");
} else {
this.uiContainer.addClass("red-ui-editableList-border");
}
this.uiContainer.addClass("red-ui-editableList-container");
this.uiHeight = this.element.height();
@@ -154,13 +95,8 @@
this.uiContainer.css("minHeight",minHeight);
this.element.css("minHeight",0);
}
var maxHeight = this.element.css("maxHeight");
if (maxHeight !== '0px') {
this.uiContainer.css("maxHeight",maxHeight);
this.element.css("maxHeight",null);
}
if (this.options.height !== 'auto') {
this.uiContainer.css("overflow-y","auto");
this.uiContainer.css("overflow-y","scroll");
if (!isNaN(this.options.height)) {
this.uiHeight = this.options.height;
}
@@ -218,22 +154,17 @@
if (this.options.resizeItem) {
var that = this;
this.element.children().each(function(i) {
that.options.resizeItem($(this).children(".red-ui-editableList-item-content"),i);
that.options.resizeItem($(this).find(".red-ui-editableList-item-content"),i);
});
}
},
_destroy: function() {
if (this.topContainer) {
var tc = this.topContainer;
delete this.topContainer;
tc.remove();
}
},
_refreshFilter: function() {
var that = this;
var count = 0;
if (!this.activeFilter) {
return this.element.children().show();
this.element.children().show();
}
var items = this.items();
items.each(function (i,el) {
@@ -258,7 +189,7 @@
var items = this.element.children();
var that = this;
items.sort(function(A,B) {
return that.activeSort($(A).children(".red-ui-editableList-item-content").data('data'),$(B).children(".red-ui-editableList-item-content").data('data'));
return that.activeSort($(A).find(".red-ui-editableList-item-content").data('data'),$(B).find(".red-ui-editableList-item-content").data('data'));
});
$.each(items,function(idx,li) {
that.element.append(li);
@@ -273,49 +204,10 @@
this.uiHeight = desiredHeight;
this._resize();
},
getItemAt: function(index) {
var items = this.items();
if (index >= 0 && index < items.length) {
return $(items[index]).data('data');
} else {
return;
}
},
indexOf: function(data) {
var items = this.items();
for (var i=0;i<items.length;i++) {
if ($(items[i]).data('data') === data) {
return i
}
}
return -1
},
insertItemAt: function(data,index) {
addItem: function(data) {
var that = this;
data = data || {};
var li = $('<li>');
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
row.data('data',data);
if (this.options.sortable === true) {
$('<i class="red-ui-editableList-item-handle fa fa-bars"></i>').appendTo(li);
li.addClass("red-ui-editableList-item-sortable");
}
if (this.options.removable) {
var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(li);
$('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
li.addClass("red-ui-editableList-item-removable");
deleteButton.on("click", function(evt) {
evt.preventDefault();
var data = row.data('data');
li.addClass("red-ui-editableList-item-deleting")
li.fadeOut(300, function() {
$(this).remove();
if (that.options.removeItem) {
that.options.removeItem(data);
}
});
});
}
var added = false;
if (this.activeSort) {
var items = this.items();
@@ -330,17 +222,33 @@
});
}
if (!added) {
if (index <= 0) {
li.prependTo(this.element);
} else if (index > that.element.children().length-1) {
li.appendTo(this.element);
} else {
li.insertBefore(this.element.children().eq(index));
}
li.appendTo(this.element);
}
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
row.data('data',data);
if (this.options.sortable === true) {
$('<i class="red-ui-editableList-item-handle fa fa-bars"></i>').appendTo(li);
li.addClass("red-ui-editableList-item-sortable");
}
if (this.options.removable) {
var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove editor-button editor-button-small"}).appendTo(li);
$('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
li.addClass("red-ui-editableList-item-removable");
deleteButton.click(function(evt) {
evt.preventDefault();
var data = row.data('data');
li.addClass("red-ui-editableList-item-deleting")
li.fadeOut(300, function() {
$(this).remove();
if (that.options.removeItem) {
that.options.removeItem(data);
}
});
});
}
if (this.options.addItem) {
var index = that.element.children().length-1;
// setTimeout(function() {
setTimeout(function() {
that.options.addItem(row,index,data);
if (that.activeFilter) {
try {
@@ -356,36 +264,23 @@
that.uiContainer.scrollTop(that.element.height());
},0);
}
// },0);
},0);
}
},
addItem: function(data) {
this.insertItemAt(data,this.element.children().length)
},
addItems: function(items) {
for (var i=0; i<items.length;i++) {
this.addItem(items[i]);
}
},
removeItem: function(data,detach) {
removeItem: function(data) {
var items = this.element.children().filter(function(f) {
return data === $(this).children(".red-ui-editableList-item-content").data('data');
return data === $(this).find(".red-ui-editableList-item-content").data('data');
});
if (detach) {
items.detach();
} else {
items.remove();
}
items.remove();
if (this.options.removeItem) {
this.options.removeItem(data);
}
},
items: function() {
return this.element.children().map(function(i) { return $(this).children(".red-ui-editableList-item-content"); });
return this.element.children().map(function(i) { return $(this).find(".red-ui-editableList-item-content"); });
},
empty: function() {
this.element.empty();
this.uiContainer.scrollTop(0);
},
filter: function(filter) {
if (filter !== undefined) {
@@ -401,25 +296,6 @@
},
length: function() {
return this.element.children().length;
},
show: function(item) {
var items = this.element.children().filter(function(f) {
return item === $(this).children(".red-ui-editableList-item-content").data('data');
});
if (items.length > 0) {
this.uiContainer.scrollTop(this.uiContainer.scrollTop()+items.position().top)
}
},
getItem: function(li) {
var el = li.children(".red-ui-editableList-item-content");
if (el.length) {
return el.data('data');
} else {
return null;
}
},
cancel: function() {
this.element.sortable("cancel");
}
});
})(jQuery);

257
editor/js/ui/common/menu.js Normal file
View File

@@ -0,0 +1,257 @@
/**
* Copyright 2014, 2016 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.menu = (function() {
var menuItems = {};
function createMenuItem(opt) {
var item;
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");
opt.onselect.call(opt, true);
} else if (savedStateActive === false) {
link.removeClass("active");
opt.onselect.call(opt, false);
} else if (opt.hasOwnProperty("selected")) {
if (opt.selected) {
link.addClass("active");
} else {
link.removeClass("active");
}
opt.onselect.call(opt, opt.selected);
}
}
if (opt === null) {
item = $('<li class="divider"></li>');
} else {
item = $('<li></li>');
if (opt.group) {
item.addClass("menu-group-"+opt.group);
}
var linkContent = '<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">';
if (opt.toggle) {
linkContent += '<i class="fa fa-square pull-left"></i>';
linkContent += '<i class="fa fa-check-square pull-left"></i>';
}
if (opt.icon !== undefined) {
if (/\.png/.test(opt.icon)) {
linkContent += '<img src="'+opt.icon+'"/> ';
} else {
linkContent += '<i class="'+(opt.icon?opt.icon:'" style="display: inline-block;"')+'"></i> ';
}
}
if (opt.sublabel) {
linkContent += '<span class="menu-label-container"><span class="menu-label">'+opt.label+'</span>'+
'<span class="menu-sublabel">'+opt.sublabel+'</span></span>'
} else {
linkContent += '<span class="menu-label">'+opt.label+'</span>'
}
linkContent += '</a>';
var link = $(linkContent).appendTo(item);
menuItems[opt.id] = opt;
if (opt.onselect) {
link.click(function() {
if ($(this).parent().hasClass("disabled")) {
return;
}
if (opt.toggle) {
var selected = isSelected(opt.id);
if (typeof opt.toggle === "string") {
if (!selected) {
for (var m in menuItems) {
if (menuItems.hasOwnProperty(m)) {
var mi = menuItems[m];
if (mi.id != opt.id && opt.toggle == mi.toggle) {
setSelected(mi.id,false);
}
}
}
setSelected(opt.id,true);
}
} else {
setSelected(opt.id, !selected);
}
} else {
opt.onselect.call(opt);
}
});
setInitialState();
} else if (opt.href) {
link.attr("target","_blank").attr("href",opt.href);
} else if (!opt.options) {
item.addClass("disabled");
link.click(function(event) {
event.preventDefault();
});
}
if (opt.options) {
item.addClass("dropdown-submenu pull-left");
var submenu = $('<ul id="'+opt.id+'-submenu" class="dropdown-menu"></ul>').appendTo(item);
for (var i=0;i<opt.options.length;i++) {
var li = createMenuItem(opt.options[i]);
if (li) {
li.appendTo(submenu);
}
}
}
if (opt.disabled) {
item.addClass("disabled");
}
}
return item;
}
function createMenu(options) {
var button = $("#"+options.id);
//button.click(function(event) {
// $("#"+options.id+"-submenu").show();
// event.preventDefault();
//});
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];
if (opt !== null || !lastAddedSeparator) {
var li = createMenuItem(opt);
if (li) {
li.appendTo(topMenu);
lastAddedSeparator = (opt === null);
}
}
}
}
function isSavedStateActive(id) {
return RED.settings.get("menu-" + id);
}
function isSelected(id) {
return $("#" + id).hasClass("active");
}
function setSavedState(id, state) {
RED.settings.set("menu-" + id, state);
}
function setSelected(id,state) {
if (isSelected(id) == state) {
return;
}
var opt = menuItems[id];
if (state) {
$("#"+id).addClass("active");
} else {
$("#"+id).removeClass("active");
}
if (opt && opt.onselect) {
opt.onselect.call(opt,state);
}
setSavedState(id, state);
}
function setDisabled(id,state) {
if (state) {
$("#"+id).parent().addClass("disabled");
} else {
$("#"+id).parent().removeClass("disabled");
}
}
function addItem(id,opt) {
var item = createMenuItem(opt);
if (opt.group) {
var groupItems = $("#"+id+"-submenu").children(".menu-group-"+opt.group);
if (groupItems.length === 0) {
item.appendTo("#"+id+"-submenu");
} else {
for (var i=0;i<groupItems.length;i++) {
var groupItem = groupItems[i];
var label = $(groupItem).find(".menu-label").html();
if (opt.label < label) {
$(groupItem).before(item);
break;
}
}
if (i === groupItems.length) {
item.appendTo("#"+id+"-submenu");
}
}
} else {
item.appendTo("#"+id+"-submenu");
}
}
function removeItem(id) {
$("#"+id).parent().remove();
}
function setAction(id,action) {
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 {
init: createMenu,
setSelected: setSelected,
isSelected: isSelected,
setDisabled: setDisabled,
addItem: addItem,
removeItem: removeItem,
setAction: setAction
//TODO: add an api for replacing a submenu - see library.js:loadFlowLibrary
}
})();

View File

@@ -0,0 +1,79 @@
/**
* 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.popover = (function() {
function createPopover(options) {
var target = options.target;
var content = options.content;
var delay = options.delay;
var timer = null;
var active;
var div;
var openPopup = function() {
if (active) {
div = $('<div class="red-ui-popover"></div>').html(content).appendTo("body");
var targetPos = target.offset();
var targetWidth = target.width();
var targetHeight = target.height();
var divHeight = div.height();
div.css({top: targetPos.top+targetHeight/2-divHeight/2-10,left:targetPos.left+targetWidth+17});
div.fadeIn("fast");
}
}
var closePopup = function() {
if (!active) {
if (div) {
div.fadeOut("fast",function() {
$(this).remove();
});
div = null;
}
}
}
target.on('mouseenter',function(e) {
clearTimeout(timer);
active = true;
timer = setTimeout(openPopup,delay.show);
});
target.on('mouseleave', function(e) {
if (timer) {
clearTimeout(timer);
}
active = false;
setTimeout(closePopup,delay.hide);
});
var res = {
setContent: function(_content) {
content = _content;
}
}
target.data('popover',res);
return res;
}
return {
create: createPopover
}
})();

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