tor-browser

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

button-event-dispatch.html (9653B)


      1 <!doctype html>
      2 <meta charset="utf-8" />
      3 <meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
      4 <meta name="timeout" content="long" />
      5 <link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <script src="resources/invoker-utils.js"></script>
      9 
     10 <div id="invokee"></div>
     11 <button id="invokerbutton" commandfor="invokee" command="--custom-command"></button>
     12 <input type="button" id="invalidbutton" commandfor="invokee" command="--custom-command">
     13 <form id="aform"></form>
     14 
     15 <script>
     16  aform.addEventListener('submit', (e) => (e.preventDefault()));
     17 
     18  function resetState() {
     19    invokerbutton.setAttribute("commandfor", "invokee");
     20    invokerbutton.setAttribute("command", "--custom-command");
     21    invokerbutton.removeAttribute("disabled");
     22    invokerbutton.removeAttribute("form");
     23    invokerbutton.removeAttribute("type");
     24  }
     25 
     26  test(function (t) {
     27    let event = null;
     28    invokee.addEventListener("command", (e) => (event = e), { once: true });
     29    invokerbutton.click();
     30    assert_true(event instanceof CommandEvent, "event is CommandEvent");
     31    assert_equals(event.type, "command", "type");
     32    assert_equals(event.bubbles, false, "bubbles");
     33    assert_equals(event.composed, false, "composed");
     34    assert_equals(event.isTrusted, true, "isTrusted");
     35    assert_equals(event.command, "--custom-command", "command");
     36    assert_equals(event.target, invokee, "target");
     37    assert_equals(event.source, invokerbutton, "source");
     38  }, "event dispatches on click with addEventListener");
     39 
     40  test(function (t) {
     41    let event = null;
     42    t.add_cleanup(() => {
     43        invokee.oncommand = null;
     44    });
     45    invokee.oncommand = (e) => (event = e);
     46    invokerbutton.click();
     47    assert_true(event instanceof CommandEvent, "event is CommandEvent");
     48    assert_equals(event.type, "command", "type");
     49    assert_equals(event.bubbles, false, "bubbles");
     50    assert_equals(event.composed, false, "composed");
     51    assert_equals(event.isTrusted, true, "isTrusted");
     52    assert_equals(event.command, "--custom-command", "command");
     53    assert_equals(event.target, invokee, "target");
     54    assert_equals(event.source, invokerbutton, "source");
     55  }, "event dispatches on click with oncommand property");
     56 
     57  // valid custom invokeactions
     58  ["--foo", "--foo-", "--cAsE-cArRiEs", "--", "--a-", "--a-b", "---", "--show-picker"].forEach(
     59    (command) => {
     60      test(function (t) {
     61        t.add_cleanup(resetState);
     62        let event = null;
     63        invokee.addEventListener("command", (e) => (event = e), { once: true });
     64        invokerbutton.command = command;
     65        invokerbutton.click();
     66        assert_true(event instanceof CommandEvent, "event is CommandEvent");
     67        assert_equals(event.type, "command", "type");
     68        assert_equals(event.bubbles, false, "bubbles");
     69        assert_equals(event.composed, false, "composed");
     70        assert_equals(event.isTrusted, true, "isTrusted");
     71        assert_equals(event.command, command, "command");
     72        assert_equals(event.target, invokee, "target");
     73        assert_equals(event.source, invokerbutton, "source");
     74      }, `setting custom command property to ${command} (must include dash) sets event command`);
     75 
     76      test(function (t) {
     77        t.add_cleanup(resetState);
     78        let event = null;
     79        invokee.addEventListener("command", (e) => (event = e), { once: true });
     80        invokerbutton.setAttribute("command", command);
     81        invokerbutton.click();
     82        assert_true(event instanceof CommandEvent, "event is CommandEvent");
     83        assert_equals(event.type, "command", "type");
     84        assert_equals(event.bubbles, false, "bubbles");
     85        assert_equals(event.composed, false, "composed");
     86        assert_equals(event.isTrusted, true, "isTrusted");
     87        assert_equals(event.command, command, "command");
     88        assert_equals(event.target, invokee, "target");
     89        assert_equals(event.source, invokerbutton, "source");
     90      }, `setting custom command attribute to ${command} (must include dash) sets event command`);
     91    },
     92  );
     93 
     94  // invalid custom invokeactions
     95  ["-foo", "-foo-", "foo-bar", "-foo bar", "—-emdash", "hidedocument"].forEach((command) => {
     96    test(function (t) {
     97      t.add_cleanup(resetState);
     98      let event = null;
     99      invokee.addEventListener("command", (e) => (event = e), { once: true });
    100      invokerbutton.command = command;
    101      invokerbutton.click();
    102      assert_equals(event, null, "event should not have fired");
    103    }, `setting custom command property to ${command} (no dash) did not dispatch an event`);
    104 
    105    test(function (t) {
    106      t.add_cleanup(resetState);
    107      let event = null;
    108      invokee.addEventListener("command", (e) => (event = e), { once: true });
    109      invokerbutton.setAttribute("command", command);
    110      invokerbutton.click();
    111      assert_equals(event, null, "event should not have fired");
    112    }, `setting custom command attribute to ${command} (no dash) did not dispatch an event`);
    113  });
    114 
    115  test(function (t) {
    116    let called = false;
    117    invokerbutton.addEventListener(
    118      "click",
    119      (event) => {
    120        event.preventDefault();
    121      },
    122      { once: true },
    123    );
    124    invokee.addEventListener(
    125      "command",
    126      (event) => {
    127        called = true;
    128      },
    129      { once: true },
    130    );
    131    invokerbutton.click();
    132    assert_false(called, "event was not called");
    133  }, "event does not dispatch if click:preventDefault is called");
    134 
    135  test(function (t) {
    136    let event = null;
    137    invokee.addEventListener("command", (e) => (event = e), { once: true });
    138    invalidbutton.click();
    139    assert_equals(event, null, "command should not have fired");
    140  }, "event does not dispatch on input[type=button]");
    141 
    142  test(function (t) {
    143    t.add_cleanup(resetState);
    144    let called = false;
    145    invokee.addEventListener("command", (e) => (called = true), { once: true });
    146    invokerbutton.setAttribute("disabled", "");
    147    invokerbutton.click();
    148    assert_false(called, "event was not called");
    149  }, "event does not dispatch if invoker is disabled");
    150 
    151  test(function (t) {
    152    t.add_cleanup(resetState);
    153    let called = false;
    154    invokee.addEventListener("command", (e) => (called = true), { once: true });
    155    invokerbutton.setAttribute("form", "aform");
    156    invokerbutton.removeAttribute("type");
    157    invokerbutton.click();
    158    assert_false(called, "event was not called");
    159  }, "event does NOT dispatch if button is form associated, with implicit type");
    160 
    161  test(function (t) {
    162    t.add_cleanup(resetState);
    163    let called = false;
    164    invokee.addEventListener("command", (e) => (called = true), { once: true });
    165    invokerbutton.setAttribute("form", "aform");
    166    invokerbutton.setAttribute("type", "invalid");
    167    invokerbutton.click();
    168    assert_false(called, "event was not called");
    169  }, "event does NOT dispatch if button is form associated, with explicit type=invalid");
    170 
    171  test(function (t) {
    172    t.add_cleanup(resetState);
    173    let event;
    174    invokee.addEventListener("command", (e) => (event = e), { once: true });
    175    invokerbutton.setAttribute("form", "aform");
    176    invokerbutton.setAttribute("type", "button");
    177    invokerbutton.click();
    178    assert_true(event instanceof CommandEvent, "event is CommandEvent");
    179    assert_equals(event.type, "command", "type");
    180    assert_equals(event.bubbles, false, "bubbles");
    181    assert_equals(event.composed, false, "composed");
    182    assert_equals(event.isTrusted, true, "isTrusted");
    183    assert_equals(event.command, "--custom-command", "command");
    184    assert_equals(event.target, invokee, "target");
    185    assert_equals(event.source, invokerbutton, "source");
    186  }, "event dispatches if button is form associated, with explicit type=button");
    187 
    188  test(function (t) {
    189    t.add_cleanup(resetState);
    190    let called = false;
    191    invokee.addEventListener("command", (e) => (called = true), { once: true });
    192    invokerbutton.setAttribute("form", "aform");
    193    invokerbutton.setAttribute("type", "submit");
    194    invokerbutton.click();
    195    assert_false(called, "event was not called");
    196  }, "event does NOT dispatch if button is form associated, with explicit type=submit");
    197 
    198  test(function (t) {
    199    t.add_cleanup(resetState);
    200    let called = false;
    201    invokee.addEventListener("command", (e) => (called = true), { once: true });
    202    invokerbutton.setAttribute("form", "aform");
    203    invokerbutton.setAttribute("type", "reset");
    204    invokerbutton.click();
    205    assert_false(called, "event was called");
    206  }, "event does NOT dispatch if button is form associated, with explicit type=reset");
    207 
    208  test(function (t) {
    209    svgInvokee = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    210    svgInvokee.setAttribute("id", "svg-invokee");
    211    t.add_cleanup(resetState);
    212    document.body.append(svgInvokee);
    213    assert_false(svgInvokee instanceof HTMLElement);
    214    assert_true(svgInvokee instanceof Element);
    215    let event = null;
    216    svgInvokee.addEventListener("command", (e) => (event = e), { once: true });
    217    invokerbutton.setAttribute("commandfor", "svg-invokee");
    218    invokerbutton.setAttribute("command", "--custom-command");
    219    assert_equals(invokerbutton.commandForElement, svgInvokee);
    220    invokerbutton.click();
    221    assert_not_equals(event, null, "event was called");
    222    assert_true(event instanceof CommandEvent, "event is CommandEvent");
    223    assert_equals(event.source, invokerbutton, "event.invoker is set to right element");
    224    assert_equals(event.target, svgInvokee, "event.target is set to right element");
    225  }, "event dispatches if invokee is non-HTML Element");
    226 </script>