--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -106,16 +106,34 @@ IsStyleCachePreservingAction(EditAction
action == EditAction::align ||
action == EditAction::makeBasicBlock ||
action == EditAction::removeList ||
action == EditAction::makeDefListItem ||
action == EditAction::insertElement ||
action == EditAction::insertQuotation;
}
+static nsIAtom&
+ParagraphSeparatorElement(ParagraphSeparator separator)
+{
+ switch (separator) {
+ default:
+ MOZ_FALLTHROUGH_ASSERT("Unexpected paragraph separator!");
+
+ case ParagraphSeparator::div:
+ return *nsGkAtoms::div;
+
+ case ParagraphSeparator::p:
+ return *nsGkAtoms::p;
+
+ case ParagraphSeparator::br:
+ return *nsGkAtoms::br;
+ }
+}
+
class TableCellAndListItemFunctor final : public BoolDomIterFunctor
{
public:
// Used to build list of all li's, td's & th's iterator covers
virtual bool operator()(nsINode* aNode) const
{
return HTMLEditUtils::IsTableCell(aNode) ||
HTMLEditUtils::IsListItem(aNode);
@@ -1520,24 +1538,62 @@ HTMLEditRules::WillInsertBreak(Selection
return NS_OK;
}
// Identify the block
nsCOMPtr<Element> blockParent = htmlEditor->GetBlock(node);
NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
// If the active editing host is an inline element, or if the active editing
- // host is the block parent itself, just append a br.
+ // host is the block parent itself and we're configured to use <br> as a
+ // paragraph separator, just append a <br>.
nsCOMPtr<Element> host = htmlEditor->GetActiveEditingHost();
- if (!EditorUtils::IsDescendantOf(blockParent, host)) {
+ if (NS_WARN_IF(!host)) {
+ return NS_ERROR_FAILURE;
+ }
+ ParagraphSeparator separator = mHTMLEditor->GetDefaultParagraphSeparator();
+ if (!IsBlockNode(*host) ||
+ // The nodes that can contain p and div are the same. If the editing
+ // host is a <p> or similar, we have to just insert a newline.
+ (!mHTMLEditor->CanContainTag(*host, *nsGkAtoms::p) &&
+ // These can't contain <p> as a child, but can as a descendant, so we
+ // don't have to fall back to inserting a newline.
+ !host->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul, nsGkAtoms::dl,
+ nsGkAtoms::table, nsGkAtoms::thead,
+ nsGkAtoms::tbody, nsGkAtoms::tfoot,
+ nsGkAtoms::tr)) ||
+ (host == blockParent && separator == ParagraphSeparator::br)) {
nsresult rv = StandardBreakImpl(node, offset, aSelection);
NS_ENSURE_SUCCESS(rv, rv);
*aHandled = true;
return NS_OK;
}
+ if (host == blockParent && separator != ParagraphSeparator::br) {
+ // Insert a new block first
+ MOZ_ASSERT(separator == ParagraphSeparator::div ||
+ separator == ParagraphSeparator::p);
+ nsresult rv = MakeBasicBlock(aSelection,
+ ParagraphSeparatorElement(separator));
+ // We warn on failure, but don't handle it, because it might be harmless.
+ // Instead we just check that a new block was actually created.
+ Unused << NS_WARN_IF(NS_FAILED(rv));
+ blockParent = mHTMLEditor->GetBlock(node);
+ if (NS_WARN_IF(!blockParent)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ if (NS_WARN_IF(blockParent == host)) {
+ // Didn't create a new block for some reason, fall back to <br>
+ rv = StandardBreakImpl(node, offset, aSelection);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ *aHandled = true;
+ return NS_OK;
+ }
+ }
// If block is empty, populate with br. (For example, imagine a div that
// contains the word "text". The user selects "text" and types return.
// "Text" is deleted leaving an empty block. We want to put in one br to
// make block have a line. Then code further below will put in a second br.)
bool isEmpty;
IsEmptyBlock(*blockParent, &isEmpty);
if (isEmpty) {
@@ -3471,49 +3527,56 @@ HTMLEditRules::WillMakeDefListItem(Selec
nsresult
HTMLEditRules::WillMakeBasicBlock(Selection& aSelection,
const nsAString& aBlockType,
bool* aCancel,
bool* aHandled)
{
MOZ_ASSERT(aCancel && aHandled);
- NS_ENSURE_STATE(mHTMLEditor);
- RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
-
OwningNonNull<nsIAtom> blockType = NS_Atomize(aBlockType);
WillInsert(aSelection, aCancel);
// We want to ignore result of WillInsert()
*aCancel = false;
- *aHandled = false;
+ *aHandled = true;
+
+ nsresult rv = MakeBasicBlock(aSelection, blockType);
+ Unused << NS_WARN_IF(NS_FAILED(rv));
+ return rv;
+}
+
+nsresult
+HTMLEditRules::MakeBasicBlock(Selection& aSelection, nsIAtom& blockType)
+{
+ NS_ENSURE_STATE(mHTMLEditor);
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
nsresult rv = NormalizeSelection(&aSelection);
NS_ENSURE_SUCCESS(rv, rv);
AutoSelectionRestorer selectionRestorer(&aSelection, htmlEditor);
AutoTransactionsConserveSelection dontSpazMySelection(htmlEditor);
- *aHandled = true;
// Contruct a list of nodes to act on.
nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
rv = GetNodesFromSelection(aSelection, EditAction::makeBasicBlock,
arrayOfNodes);
NS_ENSURE_SUCCESS(rv, rv);
// If nothing visible in list, make an empty block
if (ListIsEmptyLine(arrayOfNodes)) {
// Get selection location
NS_ENSURE_STATE(aSelection.GetRangeAt(0) &&
aSelection.GetRangeAt(0)->GetStartParent());
OwningNonNull<nsINode> parent =
*aSelection.GetRangeAt(0)->GetStartParent();
int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
- if (blockType == nsGkAtoms::normal ||
- blockType == nsGkAtoms::_empty) {
+ if (&blockType == nsGkAtoms::normal ||
+ &blockType == nsGkAtoms::_empty) {
// We are removing blocks (going to "body text")
NS_ENSURE_TRUE(htmlEditor->GetBlock(parent), NS_ERROR_NULL_POINTER);
OwningNonNull<Element> curBlock = *htmlEditor->GetBlock(parent);
if (HTMLEditUtils::IsFormatNode(curBlock)) {
// If the first editable node after selection is a br, consume it.
// Otherwise it gets pushed into a following block after the split,
// which is visually bad.
nsCOMPtr<nsIContent> brNode =
@@ -3526,17 +3589,16 @@ HTMLEditRules::WillMakeBasicBlock(Select
offset = htmlEditor->SplitNodeDeep(curBlock, *parent->AsContent(),
offset,
HTMLEditor::EmptyContainers::no);
NS_ENSURE_STATE(offset != -1);
// Put a br at the split point
brNode = htmlEditor->CreateBR(curBlock->GetParentNode(), offset);
NS_ENSURE_STATE(brNode);
// Put selection at the split point
- *aHandled = true;
rv = aSelection.Collapse(curBlock->GetParentNode(), offset);
// Don't restore the selection
selectionRestorer.Abort();
NS_ENSURE_SUCCESS(rv, rv);
}
// Else nothing to do!
} else {
// We are making a block. Consume a br, if needed.
@@ -3547,44 +3609,43 @@ HTMLEditRules::WillMakeBasicBlock(Select
NS_ENSURE_SUCCESS(rv, rv);
// We don't need to act on this node any more
arrayOfNodes.RemoveElement(brNode);
}
// Make sure we can put a block here
rv = SplitAsNeeded(blockType, parent, offset);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Element> block =
- htmlEditor->CreateNode(blockType, parent, offset);
+ htmlEditor->CreateNode(&blockType, parent, offset);
NS_ENSURE_STATE(block);
// Remember our new block for postprocessing
mNewBlock = block;
// Delete anything that was in the list of nodes
while (!arrayOfNodes.IsEmpty()) {
OwningNonNull<nsINode> curNode = arrayOfNodes[0];
rv = htmlEditor->DeleteNode(curNode);
NS_ENSURE_SUCCESS(rv, rv);
arrayOfNodes.RemoveElementAt(0);
}
// Put selection in new block
- *aHandled = true;
rv = aSelection.Collapse(block, 0);
// Don't restore the selection
selectionRestorer.Abort();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
// Okay, now go through all the nodes and make the right kind of blocks, or
// whatever is approriate. Woohoo! Note: blockquote is handled a little
// differently.
- if (blockType == nsGkAtoms::blockquote) {
+ if (&blockType == nsGkAtoms::blockquote) {
rv = MakeBlockquote(arrayOfNodes);
NS_ENSURE_SUCCESS(rv, rv);
- } else if (blockType == nsGkAtoms::normal ||
- blockType == nsGkAtoms::_empty) {
+ } else if (&blockType == nsGkAtoms::normal ||
+ &blockType == nsGkAtoms::_empty) {
rv = RemoveBlockStyle(arrayOfNodes);
NS_ENSURE_SUCCESS(rv, rv);
} else {
rv = ApplyBlockStyle(arrayOfNodes, blockType);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
@@ -6939,16 +7000,21 @@ HTMLEditRules::ApplyBlockStyle(nsTArray<
NS_ENSURE_SUCCESS(rv, rv);
curBlock = htmlEditor->CreateNode(&aBlockTag, curParent, offset);
NS_ENSURE_STATE(curBlock);
// Remember our new block for postprocessing
mNewBlock = curBlock;
// Note: doesn't matter if we set mNewBlock multiple times.
}
+ if (NS_WARN_IF(!curNode->GetParentNode())) {
+ // This is possible due to mutation events, let's not assert
+ return NS_ERROR_UNEXPECTED;
+ }
+
// XXX If curNode is a br, replace it with a return if going to <pre>
// This is a continuation of some inline nodes that belong together in
// the same block item. Use curBlock.
nsresult rv = htmlEditor->MoveNode(curNode->AsContent(), curBlock, -1);
NS_ENSURE_SUCCESS(rv, rv);
}
}
--- a/testing/web-platform/meta/editing/run/insertparagraph.html.ini
+++ b/testing/web-platform/meta/editing/run/insertparagraph.html.ini
@@ -1,25 +1,13 @@
[insertparagraph.html]
type: testharness
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "foo[bar\]baz" compare innerHTML]
- expected: FAIL
-
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "foo[bar\]baz" queryCommandValue("defaultparagraphseparator") before]
expected: FAIL
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "foo[bar\]baz" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "fo[o<table><tr><td>b\]ar</table>" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "fo[o<table><tr><td>b\]ar</table>" compare innerHTML]
- expected: FAIL
-
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<table><tr><td>[foo<td>bar\]<tr><td>baz<td>quz</table>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<table><tr><td>[foo<td>bar\]<tr><td>baz<td>quz</table>" compare innerHTML]
expected: FAIL
[[["insertparagraph",""\]\] "<table><tbody data-start=0 data-end=1><tr><td>foo<td>bar<tr><td>baz<td>quz</table>" compare innerHTML]
expected: FAIL
@@ -46,46 +34,22 @@
expected: FAIL
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<table><tr><td>[foo\]</table>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<ol><li>[foo\]<li>bar</ol>" compare innerHTML]
expected: FAIL
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "[\]foo" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "[\]foo" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "foo[\]" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "foo[\]" compare innerHTML]
- expected: FAIL
-
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<span>foo[\]</span>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<span>foo[\]</span>" compare innerHTML]
expected: FAIL
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "foo[\]<br>" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "foo[\]<br>" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "foo[\]bar" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "foo[\]bar" compare innerHTML]
- expected: FAIL
-
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<h1>foo[\]</h1>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<h1>foo[\]<br></h1>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<script>foo[\]bar</script>baz" compare innerHTML]
expected: FAIL
@@ -178,94 +142,34 @@
expected: FAIL
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<blockquote>foo[\]bar</blockquote>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<blockquote>foo[\]bar</blockquote>" compare innerHTML]
expected: FAIL
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<span>foo[\]bar</span>" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<span>foo[\]bar</span>" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<span>foo[\]bar</span>baz" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<span>foo[\]bar</span>baz" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","true"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<b>foo[\]bar</b>" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","false"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<b>foo[\]bar</b>" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","true"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<b>foo[\]bar</b>" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","false"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<b>foo[\]bar</b>" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","true"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<b>foo[\]bar</b>baz" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","false"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<b>foo[\]bar</b>baz" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","true"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<b>foo[\]bar</b>baz" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","false"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<b>foo[\]bar</b>baz" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<b>foo[\]</b>bar" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<b>foo[\]</b>bar" compare innerHTML]
- expected: FAIL
-
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "foo<b>[\]bar</b>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "foo<b>[\]bar</b>" compare innerHTML]
expected: FAIL
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<b>foo[\]</b><i>bar</i>" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<b>foo[\]</b><i>bar</i>" compare innerHTML]
- expected: FAIL
-
[[["stylewithcss","true"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<b id=x class=y>foo[\]bar</b>" compare innerHTML]
expected: FAIL
[[["stylewithcss","false"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<b id=x class=y>foo[\]bar</b>" compare innerHTML]
expected: FAIL
[[["stylewithcss","true"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<b id=x class=y>foo[\]bar</b>" compare innerHTML]
expected: FAIL
[[["stylewithcss","false"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<b id=x class=y>foo[\]bar</b>" compare innerHTML]
expected: FAIL
- [[["stylewithcss","true"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<i><b>foo[\]bar</b>baz</i>" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","false"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<i><b>foo[\]bar</b>baz</i>" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","true"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<i><b>foo[\]bar</b>baz</i>" compare innerHTML]
- expected: FAIL
-
- [[["stylewithcss","false"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<i><b>foo[\]bar</b>baz</i>" compare innerHTML]
- expected: FAIL
-
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<p><b>[\]foo</b></p>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<p><b>[\]foo</b></p>" compare innerHTML]
expected: FAIL
[[["stylewithcss","true"\],["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<p><b id=x class=y>foo[\]bar</b></p>" compare innerHTML]
expected: FAIL
@@ -274,34 +178,16 @@
expected: FAIL
[[["stylewithcss","true"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<p><b id=x class=y>foo[\]bar</b></p>" compare innerHTML]
expected: FAIL
[[["stylewithcss","false"\],["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<p><b id=x class=y>foo[\]bar</b></p>" compare innerHTML]
expected: FAIL
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<a href=foo>foo[\]bar</a>" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<a href=foo>foo[\]bar</a>" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<a href=foo>foo[\]bar</a>baz" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<a href=foo>foo[\]bar</a>baz" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<a href=foo>foo[\]</a>bar" compare innerHTML]
- expected: FAIL
-
- [[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<a href=foo>foo[\]</a>bar" compare innerHTML]
- expected: FAIL
-
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "foo<a href=foo>[\]bar</a>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "foo<a href=foo>[\]bar</a>" compare innerHTML]
expected: FAIL
[[["defaultparagraphseparator","div"\],["insertparagraph",""\]\] "<p>foo[\]<!--bar-->" compare innerHTML]
expected: FAIL