Bug 523666. Make nsGenericHTMLFormElement::mForm an nsHTMLFormElement. r=sicking

This commit is contained in:
Boris Zbarsky 2009-10-29 21:49:11 -04:00
parent 4c55c31dc5
commit 9804e7b2dc
9 changed files with 511 additions and 572 deletions

View File

@ -43,7 +43,6 @@
class nsIFormControl;
class nsISimpleEnumerator;
class nsIURI;
template<class T> class nsTArray;
#define NS_FORM_METHOD_GET 0
#define NS_FORM_METHOD_POST 1
@ -53,13 +52,12 @@ template<class T> class nsTArray;
// IID for the nsIForm interface
#define NS_IFORM_IID \
{ 0x6e8456c2, 0xcf49, 0x4b6d, \
{ 0xb5, 0xfe, 0x80, 0x0d, 0x03, 0x4f, 0x55, 0x33 } }
{ 0x27f1ff6c, 0xeb78, 0x405b, \
{ 0xa6, 0xeb, 0xf0, 0xce, 0xa8, 0x30, 0x85, 0x58 } }
/**
* This interface provides a complete set of methods dealing with
* elements which belong to a form element. When nsIDOMHTMLCollection
* allows write operations
* This interface provides some methods that can be used to access the
* guts of a form. It's being slowly phased out.
*/
class nsIForm : public nsISupports
@ -67,27 +65,6 @@ class nsIForm : public nsISupports
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFORM_IID)
/**
* Add an element to end of this form's list of elements
*
* @param aElement the element to add
* @param aNotify If true, send nsIDocumentObserver notifications as needed.
* @return NS_OK if the element was successfully added
*/
NS_IMETHOD AddElement(nsIFormControl* aElement,
PRBool aNotify) = 0;
/**
* Add an element to the lookup table mainted by the form.
*
* We can't fold this method into AddElement() because when
* AddElement() is called, the form control has no
* attributes. The name or id attributes of the form control
* are used as a key into the table.
*/
NS_IMETHOD AddElementToTable(nsIFormControl* aElement,
const nsAString& aName) = 0;
/**
* Get the element at a specified index position in form.elements
*
@ -95,7 +72,7 @@ public:
* @param aElement the element at that index
* @return NS_OK if there was an element at that position, -1 otherwise
*/
NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const = 0;
NS_IMETHOD_(nsIFormControl*) GetElementAt(PRInt32 aIndex) const = 0;
/**
* Get the number of elements in form.elements
@ -105,30 +82,6 @@ public:
*/
NS_IMETHOD_(PRUint32) GetElementCount() const = 0;
/**
* Remove an element from this form's list of elements
*
* @param aElement the element to remove
* @param aNotify If true, send nsIDocumentObserver notifications as needed.
* @return NS_OK if the element was successfully removed.
*/
NS_IMETHOD RemoveElement(nsIFormControl* aElement,
PRBool aNotify) = 0;
/**
* Remove an element from the lookup table mainted by the form.
* We can't fold this method into RemoveElement() because when
* RemoveElement() is called it doesn't know if the element is
* removed because the id attribute has changed, or bacause the
* name attribute has changed.
*
* @param aElement the element to remove
* @param aName the name or id of the element to remove
* @return NS_OK if the element was successfully removed.
*/
NS_IMETHOD RemoveElementFromTable(nsIFormControl* aElement,
const nsAString& aName) = 0;
/**
* Resolve a name in the scope of the form object, this means find
* form controls in this form with the correct value in the name
@ -147,68 +100,11 @@ public:
*/
NS_IMETHOD_(PRInt32) IndexOfControl(nsIFormControl* aControl) = 0;
/**
* Flag the form to know that a button or image triggered scripted form
* submission. In that case the form will defer the submission until the
* script handler returns and the return value is known.
*/
NS_IMETHOD OnSubmitClickBegin() = 0;
NS_IMETHOD OnSubmitClickEnd() = 0;
/**
* Flush a possible pending submission. If there was a scripted submission
* triggered by a button or image, the submission was defered. This method
* forces the pending submission to be submitted. (happens when the handler
* returns false or there is an action/target change in the script)
*/
NS_IMETHOD FlushPendingSubmission() = 0;
/**
* Forget a possible pending submission. Same as above but this time we
* get rid of the pending submission cause the handler returned true
* so we will rebuild the submission with the name/value of the triggering
* element
*/
NS_IMETHOD ForgetPendingSubmission() = 0;
/**
* Get the full URL to submit to. Do not submit if the returned URL is null.
*
* @param aActionURL the full, unadulterated URL you'll be submitting to [OUT]
*/
NS_IMETHOD GetActionURL(nsIURI** aActionURL) = 0;
/**
* Get the list of all the form's controls in document order.
* This list contains all form control elements, not just those
* returned by form.elements in JS. The controls in this list do
* not have additional references added.
*
* @param aControls Sorted list of form controls [out].
* @return NS_OK if the list was successfully created.
*/
NS_IMETHOD GetSortedControls(nsTArray<nsIFormControl*>& aControls) const = 0;
/**
* Get the default submit element. If there's no default submit element,
* return null.
*/
NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const = 0;
/**
* Check whether a given nsIFormControl is the default submit
* element. This is different from just comparing to
* GetDefaultSubmitElement() in certain situations inside an update
* when GetDefaultSubmitElement() might not be up to date. aControl
* is expected to not be null.
*/
NS_IMETHOD_(PRBool) IsDefaultSubmitElement(const nsIFormControl* aControl) const = 0;
/**
* Return whether there is one and only one input text control.
*
* @return Whether there is exactly one input text control.
*/
NS_IMETHOD_(PRBool) HasSingleTextControl() const = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIForm, NS_IFORM_IID)

View File

@ -98,6 +98,7 @@
#include "nsIForm.h"
#include "nsIFormControl.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsHTMLFormElement.h"
#include "nsFocusManager.h"
#include "nsMutationEvent.h"
@ -897,8 +898,8 @@ nsGenericHTMLElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
nsGenericElement::UnbindFromTree(aDeep, aNullParent);
}
already_AddRefed<nsIDOMHTMLFormElement>
nsGenericHTMLElement::FindForm(nsIForm* aCurrentForm)
nsHTMLFormElement*
nsGenericHTMLElement::FindForm(nsHTMLFormElement* aCurrentForm)
{
// Make sure we don't end up finding a form that's anonymous from
// our point of view.
@ -921,10 +922,7 @@ nsGenericHTMLElement::FindForm(nsIForm* aCurrentForm)
}
}
#endif
nsIDOMHTMLFormElement* form;
CallQueryInterface(content, &form);
return form;
return static_cast<nsHTMLFormElement*>(content);
}
nsIContent *prevContent = content;
@ -938,19 +936,9 @@ nsGenericHTMLElement::FindForm(nsIForm* aCurrentForm)
// we're one of those inputs-in-a-table that have a hacked mForm pointer
// and a subtree containing both us and the form got removed from the
// DOM.
nsCOMPtr<nsIContent> formCOMPtr = do_QueryInterface(aCurrentForm);
NS_ASSERTION(formCOMPtr, "aCurrentForm isn't an nsIContent?");
// Use an nsIContent temporary to reduce addref/releasing as we go up the
// tree
nsINode* iter = formCOMPtr;
do {
iter = iter->GetNodeParent();
if (iter == prevContent) {
nsIDOMHTMLFormElement* form;
CallQueryInterface(aCurrentForm, &form);
return form;
}
} while (iter);
if (nsContentUtils::ContentIsDescendantOf(aCurrentForm, prevContent)) {
return aCurrentForm;
}
}
}
@ -2265,9 +2253,9 @@ nsGenericHTMLElement::SetContentEditable(const nsAString& aContentEditable)
NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsGenericHTMLFrameElement, TabIndex, tabindex, 0)
nsGenericHTMLFormElement::nsGenericHTMLFormElement(nsINodeInfo *aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
: nsGenericHTMLElement(aNodeInfo),
mForm(nsnull)
{
mForm = nsnull;
}
nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
@ -2302,8 +2290,7 @@ nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm)
"We don't support switching from one non-null form to another.");
// keep a *weak* ref to the form here
CallQueryInterface(aForm, &mForm);
mForm->Release();
mForm = static_cast<nsHTMLFormElement*>(aForm);
}
void
@ -2341,12 +2328,7 @@ NS_IMETHODIMP
nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm)
{
NS_ENSURE_ARG_POINTER(aForm);
*aForm = nsnull;
if (mForm) {
CallQueryInterface(mForm, aForm);
}
NS_IF_ADDREF(*aForm = mForm);
return NS_OK;
}
@ -2434,10 +2416,7 @@ nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
// it to the right value. Also note that even if being bound here didn't
// change our parent, we still need to search, since our parent chain
// probably changed _somewhere_.
nsCOMPtr<nsIDOMHTMLFormElement> form = FindForm();
if (form) {
SetForm(form);
}
mForm = FindForm();
}
if (mForm && !HasFlag(ADDED_TO_FORM)) {
@ -2476,8 +2455,7 @@ nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
ClearForm(PR_TRUE, PR_TRUE);
} else {
// Recheck whether we should still have an mForm.
nsCOMPtr<nsIDOMHTMLFormElement> form = FindForm(mForm);
if (!form) {
if (!FindForm(mForm)) {
ClearForm(PR_TRUE, PR_TRUE);
} else {
UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);

View File

@ -62,6 +62,7 @@ class nsILayoutHistoryState;
class nsIEditor;
struct nsRect;
struct nsSize;
class nsHTMLFormElement;
typedef nsMappedAttributeElement nsGenericHTMLElementBase;
@ -506,7 +507,7 @@ public:
* returned. This is needed to handle cases when HTML elements have a
* current form that they're not descendants of.
*/
already_AddRefed<nsIDOMHTMLFormElement> FindForm(nsIForm* aCurrentForm = nsnull);
nsHTMLFormElement* FindForm(nsHTMLFormElement* aCurrentForm = nsnull);
virtual void RecompileScriptEventListeners();
@ -855,7 +856,7 @@ protected:
FocusTristate FocusState();
/** The form that contains this control */
nsIForm* mForm;
nsHTMLFormElement* mForm;
};
// If this flag is set on an nsGenericHTMLFormElement, that means that we have

View File

@ -61,6 +61,7 @@
#include "nsPresState.h"
#include "nsLayoutErrors.h"
#include "nsFocusManager.h"
#include "nsHTMLFormElement.h"
#define NS_IN_SUBMIT_CLICK (1 << 0)
#define NS_OUTER_ACTIVATE_EVENT (1 << 1)
@ -464,8 +465,9 @@ nsHTMLButtonElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
// Using presShell to dispatch the event. It makes sure that
// event is not handled if the window is being destroyed.
if (presShell) {
nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
presShell->HandleDOMEventWithTarget(form, &event, &status);
// Hold a strong ref while dispatching
nsRefPtr<nsHTMLFormElement> form(mForm);
presShell->HandleDOMEventWithTarget(mForm, &event, &status);
}
}
}

View File

@ -34,16 +34,10 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsIForm.h"
#include "nsIFormControl.h"
#include "nsIFormSubmission.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIDOMNSHTMLFormElement.h"
#include "nsHTMLFormElement.h"
#include "nsIHTMLDocument.h"
#include "nsIDOMNSHTMLFormControlList.h"
#include "nsIDOMEventTarget.h"
#include "nsGenericHTMLElement.h"
#include "nsEventStateManager.h"
#include "nsGkAtoms.h"
#include "nsStyleConsts.h"
@ -63,28 +57,23 @@
// form submission
#include "nsIFormSubmitObserver.h"
#include "nsIURI.h"
#include "nsIObserverService.h"
#include "nsICategoryManager.h"
#include "nsCategoryManagerUtils.h"
#include "nsISimpleEnumerator.h"
#include "nsPIDOMWindow.h"
#include "nsRange.h"
#include "nsIScriptSecurityManager.h"
#include "nsNetUtil.h"
#include "nsIWebProgress.h"
#include "nsIDocShell.h"
#include "nsIWebProgressListener.h"
// radio buttons
#include "nsIDOMHTMLInputElement.h"
#include "nsIRadioControlElement.h"
#include "nsIRadioVisitor.h"
#include "nsIRadioGroupContainer.h"
#include "nsLayoutUtils.h"
#include "nsUnicharUtils.h"
#include "nsEventDispatcher.h"
#include "mozAutoDocUpdate.h"
@ -92,280 +81,8 @@
static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16;
class nsFormControlList;
/**
* hashkey wrapper using nsAString KeyType
*
* @see nsTHashtable::EntryType for specification
*/
class nsStringCaseInsensitiveHashKey : public PLDHashEntryHdr
{
public:
typedef const nsAString& KeyType;
typedef const nsAString* KeyTypePointer;
nsStringCaseInsensitiveHashKey(KeyTypePointer aStr) : mStr(*aStr) { } //take it easy just deal HashKey
nsStringCaseInsensitiveHashKey(const nsStringCaseInsensitiveHashKey& toCopy) : mStr(toCopy.mStr) { }
~nsStringCaseInsensitiveHashKey() { }
KeyType GetKey() const { return mStr; }
PRBool KeyEquals(const KeyTypePointer aKey) const
{
return mStr.Equals(*aKey,nsCaseInsensitiveStringComparator());
}
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
static PLDHashNumber HashKey(const KeyTypePointer aKey)
{
nsAutoString tmKey(*aKey);
ToLowerCase(tmKey);
return HashString(tmKey);
}
enum { ALLOW_MEMMOVE = PR_TRUE };
private:
const nsString mStr;
};
// nsHTMLFormElement
class nsHTMLFormElement : public nsGenericHTMLElement,
public nsIDOMHTMLFormElement,
public nsIDOMNSHTMLFormElement,
public nsIWebProgressListener,
public nsIForm,
public nsIRadioGroupContainer
{
public:
nsHTMLFormElement(nsINodeInfo *aNodeInfo);
virtual ~nsHTMLFormElement();
nsresult Init();
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMNode
NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
// nsIDOMElement
NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
// nsIDOMHTMLElement
NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
// nsIDOMHTMLFormElement
NS_DECL_NSIDOMHTMLFORMELEMENT
// nsIDOMNSHTMLFormElement
NS_DECL_NSIDOMNSHTMLFORMELEMENT
// nsIWebProgressListener
NS_DECL_NSIWEBPROGRESSLISTENER
// nsIForm
NS_IMETHOD AddElement(nsIFormControl* aElement,
PRBool aNotify);
NS_IMETHOD AddElementToTable(nsIFormControl* aChild,
const nsAString& aName);
NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const;
NS_IMETHOD_(PRUint32) GetElementCount() const;
NS_IMETHOD RemoveElement(nsIFormControl* aElement,
PRBool aNotify);
NS_IMETHOD RemoveElementFromTable(nsIFormControl* aElement,
const nsAString& aName);
NS_IMETHOD_(already_AddRefed<nsISupports>) ResolveName(const nsAString& aName);
NS_IMETHOD_(PRInt32) IndexOfControl(nsIFormControl* aControl);
NS_IMETHOD OnSubmitClickBegin();
NS_IMETHOD OnSubmitClickEnd();
NS_IMETHOD FlushPendingSubmission();
NS_IMETHOD ForgetPendingSubmission();
NS_IMETHOD GetActionURL(nsIURI** aActionURL);
NS_IMETHOD GetSortedControls(nsTArray<nsIFormControl*>& aControls) const;
NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const;
NS_IMETHOD_(PRBool) IsDefaultSubmitElement(const nsIFormControl* aControl) const;
NS_IMETHOD_(PRBool) HasSingleTextControl() const;
// nsIRadioGroupContainer
NS_IMETHOD SetCurrentRadioButton(const nsAString& aName,
nsIDOMHTMLInputElement* aRadio);
NS_IMETHOD GetCurrentRadioButton(const nsAString& aName,
nsIDOMHTMLInputElement** aRadio);
NS_IMETHOD GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
PRInt32 *aPositionIndex,
PRInt32 *aItemsInGroup);
NS_IMETHOD GetNextRadioButton(const nsAString& aName,
const PRBool aPrevious,
nsIDOMHTMLInputElement* aFocusedRadio,
nsIDOMHTMLInputElement** aRadioOut);
NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
PRBool aFlushContent);
NS_IMETHOD AddToRadioGroup(const nsAString& aName,
nsIFormControl* aRadio);
NS_IMETHOD RemoveFromRadioGroup(const nsAString& aName,
nsIFormControl* aRadio);
// nsIContent
virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult);
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual nsresult WillHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers);
virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
PRBool aNullParent = PR_TRUE);
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, PRBool aNotify)
{
return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
}
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify);
/**
* Forget all information about the current submission (and the fact that we
* are currently submitting at all).
*/
void ForgetCurrentSubmission();
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLFormElement,
nsGenericHTMLElement)
protected:
class RemoveElementRunnable;
friend class RemoveElementRunnable;
class RemoveElementRunnable : public nsRunnable {
public:
RemoveElementRunnable(nsHTMLFormElement* aForm, PRBool aNotify):
mForm(aForm), mNotify(aNotify)
{}
NS_IMETHOD Run() {
mForm->HandleDefaultSubmitRemoval(mNotify);
return NS_OK;
}
private:
nsRefPtr<nsHTMLFormElement> mForm;
PRBool mNotify;
};
nsresult DoSubmitOrReset(nsEvent* aEvent,
PRInt32 aMessage);
nsresult DoReset();
// Async callback to handle removal of our default submit
void HandleDefaultSubmitRemoval(PRBool aNotify);
//
// Submit Helpers
//
//
/**
* Attempt to submit (submission might be deferred)
* (called by DoSubmitOrReset)
*
* @param aPresContext the presentation context
* @param aEvent the DOM event that was passed to us for the submit
*/
nsresult DoSubmit(nsEvent* aEvent);
/**
* Prepare the submission object (called by DoSubmit)
*
* @param aFormSubmission the submission object
* @param aEvent the DOM event that was passed to us for the submit
*/
nsresult BuildSubmission(nsCOMPtr<nsIFormSubmission>& aFormSubmission,
nsEvent* aEvent);
/**
* Perform the submission (called by DoSubmit and FlushPendingSubmission)
*
* @param aFormSubmission the submission object
*/
nsresult SubmitSubmission(nsIFormSubmission* aFormSubmission);
/**
* Walk over the form elements and call SubmitNamesValues() on them to get
* their data pumped into the FormSubmitter.
*
* @param aFormSubmission the form submission object
* @param aSubmitElement the element that was clicked on (nsnull if none)
*/
nsresult WalkFormElements(nsIFormSubmission* aFormSubmission,
nsIContent* aSubmitElement);
/**
* Notify any submit observers of the submit.
*
* @param aActionURL the URL being submitted to
* @param aCancelSubmit out param where submit observers can specify that the
* submit should be cancelled.
*/
nsresult NotifySubmitObservers(nsIURI* aActionURL, PRBool* aCancelSubmit,
PRBool aEarlyNotify);
/**
* Just like ResolveName(), but takes an arg for whether to flush
*/
already_AddRefed<nsISupports> DoResolveName(const nsAString& aName, PRBool aFlushContent);
//
// Data members
//
/** The list of controls (form.elements as well as stuff not in elements) */
nsRefPtr<nsFormControlList> mControls;
/** The currently selected radio button of each group */
nsInterfaceHashtable<nsStringCaseInsensitiveHashKey,nsIDOMHTMLInputElement> mSelectedRadioButtons;
/** Whether we are currently processing a submit event or not */
PRPackedBool mGeneratingSubmit;
/** Whether we are currently processing a reset event or not */
PRPackedBool mGeneratingReset;
/** Whether we are submitting currently */
PRPackedBool mIsSubmitting;
/** Whether the submission is to be deferred in case a script triggers it */
PRPackedBool mDeferSubmission;
/** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */
PRPackedBool mNotifiedObservers;
/** If we notified the listeners early, what was the result? */
PRPackedBool mNotifiedObserversResult;
/** Keep track of what the popup state was when the submit was initiated */
PopupControlState mSubmitPopupState;
/** Keep track of whether a submission was user-initiated or not */
PRBool mSubmitInitiatedFromUserInput;
/** The pending submission object */
nsCOMPtr<nsIFormSubmission> mPendingSubmission;
/** The request currently being submitted */
nsCOMPtr<nsIRequest> mSubmittingRequest;
/** The web progress object we are currently listening to */
nsWeakPtr mWebProgress;
/** The default submit element -- WEAK */
nsIFormControl* mDefaultSubmitElement;
/** The first submit element in mElements -- WEAK */
nsIFormControl* mFirstSubmitInElements;
/** The first submit element in mNotInElements -- WEAK */
nsIFormControl* mFirstSubmitNotInElements;
protected:
/** Detection of first form to notify observers */
static PRBool gFirstFormSubmitted;
/** Detection of first password input to initialize the password manager */
static PRBool gPasswordManagerInitialized;
};
PRBool nsHTMLFormElement::gFirstFormSubmitted = PR_FALSE;
PRBool nsHTMLFormElement::gPasswordManagerInitialized = PR_FALSE;
@ -396,7 +113,8 @@ public:
*aResult = NS_OK;
return mElements.SafeElementAt(aIndex, nsnull);
// XXXbz this should start returning nsINode* or something!
return static_cast<nsIFormControl*>(mElements.SafeElementAt(aIndex, nsnull));
}
virtual nsISupports* GetNamedItem(const nsAString& aName, nsresult* aResult)
{
@ -405,9 +123,9 @@ public:
return NamedItemInternal(aName, PR_TRUE);
}
nsresult AddElementToTable(nsIFormControl* aChild,
nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName);
nsresult RemoveElementFromTable(nsIFormControl* aChild,
nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName);
nsresult IndexOfControl(nsIFormControl* aControl,
PRInt32* aIndex);
@ -423,18 +141,18 @@ public:
* @param aControls The list of sorted controls[out].
* @return NS_OK or NS_ERROR_OUT_OF_MEMORY.
*/
nsresult GetSortedControls(nsTArray<nsIFormControl*>& aControls) const;
nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
nsHTMLFormElement* mForm; // WEAK - the form owns me
nsTArray<nsIFormControl*> mElements; // Holds WEAK references - bug 36639
nsTArray<nsGenericHTMLFormElement*> mElements; // Holds WEAK references - bug 36639
// This array holds on to all form controls that are not contained
// in mElements (form.elements in JS, see ShouldBeInFormControl()).
// This is needed to properly clean up the bi-directional references
// (both weak and strong) between the form and its form controls.
nsTArray<nsIFormControl*> mNotInElements; // Holds WEAK references
nsTArray<nsGenericHTMLFormElement*> mNotInElements; // Holds WEAK references
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFormControlList, nsIHTMLCollection)
@ -751,18 +469,16 @@ nsHTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
}
static void
MarkOrphans(const nsTArray<nsIFormControl*> aArray)
MarkOrphans(const nsTArray<nsGenericHTMLFormElement*> aArray)
{
PRUint32 length = aArray.Length();
for (PRUint32 i = 0; i < length; ++i) {
nsCOMPtr<nsINode> node = do_QueryInterface(aArray[i]);
NS_ASSERTION(node, "Form control must be nsINode");
node->SetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
aArray[i]->SetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
}
}
static void
CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsIFormControl*> aArray
CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsGenericHTMLFormElement*> aArray
#ifdef DEBUG
, nsIDOMHTMLFormElement* aThisForm
#endif
@ -771,9 +487,7 @@ CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsIFormControl*> aArray
// Walk backwards so that if we remove elements we can just keep iterating
PRUint32 length = aArray.Length();
for (PRUint32 i = length; i > 0; --i) {
nsIFormControl* control = aArray[i-1];
nsCOMPtr<nsINode> node = do_QueryInterface(control);
NS_ASSERTION(node, "Form control must be nsINode");
nsGenericHTMLFormElement* node = aArray[i-1];
// Now if MAYBE_ORPHAN_FORM_ELEMENT is not set, that would mean that the
// node is in fact a descendant of the form and hence should stay in the
@ -786,7 +500,7 @@ CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsIFormControl*> aArray
if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) {
node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) {
control->ClearForm(PR_TRUE, PR_TRUE);
node->ClearForm(PR_TRUE, PR_TRUE);
#ifdef DEBUG
removed = PR_TRUE;
#endif
@ -796,7 +510,7 @@ CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsIFormControl*> aArray
#ifdef DEBUG
if (!removed) {
nsCOMPtr<nsIDOMHTMLFormElement> form;
control->GetForm(getter_AddRefs(form));
node->GetForm(getter_AddRefs(form));
NS_ASSERTION(form == aThisForm, "How did that happen?");
}
#endif /* DEBUG */
@ -964,8 +678,8 @@ nsHTMLFormElement::DoReset()
// JBK walk the elements[] array instead of form frame controls - bug 34297
PRUint32 numElements = GetElementCount();
for (PRUint32 elementX = 0; (elementX < numElements); elementX++) {
nsCOMPtr<nsIFormControl> controlNode;
GetElementAt(elementX, getter_AddRefs(controlNode));
// Hold strong ref in case the reset does something weird
nsCOMPtr<nsIFormControl> controlNode = GetElementAt(elementX);
if (controlNode) {
controlNode->Reset();
}
@ -1236,7 +950,7 @@ nsresult
nsHTMLFormElement::WalkFormElements(nsIFormSubmission* aFormSubmission,
nsIContent* aSubmitElement)
{
nsTArray<nsIFormControl*> sortedControls;
nsTArray<nsGenericHTMLFormElement*> sortedControls;
nsresult rv = mControls->GetSortedControls(sortedControls);
NS_ENSURE_SUCCESS(rv, rv);
@ -1262,19 +976,10 @@ nsHTMLFormElement::GetElementCount() const
return count;
}
NS_IMETHODIMP
nsHTMLFormElement::GetElementAt(PRInt32 aIndex,
nsIFormControl** aFormControl) const
NS_IMETHODIMP_(nsIFormControl*)
nsHTMLFormElement::GetElementAt(PRInt32 aIndex) const
{
// Converting to unsigned int will handle negative indices.
if (PRUint32(aIndex) >= mControls->mElements.Length()) {
*aFormControl = nsnull;
} else {
*aFormControl = mControls->mElements[aIndex];
NS_ADDREF(*aFormControl);
}
return NS_OK;
return mControls->mElements.SafeElementAt(aIndex, nsnull);
}
/**
@ -1286,21 +991,17 @@ nsHTMLFormElement::GetElementAt(PRInt32 aIndex,
* > 0 if aControl1 is after aControl2,
* 0 otherwise
*/
static PRInt32 CompareFormControlPosition(nsIFormControl *aControl1,
nsIFormControl *aControl2,
const nsIContent* aForm)
static inline PRInt32
CompareFormControlPosition(nsGenericHTMLFormElement *aControl1,
nsGenericHTMLFormElement *aControl2,
const nsIContent* aForm)
{
NS_ASSERTION(aControl1 != aControl2, "Comparing a form control to itself");
nsCOMPtr<nsIContent> content1 = do_QueryInterface(aControl1);
nsCOMPtr<nsIContent> content2 = do_QueryInterface(aControl2);
NS_ASSERTION(content1 && content2,
"We should be able to QI to nsIContent here!");
NS_ASSERTION(content1->GetParent() && content2->GetParent(),
NS_ASSERTION(aControl1->GetParent() && aControl2->GetParent(),
"Form controls should always have parents");
return nsLayoutUtils::CompareTreePosition(content1, content2, aForm);
return nsLayoutUtils::CompareTreePosition(aControl1, aControl2, aForm);
}
#ifdef DEBUG
@ -1312,7 +1013,7 @@ static PRInt32 CompareFormControlPosition(nsIFormControl *aControl1,
* @param aForm Parent form of the controls.
*/
static void
AssertDocumentOrder(const nsTArray<nsIFormControl*>& aControls,
AssertDocumentOrder(const nsTArray<nsGenericHTMLFormElement*>& aControls,
nsIContent* aForm)
{
// Only iterate if aControls is not empty, since otherwise
@ -1328,29 +1029,23 @@ AssertDocumentOrder(const nsTArray<nsIFormControl*>& aControls,
}
#endif
NS_IMETHODIMP
nsHTMLFormElement::AddElement(nsIFormControl* aChild,
nsresult
nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
PRBool aNotify)
{
#ifdef DEBUG
{
nsCOMPtr<nsIContent> content = do_QueryInterface(aChild);
NS_ASSERTION(content->GetParent(),
"Form control should have a parent");
}
#endif
NS_ASSERTION(aChild->GetParent(), "Form control should have a parent");
// Determine whether to add the new element to the elements or
// the not-in-elements list.
PRBool childInElements = ShouldBeInElements(aChild);
nsTArray<nsIFormControl*>& controlList = childInElements ?
nsTArray<nsGenericHTMLFormElement*>& controlList = childInElements ?
mControls->mElements : mControls->mNotInElements;
NS_ASSERTION(controlList.IndexOf(aChild) == controlList.NoIndex,
"Form control already in form");
PRUint32 count = controlList.Length();
nsCOMPtr<nsIFormControl> element;
nsGenericHTMLFormElement* element;
// Optimize most common case where we insert at the end.
PRBool lastElement = PR_FALSE;
@ -1396,7 +1091,8 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild,
//
PRInt32 type = aChild->GetType();
if (type == NS_FORM_INPUT_RADIO) {
nsCOMPtr<nsIRadioControlElement> radio = do_QueryInterface(aChild);
nsCOMPtr<nsIRadioControlElement> radio;
CallQueryInterface(aChild, getter_AddRefs(radio));
nsresult rv = radio->AddedToRadioGroup();
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1418,7 +1114,7 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild,
// Update mDefaultSubmitElement, mFirstSubmitInElements,
// mFirstSubmitNotInElements.
nsIFormControl** firstSubmitSlot =
nsGenericHTMLFormElement** firstSubmitSlot =
childInElements ? &mFirstSubmitInElements : &mFirstSubmitNotInElements;
// The new child is the new first submit in its list if the firstSubmitSlot
@ -1469,16 +1165,16 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild,
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::AddElementToTable(nsIFormControl* aChild,
nsresult
nsHTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName)
{
return mControls->AddElementToTable(aChild, aName);
}
NS_IMETHODIMP
nsHTMLFormElement::RemoveElement(nsIFormControl* aChild,
nsresult
nsHTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
PRBool aNotify)
{
//
@ -1486,7 +1182,8 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild,
//
nsresult rv = NS_OK;
if (aChild->GetType() == NS_FORM_INPUT_RADIO) {
nsCOMPtr<nsIRadioControlElement> radio = do_QueryInterface(aChild);
nsCOMPtr<nsIRadioControlElement> radio;
CallQueryInterface(aChild, getter_AddRefs(radio));
rv = radio->WillRemoveFromRadioGroup();
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1494,7 +1191,7 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild,
// Determine whether to remove the child from the elements list
// or the not in elements list.
PRBool childInElements = ShouldBeInElements(aChild);
nsTArray<nsIFormControl*>& controls = childInElements ?
nsTArray<nsGenericHTMLFormElement*>& controls = childInElements ?
mControls->mElements : mControls->mNotInElements;
// Find the index of the child. This will be used later if necessary
@ -1505,7 +1202,7 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild,
controls.RemoveElementAt(index);
// Update our mFirstSubmit* values.
nsIFormControl** firstSubmitSlot =
nsGenericHTMLFormElement** firstSubmitSlot =
childInElements ? &mFirstSubmitInElements : &mFirstSubmitNotInElements;
if (aChild == *firstSubmitSlot) {
*firstSubmitSlot = nsnull;
@ -1513,7 +1210,7 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild,
// We are removing the first submit in this list, find the new first submit
PRUint32 length = controls.Length();
for (PRUint32 i = index; i < length; ++i) {
nsIFormControl* currentControl = controls[i];
nsGenericHTMLFormElement* currentControl = controls[i];
if (currentControl->IsSubmitControl()) {
*firstSubmitSlot = currentControl;
break;
@ -1567,15 +1264,14 @@ nsHTMLFormElement::HandleDefaultSubmitRemoval(PRBool aNotify)
nsIDocument* document = GetCurrentDoc();
if (document) {
MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE);
nsCOMPtr<nsIContent> newElement(do_QueryInterface(mDefaultSubmitElement));
document->ContentStatesChanged(newElement, nsnull,
document->ContentStatesChanged(mDefaultSubmitElement, nsnull,
NS_EVENT_STATE_DEFAULT);
}
}
}
NS_IMETHODIMP
nsHTMLFormElement::RemoveElementFromTable(nsIFormControl* aElement,
nsresult
nsHTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
const nsAString& aName)
{
return mControls->RemoveElementFromTable(aElement, aName);
@ -1596,7 +1292,7 @@ nsHTMLFormElement::DoResolveName(const nsAString& aName,
return result;
}
NS_IMETHODIMP
void
nsHTMLFormElement::OnSubmitClickBegin()
{
mDeferSubmission = PR_TRUE;
@ -1609,7 +1305,7 @@ nsHTMLFormElement::OnSubmitClickBegin()
rv = GetActionURL(getter_AddRefs(actionURI));
if (NS_FAILED(rv) || !actionURI)
return NS_OK;
return;
//
// Notify observers of submit
@ -1620,24 +1316,21 @@ nsHTMLFormElement::OnSubmitClickBegin()
mNotifiedObservers = PR_TRUE;
mNotifiedObserversResult = cancelSubmit;
}
return NS_OK;
}
NS_IMETHODIMP
void
nsHTMLFormElement::OnSubmitClickEnd()
{
mDeferSubmission = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
void
nsHTMLFormElement::FlushPendingSubmission()
{
nsCOMPtr<nsIFormSubmission> kunkFuDeathGrip(mPendingSubmission);
if (!mPendingSubmission) {
return NS_OK;
return;
}
//
@ -1647,18 +1340,16 @@ nsHTMLFormElement::FlushPendingSubmission()
// now delete the pending submission object
mPendingSubmission = nsnull;
return NS_OK;
}
NS_IMETHODIMP
void
nsHTMLFormElement::ForgetPendingSubmission()
{
// just delete the pending submission
mPendingSubmission = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsresult
nsHTMLFormElement::GetActionURL(nsIURI** aActionURL)
{
nsresult rv = NS_OK;
@ -1736,12 +1427,6 @@ nsHTMLFormElement::GetActionURL(nsIURI** aActionURL)
return rv;
}
NS_IMETHODIMP
nsHTMLFormElement::GetSortedControls(nsTArray<nsIFormControl*>& aControls) const
{
return mControls->GetSortedControls(aControls);
}
NS_IMETHODIMP_(nsIFormControl*)
nsHTMLFormElement::GetDefaultSubmitElement() const
{
@ -1752,7 +1437,7 @@ nsHTMLFormElement::GetDefaultSubmitElement() const
return mDefaultSubmitElement;
}
NS_IMETHODIMP_(PRBool)
PRBool
nsHTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const
{
NS_PRECONDITION(aControl, "Unexpected call");
@ -1787,7 +1472,7 @@ nsHTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const
return aControl == defaultSubmit;
}
NS_IMETHODIMP_(PRBool)
PRBool
nsHTMLFormElement::HasSingleTextControl() const
{
// Input text controls are always in the elements list.
@ -1938,12 +1623,8 @@ nsHTMLFormElement::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
nsCOMPtr<nsISupports> itemWithName;
itemWithName = ResolveName(name);
NS_ENSURE_TRUE(itemWithName, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNodeList> radioNodeList(do_QueryInterface(itemWithName));
nsCOMPtr<nsINodeList> radioGroup(do_QueryInterface(itemWithName));
// XXX If ResolveName could return an nsContentList instead then we
// could get an nsContentList instead of using this hacky upcast
nsBaseContentList *radioGroup =
static_cast<nsBaseContentList *>((nsIDOMNodeList *)radioNodeList);
NS_ASSERTION(radioGroup, "No such radio group in this container");
if (!radioGroup) {
return NS_OK;
@ -1951,7 +1632,7 @@ nsHTMLFormElement::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
nsCOMPtr<nsIContent> currentRadioNode(do_QueryInterface(aRadio));
NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button");
*aPositionIndex = radioGroup->IndexOf(currentRadioNode, PR_TRUE);
*aPositionIndex = radioGroup->IndexOf(currentRadioNode);
NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group");
PRUint32 itemsInGroup;
radioGroup->GetLength(&itemsInGroup);
@ -1979,20 +1660,15 @@ nsHTMLFormElement::GetNextRadioButton(const nsAString& aName,
}
nsCOMPtr<nsISupports> itemWithName = ResolveName(aName);
nsCOMPtr<nsIDOMNodeList> radioNodeList(do_QueryInterface(itemWithName));
nsCOMPtr<nsINodeList> radioGroup(do_QueryInterface(itemWithName));
// XXX If ResolveName could return an nsContentList instead then we
// could get an nsContentList instead of using this hacky upcast
nsBaseContentList *radioGroup =
static_cast<nsBaseContentList *>((nsIDOMNodeList *)radioNodeList);
if (!radioGroup) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContent> currentRadioNode(do_QueryInterface(currentRadio));
NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button");
PRInt32 index = radioGroup->IndexOf(currentRadioNode, PR_TRUE);
PRInt32 index = radioGroup->IndexOf(currentRadioNode);
if (index < 0) {
return NS_ERROR_FAILURE;
}
@ -2001,7 +1677,6 @@ nsHTMLFormElement::GetNextRadioButton(const nsAString& aName,
radioGroup->GetLength(&numRadios);
PRBool disabled = PR_TRUE;
nsCOMPtr<nsIDOMHTMLInputElement> radio;
nsCOMPtr<nsIDOMNode> radioDOMNode;
nsCOMPtr<nsIFormControl> formControl;
do {
@ -2013,11 +1688,11 @@ nsHTMLFormElement::GetNextRadioButton(const nsAString& aName,
else if (++index >= (PRInt32)numRadios) {
index = 0;
}
radioGroup->Item(index, getter_AddRefs(radioDOMNode));
radio = do_QueryInterface(radioDOMNode);
radio = do_QueryInterface(radioGroup->GetNodeAt(index));
if (!radio)
continue;
// XXXbz why is this formControl check needed, exactly?
formControl = do_QueryInterface(radio);
if (!formControl || formControl->GetType() != NS_FORM_INPUT_RADIO)
continue;
@ -2046,7 +1721,7 @@ nsHTMLFormElement::WalkRadioGroup(const nsAString& aName,
nsCOMPtr<nsIFormControl> control;
PRUint32 len = GetElementCount();
for (PRUint32 i=0; i<len; i++) {
GetElementAt(i, getter_AddRefs(control));
control = GetElementAt(i);
if (control->GetType() == NS_FORM_INPUT_RADIO) {
nsCOMPtr<nsIContent> controlContent(do_QueryInterface(control));
if (controlContent) {
@ -2292,7 +1967,7 @@ nsFormControlList::NamedItemInternal(const nsAString& aName,
}
nsresult
nsFormControlList::AddElementToTable(nsIFormControl* aChild,
nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName)
{
if (!ShouldBeInElements(aChild)) {
@ -2304,20 +1979,19 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild,
if (!supports) {
// No entry found, add the form control
nsCOMPtr<nsISupports> child(do_QueryInterface(aChild));
NS_ENSURE_TRUE( mNameLookupTable.Put(aName, child), NS_ERROR_FAILURE );
NS_ENSURE_TRUE( mNameLookupTable.Put(aName,
NS_ISUPPORTS_CAST(nsIContent*, aChild)),
NS_ERROR_FAILURE );
} else {
// Found something in the hash, check its type
nsCOMPtr<nsIContent> content(do_QueryInterface(supports));
nsCOMPtr<nsIContent> newChild(do_QueryInterface(aChild));
if (content) {
// Check if the new content is the same as the one we found in the
// hash, if it is then we leave it in the hash as it is, this will
// happen if a form control has both a name and an id with the same
// value
if (content == newChild) {
if (content == aChild) {
return NS_OK;
}
@ -2329,10 +2003,10 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild,
NS_ASSERTION(content->GetParent(), "Item in list without parent");
// Determine the ordering between the new and old element.
PRBool newFirst = nsContentUtils::PositionIsBefore(newChild, content);
PRBool newFirst = nsContentUtils::PositionIsBefore(aChild, content);
list->AppendElement(newFirst ? newChild : content);
list->AppendElement(newFirst ? content : newChild);
list->AppendElement(newFirst ? aChild : content);
list->AppendElement(newFirst ? content : aChild);
nsCOMPtr<nsISupports> listSupports =
@ -2353,8 +2027,8 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild,
NS_ASSERTION(list->Length() > 1,
"List should have been converted back to a single element");
if(nsContentUtils::PositionIsBefore(list->GetNodeAt(list->Length() - 1), newChild)) {
list->AppendElement(newChild);
if(nsContentUtils::PositionIsBefore(list->GetNodeAt(list->Length() - 1), aChild)) {
list->AppendElement(aChild);
return NS_OK;
}
@ -2368,13 +2042,13 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild,
while (last != first) {
mid = (first + last) / 2;
if (nsContentUtils::PositionIsBefore(newChild, list->GetNodeAt(mid)))
if (nsContentUtils::PositionIsBefore(aChild, list->GetNodeAt(mid)))
last = mid;
else
first = mid + 1;
}
list->InsertElementAt(newChild, first);
list->InsertElementAt(aChild, first);
}
}
@ -2395,18 +2069,13 @@ nsFormControlList::IndexOfControl(nsIFormControl* aControl,
}
nsresult
nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild,
nsFormControlList::RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName)
{
if (!ShouldBeInElements(aChild)) {
return NS_OK;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aChild);
if (!content) {
return NS_OK;
}
nsCOMPtr<nsISupports> supports;
if (!mNameLookupTable.Get(aName, getter_AddRefs(supports)))
@ -2431,7 +2100,7 @@ nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild,
nsBaseContentList *list = static_cast<nsBaseContentList *>
((nsIDOMNodeList *)nodeList.get());
list->RemoveElement(content);
list->RemoveElement(aChild);
PRUint32 length = 0;
list->GetLength(&length);
@ -2443,12 +2112,9 @@ nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild,
} else if (length == 1) {
// Only one element left, replace the list in the hash with the
// single element.
nsCOMPtr<nsIDOMNode> node;
list->Item(0, getter_AddRefs(node));
nsIContent* node = list->GetNodeAt(0);
if (node) {
nsCOMPtr<nsISupports> tmp(do_QueryInterface(node));
NS_ENSURE_TRUE(mNameLookupTable.Put(aName, tmp),NS_ERROR_FAILURE);
NS_ENSURE_TRUE(mNameLookupTable.Put(aName, node),NS_ERROR_FAILURE);
}
}
@ -2456,7 +2122,7 @@ nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild,
}
nsresult
nsFormControlList::GetSortedControls(nsTArray<nsIFormControl*>& aControls) const
nsFormControlList::GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const
{
#ifdef DEBUG
AssertDocumentOrder(mElements, mForm);
@ -2507,7 +2173,7 @@ nsFormControlList::GetSortedControls(nsTArray<nsIFormControl*>& aControls) const
"Should have remaining elements");
// Determine which of the two elements should be ordered
// first and add it to the end of the list.
nsIFormControl* elementToAdd;
nsGenericHTMLFormElement* elementToAdd;
if (CompareFormControlPosition(mElements[elementsIdx],
mNotInElements[notInElementsIdx],
mForm) < 0) {

View File

@ -0,0 +1,394 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsIForm.h"
#include "nsIFormControl.h"
#include "nsIFormSubmission.h"
#include "nsGenericHTMLElement.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIDOMNSHTMLFormElement.h"
#include "nsIWebProgressListener.h"
#include "nsIRadioGroupContainer.h"
#include "nsIURI.h"
#include "nsIWeakReferenceUtils.h"
#include "nsPIDOMWindow.h"
#include "nsUnicharUtils.h"
#include "nsThreadUtils.h"
class nsFormControlList;
/**
* hashkey wrapper using nsAString KeyType
*
* @see nsTHashtable::EntryType for specification
*/
class nsStringCaseInsensitiveHashKey : public PLDHashEntryHdr
{
public:
typedef const nsAString& KeyType;
typedef const nsAString* KeyTypePointer;
nsStringCaseInsensitiveHashKey(KeyTypePointer aStr) : mStr(*aStr) { } //take it easy just deal HashKey
nsStringCaseInsensitiveHashKey(const nsStringCaseInsensitiveHashKey& toCopy) : mStr(toCopy.mStr) { }
~nsStringCaseInsensitiveHashKey() { }
KeyType GetKey() const { return mStr; }
PRBool KeyEquals(const KeyTypePointer aKey) const
{
return mStr.Equals(*aKey,nsCaseInsensitiveStringComparator());
}
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
static PLDHashNumber HashKey(const KeyTypePointer aKey)
{
nsAutoString tmKey(*aKey);
ToLowerCase(tmKey);
return HashString(tmKey);
}
enum { ALLOW_MEMMOVE = PR_TRUE };
private:
const nsString mStr;
};
class nsHTMLFormElement : public nsGenericHTMLElement,
public nsIDOMHTMLFormElement,
public nsIDOMNSHTMLFormElement,
public nsIWebProgressListener,
public nsIForm,
public nsIRadioGroupContainer
{
public:
nsHTMLFormElement(nsINodeInfo *aNodeInfo);
virtual ~nsHTMLFormElement();
nsresult Init();
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMNode
NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
// nsIDOMElement
NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
// nsIDOMHTMLElement
NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
// nsIDOMHTMLFormElement
NS_DECL_NSIDOMHTMLFORMELEMENT
// nsIDOMNSHTMLFormElement
NS_DECL_NSIDOMNSHTMLFORMELEMENT
// nsIWebProgressListener
NS_DECL_NSIWEBPROGRESSLISTENER
// nsIForm
NS_IMETHOD_(nsIFormControl*) GetElementAt(PRInt32 aIndex) const;
NS_IMETHOD_(PRUint32) GetElementCount() const;
NS_IMETHOD_(already_AddRefed<nsISupports>) ResolveName(const nsAString& aName);
NS_IMETHOD_(PRInt32) IndexOfControl(nsIFormControl* aControl);
NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const;
// nsIRadioGroupContainer
NS_IMETHOD SetCurrentRadioButton(const nsAString& aName,
nsIDOMHTMLInputElement* aRadio);
NS_IMETHOD GetCurrentRadioButton(const nsAString& aName,
nsIDOMHTMLInputElement** aRadio);
NS_IMETHOD GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
PRInt32 *aPositionIndex,
PRInt32 *aItemsInGroup);
NS_IMETHOD GetNextRadioButton(const nsAString& aName,
const PRBool aPrevious,
nsIDOMHTMLInputElement* aFocusedRadio,
nsIDOMHTMLInputElement** aRadioOut);
NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
PRBool aFlushContent);
NS_IMETHOD AddToRadioGroup(const nsAString& aName,
nsIFormControl* aRadio);
NS_IMETHOD RemoveFromRadioGroup(const nsAString& aName,
nsIFormControl* aRadio);
// nsIContent
virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult);
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual nsresult WillHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers);
virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
PRBool aNullParent = PR_TRUE);
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, PRBool aNotify)
{
return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
}
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify);
/**
* Forget all information about the current submission (and the fact that we
* are currently submitting at all).
*/
void ForgetCurrentSubmission();
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLFormElement,
nsGenericHTMLElement)
/**
* Remove an element from this form's list of elements
*
* @param aElement the element to remove
* @param aNotify If true, send nsIDocumentObserver notifications as needed.
* @return NS_OK if the element was successfully removed.
*/
nsresult RemoveElement(nsGenericHTMLFormElement* aElement, PRBool aNotify);
/**
* Remove an element from the lookup table mainted by the form.
* We can't fold this method into RemoveElement() because when
* RemoveElement() is called it doesn't know if the element is
* removed because the id attribute has changed, or bacause the
* name attribute has changed.
*
* @param aElement the element to remove
* @param aName the name or id of the element to remove
* @return NS_OK if the element was successfully removed.
*/
nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
const nsAString& aName);
/**
* Add an element to end of this form's list of elements
*
* @param aElement the element to add
* @param aNotify If true, send nsIDocumentObserver notifications as needed.
* @return NS_OK if the element was successfully added
*/
nsresult AddElement(nsGenericHTMLFormElement* aElement, PRBool aNotify);
/**
* Add an element to the lookup table mainted by the form.
*
* We can't fold this method into AddElement() because when
* AddElement() is called, the form control has no
* attributes. The name or id attributes of the form control
* are used as a key into the table.
*/
nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName);
/**
* Return whether there is one and only one input text control.
*
* @return Whether there is exactly one input text control.
*/
PRBool HasSingleTextControl() const;
/**
* Check whether a given nsIFormControl is the default submit
* element. This is different from just comparing to
* GetDefaultSubmitElement() in certain situations inside an update
* when GetDefaultSubmitElement() might not be up to date. aControl
* is expected to not be null.
*/
PRBool IsDefaultSubmitElement(const nsIFormControl* aControl) const;
/**
* Flag the form to know that a button or image triggered scripted form
* submission. In that case the form will defer the submission until the
* script handler returns and the return value is known.
*/
void OnSubmitClickBegin();
void OnSubmitClickEnd();
protected:
class RemoveElementRunnable;
friend class RemoveElementRunnable;
class RemoveElementRunnable : public nsRunnable {
public:
RemoveElementRunnable(nsHTMLFormElement* aForm, PRBool aNotify):
mForm(aForm), mNotify(aNotify)
{}
NS_IMETHOD Run() {
mForm->HandleDefaultSubmitRemoval(mNotify);
return NS_OK;
}
private:
nsRefPtr<nsHTMLFormElement> mForm;
PRBool mNotify;
};
nsresult DoSubmitOrReset(nsEvent* aEvent,
PRInt32 aMessage);
nsresult DoReset();
// Async callback to handle removal of our default submit
void HandleDefaultSubmitRemoval(PRBool aNotify);
//
// Submit Helpers
//
//
/**
* Attempt to submit (submission might be deferred)
* (called by DoSubmitOrReset)
*
* @param aPresContext the presentation context
* @param aEvent the DOM event that was passed to us for the submit
*/
nsresult DoSubmit(nsEvent* aEvent);
/**
* Prepare the submission object (called by DoSubmit)
*
* @param aFormSubmission the submission object
* @param aEvent the DOM event that was passed to us for the submit
*/
nsresult BuildSubmission(nsCOMPtr<nsIFormSubmission>& aFormSubmission,
nsEvent* aEvent);
/**
* Perform the submission (called by DoSubmit and FlushPendingSubmission)
*
* @param aFormSubmission the submission object
*/
nsresult SubmitSubmission(nsIFormSubmission* aFormSubmission);
/**
* Walk over the form elements and call SubmitNamesValues() on them to get
* their data pumped into the FormSubmitter.
*
* @param aFormSubmission the form submission object
* @param aSubmitElement the element that was clicked on (nsnull if none)
*/
nsresult WalkFormElements(nsIFormSubmission* aFormSubmission,
nsIContent* aSubmitElement);
/**
* Notify any submit observers of the submit.
*
* @param aActionURL the URL being submitted to
* @param aCancelSubmit out param where submit observers can specify that the
* submit should be cancelled.
*/
nsresult NotifySubmitObservers(nsIURI* aActionURL, PRBool* aCancelSubmit,
PRBool aEarlyNotify);
/**
* Just like ResolveName(), but takes an arg for whether to flush
*/
already_AddRefed<nsISupports> DoResolveName(const nsAString& aName, PRBool aFlushContent);
/**
* Get the full URL to submit to. Do not submit if the returned URL is null.
*
* @param aActionURL the full, unadulterated URL you'll be submitting to [OUT]
*/
nsresult GetActionURL(nsIURI** aActionURL);
public:
/**
* Flush a possible pending submission. If there was a scripted submission
* triggered by a button or image, the submission was defered. This method
* forces the pending submission to be submitted. (happens when the handler
* returns false or there is an action/target change in the script)
*/
void FlushPendingSubmission();
protected:
/**
* Forget a possible pending submission. Same as above but this time we
* get rid of the pending submission because the handler returned true
* so we will rebuild the submission with the name/value of the triggering
* element
*/
void ForgetPendingSubmission();
//
// Data members
//
/** The list of controls (form.elements as well as stuff not in elements) */
nsRefPtr<nsFormControlList> mControls;
/** The currently selected radio button of each group */
nsInterfaceHashtable<nsStringCaseInsensitiveHashKey,nsIDOMHTMLInputElement> mSelectedRadioButtons;
/** Whether we are currently processing a submit event or not */
PRPackedBool mGeneratingSubmit;
/** Whether we are currently processing a reset event or not */
PRPackedBool mGeneratingReset;
/** Whether we are submitting currently */
PRPackedBool mIsSubmitting;
/** Whether the submission is to be deferred in case a script triggers it */
PRPackedBool mDeferSubmission;
/** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */
PRPackedBool mNotifiedObservers;
/** If we notified the listeners early, what was the result? */
PRPackedBool mNotifiedObserversResult;
/** Keep track of what the popup state was when the submit was initiated */
PopupControlState mSubmitPopupState;
/** Keep track of whether a submission was user-initiated or not */
PRBool mSubmitInitiatedFromUserInput;
/** The pending submission object */
nsCOMPtr<nsIFormSubmission> mPendingSubmission;
/** The request currently being submitted */
nsCOMPtr<nsIRequest> mSubmittingRequest;
/** The web progress object we are currently listening to */
nsWeakPtr mWebProgress;
/** The default submit element -- WEAK */
nsGenericHTMLFormElement* mDefaultSubmitElement;
/** The first submit element in mElements -- WEAK */
nsGenericHTMLFormElement* mFirstSubmitInElements;
/** The first submit element in mNotInElements -- WEAK */
nsGenericHTMLFormElement* mFirstSubmitNotInElements;
protected:
/** Detection of first form to notify observers */
static PRBool gFirstFormSubmitted;
/** Detection of first password input to initialize the password manager */
static PRBool gPasswordManagerInitialized;
};

View File

@ -115,6 +115,7 @@
#include "nsIDOMWindowInternal.h"
#include "mozAutoDocUpdate.h"
#include "nsHTMLFormElement.h"
// XXX align=left, hspace, vspace, border? other nav4 attrs
@ -1341,10 +1342,11 @@ nsHTMLInputElement::MaybeSubmitForm(nsPresContext* aPresContext)
shell->HandleDOMEventWithTarget(submitContent, &event, &status);
} else if (mForm->HasSingleTextControl()) {
// If there's only one text control, just submit the form
nsCOMPtr<nsIContent> form = do_QueryInterface(mForm);
// Hold strong ref across the event
nsRefPtr<nsHTMLFormElement> form(mForm);
nsFormEvent event(PR_TRUE, NS_FORM_SUBMIT);
nsEventStatus status = nsEventStatus_eIgnore;
shell->HandleDOMEventWithTarget(form, &event, &status);
shell->HandleDOMEventWithTarget(mForm, &event, &status);
}
return NS_OK;
@ -2050,8 +2052,9 @@ nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
// handling the event the pres context will return a null
// pres shell. See bug 125624.
if (presShell) {
nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
presShell->HandleDOMEventWithTarget(form, &event, &status);
// Hold a strong ref while dispatching
nsRefPtr<nsHTMLFormElement> form(mForm);
presShell->HandleDOMEventWithTarget(mForm, &event, &status);
}
}
break;

View File

@ -48,6 +48,7 @@
#include "nsRuleData.h"
#include "nsMappedAttributes.h"
#include "nsNetUtil.h"
#include "nsHTMLFormElement.h"
// XXX nav4 has type= start= (same as OL/UL)
extern nsAttrValue::EnumTable kListTypeTable[];
@ -203,7 +204,7 @@ NS_IMPL_INT_ATTR(nsHTMLSharedElement, Size, size)
NS_IMETHODIMP
nsHTMLSharedElement::GetForm(nsIDOMHTMLFormElement** aForm)
{
*aForm = FindForm().get();
NS_IF_ADDREF(*aForm = FindForm());
return NS_OK;
}

View File

@ -9207,8 +9207,7 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
PRInt32 n = GetArrayIndexFromId(cx, id);
if (n >= 0) {
nsCOMPtr<nsIFormControl> control;
form->GetElementAt(n, getter_AddRefs(control));
nsIFormControl* control = form->GetElementAt(n);
if (control) {
nsresult rv = WrapNative(cx, obj, control, PR_TRUE, vp);
@ -9256,8 +9255,7 @@ nsHTMLFormElementSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper,
PRUint32 count = form->GetElementCount();
if ((PRUint32)index < count) {
nsCOMPtr<nsIFormControl> controlNode;
form->GetElementAt(index, getter_AddRefs(controlNode));
nsIFormControl* controlNode = form->GetElementAt(index);
NS_ENSURE_TRUE(controlNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(controlNode);