diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 959bca74b54..b4089fed6e3 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -1058,7 +1058,7 @@ impl HTMLFormElement { NodeTypeId::Element(ElementTypeId::HTMLElement( HTMLElementTypeId::HTMLOutputElement, )) => { - // Unimplemented + child.downcast::().unwrap().reset(); }, _ => {}, } diff --git a/components/script/dom/htmloutputelement.rs b/components/script/dom/htmloutputelement.rs index 9314672d3d0..548c81bb1b4 100644 --- a/components/script/dom/htmloutputelement.rs +++ b/components/script/dom/htmloutputelement.rs @@ -3,10 +3,12 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::attr::Attr; +use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::HTMLOutputElementBinding; use crate::dom::bindings::codegen::Bindings::HTMLOutputElementBinding::HTMLOutputElementMethods; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; +use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::element::{AttributeMutation, Element}; use crate::dom::htmlelement::HTMLElement; @@ -23,6 +25,7 @@ pub struct HTMLOutputElement { htmlelement: HTMLElement, form_owner: MutNullableDom, labels_node_list: MutNullableDom, + default_value_override: DomRefCell>, } impl HTMLOutputElement { @@ -35,6 +38,7 @@ impl HTMLOutputElement { htmlelement: HTMLElement::new_inherited(local_name, prefix, document), form_owner: Default::default(), labels_node_list: Default::default(), + default_value_override: DomRefCell::new(None), } } @@ -52,6 +56,11 @@ impl HTMLOutputElement { HTMLOutputElementBinding::Wrap, ) } + + pub fn reset(&self) { + Node::string_replace_all(self.DefaultValue(), self.upcast::()); + *self.default_value_override.borrow_mut() = None; + } } impl HTMLOutputElementMethods for HTMLOutputElement { @@ -68,6 +77,43 @@ impl HTMLOutputElementMethods for HTMLOutputElement { // https://html.spec.whatwg.org/multipage/#dom-lfe-labels make_labels_getter!(Labels, labels_node_list); + + // https://html.spec.whatwg.org/multipage/#dom-output-defaultvaleu + fn DefaultValue(&self) -> DOMString { + let dvo = self.default_value_override.borrow(); + if let Some(ref dv) = *dvo { + dv.clone() + } else { + self.upcast::().descendant_text_content() + } + } + + // https://html.spec.whatwg.org/multipage/#dom-output-defaultvalue + fn SetDefaultValue(&self, value: DOMString) { + if self.default_value_override.borrow().is_none() { + // Step 1 ("and return") + Node::string_replace_all(value.clone(), self.upcast::()); + } else { + // Step 2, if not returned from step 1 + *self.default_value_override.borrow_mut() = Some(value); + } + } + + // https://html.spec.whatwg.org/multipage/#dom-output-value + fn Value(&self) -> DOMString { + self.upcast::().descendant_text_content() + } + + // https://html.spec.whatwg.org/multipage/#dom-output-value + fn SetValue(&self, value: DOMString) { + *self.default_value_override.borrow_mut() = Some(self.DefaultValue()); + Node::string_replace_all(value, self.upcast::()); + } + + // https://html.spec.whatwg.org/multipage/#dom-output-type + fn Type(&self) -> DOMString { + return DOMString::from("output"); + } } impl VirtualMethods for HTMLOutputElement { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 8ee51283146..d674970ae71 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -2017,6 +2017,16 @@ impl Node { parent.owner_doc().remove_script_and_layout_blocker(); } + // https://dom.spec.whatwg.org/multipage/#string-replace-all + pub fn string_replace_all(string: DOMString, parent: &Node) { + if string.len() == 0 { + Node::replace_all(None, parent); + } else { + let text = Text::new(string, &document_from_node(parent)); + Node::replace_all(Some(text.upcast::()), parent); + }; + } + // https://dom.spec.whatwg.org/#concept-node-pre-remove fn pre_remove(child: &Node, parent: &Node) -> Fallible> { // Step 1. @@ -2213,6 +2223,11 @@ impl Node { Node::collect_text_contents(self.children()) } + /// + pub fn descendant_text_content(&self) -> DOMString { + Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No)) + } + pub fn collect_text_contents>>(iterator: T) -> DOMString { let mut content = String::new(); for node in iterator { diff --git a/components/script/dom/webidls/HTMLOutputElement.webidl b/components/script/dom/webidls/HTMLOutputElement.webidl index ac631ab7906..b956d593d8b 100644 --- a/components/script/dom/webidls/HTMLOutputElement.webidl +++ b/components/script/dom/webidls/HTMLOutputElement.webidl @@ -12,11 +12,11 @@ interface HTMLOutputElement : HTMLElement { // [CEReactions] // attribute DOMString name; - // readonly attribute DOMString type; - // [CEReactions] - // attribute DOMString defaultValue; - // [CEReactions] - // attribute DOMString value; + [Pure] readonly attribute DOMString type; + [CEReactions] + attribute DOMString defaultValue; + [CEReactions] + attribute DOMString value; // readonly attribute boolean willValidate; readonly attribute ValidityState validity; diff --git a/tests/wpt/metadata/custom-elements/reactions/HTMLOutputElement.html.ini b/tests/wpt/metadata/custom-elements/reactions/HTMLOutputElement.html.ini deleted file mode 100644 index 27b3a75a6e9..00000000000 --- a/tests/wpt/metadata/custom-elements/reactions/HTMLOutputElement.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[HTMLOutputElement.html] - type: testharness - [value on HTMLOutputElement must enqueue disconnectedCallback when removing a custom element] - expected: FAIL - - [defaultValue on HTMLOutputElement must enqueue disconnectedCallback when removing a custom element] - expected: FAIL - - [Custom Elements: CEReactions on HTMLOutputElement interface] - expected: FAIL - diff --git a/tests/wpt/metadata/html/dom/idlharness.https.html.ini b/tests/wpt/metadata/html/dom/idlharness.https.html.ini index 0a7f3af6a0f..7d065c82a88 100644 --- a/tests/wpt/metadata/html/dom/idlharness.https.html.ini +++ b/tests/wpt/metadata/html/dom/idlharness.https.html.ini @@ -2070,9 +2070,6 @@ [HTMLInputElement interface: createInput("button") must inherit property "align" with the proper type] expected: FAIL - [HTMLOutputElement interface: document.createElement("output") must inherit property "value" with the proper type] - expected: FAIL - [HTMLMarqueeElement interface: document.createElement("marquee") must inherit property "start()" with the proper type] expected: FAIL @@ -2715,9 +2712,6 @@ [Stringification of document.createElement("menu")] expected: FAIL - [HTMLOutputElement interface: attribute defaultValue] - expected: FAIL - [HTMLCanvasElement interface: calling toBlob(BlobCallback, DOMString, any) on document.createElement("canvas") with too few arguments must throw TypeError] expected: FAIL @@ -3720,9 +3714,6 @@ [HTMLInputElement interface: createInput("time") must inherit property "reportValidity()" with the proper type] expected: FAIL - [HTMLOutputElement interface: attribute value] - expected: FAIL - [HTMLObjectElement interface: attribute declare] expected: FAIL @@ -3900,9 +3891,6 @@ [HTMLInputElement interface: createInput("time") must inherit property "list" with the proper type] expected: FAIL - [HTMLOutputElement interface: document.createElement("output") must inherit property "type" with the proper type] - expected: FAIL - [HTMLInputElement interface: calling stepUp(long) on createInput("file") with too few arguments must throw TypeError] expected: FAIL @@ -4542,9 +4530,6 @@ [HTMLEmbedElement interface: attribute width] expected: FAIL - [HTMLOutputElement interface: attribute type] - expected: FAIL - [HTMLObjectElement interface: document.createElement("object") must inherit property "standby" with the proper type] expected: FAIL @@ -4761,9 +4746,6 @@ [HTMLSelectElement interface: document.createElement("select") must inherit property "willValidate" with the proper type] expected: FAIL - [HTMLOutputElement interface: document.createElement("output") must inherit property "defaultValue" with the proper type] - expected: FAIL - [HTMLInputElement interface: calling stepDown(long) on createInput("reset") with too few arguments must throw TypeError] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/resetting-a-form/reset-form.html.ini b/tests/wpt/metadata/html/semantics/forms/resetting-a-form/reset-form.html.ini deleted file mode 100644 index 7a0f14f6953..00000000000 --- a/tests/wpt/metadata/html/semantics/forms/resetting-a-form/reset-form.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[reset-form.html] - type: testharness - [Resetting by calling the reset() method] - expected: FAIL - - [Resetting by clicking the button in reset status] - expected: FAIL - - [Resetting by clicking the input in reset status] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/forms/the-output-element/mutations.window.js.ini b/tests/wpt/metadata/html/semantics/forms/the-output-element/mutations.window.js.ini index 933f5c6921c..cba79317aa4 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-output-element/mutations.window.js.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-output-element/mutations.window.js.ini @@ -2,6 +2,3 @@ [Descendant mutations and output.value and .defaultValue] expected: FAIL - [output and output.form.reset()] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/forms/the-output-element/output.html.ini b/tests/wpt/metadata/html/semantics/forms/the-output-element/output.html.ini deleted file mode 100644 index f26529f0143..00000000000 --- a/tests/wpt/metadata/html/semantics/forms/the-output-element/output.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[output.html] - type: testharness - [output value and defaultValue] - expected: FAIL -