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:
parent
8b36279e52
commit
73d8dfe381
@ -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,12 +790,41 @@ 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++) {
|
||||||
existingTabMap[order[i]].appendTo(ul);
|
if (existingTabMap[order[i]]) {
|
||||||
|
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 {
|
||||||
|
@ -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
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user