|
15 | 15 | const mode = (new URLSearchParams(document.location.search)).get("mode"); |
16 | 16 |
|
17 | 17 | test(() => { |
| 18 | + const sel = getSelection(); |
| 19 | + |
18 | 20 | container.innerHTML = 'a<div id="host"></div>b'; |
19 | 21 | const host = container.querySelector('#host'); |
20 | 22 | const shadowRoot = host.attachShadow({ mode }); |
21 | 23 | shadowRoot.innerHTML = 'hello, world'; |
22 | | - getSelection().setBaseAndExtent(shadowRoot.firstChild, 7, container, 2); |
23 | | - const rangeBefore = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
| 24 | + sel.setBaseAndExtent(shadowRoot.firstChild, 7, container, 2); |
| 25 | + const rangeBefore = sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
24 | 26 | host.remove(); |
25 | | - const rangeAfter = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
| 27 | + const rangeAfter = sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
26 | 28 |
|
27 | 29 | assert_equals(rangeBefore.startContainer, shadowRoot.firstChild, 'StaticRange does not update on new mutation.'); |
28 | 30 | assert_equals(rangeBefore.startOffset, 7); |
|
36 | 38 | }, 'Range is fully in shadow tree. Removing shadow host collapses composed StaticRange. Note it does not update previously returned composed StaticRange.'); |
37 | 39 |
|
38 | 40 | test(() => { |
| 41 | + const sel = getSelection(); |
| 42 | + |
39 | 43 | container.innerHTML = '<div id="wrapper">a<div id="host"></div>b</div>'; |
40 | 44 | const wrapper = container.querySelector('#wrapper'); |
41 | 45 | const host = container.querySelector('#host'); |
42 | 46 | const shadowRoot = host.attachShadow({ mode }); |
43 | 47 | shadowRoot.innerHTML = 'hello, world'; |
44 | | - getSelection().setBaseAndExtent(shadowRoot.firstChild, 4, shadowRoot.firstChild, 7); |
| 48 | + sel.setBaseAndExtent(shadowRoot.firstChild, 4, shadowRoot.firstChild, 7); |
45 | 49 | wrapper.remove(); |
46 | 50 |
|
47 | | - const rangeAfter = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
| 51 | + const rangeAfter = sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
48 | 52 | assert_equals(rangeAfter.startContainer, container, 'collapsed to parent of removed node'); |
49 | 53 | assert_equals(rangeAfter.startOffset, 0); |
50 | 54 | assert_equals(rangeAfter.endContainer, container); |
51 | 55 | assert_equals(rangeAfter.endOffset, 0); |
52 | 56 | }, 'Range is fully in shadow tree. Removing parent of shadow host collapses composed StaticRange.'); |
53 | 57 |
|
54 | 58 | test(() => { |
| 59 | + const sel = getSelection(); |
| 60 | + |
55 | 61 | container.innerHTML = '<div id="hello">Hello,</div><div id="world"> World</div>'; |
56 | | - getSelection().setBaseAndExtent(hello.firstChild, 1, world.firstChild, 3); |
| 62 | + sel.setBaseAndExtent(hello.firstChild, 1, world.firstChild, 3); |
57 | 63 | hello.firstChild.remove(); |
58 | | - const rangeAfter = getSelection().getComposedRanges()[0]; |
| 64 | + const rangeAfter = sel.getComposedRanges()[0]; |
59 | 65 |
|
60 | 66 | assert_equals(rangeAfter.startContainer, hello); |
61 | 67 | assert_equals(rangeAfter.startOffset, 0); |
|
64 | 70 | }, 'Range is in light DOM. Removing startContainer rescopes new composed range to its parent.'); |
65 | 71 |
|
66 | 72 | test(() => { |
67 | | - container.innerHTML = 'a<div id="host"></div>b'; |
| 73 | + const sel = getSelection(); |
| 74 | + |
| 75 | + container.innerHTML = 'a<div id="host"></div>b'; |
68 | 76 | const host = container.querySelector('#host'); |
69 | 77 | const shadowRoot = host.attachShadow({ mode }); |
70 | 78 | shadowRoot.innerHTML = 'hello, world'; |
71 | | - getSelection().setBaseAndExtent(shadowRoot.firstChild, 7, container, 2); |
| 79 | + sel.setBaseAndExtent(shadowRoot.firstChild, 7, container, 2); |
72 | 80 | shadowRoot.innerHTML = ''; |
73 | | - const rangeAfter = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
| 81 | + const rangeAfter = sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
74 | 82 |
|
75 | 83 | assert_equals(rangeAfter.startContainer, shadowRoot, 'collapsed to be at the parent shadow root'); |
76 | 84 | assert_equals(rangeAfter.startOffset, 0); |
77 | 85 | assert_equals(rangeAfter.endContainer, container); |
78 | 86 | assert_equals(rangeAfter.endOffset, 2); |
79 | 87 | }, 'Range is across shadow trees. Replacing shadowRoot content rescopes new composed range to the shadowRoot.'); |
80 | 88 |
|
| 89 | +test(() => { |
| 90 | + const sel = getSelection(); |
| 91 | + |
| 92 | + container.innerHTML = 'a<div id="outerhost"></div>b'; |
| 93 | + const outerHost = container.querySelector('#outerhost'); |
| 94 | + const outerRoot = outerHost.attachShadow({ mode }); |
| 95 | + outerRoot.innerHTML = 'c<div id="innerHost"></div>d'; |
| 96 | + const innerHost = outerRoot.querySelector('#innerHost'); |
| 97 | + const innerRoot = innerHost.attachShadow({ mode }); |
| 98 | + innerRoot.innerHTML = 'hello, world'; |
| 99 | + sel.setBaseAndExtent(container.firstChild, 0, innerRoot.firstChild, 4); |
| 100 | + outerHost.remove(); |
| 101 | + const rangeAfter = sel.getComposedRanges({ shadowRoots: [innerRoot, outerRoot] })[0]; |
| 102 | + |
| 103 | + assert_equals(rangeAfter.startContainer, container.firstChild); |
| 104 | + assert_equals(rangeAfter.startOffset, 0); |
| 105 | + assert_equals(rangeAfter.endContainer, container); |
| 106 | + assert_equals(rangeAfter.endOffset, 1); |
| 107 | +}, 'Range is across shadow trees. Removing ancestor shadow host rescopes composed range end to parent.'); |
| 108 | + |
81 | 109 | test(() => { |
82 | 110 | container.innerHTML = [ |
83 | 111 | '<div id=host>', |
|
98 | 126 | sel.setBaseAndExtent(div1.firstChild, 2, div2.firstChild, 2); |
99 | 127 | div1.remove(); |
100 | 128 |
|
101 | | - const rangeAfter = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
| 129 | + const rangeAfter = sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0]; |
102 | 130 | assert_equals(rangeAfter.startContainer, host); |
103 | 131 | assert_equals(rangeAfter.startOffset, 0); |
104 | 132 | assert_equals(rangeAfter.endContainer, div2.firstChild); |
|
0 commit comments