mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #2655 from node-red/reorder-sidebar
Reorderable sidebar tabs
This commit is contained in:
commit
3ad1803057
@ -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
|
||||||
|
@ -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