📄 htmlediting_impl.cpp
字号:
insertNodeBefore(textBeforeNode, textNode);
insertNodeBefore(nodeToInsert, textNode);
setEndingSelection(Position(textNode, 0));
}
}
//------------------------------------------------------------------------------------------
// InputTextCommandImpl
InputTextCommandImpl::InputTextCommandImpl(DocumentImpl *document)
: CompositeEditCommandImpl(document), m_charactersAdded(0)
{
}
InputTextCommandImpl::~InputTextCommandImpl()
{
}
int InputTextCommandImpl::commandID() const
{
return InputTextCommandID;
}
void InputTextCommandImpl::doApply()
{
}
void InputTextCommandImpl::input(const DOMString &text)
{
execute(text);
}
void InputTextCommandImpl::deleteCharacter()
{
ASSERT(state() == Applied);
Selection selection = endingSelection();
if (!selection.start().node()->isTextNode())
return;
int exceptionCode = 0;
int offset = selection.start().offset() - 1;
if (offset >= selection.start().node()->caretMinOffset()) {
TextImpl *textNode = static_cast<TextImpl *>(selection.start().node());
textNode->deleteData(offset, 1, exceptionCode);
ASSERT(exceptionCode == 0);
selection = Selection(Position(textNode, offset));
setEndingSelection(selection);
m_charactersAdded--;
}
}
Position InputTextCommandImpl::prepareForTextInsertion(bool adjustDownstream)
{
// Prepare for text input by looking at the current position.
// It may be necessary to insert a text node to receive characters.
Selection selection = endingSelection();
ASSERT(selection.state() == Selection::CARET);
Position pos = selection.start();
if (adjustDownstream)
pos = pos.equivalentDownstreamPosition();
else
pos = pos.equivalentUpstreamPosition();
if (!pos.node()->isTextNode()) {
NodeImpl *textNode = document()->createEditingTextNode("");
NodeImpl *nodeToInsert = textNode;
if (document()->part()->typingStyle()) {
int exceptionCode = 0;
ElementImpl *styleElement = createTypingStyleElement();
styleElement->appendChild(textNode, exceptionCode);
ASSERT(exceptionCode == 0);
nodeToInsert = styleElement;
}
// Now insert the node in the right place
if (pos.node()->isEditableBlock()) {
// LOG(Editing, "prepareForTextInsertion case 1");
appendNode(pos.node(), nodeToInsert);
}
else if (pos.node()->id() == ID_BR && pos.offset() == 1) {
// LOG(Editing, "prepareForTextInsertion case 2");
insertNodeAfter(nodeToInsert, pos.node());
}
else if (pos.node()->caretMinOffset() == pos.offset()) {
// LOG(Editing, "prepareForTextInsertion case 3");
insertNodeBefore(nodeToInsert, pos.node());
}
else if (pos.node()->caretMaxOffset() == pos.offset()) {
// LOG(Editing, "prepareForTextInsertion case 4");
insertNodeAfter(nodeToInsert, pos.node());
}
else
ASSERT_NOT_REACHED();
pos = Position(textNode, 0);
}
else {
// Handle the case where there is a typing style.
if (document()->part()->typingStyle()) {
if (pos.node()->isTextNode() && pos.offset() > pos.node()->caretMinOffset() && pos.offset() < pos.node()->caretMaxOffset()) {
// Need to split current text node in order to insert a span.
TextImpl *text = static_cast<TextImpl *>(pos.node());
SplitTextNodeCommand cmd(document(), text, pos.offset());
applyCommandToComposite(cmd);
setEndingSelection(Position(cmd.node(), 0));
}
int exceptionCode = 0;
TextImpl *editingTextNode = document()->createEditingTextNode("");
ElementImpl *styleElement = createTypingStyleElement();
styleElement->appendChild(editingTextNode, exceptionCode);
ASSERT(exceptionCode == 0);
NodeImpl *node = endingSelection().start().node();
if (endingSelection().start().isLastRenderedPositionOnLine())
insertNodeAfter(styleElement, node);
else
insertNodeBefore(styleElement, node);
pos = Position(editingTextNode, 0);
}
}
return pos;
}
void InputTextCommandImpl::execute(const DOMString &text)
{
Selection selection = endingSelection();
bool adjustDownstream = selection.start().isFirstRenderedPositionOnLine();
// Delete the current selection, or collapse whitespace, as needed
if (selection.state() == Selection::RANGE)
deleteSelection();
else
deleteCollapsibleWhitespace();
// EDIT FIXME: Need to take typing style from upstream text, if any.
// Make sure the document is set up to receive text
Position pos = prepareForTextInsertion(adjustDownstream);
TextImpl *textNode = static_cast<TextImpl *>(pos.node());
long offset = pos.offset();
// This is a temporary implementation for inserting adjoining spaces
// into a document. We are working on a CSS-related whitespace solution
// that will replace this some day.
if (isWS(text))
insertSpace(textNode, offset);
else {
const DOMString &existingText = textNode->data();
if (textNode->length() >= 2 && offset >= 2 && isNBSP(existingText[offset - 1]) && !isWS(existingText[offset - 2])) {
// DOM looks like this:
// character nbsp caret
// As we are about to insert a non-whitespace character at the caret
// convert the nbsp to a regular space.
// EDIT FIXME: This needs to be improved some day to convert back only
// those nbsp's added by the editor to make rendering come out right.
replaceText(textNode, offset - 1, 1, " ");
}
insertText(textNode, offset, text);
}
setEndingSelection(Position(textNode, offset + text.length()));
m_charactersAdded += text.length();
}
void InputTextCommandImpl::insertSpace(TextImpl *textNode, unsigned long offset)
{
ASSERT(textNode);
DOMString text(textNode->data());
// count up all spaces and newlines in front of the caret
// delete all collapsed ones
// this will work out OK since the offset we have been passed has been upstream-ized
int count = 0;
for (unsigned int i = offset; i < text.length(); i++) {
if (isWS(text[i]))
count++;
else
break;
}
if (count > 0) {
// By checking the character at the downstream position, we can
// check if there is a rendered WS at the caret
Position pos(textNode, offset);
Position downstream = pos.equivalentDownstreamPosition();
if (downstream.offset() < (long)text.length() && isWS(text[downstream.offset()]))
count--; // leave this WS in
if (count > 0)
deleteText(textNode, offset, count);
}
if (offset > 0 && offset <= text.length() - 1 && !isWS(text[offset]) && !isWS(text[offset - 1])) {
// insert a "regular" space
insertText(textNode, offset, " ");
return;
}
if (text.length() >= 2 && offset >= 2 && isNBSP(text[offset - 2]) && isNBSP(text[offset - 1])) {
// DOM looks like this:
// nbsp nbsp caret
// insert a space between the two nbsps
insertText(textNode, offset - 1, " ");
return;
}
// insert an nbsp
insertText(textNode, offset, nonBreakingSpaceString());
}
//------------------------------------------------------------------------------------------
// InsertNodeBeforeCommandImpl
InsertNodeBeforeCommandImpl::InsertNodeBeforeCommandImpl(DocumentImpl *document, NodeImpl *insertChild, NodeImpl *refChild)
: EditCommandImpl(document), m_insertChild(insertChild), m_refChild(refChild)
{
ASSERT(m_insertChild);
m_insertChild->ref();
ASSERT(m_refChild);
m_refChild->ref();
}
InsertNodeBeforeCommandImpl::~InsertNodeBeforeCommandImpl()
{
if (m_insertChild)
m_insertChild->deref();
if (m_refChild)
m_refChild->deref();
}
int InsertNodeBeforeCommandImpl::commandID() const
{
return InsertNodeBeforeCommandID;
}
void InsertNodeBeforeCommandImpl::doApply()
{
ASSERT(m_insertChild);
ASSERT(m_refChild);
ASSERT(m_refChild->parentNode());
int exceptionCode = 0;
m_refChild->parentNode()->insertBefore(m_insertChild, m_refChild, exceptionCode);
ASSERT(exceptionCode == 0);
}
void InsertNodeBeforeCommandImpl::doUnapply()
{
ASSERT(m_insertChild);
ASSERT(m_refChild);
ASSERT(m_refChild->parentNode());
int exceptionCode = 0;
m_refChild->parentNode()->removeChild(m_insertChild, exceptionCode);
ASSERT(exceptionCode == 0);
}
//------------------------------------------------------------------------------------------
// InsertTextCommandImpl
InsertTextCommandImpl::InsertTextCommandImpl(DocumentImpl *document, TextImpl *node, long offset, const DOMString &text)
: EditCommandImpl(document), m_node(node), m_offset(offset)
{
ASSERT(m_node);
ASSERT(m_offset >= 0);
ASSERT(text.length() > 0);
m_node->ref();
m_text = text.copy(); // make a copy to ensure that the string never changes
}
InsertTextCommandImpl::~InsertTextCommandImpl()
{
if (m_node)
m_node->deref();
}
int InsertTextCommandImpl::commandID() const
{
return InsertTextCommandID;
}
void InsertTextCommandImpl::doApply()
{
ASSERT(m_node);
ASSERT(!m_text.isEmpty());
int exceptionCode = 0;
m_node->insertData(m_offset, m_text, exceptionCode);
ASSERT(exceptionCode == 0);
}
void InsertTextCommandImpl::doUnapply()
{
ASSERT(m_node);
ASSERT(!m_text.isEmpty());
int exceptionCode = 0;
m_node->deleteData(m_offset, m_text.length(), exceptionCode);
ASSERT(exceptionCode == 0);
}
//------------------------------------------------------------------------------------------
// JoinTextNodesCommandImpl
JoinTextNodesCommandImpl::JoinTextNodesCommandImpl(DocumentImpl *document, TextImpl *text1, TextImpl *text2)
: EditCommandImpl(document), m_text1(text1), m_text2(text2)
{
ASSERT(m_text1);
ASSERT(m_text2);
ASSERT(m_text1->nextSibling() == m_text2);
ASSERT(m_text1->length() > 0);
ASSERT(m_text2->length() > 0);
m_text1->ref();
m_text2->ref();
}
JoinTextNodesCommandImpl::~JoinTextNodesCommandImpl()
{
if (m_text1)
m_text1->deref();
if (m_text2)
m_text2->deref();
}
int JoinTextNodesCommandImpl::commandID() const
{
return JoinTextNodesCommandID;
}
void JoinTextNodesCommandImpl::doApply()
{
ASSERT(m_text1);
ASSERT(m_text2);
ASSERT(m_text1->nextSibling() == m_text2);
int exceptionCode = 0;
m_text2->insertData(0, m_text1->data(), exceptionCode);
ASSERT(exceptionCode == 0);
m_text2->parentNode()->removeChild(m_text1, exceptionCode);
ASSERT(exceptionCode == 0);
m_offset = m_text1->length();
}
void JoinTextNodesCommandImpl::doUnapply()
{
ASSERT(m_text2);
ASSERT(m_offset > 0);
int exceptionCode = 0;
m_text2->deleteData(0, m_offset, exceptionCode);
ASSERT(exceptionCode == 0);
m_text2->parentNode()->insertBefore(m_text1, m_text2, exceptionCode);
ASSERT(exceptionCode == 0);
ASSERT(m_text2->previousSibling()->isTextNode());
ASSERT(m_text2->previousSibling() == m_text1);
}
//------------------------------------------------------------------------------------------
// ReplaceSelectionCommandImpl
ReplaceSelectionCommandImpl::ReplaceSelectionCommandImpl(DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement)
: CompositeEditCommandImpl(document), m_fragment(fragment), m_selectRepl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -