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
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 16 Nov 2016 20:20:41 +0900
changeset 323378 a4c1e8110537ffa4c1f4064e71155bb6542d1ce7
parent 323377 ad5ce748ebddc103654bcfa8a3252b40c5ca3b7d
child 323379 43a0b34ba23a2f2c62f8973b8b60c141c210c99c
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +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
@@ -209,16 +209,17 @@ skip-if = toolkit == 'android'
 [test_bug1257363.html]
 [test_bug1248185.html]
 [test_bug1258085.html]
 [test_bug1268736.html]
 [test_bug1310912.html]
 skip-if = toolkit == 'android' # bug 1315898
 [test_bug1314790.html]
 [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>";