diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2020-02-24 21:18:10 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-24 21:18:10 -0500 |
commit | 145c89a2d49b7a0c2842e99dff65da4d8164bf7d (patch) | |
tree | 77953fcbca71db4cec36c60594796df871d93239 /components/script | |
parent | e3a5f36fb21d8a93c248016bdd59b8878713a8a3 (diff) | |
parent | 50b495684ed37042fbc0b895f1e6d0a732b9d378 (diff) | |
download | servo-145c89a2d49b7a0c2842e99dff65da4d8164bf7d.tar.gz servo-145c89a2d49b7a0c2842e99dff65da4d8164bf7d.zip |
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)
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script/dom/element.rs | 10 | ||||
-rw-r--r-- | components/script/dom/htmlelement.rs | 48 | ||||
-rw-r--r-- | components/script/dom/htmlformelement.rs | 25 | ||||
-rwxr-xr-x | components/script/dom/htmlinputelement.rs | 31 | ||||
-rwxr-xr-x | components/script/dom/htmltextareaelement.rs | 12 | ||||
-rw-r--r-- | components/script/dom/node.rs | 20 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLElement.webidl | 4 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLTextAreaElement.webidl | 4 |
9 files changed, 148 insertions, 7 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 93813953aac..03eac6cae65 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -110,6 +110,7 @@ style_traits = {path = "../style_traits"} swapper = "0.1" tendril = {version = "0.4.1", features = ["encoding_rs"]} time = "0.1.12" +unicode-bidi = "0.3.4" unicode-segmentation = "1.1.0" url = "2.0" utf-8 = "0.7" diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index eecff289cdb..268b263fc41 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -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)] diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index ac0f99416c2..00d7a64ed32 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -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 { diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index adbb790a181..30d1857de9d 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -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> diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 441206c9dad..a5fefa095ae 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -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 { diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 9fd316e3a18..d077d9eec8f 100755 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -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"); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index c1da57eae88..05b81a84d5d 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -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 { diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl index ef529dc80af..c743c0a7129 100644 --- a/components/script/dom/webidls/HTMLElement.webidl +++ b/components/script/dom/webidls/HTMLElement.webidl @@ -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 diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl index 99cf18e0c10..b09200f1dc5 100644 --- a/components/script/dom/webidls/HTMLTextAreaElement.webidl +++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl @@ -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; |