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>