4 <title>Range merging with Selection.addRange()
</title>
5 <script src=
"../../resources/js-test.js"></script>
9 description('Selection.addRange() should properly merge intersecting (and don\'t merge discrete) ranges.');
11 var selection
= window
.getSelection();
14 function createPosition(container
, offset
)
16 return {'container': container
, 'offset': offset
};
19 function createRange(startPosition
, endPosition
)
21 var range
= new Range();
22 range
.setStart(startPosition
.container
, startPosition
.offset
);
23 range
.setEnd(endPosition
.container
, endPosition
.offset
);
27 function nodeToString(node
)
29 switch (node
.nodeType
) {
30 case Node
.ELEMENT_NODE
:
31 return '[<' + node
.tagName
+ '>: #' + node
.id
+ ']';
33 return '[Text: ' + node
.data
+ ']';
35 return node
.toString();
39 function positionToString(position
)
41 return '(' + nodeToString(position
.container
) + ', ' + position
.offset
+ ')';
44 function selectionShouldBe(expectedStartPosition
, expectedEndPosition
)
46 var range
= selection
.getRangeAt(0);
47 var actualStartPosition
= createPosition(range
.startContainer
, range
.startOffset
);
48 var actualEndPosition
= createPosition(range
.endContainer
, range
.endOffset
);
49 if (actualStartPosition
.container
=== expectedStartPosition
.container
50 && actualStartPosition
.offset
=== expectedStartPosition
.offset
51 && actualEndPosition
.container
=== expectedEndPosition
.container
52 && actualEndPosition
.offset
=== expectedEndPosition
.offset
) {
53 testPassed('Selection was: start = ' + positionToString(expectedStartPosition
) + ', end = ' + positionToString(expectedEndPosition
));
55 testFailed('Selection should be: start = ' + positionToString(expectedStartPosition
) + ', end = ' + positionToString(expectedEndPosition
) + '\nbut was: start = ' + positionToString(actualStartPosition
) + ', end = ' + positionToString(actualEndPosition
));
59 function runSingleTest(testFunction
, initializePositionsFunction
, containerIsEditable
)
61 selection
.removeAllRanges();
62 var container
= document
.createElement('div');
63 container
.id
= 'container';
64 if (containerIsEditable
)
65 container
.contentEditable
= true;
66 document
.body
.appendChild(container
);
67 var positions
= initializePositionsFunction(container
);
68 debug('Running: ' + testFunction
.name
+ ' (initializePositionsFunction = ' + initializePositionsFunction
.name
+ ', containerIsEditable = ' + containerIsEditable
+ ')');
69 testFunction(positions
);
70 document
.body
.removeChild(container
);
75 // To have better coverage over the possible code paths, each test is parametarized over four document positions;
76 // these positions are guaranteed to be ordered in the document order, but each position may vary in each test run.
78 // You can assume the selection is cleared before each test run.
80 function testExpandLeftToRight(positions
)
82 selection
.addRange(createRange(positions
[0], positions
[2]));
83 selection
.addRange(createRange(positions
[1], positions
[3]));
84 selectionShouldBe(positions
[0], positions
[3]);
87 function testExpandRightToLeft(positions
)
89 selection
.addRange(createRange(positions
[1], positions
[3]));
90 selection
.addRange(createRange(positions
[0], positions
[2]));
91 selectionShouldBe(positions
[0], positions
[3]);
94 function testExpandLeftToRightAdjacent(positions
)
96 selection
.addRange(createRange(positions
[1], positions
[2]));
97 selection
.addRange(createRange(positions
[2], positions
[3]));
98 selectionShouldBe(positions
[1], positions
[3]);
101 function testExpandRightToLeftAdjacent(positions
)
103 selection
.addRange(createRange(positions
[1], positions
[2]));
104 selection
.addRange(createRange(positions
[0], positions
[1]));
105 selectionShouldBe(positions
[0], positions
[2]);
108 function testExpandBothEnds(positions
)
110 selection
.addRange(createRange(positions
[1], positions
[2]));
111 selection
.addRange(createRange(positions
[0], positions
[3]));
112 selectionShouldBe(positions
[0], positions
[3]);
115 function testDontExpand(positions
)
117 selection
.addRange(createRange(positions
[0], positions
[3]));
118 selection
.addRange(createRange(positions
[1], positions
[2]));
119 selectionShouldBe(positions
[0], positions
[3]);
122 function testAddSameRange(positions
)
124 selection
.addRange(createRange(positions
[1], positions
[2]));
125 selection
.addRange(createRange(positions
[1], positions
[2]));
126 selectionShouldBe(positions
[1], positions
[2]);
129 function testRejectDistantRangeAtRight(positions
)
131 selection
.addRange(createRange(positions
[0], positions
[1]));
132 selection
.addRange(createRange(positions
[2], positions
[3]));
133 selectionShouldBe(positions
[0], positions
[1]);
136 function testRejectDistantRangeAtLeft(positions
)
138 selection
.addRange(createRange(positions
[2], positions
[3]));
139 selection
.addRange(createRange(positions
[0], positions
[1]));
140 selectionShouldBe(positions
[2], positions
[3]);
143 function testRejectDistantCollapsedRangeAtRight(positions
)
145 selection
.addRange(createRange(positions
[0], positions
[1]));
146 selection
.addRange(createRange(positions
[2], positions
[2]));
147 selectionShouldBe(positions
[0], positions
[1]);
150 function testRejectDistantCollapsedRangeAtLeft(positions
)
152 selection
.addRange(createRange(positions
[2], positions
[3]));
153 selection
.addRange(createRange(positions
[1], positions
[1]));
154 selectionShouldBe(positions
[2], positions
[3]);
157 // Position initializers:
159 // Each initializer function takes an argument |container| which denotes the root element which can be filled with
160 // arbitrary contents. This element is created and added to the document before each test run, and removed from
161 // the document after each test run.
163 function initializeTextPositions(container
)
165 container
.innerHTML
= '12345';
166 var text
= container
.firstChild
;
167 return [createPosition(text
, 1), createPosition(text
, 2), createPosition(text
, 3), createPosition(text
, 4)];
170 function initializeOuterElementPositions(container
)
172 container
.innerHTML
= '<span id="a">1</span><span id="b">2</span><span id="c">3</span><span id="d">4</span><span id="e">5</span>';
173 return [createPosition(container
, 1), createPosition(container
, 2), createPosition(container
, 3), createPosition(container
, 4)];
176 function initializeInnerElementPositions(container
)
178 container
.innerHTML
= '<span id="a">1</span><span id="b">2</span><span id="c">3</span><span id="d">4</span><span id="e">5</span>';
179 return [createPosition(container
.childNodes
[1], 0), createPosition(container
.childNodes
[2], 0), createPosition(container
.childNodes
[3], 0), createPosition(container
.childNodes
[4], 0)];
182 function initializeVisiblyEquivalentPositionsBeforeNodes(container
)
184 container
.innerHTML
= '<span id="a"><span id="b"><span id="c"></span></span></span>';
185 return [createPosition(container
, 0), createPosition(container
.firstChild
, 0), createPosition(container
.firstChild
.firstChild
, 0), createPosition(container
.firstChild
.firstChild
.firstChild
, 0)];
188 function initializeVisiblyEquivalentPositionsAfterNodes(container
)
190 container
.innerHTML
= '<span id="a"><span id="b"><span id="c"></span></span></span>';
191 return [createPosition(container
.firstChild
.firstChild
.firstChild
, 0), createPosition(container
.firstChild
.firstChild
, 1), createPosition(container
.firstChild
, 1), createPosition(container
, 1)];
195 testExpandLeftToRight
,
196 testExpandRightToLeft
,
197 testExpandLeftToRightAdjacent
,
198 testExpandRightToLeftAdjacent
,
202 testRejectDistantRangeAtRight
,
203 testRejectDistantRangeAtLeft
,
204 testRejectDistantCollapsedRangeAtRight
,
205 testRejectDistantCollapsedRangeAtLeft
207 var positionInitializers
= [
208 initializeTextPositions
,
209 initializeOuterElementPositions
,
210 initializeInnerElementPositions
,
211 initializeVisiblyEquivalentPositionsBeforeNodes
,
212 initializeVisiblyEquivalentPositionsAfterNodes
215 tests
.forEach(function (testFunction
) {
216 positionInitializers
.forEach(function (initializePositionsFunction
) {
217 [false, true].forEach(function (containerIsEditable
) {
218 runSingleTest(testFunction
, initializePositionsFunction
, containerIsEditable
);