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 441064 da758179414a8fd40bd9b815f71140e545c75b1d
parent 441063 9efa5e3e3140f490ccd3565e3d4de35a6faf4463
child 441065 4df56c556d628ce26b396a451e53fc65006d8b26
push id36347
push usermasayuki@d-toybox.com
push dateFri, 18 Nov 2016 10:04:41 +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>";