mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Add quick-add node mode with cmd/ctrl-click
This commit is contained in:
		@@ -132,6 +132,7 @@ module.exports = function(grunt) {
 | 
				
			|||||||
                    "editor/js/ui/library.js",
 | 
					                    "editor/js/ui/library.js",
 | 
				
			||||||
                    "editor/js/ui/notifications.js",
 | 
					                    "editor/js/ui/notifications.js",
 | 
				
			||||||
                    "editor/js/ui/search.js",
 | 
					                    "editor/js/ui/search.js",
 | 
				
			||||||
 | 
					                    "editor/js/ui/typeSearch.js",
 | 
				
			||||||
                    "editor/js/ui/subflow.js",
 | 
					                    "editor/js/ui/subflow.js",
 | 
				
			||||||
                    "editor/js/ui/touch/radialMenu.js"
 | 
					                    "editor/js/ui/touch/radialMenu.js"
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,6 +62,9 @@ RED.nodes = (function() {
 | 
				
			|||||||
            getNodeList: function() {
 | 
					            getNodeList: function() {
 | 
				
			||||||
                return nodeList;
 | 
					                return nodeList;
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            getNodeTypes: function() {
 | 
				
			||||||
 | 
					                return Object.keys(nodeDefinitions);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            setNodeList: function(list) {
 | 
					            setNodeList: function(list) {
 | 
				
			||||||
                nodeList = [];
 | 
					                nodeList = [];
 | 
				
			||||||
                for(var i=0;i<list.length;i++) {
 | 
					                for(var i=0;i<list.length;i++) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -422,6 +422,8 @@ RED.palette.editor = (function() {
 | 
				
			|||||||
        RED.events.on("editor:close",function() { disabled = false; });
 | 
					        RED.events.on("editor:close",function() { disabled = false; });
 | 
				
			||||||
        RED.events.on("search:open",function() { disabled = true; });
 | 
					        RED.events.on("search:open",function() { disabled = true; });
 | 
				
			||||||
        RED.events.on("search:close",function() { disabled = false; });
 | 
					        RED.events.on("search:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					        RED.events.on("type-search:open",function() { disabled = true; });
 | 
				
			||||||
 | 
					        RED.events.on("type-search:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        RED.keyboard.add("*", /* p */ 80,{shift:true,ctrl:true},function() {RED.palette.editor.show();d3.event.preventDefault();});
 | 
					        RED.keyboard.add("*", /* p */ 80,{shift:true,ctrl:true},function() {RED.palette.editor.show();d3.event.preventDefault();});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -279,6 +279,8 @@ RED.search = (function() {
 | 
				
			|||||||
        RED.events.on("editor:close",function() { disabled = false; });
 | 
					        RED.events.on("editor:close",function() { disabled = false; });
 | 
				
			||||||
        RED.events.on("palette-editor:open",function() { disabled = true; });
 | 
					        RED.events.on("palette-editor:open",function() { disabled = true; });
 | 
				
			||||||
        RED.events.on("palette-editor:close",function() { disabled = false; });
 | 
					        RED.events.on("palette-editor:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					        RED.events.on("type-search:open",function() { disabled = true; });
 | 
				
			||||||
 | 
					        RED.events.on("type-search:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										271
									
								
								editor/js/ui/typeSearch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								editor/js/ui/typeSearch.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,271 @@
 | 
				
			|||||||
 | 
					RED.typeSearch = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var shade;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var disabled = false;
 | 
				
			||||||
 | 
					    var dialog = null;
 | 
				
			||||||
 | 
					    var searchInput;
 | 
				
			||||||
 | 
					    var searchResults;
 | 
				
			||||||
 | 
					    var searchResultsDiv;
 | 
				
			||||||
 | 
					    var selected = -1;
 | 
				
			||||||
 | 
					    var visible = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var activeFilter = "";
 | 
				
			||||||
 | 
					    var addCallback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function search(val) {
 | 
				
			||||||
 | 
					        activeFilter = val.toLowerCase();
 | 
				
			||||||
 | 
					        var visible = searchResults.editableList('filter');
 | 
				
			||||||
 | 
					        setTimeout(function() {
 | 
				
			||||||
 | 
					            selected = 0;
 | 
				
			||||||
 | 
					            searchResults.children().removeClass('selected');
 | 
				
			||||||
 | 
					            searchResults.children(":visible:first").addClass('selected');
 | 
				
			||||||
 | 
					        },100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function ensureSelectedIsVisible() {
 | 
				
			||||||
 | 
					        var selectedEntry = searchResults.find("li.selected");
 | 
				
			||||||
 | 
					        if (selectedEntry.length === 1) {
 | 
				
			||||||
 | 
					            var scrollWindow = searchResults.parent();
 | 
				
			||||||
 | 
					            var scrollHeight = scrollWindow.height();
 | 
				
			||||||
 | 
					            var scrollOffset = scrollWindow.scrollTop();
 | 
				
			||||||
 | 
					            var y = selectedEntry.position().top;
 | 
				
			||||||
 | 
					            var h = selectedEntry.height();
 | 
				
			||||||
 | 
					            if (y+h > scrollHeight) {
 | 
				
			||||||
 | 
					                scrollWindow.animate({scrollTop: '-='+(scrollHeight-(y+h)-10)},50);
 | 
				
			||||||
 | 
					            } else if (y<0) {
 | 
				
			||||||
 | 
					                scrollWindow.animate({scrollTop: '+='+(y-10)},50);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function createDialog() {
 | 
				
			||||||
 | 
					        //shade = $('<div>',{class:"red-ui-type-search-shade"}).appendTo("#main-container");
 | 
				
			||||||
 | 
					        dialog = $("<div>",{id:"red-ui-type-search",class:"red-ui-search red-ui-type-search"}).appendTo("#main-container");
 | 
				
			||||||
 | 
					        var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
 | 
				
			||||||
 | 
					        searchInput = $('<input type="text" placeholder="add a node...">').appendTo(searchDiv).searchBox({
 | 
				
			||||||
 | 
					            delay: 50,
 | 
				
			||||||
 | 
					            change: function() {
 | 
				
			||||||
 | 
					                search($(this).val());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        searchInput.on('keydown',function(evt) {
 | 
				
			||||||
 | 
					            var children = searchResults.children(":visible");
 | 
				
			||||||
 | 
					            if (children.length > 0) {
 | 
				
			||||||
 | 
					                if (evt.keyCode === 40) {
 | 
				
			||||||
 | 
					                    // Down
 | 
				
			||||||
 | 
					                    if (selected < children.length-1) {
 | 
				
			||||||
 | 
					                        if (selected > -1) {
 | 
				
			||||||
 | 
					                            $(children[selected]).removeClass('selected');
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        selected++;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    $(children[selected]).addClass('selected');
 | 
				
			||||||
 | 
					                    ensureSelectedIsVisible();
 | 
				
			||||||
 | 
					                    evt.preventDefault();
 | 
				
			||||||
 | 
					                } else if (evt.keyCode === 38) {
 | 
				
			||||||
 | 
					                    // Up
 | 
				
			||||||
 | 
					                    if (selected > 0) {
 | 
				
			||||||
 | 
					                        if (selected < children.length) {
 | 
				
			||||||
 | 
					                            $(children[selected]).removeClass('selected');
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        selected--;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    $(children[selected]).addClass('selected');
 | 
				
			||||||
 | 
					                    ensureSelectedIsVisible();
 | 
				
			||||||
 | 
					                    evt.preventDefault();
 | 
				
			||||||
 | 
					                } else if (evt.keyCode === 13) {
 | 
				
			||||||
 | 
					                    // Enter
 | 
				
			||||||
 | 
					                    var index = Math.max(0,selected);
 | 
				
			||||||
 | 
					                    if (index < children.length) {
 | 
				
			||||||
 | 
					                        // TODO: dips into editableList impl details
 | 
				
			||||||
 | 
					                        confirm($(children[index]).find(".red-ui-editableList-item-content").data('data'));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog);
 | 
				
			||||||
 | 
					        searchResults = $('<ol>',{id:"search-result-list", style:"position: absolute;top: 0;bottom: 0;left: 0;right: 0;"}).appendTo(searchResultsDiv).editableList({
 | 
				
			||||||
 | 
					            addButton: false,
 | 
				
			||||||
 | 
					            filter: function(data) {
 | 
				
			||||||
 | 
					                if (activeFilter === "" ) {
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return (activeFilter==="")||(data.index.indexOf(activeFilter) > -1);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            addItem: function(container,i,object) {
 | 
				
			||||||
 | 
					                var def = object.def;
 | 
				
			||||||
 | 
					                object.index = object.type.toLowerCase();
 | 
				
			||||||
 | 
					                var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
 | 
				
			||||||
 | 
					                var colour = def.color;
 | 
				
			||||||
 | 
					                var icon_url = "arrow-in.png";
 | 
				
			||||||
 | 
					                if (def.category === 'config') {
 | 
				
			||||||
 | 
					                    icon_url = "cog.png";
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    try {
 | 
				
			||||||
 | 
					                        icon_url = (typeof def.icon === "function" ? def.icon.call({}) : def.icon);
 | 
				
			||||||
 | 
					                    } catch(err) {
 | 
				
			||||||
 | 
					                        console.log("Definition error: "+object.type+".icon",err);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                nodeDiv.css('backgroundColor',colour);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
 | 
				
			||||||
 | 
					                $('<div/>',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var label = object.type;
 | 
				
			||||||
 | 
					                if (typeof def.paletteLabel !== "undefined") {
 | 
				
			||||||
 | 
					                    try {
 | 
				
			||||||
 | 
					                        label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
 | 
				
			||||||
 | 
					                        label += " ("+object.type+")";
 | 
				
			||||||
 | 
					                        object.index += "|"+label.toLowerCase();
 | 
				
			||||||
 | 
					                    } catch(err) {
 | 
				
			||||||
 | 
					                        console.log("Definition error: "+object.type+".paletteLabel",err);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $('<div>',{class:"red-ui-search-result-node-label"}).html(label).appendTo(contentDiv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                div.click(function(evt) {
 | 
				
			||||||
 | 
					                    evt.preventDefault();
 | 
				
			||||||
 | 
					                    confirm(object);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            scrollOnAdd: false
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function confirm(def) {
 | 
				
			||||||
 | 
					        hide();
 | 
				
			||||||
 | 
					        addCallback(def.type);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function handleMouseActivity(evt) {
 | 
				
			||||||
 | 
					        if (visible) {
 | 
				
			||||||
 | 
					            var t = $(evt.target);
 | 
				
			||||||
 | 
					            while (t.prop('nodeName').toLowerCase() !== 'body') {
 | 
				
			||||||
 | 
					                if (t.attr('id') === 'red-ui-type-search') {
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                t = t.parent();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            hide(true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function show(opts) {
 | 
				
			||||||
 | 
					        if (!visible) {
 | 
				
			||||||
 | 
					            RED.keyboard.add("*",/* ESCAPE */ 27,function(){hide();d3.event.preventDefault();});
 | 
				
			||||||
 | 
					            if (dialog === null) {
 | 
				
			||||||
 | 
					                createDialog();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            visible = true;
 | 
				
			||||||
 | 
					            setTimeout(function() {
 | 
				
			||||||
 | 
					                $(document).on('mousedown.type-search',handleMouseActivity);
 | 
				
			||||||
 | 
					                $(document).on('mouseup.type-search',handleMouseActivity);
 | 
				
			||||||
 | 
					                $(document).on('click.type-search',handleMouseActivity);
 | 
				
			||||||
 | 
					            },200);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            dialog.hide();
 | 
				
			||||||
 | 
					            searchResultsDiv.hide();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        refreshTypeList();
 | 
				
			||||||
 | 
					        addCallback = opts.add;
 | 
				
			||||||
 | 
					        RED.events.emit("type-search:open");
 | 
				
			||||||
 | 
					        //shade.show();
 | 
				
			||||||
 | 
					        dialog.css({left:opts.x+"px",top:opts.y+"px"}).show();
 | 
				
			||||||
 | 
					        searchResultsDiv.slideDown();
 | 
				
			||||||
 | 
					        setTimeout(function() {
 | 
				
			||||||
 | 
					            searchInput.focus();
 | 
				
			||||||
 | 
					        },100);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function hide(fast) {
 | 
				
			||||||
 | 
					        if (visible) {
 | 
				
			||||||
 | 
					            RED.keyboard.remove(/* ESCAPE */ 27);
 | 
				
			||||||
 | 
					            visible = false;
 | 
				
			||||||
 | 
					            if (dialog !== null) {
 | 
				
			||||||
 | 
					                searchResultsDiv.slideUp(fast?50:200,function() {
 | 
				
			||||||
 | 
					                    dialog.hide();
 | 
				
			||||||
 | 
					                    searchInput.searchBox('value','');
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                //shade.hide();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            RED.events.emit("type-search:close");
 | 
				
			||||||
 | 
					            RED.view.focus();
 | 
				
			||||||
 | 
					            $(document).off('mousedown.type-search');
 | 
				
			||||||
 | 
					            $(document).off('mouseup.type-search');
 | 
				
			||||||
 | 
					            $(document).off('click.type-search');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function refreshTypeList() {
 | 
				
			||||||
 | 
					        searchResults.editableList('empty');
 | 
				
			||||||
 | 
					        searchInput.searchBox('value','');
 | 
				
			||||||
 | 
					        selected = -1;
 | 
				
			||||||
 | 
					        searchResults.parent().scrollTop(0);
 | 
				
			||||||
 | 
					        var common = {
 | 
				
			||||||
 | 
					            "debug"   : false,
 | 
				
			||||||
 | 
					            "inject"  : false,
 | 
				
			||||||
 | 
					            "function": false
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        var nodeTypes = RED.nodes.registry.getNodeTypes().filter(function(n) {
 | 
				
			||||||
 | 
					            if (common.hasOwnProperty(n)) {
 | 
				
			||||||
 | 
					                common[n] = true;
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        // Just in case a core node has been disabled
 | 
				
			||||||
 | 
					        if (common["function"]) {
 | 
				
			||||||
 | 
					            nodeTypes.unshift("function");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (common["inject"]) {
 | 
				
			||||||
 | 
					            nodeTypes.unshift("inject");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (common["debug"]) {
 | 
				
			||||||
 | 
					            nodeTypes.unshift("debug");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var i;
 | 
				
			||||||
 | 
					        for (i=0;i<nodeTypes.length;i++) {
 | 
				
			||||||
 | 
					            var t = nodeTypes[i];
 | 
				
			||||||
 | 
					            var def = RED.nodes.getType(t);
 | 
				
			||||||
 | 
					            if (def.category !== 'config' && t !== 'unknown') {
 | 
				
			||||||
 | 
					                searchResults.editableList('addItem',{type:t,def: def})
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        setTimeout(function() {
 | 
				
			||||||
 | 
					            selected = 0;
 | 
				
			||||||
 | 
					            searchResults.children(":first").addClass('selected');
 | 
				
			||||||
 | 
					        },100);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function init() {
 | 
				
			||||||
 | 
					        // RED.keyboard.add("*",/* . */ 190,{ctrl:true},function(){if (!disabled) { show(); } d3.event.preventDefault();});
 | 
				
			||||||
 | 
					        // RED.events.on("editor:open",function() { disabled = true; });
 | 
				
			||||||
 | 
					        // RED.events.on("editor:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					        // RED.events.on("palette-editor:open",function() { disabled = true; });
 | 
				
			||||||
 | 
					        // RED.events.on("palette-editor:close",function() { disabled = false; });
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // $("#header-shade").on('mousedown',hide);
 | 
				
			||||||
 | 
					        // $("#editor-shade").on('mousedown',hide);
 | 
				
			||||||
 | 
					        // $("#palette-shade").on('mousedown',hide);
 | 
				
			||||||
 | 
					        // $("#sidebar-shade").on('mousedown',hide);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        init: init,
 | 
				
			||||||
 | 
					        show: show,
 | 
				
			||||||
 | 
					        hide: hide
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
@@ -323,70 +323,12 @@ RED.view = (function() {
 | 
				
			|||||||
            drop: function( event, ui ) {
 | 
					            drop: function( event, ui ) {
 | 
				
			||||||
                d3.event = event;
 | 
					                d3.event = event;
 | 
				
			||||||
                var selected_tool = ui.draggable[0].type;
 | 
					                var selected_tool = ui.draggable[0].type;
 | 
				
			||||||
                var m = /^subflow:(.+)$/.exec(selected_tool);
 | 
					                var result = addNode(selected_tool);
 | 
				
			||||||
 | 
					                if (!result) {
 | 
				
			||||||
                if (activeSubflow && m) {
 | 
					 | 
				
			||||||
                    var subflowId = m[1];
 | 
					 | 
				
			||||||
                    if (subflowId === activeSubflow.id) {
 | 
					 | 
				
			||||||
                        RED.notify(RED._("notification.error",{message: RED._("notification.errors.cannotAddSubflowToItself")}),"error");
 | 
					 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                    if (RED.nodes.subflowContains(m[1],activeSubflow.id)) {
 | 
					                var historyEvent = result.historyEvent;
 | 
				
			||||||
                        RED.notify(RED._("notification.error",{message: RED._("notification.errors.cannotAddCircularReference")}),"error");
 | 
					                var nn = result.node;
 | 
				
			||||||
                        return;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var nn = { id:RED.nodes.id(),z:RED.workspaces.active()};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                nn.type = selected_tool;
 | 
					 | 
				
			||||||
                nn._def = RED.nodes.getType(nn.type);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (!m) {
 | 
					 | 
				
			||||||
                    nn.inputs = nn._def.inputs || 0;
 | 
					 | 
				
			||||||
                    nn.outputs = nn._def.outputs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (var d in nn._def.defaults) {
 | 
					 | 
				
			||||||
                        if (nn._def.defaults.hasOwnProperty(d)) {
 | 
					 | 
				
			||||||
                            if (nn._def.defaults[d].value !== undefined) {
 | 
					 | 
				
			||||||
                                nn[d] = JSON.parse(JSON.stringify(nn._def.defaults[d].value));
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (nn._def.onadd) {
 | 
					 | 
				
			||||||
                        try {
 | 
					 | 
				
			||||||
                            nn._def.onadd.call(nn);
 | 
					 | 
				
			||||||
                        } catch(err) {
 | 
					 | 
				
			||||||
                            console.log("onadd:",err);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    var subflow = RED.nodes.subflow(m[1]);
 | 
					 | 
				
			||||||
                    nn.inputs = subflow.in.length;
 | 
					 | 
				
			||||||
                    nn.outputs = subflow.out.length;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                nn.changed = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                nn.w = node_width;
 | 
					 | 
				
			||||||
                nn.h = Math.max(node_height,(nn.outputs||0) * 15);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var historyEvent = {
 | 
					 | 
				
			||||||
                    t:"add",
 | 
					 | 
				
			||||||
                    nodes:[nn.id],
 | 
					 | 
				
			||||||
                    dirty:RED.nodes.dirty()
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (activeSubflow) {
 | 
					 | 
				
			||||||
                    var subflowRefresh = RED.subflow.refresh(true);
 | 
					 | 
				
			||||||
                    if (subflowRefresh) {
 | 
					 | 
				
			||||||
                        historyEvent.subflow = {
 | 
					 | 
				
			||||||
                            id:activeSubflow.id,
 | 
					 | 
				
			||||||
                            changed: activeSubflow.changed,
 | 
					 | 
				
			||||||
                            instances: subflowRefresh.instances
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0));
 | 
					                var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0));
 | 
				
			||||||
                var mousePos = d3.touches(this)[0]||d3.mouse(this);
 | 
					                var mousePos = d3.touches(this)[0]||d3.mouse(this);
 | 
				
			||||||
@@ -463,6 +405,79 @@ RED.view = (function() {
 | 
				
			|||||||
        RED.keyboard.add("workspace",/* right */ 39, {shift:true}, function() { moveSelection(20,0); d3.event.preventDefault();},endKeyboardMove);
 | 
					        RED.keyboard.add("workspace",/* right */ 39, {shift:true}, function() { moveSelection(20,0); d3.event.preventDefault();},endKeyboardMove);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function addNode(type,x,y) {
 | 
				
			||||||
 | 
					        var m = /^subflow:(.+)$/.exec(type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (activeSubflow && m) {
 | 
				
			||||||
 | 
					            var subflowId = m[1];
 | 
				
			||||||
 | 
					            if (subflowId === activeSubflow.id) {
 | 
				
			||||||
 | 
					                RED.notify(RED._("notification.error",{message: RED._("notification.errors.cannotAddSubflowToItself")}),"error");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (RED.nodes.subflowContains(m[1],activeSubflow.id)) {
 | 
				
			||||||
 | 
					                RED.notify(RED._("notification.error",{message: RED._("notification.errors.cannotAddCircularReference")}),"error");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var nn = { id:RED.nodes.id(),z:RED.workspaces.active()};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nn.type = type;
 | 
				
			||||||
 | 
					        nn._def = RED.nodes.getType(nn.type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!m) {
 | 
				
			||||||
 | 
					            nn.inputs = nn._def.inputs || 0;
 | 
				
			||||||
 | 
					            nn.outputs = nn._def.outputs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (var d in nn._def.defaults) {
 | 
				
			||||||
 | 
					                if (nn._def.defaults.hasOwnProperty(d)) {
 | 
				
			||||||
 | 
					                    if (nn._def.defaults[d].value !== undefined) {
 | 
				
			||||||
 | 
					                        nn[d] = JSON.parse(JSON.stringify(nn._def.defaults[d].value));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (nn._def.onadd) {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    nn._def.onadd.call(nn);
 | 
				
			||||||
 | 
					                } catch(err) {
 | 
				
			||||||
 | 
					                    console.log("onadd:",err);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            var subflow = RED.nodes.subflow(m[1]);
 | 
				
			||||||
 | 
					            nn.inputs = subflow.in.length;
 | 
				
			||||||
 | 
					            nn.outputs = subflow.out.length;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nn.changed = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nn.w = node_width;
 | 
				
			||||||
 | 
					        nn.h = Math.max(node_height,(nn.outputs||0) * 15);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var historyEvent = {
 | 
				
			||||||
 | 
					            t:"add",
 | 
				
			||||||
 | 
					            nodes:[nn.id],
 | 
				
			||||||
 | 
					            dirty:RED.nodes.dirty()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (activeSubflow) {
 | 
				
			||||||
 | 
					            var subflowRefresh = RED.subflow.refresh(true);
 | 
				
			||||||
 | 
					            if (subflowRefresh) {
 | 
				
			||||||
 | 
					                historyEvent.subflow = {
 | 
				
			||||||
 | 
					                    id:activeSubflow.id,
 | 
				
			||||||
 | 
					                    changed: activeSubflow.changed,
 | 
				
			||||||
 | 
					                    instances: subflowRefresh.instances
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            node: nn,
 | 
				
			||||||
 | 
					            historyEvent: historyEvent
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function canvasMouseDown() {
 | 
					    function canvasMouseDown() {
 | 
				
			||||||
        if (!mousedown_node && !mousedown_link) {
 | 
					        if (!mousedown_node && !mousedown_link) {
 | 
				
			||||||
            selected_link = null;
 | 
					            selected_link = null;
 | 
				
			||||||
@@ -473,9 +488,46 @@ RED.view = (function() {
 | 
				
			|||||||
                lasso.remove();
 | 
					                lasso.remove();
 | 
				
			||||||
                lasso = null;
 | 
					                lasso = null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            var point;
 | 
				
			||||||
 | 
					            if (d3.event.metaKey || d3.event.ctrlKey) {
 | 
				
			||||||
 | 
					                point = d3.mouse(this);
 | 
				
			||||||
 | 
					                d3.event.stopPropagation();
 | 
				
			||||||
 | 
					                var mainPos = $("#main-container").position();
 | 
				
			||||||
 | 
					                RED.typeSearch.show({
 | 
				
			||||||
 | 
					                    x:d3.event.clientX-mainPos.left-node_width/2,
 | 
				
			||||||
 | 
					                    y:d3.event.clientY-mainPos.top-node_height/2,
 | 
				
			||||||
 | 
					                    add: function(type) {
 | 
				
			||||||
 | 
					                        var result = addNode(type);
 | 
				
			||||||
 | 
					                        if (!result) {
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        var nn = result.node;
 | 
				
			||||||
 | 
					                        var historyEvent = result.historyEvent;
 | 
				
			||||||
 | 
					                        nn.x = point[0];
 | 
				
			||||||
 | 
					                        nn.y = point[1];
 | 
				
			||||||
 | 
					                        RED.history.push(historyEvent);
 | 
				
			||||||
 | 
					                        RED.nodes.add(nn);
 | 
				
			||||||
 | 
					                        RED.editor.validateNode(nn);
 | 
				
			||||||
 | 
					                        RED.nodes.dirty(true);
 | 
				
			||||||
 | 
					                        // auto select dropped node - so info shows (if visible)
 | 
				
			||||||
 | 
					                        clearSelection();
 | 
				
			||||||
 | 
					                        nn.selected = true;
 | 
				
			||||||
 | 
					                        moving_set.push({n:nn});
 | 
				
			||||||
 | 
					                        updateActiveNodes();
 | 
				
			||||||
 | 
					                        updateSelection();
 | 
				
			||||||
 | 
					                        redraw();
 | 
				
			||||||
 | 
					                        if (nn._def.autoedit) {
 | 
				
			||||||
 | 
					                            RED.editor.edit(nn);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                updateActiveNodes();
 | 
				
			||||||
 | 
					                updateSelection();
 | 
				
			||||||
 | 
					                redraw();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
                if (!touchStartTime) {
 | 
					                if (!touchStartTime) {
 | 
				
			||||||
                var point = d3.mouse(this);
 | 
					                    point = d3.mouse(this);
 | 
				
			||||||
                    lasso = vis.append("rect")
 | 
					                    lasso = vis.append("rect")
 | 
				
			||||||
                        .attr("ox",point[0])
 | 
					                        .attr("ox",point[0])
 | 
				
			||||||
                        .attr("oy",point[1])
 | 
					                        .attr("oy",point[1])
 | 
				
			||||||
@@ -490,6 +542,7 @@ RED.view = (function() {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function canvasMouseMove() {
 | 
					    function canvasMouseMove() {
 | 
				
			||||||
        var i;
 | 
					        var i;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -168,12 +168,7 @@
 | 
				
			|||||||
    color: $workspace-button-color;
 | 
					    color: $workspace-button-color;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#palette-shade, #editor-shade, #header-shade, #sidebar-shade  {
 | 
					#palette-shade, #editor-shade, #header-shade, #sidebar-shade  {
 | 
				
			||||||
    position: absolute;
 | 
					    @include shade;
 | 
				
			||||||
    top:0;
 | 
					 | 
				
			||||||
    bottom:0;
 | 
					 | 
				
			||||||
    left:0;
 | 
					 | 
				
			||||||
    right:0;
 | 
					 | 
				
			||||||
    background: $shade-color;
 | 
					 | 
				
			||||||
    z-index: 2;
 | 
					    z-index: 2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#sidebar-shade  {
 | 
					#sidebar-shade  {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -170,6 +170,11 @@
 | 
				
			|||||||
    stroke-dasharray:8, 3;
 | 
					    stroke-dasharray:8, 3;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.node_quickadd * {
 | 
				
			||||||
 | 
					    stroke-dasharray: 12,3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.node_status_label {
 | 
					.node_status_label {
 | 
				
			||||||
    @include disable-selection;
 | 
					    @include disable-selection;
 | 
				
			||||||
    stroke-width: 0;
 | 
					    stroke-width: 0;
 | 
				
			||||||
@@ -183,6 +188,13 @@
 | 
				
			|||||||
    stroke: $port-selected-color;
 | 
					    stroke: $port-selected-color;
 | 
				
			||||||
    fill:  $port-selected-color;
 | 
					    fill:  $port-selected-color;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.port_quick_link {
 | 
				
			||||||
 | 
					    stroke: $port-selected-color;
 | 
				
			||||||
 | 
					    fill:  $port-selected-color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.subflowport {
 | 
					.subflowport {
 | 
				
			||||||
    stroke-dasharray: 5,5;
 | 
					    stroke-dasharray: 5,5;
 | 
				
			||||||
    fill: #eee;
 | 
					    fill: #eee;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -156,3 +156,12 @@
 | 
				
			|||||||
    box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
 | 
					    box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@mixin shade {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    background: $shade-color;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,12 +82,7 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    .palette-module-shade {
 | 
					    .palette-module-shade {
 | 
				
			||||||
        position: absolute;
 | 
					        @include shade;
 | 
				
			||||||
        top: 0;
 | 
					 | 
				
			||||||
        bottom:0;
 | 
					 | 
				
			||||||
        left:0;
 | 
					 | 
				
			||||||
        right:0;
 | 
					 | 
				
			||||||
        background: $shade-color;
 | 
					 | 
				
			||||||
        text-align: center;
 | 
					        text-align: center;
 | 
				
			||||||
        padding-top: 20px;
 | 
					        padding-top: 20px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,59 @@
 | 
				
			|||||||
    ol {
 | 
					    ol {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.red-ui-type-search-shade {
 | 
				
			||||||
 | 
					    @include shade;
 | 
				
			||||||
 | 
					    z-index: 20;
 | 
				
			||||||
 | 
					    position: fixed;
 | 
				
			||||||
 | 
					    background: rgba(255,255,255,0.05);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.red-ui-type-search {
 | 
				
			||||||
 | 
					    box-shadow: 0 1px 6px -3px black;
 | 
				
			||||||
 | 
					    background: none;
 | 
				
			||||||
 | 
					    width: 300px;
 | 
				
			||||||
 | 
					    margin-left: 0px;
 | 
				
			||||||
 | 
					    //height: 75px;
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					    .red-ui-search-container {
 | 
				
			||||||
 | 
					        border-top-left-radius: 5px;
 | 
				
			||||||
 | 
					        border-top-right-radius: 5px;
 | 
				
			||||||
 | 
					        border: 1px dashed #aaa;
 | 
				
			||||||
 | 
					        border-bottom: none;
 | 
				
			||||||
 | 
					        padding: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .red-ui-search-results-container {
 | 
				
			||||||
 | 
					        display: none;
 | 
				
			||||||
 | 
					        height: 150px;
 | 
				
			||||||
 | 
					        // position: absolute;
 | 
				
			||||||
 | 
					        // top: 0;
 | 
				
			||||||
 | 
					        // left:0;
 | 
				
			||||||
 | 
					        // right: 0;
 | 
				
			||||||
 | 
					        // bottom: 0;
 | 
				
			||||||
 | 
					        // padding: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .red-ui-search-result {
 | 
				
			||||||
 | 
					        padding:  2px 2px 2px 5px;
 | 
				
			||||||
 | 
					        font-size: 12px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .red-ui-search-result-node {
 | 
				
			||||||
 | 
					        width: 18px;
 | 
				
			||||||
 | 
					        height: 15px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .palette_icon_container {
 | 
				
			||||||
 | 
					        width: 18px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .palette_icon {
 | 
				
			||||||
 | 
					        width: 15px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .red-ui-search-result-description {
 | 
				
			||||||
 | 
					        margin-left:28px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .red-ui-search-result-node-label {
 | 
				
			||||||
 | 
					        color: #999;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.red-ui-search-container {
 | 
					.red-ui-search-container {
 | 
				
			||||||
    padding: 3px;
 | 
					    padding: 3px;
 | 
				
			||||||
    border-bottom: 1px solid $secondary-border-color;
 | 
					    border-bottom: 1px solid $secondary-border-color;
 | 
				
			||||||
@@ -64,6 +117,11 @@
 | 
				
			|||||||
        border-color: $primary-border-color;
 | 
					        border-color: $primary-border-color;
 | 
				
			||||||
        color: $form-text-color;
 | 
					        color: $form-text-color;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    &:after {
 | 
				
			||||||
 | 
					        content: "";
 | 
				
			||||||
 | 
					        display: table;
 | 
				
			||||||
 | 
					        clear: both;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.red-ui-search-result-node {
 | 
					.red-ui-search-result-node {
 | 
				
			||||||
@@ -78,6 +136,11 @@
 | 
				
			|||||||
    background-repeat: no-repeat;
 | 
					    background-repeat: no-repeat;
 | 
				
			||||||
    background-size: contain;
 | 
					    background-size: contain;
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .palette_icon_container {
 | 
				
			||||||
 | 
					        border-right: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.red-ui-search-result-description {
 | 
					.red-ui-search-result-description {
 | 
				
			||||||
    margin-left: 40px;
 | 
					    margin-left: 40px;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,10 +101,5 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.sidebar-shade {
 | 
					.sidebar-shade {
 | 
				
			||||||
    position: absolute;
 | 
					    @include shade;
 | 
				
			||||||
    top:0;
 | 
					 | 
				
			||||||
    bottom:0;
 | 
					 | 
				
			||||||
    left:0;
 | 
					 | 
				
			||||||
    right:0;
 | 
					 | 
				
			||||||
    background: $shade-color;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user