tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit be16986e59d6f18dbf57f8d352beac2fd1b5af9e
parent 59196df365c74c3f6a368660616dfb9e8bc7c1a2
Author: Mason Freed <masonf@chromium.org>
Date:   Wed,  3 Dec 2025 14:42:59 +0000

Bug 2003546 [wpt PR 56409] - More cleanup of menu elements code [6/4], a=testonly

Automatic update from web-platform-tests
More cleanup of menu elements code [6/4]

This primarily adds a condition to the mousedown-drag-mouseup code
that makes sure the mouseup `<menuitem>` is different from the
mousedown `<menuitem>`. To do that, the popover picker mousedown
location was changed to "info" which includes the element itself.

It turns out, after quite a bit of exploration, that the "ignore
next dom activate" code is the only way to do this correctly. I
tried to come up with logic that would work without modifying the
behavior of DOMActivate, but couldn't. Fundamentally:
 - When doing mousedown-drag-mouseup, we need to activate the sub-
   menu on mousedown.
 - No matter what, when there's a mousedown and a mouseup, the
   input system will always fire a `click` which triggers a
   `DOMActivate`.
 - The default command invoker behavior is to activate command
   invokers from the `DOMActivate` event. That needs to be avoided
   in this specific case.

I at least cleaned up the behavior to explicitly avoid *just*
the command invoker for menus, rather than all default event
behavior for `DOMActivate`.

Along the way, I also cleaned up a few other things, such as:
 - Removed explicit code for keyboard events for " " and Enter.
 - Made checkable and submenu-invoker explicitly exclusive. This is
   more intuitive, I think.
 - Made sub-menu special behavior only happen for menu-specific
   commands. I.e. `show-menu` is now different from `show-popover`.
 - Popovers triggered by menuitems will now close the containing
   menulist. That also seems more intuitive, since a popover is
   distinct from menus, and shouldn't create a nested structure.
   E.g. if a menu item triggers a "more info" card, the menu that
   triggered it shouldn't stay open - that feels weird.

Bug: 406566432
Change-Id: I836ce75b7cdc040b1743953bff1efcef22970e2a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7119885
Auto-Submit: Mason Freed <masonf@chromium.org>
Commit-Queue: Dominic Farolino <dom@chromium.org>
Reviewed-by: Dominic Farolino <dom@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1552763}

--

wpt-commits: b90da17d59dc73bfeaa436e5c032e6fdf483b949
wpt-pr: 56409

Diffstat:
Mtesting/web-platform/tests/html/semantics/menu/tentative/focus-menu-elements-arrowoperations.html | 2+-
Mtesting/web-platform/tests/html/semantics/menu/tentative/menubar-invoke-menulist.html | 19++++++++++---------
Mtesting/web-platform/tests/html/semantics/menu/tentative/menuitem-activate.html | 71+++++++++++++++++++++++++++++++++++++++++++++++------------------------
3 files changed, 58 insertions(+), 34 deletions(-)

diff --git a/testing/web-platform/tests/html/semantics/menu/tentative/focus-menu-elements-arrowoperations.html b/testing/web-platform/tests/html/semantics/menu/tentative/focus-menu-elements-arrowoperations.html @@ -7,7 +7,7 @@ <link rel=help href=https://open-ui.org/components/menu.explainer> <menubar> - <menuitem id=btn commandfor="list" command="toggle-popover">Open</menuitem> + <menuitem id=btn commandfor="list" command="toggle-menu">Open</menuitem> </menubar> <menulist id="list"> diff --git a/testing/web-platform/tests/html/semantics/menu/tentative/menubar-invoke-menulist.html b/testing/web-platform/tests/html/semantics/menu/tentative/menubar-invoke-menulist.html @@ -7,7 +7,7 @@ <menubar> <menuitem id="menubaritem">More commands</menuitem> <menuitem>Command 2</menuitem> - <menuitem>Command 3</menuitem> + <menuitem id="opencheckable" commandfor="checkable" command="show-menu">Open checkable menu</menuitem> </menubar> <menulist id="more"> @@ -15,7 +15,7 @@ <menuitem>Command 2</menuitem> </menulist> -<menulist> +<menulist id="checkable"> <fieldset checkable> <menuitem id="checkable-menuitem">Show menu</menuitem> </fieldset> @@ -130,6 +130,7 @@ test(() => { test(() => { assert_equals(checkableMenuitem.commandForElement,null, "To start, checkable item shouldn't be an invoker") + opencheckable.click(); // Open the menu checkableMenuitem.click(); assert_true(checkableMenuitem.checked, "checkable menu item becomes checked"); @@ -143,15 +144,15 @@ test(() => { assert_false(menulist.matches(":popover-open"), "menulist no longer matches :popover-open"); - // Being checkable causes sub-menu functionality to stop. + // Being a sub-menu invoker makes the item non-checkable. checkableMenuitem.command = "toggle-menu"; checkableMenuitem.commandForElement = menulist; checkableMenuitem.click(); - assert_true(checkableMenuitem.checked, - "checkable menu item that invokes a menu becomes checked"); - assert_false(menulist.matches(":popover-open"), "menulist is not open"); + assert_false(checkableMenuitem.checked, + "checkable menu item that invokes a menu is not checkable"); + assert_true(menulist.matches(":popover-open"), "menulist is open"); checkableMenuitem.click(); - assert_false(checkableMenuitem.checked, "checkable menu item unchecks"); - assert_false(menulist.matches(":popover-open"), "menulist still not open"); -}, "Checkable menuitems can still invoke menulist popovers"); + assert_false(checkableMenuitem.checked, "still not checked"); + assert_false(menulist.matches(":popover-open"), "menulist closes"); +}, "menuitems that invoke menulists cannot be checkable"); </script> diff --git a/testing/web-platform/tests/html/semantics/menu/tentative/menuitem-activate.html b/testing/web-platform/tests/html/semantics/menu/tentative/menuitem-activate.html @@ -72,11 +72,14 @@ promise_test(async () => { assert_false(popover.matches(":popover-open"), "div popover starts closed"); await test_driver.click(mainmenuitem2); assert_true(popover.matches(":popover-open"), "div popover opens"); + assert_false(mainmenu.matches(":popover-open"), "mainmenu popover closes"); // Close the popover. - await test_driver.click(mainmenuitem2); + await test_driver.click(menubarmenuitem); assert_false(popover.matches(":popover-open"), "div popover gets closed"); - assert_true(mainmenu.matches(":popover-open"), "mainmenu still open"); + assert_true(mainmenu.matches(":popover-open"), "mainmenu gets opened"); + await test_driver.click(menubarmenuitem); + assert_false(mainmenu.matches(":popover-open"), "mainmenu gets closed"); }, 'User menuitem activation works with show-popover command'); promise_test(async (t) => { @@ -121,51 +124,71 @@ promise_test(async (t) => { }, 'Menulist inside a popover works correctly; does not get accidentally ' + 'dismissed by opening submenus'); +async function getCoords(invoker, invokee) { + // test_driver isn't suited to mousedown-drag-mouseup interactions when the + // mousedown triggers visibility of one of the elements. + await clickOn(invoker); + const menulist = invokee.parentElement; + assert_true(menulist.matches(":popover-open"), "menulist popover opens when clicked"); + let rect = invokee.getBoundingClientRect(); + let coords = {x: Math.round(rect.x + rect.width / 2), + y: Math.round(rect.y + rect.height / 2)}; + await test_driver.click(invoker); + assert_false(menulist.matches(":popover-open"), "menulist popover closes when clicked"); + return coords; +} + promise_test(async (t) => { assert_false(mainmenu.matches(":popover-open"), "mainmenu popover starts closed"); - let clickCount = 0; - normalmenuitem.addEventListener('click',() => (++clickCount)); + const normal_menu_coords = await getCoords(menubarmenuitem, normalmenuitem); + let invokerClicks = 0; + let itemClicks = 0; + menubarmenuitem.addEventListener('click',() => (++invokerClicks)); + normalmenuitem.addEventListener('click',() => (++itemClicks)); + let openStateAfterPointerdown = "none"; + menubarmenuitem.addEventListener('pointermove',() => { + // There will be two move events, one before the pointerdown and one after. + // Just capture the one after. + if (openStateAfterPointerdown === "none") { + openStateAfterPointerdown = "first-move"; + } else if (openStateAfterPointerdown === "first-move") { + openStateAfterPointerdown = mainmenu.matches(":popover-open") ? "open" : "closed"; + } + },{signal: t.get_signal()}); await new test_driver.Actions() .addPointer('mouse', 'mouse') .pointerMove(0, 0, {origin: menubarmenuitem}) .pointerDown() - .send(); - await waitForRender(); - assert_true(mainmenu.matches(":popover-open"), "mainmenu popover should be open while mouse is down"); - assert_equals(clickCount,0, "no clicks yet"); - await new test_driver.Actions() - .addPointer('mouse', 'mouse') - .pointerMove(0, 0, {origin: normalmenuitem}) + // Extra move to trigger event on menubarmenuitem: + .pointerMove(2, 2, {origin: menubarmenuitem}) + // This is the center of normalmenuitem: + .pointerMove(normal_menu_coords.x, normal_menu_coords.y, {}) .pointerUp() .send(); await waitForRender(); - assert_false(mainmenu.matches(":popover-open"), "mainmenu popover should be closed"); - // TODO: Menu items should fire an event when they are selected. - // The `click` event is not enough, because one won't be fired here. - // assert_equals(clickCount,1, "the sub-menu item should have been clicked"); + assert_equals(openStateAfterPointerdown,"open", "mainmenu popover should open after pointer down"); + assert_false(mainmenu.matches(":popover-open"), "mainmenu popover should be closed after interaction"); + assert_equals(invokerClicks,0, "the invoking menu didn't get a click"); + // TODO: Menu items should fire a click event when they are selected. + // assert_equals(itemClicks,1, "the invoked menu did get a click"); }, 'A mousedown-drag-mouseup gesture on a normal menuitem picks the item'); promise_test(async (t) => { assert_false(mainmenu.matches(":popover-open"), "mainmenu popover starts closed"); assert_false(submenu.matches(":popover-open"), "submenu popover starts closed"); + const main_menu_coords = await getCoords(menubarmenuitem, mainmenuitem); await new test_driver.Actions() .addPointer('mouse', 'mouse') .pointerMove(0, 0, {origin: menubarmenuitem}) .pointerDown() - .send(); - await waitForRender(); - assert_true(mainmenu.matches(":popover-open"), "mainmenu popover should be open while mouse is down"); - assert_false(submenu.matches(":popover-open"), "submenu shouldn't be open yet"); - await new test_driver.Actions() - .addPointer('mouse', 'mouse') - .pointerMove(0, 0, {origin: mainmenuitem}) + // This is the center of mainmenuitem: + .pointerMove(main_menu_coords.x, main_menu_coords.y, {}) .pointerUp() .send(); await waitForRender(); assert_true(mainmenu.matches(":popover-open"), "mainmenu popover should remain open, because submenu chosen"); assert_true(submenu.matches(":popover-open"), "submenu popover should be open"); - menubarmenuitem.click(); // Cleanup. - await waitForRender(); + await clickOn(menubarmenuitem); // Cleanup. assert_false(mainmenu.matches(":popover-open"), "mainmenu popover should be closed"); assert_false(submenu.matches(":popover-open"), "submenu popover should be closed"); }, 'A mousedown-drag-mouseup gesture on a submenu item leaves both menus open');