diff options
Diffstat (limited to 'components/script/dom/htmllabelelement.rs')
-rw-r--r-- | components/script/dom/htmllabelelement.rs | 179 |
1 files changed, 101 insertions, 78 deletions
diff --git a/components/script/dom/htmllabelelement.rs b/components/script/dom/htmllabelelement.rs index 73a62af5570..970f4a97b7a 100644 --- a/components/script/dom/htmllabelelement.rs +++ b/components/script/dom/htmllabelelement.rs @@ -1,48 +1,57 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use dom::activation::{Activatable, ActivationSource, synthetic_click_activation}; -use dom::attr::Attr; -use dom::bindings::codegen::Bindings::HTMLLabelElementBinding; -use dom::bindings::codegen::Bindings::HTMLLabelElementBinding::HTMLLabelElementMethods; -use dom::bindings::inheritance::Castable; -use dom::bindings::js::Root; -use dom::bindings::str::DOMString; -use dom::document::Document; -use dom::element::{AttributeMutation, Element}; -use dom::event::Event; -use dom::eventtarget::EventTarget; -use dom::htmlelement::HTMLElement; -use dom::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement}; -use dom::node::{document_from_node, Node}; -use dom::virtualmethods::VirtualMethods; + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::activation::Activatable; +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::HTMLElementBinding::HTMLElementMethods; +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; +use crate::dom::document::Document; +use crate::dom::element::{AttributeMutation, Element}; +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::{Node, ShadowIncluding}; +use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; -use html5ever_atoms::LocalName; +use html5ever::{LocalName, Prefix}; use style::attr::AttrValue; #[dom_struct] pub struct HTMLLabelElement { - htmlelement: HTMLElement + htmlelement: HTMLElement, } impl HTMLLabelElement { - fn new_inherited(local_name: LocalName, - prefix: Option<DOMString>, - document: &Document) -> HTMLLabelElement { + fn new_inherited( + local_name: LocalName, + prefix: Option<Prefix>, + document: &Document, + ) -> HTMLLabelElement { HTMLLabelElement { - htmlelement: - HTMLElement::new_inherited(local_name, prefix, document), + htmlelement: HTMLElement::new_inherited(local_name, prefix, document), } } #[allow(unrooted_must_root)] - pub fn new(local_name: LocalName, - prefix: Option<DOMString>, - document: &Document) -> Root<HTMLLabelElement> { - Node::reflect_node(box HTMLLabelElement::new_inherited(local_name, prefix, document), - document, - HTMLLabelElementBinding::Wrap) + pub fn new( + local_name: LocalName, + prefix: Option<Prefix>, + document: &Document, + ) -> DomRoot<HTMLLabelElement> { + Node::reflect_node( + Box::new(HTMLLabelElement::new_inherited( + local_name, prefix, document, + )), + document, + ) } } @@ -55,40 +64,21 @@ impl Activatable for HTMLLabelElement { true } - // https://html.spec.whatwg.org/multipage/#run-pre-click-activation-steps - // https://html.spec.whatwg.org/multipage/#the-button-element:activation-behavior - fn pre_click_activation(&self) { - } - - // https://html.spec.whatwg.org/multipage/#run-canceled-activation-steps - fn canceled_activation(&self) { - } - - // https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps + // https://html.spec.whatwg.org/multipage/#the-label-element:activation_behaviour + // Basically this is telling us that if activation bubbles up to the label + // at all, we are free to do an implementation-dependent thing; + // firing a click event is an example, and the precise details of that + // click event (e.g. isTrusted) are not specified. fn activation_behavior(&self, _event: &Event, _target: &EventTarget) { if let Some(e) = self.GetControl() { - let elem = e.upcast::<Element>(); - synthetic_click_activation(elem, - false, - false, - false, - false, - ActivationSource::NotFromClick); + e.Click(); } } - - // https://html.spec.whatwg.org/multipage/#implicit-submission - fn implicit_submission(&self, _ctrl_key: bool, _shift_key: bool, _alt_key: bool, _meta_key: bool) { - //FIXME: Investigate and implement implicit submission for label elements - // Issue filed at https://github.com/servo/servo/issues/8263 - } - - } impl HTMLLabelElementMethods for HTMLLabelElement { // https://html.spec.whatwg.org/multipage/#dom-fae-form - fn GetForm(&self) -> Option<Root<HTMLFormElement>> { + fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> { self.form_owner() } @@ -99,34 +89,64 @@ impl HTMLLabelElementMethods for HTMLLabelElement { make_atomic_setter!(SetHtmlFor, "for"); // https://html.spec.whatwg.org/multipage/#dom-label-control - fn GetControl(&self) -> Option<Root<HTMLElement>> { - if !self.upcast::<Node>().is_in_doc() { - return None; - } - - let for_attr = match self.upcast::<Element>().get_attribute(&ns!(), &local_name!("for")) { + fn GetControl(&self) -> Option<DomRoot<HTMLElement>> { + let for_attr = match self + .upcast::<Element>() + .get_attribute(&ns!(), &local_name!("for")) + { Some(for_attr) => for_attr, 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(Root::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 } } impl VirtualMethods for HTMLLabelElement { - fn super_type(&self) -> Option<&VirtualMethods> { - Some(self.upcast::<HTMLElement>() as &VirtualMethods) + fn super_type(&self) -> Option<&dyn VirtualMethods> { + Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods) } fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue { match name { &local_name!("for") => AttrValue::from_atomic(value.into()), - _ => self.super_type().unwrap().parse_plain_attribute(name, value), + _ => self + .super_type() + .unwrap() + .parse_plain_attribute(name, value), } } @@ -142,20 +162,23 @@ impl VirtualMethods for HTMLLabelElement { } impl HTMLLabelElement { - pub fn first_labelable_descendant(&self) -> Option<Root<HTMLElement>> { + pub fn first_labelable_descendant(&self) -> Option<DomRoot<HTMLElement>> { self.upcast::<Node>() - .traverse_preorder() - .filter_map(Root::downcast::<HTMLElement>) + .traverse_preorder(ShadowIncluding::No) + .filter_map(DomRoot::downcast::<HTMLElement>) .filter(|elem| elem.is_labelable_element()) .next() } } impl FormControl for HTMLLabelElement { - fn form_owner(&self) -> Option<Root<HTMLFormElement>> { - self.GetControl().map(Root::upcast::<Element>).and_then(|elem| { - elem.as_maybe_form_control().and_then(|control| control.form_owner()) - }) + fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> { + self.GetControl() + .map(DomRoot::upcast::<Element>) + .and_then(|elem| { + elem.as_maybe_form_control() + .and_then(|control| control.form_owner()) + }) } fn set_form_owner(&self, _: Option<&HTMLFormElement>) { |