mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge branch 'master' into master
This commit is contained in:
		@@ -334,6 +334,30 @@ RED.clipboard = (function() {
 | 
				
			|||||||
        },100);
 | 
					        },100);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Validates if the provided string looks like valid flow json
 | 
				
			||||||
 | 
					     * @param {string} flowString the string to validate
 | 
				
			||||||
 | 
					     * @returns If valid, returns the node array
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    function validateFlowString(flowString) {
 | 
				
			||||||
 | 
					        const res = JSON.parse(flowString)
 | 
				
			||||||
 | 
					        if (!Array.isArray(res)) {
 | 
				
			||||||
 | 
					            throw new Error(RED._("clipboard.import.errors.notArray"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (let i = 0; i < res.length; i++) {
 | 
				
			||||||
 | 
					            if (typeof res[i] !== "object") {
 | 
				
			||||||
 | 
					                throw new Error(RED._("clipboard.import.errors.itemNotObject",{index:i}));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!Object.hasOwn(res[i], 'id')) {
 | 
				
			||||||
 | 
					                throw new Error(RED._("clipboard.import.errors.missingId",{index:i}));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!Object.hasOwn(res[i], 'type')) {
 | 
				
			||||||
 | 
					                throw new Error(RED._("clipboard.import.errors.missingType",{index:i}));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var validateImportTimeout;
 | 
					    var validateImportTimeout;
 | 
				
			||||||
    function validateImport() {
 | 
					    function validateImport() {
 | 
				
			||||||
        if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") {
 | 
					        if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") {
 | 
				
			||||||
@@ -351,21 +375,7 @@ RED.clipboard = (function() {
 | 
				
			|||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    if (!/^\[[\s\S]*\]$/m.test(v)) {
 | 
					                    validateFlowString(v)
 | 
				
			||||||
                        throw new Error(RED._("clipboard.import.errors.notArray"));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    var res = JSON.parse(v);
 | 
					 | 
				
			||||||
                    for (var i=0;i<res.length;i++) {
 | 
					 | 
				
			||||||
                        if (typeof res[i] !== "object") {
 | 
					 | 
				
			||||||
                            throw new Error(RED._("clipboard.import.errors.itemNotObject",{index:i}));
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (!res[i].hasOwnProperty('id')) {
 | 
					 | 
				
			||||||
                            throw new Error(RED._("clipboard.import.errors.missingId",{index:i}));
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (!res[i].hasOwnProperty('type')) {
 | 
					 | 
				
			||||||
                            throw new Error(RED._("clipboard.import.errors.missingType",{index:i}));
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    currentPopoverError = null;
 | 
					                    currentPopoverError = null;
 | 
				
			||||||
                    popover.close(true);
 | 
					                    popover.close(true);
 | 
				
			||||||
                    importInput.removeClass("input-error");
 | 
					                    importInput.removeClass("input-error");
 | 
				
			||||||
@@ -998,16 +1008,16 @@ RED.clipboard = (function() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function importNodes(nodesStr,addFlow) {
 | 
					    function importNodes(nodesStr,addFlow) {
 | 
				
			||||||
        var newNodes = nodesStr;
 | 
					        let newNodes = nodesStr;
 | 
				
			||||||
        if (typeof nodesStr === 'string') {
 | 
					        if (typeof nodesStr === 'string') {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                nodesStr = nodesStr.trim();
 | 
					                nodesStr = nodesStr.trim();
 | 
				
			||||||
                if (nodesStr.length === 0) {
 | 
					                if (nodesStr.length === 0) {
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                newNodes = JSON.parse(nodesStr);
 | 
					                newNodes = validateFlowString(nodesStr)
 | 
				
			||||||
            } catch(err) {
 | 
					            } catch(err) {
 | 
				
			||||||
                var e = new Error(RED._("clipboard.invalidFlow",{message:err.message}));
 | 
					                const e = new Error(RED._("clipboard.invalidFlow",{message:err.message}));
 | 
				
			||||||
                e.code = "NODE_RED";
 | 
					                e.code = "NODE_RED";
 | 
				
			||||||
                throw e;
 | 
					                throw e;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -1342,6 +1352,7 @@ RED.clipboard = (function() {
 | 
				
			|||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    } catch(err) {
 | 
					                    } catch(err) {
 | 
				
			||||||
 | 
					                        console.warn('Import failed: ', err)
 | 
				
			||||||
                        // Ensure any errors throw above doesn't stop the drop target from
 | 
					                        // Ensure any errors throw above doesn't stop the drop target from
 | 
				
			||||||
                        // being hidden.
 | 
					                        // being hidden.
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,15 +54,15 @@ RED.contextMenu = (function () {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const scale = RED.view.scale()
 | 
				
			||||||
            const offset = $("#red-ui-workspace-chart").offset()
 | 
					            const offset = $("#red-ui-workspace-chart").offset()
 | 
				
			||||||
 | 
					            let addX = (options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft()) / scale
 | 
				
			||||||
            let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft()
 | 
					            let addY = (options.y - offset.top + $("#red-ui-workspace-chart").scrollTop()) / scale
 | 
				
			||||||
            let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (RED.view.snapGrid) {
 | 
					            if (RED.view.snapGrid) {
 | 
				
			||||||
                const gridSize = RED.view.gridSize()
 | 
					                const gridSize = RED.view.gridSize()
 | 
				
			||||||
                addX = gridSize * Math.floor(addX / gridSize)
 | 
					                addX = gridSize * Math.round(addX / gridSize)
 | 
				
			||||||
                addY = gridSize * Math.floor(addY / gridSize)
 | 
					                addY = gridSize * Math.round(addY / gridSize)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (RED.settings.theme("menu.menu-item-action-list", true)) {
 | 
					            if (RED.settings.theme("menu.menu-item-action-list", true)) {
 | 
				
			||||||
@@ -87,7 +87,9 @@ RED.contextMenu = (function () {
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
                (hasLinks) ? { // has least 1 wire selected
 | 
					                (hasLinks) ? { // has least 1 wire selected
 | 
				
			||||||
                    label: RED._("contextMenu.junction"),
 | 
					                    label: RED._("contextMenu.junction"),
 | 
				
			||||||
                    onselect: 'core:split-wires-with-junctions',
 | 
					                    onselect: function () {
 | 
				
			||||||
 | 
					                        RED.actions.invoke('core:split-wires-with-junctions', { x: addX, y: addY })
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
                    disabled: !canEdit || !hasLinks
 | 
					                    disabled: !canEdit || !hasLinks
 | 
				
			||||||
                } : {
 | 
					                } : {
 | 
				
			||||||
                    label: RED._("contextMenu.junction"),
 | 
					                    label: RED._("contextMenu.junction"),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ RED.view.annotations = (function() {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                let badgeRDX = 0;
 | 
					                let badgeRDX = 0;
 | 
				
			||||||
                let badgeLDX = 0;
 | 
					                let badgeLDX = 0;
 | 
				
			||||||
                
 | 
					                const scale = RED.view.scale()
 | 
				
			||||||
                for (let i=0,l=evt.el.__annotations__.length;i<l;i++) {
 | 
					                for (let i=0,l=evt.el.__annotations__.length;i<l;i++) {
 | 
				
			||||||
                    const annotation = evt.el.__annotations__[i];
 | 
					                    const annotation = evt.el.__annotations__[i];
 | 
				
			||||||
                    if (annotations.hasOwnProperty(annotation.id)) {
 | 
					                    if (annotations.hasOwnProperty(annotation.id)) {
 | 
				
			||||||
@@ -42,15 +42,17 @@ RED.view.annotations = (function() {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (isBadge) {
 | 
					                        if (isBadge) {
 | 
				
			||||||
                            if (showAnnotation) {
 | 
					                            if (showAnnotation) {
 | 
				
			||||||
                                const rect = annotation.element.getBoundingClientRect();
 | 
					                                // getBoundingClientRect is in real-world scale so needs to be adjusted according to
 | 
				
			||||||
 | 
					                                // the current scale factor
 | 
				
			||||||
 | 
					                                const rectWidth = annotation.element.getBoundingClientRect().width / scale;
 | 
				
			||||||
                                let annotationX
 | 
					                                let annotationX
 | 
				
			||||||
                                if (!opts.align || opts.align === 'right') {
 | 
					                                if (!opts.align || opts.align === 'right') {
 | 
				
			||||||
                                    annotationX = evt.node.w - 3 - badgeRDX - rect.width
 | 
					                                    annotationX = evt.node.w - 3 - badgeRDX - rectWidth
 | 
				
			||||||
                                    badgeRDX += rect.width + 4;
 | 
					                                    badgeRDX += rectWidth + 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                } else if (opts.align === 'left') {
 | 
					                                } else if (opts.align === 'left') {
 | 
				
			||||||
                                    annotationX = 3 + badgeLDX
 | 
					                                    annotationX = 3 + badgeLDX
 | 
				
			||||||
                                    badgeLDX += rect.width + 4;
 | 
					                                    badgeLDX += rectWidth + 4;
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                annotation.element.setAttribute("transform", "translate("+annotationX+", -8)");
 | 
					                                annotation.element.setAttribute("transform", "translate("+annotationX+", -8)");
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1154,11 +1154,11 @@ RED.view.tools = (function() {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function addJunctionsToWires(wires) {
 | 
					    function addJunctionsToWires(options = {}) {
 | 
				
			||||||
        if (RED.workspaces.isLocked()) {
 | 
					        if (RED.workspaces.isLocked()) {
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
 | 
					        let wiresToSplit = options.wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
 | 
				
			||||||
        if (!wiresToSplit) {
 | 
					        if (!wiresToSplit) {
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1206,21 +1206,26 @@ RED.view.tools = (function() {
 | 
				
			|||||||
            if (links.length === 0) {
 | 
					            if (links.length === 0) {
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            let pointCount = 0
 | 
					            if (addedJunctions.length === 0 && Object.hasOwn(options, 'x') && Object.hasOwn(options, 'y')) {
 | 
				
			||||||
            links.forEach(function(l) {
 | 
					                junction.x = options.x
 | 
				
			||||||
                if (l._sliceLocation) {
 | 
					                junction.y = options.y
 | 
				
			||||||
                    junction.x += l._sliceLocation.x
 | 
					            } else {
 | 
				
			||||||
                    junction.y += l._sliceLocation.y
 | 
					                let pointCount = 0
 | 
				
			||||||
                    delete l._sliceLocation
 | 
					                links.forEach(function(l) {
 | 
				
			||||||
                    pointCount++
 | 
					                    if (l._sliceLocation) {
 | 
				
			||||||
                } else {
 | 
					                        junction.x += l._sliceLocation.x
 | 
				
			||||||
                    junction.x += l.source.x + l.source.w/2 + l.target.x - l.target.w/2
 | 
					                        junction.y += l._sliceLocation.y
 | 
				
			||||||
                    junction.y += l.source.y + l.target.y
 | 
					                        delete l._sliceLocation
 | 
				
			||||||
                    pointCount += 2
 | 
					                        pointCount++
 | 
				
			||||||
                }
 | 
					                    } else {
 | 
				
			||||||
            })
 | 
					                        junction.x += l.source.x + l.source.w/2 + l.target.x - l.target.w/2
 | 
				
			||||||
            junction.x = Math.round(junction.x/pointCount)
 | 
					                        junction.y += l.source.y + l.target.y
 | 
				
			||||||
            junction.y = Math.round(junction.y/pointCount)
 | 
					                        pointCount += 2
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                junction.x = Math.round(junction.x/pointCount)
 | 
				
			||||||
 | 
					                junction.y = Math.round(junction.y/pointCount)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            if (RED.view.snapGrid) {
 | 
					            if (RED.view.snapGrid) {
 | 
				
			||||||
                let gridSize = RED.view.gridSize()
 | 
					                let gridSize = RED.view.gridSize()
 | 
				
			||||||
                junction.x = (gridSize*Math.round(junction.x/gridSize));
 | 
					                junction.x = (gridSize*Math.round(junction.x/gridSize));
 | 
				
			||||||
@@ -1410,7 +1415,7 @@ RED.view.tools = (function() {
 | 
				
			|||||||
            RED.actions.add("core:wire-multiple-to-node", function() { wireMultipleToNode() })
 | 
					            RED.actions.add("core:wire-multiple-to-node", function() { wireMultipleToNode() })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
 | 
					            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:split-wires-with-junctions", function (options) { addJunctionsToWires(options) });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            RED.actions.add("core:generate-node-names", generateNodeNames )
 | 
					            RED.actions.add("core:generate-node-names", generateNodeNames )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -321,8 +321,8 @@ RED.view = (function() {
 | 
				
			|||||||
            evt.stopPropagation()
 | 
					            evt.stopPropagation()
 | 
				
			||||||
            RED.contextMenu.show({
 | 
					            RED.contextMenu.show({
 | 
				
			||||||
                type: 'workspace',
 | 
					                type: 'workspace',
 | 
				
			||||||
                x:evt.clientX-5,
 | 
					                x: evt.clientX,
 | 
				
			||||||
                y:evt.clientY-5
 | 
					                y: evt.clientY
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            return false
 | 
					            return false
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
@@ -5174,8 +5174,8 @@ RED.view = (function() {
 | 
				
			|||||||
                                var delta = Infinity;
 | 
					                                var delta = Infinity;
 | 
				
			||||||
                                for (var i = 0; i < lineLength; i++) {
 | 
					                                for (var i = 0; i < lineLength; i++) {
 | 
				
			||||||
                                    var linePos = pathLine.getPointAtLength(i);
 | 
					                                    var linePos = pathLine.getPointAtLength(i);
 | 
				
			||||||
                                    var posDeltaX = Math.abs(linePos.x-d3.event.offsetX)
 | 
					                                    var posDeltaX = Math.abs(linePos.x-(d3.event.offsetX / scaleFactor))
 | 
				
			||||||
                                    var posDeltaY = Math.abs(linePos.y-d3.event.offsetY)
 | 
					                                    var posDeltaY = Math.abs(linePos.y-(d3.event.offsetY / scaleFactor))
 | 
				
			||||||
                                    var posDelta = posDeltaX*posDeltaX + posDeltaY*posDeltaY
 | 
					                                    var posDelta = posDeltaX*posDeltaX + posDeltaY*posDeltaY
 | 
				
			||||||
                                    if (posDelta < delta) {
 | 
					                                    if (posDelta < delta) {
 | 
				
			||||||
                                        pos = linePos
 | 
					                                        pos = linePos
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -339,7 +339,7 @@ module.exports = function(RED) {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
                msg.filename = filename;
 | 
					                msg.filename = filename;
 | 
				
			||||||
                var lines = Buffer.from([]);
 | 
					                const bufferArray = [];
 | 
				
			||||||
                var spare = "";
 | 
					                var spare = "";
 | 
				
			||||||
                var count = 0;
 | 
					                var count = 0;
 | 
				
			||||||
                var type = "buffer";
 | 
					                var type = "buffer";
 | 
				
			||||||
@@ -397,7 +397,7 @@ module.exports = function(RED) {
 | 
				
			|||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else {
 | 
					                            else {
 | 
				
			||||||
                                lines = Buffer.concat([lines,chunk]);
 | 
					                                bufferArray.push(chunk);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
@@ -413,10 +413,11 @@ module.exports = function(RED) {
 | 
				
			|||||||
                    })
 | 
					                    })
 | 
				
			||||||
                    .on('end', function() {
 | 
					                    .on('end', function() {
 | 
				
			||||||
                        if (node.chunk === false) {
 | 
					                        if (node.chunk === false) {
 | 
				
			||||||
 | 
					                            const buffer = Buffer.concat(bufferArray);
 | 
				
			||||||
                            if (node.format === "utf8") {
 | 
					                            if (node.format === "utf8") {
 | 
				
			||||||
                                msg.payload = decode(lines, node.encoding);
 | 
					                                msg.payload = decode(buffer, node.encoding);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else { msg.payload = lines; }
 | 
					                            else { msg.payload = buffer; }
 | 
				
			||||||
                            nodeSend(msg);
 | 
					                            nodeSend(msg);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else if (node.format === "lines") {
 | 
					                        else if (node.format === "lines") {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user