|
1 <html> |
|
2 |
|
3 <head> |
|
4 <title>Accessible mutation events testing</title> |
|
5 |
|
6 <link rel="stylesheet" type="text/css" |
|
7 href="chrome://mochikit/content/tests/SimpleTest/test.css" /> |
|
8 |
|
9 <script type="application/javascript" |
|
10 src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> |
|
11 <script type="application/javascript" |
|
12 src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> |
|
13 |
|
14 <script type="application/javascript" |
|
15 src="../common.js"></script> |
|
16 <script type="application/javascript" |
|
17 src="../events.js"></script> |
|
18 |
|
19 <script type="application/javascript"> |
|
20 //////////////////////////////////////////////////////////////////////////// |
|
21 // Invokers |
|
22 |
|
23 /** |
|
24 * Base text remove invoker and checker. |
|
25 */ |
|
26 function textRemoveInvoker(aID, aStart, aEnd, aText) |
|
27 { |
|
28 this.DOMNode = getNode(aID); |
|
29 |
|
30 this.eventSeq = [ |
|
31 new textChangeChecker(aID, aStart, aEnd, aText, false) |
|
32 ]; |
|
33 } |
|
34 |
|
35 function textInsertInvoker(aID, aStart, aEnd, aText) |
|
36 { |
|
37 this.DOMNode = getNode(aID); |
|
38 |
|
39 this.eventSeq = [ |
|
40 new textChangeChecker(aID, aStart, aEnd, aText, true) |
|
41 ]; |
|
42 } |
|
43 |
|
44 /** |
|
45 * Remove inaccessible child node containing accessibles. |
|
46 */ |
|
47 function removeChildSpan(aID) |
|
48 { |
|
49 this.__proto__ = new textRemoveInvoker(aID, 0, 5, "33322"); |
|
50 |
|
51 this.invoke = function removeChildSpan_invoke() |
|
52 { |
|
53 // remove HTML span, a first child of the node |
|
54 this.DOMNode.removeChild(this.DOMNode.firstChild); |
|
55 } |
|
56 |
|
57 this.getID = function removeChildSpan_getID() |
|
58 { |
|
59 return "Remove inaccessible span containing accessible nodes" + prettyName(aID); |
|
60 } |
|
61 } |
|
62 |
|
63 /** |
|
64 * Insert inaccessible child node containing accessibles. |
|
65 */ |
|
66 function insertChildSpan(aID, aInsertAllTogether) |
|
67 { |
|
68 this.__proto__ = new textInsertInvoker(aID, 0, 5, "33322"); |
|
69 |
|
70 this.invoke = function insertChildSpan_invoke() |
|
71 { |
|
72 // <span><span>333</span><span>22</span></span> |
|
73 if (aInsertAllTogether) { |
|
74 var topSpan = document.createElement("span"); |
|
75 var fSpan = document.createElement("span"); |
|
76 fSpan.textContent = "333"; |
|
77 topSpan.appendChild(fSpan); |
|
78 var sSpan = document.createElement("span"); |
|
79 sSpan.textContent = "22"; |
|
80 topSpan.appendChild(sSpan); |
|
81 |
|
82 this.DOMNode.insertBefore(topSpan, this.DOMNode.childNodes[0]); |
|
83 |
|
84 } else { |
|
85 var topSpan = document.createElement("span"); |
|
86 this.DOMNode.insertBefore(topSpan, this.DOMNode.childNodes[0]); |
|
87 |
|
88 var fSpan = document.createElement("span"); |
|
89 fSpan.textContent = "333"; |
|
90 topSpan.appendChild(fSpan); |
|
91 |
|
92 var sSpan = document.createElement("span"); |
|
93 sSpan.textContent = "22"; |
|
94 topSpan.appendChild(sSpan); |
|
95 } |
|
96 } |
|
97 |
|
98 this.getID = function insertChildSpan_getID() |
|
99 { |
|
100 return "Insert inaccessible span containing accessibles" + |
|
101 prettyName(aID); |
|
102 } |
|
103 } |
|
104 |
|
105 /** |
|
106 * Remove child embedded accessible. |
|
107 */ |
|
108 function removeChildDiv(aID) |
|
109 { |
|
110 this.__proto__ = new textRemoveInvoker(aID, 5, 6, kEmbedChar); |
|
111 |
|
112 this.invoke = function removeChildDiv_invoke() |
|
113 { |
|
114 var childDiv = this.DOMNode.childNodes[1]; |
|
115 |
|
116 // Ensure accessible is created to get text remove event when it's |
|
117 // removed. |
|
118 getAccessible(childDiv); |
|
119 |
|
120 this.DOMNode.removeChild(childDiv); |
|
121 } |
|
122 |
|
123 this.getID = function removeChildDiv_getID() |
|
124 { |
|
125 return "Remove accessible div from the middle of text accessible " + |
|
126 prettyName(aID); |
|
127 } |
|
128 } |
|
129 |
|
130 /** |
|
131 * Insert child embedded accessible. |
|
132 */ |
|
133 function insertChildDiv(aID) |
|
134 { |
|
135 this.__proto__ = new textInsertInvoker(aID, 5, 6, kEmbedChar); |
|
136 |
|
137 this.invoke = function insertChildDiv_invoke() |
|
138 { |
|
139 var childDiv = document.createElement("div"); |
|
140 this.DOMNode.insertBefore(childDiv, this.DOMNode.childNodes[1]); |
|
141 } |
|
142 |
|
143 this.getID = function insertChildDiv_getID() |
|
144 { |
|
145 return "Insert accessible div into the middle of text accessible " + |
|
146 prettyName(aID); |
|
147 } |
|
148 } |
|
149 |
|
150 /** |
|
151 * Remove children from text container from first to last child or vice |
|
152 * versa. |
|
153 */ |
|
154 function removeChildren(aID, aLastToFirst, aStart, aEnd, aText) |
|
155 { |
|
156 this.__proto__ = new textRemoveInvoker(aID, aStart, aEnd, aText); |
|
157 |
|
158 this.invoke = function removeChildren_invoke() |
|
159 { |
|
160 if (aLastToFirst) { |
|
161 while (this.DOMNode.firstChild) |
|
162 this.DOMNode.removeChild(this.DOMNode.lastChild); |
|
163 } else { |
|
164 while (this.DOMNode.firstChild) |
|
165 this.DOMNode.removeChild(this.DOMNode.firstChild); |
|
166 } |
|
167 } |
|
168 |
|
169 this.getID = function removeChildren_getID() |
|
170 { |
|
171 return "remove children of " + prettyName(aID) + |
|
172 (aLastToFirst ? " from last to first" : " from first to last"); |
|
173 } |
|
174 } |
|
175 |
|
176 /** |
|
177 * Remove text from HTML input. |
|
178 */ |
|
179 function removeTextFromInput(aID, aStart, aEnd, aText) |
|
180 { |
|
181 this.__proto__ = new textRemoveInvoker(aID, aStart, aEnd, aText); |
|
182 |
|
183 this.eventSeq.push(new invokerChecker(EVENT_VALUE_CHANGE, this.DOMNode)); |
|
184 |
|
185 this.invoke = function removeTextFromInput_invoke() |
|
186 { |
|
187 const nsIDOMNSEditableElement = |
|
188 Components.interfaces.nsIDOMNSEditableElement; |
|
189 |
|
190 this.DOMNode.focus(); |
|
191 this.DOMNode.setSelectionRange(aStart, aEnd); |
|
192 |
|
193 synthesizeKey("VK_DELETE", {}); |
|
194 } |
|
195 |
|
196 this.getID = function removeTextFromInput_getID() |
|
197 { |
|
198 return "Remove text from " + aStart + " to " + aEnd + " for " + |
|
199 prettyName(aID); |
|
200 } |
|
201 } |
|
202 |
|
203 /** |
|
204 * Add text into HTML input. |
|
205 */ |
|
206 function insertTextIntoInput(aID, aStart, aEnd, aText) |
|
207 { |
|
208 this.__proto__ = new textInsertInvoker(aID, aStart, aEnd, aText); |
|
209 |
|
210 this.eventSeq.push(new invokerChecker(EVENT_VALUE_CHANGE, this.DOMNode)); |
|
211 |
|
212 this.invoke = function insertTextIntoInput_invoke() |
|
213 { |
|
214 this.DOMNode.focus(); |
|
215 synthesizeKey("a", {}); |
|
216 } |
|
217 |
|
218 this.getID = function insertTextIntoInput_getID() |
|
219 { |
|
220 return "Insert text to " + aStart + " for " + prettyName(aID); |
|
221 } |
|
222 } |
|
223 |
|
224 /** |
|
225 * Remove text data from text node of editable area. |
|
226 */ |
|
227 function removeTextFromEditable(aID, aStart, aEnd, aText, aTextNode) |
|
228 { |
|
229 this.__proto__ = new textRemoveInvoker(aID, aStart, aEnd, aText); |
|
230 |
|
231 this.invoke = function removeTextFromEditable_invoke() |
|
232 { |
|
233 this.DOMNode.focus(); |
|
234 |
|
235 var selection = window.getSelection(); |
|
236 var range = document.createRange(); |
|
237 range.setStart(this.textNode, aStart); |
|
238 range.setEnd(this.textNode, aEnd); |
|
239 selection.addRange(range); |
|
240 |
|
241 synthesizeKey("VK_DELETE", {}); |
|
242 } |
|
243 |
|
244 this.getID = function removeTextFromEditable_getID() |
|
245 { |
|
246 return "Remove text from " + aStart + " to " + aEnd + " for " + |
|
247 prettyName(aID); |
|
248 } |
|
249 |
|
250 this.textNode = getNode(aTextNode); |
|
251 } |
|
252 |
|
253 //////////////////////////////////////////////////////////////////////////// |
|
254 // Do tests |
|
255 var gQueue = null; |
|
256 //gA11yEventDumpID = "eventdump"; // debug stuff |
|
257 |
|
258 function doTests() |
|
259 { |
|
260 gQueue = new eventQueue(); |
|
261 |
|
262 // Text remove event on inaccessible child HTML span removal containing |
|
263 // accessible text nodes. |
|
264 gQueue.push(new removeChildSpan("p")); |
|
265 gQueue.push(new insertChildSpan("p"), true); |
|
266 gQueue.push(new insertChildSpan("p"), false); |
|
267 |
|
268 // Remove embedded character. |
|
269 gQueue.push(new removeChildDiv("div")); |
|
270 gQueue.push(new insertChildDiv("div")); |
|
271 |
|
272 // Remove all children. |
|
273 var text = kEmbedChar + "txt" + kEmbedChar; |
|
274 gQueue.push(new removeChildren("div2", true, 0, 5, text)); |
|
275 gQueue.push(new removeChildren("div3", false, 0, 5, text)); |
|
276 |
|
277 // Text remove from text node within hypertext accessible. |
|
278 gQueue.push(new removeTextFromInput("input", 1, 3, "al")); |
|
279 gQueue.push(new insertTextIntoInput("input", 1, 2, "a")); |
|
280 |
|
281 // bug 570691 |
|
282 todo(false, "Fix text change events from editable area, see bug 570691"); |
|
283 //var textNode = getNode("editable").firstChild; |
|
284 //gQueue.push(new removeTextFromEditable("editable", 1, 3, "al", textNode)); |
|
285 //textNode = getNode("editable2").firstChild.firstChild; |
|
286 //gQueue.push(new removeTextFromEditable("editable2", 1, 3, "al", textNode)); |
|
287 |
|
288 gQueue.invoke(); // Will call SimpleTest.finish(); |
|
289 } |
|
290 |
|
291 SimpleTest.waitForExplicitFinish(); |
|
292 addA11yLoadEvent(doTests); |
|
293 </script> |
|
294 </head> |
|
295 |
|
296 <body> |
|
297 |
|
298 <a target="_blank" |
|
299 href="https://bugzilla.mozilla.org/show_bug.cgi?id=566293" |
|
300 title=" wrong length of text remove event when inaccessible node containing accessible nodes is removed"> |
|
301 Mozilla Bug 566293 |
|
302 </a><br> |
|
303 <a target="_blank" |
|
304 href="https://bugzilla.mozilla.org/show_bug.cgi?id=570710" |
|
305 title="Avoid extra array traversal during text event creation"> |
|
306 Mozilla Bug 570710 |
|
307 </a><br> |
|
308 <a target="_blank" |
|
309 href="https://bugzilla.mozilla.org/show_bug.cgi?id=574003" |
|
310 title="Coalesce text events on nodes removal"> |
|
311 Mozilla Bug 574003 |
|
312 </a> |
|
313 <a target="_blank" |
|
314 href="https://bugzilla.mozilla.org/show_bug.cgi?id=575052" |
|
315 title="Cache text offsets within hypertext accessible"> |
|
316 Mozilla Bug 575052 |
|
317 </a> |
|
318 <a target="_blank" |
|
319 href="https://bugzilla.mozilla.org/show_bug.cgi?id=570275" |
|
320 title="Rework accessible tree update code"> |
|
321 Mozilla Bug 570275 |
|
322 </a> |
|
323 |
|
324 <p id="display"></p> |
|
325 <div id="content" style="display: none"></div> |
|
326 <pre id="test"> |
|
327 </pre> |
|
328 <div id="eventdump"></div> |
|
329 |
|
330 <p id="p"><span><span>333</span><span>22</span></span>1111</p> |
|
331 <div id="div">hello<div>hello</div>hello</div> |
|
332 <div id="div2"><div>txt</div>txt<div>txt</div></div> |
|
333 <div id="div3"><div>txt</div>txt<div>txt</div></div> |
|
334 <input id="input" value="value"> |
|
335 <div contentEditable="true" id="editable">value</div> |
|
336 <div contentEditable="true" id="editable2"><span>value</span></div> |
|
337 </body> |
|
338 </html> |