2 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5 -webkit-user-modify: read-write;
7 border: 1px dashed lightblue;
8 margin: 4px 4px 4px 24px;
10 font-family: Lucida Grande;
11 counter-increment: test-number;
13 div.test:before { content: counter(test-number); position: absolute; left: 8px; font-size: x-small; text-align: right; width: 20px; }
14 div.test span { background-color: #def; }
15 div.test img { width: 1em; height: 1em; background-color: lightgreen; }
16 div.test img + img { background-color: lightblue; }
17 div.test div { border: 1px dashed pink; padding: 3px; height: 2em; }
24 messages.push(message);
29 document.getElementById("console").appendChild(document.createTextNode(messages.join("")));
32 function caretCoordinates()
34 if (!window.textInputController)
35 return { x: 0, y :0 };
36 var caretRect = textInputController.firstRectForCharacterRange(textInputController.selectedRange()[0], 0);
37 return { x: caretRect[0], y: caretRect[1] };
40 function positionsMovingInDirection(sel, direction)
44 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });
45 sel.modify("move", direction, "character");
46 if (positions[positions.length - 1].node == sel.anchorNode && positions[positions.length - 1].offset == sel.anchorOffset)
55 for (var i = 0; i < string.length; ++i) {
56 var char = string.charCodeAt(i);
57 if (char >= 0x0660) // Arabic numeral 0
58 char = char - 0x660 + '0'.charCodeAt(0);
59 else if (char >= 0x0627) // Alif
60 char = char - 0x0627 + 'A'.charCodeAt(0);
61 else if (char >= 0x05d0)
63 else if (char == 10) {
67 result += String.fromCharCode(char);
72 function logPositions(positions)
74 for (var i = 0; i < positions.length; ++i) {
76 if (positions[i].node != positions[i - 1].node)
80 if (!i || positions[i].node != positions[i - 1].node)
81 log((positions[i].node instanceof Text ? '"' + fold(positions[i].node.data) + '"' : "<" + positions[i].node.tagName + ">") + "[");
82 log(positions[i].offset);
87 function checkReverseOrder(positions, reversePositions)
89 var mismatch = positions.length != reversePositions.length;
91 var pos = positions.pop();
94 var reversePos = reversePositions.shift();
95 if (pos.node != reversePos.node || pos.offset != reversePos.offset)
100 log("WARNING: Moving to the left did not visit the same positions in reverse order as moving to the right.\n");
103 function checkCoordinatesMovingRightDown(positions)
105 for (var i = 1; i < positions.length; ++i) {
106 if (positions[i].point.y > positions[i - 1].point.y || positions[i].point.x < positions[i - 1].point.x && positions[i].point.y >= positions[i - 1].point.y)
107 log("WARNING: Moved in the wrong direction in step " + i + ": from (" + positions[i - 1].point.x + ", " + positions[i - 1].point.y + ") to (" + positions[i].point.x + ", " + positions[i].point.y + ").\n");
111 function checkCoordinatesMovingLeftDown(positions)
113 for (var i = 1; i < positions.length; ++i) {
114 if (positions[i].point.y > positions[i - 1].point.y || positions[i].point.x > positions[i - 1].point.x && positions[i].point.y >= positions[i - 1].point.y)
115 log("WARNING: Moved in the wrong direction in step " + i + ": from (" + positions[i - 1].point.x + ", " + positions[i - 1].point.y + ") to (" + positions[i].point.x + ", " + positions[i].point.y + ").\n");
119 function checkCoordinatesMovingRightUp(positions)
121 for (var i = 1; i < positions.length; ++i) {
122 if (positions[i].point.y < positions[i - 1].point.y || positions[i].point.x < positions[i - 1].point.x && positions[i].point.y <= positions[i - 1].point.y)
123 log("WARNING: Moved in the wrong direction in step " + i + ": from (" + positions[i - 1].point.x + ", " + positions[i - 1].point.y + ") to (" + positions[i].point.x + ", " + positions[i].point.y + ").\n");
127 function checkCoordinatesMovingLeftUp(positions)
129 for (var i = 1; i < positions.length; ++i) {
130 if (positions[i].point.y < positions[i - 1].point.y || positions[i].point.x > positions[i - 1].point.x && positions[i].point.y <= positions[i - 1].point.y)
131 log("WARNING: Moved in the wrong direction in step " + i + ": from (" + positions[i - 1].point.x + ", " + positions[i - 1].point.y + ") to (" + positions[i].point.x + ", " + positions[i].point.y + ").\n");
137 var tests = document.getElementsByClassName("test");
138 var sel = getSelection();
139 for (var i = 0; i < tests.length; ++i) {
140 var positionsMovingRight;
141 var positionsMovingLeft;
143 log("Test " + (i + 1) + ", LTR:\n Moving right: ");
144 sel.collapse(tests[i], 0);
145 positionsMovingRight = positionsMovingInDirection(sel, "right");
146 logPositions(positionsMovingRight);
148 checkCoordinatesMovingRightDown(positionsMovingRight);
150 log(" Moving left: ");
151 positionsMovingLeft = positionsMovingInDirection(sel, "left");
152 logPositions(positionsMovingLeft);
154 checkCoordinatesMovingLeftUp(positionsMovingLeft);
156 checkReverseOrder(positionsMovingLeft, positionsMovingRight);
158 tests[i].style.direction = "rtl";
160 log("Test " + (i + 1) + ", RTL:\n Moving left: ");
161 sel.collapse(tests[i], 0);
162 positionsMovingLeft = positionsMovingInDirection(sel, "left");
163 logPositions(positionsMovingLeft);
165 checkCoordinatesMovingLeftDown(positionsMovingLeft);
167 log(" Moving right: ");
168 positionsMovingRight = positionsMovingInDirection(sel, "right");
169 logPositions(positionsMovingRight);
171 checkCoordinatesMovingRightUp(positionsMovingRight);
173 checkReverseOrder(positionsMovingLeft, positionsMovingRight);
176 document.getElementById("testGroup").style.display = "none";
179 onload = function() {
187 if (window.testRunner)
188 testRunner.dumpAsText();
202 <div class="test"><br>abc
205 <div class="test"><br>אבג
224 <div class="test">١٢٣ابة</div>
226 <div class="test">ابة١٢٣</div>
229 <span>abc</span>אבגdef
233 <span>אבג</span>abcדהו
236 <div class="test">abcאבג123דהוdef
239 <div class="test">abcאבג123
242 <div class="test">abcאבג123def
245 <div class="test">אבג123דהוabcזחט456יכל
248 <div class="test" style="width: 120px;">
249 before אחרי אנציקלופדיה
252 <div class="test" style="width: 120px;">
253 לפני after encyclopedia
256 <div class="test" contenteditable style="width: 120px;">
257 before אחרי אנציקלופדיה
260 <div class="test" contenteditable style="width: 120px;">
261 לפני after encyclopedia
264 <div class="test" style="width: 100px;">
265 This is יותר צר מיתר the boxes.
268 <div contenteditable class="test" style="width: 100px;">
269 This is יותר צר מיתר the boxes.
293 abc<input>אבג<img><img>דהוghi
297 אבג<input>abc<img><img>defדהו
301 abcאבג<span>דהו</span>
305 אבגabc<span>def</span>
309 ab<span>cאבגdef</span>
313 אב<span>גabcדהו</span>
317 abc<span>אבגdef</span>
321 אבג<span>abcדהו</span>
333 abcאבג<span>def</span>
337 אבגabc<span>דהו</span>
341 abcא<span>בגdef</span>
345 אבגa<span>bcדהו</span>
348 <div class="test" style="white-space: pre;">abc<!-- -->
351 <div class="test" style="white-space: pre;">אבג<!-- -->
355 <span dir="rtl">abcקקק123נננdef</span>
360 <pre id="console"></pre>