extend.js (7294B)
1 "use strict"; 2 3 // Also test a selection with no ranges 4 testRanges.unshift("[]"); 5 6 // Run a subset of all of extend tests. 7 // Huge number of tests in a single file causes problems. Each of 8 // extend-NN.html runs a part of them. 9 // 10 // startIndex - Start index in testRanges array 11 // optionalEndIndex - End index in testRanges array + 1. If this argument is 12 // omitted, testRanges.length is applied. 13 function testExtendSubSet(startIndex, optionalEndIndex) { 14 var endIndex = optionalEndIndex === undefined ? testRanges.length : optionalEndIndex; 15 if (startIndex < 0 || startIndex >= testRanges.length) 16 throw "Sanity check: Specified index is invalid."; 17 if (endIndex < 0 || endIndex > testRanges.length) 18 throw "Sanity check: Specified index is invalid."; 19 20 // We test Selections that go both forwards and backwards here. In the 21 // latter case we need to use extend() to force it to go backwards, which is 22 // fair enough, since that's what we're testing. We test collapsed 23 // selections only once. 24 for (var i = startIndex; i < endIndex; i++) { 25 var endpoints = eval(testRanges[i]); 26 // We can't test extend() with unselectable endpoints. 27 if (!isSelectableNode(endpoints[0]) || !isSelectableNode(endpoints[2])) 28 continue; 29 for (var j = 0; j < testPoints.length; j++) { 30 if (endpoints[0] == endpoints[2] 31 && endpoints[1] == endpoints[3]) { 32 // Test collapsed selections only once 33 test(function() { 34 setSelectionForwards(endpoints); 35 testExtend(endpoints, eval(testPoints[j])); 36 }, "extend() with range " + i + " " + testRanges[i] 37 + " and point " + j + " " + testPoints[j]); 38 } else { 39 test(function() { 40 setSelectionForwards(endpoints); 41 testExtend(endpoints, eval(testPoints[j])); 42 }, "extend() forwards with range " + i + " " + testRanges[i] 43 + " and point " + j + " " + testPoints[j]); 44 45 test(function() { 46 setSelectionBackwards(endpoints); 47 testExtend(endpoints, eval(testPoints[j])); 48 }, "extend() backwards with range " + i + " " + testRanges[i] 49 + " and point " + j + " " + testPoints[j]); 50 } 51 } 52 } 53 } 54 55 function testExtend(endpoints, target) { 56 assert_equals(getSelection().rangeCount, endpoints.length/4, 57 "Sanity check: rangeCount must be correct"); 58 59 var node = target[0]; 60 var offset = target[1]; 61 62 // "If node's root is not the document associated with the context object, 63 // abort these steps." 64 if (!document.contains(node)) { 65 assertSelectionNoChange(function() { 66 selection.extend(node, offset); 67 }); 68 return; 69 } 70 71 // "If the context object's range is null, throw an InvalidStateError 72 // exception and abort these steps." 73 if (getSelection().rangeCount == 0) { 74 assert_throws_dom("INVALID_STATE_ERR", function() { 75 selection.extend(node, offset); 76 }, "extend() when rangeCount is 0 must throw InvalidStateError"); 77 return; 78 } 79 80 assert_equals(getSelection().getRangeAt(0).startContainer, endpoints[0], 81 "Sanity check: startContainer must be correct"); 82 assert_equals(getSelection().getRangeAt(0).startOffset, endpoints[1], 83 "Sanity check: startOffset must be correct"); 84 assert_equals(getSelection().getRangeAt(0).endContainer, endpoints[2], 85 "Sanity check: endContainer must be correct"); 86 assert_equals(getSelection().getRangeAt(0).endOffset, endpoints[3], 87 "Sanity check: endOffset must be correct"); 88 89 // "Let anchor and focus be the context object's anchor and focus, and let 90 // new focus be the boundary point (node, offset)." 91 var anchorNode = getSelection().anchorNode; 92 var anchorOffset = getSelection().anchorOffset; 93 var focusNode = getSelection().focusNode; 94 var focusOffset = getSelection().focusOffset; 95 96 // "Let new range be a new range." 97 // 98 // We'll always be setting either new range's start or its end to new 99 // focus, so we'll always throw at some point. Test that now. 100 // 101 // From DOM4's "set the start or end of a range": "If node is a doctype, 102 // throw an "InvalidNodeTypeError" exception and terminate these steps." 103 if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { 104 assert_throws_dom("INVALID_NODE_TYPE_ERR", function() { 105 selection.extend(node, offset); 106 }, "extend() to a doctype must throw InvalidNodeTypeError"); 107 return; 108 } 109 110 // From DOM4's "set the start or end of a range": "If offset is greater 111 // than node's length, throw an "IndexSizeError" exception and terminate 112 // these steps." 113 // 114 // FIXME: We should be casting offset to an unsigned int per WebIDL. Until 115 // we do, we need the offset < 0 check too. 116 if (offset < 0 || offset > getNodeLength(node)) { 117 assert_throws_dom("INDEX_SIZE_ERR", function() { 118 selection.extend(node, offset); 119 }, "extend() to an offset that's greater than node length (" + getNodeLength(node) + ") must throw IndexSizeError"); 120 return; 121 } 122 123 // Now back to the editing spec. 124 var originalRange = getSelection().getRangeAt(0); 125 126 // "If node's root is not the same as the context object's range's root, 127 // set new range's start and end to (node, offset)." 128 // 129 // "Otherwise, if anchor is before or equal to new focus, set new range's 130 // start to anchor, then set its end to new focus." 131 // 132 // "Otherwise, set new range's start to new focus, then set its end to 133 // anchor." 134 // 135 // "Set the context object's range to new range." 136 // 137 // "If new focus is before anchor, set the context object's direction to 138 // backwards. Otherwise, set it to forwards." 139 // 140 // The upshot of all these is summed up by just testing the anchor and 141 // offset. 142 getSelection().extend(node, offset); 143 144 if (furthestAncestor(anchorNode) == furthestAncestor(node)) { 145 assert_equals(getSelection().anchorNode, anchorNode, 146 "anchorNode must not change if the node passed to extend() has the same root as the original range"); 147 assert_equals(getSelection().anchorOffset, anchorOffset, 148 "anchorOffset must not change if the node passed to extend() has the same root as the original range"); 149 } else { 150 assert_equals(getSelection().anchorNode, node, 151 "anchorNode must be the node passed to extend() if it has a different root from the original range"); 152 assert_equals(getSelection().anchorOffset, offset, 153 "anchorOffset must be the offset passed to extend() if the node has a different root from the original range"); 154 } 155 assert_equals(getSelection().focusNode, node, 156 "focusNode must be the node passed to extend()"); 157 assert_equals(getSelection().focusOffset, offset, 158 "focusOffset must be the offset passed to extend()"); 159 assert_not_equals(getSelection().getRangeAt(0), originalRange, 160 "extend() must replace any existing range with a new one, not mutate the existing one"); 161 }