|
|
|
|
@ -123,6 +123,7 @@ RED.view = (function() {
|
|
|
|
|
let suggestedLinks = [];
|
|
|
|
|
let suggestedJunctions = [];
|
|
|
|
|
|
|
|
|
|
let forceFullRedraw = false
|
|
|
|
|
// Note: these are the permitted status colour aliases. The actual RGB values
|
|
|
|
|
// are set in the CSS - flow.scss/colors.scss
|
|
|
|
|
const status_colours = {
|
|
|
|
|
@ -4018,6 +4019,7 @@ RED.view = (function() {
|
|
|
|
|
if (spacebarPressed) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
clearSuggestedFlow();
|
|
|
|
|
RED.contextMenu.hide();
|
|
|
|
|
evt = evt || d3.event;
|
|
|
|
|
if (evt === 1) {
|
|
|
|
|
@ -4441,9 +4443,9 @@ RED.view = (function() {
|
|
|
|
|
return tooltip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function portMouseOver(port,d,portType,portIndex) {
|
|
|
|
|
function portMouseOver(port,d,portType,portIndex, event) {
|
|
|
|
|
if (mouse_mode === RED.state.SELECTING_NODE) {
|
|
|
|
|
d3.event.stopPropagation();
|
|
|
|
|
(d3.event || event).stopPropagation();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (spacebarPressed) {
|
|
|
|
|
@ -4485,9 +4487,9 @@ RED.view = (function() {
|
|
|
|
|
}
|
|
|
|
|
port.classed("red-ui-flow-port-hovered",active);
|
|
|
|
|
}
|
|
|
|
|
function portMouseOut(port,d,portType,portIndex) {
|
|
|
|
|
function portMouseOut(port,d,portType,portIndex, event) {
|
|
|
|
|
if (mouse_mode === RED.state.SELECTING_NODE) {
|
|
|
|
|
d3.event.stopPropagation();
|
|
|
|
|
(d3.event || event).stopPropagation();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
clearTimeout(portLabelHoverTimeout);
|
|
|
|
|
@ -4608,6 +4610,7 @@ RED.view = (function() {
|
|
|
|
|
if (spacebarPressed) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
clearSuggestedFlow()
|
|
|
|
|
focusView();
|
|
|
|
|
RED.contextMenu.hide();
|
|
|
|
|
if (d3.event.button === 1) {
|
|
|
|
|
@ -5239,6 +5242,186 @@ RED.view = (function() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildSubflowPort (d) {
|
|
|
|
|
const NODE_TYPE = d.direction === "in" ? PORT_TYPE_INPUT : PORT_TYPE_OUTPUT;
|
|
|
|
|
// PORT_TYPE is the 'opposite' of NODE_TYPE
|
|
|
|
|
const PORT_TYPE = NODE_TYPE === PORT_TYPE_INPUT ? PORT_TYPE_OUTPUT : PORT_TYPE_INPUT;
|
|
|
|
|
var node = d3.select(this);
|
|
|
|
|
var nodeContents = document.createDocumentFragment();
|
|
|
|
|
|
|
|
|
|
d.h = 40;
|
|
|
|
|
d.resize = true;
|
|
|
|
|
d.dirty = true;
|
|
|
|
|
|
|
|
|
|
var mainRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
|
|
|
|
mainRect.__data__ = d;
|
|
|
|
|
mainRect.setAttribute("class", "red-ui-flow-subflow-port");
|
|
|
|
|
mainRect.setAttribute("rx", 8);
|
|
|
|
|
mainRect.setAttribute("ry", 8);
|
|
|
|
|
mainRect.setAttribute("width", 40);
|
|
|
|
|
mainRect.setAttribute("height", 40);
|
|
|
|
|
node[0][0].__mainRect__ = mainRect;
|
|
|
|
|
d3.select(mainRect)
|
|
|
|
|
.on("mouseup",nodeMouseUp)
|
|
|
|
|
.on("mousedown",nodeMouseDown)
|
|
|
|
|
.on("touchstart",nodeTouchStart)
|
|
|
|
|
.on("touchend",nodeTouchEnd)
|
|
|
|
|
nodeContents.appendChild(mainRect);
|
|
|
|
|
|
|
|
|
|
const port_label_group = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
|
|
|
port_label_group.setAttribute("x",0);
|
|
|
|
|
port_label_group.setAttribute("y",0);
|
|
|
|
|
node[0][0].__portLabelGroup__ = port_label_group;
|
|
|
|
|
|
|
|
|
|
const port_label = document.createElementNS("http://www.w3.org/2000/svg","text");
|
|
|
|
|
port_label.setAttribute("class","red-ui-flow-port-label");
|
|
|
|
|
port_label.style["font-size"] = "10px";
|
|
|
|
|
port_label.textContent = NODE_TYPE === PORT_TYPE_INPUT? "input" : "output";
|
|
|
|
|
port_label_group.appendChild(port_label);
|
|
|
|
|
node[0][0].__portLabel__ = port_label;
|
|
|
|
|
|
|
|
|
|
if (NODE_TYPE === PORT_TYPE_OUTPUT) {
|
|
|
|
|
const port_number = document.createElementNS("http://www.w3.org/2000/svg","text");
|
|
|
|
|
port_number.setAttribute("class","red-ui-flow-port-label red-ui-flow-port-index");
|
|
|
|
|
port_number.setAttribute("x",0);
|
|
|
|
|
port_number.setAttribute("y",0);
|
|
|
|
|
port_number.textContent = d.i+1;
|
|
|
|
|
port_label_group.appendChild(port_number);
|
|
|
|
|
node[0][0].__portNumber__ = port_number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const port_border = document.createElementNS("http://www.w3.org/2000/svg","path");
|
|
|
|
|
port_border.setAttribute("d","M 40 1 l 0 38")
|
|
|
|
|
port_border.setAttribute("class", "red-ui-flow-node-icon-shade-border")
|
|
|
|
|
port_label_group.appendChild(port_border);
|
|
|
|
|
node[0][0].__portBorder__ = port_border;
|
|
|
|
|
|
|
|
|
|
nodeContents.appendChild(port_label_group);
|
|
|
|
|
|
|
|
|
|
var text = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
|
|
|
text.setAttribute("class","red-ui-flow-port-label");
|
|
|
|
|
text.setAttribute("transform","translate(38,0)");
|
|
|
|
|
text.setAttribute('style', 'fill : #888'); // hard coded here!
|
|
|
|
|
node[0][0].__textGroup__ = text;
|
|
|
|
|
nodeContents.append(text);
|
|
|
|
|
|
|
|
|
|
var portEl = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
|
|
|
portEl.setAttribute('transform','translate(-5,15)')
|
|
|
|
|
|
|
|
|
|
var port = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
|
|
|
|
port.setAttribute("class","red-ui-flow-port");
|
|
|
|
|
port.setAttribute("rx",3);
|
|
|
|
|
port.setAttribute("ry",3);
|
|
|
|
|
port.setAttribute("width",10);
|
|
|
|
|
port.setAttribute("height",10);
|
|
|
|
|
portEl.appendChild(port);
|
|
|
|
|
port.__data__ = d;
|
|
|
|
|
|
|
|
|
|
d3.select(port)
|
|
|
|
|
.on("mousedown", function(d,i){portMouseDown(d,PORT_TYPE,0);} )
|
|
|
|
|
.on("touchstart", function(d,i){portMouseDown(d,PORT_TYPE,0);d3.event.preventDefault();} )
|
|
|
|
|
.on("mouseup", function(d,i){portMouseUp(d,PORT_TYPE,0);})
|
|
|
|
|
.on("touchend",function(d,i){portMouseUp(d,PORT_TYPE,0);d3.event.preventDefault();} )
|
|
|
|
|
.on("mouseover",function(d){portMouseOver(d3.select(this),d,PORT_TYPE,0);})
|
|
|
|
|
.on("mouseout",function(d){portMouseOut(d3.select(this),d,PORT_TYPE,0);});
|
|
|
|
|
|
|
|
|
|
node[0][0].__port__ = portEl
|
|
|
|
|
nodeContents.appendChild(portEl);
|
|
|
|
|
node[0][0].appendChild(nodeContents);
|
|
|
|
|
}
|
|
|
|
|
function updateSubflowPort (d) {
|
|
|
|
|
if (d.dirty) {
|
|
|
|
|
const port_height = 40;
|
|
|
|
|
const NODE_TYPE = d.direction === "in" ? PORT_TYPE_INPUT : PORT_TYPE_OUTPUT;
|
|
|
|
|
// PORT_TYPE is the 'opposite' of NODE_TYPE
|
|
|
|
|
const PORT_TYPE = NODE_TYPE === PORT_TYPE_INPUT ? PORT_TYPE_OUTPUT : PORT_TYPE_INPUT;
|
|
|
|
|
|
|
|
|
|
var label = getPortLabel(activeSubflow, NODE_TYPE, d.i) || "";
|
|
|
|
|
var hideLabel = (label.length < 1)
|
|
|
|
|
var labelParts;
|
|
|
|
|
if (d.resize || this.__hideLabel__ !== hideLabel || this.__label__ !== label) {
|
|
|
|
|
labelParts = getLabelParts(label, "red-ui-flow-node-label");
|
|
|
|
|
if (labelParts.lines.length !== this.__labelLineCount__ || this.__label__ !== label) {
|
|
|
|
|
d.resize = true;
|
|
|
|
|
}
|
|
|
|
|
this.__label__ = label;
|
|
|
|
|
this.__labelLineCount__ = labelParts.lines.length;
|
|
|
|
|
|
|
|
|
|
if (hideLabel) {
|
|
|
|
|
d.h = Math.max(port_height,(d.outputs || 0) * 15);
|
|
|
|
|
} else {
|
|
|
|
|
d.h = Math.max(6+24*labelParts.lines.length,(d.outputs || 0) * 15, port_height);
|
|
|
|
|
}
|
|
|
|
|
this.__hideLabel__ = hideLabel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (d.resize) {
|
|
|
|
|
var ow = d.w;
|
|
|
|
|
if (hideLabel) {
|
|
|
|
|
d.w = port_height;
|
|
|
|
|
} else {
|
|
|
|
|
d.w = Math.max(port_height,20*(Math.ceil((labelParts.width+50+7)/20)) );
|
|
|
|
|
}
|
|
|
|
|
if (ow !== undefined) {
|
|
|
|
|
d.x += (d.w-ow)/2;
|
|
|
|
|
}
|
|
|
|
|
d.resize = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setAttribute("transform", "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")");
|
|
|
|
|
// This might be the first redraw after a node has been click-dragged to start a move.
|
|
|
|
|
// So its selected state might have changed since the last redraw.
|
|
|
|
|
this.classList.toggle("red-ui-flow-node-selected", !!d.selected )
|
|
|
|
|
if (mouse_mode != RED.state.MOVING_ACTIVE) {
|
|
|
|
|
this.classList.toggle("red-ui-flow-node-disabled", d.d === true);
|
|
|
|
|
this.__mainRect__.setAttribute("width", d.w)
|
|
|
|
|
this.__mainRect__.setAttribute("height", d.h)
|
|
|
|
|
this.__mainRect__.classList.toggle("red-ui-flow-node-highlighted",!!d.highlighted );
|
|
|
|
|
|
|
|
|
|
if (labelParts) {
|
|
|
|
|
// The label has changed
|
|
|
|
|
var sa = labelParts.lines;
|
|
|
|
|
var sn = labelParts.lines.length;
|
|
|
|
|
var textLines = this.__textGroup__.childNodes;
|
|
|
|
|
while(textLines.length > sn) {
|
|
|
|
|
textLines[textLines.length-1].remove();
|
|
|
|
|
}
|
|
|
|
|
for (var i=0; i<sn; i++) {
|
|
|
|
|
if (i===textLines.length) {
|
|
|
|
|
var line = document.createElementNS("http://www.w3.org/2000/svg","text");
|
|
|
|
|
line.setAttribute("class","red-ui-flow-node-label-text");
|
|
|
|
|
line.setAttribute("x",0);
|
|
|
|
|
line.setAttribute("y",i*24);
|
|
|
|
|
this.__textGroup__.appendChild(line);
|
|
|
|
|
}
|
|
|
|
|
textLines[i].textContent = sa[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var textClass = "red-ui-flow-node-label"+(hideLabel?" hide":"");
|
|
|
|
|
this.__textGroup__.setAttribute("class", textClass);
|
|
|
|
|
var yp = d.h / 2 - (this.__labelLineCount__ / 2) * 24 + 13;
|
|
|
|
|
|
|
|
|
|
// this.__textGroup__.classList.remove("red-ui-flow-node-label-right");
|
|
|
|
|
this.__textGroup__.setAttribute("transform", "translate(48,"+yp+")");
|
|
|
|
|
|
|
|
|
|
this.__portBorder__.setAttribute("d","M 40 1 l 0 "+(hideLabel?0:(d.h - 2)));
|
|
|
|
|
const portX = PORT_TYPE === PORT_TYPE_OUTPUT ? d.w - 5 : -5
|
|
|
|
|
this.__port__.setAttribute("transform","translate("+portX+","+((d.h/2)-5)+")");
|
|
|
|
|
if (NODE_TYPE === PORT_TYPE_OUTPUT) {
|
|
|
|
|
this.__portLabel__.setAttribute("transform","translate(20,"+((d.h/2)-8)+")");
|
|
|
|
|
this.__portNumber__.setAttribute("transform","translate(20,"+((d.h/2)+7)+")");
|
|
|
|
|
this.__portNumber__.textContent = d.i+1;
|
|
|
|
|
} else {
|
|
|
|
|
this.__portLabel__.setAttribute("transform","translate(20,"+(d.h/2)+")");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
d.dirty = false;
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _redraw() {
|
|
|
|
|
eventLayer.attr("transform","scale("+scaleFactor+")");
|
|
|
|
|
outer.attr("width", space_width*scaleFactor).attr("height", space_height*scaleFactor);
|
|
|
|
|
@ -5253,125 +5436,26 @@ RED.view = (function() {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Don't bother redrawing nodes if we're drawing links
|
|
|
|
|
if (showAllLinkPorts !== -1 || mouse_mode != RED.state.JOINING) {
|
|
|
|
|
|
|
|
|
|
if (forceFullRedraw || showAllLinkPorts !== -1 || mouse_mode != RED.state.JOINING) {
|
|
|
|
|
forceFullRedraw = false
|
|
|
|
|
var dirtyNodes = {};
|
|
|
|
|
|
|
|
|
|
if (activeSubflow) {
|
|
|
|
|
var subflowOutputs = nodeLayer.selectAll(".red-ui-flow-subflow-port-output").data(activeSubflow.out,function(d,i){ return d.id;});
|
|
|
|
|
subflowOutputs.exit().remove();
|
|
|
|
|
var outGroup = subflowOutputs.enter().insert("svg:g").attr("class","red-ui-flow-node red-ui-flow-subflow-port-output")
|
|
|
|
|
outGroup.each(function(d,i) {
|
|
|
|
|
var node = d3.select(this);
|
|
|
|
|
var nodeContents = document.createDocumentFragment();
|
|
|
|
|
|
|
|
|
|
d.h = 40;
|
|
|
|
|
d.resize = true;
|
|
|
|
|
d.dirty = true;
|
|
|
|
|
|
|
|
|
|
var mainRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
|
|
|
|
mainRect.__data__ = d;
|
|
|
|
|
mainRect.setAttribute("class", "red-ui-flow-subflow-port");
|
|
|
|
|
mainRect.setAttribute("rx", 8);
|
|
|
|
|
mainRect.setAttribute("ry", 8);
|
|
|
|
|
mainRect.setAttribute("width", 40);
|
|
|
|
|
mainRect.setAttribute("height", 40);
|
|
|
|
|
node[0][0].__mainRect__ = mainRect;
|
|
|
|
|
d3.select(mainRect)
|
|
|
|
|
.on("mouseup",nodeMouseUp)
|
|
|
|
|
.on("mousedown",nodeMouseDown)
|
|
|
|
|
.on("touchstart",nodeTouchStart)
|
|
|
|
|
.on("touchend",nodeTouchEnd)
|
|
|
|
|
nodeContents.appendChild(mainRect);
|
|
|
|
|
|
|
|
|
|
var output_groupEl = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
|
|
|
output_groupEl.setAttribute("x",0);
|
|
|
|
|
output_groupEl.setAttribute("y",0);
|
|
|
|
|
node[0][0].__outputLabelGroup__ = output_groupEl;
|
|
|
|
|
|
|
|
|
|
var output_output = document.createElementNS("http://www.w3.org/2000/svg","text");
|
|
|
|
|
output_output.setAttribute("class","red-ui-flow-port-label");
|
|
|
|
|
output_output.style["font-size"] = "10px";
|
|
|
|
|
output_output.textContent = "output";
|
|
|
|
|
output_groupEl.appendChild(output_output);
|
|
|
|
|
node[0][0].__outputOutput__ = output_output;
|
|
|
|
|
|
|
|
|
|
var output_number = document.createElementNS("http://www.w3.org/2000/svg","text");
|
|
|
|
|
output_number.setAttribute("class","red-ui-flow-port-label red-ui-flow-port-index");
|
|
|
|
|
output_number.setAttribute("x",0);
|
|
|
|
|
output_number.setAttribute("y",0);
|
|
|
|
|
output_number.textContent = d.i+1;
|
|
|
|
|
output_groupEl.appendChild(output_number);
|
|
|
|
|
node[0][0].__outputNumber__ = output_number;
|
|
|
|
|
|
|
|
|
|
var output_border = document.createElementNS("http://www.w3.org/2000/svg","path");
|
|
|
|
|
output_border.setAttribute("d","M 40 1 l 0 38")
|
|
|
|
|
output_border.setAttribute("class", "red-ui-flow-node-icon-shade-border")
|
|
|
|
|
output_groupEl.appendChild(output_border);
|
|
|
|
|
node[0][0].__outputBorder__ = output_border;
|
|
|
|
|
|
|
|
|
|
nodeContents.appendChild(output_groupEl);
|
|
|
|
|
|
|
|
|
|
var text = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
|
|
|
text.setAttribute("class","red-ui-flow-port-label");
|
|
|
|
|
text.setAttribute("transform","translate(38,0)");
|
|
|
|
|
text.setAttribute('style', 'fill : #888'); // hard coded here!
|
|
|
|
|
node[0][0].__textGroup__ = text;
|
|
|
|
|
nodeContents.append(text);
|
|
|
|
|
|
|
|
|
|
var portEl = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
|
|
|
portEl.setAttribute('transform','translate(-5,15)')
|
|
|
|
|
|
|
|
|
|
var port = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
|
|
|
|
port.setAttribute("class","red-ui-flow-port");
|
|
|
|
|
port.setAttribute("rx",3);
|
|
|
|
|
port.setAttribute("ry",3);
|
|
|
|
|
port.setAttribute("width",10);
|
|
|
|
|
port.setAttribute("height",10);
|
|
|
|
|
portEl.appendChild(port);
|
|
|
|
|
port.__data__ = d;
|
|
|
|
|
|
|
|
|
|
d3.select(port)
|
|
|
|
|
.on("mousedown", function(d,i){portMouseDown(d,PORT_TYPE_INPUT,0);} )
|
|
|
|
|
.on("touchstart", function(d,i){portMouseDown(d,PORT_TYPE_INPUT,0);d3.event.preventDefault();} )
|
|
|
|
|
.on("mouseup", function(d,i){portMouseUp(d,PORT_TYPE_INPUT,0);})
|
|
|
|
|
.on("touchend",function(d,i){portMouseUp(d,PORT_TYPE_INPUT,0);d3.event.preventDefault();} )
|
|
|
|
|
.on("mouseover",function(d){portMouseOver(d3.select(this),d,PORT_TYPE_INPUT,0);})
|
|
|
|
|
.on("mouseout",function(d){portMouseOut(d3.select(this),d,PORT_TYPE_INPUT,0);});
|
|
|
|
|
|
|
|
|
|
node[0][0].__port__ = portEl
|
|
|
|
|
nodeContents.appendChild(portEl);
|
|
|
|
|
node[0][0].appendChild(nodeContents);
|
|
|
|
|
});
|
|
|
|
|
outGroup.each(buildSubflowPort);
|
|
|
|
|
|
|
|
|
|
var subflowInputs = nodeLayer.selectAll(".red-ui-flow-subflow-port-input").data(activeSubflow.in,function(d,i){ return d.id;});
|
|
|
|
|
subflowInputs.exit().remove();
|
|
|
|
|
var inGroup = subflowInputs.enter().insert("svg:g").attr("class","red-ui-flow-node red-ui-flow-subflow-port-input").attr("transform",function(d) { return "translate("+(d.x-20)+","+(d.y-20)+")"});
|
|
|
|
|
inGroup.each(function(d,i) {
|
|
|
|
|
d.w=40;
|
|
|
|
|
d.h=40;
|
|
|
|
|
});
|
|
|
|
|
inGroup.append("rect").attr("class","red-ui-flow-subflow-port").attr("rx",8).attr("ry",8).attr("width",40).attr("height",40)
|
|
|
|
|
// TODO: This is exactly the same set of handlers used for regular nodes - DRY
|
|
|
|
|
.on("mouseup",nodeMouseUp)
|
|
|
|
|
.on("mousedown",nodeMouseDown)
|
|
|
|
|
.on("touchstart",nodeTouchStart)
|
|
|
|
|
.on("touchend", nodeTouchEnd);
|
|
|
|
|
|
|
|
|
|
inGroup.append("g").attr('transform','translate(35,15)').append("rect").attr("class","red-ui-flow-port").attr("rx",3).attr("ry",3).attr("width",10).attr("height",10)
|
|
|
|
|
.on("mousedown", function(d,i){portMouseDown(d,PORT_TYPE_OUTPUT,i);} )
|
|
|
|
|
.on("touchstart", function(d,i){portMouseDown(d,PORT_TYPE_OUTPUT,i);d3.event.preventDefault();} )
|
|
|
|
|
.on("mouseup", function(d,i){portMouseUp(d,PORT_TYPE_OUTPUT,i);})
|
|
|
|
|
.on("touchend",function(d,i){portMouseUp(d,PORT_TYPE_OUTPUT,i);d3.event.preventDefault();} )
|
|
|
|
|
.on("mouseover",function(d){portMouseOver(d3.select(this),d,PORT_TYPE_OUTPUT,0);})
|
|
|
|
|
.on("mouseout",function(d) {portMouseOut(d3.select(this),d,PORT_TYPE_OUTPUT,0);});
|
|
|
|
|
|
|
|
|
|
inGroup.append("svg:text").attr("class","red-ui-flow-port-label").attr("x",18).attr("y",20).style("font-size","10px").text("input");
|
|
|
|
|
inGroup.each(buildSubflowPort);
|
|
|
|
|
|
|
|
|
|
var subflowStatus = nodeLayer.selectAll(".red-ui-flow-subflow-port-status").data(activeSubflow.status?[activeSubflow.status]:[],function(d,i){ return d.id;});
|
|
|
|
|
subflowStatus.exit().remove();
|
|
|
|
|
|
|
|
|
|
var statusGroup = subflowStatus.enter().insert("svg:g").attr("class","red-ui-flow-node red-ui-flow-subflow-port-status").attr("transform",function(d) { return "translate("+(d.x-20)+","+(d.y-20)+")"});
|
|
|
|
|
// TODO: use buildSubflowPort/updateSubflowPort for status port
|
|
|
|
|
statusGroup.each(function(d,i) {
|
|
|
|
|
d.w=40;
|
|
|
|
|
d.h=40;
|
|
|
|
|
@ -5393,104 +5477,16 @@ RED.view = (function() {
|
|
|
|
|
|
|
|
|
|
statusGroup.append("svg:text").attr("class","red-ui-flow-port-label").attr("x",22).attr("y",20).style("font-size","10px").text("status");
|
|
|
|
|
|
|
|
|
|
subflowOutputs.each(function(d,i) {
|
|
|
|
|
if (d.dirty) {
|
|
|
|
|
|
|
|
|
|
var port_height = 40;
|
|
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
|
var thisNode = d3.select(this);
|
|
|
|
|
|
|
|
|
|
subflowOutputs.each(function (d,i) {
|
|
|
|
|
if (updateSubflowPort.call(this, d)) {
|
|
|
|
|
dirtyNodes[d.id] = d;
|
|
|
|
|
|
|
|
|
|
var label = getPortLabel(activeSubflow, PORT_TYPE_OUTPUT, d.i) || "";
|
|
|
|
|
var hideLabel = (label.length < 1)
|
|
|
|
|
|
|
|
|
|
var labelParts;
|
|
|
|
|
if (d.resize || this.__hideLabel__ !== hideLabel || this.__label__ !== label) {
|
|
|
|
|
labelParts = getLabelParts(label, "red-ui-flow-node-label");
|
|
|
|
|
if (labelParts.lines.length !== this.__labelLineCount__ || this.__label__ !== label) {
|
|
|
|
|
d.resize = true;
|
|
|
|
|
}
|
|
|
|
|
this.__label__ = label;
|
|
|
|
|
this.__labelLineCount__ = labelParts.lines.length;
|
|
|
|
|
|
|
|
|
|
if (hideLabel) {
|
|
|
|
|
d.h = Math.max(port_height,(d.outputs || 0) * 15);
|
|
|
|
|
} else {
|
|
|
|
|
d.h = Math.max(6+24*labelParts.lines.length,(d.outputs || 0) * 15, port_height);
|
|
|
|
|
}
|
|
|
|
|
this.__hideLabel__ = hideLabel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (d.resize) {
|
|
|
|
|
var ow = d.w;
|
|
|
|
|
if (hideLabel) {
|
|
|
|
|
d.w = port_height;
|
|
|
|
|
} else {
|
|
|
|
|
d.w = Math.max(port_height,20*(Math.ceil((labelParts.width+50+7)/20)) );
|
|
|
|
|
}
|
|
|
|
|
if (ow !== undefined) {
|
|
|
|
|
d.x += (d.w-ow)/2;
|
|
|
|
|
}
|
|
|
|
|
d.resize = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setAttribute("transform", "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")");
|
|
|
|
|
// This might be the first redraw after a node has been click-dragged to start a move.
|
|
|
|
|
// So its selected state might have changed since the last redraw.
|
|
|
|
|
this.classList.toggle("red-ui-flow-node-selected", !!d.selected )
|
|
|
|
|
if (mouse_mode != RED.state.MOVING_ACTIVE) {
|
|
|
|
|
this.classList.toggle("red-ui-flow-node-disabled", d.d === true);
|
|
|
|
|
this.__mainRect__.setAttribute("width", d.w)
|
|
|
|
|
this.__mainRect__.setAttribute("height", d.h)
|
|
|
|
|
this.__mainRect__.classList.toggle("red-ui-flow-node-highlighted",!!d.highlighted );
|
|
|
|
|
|
|
|
|
|
if (labelParts) {
|
|
|
|
|
// The label has changed
|
|
|
|
|
var sa = labelParts.lines;
|
|
|
|
|
var sn = labelParts.lines.length;
|
|
|
|
|
var textLines = this.__textGroup__.childNodes;
|
|
|
|
|
while(textLines.length > sn) {
|
|
|
|
|
textLines[textLines.length-1].remove();
|
|
|
|
|
}
|
|
|
|
|
for (var i=0; i<sn; i++) {
|
|
|
|
|
if (i===textLines.length) {
|
|
|
|
|
var line = document.createElementNS("http://www.w3.org/2000/svg","text");
|
|
|
|
|
line.setAttribute("class","red-ui-flow-node-label-text");
|
|
|
|
|
line.setAttribute("x",0);
|
|
|
|
|
line.setAttribute("y",i*24);
|
|
|
|
|
this.__textGroup__.appendChild(line);
|
|
|
|
|
}
|
|
|
|
|
textLines[i].textContent = sa[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var textClass = "red-ui-flow-node-label"+(hideLabel?" hide":"");
|
|
|
|
|
this.__textGroup__.setAttribute("class", textClass);
|
|
|
|
|
var yp = d.h / 2 - (this.__labelLineCount__ / 2) * 24 + 13;
|
|
|
|
|
|
|
|
|
|
// this.__textGroup__.classList.remove("red-ui-flow-node-label-right");
|
|
|
|
|
this.__textGroup__.setAttribute("transform", "translate(48,"+yp+")");
|
|
|
|
|
|
|
|
|
|
this.__outputBorder__.setAttribute("d","M 40 1 l 0 "+(hideLabel?0:(d.h - 2)));
|
|
|
|
|
this.__port__.setAttribute("transform","translate(-5,"+((d.h/2)-5)+")");
|
|
|
|
|
this.__outputOutput__.setAttribute("transform","translate(20,"+((d.h/2)-8)+")");
|
|
|
|
|
this.__outputNumber__.setAttribute("transform","translate(20,"+((d.h/2)+7)+")");
|
|
|
|
|
this.__outputNumber__.textContent = d.i+1;
|
|
|
|
|
}
|
|
|
|
|
d.dirty = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
subflowInputs.each(function(d,i) {
|
|
|
|
|
if (d.dirty) {
|
|
|
|
|
var input = d3.select(this);
|
|
|
|
|
input.classed("red-ui-flow-node-selected",function(d) { return d.selected; })
|
|
|
|
|
input.attr("transform", function(d) { return "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")"; });
|
|
|
|
|
})
|
|
|
|
|
subflowInputs.each(function (d,i) {
|
|
|
|
|
if (updateSubflowPort.call(this, d)) {
|
|
|
|
|
dirtyNodes[d.id] = d;
|
|
|
|
|
d.dirty = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
subflowStatus.each(function(d,i) {
|
|
|
|
|
if (d.dirty) {
|
|
|
|
|
var output = d3.select(this);
|
|
|
|
|
@ -7544,7 +7540,6 @@ RED.view = (function() {
|
|
|
|
|
refreshSuggestedFlow();
|
|
|
|
|
} else { // Anything else; clear the suggestion
|
|
|
|
|
clearSuggestedFlow();
|
|
|
|
|
RED.view.redraw(true);
|
|
|
|
|
// manually push the event to the keyboard handler
|
|
|
|
|
RED.keyboard.handle(evt)
|
|
|
|
|
}
|
|
|
|
|
@ -7553,7 +7548,6 @@ RED.view = (function() {
|
|
|
|
|
if (suggestion.clickToApply) {
|
|
|
|
|
$(window).on('mousedown.suggestedFlow', function (evnt) {
|
|
|
|
|
clearSuggestedFlow();
|
|
|
|
|
RED.view.redraw(true);
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -7574,12 +7568,16 @@ RED.view = (function() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function clearSuggestedFlow () {
|
|
|
|
|
$(window).off('mousedown.suggestedFlow');
|
|
|
|
|
$(window).off('keydown.suggestedFlow')
|
|
|
|
|
RED.keyboard.enable()
|
|
|
|
|
currentSuggestion = null
|
|
|
|
|
suggestedNodes = []
|
|
|
|
|
suggestedLinks = []
|
|
|
|
|
if (currentSuggestion) {
|
|
|
|
|
$(window).off('mousedown.suggestedFlow');
|
|
|
|
|
$(window).off('keydown.suggestedFlow')
|
|
|
|
|
RED.keyboard.enable()
|
|
|
|
|
currentSuggestion = null
|
|
|
|
|
suggestedNodes = []
|
|
|
|
|
suggestedLinks = []
|
|
|
|
|
forceFullRedraw = true
|
|
|
|
|
RED.view.redraw(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function applySuggestedFlow () {
|
|
|
|
|
|