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:
parent
e5f33ecf20
commit
660dff3cf7
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
{
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -99,6 +99,8 @@ nsXFormsItemSetElement::OnCreated(nsIXTFElementWrapper *aWrapper)
|
||||
NS_IMETHODIMP
|
||||
nsXFormsItemSetElement::ParentChanged(nsIDOMElement *aNewParent)
|
||||
{
|
||||
UpdateRepeatState(aNewParent);
|
||||
|
||||
if (aNewParent)
|
||||
Refresh();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user