Auto merge of #25499 - NeverHappened:implement-form-dirname, r=jdm

Implement dirname support for form element

Added support for dirname in input on form submit
Added Dir getter / setter for HTMLElement
NOT YET Added get directionality according to https://html.spec.whatwg.org/multipage/dom.html#the-directionality

- [X] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #25379 (GitHub issue number if applicable)
This commit is contained in:
bors-servo 2020-02-24 21:18:10 -05:00 committed by GitHub
commit 145c89a2d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 252 additions and 3303 deletions

View file

@ -540,6 +540,16 @@ impl Element {
}
true // whatwg/html#5239
}
// https://html.spec.whatwg.org/multipage/#the-directionality
pub fn directionality(&self) -> String {
self.downcast::<HTMLElement>()
.and_then(|html_element| html_element.directionality())
.unwrap_or_else(|| {
let node = self.upcast::<Node>();
node.parent_directionality()
})
}
}
#[allow(unsafe_code)]

View file

@ -27,6 +27,7 @@ use crate::dom::htmlframesetelement::HTMLFrameSetElement;
use crate::dom::htmlhtmlelement::HTMLHtmlElement;
use crate::dom::htmlinputelement::{HTMLInputElement, InputType};
use crate::dom::htmllabelelement::HTMLLabelElement;
use crate::dom::htmltextareaelement::HTMLTextAreaElement;
use crate::dom::node::{document_from_node, window_from_node};
use crate::dom::node::{BindContext, Node, NodeFlags, ShadowIncluding};
use crate::dom::text::Text;
@ -170,6 +171,11 @@ impl HTMLElementMethods for HTMLElement {
// https://html.spec.whatwg.org/multipage/#dom-hidden
make_bool_setter!(SetHidden, "hidden");
// https://html.spec.whatwg.org/multipage/#the-dir-attribute
make_getter!(Dir, "dir");
// https://html.spec.whatwg.org/multipage/#the-dir-attribute
make_setter!(SetDir, "dir");
// https://html.spec.whatwg.org/multipage/#globaleventhandlers
global_event_handlers!(NoOnload);
@ -767,6 +773,48 @@ impl HTMLElement {
})
.count() as u32
}
// https://html.spec.whatwg.org/multipage/#the-directionality.
// returns Some if can infer direction by itself or from child nodes
// returns None if requires to go up to parent
pub fn directionality(&self) -> Option<String> {
let element_direction: &str = &self.Dir();
if element_direction == "ltr" {
return Some("ltr".to_owned());
}
if element_direction == "rtl" {
return Some("rtl".to_owned());
}
if let Some(input) = self.downcast::<HTMLInputElement>() {
if input.input_type() == InputType::Tel {
return Some("ltr".to_owned());
}
}
if element_direction == "auto" {
if let Some(directionality) = self
.downcast::<HTMLInputElement>()
.and_then(|input| input.auto_directionality())
{
return Some(directionality);
}
if let Some(area) = self.downcast::<HTMLTextAreaElement>() {
return Some(area.auto_directionality());
}
}
// TODO(NeverHappened): Implement condition
// If the element's dir attribute is in the auto state OR
// If the element is a bdi element and the dir attribute is not in a defined state
// (i.e. it is not present or has an invalid value)
// Requires bdi element implementation (https://html.spec.whatwg.org/multipage/#the-bdi-element)
None
}
}
impl VirtualMethods for HTMLElement {

View file

@ -950,7 +950,6 @@ impl HTMLFormElement {
match element {
HTMLElementTypeId::HTMLInputElement => {
let input = child.downcast::<HTMLInputElement>().unwrap();
data_set.append(&mut input.form_datums(submitter, encoding));
},
HTMLElementTypeId::HTMLButtonElement => {
@ -981,10 +980,30 @@ impl HTMLFormElement {
_ => (),
}
}
// Step: 5.13. Add an entry if element has dirname attribute
// An element can only have a dirname attribute if it is a textarea element
// or an input element whose type attribute is in either the Text state or the Search state
let child_element = child.downcast::<Element>().unwrap();
let input_matches =
child_element
.downcast::<HTMLInputElement>()
.map_or(false, |input| {
input.input_type() == InputType::Text ||
input.input_type() == InputType::Search
});
let textarea_matches = child_element.is::<HTMLTextAreaElement>();
let dirname = child_element.get_string_attribute(&local_name!("dirname"));
if (input_matches || textarea_matches) && !dirname.is_empty() {
let dir = DOMString::from(child_element.directionality());
data_set.push(FormDatum {
ty: DOMString::from("string"),
name: dirname,
value: FormDatumValue::String(dir),
});
}
}
data_set
// TODO: Handle `dirnames` (needs directionality support)
// https://html.spec.whatwg.org/multipage/#the-directionality
}
/// <https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set>

View file

@ -75,6 +75,7 @@ use std::ptr::NonNull;
use style::attr::AttrValue;
use style::element_state::ElementState;
use style::str::{split_commas, str_join};
use unicode_bidi::{bidi_class, BidiClass};
const DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
const DEFAULT_RESET_VALUE: &'static str = "Reset";
@ -327,6 +328,36 @@ impl HTMLInputElement {
)
}
pub fn auto_directionality(&self) -> Option<String> {
match self.input_type() {
InputType::Text | InputType::Search | InputType::Url | InputType::Email => {
let value: String = self.Value().to_string();
Some(HTMLInputElement::directionality_from_value(&value))
},
_ => None,
}
}
pub fn directionality_from_value(value: &str) -> String {
if HTMLInputElement::is_first_strong_character_rtl(value) {
"rtl".to_owned()
} else {
"ltr".to_owned()
}
}
fn is_first_strong_character_rtl(value: &str) -> bool {
for ch in value.chars() {
return match bidi_class(ch) {
BidiClass::L => false,
BidiClass::AL => true,
BidiClass::R => true,
_ => continue,
};
}
false
}
// https://html.spec.whatwg.org/multipage/#dom-input-value
// https://html.spec.whatwg.org/multipage/#concept-input-apply
fn value_mode(&self) -> ValueMode {

View file

@ -22,6 +22,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmlfieldsetelement::HTMLFieldSetElement;
use crate::dom::htmlformelement::{FormControl, HTMLFormElement};
use crate::dom::htmlinputelement::HTMLInputElement;
use crate::dom::keyboardevent::KeyboardEvent;
use crate::dom::node::{document_from_node, window_from_node};
use crate::dom::node::{
@ -173,6 +174,11 @@ impl HTMLTextAreaElement {
)
}
pub fn auto_directionality(&self) -> String {
let value: String = self.Value().to_string();
return HTMLInputElement::directionality_from_value(&value);
}
fn update_placeholder_shown_state(&self) {
let has_placeholder = !self.placeholder.borrow().is_empty();
let has_value = !self.textinput.borrow().is_empty();
@ -205,6 +211,12 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
// https://html.spec.whatwg.org/multipage/#dom-textarea-cols
make_limited_uint_setter!(SetCols, "cols", DEFAULT_COLS);
// https://html.spec.whatwg.org/multipage/#dom-input-dirName
make_getter!(DirName, "dirname");
// https://html.spec.whatwg.org/multipage/#dom-input-dirName
make_setter!(SetDirName, "dirname");
// https://html.spec.whatwg.org/multipage/#dom-fe-disabled
make_bool_getter!(Disabled, "disabled");

View file

@ -440,6 +440,26 @@ impl Node {
.upcast::<Event>()
.dispatch(self.upcast::<EventTarget>(), false);
}
pub fn parent_directionality(&self) -> String {
let mut current = self.GetParentNode();
loop {
match current {
Some(node) => {
if let Some(directionality) = node
.downcast::<HTMLElement>()
.and_then(|html_element| html_element.directionality())
{
return directionality;
} else {
current = node.GetParentNode();
}
},
None => return "ltr".to_owned(),
}
}
}
}
pub struct QuerySelectorIterator {

View file

@ -14,8 +14,8 @@ interface HTMLElement : Element {
attribute DOMString lang;
[CEReactions]
attribute boolean translate;
// [CEReactions]
// attribute DOMString dir;
[CEReactions]
attribute DOMString dir;
readonly attribute DOMStringMap dataset;
// microdata

View file

@ -13,8 +13,8 @@ interface HTMLTextAreaElement : HTMLElement {
// attribute boolean autofocus;
[CEReactions, SetterThrows]
attribute unsigned long cols;
// [CEReactions]
// attribute DOMString dirName;
[CEReactions]
attribute DOMString dirName;
[CEReactions]
attribute boolean disabled;
readonly attribute HTMLFormElement? form;