|
1 <!DOCTYPE HTML> |
|
2 <html> |
|
3 <!-- |
|
4 https://bugzilla.mozilla.org/show_bug.cgi?id=496275 |
|
5 --> |
|
6 |
|
7 <head> |
|
8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
|
9 <title>Test for Bug 496275</title> |
|
10 <script type="application/javascript" src="/MochiKit/MochiKit.js"></script> |
|
11 <script type="application/javascript" |
|
12 src="/tests/SimpleTest/SimpleTest.js"></script> |
|
13 <script type="application/javascript" |
|
14 src="/tests/SimpleTest/WindowSnapshot.js"></script> |
|
15 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> |
|
16 </head> |
|
17 |
|
18 <body onload="run()"> |
|
19 <a target="_blank" |
|
20 href="https://bugzilla.mozilla.org/show_bug.cgi?id=496275"> |
|
21 Mozilla Bug 496275 |
|
22 </a> |
|
23 <p id="display"></p> |
|
24 <div id="c" contenteditable="true"> |
|
25 <p id="p1">The first paragraph. Another sentence. Even more text.</p> |
|
26 <p id="p2">Paragraph no. 2.</p> |
|
27 <p id="p3">This paragraph<br> |
|
28 is broken up<br> |
|
29 into four<br> |
|
30 lines</p> |
|
31 </div> |
|
32 |
|
33 <div id="ltr" contenteditable="true"> |
|
34 <p id="l1">םלש Hello</p> |
|
35 <p id="l2">Goodbye</p> |
|
36 </div> |
|
37 |
|
38 <div id="rtl" contenteditable="true" dir="rtl"> |
|
39 <p id="r1">התרגום האחרון שפיתחנו הוא עבור Firefox 3.5.6.</p> |
|
40 <p id="r2">קראו את הערות ההפצה (אנגלית) להוראות ורשימת בעיות ידועות.</p> |
|
41 </div> |
|
42 |
|
43 <!-- Special characters: لا is actually two characters, while تَ should be |
|
44 treated as one character. --> |
|
45 <div id="special" contenteditable="true"> |
|
46 <p id="s1">a لا b تَ c</p> |
|
47 </div> |
|
48 |
|
49 <div> |
|
50 <p>Anchor offset: <span id="anchor-offset"></span></p> |
|
51 <p>Focus offset: <span id="focus-offset"></span></p> |
|
52 </div> |
|
53 |
|
54 <script type="application/javascript"> |
|
55 SimpleTest.waitForExplicitFinish(); |
|
56 |
|
57 function isOrIsParent(actual, expected, msg) { |
|
58 // actual should be expected or actual's parent node should be expected. |
|
59 msg += " Expected " + actual + " or " + actual.parentNode + |
|
60 " to be " + expected + "."; |
|
61 |
|
62 ok(actual == expected || actual.parentNode == expected, msg); |
|
63 } |
|
64 |
|
65 function isAt(anchorNode, anchorOffset, focusNode, focusOffset, msg) { |
|
66 var sel = window.getSelection(); |
|
67 |
|
68 isOrIsParent(sel.anchorNode, $(anchorNode), msg + ": Wrong anchor node."); |
|
69 is(sel.anchorOffset, anchorOffset, msg + ": Wrong anchor offset."); |
|
70 isOrIsParent(sel.focusNode, $(focusNode), msg + ": Wrong focus node."); |
|
71 is(sel.focusOffset, $(focusOffset), msg + ": Wrong focus offset."); |
|
72 } |
|
73 |
|
74 function run() { |
|
75 var sel = window.getSelection(); |
|
76 |
|
77 // If nothing is focused, selection.modify() should silently fail. |
|
78 sel.removeAllRanges(); |
|
79 sel.modify("move", "forward", "character"); |
|
80 |
|
81 // Now focus our first div and put the cursor at the beginning of p1. |
|
82 $("c").focus(); |
|
83 sel.collapse($("p1"), 0); |
|
84 |
|
85 // We're intentionally inconsistent with the capitalization of "move", |
|
86 // "extend", etc. below to test the case-insensitivity of modify(). |
|
87 |
|
88 // If we move backward, selection.modify() shouldn't do anything, since we're |
|
89 // already at the beginning of the frame. |
|
90 isAt("p1", 0, "p1", 0, "test 0a"); |
|
91 sel.modify("Move", "Backward", "Character"); |
|
92 isAt("p1", 0, "p1", 0, "test 0b"); |
|
93 |
|
94 // After this move, the cursor should be at the second character of p1 |
|
95 sel.modify("Move", "Forward", "Character"); |
|
96 isAt("p1", 1, "p1", 1, "test 1"); |
|
97 |
|
98 // Select the first character in p1 |
|
99 sel.collapse($("p1"), 0); |
|
100 sel.modify("Extend", "Forward", "Character"); |
|
101 isAt("p1", 0, "p1", 1, "test 2"); |
|
102 sel.modify("Move", "Forward", "Character"); |
|
103 isAt("p1", 2, "p1", 2, "test 2a"); |
|
104 |
|
105 // Select all of p1, then move the selection forward one character a few |
|
106 // times. |
|
107 sel.collapse($("p1"), 0); |
|
108 sel.extend($("p1"), 1); |
|
109 sel.modify("move", "forward", "character"); |
|
110 isAt("p2", 0, "p2", 0, "test 3a"); |
|
111 sel.modify("move", "forward", "character"); |
|
112 isAt("p2", 1, "p2", 1, "test 3b"); |
|
113 |
|
114 // Put the cursor at the beginning of p3, then extend forward one line. |
|
115 // Now go back twice and forward once. Focus should now be at the end of p3. |
|
116 sel.collapse($("p3"), 0); |
|
117 sel.modify("Extend", "Forward", "Line"); |
|
118 sel.modify("extend", "backward", "character"); |
|
119 sel.modify("extend", "backward", "character"); |
|
120 sel.modify("extend", "forward", "character"); |
|
121 isAt("p3", 0, "p3", 14, "test 4"); |
|
122 |
|
123 // Put the cursor at the beginning of p3, then go forward a few words |
|
124 sel.collapse($("p3"), 0); |
|
125 sel.modify("Move", "Forward", "Word"); |
|
126 isAt("p3", 4, "p3", 4, "test 4a"); |
|
127 sel.modify("move", "forward", "word"); |
|
128 // Go back and forward so the indexes are correct. |
|
129 sel.modify("move", "backward", "character"); |
|
130 sel.modify("move", "forward", "character"); |
|
131 isAt("p3", 14, "p3", 14, "test 4b"); |
|
132 |
|
133 // Test the lineboundary granularity |
|
134 sel.collapse($("p3"), 0); |
|
135 sel.modify("Move", "Forward", "Lineboundary"); |
|
136 // Go back and forward so the indexes are correct. |
|
137 sel.modify("move", "Backward", "character"); |
|
138 sel.modify("move", "forward", "character"); |
|
139 isAt("p3", 14, "p3", 14, "test 5"); |
|
140 |
|
141 // |
|
142 // Test RTL text within a dir=LTR div. |
|
143 // |
|
144 $("ltr").focus(); |
|
145 sel.collapse($("l1"), 0); |
|
146 isAt("l1", 0, "l1", 0, "test 6a"); |
|
147 sel.modify("Move", "Left", "Character"); |
|
148 isAt("l1", 1, "l1", 1, "test 6b"); |
|
149 sel.modify("Extend", "Backward", "Character"); |
|
150 isAt("l1", 1, "l1", 0, "test 6c"); |
|
151 sel.modify("extend", "forward", "character"); |
|
152 isAt("l1", 1, "l1", 1, "test 6d"); |
|
153 sel.modify("Extend", "Right", "Character"); |
|
154 isAt("l1", 1, "l1", 0, "test 6e"); |
|
155 |
|
156 sel.collapse($("l1"), 0); |
|
157 sel.modify("move", "left", "character"); |
|
158 sel.modify("extend", "right", "Word"); |
|
159 isAt("l1", 1, "l1", 3, "test 7a"); |
|
160 sel.modify("move", "left", "word"); |
|
161 isAt("l1", 3, "l1", 3, "test 7b"); |
|
162 sel.modify("move", "forward", "word"); |
|
163 isAt("l1", 9, "l1", 9, "test 7c"); |
|
164 sel.modify("extend", "backward", "word"); |
|
165 isAt("l1", 9, "l1", 4, "test 7d"); |
|
166 sel.modify("move", "left", "word"); |
|
167 isAt("l1", 3, "l1", 3, "test 7e"); |
|
168 |
|
169 sel.collapse($("l1"), 0); |
|
170 sel.modify("extend", "left", "lineboundary"); |
|
171 isAt("l1", 0, "l1", 3, "test 8a"); |
|
172 sel.modify("move", "forward", "lineboundary"); |
|
173 isAt("l1", 9, "l1", 9, "test 8b"); |
|
174 sel.modify("extend", "backward", "lineboundary"); |
|
175 isAt("l1", 9, "l1", 0, "test 8c"); |
|
176 sel.modify("move", "left", "lineboundary"); |
|
177 isAt("l1", 3, "l1", 3, "test 8d"); |
|
178 sel.modify("extend", "forward", "lineboundary"); |
|
179 isAt("l1", 3, "l1", 9, "test 8e"); |
|
180 |
|
181 // Put the cursor at the left edge of the first line so that when we go up |
|
182 // and down, where we end up doesn't depend on how the characters line up. |
|
183 sel.collapse($("l1"), 0); |
|
184 sel.modify("move", "left", "lineboundary"); |
|
185 isAt("l1", 3, "l1", 3, "test 9a"); |
|
186 sel.modify("move", "forward", "Line"); |
|
187 isAt("l2", 0, "l2", 0, "test 9b"); |
|
188 sel.modify("extend", "backward", "Line"); |
|
189 // Apparently going up from the beginning of the line takes us to offset 3 in |
|
190 // the line above. This is a little weird, but it's consistent with how the |
|
191 // keyboard works. |
|
192 isAt("l2", 0, "l1", 3, "test 9c"); |
|
193 |
|
194 // Same test as above, now with absolute directions. |
|
195 sel.collapse($("l1"), 0); |
|
196 sel.modify("move", "left", "lineboundary"); |
|
197 isAt("l1", 3, "l1", 3, "test 10a"); |
|
198 sel.modify("move", "right", "line"); |
|
199 isAt("l2", 0, "l2", 0, "test 10b"); |
|
200 sel.modify("extend", "left", "line"); |
|
201 isAt("l2", 0, "l1", 3, "test 10c"); |
|
202 |
|
203 // |
|
204 // Test RTL text within a dir=RTL div. |
|
205 // |
|
206 $("rtl").focus(); |
|
207 sel.collapse($("r1"), 0); |
|
208 sel.modify("move", "forward", "character"); |
|
209 isAt("r1", 1, "r1", 1, "test 11a"); |
|
210 sel.modify("extend", "backward", "character"); |
|
211 isAt("r1", 1, "r1", 0, "test 11b"); |
|
212 sel.modify("move", "forward", "word"); |
|
213 isAt("r1", 6, "r1", 6, "test 11c"); |
|
214 sel.modify("extend", "backward", "word"); |
|
215 isAt("r1", 6, "r1", 0, "test 11d"); |
|
216 sel.modify("extend", "forward", "lineboundary"); |
|
217 isAt("r1", 6, "r1", 45, "test 11e"); |
|
218 |
|
219 // Same as above, but with absolute directions. |
|
220 sel.collapse($("r1"), 0); |
|
221 sel.modify("move", "left", "character"); |
|
222 isAt("r1", 1, "r1", 1, "test 12a"); |
|
223 sel.modify("extend", "right", "character"); |
|
224 isAt("r1", 1, "r1", 0, "test 12b"); |
|
225 sel.modify("move", "left", "word"); |
|
226 isAt("r1", 6, "r1", 6, "test 12c"); |
|
227 sel.modify("extend", "right", "word"); |
|
228 isAt("r1", 6, "r1", 0, "test 12d"); |
|
229 |
|
230 // Test that move left/right is correct within the RTL div. |
|
231 sel.collapse($("r1"), 0); |
|
232 sel.modify("extend", "left", "lineboundary"); |
|
233 isAt("r1", 0, "r1", 45, "test 13a"); |
|
234 sel.modify("move", "right", "lineboundary"); |
|
235 isAt("r1", 0, "r1", 0, "test 13b"); |
|
236 |
|
237 // Test that up/down at the first/last line correctly wraps to the |
|
238 // beginning/end of the line. |
|
239 sel.collapse($("r1"), 0); |
|
240 sel.modify("move", "forward", "word"); |
|
241 isAt("r1", 6, "r1", 6, "test 14a"); |
|
242 // Even in RTL text, "left" still means up. |
|
243 sel.modify("extend", "left", "Line"); |
|
244 isAt("r1", 6, "r1", 0, "test 14b"); |
|
245 sel.modify("move", "right", "line"); |
|
246 isAt("r2", 0, "r2", 0, "test 14c"); |
|
247 sel.modify("extend", "forward", "line"); |
|
248 isAt("r2", 0, "r2", 57, "test 14d"); |
|
249 sel.modify("move", "backward", "line"); |
|
250 isAt("r1", 45, "r1", 45, "test 14e"); |
|
251 |
|
252 // Test some special characters. |
|
253 $("special").focus(); |
|
254 sel.collapse($("s1"), 0); |
|
255 sel.modify("move", "forward", "character"); |
|
256 sel.modify("move", "forward", "character"); |
|
257 sel.modify("move", "forward", "character"); |
|
258 isAt("s1", 3, "s1", 3, "test 15a"); |
|
259 sel.modify("move", "forward", "character"); |
|
260 isAt("s1", 4, "s1", 4, "test 15b"); |
|
261 sel.modify("move", "backward", "word"); |
|
262 isAt("s1", 2, "s1", 2, "test 15c"); |
|
263 sel.modify("move", "forward", "word"); |
|
264 sel.modify("move", "forward", "word"); |
|
265 sel.modify("move", "forward", "word"); |
|
266 isAt("s1", 9, "s1", 9, "test 15d"); |
|
267 |
|
268 SimpleTest.finish(); |
|
269 } |
|
270 |
|
271 function update_debug_info() { |
|
272 var sel = window.getSelection(); |
|
273 document.getElementById("anchor-offset").innerHTML = sel.anchorOffset; |
|
274 document.getElementById("focus-offset").innerHTML = sel.focusOffset; |
|
275 setTimeout(update_debug_info, 100); |
|
276 } |
|
277 |
|
278 setTimeout(update_debug_info, 100); |
|
279 |
|
280 </script> |
|
281 </body> |
|
282 </html> |