From 242a70a7fc87ce099e0735ad8159004e32ecb4da Mon Sep 17 00:00:00 2001 From: "Olli.Pettay%helsinki.fi" Date: Wed, 28 Nov 2007 16:40:37 +0000 Subject: [PATCH] Bug 388976, [XForms1.1] Support conditional and iterated actions (i.e. 'if' and 'while'), [NPOTB], r=aaronr+me, p=jlc6@po.cwru.edu git-svn-id: svn://10.0.0.236/trunk@240037 18797224-902f-48f8-a5cc-f745e15eee43 --- .../xforms/nsXFormsActionElement.cpp | 13 +- .../extensions/xforms/nsXFormsActionElement.h | 14 +- .../xforms/nsXFormsActionModuleBase.cpp | 133 +++++++++++++++++- .../xforms/nsXFormsActionModuleBase.h | 42 +++++- .../extensions/xforms/nsXFormsCaseElement.cpp | 3 +- .../xforms/nsXFormsChoicesElement.cpp | 3 +- .../extensions/xforms/nsXFormsControlStub.h | 6 +- .../extensions/xforms/nsXFormsCopyElement.cpp | 5 +- .../xforms/nsXFormsDispatchElement.cpp | 16 +-- .../xforms/nsXFormsInsertDeleteElement.cpp | 37 ++++- .../xforms/nsXFormsInstanceElement.cpp | 2 +- .../xforms/nsXFormsInstanceElement.h | 1 - .../extensions/xforms/nsXFormsLoadElement.cpp | 15 +- .../xforms/nsXFormsMessageElement.cpp | 35 +++-- .../xforms/nsXFormsModelElement.cpp | 2 +- .../extensions/xforms/nsXFormsModelElement.h | 1 - .../xforms/nsXFormsRebuildElement.cpp | 13 +- .../xforms/nsXFormsRecalculateElement.cpp | 13 +- .../xforms/nsXFormsRefreshElement.cpp | 13 +- .../xforms/nsXFormsResetElement.cpp | 14 +- .../xforms/nsXFormsRevalidateElement.cpp | 13 +- .../extensions/xforms/nsXFormsSendElement.cpp | 17 +-- .../xforms/nsXFormsSetFocusElement.cpp | 16 +-- .../xforms/nsXFormsSetIndexElement.cpp | 18 ++- .../xforms/nsXFormsSetValueElement.cpp | 16 +-- .../extensions/xforms/nsXFormsStubElement.h | 4 + .../xforms/nsXFormsSubmissionElement.h | 3 +- .../xforms/nsXFormsToggleElement.cpp | 19 ++- mozilla/extensions/xforms/nsXFormsUtils.cpp | 95 +++++++++++++ mozilla/extensions/xforms/nsXFormsUtils.h | 19 ++- 30 files changed, 474 insertions(+), 127 deletions(-) diff --git a/mozilla/extensions/xforms/nsXFormsActionElement.cpp b/mozilla/extensions/xforms/nsXFormsActionElement.cpp index 9e10594f711..5d8159177ac 100644 --- a/mozilla/extensions/xforms/nsXFormsActionElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsActionElement.cpp @@ -49,7 +49,8 @@ #define DEFERRED_REVALIDATE 0x04 #define DEFERRED_REFRESH 0x08 -nsXFormsActionElement::nsXFormsActionElement() : mElement(nsnull) +nsXFormsActionElement::nsXFormsActionElement() : + nsXFormsActionModuleBase(PR_TRUE) { } @@ -154,14 +155,10 @@ PR_STATIC_CALLBACK(PLDHashOperator) DoDeferredActions(nsISupports * aModel, return PL_DHASH_NEXT; } -NS_IMETHODIMP -nsXFormsActionElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsActionElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { - if (!mElement) { - return NS_OK; - } - if (!mDeferredUpdates.IsInitialized()) { NS_ENSURE_TRUE(mDeferredUpdates.Init(), NS_ERROR_OUT_OF_MEMORY); } else { diff --git a/mozilla/extensions/xforms/nsXFormsActionElement.h b/mozilla/extensions/xforms/nsXFormsActionElement.h index b3848a54349..00f29f513e2 100644 --- a/mozilla/extensions/xforms/nsXFormsActionElement.h +++ b/mozilla/extensions/xforms/nsXFormsActionElement.h @@ -46,28 +46,28 @@ class nsIXTFElementWrapper; -class nsXFormsActionElement : public nsXFormsStubElement, - public nsIXFormsActionElement, - public nsIXFormsActionModuleElement, - public nsIDOMEventListener +class nsXFormsActionElement : public nsIXFormsActionElement, + public nsXFormsActionModuleBase { public: nsXFormsActionElement(); NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIDOMEVENTLISTENER NS_DECL_NSIXFORMSACTIONELEMENT - NS_DECL_NSIXFORMSACTIONMODULEELEMENT - NS_IMETHOD OnCreated(nsIXTFElementWrapper* aWrapper); + NS_IMETHOD OnCreated(nsIXTFElementWrapper *aWrapper); NS_IMETHOD OnDestroyed(); NS_IMETHOD WillChangeDocument(nsIDOMDocument *aNewDocument); NS_IMETHOD DocumentChanged(nsIDOMDocument *aNewDocument); NS_IMETHOD WillChangeParent(nsIDOMElement *aNewParent); NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); private: - nsIDOMElement* mElement; nsCOMPtr mParentAction; nsDataHashtable mDeferredUpdates; }; + #endif diff --git a/mozilla/extensions/xforms/nsXFormsActionModuleBase.cpp b/mozilla/extensions/xforms/nsXFormsActionModuleBase.cpp index 69e10fed5b3..9f67a054057 100644 --- a/mozilla/extensions/xforms/nsXFormsActionModuleBase.cpp +++ b/mozilla/extensions/xforms/nsXFormsActionModuleBase.cpp @@ -21,6 +21,7 @@ * * Contributor(s): * Olli Pettay (original author) + * John L. Clark * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -49,7 +50,16 @@ #include "nsIDOMDocumentEvent.h" #include "nsIDOMEventTarget.h" -nsXFormsActionModuleBase::nsXFormsActionModuleBase() : mElement(nsnull) +#include "nsXFormsUtils.h" +#include "nsIDOMAttr.h" +#include "nsIXFormsControl.h" + +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsServiceManagerUtils.h" + +nsXFormsActionModuleBase::nsXFormsActionModuleBase(PRBool canIterate) : + nsXFormsStubElement(), mCanIterate(canIterate) { } @@ -131,3 +141,124 @@ nsXFormsActionModuleBase::HandleEvent(nsIDOMEvent* aEvent) HandleAction(aEvent, nsnull) : NS_OK; } +NS_IMETHODIMP +nsXFormsActionModuleBase::HandleAction(nsIDOMEvent *aEvent, + nsIXFormsActionElement *aParentAction) +{ + if (!mElement) + return NS_OK; + + // Set the maximum run time for the loop (in microseconds). + PRTime microseconds = nsXFormsUtils::waitLimit * PR_USEC_PER_SEC; + + PRTime runTime = 0, start = PR_Now(); + + while (PR_TRUE) { + // Test the `if` and `while` attributes to determine whether this action + // can be performed and should be repeated. + PRBool usesWhile; + if (!CanPerformAction(&usesWhile)) { + return NS_OK; + } + + nsresult rv = HandleSingleAction(aEvent, aParentAction); + NS_ENSURE_SUCCESS(rv, rv); + + // Repeat this action if it can iterate and if it uses the `while` + // attribute (the expression of which must have evaluated to true to + // arrive here). + if (!mCanIterate || !usesWhile) { + return NS_OK; + } + + // See if we've exceeded our time limit, and if so, prompt the user to + // determine if she wants to cancel the loop. + LL_SUB(runTime, PR_Now(), start); + if (microseconds <= 0 || runTime < microseconds) { + continue; + } + + // The remaining part of the loop prompts the user about cancelling the + // loop, and is only executed if we've gone over the time limit. + PRBool stopWaiting = nsXFormsUtils::AskStopWaiting(mElement); + + if (stopWaiting) { + // Stop the loop + return NS_OK; + } else { + start = PR_Now(); + } + } +} + +PRBool +nsXFormsActionModuleBase::CanPerformAction(PRBool *aUsesWhile, + nsIDOMNode *aContext, + PRInt32 aContextSize, + PRInt32 aContextPosition) +{ + *aUsesWhile = PR_FALSE; + + nsAutoString ifExpr; + nsAutoString whileExpr; + mElement->GetAttribute(NS_LITERAL_STRING("if"), ifExpr); + mElement->GetAttribute(NS_LITERAL_STRING("while"), whileExpr); + + if (whileExpr.IsEmpty() && ifExpr.IsEmpty()) { + return PR_TRUE; + } + + nsresult rv; + nsCOMPtr res; + PRBool condTrue; + + nsCOMPtr contextNode; + + if (aContext) { + contextNode = aContext; + } else { + // Determine evaluation context. + nsCOMPtr model; + nsCOMPtr bindElement; + nsCOMPtr parentControl; + PRBool outerBind; + rv = nsXFormsUtils::GetNodeContext(mElement, 0, + getter_AddRefs(model), + getter_AddRefs(bindElement), + &outerBind, + getter_AddRefs(parentControl), + getter_AddRefs(contextNode), + &aContextPosition, &aContextSize, PR_FALSE); + NS_ENSURE_SUCCESS(rv, PR_FALSE); + } + + if (!whileExpr.IsEmpty()) { + *aUsesWhile = PR_TRUE; + + rv = nsXFormsUtils::EvaluateXPath(whileExpr, contextNode, mElement, + nsIDOMXPathResult::BOOLEAN_TYPE, + getter_AddRefs(res), + aContextPosition, aContextSize); + NS_ENSURE_SUCCESS(rv, PR_FALSE); + + rv = res->GetBooleanValue(&condTrue); + if (NS_FAILED(rv) || !condTrue) { + return PR_FALSE; + } + } + + if (!ifExpr.IsEmpty()) { + rv = nsXFormsUtils::EvaluateXPath(ifExpr, contextNode, mElement, + nsIDOMXPathResult::BOOLEAN_TYPE, + getter_AddRefs(res), + aContextPosition, aContextSize); + NS_ENSURE_SUCCESS(rv, PR_FALSE); + + rv = res->GetBooleanValue(&condTrue); + if (NS_FAILED(rv) || !condTrue) { + return PR_FALSE; + } + } + + return PR_TRUE; +} diff --git a/mozilla/extensions/xforms/nsXFormsActionModuleBase.h b/mozilla/extensions/xforms/nsXFormsActionModuleBase.h index 02a0d070ebb..e987efac2f1 100644 --- a/mozilla/extensions/xforms/nsXFormsActionModuleBase.h +++ b/mozilla/extensions/xforms/nsXFormsActionModuleBase.h @@ -21,6 +21,7 @@ * * Contributor(s): * Olli Pettay (original author) + * John L. Clark * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -40,6 +41,7 @@ #define nsXFormsActionModuleBase_h_ #include "nsIDOMEventListener.h" +#include "nsIXFormsActionElement.h" #include "nsXFormsStubElement.h" #include "nsIDOMElement.h" #include "nsIXFormsActionModuleElement.h" @@ -47,13 +49,14 @@ #include "nsXFormsUtils.h" class nsXFormsActionModuleBase : public nsIDOMEventListener, - public nsXFormsStubElement, + public virtual nsXFormsStubElement, public nsIXFormsActionModuleElement { public: - nsXFormsActionModuleBase(); + nsXFormsActionModuleBase(PRBool canIterate = PR_FALSE); virtual ~nsXFormsActionModuleBase(); NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIXFORMSACTIONMODULEELEMENT NS_DECL_NSIDOMEVENTLISTENER NS_IMETHOD OnCreated(nsIXTFElementWrapper *aWrapper); NS_IMETHOD OnDestroyed(); @@ -62,7 +65,40 @@ public: NS_IMETHOD WillChangeParent(nsIDOMElement *aNewParent); NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); protected: - nsIDOMElement* mElement; + /** + * Determine whether this action element should be executed, based upon + * optional `if` and `while` attributes. For each of these attributes + * that are present on an action element, the action is only performed if + * the boolean value of the XPath expression contained in the attribute is + * true. In addition, if the `while` attribute is used, the action is + * "executed repeatedly" until one of these attributes evaluates to false. + * This method indicates to the caller whether the action element uses a + * `while` attribute through the `usesWhile` parameter. + */ + NS_HIDDEN_(PRBool) CanPerformAction(PRBool *usesWhile, + nsIDOMNode *contextNode = nsnull, + PRInt32 contextSize = 0, + PRInt32 contextPosition = 0); + + /** + * With the `while` attribute, actions can potentially be iterated. The + * `HandleSingleAction` method processes one iteration of an action (that + * is, the "body" of the action); it should be dispatched by the + * `HandleAction` method, which manages the conditional execution and + * iteration of the action. + */ + virtual nsresult + HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) = 0; + + /** + * This signals whether or not this action can iterate. Technically, all + * XForms 1.1 actions are allowed to iterate, but for some of them it + * may not make sense. Currently, this is set to PR_TRUE for all actions, + * but we can optionally disable iteration for specific actions based upon + * additional information in the future. + */ + PRBool mCanIterate; }; #endif diff --git a/mozilla/extensions/xforms/nsXFormsCaseElement.cpp b/mozilla/extensions/xforms/nsXFormsCaseElement.cpp index 50424c39965..cf15c2a3946 100644 --- a/mozilla/extensions/xforms/nsXFormsCaseElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsCaseElement.cpp @@ -63,12 +63,11 @@ public: NS_IMETHOD DoneAddingChildren(); nsXFormsCaseElement() - : mElement(nsnull), mSelected(PR_FALSE), mCachedSelectedAttr(PR_FALSE) + : nsXFormsStubElement(), mSelected(PR_FALSE), mCachedSelectedAttr(PR_FALSE) { } protected: - nsIDOMElement* mElement; PRPackedBool mSelected; PRPackedBool mCachedSelectedAttr; }; diff --git a/mozilla/extensions/xforms/nsXFormsChoicesElement.cpp b/mozilla/extensions/xforms/nsXFormsChoicesElement.cpp index 587812aa751..e1f7ae38134 100644 --- a/mozilla/extensions/xforms/nsXFormsChoicesElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsChoicesElement.cpp @@ -51,7 +51,7 @@ class nsXFormsChoicesElement : public nsXFormsStubElement, public nsIXFormsSelectChild { public: - nsXFormsChoicesElement() : mElement(nsnull), mDoneAddingChildren(PR_FALSE) {} + nsXFormsChoicesElement() : nsXFormsStubElement(), mDoneAddingChildren(PR_FALSE) {} NS_DECL_ISUPPORTS_INHERITED @@ -69,7 +69,6 @@ public: NS_DECL_NSIXFORMSSELECTCHILD private: - nsIDOMElement* mElement; PRBool mDoneAddingChildren; void Refresh(); diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.h b/mozilla/extensions/xforms/nsXFormsControlStub.h index 9db377f19fd..ea7eb14a52b 100644 --- a/mozilla/extensions/xforms/nsXFormsControlStub.h +++ b/mozilla/extensions/xforms/nsXFormsControlStub.h @@ -64,7 +64,7 @@ class nsIDOMXPathResult; * Common stub for all XForms controls that inherit from nsIXFormsControl and * is bound to an instance node. */ -class nsXFormsControlStub : public nsXFormsStubElement, +class nsXFormsControlStub : public virtual nsXFormsStubElement, public nsIXFormsControl { public: @@ -159,6 +159,7 @@ public: /** Constructor */ nsXFormsControlStub() : + nsXFormsStubElement(), kStandardNotificationMask(nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE | nsIXTFElement::NOTIFY_ATTRIBUTE_SET | nsIXTFElement::NOTIFY_WILL_REMOVE_ATTRIBUTE | @@ -177,9 +178,6 @@ public: {}; protected: - /** The nsIXTFElementWrapper */ - nsIDOMElement* mElement; - /** The node that the control is bound to. */ nsCOMPtr mBoundNode; diff --git a/mozilla/extensions/xforms/nsXFormsCopyElement.cpp b/mozilla/extensions/xforms/nsXFormsCopyElement.cpp index 841d7c500e8..63c6d778668 100644 --- a/mozilla/extensions/xforms/nsXFormsCopyElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsCopyElement.cpp @@ -56,7 +56,7 @@ class nsXFormsCopyElement : public nsXFormsStubElement, public nsIXFormsCopyElement { public: - nsXFormsCopyElement() : mElement(nsnull) {} + nsXFormsCopyElement() : nsXFormsStubElement() {} NS_DECL_ISUPPORTS_INHERITED @@ -67,9 +67,6 @@ public: // nsIXFormsCopyElement NS_DECL_NSIXFORMSCOPYELEMENT - -private: - nsIDOMElement *mElement; }; NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsCopyElement, diff --git a/mozilla/extensions/xforms/nsXFormsDispatchElement.cpp b/mozilla/extensions/xforms/nsXFormsDispatchElement.cpp index 9ea05d3443d..ec8a2050cf4 100644 --- a/mozilla/extensions/xforms/nsXFormsDispatchElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsDispatchElement.cpp @@ -49,20 +49,20 @@ class nsXFormsDispatchElement : public nsXFormsActionModuleBase { public: nsXFormsDispatchElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsDispatchElement::nsXFormsDispatchElement() +nsXFormsDispatchElement::nsXFormsDispatchElement() : + nsXFormsActionModuleBase(PR_TRUE) { } -NS_IMETHODIMP -nsXFormsDispatchElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsDispatchElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { - if (!mElement) - return NS_OK; - nsAutoString name; mElement->GetAttribute(NS_LITERAL_STRING("name"), name); if (name.IsEmpty()) diff --git a/mozilla/extensions/xforms/nsXFormsInsertDeleteElement.cpp b/mozilla/extensions/xforms/nsXFormsInsertDeleteElement.cpp index 30593509be8..c7049965cc6 100644 --- a/mozilla/extensions/xforms/nsXFormsInsertDeleteElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsInsertDeleteElement.cpp @@ -112,8 +112,22 @@ public: /** Constructor */ nsXFormsInsertDeleteElement(PRBool aIsInsert) : + nsXFormsActionModuleBase(PR_TRUE), mIsInsert(aIsInsert) {} +protected: + /** + * Normally, an action element implements the body of its action handler + * using this method; however, since an `nsXFormsInsertDeleteElement` sets + * up additional context before evaluating `if` and `while`, it overrides + * the `HandleAction` method instead to get full control over the + * execution of its action. + */ + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) + { + return NS_OK; + } }; NS_IMETHODIMP @@ -137,6 +151,7 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent, nsCOMPtr contextNodeset; nsCOMPtr contextNode; PRUint32 contextNodesetSize = 0; + PRInt32 contextPosition; // Get the in-scope evaluation context. The last parameter to GetNodeContext // indicates whether it should try to get the context using @bind. We want to @@ -153,7 +168,9 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent, &outerBind, getter_AddRefs(parentControl), getter_AddRefs(contextNode), - nsnull, nsnull, PR_FALSE); + &contextPosition, + (PRInt32*)&contextNodesetSize, + PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); @@ -184,6 +201,7 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent, // Context node is the first node in the nodeset. contextNodeset->SnapshotItem(0, getter_AddRefs(contextNode)); + contextPosition = 1; } } @@ -201,6 +219,17 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent, return NS_OK; } + // Test the `if` and `while` attributes to determine whether this action + // can be performed and should be repeated. As the insert and delete + // actions can change their context, we do this testing here instead of + // relying on the default logic from our parent class' `HandleAction` + // definition. + PRBool usesWhile; + if (!CanPerformAction(&usesWhile, contextNode, + contextNodesetSize, contextPosition)) { + return NS_OK; + } + // // Step 2 (Insert or Delete): Determine the node-set binding. // @@ -636,6 +665,12 @@ nsXFormsInsertDeleteElement::HandleAction(nsIDOMEvent *aEvent, NS_ENSURE_SUCCESS(rv, rv); } + // Repeat this action if it uses the `while` attribute (which must have + // evaluated to true to arrive here). + if (usesWhile) { + return HandleAction(aEvent, aParentAction); + } + return NS_OK; } diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp index a78f2a887b7..63c15bbb79f 100644 --- a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp @@ -62,7 +62,7 @@ NS_IMPL_ISUPPORTS_INHERITED6(nsXFormsInstanceElement, nsIChannelEventSink) nsXFormsInstanceElement::nsXFormsInstanceElement() - : mElement(nsnull) + : nsXFormsStubElement() , mInitialized(PR_FALSE) , mLazy(PR_FALSE) { diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.h b/mozilla/extensions/xforms/nsXFormsInstanceElement.h index 2f5a92bec3e..1e1916a2837 100644 --- a/mozilla/extensions/xforms/nsXFormsInstanceElement.h +++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.h @@ -103,7 +103,6 @@ private: nsCOMPtr mDocument; nsCOMPtr mOriginalDocument; - nsIDOMElement *mElement; nsCOMPtr mListener; PRBool mInitialized; PRBool mLazy; diff --git a/mozilla/extensions/xforms/nsXFormsLoadElement.cpp b/mozilla/extensions/xforms/nsXFormsLoadElement.cpp index b857d277c61..f8dd48c383a 100644 --- a/mozilla/extensions/xforms/nsXFormsLoadElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsLoadElement.cpp @@ -49,19 +49,20 @@ class nsXFormsLoadElement : public nsXFormsActionModuleBase { public: nsXFormsLoadElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsLoadElement::nsXFormsLoadElement() +nsXFormsLoadElement::nsXFormsLoadElement() : + nsXFormsActionModuleBase(PR_TRUE) { } -NS_IMETHODIMP -nsXFormsLoadElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsLoadElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { - if(!mElement) - return NS_OK; //If the element has 'resource' and single node binding, the //action has no effect. PRBool hasBind; diff --git a/mozilla/extensions/xforms/nsXFormsMessageElement.cpp b/mozilla/extensions/xforms/nsXFormsMessageElement.cpp index 46644399e1a..f53cb391cf4 100644 --- a/mozilla/extensions/xforms/nsXFormsMessageElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsMessageElement.cpp @@ -41,6 +41,7 @@ #include "nsXFormsDelegateStub.h" #include "nsXFormsActionElement.h" #include "nsIXFormsActionModuleElement.h" +#include "nsXFormsActionModuleBase.h" #include "nsIDOMText.h" #include "nsIDOM3Node.h" @@ -103,11 +104,10 @@ class nsXFormsEventListener; * @see http://www.w3.org/TR/xforms/slice10.html#action-info */ class nsXFormsMessageElement : public nsXFormsDelegateStub, - public nsIDOMEventListener, - public nsIXFormsActionModuleElement, public nsIStreamListener, public nsIInterfaceRequestor, - public nsIChannelEventSink + public nsIChannelEventSink, + public nsXFormsActionModuleBase { public: NS_DECL_ISUPPORTS_INHERITED @@ -118,6 +118,7 @@ public: // nsIXTFElement overrides NS_IMETHOD OnCreated(nsIXTFElementWrapper *aWrapper); NS_IMETHOD WillChangeDocument(nsIDOMDocument *aNewDocument); + NS_IMETHOD DocumentChanged(nsIDOMDocument *aNewDocument); NS_IMETHOD OnDestroyed(); NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); NS_IMETHOD WillChangeParent(nsIDOMElement *aNewParent); @@ -130,7 +131,6 @@ public: NS_DECL_NSISTREAMLISTENER NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIDOMEVENTLISTENER - NS_DECL_NSIXFORMSACTIONMODULEELEMENT // Start the timer, which is used to set the message visible void StartEphemeral(); @@ -159,9 +159,13 @@ public: nsXFormsMessageElement(MessageType aType) : + nsXFormsDelegateStub(), nsXFormsActionModuleBase(PR_TRUE), mType(aType), mPosX(-1), mPosY(-1), mDocument(nsnull), mStopType(eStopType_None), mSrcAttrText(""), mDoneAddingChildren(PR_FALSE) {} +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); private: nsresult HandleEphemeralMessage(nsIDOMDocument* aDoc, nsIDOMEvent* aEvent); nsresult HandleModalAndModelessMessage(nsIDOMDocument* aDoc, nsAString& aLevel); @@ -261,6 +265,20 @@ nsXFormsMessageElement::WillChangeDocument(nsIDOMDocument *aNewDocument) return nsXFormsDelegateStub::WillChangeDocument(aNewDocument); } +/** + * The `nsXFormsMessageElement` class inherits from both + * `nsXFormsActionModuleBase` and `nsXFormsControlStub`, which both + * implement a `DocumentChanged` method. The method defined by + * `nsXFormsControlStub` completely subsumes that of + * `nsXFormsActionModuleBase`, so we delegate to the former method as the + * implementation of this method. + */ +NS_IMETHODIMP +nsXFormsMessageElement::DocumentChanged(nsIDOMDocument *aNewDocument) +{ + return nsXFormsControlStub::DocumentChanged(aNewDocument); +} + NS_IMETHODIMP nsXFormsMessageElement::OnDestroyed() { @@ -439,13 +457,10 @@ nsXFormsMessageElement::DoneAddingChildren() return NS_OK; } -NS_IMETHODIMP -nsXFormsMessageElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsMessageElement::HandleSingleAction(nsIDOMEvent *aEvent, + nsIXFormsActionElement *aParentAction) { - if (!mElement) - return NS_OK; - // If TestExternalFile fails, then there is an external link that we need // to use that we can't reach right now. If it won't load, then might as // well stop here. We don't want to be popping up empty windows diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp index df5499456a4..0746b012ef9 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp @@ -641,7 +641,7 @@ nsXFormsModelElement::CancelPostRefresh(nsIXFormsControl* aControl) } nsXFormsModelElement::nsXFormsModelElement() - : mElement(nsnull), + : nsXFormsStubElement(), mFormControls(nsnull, &mControlListHash), mSchemaCount(0), mSchemaTotal(0), diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.h b/mozilla/extensions/xforms/nsXFormsModelElement.h index d52ac161e99..c494c4ce344 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.h +++ b/mozilla/extensions/xforms/nsXFormsModelElement.h @@ -462,7 +462,6 @@ private: NS_HIDDEN_(nsresult) BuiltinTypeToPrimative(nsISchemaBuiltinType *aSchemaType, PRUint16 *aPrimType); - nsIDOMElement *mElement; nsCOMPtr mSchemas; nsStringArray mPendingInlineSchemas; nsXFormsControlListItem mFormControls; diff --git a/mozilla/extensions/xforms/nsXFormsRebuildElement.cpp b/mozilla/extensions/xforms/nsXFormsRebuildElement.cpp index 8ad919699e4..637b0d56360 100644 --- a/mozilla/extensions/xforms/nsXFormsRebuildElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsRebuildElement.cpp @@ -43,16 +43,19 @@ class nsXFormsRebuildElement : public nsXFormsActionModuleBase { public: nsXFormsRebuildElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsRebuildElement::nsXFormsRebuildElement() +nsXFormsRebuildElement::nsXFormsRebuildElement() : + nsXFormsActionModuleBase(PR_TRUE) { } -NS_IMETHODIMP -nsXFormsRebuildElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsRebuildElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { nsCOMPtr model = nsXFormsUtils::GetModel(mElement); NS_ENSURE_STATE(model); diff --git a/mozilla/extensions/xforms/nsXFormsRecalculateElement.cpp b/mozilla/extensions/xforms/nsXFormsRecalculateElement.cpp index 8605eb08d6c..cac91121297 100644 --- a/mozilla/extensions/xforms/nsXFormsRecalculateElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsRecalculateElement.cpp @@ -43,16 +43,19 @@ class nsXFormsRecalculateElement : public nsXFormsActionModuleBase { public: nsXFormsRecalculateElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsRecalculateElement::nsXFormsRecalculateElement() +nsXFormsRecalculateElement::nsXFormsRecalculateElement() : + nsXFormsActionModuleBase(PR_TRUE) { } -NS_IMETHODIMP -nsXFormsRecalculateElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsRecalculateElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { nsCOMPtr model = nsXFormsUtils::GetModel(mElement); NS_ENSURE_STATE(model); diff --git a/mozilla/extensions/xforms/nsXFormsRefreshElement.cpp b/mozilla/extensions/xforms/nsXFormsRefreshElement.cpp index 9369884b456..6263c52e18f 100644 --- a/mozilla/extensions/xforms/nsXFormsRefreshElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsRefreshElement.cpp @@ -43,16 +43,19 @@ class nsXFormsRefreshElement : public nsXFormsActionModuleBase { public: nsXFormsRefreshElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsRefreshElement::nsXFormsRefreshElement() +nsXFormsRefreshElement::nsXFormsRefreshElement() : + nsXFormsActionModuleBase(PR_TRUE) { } -NS_IMETHODIMP -nsXFormsRefreshElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsRefreshElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { nsCOMPtr model = nsXFormsUtils::GetModel(mElement); NS_ENSURE_STATE(model); diff --git a/mozilla/extensions/xforms/nsXFormsResetElement.cpp b/mozilla/extensions/xforms/nsXFormsResetElement.cpp index 4dfffc86ead..920759201e0 100644 --- a/mozilla/extensions/xforms/nsXFormsResetElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsResetElement.cpp @@ -43,15 +43,19 @@ class nsXFormsResetElement : public nsXFormsActionModuleBase { public: nsXFormsResetElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsResetElement::nsXFormsResetElement() { +nsXFormsResetElement::nsXFormsResetElement() : + nsXFormsActionModuleBase(PR_TRUE) +{ } -NS_IMETHODIMP -nsXFormsResetElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsResetElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { nsCOMPtr modelPriv = nsXFormsUtils::GetModel(mElement); nsCOMPtr model = do_QueryInterface(modelPriv); diff --git a/mozilla/extensions/xforms/nsXFormsRevalidateElement.cpp b/mozilla/extensions/xforms/nsXFormsRevalidateElement.cpp index d239016d691..83b0e5ae078 100644 --- a/mozilla/extensions/xforms/nsXFormsRevalidateElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsRevalidateElement.cpp @@ -43,16 +43,19 @@ class nsXFormsRevalidateElement : public nsXFormsActionModuleBase { public: nsXFormsRevalidateElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsRevalidateElement::nsXFormsRevalidateElement() +nsXFormsRevalidateElement::nsXFormsRevalidateElement() : + nsXFormsActionModuleBase(PR_TRUE) { } -NS_IMETHODIMP -nsXFormsRevalidateElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsRevalidateElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { nsCOMPtr model = nsXFormsUtils::GetModel(mElement); NS_ENSURE_STATE(model); diff --git a/mozilla/extensions/xforms/nsXFormsSendElement.cpp b/mozilla/extensions/xforms/nsXFormsSendElement.cpp index eaf8e29803b..a981d50a16a 100644 --- a/mozilla/extensions/xforms/nsXFormsSendElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsSendElement.cpp @@ -45,19 +45,20 @@ class nsXFormsSendElement : public nsXFormsActionModuleBase { public: nsXFormsSendElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsSendElement::nsXFormsSendElement() { +nsXFormsSendElement::nsXFormsSendElement() : + nsXFormsActionModuleBase(PR_TRUE) +{ } -NS_IMETHODIMP -nsXFormsSendElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsSendElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { - if (!mElement) - return NS_OK; - NS_NAMED_LITERAL_STRING(submission, "submission"); nsAutoString submissionID; mElement->GetAttribute(submission, submissionID); diff --git a/mozilla/extensions/xforms/nsXFormsSetFocusElement.cpp b/mozilla/extensions/xforms/nsXFormsSetFocusElement.cpp index 4be503308fe..57b8c25a0bb 100644 --- a/mozilla/extensions/xforms/nsXFormsSetFocusElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsSetFocusElement.cpp @@ -46,20 +46,20 @@ class nsXFormsSetFocusElement : public nsXFormsActionModuleBase { public: nsXFormsSetFocusElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsSetFocusElement::nsXFormsSetFocusElement() +nsXFormsSetFocusElement::nsXFormsSetFocusElement() : + nsXFormsActionModuleBase(PR_TRUE) { } -NS_IMETHODIMP -nsXFormsSetFocusElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsSetFocusElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { - if (!mElement) - return NS_OK; - nsAutoString control; mElement->GetAttribute(NS_LITERAL_STRING("control"), control); if (control.IsEmpty()) diff --git a/mozilla/extensions/xforms/nsXFormsSetIndexElement.cpp b/mozilla/extensions/xforms/nsXFormsSetIndexElement.cpp index 24220d83688..4f0fd1a14af 100644 --- a/mozilla/extensions/xforms/nsXFormsSetIndexElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsSetIndexElement.cpp @@ -60,17 +60,21 @@ class nsXFormsSetIndexElement : public nsXFormsActionModuleBase { public: - NS_DECL_NSIXFORMSACTIONMODULEELEMENT + nsXFormsSetIndexElement(); +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -NS_IMETHODIMP -nsXFormsSetIndexElement::HandleAction(nsIDOMEvent *aEvent, - nsIXFormsActionElement *aParentAction) +nsXFormsSetIndexElement::nsXFormsSetIndexElement() : + nsXFormsActionModuleBase(PR_TRUE) { - if (!mElement) - return NS_OK; +} - +nsresult +nsXFormsSetIndexElement::HandleSingleAction(nsIDOMEvent *aEvent, + nsIXFormsActionElement *aParentAction) +{ // Get @repeat and @index nsAutoString id, index; NS_NAMED_LITERAL_STRING(repeatStr, "repeat"); diff --git a/mozilla/extensions/xforms/nsXFormsSetValueElement.cpp b/mozilla/extensions/xforms/nsXFormsSetValueElement.cpp index 3762f9f8c9e..61097a81598 100644 --- a/mozilla/extensions/xforms/nsXFormsSetValueElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsSetValueElement.cpp @@ -51,20 +51,20 @@ class nsXFormsSetValueElement : public nsXFormsActionModuleBase { public: nsXFormsSetValueElement(); - NS_DECL_NSIXFORMSACTIONMODULEELEMENT +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -nsXFormsSetValueElement::nsXFormsSetValueElement() +nsXFormsSetValueElement::nsXFormsSetValueElement() : + nsXFormsActionModuleBase(PR_TRUE) { } -NS_IMETHODIMP -nsXFormsSetValueElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsresult +nsXFormsSetValueElement::HandleSingleAction(nsIDOMEvent *aEvent, + nsIXFormsActionElement *aParentAction) { - if (!mElement) - return NS_OK; - nsCOMPtr modelPriv; nsCOMPtr singleNode; PRBool succeeded = diff --git a/mozilla/extensions/xforms/nsXFormsStubElement.h b/mozilla/extensions/xforms/nsXFormsStubElement.h index 8ab76e72d06..247e9661c6b 100644 --- a/mozilla/extensions/xforms/nsXFormsStubElement.h +++ b/mozilla/extensions/xforms/nsXFormsStubElement.h @@ -41,6 +41,7 @@ #include "nsIXTFElement.h" #include "nsIXFormsControlBase.h" +#include "nsIDOMElement.h" /** * nsRepeatState is used to indicate whether the element is inside a @@ -72,6 +73,8 @@ enum nsRepeatState { class nsXFormsStubElement : public nsIXTFElement { protected: + nsIDOMElement* mElement; + // We need a virtual destructor so that when a subclass does // NS_IMPL_ISUPPORTS_INHERITED, our Release() implementation calls the // derived class destructor. @@ -109,6 +112,7 @@ public: /** Constructor */ nsXFormsStubElement() : + mElement(nsnull), mRepeatState(eType_Unknown), mHasParent(PR_FALSE), mHasDoc(PR_FALSE) diff --git a/mozilla/extensions/xforms/nsXFormsSubmissionElement.h b/mozilla/extensions/xforms/nsXFormsSubmissionElement.h index e3989f5fd3b..591f448da84 100644 --- a/mozilla/extensions/xforms/nsXFormsSubmissionElement.h +++ b/mozilla/extensions/xforms/nsXFormsSubmissionElement.h @@ -81,7 +81,7 @@ public: NS_DECL_NSIINTERFACEREQUESTOR nsXFormsSubmissionElement() - : mElement(nsnull), + : nsXFormsStubElement(), mSubmissionActive(PR_FALSE), mIsReplaceInstance(PR_FALSE), mIsSOAPRequest(PR_FALSE), @@ -145,7 +145,6 @@ public: const nsCString &contentType); private: - nsIDOMElement* mElement; PRPackedBool mSubmissionActive; // Valid when mSubmissionActive == PR_TRUE PRPackedBool mIsReplaceInstance; diff --git a/mozilla/extensions/xforms/nsXFormsToggleElement.cpp b/mozilla/extensions/xforms/nsXFormsToggleElement.cpp index d58f516e937..fea8b68736b 100644 --- a/mozilla/extensions/xforms/nsXFormsToggleElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsToggleElement.cpp @@ -51,16 +51,21 @@ class nsXFormsToggleElement : public nsXFormsActionModuleBase { public: - NS_DECL_NSIXFORMSACTIONMODULEELEMENT + nsXFormsToggleElement(); +protected: + nsresult HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction); }; -NS_IMETHODIMP -nsXFormsToggleElement::HandleAction(nsIDOMEvent* aEvent, - nsIXFormsActionElement *aParentAction) +nsXFormsToggleElement::nsXFormsToggleElement() : + nsXFormsActionModuleBase(PR_TRUE) +{ +} + +nsresult +nsXFormsToggleElement::HandleSingleAction(nsIDOMEvent* aEvent, + nsIXFormsActionElement *aParentAction) { - if (!mElement) - return NS_OK; - nsAutoString caseAttr; NS_NAMED_LITERAL_STRING(caseStr, "case"); mElement->GetAttribute(caseStr, caseAttr); diff --git a/mozilla/extensions/xforms/nsXFormsUtils.cpp b/mozilla/extensions/xforms/nsXFormsUtils.cpp index 7475a27555a..3c85aad3184 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.cpp +++ b/mozilla/extensions/xforms/nsXFormsUtils.cpp @@ -109,6 +109,16 @@ #include "nsIEventStateManager.h" #include "nsXFormsModelElement.h" +#include "prtime.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeItem.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIPrompt.h" + +// For locale aware string methods +#include "plstr.h" + #define CANCELABLE 0x01 #define BUBBLES 0x02 @@ -213,6 +223,7 @@ struct EventItem }; static PRBool gExperimentalFeaturesEnabled = PR_FALSE; +PRInt32 nsXFormsUtils::waitLimit = 10; PR_STATIC_CALLBACK(int) PrefChangedCallback(const char* aPref, void* aData) { @@ -228,6 +239,12 @@ PR_STATIC_CALLBACK(int) PrefChangedCallback(const char* aPref, void* aData) gExperimentalFeaturesEnabled = val; } } + else if (strcmp(aPref, PREF_WAIT_LIMIT) == 0) { + PRInt32 val; + if (NS_SUCCEEDED(pref->GetIntPref(PREF_WAIT_LIMIT, &val))) { + nsXFormsUtils::waitLimit = val; + } + } } return 0; // PREF_OK @@ -272,6 +289,11 @@ nsXFormsUtils::Init() if (NS_SUCCEEDED(rv)) { gExperimentalFeaturesEnabled = val; } + PRInt32 intval; + rv = prefBranch->GetIntPref(PREF_WAIT_LIMIT, &intval); + if (NS_SUCCEEDED(rv)) { + nsXFormsUtils::waitLimit = intval; + } } nsCOMPtr pref = do_GetService(NS_PREF_CONTRACTID, &rv); @@ -279,6 +301,9 @@ nsXFormsUtils::Init() rv = pref->RegisterCallback(PREF_EXPERIMENTAL_FEATURES, PrefChangedCallback, nsnull); NS_ENSURE_SUCCESS(rv, rv); + rv = pref->RegisterCallback(PREF_WAIT_LIMIT, + PrefChangedCallback, nsnull); + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } @@ -295,6 +320,9 @@ nsXFormsUtils::Shutdown() PrefChangedCallback, nsnull); NS_ENSURE_SUCCESS(rv, rv); gExperimentalFeaturesEnabled = PR_FALSE; + rv = pref->UnregisterCallback(PREF_WAIT_LIMIT, + PrefChangedCallback, nsnull); + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } @@ -2823,6 +2851,73 @@ nsXFormsUtils::NodeHasItemset(nsIDOMNode *aNode) return hasItemset; } +/* static */ PRBool +nsXFormsUtils::AskStopWaiting(nsIDOMElement *aElement) +{ + nsCOMPtr domDoc; + aElement->GetOwnerDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc(do_QueryInterface(domDoc)); + NS_ENSURE_TRUE(doc, PR_TRUE); + + nsCOMPtr win = doc->GetWindow(); + NS_ENSURE_TRUE(win, PR_TRUE); + + nsIDocShell *docShell = win->GetDocShell(); + NS_ENSURE_TRUE(docShell, PR_TRUE); + + nsCOMPtr ireq(do_QueryInterface(docShell)); + NS_ENSURE_TRUE(ireq, PR_TRUE); + + // Get the nsIPrompt interface from the docshell + nsCOMPtr prompt; + ireq->GetInterface(NS_GET_IID(nsIPrompt), getter_AddRefs(prompt)); + NS_ENSURE_TRUE(prompt, PR_TRUE); + + // Get localizable strings + nsCOMPtr + stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID)); + NS_ENSURE_TRUE(stringService, PR_TRUE); + + nsCOMPtr bundle; + stringService->CreateBundle("chrome://global/locale/dom/dom.properties", + getter_AddRefs(bundle)); + NS_ENSURE_TRUE(bundle, PR_TRUE); + + nsXPIDLString title, msg, stopButton, waitButton; + + nsresult rv; + rv = bundle->GetStringFromName(NS_LITERAL_STRING("KillScriptTitle").get(), + getter_Copies(title)); + rv |= bundle->GetStringFromName(NS_LITERAL_STRING("StopScriptButton").get(), + getter_Copies(stopButton)); + rv |= bundle->GetStringFromName(NS_LITERAL_STRING("WaitForScriptButton").get(), + getter_Copies(waitButton)); + rv |= bundle->GetStringFromName(NS_LITERAL_STRING("KillScriptMessage").get(), + getter_Copies(msg)); + + + // GetStringFromName can return NS_OK and still give NULL string + if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton) { + NS_ERROR("Failed to get localized strings."); + return PR_TRUE; + } + + PRInt32 buttonPressed = 1; // In case user exits dialog by clicking X + PRUint32 buttonFlags = (nsIPrompt::BUTTON_TITLE_IS_STRING * + (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1)); + + // Open the dialog. + rv = prompt->ConfirmEx(title, msg, buttonFlags, stopButton, waitButton, + nsnull, nsnull, nsnull, &buttonPressed); + + if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) { + // Request stopping the unresponsive code + return PR_TRUE; + } else { + return PR_FALSE; + } +} + /* static */ PRBool nsXFormsUtils::ExperimentalFeaturesEnabled() { diff --git a/mozilla/extensions/xforms/nsXFormsUtils.h b/mozilla/extensions/xforms/nsXFormsUtils.h index b3bc5957e35..e122d34763b 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.h +++ b/mozilla/extensions/xforms/nsXFormsUtils.h @@ -72,6 +72,7 @@ class nsIXPathEvaluatorInternal; #define NS_NAMESPACE_MOZ_XFORMS_LAZY "http://www.mozilla.org/projects/xforms/2005/lazy" #define PREF_EXPERIMENTAL_FEATURES "xforms.enableExperimentalFeatures" +#define PREF_WAIT_LIMIT "dom.max_script_run_time" #define NS_ERROR_XFORMS_CALCULATION_EXCEPTION \ NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 3001) @@ -716,10 +717,26 @@ public: * In valid XForms documents this should only be possible if aNode is an * xf:select/1 or an xf:choices element. This function is used primarily * as a worker function for select/1's IsContentAllowed override. - */ static NS_HIDDEN_(PRBool) NodeHasItemset(nsIDOMNode *aNode); + /** + * Ask the user if she would like to stop the current long-running script + * component. Returns PR_TRUE if yes, otherwise PR_FALSE. + * + * @param aElement An element in the current document; used to + * find the window for the prompt + */ + static NS_HIDDEN_(PRBool) AskStopWaiting(nsIDOMElement *aElement); + + /** + * Caches the current value of the PREF_WAIT_LIMIT preference, which + * stores the number of seconds that a user should have to wait before she + * is given an opportunity to stop the busy section of the processor. (A + * value of 0 indicates that the user does not want to be prompted.) + */ + static NS_HIDDEN_(PRInt32) waitLimit; + /** * Variable is true if the 'xforms.enableExperimentalFeatures' preference has * been enabled in the browser. We currently use this preference to surround