diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs index 4ebb2860a793..d61f4b6ffb0f 100644 --- a/components/script/dom/htmloptionelement.rs +++ b/components/script/dom/htmloptionelement.rs @@ -28,6 +28,7 @@ use crate::dom::window::Window; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix, QualName}; use std::cell::Cell; +use std::convert::TryInto; use style::element_state::ElementState; use style::str::{split_html_space_chars, str_join}; @@ -127,6 +128,41 @@ impl HTMLOptionElement { select.ask_for_reset(); } } + + // https://html.spec.whatwg.org/multipage/#concept-option-index + fn index(&self) -> i32 { + if let Some(parent) = self.upcast::().GetParentNode() { + if let Some(select_parent) = parent.downcast::() { + // return index in parent select's list of options + return self.index_in_select(select_parent); + } else if parent.is::() { + if let Some(grandparent) = parent.GetParentNode() { + if let Some(select_grandparent) = grandparent.downcast::() { + // return index in grandparent select's list of options + return self.index_in_select(select_grandparent); + } + } + } + } + // "If the option element is not in a list of options, + // then the option element's index is zero." + // self is neither a child of a select, nor a grandchild of a select + // via an optgroup, so it is not in a list of options + 0 + } + + fn index_in_select(&self, select: &HTMLSelectElement) -> i32 { + match select.list_of_options().position(|n| &*n == self) { + Some(index) => index.try_into().unwrap_or(0), + None => { + // shouldn't happen but not worth a browser panic + warn!( + "HTMLOptionElement called index_in_select at a select that did not contain it" + ); + 0 + }, + } + } } // FIXME(ajeffrey): Provide a way of buffering DOMStrings other than using Strings @@ -225,6 +261,11 @@ impl HTMLOptionElementMethods for HTMLOptionElement { self.selectedness.set(selected); self.pick_if_selected_and_reset(); } + + // https://html.spec.whatwg.org/multipage/#dom-option-index + fn Index(&self) -> i32 { + self.index() + } } impl VirtualMethods for HTMLOptionElement { diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index f6330b9b65a3..bef4bfff8b4d 100755 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -102,7 +102,7 @@ impl HTMLSelectElement { } // https://html.spec.whatwg.org/multipage/#concept-select-option-list - fn list_of_options(&self) -> impl Iterator> { + pub fn list_of_options(&self) -> impl Iterator> { self.upcast::().children().flat_map(|node| { if node.is::() { let node = DomRoot::downcast::(node).unwrap(); diff --git a/components/script/dom/webidls/HTMLOptionElement.webidl b/components/script/dom/webidls/HTMLOptionElement.webidl index 65f37458295e..c995070d0e78 100644 --- a/components/script/dom/webidls/HTMLOptionElement.webidl +++ b/components/script/dom/webidls/HTMLOptionElement.webidl @@ -22,5 +22,5 @@ interface HTMLOptionElement : HTMLElement { [CEReactions] attribute DOMString text; - // readonly attribute long index; + readonly attribute long index; }; diff --git a/tests/wpt/metadata/html/dom/idlharness.https.html.ini b/tests/wpt/metadata/html/dom/idlharness.https.html.ini index 7d065c82a88b..87fb3f15f10e 100644 --- a/tests/wpt/metadata/html/dom/idlharness.https.html.ini +++ b/tests/wpt/metadata/html/dom/idlharness.https.html.ini @@ -2337,9 +2337,6 @@ [HTMLInputElement interface: createInput("url") must inherit property "stepDown(long)" with the proper type] expected: FAIL - [HTMLOptionElement interface: new Option() must inherit property "index" with the proper type] - expected: FAIL - [HTMLInputElement interface: createInput("password") must inherit property "height" with the proper type] expected: FAIL @@ -3702,9 +3699,6 @@ [HTMLInputElement interface: calling setCustomValidity(DOMString) on createInput("range") with too few arguments must throw TypeError] expected: FAIL - [HTMLOptionElement interface: attribute index] - expected: FAIL - [HTMLInputElement interface: document.createElement("input") must inherit property "valueAsNumber" with the proper type] expected: FAIL @@ -4923,9 +4917,6 @@ [HTMLInputElement interface: createInput("number") must inherit property "valueAsDate" with the proper type] expected: FAIL - [HTMLOptionElement interface: document.createElement("option") must inherit property "index" with the proper type] - expected: FAIL - [HTMLInputElement interface: createInput("email") must inherit property "setCustomValidity(DOMString)" with the proper type] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-option-element/option-index.html.ini b/tests/wpt/metadata/html/semantics/forms/the-option-element/option-index.html.ini deleted file mode 100644 index 07f5873d1b4a..000000000000 --- a/tests/wpt/metadata/html/semantics/forms/the-option-element/option-index.html.ini +++ /dev/null @@ -1,14 +0,0 @@ -[option-index.html] - type: testharness - [option index should work inside the document] - expected: FAIL - - [option index should always be 0 for options in datalists] - expected: FAIL - - [option index should always be 0 for options with no container] - expected: FAIL - - [option index should always be 0 for options not even in the document] - expected: FAIL -