29#include "css/cssproperties.h"
30#include "css/css_valueimpl.h"
32#include "html/html_elementimpl.h"
33#include "html/html_imageimpl.h"
34#include "rendering/render_object.h"
35#include "rendering/render_style.h"
36#include "rendering/render_text.h"
37#include "xml/dom_docimpl.h"
38#include "xml/dom_elementimpl.h"
39#include "xml/dom_position.h"
40#include "xml/dom_positioniterator.h"
41#include "xml/dom_nodeimpl.h"
42#include "xml/dom_selection.h"
43#include "xml/dom_stringimpl.h"
44#include "xml/dom_textimpl.h"
45#include "xml/dom2_rangeimpl.h"
46#include "xml/dom2_viewsimpl.h"
56using DOM::CSSPrimitiveValueImpl;
57using DOM::CSSProperty;
58using DOM::CSSStyleDeclarationImpl;
59using DOM::CSSValueImpl;
60using DOM::DocumentFragmentImpl;
61using DOM::DocumentImpl;
63using DOM::DOMStringImpl;
64using DOM::EditingTextImpl;
65using DOM::PositionIterator;
66using DOM::ElementImpl;
67using DOM::HTMLElementImpl;
68using DOM::HTMLImageElementImpl;
69using DOM::NamedAttrMapImpl;
72using DOM::NodeListImpl;
78using DOM::TreeWalkerImpl;
81#define DEBUG_COMMANDS 1
86static inline bool isNBSP(
const QChar &c)
88 return c == QChar(0xa0);
91static inline bool isWS(
const QChar &c)
93 return c.isSpace() && c != QChar(0xa0);
101 return isWS(text[0]);
104static inline bool isWS(
const Position &pos)
109 if (!pos.node()->isTextNode())
112 const DOMString &
string =
static_cast<TextImpl *
>(pos.node())->data();
113 return isWS(
string[pos.offset()]);
121 RenderObject *renderer = node->renderer();
125 if (node->hasChildNodes())
128 if (node->rootEditableElement() == node)
131 if (renderer->isBR() || renderer->isReplaced())
134 if (node->isTextNode()) {
135 TextImpl *text =
static_cast<TextImpl *
>(node);
136 if (text->length() == 0)
141 if (!node->isHTMLElement())
144 if (node->id() == ID_BODY)
147 if (!node->isContentEditable())
157 Selection selection(pos);
158 Position prev = pos.previousCharacterPosition();
159 if (prev != pos && prev.node()->inSameContainingBlockFlowElement(pos.node()) && prev.node()->isTextNode()) {
160 DOMString string =
static_cast<TextImpl *
>(prev.node())->data();
161 if (
isWS(
string[prev.offset()]))
172 if (pos.node()->isTextNode()) {
173 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
174 if (pos.offset() >= (long)textNode->length()) {
175 Position
next = pos.nextCharacterPosition();
176 if (
next != pos &&
next.node()->inSameContainingBlockFlowElement(pos.node()) &&
next.node()->isTextNode()) {
177 DOMString string =
static_cast<TextImpl *
>(
next.node())->data();
183 DOMString string =
static_cast<TextImpl *
>(pos.node())->data();
184 if (
isWS(
string[pos.offset()]))
197 return (text1->nextSibling() == text2);
219 assert(m_document->part());
221 m_startingSelection = m_document->part()->caret();
222 m_endingSelection = m_startingSelection;
233 assert(m_document->part());
241 m_document->part()->editor()->appliedEditing(
this);
247 assert(m_document->part());
255 m_document->part()->editor()->unappliedEditing(
this);
261 assert(m_document->part());
269 m_document->part()->editor()->reappliedEditing(
this);
279 m_startingSelection = s;
282 cmd->m_startingSelection = s;
289 m_endingSelection = s;
292 cmd->m_endingSelection = s;
299 return m_parent.get();
321 if (
m_cmds.count() == 0) {
325 for (
int i =
m_cmds.count() - 1; i >= 0; --i)
333 if (
m_cmds.count() == 0) {
336 QMutableListIterator<RefPtr<EditCommandImpl> > it(
m_cmds);
338 it.next()->reapply();
350 cmd->setParent(
this);
363 if (refChild->parentNode()->lastChild() == refChild) {
364 appendNode(refChild->parentNode(), insertChild);
367 assert(refChild->nextSibling());
374 if (refChild->hasChildNodes() || (refChild->renderer() && refChild->renderer()->isBlockFlow())) {
375 NodeImpl *child = refChild->firstChild();
376 for (
long i = 0; child && i < offset; i++)
377 child = child->nextSibling();
383 else if (refChild->caretMinOffset() >= offset) {
386 else if (refChild->isTextNode() && refChild->caretMaxOffset() > offset) {
468 if (selection.state() == Selection::RANGE) {
506 int exceptionCode = 0;
507 ElementImpl *styleElement =
document()->createHTMLElement(
"SPAN");
510 styleElement->setAttribute(ATTR_STYLE,
document()->part()->editor()->typingStyle()->cssText().implementation());
514 assert(exceptionCode == 0);
525 :
EditCommandImpl(document), m_parentNode(parentNode), m_appendChild(appendChild)
531 m_appendChild->ref();
537 m_parentNode->deref();
539 m_appendChild->deref();
547 int exceptionCode = 0;
548 m_parentNode->appendChild(m_appendChild, exceptionCode);
549 assert(exceptionCode == 0);
558 int exceptionCode = 0;
559 m_parentNode->removeChild(m_appendChild, exceptionCode);
560 assert(exceptionCode == 0);
581 QListIterator<CSSProperty*> it(*(style->values()));
582 while (it.hasNext()) {
583 CSSProperty *
property = it.next();
584 switch (property->id()) {
585 case CSS_PROP_TEXT_ALIGN:
611 QScopedPointer<CSSStyleDeclarationImpl> computedStyle(
612 element->document()->defaultView()->getComputedStyle(element, 0));
613 assert(!computedStyle.isNull());
615 kDebug() <<
"[change style]" << element << endl;
618 QListIterator<CSSProperty*> it(*(style->values()));
619 while ( it.hasNext() ) {
620 CSSProperty *
property = it.next();
621 CSSValueImpl *computedValue = computedStyle->getPropertyCSSValue(property->id());
622 DOMString newValue =
property->value()->cssText();
624 kDebug() <<
"[new value]:" <<
property->cssText() << endl;
625 kDebug() <<
"[computedValue]:" << computedValue->cssText() << endl;
627 if (strcasecmp(computedValue->cssText(), newValue)) {
629 element->getInlineStyleDecls()->setProperty(property->id(), newValue);
640 Position start(
endingSelection().start().equivalentDownstreamPosition().equivalentRangeCompliantPosition());
643 kDebug() <<
"[APPLY STYLE]" << start <<
end << endl;
644 printEnclosingBlockTree(start.node()->enclosingBlockFlowElement());
649 kDebug() <<
"[APPLY BLOCK LEVEL STYLE]" << endl;
651 ElementImpl *startBlock = start.node()->enclosingBlockFlowElement();
652 ElementImpl *endBlock =
end.node()->enclosingBlockFlowElement();
654 kDebug() << startBlock << startBlock->nodeName() << endl;
656 if (startBlock == endBlock && startBlock == start.node()->rootEditableElement()) {
657 ElementImpl* block =
document()->createHTMLElement(
"DIV");
659 kDebug() <<
"[Create DIV with Style:]" << m_style->cssText() << endl;
661 block->setAttribute(ATTR_STYLE, m_style->cssText());
662 for (NodeImpl* node = startBlock->firstChild(); node; node = startBlock->firstChild()) {
664 kDebug() <<
"[reparent node]" << node << node->nodeName() << endl;
670 }
else if (startBlock == endBlock) {
680 removeStyle(start,
end);
681 bool splitStart = splitTextAtStartIfNeeded(start,
end);
686 splitTextAtEndIfNeeded(start,
end);
691 kDebug() <<
"[start;end]" << start <<
end << endl;
693 if (start.node() ==
end.node()) {
695 applyStyleIfNeeded(start.node(),
end.node());
697 NodeImpl *node = start.node();
699 if (node->childNodeCount() == 0 && node->renderer() && node->renderer()->isInline()) {
700 NodeImpl *runStart = node;
702 if (runStart->parentNode() != node->parentNode() || node->isHTMLElement() || node ==
end.node() ||
703 (node->renderer() && !node->renderer()->isInline())) {
704 applyStyleIfNeeded(runStart, node);
707 node = node->traverseNextNode();
710 if (node ==
end.node())
712 node = node->traverseNextNode();
720bool ApplyStyleCommandImpl::isHTMLStyleNode(HTMLElementImpl *elem)
722 QListIterator<CSSProperty*> it(*(
style()->values()));
723 while (it.hasNext()) {
724 CSSProperty *
property = it.next();
725 switch (property->id()) {
726 case CSS_PROP_FONT_WEIGHT:
727 if (elem->id() == ID_B)
730 case CSS_PROP_FONT_STYLE:
731 if (elem->id() == ID_I)
740void ApplyStyleCommandImpl::removeHTMLStyleNode(HTMLElementImpl *elem)
750void ApplyStyleCommandImpl::removeCSSStyle(HTMLElementImpl *elem)
754 CSSStyleDeclarationImpl *decl = elem->inlineStyleDecls();
758 QListIterator<CSSProperty*> it(*(
style()->values()));
759 while ( it.hasNext() ) {
760 CSSProperty *
property = it.next();
761 if (decl->getPropertyCSSValue(property->id()))
765 if (elem->id() == ID_SPAN) {
769 NamedAttrMapImpl *map = elem->attributes();
770 if (map && (map->length() == 1 || (map->length() == 2 && elem->getAttribute(ATTR_STYLE).isEmpty())) &&
776void ApplyStyleCommandImpl::removeStyle(
const Position &start,
const Position &end)
778 NodeImpl *node = start.node();
780 NodeImpl *
next = node->traverseNextNode();
781 if (node->isHTMLElement() && nodeFullySelected(node)) {
782 HTMLElementImpl *elem =
static_cast<HTMLElementImpl *
>(node);
783 if (isHTMLStyleNode(elem))
784 removeHTMLStyleNode(elem);
786 removeCSSStyle(elem);
788 if (node ==
end.node())
794bool ApplyStyleCommandImpl::nodeFullySelected(
const NodeImpl *node)
const
800 if (node ==
end.node())
801 return end.offset() >= node->caretMaxOffset();
803 for (NodeImpl *child = node->lastChild(); child; child = child->lastChild()) {
804 if (child ==
end.node())
805 return end.offset() >= child->caretMaxOffset();
808 return node ==
end.node() || !node->isAncestor(
end.node());
814bool ApplyStyleCommandImpl::splitTextAtStartIfNeeded(
const Position &start,
const Position &end)
816 if (start.node()->isTextNode() && start.offset() > start.node()->caretMinOffset() && start.offset() < start.node()->caretMaxOffset()) {
818 kDebug() <<
"[split start]" << start.offset() << start.node()->caretMinOffset() << start.node()->caretMaxOffset() << endl;
820 long endOffsetAdjustment = start.node() ==
end.node() ? start.offset() : 0;
821 TextImpl *text =
static_cast<TextImpl *
>(start.node());
822 RefPtr<SplitTextNodeCommandImpl> cmd =
new SplitTextNodeCommandImpl(
document(), text, start.offset());
830NodeImpl *ApplyStyleCommandImpl::splitTextAtEndIfNeeded(
const Position &start,
const Position &end)
832 if (
end.node()->isTextNode() &&
end.offset() >
end.node()->caretMinOffset() &&
end.offset() <
end.node()->caretMaxOffset()) {
834 kDebug() <<
"[split end]" <<
end.offset() <<
end.node()->caretMinOffset() <<
end.node()->caretMaxOffset() << endl;
836 TextImpl *text =
static_cast<TextImpl *
>(
end.node());
837 RefPtr<SplitTextNodeCommandImpl> cmd =
new SplitTextNodeCommandImpl(
document(), text,
end.offset());
839 NodeImpl *startNode = start.node() ==
end.node() ? cmd->node()->previousSibling() : start.node();
841 setEndingSelection(Selection(Position(startNode, start.offset()), Position(cmd->node()->previousSibling(), cmd->node()->previousSibling()->caretMaxOffset())));
842 return cmd->node()->previousSibling();
847void ApplyStyleCommandImpl::surroundNodeRangeWithElement(NodeImpl *startNode, NodeImpl *endNode, ElementImpl *element)
853 NodeImpl *node = startNode;
855 NodeImpl *
next = node->traverseNextNode();
856 if (node->childNodeCount() == 0 && node->renderer() && node->renderer()->isInline()) {
868 QScopedPointer<CSSStyleDeclarationImpl> computedStyle(
869 element->document()->defaultView()->getComputedStyle(element, 0));
870 assert(!computedStyle.isNull());
872 kDebug() <<
"[check styling]" << element << endl;
875 QListIterator<CSSProperty*> it(*(style->values()));
876 while ( it.hasNext() ) {
877 CSSProperty *
property = it.next();
878 CSSValueImpl *computedValue = computedStyle->getPropertyCSSValue(property->id());
879 DOMString newValue =
property->value()->cssText();
881 kDebug() <<
"[new value]:" <<
property->cssText() << endl;
882 kDebug() <<
"[computedValue]:" << computedValue->cssText() << endl;
884 if (strcasecmp(computedValue->cssText(), newValue))
890void ApplyStyleCommandImpl::applyStyleIfNeeded(DOM::NodeImpl *startNode, DOM::NodeImpl *endNode)
892 ElementImpl *
parent = Position(startNode, 0).element();
895 ElementImpl *styleElement = 0;
896 if (
parent->id() == ID_SPAN &&
parent->firstChild() == startNode &&
parent->lastChild() == endNode) {
899 styleElement =
document()->createHTMLElement(
"SPAN");
902 surroundNodeRangeWithElement(startNode, endNode, styleElement);
907bool ApplyStyleCommandImpl::currentlyHasStyle(
const Position &pos,
const CSSProperty *property)
const
911 CSSStyleDeclarationImpl *decl =
document()->defaultView()->getComputedStyle(pos.element(), 0);
913 CSSValueImpl *value = decl->getPropertyCSSValue(property->id());
914 return strcasecmp(value->cssText(), property->value()->cssText()) == 0;
917ApplyStyleCommandImpl::StyleChange ApplyStyleCommandImpl::computeStyleChange(
const Position &insertionPoint, CSSStyleDeclarationImpl *style)
919 assert(insertionPoint.notEmpty());
922 StyleChange styleChange;
924 QListIterator<CSSProperty*> it(*(
style->values()));
925 while ( it.hasNext() ) {
926 CSSProperty *
property = it.next();
928 kDebug() <<
"[CSS property]:" <<
property->cssText() << endl;
930 if (!currentlyHasStyle(insertionPoint, property)) {
932 kDebug() <<
"[Add to style change]" << endl;
934 switch (property->id()) {
935 case CSS_PROP_FONT_WEIGHT:
936 if (
strcasecmp(property->value()->cssText(),
"bold") == 0)
937 styleChange.applyBold =
true;
939 styleChange.cssStyle +=
property->cssText();
941 case CSS_PROP_FONT_STYLE: {
942 DOMString cssText(property->value()->cssText());
944 styleChange.applyItalic =
true;
946 styleChange.cssStyle +=
property->cssText();
950 styleChange.cssStyle +=
property->cssText();
958Position ApplyStyleCommandImpl::positionInsertionPoint(Position pos)
960 if (pos.node()->isTextNode() && (pos.offset() > 0 && pos.offset() < pos.node()->maxOffset())) {
961 RefPtr<SplitTextNodeCommandImpl> split =
new SplitTextNodeCommandImpl(
document(),
static_cast<TextImpl *
>(pos.node()), pos.offset());
963 pos = Position(split->node(), 0);
971 if (currentlyHasStyle(pos))
975 if (pos.offset() >= pos.node()->caretMaxOffset()) {
976 NodeImpl *nextNode = pos.node()->traverseNextNode();
978 Position
next = Position(nextNode, 0);
979 if (currentlyHasStyle(next))
985 if (pos.offset() <= pos.node()->caretMinOffset()) {
986 NodeImpl *prevNode = pos.node()->traversePreviousNode();
988 Position prev = Position(prevNode, prevNode->maxOffset());
989 if (currentlyHasStyle(prev))
1002 : CompositeEditCommandImpl(document), m_charactersDeleted(0), m_hasSelectionToCollapse(false)
1006DeleteCollapsibleWhitespaceCommandImpl::DeleteCollapsibleWhitespaceCommandImpl(DocumentImpl *document,
const Selection &selection)
1007 : CompositeEditCommandImpl(document), m_charactersDeleted(0), m_selectionToCollapse(selection), m_hasSelectionToCollapse(true)
1011DeleteCollapsibleWhitespaceCommandImpl::~DeleteCollapsibleWhitespaceCommandImpl()
1017 if (!pos.node()->isTextNode())
1020 RenderObject *renderer = pos.node()->renderer();
1024 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
1025 if (pos.offset() >= (long)textNode->length())
1028 if (pos.isLastRenderedPositionInEditableBlock())
1031 if (pos.isFirstRenderedPositionOnLine() || pos.isLastRenderedPositionOnLine())
1048Position DeleteCollapsibleWhitespaceCommandImpl::deleteWhitespace(
const Position &pos)
1050 Position upstream = pos.equivalentUpstreamPosition();
1051 Position downstream = pos.equivalentDownstreamPosition();
1052#ifdef DEBUG_COMMANDS
1053 kDebug() <<
"[pos]" << pos << endl;
1054 kDebug() <<
"[upstream:downstream]" << upstream << downstream << endl;
1055 printEnclosingBlockTree(pos.node());
1058 bool del = shouldDeleteUpstreamPosition(upstream);
1059#ifdef DEBUG_COMMANDS
1060 kDebug() <<
"[delete upstream]" <<
del << endl;
1063 if (upstream == downstream)
1066#ifdef DEBUG_COMMANDS
1067 PositionIterator iter(upstream);
1068 kDebug() <<
"[before print]" << endl;
1069 for (iter.next(); iter.current() != downstream; iter.next())
1070 kDebug() <<
"[iterate]" << iter.current() << endl;
1071 kDebug() <<
"[after print]" << endl;
1074 PositionIterator it(upstream);
1075 Position deleteStart = upstream;
1077 deleteStart = it.peekNext();
1078 if (deleteStart == downstream)
1082 Position endingPosition = upstream;
1084 while (it.current() != downstream) {
1085 Position
next = it.peekNext();
1086#ifdef DEBUG_COMMANDS
1087 kDebug() <<
"[iterate and delete]" <<
next << endl;
1089 if (
next.node() != deleteStart.node()) {
1091 if (deleteStart.node()->isTextNode()) {
1092 TextImpl *textNode =
static_cast<TextImpl *
>(deleteStart.node());
1093 unsigned long count = it.current().offset() - deleteStart.offset();
1094 if (count == textNode->length()) {
1095#ifdef DEBUG_COMMANDS
1096 kDebug(6200) <<
" removeNodeAndPrune 1:" << textNode;
1098 if (textNode == endingPosition.node())
1099 endingPosition = Position(
next.node(),
next.node()->caretMinOffset());
1100 removeNodeAndPrune(textNode);
1102#ifdef DEBUG_COMMANDS
1103 kDebug(6200) <<
" deleteText 1:" << textNode <<
"t len:" << textNode->length()<<
"start:" << deleteStart.offset() <<
"del len:" << (it.current().offset() - deleteStart.offset());
1105 deleteText(textNode, deleteStart.offset(), count);
1108#ifdef DEBUG_COMMANDS
1109 kDebug() <<
"[not text node is not supported yet]" << endl;
1113 }
else if (next == downstream) {
1114 assert(deleteStart.node() == downstream.node());
1115 assert(downstream.node()->isTextNode());
1116 TextImpl *textNode =
static_cast<TextImpl *
>(deleteStart.node());
1117 unsigned long count = downstream.offset() - deleteStart.offset();
1118 assert(count <= textNode->length());
1119 if (count == textNode->length()) {
1120#ifdef DEBUG_COMMANDS
1121 kDebug(6200) <<
" removeNodeAndPrune 2:"<<textNode;
1123 removeNodeAndPrune(textNode);
1125#ifdef DEBUG_COMMANDS
1126 kDebug(6200) <<
" deleteText 2:"<< textNode<<
"t len:" << textNode->length() <<
"start:" <<deleteStart.offset() <<
"del len:" << count;
1128 deleteText(textNode, deleteStart.offset(), count);
1129 m_charactersDeleted = count;
1130 endingPosition = Position(downstream.node(), downstream.offset() - m_charactersDeleted);
1134 it.setPosition(next);
1137 return endingPosition;
1140void DeleteCollapsibleWhitespaceCommandImpl::doApply()
1144 if (!m_hasSelectionToCollapse)
1145 m_selectionToCollapse = endingSelection();
1146 int state = m_selectionToCollapse.state();
1147 if (state == Selection::CARET) {
1148 Position endPosition = deleteWhitespace(m_selectionToCollapse.start());
1149 setEndingSelection(endPosition);
1150#ifdef DEBUG_COMMANDS
1151 kDebug(6200) <<
"-----------------------------------------------------";
1154 else if (state == Selection::RANGE) {
1155 Position startPosition = deleteWhitespace(m_selectionToCollapse.start());
1156#ifdef DEBUG_COMMANDS
1157 kDebug(6200) <<
"-----------------------------------------------------";
1159 Position endPosition = m_selectionToCollapse.end();
1160 if (m_charactersDeleted > 0 && startPosition.node() == endPosition.node()) {
1161#ifdef DEBUG_COMMANDS
1162 kDebug(6200) <<
"adjust end position by" << m_charactersDeleted;
1164 endPosition = Position(endPosition.node(), endPosition.offset() - m_charactersDeleted);
1166 endPosition = deleteWhitespace(endPosition);
1167 setEndingSelection(Selection(startPosition, endPosition));
1168#ifdef DEBUG_COMMANDS
1169 kDebug(6200) <<
"=====================================================";
1177DeleteSelectionCommandImpl::DeleteSelectionCommandImpl(DocumentImpl *document)
1183 : CompositeEditCommandImpl(document), m_selectionToDelete(selection), m_hasSelectionToDelete(true)
1191void DeleteSelectionCommandImpl::joinTextNodesWithSameStyle()
1195 if (selection.state() != Selection::CARET)
1198 Position pos(selection.start());
1200 if (!pos.node()->isTextNode())
1203 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
1205 if (pos.offset() == 0) {
1206 PositionIterator it(pos);
1207 Position prev = it.previous();
1210 if (prev.node()->isTextNode()) {
1211 TextImpl *prevTextNode =
static_cast<TextImpl *
>(prev.node());
1215#ifdef DEBUG_COMMANDS
1216 kDebug(6200) <<
"joinTextNodesWithSameStyle [1]";
1220 }
else if (pos.offset() == (
long)textNode->length()) {
1221 PositionIterator it(pos);
1222 Position
next = it.next();
1225 if (
next.node()->isTextNode()) {
1226 TextImpl *nextTextNode =
static_cast<TextImpl *
>(
next.node());
1230#ifdef DEBUG_COMMANDS
1231 kDebug(6200) <<
"joinTextNodesWithSameStyle [2]";
1238bool DeleteSelectionCommandImpl::containsOnlyWhitespace(
const Position &start,
const Position &end)
1242 PositionIterator it(start);
1243 while (!it.atEnd()) {
1244 if (!it.current().node()->isTextNode())
1246 const DOMString &text =
static_cast<TextImpl *
>(it.current().node())->data();
1248 if (text.
length() > INT_MAX)
1250 if (it.current().offset() < (int)text.
length() && !
isWS(text[it.current().offset()]))
1253 if (it.current() ==
end)
1259void DeleteSelectionCommandImpl::deleteContentInsideNode(NodeImpl *node,
int startOffset,
int endOffset)
1261#ifdef DEBUG_COMMANDS
1262 kDebug() <<
"[Delete content inside node]" << node << startOffset << endOffset << endl;
1264 if (node->isTextNode()) {
1266 if (startOffset == endOffset)
1269 if (!startOffset && endOffset == node->maxOffset()) {
1274 deleteText(
static_cast<TextImpl*
>(node), startOffset, endOffset - startOffset);
1277#ifdef DEBUG_COMMANDS
1278 kDebug() <<
"[non-text node] not supported" << endl;
1282void DeleteSelectionCommandImpl::deleteContentBeforeOffset(NodeImpl *node,
int offset)
1284 deleteContentInsideNode(node, 0, offset);
1287void DeleteSelectionCommandImpl::deleteContentAfterOffset(NodeImpl *node,
int offset)
1289 if (node->isTextNode())
1290 deleteContentInsideNode(node, offset, node->maxOffset());
1297 if (!m_hasSelectionToDelete)
1300 if (m_selectionToDelete.state() != Selection::RANGE)
1306 Position upstreamStart(selection.start().equivalentUpstreamPosition());
1307 Position downstreamStart(selection.start().equivalentDownstreamPosition());
1308 Position upstreamEnd(selection.end().equivalentUpstreamPosition());
1309 Position downstreamEnd(selection.end().equivalentDownstreamPosition());
1311 NodeImpl *startBlock = upstreamStart.node()->enclosingBlockFlowElement();
1312 NodeImpl *endBlock = downstreamEnd.node()->enclosingBlockFlowElement();
1314#ifdef DEBUG_COMMANDS
1315 kDebug() <<
"[Delete:Start]" << upstreamStart << downstreamStart << endl;
1316 kDebug() <<
"[Delete:End]" << upstreamEnd << downstreamEnd << endl;
1317 printEnclosingBlockTree(upstreamStart.node());
1319 if (startBlock != endBlock)
1320 printEnclosingBlockTree(downstreamEnd.node());
1322 if (upstreamStart == downstreamEnd)
1327 if (upstreamStart.node() != downstreamEnd.node()) {
1328 NodeImpl *node, *
next;
1329 for (node = upstreamStart.node()->traverseNextNode(); node && node != downstreamEnd.node(); node =
next) {
1330#ifdef DEBUG_COMMANDS
1331 kDebug() <<
"[traverse and delete]" << node << (node->renderer() && node->renderer()->isEditable()) << endl;
1333 next = node->traverseNextNode();
1334 if (node->renderer() && node->renderer()->isEditable())
1340 if (startBlock != endBlock && startBlock->parentNode() == endBlock->parentNode()) {
1341 NodeImpl *node = endBlock->firstChild();
1343 NodeImpl *moveNode = node;
1344 node = node->nextSibling();
1350 if (upstreamStart.node() == downstreamEnd.node())
1351 deleteContentInsideNode(upstreamEnd.node(), upstreamStart.offset(), downstreamEnd.offset());
1353 deleteContentAfterOffset(upstreamStart.node(), upstreamStart.offset());
1354 deleteContentBeforeOffset(downstreamEnd.node(), downstreamEnd.offset());
1359 Position endingPosition;
1360 bool adjustEndingPositionDownstream =
false;
1362 bool onlyWhitespace = containsOnlyWhitespace(upstreamStart, downstreamEnd);
1363 kDebug() <<
"[OnlyWhitespace]" << onlyWhitespace << endl;
1365 bool startCompletelySelected = !onlyWhitespace &&
1366 (downstreamStart.offset() <= downstreamStart.node()->caretMinOffset() &&
1367 ((downstreamStart.node() != upstreamEnd.node()) ||
1368 (upstreamEnd.offset() >= upstreamEnd.node()->caretMaxOffset())));
1370 bool endCompletelySelected = !onlyWhitespace &&
1371 (upstreamEnd.offset() >= upstreamEnd.node()->caretMaxOffset() &&
1372 ((downstreamStart.node() != upstreamEnd.node()) ||
1373 (downstreamStart.offset() <= downstreamStart.node()->caretMinOffset())));
1375 kDebug() <<
"[{start:end}CompletelySelected]" << startCompletelySelected << endCompletelySelected << endl;
1377 unsigned long startRenderedOffset = downstreamStart.renderedOffset();
1379 bool startAtStartOfRootEditableElement = startRenderedOffset == 0 && downstreamStart.inFirstEditableInRootEditableElement();
1380 bool startAtStartOfBlock = startAtStartOfRootEditableElement ||
1381 (startRenderedOffset == 0 && downstreamStart.inFirstEditableInContainingEditableBlock());
1382 bool endAtEndOfBlock = downstreamEnd.isLastRenderedPositionInEditableBlock();
1384 kDebug() <<
"[startAtStartOfRootEditableElement]" << startAtStartOfRootEditableElement << endl;
1385 kDebug() <<
"[startAtStartOfBlock]" << startAtStartOfBlock << endl;
1386 kDebug() <<
"[endAtEndOfBlock]" << endAtEndOfBlock << endl;
1388 NodeImpl *startBlock = upstreamStart.node()->enclosingBlockFlowElement();
1389 NodeImpl *endBlock = downstreamEnd.node()->enclosingBlockFlowElement();
1390 bool startBlockEndBlockAreSiblings = startBlock->parentNode() == endBlock->parentNode();
1392 kDebug() <<
"[startBlockEndBlockAreSiblings]" << startBlockEndBlockAreSiblings << startBlock << endBlock << endl;
1394 debugPosition(
"upstreamStart: ", upstreamStart);
1395 debugPosition(
"downstreamStart: ", downstreamStart);
1396 debugPosition(
"upstreamEnd: ", upstreamEnd);
1397 debugPosition(
"downstreamEnd: ", downstreamEnd);
1398 kDebug(6200) <<
"start selected:" << (startCompletelySelected ?
"YES" :
"NO");
1399 kDebug(6200) <<
"at start block:" << (startAtStartOfBlock ?
"YES" :
"NO");
1400 kDebug(6200) <<
"at start root block:"<< (startAtStartOfRootEditableElement ?
"YES" :
"NO");
1401 kDebug(6200) <<
"at end block:"<< (endAtEndOfBlock ?
"YES" :
"NO");
1402 kDebug(6200) <<
"only whitespace:"<< (onlyWhitespace ?
"YES" :
"NO");
1405 if (startAtStartOfBlock) {
1406 kDebug(6200) <<
"ending position case 1";
1407 endingPosition = Position(startBlock, 0);
1408 adjustEndingPositionDownstream =
true;
1409 }
else if (!startCompletelySelected) {
1410 kDebug(6200) <<
"ending position case 2";
1411 endingPosition = upstreamEnd;
1412 if (upstreamStart.node()->id() == ID_BR && upstreamStart.offset() == 1)
1413 adjustEndingPositionDownstream =
true;
1414 }
else if (upstreamStart != downstreamStart) {
1415 kDebug(6200) <<
"ending position case 3";
1416 endingPosition = upstreamStart;
1417 if (upstreamStart.node()->id() == ID_BR && upstreamStart.offset() == 1)
1418 adjustEndingPositionDownstream =
true;
1424 if ((startAtStartOfBlock && !endAtEndOfBlock) || (!startCompletelySelected && adjustEndingPositionDownstream)) {
1427 if (trailing.notEmpty()) {
1428 debugPosition(
"convertTrailingWhitespace: ", trailing);
1429 Position collapse = trailing.nextCharacterPosition();
1430 if (collapse != trailing)
1432 TextImpl *textNode =
static_cast<TextImpl *
>(trailing.node());
1435 }
else if (!startAtStartOfBlock && endAtEndOfBlock) {
1438 if (leading.notEmpty()) {
1439 debugPosition(
"convertLeadingWhitespace: ", leading);
1440 TextImpl *textNode =
static_cast<TextImpl *
>(leading.node());
1443 }
else if (!startAtStartOfBlock && !endAtEndOfBlock) {
1447 if (leading.notEmpty() && trailing.notEmpty()) {
1448 debugPosition(
"convertLeadingWhitespace [contiguous]: ", leading);
1449 TextImpl *textNode =
static_cast<TextImpl *
>(leading.node());
1457 NodeImpl *n = downstreamStart.node()->traverseNextNode();
1458 kDebug() <<
"[n]" << n << endl;
1461 if (startCompletelySelected) {
1462 kDebug(6200) <<
"start node delete case 1";
1464 }
else if (onlyWhitespace) {
1468 kDebug(6200) <<
"start node delete case 2";
1469 assert(upstreamStart.node()->isTextNode());
1470 TextImpl *text =
static_cast<TextImpl *
>(upstreamStart.node());
1471 int offset = upstreamStart.offset();
1473 int length = text->
length();
1474 if (length == upstreamStart.offset())
1477 }
else if (downstreamStart.node()->isTextNode()) {
1478 kDebug(6200) <<
"start node delete case 3";
1479 TextImpl *text =
static_cast<TextImpl *
>(downstreamStart.node());
1480 int endOffset = text == upstreamEnd.node() ? upstreamEnd.offset() : text->
length();
1481 if (endOffset > downstreamStart.offset()) {
1482 deleteText(text, downstreamStart.offset(), endOffset - downstreamStart.offset());
1487 kDebug(6200) <<
"start node delete case 4";
1488 assert(downstreamStart.offset() == 1);
1491 if (n && !onlyWhitespace && downstreamStart.node() != upstreamEnd.node()) {
1493 while (n && n != upstreamEnd.node()) {
1495 n = n->traverseNextNode();
1496 if (
d->renderer() &&
d->renderer()->isEditable())
1503 assert(n == upstreamEnd.node());
1504 if (endCompletelySelected) {
1507 else if (upstreamEnd.node()->isTextNode()) {
1508 if (upstreamEnd.offset() > 0) {
1509 TextImpl *text =
static_cast<TextImpl *
>(upstreamEnd.node());
1516 assert(downstreamStart.offset() == 0);
1525 if (startBlock != endBlock && startBlockEndBlockAreSiblings) {
1526 kDebug(6200) <<
"merging content to start block";
1527 NodeImpl *node = endBlock->firstChild();
1529 NodeImpl *moveNode = node;
1530 node = node->nextSibling();
1536 if (adjustEndingPositionDownstream) {
1537 kDebug(6200) <<
"adjust ending position downstream";
1538 endingPosition = endingPosition.equivalentDownstreamPosition();
1541 debugPosition(
"ending position: ", endingPosition);
1544 kDebug(6200) <<
"-----------------------------------------------------";
1552 :
EditCommandImpl(document), m_node(node), m_offset(offset), m_count(count)
1571 int exceptionCode = 0;
1572 m_text = m_node->substringData(m_offset, m_count, exceptionCode);
1573 assert(exceptionCode == 0);
1575 m_node->deleteData(m_offset, m_count, exceptionCode);
1576 assert(exceptionCode == 0);
1584 int exceptionCode = 0;
1585 m_node->insertData(m_offset, m_text, exceptionCode);
1586 assert(exceptionCode == 0);
1601void InputNewlineCommandImpl::insertNodeAfterPosition(NodeImpl *node,
const Position &pos)
1606 Position upstream(pos.equivalentUpstreamPosition());
1607 NodeImpl *cb = pos.node()->enclosingBlockFlowElement();
1608 if (cb == pos.node())
1614void InputNewlineCommandImpl::insertNodeBeforePosition(NodeImpl *node,
const Position &pos)
1619 Position upstream(pos.equivalentUpstreamPosition());
1620 NodeImpl *cb = pos.node()->enclosingBlockFlowElement();
1621 if (cb == pos.node())
1631 int exceptionCode = 0;
1633 NodeImpl *enclosingBlock = selection.start().node()->enclosingBlockFlowElement();
1634 kDebug() << enclosingBlock->nodeName() << endl;
1635 if (enclosingBlock->id() == ID_LI) {
1640#ifdef DEBUG_COMMANDS
1641 kDebug() <<
"[insert new list item]" << selection << endl;
1642 printEnclosingBlockTree(selection.start().node());
1644 Position pos(selection.start().equivalentDownstreamPosition());
1645 NodeImpl *node = pos.node();
1646 bool atBlockStart = pos.atStartOfContainingEditableBlock();
1647 bool atBlockEnd = pos.isLastRenderedPositionInEditableBlock();
1649 if (node->isTextNode() && !atBlockStart && !atBlockEnd) {
1650 TextImpl *textNode =
static_cast<TextImpl*
>(node);
1651 TextImpl *textBeforeNode =
document()->createTextNode(textNode->substringData(0, selection.start().offset(), exceptionCode));
1654 pos = Position(textNode, 0);
1659#ifdef DEBUG_COMMANDS
1660 kDebug() <<
"[handle node]" << node << endl;
1661 printEnclosingBlockTree(enclosingBlock->parent());
1665 RefPtr<NodeImpl> newParent =
parent->cloneNode(
false);
1667 for (NodeImpl *nextSibling = 0; node; node = nextSibling) {
1668#ifdef DEBUG_COMMANDS
1669 kDebug() <<
"[reattach sibling]" << node << endl;
1671 nextSibling = node->nextSibling();
1675 node = newParent.get();
1676 if (
parent == enclosingBlock)
1679 }
else if (node->isTextNode()) {
1682 ElementImpl *listItem =
document()->createHTMLElement(
"LI");
1685 ElementImpl *listItem =
document()->createHTMLElement(
"LI");
1690#ifdef DEBUG_COMMANDS
1691 kDebug() <<
"[result]" << endl;
1692 printEnclosingBlockTree(enclosingBlock->parent());
1698 ElementImpl *breakNode =
document()->createHTMLElement(
"BR");
1701#ifdef DEBUG_COMMANDS
1702 kDebug() <<
"[insert break]" << selection << endl;
1703 printEnclosingBlockTree(enclosingBlock);
1706 NodeImpl *nodeToInsert = breakNode;
1708 if (
document()->part()->editor()->typingStyle()) {
1709 int exceptionCode = 0;
1711 styleElement->appendChild(breakNode, exceptionCode);
1712 assert(exceptionCode == 0);
1713 nodeToInsert = styleElement;
1716 Position pos(selection.start().equivalentDownstreamPosition());
1717 bool atStart = pos.offset() <= pos.node()->caretMinOffset();
1718 bool atEndOfBlock = pos.isLastRenderedPositionInEditableBlock();
1720#ifdef DEBUG_COMMANDS
1721 kDebug() <<
"[pos]" << pos << atStart << atEndOfBlock << endl;
1725#ifdef DEBUG_COMMANDS
1726 kDebug(6200) <<
"input newline case 1";
1731 insertNodeAfterPosition(nodeToInsert, pos);
1733 ElementImpl *extraBreakNode =
document()->createHTMLElement(
"BR");
1737 }
else if (atStart) {
1738#ifdef DEBUG_COMMANDS
1739 kDebug(6200) <<
"input newline case 2";
1744 insertNodeBeforePosition(nodeToInsert, pos);
1750#ifdef DEBUG_COMMANDS
1751 kDebug(6200) <<
"input newline case 3";
1753 assert(pos.node()->isTextNode());
1754 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
1755 TextImpl *textBeforeNode =
document()->createTextNode(textNode->substringData(0, selection.start().offset(), exceptionCode));
1756 deleteText(textNode, 0, selection.start().offset());
1790 if (!selection.start().node()->isTextNode())
1793 int exceptionCode = 0;
1794 int offset = selection.start().offset() - 1;
1795 if (offset >= selection.start().node()->caretMinOffset()) {
1796 TextImpl *textNode =
static_cast<TextImpl *
>(selection.start().node());
1797 textNode->deleteData(offset, 1, exceptionCode);
1798 assert(exceptionCode == 0);
1799 selection = Selection(Position(textNode, offset));
1801 m_charactersAdded--;
1805Position InputTextCommandImpl::prepareForTextInsertion(
bool adjustDownstream)
1810 assert(selection.state() == Selection::CARET);
1812#ifdef DEBUG_COMMANDS
1813 kDebug() <<
"[prepare selection]" << selection << endl;
1816 Position pos = selection.start();
1817 if (adjustDownstream)
1818 pos = pos.equivalentDownstreamPosition();
1820 pos = pos.equivalentUpstreamPosition();
1822#ifdef DEBUG_COMMANDS
1823 kDebug() <<
"[prepare position]" << pos << endl;
1826 if (!pos.node()->isTextNode()) {
1827 NodeImpl *textNode =
document()->createEditingTextNode(
"");
1828 NodeImpl *nodeToInsert = textNode;
1829 if (
document()->part()->editor()->typingStyle()) {
1830 int exceptionCode = 0;
1832 styleElement->appendChild(textNode, exceptionCode);
1833 assert(exceptionCode == 0);
1834 nodeToInsert = styleElement;
1838 if (pos.node()->isEditableBlock()) {
1839 kDebug(6200) <<
"prepareForTextInsertion case 1";
1841 }
else if (pos.node()->id() == ID_BR && pos.offset() == 1) {
1842 kDebug(6200) <<
"prepareForTextInsertion case 2";
1844 }
else if (pos.node()->caretMinOffset() == pos.offset()) {
1845 kDebug(6200) <<
"prepareForTextInsertion case 3";
1847 }
else if (pos.node()->caretMaxOffset() == pos.offset()) {
1848 kDebug(6200) <<
"prepareForTextInsertion case 4";
1853 pos = Position(textNode, 0);
1856 if (
document()->part()->editor()->typingStyle()) {
1857 if (pos.node()->isTextNode() && pos.offset() > pos.node()->caretMinOffset() && pos.offset() < pos.node()->caretMaxOffset()) {
1859 TextImpl *text =
static_cast<TextImpl *
>(pos.node());
1860 RefPtr<SplitTextNodeCommandImpl> cmd =
new SplitTextNodeCommandImpl(
document(), text, pos.offset());
1865 int exceptionCode = 0;
1866 TextImpl *editingTextNode =
document()->createEditingTextNode(
"");
1869 styleElement->appendChild(editingTextNode, exceptionCode);
1870 assert(exceptionCode == 0);
1877 pos = Position(editingTextNode, 0);
1883void InputTextCommandImpl::execute(
const DOMString &text)
1885#ifdef DEBUG_COMMANDS
1886 kDebug() <<
"[execute command]" << text << endl;
1889#ifdef DEBUG_COMMANDS
1890 kDebug() <<
"[ending selection]" << selection << endl;
1892 bool adjustDownstream = selection.start().isFirstRenderedPositionOnLine();
1893#ifdef DEBUG_COMMANDS
1894 kDebug() <<
"[adjust]" << adjustDownstream << endl;
1897#ifdef DEBUG_COMMANDS
1898 printEnclosingBlockTree(selection.start().node());
1902 if (selection.state() == Selection::RANGE)
1907#ifdef DEBUG_COMMANDS
1908 kDebug() <<
"[after collapsible whitespace deletion]" << endl;
1909 printEnclosingBlockTree(selection.start().node());
1915 Position pos = prepareForTextInsertion(adjustDownstream);
1916#ifdef DEBUG_COMMANDS
1917 kDebug() <<
"[after prepare]" << pos << endl;
1920 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
1921 long offset = pos.offset();
1923#ifdef DEBUG_COMMANDS
1924 kDebug() <<
"[insert at]" << textNode << offset << endl;
1931 insertSpace(textNode, offset);
1933 const DOMString &existingText = textNode->data();
1934 if (textNode->length() >= 2 && offset >= 2 &&
isNBSP(existingText[offset - 1]) && !
isWS(existingText[offset - 2])) {
1946 m_charactersAdded += text.
length();
1949void InputTextCommandImpl::insertSpace(TextImpl *textNode,
unsigned long offset)
1959 for (
unsigned int i = offset; i < text.
length(); i++) {
1968 Position pos(textNode, offset);
1969 Position downstream = pos.equivalentDownstreamPosition();
1970 if (downstream.offset() < (
long)text.
length() &&
isWS(text[downstream.offset()]))
1976 if (offset > 0 && offset <= text.
length() - 1 && !
isWS(text[offset]) && !
isWS(text[offset - 1])) {
1982 if (text.
length() >= 2 && offset >= 2 &&
isNBSP(text[offset - 2]) &&
isNBSP(text[offset - 1])) {
1998 :
EditCommandImpl(document), m_insertChild(insertChild), m_refChild(refChild)
2001 m_insertChild->ref();
2010 m_insertChild->deref();
2012 m_refChild->deref();
2019 assert(m_refChild->parentNode());
2021 int exceptionCode = 0;
2022 m_refChild->parentNode()->insertBefore(m_insertChild, m_refChild, exceptionCode);
2023 assert(exceptionCode == 0);
2030 assert(m_refChild->parentNode());
2032 int exceptionCode = 0;
2033 m_refChild->parentNode()->removeChild(m_insertChild, exceptionCode);
2034 assert(exceptionCode == 0);
2062 int exceptionCode = 0;
2063 m_node->insertData(m_offset, m_text, exceptionCode);
2064 assert(exceptionCode == 0);
2072 int exceptionCode = 0;
2073 m_node->deleteData(m_offset, m_text.
length(), exceptionCode);
2074 assert(exceptionCode == 0);
2085 assert(m_text1->nextSibling() == m_text2);
2086 assert(m_text1->length() > 0);
2087 assert(m_text2->length() > 0);
2105 assert(m_text1->nextSibling() == m_text2);
2107 int exceptionCode = 0;
2108 m_text2->insertData(0, m_text1->data(), exceptionCode);
2109 assert(exceptionCode == 0);
2111 m_text2->parentNode()->removeChild(m_text1, exceptionCode);
2112 assert(exceptionCode == 0);
2114 m_offset = m_text1->length();
2122 int exceptionCode = 0;
2124 m_text2->deleteData(0, m_offset, exceptionCode);
2125 assert(exceptionCode == 0);
2127 m_text2->parentNode()->insertBefore(m_text1, m_text2, exceptionCode);
2128 assert(exceptionCode == 0);
2130 assert(m_text2->previousSibling()->isTextNode());
2131 assert(m_text2->previousSibling() == m_text1);
2148 NodeImpl *firstChild = m_fragment->firstChild();
2149 NodeImpl *lastChild = m_fragment->lastChild();
2154 if (selection.state() == Selection::RANGE)
2160 assert(!selection.isEmpty());
2165 }
else if (firstChild == lastChild && firstChild->isTextNode()) {
2167 Position base = selection.base();
2168 inputText(
static_cast<TextImpl *
>(firstChild)->data());
2169 if (m_selectReplacement) {
2175 NodeImpl *beforeNode = firstChild;
2176 NodeImpl *node = firstChild->nextSibling();
2178 insertNodeAt(firstChild, selection.start().node(), selection.start().offset());
2182 NodeImpl *
next = node->nextSibling();
2190 NodeImpl *lastLeaf = lastChild;
2192 NodeImpl *nextChild = lastLeaf->lastChild();
2195 lastLeaf = nextChild;
2198 if (m_selectReplacement) {
2200 NodeImpl *firstLeaf = firstChild;
2202 NodeImpl *nextChild = firstLeaf->firstChild();
2205 firstLeaf = nextChild;
2208 setEndingSelection(Selection(Position(firstLeaf, firstLeaf->caretMinOffset()), Position(lastLeaf, lastLeaf->caretMaxOffset())));
2231 assert(selection.state() == Selection::RANGE);
2234 NodeImpl *positionNode = m_position.node();
2235 long positionOffset = m_position.offset();
2236 Position selectionEnd = selection.end();
2237 long selectionEndOffset = selectionEnd.offset();
2238 if (selectionEnd.node() == positionNode && selectionEndOffset < positionOffset) {
2239 positionOffset -= selectionEndOffset;
2240 Position selectionStart = selection.start();
2241 if (selectionStart.node() == positionNode) {
2242 positionOffset += selectionStart.offset();
2257 :
EditCommandImpl(document), m_decl(decl), m_property(property), m_important(false)
2273 m_oldValue = m_decl->getPropertyValue(m_property);
2276 m_important = m_decl->getPropertyPriority(m_property);
2277 m_decl->removeProperty(m_property);
2285 m_decl->setProperty(m_property, m_oldValue, m_important);
2292 :
EditCommandImpl(document), m_element(element), m_attribute(attribute)
2308 m_oldValue = m_element->getAttribute(m_attribute);
2311 int exceptionCode = 0;
2312 m_element->removeAttribute(m_attribute, exceptionCode);
2313 assert(exceptionCode == 0);
2322 m_element->setAttribute(m_attribute, m_oldValue.
implementation());
2330 :
EditCommandImpl(document), m_parent(0), m_removeChild(removeChild), m_refChild(0)
2333 m_removeChild->ref();
2335 m_parent = m_removeChild->parentNode();
2339 RefPtr<DOM::NodeListImpl> children = m_parent->childNodes();
2340 for (
long i = children->length() - 1; i >= 0; --i) {
2341 NodeImpl *
node = children->item(i);
2342 if (
node == m_removeChild)
2356 m_removeChild->deref();
2358 m_refChild->deref();
2366 int exceptionCode = 0;
2367 m_parent->removeChild(m_removeChild, exceptionCode);
2368 assert(exceptionCode == 0);
2376 int exceptionCode = 0;
2378 m_parent->insertBefore(m_removeChild, m_refChild, exceptionCode);
2380 m_parent->appendChild(m_removeChild, exceptionCode);
2381 assert(exceptionCode == 0);
2398 m_pruneNode->deref();
2400 m_stopNode->deref();
2405 NodeImpl *editableBlock = m_pruneNode->enclosingBlockFlowElement();
2407 NodeImpl *node =
pruneNode->traversePreviousNode();
2410 if (node == m_stopNode || editableBlock != node->enclosingBlockFlowElement() || !
shouldPruneNode(node))
2413 node = node->traversePreviousNode();
2436 RefPtr<DOM::NodeListImpl> children =
node()->childNodes();
2437 const unsigned int length = children->length();
2438 for (
unsigned int i = 0; i < length; ++i) {
2439 NodeImpl *child = children->item(0);
2450 :
EditCommandImpl(document), m_element(element), m_attribute(attribute), m_value(value)
2469 m_oldValue = m_element->getAttribute(m_attribute);
2480 m_element->setAttribute(m_attribute, m_oldValue.
implementation());
2488 :
EditCommandImpl(document), m_text1(0), m_text2(text), m_offset(offset)
2491 assert(m_text2->length() > 0);
2509 int exceptionCode = 0;
2518 m_text1 =
document()->createTextNode(m_text2->substringData(0, m_offset, exceptionCode));
2519 assert(exceptionCode == 0);
2524 m_text2->deleteData(0, m_offset, exceptionCode);
2525 assert(exceptionCode == 0);
2527 m_text2->parentNode()->insertBefore(m_text1, m_text2, exceptionCode);
2528 assert(exceptionCode == 0);
2530 assert(m_text2->previousSibling()->isTextNode());
2531 assert(m_text2->previousSibling() == m_text1);
2539 assert(m_text1->nextSibling() == m_text2);
2541 int exceptionCode = 0;
2542 m_text2->insertData(0, m_text1->data(), exceptionCode);
2543 assert(exceptionCode == 0);
2545 m_text2->parentNode()->removeChild(m_text1, exceptionCode);
2546 assert(exceptionCode == 0);
2548 m_offset = m_text1->length();
2567void TypingCommandImpl::typingAddedToOpenCommand()
2571 document()->part()->editor()->appliedEditing(
this);
2576 if (
document()->part()->editor()->typingStyle() ||
m_cmds.count() == 0) {
2590 typingAddedToOpenCommand();
2597 typingAddedToOpenCommand();
2600void TypingCommandImpl::issueCommandForDeleteKey()
2603 assert(selectionToDelete.state() != Selection::NONE);
2605#ifdef DEBUG_COMMANDS
2606 kDebug() <<
"[selection]" << selectionToDelete << endl;
2608 if (selectionToDelete.state() == Selection::CARET) {
2609#ifdef DEBUG_COMMANDS
2610 kDebug() <<
"[caret selection]" << endl;
2612 Position pos(selectionToDelete.start());
2613 if (pos.inFirstEditableInRootEditableElement() && pos.offset() <= pos.node()->caretMinOffset()) {
2617 selectionToDelete = Selection(pos.previousCharacterPosition(), pos);
2618#ifdef DEBUG_COMMANDS
2619 kDebug() <<
"[modified selection]" << selectionToDelete << endl;
2623 typingAddedToOpenCommand();
2636 issueCommandForDeleteKey();
2638 if (
m_cmds.count() == 0) {
2639 issueCommandForDeleteKey();
2642 EditCommand lastCommand =
m_cmds.last();
2643 if (lastCommand.commandID() == InputTextCommandID) {
2644 InputTextCommand cmd =
static_cast<InputTextCommand &
>(lastCommand);
2645 cmd.deleteCharacter();
2646 if (cmd.charactersAdded() == 0) {
2650 else if (lastCommand.commandID() == InputNewlineCommandID) {
2651 lastCommand.unapply();
2652 removeCommand(lastCommand);
2655 issueCommandForDeleteKey();
2661void TypingCommandImpl::removeCommand(
const PassRefPtr<EditCommandImpl> cmd)
2690 command->deleteKeyPressed();
2705 command->insertNewline();
2711#ifdef DEBUG_COMMANDS
2712 kDebug() <<
"[insert text]" << text << endl;
2723 command->insertText(text);
2742#ifdef DEBUG_COMMANDS
2747 ElementImpl *startBlock = start.node()->enclosingBlockFlowElement();
2748 ElementImpl *endBlock =
end.node()->enclosingBlockFlowElement();
2749#ifdef DEBUG_COMMANDS
2750 kDebug() <<
"[start:end blocks]" << startBlock << endBlock << endl;
2751 printEnclosingBlockTree(start.node());
2753 if (startBlock == endBlock) {
2754 if (startBlock->id() == ID_LI) {
2756#ifdef DEBUG_COMMANDS
2757 kDebug() <<
"[remove list item]" << endl;
2759 NodeImpl *listBlock = startBlock->parent();
2762 if (listBlock->firstChild() == listBlock->lastChild() && listBlock->firstChild() == startBlock) {
2764#ifdef DEBUG_COMMANDS
2765 kDebug() <<
"[remove list completely]" << endl;
2769 }
else if (!startBlock->previousSibling()) {
2771 NodeImpl *nextSibling;
2772 for (NodeImpl *node = startBlock->firstChild(); node; node = nextSibling) {
2773 nextSibling = node->nextSibling();
2778 }
else if (!startBlock->nextSibling()) {
2780 NodeImpl *nextSibling;
2781 for (NodeImpl *node = startBlock->lastChild(); node; node = nextSibling) {
2782 nextSibling = node->previousSibling();
2789 WTF::PassRefPtr<NodeImpl> newListBlock = listBlock->cloneNode(
false);
2791 NodeImpl *node, *nextSibling;
2792 for (node = startBlock->nextSibling(); node; node = nextSibling) {
2793 nextSibling = node->nextSibling();
2797 for (node = startBlock->firstChild(); node; node = nextSibling) {
2798 nextSibling = node->nextSibling();
2806 ElementImpl *li =
document()->createHTMLElement(
"LI");
2809 for (NodeImpl *node = startBlock->firstChild(); node; node = nextNode) {
2810#ifdef DEBUG_COMMANDS
2811 kDebug() <<
"[reattach node]" << node << endl;
2813 nextNode = node->nextSibling();
2820#ifdef DEBUG_COMMANDS
2821 kDebug() <<
"[different blocks are not supported yet]" << endl;
2829 insertCommand->apply();
2846void IndentOutdentCommandImpl::indent()
2849#ifdef DEBUG_COMMANDS
2850 kDebug() <<
"[indent selection]" << selection << endl;
2852 NodeImpl *startBlock = selection.start().node()->enclosingBlockFlowElement();
2853 NodeImpl *endBlock = selection.end().node()->enclosingBlockFlowElement();
2855 if (startBlock == endBlock) {
2857 if (startBlock->id() == ID_LI && (startBlock->previousSibling() || startBlock->nextSibling())) {
2858#ifdef DEBUG_COMMANDS
2859 kDebug() <<
"[modify list]" << endl;
2861 RefPtr<NodeImpl> newList = startBlock->parent()->cloneNode(
false);
2866 NodeImpl *blockquoteElement =
document()->createHTMLElement(
"blockquote");
2867 if (startBlock->id() == ID_LI) {
2868 startBlock = startBlock->parent();
2881 if (startBlock->id() == ID_LI && endBlock->id() == ID_LI && startBlock->parent() == endBlock->parent()) {
2882#ifdef DEBUG_COMMANDS
2883 kDebug() <<
"[indent some items inside list]" << endl;
2885 RefPtr<NodeImpl> nestedList = startBlock->parent()->cloneNode(
false);
2887 NodeImpl *nextNode = 0;
2888 for (NodeImpl *node = startBlock;; node = nextNode) {
2889 nextNode = node->nextSibling();
2892 if (node == endBlock)
2896#ifdef DEBUG_COMMANDS
2897 kDebug() <<
"[blocks not from one list are not supported yet]" << endl;
2906 node = node->previousSibling();
2907 if (node && node->id() == ID_LI)
2916 node = node->nextSibling();
2917 if (node && node->id() == ID_LI)
2923void IndentOutdentCommandImpl::outdent()
2926#ifdef DEBUG_COMMANDS
2927 kDebug() <<
"[indent selection]" << selection << endl;
2929 NodeImpl *startBlock = selection.start().node()->enclosingBlockFlowElement();
2930 NodeImpl *endBlock = selection.end().node()->enclosingBlockFlowElement();
2932 if (startBlock->id() == ID_LI && endBlock->id() == ID_LI && startBlock->parent() == endBlock->parent()) {
2933#ifdef DEBUG_COMMANDS
2934 kDebug() <<
"[list items selected]" << endl;
2938 bool listFullySelected = firstItemSelected && lastItemSelected;
2940#ifdef DEBUG_COMMANDS
2941 kDebug() <<
"[first/last item selected]" << firstItemSelected << lastItemSelected << endl;
2944 NodeImpl *listNode = startBlock->parent();
2945 printEnclosingBlockTree(listNode);
2946 bool hasParentList = listNode->parent()->id() == ID_OL || listNode->parent()->id() == ID_UL;
2948 if (!firstItemSelected && !lastItemSelected) {
2950 RefPtr<NodeImpl> clonedList = listNode->cloneNode(
false);
2951 NodeImpl *nextNode = 0;
2952 for (NodeImpl *node = listNode->firstChild(); node != startBlock; node = nextNode) {
2953 nextNode = node->nextSibling();
2959 firstItemSelected =
true;
2962 NodeImpl *nextNode = 0;
2963 for (NodeImpl *node = firstItemSelected ? startBlock : endBlock;; node = nextNode) {
2964 nextNode = firstItemSelected ? node->nextSibling() : node->previousSibling();
2966 if (firstItemSelected)
2970 if (!hasParentList && node->id() == ID_LI) {
2974 if (node == (firstItemSelected ? endBlock : startBlock))
2977 if (listFullySelected)
2983 if (startBlock == endBlock) {
2984 if (startBlock->id() == ID_BLOCKQUOTE) {
2987#ifdef DEBUG_COMMANDS
2988 kDebug() <<
"[not the list or blockquote]" << endl;
2992#ifdef DEBUG_COMMANDS
2993 kDebug() <<
"[blocks not from one list are not supported yet]" << endl;
3000 if (m_commandType ==
Indent)
The CSSPrimitiveValue interface represents a single CSS value .
This class implements the basic string we use in the DOM.
DOMStringImpl * implementation() const
This class resembles the editing API when the associated khtml document is editable (in design mode),...
WTF::PassRefPtr< khtml::EditCommandImpl > lastEditCommand() const
Returns the most recent edit command applied.
The Node interface is the primary datatype for the entire Document Object Model.
AppendNodeCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *parentNode, DOM::NodeImpl *appendChild)
virtual ~AppendNodeCommandImpl()
ApplyStyleCommandImpl(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style)
DOM::CSSStyleDeclarationImpl * style() const
virtual ~ApplyStyleCommandImpl()
void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property)
void removeNodeAttribute(DOM::ElementImpl *, int attribute)
void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2)
void removeNodeAndPrune(DOM::NodeImpl *pruneNode, DOM::NodeImpl *stopNode=0)
QList< RefPtr< EditCommandImpl > > m_cmds
CompositeEditCommandImpl(DOM::DocumentImpl *)
void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset)
void splitTextNode(DOM::TextImpl *text, long offset)
void inputText(const DOM::DOMString &text)
void replaceText(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText)
void removeNodePreservingChildren(DOM::NodeImpl *node)
DOM::ElementImpl * createTypingStyleElement() const
void applyCommandToComposite(PassRefPtr< EditCommandImpl >)
void removeNode(DOM::NodeImpl *removeChild)
void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild)
void appendNode(DOM::NodeImpl *parent, DOM::NodeImpl *appendChild)
void deleteText(DOM::TextImpl *node, long offset, long count)
void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &)
virtual ~CompositeEditCommandImpl()
void insertText(DOM::TextImpl *node, long offset, const DOM::DOMString &text)
void deleteCollapsibleWhitespace()
void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild)
DeleteCollapsibleWhitespaceCommandImpl(DOM::DocumentImpl *document)
DeleteSelectionCommandImpl(DOM::DocumentImpl *document)
virtual ~DeleteSelectionCommandImpl()
DeleteTextCommandImpl(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count)
virtual ~DeleteTextCommandImpl()
ECommandState state() const
void setEndingSelection(const DOM::Selection &s)
virtual bool isInputTextCommand() const
void setStartingSelection(const DOM::Selection &s)
virtual DOM::DocumentImpl * document() const
EditCommandImpl * parent() const
bool isCompositeStep() const
EditCommandImpl(DOM::DocumentImpl *)
virtual bool isTypingCommand() const
void setParent(EditCommandImpl *)
virtual ~EditCommandImpl()
DOM::Selection endingSelection() const
DOM::Selection startingSelection() const
void setState(ECommandState state)
virtual void doUnapply()=0
IndentOutdentCommandImpl(DocumentImpl *document, Type type)
virtual ~IndentOutdentCommandImpl()
InputTextCommandImpl(DOM::DocumentImpl *document)
void input(const DOM::DOMString &text)
virtual ~InputTextCommandImpl()
InsertListCommandImpl(DOM::DocumentImpl *document, Type type)
virtual ~InsertListCommandImpl()
static void insertList(DocumentImpl *document, Type type)
InsertNodeBeforeCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild)
virtual ~InsertNodeBeforeCommandImpl()
DOM::DOMString text() const
virtual ~InsertTextCommandImpl()
InsertTextCommandImpl(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &)
JoinTextNodesCommandImpl(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *)
virtual ~JoinTextNodesCommandImpl()
MoveSelectionCommandImpl(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, DOM::Position &position)
virtual ~MoveSelectionCommandImpl()
virtual ~RemoveCSSPropertyCommandImpl()
RemoveCSSPropertyCommandImpl(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *, int property)
DOM::NodeImpl * pruneNode() const
virtual ~RemoveNodeAndPruneCommandImpl()
RemoveNodeAndPruneCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *pruneNode, DOM::NodeImpl *stopNode=0)
RemoveNodeAttributeCommandImpl(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute)
virtual ~RemoveNodeAttributeCommandImpl()
RemoveNodeCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *)
virtual ~RemoveNodeCommandImpl()
DOM::NodeImpl * node() const
virtual ~RemoveNodePreservingChildrenCommandImpl()
RemoveNodePreservingChildrenCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *)
DOM::NodeImpl * node() const
virtual ~ReplaceSelectionCommandImpl()
ReplaceSelectionCommandImpl(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true)
virtual ~SetNodeAttributeCommandImpl()
SetNodeAttributeCommandImpl(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute, const DOM::DOMString &value)
SplitTextNodeCommandImpl(DOM::DocumentImpl *, DOM::TextImpl *, long)
virtual ~SplitTextNodeCommandImpl()
virtual ~TypingCommandImpl()
static void insertNewline0(DocumentImpl *document)
static void insertText0(DocumentImpl *document, const DOMString &text)
static void deleteKeyPressed0(DocumentImpl *document)
void insertText(const DOM::DOMString &text)
TypingCommandImpl(DOM::DocumentImpl *document)
bool strcasecmp(const DOMString &a, const DOMString &b)
KAction * next(const QObject *recvr, const char *slot, QObject *parent)
static bool isBlockLevelStyle(const CSSStyleDeclarationImpl *style)
static Position leadingWhitespacePosition(const Position &pos)
static bool shouldPruneNode(NodeImpl *node)
static bool isOpenForMoreTypingCommand(const EditCommandImpl *command)
static bool textNodesAreJoinable(TextImpl *text1, TextImpl *text2)
static bool checkIfNewStylingNeeded(ElementImpl *element, CSSStyleDeclarationImpl *style)
static DOMString & nonBreakingSpaceString()
static bool shouldDeleteUpstreamPosition(const Position &pos)
static void applyStyleChangeOnTheNode(ElementImpl *element, CSSStyleDeclarationImpl *style)
static Position trailingWhitespacePosition(const Position &pos)
static bool hasNextListItem(NodeImpl *node)
static bool isNBSP(const QChar &c)
static bool isWS(const QChar &c)
static bool hasPreviousListItem(NodeImpl *node)
static DOMString & styleSpanClassString()