mirror of
https://github.com/servo/servo.git
synced 2025-06-08 00:23:30 +00:00
Implement alert dialogs
Fixed conflict Fixed merge issue Finished implementation Disable tinyfiledialogs on Windows addressed comments Use ancestor's SubpageId Move display alert from method to function Add extra test for nested iframes Addressed comments Updated tinyfiledialogs
This commit is contained in:
parent
3f2ceeff5d
commit
dc85be4be5
10 changed files with 122 additions and 19 deletions
|
@ -797,6 +797,10 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
|
||||||
debug!("constellation got SetDocumentState message");
|
debug!("constellation got SetDocumentState message");
|
||||||
self.document_states.insert(pipeline_id, state);
|
self.document_states.insert(pipeline_id, state);
|
||||||
}
|
}
|
||||||
|
Request::Script(FromScriptMsg::Alert(pipeline_id, message, sender)) => {
|
||||||
|
debug!("constellation got Alert message");
|
||||||
|
self.handle_alert(pipeline_id, message, sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Messages from layout thread
|
// Messages from layout thread
|
||||||
|
@ -1069,6 +1073,44 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_alert(&mut self, pipeline_id: PipelineId, message: String, sender: IpcSender<bool>) {
|
||||||
|
let display_alert_dialog = if prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) {
|
||||||
|
let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info);
|
||||||
|
if let Some(_) = parent_pipeline_info {
|
||||||
|
let root_pipeline_id = self.root_frame_id
|
||||||
|
.and_then(|root_frame_id| self.frames.get(&root_frame_id))
|
||||||
|
.map(|root_frame| root_frame.current);
|
||||||
|
|
||||||
|
let ancestor_info = self.get_root_pipeline_and_containing_parent(&pipeline_id);
|
||||||
|
if let Some(ancestor_info) = ancestor_info {
|
||||||
|
if root_pipeline_id == Some(ancestor_info.0) {
|
||||||
|
match root_pipeline_id.and_then(|pipeline_id| self.pipelines.get(&pipeline_id)) {
|
||||||
|
Some(root_pipeline) => {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsershowmodalprompt
|
||||||
|
let event = MozBrowserEvent::ShowModalPrompt("alert".to_owned(), "Alert".to_owned(),
|
||||||
|
String::from(message), "".to_owned());
|
||||||
|
root_pipeline.trigger_mozbrowser_event(ancestor_info.1, event);
|
||||||
|
}
|
||||||
|
None => return warn!("Alert sent to Pipeline {:?} after closure.", root_pipeline_id),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("A non-current frame is trying to show an alert.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = sender.send(display_alert_dialog);
|
||||||
|
if let Err(e) = result {
|
||||||
|
self.handle_send_error(pipeline_id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_load_url_msg(&mut self, source_id: PipelineId, load_data: LoadData) {
|
fn handle_load_url_msg(&mut self, source_id: PipelineId, load_data: LoadData) {
|
||||||
self.load_url(source_id, load_data);
|
self.load_url(source_id, load_data);
|
||||||
}
|
}
|
||||||
|
@ -1945,6 +1987,29 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For a given pipeline, determine the iframe in the root pipeline that transitively contains
|
||||||
|
/// it. There could be arbitrary levels of nested iframes in between them.
|
||||||
|
fn get_root_pipeline_and_containing_parent(&self, pipeline_id: &PipelineId) -> Option<(PipelineId, SubpageId)> {
|
||||||
|
if let Some(pipeline) = self.pipelines.get(pipeline_id) {
|
||||||
|
if let Some(mut ancestor_info) = pipeline.parent_info {
|
||||||
|
if let Some(mut ancestor) = self.pipelines.get(&ancestor_info.0) {
|
||||||
|
while let Some(next_info) = ancestor.parent_info {
|
||||||
|
ancestor_info = next_info;
|
||||||
|
ancestor = match self.pipelines.get(&ancestor_info.0) {
|
||||||
|
Some(ancestor) => ancestor,
|
||||||
|
None => {
|
||||||
|
warn!("Get parent pipeline before root via closed pipeline {:?}.", ancestor_info.0);
|
||||||
|
return None;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Some(ancestor_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange
|
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange
|
||||||
// Note that this is a no-op if the pipeline is not an immediate child iframe of the root
|
// Note that this is a no-op if the pipeline is not an immediate child iframe of the root
|
||||||
fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) {
|
fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) {
|
||||||
|
@ -1976,19 +2041,15 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
|
||||||
fn trigger_mozbrowsererror(&self, pipeline_id: PipelineId, reason: String, backtrace: String) {
|
fn trigger_mozbrowsererror(&self, pipeline_id: PipelineId, reason: String, backtrace: String) {
|
||||||
if !prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) { return; }
|
if !prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) { return; }
|
||||||
|
|
||||||
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
|
let ancestor_info = self.get_root_pipeline_and_containing_parent(&pipeline_id);
|
||||||
if let Some(mut ancestor_info) = pipeline.parent_info {
|
|
||||||
if let Some(mut ancestor) = self.pipelines.get(&ancestor_info.0) {
|
if let Some(ancestor_info) = ancestor_info {
|
||||||
while let Some(next_info) = ancestor.parent_info {
|
match self.pipelines.get(&ancestor_info.0) {
|
||||||
ancestor_info = next_info;
|
Some(ancestor) => {
|
||||||
ancestor = match self.pipelines.get(&ancestor_info.0) {
|
|
||||||
Some(ancestor) => ancestor,
|
|
||||||
None => return warn!("Mozbrowsererror via closed pipeline {:?}.", ancestor_info.0),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, Some(reason), Some(backtrace));
|
let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, Some(reason), Some(backtrace));
|
||||||
ancestor.trigger_mozbrowser_event(ancestor_info.1, event);
|
ancestor.trigger_mozbrowser_event(ancestor_info.1, event);
|
||||||
}
|
},
|
||||||
|
None => return warn!("Mozbrowsererror via closed pipeline {:?}.", ancestor_info.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ path = "lib.rs"
|
||||||
[features]
|
[features]
|
||||||
debugmozjs = ['js/debugmozjs']
|
debugmozjs = ['js/debugmozjs']
|
||||||
|
|
||||||
|
[target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies]
|
||||||
|
tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"}
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
plugins = {path = "../plugins"}
|
plugins = {path = "../plugins"}
|
||||||
util = {path = "../util"}
|
util = {path = "../util"}
|
||||||
|
|
|
@ -59,7 +59,7 @@ use script_thread::SendableMainThreadScriptChan;
|
||||||
use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper};
|
use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper};
|
||||||
use script_traits::{ConstellationControlMsg, UntrustedNodeAddress};
|
use script_traits::{ConstellationControlMsg, UntrustedNodeAddress};
|
||||||
use script_traits::{DocumentState, MsDuration, ScriptToCompositorMsg, TimerEvent, TimerEventId};
|
use script_traits::{DocumentState, MsDuration, ScriptToCompositorMsg, TimerEvent, TimerEventId};
|
||||||
use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg, TimerEventRequest, TimerSource};
|
use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, TimerSource};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -85,6 +85,8 @@ use task_source::networking::NetworkingTaskSource;
|
||||||
use task_source::user_interaction::UserInteractionTaskSource;
|
use task_source::user_interaction::UserInteractionTaskSource;
|
||||||
use time;
|
use time;
|
||||||
use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback};
|
use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback};
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||||
|
use tinyfiledialogs::{self, MessageBoxIcon};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::geometry::{self, MAX_RECT};
|
use util::geometry::{self, MAX_RECT};
|
||||||
use util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
use util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
||||||
|
@ -343,6 +345,16 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||||
|
fn display_alert_dialog(message: &str) {
|
||||||
|
tinyfiledialogs::message_box_ok("Alert!", message, MessageBoxIcon::Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||||
|
fn display_alert_dialog(_message: &str) {
|
||||||
|
// tinyfiledialogs not supported on Windows
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#atob
|
// https://html.spec.whatwg.org/multipage/#atob
|
||||||
pub fn base64_btoa(input: DOMString) -> Fallible<DOMString> {
|
pub fn base64_btoa(input: DOMString) -> Fallible<DOMString> {
|
||||||
// "The btoa() method must throw an InvalidCharacterError exception if
|
// "The btoa() method must throw an InvalidCharacterError exception if
|
||||||
|
@ -425,10 +437,13 @@ impl WindowMethods for Window {
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
stderr.flush().unwrap();
|
stderr.flush().unwrap();
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsershowmodalprompt
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
let event = MozBrowserEvent::ShowModalPrompt("alert".to_owned(), "Alert".to_owned(),
|
self.constellation_chan().0.send(ConstellationMsg::Alert(self.pipeline(), s.to_string(), sender)).unwrap();
|
||||||
String::from(s), "".to_owned());
|
|
||||||
self.Document().trigger_mozbrowser_event(event);
|
let should_display_alert_dialog = receiver.recv().unwrap();
|
||||||
|
if should_display_alert_dialog {
|
||||||
|
display_alert_dialog(&s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-window-close
|
// https://html.spec.whatwg.org/multipage/#dom-window-close
|
||||||
|
|
|
@ -73,6 +73,8 @@ extern crate smallvec;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate style;
|
extern crate style;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||||
|
extern crate tinyfiledialogs;
|
||||||
extern crate unicase;
|
extern crate unicase;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -81,4 +81,6 @@ pub enum ScriptMsg {
|
||||||
SetDocumentState(PipelineId, DocumentState),
|
SetDocumentState(PipelineId, DocumentState),
|
||||||
/// Update the pipeline Url, which can change after redirections.
|
/// Update the pipeline Url, which can change after redirections.
|
||||||
SetFinalUrl(PipelineId, Url),
|
SetFinalUrl(PipelineId, Url),
|
||||||
|
/// Check if an alert dialog box should be presented
|
||||||
|
Alert(PipelineId, String, IpcSender<bool>),
|
||||||
}
|
}
|
||||||
|
|
3
components/servo/Cargo.lock
generated
3
components/servo/Cargo.lock
generated
|
@ -1837,6 +1837,7 @@ dependencies = [
|
||||||
"string_cache 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"string_cache 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"style 0.0.1",
|
"style 0.0.1",
|
||||||
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
|
||||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"util 0.0.1",
|
"util 0.0.1",
|
||||||
|
@ -2210,7 +2211,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyfiledialogs"
|
name = "tinyfiledialogs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/jdm/tinyfiledialogs#2d2285985db1168da4d516000f24842aba46fd94"
|
source = "git+https://github.com/jdm/tinyfiledialogs#686abf781f30b360a4c265964fd3744e2f61cf2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
3
ports/cef/Cargo.lock
generated
3
ports/cef/Cargo.lock
generated
|
@ -1706,6 +1706,7 @@ dependencies = [
|
||||||
"string_cache 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"string_cache 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"style 0.0.1",
|
"style 0.0.1",
|
||||||
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
|
||||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"util 0.0.1",
|
"util 0.0.1",
|
||||||
|
@ -2086,7 +2087,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyfiledialogs"
|
name = "tinyfiledialogs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/jdm/tinyfiledialogs#2d2285985db1168da4d516000f24842aba46fd94"
|
source = "git+https://github.com/jdm/tinyfiledialogs#686abf781f30b360a4c265964fd3744e2f61cf2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
3
ports/gonk/Cargo.lock
generated
3
ports/gonk/Cargo.lock
generated
|
@ -1689,6 +1689,7 @@ dependencies = [
|
||||||
"string_cache 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"string_cache 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"style 0.0.1",
|
"style 0.0.1",
|
||||||
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
|
||||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"util 0.0.1",
|
"util 0.0.1",
|
||||||
|
@ -2067,7 +2068,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyfiledialogs"
|
name = "tinyfiledialogs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/jdm/tinyfiledialogs#2d2285985db1168da4d516000f24842aba46fd94"
|
source = "git+https://github.com/jdm/tinyfiledialogs#686abf781f30b360a4c265964fd3744e2f61cf2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
|
@ -16,4 +16,16 @@
|
||||||
}));
|
}));
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async_test(function(t) {
|
||||||
|
var iframe = document.createElement("iframe");
|
||||||
|
iframe.mozbrowser = "true";
|
||||||
|
iframe.src = "mozbrowsershowmodalprompt_event_nested_iframe.html";
|
||||||
|
iframe.addEventListener("mozbrowsershowmodalprompt", t.step_func(e => {
|
||||||
|
assert_equals(e.detail.promptType, "alert");
|
||||||
|
assert_equals(e.detail.message, "my alert message");
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
}, "mozbrowsershowmodalprompt event from nested iframes triggering an alert");
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<iframe src="mozbrowsershowmodalprompt_event_iframe.html" />
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue