[XForms] NPOTDB insert cant handle empty target nodeset. Bug 389016, r=olli+aaronr

This commit is contained in:
aaronr%us.ibm.com 2007-08-04 00:19:52 +00:00
Родитель 6285661069
Коммит a5a6a473b5
1 изменённых файлов: 62 добавлений и 29 удалений

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

@ -77,6 +77,12 @@ class nsXFormsInsertDeleteElement : public nsXFormsActionModuleBase
private: private:
PRBool mIsInsert; PRBool mIsInsert;
enum Location {
eLocation_After,
eLocation_Before,
eLocation_FirstChild,
};
/** Get the first node of a given type in aNodes. /** Get the first node of a given type in aNodes.
* *
* @param aNodes array of nodes * @param aNodes array of nodes
@ -92,12 +98,12 @@ private:
* *
* @param aTargetNode target location node * @param aTargetNode target location node
* @param aNewNode node to insert * @param aNewNode node to insert
* @param aInsertAfter insert before or after target? * @param aLocation insert location relative to target
* *
* @return aResult result node * @return aResult result node
*/ */
nsresult InsertNode(nsIDOMNode *aTargetNode, nsIDOMNode *aNewNode, nsresult InsertNode(nsIDOMNode *aTargetNode, nsIDOMNode *aNewNode,
PRBool aInsertAfter, nsIDOMNode **aResNode); Location aLocation, nsIDOMNode **aResNode);
nsresult RefreshRepeats(nsCOMArray<nsIDOMNode> *aNodes); nsresult RefreshRepeats(nsCOMArray<nsIDOMNode> *aNodes);
@ -463,15 +469,24 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent,
// the first attribute of the insert location node. If the cloned node is // the first attribute of the insert location node. If the cloned node is
// not an attribute, then the target location is before the first child // not an attribute, then the target location is before the first child
// of the insert location node. // of the insert location node.
if (!nodeset || if ((!nodeset || nodesetSize < 1) ||
(nodeset && nodesetSize > 1 && newNodeType != locationNodeType)) { (nodeset && nodesetSize > 1 && newNodeType != locationNodeType)) {
Location location = eLocation_Before;
if (newNodeType != nsIDOMNode::ATTRIBUTE_NODE) { if (newNodeType != nsIDOMNode::ATTRIBUTE_NODE) {
// target location is before first child of location node. // Target location is before the first child of location node. If the
// location node is empty (has no children), it remains the location
// node and the new node will become the first child of the location
// node.
nsCOMPtr<nsIDOMNode> targetNode; nsCOMPtr<nsIDOMNode> targetNode;
locationNode->GetFirstChild(getter_AddRefs(targetNode)); locationNode->GetFirstChild(getter_AddRefs(targetNode));
locationNode.swap(targetNode); if (targetNode) {
locationNode.swap(targetNode);
} else {
// New node will become first child of locationNode.
location = eLocation_FirstChild;
}
} }
InsertNode(locationNode, newNode, PR_FALSE, getter_AddRefs(resNode)); InsertNode(locationNode, newNode, location, getter_AddRefs(resNode));
} else { } else {
// Step 6c - If insert location node is the root element of an // Step 6c - If insert location node is the root element of an
// instance, then that instance root element location is the target // instance, then that instance root element location is the target
@ -512,7 +527,9 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} }
InsertNode(locationNode, newNode, insertAfter, getter_AddRefs(resNode)); InsertNode(locationNode, newNode,
insertAfter ? eLocation_After: eLocation_Before,
getter_AddRefs(resNode));
} }
} }
} }
@ -559,20 +576,35 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent,
while ((deleteIndex < deleteCount) && locationNode) { while ((deleteIndex < deleteCount) && locationNode) {
// Delete the node(s) unless the delete location is the root document // Delete the node(s) unless the delete location is the root document
// element of an instance. // element of an instance.
if (!SameCOMIdentity(locationNode, locationDocElement)) { PRUint16 locationNodeType;
locationNode->GetParentNode(getter_AddRefs(parentNode)); locationNode->GetNodeType(&locationNodeType);
NS_ENSURE_STATE(parentNode); if (locationNodeType == nsIDOMNode::ATTRIBUTE_NODE) {
nsCOMPtr<nsIDOMElement> ownerElement;
nsCOMPtr<nsIDOMAttr> attrNode(do_QueryInterface(locationNode));
attrNode->GetOwnerElement(getter_AddRefs(ownerElement));
NS_ENSURE_STATE(ownerElement);
rv = parentNode->RemoveChild(locationNode, getter_AddRefs(resNode)); nsCOMPtr<nsIDOMAttr> resAttr;
NS_ENSURE_SUCCESS(rv, rv); ownerElement->RemoveAttributeNode(attrNode, getter_AddRefs(resAttr));
resNode = locationNode;
// Get the next node in the node-set.
++deleteIndex;
nodeset->SnapshotItem(deleteIndex, getter_AddRefs(locationNode));
// Deleted at least one node so delete will not terminate. // Deleted at least one node so delete will not terminate.
didDelete = PR_TRUE; didDelete = PR_TRUE;
} else {
if (!SameCOMIdentity(locationNode, locationDocElement)) {
locationNode->GetParentNode(getter_AddRefs(parentNode));
NS_ENSURE_STATE(parentNode);
rv = parentNode->RemoveChild(locationNode, getter_AddRefs(resNode));
NS_ENSURE_SUCCESS(rv, rv);
// Deleted at least one node so delete will not terminate.
didDelete = PR_TRUE;
}
} }
// Get the next node in the node-set.
++deleteIndex;
nodeset->SnapshotItem(deleteIndex, getter_AddRefs(locationNode));
} }
// The delete action is terminated with no effect if no node is deleted. // The delete action is terminated with no effect if no node is deleted.
@ -631,7 +663,7 @@ nsXFormsInsertDeleteElement::GetFirstNodeOfType(nsCOMArray<nsIDOMNode> *aNodes,
nsresult nsresult
nsXFormsInsertDeleteElement::InsertNode(nsIDOMNode *aTargetNode, nsXFormsInsertDeleteElement::InsertNode(nsIDOMNode *aTargetNode,
nsIDOMNode *aNewNode, nsIDOMNode *aNewNode,
PRBool aInsertAfter, Location aLocation,
nsIDOMNode **aResNode) nsIDOMNode **aResNode)
{ {
NS_ENSURE_ARG(aTargetNode); NS_ENSURE_ARG(aTargetNode);
@ -657,16 +689,17 @@ nsXFormsInsertDeleteElement::InsertNode(nsIDOMNode *aTargetNode,
// Can add an attribute to an element node or the owning element // Can add an attribute to an element node or the owning element
// of an attribute node. // of an attribute node.
nsCOMPtr<nsIDOMElement> ownerElement; nsCOMPtr<nsIDOMElement> ownerElement;
nsCOMPtr<nsIDOMAttr> attrNode(do_QueryInterface(aNewNode));
if (targetNodeType == nsIDOMNode::ELEMENT_NODE) { if (targetNodeType == nsIDOMNode::ELEMENT_NODE) {
ownerElement = do_QueryInterface(aTargetNode); ownerElement = do_QueryInterface(aTargetNode);
} else if (targetNodeType == nsIDOMNode::ATTRIBUTE_NODE) { } else if (targetNodeType == nsIDOMNode::ATTRIBUTE_NODE) {
attrNode->GetOwnerElement(getter_AddRefs(ownerElement)); nsCOMPtr<nsIDOMAttr> targetAttrNode(do_QueryInterface(aTargetNode));
targetAttrNode->GetOwnerElement(getter_AddRefs(ownerElement));
} }
NS_ENSURE_STATE(ownerElement); NS_ENSURE_STATE(ownerElement);
// Check for a duplicate attribute. // Check for a duplicate attribute.
nsCOMPtr<nsIDOMAttr> attrNode(do_QueryInterface(aNewNode));
nsAutoString attrName, attrValue; nsAutoString attrName, attrValue;
attrNode->GetName(attrName); attrNode->GetName(attrName);
attrNode->GetValue(attrValue); attrNode->GetValue(attrValue);
@ -681,18 +714,18 @@ nsXFormsInsertDeleteElement::InsertNode(nsIDOMNode *aTargetNode,
resNode.swap(*aResNode); resNode.swap(*aResNode);
} else { } else {
// New node is not an attribute so it can only be inserted to an // New node will be inserted at location aLocation.
// element node. nsCOMPtr<nsIDOMNode> targetNode = aTargetNode;
if (targetNodeType == nsIDOMNode::ELEMENT_NODE) {
// New node will be inserted either before or after targetNode.
nsCOMPtr<nsIDOMNode> targetNode;
targetNode = aTargetNode;
nsCOMPtr<nsIDOMNode> parentNode; nsCOMPtr<nsIDOMNode> parentNode;
targetNode->GetParentNode(getter_AddRefs(parentNode)); targetNode->GetParentNode(getter_AddRefs(parentNode));
NS_ENSURE_STATE(parentNode); NS_ENSURE_STATE(parentNode);
if (aInsertAfter) { if (aLocation == eLocation_FirstChild) {
aTargetNode->AppendChild(aNewNode, getter_AddRefs(resNode));
resNode.swap(*aResNode);
} else {
if (aLocation == eLocation_After) {
// If we're at the end of the nodeset, this returns nsnull, which is // If we're at the end of the nodeset, this returns nsnull, which is
// fine, because InsertBefore then inserts at the end of the nodeset. // fine, because InsertBefore then inserts at the end of the nodeset.
aTargetNode->GetNextSibling(getter_AddRefs(targetNode)); aTargetNode->GetNextSibling(getter_AddRefs(targetNode));