Remove style spans to follow the styles of the block element
This CL removes style spans to follow the styles of the block
element(li, pre, td, and h1~6) when the text of the pasted
or merged element becomes a part of the block element.
BUG=226941
TEST=third_party/WebKit/LayoutTests/editing/deleting/backspace-merge-into-block-element.html
Review-Url: https://codereview.chromium.org/2102913002
Cr-Commit-Position: refs/heads/master@{#402659}
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/backspace-merge-into-block.html b/third_party/WebKit/LayoutTests/editing/deleting/backspace-merge-into-block.html
new file mode 100644
index 0000000..f57277f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/deleting/backspace-merge-into-block.html
@@ -0,0 +1,36 @@
+<!doctype HTML>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
+<style>
+p {
+ font-size: 20px;
+ line-height: 22px;
+ color: red;
+}
+</style>
+<div id="log"></div>
+<script>
+test(() => {
+ assert_selection(
+ '<div contenteditable="true"><h1>Heading 1:</h1>^<p>|paragraph was merged.</p></div>',
+ 'delete',
+ '<div contenteditable="true"><h1>Heading 1:|paragraph was merged.</h1></div>',
+ 'Make a paragraph into a heading');
+ assert_selection(
+ '<div contenteditable="true"><pre>Preformatted text:</pre>^<p>|paragraph was merged.</p></div>',
+ 'delete',
+ '<div contenteditable="true"><pre>Preformatted text:|paragraph was merged.</pre></div>',
+ 'Make a paragraph into a pre');
+ assert_selection(
+ '<div contenteditable="true"><ul><li>List Item:</li></ul>^<p>|paragraph was merged.</p></div>',
+ 'delete',
+ '<div contenteditable="true"><ul><li>List Item:|paragraph was merged.</li></ul></div>',
+ 'Make a paragraph into a list');
+ assert_selection(
+ '<div contenteditable="true"><table><tbody><tr><td>Table:</td></tr></tbody></table>^<p>|paragraph was merged.</p></div>',
+ 'delete',
+ '<div contenteditable="true"><table><tbody><tr><td>Table:|paragraph was merged.</td></tr></tbody></table></div>',
+ 'Make a paragraph into a table');
+}, 'merge into a block by backspace');
+</script>
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/backspace-merge-into-list-item.html b/third_party/WebKit/LayoutTests/editing/deleting/backspace-merge-into-list-item.html
deleted file mode 100644
index 3daa5ad..0000000
--- a/third_party/WebKit/LayoutTests/editing/deleting/backspace-merge-into-list-item.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!doctype HTML>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<style>
-#editable p {
- font-size: 20px;
- line-height: 22px;
- color: red;
-}
-</style>
-<div contenteditable="true" id="editable">
- <ul>
- <li>list item 1</li>
- <li>list item 2</li>
- <li>list item 3</li>
- </ul>
- <p>Paragraph</p>
-</div>
-<script>
-test(function() {
- var editor = document.getElementById('editable');
- var range = document.createRange();
- var selection = window.getSelection();
- range.setStart(editor.childNodes[2], 0);
- range.collapse(true);
- selection.removeAllRanges();
- selection.addRange(range);
- editor.focus();
- document.execCommand('delete');
-
- var htmlPara = document.getElementsByTagName('li')[2].outerHTML;
- assert_equals(htmlPara, '<li>list item 3Paragraph</li>');
-}, 'make a paragraph into a list by backspace');
-</script>
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/merge-paragraph-from-p-with-style-3-expected.txt b/third_party/WebKit/LayoutTests/editing/deleting/merge-paragraph-from-p-with-style-3-expected.txt
index 7984090..87d0eb6 100644
--- a/third_party/WebKit/LayoutTests/editing/deleting/merge-paragraph-from-p-with-style-3-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/deleting/merge-paragraph-from-p-with-style-3-expected.txt
@@ -7,10 +7,7 @@
| "
"
| <h1>
-| "hello<#selection-caret>"
-| <span>
-| style="color: green;"
-| "world"
+| "hello<#selection-caret>world"
| <font>
| color="red"
| "
diff --git a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
index cfbeebd..65e1689 100644
--- a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
@@ -35,6 +35,7 @@
#include "core/dom/Document.h"
#include "core/dom/DocumentFragment.h"
#include "core/dom/Element.h"
+#include "core/dom/NodeComputedStyle.h"
#include "core/dom/Text.h"
#include "core/editing/EditingUtilities.h"
#include "core/editing/FrameSelection.h"
@@ -794,6 +795,23 @@
}
}
+static bool followBlockElementStyle(const Node* node)
+{
+ if (!node->isHTMLElement())
+ return false;
+
+ const HTMLElement& element = toHTMLElement(*node);
+ return element.computedStyle()->display() == LIST_ITEM
+ || element.computedStyle()->display() == TABLE_CELL
+ || element.hasTagName(preTag)
+ || element.hasTagName(h1Tag)
+ || element.hasTagName(h2Tag)
+ || element.hasTagName(h3Tag)
+ || element.hasTagName(h4Tag)
+ || element.hasTagName(h5Tag)
+ || element.hasTagName(h6Tag);
+}
+
// Remove style spans before insertion if they are unnecessary. It's faster because we'll
// avoid doing a layout.
static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos)
@@ -807,10 +825,19 @@
if (isMailPasteAsQuotationHTMLBlockQuoteElement(topNode) || enclosingNodeOfType(firstPositionInOrBeforeNode(topNode), isMailHTMLBlockquoteElement, CanCrossEditingBoundary))
return false;
- // Remove style spans to follow the styles of list item when |fragment| becomes a list item.
- // See bug http://crbug.com/335955.
+ // Remove style spans to follow the styles of parent block element when |fragment| becomes a part of it.
+ // See bugs http://crbug.com/226941 and http://crbug.com/335955.
HTMLSpanElement* wrappingStyleSpan = toHTMLSpanElement(topNode);
- if (isListItem(enclosingBlock(insertionPos.anchorNode()))) {
+ const Node* node = insertionPos.anchorNode();
+ // |node| can be an inline element like <br> under <li>
+ // e.g.) editing/execCommand/switch-list-type.html
+ // editing/deleting/backspace-merge-into-block.html
+ if (node->computedStyle()->display() == INLINE) {
+ if (!(node = enclosingBlock(insertionPos.anchorNode())))
+ return false;
+ }
+
+ if (followBlockElementStyle(node)) {
fragment.removeNodePreservingChildren(wrappingStyleSpan);
return true;
}