Skip to main content

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::context::JSContext;
8use js::rust::HandleObject;
9use script_bindings::cell::DomRefCell;
10
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::attributes::storage::AttrRef;
17use crate::dom::element::{AttributeMutation, Element};
18use crate::dom::html::htmlelement::HTMLElement;
19use crate::dom::html::htmlformelement::{FormControl, HTMLFormElement};
20use crate::dom::node::virtualmethods::VirtualMethods;
21use crate::dom::node::{Node, NodeTraits};
22use crate::dom::nodelist::NodeList;
23use crate::dom::validation::Validatable;
24use crate::dom::validitystate::ValidityState;
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        cx: &mut js::context::JSContext,
52        local_name: LocalName,
53        prefix: Option<Prefix>,
54        document: &Document,
55        proto: Option<HandleObject>,
56    ) -> DomRoot<HTMLOutputElement> {
57        Node::reflect_node_with_proto(
58            cx,
59            Box::new(HTMLOutputElement::new_inherited(
60                local_name, prefix, document,
61            )),
62            document,
63            proto,
64        )
65    }
66
67    pub(crate) fn reset(&self, cx: &mut JSContext) {
68        Node::string_replace_all(cx, self.DefaultValue(), self.upcast::<Node>());
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, cx: &mut JSContext, value: DOMString) {
94        if self.default_value_override.borrow().is_none() {
95            // Step 1 ("and return")
96            Node::string_replace_all(cx, value, self.upcast::<Node>());
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, cx: &mut JSContext, value: DOMString) {
110        *self.default_value_override.borrow_mut() = Some(self.DefaultValue());
111        Node::string_replace_all(cx, value, self.upcast::<Node>());
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, cx: &mut JSContext) -> DomRoot<ValidityState> {
132        self.validity_state(cx)
133    }
134
135    /// <https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity>
136    fn CheckValidity(&self, cx: &mut JSContext) -> bool {
137        self.check_validity(cx)
138    }
139
140    /// <https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity>
141    fn ReportValidity(&self, cx: &mut JSContext) -> bool {
142        self.report_validity(cx)
143    }
144
145    /// <https://html.spec.whatwg.org/multipage/#dom-cva-validationmessage>
146    fn ValidationMessage(&self, cx: &mut JSContext) -> DOMString {
147        self.validation_message(cx)
148    }
149
150    /// <https://html.spec.whatwg.org/multipage/#dom-cva-setcustomvalidity>
151    fn SetCustomValidity(&self, cx: &mut JSContext, error: DOMString) {
152        self.validity_state(cx).set_custom_error_message(cx, 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(
162        &self,
163        cx: &mut js::context::JSContext,
164        attr: AttrRef<'_>,
165        mutation: AttributeMutation,
166    ) {
167        self.super_type()
168            .unwrap()
169            .attribute_mutated(cx, attr, mutation);
170        if attr.local_name() == &local_name!("form") {
171            self.form_attribute_mutated(cx, mutation);
172        }
173    }
174}
175
176impl FormControl for HTMLOutputElement {
177    fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
178        self.form_owner.get()
179    }
180
181    fn set_form_owner(&self, _cx: &mut JSContext, form: Option<&HTMLFormElement>) {
182        self.form_owner.set(form);
183    }
184
185    fn to_html_element(&self) -> &HTMLElement {
186        self.upcast::<HTMLElement>()
187    }
188}
189
190impl Validatable for HTMLOutputElement {
191    fn as_element(&self) -> &Element {
192        self.upcast()
193    }
194
195    fn validity_state(&self, cx: &mut JSContext) -> DomRoot<ValidityState> {
196        self.validity_state
197            .or_init(|| ValidityState::new(cx, &self.owner_window(), self.upcast()))
198    }
199
200    fn is_instance_validatable(&self) -> bool {
201        // output is not a submittable element (https://html.spec.whatwg.org/multipage/#category-submit)
202        false
203    }
204}