File: dialog-popover-closedby-complex.html

package info (click to toggle)
firefox-esr 140.4.0esr-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,539,276 kB
  • sloc: cpp: 7,381,286; javascript: 6,388,710; ansic: 3,710,139; python: 1,393,780; xml: 628,165; asm: 426,918; java: 184,004; sh: 65,742; makefile: 19,302; objc: 13,059; perl: 12,912; yacc: 4,583; cs: 3,846; pascal: 3,352; lex: 1,720; ruby: 1,226; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10
file content (158 lines) | stat: -rw-r--r-- 6,585 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="timeout" content="long">
<link rel="author" href="mailto:masonf@chromium.org">
<link rel=help href="https://html.spec.whatwg.org/multipage/interactive-elements.html#dialog-light-dismiss">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="../../popovers/resources/popover-utils.js"></script>

<div id=unrelated>Unrelated</div>

<div class=testcase data-description="normal DOM nesting">
  <dialog class=dialogA closedby=any style="position: fixed; top: 100px; bottom: auto; padding:0;">Dialog 1
    <div class=popoverA popover style="top: 150px; bottom: auto; padding:0;">Popover 1
      <dialog class=dialogB closedby=any style="position: fixed; top: 200px; bottom: auto; padding:0;">Dialog 2
        <div class=popoverB popover style="top: 250px; bottom: auto; padding:0;">Popover 2</div>
      </dialog>
    </div>
  </dialog>
</div>

<div class=testcase data-description="same structure, but with shadow DOM slots">
  <div>
    <template shadowrootmode=open>
      <dialog class=dialogA closedby=any style="position: fixed; top: 100px; bottom: auto; padding:0;">Dialog 1
        <slot></slot>
      </dialog>
    </template>
    <div>
      <template shadowrootmode=open>
        <div class=popoverA popover style="top: 150px; bottom: auto; padding:0;">Popover 1
          <slot></slot>
        </div>
      </template>
      <div>
        <template shadowrootmode=open>
          <dialog class=dialogB closedby=any style="position: fixed; top: 200px; bottom: auto; padding:0;">Dialog 2
            <slot></slot>
          </dialog>
        </template>
        <div class=popoverB popover style="top: 250px; bottom: auto; padding:0;">Popover 2</div>
      </div>
    </div>
  </div>
</div>

<script>
function openDialog(dialog,modal) {
  assert_true(!!dialog);
  assert_false(dialog.open);
  if (modal) {
    dialog.showModal();
  } else {
    dialog.show();
  }
  assert_true(dialog.open);
  assert_equals(dialog.matches(':modal'),modal);
}
function assertStates(elements,dialogAExpected,popoverAExpected,
    dialogBExpected,popoverBExpected) {
  assert_equals(elements.dialogA.open,dialogAExpected,
    `dialogA should be ${dialogAExpected ? 'open' : 'closed'}`);
  assert_equals(elements.popoverA.matches(':popover-open'),popoverAExpected,
    `popoverA should be ${popoverAExpected ? 'open' : 'closed'}`);
  assert_equals(elements.dialogB.open,dialogBExpected,
    `dialogB should be ${dialogBExpected ? 'open' : 'closed'}`);
  assert_equals(elements.popoverB.matches(':popover-open'),popoverBExpected,
    `popoverB should be ${popoverBExpected ? 'open' : 'closed'}`);
}
function findElements(wrapper) {
  let elements = {};
  if (!wrapper) {
    return elements;
  }
  Array.from(wrapper.children).forEach(child => {
    ['dialogA','popoverA','dialogB','popoverB'].forEach(pattern => {
      if (child.matches(`.${pattern}`)) {
        assert_false(elements.hasOwnProperty(pattern),'Multiple elements with the same class');
        elements[pattern] = child;
      }
      elements = {...elements, ...findElements(child)};
      elements = {...elements, ...findElements(child.shadowRoot)};
    });
  });
  return elements;
}
function openDialogPopoverStack(t,elements,modalA,modalB) {
  t.add_cleanup(() => {
    elements.dialogA.close();
    elements.popoverA.hidePopover();
    elements.dialogB.close();
    elements.popoverB.hidePopover();
  });
  openDialog(elements.dialogA,modalA);
  elements.popoverA.showPopover();
  openDialog(elements.dialogB,modalB);
  elements.popoverB.showPopover();
  assertStates(elements,true,true,true,true);
}

document.querySelectorAll('.testcase').forEach(testcase => {
  const testDescription = `, ${testcase.dataset.description}`;
  const elements = findElements(testcase);
  assert_array_equals(Object.keys(elements).sort(),['dialogA','popoverA','dialogB','popoverB'].sort());
  [false,true].forEach(modalA => {
    [false,true].forEach(modalB => {
      const modalAString = modalA ? 'modal dialogA' : 'modeless dialogA';
      const modalBString = modalB ? 'modal dialogB' : 'modeless dialogB';
      promise_test(async (t) => {
        openDialogPopoverStack(t,elements,modalA,modalB);
        await clickOn(unrelated);
        // Clicking outside all is actually a click on a dialog backdrop.
        // If dialogB is modal, it'll be dialogB, which is nested inside popoverA.
        // Either way, both popoverB and dialogB should close.
        assertStates(elements,true,modalB,false,false);
        await clickOn(unrelated);
        // Clicking outside again should close the remaining two.
        assertStates(elements,false,false,false,false);
      },`clicking outside all with ${modalAString} and ${modalBString}${testDescription}`);

      promise_test(async (t) => {
        openDialogPopoverStack(t,elements,modalA,modalB);
        await clickOn(elements.popoverB);
        // Clicking popoverB should keep everything open.
        assertStates(elements,true,true,true,true);
      },`clicking popoverB with ${modalAString} and ${modalBString}${testDescription}`);

      promise_test(async (t) => {
        openDialogPopoverStack(t,elements,modalA,modalB);
        await clickOn(elements.dialogB);
        // Only popoverB should be light dismissed.
        assertStates(elements,true,true,true,false);
      },`clicking dialogB with ${modalAString} and ${modalBString}${testDescription}`);

      promise_test(async (t) => {
        openDialogPopoverStack(t,elements,modalA,modalB);
        await clickOn(elements.popoverA);
        // Both dialogB and popoverB should be light dismissed.
        assertStates(elements,true,true,false,false);
      },`clicking popoverA with ${modalAString} and ${modalBString}${testDescription}`);

      promise_test(async (t) => {
        openDialogPopoverStack(t,elements,modalA,modalB);
        await clickOn(elements.dialogA);
        // If dialogB is modal, clicking on dialogA is actually clicking on dialogB,
        // which means popoverB will stay open.
        assertStates(elements,true,modalB,false,false);
        await clickOn(elements.dialogA);
        // The next click on dialogA should light dismiss popoverA.
        assertStates(elements,true,false,false,false);
      },`clicking dialogA with ${modalAString} and ${modalBString}${testDescription}`);
    });
  });
});
</script>