Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement imperative slotting API changes #28521

Merged
merged 1 commit into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
let tTree = setupShadowDOM(test_slotchange, test, data);
let [s1Promise, s2Promise] = monitorSlots(data);

assert_throws_dom('NotAllowedError', () => { tTree.s1.assign([tTree.c4]); });
tTree.s1.assign([]);;
tTree.s2.assign([]);
tTree.host.insertBefore(tTree.c4, tTree.c1);

Expand Down Expand Up @@ -135,7 +135,7 @@

[s1Promise] = monitorSlots(data);
tTree.s1.assign([tTree.c1, tTree.c2]);
tTree.s1.assign([tTree.c2, tTree.c1, tTree.c1, tTree.c2, tTree.c2]);
tTree.s1.assign([tTree.c1, tTree.c2, tTree.c1, tTree.c2, tTree.c2]);

s1Promise.then(test.step_func_done(() => {
assert_equals(data.s1EventCount, 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,14 @@
let tTree = createTestTree(test_basic);
assert_not_equals(tTree.host1.attachShadow({ mode: 'open', slotAssignment: 'manual'}),
null, 'slot assignment manual should work');
assert_not_equals(tTree.host2.attachShadow({ mode: 'open', slotAssignment: 'name'}),
assert_not_equals(tTree.host2.attachShadow({ mode: 'open', slotAssignment: 'named'}),
null, 'slot assignment auto should work');
assert_throws_js(TypeError, () => {
tTree.host3.attachShadow({ mode: 'open', slotAssignment: 'exceptional' })},
'others should throw exception');
}, 'attachShadow can take slotAssignment parameter.');
</script>

<div id="test_errors">
<div id="host1">
<template data-mode="open" data-slot-assignment="name">
<slot id="s1"></slot>
</template>
<div id="c1"></div>
</div>
<div id="host2">
<template data-mode="open" data-slot-assignment="manual">
<slot id="s2"></slot>
</template>
</div>
<div id="c2"></div>
</div>
<script>
test(() => {
let tTree = createTestTree(test_errors);
assert_array_equals(tTree.s1.assignedElements(), [tTree.c1]);
assert_equals(tTree.c1.assignedSlot, tTree.s1);

assert_throws_dom('NotAllowedError', () => { tTree.s1.assign([]); });
assert_array_equals(tTree.s1.assignedElements(), [tTree.c1]);
assert_equals(tTree.c1.assignedSlot, tTree.s1);
}, 'Imperative slot API throws exception when not slotAssignment != \'manual\'.');

test(() => {
let tTree = createTestTree(test_errors);
assert_throws_dom('NotAllowedError', () => { tTree.s2.assign([tTree.c2]); });

assert_throws_dom('NotAllowedError', () => { tTree.s2.assign([tTree.host1]); });
}, 'Imperative slot API throws exception when slottable parentNode != slot\'s host.');
</script>

<div id="test_assign">
<div id="host">
<template id="shadow_root" data-mode="open" data-slot-assignment="manual">
Expand Down Expand Up @@ -155,34 +122,31 @@
let tTree = createTestTree(test_assign);

// tTree.c4 is invalid for tTree.host slot assignment.
try {
tTree.s1.assign([tTree.c1, tTree.c2, tTree.c4]);
assert_unreached('assign() should have failed) ');
} catch (err) {
assert_equals(err.name, 'NotAllowedError');
}
// No exception should be thrown here.
tTree.s1.assign([tTree.c1, tTree.c4, tTree.c2]);

assert_array_equals(tTree.s1.assignedNodes(), []);
assert_equals(tTree.c1.assignedSlot, null);
assert_equals(tTree.c2.assignedSlot, null);
// All observable assignments should skip c4.
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
assert_equals(tTree.c1.assignedSlot, tTree.s1);
assert_equals(tTree.c2.assignedSlot, tTree.s1);
assert_equals(tTree.c4.assignedSlot, null);

tTree.s1.assign([tTree.c2, tTree.c3, tTree.c1]);
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c3, tTree.c1]);

try {
tTree.s1.assign([tTree.c4]);
assert_unreached('assign() should have failed) ');
} catch (err) {
assert_equals(err.name, 'NotAllowedError');
}

// Previous state is preserved.
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c3, tTree.c1]);
// Moving c4 into place should reveal the assignment.
tTree.host.append(tTree.c4);
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c4, tTree.c2]);
assert_equals(tTree.c1.assignedSlot, tTree.s1);
assert_equals(tTree.c2.assignedSlot, tTree.s1);
assert_equals(tTree.c3.assignedSlot, tTree.s1);
}, 'Assigning invalid nodes causes exception and slot returns to its previous state.');
assert_equals(tTree.c4.assignedSlot, tTree.s1);

// Moving c4 into a different shadow host and back should
// also not break the assignment.
tTree.host4.append(tTree.c4)
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
assert_equals(tTree.c4.assignedSlot, null);
tTree.host.append(tTree.c4);
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c4, tTree.c2]);
assert_equals(tTree.c4.assignedSlot, tTree.s1);
}, 'Assigning invalid nodes should be allowed.');

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

test(() => {
let tTree = createTestTree(test_assign);

tTree.s1.assign([tTree.c1]);
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);

tTree.shadow_root4.insertBefore(tTree.s1, tTree.s4);
assert_array_equals(tTree.s1.assignedNodes(), []);
// Don't trigger slot assignment on previous shadow root.
// assert_array_equals(tTree.s2.assignedNodes(), []);

tTree.shadow_root.insertBefore(tTree.s1, tTree.s2);
assert_array_equals(tTree.s1.assignedNodes(), []);
}, '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.');

test(() => {
let tTree = createTestTree(test_assign);

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

tTree.s1.assign([tTree.c1, tTree.c1, tTree.c2, tTree.c2, tTree.c1]);
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c1]);
}, 'Assignment with the same node in parameters should be ignored, last one wins.');
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
}, 'Assignment with the same node in parameters should be ignored, first one wins.');

test(() => {
let tTree = createTestTree(test_assign);
Expand All @@ -281,25 +230,45 @@
test(() => {
let tTree = createTestTree(test_assign);

tTree.s1.assign([tTree.c1]);
tTree.s2.assign([tTree.c2]);
tTree.s3.assign([tTree.c3]);
tTree.shadow_root.insertBefore(tTree.s2, tTree.s1);
tTree.shadow_root.insertBefore(tTree.s3, tTree.s1);
const isolatedDocNode = document.implementation.createHTMLDocument("").body;
isolatedDocNode.appendChild(tTree.c1);
const isolatedDocNode2 = document.implementation.createHTMLDocument("").body;
isolatedDocNode2.appendChild(tTree.s1);

assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
assert_array_equals(tTree.s2.assignedNodes(), []);
assert_array_equals(tTree.s3.assignedNodes(), []);
assert_equals(tTree.c1.assignedSlot, tTree.s1);
tTree.s1.assign([tTree.c1, tTree.c2]);
assert_array_equals(tTree.s1.assignedNodes(), [], 's1 not inside shadow root');
assert_equals(tTree.c1.assignedSlot, null);
assert_equals(tTree.c2.assignedSlot, null);
assert_equals(tTree.c3.assignedSlot, null);

tTree.s2.remove();
tTree.shadow_root.appendChild(tTree.s1);
tTree.host.appendChild(tTree.c1);
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
assert_equals(tTree.c1.assignedSlot, tTree.s1);
assert_equals(tTree.c2.assignedSlot, tTree.s1);
}, 'Nodes can be assigned even if slots or nodes aren\'t in the same tree.');

assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
assert_array_equals(tTree.s3.assignedNodes(), []);
test(() => {
let tTree = createTestTree(test_assign);

tTree.s1.assign([tTree.c1, tTree.c2]);
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
assert_equals(tTree.c1.assignedSlot, tTree.s1);
assert_equals(tTree.c2.assignedSlot, tTree.s1);

const isolatedDocNode = document.implementation.createHTMLDocument("").body;
isolatedDocNode.appendChild(tTree.c1);
const isolatedDocNode2 = document.implementation.createHTMLDocument("").body;
isolatedDocNode2.appendChild(tTree.s1);

assert_array_equals(tTree.s1.assignedNodes(), [], 's1 not inside shadow root');
assert_equals(tTree.c1.assignedSlot, null);
assert_equals(tTree.c2.assignedSlot, null);
assert_equals(tTree.c3.assignedSlot, null);
}, 'A slot should be cleared of assigned nodes even if it\'s re-inserted into the same shadow root.');

tTree.shadow_root.appendChild(tTree.s1);
tTree.host.appendChild(tTree.c1);
assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
assert_equals(tTree.c1.assignedSlot, tTree.s1);
assert_equals(tTree.c2.assignedSlot, tTree.s1);
}, 'Removing a node from the document does not break manually assigned slot linkage.');

</script>