4 <title>Test for nsITableEditor.insertTableRow()
</title>
5 <script src=
"/tests/SimpleTest/SimpleTest.js"></script>
6 <link rel=
"stylesheet" href=
"/tests/SimpleTest/test.css">
11 <div id=
"content" contenteditable
>out of table
<table><tr><td>default content
</td></tr></table></div>
15 <script class=
"testbody" type=
"application/javascript">
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}`);
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}`);
54 is(targetRanges.length,
0,
55 `getTargetRanges() of
"${aEvent.type}" event should return empty array ${aDescription}`);
59 let beforeInputEvents = [];
61 function onBeforeInput(aEvent) {
62 beforeInputEvents.push(aEvent);
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 = [];
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 = [];
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();
101 beforeInputEvents = [];
103 getTableEditor().insertTableRow(
1, false);
104 ok(false,
"getTableEditor().insertTableRow(1, false) without selection ranges should throw exception");
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');
113 beforeInputEvents = [];
115 getTableEditor().insertTableRow(
1, true);
116 ok(false,
"getTableEditor().insertTableRow(1, true) without selection ranges should throw exception");
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>" +
132 beforeInputEvents = [];
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>" +
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>" +
158 beforeInputEvents = [];
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>" +
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>" +
184 beforeInputEvents = [];
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>" +
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>" +
210 beforeInputEvents = [];
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>" +
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>" +
236 beforeInputEvents = [];
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>" +
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>" +
263 beforeInputEvents = [];
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>" +
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();
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>" +
292 beforeInputEvents = [];
294 selection.setBaseAndExtent(
295 document.getElementById(
"select").firstChild,
297 document.getElementById(
"select").firstChild,
300 getTableEditor().insertTableRow(
1, false);
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>" +
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'
316 beforeInputEvents[
0],
317 "when selection is collapsed in a cell whose row follows a text node (testInsertBeforeRowFollowingTextNode)"
322 'testInsertBeforeRowFollowingTextNode: Only one
"input" event should be fired'
326 "when selection is collapsed in a cell whose row follows a text node (testInsertBeforeRowFollowingTextNode)"
330 (function testInsertAfterRowFollowedTextNode() {
331 selection.removeAllRanges();
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>" +
339 beforeInputEvents = [];
341 selection.setBaseAndExtent(
342 document.getElementById(
"select").firstChild,
344 document.getElementById(
"select").firstChild,
347 getTableEditor().insertTableRow(
1, true);
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>" +
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'
363 beforeInputEvents[
0],
364 "when selection is collapsed in a cell whose row follows a text node (testInsertAfterRowFollowedTextNode)"
369 'testInsertAfterRowFollowedTextNode: Only one
"input" event should be fired'
373 "when selection is collapsed in a cell whose row follows a text node (testInsertAfterRowFollowedTextNode)"
376 editor.removeEventListener(
"beforeinput", onBeforeInput);
377 editor.removeEventListener(
"input", onInput);
382 function getTableEditor() {
383 var editingSession = SpecialPowers.wrap(window).docShell.editingSession;
384 return editingSession.getEditorForWindow(window).QueryInterface(SpecialPowers.Ci.nsITableEditor);