mirror of https://github.com/node-red/node-red.git
Merge pull request #5549 from node-red/5516-sidebar-tab-buttons-overflow
Improve workspace footer handling of smaller screen widthspull/5550/head
commit
55462b2dc6
|
|
@ -29,7 +29,10 @@ RED.menu = (function() {
|
|||
}
|
||||
|
||||
function setInitialState() {
|
||||
var savedStateActive = RED.settings.get("menu-" + opt.id);
|
||||
let savedStateActive;
|
||||
if (!opt.doNotPersist) {
|
||||
savedStateActive = RED.settings.get("menu-" + opt.id);
|
||||
}
|
||||
if (opt.setting) {
|
||||
// May need to migrate pre-0.17 setting
|
||||
|
||||
|
|
@ -62,6 +65,7 @@ RED.menu = (function() {
|
|||
item = $('<li></li>');
|
||||
if (!opt.id) {
|
||||
opt.id = 'red-ui-menu-item-'+(menuItemCount++)
|
||||
opt.doNotPersist = true;
|
||||
}
|
||||
if (opt.group) {
|
||||
item.addClass("red-ui-menu-group-"+opt.group);
|
||||
|
|
@ -146,7 +150,7 @@ RED.menu = (function() {
|
|||
opt.options[i].onpostselect = opt.onpostselect
|
||||
}
|
||||
opt.options[i].direction = opt.direction
|
||||
hasIcons = hasIcons || (opt.options[i].icon);
|
||||
hasIcons = hasIcons || opt.options[i].icon || opt.options[i].toggle;
|
||||
hasSubmenus = hasSubmenus || (opt.options[i].options);
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +224,7 @@ RED.menu = (function() {
|
|||
opt.direction = options.direction || 'left'
|
||||
}
|
||||
if (opt !== null || !lastAddedSeparator) {
|
||||
hasIcons = hasIcons || (opt && opt.icon);
|
||||
hasIcons = hasIcons || (opt && (opt.icon || opt.toggle));
|
||||
hasSubmenus = hasSubmenus || (opt && opt.options);
|
||||
var li = createMenuItem(opt);
|
||||
if (li) {
|
||||
|
|
|
|||
|
|
@ -284,6 +284,54 @@ RED.sidebar = (function() {
|
|||
|
||||
let draggingTabButton = false
|
||||
|
||||
|
||||
function getSidebarOptions(sidebar, targetSection) {
|
||||
const menuOptions = []
|
||||
const active = sidebar.tabBars[targetSection].active
|
||||
sidebar.tabBars[targetSection].container.find('button:not(.red-ui-sidebar-tab-bar-overflow-button)').each(function () {
|
||||
const tabId = $(this).attr('data-tab-id')
|
||||
const tabOptions = knownTabs[tabId]
|
||||
let initialStateSet = false
|
||||
menuOptions.push({
|
||||
label: tabOptions.name,
|
||||
selected: tabId === active,
|
||||
toggle: true,
|
||||
onselect: function(state) {
|
||||
if (!initialStateSet) {
|
||||
// This is called when showing the menu to initialise the state properly. This made
|
||||
// sense for other menus, but is inconvenient here. So we swallow the first call to onselect
|
||||
// without taking any action.
|
||||
initialStateSet = true
|
||||
return
|
||||
}
|
||||
if (state) {
|
||||
RED.sidebar.show(tabId)
|
||||
} else {
|
||||
// DRY: overlapping logic with the mouseup handler on the inidividual tab buttons
|
||||
if (!sidebar.sections[targetSection].hidden) {
|
||||
const otherSectionHidden = sidebar.sections[targetSection === 'top' ? 'bottom' : 'top'].hidden
|
||||
if (otherSectionHidden) {
|
||||
// Both sections are going to be hidden, so hide the sidebar first.
|
||||
// We do this *before* hiding the last section so that we remember which the 'last' section was and it can be
|
||||
// restored when the sidebar is shown again.
|
||||
RED.menu.setSelected(sidebar.menuToggle, false);
|
||||
} else {
|
||||
// Hiding just one section, clear its active setting
|
||||
sidebar.tabBars[targetSection].active = null
|
||||
}
|
||||
sidebar.hideSection(targetSection)
|
||||
} else {
|
||||
sidebar.showSection(targetSection)
|
||||
}
|
||||
exportSidebarState()
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
})
|
||||
return menuOptions
|
||||
}
|
||||
|
||||
function setupSidebarTabs(sidebar) {
|
||||
const tabBar = $('<div class="red-ui-sidebar-tab-bar"></div>').addClass('red-ui-sidebar-' + sidebar.direction);
|
||||
if (sidebar.direction === 'right') {
|
||||
|
|
@ -307,6 +355,48 @@ RED.sidebar = (function() {
|
|||
// toggleSidebarButton.prependTo(tabBar);
|
||||
// }
|
||||
|
||||
sidebar.tabOverflowButton = $('<button class="red-ui-sidebar-tab-bar-overflow-button"><i class="fa fa-ellipsis-h"></i></button>');
|
||||
sidebar.tabOverflowButton.hide()
|
||||
sidebar.tabOverflowButton.on('click', function(evt) {
|
||||
try {
|
||||
const menuOptions = getSidebarOptions(sidebar, 'top')
|
||||
const bottomMenuOptions = getSidebarOptions(sidebar, 'bottom')
|
||||
if (menuOptions.length > 0 && bottomMenuOptions.length > 0) {
|
||||
menuOptions.push(null) // separator
|
||||
}
|
||||
menuOptions.push(...bottomMenuOptions)
|
||||
if (menuOptions.length === 0) {
|
||||
return
|
||||
}
|
||||
const menu = RED.menu.init({ options: menuOptions });
|
||||
menu.attr("id",sidebar.container.attr('id')+"-menu");
|
||||
menu.css({
|
||||
position: "absolute"
|
||||
})
|
||||
menu.appendTo("body");
|
||||
var elementPos = sidebar.tabOverflowButton.offset();
|
||||
menu.css({
|
||||
top: (elementPos.top+sidebar.tabOverflowButton.height()- menu.height() - 10)+"px",
|
||||
left: sidebar.direction === 'left' ? ((elementPos.left + sidebar.tabOverflowButton.width() + 3)+"px") : ((elementPos.left - menu.width() - 3)+"px")
|
||||
})
|
||||
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
||||
setTimeout(() => {
|
||||
$(document).on("click.red-ui-sidebar-tabmenu", function(evt) {
|
||||
$(document).off("click.red-ui-sidebar-tabmenu");
|
||||
menu.remove();
|
||||
});
|
||||
}, 0)
|
||||
menu.show();
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
|
||||
if (sidebar.direction === 'right') {
|
||||
sidebar.tabOverflowButton.appendTo(tabBar);
|
||||
} else if (sidebar.direction === 'left') {
|
||||
sidebar.tabOverflowButton.prependTo(tabBar);
|
||||
}
|
||||
|
||||
|
||||
sidebar.tabBar = tabBar // sidebar.tabBars.top.container;
|
||||
|
|
@ -346,50 +436,6 @@ RED.sidebar = (function() {
|
|||
|
||||
function setupTabSection(sidebar, tabBar, position) {
|
||||
const tabBarButtonsContainer = $('<div class="red-ui-sidebar-tab-bar-buttons"></div>').appendTo(tabBar);
|
||||
const tabOverflowButton = $('<button class="red-ui-sidebar-tab-bar-overflow-button"><i class="fa fa-ellipsis-h"></i></button>').appendTo(tabBarButtonsContainer);
|
||||
tabOverflowButton.hide()
|
||||
tabOverflowButton.on('click', function(evt) {
|
||||
try {
|
||||
const menuOptions = []
|
||||
tabBarButtonsContainer.find('button:not(.red-ui-sidebar-tab-bar-overflow-button)').each(function () {
|
||||
if ($(this).is(':visible')) {
|
||||
return
|
||||
}
|
||||
const tabId = $(this).attr('data-tab-id')
|
||||
const tabOptions = knownTabs[tabId]
|
||||
menuOptions.push({
|
||||
label: tabOptions.name,
|
||||
onselect: function() {
|
||||
RED.sidebar.show(tabId)
|
||||
}
|
||||
})
|
||||
})
|
||||
if (menuOptions.length === 0) {
|
||||
return
|
||||
}
|
||||
const menu = RED.menu.init({ options: menuOptions });
|
||||
menu.attr("id",sidebar.container.attr('id')+"-menu");
|
||||
menu.css({
|
||||
position: "absolute"
|
||||
})
|
||||
menu.appendTo("body");
|
||||
var elementPos = tabOverflowButton.offset();
|
||||
menu.css({
|
||||
top: (elementPos.top+tabOverflowButton.height()- menu.height() - 10)+"px",
|
||||
left: sidebar.direction === 'left' ? ((elementPos.left + tabOverflowButton.width() + 3)+"px") : ((elementPos.left - menu.width() - 3)+"px")
|
||||
})
|
||||
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
||||
setTimeout(() => {
|
||||
$(document).on("click.red-ui-sidebar-tabmenu", function(evt) {
|
||||
$(document).off("click.red-ui-sidebar-tabmenu");
|
||||
menu.remove();
|
||||
});
|
||||
}, 0)
|
||||
menu.show();
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
tabBarButtonsContainer.data('sidebar', sidebar.id)
|
||||
tabBarButtonsContainer.data('sidebar-position', position)
|
||||
tabBarButtonsContainer.sortable({
|
||||
|
|
@ -440,7 +486,7 @@ RED.sidebar = (function() {
|
|||
container: tabBarButtonsContainer,
|
||||
addButton: function(button, position) {
|
||||
if (position === undefined || position >= tabBarButtonsContainer.children().length) {
|
||||
button.insertBefore(tabOverflowButton);
|
||||
button.appendTo(tabBarButtonsContainer);
|
||||
} else {
|
||||
button.insertBefore(tabBarButtonsContainer.children().eq(position));
|
||||
}
|
||||
|
|
@ -513,7 +559,9 @@ RED.sidebar = (function() {
|
|||
}
|
||||
sidebar.container.width(newSidebarWidth);
|
||||
ui.position.left -= scaleFactor * d
|
||||
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
||||
if (sidebar.direction === 'left') {
|
||||
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
||||
}
|
||||
RED.events.emit("sidebar:resize");
|
||||
},
|
||||
stop:function(event,ui) {
|
||||
|
|
@ -529,7 +577,9 @@ RED.sidebar = (function() {
|
|||
} else {
|
||||
sidebar.width = sidebar.container.width();
|
||||
}
|
||||
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
||||
if (sidebar.direction === 'left') {
|
||||
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
||||
}
|
||||
RED.events.emit("sidebar:resize");
|
||||
}
|
||||
});
|
||||
|
|
@ -573,7 +623,9 @@ RED.sidebar = (function() {
|
|||
}
|
||||
}
|
||||
sidebar.container.width(sidebar.width || sidebar.defaultWidth)
|
||||
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
||||
if (sidebar.direction === 'left') {
|
||||
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
||||
}
|
||||
sidebar.separator.show()
|
||||
if (sidebar.tabBars.top.active && !sidebar.sections.top.hidden) {
|
||||
sidebar.tabBars.top.container.find('button[data-tab-id="'+sidebar.tabBars.top.active+'"]').addClass('selected')
|
||||
|
|
@ -710,9 +762,37 @@ RED.sidebar = (function() {
|
|||
}
|
||||
}
|
||||
// Trigger a resize of the tab bars to handle overflow
|
||||
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
||||
if (sidebar.direction === 'left') {
|
||||
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
||||
}
|
||||
RED.events.emit("sidebar:resize");
|
||||
|
||||
if (sidebar.direction === 'right') {
|
||||
const windowWidth = $("#red-ui-editor").width();
|
||||
if (sidebar.tabOverflowButtonShown) {
|
||||
// Check if there's space to show the tab bar again
|
||||
if ($(window).width() - (sidebars.secondary.tabBar.width() + sidebar.tabOverflowButtonStatusBarWidth + sidebar.tabOverflowButtonSpace) > 0) {
|
||||
sidebar.tabOverflowButtonShown = false
|
||||
sidebar.tabOverflowButton.hide()
|
||||
sidebar.tabBars.top.container.show()
|
||||
sidebar.tabBars.bottom.container.show()
|
||||
|
||||
}
|
||||
}
|
||||
if (!sidebar.tabOverflowButtonShown) {
|
||||
const tabBarWidth = sidebar.tabBar.width()
|
||||
const tabBarPosition = sidebar.tabBar.position()
|
||||
if (tabBarWidth + tabBarPosition.left > windowWidth) {
|
||||
sidebar.tabOverflowButtonStatusBarWidth = $("#red-ui-statusbar").width()
|
||||
sidebar.tabOverflowButtonSpace = tabBarWidth
|
||||
sidebar.tabOverflowButtonShown = true
|
||||
sidebar.tabOverflowButton.show()
|
||||
sidebar.tabBars.top.container.hide()
|
||||
sidebar.tabBars.bottom.container.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$(window).on("resize", sidebar.resizeSidebar)
|
||||
|
||||
|
|
|
|||
|
|
@ -147,13 +147,18 @@
|
|||
// background: rgba(243, 160, 204, 0.617);
|
||||
|
||||
&.red-ui-sidebar-left {
|
||||
z-index: 10;
|
||||
margin-left: 5px;
|
||||
z-index: 10;
|
||||
background: none;
|
||||
}
|
||||
&.red-ui-sidebar-right {
|
||||
margin-right: 5px;
|
||||
border-bottom: none;
|
||||
justify-content: flex-end;
|
||||
|
||||
.red-ui-sidebar-tab-bar-buttons:not(:first-child) {
|
||||
padding-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
|
|
@ -216,15 +221,18 @@
|
|||
display: flex;
|
||||
}
|
||||
&.red-ui-sidebar-dragging-tab .red-ui-sidebar-tab-bar-buttons:last-child {
|
||||
border-left: 2px dashed var(--red-ui-secondary-border-color);
|
||||
// margin-left: -2px;
|
||||
width: 42px;
|
||||
height: 28px;
|
||||
}
|
||||
.red-ui-sidebar-tab-bar-buttons:last-child {
|
||||
min-width: 28px;
|
||||
}
|
||||
&.red-ui-sidebar-left .red-ui-sidebar-tab-bar-buttons:last-child,
|
||||
&.red-ui-sidebar-right .red-ui-sidebar-tab-bar-buttons:not(:first-child) {
|
||||
border-left: 2px solid var(--red-ui-secondary-border-color);
|
||||
}
|
||||
|
||||
.red-ui-sidebar-right & {
|
||||
justify-items: flex-end;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,10 +227,12 @@ button.red-ui-footer-button-toggle {
|
|||
vertical-align: middle;
|
||||
height: 100%;
|
||||
pointer-events: auto;
|
||||
text-wrap: nowrap;
|
||||
& .red-ui-footer-button,
|
||||
& .red-ui-footer-button-toggle {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue