diff --git a/Libraries/LibWeb/HTML/HTMLButtonElement.cpp b/Libraries/LibWeb/HTML/HTMLButtonElement.cpp index 1e4b836dd54..4ea99239cf5 100644 --- a/Libraries/LibWeb/HTML/HTMLButtonElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLButtonElement.cpp @@ -173,4 +173,50 @@ bool HTMLButtonElement::is_focusable() const return enabled(); } +// https://html.spec.whatwg.org/multipage/form-elements.html#dom-button-command +String HTMLButtonElement::command() const +{ + // 1. Let command be this's command attribute. + auto command = get_attribute(AttributeNames::command); + + // https://html.spec.whatwg.org/multipage/form-elements.html#attr-button-command + // The command attribute is an enumerated attribute with the following keywords and states: + // Keyword State Brief description + // toggle-popover Toggle Popover Shows or hides the targeted popover element. + // show-popover Show Popover Shows the targeted popover element. + // hide-popover Hide Popover Hides the targeted popover element. + // close Close Closes the targeted dialog element. + // show-modal Show Modal Opens the targeted dialog element as modal. + // A custom command keyword Custom Only dispatches the command event on the targeted element. + Array valid_values { "toggle-popover"_string, "show-popover"_string, "hide-popover"_string, "close"_string, "show-modal"_string }; + + // 2. If command is in the Custom state, then return command's value. + // A custom command keyword is a string that starts with "--". + if (command.has_value() && command.value().starts_with_bytes("--"sv)) { + return command.value(); + } + + // NOTE: Steps are re-ordered a bit. + + // 4. Return the keword corresponding to the value of command.return + if (command.has_value()) { + auto command_value = command.value(); + for (auto const& value : valid_values) { + if (value.equals_ignoring_ascii_case(command_value)) { + return value; + } + } + } + + // 3. If command is in the Unknown state, then return the empty string. + // The attribute's missing value default and invalid value default are both the Unknown state. + return {}; +} + +// https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element:dom-button-command-2 +WebIDL::ExceptionOr HTMLButtonElement::set_command(String const& value) +{ + return set_attribute(AttributeNames::command, value); +} + } diff --git a/Libraries/LibWeb/HTML/HTMLButtonElement.h b/Libraries/LibWeb/HTML/HTMLButtonElement.h index 831256ac816..d30d0fe3d52 100644 --- a/Libraries/LibWeb/HTML/HTMLButtonElement.h +++ b/Libraries/LibWeb/HTML/HTMLButtonElement.h @@ -80,6 +80,9 @@ public: virtual bool has_activation_behavior() const override; virtual void activation_behavior(DOM::Event const&) override; + String command() const; + WebIDL::ExceptionOr set_command(String const& command); + private: virtual void visit_edges(Visitor&) override; diff --git a/Libraries/LibWeb/HTML/HTMLButtonElement.idl b/Libraries/LibWeb/HTML/HTMLButtonElement.idl index 7a691f0733f..9746bae0635 100644 --- a/Libraries/LibWeb/HTML/HTMLButtonElement.idl +++ b/Libraries/LibWeb/HTML/HTMLButtonElement.idl @@ -15,6 +15,7 @@ enum ButtonTypeState { interface HTMLButtonElement : HTMLElement { [HTMLConstructor] constructor(); + [CEReactions] attribute DOMString command; [CEReactions, Reflect] attribute boolean disabled; readonly attribute HTMLFormElement? form; [CEReactions] attribute USVString formAction; diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/semantics/the-button-element/command-and-commandfor/command-reflection.txt b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/the-button-element/command-and-commandfor/command-reflection.txt new file mode 100644 index 00000000000..7cb8811fffa --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/the-button-element/command-and-commandfor/command-reflection.txt @@ -0,0 +1,21 @@ +Harness status: OK + +Found 16 tests + +16 Pass +Pass invoker should reflect properly +Pass invoker should reflect show-modal properly +Pass invoker should reflect toggle-popover properly +Pass invoker should reflect hide-popover properly +Pass invoker should reflect show-popover properly +Pass invoker should reflect close properly +Pass invoker should reflect --custom properly +Pass invoker should reflect odd cased sHoW-MoDaL properly - as show-modal +Pass invoker should reflect odd cased tOgGlE-pOpOvEr properly - as toggle-popover +Pass invoker should reflect odd cased hIdE-pOpOvEr properly - as hide-popover +Pass invoker should reflect odd cased sHoW-pOpOvEr properly - as show-popover +Pass invoker should reflect odd cased ClOsE properly - as close +Pass invoker should reflect odd cased --cUsToM properly - as --cUsToM +Pass invoker should reflect the invalid value "invalid" as the empty string +Pass invoker should reflect the invalid value "show-invalid" as the empty string +Pass invoker should reflect the invalid value "foo-bar" as the empty string \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/html/semantics/the-button-element/command-and-commandfor/command-reflection.html b/Tests/LibWeb/Text/input/wpt-import/html/semantics/the-button-element/command-and-commandfor/command-reflection.html new file mode 100644 index 00000000000..e6e6f0e6145 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/semantics/the-button-element/command-and-commandfor/command-reflection.html @@ -0,0 +1,42 @@ + + + + + + + + + + + + +
+ + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/semantics/the-button-element/command-and-commandfor/resources/invoker-utils.js b/Tests/LibWeb/Text/input/wpt-import/html/semantics/the-button-element/command-and-commandfor/resources/invoker-utils.js new file mode 100644 index 00000000000..4261f9c0d32 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/semantics/the-button-element/command-and-commandfor/resources/invoker-utils.js @@ -0,0 +1,27 @@ +function waitForRender() { + return new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); +} +async function clickOn(element) { + await waitForRender(); + let rect = element.getBoundingClientRect(); + let actions = new test_driver.Actions(); + // FIXME: Switch to pointerMove(0, 0, {origin: element}) once + // https://github.com/web-platform-tests/wpt/issues/41257 is fixed. + await actions + .pointerMove(Math.round(rect.x + rect.width / 2), Math.round(rect.y + rect.height / 2), {}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + await waitForRender(); +} +async function hoverOver(element) { + await waitForRender(); + let rect = element.getBoundingClientRect(); + let actions = new test_driver.Actions(); + // FIXME: Switch to pointerMove(0, 0, {origin: element}) once + // https://github.com/web-platform-tests/wpt/issues/41257 is fixed. + await actions + .pointerMove(Math.round(rect.x + rect.width / 2), Math.round(rect.y + rect.height / 2), {}) + .send(); + await waitForRender(); +}