Auto merge of #25412 - pshaughn:outputvalue, r=jdm

implement HTMLOutputElement.value

HTMLOutputElement now works. I believe layout as well as script is working for it, since it works by putting strings into a child Text node and lays itself out exactly like a span, not requiring any special case rendering like textareas or input elements.

Remaining failures are one mutation test case that everyone else is also failing and probably represents a test/spec mismatch, and all the validation-related tests since we don't have any form-validation hooks.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #25002 (GitHub issue number if applicable)

<!-- Either: -->
- [X] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2020-01-06 22:14:25 -05:00 committed by GitHub
commit 709e06928a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 67 additions and 54 deletions

View file

@ -1058,7 +1058,7 @@ impl HTMLFormElement {
NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLOutputElement,
)) => {
// Unimplemented
child.downcast::<HTMLOutputElement>().unwrap().reset();
},
_ => {},
}

View file

@ -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<HTMLFormElement>,
labels_node_list: MutNullableDom<NodeList>,
default_value_override: DomRefCell<Option<DOMString>>,
}
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::<Node>());
*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::<Node>().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::<Node>());
} 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::<Node>().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::<Node>());
}
// https://html.spec.whatwg.org/multipage/#dom-output-type
fn Type(&self) -> DOMString {
return DOMString::from("output");
}
}
impl VirtualMethods for HTMLOutputElement {

View file

@ -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::<Node>()), parent);
};
}
// https://dom.spec.whatwg.org/#concept-node-pre-remove
fn pre_remove(child: &Node, parent: &Node) -> Fallible<DomRoot<Node>> {
// Step 1.
@ -2213,6 +2223,11 @@ impl Node {
Node::collect_text_contents(self.children())
}
/// <https://html.spec.whatwg.org/multipage/#descendant-text-content>
pub fn descendant_text_content(&self) -> DOMString {
Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
}
pub fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(iterator: T) -> DOMString {
let mut content = String::new();
for node in iterator {

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -1,11 +0,0 @@
[reset-form.html]
type: testharness
[Resetting <output> by calling the reset() method]
expected: FAIL
[Resetting <output> by clicking the button in reset status]
expected: FAIL
[Resetting <output> by clicking the input in reset status]
expected: FAIL

View file

@ -2,6 +2,3 @@
[Descendant mutations and output.value and .defaultValue]
expected: FAIL
[output and output.form.reset()]
expected: FAIL

View file

@ -1,5 +0,0 @@
[output.html]
type: testharness
[output value and defaultValue]
expected: FAIL