зеркало из https://github.com/mozilla/pjs.git
[XForms] Modify repeat-index on insert and delete. Bug 282828, r=doronr+aaronr
This commit is contained in:
Родитель
fb61e2e53f
Коммит
290986c899
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче