diff --git a/.changes/js-prompt.md b/.changes/js-prompt.md new file mode 100644 index 000000000..b592d067e --- /dev/null +++ b/.changes/js-prompt.md @@ -0,0 +1,6 @@ +--- +"tauri": patch +--- + +Use native dialog on `window.alert` and `window.confirm`. +Since every communication with the webview is asynchronous, the `window.confirm` returns a Promise resolving to a boolean value. diff --git a/cli/tauri.js/templates/tauri.js b/cli/tauri.js/templates/tauri.js index 842d6c359..e3efca6c1 100644 --- a/cli/tauri.js/templates/tauri.js +++ b/cli/tauri.js/templates/tauri.js @@ -247,4 +247,18 @@ if (!String.prototype.startsWith) { setNotificationPermission(response ? 'granted' : 'denied') } }) + + window.alert = function (message) { + window.__TAURI_INVOKE_HANDLER__({ + cmd: 'messageDialog', + message: message + }) + } + + window.confirm = function (message) { + return window.__TAURI__.promisified({ + cmd: 'askDialog', + message: message + }) + } })() diff --git a/tauri-api/src/dialog.rs b/tauri-api/src/dialog.rs index 9adcc4900..00d5169b4 100644 --- a/tauri-api/src/dialog.rs +++ b/tauri-api/src/dialog.rs @@ -34,6 +34,16 @@ pub fn ask(message: impl AsRef, title: impl AsRef) -> DialogSelection .show() } +/// Displays a message dialog. +pub fn message(message: impl AsRef, title: impl AsRef) { + DialogBuilder::new() + .message(message.as_ref()) + .title(title.as_ref()) + .style(DialogStyle::Info) + .build() + .show(); +} + /// Open single select file dialog pub fn select( filter_list: Option>, diff --git a/tauri/src/endpoints.rs b/tauri/src/endpoints.rs index 52b65a91a..03a80e025 100644 --- a/tauri/src/endpoints.rs +++ b/tauri/src/endpoints.rs @@ -7,7 +7,6 @@ mod salt; mod asset; #[cfg(open)] mod browser; -#[cfg(any(open_dialog, save_dialog))] mod dialog; #[cfg(event)] mod event; @@ -208,6 +207,37 @@ pub(crate) fn handle(webview: &mut Webview, arg: &str) -> crate::Result<()> { #[cfg(not(save_dialog))] throw_whitelist_error(webview, "saveDialog"); } + MessageDialog { message } => { + let exe = std::env::current_exe()?; + let exe_dir = exe.parent().expect("failed to get exe directory"); + let app_name = exe + .file_name() + .expect("failed to get exe filename") + .to_string_lossy(); + dialog::message(app_name.to_string(), message); + } + AskDialog { + title, + message, + callback, + error, + } => { + let exe = std::env::current_exe()?; + dialog::ask( + webview, + title.unwrap_or_else(|| { + let exe_dir = exe.parent().expect("failed to get exe directory"); + exe + .file_name() + .expect("failed to get exe filename") + .to_string_lossy() + .to_string() + }), + message, + callback, + error, + )?; + } HttpRequest { options, callback, diff --git a/tauri/src/endpoints/cmd.rs b/tauri/src/endpoints/cmd.rs index 551f70735..78cf9f857 100644 --- a/tauri/src/endpoints/cmd.rs +++ b/tauri/src/endpoints/cmd.rs @@ -140,7 +140,9 @@ pub enum Cmd { error: String, }, /// The set webview title API. - SetTitle { title: String }, + SetTitle { + title: String, + }, /// The execute script API. Execute { command: String, @@ -149,7 +151,9 @@ pub enum Cmd { error: String, }, /// The open URL in browser API - Open { uri: String }, + Open { + uri: String, + }, ValidateSalt { salt: String, callback: String, @@ -178,6 +182,15 @@ pub enum Cmd { callback: String, error: String, }, + MessageDialog { + message: String, + }, + AskDialog { + title: Option, + message: String, + callback: String, + error: String, + }, /// The HTTP request API. HttpRequest { options: Box, @@ -194,7 +207,10 @@ pub enum Cmd { error: String, }, /// The get CLI matches API. - CliMatches { callback: String, error: String }, + CliMatches { + callback: String, + error: String, + }, /// The show notification API. Notification { options: NotificationOptions, @@ -202,7 +218,13 @@ pub enum Cmd { error: String, }, /// The request notification permission API. - RequestNotificationPermission { callback: String, error: String }, + RequestNotificationPermission { + callback: String, + error: String, + }, /// The notification permission check API. - IsNotificationPermissionGranted { callback: String, error: String }, + IsNotificationPermissionGranted { + callback: String, + error: String, + }, } diff --git a/tauri/src/endpoints/dialog.rs b/tauri/src/endpoints/dialog.rs index d14764ec9..b22301dc9 100644 --- a/tauri/src/endpoints/dialog.rs +++ b/tauri/src/endpoints/dialog.rs @@ -1,9 +1,13 @@ use super::cmd::{OpenDialogOptions, SaveDialogOptions}; -use crate::api::dialog::{pick_folder, save_file, select, select_multiple, Response}; +use crate::api::dialog::{ + ask as ask_dialog, message as message_dialog, pick_folder, save_file, select, select_multiple, + DialogSelection, Response, +}; use serde_json::Value as JsonValue; use webview_rust_sys::Webview; /// maps a dialog response to a JS value to eval +#[cfg(any(open_dialog, save_dialog))] fn map_response(response: Response) -> JsonValue { match response { Response::Okay(path) => path.into(), @@ -54,3 +58,28 @@ pub fn save( )?; Ok(()) } + +/// Shows a message in a dialog. +pub fn message(title: String, message: String) { + message_dialog(message, title); +} + +/// Shows a dialog with a yes/no question. +pub fn ask( + webview: &mut Webview, + title: String, + message: String, + callback: String, + error: String, +) -> crate::Result<()> { + crate::execute_promise_sync( + webview, + move || match ask_dialog(message, title) { + DialogSelection::Yes => Ok(true), + _ => Ok(false), + }, + callback, + error, + )?; + Ok(()) +}