2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-08-28 11:09:32 +04:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
#include "mozilla/dom/HTMLSelectElement.h"
|
2011-05-28 11:43:53 +04:00
|
|
|
|
2013-03-17 11:55:17 +04:00
|
|
|
#include "mozAutoDocUpdate.h"
|
2013-07-10 13:56:47 +04:00
|
|
|
#include "mozilla/Attributes.h"
|
2014-03-17 10:56:53 +04:00
|
|
|
#include "mozilla/BasicEvents.h"
|
2014-03-18 08:48:21 +04:00
|
|
|
#include "mozilla/EventDispatcher.h"
|
2014-04-03 08:18:36 +04:00
|
|
|
#include "mozilla/EventStates.h"
|
2013-03-17 11:55:17 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2016-06-16 10:24:16 +03:00
|
|
|
#include "mozilla/dom/HTMLFormSubmission.h"
|
2013-04-13 11:01:04 +04:00
|
|
|
#include "mozilla/dom/HTMLOptGroupElement.h"
|
2013-02-18 16:24:58 +04:00
|
|
|
#include "mozilla/dom/HTMLOptionElement.h"
|
2013-04-13 11:01:59 +04:00
|
|
|
#include "mozilla/dom/HTMLSelectElementBinding.h"
|
2014-10-01 22:43:26 +04:00
|
|
|
#include "mozilla/dom/UnionTypes.h"
|
2018-06-22 19:48:42 +03:00
|
|
|
#include "mozilla/MappedDeclarations.h"
|
2006-07-19 08:36:36 +04:00
|
|
|
#include "nsContentCreatorFunctions.h"
|
2013-09-02 21:23:27 +04:00
|
|
|
#include "nsContentList.h"
|
2013-03-17 11:55:17 +04:00
|
|
|
#include "nsError.h"
|
|
|
|
#include "nsGkAtoms.h"
|
2018-09-26 17:41:12 +03:00
|
|
|
#include "nsComboboxControlFrame.h"
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
1999-03-02 06:31:17 +03:00
|
|
|
#include "nsIFormControlFrame.h"
|
2013-03-17 11:55:17 +04:00
|
|
|
#include "nsIForm.h"
|
1999-01-30 04:02:28 +03:00
|
|
|
#include "nsIFrame.h"
|
2018-09-26 17:41:01 +03:00
|
|
|
#include "nsListControlFrame.h"
|
2013-03-17 11:55:17 +04:00
|
|
|
#include "nsISelectControlFrame.h"
|
|
|
|
#include "nsLayoutUtils.h"
|
|
|
|
#include "nsMappedAttributes.h"
|
2018-03-02 21:18:35 +03:00
|
|
|
#include "mozilla/PresState.h"
|
2013-03-17 11:55:17 +04:00
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsStyleConsts.h"
|
2013-04-04 16:01:08 +04:00
|
|
|
#include "nsTextNode.h"
|
2010-05-09 22:32:57 +04:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Select)
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2007-08-28 11:09:32 +04:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
2013-04-04 11:03:33 +04:00
|
|
|
// SafeOptionListMutation
|
2007-08-28 11:09:32 +04:00
|
|
|
//
|
2002-08-17 05:56:04 +04:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
SafeOptionListMutation::SafeOptionListMutation(nsIContent* aSelect,
|
|
|
|
nsIContent* aParent,
|
|
|
|
nsIContent* aKid,
|
|
|
|
uint32_t aIndex, bool aNotify)
|
2018-03-22 00:39:04 +03:00
|
|
|
: mSelect(HTMLSelectElement::FromNodeOrNull(aSelect)),
|
2011-10-17 18:59:28 +04:00
|
|
|
mTopLevelMutation(false),
|
|
|
|
mNeedsRebuild(false),
|
2016-11-25 00:15:33 +03:00
|
|
|
mNotify(aNotify),
|
|
|
|
mInitialSelectedIndex(-1) {
|
2011-04-12 16:32:00 +04:00
|
|
|
if (mSelect) {
|
2016-11-25 00:15:33 +03:00
|
|
|
mInitialSelectedIndex = mSelect->SelectedIndex();
|
2011-04-12 16:32:00 +04:00
|
|
|
mTopLevelMutation = !mSelect->mMutating;
|
2007-08-28 11:09:32 +04:00
|
|
|
if (mTopLevelMutation) {
|
2011-10-17 18:59:28 +04:00
|
|
|
mSelect->mMutating = true;
|
2002-10-03 07:43:11 +04:00
|
|
|
} else {
|
2007-08-28 11:09:32 +04: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.
|
2016-11-25 00:15:33 +03:00
|
|
|
mSelect->RebuildOptionsArray(mNotify);
|
2002-10-03 07:43:11 +04:00
|
|
|
}
|
2007-08-28 11:09:32 +04:00
|
|
|
nsresult rv;
|
|
|
|
if (aKid) {
|
2016-11-25 00:15:33 +03:00
|
|
|
rv = mSelect->WillAddOptions(aKid, aParent, aIndex, mNotify);
|
2007-08-28 11:09:32 +04:00
|
|
|
} else {
|
2016-11-25 00:15:33 +03:00
|
|
|
rv = mSelect->WillRemoveOptions(aParent, aIndex, mNotify);
|
2007-08-28 11:09:32 +04:00
|
|
|
}
|
|
|
|
mNeedsRebuild = NS_FAILED(rv);
|
2002-10-03 07:43:11 +04:00
|
|
|
}
|
2007-08-28 11:09:32 +04:00
|
|
|
}
|
2002-10-03 07:43:11 +04:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
SafeOptionListMutation::~SafeOptionListMutation() {
|
2007-08-28 11:09:32 +04:00
|
|
|
if (mSelect) {
|
|
|
|
if (mNeedsRebuild || (mTopLevelMutation && mGuard.Mutated(1))) {
|
2011-10-17 18:59:28 +04:00
|
|
|
mSelect->RebuildOptionsArray(true);
|
2007-08-28 11:09:32 +04:00
|
|
|
}
|
|
|
|
if (mTopLevelMutation) {
|
2011-10-17 18:59:28 +04:00
|
|
|
mSelect->mMutating = false;
|
2007-08-28 11:09:32 +04:00
|
|
|
}
|
2016-11-25 00:15:33 +03:00
|
|
|
if (mSelect->SelectedIndex() != mInitialSelectedIndex) {
|
|
|
|
// We must have triggered the SelectSomething() codepath, which can cause
|
|
|
|
// our validity to change. Unfortunately, our attempt to update validity
|
|
|
|
// in that case may not have worked correctly, because we actually call it
|
|
|
|
// before we have inserted the new <option>s into the DOM! Go ahead and
|
|
|
|
// update validity here as needed, because by now we know our <option>s
|
|
|
|
// are where they should be.
|
|
|
|
mSelect->UpdateValueMissingValidityState();
|
|
|
|
mSelect->UpdateState(mNotify);
|
|
|
|
}
|
2006-03-03 00:30:23 +03:00
|
|
|
#ifdef DEBUG
|
2011-04-12 16:32:00 +04:00
|
|
|
mSelect->VerifyOptionsArray();
|
2006-03-03 00:30:23 +03:00
|
|
|
#endif
|
2007-08-28 11:09:32 +04:00
|
|
|
}
|
|
|
|
}
|
1998-09-23 21:16:51 +04:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
2013-04-04 11:03:33 +04:00
|
|
|
// HTMLSelectElement
|
2001-11-02 10:40:01 +03:00
|
|
|
//
|
1998-09-23 21:16:51 +04:00
|
|
|
|
|
|
|
// construction, destruction
|
|
|
|
|
2018-09-21 23:45:49 +03:00
|
|
|
HTMLSelectElement::HTMLSelectElement(
|
|
|
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
2013-04-04 11:03:33 +04:00
|
|
|
FromParser aFromParser)
|
2019-07-01 13:06:16 +03:00
|
|
|
: nsGenericHTMLFormElementWithState(std::move(aNodeInfo), aFromParser,
|
|
|
|
NS_FORM_SELECT),
|
2015-01-07 08:39:46 +03:00
|
|
|
mOptions(new HTMLOptionsCollection(this)),
|
2014-07-24 18:55:00 +04:00
|
|
|
mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
|
2017-05-10 05:57:00 +03:00
|
|
|
mAutocompleteInfoState(nsContentUtils::eAutocompleteAttrState_Unknown),
|
2004-05-19 00:58:12 +04:00
|
|
|
mIsDoneAddingChildren(!aFromParser),
|
2011-10-17 18:59:28 +04:00
|
|
|
mDisabledChanged(false),
|
|
|
|
mMutating(false),
|
2010-10-25 16:17:38 +04:00
|
|
|
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
|
2011-10-17 18:59:28 +04:00
|
|
|
mSelectionHasChanged(false),
|
|
|
|
mDefaultSelectionSet(false),
|
|
|
|
mCanShowInvalidUI(true),
|
|
|
|
mCanShowValidUI(true),
|
2004-05-19 00:58:12 +04:00
|
|
|
mNonOptionChildren(0),
|
|
|
|
mOptGroupCount(0),
|
2006-03-03 00:30:23 +03:00
|
|
|
mSelectedIndex(-1) {
|
2013-12-17 17:58:32 +04:00
|
|
|
SetHasWeirdParserInsertionMode();
|
|
|
|
|
2002-03-31 14:14:01 +04:00
|
|
|
// DoneAddingChildren() will be called later if it's from the parser,
|
|
|
|
// otherwise it is
|
2011-06-01 05:46:57 +04:00
|
|
|
|
|
|
|
// Set up our default state: enabled, optional, and valid.
|
|
|
|
AddStatesSilently(NS_EVENT_STATE_ENABLED | NS_EVENT_STATE_OPTIONAL |
|
|
|
|
NS_EVENT_STATE_VALID);
|
1998-09-03 03:53:16 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 21:16:51 +04:00
|
|
|
// ISupports
|
1998-09-03 03:53:16 +04:00
|
|
|
|
2013-08-02 05:29:05 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLSelectElement)
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
|
2013-08-02 05:21:31 +04:00
|
|
|
HTMLSelectElement, nsGenericHTMLFormElementWithState)
|
2013-01-16 22:01:01 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
|
2012-11-15 11:32:40 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOptions)
|
2013-09-02 21:23:27 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedOptions)
|
2007-03-08 14:17:16 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
2013-04-04 11:03:33 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(
|
2013-08-02 05:21:31 +04:00
|
|
|
HTMLSelectElement, nsGenericHTMLFormElementWithState)
|
2013-01-16 22:01:01 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
|
2013-09-02 21:23:27 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedOptions)
|
2013-03-17 11:55:17 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
2007-03-08 14:17:16 +03:00
|
|
|
|
2017-09-01 02:29:22 +03:00
|
|
|
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLSelectElement,
|
|
|
|
nsGenericHTMLFormElementWithState,
|
|
|
|
nsIConstraintValidation)
|
2000-12-23 13:56:31 +03:00
|
|
|
|
1998-09-23 21:16:51 +04:00
|
|
|
// nsIDOMHTMLSelectElement
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
NS_IMPL_ELEMENT_CLONE(HTMLSelectElement)
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::SetCustomValidity(const nsAString& aError) {
|
2010-08-21 22:52:49 +04:00
|
|
|
nsIConstraintValidation::SetCustomValidity(aError);
|
2010-08-21 21:52:57 +04:00
|
|
|
|
2011-06-01 05:46:57 +04:00
|
|
|
UpdateState(true);
|
2010-08-21 21:52:57 +04:00
|
|
|
}
|
2010-08-18 22:28:08 +04:00
|
|
|
|
2014-07-24 18:55:00 +04:00
|
|
|
void HTMLSelectElement::GetAutocomplete(DOMString& aValue) {
|
|
|
|
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
|
|
|
|
|
|
|
mAutocompleteAttrState = nsContentUtils::SerializeAutocompleteAttribute(
|
|
|
|
attributeVal, aValue, mAutocompleteAttrState);
|
|
|
|
}
|
|
|
|
|
2017-03-14 09:28:00 +03:00
|
|
|
void HTMLSelectElement::GetAutocompleteInfo(AutocompleteInfo& aInfo) {
|
|
|
|
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
|
|
|
mAutocompleteInfoState = nsContentUtils::SerializeAutocompleteAttribute(
|
2017-05-10 05:57:00 +03:00
|
|
|
attributeVal, aInfo, mAutocompleteInfoState, true);
|
2017-03-14 09:28:00 +03:00
|
|
|
}
|
|
|
|
|
2018-01-25 17:59:42 +03:00
|
|
|
nsresult HTMLSelectElement::InsertChildBefore(nsIContent* aKid,
|
|
|
|
nsIContent* aBeforeThis,
|
|
|
|
bool aNotify) {
|
|
|
|
int32_t index = aBeforeThis ? ComputeIndexOf(aBeforeThis) : GetChildCount();
|
|
|
|
SafeOptionListMutation safeMutation(this, this, aKid, index, aNotify);
|
|
|
|
nsresult rv = nsGenericHTMLFormElementWithState::InsertChildBefore(
|
|
|
|
aKid, aBeforeThis, aNotify);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
safeMutation.MutationFailed();
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2018-01-15 19:18:38 +03:00
|
|
|
void HTMLSelectElement::RemoveChildNode(nsIContent* aKid, bool aNotify) {
|
2018-01-23 16:30:18 +03:00
|
|
|
SafeOptionListMutation safeMutation(this, this, nullptr, ComputeIndexOf(aKid),
|
|
|
|
aNotify);
|
2018-01-15 19:18:38 +03:00
|
|
|
nsGenericHTMLFormElementWithState::RemoveChildNode(aKid, aNotify);
|
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,
|
|
|
|
int32_t aListIndex,
|
|
|
|
int32_t aDepth, bool aNotify) {
|
2015-12-01 20:01:56 +03:00
|
|
|
MOZ_ASSERT(aDepth == 0 || aDepth == 1);
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t insertIndex = aListIndex;
|
2015-10-13 12:28:00 +03:00
|
|
|
|
2018-03-22 00:39:04 +03:00
|
|
|
HTMLOptionElement* optElement = HTMLOptionElement::FromNode(aOptions);
|
2015-10-13 12:28:00 +03:00
|
|
|
if (optElement) {
|
|
|
|
mOptions->InsertOptionAt(optElement, insertIndex);
|
|
|
|
insertIndex++;
|
2015-12-01 20:01:56 +03:00
|
|
|
} else if (aDepth == 0) {
|
2015-10-13 12:28:00 +03:00
|
|
|
// 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
|
2015-12-01 20:01:56 +03:00
|
|
|
mNonOptionChildren++;
|
2015-10-13 12:28:00 +03:00
|
|
|
|
|
|
|
// Deal with optgroups
|
|
|
|
if (aOptions->IsHTMLElement(nsGkAtoms::optgroup)) {
|
|
|
|
mOptGroupCount++;
|
|
|
|
|
|
|
|
for (nsIContent* child = aOptions->GetFirstChild(); child;
|
|
|
|
child = child->GetNextSibling()) {
|
2018-03-22 00:39:04 +03:00
|
|
|
optElement = HTMLOptionElement::FromNode(child);
|
2015-10-13 12:28:00 +03:00
|
|
|
if (optElement) {
|
|
|
|
mOptions->InsertOptionAt(optElement, insertIndex);
|
|
|
|
insertIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-01 20:01:56 +03:00
|
|
|
} // else ignore even if optgroup; we want to ignore nested optgroups.
|
2001-11-02 10:40:01 +03:00
|
|
|
|
|
|
|
// Deal with the selected list
|
|
|
|
if (insertIndex - aListIndex) {
|
|
|
|
// Fix the currently selected index
|
|
|
|
if (aListIndex <= mSelectedIndex) {
|
|
|
|
mSelectedIndex += (insertIndex - aListIndex);
|
2011-10-17 18:59:28 +04:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2001-11-06 12:10:07 +03: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.
|
2012-07-30 18:20:58 +04:00
|
|
|
nsISelectControlFrame* selectFrame = nullptr;
|
2017-03-01 20:03:14 +03:00
|
|
|
AutoWeakFrame weakSelectFrame;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool didGetFrame = false;
|
2001-11-02 10:40:01 +03:00
|
|
|
|
|
|
|
// Actually select the options if the added options warrant it
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t i = aListIndex; i < insertIndex; i++) {
|
2001-11-02 10:40:01 +03:00
|
|
|
// Notify the frame that the option is added
|
2009-02-18 06:27:25 +03:00
|
|
|
if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
|
|
|
|
selectFrame = GetSelectFrame();
|
|
|
|
weakSelectFrame = do_QueryFrame(selectFrame);
|
2011-10-17 18:59:28 +04:00
|
|
|
didGetFrame = true;
|
2009-02-18 06:27:25 +03:00
|
|
|
}
|
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
if (selectFrame) {
|
2009-02-18 06:27:25 +03:00
|
|
|
selectFrame->AddOption(i);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<HTMLOptionElement> option = Item(i);
|
2013-07-24 11:35:44 +04:00
|
|
|
if (option && option->Selected()) {
|
|
|
|
// Clear all other options
|
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
2013-09-28 23:04:20 +04:00
|
|
|
uint32_t mask = IS_SELECTED | CLEAR_ALL | SET_DISABLED | NOTIFY;
|
|
|
|
SetOptionsSelectedByIndex(i, i, mask);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2013-07-24 11:35:44 +04: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.
|
|
|
|
OnOptionSelected(selectFrame, i, true, false, false);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-17 02:41:19 +03:00
|
|
|
CheckSelectSomething(aNotify);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
nsresult HTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
|
|
|
|
int32_t aListIndex,
|
|
|
|
int32_t aDepth,
|
|
|
|
bool aNotify) {
|
2015-12-01 20:01:56 +03:00
|
|
|
MOZ_ASSERT(aDepth == 0 || aDepth == 1);
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t numRemoved = 0;
|
2015-10-13 12:28:00 +03:00
|
|
|
|
2018-03-22 00:39:04 +03:00
|
|
|
HTMLOptionElement* optElement = HTMLOptionElement::FromNode(aOptions);
|
2015-10-13 12:28:00 +03:00
|
|
|
if (optElement) {
|
|
|
|
if (mOptions->ItemAsOption(aListIndex) != optElement) {
|
|
|
|
NS_ERROR("wrong option at index");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
mOptions->RemoveOptionAt(aListIndex);
|
|
|
|
numRemoved++;
|
2015-12-01 20:01:56 +03:00
|
|
|
} else if (aDepth == 0) {
|
2015-10-13 12:28:00 +03:00
|
|
|
// Yay, one less artifact at the top level.
|
2015-12-01 20:01:56 +03:00
|
|
|
mNonOptionChildren--;
|
2015-10-13 12:28:00 +03:00
|
|
|
|
|
|
|
// Recurse down deeper for options
|
|
|
|
if (mOptGroupCount && aOptions->IsHTMLElement(nsGkAtoms::optgroup)) {
|
|
|
|
mOptGroupCount--;
|
|
|
|
|
|
|
|
for (nsIContent* child = aOptions->GetFirstChild(); child;
|
|
|
|
child = child->GetNextSibling()) {
|
2018-03-22 00:39:04 +03:00
|
|
|
optElement = HTMLOptionElement::FromNode(child);
|
2015-10-13 12:28:00 +03:00
|
|
|
if (optElement) {
|
|
|
|
if (mOptions->ItemAsOption(aListIndex) != optElement) {
|
|
|
|
NS_ERROR("wrong option at index");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
mOptions->RemoveOptionAt(aListIndex);
|
|
|
|
numRemoved++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-01 20:01:56 +03:00
|
|
|
} // else don't check for an optgroup; we want to ignore nested optgroups
|
2002-08-06 08:59:15 +04:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
if (numRemoved) {
|
|
|
|
// Tell the widget we removed the options
|
2001-12-12 10:31:15 +03:00
|
|
|
nsISelectControlFrame* selectFrame = GetSelectFrame();
|
2001-11-06 12:10:07 +03:00
|
|
|
if (selectFrame) {
|
2009-02-18 06:27:25 +03:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t i = aListIndex; i < aListIndex + numRemoved; ++i) {
|
2009-02-18 06:27:25 +03:00
|
|
|
selectFrame->RemoveOption(i);
|
2001-11-02 10:40:01 +03: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 13:09:01 +03:00
|
|
|
FindSelectedIndex(aListIndex, aNotify);
|
2001-11-02 10:40:01 +03:00
|
|
|
} else {
|
|
|
|
// Shift the selected index if something in front of it was removed
|
|
|
|
// aListIndex+numRemoved <= mSelectedIndex
|
|
|
|
mSelectedIndex -= numRemoved;
|
2011-10-17 18:59:28 +04:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select something in case we removed the selected option on a
|
|
|
|
// single select
|
2010-11-17 02:41:19 +03:00
|
|
|
if (!CheckSelectSomething(aNotify) && mSelectedIndex == -1) {
|
|
|
|
// Update the validity state in case of we've just removed the last
|
|
|
|
// option.
|
|
|
|
UpdateValueMissingValidityState();
|
|
|
|
|
2011-06-01 05:46:57 +04:00
|
|
|
UpdateState(aNotify);
|
2010-11-17 02:41:19 +03:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-08-19 22:35:09 +04:00
|
|
|
// 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.
|
2001-11-02 10:40:01 +03:00
|
|
|
NS_IMETHODIMP
|
2013-04-04 11:03:33 +04:00
|
|
|
HTMLSelectElement::WillAddOptions(nsIContent* aOptions, nsIContent* aParent,
|
|
|
|
int32_t aContentIndex, bool aNotify) {
|
2015-10-13 12:28:00 +03:00
|
|
|
if (this != aParent && this != aParent->GetParent()) {
|
|
|
|
return NS_OK;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2015-10-13 12:28:00 +03:00
|
|
|
int32_t level = aParent == this ? 0 : 1;
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// Get the index where the options will be inserted
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t ind = -1;
|
2004-01-10 02:54:21 +03:00
|
|
|
if (!mNonOptionChildren) {
|
2002-08-20 01:25:51 +04:00
|
|
|
// If there are no artifacts, aContentIndex == ind
|
|
|
|
ind = aContentIndex;
|
2001-11-02 10:40:01 +03:00
|
|
|
} else {
|
2002-08-20 01:25:51 +04:00
|
|
|
// If there are artifacts, we have to get the index of the option the
|
|
|
|
// hard way
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t children = aParent->GetChildCount();
|
2003-09-27 08:18:26 +04:00
|
|
|
|
2002-08-20 01:25:51 +04:00
|
|
|
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.
|
2018-01-03 15:59:54 +03:00
|
|
|
nsIContent* currentKid = aParent->GetChildAt_Deprecated(aContentIndex);
|
2002-08-20 01:25:51 +04:00
|
|
|
NS_ASSERTION(currentKid, "Child not found!");
|
|
|
|
if (currentKid) {
|
|
|
|
ind = GetOptionIndexAt(currentKid);
|
|
|
|
} else {
|
|
|
|
ind = -1;
|
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2000-07-12 00:55:21 +04:00
|
|
|
}
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2013-07-24 11:35:08 +04:00
|
|
|
InsertOptionsIntoList(aOptions, ind, level, aNotify);
|
|
|
|
return NS_OK;
|
2000-07-12 00:55:21 +04:00
|
|
|
}
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2000-07-12 00:55:21 +04:00
|
|
|
NS_IMETHODIMP
|
2013-04-04 11:03:33 +04:00
|
|
|
HTMLSelectElement::WillRemoveOptions(nsIContent* aParent, int32_t aContentIndex,
|
|
|
|
bool aNotify) {
|
2015-10-13 12:28:00 +03:00
|
|
|
if (this != aParent && this != aParent->GetParent()) {
|
|
|
|
return NS_OK;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2015-10-13 12:28:00 +03:00
|
|
|
int32_t level = this == aParent ? 0 : 1;
|
2001-11-02 10:40:01 +03:00
|
|
|
|
|
|
|
// Get the index where the options will be removed
|
2018-01-03 15:59:54 +03:00
|
|
|
nsIContent* currentKid = aParent->GetChildAt_Deprecated(aContentIndex);
|
2001-11-02 10:40:01 +03:00
|
|
|
if (currentKid) {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t ind;
|
2004-01-10 02:54:21 +03:00
|
|
|
if (!mNonOptionChildren) {
|
2002-08-20 01:25:51 +04:00
|
|
|
// 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);
|
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
if (ind != -1) {
|
2010-11-17 02:41:19 +03:00
|
|
|
nsresult rv = RemoveOptionsFromList(currentKid, ind, level, aNotify);
|
2006-03-03 00:30:23 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-03 00:30:23 +03:00
|
|
|
return NS_OK;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
int32_t HTMLSelectElement::GetOptionIndexAt(nsIContent* aOptions) {
|
2001-11-02 10:40:01 +03:00
|
|
|
// Search this node and below.
|
|
|
|
// If not found, find the first one *after* this node.
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t retval = GetFirstOptionIndex(aOptions);
|
2002-08-06 08:59:15 +04:00
|
|
|
if (retval == -1) {
|
|
|
|
retval = GetOptionIndexAfter(aOptions);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
return retval;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
int32_t HTMLSelectElement::GetOptionIndexAfter(nsIContent* aOptions) {
|
2001-11-02 10:40:01 +03:00
|
|
|
// - 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) {
|
2015-10-13 12:28:00 +03:00
|
|
|
return Length();
|
2002-08-06 08:59:15 +04:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t retval = -1;
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2003-07-29 01:09:56 +04:00
|
|
|
nsCOMPtr<nsIContent> parent = aOptions->GetParent();
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
if (parent) {
|
2018-01-23 16:30:18 +03:00
|
|
|
int32_t index = parent->ComputeIndexOf(aOptions);
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t count = parent->GetChildCount();
|
2002-08-06 08:59:15 +04:00
|
|
|
|
|
|
|
retval = GetFirstChildOptionIndex(parent, index + 1, count);
|
|
|
|
|
|
|
|
if (retval == -1) {
|
|
|
|
retval = GetOptionIndexAfter(parent);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
return retval;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
int32_t HTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions) {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t listIndex = -1;
|
2018-03-22 00:39:04 +03:00
|
|
|
HTMLOptionElement* optElement = HTMLOptionElement::FromNode(aOptions);
|
2001-11-02 10:40:01 +03:00
|
|
|
if (optElement) {
|
2018-05-19 06:37:56 +03:00
|
|
|
mOptions->GetOptionIndex(optElement, 0, true, &listIndex);
|
2002-08-06 08:59:15 +04:00
|
|
|
return listIndex;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2003-09-27 08:18:26 +04:00
|
|
|
listIndex = GetFirstChildOptionIndex(aOptions, 0, aOptions->GetChildCount());
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
return listIndex;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
int32_t HTMLSelectElement::GetFirstChildOptionIndex(nsIContent* aOptions,
|
|
|
|
int32_t aStartIndex,
|
|
|
|
int32_t aEndIndex) {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t retval = -1;
|
2003-09-27 08:18:26 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t i = aStartIndex; i < aEndIndex; ++i) {
|
2018-01-03 15:59:54 +03:00
|
|
|
retval = GetFirstOptionIndex(aOptions->GetChildAt_Deprecated(i));
|
2002-08-06 08:59:15 +04:00
|
|
|
if (retval != -1) {
|
|
|
|
break;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2000-07-12 00:55:21 +04:00
|
|
|
}
|
1999-07-28 09:26:55 +04:00
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
return retval;
|
1999-07-28 09:26:55 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
nsISelectControlFrame* HTMLSelectElement::GetSelectFrame() {
|
2011-10-17 18:59:28 +04:00
|
|
|
nsIFormControlFrame* form_control_frame = GetFormControlFrame(false);
|
2001-11-06 12:10:07 +03:00
|
|
|
|
2013-02-18 16:24:58 +04:00
|
|
|
nsISelectControlFrame* select_frame = nullptr;
|
2001-11-06 12:10:07 +03:00
|
|
|
|
|
|
|
if (form_control_frame) {
|
2009-01-12 22:20:59 +03:00
|
|
|
select_frame = do_QueryFrame(form_control_frame);
|
2001-11-06 12:10:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return select_frame;
|
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2013-04-13 11:01:04 +04:00
|
|
|
void HTMLSelectElement::Add(
|
|
|
|
const HTMLOptionElementOrHTMLOptGroupElement& aElement,
|
|
|
|
const Nullable<HTMLElementOrLong>& aBefore, ErrorResult& aRv) {
|
|
|
|
nsGenericHTMLElement& element =
|
|
|
|
aElement.IsHTMLOptionElement() ? static_cast<nsGenericHTMLElement&>(
|
|
|
|
aElement.GetAsHTMLOptionElement())
|
|
|
|
: static_cast<nsGenericHTMLElement&>(
|
|
|
|
aElement.GetAsHTMLOptGroupElement());
|
|
|
|
|
|
|
|
if (aBefore.IsNull()) {
|
|
|
|
Add(element, static_cast<nsGenericHTMLElement*>(nullptr), aRv);
|
|
|
|
} else if (aBefore.Value().IsHTMLElement()) {
|
|
|
|
Add(element, &aBefore.Value().GetAsHTMLElement(), aRv);
|
|
|
|
} else {
|
|
|
|
Add(element, aBefore.Value().GetAsLong(), aRv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::Add(nsGenericHTMLElement& aElement,
|
|
|
|
nsGenericHTMLElement* aBefore,
|
|
|
|
ErrorResult& aError) {
|
2003-01-08 06:07:03 +03:00
|
|
|
if (!aBefore) {
|
2013-08-08 00:23:08 +04:00
|
|
|
Element::AppendChild(aElement, aError);
|
2012-11-11 03:30:15 +04:00
|
|
|
return;
|
2003-01-08 06:07:03 +03:00
|
|
|
}
|
1999-05-05 00:53:26 +04:00
|
|
|
|
2003-01-08 06:07:03 +03:00
|
|
|
// Just in case we're not the parent, get the parent of the reference
|
|
|
|
// element
|
2016-02-24 03:23:43 +03:00
|
|
|
nsCOMPtr<nsINode> parent = aBefore->Element::GetParentNode();
|
2019-07-12 16:10:28 +03:00
|
|
|
if (!parent || !parent->IsInclusiveDescendantOf(this)) {
|
2003-01-08 06:07:03 +03:00
|
|
|
// NOT_FOUND_ERR: Raised if before is not a descendant of the SELECT
|
|
|
|
// element.
|
2012-11-11 03:30:15 +04:00
|
|
|
aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
|
|
|
|
return;
|
1999-05-05 00:53:26 +04:00
|
|
|
}
|
|
|
|
|
2003-01-08 06:07:03 +03:00
|
|
|
// If the before parameter is not null, we are equivalent to the
|
|
|
|
// insertBefore method on the parent of before.
|
2016-10-14 15:33:42 +03:00
|
|
|
nsCOMPtr<nsINode> refNode = aBefore;
|
|
|
|
parent->InsertBefore(aElement, refNode, aError);
|
1998-09-23 21:16:51 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::Remove(int32_t aIndex) {
|
2018-10-17 04:35:21 +03:00
|
|
|
if (aIndex < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-24 11:36:54 +04:00
|
|
|
nsCOMPtr<nsINode> option = Item(static_cast<uint32_t>(aIndex));
|
|
|
|
if (!option) {
|
2017-10-13 02:32:25 +03:00
|
|
|
return;
|
1998-09-23 21:16:51 +04:00
|
|
|
}
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2013-07-24 11:36:54 +04:00
|
|
|
option->Remove();
|
1998-09-03 03:53:16 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::GetType(nsAString& aType) {
|
2010-10-08 16:15:00 +04:00
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
2004-06-17 04:13:25 +04:00
|
|
|
aType.AssignLiteral("select-multiple");
|
2003-01-08 06:07:03 +03:00
|
|
|
} else {
|
2004-06-17 04:13:25 +04:00
|
|
|
aType.AssignLiteral("select-one");
|
1998-10-20 21:07:23 +04:00
|
|
|
}
|
1999-05-05 00:53:26 +04:00
|
|
|
}
|
|
|
|
|
2008-11-12 06:36:20 +03:00
|
|
|
#define MAX_DYNAMIC_SELECT_LENGTH 10000
|
|
|
|
|
2013-07-24 11:36:59 +04:00
|
|
|
void HTMLSelectElement::SetLength(uint32_t aLength, ErrorResult& aRv) {
|
|
|
|
uint32_t curlen = Length();
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2008-11-12 06:36:20 +03:00
|
|
|
if (curlen > aLength) { // Remove extra options
|
2013-07-24 11:36:59 +04:00
|
|
|
for (uint32_t i = curlen; i > aLength; --i) {
|
2017-10-13 02:32:25 +03:00
|
|
|
Remove(i - 1);
|
2008-11-12 06:36:20 +03:00
|
|
|
}
|
|
|
|
} else if (aLength > curlen) {
|
|
|
|
if (aLength > MAX_DYNAMIC_SELECT_LENGTH) {
|
2013-07-24 11:36:59 +04:00
|
|
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
|
|
|
return;
|
2000-04-20 16:34:35 +04:00
|
|
|
}
|
2013-07-24 11:36:59 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<mozilla::dom::NodeInfo> nodeInfo;
|
2000-05-10 17:13:39 +04:00
|
|
|
|
2017-02-21 06:44:00 +03:00
|
|
|
nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::option,
|
|
|
|
getter_AddRefs(nodeInfo));
|
2000-04-20 16:34:35 +04:00
|
|
|
|
2013-07-24 11:36:59 +04:00
|
|
|
nsCOMPtr<nsINode> node = NS_NewHTMLOptionElement(nodeInfo.forget());
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = curlen; i < aLength; i++) {
|
2013-07-24 11:36:59 +04:00
|
|
|
nsINode::AppendChild(*node, aRv);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
2000-04-20 16:34:35 +04:00
|
|
|
|
2010-03-12 09:50:13 +03:00
|
|
|
if (i + 1 < aLength) {
|
2013-07-24 11:36:59 +04:00
|
|
|
node = node->CloneNode(true, aRv);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(node);
|
2000-04-20 16:34:35 +04:00
|
|
|
}
|
2000-02-24 03:08:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-02 21:23:27 +04:00
|
|
|
/* static */
|
2017-02-14 00:06:45 +03:00
|
|
|
bool HTMLSelectElement::MatchSelectedOptions(Element* aElement,
|
2013-09-02 21:23:27 +04:00
|
|
|
int32_t /* unused */,
|
2017-10-03 01:05:19 +03:00
|
|
|
nsAtom* /* unused */,
|
2013-09-02 21:23:27 +04:00
|
|
|
void* /* unused*/) {
|
2018-03-22 00:39:04 +03:00
|
|
|
HTMLOptionElement* option = HTMLOptionElement::FromNode(aElement);
|
2013-09-02 21:23:27 +04:00
|
|
|
return option && option->Selected();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIHTMLCollection* HTMLSelectElement::SelectedOptions() {
|
|
|
|
if (!mSelectedOptions) {
|
|
|
|
mSelectedOptions = new nsContentList(this, MatchSelectedOptions, nullptr,
|
|
|
|
nullptr, /* deep */ true);
|
|
|
|
}
|
|
|
|
return mSelectedOptions;
|
|
|
|
}
|
|
|
|
|
2019-01-22 22:03:07 +03:00
|
|
|
void HTMLSelectElement::SetSelectedIndexInternal(int32_t aIndex, bool aNotify) {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t oldSelectedIndex = mSelectedIndex;
|
2013-09-28 23:04:20 +04:00
|
|
|
uint32_t mask = IS_SELECTED | CLEAR_ALL | SET_DISABLED;
|
|
|
|
if (aNotify) {
|
|
|
|
mask |= NOTIFY;
|
|
|
|
}
|
2005-02-05 01:56:13 +03:00
|
|
|
|
2013-09-28 23:04:20 +04:00
|
|
|
SetOptionsSelectedByIndex(aIndex, aIndex, mask);
|
2005-02-05 01:56:13 +03:00
|
|
|
|
2013-07-24 11:37:14 +04:00
|
|
|
nsISelectControlFrame* selectFrame = GetSelectFrame();
|
|
|
|
if (selectFrame) {
|
2019-01-22 22:03:07 +03:00
|
|
|
selectFrame->OnSetSelectedIndex(oldSelectedIndex, mSelectedIndex);
|
2005-02-05 01:56:13 +03:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2000-09-05 17:37:16 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
bool HTMLSelectElement::IsOptionSelectedByIndex(int32_t aIndex) {
|
2013-07-24 11:37:03 +04:00
|
|
|
HTMLOptionElement* option = Item(static_cast<uint32_t>(aIndex));
|
|
|
|
return option && option->Selected();
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2000-09-05 17:37:16 +04:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
|
|
|
|
int32_t aIndex, bool aSelected,
|
|
|
|
bool aChangeOptionState,
|
|
|
|
bool aNotify) {
|
2001-11-02 10:40:01 +03:00
|
|
|
// Set the selected index
|
|
|
|
if (aSelected && (aIndex < mSelectedIndex || mSelectedIndex < 0)) {
|
|
|
|
mSelectedIndex = aIndex;
|
2011-10-17 18:59:28 +04:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2001-11-02 10:40:01 +03:00
|
|
|
} else if (!aSelected && aIndex == mSelectedIndex) {
|
2011-11-16 11:50:19 +04:00
|
|
|
FindSelectedIndex(aIndex + 1, aNotify);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2007-12-04 19:50:32 +03:00
|
|
|
if (aChangeOptionState) {
|
|
|
|
// Tell the option to get its bad self selected
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<HTMLOptionElement> option = Item(static_cast<uint32_t>(aIndex));
|
2007-12-04 19:50:32 +03:00
|
|
|
if (option) {
|
2013-07-24 11:37:07 +04:00
|
|
|
option->SetSelectedInternal(aSelected, aNotify);
|
2007-12-04 19:50:32 +03:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Let the frame know too
|
|
|
|
if (aSelectFrame) {
|
2009-02-18 06:27:25 +03:00
|
|
|
aSelectFrame->OnOptionSelected(aIndex, aSelected);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2010-11-17 02:41:19 +03:00
|
|
|
|
2013-09-02 21:23:27 +04:00
|
|
|
UpdateSelectedOptions();
|
2010-11-17 02:41:19 +03:00
|
|
|
UpdateValueMissingValidityState();
|
2011-06-01 05:46:57 +04:00
|
|
|
UpdateState(aNotify);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::FindSelectedIndex(int32_t aStartIndex, bool aNotify) {
|
2001-11-02 10:40:01 +03:00
|
|
|
mSelectedIndex = -1;
|
2011-10-17 18:59:28 +04:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2013-07-24 11:37:10 +04:00
|
|
|
uint32_t len = Length();
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t i = aStartIndex; i < int32_t(len); i++) {
|
2002-08-06 08:59:15 +04:00
|
|
|
if (IsOptionSelectedByIndex(i)) {
|
2001-11-02 10:40:01 +03:00
|
|
|
mSelectedIndex = i;
|
2011-10-17 18:59:28 +04:00
|
|
|
SetSelectionChanged(true, aNotify);
|
2001-11-02 10:40:01 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-09-05 17:37:16 +04:00
|
|
|
}
|
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// 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 19:50:32 +03: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.
|
2013-04-04 11:03:33 +04:00
|
|
|
bool HTMLSelectElement::SetOptionsSelectedByIndex(int32_t aStartIndex,
|
|
|
|
int32_t aEndIndex,
|
2013-09-28 23:04:20 +04:00
|
|
|
uint32_t aOptionsMask) {
|
2001-11-02 10:40:01 +03:00
|
|
|
#if 0
|
|
|
|
printf("SetOption(%d-%d, %c, ClearAll=%c)\n", aStartIndex, aEndIndex,
|
2013-09-28 23:04:20 +04:00
|
|
|
(aOptionsMask & IS_SELECTED ? 'Y' : 'N'),
|
|
|
|
(aOptionsMask & CLEAR_ALL ? 'Y' : 'N'));
|
2001-11-02 10:40:01 +03:00
|
|
|
#endif
|
|
|
|
// Don't bother if the select is disabled
|
2013-09-28 23:04:20 +04:00
|
|
|
if (!(aOptionsMask & SET_DISABLED) && IsDisabled()) {
|
2013-07-24 11:37:14 +04:00
|
|
|
return false;
|
2000-09-05 17:37:16 +04:00
|
|
|
}
|
2000-02-12 19:26:24 +03:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// Don't bother if there are no options
|
2013-07-24 11:37:14 +04:00
|
|
|
uint32_t numItems = Length();
|
2001-11-02 10:40:01 +03:00
|
|
|
if (numItems == 0) {
|
2013-07-24 11:37:14 +04:00
|
|
|
return false;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2000-02-12 19:26:24 +03:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// First, find out whether multiple items can be selected
|
2013-07-24 11:37:14 +04:00
|
|
|
bool isMultiple = Multiple();
|
2000-09-05 17:37:16 +04:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// These variables tell us whether any options were selected
|
|
|
|
// or deselected.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool optionsSelected = false;
|
|
|
|
bool optionsDeselected = false;
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2013-02-18 16:24:58 +04:00
|
|
|
nsISelectControlFrame* selectFrame = nullptr;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool didGetFrame = false;
|
2017-03-01 20:03:14 +03:00
|
|
|
AutoWeakFrame weakSelectFrame;
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2013-09-28 23:04:20 +04:00
|
|
|
if (aOptionsMask & IS_SELECTED) {
|
2009-01-02 18:54:48 +03:00
|
|
|
// Setting selectedIndex to an out-of-bounds index means -1. (HTML5)
|
2014-08-25 23:17:32 +04:00
|
|
|
if (aStartIndex < 0 || AssertedCast<uint32_t>(aStartIndex) >= numItems ||
|
|
|
|
aEndIndex < 0 || AssertedCast<uint32_t>(aEndIndex) >= numItems) {
|
2009-01-02 18:54:48 +03:00
|
|
|
aStartIndex = -1;
|
|
|
|
aEndIndex = -1;
|
|
|
|
}
|
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// Only select the first value if it's not multiple
|
|
|
|
if (!isMultiple) {
|
|
|
|
aEndIndex = aStartIndex;
|
2000-09-05 17:37:16 +04:00
|
|
|
}
|
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// 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.)
|
2013-09-28 23:04:20 +04:00
|
|
|
bool allDisabled = !(aOptionsMask & SET_DISABLED);
|
2001-11-02 10:40:01 +03:00
|
|
|
|
|
|
|
//
|
|
|
|
// Save a little time when clearing other options
|
|
|
|
//
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t previousSelectedIndex = mSelectedIndex;
|
2001-11-02 10:40:01 +03:00
|
|
|
|
|
|
|
//
|
|
|
|
// Select the requested indices
|
|
|
|
//
|
|
|
|
// If index is -1, everything will be deselected (bug 28143)
|
|
|
|
if (aStartIndex != -1) {
|
2013-07-24 11:37:14 +04:00
|
|
|
MOZ_ASSERT(aStartIndex >= 0);
|
|
|
|
MOZ_ASSERT(aEndIndex >= 0);
|
2001-11-02 10:40:01 +03:00
|
|
|
// Loop through the options and select them (if they are not disabled and
|
|
|
|
// if they are not already selected).
|
2014-08-25 23:17:32 +04:00
|
|
|
for (uint32_t optIndex = AssertedCast<uint32_t>(aStartIndex);
|
|
|
|
optIndex <= AssertedCast<uint32_t>(aEndIndex); optIndex++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<HTMLOptionElement> option = Item(optIndex);
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// Ignore disabled options.
|
2013-09-28 23:04:20 +04:00
|
|
|
if (!(aOptionsMask & SET_DISABLED)) {
|
2013-07-24 11:37:14 +04:00
|
|
|
if (option && IsOptionDisabled(option)) {
|
2001-11-02 10:40:01 +03:00
|
|
|
continue;
|
2000-03-21 18:46:43 +03:00
|
|
|
}
|
2013-07-24 11:37:14 +04:00
|
|
|
allDisabled = false;
|
2000-02-12 19:26:24 +03:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2013-07-24 11:37:14 +04:00
|
|
|
// If the index is already selected, ignore it.
|
|
|
|
if (option && !option->Selected()) {
|
|
|
|
// 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();
|
|
|
|
weakSelectFrame = do_QueryFrame(selectFrame);
|
|
|
|
didGetFrame = true;
|
|
|
|
|
2013-09-28 23:04:20 +04:00
|
|
|
OnOptionSelected(selectFrame, optIndex, true, true,
|
|
|
|
aOptionsMask & NOTIFY);
|
2013-07-24 11:37:14 +04:00
|
|
|
optionsSelected = true;
|
2001-11-02 10:40:01 +03: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) ||
|
2013-09-28 23:04:20 +04:00
|
|
|
((aOptionsMask & CLEAR_ALL) && !allDisabled) || aStartIndex == -1) &&
|
2001-11-02 10:40:01 +03:00
|
|
|
previousSelectedIndex != -1) {
|
2014-08-25 23:17:32 +04:00
|
|
|
for (uint32_t optIndex = AssertedCast<uint32_t>(previousSelectedIndex);
|
2013-07-24 11:37:14 +04:00
|
|
|
optIndex < numItems; optIndex++) {
|
|
|
|
if (static_cast<int32_t>(optIndex) < aStartIndex ||
|
|
|
|
static_cast<int32_t>(optIndex) > aEndIndex) {
|
|
|
|
HTMLOptionElement* option = Item(optIndex);
|
|
|
|
// If the index is already selected, ignore it.
|
|
|
|
if (option && option->Selected()) {
|
|
|
|
if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
|
|
|
|
// 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();
|
|
|
|
weakSelectFrame = do_QueryFrame(selectFrame);
|
|
|
|
|
|
|
|
didGetFrame = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
OnOptionSelected(selectFrame, optIndex, false, true,
|
2013-09-28 23:04:20 +04:00
|
|
|
aOptionsMask & NOTIFY);
|
2013-07-24 11:37:14 +04:00
|
|
|
optionsDeselected = true;
|
|
|
|
|
|
|
|
// Only need to deselect one option if not multiple
|
|
|
|
if (!isMultiple) {
|
|
|
|
break;
|
2000-09-05 17:37:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-03-21 18:46:43 +03:00
|
|
|
}
|
2000-09-05 17:37:16 +04:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
} else {
|
|
|
|
// If we're deselecting, loop through all selected items and deselect
|
|
|
|
// any that are in the specified range.
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t optIndex = aStartIndex; optIndex <= aEndIndex; optIndex++) {
|
2013-07-24 11:37:14 +04:00
|
|
|
HTMLOptionElement* option = Item(optIndex);
|
2013-09-28 23:04:20 +04:00
|
|
|
if (!(aOptionsMask & SET_DISABLED) && IsOptionDisabled(option)) {
|
2013-07-24 11:37:14 +04:00
|
|
|
continue;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2013-07-24 11:37:14 +04:00
|
|
|
// If the index is already selected, ignore it.
|
|
|
|
if (option && option->Selected()) {
|
|
|
|
if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
|
|
|
|
// 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();
|
|
|
|
weakSelectFrame = do_QueryFrame(selectFrame);
|
|
|
|
|
|
|
|
didGetFrame = true;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2013-07-24 11:37:14 +04:00
|
|
|
|
2013-09-28 23:04:20 +04:00
|
|
|
OnOptionSelected(selectFrame, optIndex, false, true,
|
|
|
|
aOptionsMask & NOTIFY);
|
2013-07-24 11:37:14 +04:00
|
|
|
optionsDeselected = true;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2000-09-05 17:37:16 +04:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2003-03-14 09:18:20 +03:00
|
|
|
// Make sure something is selected unless we were set to -1 (none)
|
2017-05-18 09:44:00 +03:00
|
|
|
if (optionsDeselected && aStartIndex != -1 && !(aOptionsMask & NO_RESELECT)) {
|
2013-09-28 23:04:20 +04:00
|
|
|
optionsSelected =
|
|
|
|
CheckSelectSomething(aOptionsMask & NOTIFY) || optionsSelected;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Let the caller know whether anything was changed
|
2013-07-24 11:37:14 +04:00
|
|
|
return optionsSelected || optionsDeselected;
|
1999-01-30 04:02:28 +03:00
|
|
|
}
|
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
NS_IMETHODIMP
|
2013-04-04 11:03:33 +04:00
|
|
|
HTMLSelectElement::IsOptionDisabled(int32_t aIndex, bool* aIsDisabled) {
|
2011-10-17 18:59:28 +04:00
|
|
|
*aIsDisabled = false;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<HTMLOptionElement> option = Item(aIndex);
|
2013-07-24 11:31:49 +04:00
|
|
|
NS_ENSURE_TRUE(option, NS_ERROR_FAILURE);
|
2002-04-19 01:54:57 +04:00
|
|
|
|
2013-07-24 11:31:49 +04:00
|
|
|
*aIsDisabled = IsOptionDisabled(option);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-08-03 08:23:00 +03:00
|
|
|
bool HTMLSelectElement::IsOptionDisabled(HTMLOptionElement* aOption) const {
|
2013-07-24 11:31:49 +04:00
|
|
|
MOZ_ASSERT(aOption);
|
|
|
|
if (aOption->Disabled()) {
|
|
|
|
return true;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
1999-09-17 11:24:02 +04:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// Check for disabled optgroups
|
|
|
|
// If there are no artifacts, there are no optgroups
|
2002-08-20 01:25:51 +04:00
|
|
|
if (mNonOptionChildren) {
|
2013-07-24 11:36:59 +04:00
|
|
|
for (nsCOMPtr<Element> node =
|
|
|
|
static_cast<nsINode*>(aOption)->GetParentElement();
|
2013-07-24 11:31:49 +04:00
|
|
|
node; node = node->GetParentElement()) {
|
2001-11-02 10:40:01 +03:00
|
|
|
// If we reached the select element, we're done
|
2015-03-03 14:08:59 +03:00
|
|
|
if (node->IsHTMLElement(nsGkAtoms::select)) {
|
2013-07-24 11:31:49 +04:00
|
|
|
return false;
|
1999-09-11 02:54:24 +04:00
|
|
|
}
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<HTMLOptGroupElement> optGroupElement =
|
2018-03-22 00:39:04 +03:00
|
|
|
HTMLOptGroupElement::FromNode(node);
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2013-07-24 11:31:49 +04:00
|
|
|
if (!optGroupElement) {
|
2001-11-02 10:40:01 +03:00
|
|
|
// If you put something else between you and the optgroup, you're a
|
|
|
|
// moron and you deserve not to have optgroup disabling work.
|
2013-07-24 11:31:49 +04:00
|
|
|
return false;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2013-07-24 11:31:49 +04:00
|
|
|
if (optGroupElement->Disabled()) {
|
|
|
|
return true;
|
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
}
|
2004-01-10 02:54:21 +03:00
|
|
|
|
2013-07-24 11:31:49 +04:00
|
|
|
return false;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2013-04-13 11:01:04 +04:00
|
|
|
void HTMLSelectElement::GetValue(DOMString& aValue) {
|
|
|
|
int32_t selectedIndex = SelectedIndex();
|
|
|
|
if (selectedIndex < 0) {
|
|
|
|
return;
|
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2013-04-13 11:01:04 +04:00
|
|
|
RefPtr<HTMLOptionElement> option = Item(static_cast<uint32_t>(selectedIndex));
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2013-04-13 11:01:04 +04:00
|
|
|
if (!option) {
|
|
|
|
return;
|
1999-06-15 03:14:17 +04:00
|
|
|
}
|
|
|
|
|
2017-11-09 04:43:09 +03:00
|
|
|
option->GetValue(aValue);
|
1999-06-15 03:14:17 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::SetValue(const nsAString& aValue) {
|
2013-04-13 11:01:04 +04:00
|
|
|
uint32_t length = Length();
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<HTMLOptionElement> option = Item(i);
|
2011-11-16 11:50:19 +04:00
|
|
|
if (!option) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-13 11:01:04 +04:00
|
|
|
|
2011-11-16 11:50:19 +04:00
|
|
|
nsAutoString optionVal;
|
|
|
|
option->GetValue(optionVal);
|
|
|
|
if (optionVal.Equals(aValue)) {
|
2012-08-22 19:56:38 +04:00
|
|
|
SetSelectedIndexInternal(int32_t(i), true);
|
2017-10-13 02:32:25 +03:00
|
|
|
return;
|
1999-06-15 03:14:17 +04:00
|
|
|
}
|
|
|
|
}
|
2015-09-12 13:34:37 +03:00
|
|
|
// No matching option was found.
|
|
|
|
SetSelectedIndexInternal(-1, true);
|
1999-06-15 03:14:17 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
int32_t HTMLSelectElement::TabIndexDefault() { return 0; }
|
1998-09-03 03:53:16 +04:00
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
bool HTMLSelectElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
|
|
|
int32_t* aTabIndex) {
|
2013-08-02 05:21:31 +04:00
|
|
|
if (nsGenericHTMLFormElementWithState::IsHTMLFocusable(
|
|
|
|
aWithMouse, aIsFocusable, aTabIndex)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2000-09-08 05:46:00 +04:00
|
|
|
}
|
2010-06-21 16:37:34 +04:00
|
|
|
|
2010-09-19 01:33:16 +04:00
|
|
|
*aIsFocusable = !IsDisabled();
|
2010-06-21 16:37:34 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-03-02 22:19:24 +03:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
bool HTMLSelectElement::CheckSelectSomething(bool aNotify) {
|
2002-03-31 14:14:01 +04:00
|
|
|
if (mIsDoneAddingChildren) {
|
2005-06-21 03:26:35 +04:00
|
|
|
if (mSelectedIndex < 0 && IsCombobox()) {
|
2010-11-17 02:41:19 +03:00
|
|
|
return SelectSomething(aNotify);
|
2001-09-07 02:54:44 +04:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2001-09-07 02:54:44 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
bool HTMLSelectElement::SelectSomething(bool aNotify) {
|
2001-11-02 10:40:01 +03:00
|
|
|
// If we're not done building the select, don't play with this yet.
|
2002-03-31 14:14:01 +04:00
|
|
|
if (!mIsDoneAddingChildren) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-05-19 07:46:25 +04:00
|
|
|
}
|
1999-05-05 00:53:26 +04:00
|
|
|
|
2017-10-13 02:32:25 +03:00
|
|
|
uint32_t count = Length();
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool disabled;
|
2001-11-28 09:52:56 +03:00
|
|
|
nsresult rv = IsOptionDisabled(i, &disabled);
|
|
|
|
|
|
|
|
if (NS_FAILED(rv) || !disabled) {
|
2019-01-22 22:03:07 +03:00
|
|
|
SetSelectedIndexInternal(i, aNotify);
|
2010-11-17 02:41:19 +03:00
|
|
|
|
|
|
|
UpdateValueMissingValidityState();
|
2011-06-01 05:46:57 +04:00
|
|
|
UpdateState(aNotify);
|
2010-11-17 02:41:19 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2000-02-12 19:26:24 +03:00
|
|
|
}
|
|
|
|
}
|
2003-03-14 09:18:20 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-05-05 00:53:26 +04:00
|
|
|
}
|
|
|
|
|
Bug 1555216 - Change the signature of BindToTree to be (BindContext&, nsINode& aParentNode). r=bzbarsky
BindContext was going to have way more information at first, but then I realized
that most of the things I wanted to know were basically a flag away using the
parent node.
Still I think it's worth it, now experimenting with BindToTree will only mean
adding a field to a struct that's included from a couple cpp files, instead of a
massive pain.
I also think this is clearer, and doing this highlights quite a few
inconsistencies in our code which I've left untouched, but commented with
FIXMEs.
Steps are:
$ for file in $(rg 'nsresult BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#nsresult BindToTree(Document\* aDocument, nsIContent\* aParent,#nsresult BindToTree(BindContext\&, nsINode\& aParent)#g' $file; done
$ for file in $(rg 'nsresult BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's# nsIContent\* aBindingParent) override#override#g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#::BindToTree(Document\* aDocument, nsIContent\* aParent,#::BindToTree(BindContext\& aContext, nsINode\& aParent)#g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#nsIContent\* aBindingParent)##g' $file; done
$ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#::BindToTree(aDocument, aParent, aBindingParent)#::BindToTree(aContext, aParent)#g' $file; done
$ ./mach clang-format
Then manual fixups.
Depends on D32948
Differential Revision: https://phabricator.services.mozilla.com/D32949
2019-05-29 07:27:04 +03:00
|
|
|
nsresult HTMLSelectElement::BindToTree(BindContext& aContext,
|
|
|
|
nsINode& aParent) {
|
|
|
|
nsresult rv =
|
|
|
|
nsGenericHTMLFormElementWithState::BindToTree(aContext, aParent);
|
2010-09-19 01:33:16 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// If there is a disabled fieldset in the parent chain, the element is now
|
|
|
|
// barred from constraint validation.
|
2011-06-01 05:46:57 +04:00
|
|
|
// XXXbz is this still needed now that fieldset changes always call
|
|
|
|
// FieldSetDisabledChanged?
|
2010-09-19 01:33:16 +04:00
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
|
2011-06-01 05:46:57 +04:00
|
|
|
// And now make sure our state is up to date
|
|
|
|
UpdateState(false);
|
|
|
|
|
2010-09-19 01:33:16 +04:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2019-05-29 01:47:08 +03:00
|
|
|
void HTMLSelectElement::UnbindFromTree(bool aNullParent) {
|
|
|
|
nsGenericHTMLFormElementWithState::UnbindFromTree(aNullParent);
|
2011-06-01 05:46:57 +04:00
|
|
|
|
|
|
|
// We might be no longer disabled because our parent chain changed.
|
2011-06-01 05:46:57 +04:00
|
|
|
// XXXbz is this still needed now that fieldset changes always call
|
|
|
|
// FieldSetDisabledChanged?
|
2011-06-01 05:46:57 +04:00
|
|
|
UpdateBarredFromConstraintValidation();
|
2011-06-01 05:46:57 +04:00
|
|
|
|
|
|
|
// And now make sure our state is up to date
|
|
|
|
UpdateState(false);
|
2011-06-01 05:46:57 +04:00
|
|
|
}
|
|
|
|
|
2017-10-03 01:05:19 +03:00
|
|
|
nsresult HTMLSelectElement::BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
2017-03-16 21:50:41 +03:00
|
|
|
const nsAttrValueOrString* aValue,
|
2013-04-04 11:03:33 +04:00
|
|
|
bool aNotify) {
|
2017-06-07 20:28:20 +03:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
|
|
if (aName == nsGkAtoms::disabled) {
|
|
|
|
if (aNotify) {
|
|
|
|
mDisabledChanged = true;
|
|
|
|
}
|
|
|
|
} else if (aName == nsGkAtoms::multiple) {
|
|
|
|
if (!aValue && aNotify && mSelectedIndex >= 0) {
|
|
|
|
// 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.
|
|
|
|
SetSelectedIndexInternal(mSelectedIndex, aNotify);
|
|
|
|
}
|
|
|
|
}
|
2006-11-28 06:17:03 +03:00
|
|
|
}
|
|
|
|
|
2013-08-02 05:21:31 +04:00
|
|
|
return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
|
|
|
|
aValue, aNotify);
|
2006-11-28 06:17:03 +03:00
|
|
|
}
|
|
|
|
|
2017-10-03 01:05:19 +03:00
|
|
|
nsresult HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
2017-05-19 00:09:01 +03:00
|
|
|
const nsAttrValue* aValue,
|
2017-10-10 00:33:38 +03:00
|
|
|
const nsAttrValue* aOldValue,
|
|
|
|
nsIPrincipal* aSubjectPrincipal,
|
|
|
|
bool aNotify) {
|
2010-11-17 02:41:19 +03:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
|
|
if (aName == nsGkAtoms::disabled) {
|
Bug 1375599 - Change IsDisabled() to look at NS_EVENT_STATE_DISABLED instead of the "disabled" attribute. r=bz
In order to speed up IsDisabled(), instead of querying for the @disabled
attribute, we're now using the NS_EVENT_STATE_DISABLED flag to know whether an
element is disabled.
It is safe to use the NS_EVENT_STATE_DISABLED flag for the following reasons:
- For form elements, nsGenericHTMLFormElement::IsDisabled() is only called on
form elements that can be disabled; form elements that can't be disabled
overrides IsDisabled() to return false directly.
And, before this patch, NS_EVENT_STATE_DISABLED flag is set by
nsGenericHTMLFormElement::IntrinsicState() if and only if IsDisabled() in all
cases when CanBeDisabled() is true, and when CanBeDisabled() is false then
IsDisabled() is always false and the flag is not set.
- For non form elements, optgroup and option have the flag matching
IsDisabled(). Note that option's IsDisabled() should also refer to optgroup's
(if it exists) disabled state, which was not done before this patch.
For this to work correctly, we need to set NS_EVENT_STATE_DISABLED earlier,
that is, in AfterSetAttr(), before any consumer of IsDisabled().
We also need to update the flag whenever the element's parent (e.g. fieldset or
optgroup) disabled state changes and when moving into/out of a parent
container.
Note that NS_EVENT_STATE_DISABLED/ENABLED is now part of the
EXTERNALLY_MANAGED_STATES.
MozReview-Commit-ID: KSceikeqvvU
2017-07-20 09:15:00 +03:00
|
|
|
// This *has* to be called *before* validity state check because
|
|
|
|
// UpdateBarredFromConstraintValidation and
|
|
|
|
// UpdateValueMissingValidityState depend on our disabled state.
|
|
|
|
UpdateDisabledState(aNotify);
|
|
|
|
|
|
|
|
UpdateValueMissingValidityState();
|
2010-11-17 02:41:19 +03:00
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
} else if (aName == nsGkAtoms::required) {
|
2017-08-03 08:27:00 +03:00
|
|
|
// This *has* to be called *before* UpdateValueMissingValidityState
|
|
|
|
// because UpdateValueMissingValidityState depends on our required
|
|
|
|
// state.
|
|
|
|
UpdateRequiredState(!!aValue, aNotify);
|
|
|
|
|
2010-11-17 02:41:19 +03:00
|
|
|
UpdateValueMissingValidityState();
|
2014-07-24 18:55:00 +04:00
|
|
|
} else if (aName == nsGkAtoms::autocomplete) {
|
2017-05-10 05:57:00 +03:00
|
|
|
// Clear the cached @autocomplete attribute and autocompleteInfo state.
|
2014-07-24 18:55:00 +04:00
|
|
|
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
|
2017-05-10 05:57:00 +03:00
|
|
|
mAutocompleteInfoState = nsContentUtils::eAutocompleteAttrState_Unknown;
|
2017-06-07 20:28:20 +03:00
|
|
|
} else if (aName == nsGkAtoms::multiple) {
|
|
|
|
if (!aValue && aNotify) {
|
|
|
|
// We might have become a combobox; make sure _something_ gets
|
|
|
|
// selected in that case
|
|
|
|
CheckSelectSomething(aNotify);
|
|
|
|
}
|
2010-11-17 02:41:19 +03:00
|
|
|
}
|
2010-09-10 09:08:56 +04:00
|
|
|
}
|
|
|
|
|
2013-08-02 05:21:31 +04:00
|
|
|
return nsGenericHTMLFormElementWithState::AfterSetAttr(
|
|
|
|
aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
|
2010-09-10 09:08:56 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::DoneAddingChildren(bool aHaveNotified) {
|
2011-10-17 18:59:28 +04:00
|
|
|
mIsDoneAddingChildren = true;
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2002-03-31 14:14:01 +04:00
|
|
|
nsISelectControlFrame* selectFrame = GetSelectFrame();
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// If we foolishly tried to restore before we were done adding
|
|
|
|
// content, restore the rest of the options proper-like
|
2002-03-31 14:14:01 +04:00
|
|
|
if (mRestoreState) {
|
2018-03-02 21:18:35 +03:00
|
|
|
RestoreStateTo(*mRestoreState);
|
2012-07-30 18:20:58 +04:00
|
|
|
mRestoreState = nullptr;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2002-03-31 14:14:01 +04:00
|
|
|
// Notify the frame
|
|
|
|
if (selectFrame) {
|
2011-10-17 18:59:28 +04:00
|
|
|
selectFrame->DoneAddingChildren(true);
|
1999-11-12 01:13:20 +03:00
|
|
|
}
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2010-06-09 10:45:32 +04:00
|
|
|
if (!mInhibitStateRestoration) {
|
2019-07-01 10:20:04 +03:00
|
|
|
GenerateStateKey();
|
|
|
|
RestoreFormControlState();
|
2010-06-09 10:45:32 +04:00
|
|
|
}
|
2002-03-31 14:14:01 +04:00
|
|
|
|
|
|
|
// Now that we're done, select something (if it's a single select something
|
|
|
|
// must be selected)
|
2011-10-17 18:59:28 +04:00
|
|
|
if (!CheckSelectSomething(false)) {
|
2010-11-17 02:41:19 +03: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-06-01 05:46:57 +04:00
|
|
|
|
|
|
|
// And now make sure we update our content state too
|
|
|
|
UpdateState(aHaveNotified);
|
2010-11-17 02:41:19 +03:00
|
|
|
}
|
2006-11-04 08:45:02 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mDefaultSelectionSet = true;
|
1999-11-12 01:13:20 +03:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
bool HTMLSelectElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
|
|
|
const nsAString& aValue,
|
2017-11-02 06:35:52 +03:00
|
|
|
nsIPrincipal* aMaybeScriptedPrincipal,
|
2013-04-04 11:03:33 +04:00
|
|
|
nsAttrValue& aResult) {
|
2014-07-24 18:55:00 +04:00
|
|
|
if (kNameSpaceID_None == aNamespaceID) {
|
|
|
|
if (aAttribute == nsGkAtoms::size) {
|
|
|
|
return aResult.ParsePositiveIntValue(aValue);
|
|
|
|
} else if (aAttribute == nsGkAtoms::autocomplete) {
|
|
|
|
aResult.ParseAtomArray(aValue);
|
|
|
|
return true;
|
|
|
|
}
|
1998-09-23 21:16:51 +04:00
|
|
|
}
|
2005-11-29 19:37:15 +03:00
|
|
|
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
2017-11-02 06:35:52 +03:00
|
|
|
aMaybeScriptedPrincipal, aResult);
|
1998-09-03 03:53:16 +04:00
|
|
|
}
|
|
|
|
|
2013-11-19 23:21:29 +04:00
|
|
|
void HTMLSelectElement::MapAttributesIntoRule(
|
|
|
|
const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
|
2018-06-22 19:48:42 +03:00
|
|
|
nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes,
|
|
|
|
aDecls);
|
|
|
|
nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes,
|
|
|
|
aDecls);
|
1998-09-03 03:53:16 +04:00
|
|
|
}
|
|
|
|
|
2017-10-03 01:05:19 +03:00
|
|
|
nsChangeHint HTMLSelectElement::GetAttributeChangeHint(const nsAtom* aAttribute,
|
2013-04-04 11:03:33 +04:00
|
|
|
int32_t aModType) const {
|
2004-10-24 21:10:32 +04:00
|
|
|
nsChangeHint retval =
|
2013-08-02 05:21:31 +04:00
|
|
|
nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute,
|
|
|
|
aModType);
|
2006-12-26 20:47:52 +03:00
|
|
|
if (aAttribute == nsGkAtoms::multiple || aAttribute == nsGkAtoms::size) {
|
2016-07-06 08:06:14 +03:00
|
|
|
retval |= nsChangeHint_ReconstructFrame;
|
2003-07-12 01:16:12 +04:00
|
|
|
}
|
2004-10-24 21:10:32 +04:00
|
|
|
return retval;
|
2003-07-12 01:16:12 +04:00
|
|
|
}
|
2003-04-17 00:54:20 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
NS_IMETHODIMP_(bool)
|
2017-10-03 01:05:19 +03:00
|
|
|
HTMLSelectElement::IsAttributeMapped(const nsAtom* aAttribute) const {
|
2004-02-26 00:04:50 +03:00
|
|
|
static const MappedAttributeEntry* const map[] = {sCommonAttributeMap,
|
2003-07-12 01:16:12 +04:00
|
|
|
sImageAlignAttributeMap};
|
2003-04-17 00:54:20 +04:00
|
|
|
|
2011-12-18 14:09:27 +04:00
|
|
|
return FindAttributeDependence(aAttribute, map);
|
1999-07-07 05:24:40 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
nsMapRuleToAttributesFunc HTMLSelectElement::GetAttributeMappingFunction()
|
|
|
|
const {
|
2005-01-12 22:45:38 +03:00
|
|
|
return &MapAttributesIntoRule;
|
1998-09-05 08:00:06 +04:00
|
|
|
}
|
|
|
|
|
2018-10-31 11:55:33 +03:00
|
|
|
bool HTMLSelectElement::IsDisabledForEvents(WidgetEvent* aEvent) {
|
2011-10-17 18:59:28 +04:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
2012-07-30 18:20:58 +04:00
|
|
|
nsIFrame* formFrame = nullptr;
|
2011-07-19 03:16:44 +04:00
|
|
|
if (formControlFrame) {
|
|
|
|
formFrame = do_QueryFrame(formControlFrame);
|
|
|
|
}
|
2018-10-31 11:55:33 +03:00
|
|
|
return IsElementDisabledForEvents(aEvent, formFrame);
|
2013-01-03 19:17:36 +04:00
|
|
|
}
|
2000-08-09 03:38:00 +04:00
|
|
|
|
2016-10-21 05:11:07 +03:00
|
|
|
void HTMLSelectElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
2011-10-17 18:59:28 +04:00
|
|
|
aVisitor.mCanHandle = false;
|
2018-10-31 11:55:33 +03:00
|
|
|
if (IsDisabledForEvents(aVisitor.mEvent)) {
|
2018-04-05 20:42:41 +03:00
|
|
|
return;
|
2000-08-09 03:38:00 +04:00
|
|
|
}
|
|
|
|
|
2018-04-05 20:42:41 +03:00
|
|
|
nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
|
1998-09-03 03:53:16 +04:00
|
|
|
}
|
1998-09-23 21:16:51 +04:00
|
|
|
|
2014-03-18 08:48:20 +04:00
|
|
|
nsresult HTMLSelectElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
2015-09-02 09:08:00 +03:00
|
|
|
if (aVisitor.mEvent->mMessage == eFocus) {
|
2010-11-24 13:09:31 +03:00
|
|
|
// If the invalid UI is shown, we should show it while focused and
|
|
|
|
// update the invalid/valid UI.
|
2011-01-20 14:05:29 +03:00
|
|
|
mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
|
2010-11-24 13:09:31 +03:00
|
|
|
|
|
|
|
// If neither invalid UI nor valid UI is shown, we shouldn't show the valid
|
|
|
|
// UI while focused.
|
2011-01-20 14:05:29 +03:00
|
|
|
mCanShowValidUI = ShouldShowValidityUI();
|
2010-11-24 13:09:31 +03: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.
|
2015-09-02 09:08:00 +03:00
|
|
|
} else if (aVisitor.mEvent->mMessage == eBlur) {
|
2011-10-17 18:59:28 +04:00
|
|
|
mCanShowInvalidUI = true;
|
|
|
|
mCanShowValidUI = true;
|
2010-11-24 13:09:31 +03:00
|
|
|
|
2011-06-01 05:46:57 +04:00
|
|
|
UpdateState(true);
|
2010-11-24 13:09:31 +03:00
|
|
|
}
|
|
|
|
|
2013-08-02 05:21:31 +04:00
|
|
|
return nsGenericHTMLFormElementWithState::PostHandleEvent(aVisitor);
|
2010-11-24 13:09:31 +03:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
EventStates HTMLSelectElement::IntrinsicState() const {
|
2014-04-03 08:18:36 +04:00
|
|
|
EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
|
2010-08-21 21:52:57 +04:00
|
|
|
|
2010-08-21 22:51:38 +04:00
|
|
|
if (IsCandidateForConstraintValidation()) {
|
2010-11-24 13:09:01 +03:00
|
|
|
if (IsValid()) {
|
|
|
|
state |= NS_EVENT_STATE_VALID;
|
|
|
|
} else {
|
|
|
|
state |= NS_EVENT_STATE_INVALID;
|
|
|
|
|
2011-01-27 16:51:45 +03:00
|
|
|
if ((!mForm ||
|
|
|
|
!mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
|
|
|
|
(GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
|
|
|
(mCanShowInvalidUI && ShouldShowValidityUI()))) {
|
2010-11-24 13:09:01 +03:00
|
|
|
state |= NS_EVENT_STATE_MOZ_UI_INVALID;
|
|
|
|
}
|
|
|
|
}
|
2010-11-24 13:09:31 +03: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 16:51:45 +03: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 13:09:31 +03:00
|
|
|
state |= NS_EVENT_STATE_MOZ_UI_VALID;
|
|
|
|
}
|
2010-08-21 21:52:57 +04:00
|
|
|
}
|
|
|
|
|
2010-11-16 17:40:21 +03:00
|
|
|
return state;
|
2010-08-19 04:03:20 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 21:16:51 +04:00
|
|
|
// nsIFormControl
|
|
|
|
|
1999-05-05 00:53:26 +04:00
|
|
|
NS_IMETHODIMP
|
2013-04-04 11:03:33 +04:00
|
|
|
HTMLSelectElement::SaveState() {
|
2018-03-02 21:18:35 +03:00
|
|
|
PresState* presState = GetPrimaryPresState();
|
2017-08-02 22:28:48 +03:00
|
|
|
if (!presState) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-03-02 21:18:35 +03:00
|
|
|
SelectContentData state;
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2013-07-24 11:37:20 +04:00
|
|
|
uint32_t len = Length();
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t optIndex = 0; optIndex < len; optIndex++) {
|
2013-07-24 11:37:20 +04:00
|
|
|
HTMLOptionElement* option = Item(optIndex);
|
|
|
|
if (option && option->Selected()) {
|
|
|
|
nsAutoString value;
|
|
|
|
option->GetValue(value);
|
2018-03-02 21:18:35 +03:00
|
|
|
if (value.IsEmpty()) {
|
|
|
|
state.indices().AppendElement(optIndex);
|
|
|
|
} else {
|
2018-05-30 22:15:35 +03:00
|
|
|
state.values().AppendElement(std::move(value));
|
2018-03-02 21:18:35 +03:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
1999-05-05 00:53:26 +04:00
|
|
|
}
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
presState->contentData() = std::move(state);
|
2006-11-28 06:17:03 +03:00
|
|
|
|
2017-08-02 22:28:48 +03:00
|
|
|
if (mDisabledChanged) {
|
|
|
|
// We do not want to save the real disabled state but the disabled
|
|
|
|
// attribute.
|
2018-03-02 21:18:35 +03:00
|
|
|
presState->disabled() = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
|
|
|
|
presState->disabledSet() = true;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2002-08-17 05:56:04 +04:00
|
|
|
|
2013-07-24 11:38:13 +04:00
|
|
|
return NS_OK;
|
1999-05-05 00:53:26 +04:00
|
|
|
}
|
|
|
|
|
2018-03-02 21:18:35 +03:00
|
|
|
bool HTMLSelectElement::RestoreState(PresState* aState) {
|
2001-11-02 10:40:01 +03:00
|
|
|
// Get the presentation state object to retrieve our stuff out of.
|
2018-03-02 21:18:35 +03:00
|
|
|
const PresContentData& state = aState->contentData();
|
|
|
|
if (state.type() == PresContentData::TSelectContentData) {
|
|
|
|
RestoreStateTo(state.get_SelectContentData());
|
1999-05-05 00:53:26 +04:00
|
|
|
|
2007-10-10 07:39:16 +04:00
|
|
|
// Don't flush, if the frame doesn't exist yet it doesn't care if
|
|
|
|
// we're reset or not.
|
|
|
|
DispatchContentReset();
|
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2018-03-02 21:18:35 +03:00
|
|
|
if (aState->disabledSet() && !aState->disabled()) {
|
2018-02-01 22:21:14 +03:00
|
|
|
SetDisabled(false, IgnoreErrors());
|
2006-11-28 06:17:03 +03:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2018-03-02 21:18:35 +03:00
|
|
|
void HTMLSelectElement::RestoreStateTo(const SelectContentData& aNewSelected) {
|
2002-03-31 14:14:01 +04:00
|
|
|
if (!mIsDoneAddingChildren) {
|
2018-03-02 21:18:35 +03:00
|
|
|
// Make a copy of the state for us to restore from in the future.
|
|
|
|
mRestoreState = MakeUnique<SelectContentData>(aNewSelected);
|
2002-08-06 08:59:15 +04:00
|
|
|
return;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2013-07-24 11:37:24 +04:00
|
|
|
uint32_t len = Length();
|
2013-09-28 23:04:20 +04:00
|
|
|
uint32_t mask = IS_SELECTED | CLEAR_ALL | SET_DISABLED | NOTIFY;
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// First clear all
|
2013-09-28 23:04:20 +04:00
|
|
|
SetOptionsSelectedByIndex(-1, -1, mask);
|
2000-12-23 13:56:31 +03:00
|
|
|
|
2018-03-02 21:18:35 +03:00
|
|
|
// Select by index.
|
|
|
|
for (uint32_t idx : aNewSelected.indices()) {
|
|
|
|
if (idx < len) {
|
|
|
|
SetOptionsSelectedByIndex(idx, idx, IS_SELECTED | SET_DISABLED | NOTIFY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select by value.
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
2013-07-24 11:37:24 +04:00
|
|
|
HTMLOptionElement* option = Item(i);
|
2002-08-17 05:56:04 +04:00
|
|
|
if (option) {
|
|
|
|
nsAutoString value;
|
2017-11-09 04:43:09 +03:00
|
|
|
option->GetValue(value);
|
2018-03-02 21:18:35 +03:00
|
|
|
if (aNewSelected.values().Contains(value)) {
|
2013-09-28 23:04:20 +04:00
|
|
|
SetOptionsSelectedByIndex(i, i, IS_SELECTED | SET_DISABLED | NOTIFY);
|
2002-08-17 05:56:04 +04:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
NS_IMETHODIMP
|
2013-04-04 11:03:33 +04:00
|
|
|
HTMLSelectElement::Reset() {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t numSelected = 0;
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
//
|
|
|
|
// Cycle through the options array and reset the options
|
|
|
|
//
|
2013-07-24 11:37:28 +04:00
|
|
|
uint32_t numOptions = Length();
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < numOptions; i++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<HTMLOptionElement> option = Item(i);
|
2001-11-02 10:40:01 +03:00
|
|
|
if (option) {
|
2002-08-06 08:59:15 +04:00
|
|
|
//
|
|
|
|
// Reset the option to its default value
|
|
|
|
//
|
2013-09-28 23:04:20 +04:00
|
|
|
|
2017-05-18 09:44:00 +03:00
|
|
|
uint32_t mask = SET_DISABLED | NOTIFY | NO_RESELECT;
|
2013-09-28 23:04:20 +04:00
|
|
|
if (option->DefaultSelected()) {
|
|
|
|
mask |= IS_SELECTED;
|
2002-08-06 08:59:15 +04:00
|
|
|
numSelected++;
|
|
|
|
}
|
2013-09-28 23:04:20 +04:00
|
|
|
|
|
|
|
SetOptionsSelectedByIndex(i, i, mask);
|
2017-05-18 09:44:00 +03:00
|
|
|
option->SetSelectedChanged(false);
|
1998-09-23 21:16:51 +04:00
|
|
|
}
|
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
//
|
|
|
|
// If nothing was selected and it's not multiple, select something
|
|
|
|
//
|
2005-06-21 03:26:35 +04:00
|
|
|
if (numSelected == 0 && IsCombobox()) {
|
2011-10-17 18:59:28 +04:00
|
|
|
SelectSomething(true);
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
SetSelectionChanged(false, true);
|
2010-11-24 13:09:01 +03:00
|
|
|
|
2002-08-06 08:59:15 +04:00
|
|
|
//
|
|
|
|
// Let the frame know we were reset
|
|
|
|
//
|
2001-11-06 12:10:07 +03:00
|
|
|
// 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.
|
2002-08-06 08:59:15 +04:00
|
|
|
//
|
2005-12-13 02:53:06 +03:00
|
|
|
DispatchContentReset();
|
2001-11-02 10:40:01 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-02-16 04:19:24 +03:00
|
|
|
NS_IMETHODIMP
|
2016-06-16 10:24:16 +03:00
|
|
|
HTMLSelectElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission) {
|
2002-02-16 04:19:24 +03:00
|
|
|
// Disabled elements don't submit
|
2010-09-19 01:33:16 +04:00
|
|
|
if (IsDisabled()) {
|
|
|
|
return NS_OK;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2002-02-16 04:19:24 +03:00
|
|
|
//
|
|
|
|
// Get the name (if no name, no submit)
|
|
|
|
//
|
2001-11-02 10:40:01 +03:00
|
|
|
nsAutoString name;
|
2010-02-25 08:57:54 +03:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
if (name.IsEmpty()) {
|
2005-10-28 15:25:24 +04:00
|
|
|
return NS_OK;
|
2002-02-16 04:19:24 +03:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2002-02-16 04:19:24 +03:00
|
|
|
//
|
|
|
|
// Submit
|
|
|
|
//
|
2013-07-24 11:37:32 +04:00
|
|
|
uint32_t len = Length();
|
2001-11-02 10:40:01 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t optIndex = 0; optIndex < len; optIndex++) {
|
2013-07-24 11:37:32 +04:00
|
|
|
HTMLOptionElement* option = Item(optIndex);
|
|
|
|
|
2001-11-02 10:40:01 +03:00
|
|
|
// Don't send disabled options
|
2013-07-24 11:37:32 +04:00
|
|
|
if (!option || IsOptionDisabled(option)) {
|
2001-11-02 10:40:01 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-07-24 11:37:32 +04:00
|
|
|
if (!option->Selected()) {
|
2002-02-16 04:19:24 +03:00
|
|
|
continue;
|
2001-11-02 10:40:01 +03:00
|
|
|
}
|
|
|
|
|
2013-07-24 11:37:32 +04:00
|
|
|
nsString value;
|
2017-11-09 04:43:09 +03:00
|
|
|
option->GetValue(value);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2013-07-24 11:37:32 +04:00
|
|
|
aFormSubmission->AddNameValuePair(name, value);
|
2002-02-16 04:19:24 +03:00
|
|
|
}
|
2001-11-02 10:40:01 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::DispatchContentReset() {
|
2011-10-17 18:59:28 +04:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
2005-12-13 02:53:06 +03:00
|
|
|
if (formControlFrame) {
|
|
|
|
// Only dispatch content reset notification if this is a list control
|
|
|
|
// frame or combo box control frame.
|
|
|
|
if (IsCombobox()) {
|
2018-09-26 17:41:12 +03:00
|
|
|
nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
|
2005-12-13 02:53:06 +03:00
|
|
|
if (comboFrame) {
|
|
|
|
comboFrame->OnContentReset();
|
|
|
|
}
|
|
|
|
} else {
|
2018-09-26 17:41:01 +03:00
|
|
|
nsListControlFrame* listFrame = do_QueryFrame(formControlFrame);
|
2005-12-13 02:53:06 +03:00
|
|
|
if (listFrame) {
|
|
|
|
listFrame->OnContentReset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-13 12:28:00 +03:00
|
|
|
static void AddOptions(nsIContent* aRoot, HTMLOptionsCollection* aArray) {
|
|
|
|
for (nsIContent* child = aRoot->GetFirstChild(); child;
|
|
|
|
child = child->GetNextSibling()) {
|
2018-03-22 00:39:04 +03:00
|
|
|
HTMLOptionElement* opt = HTMLOptionElement::FromNode(child);
|
2006-03-03 00:30:23 +03:00
|
|
|
if (opt) {
|
|
|
|
aArray->AppendOption(opt);
|
2015-10-13 12:28:00 +03:00
|
|
|
} else if (child->IsHTMLElement(nsGkAtoms::optgroup)) {
|
|
|
|
for (nsIContent* grandchild = child->GetFirstChild(); grandchild;
|
|
|
|
grandchild = grandchild->GetNextSibling()) {
|
2018-03-22 00:39:04 +03:00
|
|
|
opt = HTMLOptionElement::FromNode(grandchild);
|
2015-10-13 12:28:00 +03:00
|
|
|
if (opt) {
|
|
|
|
aArray->AppendOption(opt);
|
|
|
|
}
|
|
|
|
}
|
2006-03-03 00:30:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::RebuildOptionsArray(bool aNotify) {
|
2006-03-03 00:30:23 +03:00
|
|
|
mOptions->Clear();
|
2015-10-13 12:28:00 +03:00
|
|
|
AddOptions(this, mOptions);
|
2010-11-24 13:09:01 +03:00
|
|
|
FindSelectedIndex(0, aNotify);
|
2006-03-03 00:30:23 +03:00
|
|
|
}
|
|
|
|
|
2017-08-03 08:23:00 +03:00
|
|
|
bool HTMLSelectElement::IsValueMissing() const {
|
2013-07-24 11:37:36 +04:00
|
|
|
if (!Required()) {
|
2010-11-17 02:41:19 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-07-24 11:37:36 +04:00
|
|
|
uint32_t length = Length();
|
2010-11-17 02:41:19 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < length; ++i) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<HTMLOptionElement> option = Item(i);
|
2016-11-25 00:15:33 +03:00
|
|
|
// Check for a placeholder label option, don't count it as a valid value.
|
|
|
|
if (i == 0 && !Multiple() && Size() <= 1 && option->GetParent() == this) {
|
|
|
|
nsAutoString value;
|
2017-11-09 04:43:09 +03:00
|
|
|
option->GetValue(value);
|
2016-11-25 00:15:33 +03:00
|
|
|
if (value.IsEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-24 11:37:36 +04:00
|
|
|
if (!option->Selected()) {
|
2010-11-17 02:41:19 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-07-24 11:37:36 +04:00
|
|
|
if (IsOptionDisabled(option)) {
|
2010-11-17 02:41:19 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-11-25 00:15:33 +03:00
|
|
|
return false;
|
2010-11-17 02:41:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::UpdateValueMissingValidityState() {
|
2010-11-17 02:41:19 +03:00
|
|
|
SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
|
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
nsresult HTMLSelectElement::GetValidationMessage(nsAString& aValidationMessage,
|
|
|
|
ValidityStateType aType) {
|
2011-11-16 11:50:19 +04:00
|
|
|
switch (aType) {
|
|
|
|
case VALIDITY_STATE_VALUE_MISSING: {
|
2017-08-04 07:40:52 +03:00
|
|
|
nsAutoString message;
|
2011-11-16 11:50:19 +04:00
|
|
|
nsresult rv = nsContentUtils::GetLocalizedString(
|
|
|
|
nsContentUtils::eDOM_PROPERTIES, "FormValidationSelectMissing",
|
|
|
|
message);
|
|
|
|
aValidationMessage = message;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
return nsIConstraintValidation::GetValidationMessage(aValidationMessage,
|
|
|
|
aType);
|
|
|
|
}
|
2010-11-17 02:41:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-03 00:30:23 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
2015-10-13 12:28:00 +03:00
|
|
|
void HTMLSelectElement::VerifyOptionsArray() {
|
|
|
|
int32_t index = 0;
|
|
|
|
for (nsIContent* child = nsINode::GetFirstChild(); child;
|
|
|
|
child = child->GetNextSibling()) {
|
2018-03-22 00:39:04 +03:00
|
|
|
HTMLOptionElement* opt = HTMLOptionElement::FromNode(child);
|
2006-03-03 00:30:23 +03:00
|
|
|
if (opt) {
|
2015-10-13 12:28:00 +03:00
|
|
|
NS_ASSERTION(opt == mOptions->ItemAsOption(index++),
|
2006-03-03 00:30:23 +03:00
|
|
|
"Options collection broken");
|
2015-10-13 12:28:00 +03:00
|
|
|
} else if (child->IsHTMLElement(nsGkAtoms::optgroup)) {
|
|
|
|
for (nsIContent* grandchild = child->GetFirstChild(); grandchild;
|
|
|
|
grandchild = grandchild->GetNextSibling()) {
|
2018-03-22 00:39:04 +03:00
|
|
|
opt = HTMLOptionElement::FromNode(grandchild);
|
2015-10-13 12:28:00 +03:00
|
|
|
if (opt) {
|
|
|
|
NS_ASSERTION(opt == mOptions->ItemAsOption(index++),
|
|
|
|
"Options collection broken");
|
|
|
|
}
|
|
|
|
}
|
2006-03-03 00:30:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::UpdateBarredFromConstraintValidation() {
|
2010-09-19 01:33:16 +04:00
|
|
|
SetBarredFromConstraintValidation(IsDisabled());
|
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::FieldSetDisabledChanged(bool aNotify) {
|
Bug 1375599 - Change IsDisabled() to look at NS_EVENT_STATE_DISABLED instead of the "disabled" attribute. r=bz
In order to speed up IsDisabled(), instead of querying for the @disabled
attribute, we're now using the NS_EVENT_STATE_DISABLED flag to know whether an
element is disabled.
It is safe to use the NS_EVENT_STATE_DISABLED flag for the following reasons:
- For form elements, nsGenericHTMLFormElement::IsDisabled() is only called on
form elements that can be disabled; form elements that can't be disabled
overrides IsDisabled() to return false directly.
And, before this patch, NS_EVENT_STATE_DISABLED flag is set by
nsGenericHTMLFormElement::IntrinsicState() if and only if IsDisabled() in all
cases when CanBeDisabled() is true, and when CanBeDisabled() is false then
IsDisabled() is always false and the flag is not set.
- For non form elements, optgroup and option have the flag matching
IsDisabled(). Note that option's IsDisabled() should also refer to optgroup's
(if it exists) disabled state, which was not done before this patch.
For this to work correctly, we need to set NS_EVENT_STATE_DISABLED earlier,
that is, in AfterSetAttr(), before any consumer of IsDisabled().
We also need to update the flag whenever the element's parent (e.g. fieldset or
optgroup) disabled state changes and when moving into/out of a parent
container.
Note that NS_EVENT_STATE_DISABLED/ENABLED is now part of the
EXTERNALLY_MANAGED_STATES.
MozReview-Commit-ID: KSceikeqvvU
2017-07-20 09:15:00 +03:00
|
|
|
// This *has* to be called before UpdateBarredFromConstraintValidation and
|
|
|
|
// UpdateValueMissingValidityState because these two functions depend on our
|
|
|
|
// disabled state.
|
2013-08-02 05:21:31 +04:00
|
|
|
nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
|
Bug 1375599 - Change IsDisabled() to look at NS_EVENT_STATE_DISABLED instead of the "disabled" attribute. r=bz
In order to speed up IsDisabled(), instead of querying for the @disabled
attribute, we're now using the NS_EVENT_STATE_DISABLED flag to know whether an
element is disabled.
It is safe to use the NS_EVENT_STATE_DISABLED flag for the following reasons:
- For form elements, nsGenericHTMLFormElement::IsDisabled() is only called on
form elements that can be disabled; form elements that can't be disabled
overrides IsDisabled() to return false directly.
And, before this patch, NS_EVENT_STATE_DISABLED flag is set by
nsGenericHTMLFormElement::IntrinsicState() if and only if IsDisabled() in all
cases when CanBeDisabled() is true, and when CanBeDisabled() is false then
IsDisabled() is always false and the flag is not set.
- For non form elements, optgroup and option have the flag matching
IsDisabled(). Note that option's IsDisabled() should also refer to optgroup's
(if it exists) disabled state, which was not done before this patch.
For this to work correctly, we need to set NS_EVENT_STATE_DISABLED earlier,
that is, in AfterSetAttr(), before any consumer of IsDisabled().
We also need to update the flag whenever the element's parent (e.g. fieldset or
optgroup) disabled state changes and when moving into/out of a parent
container.
Note that NS_EVENT_STATE_DISABLED/ENABLED is now part of the
EXTERNALLY_MANAGED_STATES.
MozReview-Commit-ID: KSceikeqvvU
2017-07-20 09:15:00 +03:00
|
|
|
|
|
|
|
UpdateValueMissingValidityState();
|
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
UpdateState(aNotify);
|
2010-09-19 01:33:16 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
void HTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify) {
|
2010-11-24 13:09:01 +03:00
|
|
|
if (!mDefaultSelectionSet) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-02 21:23:27 +04:00
|
|
|
UpdateSelectedOptions();
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool previousSelectionChangedValue = mSelectionHasChanged;
|
2010-11-24 13:09:01 +03:00
|
|
|
mSelectionHasChanged = aValue;
|
|
|
|
|
2011-06-01 05:46:57 +04:00
|
|
|
if (mSelectionHasChanged != previousSelectionChangedValue) {
|
|
|
|
UpdateState(aNotify);
|
2010-11-24 13:09:01 +03:00
|
|
|
}
|
|
|
|
}
|
2013-04-04 11:03:33 +04:00
|
|
|
|
2013-09-02 21:23:27 +04:00
|
|
|
void HTMLSelectElement::UpdateSelectedOptions() {
|
|
|
|
if (mSelectedOptions) {
|
|
|
|
mSelectedOptions->SetDirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-03 14:45:46 +03:00
|
|
|
bool HTMLSelectElement::OpenInParentProcess() {
|
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
2018-09-26 17:41:12 +03:00
|
|
|
nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
|
2016-08-03 14:45:46 +03:00
|
|
|
if (comboFrame) {
|
|
|
|
return comboFrame->IsOpenInParentProcess();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLSelectElement::SetOpenInParentProcess(bool aVal) {
|
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
2018-09-26 17:41:12 +03:00
|
|
|
nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
|
2016-08-03 14:45:46 +03:00
|
|
|
if (comboFrame) {
|
|
|
|
comboFrame->SetOpenInParentProcess(aVal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-03 12:08:44 +03:00
|
|
|
void HTMLSelectElement::SetPreviewValue(const nsAString& aValue) {
|
2017-10-25 06:57:57 +03:00
|
|
|
mPreviewValue = aValue;
|
|
|
|
nsContentUtils::RemoveNewlines(mPreviewValue);
|
2017-05-03 12:08:44 +03:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
2018-09-26 17:41:12 +03:00
|
|
|
nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
|
2017-05-03 12:08:44 +03:00
|
|
|
if (comboFrame) {
|
2017-10-25 06:57:57 +03:00
|
|
|
comboFrame->RedisplaySelectedText();
|
2017-05-03 12:08:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
|
|
|
JSObject* HTMLSelectElement::WrapNode(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aGivenProto) {
|
2018-06-26 00:20:54 +03:00
|
|
|
return HTMLSelectElement_Binding::Wrap(aCx, this, aGivenProto);
|
2013-04-13 11:01:59 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 11:03:33 +04:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|