Bug 1175418 - Don't create unnecessary text nodes in editor; r=masayuki
MozReview-Commit-ID: LnioO8XoGQT
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -2432,16 +2432,28 @@ EditorBase::InsertTextImpl(const nsAStri
nsCOMPtr<nsINode> node = *aInOutNode;
int32_t offset = *aInOutOffset;
// In some cases, the node may be the anonymous div elemnt or a mozBR
// element. Let's try to look for better insertion point in the nearest
// text node if there is.
FindBetterInsertionPoint(node, offset);
+ // If a neighboring text node already exists, use that
+ if (!node->IsNodeOfType(nsINode::eTEXT)) {
+ if (offset && node->GetChildAt(offset - 1)->IsNodeOfType(nsINode::eTEXT)) {
+ node = node->GetChildAt(offset - 1);
+ offset = node->Length();
+ } else if (offset < static_cast<int32_t>(node->Length()) &&
+ node->GetChildAt(offset)->IsNodeOfType(nsINode::eTEXT)) {
+ node = node->GetChildAt(offset);
+ offset = 0;
+ }
+ }
+
if (ShouldHandleIMEComposition()) {
CheckedInt<int32_t> newOffset;
if (!node->IsNodeOfType(nsINode::eTEXT)) {
// create a text node
RefPtr<nsTextNode> newNode = aDoc->CreateTextNode(EmptyString());
// then we insert it into the dom tree
nsresult rv = InsertNode(*newNode, *node, offset);
NS_ENSURE_SUCCESS(rv, rv);
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -86647,16 +86647,22 @@
]
],
"editing/other/delete.html": [
[
"/editing/other/delete.html",
{}
]
],
+ "editing/other/extra-text-nodes.html": [
+ [
+ "/editing/other/extra-text-nodes.html",
+ {}
+ ]
+ ],
"editing/other/restoration.html": [
[
"/editing/other/restoration.html",
{}
]
],
"editing/run/backcolor.html": [
[
@@ -163664,16 +163670,20 @@
"editing/manual/inserttext2.manual.html": [
"7a5589f41ab8405d6ed09a4b83bd0c60e2a59677",
"support"
],
"editing/other/delete.html": [
"c812df13215631719f8ff17eee4e0a854684670d",
"testharness"
],
+ "editing/other/extra-text-nodes.html": [
+ "79b4a278f0e35646cfdffeebf8f0523e2772bc9b",
+ "testharness"
+ ],
"editing/other/restoration.html": [
"432d9d66ec7621faf22a31960816290193b60aed",
"testharness"
],
"editing/run/backcolor.html": [
"72840bfcf7e62249773e925f79ba196218964373",
"testharness"
],
@@ -208153,17 +208163,17 @@
"0d244bffe67ef57be68aad99f1cbc7440ff80e27",
"support"
],
"webdriver/actions/support/test_actions_wdspec.html": [
"63b5de5ab6c7a00717663a18c3b4d79857ee2136",
"support"
],
"webdriver/conftest.py": [
- "0096317addcf73326f6df05847659d637ae6910e",
+ "39ba7649c437b50bb97d766561e4bd5a110f6459",
"wdspec"
],
"webdriver/contexts.py": [
"302a1a0cb246aef74f2c1d961a210d9de7e366c5",
"wdspec"
],
"webdriver/interface.html": [
"d783d0dd370f58b264ef238d8da5cd8601dc3c7f",
@@ -208173,17 +208183,17 @@
"8a0dd2bc5cf9c734ceebcd1a11431482c944a668",
"wdspec"
],
"webdriver/util/__init__.py": [
"8910ee7d68dfff68460731ea37eb0d406d07862d",
"support"
],
"webdriver/util/cleanup.py": [
- "1622ba96398dec13b5fa4214fe8a7f930a943c5f",
+ "e5868c6358d24100e0a90217769b42d6d025356b",
"wdspec"
],
"webdriver/util/http_request.py": [
"01c4b525c27f77d253c75031a9cee3f17aca8df0",
"wdspec"
],
"webgl/OWNERS": [
"f8e0703fe2cc88edd21ef2c94fcb2e1a8889f5ae",
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/editing/other/extra-text-nodes.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Editor should not create unnecessary text nodes</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div contenteditable></div>
+<script>
+var div = document.querySelector("div");
+var walker = document.createTreeWalker(div, NodeFilter.SHOW_TEXT);
+function testInput(html, callback, desc) {
+ test(() => {
+ div.innerHTML = html;
+ div.focus();
+ callback();
+
+ walker.currentNode = walker.root;
+ var node;
+ while (node = walker.nextNode()) {
+ if (node.nextSibling) {
+ assert_not_equals(node.nextSibling.nodeType, Node.TEXT_NODE,
+ 'text node "' + node.nodeValue + '" is next to "' +
+ node.nextSibling.nodeValue + '"');
+ }
+ }
+ }, desc);
+}
+
+[
+ ['<img src="#">foo<img src="#">',
+ () => {
+ getSelection().collapse(div, 1);
+ document.execCommand("inserttext", false, "x");
+ },
+ "Simple insertText"],
+ ['<p>editor</p>',
+ () => {
+ getSelection().collapse(div.firstChild.firstChild, 3);
+ document.execCommand("insertlinebreak", false, "");
+ document.execCommand("inserttext", false, "x");
+ },
+ "insertText after insertLineBreak"],
+].forEach(([a, b, c]) => testInput(a, b, c));
+</script>