1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef nsHTMLFormElement_h__
39 : #define nsHTMLFormElement_h__
40 :
41 : #include "nsCOMPtr.h"
42 : #include "nsIForm.h"
43 : #include "nsIFormControl.h"
44 : #include "nsFormSubmission.h"
45 : #include "nsGenericHTMLElement.h"
46 : #include "nsIDOMHTMLFormElement.h"
47 : #include "nsIWebProgressListener.h"
48 : #include "nsIRadioGroupContainer.h"
49 : #include "nsIURI.h"
50 : #include "nsIWeakReferenceUtils.h"
51 : #include "nsPIDOMWindow.h"
52 : #include "nsThreadUtils.h"
53 : #include "nsInterfaceHashtable.h"
54 : #include "nsDataHashtable.h"
55 :
56 : class nsFormControlList;
57 : class nsIMutableArray;
58 :
59 : class nsHTMLFormElement : public nsGenericHTMLElement,
60 : public nsIDOMHTMLFormElement,
61 : public nsIWebProgressListener,
62 : public nsIForm,
63 : public nsIRadioGroupContainer
64 : {
65 : public:
66 : nsHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo);
67 : virtual ~nsHTMLFormElement();
68 :
69 : nsresult Init();
70 :
71 : // nsISupports
72 : NS_DECL_ISUPPORTS_INHERITED
73 :
74 : // nsIDOMNode
75 0 : NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
76 :
77 : // nsIDOMElement
78 0 : NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
79 :
80 : // nsIDOMHTMLElement
81 0 : NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
82 :
83 : // nsIDOMHTMLFormElement
84 : NS_DECL_NSIDOMHTMLFORMELEMENT
85 :
86 : // nsIWebProgressListener
87 : NS_DECL_NSIWEBPROGRESSLISTENER
88 :
89 : // nsIForm
90 : NS_IMETHOD_(nsIFormControl*) GetElementAt(PRInt32 aIndex) const;
91 : NS_IMETHOD_(PRUint32) GetElementCount() const;
92 : NS_IMETHOD_(already_AddRefed<nsISupports>) ResolveName(const nsAString& aName);
93 : NS_IMETHOD_(PRInt32) IndexOfControl(nsIFormControl* aControl);
94 : NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const;
95 :
96 : // nsIRadioGroupContainer
97 : NS_IMETHOD SetCurrentRadioButton(const nsAString& aName,
98 : nsIDOMHTMLInputElement* aRadio);
99 : NS_IMETHOD GetCurrentRadioButton(const nsAString& aName,
100 : nsIDOMHTMLInputElement** aRadio);
101 : NS_IMETHOD GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
102 : PRInt32 *aPositionIndex,
103 : PRInt32 *aItemsInGroup);
104 : NS_IMETHOD GetNextRadioButton(const nsAString& aName,
105 : const bool aPrevious,
106 : nsIDOMHTMLInputElement* aFocusedRadio,
107 : nsIDOMHTMLInputElement** aRadioOut);
108 : NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
109 : bool aFlushContent);
110 : NS_IMETHOD AddToRadioGroup(const nsAString& aName,
111 : nsIFormControl* aRadio);
112 : NS_IMETHOD RemoveFromRadioGroup(const nsAString& aName,
113 : nsIFormControl* aRadio);
114 : virtual PRUint32 GetRequiredRadioCount(const nsAString& aName) const;
115 : virtual void RadioRequiredChanged(const nsAString& aName,
116 : nsIFormControl* aRadio);
117 : virtual bool GetValueMissingState(const nsAString& aName) const;
118 : virtual void SetValueMissingState(const nsAString& aName, bool aValue);
119 :
120 : virtual nsEventStates IntrinsicState() const;
121 :
122 : // nsIContent
123 : virtual bool ParseAttribute(PRInt32 aNamespaceID,
124 : nsIAtom* aAttribute,
125 : const nsAString& aValue,
126 : nsAttrValue& aResult);
127 : virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
128 : virtual nsresult WillHandleEvent(nsEventChainPostVisitor& aVisitor);
129 : virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
130 :
131 : virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
132 : nsIContent* aBindingParent,
133 : bool aCompileEventHandlers);
134 : virtual void UnbindFromTree(bool aDeep = true,
135 : bool aNullParent = true);
136 : nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
137 : const nsAString& aValue, bool aNotify)
138 : {
139 : return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
140 : }
141 : virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
142 : nsIAtom* aPrefix, const nsAString& aValue,
143 : bool aNotify);
144 : virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
145 : const nsAttrValue* aValue, bool aNotify);
146 :
147 : /**
148 : * Forget all information about the current submission (and the fact that we
149 : * are currently submitting at all).
150 : */
151 : void ForgetCurrentSubmission();
152 :
153 : virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
154 :
155 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLFormElement,
156 : nsGenericHTMLElement)
157 :
158 : /**
159 : * Remove an element from this form's list of elements
160 : *
161 : * @param aElement the element to remove
162 : * @param aUpdateValidity If true, updates the form validity.
163 : * @return NS_OK if the element was successfully removed.
164 : */
165 : nsresult RemoveElement(nsGenericHTMLFormElement* aElement,
166 : bool aUpdateValidity);
167 :
168 : /**
169 : * Remove an element from the lookup table maintained by the form.
170 : * We can't fold this method into RemoveElement() because when
171 : * RemoveElement() is called it doesn't know if the element is
172 : * removed because the id attribute has changed, or bacause the
173 : * name attribute has changed.
174 : *
175 : * @param aElement the element to remove
176 : * @param aName the name or id of the element to remove
177 : * @return NS_OK if the element was successfully removed.
178 : */
179 : nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
180 : const nsAString& aName);
181 : /**
182 : * Add an element to end of this form's list of elements
183 : *
184 : * @param aElement the element to add
185 : * @param aUpdateValidity If true, the form validity will be updated.
186 : * @param aNotify If true, send nsIDocumentObserver notifications as needed.
187 : * @return NS_OK if the element was successfully added
188 : */
189 : nsresult AddElement(nsGenericHTMLFormElement* aElement, bool aUpdateValidity,
190 : bool aNotify);
191 :
192 : /**
193 : * Add an element to the lookup table maintained by the form.
194 : *
195 : * We can't fold this method into AddElement() because when
196 : * AddElement() is called, the form control has no
197 : * attributes. The name or id attributes of the form control
198 : * are used as a key into the table.
199 : */
200 : nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
201 : const nsAString& aName);
202 : /**
203 : * Return whether there is one and only one input text control.
204 : *
205 : * @return Whether there is exactly one input text control.
206 : */
207 : bool HasSingleTextControl() const;
208 :
209 : /**
210 : * Check whether a given nsIFormControl is the default submit
211 : * element. This is different from just comparing to
212 : * GetDefaultSubmitElement() in certain situations inside an update
213 : * when GetDefaultSubmitElement() might not be up to date. aControl
214 : * is expected to not be null.
215 : */
216 : bool IsDefaultSubmitElement(const nsIFormControl* aControl) const;
217 :
218 : /**
219 : * Flag the form to know that a button or image triggered scripted form
220 : * submission. In that case the form will defer the submission until the
221 : * script handler returns and the return value is known.
222 : */
223 : void OnSubmitClickBegin(nsIContent* aOriginatingElement);
224 : void OnSubmitClickEnd();
225 :
226 : /**
227 : * This method will update the form validity so the submit controls states
228 : * will be updated (for -moz-submit-invalid pseudo-class).
229 : * This method has to be called by form elements whenever their validity state
230 : * or status regarding constraint validation changes.
231 : *
232 : * @note This method isn't used for CheckValidity().
233 : * @note If an element becomes barred from constraint validation, it has to be
234 : * considered as valid.
235 : *
236 : * @param aElementValidityState the new validity state of the element
237 : */
238 : void UpdateValidity(bool aElementValidityState);
239 :
240 : /**
241 : * Returns the form validity based on the last UpdateValidity() call.
242 : *
243 : * @return Whether the form was valid the last time UpdateValidity() was called.
244 : *
245 : * @note This method may not return the *current* validity state!
246 : */
247 0 : bool GetValidity() const { return !mInvalidElementsCount; }
248 :
249 : /**
250 : * This method check the form validity and make invalid form elements send
251 : * invalid event if needed.
252 : *
253 : * @return Whether the form is valid.
254 : *
255 : * @note Do not call this method if novalidate/formnovalidate is used.
256 : * @note This method might disappear with bug 592124, hopefuly.
257 : */
258 : bool CheckValidFormSubmission();
259 :
260 : virtual nsXPCClassInfo* GetClassInfo();
261 :
262 : /**
263 : * Walk over the form elements and call SubmitNamesValues() on them to get
264 : * their data pumped into the FormSubmitter.
265 : *
266 : * @param aFormSubmission the form submission object
267 : */
268 : nsresult WalkFormElements(nsFormSubmission* aFormSubmission);
269 :
270 : /**
271 : * Whether the submission of this form has been ever prevented because of
272 : * being invalid.
273 : *
274 : * @return Whether the submission of this form has been prevented because of
275 : * being invalid.
276 : */
277 0 : bool HasEverTriedInvalidSubmit() const { return mEverTriedInvalidSubmit; }
278 :
279 : protected:
280 : class RemoveElementRunnable;
281 : friend class RemoveElementRunnable;
282 :
283 0 : class RemoveElementRunnable : public nsRunnable {
284 : public:
285 0 : RemoveElementRunnable(nsHTMLFormElement* aForm)
286 0 : : mForm(aForm)
287 0 : {}
288 :
289 0 : NS_IMETHOD Run() {
290 0 : mForm->HandleDefaultSubmitRemoval();
291 0 : return NS_OK;
292 : }
293 :
294 : private:
295 : nsRefPtr<nsHTMLFormElement> mForm;
296 : };
297 :
298 : nsresult DoSubmitOrReset(nsEvent* aEvent,
299 : PRInt32 aMessage);
300 : nsresult DoReset();
301 :
302 : // Async callback to handle removal of our default submit
303 : void HandleDefaultSubmitRemoval();
304 :
305 : //
306 : // Submit Helpers
307 : //
308 : //
309 : /**
310 : * Attempt to submit (submission might be deferred)
311 : * (called by DoSubmitOrReset)
312 : *
313 : * @param aPresContext the presentation context
314 : * @param aEvent the DOM event that was passed to us for the submit
315 : */
316 : nsresult DoSubmit(nsEvent* aEvent);
317 :
318 : /**
319 : * Prepare the submission object (called by DoSubmit)
320 : *
321 : * @param aFormSubmission the submission object
322 : * @param aEvent the DOM event that was passed to us for the submit
323 : */
324 : nsresult BuildSubmission(nsFormSubmission** aFormSubmission,
325 : nsEvent* aEvent);
326 : /**
327 : * Perform the submission (called by DoSubmit and FlushPendingSubmission)
328 : *
329 : * @param aFormSubmission the submission object
330 : */
331 : nsresult SubmitSubmission(nsFormSubmission* aFormSubmission);
332 :
333 : /**
334 : * Notify any submit observers of the submit.
335 : *
336 : * @param aActionURL the URL being submitted to
337 : * @param aCancelSubmit out param where submit observers can specify that the
338 : * submit should be cancelled.
339 : */
340 : nsresult NotifySubmitObservers(nsIURI* aActionURL, bool* aCancelSubmit,
341 : bool aEarlyNotify);
342 :
343 : /**
344 : * Just like ResolveName(), but takes an arg for whether to flush
345 : */
346 : already_AddRefed<nsISupports> DoResolveName(const nsAString& aName, bool aFlushContent);
347 :
348 : /**
349 : * Get the full URL to submit to. Do not submit if the returned URL is null.
350 : *
351 : * @param aActionURL the full, unadulterated URL you'll be submitting to [OUT]
352 : * @param aOriginatingElement the originating element of the form submission [IN]
353 : */
354 : nsresult GetActionURL(nsIURI** aActionURL, nsIContent* aOriginatingElement);
355 :
356 : /**
357 : * Check the form validity following this algorithm:
358 : * http://www.whatwg.org/specs/web-apps/current-work/#statically-validate-the-constraints
359 : *
360 : * @param aInvalidElements [out] parameter containing the list of unhandled
361 : * invalid controls.
362 : *
363 : * @return Whether the form is currently valid.
364 : */
365 : bool CheckFormValidity(nsIMutableArray* aInvalidElements) const;
366 :
367 : public:
368 : /**
369 : * Flush a possible pending submission. If there was a scripted submission
370 : * triggered by a button or image, the submission was defered. This method
371 : * forces the pending submission to be submitted. (happens when the handler
372 : * returns false or there is an action/target change in the script)
373 : */
374 : void FlushPendingSubmission();
375 : protected:
376 :
377 : //
378 : // Data members
379 : //
380 : /** The list of controls (form.elements as well as stuff not in elements) */
381 : nsRefPtr<nsFormControlList> mControls;
382 : /** The currently selected radio button of each group */
383 : nsInterfaceHashtable<nsStringCaseInsensitiveHashKey,nsIDOMHTMLInputElement> mSelectedRadioButtons;
384 : /** The number of required radio button of each group */
385 : nsDataHashtable<nsStringCaseInsensitiveHashKey,PRUint32> mRequiredRadioButtonCounts;
386 : /** The value missing state of each group */
387 : nsDataHashtable<nsStringCaseInsensitiveHashKey,bool> mValueMissingRadioGroups;
388 : /** Whether we are currently processing a submit event or not */
389 : bool mGeneratingSubmit;
390 : /** Whether we are currently processing a reset event or not */
391 : bool mGeneratingReset;
392 : /** Whether we are submitting currently */
393 : bool mIsSubmitting;
394 : /** Whether the submission is to be deferred in case a script triggers it */
395 : bool mDeferSubmission;
396 : /** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */
397 : bool mNotifiedObservers;
398 : /** If we notified the listeners early, what was the result? */
399 : bool mNotifiedObserversResult;
400 : /** Keep track of what the popup state was when the submit was initiated */
401 : PopupControlState mSubmitPopupState;
402 : /** Keep track of whether a submission was user-initiated or not */
403 : bool mSubmitInitiatedFromUserInput;
404 :
405 : /** The pending submission object */
406 : nsAutoPtr<nsFormSubmission> mPendingSubmission;
407 : /** The request currently being submitted */
408 : nsCOMPtr<nsIRequest> mSubmittingRequest;
409 : /** The web progress object we are currently listening to */
410 : nsWeakPtr mWebProgress;
411 :
412 : /** The default submit element -- WEAK */
413 : nsGenericHTMLFormElement* mDefaultSubmitElement;
414 :
415 : /** The first submit element in mElements -- WEAK */
416 : nsGenericHTMLFormElement* mFirstSubmitInElements;
417 :
418 : /** The first submit element in mNotInElements -- WEAK */
419 : nsGenericHTMLFormElement* mFirstSubmitNotInElements;
420 :
421 : /**
422 : * Number of invalid and candidate for constraint validation elements in the
423 : * form the last time UpdateValidity has been called.
424 : * @note Should only be used by UpdateValidity() and GetValidity()!
425 : */
426 : PRInt32 mInvalidElementsCount;
427 :
428 : /**
429 : * Whether the submission of this form has been ever prevented because of
430 : * being invalid.
431 : */
432 : bool mEverTriedInvalidSubmit;
433 :
434 : protected:
435 : /** Detection of first form to notify observers */
436 : static bool gFirstFormSubmitted;
437 : /** Detection of first password input to initialize the password manager */
438 : static bool gPasswordManagerInitialized;
439 : };
440 :
441 : #endif // nsHTMLFormElement_h__
|