diff --git a/Gruntfile.js b/Gruntfile.js index 3738e60b4..faf68f100 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -144,10 +144,12 @@ module.exports = function(grunt) { "editor/js/ui/keyboard.js", "editor/js/ui/workspaces.js", "editor/js/ui/view.js", + "editor/js/ui/view-navigator.js", "editor/js/ui/sidebar.js", "editor/js/ui/palette.js", "editor/js/ui/tab-info.js", "editor/js/ui/tab-config.js", + "editor/js/ui/tab-context.js", "editor/js/ui/palette-editor.js", "editor/js/ui/editor.js", "editor/js/ui/tray.js", diff --git a/editor/icons/file-in.png b/editor/icons/file-in.png new file mode 100644 index 000000000..d3e5cd7fe Binary files /dev/null and b/editor/icons/file-in.png differ diff --git a/editor/icons/file-out.png b/editor/icons/file-out.png new file mode 100644 index 000000000..051f819c8 Binary files /dev/null and b/editor/icons/file-out.png differ diff --git a/editor/images/typedInput/env.png b/editor/images/typedInput/env.png new file mode 100644 index 000000000..0ea51da00 Binary files /dev/null and b/editor/images/typedInput/env.png differ diff --git a/editor/js/keymap.json b/editor/js/keymap.json index 08f83b4a5..dc37232e2 100644 --- a/editor/js/keymap.json +++ b/editor/js/keymap.json @@ -10,6 +10,7 @@ "ctrl-g i": "core:show-info-tab", "ctrl-g d": "core:show-debug-tab", "ctrl-g c": "core:show-config-tab", + "ctrl-g x": "core:show-context-tab", "ctrl-e": "core:show-export-dialog", "ctrl-i": "core:show-import-dialog", "ctrl-space": "core:toggle-sidebar", diff --git a/editor/js/main.js b/editor/js/main.js index cf295e7e7..80e0a692f 100644 --- a/editor/js/main.js +++ b/editor/js/main.js @@ -153,13 +153,13 @@ loadFlows(function() { var project = RED.projects.getActiveProject(); var message = { - "change-branch":"Change to local branch '"+project.git.branches.local+"'", - "merge-abort":"Git merge aborted", - "loaded":"Project '"+msg.project+"' loaded", - "updated":"Project '"+msg.project+"' updated", - "pull":"Project '"+msg.project+"' reloaded", - "revert": "Project '"+msg.project+"' reloaded", - "merge-complete":"Git merge completed" + "change-branch": RED._("notification.project.change-branch", {project: project.git.branches.local}), + "merge-abort": RED._("notification.project.merge-abort"), + "loaded": RED._("notification.project.loaded", {project: msg.project}), + "updated": RED._("notification.project.updated", {project: msg.project}), + "pull": RED._("notification.project.pull", {project: msg.project}), + "revert": RED._("notification.project.revert", {project: msg.project}), + "merge-complete": RED._("notification.project.merge-complete") }[msg.action]; RED.notify("
"+message+"
"); RED.sidebar.info.refresh() @@ -183,7 +183,7 @@ if (!!RED.projects.getActiveProject()) { options.buttons = [ { - text: "Manage project dependencies", + text: RED._("notification.label.manage-project-dep"), click: function() { persistentNotifications[notificationId].hideNotification(); RED.projects.settings.show('deps'); @@ -194,7 +194,7 @@ } else { options.buttons = [ { - text: "Close", + text: RED._("common.label.close"), click: function() { persistentNotifications[notificationId].hideNotification(); } @@ -207,7 +207,7 @@ if (RED.user.hasPermission("projects.write")) { options.buttons = [ { - text: "Setup credentials", + text: RED._("notification.label.setup-cred"), click: function() { persistentNotifications[notificationId].hideNotification(); RED.projects.showCredentialsPrompt(); @@ -218,7 +218,7 @@ } else { options.buttons = [ { - text: "Close", + text: RED._("common.label.close"), click: function() { persistentNotifications[notificationId].hideNotification(); } @@ -229,7 +229,7 @@ if (RED.user.hasPermission("projects.write")) { options.buttons = [ { - text: "Setup project files", + text: RED._("notification.label.setup-project"), click: function() { persistentNotifications[notificationId].hideNotification(); RED.projects.showFilesPrompt(); @@ -241,7 +241,7 @@ if (RED.user.hasPermission("projects.write")) { options.buttons = [ { - text: "Create default package file", + text: RED._("notification.label.create-default-package"), click: function() { persistentNotifications[notificationId].hideNotification(); RED.projects.createDefaultPackageFile(); @@ -253,13 +253,13 @@ if (RED.user.hasPermission("projects.write")) { options.buttons = [ { - text: "No thanks", + text: RED._("notification.label.no-thanks"), click: function() { persistentNotifications[notificationId].hideNotification(); } }, { - text: "Create default project files", + text: RED._("notification.label.create-default-project"), click: function() { persistentNotifications[notificationId].hideNotification(); RED.projects.createDefaultFileSet(); @@ -273,7 +273,7 @@ if (RED.user.hasPermission("projects.write")) { options.buttons = [ { - text: "Show merge conflicts", + text: RED._("notification.label.show-merge-conflicts"), click: function() { persistentNotifications[notificationId].hideNotification(); RED.sidebar.versionControl.showLocalChanges(); @@ -382,10 +382,10 @@ function loadEditor() { var menuOptions = []; if (RED.settings.theme("projects.enabled",false)) { - menuOptions.push({id:"menu-item-projects-menu",label:"Projects",options:[ - {id:"menu-item-projects-new",label:"New",disabled:false,onselect:"core:new-project"}, - {id:"menu-item-projects-open",label:"Open",disabled:false,onselect:"core:open-project"}, - {id:"menu-item-projects-settings",label:"Project Settings",disabled:false,onselect:"core:show-project-settings"} + menuOptions.push({id:"menu-item-projects-menu",label:RED._("menu.label.projects"),options:[ + {id:"menu-item-projects-new",label:RED._("menu.label.projects-new"),disabled:false,onselect:"core:new-project"}, + {id:"menu-item-projects-open",label:RED._("menu.label.projects-open"),disabled:false,onselect:"core:open-project"}, + {id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"} ]}); } @@ -410,8 +410,8 @@ {id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"}, {id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]} ]}); - menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[ - {id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:"core:show-export-dialog"}, + menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),options:[ + {id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-export-dialog"}, {id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"} ]}); menuOptions.push(null); diff --git a/editor/js/nodes.js b/editor/js/nodes.js index 433e400a2..12ff3e682 100644 --- a/editor/js/nodes.js +++ b/editor/js/nodes.js @@ -133,7 +133,7 @@ RED.nodes = (function() { registerNodeType: function(nt,def) { nodeDefinitions[nt] = def; def.type = nt; - if (def.category != "subflows") { + if (nt.substring(0,8) != "subflow:") { def.set = nodeSets[typeToId[nt]]; nodeSets[typeToId[nt]].added = true; nodeSets[typeToId[nt]].enabled = true; @@ -356,7 +356,7 @@ RED.nodes = (function() { defaults:{name:{value:""}}, info: sf.info, icon: function() { return sf.icon||"subflow.png" }, - category: "subflows", + category: sf.category || "subflows", inputs: sf.in.length, outputs: sf.out.length, color: "#da9", @@ -519,6 +519,7 @@ RED.nodes = (function() { node.type = n.type; node.name = n.name; node.info = n.info; + node.category = n.category; node.in = []; node.out = []; diff --git a/editor/js/ui/clipboard.js b/editor/js/ui/clipboard.js index 2bdd20052..e4350a464 100644 --- a/editor/js/ui/clipboard.js +++ b/editor/js/ui/clipboard.js @@ -276,9 +276,20 @@ RED.clipboard = (function() { if (typeof value !== "string" ) { value = JSON.stringify(value, function(key,value) { if (value !== null && typeof value === 'object') { - if (value.__encoded__ && value.hasOwnProperty('data') && value.hasOwnProperty('length')) { - truncated = value.data.length !== value.length; - return value.data; + if (value.__encoded__) { + if (value.hasOwnProperty('data') && value.hasOwnProperty('length')) { + truncated = value.data.length !== value.length; + return value.data; + } + if (value.type === 'function' || value.type === 'internal') { + return undefined + } + if (value.type === 'number') { + // Handle NaN and Infinity - they are not permitted + // in JSON. We can either substitute with a String + // representation or null + return null; + } } } return value; @@ -309,18 +320,6 @@ RED.clipboard = (function() { $('').appendTo("body"); - RED.events.on("view:selection-changed",function(selection) { - if (!selection.nodes) { - RED.menu.setDisabled("menu-item-export",true); - RED.menu.setDisabled("menu-item-export-clipboard",true); - RED.menu.setDisabled("menu-item-export-library",true); - } else { - RED.menu.setDisabled("menu-item-export",false); - RED.menu.setDisabled("menu-item-export-clipboard",false); - RED.menu.setDisabled("menu-item-export-library",false); - } - }); - RED.actions.add("core:show-export-dialog",exportNodes); RED.actions.add("core:show-import-dialog",importNodes); diff --git a/editor/js/ui/common/popover.js b/editor/js/ui/common/popover.js index 6a0bc9fdf..4e2a0b0ef 100644 --- a/editor/js/ui/common/popover.js +++ b/editor/js/ui/common/popover.js @@ -19,12 +19,14 @@ RED.popover = (function() { "default": { top: 10, leftRight: 17, - leftLeft: 25 + leftLeft: 25, + leftBottom: 8, }, "small": { top: 5, leftRight: 17, - leftLeft: 16 + leftLeft: 16, + leftBottom: 3, } } function createPopover(options) { @@ -46,29 +48,39 @@ RED.popover = (function() { var openPopup = function(instant) { if (active) { - div = $('').appendTo("body"); + div = $(''); if (size !== "default") { div.addClass("red-ui-popover-size-"+size); } if (typeof content === 'function') { - content.call(res).appendTo(div); + var result = content.call(res); + if (result === null) { + return; + } + if (typeof result === 'string') { + div.text(result); + } else { + div.append(result); + } } else { div.html(content); } if (width !== "auto") { div.width(width); } - + div.appendTo("body"); var targetPos = target.offset(); - var targetWidth = target.width(); - var targetHeight = target.height(); + var targetWidth = target.outerWidth(); + var targetHeight = target.outerHeight(); var divHeight = div.height(); var divWidth = div.width(); if (direction === 'right') { div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight}); } else if (direction === 'left') { div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth}); + } else if (direction === 'bottom') { + div.css({top: targetPos.top+targetHeight+deltaSizes[size].top,left:targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom}); } if (instant) { div.show(); @@ -143,7 +155,17 @@ RED.popover = (function() { } return { - create: createPopover + create: createPopover, + tooltip: function(target,content) { + RED.popover.create({ + target:target, + trigger: "hover", + size: "small", + direction: "bottom", + content: content, + delay: { show: 550, hide: 10 } + }); + } } })(); diff --git a/editor/js/ui/common/tabs.js b/editor/js/ui/common/tabs.js index f66b95421..700618495 100644 --- a/editor/js/ui/common/tabs.js +++ b/editor/js/ui/common/tabs.js @@ -19,8 +19,10 @@ RED.tabs = (function() { function createTabs(options) { var tabs = {}; + var pinnedTabsCount = 0; var currentTabWidth; var currentActiveTabWidth = 0; + var collapsibleMenu; var ul = options.element || $("#"+options.id); var wrapper = ul.wrap( "