diff --git a/src/components/bottom_bar/bottom_bar.ts b/src/components/bottom_bar/bottom_bar.ts index ebc2b35d1f..e53250519d 100644 --- a/src/components/bottom_bar/bottom_bar.ts +++ b/src/components/bottom_bar/bottom_bar.ts @@ -190,7 +190,7 @@ export class BottomBar extends Component { openContextMenu(x: Pixel, y: Pixel, registry: MenuItemRegistry, menuId?: UID) { this.menuState.isOpen = true; - this.menuState.menuItems = registry.getAll().filter((x) => x.isVisible(this.env)); + this.menuState.menuItems = registry.getAll(); this.menuState.position = { x, y }; this.menuState.menuId = menuId; } diff --git a/src/components/figures/figure_chart/figure_chart.ts b/src/components/figures/figure_chart/figure_chart.ts index 1650bd5466..684f379942 100644 --- a/src/components/figures/figure_chart/figure_chart.ts +++ b/src/components/figures/figure_chart/figure_chart.ts @@ -102,7 +102,7 @@ export class ChartFigure extends Component { private openContextMenu(position: DOMCoordinates) { const registry = this.getMenuItemRegistry(); this.menuState.isOpen = true; - this.menuState.menuItems = registry.getAll().filter((x) => x.isVisible(this.env)); + this.menuState.menuItems = registry.getAll(); this.menuState.position = position; } diff --git a/src/components/grid/grid.ts b/src/components/grid/grid.ts index 730c3e7733..91b23ad33c 100644 --- a/src/components/grid/grid.ts +++ b/src/components/grid/grid.ts @@ -523,9 +523,7 @@ export class Grid extends Component { } this.menuState.isOpen = true; this.menuState.position = { x, y }; - this.menuState.menuItems = registries[type] - .getAll() - .filter((item) => !item.isVisible || item.isVisible(this.env)); + this.menuState.menuItems = registries[type].getAll(); } copy(cut: boolean, ev: ClipboardEvent) { diff --git a/src/components/menu/menu.ts b/src/components/menu/menu.ts index e33909a8b4..d9c4f7f960 100644 --- a/src/components/menu/menu.ts +++ b/src/components/menu/menu.ts @@ -112,6 +112,10 @@ export class Menu extends Component { }); } + get visibleMenuItems(): MenuItem[] { + return this.props.menuItems.filter((x) => x.isVisible(this.env)); + } + get subMenuPosition(): DOMCoordinates { const position = Object.assign({}, this.subMenu.position); position.y -= this.subMenu.scrollOffset || 0; @@ -119,7 +123,7 @@ export class Menu extends Component { } get menuHeight(): Pixel { - const menuItems = this.props.menuItems; + const menuItems = this.visibleMenuItems; let menuItemsHeight = this.getMenuItemsHeight(menuItems); @@ -168,7 +172,7 @@ export class Menu extends Component { * and the menu item at a given index. */ private subMenuVerticalPosition(menuIndex: number): Pixel { - const menusAbove = this.props.menuItems.slice(0, menuIndex); + const menusAbove = this.visibleMenuItems.slice(0, menuIndex); return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING; } diff --git a/src/components/menu/menu.xml b/src/components/menu/menu.xml index abbb41534b..6edfdf2c11 100644 --- a/src/components/menu/menu.xml +++ b/src/components/menu/menu.xml @@ -1,6 +1,6 @@ - +
- +
{ const { left, top, height } = (ev.target as HTMLElement).getBoundingClientRect(); this.state.menuState.isOpen = true; this.state.menuState.position = { x: left, y: top + height }; - this.state.menuState.menuItems = getMenuChildren(menu, this.env).filter( - (item) => !item.isVisible || item.isVisible(this.env) - ); + this.state.menuState.menuItems = getMenuChildren(menu, this.env); this.state.menuState.parentMenu = menu; this.isSelectingMenu = true; this.openedEl = ev.target as HTMLElement; @@ -452,9 +450,7 @@ export class TopBar extends Component { this.fillColor = this.style.fillColor || "#ffffff"; this.textColor = this.style.textColor || "#000000"; - this.menus = topbarMenuRegistry - .getAll() - .filter((item) => !item.isVisible || item.isVisible(this.env)); + this.menus = topbarMenuRegistry.getAll(); } getMenuName(menu: FullMenuItem) { diff --git a/tests/components/context_menu.test.ts b/tests/components/context_menu.test.ts index 13449dde48..0fbf2f8d64 100644 --- a/tests/components/context_menu.test.ts +++ b/tests/components/context_menu.test.ts @@ -20,6 +20,7 @@ import { mockGetBoundingClientRect } from "../test_helpers/mock_helpers"; let fixture: HTMLElement; let model: Model; +let parent: Component; mockGetBoundingClientRect({ "o-menu": (el) => getElPosition(el), @@ -104,7 +105,7 @@ async function renderContextMenu( // x, y are relative to the upper left grid corner, but the menu // props must take the top bar into account. fixture = makeTestFixture(); - ({ fixture, model } = await mountComponent(ContextMenuParent, { + ({ fixture, model, parent } = await mountComponent(ContextMenuParent, { props: { x, y, @@ -642,6 +643,42 @@ describe("Context Menu internal tests", () => { expect(fixture.querySelector(".o-menu div[data-name='visible_submenu_1']")).toBeTruthy(); expect(fixture.querySelector(".o-menu div[data-name='invisible_submenu_1']")).toBeFalsy(); }); + + test("Enabled menus are updated at each render", async () => { + let enabled = true; + const menuItems: FullMenuItem[] = [ + createFullMenuItem("menuItem", { + name: "menuItem", + sequence: 1, + isEnabled: () => enabled, + }), + ]; + await renderContextMenu(300, 300, { menuItems }); + expect(fixture.querySelector("div[data-name='menuItem']")?.classList).not.toContain("disabled"); + + enabled = false; + parent.render(true); + await nextTick(); + expect(fixture.querySelector("div[data-name='menuItem']")?.classList).toContain("disabled"); + }); + + test("Visible menus are updated at each render", async () => { + let visible = true; + const menuItems: FullMenuItem[] = [ + createFullMenuItem("menuItem", { + name: "menuItem", + sequence: 1, + isVisible: () => visible, + }), + ]; + await renderContextMenu(300, 300, { menuItems }); + expect(fixture.querySelector("div[data-name='menuItem']")).toBeTruthy(); + + visible = false; + parent.render(true); + await nextTick(); + expect(fixture.querySelector("div[data-name='menuItem']")).toBeFalsy(); + }); }); jest.setTimeout(300000); describe("Context Menu position on large screen 1000px/1000px", () => {