mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Implement dirname for form submit and directionality for element
This commit is contained in:
parent
6bc4a7df24
commit
ef49f2e0eb
14 changed files with 178 additions and 19 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -4783,6 +4783,7 @@ dependencies = [
|
||||||
"tendril",
|
"tendril",
|
||||||
"time",
|
"time",
|
||||||
"tinyfiledialogs",
|
"tinyfiledialogs",
|
||||||
|
"unicode-bidi",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"url",
|
"url",
|
||||||
"utf-8",
|
"utf-8",
|
||||||
|
@ -6291,13 +6292,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a"
|
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matches",
|
"matches",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -1614,7 +1614,7 @@ where
|
||||||
Some(ctx) => ctx.pipeline_id,
|
Some(ctx) => ctx.pipeline_id,
|
||||||
None => {
|
None => {
|
||||||
return warn!(
|
return warn!(
|
||||||
"LoadUrl for unknow browsing context: {:?}",
|
"LoadUrl for unknown browsing context: {:?}",
|
||||||
top_level_browsing_context_id
|
top_level_browsing_context_id
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -149,7 +149,7 @@ pub enum EmbedderMsg {
|
||||||
ResizeTo(DeviceIntSize),
|
ResizeTo(DeviceIntSize),
|
||||||
/// Show dialog to user
|
/// Show dialog to user
|
||||||
Prompt(PromptDefinition, PromptOrigin),
|
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),
|
AllowNavigationRequest(PipelineId, ServoUrl),
|
||||||
/// Whether or not to allow script to open a new tab/browser
|
/// Whether or not to allow script to open a new tab/browser
|
||||||
AllowOpeningBrowser(IpcSender<bool>),
|
AllowOpeningBrowser(IpcSender<bool>),
|
||||||
|
|
|
@ -110,6 +110,7 @@ style_traits = {path = "../style_traits"}
|
||||||
swapper = "0.1"
|
swapper = "0.1"
|
||||||
tendril = {version = "0.4.1", features = ["encoding_rs"]}
|
tendril = {version = "0.4.1", features = ["encoding_rs"]}
|
||||||
time = "0.1.12"
|
time = "0.1.12"
|
||||||
|
unicode-bidi = "0.3.4"
|
||||||
unicode-segmentation = "1.1.0"
|
unicode-segmentation = "1.1.0"
|
||||||
url = "2.0"
|
url = "2.0"
|
||||||
utf-8 = "0.7"
|
utf-8 = "0.7"
|
||||||
|
|
|
@ -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;
|
||||||
use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
|
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::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods;
|
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods;
|
||||||
|
@ -540,6 +541,69 @@ impl Element {
|
||||||
}
|
}
|
||||||
true // whatwg/html#5239
|
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)]
|
#[allow(unsafe_code)]
|
||||||
|
|
|
@ -170,6 +170,11 @@ impl HTMLElementMethods for HTMLElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-hidden
|
// https://html.spec.whatwg.org/multipage/#dom-hidden
|
||||||
make_bool_setter!(SetHidden, "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
|
// https://html.spec.whatwg.org/multipage/#globaleventhandlers
|
||||||
global_event_handlers!(NoOnload);
|
global_event_handlers!(NoOnload);
|
||||||
|
|
||||||
|
|
|
@ -745,6 +745,8 @@ impl HTMLFormElement {
|
||||||
.map(|field| (&*field.name, field.replace_value(charset))),
|
.map(|field| (&*field.name, field.replace_value(charset))),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
println!("New URL: {url}", url = &load_data.url);
|
||||||
|
|
||||||
self.plan_to_navigate(load_data, target);
|
self.plan_to_navigate(load_data, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,6 +954,20 @@ impl HTMLFormElement {
|
||||||
let input = child.downcast::<HTMLInputElement>().unwrap();
|
let input = child.downcast::<HTMLInputElement>().unwrap();
|
||||||
|
|
||||||
data_set.append(&mut input.form_datums(submitter, encoding));
|
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 => {
|
HTMLElementTypeId::HTMLButtonElement => {
|
||||||
let button = child.downcast::<HTMLButtonElement>().unwrap();
|
let button = child.downcast::<HTMLButtonElement>().unwrap();
|
||||||
|
@ -983,8 +999,6 @@ impl HTMLFormElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data_set
|
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>
|
/// <https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set>
|
||||||
|
|
|
@ -75,6 +75,7 @@ use std::ptr::NonNull;
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
use style::element_state::ElementState;
|
use style::element_state::ElementState;
|
||||||
use style::str::{split_commas, str_join};
|
use style::str::{split_commas, str_join};
|
||||||
|
use unicode_bidi::{bidi_class, BidiClass};
|
||||||
|
|
||||||
const DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
|
const DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
|
||||||
const DEFAULT_RESET_VALUE: &'static str = "Reset";
|
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/#dom-input-value
|
||||||
// https://html.spec.whatwg.org/multipage/#concept-input-apply
|
// https://html.spec.whatwg.org/multipage/#concept-input-apply
|
||||||
fn value_mode(&self) -> ValueMode {
|
fn value_mode(&self) -> ValueMode {
|
||||||
|
|
|
@ -22,6 +22,7 @@ use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::htmlelement::HTMLElement;
|
use crate::dom::htmlelement::HTMLElement;
|
||||||
use crate::dom::htmlfieldsetelement::HTMLFieldSetElement;
|
use crate::dom::htmlfieldsetelement::HTMLFieldSetElement;
|
||||||
use crate::dom::htmlformelement::{FormControl, HTMLFormElement};
|
use crate::dom::htmlformelement::{FormControl, HTMLFormElement};
|
||||||
|
use crate::dom::htmlinputelement::HTMLInputElement;
|
||||||
use crate::dom::keyboardevent::KeyboardEvent;
|
use crate::dom::keyboardevent::KeyboardEvent;
|
||||||
use crate::dom::node::{document_from_node, window_from_node};
|
use crate::dom::node::{document_from_node, window_from_node};
|
||||||
use crate::dom::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) {
|
fn update_placeholder_shown_state(&self) {
|
||||||
let has_placeholder = !self.placeholder.borrow().is_empty();
|
let has_placeholder = !self.placeholder.borrow().is_empty();
|
||||||
let has_value = !self.textinput.borrow().is_empty();
|
let has_value = !self.textinput.borrow().is_empty();
|
||||||
|
|
|
@ -14,8 +14,8 @@ interface HTMLElement : Element {
|
||||||
attribute DOMString lang;
|
attribute DOMString lang;
|
||||||
[CEReactions]
|
[CEReactions]
|
||||||
attribute boolean translate;
|
attribute boolean translate;
|
||||||
// [CEReactions]
|
[CEReactions]
|
||||||
// attribute DOMString dir;
|
attribute DOMString dir;
|
||||||
readonly attribute DOMStringMap dataset;
|
readonly attribute DOMStringMap dataset;
|
||||||
|
|
||||||
// microdata
|
// microdata
|
||||||
|
|
|
@ -2017,6 +2017,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
// TODO: step 11, navigationType.
|
// TODO: step 11, navigationType.
|
||||||
// Step 12, 13
|
// Step 12, 13
|
||||||
|
println!("ScriptThread::navigate");
|
||||||
ScriptThread::navigate(pipeline_id, load_data, replace);
|
ScriptThread::navigate(pipeline_id, load_data, replace);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[dirname-ltr.html]
|
|
||||||
type: testharness
|
|
||||||
[submit element directionality]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -20,10 +20,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
var t = async_test("submit element directionality");
|
var t = async_test("submit element directionality");
|
||||||
|
setTimeout(function() {
|
||||||
document.querySelector("input").value="foobar";
|
document.querySelector("input").value="foobar";
|
||||||
document.querySelector("button").click();
|
document.querySelector("button").click();
|
||||||
|
|
||||||
document.querySelector("iframe").onload = t.step_func_done(function() {
|
document.querySelector("iframe").onload = t.step_func_done(function() {
|
||||||
assert_equals(getParameterByName("comment.dir"), "ltr");
|
assert_equals(getParameterByName("comment.dir"), "ltr");
|
||||||
});
|
});
|
||||||
|
}, 3000);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue