Bug 1772588 [wpt PR 34302] - [wpt] Add test for block-in-inline offsetParent., a...
[gecko.git] / editor / libeditor / tests / test_nsITableEditor_insertTableRow.html
blobee47673445e3650d3bdc8346c055366065e41ab3
1 <!DOCTYPE>
2 <html>
3 <head>
4 <title>Test for nsITableEditor.insertTableRow()</title>
5 <script src="/tests/SimpleTest/SimpleTest.js"></script>
6 <link rel="stylesheet" href="/tests/SimpleTest/test.css">
7 </head>
8 <body>
9 <div id="display">
10 </div>
11 <div id="content" contenteditable>out of table<table><tr><td>default content</td></tr></table></div>
12 <pre id="test">
13 </pre>
15 <script class="testbody" type="application/javascript">
16 "use strict";
18 SimpleTest.waitForExplicitFinish();
19 SimpleTest.waitForFocus(() => {
20 let editor = document.getElementById("content");
21 let selection = document.getSelection();
22 let selectionRanges = [];
24 function checkInputEvent(aEvent, aDescription) {
25 ok(aEvent instanceof InputEvent,
26 `"${aEvent.type}" event should be dispatched with InputEvent interface ${aDescription}`);
27 is(aEvent.cancelable, false,
28 `"${aEvent.type}" event should be never cancelable ${aDescription}`);
29 is(aEvent.bubbles, true,
30 `"${aEvent.type}" event should always bubble ${aDescription}`);
31 is(aEvent.inputType, "",
32 `inputType of "${aEvent.type}" event should be empty string ${aDescription}`);
33 is(aEvent.data, null,
34 `data of "${aEvent.type}" event should be null ${aDescription}`);
35 is(aEvent.dataTransfer, null,
36 `dataTransfer of "${aEvent.type}" event should be null ${aDescription}`);
37 let targetRanges = aEvent.getTargetRanges();
38 if (aEvent.type === "beforeinput") {
39 is(targetRanges.length, selectionRanges.length,
40 `getTargetRanges() of "beforeinput" event should return selection ranges ${aDescription}`);
41 if (targetRanges.length === selectionRanges.length) {
42 for (let i = 0; i < selectionRanges.length; i++) {
43 is(targetRanges[i].startContainer, selectionRanges[i].startContainer,
44 `startContainer of getTargetRanges()[${i}] of "beforeinput" event does not match ${aDescription}`);
45 is(targetRanges[i].startOffset, selectionRanges[i].startOffset,
46 `startOffset of getTargetRanges()[${i}] of "beforeinput" event does not match ${aDescription}`);
47 is(targetRanges[i].endContainer, selectionRanges[i].endContainer,
48 `endContainer of getTargetRanges()[${i}] of "beforeinput" event does not match ${aDescription}`);
49 is(targetRanges[i].endOffset, selectionRanges[i].endOffset,
50 `endOffset of getTargetRanges()[${i}] of "beforeinput" event does not match ${aDescription}`);
53 } else {
54 is(targetRanges.length, 0,
55 `getTargetRanges() of "${aEvent.type}" event should return empty array ${aDescription}`);
59 let beforeInputEvents = [];
60 let inputEvents = [];
61 function onBeforeInput(aEvent) {
62 beforeInputEvents.push(aEvent);
63 selectionRanges = [];
64 for (let i = 0; i < selection.rangeCount; i++) {
65 let range = selection.getRangeAt(i);
66 selectionRanges.push({startContainer: range.startContainer, startOffset: range.startOffset,
67 endContainer: range.endContainer, endOffset: range.endOffset});
70 function onInput(aEvent) {
71 inputEvents.push(aEvent);
73 editor.addEventListener("beforeinput", onBeforeInput);
74 editor.addEventListener("input", onInput);
76 beforeInputEvents = [];
77 inputEvents = [];
78 selection.collapse(editor.firstChild, 0);
79 getTableEditor().insertTableRow(1, false);
80 is(editor.innerHTML, "out of table<table><tbody><tr><td>default content</td></tr></tbody></table>",
81 "nsITableEditor.insertTableRow(1, false) should do nothing if selection is not in <table>");
82 is(beforeInputEvents.length, 1,
83 '"beforeinput" event should be fired when a call of nsITableEditor.insertTableRow(1, false) even though it will do nothing');
84 checkInputEvent(beforeInputEvents[0], "when selection is collapsed outside of table element (nsITableEditor.insertTableRow(1, false))");
85 is(inputEvents.length, 0,
86 'No "input" event should be fired when a call of nsITableEditor.insertTableRow(1, false) does nothing');
88 beforeInputEvents = [];
89 inputEvents = [];
90 getTableEditor().insertTableRow(1, true);
91 is(editor.innerHTML, "out of table<table><tbody><tr><td>default content</td></tr></tbody></table>",
92 "nsITableEditor.insertTableRow(1, true) should do nothing if selection is not in <table>");
93 is(beforeInputEvents.length, 1,
94 '"beforeinput" event should be fired when a call of nsITableEditor.insertTableRow(1, true) even though it will do nothing');
95 checkInputEvent(beforeInputEvents[0], "when selection is collapsed outside of table element (nsITableEditor.insertTableRow(1, true))");
96 is(inputEvents.length, 0,
97 'No "input" event should be fired when a call of nsITableEditor.insertTableRow(1, true) does nothing');
99 selection.removeAllRanges();
100 try {
101 beforeInputEvents = [];
102 inputEvents = [];
103 getTableEditor().insertTableRow(1, false);
104 ok(false, "getTableEditor().insertTableRow(1, false) without selection ranges should throw exception");
105 } catch (e) {
106 ok(true, "getTableEditor().insertTableRow(1, false) without selection ranges should throw exception");
107 is(beforeInputEvents.length, 0,
108 'No "beforeinput" event should be fired when nsITableEditor.insertTableRow(1, false) causes exception due to no selection range');
109 is(inputEvents.length, 0,
110 'No "input" event should be fired when nsITableEditor.insertTableRow(1, false) causes exception due to no selection range');
112 try {
113 beforeInputEvents = [];
114 inputEvents = [];
115 getTableEditor().insertTableRow(1, true);
116 ok(false, "getTableEditor().insertTableRow(1, true) without selection ranges should throw exception");
117 } catch (e) {
118 ok(true, "getTableEditor().insertTableRow(1, true) without selection ranges should throw exception");
119 is(beforeInputEvents.length, 0,
120 'No "beforeinput" event should be fired when nsITableEditor.insertTableRow(1, true) causes exception due to no selection range');
121 is(inputEvents.length, 0,
122 'No "input" event should be fired when nsITableEditor.insertTableRow(1, true) causes exception due to no selection range');
125 selection.removeAllRanges();
126 editor.innerHTML = "<table>" +
127 "<tr><td>cell1-1</td><td>cell1-2</td></tr>" +
128 '<tr><td id="select">cell2-1</td><td>cell2-2</td></tr>' +
129 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
130 "</table>";
131 editor.focus();
132 beforeInputEvents = [];
133 inputEvents = [];
134 selection.setBaseAndExtent(document.getElementById("select").firstChild, 0,
135 document.getElementById("select").firstChild, 0);
136 getTableEditor().insertTableRow(1, false);
137 is(editor.innerHTML, "<table><tbody>" +
138 "<tr><td>cell1-1</td><td>cell1-2</td></tr>" +
139 '<tr><td valign="top"><br></td><td valign="top"><br></td></tr>' +
140 '<tr><td id="select">cell2-1</td><td>cell2-2</td></tr>' +
141 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
142 "</tbody></table>",
143 "nsITableEditor.insertTableRow(1, false) should insert a row above the second row");
144 is(beforeInputEvents.length, 1,
145 'Only one "beforeinput" event should be fired when selection is collapsed in a cell in second row (before)');
146 checkInputEvent(beforeInputEvents[0], "when selection is collapsed in a cell in second row (before)");
147 is(inputEvents.length, 1,
148 'Only one "input" event should be fired when selection is collapsed in a cell in second row (before)');
149 checkInputEvent(inputEvents[0], "when selection is collapsed in a cell in second row (before)");
151 selection.removeAllRanges();
152 editor.innerHTML = "<table>" +
153 "<tr><td>cell1-1</td><td>cell1-2</td></tr>" +
154 '<tr><td id="select">cell2-1</td><td>cell2-2</td></tr>' +
155 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
156 "</table>";
157 editor.focus();
158 beforeInputEvents = [];
159 inputEvents = [];
160 selection.setBaseAndExtent(document.getElementById("select").firstChild, 0,
161 document.getElementById("select").firstChild, 0);
162 getTableEditor().insertTableRow(1, true);
163 is(editor.innerHTML, "<table><tbody>" +
164 "<tr><td>cell1-1</td><td>cell1-2</td></tr>" +
165 '<tr><td id="select">cell2-1</td><td>cell2-2</td></tr>' +
166 '<tr><td valign="top"><br></td><td valign="top"><br></td></tr>' +
167 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
168 "</tbody></table>",
169 "nsITableEditor.insertTableRow(1, true) should insert a row below the second row");
170 is(beforeInputEvents.length, 1,
171 'Only one "beforeinput" event should be fired when selection is collapsed in a cell in second row (after)');
172 checkInputEvent(beforeInputEvents[0], "when selection is collapsed in a cell in second row (after)");
173 is(inputEvents.length, 1,
174 'Only one "input" event should be fired when selection is collapsed in a cell in second row (after)');
175 checkInputEvent(inputEvents[0], "when selection is collapsed in a cell in second row (after)");
177 selection.removeAllRanges();
178 editor.innerHTML = "<table>" +
179 '<tr><td>cell1-1</td><td rowspan="2">cell1-2</td></tr>' +
180 '<tr><td id="select">cell2-1</td></tr>' +
181 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
182 "</table>";
183 editor.focus();
184 beforeInputEvents = [];
185 inputEvents = [];
186 selection.setBaseAndExtent(document.getElementById("select").firstChild, 0,
187 document.getElementById("select").firstChild, 0);
188 getTableEditor().insertTableRow(1, false);
189 is(editor.innerHTML, "<table><tbody>" +
190 '<tr><td>cell1-1</td><td rowspan="3">cell1-2</td></tr>' +
191 '<tr><td valign="top"><br></td></tr>' +
192 '<tr><td id="select">cell2-1</td></tr>' +
193 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
194 "</tbody></table>",
195 "nsITableEditor.insertTableRow(1, false) should insert a row above the second row and rowspan in the first row should be increased");
196 is(beforeInputEvents.length, 1,
197 'Only one "beforeinput" event should be fired when selection is collapsed in a cell in second row which has row-spanned cell (before)');
198 checkInputEvent(beforeInputEvents[0], "when selection is collapsed in a cell in second row which has row-spanned cell (before)");
199 is(inputEvents.length, 1,
200 'Only one "input" event should be fired when selection is collapsed in a cell in second row which has row-spanned cell (before)');
201 checkInputEvent(inputEvents[0], "when selection is collapsed in a cell in second row which has row-spanned cell (before)");
203 selection.removeAllRanges();
204 editor.innerHTML = "<table>" +
205 '<tr><td>cell1-1</td><td rowspan="3">cell1-2</td></tr>' +
206 '<tr><td id="select">cell2-1</td></tr>' +
207 "<tr><td>cell3-1</td></tr>" +
208 "</table>";
209 editor.focus();
210 beforeInputEvents = [];
211 inputEvents = [];
212 selection.setBaseAndExtent(document.getElementById("select").firstChild, 0,
213 document.getElementById("select").firstChild, 0);
214 getTableEditor().insertTableRow(1, true);
215 is(editor.innerHTML, "<table><tbody>" +
216 '<tr><td>cell1-1</td><td rowspan="4">cell1-2</td></tr>' +
217 '<tr><td id="select">cell2-1</td></tr>' +
218 '<tr><td valign="top"><br></td></tr>' +
219 "<tr><td>cell3-1</td></tr>" +
220 "</tbody></table>",
221 "nsITableEditor.insertTableRow(1, true) should insert a row below the second row and rowspan in the first row should be increased");
222 is(beforeInputEvents.length, 1,
223 'Only one "beforeinput" event should be fired when selection is collapsed in a cell in second row which has row-spanned cell (after)');
224 checkInputEvent(beforeInputEvents[0], "when selection is collapsed in a cell in second row which has row-spanned cell (after)");
225 is(inputEvents.length, 1,
226 'Only one "input" event should be fired when selection is collapsed in a cell in second row which has row-spanned cell (after)');
227 checkInputEvent(inputEvents[0], "when selection is collapsed in a cell in second row which has row-spanned cell (after)");
229 selection.removeAllRanges();
230 editor.innerHTML = "<table>" +
231 '<tr><td>cell1-1</td><td id="select" rowspan="2">cell1-2</td></tr>' +
232 "<tr><td>cell2-1</td></tr>" +
233 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
234 "</table>";
235 editor.focus();
236 beforeInputEvents = [];
237 inputEvents = [];
238 selection.setBaseAndExtent(document.getElementById("select").firstChild, 0,
239 document.getElementById("select").firstChild, 1);
240 getTableEditor().insertTableRow(2, false);
241 is(editor.innerHTML, "<table><tbody>" +
242 '<tr><td valign="top"><br></td><td valign="top"><br></td></tr>' +
243 '<tr><td valign="top"><br></td><td valign="top"><br></td></tr>' +
244 '<tr><td>cell1-1</td><td id="select" rowspan="2">cell1-2</td></tr>' +
245 "<tr><td>cell2-1</td></tr>" +
246 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
247 "</tbody></table>",
248 "nsITableEditor.insertTableRow(2, false) should insert 2 rows above the first row");
249 is(beforeInputEvents.length, 1,
250 'Only one "beforeinput" event should be fired when selection is collapsed in a cell which is row-spanning (before)');
251 checkInputEvent(beforeInputEvents[0], "when selection is collapsed in a cell which is row-spanning (before)");
252 is(inputEvents.length, 1,
253 'Only one "input" event should be fired when selection is collapsed in a cell which is row-spanning (before)');
254 checkInputEvent(inputEvents[0], "when selection is collapsed in a cell which is row-spanning (before)");
256 selection.removeAllRanges();
257 editor.innerHTML = "<table>" +
258 '<tr><td>cell1-1</td><td id="select" rowspan="2">cell1-2</td></tr>' +
259 "<tr><td>cell2-1</td></tr>" +
260 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
261 "</table>";
262 editor.focus();
263 beforeInputEvents = [];
264 inputEvents = [];
265 selection.setBaseAndExtent(document.getElementById("select").firstChild, 0,
266 document.getElementById("select").firstChild, 1);
267 getTableEditor().insertTableRow(2, true);
268 is(editor.innerHTML, "<table><tbody>" +
269 '<tr><td>cell1-1</td><td id="select" rowspan="2">cell1-2</td></tr>' +
270 "<tr><td>cell2-1</td></tr>" +
271 '<tr><td valign="top"><br></td><td valign="top"><br></td></tr>' +
272 '<tr><td valign="top"><br></td><td valign="top"><br></td></tr>' +
273 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
274 "</tbody></table>",
275 "nsITableEditor.insertTableRow(2, false) should insert 2 rows below the second row (i.e., below the bottom row of the row-spanning cell");
276 is(beforeInputEvents.length, 1,
277 'Only one "beforeinput" event should be fired when selection is collapsed in a cell which is row-spanning (after)');
278 checkInputEvent(beforeInputEvents[0], "when selection is collapsed in a cell which is row-spanning (after)");
279 is(inputEvents.length, 1,
280 'Only one "input" event should be fired when selection is collapsed in a cell which is row-spanning (after)');
281 checkInputEvent(inputEvents[0], "when selection is collapsed in a cell which is row-spanning (after)");
283 (function testInsertBeforeRowFollowingTextNode() {
284 selection.removeAllRanges();
285 editor.innerHTML =
286 "<table>" +
287 "<tr><td>cell1-1</td><td>cell1-2</td></tr>\n" +
288 '<tr><td id="select">cell2-1</td><td>cell2-2</td></tr>\n' +
289 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
290 "</table>";
291 editor.focus();
292 beforeInputEvents = [];
293 inputEvents = [];
294 selection.setBaseAndExtent(
295 document.getElementById("select").firstChild,
297 document.getElementById("select").firstChild,
300 getTableEditor().insertTableRow(1, false);
302 editor.innerHTML,
303 "<table><tbody>" +
304 "<tr><td>cell1-1</td><td>cell1-2</td></tr>\n" +
305 '<tr><td valign="top"><br></td><td valign="top"><br></td></tr>' +
306 '<tr><td id="select">cell2-1</td><td>cell2-2</td></tr>\n' +
307 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
308 "</tbody></table>",
309 "testInsertBeforeRowFollowingTextNode: nsITableEditor.insertTableRow(1, false) should insert a row above the second row");
311 beforeInputEvents.length,
313 'testInsertBeforeRowFollowingTextNode: Only one "beforeinput" event should be fired'
315 checkInputEvent(
316 beforeInputEvents[0],
317 "when selection is collapsed in a cell whose row follows a text node (testInsertBeforeRowFollowingTextNode)"
320 inputEvents.length,
322 'testInsertBeforeRowFollowingTextNode: Only one "input" event should be fired'
324 checkInputEvent(
325 inputEvents[0],
326 "when selection is collapsed in a cell whose row follows a text node (testInsertBeforeRowFollowingTextNode)"
328 })();
330 (function testInsertAfterRowFollowedTextNode() {
331 selection.removeAllRanges();
332 editor.innerHTML =
333 "<table>" +
334 "<tr><td>cell1-1</td><td>cell1-2</td></tr>\n" +
335 '<tr><td id="select">cell2-1</td><td>cell2-2</td></tr>\n' +
336 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
337 "</table>";
338 editor.focus();
339 beforeInputEvents = [];
340 inputEvents = [];
341 selection.setBaseAndExtent(
342 document.getElementById("select").firstChild,
344 document.getElementById("select").firstChild,
347 getTableEditor().insertTableRow(1, true);
349 editor.innerHTML,
350 "<table><tbody>" +
351 "<tr><td>cell1-1</td><td>cell1-2</td></tr>\n" +
352 '<tr><td id="select">cell2-1</td><td>cell2-2</td></tr>' +
353 '<tr><td valign="top"><br></td><td valign="top"><br></td></tr>\n' +
354 "<tr><td>cell3-1</td><td>cell3-2</td></tr>" +
355 "</tbody></table>",
356 "testInsertAfterRowFollowedTextNode: nsITableEditor.insertTableRow(1, true) should insert a row above the second row");
358 beforeInputEvents.length,
360 'testInsertAfterRowFollowedTextNode: Only one "beforeinput" event should be fired'
362 checkInputEvent(
363 beforeInputEvents[0],
364 "when selection is collapsed in a cell whose row follows a text node (testInsertAfterRowFollowedTextNode)"
367 inputEvents.length,
369 'testInsertAfterRowFollowedTextNode: Only one "input" event should be fired'
371 checkInputEvent(
372 inputEvents[0],
373 "when selection is collapsed in a cell whose row follows a text node (testInsertAfterRowFollowedTextNode)"
375 })();
376 editor.removeEventListener("beforeinput", onBeforeInput);
377 editor.removeEventListener("input", onInput);
379 SimpleTest.finish();
382 function getTableEditor() {
383 var editingSession = SpecialPowers.wrap(window).docShell.editingSession;
384 return editingSession.getEditorForWindow(window).QueryInterface(SpecialPowers.Ci.nsITableEditor);
387 </script>
388 </body>
390 </html>