|
@@ -12,40 +12,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> Tau
|
|
Ok(command) => {
|
|
Ok(command) => {
|
|
match command {
|
|
match command {
|
|
Init {} => {
|
|
Init {} => {
|
|
- #[cfg(not(any(feature = "all-api", feature = "event")))]
|
|
|
|
- let event_init = "";
|
|
|
|
- #[cfg(any(feature = "all-api", feature = "event"))]
|
|
|
|
- let event_init = format!(
|
|
|
|
- "
|
|
|
|
- window['{queue}'] = [];
|
|
|
|
- window['{fn}'] = function (payload, salt, ignoreQueue) {{
|
|
|
|
- const listeners = (window['{listeners}'] && window['{listeners}'][payload.type]) || []
|
|
|
|
- if (!ignoreQueue && listeners.length === 0) {{
|
|
|
|
- window['{queue}'].push({{
|
|
|
|
- payload: payload,
|
|
|
|
- salt: salt
|
|
|
|
- }})
|
|
|
|
- }}
|
|
|
|
-
|
|
|
|
- if (listeners.length > 0) {{
|
|
|
|
- window.tauri.promisified({{
|
|
|
|
- cmd: 'validateSalt',
|
|
|
|
- salt: salt
|
|
|
|
- }}).then(function () {{
|
|
|
|
- for (let i = listeners.length - 1; i >= 0; i--) {{
|
|
|
|
- const listener = listeners[i]
|
|
|
|
- if (listener.once)
|
|
|
|
- listeners.splice(i, 1)
|
|
|
|
- listener.handler(payload)
|
|
|
|
- }}
|
|
|
|
- }})
|
|
|
|
- }}
|
|
|
|
- }}
|
|
|
|
- ",
|
|
|
|
- fn = crate::event::emit_function_name(),
|
|
|
|
- listeners = crate::event::event_listeners_object_name(),
|
|
|
|
- queue = crate::event::event_queue_object_name()
|
|
|
|
- );
|
|
|
|
|
|
+ let event_init = init()?;
|
|
webview.eval(&format!(
|
|
webview.eval(&format!(
|
|
r#"{event_init}
|
|
r#"{event_init}
|
|
window.external.invoke('{{"cmd":"__initialized"}}')
|
|
window.external.invoke('{{"cmd":"__initialized"}}')
|
|
@@ -109,11 +76,8 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> Tau
|
|
}
|
|
}
|
|
#[cfg(any(feature = "all-api", feature = "open"))]
|
|
#[cfg(any(feature = "all-api", feature = "open"))]
|
|
Open { uri } => {
|
|
Open { uri } => {
|
|
- crate::spawn(move || {
|
|
|
|
- webbrowser::open(&uri).expect("Failed to open webbrowser with uri");
|
|
|
|
- });
|
|
|
|
|
|
+ open_fn(uri)?;
|
|
}
|
|
}
|
|
-
|
|
|
|
ValidateSalt {
|
|
ValidateSalt {
|
|
salt,
|
|
salt,
|
|
callback,
|
|
callback,
|
|
@@ -127,33 +91,8 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> Tau
|
|
handler,
|
|
handler,
|
|
once,
|
|
once,
|
|
} => {
|
|
} => {
|
|
- webview
|
|
|
|
- .eval(&format!(
|
|
|
|
- "
|
|
|
|
- if (window['{listeners}'] === void 0) {{
|
|
|
|
- window['{listeners}'] = {{}}
|
|
|
|
- }}
|
|
|
|
- if (window['{listeners}']['{evt}'] === void 0) {{
|
|
|
|
- window['{listeners}']['{evt}'] = []
|
|
|
|
- }}
|
|
|
|
- window['{listeners}']['{evt}'].push({{
|
|
|
|
- handler: window['{handler}'],
|
|
|
|
- once: {once_flag}
|
|
|
|
- }});
|
|
|
|
-
|
|
|
|
- for (let i = 0; i < (window['{queue}'] || []).length; i++) {{
|
|
|
|
- const e = window['{queue}'][i];
|
|
|
|
- window['{emit}'](e.payload, e.salt, true)
|
|
|
|
- }}
|
|
|
|
- ",
|
|
|
|
- listeners = crate::event::event_listeners_object_name(),
|
|
|
|
- queue = crate::event::event_queue_object_name(),
|
|
|
|
- emit = crate::event::emit_function_name(),
|
|
|
|
- evt = event,
|
|
|
|
- handler = handler,
|
|
|
|
- once_flag = if once { "true" } else { "false" }
|
|
|
|
- ))
|
|
|
|
- .expect("failed to call webview.eval from listen");
|
|
|
|
|
|
+ let js_string = listen_fn(event, handler, once)?;
|
|
|
|
+ webview.eval(&js_string)?;
|
|
}
|
|
}
|
|
#[cfg(any(feature = "all-api", feature = "event"))]
|
|
#[cfg(any(feature = "all-api", feature = "event"))]
|
|
Emit { event, payload } => {
|
|
Emit { event, payload } => {
|
|
@@ -166,53 +105,191 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> Tau
|
|
callback,
|
|
callback,
|
|
error,
|
|
error,
|
|
} => {
|
|
} => {
|
|
- let handle = webview.handle();
|
|
|
|
- crate::execute_promise(
|
|
|
|
- webview,
|
|
|
|
- move || {
|
|
|
|
- let read_asset = crate::assets::ASSETS.get(&format!(
|
|
|
|
- "{}{}{}",
|
|
|
|
- env!("TAURI_DIST_DIR"),
|
|
|
|
- if asset.starts_with("/") { "" } else { "/" },
|
|
|
|
- asset
|
|
|
|
- ));
|
|
|
|
- if read_asset.is_err() {
|
|
|
|
- return Err(r#""Asset not found""#.to_string());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if asset_type == "image" {
|
|
|
|
- let ext = if asset.ends_with("gif") {
|
|
|
|
- "gif"
|
|
|
|
- } else if asset.ends_with("png") {
|
|
|
|
- "png"
|
|
|
|
- } else {
|
|
|
|
- "jpeg"
|
|
|
|
- };
|
|
|
|
- Ok(format!(
|
|
|
|
- "`data:image/{};base64,{}`",
|
|
|
|
- ext,
|
|
|
|
- base64::encode(&read_asset.expect("Failed to read asset type").into_owned())
|
|
|
|
- ))
|
|
|
|
- } else {
|
|
|
|
- handle
|
|
|
|
- .dispatch(move |_webview| {
|
|
|
|
- _webview.eval(
|
|
|
|
- &std::str::from_utf8(
|
|
|
|
- &read_asset.expect("Failed to read asset type").into_owned(),
|
|
|
|
- )
|
|
|
|
- .expect("failed to convert asset bytes to u8 slice"),
|
|
|
|
- )
|
|
|
|
- })
|
|
|
|
- .map_err(|err| format!("`{}`", err))
|
|
|
|
- .map(|_| r#""Asset loaded successfully""#.to_string())
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- callback,
|
|
|
|
- error,
|
|
|
|
- );
|
|
|
|
|
|
+ load_asset(webview, asset, asset_type, callback, error)?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(true)
|
|
Ok(true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+fn init() -> TauriResult<String> {
|
|
|
|
+ #[cfg(not(any(feature = "all-api", feature = "event")))]
|
|
|
|
+ return Ok(String::from(""));
|
|
|
|
+ #[cfg(any(feature = "all-api", feature = "event"))]
|
|
|
|
+ return Ok(format!(
|
|
|
|
+ "
|
|
|
|
+ window['{queue}'] = [];
|
|
|
|
+ window['{fn}'] = function (payload, salt, ignoreQueue) {{
|
|
|
|
+ const listeners = (window['{listeners}'] && window['{listeners}'][payload.type]) || []
|
|
|
|
+ if (!ignoreQueue && listeners.length === 0) {{
|
|
|
|
+ window['{queue}'].push({{
|
|
|
|
+ payload: payload,
|
|
|
|
+ salt: salt
|
|
|
|
+ }})
|
|
|
|
+ }}
|
|
|
|
+
|
|
|
|
+ if (listeners.length > 0) {{
|
|
|
|
+ window.tauri.promisified({{
|
|
|
|
+ cmd: 'validateSalt',
|
|
|
|
+ salt: salt
|
|
|
|
+ }}).then(function () {{
|
|
|
|
+ for (let i = listeners.length - 1; i >= 0; i--) {{
|
|
|
|
+ const listener = listeners[i]
|
|
|
|
+ if (listener.once)
|
|
|
|
+ listeners.splice(i, 1)
|
|
|
|
+ listener.handler(payload)
|
|
|
|
+ }}
|
|
|
|
+ }})
|
|
|
|
+ }}
|
|
|
|
+ }}
|
|
|
|
+ ",
|
|
|
|
+ fn = crate::event::emit_function_name(),
|
|
|
|
+ queue = crate::event::event_listeners_object_name(),
|
|
|
|
+ listeners = crate::event::event_queue_object_name(),
|
|
|
|
+ ));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(any(feature = "all-api", feature = "open"))]
|
|
|
|
+fn open_fn(uri: String) -> TauriResult<()> {
|
|
|
|
+ crate::spawn(move || {
|
|
|
|
+ #[cfg(test)]
|
|
|
|
+ assert!(uri.contains("http://"));
|
|
|
|
+
|
|
|
|
+ #[cfg(not(test))]
|
|
|
|
+ webbrowser::open(&uri).expect("Failed to open webbrowser with uri");
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(any(feature = "all-api", feature = "event"))]
|
|
|
|
+fn listen_fn(event: String, handler: String, once: bool) -> TauriResult<String> {
|
|
|
|
+ Ok(format!(
|
|
|
|
+ "if (window['{listeners}'] === void 0) {{
|
|
|
|
+ window['{listeners}'] = {{}}
|
|
|
|
+ }}
|
|
|
|
+ if (window['{listeners}']['{evt}'] === void 0) {{
|
|
|
|
+ window['{listeners}']['{evt}'] = []
|
|
|
|
+ }}
|
|
|
|
+ window['{listeners}']['{evt}'].push({{
|
|
|
|
+ handler: window['{handler}'],
|
|
|
|
+ once: {once_flag}
|
|
|
|
+ }});
|
|
|
|
+
|
|
|
|
+ for (let i = 0; i < (window['{queue}'] || []).length; i++) {{
|
|
|
|
+ const e = window['{queue}'][i];
|
|
|
|
+ window['{emit}'](e.payload, e.salt, true)
|
|
|
|
+ }}
|
|
|
|
+ ",
|
|
|
|
+ listeners = crate::event::event_listeners_object_name(),
|
|
|
|
+ queue = crate::event::event_queue_object_name(),
|
|
|
|
+ emit = crate::event::emit_function_name(),
|
|
|
|
+ evt = event,
|
|
|
|
+ handler = handler,
|
|
|
|
+ once_flag = if once { "true" } else { "false" }
|
|
|
|
+ ))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(not(any(feature = "dev-server", feature = "embedded-server")))]
|
|
|
|
+fn load_asset<T: 'static>(
|
|
|
|
+ webview: &mut WebView<'_, T>,
|
|
|
|
+ asset: String,
|
|
|
|
+ asset_type: String,
|
|
|
|
+ callback: String,
|
|
|
|
+ error: String,
|
|
|
|
+) -> TauriResult<()> {
|
|
|
|
+ let handle = webview.handle();
|
|
|
|
+ crate::execute_promise(
|
|
|
|
+ webview,
|
|
|
|
+ move || {
|
|
|
|
+ let read_asset = crate::assets::ASSETS.get(&format!(
|
|
|
|
+ "{}{}{}",
|
|
|
|
+ env!("TAURI_DIST_DIR"),
|
|
|
|
+ if asset.starts_with("/") { "" } else { "/" },
|
|
|
|
+ asset
|
|
|
|
+ ));
|
|
|
|
+ if read_asset.is_err() {
|
|
|
|
+ return Err(r#""Asset not found""#.to_string());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if asset_type == "image" {
|
|
|
|
+ let ext = if asset.ends_with("gif") {
|
|
|
|
+ "gif"
|
|
|
|
+ } else if asset.ends_with("png") {
|
|
|
|
+ "png"
|
|
|
|
+ } else {
|
|
|
|
+ "jpeg"
|
|
|
|
+ };
|
|
|
|
+ Ok(format!(
|
|
|
|
+ "`data:image/{};base64,{}`",
|
|
|
|
+ ext,
|
|
|
|
+ base64::encode(&read_asset.expect("Failed to read asset type").into_owned())
|
|
|
|
+ ))
|
|
|
|
+ } else {
|
|
|
|
+ handle
|
|
|
|
+ .dispatch(move |_webview| {
|
|
|
|
+ _webview.eval(
|
|
|
|
+ &std::str::from_utf8(&read_asset.expect("Failed to read asset type").into_owned())
|
|
|
|
+ .expect("failed to convert asset bytes to u8 slice"),
|
|
|
|
+ )
|
|
|
|
+ })
|
|
|
|
+ .map_err(|err| format!("`{}`", err))
|
|
|
|
+ .map(|_| r#""Asset loaded successfully""#.to_string())
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ callback,
|
|
|
|
+ error,
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(test)]
|
|
|
|
+mod test {
|
|
|
|
+ use proptest::prelude::*;
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ // test to see if check init produces a string or not.
|
|
|
|
+ fn check_init() {
|
|
|
|
+ if cfg!(not(any(feature = "all-api", feature = "event"))) {
|
|
|
|
+ let res = super::init();
|
|
|
|
+ match res {
|
|
|
|
+ Ok(s) => assert_eq!(s, ""),
|
|
|
|
+ Err(_) => assert!(false),
|
|
|
|
+ }
|
|
|
|
+ } else if cfg!(any(feature = "all-api", feature = "event")) {
|
|
|
|
+ let res = super::init();
|
|
|
|
+ match res {
|
|
|
|
+ Ok(s) => assert!(s.contains("window.tauri.promisified")),
|
|
|
|
+ Err(_) => assert!(false),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // check the listen_fn for various usecases.
|
|
|
|
+ proptest! {
|
|
|
|
+ #[cfg(any(feature = "all-api", feature = "event"))]
|
|
|
|
+ #[test]
|
|
|
|
+ fn check_listen_fn(event in "", handler in "", once in proptest::bool::ANY) {
|
|
|
|
+ let res = super::listen_fn(event, handler, once);
|
|
|
|
+ match res {
|
|
|
|
+ Ok(_) => assert!(true),
|
|
|
|
+ Err(_) => assert!(false)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Test the open func to see if proper uris can be opened by the browser.
|
|
|
|
+ proptest! {
|
|
|
|
+ #[cfg(any(feature = "all-api", feature = "open"))]
|
|
|
|
+ #[test]
|
|
|
|
+ fn check_open(uri in r"(http://)([\\w\\d\\.]+([\\w]{2,6})?)") {
|
|
|
|
+ let res = super::open_fn(uri);
|
|
|
|
+ match res {
|
|
|
|
+ Ok(_) => assert!(true),
|
|
|
|
+ Err(_) => assert!(false),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|