2001-09-25 01:32:19 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
2004-04-17 21:52:36 +00:00
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
1998-09-02 00:56:01 +00:00
|
|
|
*
|
2004-04-17 21:52:36 +00:00
|
|
|
* 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/
|
1998-09-02 00:56:01 +00:00
|
|
|
*
|
2001-09-25 01:32:19 +00:00
|
|
|
* 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.
|
1998-09-02 00:56:01 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
2004-04-17 21:52:36 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
2001-09-25 01:32:19 +00:00
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
1999-11-06 03:40:37 +00:00
|
|
|
*
|
2001-09-25 01:32:19 +00:00
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
2004-04-17 21:52:36 +00:00
|
|
|
* 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"),
|
2001-09-25 01:32:19 +00:00
|
|
|
* 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
|
2004-04-17 21:52:36 +00:00
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
2001-09-25 01:32:19 +00:00
|
|
|
* 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
|
2004-04-17 21:52:36 +00:00
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
2001-09-25 01:32:19 +00:00
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2009-10-30 01:49:11 +00:00
|
|
|
#include "nsHTMLFormElement.h"
|
2001-03-22 08:51:52 +00:00
|
|
|
#include "nsIHTMLDocument.h"
|
2007-05-14 09:11:38 +00:00
|
|
|
#include "nsIDOMEventTarget.h"
|
2004-09-04 19:28:46 +00:00
|
|
|
#include "nsEventStateManager.h"
|
2006-12-26 17:47:52 +00:00
|
|
|
#include "nsGkAtoms.h"
|
1998-09-02 00:56:01 +00:00
|
|
|
#include "nsStyleConsts.h"
|
2004-07-31 23:15:21 +00:00
|
|
|
#include "nsPresContext.h"
|
1998-09-23 17:16:51 +00:00
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIFrame.h"
|
2001-04-17 10:02:11 +00:00
|
|
|
#include "nsIFormControlFrame.h"
|
1999-12-22 01:48:47 +00:00
|
|
|
#include "nsDOMError.h"
|
2001-02-19 12:55:42 +00:00
|
|
|
#include "nsContentUtils.h"
|
2003-09-26 19:26:17 +00:00
|
|
|
#include "nsInterfaceHashtable.h"
|
2000-06-01 22:55:19 +00:00
|
|
|
#include "nsContentList.h"
|
2001-07-16 02:40:48 +00:00
|
|
|
#include "nsGUIEvent.h"
|
2005-11-22 00:24:48 +00:00
|
|
|
#include "nsCOMArray.h"
|
2006-02-07 22:10:29 +00:00
|
|
|
#include "nsAutoPtr.h"
|
2006-09-18 04:53:54 +00:00
|
|
|
#include "nsTArray.h"
|
2002-02-16 01:19:24 +00:00
|
|
|
|
|
|
|
// form submission
|
2001-11-02 07:40:01 +00:00
|
|
|
#include "nsIFormSubmitObserver.h"
|
2002-02-16 01:19:24 +00:00
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsICategoryManager.h"
|
2002-07-18 05:09:10 +00:00
|
|
|
#include "nsCategoryManagerUtils.h"
|
2002-02-16 01:19:24 +00:00
|
|
|
#include "nsISimpleEnumerator.h"
|
|
|
|
#include "nsRange.h"
|
|
|
|
#include "nsIScriptSecurityManager.h"
|
|
|
|
#include "nsNetUtil.h"
|
2002-03-13 06:08:56 +00:00
|
|
|
#include "nsIWebProgress.h"
|
|
|
|
#include "nsIDocShell.h"
|
2010-02-25 05:58:18 +00:00
|
|
|
#include "nsFormData.h"
|
2010-08-20 17:47:30 +00:00
|
|
|
#include "nsFormSubmissionConstants.h"
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
// radio buttons
|
|
|
|
#include "nsIDOMHTMLInputElement.h"
|
2010-07-14 06:39:48 +00:00
|
|
|
#include "nsHTMLInputElement.h"
|
2002-03-07 20:53:40 +00:00
|
|
|
#include "nsIRadioVisitor.h"
|
2000-04-19 07:49:07 +00:00
|
|
|
|
2004-10-31 19:58:10 +00:00
|
|
|
#include "nsLayoutUtils.h"
|
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
#include "nsEventDispatcher.h"
|
2005-10-21 22:32:27 +00:00
|
|
|
|
2008-04-11 17:29:06 +00:00
|
|
|
#include "mozAutoDocUpdate.h"
|
2008-10-22 14:31:14 +00:00
|
|
|
#include "nsIHTMLCollection.h"
|
2008-04-11 17:29:06 +00:00
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16;
|
1998-09-02 00:56:01 +00:00
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
// nsHTMLFormElement
|
1998-09-02 00:56:01 +00:00
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
PRBool nsHTMLFormElement::gFirstFormSubmitted = PR_FALSE;
|
2002-06-04 00:44:04 +00:00
|
|
|
PRBool nsHTMLFormElement::gPasswordManagerInitialized = PR_FALSE;
|
2002-02-16 01:19:24 +00:00
|
|
|
|
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
// nsFormControlList
|
2010-03-17 15:09:01 +00:00
|
|
|
class nsFormControlList : public nsIHTMLCollection
|
2000-12-23 10:56:31 +00:00
|
|
|
{
|
1998-09-23 17:16:51 +00:00
|
|
|
public:
|
2006-02-07 22:10:29 +00:00
|
|
|
nsFormControlList(nsHTMLFormElement* aForm);
|
1998-09-23 17:16:51 +00:00
|
|
|
virtual ~nsFormControlList();
|
|
|
|
|
2003-09-26 19:26:17 +00:00
|
|
|
nsresult Init();
|
|
|
|
|
2006-02-07 22:10:29 +00:00
|
|
|
void DropFormReference();
|
1998-09-23 17:16:51 +00:00
|
|
|
|
2007-03-08 11:17:16 +00:00
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
1998-09-23 17:16:51 +00:00
|
|
|
|
|
|
|
// nsIDOMHTMLCollection interface
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
NS_DECL_NSIDOMHTMLCOLLECTION
|
|
|
|
|
2010-05-09 19:33:00 +00:00
|
|
|
virtual nsIContent* GetNodeAt(PRUint32 aIndex, nsresult* aResult)
|
2008-10-22 14:31:14 +00:00
|
|
|
{
|
|
|
|
FlushPendingNotifications();
|
|
|
|
|
|
|
|
*aResult = NS_OK;
|
|
|
|
|
2010-05-09 19:33:00 +00:00
|
|
|
return mElements.SafeElementAt(aIndex, nsnull);
|
2008-10-22 14:31:14 +00:00
|
|
|
}
|
2010-05-09 19:41:19 +00:00
|
|
|
virtual nsISupports* GetNamedItem(const nsAString& aName,
|
|
|
|
nsWrapperCache **aCache,
|
|
|
|
nsresult* aResult)
|
2008-10-31 21:40:35 +00:00
|
|
|
{
|
|
|
|
*aResult = NS_OK;
|
|
|
|
|
2010-05-09 19:41:19 +00:00
|
|
|
nsISupports *item = NamedItemInternal(aName, PR_TRUE);
|
|
|
|
*aCache = nsnull;
|
|
|
|
return item;
|
2008-10-31 21:40:35 +00:00
|
|
|
}
|
2008-10-22 14:31:14 +00:00
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
|
2002-03-23 23:04:39 +00:00
|
|
|
const nsAString& aName);
|
2009-10-30 01:49:11 +00:00
|
|
|
nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
|
2002-03-23 23:04:39 +00:00
|
|
|
const nsAString& aName);
|
2001-05-30 11:26:21 +00:00
|
|
|
nsresult IndexOfControl(nsIFormControl* aControl,
|
|
|
|
PRInt32* aIndex);
|
2000-04-19 07:49:07 +00:00
|
|
|
|
2008-10-31 21:40:35 +00:00
|
|
|
nsISupports* NamedItemInternal(const nsAString& aName, PRBool aFlushContent);
|
2006-09-18 04:53:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a sorted list of form control elements. This list is sorted
|
|
|
|
* in document order and contains the controls in the mElements and
|
|
|
|
* mNotInElements list. This function does not add references to the
|
|
|
|
* elements.
|
|
|
|
*
|
|
|
|
* @param aControls The list of sorted controls[out].
|
|
|
|
* @return NS_OK or NS_ERROR_OUT_OF_MEMORY.
|
|
|
|
*/
|
2009-10-30 01:49:11 +00:00
|
|
|
nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
|
2006-02-08 05:56:13 +00:00
|
|
|
|
2006-02-07 22:10:29 +00:00
|
|
|
nsHTMLFormElement* mForm; // WEAK - the form owns me
|
2000-04-19 07:49:07 +00:00
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsTArray<nsGenericHTMLFormElement*> mElements; // Holds WEAK references - bug 36639
|
2001-03-22 08:51:52 +00:00
|
|
|
|
2002-08-17 05:42:55 +00:00
|
|
|
// This array holds on to all form controls that are not contained
|
2002-02-20 05:51:28 +00:00
|
|
|
// 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.
|
2001-03-22 08:51:52 +00:00
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsTArray<nsGenericHTMLFormElement*> mNotInElements; // Holds WEAK references
|
2001-03-22 08:51:52 +00:00
|
|
|
|
2008-10-22 14:31:14 +00:00
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFormControlList, nsIHTMLCollection)
|
2007-03-08 11:17:16 +00:00
|
|
|
|
2000-04-19 07:49:07 +00:00
|
|
|
protected:
|
2006-02-07 22:10:29 +00:00
|
|
|
// Drop all our references to the form elements
|
|
|
|
void Clear();
|
|
|
|
|
|
|
|
// Flush out the content model so it's up to date.
|
|
|
|
void FlushPendingNotifications();
|
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
// A map from an ID or NAME attribute to the form control(s), this
|
|
|
|
// hash holds strong references either to the named form control, or
|
|
|
|
// to a list of named form controls, in the case where this hash
|
|
|
|
// holds on to a list of named form controls the list has weak
|
|
|
|
// references to the form control.
|
|
|
|
|
2003-09-26 19:26:17 +00:00
|
|
|
nsInterfaceHashtable<nsStringHashKey,nsISupports> mNameLookupTable;
|
1998-09-23 17:16:51 +00:00
|
|
|
};
|
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
static PRBool
|
2002-02-20 05:51:28 +00:00
|
|
|
ShouldBeInElements(nsIFormControl* aFormControl)
|
2001-03-22 08:51:52 +00:00
|
|
|
{
|
|
|
|
// For backwards compatibility (with 4.x and IE) we must not add
|
|
|
|
// <input type=image> elements to the list of form controls in a
|
|
|
|
// form.
|
|
|
|
|
2002-12-18 23:38:09 +00:00
|
|
|
switch (aFormControl->GetType()) {
|
2001-03-22 08:51:52 +00:00
|
|
|
case NS_FORM_BUTTON_BUTTON :
|
|
|
|
case NS_FORM_BUTTON_RESET :
|
|
|
|
case NS_FORM_BUTTON_SUBMIT :
|
|
|
|
case NS_FORM_INPUT_BUTTON :
|
|
|
|
case NS_FORM_INPUT_CHECKBOX :
|
2010-08-18 18:31:54 +00:00
|
|
|
case NS_FORM_INPUT_EMAIL :
|
2001-03-22 08:51:52 +00:00
|
|
|
case NS_FORM_INPUT_FILE :
|
|
|
|
case NS_FORM_INPUT_HIDDEN :
|
|
|
|
case NS_FORM_INPUT_RESET :
|
|
|
|
case NS_FORM_INPUT_PASSWORD :
|
|
|
|
case NS_FORM_INPUT_RADIO :
|
2010-05-17 10:20:22 +00:00
|
|
|
case NS_FORM_INPUT_SEARCH :
|
2001-03-22 08:51:52 +00:00
|
|
|
case NS_FORM_INPUT_SUBMIT :
|
|
|
|
case NS_FORM_INPUT_TEXT :
|
2010-05-12 07:17:07 +00:00
|
|
|
case NS_FORM_INPUT_TEL :
|
2010-08-18 18:33:37 +00:00
|
|
|
case NS_FORM_INPUT_URL :
|
2001-03-22 08:51:52 +00:00
|
|
|
case NS_FORM_SELECT :
|
|
|
|
case NS_FORM_TEXTAREA :
|
|
|
|
case NS_FORM_FIELDSET :
|
2002-08-06 09:53:58 +00:00
|
|
|
case NS_FORM_OBJECT :
|
2010-04-26 07:42:00 +00:00
|
|
|
case NS_FORM_OUTPUT :
|
2001-03-22 08:51:52 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// These form control types are not supposed to end up in the
|
|
|
|
// form.elements array
|
|
|
|
//
|
|
|
|
// NS_FORM_INPUT_IMAGE
|
|
|
|
// NS_FORM_LABEL
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
// nsHTMLFormElement implementation
|
|
|
|
|
|
|
|
// construction, destruction
|
2005-01-12 19:45:38 +00:00
|
|
|
nsGenericHTMLElement*
|
2010-07-23 09:49:57 +00:00
|
|
|
NS_NewHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo,
|
|
|
|
PRUint32 aFromParser)
|
1998-09-02 00:56:01 +00:00
|
|
|
{
|
2008-02-02 23:41:24 +00:00
|
|
|
nsHTMLFormElement* it = new nsHTMLFormElement(aNodeInfo);
|
2000-12-23 10:56:31 +00:00
|
|
|
if (!it) {
|
2004-06-06 02:38:32 +00:00
|
|
|
return nsnull;
|
1998-09-02 00:56:01 +00:00
|
|
|
}
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2004-05-18 20:58:12 +00:00
|
|
|
nsresult rv = it->Init();
|
2000-12-23 10:56:31 +00:00
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
delete it;
|
2004-06-06 02:38:32 +00:00
|
|
|
return nsnull;
|
2000-12-23 10:56:31 +00:00
|
|
|
}
|
|
|
|
|
2004-06-06 02:38:32 +00:00
|
|
|
return it;
|
1998-09-02 00:56:01 +00:00
|
|
|
}
|
|
|
|
|
2010-07-23 09:49:57 +00:00
|
|
|
nsHTMLFormElement::nsHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
2004-05-18 20:58:12 +00:00
|
|
|
: nsGenericHTMLElement(aNodeInfo),
|
|
|
|
mGeneratingSubmit(PR_FALSE),
|
|
|
|
mGeneratingReset(PR_FALSE),
|
|
|
|
mIsSubmitting(PR_FALSE),
|
|
|
|
mDeferSubmission(PR_FALSE),
|
2006-06-23 02:44:39 +00:00
|
|
|
mNotifiedObservers(PR_FALSE),
|
|
|
|
mNotifiedObserversResult(PR_FALSE),
|
2004-09-04 19:28:46 +00:00
|
|
|
mSubmitPopupState(openAbused),
|
|
|
|
mSubmitInitiatedFromUserInput(PR_FALSE),
|
2004-05-18 20:58:12 +00:00
|
|
|
mPendingSubmission(nsnull),
|
2006-08-16 03:20:19 +00:00
|
|
|
mSubmittingRequest(nsnull),
|
2007-08-07 02:07:24 +00:00
|
|
|
mDefaultSubmitElement(nsnull),
|
|
|
|
mFirstSubmitInElements(nsnull),
|
|
|
|
mFirstSubmitNotInElements(nsnull)
|
1998-09-02 00:56:01 +00:00
|
|
|
{
|
2004-05-18 20:58:12 +00:00
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
|
2004-05-18 20:58:12 +00:00
|
|
|
nsHTMLFormElement::~nsHTMLFormElement()
|
|
|
|
{
|
|
|
|
if (mControls) {
|
2006-02-07 22:10:29 +00:00
|
|
|
mControls->DropFormReference();
|
2004-05-18 20:58:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::Init()
|
|
|
|
{
|
1999-12-22 01:48:47 +00:00
|
|
|
mControls = new nsFormControlList(this);
|
2002-03-07 20:53:40 +00:00
|
|
|
if (!mControls) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2003-09-26 19:26:17 +00:00
|
|
|
|
2004-05-18 20:58:12 +00:00
|
|
|
nsresult rv = mControls->Init();
|
2003-09-26 19:26:17 +00:00
|
|
|
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
{
|
|
|
|
mControls = nsnull;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ENSURE_TRUE(mSelectedRadioButtons.Init(4),
|
|
|
|
NS_ERROR_OUT_OF_MEMORY);
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
return NS_OK;
|
1998-09-02 00:56:01 +00:00
|
|
|
}
|
|
|
|
|
2000-12-23 10:56:31 +00:00
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
// nsISupports
|
1998-09-02 00:56:01 +00:00
|
|
|
|
2008-10-10 15:04:34 +00:00
|
|
|
static PLDHashOperator
|
2007-03-08 11:17:16 +00:00
|
|
|
ElementTraverser(const nsAString& key, nsIDOMHTMLInputElement* element,
|
|
|
|
void* userArg)
|
|
|
|
{
|
|
|
|
nsCycleCollectionTraversalCallback *cb =
|
2007-07-08 07:08:04 +00:00
|
|
|
static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
2007-03-08 11:17:16 +00:00
|
|
|
|
|
|
|
cb->NoteXPCOMChild(element);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLFormElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLFormElement,
|
|
|
|
nsGenericHTMLElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mControls,
|
|
|
|
nsIDOMHTMLCollection)
|
|
|
|
tmp->mSelectedRadioButtons.EnumerateRead(ElementTraverser, &cb);
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2000-12-23 10:56:31 +00:00
|
|
|
NS_IMPL_ADDREF_INHERITED(nsHTMLFormElement, nsGenericElement)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsHTMLFormElement, nsGenericElement)
|
|
|
|
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
|
2010-07-23 09:49:57 +00:00
|
|
|
DOMCI_NODE_DATA(HTMLFormElement, nsHTMLFormElement)
|
2010-01-12 13:08:43 +00:00
|
|
|
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
// QueryInterface implementation for nsHTMLFormElement
|
2008-11-03 10:31:47 +00:00
|
|
|
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLFormElement)
|
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE5(nsHTMLFormElement,
|
|
|
|
nsIDOMHTMLFormElement,
|
|
|
|
nsIDOMNSHTMLFormElement,
|
|
|
|
nsIForm,
|
|
|
|
nsIWebProgressListener,
|
|
|
|
nsIRadioGroupContainer)
|
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLFormElement,
|
|
|
|
nsGenericHTMLElement)
|
2007-08-20 22:55:06 +00:00
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLFormElement)
|
2000-12-23 10:56:31 +00:00
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
|
|
|
|
// nsIDOMHTMLFormElement
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2006-09-05 10:22:54 +00:00
|
|
|
NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsHTMLFormElement)
|
1998-09-02 00:56:01 +00:00
|
|
|
|
1998-09-02 23:53:16 +00:00
|
|
|
NS_IMETHODIMP
|
1998-09-23 17:16:51 +00:00
|
|
|
nsHTMLFormElement::GetElements(nsIDOMHTMLCollection** aElements)
|
1998-09-02 23:53:16 +00:00
|
|
|
{
|
1998-09-23 17:16:51 +00:00
|
|
|
*aElements = mControls;
|
2006-02-07 22:10:29 +00:00
|
|
|
NS_ADDREF(*aElements);
|
1998-09-02 23:53:16 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-01-09 23:54:21 +00:00
|
|
|
nsresult
|
2002-08-20 02:35:39 +00:00
|
|
|
nsHTMLFormElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
2004-01-15 17:07:27 +00:00
|
|
|
nsIAtom* aPrefix, const nsAString& aValue,
|
|
|
|
PRBool aNotify)
|
1998-09-02 23:53:16 +00:00
|
|
|
{
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aName == nsGkAtoms::action || aName == nsGkAtoms::target) &&
|
2004-01-15 17:07:27 +00:00
|
|
|
aNameSpaceID == kNameSpaceID_None) {
|
2002-11-30 00:01:21 +00:00
|
|
|
if (mPendingSubmission) {
|
|
|
|
// aha, there is a pending submission that means we're in
|
|
|
|
// the script and we need to flush it. let's tell it
|
|
|
|
// that the event was ignored to force the flush.
|
|
|
|
// the second argument is not playing a role at all.
|
|
|
|
FlushPendingSubmission();
|
|
|
|
}
|
2006-07-18 00:18:32 +00:00
|
|
|
// Don't forget we've notified the password manager already if the
|
|
|
|
// page sets the action/target in the during submit. (bug 343182)
|
|
|
|
PRBool notifiedObservers = mNotifiedObservers;
|
2002-08-20 02:35:39 +00:00
|
|
|
ForgetCurrentSubmission();
|
2006-07-18 00:18:32 +00:00
|
|
|
mNotifiedObservers = notifiedObservers;
|
2002-08-20 02:35:39 +00:00
|
|
|
}
|
2004-02-10 19:36:43 +00:00
|
|
|
return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
|
|
|
|
aNotify);
|
1998-10-20 17:07:23 +00:00
|
|
|
}
|
|
|
|
|
1998-11-03 01:08:02 +00:00
|
|
|
NS_IMPL_STRING_ATTR(nsHTMLFormElement, AcceptCharset, acceptcharset)
|
2010-08-19 21:55:00 +00:00
|
|
|
NS_IMPL_STRING_ATTR(nsHTMLFormElement, Action, action)
|
2010-08-10 11:52:46 +00:00
|
|
|
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Enctype, enctype,
|
|
|
|
kFormDefaultEnctype->tag)
|
|
|
|
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Method, method,
|
|
|
|
kFormDefaultMethod->tag)
|
2002-08-20 02:35:39 +00:00
|
|
|
NS_IMPL_STRING_ATTR(nsHTMLFormElement, Name, name)
|
2010-05-31 23:43:11 +00:00
|
|
|
NS_IMPL_STRING_ATTR(nsHTMLFormElement, Target, target)
|
2001-11-02 07:40:01 +00:00
|
|
|
|
2010-08-19 21:55:35 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::GetMozActionUri(nsAString& aValue)
|
|
|
|
{
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::action, aValue);
|
|
|
|
if (aValue.IsEmpty()) {
|
|
|
|
// Avoid resolving action="" to the base uri, bug 297761.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return GetURIAttr(nsGkAtoms::action, nsnull, aValue);
|
|
|
|
}
|
|
|
|
|
1998-09-02 23:53:16 +00:00
|
|
|
NS_IMETHODIMP
|
1998-09-23 17:16:51 +00:00
|
|
|
nsHTMLFormElement::Submit()
|
1998-09-02 23:53:16 +00:00
|
|
|
{
|
2002-05-15 01:24:59 +00:00
|
|
|
// Send the submit event
|
2001-04-16 06:36:45 +00:00
|
|
|
nsresult rv = NS_OK;
|
2010-03-25 13:17:11 +00:00
|
|
|
nsRefPtr<nsPresContext> presContext = GetPresContext();
|
2005-11-08 22:45:49 +00:00
|
|
|
if (mPendingSubmission) {
|
|
|
|
// aha, we have a pending submission that was not flushed
|
|
|
|
// (this happens when form.submit() is called twice)
|
|
|
|
// we have to delete it and build a new one since values
|
|
|
|
// might have changed inbetween (we emulate IE here, that's all)
|
|
|
|
mPendingSubmission = nsnull;
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
2005-11-08 22:45:49 +00:00
|
|
|
|
|
|
|
rv = DoSubmitOrReset(nsnull, NS_FORM_SUBMIT);
|
2001-04-16 06:36:45 +00:00
|
|
|
return rv;
|
1998-09-02 23:53:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1998-09-23 17:16:51 +00:00
|
|
|
nsHTMLFormElement::Reset()
|
1998-09-02 23:53:16 +00:00
|
|
|
{
|
2006-03-07 17:08:51 +00:00
|
|
|
nsFormEvent event(PR_TRUE, NS_FORM_RESET);
|
2007-07-08 07:08:04 +00:00
|
|
|
nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), nsnull,
|
2006-03-07 17:08:51 +00:00
|
|
|
&event);
|
|
|
|
return NS_OK;
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2004-03-04 02:06:28 +00:00
|
|
|
PRBool
|
2005-11-29 16:37:15 +00:00
|
|
|
nsHTMLFormElement::ParseAttribute(PRInt32 aNamespaceID,
|
|
|
|
nsIAtom* aAttribute,
|
2004-03-04 02:06:28 +00:00
|
|
|
const nsAString& aValue,
|
|
|
|
nsAttrValue& aResult)
|
1998-09-02 00:56:01 +00:00
|
|
|
{
|
2005-11-29 16:37:15 +00:00
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::method) {
|
2010-04-15 11:03:00 +00:00
|
|
|
return aResult.ParseEnumValue(aValue, kFormMethodTable, PR_FALSE);
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::enctype) {
|
2010-04-15 11:03:00 +00:00
|
|
|
return aResult.ParseEnumValue(aValue, kFormEnctypeTable, PR_FALSE);
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
2004-03-04 02:06:28 +00:00
|
|
|
|
2005-11-29 16:37:15 +00:00
|
|
|
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
|
|
|
aResult);
|
1998-09-02 00:56:01 +00:00
|
|
|
}
|
|
|
|
|
2005-04-05 23:54:35 +00:00
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|
|
|
nsIContent* aBindingParent,
|
|
|
|
PRBool aCompileEventHandlers)
|
2002-07-16 22:38:51 +00:00
|
|
|
{
|
2005-04-05 23:54:35 +00:00
|
|
|
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
|
|
|
aBindingParent,
|
|
|
|
aCompileEventHandlers);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(aDocument));
|
|
|
|
if (htmlDoc) {
|
|
|
|
htmlDoc->AddedForm();
|
2002-07-16 22:38:51 +00:00
|
|
|
}
|
2005-04-05 23:54:35 +00:00
|
|
|
|
|
|
|
return rv;
|
2002-07-16 22:38:51 +00:00
|
|
|
}
|
|
|
|
|
2007-11-07 17:01:23 +00:00
|
|
|
static void
|
2009-10-30 01:49:11 +00:00
|
|
|
MarkOrphans(const nsTArray<nsGenericHTMLFormElement*> aArray)
|
2007-11-07 17:01:23 +00:00
|
|
|
{
|
|
|
|
PRUint32 length = aArray.Length();
|
|
|
|
for (PRUint32 i = 0; i < length; ++i) {
|
2009-10-30 01:49:11 +00:00
|
|
|
aArray[i]->SetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
|
2007-11-07 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-10-30 01:49:11 +00:00
|
|
|
CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsGenericHTMLFormElement*> aArray
|
2007-11-07 17:01:23 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
, nsIDOMHTMLFormElement* aThisForm
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// Walk backwards so that if we remove elements we can just keep iterating
|
|
|
|
PRUint32 length = aArray.Length();
|
|
|
|
for (PRUint32 i = length; i > 0; --i) {
|
2009-10-30 01:49:11 +00:00
|
|
|
nsGenericHTMLFormElement* node = aArray[i-1];
|
2007-11-07 17:01:23 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
// form. If it _is_ set, then we need to check whether the node is a
|
|
|
|
// descendant of aRemovalRoot. If it is, we leave it in the form. See
|
|
|
|
// also the code in nsGenericHTMLFormElement::FindForm.
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRBool removed = PR_FALSE;
|
|
|
|
#endif
|
|
|
|
if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) {
|
|
|
|
node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
|
|
|
|
if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) {
|
2009-10-30 01:49:11 +00:00
|
|
|
node->ClearForm(PR_TRUE, PR_TRUE);
|
2007-11-07 17:01:23 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
removed = PR_TRUE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (!removed) {
|
|
|
|
nsCOMPtr<nsIDOMHTMLFormElement> form;
|
2009-10-30 01:49:11 +00:00
|
|
|
node->GetForm(getter_AddRefs(form));
|
2007-11-07 17:01:23 +00:00
|
|
|
NS_ASSERTION(form == aThisForm, "How did that happen?");
|
|
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-05 23:54:35 +00:00
|
|
|
void
|
|
|
|
nsHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIHTMLDocument> oldDocument = do_QueryInterface(GetCurrentDoc());
|
|
|
|
|
2007-11-07 17:01:23 +00:00
|
|
|
// Mark all of our controls as maybe being orphans
|
|
|
|
MarkOrphans(mControls->mElements);
|
|
|
|
MarkOrphans(mControls->mNotInElements);
|
|
|
|
|
2005-04-05 23:54:35 +00:00
|
|
|
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
|
|
|
|
2007-11-07 17:01:23 +00:00
|
|
|
nsINode* ancestor = this;
|
|
|
|
nsINode* cur;
|
|
|
|
do {
|
|
|
|
cur = ancestor->GetNodeParent();
|
|
|
|
if (!cur) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ancestor = cur;
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
CollectOrphans(ancestor, mControls->mElements
|
|
|
|
#ifdef DEBUG
|
|
|
|
, this
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
CollectOrphans(ancestor, mControls->mNotInElements
|
|
|
|
#ifdef DEBUG
|
|
|
|
, this
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
|
2005-04-05 23:54:35 +00:00
|
|
|
if (oldDocument) {
|
|
|
|
oldDocument->RemovedForm();
|
|
|
|
}
|
|
|
|
ForgetCurrentSubmission();
|
|
|
|
}
|
2002-07-16 22:38:51 +00:00
|
|
|
|
2004-01-09 23:54:21 +00:00
|
|
|
nsresult
|
2006-03-07 17:08:51 +00:00
|
|
|
nsHTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
1998-09-02 00:56:01 +00:00
|
|
|
{
|
2008-10-08 11:35:29 +00:00
|
|
|
aVisitor.mWantsWillHandleEvent = PR_TRUE;
|
2007-07-08 07:08:04 +00:00
|
|
|
if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) {
|
2006-03-07 17:08:51 +00:00
|
|
|
PRUint32 msg = aVisitor.mEvent->message;
|
|
|
|
if (msg == NS_FORM_SUBMIT) {
|
|
|
|
if (mGeneratingSubmit) {
|
|
|
|
aVisitor.mCanHandle = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
mGeneratingSubmit = PR_TRUE;
|
2002-05-13 17:22:30 +00:00
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
// let the form know that it needs to defer the submission,
|
|
|
|
// that means that if there are scripted submissions, the
|
|
|
|
// latest one will be deferred until after the exit point of the handler.
|
|
|
|
mDeferSubmission = PR_TRUE;
|
2001-04-24 05:18:10 +00:00
|
|
|
}
|
2006-03-07 17:08:51 +00:00
|
|
|
else if (msg == NS_FORM_RESET) {
|
|
|
|
if (mGeneratingReset) {
|
|
|
|
aVisitor.mCanHandle = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
mGeneratingReset = PR_TRUE;
|
2001-04-24 05:18:10 +00:00
|
|
|
}
|
2002-12-03 23:06:34 +00:00
|
|
|
}
|
2006-03-07 17:08:51 +00:00
|
|
|
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
|
|
|
}
|
2000-08-18 05:18:01 +00:00
|
|
|
|
2008-04-17 22:15:07 +00:00
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::WillHandleEvent(nsEventChainPostVisitor& aVisitor)
|
|
|
|
{
|
|
|
|
// If this is the bubble stage and there is a nested form below us which
|
|
|
|
// received a submit event we do *not* want to handle the submit event
|
|
|
|
// for this form too.
|
|
|
|
if ((aVisitor.mEvent->message == NS_FORM_SUBMIT ||
|
|
|
|
aVisitor.mEvent->message == NS_FORM_RESET) &&
|
|
|
|
aVisitor.mEvent->flags & NS_EVENT_FLAG_BUBBLE &&
|
|
|
|
aVisitor.mEvent->originalTarget != static_cast<nsIContent*>(this)) {
|
|
|
|
aVisitor.mEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
|
|
|
{
|
2007-07-08 07:08:04 +00:00
|
|
|
if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) {
|
2006-03-07 17:08:51 +00:00
|
|
|
PRUint32 msg = aVisitor.mEvent->message;
|
|
|
|
if (msg == NS_FORM_SUBMIT) {
|
|
|
|
// let the form know not to defer subsequent submissions
|
|
|
|
mDeferSubmission = PR_FALSE;
|
|
|
|
}
|
2000-08-18 05:18:01 +00:00
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
if (aVisitor.mEventStatus == nsEventStatus_eIgnore) {
|
|
|
|
switch (msg) {
|
2002-12-03 23:06:34 +00:00
|
|
|
case NS_FORM_RESET:
|
|
|
|
case NS_FORM_SUBMIT:
|
|
|
|
{
|
2006-03-07 17:08:51 +00:00
|
|
|
if (mPendingSubmission && msg == NS_FORM_SUBMIT) {
|
2002-12-03 23:06:34 +00:00
|
|
|
// tell the form to forget a possible pending submission.
|
|
|
|
// the reason is that the script returned true (the event was
|
|
|
|
// ignored) so if there is a stored submission, it will miss
|
|
|
|
// the name/value of the submitting element, thus we need
|
|
|
|
// to forget it and the form element will build a new one
|
2010-02-25 05:58:17 +00:00
|
|
|
mPendingSubmission = nsnull;
|
2002-12-03 23:06:34 +00:00
|
|
|
}
|
2006-03-07 17:08:51 +00:00
|
|
|
DoSubmitOrReset(aVisitor.mEvent, msg);
|
2002-12-03 23:06:34 +00:00
|
|
|
}
|
|
|
|
break;
|
2000-08-18 05:18:01 +00:00
|
|
|
}
|
2002-12-03 23:06:34 +00:00
|
|
|
} else {
|
2006-03-07 17:08:51 +00:00
|
|
|
if (msg == NS_FORM_SUBMIT) {
|
2002-12-14 02:38:17 +00:00
|
|
|
// tell the form to flush a possible pending submission.
|
|
|
|
// the reason is that the script returned false (the event was
|
|
|
|
// not ignored) so if there is a stored submission, it needs to
|
|
|
|
// be submitted immediatelly.
|
|
|
|
FlushPendingSubmission();
|
|
|
|
}
|
2000-08-18 05:18:01 +00:00
|
|
|
}
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
if (msg == NS_FORM_SUBMIT) {
|
|
|
|
mGeneratingSubmit = PR_FALSE;
|
|
|
|
}
|
|
|
|
else if (msg == NS_FORM_RESET) {
|
|
|
|
mGeneratingReset = PR_FALSE;
|
|
|
|
}
|
2001-04-24 05:18:10 +00:00
|
|
|
}
|
2006-03-07 17:08:51 +00:00
|
|
|
return NS_OK;
|
1998-09-02 00:56:01 +00:00
|
|
|
}
|
1998-09-23 17:16:51 +00:00
|
|
|
|
2001-04-24 05:18:10 +00:00
|
|
|
nsresult
|
2005-11-08 22:45:49 +00:00
|
|
|
nsHTMLFormElement::DoSubmitOrReset(nsEvent* aEvent,
|
2002-02-16 01:19:24 +00:00
|
|
|
PRInt32 aMessage)
|
|
|
|
{
|
2001-04-24 05:18:10 +00:00
|
|
|
// Make sure the presentation is up-to-date
|
2004-10-11 16:14:27 +00:00
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (doc) {
|
|
|
|
doc->FlushPendingNotifications(Flush_ContentAndNotify);
|
2001-04-24 05:18:10 +00:00
|
|
|
}
|
|
|
|
|
2001-11-02 07:40:01 +00:00
|
|
|
// JBK Don't get form frames anymore - bug 34297
|
2001-04-24 05:18:10 +00:00
|
|
|
|
|
|
|
// Submit or Reset the form
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (NS_FORM_RESET == aMessage) {
|
2002-02-16 01:19:24 +00:00
|
|
|
rv = DoReset();
|
2001-04-24 05:18:10 +00:00
|
|
|
}
|
|
|
|
else if (NS_FORM_SUBMIT == aMessage) {
|
2005-11-08 22:45:49 +00:00
|
|
|
// Don't submit if we're not in a document.
|
|
|
|
if (doc) {
|
|
|
|
rv = DoSubmit(aEvent);
|
|
|
|
}
|
2001-04-24 05:18:10 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::DoReset()
|
2001-11-02 07:40:01 +00:00
|
|
|
{
|
|
|
|
// JBK walk the elements[] array instead of form frame controls - bug 34297
|
2008-10-09 23:31:40 +00:00
|
|
|
PRUint32 numElements = GetElementCount();
|
2001-11-02 07:40:01 +00:00
|
|
|
for (PRUint32 elementX = 0; (elementX < numElements); elementX++) {
|
2009-10-30 01:49:11 +00:00
|
|
|
// Hold strong ref in case the reset does something weird
|
|
|
|
nsCOMPtr<nsIFormControl> controlNode = GetElementAt(elementX);
|
2001-11-02 07:40:01 +00:00
|
|
|
if (controlNode) {
|
|
|
|
controlNode->Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-08-20 02:35:39 +00:00
|
|
|
#define NS_ENSURE_SUBMIT_SUCCESS(rv) \
|
|
|
|
if (NS_FAILED(rv)) { \
|
|
|
|
ForgetCurrentSubmission(); \
|
|
|
|
return rv; \
|
2002-03-13 06:08:56 +00:00
|
|
|
}
|
2002-11-30 00:01:21 +00:00
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
nsresult
|
2005-11-08 22:45:49 +00:00
|
|
|
nsHTMLFormElement::DoSubmit(nsEvent* aEvent)
|
2002-02-16 01:19:24 +00:00
|
|
|
{
|
2005-11-08 22:45:49 +00:00
|
|
|
NS_ASSERTION(GetCurrentDoc(), "Should never get here without a current doc");
|
2007-11-07 06:44:02 +00:00
|
|
|
|
2002-03-13 06:08:56 +00:00
|
|
|
if (mIsSubmitting) {
|
2007-11-07 06:44:02 +00:00
|
|
|
NS_WARNING("Preventing double form submission");
|
2002-03-13 06:08:56 +00:00
|
|
|
// XXX Should this return an error?
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark us as submitting so that we don't try to submit again
|
|
|
|
mIsSubmitting = PR_TRUE;
|
2002-08-20 02:35:39 +00:00
|
|
|
NS_ASSERTION(!mWebProgress && !mSubmittingRequest, "Web progress / submitting request should not exist here!");
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2010-02-25 05:58:17 +00:00
|
|
|
nsAutoPtr<nsFormSubmission> submission;
|
2010-02-25 05:58:16 +00:00
|
|
|
|
2002-11-30 00:01:21 +00:00
|
|
|
//
|
|
|
|
// prepare the submission object
|
|
|
|
//
|
2010-08-20 17:47:30 +00:00
|
|
|
nsresult rv = BuildSubmission(getter_Transfers(submission), aEvent);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mIsSubmitting = PR_FALSE;
|
|
|
|
return rv;
|
|
|
|
}
|
2004-09-04 19:28:46 +00:00
|
|
|
|
2004-10-11 16:14:27 +00:00
|
|
|
// XXXbz if the script global is that for an sXBL/XBL2 doc, it won't
|
|
|
|
// be a window...
|
2005-11-28 23:56:44 +00:00
|
|
|
nsPIDOMWindow *window = GetOwnerDoc()->GetWindow();
|
2004-09-04 19:28:46 +00:00
|
|
|
|
|
|
|
if (window) {
|
|
|
|
mSubmitPopupState = window->GetPopupControlState();
|
|
|
|
} else {
|
|
|
|
mSubmitPopupState = openAbused;
|
|
|
|
}
|
|
|
|
|
|
|
|
mSubmitInitiatedFromUserInput = nsEventStateManager::IsHandlingUserInput();
|
|
|
|
|
2002-12-03 23:06:34 +00:00
|
|
|
if(mDeferSubmission) {
|
|
|
|
// we are in an event handler, JS submitted so we have to
|
2002-11-30 00:01:21 +00:00
|
|
|
// defer this submission. let's remember it and return
|
|
|
|
// without submitting
|
|
|
|
mPendingSubmission = submission;
|
|
|
|
// ensure reentrancy
|
|
|
|
mIsSubmitting = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// perform the submission
|
|
|
|
//
|
2005-11-08 22:45:49 +00:00
|
|
|
return SubmitSubmission(submission);
|
2002-11-30 00:01:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2010-02-25 05:58:17 +00:00
|
|
|
nsHTMLFormElement::BuildSubmission(nsFormSubmission** aFormSubmission,
|
2002-11-30 00:01:21 +00:00
|
|
|
nsEvent* aEvent)
|
|
|
|
{
|
2002-12-14 02:38:17 +00:00
|
|
|
NS_ASSERTION(!mPendingSubmission, "tried to build two submissions!");
|
2002-11-30 00:01:21 +00:00
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
// Get the originating frame (failure is non-fatal)
|
2010-08-20 17:47:30 +00:00
|
|
|
nsGenericHTMLElement* originatingElement = nsnull;
|
2002-02-16 01:19:24 +00:00
|
|
|
if (aEvent) {
|
|
|
|
if (NS_FORM_EVENT == aEvent->eventStructType) {
|
2010-08-20 17:47:30 +00:00
|
|
|
nsIContent* originator = ((nsFormEvent *)aEvent)->originator;
|
|
|
|
if (originator) {
|
|
|
|
if (!originator->IsHTML()) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
originatingElement =
|
|
|
|
static_cast<nsGenericHTMLElement*>(((nsFormEvent *)aEvent)->originator);
|
|
|
|
}
|
2002-02-16 01:19:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-30 00:01:21 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
//
|
|
|
|
// Get the submission object
|
|
|
|
//
|
2010-08-19 21:58:20 +00:00
|
|
|
rv = GetSubmissionFromForm(this, originatingElement, aFormSubmission);
|
2002-03-13 06:08:56 +00:00
|
|
|
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
2002-02-16 01:19:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Dump the data into the submission object
|
|
|
|
//
|
2010-08-19 21:58:20 +00:00
|
|
|
rv = WalkFormElements(*aFormSubmission);
|
2002-03-13 06:08:56 +00:00
|
|
|
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2002-11-30 00:01:21 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2010-02-25 05:58:16 +00:00
|
|
|
nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
|
2002-11-30 00:01:21 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
2010-08-19 22:58:10 +00:00
|
|
|
nsIContent* originatingElement = aFormSubmission->GetOriginatingElement();
|
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
//
|
|
|
|
// Get the action and target
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIURI> actionURI;
|
2010-08-19 23:23:59 +00:00
|
|
|
rv = GetActionURL(getter_AddRefs(actionURI), originatingElement);
|
2002-03-13 06:08:56 +00:00
|
|
|
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2002-03-13 06:08:56 +00:00
|
|
|
if (!actionURI) {
|
|
|
|
mIsSubmitting = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2005-05-07 00:16:17 +00:00
|
|
|
// If there is no link handler, then we won't actually be able to submit.
|
2005-11-08 22:45:49 +00:00
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
2006-07-22 11:07:29 +00:00
|
|
|
nsCOMPtr<nsISupports> container = doc ? doc->GetContainer() : nsnull;
|
2005-11-08 22:45:49 +00:00
|
|
|
nsCOMPtr<nsILinkHandler> linkHandler(do_QueryInterface(container));
|
2007-07-11 13:05:05 +00:00
|
|
|
if (!linkHandler || IsEditable()) {
|
2005-05-07 00:16:17 +00:00
|
|
|
mIsSubmitting = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-01-11 17:58:36 +00:00
|
|
|
// javascript URIs are not really submissions; they just call a function.
|
|
|
|
// Also, they may synchronously call submit(), and we want them to be able to
|
|
|
|
// do so while still disallowing other double submissions. (Bug 139798)
|
|
|
|
// Note that any other URI types that are of equivalent type should also be
|
|
|
|
// added here.
|
|
|
|
// XXXbz this is a mess. The real issue here is that nsJSChannel sets the
|
|
|
|
// LOAD_BACKGROUND flag, so doesn't notify us, compounded by the fact that
|
|
|
|
// the JS executes before we forget the submission in OnStateChange on
|
|
|
|
// STATE_STOP. As a result, we have to make sure that we simply pretend
|
|
|
|
// we're not submitting when submitting to a JS URL. That's kinda bogus, but
|
|
|
|
// there we are.
|
|
|
|
PRBool schemeIsJavaScript = PR_FALSE;
|
|
|
|
if (NS_SUCCEEDED(actionURI->SchemeIs("javascript", &schemeIsJavaScript)) &&
|
|
|
|
schemeIsJavaScript) {
|
|
|
|
mIsSubmitting = PR_FALSE;
|
|
|
|
}
|
2002-04-30 23:21:58 +00:00
|
|
|
|
2010-08-19 22:58:10 +00:00
|
|
|
// The target is the originating element formtarget attribute if the element
|
|
|
|
// is a submit control and has such an attribute.
|
|
|
|
// Otherwise, the target is the form owner's target attribute,
|
|
|
|
// if it has such an attribute.
|
|
|
|
// Finally, if one of the child nodes of the head element is a base element
|
|
|
|
// with a target attribute, then the value of the target attribute of the
|
|
|
|
// first such base element; or, if there is no such element, the empty string.
|
2002-03-13 06:08:56 +00:00
|
|
|
nsAutoString target;
|
2010-08-19 22:58:10 +00:00
|
|
|
if (!(originatingElement && originatingElement->GetAttr(kNameSpaceID_None,
|
|
|
|
nsGkAtoms::formtarget,
|
|
|
|
target)) &&
|
|
|
|
!GetAttr(kNameSpaceID_None, nsGkAtoms::target, target)) {
|
2010-05-31 23:43:11 +00:00
|
|
|
GetBaseTarget(target);
|
|
|
|
}
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2002-03-13 06:08:56 +00:00
|
|
|
//
|
|
|
|
// Notify observers of submit
|
|
|
|
//
|
2006-06-23 02:44:39 +00:00
|
|
|
PRBool cancelSubmit = PR_FALSE;
|
|
|
|
if (mNotifiedObservers) {
|
|
|
|
cancelSubmit = mNotifiedObserversResult;
|
|
|
|
} else {
|
2006-07-18 00:18:32 +00:00
|
|
|
rv = NotifySubmitObservers(actionURI, &cancelSubmit, PR_TRUE);
|
2006-06-23 02:44:39 +00:00
|
|
|
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
|
|
|
}
|
2002-03-13 06:08:56 +00:00
|
|
|
|
2006-06-23 02:44:39 +00:00
|
|
|
if (cancelSubmit) {
|
2002-03-13 06:08:56 +00:00
|
|
|
mIsSubmitting = PR_FALSE;
|
|
|
|
return NS_OK;
|
2002-02-16 01:19:24 +00:00
|
|
|
}
|
|
|
|
|
2006-07-18 00:18:32 +00:00
|
|
|
cancelSubmit = PR_FALSE;
|
|
|
|
rv = NotifySubmitObservers(actionURI, &cancelSubmit, PR_FALSE);
|
|
|
|
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
|
|
|
|
|
|
|
if (cancelSubmit) {
|
|
|
|
mIsSubmitting = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-03-13 06:08:56 +00:00
|
|
|
//
|
|
|
|
// Submit
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIDocShell> docShell;
|
2004-09-04 19:28:46 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
|
|
|
|
|
2009-09-13 13:13:16 +00:00
|
|
|
nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput, PR_FALSE);
|
2004-09-04 19:28:46 +00:00
|
|
|
|
2010-02-25 05:58:17 +00:00
|
|
|
nsCOMPtr<nsIInputStream> postDataStream;
|
|
|
|
rv = aFormSubmission->GetEncodedSubmission(actionURI,
|
|
|
|
getter_AddRefs(postDataStream));
|
|
|
|
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
2004-09-04 19:28:46 +00:00
|
|
|
|
2010-02-25 05:58:17 +00:00
|
|
|
rv = linkHandler->OnLinkClickSync(this, actionURI,
|
|
|
|
target.get(),
|
|
|
|
postDataStream, nsnull,
|
|
|
|
getter_AddRefs(docShell),
|
|
|
|
getter_AddRefs(mSubmittingRequest));
|
|
|
|
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
|
|
|
}
|
2002-03-13 06:08:56 +00:00
|
|
|
|
2002-03-27 05:45:17 +00:00
|
|
|
// Even if the submit succeeds, it's possible for there to be no docshell
|
|
|
|
// or request; for example, if it's to a named anchor within the same page
|
|
|
|
// the submit will not really do anything.
|
|
|
|
if (docShell) {
|
2002-08-01 18:17:48 +00:00
|
|
|
// If the channel is pending, we have to listen for web progress.
|
|
|
|
PRBool pending = PR_FALSE;
|
|
|
|
mSubmittingRequest->IsPending(&pending);
|
2007-01-11 17:58:36 +00:00
|
|
|
if (pending && !schemeIsJavaScript) {
|
2007-11-30 17:57:03 +00:00
|
|
|
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
|
|
|
|
NS_ASSERTION(webProgress, "nsIDocShell not converted to nsIWebProgress!");
|
|
|
|
rv = webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_ALL);
|
2002-08-01 18:17:48 +00:00
|
|
|
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
2007-11-30 17:57:03 +00:00
|
|
|
mWebProgress = do_GetWeakReference(webProgress);
|
|
|
|
NS_ASSERTION(mWebProgress, "can't hold weak ref to webprogress!");
|
2002-08-01 18:17:48 +00:00
|
|
|
} else {
|
2002-08-20 02:35:39 +00:00
|
|
|
ForgetCurrentSubmission();
|
2002-08-01 18:17:48 +00:00
|
|
|
}
|
2002-08-20 02:35:39 +00:00
|
|
|
} else {
|
|
|
|
ForgetCurrentSubmission();
|
2002-03-27 05:45:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
2002-02-16 01:19:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
|
2006-07-18 00:18:32 +00:00
|
|
|
PRBool* aCancelSubmit,
|
|
|
|
PRBool aEarlyNotify)
|
2002-02-16 01:19:24 +00:00
|
|
|
{
|
|
|
|
// If this is the first form, bring alive the first form submit
|
|
|
|
// category observers
|
|
|
|
if (!gFirstFormSubmitted) {
|
|
|
|
gFirstFormSubmitted = PR_TRUE;
|
|
|
|
NS_CreateServicesFromCategory(NS_FIRST_FORMSUBMIT_CATEGORY,
|
|
|
|
nsnull,
|
|
|
|
NS_FIRST_FORMSUBMIT_CATEGORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify observers that the form is being submitted.
|
|
|
|
nsCOMPtr<nsIObserverService> service =
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 16:59:13 +00:00
|
|
|
mozilla::services::GetObserverService();
|
|
|
|
if (!service)
|
|
|
|
return NS_ERROR_FAILURE;
|
2002-02-16 01:19:24 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> theEnum;
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 16:59:13 +00:00
|
|
|
nsresult rv = service->EnumerateObservers(aEarlyNotify ?
|
|
|
|
NS_EARLYFORMSUBMIT_SUBJECT :
|
|
|
|
NS_FORMSUBMIT_SUBJECT,
|
|
|
|
getter_AddRefs(theEnum));
|
2002-02-16 01:19:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (theEnum) {
|
|
|
|
nsCOMPtr<nsISupports> inst;
|
|
|
|
*aCancelSubmit = PR_FALSE;
|
|
|
|
|
2004-10-11 16:14:27 +00:00
|
|
|
// XXXbz what do the submit observers actually want? The window
|
|
|
|
// of the document this is shown in? Or something else?
|
|
|
|
// sXBL/XBL2 issue
|
2005-11-28 23:56:44 +00:00
|
|
|
nsCOMPtr<nsPIDOMWindow> window = GetOwnerDoc()->GetWindow();
|
2002-02-16 01:19:24 +00:00
|
|
|
|
|
|
|
PRBool loop = PR_TRUE;
|
|
|
|
while (NS_SUCCEEDED(theEnum->HasMoreElements(&loop)) && loop) {
|
|
|
|
theEnum->GetNext(getter_AddRefs(inst));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFormSubmitObserver> formSubmitObserver(
|
|
|
|
do_QueryInterface(inst));
|
|
|
|
if (formSubmitObserver) {
|
|
|
|
rv = formSubmitObserver->Notify(this,
|
|
|
|
window,
|
|
|
|
aActionURL,
|
|
|
|
aCancelSubmit);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
if (*aCancelSubmit) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2010-08-19 21:58:20 +00:00
|
|
|
nsHTMLFormElement::WalkFormElements(nsFormSubmission* aFormSubmission)
|
2002-02-16 01:19:24 +00:00
|
|
|
{
|
2009-10-30 01:49:11 +00:00
|
|
|
nsTArray<nsGenericHTMLFormElement*> sortedControls;
|
2006-09-18 04:53:54 +00:00
|
|
|
nsresult rv = mControls->GetSortedControls(sortedControls);
|
2002-08-17 05:42:55 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-02-16 01:19:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Walk the list of nodes and call SubmitNamesValues() on the controls
|
|
|
|
//
|
2006-09-18 04:53:54 +00:00
|
|
|
PRUint32 len = sortedControls.Length();
|
|
|
|
for (PRUint32 i = 0; i < len; ++i) {
|
2002-02-16 01:19:24 +00:00
|
|
|
// Tell the control to submit its name/value pairs to the submission
|
2010-08-19 21:58:20 +00:00
|
|
|
sortedControls[i]->SubmitNamesValues(aFormSubmission);
|
2002-02-16 01:19:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
// nsIForm
|
|
|
|
|
2008-10-09 23:31:40 +00:00
|
|
|
NS_IMETHODIMP_(PRUint32)
|
|
|
|
nsHTMLFormElement::GetElementCount() const
|
1998-09-23 17:16:51 +00:00
|
|
|
{
|
2008-10-09 23:31:40 +00:00
|
|
|
PRUint32 count = nsnull;
|
|
|
|
mControls->GetLength(&count);
|
|
|
|
return count;
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
NS_IMETHODIMP_(nsIFormControl*)
|
|
|
|
nsHTMLFormElement::GetElementAt(PRInt32 aIndex) const
|
2001-12-21 01:10:07 +00:00
|
|
|
{
|
2009-10-30 01:49:11 +00:00
|
|
|
return mControls->mElements.SafeElementAt(aIndex, nsnull);
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
2007-07-26 04:26:07 +00:00
|
|
|
/**
|
|
|
|
* Compares the position of aControl1 and aControl2 in the document
|
|
|
|
* @param aControl1 First control to compare.
|
|
|
|
* @param aControl2 Second control to compare.
|
|
|
|
* @param aForm Parent form of the controls.
|
|
|
|
* @return < 0 if aControl1 is before aControl2,
|
|
|
|
* > 0 if aControl1 is after aControl2,
|
|
|
|
* 0 otherwise
|
|
|
|
*/
|
2009-10-30 01:49:11 +00:00
|
|
|
static inline PRInt32
|
|
|
|
CompareFormControlPosition(nsGenericHTMLFormElement *aControl1,
|
|
|
|
nsGenericHTMLFormElement *aControl2,
|
|
|
|
const nsIContent* aForm)
|
2007-07-26 04:26:07 +00:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aControl1 != aControl2, "Comparing a form control to itself");
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
NS_ASSERTION(aControl1->GetParent() && aControl2->GetParent(),
|
2007-07-26 04:26:07 +00:00
|
|
|
"Form controls should always have parents");
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
return nsLayoutUtils::CompareTreePosition(aControl1, aControl2, aForm);
|
2007-07-26 04:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/**
|
|
|
|
* Checks that all form elements are in document order. Asserts if any pair of
|
|
|
|
* consecutive elements are not in increasing document order.
|
|
|
|
*
|
|
|
|
* @param aControls List of form controls to check.
|
|
|
|
* @param aForm Parent form of the controls.
|
|
|
|
*/
|
|
|
|
static void
|
2009-10-30 01:49:11 +00:00
|
|
|
AssertDocumentOrder(const nsTArray<nsGenericHTMLFormElement*>& aControls,
|
2007-07-26 04:26:07 +00:00
|
|
|
nsIContent* aForm)
|
|
|
|
{
|
|
|
|
// Only iterate if aControls is not empty, since otherwise
|
|
|
|
// |aControls.Length() - 1| will be a very large unsigned number... not what
|
|
|
|
// we want here.
|
|
|
|
if (!aControls.IsEmpty()) {
|
|
|
|
for (PRUint32 i = 0; i < aControls.Length() - 1; ++i) {
|
|
|
|
NS_ASSERTION(CompareFormControlPosition(aControls[i], aControls[i + 1],
|
|
|
|
aForm) < 0,
|
|
|
|
"Form controls not ordered correctly");
|
|
|
|
}
|
|
|
|
}
|
2004-10-31 19:58:10 +00:00
|
|
|
}
|
2007-07-26 04:26:07 +00:00
|
|
|
#endif
|
2004-10-31 19:58:10 +00:00
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
|
2006-08-16 03:20:19 +00:00
|
|
|
PRBool aNotify)
|
1999-09-13 06:18:09 +00:00
|
|
|
{
|
2009-10-30 01:49:11 +00:00
|
|
|
NS_ASSERTION(aChild->GetParent(), "Form control should have a parent");
|
2007-07-26 04:26:07 +00:00
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
// Determine whether to add the new element to the elements or
|
|
|
|
// the not-in-elements list.
|
|
|
|
PRBool childInElements = ShouldBeInElements(aChild);
|
2009-10-30 01:49:11 +00:00
|
|
|
nsTArray<nsGenericHTMLFormElement*>& controlList = childInElements ?
|
2006-09-18 04:53:54 +00:00
|
|
|
mControls->mElements : mControls->mNotInElements;
|
|
|
|
|
2007-07-26 04:26:07 +00:00
|
|
|
NS_ASSERTION(controlList.IndexOf(aChild) == controlList.NoIndex,
|
|
|
|
"Form control already in form");
|
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
PRUint32 count = controlList.Length();
|
2009-10-30 01:49:11 +00:00
|
|
|
nsGenericHTMLFormElement* element;
|
2006-09-18 04:53:54 +00:00
|
|
|
|
|
|
|
// Optimize most common case where we insert at the end.
|
2006-08-16 03:20:19 +00:00
|
|
|
PRBool lastElement = PR_FALSE;
|
2006-09-18 04:53:54 +00:00
|
|
|
PRInt32 position = -1;
|
|
|
|
if (count > 0) {
|
|
|
|
element = controlList[count - 1];
|
2007-07-26 04:26:07 +00:00
|
|
|
position = CompareFormControlPosition(aChild, element, this);
|
2006-09-18 04:53:54 +00:00
|
|
|
}
|
2004-10-31 19:58:10 +00:00
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
// If this item comes after the last element, or the elements array is
|
|
|
|
// empty, we append to the end. Otherwise, we do a binary search to
|
|
|
|
// determine where the element should go.
|
|
|
|
if (position >= 0 || count == 0) {
|
|
|
|
// WEAK - don't addref
|
|
|
|
controlList.AppendElement(aChild);
|
|
|
|
lastElement = PR_TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PRInt32 low = 0, mid, high;
|
|
|
|
high = count - 1;
|
2004-10-31 19:58:10 +00:00
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
while (low <= high) {
|
|
|
|
mid = (low + high) / 2;
|
2004-10-31 19:58:10 +00:00
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
element = controlList[mid];
|
2007-07-26 04:26:07 +00:00
|
|
|
position = CompareFormControlPosition(aChild, element, this);
|
2006-09-18 04:53:54 +00:00
|
|
|
if (position >= 0)
|
|
|
|
low = mid + 1;
|
|
|
|
else
|
|
|
|
high = mid - 1;
|
2004-10-31 19:58:10 +00:00
|
|
|
}
|
2006-09-18 04:53:54 +00:00
|
|
|
|
2002-08-17 05:42:55 +00:00
|
|
|
// WEAK - don't addref
|
2006-09-18 04:53:54 +00:00
|
|
|
controlList.InsertElementAt(low, aChild);
|
2001-03-22 08:51:52 +00:00
|
|
|
}
|
|
|
|
|
2007-07-26 04:26:07 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
AssertDocumentOrder(controlList, this);
|
|
|
|
#endif
|
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
//
|
|
|
|
// Notify the radio button it's been added to a group
|
|
|
|
//
|
2002-12-18 23:38:09 +00:00
|
|
|
PRInt32 type = aChild->GetType();
|
2002-03-07 20:53:40 +00:00
|
|
|
if (type == NS_FORM_INPUT_RADIO) {
|
2010-07-14 06:39:48 +00:00
|
|
|
nsRefPtr<nsHTMLInputElement> radio =
|
|
|
|
static_cast<nsHTMLInputElement*>(aChild);
|
|
|
|
radio->AddedToRadioGroup();
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2002-06-04 00:44:04 +00:00
|
|
|
//
|
|
|
|
// If it is a password control, and the password manager has not yet been
|
|
|
|
// initialized, initialize the password manager
|
|
|
|
//
|
|
|
|
if (!gPasswordManagerInitialized && type == NS_FORM_INPUT_PASSWORD) {
|
|
|
|
// Initialize the password manager category
|
|
|
|
gPasswordManagerInitialized = PR_TRUE;
|
2007-05-16 18:59:32 +00:00
|
|
|
NS_CreateServicesFromCategory(NS_PASSWORDMANAGER_CATEGORY,
|
|
|
|
nsnull,
|
|
|
|
NS_PASSWORDMANAGER_CATEGORY);
|
2002-06-04 00:44:04 +00:00
|
|
|
}
|
2006-08-16 03:20:19 +00:00
|
|
|
|
|
|
|
// Default submit element handling
|
|
|
|
if (aChild->IsSubmitControl()) {
|
2007-08-07 02:07:24 +00:00
|
|
|
// Update mDefaultSubmitElement, mFirstSubmitInElements,
|
|
|
|
// mFirstSubmitNotInElements.
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsGenericHTMLFormElement** firstSubmitSlot =
|
2007-08-07 02:07:24 +00:00
|
|
|
childInElements ? &mFirstSubmitInElements : &mFirstSubmitNotInElements;
|
|
|
|
|
|
|
|
// The new child is the new first submit in its list if the firstSubmitSlot
|
|
|
|
// is currently empty or if the child is before what's currently in the
|
|
|
|
// slot. Note that if we already have a control in firstSubmitSlot and
|
|
|
|
// we're appending this element can't possibly replace what's currently in
|
|
|
|
// the slot. Also note that aChild can't become the mDefaultSubmitElement
|
|
|
|
// unless it replaces what's in the slot. If it _does_ replace what's in
|
|
|
|
// the slot, it becomes the default submit if either the default submit is
|
|
|
|
// what's in the slot or the child is earlier than the default submit.
|
|
|
|
nsIFormControl* oldDefaultSubmit = mDefaultSubmitElement;
|
|
|
|
if (!*firstSubmitSlot ||
|
|
|
|
(!lastElement &&
|
|
|
|
CompareFormControlPosition(aChild, *firstSubmitSlot, this) < 0)) {
|
2009-09-18 18:52:36 +00:00
|
|
|
// Update mDefaultSubmitElement if it's currently in a valid state.
|
|
|
|
// Valid state means either non-null or null because there are in fact
|
|
|
|
// no submit elements around.
|
|
|
|
if ((mDefaultSubmitElement ||
|
|
|
|
(!mFirstSubmitInElements && !mFirstSubmitNotInElements)) &&
|
|
|
|
(*firstSubmitSlot == mDefaultSubmitElement ||
|
|
|
|
CompareFormControlPosition(aChild,
|
|
|
|
mDefaultSubmitElement, this) < 0)) {
|
2007-08-07 02:07:24 +00:00
|
|
|
mDefaultSubmitElement = aChild;
|
|
|
|
}
|
|
|
|
*firstSubmitSlot = aChild;
|
2006-08-16 03:20:19 +00:00
|
|
|
}
|
2007-08-07 02:07:24 +00:00
|
|
|
NS_POSTCONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
|
2009-09-18 18:52:36 +00:00
|
|
|
mDefaultSubmitElement == mFirstSubmitNotInElements ||
|
|
|
|
!mDefaultSubmitElement,
|
2007-08-07 02:07:24 +00:00
|
|
|
"What happened here?");
|
2006-08-16 03:20:19 +00:00
|
|
|
|
2007-02-09 06:20:47 +00:00
|
|
|
// Notify that the state of the previous default submit element has changed
|
|
|
|
// if the element which is the default submit element has changed. The new
|
|
|
|
// default submit element is responsible for its own ContentStatesChanged
|
|
|
|
// call.
|
2007-08-07 02:07:24 +00:00
|
|
|
if (aNotify && oldDefaultSubmit &&
|
|
|
|
oldDefaultSubmit != mDefaultSubmitElement) {
|
2006-08-16 03:20:19 +00:00
|
|
|
nsIDocument* document = GetCurrentDoc();
|
|
|
|
if (document) {
|
|
|
|
MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE);
|
2007-08-07 02:07:24 +00:00
|
|
|
nsCOMPtr<nsIContent> oldElement(do_QueryInterface(oldDefaultSubmit));
|
2007-02-09 06:20:47 +00:00
|
|
|
document->ContentStatesChanged(oldElement, nsnull,
|
2006-08-16 03:20:19 +00:00
|
|
|
NS_EVENT_STATE_DEFAULT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-06-04 00:44:04 +00:00
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
return NS_OK;
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild,
|
2002-03-23 23:04:39 +00:00
|
|
|
const nsAString& aName)
|
2000-04-19 07:49:07 +00:00
|
|
|
{
|
|
|
|
return mControls->AddElementToTable(aChild, aName);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
|
2006-08-16 03:20:19 +00:00
|
|
|
PRBool aNotify)
|
2000-06-23 14:12:24 +00:00
|
|
|
{
|
2002-03-07 20:53:40 +00:00
|
|
|
//
|
|
|
|
// Remove it from the radio group if it's a radio button
|
|
|
|
//
|
2006-08-16 03:20:19 +00:00
|
|
|
nsresult rv = NS_OK;
|
2002-12-18 23:38:09 +00:00
|
|
|
if (aChild->GetType() == NS_FORM_INPUT_RADIO) {
|
2010-07-14 06:39:48 +00:00
|
|
|
nsRefPtr<nsHTMLInputElement> radio =
|
|
|
|
static_cast<nsHTMLInputElement*>(aChild);
|
2010-08-21 17:52:57 +00:00
|
|
|
radio->WillRemoveFromRadioGroup(aNotify);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
// Determine whether to remove the child from the elements list
|
|
|
|
// or the not in elements list.
|
|
|
|
PRBool childInElements = ShouldBeInElements(aChild);
|
2009-10-30 01:49:11 +00:00
|
|
|
nsTArray<nsGenericHTMLFormElement*>& controls = childInElements ?
|
2006-09-18 04:53:54 +00:00
|
|
|
mControls->mElements : mControls->mNotInElements;
|
|
|
|
|
|
|
|
// Find the index of the child. This will be used later if necessary
|
|
|
|
// to find the default submit.
|
|
|
|
PRUint32 index = controls.IndexOf(aChild);
|
2008-12-03 10:38:15 +00:00
|
|
|
NS_ENSURE_STATE(index != controls.NoIndex);
|
2006-09-18 04:53:54 +00:00
|
|
|
|
|
|
|
controls.RemoveElementAt(index);
|
2002-07-20 23:09:24 +00:00
|
|
|
|
2007-08-07 02:07:24 +00:00
|
|
|
// Update our mFirstSubmit* values.
|
2009-10-30 01:49:11 +00:00
|
|
|
nsGenericHTMLFormElement** firstSubmitSlot =
|
2007-08-07 02:07:24 +00:00
|
|
|
childInElements ? &mFirstSubmitInElements : &mFirstSubmitNotInElements;
|
|
|
|
if (aChild == *firstSubmitSlot) {
|
|
|
|
*firstSubmitSlot = nsnull;
|
|
|
|
|
|
|
|
// 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) {
|
2009-10-30 01:49:11 +00:00
|
|
|
nsGenericHTMLFormElement* currentControl = controls[i];
|
2007-08-07 02:07:24 +00:00
|
|
|
if (currentControl->IsSubmitControl()) {
|
|
|
|
*firstSubmitSlot = currentControl;
|
|
|
|
break;
|
|
|
|
}
|
2006-08-16 03:20:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-07 02:07:24 +00:00
|
|
|
if (aChild == mDefaultSubmitElement) {
|
2009-09-08 20:00:20 +00:00
|
|
|
// Need to reset mDefaultSubmitElement. Do this asynchronously so
|
|
|
|
// that we're not doing it while the DOM is in flux.
|
|
|
|
mDefaultSubmitElement = nsnull;
|
|
|
|
nsContentUtils::AddScriptRunner(new RemoveElementRunnable(this, aNotify));
|
|
|
|
|
|
|
|
// Note that we don't need to notify on the old default submit (which is
|
|
|
|
// being removed) because it's either being removed from the DOM or
|
|
|
|
// changing attributes in a way that makes it responsible for sending its
|
|
|
|
// own notifications.
|
|
|
|
}
|
2006-09-18 04:53:54 +00:00
|
|
|
|
2009-09-08 20:00:20 +00:00
|
|
|
return rv;
|
|
|
|
}
|
2007-08-07 02:07:24 +00:00
|
|
|
|
2009-09-08 20:00:20 +00:00
|
|
|
void
|
|
|
|
nsHTMLFormElement::HandleDefaultSubmitRemoval(PRBool aNotify)
|
|
|
|
{
|
|
|
|
if (mDefaultSubmitElement) {
|
|
|
|
// Already got reset somehow; nothing else to do here
|
|
|
|
return;
|
2006-09-18 04:53:54 +00:00
|
|
|
}
|
2007-08-07 02:07:24 +00:00
|
|
|
|
2009-09-08 20:00:20 +00:00
|
|
|
if (!mFirstSubmitNotInElements) {
|
|
|
|
mDefaultSubmitElement = mFirstSubmitInElements;
|
|
|
|
} else if (!mFirstSubmitInElements) {
|
|
|
|
mDefaultSubmitElement = mFirstSubmitNotInElements;
|
|
|
|
} else {
|
|
|
|
NS_ASSERTION(mFirstSubmitInElements != mFirstSubmitNotInElements,
|
|
|
|
"How did that happen?");
|
|
|
|
// Have both; use the earlier one
|
|
|
|
mDefaultSubmitElement =
|
|
|
|
CompareFormControlPosition(mFirstSubmitInElements,
|
|
|
|
mFirstSubmitNotInElements, this) < 0 ?
|
|
|
|
mFirstSubmitInElements : mFirstSubmitNotInElements;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_POSTCONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
|
|
|
|
mDefaultSubmitElement == mFirstSubmitNotInElements,
|
|
|
|
"What happened here?");
|
|
|
|
|
|
|
|
// Notify about change if needed.
|
|
|
|
if (aNotify && mDefaultSubmitElement) {
|
|
|
|
nsIDocument* document = GetCurrentDoc();
|
|
|
|
if (document) {
|
|
|
|
MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE);
|
2009-10-30 01:49:11 +00:00
|
|
|
document->ContentStatesChanged(mDefaultSubmitElement, nsnull,
|
2009-09-08 20:00:20 +00:00
|
|
|
NS_EVENT_STATE_DEFAULT);
|
|
|
|
}
|
|
|
|
}
|
2006-09-18 04:53:54 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsresult
|
|
|
|
nsHTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
|
2002-03-23 23:04:39 +00:00
|
|
|
const nsAString& aName)
|
2000-06-23 14:12:24 +00:00
|
|
|
{
|
|
|
|
return mControls->RemoveElementFromTable(aElement, aName);
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
2008-10-09 23:31:40 +00:00
|
|
|
NS_IMETHODIMP_(already_AddRefed<nsISupports>)
|
|
|
|
nsHTMLFormElement::ResolveName(const nsAString& aName)
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
{
|
2008-10-09 23:31:40 +00:00
|
|
|
return DoResolveName(aName, PR_TRUE);
|
2006-02-08 05:56:13 +00:00
|
|
|
}
|
|
|
|
|
2008-10-09 23:31:40 +00:00
|
|
|
already_AddRefed<nsISupports>
|
2006-02-08 05:56:13 +00:00
|
|
|
nsHTMLFormElement::DoResolveName(const nsAString& aName,
|
2008-10-09 23:31:40 +00:00
|
|
|
PRBool aFlushContent)
|
2006-02-08 05:56:13 +00:00
|
|
|
{
|
2008-10-31 21:40:35 +00:00
|
|
|
nsISupports *result;
|
|
|
|
NS_IF_ADDREF(result = mControls->NamedItemInternal(aName, aFlushContent));
|
2008-10-09 23:31:40 +00:00
|
|
|
return result;
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
void
|
2010-08-19 23:23:59 +00:00
|
|
|
nsHTMLFormElement::OnSubmitClickBegin(nsIContent* aOriginatingElement)
|
2002-11-30 00:01:21 +00:00
|
|
|
{
|
2002-12-03 23:06:34 +00:00
|
|
|
mDeferSubmission = PR_TRUE;
|
2006-06-23 02:44:39 +00:00
|
|
|
|
|
|
|
// Prepare to run NotifySubmitObservers early before the
|
|
|
|
// scripts on the page get to modify the form data, possibly
|
|
|
|
// throwing off any password manager. (bug 257781)
|
|
|
|
nsCOMPtr<nsIURI> actionURI;
|
|
|
|
nsresult rv;
|
|
|
|
|
2010-08-19 23:23:59 +00:00
|
|
|
rv = GetActionURL(getter_AddRefs(actionURI), aOriginatingElement);
|
2006-06-23 02:44:39 +00:00
|
|
|
if (NS_FAILED(rv) || !actionURI)
|
2009-10-30 01:49:11 +00:00
|
|
|
return;
|
2006-06-23 02:44:39 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Notify observers of submit
|
|
|
|
//
|
|
|
|
PRBool cancelSubmit = PR_FALSE;
|
2006-07-18 00:18:32 +00:00
|
|
|
rv = NotifySubmitObservers(actionURI, &cancelSubmit, PR_TRUE);
|
2006-06-23 02:44:39 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
mNotifiedObservers = PR_TRUE;
|
|
|
|
mNotifiedObserversResult = cancelSubmit;
|
|
|
|
}
|
2002-11-30 00:01:21 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
void
|
2002-11-30 00:01:21 +00:00
|
|
|
nsHTMLFormElement::OnSubmitClickEnd()
|
|
|
|
{
|
2002-12-03 23:06:34 +00:00
|
|
|
mDeferSubmission = PR_FALSE;
|
2002-11-30 00:01:21 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
void
|
2002-11-30 00:01:21 +00:00
|
|
|
nsHTMLFormElement::FlushPendingSubmission()
|
|
|
|
{
|
2010-02-25 05:58:17 +00:00
|
|
|
if (mPendingSubmission) {
|
|
|
|
// Transfer owning reference so that the submissioin doesn't get deleted
|
|
|
|
// if we reenter
|
|
|
|
nsAutoPtr<nsFormSubmission> submission = mPendingSubmission;
|
2004-09-10 08:07:04 +00:00
|
|
|
|
2010-02-25 05:58:17 +00:00
|
|
|
SubmitSubmission(submission);
|
2002-11-30 00:01:21 +00:00
|
|
|
}
|
|
|
|
}
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
nsresult
|
2010-08-19 23:23:59 +00:00
|
|
|
nsHTMLFormElement::GetActionURL(nsIURI** aActionURL,
|
|
|
|
nsIContent* aOriginatingElement)
|
2003-03-06 23:03:49 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
*aActionURL = nsnull;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Grab the URL string
|
|
|
|
//
|
2010-08-19 23:23:59 +00:00
|
|
|
// If the originating element is a submit control and has the formaction
|
|
|
|
// attribute specified, it should be used. Otherwise, the action attribute
|
|
|
|
// from the form element should be used.
|
|
|
|
//
|
2003-03-06 23:03:49 +00:00
|
|
|
nsAutoString action;
|
2010-08-19 23:23:59 +00:00
|
|
|
nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aOriginatingElement);
|
|
|
|
if (formControl && formControl->IsSubmitControl() &&
|
|
|
|
aOriginatingElement->GetAttr(kNameSpaceID_None, nsGkAtoms::formaction,
|
|
|
|
action)) {
|
|
|
|
// Avoid resolving action="" to the base uri, bug 297761.
|
|
|
|
if (!action.IsEmpty()) {
|
|
|
|
static_cast<nsGenericHTMLElement*>(aOriginatingElement)->
|
|
|
|
GetURIAttr(nsGkAtoms::formaction, nsnull, action);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
GetMozActionUri(action);
|
|
|
|
}
|
2003-03-06 23:03:49 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Form the full action URL
|
|
|
|
//
|
|
|
|
|
|
|
|
// Get the document to form the URL.
|
|
|
|
// We'll also need it later to get the DOM window when notifying form submit
|
|
|
|
// observers (bug 33203)
|
2004-08-10 10:22:36 +00:00
|
|
|
if (!IsInDoc()) {
|
2003-03-06 23:03:49 +00:00
|
|
|
return NS_OK; // No doc means don't submit, see Bug 28988
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get base URL
|
2004-08-10 10:22:36 +00:00
|
|
|
nsIDocument *document = GetOwnerDoc();
|
|
|
|
nsIURI *docURI = document->GetDocumentURI();
|
2004-01-09 23:54:21 +00:00
|
|
|
NS_ENSURE_TRUE(docURI, NS_ERROR_UNEXPECTED);
|
2003-03-06 23:03:49 +00:00
|
|
|
|
|
|
|
// If an action is not specified and we are inside
|
|
|
|
// a HTML document then reload the URL. This makes us
|
|
|
|
// compatible with 4.x browsers.
|
|
|
|
// If we are in some other type of document such as XML or
|
|
|
|
// XUL, do nothing. This prevents undesirable reloading of
|
|
|
|
// a document inside XUL.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> actionURL;
|
|
|
|
if (action.IsEmpty()) {
|
2004-08-10 10:22:36 +00:00
|
|
|
nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(document));
|
2003-03-06 23:03:49 +00:00
|
|
|
if (!htmlDoc) {
|
|
|
|
// Must be a XML, XUL or other non-HTML document type
|
|
|
|
// so do nothing.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-01-09 23:54:21 +00:00
|
|
|
rv = docURI->Clone(getter_AddRefs(actionURL));
|
2003-03-06 23:03:49 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
} else {
|
2004-01-09 23:54:21 +00:00
|
|
|
nsCOMPtr<nsIURI> baseURL = GetBaseURI();
|
2003-03-06 23:03:49 +00:00
|
|
|
NS_ASSERTION(baseURL, "No Base URL found in Form Submit!\n");
|
|
|
|
if (!baseURL) {
|
|
|
|
return NS_OK; // No base URL -> exit early, see Bug 30721
|
|
|
|
}
|
|
|
|
rv = NS_NewURI(getter_AddRefs(actionURL), action, nsnull, baseURL);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Verify the URL should be reached
|
|
|
|
//
|
|
|
|
// Get security manager, check to see if access to action URI is allowed.
|
|
|
|
//
|
2003-10-30 03:01:25 +00:00
|
|
|
nsIScriptSecurityManager *securityManager =
|
2005-10-14 09:07:29 +00:00
|
|
|
nsContentUtils::GetSecurityManager();
|
2004-04-25 16:55:27 +00:00
|
|
|
rv = securityManager->
|
2006-04-27 18:21:11 +00:00
|
|
|
CheckLoadURIWithPrincipal(NodePrincipal(), actionURL,
|
2004-04-25 16:55:27 +00:00
|
|
|
nsIScriptSecurityManager::STANDARD);
|
2003-03-06 23:03:49 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Assign to the output
|
|
|
|
//
|
|
|
|
*aActionURL = actionURL;
|
|
|
|
NS_ADDREF(*aActionURL);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2006-08-16 03:20:19 +00:00
|
|
|
NS_IMETHODIMP_(nsIFormControl*)
|
|
|
|
nsHTMLFormElement::GetDefaultSubmitElement() const
|
|
|
|
{
|
2007-08-07 02:07:24 +00:00
|
|
|
NS_PRECONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
|
|
|
|
mDefaultSubmitElement == mFirstSubmitNotInElements,
|
|
|
|
"What happened here?");
|
|
|
|
|
2006-08-16 03:20:19 +00:00
|
|
|
return mDefaultSubmitElement;
|
|
|
|
}
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
PRBool
|
2009-09-18 18:52:27 +00:00
|
|
|
nsHTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aControl, "Unexpected call");
|
|
|
|
|
|
|
|
if (aControl == mDefaultSubmitElement) {
|
|
|
|
// Yes, it is
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mDefaultSubmitElement ||
|
|
|
|
(aControl != mFirstSubmitInElements &&
|
|
|
|
aControl != mFirstSubmitNotInElements)) {
|
|
|
|
// It isn't
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// mDefaultSubmitElement is null, but we have a non-null submit around
|
|
|
|
// (aControl, in fact). figure out whether it's in fact the default submit
|
|
|
|
// and just hasn't been set that way yet. Note that we can't just call
|
|
|
|
// HandleDefaultSubmitRemoval because we might need to notify to handle that
|
|
|
|
// correctly and we don't know whether that's safe right here.
|
|
|
|
if (!mFirstSubmitInElements || !mFirstSubmitNotInElements) {
|
|
|
|
// We only have one first submit; aControl has to be it
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have both kinds of submits. Check which comes first.
|
|
|
|
nsIFormControl* defaultSubmit =
|
|
|
|
CompareFormControlPosition(mFirstSubmitInElements,
|
|
|
|
mFirstSubmitNotInElements, this) < 0 ?
|
|
|
|
mFirstSubmitInElements : mFirstSubmitNotInElements;
|
|
|
|
return aControl == defaultSubmit;
|
|
|
|
}
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
PRBool
|
2006-09-18 04:53:54 +00:00
|
|
|
nsHTMLFormElement::HasSingleTextControl() const
|
|
|
|
{
|
|
|
|
// Input text controls are always in the elements list.
|
|
|
|
PRUint32 numTextControlsFound = 0;
|
|
|
|
PRUint32 length = mControls->mElements.Length();
|
|
|
|
for (PRUint32 i = 0; i < length && numTextControlsFound < 2; ++i) {
|
2010-05-12 07:17:07 +00:00
|
|
|
if (mControls->mElements[i]->IsSingleLineTextControl(PR_FALSE)) {
|
|
|
|
numTextControlsFound++;
|
2006-09-18 04:53:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return numTextControlsFound == 1;
|
|
|
|
}
|
|
|
|
|
1998-10-06 21:41:47 +00:00
|
|
|
NS_IMETHODIMP
|
2002-03-23 23:04:39 +00:00
|
|
|
nsHTMLFormElement::GetEncoding(nsAString& aEncoding)
|
1998-10-06 21:41:47 +00:00
|
|
|
{
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
return GetEnctype(aEncoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2002-03-23 23:04:39 +00:00
|
|
|
nsHTMLFormElement::SetEncoding(const nsAString& aEncoding)
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
{
|
|
|
|
return SetEnctype(aEncoding);
|
1998-10-06 21:41:47 +00:00
|
|
|
}
|
2010-02-25 05:58:18 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::GetFormData(nsIDOMFormData** aFormData)
|
|
|
|
{
|
|
|
|
nsRefPtr<nsFormData> fd = new nsFormData();
|
|
|
|
|
2010-08-19 21:58:20 +00:00
|
|
|
nsresult rv = WalkFormElements(fd);
|
2010-02-25 05:58:18 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
*aFormData = fd.forget().get();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-10-06 21:41:47 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-04-18 23:00:58 +00:00
|
|
|
nsHTMLFormElement::GetLength(PRInt32* aLength)
|
1998-10-06 21:41:47 +00:00
|
|
|
{
|
2006-02-08 05:56:13 +00:00
|
|
|
PRUint32 length;
|
|
|
|
nsresult rv = mControls->GetLength(&length);
|
|
|
|
*aLength = length;
|
|
|
|
return rv;
|
1998-10-06 21:41:47 +00:00
|
|
|
}
|
|
|
|
|
2002-08-20 02:35:39 +00:00
|
|
|
void
|
|
|
|
nsHTMLFormElement::ForgetCurrentSubmission()
|
|
|
|
{
|
2006-06-23 02:44:39 +00:00
|
|
|
mNotifiedObservers = PR_FALSE;
|
2002-08-20 02:35:39 +00:00
|
|
|
mIsSubmitting = PR_FALSE;
|
|
|
|
mSubmittingRequest = nsnull;
|
2007-11-30 17:57:03 +00:00
|
|
|
nsCOMPtr<nsIWebProgress> webProgress = do_QueryReferent(mWebProgress);
|
|
|
|
if (webProgress) {
|
|
|
|
webProgress->RemoveProgressListener(this);
|
2002-08-20 02:35:39 +00:00
|
|
|
}
|
2007-11-30 17:57:03 +00:00
|
|
|
mWebProgress = nsnull;
|
2002-08-20 02:35:39 +00:00
|
|
|
}
|
|
|
|
|
2002-03-13 06:08:56 +00:00
|
|
|
// nsIWebProgressListener
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::OnStateChange(nsIWebProgress* aWebProgress,
|
|
|
|
nsIRequest* aRequest,
|
2002-05-16 20:57:37 +00:00
|
|
|
PRUint32 aStateFlags,
|
2002-03-13 06:08:56 +00:00
|
|
|
PRUint32 aStatus)
|
|
|
|
{
|
|
|
|
// If STATE_STOP is never fired for any reason (redirect? Failed state
|
|
|
|
// change?) the form element will leak. It will be kept around by the
|
|
|
|
// nsIWebProgressListener (assuming it keeps a strong pointer). We will
|
|
|
|
// consequently leak the request.
|
|
|
|
if (aRequest == mSubmittingRequest &&
|
|
|
|
aStateFlags & nsIWebProgressListener::STATE_STOP) {
|
2002-08-20 02:35:39 +00:00
|
|
|
ForgetCurrentSubmission();
|
2002-03-13 06:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::OnProgressChange(nsIWebProgress* aWebProgress,
|
|
|
|
nsIRequest* aRequest,
|
|
|
|
PRInt32 aCurSelfProgress,
|
|
|
|
PRInt32 aMaxSelfProgress,
|
|
|
|
PRInt32 aCurTotalProgress,
|
|
|
|
PRInt32 aMaxTotalProgress)
|
|
|
|
{
|
2002-05-16 20:57:37 +00:00
|
|
|
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
|
2002-03-13 06:08:56 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::OnLocationChange(nsIWebProgress* aWebProgress,
|
|
|
|
nsIRequest* aRequest,
|
|
|
|
nsIURI* location)
|
|
|
|
{
|
2002-05-16 20:57:37 +00:00
|
|
|
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
|
2002-03-13 06:08:56 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::OnStatusChange(nsIWebProgress* aWebProgress,
|
|
|
|
nsIRequest* aRequest,
|
|
|
|
nsresult aStatus,
|
|
|
|
const PRUnichar* aMessage)
|
|
|
|
{
|
2002-05-16 20:57:37 +00:00
|
|
|
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
|
2002-03-13 06:08:56 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress,
|
|
|
|
nsIRequest* aRequest,
|
2002-05-16 20:57:37 +00:00
|
|
|
PRUint32 state)
|
2002-03-13 06:08:56 +00:00
|
|
|
{
|
2002-05-16 20:57:37 +00:00
|
|
|
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
|
2002-03-13 06:08:56 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2002-08-17 05:42:55 +00:00
|
|
|
|
2008-10-09 23:31:40 +00:00
|
|
|
NS_IMETHODIMP_(PRInt32)
|
|
|
|
nsHTMLFormElement::IndexOfControl(nsIFormControl* aControl)
|
2001-05-30 11:26:21 +00:00
|
|
|
{
|
2008-10-09 23:31:40 +00:00
|
|
|
PRInt32 index = nsnull;
|
|
|
|
return mControls->IndexOfControl(aControl, &index) == NS_OK ? index : nsnull;
|
2001-05-30 11:26:21 +00:00
|
|
|
}
|
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::SetCurrentRadioButton(const nsAString& aName,
|
|
|
|
nsIDOMHTMLInputElement* aRadio)
|
|
|
|
{
|
2003-09-26 19:26:17 +00:00
|
|
|
NS_ENSURE_TRUE(mSelectedRadioButtons.Put(aName, aRadio),
|
|
|
|
NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2002-08-06 04:15:10 +00:00
|
|
|
return NS_OK;
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
1999-10-07 00:35:04 +00:00
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::GetCurrentRadioButton(const nsAString& aName,
|
|
|
|
nsIDOMHTMLInputElement** aRadio)
|
|
|
|
{
|
2004-05-18 20:58:12 +00:00
|
|
|
mSelectedRadioButtons.Get(aName, aRadio);
|
2003-09-26 19:26:17 +00:00
|
|
|
|
2004-07-05 01:31:30 +00:00
|
|
|
return NS_OK;
|
2005-04-04 13:43:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
|
|
|
|
PRInt32 *aPositionIndex,
|
|
|
|
PRInt32 *aItemsInGroup)
|
|
|
|
{
|
|
|
|
*aPositionIndex = 0;
|
|
|
|
*aItemsInGroup = 1;
|
|
|
|
|
|
|
|
nsAutoString name;
|
|
|
|
aRadio->GetName(name);
|
|
|
|
if (name.IsEmpty()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> itemWithName;
|
2008-10-09 23:31:40 +00:00
|
|
|
itemWithName = ResolveName(name);
|
|
|
|
NS_ENSURE_TRUE(itemWithName, NS_ERROR_FAILURE);
|
2009-10-30 01:49:11 +00:00
|
|
|
nsCOMPtr<nsINodeList> radioGroup(do_QueryInterface(itemWithName));
|
2005-04-04 13:43:43 +00:00
|
|
|
|
|
|
|
NS_ASSERTION(radioGroup, "No such radio group in this container");
|
|
|
|
if (!radioGroup) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> currentRadioNode(do_QueryInterface(aRadio));
|
|
|
|
NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button");
|
2009-10-30 01:49:11 +00:00
|
|
|
*aPositionIndex = radioGroup->IndexOf(currentRadioNode);
|
2005-04-04 13:43:43 +00:00
|
|
|
NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group");
|
|
|
|
PRUint32 itemsInGroup;
|
|
|
|
radioGroup->GetLength(&itemsInGroup);
|
|
|
|
*aItemsInGroup = itemsInGroup;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2004-07-05 01:31:30 +00:00
|
|
|
nsHTMLFormElement::GetNextRadioButton(const nsAString& aName,
|
|
|
|
const PRBool aPrevious,
|
|
|
|
nsIDOMHTMLInputElement* aFocusedRadio,
|
|
|
|
nsIDOMHTMLInputElement** aRadioOut)
|
|
|
|
{
|
|
|
|
// Return the radio button relative to the focused radio button.
|
|
|
|
// If no radio is focused, get the radio relative to the selected one.
|
|
|
|
*aRadioOut = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
|
|
|
|
if (aFocusedRadio) {
|
|
|
|
currentRadio = aFocusedRadio;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mSelectedRadioButtons.Get(aName, getter_AddRefs(currentRadio));
|
|
|
|
}
|
|
|
|
|
2008-10-09 23:31:40 +00:00
|
|
|
nsCOMPtr<nsISupports> itemWithName = ResolveName(aName);
|
2009-10-30 01:49:11 +00:00
|
|
|
nsCOMPtr<nsINodeList> radioGroup(do_QueryInterface(itemWithName));
|
2004-07-05 01:31:30 +00:00
|
|
|
|
|
|
|
if (!radioGroup) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> currentRadioNode(do_QueryInterface(currentRadio));
|
|
|
|
NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button");
|
2009-10-30 01:49:11 +00:00
|
|
|
PRInt32 index = radioGroup->IndexOf(currentRadioNode);
|
2004-07-05 01:31:30 +00:00
|
|
|
if (index < 0) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 numRadios;
|
|
|
|
radioGroup->GetLength(&numRadios);
|
2006-06-29 03:26:29 +00:00
|
|
|
PRBool disabled = PR_TRUE;
|
2004-07-05 01:31:30 +00:00
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> radio;
|
2006-06-29 03:26:29 +00:00
|
|
|
nsCOMPtr<nsIFormControl> formControl;
|
2004-07-05 01:31:30 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
if (aPrevious) {
|
|
|
|
if (--index < 0) {
|
|
|
|
index = numRadios -1;
|
|
|
|
}
|
|
|
|
}
|
2005-11-22 00:24:48 +00:00
|
|
|
else if (++index >= (PRInt32)numRadios) {
|
2004-07-05 01:31:30 +00:00
|
|
|
index = 0;
|
|
|
|
}
|
2009-10-30 01:49:11 +00:00
|
|
|
radio = do_QueryInterface(radioGroup->GetNodeAt(index));
|
2006-06-29 03:26:29 +00:00
|
|
|
if (!radio)
|
|
|
|
continue;
|
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
// XXXbz why is this formControl check needed, exactly?
|
2006-06-29 03:26:29 +00:00
|
|
|
formControl = do_QueryInterface(radio);
|
|
|
|
if (!formControl || formControl->GetType() != NS_FORM_INPUT_RADIO)
|
|
|
|
continue;
|
|
|
|
|
2004-07-05 01:31:30 +00:00
|
|
|
radio->GetDisabled(&disabled);
|
|
|
|
} while (disabled && radio != currentRadio);
|
|
|
|
|
|
|
|
NS_IF_ADDREF(*aRadioOut = radio);
|
2002-03-07 20:53:40 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::WalkRadioGroup(const nsAString& aName,
|
2006-02-08 05:56:13 +00:00
|
|
|
nsIRadioVisitor* aVisitor,
|
|
|
|
PRBool aFlushContent)
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
PRBool stopIterating = PR_FALSE;
|
|
|
|
|
|
|
|
if (aName.IsEmpty()) {
|
|
|
|
//
|
|
|
|
// XXX If the name is empty, it's not stored in the control list. There
|
|
|
|
// *must* be a more efficient way to do this.
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIFormControl> control;
|
2008-10-09 23:31:40 +00:00
|
|
|
PRUint32 len = GetElementCount();
|
2002-03-07 20:53:40 +00:00
|
|
|
for (PRUint32 i=0; i<len; i++) {
|
2009-10-30 01:49:11 +00:00
|
|
|
control = GetElementAt(i);
|
2002-12-18 23:38:09 +00:00
|
|
|
if (control->GetType() == NS_FORM_INPUT_RADIO) {
|
2002-08-06 04:32:57 +00:00
|
|
|
nsCOMPtr<nsIContent> controlContent(do_QueryInterface(control));
|
|
|
|
if (controlContent) {
|
2006-12-26 17:47:52 +00:00
|
|
|
if (controlContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
2005-10-28 11:25:24 +00:00
|
|
|
EmptyString(), eCaseMatters)) {
|
2002-03-07 20:53:40 +00:00
|
|
|
aVisitor->Visit(control, &stopIterating);
|
|
|
|
if (stopIterating) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// Get the control / list of controls from the form using form["name"]
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsISupports> item;
|
2008-10-09 23:31:40 +00:00
|
|
|
item = DoResolveName(aName, aFlushContent);
|
|
|
|
rv = item ? NS_OK : NS_ERROR_FAILURE;
|
2002-03-07 20:53:40 +00:00
|
|
|
|
|
|
|
if (item) {
|
|
|
|
//
|
|
|
|
// If it's just a lone radio button, then select it.
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(item));
|
|
|
|
if (formControl) {
|
2002-12-18 23:38:09 +00:00
|
|
|
if (formControl->GetType() == NS_FORM_INPUT_RADIO) {
|
2002-03-07 20:53:40 +00:00
|
|
|
aVisitor->Visit(formControl, &stopIterating);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsIDOMNodeList> nodeList(do_QueryInterface(item));
|
|
|
|
if (nodeList) {
|
|
|
|
PRUint32 length = 0;
|
|
|
|
nodeList->GetLength(&length);
|
|
|
|
for (PRUint32 i=0; i<length; i++) {
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nodeList->Item(i, getter_AddRefs(node));
|
|
|
|
nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(node));
|
|
|
|
if (formControl) {
|
2002-12-18 23:38:09 +00:00
|
|
|
if (formControl->GetType() == NS_FORM_INPUT_RADIO) {
|
2002-03-07 20:53:40 +00:00
|
|
|
aVisitor->Visit(formControl, &stopIterating);
|
|
|
|
if (stopIterating) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2002-07-20 23:09:24 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::AddToRadioGroup(const nsAString& aName,
|
|
|
|
nsIFormControl* aRadio)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLFormElement::RemoveFromRadioGroup(const nsAString& aName,
|
|
|
|
nsIFormControl* aRadio)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
//----------------------------------------------------------------------
|
2000-12-23 10:56:31 +00:00
|
|
|
// nsFormControlList implementation, this could go away if there were
|
|
|
|
// a lightweight collection implementation somewhere
|
1998-09-23 17:16:51 +00:00
|
|
|
|
2006-02-07 22:10:29 +00:00
|
|
|
nsFormControlList::nsFormControlList(nsHTMLFormElement* aForm) :
|
2006-09-18 04:53:54 +00:00
|
|
|
mForm(aForm),
|
|
|
|
// Initialize the elements list to have an initial capacity
|
|
|
|
// of 8 to reduce allocations on small forms.
|
|
|
|
mElements(8)
|
1998-09-23 17:16:51 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsFormControlList::~nsFormControlList()
|
|
|
|
{
|
1999-12-22 01:48:47 +00:00
|
|
|
mForm = nsnull;
|
1998-10-22 23:00:37 +00:00
|
|
|
Clear();
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
2003-09-26 19:26:17 +00:00
|
|
|
nsresult nsFormControlList::Init()
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(
|
|
|
|
mNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE),
|
|
|
|
NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-12-22 01:48:47 +00:00
|
|
|
void
|
2006-02-07 22:10:29 +00:00
|
|
|
nsFormControlList::DropFormReference()
|
1999-12-22 01:48:47 +00:00
|
|
|
{
|
2006-02-07 22:10:29 +00:00
|
|
|
mForm = nsnull;
|
|
|
|
Clear();
|
1999-12-22 01:48:47 +00:00
|
|
|
}
|
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
void
|
|
|
|
nsFormControlList::Clear()
|
|
|
|
{
|
2001-03-22 08:51:52 +00:00
|
|
|
// Null out childrens' pointer to me. No refcounting here
|
2002-08-17 05:42:55 +00:00
|
|
|
PRInt32 i;
|
2006-09-18 04:53:54 +00:00
|
|
|
for (i = mElements.Length()-1; i >= 0; i--) {
|
2008-09-11 03:21:33 +00:00
|
|
|
mElements[i]->ClearForm(PR_FALSE, PR_TRUE);
|
2001-03-22 08:51:52 +00:00
|
|
|
}
|
2000-06-23 14:12:24 +00:00
|
|
|
mElements.Clear();
|
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
for (i = mNotInElements.Length()-1; i >= 0; i--) {
|
2008-09-11 03:21:33 +00:00
|
|
|
mNotInElements[i]->ClearForm(PR_FALSE, PR_TRUE);
|
2001-03-22 08:51:52 +00:00
|
|
|
}
|
2002-08-17 05:42:55 +00:00
|
|
|
mNotInElements.Clear();
|
|
|
|
|
2003-09-26 19:26:17 +00:00
|
|
|
mNameLookupTable.Clear();
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
2006-02-07 22:10:29 +00:00
|
|
|
void
|
|
|
|
nsFormControlList::FlushPendingNotifications()
|
|
|
|
{
|
|
|
|
if (mForm) {
|
|
|
|
nsIDocument* doc = mForm->GetCurrentDoc();
|
|
|
|
if (doc) {
|
2006-02-08 05:56:13 +00:00
|
|
|
doc->FlushPendingNotifications(Flush_Content);
|
2006-02-07 22:10:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-09-23 17:16:51 +00:00
|
|
|
|
2008-10-10 15:04:34 +00:00
|
|
|
static PLDHashOperator
|
2007-03-08 11:17:16 +00:00
|
|
|
ControlTraverser(const nsAString& key, nsISupports* control, void* userArg)
|
|
|
|
{
|
|
|
|
nsCycleCollectionTraversalCallback *cb =
|
2007-07-08 07:08:04 +00:00
|
|
|
static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
2007-03-08 11:17:16 +00:00
|
|
|
|
|
|
|
cb->NoteXPCOMChild(control);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsFormControlList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormControlList)
|
|
|
|
tmp->Clear();
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormControlList)
|
|
|
|
tmp->mNameLookupTable.EnumerateRead(ControlTraverser, &cb);
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2010-01-12 13:08:43 +00:00
|
|
|
DOMCI_DATA(HTMLCollection, nsFormControlList)
|
|
|
|
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
// XPConnect interface list for nsFormControlList
|
2007-08-20 22:55:06 +00:00
|
|
|
NS_INTERFACE_TABLE_HEAD(nsFormControlList)
|
2010-03-17 15:09:01 +00:00
|
|
|
NS_INTERFACE_TABLE2(nsFormControlList,
|
2008-10-22 14:31:14 +00:00
|
|
|
nsIHTMLCollection,
|
2010-03-17 15:09:01 +00:00
|
|
|
nsIDOMHTMLCollection)
|
2007-08-20 22:55:06 +00:00
|
|
|
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsFormControlList)
|
2010-03-17 15:09:05 +00:00
|
|
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLCollection)
|
2000-12-23 10:56:31 +00:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
|
2008-10-22 14:31:14 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsFormControlList, nsIHTMLCollection)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsFormControlList, nsIHTMLCollection)
|
1998-09-23 17:16:51 +00:00
|
|
|
|
2000-12-23 10:56:31 +00:00
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
// nsIDOMHTMLCollection interface
|
2000-12-23 10:56:31 +00:00
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFormControlList::GetLength(PRUint32* aLength)
|
|
|
|
{
|
2006-02-07 22:10:29 +00:00
|
|
|
FlushPendingNotifications();
|
2006-09-18 04:53:54 +00:00
|
|
|
*aLength = mElements.Length();
|
1998-09-23 17:16:51 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFormControlList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
|
|
|
|
{
|
2008-10-22 14:31:14 +00:00
|
|
|
nsresult rv;
|
|
|
|
nsISupports* item = GetNodeAt(aIndex, &rv);
|
|
|
|
if (!item) {
|
|
|
|
*aReturn = nsnull;
|
2008-09-11 05:56:20 +00:00
|
|
|
|
2008-10-22 14:31:14 +00:00
|
|
|
return rv;
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
2004-05-18 20:58:12 +00:00
|
|
|
|
2008-10-22 14:31:14 +00:00
|
|
|
return CallQueryInterface(item, aReturn);
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2002-03-23 23:04:39 +00:00
|
|
|
nsFormControlList::NamedItem(const nsAString& aName,
|
2000-12-23 10:56:31 +00:00
|
|
|
nsIDOMNode** aReturn)
|
1998-09-23 17:16:51 +00:00
|
|
|
{
|
2006-02-07 22:10:29 +00:00
|
|
|
FlushPendingNotifications();
|
|
|
|
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
*aReturn = nsnull;
|
2000-06-01 22:55:19 +00:00
|
|
|
|
|
|
|
nsresult rv = NS_OK;
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
|
2003-09-26 19:26:17 +00:00
|
|
|
nsCOMPtr<nsISupports> supports;
|
|
|
|
|
2004-05-18 20:58:12 +00:00
|
|
|
if (!mNameLookupTable.Get(aName, getter_AddRefs(supports))) // key not found
|
2003-09-26 19:26:17 +00:00
|
|
|
return rv;
|
2000-04-19 07:49:07 +00:00
|
|
|
|
2000-06-01 22:55:19 +00:00
|
|
|
if (supports) {
|
|
|
|
// We found something, check if it's a node
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
CallQueryInterface(supports, aReturn);
|
2000-06-01 22:55:19 +00:00
|
|
|
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
if (!*aReturn) {
|
2000-06-01 22:55:19 +00:00
|
|
|
// If not, we check if it's a node list.
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
nsCOMPtr<nsIDOMNodeList> nodeList(do_QueryInterface(supports));
|
2006-03-30 18:40:56 +00:00
|
|
|
NS_ASSERTION(nodeList, "Huh, what's going one here?");
|
2000-06-01 22:55:19 +00:00
|
|
|
|
|
|
|
if (nodeList) {
|
|
|
|
// And since we're only asking for one node here, we return the first
|
|
|
|
// one from the list.
|
|
|
|
rv = nodeList->Item(0, aReturn);
|
|
|
|
}
|
|
|
|
}
|
2000-04-19 07:49:07 +00:00
|
|
|
}
|
|
|
|
|
2000-06-01 22:55:19 +00:00
|
|
|
return rv;
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
2008-10-31 21:40:35 +00:00
|
|
|
nsISupports*
|
2006-02-08 05:56:13 +00:00
|
|
|
nsFormControlList::NamedItemInternal(const nsAString& aName,
|
2008-10-31 21:40:35 +00:00
|
|
|
PRBool aFlushContent)
|
2006-02-08 05:56:13 +00:00
|
|
|
{
|
|
|
|
if (aFlushContent) {
|
|
|
|
FlushPendingNotifications();
|
|
|
|
}
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
|
2008-10-31 21:40:35 +00:00
|
|
|
return mNameLookupTable.GetWeak(aName);
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 16:46:42 +00:00
|
|
|
}
|
|
|
|
|
2000-04-19 07:49:07 +00:00
|
|
|
nsresult
|
2009-10-30 01:49:11 +00:00
|
|
|
nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
|
2002-03-23 23:04:39 +00:00
|
|
|
const nsAString& aName)
|
2000-04-19 07:49:07 +00:00
|
|
|
{
|
2002-02-20 05:51:28 +00:00
|
|
|
if (!ShouldBeInElements(aChild)) {
|
2001-03-22 08:51:52 +00:00
|
|
|
return NS_OK;
|
2000-06-01 22:55:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> supports;
|
2004-05-18 20:58:12 +00:00
|
|
|
mNameLookupTable.Get(aName, getter_AddRefs(supports));
|
2000-06-01 22:55:19 +00:00
|
|
|
|
|
|
|
if (!supports) {
|
|
|
|
// No entry found, add the form control
|
2009-10-30 01:49:11 +00:00
|
|
|
NS_ENSURE_TRUE( mNameLookupTable.Put(aName,
|
|
|
|
NS_ISUPPORTS_CAST(nsIContent*, aChild)),
|
|
|
|
NS_ERROR_FAILURE );
|
2000-06-01 22:55:19 +00:00
|
|
|
} else {
|
|
|
|
// Found something in the hash, check its type
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(supports));
|
|
|
|
|
|
|
|
if (content) {
|
2000-06-09 22:47:29 +00:00
|
|
|
// 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
|
2009-10-30 01:49:11 +00:00
|
|
|
if (content == aChild) {
|
2000-06-09 22:47:29 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-06-01 22:55:19 +00:00
|
|
|
// Found an element, create a list, add the element to the list and put
|
|
|
|
// the list in the hash
|
2002-06-28 01:30:09 +00:00
|
|
|
nsBaseContentList *list = new nsBaseContentList();
|
2000-06-01 22:55:19 +00:00
|
|
|
NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2009-07-24 13:33:20 +00:00
|
|
|
NS_ASSERTION(content->GetParent(), "Item in list without parent");
|
|
|
|
|
|
|
|
// Determine the ordering between the new and old element.
|
2009-10-30 01:49:11 +00:00
|
|
|
PRBool newFirst = nsContentUtils::PositionIsBefore(aChild, content);
|
2009-07-24 13:33:20 +00:00
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
list->AppendElement(newFirst ? aChild : content);
|
|
|
|
list->AppendElement(newFirst ? content : aChild);
|
2000-06-01 22:55:19 +00:00
|
|
|
|
|
|
|
|
2008-09-11 06:04:09 +00:00
|
|
|
nsCOMPtr<nsISupports> listSupports =
|
2008-09-11 06:13:34 +00:00
|
|
|
do_QueryInterface(static_cast<nsIDOMNodeList*>(list));
|
2001-03-22 08:51:52 +00:00
|
|
|
|
2000-06-01 22:55:19 +00:00
|
|
|
// Replace the element with the list.
|
2003-09-26 19:26:17 +00:00
|
|
|
NS_ENSURE_TRUE(mNameLookupTable.Put(aName, listSupports),
|
|
|
|
NS_ERROR_FAILURE);
|
2000-06-01 22:55:19 +00:00
|
|
|
} else {
|
|
|
|
// There's already a list in the hash, add the child to the list
|
|
|
|
nsCOMPtr<nsIDOMNodeList> nodeList(do_QueryInterface(supports));
|
|
|
|
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
// Upcast, uggly, but it works!
|
2007-07-08 07:08:04 +00:00
|
|
|
nsBaseContentList *list = static_cast<nsBaseContentList *>
|
|
|
|
((nsIDOMNodeList *)nodeList.get());
|
2000-06-01 22:55:19 +00:00
|
|
|
|
2009-07-24 13:33:20 +00:00
|
|
|
NS_ASSERTION(list->Length() > 1,
|
|
|
|
"List should have been converted back to a single element");
|
2009-11-19 20:58:46 +00:00
|
|
|
|
|
|
|
// Fast-path appends; this check is ok even if the child is
|
|
|
|
// already in the list, since if it tests true the child would
|
|
|
|
// have come at the end of the list, and the PositionIsBefore
|
|
|
|
// will test false.
|
2009-10-30 01:49:11 +00:00
|
|
|
if(nsContentUtils::PositionIsBefore(list->GetNodeAt(list->Length() - 1), aChild)) {
|
2009-11-19 20:58:46 +00:00
|
|
|
list->AppendElement(aChild);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a control has a name equal to its id, it could be in the
|
|
|
|
// list already.
|
|
|
|
if (list->IndexOf(aChild) != -1) {
|
|
|
|
return NS_OK;
|
2000-06-09 22:47:29 +00:00
|
|
|
}
|
2009-07-24 13:33:20 +00:00
|
|
|
|
|
|
|
// first is the first possible insertion index, last is the last possible
|
|
|
|
// insertion index
|
|
|
|
PRUint32 first = 0;
|
|
|
|
PRUint32 last = list->Length() - 1;
|
|
|
|
PRUint32 mid;
|
|
|
|
|
2009-11-19 20:58:46 +00:00
|
|
|
// Stop when there is only one index in our range
|
2009-07-24 13:33:20 +00:00
|
|
|
while (last != first) {
|
2009-11-19 20:58:46 +00:00
|
|
|
mid = (first + last) / 2;
|
2009-07-24 13:33:20 +00:00
|
|
|
|
2009-11-19 20:58:46 +00:00
|
|
|
if (nsContentUtils::PositionIsBefore(aChild, list->GetNodeAt(mid)))
|
|
|
|
last = mid;
|
|
|
|
else
|
|
|
|
first = mid + 1;
|
|
|
|
}
|
2009-07-24 13:33:20 +00:00
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
list->InsertElementAt(aChild, first);
|
2000-06-01 22:55:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-19 07:49:07 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-05-30 11:26:21 +00:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsFormControlList::IndexOfControl(nsIFormControl* aControl,
|
|
|
|
PRInt32* aIndex)
|
|
|
|
{
|
2006-02-07 22:10:29 +00:00
|
|
|
// Note -- not a DOM method; callers should handle flushing themselves
|
|
|
|
|
2001-05-30 11:26:21 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aIndex);
|
|
|
|
|
|
|
|
*aIndex = mElements.IndexOf(aControl);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-04-19 07:49:07 +00:00
|
|
|
|
|
|
|
nsresult
|
2009-10-30 01:49:11 +00:00
|
|
|
nsFormControlList::RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
|
2002-03-23 23:04:39 +00:00
|
|
|
const nsAString& aName)
|
2000-05-30 02:45:55 +00:00
|
|
|
{
|
2002-02-20 05:51:28 +00:00
|
|
|
if (!ShouldBeInElements(aChild)) {
|
2001-03-22 08:51:52 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2003-09-26 19:26:17 +00:00
|
|
|
nsCOMPtr<nsISupports> supports;
|
2000-06-01 22:55:19 +00:00
|
|
|
|
2004-05-18 20:58:12 +00:00
|
|
|
if (!mNameLookupTable.Get(aName, getter_AddRefs(supports)))
|
2001-03-22 08:51:52 +00:00
|
|
|
return NS_OK;
|
2000-06-01 22:55:19 +00:00
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
nsCOMPtr<nsIFormControl> fctrl(do_QueryInterface(supports));
|
2000-06-01 22:55:19 +00:00
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
if (fctrl) {
|
2003-11-25 02:34:05 +00:00
|
|
|
// Single element in the hash, just remove it if it's the one
|
|
|
|
// we're trying to remove...
|
|
|
|
if (fctrl == aChild) {
|
|
|
|
mNameLookupTable.Remove(aName);
|
|
|
|
}
|
2000-06-01 22:55:19 +00:00
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-06-01 22:55:19 +00:00
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
nsCOMPtr<nsIDOMNodeList> nodeList(do_QueryInterface(supports));
|
|
|
|
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
|
2000-06-01 22:55:19 +00:00
|
|
|
|
2001-03-22 08:51:52 +00:00
|
|
|
// Upcast, uggly, but it works!
|
2007-07-08 07:08:04 +00:00
|
|
|
nsBaseContentList *list = static_cast<nsBaseContentList *>
|
|
|
|
((nsIDOMNodeList *)nodeList.get());
|
2000-06-01 22:55:19 +00:00
|
|
|
|
2009-10-30 01:49:11 +00:00
|
|
|
list->RemoveElement(aChild);
|
2001-03-22 08:51:52 +00:00
|
|
|
|
|
|
|
PRUint32 length = 0;
|
|
|
|
list->GetLength(&length);
|
|
|
|
|
|
|
|
if (!length) {
|
|
|
|
// If the list is empty we remove if from our hash, this shouldn't
|
|
|
|
// happen tho
|
2003-09-26 19:26:17 +00:00
|
|
|
mNameLookupTable.Remove(aName);
|
2001-03-22 08:51:52 +00:00
|
|
|
} else if (length == 1) {
|
|
|
|
// Only one element left, replace the list in the hash with the
|
|
|
|
// single element.
|
2009-10-30 01:49:11 +00:00
|
|
|
nsIContent* node = list->GetNodeAt(0);
|
2001-03-22 08:51:52 +00:00
|
|
|
if (node) {
|
2009-10-30 01:49:11 +00:00
|
|
|
NS_ENSURE_TRUE(mNameLookupTable.Put(aName, node),NS_ERROR_FAILURE);
|
2000-06-01 22:55:19 +00:00
|
|
|
}
|
2000-04-19 07:49:07 +00:00
|
|
|
}
|
2001-03-22 08:51:52 +00:00
|
|
|
|
2000-04-19 07:49:07 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
nsresult
|
2009-10-30 01:49:11 +00:00
|
|
|
nsFormControlList::GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const
|
2006-09-18 04:53:54 +00:00
|
|
|
{
|
2007-07-26 04:26:07 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
AssertDocumentOrder(mElements, mForm);
|
|
|
|
AssertDocumentOrder(mNotInElements, mForm);
|
|
|
|
#endif
|
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
aControls.Clear();
|
|
|
|
|
|
|
|
// Merge the elements list and the not in elements list. Both lists are
|
|
|
|
// already sorted.
|
|
|
|
PRUint32 elementsLen = mElements.Length();
|
|
|
|
PRUint32 notInElementsLen = mNotInElements.Length();
|
|
|
|
aControls.SetCapacity(elementsLen + notInElementsLen);
|
|
|
|
|
|
|
|
PRUint32 elementsIdx = 0;
|
|
|
|
PRUint32 notInElementsIdx = 0;
|
|
|
|
|
|
|
|
while (elementsIdx < elementsLen || notInElementsIdx < notInElementsLen) {
|
|
|
|
// Check whether we're done with mElements
|
|
|
|
if (elementsIdx == elementsLen) {
|
|
|
|
NS_ASSERTION(notInElementsIdx < notInElementsLen,
|
|
|
|
"Should have remaining not-in-elements");
|
|
|
|
// Append the remaining mNotInElements elements
|
|
|
|
if (!aControls.AppendElements(mNotInElements.Elements() +
|
|
|
|
notInElementsIdx,
|
|
|
|
notInElementsLen -
|
|
|
|
notInElementsIdx)) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2002-08-17 05:42:55 +00:00
|
|
|
}
|
2006-09-18 04:53:54 +00:00
|
|
|
break;
|
2002-08-17 05:42:55 +00:00
|
|
|
}
|
2006-09-18 04:53:54 +00:00
|
|
|
// Check whether we're done with mNotInElements
|
|
|
|
if (notInElementsIdx == notInElementsLen) {
|
|
|
|
NS_ASSERTION(elementsIdx < elementsLen,
|
|
|
|
"Should have remaining in-elements");
|
|
|
|
// Append the remaining mElements elements
|
|
|
|
if (!aControls.AppendElements(mElements.Elements() +
|
|
|
|
elementsIdx,
|
|
|
|
elementsLen -
|
|
|
|
elementsIdx)) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2002-08-17 05:42:55 +00:00
|
|
|
}
|
2006-09-18 04:53:54 +00:00
|
|
|
break;
|
2002-08-17 05:42:55 +00:00
|
|
|
}
|
2006-09-18 04:53:54 +00:00
|
|
|
// Both lists have elements left.
|
|
|
|
NS_ASSERTION(mElements[elementsIdx] &&
|
|
|
|
mNotInElements[notInElementsIdx],
|
|
|
|
"Should have remaining elements");
|
|
|
|
// Determine which of the two elements should be ordered
|
|
|
|
// first and add it to the end of the list.
|
2009-10-30 01:49:11 +00:00
|
|
|
nsGenericHTMLFormElement* elementToAdd;
|
2006-09-18 04:53:54 +00:00
|
|
|
if (CompareFormControlPosition(mElements[elementsIdx],
|
2007-07-26 04:26:07 +00:00
|
|
|
mNotInElements[notInElementsIdx],
|
|
|
|
mForm) < 0) {
|
2006-09-18 04:53:54 +00:00
|
|
|
elementToAdd = mElements[elementsIdx];
|
|
|
|
++elementsIdx;
|
2002-08-17 05:42:55 +00:00
|
|
|
} else {
|
2006-09-18 04:53:54 +00:00
|
|
|
elementToAdd = mNotInElements[notInElementsIdx];
|
|
|
|
++notInElementsIdx;
|
|
|
|
}
|
|
|
|
// Add the first element to the list.
|
|
|
|
if (!aControls.AppendElement(elementToAdd)) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2002-08-17 05:42:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-18 04:53:54 +00:00
|
|
|
NS_ASSERTION(aControls.Length() == elementsLen + notInElementsLen,
|
|
|
|
"Not all form controls were added to the sorted list");
|
|
|
|
#ifdef DEBUG
|
2007-07-26 04:26:07 +00:00
|
|
|
AssertDocumentOrder(aControls, mForm);
|
2006-09-18 04:53:54 +00:00
|
|
|
#endif
|
2007-07-26 04:26:07 +00:00
|
|
|
|
2002-08-17 05:42:55 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|