ModifySelectionListLevel.cpp [plain text]
#include "config.h"
#include "ModifySelectionListLevel.h"
#include "Document.h"
#include "Element.h"
#include "Frame.h"
#include "RenderObject.h"
#include "SelectionController.h"
#include "htmlediting.h"
namespace WebCore {
ModifySelectionListLevelCommand::ModifySelectionListLevelCommand(Document* document)
: CompositeEditCommand(document)
{
}
bool ModifySelectionListLevelCommand::preservesTypingStyle() const
{
return true;
}
static bool getStartEndListChildren(const Selection& selection, Node** start, Node** end)
{
if (selection.isNone())
return false;
Node* startListChild = enclosingListChild(selection.start().node());
if (!startListChild)
return false;
Node* endListChild = selection.isRange() ? enclosingListChild(selection.end().node()) : startListChild;
if (!endListChild)
return false;
while (startListChild->parentNode() != endListChild->parentNode()) {
endListChild = endListChild->parentNode();
if (!endListChild)
return false;
}
if (endListChild->renderer()->isListItem()) {
RenderObject* r = endListChild->renderer()->nextSibling();
if (r && isListElement(r->element()))
endListChild = r->element();
}
*start = startListChild;
*end = endListChild;
return true;
}
void ModifySelectionListLevelCommand::insertSiblingNodeRangeBefore(Node* startNode, Node* endNode, Node* refNode)
{
Node* node = startNode;
while (1) {
Node* next = node->nextSibling();
removeNode(node);
insertNodeBefore(node, refNode);
if (node == endNode)
break;
node = next;
}
}
void ModifySelectionListLevelCommand::insertSiblingNodeRangeAfter(Node* startNode, Node* endNode, Node* refNode)
{
Node* node = startNode;
while (1) {
Node* next = node->nextSibling();
removeNode(node);
insertNodeAfter(node, refNode);
if (node == endNode)
break;
refNode = node;
node = next;
}
}
void ModifySelectionListLevelCommand::appendSiblingNodeRange(Node* startNode, Node* endNode, Node* newParent)
{
Node* node = startNode;
while (1) {
Node* next = node->nextSibling();
removeNode(node);
appendNode(node, newParent);
if (node == endNode)
break;
node = next;
}
}
IncreaseSelectionListLevelCommand::IncreaseSelectionListLevelCommand(Document* document, EListType listType)
: ModifySelectionListLevelCommand(document)
{
m_listType = listType;
m_listElement = 0;
}
Node* IncreaseSelectionListLevelCommand::listElement()
{
return m_listElement;
}
static bool canIncreaseListLevel(const Selection& selection, Node** start, Node** end)
{
if (!getStartEndListChildren(selection, start, end))
return false;
if (!(*start)->renderer()->previousSibling())
return false;
return true;
}
void IncreaseSelectionListLevelCommand::doApply()
{
Node* startListChild;
Node* endListChild;
if (!canIncreaseListLevel(endingSelection(), &startListChild, &endListChild))
return;
Node* previousItem = startListChild->renderer()->previousSibling()->element();
if (isListElement(previousItem)) {
appendSiblingNodeRange(startListChild, endListChild, previousItem);
m_listElement = previousItem;
} else {
RefPtr<Node> newParent;
switch (m_listType) {
case InheritedListType:
newParent = startListChild->parentNode()->cloneNode(false);
break;
case OrderedList:
newParent = createOrderedListElement(document());
break;
case UnorderedList:
newParent = createUnorderedListElement(document());
break;
}
insertNodeBefore(newParent.get(), startListChild);
appendSiblingNodeRange(startListChild, endListChild, newParent.get());
m_listElement = newParent.get();
}
}
bool IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(Document* document)
{
Node* startListChild;
Node* endListChild;
return canIncreaseListLevel(document->frame()->selection().selection(), &startListChild, &endListChild);
}
static Node* increaseSelectionListLevelWithType(Document* document, EListType listType)
{
ASSERT(document);
ASSERT(document->frame());
IncreaseSelectionListLevelCommand* modCommand = new IncreaseSelectionListLevelCommand(document, listType);
EditCommandPtr cmd(modCommand);
cmd.apply();
return modCommand->listElement();
}
Node* IncreaseSelectionListLevelCommand::increaseSelectionListLevel(Document* document) {
return increaseSelectionListLevelWithType(document, InheritedListType);
}
Node* IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(Document* document) {
return increaseSelectionListLevelWithType(document, OrderedList);
}
Node* IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(Document* document) {
return increaseSelectionListLevelWithType(document, UnorderedList);
}
DecreaseSelectionListLevelCommand::DecreaseSelectionListLevelCommand(Document* document)
: ModifySelectionListLevelCommand(document)
{
}
static bool canDecreaseListLevel(const Selection& selection, Node** start, Node** end)
{
if (!getStartEndListChildren(selection, start, end))
return false;
if (!isListElement((*start)->parentNode()->parentNode()))
return false;
return true;
}
void DecreaseSelectionListLevelCommand::doApply()
{
Node* startListChild;
Node* endListChild;
if (!canDecreaseListLevel(endingSelection(), &startListChild, &endListChild))
return;
Node* previousItem = startListChild->renderer()->previousSibling() ? startListChild->renderer()->previousSibling()->element() : 0;
Node* nextItem = endListChild->renderer()->nextSibling() ? endListChild->renderer()->nextSibling()->element() : 0;
Node* listNode = startListChild->parentNode();
if (!previousItem) {
insertSiblingNodeRangeBefore(startListChild, endListChild, listNode);
if (!nextItem)
removeNode(listNode);
} else if (!nextItem) {
insertSiblingNodeRangeAfter(startListChild, endListChild, listNode);
} else {
splitElement(static_cast<Element*>(listNode), startListChild);
insertSiblingNodeRangeBefore(startListChild, endListChild, listNode);
}
}
bool DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(Document* document)
{
Node* startListChild;
Node* endListChild;
return canDecreaseListLevel(document->frame()->selection().selection(), &startListChild, &endListChild);
}
void DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(Document* document)
{
ASSERT(document);
ASSERT(document->frame());
DecreaseSelectionListLevelCommand* modCommand = new DecreaseSelectionListLevelCommand(document);
EditCommandPtr cmd(modCommand);
cmd.apply();
}
}