BreakBlockquoteCommand.cpp [plain text]
#include "config.h"
#include "BreakBlockquoteCommand.h"
#include "HTMLBRElement.h"
#include "HTMLNames.h"
#include "NodeTraversal.h"
#include "RenderListItem.h"
#include "Text.h"
#include "htmlediting.h"
namespace WebCore {
using namespace HTMLNames;
BreakBlockquoteCommand::BreakBlockquoteCommand(Document& document)
: CompositeEditCommand(document)
{
}
void BreakBlockquoteCommand::doApply()
{
if (endingSelection().isNone())
return;
if (endingSelection().isRange())
deleteSelection(false, false);
ASSERT(!endingSelection().isNone());
if (endingSelection().isNone())
return;
VisiblePosition visiblePos = endingSelection().visibleStart();
Position pos = endingSelection().start().downstream();
Node* topBlockquote = highestEnclosingNodeOfType(pos, isMailBlockquote);
if (!topBlockquote || !topBlockquote->parentNode() || !topBlockquote->isElementNode())
return;
auto breakNode = HTMLBRElement::create(document());
bool isLastVisPosInNode = isLastVisiblePositionInNode(visiblePos, topBlockquote);
if (isFirstVisiblePositionInNode(visiblePos, topBlockquote) && !isLastVisPosInNode) {
insertNodeBefore(breakNode.copyRef(), topBlockquote);
setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.ptr()), DOWNSTREAM, endingSelection().isDirectional()));
rebalanceWhitespace();
return;
}
insertNodeAfter(breakNode.copyRef(), topBlockquote);
if (isLastVisPosInNode) {
setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.ptr()), DOWNSTREAM, endingSelection().isDirectional()));
rebalanceWhitespace();
return;
}
if (lineBreakExistsAtVisiblePosition(visiblePos))
pos = pos.next();
while (isFirstVisiblePositionInNode(VisiblePosition(pos), enclosingNodeOfType(pos, isMailBlockquote)))
pos = pos.previous();
Node* startNode = pos.deprecatedNode();
ASSERT(startNode);
if (is<Text>(*startNode)) {
Text& textNode = downcast<Text>(*startNode);
if ((unsigned)pos.deprecatedEditingOffset() >= textNode.length()) {
startNode = NodeTraversal::next(*startNode);
ASSERT(startNode);
} else if (pos.deprecatedEditingOffset() > 0)
splitTextNode(&textNode, pos.deprecatedEditingOffset());
} else if (pos.deprecatedEditingOffset() > 0) {
Node* childAtOffset = startNode->traverseToChildAt(pos.deprecatedEditingOffset());
startNode = childAtOffset ? childAtOffset : NodeTraversal::next(*startNode);
ASSERT(startNode);
}
if (!startNode->isDescendantOf(topBlockquote)) {
setEndingSelection(VisibleSelection(VisiblePosition(firstPositionInOrBeforeNode(startNode)), endingSelection().isDirectional()));
return;
}
Vector<RefPtr<Element>> ancestors;
for (Element* node = startNode->parentElement(); node && node != topBlockquote; node = node->parentElement())
ancestors.append(node);
RefPtr<Element> clonedBlockquote = downcast<Element>(*topBlockquote).cloneElementWithoutChildren(document());
insertNodeAfter(clonedBlockquote.get(), breakNode.copyRef());
RefPtr<Element> clonedAncestor = clonedBlockquote;
for (size_t i = ancestors.size(); i != 0; --i) {
RefPtr<Element> clonedChild = ancestors[i - 1]->cloneElementWithoutChildren(document());
if (clonedChild->isElementNode() && clonedChild->hasTagName(olTag)) {
Node* listChildNode = i > 1 ? ancestors[i - 2].get() : startNode;
while (listChildNode && !listChildNode->hasTagName(liTag))
listChildNode = listChildNode->nextSibling();
if (listChildNode && is<RenderListItem>(listChildNode->renderer()))
setNodeAttribute(clonedChild, startAttr, AtomicString::number(downcast<RenderListItem>(*listChildNode->renderer()).value()));
}
appendNode(clonedChild.get(), clonedAncestor.get());
clonedAncestor = clonedChild;
}
moveRemainingSiblingsToNewParent(startNode, 0, clonedAncestor);
if (!ancestors.isEmpty()) {
RefPtr<Element> ancestor;
RefPtr<Element> clonedParent;
for (ancestor = ancestors.first(), clonedParent = clonedAncestor->parentElement();
ancestor && ancestor != topBlockquote;
ancestor = ancestor->parentElement(), clonedParent = clonedParent->parentElement())
moveRemainingSiblingsToNewParent(ancestor->nextSibling(), 0, clonedParent);
Node* originalParent = ancestors.first().get();
if (!originalParent->hasChildNodes())
removeNode(originalParent);
}
addBlockPlaceholderIfNeeded(clonedBlockquote.get());
setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.ptr()), DOWNSTREAM, endingSelection().isDirectional()));
rebalanceWhitespace();
}
}