mirror of
https://github.com/servo/servo.git
synced 2025-08-09 23:45:35 +01:00
Auto merge of #7323 - samfoo:input-maxlength, r=jdm
Adds support for input element's maxlength attr This implements maxlength [as described by whatwg](https://html.spec.whatwg.org/multipage/forms.html#dom-input-maxlength) for input elements. Remaining work: * WPT test - I have no idea how to write a WPT for simulating user input. Webdriver? Open to suggestions here. * Support for textarea (should be trivial, probably worth filing another issue) servo/servo#7320 servo/servo#7004 <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7323) <!-- Reviewable:end -->
This commit is contained in:
commit
fc3e950052
15 changed files with 407 additions and 202 deletions
|
@ -1090,6 +1090,30 @@ impl Element {
|
||||||
self.set_attribute(local_name, AttrValue::from_atomic_tokens(tokens));
|
self.set_attribute(local_name, AttrValue::from_atomic_tokens(tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_int_attribute(&self, local_name: &Atom, default: i32) -> i32 {
|
||||||
|
// TODO: Is this assert necessary?
|
||||||
|
assert!(local_name.chars().all(|ch| {
|
||||||
|
!ch.is_ascii() || ch.to_ascii_lowercase() == ch
|
||||||
|
}));
|
||||||
|
let attribute = self.get_attribute(&ns!(), local_name);
|
||||||
|
|
||||||
|
match attribute {
|
||||||
|
Some(ref attribute) => {
|
||||||
|
match *attribute.r().value() {
|
||||||
|
AttrValue::Int(_, value) => value,
|
||||||
|
_ => panic!("Expected an AttrValue::Int: \
|
||||||
|
implement parse_plain_attribute"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => default,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_int_attribute(&self, local_name: &Atom, value: i32) {
|
||||||
|
assert!(&**local_name == local_name.to_ascii_lowercase());
|
||||||
|
self.set_attribute(local_name, AttrValue::Int(DOMString::from(value.to_string()), value));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_uint_attribute(&self, local_name: &Atom, default: u32) -> u32 {
|
pub fn get_uint_attribute(&self, local_name: &Atom, default: u32) -> u32 {
|
||||||
assert!(local_name.chars().all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch));
|
assert!(local_name.chars().all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch));
|
||||||
let attribute = self.get_attribute(&ns!(), local_name);
|
let attribute = self.get_attribute(&ns!(), local_name);
|
||||||
|
|
|
@ -64,6 +64,7 @@ pub struct HTMLInputElement {
|
||||||
placeholder: DOMRefCell<DOMString>,
|
placeholder: DOMRefCell<DOMString>,
|
||||||
value_changed: Cell<bool>,
|
value_changed: Cell<bool>,
|
||||||
size: Cell<u32>,
|
size: Cell<u32>,
|
||||||
|
maxlength: Cell<i32>,
|
||||||
#[ignore_heap_size_of = "#7193"]
|
#[ignore_heap_size_of = "#7193"]
|
||||||
textinput: DOMRefCell<TextInput<ConstellationChan<ConstellationMsg>>>,
|
textinput: DOMRefCell<TextInput<ConstellationChan<ConstellationMsg>>>,
|
||||||
activation_state: DOMRefCell<InputActivationState>,
|
activation_state: DOMRefCell<InputActivationState>,
|
||||||
|
@ -103,6 +104,7 @@ impl InputActivationState {
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFAULT_INPUT_SIZE: u32 = 20;
|
static DEFAULT_INPUT_SIZE: u32 = 20;
|
||||||
|
static DEFAULT_MAX_LENGTH: i32 = -1;
|
||||||
|
|
||||||
impl HTMLInputElement {
|
impl HTMLInputElement {
|
||||||
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLInputElement {
|
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLInputElement {
|
||||||
|
@ -115,8 +117,9 @@ impl HTMLInputElement {
|
||||||
placeholder: DOMRefCell::new(DOMString::new()),
|
placeholder: DOMRefCell::new(DOMString::new()),
|
||||||
checked_changed: Cell::new(false),
|
checked_changed: Cell::new(false),
|
||||||
value_changed: Cell::new(false),
|
value_changed: Cell::new(false),
|
||||||
|
maxlength: Cell::new(DEFAULT_MAX_LENGTH),
|
||||||
size: Cell::new(DEFAULT_INPUT_SIZE),
|
size: Cell::new(DEFAULT_INPUT_SIZE),
|
||||||
textinput: DOMRefCell::new(TextInput::new(Single, DOMString::new(), chan)),
|
textinput: DOMRefCell::new(TextInput::new(Single, DOMString::new(), chan, None)),
|
||||||
activation_state: DOMRefCell::new(InputActivationState::new())
|
activation_state: DOMRefCell::new(InputActivationState::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,6 +340,12 @@ impl HTMLInputElementMethods for HTMLInputElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-input-formtarget
|
// https://html.spec.whatwg.org/multipage/#dom-input-formtarget
|
||||||
make_setter!(SetFormTarget, "formtarget");
|
make_setter!(SetFormTarget, "formtarget");
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-maxlength
|
||||||
|
make_int_getter!(MaxLength, "maxlength", DEFAULT_MAX_LENGTH);
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-maxlength
|
||||||
|
make_limited_int_setter!(SetMaxLength, "maxlength", DEFAULT_MAX_LENGTH);
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-input-indeterminate
|
// https://html.spec.whatwg.org/multipage/#dom-input-indeterminate
|
||||||
fn Indeterminate(&self) -> bool {
|
fn Indeterminate(&self) -> bool {
|
||||||
self.upcast::<Element>().get_state().contains(IN_INDETERMINATE_STATE)
|
self.upcast::<Element>().get_state().contains(IN_INDETERMINATE_STATE)
|
||||||
|
@ -511,6 +520,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
|
|
||||||
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
|
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
|
||||||
self.super_type().unwrap().attribute_mutated(attr, mutation);
|
self.super_type().unwrap().attribute_mutated(attr, mutation);
|
||||||
|
|
||||||
match attr.local_name() {
|
match attr.local_name() {
|
||||||
&atom!("disabled") => {
|
&atom!("disabled") => {
|
||||||
let disabled_state = match mutation {
|
let disabled_state = match mutation {
|
||||||
|
@ -581,6 +591,18 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
self.radio_group_updated(
|
self.radio_group_updated(
|
||||||
mutation.new_value(attr).as_ref().map(|name| name.as_atom()));
|
mutation.new_value(attr).as_ref().map(|name| name.as_atom()));
|
||||||
},
|
},
|
||||||
|
&atom!("maxlength") => {
|
||||||
|
match *attr.value() {
|
||||||
|
AttrValue::Int(_, value) => {
|
||||||
|
if value < 0 {
|
||||||
|
self.textinput.borrow_mut().max_length = None
|
||||||
|
} else {
|
||||||
|
self.textinput.borrow_mut().max_length = Some(value as usize)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => panic!("Expected an AttrValue::Int"),
|
||||||
|
}
|
||||||
|
}
|
||||||
&atom!("placeholder") => {
|
&atom!("placeholder") => {
|
||||||
// FIXME(ajeffrey): Should we do in-place mutation of the placeholder?
|
// FIXME(ajeffrey): Should we do in-place mutation of the placeholder?
|
||||||
let mut placeholder = self.placeholder.borrow_mut();
|
let mut placeholder = self.placeholder.borrow_mut();
|
||||||
|
@ -599,6 +621,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
&atom!("name") => AttrValue::from_atomic(value),
|
&atom!("name") => AttrValue::from_atomic(value),
|
||||||
&atom!("size") => AttrValue::from_limited_u32(value, DEFAULT_INPUT_SIZE),
|
&atom!("size") => AttrValue::from_limited_u32(value, DEFAULT_INPUT_SIZE),
|
||||||
&atom!("type") => AttrValue::from_atomic(value),
|
&atom!("type") => AttrValue::from_atomic(value),
|
||||||
|
&atom!("maxlength") => AttrValue::from_limited_i32(value, DEFAULT_MAX_LENGTH),
|
||||||
_ => self.super_type().unwrap().parse_plain_attribute(name, value),
|
_ => self.super_type().unwrap().parse_plain_attribute(name, value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ impl HTMLTextAreaElement {
|
||||||
htmlelement:
|
htmlelement:
|
||||||
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE,
|
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE,
|
||||||
localName, prefix, document),
|
localName, prefix, document),
|
||||||
textinput: DOMRefCell::new(TextInput::new(Lines::Multiple, DOMString::new(), chan)),
|
textinput: DOMRefCell::new(TextInput::new(Lines::Multiple, DOMString::new(), chan, None)),
|
||||||
cols: Cell::new(DEFAULT_COLS),
|
cols: Cell::new(DEFAULT_COLS),
|
||||||
rows: Cell::new(DEFAULT_ROWS),
|
rows: Cell::new(DEFAULT_ROWS),
|
||||||
value_changed: Cell::new(false),
|
value_changed: Cell::new(false),
|
||||||
|
|
|
@ -26,6 +26,42 @@ macro_rules! make_bool_getter(
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! make_limited_int_setter(
|
||||||
|
($attr:ident, $htmlname:tt, $default:expr) => (
|
||||||
|
fn $attr(&self, value: i32) -> $crate::dom::bindings::error::ErrorResult {
|
||||||
|
use dom::bindings::inheritance::Castable;
|
||||||
|
use dom::element::Element;
|
||||||
|
|
||||||
|
let value = if value < 0 {
|
||||||
|
return Err($crate::dom::bindings::error::Error::IndexSize);
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
};
|
||||||
|
|
||||||
|
let element = self.upcast::<Element>();
|
||||||
|
element.set_int_attribute(&atom!($htmlname), value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
);
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! make_int_getter(
|
||||||
|
($attr:ident, $htmlname:tt, $default:expr) => (
|
||||||
|
fn $attr(&self) -> i32 {
|
||||||
|
use dom::bindings::inheritance::Castable;
|
||||||
|
use dom::element::Element;
|
||||||
|
let element = self.upcast::<Element>();
|
||||||
|
element.get_int_attribute(&atom!($htmlname), $default)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
($attr:ident, $htmlname:tt) => {
|
||||||
|
make_int_getter!($attr, $htmlname, 0);
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! make_uint_getter(
|
macro_rules! make_uint_getter(
|
||||||
($attr:ident, $htmlname:tt, $default:expr) => (
|
($attr:ident, $htmlname:tt, $default:expr) => (
|
||||||
|
|
|
@ -25,7 +25,8 @@ interface HTMLInputElement : HTMLElement {
|
||||||
// attribute DOMString inputMode;
|
// attribute DOMString inputMode;
|
||||||
//readonly attribute HTMLElement? list;
|
//readonly attribute HTMLElement? list;
|
||||||
// attribute DOMString max;
|
// attribute DOMString max;
|
||||||
// attribute long maxLength;
|
[SetterThrows]
|
||||||
|
attribute long maxLength;
|
||||||
// attribute DOMString min;
|
// attribute DOMString min;
|
||||||
// attribute long minLength;
|
// attribute long minLength;
|
||||||
// attribute boolean multiple;
|
// attribute boolean multiple;
|
||||||
|
|
|
@ -11,6 +11,7 @@ use msg::constellation_msg::{Key, KeyModifiers};
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
use std::usize;
|
||||||
use util::mem::HeapSizeOf;
|
use util::mem::HeapSizeOf;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ pub struct TextInput<T: ClipboardProvider> {
|
||||||
multiline: bool,
|
multiline: bool,
|
||||||
#[ignore_heap_size_of = "Can't easily measure this generic type"]
|
#[ignore_heap_size_of = "Can't easily measure this generic type"]
|
||||||
clipboard_provider: T,
|
clipboard_provider: T,
|
||||||
|
pub max_length: Option<usize>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resulting action to be taken by the owner of a text input that is handling an event.
|
/// Resulting action to be taken by the owner of a text input that is handling an event.
|
||||||
|
@ -107,13 +109,14 @@ fn is_printable_key(key: Key) -> bool {
|
||||||
|
|
||||||
impl<T: ClipboardProvider> TextInput<T> {
|
impl<T: ClipboardProvider> TextInput<T> {
|
||||||
/// Instantiate a new text input control
|
/// Instantiate a new text input control
|
||||||
pub fn new(lines: Lines, initial: DOMString, clipboard_provider: T) -> TextInput<T> {
|
pub fn new(lines: Lines, initial: DOMString, clipboard_provider: T, max_length: Option<usize>) -> TextInput<T> {
|
||||||
let mut i = TextInput {
|
let mut i = TextInput {
|
||||||
lines: vec!(),
|
lines: vec!(),
|
||||||
edit_point: Default::default(),
|
edit_point: Default::default(),
|
||||||
selection_begin: None,
|
selection_begin: None,
|
||||||
multiline: lines == Lines::Multiple,
|
multiline: lines == Lines::Multiple,
|
||||||
clipboard_provider: clipboard_provider
|
clipboard_provider: clipboard_provider,
|
||||||
|
max_length: max_length
|
||||||
};
|
};
|
||||||
i.set_content(initial);
|
i.set_content(initial);
|
||||||
i
|
i
|
||||||
|
@ -133,7 +136,7 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a string at the current editing point
|
/// Insert a string at the current editing point
|
||||||
fn insert_string<S: Into<String>>(&mut self, s: S) {
|
pub fn insert_string<S: Into<String>>(&mut self, s: S) {
|
||||||
if self.selection_begin.is_none() {
|
if self.selection_begin.is_none() {
|
||||||
self.selection_begin = Some(self.edit_point);
|
self.selection_begin = Some(self.edit_point);
|
||||||
}
|
}
|
||||||
|
@ -170,8 +173,40 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn selection_len(&self) -> usize {
|
||||||
|
if let Some((begin, end)) = self.get_sorted_selection() {
|
||||||
|
let prefix = &self.lines[begin.line][0..begin.index];
|
||||||
|
let suffix = &self.lines[end.line][end.index..];
|
||||||
|
let lines_prefix = &self.lines[..begin.line];
|
||||||
|
let lines_suffix = &self.lines[end.line + 1..];
|
||||||
|
|
||||||
|
self.len() - (prefix.chars().count() +
|
||||||
|
suffix.chars().count() +
|
||||||
|
lines_prefix.iter().fold(0, |m, i| m + i.chars().count() + 1) +
|
||||||
|
lines_suffix.iter().fold(0, |m, i| m + i.chars().count() + 1))
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn replace_selection(&mut self, insert: DOMString) {
|
pub fn replace_selection(&mut self, insert: DOMString) {
|
||||||
if let Some((begin, end)) = self.get_sorted_selection() {
|
if let Some((begin, end)) = self.get_sorted_selection() {
|
||||||
|
let allowed_to_insert_count = if let Some(max_length) = self.max_length {
|
||||||
|
let len_after_selection_replaced = self.len() - self.selection_len();
|
||||||
|
if len_after_selection_replaced > max_length {
|
||||||
|
// If, after deleting the selection, the len is still greater than the max
|
||||||
|
// length, then don't delete/insert anything
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
max_length - len_after_selection_replaced
|
||||||
|
} else {
|
||||||
|
usize::MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_char_to_insert = min(allowed_to_insert_count, insert.chars().count());
|
||||||
|
let chars_to_insert = (&insert[0 .. last_char_to_insert]).to_owned();
|
||||||
|
|
||||||
self.clear_selection();
|
self.clear_selection();
|
||||||
|
|
||||||
let new_lines = {
|
let new_lines = {
|
||||||
|
@ -181,13 +216,14 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
let lines_suffix = &self.lines[end.line + 1..];
|
let lines_suffix = &self.lines[end.line + 1..];
|
||||||
|
|
||||||
let mut insert_lines = if self.multiline {
|
let mut insert_lines = if self.multiline {
|
||||||
insert.split('\n').map(DOMString::from).collect()
|
chars_to_insert.split('\n').map(|s| DOMString::from(s.to_owned())).collect()
|
||||||
} else {
|
} else {
|
||||||
vec!(insert)
|
vec!(DOMString::from(chars_to_insert))
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME(ajeffrey): effecient append for DOMStrings
|
// FIXME(ajeffrey): effecient append for DOMStrings
|
||||||
let mut new_line = prefix.to_owned();
|
let mut new_line = prefix.to_owned();
|
||||||
|
|
||||||
new_line.push_str(&insert_lines[0]);
|
new_line.push_str(&insert_lines[0]);
|
||||||
insert_lines[0] = DOMString::from(new_line);
|
insert_lines[0] = DOMString::from(new_line);
|
||||||
|
|
||||||
|
@ -434,6 +470,12 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.lines.iter().fold(0, |m, l| {
|
||||||
|
m + l.len() + 1
|
||||||
|
}) - 1
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the current contents of the text input. Multiple lines are joined by \n.
|
/// Get the current contents of the text input. Multiple lines are joined by \n.
|
||||||
pub fn get_content(&self) -> DOMString {
|
pub fn get_content(&self) -> DOMString {
|
||||||
let mut content = "".to_owned();
|
let mut content = "".to_owned();
|
||||||
|
|
|
@ -6,7 +6,7 @@ use cssparser::RGBA;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use string_cache::{Atom, Namespace};
|
use string_cache::{Atom, Namespace};
|
||||||
use util::str::{DOMString, LengthOrPercentageOrAuto, parse_unsigned_integer, parse_legacy_color, parse_length};
|
use util::str::{DOMString, LengthOrPercentageOrAuto, parse_unsigned_integer, parse_legacy_color, parse_length};
|
||||||
use util::str::{split_html_space_chars, str_join};
|
use util::str::{split_html_space_chars, str_join, parse_integer};
|
||||||
use values::specified::{Length};
|
use values::specified::{Length};
|
||||||
|
|
||||||
// Duplicated from script::dom::values.
|
// Duplicated from script::dom::values.
|
||||||
|
@ -17,6 +17,7 @@ pub enum AttrValue {
|
||||||
String(DOMString),
|
String(DOMString),
|
||||||
TokenList(DOMString, Vec<Atom>),
|
TokenList(DOMString, Vec<Atom>),
|
||||||
UInt(DOMString, u32),
|
UInt(DOMString, u32),
|
||||||
|
Int(DOMString, i32),
|
||||||
Atom(Atom),
|
Atom(Atom),
|
||||||
Length(DOMString, Option<Length>),
|
Length(DOMString, Option<Length>),
|
||||||
Color(DOMString, Option<RGBA>),
|
Color(DOMString, Option<RGBA>),
|
||||||
|
@ -52,6 +53,22 @@ impl AttrValue {
|
||||||
AttrValue::UInt(string, result)
|
AttrValue::UInt(string, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_i32(string: DOMString, default: i32) -> AttrValue {
|
||||||
|
let result = parse_integer(string.chars()).unwrap_or(default);
|
||||||
|
AttrValue::Int(string, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#limited-to-only-non-negative-numbers
|
||||||
|
pub fn from_limited_i32(string: DOMString, default: i32) -> AttrValue {
|
||||||
|
let result = parse_integer(string.chars()).unwrap_or(default);
|
||||||
|
|
||||||
|
if result < 0 {
|
||||||
|
AttrValue::Int(string, default)
|
||||||
|
} else {
|
||||||
|
AttrValue::Int(string, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#limited-to-only-non-negative-numbers-greater-than-zero
|
// https://html.spec.whatwg.org/multipage/#limited-to-only-non-negative-numbers-greater-than-zero
|
||||||
pub fn from_limited_u32(string: DOMString, default: u32) -> AttrValue {
|
pub fn from_limited_u32(string: DOMString, default: u32) -> AttrValue {
|
||||||
let result = parse_unsigned_integer(string.chars()).unwrap_or(default);
|
let result = parse_unsigned_integer(string.chars()).unwrap_or(default);
|
||||||
|
@ -165,6 +182,7 @@ impl Deref for AttrValue {
|
||||||
AttrValue::UInt(ref value, _) |
|
AttrValue::UInt(ref value, _) |
|
||||||
AttrValue::Length(ref value, _) |
|
AttrValue::Length(ref value, _) |
|
||||||
AttrValue::Color(ref value, _) |
|
AttrValue::Color(ref value, _) |
|
||||||
|
AttrValue::Int(ref value, _) |
|
||||||
AttrValue::Dimension(ref value, _) => &value,
|
AttrValue::Dimension(ref value, _) => &value,
|
||||||
AttrValue::Atom(ref value) => &value,
|
AttrValue::Atom(ref value) => &value,
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,121 @@ use msg::constellation_msg::CONTROL;
|
||||||
use msg::constellation_msg::SUPER;
|
use msg::constellation_msg::SUPER;
|
||||||
use msg::constellation_msg::{Key, KeyModifiers};
|
use msg::constellation_msg::{Key, KeyModifiers};
|
||||||
use script::clipboard_provider::DummyClipboardContext;
|
use script::clipboard_provider::DummyClipboardContext;
|
||||||
use script::textinput::{TextInput, Selection, Lines, Direction};
|
use script::textinput::{TextInput, TextPoint, Selection, Lines, Direction};
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
fn text_input(lines: Lines, s: &str) -> TextInput<DummyClipboardContext> {
|
fn text_input(lines: Lines, s: &str) -> TextInput<DummyClipboardContext> {
|
||||||
TextInput::new(lines, DOMString::from(s), DummyClipboardContext::new(""))
|
TextInput::new(lines, DOMString::from(s), DummyClipboardContext::new(""), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set_content_ignores_max_length() {
|
||||||
|
let mut textinput = TextInput::new(
|
||||||
|
Lines::Single, DOMString::from(""), DummyClipboardContext::new(""), Some(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
textinput.set_content(DOMString::from("mozilla rocks"));
|
||||||
|
assert_eq!(textinput.get_content(), DOMString::from("mozilla rocks"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_textinput_when_inserting_multiple_lines_over_a_selection_respects_max_length() {
|
||||||
|
let mut textinput = TextInput::new(
|
||||||
|
Lines::Multiple,
|
||||||
|
DOMString::from("hello\nworld"),
|
||||||
|
DummyClipboardContext::new(""),
|
||||||
|
Some(17)
|
||||||
|
);
|
||||||
|
|
||||||
|
textinput.edit_point = TextPoint { line: 0, index: 1 };
|
||||||
|
textinput.adjust_horizontal(3, Selection::Selected);
|
||||||
|
textinput.adjust_vertical(1, Selection::Selected);
|
||||||
|
|
||||||
|
// Selection is now "hello\n
|
||||||
|
// ------
|
||||||
|
// world"
|
||||||
|
// ----
|
||||||
|
|
||||||
|
textinput.insert_string("cruel\nterrible\nbad".to_string());
|
||||||
|
|
||||||
|
assert_eq!(textinput.get_content(), "hcruel\nterrible\nd");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_textinput_when_inserting_multiple_lines_still_respects_max_length() {
|
||||||
|
let mut textinput = TextInput::new(
|
||||||
|
Lines::Multiple,
|
||||||
|
DOMString::from("hello\nworld"),
|
||||||
|
DummyClipboardContext::new(""),
|
||||||
|
Some(17)
|
||||||
|
);
|
||||||
|
|
||||||
|
textinput.edit_point = TextPoint { line: 1, index: 0 };
|
||||||
|
|
||||||
|
textinput.insert_string("cruel\nterrible".to_string());
|
||||||
|
|
||||||
|
assert_eq!(textinput.get_content(), "hello\ncruel\nworld");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_textinput_when_content_is_already_longer_than_max_length_and_theres_no_selection_dont_insert_anything() {
|
||||||
|
let mut textinput = TextInput::new(
|
||||||
|
Lines::Single,
|
||||||
|
DOMString::from("abc"),
|
||||||
|
DummyClipboardContext::new(""),
|
||||||
|
Some(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
textinput.insert_char('a');
|
||||||
|
|
||||||
|
assert_eq!(textinput.get_content(), "abc");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multi_line_textinput_with_maxlength_doesnt_allow_appending_characters_when_input_spans_lines() {
|
||||||
|
let mut textinput = TextInput::new(
|
||||||
|
Lines::Multiple,
|
||||||
|
DOMString::from("abc\nd"),
|
||||||
|
DummyClipboardContext::new(""),
|
||||||
|
Some(5)
|
||||||
|
);
|
||||||
|
|
||||||
|
textinput.insert_char('a');
|
||||||
|
|
||||||
|
assert_eq!(textinput.get_content(), "abc\nd");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_single_line_textinput_with_max_length_doesnt_allow_appending_characters_when_replacing_a_selection() {
|
||||||
|
let mut textinput = TextInput::new(
|
||||||
|
Lines::Single,
|
||||||
|
DOMString::from("abcde"),
|
||||||
|
DummyClipboardContext::new(""),
|
||||||
|
Some(5)
|
||||||
|
);
|
||||||
|
|
||||||
|
textinput.edit_point = TextPoint { line: 0, index: 1 };
|
||||||
|
textinput.adjust_horizontal(3, Selection::Selected);
|
||||||
|
|
||||||
|
// Selection is now "abcde"
|
||||||
|
// ---
|
||||||
|
|
||||||
|
textinput.replace_selection(DOMString::from("too long"));
|
||||||
|
|
||||||
|
assert_eq!(textinput.get_content(), "atooe");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_single_line_textinput_with_max_length_doesnt_allow_appending_characters_after_max_length_is_reached() {
|
||||||
|
let mut textinput = TextInput::new(
|
||||||
|
Lines::Single,
|
||||||
|
DOMString::from("a"),
|
||||||
|
DummyClipboardContext::new(""),
|
||||||
|
Some(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
textinput.insert_char('b');
|
||||||
|
assert_eq!(textinput.get_content(), "a");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -199,7 +309,8 @@ fn test_clipboard_paste() {
|
||||||
|
|
||||||
let mut textinput = TextInput::new(Lines::Single,
|
let mut textinput = TextInput::new(Lines::Single,
|
||||||
DOMString::from("defg"),
|
DOMString::from("defg"),
|
||||||
DummyClipboardContext::new("abc"));
|
DummyClipboardContext::new("abc"),
|
||||||
|
None);
|
||||||
assert_eq!(textinput.get_content(), "defg");
|
assert_eq!(textinput.get_content(), "defg");
|
||||||
assert_eq!(textinput.edit_point.index, 0);
|
assert_eq!(textinput.edit_point.index, 0);
|
||||||
textinput.handle_keydown_aux(Key::V, MODIFIERS);
|
textinput.handle_keydown_aux(Key::V, MODIFIERS);
|
||||||
|
|
33
tests/unit/style/attr.rs
Normal file
33
tests/unit/style/attr.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use style::attr::AttrValue;
|
||||||
|
use util::str::DOMString;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_limited_i32_should_be_default_when_less_than_0() {
|
||||||
|
let value = DOMString::from("-1");
|
||||||
|
match AttrValue::from_limited_i32(value, 0) {
|
||||||
|
AttrValue::Int(_, 0) => (),
|
||||||
|
_ => panic!("expected an IndexSize error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_limited_i32_should_parse_a_uint_when_value_is_0_or_greater() {
|
||||||
|
match AttrValue::from_limited_i32(DOMString::from("1"), 0) {
|
||||||
|
AttrValue::Int(_, 1) => (),
|
||||||
|
_ => panic!("expected an successful parsing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_limited_i32_should_keep_parsed_value_when_not_an_int() {
|
||||||
|
match AttrValue::from_limited_i32(DOMString::from("parsed-value"), 0) {
|
||||||
|
AttrValue::Int(p, 0) => {
|
||||||
|
assert_eq!(p, DOMString::from("parsed-value"))
|
||||||
|
},
|
||||||
|
_ => panic!("expected an successful parsing")
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ extern crate util;
|
||||||
#[cfg(test)] mod stylesheets;
|
#[cfg(test)] mod stylesheets;
|
||||||
#[cfg(test)] mod media_queries;
|
#[cfg(test)] mod media_queries;
|
||||||
#[cfg(test)] mod viewport;
|
#[cfg(test)] mod viewport;
|
||||||
|
#[cfg(test)] mod attr;
|
||||||
|
|
||||||
#[cfg(test)] mod writing_modes {
|
#[cfg(test)] mod writing_modes {
|
||||||
use style::properties::{INITIAL_VALUES, get_writing_mode};
|
use style::properties::{INITIAL_VALUES, get_writing_mode};
|
||||||
|
|
|
@ -18011,6 +18011,10 @@
|
||||||
"path": "html/semantics/forms/the-input-element/input-type-checkbox.html",
|
"path": "html/semantics/forms/the-input-element/input-type-checkbox.html",
|
||||||
"url": "/html/semantics/forms/the-input-element/input-type-checkbox.html"
|
"url": "/html/semantics/forms/the-input-element/input-type-checkbox.html"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "html/semantics/forms/the-input-element/maxlength.html",
|
||||||
|
"url": "/html/semantics/forms/the-input-element/maxlength.html"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "html/semantics/forms/the-input-element/month.html",
|
"path": "html/semantics/forms/the-input-element/month.html",
|
||||||
"url": "/html/semantics/forms/the-input-element/month.html"
|
"url": "/html/semantics/forms/the-input-element/month.html"
|
||||||
|
@ -30129,7 +30133,16 @@
|
||||||
},
|
},
|
||||||
"local_changes": {
|
"local_changes": {
|
||||||
"deleted": [],
|
"deleted": [],
|
||||||
"items": {},
|
"items": {
|
||||||
|
"manual": {
|
||||||
|
"html/semantics/forms/the-input-element/maxlength-manual.html": [
|
||||||
|
{
|
||||||
|
"path": "html/semantics/forms/the-input-element/maxlength-manual.html",
|
||||||
|
"url": "/html/semantics/forms/the-input-element/maxlength-manual.html"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"reftest_nodes": {}
|
"reftest_nodes": {}
|
||||||
},
|
},
|
||||||
"reftest_nodes": {
|
"reftest_nodes": {
|
||||||
|
|
|
@ -4860,9 +4860,6 @@
|
||||||
[HTMLInputElement interface: attribute max]
|
[HTMLInputElement interface: attribute max]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLInputElement interface: attribute maxLength]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLInputElement interface: attribute min]
|
[HTMLInputElement interface: attribute min]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -4983,9 +4980,6 @@
|
||||||
[HTMLInputElement interface: document.createElement("input") must inherit property "max" with the proper type (19)]
|
[HTMLInputElement interface: document.createElement("input") must inherit property "max" with the proper type (19)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLInputElement interface: document.createElement("input") must inherit property "maxLength" with the proper type (20)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLInputElement interface: document.createElement("input") must inherit property "min" with the proper type (21)]
|
[HTMLInputElement interface: document.createElement("input") must inherit property "min" with the proper type (21)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -4977,189 +4977,6 @@
|
||||||
[input.max: IDL set to object "test-valueOf" followed by IDL get]
|
[input.max: IDL set to object "test-valueOf" followed by IDL get]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input.maxLength: typeof IDL attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: IDL get with DOM attribute unset]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to -2147483649 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to -2147483648 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to -36 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to -1 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to -0 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to 0 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to 1 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to 2147483647 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to 2147483648 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to 4294967295 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to 4294967296 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "-1" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "-0" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "0" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "1" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo " followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "\\t7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "\\v7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "\\f7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "\\n7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "\\r7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "
7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "
7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to " 7" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to undefined followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to 1.5 followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to true followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to false followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to object "[object Object\]" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to NaN followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to Infinity followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to -Infinity followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to "\\0" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to object "2" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: setAttribute() to object "3" followed by IDL get]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: IDL set to -2147483648 must throw INDEX_SIZE_ERR]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: IDL set to -36 must throw INDEX_SIZE_ERR]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: IDL set to -1 must throw INDEX_SIZE_ERR]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: IDL set to 0 followed by getAttribute()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: IDL set to 1 followed by getAttribute()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.maxLength: IDL set to 2147483647 followed by getAttribute()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input.min: typeof IDL attribute]
|
[input.min: typeof IDL attribute]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>input max length</title>
|
||||||
|
<link rel="author" title="Sam Gibson" href="mailto:sam@ifdown.net">
|
||||||
|
<link rel=help href="https://html.spec.whatwg.org/multipage/forms.html#the-maxlength-and-minlength-attributes">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<p>Type a letter anywhere into the input field (do not select any text, or otherwise manipulate the input)</p>
|
||||||
|
<input type=text maxlength=4 id=only-four value="inpu"></input>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var input;
|
||||||
|
setup(function() {
|
||||||
|
input = document.getElementById('only-four');
|
||||||
|
}, {explicit_done: true, explicit_timeout: true});
|
||||||
|
|
||||||
|
|
||||||
|
on_event(input, 'keyup', function(event) {
|
||||||
|
if ((event.keyCode >= 65 && event.keyCode <= 90) ||
|
||||||
|
(event.keyCode >= 97 && event.keyCode <= 122)) {
|
||||||
|
test(function() {
|
||||||
|
assert_equals(input.value, "inpu");
|
||||||
|
}, 'input content should limit to maxlength')
|
||||||
|
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>input max length</title>
|
||||||
|
<link rel="author" title="Sam Gibson" href="mailto:sam@ifdown.net">
|
||||||
|
<link rel=help href="https://html.spec.whatwg.org/multipage/forms.html#the-maxlength-and-minlength-attributes">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Text input element</h1>
|
||||||
|
|
||||||
|
<div style="display: none">
|
||||||
|
<input id="none" />
|
||||||
|
<input id="negative" type="-5" />
|
||||||
|
<input id="non-numeric" type="not-a-number" />
|
||||||
|
<input id="assign-negative" />
|
||||||
|
<input id="assign-non-numeric" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="log"></div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
test(
|
||||||
|
function() {
|
||||||
|
assert_equals(document.getElementById("none").maxLength, -1);
|
||||||
|
}, "Unset maxlength is -1");
|
||||||
|
|
||||||
|
test(
|
||||||
|
function() {
|
||||||
|
assert_equals(document.getElementById("negative").maxLength, -1);
|
||||||
|
}, "Negative maxlength is always -1");
|
||||||
|
|
||||||
|
test(
|
||||||
|
function() {
|
||||||
|
assert_equals(document.getElementById("non-numeric").maxLength, -1);
|
||||||
|
}, "Non-numeric maxlength is -1");
|
||||||
|
|
||||||
|
test(
|
||||||
|
function() {
|
||||||
|
assert_throws("INDEX_SIZE_ERR", function() {
|
||||||
|
document.getElementById("assign-negative").maxLength = -5;
|
||||||
|
});
|
||||||
|
}, "Assigning negative integer throws IndexSizeError");
|
||||||
|
|
||||||
|
test(
|
||||||
|
function() {
|
||||||
|
document.getElementById("assign-non-numeric").maxLength = "not-a-number";
|
||||||
|
assert_equals(document.getElementById("assign-non-numeric").maxLength, 0);
|
||||||
|
}, "Assigning non-numeric to maxlength sets maxlength to 0");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue