Compare commits
	
		
			1 Commits
		
	
	
		
			4396-fix-g
			...
			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@v3
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
            node-version: '16'
 | 
					 | 
				
			||||||
      - run: node ./node-red/.github/scripts/update-node-red-docker.js
 | 
					 | 
				
			||||||
      - name: Create Docker Pull Request
 | 
					 | 
				
			||||||
        uses: peter-evans/create-pull-request@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          token: ${{ secrets.NR_REPO_TOKEN }}
 | 
					 | 
				
			||||||
          committer: GitHub <noreply@github.com>
 | 
					 | 
				
			||||||
          author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
 | 
					 | 
				
			||||||
          path: 'node-red-docker'
 | 
					 | 
				
			||||||
          commit-message: 'Bump to ${{ env.newVersion }}'
 | 
					 | 
				
			||||||
          title: '🚀 Update to Node-RED ${{ env.newVersion }} release'
 | 
					 | 
				
			||||||
          body: |
 | 
					 | 
				
			||||||
            Updates the Node-RED Docker repo for the ${{ env.newVersion }} release.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Once this is merged, you will need to create a new release with the tag `v${{ env.newVersion }}`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary
 | 
					 | 
				
			||||||
      - run: node ./node-red/.github/scripts/update-node-red-website.js
 | 
					 | 
				
			||||||
      - name: Create Website Pull Request
 | 
					 | 
				
			||||||
        uses: peter-evans/create-pull-request@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          token: ${{ secrets.NR_REPO_TOKEN }}
 | 
					 | 
				
			||||||
          committer: GitHub <noreply@github.com>
 | 
					 | 
				
			||||||
          author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
 | 
					 | 
				
			||||||
          path: 'node-red.github.io'
 | 
					 | 
				
			||||||
          commit-message: 'Bump to ${{ env.newVersion }}'
 | 
					 | 
				
			||||||
          title: '🚀 Update to Node-RED ${{ env.newVersion }} release'
 | 
					 | 
				
			||||||
          body: |
 | 
					 | 
				
			||||||
            Updates the Node-RED Website repo for the ${{ env.newVersion }} release.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary
 | 
					 | 
				
			||||||
							
								
								
									
										36
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -1,36 +0,0 @@
 | 
				
			|||||||
name: Run tests
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
on:
 | 
					 | 
				
			||||||
  push:
 | 
					 | 
				
			||||||
    branches: [ master, dev ]
 | 
					 | 
				
			||||||
  pull_request:
 | 
					 | 
				
			||||||
    branches: [ master, dev ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
permissions:
 | 
					 | 
				
			||||||
  contents: read
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jobs:
 | 
					 | 
				
			||||||
  build:
 | 
					 | 
				
			||||||
    permissions:
 | 
					 | 
				
			||||||
      checks: write  # for coverallsapp/github-action to create new checks
 | 
					 | 
				
			||||||
      contents: read  # for actions/checkout to fetch code
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
        node-version: [16, 18, 20]
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
    - uses: actions/checkout@v4
 | 
					 | 
				
			||||||
    - name: Use Node.js ${{ matrix.node-version }}
 | 
					 | 
				
			||||||
      uses: actions/setup-node@v3
 | 
					 | 
				
			||||||
      with:
 | 
					 | 
				
			||||||
        node-version: ${{ matrix.node-version }}
 | 
					 | 
				
			||||||
    - name: Install Dependencies
 | 
					 | 
				
			||||||
      run: npm install
 | 
					 | 
				
			||||||
    - name: Run tests
 | 
					 | 
				
			||||||
      run: |
 | 
					 | 
				
			||||||
        npm run test
 | 
					 | 
				
			||||||
    # - name: Publish to coveralls.io
 | 
					 | 
				
			||||||
    #   if: ${{ matrix.node-version == 16 }}
 | 
					 | 
				
			||||||
    #   uses: coverallsapp/github-action@v1.1.2
 | 
					 | 
				
			||||||
    #   with:
 | 
					 | 
				
			||||||
    #     github-token: ${{ github.token }}
 | 
					 | 
				
			||||||
							
								
								
									
										11
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
/Gruntfile.js
 | 
					/Gruntfile.js
 | 
				
			||||||
/.git/*
 | 
					/.git/*
 | 
				
			||||||
 | 
					/lib/*
 | 
				
			||||||
*.backup
 | 
					*.backup
 | 
				
			||||||
/public/*
 | 
					/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
 | 
					 | 
				
			||||||
							
								
								
									
										1367
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										577
									
								
								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,110 +109,74 @@ 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/text/bidi.js",
 | 
					                    "editor/js/history.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/text/format.js",
 | 
					                    "editor/js/validators.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/state.js",
 | 
					                    "editor/js/ui/utils.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/plugins.js",
 | 
					                    "editor/js/ui/common/editableList.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/nodes.js",
 | 
					                    "editor/js/ui/common/checkboxSet.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
 | 
					                    "editor/js/ui/common/menu.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/history.js",
 | 
					                    "editor/js/ui/common/panels.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/validators.js",
 | 
					                    "editor/js/ui/common/popover.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
 | 
					                    "editor/js/ui/common/searchBox.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
 | 
					                    "editor/js/ui/common/tabs.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
 | 
					                    "editor/js/ui/common/stack.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",
 | 
					                    "editor/js/ui/common/typedInput.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js",
 | 
					                    "editor/js/ui/actions.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js",
 | 
					                    "editor/js/ui/deploy.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js",
 | 
					                    "editor/js/ui/diff.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js",
 | 
					                    "editor/js/ui/keyboard.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js",
 | 
					                    "editor/js/ui/workspaces.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
 | 
					                    "editor/js/ui/view.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
 | 
					                    "editor/js/ui/sidebar.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
 | 
					                    "editor/js/ui/palette.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js",
 | 
					                    "editor/js/ui/tab-info.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
 | 
					                    "editor/js/ui/tab-config.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
 | 
					                    "editor/js/ui/palette-editor.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js",
 | 
					                    "editor/js/ui/editor.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
 | 
					                    "editor/js/ui/tray.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
 | 
					                    "editor/js/ui/clipboard.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js",
 | 
					                    "editor/js/ui/library.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
 | 
					                    "editor/js/ui/notifications.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js",
 | 
					                    "editor/js/ui/search.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
 | 
					                    "editor/js/ui/typeSearch.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js",
 | 
					                    "editor/js/ui/subflow.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
 | 
					                    "editor/js/ui/userSettings.js",
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js",
 | 
					                    "editor/js/ui/touch/radialMenu.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"
 | 
					 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
 | 
					                dest: "public/red/red.js"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            vendor: {
 | 
					            vendor: {
 | 
				
			||||||
                files: {
 | 
					                files: {
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
 | 
					                    "public/vendor/vendor.js": [
 | 
				
			||||||
                        "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
 | 
					                        "editor/vendor/jquery/js/jquery-1.11.3.min.js",
 | 
				
			||||||
                        "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js",
 | 
					                        "editor/vendor/bootstrap/js/bootstrap.min.js",
 | 
				
			||||||
                        "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.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.touch-punch.min.js",
 | 
					                        "editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
 | 
				
			||||||
                        "node_modules/marked/marked.min.js",
 | 
					                        "editor/vendor/marked/marked.min.js",
 | 
				
			||||||
                        "node_modules/dompurify/dist/purify.min.js",
 | 
					                        "editor/vendor/d3/d3.v3.min.js",
 | 
				
			||||||
                        "packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
 | 
					                        "editor/vendor/i18next/i18next.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"
 | 
					 | 
				
			||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                    // "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
 | 
					                    "public/vendor/vendor.css": [
 | 
				
			||||||
                    //     // TODO: resolve relative resource paths in
 | 
					                        // TODO: resolve relative resource paths in
 | 
				
			||||||
                    //     //       bootstrap/FA/jquery
 | 
					                        //       bootstrap/FA/jquery
 | 
				
			||||||
                    // ],
 | 
					 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
 | 
					 | 
				
			||||||
                        "node_modules/jsonata/jsonata-es5.min.js",
 | 
					 | 
				
			||||||
                        "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
 | 
					 | 
				
			||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                    "packages/node_modules/@node-red/editor-client/public/vendor/mermaid/mermaid.min.js": [
 | 
					                    "public/vendor/jsonata/jsonata.min.js": [
 | 
				
			||||||
                        "node_modules/mermaid/dist/mermaid.min.js"
 | 
					                        "node_modules/jsonata/jsonata-es5.min.js",
 | 
				
			||||||
 | 
					                        "editor/vendor/jsonata/formatter.js"
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    "public/vendor/ace/worker-jsonata.js": [
 | 
				
			||||||
 | 
					                        "node_modules/jsonata/jsonata-es5.min.js",
 | 
				
			||||||
 | 
					                        "editor/vendor/jsonata/worker-jsonata.js"
 | 
				
			||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -244,62 +184,63 @@ module.exports = function(grunt) {
 | 
				
			|||||||
        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: {
 | 
				
			||||||
@@ -311,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'
 | 
				
			||||||
@@ -352,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'
 | 
					 | 
				
			||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -377,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: {
 | 
				
			||||||
@@ -453,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'
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -555,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"+
 | 
				
			||||||
@@ -627,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 () {
 | 
				
			||||||
@@ -667,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  | 
@@ -28,24 +28,14 @@ RED.comms = (function() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    function connectWS() {
 | 
					    function connectWS() {
 | 
				
			||||||
        active = true;
 | 
					        active = true;
 | 
				
			||||||
        var wspath;
 | 
					        var path = location.hostname;
 | 
				
			||||||
 | 
					        var port = location.port;
 | 
				
			||||||
        if (RED.settings.apiRootUrl) {
 | 
					        if (port.length !== 0) {
 | 
				
			||||||
            var m = /^(https?):\/\/(.*)$/.exec(RED.settings.apiRootUrl);
 | 
					            path = path+":"+port;
 | 
				
			||||||
            if (m) {
 | 
					 | 
				
			||||||
                console.log(m);
 | 
					 | 
				
			||||||
                wspath = "ws"+(m[1]==="https"?"s":"")+"://"+m[2]+"comms";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            var path = location.hostname;
 | 
					 | 
				
			||||||
            var port = location.port;
 | 
					 | 
				
			||||||
            if (port.length !== 0) {
 | 
					 | 
				
			||||||
                path = path+":"+port;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            path = path+document.location.pathname;
 | 
					 | 
				
			||||||
            path = path+(path.slice(-1) == "/"?"":"/")+"comms";
 | 
					 | 
				
			||||||
            wspath = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        path = path+document.location.pathname;
 | 
				
			||||||
 | 
					        path = path+(path.slice(-1) == "/"?"":"/")+"comms";
 | 
				
			||||||
 | 
					        path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var auth_tokens = RED.settings.get("auth-tokens");
 | 
					        var auth_tokens = RED.settings.get("auth-tokens");
 | 
				
			||||||
        pendingAuth = (auth_tokens!=null);
 | 
					        pendingAuth = (auth_tokens!=null);
 | 
				
			||||||
@@ -58,7 +48,7 @@ RED.comms = (function() {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ws = new WebSocket(wspath);
 | 
					        ws = new WebSocket(path);
 | 
				
			||||||
        ws.onopen = function() {
 | 
					        ws.onopen = function() {
 | 
				
			||||||
            reconnectAttempts = 0;
 | 
					            reconnectAttempts = 0;
 | 
				
			||||||
            if (errornotification) {
 | 
					            if (errornotification) {
 | 
				
			||||||
@@ -74,41 +64,27 @@ 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 (msg.auth === "fail") {
 | 
				
			||||||
                    } else if (message.auth === "fail") {
 | 
					                    // anything else is an error...
 | 
				
			||||||
                        // anything else is an error...
 | 
					 | 
				
			||||||
                        active = false;
 | 
					 | 
				
			||||||
                        RED.user.login({updateMenu:true},function() {
 | 
					 | 
				
			||||||
                            connectWS();
 | 
					 | 
				
			||||||
                        })
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } else if (message.auth === "fail") {
 | 
					 | 
				
			||||||
                    // Our current session has expired
 | 
					 | 
				
			||||||
                    active = false;
 | 
					                    active = false;
 | 
				
			||||||
                    RED.user.login({updateMenu:true},function() {
 | 
					                    RED.user.login({updateMenu:true},function() {
 | 
				
			||||||
                        connectWS();
 | 
					                        connectWS();
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else if (msg.topic) {
 | 
				
			||||||
                // Otherwise, 'message' is an array of actual comms messages
 | 
					                for (var t in subscriptions) {
 | 
				
			||||||
                for (var m = 0; m < message.length; m++) {
 | 
					                    if (subscriptions.hasOwnProperty(t)) {
 | 
				
			||||||
                    var msg = message[m];
 | 
					                        var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
 | 
				
			||||||
                    if (msg.topic) {
 | 
					                        if (re.test(msg.topic)) {
 | 
				
			||||||
                        for (var t in subscriptions) {
 | 
					                            var subscribers = subscriptions[t];
 | 
				
			||||||
                            if (subscriptions.hasOwnProperty(t)) {
 | 
					                            if (subscribers) {
 | 
				
			||||||
                                var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
 | 
					                                for (var i=0;i<subscribers.length;i++) {
 | 
				
			||||||
                                if (re.test(msg.topic)) {
 | 
					                                    subscribers[i](msg.topic,msg.data);
 | 
				
			||||||
                                    var subscribers = subscriptions[t];
 | 
					 | 
				
			||||||
                                    if (subscribers) {
 | 
					 | 
				
			||||||
                                        for (var i=0;i<subscribers.length;i++) {
 | 
					 | 
				
			||||||
                                            subscribers[i](msg.topic,msg.data);
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@@ -142,10 +118,10 @@ RED.comms = (function() {
 | 
				
			|||||||
                        connectWS();
 | 
					                        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();
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
@@ -32,19 +32,14 @@
 | 
				
			|||||||
             }
 | 
					             }
 | 
				
			||||||
         }
 | 
					         }
 | 
				
			||||||
     }
 | 
					     }
 | 
				
			||||||
     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]) {
 | 
				
			||||||
             for (var i=0;i<handlers[evt].length;i++) {
 | 
					             for (var i=0;i<handlers[evt].length;i++) {
 | 
				
			||||||
                 try {
 | 
					                 try {
 | 
				
			||||||
                     handlers[evt][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);
 | 
				
			||||||
                 }
 | 
					                 }
 | 
				
			||||||
             }
 | 
					             }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										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 = {};
 | 
				
			||||||
module.exports = false
 | 
					 | 
				
			||||||
@@ -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
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
							
								
								
									
										380
									
								
								editor/js/ui/clipboard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,380 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright JS Foundation and other contributors, http://js.foundation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RED.clipboard = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var dialog;
 | 
				
			||||||
 | 
					    var dialogContainer;
 | 
				
			||||||
 | 
					    var exportNodesDialog;
 | 
				
			||||||
 | 
					    var importNodesDialog;
 | 
				
			||||||
 | 
					    var disabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function setupDialogs() {
 | 
				
			||||||
 | 
					        dialog = $('<div id="clipboard-dialog" class="hide node-red-dialog"><form class="dialog-form form-horizontal"></form></div>')
 | 
				
			||||||
 | 
					            .appendTo("body")
 | 
				
			||||||
 | 
					            .dialog({
 | 
				
			||||||
 | 
					                modal: true,
 | 
				
			||||||
 | 
					                autoOpen: false,
 | 
				
			||||||
 | 
					                width: 500,
 | 
				
			||||||
 | 
					                resizable: false,
 | 
				
			||||||
 | 
					                buttons: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "clipboard-dialog-cancel",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.cancel"),
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            $( this ).dialog( "close" );
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "clipboard-dialog-close",
 | 
				
			||||||
 | 
					                        class: "primary",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.close"),
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            $( this ).dialog( "close" );
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "clipboard-dialog-copy",
 | 
				
			||||||
 | 
					                        class: "primary",
 | 
				
			||||||
 | 
					                        text: RED._("clipboard.export.copy"),
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            $("#clipboard-export").select();
 | 
				
			||||||
 | 
					                            document.execCommand("copy");
 | 
				
			||||||
 | 
					                            document.getSelection().removeAllRanges();
 | 
				
			||||||
 | 
					                            RED.notify(RED._("clipboard.nodesExported"));
 | 
				
			||||||
 | 
					                            $( this ).dialog( "close" );
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "clipboard-dialog-ok",
 | 
				
			||||||
 | 
					                        class: "primary",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.import"),
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            RED.view.importNodes($("#clipboard-import").val(),$("#import-tab > a.selected").attr('id') === 'import-tab-new');
 | 
				
			||||||
 | 
					                            $( this ).dialog( "close" );
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                open: function(e) {
 | 
				
			||||||
 | 
					                    $(this).parent().find(".ui-dialog-titlebar-close").hide();
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                close: function(e) {
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dialogContainer = dialog.children(".dialog-form");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        exportNodesDialog =
 | 
				
			||||||
 | 
					            '<div class="form-row">'+
 | 
				
			||||||
 | 
					                '<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.export.copy"></label>'+
 | 
				
			||||||
 | 
					                '<span id="export-range-group" class="button-group">'+
 | 
				
			||||||
 | 
					                    '<a id="export-range-selected" class="editor-button toggle" href="#" data-i18n="clipboard.export.selected"></a>'+
 | 
				
			||||||
 | 
					                    '<a id="export-range-flow" class="editor-button toggle" href="#" data-i18n="clipboard.export.current"></a>'+
 | 
				
			||||||
 | 
					                    '<a id="export-range-full" class="editor-button toggle" href="#" data-i18n="clipboard.export.all"></a>'+
 | 
				
			||||||
 | 
					                '</span>'+
 | 
				
			||||||
 | 
					                '</div>'+
 | 
				
			||||||
 | 
					            '<div class="form-row">'+
 | 
				
			||||||
 | 
					                '<textarea readonly style="resize: none; width: 100%; border-radius: 4px;font-family: monospace; font-size: 12px; background:#f3f3f3; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-export" rows="5"></textarea>'+
 | 
				
			||||||
 | 
					            '</div>'+
 | 
				
			||||||
 | 
					            '<div class="form-row" style="text-align: right;">'+
 | 
				
			||||||
 | 
					                '<span id="export-format-group" class="button-group">'+
 | 
				
			||||||
 | 
					                    '<a id="export-format-mini" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+
 | 
				
			||||||
 | 
					                    '<a id="export-format-full" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+
 | 
				
			||||||
 | 
					                '</span>'+
 | 
				
			||||||
 | 
					            '</div>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        importNodesDialog = '<div class="form-row">'+
 | 
				
			||||||
 | 
					            '<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5" placeholder="'+
 | 
				
			||||||
 | 
					            RED._("clipboard.pasteNodes")+
 | 
				
			||||||
 | 
					            '"></textarea>'+
 | 
				
			||||||
 | 
					            '</div>'+
 | 
				
			||||||
 | 
					            '<div class="form-row">'+
 | 
				
			||||||
 | 
					            '<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+
 | 
				
			||||||
 | 
					            '<span id="import-tab" class="button-group">'+
 | 
				
			||||||
 | 
					                '<a id="import-tab-current" class="editor-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+
 | 
				
			||||||
 | 
					                '<a id="import-tab-new" class="editor-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+
 | 
				
			||||||
 | 
					            '</span>'+
 | 
				
			||||||
 | 
					            '</div>';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function validateImport() {
 | 
				
			||||||
 | 
					        var importInput = $("#clipboard-import");
 | 
				
			||||||
 | 
					        var v = importInput.val();
 | 
				
			||||||
 | 
					        v = v.substring(v.indexOf('['),v.lastIndexOf(']')+1);
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            JSON.parse(v);
 | 
				
			||||||
 | 
					            importInput.removeClass("input-error");
 | 
				
			||||||
 | 
					            importInput.val(v);
 | 
				
			||||||
 | 
					            $("#clipboard-dialog-ok").button("enable");
 | 
				
			||||||
 | 
					        } catch(err) {
 | 
				
			||||||
 | 
					            if (v !== "") {
 | 
				
			||||||
 | 
					                importInput.addClass("input-error");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $("#clipboard-dialog-ok").button("disable");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function importNodes() {
 | 
				
			||||||
 | 
					        if (disabled) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        dialogContainer.empty();
 | 
				
			||||||
 | 
					        dialogContainer.append($(importNodesDialog));
 | 
				
			||||||
 | 
					        dialogContainer.i18n();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-ok").show();
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-cancel").show();
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-close").hide();
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-copy").hide();
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-ok").button("disable");
 | 
				
			||||||
 | 
					        $("#clipboard-import").keyup(validateImport);
 | 
				
			||||||
 | 
					        $("#clipboard-import").on('paste',function() { setTimeout(validateImport,10)});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $("#import-tab > a").click(function(evt) {
 | 
				
			||||||
 | 
					            evt.preventDefault();
 | 
				
			||||||
 | 
					            if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $(this).parent().children().removeClass('selected');
 | 
				
			||||||
 | 
					            $(this).addClass('selected');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function exportNodes() {
 | 
				
			||||||
 | 
					        if (disabled) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dialogContainer.empty();
 | 
				
			||||||
 | 
					        dialogContainer.append($(exportNodesDialog));
 | 
				
			||||||
 | 
					        dialogContainer.i18n();
 | 
				
			||||||
 | 
					        var format = RED.settings.flowFilePretty ? "export-format-full" : "export-format-mini";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $("#export-format-group > a").click(function(evt) {
 | 
				
			||||||
 | 
					            evt.preventDefault();
 | 
				
			||||||
 | 
					            if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
 | 
				
			||||||
 | 
					                $("#clipboard-export").focus();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $(this).parent().children().removeClass('selected');
 | 
				
			||||||
 | 
					            $(this).addClass('selected');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var flow = $("#clipboard-export").val();
 | 
				
			||||||
 | 
					            if (flow.length > 0) {
 | 
				
			||||||
 | 
					                var nodes = JSON.parse(flow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                format = $(this).attr('id');
 | 
				
			||||||
 | 
					                if (format === 'export-format-full') {
 | 
				
			||||||
 | 
					                    flow = JSON.stringify(nodes,null,4);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    flow = JSON.stringify(nodes);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                $("#clipboard-export").val(flow);
 | 
				
			||||||
 | 
					                $("#clipboard-export").focus();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $("#export-range-group > a").click(function(evt) {
 | 
				
			||||||
 | 
					            evt.preventDefault();
 | 
				
			||||||
 | 
					            if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
 | 
				
			||||||
 | 
					                $("#clipboard-export").focus();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $(this).parent().children().removeClass('selected');
 | 
				
			||||||
 | 
					            $(this).addClass('selected');
 | 
				
			||||||
 | 
					            var type = $(this).attr('id');
 | 
				
			||||||
 | 
					            var flow = "";
 | 
				
			||||||
 | 
					            var nodes = null;
 | 
				
			||||||
 | 
					            if (type === 'export-range-selected') {
 | 
				
			||||||
 | 
					                var selection = RED.view.selection();
 | 
				
			||||||
 | 
					                // Don't include the subflow meta-port nodes in the exported selection
 | 
				
			||||||
 | 
					                nodes = RED.nodes.createExportableNodeSet(selection.nodes.filter(function(n) { return n.type !== 'subflow'}));
 | 
				
			||||||
 | 
					            } else if (type === 'export-range-flow') {
 | 
				
			||||||
 | 
					                var activeWorkspace = RED.workspaces.active();
 | 
				
			||||||
 | 
					                nodes = RED.nodes.filterNodes({z:activeWorkspace});
 | 
				
			||||||
 | 
					                var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
 | 
				
			||||||
 | 
					                nodes.unshift(parentNode);
 | 
				
			||||||
 | 
					                nodes = RED.nodes.createExportableNodeSet(nodes);
 | 
				
			||||||
 | 
					            } else if (type === 'export-range-full') {
 | 
				
			||||||
 | 
					                nodes = RED.nodes.createCompleteNodeSet(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (nodes !== null) {
 | 
				
			||||||
 | 
					                if (format === "export-format-full") {
 | 
				
			||||||
 | 
					                    flow = JSON.stringify(nodes,null,4);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    flow = JSON.stringify(nodes);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (flow.length > 0) {
 | 
				
			||||||
 | 
					                $("#export-copy").removeClass('disabled');
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $("#export-copy").addClass('disabled');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $("#clipboard-export").val(flow);
 | 
				
			||||||
 | 
					            $("#clipboard-export").focus();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-ok").hide();
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-cancel").hide();
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-copy").hide();
 | 
				
			||||||
 | 
					        $("#clipboard-dialog-close").hide();
 | 
				
			||||||
 | 
					        var selection = RED.view.selection();
 | 
				
			||||||
 | 
					        if (selection.nodes) {
 | 
				
			||||||
 | 
					            $("#export-range-selected").click();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $("#export-range-selected").addClass('disabled').removeClass('selected');
 | 
				
			||||||
 | 
					            $("#export-range-flow").click();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (format === "export-format-full") {
 | 
				
			||||||
 | 
					            $("#export-format-full").click();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $("#export-format-mini").click();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $("#clipboard-export")
 | 
				
			||||||
 | 
					            .focus(function() {
 | 
				
			||||||
 | 
					                var textarea = $(this);
 | 
				
			||||||
 | 
					                textarea.select();
 | 
				
			||||||
 | 
					                textarea.mouseup(function() {
 | 
				
			||||||
 | 
					                    textarea.unbind("mouseup");
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $("#clipboard-export").focus();
 | 
				
			||||||
 | 
					        if (!document.queryCommandSupported("copy")) {
 | 
				
			||||||
 | 
					            $("#clipboard-dialog-cancel").hide();
 | 
				
			||||||
 | 
					            $("#clipboard-dialog-close").show();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $("#clipboard-dialog-cancel").show();
 | 
				
			||||||
 | 
					            $("#clipboard-dialog-copy").show();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function hideDropTarget() {
 | 
				
			||||||
 | 
					        $("#dropTarget").hide();
 | 
				
			||||||
 | 
					        RED.keyboard.remove("escape");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function copyText(value,element,msg) {
 | 
				
			||||||
 | 
					        var truncated = false;
 | 
				
			||||||
 | 
					        if (typeof value !== "string" ) {
 | 
				
			||||||
 | 
					            value = JSON.stringify(value, function(key,value) {
 | 
				
			||||||
 | 
					                if (value !== null && typeof value === 'object') {
 | 
				
			||||||
 | 
					                    if (value.__encoded__ && value.hasOwnProperty('data') && value.hasOwnProperty('length')) {
 | 
				
			||||||
 | 
					                        truncated = value.data.length !== value.length;
 | 
				
			||||||
 | 
					                        return value.data;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return value;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (truncated) {
 | 
				
			||||||
 | 
					            msg += "_truncated";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $("#clipboard-hidden").val(value).select();
 | 
				
			||||||
 | 
					        var result =  document.execCommand("copy");
 | 
				
			||||||
 | 
					        if (result && element) {
 | 
				
			||||||
 | 
					            var popover = RED.popover.create({
 | 
				
			||||||
 | 
					                target: element,
 | 
				
			||||||
 | 
					                direction: 'left',
 | 
				
			||||||
 | 
					                size: 'small',
 | 
				
			||||||
 | 
					                content: RED._(msg)
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            setTimeout(function() {
 | 
				
			||||||
 | 
					                popover.close();
 | 
				
			||||||
 | 
					            },1000);
 | 
				
			||||||
 | 
					            popover.open();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        init: function() {
 | 
				
			||||||
 | 
					            setupDialogs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $('<input type="text" id="clipboard-hidden">').appendTo("body");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            RED.events.on("view:selection-changed",function(selection) {
 | 
				
			||||||
 | 
					                if (!selection.nodes) {
 | 
				
			||||||
 | 
					                    RED.menu.setDisabled("menu-item-export",true);
 | 
				
			||||||
 | 
					                    RED.menu.setDisabled("menu-item-export-clipboard",true);
 | 
				
			||||||
 | 
					                    RED.menu.setDisabled("menu-item-export-library",true);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    RED.menu.setDisabled("menu-item-export",false);
 | 
				
			||||||
 | 
					                    RED.menu.setDisabled("menu-item-export-clipboard",false);
 | 
				
			||||||
 | 
					                    RED.menu.setDisabled("menu-item-export-library",false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            RED.actions.add("core:show-export-dialog",exportNodes);
 | 
				
			||||||
 | 
					            RED.actions.add("core:show-import-dialog",importNodes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            RED.events.on("editor:open",function() { disabled = true; });
 | 
				
			||||||
 | 
					            RED.events.on("editor:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					            RED.events.on("search:open",function() { disabled = true; });
 | 
				
			||||||
 | 
					            RED.events.on("search:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					            RED.events.on("type-search:open",function() { disabled = true; });
 | 
				
			||||||
 | 
					            RED.events.on("type-search:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $('#chart').on("dragenter",function(event) {
 | 
				
			||||||
 | 
					                if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
 | 
				
			||||||
 | 
					                     $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
 | 
				
			||||||
 | 
					                    $("#dropTarget").css({display:'table'});
 | 
				
			||||||
 | 
					                    RED.keyboard.add("*", "escape" ,hideDropTarget);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $('#dropTarget').on("dragover",function(event) {
 | 
				
			||||||
 | 
					                if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
 | 
				
			||||||
 | 
					                     $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
 | 
				
			||||||
 | 
					                    event.preventDefault();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .on("dragleave",function(event) {
 | 
				
			||||||
 | 
					                hideDropTarget();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .on("drop",function(event) {
 | 
				
			||||||
 | 
					                if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
 | 
				
			||||||
 | 
					                    var data = event.originalEvent.dataTransfer.getData("text/plain");
 | 
				
			||||||
 | 
					                    data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
 | 
				
			||||||
 | 
					                    RED.view.importNodes(data);
 | 
				
			||||||
 | 
					                } else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
 | 
				
			||||||
 | 
					                    var files = event.originalEvent.dataTransfer.files;
 | 
				
			||||||
 | 
					                    if (files.length === 1) {
 | 
				
			||||||
 | 
					                        var file = files[0];
 | 
				
			||||||
 | 
					                        var reader = new FileReader();
 | 
				
			||||||
 | 
					                        reader.onload = (function(theFile) {
 | 
				
			||||||
 | 
					                            return function(e) {
 | 
				
			||||||
 | 
					                                RED.view.importNodes(e.target.result);
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					                        })(file);
 | 
				
			||||||
 | 
					                        reader.readAsText(file);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                hideDropTarget();
 | 
				
			||||||
 | 
					                event.preventDefault();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        import: importNodes,
 | 
				
			||||||
 | 
					        export: exportNodes,
 | 
				
			||||||
 | 
					        copyText: copyText
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||