mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge branch 'config' into 0.14.0
explain why this merge is necessary,
This commit is contained in:
commit
41445a1b48
@ -120,6 +120,7 @@ module.exports = function(grunt) {
|
|||||||
"editor/js/ui/tab-info.js",
|
"editor/js/ui/tab-info.js",
|
||||||
"editor/js/ui/tab-config.js",
|
"editor/js/ui/tab-config.js",
|
||||||
"editor/js/ui/editor.js",
|
"editor/js/ui/editor.js",
|
||||||
|
"editor/js/ui/tray.js",
|
||||||
"editor/js/ui/clipboard.js",
|
"editor/js/ui/clipboard.js",
|
||||||
"editor/js/ui/library.js",
|
"editor/js/ui/library.js",
|
||||||
"editor/js/ui/notifications.js",
|
"editor/js/ui/notifications.js",
|
||||||
|
@ -273,6 +273,10 @@ RED.history = (function() {
|
|||||||
RED.nodes.addLink(ev.removedLinks[i]);
|
RED.nodes.addLink(ev.removedLinks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (ev.t == "reorder") {
|
||||||
|
if (ev.order) {
|
||||||
|
RED.workspaces.order(ev.order);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Object.keys(modifiedTabs).forEach(function(id) {
|
Object.keys(modifiedTabs).forEach(function(id) {
|
||||||
var subflow = RED.nodes.subflow(id);
|
var subflow = RED.nodes.subflow(id);
|
||||||
|
@ -21,6 +21,7 @@ RED.nodes = (function() {
|
|||||||
var links = [];
|
var links = [];
|
||||||
var defaultWorkspace;
|
var defaultWorkspace;
|
||||||
var workspaces = {};
|
var workspaces = {};
|
||||||
|
var workspacesOrder =[];
|
||||||
var subflows = {};
|
var subflows = {};
|
||||||
|
|
||||||
var dirty = false;
|
var dirty = false;
|
||||||
@ -173,6 +174,7 @@ RED.nodes = (function() {
|
|||||||
if (type && type.category == "config") {
|
if (type && type.category == "config") {
|
||||||
var configNode = configNodes[n[d]];
|
var configNode = configNodes[n[d]];
|
||||||
if (configNode) {
|
if (configNode) {
|
||||||
|
if (configNode.users.indexOf(n) === -1) {
|
||||||
updatedConfigNode = true;
|
updatedConfigNode = true;
|
||||||
configNode.users.push(n);
|
configNode.users.push(n);
|
||||||
}
|
}
|
||||||
@ -180,6 +182,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (updatedConfigNode) {
|
if (updatedConfigNode) {
|
||||||
// TODO: refresh config tab?
|
// TODO: refresh config tab?
|
||||||
}
|
}
|
||||||
@ -269,12 +272,15 @@ RED.nodes = (function() {
|
|||||||
|
|
||||||
function addWorkspace(ws) {
|
function addWorkspace(ws) {
|
||||||
workspaces[ws.id] = ws;
|
workspaces[ws.id] = ws;
|
||||||
|
workspacesOrder.push(ws.id);
|
||||||
}
|
}
|
||||||
function getWorkspace(id) {
|
function getWorkspace(id) {
|
||||||
return workspaces[id];
|
return workspaces[id];
|
||||||
}
|
}
|
||||||
function removeWorkspace(id) {
|
function removeWorkspace(id) {
|
||||||
delete workspaces[id];
|
delete workspaces[id];
|
||||||
|
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
|
||||||
|
|
||||||
var removedNodes = [];
|
var removedNodes = [];
|
||||||
var removedLinks = [];
|
var removedLinks = [];
|
||||||
var n;
|
var n;
|
||||||
@ -517,7 +523,7 @@ RED.nodes = (function() {
|
|||||||
if ((exportable == null || exportable)) {
|
if ((exportable == null || exportable)) {
|
||||||
if (!(node[d] in exportedConfigNodes)) {
|
if (!(node[d] in exportedConfigNodes)) {
|
||||||
exportedConfigNodes[node[d]] = true;
|
exportedConfigNodes[node[d]] = true;
|
||||||
nns.unshift(RED.nodes.convertNode(confNode));
|
set.push(confNode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
convertedNode[d] = "";
|
convertedNode[d] = "";
|
||||||
@ -537,11 +543,9 @@ RED.nodes = (function() {
|
|||||||
function createCompleteNodeSet() {
|
function createCompleteNodeSet() {
|
||||||
var nns = [];
|
var nns = [];
|
||||||
var i;
|
var i;
|
||||||
for (i in workspaces) {
|
for (i=0;i<workspacesOrder.length;i++) {
|
||||||
if (workspaces.hasOwnProperty(i)) {
|
if (workspaces[workspacesOrder[i]].type == "tab") {
|
||||||
if (workspaces[i].type == "tab") {
|
nns.push(workspaces[workspacesOrder[i]]);
|
||||||
nns.push(workspaces[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i in subflows) {
|
for (i in subflows) {
|
||||||
@ -663,6 +667,9 @@ RED.nodes = (function() {
|
|||||||
var new_links = [];
|
var new_links = [];
|
||||||
var nid;
|
var nid;
|
||||||
var def;
|
var def;
|
||||||
|
var configNode;
|
||||||
|
|
||||||
|
// Find all tabs and subflow templates
|
||||||
for (i=0;i<newNodes.length;i++) {
|
for (i=0;i<newNodes.length;i++) {
|
||||||
n = newNodes[i];
|
n = newNodes[i];
|
||||||
// TODO: remove workspace in next release+1
|
// TODO: remove workspace in next release+1
|
||||||
@ -706,6 +713,8 @@ RED.nodes = (function() {
|
|||||||
addSubflow(n,createNewIds);
|
addSubflow(n,createNewIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a tab if there isn't one there already
|
||||||
if (defaultWorkspace == null) {
|
if (defaultWorkspace == null) {
|
||||||
defaultWorkspace = { type:"tab", id:getID(), label:RED._('workspace.defaultName',{number:1})};
|
defaultWorkspace = { type:"tab", id:getID(), label:RED._('workspace.defaultName',{number:1})};
|
||||||
addWorkspace(defaultWorkspace);
|
addWorkspace(defaultWorkspace);
|
||||||
@ -714,6 +723,7 @@ RED.nodes = (function() {
|
|||||||
activeWorkspace = RED.workspaces.active();
|
activeWorkspace = RED.workspaces.active();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find all config nodes and add them
|
||||||
for (i=0;i<newNodes.length;i++) {
|
for (i=0;i<newNodes.length;i++) {
|
||||||
n = newNodes[i];
|
n = newNodes[i];
|
||||||
def = registry.getNodeType(n.type);
|
def = registry.getNodeType(n.type);
|
||||||
@ -750,7 +760,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!existingConfigNode) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode._def.exclusive || existingConfigNode.z !== n.z) {
|
if (!existingConfigNode) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode._def.exclusive || existingConfigNode.z !== n.z) {
|
||||||
var configNode = {id:n.id, z:n.z, type:n.type, users:[]};
|
configNode = {id:n.id, z:n.z, type:n.type, users:[]};
|
||||||
for (var d in def.defaults) {
|
for (var d in def.defaults) {
|
||||||
if (def.defaults.hasOwnProperty(d)) {
|
if (def.defaults.hasOwnProperty(d)) {
|
||||||
configNode[d] = n[d];
|
configNode[d] = n[d];
|
||||||
@ -768,6 +778,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find regular flow nodes and subflow instances
|
||||||
for (i=0;i<newNodes.length;i++) {
|
for (i=0;i<newNodes.length;i++) {
|
||||||
n = newNodes[i];
|
n = newNodes[i];
|
||||||
// TODO: remove workspace in next release+1
|
// TODO: remove workspace in next release+1
|
||||||
@ -838,16 +849,8 @@ RED.nodes = (function() {
|
|||||||
node.outputs = n.outputs||node._def.outputs;
|
node.outputs = n.outputs||node._def.outputs;
|
||||||
for (var d2 in node._def.defaults) {
|
for (var d2 in node._def.defaults) {
|
||||||
if (node._def.defaults.hasOwnProperty(d2)) {
|
if (node._def.defaults.hasOwnProperty(d2)) {
|
||||||
if (node._def.defaults[d2].type) {
|
|
||||||
if (node_map[n[d2]]) {
|
|
||||||
node[d2] = node_map[n[d2]].id;
|
|
||||||
} else {
|
|
||||||
node[d2] = n[d2];
|
node[d2] = n[d2];
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
node[d2] = n[d2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -860,6 +863,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remap all wires and config node references
|
||||||
for (i=0;i<new_nodes.length;i++) {
|
for (i=0;i<new_nodes.length;i++) {
|
||||||
n = new_nodes[i];
|
n = new_nodes[i];
|
||||||
if (n.wires) {
|
if (n.wires) {
|
||||||
@ -875,6 +879,19 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
delete n.wires;
|
delete n.wires;
|
||||||
}
|
}
|
||||||
|
for (var d3 in n._def.defaults) {
|
||||||
|
if (n._def.defaults.hasOwnProperty(d3)) {
|
||||||
|
if (n._def.defaults[d3].type && node_map[n[d3]]) {
|
||||||
|
n[d3] = node_map[n[d3]].id;
|
||||||
|
configNode = RED.nodes.node(n[d3]);
|
||||||
|
if (configNode && configNode.users.indexOf(n) === -1) {
|
||||||
|
configNode.users.push(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
for (i=0;i<new_subflows.length;i++) {
|
for (i=0;i<new_subflows.length;i++) {
|
||||||
n = new_subflows[i];
|
n = new_subflows[i];
|
||||||
@ -972,6 +989,8 @@ RED.nodes = (function() {
|
|||||||
|
|
||||||
addWorkspace: addWorkspace,
|
addWorkspace: addWorkspace,
|
||||||
removeWorkspace: removeWorkspace,
|
removeWorkspace: removeWorkspace,
|
||||||
|
getWorkspaceOrder: function() { return workspacesOrder },
|
||||||
|
setWorkspaceOrder: function(order) { workspacesOrder = order; },
|
||||||
workspace: getWorkspace,
|
workspace: getWorkspace,
|
||||||
|
|
||||||
addSubflow: addSubflow,
|
addSubflow: addSubflow,
|
||||||
@ -1004,10 +1023,8 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
eachWorkspace: function(cb) {
|
eachWorkspace: function(cb) {
|
||||||
for (var id in workspaces) {
|
for (var i=0;i<workspacesOrder.length;i++) {
|
||||||
if (workspaces.hasOwnProperty(id)) {
|
cb(workspaces[workspacesOrder[i]]);
|
||||||
cb(workspaces[id]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ RED.clipboard = (function() {
|
|||||||
var importNodesDialog;
|
var importNodesDialog;
|
||||||
|
|
||||||
function setupDialogs() {
|
function setupDialogs() {
|
||||||
dialog = $('<div id="clipboard-dialog" class="hide"><form class="dialog-form form-horizontal"></form></div>')
|
dialog = $('<div id="clipboard-dialog" class="hide node-red-dialog"><form class="dialog-form form-horizontal"></form></div>')
|
||||||
.appendTo("body")
|
.appendTo("body")
|
||||||
.dialog({
|
.dialog({
|
||||||
modal: true,
|
modal: true,
|
||||||
@ -31,14 +31,6 @@ RED.clipboard = (function() {
|
|||||||
width: 500,
|
width: 500,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
|
||||||
id: "clipboard-dialog-ok",
|
|
||||||
text: RED._("common.label.ok"),
|
|
||||||
click: function() {
|
|
||||||
RED.view.importNodes($("#clipboard-import").val());
|
|
||||||
$( this ).dialog( "close" );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "clipboard-dialog-cancel",
|
id: "clipboard-dialog-cancel",
|
||||||
text: RED._("common.label.cancel"),
|
text: RED._("common.label.cancel"),
|
||||||
@ -48,10 +40,20 @@ RED.clipboard = (function() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clipboard-dialog-close",
|
id: "clipboard-dialog-close",
|
||||||
|
class: "primary",
|
||||||
text: RED._("common.label.close"),
|
text: RED._("common.label.close"),
|
||||||
click: function() {
|
click: function() {
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "clipboard-dialog-ok",
|
||||||
|
class: "primary",
|
||||||
|
text: RED._("common.label.import"),
|
||||||
|
click: function() {
|
||||||
|
RED.view.importNodes($("#clipboard-import").val());
|
||||||
|
$( this ).dialog( "close" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
open: function(e) {
|
open: function(e) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -254,7 +254,14 @@ RED.library = (function() {
|
|||||||
height: 450,
|
height: 450,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: RED._("common.label.ok"),
|
text: RED._("common.label.cancel"),
|
||||||
|
click: function() {
|
||||||
|
$( this ).dialog( "close" );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: RED._("common.label.load"),
|
||||||
|
class: "primary",
|
||||||
click: function() {
|
click: function() {
|
||||||
if (selectedLibraryItem) {
|
if (selectedLibraryItem) {
|
||||||
for (var i=0;i<options.fields.length;i++) {
|
for (var i=0;i<options.fields.length;i++) {
|
||||||
@ -265,12 +272,6 @@ RED.library = (function() {
|
|||||||
}
|
}
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
text: RED._("common.label.cancel"),
|
|
||||||
click: function() {
|
|
||||||
$( this ).dialog( "close" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
open: function(e) {
|
open: function(e) {
|
||||||
@ -359,15 +360,16 @@ RED.library = (function() {
|
|||||||
height: 230,
|
height: 230,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: RED._("common.label.ok"),
|
text: RED._("common.label.cancel"),
|
||||||
click: function() {
|
click: function() {
|
||||||
saveToLibrary(true);
|
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: RED._("common.label.cancel"),
|
text: RED._("common.label.save"),
|
||||||
|
class: "primary",
|
||||||
click: function() {
|
click: function() {
|
||||||
|
saveToLibrary(true);
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,15 +383,16 @@ RED.library = (function() {
|
|||||||
height: 230,
|
height: 230,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: RED._("common.label.ok"),
|
text: RED._("common.label.cancel"),
|
||||||
click: function() {
|
click: function() {
|
||||||
saveToLibrary(false);
|
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: RED._("common.label.cancel"),
|
text: RED._("common.label.save"),
|
||||||
|
class: "primary",
|
||||||
click: function() {
|
click: function() {
|
||||||
|
saveToLibrary(false);
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -432,9 +435,17 @@ RED.library = (function() {
|
|||||||
resizable: false,
|
resizable: false,
|
||||||
title: RED._("library.exportToLibrary"),
|
title: RED._("library.exportToLibrary"),
|
||||||
buttons: [
|
buttons: [
|
||||||
|
{
|
||||||
|
id: "library-dialog-cancel",
|
||||||
|
text: RED._("common.label.cancel"),
|
||||||
|
click: function() {
|
||||||
|
$( this ).dialog( "close" );
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "library-dialog-ok",
|
id: "library-dialog-ok",
|
||||||
text: RED._("common.label.ok"),
|
class: "primary",
|
||||||
|
text: RED._("common.label.export"),
|
||||||
click: function() {
|
click: function() {
|
||||||
//TODO: move this to RED.library
|
//TODO: move this to RED.library
|
||||||
var flowName = $("#node-input-library-filename").val();
|
var flowName = $("#node-input-library-filename").val();
|
||||||
@ -457,13 +468,6 @@ RED.library = (function() {
|
|||||||
}
|
}
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "library-dialog-cancel",
|
|
||||||
text: RED._("common.label.cancel"),
|
|
||||||
click: function() {
|
|
||||||
$( this ).dialog( "close" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
open: function(e) {
|
open: function(e) {
|
||||||
|
@ -103,12 +103,12 @@ RED.sidebar = (function() {
|
|||||||
sidebarSeparator.chartWidth = $("#workspace").width();
|
sidebarSeparator.chartWidth = $("#workspace").width();
|
||||||
sidebarSeparator.chartRight = winWidth-$("#workspace").width()-$("#workspace").offset().left-2;
|
sidebarSeparator.chartRight = winWidth-$("#workspace").width()-$("#workspace").offset().left-2;
|
||||||
|
|
||||||
|
|
||||||
if (!RED.menu.isSelected("menu-item-sidebar")) {
|
if (!RED.menu.isSelected("menu-item-sidebar")) {
|
||||||
sidebarSeparator.opening = true;
|
sidebarSeparator.opening = true;
|
||||||
var newChartRight = 7;
|
var newChartRight = 7;
|
||||||
$("#sidebar").addClass("closing");
|
$("#sidebar").addClass("closing");
|
||||||
$("#workspace").css("right",newChartRight);
|
$("#workspace").css("right",newChartRight);
|
||||||
|
$("#editor-stack").css("right",newChartRight+1);
|
||||||
$("#sidebar").width(0);
|
$("#sidebar").width(0);
|
||||||
RED.menu.setSelected("menu-item-sidebar",true);
|
RED.menu.setSelected("menu-item-sidebar",true);
|
||||||
RED.events.emit("sidebar:resize");
|
RED.events.emit("sidebar:resize");
|
||||||
@ -147,6 +147,7 @@ RED.sidebar = (function() {
|
|||||||
|
|
||||||
var newChartRight = sidebarSeparator.chartRight-d;
|
var newChartRight = sidebarSeparator.chartRight-d;
|
||||||
$("#workspace").css("right",newChartRight);
|
$("#workspace").css("right",newChartRight);
|
||||||
|
$("#editor-stack").css("right",newChartRight+1);
|
||||||
$("#sidebar").width(newSidebarWidth);
|
$("#sidebar").width(newSidebarWidth);
|
||||||
|
|
||||||
sidebar_tabs.resize();
|
sidebar_tabs.resize();
|
||||||
@ -159,6 +160,7 @@ RED.sidebar = (function() {
|
|||||||
if ($("#sidebar").width() < 180) {
|
if ($("#sidebar").width() < 180) {
|
||||||
$("#sidebar").width(180);
|
$("#sidebar").width(180);
|
||||||
$("#workspace").css("right",187);
|
$("#workspace").css("right",187);
|
||||||
|
$("#editor-stack").css("right",188);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$("#sidebar-separator").css("left","auto");
|
$("#sidebar-separator").css("left","auto");
|
||||||
|
@ -17,7 +17,7 @@ RED.sidebar.config = (function() {
|
|||||||
|
|
||||||
|
|
||||||
var content = document.createElement("div");
|
var content = document.createElement("div");
|
||||||
content.className = "sidebar-node-config"
|
content.className = "sidebar-node-config";
|
||||||
|
|
||||||
$('<div class="button-group sidebar-header">'+
|
$('<div class="button-group sidebar-header">'+
|
||||||
'<a class="sidebar-header-button-toggle selected" id="workspace-config-node-filter-all" href="#"><span data-i18n="sidebar.config.filterAll"></span></a>'+
|
'<a class="sidebar-header-button-toggle selected" id="workspace-config-node-filter-all" href="#"><span data-i18n="sidebar.config.filterAll"></span></a>'+
|
||||||
@ -35,6 +35,9 @@ RED.sidebar.config = (function() {
|
|||||||
var flowCategories = $("<div>").appendTo(content);
|
var flowCategories = $("<div>").appendTo(content);
|
||||||
var subflowCategories = $("<div>").appendTo(content);
|
var subflowCategories = $("<div>").appendTo(content);
|
||||||
|
|
||||||
|
|
||||||
|
var shade = $('<div class="sidebar-node-config-shade hide"></div>').appendTo(content);
|
||||||
|
|
||||||
var showUnusedOnly = false;
|
var showUnusedOnly = false;
|
||||||
|
|
||||||
var categories = {};
|
var categories = {};
|
||||||
@ -288,6 +291,12 @@ RED.sidebar.config = (function() {
|
|||||||
return {
|
return {
|
||||||
init:init,
|
init:init,
|
||||||
show:show,
|
show:show,
|
||||||
refresh:refreshConfigNodeList
|
refresh:refreshConfigNodeList,
|
||||||
|
disable: function() {
|
||||||
|
shade.show();
|
||||||
|
},
|
||||||
|
enable: function() {
|
||||||
|
shade.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013, 2015 IBM Corp.
|
* Copyright 2013, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -24,7 +24,7 @@ RED.tabs = (function() {
|
|||||||
var currentTabWidth;
|
var currentTabWidth;
|
||||||
var currentActiveTabWidth = 0;
|
var currentActiveTabWidth = 0;
|
||||||
|
|
||||||
var ul = $("#"+options.id)
|
var ul = $("#"+options.id);
|
||||||
ul.addClass("red-ui-tabs");
|
ul.addClass("red-ui-tabs");
|
||||||
ul.children().first().addClass("active");
|
ul.children().first().addClass("active");
|
||||||
ul.children().addClass("red-ui-tab");
|
ul.children().addClass("red-ui-tab");
|
||||||
@ -118,6 +118,7 @@ RED.tabs = (function() {
|
|||||||
addTab: function(tab) {
|
addTab: function(tab) {
|
||||||
tabs[tab.id] = tab;
|
tabs[tab.id] = tab;
|
||||||
var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
|
var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
|
||||||
|
li.data("tabId",tab.id);
|
||||||
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
|
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
|
||||||
if (tab.icon) {
|
if (tab.icon) {
|
||||||
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
|
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
|
||||||
@ -142,6 +143,85 @@ RED.tabs = (function() {
|
|||||||
if (ul.find("li.red-ui-tab").size() == 1) {
|
if (ul.find("li.red-ui-tab").size() == 1) {
|
||||||
activateTab(link);
|
activateTab(link);
|
||||||
}
|
}
|
||||||
|
if (options.onreorder) {
|
||||||
|
var originalTabOrder;
|
||||||
|
var tabDragIndex;
|
||||||
|
var tabElements = [];
|
||||||
|
var startDragIndex;
|
||||||
|
|
||||||
|
li.draggable({
|
||||||
|
axis:"x",
|
||||||
|
distance: 20,
|
||||||
|
start: function(event,ui) {
|
||||||
|
originalTabOrder = [];
|
||||||
|
tabElements = [];
|
||||||
|
ul.children().each(function(i) {
|
||||||
|
tabElements[i] = {
|
||||||
|
el:$(this),
|
||||||
|
text: $(this).text(),
|
||||||
|
left: $(this).position().left,
|
||||||
|
width: $(this).width()
|
||||||
|
};
|
||||||
|
if ($(this).is(li)) {
|
||||||
|
tabDragIndex = i;
|
||||||
|
startDragIndex = i;
|
||||||
|
}
|
||||||
|
originalTabOrder.push($(this).data("tabId"));
|
||||||
|
});
|
||||||
|
ul.children().each(function(i) {
|
||||||
|
if (i!==tabDragIndex) {
|
||||||
|
$(this).css({
|
||||||
|
position: 'absolute',
|
||||||
|
left: tabElements[i].left+"px",
|
||||||
|
width: tabElements[i].width+2,
|
||||||
|
transition: "left 0.3s"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
if (!li.hasClass('active')) {
|
||||||
|
li.css({'zIndex':1});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
drag: function(event,ui) {
|
||||||
|
ui.position.left += tabElements[tabDragIndex].left;
|
||||||
|
var tabCenter = ui.position.left + tabElements[tabDragIndex].width/2;
|
||||||
|
for (var i=0;i<tabElements.length;i++) {
|
||||||
|
if (i === tabDragIndex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tabCenter > tabElements[i].left && tabCenter < tabElements[i].left+tabElements[i].width) {
|
||||||
|
if (i < tabDragIndex) {
|
||||||
|
tabElements[i].left += tabElements[tabDragIndex].width+8;
|
||||||
|
tabElements[tabDragIndex].el.detach().insertBefore(tabElements[i].el);
|
||||||
|
} else {
|
||||||
|
tabElements[i].left -= tabElements[tabDragIndex].width+8;
|
||||||
|
tabElements[tabDragIndex].el.detach().insertAfter(tabElements[i].el);
|
||||||
|
}
|
||||||
|
tabElements[i].el.css({left:tabElements[i].left+"px"});
|
||||||
|
|
||||||
|
tabElements.splice(i, 0, tabElements.splice(tabDragIndex, 1)[0]);
|
||||||
|
|
||||||
|
tabDragIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(ui.position.left,ui.offset.left);
|
||||||
|
},
|
||||||
|
stop: function(event,ui) {
|
||||||
|
ul.children().css({position:"relative",left:"",transition:""});
|
||||||
|
if (!li.hasClass('active')) {
|
||||||
|
li.css({zIndex:""});
|
||||||
|
}
|
||||||
|
updateTabWidths();
|
||||||
|
if (startDragIndex !== tabDragIndex) {
|
||||||
|
options.onreorder(originalTabOrder, $.makeArray(ul.children().map(function() { return $(this).data('tabId');})));
|
||||||
|
}
|
||||||
|
activateTab(tabElements[tabDragIndex].el.data('tabId'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
removeTab: removeTab,
|
removeTab: removeTab,
|
||||||
activateTab: activateTab,
|
activateTab: activateTab,
|
||||||
@ -158,6 +238,30 @@ RED.tabs = (function() {
|
|||||||
tab.attr("title",label);
|
tab.attr("title",label);
|
||||||
tab.find("span").text(label);
|
tab.find("span").text(label);
|
||||||
updateTabWidths();
|
updateTabWidths();
|
||||||
|
},
|
||||||
|
order: function(order) {
|
||||||
|
var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));
|
||||||
|
if (existingTabOrder.length !== order.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var i;
|
||||||
|
var match = true;
|
||||||
|
for (i=0;i<order.length;i++) {
|
||||||
|
if (order[i] !== existingTabOrder[i]) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var existingTabMap = {};
|
||||||
|
var existingTabs = ul.children().detach().each(function() {
|
||||||
|
existingTabMap[$(this).data("tabId")] = $(this);
|
||||||
|
});
|
||||||
|
for (i=0;i<order.length;i++) {
|
||||||
|
existingTabMap[order[i]].appendTo(ul);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
225
editor/js/ui/tray.js
Normal file
225
editor/js/ui/tray.js
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* 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.tray = (function() {
|
||||||
|
|
||||||
|
var stack = [];
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
|
||||||
|
}
|
||||||
|
function showTray(options) {
|
||||||
|
var el = $('<div class="editor-tray"></div>');
|
||||||
|
var header = $('<div class="editor-tray-header"></div>').appendTo(el);
|
||||||
|
var body = $('<div class="editor-tray-body"></div>').appendTo(el);
|
||||||
|
var footer = $('<div class="editor-tray-footer"></div>').appendTo(el);
|
||||||
|
var resizer = $('<div class="editor-tray-resize-handle"></div>').appendTo(el);
|
||||||
|
// var growButton = $('<a class="editor-tray-resize-button" style="cursor: w-resize;"><i class="fa fa-angle-left"></i></a>').appendTo(resizer);
|
||||||
|
// var shrinkButton = $('<a class="editor-tray-resize-button" style="cursor: e-resize;"><i style="margin-left: 1px;" class="fa fa-angle-right"></i></a>').appendTo(resizer);
|
||||||
|
if (options.title) {
|
||||||
|
$('<div class="editor-tray-titlebar">'+options.title+'</div>').appendTo(header);
|
||||||
|
}
|
||||||
|
var buttonBar = $('<div class="editor-tray-toolbar"></div>').appendTo(header);
|
||||||
|
if (options.buttons) {
|
||||||
|
for (var i=0;i<options.buttons.length;i++) {
|
||||||
|
var button = options.buttons[i];
|
||||||
|
|
||||||
|
var b = $('<button>').appendTo(buttonBar);
|
||||||
|
if (button.id) {
|
||||||
|
b.attr('id',button.id);
|
||||||
|
}
|
||||||
|
if (button.text) {
|
||||||
|
b.html(button.text);
|
||||||
|
}
|
||||||
|
if (button.click) {
|
||||||
|
b.click(button.click);
|
||||||
|
}
|
||||||
|
if (button.class) {
|
||||||
|
b.addClass(button.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
el.appendTo("#editor-stack");
|
||||||
|
var tray = {
|
||||||
|
tray: el,
|
||||||
|
header: header,
|
||||||
|
body: body,
|
||||||
|
footer: footer,
|
||||||
|
options: options
|
||||||
|
};
|
||||||
|
stack.push(tray);
|
||||||
|
|
||||||
|
el.draggable({
|
||||||
|
handle: resizer,
|
||||||
|
axis: "x",
|
||||||
|
start:function(event,ui) {
|
||||||
|
el.width('auto');
|
||||||
|
},
|
||||||
|
drag: function(event,ui) {
|
||||||
|
if (ui.position.left > -tray.preferredWidth-1) {
|
||||||
|
ui.position.left = -tray.preferredWidth-1;
|
||||||
|
} else if (tray.options.resize) {
|
||||||
|
setTimeout(function() {
|
||||||
|
tray.options.resize({width: -ui.position.left});
|
||||||
|
},0);
|
||||||
|
}
|
||||||
|
tray.width = -ui.position.left;
|
||||||
|
},
|
||||||
|
stop:function(event,ui) {
|
||||||
|
el.width(-ui.position.left);
|
||||||
|
el.css({left:''});
|
||||||
|
if (tray.options.resize) {
|
||||||
|
tray.options.resize({width: -ui.position.left});
|
||||||
|
}
|
||||||
|
tray.width = -ui.position.left;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.open) {
|
||||||
|
options.open(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#header-shade").show();
|
||||||
|
$("#editor-shade").show();
|
||||||
|
RED.sidebar.config.disable();
|
||||||
|
|
||||||
|
tray.preferredWidth = el.width();
|
||||||
|
if (options.width) {
|
||||||
|
if (options.width > $("#editor-stack").position().left-8) {
|
||||||
|
options.width = $("#editor-stack").position().left-8;
|
||||||
|
}
|
||||||
|
el.width(options.width);
|
||||||
|
}
|
||||||
|
tray.width = el.width();
|
||||||
|
el.css({
|
||||||
|
right: -(el.width()+10)+"px",
|
||||||
|
transition: "right 0.2s ease"
|
||||||
|
});
|
||||||
|
$("#workspace").scrollLeft(0);
|
||||||
|
|
||||||
|
var trayHeight = el.height()-header.outerHeight()-footer.outerHeight();
|
||||||
|
body.height(trayHeight-40);
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
if (!options.width) {
|
||||||
|
el.width(tray.preferredWidth);
|
||||||
|
}
|
||||||
|
if (options.resize) {
|
||||||
|
options.resize({width:el.width()});
|
||||||
|
}
|
||||||
|
if (options.show) {
|
||||||
|
options.show();
|
||||||
|
}
|
||||||
|
},150);
|
||||||
|
el.css({right:0});
|
||||||
|
},0);
|
||||||
|
|
||||||
|
// growButton.click(function(e) {
|
||||||
|
// e.preventDefault();
|
||||||
|
// tray.lastWidth = tray.width;
|
||||||
|
// tray.width = $("#editor-stack").position().left-8;
|
||||||
|
// el.width(tray.width);
|
||||||
|
// if (options.resize) {
|
||||||
|
// options.resize({width:tray.width});
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// shrinkButton.click(function(e) {
|
||||||
|
// e.preventDefault();
|
||||||
|
// if (tray.lastWidth && tray.width > tray.lastWidth) {
|
||||||
|
// tray.width = tray.lastWidth;
|
||||||
|
// } else if (tray.width > tray.preferredWidth) {
|
||||||
|
// tray.width = tray.preferredWidth;
|
||||||
|
// }
|
||||||
|
// el.width(tray.width);
|
||||||
|
// if (options.resize) {
|
||||||
|
// options.resize({width:tray.width});
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWindowResize() {
|
||||||
|
if (stack.length > 0) {
|
||||||
|
var tray = stack[stack.length-1];
|
||||||
|
var trayHeight = tray.tray.height()-tray.header.outerHeight()-tray.footer.outerHeight();
|
||||||
|
tray.body.height(trayHeight-40);
|
||||||
|
|
||||||
|
if (tray.width > $("#editor-stack").position().left-8) {
|
||||||
|
tray.width = Math.max(tray.preferredWidth,$("#editor-stack").position().left-8);
|
||||||
|
tray.tray.width(tray.width);
|
||||||
|
}
|
||||||
|
if (tray.options.resize) {
|
||||||
|
tray.options.resize({width:tray.width});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: function init() {
|
||||||
|
$(window).resize(handleWindowResize);
|
||||||
|
RED.events.on("sidebar:resize",handleWindowResize);
|
||||||
|
},
|
||||||
|
show: function show(options) {
|
||||||
|
if (stack.length > 0) {
|
||||||
|
var oldTray = stack[stack.length-1];
|
||||||
|
oldTray.tray.css({
|
||||||
|
right: -(oldTray.tray.width()+10)+"px"
|
||||||
|
});
|
||||||
|
setTimeout(function() {
|
||||||
|
oldTray.tray.detach();
|
||||||
|
showTray(options);
|
||||||
|
},200)
|
||||||
|
} else {
|
||||||
|
showTray(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
close: function close(done) {
|
||||||
|
if (stack.length > 0) {
|
||||||
|
var tray = stack.pop();
|
||||||
|
tray.tray.css({
|
||||||
|
right: -(tray.tray.width()+10)+"px"
|
||||||
|
});
|
||||||
|
setTimeout(function() {
|
||||||
|
if (tray.options.close) {
|
||||||
|
tray.options.close();
|
||||||
|
}
|
||||||
|
tray.tray.remove();
|
||||||
|
if (stack.length > 0) {
|
||||||
|
var oldTray = stack[stack.length-1];
|
||||||
|
oldTray.tray.appendTo("#editor-stack");
|
||||||
|
setTimeout(function() {
|
||||||
|
handleWindowResize();
|
||||||
|
oldTray.tray.css({right:0});
|
||||||
|
if (oldTray.options.show) {
|
||||||
|
oldTray.options.show();
|
||||||
|
}
|
||||||
|
},0);
|
||||||
|
}
|
||||||
|
if (done) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
},200)
|
||||||
|
if (stack.length === 0) {
|
||||||
|
$("#header-shade").hide();
|
||||||
|
$("#editor-shade").hide();
|
||||||
|
RED.sidebar.config.enable();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
@ -334,7 +334,7 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var nn = { id:(1+Math.random()*4294967295).toString(16),z:RED.workspaces.active()};
|
var nn = { id:RED.nodes.id(),z:RED.workspaces.active()};
|
||||||
|
|
||||||
nn.type = selected_tool;
|
nn.type = selected_tool;
|
||||||
nn._def = RED.nodes.getType(nn.type);
|
nn._def = RED.nodes.getType(nn.type);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 IBM Corp.
|
* Copyright 2015, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -113,6 +113,11 @@ RED.workspaces = (function() {
|
|||||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
||||||
RED.menu.removeItem("menu-item-workspace-menu-"+tab.id.replace(".","-"));
|
RED.menu.removeItem("menu-item-workspace-menu-"+tab.id.replace(".","-"));
|
||||||
},
|
},
|
||||||
|
onreorder: function(oldOrder, newOrder) {
|
||||||
|
RED.history.push({t:'reorder',order:oldOrder,dirty:RED.nodes.dirty()});
|
||||||
|
RED.nodes.dirty(true);
|
||||||
|
setWorkspaceOrder(newOrder);
|
||||||
|
},
|
||||||
minimumActiveTabWidth: 150
|
minimumActiveTabWidth: 150
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -134,7 +139,14 @@ RED.workspaces = (function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: RED._("common.label.ok"),
|
text: RED._("common.label.cancel"),
|
||||||
|
click: function() {
|
||||||
|
$( this ).dialog( "close" );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: RED._("common.label.done"),
|
||||||
|
class: "primary",
|
||||||
click: function() {
|
click: function() {
|
||||||
var workspace = $(this).dialog('option','workspace');
|
var workspace = $(this).dialog('option','workspace');
|
||||||
var label = $( "#node-input-workspace-name" ).val();
|
var label = $( "#node-input-workspace-name" ).val();
|
||||||
@ -146,13 +158,8 @@ RED.workspaces = (function() {
|
|||||||
}
|
}
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
text: RED._("common.label.cancel"),
|
|
||||||
click: function() {
|
|
||||||
$( this ).dialog( "close" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
open: function(e) {
|
open: function(e) {
|
||||||
RED.keyboard.disable();
|
RED.keyboard.disable();
|
||||||
@ -216,11 +223,18 @@ RED.workspaces = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWorkspaceOrder(order) {
|
||||||
|
RED.nodes.setWorkspaceOrder(order.filter(function(id) {
|
||||||
|
return RED.nodes.workspace(id) !== undefined;
|
||||||
|
}));
|
||||||
|
workspace_tabs.order(order);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
add: addWorkspace,
|
add: addWorkspace,
|
||||||
remove: removeWorkspace,
|
remove: removeWorkspace,
|
||||||
|
order: setWorkspaceOrder,
|
||||||
edit: function(id) {
|
edit: function(id) {
|
||||||
showRenameWorkspaceDialog(id||activeWorkspace);
|
showRenameWorkspaceDialog(id||activeWorkspace);
|
||||||
},
|
},
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
$background-color: #f3f3f3;
|
||||||
|
|
||||||
$form-placeholder-color: #bbbbbb;
|
$form-placeholder-color: #bbbbbb;
|
||||||
$form-text-color: #444;
|
$form-text-color: #444;
|
||||||
$form-input-focus-color: rgba(85,150,230,0.8);
|
$form-input-focus-color: rgba(85,150,230,0.8);
|
||||||
@ -45,6 +47,13 @@ $workspace-button-color-hover: #666;
|
|||||||
$workspace-button-color-active: #666;
|
$workspace-button-color-active: #666;
|
||||||
$workspace-button-color-selected: #AAA;
|
$workspace-button-color-selected: #AAA;
|
||||||
|
|
||||||
|
$workspace-button-color-focus-outline: rgba(85,150,230,0.2);
|
||||||
|
|
||||||
$typedInput-button-background: #efefef;
|
$typedInput-button-background: #efefef;
|
||||||
$typedInput-button-background-hover: #ddd;
|
$typedInput-button-background-hover: #ddd;
|
||||||
$typedInput-button-background-active: #e3e3e3;
|
$typedInput-button-background-active: #e3e3e3;
|
||||||
|
|
||||||
|
$editor-button-color-primary: #666;
|
||||||
|
$editor-button-color-secondary: #999;
|
||||||
|
|
||||||
|
$shade-color: rgba(220,220,220,0.5);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 IBM Corp.
|
* Copyright 2015, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -14,7 +14,144 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
.dialog-form, #dialog-form, #dialog-config-form {
|
|
||||||
|
#editor-stack {
|
||||||
|
position: absolute;
|
||||||
|
margin: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 323px;
|
||||||
|
width: 0;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
.editor-tray {
|
||||||
|
position:absolute;
|
||||||
|
margin: 0;
|
||||||
|
top: 0;
|
||||||
|
min-width: 500px;
|
||||||
|
width: auto;
|
||||||
|
right: -1000px;
|
||||||
|
bottom: 0;
|
||||||
|
background: #fff;
|
||||||
|
border-left: 1px solid $secondary-border-color;
|
||||||
|
border-bottom: 1px solid $primary-border-color;
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
.editor-tray.open {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.editor-tray-body {
|
||||||
|
width: auto;
|
||||||
|
padding: 20px;
|
||||||
|
min-width: 500px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
.editor-tray-header {
|
||||||
|
@include disable-selection;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-weight: bold;
|
||||||
|
border-bottom: 1px solid $secondary-border-color;
|
||||||
|
background: $palette-header-background;
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tray-footer {
|
||||||
|
@include component-footer;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tray-toolbar {
|
||||||
|
text-align: right;
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include workspace-button;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 6px 14px;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: $editor-button-color-primary;
|
||||||
|
&.leftButton {
|
||||||
|
float: left;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
&:not(.leftButton):not(:last-child) {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
&:not(.primary) {
|
||||||
|
background: none;
|
||||||
|
&:hover {
|
||||||
|
color: $editor-button-color-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tray-titlebar {
|
||||||
|
border-bottom: 1px solid $secondary-border-color;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
.editor-tray-breadcrumbs {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding:0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
padding:0;
|
||||||
|
margin:0;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
color: $editor-button-color-secondary;
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
display: inline-block;
|
||||||
|
content: '>';
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.editor-tray-resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
width: 7px;
|
||||||
|
left: -9px;
|
||||||
|
background: $background-color url(images/grip.png) no-repeat 50% 50%;
|
||||||
|
cursor: col-resize;
|
||||||
|
border-left: 1px solid $primary-border-color;
|
||||||
|
box-shadow: -1px 0 6px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.editor-tray-resize-button {
|
||||||
|
@include workspace-button;
|
||||||
|
display: block;
|
||||||
|
height: 37px;
|
||||||
|
line-height: 35px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid $secondary-border-color;
|
||||||
|
margin: 0;
|
||||||
|
background: $background-color;
|
||||||
|
color: $workspace-button-color;
|
||||||
|
}
|
||||||
|
#editor-shade, #header-shade {
|
||||||
|
position: absolute;
|
||||||
|
top:0;
|
||||||
|
bottom:0;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
background: $shade-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.dialog-form,#dialog-form, #dialog-config-form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
@ -23,10 +160,6 @@
|
|||||||
border-color: rgb(214, 97, 95) !important;
|
border-color: rgb(214, 97, 95) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-dialog .ui-dialog-buttonpane button.leftButton {
|
|
||||||
margin-right: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row {
|
.form-row {
|
||||||
clear: both;
|
clear: both;
|
||||||
color: $form-text-color;
|
color: $form-text-color;
|
||||||
@ -83,6 +216,7 @@
|
|||||||
cursor: auto;
|
cursor: auto;
|
||||||
float: right;
|
float: right;
|
||||||
font-size: 12px !important;
|
font-size: 12px !important;
|
||||||
|
line-height: 35px;
|
||||||
}
|
}
|
||||||
#node-config-dialog-scope-warning {
|
#node-config-dialog-scope-warning {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -94,13 +228,14 @@
|
|||||||
margin: 1px 0 0 0;
|
margin: 1px 0 0 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
width: 110px;
|
width: 150px;
|
||||||
|
|
||||||
}
|
}
|
||||||
#node-config-dialog-user-count {
|
#node-config-dialog-user-count {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
margin-top: 10px;
|
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
float:left;
|
float:left;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
line-height: 35px;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,32 @@
|
|||||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ui-dialog-buttonset button {
|
||||||
|
@include workspace-button;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 6px 14px;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: $editor-button-color-primary;
|
||||||
|
&.leftButton {
|
||||||
|
float: left;
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
&:not(.leftButton):not(:last-child) {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
&:not(.primary) {
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $editor-button-color-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ui-button-text {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ui-dialog .ui-dialog-buttonpane {
|
.ui-dialog .ui-dialog-buttonpane {
|
||||||
padding: .3em 1em .5em 1em;
|
padding: .3em 1em .5em 1em;
|
||||||
}
|
}
|
||||||
|
@ -62,10 +62,13 @@
|
|||||||
background: $workspace-button-background-active;
|
background: $workspace-button-background-active;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group &:not(:first-child) {
|
.button-group &:not(:first-child) {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 1px solid $workspace-button-color-focus-outline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@mixin workspace-button-toggle {
|
@mixin workspace-button-toggle {
|
||||||
@include workspace-button;
|
@include workspace-button;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
width: 315px;
|
width: 315px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
z-index: 10;
|
||||||
@include component-border;
|
@include component-border;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,13 +47,15 @@
|
|||||||
right: 315px;
|
right: 315px;
|
||||||
bottom:10px;
|
bottom:10px;
|
||||||
width: 7px;
|
width: 7px;
|
||||||
background: url(images/grip.png) no-repeat 50% 50%;
|
z-index: 11;
|
||||||
|
background: $background-color url(images/grip.png) no-repeat 50% 50%;
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-closed > #sidebar { display: none; }
|
.sidebar-closed > #sidebar { display: none; }
|
||||||
.sidebar-closed > #sidebar-separator { right: 0px !important; }
|
.sidebar-closed > #sidebar-separator { right: 0px !important; }
|
||||||
.sidebar-closed > #workspace { right: 7px !important; }
|
.sidebar-closed > #workspace { right: 7px !important; }
|
||||||
|
.sidebar-closed > #editor-stack { right: 8px !important; }
|
||||||
|
|
||||||
#sidebar .button {
|
#sidebar .button {
|
||||||
@include workspace-button;
|
@include workspace-button;
|
||||||
|
@ -52,7 +52,7 @@ body {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||||
padding-top: 100px;
|
padding-top: 100px;
|
||||||
background: #f3f3f3;
|
background: $background-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-container {
|
#main-container {
|
||||||
|
@ -15,11 +15,21 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
.sidebar-node-config {
|
.sidebar-node-config {
|
||||||
|
position: relative;
|
||||||
background: #f3f3f3;
|
background: #f3f3f3;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y:auto;
|
overflow-y:auto;
|
||||||
@include disable-selection;
|
@include disable-selection;
|
||||||
}
|
}
|
||||||
|
.sidebar-node-config-shade {
|
||||||
|
position: absolute;
|
||||||
|
top:0;
|
||||||
|
bottom:0;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
background: $shade-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.config-node-list {
|
.config-node-list {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -104,6 +104,7 @@ ul.red-ui-tabs li.active {
|
|||||||
background: $tab-background-active;
|
background: $tab-background-active;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-bottom: 1px solid #fff;
|
border-bottom: 1px solid #fff;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
ul.red-ui-tabs li.active a {
|
ul.red-ui-tabs li.active a {
|
||||||
color: #333;
|
color: #333;
|
||||||
|
@ -50,6 +50,8 @@
|
|||||||
margin-right: 35px;
|
margin-right: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#workspace-add-tab {
|
#workspace-add-tab {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
<ul class="header-toolbar hide">
|
<ul class="header-toolbar hide">
|
||||||
<li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li>
|
<li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div id="header-shade" class="hide"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="main-container" class="sidebar-closed hide">
|
<div id="main-container" class="sidebar-closed hide">
|
||||||
<div id="palette">
|
<div id="palette">
|
||||||
@ -65,6 +66,8 @@
|
|||||||
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="editor-shade" class="hide"></div>
|
||||||
|
<div id="editor-stack"></div>
|
||||||
<div id="sidebar">
|
<div id="sidebar">
|
||||||
<ul id="sidebar-tabs"></ul>
|
<ul id="sidebar-tabs"></ul>
|
||||||
<div id="sidebar-content"></div>
|
<div id="sidebar-content"></div>
|
||||||
@ -78,24 +81,6 @@
|
|||||||
<div id="notifications"></div>
|
<div id="notifications"></div>
|
||||||
<div id="dropTarget"><div data-i18n="[append]workspace.dropFlowHere"><br/><i class="fa fa-download"></i></div></div>
|
<div id="dropTarget"><div data-i18n="[append]workspace.dropFlowHere"><br/><i class="fa fa-download"></i></div></div>
|
||||||
|
|
||||||
<div id="dialog" class="hide"><form id="dialog-form" class="form-horizontal"></form></div>
|
|
||||||
<div id="node-config-dialog" class="hide"><form id="dialog-config-form" class="form-horizontal"><div id="node-config-dialog-edit-form"></div><!--<div id="node-config-dialog-toolbar" class="form-row"><label><span>Node scope</span></label><select id="node-config-dialog-scope"></select></div>--></form></div>
|
|
||||||
<div id="subflow-dialog" class="hide">
|
|
||||||
<form class="form-horizontal">
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name">
|
|
||||||
</div>
|
|
||||||
<div class="form-row" style="margin-bottom: 0px;">
|
|
||||||
<label for="subflow-input-info" data-i18n="subflow.info"></label>
|
|
||||||
<a href="https://help.github.com/articles/markdown-basics/" style="font-size: 0.8em; float: right;" data-i18n="[html]subflow.format"></a>
|
|
||||||
</div>
|
|
||||||
<div class="form-row node-text-editor-row">
|
|
||||||
<div style="height: 250px;" class="node-text-editor" id="subflow-input-info-editor"></div>
|
|
||||||
</div>
|
|
||||||
<div class="form-row form-tips" id="subflow-dialog-user-count"></div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="node-dialog-confirm-deploy" class="hide">
|
<div id="node-dialog-confirm-deploy" class="hide">
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
<div id="node-dialog-confirm-deploy-config" style="text-align: left; padding-top: 30px;" data-i18n="[prepend]deploy.confirm.improperlyConfigured;[append]deploy.confirm.confirm">
|
<div id="node-dialog-confirm-deploy-config" style="text-align: left; padding-top: 30px;" data-i18n="[prepend]deploy.confirm.improperlyConfigured;[append]deploy.confirm.confirm">
|
||||||
@ -166,6 +151,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="subflow-template">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name">
|
||||||
|
</div>
|
||||||
|
<div class="form-row" style="margin-bottom: 0px;">
|
||||||
|
<label for="subflow-input-info" data-i18n="subflow.info"></label>
|
||||||
|
<a href="https://help.github.com/articles/markdown-basics/" style="font-size: 0.8em; float: right;" data-i18n="[html]subflow.format"></a>
|
||||||
|
</div>
|
||||||
|
<div class="form-row node-text-editor-row">
|
||||||
|
<div style="height: 250px;" class="node-text-editor" id="subflow-input-info-editor"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row form-tips" id="subflow-dialog-user-count"></div>
|
||||||
|
</script>
|
||||||
|
|
||||||
<script src="vendor/vendor.js"></script>
|
<script src="vendor/vendor.js"></script>
|
||||||
<script src="vendor/ace/ace.js"></script>
|
<script src="vendor/ace/ace.js"></script>
|
||||||
<script src="vendor/ace/ext-language_tools.js"></script>
|
<script src="vendor/ace/ext-language_tools.js"></script>
|
||||||
|
73
nodes/core/io/05-tls.html
Normal file
73
nodes/core/io/05-tls.html
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<!--
|
||||||
|
Copyright 2016 IBM Corp.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="tls-config">
|
||||||
|
<div class="form-row">
|
||||||
|
<label style="width: 120px;" for="node-config-input-cert"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.cert"></span></label>
|
||||||
|
<input style="width: 60%;" type="text" id="node-config-input-cert" data-i18n="[placeholder]tls.placeholder.cert">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label style="width: 120px;" for="node-config-input-key"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.key"></span></label>
|
||||||
|
<input style="width: 60%;" type="text" id="node-config-input-key" data-i18n="[placeholder]tls.placeholder.key">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label style="width: 120px;" for="node-config-input-ca"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.ca"></span></label>
|
||||||
|
<input style="width: 60%;" type="text" id="node-config-input-ca" data-i18n="[placeholder]tls.placeholder.ca">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
|
<label for="node-config-input-verifyservercert" style="width: 70%;" data-i18n="tls.label.verify-server-cert"></label>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label style="width: 120px;" for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||||
|
<input style="width: 60%;" type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-help-name="tls-config">
|
||||||
|
<p>Configuration options for TLS connections.</p>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('tls-config',{
|
||||||
|
category: 'config',
|
||||||
|
defaults: {
|
||||||
|
name: {value:""},
|
||||||
|
cert: {value:"", validate: function(v) {
|
||||||
|
var currentKey = $("#node-config-input-key").val();
|
||||||
|
if (currentKey === undefined) {
|
||||||
|
currentKey = this.key;
|
||||||
|
}
|
||||||
|
return currentKey === '' || v != '';
|
||||||
|
}},
|
||||||
|
key: {value:"", validate: function(v) {
|
||||||
|
var currentCert = $("#node-config-input-cert").val();
|
||||||
|
if (currentCert === undefined) {
|
||||||
|
currentCert = this.cert;
|
||||||
|
}
|
||||||
|
return currentCert === '' || v != '';
|
||||||
|
}},
|
||||||
|
ca: {value:""},
|
||||||
|
verifyservercert: {value: true}
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || this._("tls.tls");
|
||||||
|
},
|
||||||
|
labelStyle: function() {
|
||||||
|
return this.name?"node_label_italic":"";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
69
nodes/core/io/05-tls.js
Normal file
69
nodes/core/io/05-tls.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
module.exports = function(RED) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function TLSConfig(n) {
|
||||||
|
RED.nodes.createNode(this,n);
|
||||||
|
this.valid = true;
|
||||||
|
var certPath = n.cert.trim();
|
||||||
|
var keyPath = n.key.trim();
|
||||||
|
var caPath = n.ca.trim();
|
||||||
|
|
||||||
|
if ( (certPath.length > 0) !== (keyPath.length > 0)) {
|
||||||
|
this.valid = false;
|
||||||
|
this.error(RED._("tls.error.missing-file"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.verifyservercert = n.verifyservercert;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (certPath) {
|
||||||
|
this.cert = fs.readFileSync(certPath);
|
||||||
|
}
|
||||||
|
if (keyPath) {
|
||||||
|
this.key = fs.readFileSync(keyPath);
|
||||||
|
}
|
||||||
|
if (caPath) {
|
||||||
|
this.ca = fs.readFileSync(caPath);
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
this.valid = false;
|
||||||
|
this.error(err.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("tls-config",TLSConfig);
|
||||||
|
|
||||||
|
TLSConfig.prototype.addTLSOptions = function(opts) {
|
||||||
|
if (this.valid) {
|
||||||
|
if (this.key) {
|
||||||
|
opts.key = this.key;
|
||||||
|
}
|
||||||
|
if (this.cert) {
|
||||||
|
opts.cert = this.cert;
|
||||||
|
}
|
||||||
|
if (this.ca) {
|
||||||
|
opts.ca = this.ca;
|
||||||
|
}
|
||||||
|
opts.rejectUnauthorized = this.verifyservercert;
|
||||||
|
}
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -150,11 +150,17 @@
|
|||||||
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="mqtt.label.port"></span></label>
|
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="mqtt.label.port"></span></label>
|
||||||
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:45px">
|
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:45px">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<input type="checkbox" id="node-config-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
|
<label for="node-config-input-usetls" style="width: auto" data-i18n="mqtt.label.use-tls"></label>
|
||||||
|
<div id="node-config-row-tls" class="hide">
|
||||||
|
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-config-input-tls"><span data-i18n="mqtt.label.tls-config"></span></label><input style="width: 300px;" type="text" id="node-config-input-tls">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-clientid"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.clientid"></span></label>
|
<label for="node-config-input-clientid"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.clientid"></span></label>
|
||||||
<input type="text" id="node-config-input-clientid" data-i18n="[placeholder]mqtt.placeholder.clientid">
|
<input type="text" id="node-config-input-clientid" data-i18n="[placeholder]mqtt.placeholder.clientid">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-keepalive" style="width: auto"><i class="fa fa-clock-o"></i> <span data-i18n="mqtt.label.keepalive"></span></label>
|
<label for="node-config-input-keepalive" style="width: auto"><i class="fa fa-clock-o"></i> <span data-i18n="mqtt.label.keepalive"></span></label>
|
||||||
<input type="text" id="node-config-input-keepalive" style="width: 50px">
|
<input type="text" id="node-config-input-keepalive" style="width: 50px">
|
||||||
@ -175,14 +181,6 @@
|
|||||||
<label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
|
<label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
|
||||||
<input type="password" id="node-config-input-password">
|
<input type="password" id="node-config-input-password">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
|
||||||
<input type="checkbox" id="node-config-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
|
||||||
<label for="node-config-input-usetls" style="width: 70%;" data-i18n="mqtt.label.use-tls"></label>
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;">
|
|
||||||
<label for="node-config-input-verifyservercert" style="width: 70%;" data-i18n="mqtt.label.verify-server-cert"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="mqtt-broker-tab-birth" style="display:none">
|
<div id="mqtt-broker-tab-birth" style="display:none">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
@ -240,6 +238,7 @@
|
|||||||
defaults: {
|
defaults: {
|
||||||
broker: {value:"",required:true},
|
broker: {value:"",required:true},
|
||||||
port: {value:1883,required:true,validate:RED.validators.number()},
|
port: {value:1883,required:true,validate:RED.validators.number()},
|
||||||
|
tls: {type:"tls-config",required: false},
|
||||||
clientid: { value:"", validate: function(v) {
|
clientid: { value:"", validate: function(v) {
|
||||||
if ($("#node-config-input-clientid").length) {
|
if ($("#node-config-input-clientid").length) {
|
||||||
// Currently editing the node
|
// Currently editing the node
|
||||||
@ -303,10 +302,6 @@
|
|||||||
this.usetls = false;
|
this.usetls = false;
|
||||||
$("#node-config-input-usetls").prop("checked",false);
|
$("#node-config-input-usetls").prop("checked",false);
|
||||||
}
|
}
|
||||||
if (typeof this.verifyservercert === 'undefined'){
|
|
||||||
this.verifyservercert = true;
|
|
||||||
$("#node-config-input-verifyservercert").prop("checked",true);
|
|
||||||
}
|
|
||||||
if (typeof this.compatmode === 'undefined'){
|
if (typeof this.compatmode === 'undefined'){
|
||||||
this.compatmode = true;
|
this.compatmode = true;
|
||||||
$("#node-config-input-compatmode").prop('checked', true);
|
$("#node-config-input-compatmode").prop('checked', true);
|
||||||
@ -326,11 +321,9 @@
|
|||||||
|
|
||||||
function updateTLSOptions() {
|
function updateTLSOptions() {
|
||||||
if ($("#node-config-input-usetls").is(':checked')) {
|
if ($("#node-config-input-usetls").is(':checked')) {
|
||||||
$("#node-config-input-verifyservercert").prop("disabled", false);
|
$("#node-config-row-tls").show();
|
||||||
$("#node-config-input-verifyservercert").next().css("color","");
|
|
||||||
} else {
|
} else {
|
||||||
$("#node-config-input-verifyservercert").prop("disabled", true);
|
$("#node-config-row-tls").hide();
|
||||||
$("#node-config-input-verifyservercert").next().css("color","#aaa");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateTLSOptions();
|
updateTLSOptions();
|
||||||
@ -350,6 +343,11 @@
|
|||||||
$("#node-config-input-cleansession").on("click",function() {
|
$("#node-config-input-cleansession").on("click",function() {
|
||||||
updateClientId();
|
updateClientId();
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
oneditsave: function() {
|
||||||
|
if (!$("#node-config-input-usetls").is(':checked')) {
|
||||||
|
$("#node-config-input-tls").val("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -114,8 +114,18 @@ module.exports = function(RED) {
|
|||||||
this.options.protocolId = 'MQIsdp';
|
this.options.protocolId = 'MQIsdp';
|
||||||
this.options.protocolVersion = 3;
|
this.options.protocolVersion = 3;
|
||||||
}
|
}
|
||||||
|
if (this.usetls && n.tls) {
|
||||||
this.options.rejectUnauthorized = (this.verifyservercert == "true" || this.verifyservercert === true)
|
var tlsNode = RED.nodes.getNode(n.tls);
|
||||||
|
if (tlsNode) {
|
||||||
|
tlsNode.addTLSOptions(this.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If there's no rejectUnauthorized already, then this could be an
|
||||||
|
// old config where this option was provided on the broker node and
|
||||||
|
// not the tls node
|
||||||
|
if (typeof this.options.rejectUnauthorized === 'undefined') {
|
||||||
|
this.options.rejectUnauthorized = (this.verifyservercert == "true" || this.verifyservercert === true);
|
||||||
|
}
|
||||||
|
|
||||||
if (n.willTopic) {
|
if (n.willTopic) {
|
||||||
this.options.will = {
|
this.options.will = {
|
||||||
@ -284,6 +294,9 @@ module.exports = function(RED) {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
this.client.end();
|
this.client.end();
|
||||||
|
} if (this.connecting) {
|
||||||
|
node.client.end();
|
||||||
|
done();
|
||||||
} else {
|
} else {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright 2013, 2015 IBM Corp.
|
Copyright 2013, 2016 IBM Corp.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -29,19 +29,31 @@
|
|||||||
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
|
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
|
||||||
<input type="text" id="node-input-url" placeholder="http://">
|
<input type="text" id="node-input-url" placeholder="http://">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
|
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
|
||||||
|
<div id="node-row-tls" class="hide">
|
||||||
|
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label> </label>
|
|
||||||
<input type="checkbox" id="node-input-useAuth" style="display: inline-block; width: auto; vertical-align: top;">
|
<input type="checkbox" id="node-input-useAuth" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
<label for="node-input-useAuth" style="width: 70%;"><span data-i18n="httpin.basicauth"></span></label>
|
<label for="node-input-useAuth" style="width: 70%;"><span data-i18n="httpin.basicauth"></span></label>
|
||||||
</div>
|
<div style="margin-left: 20px" class="node-input-useAuth-row hide">
|
||||||
<div class="form-row node-input-useAuth-row">
|
<div class="form-row">
|
||||||
<label for="node-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
|
<label for="node-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
|
||||||
<input type="text" id="node-input-user">
|
<input type="text" id="node-input-user">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row node-input-useAuth-row">
|
<div class="form-row">
|
||||||
<label for="node-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
|
<label for="node-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
|
||||||
<input type="password" id="node-input-password">
|
<input type="password" id="node-input-password">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-ret"><i class="fa fa-arrow-left"></i> <span data-i18n="httpin.label.return"></span></label>
|
<label for="node-input-ret"><i class="fa fa-arrow-left"></i> <span data-i18n="httpin.label.return"></span></label>
|
||||||
<select type="text" id="node-input-ret" style="width:72%;">
|
<select type="text" id="node-input-ret" style="width:72%;">
|
||||||
@ -91,8 +103,7 @@
|
|||||||
method:{value:"GET"},
|
method:{value:"GET"},
|
||||||
ret: {value:"txt"},
|
ret: {value:"txt"},
|
||||||
url:{value:""},
|
url:{value:""},
|
||||||
//user -> credentials
|
tls: {type:"tls-config",required: false}
|
||||||
//pass -> credentials
|
|
||||||
},
|
},
|
||||||
credentials: {
|
credentials: {
|
||||||
user: {type:"text"},
|
user: {type:"text"},
|
||||||
@ -108,14 +119,6 @@
|
|||||||
return this.name?"node_label_italic":"";
|
return this.name?"node_label_italic":"";
|
||||||
},
|
},
|
||||||
oneditprepare: function() {
|
oneditprepare: function() {
|
||||||
if (this.credentials.user || this.credentials.has_password) {
|
|
||||||
$('#node-input-useAuth').prop('checked', true);
|
|
||||||
$(".node-input-useAuth-row").show();
|
|
||||||
} else {
|
|
||||||
$('#node-input-useAuth').prop('checked', false);
|
|
||||||
$(".node-input-useAuth-row").hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#node-input-useAuth").change(function() {
|
$("#node-input-useAuth").change(function() {
|
||||||
if ($(this).is(":checked")) {
|
if ($(this).is(":checked")) {
|
||||||
$(".node-input-useAuth-row").show();
|
$(".node-input-useAuth-row").show();
|
||||||
@ -125,7 +128,29 @@
|
|||||||
$('#node-input-password').val('');
|
$('#node-input-password').val('');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (this.credentials.user || this.credentials.has_password) {
|
||||||
|
$('#node-input-useAuth').prop('checked', true);
|
||||||
|
} else {
|
||||||
|
$('#node-input-useAuth').prop('checked', false);
|
||||||
|
}
|
||||||
|
$("#node-input-useAuth").change();
|
||||||
|
|
||||||
|
function updateTLSOptions() {
|
||||||
|
if ($("#node-input-usetls").is(':checked')) {
|
||||||
|
$("#node-row-tls").show();
|
||||||
|
} else {
|
||||||
|
$("#node-row-tls").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.tls) {
|
||||||
|
$('#node-input-usetls').prop('checked', true);
|
||||||
|
} else {
|
||||||
|
$('#node-input-usetls').prop('checked', false);
|
||||||
|
}
|
||||||
|
updateTLSOptions();
|
||||||
|
$("#node-input-usetls").on("click",function() {
|
||||||
|
updateTLSOptions();
|
||||||
|
});
|
||||||
$("#node-input-ret").change(function() {
|
$("#node-input-ret").change(function() {
|
||||||
if ($("#node-input-ret").val() === "obj") {
|
if ($("#node-input-ret").val() === "obj") {
|
||||||
$("#tip-json").show();
|
$("#tip-json").show();
|
||||||
@ -133,6 +158,11 @@
|
|||||||
$("#tip-json").hide();
|
$("#tip-json").hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
oneditsave: function() {
|
||||||
|
if (!$("#node-input-usetls").is(':checked')) {
|
||||||
|
$("#node-input-tls").val("_ADD_");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013, 2015 IBM Corp.
|
* Copyright 2013, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -24,13 +24,16 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
function HTTPRequest(n) {
|
function HTTPRequest(n) {
|
||||||
RED.nodes.createNode(this,n);
|
RED.nodes.createNode(this,n);
|
||||||
|
var node = this;
|
||||||
var nodeUrl = n.url;
|
var nodeUrl = n.url;
|
||||||
var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
|
var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
|
||||||
var nodeMethod = n.method || "GET";
|
var nodeMethod = n.method || "GET";
|
||||||
|
if (n.tls) {
|
||||||
|
var tlsNode = RED.nodes.getNode(n.tls);
|
||||||
|
}
|
||||||
this.ret = n.ret || "txt";
|
this.ret = n.ret || "txt";
|
||||||
if (RED.settings.httpRequestTimeout) { this.reqTimeout = parseInt(RED.settings.httpRequestTimeout) || 120000; }
|
if (RED.settings.httpRequestTimeout) { this.reqTimeout = parseInt(RED.settings.httpRequestTimeout) || 120000; }
|
||||||
else { this.reqTimeout = 120000; }
|
else { this.reqTimeout = 120000; }
|
||||||
var node = this;
|
|
||||||
|
|
||||||
var prox, noprox;
|
var prox, noprox;
|
||||||
if (process.env.http_proxy != null) { prox = process.env.http_proxy; }
|
if (process.env.http_proxy != null) { prox = process.env.http_proxy; }
|
||||||
@ -54,8 +57,12 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
// url must start http:// or https:// so assume http:// if not set
|
// url must start http:// or https:// so assume http:// if not set
|
||||||
if (!((url.indexOf("http://") === 0) || (url.indexOf("https://") === 0))) {
|
if (!((url.indexOf("http://") === 0) || (url.indexOf("https://") === 0))) {
|
||||||
|
if (tlsNode) {
|
||||||
|
url = "https://"+url;
|
||||||
|
} else {
|
||||||
url = "http://"+url;
|
url = "http://"+url;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var method = nodeMethod.toUpperCase() || "GET";
|
var method = nodeMethod.toUpperCase() || "GET";
|
||||||
if (msg.method && n.method && (n.method !== "use")) { // warn if override option not set
|
if (msg.method && n.method && (n.method !== "use")) { // warn if override option not set
|
||||||
@ -133,6 +140,9 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
else { node.warn("Bad proxy url: "+process.env.http_proxy); }
|
else { node.warn("Bad proxy url: "+process.env.http_proxy); }
|
||||||
}
|
}
|
||||||
|
if (tlsNode) {
|
||||||
|
tlsNode.addTLSOptions(opts);
|
||||||
|
}
|
||||||
var req = ((/^https/.test(urltotest))?https:http).request(opts,function(res) {
|
var req = ((/^https/.test(urltotest))?https:http).request(opts,function(res) {
|
||||||
(node.ret === "bin") ? res.setEncoding('binary') : res.setEncoding('utf8');
|
(node.ret === "bin") ? res.setEncoding('binary') : res.setEncoding('utf8');
|
||||||
msg.statusCode = res.statusCode;
|
msg.statusCode = res.statusCode;
|
||||||
@ -172,6 +182,7 @@ module.exports = function(RED) {
|
|||||||
req.abort();
|
req.abort();
|
||||||
});
|
});
|
||||||
req.on('error',function(err) {
|
req.on('error',function(err) {
|
||||||
|
node.error(err,msg);
|
||||||
msg.payload = err.toString() + " : " + url;
|
msg.payload = err.toString() + " : " + url;
|
||||||
msg.statusCode = err.code;
|
msg.statusCode = err.code;
|
||||||
node.send(msg);
|
node.send(msg);
|
||||||
|
@ -123,6 +123,23 @@
|
|||||||
"event": "Event name"
|
"event": "Event name"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tls": {
|
||||||
|
"tls": "TLS configuration",
|
||||||
|
"label": {
|
||||||
|
"cert": "Certificate",
|
||||||
|
"key": "Private Key",
|
||||||
|
"ca": "CA Certificate",
|
||||||
|
"verify-server-cert":"Verify server certificate"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"cert":"path to certificate (PEM format)",
|
||||||
|
"key":"path to private key (PEM format)",
|
||||||
|
"ca":"path to CA certificate (PEM format)"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"missing-file": "No certificate/key file provided"
|
||||||
|
}
|
||||||
|
},
|
||||||
"exec": {
|
"exec": {
|
||||||
"label": {
|
"label": {
|
||||||
"command": "Command",
|
"command": "Command",
|
||||||
@ -240,6 +257,7 @@
|
|||||||
"keepalive": "Keep alive time (s)",
|
"keepalive": "Keep alive time (s)",
|
||||||
"cleansession": "Use clean session",
|
"cleansession": "Use clean session",
|
||||||
"use-tls": "Enable secure (SSL/TLS) connection",
|
"use-tls": "Enable secure (SSL/TLS) connection",
|
||||||
|
"tls-config":"TLS Configuration",
|
||||||
"verify-server-cert":"Verify server certificate",
|
"verify-server-cert":"Verify server certificate",
|
||||||
"compatmode": "Use legacy MQTT 3.1 support"
|
"compatmode": "Use legacy MQTT 3.1 support"
|
||||||
},
|
},
|
||||||
@ -279,7 +297,9 @@
|
|||||||
"return": "Return"
|
"return": "Return"
|
||||||
},
|
},
|
||||||
"setby": "- set by msg.method -",
|
"setby": "- set by msg.method -",
|
||||||
"basicauth": "Use basic authentication?",
|
"basicauth": "Use basic authentication",
|
||||||
|
"use-tls": "Enable secure (SSL/TLS) connection",
|
||||||
|
"tls-config":"TLS Configuration",
|
||||||
"utf8": "a UTF-8 string",
|
"utf8": "a UTF-8 string",
|
||||||
"binary": "a binary buffer",
|
"binary": "a binary buffer",
|
||||||
"json": "a parsed JSON object",
|
"json": "a parsed JSON object",
|
||||||
|
@ -3,9 +3,14 @@
|
|||||||
"label": {
|
"label": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"ok": "Ok",
|
"ok": "Ok",
|
||||||
|
"done":"Done",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"close": "Close"
|
"close": "Close",
|
||||||
|
"load": "Load",
|
||||||
|
"save": "Save",
|
||||||
|
"import": "Import",
|
||||||
|
"export": "Export"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
@ -105,10 +110,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"subflow": {
|
"subflow": {
|
||||||
"editSubflow": "Edit flow __name__",
|
"editSubflow": "Edit flow template: __name__",
|
||||||
"edit": "Edit flow",
|
"edit": "Edit flow template",
|
||||||
"subflowInstances": "There is __count__ instance of this subflow",
|
"subflowInstances": "There is __count__ instance of this subflow template",
|
||||||
"subflowInstances_plural": "There are __count__ instances of this subflow",
|
"subflowInstances_plural": "There are __count__ instances of this subflow template",
|
||||||
"editSubflowProperties": "edit properties",
|
"editSubflowProperties": "edit properties",
|
||||||
"input": "inputs:",
|
"input": "inputs:",
|
||||||
"output": "outputs:",
|
"output": "outputs:",
|
||||||
@ -121,12 +126,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
"configEdit": "edit",
|
"configEdit": "Edit",
|
||||||
"configAdd": "add",
|
"configAdd": "Add",
|
||||||
|
"configUpdate": "Update",
|
||||||
"configDelete": "Delete",
|
"configDelete": "Delete",
|
||||||
"nodesUse": "__count__ node uses this config",
|
"nodesUse": "__count__ node uses this config",
|
||||||
"nodesUse_plural": "__count__ nodes use this config",
|
"nodesUse_plural": "__count__ nodes use this config",
|
||||||
"addNewConfig": "Add new __type__ config node",
|
"addNewConfig": "Add new __type__ config node",
|
||||||
|
"editNode": "Edit __type__ node",
|
||||||
"editConfig": "Edit __type__ config node",
|
"editConfig": "Edit __type__ config node",
|
||||||
"addNewType": "Add new __type__...",
|
"addNewType": "Add new __type__...",
|
||||||
"errors": {
|
"errors": {
|
||||||
@ -193,7 +200,7 @@
|
|||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"info": {
|
"info": {
|
||||||
"name": "Information",
|
"name": "Node information",
|
||||||
"label": "info",
|
"label": "info",
|
||||||
"node": "Node",
|
"node": "Node",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
|
@ -36,10 +36,32 @@ function Flow(global,flow) {
|
|||||||
var id;
|
var id;
|
||||||
catchNodeMap = {};
|
catchNodeMap = {};
|
||||||
statusNodeMap = {};
|
statusNodeMap = {};
|
||||||
for (id in flow.configs) {
|
|
||||||
if (flow.configs.hasOwnProperty(id)) {
|
var configNodes = Object.keys(flow.configs);
|
||||||
|
var configNodeAttempts = {};
|
||||||
|
while(configNodes.length > 0) {
|
||||||
|
id = configNodes.shift();
|
||||||
node = flow.configs[id];
|
node = flow.configs[id];
|
||||||
if (!activeNodes[id]) {
|
if (!activeNodes[id]) {
|
||||||
|
var readyToCreate = true;
|
||||||
|
// This node doesn't exist.
|
||||||
|
// Check it doesn't reference another non-existent config node
|
||||||
|
for (var prop in node) {
|
||||||
|
if (node.hasOwnProperty(prop) && prop !== 'id' && prop !== 'wires' && prop !== '_users' && flow.configs[node[prop]]) {
|
||||||
|
if (!activeNodes[node[prop]]) {
|
||||||
|
// References a non-existent config node
|
||||||
|
// Add it to the back of the list to try again later
|
||||||
|
configNodes.push(id);
|
||||||
|
configNodeAttempts[id] = (configNodeAttempts[id]||0)+1;
|
||||||
|
if (configNodeAttempts[id] === 100) {
|
||||||
|
throw new Error("Circular config node dependency detected: "+id);
|
||||||
|
}
|
||||||
|
readyToCreate = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (readyToCreate) {
|
||||||
newNode = createNode(node.type,node);
|
newNode = createNode(node.type,node);
|
||||||
if (newNode) {
|
if (newNode) {
|
||||||
activeNodes[id] = newNode;
|
activeNodes[id] = newNode;
|
||||||
@ -47,6 +69,7 @@ function Flow(global,flow) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diff && diff.rewired) {
|
if (diff && diff.rewired) {
|
||||||
for (var j=0;j<diff.rewired.length;j++) {
|
for (var j=0;j<diff.rewired.length;j++) {
|
||||||
var rewireNode = activeNodes[diff.rewired[j]];
|
var rewireNode = activeNodes[diff.rewired[j]];
|
||||||
|
@ -230,6 +230,13 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var madeChange;
|
||||||
|
// Loop through the nodes looking for references to changed config nodes
|
||||||
|
// Repeat the loop if anything is marked as changed as it may need to be
|
||||||
|
// propagated to parent nodes.
|
||||||
|
// TODO: looping through all nodes every time is a bit inefficient - could be more targeted
|
||||||
|
do {
|
||||||
|
madeChange = false;
|
||||||
for (id in newConfig.allNodes) {
|
for (id in newConfig.allNodes) {
|
||||||
if (newConfig.allNodes.hasOwnProperty(id)) {
|
if (newConfig.allNodes.hasOwnProperty(id)) {
|
||||||
node = newConfig.allNodes[id];
|
node = newConfig.allNodes[id];
|
||||||
@ -240,21 +247,34 @@ module.exports = {
|
|||||||
// changed.
|
// changed.
|
||||||
if (changed[node[prop]] || removed[node[prop]]) {
|
if (changed[node[prop]] || removed[node[prop]]) {
|
||||||
if (!changed[node.id]) {
|
if (!changed[node.id]) {
|
||||||
|
madeChange = true;
|
||||||
changed[node.id] = node;
|
changed[node.id] = node;
|
||||||
|
// This node exists within subflow template
|
||||||
|
// Mark the template as having changed
|
||||||
if (newConfig.allNodes[node.z]) {
|
if (newConfig.allNodes[node.z]) {
|
||||||
changed[node.z] = newConfig.allNodes[node.z];
|
changed[node.z] = newConfig.allNodes[node.z];
|
||||||
if (changed[node.z].type === "subflow") {
|
if (changed[node.z].type === "subflow") {
|
||||||
changedSubflows[node.z] = changed[node.z];
|
changedSubflows[node.z] = changed[node.z];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(madeChange===true)
|
||||||
|
|
||||||
|
// Find any nodes that exist on a subflow template and remove from changed
|
||||||
|
// list as the parent subflow will now be marked as containing a change
|
||||||
|
for (id in newConfig.allNodes) {
|
||||||
|
if (newConfig.allNodes.hasOwnProperty(id)) {
|
||||||
|
node = newConfig.allNodes[id];
|
||||||
|
if (newConfig.allNodes[node.z] && newConfig.allNodes[node.z].type === "subflow") {
|
||||||
delete changed[node.id];
|
delete changed[node.id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Recursively mark all instances of changed subflows as changed
|
// Recursively mark all instances of changed subflows as changed
|
||||||
var changedSubflowStack = Object.keys(changedSubflows);
|
var changedSubflowStack = Object.keys(changedSubflows);
|
||||||
|
@ -45,7 +45,7 @@ describe('Flow', function() {
|
|||||||
|
|
||||||
var TestNode = function(n) {
|
var TestNode = function(n) {
|
||||||
Node.call(this,n);
|
Node.call(this,n);
|
||||||
createCount++;
|
this._index = createCount++;
|
||||||
this.scope = n.scope;
|
this.scope = n.scope;
|
||||||
var node = this;
|
var node = this;
|
||||||
this.foo = n.foo;
|
this.foo = n.foo;
|
||||||
@ -173,6 +173,61 @@ describe('Flow', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("instantiates config nodes in the right order",function(done) {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||||
|
{id:"2",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["3"]},
|
||||||
|
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||||
|
{id:"4",z:"t1",type:"test",foo:"5"}, // This node depends on #5
|
||||||
|
{id:"5",z:"t1",type:"test"}
|
||||||
|
]);
|
||||||
|
var flow = Flow.create(config,config.flows["t1"]);
|
||||||
|
flow.start();
|
||||||
|
|
||||||
|
Object.keys(flow.getActiveNodes()).should.have.length(5);
|
||||||
|
|
||||||
|
|
||||||
|
currentNodes.should.have.a.property("1");
|
||||||
|
currentNodes.should.have.a.property("2");
|
||||||
|
currentNodes.should.have.a.property("3");
|
||||||
|
currentNodes.should.have.a.property("4");
|
||||||
|
currentNodes.should.have.a.property("5");
|
||||||
|
|
||||||
|
currentNodes["1"].should.have.a.property("_index",2);
|
||||||
|
currentNodes["2"].should.have.a.property("_index",3);
|
||||||
|
currentNodes["3"].should.have.a.property("_index",4);
|
||||||
|
currentNodes["4"].should.have.a.property("_index",1);
|
||||||
|
currentNodes["5"].should.have.a.property("_index",0);
|
||||||
|
|
||||||
|
flow.stop().then(function() {
|
||||||
|
currentNodes.should.not.have.a.property("1");
|
||||||
|
currentNodes.should.not.have.a.property("2");
|
||||||
|
currentNodes.should.not.have.a.property("3");
|
||||||
|
currentNodes.should.not.have.a.property("4");
|
||||||
|
currentNodes.should.not.have.a.property("5");
|
||||||
|
stoppedNodes.should.have.a.property("1");
|
||||||
|
stoppedNodes.should.have.a.property("2");
|
||||||
|
stoppedNodes.should.have.a.property("3");
|
||||||
|
stoppedNodes.should.have.a.property("4");
|
||||||
|
stoppedNodes.should.have.a.property("5");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("detects dependency loops in config nodes",function() {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"node1",z:"t1",type:"test",foo:"node2"}, // This node depends on #5
|
||||||
|
{id:"node2",z:"t1",type:"test",foo:"node1"}
|
||||||
|
]);
|
||||||
|
var flow = Flow.create(config,config.flows["t1"]);
|
||||||
|
/*jshint immed: false */
|
||||||
|
(function(){
|
||||||
|
flow.start();
|
||||||
|
}).should.throw("Circular config node dependency detected: node1");
|
||||||
|
});
|
||||||
it("instantiates a subflow and stops it",function(done) {
|
it("instantiates a subflow and stops it",function(done) {
|
||||||
var config = flowUtils.parseConfig([
|
var config = flowUtils.parseConfig([
|
||||||
{id:"t1",type:"tab"},
|
{id:"t1",type:"tab"},
|
||||||
|
@ -308,7 +308,7 @@ describe('flows/util', function() {
|
|||||||
diffResult.linked.sort().should.eql(["3"]);
|
diffResult.linked.sort().should.eql(["3"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('identifies config nodes changes', function() {
|
it('identifies config nodes changes, node->config', function() {
|
||||||
var config = [
|
var config = [
|
||||||
{id:"1",type:"test",foo:"configNode",wires:[["2"]]},
|
{id:"1",type:"test",foo:"configNode",wires:[["2"]]},
|
||||||
{id:"2",type:"test",bar:"b",wires:[["3"]]},
|
{id:"2",type:"test",bar:"b",wires:[["3"]]},
|
||||||
@ -329,7 +329,30 @@ describe('flows/util', function() {
|
|||||||
diffResult.removed.should.have.length(0);
|
diffResult.removed.should.have.length(0);
|
||||||
diffResult.rewired.should.have.length(0);
|
diffResult.rewired.should.have.length(0);
|
||||||
diffResult.linked.sort().should.eql(["2","3"]);
|
diffResult.linked.sort().should.eql(["2","3"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('identifies config nodes changes, node->config->config', function() {
|
||||||
|
var config = [
|
||||||
|
{id:"1",type:"test",foo:"configNode1",wires:[["2"]]},
|
||||||
|
{id:"2",type:"test",bar:"b",wires:[["3"]]},
|
||||||
|
{id:"3",type:"test",foo:"a",wires:[]},
|
||||||
|
{id:"configNode1",foo:"configNode2",type:"testConfig"},
|
||||||
|
{id:"configNode2",type:"testConfig"}
|
||||||
|
];
|
||||||
|
var newConfig = clone(config);
|
||||||
|
newConfig[4].foo = "bar";
|
||||||
|
|
||||||
|
var originalConfig = flowUtil.parseConfig(config);
|
||||||
|
var changedConfig = flowUtil.parseConfig(newConfig);
|
||||||
|
|
||||||
|
originalConfig.missingTypes.should.have.length(0);
|
||||||
|
|
||||||
|
var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
|
||||||
|
diffResult.added.should.have.length(0);
|
||||||
|
diffResult.changed.sort().should.eql(["1","configNode1","configNode2"]);
|
||||||
|
diffResult.removed.should.have.length(0);
|
||||||
|
diffResult.rewired.should.have.length(0);
|
||||||
|
diffResult.linked.sort().should.eql(["2","3"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('marks a parent subflow as changed for an internal property change', function() {
|
it('marks a parent subflow as changed for an internal property change', function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user