Jelajahi Sumber

feat(tauri) make `window.alert` and `window.confirm` available, fix #848 (#854)

Lucas Fernandes Nogueira 5 tahun lalu
induk
melakukan
0245833bb5

+ 6 - 0
.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.

+ 14 - 0
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
+    })
+  }
 })()

+ 10 - 0
tauri-api/src/dialog.rs

@@ -34,6 +34,16 @@ pub fn ask(message: impl AsRef<str>, title: impl AsRef<str>) -> DialogSelection
     .show()
 }
 
+/// Displays a message dialog.
+pub fn message(message: impl AsRef<str>, title: impl AsRef<str>) {
+  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<impl AsRef<str>>,

+ 31 - 1
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,

+ 27 - 5
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<String>,
+    message: String,
+    callback: String,
+    error: String,
+  },
   /// The HTTP request API.
   HttpRequest {
     options: Box<HttpRequestOptions>,
@@ -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,
+  },
 }

+ 30 - 1
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(())
+}