Skip to content

Commit

Permalink
Auto merge of #10840 - ConnorGBrewster:window_alert, r=jdm
Browse files Browse the repository at this point in the history
Implement alert dialogs

fix #10812

Implements alert dialogs using tinyfiledialogs

r? @jdm

<!-- 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/10840)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed May 4, 2016
2 parents 944a8dc + dc85be4 commit b4f573d
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 19 deletions.
83 changes: 72 additions & 11 deletions components/compositing/constellation.rs
Expand Up @@ -805,6 +805,10 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
debug!("constellation got SetDocumentState message");
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
Expand Down Expand Up @@ -1080,6 +1084,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) {
self.load_url(source_id, load_data);
}
Expand Down Expand Up @@ -1956,6 +1998,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
// 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) {
Expand Down Expand Up @@ -1987,19 +2052,15 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
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 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 => return warn!("Mozbrowsererror via closed pipeline {:?}.", ancestor_info.0),
};
}
let ancestor_info = self.get_root_pipeline_and_containing_parent(&pipeline_id);

if let Some(ancestor_info) = ancestor_info {
match self.pipelines.get(&ancestor_info.0) {
Some(ancestor) => {
let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, Some(reason), Some(backtrace));
ancestor.trigger_mozbrowser_event(ancestor_info.1, event);
}
},
None => return warn!("Mozbrowsererror via closed pipeline {:?}.", ancestor_info.0),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions components/script/Cargo.toml
Expand Up @@ -13,6 +13,9 @@ path = "lib.rs"
[features]
debugmozjs = ['js/debugmozjs']

[target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies]
tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"}

[dependencies]
plugins = {path = "../plugins"}
util = {path = "../util"}
Expand Down
25 changes: 20 additions & 5 deletions components/script/dom/window.rs
Expand Up @@ -60,7 +60,7 @@ use script_thread::SendableMainThreadScriptChan;
use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper};
use script_traits::{ConstellationControlMsg, UntrustedNodeAddress};
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::borrow::ToOwned;
use std::cell::Cell;
Expand All @@ -86,6 +86,8 @@ use task_source::networking::NetworkingTaskSource;
use task_source::user_interaction::UserInteractionTaskSource;
use time;
use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback};
#[cfg(any(target_os = "macos", target_os = "linux"))]
use tinyfiledialogs::{self, MessageBoxIcon};
use url::Url;
use util::geometry::{self, MAX_RECT};
use util::str::{DOMString, HTML_SPACE_CHARACTERS};
Expand Down Expand Up @@ -352,6 +354,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
pub fn base64_btoa(input: DOMString) -> Fallible<DOMString> {
// "The btoa() method must throw an InvalidCharacterError exception if
Expand Down Expand Up @@ -434,10 +446,13 @@ impl WindowMethods for Window {
stdout.flush().unwrap();
stderr.flush().unwrap();

// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsershowmodalprompt
let event = MozBrowserEvent::ShowModalPrompt("alert".to_owned(), "Alert".to_owned(),
String::from(s), "".to_owned());
self.Document().trigger_mozbrowser_event(event);
let (sender, receiver) = ipc::channel().unwrap();
self.constellation_chan().0.send(ConstellationMsg::Alert(self.pipeline(), s.to_string(), sender)).unwrap();

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
Expand Down
2 changes: 2 additions & 0 deletions components/script/lib.rs
Expand Up @@ -73,6 +73,8 @@ extern crate smallvec;
#[macro_use]
extern crate style;
extern crate time;
#[cfg(any(target_os = "macos", target_os = "linux"))]
extern crate tinyfiledialogs;
extern crate unicase;
extern crate url;
#[macro_use]
Expand Down
2 changes: 2 additions & 0 deletions components/script_traits/script_msg.rs
Expand Up @@ -81,4 +81,6 @@ pub enum ScriptMsg {
SetDocumentState(PipelineId, DocumentState),
/// Update the pipeline Url, which can change after redirections.
SetFinalUrl(PipelineId, Url),
/// Check if an alert dialog box should be presented
Alert(PipelineId, String, IpcSender<bool>),
}
3 changes: 2 additions & 1 deletion components/servo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion ports/cef/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion ports/gonk/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -16,4 +16,16 @@
}));
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>
@@ -0,0 +1,5 @@
<html>
<body>
<iframe src="mozbrowsershowmodalprompt_event_iframe.html" />
</body>
</html>

0 comments on commit b4f573d

Please sign in to comment.