tor-browser

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

popover-top-layer-combinations.html (6530B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <title>Popover combined with dialog/fullscreen behavior</title>
      4 <link rel=author href="mailto:masonf@chromium.org">
      5 <link rel=help href="https://open-ui.org/components/popover.research.explainer">
      6 <link rel=help href="https://html.spec.whatwg.org/multipage/popover.html">
      7 <script src="/resources/testharness.js"></script>
      8 <script src="/resources/testharnessreport.js"></script>
      9 <script src="/resources/testdriver.js"></script>
     10 <script src="/resources/testdriver-actions.js"></script>
     11 <script src="/resources/testdriver-vendor.js"></script>
     12 <script src="/common/top-layer.js"></script>
     13 <script src="resources/popover-utils.js"></script>
     14 
     15 <button id=visible>Visible button</button>
     16 <div id=examples>
     17  <dialog popover>Popover Dialog</dialog>
     18  <dialog popover open style="top:50px;">Open Non-modal Popover Dialog</dialog>
     19  <div    popover class=fullscreen>Fullscreen Popover</div>
     20  <dialog popover class=fullscreen>Fullscreen Popover Dialog</dialog>
     21  <dialog popover open class=fullscreen style="top:200px;">Fullscreen Open Non-modal Popover Dialog</dialog>
     22 </div>
     23 
     24 <style>
     25  [popover] {
     26    inset:auto;
     27    top:0;
     28    left:0;
     29  }
     30  [popover].fullscreen.visible {
     31    display:block;
     32  }
     33 </style>
     34 
     35 <script>
     36 const isDialog = (ex) => ex instanceof HTMLDialogElement;
     37 const isFullscreen = (ex) => ex.classList.contains('fullscreen');
     38 function ensureIsOpenPopover(ex,message) {
     39  // Because :popover-open will eventually support <dialog>, this does extra work to
     40  // verify we're dealing with an :popover-open Popover. Note that this will also throw
     41  // if this is an element with the `popover` attribute that has been made
     42  // visible via an explicit `display:block` style rule.
     43  message = message || 'Error';
     44  assert_true(ex.matches(':popover-open'),`${message}: Popover doesn\'t match :popover-open`);
     45  ex.hidePopover(); // Shouldn't throw if this is a showing popover
     46  ex.showPopover(); // Show it again to avoid state change
     47  assert_true(ex.matches(':popover-open'),`${message}: Sanity`);
     48 }
     49 window.onload = () => requestAnimationFrame(() => requestAnimationFrame(() => {
     50  const examples = Array.from(document.querySelectorAll('#examples>*'));
     51  examples.forEach(ex => {
     52    promise_test(async (t) => {
     53      t.add_cleanup(() => ex.remove());
     54      // Test initial conditions
     55      if (ex.hasAttribute('open')) {
     56        assert_true(isDialog(ex));
     57        assert_true(isElementVisible(ex),'Open dialog should be visible by default');
     58        ex.showPopover(); // Should not throw
     59        ex.removeAttribute('open');
     60        ex.hidePopover();
     61        assert_false(isElementVisible(ex),'Removing the open attribute should hide the dialog');
     62      } else {
     63        ex.showPopover(); // Should not throw
     64        ensureIsOpenPopover(ex,'showPopover should work');
     65        ex.hidePopover(); // Should not throw
     66        assert_false(ex.matches(':popover-open'),'hidePopover should work');
     67      }
     68      assert_false(isElementVisible(ex));
     69 
     70      // Start with popover, try the other API
     71      ex.showPopover();
     72      ensureIsOpenPopover(ex);
     73      let tested_something=false;
     74      if (isDialog(ex)) {
     75        tested_something=true;
     76        assert_throws_dom("InvalidStateError",() => ex.showModal(),'Calling showModal() on an already-showing Popover should throw InvalidStateError');
     77        ex.show(); // Should not throw
     78        ex.close();
     79        ex.showPopover();
     80      }
     81      if (isFullscreen(ex)) {
     82        tested_something=true;
     83        let requestSucceeded = false;
     84        await blessTopLayer(ex);
     85        await ex.requestFullscreen()
     86          .then(() => {requestSucceeded = true;}) // We should not hit this.
     87          .catch((exception) => {
     88            // This exception is expected.
     89            assert_equals(exception.name,'TypeError',`Invalid exception from requestFullscreen() (${exception.message})`);
     90          });
     91        assert_false(requestSucceeded,'requestFullscreen() should not succeed when the element is an already-showing Popover');
     92      }
     93      assert_true(tested_something);
     94      ensureIsOpenPopover(ex);
     95      ex.hidePopover();
     96 
     97      // Start with the other API, then try popover
     98      if (isDialog(ex)) {
     99        ex.show();
    100        assert_true(ex.hasAttribute('open'));
    101        ex.showPopover(); // Should not throw
    102        ex.close();
    103        assert_false(ex.hasAttribute('open'));
    104        ex.hidePopover();
    105        ex.showModal();
    106        assert_true(ex.hasAttribute('open'));
    107        assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-showing modal dialog should throw InvalidStateError');
    108        ex.close();
    109        assert_false(ex.hasAttribute('open'));
    110        ex.hidePopover();
    111      } else if (isFullscreen(ex)) {
    112        let requestSucceeded = false;
    113        await blessTopLayer(visible);
    114        await ex.requestFullscreen()
    115          .then(() => {
    116            assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-fullscreen element should throw InvalidStateError');
    117          });
    118        await document.exitFullscreen()
    119        .then(() => assert_true(true));
    120      }
    121 
    122      // Finally, try invoking these combined popovers via a declarative invoker
    123      const button = document.createElement('button');
    124      t.add_cleanup(() => button.remove());
    125      document.body.appendChild(button);
    126      button.popoverTargetElement = ex;
    127      button.popoverTargetAction = "toggle";
    128      assert_false(ex.matches(':popover-open'));
    129      await clickOn(button);
    130      ensureIsOpenPopover(ex,'Invoking element should be able to invoke all popovers');
    131      ex.hidePopover();
    132      if (isDialog(ex)) {
    133        ex.showModal();
    134        assert_true(ex.hasAttribute('open'));
    135      } else if (isFullscreen(ex)) {
    136        // Popover fullscreen isn't visible by default, so explicitly add
    137        // display:block, so that calls to "clickOn" can succeed.
    138        ex.classList.add('visible');
    139        await blessTopLayer(ex);
    140        await ex.requestFullscreen();
    141      } else {
    142        assert_unreached('Not a dialog or fullscreen');
    143      }
    144      ex.appendChild(button); // Add button to the element, so it's visible to click
    145      await clickOn(button);
    146      assert_false(ex.matches(':popover-open'),'The invoker click should have failed on the already-open dialog/fullscreen');
    147      if (isDialog(ex)) {
    148        ex.close();
    149      } else {
    150        await document.exitFullscreen()
    151      }
    152    }, `Popover combination: ${ex.textContent}`);
    153  });
    154 }));
    155 </script>