diff options
Diffstat (limited to 'components/script/dom/htmllabelelement.rs')
-rw-r--r-- | components/script/dom/htmllabelelement.rs | 50 |
1 files changed, 38 insertions, 12 deletions
diff --git a/components/script/dom/htmllabelelement.rs b/components/script/dom/htmllabelelement.rs index 0a1401d6283..cca8e0f03c9 100644 --- a/components/script/dom/htmllabelelement.rs +++ b/components/script/dom/htmllabelelement.rs @@ -4,8 +4,11 @@ use crate::dom::activation::{synthetic_click_activation, Activatable, ActivationSource}; use crate::dom::attr::Attr; +use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; +use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use crate::dom::bindings::codegen::Bindings::HTMLLabelElementBinding; use crate::dom::bindings::codegen::Bindings::HTMLLabelElementBinding::HTMLLabelElementMethods; +use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; @@ -15,7 +18,7 @@ use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement}; -use crate::dom::node::{document_from_node, Node, ShadowIncluding}; +use crate::dom::node::{Node, ShadowIncluding}; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; @@ -99,10 +102,6 @@ impl HTMLLabelElementMethods for HTMLLabelElement { // https://html.spec.whatwg.org/multipage/#dom-label-control fn GetControl(&self) -> Option<DomRoot<HTMLElement>> { - if !self.upcast::<Node>().is_in_doc() { - return None; - } - let for_attr = match self .upcast::<Element>() .get_attribute(&ns!(), &local_name!("for")) @@ -111,13 +110,40 @@ impl HTMLLabelElementMethods for HTMLLabelElement { None => return self.first_labelable_descendant(), }; - let for_value = for_attr.value(); - document_from_node(self) - .get_element_by_id(for_value.as_atom()) - .and_then(DomRoot::downcast::<HTMLElement>) - .into_iter() - .filter(|e| e.is_labelable_element()) - .next() + let for_value = for_attr.Value(); + + // "If the attribute is specified and there is an element in the tree + // whose ID is equal to the value of the for attribute, and the first + // such element in tree order is a labelable element, then that + // element is the label element's labeled control." + // Two subtle points here: we need to search the _tree_, which is + // not necessarily the document if we're detached from the document, + // and we only consider one element even if a later element with + // the same ID is labelable. + + let maybe_found = self + .upcast::<Node>() + .GetRootNode(&GetRootNodeOptions::empty()) + .traverse_preorder(ShadowIncluding::No) + .find_map(|e| { + if let Some(htmle) = e.downcast::<HTMLElement>() { + if htmle.upcast::<Element>().Id() == for_value { + Some(DomRoot::from_ref(htmle)) + } else { + None + } + } else { + None + } + }); + // We now have the element that we would return, but only return it + // if it's labelable. + if let Some(ref maybe_labelable) = maybe_found { + if maybe_labelable.is_labelable_element() { + return maybe_found; + } + } + None } } |