mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge pull request #2877 from node-red/select-tools
Add new select-* actions to editor
This commit is contained in:
		@@ -44,6 +44,9 @@
 | 
			
		||||
        "ctrl-z": "core:undo",
 | 
			
		||||
        "ctrl-y": "core:redo",
 | 
			
		||||
        "ctrl-a": "core:select-all-nodes",
 | 
			
		||||
        "alt-s u": "core:select-upstream-nodes",
 | 
			
		||||
        "alt-s d": "core:select-downstream-nodes",
 | 
			
		||||
        "alt-s c": "core:select-connected-nodes",
 | 
			
		||||
        "shift-?": "core:show-help",
 | 
			
		||||
        "w": "core:scroll-view-up",
 | 
			
		||||
        "d": "core:scroll-view-right",
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,11 @@ RED.nodes = (function() {
 | 
			
		||||
    var node_defs = {};
 | 
			
		||||
    var nodes = {};
 | 
			
		||||
    var nodeTabMap = {};
 | 
			
		||||
    var linkTabMap = {};
 | 
			
		||||
 | 
			
		||||
    var configNodes = {};
 | 
			
		||||
    var links = [];
 | 
			
		||||
    var nodeLinks = {};
 | 
			
		||||
    var defaultWorkspace;
 | 
			
		||||
    var workspaces = {};
 | 
			
		||||
    var workspacesOrder =[];
 | 
			
		||||
@@ -286,6 +288,9 @@ RED.nodes = (function() {
 | 
			
		||||
                n.i = nextId+1;
 | 
			
		||||
            }
 | 
			
		||||
            nodes[n.id] = n;
 | 
			
		||||
            if (!nodeLinks[n.id]) {
 | 
			
		||||
                nodeLinks[n.id] = {in:[],out:[]};
 | 
			
		||||
            }
 | 
			
		||||
            if (nodeTabMap[n.z]) {
 | 
			
		||||
                nodeTabMap[n.z][n.id] = n;
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -296,6 +301,22 @@ RED.nodes = (function() {
 | 
			
		||||
    }
 | 
			
		||||
    function addLink(l) {
 | 
			
		||||
        links.push(l);
 | 
			
		||||
        if (l.source) {
 | 
			
		||||
            // Possible the node hasn't been added yet
 | 
			
		||||
            if (!nodeLinks[l.source.id]) {
 | 
			
		||||
                nodeLinks[l.source.id] = {in:[],out:[]};
 | 
			
		||||
            }
 | 
			
		||||
            nodeLinks[l.source.id].out.push(l);
 | 
			
		||||
        }
 | 
			
		||||
        if (l.target) {
 | 
			
		||||
            if (!nodeLinks[l.target.id]) {
 | 
			
		||||
                nodeLinks[l.target.id] = {in:[],out:[]};
 | 
			
		||||
            }
 | 
			
		||||
            nodeLinks[l.target.id].in.push(l);
 | 
			
		||||
        }
 | 
			
		||||
        if (l.source.z === l.target.z && linkTabMap[l.source.z]) {
 | 
			
		||||
            linkTabMap[l.source.z].push(l);
 | 
			
		||||
        }
 | 
			
		||||
        RED.events.emit("links:add",l);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -320,6 +341,7 @@ RED.nodes = (function() {
 | 
			
		||||
        } else if (id in nodes) {
 | 
			
		||||
            node = nodes[id];
 | 
			
		||||
            delete nodes[id]
 | 
			
		||||
            delete nodeLinks[id];
 | 
			
		||||
            if (nodeTabMap[node.z]) {
 | 
			
		||||
                delete nodeTabMap[node.z][node.id];
 | 
			
		||||
            }
 | 
			
		||||
@@ -407,6 +429,24 @@ RED.nodes = (function() {
 | 
			
		||||
        var index = links.indexOf(l);
 | 
			
		||||
        if (index != -1) {
 | 
			
		||||
            links.splice(index,1);
 | 
			
		||||
            if (l.source) {
 | 
			
		||||
                var sIndex = nodeLinks[l.source.id].out.indexOf(l)
 | 
			
		||||
                if (sIndex !== -1) {
 | 
			
		||||
                    nodeLinks[l.source.id].out.splice(sIndex,1)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (l.target) {
 | 
			
		||||
                var tIndex = nodeLinks[l.target.id].in.indexOf(l)
 | 
			
		||||
                if (tIndex !== -1) {
 | 
			
		||||
                    nodeLinks[l.target.id].in.splice(tIndex,1)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (l.source.z === l.target.z && linkTabMap[l.source.z]) {
 | 
			
		||||
                index = linkTabMap[l.source.z].indexOf(l);
 | 
			
		||||
                if (index !== -1) {
 | 
			
		||||
                    linkTabMap[l.source.z].splice(index,1)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        RED.events.emit("links:remove",l);
 | 
			
		||||
    }
 | 
			
		||||
@@ -414,6 +454,7 @@ RED.nodes = (function() {
 | 
			
		||||
    function addWorkspace(ws,targetIndex) {
 | 
			
		||||
        workspaces[ws.id] = ws;
 | 
			
		||||
        nodeTabMap[ws.id] = {};
 | 
			
		||||
        linkTabMap[ws.id] = [];
 | 
			
		||||
 | 
			
		||||
        ws._def = RED.nodes.getType('tab');
 | 
			
		||||
        if (targetIndex === undefined) {
 | 
			
		||||
@@ -437,6 +478,7 @@ RED.nodes = (function() {
 | 
			
		||||
        if (ws) {
 | 
			
		||||
            delete workspaces[id];
 | 
			
		||||
            delete nodeTabMap[id];
 | 
			
		||||
            delete linkTabMap[id];
 | 
			
		||||
            workspacesOrder.splice(workspacesOrder.indexOf(id),1);
 | 
			
		||||
            var i;
 | 
			
		||||
            var node;
 | 
			
		||||
@@ -502,6 +544,7 @@ RED.nodes = (function() {
 | 
			
		||||
        }
 | 
			
		||||
        subflows[sf.id] = sf;
 | 
			
		||||
        nodeTabMap[sf.id] = {};
 | 
			
		||||
        linkTabMap[sf.id] = [];
 | 
			
		||||
 | 
			
		||||
        RED.nodes.registerType("subflow:"+sf.id, {
 | 
			
		||||
            defaults:{
 | 
			
		||||
@@ -574,29 +617,38 @@ RED.nodes = (function() {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getAllFlowNodes(node) {
 | 
			
		||||
        var visited = {};
 | 
			
		||||
        visited[node.id] = true;
 | 
			
		||||
        var nns = [node];
 | 
			
		||||
        var stack = [node];
 | 
			
		||||
        while(stack.length !== 0) {
 | 
			
		||||
            var n = stack.shift();
 | 
			
		||||
            var childLinks = links.filter(function(d) { return (d.source === n) || (d.target === n);});
 | 
			
		||||
            for (var i=0;i<childLinks.length;i++) {
 | 
			
		||||
                var child = (childLinks[i].source === n)?childLinks[i].target:childLinks[i].source;
 | 
			
		||||
                var id = child.id;
 | 
			
		||||
                if (!id) {
 | 
			
		||||
                    id = child.direction+":"+child.i;
 | 
			
		||||
                }
 | 
			
		||||
                if (!visited[id]) {
 | 
			
		||||
                    visited[id] = true;
 | 
			
		||||
                    nns.push(child);
 | 
			
		||||
                    stack.push(child);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return nns;
 | 
			
		||||
    function getAllDownstreamNodes(node) {
 | 
			
		||||
        return getAllFlowNodes(node,'down');
 | 
			
		||||
    }
 | 
			
		||||
    function getAllUpstreamNodes(node) {
 | 
			
		||||
        return getAllFlowNodes(node,'up');
 | 
			
		||||
    }
 | 
			
		||||
    function getAllFlowNodes(node, direction) {
 | 
			
		||||
        var selection = RED.view.selection();
 | 
			
		||||
        var visited = new Set();
 | 
			
		||||
        var nodes = [node];
 | 
			
		||||
        while(nodes.length > 0) {
 | 
			
		||||
            var n = nodes.shift();
 | 
			
		||||
            visited.add(n);
 | 
			
		||||
            var links = [];
 | 
			
		||||
            if (!direction || direction === 'up') {
 | 
			
		||||
                links = links.concat(nodeLinks[n.id].in);
 | 
			
		||||
            }
 | 
			
		||||
            if (!direction || direction === 'down') {
 | 
			
		||||
                links = links.concat(nodeLinks[n.id].out);
 | 
			
		||||
            }
 | 
			
		||||
            links.forEach(function(l) {
 | 
			
		||||
                if (!visited.has(l.source)) {
 | 
			
		||||
                    nodes.push(l.source);
 | 
			
		||||
                }
 | 
			
		||||
                if (!visited.has(l.target)) {
 | 
			
		||||
                    nodes.push(l.target);
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
        return Array.from(visited);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    function convertWorkspace(n) {
 | 
			
		||||
        var node = {};
 | 
			
		||||
@@ -1884,9 +1936,37 @@ RED.nodes = (function() {
 | 
			
		||||
    }
 | 
			
		||||
    function filterLinks(filter) {
 | 
			
		||||
        var result = [];
 | 
			
		||||
 | 
			
		||||
        for (var n=0;n<links.length;n++) {
 | 
			
		||||
            var link = links[n];
 | 
			
		||||
        var candidateLinks = [];
 | 
			
		||||
        var hasCandidates = false;
 | 
			
		||||
        var filterSZ = filter.source && filter.source.z;
 | 
			
		||||
        var filterTZ = filter.target && filter.target.z;
 | 
			
		||||
        var filterZ;
 | 
			
		||||
        if (filterSZ || filterTZ) {
 | 
			
		||||
            if (filterSZ === filterTZ) {
 | 
			
		||||
                filterZ = filterSZ;
 | 
			
		||||
            } else {
 | 
			
		||||
                filterZ = (filterSZ === undefined)?filterTZ:filterSZ
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (filterZ) {
 | 
			
		||||
            candidateLinks = linkTabMap[filterZ] || [];
 | 
			
		||||
            hasCandidates = true;
 | 
			
		||||
        } else if (filter.source && filter.source.hasOwnProperty("id")) {
 | 
			
		||||
            if (nodeLinks[filter.source.id]) {
 | 
			
		||||
                hasCandidates = true;
 | 
			
		||||
                candidateLinks = candidateLinks.concat(nodeLinks[filter.source.id].out)
 | 
			
		||||
            }
 | 
			
		||||
        } else if (filter.target && filter.target.hasOwnProperty("id")) {
 | 
			
		||||
            if (nodeLinks[filter.target.id]) {
 | 
			
		||||
                hasCandidates = true;
 | 
			
		||||
                candidateLinks = candidateLinks.concat(nodeLinks[filter.target.id].in)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!hasCandidates) {
 | 
			
		||||
            candidateLinks = links;
 | 
			
		||||
        }
 | 
			
		||||
        for (var n=0;n<candidateLinks.length;n++) {
 | 
			
		||||
            var link = candidateLinks[n];
 | 
			
		||||
            if (filter.source) {
 | 
			
		||||
                if (filter.source.hasOwnProperty("id") && link.source.id !== filter.source.id) {
 | 
			
		||||
                    continue;
 | 
			
		||||
@@ -1943,6 +2023,8 @@ RED.nodes = (function() {
 | 
			
		||||
        nodes = {};
 | 
			
		||||
        links = [];
 | 
			
		||||
        nodeTabMap = {};
 | 
			
		||||
        linkTabMap = {};
 | 
			
		||||
        nodeLinks = {};
 | 
			
		||||
        configNodes = {};
 | 
			
		||||
        workspacesOrder = [];
 | 
			
		||||
        groups = {};
 | 
			
		||||
@@ -1968,16 +2050,6 @@ RED.nodes = (function() {
 | 
			
		||||
        RED.sidebar.info.refresh();
 | 
			
		||||
 | 
			
		||||
        RED.events.emit("workspace:clear");
 | 
			
		||||
 | 
			
		||||
        // var node_defs = {};
 | 
			
		||||
        // var nodes = {};
 | 
			
		||||
        // var configNodes = {};
 | 
			
		||||
        // var links = [];
 | 
			
		||||
        // var defaultWorkspace;
 | 
			
		||||
        // var workspaces = {};
 | 
			
		||||
        // var workspacesOrder =[];
 | 
			
		||||
        // var subflows = {};
 | 
			
		||||
        // var loadedFlowVersion = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function addGroup(group) {
 | 
			
		||||
@@ -2184,6 +2256,8 @@ RED.nodes = (function() {
 | 
			
		||||
        identifyImportConflicts: identifyImportConflicts,
 | 
			
		||||
 | 
			
		||||
        getAllFlowNodes: getAllFlowNodes,
 | 
			
		||||
        getAllUpstreamNodes: getAllUpstreamNodes,
 | 
			
		||||
        getAllDownstreamNodes: getAllDownstreamNodes,
 | 
			
		||||
        createExportableNodeSet: createExportableNodeSet,
 | 
			
		||||
        createCompleteNodeSet: createCompleteNodeSet,
 | 
			
		||||
        updateConfigNodeUsers: updateConfigNodeUsers,
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,27 @@
 | 
			
		||||
 | 
			
		||||
RED.view.tools = (function() {
 | 
			
		||||
 | 
			
		||||
    function selectConnected(type) {
 | 
			
		||||
        var selection = RED.view.selection();
 | 
			
		||||
        var visited = new Set();
 | 
			
		||||
        if (selection.nodes && selection.nodes.length > 0) {
 | 
			
		||||
            selection.nodes.forEach(function(n) {
 | 
			
		||||
                if (!visited.has(n)) {
 | 
			
		||||
                    var connected;
 | 
			
		||||
                    if (type === 'all') {
 | 
			
		||||
                        connected = RED.nodes.getAllFlowNodes(n);
 | 
			
		||||
                    } else if (type === 'up') {
 | 
			
		||||
                        connected = RED.nodes.getAllUpstreamNodes(n);
 | 
			
		||||
                    } else if (type === 'down') {
 | 
			
		||||
                        connected = RED.nodes.getAllDownstreamNodes(n);
 | 
			
		||||
                    }
 | 
			
		||||
                    connected.forEach(function(nn) { visited.add(nn) })
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            RED.view.select({nodes:Array.from(visited)});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function alignToGrid() {
 | 
			
		||||
        var selection = RED.view.selection();
 | 
			
		||||
@@ -206,6 +227,10 @@ RED.view.tools = (function() {
 | 
			
		||||
            RED.actions.add("core:step-selection-right", function() { moveSelection(RED.view.gridSize(),0);});
 | 
			
		||||
            RED.actions.add("core:step-selection-down", function() { moveSelection(0,RED.view.gridSize());});
 | 
			
		||||
            RED.actions.add("core:step-selection-left", function() { moveSelection(-RED.view.gridSize(),0);});
 | 
			
		||||
 | 
			
		||||
            RED.actions.add("core:select-connected-nodes", function() { selectConnected("all") });
 | 
			
		||||
            RED.actions.add("core:select-downstream-nodes", function() { selectConnected("down") });
 | 
			
		||||
            RED.actions.add("core:select-upstream-nodes", function() { selectConnected("up") });
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * Aligns all selected nodes to the current grid
 | 
			
		||||
 
 | 
			
		||||
@@ -2992,6 +2992,7 @@ RED.view = (function() {
 | 
			
		||||
                        enterActiveGroup(ag);
 | 
			
		||||
                        activeGroup.selected = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    console.log(d3.event);
 | 
			
		||||
                    var cnodes = RED.nodes.getAllFlowNodes(mousedown_node);
 | 
			
		||||
                    for (var n=0;n<cnodes.length;n++) {
 | 
			
		||||
                        if (!cnodes[n].selected) {
 | 
			
		||||
@@ -3080,7 +3081,19 @@ RED.view = (function() {
 | 
			
		||||
            // } else
 | 
			
		||||
            if (d3.event.shiftKey) {
 | 
			
		||||
                clearSelection();
 | 
			
		||||
                var cnodes = RED.nodes.getAllFlowNodes(mousedown_node);
 | 
			
		||||
                var clickPosition = (d3.event.offsetX - mousedown_node.x)
 | 
			
		||||
                var edgeDelta = (mousedown_node.w/2) - Math.abs(clickPosition);
 | 
			
		||||
                var cnodes;
 | 
			
		||||
                var targetEdgeDelta = mousedown_node.w > 30 ? 25 : 8;
 | 
			
		||||
                if (edgeDelta < targetEdgeDelta) {
 | 
			
		||||
                    if (clickPosition < 0) {
 | 
			
		||||
                        cnodes = RED.nodes.getAllUpstreamNodes(mousedown_node);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        cnodes = RED.nodes.getAllDownstreamNodes(mousedown_node);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    cnodes = RED.nodes.getAllFlowNodes(mousedown_node);
 | 
			
		||||
                }
 | 
			
		||||
                for (var n=0;n<cnodes.length;n++) {
 | 
			
		||||
                    cnodes[n].selected = true;
 | 
			
		||||
                    cnodes[n].dirty = true;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user