📄 compositeeditcommand.cpp
字号:
/* * Copyright (C) 2005, 2006, 2007, 2008 Apple 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. */#include "config.h"#include "CompositeEditCommand.h"#include "AppendNodeCommand.h"#include "ApplyStyleCommand.h"#include "CSSComputedStyleDeclaration.h"#include "CSSMutableStyleDeclaration.h"#include "CharacterNames.h"#include "DeleteFromTextNodeCommand.h"#include "DeleteSelectionCommand.h"#include "Document.h"#include "DocumentFragment.h"#include "EditorInsertAction.h"#include "Element.h"#include "HTMLNames.h"#include "InlineTextBox.h"#include "InsertIntoTextNodeCommand.h"#include "InsertLineBreakCommand.h"#include "InsertNodeBeforeCommand.h"#include "InsertParagraphSeparatorCommand.h"#include "InsertTextCommand.h"#include "JoinTextNodesCommand.h"#include "MergeIdenticalElementsCommand.h"#include "Range.h"#include "RemoveCSSPropertyCommand.h"#include "RemoveNodeCommand.h"#include "RemoveNodePreservingChildrenCommand.h"#include "ReplaceSelectionCommand.h"#include "RenderBlock.h"#include "RenderText.h"#include "SetNodeAttributeCommand.h"#include "SplitElementCommand.h"#include "SplitTextNodeCommand.h"#include "SplitTextNodeContainingElementCommand.h"#include "Text.h"#include "TextIterator.h"#include "WrapContentsInDummySpanCommand.h"#include "htmlediting.h"#include "markup.h"#include "visible_units.h"using namespace std;namespace WebCore {using namespace HTMLNames;CompositeEditCommand::CompositeEditCommand(Document *document) : EditCommand(document){}void CompositeEditCommand::doUnapply(){ size_t size = m_commands.size(); for (size_t i = size; i != 0; --i) m_commands[i - 1]->unapply();}void CompositeEditCommand::doReapply(){ size_t size = m_commands.size(); for (size_t i = 0; i != size; ++i) m_commands[i]->reapply();}//// sugary-sweet convenience functions to help create and apply edit commands in composite commands//void CompositeEditCommand::applyCommandToComposite(PassRefPtr<EditCommand> cmd){ cmd->setParent(this); cmd->apply(); m_commands.append(cmd);}void CompositeEditCommand::applyStyle(CSSStyleDeclaration* style, EditAction editingAction){ applyCommandToComposite(ApplyStyleCommand::create(document(), style, editingAction));}void CompositeEditCommand::applyStyle(CSSStyleDeclaration* style, const Position& start, const Position& end, EditAction editingAction){ applyCommandToComposite(ApplyStyleCommand::create(document(), style, start, end, editingAction));}void CompositeEditCommand::applyStyledElement(PassRefPtr<Element> element){ applyCommandToComposite(ApplyStyleCommand::create(element, false));}void CompositeEditCommand::removeStyledElement(PassRefPtr<Element> element){ applyCommandToComposite(ApplyStyleCommand::create(element, true));}void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElement){ applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), useDefaultParagraphElement));}void CompositeEditCommand::insertLineBreak(){ applyCommandToComposite(InsertLineBreakCommand::create(document()));}void CompositeEditCommand::insertNodeBefore(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild){ ASSERT(!refChild->hasTagName(bodyTag)); applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChild));}void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild){ ASSERT(insertChild); ASSERT(refChild); ASSERT(!refChild->hasTagName(bodyTag)); Element* parent = refChild->parentElement(); ASSERT(parent); if (parent->lastChild() == refChild) appendNode(insertChild, parent); else { ASSERT(refChild->nextSibling()); insertNodeBefore(insertChild, refChild->nextSibling()); }}void CompositeEditCommand::insertNodeAt(PassRefPtr<Node> insertChild, const Position& editingPosition){ ASSERT(isEditablePosition(editingPosition)); // For editing positions like [table, 0], insert before the table, // likewise for replaced elements, brs, etc. Position p = rangeCompliantEquivalent(editingPosition); Node* refChild = p.node(); int offset = p.offset(); if (canHaveChildrenForEditing(refChild)) { Node* child = refChild->firstChild(); for (int i = 0; child && i < offset; i++) child = child->nextSibling(); if (child) insertNodeBefore(insertChild, child); else appendNode(insertChild, static_cast<Element*>(refChild)); } else if (caretMinOffset(refChild) >= offset) insertNodeBefore(insertChild, refChild); else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) { splitTextNode(static_cast<Text *>(refChild), offset); insertNodeBefore(insertChild, refChild); } else insertNodeAfter(insertChild, refChild);}void CompositeEditCommand::appendNode(PassRefPtr<Node> node, PassRefPtr<Element> parent){ ASSERT(canHaveChildrenForEditing(parent.get())); applyCommandToComposite(AppendNodeCommand::create(parent, node));}void CompositeEditCommand::removeChildrenInRange(PassRefPtr<Node> node, unsigned from, unsigned to){ Vector<RefPtr<Node> > children; Node* child = node->childNode(from); for (unsigned i = from; child && i < to; i++, child = child->nextSibling()) children.append(child); size_t size = children.size(); for (size_t i = 0; i < size; ++i) removeNode(children[i].release());}void CompositeEditCommand::removeNode(PassRefPtr<Node> node){ applyCommandToComposite(RemoveNodeCommand::create(node));}void CompositeEditCommand::removeNodePreservingChildren(PassRefPtr<Node> node){ applyCommandToComposite(RemoveNodePreservingChildrenCommand::create(node));}void CompositeEditCommand::removeNodeAndPruneAncestors(PassRefPtr<Node> node){ RefPtr<Node> parent = node->parentNode(); removeNode(node); prune(parent.release());}static bool hasARenderedDescendant(Node* node){ Node* n = node->firstChild(); while (n) { if (n->renderer()) return true; n = n->traverseNextNode(node); } return false;}void CompositeEditCommand::prune(PassRefPtr<Node> node){ while (node) { // If you change this rule you may have to add an updateLayout() here. RenderObject* renderer = node->renderer(); if (renderer && (!renderer->canHaveChildren() || hasARenderedDescendant(node.get()) || node->rootEditableElement() == node)) return; RefPtr<Node> next = node->parentNode(); removeNode(node); node = next; }}void CompositeEditCommand::splitTextNode(PassRefPtr<Text> node, unsigned offset){ applyCommandToComposite(SplitTextNodeCommand::create(node, offset));}void CompositeEditCommand::splitElement(PassRefPtr<Element> element, PassRefPtr<Node> atChild){ applyCommandToComposite(SplitElementCommand::create(element, atChild));}void CompositeEditCommand::mergeIdenticalElements(PassRefPtr<Element> prpFirst, PassRefPtr<Element> prpSecond){ RefPtr<Element> first = prpFirst; RefPtr<Element> second = prpSecond; ASSERT(!first->isDescendantOf(second.get()) && second != first); if (first->nextSibling() != second) { removeNode(second); insertNodeAfter(second, first); } applyCommandToComposite(MergeIdenticalElementsCommand::create(first, second));}void CompositeEditCommand::wrapContentsInDummySpan(PassRefPtr<Element> element){ applyCommandToComposite(WrapContentsInDummySpanCommand::create(element));}void CompositeEditCommand::splitTextNodeContainingElement(PassRefPtr<Text> text, unsigned offset){ applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text, offset));}void CompositeEditCommand::joinTextNodes(PassRefPtr<Text> text1, PassRefPtr<Text> text2){ applyCommandToComposite(JoinTextNodesCommand::create(text1, text2));}void CompositeEditCommand::inputText(const String& text, bool selectInsertedText){ int offset = 0; int length = text.length(); RefPtr<Range> startRange = Range::create(document(), Position(document()->documentElement(), 0), endingSelection().start()); int startIndex = TextIterator::rangeLength(startRange.get()); int newline; do { newline = text.find('\n', offset); if (newline != offset) { RefPtr<InsertTextCommand> command = InsertTextCommand::create(document()); applyCommandToComposite(command); int substringLength = newline == -1 ? length - offset : newline - offset; command->input(text.substring(offset, substringLength), false); } if (newline != -1) insertLineBreak(); offset = newline + 1; } while (newline != -1 && offset != length); if (selectInsertedText) { RefPtr<Range> selectedRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), startIndex, length); setEndingSelection(VisibleSelection(selectedRange.get())); }}void CompositeEditCommand::insertTextIntoNode(PassRefPtr<Text> node, unsigned offset, const String& text){ applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset, text));}void CompositeEditCommand::deleteTextFromNode(PassRefPtr<Text> node, unsigned offset, unsigned count){ applyCommandToComposite(DeleteFromTextNodeCommand::create(node, offset, count));}void CompositeEditCommand::replaceTextInNode(PassRefPtr<Text> node, unsigned offset, unsigned count, const String& replacementText){ applyCommandToComposite(DeleteFromTextNodeCommand::create(node.get(), offset, count)); applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset, replacementText));}Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos){ if (!isTabSpanTextNode(pos.node())) return pos; Node* tabSpan = tabSpanNode(pos.node()); if (pos.offset() <= caretMinOffset(pos.node())) return positionBeforeNode(tabSpan); if (pos.offset() >= caretMaxOffset(pos.node())) return positionAfterNode(tabSpan); splitTextNodeContainingElement(static_cast<Text *>(pos.node()), pos.offset()); return positionBeforeNode(tabSpan);}void CompositeEditCommand::insertNodeAtTabSpanPosition(PassRefPtr<Node> node, const Position& pos){ // insert node before, after, or at split of tab span insertNodeAt(node, positionOutsideTabSpan(pos));}void CompositeEditCommand::deleteSelection(bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements){ if (endingSelection().isRange()) applyCommandToComposite(DeleteSelectionCommand::create(document(), smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -