Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE html>
<html>
<body>
<meta name="assert" content="Selection's getComposedRanges should be updated when its associated live range changes">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="light">Start outside shadow DOM</div>
<div id="outerHost">outerHost
<template shadowrootmode="open">
<slot></slot>
<div id="innerHost">innerHost
<template shadowrootmode="open">
<slot></slot>
</template>
</div>
</template>
</div>
<script>
const selection = getSelection();
const outerHost = document.getElementById('outerHost')
const outerRoot = outerHost.shadowRoot;
const innerHost = outerRoot.getElementById('innerHost');
const innerRoot = innerHost.shadowRoot;
test(() => {
// Step 1: Setting a composed live range that crosses boundaries
selection.setBaseAndExtent(light.firstChild, 10, innerHost.firstChild, 5);
const liveRange = selection.getRangeAt(0);
const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
assert_equals(liveRange.startContainer, innerHost.firstChild);
assert_equals(liveRange.startOffset, 5);
assert_equals(liveRange.endContainer, innerHost.firstChild);
assert_equals(liveRange.endOffset, 5);
assert_equals(selection.anchorNode, innerHost.firstChild);
assert_equals(selection.anchorOffset, 5);
assert_equals(selection.focusNode, innerHost.firstChild);
assert_equals(selection.focusOffset, 5);
assert_equals(composedRange.startContainer, light.firstChild);
assert_equals(composedRange.startOffset, 10);
assert_equals(composedRange.endContainer, innerHost.firstChild);
assert_equals(composedRange.endOffset, 5);
// Step 2: Update the live range only using setEnd
liveRange.setEnd(innerHost.firstChild, 6);
const composedRange2 = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
assert_equals(liveRange.startContainer, innerHost.firstChild);
assert_equals(liveRange.startOffset, 5);
assert_equals(liveRange.endContainer, innerHost.firstChild);
assert_equals(liveRange.endOffset, 6);
assert_equals(selection.anchorNode, innerHost.firstChild);
assert_equals(selection.anchorOffset, 5);
assert_equals(selection.focusNode, innerHost.firstChild);
assert_equals(selection.focusOffset, 6);
assert_equals(composedRange2.startContainer, light.firstChild);
assert_equals(composedRange2.startOffset, 10);
assert_equals(composedRange2.endContainer, innerHost.firstChild);
assert_equals(composedRange2.endOffset, 6);
// Step 3: selectNode() calls both setStart/setEnd
liveRange.selectNode(innerHost);
const composedRange3 = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
assert_equals(liveRange.startContainer, outerRoot);
assert_equals(liveRange.startOffset, 3);
assert_equals(liveRange.endContainer, outerRoot);
assert_equals(liveRange.endOffset, 4);
assert_equals(selection.anchorNode, outerRoot);
assert_equals(selection.anchorOffset, 3);
assert_equals(selection.focusNode, outerRoot);
assert_equals(selection.focusOffset, 4);
assert_equals(composedRange3.startContainer, outerRoot);
assert_equals(composedRange3.startOffset, 3);
assert_equals(composedRange3.endContainer, outerRoot);
assert_equals(composedRange3.endOffset, 4);
// Step 4: collapse(false) calls setEnd only
liveRange.collapse();
const composedRange4 = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
assert_equals(liveRange.startContainer, outerRoot);
assert_equals(liveRange.startOffset, 4);
assert_equals(liveRange.endContainer, outerRoot);
assert_equals(liveRange.endOffset, 4);
assert_equals(selection.anchorNode, outerRoot);
assert_equals(selection.anchorOffset, 4);
assert_equals(selection.focusNode, outerRoot);
assert_equals(selection.focusOffset, 4);
assert_equals(composedRange4.startContainer, outerRoot);
assert_equals(composedRange4.startOffset, 4);
assert_equals(composedRange4.endContainer, outerRoot);
assert_equals(composedRange4.endOffset, 4);
}, 'modify getRangeAt() range.');
test(() => {
// Step 1: Creating a live range and only setting its end/anchor
selection.removeAllRanges();
const liveRange = document.createRange();
liveRange.setEnd(innerHost.firstChild, 5);
const composedRanges = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] });
assert_equals(liveRange.startContainer, innerHost.firstChild);
assert_equals(liveRange.startOffset, 5);
assert_equals(liveRange.endContainer, innerHost.firstChild);
assert_equals(liveRange.endOffset, 5);
assert_equals(selection.anchorNode, null);
assert_equals(selection.anchorOffset, 0);
assert_equals(selection.focusNode, null);
assert_equals(selection.focusOffset, 0);
assert_equals(composedRanges.length, 0);
// Step 2: Add range to selection so range API updates will change selection
selection.addRange(liveRange);
const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
assert_equals(liveRange.startContainer, innerHost.firstChild);
assert_equals(liveRange.startOffset, 5);
assert_equals(liveRange.endContainer, innerHost.firstChild);
assert_equals(liveRange.endOffset, 5);
assert_equals(selection.anchorNode, innerHost.firstChild);
assert_equals(selection.anchorOffset, 5);
assert_equals(selection.focusNode, innerHost.firstChild);
assert_equals(selection.focusOffset, 5);
assert_equals(composedRange.startContainer, innerHost.firstChild);
assert_equals(composedRange.startOffset, 5);
assert_equals(composedRange.endContainer, innerHost.firstChild);
assert_equals(composedRange.endOffset, 5);
}, 'modify createRange() range added to selection after setEnd call.');
test(() => {
// Step 1: Creating a live range and only setting its end/anchor
selection.removeAllRanges();
const liveRange = document.createRange();
// Add range to selection so range API updates will change selection
selection.addRange(liveRange);
liveRange.setEnd(innerHost.firstChild, 5);
const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
assert_equals(liveRange.startContainer, innerHost.firstChild);
assert_equals(liveRange.startOffset, 5);
assert_equals(liveRange.endContainer, innerHost.firstChild);
assert_equals(liveRange.endOffset, 5);
assert_equals(selection.anchorNode, innerHost.firstChild);
assert_equals(selection.anchorOffset, 5);
assert_equals(selection.focusNode, innerHost.firstChild);
assert_equals(selection.focusOffset, 5);
assert_equals(composedRange.startContainer, document);
assert_equals(composedRange.startOffset, 0);
assert_equals(composedRange.endContainer, innerHost.firstChild);
assert_equals(composedRange.endOffset, 5);
// Step 2: Update the live range by setting its start/focus
liveRange.setStart(light.firstChild, 10);
const composedRangeAfter = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
assert_equals(liveRange.startContainer, light.firstChild);
assert_equals(liveRange.startOffset, 10);
assert_equals(liveRange.endContainer, light.firstChild);
assert_equals(liveRange.endOffset, 10);
assert_equals(selection.anchorNode, light.firstChild);
assert_equals(selection.anchorOffset, 10);
assert_equals(selection.focusNode, light.firstChild);
assert_equals(selection.focusOffset, 10);
assert_equals(composedRangeAfter.startContainer, light.firstChild);
assert_equals(composedRangeAfter.startOffset, 10);
assert_equals(composedRangeAfter.endContainer, innerHost.firstChild);
assert_equals(composedRangeAfter.endOffset, 5);
}, 'modify createRange() range added to selection before setStart/setEnd calls.');
</script>