mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Auto merge of #9514 - g-k:html-input-value, r=KiChjang
HTML input value Ready for review. Fixes #9455. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9514) <!-- Reviewable:end -->
This commit is contained in:
commit
0d7a2eee2d
5 changed files with 114 additions and 152 deletions
|
@ -11,6 +11,7 @@ use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
|||
use dom::bindings::codegen::Bindings::HTMLInputElementBinding;
|
||||
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
||||
use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
|
||||
use dom::bindings::error::{Error, ErrorResult};
|
||||
use dom::bindings::global::GlobalRef;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::{JS, LayoutJS, Root, RootedReference};
|
||||
|
@ -59,6 +60,14 @@ enum InputType {
|
|||
InputPassword
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum ValueMode {
|
||||
Value,
|
||||
Default,
|
||||
DefaultOn,
|
||||
Filename,
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct HTMLInputElement {
|
||||
htmlelement: HTMLElement,
|
||||
|
@ -71,6 +80,10 @@ pub struct HTMLInputElement {
|
|||
#[ignore_heap_size_of = "#7193"]
|
||||
textinput: DOMRefCell<TextInput<ConstellationChan<ConstellationMsg>>>,
|
||||
activation_state: DOMRefCell<InputActivationState>,
|
||||
// https://html.spec.whatwg.org/multipage/#concept-input-value-dirty-flag
|
||||
value_dirty: Cell<bool>,
|
||||
|
||||
// TODO: selected files for file input
|
||||
}
|
||||
|
||||
#[derive(JSTraceable)]
|
||||
|
@ -117,7 +130,8 @@ impl HTMLInputElement {
|
|||
maxlength: Cell::new(DEFAULT_MAX_LENGTH),
|
||||
size: Cell::new(DEFAULT_INPUT_SIZE),
|
||||
textinput: DOMRefCell::new(TextInput::new(Single, DOMString::new(), chan, None)),
|
||||
activation_state: DOMRefCell::new(InputActivationState::new())
|
||||
activation_state: DOMRefCell::new(InputActivationState::new()),
|
||||
value_dirty: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,6 +148,22 @@ impl HTMLInputElement {
|
|||
.get_attribute(&ns!(), &atom!("type"))
|
||||
.map_or_else(|| atom!(""), |a| a.value().as_atom().to_owned())
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#input-type-attr-summary
|
||||
fn get_value_mode(&self) -> ValueMode {
|
||||
match self.input_type.get() {
|
||||
InputType::InputSubmit |
|
||||
InputType::InputReset |
|
||||
InputType::InputButton |
|
||||
InputType::InputImage => ValueMode::Default,
|
||||
InputType::InputCheckbox |
|
||||
InputType::InputRadio => ValueMode::DefaultOn,
|
||||
InputType::InputPassword |
|
||||
InputType::InputText => ValueMode::Value,
|
||||
InputType::InputFile => ValueMode::Filename,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub trait LayoutHTMLInputElementHelpers {
|
||||
|
@ -292,14 +322,50 @@ impl HTMLInputElementMethods for HTMLInputElement {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-input-value
|
||||
fn Value(&self) -> DOMString {
|
||||
self.textinput.borrow().get_content()
|
||||
match self.get_value_mode() {
|
||||
ValueMode::Value => self.textinput.borrow().get_content(),
|
||||
ValueMode::Default => {
|
||||
self.upcast::<Element>()
|
||||
.get_attribute(&ns!(), &atom!("value"))
|
||||
.map_or(DOMString::from(""),
|
||||
|a| DOMString::from(a.summarize().value))
|
||||
}
|
||||
ValueMode::DefaultOn => {
|
||||
self.upcast::<Element>()
|
||||
.get_attribute(&ns!(), &atom!("value"))
|
||||
.map_or(DOMString::from("on"),
|
||||
|a| DOMString::from(a.summarize().value))
|
||||
}
|
||||
ValueMode::Filename => {
|
||||
// TODO: return C:\fakepath\<first of selected files> when a file is selected
|
||||
DOMString::from("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-input-value
|
||||
fn SetValue(&self, value: DOMString) {
|
||||
self.textinput.borrow_mut().set_content(value);
|
||||
fn SetValue(&self, value: DOMString) -> ErrorResult {
|
||||
match self.get_value_mode() {
|
||||
ValueMode::Value => {
|
||||
self.textinput.borrow_mut().set_content(value);
|
||||
self.value_dirty.set(true);
|
||||
}
|
||||
ValueMode::Default |
|
||||
ValueMode::DefaultOn => {
|
||||
self.upcast::<Element>().set_string_attribute(&atom!("value"), value);
|
||||
}
|
||||
ValueMode::Filename => {
|
||||
if value.is_empty() {
|
||||
// TODO: empty list of selected files
|
||||
} else {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.value_changed.set(true);
|
||||
self.force_relayout();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-input-defaultvalue
|
||||
|
@ -465,17 +531,11 @@ impl HTMLInputElement {
|
|||
|
||||
}
|
||||
|
||||
let mut value = self.Value();
|
||||
// Step 3.6
|
||||
if ty == atom!("radio") || ty == atom!("checkbox") {
|
||||
if value.is_empty() {
|
||||
value = DOMString::from("on");
|
||||
}
|
||||
}
|
||||
Some(FormDatum {
|
||||
ty: DOMString::from(&*ty), // FIXME(ajeffrey): Convert directly from Atoms to DOMStrings
|
||||
name: name,
|
||||
value: value
|
||||
value: self.Value()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -525,7 +585,9 @@ impl HTMLInputElement {
|
|||
_ => ()
|
||||
}
|
||||
|
||||
self.SetValue(self.DefaultValue());
|
||||
self.SetValue(self.DefaultValue())
|
||||
.expect("Failed to reset input value to default.");
|
||||
self.value_dirty.set(false);
|
||||
self.value_changed.set(false);
|
||||
self.force_relayout();
|
||||
}
|
||||
|
@ -574,7 +636,7 @@ impl VirtualMethods for HTMLInputElement {
|
|||
&atom!("type") => {
|
||||
match mutation {
|
||||
AttributeMutation::Set(_) => {
|
||||
let value = match attr.value().as_atom() {
|
||||
let new_type = match attr.value().as_atom() {
|
||||
&atom!("button") => InputType::InputButton,
|
||||
&atom!("submit") => InputType::InputSubmit,
|
||||
&atom!("reset") => InputType::InputReset,
|
||||
|
@ -584,11 +646,46 @@ impl VirtualMethods for HTMLInputElement {
|
|||
&atom!("password") => InputType::InputPassword,
|
||||
_ => InputType::InputText,
|
||||
};
|
||||
self.input_type.set(value);
|
||||
if value == InputType::InputRadio {
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#input-type-change
|
||||
let (old_value_mode, old_idl_value) = (self.get_value_mode(), self.Value());
|
||||
self.input_type.set(new_type);
|
||||
let new_value_mode = self.get_value_mode();
|
||||
|
||||
match (&old_value_mode, old_idl_value.is_empty(), new_value_mode) {
|
||||
|
||||
// Step 1
|
||||
(&ValueMode::Value, false, ValueMode::Default) |
|
||||
(&ValueMode::Value, false, ValueMode::DefaultOn) => {
|
||||
self.SetValue(old_idl_value)
|
||||
.expect("Failed to set input value on type change to a default ValueMode.");
|
||||
}
|
||||
|
||||
// Step 2
|
||||
(_, _, ValueMode::Value) if old_value_mode != ValueMode::Value => {
|
||||
self.SetValue(self.upcast::<Element>()
|
||||
.get_attribute(&ns!(), &atom!("value"))
|
||||
.map_or(DOMString::from(""),
|
||||
|a| DOMString::from(a.summarize().value)))
|
||||
.expect("Failed to set input value on type change to ValueMode::Value.");
|
||||
self.value_dirty.set(false);
|
||||
}
|
||||
|
||||
// Step 3
|
||||
(_, _, ValueMode::Filename) if old_value_mode != ValueMode::Filename => {
|
||||
self.SetValue(DOMString::from(""))
|
||||
.expect("Failed to set input value on type change to ValueMode::Filename.");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Step 5
|
||||
if new_type == InputType::InputRadio {
|
||||
self.radio_group_updated(
|
||||
self.get_radio_group_name().as_ref());
|
||||
}
|
||||
|
||||
// TODO: Step 6 - value sanitization
|
||||
},
|
||||
AttributeMutation::Removed => {
|
||||
if self.input_type.get() == InputType::InputRadio {
|
||||
|
|
|
@ -41,7 +41,8 @@ interface HTMLInputElement : HTMLElement {
|
|||
// attribute DOMString step;
|
||||
attribute DOMString type;
|
||||
attribute DOMString defaultValue;
|
||||
[TreatNullAs=EmptyString] attribute DOMString value;
|
||||
[TreatNullAs=EmptyString, SetterThrows]
|
||||
attribute DOMString value;
|
||||
// attribute Date? valueAsDate;
|
||||
// attribute unrestricted double valueAsNumber;
|
||||
// attribute double valueLow;
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[radionodelist.html]
|
||||
type: testharness
|
||||
[Check the RadioNodeList.value on setting to 'on']
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[input-type-checkbox.html]
|
||||
type: testharness
|
||||
[default/on: on getting, if the element has a value attribute, it must return that attribute's value; otherwise, it must return the string 'on']
|
||||
expected: FAIL
|
||||
|
|
@ -672,69 +672,6 @@
|
|||
[change state from radio to color]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to hidden]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to text]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to search]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to tel]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to url]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to email]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to password]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to datetime]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to date]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to month]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to week]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to time]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to number]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to range]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to color]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to checkbox]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to radio]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to submit]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to image]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to reset]
|
||||
expected: FAIL
|
||||
|
||||
[change state from file to button]
|
||||
expected: FAIL
|
||||
|
||||
[change state from submit to text]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -903,66 +840,3 @@
|
|||
[change state from button to color]
|
||||
expected: FAIL
|
||||
|
||||
[change state from hidden to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from text to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from search to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from tel to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from url to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from email to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from password to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from datetime to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from date to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from month to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from week to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from time to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from number to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from range to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from color to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from checkbox to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from radio to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from submit to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from image to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from reset to file]
|
||||
expected: FAIL
|
||||
|
||||
[change state from button to file]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue