diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js index 091c69c34..5c960c259 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js @@ -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 = $('
'); 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) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js b/packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js index ed3a540b6..85404a51b 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js @@ -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 = $('').addClass('red-ui-sidebar-' + sidebar.direction); if (sidebar.direction === 'right') { @@ -307,6 +355,48 @@ RED.sidebar = (function() { // toggleSidebarButton.prependTo(tabBar); // } + sidebar.tabOverflowButton = $(''); + 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 = $('').appendTo(tabBar); - const tabOverflowButton = $('').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) diff --git a/packages/node_modules/@node-red/editor-client/src/sass/sidebar.scss b/packages/node_modules/@node-red/editor-client/src/sass/sidebar.scss index 22b5f5aaa..20aa63785 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/sidebar.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/sidebar.scss @@ -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; } diff --git a/packages/node_modules/@node-red/editor-client/src/sass/workspace.scss b/packages/node_modules/@node-red/editor-client/src/sass/workspace.scss index 7035974f5..02cfaa5ee 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/workspace.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/workspace.scss @@ -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; } }