Skip to content

Commit 084f000

Browse files
mfreed7chromium-wpt-export-bot
authored andcommitted
Implement imperative slotting API changes
The original implementation of the imperative slot distribution API was done before the final spec PRs landed. In the process of landing those PRs, several changes were made to the way the API works. Primarily, there are two changes: 1. The "auto" slotAssignment mode was renamed to "named". 2. The "linkage" that is created by HTMLSlotElement.assign() was made more permanent. Previously, moving either the <slot> or the assigned node around in the tree (or across documents) would "break" the linkage. Now, the linkage is more permanent, and the only way to break it is through another call to .assign(). See [1] for the chromestatus entry, [2] for the intent to ship, [3], [4], and [5] for the spec PRs, and [6]/[7] for the landed spec. [1] https://chromestatus.com/feature/4979822998585344 [2] https://groups.google.com/a/chromium.org/g/blink-dev/c/6U78F3KWJ78 [3] whatwg/html#6561 [4] whatwg/html#6585 [5] whatwg/dom#966 [6] https://dom.spec.whatwg.org/#find-slotables [7] https://html.spec.whatwg.org/#dom-slot-assign Fixed: 1196842 Fixed: 1067153 Bug: 1067157 Change-Id: I0ee71043c23f3b49a1461296d722045f06eca540
1 parent d0d5cb6 commit 084f000

File tree

2 files changed

+25
-100
lines changed

2 files changed

+25
-100
lines changed

shadow-dom/slots-imperative-api-slotchange.tentative.html shadow-dom/imperative-slot-api-slotchange.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
let tTree = setupShadowDOM(test_slotchange, test, data);
108108
let [s1Promise, s2Promise] = monitorSlots(data);
109109

110-
assert_throws_dom('NotAllowedError', () => { tTree.s1.assign([tTree.c4]); });
110+
tTree.s1.assign([]);;
111111
tTree.s2.assign([]);
112112
tTree.host.insertBefore(tTree.c4, tTree.c1);
113113

@@ -135,7 +135,7 @@
135135

136136
[s1Promise] = monitorSlots(data);
137137
tTree.s1.assign([tTree.c1, tTree.c2]);
138-
tTree.s1.assign([tTree.c2, tTree.c1, tTree.c1, tTree.c2, tTree.c2]);
138+
tTree.s1.assign([tTree.c1, tTree.c2, tTree.c1, tTree.c2, tTree.c2]);
139139

140140
s1Promise.then(test.step_func_done(() => {
141141
assert_equals(data.s1EventCount, 1);

shadow-dom/slots-imperative-slot-api.tentative.html shadow-dom/imperative-slot-api.html

+23-98
Original file line numberDiff line numberDiff line change
@@ -15,47 +15,14 @@
1515
let tTree = createTestTree(test_basic);
1616
assert_not_equals(tTree.host1.attachShadow({ mode: 'open', slotAssignment: 'manual'}),
1717
null, 'slot assignment manual should work');
18-
assert_not_equals(tTree.host2.attachShadow({ mode: 'open', slotAssignment: 'name'}),
18+
assert_not_equals(tTree.host2.attachShadow({ mode: 'open', slotAssignment: 'named'}),
1919
null, 'slot assignment auto should work');
2020
assert_throws_js(TypeError, () => {
2121
tTree.host3.attachShadow({ mode: 'open', slotAssignment: 'exceptional' })},
2222
'others should throw exception');
2323
}, 'attachShadow can take slotAssignment parameter.');
2424
</script>
2525

26-
<div id="test_errors">
27-
<div id="host1">
28-
<template data-mode="open" data-slot-assignment="name">
29-
<slot id="s1"></slot>
30-
</template>
31-
<div id="c1"></div>
32-
</div>
33-
<div id="host2">
34-
<template data-mode="open" data-slot-assignment="manual">
35-
<slot id="s2"></slot>
36-
</template>
37-
</div>
38-
<div id="c2"></div>
39-
</div>
40-
<script>
41-
test(() => {
42-
let tTree = createTestTree(test_errors);
43-
assert_array_equals(tTree.s1.assignedElements(), [tTree.c1]);
44-
assert_equals(tTree.c1.assignedSlot, tTree.s1);
45-
46-
assert_throws_dom('NotAllowedError', () => { tTree.s1.assign([]); });
47-
assert_array_equals(tTree.s1.assignedElements(), [tTree.c1]);
48-
assert_equals(tTree.c1.assignedSlot, tTree.s1);
49-
}, 'Imperative slot API throws exception when not slotAssignment != \'manual\'.');
50-
51-
test(() => {
52-
let tTree = createTestTree(test_errors);
53-
assert_throws_dom('NotAllowedError', () => { tTree.s2.assign([tTree.c2]); });
54-
55-
assert_throws_dom('NotAllowedError', () => { tTree.s2.assign([tTree.host1]); });
56-
}, 'Imperative slot API throws exception when slottable parentNode != slot\'s host.');
57-
</script>
58-
5926
<div id="test_assign">
6027
<div id="host">
6128
<template id="shadow_root" data-mode="open" data-slot-assignment="manual">
@@ -155,34 +122,31 @@
155122
let tTree = createTestTree(test_assign);
156123

157124
// tTree.c4 is invalid for tTree.host slot assignment.
158-
try {
159-
tTree.s1.assign([tTree.c1, tTree.c2, tTree.c4]);
160-
assert_unreached('assign() should have failed) ');
161-
} catch (err) {
162-
assert_equals(err.name, 'NotAllowedError');
163-
}
125+
// No exception should be thrown here.
126+
tTree.s1.assign([tTree.c1, tTree.c4, tTree.c2]);
164127

165-
assert_array_equals(tTree.s1.assignedNodes(), []);
166-
assert_equals(tTree.c1.assignedSlot, null);
167-
assert_equals(tTree.c2.assignedSlot, null);
128+
// All observable assignments should skip c4.
129+
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
130+
assert_equals(tTree.c1.assignedSlot, tTree.s1);
131+
assert_equals(tTree.c2.assignedSlot, tTree.s1);
168132
assert_equals(tTree.c4.assignedSlot, null);
169133

170-
tTree.s1.assign([tTree.c2, tTree.c3, tTree.c1]);
171-
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c3, tTree.c1]);
172-
173-
try {
174-
tTree.s1.assign([tTree.c4]);
175-
assert_unreached('assign() should have failed) ');
176-
} catch (err) {
177-
assert_equals(err.name, 'NotAllowedError');
178-
}
179-
180-
// Previous state is preserved.
181-
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c3, tTree.c1]);
134+
// Moving c4 into place should reveal the assignment.
135+
tTree.host.append(tTree.c4);
136+
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c4, tTree.c2]);
182137
assert_equals(tTree.c1.assignedSlot, tTree.s1);
183138
assert_equals(tTree.c2.assignedSlot, tTree.s1);
184-
assert_equals(tTree.c3.assignedSlot, tTree.s1);
185-
}, 'Assigning invalid nodes causes exception and slot returns to its previous state.');
139+
assert_equals(tTree.c4.assignedSlot, tTree.s1);
140+
141+
// Moving c4 into a different shadow host and back should
142+
// also not break the assignment.
143+
tTree.host4.append(tTree.c4)
144+
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
145+
assert_equals(tTree.c4.assignedSlot, null);
146+
tTree.host.append(tTree.c4);
147+
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c4, tTree.c2]);
148+
assert_equals(tTree.c4.assignedSlot, tTree.s1);
149+
}, 'Assigning invalid nodes should be allowed.');
186150

187151
test(() => {
188152
let tTree = createTestTree(test_assign);
@@ -227,21 +191,6 @@
227191
assert_equals(tTree.c1.assignedSlot, tTree.s4);
228192
}, 'Appending slottable to different host, it loses slot assignment. It can be re-assigned within a new host.');
229193

230-
test(() => {
231-
let tTree = createTestTree(test_assign);
232-
233-
tTree.s1.assign([tTree.c1]);
234-
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
235-
236-
tTree.shadow_root4.insertBefore(tTree.s1, tTree.s4);
237-
assert_array_equals(tTree.s1.assignedNodes(), []);
238-
// Don't trigger slot assignment on previous shadow root.
239-
// assert_array_equals(tTree.s2.assignedNodes(), []);
240-
241-
tTree.shadow_root.insertBefore(tTree.s1, tTree.s2);
242-
assert_array_equals(tTree.s1.assignedNodes(), []);
243-
}, 'Previously assigned node should not be assigned if slot moved to a new shadow root. The slot remains empty when moved back, no trigger recalc.');
244-
245194
test(() => {
246195
let tTree = createTestTree(test_assign);
247196

@@ -264,8 +213,8 @@
264213
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
265214

266215
tTree.s1.assign([tTree.c1, tTree.c1, tTree.c2, tTree.c2, tTree.c1]);
267-
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c1]);
268-
}, 'Assignment with the same node in parameters should be ignored, last one wins.');
216+
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
217+
}, 'Assignment with the same node in parameters should be ignored, first one wins.');
269218

270219
test(() => {
271220
let tTree = createTestTree(test_assign);
@@ -278,28 +227,4 @@
278227
assert_equals(tTree.c3.assignedSlot, null);
279228
}, 'Removing a slot from DOM resets its slottable\'s slot assignment.');
280229

281-
test(() => {
282-
let tTree = createTestTree(test_assign);
283-
284-
tTree.s1.assign([tTree.c1]);
285-
tTree.s2.assign([tTree.c2]);
286-
tTree.s3.assign([tTree.c3]);
287-
tTree.shadow_root.insertBefore(tTree.s2, tTree.s1);
288-
tTree.shadow_root.insertBefore(tTree.s3, tTree.s1);
289-
290-
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
291-
assert_array_equals(tTree.s2.assignedNodes(), []);
292-
assert_array_equals(tTree.s3.assignedNodes(), []);
293-
assert_equals(tTree.c1.assignedSlot, tTree.s1);
294-
assert_equals(tTree.c2.assignedSlot, null);
295-
assert_equals(tTree.c3.assignedSlot, null);
296-
297-
tTree.s2.remove();
298-
299-
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
300-
assert_array_equals(tTree.s3.assignedNodes(), []);
301-
assert_equals(tTree.c1.assignedSlot, tTree.s1);
302-
assert_equals(tTree.c2.assignedSlot, null);
303-
assert_equals(tTree.c3.assignedSlot, null);
304-
}, 'A slot should be cleared of assigned nodes even if it\'s re-inserted into the same shadow root.');
305230
</script>

0 commit comments

Comments
 (0)