diff options
author | Dmitry Kolupaev <dmitry.klpv@gmail.com> | 2020-01-28 10:34:10 +0300 |
---|---|---|
committer | Dmitry Kolupaev <dmitry.klpv@gmail.com> | 2020-02-25 01:18:20 +0300 |
commit | ef49f2e0eb28f3eb6445eff3aa095edc4b8a64d8 (patch) | |
tree | 530e0ab4dd56c0512639a2cefc32786c47edd7ff | |
parent | 6bc4a7df24df6c7ed41f2ee4c2d38a282760c2b6 (diff) | |
download | servo-ef49f2e0eb28f3eb6445eff3aa095edc4b8a64d8.tar.gz servo-ef49f2e0eb28f3eb6445eff3aa095edc4b8a64d8.zip |
Implement dirname for form submit and directionality for element
-rw-r--r-- | Cargo.lock | 6 | ||||
-rw-r--r-- | components/constellation/constellation.rs | 2 | ||||
-rw-r--r-- | components/embedder_traits/lib.rs | 2 | ||||
-rw-r--r-- | components/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script/dom/element.rs | 64 | ||||
-rw-r--r-- | components/script/dom/htmlelement.rs | 5 | ||||
-rw-r--r-- | components/script/dom/htmlformelement.rs | 18 | ||||
-rwxr-xr-x | components/script/dom/htmlinputelement.rs | 36 | ||||
-rwxr-xr-x | components/script/dom/htmltextareaelement.rs | 9 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLElement.webidl | 4 | ||||
-rw-r--r-- | components/script/dom/window.rs | 1 | ||||
-rw-r--r-- | tests/wpt/metadata/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html.ini | 5 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html | 12 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl.html | 32 |
14 files changed, 178 insertions, 19 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0aebb0c0e24..07524b670c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4783,6 +4783,7 @@ dependencies = [ "tendril", "time", "tinyfiledialogs", + "unicode-bidi", "unicode-segmentation", "url", "utf-8", @@ -6291,13 +6292,12 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" dependencies = [ "matches", "serde", - "serde_derive", ] [[package]] diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 0df1a28c15c..629921035f0 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1614,7 +1614,7 @@ where Some(ctx) => ctx.pipeline_id, None => { return warn!( - "LoadUrl for unknow browsing context: {:?}", + "LoadUrl for unknown browsing context: {:?}", top_level_browsing_context_id ); }, diff --git a/components/embedder_traits/lib.rs b/components/embedder_traits/lib.rs index 246ef63f250..c13ad617920 100644 --- a/components/embedder_traits/lib.rs +++ b/components/embedder_traits/lib.rs @@ -149,7 +149,7 @@ pub enum EmbedderMsg { ResizeTo(DeviceIntSize), /// Show dialog to user Prompt(PromptDefinition, PromptOrigin), - /// Wether or not to allow a pipeline to load a url. + /// Whether or not to allow a pipeline to load a url. AllowNavigationRequest(PipelineId, ServoUrl), /// Whether or not to allow script to open a new tab/browser AllowOpeningBrowser(IpcSender<bool>), 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..bb51ee432fd 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -12,6 +12,7 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use crate::dom::bindings::codegen::Bindings::ElementBinding; use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; +use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementBinding::HTMLElementMethods; use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; @@ -540,6 +541,69 @@ impl Element { } true // whatwg/html#5239 } + + /// https://html.spec.whatwg.org/#the-directionality + pub fn directionality(&self) -> String { + if self.is::<HTMLElement>() { + let htmlElement = self.downcast::<HTMLElement>().unwrap(); + self.html_element_directionality(&htmlElement.Dir()) + } else { + let node = self.upcast::<Node>(); + self.parent_directionality(node) + } + } + + fn html_element_directionality(&self, element_direction: &str) -> String { + if element_direction == "ltr" { + return "ltr".to_owned(); + } + + if element_direction == "rtl" { + return "rtl".to_owned(); + } + + if self.is::<HTMLInputElement>() { + let input = self.downcast::<HTMLInputElement>().unwrap(); + return input.directionality(element_direction); + } + + if self.is::<HTMLTextAreaElement>() { + let area = self.downcast::<HTMLTextAreaElement>().unwrap(); + return area.directionality(element_direction); + } + + // TODO(dmitry.klpv): 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/#the-bdi-element) + + let node = self.upcast::<Node>(); + self.parent_directionality(node) + } + + fn parent_directionality(&self, node: &Node) -> String { + if !node.has_parent() { + return "ltr".to_owned(); + } + + let parent = node.GetParentNode(); + match parent { + Some(parent) => { + if parent.is::<Document>() { + return "ltr".to_owned(); + } + + return if parent.is::<Element>() { + let parentHtml = parent.downcast::<Element>().unwrap(); + parentHtml.directionality() + } else { + self.parent_directionality(&*parent) + }; + }, + None => "ltr".to_owned(), + } + } } #[allow(unsafe_code)] diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index ac0f99416c2..48401acc3fd 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -170,6 +170,11 @@ impl HTMLElementMethods for HTMLElement { // https://html.spec.whatwg.org/multipage/#dom-hidden make_bool_setter!(SetHidden, "hidden"); + // https://html.spec.whatwg.org/multipage/dom.html#the-dir-attribute + make_getter!(Dir, "dir"); + // https://html.spec.whatwg.org/multipage/dom.html#the-dir-attribute + make_setter!(SetDir, "dir"); + // https://html.spec.whatwg.org/multipage/#globaleventhandlers global_event_handlers!(NoOnload); diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index adbb790a181..ffd0d111cad 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -745,6 +745,8 @@ impl HTMLFormElement { .map(|field| (&*field.name, field.replace_value(charset))), ); + println!("New URL: {url}", url = &load_data.url); + self.plan_to_navigate(load_data, target); } @@ -952,6 +954,20 @@ impl HTMLFormElement { let input = child.downcast::<HTMLInputElement>().unwrap(); data_set.append(&mut input.form_datums(submitter, encoding)); + + // TODO: probably move to input.form_datums(...) function + // 4.10.18.2 https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submitting-element-directionality:-the-dirname-attribute + let dirname: DOMString = input.DirName(); + let dirname_str: &str = &*dirname; + if !dirname_str.is_empty() { + data_set.push(FormDatum { + ty: input.Type(), + name: DOMString::from_string(dirname_str.to_owned()), + value: FormDatumValue::String(DOMString::from( + input.directionality("auto"), + )), + }); + } }, HTMLElementTypeId::HTMLButtonElement => { let button = child.downcast::<HTMLButtonElement>().unwrap(); @@ -983,8 +999,6 @@ impl HTMLFormElement { } } 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..298af937a32 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,41 @@ impl HTMLInputElement { ) } + pub fn directionality(&self, element_direction: &str) -> String { + match self.input_type() { + InputType::Tel => return "ltr".to_owned(), + InputType::Text | InputType::Search | InputType::Url | InputType::Email => { + if element_direction == "auto" { + let value: String = self.Value().to_string(); + return HTMLInputElement::auto_directionality(&value); + } + }, + _ => {}, + } + + return "ltr".to_owned(); + } + + pub fn auto_directionality(value: &str) -> String { + if HTMLInputElement::first_strong_character_is_rtl(value) { + "rtl".to_owned() + } else { + "ltr".to_owned() + } + } + + fn first_strong_character_is_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..0cc174cc3c1 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,14 @@ impl HTMLTextAreaElement { ) } + pub fn directionality(&self, element_direction: &str) -> String { + if element_direction == "auto" { + let value: String = self.Value().to_string(); + return HTMLInputElement::auto_directionality(&value); + } + return "ltr".to_owned(); + } + fn update_placeholder_shown_state(&self) { let has_placeholder = !self.placeholder.borrow().is_empty(); let has_value = !self.textinput.borrow().is_empty(); diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl index ef529dc80af..5300ca8b2a0 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/window.rs b/components/script/dom/window.rs index ce290caabf7..724a44e9869 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -2017,6 +2017,7 @@ impl Window { } // TODO: step 11, navigationType. // Step 12, 13 + println!("ScriptThread::navigate"); ScriptThread::navigate(pipeline_id, load_data, replace); }; } diff --git a/tests/wpt/metadata/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html.ini b/tests/wpt/metadata/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html.ini deleted file mode 100644 index 13a9c4d0918..00000000000 --- a/tests/wpt/metadata/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[dirname-ltr.html] - type: testharness - [submit element directionality] - expected: FAIL - diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html b/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html index 28d1c150b37..6420b5b0c76 100644 --- a/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html +++ b/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-ltr.html @@ -20,10 +20,12 @@ } var t = async_test("submit element directionality"); - document.querySelector("input").value="foobar"; - document.querySelector("button").click(); + setTimeout(function() { + document.querySelector("input").value="foobar"; + document.querySelector("button").click(); - document.querySelector("iframe").onload = t.step_func_done(function() { - assert_equals(getParameterByName("comment.dir"), "ltr"); - }); + document.querySelector("iframe").onload = t.step_func_done(function() { + assert_equals(getParameterByName("comment.dir"), "ltr"); + }); + }, 3000); </script> diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl.html b/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl.html new file mode 100644 index 00000000000..69eb45c992c --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Submitting element directionality: the dirname attribute</title> +<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org"> +<link rel=help href="https://html.spec.whatwg.org/multipage/#submitting-element-directionality:-the-dirname-attribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<form action="dirname-ltr-iframe.html" method=get target="iframe"> + <p><label>Comment: <input type=text id="comment-input" name="comment" dirname="comment.dir" required/></label></p> + <p><button type=submit>Post Comment</button></p> +</form> +<iframe name="iframe"></iframe> +<script> + function getParameterByName(name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(document.querySelector("iframe").contentWindow.location.search); + return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } + + var t = async_test("submit element directionality"); + setTimeout(3000, function() { + var rtlValue = "مرحبا"; + document.querySelector("input").value = rtlValue; + document.querySelector("button").click(); + + document.querySelector("iframe").onload = t.step_func_done(function() { + assert_equals(getParameterByName("comment.dir"), "rtl"); + }); + }, 3000); +</script> |