mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Auto merge of #11542 - asajeffrey:mozbrowser-send-opentab-event, r=paulrouget
Fire a mozbrowseropenwindow event when an html anchor has a non-self target <!-- Please describe your changes on the following line: --> When an html anchor has a non-self target, fire a `mozbrowseropenwindow` event. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #11539. - [X] These changes do not require tests because we don't have the infrastructure for mozbrowser testing yet. <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11542) <!-- Reviewable:end -->
This commit is contained in:
commit
bdecfa13d2
9 changed files with 115 additions and 8 deletions
|
@ -26,9 +26,11 @@ use dom::node::{Node, document_from_node, window_from_node};
|
||||||
use dom::urlhelper::UrlHelper;
|
use dom::urlhelper::UrlHelper;
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
use script_traits::MozBrowserEvent;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
use util::prefs::mozbrowser_enabled;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLAnchorElement {
|
pub struct HTMLAnchorElement {
|
||||||
|
@ -542,30 +544,48 @@ impl Activatable for HTMLAnchorElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
|
||||||
|
fn is_current_browsing_context(target: DOMString) -> bool {
|
||||||
|
target.is_empty() || target == "_self"
|
||||||
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#following-hyperlinks-2
|
/// https://html.spec.whatwg.org/multipage/#following-hyperlinks-2
|
||||||
fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
|
fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
|
||||||
// Step 1: replace.
|
// Step 1: replace.
|
||||||
// Step 2: source browsing context.
|
// Step 2: source browsing context.
|
||||||
// Step 3: target browsing context.
|
// Step 3: target browsing context.
|
||||||
|
let target = subject.get_attribute(&ns!(), &atom!("target"));
|
||||||
|
|
||||||
// Step 4.
|
// Step 4: disown target's opener if needed.
|
||||||
let attribute = subject.get_attribute(&ns!(), &atom!("href")).unwrap();
|
let attribute = subject.get_attribute(&ns!(), &atom!("href")).unwrap();
|
||||||
let mut href = attribute.Value();
|
let mut href = attribute.Value();
|
||||||
|
|
||||||
// Step 6.
|
// Step 7: append a hyperlink suffix.
|
||||||
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=28925
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=28925
|
||||||
if let Some(suffix) = hyperlink_suffix {
|
if let Some(suffix) = hyperlink_suffix {
|
||||||
href.push_str(&suffix);
|
href.push_str(&suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4-5.
|
// Step 5: parse the URL.
|
||||||
|
// Step 6: navigate to an error document if parsing failed.
|
||||||
let document = document_from_node(subject);
|
let document = document_from_node(subject);
|
||||||
let url = match document.url().join(&href) {
|
let url = match document.url().join(&href) {
|
||||||
Ok(url) => url,
|
Ok(url) => url,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 7.
|
// Step 8: navigate to the URL.
|
||||||
|
if let Some(target) = target {
|
||||||
|
if mozbrowser_enabled() && !is_current_browsing_context(target.Value()) {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowseropenwindow
|
||||||
|
// TODO: referrer and opener
|
||||||
|
// TODO: should we send the normalized url or the non-normalized href?
|
||||||
|
let event = MozBrowserEvent::OpenWindow(url.into_string(), Some(String::from(target.Value())), None);
|
||||||
|
document.trigger_mozbrowser_event(event);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
debug!("following hyperlink to {}", url);
|
debug!("following hyperlink to {}", url);
|
||||||
let window = document.window();
|
let window = document.window();
|
||||||
window.load_url(url);
|
window.load_url(url);
|
||||||
|
|
|
@ -8,6 +8,8 @@ use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementErrorEventDetail;
|
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementErrorEventDetail;
|
||||||
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementIconChangeEventDetail;
|
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementIconChangeEventDetail;
|
||||||
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementLocationChangeEventDetail;
|
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementLocationChangeEventDetail;
|
||||||
|
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenTabEventDetail;
|
||||||
|
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenWindowEventDetail;
|
||||||
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementSecurityChangeDetail;
|
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementSecurityChangeDetail;
|
||||||
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserShowModalPromptEventDetail;
|
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserShowModalPromptEventDetail;
|
||||||
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
|
||||||
|
@ -310,7 +312,7 @@ impl MozBrowserEventDetailBuilder for HTMLIFrameElement {
|
||||||
match event {
|
match event {
|
||||||
MozBrowserEvent::AsyncScroll | MozBrowserEvent::Close | MozBrowserEvent::ContextMenu |
|
MozBrowserEvent::AsyncScroll | MozBrowserEvent::Close | MozBrowserEvent::ContextMenu |
|
||||||
MozBrowserEvent::LoadEnd | MozBrowserEvent::LoadStart |
|
MozBrowserEvent::LoadEnd | MozBrowserEvent::LoadStart |
|
||||||
MozBrowserEvent::Connected | MozBrowserEvent::OpenWindow | MozBrowserEvent::OpenSearch |
|
MozBrowserEvent::Connected | MozBrowserEvent::OpenSearch |
|
||||||
MozBrowserEvent::UsernameAndPasswordRequired => {
|
MozBrowserEvent::UsernameAndPasswordRequired => {
|
||||||
rval.set(NullValue());
|
rval.set(NullValue());
|
||||||
}
|
}
|
||||||
|
@ -347,6 +349,18 @@ impl MozBrowserEventDetailBuilder for HTMLIFrameElement {
|
||||||
canGoForward: Some(can_go_forward),
|
canGoForward: Some(can_go_forward),
|
||||||
}.to_jsval(cx, rval);
|
}.to_jsval(cx, rval);
|
||||||
}
|
}
|
||||||
|
MozBrowserEvent::OpenTab(url) => {
|
||||||
|
BrowserElementOpenTabEventDetail {
|
||||||
|
url: Some(DOMString::from(url)),
|
||||||
|
}.to_jsval(cx, rval);
|
||||||
|
}
|
||||||
|
MozBrowserEvent::OpenWindow(url, target, features) => {
|
||||||
|
BrowserElementOpenWindowEventDetail {
|
||||||
|
url: Some(DOMString::from(url)),
|
||||||
|
target: target.map(DOMString::from),
|
||||||
|
features: features.map(DOMString::from),
|
||||||
|
}.to_jsval(cx, rval);
|
||||||
|
}
|
||||||
MozBrowserEvent::IconChange(rel, href, sizes) => {
|
MozBrowserEvent::IconChange(rel, href, sizes) => {
|
||||||
BrowserElementIconChangeEventDetail {
|
BrowserElementIconChangeEventDetail {
|
||||||
rel: Some(DOMString::from(rel)),
|
rel: Some(DOMString::from(rel)),
|
||||||
|
|
|
@ -83,6 +83,19 @@ dictionary BrowserShowModalPromptEventDetail {
|
||||||
// TODO(simartin) unblock() callback
|
// TODO(simartin) unblock() callback
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dictionary BrowserElementOpenTabEventDetail {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowseropentab
|
||||||
|
DOMString url;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary BrowserElementOpenWindowEventDetail {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowseropenwindow
|
||||||
|
DOMString url;
|
||||||
|
DOMString target;
|
||||||
|
DOMString features;
|
||||||
|
// Element frameElement;
|
||||||
|
};
|
||||||
|
|
||||||
BrowserElement implements BrowserElementCommon;
|
BrowserElement implements BrowserElementCommon;
|
||||||
BrowserElement implements BrowserElementPrivileged;
|
BrowserElement implements BrowserElementPrivileged;
|
||||||
|
|
||||||
|
|
|
@ -404,8 +404,13 @@ pub enum MozBrowserEvent {
|
||||||
LoadStart,
|
LoadStart,
|
||||||
/// Sent when a browser `<iframe>`'s location changes.
|
/// Sent when a browser `<iframe>`'s location changes.
|
||||||
LocationChange(String, bool, bool),
|
LocationChange(String, bool, bool),
|
||||||
/// Sent when window.open() is called within a browser `<iframe>`.
|
/// Sent when a new tab is opened within a browser `<iframe>` as a result of the user
|
||||||
OpenWindow,
|
/// issuing a command to open a link target in a new tab (for example ctrl/cmd + click.)
|
||||||
|
/// Includes the URL.
|
||||||
|
OpenTab(String),
|
||||||
|
/// Sent when a new window is opened within a browser `<iframe>`.
|
||||||
|
/// Includes the URL, target browsing context name, and features.
|
||||||
|
OpenWindow(String, Option<String>, Option<String>),
|
||||||
/// Sent when the SSL state changes within a browser `<iframe>`.
|
/// Sent when the SSL state changes within a browser `<iframe>`.
|
||||||
SecurityChange(HttpsState),
|
SecurityChange(HttpsState),
|
||||||
/// Sent when alert(), confirm(), or prompt() is called within a browser `<iframe>`.
|
/// Sent when alert(), confirm(), or prompt() is called within a browser `<iframe>`.
|
||||||
|
@ -431,7 +436,8 @@ impl MozBrowserEvent {
|
||||||
MozBrowserEvent::LoadEnd => "mozbrowserloadend",
|
MozBrowserEvent::LoadEnd => "mozbrowserloadend",
|
||||||
MozBrowserEvent::LoadStart => "mozbrowserloadstart",
|
MozBrowserEvent::LoadStart => "mozbrowserloadstart",
|
||||||
MozBrowserEvent::LocationChange(_, _, _) => "mozbrowserlocationchange",
|
MozBrowserEvent::LocationChange(_, _, _) => "mozbrowserlocationchange",
|
||||||
MozBrowserEvent::OpenWindow => "mozbrowseropenwindow",
|
MozBrowserEvent::OpenTab(_) => "mozbrowseropentab",
|
||||||
|
MozBrowserEvent::OpenWindow(_, _, _) => "mozbrowseropenwindow",
|
||||||
MozBrowserEvent::SecurityChange(_) => "mozbrowsersecuritychange",
|
MozBrowserEvent::SecurityChange(_) => "mozbrowsersecuritychange",
|
||||||
MozBrowserEvent::ShowModalPrompt(_, _, _, _) => "mozbrowsershowmodalprompt",
|
MozBrowserEvent::ShowModalPrompt(_, _, _, _) => "mozbrowsershowmodalprompt",
|
||||||
MozBrowserEvent::TitleChange(_) => "mozbrowsertitlechange",
|
MozBrowserEvent::TitleChange(_) => "mozbrowsertitlechange",
|
||||||
|
|
|
@ -6538,6 +6538,12 @@
|
||||||
"url": "/_mozilla/mozilla/mozbrowser/iframe_reload_twice.html"
|
"url": "/_mozilla/mozilla/mozbrowser/iframe_reload_twice.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"mozilla/mozbrowser/mozbrowser_click_fires_openwindow.html": [
|
||||||
|
{
|
||||||
|
"path": "mozilla/mozbrowser/mozbrowser_click_fires_openwindow.html",
|
||||||
|
"url": "/_mozilla/mozilla/mozbrowser/mozbrowser_click_fires_openwindow.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"mozilla/mozbrowser/mozbrowser_loadevents.html": [
|
"mozilla/mozbrowser/mozbrowser_loadevents.html": [
|
||||||
{
|
{
|
||||||
"path": "mozilla/mozbrowser/mozbrowser_loadevents.html",
|
"path": "mozilla/mozbrowser/mozbrowser_loadevents.html",
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<head>
|
||||||
|
<title>Browser API; mozbrowseropenwindow event</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
async_test(function(t) {
|
||||||
|
|
||||||
|
var iframe = document.createElement("iframe");
|
||||||
|
iframe.mozbrowser = "true";
|
||||||
|
iframe.src = "mozbrowser_click_fires_openwindow_iframe1.html";
|
||||||
|
|
||||||
|
iframe.addEventListener("mozbrowseropenwindow", t.step_func(function(e) {
|
||||||
|
var expectedURL = new URL("mozbrowser_click_fires_openwindow_iframe3.html", window.location.href);
|
||||||
|
assert_equals(e.detail.target, "_blank");
|
||||||
|
assert_equals(e.detail.url.toString(), expectedURL.toString());
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Frame 1: <a id="anchor" href="mozbrowser_click_fires_openwindow_iframe2.html">go</a>.
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
document.getElementById("anchor").click()
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Frame 2: <a id="anchor" href="mozbrowser_click_fires_openwindow_iframe3.html" target="_blank">go</a>.
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
document.getElementById("anchor").click()
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Frame 3.
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue