1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Allow sidebar tabs to be reordered

The sidebar tab buttons can now be dragged to reorder them.

Changes to the order are stored in user preferences.
This commit is contained in:
Nick O'Leary 2020-07-15 11:26:08 +01:00
parent 8b36279e52
commit 73d8dfe381
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
2 changed files with 150 additions and 19 deletions

View File

@ -29,7 +29,7 @@ RED.tabs = (function() {
var currentTabWidth; var currentTabWidth;
var currentActiveTabWidth = 0; var currentActiveTabWidth = 0;
var collapsibleMenu; var collapsibleMenu;
var preferredOrder = options.order;
var ul = options.element || $("#"+options.id); var ul = options.element || $("#"+options.id);
var wrapper = ul.wrap( "<div>" ).parent(); var wrapper = ul.wrap( "<div>" ).parent();
var scrollContainer = ul.wrap( "<div>" ).parent(); var scrollContainer = ul.wrap( "<div>" ).parent();
@ -132,11 +132,11 @@ RED.tabs = (function() {
activateTab(id); activateTab(id);
} }
}; };
if (tabs[id].pinned) { // if (tabs[id].pinned) {
pinnedOptions.push(opt); // pinnedOptions.push(opt);
} else { // } else {
options.push(opt); options.push(opt);
} // }
}); });
options = pinnedOptions.concat(options); options = pinnedOptions.concat(options);
collapsibleMenu = RED.menu.init({options: options}); collapsibleMenu = RED.menu.init({options: options});
@ -363,23 +363,39 @@ RED.tabs = (function() {
var tabWidth; var tabWidth;
if (options.collapsible) { if (options.collapsible) {
var availableCount = collapsedButtonsRow.children().length;
var visibleCount = collapsedButtonsRow.children(":visible").length;
tabWidth = width - collapsedButtonsRow.width()-10; tabWidth = width - collapsedButtonsRow.width()-10;
if (tabWidth < 198) { var maxTabWidth = 198;
var delta = 198 - tabWidth; var minTabWidth = 80;
if (tabWidth <= minTabWidth || (tabWidth < maxTabWidth && visibleCount > 5)) {
// The tab is too small. Hide the next button to make room
// Start at the end of the button row, -1 for the menu button
var b = collapsedButtonsRow.find("a:last").prev(); var b = collapsedButtonsRow.find("a:last").prev();
var index = collapsedButtonsRow.children().length - 2;
// Work backwards to find the first visible button
while (b.is(":not(:visible)")) { while (b.is(":not(:visible)")) {
b = b.prev(); b = b.prev();
index--;
} }
if (!b.hasClass("red-ui-tab-link-button-pinned")) { // If it isn't a pinned button, hide it to get the room
if (tabWidth <= minTabWidth || visibleCount>6) {//}!b.hasClass("red-ui-tab-link-button-pinned")) {
b.hide(); b.hide();
} }
tabWidth = width - collapsedButtonsRow.width()-10; tabWidth = Math.max(minTabWidth,width - collapsedButtonsRow.width()-10);
} else { } else {
var space = width - 198 - collapsedButtonsRow.width(); if (visibleCount !== availableCount) {
if (visibleCount < 6) {
tabWidth = minTabWidth;
} else {
tabWidth = maxTabWidth;
}
}
var space = width - tabWidth - collapsedButtonsRow.width();
if (space > 40) { if (space > 40) {
collapsedButtonsRow.find("a:not(:visible):first").show(); collapsedButtonsRow.find("a:not(:visible):first").show();
tabWidth = width - collapsedButtonsRow.width()-10;
} }
tabWidth = width - collapsedButtonsRow.width()-10;
} }
tabs.css({width:tabWidth}); tabs.css({width:tabWidth});
@ -469,7 +485,7 @@ RED.tabs = (function() {
} }
} }
return { var tabAPI = {
addTab: function(tab,targetIndex) { addTab: function(tab,targetIndex) {
if (options.onselect) { if (options.onselect) {
var selection = ul.find("li.red-ui-tab.selected"); var selection = ul.find("li.red-ui-tab.selected");
@ -531,11 +547,92 @@ RED.tabs = (function() {
evt.preventDefault(); evt.preventDefault();
activateTab(tab.id); activateTab(tab.id);
}); });
pinnedLink.data("tabId",tab.id)
if (tab.pinned) { if (tab.pinned) {
pinnedLink.addClass("red-ui-tab-link-button-pinned"); pinnedLink.addClass("red-ui-tab-link-button-pinned");
pinnedTabsCount++; pinnedTabsCount++;
} }
RED.popover.tooltip($(pinnedLink), tab.name, tab.action); RED.popover.tooltip($(pinnedLink), tab.name, tab.action);
if (options.onreorder) {
var pinnedLinkIndex;
var pinnedLinks = [];
var startPinnedIndex;
pinnedLink.draggable({
distance: 10,
axis:"x",
containment: ".red-ui-tab-link-buttons",
start: function(event,ui) {
dragActive = true;
$(".red-ui-tab-link-buttons").width($(".red-ui-tab-link-buttons").width());
if (dblClickArmed) { dblClickArmed = false; return false }
collapsedButtonsRow.children().each(function(i) {
pinnedLinks[i] = {
el:$(this),
text: $(this).text(),
left: $(this).position().left,
width: $(this).width(),
menu: $(this).hasClass("red-ui-tab-link-button-menu")
};
if ($(this).is(pinnedLink)) {
pinnedLinkIndex = i;
startPinnedIndex = i;
}
});
collapsedButtonsRow.children().each(function(i) {
if (i!==pinnedLinkIndex) {
$(this).css({
position: 'absolute',
left: pinnedLinks[i].left+"px",
width: pinnedLinks[i].width+2,
transition: "left 0.3s"
});
}
})
if (!pinnedLink.hasClass('active')) {
pinnedLink.css({'zIndex':1});
}
},
drag: function(event,ui) {
ui.position.left += pinnedLinks[pinnedLinkIndex].left;
var tabCenter = ui.position.left + pinnedLinks[pinnedLinkIndex].width/2;
for (var i=0;i<pinnedLinks.length;i++) {
if (i === pinnedLinkIndex || pinnedLinks[i].menu || pinnedLinks[i].el.is(":not(:visible)")) {
continue;
}
if (tabCenter > pinnedLinks[i].left && tabCenter < pinnedLinks[i].left+pinnedLinks[i].width) {
if (i < pinnedLinkIndex) {
pinnedLinks[i].left += pinnedLinks[pinnedLinkIndex].width+8;
pinnedLinks[pinnedLinkIndex].el.detach().insertBefore(pinnedLinks[i].el);
} else {
pinnedLinks[i].left -= pinnedLinks[pinnedLinkIndex].width+8;
pinnedLinks[pinnedLinkIndex].el.detach().insertAfter(pinnedLinks[i].el);
}
pinnedLinks[i].el.css({left:pinnedLinks[i].left+"px"});
pinnedLinks.splice(i, 0, pinnedLinks.splice(pinnedLinkIndex, 1)[0]);
pinnedLinkIndex = i;
break;
}
}
},
stop: function(event,ui) {
collapsedButtonsRow.children().css({position:"relative",left:"",transition:""});
$(".red-ui-tab-link-buttons").width('auto');
pinnedLink.css({zIndex:""});
updateTabWidths();
if (startPinnedIndex !== pinnedLinkIndex) {
if (collapsibleMenu) {
collapsibleMenu.remove();
collapsibleMenu = null;
}
var newOrder = $.makeArray(collapsedButtonsRow.children().map(function() { return $(this).data('tabId');}));
tabAPI.order(newOrder);
options.onreorder(newOrder);
}
}
});
}
} }
link.on("mouseup",onTabClick); link.on("mouseup",onTabClick);
@ -565,7 +662,7 @@ RED.tabs = (function() {
if (ul.find("li.red-ui-tab").length == 1) { if (ul.find("li.red-ui-tab").length == 1) {
activateTab(link); activateTab(link);
} }
if (options.onreorder) { if (options.onreorder && !options.collapsible) {
var originalTabOrder; var originalTabOrder;
var tabDragIndex; var tabDragIndex;
var tabElements = []; var tabElements = [];
@ -652,6 +749,9 @@ RED.tabs = (function() {
collapsibleMenu.remove(); collapsibleMenu.remove();
collapsibleMenu = null; collapsibleMenu = null;
} }
if (preferredOrder) {
tabAPI.order(preferredOrder);
}
}, },
removeTab: removeTab, removeTab: removeTab,
activateTab: activateTab, activateTab: activateTab,
@ -673,10 +773,8 @@ RED.tabs = (function() {
}, },
selection: getSelection, selection: getSelection,
order: function(order) { order: function(order) {
preferredOrder = order;
var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');})); var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));
if (existingTabOrder.length !== order.length) {
return
}
var i; var i;
var match = true; var match = true;
for (i=0;i<order.length;i++) { for (i=0;i<order.length;i++) {
@ -692,13 +790,42 @@ RED.tabs = (function() {
var existingTabs = ul.children().detach().each(function() { var existingTabs = ul.children().detach().each(function() {
existingTabMap[$(this).data("tabId")] = $(this); existingTabMap[$(this).data("tabId")] = $(this);
}); });
var pinnedButtons = {};
if (options.collapsible) {
collapsedButtonsRow.children().detach().each(function() {
var id = $(this).data("tabId");
if (!id) {
id = "__menu__"
}
pinnedButtons[id] = $(this);
});
}
for (i=0;i<order.length;i++) { for (i=0;i<order.length;i++) {
if (existingTabMap[order[i]]) {
existingTabMap[order[i]].appendTo(ul); existingTabMap[order[i]].appendTo(ul);
if (options.collapsible) {
pinnedButtons[order[i]].appendTo(collapsedButtonsRow);
}
delete existingTabMap[order[i]];
} }
} }
// Add any tabs that aren't known in the order
for (i in existingTabMap) {
if (existingTabMap.hasOwnProperty(i)) {
existingTabMap[i].appendTo(ul);
if (options.collapsible) {
pinnedButtons[i].appendTo(collapsedButtonsRow);
} }
} }
}
if (options.collapsible) {
pinnedButtons["__menu__"].appendTo(collapsedButtonsRow);
updateTabWidths();
}
}
}
return tabAPI;
}
return { return {
create: createTabs create: createTabs

View File

@ -232,7 +232,11 @@ RED.sidebar = (function() {
} }
}, },
// minimumActiveTabWidth: 70, // minimumActiveTabWidth: 70,
collapsible: true collapsible: true,
onreorder: function(order) {
RED.settings.set("editor.sidebar.order",order);
},
order: RED.settings.get("editor.sidebar.order",["info", "help", "version-control", "debug"])
// scrollable: true // scrollable: true
}); });