aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/htmllabelelement.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/htmllabelelement.rs')
-rw-r--r--components/script/dom/htmllabelelement.rs50
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
}
}