From 89a58566a5b9082ae2375dde318339110a4d599f Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Fri, 11 Oct 2024 13:00:58 -0700 Subject: [PATCH] Rename & refactor invoker commands to reflect new spec decisions. Invoker commands now live solely on HTMLButtonElement, and have been dropped from HTMLInputElement. This was discussed and resolved + minuted in Jul 18 WHATNOT meeting: https://github.com/whatwg/html/issues/10471#issuecomment-2237135334) Words must be separated with dashes. This was discussed and resolved + minuted in Jul 18 WHATNOT meeting: https://github.com/whatwg/html/issues/10471#issuecomment-2237135334) "Custom" commands now require a double dash (`--`) prefix. This was discussed & resolved + minuted in the Jul 25 OpenUI meeting: https://github.com/openui/open-ui/issues/969#issuecomment-2251153158 In addition, CommandEvent#invoker is now renamed to CommandEvent#source as discussed and resolved + minuted in Jul 18 WHATNOT meeting: https://github.com/whatwg/html/issues/10471#issuecomment-2237135334) This CL updates the tests & implementation to follow these changes. The changes can also be found in the spec PR which reflects this updated status: https://github.com/whatwg/html/pull/9841 Bug: 40284894 Change-Id: Iefa91a1736867239a21f8717aee1fcaaa54fdfd0 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839601 Reviewed-by: Mason Freed Reviewed-by: Luke Commit-Queue: Keith Cirkel Cr-Commit-Position: refs/heads/main@{#1367705} --- ...ttarget-on-popover-behavior.tentative.html | 10 ++-- ...invokeevent-dispatch-shadow.tentative.html | 30 +++++------ .../invokeevent-interface.tentative.html | 54 +++++++++---------- ...arget-button-event-dispatch.tentative.html | 28 ++++++---- ...etarget-fullscreen-behavior.tentative.html | 50 ++++++++--------- ...oketarget-on-audio-behavior.tentative.html | 30 +++++------ ...t-on-audio-invalid-behavior.tentative.html | 7 +-- ...etarget-on-details-behavior.tentative.html | 8 +-- ...on-details-invalid-behavior.tentative.html | 10 ++-- ...ketarget-on-dialog-behavior.tentative.html | 24 ++++----- ...-on-dialog-invalid-behavior.tentative.html | 11 ++-- ...nvoketarget-on-input-number.tentative.html | 28 +++++----- ...etarget-on-popover-behavior.tentative.html | 38 ++++++------- ...on-popover-invalid-behavior.tentative.html | 4 +- ...oketarget-on-video-behavior.tentative.html | 26 ++++----- interfaces/invokers.tentative.idl | 10 ++-- 16 files changed, 189 insertions(+), 179 deletions(-) diff --git a/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html b/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html index b930fc645dd413..fd0a77b9359317 100644 --- a/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html +++ b/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html @@ -71,7 +71,7 @@ promise_test(async function (t) { t.add_cleanup(reset); assert_false(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "togglepopover"); + interestbutton.setAttribute("interestaction", "toggle-popover"); await hoverOver(interestbutton); assert_true(interestee.matches(":popover-open")); }, "hover interest invoking (as togglepopover) closed popover opens"); @@ -80,7 +80,7 @@ t.add_cleanup(reset); interestee.showPopover(); assert_true(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "togglepopover"); + interestbutton.setAttribute("interestaction", "toggle-popover"); await hoverOver(interestbutton); assert_false(interestee.matches(":popover-open")); }, "hover interest invoking (as togglepopover) open popover closes"); @@ -88,7 +88,7 @@ promise_test(async function (t) { t.add_cleanup(reset); assert_false(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "togglepopover"); + interestbutton.setAttribute("interestaction", "toggle-popover"); interestbutton.focus(); assert_true(interestee.matches(":popover-open")); }, "focus interest invoking (as togglepopover) closed popover opens"); @@ -97,7 +97,7 @@ t.add_cleanup(reset); interestee.showPopover(); assert_true(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "togglepopover"); + interestbutton.setAttribute("interestaction", "toggle-popover"); interestbutton.focus(); assert_false(interestee.matches(":popover-open")); }, "focus interest invoking (as togglepopover) open popover closes"); @@ -105,7 +105,7 @@ promise_test(async function (t) { t.add_cleanup(reset); assert_false(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "tOgGlEpOpOvEr"); + interestbutton.setAttribute("interestaction", "tOgGlE-pOpOvEr"); interestbutton.focus(); assert_true(interestee.matches(":popover-open")); }, "interest invoking (as togglepopover - case insensitive) closed popover opens"); diff --git a/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html b/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html index fb2a113994f762..9d9b99259789a8 100644 --- a/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html +++ b/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html @@ -20,16 +20,16 @@ const slot = shadow.appendChild(document.createElement("slot")); let childEvent = null; let childEventTarget = null; - let childEventInvoker = null; + let childEventSource = null; let hostEvent = null; let hostEventTarget = null; - let hostEventInvoker = null; + let hostEventSource = null; slot.addEventListener( "command", (e) => { childEvent = e; childEventTarget = e.target; - childEventInvoker = e.invoker; + childEventSource = e.source; }, { once: true }, ); @@ -38,13 +38,13 @@ (e) => { hostEvent = e; hostEventTarget = e.target; - hostEventInvoker = e.invoker; + hostEventSource = e.source; }, { once: true }, ); const event = new CommandEvent("command", { bubbles: true, - invoker: slot, + source: slot, composed: true, }); slot.dispatchEvent(event); @@ -55,9 +55,9 @@ "target is child inside shadow boundary", ); assert_equals( - childEventInvoker, + childEventSource, slot, - "invoker is child inside shadow boundary", + "source is child inside shadow boundary", ); assert_equals( hostEvent, @@ -70,11 +70,11 @@ "target is retargeted to shadowroot host", ); assert_equals( - hostEventInvoker, + hostEventSource, host, - "invoker is retargeted to shadowroot host", + "source is retargeted to shadowroot host", ); - }, "CommandEvent propagates across shadow boundaries retargeting invoker"); + }, "CommandEvent propagates across shadow boundaries retargeting source"); test(function (t) { const host = document.createElement("div"); @@ -84,22 +84,22 @@ const button = shadow.appendChild(document.createElement("button")); const invokee = host.appendChild(document.createElement("div")); button.commandForElement = invokee; - button.command = 'test-command'; + button.command = '--test-command'; let event = null; let eventTarget = null; - let eventInvoker = null; + let eventSource = null; invokee.addEventListener( "command", (e) => { event = e; eventTarget = e.target; - eventInvoker = e.invoker; + eventSource = e.source; }, { once: true }, ); button.click(); assert_true(event instanceof CommandEvent); assert_equals(eventTarget, invokee, "target is invokee"); - assert_equals(eventInvoker, host, "invoker is host"); - }, "cross shadow CommandEvent retargets invoker to host element"); + assert_equals(eventSource, host, "source is host"); + }, "cross shadow CommandEvent retargets source to host element"); diff --git a/html/semantics/invokers/invokeevent-interface.tentative.html b/html/semantics/invokers/invokeevent-interface.tentative.html index 500c05f88a106a..cc2b5c94ea25d8 100644 --- a/html/semantics/invokers/invokeevent-interface.tentative.html +++ b/html/semantics/invokers/invokeevent-interface.tentative.html @@ -21,9 +21,9 @@ test(function () { const event = new CommandEvent("test"); - assert_equals(event.invoker, null); - assert_readonly(event, "invoker", "readonly attribute value"); - }, "invoker is readonly defaulting to null"); + assert_equals(event.source, null); + assert_readonly(event, "source", "readonly attribute value"); + }, "source is readonly defaulting to null"); test(function () { const event = new CommandEvent("test", { command: "sAmPle" }); @@ -87,80 +87,80 @@ }, "command set to an object with a toString function"); test(function () { - const eventInit = { command: "sample", invoker: document.body }; + const eventInit = { command: "sample", source: document.body }; const event = new CommandEvent("test", eventInit); assert_equals(event.command, "sample"); - assert_equals(event.invoker, document.body); + assert_equals(event.source, document.body); }, "CommandEventInit properties set value"); test(function () { const eventInit = { command: "open", - invoker: document.getElementById("div"), + source: document.getElementById("div"), }; const event = new CommandEvent("beforetoggle", eventInit); assert_equals(event.command, "open"); - assert_equals(event.invoker, document.getElementById("div")); + assert_equals(event.source, document.getElementById("div")); }, "CommandEventInit properties set value 2"); test(function () { const eventInit = { command: "closed", - invoker: document.getElementById("button"), + source: document.getElementById("button"), }; const event = new CommandEvent("toggle", eventInit); assert_equals(event.command, "closed"); - assert_equals(event.invoker, document.getElementById("button")); + assert_equals(event.source, document.getElementById("button")); }, "CommandEventInit properties set value 3"); test(function () { - const event = new CommandEvent("test", { invoker: undefined }); - assert_equals(event.invoker, null); - }, "invoker set to undefined"); + const event = new CommandEvent("test", { source: undefined }); + assert_equals(event.source, null); + }, "source set to undefined"); test(function () { - const event = new CommandEvent("test", { invoker: null }); - assert_equals(event.invoker, null); - }, "invoker set to null"); + const event = new CommandEvent("test", { source: null }); + assert_equals(event.source, null); + }, "source set to null"); test(function () { assert_throws_js( TypeError, function () { - new CommandEvent("test", { invoker: false }); + new CommandEvent("test", { source: false }); }, - "invoker is not an object", + "source is not an object", ); - }, "invoker set to false"); + }, "source set to false"); test(function () { assert_throws_js( TypeError, function () { - const event = new CommandEvent("test", { invoker: true }); + const event = new CommandEvent("test", { source: true }); }, - "invoker is not an object", + "source is not an object", ); - }, "invoker set to true"); + }, "source set to true"); test(function () { assert_throws_js( TypeError, function () { - const event = new CommandEvent("test", { invoker: {} }); + const event = new CommandEvent("test", { source: {} }); }, - "invoker is not an object", + "source is not an object", ); - }, "invoker set to {}"); + }, "source set to {}"); test(function () { assert_throws_js( TypeError, function () { - const eventInit = { command: "closed", invoker: new XMLHttpRequest() }; + const eventInit = { command: "closed", source: new XMLHttpRequest() }; const event = new CommandEvent("toggle", eventInit); }, - "invoker is not an Element", + "source is not an Element", ); - }, "invoker set to non-Element EventTarget"); + }, "source set to non-Element EventTarget"); diff --git a/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html b/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html index c5dfe14f90b7f2..ef870627a066f5 100644 --- a/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html +++ b/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html @@ -11,7 +11,8 @@
- + +
diff --git a/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html b/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html index 1210b8637deef9..bc7b6f416f19ed 100644 --- a/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html @@ -17,27 +17,27 @@ diff --git a/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html b/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html index 309a91e2842dd1..77fb204b98689f 100644 --- a/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html @@ -21,29 +21,29 @@ invokee.muted = false; } - // playpause + // play-pause promise_test(async function (t) { t.add_cleanup(resetState); assert_true(invokee.paused); - invokerbutton.setAttribute("command", "playpause"); + invokerbutton.setAttribute("command", "play-pause"); await clickOn(invokerbutton); await new Promise((resolve) => { requestAnimationFrame(resolve); }); assert_false(invokee.paused); - }, "invoking audio with playpause action makes audio play"); + }, "invoking audio with play-pause action makes audio play"); promise_test(async function (t) { t.add_cleanup(resetState); assert_true(invokee.paused); - invokerbutton.setAttribute("command", "playpause"); + invokerbutton.setAttribute("command", "play-pause"); invokerbutton.click(); await new Promise((resolve) => { requestAnimationFrame(resolve); }); assert_false(invokee.paused); - }, "invoking audio with playpause action (without user activation) is a no-op"); + }, "invoking audio with play-pause action (without user activation) is a no-op"); promise_test(async function (t) { t.add_cleanup(resetState); @@ -51,26 +51,26 @@ once: true, }); assert_true(invokee.paused); - invokerbutton.setAttribute("command", "playpause"); + invokerbutton.setAttribute("command", "play-pause"); await clickOn(invokerbutton); await new Promise((resolve) => { requestAnimationFrame(resolve); }); assert_true(invokee.paused); - }, "invoking audio with playpause action and preventDefault is a no-op"); + }, "invoking audio with play-pause action and preventDefault is a no-op"); promise_test(async function (t) { t.add_cleanup(resetState); await test_driver.bless("play audio"); invokee.play(); assert_false(invokee.paused); - invokerbutton.setAttribute("command", "playpause"); + invokerbutton.setAttribute("command", "play-pause"); await clickOn(invokerbutton); await new Promise((resolve) => { requestAnimationFrame(resolve); }); assert_true(invokee.paused); - }, "invoking playing audio with playpause action pauses it"); + }, "invoking playing audio with play-pause action pauses it"); // play @@ -168,13 +168,13 @@ promise_test(async function (t) { t.add_cleanup(resetState); assert_false(invokee.muted); - invokerbutton.setAttribute("command", "toggleMuted"); + invokerbutton.setAttribute("command", "toggle-muted"); await clickOn(invokerbutton); await new Promise((resolve) => { requestAnimationFrame(resolve); }); assert_true(invokee.muted); - }, "invoking audio with toggleMuted action mutes it"); + }, "invoking audio with toggle-muted action mutes it"); promise_test(async function (t) { t.add_cleanup(resetState); @@ -182,23 +182,23 @@ once: true, }); assert_false(invokee.muted); - invokerbutton.setAttribute("command", "toggleMuted"); + invokerbutton.setAttribute("command", "toggle-muted"); await clickOn(invokerbutton); await new Promise((resolve) => { requestAnimationFrame(resolve); }); assert_false(invokee.muted); - }, "invoking audio with toggleMuted action and preventDefault is a no-op"); + }, "invoking audio with toggle-muted action and preventDefault is a no-op"); promise_test(async function (t) { t.add_cleanup(resetState); invokee.muted = true; assert_true(invokee.muted); - invokerbutton.setAttribute("command", "toggleMuted"); + invokerbutton.setAttribute("command", "toggle-muted"); await clickOn(invokerbutton); await new Promise((resolve) => { requestAnimationFrame(resolve); }); assert_false(invokee.muted); - }, "invoking muted audio with toggleMuted action unmutes it"); + }, "invoking muted audio with toggle-muted action unmutes it"); diff --git a/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html b/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html index 3e18478a52f31d..5aee3ae819c280 100644 --- a/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html @@ -18,9 +18,10 @@ [ "", "foo-bar", - "showpopover", - "showmodal", - "showpicker", + "playpause", + "show-popover", + "show-modal", + "show-picker", "open", "close", ].forEach((action) => { diff --git a/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html b/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html index 4c4998cf9d860d..d5e8e97cf416f8 100644 --- a/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html @@ -31,9 +31,9 @@ async function (t) { t.add_cleanup(resetState); invokerbutton.command = command; - assert_false(invokee.matches("[open]")); + assert_false(invokee.matches("[open]"), "invokee does not match [open]"); await clickOn(invokerbutton); - assert_true(invokee.matches("[open]")); + assert_true(invokee.matches("[open]"), "invokee matches [open]"); }, `invoking (as ${command}) closed details opens`, ); @@ -42,13 +42,13 @@ async function (t) { t.add_cleanup(resetState); invokerbutton.command = command; - assert_false(invokee.matches("[open]")); + assert_false(invokee.matches("[open]"), "invokee does not match [open]"); invokee.addEventListener("command", (e) => e.preventDefault(), { once: true, }); await clickOn(invokerbutton); t.add_cleanup(() => invokee.removeAttribute("open")); - assert_false(invokee.matches("[open]")); + assert_false(invokee.matches("[open]"), "invokee still does not match [open]"); }, `invoking (as ${command}) closed details with preventDefault does not open`, ); diff --git a/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html b/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html index 3a4e86e9f2c901..9acff71c7b59d6 100644 --- a/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html @@ -23,12 +23,12 @@ [ "", "foo-bar", - "showpopover", - "showmodal", - "showpicker", - "hidepopover", + "show-popover", + "show-modal", + "show-picker", + "hide-popover", "hide", - "toggleopen", + "toggle-open", ].forEach((command) => { promise_test(async function (t) { t.add_cleanup(resetState); diff --git a/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html b/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html index 9cf1e530b3d176..4fca8a312f920a 100644 --- a/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html @@ -13,20 +13,20 @@ - + diff --git a/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html b/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html index c974b6ff108b4c..7462ce6159a8fe 100644 --- a/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html @@ -11,16 +11,16 @@
- +
- + diff --git a/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html b/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html index 31442261f37de3..91efd92ba82aa3 100644 --- a/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html @@ -25,8 +25,8 @@ invokee.setAttribute("popover", ""); } - // invalid actions on showpopover - [null, "", "foo-bar", "showmodal", "showpicker", "open", "close"].forEach((command) => { + // invalid actions on show-popover + [null, "", "foo-bar", "showpopover", "show-modal", "show-picker", "open", "close"].forEach((command) => { promise_test(async function (t) { t.add_cleanup(resetState); invokerbutton.command = command; diff --git a/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html b/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html index e395281ee31fd8..0812e7f0386458 100644 --- a/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html +++ b/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html @@ -14,7 +14,7 @@ diff --git a/interfaces/invokers.tentative.idl b/interfaces/invokers.tentative.idl index 4724d7deb08d01..046a365939c4bf 100644 --- a/interfaces/invokers.tentative.idl +++ b/interfaces/invokers.tentative.idl @@ -1,15 +1,15 @@ -interface mixin InvokerElement { - [CEReactions,Reflect=invoketarget] attribute Element? commandForElement; - [CEReactions,Reflect=invokeaction] attribute DOMString command; +interface mixin CommandElement { + [CEReactions,Reflect=commandfor] attribute Element? commandForElement; + [CEReactions,Reflect=command] attribute DOMString command; }; interface CommandEvent : Event { constructor(DOMString type, optional CommandEventInit eventInitDict = {}); - readonly attribute Element? invoker; + readonly attribute Element? source; readonly attribute DOMString command; }; dictionary CommandEventInit : EventInit { - Element? invoker = null; + Element? source = null; DOMString command = ""; };