+2006-06-14 Levi Weintraub <lweintraub@apple.com>
+
+ Reviewed by justin
+
+ <http://bugzilla.opendarwin.org/show_bug.cgi?id=7580>
+ TinyMCE: Implement execCommand(formatBlock, ...)
+
+ * editing/deleting/delete-ws-fixup-002-expected.checksum:
+ * editing/deleting/delete-ws-fixup-002-expected.png:
+ * editing/deleting/delete-ws-fixup-002-expected.txt:
+ * editing/deleting/delete-ws-fixup-002.html:
+ * editing/execCommand/format-block-expected.checksum: Added.
+ * editing/execCommand/format-block-expected.png: Added.
+ * editing/execCommand/format-block-expected.txt: Added.
+ * editing/execCommand/format-block-from-range-selection-expected.checksum: Added.
+ * editing/execCommand/format-block-from-range-selection-expected.png: Added.
+ * editing/execCommand/format-block-from-range-selection-expected.txt: Added.
+ * editing/execCommand/format-block-from-range-selection.html: Added.
+ * editing/execCommand/format-block.html: Added.
+
2006-06-14 Maciej Stachowiak <mjs@apple.com>
Test case by Anders, reviewed and tweaked by Maciej.
-7dd2af131f1af4b77082b09870243199
\ No newline at end of file
+15539ab6f39397a51bebded6f34a06d0
\ No newline at end of file
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > B > SPAN > DIV > BODY > HTML > #document to 0 of #text > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 7 of #text > SPAN > DIV > BODY > HTML > #document to 7 of #text > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > SPAN > DIV > BODY > HTML > #document to 0 of #text > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 7 of #text > SPAN > DIV > BODY > HTML > #document to 7 of #text > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
layer 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 784x84 [border: (2px solid #FF0000)]
- RenderInline {SPAN} at (0,0) size 741x56
+ RenderBlock {P} at (0,0) size 784x36
+ RenderText {#text} at (0,0) size 751x36
+ text run at (0,0) width 259: "This testcase demonstrates a bug (9441). "
+ text run at (259,0) width 446: "When 'as' is deleted, there should be a space before and after the caret. "
+ text run at (705,0) width 46: "Editing"
+ text run at (0,18) width 531: "produces a tree that should result in two spaces, but for some reason it isn't rendered."
+ RenderBlock {DIV} at (0,52) size 784x84 [border: (2px solid #FF0000)]
+ RenderInline {SPAN} at (0,0) size 735x56
RenderText {#text} at (14,14) size 97x28
text run at (14,14) width 97: "in Liberty"
RenderInline {I} at (0,0) size 117x28
text run at (132,14) width 96: "and seven"
RenderText {#text} at (228,14) size 63x28
text run at (228,14) width 63: " years "
- RenderInline {B} at (0,0) size 6x28
- RenderText {#text} at (291,14) size 6x28
- text run at (291,14) width 6: " "
- RenderText {#text} at (297,14) size 741x56
- text run at (297,14) width 110: "our fathers "
- text run at (407,14) width 348: "f upon this continent, a new nation, "
+ RenderInline {B} at (0,0) size 0x0
+ RenderText {#text} at (0,0) size 0x0
+ RenderText {#text} at (291,14) size 735x56
+ text run at (291,14) width 110: "our fathers "
+ text run at (401,14) width 348: "f upon this continent, a new nation, "
text run at (14,42) width 232: "conceived in Liberty, "
text run at (246,42) width 386: "and dedicated to the proposition that all"
RenderText {#text} at (0,0) size 0x0
-caret: position 7 of child 2 {#text} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 7 of child 2 {#text} of child 1 {SPAN} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document
<title>Editing Test</title>
</head>
<body>
+<p>This testcase demonstrates a bug (9441). When 'as' is deleted, there should be a space before and after the caret. Editing produces a tree that should result in two spaces, but for some reason it isn't rendered.</p>
<div contenteditable id="root" class="editing">
<span id="test">in Liberty<i>F and seven</i> years <b> as </b>our fathers f upon this
continent, a new nation, conceived in Liberty, and dedicated to the
--- /dev/null
+7310a63506bf17b27dcf3ad5b36a075a
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 11 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+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
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of H1 > DIV > DIV > BODY > HTML > #document to 0 of H1 > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of ADDRESS > DIV > BODY > HTML > #document to 0 of ADDRESS > DIV > BODY > HTML > #document toDOMRange:range from 0 of ADDRESS > DIV > BODY > HTML > #document to 0 of ADDRESS > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+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 784x18
+ RenderText {#text} at (0,0) size 427x18
+ text run at (0,0) width 427: "This test uses FormatBlock to modify three of the paragraphs below"
+ RenderBlock (anonymous) at (0,18) size 784x18
+ RenderBR {BR} at (0,0) size 0x18
+ RenderBlock {DIV} at (0,36) size 784x212 [border: (1px solid #000000)]
+ RenderBlock {PRE} at (1,14) size 782x15
+ RenderText {#text} at (0,0) size 64x15
+ text run at (0,0) width 64: "Make Pre"
+ RenderBlock (anonymous) at (1,42) size 782x18
+ RenderBR {BR} at (0,0) size 0x18
+ RenderBlock {DIV} at (1,60) size 782x115
+ RenderBlock (anonymous) at (0,0) size 782x18
+ RenderText {#text} at (0,0) size 25x18
+ text run at (0,0) width 25: "Foo"
+ RenderBR {BR} at (25,14) size 0x0
+ RenderBlock {H1} at (0,39) size 782x37
+ RenderInline {SPAN} at (0,0) size 120x37
+ RenderText {#text} at (0,0) size 120x37
+ text run at (0,0) width 120: "Make h1"
+ RenderBlock (anonymous) at (0,97) size 782x18
+ RenderText {#text} at (0,0) size 22x18
+ text run at (0,0) width 22: "baz"
+ RenderBlock (anonymous) at (1,175) size 782x18
+ RenderBR {BR} at (0,0) size 0x18
+ RenderBlock {ADDRESS} at (1,193) size 782x18
+ RenderText {#text} at (0,0) size 279x18
+ text run at (0,0) width 279: "Attempt to apply the current formatting here"
+caret: position 0 of child 0 {#text} of child 9 {ADDRESS} of child 4 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+2850169a8a5d6df7c64334e118869a1b
\ No newline at end of file
--- /dev/null
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 9 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 2 of #text > DL > DIV > BODY > HTML > #document to 2 of #text > DL > 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 784x18
+ RenderText {#text} at (0,0) size 605x18
+ text run at (0,0) width 605: "This test uses FormatBlock to apply the dl tag to a range of paragraphs with different block tags."
+ RenderBlock (anonymous) at (0,18) size 784x18
+ RenderBR {BR} at (0,0) size 0x18
+ RenderBlock {DIV} at (0,36) size 784x222 [border: (1px solid #000000)]
+ RenderBlock {DL} at (1,17) size 782x18
+ RenderText {#text} at (0,0) size 25x18
+ text run at (0,0) width 25: "Foo"
+ RenderBlock {DIV} at (1,51) size 782x86
+ RenderBlock {DL} at (0,0) size 782x18
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "bar"
+ RenderBlock (anonymous) at (0,34) size 782x0
+ RenderInline {SPAN} at (0,0) size 0x0
+ RenderBlock (anonymous) at (0,34) size 782x18
+ RenderBlock {DL} at (0,0) size 782x18
+ RenderInline {SPAN} at (0,0) size 22x18
+ RenderText {#text} at (0,0) size 22x18
+ text run at (0,0) width 22: "baz"
+ RenderBlock (anonymous) at (0,68) size 782x0
+ RenderInline {SPAN} at (0,0) size 0x0
+ RenderBlock {DL} at (0,68) size 782x18
+ RenderText {#text} at (0,0) size 19x18
+ text run at (0,0) width 19: "raz"
+ RenderBlock (anonymous) at (0,102) size 782x0
+ RenderBlock {DL} at (1,153) size 782x18
+ RenderText {#text} at (0,0) size 24x18
+ text run at (0,0) width 24: "dar "
+ RenderBlock (anonymous) at (1,187) size 782x0
+ RenderBlock {DL} at (1,187) size 782x18
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "yar"
+selection start: position 2 of child 0 {#text} of child 1 {DL} of child 4 {DIV} of child 0 {BODY} of child 0 {HTML} of document
+selection end: position 2 of child 0 {#text} of child 6 {DL} of child 4 {DIV} of child 0 {BODY} of child 0 {HTML} of document
--- /dev/null
+<div id="description">This test uses FormatBlock to apply the dl tag to a range of paragraphs with different block tags.</div>
+<br>
+<div style="border:1px solid black" contenteditable="true">
+<pre id="start">Foo</pre>
+<div>bar<br><span>baz</span><br>raz</div>
+dar
+<br>
+<address id="end">yar</address>
+</div>
+
+<script>
+var s = window.getSelection();
+var start = document.getElementById("start").firstChild;
+var end = document.getElementById("end").firstChild;
+s.setBaseAndExtent(start, 2, end, 2);
+
+document.execCommand("FormatBlock", false, "dl");
+</script>
\ No newline at end of file
--- /dev/null
+<div id="description">This test uses FormatBlock to modify three of the paragraphs below</div>
+<br>
+<div style="border:1px solid black" contenteditable="true">
+<p id="item1">Make Pre</p>
+<br>
+<div>Foo<br><span id="item2">Make h1</span><br>baz</div>
+<br>
+<address id="item3">Attempt to apply the current formatting here</address>
+</div>
+
+<script>
+var s = window.getSelection();
+var r = document.createRange();
+var p1 = document.getElementById("item1");
+var p2 = document.getElementById("item2");
+var p3 = document.getElementById("item3");
+s.setPosition(p1, 0);
+document.execCommand("FormatBlock", false, "pre");
+s.setPosition(p2, 0);
+document.execCommand("FormatBlock", false, "h1");
+s.setPosition(p3, 0);
+document.execCommand("FormatBlock", false, "address");
+</script>
\ No newline at end of file
+2006-06-14 Levi Weintraub <lweintraub@apple.com>
+
+ Reviewed by justin
+
+ <http://bugzilla.opendarwin.org/show_bug.cgi?id=7580>
+ TinyMCE: Implement execCommand(formatBlock, ...)
+
+ * WebCore.xcodeproj/project.pbxproj: Added FormatBlock.{h,cpp} to the project.
+ * WebCore.vcproj/WebCore/WebCore.vcproj: Ditto.
+ * bridge/mac/WebCoreFrameBridge.h: Added WebUndoActions
+ * editing/CompositeEditCommand.cpp:
+ (WebCore::CompositeEditCommand::moveParagraph): Added a preserveStyle bool.
+ (WebCore::CompositeEditCommand::moveParagraphs): Ditto. downstream() the start
+ or else we'll move collapsed whitespace and uncollapse it.
+ * editing/CompositeEditCommand.h:
+ * editing/DeleteSelectionCommand.cpp:
+ (WebCore::DeleteSelectionCommand::initializePositionData):
+ (WebCore::DeleteSelectionCommand::handleSpecialCaseBRDelete): Don't update m_endingPosition
+ because that's removeNode's responsibility.
+ (WebCore::updatePositionForNodeRemoval): Added.
+ (WebCore::DeleteSelectionCommand::removeNode): Turned removeFullySelectedNode into a virtual
+ overload of removeNode so that we can update positions as we remove nodes.
+ (WebCore::updatePositionForTextRemoval): Added.
+ (WebCore::DeleteSelectionCommand::deleteTextFromNode):
+ (WebCore::DeleteSelectionCommand::handleGeneralDelete):
+ (WebCore::DeleteSelectionCommand::fixupWhitespace): Got rid of m_trailingWhitespaceValid
+ since m_trailingWhitespace is always valid (we update it as we remove nodes).
+ (WebCore::DeleteSelectionCommand::mergeParagraphs):
+ (WebCore::DeleteSelectionCommand::doApply): Leading and trailing spaces should
+ be fixed if they have collapsed before merging paragraphs.
+ * editing/DeleteSelectionCommand.h:
+ * editing/EditAction.h:
+ (WebCore::):
+ * editing/FormatBlockCommand.cpp: Added.
+ (WebCore::FormatBlockCommand::FormatBlockCommand):
+ (WebCore::FormatBlockCommand::modifyRange): Similar to InsertListCommand::modifyRange().
+ (WebCore::FormatBlockCommand::doApply):
+ * editing/FormatBlockCommand.h: Added.
+ (WebCore::FormatBlockCommand::editingAction):
+ * editing/InsertListCommand.h:
+ (WebCore::InsertListCommand::editingAction):
+ * editing/JSEditor.cpp:
+ * editing/MergeIdenticalElementsCommand.cpp:
+ (WebCore::MergeIdenticalElementsCommand::doApply):
+ * editing/htmlediting.cpp:
+ (WebCore::validBlockTag):
+ (WebCore::createElement):
+ * editing/htmlediting.h:
+
2006-06-14 Maciej Stachowiak <mjs@apple.com>
Reviewed by Anders.
<File\r
RelativePath="..\..\editing\EditCommand.h"\r
>\r
+ </File>
+ <File\r
+ RelativePath="..\..\editing\FormatBlockCommand.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\editing\FormatBlockCommand.h"\r
+ >\r
</File>\r
<File\r
RelativePath="..\..\editing\htmlediting.cpp"\r
BCFE8E320A02A1D30009E61D /* WebCoreTextRenderer.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCFE8E310A02A1D30009E61D /* WebCoreTextRenderer.mm */; };
C6D74AD509AA282E000B0A52 /* ModifySelectionListLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = C6D74AD309AA282E000B0A52 /* ModifySelectionListLevel.h */; };
C6D74AE409AA290A000B0A52 /* ModifySelectionListLevel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6D74AE309AA290A000B0A52 /* ModifySelectionListLevel.cpp */; };
+ D05CED290A40BB2C00C5AF38 /* FormatBlockCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D05CED270A40BB2C00C5AF38 /* FormatBlockCommand.cpp */; };
+ D05CED2A0A40BB2C00C5AF38 /* FormatBlockCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D05CED280A40BB2C00C5AF38 /* FormatBlockCommand.h */; };
D07DEAB90A36554A00CA30F8 /* InsertListCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D07DEAB70A36554A00CA30F8 /* InsertListCommand.cpp */; };
D07DEABA0A36554A00CA30F8 /* InsertListCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D07DEAB80A36554A00CA30F8 /* InsertListCommand.h */; };
D086FE9809D53AAB005BC74D /* UnlinkCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D086FE9609D53AAB005BC74D /* UnlinkCommand.h */; };
BEF7EEA105FF8F0D009717EE /* KWQEditCommand.mm */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KWQEditCommand.mm; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
C6D74AD309AA282E000B0A52 /* ModifySelectionListLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModifySelectionListLevel.h; sourceTree = "<group>"; };
C6D74AE309AA290A000B0A52 /* ModifySelectionListLevel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModifySelectionListLevel.cpp; sourceTree = "<group>"; };
+ D05CED270A40BB2C00C5AF38 /* FormatBlockCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FormatBlockCommand.cpp; sourceTree = "<group>"; };
+ D05CED280A40BB2C00C5AF38 /* FormatBlockCommand.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FormatBlockCommand.h; sourceTree = "<group>"; };
D07DEAB70A36554A00CA30F8 /* InsertListCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = InsertListCommand.cpp; sourceTree = "<group>"; };
D07DEAB80A36554A00CA30F8 /* InsertListCommand.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = InsertListCommand.h; sourceTree = "<group>"; };
D086FE9609D53AAB005BC74D /* UnlinkCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnlinkCommand.h; sourceTree = "<group>"; };
93309D86099E64910056E581 /* editing */ = {
isa = PBXGroup;
children = (
+ D05CED270A40BB2C00C5AF38 /* FormatBlockCommand.cpp */,
+ D05CED280A40BB2C00C5AF38 /* FormatBlockCommand.h */,
93309D87099E64910056E581 /* AppendNodeCommand.cpp */,
93309D88099E64910056E581 /* AppendNodeCommand.h */,
93309D89099E64910056E581 /* ApplyStyleCommand.cpp */,
1AC694C80A3B1676003F5049 /* PluginDocument.h in Headers */,
51D3EA170A3D24D300BADA35 /* SQLDatabase.h in Headers */,
BC92F1DE0A40AEA300AC0746 /* DeprecatedSlider.h in Headers */,
+ D05CED2A0A40BB2C00C5AF38 /* FormatBlockCommand.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
51D3EA160A3D24D300BADA35 /* SQLDatabase.cpp in Sources */,
51D3EA180A3D24D300BADA35 /* SQLStatement.cpp in Sources */,
BC92F1DD0A40AEA300AC0746 /* DeprecatedSlider.cpp in Sources */,
+ D05CED290A40BB2C00C5AF38 /* FormatBlockCommand.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
WebUndoActionTyping,
WebUndoActionCreateLink,
WebUndoActionUnlink,
+ WebUndoActionFormatBlock,
+ WebUndoActionInsertList
} WebUndoAction;
typedef enum {
}
// This moves a paragraph preserving its style.
-void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection)
+void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
{
ASSERT(isStartOfParagraph(startOfParagraphToMove));
ASSERT(isEndOfParagraph(endOfParagraphToMove));
- moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, preserveSelection);
+ moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, preserveSelection, preserveStyle);
}
-// FIXME: Always preserve the selection, and pass the paragraphs to operate on using an endingSelection().
-void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection)
+void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
{
if (startOfParagraphToMove == destination)
return;
}
VisiblePosition beforeParagraph = startOfParagraphToMove.previous();
-
- Position start = startOfParagraphToMove.deepEquivalent().upstream();
- // We upstream() the end so that we don't include collapsed whitespace in the move.
- // If we must later add a br after the moved paragraph, doing so would cause the moved unrendered space to become rendered.
+
+ // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
+ // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
+ Position start = startOfParagraphToMove.deepEquivalent().downstream();
Position end = endOfParagraphToMove.deepEquivalent().upstream();
RefPtr<Range> range = new Range(document(), start.node(), start.offset(), end.node(), end.offset());
// FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move. It
// shouldn't matter though, since moved paragraphs will usually be quite small.
- RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(document(), range->toHTML(), "");
+ RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraphToMove ? createFragmentFromMarkup(document(), range->toHTML(), "") : 0;
setEndingSelection(Selection(start, end, DOWNSTREAM));
deleteSelection(false, false);
destinationIndex = TextIterator::rangeLength(new Range(document(), Position(document(), 0), destination.deepEquivalent()));
setEndingSelection(destination);
- EditCommandPtr cmd(new ReplaceSelectionCommand(document(), fragment.get(), true, false, false, true));
+ EditCommandPtr cmd(new ReplaceSelectionCommand(document(), fragment.get(), true, false, !preserveStyle, true));
applyCommandToComposite(cmd);
if (preserveSelection && startIndex != -1) {
void removeCSSProperty(WebCore::CSSStyleDeclaration *, int property);
void removeNodeAttribute(WebCore::Element *, const WebCore::QualifiedName& attribute);
void removeChildrenInRange(WebCore::Node *node, int from, int to);
- void removeNode(WebCore::Node *removeChild);
- void removeNodePreservingChildren(WebCore::Node *node);
+ virtual void removeNode(WebCore::Node*);
+ void removeNodePreservingChildren(WebCore::Node*);
void removeNodeAndPruneAncestors(Node* node);
void prune(PassRefPtr<Node> node);
void replaceTextInNode(WebCore::Text *node, int offset, int count, const WebCore::String &replacementText);
void pushAnchorElementDown(WebCore::Node*);
void pushPartiallySelectedAnchorElementsDown();
- void moveParagraph(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false);
- void moveParagraphs(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false);
+ void moveParagraph(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false, bool preserveStyle = true);
+ void moveParagraphs(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false, bool preserveStyle = true);
DeprecatedValueList<EditCommandPtr> m_cmds;
};
}
}
- m_trailingWhitespaceValid = true;
-
//
// Handle setting start and end blocks and the start node.
//
bool downstreamStartIsBR = m_downstreamStart.node()->hasTagName(brTag);
bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && m_downstreamStart.node() == m_upstreamEnd.node();
if (isBROnLineByItself) {
- m_endingPosition = Position(m_downstreamStart.node()->parentNode(), m_downstreamStart.node()->nodeIndex());
removeNode(m_downstreamStart.node());
m_mergeBlocksAfterDelete = false;
return true;
return false;
}
-void DeleteSelectionCommand::removeFullySelectedNode(Node *node)
+static void updatePositionForNodeRemoval(Node* node, Position& position)
+{
+ if (position.isNull())
+ return;
+ if (node->parent() == position.node() && node->nodeIndex() < (unsigned)position.offset())
+ position = Position(position.node(), position.offset() - 1);
+ if (position.node() == node || position.node()->isAncestor(node))
+ position = positionBeforeNode(node);
+}
+
+void DeleteSelectionCommand::removeNode(Node *node)
{
if (isTableStructureNode(node) || node == node->rootEditableElement()) {
// Do not remove an element of table structure; remove its contents.
while (child) {
Node *remove = child;
child = child->nextSibling();
- removeFullySelectedNode(remove);
+ removeNode(remove);
}
// make sure empty cell has some height
return;
}
- Position p = positionBeforeNode(node);
-
- if (node->parent() == m_endingPosition.node() && node->nodeIndex() < (unsigned)m_endingPosition.offset())
- m_endingPosition = Position(m_endingPosition.node(), m_endingPosition.offset() - 1);
+ // FIXME: Update the endpoints of the range being deleted.
+ updatePositionForNodeRemoval(node, m_endingPosition);
+ updatePositionForNodeRemoval(node, m_leadingWhitespace);
+ updatePositionForNodeRemoval(node, m_trailingWhitespace);
- removeNode(node);
-
- if (!m_endingPosition.node()->inDocument())
- m_endingPosition = p;
+ CompositeEditCommand::removeNode(node);
}
-void DeleteSelectionCommand::deleteTextFromNode(Text *node, int offset, int count)
+
+void updatePositionForTextRemoval(Node* node, int offset, int count, Position& position)
{
- if (m_endingPosition.node() == node) {
- if (m_endingPosition.offset() > offset + count)
- m_endingPosition = Position(m_endingPosition.node(), m_endingPosition.offset() - count);
- else if (m_endingPosition.offset() > offset)
- m_endingPosition = Position(m_endingPosition.node(), offset);
+ if (position.node() == node) {
+ if (position.offset() > offset + count)
+ position = Position(position.node(), position.offset() - count);
+ else if (position.offset() > offset)
+ position = Position(position.node(), offset);
}
+}
+
+void DeleteSelectionCommand::deleteTextFromNode(Text *node, int offset, int count)
+{
+ // FIXME: Update the endpoints of the range being deleted.
+ updatePositionForTextRemoval(node, offset, count, m_endingPosition);
+ updatePositionForTextRemoval(node, offset, count, m_leadingWhitespace);
+ updatePositionForTextRemoval(node, offset, count, m_trailingWhitespace);
CompositeEditCommand::deleteTextFromNode(node, offset, count);
}
if (!startNode->renderer() ||
(startOffset == 0 && m_downstreamEnd.offset() >= maxDeepOffset(startNode))) {
// just delete
- removeFullySelectedNode(startNode);
+ removeNode(startNode);
} else if (m_downstreamEnd.offset() - startOffset > 0) {
if (startNode->isTextNode()) {
// in a text node that needs to be trimmed
Text *text = static_cast<Text *>(startNode);
deleteTextFromNode(text, startOffset, m_downstreamEnd.offset() - startOffset);
- m_trailingWhitespaceValid = false;
} else {
removeChildrenInRange(startNode, startOffset, m_downstreamEnd.offset());
m_endingPosition = m_upstreamStart;
ASSERT(node->nodeIndex() < (unsigned)m_downstreamEnd.offset());
m_downstreamEnd = Position(m_downstreamEnd.node(), m_downstreamEnd.offset() - 1);
}
- removeFullySelectedNode(node);
+ removeNode(node);
node = nextNode;
} else {
Node* n = node->lastDescendant();
if (m_downstreamEnd.node() == n && m_downstreamEnd.offset() >= n->caretMaxOffset()) {
- removeFullySelectedNode(node);
- m_trailingWhitespaceValid = false;
+ removeNode(node);
node = 0;
} else {
node = node->traverseNextNode();
m_upstreamStart = Position(m_downstreamEnd.node()->parentNode(), m_downstreamEnd.node()->nodeIndex());
}
- removeFullySelectedNode(m_downstreamEnd.node());
- m_trailingWhitespaceValid = false;
+ removeNode(m_downstreamEnd.node());
} else {
if (m_downstreamEnd.node()->isTextNode()) {
// in a text node that needs to be trimmed
if (m_downstreamEnd.offset() > 0) {
deleteTextFromNode(text, 0, m_downstreamEnd.offset());
m_downstreamEnd = Position(text, 0);
- m_trailingWhitespaceValid = false;
}
} else {
int offset = 0;
}
}
-// FIXME: Can't really determine this without taking white-space mode into account.
-static inline bool nextCharacterIsCollapsibleWhitespace(const Position &pos)
-{
- if (!pos.node())
- return false;
- if (!pos.node()->isTextNode())
- return false;
- return isCollapsibleWhitespace(static_cast<Text *>(pos.node())->data()[pos.offset()]);
-}
-
void DeleteSelectionCommand::fixupWhitespace()
{
updateLayout();
- if (m_leadingWhitespace.isNotNull() && (m_trailingWhitespace.isNotNull() || !m_leadingWhitespace.isRenderedCharacter())) {
- LOG(Editing, "replace leading");
+ // FIXME: isRenderedCharacter should be removed, and we should use VisiblePosition::characterAfter and VisiblePosition::characterBefore
+ if (m_leadingWhitespace.isNotNull() && !m_leadingWhitespace.isRenderedCharacter()) {
Text *textNode = static_cast<Text *>(m_leadingWhitespace.node());
replaceTextInNode(textNode, m_leadingWhitespace.offset(), 1, nonBreakingSpaceString());
}
- else if (m_trailingWhitespace.isNotNull()) {
- if (m_trailingWhitespaceValid) {
- if (!m_trailingWhitespace.isRenderedCharacter()) {
- LOG(Editing, "replace trailing [valid]");
- Text *textNode = static_cast<Text *>(m_trailingWhitespace.node());
- replaceTextInNode(textNode, m_trailingWhitespace.offset(), 1, nonBreakingSpaceString());
- }
- }
- else {
- Position pos = m_endingPosition.downstream();
- pos = Position(pos.node(), pos.offset() - 1);
- if (nextCharacterIsCollapsibleWhitespace(pos) && !pos.isRenderedCharacter()) {
- LOG(Editing, "replace trailing [invalid]");
- Text *textNode = static_cast<Text *>(pos.node());
- replaceTextInNode(textNode, pos.offset(), 1, nonBreakingSpaceString());
- // need to adjust ending position since the trailing position is not valid.
- m_endingPosition = pos;
- }
- }
+ if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedCharacter()) {
+ Text *textNode = static_cast<Text *>(m_trailingWhitespace.node());
+ replaceTextInNode(textNode, m_trailingWhitespace.offset(), 1, nonBreakingSpaceString());
}
}
-// If a selection ended in a different paragraph than it started in, we must merge
-// the two paragraphs after deleting the selection.
+// If a selection starts in one block and ends in another, we have to merge to bring content before the
+// start together with content after the end.
void DeleteSelectionCommand::mergeParagraphs()
{
if (!m_mergeBlocksAfterDelete)
if (m_endBlock == m_startBlock)
return;
- // Don't move content between parts of a table.
+ // Don't move content between parts of a table or between table and non-table content.
+ // FIXME: This isn't right. A table with two rows and a single column appears as two paragraphs.
if (isTableStructureNode(m_downstreamEnd.node()->enclosingBlockFlowElement()) || isTableStructureNode(m_upstreamStart.node()->enclosingBlockFlowElement()))
return;
handleGeneralDelete();
- mergeParagraphs();
-
fixupWhitespace();
+ mergeParagraphs();
+
RefPtr<Node> placeholder = needPlaceholder ? createBreakElement(document()) : 0;
if (placeholder)
insertNodeAt(placeholder.get(), m_endingPosition.node(), m_endingPosition.offset());
void fixupWhitespace();
void mergeParagraphs();
void calculateEndingPosition();
- void calculateTypingStyleAfterDelete(WebCore::Node *insertedPlaceholder);
+ void calculateTypingStyleAfterDelete(WebCore::Node*);
void clearTransientState();
- void removeFullySelectedNode(Node* node);
- virtual void deleteTextFromNode(Text *node, int offset, int count);
+ virtual void removeNode(Node*);
+ virtual void deleteTextFromNode(Text*, int, int);
bool m_hasSelectionToDelete;
bool m_smartDelete;
bool m_mergeBlocksAfterDelete;
- bool m_trailingWhitespaceValid;
// This data is transient and should be cleared at the end of the doApply function.
Selection m_selectionToDelete;
EditActionTyping,
EditActionCreateLink,
EditActionUnlink,
+ EditActionFormatBlock,
+ EditActionInsertList
} EditAction;
}
--- /dev/null
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Element.h"
+#include "FormatBlockCommand.h"
+#include "Document.h"
+#include "htmlediting.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "visible_units.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+FormatBlockCommand::FormatBlockCommand(Document* document, const String& tagName)
+ : CompositeEditCommand(document), m_tagName(tagName)
+{}
+
+
+
+bool FormatBlockCommand::modifyRange()
+{
+ ASSERT(endingSelection().isRange());
+ VisiblePosition visibleStart = endingSelection().visibleStart();
+ VisiblePosition visibleEnd = endingSelection().visibleEnd();
+ VisiblePosition startOfLastParagraph = startOfParagraph(visibleEnd);
+
+ if (startOfParagraph(visibleStart) == startOfLastParagraph)
+ return false;
+
+ setEndingSelection(visibleStart);
+ doApply();
+ visibleStart = endingSelection().visibleStart();
+ VisiblePosition nextParagraph = endOfParagraph(visibleStart).next();
+ while (nextParagraph.isNotNull() && nextParagraph != startOfLastParagraph) {
+ setEndingSelection(nextParagraph);
+ doApply();
+ nextParagraph = endOfParagraph(endingSelection().visibleStart()).next();
+ }
+ setEndingSelection(visibleEnd);
+ doApply();
+ visibleEnd = endingSelection().visibleEnd();
+ setEndingSelection(Selection(visibleStart.deepEquivalent(), visibleEnd.deepEquivalent(), DOWNSTREAM));
+
+ return true;
+}
+
+void FormatBlockCommand::doApply()
+{
+ if (endingSelection().isNone())
+ return;
+
+ if (endingSelection().isRange() && modifyRange())
+ return;
+
+ if (!endingSelection().rootEditableElement())
+ return;
+
+ String localName, prefix;
+ if (!Document::parseQualifiedName(m_tagName, prefix, localName))
+ return;
+ QualifiedName qTypeOfBlock = QualifiedName(AtomicString(prefix), AtomicString(localName), xhtmlNamespaceURI);
+
+ Node* enclosingBlock = enclosingBlockFlowElement(endingSelection().visibleStart());
+ if (enclosingBlock->hasTagName(qTypeOfBlock))
+ // We're already in a block with the format we want, so we don't have to do anything
+ return;
+
+ VisiblePosition paragraphStart = startOfParagraph(endingSelection().visibleStart());
+ VisiblePosition paragraphEnd = endOfParagraph(endingSelection().visibleStart());
+ VisiblePosition blockStart = startOfBlock(endingSelection().visibleStart());
+ VisiblePosition blockEnd = endOfBlock(endingSelection().visibleStart());
+ RefPtr<Node> blockNode = createElement(document(), m_tagName);
+ RefPtr<Node> placeholder = createBreakElement(document());
+
+ if (validBlockTag(enclosingBlock->nodeName().lower()) && paragraphStart == blockStart && paragraphEnd == blockEnd)
+ // Already in a valid block tag that only contains the current paragraph, so we can swap with the new tag
+ insertNodeBefore(blockNode.get(), enclosingBlock);
+ else {
+ Position upstreamStart = paragraphStart.deepEquivalent().upstream();
+ insertNodeAt(blockNode.get(), upstreamStart.node(), upstreamStart.offset());
+ }
+ appendNode(placeholder.get(), blockNode.get());
+ moveParagraph(paragraphStart, paragraphEnd, VisiblePosition(Position(placeholder.get(), 0)), true, false);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FormatBlockCommand_h
+#define FormatBlockCommand_h
+
+#include "CompositeEditCommand.h"
+
+namespace WebCore {
+
+class FormatBlockCommand : public CompositeEditCommand
+{
+public:
+ FormatBlockCommand(WebCore::Document*, const String&);
+ virtual void doApply();
+ virtual EditAction editingAction() const { return EditActionFormatBlock; }
+private:
+ bool modifyRange();
+ String m_tagName;
+};
+
+} // namespace WebCore
+
+#endif // InsertListCommand_h
enum EListType { OrderedListType, UnorderedListType };
InsertListCommand(WebCore::Document*, EListType, const String&);
virtual void doApply();
+ virtual EditAction editingAction() const { return EditActionInsertList; }
private:
Node* fixOrphanedListChild(Node*);
bool modifyRange();
#include "CreateLinkCommand.h"
#include "Document.h"
#include "DocumentFragment.h"
+#include "FormatBlockCommand.h"
#include "Frame.h"
#include "HTMLNames.h"
#include "HTMLImageElement.h"
return execStyleChange(frame, CSS_PROP_COLOR, value);
}
+bool execFormatBlock(Frame *frame, bool userInterface, const String &value)
+{
+ String tagName = value.lower();
+ if (!validBlockTag(tagName))
+ return false;
+
+ EditCommandPtr(new FormatBlockCommand(frame->document(), tagName)).apply();
+ return true;
+}
+
bool execInsertHorizontalRule(Frame* frame, bool userInterface, const String& value)
{
RefPtr<HTMLElement> hr = new HTMLElement(hrTag, frame->document());
{ "FontSize", { execFontSize, enabledAnySelection, stateNone, valueFontSize } },
{ "FontSizeDelta", { execFontSizeDelta, enabledAnySelection, stateNone, valueFontSizeDelta } },
{ "ForeColor", { execForeColor, enabledAnySelection, stateNone, valueForeColor } },
+ { "FormatBlock", { execFormatBlock, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
{ "ForwardDelete", { execForwardDelete, enabledAnyEditableSelection, stateNone, valueNull } },
{ "Indent", { execIndent, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
{ "InsertHorizontalRule", { execInsertHorizontalRule, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
// DirLTR (not supported)
// DirRTL (not supported)
// EditMode (not supported)
- // FormatBlock (not supported)
// InlineDirLTR (not supported)
// InlineDirRTL (not supported)
// InsertButton (not supported)
ASSERT(m_element1);
ASSERT(m_element2);
ASSERT(m_element1->nextSibling() == m_element2);
-
+
ExceptionCode ec = 0;
if (!m_atChild)
return false;
}
+// Checks if a string is a valid tag for the FormatBlockCommand function of execCommand. Expects lower case strings.
+bool validBlockTag(const String& blockTag)
+{
+ if (blockTag == "address" ||
+ blockTag == "blockquote" ||
+ blockTag == "dd" ||
+ blockTag == "div" ||
+ blockTag == "dl" ||
+ blockTag == "dt" ||
+ blockTag == "h1" ||
+ blockTag == "h2" ||
+ blockTag == "h3" ||
+ blockTag == "h4" ||
+ blockTag == "h5" ||
+ blockTag == "h6" ||
+ blockTag == "p" ||
+ blockTag == "pre")
+ return true;
+ return false;
+}
+
static Node* firstInSpecialElement(const Position& pos)
{
Node* rootEditableElement = pos.node()->rootEditableElement();
return breakNode.release();
}
+PassRefPtr<Element> createElement(Document* document, String& tagName)
+{
+ ExceptionCode ec = 0;
+ RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, tagName, ec);
+ ASSERT(ec == 0);
+ return breakNode.release();
+}
+
bool isTabSpanNode(const Node *node)
{
return (node && node->isElementNode() && static_cast<const Element *>(node)->getAttribute("class") == AppleTabSpanClass);
Position positionAfterNode(const Node*);
bool isSpecialElement(const Node*);
+bool validBlockTag(const String&);
PassRefPtr<Element> createDefaultParagraphElement(Document*);
PassRefPtr<Element> createBreakElement(Document*);
PassRefPtr<Element> createOrderedListElement(Document*);
PassRefPtr<Element> createUnorderedListElement(Document*);
PassRefPtr<Element> createListItemElement(Document*);
+PassRefPtr<Element> createElement(Document*, String&);
bool isTabSpanNode(const Node*);
bool isTabSpanTextNode(const Node*);
+2006-06-14 Levi Weintraub <lweintraub@apple.com>
+
+ Reviewed by justin
+
+ <http://bugzilla.opendarwin.org/show_bug.cgi?id=7580>
+ TinyMCE: Implement execCommand(formatBlock, ...)
+
+ * English.lproj/Localizable.strings:
+ * WebCoreSupport/WebFrameBridge.m:
+ (-[WebFrameBridge nameForUndoAction:]):
+
2006-06-14 Tim Omernick <timo@apple.com>
Reviewed by John Sullivan.
case WebUndoActionTyping: return UI_STRING_KEY("Typing", "Typing (Undo action name)", "Undo action name");
case WebUndoActionCreateLink: return UI_STRING_KEY("Create Link", "Create Link (Undo action name)", "Undo action name");
case WebUndoActionUnlink: return UI_STRING_KEY("Unlink", "Unlink (Undo action name)", "Undo action name");
+ case WebUndoActionInsertList: return UI_STRING_KEY("Insert List", "Insert List (Undo action name)", "Undo action name");
+ case WebUndoActionFormatBlock: return UI_STRING_KEY("Formatting", "Format Block (Undo action name)", "Undo action name");
}
return nil;
}