[evolution/wip/mcrha/webkit-jsc-api] e-editor.js: Correct deletion in blockquote in Plain Text mode



commit 455c106324dafe51a1462ea50af051e0e5c23b7c
Author: Milan Crha <mcrha redhat com>
Date:   Thu Apr 16 16:52:50 2020 +0200

    e-editor.js: Correct deletion in blockquote in Plain Text mode

 data/webkit/e-editor.js             | 288 +++++++++++++++++-------------------
 src/e-util/test-html-editor-units.c |  80 ++++++++++
 2 files changed, 214 insertions(+), 154 deletions(-)
---
diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js
index e85a6dcbb5..c3c2d8a7d9 100644
--- a/data/webkit/e-editor.js
+++ b/data/webkit/e-editor.js
@@ -3004,11 +3004,26 @@ EvoEditor.removeEmptyElements = function(tagName)
 {
        var nodes, node, ii, didRemove = 0;
 
-       nodes = document.querySelectorAll(tagName + ":empty");
+       nodes = document.getElementsByTagName(tagName);
 
        for (ii = nodes.length - 1; ii >= 0; ii--) {
                node = nodes[ii];
 
+               // more than one child element means it's not empty
+               if (node.childElementCount > 1)
+                       continue;
+
+               // the first element is not quotation mark
+               if (node.firstElementChild && (node.firstElementChild.tagName != "SPAN" ||
+                   node.firstElementChild.className != "-x-evo-quoted"))
+                       continue;
+
+               // the text inside is not empty, possibly on either of the two sides of the quotation mark
+               if ((node.firstChild && (node.firstChild.nodeType == node.TEXT_NODE && 
node.firstChild.nodeValue)) ||
+                   (node.lastChild && !(node.lastChild === node.firstChild) && (node.lastChild.nodeType == 
node.TEXT_NODE && node.lastChild.nodeValue)))
+                       continue;
+
+               // it's either completely empty or it contains only the quotation mark and nothing else
                didRemove++;
 
                EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "removeEmptyElem::" + tagName, 
node.parentElement, node.parentElement,
@@ -3056,55 +3071,6 @@ EvoEditor.beforeInputCb = function(inputEvent)
 
                        return;
                }
-
-               if (!selection.isCollapsed) {
-                       var didRemove = 0;
-
-                       if (selection.anchorNode && selection.anchorNode.previousSibling &&
-                           EvoEditor.maybeRemoveQuotationMark(selection.anchorNode.previousSibling))
-                               didRemove++;
-
-                       if (selection.focusNode && selection.focusNode.previousSibling &&
-                           EvoEditor.maybeRemoveQuotationMark(selection.focusNode.previousSibling))
-                               didRemove++;
-
-                       if (didRemove) {
-                               EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, inputEvent.inputType 
+ "::selDeletion", selection.anchorNode.parentElement, selection.focusNode.parentElement,
-                                       EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML | 
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
-                               try {
-                                       var anchorBlockquote = EvoEditor.getParentElement("BLOCKQUOTE", 
selection.anchorNode, true);
-                                       var blockquote = EvoEditor.getParentElement("BLOCKQUOTE", 
selection.focusNode, true);
-
-                                       selection.deleteFromDocument();
-
-                                       if (blockquote && anchorBlockquote === blockquote && 
blockquote.lastElementChild &&
-                                           (blockquote.lastElementChild.tagName == "DIV" || 
blockquote.lastElementChild.tagName == "PRE") &&
-                                           (!blockquote.lastElementChild.childNodes.length || 
(blockquote.lastElementChild.childNodes.length == 1 &&
-                                            blockquote.lastElementChild.childNodes[0].nodeType == 
blockquote.TEXT_NODE && !blockquote.lastElementChild.childNodes[0].nodeValue))) {
-                                               // keep at least one empty DIV/PRE, when it's at the end of 
the BLOCKQUOTE
-                                               
blockquote.lastElementChild.append(document.createElement("BR"));
-
-                                               if 
(EvoEditor.requoteNodeParagraph(blockquote.lastElementChild.firstElementChild))
-                                                    didRemove++;
-                                       }
-                               } finally {
-                                       EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, 
inputEvent.inputType + "::selDeletion");
-                               }
-
-                               didRemove += EvoEditor.removeEmptyElements("DIV");
-                               didRemove += EvoEditor.removeEmptyElements("PRE");
-
-                               EvoUndoRedo.GroupTopRecords(didRemove + 1, inputEvent.inputType + 
"::grouped");
-                               EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
-                               EvoEditor.EmitContentChanged();
-
-                               inputEvent.stopImmediatePropagation();
-                               inputEvent.stopPropagation();
-                               inputEvent.preventDefault();
-
-                               return;
-                       }
-               }
        }
 
        if (EvoUndoRedo.disabled ||
@@ -3224,149 +3190,163 @@ EvoEditor.AfterInputEvent = function(inputEvent, isWordDelim)
        }
 
        // special editing of blockquotes
-       if ((inputEvent.inputType.startsWith("insert") || inputEvent.inputType.startsWith("delete")) &&
-           selection.isCollapsed && EvoEditor.hasElementWithTagNameAsParent(selection.anchorNode, 
"BLOCKQUOTE")) {
-               // insertParagraph should split the blockquote into two
-               if (isInsertParagraph) {
-                       var node = selection.anchorNode, childNode = node, parent, removeNode = null;
-
-                       for (parent = node.parentElement; parent && parent.tagName != "BODY"; parent = 
parent.parentElement) {
-                               if (parent.tagName == "BLOCKQUOTE") {
-                                       childNode = parent;
-                               }
-                       }
+       if (selection.isCollapsed && (inputEvent.inputType.startsWith("insert") || 
inputEvent.inputType.startsWith("delete"))) {
+               if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT && inputEvent.inputType.startsWith("delete")) 
{
+                       var didRemove = 0;
 
-                       EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "blockquoteSplit", childNode, 
childNode,
-                               EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+                       didRemove += EvoEditor.removeEmptyElements("DIV");
+                       didRemove += EvoEditor.removeEmptyElements("PRE");
 
-                       try {
-                               if (node.nodeType == node.ELEMENT_NODE && node.childNodes.length == 1 && 
node.firstChild.tagName == "BR")
-                                       removeNode = node;
-                               else if (node.nodeType == node.ELEMENT_NODE && node.childNodes.length > 1 && 
node.firstChild.tagName == "BR")
-                                       removeNode = node.firstChild;
+                       if (didRemove)
+                               EvoUndoRedo.GroupTopRecords(didRemove + 1, inputEvent.inputType + 
"::removeEmptyElems");
+               }
 
-                               childNode = node;
+               if (EvoEditor.hasElementWithTagNameAsParent(selection.anchorNode, "BLOCKQUOTE")) {
+                       // insertParagraph should split the blockquote into two
+                       if (isInsertParagraph) {
+                               var node = selection.anchorNode, childNode = node, parent, removeNode = null;
 
                                for (parent = node.parentElement; parent && parent.tagName != "BODY"; parent 
= parent.parentElement) {
                                        if (parent.tagName == "BLOCKQUOTE") {
-                                               childNode = EvoEditor.splitAtChild(parent, childNode);
-                                               parent = childNode;
-                                       } else {
                                                childNode = parent;
                                        }
                                }
 
-                               if (parent) {
-                                       var divNode = document.createElement("DIV");
-                                       divNode.appendChild(document.createElement("BR"));
-                                       parent.insertBefore(divNode, childNode);
-                                       document.getSelection().setPosition(divNode, 0);
-                                       EvoEditor.maybeUpdateParagraphWidth(divNode);
-                               }
+                               EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "blockquoteSplit", 
childNode, childNode,
+                                       EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
 
-                               while (removeNode && removeNode.tagName != "BODY") {
-                                       node = removeNode.parentElement;
-                                       node.removeChild(removeNode);
+                               try {
+                                       if (node.nodeType == node.ELEMENT_NODE && node.childNodes.length == 1 
&& node.firstChild.tagName == "BR")
+                                               removeNode = node;
+                                       else if (node.nodeType == node.ELEMENT_NODE && node.childNodes.length 
1 && node.firstChild.tagName == "BR")
+                                               removeNode = node.firstChild;
 
-                                       if (node.childNodes.length)
-                                               break;
+                                       childNode = node;
 
-                                       removeNode = node;
-                               }
+                                       for (parent = node.parentElement; parent && parent.tagName != "BODY"; 
parent = parent.parentElement) {
+                                               if (parent.tagName == "BLOCKQUOTE") {
+                                                       childNode = EvoEditor.splitAtChild(parent, childNode);
+                                                       parent = childNode;
+                                               } else {
+                                                       childNode = parent;
+                                               }
+                                       }
 
-                               if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
-                                       node = document.getSelection().anchorNode;
+                                       if (parent) {
+                                               var divNode = document.createElement("DIV");
+                                               divNode.appendChild(document.createElement("BR"));
+                                               parent.insertBefore(divNode, childNode);
+                                               document.getSelection().setPosition(divNode, 0);
+                                               EvoEditor.maybeUpdateParagraphWidth(divNode);
+                                       }
+
+                                       while (removeNode && removeNode.tagName != "BODY") {
+                                               node = removeNode.parentElement;
+                                               node.removeChild(removeNode);
 
-                                       if (node && node.nextElementSibling) {
-                                               var blockquoteLevel = (node.nextElementSibling.tagName == 
"BLOCKQUOTE" ? 1 : 0);
+                                               if (node.childNodes.length)
+                                                       break;
 
-                                               EvoEditor.removeQuoteMarks(node.nextElementSibling);
-                                               EvoEditor.convertParagraphs(node.nextElementSibling, 
blockquoteLevel,
-                                                       EvoEditor.NORMAL_PARAGRAPH_WIDTH - (blockquoteLevel * 
2), false);
+                                               removeNode = node;
                                        }
 
-                                       if (node && node.previousElementSibling) {
-                                               var blockquoteLevel = (node.previousElementSibling.tagName == 
"BLOCKQUOTE" ? 1 : 0);
+                                       if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+                                               node = document.getSelection().anchorNode;
+
+                                               if (node && node.nextElementSibling) {
+                                                       var blockquoteLevel = 
(node.nextElementSibling.tagName == "BLOCKQUOTE" ? 1 : 0);
+
+                                                       EvoEditor.removeQuoteMarks(node.nextElementSibling);
+                                                       EvoEditor.convertParagraphs(node.nextElementSibling, 
blockquoteLevel,
+                                                               EvoEditor.NORMAL_PARAGRAPH_WIDTH - 
(blockquoteLevel * 2), false);
+                                               }
 
-                                               EvoEditor.removeQuoteMarks(node.previousElementSibling);
-                                               EvoEditor.convertParagraphs(node.previousElementSibling, 
blockquoteLevel,
-                                                       EvoEditor.NORMAL_PARAGRAPH_WIDTH - (blockquoteLevel * 
2), false);
+                                               if (node && node.previousElementSibling) {
+                                                       var blockquoteLevel = 
(node.previousElementSibling.tagName == "BLOCKQUOTE" ? 1 : 0);
+
+                                                       
EvoEditor.removeQuoteMarks(node.previousElementSibling);
+                                                       
EvoEditor.convertParagraphs(node.previousElementSibling, blockquoteLevel,
+                                                               EvoEditor.NORMAL_PARAGRAPH_WIDTH - 
(blockquoteLevel * 2), false);
+                                               }
                                        }
+                               } finally {
+                                       EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, 
"blockquoteSplit");
+                                       EvoUndoRedo.GroupTopRecords(2, "insertParagraph::blockquoteSplit");
+                                       EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+                                       EvoEditor.EmitContentChanged();
                                }
-                       } finally {
-                               EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "blockquoteSplit");
-                               EvoUndoRedo.GroupTopRecords(2, "insertParagraph::blockquoteSplit");
-                               EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
-                               EvoEditor.EmitContentChanged();
-                       }
-               // insertLineBreak should re-quote text in the Plain Text mode
-               } else if (inputEvent.inputType == "insertLineBreak") {
-                       if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
-                               var selNode = document.getSelection().anchorNode, node = selNode, parent;
+                       // insertLineBreak should re-quote text in the Plain Text mode
+                       } else if (inputEvent.inputType == "insertLineBreak") {
+                               if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+                                       var selNode = document.getSelection().anchorNode, node = selNode, 
parent;
 
-                               while (node && node.tagName != "BODY" && !EvoEditor.IsBlockNode(node)) {
-                                       node = node.parentElement;
-                               }
+                                       while (node && node.tagName != "BODY" && 
!EvoEditor.IsBlockNode(node)) {
+                                               node = node.parentElement;
+                                       }
 
-                               if (node && node.tagName != "BODY" && selNode.previousSibling && 
selNode.previousSibling.nodeValue == "\n") {
-                                       EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "requote", 
node, node,
-                                               EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+                                       if (node && node.tagName != "BODY" && selNode.previousSibling && 
selNode.previousSibling.nodeValue == "\n") {
+                                               EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, 
"requote", node, node,
+                                                       EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
 
-                                       try {
-                                               var blockquoteLevel;
+                                               try {
+                                                       var blockquoteLevel;
 
-                                               // the "\n" is replaced with full paragraph
-                                               selNode.parentElement.removeChild(selNode.previousSibling);
+                                                       // the "\n" is replaced with full paragraph
+                                                       
selNode.parentElement.removeChild(selNode.previousSibling);
 
-                                               parent = selNode.parentElement;
+                                                       parent = selNode.parentElement;
 
-                                               var childNode = selNode;
+                                                       var childNode = selNode;
 
-                                               while (parent && parent.tagName != "BODY") {
-                                                       childNode = EvoEditor.splitAtChild(parent, childNode);
+                                                       while (parent && parent.tagName != "BODY") {
+                                                               childNode = EvoEditor.splitAtChild(parent, 
childNode);
 
-                                                       if (childNode === node || 
EvoEditor.IsBlockNode(parent))
-                                                               break;
+                                                               if (childNode === node || 
EvoEditor.IsBlockNode(parent))
+                                                                       break;
 
-                                                       parent = childNode.parentElement;
-                                               }
+                                                               parent = childNode.parentElement;
+                                                       }
 
-                                               blockquoteLevel = EvoEditor.getBlockquoteLevel(parent);
+                                                       blockquoteLevel = 
EvoEditor.getBlockquoteLevel(parent);
 
-                                               EvoEditor.quoteParagraph(childNode, blockquoteLevel, 
EvoEditor.NORMAL_PARAGRAPH_WIDTH - (2 * blockquoteLevel));
+                                                       EvoEditor.quoteParagraph(childNode, blockquoteLevel, 
EvoEditor.NORMAL_PARAGRAPH_WIDTH - (2 * blockquoteLevel));
 
-                                               document.getSelection().setPosition(childNode, 0);
-                                       } finally {
-                                               EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, 
"requote");
-                                               EvoUndoRedo.GroupTopRecords(2, "insertLineBreak::requote");
-                                               EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
-                                               EvoEditor.EmitContentChanged();
+                                                       document.getSelection().setPosition(childNode, 0);
+                                               } finally {
+                                                       
EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "requote");
+                                                       EvoUndoRedo.GroupTopRecords(2, 
"insertLineBreak::requote");
+                                                       
EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+                                                       EvoEditor.EmitContentChanged();
+                                               }
                                        }
                                }
-                       }
-               // it's an insert or delete in the blockquote, which means to recalculate where quotation 
marks should be
-               } else if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
-                       var node = document.getSelection().anchorNode;
+                       // it's an insert or delete in the blockquote, which means to recalculate where 
quotation marks should be
+                       } else if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+                               var node = document.getSelection().anchorNode;
 
-                       EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "requote::group");
-                       try {
-                               var selection = EvoSelection.Store(document);
+                               EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "requote::group");
+                               try {
+                                       var selection = EvoSelection.Store(document);
 
-                               node = EvoEditor.requoteNodeParagraph(node);
+                                       EvoEditor.removeEmptyElements("DIV");
+                                       EvoEditor.removeEmptyElements("PRE");
 
-                               if (node && inputEvent.inputType.startsWith("delete")) {
-                                       if (node.nextSiblingElement)
-                                               EvoEditor.requoteNodeParagraph(node.nextSiblingElement);
-                                       if (node.previousSiblingElement)
-                                               EvoEditor.requoteNodeParagraph(node.previousSiblingElement);
-                               }
+                                       node = EvoEditor.requoteNodeParagraph(node);
 
-                               EvoSelection.Restore(document, selection);
-                       } finally {
-                               EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "requote::group");
-                               EvoUndoRedo.GroupTopRecords(2, inputEvent.inputType + "::requote");
-                               EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
-                               EvoEditor.EmitContentChanged();
+                                       if (node && inputEvent.inputType.startsWith("delete")) {
+                                               if (node.nextSiblingElement)
+                                                       
EvoEditor.requoteNodeParagraph(node.nextSiblingElement);
+                                               if (node.previousSiblingElement)
+                                                       
EvoEditor.requoteNodeParagraph(node.previousSiblingElement);
+                                       }
+
+                                       EvoSelection.Restore(document, selection);
+                               } finally {
+                                       EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, 
"requote::group");
+                                       EvoUndoRedo.GroupTopRecords(2, inputEvent.inputType + "::requote");
+                                       EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+                                       EvoEditor.EmitContentChanged();
+                               }
                        }
                }
        }
diff --git a/src/e-util/test-html-editor-units.c b/src/e-util/test-html-editor-units.c
index 04bc9977b5..c738c23aef 100644
--- a/src/e-util/test-html-editor-units.c
+++ b/src/e-util/test-html-editor-units.c
@@ -5926,6 +5926,85 @@ test_delete_quoted_selection (TestFixture *fixture)
                g_test_fail ();
 }
 
+static void
+test_delete_quoted_multiselect (TestFixture *fixture)
+{
+       test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE);
+
+       if (!test_utils_run_simple_test (fixture,
+               "mode:html\n"
+               "action:paste-quote\n"
+               "type:X\n"
+               "undo:save\n" /* 1 */
+               "seq:ChcrrSdsD\n",
+               HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+               "<div>line 2</div>"
+               "<div>line 3X</div>"
+               "</blockquote>"
+               HTML_SUFFIX,
+               "> line 2\n"
+               "> line 3X\n")) {
+               g_test_fail ();
+               return;
+       }
+
+       if (!test_utils_run_simple_test (fixture,
+               "undo:undo\n"
+               "undo:test\n"
+               "undo:redo\n"
+               "undo:drop:1\n"
+               "seq:Cec\n" /* Go to the end of the document (Ctrl+End) */
+               "type:\\nY\n",
+               HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+               "<div>line 2</div>"
+               "<div>line 3X</div>"
+               "</blockquote>"
+               "<div>Y</div>"
+               HTML_SUFFIX,
+               "> line 2\n"
+               "> line 3X\n"
+               "Y\n")) {
+               g_test_fail ();
+               return;
+       }
+
+       test_utils_insert_content (fixture, "<body></body>", E_CONTENT_EDITOR_INSERT_REPLACE_ALL | 
E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+       if (!test_utils_run_simple_test (fixture,
+               "mode:plain\n"
+               "action:paste-quote\n"
+               "type:X\n"
+               "undo:save\n" /* 1 */
+               "seq:ChcrrSdsD\n",
+               HTML_PREFIX "<blockquote type=\"cite\">"
+               "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div>"
+               "<div>" QUOTE_SPAN (QUOTE_CHR) "line 3X</div>"
+               "</blockquote>"
+               HTML_SUFFIX,
+               "> line 2\n"
+               "> line 3X\n")) {
+               g_test_fail ();
+               return;
+       }
+
+       if (!test_utils_run_simple_test (fixture,
+               "undo:undo\n"
+               "undo:test\n"
+               "undo:redo\n"
+               "seq:Cec\n" /* Go to the end of the document (Ctrl+End) */
+               "type:\\nY\n",
+               HTML_PREFIX "<blockquote type=\"cite\">"
+               "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div>"
+               "<div>" QUOTE_SPAN (QUOTE_CHR) "line 3X</div>"
+               "</blockquote>"
+               "<div style=\"width: 71ch;\">Y</div>"
+               HTML_SUFFIX,
+               "> line 2\n"
+               "> line 3X\n"
+               "Y\n"))
+               g_test_fail ();
+}
+
 static void
 test_replace_dialog (TestFixture *fixture)
 {
@@ -6525,6 +6604,7 @@ main (gint argc,
        test_utils_add_test ("/delete/quoted", test_delete_quoted);
        test_utils_add_test ("/delete/after-quoted", test_delete_after_quoted);
        test_utils_add_test ("/delete/quoted-selection", test_delete_quoted_selection);
+       test_utils_add_test ("/delete/quoted-multiselect", test_delete_quoted_multiselect);
        test_utils_add_test ("/replace/dialog", test_replace_dialog);
        test_utils_add_test ("/replace/dialog-all", test_replace_dialog_all);
        test_utils_add_test ("/wrap/basic", test_wrap_basic);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]