This source file includes following definitions.
- isListOrIndentBlockquote
- m_typeOfAction
- tryIndentingAsListItem
- indentIntoBlockquote
- outdentParagraph
- outdentRegion
- formatSelection
- formatRange
#include "config.h"
#include "core/editing/IndentOutdentCommand.h"
#include "HTMLNames.h"
#include "core/dom/Document.h"
#include "core/dom/ElementTraversal.h"
#include "core/editing/InsertListCommand.h"
#include "core/editing/VisibleUnits.h"
#include "core/editing/htmlediting.h"
#include "core/html/HTMLElement.h"
#include "core/rendering/RenderObject.h"
namespace WebCore {
using namespace HTMLNames;
static bool isListOrIndentBlockquote(const Node* node)
{
return node && (isHTMLUListElement(*node) || isHTMLOListElement(*node) || node->hasTagName(blockquoteTag));
}
IndentOutdentCommand::IndentOutdentCommand(Document& document, EIndentType typeOfAction)
: ApplyBlockElementCommand(document, blockquoteTag, "margin: 0 0 0 40px; border: none; padding: 0px;")
, m_typeOfAction(typeOfAction)
{
}
bool IndentOutdentCommand::tryIndentingAsListItem(const Position& start, const Position& end)
{
RefPtr<Node> lastNodeInSelectedParagraph = start.deprecatedNode();
RefPtr<Element> listNode = enclosingList(lastNodeInSelectedParagraph.get());
if (!listNode)
return false;
RefPtr<Element> selectedListItem = enclosingBlock(lastNodeInSelectedParagraph.get());
if (!isHTMLLIElement(*selectedListItem))
return false;
RefPtr<Element> previousList = ElementTraversal::previousSibling(*selectedListItem);
RefPtr<Element> nextList = ElementTraversal::nextSibling(*selectedListItem);
RefPtr<Element> newList = document().createElement(listNode->tagQName(), false);
insertNodeBefore(newList, selectedListItem.get());
if (end.anchorNode() == selectedListItem.get() || end.anchorNode()->isDescendantOf(selectedListItem->lastChild())) {
moveParagraphWithClones(VisiblePosition(start), VisiblePosition(end), newList.get(), selectedListItem.get());
} else {
moveParagraphWithClones(VisiblePosition(start), VisiblePosition(positionAfterNode(selectedListItem->lastChild())), newList.get(), selectedListItem.get());
removeNode(selectedListItem.get());
}
if (canMergeLists(previousList.get(), newList.get()))
mergeIdenticalElements(previousList.get(), newList.get());
if (canMergeLists(newList.get(), nextList.get()))
mergeIdenticalElements(newList.get(), nextList.get());
return true;
}
void IndentOutdentCommand::indentIntoBlockquote(const Position& start, const Position& end, RefPtr<Element>& targetBlockquote)
{
Node* enclosingCell = enclosingNodeOfType(start, &isTableCell);
Node* nodeToSplitTo;
if (enclosingCell)
nodeToSplitTo = enclosingCell;
else if (enclosingList(start.containerNode()))
nodeToSplitTo = enclosingBlock(start.containerNode());
else
nodeToSplitTo = editableRootForPosition(start);
if (!nodeToSplitTo)
return;
RefPtr<Node> outerBlock = (start.containerNode() == nodeToSplitTo) ? start.containerNode() : splitTreeToNode(start.containerNode(), nodeToSplitTo);
VisiblePosition startOfContents(start);
if (!targetBlockquote) {
targetBlockquote = createBlockElement();
if (outerBlock == start.containerNode())
insertNodeAt(targetBlockquote, start);
else
insertNodeBefore(targetBlockquote, outerBlock);
startOfContents = VisiblePosition(positionInParentAfterNode(*targetBlockquote));
}
moveParagraphWithClones(startOfContents, VisiblePosition(end), targetBlockquote.get(), outerBlock.get());
}
void IndentOutdentCommand::outdentParagraph()
{
VisiblePosition visibleStartOfParagraph = startOfParagraph(endingSelection().visibleStart());
VisiblePosition visibleEndOfParagraph = endOfParagraph(visibleStartOfParagraph);
Node* enclosingNode = enclosingNodeOfType(visibleStartOfParagraph.deepEquivalent(), &isListOrIndentBlockquote);
if (!enclosingNode || !enclosingNode->parentNode()->rendererIsEditable())
return;
if (isHTMLOListElement(*enclosingNode)) {
applyCommandToComposite(InsertListCommand::create(document(), InsertListCommand::OrderedList));
return;
}
if (isHTMLUListElement(*enclosingNode)) {
applyCommandToComposite(InsertListCommand::create(document(), InsertListCommand::UnorderedList));
return;
}
VisiblePosition positionInEnclosingBlock = VisiblePosition(firstPositionInNode(enclosingNode));
VisiblePosition startOfEnclosingBlock = (enclosingNode->renderer() && enclosingNode->renderer()->isInline()) ? positionInEnclosingBlock : startOfBlock(positionInEnclosingBlock);
VisiblePosition lastPositionInEnclosingBlock = VisiblePosition(lastPositionInNode(enclosingNode));
VisiblePosition endOfEnclosingBlock = endOfBlock(lastPositionInEnclosingBlock);
if (visibleStartOfParagraph == startOfEnclosingBlock &&
visibleEndOfParagraph == endOfEnclosingBlock) {
Node* splitPoint = enclosingNode->nextSibling();
removeNodePreservingChildren(enclosingNode);
if (splitPoint) {
if (ContainerNode* splitPointParent = splitPoint->parentNode()) {
if (splitPointParent->hasTagName(blockquoteTag)
&& !splitPoint->hasTagName(blockquoteTag)
&& splitPointParent->parentNode()->rendererIsEditable())
splitElement(toElement(splitPointParent), splitPoint);
}
}
document().updateLayoutIgnorePendingStylesheets();
visibleStartOfParagraph = VisiblePosition(visibleStartOfParagraph.deepEquivalent());
visibleEndOfParagraph = VisiblePosition(visibleEndOfParagraph.deepEquivalent());
if (visibleStartOfParagraph.isNotNull() && !isStartOfParagraph(visibleStartOfParagraph))
insertNodeAt(createBreakElement(document()), visibleStartOfParagraph.deepEquivalent());
if (visibleEndOfParagraph.isNotNull() && !isEndOfParagraph(visibleEndOfParagraph))
insertNodeAt(createBreakElement(document()), visibleEndOfParagraph.deepEquivalent());
return;
}
Node* enclosingBlockFlow = enclosingBlock(visibleStartOfParagraph.deepEquivalent().deprecatedNode());
RefPtr<Node> splitBlockquoteNode = enclosingNode;
if (enclosingBlockFlow != enclosingNode)
splitBlockquoteNode = splitTreeToNode(enclosingBlockFlow, enclosingNode, true);
else {
Node* highestInlineNode = highestEnclosingNodeOfType(visibleStartOfParagraph.deepEquivalent(), isInline, CannotCrossEditingBoundary, enclosingBlockFlow);
splitElement(toElement(enclosingNode), (highestInlineNode) ? highestInlineNode : visibleStartOfParagraph.deepEquivalent().deprecatedNode());
}
RefPtr<Node> placeholder = createBreakElement(document());
insertNodeBefore(placeholder, splitBlockquoteNode);
moveParagraph(startOfParagraph(visibleStartOfParagraph), endOfParagraph(visibleEndOfParagraph), VisiblePosition(positionBeforeNode(placeholder.get())), true);
}
void IndentOutdentCommand::outdentRegion(const VisiblePosition& startOfSelection, const VisiblePosition& endOfSelection)
{
VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection);
VisiblePosition endOfLastParagraph = endOfParagraph(endOfSelection);
if (endOfCurrentParagraph == endOfLastParagraph) {
outdentParagraph();
return;
}
Position originalSelectionEnd = endingSelection().end();
VisiblePosition endAfterSelection = endOfParagraph(endOfLastParagraph.next());
while (endOfCurrentParagraph != endAfterSelection) {
VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
if (endOfCurrentParagraph == endOfLastParagraph)
setEndingSelection(VisibleSelection(originalSelectionEnd, DOWNSTREAM));
else
setEndingSelection(endOfCurrentParagraph);
outdentParagraph();
if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().inDocument())
break;
if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().inDocument()) {
endOfCurrentParagraph = VisiblePosition(endingSelection().end());
endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
}
endOfCurrentParagraph = endOfNextParagraph;
}
}
void IndentOutdentCommand::formatSelection(const VisiblePosition& startOfSelection, const VisiblePosition& endOfSelection)
{
if (m_typeOfAction == Indent)
ApplyBlockElementCommand::formatSelection(startOfSelection, endOfSelection);
else
outdentRegion(startOfSelection, endOfSelection);
}
void IndentOutdentCommand::formatRange(const Position& start, const Position& end, const Position&, RefPtr<Element>& blockquoteForNextIndent)
{
if (tryIndentingAsListItem(start, end))
blockquoteForNextIndent = nullptr;
else
indentIntoBlockquote(start, end, blockquoteForNextIndent);
}
}