mirror of https://github.com/node-red/node-red.git
				
				
				
			Add right-click context menu to workspace
							parent
							
								
									28238eb5a7
								
							
						
					
					
						commit
						0eba4bdd61
					
				| 
						 | 
				
			
			@ -192,6 +192,7 @@ module.exports = function(grunt) {
 | 
			
		|||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
 | 
			
		||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
 | 
			
		||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
 | 
			
		||||
                    "packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js",
 | 
			
		||||
                    "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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,175 @@
 | 
			
		|||
RED.contextMenu = (function() {
 | 
			
		||||
 | 
			
		||||
    let menu;
 | 
			
		||||
    function createMenu() {
 | 
			
		||||
        // menu = RED.popover.menu({
 | 
			
		||||
        //     options: [
 | 
			
		||||
        //         {
 | 
			
		||||
        //             label: 'delete selection',
 | 
			
		||||
        //             onselect: function() {
 | 
			
		||||
        //                 RED.actions.invoke('core:delete-selection')
 | 
			
		||||
        //                 RED.view.focus()
 | 
			
		||||
        //             }
 | 
			
		||||
        //         },
 | 
			
		||||
        //         { label: 'world' }
 | 
			
		||||
        //     ],
 | 
			
		||||
        //     width: 200,
 | 
			
		||||
        // })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function disposeMenu() {
 | 
			
		||||
        $(document).off("mousedown.red-ui-workspace-context-menu");
 | 
			
		||||
        if (menu) {
 | 
			
		||||
            menu.remove();
 | 
			
		||||
        }
 | 
			
		||||
        menu = null;
 | 
			
		||||
    }
 | 
			
		||||
    function show(options) {
 | 
			
		||||
        if (menu) {
 | 
			
		||||
            menu.remove()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const selection = RED.view.selection()
 | 
			
		||||
        const hasSelection = (selection.nodes && selection.nodes.length > 0);
 | 
			
		||||
        const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
 | 
			
		||||
        const hasLinks = selection.links && selection.links.length > 0;
 | 
			
		||||
        const isSingleLink = !hasSelection && hasLinks && selection.links.length === 1
 | 
			
		||||
        const isMultipleLinks = !hasSelection && hasLinks && selection.links.length > 1
 | 
			
		||||
        const canDelete = hasSelection || hasLinks
 | 
			
		||||
        const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
 | 
			
		||||
 | 
			
		||||
        const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        const menuItems = [
 | 
			
		||||
            { onselect: 'core:show-action-list', onpostselect: function() {} },
 | 
			
		||||
            {
 | 
			
		||||
                label: 'Insert',
 | 
			
		||||
                options: [
 | 
			
		||||
                    {
 | 
			
		||||
                        label: 'Node',
 | 
			
		||||
                        onselect: function() {
 | 
			
		||||
                            RED.view.showQuickAddDialog({
 | 
			
		||||
                                position: [ options.x - offset.left, options.y - offset.top ],
 | 
			
		||||
                                touchTrigger: true,
 | 
			
		||||
                                splice: isSingleLink?selection.links[0]:undefined,
 | 
			
		||||
                                // spliceMultiple: isMultipleLinks
 | 
			
		||||
                            })
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        label: 'Junction',
 | 
			
		||||
                        onselect: 'core:split-wires-with-junctions',
 | 
			
		||||
                        disabled: hasSelection || !hasLinks
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        label: 'Link Nodes',
 | 
			
		||||
                        onselect: 'core:split-wire-with-link-nodes',
 | 
			
		||||
                        disabled: hasSelection || !hasLinks
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
        // menuItems.push(
 | 
			
		||||
        //     {
 | 
			
		||||
        //         label: (isSingleLink || isMultipleLinks)?'Insert into wire...':'Add node...',
 | 
			
		||||
        //         onselect: function() {
 | 
			
		||||
        //             RED.view.showQuickAddDialog({
 | 
			
		||||
        //                 position: [ options.x - offset.left, options.y - offset.top ],
 | 
			
		||||
        //                 touchTrigger: true,
 | 
			
		||||
        //                 splice: isSingleLink?selection.links[0]:undefined,
 | 
			
		||||
        //                 spliceMultiple: isMultipleLinks
 | 
			
		||||
        //             })
 | 
			
		||||
        //         }
 | 
			
		||||
        //     },
 | 
			
		||||
        // )
 | 
			
		||||
        // if (hasLinks && !hasSelection) {
 | 
			
		||||
        //     menuItems.push({ onselect: 'core:split-wires-with-junctions', label: 'Insert junction'})
 | 
			
		||||
        // }
 | 
			
		||||
        menuItems.push(
 | 
			
		||||
            null,
 | 
			
		||||
            { onselect: 'core:undo', disabled: RED.history.list().length === 0 },
 | 
			
		||||
            { onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
 | 
			
		||||
            null,
 | 
			
		||||
            { onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection},
 | 
			
		||||
            { onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection },
 | 
			
		||||
            { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !RED.view.clipboard() },
 | 
			
		||||
            { onselect: 'core:delete-selection', disabled: !canDelete },
 | 
			
		||||
            { onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
 | 
			
		||||
            { onselect: 'core:select-all-nodes' },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if (hasSelection) {
 | 
			
		||||
            menuItems.push(
 | 
			
		||||
                null,
 | 
			
		||||
                isGroup
 | 
			
		||||
                ? { onselect: 'core:ungroup-selection', disabled: !isGroup }
 | 
			
		||||
                : { onselect: 'core:group-selection', disabled: !hasSelection }
 | 
			
		||||
            )
 | 
			
		||||
            if (canRemoveFromGroup) {
 | 
			
		||||
                menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") })
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        const offset = $("#red-ui-workspace-chart").offset()
 | 
			
		||||
        menu = RED.menu.init({
 | 
			
		||||
            direction: 'right',
 | 
			
		||||
            onpreselect: function() {
 | 
			
		||||
                disposeMenu()
 | 
			
		||||
            },
 | 
			
		||||
            onpostselect: function() {
 | 
			
		||||
                RED.view.focus()
 | 
			
		||||
            },
 | 
			
		||||
            options: menuItems
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        menu.attr("id","red-ui-workspace-context-menu");
 | 
			
		||||
        menu.css({
 | 
			
		||||
            position: "absolute"
 | 
			
		||||
        })
 | 
			
		||||
        menu.appendTo("body");
 | 
			
		||||
 | 
			
		||||
        // TODO: prevent the menu from overflowing the window.
 | 
			
		||||
 | 
			
		||||
        var top = options.y
 | 
			
		||||
        var left = options.x
 | 
			
		||||
 | 
			
		||||
        if (top+menu.height()-$(document).scrollTop() > $(window).height()) {
 | 
			
		||||
            top -= (top+menu.height())-$(window).height() + 22;
 | 
			
		||||
        }
 | 
			
		||||
        if (left+menu.width()-$(document).scrollLeft() > $(window).width()) {
 | 
			
		||||
            left -= (left+menu.width())-$(window).width() + 18;
 | 
			
		||||
        }
 | 
			
		||||
        menu.css({
 | 
			
		||||
            top: top+"px",
 | 
			
		||||
            left: left+"px"
 | 
			
		||||
        })
 | 
			
		||||
        $(".red-ui-menu.red-ui-menu-dropdown").hide();
 | 
			
		||||
        $(document).on("mousedown.red-ui-workspace-context-menu", function(evt) {
 | 
			
		||||
            if (menu && menu[0].contains(evt.target)) {
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
            disposeMenu()
 | 
			
		||||
        });
 | 
			
		||||
        menu.show();
 | 
			
		||||
 | 
			
		||||
        // menu.show({
 | 
			
		||||
        //     target: $('#red-ui-main-container'),
 | 
			
		||||
        //     x: options.x,
 | 
			
		||||
        //     y: options.y
 | 
			
		||||
        // })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        show: show
 | 
			
		||||
    }
 | 
			
		||||
})()
 | 
			
		||||
| 
						 | 
				
			
			@ -336,17 +336,17 @@ RED.view.tools = (function() {
 | 
			
		|||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function addNode() {
 | 
			
		||||
        var selection = RED.view.selection();
 | 
			
		||||
        if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].outputs > 0) {
 | 
			
		||||
            var selectedNode = selection.nodes[0];
 | 
			
		||||
            RED.view.showQuickAddDialog([
 | 
			
		||||
                selectedNode.x + selectedNode.w + 50,selectedNode.y
 | 
			
		||||
            ])
 | 
			
		||||
        } else {
 | 
			
		||||
            RED.view.showQuickAddDialog();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // function addNode() {
 | 
			
		||||
    //     var selection = RED.view.selection();
 | 
			
		||||
    //     if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].outputs > 0) {
 | 
			
		||||
    //         var selectedNode = selection.nodes[0];
 | 
			
		||||
    //         RED.view.showQuickAddDialog([
 | 
			
		||||
    //             selectedNode.x + selectedNode.w + 50,selectedNode.y
 | 
			
		||||
    //         ])
 | 
			
		||||
    //     } else {
 | 
			
		||||
    //         RED.view.showQuickAddDialog();
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    function gotoNearestNode(direction) {
 | 
			
		||||
| 
						 | 
				
			
			@ -815,6 +815,9 @@ RED.view.tools = (function() {
 | 
			
		|||
     */
 | 
			
		||||
    function splitWiresWithLinkNodes(wires) {
 | 
			
		||||
        let wiresToSplit = wires || RED.view.selection().links;
 | 
			
		||||
        if (!wiresToSplit) {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        if (!Array.isArray(wiresToSplit)) {
 | 
			
		||||
            wiresToSplit = [wiresToSplit];
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1047,6 +1050,135 @@ RED.view.tools = (function() {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function addJunctionsToWires(wires) {
 | 
			
		||||
        let wiresToSplit = wires || RED.view.selection().links;
 | 
			
		||||
        if (!wiresToSplit) {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        if (!Array.isArray(wiresToSplit)) {
 | 
			
		||||
            wiresToSplit = [wiresToSplit];
 | 
			
		||||
        }
 | 
			
		||||
        if (wiresToSplit.length === 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var removedLinks = new Set()
 | 
			
		||||
        var addedLinks = []
 | 
			
		||||
        var addedJunctions = []
 | 
			
		||||
 | 
			
		||||
        var groupedLinks = {}
 | 
			
		||||
        wiresToSplit.forEach(function(l) {
 | 
			
		||||
            var sourceId = l.source.id+":"+l.sourcePort
 | 
			
		||||
            groupedLinks[sourceId] = groupedLinks[sourceId] || []
 | 
			
		||||
            groupedLinks[sourceId].push(l)
 | 
			
		||||
 | 
			
		||||
            groupedLinks[l.target.id] = groupedLinks[l.target.id] || []
 | 
			
		||||
            groupedLinks[l.target.id].push(l)
 | 
			
		||||
        });
 | 
			
		||||
        var linkGroups = Object.keys(groupedLinks)
 | 
			
		||||
        linkGroups.sort(function(A,B) {
 | 
			
		||||
            return groupedLinks[B].length - groupedLinks[A].length
 | 
			
		||||
        })
 | 
			
		||||
        linkGroups.forEach(function(gid) {
 | 
			
		||||
            var links = groupedLinks[gid]
 | 
			
		||||
            var junction = {
 | 
			
		||||
                _def: {defaults:{}},
 | 
			
		||||
                type: 'junction',
 | 
			
		||||
                z: RED.workspaces.active(),
 | 
			
		||||
                id: RED.nodes.id(),
 | 
			
		||||
                x: 0,
 | 
			
		||||
                y: 0,
 | 
			
		||||
                w: 0, h: 0,
 | 
			
		||||
                outputs: 1,
 | 
			
		||||
                inputs: 1,
 | 
			
		||||
                dirty: true
 | 
			
		||||
            }
 | 
			
		||||
            links = links.filter(function(l) { return !removedLinks.has(l) })
 | 
			
		||||
            if (links.length === 0) {
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
            let pointCount = 0
 | 
			
		||||
            links.forEach(function(l) {
 | 
			
		||||
                if (l._sliceLocation) {
 | 
			
		||||
                    junction.x += l._sliceLocation.x
 | 
			
		||||
                    junction.y += l._sliceLocation.y
 | 
			
		||||
                    delete l._sliceLocation
 | 
			
		||||
                    pointCount++
 | 
			
		||||
                } else {
 | 
			
		||||
                    junction.x += l.source.x + l.source.w/2 + l.target.x - l.target.w/2
 | 
			
		||||
                    junction.y += l.source.y + l.target.y
 | 
			
		||||
                    pointCount += 2
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            junction.x = Math.round(junction.x/pointCount)
 | 
			
		||||
            junction.y = Math.round(junction.y/pointCount)
 | 
			
		||||
            if (RED.view.snapGrid) {
 | 
			
		||||
                let gridSize = RED.view.gridSize()
 | 
			
		||||
                junction.x = (gridSize*Math.round(junction.x/gridSize));
 | 
			
		||||
                junction.y = (gridSize*Math.round(junction.y/gridSize));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var nodeGroups = new Set()
 | 
			
		||||
 | 
			
		||||
            RED.nodes.addJunction(junction)
 | 
			
		||||
            addedJunctions.push(junction)
 | 
			
		||||
            let newLink
 | 
			
		||||
            if (gid === links[0].source.id+":"+links[0].sourcePort) {
 | 
			
		||||
                newLink = {
 | 
			
		||||
                    source: links[0].source,
 | 
			
		||||
                    sourcePort: links[0].sourcePort,
 | 
			
		||||
                    target: junction
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                newLink = {
 | 
			
		||||
                    source: junction,
 | 
			
		||||
                    sourcePort: 0,
 | 
			
		||||
                    target: links[0].target
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            addedLinks.push(newLink)
 | 
			
		||||
            RED.nodes.addLink(newLink)
 | 
			
		||||
            links.forEach(function(l) {
 | 
			
		||||
                removedLinks.add(l)
 | 
			
		||||
                RED.nodes.removeLink(l)
 | 
			
		||||
                let newLink
 | 
			
		||||
                if (gid === l.target.id) {
 | 
			
		||||
                    newLink = {
 | 
			
		||||
                        source: l.source,
 | 
			
		||||
                        sourcePort: l.sourcePort,
 | 
			
		||||
                        target: junction
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    newLink = {
 | 
			
		||||
                        source: junction,
 | 
			
		||||
                        sourcePort: 0,
 | 
			
		||||
                        target: l.target
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                addedLinks.push(newLink)
 | 
			
		||||
                RED.nodes.addLink(newLink)
 | 
			
		||||
                nodeGroups.add(l.source.g || "__NONE__")
 | 
			
		||||
                nodeGroups.add(l.target.g || "__NONE__")
 | 
			
		||||
            })
 | 
			
		||||
            if (nodeGroups.size === 1) {
 | 
			
		||||
                var group = nodeGroups.values().next().value
 | 
			
		||||
                if (group !== "__NONE__") {
 | 
			
		||||
                    RED.group.addToGroup(RED.nodes.group(group), junction)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        if (addedJunctions.length > 0) {
 | 
			
		||||
            RED.history.push({
 | 
			
		||||
                t: 'add',
 | 
			
		||||
                links: addedLinks,
 | 
			
		||||
                junctions: addedJunctions,
 | 
			
		||||
                removedLinks: Array.from(removedLinks)
 | 
			
		||||
            })
 | 
			
		||||
            RED.nodes.dirty(true)
 | 
			
		||||
        }
 | 
			
		||||
        RED.view.redraw(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        init: function() {
 | 
			
		||||
            RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
 | 
			
		||||
| 
						 | 
				
			
			@ -1109,6 +1241,7 @@ RED.view.tools = (function() {
 | 
			
		|||
            RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
 | 
			
		||||
 | 
			
		||||
            RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
 | 
			
		||||
            RED.actions.add("core:split-wires-with-junctions", function () { addJunctionsToWires() });
 | 
			
		||||
 | 
			
		||||
            RED.actions.add("core:generate-node-names", generateNodeNames )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -206,7 +206,15 @@ RED.view = (function() {
 | 
			
		|||
    function init() {
 | 
			
		||||
 | 
			
		||||
        chart = $("#red-ui-workspace-chart");
 | 
			
		||||
 | 
			
		||||
        chart.on('contextmenu', function(evt) {
 | 
			
		||||
            evt.preventDefault()
 | 
			
		||||
            evt.stopPropagation()
 | 
			
		||||
            RED.contextMenu.show({
 | 
			
		||||
                x:evt.clientX-5,
 | 
			
		||||
                y:evt.clientY-5
 | 
			
		||||
            })
 | 
			
		||||
            return false
 | 
			
		||||
        })
 | 
			
		||||
        outer = d3.select("#red-ui-workspace-chart")
 | 
			
		||||
            .append("svg:svg")
 | 
			
		||||
            .attr("width", space_width)
 | 
			
		||||
| 
						 | 
				
			
			@ -992,7 +1000,10 @@ RED.view = (function() {
 | 
			
		|||
            scroll_position = [chart.scrollLeft(),chart.scrollTop()];
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (!mousedown_node && !mousedown_link && !mousedown_group) {
 | 
			
		||||
        if (d3.event.button === 2) {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        if (!mousedown_node && !mousedown_link && !mousedown_group && !d3.event.shiftKey) {
 | 
			
		||||
            selectedLinks.clear();
 | 
			
		||||
            updateSelection();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1046,6 +1057,7 @@ RED.view = (function() {
 | 
			
		|||
        options = options || {};
 | 
			
		||||
        var point = options.position || lastClickPosition;
 | 
			
		||||
        var spliceLink = options.splice;
 | 
			
		||||
        var spliceMultipleLinks = options.spliceMultiple
 | 
			
		||||
        var targetGroup = options.group;
 | 
			
		||||
        var touchTrigger = options.touchTrigger;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1058,6 +1070,10 @@ RED.view = (function() {
 | 
			
		|||
        var ox = point[0];
 | 
			
		||||
        var oy = point[1];
 | 
			
		||||
 | 
			
		||||
        const offset = $("#red-ui-workspace-chart").offset()
 | 
			
		||||
        var clientX = ox + offset.left
 | 
			
		||||
        var clientY = oy + offset.top
 | 
			
		||||
 | 
			
		||||
        if (RED.settings.get("editor").view['view-snap-grid']) {
 | 
			
		||||
            // eventLayer.append("circle").attr("cx",point[0]).attr("cy",point[1]).attr("r","2").attr('fill','red')
 | 
			
		||||
            point[0] = Math.round(point[0] / gridSize) * gridSize;
 | 
			
		||||
| 
						 | 
				
			
			@ -1109,8 +1125,12 @@ RED.view = (function() {
 | 
			
		|||
            }
 | 
			
		||||
            hideDragLines();
 | 
			
		||||
        }
 | 
			
		||||
        if (spliceLink) {
 | 
			
		||||
            filter = {input:true, output:true}
 | 
			
		||||
        if (spliceLink || spliceMultipleLinks) {
 | 
			
		||||
            filter = {
 | 
			
		||||
                input:true,
 | 
			
		||||
                output:true,
 | 
			
		||||
                spliceMultiple: spliceMultipleLinks
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var rebuildQuickAddLink = function() {
 | 
			
		||||
| 
						 | 
				
			
			@ -1135,8 +1155,8 @@ RED.view = (function() {
 | 
			
		|||
        var lastAddedWidth;
 | 
			
		||||
 | 
			
		||||
        RED.typeSearch.show({
 | 
			
		||||
            x:d3.event.clientX-mainPos.left-node_width/2 - (ox-point[0]),
 | 
			
		||||
            y:d3.event.clientY-mainPos.top+ node_height/2 + 5 - (oy-point[1]),
 | 
			
		||||
            x:clientX-mainPos.left-node_width/2 - (ox-point[0]),
 | 
			
		||||
            y:clientY-mainPos.top+ node_height/2 + 5 - (oy-point[1]),
 | 
			
		||||
            disableFocus: touchTrigger,
 | 
			
		||||
            filter: filter,
 | 
			
		||||
            move: function(dx,dy) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1164,7 +1184,7 @@ RED.view = (function() {
 | 
			
		|||
                hideDragLines();
 | 
			
		||||
                redraw();
 | 
			
		||||
            },
 | 
			
		||||
            add: function(type,keepAdding) {
 | 
			
		||||
            add: function(type, keepAdding) {
 | 
			
		||||
                if (touchTrigger) {
 | 
			
		||||
                    keepAdding = false;
 | 
			
		||||
                    resetMouseVars();
 | 
			
		||||
| 
						 | 
				
			
			@ -1172,7 +1192,13 @@ RED.view = (function() {
 | 
			
		|||
 | 
			
		||||
                var nn;
 | 
			
		||||
                var historyEvent;
 | 
			
		||||
                if (type === 'junction') {
 | 
			
		||||
                if (/^_action_:/.test(type)) {
 | 
			
		||||
                    const actionName = type.substring(9)
 | 
			
		||||
                    quickAddActive = false;
 | 
			
		||||
                    ghostNode.remove();
 | 
			
		||||
                    RED.actions.invoke(actionName)
 | 
			
		||||
                    return
 | 
			
		||||
                } else if (type === 'junction') {
 | 
			
		||||
                    nn = {
 | 
			
		||||
                        _def: {defaults:{}},
 | 
			
		||||
                        type: 'junction',
 | 
			
		||||
| 
						 | 
				
			
			@ -1844,8 +1870,20 @@ RED.view = (function() {
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            activeLinks.forEach(function(link) {
 | 
			
		||||
                if (!link.selected) {
 | 
			
		||||
                    var sourceY = link.source.y
 | 
			
		||||
                    var targetY = link.target.y
 | 
			
		||||
                    var sourceX = link.source.x+(link.source.w/2) + 10
 | 
			
		||||
                    var targetX = link.target.x-(link.target.w/2) - 10
 | 
			
		||||
                    if (
 | 
			
		||||
                        sourceX > x && sourceX < x2 && sourceY > y && sourceY < y2 &&
 | 
			
		||||
                        targetX > x && targetX < x2 && targetY > y && targetY < y2
 | 
			
		||||
                    ) {
 | 
			
		||||
                        selectedLinks.add(link);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            // var selectionChanged = false;
 | 
			
		||||
            // do {
 | 
			
		||||
| 
						 | 
				
			
			@ -1893,114 +1931,118 @@ RED.view = (function() {
 | 
			
		|||
            slicePath = null;
 | 
			
		||||
            RED.view.redraw(true);
 | 
			
		||||
        } else if (mouse_mode == RED.state.SLICING_JUNCTION) {
 | 
			
		||||
            var removedLinks = new Set()
 | 
			
		||||
            var addedLinks = []
 | 
			
		||||
            var addedJunctions = []
 | 
			
		||||
 | 
			
		||||
            var groupedLinks = {}
 | 
			
		||||
            selectedLinks.forEach(function(l) {
 | 
			
		||||
                var sourceId = l.source.id+":"+l.sourcePort
 | 
			
		||||
                groupedLinks[sourceId] = groupedLinks[sourceId] || []
 | 
			
		||||
                groupedLinks[sourceId].push(l)
 | 
			
		||||
 | 
			
		||||
                groupedLinks[l.target.id] = groupedLinks[l.target.id] || []
 | 
			
		||||
                groupedLinks[l.target.id].push(l)
 | 
			
		||||
            });
 | 
			
		||||
            var linkGroups = Object.keys(groupedLinks)
 | 
			
		||||
            linkGroups.sort(function(A,B) {
 | 
			
		||||
                return groupedLinks[B].length - groupedLinks[A].length
 | 
			
		||||
            })
 | 
			
		||||
            linkGroups.forEach(function(gid) {
 | 
			
		||||
                var links = groupedLinks[gid]
 | 
			
		||||
                var junction = {
 | 
			
		||||
                    _def: {defaults:{}},
 | 
			
		||||
                    type: 'junction',
 | 
			
		||||
                    z: RED.workspaces.active(),
 | 
			
		||||
                    id: RED.nodes.id(),
 | 
			
		||||
                    x: 0,
 | 
			
		||||
                    y: 0,
 | 
			
		||||
                    w: 0, h: 0,
 | 
			
		||||
                    outputs: 1,
 | 
			
		||||
                    inputs: 1,
 | 
			
		||||
                    dirty: true
 | 
			
		||||
                }
 | 
			
		||||
                links = links.filter(function(l) { return !removedLinks.has(l) })
 | 
			
		||||
                if (links.length === 0) {
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                links.forEach(function(l) {
 | 
			
		||||
                    junction.x += l._sliceLocation.x
 | 
			
		||||
                    junction.y += l._sliceLocation.y
 | 
			
		||||
                })
 | 
			
		||||
                junction.x = Math.round(junction.x/links.length)
 | 
			
		||||
                junction.y = Math.round(junction.y/links.length)
 | 
			
		||||
                if (snapGrid) {
 | 
			
		||||
                    junction.x = (gridSize*Math.round(junction.x/gridSize));
 | 
			
		||||
                    junction.y = (gridSize*Math.round(junction.y/gridSize));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var nodeGroups = new Set()
 | 
			
		||||
 | 
			
		||||
                RED.nodes.addJunction(junction)
 | 
			
		||||
                addedJunctions.push(junction)
 | 
			
		||||
                let newLink
 | 
			
		||||
                if (gid === links[0].source.id+":"+links[0].sourcePort) {
 | 
			
		||||
                    newLink = {
 | 
			
		||||
                        source: links[0].source,
 | 
			
		||||
                        sourcePort: links[0].sourcePort,
 | 
			
		||||
                        target: junction
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    newLink = {
 | 
			
		||||
                        source: junction,
 | 
			
		||||
                        sourcePort: 0,
 | 
			
		||||
                        target: links[0].target
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                addedLinks.push(newLink)
 | 
			
		||||
                RED.nodes.addLink(newLink)
 | 
			
		||||
                links.forEach(function(l) {
 | 
			
		||||
                    removedLinks.add(l)
 | 
			
		||||
                    RED.nodes.removeLink(l)
 | 
			
		||||
                    let newLink
 | 
			
		||||
                    if (gid === l.target.id) {
 | 
			
		||||
                        newLink = {
 | 
			
		||||
                            source: l.source,
 | 
			
		||||
                            sourcePort: l.sourcePort,
 | 
			
		||||
                            target: junction
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        newLink = {
 | 
			
		||||
                            source: junction,
 | 
			
		||||
                            sourcePort: 0,
 | 
			
		||||
                            target: l.target
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    addedLinks.push(newLink)
 | 
			
		||||
                    RED.nodes.addLink(newLink)
 | 
			
		||||
                    nodeGroups.add(l.source.g || "__NONE__")
 | 
			
		||||
                    nodeGroups.add(l.target.g || "__NONE__")
 | 
			
		||||
                })
 | 
			
		||||
                if (nodeGroups.size === 1) {
 | 
			
		||||
                    var group = nodeGroups.values().next().value
 | 
			
		||||
                    if (group !== "__NONE__") {
 | 
			
		||||
                        RED.group.addToGroup(RED.nodes.group(group), junction)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            RED.actions.invoke("core:split-wires-with-junctions")
 | 
			
		||||
            slicePath.remove();
 | 
			
		||||
            slicePath = null;
 | 
			
		||||
 | 
			
		||||
            if (addedJunctions.length > 0) {
 | 
			
		||||
                RED.history.push({
 | 
			
		||||
                    t: 'add',
 | 
			
		||||
                    links: addedLinks,
 | 
			
		||||
                    junctions: addedJunctions,
 | 
			
		||||
                    removedLinks: Array.from(removedLinks)
 | 
			
		||||
                })
 | 
			
		||||
                RED.nodes.dirty(true)
 | 
			
		||||
            }
 | 
			
		||||
            RED.view.redraw(true);
 | 
			
		||||
            // var removedLinks = new Set()
 | 
			
		||||
            // var addedLinks = []
 | 
			
		||||
            // var addedJunctions = []
 | 
			
		||||
            //
 | 
			
		||||
            // var groupedLinks = {}
 | 
			
		||||
            // selectedLinks.forEach(function(l) {
 | 
			
		||||
            //     var sourceId = l.source.id+":"+l.sourcePort
 | 
			
		||||
            //     groupedLinks[sourceId] = groupedLinks[sourceId] || []
 | 
			
		||||
            //     groupedLinks[sourceId].push(l)
 | 
			
		||||
            //
 | 
			
		||||
            //     groupedLinks[l.target.id] = groupedLinks[l.target.id] || []
 | 
			
		||||
            //     groupedLinks[l.target.id].push(l)
 | 
			
		||||
            // });
 | 
			
		||||
            // var linkGroups = Object.keys(groupedLinks)
 | 
			
		||||
            // linkGroups.sort(function(A,B) {
 | 
			
		||||
            //     return groupedLinks[B].length - groupedLinks[A].length
 | 
			
		||||
            // })
 | 
			
		||||
            // linkGroups.forEach(function(gid) {
 | 
			
		||||
            //     var links = groupedLinks[gid]
 | 
			
		||||
            //     var junction = {
 | 
			
		||||
            //         _def: {defaults:{}},
 | 
			
		||||
            //         type: 'junction',
 | 
			
		||||
            //         z: RED.workspaces.active(),
 | 
			
		||||
            //         id: RED.nodes.id(),
 | 
			
		||||
            //         x: 0,
 | 
			
		||||
            //         y: 0,
 | 
			
		||||
            //         w: 0, h: 0,
 | 
			
		||||
            //         outputs: 1,
 | 
			
		||||
            //         inputs: 1,
 | 
			
		||||
            //         dirty: true
 | 
			
		||||
            //     }
 | 
			
		||||
            //     links = links.filter(function(l) { return !removedLinks.has(l) })
 | 
			
		||||
            //     if (links.length === 0) {
 | 
			
		||||
            //         return
 | 
			
		||||
            //     }
 | 
			
		||||
            //     links.forEach(function(l) {
 | 
			
		||||
            //         junction.x += l._sliceLocation.x
 | 
			
		||||
            //         junction.y += l._sliceLocation.y
 | 
			
		||||
            //     })
 | 
			
		||||
            //     junction.x = Math.round(junction.x/links.length)
 | 
			
		||||
            //     junction.y = Math.round(junction.y/links.length)
 | 
			
		||||
            //     if (snapGrid) {
 | 
			
		||||
            //         junction.x = (gridSize*Math.round(junction.x/gridSize));
 | 
			
		||||
            //         junction.y = (gridSize*Math.round(junction.y/gridSize));
 | 
			
		||||
            //     }
 | 
			
		||||
            //
 | 
			
		||||
            //     var nodeGroups = new Set()
 | 
			
		||||
            //
 | 
			
		||||
            //     RED.nodes.addJunction(junction)
 | 
			
		||||
            //     addedJunctions.push(junction)
 | 
			
		||||
            //     let newLink
 | 
			
		||||
            //     if (gid === links[0].source.id+":"+links[0].sourcePort) {
 | 
			
		||||
            //         newLink = {
 | 
			
		||||
            //             source: links[0].source,
 | 
			
		||||
            //             sourcePort: links[0].sourcePort,
 | 
			
		||||
            //             target: junction
 | 
			
		||||
            //         }
 | 
			
		||||
            //     } else {
 | 
			
		||||
            //         newLink = {
 | 
			
		||||
            //             source: junction,
 | 
			
		||||
            //             sourcePort: 0,
 | 
			
		||||
            //             target: links[0].target
 | 
			
		||||
            //         }
 | 
			
		||||
            //     }
 | 
			
		||||
            //     addedLinks.push(newLink)
 | 
			
		||||
            //     RED.nodes.addLink(newLink)
 | 
			
		||||
            //     links.forEach(function(l) {
 | 
			
		||||
            //         removedLinks.add(l)
 | 
			
		||||
            //         RED.nodes.removeLink(l)
 | 
			
		||||
            //         let newLink
 | 
			
		||||
            //         if (gid === l.target.id) {
 | 
			
		||||
            //             newLink = {
 | 
			
		||||
            //                 source: l.source,
 | 
			
		||||
            //                 sourcePort: l.sourcePort,
 | 
			
		||||
            //                 target: junction
 | 
			
		||||
            //             }
 | 
			
		||||
            //         } else {
 | 
			
		||||
            //             newLink = {
 | 
			
		||||
            //                 source: junction,
 | 
			
		||||
            //                 sourcePort: 0,
 | 
			
		||||
            //                 target: l.target
 | 
			
		||||
            //             }
 | 
			
		||||
            //         }
 | 
			
		||||
            //         addedLinks.push(newLink)
 | 
			
		||||
            //         RED.nodes.addLink(newLink)
 | 
			
		||||
            //         nodeGroups.add(l.source.g || "__NONE__")
 | 
			
		||||
            //         nodeGroups.add(l.target.g || "__NONE__")
 | 
			
		||||
            //     })
 | 
			
		||||
            //     if (nodeGroups.size === 1) {
 | 
			
		||||
            //         var group = nodeGroups.values().next().value
 | 
			
		||||
            //         if (group !== "__NONE__") {
 | 
			
		||||
            //             RED.group.addToGroup(RED.nodes.group(group), junction)
 | 
			
		||||
            //         }
 | 
			
		||||
            //     }
 | 
			
		||||
            // })
 | 
			
		||||
            // slicePath.remove();
 | 
			
		||||
            // slicePath = null;
 | 
			
		||||
            //
 | 
			
		||||
            // if (addedJunctions.length > 0) {
 | 
			
		||||
            //     RED.history.push({
 | 
			
		||||
            //         t: 'add',
 | 
			
		||||
            //         links: addedLinks,
 | 
			
		||||
            //         junctions: addedJunctions,
 | 
			
		||||
            //         removedLinks: Array.from(removedLinks)
 | 
			
		||||
            //     })
 | 
			
		||||
            //     RED.nodes.dirty(true)
 | 
			
		||||
            // }
 | 
			
		||||
            // RED.view.redraw(true);
 | 
			
		||||
        }
 | 
			
		||||
        if (mouse_mode == RED.state.MOVING_ACTIVE) {
 | 
			
		||||
            if (movingSet.length() > 0) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@
 | 
			
		|||
    & > li > a,
 | 
			
		||||
    & > li > a:focus {
 | 
			
		||||
        display: block;
 | 
			
		||||
        padding: 4px 12px 4px 32px;
 | 
			
		||||
        padding: 4px 20px 4px 12px;
 | 
			
		||||
        clear: both;
 | 
			
		||||
        font-weight: normal;
 | 
			
		||||
        line-height: 20px;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,10 @@
 | 
			
		|||
        white-space: normal !important;
 | 
			
		||||
        outline: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > li.pull-left > a,
 | 
			
		||||
    & > li.pull-left > a:focus {
 | 
			
		||||
        padding: 4px 12px 4px 32px;
 | 
			
		||||
    }
 | 
			
		||||
    & > .active > a,
 | 
			
		||||
    & > .active > a:hover,
 | 
			
		||||
    & > .active > a:focus {
 | 
			
		||||
| 
						 | 
				
			
			@ -145,8 +148,8 @@
 | 
			
		|||
    position: relative;
 | 
			
		||||
    & > .red-ui-menu-dropdown {
 | 
			
		||||
        top: 0;
 | 
			
		||||
        left: 100%;
 | 
			
		||||
        margin-top: -6px;
 | 
			
		||||
        left: calc(100% - 5px);
 | 
			
		||||
        margin-top: 0;
 | 
			
		||||
        margin-left: -1px;
 | 
			
		||||
    }
 | 
			
		||||
    &.open > .red-ui-menu-dropdown,
 | 
			
		||||
| 
						 | 
				
			
			@ -175,10 +178,10 @@
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.red-ui-menu-dropdown-submenu>a:after {
 | 
			
		||||
.red-ui-menu-dropdown-submenu.pull-left>a:after {
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
.red-ui-menu-dropdown-submenu>a:before {
 | 
			
		||||
.red-ui-menu-dropdown-submenu.pull-left>a:before {
 | 
			
		||||
    display: block;
 | 
			
		||||
    float: left;
 | 
			
		||||
    width: 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -192,7 +195,25 @@
 | 
			
		|||
    border-width: 5px 5px 5px 0;
 | 
			
		||||
    content: " ";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.red-ui-menu-dropdown-direction-right {
 | 
			
		||||
    .red-ui-menu-dropdown-submenu>a:after {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
    .red-ui-menu-dropdown-submenu>a:before {
 | 
			
		||||
        display: block;
 | 
			
		||||
        float: right;
 | 
			
		||||
        width: 0;
 | 
			
		||||
        height: 0;
 | 
			
		||||
        margin-top: 5px;
 | 
			
		||||
        margin-right: -15px;
 | 
			
		||||
        /* Caret Arrow */
 | 
			
		||||
        border-color: transparent;
 | 
			
		||||
        border-left-color: $menuCaret;
 | 
			
		||||
        border-style: solid;
 | 
			
		||||
        border-width: 5px 0 5px 5px;
 | 
			
		||||
        content: " ";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
.red-ui-menu-dropdown-submenu.disabled > a:before {
 | 
			
		||||
    border-right-color: $menuCaret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue