[XForms] Modify repeat-index on insert and delete. Bug 282828, r=doronr+aaronr

This commit is contained in:
allan%beaufour.dk 2006-03-29 07:39:28 +00:00
Родитель fb61e2e53f
Коммит 290986c899
3 изменённых файлов: 176 добавлений и 32 удалений

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

@ -46,7 +46,7 @@
interface nsIXFormsControl;
interface nsIDOMNode;
[uuid(419e780d-4f31-4aa4-bae8-a18099d77bb6)]
[uuid(41a0ea05-3fe0-48e8-8c38-96cbb544309c)]
interface nsIXFormsRepeatElement : nsISupports
{
/**
@ -115,5 +115,19 @@ interface nsIXFormsRepeatElement : nsISupports
*/
void indexHasChanged();
/**
* Retrieve the starting index for the repeat, that is the index that the
* repeat is initialized to. It is the "startindex" attribute, corrected to
* be a valid index value.
*/
unsigned long getStartingIndex();
/**
* Handle insertion of a node, ie. eventually adjust index. Note that the
* node might not be influencing the repeat, it is the repeat's
* responsibility to check that.
*
* @param node The node that was inserted
*/
void handleNodeInsert(in nsIDOMNode node);
};

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

@ -41,6 +41,8 @@
#include "nsIDOMElement.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNodeList.h"
#include "nsIXFormsRepeatElement.h"
#include "nsIXFormsControl.h"
#include "nsString.h"
@ -48,6 +50,7 @@
#include "nsXFormsActionModuleBase.h"
#include "nsXFormsActionElement.h"
#include "nsXFormsUtils.h"
#include "nsIDOM3Node.h"
#include "math.h"
@ -65,14 +68,14 @@
* @see http://www.w3.org/TR/xforms/slice4.html#evt-insert
* @see https://bugzilla.mozilla.org/show_bug.cgi?id=280423
*
* @todo Any \<repeat\> elements need to set their repeat-indexes properly if
* they are bound to the same nodeset. (XXX)
*/
class nsXFormsInsertDeleteElement : public nsXFormsActionModuleBase
{
private:
PRBool mIsInsert;
nsresult RefreshRepeats(nsIDOMNode *aNode);
public:
NS_DECL_NSIXFORMSACTIONMODULEELEMENT
@ -200,7 +203,6 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent,
nsCOMPtr<nsIDOMNode> resNode;
if (mIsInsert) {
//
// Get prototype and clone it (last member of nodeset)
nsCOMPtr<nsIDOMNode> prototype;
nodeset->SnapshotItem(setSize - 1, getter_AddRefs(prototype));
@ -214,6 +216,11 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent,
location,
getter_AddRefs(resNode));
NS_ENSURE_STATE(resNode);
// Set indexes for repeats
rv = RefreshRepeats(resNode);
NS_ENSURE_SUCCESS(rv, rv);
} else {
rv = parent->RemoveChild(location, getter_AddRefs(resNode));
NS_ENSURE_SUCCESS(rv, rv);
@ -221,9 +228,6 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent,
// Dispatch xforms-insert/delete event to the instance node we have modified
// data for
nsCOMPtr<nsIDOMElement> modelElem = do_QueryInterface(model);
NS_ENSURE_STATE(modelElem);
nsCOMPtr<nsIDOMNode> instNode;
rv = nsXFormsUtils::GetInstanceNodeForData(resNode, getter_AddRefs(instNode));
NS_ENSURE_SUCCESS(rv, rv);
@ -233,6 +237,8 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent,
NS_ENSURE_SUCCESS(rv, rv);
// Dispatch refreshing events to the model
nsCOMPtr<nsIDOMElement> modelElem(do_QueryInterface(model));
NS_ASSERTION(modelElem, "Model not implementing nsIDOMElement?!");
if (aParentAction) {
aParentAction->SetRebuild(modelElem, PR_TRUE);
aParentAction->SetRecalculate(modelElem, PR_TRUE);
@ -248,6 +254,46 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent,
return NS_OK;
}
nsresult
nsXFormsInsertDeleteElement::RefreshRepeats(nsIDOMNode *aNode)
{
// XXXbeaufour: only check repeats belonging to the same model...
// possibly use mFormControls? Should be quicker than searching through
// entire document!! mModel->GetControls("repeat"); Would also possibly
// save a QI?
nsCOMPtr<nsIDOMDocument> document;
nsresult rv = mElement->GetOwnerDocument(getter_AddRefs(document));
NS_ENSURE_STATE(document);
nsCOMPtr<nsIDOMNodeList> repeatNodes;
document->GetElementsByTagNameNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
NS_LITERAL_STRING("repeat"),
getter_AddRefs(repeatNodes));
NS_ENSURE_STATE(repeatNodes);
// work over each node and if the node contains the inserted element
PRUint32 nodeCount;
rv = repeatNodes->GetLength(&nodeCount);
NS_ENSURE_SUCCESS(rv, rv);
for (PRUint32 node = 0; node < nodeCount; ++node) {
nsCOMPtr<nsIDOMNode> repeatNode;
rv = repeatNodes->Item(node, getter_AddRefs(repeatNode));
nsCOMPtr<nsIXFormsRepeatElement> repeatEl(do_QueryInterface(repeatNode));
NS_ENSURE_STATE(repeatEl);
rv = repeatEl->HandleNodeInsert(aNode);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
NS_HIDDEN_(nsresult)
NS_NewXFormsInsertElement(nsIXTFElement **aResult)
{

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

@ -293,6 +293,13 @@ protected:
*/
void MaybeBindAndRefresh(nsIAtom *aName);
/**
* Make sure that an index value is inside the valid index range.
*
* @param aIndex The index value to sanitize
* @param aIsScroll Send scroll events if first or last index?
*/
void SanitizeIndex(PRUint32 *aIndex, PRBool aIsScroll = PR_FALSE);
public:
NS_DECL_ISUPPORTS_INHERITED
@ -445,32 +452,32 @@ nsXFormsRepeatElement::SetIndex(PRUint32 *aIndex,
// Set repeat-index
if (mIsParent) {
NS_ASSERTION(mCurrentRepeat, "How can we be a repeat parent without a child?");
NS_ASSERTION(mCurrentRepeat,
"How can we be a repeat parent without a child?");
// We're the parent of nested repeats, set through the correct repeat
return mCurrentRepeat->SetIndex(aIndex, aIsRefresh);
}
// Do nothing if we are not showing anything
if (mMaxIndex == 0)
if (mMaxIndex == 0) {
// 9.3.6 states that the index position becomes 0 if there are
// no elements in the repeat.
mCurrentIndex = 0;
// XXXbeaufour: handle scroll-first/last
return NS_OK;
}
if (aIsRefresh && !mCurrentIndex) {
// If we are refreshing, get existing index value from parent
NS_ASSERTION(mParent, "SetIndex with aIsRefresh == PR_TRUE for a non-nested repeat?!");
NS_ASSERTION(mParent,
"SetIndex with aIsRefresh == PR_TRUE for a non-nested repeat?!");
rv = mParent->GetIndex(aIndex);
NS_ENSURE_SUCCESS(rv, rv);
}
// Check min. and max. value
if (*aIndex < 1) {
*aIndex = 1;
if (!aIsRefresh)
nsXFormsUtils::DispatchEvent(mElement, eEvent_ScrollFirst);
} else if (*aIndex > mMaxIndex) {
*aIndex = mMaxIndex;
if (!aIsRefresh)
nsXFormsUtils::DispatchEvent(mElement, eEvent_ScrollLast);
}
SanitizeIndex(aIndex, PR_TRUE);
// Do nothing if setting to existing value
if (!aIsRefresh && mCurrentIndex && *aIndex == mCurrentIndex)
@ -490,7 +497,9 @@ nsXFormsRepeatElement::SetIndex(PRUint32 *aIndex,
if (mCurrentIndex) {
// We had the previous selection, unset directly
SetChildIndex(mCurrentIndex, PR_FALSE, aIsRefresh);
} if (mParent) {
}
if (mParent) {
// Selection is in another repeat, inform parent (it will inform the
// previous owner of its new state)
rv = mParent->SetCurrentRepeat(this, *aIndex);
@ -542,11 +551,8 @@ nsXFormsRepeatElement::GetStartingIndex(PRUint32 *aRes)
if (NS_FAILED(rv)) {
*aRes = 1;
}
if (*aRes < 1) {
*aRes = 1;
} else if (*aRes > mMaxIndex) {
*aRes = mMaxIndex;
}
SanitizeIndex(aRes);
return NS_OK;
}
@ -677,6 +683,58 @@ nsXFormsRepeatElement::GetLevel(PRUint32 *aLevel)
return NS_OK;
}
NS_IMETHODIMP
nsXFormsRepeatElement::HandleNodeInsert(nsIDOMNode *aNode)
{
NS_ENSURE_STATE(mHTMLElement);
nsCOMPtr<nsIDOM3Node> node(do_QueryInterface(aNode));
NS_ENSURE_STATE(node);
// XXX, badness^2: If it is a insert we have to refresh before we can
// figure out whether the node is in our nodeset... refactor this so
// repeat actually gets the nodeset in Bind() and then uses it refresh,
// then we can "just" re-evaluate the nodeset, and only refresh if the
// node actually hits this repeat
// XXX, moreover it is also wrong to refresh at this point. It will happen
// in insert processing (and possibly deferred...)
nsresult rv = Refresh();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> child;
mHTMLElement->GetFirstChild(getter_AddRefs(child));
PRUint32 index = 1;
while (child) {
nsCOMPtr<nsIXFormsContextControl> context(do_QueryInterface(child));
NS_ASSERTION(context,
"repeat child not implementing nsIXFormsContextControl?!");
nsAutoString modelID;
PRInt32 position, size;
nsCOMPtr<nsIDOMNode> boundNode;
rv = context->GetContext(modelID, getter_AddRefs(boundNode), &position,
&size);
NS_ENSURE_SUCCESS(rv, rv);
PRBool sameNode = PR_FALSE;
node->IsSameNode(boundNode, &sameNode);
if (sameNode) {
rv = SetIndex(&index, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
break;
}
nsCOMPtr<nsIDOMNode> tmp;
child->GetNextSibling(getter_AddRefs(tmp));
child.swap(tmp);
++index;
}
return NS_OK;
}
// nsXFormsControl
NS_IMETHODIMP
@ -751,7 +809,7 @@ nsXFormsRepeatElement::Refresh()
for (PRUint32 i = 1; i < mMaxIndex + 1; ++i) {
// Create <contextcontainer>
nsCOMPtr<nsIDOMElement> riElement;
rv = domDoc->CreateElementNS(NS_LITERAL_STRING("http://www.w3.org/2002/xforms"),
rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
NS_LITERAL_STRING("contextcontainer"),
getter_AddRefs(riElement));
NS_ENSURE_SUCCESS(rv, rv);
@ -782,7 +840,8 @@ nsXFormsRepeatElement::Refresh()
rv = mHTMLElement->AppendChild(riElement, getter_AddRefs(domNode));
NS_ENSURE_SUCCESS(rv, rv);
// Iterate over template children, clone them, and append them to <contextcontainer>
// Iterate over template children, clone them, and append them to
// \<contextcontainer\>
nsCOMPtr<nsIDOMNode> child;
rv = mElement->GetFirstChild(getter_AddRefs(child));
NS_ENSURE_SUCCESS(rv, rv);
@ -803,7 +862,12 @@ nsXFormsRepeatElement::Refresh()
}
}
if (!mParent && !mCurrentIndex && mMaxIndex) {
if (mCurrentIndex) {
// somebody might have been fooling around with our children since last
// refresh (either using delete or through script, so check the index
// value
SanitizeIndex(&mCurrentIndex);
} else if (!mParent && mMaxIndex) {
// repeat-index has not been initialized, set it.
GetStartingIndex(&mCurrentIndex);
}
@ -835,11 +899,14 @@ nsXFormsRepeatElement::SetChildIndex(PRUint32 aPosition,
mHTMLElement->GetChildNodes(getter_AddRefs(children));
NS_ENSURE_STATE(children);
PRUint32 index = aPosition - 1; // Indexes are 1-based, the DOM is 0-based;
nsCOMPtr<nsIDOMNode> child;
children->Item(aPosition - 1, // Indexes are 1-based, the DOM is 0-based
children->Item(index,
getter_AddRefs(child));
nsCOMPtr<nsIXFormsRepeatItemElement> repeatItem = do_QueryInterface(child);
NS_ENSURE_STATE(repeatItem);
nsCOMPtr<nsIXFormsRepeatItemElement> repeatItem(do_QueryInterface(child));
NS_ASSERTION(repeatItem,
"repeat child not implementing nsIXFormsRepeatItemElement?!");
nsresult rv;
PRBool curState;
@ -860,6 +927,23 @@ nsXFormsRepeatElement::SetChildIndex(PRUint32 aPosition,
return NS_OK;
}
void
nsXFormsRepeatElement::SanitizeIndex(PRUint32 *aIndex, PRBool aIsScroll)
{
if (!aIndex)
return;
if (*aIndex < 1) {
*aIndex = 1;
if (aIsScroll)
nsXFormsUtils::DispatchEvent(mElement, eEvent_ScrollFirst);
} else if (*aIndex > mMaxIndex) {
*aIndex = mMaxIndex;
if (aIsScroll)
nsXFormsUtils::DispatchEvent(mElement, eEvent_ScrollLast);
}
}
nsresult
nsXFormsRepeatElement::ResetInnerRepeats(nsIDOMNode *aNode,
PRBool aIsRefresh)