NPOTDB Fix bug 368248 - getting binding exceptions with xforms:repeat. Patch by aaronr, r=smaug,me

git-svn-id: svn://10.0.0.236/trunk@221446 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
doronr%us.ibm.com 2007-03-07 17:46:57 +00:00
parent e5f33ecf20
commit 660dff3cf7
6 changed files with 124 additions and 65 deletions

View File

@ -137,6 +137,9 @@ public:
nsresult HandleFocus(nsIDOMEvent *aEvent);
// Overriding to make sure only appropriate values can be set.
void SetRepeatState(nsRepeatState aState);
#ifdef DEBUG_smaug
virtual const char* Name() {
if (mElement) {
@ -362,6 +365,21 @@ nsXFormsContextContainer::GetContextPosition(PRInt32 *aContextPosition)
return NS_OK;
}
void
nsXFormsContextContainer::SetRepeatState(nsRepeatState aState)
{
// A context container can have one of two states...eType_Unknown
// (uninitialized) and eType_GeneratedContent. This assumes
// that one cannot be generated outside of the repeat or itemset code.
nsRepeatState state = aState;
if (state != eType_Unknown) {
state = eType_GeneratedContent;
}
return nsXFormsControlStub::SetRepeatState(state);
}
// Factory
NS_HIDDEN_(nsresult)
NS_NewXFormsContextContainer(nsIXTFElement **aResult)

View File

@ -303,6 +303,12 @@ nsresult
nsXFormsControlStub::MaybeAddToModel(nsIModelElementPrivate *aOldModel,
nsIXFormsControl *aParent)
{
if (GetRepeatState() == eType_Template) {
// No sense going any further. A template control has no need to bind,
// refresh, etc. so no reason to put it on the model's control list
return NS_OK;
}
// XXX: just doing pointer comparison would be nice....
PRBool sameModel = PR_FALSE;
nsresult rv;
@ -410,6 +416,12 @@ nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr,
NS_IMETHODIMP
nsXFormsControlStub::BindToModel(PRBool aSetBoundNode)
{
if (GetRepeatState() == eType_Template) {
// No sense going any further. A template control has no need to bind,
// refresh, etc. so no reason to put it on the model's control list
return NS_OK;
}
nsCOMPtr<nsIModelElementPrivate> oldModel(mModel);
nsCOMPtr<nsIXFormsControl> parentControl;
@ -654,6 +666,7 @@ nsXFormsControlStub::ForceModelDetach(PRBool aRebind)
NS_IMETHODIMP
nsXFormsControlStub::WillChangeDocument(nsIDOMDocument *aNewDocument)
{
SetRepeatState(eType_Unknown);
ResetHelpAndHint(PR_FALSE);
return NS_OK;
}
@ -679,10 +692,21 @@ nsXFormsControlStub::DocumentChanged(nsIDOMDocument *aNewDocument)
return ForceModelDetach(mHasParent && aNewDocument);
}
NS_IMETHODIMP
nsXFormsControlStub::WillChangeParent(nsIDOMElement *aNewParent)
{
SetRepeatState(eType_Unknown);
return NS_OK;
}
NS_IMETHODIMP
nsXFormsControlStub::ParentChanged(nsIDOMElement *aNewParent)
{
mHasParent = aNewParent != nsnull;
UpdateRepeatState(aNewParent);
// We need to re-evaluate our instance data binding when our parent changes,
// since xmlns declarations or our context could have changed.
return ForceModelDetach(mHasParent);
@ -866,6 +890,47 @@ nsXFormsControlStub::IsContentComplex()
return isComplex;
}
nsRepeatState
nsXFormsControlStub::GetRepeatState()
{
return mRepeatState;
}
void
nsXFormsControlStub::SetRepeatState(nsRepeatState aState)
{
mRepeatState = aState;
return;
}
nsRepeatState
nsXFormsControlStub::UpdateRepeatState(nsIDOMNode *aParent)
{
nsRepeatState repeatState = eType_NotApplicable;
nsCOMPtr<nsIDOMNode> parent = aParent;
while (parent) {
if (nsXFormsUtils::IsXFormsElement(parent, NS_LITERAL_STRING("contextcontainer"))) {
repeatState = eType_GeneratedContent;
break;
}
if (nsXFormsUtils::IsXFormsElement(parent, NS_LITERAL_STRING("repeat"))) {
repeatState = eType_Template;
break;
}
if (nsXFormsUtils::IsXFormsElement(parent, NS_LITERAL_STRING("itemset"))) {
repeatState = eType_Template;
break;
}
nsCOMPtr<nsIDOMNode> tmp;
parent->GetParentNode(getter_AddRefs(tmp));
parent = tmp;
}
SetRepeatState(repeatState);
return repeatState;
}
NS_IMPL_ISUPPORTS_INHERITED3(nsXFormsControlStub,
nsXFormsStubElement,
nsIXFormsContextControl,

View File

@ -60,6 +60,18 @@
class nsIDOMEvent;
class nsIDOMXPathResult;
/**
* nsRepeatState is used to indicate whether the element
* is inside \<repeat\>'s template. If it is, there is no need
* to refresh the widget bound to the element.
*/
enum nsRepeatState {
eType_Unknown,
eType_Template,
eType_GeneratedContent,
eType_NotApplicable
};
/**
* Common stub for all XForms controls that inherit from nsIXFormsControl and
* is bound to an instance node.
@ -105,6 +117,7 @@ public:
NS_IMETHOD OnDestroyed();
NS_IMETHOD WillChangeDocument(nsIDOMDocument *aNewDocument);
NS_IMETHOD DocumentChanged(nsIDOMDocument *aNewDocument);
NS_IMETHOD WillChangeParent(nsIDOMElement *aNewParent);
NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent);
NS_IMETHOD WillSetAttribute(nsIAtom *aName, const nsAString &aValue);
NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aValue);
@ -144,6 +157,14 @@ public:
*/
virtual PRBool IsContentComplex();
/**
* Get/Set the repeat state for the control. The repeat state indicates
* whether the control lives inside a context container, a repeat element,
* an itemset or non of the above.
*/
virtual nsRepeatState GetRepeatState();
virtual void SetRepeatState(nsRepeatState aState);
// nsIXFormsContextControl
NS_DECL_NSIXFORMSCONTEXTCONTROL
@ -160,6 +181,7 @@ public:
nsIXTFElement::NOTIFY_ATTRIBUTE_REMOVED |
nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT |
nsIXTFElement::NOTIFY_DOCUMENT_CHANGED |
nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT |
nsIXTFElement::NOTIFY_PARENT_CHANGED |
nsIXTFElement::NOTIFY_HANDLE_DEFAULT),
kElementFlags(nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR),
@ -168,7 +190,8 @@ public:
mUsesModelBinding(PR_FALSE),
mAppearDisabled(PR_FALSE),
mOnDeferredBindList(PR_FALSE),
mBindAttrsCount(0)
mBindAttrsCount(0),
mRepeatState(eType_Unknown)
{};
protected:
@ -217,6 +240,8 @@ protected:
*/
PRInt8 mBindAttrsCount;
nsRepeatState mRepeatState;
/**
* List of repeats that the node binding depends on. This happens when using
* the index() function in the binding expression.
@ -305,6 +330,16 @@ protected:
* bound.
*/
nsresult GetBoundBuiltinType(PRUint16 *aBuiltinType);
/**
* This is called when the parent node for a XForms control changes.
* It checks the ancestors of the element and returns an nsRepeatState
* depending on the element's place in the document.
*
* @param aParent The new parent of the XForms control
*/
nsRepeatState UpdateRepeatState(nsIDOMNode *aParent);
};
#endif

View File

@ -61,19 +61,6 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsDelegateStub,
nsIXFormsDelegate)
NS_IMETHODIMP
nsXFormsDelegateStub::WillChangeDocument(nsIDOMDocument *aNewDocument)
{
mRepeatState = eType_Unknown;
return nsXFormsControlStub::WillChangeDocument(aNewDocument);
}
NS_IMETHODIMP
nsXFormsDelegateStub::WillChangeParent(nsIDOMElement *aNewParent)
{
mRepeatState = eType_Unknown;
return nsXFormsControlStub::WillChangeParent(aNewParent);
}
NS_IMETHODIMP
nsXFormsDelegateStub::GetAccesskeyNode(nsIDOMAttr** aNode)
@ -99,7 +86,6 @@ nsXFormsDelegateStub::OnCreated(nsIXTFElementWrapper *aWrapper)
nsresult rv = nsXFormsControlStub::OnCreated(aWrapper);
NS_ENSURE_SUCCESS(rv, rv);
aWrapper->SetNotificationMask(kStandardNotificationMask |
nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT |
nsIXTFElement::NOTIFY_PERFORM_ACCESSKEY);
return rv;
}
@ -119,7 +105,7 @@ nsXFormsDelegateStub::OnDestroyed()
NS_IMETHODIMP
nsXFormsDelegateStub::Refresh()
{
if (mRepeatState == eType_Template)
if (GetRepeatState() == eType_Template)
return NS_OK_XFORMS_NOREFRESH;
const nsVoidArray* list = nsPostRefresh::PostRefreshList();
@ -205,7 +191,7 @@ nsXFormsDelegateStub::ReportErrorMessage(const nsAString& aErrorMsg)
NS_IMETHODIMP
nsXFormsDelegateStub::WidgetAttached()
{
if (UpdateRepeatState() == eType_Template)
if (GetRepeatState() == eType_Template)
return NS_OK;
if (HasBindingAttribute()) {
@ -235,32 +221,6 @@ nsXFormsDelegateStub::IsTypeAllowed(PRUint16 aType, PRBool *aIsAllowed,
return NS_OK;
}
nsRepeatState
nsXFormsDelegateStub::UpdateRepeatState()
{
mRepeatState = eType_NotApplicable;
nsCOMPtr<nsIDOMNode> parent;
mElement->GetParentNode(getter_AddRefs(parent));
while (parent) {
if (nsXFormsUtils::IsXFormsElement(parent, NS_LITERAL_STRING("contextcontainer"))) {
mRepeatState = eType_GeneratedContent;
break;
}
if (nsXFormsUtils::IsXFormsElement(parent, NS_LITERAL_STRING("repeat"))) {
mRepeatState = eType_Template;
break;
}
if (nsXFormsUtils::IsXFormsElement(parent, NS_LITERAL_STRING("itemset"))) {
mRepeatState = eType_Template;
break;
}
nsCOMPtr<nsIDOMNode> tmp;
parent->GetParentNode(getter_AddRefs(tmp));
parent = tmp;
}
return mRepeatState;
}
void
nsXFormsDelegateStub::SetMozTypeAttribute()
{

View File

@ -51,18 +51,6 @@
class nsIAtom;
/**
* nsRepeatState is used to indicate whether the element
* is inside \<repeat\>'s template. If it is, there is no need
* to refresh the widget bound to the element.
*/
enum nsRepeatState {
eType_Unknown,
eType_Template,
eType_GeneratedContent,
eType_NotApplicable
};
enum nsRestrictionFlag {
eTypes_NoRestriction,
eTypes_Inclusive,
@ -82,8 +70,6 @@ public:
NS_IMETHOD OnCreated(nsIXTFElementWrapper *aWrapper);
NS_IMETHOD OnDestroyed();
NS_IMETHOD WillChangeParent(nsIDOMElement *aNewParent);
NS_IMETHOD WillChangeDocument(nsIDOMDocument *aNewDocument);
NS_IMETHOD GetAccesskeyNode(nsIDOMAttr** aNode);
NS_IMETHOD PerformAccesskey();
@ -124,21 +110,14 @@ public:
nsXFormsDelegateStub(const nsAString& aType = EmptyString())
: mControlType(aType), mRepeatState(eType_Unknown) {}
: mControlType(aType) {}
protected:
// This is called when XBL widget is attached to the XForms control.
// It checks the ancestors of the element and returns an nsRepeatState
// depending on the elements place in the document.
nsRepeatState UpdateRepeatState();
// Sets/removes the moz:type attribute. The attribute can be used to detect the
// type of the node, which is bound the the control.
void SetMozTypeAttribute();
nsString mControlType;
nsRepeatState mRepeatState;
/** The accessors object for this delegate */
nsRefPtr<nsXFormsAccessors> mAccessor;
};

View File

@ -99,6 +99,8 @@ nsXFormsItemSetElement::OnCreated(nsIXTFElementWrapper *aWrapper)
NS_IMETHODIMP
nsXFormsItemSetElement::ParentChanged(nsIDOMElement *aNewParent)
{
UpdateRepeatState(aNewParent);
if (aNewParent)
Refresh();