1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/HTMLOptionsCollection.h"
8 #include "mozilla/dom/HTMLOptionsCollectionBinding.h"
10 #include "mozilla/dom/HTMLOptionElement.h"
11 #include "mozilla/dom/HTMLSelectElement.h"
13 namespace mozilla::dom
{
15 HTMLOptionsCollection::HTMLOptionsCollection(HTMLSelectElement
* aSelect
)
18 nsresult
HTMLOptionsCollection::GetOptionIndex(Element
* aOption
,
20 bool aForward
, int32_t* aIndex
) {
21 // NOTE: aIndex shouldn't be set if the returned value isn't NS_OK.
25 // Make the common case fast
26 if (aStartIndex
== 0 && aForward
) {
27 index
= mElements
.IndexOf(aOption
);
29 return NS_ERROR_FAILURE
;
36 int32_t high
= mElements
.Length();
37 int32_t step
= aForward
? 1 : -1;
39 for (index
= aStartIndex
; index
< high
&& index
> -1; index
+= step
) {
40 if (mElements
[index
] == aOption
) {
46 return NS_ERROR_FAILURE
;
49 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection
, mElements
, mSelect
)
53 // QueryInterface implementation for HTMLOptionsCollection
54 NS_INTERFACE_TABLE_HEAD(HTMLOptionsCollection
)
55 NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
56 NS_INTERFACE_TABLE(HTMLOptionsCollection
, nsIHTMLCollection
)
57 NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLOptionsCollection
)
60 NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLOptionsCollection
)
61 NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLOptionsCollection
)
63 JSObject
* HTMLOptionsCollection::WrapObject(JSContext
* aCx
,
64 JS::Handle
<JSObject
*> aGivenProto
) {
65 return HTMLOptionsCollection_Binding::Wrap(aCx
, this, aGivenProto
);
68 uint32_t HTMLOptionsCollection::Length() { return mElements
.Length(); }
70 void HTMLOptionsCollection::SetLength(uint32_t aLength
, ErrorResult
& aError
) {
71 mSelect
->SetLength(aLength
, aError
);
74 void HTMLOptionsCollection::IndexedSetter(uint32_t aIndex
,
75 HTMLOptionElement
* aOption
,
76 ErrorResult
& aError
) {
77 // if the new option is null, just remove this option. Note that it's safe
78 // to pass a too-large aIndex in here.
80 mSelect
->Remove(aIndex
);
86 // Now we're going to be setting an option in our collection
87 if (aIndex
> mElements
.Length()) {
88 // Fill our array with blank options up to (but not including, since we're
89 // about to change it) aIndex, for compat with other browsers.
90 SetLength(aIndex
, aError
);
91 ENSURE_SUCCESS_VOID(aError
);
94 NS_ASSERTION(aIndex
<= mElements
.Length(), "SetLength lied");
96 if (aIndex
== mElements
.Length()) {
97 mSelect
->AppendChild(*aOption
, aError
);
101 // Find the option they're talking about and replace it
102 // hold a strong reference to follow COM rules.
103 RefPtr
<HTMLOptionElement
> refChild
= ItemAsOption(aIndex
);
105 aError
.Throw(NS_ERROR_UNEXPECTED
);
109 nsCOMPtr
<nsINode
> parent
= refChild
->GetParent();
114 parent
->ReplaceChild(*aOption
, *refChild
, aError
);
117 int32_t HTMLOptionsCollection::SelectedIndex() {
118 return mSelect
->SelectedIndex();
121 void HTMLOptionsCollection::SetSelectedIndex(int32_t aSelectedIndex
) {
122 mSelect
->SetSelectedIndex(aSelectedIndex
);
125 Element
* HTMLOptionsCollection::GetElementAt(uint32_t aIndex
) {
126 return ItemAsOption(aIndex
);
129 HTMLOptionElement
* HTMLOptionsCollection::NamedGetter(const nsAString
& aName
,
131 uint32_t count
= mElements
.Length();
132 for (uint32_t i
= 0; i
< count
; i
++) {
133 HTMLOptionElement
* content
= mElements
.ElementAt(i
);
134 if (content
&& (content
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::name
,
135 aName
, eCaseMatters
) ||
136 content
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::id
,
137 aName
, eCaseMatters
))) {
147 nsINode
* HTMLOptionsCollection::GetParentObject() { return mSelect
; }
149 DocGroup
* HTMLOptionsCollection::GetDocGroup() const {
150 return mSelect
? mSelect
->GetDocGroup() : nullptr;
153 void HTMLOptionsCollection::GetSupportedNames(nsTArray
<nsString
>& aNames
) {
154 AutoTArray
<nsAtom
*, 8> atoms
;
155 for (uint32_t i
= 0; i
< mElements
.Length(); ++i
) {
156 HTMLOptionElement
* content
= mElements
.ElementAt(i
);
158 // Note: HasName means the names is exposed on the document,
159 // which is false for options, so we don't check it here.
160 const nsAttrValue
* val
= content
->GetParsedAttr(nsGkAtoms::name
);
161 if (val
&& val
->Type() == nsAttrValue::eAtom
) {
162 nsAtom
* name
= val
->GetAtomValue();
163 if (!atoms
.Contains(name
)) {
164 atoms
.AppendElement(name
);
167 if (content
->HasID()) {
168 nsAtom
* id
= content
->GetID();
169 if (!atoms
.Contains(id
)) {
170 atoms
.AppendElement(id
);
176 uint32_t atomsLen
= atoms
.Length();
177 nsString
* names
= aNames
.AppendElements(atomsLen
);
178 for (uint32_t i
= 0; i
< atomsLen
; ++i
) {
179 atoms
[i
]->ToString(names
[i
]);
183 void HTMLOptionsCollection::Add(const HTMLOptionOrOptGroupElement
& aElement
,
184 const Nullable
<HTMLElementOrLong
>& aBefore
,
185 ErrorResult
& aError
) {
186 mSelect
->Add(aElement
, aBefore
, aError
);
189 void HTMLOptionsCollection::Remove(int32_t aIndex
) { mSelect
->Remove(aIndex
); }
191 } // namespace mozilla::dom