mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
libservo: Clean up interfaces for alert()/confirm()/prompt() (#35579)
Signed-off-by: Delan Azabani <dazabani@igalia.com>
This commit is contained in:
parent
03e953e22c
commit
276f6a3ba7
16 changed files with 278 additions and 222 deletions
|
@ -201,7 +201,7 @@ mod from_script {
|
|||
Self::ChangePageTitle(..) => target_variant!("ChangePageTitle"),
|
||||
Self::MoveTo(..) => target_variant!("MoveTo"),
|
||||
Self::ResizeTo(..) => target_variant!("ResizeTo"),
|
||||
Self::Prompt(..) => target_variant!("Prompt"),
|
||||
Self::ShowSimpleDialog(..) => target_variant!("ShowSimpleDialog"),
|
||||
Self::RequestAuthentication(..) => target_variant!("RequestAuthentication"),
|
||||
Self::ShowContextMenu(..) => target_variant!("ShowContextMenu"),
|
||||
Self::AllowNavigationRequest(..) => target_variant!("AllowNavigationRequest"),
|
||||
|
|
|
@ -26,8 +26,8 @@ use cssparser::{Parser, ParserInput, SourceLocation};
|
|||
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::{
|
||||
EmbedderMsg, PromptDefinition, PromptOrigin, PromptResult, Theme, WebDriverJSError,
|
||||
WebDriverJSResult,
|
||||
AlertResponse, ConfirmResponse, EmbedderMsg, PromptResponse, SimpleDialog, Theme,
|
||||
WebDriverJSError, WebDriverJSResult,
|
||||
};
|
||||
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
|
||||
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
|
||||
|
@ -736,30 +736,43 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
|
|||
}
|
||||
let (sender, receiver) =
|
||||
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
let prompt = PromptDefinition::Alert(s.to_string(), sender);
|
||||
let msg = EmbedderMsg::Prompt(self.webview_id(), prompt, PromptOrigin::Untrusted);
|
||||
let dialog = SimpleDialog::Alert {
|
||||
message: s.to_string(),
|
||||
response_sender: sender,
|
||||
};
|
||||
let msg = EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog);
|
||||
self.send_to_embedder(msg);
|
||||
receiver.recv().unwrap();
|
||||
let AlertResponse::Ok = receiver.recv().unwrap();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-confirm
|
||||
fn Confirm(&self, s: DOMString) -> bool {
|
||||
let (sender, receiver) =
|
||||
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
let prompt = PromptDefinition::OkCancel(s.to_string(), sender);
|
||||
let msg = EmbedderMsg::Prompt(self.webview_id(), prompt, PromptOrigin::Untrusted);
|
||||
let dialog = SimpleDialog::Confirm {
|
||||
message: s.to_string(),
|
||||
response_sender: sender,
|
||||
};
|
||||
let msg = EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog);
|
||||
self.send_to_embedder(msg);
|
||||
receiver.recv().unwrap() == PromptResult::Primary
|
||||
receiver.recv().unwrap() == ConfirmResponse::Ok
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-prompt
|
||||
fn Prompt(&self, message: DOMString, default: DOMString) -> Option<DOMString> {
|
||||
let (sender, receiver) =
|
||||
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
let prompt = PromptDefinition::Input(message.to_string(), default.to_string(), sender);
|
||||
let msg = EmbedderMsg::Prompt(self.webview_id(), prompt, PromptOrigin::Untrusted);
|
||||
let dialog = SimpleDialog::Prompt {
|
||||
message: message.to_string(),
|
||||
default: default.to_string(),
|
||||
response_sender: sender,
|
||||
};
|
||||
let msg = EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog);
|
||||
self.send_to_embedder(msg);
|
||||
receiver.recv().unwrap().map(|s| s.into())
|
||||
match receiver.recv().unwrap() {
|
||||
PromptResponse::Ok(input) => Some(input.into()),
|
||||
PromptResponse::Cancel => None,
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-window-stop
|
||||
|
|
|
@ -708,11 +708,11 @@ impl Servo {
|
|||
webview.delegate().request_resize_to(webview, size);
|
||||
}
|
||||
},
|
||||
EmbedderMsg::Prompt(webview_id, prompt_definition, prompt_origin) => {
|
||||
EmbedderMsg::ShowSimpleDialog(webview_id, prompt_definition) => {
|
||||
if let Some(webview) = self.get_webview_handle(webview_id) {
|
||||
webview
|
||||
.delegate()
|
||||
.show_prompt(webview, prompt_definition, prompt_origin);
|
||||
.show_simple_dialog(webview, prompt_definition);
|
||||
}
|
||||
},
|
||||
EmbedderMsg::ShowContextMenu(webview_id, ipc_sender, title, items) => {
|
||||
|
|
|
@ -9,8 +9,7 @@ use compositing_traits::ConstellationMsg;
|
|||
use embedder_traits::{
|
||||
AllowOrDeny, AuthenticationResponse, ContextMenuResult, Cursor, FilterPattern,
|
||||
GamepadHapticEffectType, InputMethodType, LoadStatus, MediaSessionEvent, PermissionFeature,
|
||||
PromptDefinition, PromptOrigin, WebResourceRequest, WebResourceResponse,
|
||||
WebResourceResponseMsg,
|
||||
SimpleDialog, WebResourceRequest, WebResourceResponse, WebResourceResponseMsg,
|
||||
};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use keyboard_types::KeyboardEvent;
|
||||
|
@ -338,17 +337,25 @@ pub trait WebViewDelegate {
|
|||
) {
|
||||
}
|
||||
|
||||
/// Show dialog to user
|
||||
/// Show the user a [simple dialog](https://html.spec.whatwg.org/multipage/#simple-dialogs) (`alert()`, `confirm()`,
|
||||
/// or `prompt()`). Since their messages are controlled by web content, they should be presented to the user in a
|
||||
/// way that makes them impossible to mistake for browser UI.
|
||||
/// TODO: This API needs to be reworked to match the new model of how responses are sent.
|
||||
fn show_prompt(&self, _webview: WebView, prompt: PromptDefinition, _: PromptOrigin) {
|
||||
let _ = match prompt {
|
||||
PromptDefinition::Alert(_, response_sender) => response_sender.send(()),
|
||||
PromptDefinition::OkCancel(_, response_sender) => {
|
||||
response_sender.send(embedder_traits::PromptResult::Dismissed)
|
||||
},
|
||||
PromptDefinition::Input(_, _, response_sender) => response_sender.send(None),
|
||||
fn show_simple_dialog(&self, _webview: WebView, dialog: SimpleDialog) {
|
||||
// Return the DOM-specified default value for when we **cannot show simple dialogs**.
|
||||
let _ = match dialog {
|
||||
SimpleDialog::Alert {
|
||||
response_sender, ..
|
||||
} => response_sender.send(Default::default()),
|
||||
SimpleDialog::Confirm {
|
||||
response_sender, ..
|
||||
} => response_sender.send(Default::default()),
|
||||
SimpleDialog::Prompt {
|
||||
response_sender, ..
|
||||
} => response_sender.send(Default::default()),
|
||||
};
|
||||
}
|
||||
|
||||
/// Show a context menu to the user
|
||||
fn show_context_menu(
|
||||
&self,
|
||||
|
|
|
@ -123,14 +123,30 @@ pub enum ContextMenuResult {
|
|||
Selected(usize),
|
||||
}
|
||||
|
||||
/// [Simple dialogs](https://html.spec.whatwg.org/multipage/#simple-dialogs) are synchronous dialogs
|
||||
/// that can be opened by web content. Since their messages are controlled by web content, they
|
||||
/// should be presented to the user in a way that makes them impossible to mistake for browser UI.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum PromptDefinition {
|
||||
/// Show a message.
|
||||
Alert(String, IpcSender<()>),
|
||||
/// Ask a Ok/Cancel question.
|
||||
OkCancel(String, IpcSender<PromptResult>),
|
||||
/// Ask the user to enter text.
|
||||
Input(String, String, IpcSender<Option<String>>),
|
||||
pub enum SimpleDialog {
|
||||
/// [`alert()`](https://html.spec.whatwg.org/multipage/#dom-alert).
|
||||
/// TODO: Include details about the document origin.
|
||||
Alert {
|
||||
message: String,
|
||||
response_sender: IpcSender<AlertResponse>,
|
||||
},
|
||||
/// [`confirm()`](https://html.spec.whatwg.org/multipage/#dom-confirm).
|
||||
/// TODO: Include details about the document origin.
|
||||
Confirm {
|
||||
message: String,
|
||||
response_sender: IpcSender<ConfirmResponse>,
|
||||
},
|
||||
/// [`prompt()`](https://html.spec.whatwg.org/multipage/#dom-prompt).
|
||||
/// TODO: Include details about the document origin.
|
||||
Prompt {
|
||||
message: String,
|
||||
default: String,
|
||||
response_sender: IpcSender<PromptResponse>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
|
@ -142,22 +158,52 @@ pub struct AuthenticationResponse {
|
|||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Serialize)]
|
||||
pub enum PromptOrigin {
|
||||
/// Prompt is triggered from content (window.prompt/alert/confirm/…).
|
||||
/// Prompt message is unknown.
|
||||
Untrusted,
|
||||
/// Prompt is triggered from Servo (ask for permission, show error,…).
|
||||
Trusted,
|
||||
pub enum AlertResponse {
|
||||
/// The user chose Ok, or the dialog was otherwise dismissed or ignored.
|
||||
Ok,
|
||||
}
|
||||
|
||||
impl Default for AlertResponse {
|
||||
fn default() -> Self {
|
||||
// Per <https://html.spec.whatwg.org/multipage/#dom-alert>,
|
||||
// if we **cannot show simple dialogs**, including cases where the user or user agent decides to ignore
|
||||
// all modal dialogs, we need to return (which represents Ok).
|
||||
Self::Ok
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Serialize)]
|
||||
pub enum PromptResult {
|
||||
/// Prompt was closed by clicking on the primary button (ok/yes)
|
||||
Primary,
|
||||
/// Prompt was closed by clicking on the secondary button (cancel/no)
|
||||
Secondary,
|
||||
/// Prompt was dismissed
|
||||
Dismissed,
|
||||
pub enum ConfirmResponse {
|
||||
/// The user chose Ok.
|
||||
Ok,
|
||||
/// The user chose Cancel, or the dialog was otherwise dismissed or ignored.
|
||||
Cancel,
|
||||
}
|
||||
|
||||
impl Default for ConfirmResponse {
|
||||
fn default() -> Self {
|
||||
// Per <https://html.spec.whatwg.org/multipage/#dom-confirm>,
|
||||
// if we **cannot show simple dialogs**, including cases where the user or user agent decides to ignore
|
||||
// all modal dialogs, we need to return false (which represents Cancel), not true (Ok).
|
||||
Self::Cancel
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Serialize)]
|
||||
pub enum PromptResponse {
|
||||
/// The user chose Ok, with the given input.
|
||||
Ok(String),
|
||||
/// The user chose Cancel, or the dialog was otherwise dismissed or ignored.
|
||||
Cancel,
|
||||
}
|
||||
|
||||
impl Default for PromptResponse {
|
||||
fn default() -> Self {
|
||||
// Per <https://html.spec.whatwg.org/multipage/#dom-prompt>,
|
||||
// if we **cannot show simple dialogs**, including cases where the user or user agent decides to ignore
|
||||
// all modal dialogs, we need to return null (which represents Cancel), not the default input.
|
||||
Self::Cancel
|
||||
}
|
||||
}
|
||||
|
||||
/// A response to a request to allow or deny an action.
|
||||
|
@ -177,8 +223,10 @@ pub enum EmbedderMsg {
|
|||
MoveTo(WebViewId, DeviceIntPoint),
|
||||
/// Resize the window to size
|
||||
ResizeTo(WebViewId, DeviceIntSize),
|
||||
/// Show dialog to user
|
||||
Prompt(WebViewId, PromptDefinition, PromptOrigin),
|
||||
/// Show the user a [simple dialog](https://html.spec.whatwg.org/multipage/#simple-dialogs) (`alert()`, `confirm()`,
|
||||
/// or `prompt()`). Since their messages are controlled by web content, they should be presented to the user in a
|
||||
/// way that makes them impossible to mistake for browser UI.
|
||||
ShowSimpleDialog(WebViewId, SimpleDialog),
|
||||
/// Request authentication for a load or navigation from the embedder.
|
||||
RequestAuthentication(
|
||||
WebViewId,
|
||||
|
@ -280,7 +328,7 @@ impl Debug for EmbedderMsg {
|
|||
EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
|
||||
EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"),
|
||||
EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
|
||||
EmbedderMsg::Prompt(..) => write!(f, "Prompt"),
|
||||
EmbedderMsg::ShowSimpleDialog(..) => write!(f, "ShowSimpleDialog"),
|
||||
EmbedderMsg::RequestAuthentication(..) => write!(f, "RequestAuthentication"),
|
||||
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
|
||||
EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"),
|
||||
|
|
|
@ -18,8 +18,8 @@ use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
|||
use servo::webrender_api::ScrollLocation;
|
||||
use servo::{
|
||||
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, GamepadHapticEffectType, LoadStatus,
|
||||
PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, Servo, ServoDelegate,
|
||||
ServoError, TouchEventType, WebView, WebViewDelegate,
|
||||
PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog, TouchEventType, WebView,
|
||||
WebViewDelegate,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
|
@ -415,36 +415,25 @@ impl WebViewDelegate for RunningAppState {
|
|||
self.inner().window.request_resize(&webview, new_size);
|
||||
}
|
||||
|
||||
fn show_prompt(
|
||||
&self,
|
||||
webview: servo::WebView,
|
||||
definition: PromptDefinition,
|
||||
_origin: PromptOrigin,
|
||||
) {
|
||||
fn show_simple_dialog(&self, webview: servo::WebView, dialog: SimpleDialog) {
|
||||
if self.servoshell_preferences.headless {
|
||||
let _ = match definition {
|
||||
PromptDefinition::Alert(_message, sender) => sender.send(()),
|
||||
PromptDefinition::OkCancel(_message, sender) => sender.send(PromptResult::Primary),
|
||||
PromptDefinition::Input(_message, default, sender) => {
|
||||
sender.send(Some(default.to_owned()))
|
||||
},
|
||||
// TODO: Avoid copying this from the default trait impl?
|
||||
// Return the DOM-specified default value for when we **cannot show simple dialogs**.
|
||||
let _ = match dialog {
|
||||
SimpleDialog::Alert {
|
||||
response_sender, ..
|
||||
} => response_sender.send(Default::default()),
|
||||
SimpleDialog::Confirm {
|
||||
response_sender, ..
|
||||
} => response_sender.send(Default::default()),
|
||||
SimpleDialog::Prompt {
|
||||
response_sender, ..
|
||||
} => response_sender.send(Default::default()),
|
||||
};
|
||||
return;
|
||||
}
|
||||
match definition {
|
||||
PromptDefinition::Alert(message, sender) => {
|
||||
let alert_dialog = Dialog::new_alert_dialog(message, sender);
|
||||
self.add_dialog(webview, alert_dialog);
|
||||
},
|
||||
PromptDefinition::OkCancel(message, sender) => {
|
||||
let okcancel_dialog = Dialog::new_okcancel_dialog(message, sender);
|
||||
self.add_dialog(webview, okcancel_dialog);
|
||||
},
|
||||
PromptDefinition::Input(message, default, sender) => {
|
||||
let input_dialog = Dialog::new_input_dialog(message, default, sender);
|
||||
self.add_dialog(webview, input_dialog);
|
||||
},
|
||||
}
|
||||
let dialog = Dialog::new_simple_dialog(dialog);
|
||||
self.add_dialog(webview, dialog);
|
||||
}
|
||||
|
||||
fn request_authentication(
|
||||
|
|
|
@ -9,7 +9,10 @@ use egui::Modal;
|
|||
use egui_file_dialog::{DialogState, FileDialog as EguiFileDialog};
|
||||
use log::warn;
|
||||
use servo::ipc_channel::ipc::IpcSender;
|
||||
use servo::{AuthenticationRequest, FilterPattern, PermissionRequest, PromptResult};
|
||||
use servo::{
|
||||
AlertResponse, AuthenticationRequest, ConfirmResponse, FilterPattern, PermissionRequest,
|
||||
PromptResponse, SimpleDialog,
|
||||
};
|
||||
|
||||
pub enum Dialog {
|
||||
File {
|
||||
|
@ -17,19 +20,8 @@ pub enum Dialog {
|
|||
multiple: bool,
|
||||
response_sender: IpcSender<Option<Vec<PathBuf>>>,
|
||||
},
|
||||
Alert {
|
||||
message: String,
|
||||
sender: IpcSender<()>,
|
||||
},
|
||||
OkCancel {
|
||||
message: String,
|
||||
sender: IpcSender<PromptResult>,
|
||||
},
|
||||
Input {
|
||||
message: String,
|
||||
input_text: String,
|
||||
sender: IpcSender<Option<String>>,
|
||||
},
|
||||
#[allow(clippy::enum_variant_names, reason = "spec terminology")]
|
||||
SimpleDialog(SimpleDialog),
|
||||
Authentication {
|
||||
username: String,
|
||||
password: String,
|
||||
|
@ -76,24 +68,8 @@ impl Dialog {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_alert_dialog(message: String, sender: IpcSender<()>) -> Self {
|
||||
Dialog::Alert { message, sender }
|
||||
}
|
||||
|
||||
pub fn new_okcancel_dialog(message: String, sender: IpcSender<PromptResult>) -> Self {
|
||||
Dialog::OkCancel { message, sender }
|
||||
}
|
||||
|
||||
pub fn new_input_dialog(
|
||||
message: String,
|
||||
default: String,
|
||||
sender: IpcSender<Option<String>>,
|
||||
) -> Self {
|
||||
Dialog::Input {
|
||||
message,
|
||||
input_text: default,
|
||||
sender,
|
||||
}
|
||||
pub fn new_simple_dialog(dialog: SimpleDialog) -> Self {
|
||||
Self::SimpleDialog(dialog)
|
||||
}
|
||||
|
||||
pub fn new_authentication_dialog(authentication_request: AuthenticationRequest) -> Self {
|
||||
|
@ -165,9 +141,12 @@ impl Dialog {
|
|||
DialogState::Closed => false,
|
||||
}
|
||||
},
|
||||
Dialog::Alert { message, sender } => {
|
||||
Dialog::SimpleDialog(SimpleDialog::Alert {
|
||||
message,
|
||||
response_sender,
|
||||
}) => {
|
||||
let mut is_open = true;
|
||||
let modal = Modal::new("alert".into());
|
||||
let modal = Modal::new("Alert".into());
|
||||
modal.show(ctx, |ui| {
|
||||
make_dialog_label(message, ui, None);
|
||||
egui::Sides::new().show(
|
||||
|
@ -176,7 +155,7 @@ impl Dialog {
|
|||
|ui| {
|
||||
if ui.button("Close").clicked() {
|
||||
is_open = false;
|
||||
if let Err(e) = sender.send(()) {
|
||||
if let Err(e) = response_sender.send(AlertResponse::Ok) {
|
||||
warn!("Failed to send alert dialog response: {}", e);
|
||||
}
|
||||
}
|
||||
|
@ -185,9 +164,12 @@ impl Dialog {
|
|||
});
|
||||
is_open
|
||||
},
|
||||
Dialog::OkCancel { message, sender } => {
|
||||
Dialog::SimpleDialog(SimpleDialog::Confirm {
|
||||
message,
|
||||
response_sender,
|
||||
}) => {
|
||||
let mut is_open = true;
|
||||
let modal = Modal::new("OkCancel".into());
|
||||
let modal = Modal::new("Confirm".into());
|
||||
modal.show(ctx, |ui| {
|
||||
make_dialog_label(message, ui, None);
|
||||
egui::Sides::new().show(
|
||||
|
@ -196,13 +178,13 @@ impl Dialog {
|
|||
|ui| {
|
||||
if ui.button("Ok").clicked() {
|
||||
is_open = false;
|
||||
if let Err(e) = sender.send(PromptResult::Primary) {
|
||||
if let Err(e) = response_sender.send(ConfirmResponse::Ok) {
|
||||
warn!("Failed to send alert dialog response: {}", e);
|
||||
}
|
||||
}
|
||||
if ui.button("Cancel").clicked() {
|
||||
is_open = false;
|
||||
if let Err(e) = sender.send(PromptResult::Secondary) {
|
||||
if let Err(e) = response_sender.send(ConfirmResponse::Cancel) {
|
||||
warn!("Failed to send alert dialog response: {}", e);
|
||||
}
|
||||
}
|
||||
|
@ -211,27 +193,30 @@ impl Dialog {
|
|||
});
|
||||
is_open
|
||||
},
|
||||
Dialog::Input {
|
||||
Dialog::SimpleDialog(SimpleDialog::Prompt {
|
||||
message,
|
||||
input_text,
|
||||
sender,
|
||||
} => {
|
||||
// The `default` field gets reused as the input buffer.
|
||||
default: input,
|
||||
response_sender,
|
||||
}) => {
|
||||
let mut is_open = true;
|
||||
Modal::new("input".into()).show(ctx, |ui| {
|
||||
make_dialog_label(message, ui, Some(input_text));
|
||||
Modal::new("Prompt".into()).show(ctx, |ui| {
|
||||
make_dialog_label(message, ui, Some(input));
|
||||
egui::Sides::new().show(
|
||||
ui,
|
||||
|_ui| {},
|
||||
|ui| {
|
||||
if ui.button("Ok").clicked() {
|
||||
is_open = false;
|
||||
if let Err(e) = sender.send(Some(input_text.clone())) {
|
||||
if let Err(e) =
|
||||
response_sender.send(PromptResponse::Ok(input.clone()))
|
||||
{
|
||||
warn!("Failed to send input dialog response: {}", e);
|
||||
}
|
||||
}
|
||||
if ui.button("Cancel").clicked() {
|
||||
is_open = false;
|
||||
if let Err(e) = sender.send(None) {
|
||||
if let Err(e) = response_sender.send(PromptResponse::Cancel) {
|
||||
warn!("Failed to send input dialog response: {}", e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,11 @@ use log::{debug, error, info, warn};
|
|||
use raw_window_handle::{
|
||||
AndroidDisplayHandle, AndroidNdkWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||
};
|
||||
use servo::{LoadStatus, MediaSessionActionType};
|
||||
use servo::{
|
||||
AlertResponse, LoadStatus, MediaSessionActionType, PermissionRequest, SimpleDialog, WebView,
|
||||
};
|
||||
use simpleservo::{
|
||||
DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState,
|
||||
PromptResult, APP,
|
||||
DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState, APP,
|
||||
};
|
||||
|
||||
use super::app_state::{Coordinates, RunningAppState};
|
||||
|
@ -461,11 +462,8 @@ impl HostCallbacks {
|
|||
let jvm = env.get_java_vm().unwrap();
|
||||
HostCallbacks { callbacks, jvm }
|
||||
}
|
||||
}
|
||||
|
||||
impl HostTrait for HostCallbacks {
|
||||
fn prompt_alert(&self, message: String, _trusted: bool) {
|
||||
debug!("prompt_alert");
|
||||
fn show_alert(&self, message: String) {
|
||||
let mut env = self.jvm.get_env().unwrap();
|
||||
let Ok(string) = new_string_as_jvalue(&mut env, &message) else {
|
||||
return;
|
||||
|
@ -478,20 +476,41 @@ impl HostTrait for HostCallbacks {
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_ok_cancel(&self, message: String, _trusted: bool) -> PromptResult {
|
||||
warn!("Prompt not implemented. Cancelled. {}", message);
|
||||
PromptResult::Secondary
|
||||
impl HostTrait for HostCallbacks {
|
||||
fn request_permission(&self, _webview: WebView, request: PermissionRequest) {
|
||||
warn!("Permissions prompt not implemented. Denied.");
|
||||
request.deny();
|
||||
}
|
||||
|
||||
fn prompt_yes_no(&self, message: String, _trusted: bool) -> PromptResult {
|
||||
warn!("Prompt not implemented. Cancelled. {}", message);
|
||||
PromptResult::Secondary
|
||||
}
|
||||
|
||||
fn prompt_input(&self, message: String, default: String, _trusted: bool) -> Option<String> {
|
||||
warn!("Input prompt not implemented. {}", message);
|
||||
Some(default)
|
||||
fn show_simple_dialog(&self, _webview: WebView, dialog: SimpleDialog) {
|
||||
let _ = match dialog {
|
||||
SimpleDialog::Alert {
|
||||
message,
|
||||
response_sender,
|
||||
} => {
|
||||
debug!("SimpleDialog::Alert");
|
||||
// TODO: Indicate that this message is untrusted, and what origin it came from.
|
||||
self.show_alert(message);
|
||||
response_sender.send(AlertResponse::Ok)
|
||||
},
|
||||
SimpleDialog::Confirm {
|
||||
message,
|
||||
response_sender,
|
||||
} => {
|
||||
warn!("Confirm dialog not implemented. Cancelled. {}", message);
|
||||
response_sender.send(Default::default())
|
||||
},
|
||||
SimpleDialog::Prompt {
|
||||
message,
|
||||
response_sender,
|
||||
..
|
||||
} => {
|
||||
warn!("Prompt dialog not implemented. Cancelled. {}", message);
|
||||
response_sender.send(Default::default())
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn notify_load_status_changed(&self, load_status: LoadStatus) {
|
||||
|
|
|
@ -14,7 +14,7 @@ pub use servo::webrender_api::units::DeviceIntRect;
|
|||
/// and that perform_updates need to be called
|
||||
pub use servo::EventLoopWaker;
|
||||
use servo::{self, resources, Servo};
|
||||
pub use servo::{InputMethodType, MediaSessionPlaybackState, PromptResult, WindowRenderingContext};
|
||||
pub use servo::{InputMethodType, MediaSessionPlaybackState, WindowRenderingContext};
|
||||
|
||||
use crate::egl::android::resources::ResourceReaderInstance;
|
||||
use crate::egl::app_state::{
|
||||
|
|
|
@ -22,9 +22,9 @@ use servo::{
|
|||
AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, ImeEvent, InputEvent,
|
||||
InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType,
|
||||
MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent,
|
||||
NavigationRequest, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult,
|
||||
RenderingContext, Servo, ServoDelegate, ServoError, TouchEvent, TouchEventType, TouchId,
|
||||
WebView, WebViewDelegate, WindowRenderingContext,
|
||||
NavigationRequest, PermissionRequest, RenderingContext, Servo, ServoDelegate, ServoError,
|
||||
SimpleDialog, TouchEvent, TouchEventType, TouchId, WebView, WebViewDelegate,
|
||||
WindowRenderingContext,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
|
@ -198,15 +198,10 @@ impl WebViewDelegate for RunningAppState {
|
|||
Some(new_webview)
|
||||
}
|
||||
|
||||
fn request_permission(&self, _webview: WebView, request: PermissionRequest) {
|
||||
let message = format!(
|
||||
"Do you want to grant permission for {:?}?",
|
||||
request.feature()
|
||||
);
|
||||
let result = match self.callbacks.host_callbacks.prompt_yes_no(message, true) {
|
||||
PromptResult::Primary => request.allow(),
|
||||
PromptResult::Secondary | PromptResult::Dismissed => request.deny(),
|
||||
};
|
||||
fn request_permission(&self, webview: WebView, request: PermissionRequest) {
|
||||
self.callbacks
|
||||
.host_callbacks
|
||||
.request_permission(webview, request);
|
||||
}
|
||||
|
||||
fn request_resize_to(&self, _webview: WebView, size: DeviceIntSize) {
|
||||
|
@ -231,21 +226,10 @@ impl WebViewDelegate for RunningAppState {
|
|||
}
|
||||
}
|
||||
|
||||
fn show_prompt(&self, _webview: WebView, prompt: PromptDefinition, origin: PromptOrigin) {
|
||||
let cb = &self.callbacks.host_callbacks;
|
||||
let trusted = origin == PromptOrigin::Trusted;
|
||||
let _ = match prompt {
|
||||
PromptDefinition::Alert(message, response_sender) => {
|
||||
cb.prompt_alert(message, trusted);
|
||||
response_sender.send(())
|
||||
},
|
||||
PromptDefinition::OkCancel(message, response_sender) => {
|
||||
response_sender.send(cb.prompt_ok_cancel(message, trusted))
|
||||
},
|
||||
PromptDefinition::Input(message, default, response_sender) => {
|
||||
response_sender.send(cb.prompt_input(message, default, trusted))
|
||||
},
|
||||
};
|
||||
fn show_simple_dialog(&self, webview: WebView, dialog: SimpleDialog) {
|
||||
self.callbacks
|
||||
.host_callbacks
|
||||
.show_simple_dialog(webview, dialog);
|
||||
}
|
||||
|
||||
fn show_ime(
|
||||
|
|
|
@ -3,18 +3,22 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use servo::webrender_api::units::DeviceIntRect;
|
||||
use servo::{InputMethodType, LoadStatus, MediaSessionPlaybackState, PromptResult};
|
||||
use servo::{
|
||||
InputMethodType, LoadStatus, MediaSessionPlaybackState, PermissionRequest, SimpleDialog,
|
||||
WebView,
|
||||
};
|
||||
|
||||
/// Callbacks. Implemented by embedder. Called by Servo.
|
||||
/// Callbacks implemented by embedder. Called by our RunningAppState, generally on behalf of Servo.
|
||||
pub trait HostTrait {
|
||||
/// Show alert.
|
||||
fn prompt_alert(&self, msg: String, trusted: bool);
|
||||
/// Ask Yes/No question.
|
||||
fn prompt_yes_no(&self, msg: String, trusted: bool) -> PromptResult;
|
||||
/// Ask Ok/Cancel question.
|
||||
fn prompt_ok_cancel(&self, msg: String, trusted: bool) -> PromptResult;
|
||||
/// Ask for string
|
||||
fn prompt_input(&self, msg: String, default: String, trusted: bool) -> Option<String>;
|
||||
/// Content in a [`WebView`] is requesting permission to access a feature requiring
|
||||
/// permission from the user. The embedder should allow or deny the request, either by
|
||||
/// reading a cached value or querying the user for permission via the user interface.
|
||||
fn request_permission(&self, _webview: WebView, _: PermissionRequest);
|
||||
/// Show the user a [simple dialog](https://html.spec.whatwg.org/multipage/#simple-dialogs) (`alert()`, `confirm()`,
|
||||
/// or `prompt()`). Since their messages are controlled by web content, they should be presented to the user in a
|
||||
/// way that makes them impossible to mistake for browser UI.
|
||||
/// TODO: This API needs to be reworked to match the new model of how responses are sent.
|
||||
fn show_simple_dialog(&self, _webview: WebView, dialog: SimpleDialog);
|
||||
/// Show context menu
|
||||
fn show_context_menu(&self, title: Option<String>, items: Vec<String>);
|
||||
/// Notify that the load status of the page has changed.
|
||||
|
|
|
@ -21,7 +21,10 @@ use napi_ohos::{Env, JsObject, JsString, NapiRaw};
|
|||
use ohos_ime::{AttachOptions, Ime, ImeProxy, RawTextEditorProxy};
|
||||
use ohos_ime_sys::types::InputMethod_EnterKeyType;
|
||||
use servo::style::Zero;
|
||||
use servo::{InputMethodType, LoadStatus, MediaSessionPlaybackState, PromptResult};
|
||||
use servo::{
|
||||
AlertResponse, InputMethodType, LoadStatus, MediaSessionPlaybackState, PermissionRequest,
|
||||
SimpleDialog, WebView,
|
||||
};
|
||||
use simpleservo::EventLoopWaker;
|
||||
use xcomponent_sys::{
|
||||
OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_GetKeyEvent,
|
||||
|
@ -671,6 +674,19 @@ impl HostCallbacks {
|
|||
ime_proxy: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_alert(&self, message: String) {
|
||||
match PROMPT_TOAST.get() {
|
||||
Some(prompt_fn) => {
|
||||
let status = prompt_fn.call(message, ThreadsafeFunctionCallMode::NonBlocking);
|
||||
if status != napi_ohos::Status::Ok {
|
||||
// Queue could be full.
|
||||
error!("show_alert failed with {status}");
|
||||
}
|
||||
},
|
||||
None => error!("PROMPT_TOAST not set. Dropping message {message}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ServoIme {
|
||||
|
@ -698,33 +714,38 @@ impl Ime for ServoIme {
|
|||
|
||||
#[allow(unused)]
|
||||
impl HostTrait for HostCallbacks {
|
||||
fn prompt_alert(&self, msg: String, _trusted: bool) {
|
||||
debug!("prompt_alert: {msg}");
|
||||
match PROMPT_TOAST.get() {
|
||||
Some(prompt_fn) => {
|
||||
let status = prompt_fn.call(msg, ThreadsafeFunctionCallMode::NonBlocking);
|
||||
if status != napi_ohos::Status::Ok {
|
||||
// Queue could be full.
|
||||
error!("prompt_alert failed with {status}");
|
||||
}
|
||||
fn request_permission(&self, _webview: WebView, request: PermissionRequest) {
|
||||
warn!("Permissions prompt not implemented. Denied.");
|
||||
request.deny();
|
||||
}
|
||||
|
||||
fn show_simple_dialog(&self, _webview: WebView, dialog: SimpleDialog) {
|
||||
let _ = match dialog {
|
||||
SimpleDialog::Alert {
|
||||
message,
|
||||
response_sender,
|
||||
} => {
|
||||
debug!("SimpleDialog::Alert");
|
||||
// TODO: Indicate that this message is untrusted, and what origin it came from.
|
||||
self.show_alert(message);
|
||||
response_sender.send(AlertResponse::Ok)
|
||||
},
|
||||
None => error!("PROMPT_TOAST not set. Dropping msg {msg}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_yes_no(&self, msg: String, trusted: bool) -> PromptResult {
|
||||
warn!("Prompt not implemented. Cancelled. {}", msg);
|
||||
PromptResult::Secondary
|
||||
}
|
||||
|
||||
fn prompt_ok_cancel(&self, msg: String, trusted: bool) -> PromptResult {
|
||||
warn!("Prompt not implemented. Cancelled. {}", msg);
|
||||
PromptResult::Secondary
|
||||
}
|
||||
|
||||
fn prompt_input(&self, msg: String, default: String, trusted: bool) -> Option<String> {
|
||||
warn!("Input prompt not implemented. Cancelled. {}", msg);
|
||||
Some(default)
|
||||
SimpleDialog::Confirm {
|
||||
message,
|
||||
response_sender,
|
||||
} => {
|
||||
warn!("Confirm dialog not implemented. Cancelled. {}", message);
|
||||
response_sender.send(Default::default())
|
||||
},
|
||||
SimpleDialog::Prompt {
|
||||
message,
|
||||
response_sender,
|
||||
..
|
||||
} => {
|
||||
warn!("Prompt dialog not implemented. Cancelled. {}", message);
|
||||
response_sender.send(Default::default())
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn show_context_menu(&self, title: Option<String>, items: Vec<String>) {
|
||||
|
@ -740,7 +761,7 @@ impl HostTrait for HostCallbacks {
|
|||
if load_status == LoadStatus::Complete {
|
||||
#[cfg(feature = "tracing-hitrace")]
|
||||
let _scope = hitrace::ScopedTrace::start_trace(&c"PageLoadEndedPrompt");
|
||||
self.prompt_alert("Page finished loading!".to_string(), true);
|
||||
self.show_alert("Page finished loading!".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -838,7 +859,7 @@ impl HostTrait for HostCallbacks {
|
|||
if let Some(bt) = backtrace {
|
||||
error!("Backtrace: {bt:?}")
|
||||
}
|
||||
self.prompt_alert("Servo crashed!".to_string(), true);
|
||||
self.prompt_alert(reason, true);
|
||||
self.show_alert("Servo crashed!".to_string());
|
||||
self.show_alert(reason);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[iframe_sandbox_block_modals-2.html]
|
||||
[Frames without `allow-modals` should not be able to open modal dialogs]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[iframe_sandbox_block_modals-3.html]
|
||||
[Frames without `allow-modals` should not be able to open modal dialogs]
|
||||
expected: FAIL
|
|
@ -1,4 +0,0 @@
|
|||
[confirm-different-origin-frame.sub.html]
|
||||
[confirm-different-origin-frame]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[prompt-different-origin-frame.sub.html]
|
||||
[prompt-different-origin-frame]
|
||||
expected: FAIL
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue