mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge pull request #3678 from node-red/right-click-menu
Right click menu
This commit is contained in:
		| @@ -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", | ||||
|   | ||||
| @@ -21,6 +21,34 @@ RED.actions = (function() { | ||||
|     function getAction(name) { | ||||
|         return actions[name].handler; | ||||
|     } | ||||
|     function getActionLabel(name) { | ||||
|         let def = actions[name] | ||||
|         if (!def) { | ||||
|             return '' | ||||
|         } | ||||
|         if (!def.label) { | ||||
|             var options = def.options; | ||||
|             var key = options ? options.label : undefined; | ||||
|             if (!key) { | ||||
|                 key = "action-list." +name.replace(/^.*:/,""); | ||||
|             } | ||||
|             var label = RED._(key); | ||||
|             if (label === key) { | ||||
|                 // no translation. convert `name` to description | ||||
|                 label = name.replace(/(^.+:([a-z]))|(-([a-z]))/g, function() { | ||||
|                     if (arguments[5] === 0) { | ||||
|                         return arguments[2].toUpperCase(); | ||||
|                     } else { | ||||
|                         return " "+arguments[4].toUpperCase(); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|             def.label = label; | ||||
|         } | ||||
|         return def.label | ||||
|     } | ||||
|  | ||||
|  | ||||
|     function invokeAction() { | ||||
|         var args = Array.prototype.slice.call(arguments); | ||||
|         var name = args.shift(); | ||||
| @@ -31,7 +59,7 @@ RED.actions = (function() { | ||||
|     } | ||||
|     function listActions() { | ||||
|         var result = []; | ||||
|         var missing = []; | ||||
|  | ||||
|         Object.keys(actions).forEach(function(action) { | ||||
|             var def = actions[action]; | ||||
|             var shortcut = RED.keyboard.getShortcut(action); | ||||
| @@ -42,28 +70,8 @@ RED.actions = (function() { | ||||
|                 isUser = !!RED.keyboard.getUserShortcut(action); | ||||
|             } | ||||
|             if (!def.label) { | ||||
|                 var name = action; | ||||
|                 var options = def.options; | ||||
|                 var key = options ? options.label : undefined; | ||||
|                 if (!key) { | ||||
|                     key = "action-list." +name.replace(/^.*:/,""); | ||||
|                 } | ||||
|                 var label = RED._(key); | ||||
|                 if (label === key) { | ||||
|                     // no translation. convert `name` to description  | ||||
|                     label = name.replace(/(^.+:([a-z]))|(-([a-z]))/g, function() { | ||||
|                         if (arguments[5] === 0) { | ||||
|                             return arguments[2].toUpperCase(); | ||||
|                         } else { | ||||
|                             return " "+arguments[4].toUpperCase(); | ||||
|                         } | ||||
|                     }); | ||||
|                     missing.push(key); | ||||
|                 } | ||||
|                 def.label = label; | ||||
|                 def.label = getActionLabel(action) | ||||
|             } | ||||
|             //console.log("; missing:", missing); | ||||
|  | ||||
|             result.push({ | ||||
|                 id:action, | ||||
|                 scope:shortcut?shortcut.scope:undefined, | ||||
| @@ -79,6 +87,7 @@ RED.actions = (function() { | ||||
|         add: addAction, | ||||
|         remove: removeAction, | ||||
|         get: getAction, | ||||
|         getLabel: getActionLabel, | ||||
|         invoke: invokeAction, | ||||
|         list: listActions | ||||
|     } | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
| RED.menu = (function() { | ||||
|  | ||||
|     var menuItems = {}; | ||||
|     let menuItemCount = 0 | ||||
|  | ||||
|     function createMenuItem(opt) { | ||||
|         var item; | ||||
| @@ -59,15 +60,16 @@ RED.menu = (function() { | ||||
|             item = $('<li class="red-ui-menu-divider"></li>'); | ||||
|         } else { | ||||
|             item = $('<li></li>'); | ||||
|  | ||||
|             if (!opt.id) { | ||||
|                 opt.id = 'red-ui-menu-item-'+(menuItemCount++) | ||||
|             } | ||||
|             if (opt.group) { | ||||
|                 item.addClass("red-ui-menu-group-"+opt.group); | ||||
|  | ||||
|             } | ||||
|             var linkContent = '<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">'; | ||||
|             if (opt.toggle) { | ||||
|                 linkContent += '<i class="fa fa-square pull-left"></i>'; | ||||
|                 linkContent += '<i class="fa fa-check-square pull-left"></i>'; | ||||
|                 linkContent += '<i class="fa fa-square'+(opt.direction!=='right'?" pull-left":"")+'"></i>'; | ||||
|                 linkContent += '<i class="fa fa-check-square'+(opt.direction!=='right'?" pull-left":"")+'"></i>'; | ||||
|  | ||||
|             } | ||||
|             if (opt.icon !== undefined) { | ||||
| @@ -77,12 +79,15 @@ RED.menu = (function() { | ||||
|                     linkContent += '<i class="'+(opt.icon?opt.icon:'" style="display: inline-block;"')+'"></i> '; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             let label = opt.label | ||||
|             if (!opt.label && typeof opt.onselect === 'string') { | ||||
|                 label = RED.actions.getLabel(opt.onselect) | ||||
|             } | ||||
|             if (opt.sublabel) { | ||||
|                 linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+opt.label+'</span>'+ | ||||
|                 linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+label+'</span>'+ | ||||
|                                '<span class="red-ui-menu-sublabel">'+opt.sublabel+'</span></span>' | ||||
|             } else { | ||||
|                 linkContent += '<span class="red-ui-menu-label"><span>'+opt.label+'</span></span>' | ||||
|                 linkContent += '<span class="red-ui-menu-label"><span>'+label+'</span></span>' | ||||
|             } | ||||
|  | ||||
|             linkContent += '</a>'; | ||||
| @@ -126,10 +131,21 @@ RED.menu = (function() { | ||||
|                 }); | ||||
|             } | ||||
|             if (opt.options) { | ||||
|                 item.addClass("red-ui-menu-dropdown-submenu pull-left"); | ||||
|                 item.addClass("red-ui-menu-dropdown-submenu"+(opt.direction!=='right'?" pull-left":"")); | ||||
|                 var submenu = $('<ul id="'+opt.id+'-submenu" class="red-ui-menu-dropdown"></ul>').appendTo(item); | ||||
|  | ||||
|                 for (var i=0;i<opt.options.length;i++) { | ||||
|  | ||||
|                     if (opt.options[i]) { | ||||
|                         if (opt.onpreselect && opt.options[i].onpreselect === undefined) { | ||||
|                             opt.options[i].onpreselect = opt.onpreselect | ||||
|                         } | ||||
|                         if (opt.onpostselect && opt.options[i].onpostselect === undefined) { | ||||
|                             opt.options[i].onpostselect = opt.onpostselect | ||||
|                         } | ||||
|                         opt.options[i].direction = opt.direction | ||||
|                     } | ||||
|  | ||||
|                     var li = createMenuItem(opt.options[i]); | ||||
|                     if (li) { | ||||
|                         li.appendTo(submenu); | ||||
| @@ -147,7 +163,9 @@ RED.menu = (function() { | ||||
|     } | ||||
|     function createMenu(options) { | ||||
|         var topMenu = $("<ul/>",{class:"red-ui-menu red-ui-menu-dropdown pull-right"}); | ||||
|  | ||||
|         if (options.direction) { | ||||
|             topMenu.addClass("red-ui-menu-dropdown-direction-"+options.direction) | ||||
|         } | ||||
|         if (options.id) { | ||||
|             topMenu.attr({id:options.id+"-submenu"}); | ||||
|             var menuParent = $("#"+options.id); | ||||
| @@ -175,6 +193,15 @@ RED.menu = (function() { | ||||
|         var lastAddedSeparator = false; | ||||
|         for (var i=0;i<options.options.length;i++) { | ||||
|             var opt = options.options[i]; | ||||
|             if (opt) { | ||||
|                 if (options.onpreselect && opt.onpreselect === undefined) { | ||||
|                     opt.onpreselect = options.onpreselect | ||||
|                 } | ||||
|                 if (options.onpostselect && opt.onpostselect === undefined) { | ||||
|                     opt.onpostselect = options.onpostselect | ||||
|                 } | ||||
|                 opt.direction = options.direction || 'left' | ||||
|             } | ||||
|             if (opt !== null || !lastAddedSeparator) { | ||||
|                 var li = createMenuItem(opt); | ||||
|                 if (li) { | ||||
| @@ -190,6 +217,9 @@ RED.menu = (function() { | ||||
|     function triggerAction(id, args) { | ||||
|         var opt = menuItems[id]; | ||||
|         var callback = opt.onselect; | ||||
|         if (opt.onpreselect) { | ||||
|             opt.onpreselect.call(opt,args) | ||||
|         } | ||||
|         if (typeof opt.onselect === 'string') { | ||||
|             callback = RED.actions.get(opt.onselect); | ||||
|         } | ||||
| @@ -198,6 +228,9 @@ RED.menu = (function() { | ||||
|         } else { | ||||
|             console.log("No callback for",id,opt.onselect); | ||||
|         } | ||||
|         if (opt.onpostselect) { | ||||
|             opt.onpostselect.call(opt,args) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function isSelected(id) { | ||||
|   | ||||
| @@ -610,10 +610,13 @@ RED.popover = (function() { | ||||
|                 var target = options.target; | ||||
|                 var align = options.align || "right"; | ||||
|                 var offset = options.offset || [0,0]; | ||||
|                 var xPos = options.x; | ||||
|                 var yPos = options.y; | ||||
|                 var isAbsolutePosition = (xPos !== undefined && yPos !== undefined) | ||||
|  | ||||
|                 var pos = target.offset(); | ||||
|                 var targetWidth = target.width(); | ||||
|                 var targetHeight = target.outerHeight(); | ||||
|                 var pos = isAbsolutePosition?{left:xPos, top: yPos}:target.offset(); | ||||
|                 var targetWidth = isAbsolutePosition?0:target.width(); | ||||
|                 var targetHeight = isAbsolutePosition?0:target.outerHeight(); | ||||
|                 var panelHeight = panel.height(); | ||||
|                 var panelWidth = panel.width(); | ||||
|  | ||||
|   | ||||
							
								
								
									
										175
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
|     } | ||||
| })() | ||||
| @@ -104,7 +104,9 @@ RED.typeSearch = (function() { | ||||
|                     var index = Math.max(0,selected); | ||||
|                     if (index < children.length) { | ||||
|                         var n = $(children[index]).find(".red-ui-editableList-item-content").data('data'); | ||||
|                         typesUsed[n.type] = Date.now(); | ||||
|                         if (!/^_action_:/.test(n.type)) { | ||||
|                             typesUsed[n.type] = Date.now(); | ||||
|                         } | ||||
|                         if (n.def.outputs === 0) { | ||||
|                             confirm(n); | ||||
|                         } else { | ||||
| @@ -173,6 +175,8 @@ RED.typeSearch = (function() { | ||||
|                 var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div); | ||||
|                 if (object.type === "junction") { | ||||
|                     nodeDiv.addClass("red-ui-palette-icon-junction"); | ||||
|                 } else if (/^_action_:/.test(object.type)) { | ||||
|                     nodeDiv.addClass("red-ui-palette-icon-junction") | ||||
|                 } else { | ||||
|                     var colour = RED.utils.getNodeColor(object.type,def); | ||||
|                     nodeDiv.css('backgroundColor',colour); | ||||
| @@ -182,11 +186,14 @@ RED.typeSearch = (function() { | ||||
|                 var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv); | ||||
|                 RED.utils.createIconElement(icon_url, iconContainer, false); | ||||
|  | ||||
|                 if (object.type !== "junction" && def.inputs > 0) { | ||||
|                     $('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv); | ||||
|                 } | ||||
|                 if (object.type !== "junction" && def.outputs > 0) { | ||||
|                     $('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv); | ||||
|  | ||||
|                 if (!/^_action_:/.test(object.type) && object.type !== "junction") { | ||||
|                     if (def.inputs > 0) { | ||||
|                         $('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv); | ||||
|                     } | ||||
|                     if (def.outputs > 0) { | ||||
|                         $('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div); | ||||
| @@ -207,7 +214,9 @@ RED.typeSearch = (function() { | ||||
|     } | ||||
|     function confirm(def) { | ||||
|         hide(); | ||||
|         typesUsed[def.type] = Date.now(); | ||||
|         if (!/^_action_:/.test(def.type)) { | ||||
|             typesUsed[def.type] = Date.now(); | ||||
|         } | ||||
|         addCallback(def.type); | ||||
|     } | ||||
|  | ||||
| @@ -316,6 +325,7 @@ RED.typeSearch = (function() { | ||||
|     function applyFilter(filter,type,def) { | ||||
|         return !filter || | ||||
|             ( | ||||
|                 (!filter.spliceMultiple) && | ||||
|                 (!filter.type || type === filter.type) && | ||||
|                 (!filter.input || type === 'junction' || def.inputs > 0) && | ||||
|                 (!filter.output || type === 'junction' || def.outputs > 0) | ||||
| @@ -330,6 +340,13 @@ RED.typeSearch = (function() { | ||||
|             'inject','debug','function','change','switch','junction' | ||||
|         ].filter(function(t) { return applyFilter(opts.filter,t,RED.nodes.getType(t)); }); | ||||
|  | ||||
|         // if (opts.filter && opts.filter.input && opts.filter.output && !opts.filter.type) { | ||||
|         //     if (opts.filter.spliceMultiple) { | ||||
|         //         common.push('_action_:core:split-wires-with-junctions') | ||||
|         //     } | ||||
|         //     common.push('_action_:core:split-wire-with-link-nodes') | ||||
|         // } | ||||
|  | ||||
|         var recentlyUsed = Object.keys(typesUsed); | ||||
|         recentlyUsed.sort(function(a,b) { | ||||
|             return typesUsed[b]-typesUsed[a]; | ||||
| @@ -354,6 +371,8 @@ RED.typeSearch = (function() { | ||||
|             var itemDef = RED.nodes.getType(common[i]); | ||||
|             if (common[i] === 'junction') { | ||||
|                 itemDef = { inputs:1, outputs: 1, label: 'junction', type: 'junction'} | ||||
|             } else if (/^_action_:/.test(common[i]) ) { | ||||
|                 itemDef = { inputs:1, outputs: 1, label: common[i], type: common[i]} | ||||
|             } | ||||
|             if (itemDef) { | ||||
|                 item = { | ||||
|   | ||||
| @@ -1032,6 +1032,8 @@ RED.utils = (function() { | ||||
|             return "font-awesome/fa-circle-o" | ||||
|         } else if (def.category === 'config') { | ||||
|             return RED.settings.apiRootUrl+"icons/node-red/cog.svg" | ||||
|         } else if ((node && /^_action_:/.test(node.type)) || /^_action_:/.test(def.type)) { | ||||
|             return "font-awesome/fa-cogs" | ||||
|         } else if (node && node.type === 'tab') { | ||||
|             return "red-ui-icons/red-ui-icons-flow" | ||||
|             // return RED.settings.apiRootUrl+"images/subflow_tab.svg" | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user