Skip to content

Commit 4974286

Browse files
mstenshochromium-wpt-export-bot
authored andcommitted
[carousel] Focus a column from ::column::scroll-marker.
Add support for focusing column content from a column scroll marker (activate a scroll marker, then press tab). Since columns are in fragment tree order, whereas focus switching operates on the DOM tree in DOM order, some extra attention is required. Look for all Element subtree roots inside the column, and then sort those in DOM order. There's one thing missing, and that is culled inlines. If a column starts with a focusable non-atomic inline (e.g. a plain A element), we'll fail to find it in the fragment tree, since they get culled instead of creating a proper fragment. Will fix that in a follow-up. Bug: 378698659 Change-Id: Ice52d93946b06be2dc616328bac9838cb803e4a5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6335848 Reviewed-by: Ian Kilpatrick <[email protected]> Reviewed-by: Daniil Sakhapov <[email protected]> Commit-Queue: Morten Stenshorne <[email protected]> Cr-Commit-Position: refs/heads/main@{#1431220}
1 parent 3f6ab5c commit 4974286

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
<!DOCTYPE html>
2+
<title>Tab focus and ::colum::scroll-marker</title>
3+
<link rel="author" title="Morten Stenshorne" href="mailto:[email protected]">
4+
<link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-marker-next-focus">
5+
<style>
6+
body {
7+
margin: 0;
8+
}
9+
#container {
10+
scroll-marker-group: before;
11+
overflow: hidden;
12+
columns: 9;
13+
column-fill: auto;
14+
column-rule: solid;
15+
height: 100px;
16+
line-height: 20px;
17+
}
18+
#container::scroll-marker-group {
19+
display: flex;
20+
height: 20px;
21+
background: hotpink;
22+
}
23+
#container::column::scroll-marker {
24+
content: "";
25+
width: 20px;
26+
height: 20px;
27+
margin-right: 5px;
28+
background: blue;
29+
}
30+
#container::column::scroll-marker:focus {
31+
background: cyan;
32+
}
33+
</style>
34+
<div id="container">
35+
<!-- Column #0 -->
36+
<div style="height:100px;">Nothing</div>
37+
38+
<!-- Column #1 -->
39+
<div tabindex="0" id="c1first">line</div>
40+
<div tabindex="0" id="c1second" style="height:180px;">line</div>
41+
42+
<!-- Column #2 only has a resumed block (#c1second). -->
43+
44+
<!-- Column #3 -->
45+
<div tabindex="0" id="inlineBlock" style="display:inline-block; box-sizing:border-box; width:100%; height:90px; border:solid;"></div>
46+
47+
<!-- Column #4 -->
48+
<div>
49+
<div style="display:flex; flex-flow:wrap row-reverse;">
50+
<div tabindex="0" id="flex1" style="width:30%; height:100px;">A</div>
51+
<div tabindex="0" id="flex2" style="width:30%;">B</div>
52+
<div tabindex="0" id="flex3" style="width:30%;">C</div>
53+
54+
<!-- Column #5 -->
55+
<div tabindex="0" id="flex4" style="width:30%;">D</div>
56+
<div tabindex="0" id="flex5" style="width:30%;">E</div>
57+
<div tabindex="0" id="flex6" style="width:30%;">F</div>
58+
</div>
59+
</div>
60+
<div style="display:table;">
61+
<div style="display:table-caption; height:70px; background:cyan;">caption</div>
62+
63+
<!-- Column #6 -->
64+
<div tabindex="0" id="tfoot" style="display:table-footer-group;">footer</div>
65+
<div tabindex="0" id="thead" style="display:table-header-group;">header</div>
66+
<div tabindex="0" id="tbody" style="display:table-row-group;">body</div>
67+
</div>
68+
<div style="position:relative;">
69+
<div style="height:50px; background:black;"></div>
70+
71+
<!-- Column #7 -->
72+
<div tabindex="0" id="c6Abs" style="position:absolute; left:50px;">abs</div>
73+
<div tabindex="0" id="c6Block" style="width:50px;">block</div>
74+
<div style="height:80px; background:black;"></div>
75+
76+
<!-- Column #8 -->
77+
<div tabindex="0" id="c7Block" style="width:50px;">block</div>
78+
<div tabindex="0" id="c7Abs" style="position:absolute; margin-top:-20px; left:50px;">abs</div>
79+
</div>
80+
</div>
81+
82+
<div tabindex="0" id="after">after</div>
83+
84+
<script src="/resources/testharness.js"></script>
85+
<script src="/resources/testharnessreport.js"></script>
86+
<script src="/resources/testdriver.js"></script>
87+
<script src="/resources/testdriver-actions.js"></script>
88+
<script src="/resources/testdriver-vendor.js"></script>
89+
90+
<script>
91+
async function activateMarker(idx) {
92+
await new test_driver.Actions()
93+
.pointerMove(5 + idx*25, 5)
94+
.pointerDown()
95+
.pointerUp()
96+
.send();
97+
}
98+
99+
async function focusNext() {
100+
// https://w3c.github.io/webdriver/#keyboard-actions
101+
const kTab = '\uE004';
102+
103+
await new test_driver.Actions()
104+
.keyDown(kTab)
105+
.keyUp(kTab)
106+
.send();
107+
}
108+
109+
promise_test(async t => {
110+
await activateMarker(4);
111+
await focusNext();
112+
assert_equals(document.activeElement, flex1);
113+
await focusNext();
114+
assert_equals(document.activeElement, flex2);
115+
await focusNext();
116+
assert_equals(document.activeElement, flex3);
117+
await focusNext();
118+
assert_equals(document.activeElement, flex4);
119+
}, "Column 4");
120+
121+
promise_test(async t => {
122+
await activateMarker(3);
123+
await focusNext();
124+
assert_equals(document.activeElement, inlineBlock);
125+
await focusNext();
126+
assert_equals(document.activeElement, flex1);
127+
}, "Column #3");
128+
129+
// TODO(https://github.com/w3c/csswg-drafts/issues/11882): Figure out how to
130+
// treat columns with no elements, and test it here. Column #2 has no start
131+
// elements.
132+
promise_test(async t => {
133+
// At the very least, we should not crash. :)
134+
await activateMarker(2);
135+
await focusNext();
136+
}, "Column #2");
137+
138+
promise_test(async t => {
139+
await activateMarker(1);
140+
await focusNext();
141+
assert_equals(document.activeElement, c1first);
142+
await focusNext();
143+
assert_equals(document.activeElement, c1second);
144+
await focusNext();
145+
assert_equals(document.activeElement, inlineBlock);
146+
}, "Column #1");
147+
148+
promise_test(async t => {
149+
// Column #0 has nothing focusable. The next column has something.
150+
await activateMarker(0);
151+
await focusNext();
152+
assert_equals(document.activeElement, c1first);
153+
}, "Column #0");
154+
155+
promise_test(async t => {
156+
await activateMarker(8);
157+
await focusNext();
158+
assert_equals(document.activeElement, c7Block);
159+
await focusNext();
160+
assert_equals(document.activeElement, c7Abs);
161+
await focusNext();
162+
assert_equals(document.activeElement, after);
163+
}, "Column #8");
164+
165+
promise_test(async t => {
166+
await activateMarker(7);
167+
await focusNext();
168+
assert_equals(document.activeElement, c6Abs);
169+
await focusNext();
170+
assert_equals(document.activeElement, c6Block);
171+
await focusNext();
172+
assert_equals(document.activeElement, c7Block);
173+
}, "Column 7");
174+
175+
promise_test(async t => {
176+
await activateMarker(6);
177+
await focusNext();
178+
assert_equals(document.activeElement, tfoot);
179+
await focusNext();
180+
assert_equals(document.activeElement, thead);
181+
await focusNext();
182+
assert_equals(document.activeElement, tbody);
183+
await focusNext();
184+
assert_equals(document.activeElement, c6Abs);
185+
}, "Column 6");
186+
187+
promise_test(async t => {
188+
await activateMarker(5);
189+
await focusNext();
190+
assert_equals(document.activeElement, flex4);
191+
await focusNext();
192+
assert_equals(document.activeElement, flex5);
193+
await focusNext();
194+
assert_equals(document.activeElement, flex6);
195+
await focusNext();
196+
assert_equals(document.activeElement, tfoot);
197+
}, "Column 5");
198+
</script>

0 commit comments

Comments
 (0)