Reviewed by justin
http://bugzilla.opendarwin.org/show_bug.cgi?id=7568
Bug 7568: Implement Indent/Outdent
* editing/execCommand/indent-list-item-expected.checksum: Added.
* editing/execCommand/indent-list-item-expected.png: Added.
* editing/execCommand/indent-list-item-expected.txt: Added.
* editing/execCommand/indent-list-item.html: Added.
* editing/execCommand/indent-selection-expected.checksum: Added.
* editing/execCommand/indent-selection-expected.png: Added.
* editing/execCommand/indent-selection-expected.txt: Added.
* editing/execCommand/indent-selection.html: Added.
* editing/execCommand/outdent-selection.html: Added.
WebCore:
Reviewed by justin
http://bugzilla.opendarwin.org/show_bug.cgi?id=7568
Bug 7568: Implement Indent/Outdent
* WebCore.vcproj/WebCore/WebCore.vcproj: Added IndentOutdentCommand.h/cpp
* WebCore.xcodeproj/project.pbxproj: Ditto.
* editing/IndentOutdentCommand.cpp: Added.
(WebCore::IndentOutdentCommand::IndentOutdentCommand):
(WebCore::enclosingListOrBlockquote):
(WebCore::IndentOutdentCommand::splitTreeToNode): Splits the DOM tree from a
descendent node to an ending ancestor, duplicating nodes when necessary. Returns
the last node split. Used to insert blockquotes at the topmost level.
(WebCore::IndentOutdentCommand::indentRegion):
(WebCore::IndentOutdentCommand::outdentParagraph):
(WebCore::IndentOutdentCommand::outdentRegion):
(WebCore::IndentOutdentCommand::doApply):
* editing/IndentOutdentCommand.h: Added.
(WebCore::IndentOutdentCommand::):
* editing/JSEditor.cpp: Added the execCommands Indent and Outdent
* editing/htmlediting.cpp:
(WebCore::enclosingNodeWithTag): Finds the enclosing node with any specified tag.
(WebCore::enclosingListChild): Added checks for nill and editable boundaries.
(WebCore::outermostEnclosingListChild): Returns the highest ancestor list child.
(WebCore::highestAncestor): Added.
(WebCore::createElement): Changed the passed in string to a const reference.
* editing/htmlediting.h:
WebKit:
Reviewed by justin
http://bugzilla.opendarwin.org/show_bug.cgi?id=7568
Bug 7568: Implement Indent/Outdent
Added undo action strings and enum values
* English.lproj/Localizable.strings:
* WebCoreSupport/WebFrameBridge.m:
(-[WebFrameBridge nameForUndoAction:]):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15080
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2006-06-28 Levi Weintraub <lweintraub@apple.com>
+
+ Reviewed by justin
+
+ http://bugzilla.opendarwin.org/show_bug.cgi?id=7568
+ Bug 7568: Implement Indent/Outdent
+
+ * editing/execCommand/indent-list-item-expected.checksum: Added.
+ * editing/execCommand/indent-list-item-expected.png: Added.
+ * editing/execCommand/indent-list-item-expected.txt: Added.
+ * editing/execCommand/indent-list-item.html: Added.
+ * editing/execCommand/indent-selection-expected.checksum: Added.
+ * editing/execCommand/indent-selection-expected.png: Added.
+ * editing/execCommand/indent-selection-expected.txt: Added.
+ * editing/execCommand/indent-selection.html: Added.
+ * editing/execCommand/outdent-selection.html: Added.
+
2006-06-28 Mitz Pettel <opendarwin.org@mitzpettel.com>
Reviewed by Darin and Hyatt.
+2006-06-28 Levi Weintraub <lweintraub@apple.com>
+
+ Reviewed by justin
+
+ http://bugzilla.opendarwin.org/show_bug.cgi?id=7568
+ Bug 7568: Implement Indent/Outdent
+
+ * WebCore.vcproj/WebCore/WebCore.vcproj: Added IndentOutdentCommand.h/cpp
+ * WebCore.xcodeproj/project.pbxproj: Ditto.
+ * editing/IndentOutdentCommand.cpp: Added.
+ (WebCore::IndentOutdentCommand::IndentOutdentCommand):
+ (WebCore::enclosingListOrBlockquote):
+ (WebCore::IndentOutdentCommand::splitTreeToNode): Splits the DOM tree from a
+ descendent node to an ending ancestor, duplicating nodes when necessary. Returns
+ the last node split. Used to insert blockquotes at the topmost level.
+ (WebCore::IndentOutdentCommand::indentRegion):
+ (WebCore::IndentOutdentCommand::outdentParagraph):
+ (WebCore::IndentOutdentCommand::outdentRegion):
+ (WebCore::IndentOutdentCommand::doApply):
+ * editing/IndentOutdentCommand.h: Added.
+ (WebCore::IndentOutdentCommand::):
+ * editing/JSEditor.cpp: Added the execCommands Indent and Outdent
+ * editing/htmlediting.cpp:
+ (WebCore::enclosingNodeWithTag): Finds the enclosing node with any specified tag.
+ (WebCore::enclosingListChild): Added checks for nill and editable boundaries.
+ (WebCore::outermostEnclosingListChild): Returns the highest ancestor list child.
+ (WebCore::highestAncestor): Added.
+ (WebCore::createElement): Changed the passed in string to a const reference.
+ * editing/htmlediting.h:
+
2006-06-28 Mitz Pettel <opendarwin.org@mitzpettel.com>
Reviewed by Darin and Hyatt.
(WebCore::SQLStatement::getColumnBlobAsVector):
(WebCore::SQLStatement::getColumnBlob):
+>>>>>>> .r15079
2006-06-27 Ada Chan <adachan@apple.com>
Reviewed by sfalken.
RelativePath="..\..\editing\InsertListCommand.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath="..\..\editing\IndentOutdentCommand.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\editing\IndentOutdentCommand.h"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\..\editing\InsertNodeBeforeCommand.cpp"\r
>\r
D086FE9909D53AAB005BC74D /* UnlinkCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D086FE9709D53AAB005BC74D /* UnlinkCommand.cpp */; };
D0B0556809C6700100307E43 /* CreateLinkCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B0556609C6700100307E43 /* CreateLinkCommand.h */; };
D0B0556909C6700100307E43 /* CreateLinkCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0B0556709C6700100307E43 /* CreateLinkCommand.cpp */; };
+ DB23C2CB0A508D29002489EB /* IndentOutdentCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DB23C2C90A508D29002489EB /* IndentOutdentCommand.cpp */; };
+ DB23C2CC0A508D29002489EB /* IndentOutdentCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = DB23C2CA0A508D29002489EB /* IndentOutdentCommand.h */; };
DD763BB20992C2C900740B8E /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DD763BB10992C2C900740B8E /* libxml2.dylib */; };
DD7CDF250A23CF9800069928 /* CSSUnknownRule.h in Headers */ = {isa = PBXBuildFile; fileRef = A80E6CCE0A1989CA007FB8C5 /* CSSUnknownRule.h */; };
E1052C320A4D70010072D99B /* DOMEventsNonstandard.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1052C310A4D70010072D99B /* DOMEventsNonstandard.mm */; };
D086FE9709D53AAB005BC74D /* UnlinkCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnlinkCommand.cpp; sourceTree = "<group>"; };
D0B0556609C6700100307E43 /* CreateLinkCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CreateLinkCommand.h; sourceTree = "<group>"; };
D0B0556709C6700100307E43 /* CreateLinkCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CreateLinkCommand.cpp; sourceTree = "<group>"; };
+ DB23C2C90A508D29002489EB /* IndentOutdentCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = IndentOutdentCommand.cpp; sourceTree = "<group>"; };
+ DB23C2CA0A508D29002489EB /* IndentOutdentCommand.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = IndentOutdentCommand.h; sourceTree = "<group>"; };
DD763BB10992C2C900740B8E /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = /usr/lib/libxml2.dylib; sourceTree = "<absolute>"; };
E1052C310A4D70010072D99B /* DOMEventsNonstandard.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = DOMEventsNonstandard.mm; sourceTree = "<group>"; };
E1EE773508F1086C00166870 /* WebCoreTextDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = WebCoreTextDecoder.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
93309D86099E64910056E581 /* editing */ = {
isa = PBXGroup;
children = (
+ DB23C2C90A508D29002489EB /* IndentOutdentCommand.cpp */,
+ DB23C2CA0A508D29002489EB /* IndentOutdentCommand.h */,
D05CED270A40BB2C00C5AF38 /* FormatBlockCommand.cpp */,
D05CED280A40BB2C00C5AF38 /* FormatBlockCommand.h */,
93309D87099E64910056E581 /* AppendNodeCommand.cpp */,
85031B4F0A44EFC700F992E0 /* UIEventWithKeyState.h in Headers */,
85031B510A44EFC700F992E0 /* WheelEvent.h in Headers */,
ABE7B5240A489F830031881C /* DeprecatedRenderSelect.h in Headers */,
+ DB23C2CC0A508D29002489EB /* IndentOutdentCommand.h in Headers */,
BCCD74DC0A4C8D35005FDA6D /* HTMLViewSourceDocument.h in Headers */,
1A8086CC0A4D097600DFB6A7 /* DOMCSSInternal.h in Headers */,
);
85031B500A44EFC700F992E0 /* WheelEvent.cpp in Sources */,
ABE7B5230A489F830031881C /* DeprecatedRenderSelect.cpp in Sources */,
51F11E150A48C2920034A24E /* SQLTransaction.cpp in Sources */,
+ DB23C2CB0A508D29002489EB /* IndentOutdentCommand.cpp in Sources */,
BCCD74E50A4C8DDF005FDA6D /* HTMLViewSourceDocument.cpp in Sources */,
E1052C320A4D70010072D99B /* DOMEventsNonstandard.mm in Sources */,
516149ED0A525E3A003DFC7A /* SiteIcon.cpp in Sources */,
EditActionCreateLink,
EditActionUnlink,
EditActionFormatBlock,
- EditActionInsertList
+ EditActionInsertList,
+ EditActionIndent,
+ EditActionOutdent
} 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 (IndentOutdentCommandINCLUDING, 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 "IndentOutdentCommand.h"
+#include "InsertListCommand.h"
+#include "Document.h"
+#include "htmlediting.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "InsertLineBreakCommand.h"
+#include "Range.h"
+#include "SplitElementCommand.h"
+#include "visible_units.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+IndentOutdentCommand::IndentOutdentCommand(Document* document, EIndentType typeOfAction, int marginInPixels)
+ : CompositeEditCommand(document), m_typeOfAction(typeOfAction), m_marginInPixels(marginInPixels)
+{}
+
+static Node* enclosingListOrBlockquote(Node* node)
+{
+ if (!node)
+ return 0;
+ Node* root = (node->inDocument()) ? node->rootEditableElement() : highestAncestor(node);
+ ASSERT(root);
+ for (Node* n = node->parentNode(); n && (n == root || n->isAncestor(root)); n = n->parentNode())
+ if (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(blockquoteTag))
+ return n;
+
+ return 0;
+}
+
+// This function is a workaround for moveParagraph's tendency to strip blockquotes. It updates lastBlockquote to point to the
+// correct level for the current paragraph, and returns a pointer to a placeholder br where the insertion should be performed.
+Node* IndentOutdentCommand::prepareBlockquoteLevelForInsertion(VisiblePosition& currentParagraph, Node** lastBlockquote)
+{
+ int currentBlockquoteLevel = 0;
+ int lastBlockquoteLevel = 0;
+ Node* node = currentParagraph.deepEquivalent().node();
+ while ((node = enclosingNodeWithTag(node, blockquoteTag)))
+ currentBlockquoteLevel++;
+ node = *lastBlockquote;
+ while ((node = enclosingNodeWithTag(node, blockquoteTag)))
+ lastBlockquoteLevel++;
+ while (currentBlockquoteLevel > lastBlockquoteLevel) {
+ RefPtr<Node> newBlockquote = createElement(document(), "blockquote");
+ appendNode(newBlockquote.get(), *lastBlockquote);
+ *lastBlockquote = newBlockquote.get();
+ lastBlockquoteLevel++;
+ }
+ while (currentBlockquoteLevel < lastBlockquoteLevel) {
+ *lastBlockquote = enclosingNodeWithTag(*lastBlockquote, blockquoteTag);
+ lastBlockquoteLevel--;
+ }
+ RefPtr<Node> placeholder = createBreakElement(document());
+ if ((*lastBlockquote)->firstChild() && !(*lastBlockquote)->lastChild()->hasTagName(brTag)) {
+ RefPtr<Node> collapsedPlaceholder = createBreakElement(document());
+ appendNode(collapsedPlaceholder.get(), (*lastBlockquote));
+ }
+ appendNode(placeholder.get(), *lastBlockquote);
+ return placeholder.get();
+}
+
+// Splits the tree parent by parent until we reach the specified ancestor. We use VisiblePositions
+// to determine if the split is necessary. Returns the last split node.
+Node* IndentOutdentCommand::splitTreeToNode(Node* start, Node* end, bool splitAncestor)
+{
+ Node* node;
+ for (node = start; node && node->parent() != end; node = node->parent()) {
+ VisiblePosition positionInParent(Position(node->parent(), 0), DOWNSTREAM);
+ VisiblePosition positionInNode(Position(node, 0), DOWNSTREAM);
+ if (positionInParent != positionInNode) {
+ EditCommandPtr cmd(new SplitElementCommand(document(), static_cast<Element*>(node->parent()), node));
+ applyCommandToComposite(cmd);
+ }
+ }
+ if (splitAncestor)
+ return splitTreeToNode(end, end->parent());
+ return node;
+}
+
+void IndentOutdentCommand::indentRegion()
+{
+ VisiblePosition startOfSelection = endingSelection().visibleStart();
+ VisiblePosition endOfSelection = endingSelection().visibleEnd();
+
+ ASSERT(!startOfSelection.isNull());
+ ASSERT(!endOfSelection.isNull());
+
+ Node* previousListNode = 0;
+ Node* newListNode;
+ Node* newBlockquote = 0;
+ VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection);
+ VisiblePosition endAfterSelection = endOfParagraph(endOfParagraph(endOfSelection).next());
+ while (endOfCurrentParagraph != endAfterSelection) {
+ // Iterate across the selected paragraphs...
+ VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
+ Node* listNode = enclosingList(endOfCurrentParagraph.deepEquivalent().node());
+ Node* insertionPoint;
+ if (listNode) {
+ RefPtr<Node> placeholder = createBreakElement(document());
+ insertionPoint = placeholder.get();
+ newBlockquote = 0;
+ RefPtr<Node> listItem = createListItemElement(document());
+ if (listNode == previousListNode) {
+ // The previous paragraph was inside the same list, so add this list item to the list we already created
+ appendNode(listItem.get(), newListNode);
+ appendNode(placeholder.get(), listItem.get());
+ } else {
+ // Clone the list element, insert it before the current paragraph, and move the paragraph into it.
+ RefPtr<Node> clonedList = static_cast<Element*>(listNode)->cloneNode(false);
+ insertNodeBefore(clonedList.get(), enclosingListChild(endOfCurrentParagraph.deepEquivalent().node()));
+ appendNode(listItem.get(), clonedList.get());
+ appendNode(placeholder.get(), listItem.get());
+ newListNode = clonedList.get();
+ previousListNode = listNode;
+ }
+ } else if (newBlockquote)
+ // The previous paragraph was put into a new blockquote, so move this paragraph there as well
+ insertionPoint = prepareBlockquoteLevelForInsertion(endOfCurrentParagraph, &newBlockquote);
+ else {
+ // Create a new blockquote and insert it as a child of the root editable element. We accomplish
+ // this by splitting all parents of the current paragraph up to that point.
+ RefPtr<Node> blockquote = createElement(document(), "blockquote");
+ Node* startNode = startOfParagraph(endOfCurrentParagraph).deepEquivalent().node();
+ Node* startOfNewBlock = splitTreeToNode(startNode, startNode->rootEditableElement());
+ insertNodeBefore(blockquote.get(), startOfNewBlock);
+ newBlockquote = blockquote.get();
+ insertionPoint = prepareBlockquoteLevelForInsertion(endOfCurrentParagraph, &newBlockquote);
+ }
+ moveParagraph(startOfParagraph(endOfCurrentParagraph), endOfCurrentParagraph, VisiblePosition(Position(insertionPoint, 0)), true);
+ endOfCurrentParagraph = endOfNextParagraph;
+ }
+}
+
+void IndentOutdentCommand::outdentParagraph()
+{
+ VisiblePosition visibleStartOfParagraph = startOfParagraph(endingSelection().visibleStart());
+ VisiblePosition visibleEndOfParagraph = endOfParagraph(visibleStartOfParagraph);
+
+ Node* enclosingNode = enclosingListOrBlockquote(visibleStartOfParagraph.deepEquivalent().node());
+ if (!enclosingNode)
+ return;
+
+ // Handle the list case
+ bool inList = false;
+ InsertListCommand::EListType typeOfList;
+ if (enclosingNode->hasTagName(olTag)) {
+ inList = true;
+ typeOfList = InsertListCommand::OrderedListType;
+ } else if (enclosingNode->hasTagName(ulTag)) {
+ inList = true;
+ typeOfList = InsertListCommand::UnorderedListType;
+ }
+ if (inList) {
+ // Use InsertListCommand to remove the selection from the list
+ EditCommandPtr cmd(new InsertListCommand(document(), typeOfList, ""));
+ applyCommandToComposite(cmd);
+ return;
+ }
+ // The selection is inside a blockquote
+ VisiblePosition positionInEnclosingBlock = VisiblePosition(Position(enclosingNode, 0));
+ VisiblePosition startOfEnclosingBlock = startOfBlock(positionInEnclosingBlock);
+ VisiblePosition endOfEnclosingBlock = endOfBlock(positionInEnclosingBlock);
+ if (visibleStartOfParagraph == startOfEnclosingBlock &&
+ visibleEndOfParagraph == endOfEnclosingBlock) {
+ // The blockquote doesn't contain anything outside the paragraph, so it can be totally removed.
+ removeNodePreservingChildren(enclosingNode);
+ return;
+ }
+ Node* enclosingBlockFlow = enclosingBlockFlowElement(visibleStartOfParagraph);
+ Node* splitBlockquoteNode = enclosingNode;
+ if (enclosingBlockFlow != enclosingNode)
+ splitBlockquoteNode = splitTreeToNode(enclosingBlockFlowElement(visibleStartOfParagraph), enclosingNode, true);
+ RefPtr<Node> placeholder = createBreakElement(document());
+ insertNodeBefore(placeholder.get(), splitBlockquoteNode);
+ moveParagraph(startOfParagraph(visibleStartOfParagraph), endOfParagraph(visibleEndOfParagraph), VisiblePosition(Position(placeholder.get(), 0)), true);
+}
+
+void IndentOutdentCommand::outdentRegion()
+{
+ VisiblePosition startOfSelection = endingSelection().visibleStart();
+ VisiblePosition endOfSelection = endingSelection().visibleEnd();
+ VisiblePosition endOfLastParagraph = endOfParagraph(endOfSelection);
+
+ ASSERT(!startOfSelection.isNull());
+ ASSERT(!endOfSelection.isNull());
+
+ if (endOfParagraph(startOfSelection) == endOfLastParagraph) {
+ outdentParagraph();
+ return;
+ }
+
+ Position originalSelectionEnd = endingSelection().end();
+ setEndingSelection(endingSelection().visibleStart());
+ outdentParagraph();
+ Position originalSelectionStart = endingSelection().start();
+ VisiblePosition endOfCurrentParagraph = endOfParagraph(endOfParagraph(endingSelection().visibleStart()).next(true));
+ VisiblePosition endAfterSelection = endOfParagraph(endOfParagraph(endOfSelection).next());
+ while (endOfCurrentParagraph != endAfterSelection) {
+ VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
+ if (endOfCurrentParagraph == endOfLastParagraph)
+ setEndingSelection(originalSelectionEnd, DOWNSTREAM);
+ else
+ setEndingSelection(endOfCurrentParagraph);
+ outdentParagraph();
+ endOfCurrentParagraph = endOfNextParagraph;
+ }
+ setEndingSelection(Selection(originalSelectionStart, endingSelection().end(), DOWNSTREAM));
+}
+
+void IndentOutdentCommand::doApply()
+{
+ if (endingSelection().isNone())
+ return;
+
+ if (!endingSelection().rootEditableElement())
+ return;
+
+ if (m_typeOfAction == Indent)
+ indentRegion();
+ else
+ outdentRegion();
+}
+
+}
--- /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 IndentOutdentCommand_h
+#define IndentOutdentCommand_h
+
+#include "CompositeEditCommand.h"
+
+namespace WebCore {
+
+class IndentOutdentCommand : public CompositeEditCommand
+{
+public:
+ enum EIndentType { Indent, Outdent };
+ IndentOutdentCommand(WebCore::Document*, EIndentType, int marginInPixels = 0);
+ virtual void doApply();
+ virtual EditAction editingAction() const { return m_typeOfAction == Indent ? EditActionIndent : EditActionOutdent; }
+private:
+ void splitTreeTo(Node* start, Node* stop);
+ bool modifyRange();
+ EIndentType m_typeOfAction;
+ int m_marginInPixels;
+ void indentRegion();
+ void outdentRegion();
+ void outdentParagraph();
+ Node* splitTreeToNode(Node*, Node*, bool splitAncestor = false);
+ Node* prepareBlockquoteLevelForInsertion(VisiblePosition&, Node**);
+};
+
+} // namespace WebCore
+
+#endif // IndentOutdentCommand_h
#include "Frame.h"
#include "HTMLNames.h"
#include "HTMLImageElement.h"
+#include "IndentOutdentCommand.h"
#include "InsertListCommand.h"
#include "ReplaceSelectionCommand.h"
#include "SelectionController.h"
bool execIndent(Frame *frame, bool userInterface, const String &value)
{
- // FIXME: Implement.
- return false;
+ EditCommandPtr(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Indent)).apply();
+ return true;
}
bool execInsertLineBreak(Frame *frame, bool userInterface, const String &value)
bool execOutdent(Frame *frame, bool userInterface, const String &value)
{
- // FIXME: Implement.
- return false;
+ EditCommandPtr(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Outdent)).apply();
+ return true;
}
bool execPaste(Frame *frame, bool userInterface, const String &value)
using namespace HTMLNames;
-static Node* highestAncestor(Node* node)
-{
- ASSERT(node);
- Node* parent = node;
- while ((node = node->parentNode()))
- parent = node;
- return parent;
-}
-
// Atomic means that the node has no children, or has children which are ignored for the
// purposes of editing.
bool isAtomicNode(const Node *node)
return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
}
+Node* enclosingNodeWithTag(Node* node, const QualifiedName& tagName)
+{
+ if (!node)
+ return 0;
+ Node* root = (node->inDocument()) ? node->rootEditableElement() : highestAncestor(node);
+ ASSERT(root);
+ for (Node* n = node->parentNode(); n && (n == root || n->isAncestor(root)); n = n->parentNode())
+ if (n->hasTagName(tagName))
+ return n;
+
+ return 0;
+}
+
Node* enclosingTableCell(Node* node)
{
if (!node)
return 0;
}
-Node *enclosingListChild (Node *node)
+Node* enclosingListChild (Node *node)
{
+ if (!node)
+ return 0;
// Check for a list item element, or for a node whose parent is a list element. Such a node
// will appear visually as a list item (but without a list marker)
- for (Node *n = node; n && n->parentNode(); n = n->parentNode()) {
+ Node* root = (node->inDocument()) ? node->rootEditableElement() : highestAncestor(node);
+ ASSERT(root);
+ for (Node *n = node; n && n->parentNode() && (n == root || n->isAncestor(root)); n = n->parentNode()) {
if (n->hasTagName(liTag) || isListElement(n->parentNode()))
return n;
}
return 0;
}
+Node* outermostEnclosingListChild(Node* node)
+{
+ Node* listNode = 0;
+ Node* nextNode = node;
+ while ((nextNode = enclosingListChild(nextNode)))
+ listNode = nextNode;
+ return listNode;
+}
+
Node* outermostEnclosingList(Node* node)
{
Node* listNode = 0;
return listNode;
}
+Node* highestAncestor(Node* node)
+{
+ ASSERT(node);
+ Node* parent = node;
+ while ((node = node->parentNode()))
+ parent = node;
+ return parent;
+}
+
// FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
bool isTableElement(Node *n)
{
return breakNode.release();
}
-PassRefPtr<Element> createElement(Document* document, String& tagName)
+PassRefPtr<Element> createElement(Document* document, const String& tagName)
{
ExceptionCode ec = 0;
RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, tagName, ec);
#define htmlediting_h
#include <wtf/Forward.h>
+#include "HTMLNames.h"
namespace WebCore {
PassRefPtr<Element> createOrderedListElement(Document*);
PassRefPtr<Element> createUnorderedListElement(Document*);
PassRefPtr<Element> createListItemElement(Document*);
-PassRefPtr<Element> createElement(Document*, String&);
+PassRefPtr<Element> createElement(Document*, const String&);
bool isTabSpanNode(const Node*);
bool isTabSpanTextNode(const Node*);
Position positionAfterContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
Position positionOutsideContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
+Node* enclosingNodeWithTag(Node*, const QualifiedName&);
Node* enclosingTableCell(Node*);
bool isListElement(Node*);
Node* enclosingList(Node*);
Node* outermostEnclosingList(Node*);
Node* enclosingListChild(Node*);
+Node* highestAncestor(Node*);
bool isTableElement(Node*);
bool isFirstVisiblePositionAfterTableElement(const Position&);
Position positionBeforePrecedingTableElement(const Position&);
+2006-06-28 Levi Weintraub <lweintraub@apple.com>
+
+ Reviewed by justin
+
+ http://bugzilla.opendarwin.org/show_bug.cgi?id=7568
+ Bug 7568: Implement Indent/Outdent
+ Added undo action strings and enum values
+
+ * English.lproj/Localizable.strings:
+ * WebCoreSupport/WebFrameBridge.m:
+ (-[WebFrameBridge nameForUndoAction:]):
+
2006-06-27 Brady Eidson <beidson@apple.com>
Reviewed by Maciej
Renamed from -initWithPath:. Instead of releasing/deallocating self on error, return NO.
(-[WebNetscapePluginPackage initWithPath:]):
Call the new -_initWithPath:. If it returns NO, unload the plugin package before deallocating it.
-
->>>>>>> .r14837
+
2006-06-11 Darin Adler <darin@apple.com>
- try to fix Windows build
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");
+ case WebUndoActionIndent: return UI_STRING_KEY("Indent", "Indent (Undo action name)", "Undo action name");
+ case WebUndoActionOutdent: return UI_STRING_KEY("Outdent", "Outdent (Undo action name)", "Undo action name");
}
return nil;
}