Commit 613b7e24 authored by lweintraub's avatar lweintraub

LayoutTests:

        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: http://svn.webkit.org/repository/webkit/trunk@15080 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent fcd2c934
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.
......@@ -243,6 +273,7 @@
(WebCore::SQLStatement::getColumnBlobAsVector):
(WebCore::SQLStatement::getColumnBlob):
>>>>>>> .r15079
2006-06-27 Ada Chan <adachan@apple.com>
Reviewed by sfalken.
......
......@@ -3990,6 +3990,14 @@
RelativePath="..\..\editing\InsertListCommand.h"
>
</File>
<File
RelativePath="..\..\editing\IndentOutdentCommand.cpp"
>
</File>
<File
RelativePath="..\..\editing\IndentOutdentCommand.h"
>
</File>
<File
RelativePath="..\..\editing\InsertNodeBeforeCommand.cpp"
>
......
......@@ -1552,6 +1552,8 @@
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 */; };
......@@ -3294,6 +3296,8 @@
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; };
......@@ -3939,6 +3943,8 @@
93309D86099E64910056E581 /* editing */ = {
isa = PBXGroup;
children = (
DB23C2C90A508D29002489EB /* IndentOutdentCommand.cpp */,
DB23C2CA0A508D29002489EB /* IndentOutdentCommand.h */,
D05CED270A40BB2C00C5AF38 /* FormatBlockCommand.cpp */,
D05CED280A40BB2C00C5AF38 /* FormatBlockCommand.h */,
93309D87099E64910056E581 /* AppendNodeCommand.cpp */,
......@@ -6329,6 +6335,7 @@
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 */,
);
......@@ -7182,6 +7189,7 @@
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 */,
......
......@@ -62,7 +62,9 @@ namespace WebCore {
EditActionCreateLink,
EditActionUnlink,
EditActionFormatBlock,
EditActionInsertList
EditActionInsertList,
EditActionIndent,
EditActionOutdent
} EditAction;
}
......
/*
* 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();
}
}
/*
* 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
......@@ -34,6 +34,7 @@
#include "Frame.h"
#include "HTMLNames.h"
#include "HTMLImageElement.h"
#include "IndentOutdentCommand.h"
#include "InsertListCommand.h"
#include "ReplaceSelectionCommand.h"
#include "SelectionController.h"
......@@ -314,8 +315,8 @@ bool execInsertImage(Frame* frame, bool userInterface, const String& value)
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)
......@@ -382,8 +383,8 @@ bool execJustifyRight(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)
......
......@@ -42,15 +42,6 @@ namespace WebCore {
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)
......@@ -370,6 +361,19 @@ bool isListElement(Node *n)
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)
......@@ -395,11 +399,15 @@ Node* enclosingList(Node* 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;
}
......@@ -407,6 +415,15 @@ Node *enclosingListChild (Node *node)
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;
......@@ -416,6 +433,15 @@ Node* outermostEnclosingList(Node* node)
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)
{
......@@ -528,7 +554,7 @@ PassRefPtr<Element> createListItemElement(Document *document)
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);
......
......@@ -27,6 +27,7 @@
#define htmlediting_h
#include <wtf/Forward.h>
#include "HTMLNames.h"
namespace WebCore {
......@@ -62,7 +63,7 @@ PassRefPtr<Element> createBreakElement(Document*);
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*);
......@@ -87,11 +88,13 @@ bool isLastVisiblePositionInSpecialElement(const Position&);
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
......@@ -670,8 +682,7 @@
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
......
B/* window title for a standalone image (uses multiplication symbol, not x) */
......
......@@ -1583,6 +1583,8 @@ - (NSString *)nameForUndoAction:(WebUndoAction)undoAction
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;