1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Merge branch 'dev' into pr_2478

This commit is contained in:
Nick O'Leary 2020-05-29 17:04:54 +01:00
commit 13718032f6
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
245 changed files with 12801 additions and 4077 deletions

View File

@ -32,3 +32,4 @@ To help us understand the issue, please fill-in as much of the following informa
- [ ] npm version: - [ ] npm version:
- [ ] Platform/OS: - [ ] Platform/OS:
- [ ] Browser: - [ ] Browser:
- [ ] running in Docker:

View File

@ -1,6 +1,6 @@
--- ---
name: Bug report name: Bug report
about: Reproducable software issues in the core of Node-RED about: Reproducible software issues in the core of Node-RED
title: '' title: ''
labels: '' labels: ''
assignees: '' assignees: ''

View File

@ -29,6 +29,6 @@ the [forum](https://discourse.nodered.org) or
<!-- Put an `x` in the boxes that apply --> <!-- 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) - [ ] 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 mailing list/slack team. - [ ] For non-bugfix PRs, I have discussed this change on the forum/slack team.
- [ ] I have run `grunt` to verify the unit tests pass - [ ] I have run `grunt` to verify the unit tests pass
- [ ] I have added suitable unit tests to cover the new/changed functionality - [ ] I have added suitable unit tests to cover the new/changed functionality

1
.gitignore vendored
View File

@ -22,3 +22,4 @@ packages/node_modules/@node-red/editor-client/public
!test/**/node_modules !test/**/node_modules
docs docs
!packages/node_modules/**/docs !packages/node_modules/**/docs
.vscode

View File

@ -2,6 +2,7 @@ sudo: false
language: node_js language: node_js
matrix: matrix:
include: include:
- node_js: "14"
- node_js: "12" - node_js: "12"
- node_js: "10" - node_js: "10"
script: script:

File diff suppressed because it is too large Load Diff

View File

@ -125,6 +125,7 @@ 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",
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js", "packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
"packages/node_modules/@node-red/editor-client/src/js/red.js", "packages/node_modules/@node-red/editor-client/src/js/red.js",
"packages/node_modules/@node-red/editor-client/src/js/events.js", "packages/node_modules/@node-red/editor-client/src/js/events.js",
@ -151,6 +152,7 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js", "packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js", "packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js", "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
@ -163,6 +165,8 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.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/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.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-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/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/palette-editor.js",
@ -177,6 +181,7 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.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/typeSearch.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.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/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/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/projectSettings.js",
@ -189,11 +194,12 @@ module.exports = function(grunt) {
vendor: { vendor: {
files: { files: {
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [ "packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.4.1.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.0.1.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js", "node_modules/marked/marked.min.js",
"node_modules/dompurify/dist/purify.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js",
"node_modules/jsonata/jsonata-es5.min.js", "node_modules/jsonata/jsonata-es5.min.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "node-red", "name": "node-red",
"version": "1.0.3", "version": "1.1.0",
"description": "Low-code programming for event-driven applications", "description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org", "homepage": "http://nodered.org",
"license": "Apache-2.0", "license": "Apache-2.0",
@ -24,7 +24,7 @@
} }
], ],
"dependencies": { "dependencies": {
"ajv": "6.10.2", "ajv": "6.12.0",
"basic-auth": "2.0.1", "basic-auth": "2.0.1",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "1.19.0", "body-parser": "1.19.0",
@ -32,7 +32,7 @@
"clone": "2.1.2", "clone": "2.1.2",
"content-type": "1.0.4", "content-type": "1.0.4",
"cookie": "0.4.0", "cookie": "0.4.0",
"cookie-parser": "1.4.4", "cookie-parser": "1.4.5",
"cors": "2.8.5", "cors": "2.8.5",
"cron": "1.7.2", "cron": "1.7.2",
"denque": "1.4.1", "denque": "1.4.1",
@ -41,40 +41,43 @@
"fs-extra": "8.1.0", "fs-extra": "8.1.0",
"fs.notify": "0.0.4", "fs.notify": "0.0.4",
"hash-sum": "2.0.0", "hash-sum": "2.0.0",
"https-proxy-agent": "2.2.4", "https-proxy-agent": "5.0.0",
"i18next": "15.1.2", "i18next": "15.1.2",
"iconv-lite": "0.5.0", "iconv-lite": "0.5.1",
"is-utf8": "0.2.1", "is-utf8": "0.2.1",
"js-yaml": "3.13.1", "js-yaml": "3.13.1",
"json-stringify-safe": "5.0.1", "json-stringify-safe": "5.0.1",
"jsonata": "1.8.0", "jsonata": "1.8.3",
"lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0", "media-typer": "1.1.0",
"memorystore": "1.6.1", "memorystore": "1.6.2",
"mime": "2.4.4", "mime": "2.4.4",
"mqtt": "2.18.8", "mqtt": "2.18.8",
"multer": "1.4.2", "multer": "1.4.2",
"mustache": "3.0.2", "mustache": "4.0.1",
"node-red-node-rbe": "^0.2.6", "node-red-node-rbe": "^0.2.6",
"node-red-node-sentiment": "^0.1.6", "node-red-node-sentiment": "^0.1.6",
"node-red-node-tail": "^0.1.0", "node-red-node-tail": "^0.1.0",
"nopt": "4.0.1", "nopt": "4.0.3",
"oauth2orize": "1.11.0", "oauth2orize": "1.11.0",
"on-headers": "1.0.2", "on-headers": "1.0.2",
"passport": "0.4.0", "passport": "0.4.1",
"passport-http-bearer": "1.0.1", "passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"raw-body": "2.4.1", "raw-body": "2.4.1",
"request": "2.88.0", "request": "2.88.0",
"semver": "6.3.0", "semver": "6.3.0",
"uglify-js": "3.6.9", "uglify-js": "3.8.1",
"when": "3.7.8", "when": "3.7.8",
"ws": "6.2.1", "ws": "6.2.1",
"xml2js": "0.4.22" "xml2js": "0.4.23"
}, },
"optionalDependencies": { "optionalDependencies": {
"bcrypt": "3.0.6" "bcrypt": "3.0.8"
}, },
"devDependencies": { "devDependencies": {
"marked": "0.8.2",
"dompurify": "2.0.8",
"grunt": "~1.0.4", "grunt": "~1.0.4",
"grunt-chmod": "~1.1.1", "grunt-chmod": "~1.1.1",
"grunt-cli": "~1.3.2", "grunt-cli": "~1.3.2",
@ -101,8 +104,8 @@
"minami": "1.2.3", "minami": "1.2.3",
"mocha": "^5.2.0", "mocha": "^5.2.0",
"mosca": "^2.8.3", "mosca": "^2.8.3",
"node-red-node-test-helper": "^0.2.3", "node-red-node-test-helper": "^0.2.5",
"node-sass": "^4.13.0", "node-sass": "^4.13.1",
"should": "^8.4.0", "should": "^8.4.0",
"sinon": "1.17.7", "sinon": "1.17.7",
"stoppable": "^1.1.0", "stoppable": "^1.1.0",

View File

@ -36,6 +36,7 @@ var log = require("@node-red/util").log; // TODO: separate module
passport.use(strategies.bearerStrategy.BearerStrategy); passport.use(strategies.bearerStrategy.BearerStrategy);
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy); passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
passport.use(strategies.anonymousStrategy); passport.use(strategies.anonymousStrategy);
passport.use(strategies.tokensStrategy);
var server = oauth2orize.createServer(); var server = oauth2orize.createServer();
@ -60,7 +61,7 @@ function init(_settings,storage) {
function needsPermission(permission) { function needsPermission(permission) {
return function(req,res,next) { return function(req,res,next) {
if (settings && settings.adminAuth) { if (settings && settings.adminAuth) {
return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() { return passport.authenticate(['bearer','tokens','anon'],{ session: false })(req,res,function() {
if (!req.user) { if (!req.user) {
return next(); return next();
} }
@ -100,7 +101,10 @@ function login(req,res) {
} }
} else if (mergedAdminAuth.type === "strategy") { } else if (mergedAdminAuth.type === "strategy") {
var urlPrefix = (settings.httpAdminRoot==='/')?"":settings.httpAdminRoot; var urlPrefix = (settings.httpAdminRoot||"").replace(/\/$/,"");
if (urlPrefix.length > 0) {
urlPrefix += "/";
}
response = { response = {
"type":"strategy", "type":"strategy",
"prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}] "prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]

View File

@ -123,9 +123,38 @@ AnonymousStrategy.prototype.authenticate = function(req) {
}); });
} }
function TokensStrategy() {
passport.Strategy.call(this);
this.name = 'tokens';
}
util.inherits(TokensStrategy, passport.Strategy);
TokensStrategy.prototype.authenticate = function(req) {
var self = this;
var token = null;
if (Users.tokenHeader() === 'authorization') {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
token = req.headers.authorization.split(' ')[1];
}
} else {
token = req.headers[Users.tokenHeader()];
}
if (token) {
Users.tokens(token).then(function(admin) {
if (admin) {
self.success(admin,{scope:admin.permissions});
} else {
self.fail(401);
}
});
} else {
self.fail(401);
}
}
module.exports = { module.exports = {
bearerStrategy: bearerStrategy, bearerStrategy: bearerStrategy,
clientPasswordStrategy: clientPasswordStrategy, clientPasswordStrategy: clientPasswordStrategy,
passwordTokenExchange: passwordTokenExchange, passwordTokenExchange: passwordTokenExchange,
anonymousStrategy: new AnonymousStrategy() anonymousStrategy: new AnonymousStrategy(),
tokensStrategy: new TokensStrategy()
} }

View File

@ -59,7 +59,9 @@ function getDefaultUser() {
var api = { var api = {
get: get, get: get,
authenticate: authenticate, authenticate: authenticate,
default: getDefaultUser default: getDefaultUser,
tokens: getDefaultUser,
tokenHeader: "authorization"
} }
function init(config) { function init(config) {
@ -105,6 +107,12 @@ function init(config) {
} else { } else {
api.default = getDefaultUser; api.default = getDefaultUser;
} }
if (config.tokens && typeof config.tokens === "function") {
api.tokens = config.tokens;
if (config.tokenHeader && typeof config.tokenHeader === "string") {
api.tokenHeader = config.tokenHeader.toLowerCase();
}
}
} }
function cleanUser(user) { function cleanUser(user) {
if (user && user.hasOwnProperty('password')) { if (user && user.hasOwnProperty('password')) {
@ -118,5 +126,7 @@ module.exports = {
init: init, init: init,
get: function(username) { return api.get(username).then(cleanUser)}, get: function(username) { return api.get(username).then(cleanUser)},
authenticate: function() { return api.authenticate.apply(null, arguments) }, authenticate: function() { return api.authenticate.apply(null, arguments) },
default: function() { return api.default(); } default: function() { return api.default(); },
tokens: function(token) { return api.tokens(token); },
tokenHeader: function() { return api.tokenHeader }
}; };

View File

@ -59,6 +59,12 @@ function init(settings,_server,storage,runtimeAPI) {
}); });
adminApp.use(corsHandler); adminApp.use(corsHandler);
if (settings.httpAdminMiddleware) {
if (typeof settings.httpAdminMiddleware === "function") {
adminApp.use(settings.httpAdminMiddleware)
}
}
auth.init(settings,storage); auth.init(settings,storage);
var maxApiRequestSize = settings.apiMaxLength || '5mb'; var maxApiRequestSize = settings.apiMaxLength || '5mb';

View File

@ -43,10 +43,16 @@ module.exports = {
rejectHandler: function(req,res,err) { rejectHandler: function(req,res,err) {
//TODO: why this when errorHandler also?! //TODO: why this when errorHandler also?!
log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req); log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req);
res.status(err.status||400).json({ var response = {
code: err.code||"unexpected_error", code: err.code||"unexpected_error",
message: err.message||err.toString() message: err.message||err.toString()
}); };
// Handle auth failures on a specific remote
// TODO: don't hardcode this here - allow users of rejectHandler to identify extra props to send
if (err.remote) {
response.remote = err.remote;
}
res.status(err.status||400).json(response);
}, },
getRequestLogObject: function(req) { getRequestLogObject: function(req) {
return { return {

View File

@ -1,6 +1,6 @@
{ {
"name": "@node-red/editor-api", "name": "@node-red/editor-api",
"version": "1.0.3", "version": "1.1.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@ -16,21 +16,21 @@
} }
], ],
"dependencies": { "dependencies": {
"@node-red/util": "1.0.3", "@node-red/util": "1.1.0",
"@node-red/editor-client": "1.0.3", "@node-red/editor-client": "1.1.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "1.19.0", "body-parser": "1.19.0",
"clone": "2.1.2", "clone": "2.1.2",
"cors": "2.8.5", "cors": "2.8.5",
"express-session": "1.17.0", "express-session": "1.17.0",
"express": "4.17.1", "express": "4.17.1",
"memorystore": "1.6.1", "memorystore": "1.6.2",
"mime": "2.4.4", "mime": "2.4.4",
"mustache": "3.0.2", "mustache": "4.0.1",
"oauth2orize": "1.11.0", "oauth2orize": "1.11.0",
"passport-http-bearer": "1.0.1", "passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"passport": "0.4.0", "passport": "0.4.1",
"when": "3.7.8", "when": "3.7.8",
"ws": "6.2.1" "ws": "6.2.1"
}, },

View File

@ -34,11 +34,11 @@
"view" : "Ansicht", "view" : "Ansicht",
"grid" : "Gitter", "grid" : "Gitter",
"showGrid" : "Raster anzeigen", "showGrid" : "Raster anzeigen",
"snapGrid" : "Einrasten am Raster", "snapGrid" : "Am Raster ausrichten",
"gridSize" : "Rastergröße", "gridSize" : "Rastergröße",
"textDir" : "Textrichtung", "textDir" : "Textrichtung",
"defaultDir" : "Standard", "defaultDir" : "Standard",
"ltr" : "Links-nach-rechts", "ltr" : "Von links nach rechts",
"rtl" : "Von rechts nach links", "rtl" : "Von rechts nach links",
"auto" : "Kontextuell" "auto" : "Kontextuell"
}, },
@ -53,15 +53,15 @@
"import" : "Import", "import" : "Import",
"export" : "Exportieren", "export" : "Exportieren",
"search" : "Flows durchsuchen", "search" : "Flows durchsuchen",
"searchInput" : "durchsuchen Sie Ihre Flows", "searchInput" : "Flows durchsuchen",
"subflows" : "Subflow", "subflows" : "Subflow",
"createSubflow" : "Subflow erstellen", "createSubflow" : "Subflow erstellen",
"selectionToSubflow" : "Auswahl für Subflow", "selectionToSubflow" : "Auswahl zu Subflow",
"flows" : "Flows", "flows" : "Flows",
"add" : "Hinzufügen", "add" : "Hinzufügen",
"rename" : "Umbenennen", "rename" : "Umbenennen",
"delete" : "Löschen", "delete" : "Löschen",
"keyboardShortcuts" : "Tastaturkurzbefehle", "keyboardShortcuts" : "Tastenkürzel",
"login" : "Anmelden", "login" : "Anmelden",
"logout" : "Abmelden", "logout" : "Abmelden",
"editPalette" : "Palette verwalten", "editPalette" : "Palette verwalten",
@ -217,7 +217,7 @@
"remote" : "Ferne Änderungen", "remote" : "Ferne Änderungen",
"reviewChanges" : "Änderungen prüfen", "reviewChanges" : "Änderungen prüfen",
"noBinaryFileShowed" : "Der Inhalt der Binärdatei kann nicht angezeigt", "noBinaryFileShowed" : "Der Inhalt der Binärdatei kann nicht angezeigt",
"viewCommitDiff" : "Änderungen festschreiben", "viewCommitDiff" : "Änderungen committen",
"compareChanges" : "Änderungen vergleichen", "compareChanges" : "Änderungen vergleichen",
"saveConflict" : "Konfliktlösung speichern", "saveConflict" : "Konfliktlösung speichern",
"conflictHeader" : "<span> __resolved__ </span> von <span> __unresolved__ </span> -Konflikten behoben", "conflictHeader" : "<span> __resolved__ </span> von <span> __unresolved__ </span> -Konflikten behoben",
@ -226,8 +226,8 @@
"newVersionError" : "Neue Version enthält keine gültige JSON-Datei:" "newVersionError" : "Neue Version enthält keine gültige JSON-Datei:"
}, },
"subflow" : { "subflow" : {
"editSubflow" : "Flowschablone bearbeiten: __name__", "editSubflow" : "Subflow bearbeiten: __name__",
"edit" : "Flowsschablone bearbeiten", "edit" : "Subflow bearbeiten",
"subflowInstances" : "Es ist __count__ Instanz dieser Subflow-Vorlage vorhanden.", "subflowInstances" : "Es ist __count__ Instanz dieser Subflow-Vorlage vorhanden.",
"subflowInstances_plural" : "Es gibt __count__ Instanzen dieser Subflow-Vorlage.", "subflowInstances_plural" : "Es gibt __count__ Instanzen dieser Subflow-Vorlage.",
"editSubflowProperties" : "Eigenschaften bearbeiten", "editSubflowProperties" : "Eigenschaften bearbeiten",
@ -266,7 +266,7 @@
} }
}, },
"keyboard" : { "keyboard" : {
"title" : "Tastaturkurzbefehle", "title" : "Tastenkürzel",
"keyboard" : "Tastatur", "keyboard" : "Tastatur",
"filterActions" : "Filteraktionen", "filterActions" : "Filteraktionen",
"shortcut" : "Direktaufruf", "shortcut" : "Direktaufruf",
@ -283,7 +283,7 @@
"exportNode" : "Node exportieren", "exportNode" : "Node exportieren",
"nudgeNode" : "Ausgewählte Nodes verschieben (1px)", "nudgeNode" : "Ausgewählte Nodes verschieben (1px)",
"moveNode" : "Ausgewählte Nodes verschieben (20px)", "moveNode" : "Ausgewählte Nodes verschieben (20px)",
"toggleSidebar" : "Seitenleiste ein-/ausschalten", "toggleSidebar" : "Seitenleiste ein-/ausblenden",
"copyNode" : "Ausgewählte Nodes kopieren", "copyNode" : "Ausgewählte Nodes kopieren",
"cutNode" : "Ausgewählte Nodes ausschneiden", "cutNode" : "Ausgewählte Nodes ausschneiden",
"pasteNode" : "Node einfügen", "pasteNode" : "Node einfügen",
@ -308,7 +308,7 @@
}, },
"palette" : { "palette" : {
"noInfo" : "Keine Informationen verfügbar", "noInfo" : "Keine Informationen verfügbar",
"filter" : "Filter Nodes", "filter" : "Nodes filtern",
"search" : "Suchmodule", "search" : "Suchmodule",
"addCategory" : "Neu hinzufügen ...", "addCategory" : "Neu hinzufügen ...",
"label" : { "label" : {
@ -366,11 +366,11 @@
"remove" : "entfernen", "remove" : "entfernen",
"update" : "Update auf __version__", "update" : "Update auf __version__",
"updated" : "aktualisiert", "updated" : "aktualisiert",
"install" : "installieren", "install" : "Installieren",
"installed" : "installiert", "installed" : "Installiert",
"loading" : "Kataloge werden geladen ...", "loading" : "Kataloge werden geladen ...",
"tab-nodes" : "Nodes", "tab-nodes" : "Nodes",
"tab-install" : "installieren", "tab-install" : "Installieren",
"sort" : "Sortierung:", "sort" : "Sortierung:",
"sortAZ" : "a-z", "sortAZ" : "a-z",
"sortRecent" : "kürzlich", "sortRecent" : "kürzlich",
@ -452,7 +452,7 @@
"name" : "Kontextdaten", "name" : "Kontextdaten",
"label" : "Kontext", "label" : "Kontext",
"none" : "keine ausgewählt", "none" : "keine ausgewählt",
"refresh" : "Aktualisierung zum Laden", "refresh" : "Zum Aktualisieren neu laden",
"empty" : "leer", "empty" : "leer",
"node" : "Node", "node" : "Node",
"flow" : "Flow", "flow" : "Flow",
@ -477,7 +477,7 @@
"none" : "Keine", "none" : "Keine",
"install" : "installieren", "install" : "installieren",
"removeFromProject" : "Aus Projekt entfernen", "removeFromProject" : "Aus Projekt entfernen",
"addToProject" : "zu Projekt hinzufügen", "addToProject" : "Zu Projekt hinzufügen",
"files" : "Dateien", "files" : "Dateien",
"flow" : "Flow", "flow" : "Flow",
"credentials" : "Berechtigungsnachweis", "credentials" : "Berechtigungsnachweis",
@ -510,7 +510,7 @@
}, },
"userSettings" : { "userSettings" : {
"committerDetail" : "Committer-Details", "committerDetail" : "Committer-Details",
"committerTip" : "Leer Wert für Systemstandardwert belassen", "committerTip" : "Leer lassen für Systemstandard",
"userName" : "Benutzername", "userName" : "Benutzername",
"email" : "E-Mail", "email" : "E-Mail",
"sshKeys" : "SSH-Schlüssel", "sshKeys" : "SSH-Schlüssel",
@ -544,7 +544,7 @@
"revertChanges" : "Änderungen zurücksetzen", "revertChanges" : "Änderungen zurücksetzen",
"localChanges" : "Lokale Änderungen", "localChanges" : "Lokale Änderungen",
"none" : "Keine", "none" : "Keine",
"conflictResolve" : "Alle Konflikte wurden aufgelöst. Festschreiben der Änderungen, um den Mischvorgang abzuschließen.", "conflictResolve" : "Alle Konflikte wurden aufgelöst. Committe die Änderungen, um den Merge Request abzuschließen.",
"localFiles" : "Lokale Dateien", "localFiles" : "Lokale Dateien",
"all" : "alle", "all" : "alle",
"unmergedChanges" : "Nicht zusammengeführte Änderungen", "unmergedChanges" : "Nicht zusammengeführte Änderungen",

View File

@ -14,7 +14,13 @@
"back": "Back", "back": "Back",
"next": "Next", "next": "Next",
"clone": "Clone project", "clone": "Clone project",
"cont": "Continue" "cont": "Continue",
"style": "Style",
"line": "Outline",
"fill": "Fill",
"label": "Label",
"color": "Color",
"position": "Position"
}, },
"type": { "type": {
"string": "string", "string": "string",
@ -28,6 +34,13 @@
"null": "null" "null": "null"
} }
}, },
"event": {
"loadPalette": "Loading Palette",
"loadNodeCatalogs": "Loading Node catalogs",
"loadNodes": "Loading Nodes __count__",
"loadFlows": "Loading Flows",
"importFlows": "Adding Flows to workspace"
},
"workspace": { "workspace": {
"defaultName": "Flow __number__", "defaultName": "Flow __number__",
"editFlow": "Edit flow: __name__", "editFlow": "Edit flow: __name__",
@ -91,7 +104,12 @@
"projects-new": "New", "projects-new": "New",
"projects-open": "Open", "projects-open": "Open",
"projects-settings": "Project Settings", "projects-settings": "Project Settings",
"showNodeLabelDefault": "Show label of newly added nodes" "showNodeLabelDefault": "Show label of newly added nodes",
"groups": "Groups",
"groupSelection": "Group selection",
"ungroupSelection": "Ungroup selection",
"groupMergeSelection": "Merge selection",
"groupRemoveSelection": "Remove from group"
} }
}, },
"actions": { "actions": {
@ -171,6 +189,8 @@
"node_plural": "__count__ nodes", "node_plural": "__count__ nodes",
"configNode": "__count__ configuration node", "configNode": "__count__ configuration node",
"configNode_plural": "__count__ configuration nodes", "configNode_plural": "__count__ configuration nodes",
"group": "__count__ group",
"group_plural": "__count__ groups",
"flow": "__count__ flow", "flow": "__count__ flow",
"flow_plural": "__count__ flows", "flow_plural": "__count__ flows",
"subflow": "__count__ subflow", "subflow": "__count__ subflow",
@ -186,6 +206,9 @@
"nodesImported": "Imported:", "nodesImported": "Imported:",
"nodeCopied": "__count__ node copied", "nodeCopied": "__count__ node copied",
"nodeCopied_plural": "__count__ nodes copied", "nodeCopied_plural": "__count__ nodes copied",
"groupCopied": "__count__ group copied",
"groupCopied_plural": "__count__ groups copied",
"groupStyleCopied": "Group style copied",
"invalidFlow": "Invalid flow: __message__", "invalidFlow": "Invalid flow: __message__",
"export": { "export": {
"selected":"selected nodes", "selected":"selected nodes",
@ -308,6 +331,13 @@
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection" "multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
} }
}, },
"group": {
"editGroup": "Edit group: __name__",
"errors": {
"cannotCreateDiffGroups": "Cannot create group using nodes from different groups",
"cannotAddSubflowPorts": "Cannot add subflow ports to a group"
}
},
"editor": { "editor": {
"configEdit": "Edit", "configEdit": "Edit",
"configAdd": "Add", "configAdd": "Add",
@ -539,6 +569,7 @@
"label": "info", "label": "info",
"node": "Node", "node": "Node",
"type": "Type", "type": "Type",
"group": "Group",
"module": "Module", "module": "Module",
"id": "ID", "id": "ID",
"status": "Status", "status": "Status",
@ -561,7 +592,20 @@
"nodeHelp": "Node Help", "nodeHelp": "Node Help",
"none":"None", "none":"None",
"arrayItems": "__count__ items", "arrayItems": "__count__ items",
"showTips":"You can open the tips from the settings panel" "showTips":"You can open the tips from the settings panel",
"outline": "Outline",
"empty": "empty",
"globalConfig": "Global Configuration Nodes"
},
"help": {
"name": "Help",
"label": "help",
"search": "Search help",
"nodeHelp": "Node Help",
"showHelp": "Show help",
"showInOutline": "Show in outline",
"showTopics": "Show topics",
"noHelp": "No help topic selected"
}, },
"config": { "config": {
"name": "Configuration nodes", "name": "Configuration nodes",
@ -614,7 +658,6 @@
"removeFromProject": "remove from project", "removeFromProject": "remove from project",
"addToProject": "add to project", "addToProject": "add to project",
"files": "Files", "files": "Files",
"package": "Package",
"flow": "Flow", "flow": "Flow",
"credentials": "Credentials", "credentials": "Credentials",
"package":"Package", "package":"Package",
@ -806,9 +849,9 @@
"expandItems": "Expand items", "expandItems": "Expand items",
"collapseItems": "Collapse items", "collapseItems": "Collapse items",
"duplicate": "Duplicate", "duplicate": "Duplicate",
"error": { "error": {
"invalidJSON": "Invalid JSON: " "invalidJSON": "Invalid JSON: "
} }
}, },
"markdownEditor": { "markdownEditor": {
"title": "Markdown editor", "title": "Markdown editor",
@ -979,7 +1022,8 @@
"passphrase": "Passphrase", "passphrase": "Passphrase",
"retry": "Retry", "retry": "Retry",
"update-failed": "Failed to update auth", "update-failed": "Failed to update auth",
"unhandled": "Unhandled error response" "unhandled": "Unhandled error response",
"host-key-verify-failed": "<p>Host key verification failed.</p><p>The repository host key could not be verified. Please update your <code>known_hosts</code> file and try again.</p>"
}, },
"create-branch-list": { "create-branch-list": {
"invalid": "Invalid branch", "invalid": "Invalid branch",

60
packages/node_modules/@node-red/editor-client/locales/ja/editor.json vendored Executable file → Normal file
View File

@ -14,7 +14,13 @@
"back": "戻る", "back": "戻る",
"next": "進む", "next": "進む",
"clone": "プロジェクトをクローン", "clone": "プロジェクトをクローン",
"cont": "続ける" "cont": "続ける",
"style": "形式",
"line": "線",
"fill": "塗りつぶし",
"label": "ラベル",
"color": "色",
"position": "配置"
}, },
"type": { "type": {
"string": "文字列", "string": "文字列",
@ -28,6 +34,13 @@
"null": "null" "null": "null"
} }
}, },
"event": {
"loadPalette": "パレットを読み込み中",
"loadNodeCatalogs": "ノードカタログを読み込み中",
"loadNodes": "ノードを読み込み中 __count__",
"loadFlows": "フローを読み込み中",
"importFlows": "ワークスペースにフローを追加中"
},
"workspace": { "workspace": {
"defaultName": "フロー __number__", "defaultName": "フロー __number__",
"editFlow": "フローを編集: __name__", "editFlow": "フローを編集: __name__",
@ -67,7 +80,7 @@
"settings": "設定", "settings": "設定",
"userSettings": "ユーザ設定", "userSettings": "ユーザ設定",
"nodes": "ノード", "nodes": "ノード",
"displayStatus": "ノードの状態を表示", "displayStatus": "ノードのステータスを表示",
"displayConfig": "ノードの設定", "displayConfig": "ノードの設定",
"import": "読み込み", "import": "読み込み",
"export": "書き出し", "export": "書き出し",
@ -91,7 +104,12 @@
"projects-new": "新規", "projects-new": "新規",
"projects-open": "開く", "projects-open": "開く",
"projects-settings": "設定", "projects-settings": "設定",
"showNodeLabelDefault": "追加したノードのラベルを表示" "showNodeLabelDefault": "追加したノードのラベルを表示",
"groups": "グループ",
"groupSelection": "選択部分をグループ化",
"ungroupSelection": "選択部分をグループ解除",
"groupMergeSelection": "選択部分をマージ",
"groupRemoveSelection": "グループから削除"
} }
}, },
"actions": { "actions": {
@ -171,6 +189,8 @@
"node_plural": "__count__ 個のノード", "node_plural": "__count__ 個のノード",
"configNode": "__count__ 個の設定ノード", "configNode": "__count__ 個の設定ノード",
"configNode_plural": "__count__ 個の設定ノード", "configNode_plural": "__count__ 個の設定ノード",
"group": "__count__ 個のグループ",
"group_plural": "__count__ 個のグループ",
"flow": "__count__ 個のフロー", "flow": "__count__ 個のフロー",
"flow_plural": "__count__ 個のフロー", "flow_plural": "__count__ 個のフロー",
"subflow": "__count__ 個のサブフロー", "subflow": "__count__ 個のサブフロー",
@ -186,6 +206,9 @@
"nodesImported": "読み込みました:", "nodesImported": "読み込みました:",
"nodeCopied": "__count__ 個のノードをコピーしました", "nodeCopied": "__count__ 個のノードをコピーしました",
"nodeCopied_plural": "__count__ 個のノードをコピーしました", "nodeCopied_plural": "__count__ 個のノードをコピーしました",
"groupCopied": "__count__ 個のグループをコピーしました",
"groupCopied_plural": "__count__ 個のグループをコピーしました",
"groupStyleCopied": "グループの形式をコピーしました",
"invalidFlow": "不正なフロー: __message__", "invalidFlow": "不正なフロー: __message__",
"export": { "export": {
"selected": "選択したフロー", "selected": "選択したフロー",
@ -308,6 +331,13 @@
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています" "multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"
} }
}, },
"group": {
"editGroup": "__name__ グループを編集",
"errors": {
"cannotCreateDiffGroups": "異なるグループのノードを使用してグループを作成することはできません",
"cannotAddSubflowPorts": "グループにサブフローの端子を追加できません"
}
},
"editor": { "editor": {
"configEdit": "編集", "configEdit": "編集",
"configAdd": "追加", "configAdd": "追加",
@ -539,6 +569,7 @@
"label": "情報", "label": "情報",
"node": "ノード", "node": "ノード",
"type": "型", "type": "型",
"group": "グループ",
"module": "モジュール", "module": "モジュール",
"id": "ID", "id": "ID",
"status": "状態", "status": "状態",
@ -561,7 +592,20 @@
"nodeHelp": "ノードのヘルプ", "nodeHelp": "ノードのヘルプ",
"none": "なし", "none": "なし",
"arrayItems": "__count__ 要素", "arrayItems": "__count__ 要素",
"showTips": "設定からヒントを表示できます" "showTips": "設定からヒントを表示できます",
"outline": "アウトライン",
"empty": "空",
"globalConfig": "グローバル設定ノード"
},
"help": {
"name": "ヘルプ",
"label": "ヘルプ",
"search": "ヘルプを検索",
"nodeHelp": "ノードヘルプ",
"showHelp": "ヘルプを表示",
"showInOutline": "アウトラインに表示",
"showTopics": "トピックを表示",
"noHelp": "ヘルプのトピックが未選択"
}, },
"config": { "config": {
"name": "ノードの設定を表示", "name": "ノードの設定を表示",
@ -614,9 +658,9 @@
"removeFromProject": "プロジェクトから削除", "removeFromProject": "プロジェクトから削除",
"addToProject": "プロジェクトへ追加", "addToProject": "プロジェクトへ追加",
"files": "ファイル", "files": "ファイル",
"package": "パッケージ",
"flow": "フロー", "flow": "フロー",
"credentials": "認証情報", "credentials": "認証情報",
"package": "パッケージ",
"packageCreate": "変更が保存された時にファイルが作成されます", "packageCreate": "変更が保存された時にファイルが作成されます",
"fileNotExist": "ファイルが存在しません", "fileNotExist": "ファイルが存在しません",
"selectFile": "ファイルを選択", "selectFile": "ファイルを選択",
@ -757,7 +801,8 @@
"bin": "バッファ", "bin": "バッファ",
"date": "日時", "date": "日時",
"jsonata": "JSONata式", "jsonata": "JSONata式",
"env": "環境変数" "env": "環境変数",
"cred": "認証情報"
} }
}, },
"editableList": { "editableList": {
@ -977,7 +1022,8 @@
"passphrase": "パスフレーズ", "passphrase": "パスフレーズ",
"retry": "リトライ", "retry": "リトライ",
"update-failed": "認証の更新に失敗しました", "update-failed": "認証の更新に失敗しました",
"unhandled": "エラー応答が処理されませんでした" "unhandled": "エラー応答が処理されませんでした",
"host-key-verify-failed": "<p>ホストキーの検証に失敗</p><p>リポジトリのホストキーを検証できませんでした。<code>known_hosts</code>ファイルを更新して、もう一度試してください。</p>"
}, },
"create-branch-list": { "create-branch-list": {
"invalid": "不正なブランチ", "invalid": "不正なブランチ",

View File

@ -24,7 +24,7 @@
"buffer": "buffer", "buffer": "buffer",
"object": "对象", "object": "对象",
"jsonString": "JSON字符串", "jsonString": "JSON字符串",
"undefined": "定义", "undefined": "定义",
"null": "空" "null": "空"
} }
}, },
@ -1008,6 +1008,7 @@
"en-US": "英文", "en-US": "英文",
"ja": "日语", "ja": "日语",
"ko": "韩文", "ko": "韩文",
"zh-CN": "简体中文" "zh-CN": "简体中文",
"zh-TW": "繁体中文"
} }
} }

View File

@ -262,5 +262,9 @@
"$distinct": { "$distinct": {
"args": "array", "args": "array",
"desc": "返回一个数组,其中重复的值已从`数组`中删除" "desc": "返回一个数组,其中重复的值已从`数组`中删除"
},
"$type": {
"args": "value",
"desc": "以字符串形式返回`值`的类型。 如果该`值`未定义,则将返回`未定义`"
} }
} }

View File

@ -15,6 +15,17 @@
"next": "下一步", "next": "下一步",
"clone": "複製專案", "clone": "複製專案",
"cont": "Continue" "cont": "Continue"
},
"type": {
"string": "字符串",
"number": "數值",
"boolean": "布林",
"array": "數組",
"buffer": "buffer",
"object": "對象",
"jsonString": "JSON字符串",
"undefined": "未定義",
"null": "空"
} }
}, },
"workspace": { "workspace": {
@ -29,8 +40,7 @@
"enabled": "有效", "enabled": "有效",
"disabled": "無效", "disabled": "無效",
"info": "詳細描述", "info": "詳細描述",
"selectNodes": "點擊節點用於選擇", "selectNodes": "點擊節點用於選擇"
"tip": "詳細描述支援Markdown羽量級標記語言並將出現在資訊標籤中。"
}, },
"menu": { "menu": {
"label": { "label": {
@ -45,14 +55,14 @@
"ltr": "從左到右", "ltr": "從左到右",
"rtl": "從右到左", "rtl": "從右到左",
"auto": "上下文", "auto": "上下文",
"language": "Language", "language": "語言",
"browserDefault": "Browser default" "browserDefault": "瀏覽器默認"
}, },
"sidebar": { "sidebar": {
"show": "顯示側邊欄" "show": "顯示側邊欄"
}, },
"palette": { "palette": {
"show": "Show palette" "show": "顯示控制板"
}, },
"settings": "設置", "settings": "設置",
"userSettings": "使用者設置", "userSettings": "使用者設置",
@ -81,10 +91,7 @@
"projects-new": "新專案", "projects-new": "新專案",
"projects-open": "開啟專案", "projects-open": "開啟專案",
"projects-settings": "專案設定", "projects-settings": "專案設定",
"showNodeLabelDefault": "顯示新添加節點的標籤", "showNodeLabelDefault": "顯示新添加節點的標籤"
"clipboard": "剪貼簿",
"library": "庫",
"examples": "範例"
} }
}, },
"actions": { "actions": {
@ -204,8 +211,7 @@
}, },
"copyMessagePath": "已複製路徑", "copyMessagePath": "已複製路徑",
"copyMessageValue": "已複製數值", "copyMessageValue": "已複製數值",
"copyMessageValue_truncated": "已複製捨棄的數值", "copyMessageValue_truncated": "已複製捨棄的數值"
"selectNodes": "選擇上面的文本並複製到剪貼簿"
}, },
"deploy": { "deploy": {
"deploy": "部署", "deploy": "部署",
@ -237,7 +243,7 @@
"undeployedChanges": "您有未部署的更改。\n\n離開此頁面將丟失這些更改。", "undeployedChanges": "您有未部署的更改。\n\n離開此頁面將丟失這些更改。",
"improperlyConfigured": "工作區包含一些未正確配置的節點:", "improperlyConfigured": "工作區包含一些未正確配置的節點:",
"unknown": "工作區包含一些未知的節點類型:", "unknown": "工作區包含一些未知的節點類型:",
"confirm": "確定要部署嗎?", "confirm": "確定要部署嗎?",
"doNotWarn": "不要再對此發出警告", "doNotWarn": "不要再對此發出警告",
"conflict": "伺服器正在運行較新的一組流程。", "conflict": "伺服器正在運行較新的一組流程。",
"backgroundUpdate": "伺服器上的流程已更新。", "backgroundUpdate": "伺服器上的流程已更新。",
@ -300,8 +306,7 @@
"errors": { "errors": {
"noNodesSelected": "<strong>無法創建子流程</strong>: 未選擇節點", "noNodesSelected": "<strong>無法創建子流程</strong>: 未選擇節點",
"multipleInputsToSelection": "<strong>無法創建子流程</strong>: 多個輸入到了選擇" "multipleInputsToSelection": "<strong>無法創建子流程</strong>: 多個輸入到了選擇"
}, }
"format": "標記格式"
}, },
"editor": { "editor": {
"configEdit": "編輯", "configEdit": "編輯",
@ -316,17 +321,53 @@
"addNewType": "添加新的__type__節點", "addNewType": "添加新的__type__節點",
"nodeProperties": "節點屬性", "nodeProperties": "節點屬性",
"label": "Label", "label": "Label",
"color": "顏色",
"portLabels": "埠標籤", "portLabels": "埠標籤",
"labelInputs": "輸入", "labelInputs": "輸入",
"labelOutputs": "輸出", "labelOutputs": "輸出",
"settingIcon": "Icon", "settingIcon": "Icon",
"default": "默認",
"noDefaultLabel": "無", "noDefaultLabel": "無",
"defaultLabel": "使用默認標籤", "defaultLabel": "使用默認標籤",
"searchIcons": "搜尋 icons", "searchIcons": "搜尋圖標",
"useDefault": "使用默認", "useDefault": "使用默認",
"description": "描述", "description": "描述",
"show": "顯示", "show": "顯示",
"hide": "隱藏", "hide": "隱藏",
"locale": "選擇界面語言",
"icon": "圖標",
"inputType": "輸入類型",
"inputs": {
"input": "輸入",
"select": "選擇",
"checkbox": "復選框",
"spinner": "微調器",
"none": "空",
"hidden": "隱藏屬性"
},
"types": {
"str": "字符串",
"num": "數字",
"bool": "布爾",
"json": "JSON",
"bin": "buffer",
"env": "環境變量"
},
"menu": {
"input": "輸入",
"select": "選擇",
"checkbox": "復選框",
"spinner": "微調器",
"hidden": "僅標簽"
},
"select": {
"label": "標簽",
"value": "值"
},
"spinner": {
"min": "最小值",
"max": "最大值"
},
"errors": { "errors": {
"scopeChange": "更改範圍將使其他流程中的節點無法使用", "scopeChange": "更改範圍將使其他流程中的節點無法使用",
"invalidProperties": "無效的屬性:" "invalidProperties": "無效的屬性:"
@ -356,8 +397,9 @@
"cutNode": "剪切所選節點", "cutNode": "剪切所選節點",
"pasteNode": "粘貼節點", "pasteNode": "粘貼節點",
"undoChange": "撤銷上次執行的更改", "undoChange": "撤銷上次執行的更改",
"searchBox": "打開搜索框", "searchBox": "打開搜尋框",
"managePalette": "管理面板" "managePalette": "管理面板",
"actionList": "動作列表"
}, },
"library": { "library": {
"library": "庫", "library": "庫",
@ -371,28 +413,27 @@
"savedNodes": "保存的節點", "savedNodes": "保存的節點",
"savedType": "已保存__type__", "savedType": "已保存__type__",
"saveFailed": "保存失敗: __message__", "saveFailed": "保存失敗: __message__",
"newFolder": "新文件夾",
"types": { "types": {
"local": "本地", "local": "本地",
"examples": "例子" "examples": "例子"
}, },
"exportToLibrary": "將節點匯出到庫", "exportToLibrary": "將節點匯出到庫"
"filename": "檔案名",
"folder": "資料夾",
"filenamePlaceholder": "文件",
"fullFilenamePlaceholder": "a/b/文件",
"folderPlaceholder": "a/b",
"breadcrumb": "庫"
}, },
"palette": { "palette": {
"noInfo": "無可用資訊", "noInfo": "無可用資訊",
"filter": "過濾節點", "filter": "過濾節點",
"search": "搜模組", "search": "搜尋模組",
"addCategory": "添加新的...", "addCategory": "添加新的...",
"label": { "label": {
"subflows": "子流程", "subflows": "子流程",
"network": "網絡",
"common": "共通",
"input": "輸入", "input": "輸入",
"output": "輸出", "output": "輸出",
"function": "功能", "function": "功能",
"sequence": "序列",
"parser": "解析",
"social": "社交", "social": "社交",
"storage": "存儲", "storage": "存儲",
"analysis": "分析", "analysis": "分析",
@ -459,7 +500,7 @@
"sortRecent": "日期順序", "sortRecent": "日期順序",
"more": "增加__count__個", "more": "增加__count__個",
"errors": { "errors": {
"catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制瞭解更多資訊", "catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制瞭解更多資訊",
"installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊", "installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊",
"removeFailed": "無法刪除: __module__<br>__message__<br>查看日誌瞭解更多資訊", "removeFailed": "無法刪除: __module__<br>__message__<br>查看日誌瞭解更多資訊",
"updateFailed": "無法更新: __module__<br>__message__<br>查看日誌瞭解更多資訊", "updateFailed": "無法更新: __module__<br>__message__<br>查看日誌瞭解更多資訊",
@ -529,8 +570,10 @@
"none": "無", "none": "無",
"subflows": "子流程", "subflows": "子流程",
"flows": "流程", "flows": "流程",
"filterUnused": "未使用",
"filterAll": "所有", "filterAll": "所有",
"showAllConfigNodes": "顯示所有配置節點",
"filterUnused": "未使用",
"showAllUnusedConfigNodes": "顯示所有未使用的配置節點",
"filtered": "__count__ 個隱藏" "filtered": "__count__ 個隱藏"
}, },
"context": { "context": {
@ -543,7 +586,9 @@
"flow": "流程", "flow": "流程",
"global": "全局的", "global": "全局的",
"deleteConfirm": "你確定要刪除這個項目嗎?", "deleteConfirm": "你確定要刪除這個項目嗎?",
"autoRefresh": "自動刷新" "autoRefresh": "自動刷新",
"refrsh": "刷新",
"delete": "刪除"
}, },
"palette": { "palette": {
"name": "節點管理", "name": "節點管理",
@ -558,6 +603,7 @@
"noSummaryAvailable": "無可用摘要", "noSummaryAvailable": "無可用摘要",
"editDescription": "編輯專案描述", "editDescription": "編輯專案描述",
"editDependencies": "編輯項目依賴", "editDependencies": "編輯項目依賴",
"noDescriptionAvailable": "沒有可用的描述",
"editReadme": "Edit README.md", "editReadme": "Edit README.md",
"showProjectSettings": "顯示項目設置", "showProjectSettings": "顯示項目設置",
"projectSettings": { "projectSettings": {
@ -657,15 +703,15 @@
"moreCommits": "更多提交", "moreCommits": "更多提交",
"changeLocalBranch": "變更當地分支", "changeLocalBranch": "變更當地分支",
"createBranchPlaceholder": "查找或創建分支", "createBranchPlaceholder": "查找或創建分支",
"upstream": "上的", "upstream": "上的",
"localOverwrite": "您有可通过切换分支覆盖的本地更改。您必须先提交或撤销那些更改。", "localOverwrite": "您有可通過切換分支覆蓋的本地更改。您必須先提交或撤銷那些更改。",
"manageRemoteBranch": "管理遠程分支", "manageRemoteBranch": "管理遠程分支",
"unableToAccess": "無法訪問遠程存儲庫", "unableToAccess": "無法訪問遠程存儲庫",
"retry": "重試", "retry": "重試",
"setUpstreamBranch": "設置為上分支", "setUpstreamBranch": "設置為上分支",
"createRemoteBranchPlaceholder": "查找或創建遠程分支", "createRemoteBranchPlaceholder": "查找或創建遠程分支",
"trackedUpstreamBranch": "創建的分支將被設置為跟踪的上游分支。", "trackedUpstreamBranch": "創建的分支將被設置為跟蹤的上遊分支。",
"selectUpstreamBranch": "分支將被創建。 在下面選擇以將其設置為被跟踪的上游分支。", "selectUpstreamBranch": "分支將被創建。 在下面選擇以將其設置為被跟蹤的上遊分支。",
"pushFailed": "Push失敗因為遠程具有更多的最新提交。請先進行pull與merge然後再嘗試push。", "pushFailed": "Push失敗因為遠程具有更多的最新提交。請先進行pull與merge然後再嘗試push。",
"push": "push", "push": "push",
"pull": "pull", "pull": "pull",
@ -683,7 +729,7 @@
"minsAgo": "__count__分鐘前", "minsAgo": "__count__分鐘前",
"minsAgo_plural": "__count__分鐘前", "minsAgo_plural": "__count__分鐘前",
"secondsAgo": "秒前", "secondsAgo": "秒前",
"notTracking": "您的本地分支當前未跟遠程分支。", "notTracking": "您的本地分支當前未跟遠程分支。",
"statusUnmergedChanged": "您的存儲庫中有未合併的更改。您需要解決衝突並提交結果。", "statusUnmergedChanged": "您的存儲庫中有未合併的更改。您需要解決衝突並提交結果。",
"repositoryUpToDate": "您的存儲庫是最新的。", "repositoryUpToDate": "您的存儲庫是最新的。",
"commitsAhead": "您的倉庫領先遠程倉庫__count__次提交。您現在可以push這些提交。", "commitsAhead": "您的倉庫領先遠程倉庫__count__次提交。您現在可以push這些提交。",
@ -748,10 +794,23 @@
}, },
"jsonEditor": { "jsonEditor": {
"title": "JSON編輯器", "title": "JSON編輯器",
"format": "格式化JSON" "format": "格式化JSON",
"rawMode": "編輯 JSON",
"uiMode": "Visual編輯器",
"insertAbove": "在上方插入",
"insertBelow": "在下方插入",
"addItem": "添加項目",
"copyPath": "復制路徑到項目",
"expandItems": "展開項目",
"collapseItems": "收合項目",
"duplicate": "重復",
"error": {
"invalidJSON": "無效的JSON: "
}
}, },
"markdownEditor": { "markdownEditor": {
"title": "Markdown 編輯器", "title": "Markdown 編輯器",
"expand": "展開",
"format": "F使用markdown格式化", "format": "F使用markdown格式化",
"heading1": "Heading 1", "heading1": "Heading 1",
"heading2": "Heading 2", "heading2": "Heading 2",
@ -786,7 +845,7 @@
}, },
"git-config": { "git-config": {
"setup": "設置您的版本控制客戶端", "setup": "設置您的版本控制客戶端",
"desc0": "Node-RED使用開源工具Git進行版本控制。 它跟對項目文件的更改,並允許您將其推送到遠程存儲庫。", "desc0": "Node-RED使用開源工具Git進行版本控制。 它跟對項目文件的更改,並允許您將其推送到遠程存儲庫。",
"desc1": "提交一組更改時Git會使用用戶名和電子郵件地址記錄誰進行了更改。 用戶名可以是您想要的任何名稱-不必是您的真實姓名。", "desc1": "提交一組更改時Git會使用用戶名和電子郵件地址記錄誰進行了更改。 用戶名可以是您想要的任何名稱-不必是您的真實姓名。",
"desc2": "您的Git客戶端已經配置了以下詳細信息。", "desc2": "您的Git客戶端已經配置了以下詳細信息。",
"desc3": "您可以稍後在設置對話框的“ Git config”標籤下更改這些設置。", "desc3": "您可以稍後在設置對話框的“ Git config”標籤下更改這些設置。",
@ -905,7 +964,7 @@
"confirm": "您確定要刪除此項目嗎?" "confirm": "您確定要刪除此項目嗎?"
}, },
"create-project-list": { "create-project-list": {
"search": "搜您的項目", "search": "搜您的項目",
"current": "當前的" "current": "當前的"
}, },
"require-clean": { "require-clean": {
@ -938,8 +997,19 @@
}, },
"editor-tab": { "editor-tab": {
"properties": "屬性", "properties": "屬性",
"envProperties": "環境變量",
"description": "描述", "description": "描述",
"appearance": "外觀", "appearance": "外觀",
"preview": "UI預覽",
"defaultValue": "默認值",
"env": "環境變量" "env": "環境變量"
},
"languages": {
"de": "德語",
"en-US": "英語",
"ja": "日語",
"ko": "韓語",
"zh-CN": "簡體中文",
"zh-TW": "繁體中文"
} }
} }

View File

@ -214,5 +214,57 @@
"$toMillis": { "$toMillis": {
"args": "timestamp", "args": "timestamp",
"desc": "將ISO 8601格式的字串`timestamp`轉換為從UNIX時間 (1970年1月1日 UTC/GMT的午夜開始到現在的毫秒數。如果該字串的格式不正確則拋出錯誤。" "desc": "將ISO 8601格式的字串`timestamp`轉換為從UNIX時間 (1970年1月1日 UTC/GMT的午夜開始到現在的毫秒數。如果該字串的格式不正確則拋出錯誤。"
},
"$env": {
"args": "arg",
"desc": "返回環境變量的值。\n\n這是Node-RED定義的函數。"
},
"$eval": {
"args": "expr [, context]",
"desc": "使用當前上下文來作為評估依據,分析並評估字符串`expr`其中包含文字JSON或JSONata表達式。"
},
"$formatInteger": {
"args": "number, picture",
"desc": "將“數字”轉換為字符串並將其格式化為“圖片”字符串指定的整數表示形式。圖片字符串參數定義了數字的格式並具有與XPath F&O 3.1 規範中的fnformat-integer相同的語法。"
},
"$parseInteger": {
"args": "string, picture",
"desc": "使用“圖片”字符串指定的格式將“字符串”參數的內容解析為整數作為JSON數字。圖片字符串參數與$formatInteger格式相同。."
},
"$error": {
"args": "[str]",
"desc": "引發錯誤並顯示一條消息。 可選的`str`將替代$error()函數評估的默認消息。"
},
"$assert": {
"args": "arg, str",
"desc": "如果`arg`為真,則該函數返回。 如果arg為假則拋出帶有str的異常作為異常消息。"
},
"$single": {
"args": "array, function",
"desc": "返回滿足參數function謂語的array參數中的唯一值 (比如傳遞值時函數返回布林值“true”)。如果匹配值的數量不唯一時,則拋出異常。\n\n應在以下簽名中提供函數`functionvalue [index [array []]]`其中value是數組的每個輸入index是該值的位置整個數組作為第三個參數傳遞。"
},
"$encodeUrl": {
"args": "str",
"desc": "通過用表示字符的UTF-8編碼的一個兩個三個或四個轉義序列替換某些字符的每個實例對統一資源定位符URL組件進行編碼。\n\n示例`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "通過用表示字符的UTF-8編碼的一個兩個三個或四個轉義序列替換某些字符的每個實例對統一資源定位符URL進行編碼。\n\n示例 `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "解碼以前由encodeUrlComponent創建的統一資源定位器URL組件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "解碼先前由encodeUrl創建的統一資源定位符URL。 \n\n示例 `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "返回一個數組,其中重復的值已從`數組`中刪除"
},
"$type": {
"args": "value",
"desc": "以字符串形式返回`值`的類型。 如果該`值`未定義,則將返回`未定義`"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@node-red/editor-client", "name": "@node-red/editor-client",
"version": "1.0.3", "version": "1.1.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -32,11 +32,16 @@
} }
} }
} }
function emit(evt,arg) { function emit() {
var evt = arguments[0]
var args = Array.prototype.slice.call(arguments,1);
if (RED.events.DEBUG) {
console.log(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](arg); handlers[evt][i].apply(null, args);
} catch(err) { } catch(err) {
console.log("RED.events.emit error: ["+evt+"] "+(err.toString())); console.log("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.log(err); console.log(err);

View File

@ -21,6 +21,7 @@ RED.history = (function() {
var i; var i;
var len; var len;
var node; var node;
var group;
var subflow; var subflow;
var modifiedTabs = {}; var modifiedTabs = {};
var inverseEv; var inverseEv;
@ -74,6 +75,15 @@ RED.history = (function() {
RED.nodes.removeLink(ev.links[i]); RED.nodes.removeLink(ev.links[i]);
} }
} }
if (ev.groups) {
inverseEv.groups = [];
for (i=0;i<ev.groups.length;i++) {
group = ev.groups[i];
modifiedTabs[group.z] = true;
inverseEv.groups.push(group);
RED.nodes.removeGroup(group);
}
}
if (ev.workspaces) { if (ev.workspaces) {
inverseEv.workspaces = []; inverseEv.workspaces = [];
for (i=0;i<ev.workspaces.length;i++) { for (i=0;i<ev.workspaces.length;i++) {
@ -193,12 +203,35 @@ RED.history = (function() {
n.dirty = true; n.dirty = true;
}); });
} }
if (ev.groups) {
inverseEv.groups = [];
var groupsToAdd = new Set(ev.groups.map(function(g) { return g.id }));
for (i=0;i<ev.groups.length;i++) {
RED.nodes.addGroup(ev.groups[i])
modifiedTabs[ev.groups[i].z] = true;
inverseEv.groups.push(ev.groups[i]);
if (ev.groups[i].g && !groupsToAdd.has(ev.groups[i].g)) {
group = RED.nodes.group(ev.groups[i].g);
if (group.nodes.indexOf(ev.groups[i]) === -1) {
group.nodes.push(ev.groups[i]);
}
RED.group.markDirty(ev.groups[i])
}
}
}
if (ev.nodes) { if (ev.nodes) {
inverseEv.nodes = []; inverseEv.nodes = [];
for (i=0;i<ev.nodes.length;i++) { for (i=0;i<ev.nodes.length;i++) {
RED.nodes.add(ev.nodes[i]); RED.nodes.add(ev.nodes[i]);
modifiedTabs[ev.nodes[i].z] = true; modifiedTabs[ev.nodes[i].z] = true;
inverseEv.nodes.push(ev.nodes[i].id); inverseEv.nodes.push(ev.nodes[i].id);
if (ev.nodes[i].g) {
group = RED.nodes.group(ev.nodes[i].g);
if (group.nodes.indexOf(ev.nodes[i]) === -1) {
group.nodes.push(ev.nodes[i]);
}
RED.group.markDirty(group)
}
} }
} }
if (ev.links) { if (ev.links) {
@ -227,9 +260,12 @@ RED.history = (function() {
} }
node.dirty = true; node.dirty = true;
} }
RED.events.emit("nodes:change",node);
} }
} }
}
if (subflow) {
RED.events.emit("subflows:change", subflow);
} }
} else if (ev.t == "move") { } else if (ev.t == "move") {
inverseEv = { inverseEv = {
@ -260,6 +296,13 @@ RED.history = (function() {
RED.nodes.addLink(ev.removedLinks[i]); RED.nodes.addLink(ev.removedLinks[i]);
} }
} }
if (ev.addToGroup) {
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),true);
inverseEv.removeFromGroup = ev.addToGroup;
} else if (ev.removeFromGroup) {
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
inverseEv.addToGroup = ev.removeFromGroup;
}
} else if (ev.t == "edit") { } else if (ev.t == "edit") {
inverseEv = { inverseEv = {
t: "edit", t: "edit",
@ -283,6 +326,17 @@ RED.history = (function() {
ev.node[i] = ev.changes[i]; ev.node[i] = ev.changes[i];
} }
} }
var eventType;
switch(ev.node.type) {
case 'tab': eventType = "flows"; break;
case 'group': eventType = "groups"; break;
case 'subflow': eventType = "subflows"; break;
default: eventType = "nodes"; break;
}
eventType += ":change";
RED.events.emit(eventType,ev.node);
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) { if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled); $("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled); $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled);
@ -370,7 +424,9 @@ RED.history = (function() {
if (ev.nodes) { if (ev.nodes) {
inverseEv.movedNodes = []; inverseEv.movedNodes = [];
var z = ev.activeWorkspace; var z = ev.activeWorkspace;
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) { var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
fullNodeList.forEach(function(n) {
n.x += ev.subflow.offsetX; n.x += ev.subflow.offsetX;
n.y += ev.subflow.offsetY; n.y += ev.subflow.offsetY;
n.dirty = true; n.dirty = true;
@ -411,6 +467,9 @@ RED.history = (function() {
if (ev.subflow) { if (ev.subflow) {
RED.nodes.addSubflow(ev.subflow.subflow); RED.nodes.addSubflow(ev.subflow.subflow);
inverseEv.subflow = ev.subflow; inverseEv.subflow = ev.subflow;
if (ev.subflow.subflow.g) {
RED.group.addToGroup(RED.nodes.group(ev.subflow.subflow.g),ev.subflow.subflow);
}
} }
if (ev.subflows) { if (ev.subflows) {
inverseEv.nodes = []; inverseEv.nodes = [];
@ -422,6 +481,9 @@ RED.history = (function() {
if (ev.movedNodes) { if (ev.movedNodes) {
ev.movedNodes.forEach(function(nid) { ev.movedNodes.forEach(function(nid) {
nn = RED.nodes.node(nid); nn = RED.nodes.node(nid);
if (!nn) {
nn = RED.nodes.group(nid);
}
nn.x -= ev.subflow.offsetX; nn.x -= ev.subflow.offsetX;
nn.y -= ev.subflow.offsetY; nn.y -= ev.subflow.offsetY;
nn.dirty = true; nn.dirty = true;
@ -435,7 +497,7 @@ RED.history = (function() {
RED.nodes.addLink(ev.links[i]); RED.nodes.addLink(ev.links[i]);
} }
} }
if (ev.createdLinks) { if (ev.createdLinks) {
inverseEv.removedLinks = []; inverseEv.removedLinks = [];
for (i=0;i<ev.createdLinks.length;i++) { for (i=0;i<ev.createdLinks.length;i++) {
inverseEv.removedLinks.push(ev.createdLinks[i]); inverseEv.removedLinks.push(ev.createdLinks[i]);
@ -450,6 +512,60 @@ RED.history = (function() {
if (ev.order) { if (ev.order) {
RED.workspaces.order(ev.order); RED.workspaces.order(ev.order);
} }
} else if (ev.t == "createGroup") {
inverseEv = {
t: "ungroup",
dirty: RED.nodes.dirty(),
groups: []
}
if (ev.groups) {
for (i=0;i<ev.groups.length;i++) {
inverseEv.groups.push(ev.groups[i]);
RED.group.ungroup(ev.groups[i]);
}
}
} else if (ev.t == "ungroup") {
inverseEv = {
t: "createGroup",
dirty: RED.nodes.dirty(),
groups: []
}
if (ev.groups) {
for (i=0;i<ev.groups.length;i++) {
inverseEv.groups.push(ev.groups[i]);
var nodes = ev.groups[i].nodes.slice();
ev.groups[i].nodes = [];
RED.nodes.addGroup(ev.groups[i]);
RED.group.addToGroup(ev.groups[i],nodes);
}
}
} else if (ev.t == "addToGroup") {
inverseEv = {
t: "removeFromGroup",
dirty: RED.nodes.dirty(),
group: ev.group,
nodes: ev.nodes,
reparent: ev.reparent
}
if (ev.nodes) {
RED.group.removeFromGroup(ev.group,ev.nodes,(ev.hasOwnProperty('reparent')&&ev.hasOwnProperty('reparent')!==undefined)?ev.reparent:true);
}
} else if (ev.t == "removeFromGroup") {
inverseEv = {
t: "addToGroup",
dirty: RED.nodes.dirty(),
group: ev.group,
nodes: ev.nodes,
reparent: ev.reparent
}
if (ev.nodes) {
RED.group.addToGroup(ev.group,ev.nodes);
}
}
if(ev.callback && typeof ev.callback === 'function') {
inverseEv.callback = ev.callback;
ev.callback(ev);
} }
Object.keys(modifiedTabs).forEach(function(id) { Object.keys(modifiedTabs).forEach(function(id) {
@ -460,9 +576,8 @@ RED.history = (function() {
}); });
RED.nodes.dirty(ev.dirty); RED.nodes.dirty(ev.dirty);
RED.view.updateActive();
RED.view.select(null); RED.view.select(null);
RED.view.redraw(true);
RED.palette.refresh();
RED.workspaces.refresh(); RED.workspaces.refresh();
RED.sidebar.config.refresh(); RED.sidebar.config.refresh();
RED.subflow.refresh(); RED.subflow.refresh();
@ -482,6 +597,9 @@ RED.history = (function() {
list: function() { list: function() {
return undoHistory; return undoHistory;
}, },
listRedo: function() {
return redoHistory;
},
depth: function() { depth: function() {
return undoHistory.length; return undoHistory.length;
}, },

View File

@ -61,6 +61,10 @@
"shift-down": "core:step-selection-down", "shift-down": "core:step-selection-down",
"shift-left": "core:step-selection-left", "shift-left": "core:step-selection-left",
"ctrl-shift-j": "core:show-previous-tab", "ctrl-shift-j": "core:show-previous-tab",
"ctrl-shift-k": "core:show-next-tab" "ctrl-shift-k": "core:show-next-tab",
"ctrl-shift-g": "core:group-selection",
"ctrl-shift-u": "core:ungroup-selection",
"ctrl-shift-c": "core:copy-group-style",
"ctrl-shift-v": "core:paste-group-style"
} }
} }

View File

@ -27,13 +27,16 @@ RED.nodes = (function() {
var subflows = {}; var subflows = {};
var loadedFlowVersion = null; var loadedFlowVersion = null;
var groups = {};
var groupsByZ = {};
var initialLoad; var initialLoad;
var dirty = false; var dirty = false;
function setDirty(d) { function setDirty(d) {
dirty = d; dirty = d;
RED.events.emit("nodes:change",{dirty:dirty}); RED.events.emit("workspace:dirty",{dirty:dirty});
} }
var registry = (function() { var registry = (function() {
@ -225,6 +228,7 @@ RED.nodes = (function() {
} }
function addLink(l) { function addLink(l) {
links.push(l); links.push(l);
RED.events.emit("links:add",l);
} }
function getNode(id) { function getNode(id) {
@ -257,7 +261,7 @@ RED.nodes = (function() {
delete nodeTabMap[node.z][node.id]; delete nodeTabMap[node.z][node.id];
} }
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); }); removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
removedLinks.forEach(function(l) {links.splice(links.indexOf(l), 1); }); removedLinks.forEach(removeLink);
var updatedConfigNode = false; var updatedConfigNode = false;
for (var d in node._def.defaults) { for (var d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d)) { if (node._def.defaults.hasOwnProperty(d)) {
@ -302,6 +306,10 @@ RED.nodes = (function() {
} }
function moveNodeToTab(node, z) { function moveNodeToTab(node, z) {
if (node.type === "group") {
moveGroupToTab(node,z);
return;
}
if (nodeTabMap[node.z]) { if (nodeTabMap[node.z]) {
delete nodeTabMap[node.z][node.id]; delete nodeTabMap[node.z][node.id];
} }
@ -310,6 +318,15 @@ RED.nodes = (function() {
} }
nodeTabMap[z][node.id] = node; nodeTabMap[z][node.id] = node;
node.z = z; node.z = z;
RED.events.emit("nodes:change",node);
}
function moveGroupToTab(group, z) {
var index = groupsByZ[group.z].indexOf(group);
groupsByZ[group.z].splice(index,1);
groupsByZ[z] = groupsByZ[z] || [];
groupsByZ[z].push(group);
group.z = z;
RED.events.emit("groups:change",group);
} }
function removeLink(l) { function removeLink(l) {
@ -317,6 +334,7 @@ RED.nodes = (function() {
if (index != -1) { if (index != -1) {
links.splice(index,1); links.splice(index,1);
} }
RED.events.emit("links:remove",l);
} }
function addWorkspace(ws,targetIndex) { function addWorkspace(ws,targetIndex) {
@ -329,38 +347,53 @@ RED.nodes = (function() {
} else { } else {
workspacesOrder.splice(targetIndex,0,ws.id); workspacesOrder.splice(targetIndex,0,ws.id);
} }
RED.events.emit('flows:add',ws);
if (targetIndex !== undefined) {
RED.events.emit('flows:reorder',workspacesOrder)
}
} }
function getWorkspace(id) { function getWorkspace(id) {
return workspaces[id]; return workspaces[id];
} }
function removeWorkspace(id) { function removeWorkspace(id) {
delete workspaces[id]; var ws = workspaces[id];
delete nodeTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var removedNodes = []; var removedNodes = [];
var removedLinks = []; var removedLinks = [];
var n; var removedGroups = [];
var node; if (ws) {
for (n=0;n<nodes.length;n++) { delete workspaces[id];
node = nodes[n]; delete nodeTabMap[id];
if (node.z == id) { workspacesOrder.splice(workspacesOrder.indexOf(id),1);
removedNodes.push(node); var n;
} var node;
} for (n=0;n<nodes.length;n++) {
for(n in configNodes) { node = nodes[n];
if (configNodes.hasOwnProperty(n)) {
node = configNodes[n];
if (node.z == id) { if (node.z == id) {
removedNodes.push(node); removedNodes.push(node);
} }
} }
for(n in configNodes) {
if (configNodes.hasOwnProperty(n)) {
node = configNodes[n];
if (node.z == id) {
removedNodes.push(node);
}
}
}
removedGroups = groupsByZ[id] || [];
removedGroups.forEach(function(g) {
delete groups[g.id]
})
delete groupsByZ[id];
for (n=0;n<removedNodes.length;n++) {
var result = removeNode(removedNodes[n].id);
removedLinks = removedLinks.concat(result.links);
}
RED.events.emit('flows:remove',ws);
} }
for (n=0;n<removedNodes.length;n++) {
var result = removeNode(removedNodes[n].id); return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
removedLinks = removedLinks.concat(result.links);
}
return {nodes:removedNodes,links:removedLinks};
} }
function addSubflow(sf, createNewIds) { function addSubflow(sf, createNewIds) {
@ -417,14 +450,18 @@ RED.nodes = (function() {
} }
}); });
sf._def = RED.nodes.getType("subflow:"+sf.id); sf._def = RED.nodes.getType("subflow:"+sf.id);
RED.events.emit("subflows:add",sf);
} }
function getSubflow(id) { function getSubflow(id) {
return subflows[id]; return subflows[id];
} }
function removeSubflow(sf) { function removeSubflow(sf) {
delete subflows[sf.id]; if (subflows[sf.id]) {
delete nodeTabMap[sf.id]; delete subflows[sf.id];
registry.removeNodeType("subflow:"+sf.id); delete nodeTabMap[sf.id];
registry.removeNodeType("subflow:"+sf.id);
RED.events.emit("subflows:remove",sf);
}
} }
function subflowContains(sfid,nodeid) { function subflowContains(sfid,nodeid) {
@ -497,6 +534,9 @@ RED.nodes = (function() {
if (n.d === true) { if (n.d === true) {
node.d = true; node.d = true;
} }
if (n.g) {
node.g = n.g;
}
if (node.type == "unknown") { if (node.type == "unknown") {
for (var p in n._orig) { for (var p in n._orig) {
if (n._orig.hasOwnProperty(p)) { if (n._orig.hasOwnProperty(p)) {
@ -544,6 +584,13 @@ RED.nodes = (function() {
} }
} }
} }
if (n.type === "group") {
node.x = n.x;
node.y = n.y;
node.w = n.w;
node.h = n.h;
node.nodes = node.nodes.map(function(n) { return n.id });
}
if (n._def.category != "config") { if (n._def.category != "config") {
node.x = n.x; node.x = n.x;
node.y = n.y; node.y = n.y;
@ -669,8 +716,18 @@ RED.nodes = (function() {
/** /**
* Converts the current node selection to an exportable JSON Object * Converts the current node selection to an exportable JSON Object
**/ **/
function createExportableNodeSet(set, exportedSubflows, exportedConfigNodes) { function createExportableNodeSet(set, exportedIds, exportedSubflows, exportedConfigNodes) {
var nns = []; var nns = [];
exportedIds = exportedIds || {};
set = set.filter(function(n) {
if (exportedIds[n.id]) {
return false;
}
exportedIds[n.id] = true;
return true;
})
exportedConfigNodes = exportedConfigNodes || {}; exportedConfigNodes = exportedConfigNodes || {};
exportedSubflows = exportedSubflows || {}; exportedSubflows = exportedSubflows || {};
for (var n=0;n<set.length;n++) { for (var n=0;n<set.length;n++) {
@ -686,11 +743,11 @@ RED.nodes = (function() {
subflowSet.push(n); subflowSet.push(n);
} }
}); });
var exportableSubflow = createExportableNodeSet(subflowSet, exportedSubflows, exportedConfigNodes); var exportableSubflow = createExportableNodeSet(subflowSet, exportedIds, exportedSubflows, exportedConfigNodes);
nns = exportableSubflow.concat(nns); nns = exportableSubflow.concat(nns);
} }
} }
if (node.type != "subflow") { if (node.type !== "subflow") {
var convertedNode = RED.nodes.convertNode(node); var convertedNode = RED.nodes.convertNode(node);
for (var d in node._def.defaults) { for (var d in node._def.defaults) {
if (node._def.defaults[d].type && node[d] in configNodes) { if (node._def.defaults[d].type && node[d] in configNodes) {
@ -707,6 +764,9 @@ RED.nodes = (function() {
} }
} }
nns.push(convertedNode); nns.push(convertedNode);
if (node.type === "group") {
nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes));
}
} else { } else {
var convertedSubflow = convertSubflow(node); var convertedSubflow = convertSubflow(node);
nns.push(convertedSubflow); nns.push(convertedSubflow);
@ -732,6 +792,11 @@ RED.nodes = (function() {
nns.push(convertSubflow(subflows[i], exportCredentials)); nns.push(convertSubflow(subflows[i], exportCredentials));
} }
} }
for (i in groups) {
if (groups.hasOwnProperty(i)) {
nns.push(convertNode(groups[i]));
}
}
for (i in configNodes) { for (i in configNodes) {
if (configNodes.hasOwnProperty(i)) { if (configNodes.hasOwnProperty(i)) {
nns.push(convertNode(configNodes[i], exportCredentials)); nns.push(convertNode(configNodes[i], exportCredentials));
@ -858,6 +923,7 @@ RED.nodes = (function() {
if (n.type != "workspace" && if (n.type != "workspace" &&
n.type != "tab" && n.type != "tab" &&
n.type != "subflow" && n.type != "subflow" &&
n.type != "group" &&
!registry.getNodeType(n.type) && !registry.getNodeType(n.type) &&
n.type.substring(0,8) != "subflow:" && n.type.substring(0,8) != "subflow:" &&
unknownTypes.indexOf(n.type)==-1) { unknownTypes.indexOf(n.type)==-1) {
@ -907,6 +973,7 @@ RED.nodes = (function() {
var node_map = {}; var node_map = {};
var new_nodes = []; var new_nodes = [];
var new_links = []; var new_links = [];
var new_groups = [];
var nid; var nid;
var def; var def;
var configNode; var configNode;
@ -1057,7 +1124,6 @@ RED.nodes = (function() {
} }
node_map[n.id] = configNode; node_map[n.id] = configNode;
new_nodes.push(configNode); new_nodes.push(configNode);
RED.nodes.add(configNode);
} }
} }
} }
@ -1074,20 +1140,25 @@ RED.nodes = (function() {
y:parseFloat(n.y || 0), y:parseFloat(n.y || 0),
z:n.z, z:n.z,
type:0, type:0,
wires:n.wires||[],
inputLabels: n.inputLabels,
outputLabels: n.outputLabels,
icon: n.icon,
info: n.info, info: n.info,
changed:false, changed:false,
_config:{} _config:{}
}; }
if (n.type !== "group") {
node.wires = n.wires||[];
node.inputLabels = n.inputLabels;
node.outputLabels = n.outputLabels;
node.icon = n.icon;
}
if (n.hasOwnProperty('l')) { if (n.hasOwnProperty('l')) {
node.l = n.l; node.l = n.l;
} }
if (n.hasOwnProperty('d')) { if (n.hasOwnProperty('d')) {
node.d = n.d; node.d = n.d;
} }
if (n.hasOwnProperty('g')) {
node.g = n.g;
}
if (createNewIds) { if (createNewIds) {
if (subflow_blacklist[n.z]) { if (subflow_blacklist[n.z]) {
continue; continue;
@ -1124,7 +1195,17 @@ RED.nodes = (function() {
} }
node.type = n.type; node.type = n.type;
node._def = def; node._def = def;
if (n.type.substring(0,7) === "subflow") { if (node.type === "group") {
node._def = RED.group.def;
for (d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
node[d] = n[d];
node._config[d] = JSON.stringify(n[d]);
}
}
node._config.x = node.x;
node._config.y = node.y;
} else if (n.type.substring(0,7) === "subflow") {
var parentId = n.type.split(":")[1]; var parentId = n.type.split(":")[1];
var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId); var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId);
if (createNewIds) { if (createNewIds) {
@ -1145,7 +1226,7 @@ RED.nodes = (function() {
defaults: {}, defaults: {},
label: "unknown: "+n.type, label: "unknown: "+n.type,
labelStyle: "red-ui-flow-node-label-italic", labelStyle: "red-ui-flow-node-label-italic",
outputs: n.outputs||n.wires.length, outputs: n.outputs|| (n.wires && n.wires.length) || 0,
set: registry.getNodeSet("node-red/unknown") set: registry.getNodeSet("node-red/unknown")
} }
} else { } else {
@ -1214,13 +1295,13 @@ RED.nodes = (function() {
} }
} }
} }
addNode(node);
RED.editor.validateNode(node);
node_map[n.id] = node; node_map[n.id] = node;
// If an 'unknown' config node, it will not have been caught by the // If an 'unknown' config node, it will not have been caught by the
// proper config node handling, so needs adding to new_nodes here // proper config node handling, so needs adding to new_nodes here
if (node.type === "unknown" || node._def.category !== "config") { if (node.type === "unknown" || node._def.category !== "config") {
new_nodes.push(node); new_nodes.push(node);
} else if (node.type === "group") {
new_groups.push(node);
} }
} }
} }
@ -1255,6 +1336,11 @@ RED.nodes = (function() {
} }
delete n.wires; delete n.wires;
} }
if (n.g && node_map[n.g]) {
n.g = node_map[n.g].id;
} else {
delete n.g
}
for (var d3 in n._def.defaults) { for (var d3 in n._def.defaults) {
if (n._def.defaults.hasOwnProperty(d3)) { if (n._def.defaults.hasOwnProperty(d3)) {
if (n._def.defaults[d3].type && node_map[n[d3]]) { if (n._def.defaults[d3].type && node_map[n[d3]]) {
@ -1323,9 +1409,27 @@ RED.nodes = (function() {
delete n.status.wires; delete n.status.wires;
} }
} }
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
if (n.g && node_map[n.g]) {
n.g = node_map[n.g].id;
} else {
delete n.g;
}
n.nodes = n.nodes.map(function(id) {
return node_map[id];
})
addGroup(n);
}
// Now the nodes have been fully updated, add them.
for (i=0;i<new_nodes.length;i++) {
var node = new_nodes[i];
addNode(node);
RED.editor.validateNode(node);
}
RED.workspaces.refresh(); RED.workspaces.refresh();
return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace]; return [new_nodes,new_links,new_groups,new_workspaces,new_subflows,missingWorkspace];
} }
// TODO: supports filter.z|type // TODO: supports filter.z|type
@ -1416,6 +1520,9 @@ RED.nodes = (function() {
nodeTabMap = {}; nodeTabMap = {};
configNodes = {}; configNodes = {};
workspacesOrder = []; workspacesOrder = [];
groups = {};
groupsByZ = {};
var subflowIds = Object.keys(subflows); var subflowIds = Object.keys(subflows);
subflowIds.forEach(function(id) { subflowIds.forEach(function(id) {
RED.subflow.removeSubflow(id) RED.subflow.removeSubflow(id)
@ -1433,6 +1540,8 @@ RED.nodes = (function() {
RED.sidebar.config.refresh(); RED.sidebar.config.refresh();
RED.sidebar.info.refresh(); RED.sidebar.info.refresh();
RED.events.emit("workspace:clear");
// var node_defs = {}; // var node_defs = {};
// var nodes = []; // var nodes = [];
// var configNodes = {}; // var configNodes = {};
@ -1444,6 +1553,29 @@ RED.nodes = (function() {
// var loadedFlowVersion = null; // var loadedFlowVersion = null;
} }
function addGroup(group) {
groupsByZ[group.z] = groupsByZ[group.z] || [];
groupsByZ[group.z].push(group);
groups[group.id] = group;
RED.events.emit("groups:add",group);
}
function removeGroup(group) {
var i = groupsByZ[group.z].indexOf(group);
groupsByZ[group.z].splice(i,1);
if (group.g) {
if (groups[group.g]) {
var index = groups[group.g].nodes.indexOf(group);
groups[group.g].nodes.splice(index,1);
}
}
RED.group.markDirty(group);
delete groups[group.id];
RED.events.emit("groups:remove",group);
}
return { return {
init: function() { init: function() {
RED.events.on("registry:node-type-added",function(type) { RED.events.on("registry:node-type-added",function(type) {
@ -1470,6 +1602,9 @@ RED.nodes = (function() {
delete configNodes[n.id]; delete configNodes[n.id];
} else { } else {
nodes.splice(nodes.indexOf(n),1); nodes.splice(nodes.indexOf(n),1);
if (nodeTabMap[n.z]) {
delete nodeTabMap[n.z][n.id];
}
} }
reimportList.push(convertNode(n)); reimportList.push(convertNode(n));
}); });
@ -1484,8 +1619,9 @@ RED.nodes = (function() {
}); });
removeLinks.forEach(removeLink); removeLinks.forEach(removeLink);
// Force the redraw to be synchronous so the view updates
RED.view.redraw(true); // *now* and removes the unknown node
RED.view.redraw(true, true);
var result = importNodes(reimportList,false); var result = importNodes(reimportList,false);
var newNodeMap = {}; var newNodeMap = {};
result[0].forEach(function(n) { result[0].forEach(function(n) {
@ -1539,6 +1675,11 @@ RED.nodes = (function() {
subflow: getSubflow, subflow: getSubflow,
subflowContains: subflowContains, subflowContains: subflowContains,
addGroup: addGroup,
removeGroup: removeGroup,
group: function(id) { return groups[id] },
groups: function(z) { return groupsByZ[z]||[] },
eachNode: function(cb) { eachNode: function(cb) {
for (var n=0;n<nodes.length;n++) { for (var n=0;n<nodes.length;n++) {
if (cb(nodes[n]) === false) { if (cb(nodes[n]) === false) {

View File

@ -0,0 +1,33 @@
(function() {
var isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
if (isIE11) {
// IE11 does not provide classList on SVGElements
if (! ("classList" in SVGElement.prototype)) {
Object.defineProperty(SVGElement.prototype, 'classList', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'classList'));
}
// IE11 does not provide children on SVGElements
if (! ("children" in SVGElement.prototype)) {
Object.defineProperty(SVGElement.prototype, 'children', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'children'));
}
Array.from = function() {
if (arguments.length > 1) {
throw new Error("Node-RED's IE11 Array.from polyfill doesn't support multiple arguments");
}
var arrayLike = arguments[0]
var result = [];
if (arrayLike.forEach) {
arrayLike.forEach(function(i) {
result.push(i);
})
} else {
for (var i=0;i<arrayLike.length;i++) {
result.push(arrayList[i]);
}
}
return result;
}
}
})();

View File

@ -75,6 +75,7 @@ var RED = (function() {
} }
function loadNodeList() { function loadNodeList() {
loader.reportProgress(RED._("event.loadPalette"), 20)
$.ajax({ $.ajax({
headers: { headers: {
"Accept":"application/json" "Accept":"application/json"
@ -83,6 +84,7 @@ var RED = (function() {
url: 'nodes', url: 'nodes',
success: function(data) { success: function(data) {
RED.nodes.setNodeList(data); RED.nodes.setNodeList(data);
loader.reportProgress(RED._("event.loadNodeCatalogs"), 25)
RED.i18n.loadNodeCatalogs(function() { RED.i18n.loadNodeCatalogs(function() {
loadIconList(loadNodes); loadIconList(loadNodes);
}); });
@ -107,6 +109,7 @@ var RED = (function() {
} }
function loadNodes() { function loadNodes() {
loader.reportProgress(RED._("event.loadNodes",{count:""}), 30)
var lang = localStorage.getItem("editor-language")||i18n.detectLanguage(); var lang = localStorage.getItem("editor-language")||i18n.detectLanguage();
$.ajax({ $.ajax({
@ -118,15 +121,19 @@ var RED = (function() {
url: 'nodes', url: 'nodes',
success: function(data) { success: function(data) {
var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/); var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/);
var totalCount = configs.length;
var stepConfig = function() { var stepConfig = function() {
loader.reportProgress(RED._("event.loadNodes",{count:(totalCount-configs.length)+"/"+totalCount}), 30 + ((totalCount-configs.length)/totalCount)*40 )
if (configs.length === 0) { if (configs.length === 0) {
$("#red-ui-editor").i18n(); $("#red-ui-editor").i18n();
$("#red-ui-palette > .red-ui-palette-spinner").hide(); $("#red-ui-palette > .red-ui-palette-spinner").hide();
$(".red-ui-palette-scroll").removeClass("hide"); $(".red-ui-palette-scroll").removeClass("hide");
$("#red-ui-palette-search").removeClass("hide"); $("#red-ui-palette-search").removeClass("hide");
loadFlows(function() { if (RED.settings.theme("projects.enabled",false)) {
if (RED.settings.theme("projects.enabled",false)) { RED.projects.refresh(function(activeProject) {
RED.projects.refresh(function(activeProject) { loadFlows(function() {
RED.sidebar.info.refresh() RED.sidebar.info.refresh()
if (!activeProject) { if (!activeProject) {
// Projects enabled but no active project // Projects enabled but no active project
@ -140,12 +147,14 @@ var RED = (function() {
} }
completeLoad(); completeLoad();
}); });
} else { });
} else {
loadFlows(function() {
// Projects disabled by the user // Projects disabled by the user
RED.sidebar.info.refresh() RED.sidebar.info.refresh()
completeLoad(); completeLoad();
} });
}); }
} else { } else {
var config = configs.shift(); var config = configs.shift();
appendNodeConfig(config,stepConfig); appendNodeConfig(config,stepConfig);
@ -157,6 +166,7 @@ var RED = (function() {
} }
function loadFlows(done) { function loadFlows(done) {
loader.reportProgress(RED._("event.loadFlows"),80 )
$.ajax({ $.ajax({
headers: { headers: {
"Accept":"application/json", "Accept":"application/json",
@ -167,6 +177,7 @@ var RED = (function() {
if (nodes) { if (nodes) {
var currentHash = window.location.hash; var currentHash = window.location.hash;
RED.nodes.version(nodes.rev); RED.nodes.version(nodes.rev);
loader.reportProgress(RED._("event.importFlows"),90 )
RED.nodes.import(nodes.flows); RED.nodes.import(nodes.flows);
RED.nodes.dirty(false); RED.nodes.dirty(false);
RED.view.redraw(true); RED.view.redraw(true);
@ -193,6 +204,7 @@ var RED = (function() {
return; return;
} }
if (notificationId === "project-update") { if (notificationId === "project-update") {
loader.start("Loading project",0)
RED.nodes.clear(); RED.nodes.clear();
RED.history.clear(); RED.history.clear();
RED.view.redraw(true); RED.view.redraw(true);
@ -208,6 +220,7 @@ var RED = (function() {
"revert": RED._("notification.project.revert", {project: msg.project}), "revert": RED._("notification.project.revert", {project: msg.project}),
"merge-complete": RED._("notification.project.merge-complete") "merge-complete": RED._("notification.project.merge-complete")
}[msg.action]; }[msg.action];
loader.end()
RED.notify("<p>"+message+"</p>"); RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh() RED.sidebar.info.refresh()
}); });
@ -423,6 +436,12 @@ var RED = (function() {
var id = topic.substring(9); var id = topic.substring(9);
RED.eventLog.log(id,payload); RED.eventLog.log(id,payload);
}); });
$(".red-ui-header-toolbar").show();
setTimeout(function() {
loader.end();
},100);
} }
function showAbout() { function showAbout() {
@ -431,8 +450,7 @@ var RED = (function() {
'<img width="50px" src="red/images/node-red-icon.svg" />'+ '<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>'; '</div>';
RED.sidebar.info.set(aboutHeader+marked(data)); RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data));
RED.sidebar.info.show();
}); });
} }
@ -472,6 +490,14 @@ var RED = (function() {
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:"core:create-subflow"}, {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"}, {id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:"core:convert-to-subflow"},
]}); ]});
menuOptions.push({id:"menu-item-group",label:RED._("menu.label.groups"), options: [
{id:"menu-item-group-group",label:RED._("menu.label.groupSelection"),disabled:true,onselect:"core:group-selection"},
{id:"menu-item-group-ungroup",label:RED._("menu.label.ungroupSelection"),disabled:true,onselect:"core:ungroup-selection"},
null,
{id:"menu-item-group-merge",label:RED._("menu.label.groupMergeSelection"),disabled:true,onselect:"core:merge-selection-to-group"},
{id:"menu-item-group-remove",label:RED._("menu.label.groupRemoveSelection"),disabled:true,onselect:"core:remove-selection-from-group"}
]});
menuOptions.push(null); menuOptions.push(null);
if (RED.settings.theme('palette.editable') !== false) { 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({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"});
@ -497,7 +523,6 @@ var RED = (function() {
} }
function loadEditor() { function loadEditor() {
RED.workspaces.init(); RED.workspaces.init();
RED.statusBar.init(); RED.statusBar.init();
RED.view.init(); RED.view.init();
@ -524,6 +549,7 @@ var RED = (function() {
} }
RED.subflow.init(); RED.subflow.init();
RED.group.init();
RED.clipboard.init(); RED.clipboard.init();
RED.search.init(); RED.search.init();
RED.actionList.init(); RED.actionList.init();
@ -539,13 +565,14 @@ var RED = (function() {
RED.comms.connect(); RED.comms.connect();
$("#red-ui-main-container").show(); $("#red-ui-main-container").show();
$(".red-ui-header-toolbar").show();
RED.actions.add("core:show-about", showAbout); RED.actions.add("core:show-about", showAbout);
loadNodeList(); loadNodeList();
} }
function buildEditor(options) { function buildEditor(options) {
var header = $('<div id="red-ui-header"></div>').appendTo(options.target); var header = $('<div id="red-ui-header"></div>').appendTo(options.target);
var logo = $('<span class="red-ui-header-logo"></span>').appendTo(header); var logo = $('<span class="red-ui-header-logo"></span>').appendTo(header);
@ -560,6 +587,10 @@ var RED = (function() {
'</div>').appendTo(options.target); '</div>').appendTo(options.target);
$('<div id="red-ui-editor-node-configs"></div>').appendTo(options.target); $('<div id="red-ui-editor-node-configs"></div>').appendTo(options.target);
$('<div id="red-ui-full-shade" class="hide"></div>').appendTo(options.target); $('<div id="red-ui-full-shade" class="hide"></div>').appendTo(options.target);
loader.init().appendTo("#red-ui-main-container");
loader.start("...",0);
$.getJSON(options.apiRootUrl+"theme", function(theme) { $.getJSON(options.apiRootUrl+"theme", function(theme) {
if (theme.header) { if (theme.header) {
if (theme.header.url) { if (theme.header.url) {
@ -592,12 +623,39 @@ var RED = (function() {
options.target.addClass("red-ui-editor"); options.target.addClass("red-ui-editor");
buildEditor(options); buildEditor(options);
RED.i18n.init(options, function() { RED.i18n.init(options, function() {
RED.settings.init(options, loadEditor); RED.settings.init(options, loadEditor);
}) })
} }
var loader = {
init: function() {
var wrapper = $('<div id="red-ui-loading-progress"></div>').hide();
var container = $('<div>').appendTo(wrapper);
var label = $('<div>',{class:"red-ui-loading-bar-label"}).appendTo(container);
var bar = $('<div>',{class:"red-ui-loading-bar"}).appendTo(container);
var fill =$('<span>').appendTo(bar);
return wrapper;
},
start: function(text, prcnt) {
if (text) {
loader.reportProgress(text,prcnt)
}
$("#red-ui-loading-progress").show();
},
reportProgress: function(text, prcnt) {
$(".red-ui-loading-bar-label").text(text);
$(".red-ui-loading-bar span").width(prcnt+"%")
},
end: function() {
$("#red-ui-loading-progress").hide();
loader.reportProgress("",0);
}
}
return { return {
init: init init: init,
loader: loader
} }
})(); })();

View File

@ -184,7 +184,7 @@ RED.clipboard = (function() {
'</div>'+ '</div>'+
'<div id="red-ui-clipboard-dialog-export-tabs-content" class="red-ui-clipboard-dialog-tabs-content">'+ '<div id="red-ui-clipboard-dialog-export-tabs-content" class="red-ui-clipboard-dialog-tabs-content">'+
'<div id="red-ui-clipboard-dialog-export-tab-clipboard" class="red-ui-clipboard-dialog-tab-clipboard">'+ '<div id="red-ui-clipboard-dialog-export-tab-clipboard" class="red-ui-clipboard-dialog-tab-clipboard">'+
'<div class="form-row">'+ '<div class="form-row" style="height:calc(100% - 30px)">'+
'<textarea readonly id="red-ui-clipboard-dialog-export-text"></textarea>'+ '<textarea readonly id="red-ui-clipboard-dialog-export-text"></textarea>'+
'</div>'+ '</div>'+
'<div class="form-row" style="text-align: right;">'+ '<div class="form-row" style="text-align: right;">'+
@ -216,7 +216,7 @@ RED.clipboard = (function() {
' <a class="red-ui-button" id="red-ui-clipboard-dialog-import-file-upload-btn"><i class="fa fa-upload"></i> <span data-i18n="clipboard.selectFile"></span></a>'+ ' <a class="red-ui-button" id="red-ui-clipboard-dialog-import-file-upload-btn"><i class="fa fa-upload"></i> <span data-i18n="clipboard.selectFile"></span></a>'+
'<input type="file" id="red-ui-clipboard-dialog-import-file-upload" accept=".json" style="display:none">'+ '<input type="file" id="red-ui-clipboard-dialog-import-file-upload" accept=".json" style="display:none">'+
'</div>'+ '</div>'+
'<div class="form-row">'+ '<div class="form-row" style="height:calc(100% - 47px)">'+
'<textarea id="red-ui-clipboard-dialog-import-text"></textarea>'+ '<textarea id="red-ui-clipboard-dialog-import-text"></textarea>'+
'</div>'+ '</div>'+
'</div>'+ '</div>'+
@ -474,6 +474,12 @@ RED.clipboard = (function() {
},100) },100)
} }
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 600) {
dialogHeight = 400 - (600 - winHeight);
}
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open"); dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
popover = RED.popover.create({ popover = RED.popover.create({
@ -583,6 +589,7 @@ RED.clipboard = (function() {
nodes = []; nodes = [];
selection.forEach(function(n) { selection.forEach(function(n) {
nodes.push(n); nodes.push(n);
nodes = nodes.concat(RED.nodes.groups(n.id));
nodes = nodes.concat(RED.nodes.filterNodes({z:n.id})); nodes = nodes.concat(RED.nodes.filterNodes({z:n.id}));
}); });
} else { } else {
@ -592,7 +599,8 @@ RED.clipboard = (function() {
nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'})); nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'}));
} else if (type === 'red-ui-clipboard-dialog-export-rng-flow') { } else if (type === 'red-ui-clipboard-dialog-export-rng-flow') {
var activeWorkspace = RED.workspaces.active(); var activeWorkspace = RED.workspaces.active();
nodes = RED.nodes.filterNodes({z:activeWorkspace}); nodes = RED.nodes.groups(activeWorkspace);
nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace}));
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace); var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
nodes.unshift(parentNode); nodes.unshift(parentNode);
nodes = RED.nodes.createExportableNodeSet(nodes); nodes = RED.nodes.createExportableNodeSet(nodes);
@ -637,6 +645,14 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click"); $("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
} }
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode); tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode);
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 600) {
dialogHeight = 400 - (600 - winHeight);
}
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" ); dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
$("#red-ui-clipboard-dialog-export-text").trigger("focus"); $("#red-ui-clipboard-dialog-export-text").trigger("focus");
@ -738,6 +754,8 @@ RED.clipboard = (function() {
RED.actions.add("core:show-library-export-dialog",function() { exportNodes('library') }); RED.actions.add("core:show-library-export-dialog",function() { exportNodes('library') });
RED.actions.add("core:show-library-import-dialog",function() { importNodes('library') }); RED.actions.add("core:show-library-import-dialog",function() { importNodes('library') });
RED.actions.add("core:show-examples-import-dialog",function() { importNodes('examples') });
RED.events.on("editor:open",function() { disabled = true; }); RED.events.on("editor:open",function() { disabled = true; });
RED.events.on("editor:close",function() { disabled = false; }); RED.events.on("editor:close",function() { disabled = false; });
RED.events.on("search:open",function() { disabled = true; }); RED.events.on("search:open",function() { disabled = true; });

View File

@ -0,0 +1,203 @@
RED.colorPicker = (function() {
function create(options) {
var color = options.value;
var id = options.id;
var colorPalette = options.palette || [];
var width = options.cellWidth || 30;
var height = options.cellHeight || 30;
var margin = options.cellMargin || 2;
var perRow = options.cellPerRow || 6;
var container = $("<div>",{style:"display:inline-block"});
var colorHiddenInput = $("<input/>", { id: id, type: "hidden", value: color }).appendTo(container);
var opacityHiddenInput = $("<input/>", { id: id+"-opacity", type: "hidden", value: options.hasOwnProperty('opacity')?options.opacity:"1" }).appendTo(container);
var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container);
$('<i class="fa fa-caret-down"></i>').appendTo(colorButton);
var colorDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton);
$('<div>',{class:"red-ui-color-picker-cell-none"}).appendTo(colorDispContainer);
var colorDisp = $('<div>',{class:"red-ui-color-picker-swatch"}).appendTo(colorDispContainer);
var refreshDisplay = function(color) {
if (color === "none") {
colorDisp.addClass('red-ui-color-picker-cell-none').css({
"background-color": "",
opacity: 1
});
colorDispContainer.css({
"border-color":""
})
} else {
var opacity = parseFloat(opacityHiddenInput.val())
colorDisp.removeClass('red-ui-color-picker-cell-none').css({
"background-color": color,
"opacity": opacity
});
var border = RED.utils.getDarkerColor(color);
if (border[0] === '#') {
border += Math.round(255*Math.floor(opacity*100)/100).toString(16);
} else {
border = "";
}
colorDispContainer.css({
"border-color": border
})
}
if (options.hasOwnProperty('opacity')) {
$(".red-ui-color-picker-opacity-slider-overlay").css({
"background-image": "linear-gradient(90deg, transparent 0%, "+color+" 100%)"
})
}
}
colorButton.on("click", function (e) {
var numColors = colorPalette.length;
var picker = $("<div/>", {
class: "red-ui-color-picker"
}).css({
width: ((width+margin+margin)*perRow)+"px",
height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px"
});
var count = 0;
var row = null;
row = $("<div/>").appendTo(picker);
var colorInput = $('<input>',{
type:"text",
value:colorHiddenInput.val()
}).appendTo(row);
colorInput.on("change", function (e) {
var color = colorInput.val();
colorHiddenInput.val(color).trigger('change');
refreshDisplay(color);
});
// if (options.hasOwnProperty('opacity')) {
// var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider"
// }
if (options.none) {
row = $("<div/>").appendTo(picker);
var button = $("<button/>", {
class:"red-ui-color-picker-cell red-ui-color-picker-cell-none"
}).css({
width: width+"px",
height: height+"px",
margin: margin+"px"
}).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
colorInput.val("none");
colorInput.trigger("change");
});
}
colorPalette.forEach(function (col) {
if ((count % perRow) == 0) {
row = $("<div/>").appendTo(picker);
}
var button = $("<button/>", {
class:"red-ui-color-picker-cell"
}).css({
width: width+"px",
height: height+"px",
margin: margin+"px",
backgroundColor: col,
"border-color": RED.utils.getDarkerColor(col)
}).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
// colorPanel.hide();
colorInput.val(col);
colorInput.trigger("change");
});
count++;
});
if (options.none || options.hasOwnProperty('opacity')) {
row = $("<div/>").appendTo(picker);
// if (options.none) {
// var button = $("<button/>", {
// class:"red-ui-color-picker-cell red-ui-color-picker-cell-none"
// }).css({
// width: width+"px",
// height: height+"px",
// margin: margin+"px"
// }).appendTo(row);
// button.on("click", function (e) {
// e.preventDefault();
// colorPanel.hide();
// selector.val("none");
// selector.trigger("change");
// });
// }
if (options.hasOwnProperty('opacity')) {
var sliderContainer = $("<div>",{class:"red-ui-color-picker-opacity-slider"}).appendTo(row);
sliderContainer.on("mousedown", function(evt) {
if (evt.target === sliderHandle[0]) {
return;
}
var v = evt.offsetX/sliderContainer.width();
sliderHandle.css({
left: ( v*(sliderContainer.width() - sliderHandle.outerWidth()))+"px"
});
v = Math.floor(100*v)
opacityHiddenInput.val(v/100)
opacityLabel.text(v+"%");
refreshDisplay(colorHiddenInput.val());
})
$("<div>",{class:"red-ui-color-picker-opacity-slider-overlay"}).appendTo(sliderContainer);
var sliderHandle = $("<div>",{class:"red-ui-color-picker-opacity-slider-handle red-ui-button red-ui-button-small"}).appendTo(sliderContainer).draggable({
containment: "parent",
axis: "x",
drag: function( event, ui ) {
var v = Math.max(0,ui.position.left/($(this).parent().width()-$(this).outerWidth()));
// Odd bug that if it is loaded with a non-0 value, the first time
// it is dragged it ranges -1 to 99. But every other time, its 0 to 100.
// The Math.max above makes the -1 disappear. The follow hack ensures
// it always maxes out at a 100, at the cost of not allowing 99% exactly.
v = Math.floor(100*v)
if ( v === 99 ) {
v = 100;
}
// console.log("uip",ui.position.left);
opacityHiddenInput.val(v/100)
opacityLabel.text(v+"%");
refreshDisplay(colorHiddenInput.val());
}
});
var opacityLabel = $('<small></small>').appendTo(row);
setTimeout(function() {
sliderHandle.css({
left: (parseFloat(opacityHiddenInput.val())*(sliderContainer.width() - sliderHandle.outerWidth()))+"px"
})
opacityLabel.text(Math.floor(opacityHiddenInput.val()*100)+"%");
},50);
}
}
var colorPanel = RED.popover.panel(picker);
setTimeout(function() {
refreshDisplay(colorHiddenInput.val())
},50);
colorPanel.show({
target: colorButton
})
});
setTimeout(function() {
refreshDisplay(colorHiddenInput.val())
},50);
return container;
}
return {
create: create
}
})();

View File

@ -183,7 +183,7 @@
if (this.options.resizeItem) { if (this.options.resizeItem) {
var that = this; var that = this;
this.element.children().each(function(i) { this.element.children().each(function(i) {
that.options.resizeItem($(this).find(".red-ui-editableList-item-content"),i); that.options.resizeItem($(this).children(".red-ui-editableList-item-content"),i);
}); });
} }
}, },
@ -223,7 +223,7 @@
var items = this.element.children(); var items = this.element.children();
var that = this; var that = this;
items.sort(function(A,B) { items.sort(function(A,B) {
return that.activeSort($(A).find(".red-ui-editableList-item-content").data('data'),$(B).find(".red-ui-editableList-item-content").data('data')); return that.activeSort($(A).children(".red-ui-editableList-item-content").data('data'),$(B).children(".red-ui-editableList-item-content").data('data'));
}); });
$.each(items,function(idx,li) { $.each(items,function(idx,li) {
that.element.append(li); that.element.append(li);
@ -305,7 +305,7 @@
} }
if (this.options.addItem) { if (this.options.addItem) {
var index = that.element.children().length-1; var index = that.element.children().length-1;
setTimeout(function() { // setTimeout(function() {
that.options.addItem(row,index,data); that.options.addItem(row,index,data);
if (that.activeFilter) { if (that.activeFilter) {
try { try {
@ -321,7 +321,7 @@
that.uiContainer.scrollTop(that.element.height()); that.uiContainer.scrollTop(that.element.height());
},0); },0);
} }
},0); // },0);
} }
}, },
addItem: function(data) { addItem: function(data) {
@ -334,7 +334,7 @@
}, },
removeItem: function(data) { removeItem: function(data) {
var items = this.element.children().filter(function(f) { var items = this.element.children().filter(function(f) {
return data === $(this).find(".red-ui-editableList-item-content").data('data'); return data === $(this).children(".red-ui-editableList-item-content").data('data');
}); });
items.remove(); items.remove();
if (this.options.removeItem) { if (this.options.removeItem) {
@ -342,7 +342,7 @@
} }
}, },
items: function() { items: function() {
return this.element.children().map(function(i) { return $(this).find(".red-ui-editableList-item-content"); }); return this.element.children().map(function(i) { return $(this).children(".red-ui-editableList-item-content"); });
}, },
empty: function() { empty: function() {
this.element.empty(); this.element.empty();
@ -365,14 +365,14 @@
}, },
show: function(item) { show: function(item) {
var items = this.element.children().filter(function(f) { var items = this.element.children().filter(function(f) {
return item === $(this).find(".red-ui-editableList-item-content").data('data'); return item === $(this).children(".red-ui-editableList-item-content").data('data');
}); });
if (items.length > 0) { if (items.length > 0) {
this.uiContainer.scrollTop(this.uiContainer.scrollTop()+items.position().top) this.uiContainer.scrollTop(this.uiContainer.scrollTop()+items.position().top)
} }
}, },
getItem: function(li) { getItem: function(li) {
var el = li.find(".red-ui-editableList-item-content"); var el = li.children(".red-ui-editableList-item-content");
if (el.length) { if (el.length) {
return el.data('data'); return el.data('data');
} else { } else {

View File

@ -29,6 +29,10 @@ RED.panels = (function() {
if (!vertical) { if (!vertical) {
container.addClass("red-ui-panels-horizontal"); container.addClass("red-ui-panels-horizontal");
} }
$(children[0]).addClass("red-ui-panel");
$(children[1]).addClass("red-ui-panel");
var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]); var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
var startPosition; var startPosition;
var panelSizes = []; var panelSizes = [];
@ -52,11 +56,11 @@ RED.panels = (function() {
var newSizes = [panelSizes[0]+delta,panelSizes[1]-delta]; var newSizes = [panelSizes[0]+delta,panelSizes[1]-delta];
if (vertical) { if (vertical) {
$(children[0]).height(newSizes[0]); $(children[0]).height(newSizes[0]);
$(children[1]).height(newSizes[1]); // $(children[1]).height(newSizes[1]);
ui.position.top -= delta; ui.position.top -= delta;
} else { } else {
$(children[0]).width(newSizes[0]); $(children[0]).width(newSizes[0]);
$(children[1]).width(newSizes[1]); // $(children[1]).width(newSizes[1]);
ui.position.left -= delta; ui.position.left -= delta;
} }
if (options.resize) { if (options.resize) {
@ -71,6 +75,9 @@ RED.panels = (function() {
var panel = { var panel = {
ratio: function(ratio) { ratio: function(ratio) {
if (ratio === undefined) {
return panelRatio;
}
panelRatio = ratio; panelRatio = ratio;
modifiedSizes = true; modifiedSizes = true;
if (ratio === 0 || ratio === 1) { if (ratio === 0 || ratio === 1) {
@ -99,10 +106,10 @@ RED.panels = (function() {
panelSizes = [topPanelSize,bottomPanelSize]; panelSizes = [topPanelSize,bottomPanelSize];
if (vertical) { if (vertical) {
$(children[0]).outerHeight(panelSizes[0]); $(children[0]).outerHeight(panelSizes[0]);
$(children[1]).outerHeight(panelSizes[1]); // $(children[1]).outerHeight(panelSizes[1]);
} else { } else {
$(children[0]).outerWidth(panelSizes[0]); $(children[0]).outerWidth(panelSizes[0]);
$(children[1]).outerWidth(panelSizes[1]); // $(children[1]).outerWidth(panelSizes[1]);
} }
} }
if (options.resize) { if (options.resize) {

View File

@ -136,6 +136,23 @@ RED.popover = (function() {
closePopup(true); closePopup(true);
}); });
} }
if (trigger === 'hover' && options.interactive) {
div.on('mouseenter', function(e) {
clearTimeout(timer);
active = true;
})
div.on('mouseleave', function(e) {
if (timer) {
clearTimeout(timer);
}
if (active) {
timer = setTimeout(function() {
active = false;
closePopup();
},delay.hide);
}
})
}
if (instant) { if (instant) {
div.show(); div.show();
} else { } else {
@ -163,8 +180,10 @@ RED.popover = (function() {
if (trigger === 'hover') { if (trigger === 'hover') {
target.on('mouseenter',function(e) { target.on('mouseenter',function(e) {
clearTimeout(timer); clearTimeout(timer);
active = true; if (!active) {
timer = setTimeout(openPopup,delay.show); active = true;
timer = setTimeout(openPopup,delay.show);
}
}); });
target.on('mouseleave disabled', function(e) { target.on('mouseleave disabled', function(e) {
if (timer) { if (timer) {
@ -278,6 +297,7 @@ RED.popover = (function() {
var closeCallback = options.onclose; var closeCallback = options.onclose;
var target = options.target; var target = options.target;
var align = options.align || "left"; var align = options.align || "left";
var offset = options.offset || [0,0];
var pos = target.offset(); var pos = target.offset();
var targetWidth = target.width(); var targetWidth = target.width();
@ -285,7 +305,7 @@ RED.popover = (function() {
var panelHeight = panel.height(); var panelHeight = panel.height();
var panelWidth = panel.width(); var panelWidth = panel.width();
var top = (targetHeight+pos.top); var top = (targetHeight+pos.top) + offset[1];
if (top+panelHeight > $(window).height()) { if (top+panelHeight > $(window).height()) {
top -= (top+panelHeight)-$(window).height() + 5; top -= (top+panelHeight)-$(window).height() + 5;
} }
@ -296,12 +316,12 @@ RED.popover = (function() {
if (align === "left") { if (align === "left") {
panel.css({ panel.css({
top: top+"px", top: top+"px",
left: (pos.left)+"px", left: (pos.left+offset[0])+"px",
}); });
} else if(align === "right") { } else if(align === "right") {
panel.css({ panel.css({
top: top+"px", top: top+"px",
left: (pos.left-panelWidth)+"px", left: (pos.left-panelWidth+offset[0])+"px",
}); });
} }
panel.slideDown(100); panel.slideDown(100);

View File

@ -38,7 +38,10 @@
this.element.addClass("red-ui-searchBox-input"); this.element.addClass("red-ui-searchBox-input");
this.uiContainer = this.element.wrap("<div>").parent(); this.uiContainer = this.element.wrap("<div>").parent();
this.uiContainer.addClass("red-ui-searchBox-container"); this.uiContainer.addClass("red-ui-searchBox-container");
if (this.element.parents("form").length === 0) {
var form = this.element.wrap("<form>").parent();
form.addClass("red-ui-searchBox-form");
}
$('<i class="fa fa-search"></i>').prependTo(this.uiContainer); $('<i class="fa fa-search"></i>').prependTo(this.uiContainer);
this.clearButton = $('<a href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer); this.clearButton = $('<a href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer);
this.clearButton.on("click",function(e) { this.clearButton.on("click",function(e) {

View File

@ -27,7 +27,8 @@
* *
* methods: * methods:
* - data(items) - clears existing items and replaces with new data * - data(items) - clears existing items and replaces with new data
* * - clearSelection - clears the selected items
* - filter(filterFunc) - filters the tree using the provided function
* events: * events:
* - treelistselect : function(event, item) {} * - treelistselect : function(event, item) {}
* - treelistconfirm : function(event,item) {} * - treelistconfirm : function(event,item) {}
@ -39,7 +40,8 @@
* label: 'Local', // label for the item * label: 'Local', // label for the item
* sublabel: 'Local', // a sub-label for the item * sublabel: 'Local', // a sub-label for the item
* icon: 'fa fa-rocket', // (optional) icon for the item * icon: 'fa fa-rocket', // (optional) icon for the item
* selected: true/false, // (optional) if present, display checkbox accordingly * checkbox: true/false, // (optional) if present, display checkbox accordingly
* selected: true/false, // (optional) whether the item is selected or not
* children: [] | function(done,item) // (optional) an array of child items, or a function * children: [] | function(done,item) // (optional) an array of child items, or a function
* // that will call the `done` callback with an array * // that will call the `done` callback with an array
* // of child items * // of child items
@ -59,9 +61,9 @@
* properties and functions: * properties and functions:
* *
* item.parent - set to the parent item * item.parent - set to the parent item
* item.depth - the depth in the tree (0 == root)
* item.treeList.container * item.treeList.container
* item.treeList.label - the label element for the item * item.treeList.label - the label element for the item
* item.treeList.depth - the depth in the tree (0 == root)
* item.treeList.parentList - the editableList instance this item is in * item.treeList.parentList - the editableList instance this item is in
* item.treeList.remove() - removes the item from the tree * item.treeList.remove() - removes the item from the tree
* item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node, * item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node,
@ -78,8 +80,8 @@
* Optionally selects the item after adding. * Optionally selects the item after adding.
* item.treeList.expand(done) - expands the parent item to show children. Optional 'done' callback. * item.treeList.expand(done) - expands the parent item to show children. Optional 'done' callback.
* item.treeList.collapse() - collapse the parent item to hide children. * item.treeList.collapse() - collapse the parent item to hide children.
* * item.treeList.sortChildren(sortFunction) - does a one-time sort of the children using sortFunction
* * item.treeList.replaceElement(element) - replace the custom element for the item
* *
* *
*/ */
@ -100,6 +102,8 @@
var target; var target;
switch(evt.keyCode) { switch(evt.keyCode) {
case 13: // ENTER case 13: // ENTER
evt.preventDefault();
evt.stopPropagation();
if (selected.children) { if (selected.children) {
if (selected.treeList.container.hasClass("expanded")) { if (selected.treeList.container.hasClass("expanded")) {
selected.treeList.collapse() selected.treeList.collapse()
@ -112,6 +116,8 @@
break; break;
case 37: // LEFT case 37: // LEFT
evt.preventDefault();
evt.stopPropagation();
if (selected.children&& selected.treeList.container.hasClass("expanded")) { if (selected.children&& selected.treeList.container.hasClass("expanded")) {
selected.treeList.collapse() selected.treeList.collapse()
} else if (selected.parent) { } else if (selected.parent) {
@ -119,6 +125,8 @@
} }
break; break;
case 38: // UP case 38: // UP
evt.preventDefault();
evt.stopPropagation();
target = that._getPreviousSibling(selected); target = that._getPreviousSibling(selected);
if (target) { if (target) {
target = that._getLastDescendant(target); target = that._getLastDescendant(target);
@ -128,6 +136,8 @@
} }
break; break;
case 39: // RIGHT case 39: // RIGHT
evt.preventDefault();
evt.stopPropagation();
if (selected.children) { if (selected.children) {
if (!selected.treeList.container.hasClass("expanded")) { if (!selected.treeList.container.hasClass("expanded")) {
selected.treeList.expand() selected.treeList.expand()
@ -135,6 +145,8 @@
} }
break break
case 40: //DOWN case 40: //DOWN
evt.preventDefault();
evt.stopPropagation();
if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) { if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) {
target = selected.children[0]; target = selected.children[0];
} else { } else {
@ -151,7 +163,8 @@
} }
}); });
this._data = []; this._data = [];
this._items = {};
this._selected = new Set();
this._topList = $('<ol class="red-ui-treeList-list">').css({ this._topList = $('<ol class="red-ui-treeList-list">').css({
position:'absolute', position:'absolute',
top: 0, top: 0,
@ -244,7 +257,8 @@
that._trigger("changeparent",null,evt); that._trigger("changeparent",null,evt);
}); });
that._trigger("sort",null,parent); that._trigger("sort",null,parent);
} },
filter: parent.treeList.childFilter
}); });
if (!!that.options.sortable) { if (!!that.options.sortable) {
subtree.addClass('red-ui-treeList-sortable'); subtree.addClass('red-ui-treeList-sortable');
@ -289,21 +303,171 @@
} }
return reparentedEvent; return reparentedEvent;
}, },
_addSubtree: function(parentList, container, item, depth) { _initItem: function(item,depth) {
if (item.treeList) {
return;
}
var that = this; var that = this;
this._items[item.id] = item;
item.treeList = {}; item.treeList = {};
item.treeList.depth = depth; item.depth = depth;
item.treeList.container = container;
item.treeList.parentList = parentList;
item.treeList.remove = function() { item.treeList.remove = function() {
parentList.editableList('removeItem',item); if (item.treeList.parentList) {
item.treeList.parentList.editableList('removeItem',item);
}
if (item.parent) { if (item.parent) {
var index = item.parent.children.indexOf(item); var index = item.parent.children.indexOf(item);
item.parent.children.splice(index,1) item.parent.children.splice(index,1)
that._trigger("sort",null,item.parent); that._trigger("sort",null,item.parent);
} }
that._selected.delete(item);
delete item.treeList;
delete(that._items[item.id]);
} }
item.treeList.insertChildAt = function(newItem,position,select) {
newItem.parent = item;
item.children.splice(position,0,newItem);
var processChildren = function(parent,i) {
that._initItem(i,parent.depth+1)
i.parent = parent;
if (i.children && typeof i.children !== 'function') {
i.children.forEach(function(item) {
processChildren(i, item, parent.depth+2)
});
}
}
processChildren(item,newItem);
if (!item.deferBuild) {
item.treeList.childList.editableList('insertItemAt',newItem,position)
if (select) {
setTimeout(function() {
that.select(newItem)
},100);
}
that._trigger("sort",null,item);
}
}
item.treeList.addChild = function(newItem,select) {
item.treeList.insertChildAt(newItem,item.children.length,select);
}
item.treeList.expand = function(done) {
if (!item.children) {
if (done) { done(false) }
return;
}
if (!item.treeList.container) {
item.expanded = true;
if (done) { done(false) }
return;
}
var container = item.treeList.container;
if (container.hasClass("expanded")) {
if (done) { done(false) }
return;
}
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
container.addClass('built');
var childrenAdded = false;
var spinner;
var startTime = 0;
var completeBuild = function(children) {
childrenAdded = true;
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
var delta = Date.now() - startTime;
if (delta < 400) {
setTimeout(function() {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
},400-delta);
} else {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
}
item.expanded = true;
if (done) { done(true) }
that._trigger("childrenloaded",null,item)
}
if (typeof item.children === 'function') {
item.children(completeBuild,item);
} else {
delete item.deferBuild;
completeBuild(item.children);
}
if (!childrenAdded) {
startTime = Date.now();
spinner = $('<div class="red-ui-treeList-spinner">').css({
"background-position": (35+depth*20)+'px 50%'
}).appendTo(container);
}
} else {
if (that._loadingData) {
item.treeList.childList.show();
} else {
item.treeList.childList.slideDown('fast');
}
item.expanded = true;
if (done) { done(!that._loadingData) }
}
container.addClass("expanded");
}
item.treeList.collapse = function() {
if (!item.children) {
return;
}
item.expanded = false;
if (item.treeList.container) {
item.treeList.childList.slideUp('fast');
item.treeList.container.removeClass("expanded");
}
}
item.treeList.sortChildren = function(sortFunc) {
if (!item.children) {
return;
}
item.children.sort(sortFunc);
if (item.treeList.childList) {
// Do a one-off sort of the list, which means calling sort twice:
// 1. first with the desired sort function
item.treeList.childList.editableList('sort',sortFunc);
// 2. and then with null to remove it
item.treeList.childList.editableList('sort',null);
}
}
item.treeList.replaceElement = function (element) {
if (item.element) {
if (item.treeList.container) {
$(item.element).remove();
$(element).appendTo(item.treeList.label);
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(item.depth*20);
$(element).css({
width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
})
}
item.element = element;
}
}
if (item.children && typeof item.children !== "function") {
item.children.forEach(function(i) {
that._initItem(i,depth+1);
})
}
},
_addSubtree: function(parentList, container, item, depth) {
var that = this;
this._initItem(item,depth);
// item.treeList = {};
// item.treeList.depth = depth;
item.treeList.container = container;
item.treeList.parentList = parentList;
var label = $("<div>",{class:"red-ui-treeList-label"}).appendTo(container); var label = $("<div>",{class:"red-ui-treeList-label"}).appendTo(container);
item.treeList.label = label; item.treeList.label = label;
@ -357,6 +521,7 @@
treeListIcon.off("click.red-ui-treeList-expand"); treeListIcon.off("click.red-ui-treeList-expand");
delete item.children; delete item.children;
container.removeClass("expanded"); container.removeClass("expanded");
delete item.expanded;
} }
item.treeList.makeParent = function(children) { item.treeList.makeParent = function(children) {
if (treeListIcon.children().length) { if (treeListIcon.children().length) {
@ -388,101 +553,25 @@
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide(); item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
} }
} }
item.treeList.insertChildAt = function(newItem,position,select) {
newItem.parent = item;
item.children.splice(position,0,newItem);
if (!item.deferBuild) {
item.treeList.childList.editableList('insertItemAt',newItem,position)
if (select) {
setTimeout(function() {
that.select(newItem)
},100);
}
that._trigger("sort",null,item);
}
}
item.treeList.addChild = function(newItem,select) {
item.treeList.insertChildAt(newItem,item.children.length,select);
}
item.treeList.expand = function(done) {
if (!item.children) {
return;
}
if (container.hasClass("expanded")) {
if (done) { done() }
return;
}
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
container.addClass('built');
var childrenAdded = false;
var spinner;
var startTime = 0;
var completeBuild = function(children) {
childrenAdded = true;
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
var delta = Date.now() - startTime;
if (delta < 400) {
setTimeout(function() {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
},400-delta);
} else {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
}
if (done) { done() }
that._trigger("childrenloaded",null,item)
}
if (typeof item.children === 'function') {
item.children(completeBuild,item);
} else {
delete item.deferBuild;
completeBuild(item.children);
}
if (!childrenAdded) {
startTime = Date.now();
spinner = $('<div class="red-ui-treeList-spinner">').css({
"background-position": (35+depth*20)+'px 50%'
}).appendTo(container);
}
} else {
if (that._loadingData) {
item.treeList.childList.show();
} else {
item.treeList.childList.slideDown('fast');
}
if (done) { done() }
}
container.addClass("expanded");
}
item.treeList.collapse = function() {
if (!item.children) {
return;
}
item.treeList.childList.slideUp('fast');
container.removeClass("expanded");
}
var treeListIcon = $('<span class="red-ui-treeList-icon"></span>').appendTo(label); var treeListIcon = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
if (item.children) { if (item.children) {
item.treeList.makeParent(); item.treeList.makeParent();
} }
if (item.hasOwnProperty('selected')) { if (item.checkbox) {
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>').appendTo(label); var selectWrapper = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
var cb = $('<input class="red-ui-treeList-checkbox" type="checkbox">').prop('checked',item.selected).appendTo(selectWrapper); var cb = $('<input class="red-ui-treeList-checkbox" type="checkbox">').prop('checked',item.selected).appendTo(selectWrapper);
label.toggleClass("selected",item.selected);
cb.on('click', function(e) { cb.on('click', function(e) {
e.stopPropagation(); e.stopPropagation();
}); });
cb.on('change', function(e) { cb.on('change', function(e) {
item.selected = this.checked; item.selected = this.checked;
if (item.selected) {
that._selected.add(item);
} else {
that._selected.delete(item);
}
label.toggleClass("selected",this.checked); label.toggleClass("selected",this.checked);
that._trigger("select",e,item); that._trigger("select",e,item);
}) })
@ -499,8 +588,12 @@
} }
} else { } else {
label.on("click", function(e) { label.on("click", function(e) {
that._topList.find(".selected").removeClass("selected"); if (!that.options.multi) {
that.clearSelection();
}
label.addClass("selected"); label.addClass("selected");
that._selected.add(item);
that._trigger("select",e,item) that._trigger("select",e,item)
}) })
label.on("dblclick", function(e) { label.on("dblclick", function(e) {
@ -508,9 +601,30 @@
that._trigger("confirm",e,item); that._trigger("confirm",e,item);
} }
}) })
item.treeList.select = function(v) {
if (!that.options.multi) {
that.clearSelection();
}
label.toggleClass("selected",v);
if (v) {
that._selected.add(item);
that._trigger("select",null,item)
} else {
that._selected.delete(item);
}
that.reveal(item);
}
}
label.toggleClass("selected",!!item.selected);
if (item.selected) {
that._selected.add(item);
} }
if (item.icon) { if (item.icon) {
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label); if (typeof item.icon === "string") {
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
} else {
$('<span class="red-ui-treeList-icon">').appendTo(label).append(item.icon);
}
} }
if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) { if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) {
if (item.hasOwnProperty('label')) { if (item.hasOwnProperty('label')) {
@ -542,6 +656,7 @@
var that = this; var that = this;
if (items !== undefined) { if (items !== undefined) {
this._data = items; this._data = items;
this._items = {};
this._topList.editableList('empty'); this._topList.editableList('empty');
this._loadingData = true; this._loadingData = true;
for (var i=0; i<items.length;i++) { for (var i=0; i<items.length;i++) {
@ -556,33 +671,142 @@
return this._data; return this._data;
} }
}, },
show: function(id) { show: function(item, done) {
for (var i=0;i<this._data.length;i++) { if (typeof item === "string") {
if (this._data[i].id === id) { item = this._items[item]
this._topList.editableList('show',this._data[i]); }
if (!item) {
return;
}
var that = this;
var stack = [];
var i = item;
while(i) {
stack.unshift(i);
i = i.parent;
}
var isOpening = false;
var handleStack = function(opening) {
isOpening = isOpening ||opening
var item = stack.shift();
if (stack.length === 0) {
setTimeout(function() {
that.reveal(item);
if (done) { done(); }
},isOpening?200:0);
} else {
item.treeList.expand(handleStack)
} }
} }
handleStack();
}, },
select: function(item) { reveal: function(item) {
this._topList.find(".selected").removeClass("selected"); if (typeof item === "string") {
item.treeList.label.addClass("selected"); item = this._items[item]
this._trigger("select",null,item) }
if (!item) {
return;
}
var listOffset = this._topList.offset().top;
var itemOffset = item.treeList.label.offset().top;
var scrollTop = this._topList.parent().scrollTop();
itemOffset -= listOffset+scrollTop;
var treeHeight = this._topList.parent().height();
var itemHeight = item.treeList.label.outerHeight();
if (itemOffset < itemHeight/2) {
this._topList.parent().scrollTop(scrollTop+itemOffset-itemHeight/2-itemHeight)
} else if (itemOffset+itemHeight > treeHeight) {
this._topList.parent().scrollTop(scrollTop+((itemOffset+2.5*itemHeight)-treeHeight));
}
},
select: function(item, triggerEvent, deselectExisting) {
var that = this;
if (!this.options.multi && deselectExisting !== false) {
this.clearSelection();
}
if (Array.isArray(item)) {
item.forEach(function(i) {
that.select(i,triggerEvent,false);
})
return;
}
if (typeof item === "string") {
item = this._items[item]
}
if (!item) {
return;
}
// this.show(item.id);
item.selected = true;
this._selected.add(item);
if (item.treeList.label) {
item.treeList.label.addClass("selected");
}
if (triggerEvent !== false) {
this._trigger("select",null,item)
}
},
clearSelection: function() {
this._selected.forEach(function(item) {
item.selected = false;
if (item.treeList.label) {
item.treeList.label.removeClass("selected")
}
});
this._selected.clear();
}, },
selected: function() { selected: function() {
var s = this._topList.find(".selected"); var selected = [];
this._selected.forEach(function(item) {
selected.push(item);
})
if (this.options.multi) { if (this.options.multi) {
var res = []; return selected;
s.each(function() {
res.push($(this).parent().data('data'));
})
return res;
} }
if (s.length) { if (selected.length) {
return s.parent().data('data'); return selected[0]
} else { } else {
// TODO: This may be a bug.. it causes the call to return itself
// not undefined.
return undefined; return undefined;
} }
},
filter: function(filterFunc,expandResults) {
var filter = function(item) {
var matchCount = 0;
if (filterFunc && filterFunc(item)) {
matchCount++;
}
var childCount = 0;
if (item.children && typeof item.children !== "function") {
if (item.treeList.childList) {
childCount = item.treeList.childList.editableList('filter', filter);
} else {
item.treeList.childFilter = filter;
if (filterFunc) {
item.children.forEach(function(i) {
if (filter(i)) {
childCount++;
}
})
}
}
matchCount += childCount;
if (childCount > 0) {
item.treeList.expand();
}
}
if (!filterFunc) {
return true
}
return matchCount > 0
}
return this._topList.editableList('filter', filter);
},
get: function(id) {
return this._items[id] || null;
} }
}); });

View File

@ -568,56 +568,6 @@
done(labelWidth); done(labelWidth);
} }
}, },
_resize: function() {
var that = this;
if (this.uiWidth !== null) {
this.uiSelect.width(this.uiWidth);
}
var type = this.typeMap[this.propertyType];
if (type && type.hasValue === false) {
this.selectTrigger.addClass("red-ui-typedInput-full-width");
} else {
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
this._getLabelWidth(this.selectTrigger, function(labelWidth) {
that.elementDiv.css('left',labelWidth+"px");
that.valueLabelContainer.css('left',labelWidth+"px");
if (that.optionExpandButton.shown) {
that.elementDiv.css('right',"22px");
that.valueLabelContainer.css('right',"22px");
} else {
that.elementDiv.css('right','0');
that.valueLabelContainer.css('right','0');
that.input.css({
'border-top-right-radius': '4px',
'border-bottom-right-radius': '4px'
});
}
if (that.optionSelectTrigger) {
if (type && type.options && type.hasValue === true) {
that.optionSelectLabel.css({'left':'auto'})
that._getLabelWidth(that.optionSelectLabel, function(lw) {
that.optionSelectTrigger.css({'width':(23+lw)+"px"});
that.elementDiv.css('right',(23+lw)+"px");
that.input.css({
'border-top-right-radius': 0,
'border-bottom-right-radius': 0
});
});
} else {
that.optionSelectLabel.css({'left':'0'})
that.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'});
if (!that.optionExpandButton.shown) {
that.elementDiv.css({'right':0});
that.input.css({
'border-top-right-radius': '4px',
'border-bottom-right-radius': '4px'
});
}
}
}
});
}
},
_updateOptionSelectLabel: function(o) { _updateOptionSelectLabel: function(o) {
var opt = this.typeMap[this.propertyType]; var opt = this.typeMap[this.propertyType];
this.optionSelectLabel.empty(); this.optionSelectLabel.empty();
@ -645,7 +595,6 @@
} }
if (opt.hasValue) { if (opt.hasValue) {
this.optionValue = o.value; this.optionValue = o.value;
this._resize();
this.input.trigger('change',this.propertyType,this.value()); this.input.trigger('change',this.propertyType,this.value());
} }
} else { } else {
@ -685,11 +634,12 @@
this.propertyType = null; this.propertyType = null;
this.type(currentType); this.type(currentType);
} }
setTimeout(function() {that._resize();},0);
}, },
width: function(desiredWidth) { width: function(desiredWidth) {
this.uiWidth = desiredWidth; this.uiWidth = desiredWidth;
this._resize(); if (this.uiWidth !== null) {
this.uiSelect.width(this.uiWidth);
}
}, },
value: function(value) { value: function(value) {
var that = this; var that = this;
@ -760,8 +710,6 @@
} }
else if (opt.icon.indexOf("/") !== -1) { else if (opt.icon.indexOf("/") !== -1) {
image = new Image(); image = new Image();
image.onload = function() { that._resize(); }
image.onerror = function() { that._resize(); }
image.name = opt.icon; image.name = opt.icon;
image.src = mapDeprecatedIcon(opt.icon); image.src = mapDeprecatedIcon(opt.icon);
$('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel); $('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel);
@ -773,6 +721,12 @@
if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) { if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) {
this.selectLabel.text(opt.label); this.selectLabel.text(opt.label);
} }
if (opt.hasValue === false) {
this.selectTrigger.addClass("red-ui-typedInput-full-width");
} else {
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
}
if (this.optionMenu) { if (this.optionMenu) {
this.optionMenu.remove(); this.optionMenu.remove();
this.optionMenu = null; this.optionMenu = null;
@ -783,11 +737,13 @@
this.optionExpandButton.shown = false; this.optionExpandButton.shown = false;
} }
if (this.optionSelectTrigger) { if (this.optionSelectTrigger) {
this.optionSelectTrigger.show(); this.optionSelectTrigger.css({"display":"inline-flex"});
if (!opt.hasValue) { if (!opt.hasValue) {
this.optionSelectTrigger.css({"flex-grow":1})
this.elementDiv.hide(); this.elementDiv.hide();
this.valueLabelContainer.hide(); this.valueLabelContainer.hide();
} else { } else {
this.optionSelectTrigger.css({"flex-grow":0})
this.elementDiv.show(); this.elementDiv.show();
this.valueLabelContainer.hide(); this.valueLabelContainer.hide();
} }
@ -966,9 +922,6 @@
this._trigger("typechange",null,this.propertyType); this._trigger("typechange",null,this.propertyType);
this.input.trigger('change',this.propertyType,this.value()); this.input.trigger('change',this.propertyType,this.value());
} }
if (!image) {
this._resize();
}
} }
} }
}, },
@ -995,7 +948,6 @@
}, },
show: function() { show: function() {
this.uiSelect.show(); this.uiSelect.show();
this._resize();
}, },
hide: function() { hide: function() {
this.uiSelect.hide(); this.uiSelect.hide();

View File

@ -108,7 +108,7 @@ RED.deploy = (function() {
RED.events.on('nodes:change',function(state) { RED.events.on('workspace:dirty',function(state) {
if (state.dirty) { if (state.dirty) {
window.onbeforeunload = function() { window.onbeforeunload = function() {
return RED._("deploy.confirm.undeployedChanges"); return RED._("deploy.confirm.undeployedChanges");

View File

@ -514,7 +514,9 @@ RED.editor = (function() {
for (var i=editStack.length-1;i<editStack.length;i++) { for (var i=editStack.length-1;i<editStack.length;i++) {
var node = editStack[i]; var node = editStack[i];
label = node.type; label = node.type;
if (node.type === '_expression') { if (node.type === 'group') {
label = RED._("group.editGroup",{name:RED.utils.sanitize(node.name||node.id)});
} else if (node.type === '_expression') {
label = RED._("expressionEditor.title"); label = RED._("expressionEditor.title");
} else if (node.type === '_js') { } else if (node.type === '_js') {
label = RED._("jsEditor.title"); label = RED._("jsEditor.title");
@ -588,8 +590,9 @@ RED.editor = (function() {
// cases, and also prevent browser auto-fill of password // cases, and also prevent browser auto-fill of password
// - the elements cannot be hidden otherwise Chrome will ignore them. // - the elements cannot be hidden otherwise Chrome will ignore them.
// - the elements need to have id's that imply password/username // - the elements need to have id's that imply password/username
$('<div style="position: absolute; top: -2000px;"><input id="red-ui-trap-password" type="password"/></div>').prependTo(dialogForm); $('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-password" type="password"/></span>').prependTo(dialogForm);
$('<div style="position: absolute; top: -2000px;"><input id="red-ui-trap-username" type="text"/></div>').prependTo(dialogForm); $('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-username" type="text"/></span>').prependTo(dialogForm);
$('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-user" type="text"/></span>').prependTo(dialogForm);
dialogForm.on("submit", function(e) { e.preventDefault();}); dialogForm.on("submit", function(e) { e.preventDefault();});
dialogForm.find('input').attr("autocomplete","off"); dialogForm.find('input').attr("autocomplete","off");
return dialogForm; return dialogForm;
@ -788,6 +791,11 @@ RED.editor = (function() {
nodeDiv.css({ nodeDiv.css({
'backgroundColor': backgroundColor 'backgroundColor': backgroundColor
}); });
var borderColor = RED.utils.getDarkerColor(backgroundColor);
if (borderColor !== backgroundColor) {
nodeDiv.css('border-color',borderColor)
}
} }
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv); var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true); RED.utils.createIconElement(icon_url, iconContainer, true);
@ -823,99 +831,6 @@ RED.editor = (function() {
searchInput.trigger("focus"); searchInput.trigger("focus");
} }
function createColorPicker(colorRow, color) {
var colorButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(colorRow);
$('<i class="fa fa-caret-down"></i>').appendTo(colorButton);
var colorDisp = $('<div>',{class:"red-ui-search-result-node"}).appendTo(colorButton);
var selector = $("<input/>", {
id: "red-ui-editor-node-color",
type: "text",
value: color
}).css({
marginLeft: "10px",
width: "150px",
}).appendTo(colorRow);
selector.on("change", function (e) {
var color = selector.val();
$(".red-ui-editor-node-appearance-button .red-ui-search-result-node").css({
"background-color": color
});
});
selector.trigger("change");
colorButton.on("click", function (e) {
var recommendedColors = [
"#DDAA99",
"#3FADB5", "#87A980", "#A6BBCF",
"#AAAA66", "#C0C0C0", "#C0DEED",
"#C7E9C0", "#D7D7A0", "#D8BFD8",
"#DAC4B4", "#DEB887", "#DEBD5C",
"#E2D96E", "#E6E0F8", "#E7E7AE",
"#E9967A", "#F3B567", "#FDD0A2",
"#FDF0C2", "#FFAAAA", "#FFCC66",
"#FFF0F0", "#FFFFFF"
].map(function(c) {
var r = parseInt(c.substring(1, 3), 16) / 255;
var g = parseInt(c.substring(3, 5), 16) / 255;
var b = parseInt(c.substring(5, 7), 16) / 255;
return {
hex: c,
r: r,
g: g,
b: b,
l: 0.3 * r + 0.59 * g + 0.11 * b
}
});
// Sort by luminosity.
recommendedColors.sort(function (a, b) {
return a.l - b.l;
});
var numColors = recommendedColors.length;
var width = 30;
var height = 30;
var margin = 2;
var perRow = 6;
var picker = $("<div/>", {
class: "red-ui-color-picker"
}).css({
width: ((width+margin+margin)*perRow)+"px",
height: Math.ceil(numColors/perRow)*(height+margin+margin)+"+px"
});
var count = 0;
var row = null;
recommendedColors.forEach(function (col) {
if ((count % perRow) == 0) {
row = $("<div/>").appendTo(picker);
}
var button = $("<button/>", {
}).css({
width: width+"px",
height: height+"px",
margin: margin+"px",
backgroundColor: col.hex,
"border-style": "solid",
"border-width": "1px",
"border-color": col.luma<0.92?col.hex:'#ccc'
}).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
colorPanel.hide();
selector.val(col.hex);
selector.trigger("change");
});
count++;
});
var colorPanel = RED.popover.panel(picker);
colorPanel.show({
target: colorButton
})
});
}
function buildAppearanceForm(container,node) { function buildAppearanceForm(container,node) {
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container); var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
@ -1001,7 +916,35 @@ RED.editor = (function() {
class: "form-row" class: "form-row"
}).appendTo(dialogForm); }).appendTo(dialogForm);
$("<label/>").text(RED._("editor.color")).appendTo(colorRow); $("<label/>").text(RED._("editor.color")).appendTo(colorRow);
createColorPicker(colorRow, color);
var recommendedColors = [
"#DDAA99",
"#3FADB5", "#87A980", "#A6BBCF",
"#AAAA66", "#C0C0C0", "#C0DEED",
"#C7E9C0", "#D7D7A0", "#D8BFD8",
"#DAC4B4", "#DEB887", "#DEBD5C",
"#E2D96E", "#E6E0F8", "#E7E7AE",
"#E9967A", "#F3B567", "#FDD0A2",
"#FDF0C2", "#FFAAAA", "#FFCC66",
"#FFF0F0", "#FFFFFF"
]
RED.colorPicker.create({
id: "red-ui-editor-node-color",
value: color,
palette: recommendedColors,
sortPalette: function (a, b) {return a.l - b.l;}
}).appendTo(colorRow);
$("#red-ui-editor-node-color").on('change', function(ev) {
// Horribly out of scope...
var colour = $(this).val();
nodeDiv.css('backgroundColor',colour);
var borderColor = RED.utils.getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
})
} }
@ -1016,6 +959,11 @@ RED.editor = (function() {
var colour = RED.utils.getNodeColor(node.type, node._def); var colour = RED.utils.getNodeColor(node.type, node._def);
var icon_url = RED.utils.getNodeIcon(node._def,node); var icon_url = RED.utils.getNodeIcon(node._def,node);
nodeDiv.css('backgroundColor',colour); nodeDiv.css('backgroundColor',colour);
var borderColor = RED.utils.getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv); var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true); RED.utils.createIconElement(icon_url, iconContainer, true);
@ -1136,15 +1084,17 @@ RED.editor = (function() {
if (node.info) { if (node.info) {
nodeInfoEditor.getSession().setValue(node.info, -1); nodeInfoEditor.getSession().setValue(node.info, -1);
} }
node.infoEditor = nodeInfoEditor;
return nodeInfoEditor; return nodeInfoEditor;
} }
function showEditDialog(node) { function showEditDialog(node, defaultTab) {
var editing_node = node; var editing_node = node;
var isDefaultIcon; var isDefaultIcon;
var defaultIcon; var defaultIcon;
var nodeInfoEditor; var nodeInfoEditor;
var finishedBuilding = false; var finishedBuilding = false;
var skipInfoRefreshOnClose = false;
editStack.push(node); editStack.push(node);
RED.view.state(RED.state.EDITING); RED.view.state(RED.state.EDITING);
@ -1537,6 +1487,7 @@ RED.editor = (function() {
editing_node.dirty = true; editing_node.dirty = true;
validateNode(editing_node); validateNode(editing_node);
RED.events.emit("editor:save",editing_node); RED.events.emit("editor:save",editing_node);
RED.events.emit("nodes:change",editing_node);
RED.tray.close(); RED.tray.close();
} }
} }
@ -1584,9 +1535,6 @@ RED.editor = (function() {
collapsible: true, collapsible: true,
menu: false menu: false
}); });
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
}
var ns; var ns;
if (node._def.set.module === "node-red") { if (node._def.set.module === "node-red") {
ns = "node-red"; ns = "node-red";
@ -1656,6 +1604,9 @@ RED.editor = (function() {
prepareEditDialog(node,node._def,"node-input", function() { prepareEditDialog(node,node._def,"node-input", function() {
trayBody.i18n(); trayBody.i18n();
finishedBuilding = true; finishedBuilding = true;
if (defaultTab) {
editorTabs.activateTab(defaultTab);
}
done(); done();
}); });
}, },
@ -1663,7 +1614,7 @@ RED.editor = (function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) { if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT); RED.view.state(RED.state.DEFAULT);
} }
if (editing_node) { if (editing_node && !skipInfoRefreshOnClose) {
RED.sidebar.info.refresh(editing_node); RED.sidebar.info.refresh(editing_node);
} }
RED.workspaces.refresh(); RED.workspaces.refresh();
@ -1691,6 +1642,7 @@ RED.editor = (function() {
text: RED._("subflow.edit"), text: RED._("subflow.edit"),
click: function() { click: function() {
RED.workspaces.show(id); RED.workspaces.show(id);
skipInfoRefreshOnClose = true;
$("#node-dialog-ok").trigger("click"); $("#node-dialog-ok").trigger("click");
} }
}); });
@ -2057,6 +2009,7 @@ RED.editor = (function() {
RED.view.redraw(true); RED.view.redraw(true);
if (!configAdding) { if (!configAdding) {
RED.events.emit("editor:save",editing_config_node); RED.events.emit("editor:save",editing_config_node);
RED.events.emit("nodes:change",editing_config_node);
} }
RED.tray.close(function() { RED.tray.close(function() {
updateConfigNodeSelect(configProperty,configType,editing_config_node.id,prefix); updateConfigNodeSelect(configProperty,configType,editing_config_node.id,prefix);
@ -2290,7 +2243,6 @@ RED.editor = (function() {
changes.env = editing_node.env; changes.env = editing_node.env;
changed = true; changed = true;
} }
RED.palette.refresh();
if (changed) { if (changed) {
var wasChanged = editing_node.changed; var wasChanged = editing_node.changed;
@ -2310,6 +2262,7 @@ RED.editor = (function() {
validateNode(n); validateNode(n);
} }
}); });
RED.events.emit("subflows:change",editing_node);
RED.nodes.dirty(true); RED.nodes.dirty(true);
var historyEvent = { var historyEvent = {
t:'edit', t:'edit',
@ -2423,15 +2376,16 @@ RED.editor = (function() {
buildAppearanceForm(appearanceTab.content,editing_node); buildAppearanceForm(appearanceTab.content,editing_node);
editorTabs.addTab(appearanceTab); editorTabs.addTab(appearanceTab);
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
trayBody.i18n();
$.getJSON(getCredentialsURL("subflow", subflow.id), function (data) { $.getJSON(getCredentialsURL("subflow", subflow.id), function (data) {
subflow.credentials = data; subflow.credentials = data;
subflow.credentials._ = $.extend(true,{},data); subflow.credentials._ = $.extend(true,{},data);
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
$("#subflow-input-name").val(subflow.name); $("#subflow-input-name").val(subflow.name);
RED.text.bidi.prepareInput($("#subflow-input-name")); RED.text.bidi.prepareInput($("#subflow-input-name"));
trayBody.i18n();
finishedBuilding = true; finishedBuilding = true;
done(); done();
}); });
@ -2453,6 +2407,251 @@ RED.editor = (function() {
RED.tray.show(trayOptions); RED.tray.show(trayOptions);
} }
function showEditGroupDialog(group) {
var editing_node = group;
editStack.push(group);
RED.view.state(RED.state.EDITING);
var nodeInfoEditor;
var finishedBuilding = false;
var trayOptions = {
title: getEditStackTitle(),
buttons: [
{
id: "node-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
RED.tray.close();
}
},
{
id: "node-dialog-ok",
class: "primary",
text: RED._("common.label.done"),
click: function() {
var changes = {};
var changed = false;
var wasDirty = RED.nodes.dirty();
var d;
var outputMap;
if (editing_node._def.oneditsave) {
var oldValues = {};
for (d in editing_node._def.defaults) {
if (editing_node._def.defaults.hasOwnProperty(d)) {
if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
oldValues[d] = editing_node[d];
} else {
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
}
}
}
try {
var rc = editing_node._def.oneditsave.call(editing_node);
if (rc === true) {
changed = true;
}
} catch(err) {
console.log("oneditsave",editing_node.id,editing_node.type,err.toString());
}
for (d in editing_node._def.defaults) {
if (editing_node._def.defaults.hasOwnProperty(d)) {
if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") {
if (oldValues[d] !== editing_node[d]) {
changes[d] = oldValues[d];
changed = true;
}
} else {
if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) {
changes[d] = oldValues[d];
changed = true;
}
}
}
}
}
var newValue;
if (editing_node._def.defaults) {
for (d in editing_node._def.defaults) {
if (editing_node._def.defaults.hasOwnProperty(d)) {
var input = $("#node-input-"+d);
if (input.attr('type') === "checkbox") {
newValue = input.prop('checked');
} else if (input.prop("nodeName") === "select" && input.attr("multiple") === "multiple") {
// An empty select-multiple box returns null.
// Need to treat that as an empty array.
newValue = input.val();
if (newValue == null) {
newValue = [];
}
} else if ("format" in editing_node._def.defaults[d] && editing_node._def.defaults[d].format !== "" && input[0].nodeName === "DIV") {
newValue = input.text();
} else {
newValue = input.val();
}
if (newValue != null) {
if (editing_node._def.defaults[d].type) {
if (newValue == "_ADD_") {
newValue = "";
}
}
if (editing_node[d] != newValue) {
if (editing_node._def.defaults[d].type) {
// Change to a related config node
var configNode = RED.nodes.node(editing_node[d]);
if (configNode) {
var users = configNode.users;
users.splice(users.indexOf(editing_node),1);
}
configNode = RED.nodes.node(newValue);
if (configNode) {
configNode.users.push(editing_node);
}
}
changes[d] = editing_node[d];
editing_node[d] = newValue;
changed = true;
}
}
}
}
}
var oldInfo = editing_node.info;
if (nodeInfoEditor) {
var newInfo = nodeInfoEditor.getValue();
if (!!oldInfo) {
// Has existing info property
if (newInfo.trim() === "") {
// New value is blank - remove the property
changed = true;
changes.info = oldInfo;
delete editing_node.info;
} else if (newInfo !== oldInfo) {
// New value is different
changed = true;
changes.info = oldInfo;
editing_node.info = newInfo;
}
} else {
// No existing info
if (newInfo.trim() !== "") {
// New value is not blank
changed = true;
changes.info = undefined;
editing_node.info = newInfo;
}
}
}
if (changed) {
var wasChanged = editing_node.changed;
editing_node.changed = true;
RED.nodes.dirty(true);
var historyEvent = {
t:'edit',
node:editing_node,
changes:changes,
dirty:wasDirty,
changed:wasChanged
};
RED.history.push(historyEvent);
RED.events.emit("groups:change",editing_node);
}
editing_node.dirty = true;
RED.tray.close();
RED.view.redraw(true);
}
}
],
resize: function(size) {
editTrayWidthCache['group'] = size.width;
$(".red-ui-tray-content").height(size.height - 50);
// var form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40);
// if (editing_node && editing_node._def.oneditresize) {
// try {
// editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()});
// } catch(err) {
// console.log("oneditresize",editing_node.id,editing_node.type,err.toString());
// }
// }
},
open: function(tray, done) {
var trayFooter = tray.find(".red-ui-tray-footer");
var trayFooterLeft = $("<div/>", {
class: "red-ui-tray-footer-left"
}).appendTo(trayFooter)
var trayBody = tray.find('.red-ui-tray-body');
trayBody.parent().css('overflow','hidden');
var editorTabEl = $('<ul></ul>').appendTo(trayBody);
var editorContent = $('<div></div>').appendTo(trayBody);
var editorTabs = RED.tabs.create({
element:editorTabEl,
onchange:function(tab) {
editorContent.children().hide();
if (tab.onchange) {
tab.onchange.call(tab);
}
tab.content.show();
if (finishedBuilding) {
RED.tray.resize();
}
},
collapsible: true,
menu: false
});
var nodePropertiesTab = {
id: "editor-tab-properties",
label: RED._("editor-tab.properties"),
name: RED._("editor-tab.properties"),
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
iconClass: "fa fa-cog"
};
buildEditForm(nodePropertiesTab.content,"dialog-form","group","node-red",group);
editorTabs.addTab(nodePropertiesTab);
var descriptionTab = {
id: "editor-tab-description",
label: RED._("editor-tab.description"),
name: RED._("editor-tab.description"),
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
iconClass: "fa fa-file-text-o",
onchange: function() {
nodeInfoEditor.focus();
}
};
editorTabs.addTab(descriptionTab);
nodeInfoEditor = buildDescriptionForm(descriptionTab.content,editing_node);
prepareEditDialog(group,group._def,"node-input", function() {
trayBody.i18n();
finishedBuilding = true;
done();
});
},
close: function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
RED.sidebar.info.refresh(editing_node);
nodeInfoEditor.destroy();
nodeInfoEditor = null;
editStack.pop();
editing_node = null;
},
show: function() {
}
}
if (editTrayWidthCache.hasOwnProperty('group')) {
trayOptions.width = editTrayWidthCache['group'];
}
RED.tray.show(trayOptions);
}
function showTypeEditor(type, options) { function showTypeEditor(type, options) {
if (customEditTypes.hasOwnProperty(type)) { if (customEditTypes.hasOwnProperty(type)) {
if (editStack.length > 0) { if (editStack.length > 0) {
@ -2576,6 +2775,7 @@ RED.editor = (function() {
edit: showEditDialog, edit: showEditDialog,
editConfig: showEditConfigNodeDialog, editConfig: showEditConfigNodeDialog,
editSubflow: showEditSubflowDialog, editSubflow: showEditSubflowDialog,
editGroup: showEditGroupDialog,
editJavaScript: function(options) { showTypeEditor("_js",options) }, editJavaScript: function(options) { showTypeEditor("_js",options) },
editExpression: function(options) { showTypeEditor("_expression", options) }, editExpression: function(options) { showTypeEditor("_expression", options) },
editJSON: function(options) { showTypeEditor("_json", options) }, editJSON: function(options) { showTypeEditor("_json", options) },

View File

@ -15,7 +15,7 @@
**/ **/
(function() { (function() {
var template = '<script type="text/x-red" data-template-name="_buffer"><div id="red-ui-editor-type-buffer-panels"><div id="red-ui-editor-type-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button class="red-ui-editor-type-buffer-type red-ui-button red-ui-button-small"><i class="fa fa-exclamation-circle"></i> <span id="red-ui-editor-type-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="red-ui-editor-type-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></button></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="red-ui-editor-type-buffer-str"></div></div></div><div id="red-ui-editor-type-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px"><div class="node-text-editor" id="red-ui-editor-type-buffer-bin"></div></div></div></div></script>'; var template = '<script type="text/x-red" data-template-name="_buffer"><div id="red-ui-editor-type-buffer-panels"><div id="red-ui-editor-type-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button class="red-ui-editor-type-buffer-type red-ui-button red-ui-button-small"><i class="fa fa-exclamation-circle"></i> <span id="red-ui-editor-type-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="red-ui-editor-type-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></button></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="red-ui-editor-type-buffer-str"></div></div></div><div id="red-ui-editor-type-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px; margin-bottom:0;"><div class="node-text-editor" id="red-ui-editor-type-buffer-bin"></div></div></div></div></script>';
function stringToUTF8Array(str) { function stringToUTF8Array(str) {
var data = []; var data = [];
@ -187,8 +187,7 @@
$(".red-ui-editor-type-buffer-type").on("click", function(e) { $(".red-ui-editor-type-buffer-type").on("click", function(e) {
e.preventDefault(); e.preventDefault();
RED.sidebar.info.set(RED._("bufferEditor.modeDesc")); RED.sidebar.help.set(RED._("bufferEditor.modeDesc"));
RED.sidebar.info.show();
}) })

View File

@ -102,7 +102,7 @@
var f = $(this).val(); var f = $(this).val();
var args = RED._('jsonata:'+f+".args",{defaultValue:''}); var args = RED._('jsonata:'+f+".args",{defaultValue:''});
var title = "<h5>"+f+"("+args+")</h5>"; var title = "<h5>"+f+"("+args+")</h5>";
var body = marked(RED._('jsonata:'+f+'.desc',{defaultValue:''})); var body = RED.utils.renderMarkdown(RED._('jsonata:'+f+'.desc',{defaultValue:''}));
$("#red-ui-editor-type-expression-help").html(title+"<p>"+body+"</p>"); $("#red-ui-editor-type-expression-help").html(title+"<p>"+body+"</p>");
}) })
@ -237,8 +237,7 @@
var changeTimer; var changeTimer;
$(".red-ui-editor-type-expression-legacy").on("click", function(e) { $(".red-ui-editor-type-expression-legacy").on("click", function(e) {
e.preventDefault(); e.preventDefault();
RED.sidebar.info.set(RED._("expressionEditor.compatModeDesc")); RED.sidebar.help.set(RED._("expressionEditor.compatModeDesc"));
RED.sidebar.info.show();
}) })
var testExpression = function() { var testExpression = function() {
var value = testDataEditor.getValue(); var value = testDataEditor.getValue();
@ -318,9 +317,9 @@
var p2 = $("#red-ui-editor-type-expression-panel-info > .form-row > div:first-child"); var p2 = $("#red-ui-editor-type-expression-panel-info > .form-row > div:first-child");
p2Height -= p2.outerHeight(true) + 20; p2Height -= p2.outerHeight(true) + 20;
$(".red-ui-editor-type-expression-tab-content").height(p2Height); $(".red-ui-editor-type-expression-tab-content").height(p2Height);
$("#red-ui-editor-type-expression-test-data").css("height",(p2Height-5)+"px"); $("#red-ui-editor-type-expression-test-data").css("height",(p2Height-25)+"px");
testDataEditor.resize(); testDataEditor.resize();
$("#red-ui-editor-type-expression-test-result").css("height",(p2Height-5)+"px"); $("#red-ui-editor-type-expression-test-result").css("height",(p2Height-25)+"px");
testResultEditor.resize(); testResultEditor.resize();
} }
}); });

View File

@ -87,6 +87,9 @@
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false); expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
} }
dialogForm.i18n(); dialogForm.i18n();
setTimeout(function() {
expressionEditor.focus();
},300);
}, },
close: function() { close: function() {
expressionEditor.destroy(); expressionEditor.destroy();

View File

@ -107,7 +107,7 @@
clearTimeout(changeTimer); clearTimeout(changeTimer);
changeTimer = setTimeout(function() { changeTimer = setTimeout(function() {
var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop(); var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop();
$(".red-ui-editor-type-markdown-panel-preview").html(marked(expressionEditor.getValue())); $(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
$(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop); $(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop);
},200); },200);
}) })
@ -116,7 +116,7 @@
} }
if (value) { if (value) {
$(".red-ui-editor-type-markdown-panel-preview").html(marked(expressionEditor.getValue())); $(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
} }
panels = RED.panels.create({ panels = RED.panels.create({
id:"red-ui-editor-type-markdown-panels", id:"red-ui-editor-type-markdown-panels",

View File

@ -0,0 +1,653 @@
/**
* 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.group = (function() {
var _groupEditTemplate = '<script type="text/x-red" data-template-name="group">'+
'<div class="form-row">'+
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
'<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">'+
'</div>'+
// '<div class="node-input-group-style-tools"><span class="button-group"><button class="red-ui-button red-ui-button-small">Use default style</button><button class="red-ui-button red-ui-button-small">Set as default style</button></span></div>'+
'<div class="form-row" id="node-input-row-style-stroke">'+
'<label data-i18n="editor:common.label.style"></label>'+
'<label style="width: 70px;margin-right:10px" for="node-input-style-stroke" data-i18n="editor:common.label.line"></label>'+
'</div>'+
'<div class="form-row" style="padding-left: 100px;" id="node-input-row-style-fill">'+
'<label style="width: 70px;margin-right: 10px " for="node-input-style-fill" data-i18n="editor:common.label.fill"></label>'+
'</div>'+
'<div class="form-row">'+
'<label for="node-input-style-label" data-i18n="editor:common.label.label"></label>'+
'<input type="checkbox" id="node-input-style-label"/>'+
'</div>'+
'<div class="form-row" id="node-input-row-style-label-options">'+
'<div style="margin-left: 100px; display: inline-block">'+
'<div class="form-row">'+
'<span style="display: inline-block; min-width: 140px" id="node-input-row-style-label-color">'+
'<label style="width: 70px;margin-right: 10px" for="node-input-style-fill" data-i18n="editor:common.label.color"></label>'+
'</span>'+
'</div>'+
'<div class="form-row">'+
'<span style="display: inline-block; min-width: 140px;" id="node-input-row-style-label-position">'+
'<label style="width: 70px;margin-right: 10px " for="node-input-style-label-position" data-i18n="editor:common.label.position"></label>'+
'</span>'+
'</div>'+
'</div>'+
'</div>'+
'</script>';
var colorPalette = [
"#ff0000",
"#ffC000",
"#ffff00",
"#92d04f",
"#0070c0",
"#001f60",
"#6f2fa0",
"#000000",
"#777777"
]
var colorSteps = 3;
var colorCount = colorPalette.length;
for (var i=0,len=colorPalette.length*colorSteps;i<len;i++) {
var ci = i%colorCount;
var j = Math.floor(i/colorCount)+1;
var c = colorPalette[ci];
var r = parseInt(c.substring(1, 3), 16);
var g = parseInt(c.substring(3, 5), 16);
var b = parseInt(c.substring(5, 7), 16);
var dr = (255-r)/(colorSteps+((ci===colorCount-1) ?0:1));
var dg = (255-g)/(colorSteps+((ci===colorCount-1) ?0:1));
var db = (255-b)/(colorSteps+((ci===colorCount-1) ?0:1));
r = Math.min(255,Math.floor(r+j*dr));
g = Math.min(255,Math.floor(g+j*dg));
b = Math.min(255,Math.floor(b+j*db));
var s = ((r<<16) + (g<<8) + b).toString(16);
colorPalette.push('#'+'000000'.slice(0, 6-s.length)+s);
}
var defaultGroupStyle = {};
var groupDef = {
defaults:{
name:{value:""},
style:{value:{}},
nodes:{value:[]}
},
category: "config",
oneditprepare: function() {
var style = this.style || {};
RED.colorPicker.create({
id:"node-input-style-stroke",
value: style.stroke || "#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
cellHeight: 16,
cellMargin: 3,
none: true,
opacity: style['stroke-opacity'] || 1.0
}).appendTo("#node-input-row-style-stroke");
RED.colorPicker.create({
id:"node-input-style-fill",
value: style.fill || "none",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
cellHeight: 16,
cellMargin: 3,
none: true,
opacity: style['fill-opacity'] || 1.0
}).appendTo("#node-input-row-style-fill");
createLayoutPicker({
id:"node-input-style-label-position",
value:style["label-position"] || "nw"
}).appendTo("#node-input-row-style-label-position");
RED.colorPicker.create({
id:"node-input-style-color",
value: style.color || "#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
cellHeight: 16,
cellMargin: 3
}).appendTo("#node-input-row-style-label-color");
$("#node-input-style-label").toggleButton({
enabledLabel: RED._("editor.show"),
disabledLabel: RED._("editor.hide")
})
$("#node-input-style-label").on("change", function(evt) {
$("#node-input-row-style-label-options").toggle($(this).prop("checked"));
})
$("#node-input-style-label").prop("checked", this.style.label)
$("#node-input-style-label").trigger("change");
},
oneditresize: function(size) {
},
oneditsave: function() {
this.style.stroke = $("#node-input-style-stroke").val();
this.style.fill = $("#node-input-style-fill").val();
this.style["stroke-opacity"] = $("#node-input-style-stroke-opacity").val();
this.style["fill-opacity"] = $("#node-input-style-fill-opacity").val();
this.style.label = $("#node-input-style-label").prop("checked");
if (this.style.label) {
this.style["label-position"] = $("#node-input-style-label-position").val();
this.style.color = $("#node-input-style-color").val();
} else {
delete this.style["label-position"];
delete this.style.color;
}
if (this.style["stroke-opacity"] === "1") {
delete this.style["stroke-opacity"]
}
if (this.style["fill-opacity"] === "1") {
delete this.style["fill-opacity"]
}
this.resize = true;
},
set:{
module: "node-red"
}
}
function init() {
RED.events.on("view:selection-changed",function(selection) {
RED.menu.setDisabled("menu-item-group-group",!!!selection.nodes);
RED.menu.setDisabled("menu-item-group-ungroup",!!!selection.nodes || selection.nodes.filter(function(n) { return n.type==='group'}).length === 0);
RED.menu.setDisabled("menu-item-group-merge",!!!selection.nodes);
RED.menu.setDisabled("menu-item-group-remove",!!!selection.nodes || selection.nodes.filter(function(n) { return !!n.g }).length === 0);
});
RED.actions.add("core:group-selection", function() { groupSelection() })
RED.actions.add("core:ungroup-selection", function() { ungroupSelection() })
RED.actions.add("core:merge-selection-to-group", function() { mergeSelection() })
RED.actions.add("core:remove-selection-from-group", function() { removeSelection() })
RED.actions.add("core:copy-group-style", function() { copyGroupStyle() });
RED.actions.add("core:paste-group-style", function() { pasteGroupStyle() });
$(_groupEditTemplate).appendTo("#red-ui-editor-node-configs");
var groupStyleDiv = $("<div>",{
class:"red-ui-flow-group-body",
style: "position: absolute; top: -1000px;"
}).appendTo(document.body);
var groupStyle = getComputedStyle(groupStyleDiv[0]);
defaultGroupStyle = {
stroke: convertColorToHex(groupStyle.stroke),
"stroke-opacity": groupStyle.strokeOpacity,
fill: convertColorToHex(groupStyle.fill),
"fill-opacity": groupStyle.fillOpacity
}
groupStyleDiv.remove();
}
function convertColorToHex(c) {
var m = /^rgb\((\d+), (\d+), (\d+)\)$/.exec(c);
if (m) {
var s = ((parseInt(m[1])<<16) + (parseInt(m[2])<<8) + parseInt(m[3])).toString(16)
return '#'+'000000'.slice(0, 6-s.length)+s;
}
return c;
}
var groupStyleClipboard;
function copyGroupStyle() {
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].type === 'group') {
groupStyleClipboard = JSON.parse(JSON.stringify(selection.nodes[0].style));
RED.notify(RED._("clipboard.groupStyleCopied"),{id:"clipboard"})
}
}
function pasteGroupStyle() {
if (groupStyleClipboard) {
var selection = RED.view.selection();
if (selection.nodes) {
var historyEvent = {
t:'multi',
events:[],
dirty: RED.nodes.dirty()
}
selection.nodes.forEach(function(n) {
if (n.type === 'group') {
historyEvent.events.push({
t: "edit",
node: n,
changes: {
style: JSON.parse(JSON.stringify(n.style))
},
dirty: RED.nodes.dirty()
});
n.style = JSON.parse(JSON.stringify(groupStyleClipboard));
n.dirty = true;
}
})
if (historyEvent.events.length > 0) {
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.view.redraw();
}
}
}
}
function groupSelection() {
var selection = RED.view.selection();
if (selection.nodes) {
var group = createGroup(selection.nodes);
if (group) {
var historyEvent = {
t:"createGroup",
groups: [ group ],
dirty: RED.nodes.dirty()
}
RED.history.push(historyEvent);
RED.view.select({nodes:[group]});
RED.nodes.dirty(true);
}
}
}
function ungroupSelection() {
var selection = RED.view.selection();
if (selection.nodes) {
var newSelection = [];
groups = selection.nodes.filter(function(n) { return n.type === "group" });
var historyEvent = {
t:"ungroup",
groups: [ ],
dirty: RED.nodes.dirty()
}
RED.history.push(historyEvent);
groups.forEach(function(g) {
newSelection = newSelection.concat(ungroup(g))
historyEvent.groups.push(g);
})
RED.history.push(historyEvent);
RED.view.select({nodes:newSelection})
RED.nodes.dirty(true);
}
}
function ungroup(g) {
var nodes = [];
var parentGroup = RED.nodes.group(g.g);
g.nodes.forEach(function(n) {
nodes.push(n);
if (parentGroup) {
// Move nodes to parent group
n.g = parentGroup.id;
parentGroup.nodes.push(n);
parentGroup.dirty = true;
n.dirty = true;
} else {
delete n.g;
}
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
})
RED.nodes.removeGroup(g);
return nodes;
}
function mergeSelection() {
// TODO: this currently creates an entirely new group. Need to merge properties
// of any existing group
var selection = RED.view.selection();
if (selection.nodes) {
var nodes = [];
var historyEvent = {
t: "multi",
events: []
}
var ungroupHistoryEvent = {
t: "ungroup",
groups: []
}
var n;
var parentGroup;
// First pass, check they are all in the same parent
// TODO: DRY mergeSelection,removeSelection,...
for (var i=0; i<selection.nodes.length; i++) {
n = selection.nodes[i];
if (i === 0) {
parentGroup = n.g;
} else if (n.g !== parentGroup) {
RED.notify(RED._("group.errors.cannotCreateDiffGroups"),"error");
return;
}
}
// Second pass, ungroup any groups in the selection and add their contents
// to the selection
for (var i=0; i<selection.nodes.length; i++) {
n = selection.nodes[i];
if (n.type === "group") {
ungroupHistoryEvent.groups.push(n);
nodes = nodes.concat(ungroup(n));
} else {
nodes.push(n);
}
n.dirty = true;
}
if (ungroupHistoryEvent.groups.length > 0) {
historyEvent.events.push(ungroupHistoryEvent);
}
// Finally, create the new group
var group = createGroup(nodes);
if (group) {
RED.view.select({nodes:[group]})
}
historyEvent.events.push({
t:"createGroup",
groups: [ group ],
dirty: RED.nodes.dirty()
});
RED.history.push(historyEvent);
RED.nodes.dirty(true);
}
}
function removeSelection() {
var selection = RED.view.selection();
if (selection.nodes) {
var nodes = [];
var n;
var parentGroup = RED.nodes.group(selection.nodes[0].g);
if (parentGroup) {
try {
removeFromGroup(parentGroup,selection.nodes,true);
var historyEvent = {
t: "removeFromGroup",
dirty: RED.nodes.dirty(),
group: parentGroup,
nodes: selection.nodes
}
RED.history.push(historyEvent);
RED.nodes.dirty(true);
} catch(err) {
RED.notify(err,"error");
return;
}
}
RED.view.select({nodes:selection.nodes})
}
}
function createGroup(nodes) {
if (nodes.length === 0) {
return;
}
if (nodes.filter(function(n) { return n.type === "subflow" }).length > 0) {
RED.notify(RED._("group.errors.cannotAddSubflowPorts"),"error");
return;
}
// nodes is an array
// each node must be on the same tab (z)
var group = {
id: RED.nodes.id(),
type: 'group',
nodes: [],
style: JSON.parse(JSON.stringify(defaultGroupStyle)),
x: Number.POSITIVE_INFINITY,
y: Number.POSITIVE_INFINITY,
w: 0,
h: 0,
_def: RED.group.def
}
group.z = nodes[0].z;
RED.nodes.addGroup(group);
try {
addToGroup(group,nodes);
} catch(err) {
RED.notify(err,"error");
return;
}
return group;
}
function addToGroup(group,nodes) {
if (!Array.isArray(nodes)) {
nodes = [nodes];
}
var i,n,z;
var g;
// First pass - validate we can safely add these nodes to the group
for (i=0;i<nodes.length;i++) {
n = nodes[i]
if (!n.z) {
throw new Error("Cannot add node without a z property to a group")
}
if (!z) {
z = n.z;
} else if (z !== n.z) {
throw new Error("Cannot add nooes with different z properties")
}
if (n.g) {
// This is already in a group.
// - check they are all in the same group
if (!g) {
if (i!==0) {
// TODO: this might be ok when merging groups
throw new Error(RED._("group.errors.cannotCreateDiffGroups"))
}
g = n.g
}
}
if (g !== n.g) {
throw new Error(RED._("group.errors.cannotCreateDiffGroups"))
}
}
// The nodes are already in a group. The assumption is they should be
// wrapped in the newly provided group, and that group added to in their
// place to the existing containing group.
if (g) {
g = RED.nodes.group(g);
g.nodes.push(group);
g.dirty = true;
group.g = g.id;
}
// Second pass - add them to the group
for (i=0;i<nodes.length;i++) {
n = nodes[i];
if (n.type !== "subflow") {
if (g && n.g === g.id) {
var ni = g.nodes.indexOf(n);
if (ni > -1) {
g.nodes.splice(ni,1)
}
}
n.g = group.id;
n.dirty = true;
group.nodes.push(n);
group.x = Math.min(group.x,n.x-n.w/2-25-((n._def.button && n._def.align!=="right")?20:0));
group.y = Math.min(group.y,n.y-n.h/2-25);
group.w = Math.max(group.w,n.x+n.w/2+25+((n._def.button && n._def.align=="right")?20:0) - group.x);
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
}
}
if (g) {
RED.events.emit("groups:change",group)
}
markDirty(group);
}
function removeFromGroup(group, nodes, reparent) {
if (!Array.isArray(nodes)) {
nodes = [nodes];
}
var n;
// First pass, check they are all in the same parent
// TODO: DRY mergeSelection,removeSelection,...
for (var i=0; i<nodes.length; i++) {
if (nodes[i].g !== group.id) {
return;
}
}
var parentGroup = RED.nodes.group(group.g);
for (var i=0; i<nodes.length; i++) {
n = nodes[i];
n.dirty = true;
var index = group.nodes.indexOf(n);
group.nodes.splice(index,1);
if (reparent && group.g) {
n.g = group.g
parentGroup.nodes.push(n);
} else {
delete n.g;
}
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
}
markDirty(group);
}
function getNodes(group,recursive) {
var nodes = [];
group.nodes.forEach(function(n) {
nodes.push(n);
if (recursive && n.type === 'group') {
nodes = nodes.concat(getNodes(n,recursive))
}
})
return nodes;
}
function groupContains(group,item) {
if (item.g === group.id) {
return true;
}
for (var i=0;i<group.nodes.length;i++) {
if (group.nodes[i].type === "group") {
if (groupContains(group.nodes[i],item)) {
return true;
}
}
}
return false;
}
function getRootGroup(group) {
if (!group.g) {
return group;
}
return getRootGroup(RED.nodes.group(group.g))
}
function createLayoutPicker(options) {
var container = $("<div>",{style:"display:inline-block"});
var layoutHiddenInput = $("<input/>", { id: options.id, type: "hidden", value: options.value }).appendTo(container);
var layoutButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(container);
$('<i class="fa fa-caret-down"></i>').appendTo(layoutButton);
var layoutDispContainer = $('<div>',{class:"red-ui-search-result-node"}).appendTo(layoutButton);
var layoutDisp = $('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"}).appendTo(layoutDispContainer);
var refreshDisplay = function() {
var val = layoutHiddenInput.val();
layoutDisp.removeClass().addClass("red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val)
}
layoutButton.on("click", function(e) {
var picker = $("<div/>", {
class: "red-ui-group-layout-picker"
}).css({
width: "126px"
});
var row = null;
row = $("<div/>").appendTo(picker);
for (var y=0;y<2;y++) { //red-ui-group-layout-text-pos
var yComponent= "ns"[y];
row = $("<div/>").appendTo(picker);
for (var x=0;x<3;x++) {
var xComponent = ["w","","e"][x];
var val = yComponent+xComponent;
var button = $("<button/>", { class:"red-ui-search-result-node","data-pos":val }).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
layoutHiddenInput.val($(this).data("pos"));
layoutPanel.hide()
refreshDisplay();
});
$('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val}).appendTo(button);
}
}
refreshDisplay();
var layoutPanel = RED.popover.panel(picker);
layoutPanel.show({
target: layoutButton
})
})
refreshDisplay();
return container;
}
function markDirty(group) {
group.dirty = true;
while(group) {
group.dirty = true;
group = RED.nodes.group(group.g);
}
}
return {
def: groupDef,
init: init,
createGroup: createGroup,
ungroup: ungroup,
addToGroup: addToGroup,
removeFromGroup: removeFromGroup,
getNodes: getNodes,
contains: groupContains,
markDirty: markDirty
}
})();

View File

@ -524,12 +524,12 @@ RED.keyboard = (function() {
var pane = $('<div id="red-ui-settings-tab-keyboard"></div>'); var pane = $('<div id="red-ui-settings-tab-keyboard"></div>');
$('<div class="keyboard-shortcut-entry keyboard-shortcut-list-header">'+ $('<div class="keyboard-shortcut-entry keyboard-shortcut-list-header">'+
'<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input id="red-ui-settings-tab-keyboard-filter" type="text" data-i18n="[placeholder]keyboard.filterActions"></div>'+ '<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input autocomplete="off" name="keyboard-filter" id="red-ui-settings-tab-keyboard-filter" type="text" data-i18n="[placeholder]keyboard.filterActions"></div>'+
'<div class="keyboard-shortcut-entry-key" data-i18n="keyboard.shortcut"></div>'+ '<div class="keyboard-shortcut-entry-key" data-i18n="keyboard.shortcut"></div>'+
'<div class="keyboard-shortcut-entry-scope" data-i18n="keyboard.scope"></div>'+ '<div class="keyboard-shortcut-entry-scope" data-i18n="keyboard.scope"></div>'+
'</div>').appendTo(pane); '</div>').appendTo(pane);
pane.find("input").searchBox({ pane.find("#red-ui-settings-tab-keyboard-filter").searchBox({
delay: 100, delay: 100,
change: function() { change: function() {
var filterValue = $(this).val().trim(); var filterValue = $(this).val().trim();

View File

@ -22,7 +22,7 @@ RED.library = (function() {
var _libraryLookup = '<div id="red-ui-library-dialog-load" class="hide">'+ var _libraryLookup = '<div id="red-ui-library-dialog-load" class="hide">'+
'<form class="form-horizontal">'+ '<form class="form-horizontal">'+
'<div style="height: 400px; position:relative; ">'+ '<div class="red-ui-library-dialog-box" style="height: 400px; position:relative; ">'+
'<div id="red-ui-library-dialog-load-panes">'+ '<div id="red-ui-library-dialog-load-panes">'+
'<div class="red-ui-panel" id="red-ui-library-dialog-load-browser"></div>'+ '<div class="red-ui-panel" id="red-ui-library-dialog-load-browser"></div>'+
'<div class="red-ui-panel">'+ '<div class="red-ui-panel">'+
@ -41,7 +41,7 @@ RED.library = (function() {
var _librarySave = '<div id="red-ui-library-dialog-save" class="hide">'+ var _librarySave = '<div id="red-ui-library-dialog-save" class="hide">'+
'<form class="form-horizontal">'+ '<form class="form-horizontal">'+
'<div style="height: 400px; position:relative; ">'+ '<div class="red-ui-library-dialog-box" style="height: 400px; position:relative; ">'+
'<div id="red-ui-library-dialog-save-browser"></div>'+ '<div id="red-ui-library-dialog-save-browser"></div>'+
'<div class="form-row">'+ '<div class="form-row">'+
'<label data-i18n="clipboard.export.exportAs"></label><input id="red-ui-library-dialog-save-filename" type="text">'+ '<label data-i18n="clipboard.export.exportAs"></label><input id="red-ui-library-dialog-save-filename" type="text">'+
@ -64,12 +64,14 @@ RED.library = (function() {
var queryArgs = []; var queryArgs = [];
var data = {}; var data = {};
for (var i=0; i<activeLibrary.fields.length; i++) { for (var i=0; i < activeLibrary.fields.length; i++) {
var field = activeLibrary.fields[i]; var field = activeLibrary.fields[i];
if (field == "name") { if (field === "name") {
data.name = name; data.name = name;
} else if (typeof(field) === 'object') {
data[field.name] = field.get();
} else { } else {
data[field] = $("#"+elementPrefix+field).val(); data[field] = $("#" + elementPrefix + field).val();
} }
} }
data.text = activeLibrary.editor.getValue(); data.text = activeLibrary.editor.getValue();
@ -254,6 +256,13 @@ RED.library = (function() {
libraryEditor.renderer.$cursorLayer.element.style.opacity=0; libraryEditor.renderer.$cursorLayer.element.style.opacity=0;
libraryEditor.$blockScrolling = Infinity; libraryEditor.$blockScrolling = Infinity;
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 570) {
dialogHeight = 400 - (570 - winHeight);
}
$("#red-ui-library-dialog-load .red-ui-library-dialog-box").height(dialogHeight);
$( "#red-ui-library-dialog-load" ).dialog("option","title",RED._("library.typeLibrary", {type:options.type})).dialog( "open" ); $( "#red-ui-library-dialog-load" ).dialog("option","title",RED._("library.typeLibrary", {type:options.type})).dialog( "open" );
} }
}, },
@ -293,6 +302,15 @@ RED.library = (function() {
saveLibraryBrowser.select(listing[0].children[0]); saveLibraryBrowser.select(listing[0].children[0]);
},200); },200);
}); });
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 570) {
dialogHeight = 400 - (570 - winHeight);
}
$("#red-ui-library-dialog-save .red-ui-library-dialog-box").height(dialogHeight);
$( "#red-ui-library-dialog-save" ).dialog( "open" ); $( "#red-ui-library-dialog-save" ).dialog( "open" );
} }
} }
@ -518,14 +536,20 @@ RED.library = (function() {
{ {
text: RED._("common.label.load"), text: RED._("common.label.load"),
class: "primary", class: "primary",
click: function() { click: function () {
if (selectedLibraryItem) { if (selectedLibraryItem) {
var elementPrefix = activeLibrary.elementPrefix || "node-input-"; var elementPrefix = activeLibrary.elementPrefix || "node-input-";
for (var i=0; i<activeLibrary.fields.length; i++) { for (var i = 0; i < activeLibrary.fields.length; i++) {
var field = activeLibrary.fields[i]; var field = activeLibrary.fields[i];
$("#"+elementPrefix+field).val(selectedLibraryItem[field]); if (typeof(field) === 'object') {
var val = selectedLibraryItem[field.name];
field.set(val);
}
else {
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
}
} }
activeLibrary.editor.setValue(libraryEditor.getValue(),-1); activeLibrary.editor.setValue(libraryEditor.getValue(), -1);
} }
$( this ).dialog( "close" ); $( this ).dialog( "close" );
} }

View File

@ -223,7 +223,11 @@ RED.palette.editor = (function() {
var setElements = nodeEntry.sets[setName]; var setElements = nodeEntry.sets[setName];
if (set.err) { if (set.err) {
errorCount++; errorCount++;
$("<li>").text(set.err).appendTo(nodeEntry.errorList); var errMessage = set.err;
if (set.err.message) {
errMessage = set.err.message;
}
$("<li>").text(errMessage).appendTo(nodeEntry.errorList);
} }
if (set.enabled) { if (set.enabled) {
activeTypeCount += set.types.length; activeTypeCount += set.types.length;
@ -384,6 +388,7 @@ RED.palette.editor = (function() {
handleCatalogResponse(null,catalog,index,v); handleCatalogResponse(null,catalog,index,v);
refreshNodeModuleList(); refreshNodeModuleList();
}).fail(function(jqxhr, textStatus, error) { }).fail(function(jqxhr, textStatus, error) {
console.warn("Error loading catalog",catalog,":",error);
handleCatalogResponse(jqxhr,catalog,index); handleCatalogResponse(jqxhr,catalog,index);
}).always(function() { }).always(function() {
handled++; handled++;

View File

@ -165,6 +165,7 @@ RED.palette = (function() {
metaData = typeInfo.set.module+" : "; metaData = typeInfo.set.module+" : ";
} }
metaData += type; metaData += type;
$('<button type="button" onclick="RED.sidebar.help.show(\''+type+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent); $('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
} }
} catch(err) { } catch(err) {
@ -181,7 +182,11 @@ RED.palette = (function() {
function setIcon(element,sf) { function setIcon(element,sf) {
var icon_url = RED.utils.getNodeIcon(sf._def); var icon_url = RED.utils.getNodeIcon(sf._def);
var iconContainer = element.find(".red-ui-palette-icon-container"); var iconContainer = element.find(".red-ui-palette-icon-container");
RED.utils.createIconElement(icon_url, iconContainer, true); var currentIcon = iconContainer.attr("data-palette-icon");
if (currentIcon !== icon_url) {
iconContainer.attr("data-palette-icon", icon_url);
RED.utils.createIconElement(icon_url, iconContainer, true);
}
} }
function getPaletteNode(type) { function getPaletteNode(type) {
@ -224,6 +229,7 @@ RED.palette = (function() {
var iconContainer = $('<div/>', { var iconContainer = $('<div/>', {
class: "red-ui-palette-icon-container"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-icon-container-right" : "") class: "red-ui-palette-icon-container"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-icon-container-right" : "")
}).appendTo(d); }).appendTo(d);
iconContainer.attr("data-palette-icon", icon_url);
RED.utils.createIconElement(icon_url, iconContainer, true); RED.utils.createIconElement(icon_url, iconContainer, true);
} }
@ -250,6 +256,7 @@ RED.palette = (function() {
var popover = RED.popover.create({ var popover = RED.popover.create({
target:d, target:d,
trigger: "hover", trigger: "hover",
interactive: true,
width: "300px", width: "300px",
content: "hi", content: "hi",
delay: { show: 750, hide: 50 } delay: { show: 750, hide: 50 }
@ -265,25 +272,28 @@ RED.palette = (function() {
// html: true, // html: true,
// container:'body' // container:'body'
// }); // });
d.on("click", function() { // d.on("click", function() {
RED.view.focus(); // RED.view.focus();
var helpText; // var helpText;
if (nt.indexOf("subflow:") === 0) { // if (nt.indexOf("subflow:") === 0) {
helpText = marked(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'); // helpText = RED.utils.renderMarkdown(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
} else { // } else {
helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'); // helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
} // }
// Don't look too closely. RED.sidebar.info.set will set the 'Description' // // Don't look too closely. RED.sidebar.info.set will set the 'Description'
// section of the sidebar. Pass in the title of the Help section so it looks // // section of the sidebar. Pass in the title of the Help section so it looks
// right. // // right.
RED.sidebar.info.set(helpText,RED._("sidebar.info.nodeHelp")); // RED.sidebar.type.show(helpText,RED._("sidebar.info.nodeHelp"));
}); // });
var chart = $("#red-ui-workspace-chart"); var chart = $("#red-ui-workspace-chart");
var chartSVG = $("#red-ui-workspace-chart>svg").get(0); var chartSVG = $("#red-ui-workspace-chart>svg").get(0);
var activeSpliceLink; var activeSpliceLink;
var mouseX; var mouseX;
var mouseY; var mouseY;
var spliceTimer; var spliceTimer;
var groupTimer;
var activeGroup;
var hoverGroup;
var paletteWidth; var paletteWidth;
var paletteTop; var paletteTop;
$(d).draggable({ $(d).draggable({
@ -295,16 +305,53 @@ RED.palette = (function() {
start: function() { start: function() {
paletteWidth = $("#red-ui-palette").width(); paletteWidth = $("#red-ui-palette").width();
paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top; paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top;
hoverGroup = null;
activeGroup = RED.view.getActiveGroup();
if (activeGroup) {
document.getElementById("group_select_"+activeGroup.id).classList.add("red-ui-flow-group-active-hovered");
}
RED.view.focus(); RED.view.focus();
}, },
stop: function() { d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}}, stop: function() {
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
if (hoverGroup) {
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
}
if (activeGroup) {
document.getElementById("group_select_"+activeGroup.id).classList.remove("red-ui-flow-group-active-hovered");
}
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
},
drag: function(e,ui) { drag: function(e,ui) {
var paletteNode = getPaletteNode(nt); var paletteNode = getPaletteNode(nt);
ui.originalPosition.left = paletteNode.offset().left; ui.originalPosition.left = paletteNode.offset().left;
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop();
if (!groupTimer) {
groupTimer = setTimeout(function() {
mouseX /= RED.view.scale();
mouseY /= RED.view.scale();
var group = RED.view.getGroupAtPoint(mouseX,mouseY);
if (group !== hoverGroup) {
if (hoverGroup) {
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
}
if (group) {
document.getElementById("group_select_"+group.id).classList.add("red-ui-flow-group-hovered");
}
hoverGroup = group;
if (hoverGroup) {
$(ui.helper).data('group',hoverGroup);
} else {
$(ui.helper).removeData('group');
}
}
groupTimer = null;
},200)
}
if (def.inputs > 0 && def.outputs > 0) { if (def.inputs > 0 && def.outputs > 0) {
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop();
if (!spliceTimer) { if (!spliceTimer) {
spliceTimer = setTimeout(function() { spliceTimer = setTimeout(function() {
var nodes = []; var nodes = [];
@ -370,7 +417,7 @@ RED.palette = (function() {
RED.workspaces.show(nt.substring(8)); RED.workspaces.show(nt.substring(8));
e.preventDefault(); e.preventDefault();
}); });
nodeInfo = marked(def.info||""); nodeInfo = RED.utils.renderMarkdown(def.info||"");
} }
setLabel(nt,d,label,nodeInfo); setLabel(nt,d,label,nodeInfo);
@ -412,61 +459,67 @@ RED.palette = (function() {
categoryNode.show(); categoryNode.show();
paletteNode.show(); paletteNode.show();
} }
function refreshNodeTypes() { function refreshNodeTypes() {
RED.nodes.eachSubflow(function(sf) { RED.nodes.eachSubflow(refreshSubflow)
var paletteNode = getPaletteNode('subflow:'+sf.id); }
var portInput = paletteNode.find(".red-ui-palette-port-input"); function refreshSubflow(sf) {
var portOutput = paletteNode.find(".red-ui-palette-port-output"); var paletteNode = getPaletteNode('subflow:'+sf.id);
var portInput = paletteNode.find(".red-ui-palette-port-input");
var portOutput = paletteNode.find(".red-ui-palette-port-output");
var paletteLabel = paletteNode.find(".red-ui-palette-label"); var paletteLabel = paletteNode.find(".red-ui-palette-label");
paletteLabel.attr("class","red-ui-palette-label" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-label-right" : "")); paletteLabel.attr("class","red-ui-palette-label" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-label-right" : ""));
var paletteIconContainer = paletteNode.find(".red-ui-palette-icon-container"); var paletteIconContainer = paletteNode.find(".red-ui-palette-icon-container");
paletteIconContainer.attr("class","red-ui-palette-icon-container" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-icon-container-right" : "")); paletteIconContainer.attr("class","red-ui-palette-icon-container" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-icon-container-right" : ""));
if (portInput.length === 0 && sf.in.length > 0) { if (portInput.length === 0 && sf.in.length > 0) {
var portIn = document.createElement("div"); var portIn = document.createElement("div");
portIn.className = "red-ui-palette-port red-ui-palette-port-input"; portIn.className = "red-ui-palette-port red-ui-palette-port-input";
paletteNode.append(portIn); paletteNode.append(portIn);
} else if (portInput.length !== 0 && sf.in.length === 0) { } else if (portInput.length !== 0 && sf.in.length === 0) {
portInput.remove(); portInput.remove();
}
if (portOutput.length === 0 && sf.out.length > 0) {
var portOut = document.createElement("div");
portOut.className = "red-ui-palette-port red-ui-palette-port-output";
paletteNode.append(portOut);
} else if (portOutput.length !== 0 && sf.out.length === 0) {
portOutput.remove();
}
var currentLabel = paletteNode.attr("data-palette-label");
var currentInfo = paletteNode.attr("data-palette-info");
if (currentLabel !== sf.name || currentInfo !== sf.info) {
paletteNode.attr("data-palette-info",sf.info);
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,RED.utils.renderMarkdown(sf.info||""));
}
setIcon(paletteNode,sf);
var currentCategory = paletteNode.data('category');
var newCategory = (sf.category||"subflows");
if (currentCategory !== newCategory) {
var category = escapeCategory(newCategory);
createCategory(newCategory,category,category,"node-red");
var currentCategoryNode = paletteNode.closest(".red-ui-palette-category");
var newCategoryNode = $("#red-ui-palette-"+category);
newCategoryNode.append(paletteNode);
if (newCategoryNode.find(".red-ui-palette-node").length === 1) {
categoryContainers[category].open();
} }
if (portOutput.length === 0 && sf.out.length > 0) { paletteNode.data('category',newCategory);
var portOut = document.createElement("div"); if (currentCategoryNode.find(".red-ui-palette-node").length === 0) {
portOut.className = "red-ui-palette-port red-ui-palette-port-output"; if (currentCategoryNode.find("i").hasClass("expanded")) {
paletteNode.append(portOut); currentCategoryNode.find(".red-ui-palette-content").slideToggle();
} else if (portOutput.length !== 0 && sf.out.length === 0) { currentCategoryNode.find("i").toggleClass("expanded");
portOutput.remove();
}
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||""));
setIcon(paletteNode,sf);
var currentCategory = paletteNode.data('category');
var newCategory = (sf.category||"subflows");
if (currentCategory !== newCategory) {
var category = escapeCategory(newCategory);
createCategory(newCategory,category,category,"node-red");
var currentCategoryNode = paletteNode.closest(".red-ui-palette-category");
var newCategoryNode = $("#red-ui-palette-"+category);
newCategoryNode.append(paletteNode);
if (newCategoryNode.find(".red-ui-palette-node").length === 1) {
categoryContainers[category].open();
}
paletteNode.data('category',newCategory);
if (currentCategoryNode.find(".red-ui-palette-node").length === 0) {
if (currentCategoryNode.find("i").hasClass("expanded")) {
currentCategoryNode.find(".red-ui-palette-content").slideToggle();
currentCategoryNode.find("i").toggleClass("expanded");
}
} }
} }
}
paletteNode.css("backgroundColor", sf.color); paletteNode.css("backgroundColor", sf.color);
});
} }
function filterChange(val) { function filterChange(val) {
@ -504,6 +557,8 @@ RED.palette = (function() {
$('<div class="red-ui-component-footer"></div>').appendTo("#red-ui-palette"); $('<div class="red-ui-component-footer"></div>').appendTo("#red-ui-palette");
$('<div id="red-ui-palette-shade" class="hide"></div>').appendTo("#red-ui-palette"); $('<div id="red-ui-palette-shade" class="hide"></div>').appendTo("#red-ui-palette");
$("#red-ui-palette > .red-ui-palette-spinner").show();
RED.events.on('registry:node-type-added', function(nodeType) { RED.events.on('registry:node-type-added', function(nodeType) {
var def = RED.nodes.getType(nodeType); var def = RED.nodes.getType(nodeType);
@ -545,7 +600,8 @@ RED.palette = (function() {
} }
}); });
$("#red-ui-palette > .red-ui-palette-spinner").show(); RED.events.on("subflows:change",refreshSubflow);
$("#red-ui-palette-search input").searchBox({ $("#red-ui-palette-search input").searchBox({

View File

@ -158,7 +158,7 @@ RED.projects.settings = (function() {
container.empty(); container.empty();
var desc; var desc;
if (activeProject.description) { if (activeProject.description) {
desc = marked(activeProject.description); desc = RED.utils.renderMarkdown(activeProject.description);
} else { } else {
desc = '<span class="red-ui-help-info-none">' + RED._("sidebar.project.noDescriptionAvailable") + '</span>'; desc = '<span class="red-ui-help-info-none">' + RED._("sidebar.project.noDescriptionAvailable") + '</span>';
} }

View File

@ -30,13 +30,13 @@ RED.projects.userSettings = (function() {
$('<div class="red-ui-settings-section-description"></div>').appendTo(gitconfigContainer).text(RED._("editor:sidebar.project.userSettings.committerTip")); $('<div class="red-ui-settings-section-description"></div>').appendTo(gitconfigContainer).text(RED._("editor:sidebar.project.userSettings.committerTip"));
var row = $('<div class="red-ui-settings-row"></div>').appendTo(gitconfigContainer); var row = $('<div class="red-ui-settings-row"></div>').appendTo(gitconfigContainer);
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row); $('<label for="user-settings-gitconfig-username"></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row);
gitUsernameInput = $('<input type="text">').appendTo(row); gitUsernameInput = $('<input type="text" id="user-settings-gitconfig-username">').appendTo(row);
gitUsernameInput.val(currentGitSettings.user.name||""); gitUsernameInput.val(currentGitSettings.user.name||"");
row = $('<div class="red-ui-settings-row"></div>').appendTo(gitconfigContainer); row = $('<div class="red-ui-settings-row"></div>').appendTo(gitconfigContainer);
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row); $('<label for="user-settings-gitconfig-email"></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row);
gitEmailInput = $('<input type="text">').appendTo(row); gitEmailInput = $('<input type="text" id="user-settings-gitconfig-email">').appendTo(row);
gitEmailInput.val(currentGitSettings.user.email||""); gitEmailInput.val(currentGitSettings.user.email||"");
} }

View File

@ -685,6 +685,8 @@ RED.projects = (function() {
} }
} }
},projectData).then(function() { },projectData).then(function() {
RED.menu.setDisabled('menu-item-projects-open',false);
RED.menu.setDisabled('menu-item-projects-settings',false);
RED.events.emit("project:change", {name:name}); RED.events.emit("project:change", {name:name});
}).always(function() { }).always(function() {
setTimeout(function() { setTimeout(function() {
@ -1495,7 +1497,6 @@ RED.projects = (function() {
} }
} else if (projectType === 'open') { } else if (projectType === 'open') {
return switchProject(selectedProject.name,function(err,data) { return switchProject(selectedProject.name,function(err,data) {
dialog.dialog( "close" );
if (err) { if (err) {
if (err.code !== 'credentials_load_failed') { if (err.code !== 'credentials_load_failed') {
console.log(RED._("projects.create.unexpected_error"),err) console.log(RED._("projects.create.unexpected_error"),err)
@ -1604,6 +1605,7 @@ RED.projects = (function() {
}, },
} }
},{active:true}).then(function() { },{active:true}).then(function() {
dialog.dialog( "close" );
RED.events.emit("project:change", {name:name}); RED.events.emit("project:change", {name:name});
}).always(function() { }).always(function() {
setTimeout(function() { setTimeout(function() {
@ -1671,16 +1673,27 @@ RED.projects = (function() {
if (typeof buttons === 'function') { if (typeof buttons === 'function') {
buttons = buttons(options||{}); buttons = buttons(options||{});
} }
dialog.dialog('option','buttons',buttons); dialog.dialog('option','buttons',buttons);
dialogBody.append(container); dialogBody.append(container);
var dialogHeight = 590;
var winHeight = $(window).height();
if (winHeight < 750) {
dialogHeight = 590 - (750 - winHeight);
}
$(".red-ui-projects-dialog-box").height(dialogHeight);
$(".red-ui-projects-dialog-project-list-inner-container").height(Math.max(500,dialogHeight) - 180);
dialog.dialog('option','title',screen.title||""); dialog.dialog('option','title',screen.title||"");
dialog.dialog("open"); dialog.dialog("open");
dialog.dialog({position: { 'my': 'center top', 'at': 'center top+20', 'of': window }});
} }
function createProjectList(options) { function createProjectList(options) {
options = options||{}; options = options||{};
var height = options.height || "300px"; var height = options.height || "200px";
var container = $('<div></div>',{class:"red-ui-projects-dialog-project-list-container" }); var container = $('<div></div>',{class:"red-ui-projects-dialog-project-list-container" });
var filterTerm = ""; var filterTerm = "";
@ -1939,100 +1952,121 @@ RED.projects = (function() {
} }
}).fail(function(xhr,textStatus,err) { }).fail(function(xhr,textStatus,err) {
var responses; var responses;
if (options.responses && options.responses[xhr.status]) { if (options.responses && options.responses[xhr.status]) {
responses = options.responses[xhr.status]; responses = options.responses[xhr.status];
if (typeof responses === 'function') { if (typeof responses === 'function') {
resultCallback = responses; resultCallback = responses;
resultCallbackArgs = {error:responses.statusText}; resultCallbackArgs = {error:responses.statusText};
return; return;
} else if (options.handleAuthFail !== false && xhr.responseJSON.code === 'git_auth_failed') { } else if (options.handleAuthFail !== false && (xhr.responseJSON.code === 'git_auth_failed' || xhr.responseJSON.code === 'git_host_key_verification_failed')) {
var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch; if (xhr.responseJSON.code === 'git_auth_failed') {
var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch;
var message = $('<div>'+ var message = $('<div>'+
'<div class="form-row">'+RED._("projects.send-req.auth-req")+':</div>'+ '<div class="form-row">'+RED._("projects.send-req.auth-req")+':</div>'+
'<div class="form-row"><div style="margin-left: 20px;">'+url+'</div></div>'+ '<div class="form-row"><div style="margin-left: 20px;">'+url+'</div></div>'+
'</div>'); '</div>');
var isSSH = false; var isSSH = false;
if (/^https?:\/\//.test(url)) { if (/^https?:\/\//.test(url)) {
$('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+ $('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+
'<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message); '<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
} else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) { } else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
isSSH = true; isSSH = true;
var row = $('<div class="form-row"></div>').appendTo(message); var row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-key">SSH Key</label>').appendTo(row); $('<label for="projects-user-auth-key">SSH Key</label>').appendTo(row);
var projectRepoSSHKeySelect = $('<select id="projects-user-auth-key">').width('70%').appendTo(row); var projectRepoSSHKeySelect = $('<select id="projects-user-auth-key">').width('70%').appendTo(row);
$.getJSON("settings/user/keys", function(data) { $.getJSON("settings/user/keys", function(data) {
var count = 0; var count = 0;
data.keys.forEach(function(key) { data.keys.forEach(function(key) {
projectRepoSSHKeySelect.append($("<option></option>").val(key.name).text(key.name)); projectRepoSSHKeySelect.append($("<option></option>").val(key.name).text(key.name));
count++; count++;
});
if (count === 0) {
//TODO: handle no keys yet setup
}
}); });
if (count === 0) { row = $('<div class="form-row"></div>').appendTo(message);
//TODO: handle no keys yet setup $('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row);
} $('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row);
}); }
row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row);
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row);
}
var notification = RED.notify(message,{ var notification = RED.notify(message,{
type:"error", type:"error",
fixed: true, fixed: true,
modal: true, modal: true,
buttons: [ buttons: [
{ {
//id: "node-dialog-delete", //id: "node-dialog-delete",
//class: 'leftButton', //class: 'leftButton',
text: RED._("common.label.cancel"), text: RED._("common.label.cancel"),
click: function() { click: function() {
notification.close(); notification.close();
}
},{
text: '<span><i class="fa fa-refresh"></i> ' +RED._("projects.send-req.retry") +'</span>',
click: function() {
body = body || {};
var authBody = {};
if (isSSH) {
authBody.keyFile = $('#projects-user-auth-key').val();
authBody.passphrase = $('#projects-user-auth-passphrase').val();
} else {
authBody.username = $('#projects-user-auth-username').val();
authBody.password = $('#projects-user-auth-password').val();
} }
var done = function(err) { },{
if (err) { text: '<span><i class="fa fa-refresh"></i> ' +RED._("projects.send-req.retry") +'</span>',
console.log(RED._("projects.send-req.update-failed")); click: function() {
console.log(err); body = body || {};
var authBody = {};
if (isSSH) {
authBody.keyFile = $('#projects-user-auth-key').val();
authBody.passphrase = $('#projects-user-auth-passphrase').val();
} else { } else {
sendRequest(options,body); authBody.username = $('#projects-user-auth-username').val();
notification.close(); authBody.password = $('#projects-user-auth-password').val();
} }
var done = function(err) {
if (err) {
console.log(RED._("projects.send-req.update-failed"));
console.log(err);
} else {
sendRequest(options,body);
notification.close();
}
}
sendRequest({
url: "projects/"+activeProject.name+"/remotes/"+(xhr.responseJSON.remote||options.remote||'origin'),
type: "PUT",
responses: {
0: function(error) {
done(error,null);
},
200: function(data) {
done(null,data);
},
400: {
'unexpected_error': function(error) {
done(error,null);
}
},
} }
},{auth:authBody}); sendRequest({
url: "projects/"+activeProject.name+"/remotes/"+(xhr.responseJSON.remote||options.remote||'origin'),
type: "PUT",
responses: {
0: function(error) {
done(error,null);
},
200: function(data) {
done(null,data);
},
400: {
'unexpected_error': function(error) {
done(error,null);
}
},
}
},{auth:authBody});
}
} }
} ]
] });
}); return;
return; } else if (xhr.responseJSON.code === 'git_host_key_verification_failed') {
var message = $('<div>'+
'<div class="form-row">'+RED._("projects.send-req.host-key-verify-failed")+'</div>'+
'</div>');
var notification = RED.notify(message,{
type:"error",
fixed: true,
modal: true,
buttons: [
{
text: RED._("common.label.close"),
click: function() {
notification.close();
}
}
]
});
return;
}
} else if (responses[xhr.responseJSON.code]) { } else if (responses[xhr.responseJSON.code]) {
resultCallback = responses[xhr.responseJSON.code]; resultCallback = responses[xhr.responseJSON.code];
resultCallbackArgs = xhr.responseJSON; resultCallbackArgs = xhr.responseJSON;
@ -2066,6 +2100,8 @@ RED.projects = (function() {
var branchFilterTerm = ""; var branchFilterTerm = "";
var branchFilterCreateItem; var branchFilterCreateItem;
var branches = []; var branches = [];
var branchNames = new Set();
var remotes = [];
var branchPrefix = ""; var branchPrefix = "";
var container = $('<div class="red-ui-projects-branch-list">').appendTo(options.container); var container = $('<div class="red-ui-projects-branch-list">').appendTo(options.container);
@ -2073,18 +2109,30 @@ RED.projects = (function() {
delay: 200, delay: 200,
change: function() { change: function() {
branchFilterTerm = $(this).val(); branchFilterTerm = $(this).val();
if (/(\.\.|\/\.|[?*[~^: \\]|\/\/|\/.$|\/$)/.test(branchFilterTerm)) { // if there is a / then
// - check what preceeds it is a known remote
var valid = false;
var hasRemote = false;
var m = /^([^/]+)\/[^/.~*?\[]/.exec(branchFilterTerm);
if (m && remotes.indexOf(m[1]) > -1) {
valid = true;
hasRemote = true;
}
if (!valid && /(\.\.|\/\.|[?*[~^: \\]|\/\/|\/.$|\/$)/.test(branchFilterTerm)) {
if (!branchFilterCreateItem.hasClass("input-error")) { if (!branchFilterCreateItem.hasClass("input-error")) {
branchFilterCreateItem.addClass("input-error"); branchFilterCreateItem.addClass("input-error");
branchFilterCreateItem.find("i").addClass("fa-warning").removeClass("fa-code-fork"); branchFilterCreateItem.find("i").addClass("fa-warning").removeClass("fa-code-fork");
} }
branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.invalid")+": "+branchPrefix+branchFilterTerm); branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.invalid")+": "+(hasRemote?"":branchPrefix)+branchFilterTerm);
} else { } else {
if (branchFilterCreateItem.hasClass("input-error")) { if (branchFilterCreateItem.hasClass("input-error")) {
branchFilterCreateItem.removeClass("input-error"); branchFilterCreateItem.removeClass("input-error");
branchFilterCreateItem.find("i").removeClass("fa-warning").addClass("fa-code-fork"); branchFilterCreateItem.find("i").removeClass("fa-warning").addClass("fa-code-fork");
} }
branchFilterCreateItem.find(".red-ui-sidebar-vc-branch-list-entry-create-name").text(branchPrefix+branchFilterTerm); branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.create")+":");
branchFilterCreateItem.find(".red-ui-sidebar-vc-branch-list-entry-create-name").text((hasRemote?"":branchPrefix)+branchFilterTerm);
} }
branchList.editableList("filter"); branchList.editableList("filter");
} }
@ -2117,8 +2165,12 @@ RED.projects = (function() {
if (!entry.hasOwnProperty('commit')) { if (!entry.hasOwnProperty('commit')) {
body.name = branchFilter.val(); body.name = branchFilter.val();
body.create = true; body.create = true;
if (options.remote) {
body.name = options.remote()+"/"+body.name; if (options.remotes) {
var m = /^([^/]+)\/[^/.~*?\[]/.exec(body.name);
if (!m || remotes.indexOf(m[1]) === -1) {
body.name = remotes[0]+"/"+body.name;
}
} }
} else { } else {
if ($(this).hasClass('selected')) { if ($(this).hasClass('selected')) {
@ -2133,11 +2185,17 @@ RED.projects = (function() {
}, },
filter: function(data) { filter: function(data) {
var isCreateEntry = (!data.hasOwnProperty('commit')); var isCreateEntry = (!data.hasOwnProperty('commit'));
var filterTerm = branchFilterTerm;
if (remotes.length > 0) {
var m = /^([^/]+)\/[^/.~*?\[]/.exec(filterTerm);
if (filterTerm !== "" && (!m || remotes.indexOf(m[1]) == -1)) {
filterTerm = remotes[0]+"/"+filterTerm;
}
}
return ( return (
isCreateEntry && isCreateEntry &&
( (
branchFilterTerm !== "" && filterTerm !== "" && !branchNames.has(filterTerm)
branches.indexOf(branchPrefix+branchFilterTerm) === -1
) )
) || ) ||
( (
@ -2152,12 +2210,14 @@ RED.projects = (function() {
branchList.editableList('empty'); branchList.editableList('empty');
var start = Date.now(); var start = Date.now();
var spinner = addSpinnerOverlay(container).addClass("red-ui-component-spinner-contain"); var spinner = addSpinnerOverlay(container).addClass("red-ui-component-spinner-contain");
if (options.remote) { if (options.remotes) {
branchPrefix = options.remote()+"/"; remotes = options.remotes();
branchPrefix = remotes[0]+"/";
} else { } else {
branchPrefix = ""; branchPrefix = "";
remotes = [];
} }
branchNames = new Set();
sendRequest({ sendRequest({
url: url, url: url,
type: "GET", type: "GET",
@ -2169,6 +2229,7 @@ RED.projects = (function() {
branches = result.branches; branches = result.branches;
result.branches.forEach(function(b) { result.branches.forEach(function(b) {
branchList.editableList('addItem',b); branchList.editableList('addItem',b);
branchNames.add(b.name);
}); });
branchList.editableList('addItem',{}); branchList.editableList('addItem',{});
setTimeout(function() { setTimeout(function() {
@ -2204,7 +2265,7 @@ RED.projects = (function() {
} }
function init() { function init() {
dialog = $('<div id="red-ui-projects-dialog" class="hide red-ui-projects-edit-form"><form class="form-horizontal"></form><div class="red-ui-component-spinner hide"><img src="red/images/spin.svg"/></div></div>') dialog = $('<div id="red-ui-projects-dialog" class="hide red-ui-projects-edit-form"><div class="red-ui-projects-dialog-box"><form class="form-horizontal"></form><div class="red-ui-component-spinner hide"><img src="red/images/spin.svg"/></div></div></div>')
.appendTo("#red-ui-editor") .appendTo("#red-ui-editor")
.dialog({ .dialog({
modal: true, modal: true,
@ -2291,6 +2352,7 @@ RED.projects = (function() {
if (data.active) { if (data.active) {
$.getJSON("projects/"+data.active, function(project) { $.getJSON("projects/"+data.active, function(project) {
activeProject = project; activeProject = project;
RED.events.emit("projects:load",activeProject);
RED.sidebar.versionControl.refresh(true); RED.sidebar.versionControl.refresh(true);
if (done) { if (done) {
done(activeProject); done(activeProject);

View File

@ -830,10 +830,9 @@ RED.sidebar.versionControl = (function() {
var remoteBranchList = utils.createBranchList({ var remoteBranchList = utils.createBranchList({
placeholder: RED._("sidebar.project.versionControl.createRemoteBranchPlaceholder"), placeholder: RED._("sidebar.project.versionControl.createRemoteBranchPlaceholder"),
currentLabel: RED._("sidebar.project.versionControl.upstream"), currentLabel: RED._("sidebar.project.versionControl.upstream"),
remote: function() { remotes: function() {
var project = RED.projects.getActiveProject(); var project = RED.projects.getActiveProject();
var remotes = Object.keys(project.git.remotes); return Object.keys(project.git.remotes);
return remotes[0];
}, },
container: remoteBranchSubRow, container: remoteBranchSubRow,
onselect: function(body) { onselect: function(body) {

View File

@ -23,8 +23,7 @@ RED.search = (function() {
var visible = false; var visible = false;
var index = {}; var index = {};
var keys = []; var currentResults = [];
var results = [];
var previousActiveElement; var previousActiveElement;
@ -66,23 +65,9 @@ RED.search = (function() {
} }
} }
function indexWorkspace() {
index = {};
RED.nodes.eachWorkspace(indexNode);
RED.nodes.eachSubflow(indexNode);
RED.nodes.eachConfig(indexNode);
RED.nodes.eachNode(indexNode);
keys = Object.keys(index);
keys.sort();
keys.forEach(function(key) {
index[key] = Object.keys(index[key]).map(function(id) {
return index[key][id];
})
})
}
function search(val) { function search(val) {
searchResults.editableList('empty'); var results = [];
var keys = Object.keys(index);
var typeFilter; var typeFilter;
var m = /(?:^| )type:([^ ]+)/.exec(val); var m = /(?:^| )type:([^ ]+)/.exec(val);
if (m) { if (m) {
@ -92,8 +77,7 @@ RED.search = (function() {
val = val.trim(); val = val.trim();
selected = -1;
results = [];
if (val.length > 0 || typeFilter) { if (val.length > 0 || typeFilter) {
val = val.toLowerCase(); val = val.toLowerCase();
var i; var i;
@ -104,10 +88,14 @@ RED.search = (function() {
var key = keys[i]; var key = keys[i];
var kpos = keys[i].indexOf(val); var kpos = keys[i].indexOf(val);
if (kpos > -1) { if (kpos > -1) {
for (j=0;j<index[key].length;j++) { var ids = Object.keys(index[key]);
var node = index[key][j]; for (j=0;j<ids.length;j++) {
var node = index[key][ids[j]];
if (!typeFilter || node.node.type === typeFilter) { if (!typeFilter || node.node.type === typeFilter) {
nodes[node.node.id] = nodes[node.node.id] = node; nodes[node.node.id] = nodes[node.node.id] = {
node: node.node,
label: node.label
};
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos); nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
} }
} }
@ -121,22 +109,8 @@ RED.search = (function() {
for (i=0;i<list.length;i++) { for (i=0;i<list.length;i++) {
results.push(nodes[list[i]]); results.push(nodes[list[i]]);
} }
if (results.length > 0) {
for (i=0;i<Math.min(results.length,25);i++) {
searchResults.editableList('addItem',results[i])
}
if (results.length > 25) {
searchResults.editableList('addItem', {
more: {
results: results,
start: 25
}
})
}
} else {
searchResults.editableList('addItem',{});
}
} }
return results;
} }
function ensureSelectedIsVisible() { function ensureSelectedIsVisible() {
@ -161,13 +135,37 @@ RED.search = (function() {
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.searchInput">').appendTo(searchDiv).searchBox({ searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.searchInput">').appendTo(searchDiv).searchBox({
delay: 200, delay: 200,
change: function() { change: function() {
search($(this).val()); searchResults.editableList('empty');
selected = -1;
currentResults = search($(this).val());
if (currentResults.length > 0) {
for (i=0;i<Math.min(currentResults.length,25);i++) {
searchResults.editableList('addItem',currentResults[i])
}
if (currentResults.length > 25) {
searchResults.editableList('addItem', {
more: {
results: currentResults,
start: 25
}
})
}
} else {
searchResults.editableList('addItem',{});
}
} }
}); });
var copySearchContainer = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-caret-right"></button>').appendTo(searchDiv).on('click', function(evt) {
evt.preventDefault();
RED.sidebar.info.outliner.search(searchInput.val())
hide();
});
searchInput.on('keydown',function(evt) { searchInput.on('keydown',function(evt) {
var children; var children;
if (results.length > 0) { if (currentResults.length > 0) {
if (evt.keyCode === 40) { if (evt.keyCode === 40) {
// Down // Down
children = searchResults.children(); children = searchResults.children();
@ -199,21 +197,21 @@ RED.search = (function() {
var object = $(children[selected]).find(".red-ui-editableList-item-content").data('data'); var object = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
if (object) { if (object) {
searchResults.editableList('removeItem',object); searchResults.editableList('removeItem',object);
for (i=object.more.start;i<Math.min(results.length,object.more.start+25);i++) { for (i=object.more.start;i<Math.min(currentResults.length,object.more.start+25);i++) {
searchResults.editableList('addItem',results[i]) searchResults.editableList('addItem',currentResults[i])
} }
if (results.length > object.more.start+25) { if (currentResults.length > object.more.start+25) {
searchResults.editableList('addItem', { searchResults.editableList('addItem', {
more: { more: {
results: results, results: currentResults,
start: object.more.start+25 start: object.more.start+25
} }
}) })
} }
} }
} else { } else {
if (results.length > 0) { if (currentResults.length > 0) {
reveal(results[Math.max(0,selected)].node); reveal(currentResults[Math.max(0,selected)].node);
} }
} }
} }
@ -234,13 +232,13 @@ RED.search = (function() {
div.on("click", function(evt) { div.on("click", function(evt) {
evt.preventDefault(); evt.preventDefault();
searchResults.editableList('removeItem',object); searchResults.editableList('removeItem',object);
for (i=object.more.start;i<Math.min(results.length,object.more.start+25);i++) { for (i=object.more.start;i<Math.min(currentResults.length,object.more.start+25);i++) {
searchResults.editableList('addItem',results[i]) searchResults.editableList('addItem',currentResults[i])
} }
if (results.length > object.more.start+25) { if (currentResults.length > object.more.start+25) {
searchResults.editableList('addItem', { searchResults.editableList('addItem', {
more: { more: {
results: results, results: currentResults,
start: object.more.start+25 start: object.more.start+25
} }
}) })
@ -253,17 +251,7 @@ RED.search = (function() {
var def = node._def; var def = node._def;
div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container); div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div); RED.utils.createNodeIcon(node).appendTo(div);
var colour = RED.utils.getNodeColor(node.type,def);
var icon_url = RED.utils.getNodeIcon(def,node);
if (node.type === 'tab') {
colour = "#C0DEED";
}
nodeDiv.css('backgroundColor',colour);
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
var contentDiv = $('<div>',{class:"red-ui-search-result-node-description"}).appendTo(div); var contentDiv = $('<div>',{class:"red-ui-search-result-node-description"}).appendTo(div);
if (node.z) { if (node.z) {
var workspace = RED.nodes.workspace(node.z); var workspace = RED.nodes.workspace(node.z);
@ -308,7 +296,7 @@ RED.search = (function() {
$("#red-ui-palette-shade").show(); $("#red-ui-palette-shade").show();
$("#red-ui-sidebar-shade").show(); $("#red-ui-sidebar-shade").show();
$("#red-ui-sidebar-separator").hide(); $("#red-ui-sidebar-separator").hide();
indexWorkspace();
if (dialog === null) { if (dialog === null) {
createDialog(); createDialog();
} }
@ -342,6 +330,28 @@ RED.search = (function() {
} }
} }
function clearIndex() {
index = {};
}
function addItemToIndex(item) {
indexNode(item);
}
function removeItemFromIndex(item) {
var keys = Object.keys(index);
for (var i=0,l=keys.length;i<l;i++) {
delete index[keys[i]][item.id];
if (Object.keys(index[keys[i]]).length === 0) {
delete index[keys[i]];
}
}
}
function updateItemOnIndex(item) {
removeItemFromIndex(item);
addItemToIndex(item);
}
function init() { function init() {
RED.actions.add("core:search",show); RED.actions.add("core:search",show);
@ -358,12 +368,33 @@ RED.search = (function() {
$("#red-ui-editor-shade").on('mousedown',hide); $("#red-ui-editor-shade").on('mousedown',hide);
$("#red-ui-palette-shade").on('mousedown',hide); $("#red-ui-palette-shade").on('mousedown',hide);
$("#red-ui-sidebar-shade").on('mousedown',hide); $("#red-ui-sidebar-shade").on('mousedown',hide);
RED.events.on("workspace:clear", clearIndex)
RED.events.on("flows:add", addItemToIndex)
RED.events.on("flows:remove", removeItemFromIndex)
RED.events.on("flows:change", updateItemOnIndex)
RED.events.on("subflows:add", addItemToIndex)
RED.events.on("subflows:remove", removeItemFromIndex)
RED.events.on("subflows:change", updateItemOnIndex)
RED.events.on("nodes:add",addItemToIndex);
RED.events.on("nodes:remove",removeItemFromIndex);
RED.events.on("nodes:change",updateItemOnIndex);
RED.events.on("groups:add",addItemToIndex);
RED.events.on("groups:remove",removeItemFromIndex);
RED.events.on("groups:change",updateItemOnIndex);
} }
return { return {
init: init, init: init,
show: show, show: show,
hide: hide hide: hide,
search: search
}; };
})(); })();

View File

@ -250,6 +250,7 @@ RED.sidebar = (function() {
RED.popover.tooltip($("#red-ui-sidebar-separator").find(".red-ui-sidebar-control-right"),RED._("keyboard.toggleSidebar"),"core:toggle-sidebar"); RED.popover.tooltip($("#red-ui-sidebar-separator").find(".red-ui-sidebar-control-right"),RED._("keyboard.toggleSidebar"),"core:toggle-sidebar");
showSidebar(); showSidebar();
RED.sidebar.info.init(); RED.sidebar.info.init();
RED.sidebar.help.init();
RED.sidebar.config.init(); RED.sidebar.config.init();
RED.sidebar.context.init(); RED.sidebar.context.init();
// hide info bar at start if screen rather narrow... // hide info bar at start if screen rather narrow...

View File

@ -25,5 +25,7 @@ RED.state = {
IMPORT_DRAGGING: 8, IMPORT_DRAGGING: 8,
QUICK_JOINING: 9, QUICK_JOINING: 9,
PANNING: 10, PANNING: 10,
SELECTING_NODE: 11 SELECTING_NODE: 11,
GROUP_DRAGGING: 12,
GROUP_RESIZE: 13
} }

View File

@ -106,7 +106,7 @@ RED.subflow = (function() {
RED.view.redraw(); RED.view.redraw();
$("#red-ui-subflow-input-add").addClass("active"); $("#red-ui-subflow-input-add").addClass("active");
$("#red-ui-subflow-input-remove").removeClass("active"); $("#red-ui-subflow-input-remove").removeClass("active");
RED.palette.refresh(); RED.events.emit("subflows:change",subflow);
} }
function removeSubflowInput() { function removeSubflowInput() {
@ -128,7 +128,7 @@ RED.subflow = (function() {
$("#red-ui-subflow-input-add").removeClass("active"); $("#red-ui-subflow-input-add").removeClass("active");
$("#red-ui-subflow-input-remove").addClass("active"); $("#red-ui-subflow-input-remove").addClass("active");
activeSubflow.changed = true; activeSubflow.changed = true;
RED.palette.refresh(); RED.events.emit("subflows:change",activeSubflow);
return {subflowInputs: [ removedInput ], links:removedInputLinks}; return {subflowInputs: [ removedInput ], links:removedInputLinks};
} }
@ -169,7 +169,7 @@ RED.subflow = (function() {
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.view.redraw(); RED.view.redraw();
$("#red-ui-subflow-output .spinner-value").text(subflow.out.length); $("#red-ui-subflow-output .spinner-value").text(subflow.out.length);
RED.palette.refresh(); RED.events.emit("subflows:change",subflow);
} }
function removeSubflowOutput(removedSubflowOutputs) { function removeSubflowOutput(removedSubflowOutputs) {
@ -209,7 +209,7 @@ RED.subflow = (function() {
} }
} }
activeSubflow.changed = true; activeSubflow.changed = true;
RED.palette.refresh(); RED.events.emit("subflows:change",activeSubflow);
return {subflowOutputs: removedSubflowOutputs, links: removedLinks} return {subflowOutputs: removedSubflowOutputs, links: removedLinks}
} }
@ -244,6 +244,7 @@ RED.subflow = (function() {
RED.view.select(); RED.view.select();
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.view.redraw(); RED.view.redraw();
RED.events.emit("subflows:change",subflow);
$("#red-ui-subflow-status").prop("checked",!!subflow.status); $("#red-ui-subflow-status").prop("checked",!!subflow.status);
$("#red-ui-subflow-status").parent().parent().toggleClass("active",!!subflow.status); $("#red-ui-subflow-status").parent().parent().toggleClass("active",!!subflow.status);
} }
@ -462,15 +463,15 @@ RED.subflow = (function() {
var activeSubflow = RED.nodes.subflow(id); var activeSubflow = RED.nodes.subflow(id);
RED.nodes.eachNode(function(n) { RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+activeSubflow.id) { if (n.type == "subflow:"+id) {
removedNodes.push(n); removedNodes.push(n);
} }
if (n.z == activeSubflow.id) { if (n.z == id) {
removedNodes.push(n); removedNodes.push(n);
} }
}); });
RED.nodes.eachConfig(function(n) { RED.nodes.eachConfig(function(n) {
if (n.z == activeSubflow.id) { if (n.z == id) {
removedNodes.push(n); removedNodes.push(n);
} }
}); });
@ -567,6 +568,34 @@ RED.subflow = (function() {
return; return;
} }
var i,n; var i,n;
var nodeList = new Set();
var tmplist = selection.nodes.slice();
var includedGroups = new Set();
while(tmplist.length > 0) {
n = tmplist.shift();
if (n.type === "group") {
includedGroups.add(n.id);
tmplist = tmplist.concat(n.nodes);
}
nodeList.add(n);
}
nodeList = Array.from(nodeList);
var containingGroup = nodeList[0].g;
var nodesMovedFromGroup = [];
for (i=0; i<nodeList.length;i++) {
if (nodeList[i].g && !includedGroups.has(nodeList[i].g)) {
if (containingGroup !== nodeList[i].g) {
RED.notify("Cannot create subflow across multiple groups","error");
return;
}
}
}
if (containingGroup) {
containingGroup = RED.nodes.group(containingGroup);
}
var nodes = {}; var nodes = {};
var new_links = []; var new_links = [];
var removedLinks = []; var removedLinks = [];
@ -575,13 +604,13 @@ RED.subflow = (function() {
var candidateOutputs = []; var candidateOutputs = [];
var candidateInputNodes = {}; var candidateInputNodes = {};
var boundingBox = [selection.nodes[0].x, var boundingBox = [nodeList[0].x,
selection.nodes[0].y, nodeList[0].y,
selection.nodes[0].x, nodeList[0].x,
selection.nodes[0].y]; nodeList[0].y];
for (i=0;i<selection.nodes.length;i++) { for (i=0;i<nodeList.length;i++) {
n = selection.nodes[i]; n = nodeList[i];
nodes[n.id] = {n:n,outputs:{}}; nodes[n.id] = {n:n,outputs:{}};
boundingBox = [ boundingBox = [
Math.min(boundingBox[0],n.x), Math.min(boundingBox[0],n.x),
@ -690,6 +719,20 @@ RED.subflow = (function() {
RED.editor.validateNode(subflowInstance); RED.editor.validateNode(subflowInstance);
RED.nodes.add(subflowInstance); RED.nodes.add(subflowInstance);
if (containingGroup) {
RED.group.addToGroup(containingGroup, subflowInstance);
nodeList.forEach(function(nl) {
if (nl.g === containingGroup.id) {
delete nl.g;
var index = containingGroup.nodes.indexOf(nl);
containingGroup.nodes.splice(index,1);
nodesMovedFromGroup.push(nl);
}
})
containingGroup.dirty = true;
}
candidateInputs.forEach(function(l) { candidateInputs.forEach(function(l) {
var link = {source:l.source, sourcePort:l.sourcePort, target: subflowInstance}; var link = {source:l.source, sourcePort:l.sourcePort, target: subflowInstance};
new_links.push(link); new_links.push(link);
@ -723,8 +766,8 @@ RED.subflow = (function() {
RED.nodes.removeLink(removedLinks[i]); RED.nodes.removeLink(removedLinks[i]);
} }
for (i=0;i<selection.nodes.length;i++) { for (i=0;i<nodeList.length;i++) {
n = selection.nodes[i]; n = nodeList[i];
if (/^link /.test(n.type)) { if (/^link /.test(n.type)) {
n.links = n.links.filter(function(id) { n.links = n.links.filter(function(id) {
var isLocalLink = nodes.hasOwnProperty(id); var isLocalLink = nodes.hasOwnProperty(id);
@ -745,7 +788,8 @@ RED.subflow = (function() {
RED.nodes.moveNodeToTab(n, subflow.id); RED.nodes.moveNodeToTab(n, subflow.id);
} }
RED.history.push({
var historyEvent = {
t:'createSubflow', t:'createSubflow',
nodes:[subflowInstance.id], nodes:[subflowInstance.id],
links:new_links, links:new_links,
@ -759,11 +803,29 @@ RED.subflow = (function() {
removedLinks: removedLinks, removedLinks: removedLinks,
dirty:RED.nodes.dirty() dirty:RED.nodes.dirty()
}); }
RED.view.select(null); if (containingGroup) {
historyEvent = {
t:'multi',
events: [ historyEvent ]
}
historyEvent.events.push({
t:'addToGroup',
group: containingGroup,
nodes: [subflowInstance]
})
historyEvent.events.push({
t:'removeFromGroup',
group: containingGroup,
nodes: nodesMovedFromGroup,
reparent: false
})
}
RED.history.push(historyEvent);
RED.editor.validateNode(subflow); RED.editor.validateNode(subflow);
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.view.redraw(true); RED.view.updateActive();
RED.view.select(null);
} }

View File

@ -231,7 +231,8 @@ RED.sidebar.context = (function() {
RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), { RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), {
typeHint: data.format, typeHint: data.format,
sourceId: id+"."+k, sourceId: id+"."+k,
tools: tools tools: tools,
path: ""
}).appendTo(propRow.children()[1]); }).appendTo(propRow.children()[1]);
} }
}) })
@ -275,7 +276,8 @@ RED.sidebar.context = (function() {
RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), { RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), {
typeHint: data.format, typeHint: data.format,
sourceId: id+"."+k, sourceId: id+"."+k,
tools: tools tools: tools,
path: ""
}).appendTo(propRow.children()[1]); }).appendTo(propRow.children()[1]);
} }
}); });
@ -295,7 +297,8 @@ RED.sidebar.context = (function() {
RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), { RED.utils.createObjectElement(RED.utils.decodeObject(payload,format), {
typeHint: v.format, typeHint: v.format,
sourceId: id+"."+k, sourceId: id+"."+k,
tools: tools tools: tools,
path: ""
}).appendTo(propRow.children()[1]); }).appendTo(propRow.children()[1]);
if (contextStores.length > 1) { if (contextStores.length > 1) {
$("<span>",{class:"red-ui-sidebar-context-property-storename"}).text(v.store).appendTo($(propRow.children()[0])) $("<span>",{class:"red-ui-sidebar-context-property-storename"}).text(v.store).appendTo($(propRow.children()[0]))

View File

@ -0,0 +1,332 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.sidebar.help = (function() {
var content;
var toolbar;
var helpSection;
var panels;
var panelRatio;
var helpTopics = [];
var treeList;
var tocPanel;
var helpIndex = {};
function resizeStack() {
var h = $(content).parent().height() - toolbar.outerHeight();
panels.resize(h)
}
function init() {
content = document.createElement("div");
content.className = "red-ui-sidebar-info"
toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(content);
$('<span class="button-group"><a id="red-ui-sidebar-help-show-toc" class="red-ui-button red-ui-button-small selected" href="#"><i class="fa fa-list-ul"></i></a></span>').appendTo(toolbar)
var showTOCButton = toolbar.find('#red-ui-sidebar-help-show-toc')
RED.popover.tooltip(showTOCButton,RED._("sidebar.help.showTopics"));
showTOCButton.on("click",function(e) {
e.preventDefault();
if ($(this).hasClass('selected')) {
hideTOC();
} else {
showTOC();
}
});
var stackContainer = $("<div>",{class:"red-ui-sidebar-help-stack"}).appendTo(content);
tocPanel = $("<div>", {class: "red-ui-sidebar-help-toc"}).appendTo(stackContainer);
var helpPanel = $("<div>").css({
"overflow-y": "scroll"
}).appendTo(stackContainer);
panels = RED.panels.create({
container: stackContainer
})
panels.ratio(0.3);
helpSearch = $('<input type="text" data-i18n="[placeholder]sidebar.help.search">').appendTo(toolbar).searchBox({
delay: 100,
change: function() {
var val = $(this).val().toLowerCase();
if (val) {
showTOC();
var c = treeList.treeList('filter',function(item) {
if (item.depth === 0) {
return true;
}
return (item.nodeType && item.nodeType.indexOf(val) > -1) ||
(item.subflowLabel && item.subflowLabel.indexOf(val) > -1)
},true)
} else {
treeList.treeList('filter',null);
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected.id);
}
}
}
})
helpSection = $("<div>",{class:"red-ui-help"}).css({
"padding":"6px",
}).appendTo(helpPanel)
$('<span class="red-ui-help-info-none">'+RED._("sidebar.help.noHelp")+'</span>').appendTo(helpSection);
treeList = $("<div>").css({width: "100%"}).appendTo(tocPanel).treeList({data: []})
treeList.on('treelistselect', function(e,item) {
if (item.nodeType) {
showHelp(item.nodeType);
}
})
RED.sidebar.addTab({
id: "help",
label: RED._("sidebar.help.label"),
name: RED._("sidebar.help.name"),
iconClass: "fa fa-book",
action:"core:show-help-tab",
content: content,
pinned: true,
enableOnEdit: true,
onchange: function() {
resizeStack()
}
});
$(window).on("resize", resizeStack);
$(window).on("focus", resizeStack);
RED.events.on('registry:node-type-added', queueRefresh);
RED.events.on('registry:node-type-removed', queueRefresh);
RED.events.on('subflows:change', refreshSubflow);
RED.actions.add("core:show-help-tab",show);
}
var refreshTimer;
function queueRefresh() {
if (!refreshTimer) {
refreshTimer = setTimeout(function() {
refreshTimer = null;
refreshHelpIndex();
},500);
}
}
function refreshSubflow(sf) {
var item = treeList.treeList('get',"node-type:subflow:"+sf.id);
item.subflowLabel = sf._def.label().toLowerCase();
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()}));
}
function hideTOC() {
var tocButton = $('#red-ui-sidebar-help-show-toc')
if (tocButton.hasClass('selected')) {
tocButton.removeClass('selected');
panelRatio = panels.ratio();
tocPanel.css({"transition":"height 0.2s"})
panels.ratio(0)
setTimeout(function() {
tocPanel.css({"transition":""})
},250);
}
}
function showTOC() {
var tocButton = $('#red-ui-sidebar-help-show-toc')
if (!tocButton.hasClass('selected')) {
tocButton.addClass('selected');
tocPanel.css({"transition":"height 0.2s"})
panels.ratio(Math.max(0.3,Math.min(panelRatio,0.7)));
setTimeout(function() {
tocPanel.css({"transition":""})
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected);
}
},250);
}
}
function refreshHelpIndex() {
helpTopics = [];
var modules = RED.nodes.registry.getModuleList();
var moduleNames = Object.keys(modules);
moduleNames.sort();
var helpData = [{
label: RED._("sidebar.help.nodeHelp"),
children: [],
expanded: true
}]
var subflows = RED.nodes.registry.getNodeTypes().filter(function(t) {return /subflow/.test(t)});
if (subflows.length > 0) {
helpData[0].children.push({
label: RED._("menu.label.subflows"),
children: []
})
subflows.forEach(function(nodeType) {
var sf = RED.nodes.getType(nodeType);
helpData[0].children[0].children.push({
id:"node-type:"+nodeType,
nodeType: nodeType,
subflowLabel: sf.label().toLowerCase(),
element: getNodeLabel({_def:sf,type:sf.label()})
})
})
}
moduleNames.forEach(function(moduleName) {
var module = modules[moduleName];
var nodeTypes = [];
var setNames = Object.keys(module.sets);
setNames.forEach(function(setName) {
module.sets[setName].types.forEach(function(nodeType) {
if ($("script[data-help-name='"+nodeType+"']").length) {
nodeTypes.push({
id: "node-type:"+nodeType,
nodeType: nodeType,
element:getNodeLabel({_def:RED.nodes.getType(nodeType),type:nodeType})
})
}
})
})
if (nodeTypes.length > 0) {
nodeTypes.sort(function(A,B) {
return A.nodeType.localeCompare(B.nodeType)
})
helpData[0].children.push({
id: moduleName,
icon: "fa fa-cube",
label: moduleName,
children: nodeTypes
})
}
});
treeList.treeList("data",helpData);
}
function getNodeLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
$('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).text(n.name||n.type).appendTo(contentDiv);
return div;
}
function showHelp(nodeType) {
helpSection.empty();
var helpText;
var title;
var m = /^subflow(:(.+))?$/.exec(nodeType);
if (m && m[2]) {
var subflowNode = RED.nodes.subflow(m[2]);
helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
title = subflowNode.name || nodeType;
} else {
helpText = $("script[data-help-name='"+nodeType+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
title = nodeType;
}
setInfoText(title, helpText, helpSection);
var ratio = panels.ratio();
if (ratio > 0.7) {
panels.ratio(0.7)
}
treeList.treeList("show","node-type:"+nodeType)
treeList.treeList("select","node-type:"+nodeType, false);
}
function show(type) {
RED.sidebar.show("help");
if (type) {
hideTOC();
showHelp(type);
}
}
// TODO: DRY - projects.js
function addTargetToExternalLinks(el) {
$(el).find("a").each(function(el) {
var href = $(this).attr('href');
if (/^https?:/.test(href)) {
$(this).attr('target','_blank');
}
});
return el;
}
function setInfoText(title, infoText,target) {
if (title) {
$("<h1>",{class:"red-ui-help-title"}).text(title).appendTo(target);
}
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(target);
info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
var foldingHeader = "H3";
info.find(foldingHeader).wrapInner('<a class="red-ui-help-info-header expanded" href="#"></a>')
.find("a").prepend('<i class="fa fa-angle-right">').on("click", function(e) {
e.preventDefault();
var isExpanded = $(this).hasClass('expanded');
var el = $(this).parent().next();
while(el.length === 1 && el[0].nodeName !== foldingHeader) {
el.toggle(!isExpanded);
el = el.next();
}
$(this).toggleClass('expanded',!isExpanded);
})
target.parent().scrollTop(0);
}
function set(html,title) {
$(helpSection).empty();
setInfoText(title,html,helpSection);
hideTOC();
show();
}
function refreshSelection(selection) {
if (selection === undefined) {
selection = RED.view.selection();
}
if (selection.nodes) {
if (selection.nodes.length == 1) {
var node = selection.nodes[0];
if (node.type === "subflow" && node.direction) {
// ignore subflow virtual ports
} else if (node.type !== 'group'){
showHelp(node.type);
}
}
}
}
RED.events.on("view:selection-changed",refreshSelection);
return {
init: init,
show: show,
set: set
}
})();

View File

@ -0,0 +1,475 @@
RED.sidebar.info.outliner = (function() {
var treeList;
var searchInput;
var projectInfo;
var projectInfoLabel;
var flowList;
var subflowList;
var globalConfigNodes;
var objects = {};
var missingParents = {};
function getFlowData() {
var flowData = [
{
label: RED._("menu.label.flows"),
expanded: true,
children: []
},
{
label: RED._("menu.label.subflows"),
children: []
},
{
id: "__global__",
label: RED._("sidebar.info.globalConfig"),
children: []
}
]
flowList = flowData[0];
subflowList = flowData[1];
globalConfigNodes = flowData[2];
return flowData;
}
function getProjectLabel(p) {
var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
div.css("width", "calc(100% - 40px)");
var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
contentDiv.text(p.name);
var controls = $('<div>',{class:"red-ui-info-outline-item-controls"}).appendTo(div);
var editProjectButton = $('<button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;top: 3px;"><i class="fa fa-ellipsis-h"></i></button>')
.appendTo(controls)
.on("click", function(evt) {
evt.preventDefault();
RED.projects.editProject();
});
RED.popover.tooltip(editProjectButton,RED._('sidebar.project.showProjectSettings'));
return div;
}
var empties = {};
function getEmptyItem(id) {
var item = {
empty: true,
element: $('<div class="red-ui-info-outline-item red-ui-info-outline-item-empty">').text(RED._("sidebar.info.empty")),
}
empties[id] = item;
return item;
}
function getNodeLabelText(n) {
var label = n.name || n.type+": "+n.id;
if (n._def.label) {
try {
label = (typeof n._def.label === "function" ? n._def.label.call(n) : n._def.label)||"";
} catch(err) {
console.log("Definition error: "+type+".label",err);
}
}
var newlineIndex = label.indexOf("\\n");
if (newlineIndex > -1) {
label = label.substring(0,newlineIndex)+"...";
}
return label;
}
function getNodeLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
var labelText = getNodeLabelText(n);
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
if (labelText) {
label.text(labelText)
} else {
label.html("&nbsp;")
}
addControls(n, div);
return div;
}
function getFlowLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
var label = (typeof n === "string")? n : n.label;
var newlineIndex = label.indexOf("\\n");
if (newlineIndex > -1) {
label = label.substring(0,newlineIndex)+"...";
}
contentDiv.text(label);
addControls(n, div);
return div;
}
function getSubflowLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
var labelText = getNodeLabelText(n);
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
if (labelText) {
label.text(labelText)
} else {
label.html("&nbsp;")
}
addControls(n, div);
return div;
// var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
// var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
// contentDiv.text(n.name || n.id);
// addControls(n, div);
// return div;
}
function addControls(n,div) {
var controls = $('<div>',{class:"red-ui-info-outline-item-controls red-ui-info-outline-item-hover-controls"}).appendTo(div);
if (n._def.button) {
$('<button type="button" class="red-ui-info-outline-item-control-action red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.view.clickNodeButton(n);
})
}
// $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-eye"></i></button>').appendTo(controls).on("click",function(evt) {
// evt.preventDefault();
// evt.stopPropagation();
// RED.view.reveal(n.id);
// })
if (n.type !== 'group' && n.type !== 'subflow') {
$('<button type="button" class="red-ui-info-outline-item-control-disable red-ui-button red-ui-button-small"><i class="fa fa-circle-thin"></i><i class="fa fa-ban"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (n.type === 'tab') {
if (n.disabled) {
RED.workspaces.enable(n.id)
} else {
RED.workspaces.disable(n.id)
}
} else {
// TODO: this ought to be a utility function in RED.nodes
var historyEvent = {
t: "edit",
node: n,
changed: n.changed,
changes: {
d: n.d
},
dirty:RED.nodes.dirty()
}
if (n.d) {
delete n.d;
} else {
n.d = true;
}
n.dirty = true;
n.changed = true;
RED.events.emit("nodes:change",n);
RED.nodes.dirty(true)
RED.view.redraw();
}
});
} else {
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
}
controls.find("button").on("dblclick", function(evt) {
evt.preventDefault();
evt.stopPropagation();
})
}
function onProjectLoad(activeProject) {
objects = {};
var newFlowData = getFlowData();
projectInfoLabel.empty();
getProjectLabel(activeProject).appendTo(projectInfoLabel);
projectInfo.show();
treeList.treeList('data',newFlowData);
}
function build() {
var container = $("<div>", {class:"red-ui-info-outline"}).css({'height': '100%'});
var toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(container);
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.search">').appendTo(toolbar).searchBox({
delay: 300,
change: function() {
var val = $(this).val();
var searchResults = RED.search.search(val);
if (val) {
var resultMap = {};
for (var i=0,l=searchResults.length;i<l;i++) {
resultMap[searchResults[i].node.id] = true;
}
var c = treeList.treeList('filter',function(item) {
if (item.depth === 0) {
return true;
}
return item.id && objects[item.id] && resultMap[item.id]
},true)
} else {
treeList.treeList('filter',null);
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected.id);
}
}
}
});
projectInfo = $('<div class="red-ui-treeList-label red-ui-info-outline-project"><span class="red-ui-treeList-icon"><i class="fa fa-archive"></i></span></div>').hide().appendTo(container)
projectInfoLabel = $('<span>').appendTo(projectInfo);
// <div class="red-ui-info-outline-item red-ui-info-outline-item-flow" style=";"><div class="red-ui-search-result-description red-ui-info-outline-item-label">Space Monkey</div><div class="red-ui-info-outline-item-controls"><button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;"><i class="fa fa-ellipsis-h"></i></button></div></div></div>').appendTo(container)
treeList = $("<div>").css({width: "100%"}).appendTo(container).treeList({
data:getFlowData()
})
treeList.on('treelistselect', function(e,item) {
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id);
if (node) {
if (node.type === 'group' || node._def.category !== "config") {
RED.view.select({nodes:[node]})
} else {
RED.view.select({nodes:[]})
}
}
})
treeList.on('treelistconfirm', function(e,item) {
var node = RED.nodes.node(item.id);
if (node) {
if (node._def.category === "config") {
RED.editor.editConfig("", node.type, node.id);
} else {
RED.editor.edit(node);
}
}
})
RED.events.on("projects:load", onProjectLoad)
RED.events.on("flows:add", onFlowAdd)
RED.events.on("flows:remove", onObjectRemove)
RED.events.on("flows:change", onFlowChange)
RED.events.on("flows:reorder", onFlowsReorder)
RED.events.on("subflows:add", onSubflowAdd)
RED.events.on("subflows:remove", onObjectRemove)
RED.events.on("subflows:change", onSubflowChange)
RED.events.on("nodes:add",onNodeAdd);
RED.events.on("nodes:remove",onObjectRemove);
RED.events.on("nodes:change",onNodeChange);
RED.events.on("groups:add",onNodeAdd);
RED.events.on("groups:remove",onObjectRemove);
RED.events.on("groups:change",onNodeChange);
RED.events.on("view:selection-changed", onSelectionChanged);
RED.events.on("workspace:clear", onWorkspaceClear)
return container;
}
function onWorkspaceClear() {
treeList.treeList('data',getFlowData());
}
function onFlowAdd(ws) {
objects[ws.id] = {
id: ws.id,
element: getFlowLabel(ws),
children:[],
deferBuild: true,
icon: "red-ui-icons red-ui-icons-flow",
gutter: getGutter(ws)
}
if (missingParents[ws.id]) {
objects[ws.id].children = missingParents[ws.id];
delete missingParents[ws.id]
} else {
objects[ws.id].children.push(getEmptyItem(ws.id));
}
flowList.treeList.addChild(objects[ws.id])
objects[ws.id].element.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
}
function onFlowChange(n) {
var existingObject = objects[n.id];
var label = n.label || n.id;
var newlineIndex = label.indexOf("\\n");
if (newlineIndex > -1) {
label = label.substring(0,newlineIndex)+"...";
}
existingObject.element.find(".red-ui-info-outline-item-label").text(label);
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
existingObject.treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
}
function onFlowsReorder(order) {
var indexMap = {};
order.forEach(function(id,index) {
indexMap[id] = index;
})
flowList.treeList.sortChildren(function(A,B) {
if (A.id === "__global__") { return -1 }
if (B.id === "__global__") { return 1 }
return indexMap[A.id] - indexMap[B.id]
})
}
function onSubflowAdd(sf) {
objects[sf.id] = {
id: sf.id,
element: getNodeLabel(sf),
children:[],
deferBuild: true,
gutter: getGutter(sf)
}
if (missingParents[sf.id]) {
objects[sf.id].children = missingParents[sf.id];
delete missingParents[sf.id]
} else {
objects[sf.id].children.push(getEmptyItem(sf.id));
}
subflowList.treeList.addChild(objects[sf.id])
}
function onSubflowChange(sf) {
var existingObject = objects[sf.id];
existingObject.treeList.replaceElement(getNodeLabel(sf));
// existingObject.element.find(".red-ui-info-outline-item-label").text(n.name || n.id);
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+sf.id) {
var sfInstance = objects[n.id];
sfInstance.treeList.replaceElement(getNodeLabel(n));
}
});
}
function onNodeChange(n) {
var existingObject = objects[n.id];
var parent = n.g||n.z;
var nodeLabelText = getNodeLabelText(n);
if (nodeLabelText) {
existingObject.element.find(".red-ui-info-outline-item-label").text(nodeLabelText);
} else {
existingObject.element.find(".red-ui-info-outline-item-label").html("&nbsp;");
}
if (parent !== existingObject.parent.id) {
existingObject.treeList.remove();
if (!parent) {
globalConfigNodes.treeList.addChild(existingObject);
} else {
if (empties[parent]) {
empties[parent].treeList.remove();
delete empties[parent];
}
objects[parent].treeList.addChild(existingObject)
}
}
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
}
function onObjectRemove(n) {
var existingObject = objects[n.id];
existingObject.treeList.remove();
delete objects[n.id]
var parent = existingObject.parent;
if (parent.children.length === 0) {
parent.treeList.addChild(getEmptyItem(parent.id));
}
if (existingObject.children && (existingObject.children.length > 0)) {
existingObject.children.forEach(function (nc) {
if (!nc.empty) {
var childObject = objects[nc.id];
nc.parent = parent;
objects[parent.id].treeList.addChild(childObject);
}
});
}
}
function getGutter(n) {
var span = $("<span>",{class:"red-ui-info-outline-gutter"});
$('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.view.reveal(n.id);
})
return span;
}
function onNodeAdd(n) {
objects[n.id] = {
id: n.id,
element: getNodeLabel(n),
gutter: getGutter(n)
}
if (n.type === "group") {
objects[n.id].children = [];
objects[n.id].deferBuild = true;
if (missingParents[n.id]) {
objects[n.id].children = missingParents[n.id];
delete missingParents[n.id]
}
}
var parent = n.g||n.z;
if (parent) {
if (objects[parent]) {
if (empties[parent]) {
empties[parent].treeList.remove();
delete empties[parent];
}
if (objects[parent].treeList) {
objects[parent].treeList.addChild(objects[n.id]);
} else {
objects[parent].children.push(objects[n.id])
}
} else {
missingParents[parent] = missingParents[parent]||[];
missingParents[parent].push(objects[n.id])
}
} else {
// No parent - add to Global flow list
globalConfigNodes.treeList.addChild(objects[n.id])
}
objects[n.id].element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
}
function onSelectionChanged(selection) {
// treeList.treeList('clearSelection');
}
return {
build: build,
search: function(val) {
searchInput.searchBox('value',val)
},
select: function(node) {
if (node) {
if (Array.isArray(node)) {
treeList.treeList('select', node.map(function(n) { return objects[n.id] }), false)
} else {
treeList.treeList('select', objects[node.id], false)
}
} else {
treeList.treeList('clearSelection')
}
},
reveal: function(node) {
treeList.treeList('show', objects[node.id])
}
}
})();

View File

@ -15,28 +15,33 @@
**/ **/
RED.sidebar.info = (function() { RED.sidebar.info = (function() {
marked.setOptions({
renderer: new marked.Renderer(),
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: true,
smartLists: true,
smartypants: false
});
var content; var content;
var sections; var panels;
var propertiesSection;
var infoSection; var infoSection;
var helpSection;
var propertiesPanelContent;
var propertiesPanelHeader;
var propertiesPanelHeaderIcon;
var propertiesPanelHeaderLabel;
var propertiesPanelHeaderReveal;
var propertiesPanelHeaderHelp;
var selectedObject;
var tipContainer;
var tipBox; var tipBox;
// TODO: remove this
var expandedSections = { var expandedSections = {
"property": false "property": false
}; };
function resizeStack() {
if (panels) {
var h = $(content).parent().height() - tipContainer.outerHeight();
panels.resize(h)
}
}
function init() { function init() {
content = document.createElement("div"); content = document.createElement("div");
@ -46,31 +51,79 @@ RED.sidebar.info = (function() {
var stackContainer = $("<div>",{class:"red-ui-sidebar-info-stack"}).appendTo(content); var stackContainer = $("<div>",{class:"red-ui-sidebar-info-stack"}).appendTo(content);
sections = RED.stack.create({ var outlinerPanel = $("<div>").css({
container: stackContainer "overflow": "hidden",
}).hide(); "height": "calc(70%)"
}).appendTo(stackContainer);
var propertiesPanel = $("<div>").css({
"overflow":"hidden",
"height":"100%",
"display": "flex",
"flex-direction": "column"
}).appendTo(stackContainer);
propertiesPanelHeader = $("<div>", {class:"red-ui-palette-header red-ui-info-header"}).css({
"flex":"0 0 auto"
}).appendTo(propertiesPanel);
propertiesSection = sections.add({ propertiesPanelHeaderIcon = $("<span>").appendTo(propertiesPanelHeader);
title: RED._("sidebar.info.info"), propertiesPanelHeaderLabel = $("<span>").appendTo(propertiesPanelHeader);
collapsible: true propertiesPanelHeaderHelp = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
position: 'absolute',
top: '12px',
right: '32px'
}).on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (selectedObject) {
RED.sidebar.help.show(selectedObject.type);
}
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp"));
propertiesPanelHeaderReveal = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
position: 'absolute',
top: '12px',
right: '8px'
}).on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (selectedObject) {
RED.sidebar.info.outliner.reveal(selectedObject);
RED.view.reveal(selectedObject.id);
}
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderReveal,RED._("sidebar.help.showInOutline"));
propertiesPanelContent = $("<div>").css({
"flex":"1 1 auto",
"overflow-y":"scroll",
}).appendTo(propertiesPanel);
panels = RED.panels.create({container: stackContainer})
panels.ratio(0.6);
RED.sidebar.info.outliner.build().appendTo(outlinerPanel);
RED.sidebar.addTab({
id: "info",
label: RED._("sidebar.info.label"),
name: RED._("sidebar.info.name"),
iconClass: "fa fa-info",
action:"core:show-info-tab",
content: content,
pinned: true,
enableOnEdit: true
}); });
propertiesSection.expand();
infoSection = sections.add({ $(window).on("resize", resizeStack);
title: RED._("sidebar.info.desc"), $(window).on("focus", resizeStack);
collapsible: true
});
infoSection.expand();
infoSection.content.css("padding","6px");
helpSection = sections.add({
title: RED._("sidebar.info.nodeHelp"),
collapsible: true
});
helpSection.expand();
helpSection.content.css("padding","6px");
var tipContainer = $('<div class="red-ui-help-tips"></div>').appendTo(content); // Tip Box
tipContainer = $('<div class="red-ui-help-tips"></div>').appendTo(content);
tipBox = $('<div class="red-ui-help-tip"></div>').appendTo(tipContainer); tipBox = $('<div class="red-ui-help-tip"></div>').appendTo(tipContainer);
var tipButtons = $('<div class="red-ui-help-tips-buttons"></div>').appendTo(tipContainer); var tipButtons = $('<div class="red-ui-help-tips-buttons"></div>').appendTo(tipContainer);
@ -86,17 +139,6 @@ RED.sidebar.info = (function() {
RED.actions.invoke("core:toggle-show-tips"); RED.actions.invoke("core:toggle-show-tips");
RED.notify(RED._("sidebar.info.showTips")); RED.notify(RED._("sidebar.info.showTips"));
}); });
RED.sidebar.addTab({
id: "info",
label: RED._("sidebar.info.label"),
name: RED._("sidebar.info.name"),
iconClass: "fa fa-info",
action:"core:show-info-tab",
content: content,
pinned: true,
enableOnEdit: true
});
if (tips.enabled()) { if (tips.enabled()) {
tips.start(); tips.start();
} else { } else {
@ -124,46 +166,36 @@ RED.sidebar.info = (function() {
refreshSelection(); refreshSelection();
return; return;
} }
sections.show(); $(propertiesPanelContent).empty();
$(propertiesSection.content).empty();
$(infoSection.content).empty();
$(helpSection.content).empty();
infoSection.title.text(RED._("sidebar.info.desc"));
var propRow; var propRow;
var table = $('<table class="red-ui-info-table"></table>').appendTo(propertiesSection.content); var table = $('<table class="red-ui-info-table"></table>').appendTo(propertiesPanelContent);
var tableBody = $('<tbody>').appendTo(table); var tableBody = $('<tbody>').appendTo(table);
var subflowNode; var subflowNode;
var subflowUserCount; var subflowUserCount;
var activeProject = RED.projects.getActiveProject();
if (activeProject) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+ RED._("sidebar.project.name") + '</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).text(activeProject.name||"");
$('<tr class="red-ui-help-property-expand blank"><td colspan="2"></td></tr>').appendTo(tableBody);
var editProjectButton = $('<button class="red-ui-button red-ui-button-small" style="position:absolute;right:2px;"><i class="fa fa-ellipsis-h"></i></button>')
.appendTo(propRow.children()[1])
.on("click", function(evt) {
evt.preventDefault();
RED.projects.editProject();
});
RED.popover.tooltip(editProjectButton,RED._('sidebar.project.showProjectSettings'));
}
propertiesSection.container.show();
infoSection.container.show();
helpSection.container.show();
if (node === null) { if (node === null) {
RED.sidebar.info.outliner.select(null);
return; return;
} else if (Array.isArray(node)) { } else if (Array.isArray(node)) {
// Multiple things selected // Multiple things selected
// - hide help and info sections // - hide help and info sections
RED.sidebar.info.outliner.select(node);
propertiesPanelHeaderIcon.empty();
RED.utils.createNodeIcon({type:"_selection_"}).appendTo(propertiesPanelHeaderIcon);
propertiesPanelHeaderLabel.text("Selection");
propertiesPanelHeaderReveal.hide();
propertiesPanelHeaderHelp.hide();
selectedObject = null;
var types = { var types = {
nodes:0, nodes:0,
flows:0, flows:0,
subflows:0 subflows:0,
groups: 0
} }
node.forEach(function(n) { node.forEach(function(n) {
if (n.type === 'tab') { if (n.type === 'tab') {
@ -171,12 +203,13 @@ RED.sidebar.info = (function() {
types.nodes += RED.nodes.filterNodes({z:n.id}).length; types.nodes += RED.nodes.filterNodes({z:n.id}).length;
} else if (n.type === 'subflow') { } else if (n.type === 'subflow') {
types.subflows++; types.subflows++;
} else if (n.type === 'group') {
types.groups++;
} else { } else {
types.nodes++; types.nodes++;
} }
}); });
helpSection.container.hide(); // infoSection.container.hide();
infoSection.container.hide();
// - show the count of selected nodes // - show the count of selected nodes
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.selection")+"</td><td></td></tr>").appendTo(tableBody); propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.selection")+"</td><td></td></tr>").appendTo(tableBody);
@ -190,14 +223,19 @@ RED.sidebar.info = (function() {
if (types.nodes > 0) { if (types.nodes > 0) {
$('<div>').text(RED._("clipboard.node",{count:types.nodes})).appendTo(counts); $('<div>').text(RED._("clipboard.node",{count:types.nodes})).appendTo(counts);
} }
if (types.groups > 0) {
$('<div>').text(RED._("clipboard.group",{count:types.groups})).appendTo(counts);
}
} else { } else {
// A single 'thing' selected. // A single 'thing' selected.
RED.sidebar.info.outliner.select(node);
// Check to see if this is a subflow or subflow instance // Check to see if this is a subflow or subflow instance
var m = /^subflow(:(.+))?$/.exec(node.type); var subflowRegex = /^subflow(:(.+))?$/.exec(node.type);
if (m) { if (subflowRegex) {
if (m[2]) { if (subflowRegex[2]) {
subflowNode = RED.nodes.subflow(m[2]); subflowNode = RED.nodes.subflow(subflowRegex[2]);
} else { } else {
subflowNode = node; subflowNode = node;
} }
@ -210,33 +248,76 @@ RED.sidebar.info = (function() {
} }
}); });
} }
propertiesPanelHeaderIcon.empty();
RED.utils.createNodeIcon(node).appendTo(propertiesPanelHeaderIcon);
var objectLabel = RED.utils.getNodeLabel(node, node.type+": "+node.id)
var newlineIndex = objectLabel.indexOf("\\n");
if (newlineIndex > -1) {
objectLabel = objectLabel.substring(0,newlineIndex)+"...";
}
propertiesPanelHeaderLabel.text(objectLabel);
propertiesPanelHeaderReveal.show();
selectedObject = node;
propRow = $('<tr class="red-ui-help-info-row"><td></td><td></td></tr>').appendTo(tableBody);
var objectType = "node";
if (node.type === "subflow" || subflowRegex) {
objectType = "subflow";
} else if (node.type === "tab") {
objectType = "flow";
}else if (node.type === "group") {
objectType = "group";
}
$(propRow.children()[0]).text(RED._("sidebar.info."+objectType))
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
if (node.type === "tab" || node.type === "subflow") { if (node.type === "tab" || node.type === "subflow") {
// If nothing is selected, but we're on a flow or subflow tab. // If nothing is selected, but we're on a flow or subflow tab.
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info."+(node.type==='tab'?'flow':'subflow'))+'</td><td></td></tr>').appendTo(tableBody); propertiesPanelHeaderHelp.hide();
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.tabName")+"</td><td></td></tr>").appendTo(tableBody); } else if (node.type === "group") {
$(propRow.children()[1]).text(node.label||node.name||""); propertiesPanelHeaderHelp.hide();
if (node.type === "tab") {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody); propRow = $('<tr class="red-ui-help-info-row"><td>&nbsp;</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).text((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
var typeCounts = {
nodes:0,
groups: 0
} }
var allNodes = RED.group.getNodes(node,true);
allNodes.forEach(function(n) {
if (n.type === "group") {
typeCounts.groups++;
} else {
typeCounts.nodes++
}
});
var counts = $('<div>').appendTo($(propRow.children()[1]));
if (typeCounts.nodes > 0) {
$('<div>').text(RED._("clipboard.node",{count:typeCounts.nodes})).appendTo(counts);
}
if (typeCounts.groups > 0) {
$('<div>').text(RED._("clipboard.group",{count:typeCounts.groups})).appendTo(counts);
}
} else { } else {
// An actual node is selected in the editor - build up its properties table propertiesPanelHeaderHelp.show();
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]); if (!subflowRegex) {
if (node.type !== "subflow" && node.type !== "unknown" && node.name) { propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+'</td><td></td></tr>').appendTo(tableBody);
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody);
$('<span class="red-ui-text-bidi-aware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]);
}
if (!m) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+"</td><td></td></tr>").appendTo(tableBody);
$(propRow.children()[1]).text((node.type === "unknown")?node._orig.type:node.type); $(propRow.children()[1]).text((node.type === "unknown")?node._orig.type:node.type);
if (node.type === "unknown") { if (node.type === "unknown") {
$('<span style="float: right; font-size: 0.8em"><i class="fa fa-warning"></i></span>').prependTo($(propRow.children()[1])) $('<span style="float: right; font-size: 0.8em"><i class="fa fa-warning"></i></span>').prependTo($(propRow.children()[1]))
} }
} }
var count = 0; var count = 0;
if (!m && node.type != "subflow") { if (!subflowRegex && node.type != "subflow" && node.type != "group") {
var blankRow = $('<tr class="red-ui-help-property-expand blank"><td colspan="2"></td></tr>').appendTo(tableBody);
var defaults; var defaults;
if (node.type === 'unknown') { if (node.type === 'unknown') {
defaults = {}; defaults = {};
@ -251,7 +332,6 @@ RED.sidebar.info = (function() {
$(propRow.children()[1]).text(RED.nodes.getType(node.type).set.module); $(propRow.children()[1]).text(RED.nodes.getType(node.type).set.module);
count++; count++;
} }
$('<tr class="red-ui-help-property-expand red-ui-help-info-property-row blank'+(expandedSections.property?"":" hide")+'"><td colspan="2"></td></tr>').appendTo(tableBody);
if (defaults) { if (defaults) {
for (var n in defaults) { for (var n in defaults) {
@ -259,7 +339,8 @@ RED.sidebar.info = (function() {
var val = node[n]; var val = node[n];
var type = typeof val; var type = typeof val;
count++; count++;
propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td>'+n+"</td><td></td></tr>").appendTo(tableBody); propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td></td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[0]).text(n);
if (defaults[n].type) { if (defaults[n].type) {
var configNode = RED.nodes.node(val); var configNode = RED.nodes.node(val);
if (!configNode) { if (!configNode) {
@ -289,49 +370,66 @@ RED.sidebar.info = (function() {
} }
} }
if (count > 0) { if (count > 0) {
$('<tr class="red-ui-help-property-expand blank"><td colspan="2"><a href="#" class="node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="red-ui-help-property-more">'+RED._("sidebar.info.showMore")+'</span><span class="red-ui-help-property-less">'+RED._("sidebar.info.showLess")+'</span> <i class="fa fa-caret-down"></i></a></td></tr>').appendTo(tableBody); $('<a href="#" class="node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="red-ui-help-property-more">'+RED._("sidebar.info.showMore")+'</span><span class="red-ui-help-property-less">'+RED._("sidebar.info.showLess")+'</span> <i class="fa fa-caret-down"></i></a>').appendTo(blankRow.children()[0]);
} }
} }
if (node.type !== 'tab') { if (node.type !== 'tab') {
if (m) { if (subflowRegex) {
$('<tr class="blank"><th colspan="2">'+RED._("sidebar.info.subflow")+'</th></tr>').appendTo(tableBody); $('<tr class="blank"><th colspan="2">'+RED._("sidebar.info.subflow")+'</th></tr>').appendTo(tableBody);
$('<tr class="node-info-subflow-row"><td>'+RED._("common.label.name")+'</td><td><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+RED.utils.sanitize(subflowNode.name)+'</span></td></tr>').appendTo(tableBody); $('<tr class="node-info-subflow-row"><td>'+RED._("common.label.name")+'</td><td><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+RED.utils.sanitize(subflowNode.name)+'</span></td></tr>').appendTo(tableBody);
} }
} }
} }
if (m) { if (subflowRegex) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("subflow.category")+'</td><td></td></tr>').appendTo(tableBody); propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("subflow.category")+'</td><td></td></tr>').appendTo(tableBody);
var category = subflowNode.category||"subflows"; var category = subflowNode.category||"subflows";
$(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category})) $(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category}))
$('<tr class="node-info-subflow-row"><td>'+RED._("sidebar.info.instances")+"</td><td>"+subflowUserCount+'</td></tr>').appendTo(tableBody); $('<tr class="node-info-subflow-row"><td>'+RED._("sidebar.info.instances")+"</td><td>"+subflowUserCount+'</td></tr>').appendTo(tableBody);
} }
var helpText = ""; // var helpText = "";
if (node.type === "tab" || node.type === "subflow") { // if (node.type === "tab" || node.type === "subflow") {
$(helpSection.container).hide(); // } else {
} else { // if (subflowNode && node.type !== "subflow") {
$(helpSection.container).show(); // // Selected a subflow instance node.
if (subflowNode && node.type !== "subflow") { // // - The subflow template info goes into help
// Selected a subflow instance node. // helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
// - The subflow template info goes into help // } else {
helpText = (marked(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>')); // helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
} else { // }
helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'); // setInfoText(helpText, helpSection.content);
} // }
setInfoText(helpText, helpSection.content);
}
var infoText = ""; var infoText = "";
if (node._def && node._def.info) { if (node._def && node._def.info) {
var info = node._def.info; var info = node._def.info;
var textInfo = (typeof info === "function" ? info.call(node) : info); var textInfo = (typeof info === "function" ? info.call(node) : info);
infoText = infoText + marked(textInfo); infoText = infoText + RED.utils.renderMarkdown(textInfo);
} }
if (node.info) { if (node.info) {
infoText = infoText + marked(node.info || "") infoText = infoText + RED.utils.renderMarkdown(node.info || "")
} }
setInfoText(infoText, infoSection.content); var infoSectionContainer = $("<div>").css("padding","0 6px 6px").appendTo(propertiesPanelContent)
// var editInfo = $('<button class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-file-text-o"></button>').appendTo(infoSectionContainer).on("click", function(evt) {
// //.text(RED._("sidebar.info.editDescription"))
// evt.preventDefault();
// evt.stopPropagation();
// if (node.type === 'tab') {
//
// } else if (node.type === 'subflow') {
//
// } else if (node.type === 'group') {
//
// } else if (node._def.category !== 'config') {
// RED.editor.edit(node,"editor-tab-description");
// } else {
//
// }
// })
setInfoText(infoText, infoSectionContainer);
$(".red-ui-sidebar-info-stack").scrollTop(0); $(".red-ui-sidebar-info-stack").scrollTop(0);
$(".node-info-property-header").on("click", function(e) { $(".node-info-property-header").on("click", function(e) {
@ -347,7 +445,7 @@ RED.sidebar.info = (function() {
// propRow = $('<tr class="red-ui-help-info-row"><td>Actions</td><td></td></tr>').appendTo(tableBody); // propRow = $('<tr class="red-ui-help-info-row"><td>Actions</td><td></td></tr>').appendTo(tableBody);
// var actionBar = $(propRow.children()[1]); // var actionBar = $(propRow.children()[1]);
// //
// // var actionBar = $('<div>',{style:"background: #fefefe; padding: 3px;"}).appendTo(propertiesSection.content); // // var actionBar = $('<div>',{style:"background: #fefefe; padding: 3px;"}).appendTo(propertiesPanel);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar); // $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar); // $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar); // $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
@ -422,6 +520,7 @@ RED.sidebar.info = (function() {
} }
function startTips() { function startTips() {
$(".red-ui-sidebar-info").addClass('show-tips'); $(".red-ui-sidebar-info").addClass('show-tips');
resizeStack();
if (enabled) { if (enabled) {
if (!startTimeout && !refreshTimeout) { if (!startTimeout && !refreshTimeout) {
if (tipCount === -1) { if (tipCount === -1) {
@ -435,6 +534,7 @@ RED.sidebar.info = (function() {
} }
function stopTips() { function stopTips() {
$(".red-ui-sidebar-info").removeClass('show-tips'); $(".red-ui-sidebar-info").removeClass('show-tips');
resizeStack();
clearInterval(refreshTimeout); clearInterval(refreshTimeout);
clearTimeout(startTimeout); clearTimeout(startTimeout);
refreshTimeout = null; refreshTimeout = null;
@ -459,15 +559,8 @@ RED.sidebar.info = (function() {
} }
function set(html,title) { function set(html,title) {
// tips.stop(); console.warn("Deprecated use of RED.sidebar.info.set - use RED.sidebar.help.set instead")
// sections.show(); RED.sidebar.help.set(html,title);
refresh(null);
propertiesSection.container.hide();
helpSection.container.hide();
infoSection.container.show();
infoSection.title.text(title||RED._("sidebar.info.desc"));
setInfoText(html,infoSection.content);
$(".red-ui-sidebar-info-stack").scrollTop(0);
} }
function refreshSelection(selection) { function refreshSelection(selection) {

View File

@ -16,6 +16,28 @@
RED.utils = (function() { RED.utils = (function() {
window._marked = window.marked;
window.marked = function(txt) {
console.warn("Use of 'marked()' is deprecated. Use RED.utils.renderMarkdown() instead");
return renderMarkdown(txt);
}
_marked.setOptions({
renderer: new _marked.Renderer(),
gfm: true,
tables: true,
breaks: false,
pedantic: false,
smartLists: true,
smartypants: false
});
function renderMarkdown(txt) {
var rendered = _marked(txt);
var cleaned = DOMPurify.sanitize(rendered, {SAFE_FOR_JQUERY: true})
return cleaned;
}
function formatString(str) { function formatString(str) {
return str.replace(/\r?\n/g,"&crarr;").replace(/\t/g,"&rarr;"); return str.replace(/\r?\n/g,"&crarr;").replace(/\t/g,"&rarr;");
} }
@ -784,9 +806,9 @@ RED.utils = (function() {
function separateIconPath(icon) { function separateIconPath(icon) {
var result = {module: "", file: ""}; var result = {module: "", file: ""};
if (icon) { if (icon) {
var index = icon.indexOf('icons/'); var index = icon.indexOf(RED.settings.apiRootUrl+'icons/');
if (index !== -1) { if (index === 0) {
icon = icon.substring(index+6); icon = icon.substring((RED.settings.apiRootUrl+'icons/').length);
} }
index = icon.indexOf('/'); index = icon.indexOf('/');
if (index !== -1) { if (index !== -1) {
@ -837,10 +859,15 @@ RED.utils = (function() {
} }
function getNodeIcon(def,node) { function getNodeIcon(def,node) {
if (def.category === 'config') { if (node && node.type === '_selection_') {
return "font-awesome/fa-object-ungroup";
} else if (node && node.type === 'group') {
return "font-awesome/fa-object-group"
} else if (def.category === 'config') {
return RED.settings.apiRootUrl+"icons/node-red/cog.svg" return RED.settings.apiRootUrl+"icons/node-red/cog.svg"
} else if (node && node.type === 'tab') { } else if (node && node.type === 'tab') {
return RED.settings.apiRootUrl+"icons/node-red/subflow.svg" return "red-ui-icons/red-ui-icons-flow"
// return RED.settings.apiRootUrl+"images/subflow_tab.svg"
} else if (node && node.type === 'unknown') { } else if (node && node.type === 'unknown') {
return RED.settings.apiRootUrl+"icons/node-red/alert.svg" return RED.settings.apiRootUrl+"icons/node-red/alert.svg"
} else if (node && node.icon) { } else if (node && node.icon) {
@ -899,6 +926,8 @@ RED.utils = (function() {
var l; var l;
if (node.type === 'tab') { if (node.type === 'tab') {
l = node.label || defaultLabel l = node.label || defaultLabel
} else if (node.type === 'group') {
l = node.name || defaultLabel
} else { } else {
l = node._def.label; l = node._def.label;
try { try {
@ -1032,11 +1061,63 @@ RED.utils = (function() {
} }
// If the specified name is not defined in font-awesome, show arrow-in icon. // If the specified name is not defined in font-awesome, show arrow-in icon.
iconUrl = RED.settings.apiRootUrl+"icons/node-red/arrow-in.svg" iconUrl = RED.settings.apiRootUrl+"icons/node-red/arrow-in.svg"
} else if (iconPath.module === "red-ui-icons") {
var redIconElement = $('<i/>').appendTo(iconContainer);
redIconElement.addClass("red-ui-palette-icon red-ui-icons " + iconPath.file);
return;
} }
var imageIconElement = $('<div/>',{class:"red-ui-palette-icon"}).appendTo(iconContainer); var imageIconElement = $('<div/>',{class:"red-ui-palette-icon"}).appendTo(iconContainer);
imageIconElement.css("backgroundImage", "url("+iconUrl+")"); imageIconElement.css("backgroundImage", "url("+iconUrl+")");
} }
function createNodeIcon(node) {
var def = node._def;
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"})
if (node.type === "_selection_") {
nodeDiv.addClass("red-ui-palette-icon-selection");
} else if (node.type === "group") {
nodeDiv.addClass("red-ui-palette-icon-group");
} else if (node.type === 'tab') {
nodeDiv.addClass("red-ui-palette-icon-flow");
} else {
var colour = RED.utils.getNodeColor(node.type,def);
// if (node.type === 'tab') {
// colour = "#C0DEED";
// }
nodeDiv.css('backgroundColor',colour);
var borderColor = getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
}
var icon_url = RED.utils.getNodeIcon(def,node);
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
return nodeDiv;
}
function getDarkerColor(c) {
var r,g,b;
if (/^#[a-f0-9]{6}$/i.test(c)) {
r = parseInt(c.substring(1, 3), 16);
g = parseInt(c.substring(3, 5), 16);
b = parseInt(c.substring(5, 7), 16);
} else if (/^#[a-f0-9]{3}$/i.test(c)) {
r = parseInt(c.substring(1, 2)+c.substring(1, 2), 16);
g = parseInt(c.substring(2, 3)+c.substring(2, 3), 16);
b = parseInt(c.substring(3, 4)+c.substring(3, 4), 16);
} else {
return c;
}
var l = 0.3 * r/255 + 0.59 * g/255 + 0.11 * b/255 ;
r = Math.max(0,r-50);
g = Math.max(0,g-50);
b = Math.max(0,b-50);
var s = ((r<<16) + (g<<8) + b).toString(16);
return '#'+'000000'.slice(0, 6-s.length)+s;
}
return { return {
createObjectElement: buildMessageElement, createObjectElement: buildMessageElement,
getMessageProperty: getMessageProperty, getMessageProperty: getMessageProperty,
@ -1053,6 +1134,9 @@ RED.utils = (function() {
decodeObject: decodeObject, decodeObject: decodeObject,
parseContextKey: parseContextKey, parseContextKey: parseContextKey,
createIconElement: createIconElement, createIconElement: createIconElement,
sanitize: sanitize sanitize: sanitize,
renderMarkdown: renderMarkdown,
createNodeIcon: createNodeIcon,
getDarkerColor: getDarkerColor
} }
})(); })();

View File

@ -67,9 +67,16 @@ RED.view.tools = (function() {
function moveSelection(dx,dy) { function moveSelection(dx,dy) {
if (moving_set === null) { if (moving_set === null) {
moving_set = [];
var selection = RED.view.selection(); var selection = RED.view.selection();
if (selection.nodes) { if (selection.nodes) {
moving_set = selection.nodes.map(function(n) { return {n:n}}); while (selection.nodes.length > 0) {
var n = selection.nodes.shift();
moving_set.push({n:n});
if (n.type === "group") {
selection.nodes = selection.nodes.concat(n.nodes);
}
}
} }
} }
if (moving_set && moving_set.length > 0) { if (moving_set && moving_set.length > 0) {
@ -93,6 +100,9 @@ RED.view.tools = (function() {
node.n.x += dx; node.n.x += dx;
node.n.y += dy; node.n.y += dy;
node.n.dirty = true; node.n.dirty = true;
if (node.n.type === "group") {
RED.group.markDirty(node.n);
}
minX = Math.min(node.n.x-node.n.w/2-5,minX); minX = Math.min(node.n.x-node.n.w/2-5,minX);
minY = Math.min(node.n.y-node.n.h/2-5,minY); minY = Math.min(node.n.y-node.n.h/2-5,minY);
} }
@ -110,8 +120,69 @@ RED.view.tools = (function() {
} }
} }
function setSelectedNodeLabelState(labelShown) {
var selection = RED.view.selection();
var historyEvents = [];
var nodes = [];
if (selection.nodes) {
selection.nodes.forEach(function(n) {
if (n.type !== 'subflow' && n.type !== 'group') {
nodes.push(n);
} else if (n.type === 'group') {
nodes = nodes.concat( RED.group.getNodes(n,true));
}
});
}
nodes.forEach(function(n) {
var modified = false;
var oldValue = n.l === undefined?true:n.l;
var isLink = /^link (in|out)$/.test(n._def.type);
if (labelShown) {
if (n.l === false || (isLink && !n.hasOwnProperty('l'))) {
n.l = true;
modified = true;
}
} else {
if ((!isLink && (!n.hasOwnProperty('l') || n.l === true)) || (isLink && n.l === true) ) {
n.l = false;
modified = true;
}
}
if (modified) {
historyEvents.push({
t: "edit",
node: n,
changed: n.changed,
changes: {
l: oldValue
}
})
n.changed = true;
n.dirty = true;
n.resize = true;
}
})
if (historyEvents.length > 0) {
RED.history.push({
t: "multi",
events: historyEvents,
dirty: RED.nodes.dirty()
})
RED.nodes.dirty(true);
}
RED.view.redraw();
}
return { return {
init: function() { init: function() {
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
RED.actions.add("core:hide-selected-node-labels", function() { setSelectedNodeLabelState(false); })
RED.actions.add("core:align-selection-to-grid", alignToGrid); RED.actions.add("core:align-selection-to-grid", alignToGrid);
RED.actions.add("core:scroll-view-up", function() { RED.view.scroll(0,-RED.view.gridSize());}); RED.actions.add("core:scroll-view-up", function() { RED.view.scroll(0,-RED.view.gridSize());});

File diff suppressed because it is too large Load Diff

View File

@ -128,10 +128,6 @@ RED.workspaces = (function() {
RED.history.push(historyEvent); RED.history.push(historyEvent);
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.sidebar.config.refresh(); RED.sidebar.config.refresh();
var selection = RED.view.selection();
if (!selection.nodes && !selection.links) {
RED.sidebar.info.refresh(workspace);
}
if (changes.hasOwnProperty('disabled')) { if (changes.hasOwnProperty('disabled')) {
RED.nodes.eachNode(function(n) { RED.nodes.eachNode(function(n) {
if (n.z === workspace.id) { if (n.z === workspace.id) {
@ -140,6 +136,7 @@ RED.workspaces = (function() {
}); });
RED.view.redraw(); RED.view.redraw();
} }
RED.events.emit("flows:change",workspace);
} }
RED.tray.close(); RED.tray.close();
} }
@ -219,7 +216,10 @@ RED.workspaces = (function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) { if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT); RED.view.state(RED.state.DEFAULT);
} }
RED.sidebar.info.refresh(workspace); var selection = RED.view.selection();
if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
RED.sidebar.info.refresh(workspace);
}
tabflowEditor.destroy(); tabflowEditor.destroy();
} }
} }
@ -371,7 +371,9 @@ RED.workspaces = (function() {
var changes = { disabled: workspace.disabled }; var changes = { disabled: workspace.disabled };
workspace.disabled = disabled; workspace.disabled = disabled;
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled); $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled); if (id === activeWorkspace) {
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
}
var historyEvent = { var historyEvent = {
t: "edit", t: "edit",
changes:changes, changes:changes,
@ -380,10 +382,11 @@ RED.workspaces = (function() {
} }
workspace.changed = true; workspace.changed = true;
RED.history.push(historyEvent); RED.history.push(historyEvent);
RED.events.emit("flows:change",workspace);
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.sidebar.config.refresh(); RED.sidebar.config.refresh();
var selection = RED.view.selection(); var selection = RED.view.selection();
if (!selection.nodes && !selection.links) { if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
RED.sidebar.info.refresh(workspace); RED.sidebar.info.refresh(workspace);
} }
if (changes.hasOwnProperty('disabled')) { if (changes.hasOwnProperty('disabled')) {
@ -412,9 +415,14 @@ RED.workspaces = (function() {
} }
function setWorkspaceOrder(order) { function setWorkspaceOrder(order) {
RED.nodes.setWorkspaceOrder(order.filter(function(id) { var newOrder = order.filter(function(id) {
return RED.nodes.workspace(id) !== undefined; return RED.nodes.workspace(id) !== undefined;
})); })
var currentOrder = RED.nodes.getWorkspaceOrder();
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
RED.nodes.setWorkspaceOrder(newOrder);
RED.events.emit("flows:reorder",newOrder);
}
workspace_tabs.order(order); workspace_tabs.order(order);
} }

View File

@ -9,19 +9,15 @@
color: transparent !important; color: transparent !important;
} }
} }
.ace_gutter { .ace_gutter {
background: $text-editor-gutter-background;
border-top-left-radius: 4px; border-top-left-radius: 4px;
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
} }
.ace_scroller { .ace_scroller {
background: $text-editor-background;
border-top-right-radius: 4px; border-top-right-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
}
.ace_scroller {
background: $text-editor-background;
color: $text-editor-color; color: $text-editor-color;
} }
.ace_marker-layer .ace_active-line { .ace_marker-layer .ace_active-line {
@ -37,9 +33,6 @@
.ace_gutter-active-line { .ace_gutter-active-line {
background: $text-editor-gutter-active-line-background; background: $text-editor-gutter-active-line-background;
} }
.ace_gutter {
background: $text-editor-gutter-background;
}
.ace_tooltip { .ace_tooltip {
font-family: $primary-font; font-family: $primary-font;
line-height: 1.4em; line-height: 1.4em;

View File

@ -23,7 +23,7 @@ $primary-background: #f3f3f3;//#0ff;
$secondary-background: #fff;//#ff0; $secondary-background: #fff;//#ff0;
$secondary-background-selected: #efefef;//#e9e900; $secondary-background-selected: #efefef;//#e9e900;
$secondary-background-inactive: #f0f0f0;//#f0f000; $secondary-background-inactive: #f0f0f0;//#f0f000;
$secondary-background-hover: #ddd;//#dd0; $secondary-background-hover: #e6e6e6;//#dd0;
$secondary-background-disabled: #f9f9f9;//#fafa0; $secondary-background-disabled: #f9f9f9;//#fafa0;
$tertiary-background: #f7f7f7;//#f0f; $tertiary-background: #f7f7f7;//#f0f;
@ -94,7 +94,7 @@ $list-item-secondary-color: $secondary-text-color;
$list-item-background: $secondary-background; $list-item-background: $secondary-background;
$list-item-background-disabled: $secondary-background-inactive; $list-item-background-disabled: $secondary-background-inactive;
$list-item-background-hover: $secondary-background-hover; $list-item-background-hover: $secondary-background-hover;
$list-item-background-selected: $secondary-background-selected; $list-item-background-selected: #ffebc7; // #fff1e5;
$list-item-border-selected: $secondary-text-color-selected; $list-item-border-selected: $secondary-text-color-selected;
$tab-text-color-active: $header-text-color; $tab-text-color-active: $header-text-color;
@ -284,3 +284,8 @@ $debug-message-border: #eee;
$debug-message-border-hover: #999; $debug-message-border-hover: #999;
$debug-message-border-warning: #ffdf9d; $debug-message-border-warning: #ffdf9d;
$debug-message-border-error: #f99; $debug-message-border-error: #f99;
$group-default-fill: none;
$group-default-fill-opacity: 1;
$group-default-stroke: #999;
$group-default-stroke-opacity: 1;

View File

@ -217,6 +217,10 @@
.red-ui-debug-msg-type-number { color: $debug-message-text-color-msg-type-number; }; .red-ui-debug-msg-type-number { color: $debug-message-text-color-msg-type-number; };
.red-ui-debug-msg-type-number-toggle { cursor: pointer;} .red-ui-debug-msg-type-number-toggle { cursor: pointer;}
.red-ui-debug-msg-type-string {
white-space: pre-wrap;
}
.red-ui-debug-msg-row { .red-ui-debug-msg-row {
display: block; display: block;
padding: 4px 2px 2px; padding: 4px 2px 2px;

View File

@ -304,9 +304,6 @@ button.red-ui-button-small
&:first-child { &:first-child {
padding: 20px 20px 0; padding: 20px 20px 0;
} }
&:last-child {
padding-bottom: 20px;
}
} }
} }
.red-ui-editor-type-expression-tab-content { .red-ui-editor-type-expression-tab-content {
@ -411,6 +408,133 @@ button.red-ui-button.red-ui-editor-node-appearance-button {
} }
} }
.red-ui-group-layout-picker {
padding: 5px;
background: $primary-background;
}
.red-ui-group-layout-picker-cell-text {
position: absolute;
width: 14px;
height: 2px;
border-top: 2px solid $secondary-text-color;
border-bottom: 2px solid $secondary-text-color;
margin: 2px;
&.red-ui-group-layout-text-pos-nw { top: 0; left: 0; }
&.red-ui-group-layout-text-pos-n { top: 0; left: calc(50% - 9px); }
&.red-ui-group-layout-text-pos-ne { top: 0; right: 0; }
&.red-ui-group-layout-text-pos-sw { bottom: 0; left: 0; }
&.red-ui-group-layout-text-pos-s { bottom: 0; left: calc(50% - 9px); }
&.red-ui-group-layout-text-pos-se { bottom: 0; right: 0; }
&.red-ui-group-layout-text-pos- {
width: 100%;
height: 100%;
border-radius: 5px;
margin: 0;
background-color: #FFF;
background-size: 100% 100%;
background-position: 0 0, 50% 50%;
background-image: linear-gradient(45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent),linear-gradient(-45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent);
border: none;
}
}
.red-ui-group-layout-picker button.red-ui-search-result-node {
float: none;
position: relative;
padding: 0;
margin: 5px;
width: 32px;
height: 27px;
}
button.red-ui-group-layout-picker-none {
width: 100%;
}
.red-ui-color-picker {
input[type="text"] {
border-radius:0;
width: 100%;
margin-bottom: 0;
border: none;
border-bottom: 1px solid $form-input-border-color;
}
small {
color: $secondary-text-color;
margin-left: 5px;
margin-right: 4px;
display: inline-block;
min-width: 35px;
text-align: right;
}
background: $primary-background;
}
.red-ui-editor-node-appearance-button {
.red-ui-search-result-node {
overflow: hidden
}
}
.red-ui-color-picker-cell {
padding: 0;
border-style: solid;
border-width: 1px;
border-color: $secondary-border-color;
}
.red-ui-color-picker-swatch {
position: absolute;
top:-1px;right:-1px;left:-1px;bottom:-1px;
border-radius: 4px;
}
.red-ui-color-picker-cell-none {
height: 100%;
background-color: #FFF;
background-size: 100% 100%;
background-position: 0 0, 50% 50%;
background-image: linear-gradient(45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent),linear-gradient(-45deg, transparent 45%, $secondary-border-color 45%, $secondary-border-color 55%, transparent 55%, transparent)
}
.red-ui-search-result-node .red-ui-color-picker-cell-none {
border-radius: 4px;
background-size: 50% 50%;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee), linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
}
.red-ui-color-picker-opacity-slider {
position:relative;
vertical-align: middle;
display: inline-block;
width: calc(100% - 50px);
height: 14px;
margin: 6px 3px 8px;
box-sizing: border-box;
background-color: white;
background-image:
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 25%),
linear-gradient(-45deg, #eee 25%, transparent 25%, transparent 75%, #eee 25%);
background-size: 6px 6px;
}
.red-ui-color-picker-opacity-slider-overlay {
position: absolute;
top:0;right:0;left:0;bottom:0;
background-image:linear-gradient(90deg, transparent 0%, #f00 100%);
background-size: 100% 100%;
border: 1px solid $primary-border-color;
}
div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle {
z-Index: 10;
top: -4px;
cursor: pointer;
min-width: 0;
width: 10px;
height: 22px;
padding: 0;
border: 1px solid $primary-border-color;
border-radius: 1px;
background: $secondary-background;
box-sizing: border-box;
}
.red-ui-icon-picker { .red-ui-icon-picker {
select { select {
box-sizing: border-box; box-sizing: border-box;
@ -633,7 +757,7 @@ button.red-ui-toggleButton.toggle {
.red-ui-typedInput-value-label,.red-ui-typedInput-option-label { .red-ui-typedInput-value-label,.red-ui-typedInput-option-label {
select,.placeholder-input { select,.placeholder-input {
margin: 3px; margin: 3px;
height: 26px; height: 24px;
width: calc(100% - 10px); width: calc(100% - 10px);
padding-left: 3px; padding-left: 3px;
} }

View File

@ -71,6 +71,48 @@
} }
} }
.red-ui-flow-group {
&.red-ui-flow-group-hovered {
.red-ui-flow-group-outline-select {
stroke-opacity: 0.8 !important;
stroke-dasharray: 10 4 !important;
}
}
&.red-ui-flow-group-active-hovered:not(.red-ui-flow-group-hovered) {
.red-ui-flow-group-outline-select {
stroke: $link-link-color;
}
}
}
.red-ui-flow-group-outline {
fill: none;
stroke: $node-selected-color;
stroke-opacity: 0;
stroke-width: 12;
pointer-events: stroke;
}
.red-ui-flow-group-outline-select {
fill: none;
stroke: $node-selected-color;
pointer-events: stroke;
stroke-opacity: 0;
stroke-width: 3;
}
.red-ui-flow-group-body {
pointer-events: none;
fill: $group-default-fill;
fill-opacity: $group-default-fill-opacity;
stroke-width: 2;
stroke: $group-default-stroke;
stroke-opacity: $group-default-stroke-opacity;
}
.red-ui-flow-group-label {
@include disable-selection;
}
.red-ui-flow-node-unknown { .red-ui-flow-node-unknown {
stroke-dasharray:10,4; stroke-dasharray:10,4;
stroke: $node-border-unknown; stroke: $node-border-unknown;
@ -166,6 +208,9 @@ g.red-ui-flow-node-selected {
fill-opacity: 1; fill-opacity: 1;
stroke-dasharray: none; stroke-dasharray: none;
} }
.red-ui-flow-group, .red-ui-flow-group-body {
stroke-dasharray: 8, 3;
}
} }
.red-ui-flow-node-disabled { .red-ui-flow-node-disabled {
&.red-ui-flow-node, .red-ui-flow-node { &.red-ui-flow-node, .red-ui-flow-node {
@ -248,6 +293,7 @@ g.red-ui-flow-node-selected {
.red-ui-flow-link-outline { .red-ui-flow-link-outline {
stroke: $view-background; stroke: $view-background;
stroke-opacity: 0.4;
stroke-width: 5; stroke-width: 5;
cursor: crosshair; cursor: crosshair;
fill: none; fill: none;

View File

@ -37,7 +37,7 @@
border-radius: 4px; border-radius: 4px;
font-family: $monospace-font !important; font-family: $monospace-font !important;
font-size: 13px !important; font-size: 13px !important;
height: 300px; height: 100%;
line-height: 1.3em; line-height: 1.3em;
padding: 6px 10px; padding: 6px 10px;
background: $clipboard-textarea-background; background: $clipboard-textarea-background;
@ -62,6 +62,7 @@
background: $form-input-background; background: $form-input-background;
&>div { &>div {
height: 100%; height: 100%;
box-sizing: border-box;
} }
} }
.red-ui-clipboard-dialog-box { .red-ui-clipboard-dialog-box {

View File

@ -186,6 +186,21 @@
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.red-ui-search-result-node {
&.red-ui-palette-icon-flow,
&.red-ui-palette-icon-group,
&.red-ui-palette-icon-selection {
background: none;
border-color: transparent;
.red-ui-palette-icon-container {
background: none;
}
.red-ui-palette-icon-fa {
color: $secondary-text-color;
font-size: 18px;
}
}
}
.red-ui-palette-icon-fa { .red-ui-palette-icon-fa {
color: white; color: white;
position: absolute; position: absolute;

View File

@ -22,9 +22,19 @@
// border: 1px solid red; // border: 1px solid red;
box-sizing: border-box; box-sizing: border-box;
} }
display: flex;
flex-direction: column;
>.red-ui-panel:first-child {
flex: 0 0 auto;
}
>.red-ui-panel:last-child {
flex: 1 1 auto;
}
} }
.red-ui-panels-separator { .red-ui-panels-separator {
flex: 0 0 auto;
border-top: 1px solid $secondary-border-color; border-top: 1px solid $secondary-border-color;
border-bottom: 1px solid $secondary-border-color; border-bottom: 1px solid $secondary-border-color;
height: 7px; height: 7px;
@ -37,10 +47,13 @@
.red-ui-panel { .red-ui-panel {
overflow: auto; overflow: auto;
height: calc(50% - 4px); height: calc(50% - 4px);
position: relative;
} }
.red-ui-panels.red-ui-panels-horizontal { .red-ui-panels.red-ui-panels-horizontal {
height: 100%; height: 100%;
flex-direction: row;
&>.red-ui-panel { &>.red-ui-panel {
vertical-align: top; vertical-align: top;
display: inline-block; display: inline-block;

View File

@ -150,6 +150,16 @@
.red-ui-popover a.red-ui-button, .red-ui-popover a.red-ui-button,
.red-ui-popover button.red-ui-button { .red-ui-popover button.red-ui-button {
&:not(.primary) {
border-color: $popover-button-border-color;
background: $popover-background;
color: $popover-color !important;
}
&:not(.primary):not(.disabled):not(.ui-button-disabled):hover {
border-color: $popover-button-border-color-hover;
}
&.primary { &.primary {
border-color: $popover-button-border-color; border-color: $popover-button-border-color;
} }

View File

@ -18,7 +18,12 @@
.red-ui-editableList-container { .red-ui-editableList-container {
padding: 0px; padding: 0px;
} }
padding: 0;
.red-ui-projects-dialog-box {
box-sizing: border-box;
overflow-y: auto;
padding: 25px 25px 10px 25px;
}
} }
#red-ui-project-settings-tab-settings { #red-ui-project-settings-tab-settings {
overflow-y: scroll; overflow-y: scroll;
@ -99,6 +104,7 @@
.red-ui-projects-dialog-screen-create { .red-ui-projects-dialog-screen-create {
min-height: 500px; min-height: 500px;
button.red-ui-projects-dialog-screen-create-type { button.red-ui-projects-dialog-screen-create-type {
position: relative;
height: auto; height: auto;
padding: 10px; padding: 10px;
} }
@ -169,9 +175,14 @@
.red-ui-projects-dialog-project-list-container { .red-ui-projects-dialog-project-list-container {
border: 1px solid $secondary-border-color; border: 1px solid $secondary-border-color;
border-radius: 2px; border-radius: 2px;
display: flex;
flex-direction: column;
.red-ui-search-container {
flex-grow: 0;
}
} }
.red-ui-projects-dialog-project-list-inner-container { .red-ui-projects-dialog-project-list-inner-container {
height: 300px; flex-grow: 1 ;
overflow-y: scroll; overflow-y: scroll;
position:relative; position:relative;
.red-ui-editableList-border { .red-ui-editableList-border {
@ -254,6 +265,9 @@
} }
} }
} }
.red-ui-projects-dialog-screen-create-type {
position: relative;
}
.red-ui-projects-dialog-screen-create-type.red-ui-button.toggle.selected:not(.disabled):not(:disabled) { .red-ui-projects-dialog-screen-create-type.red-ui-button.toggle.selected:not(.disabled):not(:disabled) {
color: $secondary-text-color-active !important; color: $secondary-text-color-active !important;
} }

View File

@ -24,6 +24,13 @@
top: 0px; top: 0px;
border: 1px solid $primary-border-color; border: 1px solid $primary-border-color;
box-shadow: 0 0 10px $shadow; box-shadow: 0 0 10px $shadow;
background: $secondary-background;
.red-ui-searchBox-container {
display: inline-block;
margin-right: 6px;
width: calc(100% - 30px);
}
} }
.red-ui-type-search { .red-ui-type-search {
@ -87,6 +94,8 @@
} }
.red-ui-palette-icon { .red-ui-palette-icon {
width: 15px; width: 15px;
position:relative;
left: -1px;
} }
.red-ui-search-result-description { .red-ui-search-result-description {
margin-left:28px; margin-left:28px;
@ -153,7 +162,7 @@
width: 30px; width: 30px;
float:left; float:left;
height: 25px; height: 25px;
border-radius: 5px; border-radius: 3px;
border: 1px solid $node-border; border: 1px solid $node-border;
background-position: 5% 50%; background-position: 5% 50%;
background-repeat: no-repeat; background-repeat: no-repeat;

View File

@ -42,6 +42,7 @@
@import "tab-config"; @import "tab-config";
@import "tab-context"; @import "tab-context";
@import "tab-info"; @import "tab-info";
@import "tab-help";
@import "popover"; @import "popover";
@import "flow"; @import "flow";
@import "palette-editor"; @import "palette-editor";

View File

@ -0,0 +1,27 @@
.red-ui-sidebar-help-stack {
// height: calc(100% - 39px);
}
.red-ui-help-search {
border-bottom: 1px solid $secondary-border-color;
}
.red-ui-sidebar-help-toc {
.red-ui-treeList-label {
font-size: 13px;
padding: 2px 0;
overflow: hidden;
white-space: nowrap;
}
}
#red-ui-sidebar-help-show-toc {
i.fa-angle-right {
transition: all 0.2s ease-in-out;
}
&.selected {
i.fa-angle-right {
transform: rotate(90deg);
}
}
}

View File

@ -14,9 +14,25 @@
* limitations under the License. * limitations under the License.
**/ **/
.red-ui-sidebar-info {
height: 100%;
}
.red-ui-sidebar-info hr { .red-ui-sidebar-info hr {
margin: 10px 0; margin: 10px 0;
} }
.red-ui-info-header {
padding-left: 9px;
line-height: 21px;
cursor: default;
> * {
vertical-align: middle
}
> span {
display: inline-block;
margin-left: 5px;
}
border-bottom: 1px solid $secondary-border-color;
}
table.red-ui-info-table { table.red-ui-info-table {
font-size: 14px; font-size: 14px;
margin: 0 0 10px; margin: 0 0 10px;
@ -125,6 +141,9 @@ div.red-ui-info-table {
font-size: 1.296em; font-size: 1.296em;
line-height: 1.3em; line-height: 1.3em;
margin: 8px auto; margin: 8px auto;
&.red-ui-help-title {
border-bottom: 1px solid $tertiary-border-color;
}
} }
h2 { h2 {
font-weight: 500; font-weight: 500;
@ -214,12 +233,13 @@ div.red-ui-info-table {
} }
.red-ui-sidebar-info-stack { .red-ui-sidebar-info-stack {
position: absolute; height: 100%;
top: 0; // position: absolute;
bottom: 0; // top: 0;
left: 0; // bottom: 0;
right: 0; // left: 0;
overflow-y: scroll; // right: 0;
// overflow-y: scroll;
} }
.red-ui-help-tips { .red-ui-help-tips {
display: none; display: none;
@ -227,20 +247,23 @@ div.red-ui-info-table {
left:0; left:0;
right:0; right:0;
bottom: 0; bottom: 0;
height: 150px; height: 0;
transition: height 0.2s, padding 0.2s;
box-sizing: border-box; box-sizing: border-box;
border-top: 1px solid $secondary-border-color; border-top: 1px solid $secondary-border-color;
background-color: $secondary-background; background-color: $secondary-background;
padding: 20px; padding: 0;
box-shadow: 0 5px 20px 0px $shadow; box-shadow: 0 5px 20px 0px $shadow;
overflow-y: auto; overflow-y: auto;
} }
.red-ui-sidebar-info.show-tips { .red-ui-sidebar-info.show-tips {
.red-ui-sidebar-info-stack { .red-ui-sidebar-info-stack {
bottom: 150px; height: calc(100% - 150px);
} }
.red-ui-help-tips { .red-ui-help-tips {
display: block; display: block;
height: 150px;
padding: 20px;
} }
} }
@ -279,3 +302,220 @@ div.red-ui-info-table {
border-radius: 4px; border-radius: 4px;
padding: 2px 4px 2px; padding: 2px 4px 2px;
} }
.red-ui-info-outline,.red-ui-sidebar-help-toc {
display: flex;
flex-direction: column;
.red-ui-treeList {
flex-grow: 1;
position: relative;
}
.red-ui-treeList-container {
position: absolute;
top: 0;
bottom: 0;
}
.red-ui-treeList-container,.red-ui-editableList-border {
border: none;
border-radius: 0;
}
.red-ui-treeList-label {
font-size: 13px;
padding: 2px 0;
overflow: hidden;
}
.red-ui-info-outline-project {
border-bottom: 1px solid $secondary-border-color;
}
.red-ui-info-outline-item {
display: inline-block;
padding: 0;
font-size: 13px;
border: none;
.red-ui-palette-icon-fa {
position: relative;
top: 1px;
left: 0px;
}
&:hover {
background: inherit
}
&.red-ui-info-outline-item-flow {
.red-ui-search-result-description {
margin-left: 4px;
}
}
&.red-ui-info-outline-item-group .red-ui-search-result-node {
background: none;
border-color: transparent;
.red-ui-palette-icon-container {
background: none;
}
.red-ui-palette-icon-fa {
color: $secondary-text-color;
font-size: 18px;
}
}
&.red-ui-info-outline-item-empty {
font-style: italic;
color: $form-placeholder-color;
}
}
.red-ui-search-result-node {
width: 24px;
height: 20px;
margin-top: 1px;
}
.red-ui-palette-icon-container {
width: 24px;
}
.red-ui-palette-icon {
width: 20px;
}
.red-ui-search-result-description {
margin-left: 32px;
line-height: 22px;
white-space: nowrap;
}
.red-ui-search-result-node-label {
color: $secondary-text-color;
}
}
.red-ui-info-outline-item-control-spacer {
display: inline-block;
width: 23px;
}
.red-ui-info-outline-gutter {
display:none;
button {
position: absolute;
top: 1px;
left: 2px;
}
.red-ui-treeList-label:hover & {
display: inline;
}
}
.red-ui-info-outline-item-controls {
position: absolute;
top:0;
bottom: 0;
right: 0px;
padding: 2px 3px 0 1px;
text-align: right;
background: $list-item-background;
.red-ui-treeList-label:hover & {
background: $list-item-background-hover;
}
.red-ui-treeList-label.selected & {
background: $list-item-background-selected;
}
&.red-ui-info-outline-item-hover-controls button {
min-width: 23px;
}
.red-ui-treeList-label:not(:hover) &.red-ui-info-outline-item-hover-controls {
button {
border: none;
background: none;
}
}
.red-ui-info-outline-item-control-reveal,
.red-ui-info-outline-item-control-action {
display: none;
}
.red-ui-treeList-label:hover & {
.red-ui-info-outline-item-control-reveal,
.red-ui-info-outline-item-control-action {
display: inline-block;
}
}
.fa-ban {
display: none;
}
.red-ui-info-outline-item.red-ui-info-outline-item-disabled & {
.fa-ban {
display: inline-block;
}
.fa-circle-thin {
display: none;
}
}
button {
margin-right: 3px
}
}
.red-ui-info-outline-item-disabled {
.red-ui-search-result-node {
opacity: 0.4;
}
.red-ui-info-outline-item-label {
font-style: italic;
color: $secondary-text-color-disabled;
}
.red-ui-icons-flow {
opacity: 0.4;
}
}
.red-ui-icons {
display: inline-block;
width: 18px;
&:before {
white-space: pre;
content: ' '
}
}
.red-ui-icons-flow {
background-image: url('images/subflow_tab.svg');
background-repeat: no-repeat;
background-size: contain;
filter: brightness(2.5);
}
.red-ui-info-toolbar {
min-height: 39px;
height: 39px;
box-sizing: border-box;
text-align: left;
// padding-left: 9px;
// box-sizing: border-box;
// background: $palette-header-background;
// border-bottom: 1px solid $secondary-border-color;
.red-ui-searchBox-container {
position: absolute;
top: 6px;
right: 8px;
width: calc(100% - 150px);
max-width: 250px;
background: $palette-header-background;
input.red-ui-searchBox-input {
border: 1px solid $secondary-border-color;
border-radius: 3px;
font-size: 12px;
height: 26px;
}
input:focus.red-ui-searchBox-input {
border: 1px solid $secondary-border-color;
}
i.fa-search, i.fa-times {
top: 7px;
}
}
}

View File

@ -32,6 +32,9 @@
right: 5px; right: 5px;
top: 9px; top: 9px;
} }
form.red-ui-searchBox-form {
margin: 0;
}
input.red-ui-searchBox-input { input.red-ui-searchBox-input {
border-radius: 0; border-radius: 0;
border: none; border: none;

View File

@ -18,7 +18,7 @@
border: 1px solid $form-input-border-color; border: 1px solid $form-input-border-color;
border-radius: 4px; border-radius: 4px;
height: 34px; height: 34px;
display: inline-block; display: inline-flex;
padding: 0; padding: 0;
margin: 0; margin: 0;
vertical-align: middle; vertical-align: middle;
@ -26,12 +26,7 @@
overflow:visible; overflow:visible;
position: relative; position: relative;
.red-ui-typedInput-input-wrap { .red-ui-typedInput-input-wrap {
position: absolute; flex-grow: 1;
left:0;
right:0;
top:0;
bottom:0;
outline: red;
} }
input.red-ui-typedInput-input { input.red-ui-typedInput-input {
width: 100%; width: 100%;
@ -49,7 +44,7 @@
border-color: $form-input-focus-color !important; border-color: $form-input-focus-color !important;
} }
.red-ui-typedInput-value-label { .red-ui-typedInput-value-label {
position: absolute; flex-grow: 1;
display: inline-block; display: inline-block;
height: 32px; height: 32px;
box-sizing: border-box; box-sizing: border-box;
@ -107,18 +102,17 @@ button.red-ui-typedInput-option-trigger
{ {
text-align: left; text-align: left;
border: none; border: none;
position: absolute; flex-basis: auto;
box-sizing: border-box; box-sizing: border-box;
border-top-left-radius: 4px; border-top-left-radius: 4px;
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
padding: 0 1px 0 5px; padding: 0 1px 0 5px;
display:inline-block;
background: $form-button-background; background: $form-button-background;
height: 32px; height: 32px;
line-height: 30px; line-height: 30px;
min-width: 23px;
vertical-align: middle; vertical-align: middle;
color: $form-text-color; color: $form-text-color;
white-space: nowrap;
i.red-ui-typedInput-icon { i.red-ui-typedInput-icon {
margin-left: 1px; margin-left: 1px;
margin-right: 2px; margin-right: 2px;
@ -154,7 +148,7 @@ button.red-ui-typedInput-option-trigger
text-decoration: none; text-decoration: none;
} }
&.red-ui-typedInput-full-width { &.red-ui-typedInput-full-width {
width: 100%; flex-grow: 1;
border-top-right-radius: 4px; border-top-right-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
} }
@ -170,7 +164,6 @@ button.red-ui-typedInput-option-expand {
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
border-top-left-radius: 0; border-top-left-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
right: 0;
} }
button.red-ui-typedInput-option-trigger { button.red-ui-typedInput-option-trigger {
@ -179,27 +172,23 @@ button.red-ui-typedInput-option-trigger {
border-top-right-radius: 4px; border-top-right-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
padding: 0 0 0 0; padding: 0 0 0 0;
position:absolute; position:relative;
right: 0; flex-grow: 1;
line-height: 32px;
display: inline-flex;
.red-ui-typedInput-option-label { .red-ui-typedInput-option-label {
background:$form-button-background; background:$form-button-background;
color: $form-text-color; color: $form-text-color;
position:absolute; flex-grow: 1;
left:0; padding: 0 0 0 8px;
right:23px; display:inline-block;
top: 0;
padding: 0 5px 0 8px;
i.red-ui-typedInput-icon {
margin-right: 4px;
}
} }
.red-ui-typedInput-option-caret { .red-ui-typedInput-option-caret {
top: 0; flex-grow: 0;
position: absolute; display:inline-block;
right: 0; width: 23px;
bottom: 0; text-align: center;
width: 17px; height: 100%;
padding-left: 5px;
&:before { &:before {
content:''; content:'';
display: inline-block; display: inline-block;

View File

@ -112,7 +112,7 @@
position: absolute; position: absolute;
bottom: 0; bottom: 0;
right:0; right:0;
zIndex: 101; z-index: 101;
border-left: 1px solid $primary-border-color; border-left: 1px solid $primary-border-color;
border-top: 1px solid $primary-border-color; border-top: 1px solid $primary-border-color;
background: $view-navigator-background; background: $view-navigator-background;
@ -122,7 +122,7 @@
stroke-dasharray: 5,5; stroke-dasharray: 5,5;
pointer-events: none; pointer-events: none;
stroke: $secondary-border-color; stroke: $secondary-border-color;
strokeWidth: 1; stroke-width: 1;
fill: $view-background; fill: $view-background;
} }
@ -172,3 +172,44 @@ button.red-ui-footer-button-toggle {
margin-right: 0; margin-right: 0;
} }
} }
#red-ui-loading-progress {
position: absolute;
background: $primary-background;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 200;
& > div {
position: absolute;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height:80px;
text-align: center;
color: $secondary-text-color;
}
}
.red-ui-loading-bar {
box-sizing: border-box;
width: 300px;
height: 30px;
border: 2px solid $primary-border-color;
border-radius: 4px;
> span {
display: block;
height: 100%;
background: $secondary-border-color;
transition: width 0.2s;
width: 10%;
}
}
.red-ui-loading-bar-label {
font-size: 13px;
margin-bottom: 2px;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,626 +0,0 @@
/*!
* jQuery Migrate - v3.0.1 - 2017-09-26
* Copyright jQuery Foundation and other contributors
*/
;( function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define( [ "jquery" ], window, factory );
} else if ( typeof module === "object" && module.exports ) {
// Node/CommonJS
// eslint-disable-next-line no-undef
module.exports = factory( require( "jquery" ), window );
} else {
// Browser globals
factory( jQuery, window );
}
} )( function( jQuery, window ) {
"use strict";
jQuery.migrateVersion = "3.0.1";
/* exported migrateWarn, migrateWarnFunc, migrateWarnProp */
( function() {
var rbadVersions = /^[12]\./;
// Support: IE9 only
// IE9 only creates console object when dev tools are first opened
// IE9 console is a host object, callable but doesn't have .apply()
if ( !window.console || !window.console.log ) {
return;
}
// Need jQuery 3.0.0+ and no older Migrate loaded
if ( !jQuery || rbadVersions.test( jQuery.fn.jquery ) ) {
window.console.log( "JQMIGRATE: jQuery 3.0.0+ REQUIRED" );
}
if ( jQuery.migrateWarnings ) {
window.console.log( "JQMIGRATE: Migrate plugin loaded multiple times" );
}
// Show a message on the console so devs know we're active
window.console.log( "JQMIGRATE: Migrate is installed" +
( jQuery.migrateMute ? "" : " with logging active" ) +
", version " + jQuery.migrateVersion );
} )();
var warnedAbout = {};
// List of warnings already given; public read only
jQuery.migrateWarnings = [];
// Set to false to disable traces that appear with warnings
if ( jQuery.migrateTrace === undefined ) {
jQuery.migrateTrace = true;
}
// Forget any warnings we've already given; public
jQuery.migrateReset = function() {
warnedAbout = {};
jQuery.migrateWarnings.length = 0;
};
function migrateWarn( msg ) {
var console = window.console;
if ( !warnedAbout[ msg ] ) {
warnedAbout[ msg ] = true;
jQuery.migrateWarnings.push( msg );
if ( console && console.warn && !jQuery.migrateMute ) {
console.warn( "JQMIGRATE: " + msg );
if ( jQuery.migrateTrace && console.trace ) {
console.trace();
}
}
}
}
function migrateWarnProp( obj, prop, value, msg ) {
Object.defineProperty( obj, prop, {
configurable: true,
enumerable: true,
get: function() {
migrateWarn( msg );
return value;
},
set: function( newValue ) {
migrateWarn( msg );
value = newValue;
}
} );
}
function migrateWarnFunc( obj, prop, newFunc, msg ) {
obj[ prop ] = function() {
migrateWarn( msg );
return newFunc.apply( this, arguments );
};
}
if ( window.document.compatMode === "BackCompat" ) {
// JQuery has never supported or tested Quirks Mode
migrateWarn( "jQuery is not compatible with Quirks Mode" );
}
var oldInit = jQuery.fn.init,
oldIsNumeric = jQuery.isNumeric,
oldFind = jQuery.find,
rattrHashTest = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,
rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
jQuery.fn.init = function( arg1 ) {
var args = Array.prototype.slice.call( arguments );
if ( typeof arg1 === "string" && arg1 === "#" ) {
// JQuery( "#" ) is a bogus ID selector, but it returned an empty set before jQuery 3.0
migrateWarn( "jQuery( '#' ) is not a valid selector" );
args[ 0 ] = [];
}
return oldInit.apply( this, args );
};
jQuery.fn.init.prototype = jQuery.fn;
jQuery.find = function( selector ) {
var args = Array.prototype.slice.call( arguments );
// Support: PhantomJS 1.x
// String#match fails to match when used with a //g RegExp, only on some strings
if ( typeof selector === "string" && rattrHashTest.test( selector ) ) {
// The nonstandard and undocumented unquoted-hash was removed in jQuery 1.12.0
// First see if qS thinks it's a valid selector, if so avoid a false positive
try {
window.document.querySelector( selector );
} catch ( err1 ) {
// Didn't *look* valid to qSA, warn and try quoting what we think is the value
selector = selector.replace( rattrHashGlob, function( _, attr, op, value ) {
return "[" + attr + op + "\"" + value + "\"]";
} );
// If the regexp *may* have created an invalid selector, don't update it
// Note that there may be false alarms if selector uses jQuery extensions
try {
window.document.querySelector( selector );
migrateWarn( "Attribute selector with '#' must be quoted: " + args[ 0 ] );
args[ 0 ] = selector;
} catch ( err2 ) {
migrateWarn( "Attribute selector with '#' was not fixed: " + args[ 0 ] );
}
}
}
return oldFind.apply( this, args );
};
// Copy properties attached to original jQuery.find method (e.g. .attr, .isXML)
var findProp;
for ( findProp in oldFind ) {
if ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) {
jQuery.find[ findProp ] = oldFind[ findProp ];
}
}
// The number of elements contained in the matched element set
jQuery.fn.size = function() {
migrateWarn( "jQuery.fn.size() is deprecated and removed; use the .length property" );
return this.length;
};
jQuery.parseJSON = function() {
migrateWarn( "jQuery.parseJSON is deprecated; use JSON.parse" );
return JSON.parse.apply( null, arguments );
};
jQuery.isNumeric = function( val ) {
// The jQuery 2.2.3 implementation of isNumeric
function isNumeric2( obj ) {
var realStringObj = obj && obj.toString();
return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
}
var newValue = oldIsNumeric( val ),
oldValue = isNumeric2( val );
if ( newValue !== oldValue ) {
migrateWarn( "jQuery.isNumeric() should not be called on constructed objects" );
}
return oldValue;
};
migrateWarnFunc( jQuery, "holdReady", jQuery.holdReady,
"jQuery.holdReady is deprecated" );
migrateWarnFunc( jQuery, "unique", jQuery.uniqueSort,
"jQuery.unique is deprecated; use jQuery.uniqueSort" );
// Now jQuery.expr.pseudos is the standard incantation
migrateWarnProp( jQuery.expr, "filters", jQuery.expr.pseudos,
"jQuery.expr.filters is deprecated; use jQuery.expr.pseudos" );
migrateWarnProp( jQuery.expr, ":", jQuery.expr.pseudos,
"jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos" );
var oldAjax = jQuery.ajax;
jQuery.ajax = function( ) {
var jQXHR = oldAjax.apply( this, arguments );
// Be sure we got a jQXHR (e.g., not sync)
if ( jQXHR.promise ) {
migrateWarnFunc( jQXHR, "success", jQXHR.done,
"jQXHR.success is deprecated and removed" );
migrateWarnFunc( jQXHR, "error", jQXHR.fail,
"jQXHR.error is deprecated and removed" );
migrateWarnFunc( jQXHR, "complete", jQXHR.always,
"jQXHR.complete is deprecated and removed" );
}
return jQXHR;
};
var oldRemoveAttr = jQuery.fn.removeAttr,
oldToggleClass = jQuery.fn.toggleClass,
rmatchNonSpace = /\S+/g;
jQuery.fn.removeAttr = function( name ) {
var self = this;
jQuery.each( name.match( rmatchNonSpace ), function( i, attr ) {
if ( jQuery.expr.match.bool.test( attr ) ) {
migrateWarn( "jQuery.fn.removeAttr no longer sets boolean properties: " + attr );
self.prop( attr, false );
}
} );
return oldRemoveAttr.apply( this, arguments );
};
jQuery.fn.toggleClass = function( state ) {
// Only deprecating no-args or single boolean arg
if ( state !== undefined && typeof state !== "boolean" ) {
return oldToggleClass.apply( this, arguments );
}
migrateWarn( "jQuery.fn.toggleClass( boolean ) is deprecated" );
// Toggle entire class name of each element
return this.each( function() {
var className = this.getAttribute && this.getAttribute( "class" ) || "";
if ( className ) {
jQuery.data( this, "__className__", className );
}
// If the element has a class name or if we're passed `false`,
// then remove the whole classname (if there was one, the above saved it).
// Otherwise bring back whatever was previously saved (if anything),
// falling back to the empty string if nothing was stored.
if ( this.setAttribute ) {
this.setAttribute( "class",
className || state === false ?
"" :
jQuery.data( this, "__className__" ) || ""
);
}
} );
};
var internalSwapCall = false;
// If this version of jQuery has .swap(), don't false-alarm on internal uses
if ( jQuery.swap ) {
jQuery.each( [ "height", "width", "reliableMarginRight" ], function( _, name ) {
var oldHook = jQuery.cssHooks[ name ] && jQuery.cssHooks[ name ].get;
if ( oldHook ) {
jQuery.cssHooks[ name ].get = function() {
var ret;
internalSwapCall = true;
ret = oldHook.apply( this, arguments );
internalSwapCall = false;
return ret;
};
}
} );
}
jQuery.swap = function( elem, options, callback, args ) {
var ret, name,
old = {};
if ( !internalSwapCall ) {
migrateWarn( "jQuery.swap() is undocumented and deprecated" );
}
// Remember the old values, and insert the new ones
for ( name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
ret = callback.apply( elem, args || [] );
// Revert the old values
for ( name in options ) {
elem.style[ name ] = old[ name ];
}
return ret;
};
var oldData = jQuery.data;
jQuery.data = function( elem, name, value ) {
var curData;
// Name can be an object, and each entry in the object is meant to be set as data
if ( name && typeof name === "object" && arguments.length === 2 ) {
curData = jQuery.hasData( elem ) && oldData.call( this, elem );
var sameKeys = {};
for ( var key in name ) {
if ( key !== jQuery.camelCase( key ) ) {
migrateWarn( "jQuery.data() always sets/gets camelCased names: " + key );
curData[ key ] = name[ key ];
} else {
sameKeys[ key ] = name[ key ];
}
}
oldData.call( this, elem, sameKeys );
return name;
}
// If the name is transformed, look for the un-transformed name in the data object
if ( name && typeof name === "string" && name !== jQuery.camelCase( name ) ) {
curData = jQuery.hasData( elem ) && oldData.call( this, elem );
if ( curData && name in curData ) {
migrateWarn( "jQuery.data() always sets/gets camelCased names: " + name );
if ( arguments.length > 2 ) {
curData[ name ] = value;
}
return curData[ name ];
}
}
return oldData.apply( this, arguments );
};
var oldTweenRun = jQuery.Tween.prototype.run;
var linearEasing = function( pct ) {
return pct;
};
jQuery.Tween.prototype.run = function( ) {
if ( jQuery.easing[ this.easing ].length > 1 ) {
migrateWarn(
"'jQuery.easing." + this.easing.toString() + "' should use only one argument"
);
jQuery.easing[ this.easing ] = linearEasing;
}
oldTweenRun.apply( this, arguments );
};
jQuery.fx.interval = jQuery.fx.interval || 13;
// Support: IE9, Android <=4.4
// Avoid false positives on browsers that lack rAF
if ( window.requestAnimationFrame ) {
migrateWarnProp( jQuery.fx, "interval", jQuery.fx.interval,
"jQuery.fx.interval is deprecated" );
}
var oldLoad = jQuery.fn.load,
oldEventAdd = jQuery.event.add,
originalFix = jQuery.event.fix;
jQuery.event.props = [];
jQuery.event.fixHooks = {};
migrateWarnProp( jQuery.event.props, "concat", jQuery.event.props.concat,
"jQuery.event.props.concat() is deprecated and removed" );
jQuery.event.fix = function( originalEvent ) {
var event,
type = originalEvent.type,
fixHook = this.fixHooks[ type ],
props = jQuery.event.props;
if ( props.length ) {
migrateWarn( "jQuery.event.props are deprecated and removed: " + props.join() );
while ( props.length ) {
jQuery.event.addProp( props.pop() );
}
}
if ( fixHook && !fixHook._migrated_ ) {
fixHook._migrated_ = true;
migrateWarn( "jQuery.event.fixHooks are deprecated and removed: " + type );
if ( ( props = fixHook.props ) && props.length ) {
while ( props.length ) {
jQuery.event.addProp( props.pop() );
}
}
}
event = originalFix.call( this, originalEvent );
return fixHook && fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
};
jQuery.event.add = function( elem, types ) {
// This misses the multiple-types case but that seems awfully rare
if ( elem === window && types === "load" && window.document.readyState === "complete" ) {
migrateWarn( "jQuery(window).on('load'...) called after load event occurred" );
}
return oldEventAdd.apply( this, arguments );
};
jQuery.each( [ "load", "unload", "error" ], function( _, name ) {
jQuery.fn[ name ] = function() {
var args = Array.prototype.slice.call( arguments, 0 );
// If this is an ajax load() the first arg should be the string URL;
// technically this could also be the "Anything" arg of the event .load()
// which just goes to show why this dumb signature has been deprecated!
// jQuery custom builds that exclude the Ajax module justifiably die here.
if ( name === "load" && typeof args[ 0 ] === "string" ) {
return oldLoad.apply( this, args );
}
migrateWarn( "jQuery.fn." + name + "() is deprecated" );
args.splice( 0, 0, name );
if ( arguments.length ) {
return this.on.apply( this, args );
}
// Use .triggerHandler here because:
// - load and unload events don't need to bubble, only applied to window or image
// - error event should not bubble to window, although it does pre-1.7
// See http://bugs.jquery.com/ticket/11820
this.triggerHandler.apply( this, args );
return this;
};
} );
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup contextmenu" ).split( " " ),
function( i, name ) {
// Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
migrateWarn( "jQuery.fn." + name + "() event shorthand is deprecated" );
return arguments.length > 0 ?
this.on( name, null, data, fn ) :
this.trigger( name );
};
} );
// Trigger "ready" event only once, on document ready
jQuery( function() {
jQuery( window.document ).triggerHandler( "ready" );
} );
jQuery.event.special.ready = {
setup: function() {
if ( this === window.document ) {
migrateWarn( "'ready' event is deprecated" );
}
}
};
jQuery.fn.extend( {
bind: function( types, data, fn ) {
migrateWarn( "jQuery.fn.bind() is deprecated" );
return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
migrateWarn( "jQuery.fn.unbind() is deprecated" );
return this.off( types, null, fn );
},
delegate: function( selector, types, data, fn ) {
migrateWarn( "jQuery.fn.delegate() is deprecated" );
return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
migrateWarn( "jQuery.fn.undelegate() is deprecated" );
return arguments.length === 1 ?
this.off( selector, "**" ) :
this.off( types, selector || "**", fn );
},
hover: function( fnOver, fnOut ) {
migrateWarn( "jQuery.fn.hover() is deprecated" );
return this.on( "mouseenter", fnOver ).on( "mouseleave", fnOut || fnOver );
}
} );
var oldOffset = jQuery.fn.offset;
jQuery.fn.offset = function() {
var docElem,
elem = this[ 0 ],
origin = { top: 0, left: 0 };
if ( !elem || !elem.nodeType ) {
migrateWarn( "jQuery.fn.offset() requires a valid DOM element" );
return origin;
}
docElem = ( elem.ownerDocument || window.document ).documentElement;
if ( !jQuery.contains( docElem, elem ) ) {
migrateWarn( "jQuery.fn.offset() requires an element connected to a document" );
return origin;
}
return oldOffset.apply( this, arguments );
};
var oldParam = jQuery.param;
jQuery.param = function( data, traditional ) {
var ajaxTraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
if ( traditional === undefined && ajaxTraditional ) {
migrateWarn( "jQuery.param() no longer uses jQuery.ajaxSettings.traditional" );
traditional = ajaxTraditional;
}
return oldParam.call( this, data, traditional );
};
var oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
jQuery.fn.andSelf = function() {
migrateWarn( "jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()" );
return oldSelf.apply( this, arguments );
};
var oldDeferred = jQuery.Deferred,
tuples = [
// Action, add listener, callbacks, .then handlers, final state
[ "resolve", "done", jQuery.Callbacks( "once memory" ),
jQuery.Callbacks( "once memory" ), "resolved" ],
[ "reject", "fail", jQuery.Callbacks( "once memory" ),
jQuery.Callbacks( "once memory" ), "rejected" ],
[ "notify", "progress", jQuery.Callbacks( "memory" ),
jQuery.Callbacks( "memory" ) ]
];
jQuery.Deferred = function( func ) {
var deferred = oldDeferred(),
promise = deferred.promise();
deferred.pipe = promise.pipe = function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
migrateWarn( "deferred.pipe() is deprecated" );
return jQuery.Deferred( function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// Deferred.done(function() { bind to newDefer or newDefer.resolve })
// deferred.fail(function() { bind to newDefer or newDefer.reject })
// deferred.progress(function() { bind to newDefer or newDefer.notify })
deferred[ tuple[ 1 ] ]( function() {
var returned = fn && fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
newDefer[ tuple[ 0 ] + "With" ](
this === promise ? newDefer.promise() : this,
fn ? [ returned ] : arguments
);
}
} );
} );
fns = null;
} ).promise();
};
if ( func ) {
func.call( deferred, deferred );
}
return deferred;
};
// Preserve handler of uncaught exceptions in promise chains
jQuery.Deferred.exceptionHook = oldDeferred.exceptionHook;
return jQuery;
} );

View File

@ -1,215 +0,0 @@
/*! jQuery Migrate v3.0.1 | (c) jQuery Foundation and other contributors | jquery.org/license */
void 0 === jQuery.migrateMute && (jQuery.migrateMute = !0), function(e) {
"function" == typeof define && define.amd ? define([ "jquery" ], window, e) : "object" == typeof module && module.exports ? module.exports = e(require("jquery"), window) : e(jQuery, window);
}(function(e, t) {
"use strict";
function r(r) {
var n = t.console;
o[r] || (o[r] = !0, e.migrateWarnings.push(r), n && n.warn && !e.migrateMute && (n.warn("JQMIGRATE: " + r),
e.migrateTrace && n.trace && n.trace()));
}
function n(e, t, n, a) {
Object.defineProperty(e, t, {
configurable: !0,
enumerable: !0,
get: function() {
return r(a), n;
},
set: function(e) {
r(a), n = e;
}
});
}
function a(e, t, n, a) {
e[t] = function() {
return r(a), n.apply(this, arguments);
};
}
e.migrateVersion = "3.0.1", function() {
var r = /^[12]\./;
t.console && t.console.log && (e && !r.test(e.fn.jquery) || t.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"),
e.migrateWarnings && t.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),
t.console.log("JQMIGRATE: Migrate is installed" + (e.migrateMute ? "" : " with logging active") + ", version " + e.migrateVersion));
}();
var o = {};
e.migrateWarnings = [], void 0 === e.migrateTrace && (e.migrateTrace = !0), e.migrateReset = function() {
o = {}, e.migrateWarnings.length = 0;
}, "BackCompat" === t.document.compatMode && r("jQuery is not compatible with Quirks Mode");
var i = e.fn.init, s = e.isNumeric, u = e.find, c = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, l = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
e.fn.init = function(e) {
var t = Array.prototype.slice.call(arguments);
return "string" == typeof e && "#" === e && (r("jQuery( '#' ) is not a valid selector"),
t[0] = []), i.apply(this, t);
}, e.fn.init.prototype = e.fn, e.find = function(e) {
var n = Array.prototype.slice.call(arguments);
if ("string" == typeof e && c.test(e)) try {
t.document.querySelector(e);
} catch (a) {
e = e.replace(l, function(e, t, r, n) {
return "[" + t + r + '"' + n + '"]';
});
try {
t.document.querySelector(e), r("Attribute selector with '#' must be quoted: " + n[0]),
n[0] = e;
} catch (e) {
r("Attribute selector with '#' was not fixed: " + n[0]);
}
}
return u.apply(this, n);
};
var d;
for (d in u) Object.prototype.hasOwnProperty.call(u, d) && (e.find[d] = u[d]);
e.fn.size = function() {
return r("jQuery.fn.size() is deprecated and removed; use the .length property"),
this.length;
}, e.parseJSON = function() {
return r("jQuery.parseJSON is deprecated; use JSON.parse"), JSON.parse.apply(null, arguments);
}, e.isNumeric = function(t) {
var n = s(t), a = function(t) {
var r = t && t.toString();
return !e.isArray(t) && r - parseFloat(r) + 1 >= 0;
}(t);
return n !== a && r("jQuery.isNumeric() should not be called on constructed objects"),
a;
}, a(e, "holdReady", e.holdReady, "jQuery.holdReady is deprecated"), a(e, "unique", e.uniqueSort, "jQuery.unique is deprecated; use jQuery.uniqueSort"),
n(e.expr, "filters", e.expr.pseudos, "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),
n(e.expr, ":", e.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos");
var p = e.ajax;
e.ajax = function() {
var e = p.apply(this, arguments);
return e.promise && (a(e, "success", e.done, "jQXHR.success is deprecated and removed"),
a(e, "error", e.fail, "jQXHR.error is deprecated and removed"), a(e, "complete", e.always, "jQXHR.complete is deprecated and removed")),
e;
};
var f = e.fn.removeAttr, y = e.fn.toggleClass, m = /\S+/g;
e.fn.removeAttr = function(t) {
var n = this;
return e.each(t.match(m), function(t, a) {
e.expr.match.bool.test(a) && (r("jQuery.fn.removeAttr no longer sets boolean properties: " + a),
n.prop(a, !1));
}), f.apply(this, arguments);
}, e.fn.toggleClass = function(t) {
return void 0 !== t && "boolean" != typeof t ? y.apply(this, arguments) : (r("jQuery.fn.toggleClass( boolean ) is deprecated"),
this.each(function() {
var r = this.getAttribute && this.getAttribute("class") || "";
r && e.data(this, "__className__", r), this.setAttribute && this.setAttribute("class", r || !1 === t ? "" : e.data(this, "__className__") || "");
}));
};
var h = !1;
e.swap && e.each([ "height", "width", "reliableMarginRight" ], function(t, r) {
var n = e.cssHooks[r] && e.cssHooks[r].get;
n && (e.cssHooks[r].get = function() {
var e;
return h = !0, e = n.apply(this, arguments), h = !1, e;
});
}), e.swap = function(e, t, n, a) {
var o, i, s = {};
h || r("jQuery.swap() is undocumented and deprecated");
for (i in t) s[i] = e.style[i], e.style[i] = t[i];
o = n.apply(e, a || []);
for (i in t) e.style[i] = s[i];
return o;
};
var g = e.data;
e.data = function(t, n, a) {
var o;
if (n && "object" == typeof n && 2 === arguments.length) {
o = e.hasData(t) && g.call(this, t);
var i = {};
for (var s in n) s !== e.camelCase(s) ? (r("jQuery.data() always sets/gets camelCased names: " + s),
o[s] = n[s]) : i[s] = n[s];
return g.call(this, t, i), n;
}
return n && "string" == typeof n && n !== e.camelCase(n) && (o = e.hasData(t) && g.call(this, t)) && n in o ? (r("jQuery.data() always sets/gets camelCased names: " + n),
arguments.length > 2 && (o[n] = a), o[n]) : g.apply(this, arguments);
};
var v = e.Tween.prototype.run, j = function(e) {
return e;
};
e.Tween.prototype.run = function() {
e.easing[this.easing].length > 1 && (r("'jQuery.easing." + this.easing.toString() + "' should use only one argument"),
e.easing[this.easing] = j), v.apply(this, arguments);
}, e.fx.interval = e.fx.interval || 13, t.requestAnimationFrame && n(e.fx, "interval", e.fx.interval, "jQuery.fx.interval is deprecated");
var Q = e.fn.load, b = e.event.add, w = e.event.fix;
e.event.props = [], e.event.fixHooks = {}, n(e.event.props, "concat", e.event.props.concat, "jQuery.event.props.concat() is deprecated and removed"),
e.event.fix = function(t) {
var n, a = t.type, o = this.fixHooks[a], i = e.event.props;
if (i.length) for (r("jQuery.event.props are deprecated and removed: " + i.join()); i.length; ) e.event.addProp(i.pop());
if (o && !o._migrated_ && (o._migrated_ = !0, r("jQuery.event.fixHooks are deprecated and removed: " + a),
(i = o.props) && i.length)) for (;i.length; ) e.event.addProp(i.pop());
return n = w.call(this, t), o && o.filter ? o.filter(n, t) : n;
}, e.event.add = function(e, n) {
return e === t && "load" === n && "complete" === t.document.readyState && r("jQuery(window).on('load'...) called after load event occurred"),
b.apply(this, arguments);
}, e.each([ "load", "unload", "error" ], function(t, n) {
e.fn[n] = function() {
var e = Array.prototype.slice.call(arguments, 0);
return "load" === n && "string" == typeof e[0] ? Q.apply(this, e) : (r("jQuery.fn." + n + "() is deprecated"),
e.splice(0, 0, n), arguments.length ? this.on.apply(this, e) : (this.triggerHandler.apply(this, e),
this));
};
}), e.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(t, n) {
e.fn[n] = function(e, t) {
return r("jQuery.fn." + n + "() event shorthand is deprecated"), arguments.length > 0 ? this.on(n, null, e, t) : this.trigger(n);
};
}), e(function() {
e(t.document).triggerHandler("ready");
}), e.event.special.ready = {
setup: function() {
this === t.document && r("'ready' event is deprecated");
}
}, e.fn.extend({
bind: function(e, t, n) {
return r("jQuery.fn.bind() is deprecated"), this.on(e, null, t, n);
},
unbind: function(e, t) {
return r("jQuery.fn.unbind() is deprecated"), this.off(e, null, t);
},
delegate: function(e, t, n, a) {
return r("jQuery.fn.delegate() is deprecated"), this.on(t, e, n, a);
},
undelegate: function(e, t, n) {
return r("jQuery.fn.undelegate() is deprecated"), 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n);
},
hover: function(e, t) {
return r("jQuery.fn.hover() is deprecated"), this.on("mouseenter", e).on("mouseleave", t || e);
}
});
var x = e.fn.offset;
e.fn.offset = function() {
var n, a = this[0], o = {
top: 0,
left: 0
};
return a && a.nodeType ? (n = (a.ownerDocument || t.document).documentElement, e.contains(n, a) ? x.apply(this, arguments) : (r("jQuery.fn.offset() requires an element connected to a document"),
o)) : (r("jQuery.fn.offset() requires a valid DOM element"), o);
};
var k = e.param;
e.param = function(t, n) {
var a = e.ajaxSettings && e.ajaxSettings.traditional;
return void 0 === n && a && (r("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"),
n = a), k.call(this, t, n);
};
var A = e.fn.andSelf || e.fn.addBack;
e.fn.andSelf = function() {
return r("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"),
A.apply(this, arguments);
};
var S = e.Deferred, q = [ [ "resolve", "done", e.Callbacks("once memory"), e.Callbacks("once memory"), "resolved" ], [ "reject", "fail", e.Callbacks("once memory"), e.Callbacks("once memory"), "rejected" ], [ "notify", "progress", e.Callbacks("memory"), e.Callbacks("memory") ] ];
return e.Deferred = function(t) {
var n = S(), a = n.promise();
return n.pipe = a.pipe = function() {
var t = arguments;
return r("deferred.pipe() is deprecated"), e.Deferred(function(r) {
e.each(q, function(o, i) {
var s = e.isFunction(t[o]) && t[o];
n[i[1]](function() {
var t = s && s.apply(this, arguments);
t && e.isFunction(t.promise) ? t.promise().done(r.resolve).fail(r.reject).progress(r.notify) : r[i[0] + "With"](this === a ? r.promise() : this, s ? [ t ] : arguments);
});
}), t = null;
}).promise();
}, t && t.call(n, n), n;
}, e.Deferred.exceptionHook = S.exceptionHook, e;
});

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,7 @@
var length = str.length; var length = str.length;
var start = 0; var start = 0;
var inString = false; var inString = false;
var inRegex = false;
var inBox = false; var inBox = false;
var quoteChar; var quoteChar;
var list = []; var list = [];
@ -24,8 +25,13 @@
} }
for (var i=0;i<length;i++) { for (var i=0;i<length;i++) {
var c = str[i]; var c = str[i];
if (!inString) { if (!inString && !inRegex) {
if (c === "'" || c === '"') { if (c === "/") {
inRegex = true;
frame = {type:"regex",pos:i};
list.push(frame);
stack.push(frame);
} else if (c === "'" || c === '"') {
inString = true; inString = true;
quoteChar = c; quoteChar = c;
frame = {type:"string",pos:i}; frame = {type:"string",pos:i};
@ -37,6 +43,9 @@
} else if (c === ",") { } else if (c === ",") {
frame = {type:",",pos:i}; frame = {type:",",pos:i};
list.push(frame); list.push(frame);
} else if (c === "&") {
frame = {type:"&",pos:i};
list.push(frame);
} else if (/[\(\[\{]/.test(c)) { } else if (/[\(\[\{]/.test(c)) {
frame = {type:"open-block",char:c,pos:i}; frame = {type:"open-block",char:c,pos:i};
list.push(frame); list.push(frame);
@ -44,7 +53,8 @@
} else if (/[\}\)\]]/.test(c)) { } else if (/[\}\)\]]/.test(c)) {
var oldFrame = stack.pop(); var oldFrame = stack.pop();
if (matchingBrackets[oldFrame.char] !== c) { if (matchingBrackets[oldFrame.char] !== c) {
//console.log("Stack frame mismatch",c,"at",i,"expected",matchingBrackets[oldFrame.char],"from",oldFrame.pos); // console.log("Stack frame mismatch",c,"at",i,"expected",matchingBrackets[oldFrame.char],"from",oldFrame.pos);
// console.log(list);
return str; return str;
} }
//console.log("Closing",c,"at",i,"compare",oldFrame.type,oldFrame.pos); //console.log("Closing",c,"at",i,"compare",oldFrame.type,oldFrame.pos);
@ -53,19 +63,32 @@
list.push(frame); list.push(frame);
} }
} else { } else {
if (c === quoteChar) { if (c === "\\") {
// Next char must be a ] // an escaped char - stay in current mode and skip the next char
inString = false; i++;
stack.pop(); }
if (inString) {
if (c === quoteChar) {
// Next char must be a ]
inString = false;
var f = stack.pop();
f.end = i;
}
} else if (inRegex) {
if (c === "/") {
inRegex = false;
var f = stack.pop();
f.end = i;
}
} }
} }
} }
// console.log(stack); // console.log("list",list);
var result = str; var result = str;
var indent = 0; var indent = 0;
var offset = 0; var offset = 0;
var pre,post,indented; var pre,post,indented,hasNewline;
var longStack = []; var longStack = [];
list.forEach(function(f) { list.forEach(function(f) {
if (f.type === ";" || f.type === ",") { if (f.type === ";" || f.type === ",") {
@ -73,29 +96,51 @@
pre = result.substring(0,offset+f.pos+1); pre = result.substring(0,offset+f.pos+1);
post = result.substring(offset+f.pos+1); post = result.substring(offset+f.pos+1);
indented = indentLine(post,indent); indented = indentLine(post,indent);
result = pre+"\n"+indented; hasNewline = /\n$/.test(pre);
offset += indented.length-post.length+1; // console.log("A§"+pre+"§\n§"+indented+"§",hasNewline);
result = pre+(hasNewline?"":"\n")+indented;
offset += indented.length-post.length+(hasNewline?0:1);
} }
} else if (f.type === "&") {
pre = result.substring(0,offset+f.pos+1);
var lastLineBreak = pre.lastIndexOf("\n");
var lineLength = pre.length - lastLineBreak;
if (lineLength > 70) {
post = result.substring(offset+f.pos+1);
if (!/^\n/.test(post)) {
indented = indentLine(post,indent);
hasNewline = /\n$/.test(pre);
result = pre+(hasNewline?"":"\n")+indented;
offset += indented.length-post.length+(hasNewline?0:1);
}
}
} else if (f.type === "open-block") { } else if (f.type === "open-block") {
if (f.width > 30) { if (f.width > 40) {
longStack.push(true); longStack.push(true);
indent += 4; indent += 4;
pre = result.substring(0,offset+f.pos+1); pre = result.substring(0,offset+f.pos+1);
post = result.substring(offset+f.pos+1); post = result.substring(offset+f.pos+1);
hasNewline = /\n$/.test(pre);
indented = indentLine(post,indent); indented = indentLine(post,indent);
result = pre+"\n"+indented; result = pre+(hasNewline?"":"\n")+indented;
offset += indented.length-post.length+1; offset += indented.length-post.length+(hasNewline?0:1);
} else { } else {
longStack.push(false); longStack.push(false);
} }
} else if (f.type === "close-block") { } else if (f.type === "close-block") {
if (f.width > 30) { if (f.width > 40) {
indent -= 4; indent -= 4;
pre = result.substring(0,offset+f.pos); pre = result.substring(0,offset+f.pos);
post = result.substring(offset+f.pos); post = result.substring(offset+f.pos);
indented = indentLine(post,indent); indented = indentLine(post,indent);
result = pre+"\n"+indented; hasNewline = /\n *$/.test(pre);
offset += indented.length-post.length+1; if (hasNewline) {
result = pre + post;
} else {
result = pre+"\n"+indented;
offset += indented.length-post.length+1;
}
} }
longStack.pop(); longStack.pop();
} }

View File

@ -28,6 +28,11 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
}, "identifier"); }, "identifier");
this.$rules = { this.$rules = {
"start" : [ "start" : [
{
token: "string.regexp",
regex: "\\/",
next: "regex"
},
{ {
token : "string", token : "string",
regex : "'(?=.)", regex : "'(?=.)",
@ -46,34 +51,35 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
token : "constant.numeric", // float token : "constant.numeric", // float
regex : /[+-]?\d[\d_]*(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/ regex : /[+-]?\d[\d_]*(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/
}, },
{ token: "keyword", {
regex: /λ/ token: "keyword",
}, regex: /λ/
{ },
token: "keyword", {
regex: jsonataFunctions token: "keyword",
}, regex: jsonataFunctions
{ },
token : keywordMapper, {
regex : "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*" token : keywordMapper,
}, regex : "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*"
{ },
token : "punctuation.operator", {
regex : /[.](?![.])/ token : "punctuation.operator",
}, regex : /[.](?![.])/
{ },
token : "keyword.operator", {
regex : /\|\||<=|>=|\.\.|\*\*|!=|:=|[=<>`!$%&*+\-~\/^]/, token : "keyword.operator",
next : "start" regex : /\|\||<=|>=|\.\.|\*\*|!=|:=|[=<>`!$%&*+\-~\/^]/,
}, next : "start"
{ },
token : "punctuation.operator", {
regex : /[?:,;.]/, token : "punctuation.operator",
next : "start" regex : /[?:,;.]/,
}, next : "start"
{ },
token : "paren.lparen", {
regex : /[\[({]/, token : "paren.lparen",
regex : /[\[({]/,
next : "start" next : "start"
}, },
{ {
@ -86,7 +92,8 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
token : "string", token : "string",
regex : '"|$', regex : '"|$',
next : "start" next : "start"
}, { },
{
defaultToken: "string" defaultToken: "string"
} }
], ],
@ -95,9 +102,24 @@ ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/m
token : "string", token : "string",
regex : "'|$", regex : "'|$",
next : "start" next : "start"
}, { },
{
defaultToken: "string" defaultToken: "string"
} }
],
"regex" : [
{
token: "string.regexp",
regex: "\\\\/"
},
{
token: "string.regexp",
regex: "/[sxngimy]*",
next: "start"
},
{
defaultToken: "string.regexp"
}
] ]
}; };
}; };

File diff suppressed because one or more lines are too long

View File

@ -16,14 +16,12 @@
<script type="text/html" data-template-name="inject"> <script type="text/html" data-template-name="inject">
<div class="form-row"> <div class="form-row">
<label for="node-input-payload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-payload" style="width:70%"> <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
<input type="hidden" id="node-input-payloadType">
</div> </div>
<div class="form-row"> <div class="form-row node-input-property-container-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label> <ol id="node-input-property-container"></ol>
<input type="text" id="node-input-topic">
</div> </div>
<div class="form-row" id="node-once"> <div class="form-row" id="node-once">
@ -114,12 +112,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-tips" data-i18n="[html]inject.tip"></div>
</script> </script>
<style> <style>
.inject-time-row { .inject-time-row {
@ -155,37 +148,76 @@
</style> </style>
<script type="text/javascript"> <script type="text/javascript">
(function() {
function resizeDialog(size) {
size = size || { height: $(".red-ui-tray-content form").height() }
var rows = $("#dialog-form>div:not(.node-input-property-container-row):visible");
var height = size.height;
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-property-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
height += 16;
$("#node-input-property-container").editableList('height',height);
}
RED.nodes.registerType('inject',{ RED.nodes.registerType('inject',{
category: 'common', category: 'common',
color:"#a6bbcf", color:"#a6bbcf",
defaults: { defaults: {
name: {value:""}, name: {value:""},
topic: {value:""}, props:{value:[{p:"payload"},{p:"topic",vt:"str"}]},
payload: {value:"", validate: RED.validators.typedInput("payloadType")},
payloadType: {value:"date"},
repeat: {value:"", validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }}, repeat: {value:"", validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
crontab: {value:""}, crontab: {value:""},
once: {value:false}, once: {value:false},
onceDelay: {value:0.1} onceDelay: {value:0.1},
topic: {value:""},
payload: {value:"", validate: RED.validators.typedInput("payloadType")},
payloadType: {value:"date"},
}, },
icon: "inject.svg", icon: "inject.svg",
inputs:0, inputs:0,
outputs:1, outputs:1,
outputLabels: function(index) { outputLabels: function(index) {
var lab = this.payloadType; var lab = '';
if (lab === "json") {
try { // if only payload and topic - display payload type
lab = typeof JSON.parse(this.payload); // if only one property - show it's type
if (lab === "object") { // if more than one property (other than payload and topic) - show "x properties" where x is the number of properties.
if (Array.isArray(JSON.parse(this.payload))) { lab = "Array"; } // this.props will not be an array for legacy inject nodes until they are re-deployed
} //
} catch(e) { var props = this.props;
return this._("inject.label.invalid"); } if (!Array.isArray(props)) {
props = [
{ p:"payload", v: this.payload, vt: this.payloadType },
{ p:"topic", v: this.topic, vt: "str" }
]
} }
var name = "inject.label."+lab; if (props) {
var label = this._(name); for (var i=0,l=props.length; i<l; i++) {
if (name !== label) { if (i > 0) lab += "\n";
return label; if (i === 5) {
lab += " + "+(props.length-4);
break;
}
lab += props[i].p+": ";
var propType = props[i].p === "payload"? this.payloadType : props[i].vt;
if (propType === "json") {
try {
var parsedProp = JSON.parse(props[i].p === "payload"? this.payload : props[i].v);
propType = typeof parsedProp;
if (propType === "object" && Array.isArray(parsedProp)) {
propType = "Array";
}
} catch(e) {
propType = "invalid";
}
}
lab += this._("inject.label."+propType);
}
} }
return lab; return lab;
}, },
@ -201,27 +233,33 @@
} }
if (this.name) { if (this.name) {
return this.name+suffix; return this.name+suffix;
} else if (this.payloadType === "string" || }
this.payloadType === "str" ||
this.payloadType === "num" || var payload = this.payload || "";
this.payloadType === "bool" || var payloadType = this.payloadType || "str";
this.payloadType === "json") { var topic = this.topic || "";
if ((this.topic !== "") && ((this.topic.length + this.payload.length) <= 32)) {
return this.topic + ":" + this.payload+suffix; if (payloadType === "string" ||
} else if (this.payload.length > 0 && this.payload.length < 24) { payloadType === "str" ||
return this.payload+suffix; payloadType === "num" ||
payloadType === "bool" ||
payloadType === "json") {
if ((topic !== "") && ((topic.length + payload.length) <= 32)) {
return topic + ":" + payload+suffix;
} else if (payload.length > 0 && payload.length < 24) {
return payload+suffix;
} else { } else {
return this._("inject.inject")+suffix; return this._("inject.inject")+suffix;
} }
} else if (this.payloadType === 'date') { } else if (payloadType === 'date' || payloadType === 'bin' || payloadType === 'env') {
if ((this.topic !== "") && (this.topic.length <= 16)) { if ((topic !== "") && (topic.length <= 16)) {
return this.topic + ":" + this._("inject.timestamp")+suffix; return topic + ":" + this._('inject.label.'+payloadType)+suffix;
} else { } else {
return this._("inject.timestamp")+suffix; return this._('inject.label.'+payloadType)+suffix;
} }
} else if (this.payloadType === 'flow' || this.payloadType === 'global') { } else if (payloadType === 'flow' || payloadType === 'global') {
var key = RED.utils.parseContextKey(this.payload); var key = RED.utils.parseContextKey(payload);
return this.payloadType+"."+key.key+suffix; return payloadType+"."+key.key+suffix;
} else { } else {
return this._("inject.inject")+suffix; return this._("inject.inject")+suffix;
} }
@ -239,13 +277,6 @@
} else if (this.payloadType === 'string' || this.payloadType === 'none') { } else if (this.payloadType === 'string' || this.payloadType === 'none') {
this.payloadType = "str"; this.payloadType = "str";
} }
$("#node-input-payloadType").val(this.payloadType);
$("#node-input-payload").typedInput({
default: 'str',
typeField: $("#node-input-payloadType"),
types:['flow','global','str','num','bool','json','bin','date','env']
});
$("#inject-time-type-select").on("change", function() { $("#inject-time-type-select").on("change", function() {
$("#node-input-crontab").val(''); $("#node-input-crontab").val('');
@ -259,6 +290,11 @@
$("#node-once").hide(); $("#node-once").hide();
$("#node-input-once").prop('checked', false); $("#node-input-once").prop('checked', false);
} }
// Scroll down
var scrollDiv = $("#dialog-form").parent();
scrollDiv.scrollTop(scrollDiv.prop('scrollHeight'));
resizeDialog();
}); });
$("#node-input-once").on("change", function() { $("#node-input-once").on("change", function() {
@ -378,7 +414,70 @@
$("#inject-time-type-select").val(repeattype); $("#inject-time-type-select").val(repeattype);
$("#inject-time-row-"+repeattype).show(); $("#inject-time-row-"+repeattype).show();
$("#node-input-payload").typedInput('type',this.payloadType); /* */
$('#node-input-property-container').css('min-height','120px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var prop = opt;
if (!prop.hasOwnProperty('p')) {
prop = {p:"",v:"",vt:"str"};
}
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
var row = $('<div/>').appendTo(container);
var propertyName = $('<input/>',{class:"node-input-prop-property-name",type:"text"})
.css("width","30%")
.appendTo(row)
.typedInput({types:['msg']});
$('<div/>',{style: 'display:inline-block; padding:0px 6px;'})
.text('=')
.appendTo(row);
var propertyValue = $('<input/>',{class:"node-input-prop-property-value",type:"text"})
.css("width","calc(70% - 30px)")
.appendTo(row)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
propertyName.typedInput('value',prop.p);
propertyValue.typedInput('value',prop.v);
propertyValue.typedInput('type',prop.vt);
},
removable: true,
sortable: true
});
if (!this.props) {
var payload = {
p:'payload',
v: this.payload ? this.payload : '',
vt:this.payloadType ? this.payloadType : 'date'
};
var topic = {
p:'topic',
v: this.topic ? this.topic : '',
vt:'string'
}
this.props = [payload,topic];
}
for (var i=0; i<this.props.length; i++) {
var prop = this.props[i];
var newProp = { p: prop.p, v: prop.v, vt: prop.vt };
if (newProp.v === undefined) {
if (prop.p === 'payload') {
newProp.v = this.payload ? this.payload : '';
newProp.vt = this.payloadType ? this.payloadType : 'date';
} else if (prop.p === 'topic' && prop.vt === "str") {
newProp.v = this.topic ? this.topic : '';
}
}
$("#node-input-property-container").editableList('addItem',newProp);
}
$("#inject-time-type-select").trigger("change"); $("#inject-time-type-select").trigger("change");
$("#inject-time-interval-time-start").trigger("change"); $("#inject-time-interval-time-start").trigger("change");
@ -474,6 +573,34 @@
$("#node-input-repeat").val(repeat); $("#node-input-repeat").val(repeat);
$("#node-input-crontab").val(crontab); $("#node-input-crontab").val(crontab);
/* Gather the injected properties of the msg object */
var props = $("#node-input-property-container").editableList('items');
var node = this;
node.props= [];
delete node.payloadType;
delete node.payload;
delete node.topic;
props.each(function(i) {
var prop = $(this);
var p = {
p:prop.find(".node-input-prop-property-name").typedInput('value')
};
if (p.p) {
p.v = prop.find(".node-input-prop-property-value").typedInput('value');
p.vt = prop.find(".node-input-prop-property-value").typedInput('type');
if (p.p === "payload") { // save payload to old "legacy" property
node.payloadType = p.vt;
node.payload = p.v;
delete p.v;
delete p.vt;
} else if (p.p === "topic" && p.vt === "str") {
node.topic = p.v;
delete p.v;
}
node.props.push(p);
}
});
}, },
button: { button: {
enabled: function() { enabled: function() {
@ -483,12 +610,7 @@
if (this.changed) { if (this.changed) {
return RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.undeployedChanges")}),"warning"); return RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.undeployedChanges")}),"warning");
} }
var payload = this.payload;
if ((this.payloadType === 'flow') ||
(this.payloadType === 'global')) {
var key = RED.utils.parseContextKey(payload);
payload = this.payloadType+"."+key.key;
}
var label = this._def.label.call(this); var label = this._def.label.call(this);
if (label.length > 30) { if (label.length > 30) {
label = label.substring(0,50)+"..."; label = label.substring(0,50)+"...";
@ -514,7 +636,8 @@
} }
}); });
} }
} },
oneditresize: resizeDialog
}); });
})();
</script> </script>

View File

@ -20,9 +20,32 @@ module.exports = function(RED) {
function InjectNode(n) { function InjectNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.topic = n.topic;
this.payload = n.payload; /* Handle legacy */
this.payloadType = n.payloadType; if(!Array.isArray(n.props)){
n.props = [];
n.props.push({
p:'payload',
v:n.payload,
vt:n.payloadType
});
n.props.push({
p:'topic',
v:n.topic,
vt:'str'
});
} else {
for (var i=0,l=n.props.length; i<l; i++) {
if (n.props[i].p === 'payload' && !n.props[i].hasOwnProperty('v')) {
n.props[i].v = n.payload;
n.props[i].vt = n.payloadType;
} else if (n.props[i].p === 'topic' && n.props[i].vt === 'str' && !n.props[i].hasOwnProperty('v')) {
n.props[i].v = n.topic;
}
}
}
this.props = n.props;
this.repeat = n.repeat; this.repeat = n.repeat;
this.crontab = n.crontab; this.crontab = n.crontab;
this.once = n.once; this.once = n.once;
@ -31,65 +54,83 @@ module.exports = function(RED) {
this.cronjob = null; this.cronjob = null;
var node = this; var node = this;
node.props.forEach(function (prop) {
if (prop.vt === "jsonata") {
try {
var val = prop.v ? prop.v : "";
prop.exp = RED.util.prepareJSONataExpression(val, node);
}
catch (err) {
node.error(RED._("inject.errors.invalid-expr", {error:err.message}));
prop.exp = null;
}
}
});
if (node.repeat > 2147483) { if (node.repeat > 2147483) {
node.error(RED._("inject.errors.toolong", this)); node.error(RED._("inject.errors.toolong", this));
delete node.repeat; delete node.repeat;
} }
node.repeaterSetup = function () { node.repeaterSetup = function () {
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) { if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
this.repeat = this.repeat * 1000; this.repeat = this.repeat * 1000;
if (RED.settings.verbose) { if (RED.settings.verbose) {
this.log(RED._("inject.repeat", this)); this.log(RED._("inject.repeat", this));
}
this.interval_id = setInterval(function() {
node.emit("input", {});
}, this.repeat);
} else if (this.crontab) {
if (RED.settings.verbose) {
this.log(RED._("inject.crontab", this));
}
this.cronjob = new cron.CronJob(this.crontab, function() { node.emit("input", {}); }, null, true);
} }
this.interval_id = setInterval(function() {
node.emit("input", {});
}, this.repeat);
} else if (this.crontab) {
if (RED.settings.verbose) {
this.log(RED._("inject.crontab", this));
}
this.cronjob = new cron.CronJob(this.crontab, function() { node.emit("input", {}); }, null, true);
}
}; };
if (this.once) { if (this.once) {
this.onceTimeout = setTimeout( function() { this.onceTimeout = setTimeout( function() {
node.emit("input",{}); node.emit("input",{});
node.repeaterSetup(); node.repeaterSetup();
}, this.onceDelay); }, this.onceDelay);
} else { } else {
node.repeaterSetup(); node.repeaterSetup();
} }
this.on("input",function(msg) { this.on("input", function(msg) {
msg.topic = this.topic; var errors = [];
if (this.payloadType !== 'flow' && this.payloadType !== 'global') {
try {
if ( (this.payloadType == null && this.payload === "") || this.payloadType === "date") {
msg.payload = Date.now();
} else if (this.payloadType == null) {
msg.payload = this.payload;
} else if (this.payloadType === 'none') {
msg.payload = "";
} else {
msg.payload = RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg);
}
this.send(msg);
msg = null;
} catch(err) {
this.error(err,msg);
}
} else {
RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg, function(err,res) {
if (err) {
node.error(err,msg);
} else {
msg.payload = res;
node.send(msg);
}
}); this.props.forEach(p => {
var property = p.p;
var value = p.v ? p.v : '';
var valueType = p.vt ? p.vt : 'str';
if (!property) return;
if (valueType === "jsonata") {
if (p.exp) {
try {
var val = RED.util.evaluateJSONataExpression(p.exp, msg);
RED.util.setMessageProperty(msg, property, val, true);
}
catch (err) {
errors.push(err.message);
}
}
return;
}
try {
RED.util.setMessageProperty(msg,property,RED.util.evaluateNodeProperty(value, valueType, this, msg),true);
} catch (err) {
errors.push(err.toString());
}
});
if (errors.length) {
node.error(errors.join('; '), msg);
} else {
node.send(msg);
} }
}); });
} }

View File

@ -6,25 +6,30 @@
<input id="node-input-complete" type="hidden"> <input id="node-input-complete" type="hidden">
<input id="node-input-targetType" type="hidden"> <input id="node-input-targetType" type="hidden">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-tosidebar"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label> <label for="node-input-tosidebar"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label>
<label for="node-input-tosidebar" style="width:70%"> <label for="node-input-tosidebar" style="width:70%">
<input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toSidebar"></span> <input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toSidebar"></span>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-console"> </label> <label for="node-input-console"> </label>
<label for="node-input-console" style="width:70%"> <label for="node-input-console" style="width:70%">
<input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toConsole"></span> <input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toConsole"></span>
</label> </label>
</div> </div>
<div class="form-row" id="node-tostatus-line"> <div class="form-row">
<label for="node-input-tostatus"> </label> <label for="node-input-tostatus"> </label>
<label for="node-input-tostatus" style="width:70%"> <label for="node-input-tostatus" style="width:70%">
<input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toStatus"></span> <input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toStatus"></span>
</label> </label>
</div> </div>
<div class="form-row" id="node-tostatus-line">
<label for="node-input-typed-status"><i class="fa fa-ellipsis-h"></i> <span data-i18n="debug.status"></span></label>
<input id="node-input-typed-status" type="text" style="width: 70%">
<input id="node-input-statusVal" type="hidden">
<input id="node-input-statusType" type="hidden">
</div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"> <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
@ -36,6 +41,36 @@
<script type="text/javascript"> <script type="text/javascript">
(function() { (function() {
var subWindow = null; var subWindow = null;
function activateAjaxCall(node, active, successCallback) {
var url;
var body;
if (Array.isArray(node)) {
url = "debug/"+(active?"enable":"disable");
body = {nodes: node.map(function(n) { return n.id})}
node = node[0];
} else {
url = "debug/"+node.id+"/"+(active?"enable":"disable");
}
$.ajax({
url: url,
type: "POST",
data: body,
success: successCallback,
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status == 404) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.not-deployed")}),"error");
} else if (jqXHR.status === 0) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.no-response")}),"error");
} else {
// TODO where is the err.status comming from?
RED.notify(node._("common.notification.error",{message:node._("common.notification.errors.unexpected",{status:err.status,message:err.response})}),"error");
}
}
});
}
RED.nodes.registerType('debug',{ RED.nodes.registerType('debug',{
category: 'common', category: 'common',
defaults: { defaults: {
@ -45,7 +80,9 @@
console: {value:false}, console: {value:false},
tostatus: {value:false}, tostatus: {value:false},
complete: {value:"false", required:true}, complete: {value:"false", required:true},
targetType: {value:undefined} targetType: {value:undefined},
statusVal: {value:""},
statusType: {value:"auto"}
}, },
label: function() { label: function() {
var suffix = ""; var suffix = "";
@ -73,38 +110,28 @@
onclick: function() { onclick: function() {
var label = this.name||"debug"; var label = this.name||"debug";
var node = this; var node = this;
$.ajax({ activateAjaxCall(node, node.active, function(resp, textStatus, xhr) {
url: "debug/"+this.id+"/"+(this.active?"enable":"disable"), var historyEvent = {
type: "POST", t:'edit',
success: function(resp, textStatus, xhr) { node:node,
var historyEvent = { changes:{
t:'edit', active:!node.active
node:node, },
changes:{ dirty:node.dirty,
active:!node.active changed:node.changed,
}, callback: function(ev) {
dirty:node.dirty, activateAjaxCall(ev.node, ev.node.active);
changed:node.changed
};
node.changed = true;
node.dirty = true;
RED.nodes.dirty(true);
RED.history.push(historyEvent);
RED.view.redraw();
if (xhr.status == 200) {
RED.notify(node._("debug.notification.activated",{label:label}),"success");
} else if (xhr.status == 201) {
RED.notify(node._("debug.notification.deactivated",{label:label}),"success");
}
},
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status == 404) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.not-deployed")}),"error");
} else if (jqXHR.status === 0) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.no-response")}),"error");
} else {
RED.notify(node._("common.notification.error",{message:node._("common.notification.errors.unexpected",{status:err.status,message:err.response})}),"error");
} }
};
node.changed = true;
node.dirty = true;
RED.nodes.dirty(true);
RED.history.push(historyEvent);
RED.view.redraw();
if (xhr.status == 200) {
RED.notify(node._("debug.notification.activated",{label:label}),"success");
} else if (xhr.status == 201) {
RED.notify(node._("debug.notification.deactivated",{label:label}),"success");
} }
}); });
} }
@ -266,6 +293,78 @@
RED.events.on("project:change", this.clearMessageList); RED.events.on("project:change", this.clearMessageList);
RED.actions.add("core:clear-debug-messages", function() { RED.debug.clearMessageList(true) }); RED.actions.add("core:clear-debug-messages", function() { RED.debug.clearMessageList(true) });
RED.actions.add("core:activate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(true), true); });
RED.actions.add("core:activate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, true),true); });
RED.actions.add("core:activate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, false),true); });
RED.actions.add("core:deactivate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(false), false); });
RED.actions.add("core:deactivate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, true),false); });
RED.actions.add("core:deactivate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, false),false); });
function getSelectedDebugNodes(state) {
var nodes = [];
var selection = RED.view.selection();
if (selection.nodes) {
selection.nodes.forEach(function(n) {
if (RED.nodes.subflow(n.z)) {
return;
}
if (n.type === 'debug' && n.active !== state) {
nodes.push(n);
} else if (n.type === 'group') {
nodes = nodes.concat( RED.group.getNodes(n,true).filter(function(n) {
return n.type === 'debug' && n.active !== state
}));
}
});
}
return nodes;
}
function getMatchingDebugNodes(state,globally) {
var nodes = [];
var filter = {type:"debug"};
if (!globally) {
filter.z = RED.workspaces.active();
}
var candidateNodes = RED.nodes.filterNodes(filter);
nodes = candidateNodes.filter(function(n) {
return n.active !== state && !RED.nodes.subflow(n.z)
})
return nodes;
}
function setDebugNodeState(nodes,state) {
var historyEvents = [];
if (nodes.length > 0) {
activateAjaxCall(nodes,false, function(resp, textStatus, xhr) {
nodes.forEach(function(n) {
historyEvents.push({
t: "edit",
node: n,
changed: n.changed,
changes: {
active: n.active
}
});
n.active = state;
n.changed = true;
n.dirty = true;
})
RED.history.push({
t: "multi",
events: historyEvents,
dirty: RED.nodes.dirty(),
callback: function() {
activateAjaxCall(nodes,nodes[0].active);
}
});
RED.nodes.dirty(true);
RED.view.redraw();
});
}
}
$("#red-ui-sidebar-debug-open").on("click", function(e) { $("#red-ui-sidebar-debug-open").on("click", function(e) {
e.preventDefault(); e.preventDefault();
subWindow = window.open(document.location.toString().replace(/[?#].*$/,"")+"debug/view/view.html"+document.location.search,"nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600"); subWindow = window.open(document.location.toString().replace(/[?#].*$/,"")+"debug/view/view.html"+document.location.search,"nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600");
@ -308,10 +407,20 @@
window.removeEventListener("message",this.handleWindowMessage); window.removeEventListener("message",this.handleWindowMessage);
RED.actions.remove("core:show-debug-tab"); RED.actions.remove("core:show-debug-tab");
RED.actions.remove("core:clear-debug-messages"); RED.actions.remove("core:clear-debug-messages");
delete RED._debug; delete RED._debug;
}, },
oneditprepare: function() { oneditprepare: function() {
var autoType = {
value: "auto",
label: RED._("node-red:debug.autostatus"),
hasValue: false
};
$("#node-input-typed-status").typedInput({
default: "auto",
types:[autoType, "msg", "jsonata"],
typeField: $("#node-input-statusType")
});
var that = this;
var none = { var none = {
value: "none", value: "none",
label: RED._("node-red:debug.none"), label: RED._("node-red:debug.none"),
@ -321,6 +430,14 @@
this.tosidebar = true; this.tosidebar = true;
$("#node-input-tosidebar").prop('checked', true); $("#node-input-tosidebar").prop('checked', true);
} }
if (this.statusVal === undefined) {
this.statusVal = (this.complete === "false") ? "payload" : ((this.complete === "true") ? "payload" : this.complete+"");
$("#node-input-typed-status").typedInput('value',this.statusVal || "");
}
if (this.statusType === undefined) {
this.statusType = this.targetType;
$("#node-input-typed-status").typedInput('type',this.statusType || "auto");
}
if (typeof this.console === "string") { if (typeof this.console === "string") {
this.console = (this.console == 'true'); this.console = (this.console == 'true');
$("#node-input-console").prop('checked', this.console); $("#node-input-console").prop('checked', this.console);
@ -331,6 +448,7 @@
label: RED._("node-red:debug.msgobj"), label: RED._("node-red:debug.msgobj"),
hasValue: false hasValue: false
}; };
$("#node-input-typed-complete").typedInput({ $("#node-input-typed-complete").typedInput({
default: "msg", default: "msg",
types:['msg', fullType, "jsonata"], types:['msg', fullType, "jsonata"],
@ -354,17 +472,29 @@
) { ) {
$("#node-input-typed-complete").typedInput('value','payload'); $("#node-input-typed-complete").typedInput('value','payload');
} }
if ($("#node-input-typed-complete").typedInput('type') === 'full') { });
$("#node-tostatus-line").hide();
} else { $("#node-input-tostatus").on('change',function() {
if ($(this).is(":checked")) {
if (!that.hasOwnProperty("statusVal") || that.statusVal === "") {
var type = $("#node-input-typed-complete").typedInput('type');
var comp = "payload";
if (type !== 'full') {
comp = $("#node-input-typed-complete").typedInput('value');
}
that.statusType = "auto";
that.statusVal = comp;
}
$("#node-input-typed-status").typedInput('type',that.statusType);
$("#node-input-typed-status").typedInput('value',that.statusVal);
$("#node-tostatus-line").show(); $("#node-tostatus-line").show();
} }
}); else {
$("#node-input-complete").on('change',function() {
if ($("#node-input-typed-complete").typedInput('type') === 'full') {
$("#node-tostatus-line").hide(); $("#node-tostatus-line").hide();
} else { that.statusType = "auto";
$("#node-tostatus-line").show(); that.statusVal = "";
$("#node-input-typed-status").typedInput('type',that.statusType);
$("#node-input-typed-status").typedInput('value',that.statusVal);
} }
}); });
}, },
@ -375,6 +505,7 @@
} else { } else {
$("#node-input-complete").val($("#node-input-typed-complete").typedInput('value')); $("#node-input-complete").val($("#node-input-typed-complete").typedInput('value'));
} }
$("#node-input-statusVal").val($("#node-input-typed-status").typedInput('value'));
} }
}); });
})(); })();

View File

@ -2,7 +2,7 @@ module.exports = function(RED) {
"use strict"; "use strict";
var util = require("util"); var util = require("util");
var events = require("events"); var events = require("events");
var path = require("path"); //var path = require("path");
var debuglength = RED.settings.debugMaxLength || 1000; var debuglength = RED.settings.debugMaxLength || 1000;
var useColors = RED.settings.debugUseColors || false; var useColors = RED.settings.debugUseColors || false;
util.inspect.styles.boolean = "red"; util.inspect.styles.boolean = "red";
@ -15,36 +15,20 @@ module.exports = function(RED) {
this.complete = hasEditExpression ? null : (n.complete||"payload").toString(); this.complete = hasEditExpression ? null : (n.complete||"payload").toString();
if (this.complete === "false") { this.complete = "payload"; } if (this.complete === "false") { this.complete = "payload"; }
this.console = ""+(n.console || false); this.console = ""+(n.console || false);
this.tostatus = (this.complete !== "true") && (n.tostatus || false); this.tostatus = n.tostatus || false;
this.statusType = n.statusType || "msg";
this.statusVal = n.statusVal || this.complete;
this.tosidebar = n.tosidebar; this.tosidebar = n.tosidebar;
if (this.tosidebar === undefined) { this.tosidebar = true; } if (this.tosidebar === undefined) { this.tosidebar = true; }
this.severity = n.severity || 40;
this.active = (n.active === null || typeof n.active === "undefined") || n.active; this.active = (n.active === null || typeof n.active === "undefined") || n.active;
if (this.tostatus) { this.status({fill:"grey", shape:"ring"}); } if (this.tostatus) { this.status({fill:"grey", shape:"ring"}); }
else { this.status({}); } else { this.status({}); }
var hasStatExpression = (n.statusType === "jsonata");
var statExpression = hasStatExpression ? n.statusVal : null;
var node = this; var node = this;
var levels = {
off: 1,
fatal: 10,
error: 20,
warn: 30,
info: 40,
debug: 50,
trace: 60,
audit: 98,
metric: 99
};
var colors = {
"0": "grey",
"10": "grey",
"20": "red",
"30": "yellow",
"40": "grey",
"50": "green",
"60": "blue"
};
var preparedEditExpression = null; var preparedEditExpression = null;
var preparedStatExpression = null;
if (editExpression) { if (editExpression) {
try { try {
preparedEditExpression = RED.util.prepareJSONataExpression(editExpression, this); preparedEditExpression = RED.util.prepareJSONataExpression(editExpression, this);
@ -54,16 +38,22 @@ module.exports = function(RED) {
return; return;
} }
} }
if (statExpression) {
try {
preparedStatExpression = RED.util.prepareJSONataExpression(statExpression, this);
}
catch (e) {
node.error(RED._("debug.invalid-exp", {error: editExpression}));
return;
}
}
function prepareValue(msg, done) { function prepareValue(msg, done) {
// Either apply the jsonata expression or... // Either apply the jsonata expression or...
if (preparedEditExpression) { if (preparedEditExpression) {
RED.util.evaluateJSONataExpression(preparedEditExpression, msg, (err, value) => { RED.util.evaluateJSONataExpression(preparedEditExpression, msg, (err, value) => {
if (err) { if (err) { done(RED._("debug.invalid-exp", {error: editExpression})); }
done(RED._("debug.invalid-exp", {error: editExpression})); else { done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:value}); }
} else {
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:value});
}
}); });
} else { } else {
// Extract the required message property // Extract the required message property
@ -71,17 +61,67 @@ module.exports = function(RED) {
var output = msg[property]; var output = msg[property];
if (node.complete !== "false" && typeof node.complete !== "undefined") { if (node.complete !== "false" && typeof node.complete !== "undefined") {
property = node.complete; property = node.complete;
try { try { output = RED.util.getMessageProperty(msg,node.complete); }
output = RED.util.getMessageProperty(msg,node.complete); catch(err) { output = undefined; }
} catch(err) {
output = undefined;
}
} }
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, property:property, msg:output}); done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, property:property, msg:output});
} }
} }
function prepareStatus(msg, done) {
if (node.statusType === "auto") {
if (node.complete === "true") {
done(null,{msg:msg.payload});
}
else {
prepareValue(msg,function(err,debugMsg) {
if (err) { node.error(err); return; }
done(null,{msg:debugMsg.msg});
});
}
}
else {
// Either apply the jsonata expression or...
if (preparedStatExpression) {
RED.util.evaluateJSONataExpression(preparedStatExpression, msg, (err, value) => {
if (err) { done(RED._("debug.invalid-exp", {error:editExpression})); }
else { done(null,{msg:value}); }
});
}
else {
// Extract the required message property
var output;
try { output = RED.util.getMessageProperty(msg,node.statusVal); }
catch(err) { output = undefined; }
done(null,{msg:output});
}
}
}
this.on("input", function(msg, send, done) { this.on("input", function(msg, send, done) {
if (node.tostatus === true) {
prepareStatus(msg, function(err,debugMsg) {
if (err) { node.error(err); return; }
var output = debugMsg.msg;
var st = (typeof output === 'string') ? output : util.inspect(output);
var fill = "grey";
var shape = "dot";
if (node.statusType === "auto") {
if (msg.hasOwnProperty("error")) {
fill = "red";
st = msg.error.message;
}
if (msg.hasOwnProperty("status")) {
if (msg.status.hasOwnProperty("fill")) { fill = msg.status.fill; }
if (msg.status.hasOwnProperty("shape")) { shape = msg.status.shape; }
if (msg.status.hasOwnProperty("text")) { st = msg.status.text; }
}
}
if (st.length > 32) { st = st.substr(0,32) + "..."; }
node.status({fill:fill, shape:shape, text:st});
});
}
if (this.complete === "true") { if (this.complete === "true") {
// debug complete msg object // debug complete msg object
if (this.console === "true") { if (this.console === "true") {
@ -91,7 +131,8 @@ module.exports = function(RED) {
sendDebug({id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:msg}); sendDebug({id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:msg});
} }
done(); done();
} else { }
else {
prepareValue(msg,function(err,debugMsg) { prepareValue(msg,function(err,debugMsg) {
if (err) { if (err) {
node.error(err); node.error(err);
@ -107,12 +148,6 @@ module.exports = function(RED) {
node.log(util.inspect(output, {colors:useColors})); node.log(util.inspect(output, {colors:useColors}));
} }
} }
if (node.tostatus === true) {
var st = (typeof output === 'string')?output:util.inspect(output);
var severity = node.severity;
if (st.length > 32) { st = st.substr(0,32) + "..."; }
node.status({fill:colors[severity], shape:"dot", text:st});
}
if (node.active) { if (node.active) {
if (node.tosidebar == true) { if (node.tosidebar == true) {
sendDebug(debugMsg); sendDebug(debugMsg);
@ -150,24 +185,49 @@ module.exports = function(RED) {
}); });
RED.log.addHandler(DebugNode.logHandler); RED.log.addHandler(DebugNode.logHandler);
RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) { function setNodeState(node,state) {
var node = RED.nodes.getNode(req.params.id); if (state) {
var state = req.params.state; node.active = true;
if (node !== null && typeof node !== "undefined" ) { if (node.tostatus) { node.status({fill:"grey", shape:"dot"}); }
if (state === "enable") { } else {
node.active = true; node.active = false;
res.sendStatus(200); if (node.tostatus && node.hasOwnProperty("oldStatus")) {
if (node.tostatus) { node.status({fill:"grey", shape:"dot"}); } node.oldStatus.shape = "dot";
} else if (state === "disable") { node.status(node.oldStatus);
node.active = false;
res.sendStatus(201);
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
node.oldStatus.shape = "dot";
node.status(node.oldStatus);
}
} else {
res.sendStatus(404);
} }
}
}
RED.httpAdmin.post("/debug/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var state = req.params.state;
if (state !== 'enable' && state !== 'disable') {
res.sendStatus(404);
return;
}
var nodes = req.body && req.body.nodes;
if (Array.isArray(nodes)) {
nodes.forEach(function(id) {
var node = RED.nodes.getNode(id);
if (node !== null && typeof node !== "undefined" ) {
setNodeState(node, state === "enable");
}
})
res.sendStatus(state === "enable" ? 200 : 201);
} else {
res.sendStatus(400);
}
})
RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var state = req.params.state;
if (state !== 'enable' && state !== 'disable') {
res.sendStatus(404);
return;
}
var node = RED.nodes.getNode(req.params.id);
if (node !== null && typeof node !== "undefined" ) {
setNodeState(node,state === "enable");
res.sendStatus(state === "enable" ? 200 : 201);
} else { } else {
res.sendStatus(404); res.sendStatus(404);
} }

View File

@ -89,7 +89,8 @@
node: n, node: n,
label: label, label: label,
sublabel: sublabel, sublabel: sublabel,
selected: isChecked selected: isChecked,
checkbox: true
}; };
items.push(nodeItemMap[n.id]); items.push(nodeItemMap[n.id]);
}); });

View File

@ -104,7 +104,8 @@
node: n, node: n,
label: label, label: label,
sublabel: sublabel, sublabel: sublabel,
selected: isChecked selected: isChecked,
checkbox: true
}; };
items.push(nodeItemMap[n.id]); items.push(nodeItemMap[n.id]);
}); });

View File

@ -92,7 +92,8 @@
node: n, node: n,
label: label, label: label,
sublabel: sublabel, sublabel: sublabel,
selected: isChecked selected: isChecked,
checkbox: true
}; };
items.push(nodeItemMap[n.id]); items.push(nodeItemMap[n.id]);
}); });

View File

@ -83,7 +83,8 @@
id: n.id, id: n.id,
node: n, node: n,
label: n.name||n.id, label: n.name||n.id,
selected: isChecked selected: isChecked,
checkbox: true
}) })
} }
}); });

View File

@ -457,7 +457,7 @@ RED.debug = (function() {
var metaRow = $('<div class="red-ui-debug-msg-meta"></div>').appendTo(msg); var metaRow = $('<div class="red-ui-debug-msg-meta"></div>').appendTo(msg);
$('<span class="red-ui-debug-msg-date">'+ getTimestamp()+'</span>').appendTo(metaRow); $('<span class="red-ui-debug-msg-date">'+ getTimestamp()+'</span>').appendTo(metaRow);
if (sourceNode) { if (sourceNode) {
$('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text('node: '+sanitize(o.name||sourceNode.name||sourceNode.id)) $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text('node: '+(o.name||sourceNode.name||sourceNode.id))
.appendTo(metaRow) .appendTo(metaRow)
.on("click", function(evt) { .on("click", function(evt) {
evt.preventDefault(); evt.preventDefault();

View File

@ -4,19 +4,54 @@
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div> <div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div>
</div> </div>
<div class="form-row" style="margin-bottom: 0px;">
<label for="node-input-func"><i class="fa fa-wrench"></i> <span data-i18n="function.label.function"></span></label> <div class="form-row">
<input type="hidden" id="node-input-func" autofocus="autofocus"> <ul style="min-width: 600px; margin-bottom: 20px;" id="func-tabs"></ul>
<input type="hidden" id="node-input-noerr">
</div> </div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="position: absolute; right:0; bottom:calc(100% + 3px);"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div> <div id="func-tabs-content" style="min-height: calc(100% - 95px);">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
</div> <div id="func-tab-init" style="display:none">
<div class="form-row" style="margin-bottom: 0px"> <div class="form-row" style="margin-bottom: 0px;">
<label for="node-input-outputs"><i class="fa fa-random"></i> <span data-i18n="function.label.outputs"></span></label> <input type="hidden" id="node-input-initialize" autofocus="autofocus">
<input id="node-input-outputs" style="width: 60px;" value="1"> </div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 250px; min-height:150px; margin-top: 30px;" class="node-text-editor" id="node-input-init-editor" ></div>
</div>
</div>
<div id="func-tab-body" style="display:none">
<div class="form-row" style="margin-bottom: 0px;">
<input type="hidden" id="node-input-func" autofocus="autofocus">
<input type="hidden" id="node-input-noerr">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 220px; min-height:120px; margin-top: 30px;" class="node-text-editor" id="node-input-func-editor" ></div>
</div>
<div class="form-row" style="margin-bottom: 0px">
<label for="node-input-outputs"><i class="fa fa-random"></i> <span data-i18n="function.label.outputs"></span></label>
<input id="node-input-outputs" style="width: 60px;" value="1">
</div>
</div>
<div id="func-tab-finalize" style="display:none">
<div class="form-row" style="margin-bottom: 0px;">
<input type="hidden" id="node-input-finalize" autofocus="autofocus">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 250px; min-height:150px; margin-top: 30px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
</div>
</div>
</div> </div>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
@ -27,7 +62,9 @@
name: {value:""}, name: {value:""},
func: {value:"\nreturn msg;"}, func: {value:"\nreturn msg;"},
outputs: {value:1}, outputs: {value:1},
noerr: {value:0,required:true,validate:function(v) { return !v; }} noerr: {value:0,required:true,validate:function(v) { return !v; }},
initialize: {value:""},
finalize: {value:""}
}, },
inputs:1, inputs:1,
outputs:1, outputs:1,
@ -40,6 +77,28 @@
}, },
oneditprepare: function() { oneditprepare: function() {
var that = this; var that = this;
var tabs = RED.tabs.create({
id: "func-tabs",
onchange: function(tab) {
$("#func-tabs-content").children().hide();
$("#" + tab.id).show();
}
});
tabs.addTab({
id: "func-tab-init",
label: that._("function.label.initialize")
});
tabs.addTab({
id: "func-tab-body",
label: that._("function.label.function")
});
tabs.addTab({
id: "func-tab-finalize",
label: that._("function.label.finalize")
});
tabs.activateTab("func-tab-body");
$( "#node-input-outputs" ).spinner({ $( "#node-input-outputs" ).spinner({
min:0, min:0,
change: function(event, ui) { change: function(event, ui) {
@ -50,74 +109,145 @@
} }
}); });
this.editor = RED.editor.createEditor({ var buildEditor = function(id, value, defaultValue) {
id: 'node-input-func-editor', var editor = RED.editor.createEditor({
mode: 'ace/mode/nrjavascript', id: id,
value: $("#node-input-func").val(), mode: 'ace/mode/nrjavascript',
globals: { value: value || defaultValue || "",
msg:true, globals: {
context:true, msg:true,
RED: true, context:true,
util: true, RED: true,
flow: true, util: true,
global: true, flow: true,
console: true, global: true,
Buffer: true, console: true,
setTimeout: true, Buffer: true,
clearTimeout: true, setTimeout: true,
setInterval: true, clearTimeout: true,
clearInterval: true setInterval: true,
clearInterval: true
}
});
if (defaultValue && value === "") {
editor.moveCursorTo(defaultValue.split("\n").length - 1, 0);
} }
}); return editor;
}
this.initEditor = buildEditor('node-input-init-editor',$("#node-input-initialize").val(),RED._("node-red:function.text.initialize"))
this.editor = buildEditor('node-input-func-editor',$("#node-input-func").val())
this.finalizeEditor = buildEditor('node-input-finalize-editor',$("#node-input-finalize").val(),RED._("node-red:function.text.finalize"))
RED.library.create({ RED.library.create({
url:"functions", // where to get the data from url:"functions", // where to get the data from
type:"function", // the type of object the library is for type:"function", // the type of object the library is for
editor:this.editor, // the field name the main text body goes to editor:this.editor, // the field name the main text body goes to
mode:"ace/mode/nrjavascript", mode:"ace/mode/nrjavascript",
fields:['name','outputs'], fields:[
'name', 'outputs',
{
name: 'initialize',
get: function() {
return that.initEditor.getValue();
},
set: function(v) {
that.initEditor.setValue(v||RED._("node-red:function.text.initialize"), -1);
}
},
{
name: 'finalize',
get: function() {
return that.finalizeEditor.getValue();
},
set: function(v) {
that.finalizeEditor.setValue(v||RED._("node-red:function.text.finalize"), -1);
}
},
{
name: 'info',
get: function() {
return that.infoEditor.getValue();
},
set: function(v) {
that.infoEditor.setValue(v||"", -1);
}
}
],
ext:"js" ext:"js"
}); });
this.editor.focus(); this.editor.focus();
RED.popover.tooltip($("#node-function-expand-js"), RED._("node-red:common.label.expand"));
$("#node-function-expand-js").on("click", function(e) { var expandButtonClickHandler = function(editor) {
e.preventDefault(); return function(e) {
var value = that.editor.getValue(); e.preventDefault();
RED.editor.editJavaScript({ var value = editor.getValue();
value: value, RED.editor.editJavaScript({
width: "Infinity", value: value,
cursor: that.editor.getCursorPosition(), width: "Infinity",
mode: "ace/mode/nrjavascript", cursor: editor.getCursorPosition(),
complete: function(v,cursor) { mode: "ace/mode/nrjavascript",
that.editor.setValue(v, -1); complete: function(v,cursor) {
that.editor.gotoLine(cursor.row+1,cursor.column,false); editor.setValue(v, -1);
setTimeout(function() { editor.gotoLine(cursor.row+1,cursor.column,false);
that.editor.focus(); setTimeout(function() {
},300); editor.focus();
} },300);
}) }
}) })
},
oneditsave: function() {
var annot = this.editor.getSession().getAnnotations();
this.noerr = 0;
$("#node-input-noerr").val(0);
for (var k=0; k < annot.length; k++) {
//console.log(annot[k].type,":",annot[k].text, "on line", annot[k].row);
if (annot[k].type === "error") {
$("#node-input-noerr").val(annot.length);
this.noerr = annot.length;
} }
} }
$("#node-input-func").val(this.editor.getValue()); $("#node-init-expand-js").on("click", expandButtonClickHandler(this.initEditor));
this.editor.destroy(); $("#node-function-expand-js").on("click", expandButtonClickHandler(this.editor));
delete this.editor; $("#node-finalize-expand-js").on("click", expandButtonClickHandler(this.finalizeEditor));
RED.popover.tooltip($("#node-init-expand-js"), RED._("node-red:common.label.expand"));
RED.popover.tooltip($("#node-function-expand-js"), RED._("node-red:common.label.expand"));
RED.popover.tooltip($("#node-finalize-expand-js"), RED._("node-red:common.label.expand"));
},
oneditsave: function() {
var node = this;
var noerr = 0;
$("#node-input-noerr").val(0);
var disposeEditor = function(editorName,targetName,defaultValue) {
var editor = node[editorName];
var annot = editor.getSession().getAnnotations();
for (var k=0; k < annot.length; k++) {
if (annot[k].type === "error") {
noerr += annot.length;
break;
}
}
var val = editor.getValue();
if (defaultValue && val == defaultValue) {
val = "";
}
editor.destroy();
delete node[editorName];
$("#"+targetName).val(val);
}
disposeEditor("editor","node-input-func");
disposeEditor("initEditor","node-input-initialize", RED._("node-red:function.text.initialize"));
disposeEditor("finalizeEditor","node-input-finalize", RED._("node-red:function.text.finalize"));
$("#node-input-noerr").val(noerr);
this.noerr = noerr;
}, },
oneditcancel: function() { oneditcancel: function() {
this.editor.destroy(); var node = this;
delete this.editor;
node.editor.destroy();
delete node.editor;
node.initEditor.destroy();
delete node.initEditor;
node.finalizeEditor.destroy();
delete node.finalizeEditor;
}, },
oneditresize: function(size) { oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)"); var rows = $("#dialog-form>div:not(.node-text-editor-row)");
@ -129,6 +259,16 @@
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom"))); height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px"); $(".node-text-editor").css("height",height+"px");
this.editor.resize(); this.editor.resize();
var height = size.height;
$("#node-input-init-editor").css("height", (height -105)+"px");
$("#node-input-func-editor").css("height", (height -145)+"px");
$("#node-input-finalize-editor").css("height", (height -105)+"px");
this.initEditor.resize();
this.editor.resize();
this.finalizeEditor.resize();
} }
}); });
</script> </script>

View File

@ -57,22 +57,55 @@ module.exports = function(RED) {
} }
} }
function createVMOpt(node, kind) {
var opt = {
filename: 'Function node'+kind+':'+node.id+(node.name?' ['+node.name+']':''), // filename for stack traces
displayErrors: true
// Using the following options causes node 4/6 to not include the line number
// in the stack output. So don't use them.
// lineOffset: -11, // line number offset to be used for stack traces
// columnOffset: 0, // column number offset to be used for stack traces
};
return opt;
}
function updateErrorInfo(err) {
if (err.stack) {
var stack = err.stack.toString();
var m = /^([^:]+):([^:]+):(\d+).*/.exec(stack);
if (m) {
var line = parseInt(m[3]) -1;
var kind = "body:";
if (/setup/.exec(m[1])) {
kind = "setup:";
}
if (/cleanup/.exec(m[1])) {
kind = "cleanup:";
}
err.message += " ("+kind+"line "+line+")";
}
}
}
function FunctionNode(n) { function FunctionNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
var node = this; var node = this;
this.name = n.name; node.name = n.name;
this.func = n.func; node.func = n.func;
node.ini = n.initialize ? n.initialize : "";
node.fin = n.finalize ? n.finalize : "";
var handleNodeDoneCall = true; var handleNodeDoneCall = true;
// Check to see if the Function appears to call `node.done()`. If so, // Check to see if the Function appears to call `node.done()`. If so,
// we will assume it is well written and does actually call node.done(). // we will assume it is well written and does actually call node.done().
// Otherwise, we will call node.done() after the function returns regardless. // Otherwise, we will call node.done() after the function returns regardless.
if (/node\.done\s*\(\s*\)/.test(this.func)) { if (/node\.done\s*\(\s*\)/.test(node.func)) {
handleNodeDoneCall = false; handleNodeDoneCall = false;
} }
var functionText = "var results = null;"+ var functionText = "var results = null;"+
"results = (function(msg,__send__,__done__){ "+ "results = (async function(msg,__send__,__done__){ "+
"var __msgid__ = msg._msgid;"+ "var __msgid__ = msg._msgid;"+
"var node = {"+ "var node = {"+
"id:__node__.id,"+ "id:__node__.id,"+
@ -87,11 +120,13 @@ module.exports = function(RED) {
"send:function(msgs,cloneMsg){ __node__.send(__send__,__msgid__,msgs,cloneMsg);},"+ "send:function(msgs,cloneMsg){ __node__.send(__send__,__msgid__,msgs,cloneMsg);},"+
"done:__done__"+ "done:__done__"+
"};\n"+ "};\n"+
this.func+"\n"+ node.func+"\n"+
"})(msg,send,done);"; "})(msg,send,done);";
this.topic = n.topic; var finScript = null;
this.outstandingTimers = []; var finOpt = null;
this.outstandingIntervals = []; node.topic = n.topic;
node.outstandingTimers = [];
node.outstandingIntervals = [];
var sandbox = { var sandbox = {
console:console, console:console,
util:util, util:util,
@ -182,12 +217,12 @@ module.exports = function(RED) {
arguments[0] = function() { arguments[0] = function() {
sandbox.clearTimeout(timerId); sandbox.clearTimeout(timerId);
try { try {
func.apply(this,arguments); func.apply(node,arguments);
} catch(err) { } catch(err) {
node.error(err,{}); node.error(err,{});
} }
}; };
timerId = setTimeout.apply(this,arguments); timerId = setTimeout.apply(node,arguments);
node.outstandingTimers.push(timerId); node.outstandingTimers.push(timerId);
return timerId; return timerId;
}, },
@ -203,12 +238,12 @@ module.exports = function(RED) {
var timerId; var timerId;
arguments[0] = function() { arguments[0] = function() {
try { try {
func.apply(this,arguments); func.apply(node,arguments);
} catch(err) { } catch(err) {
node.error(err,{}); node.error(err,{});
} }
}; };
timerId = setInterval.apply(this,arguments); timerId = setInterval.apply(node,arguments);
node.outstandingIntervals.push(timerId); node.outstandingIntervals.push(timerId);
return timerId; return timerId;
}, },
@ -226,37 +261,48 @@ module.exports = function(RED) {
sandbox.setTimeout(function(){ resolve(value); }, after); sandbox.setTimeout(function(){ resolve(value); }, after);
}); });
}; };
sandbox.promisify = util.promisify;
} }
var context = vm.createContext(sandbox); var context = vm.createContext(sandbox);
try { try {
this.script = vm.createScript(functionText, { var iniScript = null;
filename: 'Function node:'+this.id+(this.name?' ['+this.name+']':''), // filename for stack traces var iniOpt = null;
displayErrors: true if (node.ini && (node.ini !== "")) {
// Using the following options causes node 4/6 to not include the line number var iniText = "(async function () {\n"+node.ini +"\n})();";
// in the stack output. So don't use them. iniOpt = createVMOpt(node, " setup");
// lineOffset: -11, // line number offset to be used for stack traces iniScript = new vm.Script(iniText, iniOpt);
// columnOffset: 0, // column number offset to be used for stack traces }
}); node.script = vm.createScript(functionText, createVMOpt(node, ""));
this.on("input", function(msg,send,done) { if (node.fin && (node.fin !== "")) {
try { var finText = "(function () {\n"+node.fin +"\n})();";
var start = process.hrtime(); finOpt = createVMOpt(node, " cleanup");
context.msg = msg; finScript = new vm.Script(finText, finOpt);
context.send = send; }
context.done = done; var promise = Promise.resolve();
if (iniScript) {
promise = iniScript.runInContext(context, iniOpt);
}
this.script.runInContext(context); function processMessage(msg, send, done) {
sendResults(this,send,msg._msgid,context.results,false); var start = process.hrtime();
context.msg = msg;
context.send = send;
context.done = done;
node.script.runInContext(context);
context.results.then(function(results) {
sendResults(node,send,msg._msgid,results,false);
if (handleNodeDoneCall) { if (handleNodeDoneCall) {
done(); done();
} }
var duration = process.hrtime(start); var duration = process.hrtime(start);
var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100; var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100;
this.metric("duration", msg, converted); node.metric("duration", msg, converted);
if (process.env.NODE_RED_FUNCTION_TIME) { if (process.env.NODE_RED_FUNCTION_TIME) {
this.status({fill:"yellow",shape:"dot",text:""+converted}); node.status({fill:"yellow",shape:"dot",text:""+converted});
} }
} catch(err) { }).catch(err => {
if ((typeof err === "object") && err.hasOwnProperty("stack")) { if ((typeof err === "object") && err.hasOwnProperty("stack")) {
//remove unwanted part //remove unwanted part
var index = err.stack.search(/\n\s*at ContextifyScript.Script.runInContext/); var index = err.stack.search(/\n\s*at ContextifyScript.Script.runInContext/);
@ -294,23 +340,67 @@ module.exports = function(RED) {
else { else {
done(JSON.stringify(err)); done(JSON.stringify(err));
} }
});
}
const RESOLVING = 0;
const RESOLVED = 1;
const ERROR = 2;
var state = RESOLVING;
var messages = [];
node.on("input", function(msg,send,done) {
if(state === RESOLVING) {
messages.push({msg:msg, send:send, done:done});
}
else if(state === RESOLVED) {
processMessage(msg, send, done);
} }
}); });
this.on("close", function() { node.on("close", function() {
if (finScript) {
try {
finScript.runInContext(context, finOpt);
}
catch (err) {
node.error(err);
}
}
while (node.outstandingTimers.length > 0) { while (node.outstandingTimers.length > 0) {
clearTimeout(node.outstandingTimers.pop()); clearTimeout(node.outstandingTimers.pop());
} }
while (node.outstandingIntervals.length > 0) { while (node.outstandingIntervals.length > 0) {
clearInterval(node.outstandingIntervals.pop()); clearInterval(node.outstandingIntervals.pop());
} }
this.status({}); node.status({});
}); });
} catch(err) {
promise.then(function (v) {
var msgs = messages;
messages = [];
while (msgs.length > 0) {
msgs.forEach(function (s) {
processMessage(s.msg, s.send, s.done);
});
msgs = messages;
messages = [];
}
state = RESOLVED;
}).catch((error) => {
messages = [];
state = ERROR;
node.error(error);
});
}
catch(err) {
// eg SyntaxError - which v8 doesn't include line number information // eg SyntaxError - which v8 doesn't include line number information
// so we can't do better than this // so we can't do better than this
this.error(err); updateErrorInfo(err);
node.error(err);
} }
} }
RED.nodes.registerType("function",FunctionNode); RED.nodes.registerType("function",FunctionNode);
RED.library.register("functions"); RED.library.register("functions");
}; };

View File

@ -1,5 +1,10 @@
<script type="text/html" data-template-name="change"> <script type="text/html" data-template-name="change">
<style>
ol#node-input-rule-container .red-ui-typedInput-container {
flex:1;
}
</style>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"> <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
@ -76,11 +81,6 @@
var replace = this._("change.action.replace"); var replace = this._("change.action.replace");
var regex = this._("change.label.regex"); var regex = this._("change.label.regex");
function resizeRule(rule) {
var newWidth = rule.width();
rule.find('.red-ui-typedInput').typedInput("width",newWidth-130);
}
$('#node-input-rule-container').css('min-height','150px').css('min-width','450px').editableList({ $('#node-input-rule-container').css('min-height','150px').css('min-width','450px').editableList({
addItem: function(container,i,opt) { addItem: function(container,i,opt) {
var rule = opt; var rule = opt;
@ -106,10 +106,11 @@
overflow: 'hidden', overflow: 'hidden',
whiteSpace: 'nowrap' whiteSpace: 'nowrap'
}); });
var row1 = $('<div/>').appendTo(container); let fragment = document.createDocumentFragment();
var row2 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container); var row1 = $('<div/>',{style:"display:flex;"}).appendTo(fragment);
var row3 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container); var row2 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(fragment);
var row4 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container); var row3 = $('<div/>',{style:"margin-top:8px;"}).appendTo(fragment);
var row4 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(fragment);
var selectField = $('<select/>',{class:"node-input-rule-type",style:"width:110px; margin-right:10px;"}).appendTo(row1); var selectField = $('<select/>',{class:"node-input-rule-type",style:"width:110px; margin-right:10px;"}).appendTo(row1);
var selectOptions = [{v:"set",l:set},{v:"change",l:change},{v:"delete",l:del},{v:"move",l:move}]; var selectOptions = [{v:"set",l:set},{v:"change",l:change},{v:"delete",l:del},{v:"move",l:move}];
@ -124,41 +125,82 @@
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"}) $('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(to) .text(to)
.appendTo(row2); .appendTo(row2);
var propertyValue = $('<input/>',{class:"node-input-rule-property-value",type:"text"})
function createPropertyValue() {
return $('<input/>',{class:"node-input-rule-property-value",type:"text"})
.appendTo(row2) .appendTo(row2)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']}); .typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
}
var row3_1 = $('<div/>').appendTo(row3); var row3_1 = $('<div/>', {style:"display:flex;"}).appendTo(row3);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"}) $('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(search) .text(search)
.appendTo(row3_1); .appendTo(row3_1);
var fromValue = $('<input/>',{class:"node-input-rule-property-search-value",type:"text"})
function createFromValue() {
return $('<input/>',{class:"node-input-rule-property-search-value",type:"text"})
.appendTo(row3_1) .appendTo(row3_1)
.typedInput({default:'str',types:['msg','flow','global','str','re','num','bool','env']}); .typedInput({default:'str',types:['msg','flow','global','str','re','num','bool','env']});
}
var row3_2 = $('<div/>',{style:"margin-top:8px;"}).appendTo(row3); var row3_2 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(row3);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"}) $('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(replace) .text(replace)
.appendTo(row3_2); .appendTo(row3_2);
var toValue = $('<input/>',{class:"node-input-rule-property-replace-value",type:"text"})
function createToValue() {
return $('<input/>',{class:"node-input-rule-property-replace-value",type:"text"})
.appendTo(row3_2) .appendTo(row3_2)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','env']}); .typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','env']});
}
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"}) $('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(to) .text(to)
.appendTo(row4); .appendTo(row4);
var moveValue = $('<input/>',{class:"node-input-rule-property-move-value",type:"text"})
function createMoveValue() {
return $('<input/>',{class:"node-input-rule-property-move-value",type:"text"})
.appendTo(row4) .appendTo(row4)
.typedInput({default:'msg',types:['msg','flow','global']}); .typedInput({default:'msg',types:['msg','flow','global']});
}
let propertyValue = null;
let fromValue = null;
let toValue = null;
let moveValue = null;
selectField.on("change", function() { selectField.on("change", function() {
var width = $("#node-input-rule-container").width();
var type = $(this).val(); var type = $(this).val();
if (propertyValue) {
propertyValue.typedInput('hide');
}
if (fromValue) {
fromValue.typedInput('hide');
}
if (toValue) {
toValue.typedInput('hide');
}
if (moveValue) {
moveValue.typedInput('hide');
}
if (type == "set") { if (type == "set") {
if(!propertyValue) {
propertyValue = createPropertyValue();
}
propertyValue.typedInput('show');
row2.show(); row2.show();
row3.hide(); row3.hide();
row4.hide(); row4.hide();
} else if (type == "change") { } else if (type == "change") {
if(!fromValue) {
fromValue = createFromValue();
}
fromValue.typedInput('show');
if(!toValue) {
toValue = createToValue();
}
toValue.typedInput('show');
row2.hide(); row2.hide();
row3.show(); row3.show();
row4.hide(); row4.hide();
@ -167,30 +209,48 @@
row3.hide(); row3.hide();
row4.hide(); row4.hide();
} else if (type == "move") { } else if (type == "move") {
if(!moveValue) {
moveValue = createMoveValue();
}
moveValue.typedInput('show');
row2.hide(); row2.hide();
row3.hide(); row3.hide();
row4.show(); row4.show();
} }
resizeRule(container);
}); });
selectField.val(rule.t); selectField.val(rule.t);
propertyName.typedInput('value',rule.p); propertyName.typedInput('value',rule.p);
propertyName.typedInput('type',rule.pt); propertyName.typedInput('type',rule.pt);
propertyValue.typedInput('value',rule.to); if (rule.t == "set") {
propertyValue.typedInput('type',rule.tot); if(!propertyValue) {
moveValue.typedInput('value',rule.to); propertyValue = createPropertyValue();
moveValue.typedInput('type',rule.tot); }
fromValue.typedInput('value',rule.from); propertyValue.typedInput('value',rule.to);
fromValue.typedInput('type',rule.fromt); propertyValue.typedInput('type',rule.tot);
toValue.typedInput('value',rule.to); }
toValue.typedInput('type',rule.tot); if (rule.t == "move") {
if(!moveValue) {
moveValue = createMoveValue();
}
moveValue.typedInput('value',rule.to);
moveValue.typedInput('type',rule.tot);
}
if (rule.t == "change") {
if(!fromValue) {
fromValue = createFromValue();
}
fromValue.typedInput('value',rule.from);
fromValue.typedInput('type',rule.fromt);
if (!toValue) {
toValue = createToValue();
}
toValue.typedInput('value',rule.to);
toValue.typedInput('type',rule.tot);
}
selectField.change(); selectField.change();
container[0].appendChild(fragment);
var newWidth = $("#node-input-rule-container").width();
resizeRule(container);
}, },
resizeItem: resizeRule,
removable: true, removable: true,
sortable: true sortable: true
}); });

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