diff options
Diffstat (limited to 'WebCore/editing')
-rw-r--r-- | WebCore/editing/Editor.cpp | 14 | ||||
-rw-r--r-- | WebCore/editing/EditorCommand.cpp | 2 | ||||
-rw-r--r-- | WebCore/editing/InsertParagraphSeparatorCommand.cpp | 24 | ||||
-rw-r--r-- | WebCore/editing/ReplaceSelectionCommand.cpp | 56 | ||||
-rw-r--r-- | WebCore/editing/ReplaceSelectionCommand.h | 1 | ||||
-rw-r--r-- | WebCore/editing/htmlediting.cpp | 17 | ||||
-rw-r--r-- | WebCore/editing/htmlediting.h | 3 |
7 files changed, 94 insertions, 23 deletions
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp index 5798452..1061dd2 100644 --- a/WebCore/editing/Editor.cpp +++ b/WebCore/editing/Editor.cpp @@ -1004,16 +1004,6 @@ bool Editor::insertParagraphSeparator() return true; } -static bool nodeIsInTextFormControl(Node* node) -{ - if (!node) - return false; - Node* ancestor = node->shadowAncestorNode(); - if (ancestor == node) - return false; - return ancestor->isElementNode() && static_cast<Element*>(ancestor)->isTextFormControl(); -} - void Editor::cut() { if (tryDHTMLCut()) @@ -1024,7 +1014,7 @@ void Editor::cut() } RefPtr<Range> selection = selectedRange(); if (shouldDeleteRange(selection.get())) { - if (nodeIsInTextFormControl(m_frame->selection()->start().node())) + if (isNodeInTextFormControl(m_frame->selection()->start().node())) Pasteboard::generalPasteboard()->writePlainText(m_frame->selectedText()); else Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame); @@ -1042,7 +1032,7 @@ void Editor::copy() return; } - if (nodeIsInTextFormControl(m_frame->selection()->start().node())) + if (isNodeInTextFormControl(m_frame->selection()->start().node())) Pasteboard::generalPasteboard()->writePlainText(m_frame->selectedText()); else { Document* document = m_frame->document(); diff --git a/WebCore/editing/EditorCommand.cpp b/WebCore/editing/EditorCommand.cpp index 6a9e10f..437d584 100644 --- a/WebCore/editing/EditorCommand.cpp +++ b/WebCore/editing/EditorCommand.cpp @@ -260,7 +260,7 @@ static int verticalScrollDistance(Frame* frame) if (!(style->overflowY() == OSCROLL || style->overflowY() == OAUTO || renderer->isTextArea())) return 0; int height = toRenderBox(renderer)->clientHeight(); - return max(height * cFractionToStepWhenPaging, 1.f); + return max(max<int>(height * Scrollbar::minFractionToStepWhenPaging(), height - Scrollbar::maxOverlapBetweenPages()), 1); } static RefPtr<Range> unionDOMRanges(Range* a, Range* b) diff --git a/WebCore/editing/InsertParagraphSeparatorCommand.cpp b/WebCore/editing/InsertParagraphSeparatorCommand.cpp index 695f46a..058b961 100644 --- a/WebCore/editing/InsertParagraphSeparatorCommand.cpp +++ b/WebCore/editing/InsertParagraphSeparatorCommand.cpp @@ -44,6 +44,22 @@ namespace WebCore { using namespace HTMLNames; +// When inserting a new line, we want to avoid nesting empty divs if we can. Otherwise, when +// pasting, it's easy to have each new line be a div deeper than the previous. E.g., in the case +// below, we want to insert at ^ instead of |. +// <div>foo<div>bar</div>|</div>^ +static Element* highestVisuallyEquivalentDiv(Element* startBlock) +{ + Element* curBlock = startBlock; + while (!curBlock->nextSibling() && curBlock->parentElement()->hasTagName(divTag)) { + NamedNodeMap* attributes = curBlock->parentElement()->attributes(true); + if (attributes && !attributes->isEmpty()) + break; + curBlock = curBlock->parentElement(); + } + return curBlock; +} + InsertParagraphSeparatorCommand::InsertParagraphSeparatorCommand(Document *document, bool mustUseDefaultParagraphElement) : CompositeEditCommand(document) , m_mustUseDefaultParagraphElement(mustUseDefaultParagraphElement) @@ -214,7 +230,13 @@ void InsertParagraphSeparatorCommand::doApply() // When inserting the newline after the blockquote, we don't want to apply the original style after the insertion shouldApplyStyleAfterInsertion = false; } - insertNodeAfter(blockToInsert, startBlock); + + // Most of the time we want to stay at the nesting level of the startBlock (e.g., when nesting within lists). However, + // for div nodes, this can result in nested div tags that are hard to break out of. + Element* siblingNode = startBlock; + if (blockToInsert->hasTagName(divTag)) + siblingNode = highestVisuallyEquivalentDiv(startBlock); + insertNodeAfter(blockToInsert, siblingNode); } // Recreate the same structure in the new paragraph. diff --git a/WebCore/editing/ReplaceSelectionCommand.cpp b/WebCore/editing/ReplaceSelectionCommand.cpp index 85a4471..f26757e 100644 --- a/WebCore/editing/ReplaceSelectionCommand.cpp +++ b/WebCore/editing/ReplaceSelectionCommand.cpp @@ -752,9 +752,7 @@ void ReplaceSelectionCommand::doApply() bool startIsInsideMailBlockquote = nearestMailBlockquote(insertionPos.node()); if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !startIsInsideMailBlockquote) || - startBlock == currentRoot || - (startBlock && startBlock->renderer() && startBlock->renderer()->isListItem()) || - selectionIsPlainText) + startBlock == currentRoot || isListItem(startBlock) || selectionIsPlainText) m_preventNesting = false; if (selection.isRange()) { @@ -871,7 +869,12 @@ void ReplaceSelectionCommand::doApply() RefPtr<Node> node = refNode->nextSibling(); fragment.removeNode(refNode); - insertNodeAtAndUpdateNodesInserted(refNode, insertionPos); + + Node* blockStart = enclosingBlock(insertionPos.node()); + if (isListElement(refNode.get()) && blockStart->renderer()->isListItem()) + refNode = insertAsListItems(refNode, blockStart, insertionPos); + else + insertNodeAtAndUpdateNodesInserted(refNode, insertionPos); // Mutation events (bug 22634) may have already removed the inserted content if (!refNode->inDocument()) @@ -960,9 +963,15 @@ void ReplaceSelectionCommand::doApply() if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedContent) || next.isNull()) { if (!isStartOfParagraph(endOfInsertedContent)) { setEndingSelection(endOfInsertedContent); - // Use a default paragraph element (a plain div) for the empty paragraph, using the last paragraph - // block's style seems to annoy users. - insertParagraphSeparator(true); + Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEquivalent().node()); + if (isListItem(enclosingNode)) { + RefPtr<Node> newListItem = createListItemElement(document()); + insertNodeAfter(newListItem, enclosingNode); + setEndingSelection(VisiblePosition(Position(newListItem, 0))); + } else + // Use a default paragraph element (a plain div) for the empty paragraph, using the last paragraph + // block's style seems to annoy users. + insertParagraphSeparator(true); // Select up to the paragraph separator that was added. lastPositionToSelect = endingSelection().visibleStart().deepEquivalent(); @@ -1111,6 +1120,39 @@ void ReplaceSelectionCommand::insertNodeBeforeAndUpdateNodesInserted(PassRefPtr< updateNodesInserted(nodeToUpdate); } +// If the user is inserting a list into an existing list, instead of nesting the list, +// we put the list items into the existing list. +Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<Node> listElement, Node* insertionNode, const Position& p) +{ + while (listElement->hasChildNodes() && isListElement(listElement->firstChild()) && listElement->childNodeCount() == 1) + listElement = listElement->firstChild(); + + bool isStart = isStartOfParagraph(p); + bool isEnd = isEndOfParagraph(p); + + Node* lastNode = insertionNode; + while (RefPtr<Node> listItem = listElement->firstChild()) { + ExceptionCode ec = 0; + listElement->removeChild(listItem.get(), ec); + ASSERT(!ec); + if (isStart) + insertNodeBefore(listItem, lastNode); + else if (isEnd) { + insertNodeAfter(listItem, lastNode); + lastNode = listItem.get(); + } else { + // FIXME: If we're in the middle of a list item, we should split it into two separate + // list items and insert these nodes between them. For now, just append the nodes. + insertNodeAfter(listItem, lastNode); + lastNode = listItem.get(); + } + } + if (isStart) + lastNode = lastNode->previousSibling(); + updateNodesInserted(lastNode); + return lastNode; +} + void ReplaceSelectionCommand::updateNodesInserted(Node *node) { if (!node) diff --git a/WebCore/editing/ReplaceSelectionCommand.h b/WebCore/editing/ReplaceSelectionCommand.h index 1cb93c3..19f63bb 100644 --- a/WebCore/editing/ReplaceSelectionCommand.h +++ b/WebCore/editing/ReplaceSelectionCommand.h @@ -54,6 +54,7 @@ private: void insertNodeAfterAndUpdateNodesInserted(PassRefPtr<Node> insertChild, Node* refChild); void insertNodeAtAndUpdateNodesInserted(PassRefPtr<Node>, const Position&); void insertNodeBeforeAndUpdateNodesInserted(PassRefPtr<Node> insertChild, Node* refChild); + Node* insertAsListItems(PassRefPtr<Node>, Node* insertionNode, const Position&); void updateNodesInserted(Node*); bool shouldRemoveEndBR(Node*, const VisiblePosition&); diff --git a/WebCore/editing/htmlediting.cpp b/WebCore/editing/htmlediting.cpp index b58dff3..c0a9b63 100644 --- a/WebCore/editing/htmlediting.cpp +++ b/WebCore/editing/htmlediting.cpp @@ -658,6 +658,11 @@ bool isListElement(Node *n) return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag))); } +bool isListItem(Node *n) +{ + return n && n->renderer() && n->renderer()->isListItem(); +} + Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName) { if (p.isNull()) @@ -779,7 +784,7 @@ static Node* appendedSublist(Node* listItem) for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) { if (isListElement(n)) return static_cast<HTMLElement*>(n); - if (n->renderer() && n->renderer()->isListItem()) + if (isListItem(listItem)) return 0; } @@ -911,6 +916,16 @@ Node *tabSpanNode(const Node *node) return isTabSpanTextNode(node) ? node->parentNode() : 0; } +bool isNodeInTextFormControl(Node* node) +{ + if (!node) + return false; + Node* ancestor = node->shadowAncestorNode(); + if (ancestor == node) + return false; + return ancestor->isElementNode() && static_cast<Element*>(ancestor)->isTextFormControl(); +} + Position positionBeforeTabSpan(const Position& pos) { Node *node = pos.node(); diff --git a/WebCore/editing/htmlediting.h b/WebCore/editing/htmlediting.h index c5a44ac..1559fa5 100644 --- a/WebCore/editing/htmlediting.h +++ b/WebCore/editing/htmlediting.h @@ -90,10 +90,11 @@ bool isTableCell(const Node*); bool isEmptyTableCell(const Node*); bool isTableStructureNode(const Node*); bool isListElement(Node*); +bool isListItem(Node*); bool isNodeRendered(const Node*); bool isNodeVisiblyContainedWithin(Node*, const Range*); bool isRenderedAsNonInlineTableImageOrHR(const Node*); - +bool isNodeInTextFormControl(Node* node); // ------------------------------------------------------------------------- // Position |