Subject of the issue
The box menu can render every menu item twice. This happens whenever something asks the menu to add its children again after the menu has already rendered (for example when Trickle fires its trickle:kill event, which Dev Tools triggers via its "Complete menu" button). Navigating into a child page and back clears the duplicates, because the menu is then rebuilt from scratch.
Originally raised against Dev Tools (cgkineo/adapt-devtools#91), but the root cause is in Box Menu.
Your environment
- Framework v5.56.2
- Box Menu v6.7.0 and v7.0.1 (JSX)
- Reproduced in Chrome on macOS
Steps to reproduce
- Use a course with the box menu and Dev Tools enabled.
- Open the menu.
- Open Dev Tools and click "Complete menu" (this fires
trickle:kill).
- The menu items are now shown twice.
Alternatively, trigger the underlying cause directly in the console (using v5 console access):
const Adapt = require('core/js/adapt').default;
Adapt.trigger('trickle:kill'); // menu items double
Expected behaviour
Re-running the menu's child rendering should be a no-op once the items are already on screen. The item count should stay the same.
Actual behaviour
The full set of items is appended a second time, so each topic appears twice.
Suggested Fix
BoxMenuView.addChildren() in BoxMenuView.js renders all children in a single pass and appends them to the container, but unlike the core AdaptView.addChildren() it has no guard against being called again. Every call starts from nthChild = 0 and appends a fresh full set, with no early return and no check for already-rendered views.
The core view is incremental and idempotent (it tracks progress and only adds new children). The box menu override is all-or-nothing, so the simplest safe fix is to bail out when child views already exist for this view instance:
addChildren() {
// BoxMenu renders all children in a single pass. Ignore subsequent calls
// (e.g. triggered by trickle:kill) that would otherwise append a second
// full set of child views and duplicate the menu items.
if (this.getChildViews()) return;
// ...existing body...
}
A freshly constructed view (e.g. on revisiting the menu) has no child views yet, so it still renders normally; only the redundant second call is skipped.
Verified in v5.56.2: with the guard, calling addChildren() again and firing trickle:kill both leave the item count unchanged (12 -> 12). Temporarily removing the guard reproduces the doubling (12 -> 24).
Posted via collaboration with Claude Code
Subject of the issue
The box menu can render every menu item twice. This happens whenever something asks the menu to add its children again after the menu has already rendered (for example when Trickle fires its
trickle:killevent, which Dev Tools triggers via its "Complete menu" button). Navigating into a child page and back clears the duplicates, because the menu is then rebuilt from scratch.Originally raised against Dev Tools (cgkineo/adapt-devtools#91), but the root cause is in Box Menu.
Your environment
Steps to reproduce
trickle:kill).Alternatively, trigger the underlying cause directly in the console (using v5 console access):
Expected behaviour
Re-running the menu's child rendering should be a no-op once the items are already on screen. The item count should stay the same.
Actual behaviour
The full set of items is appended a second time, so each topic appears twice.
Suggested Fix
BoxMenuView.addChildren()in BoxMenuView.js renders all children in a single pass and appends them to the container, but unlike the coreAdaptView.addChildren()it has no guard against being called again. Every call starts fromnthChild = 0and appends a fresh full set, with no early return and no check for already-rendered views.The core view is incremental and idempotent (it tracks progress and only adds new children). The box menu override is all-or-nothing, so the simplest safe fix is to bail out when child views already exist for this view instance:
A freshly constructed view (e.g. on revisiting the menu) has no child views yet, so it still renders normally; only the redundant second call is skipped.
Verified in v5.56.2: with the guard, calling
addChildren()again and firingtrickle:killboth leave the item count unchanged (12 -> 12). Temporarily removing the guard reproduces the doubling (12 -> 24).Posted via collaboration with Claude Code