Compare commits
	
		
			1 Commits
		
	
	
		
			5004-icon-
			...
			bidi-17
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 1532d9b6e2 | 
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1 +0,0 @@ | |||||||
| /packages/node_modules/** linguist-generated=false |  | ||||||
							
								
								
									
										61
									
								
								.github/ISSUE_TEMPLATE/bug_report.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -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 |  | ||||||
							
								
								
									
										14
									
								
								.github/ISSUE_TEMPLATE/config.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -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 |  | ||||||
							
								
								
									
										34
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -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 |  | ||||||
							
								
								
									
										15
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -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: |  | ||||||
|           - "*" |  | ||||||
							
								
								
									
										29
									
								
								.github/scripts/update-node-red-docker.js
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -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); |  | ||||||
| } |  | ||||||
							
								
								
									
										18
									
								
								.github/scripts/update-node-red-website.js
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -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); |  | ||||||
							
								
								
									
										62
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -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@v4 |  | ||||||
|         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@v6 |  | ||||||
|         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@v6 |  | ||||||
|         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 |  | ||||||
							
								
								
									
										30
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,30 +0,0 @@ | |||||||
| name: Run tests |  | ||||||
|  |  | ||||||
| on: |  | ||||||
|   push: |  | ||||||
|     branches: [ master, dev ] |  | ||||||
|   pull_request: |  | ||||||
|     branches: [ master, dev ] |  | ||||||
|  |  | ||||||
| permissions: |  | ||||||
|   contents: read |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   build: |  | ||||||
|     permissions: |  | ||||||
|       contents: read  # for actions/checkout to fetch code |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     strategy: |  | ||||||
|       matrix: |  | ||||||
|         node-version: [18, 20, 22] |  | ||||||
|     steps: |  | ||||||
|     - uses: actions/checkout@v4 |  | ||||||
|     - name: Use Node.js ${{ matrix.node-version }} |  | ||||||
|       uses: actions/setup-node@v4 |  | ||||||
|       with: |  | ||||||
|         node-version: ${{ matrix.node-version }} |  | ||||||
|     - name: Install Dependencies |  | ||||||
|       run: npm install |  | ||||||
|     - name: Run tests |  | ||||||
|       run: | |  | ||||||
|         npm run test |  | ||||||
							
								
								
									
										11
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -7,9 +7,7 @@ | |||||||
| .sessions.json | .sessions.json | ||||||
| .settings | .settings | ||||||
| .tern-project | .tern-project | ||||||
| .i18n-editor-metadata |  | ||||||
| *.backup | *.backup | ||||||
| *.bak |  | ||||||
| *_cred* | *_cred* | ||||||
| coverage | coverage | ||||||
| credentials.json | credentials.json | ||||||
| @@ -19,12 +17,3 @@ node_modules | |||||||
| public | public | ||||||
| locales/zz-ZZ | locales/zz-ZZ | ||||||
| nodes/core/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 |  | ||||||
|   | |||||||
| @@ -15,5 +15,5 @@ | |||||||
|     "shadow": true,     // allow variable shadowing (re-use of names...) |     "shadow": true,     // allow variable shadowing (re-use of names...) | ||||||
|     "sub": true,        // don't warn that foo['bar'] should be written as foo.bar |     "sub": true,        // don't warn that foo['bar'] should be written as foo.bar | ||||||
|     "proto": true,      // allow setting of __proto__ in node < v0.12, |     "proto": true,      // allow setting of __proto__ in node < v0.12, | ||||||
|     "esversion": 11      // allow es11(ES2020) |     "esversion": 6      // allow es6 | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								.nodemonignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,5 @@ | |||||||
|  | /Gruntfile.js | ||||||
|  | /.git/* | ||||||
|  | /lib/* | ||||||
|  | *.backup | ||||||
|  | /public/* | ||||||
							
								
								
									
										7
									
								
								.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | |||||||
|  | .settings | ||||||
|  | .jshintignore | ||||||
|  | .jshintrc | ||||||
|  | .project | ||||||
|  | .tern-project | ||||||
|  | .travis.yml | ||||||
|  | .git | ||||||
							
								
								
									
										21
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,21 @@ | |||||||
|  | sudo: false | ||||||
|  | language: node_js | ||||||
|  | env: | ||||||
|  |   - CXX="g++-4.8" | ||||||
|  | addons: | ||||||
|  |   apt: | ||||||
|  |     sources: | ||||||
|  |     - ubuntu-toolchain-r-test | ||||||
|  |     packages: | ||||||
|  |     - g++-4.8 | ||||||
|  |     - gcc-4.8 | ||||||
|  | node_js: | ||||||
|  |   - "8" | ||||||
|  |   - "7" | ||||||
|  |   - "6" | ||||||
|  |   - "4" | ||||||
|  | script: | ||||||
|  |   - istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage | ||||||
|  | before_script: | ||||||
|  |   - npm install -g istanbul | ||||||
|  |   - npm install coveralls | ||||||
							
								
								
									
										19
									
								
								API.md
									
									
									
									
									
								
							
							
						
						| @@ -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 |  | ||||||
							
								
								
									
										1109
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						| @@ -1,7 +0,0 @@ | |||||||
| cff-version: 1.2.0 |  | ||||||
| message: "If you use this software, please cite it as below." |  | ||||||
| title: "Node-RED" |  | ||||||
| authors: |  | ||||||
|   - family-names: "OpenJS Foundation" |  | ||||||
|   - family-names: "Contributors" |  | ||||||
| url: "https://nodered.org" |  | ||||||
| @@ -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/). | 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 | 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 | ## Raising issues | ||||||
|  |  | ||||||
| Please raise any bug reports on the relevant project's issue tracker. Be sure to | Please raise any bug reports on the relevant project's issue tracker. Be sure to | ||||||
| search the list to see if your issue has already been raised. | 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 | A good bug report is one that make it easy for us to understand what you were | ||||||
| trying to do and what went wrong. | trying to do and what went wrong. | ||||||
|  |  | ||||||
| @@ -29,34 +26,25 @@ relevant nodes, press Ctrl-E and copy the flow data from the Export dialog. | |||||||
| At a minimum, please include: | 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-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 | ## 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 | ## Pull-Requests | ||||||
|  |  | ||||||
| If you want to raise a pull-request with a new feature, or a refactoring | 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 | of existing code, it may well get rejected if you haven't discussed it on | ||||||
| do it that way to make sure your time and effort is well spent on something | the [mailing list](https://groups.google.com/forum/#!forum/node-red) first. | ||||||
| that fits with our goals. |  | ||||||
|  |  | ||||||
| If you've got a bug-fix or similar for us, then you are most welcome to | All contributors need to sign the JS Foundation's Contributor License Agreement. | ||||||
| get it raised - just make sure you link back to the issue it's fixing and | It is an online process and quick to do. You can read the details of the agreement | ||||||
| try to include some tests! | here: https://cla.js.foundation/node-red/node-red. | ||||||
|  |  | ||||||
| All contributors need to sign the OpenJS Foundation's Contributor License Agreement. | If you raise a pull-request without having signed the CLA, you will be prompted | ||||||
| It is an online process and quick to do. If you raise a pull-request without | to do so automatically. | ||||||
| having signed the CLA, you will be prompted to do so automatically. |  | ||||||
|  |  | ||||||
| ### Code Branches |  | ||||||
|  |  | ||||||
| When raising a PR for a fix or a new feature, it is important to target the right branch. |  | ||||||
|  |  | ||||||
|  - `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. |  | ||||||
|  |  | ||||||
| ### Coding standards | ### Coding standards | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										596
									
								
								Gruntfile.js
									
									
									
									
									
								
							
							
						
						| @@ -15,35 +15,17 @@ | |||||||
|  **/ |  **/ | ||||||
|  |  | ||||||
| var path = require("path"); | var path = require("path"); | ||||||
| var fs = require("fs-extra"); |  | ||||||
| var sass = require("sass"); |  | ||||||
|  |  | ||||||
| module.exports = function(grunt) { | module.exports = function(grunt) { | ||||||
|  |  | ||||||
|     var nodemonArgs = ["-V"]; |     var nodemonArgs = ["-v"]; | ||||||
|     var flowFile = grunt.option('flowFile'); |     var flowFile = grunt.option('flowFile'); | ||||||
|     if (flowFile) { |     if (flowFile) { | ||||||
|         nodemonArgs.push(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({ |     grunt.initConfig({ | ||||||
|         pkg: pkg, |         pkg: grunt.file.readJSON('package.json'), | ||||||
|         paths: { |         paths: { | ||||||
|             dist: ".dist" |             dist: ".dist" | ||||||
|         }, |         }, | ||||||
| @@ -55,28 +37,20 @@ module.exports = function(grunt) { | |||||||
|                 ui: 'bdd', |                 ui: 'bdd', | ||||||
|                 reporter: 'spec' |                 reporter: 'spec' | ||||||
|             }, |             }, | ||||||
|             all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] }, |             all: { src: ['test/**/*_spec.js'] }, | ||||||
|             core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]}, |             core: { src: ["test/_spec.js","test/red/**/*_spec.js"]}, | ||||||
|             nodes: { src: ["test/nodes/**/*_spec.js"]} |             nodes: { src: ["test/nodes/**/*_spec.js"]} | ||||||
|         }, |         }, | ||||||
|         webdriver: { |         mocha_istanbul: { | ||||||
|             all: { |  | ||||||
|                 configFile: 'test/editor/wdio.conf.js' |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         nyc: { |  | ||||||
|             options: { |             options: { | ||||||
|                 cwd: '.', |                 globals: ['expect'], | ||||||
|                 include: ['packages/node_modules/**'], |                 timeout: 3000, | ||||||
|                 excludeNodeModules: false, |                 ignoreLeaks: false, | ||||||
|                 exclude: ['packages/node_modules/@node-red/editor-client/**'], |                 ui: 'bdd', | ||||||
|                 reporter: ['lcov', 'html','text-summary'], |                 reportFormats: ['lcov'], | ||||||
|                 reportDir: 'coverage', |                 print: 'both' | ||||||
|                 all: true |  | ||||||
|             }, |             }, | ||||||
|             all:   { cmd: false, args: ['grunt', 'simplemocha:all'] }, |             coverage: { src: ['test/**/*_spec.js'] } | ||||||
|             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: { |         jshint: { | ||||||
|             options: { |             options: { | ||||||
| @@ -92,20 +66,22 @@ module.exports = function(grunt) { | |||||||
|                 //"loopfunc": true, // allow functions to be defined in loops |                 //"loopfunc": true, // allow functions to be defined in loops | ||||||
|                 //"sub": true       // don't warn that foo['bar'] should be written as foo.bar |                 //"sub": true       // don't warn that foo['bar'] should be written as foo.bar | ||||||
|             }, |             }, | ||||||
|             // all: [ |             all: [ | ||||||
|             //     'Gruntfile.js', |                 'Gruntfile.js', | ||||||
|             //     'red.js', |                 'red.js', | ||||||
|             //     'packages/**/*.js' |                 'red/**/*.js', | ||||||
|             // ], |                 'nodes/core/*/*.js', | ||||||
|             // core: { |                 'editor/js/**/*.js' | ||||||
|             //     files: { |             ], | ||||||
|             //         src: [ |             core: { | ||||||
|             //             'Gruntfile.js', |                 files: { | ||||||
|             //             'red.js', |                     src: [ | ||||||
|             //             'packages/**/*.js', |                         'Gruntfile.js', | ||||||
|             //         ] |                         'red.js', | ||||||
|             //     } |                         'red/**/*.js' | ||||||
|             // }, |                     ] | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|             nodes: { |             nodes: { | ||||||
|                 files: { |                 files: { | ||||||
|                     src: [ 'nodes/core/*/*.js' ] |                     src: [ 'nodes/core/*/*.js' ] | ||||||
| @@ -113,7 +89,7 @@ module.exports = function(grunt) { | |||||||
|             }, |             }, | ||||||
|             editor: { |             editor: { | ||||||
|                 files: { |                 files: { | ||||||
|                     src: [ 'packages/node_modules/@node-red/editor-client/src/js/**/*.js' ] |                     src: [ 'editor/js/**/*.js' ] | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             tests: { |             tests: { | ||||||
| @@ -133,188 +109,138 @@ module.exports = function(grunt) { | |||||||
|                 src: [ |                 src: [ | ||||||
|                     // Ensure editor source files are concatenated in |                     // Ensure editor source files are concatenated in | ||||||
|                     // the right order |                     // the right order | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/polyfills.js", |                     "editor/js/red.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js", |                     "editor/js/events.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/red.js", |                     "editor/js/i18n.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/events.js", |                     "editor/js/settings.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/hooks.js", |                     "editor/js/user.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/i18n.js", |                     "editor/js/comms.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/settings.js", |                     "editor/js/text/bidi.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/user.js", |                     "editor/js/text/format.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/comms.js", |                     "editor/js/ui/state.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/runtime.js", |                     "editor/js/nodes.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/multiplayer.js", |                     "editor/js/history.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/text/bidi.js", |                     "editor/js/validators.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/text/format.js", |                     "editor/js/ui/utils.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/state.js", |                     "editor/js/ui/common/editableList.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/plugins.js", |                     "editor/js/ui/common/checkboxSet.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/nodes.js", |                     "editor/js/ui/common/menu.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/font-awesome.js", |                     "editor/js/ui/common/panels.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/history.js", |                     "editor/js/ui/common/popover.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/validators.js", |                     "editor/js/ui/common/searchBox.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/utils.js", |                     "editor/js/ui/common/tabs.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js", |                     "editor/js/ui/common/stack.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js", |                     "editor/js/ui/common/typedInput.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js", |                     "editor/js/ui/actions.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js", |                     "editor/js/ui/deploy.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js", |                     "editor/js/ui/diff.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js", |                     "editor/js/ui/keyboard.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js", |                     "editor/js/ui/workspaces.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js", |                     "editor/js/ui/view.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js", |                     "editor/js/ui/sidebar.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js", |                     "editor/js/ui/palette.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js", |                     "editor/js/ui/tab-info.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js", |                     "editor/js/ui/tab-config.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/actions.js", |                     "editor/js/ui/palette-editor.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js", |                     "editor/js/ui/editor.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js", |                     "editor/js/ui/tray.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js", |                     "editor/js/ui/clipboard.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js", |                     "editor/js/ui/library.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js", |                     "editor/js/ui/notifications.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js", |                     "editor/js/ui/search.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js", |                     "editor/js/ui/typeSearch.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/view.js", |                     "editor/js/ui/subflow.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js", |                     "editor/js/ui/userSettings.js", | ||||||
|                     "packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js", |                     "editor/js/ui/touch/radialMenu.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" |  | ||||||
|                 ], |                 ], | ||||||
|                 nonull: true, |                 dest: "public/red/red.js" | ||||||
|                 dest: "packages/node_modules/@node-red/editor-client/public/red/red.js" |  | ||||||
|             }, |             }, | ||||||
|             vendor: { |             vendor: { | ||||||
|                 files: [ |                 files: { | ||||||
|                     { |                     "public/vendor/vendor.js": [ | ||||||
|                         src: [ |                         "editor/vendor/jquery/js/jquery-1.11.3.min.js", | ||||||
|                             "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js", |                         "editor/vendor/bootstrap/js/bootstrap.min.js", | ||||||
|                             "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js", |                         "editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js", | ||||||
|                             "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js", |                         "editor/vendor/jquery/js/jquery.ui.touch-punch.min.js", | ||||||
|                             "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js", |                         "editor/vendor/marked/marked.min.js", | ||||||
|                             "node_modules/marked/marked.min.js", |                         "editor/vendor/d3/d3.v3.min.js", | ||||||
|                             "node_modules/dompurify/dist/purify.min.js", |                         "editor/vendor/i18next/i18next.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" |  | ||||||
|                     ], |                     ], | ||||||
|                         nonull: true, |                     "public/vendor/vendor.css": [ | ||||||
|                         dest: "packages/node_modules/@node-red/editor-client/public/vendor/vendor.js" |                         // TODO: resolve relative resource paths in | ||||||
|                     }, |                         //       bootstrap/FA/jquery | ||||||
|                     // { |  | ||||||
|                     //     src: [ |  | ||||||
|                     //         // TODO: resolve relative resource paths in |  | ||||||
|                     //         //       bootstrap/FA/jquery |  | ||||||
|                     //     ], |  | ||||||
|                     //     dest: "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css" |  | ||||||
|                     // }, |  | ||||||
|                     { |  | ||||||
|                         src: [ |  | ||||||
|                             "node_modules/jsonata/jsonata-es5.min.js", |  | ||||||
|                             "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js" |  | ||||||
|                     ], |                     ], | ||||||
|                         nonull: true, |                     "public/vendor/jsonata/jsonata.min.js": [ | ||||||
|                         dest: "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js", |                         "node_modules/jsonata/jsonata-es5.min.js", | ||||||
|                     }, |                         "editor/vendor/jsonata/formatter.js" | ||||||
|                     { |                     ], | ||||||
|                         src: "node_modules/mermaid/dist/mermaid.min.js", |                     "public/vendor/ace/worker-jsonata.js": [ | ||||||
|                         nonull: true, |                         "node_modules/jsonata/jsonata-es5.min.js", | ||||||
|                         dest: "packages/node_modules/@node-red/editor-client/public/vendor/mermaid/mermaid.min.js", |                         "editor/vendor/jsonata/worker-jsonata.js" | ||||||
|                     }, |  | ||||||
|                     ] |                     ] | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|         }, |         }, | ||||||
|         uglify: { |         uglify: { | ||||||
|             build: { |             build: { | ||||||
|                 files: { |                 files: { | ||||||
|                     'packages/node_modules/@node-red/editor-client/public/red/red.min.js': 'packages/node_modules/@node-red/editor-client/public/red/red.js', |                     'public/red/red.min.js': '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', |                     'public/red/main.min.js': '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', |                     'public/vendor/ace/mode-jsonata.js': 'editor/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/vendor/ace/snippets/jsonata.js': 'editor/vendor/jsonata/snippets-jsonata.js' | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         sass: { |         sass: { | ||||||
|             build: { |             build: { | ||||||
|                 options: { |                 options: { | ||||||
|                     implementation: sass, |  | ||||||
|                     outputStyle: 'compressed' |                     outputStyle: 'compressed' | ||||||
|                 }, |                 }, | ||||||
|                 files: [{ |                 files: [{ | ||||||
|                     dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css', |                     dest: 'public/red/style.min.css', | ||||||
|                     src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss' |                     src: 'editor/sass/style.scss' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     dest: 'public/vendor/bootstrap/css/bootstrap.min.css', | ||||||
|  |                     src: 'editor/vendor/bootstrap/css/bootstrap.css' | ||||||
|                 }] |                 }] | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         jsonlint: { |         jsonlint: { | ||||||
|             messages: { |             messages: { | ||||||
|                 src: [ |                 src: [ | ||||||
|                     'packages/node_modules/@node-red/nodes/locales/**/*.json', |                     'nodes/core/locales/en-US/messages.json', | ||||||
|                     'packages/node_modules/@node-red/editor-client/locales/**/*.json', |                     'red/api/locales/en-US/editor.json', | ||||||
|                     'packages/node_modules/@node-red/runtime/locales/**/*.json' |                     'red/runtime/locales/en-US/runtime.json' | ||||||
|                 ] |                 ] | ||||||
|             }, |             }, | ||||||
|             keymaps: { |             keymaps: { | ||||||
|                 src: [ |                 src: [ | ||||||
|                     'packages/node_modules/@node-red/editor-client/src/js/keymap.json' |                     'editor/js/keymap.json' | ||||||
|                 ] |                 ] | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         attachCopyright: { |         attachCopyright: { | ||||||
|             js: { |             js: { | ||||||
|                 src: [ |                 src: [ | ||||||
|                     'packages/node_modules/@node-red/editor-client/public/red/red.min.js', |                     'public/red/red.min.js', | ||||||
|                     'packages/node_modules/@node-red/editor-client/public/red/main.min.js' |                     'public/red/main.min.js' | ||||||
|                 ] |                 ] | ||||||
|             }, |             }, | ||||||
|             css: { |             css: { | ||||||
|                 src: [ |                 src: [ | ||||||
|                     'packages/node_modules/@node-red/editor-client/public/red/style.min.css' |                     'public/red/style.min.css' | ||||||
|                 ] |                 ] | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         clean: { |         clean: { | ||||||
|             build: { |             build: { | ||||||
|                 src: [ |                 src: [ | ||||||
|                     "packages/node_modules/@node-red/editor-client/public/red", |                     "public/red", | ||||||
|                     "packages/node_modules/@node-red/editor-client/public/index.html", |                     "public/index.html", | ||||||
|                     "packages/node_modules/@node-red/editor-client/public/favicon.ico", |                     "public/favicon.ico", | ||||||
|                     "packages/node_modules/@node-red/editor-client/public/icons", |                     "public/icons", | ||||||
|                     "packages/node_modules/@node-red/editor-client/public/vendor", |                     "public/vendor" | ||||||
|                     "packages/node_modules/@node-red/editor-client/public/types/node", |  | ||||||
|                     "packages/node_modules/@node-red/editor-client/public/types/node-red", |  | ||||||
|                 ] |                 ] | ||||||
|             }, |             }, | ||||||
|             release: { |             release: { | ||||||
| @@ -326,36 +252,30 @@ module.exports = function(grunt) { | |||||||
|         watch: { |         watch: { | ||||||
|             js: { |             js: { | ||||||
|                 files: [ |                 files: [ | ||||||
|                     'packages/node_modules/@node-red/editor-client/src/js/**/*.js' |                     'editor/js/**/*.js' | ||||||
|                 ], |                 ], | ||||||
|                 tasks: ['copy:build','concat',/*'uglify',*/ 'attachCopyright:js'] |                 tasks: ['copy:build','concat','uglify','attachCopyright:js'] | ||||||
|             }, |             }, | ||||||
|             sass: { |             sass: { | ||||||
|                 files: [ |                 files: [ | ||||||
|                     'packages/node_modules/@node-red/editor-client/src/sass/**/*.scss' |                     'editor/sass/**/*.scss' | ||||||
|                 ], |                 ], | ||||||
|                 tasks: ['sass','attachCopyright:css'] |                 tasks: ['sass','attachCopyright:css'] | ||||||
|             }, |             }, | ||||||
|             json: { |             json: { | ||||||
|                 files: [ |                 files: [ | ||||||
|                     'packages/node_modules/@node-red/nodes/locales/**/*.json', |                     'nodes/core/locales/en-US/messages.json', | ||||||
|                     'packages/node_modules/@node-red/editor-client/locales/**/*.json', |                     'red/api/locales/en-US/editor.json', | ||||||
|                     'packages/node_modules/@node-red/runtime/locales/**/*.json' |                     'red/runtime/locales/en-US/runtime.json' | ||||||
|                 ], |                 ], | ||||||
|                 tasks: ['jsonlint:messages'] |                 tasks: ['jsonlint:messages'] | ||||||
|             }, |             }, | ||||||
|             keymaps: { |             keymaps: { | ||||||
|                 files: [ |                 files: [ | ||||||
|                     'packages/node_modules/@node-red/editor-client/src/js/keymap.json' |                     'editor/js/keymap.json' | ||||||
|                 ], |                 ], | ||||||
|                 tasks: ['jsonlint:keymaps','copy:build'] |                 tasks: ['jsonlint:keymaps','copy:build'] | ||||||
|             }, |             }, | ||||||
|             tours: { |  | ||||||
|                 files: [ |  | ||||||
|                     'packages/node_modules/@node-red/editor-client/src/tours/**/*.js' |  | ||||||
|                 ], |  | ||||||
|                 tasks: ['copy:build'] |  | ||||||
|             }, |  | ||||||
|             misc: { |             misc: { | ||||||
|                 files: [ |                 files: [ | ||||||
|                     'CHANGELOG.md' |                     'CHANGELOG.md' | ||||||
| @@ -367,13 +287,12 @@ module.exports = function(grunt) { | |||||||
|         nodemon: { |         nodemon: { | ||||||
|             /* uses .nodemonignore */ |             /* uses .nodemonignore */ | ||||||
|             dev: { |             dev: { | ||||||
|                 script: 'packages/node_modules/node-red/red.js', |                 script: 'red.js', | ||||||
|                 options: { |                 options: { | ||||||
|                     args: nodemonArgs, |                     args: nodemonArgs, | ||||||
|                     ext: 'js,html,json', |                     ext: 'js,html,json', | ||||||
|                     watch: [ |                     watch: [ | ||||||
|                         'packages/node_modules', |                         'red','nodes' | ||||||
|                         '!packages/node_modules/@node-red/editor-client' |  | ||||||
|                     ] |                     ] | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -392,75 +311,69 @@ module.exports = function(grunt) { | |||||||
|             build: { |             build: { | ||||||
|                 files:[ |                 files:[ | ||||||
|                     { |                     { | ||||||
|                         src: 'packages/node_modules/@node-red/editor-client/src/js/main.js', |                         src: 'editor/js/main.js', | ||||||
|                         dest: 'packages/node_modules/@node-red/editor-client/public/red/main.js' |                         dest: 'public/red/main.js' | ||||||
|                     }, |                     }, | ||||||
|                     { |                     { | ||||||
|                         src: 'packages/node_modules/@node-red/editor-client/src/js/keymap.json', |                         src: 'editor/js/keymap.json', | ||||||
|                         dest: 'packages/node_modules/@node-red/editor-client/public/red/keymap.json' |                         dest: 'public/red/keymap.json' | ||||||
|                     }, |                     }, | ||||||
|                     { |                     { | ||||||
|                         cwd: 'packages/node_modules/@node-red/editor-client/src/images', |                         cwd: 'editor/images', | ||||||
|                         src: '**', |                         src: '**', | ||||||
|                         expand: true, |                         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: [ |                         src: [ | ||||||
|                             'ace/**', |                             'ace/**', | ||||||
|                             'jquery/css/base/**', |                             //'bootstrap/css/**', | ||||||
|                             'font-awesome/**', |                             'bootstrap/img/**', | ||||||
|                             'monaco/dist/**', |                             'jquery/css/**', | ||||||
|                             'monaco/types/extraLibs.js', |                             'font-awesome/**' | ||||||
|                             'monaco/style.css', |  | ||||||
|                             'monaco/monaco-bootstrap.js' |  | ||||||
|                         ], |                         ], | ||||||
|                         expand: true, |                         expand: true, | ||||||
|                         dest: 'packages/node_modules/@node-red/editor-client/public/vendor/' |                         dest: 'public/vendor/' | ||||||
|                     }, |                     }, | ||||||
|                     { |                     { | ||||||
|                         cwd: 'packages/node_modules/@node-red/editor-client/src', |                         cwd: 'editor/icons', | ||||||
|                         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', |  | ||||||
|                         src: '**', |                         src: '**', | ||||||
|                         expand: true, |                         expand: true, | ||||||
|                         dest: 'packages/node_modules/@node-red/editor-client/public/icons/' |                         dest: 'public/icons/' | ||||||
|                     }, |                     }, | ||||||
|                     { |                     { | ||||||
|                         expand: true, |                         expand: true, | ||||||
|                         src: ['packages/node_modules/@node-red/editor-client/src/index.html','packages/node_modules/@node-red/editor-client/src/favicon.ico'], |                         src: ['editor/index.html','editor/favicon.ico'], | ||||||
|                         dest: 'packages/node_modules/@node-red/editor-client/public/', |                         dest: 'public/', | ||||||
|                         flatten: true |                         flatten: true | ||||||
|                     }, |                     }, | ||||||
|                     { |                     { | ||||||
|                         src: 'CHANGELOG.md', |                         src: 'CHANGELOG.md', | ||||||
|                         dest: 'packages/node_modules/@node-red/editor-client/public/red/about' |                         dest: '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/' |  | ||||||
|                     } |                     } | ||||||
|                 ] |                 ] | ||||||
|  |             }, | ||||||
|  |             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: { |         chmod: { | ||||||
| @@ -468,96 +381,20 @@ module.exports = function(grunt) { | |||||||
|                 mode: '755' |                 mode: '755' | ||||||
|             }, |             }, | ||||||
|             release: { |             release: { | ||||||
|  |                 // Target-specific file/dir lists and/or options go here. | ||||||
|                 src: [ |                 src: [ | ||||||
|                     "packages/node_modules/@node-red/nodes/core/hardware/nrgpio", |                     path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*') | ||||||
|                     "packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/node-red-*sh" |  | ||||||
|                 ] |                 ] | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         'npm-command': { |  | ||||||
|             options: { |  | ||||||
|                 cmd: "pack", |  | ||||||
|                 cwd: "<%= paths.dist %>/modules" |  | ||||||
|             }, |  | ||||||
|             'node-red': { options: { args: [__dirname+'/packages/node_modules/node-red'] } }, |  | ||||||
|             '@node-red/editor-api': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-api'] } }, |  | ||||||
|             '@node-red/editor-client': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-client'] } }, |  | ||||||
|             '@node-red/nodes': { options: { args: [__dirname+'/packages/node_modules/@node-red/nodes'] } }, |  | ||||||
|             '@node-red/registry': { options: { args: [__dirname+'/packages/node_modules/@node-red/registry'] } }, |  | ||||||
|             '@node-red/runtime': { options: { args: [__dirname+'/packages/node_modules/@node-red/runtime'] } }, |  | ||||||
|             '@node-red/util': { options: { args: [__dirname+'/packages/node_modules/@node-red/util'] } } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         }, |  | ||||||
|         mkdir: { |  | ||||||
|             release: { |  | ||||||
|                 options: { |  | ||||||
|                     create: ['<%= paths.dist %>/modules'] |  | ||||||
|                 }, |  | ||||||
|             }, |  | ||||||
|         }, |  | ||||||
|         compress: { |         compress: { | ||||||
|             release: { |             release: { | ||||||
|                 options: { |                 options: { | ||||||
|                     archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip' |                     archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip' | ||||||
|                 }, |                 }, | ||||||
|                 expand: true, |                 expand: true, | ||||||
|                 cwd: 'packages/node_modules/', |                 cwd: '<%= paths.dist %>/', | ||||||
|                 src: [ |                 src: ['node-red-<%= pkg.version %>/**'] | ||||||
|                     '**', |  | ||||||
|                     '!@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' |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| @@ -570,42 +407,17 @@ module.exports = function(grunt) { | |||||||
|     grunt.loadNpmTasks('grunt-contrib-watch'); |     grunt.loadNpmTasks('grunt-contrib-watch'); | ||||||
|     grunt.loadNpmTasks('grunt-concurrent'); |     grunt.loadNpmTasks('grunt-concurrent'); | ||||||
|     grunt.loadNpmTasks('grunt-sass'); |     grunt.loadNpmTasks('grunt-sass'); | ||||||
|  |     grunt.loadNpmTasks('grunt-nodemon'); | ||||||
|     grunt.loadNpmTasks('grunt-contrib-compress'); |     grunt.loadNpmTasks('grunt-contrib-compress'); | ||||||
|     grunt.loadNpmTasks('grunt-contrib-copy'); |     grunt.loadNpmTasks('grunt-contrib-copy'); | ||||||
|     grunt.loadNpmTasks('grunt-chmod'); |     grunt.loadNpmTasks('grunt-chmod'); | ||||||
|     grunt.loadNpmTasks('grunt-jsonlint'); |     grunt.loadNpmTasks('grunt-jsonlint'); | ||||||
|     if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) { |     grunt.loadNpmTasks('grunt-mocha-istanbul'); | ||||||
|         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() { |     grunt.registerMultiTask('attachCopyright', function() { | ||||||
|         var files = this.data.src; |         var files = this.data.src; | ||||||
|         var copyright = "/**\n"+ |         var copyright = "/**\n"+ | ||||||
|             " * Copyright OpenJS Foundation and other contributors, https://openjsf.org/\n"+ |             " * Copyright JS Foundation and other contributors, http://js.foundation\n"+ | ||||||
|             " *\n"+ |             " *\n"+ | ||||||
|             " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+ |             " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+ | ||||||
|             " * you may not use this file except in compliance with the License.\n"+ |             " * you may not use this file except in compliance with the License.\n"+ | ||||||
| @@ -642,38 +454,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', |     grunt.registerTask('setDevEnv', | ||||||
|         'Sets NODE_ENV=development so non-minified assets are used', |         'Sets NODE_ENV=development so non-minified assets are used', | ||||||
|             function () { |             function () { | ||||||
| @@ -682,61 +462,33 @@ module.exports = function(grunt) { | |||||||
|  |  | ||||||
|     grunt.registerTask('default', |     grunt.registerTask('default', | ||||||
|         'Builds editor content then runs code style checks and unit tests on all components', |         'Builds editor content then runs code style checks and unit tests on all components', | ||||||
|         ['build','verifyPackageDependencies','jshint:editor','nyc:all']); |         ['build','test-core','test-editor','test-nodes']); | ||||||
|  |  | ||||||
|     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']); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     grunt.registerTask('test-core', |     grunt.registerTask('test-core', | ||||||
|         'Runs code style check and unit tests on core runtime code', |         'Runs code style check and unit tests on core runtime code', | ||||||
|         ['build','nyc:core']); |         ['jshint:core','simplemocha:core']); | ||||||
|  |  | ||||||
|     grunt.registerTask('test-editor', |     grunt.registerTask('test-editor', | ||||||
|         'Runs code style check on editor code', |         'Runs code style check on editor code', | ||||||
|         ['jshint:editor']); |         ['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', |     grunt.registerTask('test-nodes', | ||||||
|         'Runs unit tests on core nodes', |         'Runs unit tests on core nodes', | ||||||
|         ['build','nyc:nodes']); |         ['simplemocha:nodes']); | ||||||
|  |  | ||||||
|     grunt.registerTask('build', |     grunt.registerTask('build', | ||||||
|         'Builds editor content', |         'Builds editor content', | ||||||
|         ['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']); |         ['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']); | ||||||
|  |  | ||||||
|     grunt.registerTask('build-dev', |  | ||||||
|         'Developer mode: build dev version', |  | ||||||
|         ['clean:build','concat:build','concat:vendor','copy:build','sass:build','setDevEnv']); |  | ||||||
|  |  | ||||||
|     grunt.registerTask('dev', |     grunt.registerTask('dev', | ||||||
|         'Developer mode: run node-red, watch for source changes and build/restart', |         'Developer mode: run node-red, watch for source changes and build/restart', | ||||||
|         ['build','setDevEnv','concurrent:dev']); |         ['build','setDevEnv','concurrent:dev']); | ||||||
|  |  | ||||||
|     grunt.registerTask('release', |     grunt.registerTask('release', | ||||||
|         'Create distribution zip file', |         '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', |     grunt.registerTask('coverage', | ||||||
|         'Run Istanbul code test coverage task', |         'Run Istanbul code test coverage task', | ||||||
|         ['build','nyc:all']); |         ['build','mocha_istanbul']); | ||||||
|  |  | ||||||
|     grunt.registerTask('docs', |  | ||||||
|         'Generates API documentation', |  | ||||||
|         ['jsdoc']); |  | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						| @@ -1,4 +1,4 @@ | |||||||
| Copyright OpenJS Foundation and other contributors, https://openjsf.org/ | Copyright JS Foundation and other contributors, http://js.foundation | ||||||
|  |  | ||||||
|                                  Apache License |                                  Apache License | ||||||
|                            Version 2.0, January 2004 |                            Version 2.0, January 2004 | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1,27 +1,29 @@ | |||||||
| # Node-RED | # Node-RED | ||||||
|  |  | ||||||
| https://nodered.org | http://nodered.org | ||||||
|  |  | ||||||
| [](https://github.com/node-red/node-red/actions?query=branch%3Amaster) | [](https://travis-ci.org/node-red/node-red) | ||||||
|  | [](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. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Quick Start | ## 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. | started. | ||||||
|  |  | ||||||
| 1. `sudo npm install -g --unsafe-perm node-red` | 1. `sudo npm install -g node-red` | ||||||
| 2. `node-red` | 2. `node-red` | ||||||
| 3. Open <http://localhost:1880> | 3. Open <http://localhost:1880> | ||||||
|  |  | ||||||
| ## Getting Help | ## 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 | ## Developers | ||||||
|  |  | ||||||
| @@ -43,6 +45,9 @@ If you want to run the latest code from git, here's how to get started: | |||||||
| 4. Run | 4. Run | ||||||
|  |  | ||||||
|         npm start |         npm start | ||||||
|  |    or | ||||||
|  |  | ||||||
|  |         node red.js | ||||||
|  |  | ||||||
| ## Contributing | ## Contributing | ||||||
|  |  | ||||||
| @@ -51,19 +56,19 @@ Before raising a pull-request, please read our | |||||||
|  |  | ||||||
| This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/). | 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 |  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 | ## Authors | ||||||
|  |  | ||||||
| Node-RED is a project of the [OpenJS Foundation](http://openjsf.org). | Node-RED is a project of the [JS Foundation](http://js.foundation). | ||||||
|  |  | ||||||
| It is maintained by: | It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/). | ||||||
|  |  | ||||||
|  | * Nick O'Leary [@knolleary](http://twitter.com/knolleary) | ||||||
|  | * Dave Conway-Jones [@ceejay](http://twitter.com/ceejay) | ||||||
|  |  | ||||||
|  * Nick O'Leary [@knolleary](http://twitter.com/knolleary) |  | ||||||
|  * Dave Conway-Jones [@ceejay](http://twitter.com/ceejay) |  | ||||||
|  * And many others... |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Copyright and license | ## Copyright and license | ||||||
|  |  | ||||||
| Copyright OpenJS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE). | Copyright JS Foundation and other contributors, http://js.foundation under [the Apache 2.0 license](LICENSE). | ||||||
|   | |||||||
| @@ -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. |  | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| #!/bin/sh | #!/bin/bash | ||||||
| # | # | ||||||
| # Copyright JS Foundation and other contributors, http://js.foundation | # Copyright JS Foundation and other contributors, http://js.foundation | ||||||
| # | # | ||||||
| @@ -29,16 +29,15 @@ do | |||||||
| done | done | ||||||
| 
 | 
 | ||||||
| # Find the real location of this script | # Find the real location of this script | ||||||
| CURRENT_PATH=$(pwd) | CURRENT_PATH=`pwd` | ||||||
| SCRIPT_PATH=$(readlink -f "$0") | SCRIPT_PATH="${BASH_SOURCE[0]}"; | ||||||
| while [ -h "${SCRIPT_PATH}" ]; do | while([ -h "${SCRIPT_PATH}" ]); do | ||||||
|     cd "$(dirname "${SCRIPT_PATH}")" || exit 1 |     cd "`dirname "${SCRIPT_PATH}"`" | ||||||
|     P=$(basename "${SCRIPT_PATH}") |     SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")"; | ||||||
|     SCRIPT_PATH=$(readlink "${P}") |  | ||||||
| done | done | ||||||
| cd "$(dirname "${SCRIPT_PATH}")" > /dev/null || exit 1 | cd "`dirname "${SCRIPT_PATH}"`" > /dev/null | ||||||
| SCRIPT_PATH=$(pwd) | SCRIPT_PATH="`pwd`"; | ||||||
| cd "$CURRENT_PATH" || exit 1 | cd $CURRENT_PATH | ||||||
| 
 | 
 | ||||||
| # Run Node-RED | # 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 | ||||||
| Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/alert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 308 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/arduino.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 603 B | 
| Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 393 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/bluetooth.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/bridge-dash.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 508 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/bridge.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 575 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/cog.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 493 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/comment.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 601 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/db.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 459 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/debug.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 218 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/envelope.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 324 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/feed.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 378 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/file.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 255 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/function.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 457 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/hash.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 502 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/inject.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 449 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/join.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 253 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/leveldb.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/light.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 639 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/link-out.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 402 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/mongodb.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 414 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/mouse.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 671 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/node-changed.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 386 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/node-error.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 386 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-csv.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 413 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-html.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 393 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-json.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 467 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-xml.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 393 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/parser-yaml.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 423 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/range.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 360 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/redis.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 736 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/rpi.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 482 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/serial.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 273 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/split.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 256 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/subflow.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 439 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/swap.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 592 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/switch.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 509 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/template.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 488 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/timer.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 628 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/trigger.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 258 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/twitter.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 404 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/watch.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 591 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/icons/white-globe.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 707 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/deploy-flows-o.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 291 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/deploy-flows.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 386 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/deploy-full-o.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 289 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/deploy-full.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 368 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/deploy-nodes-o.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 290 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/deploy-nodes.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 392 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/grip.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 192 B | 
| Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB | 
| Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB | 
| Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/node-red.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1019 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/pw_maze_white.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 600 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/subflow_tab.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 410 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/09.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 638 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/az.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 546 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/bin.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 638 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/bool.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 646 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/expr.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 563 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/json.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 588 B | 
							
								
								
									
										
											BIN
										
									
								
								editor/images/typedInput/re.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 502 B | 
| @@ -26,26 +26,8 @@ RED.comms = (function() { | |||||||
|     var reconnectAttempts = 0; |     var reconnectAttempts = 0; | ||||||
|     var active = false; |     var active = false; | ||||||
| 
 | 
 | ||||||
|     RED.events.on('login', function(username) { |  | ||||||
|         // User has logged in
 |  | ||||||
|         // Need to upgrade the connection to be authenticated
 |  | ||||||
|         if (ws && ws.readyState == 1) { |  | ||||||
|             const auth_tokens = RED.settings.get("auth-tokens"); |  | ||||||
|             ws.send(JSON.stringify({auth:auth_tokens.access_token})) |  | ||||||
|         } |  | ||||||
|     }) |  | ||||||
| 
 |  | ||||||
|     function connectWS() { |     function connectWS() { | ||||||
|         active = true; |         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 path = location.hostname; | ||||||
|         var port = location.port; |         var port = location.port; | ||||||
|         if (port.length !== 0) { |         if (port.length !== 0) { | ||||||
| @@ -53,8 +35,7 @@ RED.comms = (function() { | |||||||
|         } |         } | ||||||
|         path = path+document.location.pathname; |         path = path+document.location.pathname; | ||||||
|         path = path+(path.slice(-1) == "/"?"":"/")+"comms"; |         path = path+(path.slice(-1) == "/"?"":"/")+"comms"; | ||||||
|             wspath = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path; |         path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path; | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         var auth_tokens = RED.settings.get("auth-tokens"); |         var auth_tokens = RED.settings.get("auth-tokens"); | ||||||
|         pendingAuth = (auth_tokens!=null); |         pendingAuth = (auth_tokens!=null); | ||||||
| @@ -65,10 +46,9 @@ RED.comms = (function() { | |||||||
|                     ws.send(JSON.stringify({subscribe:t})); |                     ws.send(JSON.stringify({subscribe:t})); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             emit('connect') |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ws = new WebSocket(wspath); |         ws = new WebSocket(path); | ||||||
|         ws.onopen = function() { |         ws.onopen = function() { | ||||||
|             reconnectAttempts = 0; |             reconnectAttempts = 0; | ||||||
|             if (errornotification) { |             if (errornotification) { | ||||||
| @@ -84,31 +64,19 @@ RED.comms = (function() { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         ws.onmessage = function(event) { |         ws.onmessage = function(event) { | ||||||
|             var message = JSON.parse(event.data); |             var msg = JSON.parse(event.data); | ||||||
|             if (message.auth) { |             if (pendingAuth && msg.auth) { | ||||||
|                 if (pendingAuth) { |                 if (msg.auth === "ok") { | ||||||
|                     if (message.auth === "ok") { |  | ||||||
|                     pendingAuth = false; |                     pendingAuth = false; | ||||||
|                     completeConnection(); |                     completeConnection(); | ||||||
|                     } else if (message.auth === "fail") { |                 } else if (msg.auth === "fail") { | ||||||
|                     // anything else is an error...
 |                     // anything else is an error...
 | ||||||
|                     active = false; |                     active = false; | ||||||
|                     RED.user.login({updateMenu:true},function() { |                     RED.user.login({updateMenu:true},function() { | ||||||
|                         connectWS(); |                         connectWS(); | ||||||
|                     }) |                     }) | ||||||
|                 } |                 } | ||||||
|                 } else if (message.auth === "fail") { |             } else if (msg.topic) { | ||||||
|                     // Our current session has expired
 |  | ||||||
|                     active = false; |  | ||||||
|                     RED.user.login({updateMenu:true},function() { |  | ||||||
|                         connectWS(); |  | ||||||
|                     }) |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 // Otherwise, 'message' is an array of actual comms messages
 |  | ||||||
|                 for (var m = 0; m < message.length; m++) { |  | ||||||
|                     var msg = message[m]; |  | ||||||
|                     if (msg.topic) { |  | ||||||
|                 for (var t in subscriptions) { |                 for (var t in subscriptions) { | ||||||
|                     if (subscriptions.hasOwnProperty(t)) { |                     if (subscriptions.hasOwnProperty(t)) { | ||||||
|                         var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$"); |                         var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$"); | ||||||
| @@ -123,8 +91,6 @@ RED.comms = (function() { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }; |         }; | ||||||
|         ws.onclose = function() { |         ws.onclose = function() { | ||||||
|             if (!active) { |             if (!active) { | ||||||
| @@ -152,10 +118,10 @@ RED.comms = (function() { | |||||||
|                         connectWS(); |                         connectWS(); | ||||||
|                     } else { |                     } else { | ||||||
|                         var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>'; |                         var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>'; | ||||||
|                         errornotification.update(msg,{silent:true}); |                         errornotification.update(msg); | ||||||
|                         $(errornotification).find("a").on("click", function(e) { |                         $(errornotification).find("a").click(function(e) { | ||||||
|                             e.preventDefault(); |                             e.preventDefault(); | ||||||
|                             errornotification.update(RED._("notification.errors.lostConnection"),{silent:true}); |                             errornotification.update(RED._("notification.errors.lostConnection")); | ||||||
|                             clearInterval(connectCountdownTimer); |                             clearInterval(connectCountdownTimer); | ||||||
|                             connectWS(); |                             connectWS(); | ||||||
|                         }) |                         }) | ||||||
| @@ -190,53 +156,9 @@ RED.comms = (function() { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function send(topic, msg) { |  | ||||||
|         if (ws && ws.readyState == 1) { |  | ||||||
|             ws.send(JSON.stringify({ |  | ||||||
|                 topic, |  | ||||||
|                 data: msg |  | ||||||
|             })) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const eventHandlers = {}; |  | ||||||
|     function on(evt,func) { |  | ||||||
|         eventHandlers[evt] = eventHandlers[evt]||[]; |  | ||||||
|         eventHandlers[evt].push(func); |  | ||||||
|     } |  | ||||||
|     function off(evt,func) { |  | ||||||
|         const handler = eventHandlers[evt]; |  | ||||||
|         if (handler) { |  | ||||||
|             for (let i=0;i<handler.length;i++) { |  | ||||||
|                 if (handler[i] === func) { |  | ||||||
|                     handler.splice(i,1); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     function emit() { |  | ||||||
|         const evt = arguments[0] |  | ||||||
|         const args = Array.prototype.slice.call(arguments,1); |  | ||||||
|         if (eventHandlers[evt]) { |  | ||||||
|             let cpyHandlers = [...eventHandlers[evt]]; |  | ||||||
|             for (let i=0;i<cpyHandlers.length;i++) { |  | ||||||
|                 try { |  | ||||||
|                     cpyHandlers[i].apply(null, args); |  | ||||||
|                 } catch(err) { |  | ||||||
|                     console.warn("RED.comms.emit error: ["+evt+"] "+(err.toString())); |  | ||||||
|                     console.warn(err); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return { |     return { | ||||||
|         connect: connectWS, |         connect: connectWS, | ||||||
|         subscribe: subscribe, |         subscribe: subscribe, | ||||||
|         unsubscribe:unsubscribe, |         unsubscribe:unsubscribe | ||||||
|         on, |  | ||||||
|         off, |  | ||||||
|         send |  | ||||||
|     } |     } | ||||||
| })(); | })(); | ||||||
| @@ -32,23 +32,17 @@ | |||||||
|              } |              } | ||||||
|          } |          } | ||||||
|      } |      } | ||||||
|      function emit() { |      function emit(evt,arg) { | ||||||
|          var evt = arguments[0] |  | ||||||
|          var args = Array.prototype.slice.call(arguments,1); |  | ||||||
|          if (RED.events.DEBUG) { |  | ||||||
|              console.warn(evt,args); |  | ||||||
|          } |  | ||||||
|          if (handlers[evt]) { |          if (handlers[evt]) { | ||||||
|              let cpyHandlers = [...handlers[evt]]; |              for (var i=0;i<handlers[evt].length;i++) { | ||||||
|            |  | ||||||
|              for (var i=0;i<cpyHandlers.length;i++) { |  | ||||||
|                  try { |                  try { | ||||||
|                      cpyHandlers[i].apply(null, args); |                      handlers[evt][i](arg); | ||||||
|                  } catch(err) { |                  } catch(err) { | ||||||
|                      console.warn("RED.events.emit error: ["+evt+"] "+(err.toString())); |                      console.log("RED.events.emit error: ["+evt+"] "+(err.toString())); | ||||||
|                      console.warn(err); |                      console.log(err); | ||||||
|                  } |                  } | ||||||
|              } |              } | ||||||
|  | 
 | ||||||
|          } |          } | ||||||
|      } |      } | ||||||
|      return { |      return { | ||||||
							
								
								
									
										327
									
								
								editor/js/history.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,327 @@ | |||||||
|  | /** | ||||||
|  |  * Copyright JS Foundation and other contributors, http://js.foundation | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  * http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  **/ | ||||||
|  | RED.history = (function() { | ||||||
|  |     var undo_history = []; | ||||||
|  |  | ||||||
|  |     function undoEvent(ev) { | ||||||
|  |         var i; | ||||||
|  |         var len; | ||||||
|  |         var node; | ||||||
|  |         var subflow; | ||||||
|  |         var modifiedTabs = {}; | ||||||
|  |         if (ev) { | ||||||
|  |             if (ev.t == 'multi') { | ||||||
|  |                 len = ev.events.length; | ||||||
|  |                 for (i=len-1;i>=0;i--) { | ||||||
|  |                     undoEvent(ev.events[i]); | ||||||
|  |                 } | ||||||
|  |             } else if (ev.t == 'replace') { | ||||||
|  |                 RED.nodes.clear(); | ||||||
|  |                 var imported = RED.nodes.import(ev.config); | ||||||
|  |                 imported[0].forEach(function(n) { | ||||||
|  |                     if (ev.changed[n.id]) { | ||||||
|  |                         n.changed = true; | ||||||
|  |                     } | ||||||
|  |                 }) | ||||||
|  |  | ||||||
|  |                 RED.nodes.version(ev.rev); | ||||||
|  |             } else if (ev.t == 'add') { | ||||||
|  |                 if (ev.nodes) { | ||||||
|  |                     for (i=0;i<ev.nodes.length;i++) { | ||||||
|  |                         node = RED.nodes.node(ev.nodes[i]); | ||||||
|  |                         if (node.z) { | ||||||
|  |                             modifiedTabs[node.z] = true; | ||||||
|  |                         } | ||||||
|  |                         RED.nodes.remove(ev.nodes[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.links) { | ||||||
|  |                     for (i=0;i<ev.links.length;i++) { | ||||||
|  |                         RED.nodes.removeLink(ev.links[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.workspaces) { | ||||||
|  |                     for (i=0;i<ev.workspaces.length;i++) { | ||||||
|  |                         RED.nodes.removeWorkspace(ev.workspaces[i].id); | ||||||
|  |                         RED.workspaces.remove(ev.workspaces[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.subflows) { | ||||||
|  |                     for (i=0;i<ev.subflows.length;i++) { | ||||||
|  |                         RED.nodes.removeSubflow(ev.subflows[i]); | ||||||
|  |                         RED.workspaces.remove(ev.subflows[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.subflow) { | ||||||
|  |                     if (ev.subflow.instances) { | ||||||
|  |                         ev.subflow.instances.forEach(function(n) { | ||||||
|  |                             var node = RED.nodes.node(n.id); | ||||||
|  |                             if (node) { | ||||||
|  |                                 node.changed = n.changed; | ||||||
|  |                                 node.dirty = true; | ||||||
|  |                             } | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                     if (ev.subflow.hasOwnProperty('changed')) { | ||||||
|  |                         subflow = RED.nodes.subflow(ev.subflow.id); | ||||||
|  |                         if (subflow) { | ||||||
|  |                             subflow.changed = ev.subflow.changed; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.removedLinks) { | ||||||
|  |                     for (i=0;i<ev.removedLinks.length;i++) { | ||||||
|  |                         RED.nodes.addLink(ev.removedLinks[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             } else if (ev.t == "delete") { | ||||||
|  |                 if (ev.workspaces) { | ||||||
|  |                     for (i=0;i<ev.workspaces.length;i++) { | ||||||
|  |                         RED.nodes.addWorkspace(ev.workspaces[i]); | ||||||
|  |                         RED.workspaces.add(ev.workspaces[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.subflow && ev.subflow.subflow) { | ||||||
|  |                     RED.nodes.addSubflow(ev.subflow.subflow); | ||||||
|  |                 } | ||||||
|  |                 if (ev.subflowInputs && ev.subflowInputs.length > 0) { | ||||||
|  |                     subflow = RED.nodes.subflow(ev.subflowInputs[0].z); | ||||||
|  |                     subflow.in.push(ev.subflowInputs[0]); | ||||||
|  |                     subflow.in[0].dirty = true; | ||||||
|  |                 } | ||||||
|  |                 if (ev.subflowOutputs && ev.subflowOutputs.length > 0) { | ||||||
|  |                     subflow = RED.nodes.subflow(ev.subflowOutputs[0].z); | ||||||
|  |                     ev.subflowOutputs.sort(function(a,b) { return a.i-b.i}); | ||||||
|  |                     for (i=0;i<ev.subflowOutputs.length;i++) { | ||||||
|  |                         var output = ev.subflowOutputs[i]; | ||||||
|  |                         subflow.out.splice(output.i,0,output); | ||||||
|  |                         for (var j=output.i+1;j<subflow.out.length;j++) { | ||||||
|  |                             subflow.out[j].i++; | ||||||
|  |                             subflow.out[j].dirty = true; | ||||||
|  |                         } | ||||||
|  |                         RED.nodes.eachLink(function(l) { | ||||||
|  |                             if (l.source.type == "subflow:"+subflow.id) { | ||||||
|  |                                 if (l.sourcePort >= output.i) { | ||||||
|  |                                     l.sourcePort++; | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.subflow && ev.subflow.hasOwnProperty('instances')) { | ||||||
|  |                     ev.subflow.instances.forEach(function(n) { | ||||||
|  |                         var node = RED.nodes.node(n.id); | ||||||
|  |                         if (node) { | ||||||
|  |                             node.changed = n.changed; | ||||||
|  |                             node.dirty = true; | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |                 if (subflow) { | ||||||
|  |                     RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) { | ||||||
|  |                         n.inputs = subflow.in.length; | ||||||
|  |                         n.outputs = subflow.out.length; | ||||||
|  |                         while (n.outputs > n.ports.length) { | ||||||
|  |                             n.ports.push(n.ports.length); | ||||||
|  |                         } | ||||||
|  |                         n.resize = true; | ||||||
|  |                         n.dirty = true; | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |                 if (ev.nodes) { | ||||||
|  |                     for (i=0;i<ev.nodes.length;i++) { | ||||||
|  |                         RED.nodes.add(ev.nodes[i]); | ||||||
|  |                         modifiedTabs[ev.nodes[i].z] = true; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.links) { | ||||||
|  |                     for (i=0;i<ev.links.length;i++) { | ||||||
|  |                         RED.nodes.addLink(ev.links[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.changes) { | ||||||
|  |                     for (i in ev.changes) { | ||||||
|  |                         if (ev.changes.hasOwnProperty(i)) { | ||||||
|  |                             node = RED.nodes.node(i); | ||||||
|  |                             if (node) { | ||||||
|  |                                 for (var d in ev.changes[i]) { | ||||||
|  |                                     if (ev.changes[i].hasOwnProperty(d)) { | ||||||
|  |                                         node[d] = ev.changes[i][d]; | ||||||
|  |                                     } | ||||||
|  |                                 } | ||||||
|  |                                 node.dirty = true; | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                 } | ||||||
|  |             } else if (ev.t == "move") { | ||||||
|  |                 for (i=0;i<ev.nodes.length;i++) { | ||||||
|  |                     var n = ev.nodes[i]; | ||||||
|  |                     n.n.x = n.ox; | ||||||
|  |                     n.n.y = n.oy; | ||||||
|  |                     n.n.dirty = true; | ||||||
|  |                     n.n.moved = n.moved; | ||||||
|  |                 } | ||||||
|  |                 // A move could have caused a link splice | ||||||
|  |                 if (ev.links) { | ||||||
|  |                     for (i=0;i<ev.links.length;i++) { | ||||||
|  |                         RED.nodes.removeLink(ev.links[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.removedLinks) { | ||||||
|  |                     for (i=0;i<ev.removedLinks.length;i++) { | ||||||
|  |                         RED.nodes.addLink(ev.removedLinks[i]); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else if (ev.t == "edit") { | ||||||
|  |                 for (i in ev.changes) { | ||||||
|  |                     if (ev.changes.hasOwnProperty(i)) { | ||||||
|  |                         if (ev.node._def.defaults[i] && ev.node._def.defaults[i].type) { | ||||||
|  |                             // This is a config node property | ||||||
|  |                             var currentConfigNode = RED.nodes.node(ev.node[i]); | ||||||
|  |                             if (currentConfigNode) { | ||||||
|  |                                 currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1); | ||||||
|  |                             } | ||||||
|  |                             var newConfigNode = RED.nodes.node(ev.changes[i]); | ||||||
|  |                             if (newConfigNode) { | ||||||
|  |                                 newConfigNode.users.push(ev.node); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         ev.node[i] = ev.changes[i]; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (ev.subflow) { | ||||||
|  |                     if (ev.subflow.hasOwnProperty('inputCount')) { | ||||||
|  |                         if (ev.node.in.length > ev.subflow.inputCount) { | ||||||
|  |                             ev.node.in.splice(ev.subflow.inputCount); | ||||||
|  |                         } else if (ev.subflow.inputs.length > 0) { | ||||||
|  |                             ev.node.in = ev.node.in.concat(ev.subflow.inputs); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     if (ev.subflow.hasOwnProperty('outputCount')) { | ||||||
|  |                         if (ev.node.out.length > ev.subflow.outputCount) { | ||||||
|  |                             ev.node.out.splice(ev.subflow.outputCount); | ||||||
|  |                         } else if (ev.subflow.outputs.length > 0) { | ||||||
|  |                             ev.node.out = ev.node.out.concat(ev.subflow.outputs); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     if (ev.subflow.hasOwnProperty('instances')) { | ||||||
|  |                         ev.subflow.instances.forEach(function(n) { | ||||||
|  |                             var node = RED.nodes.node(n.id); | ||||||
|  |                             if (node) { | ||||||
|  |                                 node.changed = n.changed; | ||||||
|  |                                 node.dirty = true; | ||||||
|  |                             } | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                     RED.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(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |         //TODO: this function is a placeholder until there is a 'save' event that can be listened to | ||||||
|  |         markAllDirty: function() { | ||||||
|  |             for (var i=0;i<undo_history.length;i++) { | ||||||
|  |                 undo_history[i].dirty = true; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         list: function() { | ||||||
|  |             return undo_history | ||||||
|  |         }, | ||||||
|  |         depth: function() { | ||||||
|  |             return undo_history.length; | ||||||
|  |         }, | ||||||
|  |         push: function(ev) { | ||||||
|  |             undo_history.push(ev); | ||||||
|  |         }, | ||||||
|  |         pop: function() { | ||||||
|  |             var ev = undo_history.pop(); | ||||||
|  |             undoEvent(ev); | ||||||
|  |         }, | ||||||
|  |         peek: function() { | ||||||
|  |             return undo_history[undo_history.length-1]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | })(); | ||||||
							
								
								
									
										86
									
								
								editor/js/i18n.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,86 @@ | |||||||
|  | /** | ||||||
|  |  * Copyright JS Foundation and other contributors, http://js.foundation | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  * http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  **/ | ||||||
|  |  | ||||||
|  | RED.i18n = (function() { | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |         init: function(done) { | ||||||
|  |             i18n.init({ | ||||||
|  |                 resGetPath: 'locales/__ns__?lng=__lng__', | ||||||
|  |                 dynamicLoad: false, | ||||||
|  |                 load:'current', | ||||||
|  |                 ns: { | ||||||
|  |                     namespaces: ["editor","node-red","jsonata","infotips"], | ||||||
|  |                     defaultNs: "editor" | ||||||
|  |                 }, | ||||||
|  |                 fallbackLng: ['en-US'], | ||||||
|  |                 useCookie: false | ||||||
|  |             },function() { | ||||||
|  |                 done(); | ||||||
|  |             }); | ||||||
|  |             RED["_"] = function() { | ||||||
|  |                 return i18n.t.apply(null,arguments); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         }, | ||||||
|  |         loadCatalog: function(namespace,done) { | ||||||
|  |             var languageList = i18n.functions.toLanguages(i18n.detectLanguage()); | ||||||
|  |             var toLoad = languageList.length; | ||||||
|  |             languageList.forEach(function(lang) { | ||||||
|  |                 $.ajax({ | ||||||
|  |                     headers: { | ||||||
|  |                         "Accept":"application/json" | ||||||
|  |                     }, | ||||||
|  |                     cache: false, | ||||||
|  |                     url: 'locales/'+namespace+'?lng='+lang, | ||||||
|  |                     success: function(data) { | ||||||
|  |                         i18n.addResourceBundle(lang,namespace,data); | ||||||
|  |                         toLoad--; | ||||||
|  |                         if (toLoad === 0) { | ||||||
|  |                             done(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |  | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         loadNodeCatalogs: function(done) { | ||||||
|  |             var languageList = i18n.functions.toLanguages(i18n.detectLanguage()); | ||||||
|  |             var toLoad = languageList.length; | ||||||
|  |  | ||||||
|  |             languageList.forEach(function(lang) { | ||||||
|  |                 $.ajax({ | ||||||
|  |                     headers: { | ||||||
|  |                         "Accept":"application/json" | ||||||
|  |                     }, | ||||||
|  |                     cache: false, | ||||||
|  |                     url: 'locales/nodes?lng='+lang, | ||||||
|  |                     success: function(data) { | ||||||
|  |                         var namespaces = Object.keys(data); | ||||||
|  |                         namespaces.forEach(function(ns) { | ||||||
|  |                             i18n.addResourceBundle(lang,ns,data[ns]); | ||||||
|  |                         }); | ||||||
|  |                         toLoad--; | ||||||
|  |                         if (toLoad === 0) { | ||||||
|  |                             done(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | })(); | ||||||
							
								
								
									
										39
									
								
								editor/js/keymap.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | |||||||
|  | { | ||||||
|  |     "*": { | ||||||
|  |         "ctrl-shift-p":"core:manage-palette", | ||||||
|  |         "ctrl-f": "core:search", | ||||||
|  |         "ctrl-=": "core:zoom-in", | ||||||
|  |         "ctrl--": "core:zoom-out", | ||||||
|  |         "ctrl-0": "core:zoom-reset", | ||||||
|  |         "ctrl-enter": "core:confirm-edit-tray", | ||||||
|  |         "ctrl-escape": "core:cancel-edit-tray", | ||||||
|  |         "ctrl-g i": "core:show-info-tab", | ||||||
|  |         "ctrl-g d": "core:show-debug-tab", | ||||||
|  |         "ctrl-g c": "core:show-config-tab", | ||||||
|  |         "ctrl-e": "core:show-export-dialog", | ||||||
|  |         "ctrl-i": "core:show-import-dialog", | ||||||
|  |         "ctrl-space": "core:toggle-sidebar", | ||||||
|  |         "ctrl-,": "core:show-user-settings" | ||||||
|  |     }, | ||||||
|  |     "workspace": { | ||||||
|  |         "backspace": "core:delete-selection", | ||||||
|  |         "delete": "core:delete-selection", | ||||||
|  |         "enter": "core:edit-selected-node", | ||||||
|  |         "ctrl-c": "core:copy-selection-to-internal-clipboard", | ||||||
|  |         "ctrl-x": "core:cut-selection-to-internal-clipboard", | ||||||
|  |         "ctrl-v": "core:paste-from-internal-clipboard", | ||||||
|  |         "ctrl-z": "core:undo", | ||||||
|  |         "ctrl-a": "core:select-all-nodes", | ||||||
|  |         "shift-?": "core:show-help", | ||||||
|  |         "up": "core:move-selection-up", | ||||||
|  |         "right": "core:move-selection-right", | ||||||
|  |         "down": "core:move-selection-down", | ||||||
|  |         "left": "core:move-selection-left", | ||||||
|  |         "shift-up": "core:step-selection-up", | ||||||
|  |         "shift-right": "core:step-selection-right", | ||||||
|  |         "shift-down": "core:step-selection-down", | ||||||
|  |         "shift-left": "core:step-selection-left", | ||||||
|  |         "ctrl-shift-j": "core:show-previous-tab", | ||||||
|  |         "ctrl-shift-k": "core:show-next-tab" | ||||||
|  |      } | ||||||
|  | } | ||||||
							
								
								
									
										277
									
								
								editor/js/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,277 @@ | |||||||
|  | /** | ||||||
|  |  * Copyright JS Foundation and other contributors, http://js.foundation | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  * http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  **/ | ||||||
|  | (function() { | ||||||
|  |  | ||||||
|  |     function loadNodeList() { | ||||||
|  |         $.ajax({ | ||||||
|  |             headers: { | ||||||
|  |                 "Accept":"application/json" | ||||||
|  |             }, | ||||||
|  |             cache: false, | ||||||
|  |             url: 'nodes', | ||||||
|  |             success: function(data) { | ||||||
|  |                 RED.nodes.setNodeList(data); | ||||||
|  |                 RED.i18n.loadNodeCatalogs(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)); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 var persistentNotifications = {}; | ||||||
|  |                 RED.comms.subscribe("notification/#",function(topic,msg) { | ||||||
|  |                     var parts = topic.split("/"); | ||||||
|  |                     var notificationId = parts[1]; | ||||||
|  |                     if (notificationId === "runtime-deploy") { | ||||||
|  |                         // handled in ui/deploy.js | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|  |                     if (notificationId === "node") { | ||||||
|  |                         // handled below | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|  |                     if (msg.text) { | ||||||
|  |                         var text = RED._(msg.text,{default:msg.text}); | ||||||
|  |                         if (!persistentNotifications.hasOwnProperty(notificationId)) { | ||||||
|  |                             persistentNotifications[notificationId] = RED.notify(text,msg.type,msg.timeout === undefined,msg.timeout); | ||||||
|  |                         } else { | ||||||
|  |                             persistentNotifications[notificationId].update(text,msg.timeout); | ||||||
|  |                         } | ||||||
|  |                     } else if (persistentNotifications.hasOwnProperty(notificationId)) { | ||||||
|  |                         persistentNotifications[notificationId].close(); | ||||||
|  |                         delete persistentNotifications[notificationId]; | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |                 RED.comms.subscribe("status/#",function(topic,msg) { | ||||||
|  |                     var parts = topic.split("/"); | ||||||
|  |                     var node = RED.nodes.node(parts[1]); | ||||||
|  |                     if (node) { | ||||||
|  |                         if (msg.hasOwnProperty("text")) { | ||||||
|  |                             if (msg.text[0] !== ".") { | ||||||
|  |                                 msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()}); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         node.status = msg; | ||||||
|  |                         node.dirty = true; | ||||||
|  |                         RED.view.redraw(); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |                 RED.comms.subscribe("notification/node/#",function(topic,msg) { | ||||||
|  |                     var i,m; | ||||||
|  |                     var typeList; | ||||||
|  |                     var info; | ||||||
|  |                     if (topic == "notification/node/added") { | ||||||
|  |                         var addedTypes = []; | ||||||
|  |                         msg.forEach(function(m) { | ||||||
|  |                             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 == "notification/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 == "notification/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 == "notification/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"); | ||||||
|  |                         } | ||||||
|  |                     } else if (topic == "node/upgraded") { | ||||||
|  |                         RED.notify(RED._("palette.event.nodeUpgraded", {module:msg.module,version:msg.version}),"success"); | ||||||
|  |                         RED.nodes.registry.setModulePendingUpdated(msg.module,msg.version); | ||||||
|  |                     } | ||||||
|  |                     // 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(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function loadEditor() { | ||||||
|  |         var menuOptions = []; | ||||||
|  |         menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[ | ||||||
|  |             // {id:"menu-item-view-show-grid",setting:"view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:"core:toggle-show-grid"}, | ||||||
|  |             // {id:"menu-item-view-snap-grid",setting:"view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:"core:toggle-snap-grid"}, | ||||||
|  |             // {id:"menu-item-status",setting:"node-show-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:"core:toggle-status", selected: true}, | ||||||
|  |             //null, | ||||||
|  |             // {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[ | ||||||
|  |             //     {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}}, | ||||||
|  |             //     {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}}, | ||||||
|  |             //     {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}}, | ||||||
|  |             //     {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}} | ||||||
|  |             // ]}, | ||||||
|  |             // null, | ||||||
|  |             {id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true}, | ||||||
|  |             null | ||||||
|  |         ]}); | ||||||
|  |         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:"core:show-import-dialog"}, | ||||||
|  |             {id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]} | ||||||
|  |         ]}); | ||||||
|  |         menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[ | ||||||
|  |             {id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:"core:show-export-dialog"}, | ||||||
|  |             {id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"} | ||||||
|  |         ]}); | ||||||
|  |         menuOptions.push(null); | ||||||
|  |         menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"}); | ||||||
|  |         menuOptions.push(null); | ||||||
|  |         menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:"core:show-config-tab"}); | ||||||
|  |         menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[ | ||||||
|  |             {id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:"core:add-flow"}, | ||||||
|  |             {id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:"core:edit-flow"}, | ||||||
|  |             {id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:"core:remove-flow"} | ||||||
|  |         ]}); | ||||||
|  |         menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [ | ||||||
|  |             {id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:"core:create-subflow"}, | ||||||
|  |             {id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:"core:convert-to-subflow"}, | ||||||
|  |         ]}); | ||||||
|  |         menuOptions.push(null); | ||||||
|  |         if (RED.settings.theme('palette.editable') !== false) { | ||||||
|  |             menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"}); | ||||||
|  |             menuOptions.push(null); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         menuOptions.push({id:"menu-item-user-settings",label:RED._("menu.label.settings"),onselect:"core:show-user-settings"}); | ||||||
|  |         menuOptions.push(null); | ||||||
|  |  | ||||||
|  |         menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:"core:show-help"}); | ||||||
|  |         menuOptions.push({id:"menu-item-help", | ||||||
|  |             label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")), | ||||||
|  |             href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs") | ||||||
|  |         }); | ||||||
|  |         menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         RED.view.init(); | ||||||
|  |         RED.userSettings.init(); | ||||||
|  |         RED.user.init(); | ||||||
|  |         RED.library.init(); | ||||||
|  |         RED.keyboard.init(); | ||||||
|  |         RED.palette.init(); | ||||||
|  |         if (RED.settings.theme('palette.editable') !== false) { | ||||||
|  |             RED.palette.editor.init(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         RED.sidebar.init(); | ||||||
|  |         RED.subflow.init(); | ||||||
|  |         RED.workspaces.init(); | ||||||
|  |         RED.clipboard.init(); | ||||||
|  |         RED.search.init(); | ||||||
|  |         RED.editor.init(); | ||||||
|  |         RED.diff.init(); | ||||||
|  |  | ||||||
|  |         RED.menu.init({id:"btn-sidemenu",options: menuOptions}); | ||||||
|  |  | ||||||
|  |         RED.deploy.init(RED.settings.theme("deployButton",null)); | ||||||
|  |  | ||||||
|  |         RED.actions.add("core:show-about", showAbout); | ||||||
|  |         RED.nodes.init(); | ||||||
|  |         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); | ||||||
|  |         }) | ||||||
|  |     }); | ||||||
|  | })(); | ||||||
							
								
								
									
										1356
									
								
								editor/js/nodes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -13,5 +13,4 @@ | |||||||
|  * See the License for the specific language governing permissions and |  * See the License for the specific language governing permissions and | ||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  **/ |  **/ | ||||||
| 
 | var RED = {}; | ||||||
|  $header-height: 48px; |  | ||||||
| @@ -18,8 +18,6 @@ | |||||||
| RED.settings = (function () { | RED.settings = (function () { | ||||||
| 
 | 
 | ||||||
|     var loadedSettings = {}; |     var loadedSettings = {}; | ||||||
|     var userSettings = {}; |  | ||||||
|     var pendingSave; |  | ||||||
| 
 | 
 | ||||||
|     var hasLocalStorage = function () { |     var hasLocalStorage = function () { | ||||||
|         try { |         try { | ||||||
| @@ -33,50 +31,27 @@ RED.settings = (function () { | |||||||
|         if (!hasLocalStorage()) { |         if (!hasLocalStorage()) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         if (key.startsWith("auth-tokens")) { |         localStorage.setItem(key, JSON.stringify(value)); | ||||||
|             localStorage.setItem(key+this.authTokensSuffix, JSON.stringify(value)); |  | ||||||
|         } else { |  | ||||||
|             RED.utils.setMessageProperty(userSettings,key,value); |  | ||||||
|             saveUserSettings(); |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * If the key is not set in the localStorage it returns <i>undefined</i> |      * If the key is not set in the localStorage it returns <i>undefined</i> | ||||||
|      * Else return the JSON parsed value |      * Else return the JSON parsed value | ||||||
|      * @param key |      * @param key | ||||||
|      * @param defaultIfUndefined |  | ||||||
|      * @returns {*} |      * @returns {*} | ||||||
|      */ |      */ | ||||||
|     var get = function (key,defaultIfUndefined) { |     var get = function (key) { | ||||||
|         if (!hasLocalStorage()) { |         if (!hasLocalStorage()) { | ||||||
|             return undefined; |             return undefined; | ||||||
|         } |         } | ||||||
|         if (key.startsWith("auth-tokens")) { |         return JSON.parse(localStorage.getItem(key)); | ||||||
|             return JSON.parse(localStorage.getItem(key+this.authTokensSuffix)); |  | ||||||
|         } else { |  | ||||||
|             var v; |  | ||||||
|             try { v = RED.utils.getMessageProperty(userSettings,key); } catch(err) {} |  | ||||||
|             if (v === undefined) { |  | ||||||
|                 try { v = RED.utils.getMessageProperty(RED.settings,key); } catch(err) {} |  | ||||||
|             } |  | ||||||
|             if (v === undefined) { |  | ||||||
|                 v = defaultIfUndefined; |  | ||||||
|             } |  | ||||||
|             return v; |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     var remove = function (key) { |     var remove = function (key) { | ||||||
|         if (!hasLocalStorage()) { |         if (!hasLocalStorage()) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         if (key.startsWith("auth-tokens")) { |         localStorage.removeItem(key); | ||||||
|             localStorage.removeItem(key+this.authTokensSuffix); |  | ||||||
|         } else { |  | ||||||
|             delete userSettings[key]; |  | ||||||
|             saveUserSettings(); |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     var setProperties = function(data) { |     var setProperties = function(data) { | ||||||
| @@ -93,28 +68,18 @@ RED.settings = (function () { | |||||||
|         loadedSettings = data; |         loadedSettings = data; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     var setUserSettings = function(data) { |     var init = function (done) { | ||||||
|         userSettings = data; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     var init = function (options, done) { |  | ||||||
|         var accessTokenMatch = /[?&]access_token=(.*?)(?:$|&)/.exec(window.location.search); |         var accessTokenMatch = /[?&]access_token=(.*?)(?:$|&)/.exec(window.location.search); | ||||||
|         var path=window.location.pathname.slice(0,-1); |  | ||||||
|         RED.settings.authTokensSuffix=path.replace(/\//g, '-'); |  | ||||||
|         if (accessTokenMatch) { |         if (accessTokenMatch) { | ||||||
|             var accessToken = accessTokenMatch[1]; |             var accessToken = accessTokenMatch[1]; | ||||||
|             RED.settings.set("auth-tokens",{access_token: accessToken}); |             RED.settings.set("auth-tokens",{access_token: accessToken}); | ||||||
|             window.location.search = ""; |             window.location.search = ""; | ||||||
|         } |         } | ||||||
|         RED.settings.apiRootUrl = options.apiRootUrl; |  | ||||||
| 
 | 
 | ||||||
|         $.ajaxSetup({ |         $.ajaxSetup({ | ||||||
|             beforeSend: function(jqXHR,settings) { |             beforeSend: function(jqXHR,settings) { | ||||||
|                 // Only attach auth header for requests to relative paths
 |                 // Only attach auth header for requests to relative paths
 | ||||||
|                 if (!/^\s*(https?:|\/|\.)/.test(settings.url)) { |                 if (!/^\s*(https?:|\/|\.)/.test(settings.url)) { | ||||||
|                     if (options.apiRootUrl) { |  | ||||||
|                         settings.url = options.apiRootUrl+settings.url; |  | ||||||
|                     } |  | ||||||
|                     var auth_tokens = RED.settings.get("auth-tokens"); |                     var auth_tokens = RED.settings.get("auth-tokens"); | ||||||
|                     if (auth_tokens) { |                     if (auth_tokens) { | ||||||
|                         jqXHR.setRequestHeader("Authorization","Bearer "+auth_tokens.access_token); |                         jqXHR.setRequestHeader("Authorization","Bearer "+auth_tokens.access_token); | ||||||
| @@ -127,7 +92,7 @@ RED.settings = (function () { | |||||||
|         load(done); |         load(done); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     var refreshSettings = function(done) { |     var load = function(done) { | ||||||
|         $.ajax({ |         $.ajax({ | ||||||
|             headers: { |             headers: { | ||||||
|                 "Accept": "application/json" |                 "Accept": "application/json" | ||||||
| @@ -137,79 +102,25 @@ RED.settings = (function () { | |||||||
|             url: 'settings', |             url: 'settings', | ||||||
|             success: function (data) { |             success: function (data) { | ||||||
|                 setProperties(data); |                 setProperties(data); | ||||||
|                 done(null, 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) { |             error: function(jqXHR,textStatus,errorThrown) { | ||||||
|                 if (jqXHR.status === 401) { |                 if (jqXHR.status === 401) { | ||||||
|                     if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) { |                     if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) { | ||||||
|                         window.location.search = ""; |                         window.location.search = ""; | ||||||
|                     } |                     } | ||||||
|                     RED.user.login(function() { refreshSettings(done); }); |                     RED.user.login(function() { load(done); }); | ||||||
|                 } else { |                 } else { | ||||||
|                     console.log("Unexpected error loading settings:",jqXHR.status,textStatus); |                     console.log("Unexpected error:",jqXHR.status,textStatus); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|     } |  | ||||||
|     var load = function(done) { |  | ||||||
|         refreshSettings(function(err, data) { |  | ||||||
|             if (!err) { |  | ||||||
|                 if (!RED.settings.user || RED.settings.user.anonymous) { |  | ||||||
|                     RED.settings.remove("auth-tokens"); |  | ||||||
|                 } |  | ||||||
|                 console.log("Node-RED: " + data.version); |  | ||||||
|                 console.groupCollapsed("Versions"); |  | ||||||
|                 console.log("jQuery",$().jquery) |  | ||||||
|                 console.log("jQuery UI",$.ui.version); |  | ||||||
|                 if(window.ace) { console.log("ACE",ace.version); } |  | ||||||
|                 if(window.monaco) { console.log("MONACO",monaco.version || "unknown"); } |  | ||||||
|                 console.log("D3",d3.version); |  | ||||||
|                 console.groupEnd(); |  | ||||||
|                 loadUserSettings(done); |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     function loadUserSettings(done) { |  | ||||||
|         $.ajax({ |  | ||||||
|             headers: { |  | ||||||
|                 "Accept": "application/json" |  | ||||||
|             }, |  | ||||||
|             dataType: "json", |  | ||||||
|             cache: false, |  | ||||||
|             url: 'settings/user', |  | ||||||
|             success: function (data) { |  | ||||||
|                 setUserSettings(data); |  | ||||||
|                 done(); |  | ||||||
|             }, |  | ||||||
|             error: function(jqXHR,textStatus,errorThrown) { |  | ||||||
|                 console.log("Unexpected error loading user settings:",jqXHR.status,textStatus); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     function saveUserSettings() { |  | ||||||
|         if (RED.user.hasPermission("settings.write")) { |  | ||||||
|             if (pendingSave) { |  | ||||||
|                 clearTimeout(pendingSave); |  | ||||||
|             } |  | ||||||
|             pendingSave = setTimeout(function() { |  | ||||||
|                 pendingSave = null; |  | ||||||
|                 $.ajax({ |  | ||||||
|                     method: 'POST', |  | ||||||
|                     contentType: 'application/json', |  | ||||||
|                     url: 'settings/user', |  | ||||||
|                     data: JSON.stringify(userSettings), |  | ||||||
|                     success: function (data) { |  | ||||||
|                     }, |  | ||||||
|                     error: function(jqXHR,textStatus,errorThrown) { |  | ||||||
|                         console.log("Unexpected error saving user settings:",jqXHR.status,textStatus); |  | ||||||
|                     } |  | ||||||
|                 }); |  | ||||||
|             },300); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     function theme(property,defaultValue) { |     function theme(property,defaultValue) { | ||||||
|         if (!RED.settings.editorTheme) { |         if (!RED.settings.editorTheme) { | ||||||
|             return defaultValue; |             return defaultValue; | ||||||
| @@ -228,28 +139,14 @@ RED.settings = (function () { | |||||||
|             return defaultValue; |             return defaultValue; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     function getLocal(key) { |  | ||||||
|         return localStorage.getItem(key) |  | ||||||
|     } |  | ||||||
|     function setLocal(key, value) { |  | ||||||
|         localStorage.setItem(key, value); |  | ||||||
|     } |  | ||||||
|     function removeLocal(key) { |  | ||||||
|         localStorage.removeItem(key) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
|         init: init, |         init: init, | ||||||
|         load: load, |         load: load, | ||||||
|         loadUserSettings: loadUserSettings, |  | ||||||
|         refreshSettings: refreshSettings, |  | ||||||
|         set: set, |         set: set, | ||||||
|         get: get, |         get: get, | ||||||
|         remove: remove, |         remove: remove, | ||||||
|         theme: theme, |         theme: theme | ||||||
|         setLocal: setLocal, |  | ||||||
|         getLocal: getLocal, |  | ||||||
|         removeLocal: removeLocal |  | ||||||
|     } |     } | ||||||
| })(); | }) | ||||||
|  | (); | ||||||
| @@ -16,6 +16,8 @@ | |||||||
| RED.text = {}; | RED.text = {}; | ||||||
| RED.text.bidi = (function() { | RED.text.bidi = (function() { | ||||||
|     var textDir = "";     |     var textDir = "";     | ||||||
|  |     var textDirPref = "auto"; | ||||||
|  |     var bidiEnabled = false; | ||||||
|     var LRE = "\u202A", |     var LRE = "\u202A", | ||||||
|         RLE = "\u202B", |         RLE = "\u202B", | ||||||
|         PDF = "\u202C"; |         PDF = "\u202C"; | ||||||
| @@ -97,21 +99,21 @@ 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 |      * workspace or sidebar div | ||||||
|      */ |      */ | ||||||
|     function enforceTextDirectionOnPage() { |     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())); |             $(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())); |             $(this).attr("dir", resolveBaseTextDir($(this).text())); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Sets the text direction preference |      * Sets the text direction | ||||||
|      * @param dir - the text direction preference |      * @param dir - the actual text direction | ||||||
|      */ |      */ | ||||||
|     function setTextDirection(dir) { |     function setTextDirection(dir) { | ||||||
|         textDir = dir; |         textDir = dir; | ||||||
| @@ -121,8 +123,43 @@ RED.text.bidi = (function() { | |||||||
|         enforceTextDirectionOnPage(); |         enforceTextDirectionOnPage(); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     /** | ||||||
|  |      * Gets the bidi enabled preference | ||||||
|  |      */ | ||||||
|  |     function getBidiEnabled() { | ||||||
|  |         return bidiEnabled; | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     /** | ||||||
|  |      * Sets the bidi enabled preference | ||||||
|  |      * @param state - the bidi enabled preference | ||||||
|  |      */ | ||||||
|  |     function setBidiEnabled(state) { | ||||||
|  |         bidiEnabled = state; | ||||||
|  |         setTextDirection((state ? textDirPref : "")); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Gets the text direction preference | ||||||
|  |      */ | ||||||
|  |     function getTextDirPref() {         | ||||||
|  |         return textDirPref; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Sets the text direction preference | ||||||
|  |      * @param dirPref - text direction preference | ||||||
|  |      */ | ||||||
|  |     function setTextDirPref(dirPref) { | ||||||
|  |         textDirPref = dirPref; | ||||||
|  |         setTextDirection(textDirPref); | ||||||
|  |     } | ||||||
|  |     | ||||||
|     return { |     return { | ||||||
|         setTextDirection: setTextDirection, |         setBidiEnabled: setBidiEnabled, | ||||||
|  |         setTextDirPref: setTextDirPref, | ||||||
|  |         getBidiEnabled: getBidiEnabled, | ||||||
|  |         getTextDirPref: getTextDirPref, | ||||||
|         enforceTextDirectionWithUCC: enforceTextDirectionWithUCC, |         enforceTextDirectionWithUCC: enforceTextDirectionWithUCC, | ||||||
|         resolveBaseTextDir: resolveBaseTextDir, |         resolveBaseTextDir: resolveBaseTextDir, | ||||||
|         prepareInput: prepareInput |         prepareInput: prepareInput | ||||||
| @@ -1304,7 +1304,7 @@ RED.text.format = (function() { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
|         /*! |         /** | ||||||
|         * Returns the HTML representation of a given structured text |         * Returns the HTML representation of a given structured text | ||||||
|         * @param text - the structured text |         * @param text - the structured text | ||||||
|         * @param type - could be one of filepath, url, email |         * @param type - could be one of filepath, url, email | ||||||
| @@ -1315,7 +1315,7 @@ RED.text.format = (function() { | |||||||
|         getHtml: function (text, type, args, isRtl, locale) { |         getHtml: function (text, type, args, isRtl, locale) { | ||||||
|             return getHandler(type).format(text, args, isRtl, true, locale); |             return getHandler(type).format(text, args, isRtl, true, locale); | ||||||
|         }, |         }, | ||||||
|         /*! |         /** | ||||||
|         * Handle Structured text correct display for a given HTML element. |         * Handle Structured text correct display for a given HTML element. | ||||||
|         * @param element - the element  : should be of type div contenteditable=true |         * @param element - the element  : should be of type div contenteditable=true | ||||||
|         * @param type - could be one of filepath, url, email |         * @param type - could be one of filepath, url, email | ||||||
							
								
								
									
										35
									
								
								editor/js/ui/actions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | |||||||
|  | RED.actions = (function() { | ||||||
|  |     var actions = { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function addAction(name,handler) { | ||||||
|  |         actions[name] = handler; | ||||||
|  |     } | ||||||
|  |     function removeAction(name) { | ||||||
|  |         delete actions[name]; | ||||||
|  |     } | ||||||
|  |     function getAction(name) { | ||||||
|  |         return actions[name]; | ||||||
|  |     } | ||||||
|  |     function invokeAction(name) { | ||||||
|  |         if (actions.hasOwnProperty(name)) { | ||||||
|  |             actions[name](); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     function listActions() { | ||||||
|  |         var result = []; | ||||||
|  |         Object.keys(actions).forEach(function(action) { | ||||||
|  |             var shortcut = RED.keyboard.getShortcut(action); | ||||||
|  |             result.push({id:action,scope:shortcut?shortcut.scope:undefined,key:shortcut?shortcut.key:undefined,user:shortcut?shortcut.user:undefined}) | ||||||
|  |         }) | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |     return { | ||||||
|  |         add: addAction, | ||||||
|  |         remove: removeAction, | ||||||
|  |         get: getAction, | ||||||
|  |         invoke: invokeAction, | ||||||
|  |         list: listActions | ||||||
|  |     } | ||||||
|  | })(); | ||||||