tor-browser

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

slotchange-events.html (5264B)


      1 <!DOCTYPE html>
      2 <title>slotchanged event</title>
      3 <script src="/resources/testharness.js"></script>
      4 <script src="/resources/testharnessreport.js"></script>
      5 <body>
      6 
      7 <script>
      8 customElements.define(
      9  "custom-element",
     10  class extends HTMLElement {
     11    constructor() {
     12      super();
     13      const shadowRoot = this.attachShadow({mode: "open"});
     14      const slot = document.createElement('slot');
     15      slot.name = 'content';
     16      shadowRoot.append(slot);
     17    }
     18  },
     19 );
     20 
     21 promise_test(async t => {
     22  const customElement = document.body.appendChild(document.createElement('custom-element'));
     23  t.add_cleanup(() => customElement.remove());
     24 
     25  const slot = customElement.shadowRoot.children[0];
     26  const slotChangePromise = new Promise((resolve, reject) => {
     27    slot.addEventListener('slotchange', e => resolve(), {once: true});
     28    t.step_timeout(() => reject('Timeout; slotchange was not fired'), 1500);
     29  });
     30 
     31  const defaultContentP = customElement.shadowRoot.appendChild(document.createElement('p'));
     32  slot.moveBefore(defaultContentP, null);
     33  await slotChangePromise;
     34 }, "Moving default content into a slot fires 'slotchange' event");
     35 
     36 promise_test(async t => {
     37  const customElement = document.body.appendChild(document.createElement('custom-element'));
     38  t.add_cleanup(() => customElement.remove());
     39 
     40  const slot = customElement.shadowRoot.children[0];
     41  const defaultContentP = slot.appendChild(document.createElement('p'));
     42 
     43  // Wait for "signal a slot change" to asynchronously settle. This should fire
     44  // the 'slotchange' event for the insertion above, but we will not assert that,
     45  // since this test is only testing that 'slotchange' is fired on removal. We
     46  // separate this out in case an implementation fires one but not the other
     47  // (i.e., Chromium, at the time of writing this).
     48  await new Promise(resolve => t.step_timeout(() => resolve()));
     49 
     50  const slotChangePromise = new Promise((resolve, reject) => {
     51    slot.addEventListener('slotchange', e => resolve(), {once: true});
     52    t.step_timeout(() => reject('Timeout; slotchange was not fired'), 1500);
     53  });
     54 
     55  // Move `defaultContentP` OUT of the slot, and into the ShadowRoot. This
     56  // triggers "signal a slot change" on `defaultContentP`'s old parent, which is
     57  // the slot.
     58  customElement.shadowRoot.moveBefore(defaultContentP, null);
     59  await slotChangePromise;
     60 }, "Moving default content out of a slot fires 'slotchange' event");
     61 
     62 promise_test(async t => {
     63  const customElement = document.body.appendChild(document.createElement('custom-element'));
     64  t.add_cleanup(() => customElement.remove());
     65 
     66  const slot = customElement.shadowRoot.children[0];
     67  const slottable = document.body.appendChild(document.createElement('p'));
     68  slottable.slot = 'content';
     69 
     70  {
     71    const slotChangePromise = new Promise((resolve, reject) => {
     72      slot.addEventListener('slotchange', e => {
     73        if (slot.assignedNodes().includes(slottable)) {
     74          resolve();
     75        } else {
     76          reject('slot.assignedNodes() did not include the slottable after move');
     77        }
     78      }, {once: true});
     79 
     80      t.step_timeout(() => reject('Timeout; slotchange (whiling moving an element in) was not fired'), 1500);
     81    });
     82 
     83    // Move the slottable INTO the custom element, thus slotting it.
     84    customElement.moveBefore(slottable, null);
     85    await slotChangePromise;
     86  }
     87 
     88  {
     89    const slotChangePromise = new Promise((resolve, reject) => {
     90      slot.addEventListener('slotchange', e => {
     91        if (slot.assignedNodes().length === 0) {
     92          resolve();
     93        } else {
     94          reject('slot.assignedNodes() not empty after the slottable moved out');
     95        }
     96      }, {once: true});
     97 
     98      t.step_timeout(() => reject('Timeout; slotchange (whiling moving an element out) was not fired'), 1500);
     99    });
    100 
    101    // Move the slottable OUT of the custom element, thus unslotting it.
    102    document.body.moveBefore(slottable, null);
    103    await slotChangePromise;
    104  }
    105 }, "Moving a slottable into and out out of a custom element fires 'slotchange' event");
    106 
    107 promise_test(async t => {
    108  const customElement = document.body.appendChild(document.createElement('custom-element'));
    109  const slot = customElement.shadowRoot.children[0];
    110  t.add_cleanup(() => customElement.remove());
    111 
    112  const p = document.createElement('p');
    113  p.slot = 'content';
    114  p.textContent = 'The content';
    115  customElement.appendChild(p);
    116 
    117  // See the above tests that do the same thing, for implementations that do not fire `slotchange`
    118  // at this phase.
    119  await new Promise(resolve => t.step_timeout(() => resolve()));
    120 
    121  assert_array_equals(slot.assignedNodes(), [p]);
    122  document.body.moveBefore(slot, null);
    123 
    124  await new Promise((resolve, reject) => {
    125    slot.addEventListener('slotchange', e => resolve(), {once: true});
    126    t.step_timeout(() => reject('Timeout; slotchange was not fired2'), 1500);
    127  });
    128 
    129  assert_array_equals(slot.assignedNodes(), []);
    130  customElement.shadowRoot.moveBefore(slot, null);
    131 
    132  await new Promise((resolve, reject) => {
    133    slot.addEventListener('slotchange', e => resolve(), {once: true});
    134    t.step_timeout(() => reject('Timeout; slotchange was not fired3'), 1500);
    135  });
    136 
    137  assert_array_equals(slot.assignedNodes(), [p]);
    138 }, "Moving a slot runs the assign slottables algorithm");
    139 </script>