Bug 1316302 part.2 WillDeleteSelection() should retry to handle it when selection is collapsed and JoinBlocks() doesn't handle nor cancel the action r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 16 Nov 2016 20:20:41 +0900
changeset 439602 0aaa7642795b288b2df070e6bb83ac3e8fb6c9bd
parent 439597 d201b4136a52f28cfc3f37fcbbb545c6a6fab99c
child 439603 e948cc22afe1be80cb4e0e1076d0dd6546f04f59
push id36058
push usermasayuki@d-toybox.com
push dateWed, 16 Nov 2016 11:23:22 +0000
reviewerssmaug
bugs1316302
milestone53.0a1
Bug 1316302 part.2 WillDeleteSelection() should retry to handle it when selection is collapsed and JoinBlocks() doesn't handle nor cancel the action r?smaug When selection is collapsed and JoinBlocks() doesn't handle nor cancel the action, WillDeleteSelection() should move selection to the start/end of leftmost/rightmost editable leaf node and retry to handle the action again. For avoiding infinite loop, it checks if selected node is changed actually before calling itself again. MozReview-Commit-ID: GtEC4dim3r9
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/tests/mochitest.ini
editor/libeditor/tests/test_bug1316302.html
editor/libeditor/tests/test_bug414526.html
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -2170,22 +2170,34 @@ HTMLEditRules::WillDeleteSelection(Selec
         NS_ENSURE_STATE(mHTMLEditor);
         AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
                                   address_of(selPointNode), &selPointOffset);
         NS_ENSURE_STATE(leftNode && leftNode->IsContent() &&
                         rightNode && rightNode->IsContent());
         bool handled = false, canceled = false;
         rv = TryToJoinBlocks(*leftNode->AsContent(), *rightNode->AsContent(),
                              &canceled, &handled);
-        // TODO: If it does nothing and previous or next node is a text node,
-        //       we should modify it.
-        *aHandled = true;
+        *aHandled |= handled;
         *aCancel |= canceled;
         NS_ENSURE_SUCCESS(rv, rv);
       }
+
+      // If TryToJoinBlocks() didn't handle it  and it's not canceled,
+      // user may want to modify the start leaf node or the last leaf node
+      // of the block.
+      if (!*aHandled && !*aCancel && leafNode != startNode) {
+        int32_t offset =
+          aAction == nsIEditor::ePrevious ?
+            static_cast<int32_t>(leafNode->Length()) : 0;
+        aSelection->Collapse(leafNode, offset);
+        return WillDeleteSelection(aSelection, aAction, aStripWrappers,
+                                   aCancel, aHandled);
+      }
+
+      // Otherwise, we must have deleted the selection as user expected.
       aSelection->Collapse(selPointNode, selPointOffset);
       return NS_OK;
     }
 
     if (wsType == WSType::thisBlock) {
       // At edge of our block.  Look beside it and see if we can join to an
       // adjacent block
 
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -208,16 +208,17 @@ skip-if = toolkit == 'android'
 [test_bug1250010.html]
 [test_bug1257363.html]
 [test_bug1248185.html]
 [test_bug1258085.html]
 [test_bug1268736.html]
 [test_bug1310912.html]
 skip-if = toolkit == 'android' # bug 1315898
 [test_bug1315065.html]
+[test_bug1316302.html]
 
 [test_CF_HTML_clipboard.html]
 subsuite = clipboard
 [test_composition_event_created_in_chrome.html]
 [test_contenteditable_focus.html]
 [test_dom_input_event_on_htmleditor.html]
 skip-if = toolkit == 'android' # bug 1054087
 [test_dom_input_event_on_texteditor.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1316302.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1316302
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1316302</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1316302">Mozilla Bug 1316302</a>
+<div contenteditable>
+<blockquote><p>abc</p></blockquote>
+</div>
+<script type="application/javascript">
+/** Test for Bug 1316302 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(()=>{
+  var editor = document.getElementsByTagName("div")[0];
+  var blockquote = document.getElementsByTagName("blockquote")[0];
+  var selection = window.getSelection();
+
+  editor.focus();
+
+  // Try to remove the last character from the end of the <blockquote>
+  selection.collapse(blockquote, blockquote.childNodes.length);
+  var range = selection.getRangeAt(0);
+  ok(range.collapsed, "range should be collapsed at the end of <blockquote>");
+  is(range.startContainer, blockquote, "range should be collapsed in the <blockquote>");
+  is(range.startOffset, blockquote.childNodes.length, "range should be collapsed at the end");
+  synthesizeKey("KEY_Backspace", { code: "Backspace" });
+  is(blockquote.innerHTML, "<p>ab</p>", "Pressing Backspace key at the end of <blockquote> should remove the last character in the <p>");
+
+  // Try to remove the first character from the start of the <blockquote>
+  selection.collapse(blockquote, 0);
+  range = selection.getRangeAt(0);
+  ok(range.collapsed, "range should be collapsed at the start of <blockquote>");
+  is(range.startContainer, blockquote, "range should be collapsed in the <blockquote>");
+  is(range.startOffset, 0, "range should be collapsed at the start");
+  synthesizeKey("KEY_Delete", { code: "Delete" });
+  is(blockquote.innerHTML, "<p>b</p>", "Pressing Delete key at the start of <blockquote> should remove the first character in the <p>");
+
+  SimpleTest.finish();
+});
+</script>
+</body>
+</html>
--- a/editor/libeditor/tests/test_bug414526.html
+++ b/editor/libeditor/tests/test_bug414526.html
@@ -145,30 +145,22 @@ function runTests()
   editor3.focus();
   moveCaretToStartOf(editor3);
   synthesizeKey("VK_DELETE", { });
   is(container.innerHTML, kTestCase1_editor3_deleteAtStart,
      "Pressing delete key at start of editor3 changes adjacent elements"
      + " and/or does not remove the first character.");
   reset();
 
-  // Backspace doesn't work here yet.
   editor3.focus();
   moveCaretToEndOf(editor3);
   synthesizeKey("VK_BACK_SPACE", { });
-  todo_is(container.innerHTML, kTestCase1_editor3_backspaceAtEnd,
-          "Pressing backspace key at end of editor3 changes adjacent elements"
-          + " and/or does not remove the last character.");
-  reset();
-  //  We can still check that adjacent elements are not affected.
-  editor3.focus();
-  moveCaretToEndOf(editor3);
-  synthesizeKey("VK_BACK_SPACE", { });
-  is(container.innerHTML, kTestCase1,
-     "Pressing backspace key at end of editor3 changes the content");
+  is(container.innerHTML, kTestCase1_editor3_backspaceAtEnd,
+     "Pressing backspace key at end of editor3 changes adjacent elements"
+     + " and/or does not remove the last character.");
   reset();
 
   /* TestCase #2:
    * two adjacent editable <span> in a table cell.
    */
   const kTestCase2 = "<table><tbody><tr><td><span id=\"editor1\" contenteditable=\"true\">test</span>" +
     "<span id=\"editor2\" contenteditable=\"true\">test</span></td></tr></tbody></table>";