mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
[groups] add basic group functionality to editor
This commit is contained in:
parent
c9ad5bea93
commit
86ce5c591b
@ -177,6 +177,7 @@ module.exports = function(grunt) {
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/group.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
|
||||
|
@ -61,6 +61,7 @@
|
||||
"shift-down": "core:step-selection-down",
|
||||
"shift-left": "core:step-selection-left",
|
||||
"ctrl-shift-j": "core:show-previous-tab",
|
||||
"ctrl-shift-k": "core:show-next-tab"
|
||||
"ctrl-shift-k": "core:show-next-tab",
|
||||
"ctrl-shift-g": "core:group-selection"
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ RED.nodes = (function() {
|
||||
var subflows = {};
|
||||
var loadedFlowVersion = null;
|
||||
|
||||
var groups = {};
|
||||
var groupsByZ = {};
|
||||
|
||||
var initialLoad;
|
||||
|
||||
var dirty = false;
|
||||
@ -1444,6 +1447,14 @@ RED.nodes = (function() {
|
||||
// var loadedFlowVersion = null;
|
||||
}
|
||||
|
||||
function addGroup(group) {
|
||||
groupsByZ[group.z] = groupsByZ[group.z] || [];
|
||||
groupsByZ[group.z].push(group);
|
||||
groups[group.id] = group;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
RED.events.on("registry:node-type-added",function(type) {
|
||||
@ -1539,6 +1550,10 @@ RED.nodes = (function() {
|
||||
subflow: getSubflow,
|
||||
subflowContains: subflowContains,
|
||||
|
||||
addGroup: addGroup,
|
||||
group: function(id) { return groups[id] },
|
||||
groups: function(z) { return groupsByZ[z] },
|
||||
|
||||
eachNode: function(cb) {
|
||||
for (var n=0;n<nodes.length;n++) {
|
||||
if (cb(nodes[n]) === false) {
|
||||
|
@ -524,6 +524,7 @@ var RED = (function() {
|
||||
}
|
||||
|
||||
RED.subflow.init();
|
||||
RED.group.init();
|
||||
RED.clipboard.init();
|
||||
RED.search.init();
|
||||
RED.actionList.init();
|
||||
|
@ -514,7 +514,9 @@ RED.editor = (function() {
|
||||
for (var i=editStack.length-1;i<editStack.length;i++) {
|
||||
var node = editStack[i];
|
||||
label = node.type;
|
||||
if (node.type === '_expression') {
|
||||
if (node.type === 'group') {
|
||||
label = RED._("subflow.editGroup",{name:RED.utils.sanitize(node.name||node.id)});
|
||||
} else if (node.type === '_expression') {
|
||||
label = RED._("expressionEditor.title");
|
||||
} else if (node.type === '_js') {
|
||||
label = RED._("jsEditor.title");
|
||||
@ -2453,6 +2455,249 @@ RED.editor = (function() {
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
|
||||
function showEditGroupDialog(group) {
|
||||
var editing_node = group;
|
||||
editStack.push(group);
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var nodeInfoEditor;
|
||||
var finishedBuilding = false;
|
||||
var trayOptions = {
|
||||
title: getEditStackTitle(),
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
class: "primary",
|
||||
text: RED._("common.label.done"),
|
||||
click: function() {
|
||||
var changes = {};
|
||||
var changed = false;
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
var d;
|
||||
var outputMap;
|
||||
|
||||
if (editing_node._def.oneditsave) {
|
||||
var oldValues = {};
|
||||
for (d in editing_node._def.defaults) {
|
||||
if (editing_node._def.defaults.hasOwnProperty(d)) {
|
||||
if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
|
||||
oldValues[d] = editing_node[d];
|
||||
} else {
|
||||
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
var rc = editing_node._def.oneditsave.call(editing_node);
|
||||
if (rc === true) {
|
||||
changed = true;
|
||||
}
|
||||
} catch(err) {
|
||||
console.log("oneditsave",editing_node.id,editing_node.type,err.toString());
|
||||
}
|
||||
|
||||
for (d in editing_node._def.defaults) {
|
||||
if (editing_node._def.defaults.hasOwnProperty(d)) {
|
||||
if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") {
|
||||
if (oldValues[d] !== editing_node[d]) {
|
||||
changes[d] = oldValues[d];
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) {
|
||||
changes[d] = oldValues[d];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var newValue;
|
||||
if (editing_node._def.defaults) {
|
||||
for (d in editing_node._def.defaults) {
|
||||
if (editing_node._def.defaults.hasOwnProperty(d)) {
|
||||
var input = $("#node-input-"+d);
|
||||
if (input.attr('type') === "checkbox") {
|
||||
newValue = input.prop('checked');
|
||||
} else if (input.prop("nodeName") === "select" && input.attr("multiple") === "multiple") {
|
||||
// An empty select-multiple box returns null.
|
||||
// Need to treat that as an empty array.
|
||||
newValue = input.val();
|
||||
if (newValue == null) {
|
||||
newValue = [];
|
||||
}
|
||||
} else if ("format" in editing_node._def.defaults[d] && editing_node._def.defaults[d].format !== "" && input[0].nodeName === "DIV") {
|
||||
newValue = input.text();
|
||||
} else {
|
||||
newValue = input.val();
|
||||
}
|
||||
if (newValue != null) {
|
||||
if (editing_node._def.defaults[d].type) {
|
||||
if (newValue == "_ADD_") {
|
||||
newValue = "";
|
||||
}
|
||||
}
|
||||
if (editing_node[d] != newValue) {
|
||||
if (editing_node._def.defaults[d].type) {
|
||||
// Change to a related config node
|
||||
var configNode = RED.nodes.node(editing_node[d]);
|
||||
if (configNode) {
|
||||
var users = configNode.users;
|
||||
users.splice(users.indexOf(editing_node),1);
|
||||
}
|
||||
configNode = RED.nodes.node(newValue);
|
||||
if (configNode) {
|
||||
configNode.users.push(editing_node);
|
||||
}
|
||||
}
|
||||
changes[d] = editing_node[d];
|
||||
editing_node[d] = newValue;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var oldInfo = editing_node.info;
|
||||
if (nodeInfoEditor) {
|
||||
var newInfo = nodeInfoEditor.getValue();
|
||||
if (!!oldInfo) {
|
||||
// Has existing info property
|
||||
if (newInfo.trim() === "") {
|
||||
// New value is blank - remove the property
|
||||
changed = true;
|
||||
changes.info = oldInfo;
|
||||
delete editing_node.info;
|
||||
} else if (newInfo !== oldInfo) {
|
||||
// New value is different
|
||||
changed = true;
|
||||
changes.info = oldInfo;
|
||||
editing_node.info = newInfo;
|
||||
}
|
||||
} else {
|
||||
// No existing info
|
||||
if (newInfo.trim() !== "") {
|
||||
// New value is not blank
|
||||
changed = true;
|
||||
changes.info = undefined;
|
||||
editing_node.info = newInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
var wasChanged = editing_node.changed;
|
||||
editing_node.changed = true;
|
||||
RED.nodes.dirty(true);
|
||||
var historyEvent = {
|
||||
t:'edit',
|
||||
node:editing_node,
|
||||
changes:changes,
|
||||
dirty:wasDirty,
|
||||
changed:wasChanged
|
||||
};
|
||||
RED.history.push(historyEvent);
|
||||
}
|
||||
editing_node.dirty = true;
|
||||
RED.tray.close();
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(size) {
|
||||
editTrayWidthCache['group'] = size.width;
|
||||
$(".red-ui-tray-content").height(size.height - 50);
|
||||
// var form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40);
|
||||
// if (editing_node && editing_node._def.oneditresize) {
|
||||
// try {
|
||||
// editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()});
|
||||
// } catch(err) {
|
||||
// console.log("oneditresize",editing_node.id,editing_node.type,err.toString());
|
||||
// }
|
||||
// }
|
||||
},
|
||||
open: function(tray, done) {
|
||||
var trayFooter = tray.find(".red-ui-tray-footer");
|
||||
var trayFooterLeft = $("<div/>", {
|
||||
class: "red-ui-tray-footer-left"
|
||||
}).appendTo(trayFooter)
|
||||
var trayBody = tray.find('.red-ui-tray-body');
|
||||
trayBody.parent().css('overflow','hidden');
|
||||
|
||||
var editorTabEl = $('<ul></ul>').appendTo(trayBody);
|
||||
var editorContent = $('<div></div>').appendTo(trayBody);
|
||||
|
||||
var editorTabs = RED.tabs.create({
|
||||
element:editorTabEl,
|
||||
onchange:function(tab) {
|
||||
editorContent.children().hide();
|
||||
if (tab.onchange) {
|
||||
tab.onchange.call(tab);
|
||||
}
|
||||
tab.content.show();
|
||||
if (finishedBuilding) {
|
||||
RED.tray.resize();
|
||||
}
|
||||
},
|
||||
collapsible: true,
|
||||
menu: false
|
||||
});
|
||||
|
||||
var nodePropertiesTab = {
|
||||
id: "editor-tab-properties",
|
||||
label: RED._("editor-tab.properties"),
|
||||
name: RED._("editor-tab.properties"),
|
||||
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||
iconClass: "fa fa-cog"
|
||||
};
|
||||
buildEditForm(nodePropertiesTab.content,"dialog-form","group","node-red",group);
|
||||
|
||||
editorTabs.addTab(nodePropertiesTab);
|
||||
|
||||
var descriptionTab = {
|
||||
id: "editor-tab-description",
|
||||
label: RED._("editor-tab.description"),
|
||||
name: RED._("editor-tab.description"),
|
||||
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||
iconClass: "fa fa-file-text-o",
|
||||
onchange: function() {
|
||||
nodeInfoEditor.focus();
|
||||
}
|
||||
};
|
||||
editorTabs.addTab(descriptionTab);
|
||||
nodeInfoEditor = buildDescriptionForm(descriptionTab.content,editing_node);
|
||||
prepareEditDialog(group,group._def,"node-input", function() {
|
||||
trayBody.i18n();
|
||||
finishedBuilding = true;
|
||||
done();
|
||||
});
|
||||
},
|
||||
close: function() {
|
||||
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
|
||||
RED.view.state(RED.state.DEFAULT);
|
||||
}
|
||||
nodeInfoEditor.destroy();
|
||||
nodeInfoEditor = null;
|
||||
editStack.pop();
|
||||
editing_node = null;
|
||||
},
|
||||
show: function() {
|
||||
}
|
||||
}
|
||||
|
||||
if (editTrayWidthCache.hasOwnProperty('group')) {
|
||||
trayOptions.width = editTrayWidthCache['group'];
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
|
||||
function showTypeEditor(type, options) {
|
||||
if (customEditTypes.hasOwnProperty(type)) {
|
||||
if (editStack.length > 0) {
|
||||
@ -2576,6 +2821,7 @@ RED.editor = (function() {
|
||||
edit: showEditDialog,
|
||||
editConfig: showEditConfigNodeDialog,
|
||||
editSubflow: showEditSubflowDialog,
|
||||
editGroup: showEditGroupDialog,
|
||||
editJavaScript: function(options) { showTypeEditor("_js",options) },
|
||||
editExpression: function(options) { showTypeEditor("_expression", options) },
|
||||
editJSON: function(options) { showTypeEditor("_json", options) },
|
||||
|
@ -25,5 +25,7 @@ RED.state = {
|
||||
IMPORT_DRAGGING: 8,
|
||||
QUICK_JOINING: 9,
|
||||
PANNING: 10,
|
||||
SELECTING_NODE: 11
|
||||
SELECTING_NODE: 11,
|
||||
GROUP_DRAGGING: 12,
|
||||
GROUP_RESIZE: 13
|
||||
}
|
||||
|
@ -21,12 +21,15 @@
|
||||
* \- <g>.red-ui-workspace-chart-event-layer "eventLayer"
|
||||
* |- <rect>.red-ui-workspace-chart-background
|
||||
* |- <g>.red-ui-workspace-chart-grid "gridLayer"
|
||||
* |- <g> "groupLayer"
|
||||
* |- <g> "linkLayer"
|
||||
* |- <g> "dragGroupLayer"
|
||||
* \- <g> "nodeLayer"
|
||||
*/
|
||||
|
||||
RED.view = (function() {
|
||||
var DEBUG_EVENTS = false;
|
||||
2
|
||||
var space_width = 5000,
|
||||
space_height = 5000,
|
||||
lineCurveScale = 0.75,
|
||||
@ -48,22 +51,29 @@ RED.view = (function() {
|
||||
var activeSpliceLink;
|
||||
var spliceActive = false;
|
||||
var spliceTimer;
|
||||
var groupHoverTimer;
|
||||
|
||||
var activeSubflow = null;
|
||||
var activeNodes = [];
|
||||
var activeLinks = [];
|
||||
var activeFlowLinks = [];
|
||||
var activeLinkNodes = {};
|
||||
var activeGroup = null;
|
||||
var activeHoverGroup = null;
|
||||
var activeGroups = [];
|
||||
var dirtyGroups = {};
|
||||
|
||||
var selected_link = null,
|
||||
mousedown_link = null,
|
||||
mousedown_node = null,
|
||||
mousedown_group = null,
|
||||
mousedown_port_type = null,
|
||||
mousedown_port_index = 0,
|
||||
mouseup_node = null,
|
||||
mouse_offset = [0,0],
|
||||
mouse_position = null,
|
||||
mouse_mode = 0,
|
||||
mousedown_group_handle = null;
|
||||
moving_set = [],
|
||||
lasso = null,
|
||||
ghostNode = null,
|
||||
@ -75,7 +85,8 @@ RED.view = (function() {
|
||||
scroll_position = [],
|
||||
quickAddActive = false,
|
||||
quickAddLink = null,
|
||||
showAllLinkPorts = -1;
|
||||
showAllLinkPorts = -1,
|
||||
groupNodeSelectPrimed = false;
|
||||
|
||||
var selectNodesOptions;
|
||||
|
||||
@ -101,6 +112,7 @@ RED.view = (function() {
|
||||
var linkLayer;
|
||||
var dragGroupLayer;
|
||||
var nodeLayer;
|
||||
var groupLayer;
|
||||
var drag_lines;
|
||||
|
||||
function init() {
|
||||
@ -253,6 +265,7 @@ RED.view = (function() {
|
||||
gridLayer = eventLayer.append("g").attr("class","red-ui-workspace-chart-grid");
|
||||
updateGrid();
|
||||
|
||||
groupLayer = eventLayer.append("g");
|
||||
linkLayer = eventLayer.append("g");
|
||||
dragGroupLayer = eventLayer.append("g");
|
||||
nodeLayer = eventLayer.append("g");
|
||||
@ -517,6 +530,8 @@ RED.view = (function() {
|
||||
source:{z:activeWorkspace},
|
||||
target:{z:activeWorkspace}
|
||||
});
|
||||
|
||||
activeGroups = RED.nodes.groups(activeWorkspace)||[];
|
||||
}
|
||||
|
||||
function generateLinkPath(origX,origY, destX, destY, sc) {
|
||||
@ -671,6 +686,7 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function canvasMouseDown() {
|
||||
if (DEBUG_EVENTS) { console.warn("canvasMouseDown", mouse_mode); }
|
||||
var point;
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
d3.event.stopPropagation();
|
||||
@ -684,7 +700,7 @@ RED.view = (function() {
|
||||
scroll_position = [chart.scrollLeft(),chart.scrollTop()];
|
||||
return;
|
||||
}
|
||||
if (!mousedown_node && !mousedown_link) {
|
||||
if (!mousedown_node && !mousedown_link && !mousedown_group) {
|
||||
selected_link = null;
|
||||
updateSelection();
|
||||
}
|
||||
@ -697,7 +713,13 @@ RED.view = (function() {
|
||||
if (mouse_mode === 0 || mouse_mode === RED.state.QUICK_JOINING) {
|
||||
if (d3.event.metaKey || d3.event.ctrlKey) {
|
||||
d3.event.stopPropagation();
|
||||
showQuickAddDialog(d3.mouse(this));
|
||||
clearSelection();
|
||||
point = d3.mouse(this);
|
||||
var clickedGroup = getGroupAt(point[0],point[1]);
|
||||
if (drag_lines.length > 0) {
|
||||
clickedGroup = clickedGroup || RED.nodes.group(drag_lines[0].node.g)
|
||||
}
|
||||
showQuickAddDialog(point, null, clickedGroup);
|
||||
}
|
||||
}
|
||||
if (mouse_mode === 0 && !(d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
@ -718,7 +740,15 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function showQuickAddDialog(point,spliceLink) {
|
||||
function showQuickAddDialog(point, spliceLink, targetGroup) {
|
||||
if (targetGroup && !targetGroup.active) {
|
||||
targetGroup.active = true;
|
||||
targetGroup.dirty = true;
|
||||
selectGroup(targetGroup,false);
|
||||
activeGroup = targetGroup;
|
||||
RED.view.redraw();
|
||||
}
|
||||
|
||||
var ox = point[0];
|
||||
var oy = point[1];
|
||||
|
||||
@ -946,6 +976,11 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetGroup) {
|
||||
RED.group.addToGroup(targetGroup, nn);
|
||||
|
||||
}
|
||||
|
||||
if (spliceLink) {
|
||||
resetMouseVars();
|
||||
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp/showQuickAddDialog
|
||||
@ -972,6 +1007,12 @@ RED.view = (function() {
|
||||
// auto select dropped node - so info shows (if visible)
|
||||
clearSelection();
|
||||
nn.selected = true;
|
||||
if (targetGroup) {
|
||||
selectGroup(targetGroup,false);
|
||||
targetGroup.active = true
|
||||
targetGroup.dirty = true;
|
||||
activeGroup = targetGroup;
|
||||
}
|
||||
moving_set.push({n:nn});
|
||||
updateActiveNodes();
|
||||
updateSelection();
|
||||
@ -1076,12 +1117,23 @@ RED.view = (function() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && selected_link == null) {
|
||||
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && !mousedown_group && selected_link == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mousePos;
|
||||
if (mouse_mode == RED.state.JOINING || mouse_mode === RED.state.QUICK_JOINING) {
|
||||
if (mouse_mode === RED.state.GROUP_RESIZE) {
|
||||
mousePos = mouse_position;
|
||||
var nx = mousePos[0] + mousedown_group.dx;
|
||||
var ny = mousePos[1] + mousedown_group.dy;
|
||||
switch(mousedown_group.activeHandle) {
|
||||
case 0: mousedown_group.pos.x0 = nx; mousedown_group.pos.y0 = ny; break;
|
||||
case 1: mousedown_group.pos.x1 = nx; mousedown_group.pos.y0 = ny; break;
|
||||
case 2: mousedown_group.pos.x1 = nx; mousedown_group.pos.y1 = ny; break;
|
||||
case 3: mousedown_group.pos.x0 = nx; mousedown_group.pos.y1 = ny; break;
|
||||
}
|
||||
mousedown_group.dirty = true;
|
||||
} else if (mouse_mode == RED.state.JOINING || mouse_mode === RED.state.QUICK_JOINING) {
|
||||
// update drag line
|
||||
if (drag_lines.length === 0 && mousedown_port_type !== null) {
|
||||
if (d3.event.shiftKey) {
|
||||
@ -1201,6 +1253,13 @@ RED.view = (function() {
|
||||
node.n.y -= (maxY - space_height);
|
||||
}
|
||||
}
|
||||
if (mousedown_group) {
|
||||
mousedown_group.pos.x0 = mousePos[0] + mousedown_group.dx0;
|
||||
mousedown_group.pos.y0 = mousePos[1] + mousedown_group.dy0;
|
||||
mousedown_group.pos.x1 = mousePos[0] + mousedown_group.dx1;
|
||||
mousedown_group.pos.y1 = mousePos[1] + mousedown_group.dy1;
|
||||
mousedown_group.dirty = true;
|
||||
}
|
||||
if (snapGrid != d3.event.shiftKey && moving_set.length > 0) {
|
||||
var gridOffset = [0,0];
|
||||
node = moving_set[0];
|
||||
@ -1265,6 +1324,29 @@ RED.view = (function() {
|
||||
},100);
|
||||
}
|
||||
}
|
||||
if (!node.n.g && activeGroups) {
|
||||
if (!groupHoverTimer) {
|
||||
groupHoverTimer = setTimeout(function() {
|
||||
activeHoverGroup = null;
|
||||
for (var i=0;i<activeGroups.length;i++) {
|
||||
var g = activeGroups[i];
|
||||
if ( !activeHoverGroup &&
|
||||
node.n.x >= g.pos.x0 && node.n.x <= g.pos.x1 &&
|
||||
node.n.y >= g.pos.y0 && node.n.y <= g.pos.y1
|
||||
) {
|
||||
g.dirty = !g.hovered;
|
||||
g.hovered = true;
|
||||
activeHoverGroup = g;
|
||||
} else {
|
||||
// Mark dirty if it is selected
|
||||
g.dirty = g.hovered;
|
||||
g.hovered = false;
|
||||
}
|
||||
}
|
||||
groupHoverTimer = null;
|
||||
},50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1275,6 +1357,7 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function canvasMouseUp() {
|
||||
if (DEBUG_EVENTS) { console.warn("canvasMouseUp", mouse_mode); }
|
||||
var i;
|
||||
var historyEvent;
|
||||
if (mouse_mode === RED.state.PANNING) {
|
||||
@ -1311,15 +1394,22 @@ RED.view = (function() {
|
||||
var y = parseInt(lasso.attr("y"));
|
||||
var x2 = x+parseInt(lasso.attr("width"));
|
||||
var y2 = y+parseInt(lasso.attr("height"));
|
||||
if (!d3.event.ctrlKey) {
|
||||
if (!d3.event.shiftKey) {
|
||||
clearSelection();
|
||||
}
|
||||
RED.nodes.eachNode(function(n) {
|
||||
activeNodes.forEach(function(n) {
|
||||
if (n.z == RED.workspaces.active() && !n.selected) {
|
||||
n.selected = (n.x > x && n.x < x2 && n.y > y && n.y < y2);
|
||||
if (n.selected) {
|
||||
n.dirty = true;
|
||||
moving_set.push({n:n});
|
||||
if (n.x > x && n.x < x2 && n.y > y && n.y < y2) {
|
||||
if (n.g) {
|
||||
var group = RED.nodes.group(n.g);
|
||||
if (!group.selected) {
|
||||
selectGroup(RED.nodes.group(n.g),true);
|
||||
}
|
||||
} else {
|
||||
n.selected = true;
|
||||
n.dirty = true;
|
||||
moving_set.push({n:n});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1355,6 +1445,20 @@ RED.view = (function() {
|
||||
}
|
||||
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||
if (moving_set.length > 0) {
|
||||
if (activeHoverGroup) {
|
||||
for (var j=0;j<moving_set.length;j++) {
|
||||
var n = moving_set[j];
|
||||
RED.group.addToGroup(activeHoverGroup,n.n);
|
||||
}
|
||||
activeHoverGroup.hovered = false;
|
||||
activeHoverGroup.dirty = true;
|
||||
activeHoverGroup.active = true;
|
||||
activeGroup = activeHoverGroup;
|
||||
activeGroup.selected = true;
|
||||
|
||||
activeHoverGroup = null;
|
||||
}
|
||||
|
||||
var ns = [];
|
||||
for (var j=0;j<moving_set.length;j++) {
|
||||
var n = moving_set[j];
|
||||
@ -1391,7 +1495,23 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (mouse_mode === RED.state.MOVING && mousedown_node && mousedown_node.g) {
|
||||
// if (mousedown_node.gSelected) {
|
||||
// delete mousedown_node.gSelected
|
||||
// } else {
|
||||
// if (!d3.event.ctrlKey && !d3.event.metaKey) {
|
||||
// clearSelection();
|
||||
// }
|
||||
// RED.nodes.group(mousedown_node.g).selected = true;
|
||||
// mousedown_node.selected = true;
|
||||
// mousedown_node.dirty = true;
|
||||
// moving_set.push({n:mousedown_node});
|
||||
// }
|
||||
// }
|
||||
if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||
// if (mousedown_node) {
|
||||
// delete mousedown_node.gSelected;
|
||||
// }
|
||||
for (i=0;i<moving_set.length;i++) {
|
||||
delete moving_set[i].ox;
|
||||
delete moving_set[i].oy;
|
||||
@ -1437,20 +1557,28 @@ RED.view = (function() {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE && selectNodesOptions.single) {
|
||||
return;
|
||||
}
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.z == RED.workspaces.active()) {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
if (selectNodesOptions.filter && !selectNodesOptions.filter(n)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!n.selected) {
|
||||
n.selected = true;
|
||||
n.dirty = true;
|
||||
moving_set.push({n:n});
|
||||
|
||||
activeGroups.forEach(function(g) {
|
||||
selectGroup(g, true);
|
||||
if (!g.selected) {
|
||||
g.selected = true;
|
||||
g.dirty = true;
|
||||
}
|
||||
})
|
||||
|
||||
activeNodes.forEach(function(n) {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
if (selectNodesOptions.filter && !selectNodesOptions.filter(n)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!n.g && !n.selected) {
|
||||
n.selected = true;
|
||||
n.dirty = true;
|
||||
moving_set.push({n:n});
|
||||
}
|
||||
});
|
||||
|
||||
if (mouse_mode !== RED.state.SELECTING_NODE && activeSubflow) {
|
||||
activeSubflow.in.forEach(function(n) {
|
||||
if (!n.selected) {
|
||||
@ -1483,6 +1611,7 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
||||
for (var i=0;i<moving_set.length;i++) {
|
||||
var n = moving_set[i];
|
||||
n.n.dirty = true;
|
||||
@ -1490,6 +1619,15 @@ RED.view = (function() {
|
||||
}
|
||||
moving_set = [];
|
||||
selected_link = null;
|
||||
if (activeGroup) {
|
||||
activeGroup.active = false
|
||||
activeGroup.dirty = true;
|
||||
activeGroup = null;
|
||||
}
|
||||
activeGroups.forEach(function(g) {
|
||||
g.selected = false;
|
||||
g.dirty = true;
|
||||
})
|
||||
}
|
||||
|
||||
var lastSelection = null;
|
||||
@ -1505,6 +1643,7 @@ RED.view = (function() {
|
||||
if (selected_link != null) {
|
||||
selection.link = selected_link;
|
||||
}
|
||||
selection.groups = activeGroups.filter(function(g) { return g.selected })
|
||||
activeLinks = RED.nodes.filterLinks({
|
||||
source:{z:activeWorkspace},
|
||||
target:{z:activeWorkspace}
|
||||
@ -1588,7 +1727,7 @@ RED.view = (function() {
|
||||
selection.flows = workspaceSelection;
|
||||
}
|
||||
var selectionJSON = activeWorkspace+":"+JSON.stringify(selection,function(key,value) {
|
||||
if (key === 'nodes' || key === 'flows') {
|
||||
if (key === 'nodes' || key === 'flows' || key === 'groups') {
|
||||
return value.map(function(n) { return n.id })
|
||||
} else if (key === 'link') {
|
||||
return value.source.id+":"+value.sourcePort+":"+value.target.id;
|
||||
@ -1895,6 +2034,8 @@ RED.view = (function() {
|
||||
|
||||
function resetMouseVars() {
|
||||
mousedown_node = null;
|
||||
mousedown_group = null;
|
||||
mousedown_group_handle = null;
|
||||
mouseup_node = null;
|
||||
mousedown_link = null;
|
||||
mouse_mode = 0;
|
||||
@ -1906,6 +2047,10 @@ RED.view = (function() {
|
||||
clearTimeout(spliceTimer);
|
||||
spliceTimer = null;
|
||||
}
|
||||
if (groupHoverTimer) {
|
||||
clearTimeout(groupHoverTimer);
|
||||
groupHoverTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function disableQuickJoinEventHandler(evt) {
|
||||
@ -1919,6 +2064,7 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function portMouseDown(d,portType,portIndex) {
|
||||
if (DEBUG_EVENTS) { console.warn("portMouseDown", mouse_mode,d); }
|
||||
//console.log(d,portType,portIndex);
|
||||
// disable zoom
|
||||
//eventLayer.call(d3.behavior.zoom().on("zoom"), null);
|
||||
@ -1946,6 +2092,7 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function portMouseUp(d,portType,portIndex) {
|
||||
if (DEBUG_EVENTS) { console.warn("portMouseUp", mouse_mode,d); }
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
@ -2280,6 +2427,7 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function nodeMouseUp(d) {
|
||||
if (DEBUG_EVENTS) { console.warn("nodeMouseUp", mouse_mode,d); }
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
@ -2295,6 +2443,27 @@ RED.view = (function() {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
if (mouse_mode === RED.state.MOVING) {
|
||||
// Moving primed, but not active.
|
||||
if (!groupNodeSelectPrimed && !d.selected && d.g && RED.nodes.group(d.g).selected) {
|
||||
clearSelection();
|
||||
activeGroup = RED.nodes.group(d.g);
|
||||
activeGroup.active = true;
|
||||
activeGroup.dirty = true;
|
||||
|
||||
selectGroup(RED.nodes.group(d.g), false);
|
||||
mousedown_node.selected = true;
|
||||
moving_set.push({n:mousedown_node});
|
||||
var mouse = d3.touches(this)[0]||d3.mouse(this);
|
||||
mouse[0] += d.x-d.w/2;
|
||||
mouse[1] += d.y-d.h/2;
|
||||
prepareDrag(mouse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
groupNodeSelectPrimed = false;
|
||||
|
||||
var direction = d._def? (d.inputs > 0 ? 1: 0) : (d.direction == "in" ? 0: 1)
|
||||
var wasJoining = false;
|
||||
if (mouse_mode === RED.state.JOINING || mouse_mode === RED.state.QUICK_JOINING) {
|
||||
@ -2316,7 +2485,23 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function prepareDrag(mouse) {
|
||||
mouse_mode = RED.state.MOVING;
|
||||
// Called when moving_set should be prepared to be dragged
|
||||
for (i=0;i<moving_set.length;i++) {
|
||||
moving_set[i].ox = moving_set[i].n.x;
|
||||
moving_set[i].oy = moving_set[i].n.y;
|
||||
moving_set[i].dx = moving_set[i].n.x-mouse[0];
|
||||
moving_set[i].dy = moving_set[i].n.y-mouse[1];
|
||||
}
|
||||
mouse_offset = d3.mouse(document.body);
|
||||
if (isNaN(mouse_offset[0])) {
|
||||
mouse_offset = d3.touches(document.body)[0];
|
||||
}
|
||||
}
|
||||
|
||||
function nodeMouseDown(d) {
|
||||
if (DEBUG_EVENTS) { console.warn("nodeMouseDown", mouse_mode,d); }
|
||||
focusView();
|
||||
if (d3.event.button === 1) {
|
||||
return;
|
||||
@ -2385,7 +2570,9 @@ RED.view = (function() {
|
||||
// }
|
||||
return;
|
||||
}
|
||||
|
||||
mousedown_node = d;
|
||||
|
||||
var now = Date.now();
|
||||
clickElapsed = now-clickTime;
|
||||
clickTime = now;
|
||||
@ -2393,11 +2580,76 @@ RED.view = (function() {
|
||||
dblClickPrimed = (lastClickNode == mousedown_node &&
|
||||
d3.event.button === 0 &&
|
||||
!d3.event.shiftKey && !d3.event.metaKey && !d3.event.altKey && !d3.event.ctrlKey);
|
||||
lastClickNode = mousedown_node;
|
||||
lastClickNode = mousedown_node;
|
||||
|
||||
var i;
|
||||
|
||||
if (d.selected && (d3.event.ctrlKey||d3.event.metaKey)) {
|
||||
if (!d.selected && d.g /*&& !RED.nodes.group(d.g).selected*/) {
|
||||
var nodeGroup = RED.nodes.group(d.g);
|
||||
|
||||
if (nodeGroup !== activeGroup && (d3.event.ctrlKey || d3.event.metaKey)) {
|
||||
// Clicked on a node in a non-active group with ctrl pressed
|
||||
// - exit active group
|
||||
// - toggle the select state of the group
|
||||
exitActiveGroup();
|
||||
groupNodeSelectPrimed = true;
|
||||
if (nodeGroup.selected) {
|
||||
deselectGroup(nodeGroup);
|
||||
} else {
|
||||
selectGroup(nodeGroup,true);
|
||||
}
|
||||
} else if (nodeGroup === activeGroup ) {
|
||||
// Clicked on a node in the active group
|
||||
if (!d3.event.ctrlKey && !d3.event.metaKey) {
|
||||
// Ctrl not pressed so clear selection
|
||||
deselectGroup(nodeGroup);
|
||||
selectGroup(nodeGroup,false);
|
||||
}
|
||||
// Select this node
|
||||
mousedown_node.selected = true;
|
||||
moving_set.push({n:mousedown_node});
|
||||
} else {
|
||||
// Clicked on a node in a group
|
||||
// - if this group is not selected, clear current selection
|
||||
// and select this group
|
||||
// - if this group is not the active group, exit the active group
|
||||
// and select the group
|
||||
// - if this group is the active group, keep it active and
|
||||
// change node selection
|
||||
|
||||
// Set groupNodeSelectPrimed to true as this is a (de)select of the
|
||||
// group and NOT meant to trigger going into the group - see nodeMouseUp
|
||||
groupNodeSelectPrimed = !nodeGroup.selected;
|
||||
var ag = activeGroup;
|
||||
if (!nodeGroup.selected) {
|
||||
clearSelection();
|
||||
}
|
||||
if (ag) {
|
||||
if (ag !== nodeGroup) {
|
||||
ag.active = false;
|
||||
ag.dirty = true;
|
||||
} else {
|
||||
activeGroup = nodeGroup;
|
||||
activeGroup.active = true;
|
||||
}
|
||||
} else {
|
||||
dblClickPrimed = false;
|
||||
}
|
||||
selectGroup(nodeGroup, !activeGroup);
|
||||
if (activeGroup) {
|
||||
mousedown_node.selected = true;
|
||||
moving_set.push({n:mousedown_node});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (d3.event.button != 2) {
|
||||
var mouse = d3.touches(this)[0]||d3.mouse(this);
|
||||
mouse[0] += d.x-d.w/2;
|
||||
mouse[1] += d.y-d.h/2;
|
||||
prepareDrag(mouse);
|
||||
}
|
||||
} else if (d.selected && (d3.event.ctrlKey||d3.event.metaKey)) {
|
||||
mousedown_node.selected = false;
|
||||
for (i=0;i<moving_set.length;i+=1) {
|
||||
if (moving_set[i].n === mousedown_node) {
|
||||
@ -2406,6 +2658,21 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// if (d.g && !RED.nodes.group(d.g).selected) {
|
||||
// selectGroup(RED.nodes.group(d.g), false);
|
||||
// }
|
||||
|
||||
|
||||
// if (!d.selected && d.g) {
|
||||
// if (!RED.nodes.group(d.g).selected) {// && !RED.nodes.group(d.g).selected) {
|
||||
// clearSelection();
|
||||
// selectGroup(RED.nodes.group(d.g));
|
||||
// d.selected = true;
|
||||
// console.log(d.id,"Setting selected")
|
||||
// d.gSelected = true;
|
||||
// }
|
||||
// } else
|
||||
if (d3.event.shiftKey) {
|
||||
clearSelection();
|
||||
var cnodes = RED.nodes.getAllFlowNodes(mousedown_node);
|
||||
@ -2417,6 +2684,8 @@ RED.view = (function() {
|
||||
} else if (!d.selected) {
|
||||
if (!d3.event.ctrlKey && !d3.event.metaKey) {
|
||||
clearSelection();
|
||||
} else {
|
||||
exitActiveGroup();
|
||||
}
|
||||
mousedown_node.selected = true;
|
||||
moving_set.push({n:mousedown_node});
|
||||
@ -2427,16 +2696,7 @@ RED.view = (function() {
|
||||
var mouse = d3.touches(this)[0]||d3.mouse(this);
|
||||
mouse[0] += d.x-d.w/2;
|
||||
mouse[1] += d.y-d.h/2;
|
||||
for (i=0;i<moving_set.length;i++) {
|
||||
moving_set[i].ox = moving_set[i].n.x;
|
||||
moving_set[i].oy = moving_set[i].n.y;
|
||||
moving_set[i].dx = moving_set[i].n.x-mouse[0];
|
||||
moving_set[i].dy = moving_set[i].n.y-mouse[1];
|
||||
}
|
||||
mouse_offset = d3.mouse(document.body);
|
||||
if (isNaN(mouse_offset[0])) {
|
||||
mouse_offset = d3.touches(document.body)[0];
|
||||
}
|
||||
prepareDrag(mouse);
|
||||
}
|
||||
}
|
||||
d.dirty = true;
|
||||
@ -2445,6 +2705,164 @@ RED.view = (function() {
|
||||
d3.event.stopPropagation();
|
||||
}
|
||||
|
||||
function groupMouseUp(g) {
|
||||
if (dblClickPrimed && mousedown_group == g && clickElapsed > 0 && clickElapsed < 750) {
|
||||
mouse_mode = RED.state.DEFAULT;
|
||||
RED.editor.editGroup(g);
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
function groupMouseDown(g) {
|
||||
var mouse = d3.touches(this.parentNode)[0]||d3.mouse(this.parentNode);
|
||||
if (! (mouse[0] < g.pos.x0+10 || mouse[0] > g.pos.x1-10 || mouse[1] < g.pos.y0+10 || mouse[1] > g.pos.y1-10) ) {
|
||||
return
|
||||
}
|
||||
|
||||
focusView();
|
||||
if (d3.event.button === 1) {
|
||||
return;
|
||||
}
|
||||
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
|
||||
RED.keyboard.remove("escape");
|
||||
console.log("Dragged a node into the group")
|
||||
} else if (mouse_mode == RED.state.QUICK_JOINING) {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
} else if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
mousedown_group = g;
|
||||
|
||||
var now = Date.now();
|
||||
clickElapsed = now-clickTime;
|
||||
clickTime = now;
|
||||
|
||||
dblClickPrimed = (
|
||||
lastClickNode == g &&
|
||||
d3.event.button === 0 &&
|
||||
!d3.event.shiftKey && !d3.event.metaKey && !d3.event.altKey && !d3.event.ctrlKey
|
||||
);
|
||||
lastClickNode = g;
|
||||
|
||||
if (g.selected && (d3.event.ctrlKey||d3.event.metaKey)) {
|
||||
if (g === activeGroup) {
|
||||
exitActiveGroup();
|
||||
}
|
||||
deselectGroup(g);
|
||||
d3.event.stopPropagation();
|
||||
} else {
|
||||
if (!g.selected) {
|
||||
if (!d3.event.ctrlKey && !d3.event.metaKey) {
|
||||
clearSelection();
|
||||
}
|
||||
selectGroup(g,true);//!wasSelected);
|
||||
} else {
|
||||
exitActiveGroup();
|
||||
}
|
||||
|
||||
|
||||
if (d3.event.button != 2) {
|
||||
var d = g.nodes[0];
|
||||
prepareDrag(mouse);
|
||||
mousedown_group.dx0 = mousedown_group.pos.x0 - mouse[0];
|
||||
mousedown_group.dy0 = mousedown_group.pos.y0 - mouse[1];
|
||||
mousedown_group.dx1 = mousedown_group.pos.x1 - mouse[0];
|
||||
mousedown_group.dy1 = mousedown_group.pos.y1 - mouse[1];
|
||||
}
|
||||
}
|
||||
|
||||
updateSelection();
|
||||
redraw();
|
||||
d3.event.stopPropagation();
|
||||
}
|
||||
|
||||
function selectGroup(g, includeNodes) {
|
||||
if (!g.selected) {
|
||||
g.selected = true;
|
||||
g.dirty = true;
|
||||
}
|
||||
if (includeNodes) {
|
||||
var currentSet = new Set(moving_set.map(function(n) { return n.n }));
|
||||
g.nodes.forEach(function(n) {
|
||||
if (!currentSet.has(n)) {
|
||||
moving_set.push({n:n})
|
||||
// n.selected = true;
|
||||
}
|
||||
n.dirty = true;
|
||||
})
|
||||
}
|
||||
}
|
||||
function exitActiveGroup() {
|
||||
if (activeGroup) {
|
||||
activeGroup.active = false;
|
||||
activeGroup.dirty = true;
|
||||
deselectGroup(activeGroup);
|
||||
selectGroup(activeGroup,true);
|
||||
activeGroup = null;
|
||||
}
|
||||
}
|
||||
function deselectGroup(g) {
|
||||
if (g.selected) {
|
||||
g.selected = false;
|
||||
g.dirty = true;
|
||||
}
|
||||
var nodeSet = new Set(g.nodes);
|
||||
for (var i = moving_set.length-1; i >= 0; i -= 1) {
|
||||
if (nodeSet.has(moving_set[i].n)) {
|
||||
moving_set[i].n.selected = false;
|
||||
moving_set[i].n.dirty = true;
|
||||
moving_set.splice(i,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
function getGroupAt(x,y) {
|
||||
for (var i=0;i<activeGroups.length;i++) {
|
||||
var g = activeGroups[i];
|
||||
if (x >= g.pos.x0 && x <= g.pos.x1 && y >= g.pos.y0 && y <= g.pos.y1) {
|
||||
return g;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function groupHandleMouseDown(group, groupEl, handle,handleIndex) {
|
||||
d3.event.stopPropagation();
|
||||
console.log("GHANDLE MD");
|
||||
if (d3.event.button != 2) {
|
||||
mousedown_group = group;
|
||||
group.activeHandle = handleIndex;
|
||||
var mouse = d3.touches(handle.parentNode.parentNode)[0]||d3.mouse(handle.parentNode.parentNode);
|
||||
switch(handleIndex) {
|
||||
case 0: group.ox = group.pos.x0; group.oy = group.pos.y0; break;
|
||||
case 1: group.ox = group.pos.x1; group.oy = group.pos.y0; break;
|
||||
case 2: group.ox = group.pos.x1; group.oy = group.pos.y1; break;
|
||||
case 3: group.ox = group.pos.x0; group.oy = group.pos.y1; break;
|
||||
}
|
||||
group.dx = group.ox - mouse[0];
|
||||
group.dy = group.oy - mouse[1];
|
||||
console.log("START",group.ox, group.oy);
|
||||
mouse_offset = d3.mouse(document.body);
|
||||
if (isNaN(mouse_offset[0])) {
|
||||
mouse_offset = d3.touches(document.body)[0];
|
||||
}
|
||||
mouse_mode = RED.state.GROUP_RESIZE;
|
||||
}
|
||||
}
|
||||
function groupHandleMouseUp(group,groupEl,handle,handleIndex) {
|
||||
console.log("GHANDLE MU");
|
||||
d3.event.stopPropagation();
|
||||
delete group.ox;
|
||||
delete group.oy;
|
||||
delete group.dx;
|
||||
delete group.dy;
|
||||
resetMouseVars();
|
||||
mouse_mode = RED.state.DEFAULT;
|
||||
}
|
||||
|
||||
function isButtonEnabled(d) {
|
||||
var buttonEnabled = true;
|
||||
var ws = RED.nodes.workspace(RED.workspaces.active());
|
||||
@ -3294,6 +3712,19 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
d.dirty = false;
|
||||
|
||||
if (d.g) {
|
||||
if (!dirtyGroups[d.g]) {
|
||||
dirtyGroups[d.g] = RED.nodes.group(d.g);
|
||||
}
|
||||
var group = dirtyGroups[d.g];
|
||||
group.pos = {
|
||||
x0: Math.min(group.pos.x0,d.x-d.w/2-25-((d._def.button && d._def.align!=="right")?20:0)),
|
||||
y0: Math.min(group.pos.y0,d.y-d.h/2-25),
|
||||
x1: Math.max(group.pos.x1,d.x+d.w/2+25+((d._def.button && d._def.align=="right")?20:0)),
|
||||
y1: Math.max(group.pos.y1,d.y+d.h/2+25)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -3324,7 +3755,9 @@ RED.view = (function() {
|
||||
d3.event.stopPropagation();
|
||||
if (d3.event.metaKey || d3.event.ctrlKey) {
|
||||
l.classed("red-ui-flow-link-splice",true);
|
||||
showQuickAddDialog(d3.mouse(this), selected_link);
|
||||
var point = d3.mouse(this);
|
||||
var clickedGroup = getGroupAt(point[0],point[1]);
|
||||
showQuickAddDialog(point, selected_link, clickedGroup);
|
||||
}
|
||||
})
|
||||
.on("touchstart",function(d) {
|
||||
@ -3509,6 +3942,112 @@ RED.view = (function() {
|
||||
|
||||
})
|
||||
|
||||
|
||||
var group = groupLayer.selectAll(".red-ui-flow-group").data(activeGroups,function(d) { return d.id });
|
||||
group.exit().remove();
|
||||
var groupEnter = group.enter().insert("svg:g")
|
||||
.attr("class", "red-ui-flow-group")
|
||||
|
||||
groupEnter.each(function(d,i) {
|
||||
var g = d3.select(this);
|
||||
|
||||
// g.append('path').classed("red-ui-flow-group-handle red-ui-flow-group-handle-0",true).style({
|
||||
// "fill":"white",
|
||||
// "stroke": "#ff7f0e",
|
||||
// "stroke-width": 2
|
||||
// }).attr("d","m -5 6 v -2 q 0 -9 9 -9 h 2 v 11 z")
|
||||
//
|
||||
// g.append('path').classed("red-ui-flow-group-handle red-ui-flow-group-handle-1",true).style({
|
||||
// "fill": "white",
|
||||
// "stroke": "#ff7f0e",
|
||||
// "stroke-width": 2
|
||||
// }).attr("d","m -6 -5 h 2 q 9 0 9 9 v 2 h -11 z")
|
||||
//
|
||||
// g.append('path').classed("red-ui-flow-group-handle red-ui-flow-group-handle-2",true).style({
|
||||
// "fill": "white",
|
||||
// "stroke": "#ff7f0e",
|
||||
// "stroke-width": 2
|
||||
// }).attr("d","m 5 -6 v 2 q 0 9 -9 9 h -2 v -11 z")
|
||||
//
|
||||
// g.append('path').classed("red-ui-flow-group-handle red-ui-flow-group-handle-3",true).style({
|
||||
// "fill": "white",
|
||||
// "stroke": "#ff7f0e",
|
||||
// "stroke-width": 2
|
||||
// }).attr("d","m 6 5 h -2 q -9 0 -9 -9 v -2 h 11 z")
|
||||
|
||||
|
||||
|
||||
g.append('rect').classed("red-ui-flow-group-outline",true)
|
||||
.attr('rx',1).attr('ry',1).style({
|
||||
"fill":"none",
|
||||
"stroke": "#ff7f0e",
|
||||
"stroke-opacity": 0,
|
||||
"stroke-width": 15
|
||||
})
|
||||
g.append('rect').classed("red-ui-flow-group-body",true)
|
||||
.attr('rx',1).attr('ry',1).style({
|
||||
"fill":d.fill||"none",
|
||||
"stroke": d.stroke||"none",
|
||||
"stroke-width": 2
|
||||
})
|
||||
|
||||
|
||||
d.dirty = true;
|
||||
g.on("mousedown",groupMouseDown).on("mouseup",groupMouseUp)
|
||||
|
||||
});
|
||||
group.each(function(d,i) {
|
||||
if (d.dirty || dirtyGroups[d.id]) {
|
||||
var g = d3.select(this);
|
||||
var minX = Number.POSITIVE_INFINITY;
|
||||
var minY = Number.POSITIVE_INFINITY;
|
||||
var maxX = 0;
|
||||
var maxY = 0;
|
||||
d.nodes.forEach(function(n) {
|
||||
minX = Math.min(minX,n.x-n.w/2-25-((n._def.button && n._def.align!=="right")?20:0));
|
||||
minY = Math.min(minY,n.y-n.h/2-25);
|
||||
maxX = Math.max(maxX,n.x+n.w/2+25+((n._def.button && n._def.align=="right")?20:0));
|
||||
maxY = Math.max(maxY,n.y+n.h/2+25);
|
||||
});
|
||||
|
||||
d.pos = {
|
||||
x0: minX, y0: minY,
|
||||
x1: maxX, y1: maxY
|
||||
}
|
||||
|
||||
g.attr("transform","translate("+d.pos.x0+","+d.pos.y0+")");
|
||||
g.selectAll(".red-ui-flow-group-outline")
|
||||
.attr("width",d.pos.x1-d.pos.x0)
|
||||
.attr("height",d.pos.y1-d.pos.y0)
|
||||
.style("stroke-opacity",function(d) { if (d.selected) { return 0.3 } return 0});
|
||||
|
||||
g.selectAll(".red-ui-flow-group-body")
|
||||
.attr("width",d.pos.x1-d.pos.x0)
|
||||
.attr("height",d.pos.y1-d.pos.y0)
|
||||
.style("stroke",function(d) { /*if (d.selected) { return "#ff7f0e" } */return d.style.stroke || "none"})
|
||||
.style("stroke-dasharray", function(d) { return (d.active||d.hovered)?"10 4":"none"})
|
||||
.style("fill", function(d) { return d.style.fill || "none"})
|
||||
.style("fill-opacity", 0.1)
|
||||
|
||||
// g.selectAll(".red-ui-flow-group-handle-0")
|
||||
// .style("opacity",function(d) { return d.selected?1:0})
|
||||
// g.selectAll(".red-ui-flow-group-handle-1")
|
||||
// .attr("transform","translate("+(maxX-minX)+",0)")
|
||||
// .style("opacity",function(d) { return d.selected?1:0})
|
||||
// g.selectAll(".red-ui-flow-group-handle-2")
|
||||
// .attr("transform","translate("+(maxX-minX)+","+(maxY-minY)+")")
|
||||
// .style("opacity",function(d) { return d.selected?1:0})
|
||||
// g.selectAll(".red-ui-flow-group-handle-3")
|
||||
// .attr("transform","translate(0,"+(maxY-minY)+")")
|
||||
// .style("opacity",function(d) { return d.selected?1:0})
|
||||
|
||||
|
||||
delete dirtyGroups[d.id];
|
||||
delete d.dirty;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
} else {
|
||||
// JOINING - unselect any selected links
|
||||
linkLayer.selectAll(".red-ui-flow-link-selected").data(
|
||||
@ -3785,10 +4324,17 @@ RED.view = (function() {
|
||||
selectedNode.dirty = true;
|
||||
moving_set = [{n:selectedNode}];
|
||||
}
|
||||
} else if (selection) {
|
||||
if (selection.groups) {
|
||||
updateActiveNodes();
|
||||
selection.groups.forEach(function(g) {
|
||||
selectGroup(g,true);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
updateSelection();
|
||||
redraw();
|
||||
redraw(true);
|
||||
},
|
||||
selection: function() {
|
||||
var selection = {};
|
||||
@ -3798,6 +4344,10 @@ RED.view = (function() {
|
||||
if (selected_link != null) {
|
||||
selection.link = selected_link;
|
||||
}
|
||||
selection.groups = activeGroups.filter(function(g) { return g.selected })
|
||||
if (selection.groups.length === 0) {
|
||||
delete selection.groups;
|
||||
}
|
||||
return selection;
|
||||
},
|
||||
scale: function() {
|
||||
|
Loading…
Reference in New Issue
Block a user