mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-27 07:34:20 +00:00
Bug 596681 - Implement HTMLSelectElement.selectedOptions attribute. r=smaug
This commit is contained in:
parent
2209a370c7
commit
cad644ddfe
@ -299,6 +299,16 @@ public:
|
||||
mMatchNameSpaceId == aKey.mMatchNameSpaceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state to LIST_DIRTY and clears mElements array.
|
||||
* @note This is the only acceptable way to set state to LIST_DIRTY.
|
||||
*/
|
||||
void SetDirty()
|
||||
{
|
||||
mState = LIST_DIRTY;
|
||||
Reset();
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns whether the element matches our criterion
|
||||
@ -350,16 +360,6 @@ protected:
|
||||
*/
|
||||
inline void BringSelfUpToDate(bool aDoFlush);
|
||||
|
||||
/**
|
||||
* Sets the state to LIST_DIRTY and clears mElements array.
|
||||
* @note This is the only acceptable way to set state to LIST_DIRTY.
|
||||
*/
|
||||
void SetDirty()
|
||||
{
|
||||
mState = LIST_DIRTY;
|
||||
Reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called from non-destructor locations that want to remove from caches.
|
||||
* Needed because if subclasses want to have cache behavior they can't just
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/dom/HTMLSelectElementBinding.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsError.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsEventStates.h"
|
||||
@ -139,10 +140,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLSelectElement,
|
||||
nsGenericHTMLFormElementWithState)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOptions)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedOptions)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLSelectElement,
|
||||
nsGenericHTMLFormElementWithState)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedOptions)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLSelectElement, Element)
|
||||
@ -769,6 +772,34 @@ HTMLSelectElement::SetLength(uint32_t aLength, ErrorResult& aRv)
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
HTMLSelectElement::MatchSelectedOptions(nsIContent* aContent,
|
||||
int32_t /* unused */,
|
||||
nsIAtom* /* unused */,
|
||||
void* /* unused*/)
|
||||
{
|
||||
HTMLOptionElement* option = HTMLOptionElement::FromContent(aContent);
|
||||
return option && option->Selected();
|
||||
}
|
||||
|
||||
nsIHTMLCollection*
|
||||
HTMLSelectElement::SelectedOptions()
|
||||
{
|
||||
if (!mSelectedOptions) {
|
||||
mSelectedOptions = new nsContentList(this, MatchSelectedOptions, nullptr,
|
||||
nullptr, /* deep */ true);
|
||||
}
|
||||
return mSelectedOptions;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLSelectElement::GetSelectedOptions(nsIDOMHTMLCollection** aSelectedOptions)
|
||||
{
|
||||
NS_ADDREF(*aSelectedOptions = SelectedOptions());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//NS_IMPL_INT_ATTR(HTMLSelectElement, SelectedIndex, selectedindex)
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -847,6 +878,7 @@ HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
|
||||
aSelectFrame->OnOptionSelected(aIndex, aSelected);
|
||||
}
|
||||
|
||||
UpdateSelectedOptions();
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
@ -1848,6 +1880,8 @@ HTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify)
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateSelectedOptions();
|
||||
|
||||
bool previousSelectionChangedValue = mSelectionHasChanged;
|
||||
mSelectionHasChanged = aValue;
|
||||
|
||||
@ -1856,6 +1890,14 @@ HTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSelectElement::UpdateSelectedOptions()
|
||||
{
|
||||
if (mSelectedOptions) {
|
||||
mSelectedOptions->SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLSelectElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
|
@ -18,7 +18,9 @@
|
||||
#include "nsError.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
|
||||
class nsContentList;
|
||||
class nsIDOMHTMLOptionElement;
|
||||
class nsIHTMLCollection;
|
||||
class nsISelectControlFrame;
|
||||
class nsPresState;
|
||||
|
||||
@ -208,6 +210,11 @@ public:
|
||||
mOptions->IndexedSetter(aIndex, aOption, aRv);
|
||||
}
|
||||
|
||||
static bool MatchSelectedOptions(nsIContent* aContent, int32_t, nsIAtom*,
|
||||
void*);
|
||||
|
||||
nsIHTMLCollection* SelectedOptions();
|
||||
|
||||
int32_t SelectedIndex() const
|
||||
{
|
||||
return mSelectedIndex;
|
||||
@ -553,6 +560,12 @@ protected:
|
||||
|
||||
void SetSelectionChanged(bool aValue, bool aNotify);
|
||||
|
||||
/**
|
||||
* Marks the selectedOptions list as dirty, so that it'll populate itself
|
||||
* again.
|
||||
*/
|
||||
void UpdateSelectedOptions();
|
||||
|
||||
/**
|
||||
* Return whether an element should have a validity UI.
|
||||
* (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes).
|
||||
@ -618,6 +631,11 @@ protected:
|
||||
* done adding options
|
||||
*/
|
||||
nsCOMPtr<SelectState> mRestoreState;
|
||||
|
||||
/**
|
||||
* The live list of selected options.
|
||||
*/
|
||||
nsRefPtr<nsContentList> mSelectedOptions;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -67,6 +67,7 @@ MOCHITEST_FILES = \
|
||||
test_input_color_picker_popup.html \
|
||||
test_input_color_input_change_events.html \
|
||||
test_restore_form_elements.html \
|
||||
test_select_selectedOptions.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
120
content/html/content/test/forms/test_select_selectedOptions.html
Normal file
120
content/html/content/test/forms/test_select_selectedOptions.html
Normal file
@ -0,0 +1,120 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=596681
|
||||
-->
|
||||
<head>
|
||||
<title>Test for HTMLSelectElement.selectedOptions</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=596681">Mozilla Bug 596681</a>
|
||||
<p id="display"></p>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
/** Test for HTMLSelectElement's selectedOptions attribute.
|
||||
*
|
||||
* selectedOptions is a live list of the options that have selectedness of true
|
||||
* (not the selected content attribute).
|
||||
*
|
||||
* See http://www.whatwg.org/html/#dom-select-selectedoptions
|
||||
**/
|
||||
|
||||
function checkSelectedOptions(size, elements)
|
||||
{
|
||||
is(selectedOptions.length, size,
|
||||
"select should have " + size + " selected options");
|
||||
for (let i = 0; i < size; ++i) {
|
||||
ok(selectedOptions[i], "selected option is valid");
|
||||
if (selectedOptions[i]) {
|
||||
is(selectedOptions[i].value, elements[i].value, "selected options are correct");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let select = document.createElement("select");
|
||||
document.body.appendChild(select);
|
||||
let selectedOptions = select.selectedOptions;
|
||||
|
||||
ok("selectedOptions" in select,
|
||||
"select element should have a selectedOptions IDL attribute");
|
||||
|
||||
ok(select.selectedOptions instanceof HTMLCollection,
|
||||
"selectedOptions should be an HTMLCollection instance");
|
||||
|
||||
let option1 = document.createElement("option");
|
||||
let option2 = document.createElement("option");
|
||||
let option3 = document.createElement("option");
|
||||
option1.id = "option1";
|
||||
option1.value = "option1";
|
||||
option2.value = "option2";
|
||||
option3.value = "option3";
|
||||
|
||||
checkSelectedOptions(0, null);
|
||||
|
||||
select.add(option1, null);
|
||||
is(selectedOptions.namedItem("option1").value, "option1", "named getter works");
|
||||
checkSelectedOptions(1, [option1]);
|
||||
|
||||
select.add(option2, null);
|
||||
checkSelectedOptions(1, [option1]);
|
||||
|
||||
select.options[1].selected = true;
|
||||
checkSelectedOptions(1, [option2]);
|
||||
|
||||
select.multiple = true;
|
||||
checkSelectedOptions(1, [option2]);
|
||||
|
||||
select.options[0].selected = true;
|
||||
checkSelectedOptions(2, [option1, option2]);
|
||||
|
||||
option1.selected = false;
|
||||
// Usinig selected directly on the option should work.
|
||||
checkSelectedOptions(1, [option2]);
|
||||
|
||||
select.remove(1);
|
||||
select.add(option2, 0);
|
||||
select.options[0].selected = true;
|
||||
select.options[1].selected = true;
|
||||
// Should be in tree order.
|
||||
checkSelectedOptions(2, [option2, option1]);
|
||||
|
||||
select.add(option3, null);
|
||||
checkSelectedOptions(2, [option2, option1]);
|
||||
|
||||
select.options[2].selected = true;
|
||||
checkSelectedOptions(3, [option2, option1, option3]);
|
||||
|
||||
select.length = 0;
|
||||
option1.selected = false;
|
||||
option2.selected = false;
|
||||
option3.selected = false;
|
||||
var optgroup1 = document.createElement("optgroup");
|
||||
optgroup1.appendChild(option1);
|
||||
optgroup1.appendChild(option2);
|
||||
select.add(optgroup1)
|
||||
var optgroup2 = document.createElement("optgroup");
|
||||
optgroup2.appendChild(option3);
|
||||
select.add(optgroup2);
|
||||
|
||||
checkSelectedOptions(0, null);
|
||||
|
||||
option2.selected = true;
|
||||
checkSelectedOptions(1, [option2]);
|
||||
|
||||
option3.selected = true;
|
||||
checkSelectedOptions(2, [option2, option3]);
|
||||
|
||||
optgroup1.removeChild(option2);
|
||||
checkSelectedOptions(1, [option3]);
|
||||
|
||||
document.body.removeChild(select);
|
||||
option1.selected = true;
|
||||
checkSelectedOptions(2, [option1, option3]);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -19,7 +19,7 @@
|
||||
|
||||
interface nsIDOMValidityState;
|
||||
|
||||
[scriptable, uuid(846578b2-6d4f-4399-86cc-2c05f19469d0)]
|
||||
[scriptable, uuid(d8914a2d-3556-4b66-911c-a84c4394e7fa)]
|
||||
interface nsIDOMHTMLSelectElement : nsISupports
|
||||
{
|
||||
attribute boolean autofocus;
|
||||
@ -44,6 +44,7 @@ interface nsIDOMHTMLSelectElement : nsISupports
|
||||
raises(DOMException);
|
||||
void remove(in long index);
|
||||
|
||||
readonly attribute nsIDOMHTMLCollection selectedOptions;
|
||||
attribute long selectedIndex;
|
||||
attribute DOMString value;
|
||||
|
||||
|
@ -38,7 +38,7 @@ interface HTMLSelectElement : HTMLElement {
|
||||
[Throws]
|
||||
setter creator void (unsigned long index, HTMLOptionElement? option);
|
||||
|
||||
// NYI: readonly attribute HTMLCollection selectedOptions;
|
||||
readonly attribute HTMLCollection selectedOptions;
|
||||
[SetterThrows, Pure]
|
||||
attribute long selectedIndex;
|
||||
[Pure]
|
||||
|
Loading…
x
Reference in New Issue
Block a user