2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
|
|
* Mats Palmgren <mats.palmgren@bredband.net>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2007-08-28 00:09:32 -07:00
|
|
|
|
2011-10-10 22:50:08 -07:00
|
|
|
#include "mozilla/Util.h"
|
|
|
|
|
2007-08-28 00:09:32 -07:00
|
|
|
#include "nsHTMLSelectElement.h"
|
2011-05-28 00:43:53 -07:00
|
|
|
|
2010-05-09 11:32:57 -07:00
|
|
|
#include "nsHTMLOptionElement.h"
|
2007-05-14 02:11:38 -07:00
|
|
|
#include "nsIDOMEventTarget.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsContentCreatorFunctions.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsStyleConsts.h"
|
|
|
|
#include "nsLayoutUtils.h"
|
|
|
|
#include "nsMappedAttributes.h"
|
|
|
|
#include "nsIForm.h"
|
2010-05-26 05:49:38 -07:00
|
|
|
#include "nsFormSubmission.h"
|
2010-02-24 21:58:16 -08:00
|
|
|
#include "nsIFormProcessor.h"
|
2010-06-08 23:45:32 -07:00
|
|
|
#include "nsContentCreatorFunctions.h"
|
2007-08-28 00:09:32 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMHTMLOptGroupElement.h"
|
2011-04-21 10:35:52 -07:00
|
|
|
#include "nsEventStates.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsGUIEvent.h"
|
|
|
|
#include "nsIPrivateDOMEvent.h"
|
|
|
|
|
|
|
|
// Notify/query select frame for selectedIndex
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIFormControlFrame.h"
|
|
|
|
#include "nsIComboboxControlFrame.h"
|
|
|
|
#include "nsIListControlFrame.h"
|
|
|
|
#include "nsIFrame.h"
|
|
|
|
|
|
|
|
#include "nsDOMError.h"
|
2010-02-24 21:58:16 -08:00
|
|
|
#include "nsServiceManagerUtils.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsRuleData.h"
|
|
|
|
#include "nsEventDispatcher.h"
|
2010-05-09 11:32:57 -07:00
|
|
|
#include "mozilla/dom/Element.h"
|
2010-09-08 10:43:28 -07:00
|
|
|
#include "mozAutoDocUpdate.h"
|
2011-08-20 06:53:34 -07:00
|
|
|
#include "dombindings.h"
|
2010-05-09 11:32:57 -07:00
|
|
|
|
2011-10-10 22:50:08 -07:00
|
|
|
using namespace mozilla;
|
2010-05-09 11:32:57 -07:00
|
|
|
using namespace mozilla::dom;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-12-12 11:25:22 -08:00
|
|
|
NS_IMPL_ISUPPORTS1(nsSelectState, nsSelectState)
|
|
|
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsSelectState, NS_SELECT_STATE_IID)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-08-28 00:09:32 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsSafeOptionListMutation
|
|
|
|
//
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-08-28 00:09:32 -07:00
|
|
|
nsSafeOptionListMutation::nsSafeOptionListMutation(nsIContent* aSelect,
|
|
|
|
nsIContent* aParent,
|
|
|
|
nsIContent* aKid,
|
2010-11-16 15:41:19 -08:00
|
|
|
PRUint32 aIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2011-04-12 05:32:00 -07:00
|
|
|
: mSelect(nsHTMLSelectElement::FromContent(aSelect))
|
2011-10-17 07:59:28 -07:00
|
|
|
, mTopLevelMutation(false)
|
|
|
|
, mNeedsRebuild(false)
|
2007-08-28 00:09:32 -07:00
|
|
|
{
|
2011-04-12 05:32:00 -07:00
|
|
|
if (mSelect) {
|
|
|
|
mTopLevelMutation = !mSelect->mMutating;
|
2007-08-28 00:09:32 -07:00
|
|
|
if (mTopLevelMutation) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mSelect->mMutating = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2007-08-28 00:09:32 -07:00
|
|
|
// This is very unfortunate, but to handle mutation events properly,
|
|
|
|
// option list must be up-to-date before inserting or removing options.
|
|
|
|
// Fortunately this is called only if mutation event listener
|
|
|
|
// adds or removes options.
|
2011-04-12 05:32:00 -07:00
|
|
|
mSelect->RebuildOptionsArray(aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-08-28 00:09:32 -07:00
|
|
|
nsresult rv;
|
|
|
|
if (aKid) {
|
2010-11-16 15:41:19 -08:00
|
|
|
rv = mSelect->WillAddOptions(aKid, aParent, aIndex, aNotify);
|
2007-08-28 00:09:32 -07:00
|
|
|
} else {
|
2010-11-16 15:41:19 -08:00
|
|
|
rv = mSelect->WillRemoveOptions(aParent, aIndex, aNotify);
|
2007-08-28 00:09:32 -07:00
|
|
|
}
|
|
|
|
mNeedsRebuild = NS_FAILED(rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-08-28 00:09:32 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-08-28 00:09:32 -07:00
|
|
|
nsSafeOptionListMutation::~nsSafeOptionListMutation()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-08-28 00:09:32 -07:00
|
|
|
if (mSelect) {
|
|
|
|
if (mNeedsRebuild || (mTopLevelMutation && mGuard.Mutated(1))) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mSelect->RebuildOptionsArray(true);
|
2007-08-28 00:09:32 -07:00
|
|
|
}
|
|
|
|
if (mTopLevelMutation) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mSelect->mMutating = false;
|
2007-08-28 00:09:32 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef DEBUG
|
2011-04-12 05:32:00 -07:00
|
|
|
mSelect->VerifyOptionsArray();
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2007-08-28 00:09:32 -07:00
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsHTMLSelectElement
|
|
|
|
//
|
|
|
|
|
|
|
|
// construction, destruction
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Select)
|
|
|
|
|
2010-07-23 02:49:57 -07:00
|
|
|
nsHTMLSelectElement::nsHTMLSelectElement(already_AddRefed<nsINodeInfo> aNodeInfo,
|
2010-10-25 05:17:38 -07:00
|
|
|
FromParser aFromParser)
|
2007-03-22 10:30:00 -07:00
|
|
|
: nsGenericHTMLFormElement(aNodeInfo),
|
|
|
|
mOptions(new nsHTMLOptionCollection(this)),
|
|
|
|
mIsDoneAddingChildren(!aFromParser),
|
2011-10-17 07:59:28 -07:00
|
|
|
mDisabledChanged(false),
|
|
|
|
mMutating(false),
|
2010-10-25 05:17:38 -07:00
|
|
|
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
|
2011-10-17 07:59:28 -07:00
|
|
|
mSelectionHasChanged(false),
|
|
|
|
mDefaultSelectionSet(false),
|
|
|
|
mCanShowInvalidUI(true),
|
|
|
|
mCanShowValidUI(true),
|
2007-03-22 10:30:00 -07:00
|
|
|
mNonOptionChildren(0),
|
|
|
|
mOptGroupCount(0),
|
|
|
|
mSelectedIndex(-1)
|
|
|
|
{
|
|
|
|
// DoneAddingChildren() will be called later if it's from the parser,
|
|
|
|
// otherwise it is
|
2011-05-31 18:46:57 -07:00
|
|
|
|
|
|
|
// Set up our default state: enabled, optional, and valid.
|
|
|
|
AddStatesSilently(NS_EVENT_STATE_ENABLED |
|
|
|
|
NS_EVENT_STATE_OPTIONAL |
|
|
|
|
NS_EVENT_STATE_VALID);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsHTMLSelectElement::~nsHTMLSelectElement()
|
|
|
|
{
|
2011-10-15 00:26:41 -07:00
|
|
|
mOptions->DropReference();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// ISupports
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLSelectElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLSelectElement,
|
|
|
|
nsGenericHTMLFormElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mOptions,
|
|
|
|
nsIDOMHTMLCollection)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsHTMLSelectElement, nsGenericElement)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsHTMLSelectElement, nsGenericElement)
|
|
|
|
|
|
|
|
|
2010-07-23 02:49:57 -07:00
|
|
|
DOMCI_NODE_DATA(HTMLSelectElement, nsHTMLSelectElement)
|
2010-01-12 05:08:43 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// QueryInterface implementation for nsHTMLSelectElement
|
2008-11-03 02:31:47 -08:00
|
|
|
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLSelectElement)
|
2011-04-12 05:32:01 -07:00
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE2(nsHTMLSelectElement,
|
2008-11-03 02:31:47 -08:00
|
|
|
nsIDOMHTMLSelectElement,
|
2010-08-21 11:52:49 -07:00
|
|
|
nsIConstraintValidation)
|
2008-11-03 02:31:47 -08:00
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLSelectElement,
|
|
|
|
nsGenericHTMLFormElement)
|
2007-08-20 15:55:06 -07:00
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLSelectElement)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
|
|
|
|
// nsIDOMHTMLSelectElement
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ELEMENT_CLONE(nsHTMLSelectElement)
|
|
|
|
|
2010-08-21 11:52:49 -07:00
|
|
|
// nsIConstraintValidation
|
|
|
|
NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(nsHTMLSelectElement)
|
2010-08-21 10:52:57 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::SetCustomValidity(const nsAString& aError)
|
|
|
|
{
|
2010-08-21 11:52:49 -07:00
|
|
|
nsIConstraintValidation::SetCustomValidity(aError);
|
2010-08-21 10:52:57 -07:00
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateState(true);
|
2010-08-21 10:52:57 -07:00
|
|
|
|
2010-08-21 11:51:38 -07:00
|
|
|
return NS_OK;
|
2010-08-21 10:52:57 -07:00
|
|
|
}
|
2010-08-18 11:28:08 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
|
|
|
{
|
|
|
|
return nsGenericHTMLFormElement::GetForm(aForm);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::InsertChildAt(nsIContent* aKid,
|
|
|
|
PRUint32 aIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-11-16 15:41:19 -08:00
|
|
|
nsSafeOptionListMutation safeMutation(this, this, aKid, aIndex, aNotify);
|
2007-08-28 00:09:32 -07:00
|
|
|
nsresult rv = nsGenericHTMLFormElement::InsertChildAt(aKid, aIndex, aNotify);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
safeMutation.MutationFailed();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-08-28 00:09:32 -07:00
|
|
|
return rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-11-16 15:41:19 -08:00
|
|
|
nsSafeOptionListMutation safeMutation(this, this, nsnull, aIndex, aNotify);
|
2011-05-25 10:58:23 -07:00
|
|
|
nsresult rv = nsGenericHTMLFormElement::RemoveChildAt(aIndex, aNotify);
|
2007-08-28 00:09:32 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
safeMutation.MutationFailed();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-08-28 00:09:32 -07:00
|
|
|
return rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SelectElement methods
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,
|
|
|
|
PRInt32 aListIndex,
|
2010-11-16 15:41:19 -08:00
|
|
|
PRInt32 aDepth,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRInt32 insertIndex = aListIndex;
|
|
|
|
nsresult rv = InsertOptionsIntoListRecurse(aOptions, &insertIndex, aDepth);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Deal with the selected list
|
|
|
|
if (insertIndex - aListIndex) {
|
|
|
|
// Fix the currently selected index
|
|
|
|
if (aListIndex <= mSelectedIndex) {
|
|
|
|
mSelectedIndex += (insertIndex - aListIndex);
|
2011-10-17 07:59:28 -07:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the frame stuff for notification. No need to flush here
|
|
|
|
// since if there's no frame for the select yet the select will
|
|
|
|
// get into the right state once it's created.
|
2009-02-17 19:27:25 -08:00
|
|
|
nsISelectControlFrame* selectFrame = nsnull;
|
|
|
|
nsWeakFrame weakSelectFrame;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool didGetFrame = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Actually select the options if the added options warrant it
|
|
|
|
nsCOMPtr<nsIDOMNode> optionNode;
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> option;
|
|
|
|
for (PRInt32 i=aListIndex;i<insertIndex;i++) {
|
|
|
|
// Notify the frame that the option is added
|
2009-02-17 19:27:25 -08:00
|
|
|
if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
|
|
|
|
selectFrame = GetSelectFrame();
|
|
|
|
weakSelectFrame = do_QueryFrame(selectFrame);
|
2011-10-17 07:59:28 -07:00
|
|
|
didGetFrame = true;
|
2009-02-17 19:27:25 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (selectFrame) {
|
2009-02-17 19:27:25 -08:00
|
|
|
selectFrame->AddOption(i);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Item(i, getter_AddRefs(optionNode));
|
|
|
|
option = do_QueryInterface(optionNode);
|
|
|
|
if (option) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool selected;
|
2007-03-22 10:30:00 -07:00
|
|
|
option->GetSelected(&selected);
|
|
|
|
if (selected) {
|
|
|
|
// Clear all other options
|
2010-10-08 05:15:00 -07:00
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
SetOptionsSelectedByIndex(i, i, true, true, true, true, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// This is sort of a hack ... we need to notify that the option was
|
|
|
|
// set and change selectedIndex even though we didn't really change
|
|
|
|
// its value.
|
2011-10-17 07:59:28 -07:00
|
|
|
OnOptionSelected(selectFrame, i, true, false, false);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-16 15:41:19 -08:00
|
|
|
CheckSelectSomething(aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
|
|
|
|
PRInt32 aListIndex,
|
2010-11-16 15:41:19 -08:00
|
|
|
PRInt32 aDepth,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRInt32 numRemoved = 0;
|
|
|
|
nsresult rv = RemoveOptionsFromListRecurse(aOptions, aListIndex, &numRemoved,
|
|
|
|
aDepth);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (numRemoved) {
|
|
|
|
// Tell the widget we removed the options
|
|
|
|
nsISelectControlFrame* selectFrame = GetSelectFrame();
|
|
|
|
if (selectFrame) {
|
2009-02-17 19:27:25 -08:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2007-03-22 10:30:00 -07:00
|
|
|
for (int i = aListIndex; i < aListIndex + numRemoved; ++i) {
|
2009-02-17 19:27:25 -08:00
|
|
|
selectFrame->RemoveOption(i);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fix the selected index
|
|
|
|
if (aListIndex <= mSelectedIndex) {
|
|
|
|
if (mSelectedIndex < (aListIndex+numRemoved)) {
|
|
|
|
// aListIndex <= mSelectedIndex < aListIndex+numRemoved
|
|
|
|
// Find a new selected index if it was one of the ones removed.
|
2010-11-24 02:09:01 -08:00
|
|
|
FindSelectedIndex(aListIndex, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
|
|
|
// Shift the selected index if something in front of it was removed
|
|
|
|
// aListIndex+numRemoved <= mSelectedIndex
|
|
|
|
mSelectedIndex -= numRemoved;
|
2011-10-17 07:59:28 -07:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select something in case we removed the selected option on a
|
|
|
|
// single select
|
2010-11-16 15:41:19 -08:00
|
|
|
if (!CheckSelectSomething(aNotify) && mSelectedIndex == -1) {
|
|
|
|
// Update the validity state in case of we've just removed the last
|
|
|
|
// option.
|
|
|
|
UpdateValueMissingValidityState();
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateState(aNotify);
|
2010-11-16 15:41:19 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the document is such that recursing over these options gets us
|
|
|
|
// deeper than four levels, there is something terribly wrong with the
|
|
|
|
// world.
|
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::InsertOptionsIntoListRecurse(nsIContent* aOptions,
|
|
|
|
PRInt32* aInsertIndex,
|
|
|
|
PRInt32 aDepth)
|
|
|
|
{
|
|
|
|
// We *assume* here that someone's brain has not gone horribly
|
|
|
|
// wrong by putting <option> inside of <option>. I'm sorry, I'm
|
|
|
|
// just not going to look for an option inside of an option.
|
|
|
|
// Sue me.
|
|
|
|
|
2010-05-09 11:32:57 -07:00
|
|
|
nsHTMLOptionElement *optElement = nsHTMLOptionElement::FromContent(aOptions);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (optElement) {
|
|
|
|
nsresult rv = mOptions->InsertOptionAt(optElement, *aInsertIndex);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
(*aInsertIndex)++;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it's at the top level, then we just found out there are non-options
|
|
|
|
// at the top level, which will throw off the insert count
|
|
|
|
if (aDepth == 0) {
|
|
|
|
mNonOptionChildren++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recurse down into optgroups
|
2011-08-08 08:14:33 -07:00
|
|
|
if (aOptions->IsHTML(nsGkAtoms::optgroup)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
mOptGroupCount++;
|
|
|
|
|
2011-09-27 00:54:58 -07:00
|
|
|
for (nsIContent* child = aOptions->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
|
|
|
nsresult rv = InsertOptionsIntoListRecurse(child,
|
2007-03-22 10:30:00 -07:00
|
|
|
aInsertIndex, aDepth+1);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the document is such that recursing over these options gets us deeper than
|
|
|
|
// four levels, there is something terribly wrong with the world.
|
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::RemoveOptionsFromListRecurse(nsIContent* aOptions,
|
|
|
|
PRInt32 aRemoveIndex,
|
|
|
|
PRInt32* aNumRemoved,
|
|
|
|
PRInt32 aDepth)
|
|
|
|
{
|
|
|
|
// We *assume* here that someone's brain has not gone horribly
|
|
|
|
// wrong by putting <option> inside of <option>. I'm sorry, I'm
|
|
|
|
// just not going to look for an option inside of an option.
|
|
|
|
// Sue me.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> optElement(do_QueryInterface(aOptions));
|
|
|
|
if (optElement) {
|
|
|
|
if (mOptions->ItemAsOption(aRemoveIndex) != optElement) {
|
|
|
|
NS_ERROR("wrong option at index");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
mOptions->RemoveOptionAt(aRemoveIndex);
|
|
|
|
(*aNumRemoved)++;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Yay, one less artifact at the top level.
|
|
|
|
if (aDepth == 0) {
|
|
|
|
mNonOptionChildren--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recurse down deeper for options
|
2011-08-08 08:14:33 -07:00
|
|
|
if (mOptGroupCount && aOptions->IsHTML(nsGkAtoms::optgroup)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
mOptGroupCount--;
|
|
|
|
|
2011-09-27 00:54:58 -07:00
|
|
|
for (nsIContent* child = aOptions->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
|
|
|
|
|
|
|
nsresult rv = RemoveOptionsFromListRecurse(child,
|
2007-03-22 10:30:00 -07:00
|
|
|
aRemoveIndex,
|
|
|
|
aNumRemoved,
|
|
|
|
aDepth + 1);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXXldb Doing the processing before the content nodes have been added
|
|
|
|
// to the document (as the name of this function seems to require, and
|
|
|
|
// as the callers do), is highly unusual. Passing around unparented
|
|
|
|
// content to other parts of the app can make those things think the
|
|
|
|
// options are the root content node.
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::WillAddOptions(nsIContent* aOptions,
|
|
|
|
nsIContent* aParent,
|
2010-11-16 15:41:19 -08:00
|
|
|
PRInt32 aContentIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRInt32 level = GetContentDepth(aParent);
|
|
|
|
if (level == -1) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the index where the options will be inserted
|
|
|
|
PRInt32 ind = -1;
|
|
|
|
if (!mNonOptionChildren) {
|
|
|
|
// If there are no artifacts, aContentIndex == ind
|
|
|
|
ind = aContentIndex;
|
|
|
|
} else {
|
|
|
|
// If there are artifacts, we have to get the index of the option the
|
|
|
|
// hard way
|
|
|
|
PRInt32 children = aParent->GetChildCount();
|
|
|
|
|
|
|
|
if (aContentIndex >= children) {
|
|
|
|
// If the content insert is after the end of the parent, then we want to get
|
|
|
|
// the next index *after* the parent and insert there.
|
|
|
|
ind = GetOptionIndexAfter(aParent);
|
|
|
|
} else {
|
|
|
|
// If the content insert is somewhere in the middle of the container, then
|
|
|
|
// we want to get the option currently at the index and insert in front of
|
|
|
|
// that.
|
|
|
|
nsIContent *currentKid = aParent->GetChildAt(aContentIndex);
|
|
|
|
NS_ASSERTION(currentKid, "Child not found!");
|
|
|
|
if (currentKid) {
|
|
|
|
ind = GetOptionIndexAt(currentKid);
|
|
|
|
} else {
|
|
|
|
ind = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-16 15:41:19 -08:00
|
|
|
return InsertOptionsIntoList(aOptions, ind, level, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::WillRemoveOptions(nsIContent* aParent,
|
2010-11-16 15:41:19 -08:00
|
|
|
PRInt32 aContentIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRInt32 level = GetContentDepth(aParent);
|
|
|
|
NS_ASSERTION(level >= 0, "getting notified by unexpected content");
|
|
|
|
if (level == -1) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the index where the options will be removed
|
|
|
|
nsIContent *currentKid = aParent->GetChildAt(aContentIndex);
|
|
|
|
if (currentKid) {
|
|
|
|
PRInt32 ind;
|
|
|
|
if (!mNonOptionChildren) {
|
|
|
|
// If there are no artifacts, aContentIndex == ind
|
|
|
|
ind = aContentIndex;
|
|
|
|
} else {
|
|
|
|
// If there are artifacts, we have to get the index of the option the
|
|
|
|
// hard way
|
|
|
|
ind = GetFirstOptionIndex(currentKid);
|
|
|
|
}
|
|
|
|
if (ind != -1) {
|
2010-11-16 15:41:19 -08:00
|
|
|
nsresult rv = RemoveOptionsFromList(currentKid, ind, level, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsHTMLSelectElement::GetContentDepth(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
nsIContent* content = aContent;
|
|
|
|
|
|
|
|
PRInt32 retval = 0;
|
|
|
|
while (content != this) {
|
|
|
|
retval++;
|
|
|
|
content = content->GetParent();
|
|
|
|
if (!content) {
|
|
|
|
retval = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsHTMLSelectElement::GetOptionIndexAt(nsIContent* aOptions)
|
|
|
|
{
|
|
|
|
// Search this node and below.
|
|
|
|
// If not found, find the first one *after* this node.
|
|
|
|
PRInt32 retval = GetFirstOptionIndex(aOptions);
|
|
|
|
if (retval == -1) {
|
|
|
|
retval = GetOptionIndexAfter(aOptions);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsHTMLSelectElement::GetOptionIndexAfter(nsIContent* aOptions)
|
|
|
|
{
|
|
|
|
// - If this is the select, the next option is the last.
|
|
|
|
// - If not, search all the options after aOptions and up to the last option
|
|
|
|
// in the parent.
|
|
|
|
// - If it's not there, search for the first option after the parent.
|
|
|
|
if (aOptions == this) {
|
|
|
|
PRUint32 len;
|
|
|
|
GetLength(&len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 retval = -1;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> parent = aOptions->GetParent();
|
|
|
|
|
|
|
|
if (parent) {
|
|
|
|
PRInt32 index = parent->IndexOf(aOptions);
|
|
|
|
PRInt32 count = parent->GetChildCount();
|
|
|
|
|
|
|
|
retval = GetFirstChildOptionIndex(parent, index+1, count);
|
|
|
|
|
|
|
|
if (retval == -1) {
|
|
|
|
retval = GetOptionIndexAfter(parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsHTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions)
|
|
|
|
{
|
|
|
|
PRInt32 listIndex = -1;
|
2010-05-09 11:32:57 -07:00
|
|
|
nsHTMLOptionElement *optElement = nsHTMLOptionElement::FromContent(aOptions);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (optElement) {
|
2011-10-17 07:59:28 -07:00
|
|
|
GetOptionIndex(optElement, 0, true, &listIndex);
|
2007-03-22 10:30:00 -07:00
|
|
|
// If you nested stuff under the option, you're just plain
|
|
|
|
// screwed. *I'm* not going to aid and abet your evil deed.
|
|
|
|
return listIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
listIndex = GetFirstChildOptionIndex(aOptions, 0, aOptions->GetChildCount());
|
|
|
|
|
|
|
|
return listIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsHTMLSelectElement::GetFirstChildOptionIndex(nsIContent* aOptions,
|
|
|
|
PRInt32 aStartIndex,
|
|
|
|
PRInt32 aEndIndex)
|
|
|
|
{
|
|
|
|
PRInt32 retval = -1;
|
|
|
|
|
|
|
|
for (PRInt32 i = aStartIndex; i < aEndIndex; ++i) {
|
|
|
|
retval = GetFirstOptionIndex(aOptions->GetChildAt(i));
|
|
|
|
if (retval != -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsISelectControlFrame *
|
|
|
|
nsHTMLSelectElement::GetSelectFrame()
|
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
nsIFormControlFrame* form_control_frame = GetFormControlFrame(false);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsISelectControlFrame *select_frame = nsnull;
|
|
|
|
|
|
|
|
if (form_control_frame) {
|
2009-01-12 11:20:59 -08:00
|
|
|
select_frame = do_QueryFrame(form_control_frame);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return select_frame;
|
|
|
|
}
|
|
|
|
|
2011-07-21 03:16:28 -07:00
|
|
|
nsresult
|
2007-03-22 10:30:00 -07:00
|
|
|
nsHTMLSelectElement::Add(nsIDOMHTMLElement* aElement,
|
|
|
|
nsIDOMHTMLElement* aBefore)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> added;
|
|
|
|
if (!aBefore) {
|
|
|
|
return AppendChild(aElement, getter_AddRefs(added));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Just in case we're not the parent, get the parent of the reference
|
|
|
|
// element
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
aBefore->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if (!parent) {
|
|
|
|
// NOT_FOUND_ERR: Raised if before is not a descendant of the SELECT
|
|
|
|
// element.
|
|
|
|
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> ancestor(parent);
|
|
|
|
nsCOMPtr<nsIDOMNode> temp;
|
2007-07-08 00:08:04 -07:00
|
|
|
while (ancestor != static_cast<nsIDOMNode*>(this)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
ancestor->GetParentNode(getter_AddRefs(temp));
|
|
|
|
if (!temp) {
|
|
|
|
// NOT_FOUND_ERR: Raised if before is not a descendant of the SELECT
|
|
|
|
// element.
|
|
|
|
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
|
|
|
}
|
|
|
|
temp.swap(ancestor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the before parameter is not null, we are equivalent to the
|
|
|
|
// insertBefore method on the parent of before.
|
|
|
|
return parent->InsertBefore(aElement, aBefore, getter_AddRefs(added));
|
|
|
|
}
|
|
|
|
|
2011-07-21 03:16:28 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::Add(nsIDOMHTMLElement* aElement,
|
|
|
|
nsIVariant* aBefore)
|
|
|
|
{
|
|
|
|
PRUint16 dataType;
|
|
|
|
nsresult rv = aBefore->GetDataType(&dataType);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-08-01 04:28:52 -07:00
|
|
|
// aBefore is omitted, undefined or null
|
|
|
|
if (dataType == nsIDataType::VTYPE_EMPTY ||
|
|
|
|
dataType == nsIDataType::VTYPE_VOID) {
|
2011-07-21 03:16:28 -07:00
|
|
|
return Add(aElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> supports;
|
|
|
|
nsCOMPtr<nsIDOMHTMLElement> beforeElement;
|
|
|
|
|
|
|
|
// whether aBefore is nsIDOMHTMLElement...
|
|
|
|
if (NS_SUCCEEDED(aBefore->GetAsISupports(getter_AddRefs(supports)))) {
|
|
|
|
beforeElement = do_QueryInterface(supports);
|
|
|
|
|
|
|
|
NS_ENSURE_TRUE(beforeElement, NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
return Add(aElement, beforeElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, whether aBefore is long
|
|
|
|
PRInt32 index;
|
|
|
|
NS_ENSURE_SUCCESS(aBefore->GetAsInt32(&index), NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
|
|
|
// If item index is out of range, insert to last.
|
|
|
|
// (since beforeElement becomes null, it is inserted to last)
|
|
|
|
nsCOMPtr<nsIDOMNode> beforeNode;
|
2011-07-21 03:23:28 -07:00
|
|
|
if (NS_SUCCEEDED(Item(index, getter_AddRefs(beforeNode)))) {
|
2011-07-21 03:16:28 -07:00
|
|
|
beforeElement = do_QueryInterface(beforeNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Add(aElement, beforeElement);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::Remove(PRInt32 aIndex)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> option;
|
|
|
|
Item(aIndex, getter_AddRefs(option));
|
|
|
|
|
|
|
|
if (option) {
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
|
|
|
|
option->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if (parent) {
|
|
|
|
nsCOMPtr<nsIDOMNode> ret;
|
|
|
|
parent->RemoveChild(option, getter_AddRefs(ret));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::GetOptions(nsIDOMHTMLOptionsCollection** aValue)
|
|
|
|
{
|
2010-05-09 11:32:57 -07:00
|
|
|
NS_IF_ADDREF(*aValue = GetOptions());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::GetType(nsAString& aType)
|
|
|
|
{
|
2010-10-08 05:15:00 -07:00
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
aType.AssignLiteral("select-multiple");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aType.AssignLiteral("select-one");
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::GetLength(PRUint32* aLength)
|
|
|
|
{
|
|
|
|
return mOptions->GetLength(aLength);
|
|
|
|
}
|
|
|
|
|
2008-11-11 19:36:20 -08:00
|
|
|
#define MAX_DYNAMIC_SELECT_LENGTH 10000
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::SetLength(PRUint32 aLength)
|
|
|
|
{
|
|
|
|
nsresult rv=NS_OK;
|
|
|
|
|
|
|
|
PRUint32 curlen;
|
2008-11-11 19:36:20 -08:00
|
|
|
PRUint32 i;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
rv = GetLength(&curlen);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
curlen = 0;
|
|
|
|
}
|
|
|
|
|
2008-11-11 19:36:20 -08:00
|
|
|
if (curlen > aLength) { // Remove extra options
|
|
|
|
for (i = curlen; i > aLength && NS_SUCCEEDED(rv); --i) {
|
|
|
|
rv = Remove(i-1);
|
|
|
|
}
|
|
|
|
} else if (aLength > curlen) {
|
|
|
|
if (aLength > MAX_DYNAMIC_SELECT_LENGTH) {
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-11-11 19:36:20 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// This violates the W3C DOM but we do this for backwards compatibility
|
|
|
|
nsCOMPtr<nsINodeInfo> nodeInfo;
|
|
|
|
|
|
|
|
nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::option,
|
|
|
|
getter_AddRefs(nodeInfo));
|
|
|
|
|
2010-07-23 02:49:57 -07:00
|
|
|
nsCOMPtr<nsIContent> element = NS_NewHTMLOptionElement(nodeInfo.forget());
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!element) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> text;
|
|
|
|
rv = NS_NewTextNode(getter_AddRefs(text), mNodeInfo->NodeInfoManager());
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
rv = element->AppendChildTo(text, false);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(element));
|
|
|
|
|
2008-11-11 19:36:20 -08:00
|
|
|
for (i = curlen; i < aLength; i++) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNode> tmpNode;
|
|
|
|
|
|
|
|
rv = AppendChild(node, getter_AddRefs(tmpNode));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2010-03-11 22:50:13 -08:00
|
|
|
if (i + 1 < aLength) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNode> newNode;
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
rv = node->CloneNode(true, getter_AddRefs(newNode));
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
node = newNode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//NS_IMPL_INT_ATTR(nsHTMLSelectElement, SelectedIndex, selectedindex)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::GetSelectedIndex(PRInt32* aValue)
|
|
|
|
{
|
|
|
|
*aValue = mSelectedIndex;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-11-24 02:09:01 -08:00
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::SetSelectedIndexInternal(PRInt32 aIndex, bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRInt32 oldSelectedIndex = mSelectedIndex;
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
nsresult rv = SetOptionsSelectedByIndex(aIndex, aIndex, true,
|
|
|
|
true, true, aNotify, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsISelectControlFrame* selectFrame = GetSelectFrame();
|
|
|
|
if (selectFrame) {
|
|
|
|
rv = selectFrame->OnSetSelectedIndex(oldSelectedIndex, mSelectedIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2010-11-24 02:09:01 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-11-24 02:09:01 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::SetSelectedIndex(PRInt32 aIndex)
|
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
return SetSelectedIndexInternal(aIndex, true);
|
2010-11-24 02:09:01 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
|
2011-09-28 23:19:26 -07:00
|
|
|
PRInt32 aStartIndex, bool aForward,
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32* aIndex)
|
|
|
|
{
|
2010-07-30 20:44:45 -07:00
|
|
|
nsCOMPtr<nsINode> option = do_QueryInterface(aOption);
|
|
|
|
return mOptions->GetOptionIndex(option->AsElement(), aStartIndex, aForward, aIndex);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsHTMLSelectElement::IsOptionSelectedByIndex(PRInt32 aIndex)
|
|
|
|
{
|
|
|
|
nsIDOMHTMLOptionElement *option = mOptions->ItemAsOption(aIndex);
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isSelected = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (option) {
|
|
|
|
option->GetSelected(&isSelected);
|
|
|
|
}
|
|
|
|
return isSelected;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsHTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
|
|
|
|
PRInt32 aIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aSelected,
|
|
|
|
bool aChangeOptionState,
|
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// Set the selected index
|
|
|
|
if (aSelected && (aIndex < mSelectedIndex || mSelectedIndex < 0)) {
|
|
|
|
mSelectedIndex = aIndex;
|
2011-10-17 07:59:28 -07:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else if (!aSelected && aIndex == mSelectedIndex) {
|
2010-11-24 02:09:01 -08:00
|
|
|
FindSelectedIndex(aIndex+1, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-12-04 08:50:32 -08:00
|
|
|
if (aChangeOptionState) {
|
|
|
|
// Tell the option to get its bad self selected
|
|
|
|
nsCOMPtr<nsIDOMNode> option;
|
|
|
|
Item(aIndex, getter_AddRefs(option));
|
|
|
|
if (option) {
|
2010-07-13 23:39:48 -07:00
|
|
|
nsRefPtr<nsHTMLOptionElement> optionElement =
|
|
|
|
static_cast<nsHTMLOptionElement*>(option.get());
|
2007-12-04 08:50:32 -08:00
|
|
|
optionElement->SetSelectedInternal(aSelected, aNotify);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Let the frame know too
|
|
|
|
if (aSelectFrame) {
|
2009-02-17 19:27:25 -08:00
|
|
|
aSelectFrame->OnOptionSelected(aIndex, aSelected);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-11-16 15:41:19 -08:00
|
|
|
|
|
|
|
UpdateValueMissingValidityState();
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateState(aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::FindSelectedIndex(PRInt32 aStartIndex, bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
mSelectedIndex = -1;
|
2011-10-17 07:59:28 -07:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
PRUint32 len;
|
|
|
|
GetLength(&len);
|
|
|
|
for (PRInt32 i=aStartIndex; i<(PRInt32)len; i++) {
|
|
|
|
if (IsOptionSelectedByIndex(i)) {
|
|
|
|
mSelectedIndex = i;
|
2011-10-17 07:59:28 -07:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX Consider splitting this into two functions for ease of reading:
|
|
|
|
// SelectOptionsByIndex(startIndex, endIndex, clearAll, checkDisabled)
|
|
|
|
// startIndex, endIndex - the range of options to turn on
|
|
|
|
// (-1, -1) will clear all indices no matter what.
|
|
|
|
// clearAll - will clear all other options unless checkDisabled is on
|
|
|
|
// and all the options attempted to be set are disabled
|
|
|
|
// (note that if it is not multiple, and an option is selected,
|
|
|
|
// everything else will be cleared regardless).
|
|
|
|
// checkDisabled - if this is TRUE, and an option is disabled, it will not be
|
|
|
|
// changed regardless of whether it is selected or not.
|
|
|
|
// Generally the UI passes TRUE and JS passes FALSE.
|
|
|
|
// (setDisabled currently is the opposite)
|
|
|
|
// DeselectOptionsByIndex(startIndex, endIndex, checkDisabled)
|
|
|
|
// startIndex, endIndex - the range of options to turn on
|
|
|
|
// (-1, -1) will clear all indices no matter what.
|
|
|
|
// checkDisabled - if this is TRUE, and an option is disabled, it will not be
|
|
|
|
// changed regardless of whether it is selected or not.
|
|
|
|
// Generally the UI passes TRUE and JS passes FALSE.
|
|
|
|
// (setDisabled currently is the opposite)
|
2007-12-04 08:50:32 -08:00
|
|
|
//
|
|
|
|
// XXXbz the above comment is pretty confusing. Maybe we should actually
|
|
|
|
// document the args to this function too, in addition to documenting what
|
|
|
|
// things might end up looking like? In particular, pay attention to the
|
|
|
|
// setDisabled vs checkDisabled business.
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::SetOptionsSelectedByIndex(PRInt32 aStartIndex,
|
|
|
|
PRInt32 aEndIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aIsSelected,
|
|
|
|
bool aClearAll,
|
|
|
|
bool aSetDisabled,
|
|
|
|
bool aNotify,
|
|
|
|
bool* aChangedSomething)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
printf("SetOption(%d-%d, %c, ClearAll=%c)\n", aStartIndex, aEndIndex,
|
|
|
|
(aIsSelected ? 'Y' : 'N'),
|
|
|
|
(aClearAll ? 'Y' : 'N'));
|
|
|
|
#endif
|
|
|
|
if (aChangedSomething) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aChangedSomething = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Don't bother if the select is disabled
|
2010-09-18 14:33:16 -07:00
|
|
|
if (!aSetDisabled && IsDisabled()) {
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Don't bother if there are no options
|
|
|
|
PRUint32 numItems = 0;
|
|
|
|
GetLength(&numItems);
|
|
|
|
if (numItems == 0) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// First, find out whether multiple items can be selected
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isMultiple = HasAttr(kNameSpaceID_None, nsGkAtoms::multiple);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// These variables tell us whether any options were selected
|
|
|
|
// or deselected.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool optionsSelected = false;
|
|
|
|
bool optionsDeselected = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsISelectControlFrame *selectFrame = nsnull;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool didGetFrame = false;
|
2009-02-17 19:27:25 -08:00
|
|
|
nsWeakFrame weakSelectFrame;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (aIsSelected) {
|
2009-01-02 07:54:48 -08:00
|
|
|
// Setting selectedIndex to an out-of-bounds index means -1. (HTML5)
|
|
|
|
if (aStartIndex >= (PRInt32)numItems || aStartIndex < 0 ||
|
|
|
|
aEndIndex >= (PRInt32)numItems || aEndIndex < 0) {
|
|
|
|
aStartIndex = -1;
|
|
|
|
aEndIndex = -1;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Only select the first value if it's not multiple
|
|
|
|
if (!isMultiple) {
|
|
|
|
aEndIndex = aStartIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This variable tells whether or not all of the options we attempted to
|
|
|
|
// select are disabled. If ClearAll is passed in as true, and we do not
|
|
|
|
// select anything because the options are disabled, we will not clear the
|
|
|
|
// other options. (This is to make the UI work the way one might expect.)
|
2011-09-28 23:19:26 -07:00
|
|
|
bool allDisabled = !aSetDisabled;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
//
|
|
|
|
// Save a little time when clearing other options
|
|
|
|
//
|
|
|
|
PRInt32 previousSelectedIndex = mSelectedIndex;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Select the requested indices
|
|
|
|
//
|
|
|
|
// If index is -1, everything will be deselected (bug 28143)
|
|
|
|
if (aStartIndex != -1) {
|
|
|
|
// Loop through the options and select them (if they are not disabled and
|
|
|
|
// if they are not already selected).
|
|
|
|
for (PRInt32 optIndex = aStartIndex; optIndex <= aEndIndex; optIndex++) {
|
|
|
|
|
|
|
|
// Ignore disabled options.
|
|
|
|
if (!aSetDisabled) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isDisabled;
|
2007-03-22 10:30:00 -07:00
|
|
|
IsOptionDisabled(optIndex, &isDisabled);
|
|
|
|
|
|
|
|
if (isDisabled) {
|
|
|
|
continue;
|
|
|
|
} else {
|
2011-10-17 07:59:28 -07:00
|
|
|
allDisabled = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDOMHTMLOptionElement *option = mOptions->ItemAsOption(optIndex);
|
|
|
|
if (option) {
|
|
|
|
// If the index is already selected, ignore it.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isSelected = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
option->GetSelected(&isSelected);
|
|
|
|
if (!isSelected) {
|
|
|
|
// To notify the frame if anything gets changed. No need
|
|
|
|
// to flush here, if there's no frame yet we don't need to
|
|
|
|
// force it to be created just to notify it about a change
|
|
|
|
// in the select.
|
|
|
|
selectFrame = GetSelectFrame();
|
2009-02-17 19:27:25 -08:00
|
|
|
weakSelectFrame = do_QueryFrame(selectFrame);
|
2011-10-17 07:59:28 -07:00
|
|
|
didGetFrame = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
OnOptionSelected(selectFrame, optIndex, true, true, aNotify);
|
|
|
|
optionsSelected = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next remove all other options if single select or all is clear
|
|
|
|
// If index is -1, everything will be deselected (bug 28143)
|
|
|
|
if (((!isMultiple && optionsSelected)
|
|
|
|
|| (aClearAll && !allDisabled)
|
|
|
|
|| aStartIndex == -1)
|
|
|
|
&& previousSelectedIndex != -1) {
|
|
|
|
for (PRInt32 optIndex = previousSelectedIndex;
|
|
|
|
optIndex < (PRInt32)numItems;
|
|
|
|
optIndex++) {
|
|
|
|
if (optIndex < aStartIndex || optIndex > aEndIndex) {
|
|
|
|
nsIDOMHTMLOptionElement *option = mOptions->ItemAsOption(optIndex);
|
|
|
|
if (option) {
|
|
|
|
// If the index is already selected, ignore it.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isSelected = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
option->GetSelected(&isSelected);
|
|
|
|
if (isSelected) {
|
2009-02-17 19:27:25 -08:00
|
|
|
if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// To notify the frame if anything gets changed, don't
|
|
|
|
// flush, if the frame doesn't exist we don't need to
|
|
|
|
// create it just to tell it about this change.
|
|
|
|
selectFrame = GetSelectFrame();
|
2009-02-17 19:27:25 -08:00
|
|
|
weakSelectFrame = do_QueryFrame(selectFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
didGetFrame = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
OnOptionSelected(selectFrame, optIndex, false, true,
|
2009-02-17 19:27:25 -08:00
|
|
|
aNotify);
|
2011-10-17 07:59:28 -07:00
|
|
|
optionsDeselected = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Only need to deselect one option if not multiple
|
|
|
|
if (!isMultiple) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// If we're deselecting, loop through all selected items and deselect
|
|
|
|
// any that are in the specified range.
|
|
|
|
for (PRInt32 optIndex = aStartIndex; optIndex <= aEndIndex; optIndex++) {
|
|
|
|
if (!aSetDisabled) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isDisabled;
|
2007-03-22 10:30:00 -07:00
|
|
|
IsOptionDisabled(optIndex, &isDisabled);
|
|
|
|
if (isDisabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDOMHTMLOptionElement *option = mOptions->ItemAsOption(optIndex);
|
|
|
|
if (option) {
|
|
|
|
// If the index is already selected, ignore it.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isSelected = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
option->GetSelected(&isSelected);
|
|
|
|
if (isSelected) {
|
2009-02-17 19:27:25 -08:00
|
|
|
if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// To notify the frame if anything gets changed, don't
|
|
|
|
// flush, if the frame doesn't exist we don't need to
|
|
|
|
// create it just to tell it about this change.
|
|
|
|
selectFrame = GetSelectFrame();
|
2009-02-17 19:27:25 -08:00
|
|
|
weakSelectFrame = do_QueryFrame(selectFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
didGetFrame = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
OnOptionSelected(selectFrame, optIndex, false, true, aNotify);
|
|
|
|
optionsDeselected = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure something is selected unless we were set to -1 (none)
|
|
|
|
if (optionsDeselected && aStartIndex != -1) {
|
2010-11-16 15:41:19 -08:00
|
|
|
optionsSelected = CheckSelectSomething(aNotify) || optionsSelected;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Let the caller know whether anything was changed
|
|
|
|
if (optionsSelected || optionsDeselected) {
|
|
|
|
if (aChangedSomething)
|
2011-10-17 07:59:28 -07:00
|
|
|
*aChangedSomething = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::IsOptionDisabled(PRInt32 aIndex, bool* aIsDisabled)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
*aIsDisabled = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNode> optionNode;
|
|
|
|
Item(aIndex, getter_AddRefs(optionNode));
|
|
|
|
NS_ENSURE_TRUE(optionNode, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> option = do_QueryInterface(optionNode);
|
|
|
|
if (option) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isDisabled;
|
2007-03-22 10:30:00 -07:00
|
|
|
option->GetDisabled(&isDisabled);
|
|
|
|
if (isDisabled) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aIsDisabled = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for disabled optgroups
|
|
|
|
// If there are no artifacts, there are no optgroups
|
|
|
|
if (mNonOptionChildren) {
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
while (1) {
|
|
|
|
optionNode->GetParentNode(getter_AddRefs(parent));
|
|
|
|
|
|
|
|
// If we reached the top of the doc (scary), we're done
|
|
|
|
if (!parent) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we reached the select element, we're done
|
|
|
|
nsCOMPtr<nsIDOMHTMLSelectElement> selectElement =
|
|
|
|
do_QueryInterface(parent);
|
|
|
|
if (selectElement) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptGroupElement> optGroupElement =
|
|
|
|
do_QueryInterface(parent);
|
|
|
|
|
|
|
|
if (optGroupElement) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isDisabled;
|
2007-03-22 10:30:00 -07:00
|
|
|
optGroupElement->GetDisabled(&isDisabled);
|
|
|
|
|
|
|
|
if (isDisabled) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aIsDisabled = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If you put something else between you and the optgroup, you're a
|
|
|
|
// moron and you deserve not to have optgroup disabling work.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
optionNode = parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::GetValue(nsAString& aValue)
|
|
|
|
{
|
|
|
|
PRInt32 selectedIndex;
|
|
|
|
|
|
|
|
nsresult rv = GetSelectedIndex(&selectedIndex);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && selectedIndex > -1) {
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
|
|
|
|
rv = Item(selectedIndex, getter_AddRefs(node));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> option = do_QueryInterface(node);
|
|
|
|
if (NS_SUCCEEDED(rv) && option) {
|
|
|
|
return option->GetValue(aValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aValue.Truncate(0);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::SetValue(const nsAString& aValue)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
PRUint32 length;
|
|
|
|
rv = GetLength(&length);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
|
|
|
|
rv = Item(i, getter_AddRefs(node));
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && node) {
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> option = do_QueryInterface(node);
|
|
|
|
|
|
|
|
if (option) {
|
|
|
|
nsAutoString optionVal;
|
|
|
|
|
|
|
|
option->GetValue(optionVal);
|
|
|
|
|
|
|
|
if (optionVal.Equals(aValue)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
SetSelectedIndexInternal((PRInt32)i, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-19 10:52:17 -07:00
|
|
|
NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Autofocus, autofocus)
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Disabled, disabled)
|
|
|
|
NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Multiple, multiple)
|
|
|
|
NS_IMPL_STRING_ATTR(nsHTMLSelectElement, Name, name)
|
2010-11-16 12:06:15 -08:00
|
|
|
NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Required, required)
|
2011-03-24 04:49:19 -07:00
|
|
|
NS_IMPL_NON_NEGATIVE_INT_ATTR_DEFAULT_VALUE(nsHTMLSelectElement, Size, size, 0)
|
2010-10-18 22:53:15 -07:00
|
|
|
NS_IMPL_INT_ATTR(nsHTMLSelectElement, TabIndex, tabindex)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
|
|
|
nsHTMLSelectElement::IsHTMLFocusable(bool aWithMouse,
|
|
|
|
bool *aIsFocusable, PRInt32 *aTabIndex)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-01-05 05:23:37 -08:00
|
|
|
if (nsGenericHTMLFormElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-06-21 05:37:34 -07:00
|
|
|
|
2010-09-18 14:33:16 -07:00
|
|
|
*aIsFocusable = !IsDisabled();
|
2010-06-21 05:37:34 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
return mOptions->Item(aIndex, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::NamedItem(const nsAString& aName,
|
|
|
|
nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
return mOptions->NamedItem(aName, aReturn);
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
|
|
|
nsHTMLSelectElement::CheckSelectSomething(bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (mIsDoneAddingChildren) {
|
|
|
|
if (mSelectedIndex < 0 && IsCombobox()) {
|
2010-11-16 15:41:19 -08:00
|
|
|
return SelectSomething(aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
|
|
|
nsHTMLSelectElement::SelectSomething(bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// If we're not done building the select, don't play with this yet.
|
|
|
|
if (!mIsDoneAddingChildren) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 count;
|
|
|
|
GetLength(&count);
|
|
|
|
for (PRUint32 i=0; i<count; i++) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool disabled;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv = IsOptionDisabled(i, &disabled);
|
|
|
|
|
|
|
|
if (NS_FAILED(rv) || !disabled) {
|
2010-11-24 02:09:01 -08:00
|
|
|
rv = SetSelectedIndexInternal(i, aNotify);
|
2011-10-17 07:59:28 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
2010-11-16 15:41:19 -08:00
|
|
|
|
|
|
|
UpdateValueMissingValidityState();
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateState(aNotify);
|
2010-11-16 15:41:19 -08:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-09-18 14:33:16 -07:00
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|
|
|
nsIContent* aBindingParent,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aCompileEventHandlers)
|
2010-09-18 14:33:16 -07:00
|
|
|
{
|
|
|
|
nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
|
|
|
|
aBindingParent,
|
|
|
|
aCompileEventHandlers);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// If there is a disabled fieldset in the parent chain, the element is now
|
|
|
|
// barred from constraint validation.
|
2011-05-31 18:46:57 -07:00
|
|
|
// XXXbz is this still needed now that fieldset changes always call
|
|
|
|
// FieldSetDisabledChanged?
|
2010-09-18 14:33:16 -07:00
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
// And now make sure our state is up to date
|
|
|
|
UpdateState(false);
|
|
|
|
|
2010-09-18 14:33:16 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
void
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
2011-05-31 18:46:57 -07:00
|
|
|
{
|
|
|
|
nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
|
|
|
|
|
|
|
|
// We might be no longer disabled because our parent chain changed.
|
2011-05-31 18:46:57 -07:00
|
|
|
// XXXbz is this still needed now that fieldset changes always call
|
|
|
|
// FieldSetDisabledChanged?
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateBarredFromConstraintValidation();
|
2011-05-31 18:46:57 -07:00
|
|
|
|
|
|
|
// And now make sure our state is up to date
|
|
|
|
UpdateState(false);
|
2011-05-31 18:46:57 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
2011-09-28 23:19:26 -07:00
|
|
|
const nsAString* aValue, bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (aNotify && aName == nsGkAtoms::disabled &&
|
|
|
|
aNameSpaceID == kNameSpaceID_None) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mDisabledChanged = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName,
|
|
|
|
aValue, aNotify);
|
|
|
|
}
|
|
|
|
|
2010-09-09 22:08:56 -07:00
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
2011-09-28 23:19:26 -07:00
|
|
|
const nsAString* aValue, bool aNotify)
|
2010-09-09 22:08:56 -07:00
|
|
|
{
|
2010-11-16 15:41:19 -08:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
|
|
if (aName == nsGkAtoms::disabled) {
|
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
} else if (aName == nsGkAtoms::required) {
|
|
|
|
UpdateValueMissingValidityState();
|
|
|
|
}
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateState(aNotify);
|
2010-09-09 22:08:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
|
|
|
|
aValue, aNotify);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (aNotify && aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
aAttribute == nsGkAtoms::multiple) {
|
|
|
|
// We're changing from being a multi-select to a single-select.
|
|
|
|
// Make sure we only have one option selected before we do that.
|
|
|
|
// Note that this needs to come before we really unset the attr,
|
|
|
|
// since SetOptionsSelectedByIndex does some bail-out type
|
|
|
|
// optimization for cases when the select is not multiple that
|
|
|
|
// would lead to only a single option getting deselected.
|
|
|
|
if (mSelectedIndex >= 0) {
|
2010-11-24 02:09:01 -08:00
|
|
|
SetSelectedIndexInternal(mSelectedIndex, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = nsGenericHTMLFormElement::UnsetAttr(aNameSpaceID, aAttribute,
|
|
|
|
aNotify);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (aNotify && aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
aAttribute == nsGkAtoms::multiple) {
|
|
|
|
// We might have become a combobox; make sure _something_ gets
|
|
|
|
// selected in that case
|
2010-11-16 15:41:19 -08:00
|
|
|
CheckSelectSomething(aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::DoneAddingChildren(bool aHaveNotified)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsDoneAddingChildren = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsISelectControlFrame* selectFrame = GetSelectFrame();
|
|
|
|
|
|
|
|
// If we foolishly tried to restore before we were done adding
|
|
|
|
// content, restore the rest of the options proper-like
|
|
|
|
if (mRestoreState) {
|
|
|
|
RestoreStateTo(mRestoreState);
|
|
|
|
mRestoreState = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify the frame
|
|
|
|
if (selectFrame) {
|
2011-10-17 07:59:28 -07:00
|
|
|
selectFrame->DoneAddingChildren(true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Restore state
|
2010-06-08 23:45:32 -07:00
|
|
|
if (!mInhibitStateRestoration) {
|
|
|
|
RestoreFormControlState(this, this);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Now that we're done, select something (if it's a single select something
|
|
|
|
// must be selected)
|
2011-10-17 07:59:28 -07:00
|
|
|
if (!CheckSelectSomething(false)) {
|
2010-11-16 15:41:19 -08:00
|
|
|
// If an option has @selected set, it will be selected during parsing but
|
|
|
|
// with an empty value. We have to make sure the select element updates it's
|
|
|
|
// validity state to take this into account.
|
|
|
|
UpdateValueMissingValidityState();
|
2011-05-31 18:46:57 -07:00
|
|
|
|
|
|
|
// And now make sure we update our content state too
|
|
|
|
UpdateState(aHaveNotified);
|
2010-11-16 15:41:19 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mDefaultSelectionSet = true;
|
2010-11-24 02:09:01 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsHTMLSelectElement::ParseAttribute(PRInt32 aNamespaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsAttrValue& aResult)
|
|
|
|
{
|
|
|
|
if (aAttribute == nsGkAtoms::size && kNameSpaceID_None == aNamespaceID) {
|
2010-05-23 14:36:49 -07:00
|
|
|
return aResult.ParsePositiveIntValue(aValue);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
|
|
|
aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
|
|
|
nsRuleData* aData)
|
|
|
|
{
|
|
|
|
nsGenericHTMLFormElement::MapImageAlignAttributeInto(aAttributes, aData);
|
|
|
|
nsGenericHTMLFormElement::MapCommonAttributesInto(aAttributes, aData);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsChangeHint
|
|
|
|
nsHTMLSelectElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
|
|
|
PRInt32 aModType) const
|
|
|
|
{
|
|
|
|
nsChangeHint retval =
|
|
|
|
nsGenericHTMLFormElement::GetAttributeChangeHint(aAttribute, aModType);
|
|
|
|
if (aAttribute == nsGkAtoms::multiple ||
|
|
|
|
aAttribute == nsGkAtoms::size) {
|
|
|
|
NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
NS_IMETHODIMP_(bool)
|
2007-03-22 10:30:00 -07:00
|
|
|
nsHTMLSelectElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
|
|
|
{
|
|
|
|
static const MappedAttributeEntry* const map[] = {
|
|
|
|
sCommonAttributeMap,
|
|
|
|
sImageAlignAttributeMap
|
|
|
|
};
|
|
|
|
|
2011-10-10 22:50:08 -07:00
|
|
|
return FindAttributeDependence(aAttribute, map, ArrayLength(map));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsMapRuleToAttributesFunc
|
|
|
|
nsHTMLSelectElement::GetAttributeMappingFunction() const
|
|
|
|
{
|
|
|
|
return &MapAttributesIntoRule;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIFrame* formFrame = nsnull;
|
2011-07-18 16:16:44 -07:00
|
|
|
if (formControlFrame) {
|
|
|
|
formFrame = do_QueryFrame(formControlFrame);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
aVisitor.mCanHandle = false;
|
2011-07-18 16:16:44 -07:00
|
|
|
if (IsElementDisabledForEvents(aVisitor.mEvent->message, formFrame)) {
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-11-24 02:09:31 -08:00
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
|
|
|
{
|
|
|
|
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) {
|
|
|
|
// If the invalid UI is shown, we should show it while focused and
|
|
|
|
// update the invalid/valid UI.
|
2011-01-20 03:05:29 -08:00
|
|
|
mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
|
2010-11-24 02:09:31 -08:00
|
|
|
|
|
|
|
// If neither invalid UI nor valid UI is shown, we shouldn't show the valid
|
|
|
|
// UI while focused.
|
2011-01-20 03:05:29 -08:00
|
|
|
mCanShowValidUI = ShouldShowValidityUI();
|
2010-11-24 02:09:31 -08:00
|
|
|
|
|
|
|
// We don't have to update NS_EVENT_STATE_MOZ_UI_INVALID nor
|
|
|
|
// NS_EVENT_STATE_MOZ_UI_VALID given that the states should not change.
|
|
|
|
} else if (aVisitor.mEvent->message == NS_BLUR_CONTENT) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mCanShowInvalidUI = true;
|
|
|
|
mCanShowValidUI = true;
|
2010-11-24 02:09:31 -08:00
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateState(true);
|
2010-11-24 02:09:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsGenericHTMLFormElement::PostHandleEvent(aVisitor);
|
|
|
|
}
|
|
|
|
|
2010-10-20 04:26:32 -07:00
|
|
|
nsEventStates
|
2010-08-18 17:03:20 -07:00
|
|
|
nsHTMLSelectElement::IntrinsicState() const
|
|
|
|
{
|
2010-10-20 04:26:32 -07:00
|
|
|
nsEventStates state = nsGenericHTMLFormElement::IntrinsicState();
|
2010-08-21 10:52:57 -07:00
|
|
|
|
2010-08-21 11:51:38 -07:00
|
|
|
if (IsCandidateForConstraintValidation()) {
|
2010-11-24 02:09:01 -08:00
|
|
|
if (IsValid()) {
|
|
|
|
state |= NS_EVENT_STATE_VALID;
|
|
|
|
} else {
|
|
|
|
state |= NS_EVENT_STATE_INVALID;
|
|
|
|
|
2011-01-27 05:51:45 -08:00
|
|
|
if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
|
|
|
|
(GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
|
|
|
(mCanShowInvalidUI && ShouldShowValidityUI()))) {
|
2010-11-24 02:09:01 -08:00
|
|
|
state |= NS_EVENT_STATE_MOZ_UI_INVALID;
|
|
|
|
}
|
|
|
|
}
|
2010-11-24 02:09:31 -08:00
|
|
|
|
|
|
|
// :-moz-ui-valid applies if all the following are true:
|
|
|
|
// 1. The element is not focused, or had either :-moz-ui-valid or
|
|
|
|
// :-moz-ui-invalid applying before it was focused ;
|
|
|
|
// 2. The element is either valid or isn't allowed to have
|
|
|
|
// :-moz-ui-invalid applying ;
|
2011-01-27 05:51:45 -08:00
|
|
|
// 3. The element has no form owner or its form owner doesn't have the
|
|
|
|
// novalidate attribute set ;
|
|
|
|
// 4. The element has already been modified or the user tried to submit the
|
|
|
|
// form owner while invalid.
|
|
|
|
if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
|
|
|
|
(mCanShowValidUI && ShouldShowValidityUI() &&
|
|
|
|
(IsValid() || (state.HasState(NS_EVENT_STATE_MOZ_UI_INVALID) &&
|
|
|
|
!mCanShowInvalidUI)))) {
|
2010-11-24 02:09:31 -08:00
|
|
|
state |= NS_EVENT_STATE_MOZ_UI_VALID;
|
|
|
|
}
|
2010-08-21 10:52:57 -07:00
|
|
|
}
|
|
|
|
|
2010-11-16 06:40:21 -08:00
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
|
|
|
|
state |= NS_EVENT_STATE_REQUIRED;
|
|
|
|
} else {
|
|
|
|
state |= NS_EVENT_STATE_OPTIONAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
2010-08-18 17:03:20 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// nsIFormControl
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::SaveState()
|
|
|
|
{
|
|
|
|
nsRefPtr<nsSelectState> state = new nsSelectState();
|
|
|
|
if (!state) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 len;
|
|
|
|
GetLength(&len);
|
|
|
|
|
|
|
|
for (PRUint32 optIndex = 0; optIndex < len; optIndex++) {
|
|
|
|
nsIDOMHTMLOptionElement *option = mOptions->ItemAsOption(optIndex);
|
|
|
|
if (option) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isSelected;
|
2007-03-22 10:30:00 -07:00
|
|
|
option->GetSelected(&isSelected);
|
|
|
|
if (isSelected) {
|
|
|
|
nsAutoString value;
|
|
|
|
option->GetValue(value);
|
|
|
|
state->PutOption(optIndex, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsPresState *presState = nsnull;
|
|
|
|
nsresult rv = GetPrimaryPresState(this, &presState);
|
|
|
|
if (presState) {
|
2008-12-12 11:25:22 -08:00
|
|
|
presState->SetStateProperty(state);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mDisabledChanged) {
|
2010-09-18 14:33:16 -07:00
|
|
|
// We do not want to save the real disabled state but the disabled
|
|
|
|
// attribute.
|
|
|
|
presState->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsHTMLSelectElement::RestoreState(nsPresState* aState)
|
|
|
|
{
|
|
|
|
// Get the presentation state object to retrieve our stuff out of.
|
2008-12-12 11:25:22 -08:00
|
|
|
nsCOMPtr<nsSelectState> state(
|
|
|
|
do_QueryInterface(aState->GetStateProperty()));
|
|
|
|
|
|
|
|
if (state) {
|
|
|
|
RestoreStateTo(state);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-10-09 20:39:16 -07:00
|
|
|
// Don't flush, if the frame doesn't exist yet it doesn't care if
|
|
|
|
// we're reset or not.
|
|
|
|
DispatchContentReset();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-12-12 11:25:22 -08:00
|
|
|
if (aState->IsDisabledSet()) {
|
|
|
|
SetDisabled(aState->GetDisabled());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsHTMLSelectElement::RestoreStateTo(nsSelectState* aNewSelected)
|
|
|
|
{
|
|
|
|
if (!mIsDoneAddingChildren) {
|
|
|
|
mRestoreState = aNewSelected;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 len;
|
|
|
|
GetLength(&len);
|
|
|
|
|
|
|
|
// First clear all
|
2011-10-17 07:59:28 -07:00
|
|
|
SetOptionsSelectedByIndex(-1, -1, true, true, true, true, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Next set the proper ones
|
|
|
|
for (PRInt32 i = 0; i < (PRInt32)len; i++) {
|
|
|
|
nsIDOMHTMLOptionElement *option = mOptions->ItemAsOption(i);
|
|
|
|
if (option) {
|
|
|
|
nsAutoString value;
|
2008-12-12 11:25:22 -08:00
|
|
|
nsresult rv = option->GetValue(value);
|
|
|
|
if (NS_SUCCEEDED(rv) && aNewSelected->ContainsOption(i, value)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
SetOptionsSelectedByIndex(i, i, true, false, true, true, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//CheckSelectSomething();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLSelectElement::Reset()
|
|
|
|
{
|
|
|
|
PRUint32 numSelected = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Cycle through the options array and reset the options
|
|
|
|
//
|
|
|
|
PRUint32 numOptions;
|
|
|
|
nsresult rv = GetLength(&numOptions);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < numOptions; i++) {
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
rv = Item(i, getter_AddRefs(node));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> option(do_QueryInterface(node));
|
|
|
|
|
|
|
|
NS_ASSERTION(option, "option not an OptionElement");
|
|
|
|
if (option) {
|
|
|
|
//
|
|
|
|
// Reset the option to its default value
|
|
|
|
//
|
2011-09-28 23:19:26 -07:00
|
|
|
bool selected = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
option->GetDefaultSelected(&selected);
|
|
|
|
SetOptionsSelectedByIndex(i, i, selected,
|
2011-10-17 07:59:28 -07:00
|
|
|
false, true, true, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (selected) {
|
|
|
|
numSelected++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// If nothing was selected and it's not multiple, select something
|
|
|
|
//
|
|
|
|
if (numSelected == 0 && IsCombobox()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
SelectSomething(true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
SetSelectionChanged(false, true);
|
2010-11-24 02:09:01 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
|
|
|
// Let the frame know we were reset
|
|
|
|
//
|
|
|
|
// Don't flush, if there's no frame yet it won't care about us being
|
|
|
|
// reset even if we forced it to be created now.
|
|
|
|
//
|
|
|
|
DispatchContentReset();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-02-24 21:58:16 -08:00
|
|
|
static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
2010-08-19 14:58:20 -07:00
|
|
|
nsHTMLSelectElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
// Disabled elements don't submit
|
2010-09-18 14:33:16 -07:00
|
|
|
if (IsDisabled()) {
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get the name (if no name, no submit)
|
|
|
|
//
|
|
|
|
nsAutoString name;
|
2010-02-24 21:57:54 -08:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
if (name.IsEmpty()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Submit
|
|
|
|
//
|
|
|
|
PRUint32 len;
|
|
|
|
GetLength(&len);
|
|
|
|
|
2010-02-24 21:58:16 -08:00
|
|
|
nsAutoString mozType;
|
|
|
|
nsCOMPtr<nsIFormProcessor> keyGenProcessor;
|
|
|
|
if (GetAttr(kNameSpaceID_None, nsGkAtoms::_moz_type, mozType) &&
|
|
|
|
mozType.EqualsLiteral("-mozilla-keygen")) {
|
|
|
|
keyGenProcessor = do_GetService(kFormProcessorCID, &rv);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
for (PRUint32 optIndex = 0; optIndex < len; optIndex++) {
|
|
|
|
// Don't send disabled options
|
2011-09-28 23:19:26 -07:00
|
|
|
bool disabled;
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = IsOptionDisabled(optIndex, &disabled);
|
|
|
|
if (NS_FAILED(rv) || disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDOMHTMLOptionElement *option = mOptions->ItemAsOption(optIndex);
|
|
|
|
NS_ENSURE_TRUE(option, NS_ERROR_UNEXPECTED);
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isSelected;
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = option->GetSelected(&isSelected);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!isSelected) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> optionElement = do_QueryInterface(option);
|
|
|
|
NS_ENSURE_TRUE(optionElement, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
nsAutoString value;
|
|
|
|
rv = optionElement->GetValue(value);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2010-02-24 21:58:16 -08:00
|
|
|
if (keyGenProcessor) {
|
|
|
|
nsAutoString tmp(value);
|
|
|
|
rv = keyGenProcessor->ProcessValue(this, name, tmp);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
value = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = aFormSubmission->AddNameValuePair(name, value);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::GetHasOptGroups(bool* aHasGroups)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
*aHasGroups = (mOptGroupCount > 0);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsHTMLSelectElement::DispatchContentReset() {
|
2011-10-17 07:59:28 -07:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (formControlFrame) {
|
|
|
|
// Only dispatch content reset notification if this is a list control
|
|
|
|
// frame or combo box control frame.
|
|
|
|
if (IsCombobox()) {
|
2009-01-12 11:20:59 -08:00
|
|
|
nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (comboFrame) {
|
|
|
|
comboFrame->OnContentReset();
|
|
|
|
}
|
|
|
|
} else {
|
2009-01-12 11:20:59 -08:00
|
|
|
nsIListControlFrame* listFrame = do_QueryFrame(formControlFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (listFrame) {
|
|
|
|
listFrame->OnContentReset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
AddOptionsRecurse(nsIContent* aRoot, nsHTMLOptionCollection* aArray)
|
|
|
|
{
|
2011-08-08 08:14:33 -07:00
|
|
|
for (nsIContent* cur = aRoot->GetFirstChild();
|
|
|
|
cur;
|
|
|
|
cur = cur->GetNextSibling()) {
|
|
|
|
nsHTMLOptionElement* opt = nsHTMLOptionElement::FromContent(cur);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (opt) {
|
|
|
|
// If we fail here, then at least we've tried our best
|
|
|
|
aArray->AppendOption(opt);
|
2011-08-08 08:14:33 -07:00
|
|
|
} else if (cur->IsHTML(nsGkAtoms::optgroup)) {
|
|
|
|
AddOptionsRecurse(cur, aArray);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::RebuildOptionsArray(bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
mOptions->Clear();
|
|
|
|
AddOptionsRecurse(this, mOptions);
|
2010-11-24 02:09:01 -08:00
|
|
|
FindSelectedIndex(0, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-11-16 15:41:19 -08:00
|
|
|
bool
|
|
|
|
nsHTMLSelectElement::IsValueMissing()
|
|
|
|
{
|
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 length;
|
|
|
|
nsIDOMHTMLOptionElement* option = nsnull;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool disabled;
|
|
|
|
bool selected;
|
2010-11-16 15:41:19 -08:00
|
|
|
|
|
|
|
mOptions->GetLength(&length);
|
|
|
|
|
|
|
|
for (PRUint32 i=0; i<length; ++i) {
|
|
|
|
option = mOptions->ItemAsOption(i);
|
|
|
|
NS_ENSURE_SUCCESS(option->GetSelected(&selected), false);
|
|
|
|
|
|
|
|
if (!selected) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
IsOptionDisabled(i, &disabled);
|
|
|
|
if (disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString value;
|
|
|
|
NS_ENSURE_SUCCESS(option->GetValue(value), false);
|
|
|
|
if (!value.IsEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsHTMLSelectElement::UpdateValueMissingValidityState()
|
|
|
|
{
|
|
|
|
SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLSelectElement::GetValidationMessage(nsAString& aValidationMessage,
|
|
|
|
ValidityStateType aType)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
switch (aType)
|
|
|
|
{
|
|
|
|
case VALIDITY_STATE_VALUE_MISSING:
|
|
|
|
{
|
|
|
|
nsXPIDLString message;
|
|
|
|
|
|
|
|
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
"FormValidationSelectMissing",
|
|
|
|
message);
|
|
|
|
|
|
|
|
aValidationMessage = message;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
static void
|
|
|
|
VerifyOptionsRecurse(nsIContent* aRoot, PRInt32& aIndex,
|
|
|
|
nsHTMLOptionCollection* aArray)
|
|
|
|
{
|
2011-08-08 08:14:33 -07:00
|
|
|
for (nsIContent* cur = aRoot->GetFirstChild();
|
|
|
|
cur;
|
|
|
|
cur = cur->GetNextSibling()) {
|
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> opt = do_QueryInterface(cur);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (opt) {
|
|
|
|
NS_ASSERTION(opt == aArray->ItemAsOption(aIndex++),
|
|
|
|
"Options collection broken");
|
2011-08-08 08:14:33 -07:00
|
|
|
} else if (cur->IsHTML(nsGkAtoms::optgroup)) {
|
|
|
|
VerifyOptionsRecurse(cur, aIndex, aArray);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsHTMLSelectElement::VerifyOptionsArray()
|
|
|
|
{
|
|
|
|
PRInt32 aIndex = 0;
|
|
|
|
VerifyOptionsRecurse(this, aIndex, mOptions);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsHTMLOptionCollection implementation
|
|
|
|
//
|
|
|
|
|
|
|
|
nsHTMLOptionCollection::nsHTMLOptionCollection(nsHTMLSelectElement* aSelect)
|
|
|
|
{
|
2011-08-20 06:53:34 -07:00
|
|
|
SetIsProxy();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Do not maintain a reference counted reference. When
|
|
|
|
// the select goes away, it will let us know.
|
|
|
|
mSelect = aSelect;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsHTMLOptionCollection::~nsHTMLOptionCollection()
|
|
|
|
{
|
|
|
|
DropReference();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsHTMLOptionCollection::DropReference()
|
|
|
|
{
|
|
|
|
// Drop our (non ref-counted) reference
|
|
|
|
mSelect = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2010-05-09 11:32:57 -07:00
|
|
|
nsHTMLOptionCollection::GetOptionIndex(mozilla::dom::Element* aOption,
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 aStartIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aForward,
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32* aIndex)
|
|
|
|
{
|
|
|
|
PRInt32 index;
|
|
|
|
|
|
|
|
// Make the common case fast
|
|
|
|
if (aStartIndex == 0 && aForward) {
|
|
|
|
index = mElements.IndexOf(aOption);
|
|
|
|
if (index == -1) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aIndex = index;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-05-09 11:32:57 -07:00
|
|
|
PRInt32 high = mElements.Length();
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 step = aForward ? 1 : -1;
|
|
|
|
|
|
|
|
for (index = aStartIndex; index < high && index > -1; index += step) {
|
|
|
|
if (mElements[index] == aOption) {
|
|
|
|
*aIndex = index;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLOptionCollection)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHTMLOptionCollection)
|
2010-05-09 11:32:57 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mElements)
|
2011-08-20 06:53:34 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHTMLOptionCollection)
|
2011-08-20 06:53:34 -07:00
|
|
|
{
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < tmp->mElements.Length(); ++i) {
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mElements[i]");
|
|
|
|
cb.NoteXPCOMChild(static_cast<Element*>(tmp->mElements[i]));
|
2010-05-09 11:32:57 -07:00
|
|
|
}
|
2011-08-20 06:53:34 -07:00
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
2011-08-20 06:53:34 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsHTMLOptionCollection)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// nsISupports
|
|
|
|
|
2010-01-12 05:08:43 -08:00
|
|
|
DOMCI_DATA(HTMLOptionsCollection, nsHTMLOptionCollection)
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// QueryInterface implementation for nsHTMLOptionCollection
|
2007-08-20 15:55:06 -07:00
|
|
|
NS_INTERFACE_TABLE_HEAD(nsHTMLOptionCollection)
|
2011-08-20 06:53:34 -07:00
|
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
|
|
NS_INTERFACE_TABLE3(nsHTMLOptionCollection,
|
2008-10-22 07:31:14 -07:00
|
|
|
nsIHTMLCollection,
|
2007-08-20 15:55:06 -07:00
|
|
|
nsIDOMHTMLOptionsCollection,
|
|
|
|
nsIDOMHTMLCollection)
|
|
|
|
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsHTMLOptionCollection)
|
2010-03-17 08:09:05 -07:00
|
|
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLOptionsCollection)
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
|
2011-03-06 03:11:31 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTMLOptionCollection)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTMLOptionCollection)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
|
2011-08-20 06:53:34 -07:00
|
|
|
JSObject*
|
|
|
|
nsHTMLOptionCollection::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
|
|
|
|
bool *triedToWrap)
|
|
|
|
{
|
|
|
|
return mozilla::dom::binding::HTMLOptionsCollection::create(cx, scope, this,
|
|
|
|
triedToWrap);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::GetLength(PRUint32* aLength)
|
|
|
|
{
|
2010-05-09 11:32:57 -07:00
|
|
|
*aLength = mElements.Length();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::SetLength(PRUint32 aLength)
|
|
|
|
{
|
|
|
|
if (!mSelect) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mSelect->SetLength(aLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-08-20 06:53:34 -07:00
|
|
|
nsHTMLOptionCollection::SetOption(PRUint32 aIndex,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIDOMHTMLOptionElement *aOption)
|
|
|
|
{
|
2011-08-20 06:53:34 -07:00
|
|
|
if (!mSelect) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-05-09 11:32:57 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// if the new option is null, just remove this option. Note that it's safe
|
|
|
|
// to pass a too-large aIndex in here.
|
|
|
|
if (!aOption) {
|
|
|
|
mSelect->Remove(aIndex);
|
|
|
|
|
|
|
|
// We're done.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
2010-05-09 11:32:57 -07:00
|
|
|
PRUint32 index = PRUint32(aIndex);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Now we're going to be setting an option in our collection
|
2010-05-09 11:32:57 -07:00
|
|
|
if (index > mElements.Length()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Fill our array with blank options up to (but not including, since we're
|
|
|
|
// about to change it) aIndex, for compat with other browsers.
|
2010-05-09 11:32:57 -07:00
|
|
|
rv = SetLength(index);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
2010-05-09 11:32:57 -07:00
|
|
|
NS_ASSERTION(index <= mElements.Length(), "SetLength lied");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> ret;
|
2010-05-09 11:32:57 -07:00
|
|
|
if (index == mElements.Length()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = mSelect->AppendChild(aOption, getter_AddRefs(ret));
|
|
|
|
} else {
|
|
|
|
// Find the option they're talking about and replace it
|
|
|
|
// hold a strong reference to follow COM rules.
|
2010-05-09 11:32:57 -07:00
|
|
|
nsCOMPtr<nsIDOMHTMLOptionElement> refChild = ItemAsOption(index);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_TRUE(refChild, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
refChild->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if (parent) {
|
|
|
|
rv = parent->ReplaceChild(aOption, refChild, getter_AddRefs(ret));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::GetSelectedIndex(PRInt32 *aSelectedIndex)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(mSelect, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
return mSelect->GetSelectedIndex(aSelectedIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::SetSelectedIndex(PRInt32 aSelectedIndex)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(mSelect, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
return mSelect->SetSelectedIndex(aSelectedIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
|
|
|
|
{
|
2011-04-25 10:46:57 -07:00
|
|
|
nsISupports* item = GetNodeAt(aIndex);
|
2008-10-22 07:31:14 -07:00
|
|
|
if (!item) {
|
|
|
|
*aReturn = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-04-25 10:46:57 -07:00
|
|
|
return NS_OK;
|
2008-10-22 07:31:14 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-10-22 07:31:14 -07:00
|
|
|
return CallQueryInterface(item, aReturn);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-05-09 12:33:00 -07:00
|
|
|
nsIContent*
|
2011-04-25 10:46:57 -07:00
|
|
|
nsHTMLOptionCollection::GetNodeAt(PRUint32 aIndex)
|
2010-05-09 11:32:57 -07:00
|
|
|
{
|
2010-05-09 12:33:00 -07:00
|
|
|
return static_cast<nsIContent*>(ItemAsOption(aIndex));
|
2010-05-09 11:32:57 -07:00
|
|
|
}
|
|
|
|
|
2010-05-09 12:41:19 -07:00
|
|
|
static nsHTMLOptionElement*
|
|
|
|
GetNamedItemHelper(nsTArray<nsRefPtr<nsHTMLOptionElement> > &aElements,
|
|
|
|
const nsAString& aName)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-05-09 12:41:19 -07:00
|
|
|
PRUint32 count = aElements.Length();
|
2010-05-09 11:32:57 -07:00
|
|
|
for (PRUint32 i = 0; i < count; i++) {
|
2010-05-09 12:41:19 -07:00
|
|
|
nsHTMLOptionElement *content = aElements.ElementAt(i);
|
2008-10-31 14:40:35 -07:00
|
|
|
if (content &&
|
|
|
|
(content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, aName,
|
|
|
|
eCaseMatters) ||
|
|
|
|
content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id, aName,
|
|
|
|
eCaseMatters))) {
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-10-31 14:40:35 -07:00
|
|
|
return nsnull;
|
|
|
|
}
|
2008-10-31 08:55:59 -07:00
|
|
|
|
2010-05-09 12:41:19 -07:00
|
|
|
nsISupports*
|
|
|
|
nsHTMLOptionCollection::GetNamedItem(const nsAString& aName,
|
2011-04-25 10:46:59 -07:00
|
|
|
nsWrapperCache **aCache)
|
2010-05-09 12:41:19 -07:00
|
|
|
{
|
|
|
|
nsINode *item = GetNamedItemHelper(mElements, aName);
|
|
|
|
*aCache = item;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
2011-05-31 14:47:59 -07:00
|
|
|
nsINode*
|
|
|
|
nsHTMLOptionCollection::GetParentObject()
|
|
|
|
{
|
|
|
|
return mSelect;
|
|
|
|
}
|
|
|
|
|
2008-10-31 14:40:35 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::NamedItem(const nsAString& aName,
|
|
|
|
nsIDOMNode** aReturn)
|
|
|
|
{
|
2010-05-09 12:41:19 -07:00
|
|
|
NS_IF_ADDREF(*aReturn = GetNamedItemHelper(mElements, aName));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-05-09 12:41:19 -07:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::GetSelect(nsIDOMHTMLSelectElement **aReturn)
|
|
|
|
{
|
|
|
|
NS_IF_ADDREF(*aReturn = mSelect);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2009-08-10 07:41:12 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::Add(nsIDOMHTMLOptionElement *aOption,
|
2011-07-21 03:16:28 -07:00
|
|
|
nsIVariant *aBefore)
|
2009-08-10 07:41:12 -07:00
|
|
|
{
|
|
|
|
if (!aOption) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mSelect) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
2011-07-21 03:16:28 -07:00
|
|
|
return mSelect->Add(aOption, aBefore);
|
2009-08-10 07:41:12 -07:00
|
|
|
}
|
2010-02-24 20:53:42 -08:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLOptionCollection::Remove(PRInt32 aIndex)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(mSelect, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
PRUint32 len = 0;
|
|
|
|
mSelect->GetLength(&len);
|
2010-03-11 22:50:13 -08:00
|
|
|
if (aIndex < 0 || (PRUint32)aIndex >= len)
|
2010-02-24 20:53:42 -08:00
|
|
|
aIndex = 0;
|
|
|
|
|
|
|
|
return mSelect->Remove(aIndex);
|
|
|
|
}
|
2010-09-18 14:33:16 -07:00
|
|
|
|
|
|
|
void
|
|
|
|
nsHTMLSelectElement::UpdateBarredFromConstraintValidation()
|
|
|
|
{
|
|
|
|
SetBarredFromConstraintValidation(IsDisabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::FieldSetDisabledChanged(bool aNotify)
|
2010-09-18 14:33:16 -07:00
|
|
|
{
|
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
|
2010-09-18 14:33:16 -07:00
|
|
|
}
|
|
|
|
|
2010-11-24 02:09:01 -08:00
|
|
|
void
|
2011-09-28 23:19:26 -07:00
|
|
|
nsHTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify)
|
2010-11-24 02:09:01 -08:00
|
|
|
{
|
|
|
|
if (!mDefaultSelectionSet) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool previousSelectionChangedValue = mSelectionHasChanged;
|
2010-11-24 02:09:01 -08:00
|
|
|
mSelectionHasChanged = aValue;
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
if (mSelectionHasChanged != previousSelectionChangedValue) {
|
|
|
|
UpdateState(aNotify);
|
2010-11-24 02:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|