Bug 1451672 - part 14: Rename EditorBase::ReplaceContainer() to EditorBase::ReplaceContainerWithTransactionInternal() and create some wrappers of it r=m_kato

The parameters of EditorBase::ReplaceContainer() are complicated.  For example,
if it's specified as cloning all attributes, aAttribute and aValue are ignored
because CloneAttributes() removes all existing attributes but ReplaceContainer()
sets attributes before calling CloneAttributes().  This method has 3 modes:
1. Just replaces aOldContainer with new element.
2. #1 and clones all attributes from aOldContainer to the new element.
3. #1 and sets aAttribute of the new element to aValue.

Therefore, this patch creates 3 inline wrappers of the renamed method.

MozReview-Commit-ID: IsPu2uZuU8f

--HG--
extra : rebase_source : 02a23f48a91e0c9558126552a4c8d4b12c8b76bc
This commit is contained in:
Masayuki Nakano 2018-04-12 21:45:55 +09:00
Родитель e31bcb6efe
Коммит b7fe9939db
4 изменённых файлов: 145 добавлений и 56 удалений

Просмотреть файл

@ -1653,52 +1653,47 @@ EditorBase::DeleteNodeWithTransaction(nsINode& aNode)
return NS_OK;
}
/**
* ReplaceContainer() replaces inNode with a new node (outNode) which is
* constructed to be of type aNodeType. Put inNodes children into outNode.
* Callers responsibility to make sure inNode's children can go in outNode.
*/
already_AddRefed<Element>
EditorBase::ReplaceContainer(Element* aOldContainer,
nsAtom* aNodeType,
nsAtom* aAttribute,
const nsAString* aValue,
ECloneAttributes aCloneAttributes)
EditorBase::ReplaceContainerWithTransactionInternal(
Element& aOldContainer,
nsAtom& aTagName,
nsAtom& aAttribute,
const nsAString& aAttributeValue,
bool aCloneAllAttributes)
{
MOZ_ASSERT(aOldContainer && aNodeType);
EditorDOMPoint atOldContainer(aOldContainer);
EditorDOMPoint atOldContainer(&aOldContainer);
if (NS_WARN_IF(!atOldContainer.IsSet())) {
return nullptr;
}
RefPtr<Element> newContainer = CreateHTMLContent(aNodeType);
RefPtr<Element> newContainer = CreateHTMLContent(&aTagName);
if (NS_WARN_IF(!newContainer)) {
return nullptr;
}
// Set attribute if needed.
if (aAttribute && aValue && aAttribute != nsGkAtoms::_empty) {
// Set or clone attribute if needed.
if (aCloneAllAttributes) {
MOZ_ASSERT(&aAttribute == nsGkAtoms::_empty);
CloneAttributes(newContainer, &aOldContainer);
} else if (&aAttribute != nsGkAtoms::_empty) {
nsresult rv =
newContainer->SetAttr(kNameSpaceID_None, aAttribute, *aValue, true);
newContainer->SetAttr(kNameSpaceID_None, &aAttribute, aAttributeValue,
true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
}
if (aCloneAttributes == eCloneAttributes) {
CloneAttributes(newContainer, aOldContainer);
}
// Notify our internal selection state listener.
// Note: An AutoSelectionRestorer object must be created before calling this
// to initialize mRangeUpdater.
AutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, aOldContainer,
AutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, &aOldContainer,
newContainer);
{
AutoTransactionsConserveSelection conserveSelection(this);
// Move all children from the old container to the new container.
while (aOldContainer->HasChildren()) {
nsCOMPtr<nsIContent> child = aOldContainer->GetFirstChild();
while (aOldContainer.HasChildren()) {
nsCOMPtr<nsIContent> child = aOldContainer.GetFirstChild();
if (NS_WARN_IF(!child)) {
return nullptr;
}
@ -1725,7 +1720,7 @@ EditorBase::ReplaceContainer(Element* aOldContainer,
}
// Delete old container.
rv = DeleteNodeWithTransaction(*aOldContainer);
rv = DeleteNodeWithTransaction(aOldContainer);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}

Просмотреть файл

@ -365,13 +365,66 @@ public:
InsertNodeWithTransaction(nsIContent& aContentToInsert,
const EditorDOMPointBase<PT, CT>& aPointToInsert);
enum ECloneAttributes { eDontCloneAttributes, eCloneAttributes };
already_AddRefed<Element> ReplaceContainer(Element* aOldContainer,
nsAtom* aNodeType,
nsAtom* aAttribute = nullptr,
const nsAString* aValue = nullptr,
ECloneAttributes aCloneAttributes
= eDontCloneAttributes);
/**
* ReplaceContainerWithTransaction() creates new element whose name is
* aTagName, moves all children in aOldContainer to the new element, then,
* removes aOldContainer from the DOM tree.
*
* @param aOldContainer The element node which should be replaced
* with new element.
* @param aTagName The name of new element node.
*/
already_AddRefed<Element>
ReplaceContainerWithTransaction(Element& aOldContainer,
nsAtom& aTagName)
{
return ReplaceContainerWithTransactionInternal(aOldContainer, aTagName,
*nsGkAtoms::_empty,
EmptyString(), false);
}
/**
* ReplaceContainerAndCloneAttributesWithTransaction() creates new element
* whose name is aTagName, copies all attributes from aOldContainer to the
* new element, moves all children in aOldContainer to the new element, then,
* removes aOldContainer from the DOM tree.
*
* @param aOldContainer The element node which should be replaced
* with new element.
* @param aTagName The name of new element node.
*/
already_AddRefed<Element>
ReplaceContainerAndCloneAttributesWithTransaction(Element& aOldContainer,
nsAtom& aTagName)
{
return ReplaceContainerWithTransactionInternal(aOldContainer, aTagName,
*nsGkAtoms::_empty,
EmptyString(), true);
}
/**
* ReplaceContainerWithTransaction() creates new element whose name is
* aTagName, sets aAttributes of the new element to aAttributeValue, moves
* all children in aOldContainer to the new element, then, removes
* aOldContainer from the DOM tree.
*
* @param aOldContainer The element node which should be replaced
* with new element.
* @param aTagName The name of new element node.
* @param aAttribute Attribute name to be set to the new element.
* @param aAttributeValue Attribute value to be set to aAttribute.
*/
already_AddRefed<Element>
ReplaceContainerWithTransaction(Element& aOldContainer,
nsAtom& aTagName,
nsAtom& aAttribute,
const nsAString& aAttributeValue)
{
return ReplaceContainerWithTransactionInternal(aOldContainer, aTagName,
aAttribute,
aAttributeValue, false);
}
void CloneAttributes(Element* aDest, Element* aSource);
nsresult RemoveContainer(nsIContent* aNode);
@ -629,6 +682,29 @@ protected:
nsresult DeleteTextWithTransaction(dom::CharacterData& aCharacterData,
uint32_t aOffset, uint32_t aLength);
/**
* ReplaceContainerWithTransactionInternal() is implementation of
* ReplaceContainerWithTransaction() and
* ReplaceContainerAndCloneAttributesWithTransaction().
*
* @param aOldContainer The element which will be replaced with new
* element.
* @param aTagName The name of new element node.
* @param aAttribute Attribute name which will be set to the new
* element. This will be ignored if
* aCloneAllAttributes is set to true.
* @param aAttributeValue Attribute value which will be set to
* aAttribute.
* @param aCloneAllAttributes If true, all attributes of aOldContainer will
* be copied to the new element.
*/
already_AddRefed<Element>
ReplaceContainerWithTransactionInternal(Element& aElement,
nsAtom& aTagName,
nsAtom& aAttribute,
const nsAString& aAttributeValue,
bool aCloneAllAttributes);
/**
* Called after a transaction is done successfully.
*/

Просмотреть файл

@ -3788,9 +3788,12 @@ HTMLEditRules::WillMakeList(Selection* aSelection,
NS_ENSURE_SUCCESS(rv, rv);
// convert list item type if needed
if (!curNode->IsHTMLElement(itemType)) {
newBlock = htmlEditor->ReplaceContainer(curNode->AsElement(),
itemType);
NS_ENSURE_STATE(newBlock);
newBlock =
htmlEditor->ReplaceContainerWithTransaction(*curNode->AsElement(),
*itemType);
if (NS_WARN_IF(!newBlock)) {
return NS_ERROR_FAILURE;
}
}
} else {
// item is in right type of list. But we might still have to move it.
@ -3803,9 +3806,12 @@ HTMLEditRules::WillMakeList(Selection* aSelection,
NS_ENSURE_SUCCESS(rv, rv);
}
if (!curNode->IsHTMLElement(itemType)) {
newBlock = htmlEditor->ReplaceContainer(curNode->AsElement(),
itemType);
NS_ENSURE_STATE(newBlock);
newBlock =
htmlEditor->ReplaceContainerWithTransaction(*curNode->AsElement(),
*itemType);
if (NS_WARN_IF(!newBlock)) {
return NS_ERROR_FAILURE;
}
}
}
nsCOMPtr<Element> curElement = do_QueryInterface(curNode);
@ -3875,9 +3881,12 @@ HTMLEditRules::WillMakeList(Selection* aSelection,
} else {
// don't wrap li around a paragraph. instead replace paragraph with li
if (curNode->IsHTMLElement(nsGkAtoms::p)) {
listItem = htmlEditor->ReplaceContainer(curNode->AsElement(),
itemType);
NS_ENSURE_STATE(listItem);
listItem =
htmlEditor->ReplaceContainerWithTransaction(*curNode->AsElement(),
*itemType);
if (NS_WARN_IF(!listItem)) {
return NS_ERROR_FAILURE;
}
} else {
listItem = htmlEditor->InsertContainerAbove(curNode, itemType);
NS_ENSURE_STATE(listItem);
@ -5021,7 +5030,8 @@ HTMLEditRules::ConvertListType(Element* aList,
dom::Element* element = child->AsElement();
if (HTMLEditUtils::IsListItem(element) &&
!element->IsHTMLElement(aItemType)) {
child = mHTMLEditor->ReplaceContainer(element, aItemType);
child =
mHTMLEditor->ReplaceContainerWithTransaction(*element, *aItemType);
if (NS_WARN_IF(!child)) {
return nullptr;
}
@ -5041,7 +5051,7 @@ HTMLEditRules::ConvertListType(Element* aList,
return list.forget();
}
return mHTMLEditor->ReplaceContainer(aList, aListType);
return mHTMLEditor->ReplaceContainerWithTransaction(*aList, *aListType);
}
@ -7747,9 +7757,8 @@ HTMLEditRules::ApplyBlockStyle(nsTArray<OwningNonNull<nsINode>>& aNodeArray,
// Forget any previous block used for previous inline nodes
curBlock = nullptr;
newBlock =
htmlEditor->ReplaceContainer(curNode->AsElement(),
&aBlockTag, nullptr, nullptr,
EditorBase::eCloneAttributes);
htmlEditor->ReplaceContainerAndCloneAttributesWithTransaction(
*curNode->AsElement(), aBlockTag);
NS_ENSURE_STATE(newBlock);
continue;
}

Просмотреть файл

@ -1970,32 +1970,41 @@ HTMLEditor::SwitchTableCellHeaderType(nsIDOMElement* aSourceCell,
nsIDOMElement** aNewCell)
{
nsCOMPtr<Element> sourceCell = do_QueryInterface(aSourceCell);
NS_ENSURE_TRUE(sourceCell, NS_ERROR_NULL_POINTER);
if (NS_WARN_IF(!sourceCell)) {
return NS_ERROR_INVALID_ARG;
}
AutoPlaceholderBatch beginBatching(this);
// Prevent auto insertion of BR in new cell created by ReplaceContainer
// Prevent auto insertion of BR in new cell created by
// ReplaceContainerAndCloneAttributesWithTransaction().
AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
// Save current selection to restore when done
// This is needed so ReplaceContainer can monitor selection
// when replacing nodes
// Save current selection to restore when done.
// This is needed so ReplaceContainerAndCloneAttributesWithTransaction()
// can monitor selection when replacing nodes.
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
AutoSelectionRestorer selectionRestorer(selection, this);
// Set to the opposite of current type
nsAtom* newCellType =
nsAtom* newCellName =
sourceCell->IsHTMLElement(nsGkAtoms::td) ? nsGkAtoms::th : nsGkAtoms::td;
// This creates new node, moves children, copies attributes (true)
// and manages the selection!
nsCOMPtr<Element> newNode = ReplaceContainer(sourceCell, newCellType,
nullptr, nullptr, EditorBase::eCloneAttributes);
NS_ENSURE_TRUE(newNode, NS_ERROR_FAILURE);
RefPtr<Element> newCell =
ReplaceContainerAndCloneAttributesWithTransaction(*sourceCell,
*newCellName);
if (NS_WARN_IF(!newCell)) {
return NS_ERROR_FAILURE;
}
// Return the new cell
if (aNewCell) {
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newNode);
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newCell);
*aNewCell = newElement.get();
NS_ADDREF(*aNewCell);
}