WebCore:

2009-02-06  Justin Garcia  <justin.garcia@apple.com>

        Reviewed by Oliver Hunt.
        
        https://bugs.webkit.org/show_bug.cgi?id=23800
        Header elements are not always preserved during paste
        
        At paste time, don't merge out of header elements.  At copy time, be sure to include
        headers in the list of special common ancestor blocks, so that copying a paragraph or less
        of content inside a header will include the header element in the copied markup.

        * editing/ReplaceSelectionCommand.cpp:
        (WebCore::areSameHeaderElements):
        (WebCore::ReplaceSelectionCommand::shouldMerge):
        * editing/markup.cpp:
        (WebCore::isSpecialAncestorBlock):
        (WebCore::createMarkup):

LayoutTests:

2009-02-06  Justin Garcia  <justin.garcia@apple.com>

        Reviewed by Oliver Hunt.
        
        https://bugs.webkit.org/show_bug.cgi?id=23800
        Header elements are not always preserved during paste

        * editing/execCommand/4128080-1-expected.txt: Added.
        * editing/execCommand/4128080-1.html: Added.
        * editing/execCommand/4128080-2-expected.txt: Added.
        * editing/execCommand/4128080-2.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@40741 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 858c1b45
2009-02-06 Justin Garcia <justin.garcia@apple.com>
Reviewed by Oliver Hunt.
https://bugs.webkit.org/show_bug.cgi?id=23800
Header elements are not always preserved during paste
* editing/execCommand/4128080-1-expected.txt: Added.
* editing/execCommand/4128080-1.html: Added.
* editing/execCommand/4128080-2-expected.txt: Added.
* editing/execCommand/4128080-2.html: Added.
2009-02-05 Alexey Proskuryakov <ap@webkit.org>
Reviewed by Darin Adler.
......
<div id="div1" contentEditable="true">foofoo</div>
<div id="div2" contentEditable="true">foofoo</div>
<script>
if (window.layoutTestController)
window.layoutTestController.dumpAsText();
output = "";
// Test 1: Verify that a header at the beginning of inserted content is preserved.
div = document.getElementById("div1");
text = div.firstChild;
window.getSelection().setPosition(text, 3);
document.execCommand("InsertHTML", false, "<h1>bar</h1><div>baz</div>");
expected = "foo<h1>bar</h1>bazfoo";
actual = div.innerHTML;
if (actual == expected)
output += "Success\n";
else
output += "Failure. Result was: " + actual + ", should have been: " + expected + "\n";
// Test 2: Verify that a header at the end of inserted content is preserved.
div = document.getElementById("div2");
text = div.firstChild;
window.getSelection().setPosition(text, 3);
document.execCommand("InsertHTML", false, "<div>bar</div><h1>baz</h1>");
expected = "foobar<h1>baz</h1>foo";
actual = div.innerHTML;
if (actual == expected)
output += "Success\n";
else
output += "Failure. Result was: " + actual + ", should have been: " + expected + "\n";
document.body.innerText = output;
</script>
<div id="description">This tests to make sure that copying and pasting a paragraph or less of content inside a header preserves the header element. To run it manually, Paste, then inspect the pasted content and verify that it's in an H1 element.</div>
<div id="copy"><h1>foo</h1></div>
<div id="paste" contentEditable="true"></div>
<script>
if (window.layoutTestController)
window.layoutTestController.dumpAsText();
// Test 2: Verify that a header at the end of inserted content is preserved.
copy = document.getElementById("copy");
window.getSelection().setBaseAndExtent(copy, 0, copy, copy.childNodes.length);
document.execCommand("Copy");
paste = document.getElementById("paste");
window.getSelection().setPosition(paste, 0);
document.execCommand("Paste");
expected = "<h1>foo</h1>";
actual = paste.innerHTML;
if (window.layoutTestController && actual == expected)
document.body.innerText = "Success";
else
document.body.innerText = "Failure. Found: " + actual + ", but expected: " + expected;
</script>
<html>
<head>
<style>
.editing {
border: 2px solid red;
font-size: 24px;
}
.explanation {
border: 2px solid blue;
padding: 12px;
font-size: 24px;
margin-bottom: 24px;
}
.scenario { margin-bottom: 16px;}
.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
.expected-results:first-line { font-weight: bold }
</style>
<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
<script>
function editingTest() {
moveSelectionForwardByLineCommand();
extendSelectionForwardByLineCommand();
cutCommand();
deleteCommand();
moveSelectionBackwardByLineCommand();
moveSelectionForwardByCharacterCommand();
moveSelectionForwardByCharacterCommand();
pasteCommand();
}
</script>
<title>Editing Test</title>
</head>
<body>
<div class="explanation">
<div class="scenario">
Tests:
<br>
Pasting text which gets its style from an &lt;H1&gt; tag into a block of styled text.
</div>
<div class="expected-results">
Expected Results:
<br>
Should see this content in the red box below: <span style="font-family: Lucida Grande; color: red">ab<span style="color: black; font-family: serif; font-size: 32px; font-weight: bold">cde</span>fg</span>
</div>
</div>
<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
<div id="test" class="editing">
<span style="font-family: Lucida Grande; color: red">abfg</span>
</div>
<h1>
cde
</div>
</div>
<script>
runEditingTest();
</script>
</body>
</html>
e23c73b1512999a9a4f4286b23254eb0
\ No newline at end of file
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 4 of DIV > BODY > HTML > #document
EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldDeleteDOMRange:range from 1 of #text > H1 > DIV > BODY > HTML > #document to 4 of #text > H1 > DIV > BODY > HTML > #document
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of H1 > DIV > BODY > HTML > #document to 0 of H1 > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
EDITING DELEGATE: shouldDeleteDOMRange:range from 1 of #text > DIV > DIV > BODY > HTML > #document to 0 of H1 > DIV > BODY > HTML > #document
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 4 of #text > SPAN > DIV > DIV > BODY > HTML > #document to 4 of #text > SPAN > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 2 of #text > SPAN > DIV > DIV > BODY > HTML > #document to 2 of #text > SPAN > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 3 of #text > SPAN > SPAN > DIV > DIV > BODY > HTML > #document to 3 of #text > SPAN > SPAN > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x584
RenderBlock {DIV} at (0,0) size 784x165 [border: (2px solid #0000FF)]
RenderBlock {DIV} at (14,14) size 756x56
RenderText {#text} at (0,0) size 67x28
text run at (0,0) width 67: "Tests: "
RenderBR {BR} at (0,0) size 0x0
RenderText {#text} at (0,28) size 746x28
text run at (0,28) width 746: "Pasting text which gets its style from an <H1> tag into a block of styled text."
RenderBlock {DIV} at (14,86) size 756x65
RenderText {#text} at (0,0) size 189x28
text run at (0,0) width 189: "Expected Results: "
RenderBR {BR} at (189,22) size 0x0
RenderText {#text} at (0,35) size 442x28
text run at (0,35) width 442: "Should see this content in the red box below: "
RenderInline {SPAN} at (0,0) size 99x28 [color=#FF0000]
RenderText {#text} at (442,34) size 29x28
text run at (442,34) width 29: "ab"
RenderInline {SPAN} at (0,0) size 46x37 [color=#000000]
RenderText {#text} at (471,28) size 46x37
text run at (471,28) width 46: "cde"
RenderText {#text} at (517,34) size 24x28
text run at (517,34) width 24: "fg"
RenderText {#text} at (0,0) size 0x0
RenderBlock {DIV} at (0,189) size 784x41
RenderBlock {DIV} at (0,0) size 784x41 [border: (2px solid #FF0000)]
RenderInline {SPAN} at (0,0) size 99x28 [color=#FF0000]
RenderText {#text} at (2,8) size 29x28
text run at (2,8) width 29: "ab"
RenderInline {SPAN} at (0,0) size 70x37 [color=#000000]
RenderText {#text} at (31,2) size 46x37
text run at (31,2) width 46: "cde"
RenderInline {SPAN} at (0,0) size 24x28 [color=#FF0000]
RenderText {#text} at (77,8) size 24x28
text run at (77,8) width 24: "fg"
RenderBlock (anonymous) at (0,41) size 784x0
caret: position 3 of child 0 {#text} of child 1 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document
2009-02-06 Justin Garcia <justin.garcia@apple.com>
Reviewed by Oliver Hunt.
https://bugs.webkit.org/show_bug.cgi?id=23800
Header elements are not always preserved during paste
At paste time, don't merge out of header elements. At copy time, be sure to include
headers in the list of special common ancestor blocks, so that copying a paragraph or less
of content inside a header will include the header element in the copied markup.
* editing/ReplaceSelectionCommand.cpp:
(WebCore::areSameHeaderElements):
(WebCore::ReplaceSelectionCommand::shouldMerge):
* editing/markup.cpp:
(WebCore::isSpecialAncestorBlock):
(WebCore::createMarkup):
2009-02-06 Geoffrey Garen <ggaren@apple.com>
Reviewed by Sam Weinig.
......@@ -405,6 +405,22 @@ void ReplaceSelectionCommand::removeNodeAndPruneAncestors(Node* node)
if (m_firstNodeInserted && !m_firstNodeInserted->inDocument())
m_firstNodeInserted = m_lastLeafInserted && m_lastLeafInserted->inDocument() ? afterFirst : 0;
}
bool isHeaderElement(Node* a)
{
if (!a)
return false;
return a->hasTagName(h1Tag) ||
a->hasTagName(h2Tag) ||
a->hasTagName(h3Tag) ||
a->hasTagName(h4Tag) ||
a->hasTagName(h5Tag);
}
bool haveSameTagName(Node* a, Node* b)
{
return a && b && a->isElementNode() && b->isElementNode() && static_cast<Element*>(a)->tagName() == static_cast<Element*>(b)->tagName();
}
bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const VisiblePosition& destination)
{
......@@ -414,10 +430,12 @@ bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V
Node* sourceNode = source.deepEquivalent().node();
Node* destinationNode = destination.deepEquivalent().node();
Node* sourceBlock = enclosingBlock(sourceNode);
Node* destinationBlock = enclosingBlock(destinationNode);
return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotationNode) &&
sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || isMailBlockquote(sourceBlock)) &&
enclosingListChild(sourceBlock) == enclosingListChild(destinationNode) &&
enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(destination.deepEquivalent()) &&
(!isHeaderElement(sourceBlock) || haveSameTagName(sourceBlock, destinationBlock)) &&
// Don't merge to or from a position before or after a block because it would
// be a no-op and cause infinite recursion.
!isBlock(sourceNode) && !isBlock(destinationNode);
......
......@@ -701,6 +701,24 @@ static String joinMarkups(const Vector<String>& preMarkups, const Vector<String>
return String::adopt(result);
}
bool isSpecialAncestorBlock(Node* node)
{
if (!node || !isBlock(node))
return false;
return node->hasTagName(listingTag) ||
node->hasTagName(olTag) ||
node->hasTagName(preTag) ||
node->hasTagName(tableTag) ||
node->hasTagName(ulTag) ||
node->hasTagName(xmpTag) ||
node->hasTagName(h1Tag) ||
node->hasTagName(h2Tag) ||
node->hasTagName(h3Tag) ||
node->hasTagName(h4Tag) ||
node->hasTagName(h5Tag);
}
// FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange?
// FIXME: At least, annotation and style info should probably not be included in range.markupString()
String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterchange annotate, bool convertBlocksToInlines)
......@@ -849,12 +867,7 @@ String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterc
table = table->parentNode();
if (table)
specialCommonAncestor = table;
} else if (commonAncestorBlock->hasTagName(listingTag)
|| commonAncestorBlock->hasTagName(olTag)
|| commonAncestorBlock->hasTagName(preTag)
|| commonAncestorBlock->hasTagName(tableTag)
|| commonAncestorBlock->hasTagName(ulTag)
|| commonAncestorBlock->hasTagName(xmpTag))
} else if (isSpecialAncestorBlock(commonAncestorBlock))
specialCommonAncestor = commonAncestorBlock;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment