mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implemented get element target and get element noopener algorithms
and refactored into functions.
This commit is contained in:
parent
8d9615fa41
commit
2d5c30d042
11 changed files with 90 additions and 62 deletions
|
@ -18,7 +18,9 @@ use crate::dom::element::{referrer_policy_for_element, Element};
|
||||||
use crate::dom::event::Event;
|
use crate::dom::event::Event;
|
||||||
use crate::dom::eventtarget::EventTarget;
|
use crate::dom::eventtarget::EventTarget;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::htmlareaelement::HTMLAreaElement;
|
||||||
use crate::dom::htmlelement::HTMLElement;
|
use crate::dom::htmlelement::HTMLElement;
|
||||||
|
use crate::dom::htmlformelement::HTMLFormElement;
|
||||||
use crate::dom::htmlimageelement::HTMLImageElement;
|
use crate::dom::htmlimageelement::HTMLImageElement;
|
||||||
use crate::dom::mouseevent::MouseEvent;
|
use crate::dom::mouseevent::MouseEvent;
|
||||||
use crate::dom::node::{document_from_node, Node};
|
use crate::dom::node::{document_from_node, Node};
|
||||||
|
@ -566,6 +568,52 @@ impl Activatable for HTMLAnchorElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://html.spec.whatwg.org/multipage/#get-an-element's-target>
|
||||||
|
pub fn get_element_target(subject: &Element) -> Option<DOMString> {
|
||||||
|
if !(subject.is::<HTMLAreaElement>() ||
|
||||||
|
subject.is::<HTMLAnchorElement>() ||
|
||||||
|
subject.is::<HTMLFormElement>())
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if subject.has_attribute(&local_name!("target")) {
|
||||||
|
return Some(subject.get_string_attribute(&local_name!("target")));
|
||||||
|
}
|
||||||
|
|
||||||
|
let doc = document_from_node(subject).base_element();
|
||||||
|
match doc {
|
||||||
|
Some(doc) => {
|
||||||
|
let element = doc.upcast::<Element>();
|
||||||
|
if element.has_attribute(&local_name!("target")) {
|
||||||
|
return Some(element.get_string_attribute(&local_name!("target")));
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// < https://html.spec.whatwg.org/multipage/#get-an-element's-noopener>
|
||||||
|
pub fn get_element_noopener(subject: &Element, target_attribute_value: Option<DOMString>) -> bool {
|
||||||
|
if !(subject.is::<HTMLAreaElement>() ||
|
||||||
|
subject.is::<HTMLAnchorElement>() ||
|
||||||
|
subject.is::<HTMLFormElement>())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let target_is_blank = target_attribute_value
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |target| target.to_lowercase() == "_blank");
|
||||||
|
let link_types = match subject.get_attribute(&ns!(), &local_name!("rel")) {
|
||||||
|
Some(rel) => rel.Value(),
|
||||||
|
None => return target_is_blank,
|
||||||
|
};
|
||||||
|
return link_types.contains("noreferrer") ||
|
||||||
|
link_types.contains("noopener") ||
|
||||||
|
(!link_types.contains("opener") && target_is_blank);
|
||||||
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#following-hyperlinks-2>
|
/// <https://html.spec.whatwg.org/multipage/#following-hyperlinks-2>
|
||||||
pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
|
pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
|
@ -581,29 +629,19 @@ pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
|
||||||
let source = document.browsing_context().unwrap();
|
let source = document.browsing_context().unwrap();
|
||||||
|
|
||||||
// Step 4-5: target attribute.
|
// Step 4-5: target attribute.
|
||||||
let target_attribute_value = subject.get_attribute(&ns!(), &local_name!("target"));
|
let target_attribute_value =
|
||||||
|
if subject.is::<HTMLAreaElement>() || subject.is::<HTMLAnchorElement>() {
|
||||||
// Step 6.
|
get_element_target(subject)
|
||||||
let noopener = if let Some(link_types) = subject.get_attribute(&ns!(), &local_name!("rel")) {
|
|
||||||
let values = link_types.Value();
|
|
||||||
let contains_noopener = values.contains("noopener");
|
|
||||||
let contains_noreferrer = values.contains("noreferrer");
|
|
||||||
let contains_opener = values.contains("opener");
|
|
||||||
let target_is_blank = if let Some(name) = target_attribute_value.as_ref() {
|
|
||||||
name.Value().to_lowercase() == "_blank"
|
|
||||||
} else {
|
} else {
|
||||||
false
|
None
|
||||||
};
|
};
|
||||||
|
// Step 6.
|
||||||
contains_noreferrer || contains_noopener || (!contains_opener && target_is_blank)
|
let noopener = get_element_noopener(subject, target_attribute_value.clone());
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
// Step 7.
|
// Step 7.
|
||||||
let (maybe_chosen, replace) = match target_attribute_value {
|
let (maybe_chosen, replace) = match target_attribute_value {
|
||||||
Some(name) => {
|
Some(name) => {
|
||||||
let (maybe_chosen, new) = source.choose_browsing_context(name.Value(), noopener);
|
let (maybe_chosen, new) = source.choose_browsing_context(name, noopener);
|
||||||
let replace = if new {
|
let replace = if new {
|
||||||
HistoryEntryReplacement::Enabled
|
HistoryEntryReplacement::Enabled
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -31,6 +31,7 @@ use crate::dom::file::File;
|
||||||
use crate::dom::formdata::FormData;
|
use crate::dom::formdata::FormData;
|
||||||
use crate::dom::formdataevent::FormDataEvent;
|
use crate::dom::formdataevent::FormDataEvent;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::htmlanchorelement::{get_element_noopener, get_element_target};
|
||||||
use crate::dom::htmlbuttonelement::HTMLButtonElement;
|
use crate::dom::htmlbuttonelement::HTMLButtonElement;
|
||||||
use crate::dom::htmlcollection::CollectionFilter;
|
use crate::dom::htmlcollection::CollectionFilter;
|
||||||
use crate::dom::htmldatalistelement::HTMLDataListElement;
|
use crate::dom::htmldatalistelement::HTMLDataListElement;
|
||||||
|
@ -576,12 +577,12 @@ impl HTMLFormElementMethods for HTMLFormElement {
|
||||||
return names_vec;
|
return names_vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-form-checkvalidity
|
/// https://html.spec.whatwg.org/multipage/#dom-form-checkvalidity
|
||||||
fn CheckValidity(&self) -> bool {
|
fn CheckValidity(&self) -> bool {
|
||||||
self.static_validation().is_ok()
|
self.static_validation().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-form-reportvalidity
|
/// https://html.spec.whatwg.org/multipage/#dom-form-reportvalidity
|
||||||
fn ReportValidity(&self) -> bool {
|
fn ReportValidity(&self) -> bool {
|
||||||
self.interactive_validation().is_ok()
|
self.interactive_validation().is_ok()
|
||||||
}
|
}
|
||||||
|
@ -746,10 +747,26 @@ impl HTMLFormElement {
|
||||||
let enctype = submitter.enctype();
|
let enctype = submitter.enctype();
|
||||||
let method = submitter.method();
|
let method = submitter.method();
|
||||||
|
|
||||||
// Step 17-21
|
// Step 17
|
||||||
let target_attribute_value = submitter.target();
|
let target_attribute_value =
|
||||||
|
if submitter.is_submit_button() && submitter.target() != DOMString::new() {
|
||||||
|
Some(submitter.target())
|
||||||
|
} else {
|
||||||
|
let form_owner = submitter.form_owner();
|
||||||
|
let form = form_owner.as_ref().map(|form| &**form).unwrap_or(self);
|
||||||
|
get_element_target(form.upcast::<Element>())
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 18
|
||||||
|
let noopener =
|
||||||
|
get_element_noopener(self.upcast::<Element>(), target_attribute_value.clone());
|
||||||
|
|
||||||
|
// Step 19
|
||||||
let source = doc.browsing_context().unwrap();
|
let source = doc.browsing_context().unwrap();
|
||||||
let (maybe_chosen, _new) = source.choose_browsing_context(target_attribute_value, false);
|
let (maybe_chosen, _new) = source
|
||||||
|
.choose_browsing_context(target_attribute_value.unwrap_or(DOMString::new()), noopener);
|
||||||
|
|
||||||
|
// Step 20
|
||||||
let chosen = match maybe_chosen {
|
let chosen = match maybe_chosen {
|
||||||
Some(proxy) => proxy,
|
Some(proxy) => proxy,
|
||||||
None => return,
|
None => return,
|
||||||
|
@ -758,6 +775,7 @@ impl HTMLFormElement {
|
||||||
Some(doc) => doc,
|
Some(doc) => doc,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
// Step 21
|
||||||
let target_window = target_document.window();
|
let target_window = target_document.window();
|
||||||
let mut load_data = LoadData::new(
|
let mut load_data = LoadData::new(
|
||||||
LoadOrigin::Script(doc.origin().immutable().clone()),
|
LoadOrigin::Script(doc.origin().immutable().clone()),
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
[[data-expected-height\] 3]
|
[[data-expected-height\] 3]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[[data-expected-height\] 4]
|
[[data-expected-height\] 1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[[data-expected-height\] 2]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,3 @@
|
||||||
[X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!]
|
[X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[X-Content-Type-Options%3A%20%2Cnosniff]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[opener-closed.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[An auxiliary browsing context should report `null` for `window.opener` when that browsing context is discarded]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[choose-_blank-003.html]
|
||||||
|
[Context created by link targeting "_blank" should retain opener reference]
|
||||||
|
expected: FAIL
|
|
@ -2,21 +2,12 @@
|
||||||
[<form rel="opener noopener"> with <button formtarget>]
|
[<form rel="opener noopener"> with <button formtarget>]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[<form rel="noopener noreferrer"> with <button formtarget>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel=""> with <button formtarget>]
|
[<form rel=""> with <button formtarget>]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[<form rel="noreferrer opener"> with <button formtarget>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel="noopener"> with <button formtarget>]
|
[<form rel="noopener"> with <button formtarget>]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[<form rel="noreferrer"> with <button formtarget>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel="opener"> with <button formtarget>]
|
[<form rel="opener"> with <button formtarget>]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
[rel-form-target.html]
|
[rel-form-target.html]
|
||||||
[<form rel="noopener noreferrer"> with <form target>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel="noreferrer opener"> with <form target>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel="noreferrer"> with <form target>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel="opener noopener"> with <form target>]
|
[<form rel="opener noopener"> with <form target>]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,6 @@
|
||||||
[<form rel=""> with <input formtarget>]
|
[<form rel=""> with <input formtarget>]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[<form rel="noreferrer opener"> with <input formtarget>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel="noopener noreferrer"> with <input formtarget>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel="noreferrer"> with <input formtarget>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<form rel="noopener"> with <input formtarget>]
|
[<form rel="noopener"> with <input formtarget>]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,9 @@
|
||||||
[Check that targeting of rel=noopener with a given name ignores an existing window with that name]
|
[Check that targeting of rel=noopener with a given name ignores an existing window with that name]
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
||||||
|
|
||||||
[Check that rel=noopener with target=_parent does a normal load]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Check that targeting of rel=noopener with a given name reuses an existing window with that name]
|
[Check that targeting of rel=noopener with a given name reuses an existing window with that name]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Check that rel=noopener with target=_top does a normal load]
|
[Check that rel=noopener with target=_top does a normal load]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Check that rel=noopener with target=_self does a normal load]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
[Area element with target=_blank with rel=opener]
|
[Area element with target=_blank with rel=opener]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Anchor element with target=_blank with implicit rel=noopener]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Area element with target=_blank with implicit rel=noopener]
|
[Area element with target=_blank with implicit rel=noopener]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue