script/dom/html/
htmloutputelement.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name};
7use js::rust::HandleObject;
8
9use crate::dom::attr::Attr;
10use crate::dom::bindings::cell::DomRefCell;
11use crate::dom::bindings::codegen::Bindings::HTMLOutputElementBinding::HTMLOutputElementMethods;
12use crate::dom::bindings::inheritance::Castable;
13use crate::dom::bindings::root::{DomRoot, MutNullableDom};
14use crate::dom::bindings::str::DOMString;
15use crate::dom::document::Document;
16use crate::dom::element::{AttributeMutation, Element};
17use crate::dom::html::htmlelement::HTMLElement;
18use crate::dom::html::htmlformelement::{FormControl, HTMLFormElement};
19use crate::dom::node::{Node, NodeTraits};
20use crate::dom::nodelist::NodeList;
21use crate::dom::validation::Validatable;
22use crate::dom::validitystate::ValidityState;
23use crate::dom::virtualmethods::VirtualMethods;
24use crate::script_runtime::CanGc;
25
26#[dom_struct]
27pub(crate) struct HTMLOutputElement {
28    htmlelement: HTMLElement,
29    form_owner: MutNullableDom<HTMLFormElement>,
30    labels_node_list: MutNullableDom<NodeList>,
31    default_value_override: DomRefCell<Option<DOMString>>,
32    validity_state: MutNullableDom<ValidityState>,
33}
34
35impl HTMLOutputElement {
36    fn new_inherited(
37        local_name: LocalName,
38        prefix: Option<Prefix>,
39        document: &Document,
40    ) -> HTMLOutputElement {
41        HTMLOutputElement {
42            htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
43            form_owner: Default::default(),
44            labels_node_list: Default::default(),
45            default_value_override: DomRefCell::new(None),
46            validity_state: Default::default(),
47        }
48    }
49
50    pub(crate) fn new(
51        local_name: LocalName,
52        prefix: Option<Prefix>,
53        document: &Document,
54        proto: Option<HandleObject>,
55        can_gc: CanGc,
56    ) -> DomRoot<HTMLOutputElement> {
57        Node::reflect_node_with_proto(
58            Box::new(HTMLOutputElement::new_inherited(
59                local_name, prefix, document,
60            )),
61            document,
62            proto,
63            can_gc,
64        )
65    }
66
67    pub(crate) fn reset(&self, can_gc: CanGc) {
68        Node::string_replace_all(self.DefaultValue(), self.upcast::<Node>(), can_gc);
69        *self.default_value_override.borrow_mut() = None;
70    }
71}
72
73impl HTMLOutputElementMethods<crate::DomTypeHolder> for HTMLOutputElement {
74    /// <https://html.spec.whatwg.org/multipage/#dom-fae-form>
75    fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
76        self.form_owner()
77    }
78
79    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
80    make_labels_getter!(Labels, labels_node_list);
81
82    /// <https://html.spec.whatwg.org/multipage/#dom-output-defaultvaleu>
83    fn DefaultValue(&self) -> DOMString {
84        let dvo = self.default_value_override.borrow();
85        if let Some(ref dv) = *dvo {
86            dv.clone()
87        } else {
88            self.upcast::<Node>().descendant_text_content()
89        }
90    }
91
92    /// <https://html.spec.whatwg.org/multipage/#dom-output-defaultvalue>
93    fn SetDefaultValue(&self, value: DOMString, can_gc: CanGc) {
94        if self.default_value_override.borrow().is_none() {
95            // Step 1 ("and return")
96            Node::string_replace_all(value.clone(), self.upcast::<Node>(), can_gc);
97        } else {
98            // Step 2, if not returned from step 1
99            *self.default_value_override.borrow_mut() = Some(value);
100        }
101    }
102
103    /// <https://html.spec.whatwg.org/multipage/#dom-output-value>
104    fn Value(&self) -> DOMString {
105        self.upcast::<Node>().descendant_text_content()
106    }
107
108    /// <https://html.spec.whatwg.org/multipage/#dom-output-value>
109    fn SetValue(&self, value: DOMString, can_gc: CanGc) {
110        *self.default_value_override.borrow_mut() = Some(self.DefaultValue());
111        Node::string_replace_all(value, self.upcast::<Node>(), can_gc);
112    }
113
114    /// <https://html.spec.whatwg.org/multipage/#dom-output-type>
115    fn Type(&self) -> DOMString {
116        DOMString::from("output")
117    }
118
119    // https://html.spec.whatwg.org/multipage/#dom-fe-name
120    make_atomic_setter!(SetName, "name");
121
122    // https://html.spec.whatwg.org/multipage/#dom-fe-name
123    make_getter!(Name, "name");
124
125    /// <https://html.spec.whatwg.org/multipage/#dom-cva-willvalidate>
126    fn WillValidate(&self) -> bool {
127        self.is_instance_validatable()
128    }
129
130    /// <https://html.spec.whatwg.org/multipage/#dom-cva-validity>
131    fn Validity(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
132        self.validity_state(can_gc)
133    }
134
135    /// <https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity>
136    fn CheckValidity(&self, can_gc: CanGc) -> bool {
137        self.check_validity(can_gc)
138    }
139
140    /// <https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity>
141    fn ReportValidity(&self, can_gc: CanGc) -> bool {
142        self.report_validity(can_gc)
143    }
144
145    /// <https://html.spec.whatwg.org/multipage/#dom-cva-validationmessage>
146    fn ValidationMessage(&self) -> DOMString {
147        self.validation_message()
148    }
149
150    /// <https://html.spec.whatwg.org/multipage/#dom-cva-setcustomvalidity>
151    fn SetCustomValidity(&self, error: DOMString, can_gc: CanGc) {
152        self.validity_state(can_gc).set_custom_error_message(error);
153    }
154}
155
156impl VirtualMethods for HTMLOutputElement {
157    fn super_type(&self) -> Option<&dyn VirtualMethods> {
158        Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
159    }
160
161    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
162        self.super_type()
163            .unwrap()
164            .attribute_mutated(attr, mutation, can_gc);
165        if attr.local_name() == &local_name!("form") {
166            self.form_attribute_mutated(mutation, can_gc);
167        }
168    }
169}
170
171impl FormControl for HTMLOutputElement {
172    fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
173        self.form_owner.get()
174    }
175
176    fn set_form_owner(&self, form: Option<&HTMLFormElement>) {
177        self.form_owner.set(form);
178    }
179
180    fn to_element(&self) -> &Element {
181        self.upcast::<Element>()
182    }
183}
184
185impl Validatable for HTMLOutputElement {
186    fn as_element(&self) -> &Element {
187        self.upcast()
188    }
189
190    fn validity_state(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
191        self.validity_state
192            .or_init(|| ValidityState::new(&self.owner_window(), self.upcast(), can_gc))
193    }
194
195    fn is_instance_validatable(&self) -> bool {
196        // output is not a submittable element (https://html.spec.whatwg.org/multipage/#category-submit)
197        false
198    }
199}