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
|
<!DOCTYPE html>
<meta charset="utf-8">
<title>Popover combined with dialog/fullscreen behavior</title>
<link rel=author href="mailto:masonf@chromium.org">
<link rel=help href="https://open-ui.org/components/popover.research.explainer">
<link rel=help href="https://html.spec.whatwg.org/multipage/popover.html">
<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="resources/popover-utils.js"></script>
<button id=visible>Visible button</button>
<div id=examples>
<dialog popover>Popover Dialog</dialog>
<dialog popover open style="top:50px;">Open Non-modal Popover Dialog</dialog>
<div popover class=fullscreen>Fullscreen Popover</div>
<dialog popover class=fullscreen>Fullscreen Popover Dialog</dialog>
<dialog popover open class=fullscreen style="top:200px;">Fullscreen Open Non-modal Popover Dialog</dialog>
</div>
<style>
[popover] {
inset:auto;
top:0;
left:0;
}
[popover].fullscreen.visible {
display:block;
}
</style>
<script>
const isDialog = (ex) => ex instanceof HTMLDialogElement;
const isFullscreen = (ex) => ex.classList.contains('fullscreen');
function ensureIsOpenPopover(ex,message) {
// Because :popover-open will eventually support <dialog>, this does extra work to
// verify we're dealing with an :popover-open Popover. Note that this will also throw
// if this is an element with the `popover` attribute that has been made
// visible via an explicit `display:block` style rule.
message = message || 'Error';
assert_true(ex.matches(':popover-open'),`${message}: Popover doesn\'t match :popover-open`);
ex.hidePopover(); // Shouldn't throw if this is a showing popover
ex.showPopover(); // Show it again to avoid state change
assert_true(ex.matches(':popover-open'),`${message}: Sanity`);
}
window.onload = () => requestAnimationFrame(() => requestAnimationFrame(() => {
const examples = Array.from(document.querySelectorAll('#examples>*'));
examples.forEach(ex => {
promise_test(async (t) => {
t.add_cleanup(() => ex.remove());
// Test initial conditions
if (ex.hasAttribute('open')) {
assert_true(isDialog(ex));
assert_true(isElementVisible(ex),'Open dialog should be visible by default');
assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover on an already-showing element should throw InvalidStateError');
ex.removeAttribute('open');
assert_false(isElementVisible(ex),'Removing the open attribute should hide the dialog');
} else {
ex.showPopover(); // Should not throw
ensureIsOpenPopover(ex,'showPopover should work');
ex.hidePopover(); // Should not throw
assert_false(ex.matches(':popover-open'),'hidePopover should work');
}
assert_false(isElementVisible(ex));
// Start with popover, try the other API
ex.showPopover();
ensureIsOpenPopover(ex);
let tested_something=false;
if (isDialog(ex)) {
tested_something=true;
assert_throws_dom("InvalidStateError",() => ex.showModal(),'Calling showModal() on an already-showing Popover should throw InvalidStateError');
assert_throws_dom("InvalidStateError",() => ex.show(),'Calling show() on an already-showing Popover should throw InvalidStateError');
}
if (isFullscreen(ex)) {
tested_something=true;
let requestSucceeded = false;
await blessTopLayer(ex);
await ex.requestFullscreen()
.then(() => {requestSucceeded = true;}) // We should not hit this.
.catch((exception) => {
// This exception is expected.
assert_equals(exception.name,'TypeError',`Invalid exception from requestFullscreen() (${exception.message})`);
});
assert_false(requestSucceeded,'requestFullscreen() should not succeed when the element is an already-showing Popover');
}
assert_true(tested_something);
ensureIsOpenPopover(ex);
ex.hidePopover();
// Start with the other API, then try popover
if (isDialog(ex)) {
ex.show();
assert_true(ex.hasAttribute('open'));
assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-showing non-modal dialog should throw InvalidStateError');
ex.close();
assert_false(ex.hasAttribute('open'));
ex.showModal();
assert_true(ex.hasAttribute('open'));
assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-showing modal dialog should throw InvalidStateError');
ex.close();
assert_false(ex.hasAttribute('open'));
} else if (isFullscreen(ex)) {
let requestSucceeded = false;
await blessTopLayer(visible);
await ex.requestFullscreen()
.then(() => {
assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-fullscreen element should throw InvalidStateError');
});
await document.exitFullscreen()
.then(() => assert_true(true));
}
// Finally, try invoking these combined popovers via a declarative invoker
const button = document.createElement('button');
t.add_cleanup(() => button.remove());
document.body.appendChild(button);
button.popoverTargetElement = ex;
button.popoverTargetAction = "toggle";
assert_false(ex.matches(':popover-open'));
await clickOn(button);
ensureIsOpenPopover(ex,'Invoking element should be able to invoke all popovers');
ex.hidePopover();
if (isDialog(ex)) {
ex.showModal();
assert_true(ex.hasAttribute('open'));
} else if (isFullscreen(ex)) {
// Popover fullscreen isn't visible by default, so explicitly add
// display:block, so that calls to "clickOn" can succeed.
ex.classList.add('visible');
await blessTopLayer(visible);
await ex.requestFullscreen();
} else {
assert_unreached('Not a dialog or fullscreen');
}
ex.appendChild(button); // Add button to the element, so it's visible to click
await clickOn(button);
assert_false(ex.matches(':popover-open'),'The invoker click should have failed on the already-open dialog/fullscreen');
if (isDialog(ex)) {
ex.close();
} else {
await document.exitFullscreen()
}
}, `Popover combination: ${ex.textContent}`);
});
}));
</script>
|