Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE>
<html>
<head>
<title>Test for nsIEditor.insertLineBreak()</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<div id="display">
</div>
<input value="abcdef">
<textarea>abcdef</textarea>
<div id="content" contenteditable></div>
<pre id="test">
</pre>
<script class="testbody" type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
SimpleTest.expectAssertions(0, 2); // In a11y module
SimpleTest.waitForFocus(() => {
let input = document.getElementsByTagName("input")[0];
let textarea = document.getElementsByTagName("textarea")[0];
let contenteditable = document.getElementById("content");
let selection = window.getSelection();
let beforeInputEvents = [];
let inputEvents = [];
function onBeforeInput(event) {
beforeInputEvents.push(event);
}
function onInput(event) {
inputEvents.push(event);
}
function checkInputEvent(aEvent, aInputType, aTargetRanges, aDescription) {
ok(aEvent != null, `aEvent is null (${aDescription})`);
ok(aEvent instanceof InputEvent,
`"${aEvent.type}" event should be dispatched with InputEvent interface (${aDescription})`);
is(aEvent.cancelable, aEvent.type === "beforeinput",
`"${aEvent.type}" event should ${aEvent.type === "beforeinput" ? "be" : "be never"} cancelable (${aDescription})`);
is(aEvent.bubbles, true,
`"${aEvent.type}" event should always bubble (${aDescription})`);
is(aEvent.inputType, aInputType,
`inputType of "${aEvent.type}" event should be "${aInputType}" ${aDescription}`);
is(aEvent.data, null,
`data of "${aEvent.type}" event should be null ${aDescription}`);
is(aEvent.dataTransfer, null,
`dataTransfer of "${aEvent.type}" event should be null ${aDescription}`);
let targetRanges = aEvent.getTargetRanges();
if (aTargetRanges.length === 0) {
is(targetRanges.length, 0,
`getTargetRange() of "${aEvent.type}" event should return empty array: ${aDescription}`);
} else {
is(targetRanges.length, aTargetRanges.length,
`getTargetRange() of "${aEvent.type}" event should return static range array: ${aDescription}`);
if (targetRanges.length == aTargetRanges.length) {
for (let i = 0; i < targetRanges.length; i++) {
is(targetRanges[i].startContainer, aTargetRanges[i].startContainer,
`startContainer of getTargetRanges()[${i}] of "${aEvent.type}" event does not match: ${aDescription}`);
is(targetRanges[i].startOffset, aTargetRanges[i].startOffset,
`startOffset of getTargetRanges()[${i}] of "${aEvent.type}" event does not match: ${aDescription}`);
is(targetRanges[i].endContainer, aTargetRanges[i].endContainer,
`endContainer of getTargetRanges()[${i}] of "${aEvent.type}" event does not match: ${aDescription}`);
is(targetRanges[i].endOffset, aTargetRanges[i].endOffset,
`endOffset of getTargetRanges()[${i}] of "${aEvent.type}" event does not match: ${aDescription}`);
}
}
}
}
input.focus();
input.selectionStart = input.selectionEnd = 3;
beforeInputEvents = [];
inputEvents = [];
input.addEventListener("beforeinput", onBeforeInput);
input.addEventListener("input", onInput);
try {
getPlaintextEditor(input).insertLineBreak();
} catch (e) {
ok(true, e.message);
}
input.removeEventListener("beforeinput", onBeforeInput);
input.removeEventListener("input", onInput);
is(input.value, "abcdef", "nsIEditor.insertLineBreak() should do nothing on single line editor");
is(beforeInputEvents.length, 1, 'nsIEditor.insertLineBreak() should cause a "beforeinput" event on single line editor');
checkInputEvent(beforeInputEvents[0], "insertLineBreak", [], "on single line editor");
is(inputEvents.length, 0, 'nsIEditor.insertLineBreak() should not cause "input" event on single line editor');
textarea.focus();
textarea.selectionStart = textarea.selectionEnd = 3;
beforeInputEvents = [];
inputEvents = [];
textarea.addEventListener("beforeinput", onBeforeInput);
textarea.addEventListener("input", onInput);
getPlaintextEditor(textarea).insertLineBreak();
textarea.removeEventListener("beforeinput", onBeforeInput);
textarea.removeEventListener("input", onInput);
is(textarea.value, "abc\ndef", "nsIEditor.insertLineBreak() should insert \\n into multi-line editor");
is(beforeInputEvents.length, 1, 'nsIEditor.insertLineBreak() should cause "beforeinput" event once on multi-line editor');
checkInputEvent(beforeInputEvents[0], "insertLineBreak", [], "on multi-line editor");
is(inputEvents.length, 1, 'nsIEditor.insertLineBreak() should cause "input" event once on multi-line editor');
checkInputEvent(inputEvents[0], "insertLineBreak", [], "on multi-line editor");
// Note that despite of the name, insertLineBreak() should insert paragraph separator in HTMLEditor.
document.execCommand("defaultParagraphSeparator", false, "br");
contenteditable.innerHTML = "abcdef";
contenteditable.focus();
contenteditable.scrollTop;
let selectionContainer = contenteditable.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "abc<br>def",
'nsIEditor.insertLineBreak() should insert <br> element into text node when defaultParagraphSeparator is "br"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has only text node when defaultParagraphSeparator is "br"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'on HTMLEditor (when defaultParagraphSeparator is "br")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has only text node when defaultParagraphSeparator is "br"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'on HTMLEditor (when defaultParagraphSeparator is "br")');
contenteditable.innerHTML = "<p>abcdef</p>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<p>abc</p><p>def</p>",
'nsIEditor.insertLineBreak() should add <p> element after <p> element even when defaultParagraphSeparator is "br"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <p> element when defaultParagraphSeparator is "br"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <p> element on HTMLEditor (when defaultParagraphSeparator is "br")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <p> element when defaultParagraphSeparator is "br"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <p> element on HTMLEditor (when defaultParagraphSeparator is "br")');
contenteditable.innerHTML = "<div>abcdef</div>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<div>abc<br>def</div>",
'nsIEditor.insertLineBreak() should insert <br> element into <div> element when defaultParagraphSeparator is "br"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <div> element when defaultParagraphSeparator is "br"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <div> element on HTMLEditor (when defaultParagraphSeparator is "br")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <div> element when defaultParagraphSeparator is "br"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <div> element on HTMLEditor (when defaultParagraphSeparator is "br")');
contenteditable.innerHTML = "<pre>abcdef</pre>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<pre>abc<br>def</pre>",
'nsIEditor.insertLineBreak() should insert <br> element into <pre> element when defaultParagraphSeparator is "br"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <pre> element when defaultParagraphSeparator is "br"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <pre> element on HTMLEditor (when defaultParagraphSeparator is "br")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <pre> element when defaultParagraphSeparator is "br"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <pre> element on HTMLEditor (when defaultParagraphSeparator is "br")');
document.execCommand("defaultParagraphSeparator", false, "p");
contenteditable.innerHTML = "abcdef";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<p>abc</p><p>def</p>",
'nsIEditor.insertLineBreak() should create <p> elements when there is only text node and defaultParagraphSeparator is "p"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has only text node when defaultParagraphSeparator is "p"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'on HTMLEditor (when defaultParagraphSeparator is "p")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has only text node when defaultParagraphSeparator is "p"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'on HTMLEditor (when defaultParagraphSeparator is "p")');
contenteditable.innerHTML = "<p>abcdef</p>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<p>abc</p><p>def</p>",
'nsIEditor.insertLineBreak() should add <p> element after <p> element when defaultParagraphSeparator is "p"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <p> element when defaultParagraphSeparator is "p"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <p> element on HTMLEditor (when defaultParagraphSeparator is "p")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <p> element when defaultParagraphSeparator is "p"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <p> element on HTMLEditor (when defaultParagraphSeparator is "p")');
contenteditable.innerHTML = "<div>abcdef</div>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<div>abc</div><div>def</div>",
'nsIEditor.insertLineBreak() should add <div> element after <div> element even when defaultParagraphSeparator is "p"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <div> element when defaultParagraphSeparator is "p"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <div> element on HTMLEditor (when defaultParagraphSeparator is "p")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <div> element when defaultParagraphSeparator is "p"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <div> element on HTMLEditor (when defaultParagraphSeparator is "p")');
contenteditable.innerHTML = "<pre>abcdef</pre>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<pre>abc<br>def</pre>",
'nsIEditor.insertLineBreak() should insert <br> element into <pre> element when defaultParagraphSeparator is "p"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <pre> element when defaultParagraphSeparator is "p"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <pre> element on HTMLEditor (when defaultParagraphSeparator is "p")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <pre> element when defaultParagraphSeparator is "p"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <pre> element on HTMLEditor (when defaultParagraphSeparator is "p")');
document.execCommand("defaultParagraphSeparator", false, "div");
contenteditable.innerHTML = "abcdef";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<div>abc</div><div>def</div>",
'nsIEditor.insertLineBreak() should create <div> elements when there is only text node and defaultParagraphSeparator is "div"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has only text node when defaultParagraphSeparator is "div"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'on HTMLEditor (when defaultParagraphSeparator is "div")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has only text node when defaultParagraphSeparator is "div"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'on HTMLEditor (when defaultParagraphSeparator is "div")');
contenteditable.innerHTML = "<p>abcdef</p>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<p>abc</p><p>def</p>",
'nsIEditor.insertLineBreak() should add <p> element after <p> element even when defaultParagraphSeparator is "div"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <p> element when defaultParagraphSeparator is "div"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <p> element on HTMLEditor (when defaultParagraphSeparator is "div")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <p> element when defaultParagraphSeparator is "div"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <p> element on HTMLEditor (when defaultParagraphSeparator is "div")');
contenteditable.innerHTML = "<div>abcdef</div>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<div>abc</div><div>def</div>",
'nsIEditor.insertLineBreak() should add <div> element after <div> element when defaultParagraphSeparator is "div"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <div> element when defaultParagraphSeparator is "div"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <div> element on HTMLEditor (when defaultParagraphSeparator is "div")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <div> element when defaultParagraphSeparator is "div"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <div> element on HTMLEditor (when defaultParagraphSeparator is "div")');
contenteditable.innerHTML = "<pre>abcdef</pre>";
contenteditable.focus();
contenteditable.scrollTop;
selectionContainer = contenteditable.firstChild.firstChild;
selection.collapse(selectionContainer, 3);
beforeInputEvents = [];
inputEvents = [];
contenteditable.addEventListener("beforeinput", onBeforeInput);
contenteditable.addEventListener("input", onInput);
getPlaintextEditor(contenteditable).insertLineBreak();
contenteditable.removeEventListener("beforeinput", onBeforeInput);
contenteditable.removeEventListener("input", onInput);
is(contenteditable.innerHTML, "<pre>abc<br>def</pre>",
'nsIEditor.insertLineBreak() should insert <br> element into <pre> element when defaultParagraphSeparator is "div"');
is(beforeInputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "beforeinput" event once on contenteditable which has <pre> element when defaultParagraphSeparator is "div"');
checkInputEvent(beforeInputEvents[0], "insertParagraph",
[{startContainer: selectionContainer, startOffset: 3,
endContainer: selectionContainer, endOffset: 3}],
'in <pre> element on HTMLEditor (when defaultParagraphSeparator is "div")');
is(inputEvents.length, 1,
'nsIEditor.insertLineBreak() should cause "input" event once on contenteditable which has <pre> element when defaultParagraphSeparator is "div"');
checkInputEvent(inputEvents[0], "insertParagraph", [], 'in <pre> element on HTMLEditor (when defaultParagraphSeparator is "div")');
SimpleTest.finish();
});
function getPlaintextEditor(aEditorElement) {
let editor = aEditorElement ? SpecialPowers.wrap(aEditorElement).editor : null;
if (!editor) {
editor = SpecialPowers.wrap(window).docShell.editingSession.getEditorForWindow(window);
}
return editor;
}
</script>
</body>
</html>