summaryrefslogtreecommitdiffstats
path: root/WebCore/editing
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/editing')
-rw-r--r--WebCore/editing/Editor.cpp14
-rw-r--r--WebCore/editing/EditorCommand.cpp2
-rw-r--r--WebCore/editing/InsertParagraphSeparatorCommand.cpp24
-rw-r--r--WebCore/editing/ReplaceSelectionCommand.cpp56
-rw-r--r--WebCore/editing/ReplaceSelectionCommand.h1
-rw-r--r--WebCore/editing/htmlediting.cpp17
-rw-r--r--WebCore/editing/htmlediting.h3
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