Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/content/tests/widgets/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 44 kB image not shown  

Quelle  test_moz_box_group.html

  Sprache: HTML
 

 products/Sources/formale Sprachen/C/Firefox/toolkit/content/tests/widgets/test_moz_box_group.html


<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>MozBoxGroup Tests</title>
    <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
    <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
    <script
      type="module"
      src="chrome://browser/content/preferences/widgets/setting-control.mjs"
    ></script>
    <link
      rel="stylesheet"
      href="chrome://mochikit/content/tests/SimpleTest/test.css"
    />
    <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
    <script
      type="module"
      src="chrome://global/content/elements/moz-box-group.mjs"
    ></script>
    <script src="lit-test-helpers.js"></script>
    <script>
      let html;
      let MozLitElement;
      let testHelpers = new LitTestHelpers();

      async function keyboardNavigate(direction, boxGroup) {
        let keyCode = `KEY_Arrow${
          direction.charAt(0).toUpperCase() + direction.slice(1)
        }`;
        synthesizeKey(keyCode);
        await boxGroup.updateComplete;
      }

      add_setup(async function setup() {
        ({ html } = await testHelpers.setupLit());
        ({ MozLitElement } =
          await import("chrome://global/content/lit-utils.mjs"));
        let templateFn = () => html`
          <moz-box-group>
            <moz-box-item label="item"></moz-box-item>
            <moz-box-button label="button"></moz-box-button>
          </moz-box-group>
        `;
        testHelpers.setupTests({ templateFn });
      });

      add_task(async function testMozBoxGroupStyles() {
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate();
        let [boxItem, boxButton] = boxGroup.shadowRoot
          .querySelector("slot:not([name])")
          .assignedElements();

        const normalizePx = pxVal => Math.round(parseFloat(pxVal));

        function verifyStyles(el, expectedStyles) {
          let styles = getComputedStyle(el);
          Object.entries(expectedStyles).forEach(([property, value]) => {
            is(
              normalizePx(styles[property]),
              normalizePx(value),
              `${property} is ${value}.`
            );
          });
        }

        const FIRST_ITEM_STYLES = {
          borderStartEndRadius: "7px",
          borderStartStartRadius: "7px",
          borderEndEndRadius: "0px",
          borderEndStartRadius: "0px",
          borderTopWidth: "0px",
        };

        const MIDDLE_ITEM_STYLES = {
          borderStartEndRadius: "0px",
          borderStartStartRadius: "0px",
          borderEndEndRadius: "0px",
          borderEndStartRadius: "0px",
          borderTopWidth: "1px",
        };

        const LAST_ITEM_STYLES = {
          borderStartEndRadius: "0px",
          borderStartStartRadius: "0px",
          borderEndEndRadius: "7px",
          borderEndStartRadius: "7px",
          borderTopWidth: "1px",
        };

        // Verify that two items use the first and last item styles.
        verifyStyles(boxItem, FIRST_ITEM_STYLES);
        verifyStyles(boxButton, LAST_ITEM_STYLES);

        // Change the last item and check that styles change accordingly.
        let slotChanged = BrowserTestUtils.waitForEvent(
          boxGroup.shadowRoot,
          "slotchange"
        );
        let secondButton = document.createElement("moz-box-button");
        secondButton.label = "second button";
        boxGroup.append(secondButton);
        await slotChanged;

        verifyStyles(boxItem, FIRST_ITEM_STYLES);
        verifyStyles(boxButton, MIDDLE_ITEM_STYLES);
        verifyStyles(secondButton, LAST_ITEM_STYLES);

        // Change the first item and verify that styles change accordingly.
        slotChanged = BrowserTestUtils.waitForEvent(
          boxGroup.shadowRoot,
          "slotchange"
        );
        let secondItem = document.createElement("moz-box-item");
        secondButton.label = "second item";
        boxGroup.prepend(secondItem);
        await slotChanged;

        verifyStyles(secondItem, FIRST_ITEM_STYLES);
        verifyStyles(boxItem, MIDDLE_ITEM_STYLES);
        verifyStyles(boxButton, MIDDLE_ITEM_STYLES);
        verifyStyles(secondButton, LAST_ITEM_STYLES);

        // Verify that hiding items doesn't break the box-group styles.
        secondItem.hidden = true;
        await TestUtils.waitForTick();

        verifyStyles(boxItem, FIRST_ITEM_STYLES);
        verifyStyles(boxButton, MIDDLE_ITEM_STYLES);
        verifyStyles(secondButton, LAST_ITEM_STYLES);
      });

      add_task(async function testMozBoxGroupList() {
        let listTemplate = html`<moz-box-group type="list">
          <moz-box-item label="header" slot="header"></moz-box-item>
          <moz-box-item label="item"></moz-box-item>
          <moz-box-item label="item 2"></moz-box-item>
          <moz-box-item label="item 3"></moz-box-item>
          <moz-box-button label="button"></moz-box-button>
          <moz-box-item label="footer" slot="footer"></moz-box-item>
        </moz-box-group>`;
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate(listTemplate);
        let boxEls = boxGroup.querySelectorAll("moz-box-item, moz-box-button");
        const getListItems = () => boxGroup.shadowRoot.querySelectorAll("li");

        let list = boxGroup.shadowRoot.querySelector("ul");
        ok(list, "Box group renders items in a list element.");
        is(
          list.ariaOrientation,
          "vertical",
          "aria-orientation is set on the list element."
        );
        ok(
          !list.hasAttribute("role"),
          "List has no role override (uses implicit list semantics)."
        );

        let listItems = getListItems();
        is(
          listItems.length,
          4,
          "Box group renders an li for each slotted moz-box-* element."
        );
        listItems.forEach(li => {
          ok(!li.hasAttribute("role"), "li keeps implicit listitem semantics.");
        });
        boxGroup.listItems.forEach(item => {
          ok(!item.hasAttribute("role"), "moz-box-item has no role override.");
        });

        let [listHeader] = boxGroup.shadowRoot
          .querySelector('slot[name="header"]')
          .assignedElements();
        is(listHeader, boxEls[0], "List header is the first box element");

        let [listFooter] = boxGroup.shadowRoot
          .querySelector('slot[name="footer"]')
          .assignedElements();
        is(
          listFooter,
          boxEls[boxEls.length - 1],
          "List footer is the last box element"
        );

        listItems.forEach((item, i) => {
          let element = item.querySelector("slot").assignedElements()[0];
          is(
            element,
            boxGroup.listItems[i],
            "Each moz-box-* element is wrapped in an li."
          );
        });

        let slotChanged = BrowserTestUtils.waitForEvent(
          boxGroup.shadowRoot,
          "slotchange"
        );
        let newItem = document.createElement("moz-box-item");
        newItem.label = "create another item.";
        boxGroup.append(newItem);
        await slotChanged;

        listItems = getListItems();
        is(
          listItems.length,
          5,
          "Box group renders an additional li for the newly slotted element."
        );
        let lastElement = listItems[listItems.length - 1]
          .querySelector("slot")
          .assignedElements()[0];
        is(
          lastElement,
          newItem,
          "The new item is slotted in the last li element."
        );
      });

      add_task(async function testMozBoxGroupKeyboardInteraction() {
        let keyboardTemplate = html`<moz-button tabindex="0">
            Focus me!
          </moz-button>
          <moz-box-group>
            <moz-box-item label="header" slot="header"></moz-box-item>
            <moz-box-item label="item">
              <moz-button
                class="first-button"
                slot="actions-start"
                iconsrc="chrome://global/skin/icons/more.svg"
              ></moz-button>
              <moz-toggle slot="actions"></moz-toggle>
              <moz-button
                class="disabled-button"
                slot="actions"
                disabled
                iconsrc="chrome://global/skin/icons/more.svg"
              ></moz-button>
              <img src="chrome://global/skin/icons/more.svg" slot="actions" />
              <moz-button
                class="second-button"
                slot="actions"
                iconsrc="chrome://global/skin/icons/more.svg"
              ></moz-button>
            </moz-box-item>
            <moz-box-link label="link"></moz-box-link>
            <moz-box-button label="button"></moz-box-button>
            <moz-box-button label="footer" slot="footer"></moz-box-button>
          </moz-box-group>
          <moz-button tabindex="0">Focus me too!</moz-button>`;
        let {
          children: [beforeButton, boxGroup, afterButton],
        } = await testHelpers.renderTemplate(keyboardTemplate);
        let [, boxItem, boxLink, boxButton, footerButton] =
          boxGroup.querySelectorAll(
            "moz-box-item, moz-box-button, moz-box-link"
          );

        isnot(document.activeElement, boxGroup, "Box group is not focused.");
        beforeButton.focus();

        // Verify tab can be used to move through elements in a regular moz-box-group.
        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxItem.querySelector(".first-button"),
          "Focus moves to the first button action element in moz-box-item."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus moves to the toggle action element in moz-box-item."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxItem.querySelector(".second-button"),
          "Focus moves to the second button action element in the moz-box-item."
        );

        await keyboardNavigate("left", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus moves to the toggle action element in moz-box-item."
        );

        await keyboardNavigate("left", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector(".first-button"),
          "Focus moves to the first button action element in moz-box-item."
        );

        await keyboardNavigate("right", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus moves to the toggle action element in the moz-box-item."
        );

        await keyboardNavigate("right", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector(".second-button"),
          "Focus skips disabled button and image and moves to the second button action element in the moz-box-item."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxLink,
          "Focus moves to the moz-box-link element."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxButton,
          "Focus moves to the moz-box-button element."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          footerButton,
          "Focus moves to the footer moz-box-button element."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          afterButton,
          "Focus moves out of the group after hitting tab."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          footerButton,
          "Focus moves back to the moz-box-button element."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxButton,
          "Focus moves back to the moz-box-button element."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxLink,
          "Focus moves back to the moz-box-link element."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxItem.querySelector(".second-button"),
          "Focus moves back to the second button action element in the moz-box-item."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus skips disabled button and image and moves back to the toggle action element in the moz-box-item."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxItem.querySelector(".first-button"),
          "Focus moves back to the first button action element in the moz-box-item."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          beforeButton,
          "Focus moves out of the group."
        );

        // Verify tab and arrow key behavior in moz-box-group of type="list".
        boxGroup.type = "list";
        await boxGroup.updateComplete;
        await Promise.all(boxGroup.listItems.map(item => item.updateComplete));

        // Tab from outside lands on the moz-box-item row.
        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxItem,
          "Focus moves to the moz-box-item row."
        );

        // Tab from the row enters its actions, then steps through them.
        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxItem.querySelector(".first-button"),
          "Focus moves to the first button action element in moz-box-item."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus moves to the toggle action element in moz-box-item."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxItem.querySelector(".second-button"),
          "Focus moves to the second button action element in the moz-box-item."
        );

        await keyboardNavigate("left", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus moves to the toggle action element in moz-box-item."
        );

        await keyboardNavigate("left", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector(".first-button"),
          "Focus moves to the first button action element in moz-box-item."
        );

        await keyboardNavigate("right", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus moves to the toggle action element in moz-box-item."
        );

        await keyboardNavigate("right", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector(".second-button"),
          "Focus skips disabled button and image and moves to the second button action element in the moz-box-item."
        );

        // Shift+Tab from an action steps back through actions, then to the row.
        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Shift+Tab from an action goes to the previous action."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxItem.querySelector(".first-button"),
          "Shift+Tab continues to the first action."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxItem,
          "Shift+Tab from the first action returns to the row."
        );

        // Arrow Down/Up navigate between rows.
        await keyboardNavigate("down", boxGroup);
        is(
          document.activeElement,
          boxLink,
          "Focus moves to the moz-box-link element."
        );

        await keyboardNavigate("down", boxGroup);
        is(
          document.activeElement,
          boxButton,
          "Focus moves to the moz-box-button element."
        );

        await keyboardNavigate("down", boxGroup);
        is(
          document.activeElement,
          boxButton,
          "Down arrow key does not move focus out of the group from the last item."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          footerButton,
          "Focus moves to the footer button."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          afterButton,
          "Focus moves out of the group."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          footerButton,
          "Focus moves to the last element in the group."
        );

        await keyboardNavigate("up", boxGroup);
        is(
          document.activeElement,
          footerButton,
          "Focus stays on the last element in the group."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxButton,
          "Focus moves to the last element in the list."
        );

        await keyboardNavigate("up", boxGroup);
        is(
          document.activeElement,
          boxLink,
          "Focus moves to the moz-box-link element."
        );

        await keyboardNavigate("up", boxGroup);
        is(
          document.activeElement,
          boxItem,
          "Arrow up returns to the moz-box-item row."
        );

        await keyboardNavigate("up", boxGroup);
        is(
          document.activeElement,
          boxItem,
          "Up arrow key does not move focus out of the group from the first item."
        );

        // Tab forward exits the group via the footer; non-focused rows are
        // taken out of tab order while focus is inside the group.
        synthesizeKey("KEY_Tab", {}); // → .first-button
        synthesizeKey("KEY_Tab", {}); // → moz-toggle
        synthesizeKey("KEY_Tab", {}); // → .second-button
        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          footerButton,
          "Other list items are not tabbable, so focus moves to the footer button."
        );

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          afterButton,
          "Focus moves out of the group."
        );

        // Shift+Tab from outside walks back through the footer and last row
        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          footerButton,
          "Focus moves to the last element in the group."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          boxButton,
          "Focus moves to the last element in the list."
        );

        synthesizeKey("KEY_Tab", { shiftKey: true });
        is(
          document.activeElement,
          beforeButton,
          "Focus moves out of the group"
        );

        // Validate left/right keyboard navigation between action items for RTL.
        await SpecialPowers.pushPrefEnv({
          set: [["intl.l10n.pseudo""bidi"]],
        });

        synthesizeKey("KEY_Tab", {}); // → moz-box-item
        synthesizeKey("KEY_Tab", {}); // → .first-button
        synthesizeKey("KEY_Tab", {}); // → moz-toggle

        synthesizeKey("KEY_Tab", {});
        is(
          document.activeElement,
          boxItem.querySelector(".second-button"),
          "Focus lands on the last action of the moz-box-item."
        );
        await keyboardNavigate("right", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus skips disabled button and image and moves to the toggle action element in the moz-box-item."
        );

        await keyboardNavigate("right", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector(".first-button"),
          "Focus moves to the first button action element in the moz-box-item."
        );

        await keyboardNavigate("left", boxGroup);
        is(
          document.activeElement,
          boxItem.querySelector("moz-toggle"),
          "Focus skips disabled button and image and moves to the toggle action element in the moz-box-item."
        );

        await SpecialPowers.popPrefEnv();
      });

      add_task(async function testMozBoxGroupKeydownOnWhitespace() {
        // Test bug 2001746 - ignore keypresses that fire on the ul if whitespace
        // was clicked in moz-box-group
        let listTemplate = html`<moz-box-group type="list">
          <moz-box-item label="item 1"></moz-box-item>
          <moz-box-item label="item 2"></moz-box-item>
          <moz-box-item label="item 3"></moz-box-item>
        </moz-box-group>`;
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate(listTemplate);

        let list = boxGroup.shadowRoot.querySelector("ul");
        ok(list, "Box group has a list element.");

        // Simulate clicking on the list container (whitespace) by focusing it
        list.focus();
        is(
          boxGroup.shadowRoot.activeElement,
          list,
          "The list container can be focused."
        );
        is(
          document.activeElement,
          boxGroup,
          "The moz-box-group is the activeElement."
        );

        // Press arrow keys - this should not throw an error
        let errorThrown = false;
        try {
          synthesizeKey("KEY_ArrowDown");
          await boxGroup.updateComplete;
          synthesizeKey("KEY_ArrowUp");
          await boxGroup.updateComplete;
        } catch (e) {
          errorThrown = true;
          ok(false, `Unexpected error: ${e.message}`);
        }

        ok(
          !errorThrown,
          "No error thrown when pressing keys on whitespace in moz-box-group."
        );
        is(
          document.activeElement,
          boxGroup,
          "Focus did not move after arrow key press."
        );
      });

      add_task(async function testMozBoxGroupReorderable() {
        class TestReorderable extends MozLitElement {
          static properties = { items: { type: Array } };
          constructor() {
            super();
            this.items = [
              html`<moz-box-item label="item 1"></moz-box-item>`,
              html`<moz-box-item label="item 2"></moz-box-item>`,
              html`<moz-box-item label="item 3"></moz-box-item>`,
              html`<moz-box-item label="footer" slot="footer"></moz-box-item>`,
            ];
          }
          render() {
            return html`<moz-box-group
              @reorder=${this.onReorder}
              type="reorderable-list"
            >
              ${this.items}
            </moz-box-group>`;
          }

          onReorder(event) {
            const { draggedIndex, targetIndex } = event.detail;
            const [draggedItem] = this.items.splice(draggedIndex, 1);
            this.items.splice(targetIndex, 0, draggedItem);
            this.requestUpdate();
          }
        }
        customElements.define("test-reorderable", TestReorderable);
        let reorderableTemplate = html`<test-reorderable></test-reorderable>`;
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate(reorderableTemplate);
        let reorderableWrapper = boxGroup;
        boxGroup = boxGroup.shadowRoot.querySelector("moz-box-group");

        /**
          Since the DOM nodes are destroyed and recreated, we need to
          get fresh references to the newly created elements. Otherwise,
          we will send a keydown event to an element that is no longer in
          the DOM tree. This will cause the test to timeout.
        */
        function getNewRefs() {
          let item1 = boxGroup.querySelector("[label='item 1']");
          let item2 = boxGroup.querySelector("[label='item 2']");
          let item3 = boxGroup.querySelector("[label='item 3']");
          let footer = boxGroup.querySelector("[label='footer']");
          return [item1, item2, item3, footer];
        }

        let [item1, item2, item3, footer] = getNewRefs();

        async function moveItem(item, direction) {
          if (!item.isDraggable) {
            return;
          }
          let keydown = BrowserTestUtils.waitForEvent(item, "keydown");
          item.focus();
          synthesizeKey(
            `KEY_Arrow${direction.charAt(0).toUpperCase() + direction.slice(1)}`,
            { shiftKey: true, ctrlKey: true }
          );
          await keydown;
          await boxGroup.updateComplete;
        }

        ok(
          boxGroup.reorderableList,
          "Box group renders a moz-reorderable-list."
        );

        let list = boxGroup.shadowRoot.querySelector("ol");
        is(
          list.getAttribute("role"),
          "listbox",
          "Reorderable list has role=listbox."
        );
        boxGroup.shadowRoot.querySelectorAll("li").forEach(li => {
          is(
            li.getAttribute("role"),
            "presentation",
            "Reorderable list li has role=presentation."
          );
        });
        [item1, item2, item3].forEach(item => {
          is(
            item.getAttribute("role"),
            "option",
            `${item.label} has role=option.`
          );
        });
        is(
          footer.getAttribute("role"),
          null,
          "Footer item has no role=option."
        );

        is(
          item1.handleEl.getAttribute("data-l10n-id"),
          "moz-box-item-reorder-handle-named",
          "Handle uses the named l10n-id when the item has a label."
        );
        is(
          item1.handleEl.getAttribute("data-l10n-args"),
          JSON.stringify({ item: item1.label }),
          "Handle passes the item label via data-l10n-args."
        );

        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(2)").label,
          item2.label,
          "item2 starts in the second position."
        );
        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(3)").label,
          item3.label,
          "item3 starts after item2 in the third position."
        );

        /*
          Ensure the moz-box-items get the REORDER_PROP so that the
          reorder event fires as expected.
        **/
        boxGroup.reorderableList.getItems();
        let reordered = BrowserTestUtils.waitForEvent(boxGroup, "reorder");
        await moveItem(item3, "up");
        await reordered;
        await reorderableWrapper.updateComplete;

        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(2)").label,
          item3.label,
          "item3 has been reordered to the second position."
        );
        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(3)").label,
          item2.label,
          "item2 has been reordered to the third position."
        );

        reordered = BrowserTestUtils.waitForEvent(boxGroup, "reorder");
        await moveItem(item1, "down");
        await reordered;
        await reorderableWrapper.updateComplete;

        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(1)").label,
          item3.label,
          "item3 has been reordered to the first position."
        );
        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(2)").label,
          item1.label,
          "item1 has been reordered to the second position."
        );
        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(3)").label,
          item2.label,
          "item2 is still in the third position."
        );

        /*
          Since item2 was moved when item3 was moved up, item2 no longer
          exists in our DOM. Therefore we need to get a new reference to
          item2 before trying to move it down
        **/
        [item1, item2, item3, footer] = getNewRefs();
        /*
         Item2 is at the bottom of the list, thus trying to move it
         down will never fire a reorder event.
        **/
        await moveItem(item2, "down");
        await reorderableWrapper.updateComplete;

        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(3)").label,
          item2.label,
          "item2 is still in the third position."
        );

        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(4)"),
          footer,
          "footer is in the forth position."
        );

        /*
          The footer element can't be reordered, so no reorder event
          will fire in this case.
        **/
        await moveItem(footer"up");
        await reorderableWrapper.updateComplete;

        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(4)"),
          footer,
          "footer is still in the forth position."
        );
      });

      /*
        Assert that the tabIndex attribute is removed from all list
        items if the length of the list items changes. Otherwise,
        there's a possibility that a user will not be able to keyboard
        navigate back to the list due to the items having tabindex="-1"
      **/
      add_task(async function testWhenListItemsChange() {
        const removeSelf = event => {
          event.target.closest("moz-box-item").remove();
        };
        let listTemplate = html` <moz-button>Focus me!</moz-button>
          <moz-box-group type="list">
            <moz-box-item label="item 1">
              <moz-button slot="actions" label="item 1 action 1"></moz-button>
            </moz-box-item>
            <moz-box-item label="item 2">
              <moz-button slot="actions" label="item 2 action 1"></moz-button>
            </moz-box-item>
            <moz-box-item label="item 3">
              <moz-button
                slot="actions"
                label="item 3 action 1"
                @click=${removeSelf}
              ></moz-button>
            </moz-box-item>
          </moz-box-group>`;
        let {
          children: [beforeButton, boxGroup],
        } = await testHelpers.renderTemplate(listTemplate);

        let list = boxGroup.shadowRoot.querySelector("ul");
        ok(list, "Box group has a list element.");

        // Focus the button outside of the list so we can easily
        // move focus via the Tab key.
        beforeButton.focus();
        await synthesizeKey("KEY_Tab");

        // Move through the list until we reach the item that can be
        // removed.
        await keyboardNavigate("down", boxGroup);
        await keyboardNavigate("down", boxGroup);
        await keyboardNavigate("down", boxGroup);
        is(
          document.activeElement.label,
          "item 3",
          "The last item in the box group should be focused."
        );
        await synthesizeKey("KEY_Tab");
        is(
          document.activeElement.label,
          "item 3 action 1",
          "The last action in the box group should be focused."
        );

        await synthesizeKey("KEY_Enter");

        await boxGroup.updateComplete;
        await Promise.all(boxGroup.listItems.map(item => item.updateComplete));

        // Ensure each remaining list item is restored to the focusable
        // tabindex so the user can tab back into the group.
        boxGroup.listItems.forEach(item => {
          is(
            item.getAttribute("tabindex"),
            "0",
            "List item is restored to tabindex=0 after an item is removed"
          );
        });

        // Ensure that we can tab navigate back to the box group
        beforeButton.focus();
        await synthesizeKey("KEY_Tab");

        ok(
          boxGroup.contains(document.activeElement),
          "Focus should be able to move back into the box group after a list item is removed"
        );
      });

      add_task(async function testMozBoxGroupStaticItems() {
        let staticTemplate = html`<moz-box-group type="reorderable-list">
          <moz-box-item label="item 1"></moz-box-item>
          <moz-box-item label="item 2"></moz-box-item>
          <moz-box-item label="static item 1" slot="static"></moz-box-item>
          <moz-box-item label="static item 2" slot="static"></moz-box-item>
        </moz-box-group>`;
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate(staticTemplate);
        await boxGroup.updateComplete;

        is(boxGroup.listItems.length, 2"Box group has 2 regular items.");
        is(boxGroup.staticItems.length, 2"Box group has 2 static items.");

        boxGroup.staticItems.forEach((item, i) => {
          ok(
            item.hasAttribute("static"),
            `Static item ${i} has static attribute.`
          );
          is(
            item.slot,
            `static-${i}`,
            `Static item ${i} has slot static-${i}.`
          );
          is(
            item.getAttribute("position"),
            String(2 + i),
            `Static item ${i} positioned after regular items.`
          );
          ok(!item.handleEl, `Static item ${i} has no handle element.`);
          is(
            item.getAttribute("role"),
            "option",
            `Static item ${i} has role=option.`
          );
        });
      });

      add_task(async function testMozBoxGroupStaticItemsNotReorderable() {
        class TestStaticReorderable extends MozLitElement {
          static properties = { items: { type: Array } };
          constructor() {
            super();
            this.items = [];
          }
          render() {
            return html`<moz-box-group
              @reorder=${this.onReorder}
              type="reorderable-list"
            >
              ${this.items}
            </moz-box-group>`;
          }

          onReorder(event) {
            const { draggedIndex, targetIndex } = event.detail;
            const regularItems = this.items.filter(
              item => !item.values?.[0]?.slot
            );
            const [draggedItem] = regularItems.splice(draggedIndex, 1);
            regularItems.splice(targetIndex, 0, draggedItem);
            const staticItems = this.items.filter(
              item => item.values?.[0]?.slot === "static"
            );
            this.items = [...regularItems, ...staticItems];
            this.requestUpdate();
          }
        }
        customElements.define("test-static-reorderable", TestStaticReorderable);

        let wrapper = document.createElement("test-static-reorderable");
        wrapper.items = [
          html`<moz-box-item label="item 1"></moz-box-item>`,
          html`<moz-box-item label="item 2"></moz-box-item>`,
          html`<moz-box-item label="static item" slot="static"></moz-box-item>`,
        ];
        document.body.appendChild(wrapper);
        await wrapper.updateComplete;

        let boxGroup = wrapper.shadowRoot.querySelector("moz-box-group");
        await boxGroup.updateComplete;

        let staticItem = boxGroup.querySelector("[label='static item']");
        ok(!staticItem.handleEl, "Static item has no handle element.");
        ok(
          staticItem.hasAttribute("static"),
          "Static item has static attribute."
        );

        // Verify only non-static items are in the reorderable list.
        let item1 = boxGroup.querySelector("[label='item 1']");
        let item2 = boxGroup.querySelector("[label='item 2']");
        ok(item1.handleEl, "Regular item 1 has handle element.");
        ok(item2.handleEl, "Regular item 2 has handle element.");

        boxGroup.reorderableList.getItems();
        item1.focus();
        let reordered = BrowserTestUtils.waitForEvent(boxGroup, "reorder");
        synthesizeKey("KEY_ArrowDown", { shiftKey: true, ctrlKey: true });
        await reordered;
        await wrapper.updateComplete;

        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(2)").label,
          "item 1",
          "Regular items reordered."
        );
        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(3)").label,
          "static item",
          "Static item remains in place after reorder."
        );

        synthesizeKey("KEY_ArrowDown", { shiftKey: true, ctrlKey: true });
        await wrapper.updateComplete;

        is(
          boxGroup.querySelector("moz-box-item:nth-of-type(2)").label,
          "item 1",
          "Regular items not reordered when the next item is static."
        );

        wrapper.remove();
      });

      add_task(async function testMozBoxGroupStaticItemsKeyboardNavigation() {
        let keyboardTemplate = html`<moz-box-group type="list">
          <moz-box-item label="item 1">
            <moz-button slot="actions" label="action 1"></moz-button>
          </moz-box-item>
          <moz-box-item label="item 2">
            <moz-button slot="actions" label="action 2"></moz-button>
          </moz-box-item>
          <moz-box-item label="static item 1" slot="static">
            <moz-button slot="actions" label="static action 1"></moz-button>
          </moz-box-item>
          <moz-box-item label="static item 2" slot="static">
            <moz-button slot="actions" label="static action 2"></moz-button>
          </moz-box-item>
        </moz-box-group>`;
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate(keyboardTemplate);
        await boxGroup.updateComplete;

        let allItems = [...boxGroup.listItems, ...boxGroup.staticItems];
        await Promise.all(allItems.map(item => item.updateComplete));

        // Focus the first row.
        allItems[0].focus();

        // Navigate down through all items.
        for (let i = 1i < allItems.length; i++) {
          await keyboardNavigate("down", boxGroup);
          is(
            document.activeElement,
            allItems[i],
            `Down navigates to item ${i}.`
          );
        }

        // Navigate up through all items.
        for (let i = allItems.length - 2i >= 0i--) {
          await keyboardNavigate("up", boxGroup);
          is(document.activeElement, allItems[i], `Up navigates to item ${i}.`);
        }
      });

      add_task(async function testMozBoxGroupStaticItemsFirstLastStyles() {
        let stylesTemplate = html`<moz-box-group>
          <moz-box-item label="item 1"></moz-box-item>
          <moz-box-item label="item 2"></moz-box-item>
          <moz-box-item label="static item" slot="static"></moz-box-item>
        </moz-box-group>`;
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate(stylesTemplate);
        await boxGroup.updateComplete;

        let [item1, item2] = boxGroup.listItems;
        let [staticItem] = boxGroup.staticItems;

        ok(item1.classList.contains("first"), "First item has 'first' class.");
        ok(!item2.classList.contains("last"), "Middle item no 'last' class.");
        ok(
          staticItem.classList.contains("last"),
          "Static item has 'last' class."
        );
      });

      add_task(async function testMozBoxItemSettingControlKeyboardNavigation() {
        const mockSetting = {
          value: true,
          on() {},
          off() {},
          userChange() {},
          getControlConfig: c => c,
          controllingExtensionInfo: {},
          visible: true,
        };

        const disabledSetting = {
          value: false,
          disabled: true,
          on() {},
          off() {},
          userChange() {},
          getControlConfig: c => c,
          controllingExtensionInfo: {},
          visible: true,
        };

        const settingConfig = {
          id: "test-toggle-setting",
          control: "moz-toggle",
          label"Test Toggle",
        };

        const disabledSettingConfig = {
          id: "test-disabled-setting",
          control: "moz-toggle",
          label"Disabled Toggle",
        };

        let settingControlTemplate = html`<moz-box-group>
          <moz-box-item label="item with setting control">
            <moz-button
              class="first-button"
              slot="actions-start"
              iconsrc="chrome://global/skin/icons/more.svg"
            ></moz-button>
            <setting-control
              slot="actions"
              class="test-setting-control"
              .config=${settingConfig}
              .setting=${mockSetting}
            ></setting-control>
            <setting-control
              slot="actions"
              class="disabled-setting-control"
              .config=${disabledSettingConfig}
              .setting=${disabledSetting}
            ></setting-control>
            <moz-button
              class="second-button"
              slot="actions"
              iconsrc="chrome://global/skin/icons/more.svg"
            ></moz-button>
          </moz-box-item>
        </moz-box-group>`;
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate(settingControlTemplate);
        let boxItem = boxGroup.querySelector("moz-box-item");
        await boxItem.updateComplete;

        let firstButton = boxItem.querySelector(".first-button");
        let settingControl = boxItem.querySelector(".test-setting-control");
        let disabledSettingControl = boxItem.querySelector(
          ".disabled-setting-control"
        );
        let secondButton = boxItem.querySelector(".second-button");

        await settingControl.updateComplete;
        await disabledSettingControl.updateComplete;

        // Get the actual toggle element inside the setting-control
        // Note: setting-control delegates focus to its inner toggle element
        let toggle = settingControl.querySelector("moz-toggle");
        ok(toggle, "Toggle element exists inside setting-control.");

        ok(
          disabledSettingControl.disabled,
          "Disabled setting-control reports disabled."
        );

        firstButton.focus();
        is(
          document.activeElement,
          firstButton,
          "First button is focused initially."
        );

        await keyboardNavigate("right", boxGroup);
        ok(
          settingControl.contains(document.activeElement),
          "Focus moves into setting-control after right arrow."
        );
        is(
          document.activeElement,
          toggle,
          "The toggle inside setting-control is the activeElement."
        );

        await keyboardNavigate("right", boxGroup);
        is(
          document.activeElement,
          secondButton,
          "Focus skips disabled setting-control and moves to second button."
        );

        await keyboardNavigate("left", boxGroup);
        ok(
          settingControl.contains(document.activeElement),
          "Focus moves back into setting-control, skipping disabled one."
        );
        is(
          document.activeElement,
          toggle,
          "The toggle inside setting-control is the activeElement."
        );

        await keyboardNavigate("left", boxGroup);
        is(
          document.activeElement,
          firstButton,
          "Focus moves back to first button after left arrow."
        );
      });

      add_task(async function testSlottedPanelListClosesOnScroll() {
        let template = html`
          <moz-box-group style="--box-group-max-height: 80px">
            <moz-box-item label="item 1">
              <moz-select slot="actions">
                <moz-option
                  value="1"
                  label="One"
                  iconSrc="chrome://global/skin/icons/info.svg"
                ></moz-option>
                <moz-option
                  value="2"
                  label="Two"
                  iconSrc="chrome://global/skin/icons/warning.svg"
                ></moz-option>
              </moz-select>
            </moz-box-item>
            <moz-box-item label="item 2"></moz-box-item>
            <moz-box-item label="item 3"></moz-box-item>
            <moz-box-item label="item 4"></moz-box-item>
            <moz-box-item label="item 5"></moz-box-item>
          </moz-box-group>
        `;
        let {
          children: [boxGroup],
        } = await testHelpers.renderTemplate(template);
        await boxGroup.updateComplete;

        let select = boxGroup.querySelector("moz-select");
        await select.updateComplete;
        ok(select.usePanelList, "moz-select renders a panel-list.");

        let scrollContainer =
          boxGroup.shadowRoot.querySelector(".scroll-container");
        ok(
          scrollContainer.scrollHeight > scrollContainer.clientHeight,
          "Scroll container overflows so it can scroll."
        );

        let selectButton = select.shadowRoot.querySelector(".panel-trigger");
        let shown = BrowserTestUtils.waitForEvent(select.panelList, "shown");
        synthesizeMouseAtCenter(selectButton, {});
        await shown;
        ok(select.panelList.open, "panel-list opened.");

        let hidden = BrowserTestUtils.waitForEvent(select.panelList, "hidden");
        scrollContainer.scrollTop = 40;
        await hidden;
        ok(
          !select.panelList.open,
          "panel-list closes when the slotted scroll container is scrolled."
        );
      });
    </script>
  </head>
  <body>
    <p id="display"></p>
    <div id="content" style="display: none"></div>
    <pre id="test"></pre>
  </body>
</html>

Messung V0.5 in Prozent
C=84 H=99 G=91

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.