+2006-05-02 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by harrison
+
+ <http://bugzilla.opendarwin.org/show_bug.cgi?id=8704>
+ Fix a few end merge bugs
+ <rdar://problem/4424044>
+ REGRESSION: Extra line appears when typing
+
+ Added a function so that selection changes can participate in slow-motion-mode:
+ * editing/editing.js:
+ Extra newlines were added:
+ * editing/inserting/paragraph-separator-01-expected.checksum: Added.
+ * editing/inserting/paragraph-separator-01-expected.png: Added.
+ * editing/inserting/paragraph-separator-01-expected.txt: Added.
+ * editing/inserting/paragraph-separator-01.html: Added.
+ * editing/inserting/paragraph-separator-02-expected.checksum: Added.
+ * editing/inserting/paragraph-separator-02-expected.png: Added.
+ * editing/inserting/paragraph-separator-02-expected.txt: Added.
+ * editing/inserting/paragraph-separator-02.html: Added.
+ A preserved newline was turned into a nbsp:
+ * editing/inserting/paragraph-separator-03-expected.checksum: Added.
+ * editing/inserting/paragraph-separator-03-expected.png: Added.
+ * editing/inserting/paragraph-separator-03-expected.txt: Added.
+ * editing/inserting/paragraph-separator-03.html: Added.
+ End merge didn't happen:
+ * editing/pasteboard/merge-end-4-expected.checksum: Added.
+ * editing/pasteboard/merge-end-4-expected.png: Added.
+ * editing/pasteboard/merge-end-4-expected.txt: Added.
+ * editing/pasteboard/merge-end-4.html: Added.
+ Content was pulled out of these special elements:
+ * editing/pasteboard/merge-end-blockquote-expected.checksum: Added.
+ * editing/pasteboard/merge-end-blockquote-expected.png: Added.
+ * editing/pasteboard/merge-end-blockquote-expected.txt: Added.
+ * editing/pasteboard/merge-end-blockquote.html: Added.
+ * editing/pasteboard/merge-end-list-expected.checksum: Added.
+ * editing/pasteboard/merge-end-list-expected.png: Added.
+ * editing/pasteboard/merge-end-list-expected.txt: Added.
+ * editing/pasteboard/merge-end-list.html: Added.
+ * editing/pasteboard/merge-end-table-expected.checksum: Added.
+ * editing/pasteboard/merge-end-table-expected.png: Added.
+ * editing/pasteboard/merge-end-table-expected.txt: Added.
+ * editing/pasteboard/merge-end-table.html: Added.
+
2006-05-02 Anders Carlsson <andersca@mac.com>
Reviewed by Dave Hyatt.
//-------------------------------------------------------------------------------------------------------
+function execSetSelectionCommand(sn, so, en, eo) {
+ window.getSelection().setBaseAndExtent(sn, so, en, eo);
+}
+function setSelectionCommand(sn, so, en, eo) {
+ if (commandDelay > 0) {
+ window.setTimeout(execSetSelectionCommand, commandCount * commandDelay, sn, so, en, eo);
+ commandCount++;
+ } else
+ execSetSelectionCommand(sn, so, en, eo);
+}
+
+//-------------------------------------------------------------------------------------------------------
+
function execTransposeCharactersCommand() {
document.execCommand("Transpose");
}
--- /dev/null
+93799e14c727b5db18680879114d7c4d
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 3 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 3 of #text > DIV > BODY > HTML > #document to 3 of #text > DIV > BODY > HTML > #document toDOMRange:range from 0 of DIV > DIV > BODY > HTML > #document to 0 of DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+layer at (0,0) size 800x600
+ RenderCanvas 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 {P} at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 585x18
+ text run at (0,0) width 361: "Tests for a bug in the paragraph separator insertion code. "
+ text run at (361,0) width 224: "Only one newline should be added."
+ RenderBlock {DIV} at (0,34) size 784x54
+ RenderBlock (anonymous) at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 21x18
+ text run at (0,0) width 21: "foo"
+ RenderBlock {DIV} at (0,18) size 784x36
+ RenderBlock (anonymous) at (0,0) size 784x18
+ RenderBR {BR} at (0,0) size 0x18
+ RenderBlock {DIV} at (0,18) size 784x18
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "bar"
+caret: position 0 of child 0 {BR} of child 1 {DIV} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+<p>Tests for a bug in the paragraph separator insertion code. Only one newline should be added.</p>
+<div id="test" contenteditable="true">foo<br><div>bar</div></div>
+
+<script type="text/javascript" src="../editing.js"></script>
+<script>
+var e = document.getElementById("test");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+moveSelectionForwardByWordCommand();
+insertParagraphCommand();
+</script>
\ No newline at end of file
--- /dev/null
+93799e14c727b5db18680879114d7c4d
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 2 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 3 of #text > DIV > BODY > HTML > #document to 3 of #text > DIV > BODY > HTML > #document toDOMRange:range from 0 of DIV > DIV > BODY > HTML > #document to 0 of DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+layer at (0,0) size 800x600
+ RenderCanvas 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 {P} at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 585x18
+ text run at (0,0) width 361: "Tests for a bug in the paragraph separator insertion code. "
+ text run at (361,0) width 224: "Only one newline should be added."
+ RenderBlock {DIV} at (0,34) size 784x54
+ RenderBlock (anonymous) at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 21x18
+ text run at (0,0) width 21: "foo"
+ RenderBlock {DIV} at (0,18) size 784x36
+ RenderBlock (anonymous) at (0,0) size 784x18
+ RenderBR {BR} at (0,0) size 0x18
+ RenderBlock {DIV} at (0,18) size 784x18
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "bar"
+caret: position 0 of child 0 {BR} of child 1 {DIV} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+<p>Tests for a bug in the paragraph separator insertion code. Only one newline should be added.</p>
+<div id="test" contenteditable="true">foo<div>bar</div></div>
+
+<script type="text/javascript" src="../editing.js"></script>
+<script>
+var e = document.getElementById("test");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+moveSelectionForwardByWordCommand();
+insertParagraphCommand();
+</script>
\ No newline at end of file
--- /dev/null
+4e7265437c081de5e72698981740280b
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of PRE > DIV > BODY > HTML > #document to 0 of PRE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+layer at (0,0) size 800x600
+ RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x579
+ RenderBlock {P} at (0,0) size 784x54
+ RenderText {#text} at (0,0) size 754x54
+ text run at (0,0) width 734: "Tests for a bug in the paragraph separator insertion code that would add an extra newline when inserting a paragraph"
+ text run at (0,18) width 418: "separator at the end of a paragraph in text that preserves newlines. "
+ text run at (418,18) width 336: "Also, an extraneous space would be added after 'foo'."
+ text run at (0,36) width 228: "Only one newline should be added. "
+ text run at (228,36) width 269: "And there should be no extraneous spaces."
+ RenderBlock {P} at (0,70) size 784x18
+ RenderInline {B} at (0,0) size 152x18
+ RenderText {#text} at (0,0) size 152x18
+ text run at (0,0) width 152: "It demonstrates a bug:"
+ RenderText {#text} at (152,0) size 583x18
+ text run at (152,0) width 583: " too much padding is left between the new line and the end of the paragraph containing 'foo'."
+ RenderBlock {DIV} at (0,104) size 784x58
+ RenderBlock {PRE} at (0,0) size 784x15
+ RenderText {#text} at (0,0) size 24x15
+ text run at (0,0) width 24: "foo"
+ RenderBlock {PRE} at (0,28) size 784x30
+ RenderText {#text} at (0,0) size 24x30
+ text run at (0,0) width 0: " "
+ text run at (0,15) width 24: "bar"
+caret: position 0 of child 0 {#text} of child 1 {PRE} of child 4 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+<p>Tests for a bug in the paragraph separator insertion code that would add an extra newline when inserting a paragraph separator at the end of a paragraph in text that preserves newlines. Also, an extraneous space would be added after 'foo'. Only one newline should be added. And there should be no extraneous spaces.</p>
+<p><b>It demonstrates a bug:</b> too much padding is left between the new line and the end of the paragraph containing 'foo'.</p>
+<div id="test" contenteditable="true"><pre>foo
+bar</pre></div>
+
+<script type="text/javascript" src="../editing.js"></script>
+<script>
+var e = document.getElementById("test");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+moveSelectionForwardByWordCommand();
+insertParagraphCommand();
+</script>
\ No newline at end of file
--- /dev/null
+d9f09bf8753f0b0ce51a463382519e66
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 3 of #text > DIV > DIV > BODY > HTML > #document to 3 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+layer at (0,0) size 800x600
+ RenderCanvas 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 {P} at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 545x18
+ text run at (0,0) width 336: "Tests for a case where paste's end merge was failing. "
+ text run at (336,0) width 209: "You should see xfoo\\nbar\\nbazx."
+ RenderBlock {DIV} at (0,34) size 784x54
+ RenderBlock (anonymous) at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 8x18
+ text run at (0,0) width 8: "x"
+ RenderText {#text} at (8,0) size 21x18
+ text run at (8,0) width 21: "foo"
+ RenderBlock {DIV} at (0,18) size 784x18
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "bar"
+ RenderBlock (anonymous) at (0,36) size 784x0
+ RenderBlock {DIV} at (0,36) size 784x18
+ RenderText {#text} at (0,0) size 22x18
+ text run at (0,0) width 22: "baz"
+ RenderText {#text} at (22,0) size 8x18
+ text run at (22,0) width 8: "x"
+caret: position 3 of child 0 {#text} of child 3 {DIV} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+<p>Tests for a case where paste's end merge was failing. You should see xfoo\nbar\nbazx.</p>
+<div id="test" contenteditable="true">xx</div>
+
+<script type="text/javascript" src="../editing.js"></script>
+<script>
+var e = document.getElementById("test");
+var s = window.getSelection();
+
+s.setPosition(e, 0);
+moveSelectionForwardByCharacterCommand();
+insertHTMLCommand("<div>foo</div><div>bar</div>baz");
+</script>
\ No newline at end of file
--- /dev/null
+e109b0d0ef8241dca4013225c26f810d
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 0 of #text > DIV > BODY > HTML > #document toDOMRange:range from 16 of #text > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document to 16 of #text > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldEndEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 2 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 3 of #text > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document to 3 of #text > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+layer at (0,0) size 800x600
+ RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x576
+ RenderBlock {P} at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 597x18
+ text run at (0,0) width 597: "This tests pasting a Mail blockquote into a position that would normally result in an end merge."
+ RenderBlock {DIV} at (0,34) size 784x52
+ RenderBlock {BLOCKQUOTE} at (40,0) size 704x18
+ RenderBlock {DIV} at (0,0) size 704x18
+ RenderText {#text} at (0,0) size 114x18
+ text run at (0,0) width 114: "Blockquoted Text"
+ RenderBlock (anonymous) at (0,34) size 784x18
+ RenderText {#text} at (0,0) size 8x18
+ text run at (0,0) width 8: "x"
+ RenderBlock {P} at (0,102) size 784x36
+ RenderText {#text} at (0,0) size 759x36
+ text run at (0,0) width 289: "This tests pasting text into a Mail blockquote. "
+ text run at (289,0) width 470: "The last bit of content in the incoming fragment should be merged with the"
+ text run at (0,18) width 287: "paragraph after the position being pasted into."
+ RenderBlock {DIV} at (0,154) size 784x36
+ RenderBlock {BLOCKQUOTE} at (40,0) size 704x36
+ RenderBlock {DIV} at (0,0) size 704x18
+ RenderText {#text} at (0,0) size 81x18
+ text run at (0,0) width 81: "Blockquoted"
+ RenderText {#text} at (81,0) size 21x18
+ text run at (81,0) width 21: "foo"
+ RenderBlock {DIV} at (0,18) size 704x18
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "bar"
+ RenderText {#text} at (20,0) size 33x18
+ text run at (20,0) width 33: " Text"
+caret: position 3 of child 0 {#text} of child 1 {DIV} of child 0 {BLOCKQUOTE} of child 10 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+<p>This tests pasting a Mail blockquote into a position that would normally result in an end merge.</p>
+<div id="test1" contenteditable="true">x</div>
+
+<script type="text/javascript" src="../editing.js"></script>
+<script>
+var e = document.getElementById("test1");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+insertHTMLCommand("<blockquote type='cite'><div>Blockquoted Text</div></blockquote>");
+</script>
+
+<p>This tests pasting text into a Mail blockquote. The last bit of content in the incoming fragment should be merged with the paragraph after the position being pasted into.</p>
+<div id="test2" contenteditable="true"><blockquote type='cite'><div>Blockquoted Text</div></blockquote></div>
+
+<script>
+var e = document.getElementById("test2");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+moveSelectionForwardByWordCommand();
+insertHTMLCommand("<div>foo</div><div>bar</div>");
+</script>
\ No newline at end of file
--- /dev/null
+e283287e9856989c2fb29a35209859d7
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 6 of #text > DIV > LI > UL > DIV > BODY > HTML > #document to 6 of #text > DIV > LI > UL > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldEndEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 3 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 3 of #text > DIV > LI > UL > DIV > BODY > HTML > #document to 3 of #text > DIV > LI > UL > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+layer at (0,0) size 800x600
+ RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x576
+ RenderBlock {P} at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 512x18
+ text run at (0,0) width 512: "This tests pasting a list into a position that would normally result in an end merge."
+ RenderBlock {DIV} at (0,34) size 784x86
+ RenderBlock (anonymous) at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 8x18
+ text run at (0,0) width 8: "x"
+ RenderBlock {UL} at (0,34) size 784x18
+ RenderListItem {LI} at (40,0) size 744x18
+ RenderBlock {DIV} at (0,0) size 744x18
+ RenderListMarker at (-17,0) size 7x18
+ RenderText {#text} at (0,0) size 40x18
+ text run at (0,0) width 40: "Item 1"
+ RenderBlock {DIV} at (0,68) size 784x18
+ RenderText {#text} at (0,0) size 8x18
+ text run at (0,0) width 8: "x"
+ RenderBlock {P} at (0,136) size 784x36
+ RenderText {#text} at (0,0) size 772x36
+ text run at (0,0) width 235: "This tests pasting text into a list item. "
+ text run at (235,0) width 537: "The last bit of content in the incoming fragment should be merged with the paragraph"
+ text run at (0,18) width 220: "after the position being pasted into."
+ RenderBlock {DIV} at (0,188) size 784x36
+ RenderBlock {UL} at (0,0) size 784x36
+ RenderListItem {LI} at (40,0) size 744x36
+ RenderBlock {DIV} at (0,0) size 744x18
+ RenderListMarker at (-17,0) size 7x18
+ RenderText {#text} at (0,0) size 28x18
+ text run at (0,0) width 28: "Item"
+ RenderText {#text} at (28,0) size 21x18
+ text run at (28,0) width 21: "foo"
+ RenderBlock {DIV} at (0,18) size 744x18
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "bar"
+ RenderText {#text} at (20,0) size 12x18
+ text run at (20,0) width 12: " 1"
+caret: position 3 of child 0 {#text} of child 1 {DIV} of child 0 {LI} of child 0 {UL} of child 10 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+<p>This tests pasting a list into a position that would normally result in an end merge.</p>
+<div id="test1" contenteditable="true">xx</div>
+
+<script type="text/javascript" src="../editing.js"></script>
+<script>
+var e = document.getElementById("test1");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+moveSelectionForwardByCharacterCommand();
+insertHTMLCommand("<ul><li><div>Item 1</div></li></ul>");
+</script>
+
+<p>This tests pasting text into a list item. The last bit of content in the incoming fragment should be merged with the paragraph after the position being pasted into.</p>
+<div id="test2" contenteditable="true"><ul><li><div>Item 1</div></li></ul></div>
+
+<script>
+var e = document.getElementById("test2");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+moveSelectionForwardByWordCommand();
+insertHTMLCommand("<div>foo</div><div>bar</div>");
+</script>
\ No newline at end of file
--- /dev/null
+a9f14eec350ebbcc4797229a8e922aa7
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > TD > TR > TBODY > TABLE > DIV > BODY > HTML > #document to 1 of #text > TD > TR > TBODY > TABLE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldEndEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 3 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 3 of #text > SPAN > DIV > TD > TR > TBODY > TABLE > DIV > BODY > HTML > #document to 3 of #text > SPAN > DIV > TD > TR > TBODY > TABLE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+layer at (0,0) size 800x600
+ RenderCanvas 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 {P} at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 524x18
+ text run at (0,0) width 524: "This tests pasting a table into a position that would normally result in an end merge."
+ RenderBlock {DIV} at (0,34) size 784x64
+ RenderBlock (anonymous) at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 8x18
+ text run at (0,0) width 8: "x"
+ RenderTable {TABLE} at (0,18) size 32x28 [border: (1px outset #808080)]
+ RenderTableSection {TBODY} at (1,1) size 30x26
+ RenderTableRow {TR} at (0,2) size 30x22
+ RenderTableCell {TD} at (2,2) size 12x22 [border: (1px inset #808080)] [r=0 c=0 rs=1 cs=1]
+ RenderText {#text} at (2,2) size 8x18
+ text run at (2,2) width 8: "1"
+ RenderTableCell {TD} at (16,2) size 12x22 [border: (1px inset #808080)] [r=0 c=1 rs=1 cs=1]
+ RenderText {#text} at (2,2) size 8x18
+ text run at (2,2) width 8: "2"
+ RenderBlock {DIV} at (0,46) size 784x18
+ RenderText {#text} at (0,0) size 8x18
+ text run at (0,0) width 8: "x"
+ RenderBlock {P} at (0,114) size 784x36
+ RenderText {#text} at (0,0) size 779x36
+ text run at (0,0) width 242: "This tests pasting text into a table cell. "
+ text run at (242,0) width 537: "The last bit of content in the incoming fragment should be merged with the paragraph"
+ text run at (0,18) width 220: "after the position being pasted into."
+ RenderBlock {DIV} at (0,166) size 784x46
+ RenderTable {TABLE} at (0,0) size 105x46 [border: (1px outset #808080)]
+ RenderTableSection {TBODY} at (1,1) size 103x44
+ RenderTableRow {TR} at (0,2) size 103x40
+ RenderTableCell {TD} at (2,2) size 53x40 [border: (1px inset #808080)] [r=0 c=0 rs=1 cs=1]
+ RenderBlock {DIV} at (2,2) size 49x18
+ RenderText {#text} at (0,0) size 28x18
+ text run at (0,0) width 28: "Item"
+ RenderInline {SPAN} at (0,0) size 21x18
+ RenderText {#text} at (28,0) size 21x18
+ text run at (28,0) width 21: "foo"
+ RenderBlock {DIV} at (2,20) size 49x18
+ RenderInline {SPAN} at (0,0) size 20x18
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "bar"
+ RenderText {#text} at (20,0) size 12x18
+ text run at (20,0) width 12: " 1"
+ RenderTableCell {TD} at (57,11) size 44x22 [border: (1px inset #808080)] [r=0 c=1 rs=1 cs=1]
+ RenderText {#text} at (2,2) size 40x18
+ text run at (2,2) width 40: "Item 2"
+caret: position 3 of child 0 {#text} of child 0 {SPAN} of child 1 {DIV} of child 0 {TD} of child 0 {TR} of child 0 {TBODY} of child 0 {TABLE} of child 10 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+<p>This tests pasting a table into a position that would normally result in an end merge.</p>
+<div id="test1" contenteditable="true">xx</div>
+
+<script type="text/javascript" src="../editing.js"></script>
+<script>
+var e = document.getElementById("test1");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+moveSelectionForwardByCharacterCommand();
+insertHTMLCommand("<table border='1'><tr><td>1</td><td>2</td></tr></table>");
+</script>
+
+<p>This tests pasting text into a table cell. The last bit of content in the incoming fragment should be merged with the paragraph after the position being pasted into.</p>
+<div contenteditable="true"><table border='1'><tr><td><div id="test2">Item 1</div></td><td>Item 2</td></tr></table></div>
+
+<script>
+var e = document.getElementById("test2");
+var s = window.getSelection();
+
+setSelectionCommand(e, 0, e, 0);
+moveSelectionForwardByWordCommand();
+insertHTMLCommand("<div>foo</div><div>bar</div>");
+</script>
\ No newline at end of file
+2006-05-02 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by harrison
+
+ <http://bugzilla.opendarwin.org/show_bug.cgi?id=8704>
+ Fix a few end merge bugs
+ <rdar://problem/4424044>
+ REGRESSION: Extra line appears when typing
+
+ * bridge/mac/WebCoreFrameBridge.mm:
+ (-[WebCoreFrameBridge smartInsertForString:replacingRange:beforeString:afterString:]):
+ Use renamed characterAfter.
+ * editing/InsertParagraphSeparatorCommand.cpp:
+ (WebCore::InsertParagraphSeparatorCommand::doApply):
+ Regenerate a VisiblePosition that became stale during a text node split.
+ Don't rebalance whitespace after the operation, 1) it has a bug that turns preserved
+ newlines into nbsps, 2) I think it should only be done during serialization, not after
+ every command (since editable regions now always have -webkit-nbsp-mode:space on them).
+ Use a regular br for the placeholder as I think we can move away from -webkit-block-placeholders.
+
+ * editing/RebalanceWhitespaceCommand.cpp: Added FIXMEs.
+ * editing/ReplaceSelectionCommand.cpp:
+ (WebCore::ReplaceSelectionCommand::shouldMergeStart): Removed FIXME.
+ (WebCore::ReplaceSelectionCommand::shouldMergeEnd): Can now use rendering information.
+ (WebCore::ReplaceSelectionCommand::doApply):
+ Call shouldMergeEnd after the insertion so that it can use rendering information.
+ Don't use positionAfterNode of the last node inserted to mark the position at the end
+ of inserted content because canonicalization can send it into content that was already
+ in the document.
+
+ * editing/ReplaceSelectionCommand.h:
+ * editing/VisiblePosition.cpp:
+ (WebCore::VisiblePosition::characterAfter):
+ Renamed. When two candidates are visually equivalent, the rightmost candidate will be
+ the one inside the text node where the character will be.
+
+ * editing/VisiblePosition.h:
+ * editing/htmlediting.cpp:
+ (WebCore::enclosingTableCell): Added.
+ (WebCore::enclosingList):
+ * editing/htmlediting.h:
+
2006-05-02 David Hyatt <hyatt@apple.com>
Partial fix for the crash in bugzilla bug 8088. There's a third crash
bool addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos);
if (addLeadingSpace) {
- QChar previousChar = startVisiblePos.previous().character();
+ QChar previousChar = startVisiblePos.previous().characterAfter();
if (!previousChar.isNull()) {
addLeadingSpace = !m_frame->isCharacterSmartReplaceExempt(previousChar, true);
}
bool addTrailingSpace = endPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos);
if (addTrailingSpace) {
- QChar thisChar = endVisiblePos.character();
+ QChar thisChar = endVisiblePos.characterAfter();
if (!thisChar.isNull()) {
addTrailingSpace = !m_frame->isCharacterSmartReplaceExempt(thisChar, false);
}
// Make sure we do not cause a rendered space to become unrendered.
// FIXME: We need the affinity for pos, but pos.downstream() does not give it
Position leadingWhitespace = pos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY);
+ // FIXME: leadingWhitespacePosition is returning the position before preserved newlines for positions
+ // after the preserved newline, causing the newline to be turned into a nbsp.
if (leadingWhitespace.isNotNull()) {
Text *textNode = static_cast<Text *>(leadingWhitespace.node());
replaceTextInNode(textNode, leadingWhitespace.offset(), 1, nonBreakingSpaceString());
if (pos.offset() > 0 && !atEnd) {
splitTextNode(textNode, pos.offset());
pos = Position(startNode, 0);
+ visiblePos = VisiblePosition(pos);
splitText = true;
}
}
parent = child.release();
}
- // Insert a block placeholder if the next visible position is in a different paragraph,
- // because we know that there will be no content on the first line of the new block
- // before the first block child. So, we need the placeholder to "hold the first line open".
- VisiblePosition next = visiblePos.next();
- if (!next.isNull() && !inSameBlock(visiblePos, next))
- appendBlockPlaceholder(blockToInsert.get());
-
+ // If the paragraph separator was inserted at the end of a paragraph, an empty line must be
+ // created. All of the nodes, starting at visiblePos, are about to be added to the new paragraph
+ // element. If the first node to be inserted won't be one that will hold an empty line open, add a br.
+ if (isEndOfParagraph(visiblePos) && !startNode->hasTagName(brTag) &&
+ !(startNode->renderer()->style()->preserveNewline() && visiblePos.characterAfter() == '\n'))
+ appendNode(createBreakElement(document()).get(), blockToInsert.get());
+
// Move the start node and the siblings of the start node.
if (startNode != startBlock) {
Node *n = startNode;
}
setEndingSelection(Position(blockToInsert.get(), 0), DOWNSTREAM);
- rebalanceWhitespace();
applyStyleAfterInsertion();
}
return c.unicode() == 0xa0 || isCollapsibleWhitespace(c);
}
+// FIXME: This doesn't go into adjacent text in siblings, cousins, etc.
+// FIXME: This turns preserved newlines into nbsps.
void RebalanceWhitespaceCommand::doApply()
{
if (m_position.isNull() || !m_position.node()->isTextNode())
return false;
// Don't pull content out of a list item.
- // FIXMEs: Do this check in shouldMergeEnd too. Don't pull content out of a table cell either.
+ // FIXMEs: Don't pull content out of a table cell either.
if (enclosingList(incomingFragment.mergeStartNode()))
return false;
return false;
}
-bool ReplaceSelectionCommand::shouldMergeEnd(const ReplacementFragment& incomingFragment, const Selection& destinationSelection)
+bool ReplaceSelectionCommand::shouldMergeEnd(const ReplacementFragment& incomingFragment, const VisiblePosition& endOfInsertedContent, const VisiblePosition& destination)
{
- return !incomingFragment.hasInterchangeNewlineAtEnd() && !isEndOfParagraph(destinationSelection.visibleEnd());
+ Node* endNode = endOfInsertedContent.deepEquivalent().node();
+ Node* destinationNode = destination.deepEquivalent().node();
+ // FIXME: Unify the naming scheme for these enclosing element getters.
+ return !incomingFragment.hasInterchangeNewlineAtEnd() &&
+ isEndOfParagraph(endOfInsertedContent) &&
+ nearestMailBlockquote(endNode) == nearestMailBlockquote(destinationNode) &&
+ enclosingListChild(endNode) == enclosingListChild(destinationNode) &&
+ enclosingTableCell(endNode) == enclosingTableCell(destinationNode) &&
+ !endNode->hasTagName(hrTag);
}
void ReplaceSelectionCommand::doApply()
// Whether the first paragraph of the incoming fragment should be merged with content from visibleStart to startOfParagraph(visibleStart).
bool mergeStart = shouldMergeStart(fragment, selection);
- // Whether the last paragraph of the incoming fragment should be merged with content from visibleEnd to endOfParagraph(visibleEnd).
- bool mergeEnd = shouldMergeEnd(fragment, selection);
+ bool endWasEndOfParagraph = isEndOfParagraph(visibleEnd);
Position startPos = selection.start();
assert(visiblePos.isNotNull());
addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(visiblePos);
if (addLeadingSpace) {
- QChar previousChar = visiblePos.previous().character();
+ QChar previousChar = visiblePos.previous().characterAfter();
if (!previousChar.isNull()) {
addLeadingSpace = !frame->isCharacterSmartReplaceExempt(previousChar, true);
}
}
addTrailingSpace = startPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(visiblePos);
if (addTrailingSpace) {
- QChar thisChar = visiblePos.character();
+ QChar thisChar = visiblePos.characterAfter();
if (!thisChar.isNull()) {
addTrailingSpace = !frame->isCharacterSmartReplaceExempt(thisChar, false);
}
// Make sure that content after the end of the selection being pasted into is in the same paragraph as the
// last bit of content that was inserted.
- if (mergeEnd) {
- VisiblePosition afterInsertedContent(positionAfterNode(m_lastNodeInserted.get()));
- if (isEndOfParagraph(afterInsertedContent)) {
- VisiblePosition startOfParagraphToMove = startOfParagraph(afterInsertedContent);
- VisiblePosition destination = afterInsertedContent.next();
- moveParagraph(startOfParagraphToMove, afterInsertedContent, destination);
- }
+ VisiblePosition endOfInsertedContent(Position(m_lastNodeInserted.get(), maxDeepOffset(m_lastNodeInserted.get())));
+ VisiblePosition destination = endOfInsertedContent.next();
+ if (!endWasEndOfParagraph && shouldMergeEnd(fragment, endOfInsertedContent, destination)) {
+ VisiblePosition startOfParagraphToMove = startOfParagraph(endOfInsertedContent);
+ moveParagraph(startOfParagraphToMove, endOfInsertedContent, destination);
}
completeHTMLReplacement(lastPositionToSelect);
void removeEndBRIfNeeded(Node*);
bool shouldMergeStart(const ReplacementFragment&, const Selection&);
- bool shouldMergeEnd(const ReplacementFragment&, const Selection&);
+ bool shouldMergeEnd(const ReplacementFragment&, const VisiblePosition&, const VisiblePosition&);
RefPtr<Node> m_firstNodeInserted;
RefPtr<Node> m_lastNodeInserted;
return node->offsetInCharacters() ? (int)static_cast<const CharacterData *>(node)->length() : (int)node->childNodeCount();
}
-QChar VisiblePosition::character() const
+QChar VisiblePosition::characterAfter() const
{
- Position pos = m_deepPosition;
+ // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
+ // is the one that will be inside the text node containing the character after this visible position.
+ Position pos = m_deepPosition.downstream();
Node *node = pos.node();
if (!node || !node->isTextNode()) {
return QChar();
bool isLastInBlock() const;
- QChar character() const;
+ QChar characterAfter() const;
void debugPosition(const char* msg = "") const;
return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
}
+Node* enclosingTableCell(Node* node)
+{
+ if (!node)
+ return 0;
+
+ for (Node* n = node->parentNode(); n; n = n->parentNode())
+ if (n->renderer() && n->renderer()->isTableCell())
+ return n;
+
+ return 0;
+}
+
Node* enclosingList(Node* node)
{
if (!node)
for (Node* n = node->parentNode(); n; n = n->parentNode())
if (n->hasTagName(ulTag) || n->hasTagName(olTag))
return n;
+
return 0;
}
Position positionAfterContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
Position positionOutsideContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
-bool isListElement(Node* n);
-Node* enclosingList(Node* node);
-Node *enclosingListChild(Node *n);
-bool isTableElement(Node* n);
+Node* enclosingTableCell(Node*);
+bool isListElement(Node*);
+Node* enclosingList(Node*);
+Node* enclosingListChild(Node*);
+bool isTableElement(Node*);
bool isFirstVisiblePositionAfterTableElement(const Position&);
Position positionBeforePrecedingTableElement(const Position&);
bool isLastVisiblePositionBeforeTableElement(const Position&);