mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-03 10:11:15 +02:00
feature: import official webview rust binding (#846)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
committed by
GitHub
parent
dac1db3983
commit
cd5b401707
8
.changes/tauri-webview.md
Normal file
8
.changes/tauri-webview.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
"tauri": minor
|
||||
---
|
||||
|
||||
Moving the webview implementation to [webview](https://github.com/webview/webview), with the [official Rust binding](https://github.com/webview/webview_rust).
|
||||
This is a breaking change.
|
||||
IE support has been dropped, so the `edge` object on `tauri.conf.json > tauri` no longer exists and you need to remove it.
|
||||
`webview.handle()` has been replaced with `webview.as_mut()`.
|
||||
@@ -1,6 +1,6 @@
|
||||
declare global {
|
||||
interface External {
|
||||
invoke: (command: string) => void
|
||||
interface Window {
|
||||
__TAURI_INVOKE_HANDLER__: (command: string) => void
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ function uid(): string {
|
||||
* @param args
|
||||
*/
|
||||
function invoke(args: any): void {
|
||||
window.external.invoke(typeof args === 'object' ? JSON.stringify(args) : args)
|
||||
window.__TAURI_INVOKE_HANDLER__(args)
|
||||
}
|
||||
|
||||
function transformCallback(callback?: (response: any) => void, once = false): string {
|
||||
|
||||
@@ -192,10 +192,6 @@ async function printAppInfo(tauriDir: string): Promise<void> {
|
||||
key: ' CSP',
|
||||
value: config.tauri.security ? config.tauri.security.csp : 'unset'
|
||||
})
|
||||
printInfo({
|
||||
key: ' Windows',
|
||||
value: config.tauri.edge?.active ? 'Edge' : 'MSHTML'
|
||||
})
|
||||
printInfo({
|
||||
key: ' distDir',
|
||||
value: config.build
|
||||
|
||||
@@ -54,9 +54,6 @@ const getTauriConfig = (cfg: Partial<TauriConfig>): TauriConfig => {
|
||||
security: {
|
||||
csp: "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
|
||||
},
|
||||
edge: {
|
||||
active: true
|
||||
},
|
||||
inliner: {
|
||||
active: true
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ class Runner {
|
||||
self.__parseHtml(cfg, indexDir, false)
|
||||
.then(({ html }) => {
|
||||
const headers: { [key: string]: string } = {}
|
||||
if(proxyRes.headers['content-type']) {
|
||||
if (proxyRes.headers['content-type']) {
|
||||
headers['content-type'] = proxyRes.headers['content-type']
|
||||
} else {
|
||||
const charsetMatch = /charset="(\S+)"/g.exec(bodyStr)
|
||||
@@ -527,10 +527,6 @@ class Runner {
|
||||
tomlFeatures.push(...whitelist.map(toKebabCase))
|
||||
}
|
||||
|
||||
if (cfg.tauri.edge.active) {
|
||||
tomlFeatures.push('edge')
|
||||
}
|
||||
|
||||
if (cfg.tauri.cli) {
|
||||
tomlFeatures.push('cli')
|
||||
}
|
||||
|
||||
@@ -45,9 +45,6 @@ export default {
|
||||
security: {
|
||||
csp: "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
|
||||
},
|
||||
edge: {
|
||||
active: true
|
||||
},
|
||||
inliner: {
|
||||
active: true
|
||||
}
|
||||
|
||||
@@ -391,17 +391,6 @@
|
||||
"$ref": "#/definitions/CliConfig",
|
||||
"description": "app's CLI definition"
|
||||
},
|
||||
"edge": {
|
||||
"additionalProperties": false,
|
||||
"defaultProperties": [
|
||||
],
|
||||
"properties": {
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"embeddedServer": {
|
||||
"additionalProperties": false,
|
||||
"defaultProperties": [
|
||||
@@ -496,7 +485,6 @@
|
||||
},
|
||||
"required": [
|
||||
"bundle",
|
||||
"edge",
|
||||
"embeddedServer",
|
||||
"inliner",
|
||||
"security",
|
||||
|
||||
@@ -285,9 +285,6 @@ export interface TauriConfig {
|
||||
security: {
|
||||
csp?: string
|
||||
}
|
||||
edge: {
|
||||
active?: boolean
|
||||
}
|
||||
inliner: {
|
||||
active?: boolean
|
||||
}
|
||||
|
||||
@@ -401,17 +401,6 @@ export const TauriConfigSchema = {
|
||||
"$ref": "#/definitions/CliConfig",
|
||||
"description": "app's CLI definition"
|
||||
},
|
||||
"edge": {
|
||||
"additionalProperties": false,
|
||||
"defaultProperties": [
|
||||
],
|
||||
"properties": {
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"embeddedServer": {
|
||||
"additionalProperties": false,
|
||||
"defaultProperties": [
|
||||
@@ -506,7 +495,6 @@ export const TauriConfigSchema = {
|
||||
},
|
||||
"required": [
|
||||
"bundle",
|
||||
"edge",
|
||||
"embeddedServer",
|
||||
"inliner",
|
||||
"security",
|
||||
|
||||
@@ -6,31 +6,29 @@ if (!String.prototype.startsWith) {
|
||||
}
|
||||
}
|
||||
|
||||
// makes the window.external.invoke API available after window.location.href changes
|
||||
switch (navigator.platform) {
|
||||
case "Macintosh":
|
||||
case "MacPPC":
|
||||
case "MacIntel":
|
||||
case "Mac68K":
|
||||
window.external = this
|
||||
invoke = function (x) {
|
||||
webkit.messageHandlers.invoke.postMessage(x);
|
||||
}
|
||||
break;
|
||||
case "Windows":
|
||||
case "WinCE":
|
||||
case "Win32":
|
||||
case "Win64":
|
||||
break;
|
||||
default:
|
||||
window.external = this
|
||||
invoke = function (x) {
|
||||
window.webkit.messageHandlers.external.postMessage(x);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
(function () {
|
||||
function webviewBind (name) {
|
||||
var RPC = window._rpc = (window._rpc || { nextSeq: 1 });
|
||||
window[name] = function () {
|
||||
var seq = RPC.nextSeq++;
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
RPC[seq] = {
|
||||
resolve: resolve,
|
||||
reject: reject,
|
||||
};
|
||||
});
|
||||
window.external.invoke(JSON.stringify({
|
||||
id: seq,
|
||||
method: name,
|
||||
params: Array.prototype.slice.call(arguments),
|
||||
}));
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
if (!window.__TAURI_INVOKE_HANDLER__) {
|
||||
webviewBind('__TAURI_INVOKE_HANDLER__')
|
||||
}
|
||||
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
@@ -89,9 +87,6 @@ switch (navigator.platform) {
|
||||
if (!window.__TAURI__) {
|
||||
window.__TAURI__ = {}
|
||||
}
|
||||
window.__TAURI__.invoke = function invoke(args) {
|
||||
window.external.invoke(JSON.stringify(args))
|
||||
}
|
||||
|
||||
window.__TAURI__.transformCallback = function transformCallback(callback) {
|
||||
var once = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false
|
||||
@@ -109,10 +104,10 @@ switch (navigator.platform) {
|
||||
}
|
||||
|
||||
window.__TAURI__.promisified = function promisified(args) {
|
||||
var _this = this;
|
||||
var _this = this
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
_this.invoke(_objectSpread({
|
||||
window.__TAURI_INVOKE_HANDLER__(_objectSpread({
|
||||
callback: _this.transformCallback(resolve),
|
||||
error: _this.transformCallback(reject)
|
||||
}, args))
|
||||
@@ -127,19 +122,6 @@ switch (navigator.platform) {
|
||||
})
|
||||
}
|
||||
|
||||
// init tauri API
|
||||
try {
|
||||
window.__TAURI__.invoke({
|
||||
cmd: 'init'
|
||||
})
|
||||
} catch (e) {
|
||||
window.addEventListener('DOMContentLoaded', function () {
|
||||
window.__TAURI__.invoke({
|
||||
cmd: 'init'
|
||||
})
|
||||
}, true)
|
||||
}
|
||||
|
||||
document.addEventListener('error', function (e) {
|
||||
var target = e.target
|
||||
while (target != null) {
|
||||
@@ -161,7 +143,7 @@ switch (navigator.platform) {
|
||||
while (target != null) {
|
||||
if (target.matches ? target.matches('a') : target.msMatchesSelector('a')) {
|
||||
if (target.href && target.href.startsWith('http') && target.target === '_blank') {
|
||||
window.__TAURI__.invoke({
|
||||
window.__TAURI_INVOKE_HANDLER__({
|
||||
cmd: 'open',
|
||||
uri: target.href
|
||||
})
|
||||
|
||||
@@ -20,8 +20,7 @@ features = [ "all-api" ]
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
tauri-webview-sys = "0.5.0"
|
||||
tauri-web-view = "0.6.2"
|
||||
webview_rust = { version = "0.1", git = "https://github.com/webview/webview_rust.git", branch = "dev" }
|
||||
tauri_includedir = "0.6.0"
|
||||
phf = "0.8.0"
|
||||
base64 = "0.12.3"
|
||||
@@ -35,6 +34,7 @@ thiserror = "1.0.20"
|
||||
envmnt = "0.8.3"
|
||||
once_cell = "1.4.0"
|
||||
tauri-api = { version = "0.7", path = "../tauri-api" }
|
||||
urlencoding = "1.1.1"
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies]
|
||||
runas = "0.2"
|
||||
@@ -46,12 +46,11 @@ cfg_aliases = "0.1.0"
|
||||
[dev-dependencies]
|
||||
proptest = "0.10.0"
|
||||
serde_json = "1.0"
|
||||
tauri = { path = ".", features = [ "all-api", "edge" ] }
|
||||
tauri = { path = ".", features = [ "all-api" ] }
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
|
||||
[features]
|
||||
cli = [ "tauri-api/cli" ]
|
||||
edge = [ "tauri-web-view/edge" ]
|
||||
embedded-server = [ "tiny_http" ]
|
||||
no-server = [ ]
|
||||
all-api = [ "tauri-api/notification" ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
document.getElementById('log').addEventListener('click', function () {
|
||||
window.__TAURI__.invoke({
|
||||
window.__TAURI__.tauri.invoke({
|
||||
cmd: 'logOperation',
|
||||
event: 'tauri-click',
|
||||
payload: 'this payload is optional because we used Option in Rust'
|
||||
@@ -7,7 +7,7 @@ document.getElementById('log').addEventListener('click', function () {
|
||||
})
|
||||
|
||||
document.getElementById('request').addEventListener('click', function () {
|
||||
window.__TAURI__.promisified({
|
||||
window.__TAURI__.tauri.promisified({
|
||||
cmd: 'performRequest',
|
||||
endpoint: 'dummy endpoint arg',
|
||||
body: {
|
||||
|
||||
511
tauri/examples/communication/dist/index.tauri.html
vendored
511
tauri/examples/communication/dist/index.tauri.html
vendored
File diff suppressed because one or more lines are too long
@@ -24,7 +24,7 @@ icon = [
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
tauri = { path = "../../..", features = [ "all-api", "edge", "cli" ] }
|
||||
tauri = { path = "../../..", features = [ "all-api", "cli" ] }
|
||||
|
||||
[target."cfg(windows)".build-dependencies]
|
||||
winres = "0.1"
|
||||
|
||||
@@ -15,14 +15,14 @@ struct Reply {
|
||||
fn main() {
|
||||
tauri::AppBuilder::new()
|
||||
.setup(|webview, _source| {
|
||||
let handle = webview.handle();
|
||||
let mut webview = webview.as_mut();
|
||||
tauri::event::listen(String::from("js-event"), move |msg| {
|
||||
println!("got js-event with message '{:?}'", msg);
|
||||
let reply = Reply {
|
||||
data: "something else".to_string(),
|
||||
};
|
||||
|
||||
tauri::event::emit(&handle, String::from("rust-event"), Some(reply))
|
||||
tauri::event::emit(&mut webview, String::from("rust-event"), Some(reply))
|
||||
.expect("failed to emit");
|
||||
});
|
||||
})
|
||||
|
||||
@@ -55,9 +55,6 @@
|
||||
"security": {
|
||||
"csp": "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
|
||||
},
|
||||
"edge": {
|
||||
"active": true
|
||||
},
|
||||
"inliner": {
|
||||
"active": true
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
mod runner;
|
||||
|
||||
type InvokeHandler = Box<dyn FnMut(&mut WebView<'_, ()>, &str) -> Result<(), String>>;
|
||||
type Setup = Box<dyn FnMut(&mut WebView<'_, ()>, String)>;
|
||||
type InvokeHandler = Box<dyn FnMut(&mut Webview, &str) -> Result<(), String>>;
|
||||
type Setup = Box<dyn FnMut(&mut Webview, String)>;
|
||||
|
||||
/// The application runner.
|
||||
pub struct App {
|
||||
@@ -26,7 +26,7 @@ impl App {
|
||||
/// The message is considered consumed if the handler exists and returns an Ok Result.
|
||||
pub(crate) fn run_invoke_handler(
|
||||
&mut self,
|
||||
webview: &mut WebView<'_, ()>,
|
||||
webview: &mut Webview,
|
||||
arg: &str,
|
||||
) -> Result<bool, String> {
|
||||
if let Some(ref mut invoke_handler) = self.invoke_handler {
|
||||
@@ -37,7 +37,7 @@ impl App {
|
||||
}
|
||||
|
||||
/// Runs the setup callback if defined.
|
||||
pub(crate) fn run_setup(&mut self, webview: &mut WebView<'_, ()>, source: String) {
|
||||
pub(crate) fn run_setup(&mut self, webview: &mut Webview, source: String) {
|
||||
if let Some(ref mut setup) = self.setup {
|
||||
setup(webview, source);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ impl AppBuilder {
|
||||
}
|
||||
|
||||
/// Defines the JS message handler callback.
|
||||
pub fn invoke_handler<F: FnMut(&mut WebView<'_, ()>, &str) -> Result<(), String> + 'static>(
|
||||
pub fn invoke_handler<F: FnMut(&mut Webview, &str) -> Result<(), String> + 'static>(
|
||||
mut self,
|
||||
invoke_handler: F,
|
||||
) -> Self {
|
||||
@@ -80,7 +80,7 @@ impl AppBuilder {
|
||||
}
|
||||
|
||||
/// Defines the setup callback.
|
||||
pub fn setup<F: FnMut(&mut WebView<'_, ()>, String) + 'static>(mut self, setup: F) -> Self {
|
||||
pub fn setup<F: FnMut(&mut Webview, String) + 'static>(mut self, setup: F) -> Self {
|
||||
self.setup = Some(Box::new(setup));
|
||||
self
|
||||
}
|
||||
|
||||
@@ -7,13 +7,19 @@ use std::{
|
||||
thread::spawn,
|
||||
};
|
||||
|
||||
use web_view::{builder, Content, WebView};
|
||||
use webview_rust_sys::{SizeHint, Webview, WebviewBuilder};
|
||||
|
||||
use super::App;
|
||||
#[cfg(embedded_server)]
|
||||
use crate::api::tcp::{get_available_port, port_is_available};
|
||||
use tauri_api::config::get;
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum Content<T> {
|
||||
Html(T),
|
||||
Url(T),
|
||||
}
|
||||
|
||||
/// Main entry point for running the Webview
|
||||
pub(crate) fn run(application: &mut App) -> crate::Result<()> {
|
||||
// setup the content using the config struct depending on the compile target
|
||||
@@ -56,7 +62,7 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
|
||||
spawn_updater()?;
|
||||
|
||||
// run the webview
|
||||
webview.run()?;
|
||||
webview.run();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -99,7 +105,10 @@ fn setup_content() -> crate::Result<Content<String>> {
|
||||
dev_dir
|
||||
);
|
||||
}
|
||||
Ok(Content::Html(read_to_string(dev_path)?))
|
||||
Ok(Content::Html(format!(
|
||||
"data:text/html,{}",
|
||||
urlencoding::encode(&read_to_string(dev_path)?)
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +130,10 @@ fn setup_content() -> crate::Result<Content<String>> {
|
||||
#[cfg(no_server)]
|
||||
fn setup_content() -> crate::Result<Content<String>> {
|
||||
let html = include_str!(concat!(env!("OUT_DIR"), "/index.tauri.html"));
|
||||
Ok(Content::Html(html.to_string()))
|
||||
Ok(Content::Html(format!(
|
||||
"data:text/html,{}",
|
||||
urlencoding::encode(html)
|
||||
)))
|
||||
}
|
||||
|
||||
// get the port for the embedded server
|
||||
@@ -182,12 +194,49 @@ fn spawn_updater() -> crate::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init() -> String {
|
||||
#[cfg(not(event))]
|
||||
return String::from("");
|
||||
#[cfg(event)]
|
||||
return 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_queue_object_name(),
|
||||
listeners = crate::event::event_listeners_object_name()
|
||||
);
|
||||
}
|
||||
|
||||
// build the webview struct
|
||||
fn build_webview(
|
||||
application: &mut App,
|
||||
content: Content<String>,
|
||||
splashscreen_content: Option<Content<String>>,
|
||||
) -> crate::Result<WebView<'_, ()>> {
|
||||
) -> crate::Result<Webview> {
|
||||
let config = get()?;
|
||||
let content_clone = match content {
|
||||
Content::Html(ref html) => Content::Html(html.clone()),
|
||||
@@ -197,107 +246,123 @@ fn build_webview(
|
||||
// get properties from config struct
|
||||
let width = config.tauri.window.width;
|
||||
let height = config.tauri.window.height;
|
||||
let resizable = config.tauri.window.resizable;
|
||||
let fullscreen = config.tauri.window.fullscreen;
|
||||
let resizable = if config.tauri.window.resizable {
|
||||
SizeHint::NONE
|
||||
} else {
|
||||
SizeHint::FIXED
|
||||
};
|
||||
// let fullscreen = config.tauri.window.fullscreen;
|
||||
let title = config.tauri.window.title.clone().into_boxed_str();
|
||||
|
||||
let has_splashscreen = splashscreen_content.is_some();
|
||||
let mut initialized_splashscreen = false;
|
||||
let url = match splashscreen_content {
|
||||
Some(Content::Html(s)) => s,
|
||||
_ => match content {
|
||||
Content::Html(s) => s,
|
||||
Content::Url(s) => s,
|
||||
},
|
||||
};
|
||||
|
||||
let mut webview = builder()
|
||||
let mut webview = WebviewBuilder::new()
|
||||
.init(&format!(
|
||||
r#"
|
||||
{event_init}
|
||||
if (window.__TAURI_INVOKE_HANDLER__) {{
|
||||
window.__TAURI_INVOKE_HANDLER__({{ cmd: "__initialized" }})
|
||||
}} else {{
|
||||
window.addEventListener('DOMContentLoaded', function () {{
|
||||
window.__TAURI_INVOKE_HANDLER__({{ cmd: "__initialized" }})
|
||||
}})
|
||||
}}
|
||||
"#,
|
||||
event_init = init()
|
||||
))
|
||||
.title(Box::leak(title))
|
||||
.size(width, height)
|
||||
.resizable(resizable)
|
||||
.width(width as usize)
|
||||
.height(height as usize)
|
||||
.resize(resizable)
|
||||
.debug(debug)
|
||||
.user_data(())
|
||||
.invoke_handler(move |webview, arg| {
|
||||
if arg == r#"{"cmd":"__initialized"}"# {
|
||||
let source = if has_splashscreen && !initialized_splashscreen {
|
||||
initialized_splashscreen = true;
|
||||
"splashscreen"
|
||||
} else {
|
||||
"window-1"
|
||||
};
|
||||
application.run_setup(webview, source.to_string());
|
||||
if source == "window-1" {
|
||||
let handle = webview.handle();
|
||||
handle
|
||||
.dispatch(|webview| {
|
||||
crate::plugin::ready(webview);
|
||||
Ok(())
|
||||
})
|
||||
.expect("failed to invoke ready hook");
|
||||
}
|
||||
} else if arg == r#"{"cmd":"closeSplashscreen"}"# {
|
||||
let content_href = match content_clone {
|
||||
Content::Html(ref html) => html,
|
||||
Content::Url(ref url) => url,
|
||||
};
|
||||
webview.eval(&format!(r#"window.location.href = "{}""#, content_href))?;
|
||||
} else {
|
||||
let endpoint_handle = crate::endpoints::handle(webview, arg)
|
||||
.map_err(|tauri_handle_error| {
|
||||
let tauri_handle_error_str = tauri_handle_error.to_string();
|
||||
if tauri_handle_error_str.contains("unknown variant") {
|
||||
match application.run_invoke_handler(webview, arg) {
|
||||
Ok(handled) => {
|
||||
if handled {
|
||||
String::from("")
|
||||
} else {
|
||||
tauri_handle_error_str
|
||||
}
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
} else {
|
||||
tauri_handle_error_str
|
||||
}
|
||||
})
|
||||
.map_err(|app_handle_error| {
|
||||
if app_handle_error.contains("unknown variant") {
|
||||
match crate::plugin::extend_api(webview, arg) {
|
||||
Ok(handled) => {
|
||||
if handled {
|
||||
String::from("")
|
||||
} else {
|
||||
app_handle_error
|
||||
}
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
} else {
|
||||
app_handle_error
|
||||
}
|
||||
})
|
||||
.map_err(|e| e.replace("'", "\\'"));
|
||||
if let Err(handler_error_message) = endpoint_handle {
|
||||
if handler_error_message != "" {
|
||||
webview.eval(&get_api_error_message(arg, handler_error_message))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.content(if splashscreen_content.is_some() {
|
||||
splashscreen_content.expect("failed to get splashscreen content")
|
||||
} else {
|
||||
content
|
||||
})
|
||||
.build()?;
|
||||
|
||||
webview.set_fullscreen(fullscreen);
|
||||
.url(&url)
|
||||
.build();
|
||||
// TODO waiting for webview window API
|
||||
// webview.set_fullscreen(fullscreen);
|
||||
|
||||
if has_splashscreen {
|
||||
let env_var = envmnt::get_or("TAURI_DIR", "../dist");
|
||||
let path = Path::new(&env_var);
|
||||
let contents = fs::read_to_string(path.join("/tauri.js"))?;
|
||||
// inject the tauri.js entry point
|
||||
webview
|
||||
.handle()
|
||||
.dispatch(move |_webview| _webview.eval(&contents))?;
|
||||
webview.dispatch(move |_webview| _webview.eval(&contents));
|
||||
}
|
||||
|
||||
let mut w = webview.clone();
|
||||
webview.bind("__TAURI_INVOKE_HANDLER__", move |_, arg| {
|
||||
// transform `[payload]` to `payload`
|
||||
let arg = arg.chars().skip(1).take(arg.len() - 2).collect::<String>();
|
||||
if arg == r#"{"cmd":"__initialized"}"# {
|
||||
let source = if has_splashscreen && !initialized_splashscreen {
|
||||
initialized_splashscreen = true;
|
||||
"splashscreen"
|
||||
} else {
|
||||
"window-1"
|
||||
};
|
||||
application.run_setup(&mut w, source.to_string());
|
||||
if source == "window-1" {
|
||||
w.dispatch(|w| {
|
||||
crate::plugin::ready(w);
|
||||
});
|
||||
}
|
||||
} else if arg == r#"{"cmd":"closeSplashscreen"}"# {
|
||||
let content_href = match content_clone {
|
||||
Content::Html(ref html) => html,
|
||||
Content::Url(ref url) => url,
|
||||
};
|
||||
w.eval(&format!(r#"window.location.href = "{}""#, content_href));
|
||||
} else {
|
||||
let endpoint_handle = crate::endpoints::handle(&mut w, &arg)
|
||||
.map_err(|tauri_handle_error| {
|
||||
let tauri_handle_error_str = tauri_handle_error.to_string();
|
||||
if tauri_handle_error_str.contains("unknown variant") {
|
||||
match application.run_invoke_handler(&mut w, &arg) {
|
||||
Ok(handled) => {
|
||||
if handled {
|
||||
String::from("")
|
||||
} else {
|
||||
tauri_handle_error_str
|
||||
}
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
} else {
|
||||
tauri_handle_error_str
|
||||
}
|
||||
})
|
||||
.map_err(|app_handle_error| {
|
||||
if app_handle_error.contains("unknown variant") {
|
||||
match crate::plugin::extend_api(&mut w, &arg) {
|
||||
Ok(handled) => {
|
||||
if handled {
|
||||
String::from("")
|
||||
} else {
|
||||
app_handle_error
|
||||
}
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
} else {
|
||||
app_handle_error
|
||||
}
|
||||
})
|
||||
.map_err(|e| e.replace("'", "\\'"));
|
||||
if let Err(handler_error_message) = endpoint_handle {
|
||||
if handler_error_message != "" {
|
||||
w.eval(&get_api_error_message(&arg, handler_error_message));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(webview)
|
||||
}
|
||||
|
||||
@@ -312,9 +377,9 @@ fn get_api_error_message(arg: &str, handler_error_message: String) -> String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Content;
|
||||
use proptest::prelude::*;
|
||||
use std::env;
|
||||
use web_view::Content;
|
||||
|
||||
#[cfg(not(feature = "embedded-server"))]
|
||||
use std::{fs::read_to_string, path::Path};
|
||||
@@ -351,7 +416,12 @@ mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
s,
|
||||
read_to_string(Path::new(&dist_dir).join("index.tauri.html")).unwrap()
|
||||
format!(
|
||||
"data:text/html,{}",
|
||||
urlencoding::encode(
|
||||
&read_to_string(Path::new(&dist_dir).join("index.tauri.html")).unwrap()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
_ => panic!("setup content failed"),
|
||||
@@ -367,7 +437,10 @@ mod test {
|
||||
let dev_path = Path::new(dev_dir).join("index.tauri.html");
|
||||
assert_eq!(
|
||||
s,
|
||||
read_to_string(dev_path).expect("failed to read dev path")
|
||||
format!(
|
||||
"data:text/html,{}",
|
||||
urlencoding::encode(&read_to_string(dev_path).expect("failed to read dev path"))
|
||||
)
|
||||
);
|
||||
}
|
||||
_ => panic!("setup content failed"),
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
mod cmd;
|
||||
#[allow(unused_imports)]
|
||||
mod file_system;
|
||||
mod init;
|
||||
mod salt;
|
||||
|
||||
use init::init;
|
||||
|
||||
#[cfg(assets)]
|
||||
mod asset;
|
||||
#[cfg(open)]
|
||||
@@ -19,24 +16,15 @@ mod http;
|
||||
#[cfg(notification)]
|
||||
mod notification;
|
||||
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> crate::Result<()> {
|
||||
pub(crate) fn handle(webview: &mut Webview, arg: &str) -> crate::Result<()> {
|
||||
use cmd::Cmd::*;
|
||||
match serde_json::from_str(arg) {
|
||||
Err(e) => Err(e.into()),
|
||||
Ok(command) => {
|
||||
match command {
|
||||
Init {} => {
|
||||
let event_init = init()?;
|
||||
webview.eval(&format!(
|
||||
r#"{event_init}
|
||||
window.external.invoke('{{"cmd":"__initialized"}}')
|
||||
"#,
|
||||
event_init = event_init
|
||||
))?;
|
||||
}
|
||||
ReadTextFile {
|
||||
path,
|
||||
options,
|
||||
@@ -153,7 +141,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
|
||||
}
|
||||
SetTitle { title } => {
|
||||
#[cfg(set_title)]
|
||||
webview.set_title(&title)?;
|
||||
webview.set_title(&title);
|
||||
#[cfg(not(set_title))]
|
||||
throw_whitelist_error(webview, "title");
|
||||
}
|
||||
@@ -189,7 +177,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
|
||||
#[cfg(event)]
|
||||
{
|
||||
let js_string = event::listen_fn(event, handler, once)?;
|
||||
webview.eval(&js_string)?;
|
||||
webview.eval(&js_string);
|
||||
}
|
||||
#[cfg(not(event))]
|
||||
throw_whitelist_error(webview, "event");
|
||||
@@ -286,19 +274,13 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn api_error<T: 'static>(webview: &mut WebView<'_, T>, error_fn: String, message: &str) {
|
||||
fn api_error(webview: &mut Webview, error_fn: String, message: &str) {
|
||||
let reject_code = tauri_api::rpc::format_callback(error_fn, message);
|
||||
webview
|
||||
.eval(&reject_code)
|
||||
.expect("failed to eval api error")
|
||||
webview.eval(&reject_code)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn whitelist_error<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
error_fn: String,
|
||||
whitelist_key: &str,
|
||||
) {
|
||||
fn whitelist_error(webview: &mut Webview, error_fn: String, whitelist_key: &str) {
|
||||
api_error(
|
||||
webview,
|
||||
error_fn,
|
||||
@@ -310,35 +292,15 @@ fn whitelist_error<T: 'static>(
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn throw_whitelist_error<T: 'static>(webview: &mut WebView<'_, T>, whitelist_key: &str) {
|
||||
fn throw_whitelist_error(webview: &mut Webview, whitelist_key: &str) {
|
||||
let reject_code = format!(r#"throw new Error("'{}' not whitelisted")"#, whitelist_key);
|
||||
webview
|
||||
.eval(&reject_code)
|
||||
.expect("failed to eval whitelist error")
|
||||
webview.eval(&reject_code)
|
||||
}
|
||||
|
||||
#[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(event)) {
|
||||
let res = super::init();
|
||||
match res {
|
||||
Ok(s) => assert_eq!(s, ""),
|
||||
Err(e) => panic!("init Err {:?}", e.to_string()),
|
||||
}
|
||||
} else if cfg!(event) {
|
||||
let res = super::init();
|
||||
match res {
|
||||
Ok(s) => assert!(s.contains("window.__TAURI__.promisified")),
|
||||
Err(e) => panic!("init Err {:?}", e.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check the listen_fn for various usecases.
|
||||
proptest! {
|
||||
#[cfg(event)]
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use std::path::PathBuf;
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
pub fn load<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn load(
|
||||
webview: &mut Webview,
|
||||
asset: String,
|
||||
asset_type: String,
|
||||
callback: String,
|
||||
error: String,
|
||||
) {
|
||||
let handle = webview.handle();
|
||||
let mut webview_mut = webview.as_mut();
|
||||
crate::execute_promise(
|
||||
webview,
|
||||
move || {
|
||||
@@ -58,19 +58,30 @@ pub fn load<T: 'static>(
|
||||
base64::encode(&read_asset.expect("Failed to read asset type").into_owned())
|
||||
))
|
||||
} else {
|
||||
handle
|
||||
.dispatch(move |_webview| {
|
||||
let asset_bytes = &read_asset.expect("Failed to read asset type").into_owned();
|
||||
let asset_str =
|
||||
&std::str::from_utf8(asset_bytes).expect("failed to convert asset bytes to u8 slice");
|
||||
if asset_type == "stylesheet" {
|
||||
_webview.inject_css(asset_str)
|
||||
} else {
|
||||
_webview.eval(asset_str)
|
||||
}
|
||||
})
|
||||
.map_err(|err| err.into())
|
||||
.map(|_| "Asset loaded successfully".to_string())
|
||||
let asset_bytes = read_asset.expect("Failed to read asset type");
|
||||
webview_mut.dispatch(move |webview_ref| {
|
||||
let asset_str =
|
||||
std::str::from_utf8(&asset_bytes).expect("failed to convert asset bytes to u8 slice");
|
||||
if asset_type == "stylesheet" {
|
||||
webview_ref.eval(&format!(
|
||||
r#"
|
||||
(function () {{
|
||||
var css = document.createElement('style')
|
||||
css.type = 'text/css'
|
||||
if (css.styleSheet)
|
||||
css.styleSheet.cssText = {css}
|
||||
else
|
||||
css.appendChild(document.createTextNode({css}))
|
||||
document.getElementsByTagName("head")[0].appendChild(css);
|
||||
}})()
|
||||
"#,
|
||||
css = asset_str
|
||||
));
|
||||
} else {
|
||||
webview_ref.eval(asset_str);
|
||||
}
|
||||
})?;
|
||||
Ok("Asset loaded successfully".to_string())
|
||||
}
|
||||
},
|
||||
callback,
|
||||
|
||||
@@ -64,8 +64,6 @@ pub struct NotificationOptions {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "cmd", rename_all = "camelCase")]
|
||||
pub enum Cmd {
|
||||
/// The init command
|
||||
Init {},
|
||||
/// The read text file API.
|
||||
ReadTextFile {
|
||||
path: PathBuf,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::cmd::{OpenDialogOptions, SaveDialogOptions};
|
||||
use crate::api::dialog::{pick_folder, save_file, select, select_multiple, Response};
|
||||
use serde_json::Value as JsonValue;
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
/// maps a dialog response to a JS value to eval
|
||||
fn map_response(response: Response) -> JsonValue {
|
||||
@@ -14,8 +14,8 @@ fn map_response(response: Response) -> JsonValue {
|
||||
|
||||
/// Shows an open dialog.
|
||||
#[cfg(open_dialog)]
|
||||
pub fn open<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn open(
|
||||
webview: &mut Webview,
|
||||
options: OpenDialogOptions,
|
||||
callback: String,
|
||||
error: String,
|
||||
@@ -40,8 +40,8 @@ pub fn open<T: 'static>(
|
||||
|
||||
/// Shows a save dialog.
|
||||
#[cfg(save_dialog)]
|
||||
pub fn save<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn save(
|
||||
webview: &mut Webview,
|
||||
options: SaveDialogOptions,
|
||||
callback: String,
|
||||
error: String,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
use tauri_api::dir;
|
||||
use tauri_api::file;
|
||||
@@ -13,8 +13,8 @@ use super::cmd::{DirOperationOptions, FileOperationOptions};
|
||||
|
||||
/// Reads a directory.
|
||||
#[cfg(read_dir)]
|
||||
pub fn read_dir<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn read_dir(
|
||||
webview: &mut Webview,
|
||||
path: PathBuf,
|
||||
options: Option<DirOperationOptions>,
|
||||
callback: String,
|
||||
@@ -37,8 +37,8 @@ pub fn read_dir<T: 'static>(
|
||||
|
||||
/// Copies a file.
|
||||
#[cfg(copy_file)]
|
||||
pub fn copy_file<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn copy_file(
|
||||
webview: &mut Webview,
|
||||
source: PathBuf,
|
||||
destination: PathBuf,
|
||||
options: Option<FileOperationOptions>,
|
||||
@@ -64,8 +64,8 @@ pub fn copy_file<T: 'static>(
|
||||
|
||||
/// Creates a directory.
|
||||
#[cfg(create_dir)]
|
||||
pub fn create_dir<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn create_dir(
|
||||
webview: &mut Webview,
|
||||
path: PathBuf,
|
||||
options: Option<DirOperationOptions>,
|
||||
callback: String,
|
||||
@@ -95,8 +95,8 @@ pub fn create_dir<T: 'static>(
|
||||
|
||||
/// Removes a directory.
|
||||
#[cfg(remove_dir)]
|
||||
pub fn remove_dir<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn remove_dir(
|
||||
webview: &mut Webview,
|
||||
path: PathBuf,
|
||||
options: Option<DirOperationOptions>,
|
||||
callback: String,
|
||||
@@ -126,8 +126,8 @@ pub fn remove_dir<T: 'static>(
|
||||
|
||||
/// Removes a file
|
||||
#[cfg(remove_file)]
|
||||
pub fn remove_file<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn remove_file(
|
||||
webview: &mut Webview,
|
||||
path: PathBuf,
|
||||
options: Option<FileOperationOptions>,
|
||||
callback: String,
|
||||
@@ -146,8 +146,8 @@ pub fn remove_file<T: 'static>(
|
||||
|
||||
/// Renames a file.
|
||||
#[cfg(rename_file)]
|
||||
pub fn rename_file<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn rename_file(
|
||||
webview: &mut Webview,
|
||||
old_path: PathBuf,
|
||||
new_path: PathBuf,
|
||||
options: Option<FileOperationOptions>,
|
||||
@@ -173,8 +173,8 @@ pub fn rename_file<T: 'static>(
|
||||
|
||||
/// Writes a text file.
|
||||
#[cfg(write_file)]
|
||||
pub fn write_file<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn write_file(
|
||||
webview: &mut Webview,
|
||||
path: PathBuf,
|
||||
contents: String,
|
||||
options: Option<FileOperationOptions>,
|
||||
@@ -195,8 +195,8 @@ pub fn write_file<T: 'static>(
|
||||
|
||||
/// Writes a binary file.
|
||||
#[cfg(write_binary_file)]
|
||||
pub fn write_binary_file<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn write_binary_file(
|
||||
webview: &mut Webview,
|
||||
path: PathBuf,
|
||||
contents: String,
|
||||
options: Option<FileOperationOptions>,
|
||||
@@ -221,8 +221,8 @@ pub fn write_binary_file<T: 'static>(
|
||||
|
||||
/// Reads a text file.
|
||||
#[cfg(read_text_file)]
|
||||
pub fn read_text_file<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn read_text_file(
|
||||
webview: &mut Webview,
|
||||
path: PathBuf,
|
||||
options: Option<FileOperationOptions>,
|
||||
callback: String,
|
||||
@@ -238,8 +238,8 @@ pub fn read_text_file<T: 'static>(
|
||||
|
||||
/// Reads a binary file.
|
||||
#[cfg(read_binary_file)]
|
||||
pub fn read_binary_file<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn read_binary_file(
|
||||
webview: &mut Webview,
|
||||
path: PathBuf,
|
||||
options: Option<FileOperationOptions>,
|
||||
callback: String,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use tauri_api::http::{make_request as request, HttpRequestOptions};
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
/// Makes an HTTP request and resolves the response to the webview
|
||||
pub fn make_request<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn make_request(
|
||||
webview: &mut Webview,
|
||||
options: HttpRequestOptions,
|
||||
callback: String,
|
||||
error: String,
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
pub fn init() -> crate::Result<String> {
|
||||
#[cfg(not(event))]
|
||||
return Ok(String::from(""));
|
||||
#[cfg(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_queue_object_name(),
|
||||
listeners = crate::event::event_listeners_object_name()
|
||||
));
|
||||
}
|
||||
@@ -1,13 +1,8 @@
|
||||
use super::cmd::NotificationOptions;
|
||||
use serde_json::Value as JsonValue;
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
pub fn send<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
options: NotificationOptions,
|
||||
callback: String,
|
||||
error: String,
|
||||
) {
|
||||
pub fn send(webview: &mut Webview, options: NotificationOptions, callback: String, error: String) {
|
||||
crate::execute_promise(
|
||||
webview,
|
||||
move || {
|
||||
@@ -26,11 +21,7 @@ pub fn send<T: 'static>(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn is_permission_granted<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
callback: String,
|
||||
error: String,
|
||||
) {
|
||||
pub fn is_permission_granted(webview: &mut Webview, callback: String, error: String) {
|
||||
crate::execute_promise(
|
||||
webview,
|
||||
move || {
|
||||
@@ -46,8 +37,8 @@ pub fn is_permission_granted<T: 'static>(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn request_permission<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn request_permission(
|
||||
webview: &mut Webview,
|
||||
callback: String,
|
||||
error: String,
|
||||
) -> crate::Result<()> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
/// Validates a salt.
|
||||
pub fn validate<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn validate(
|
||||
webview: &mut Webview,
|
||||
salt: String,
|
||||
callback: String,
|
||||
error: String,
|
||||
@@ -13,6 +13,6 @@ pub fn validate<T: 'static>(
|
||||
Err("Invalid salt")
|
||||
};
|
||||
let callback_string = crate::api::rpc::format_callback_result(response, callback, error)?;
|
||||
webview.eval(callback_string.as_str())?;
|
||||
webview.eval(callback_string.as_str());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use lazy_static::lazy_static;
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use web_view::Handle;
|
||||
use webview_rust_sys::WebviewMut;
|
||||
|
||||
/// An event handler.
|
||||
struct EventHandler {
|
||||
@@ -57,8 +57,8 @@ pub fn listen<F: FnMut(Option<String>) + Send + 'static>(id: impl Into<String>,
|
||||
}
|
||||
|
||||
/// Emits an event to JS.
|
||||
pub fn emit<T: 'static, S: Serialize>(
|
||||
webview_handle: &Handle<T>,
|
||||
pub fn emit<S: Serialize>(
|
||||
webview: &mut WebviewMut,
|
||||
event: impl AsRef<str> + Send + 'static,
|
||||
payload: Option<S>,
|
||||
) -> crate::Result<()> {
|
||||
@@ -70,17 +70,15 @@ pub fn emit<T: 'static, S: Serialize>(
|
||||
JsonValue::Null
|
||||
};
|
||||
|
||||
webview_handle
|
||||
.dispatch(move |_webview| {
|
||||
_webview.eval(&format!(
|
||||
"window['{}']({{type: '{}', payload: {}}}, '{}')",
|
||||
emit_function_name(),
|
||||
event.as_ref(),
|
||||
js_payload,
|
||||
salt
|
||||
))
|
||||
})
|
||||
.expect("Failed to dispatch JS from emit");
|
||||
webview.dispatch(move |webview_ref| {
|
||||
webview_ref.eval(&format!(
|
||||
"window['{}']({{type: '{}', payload: {}}}, '{}')",
|
||||
emit_function_name(),
|
||||
event.as_ref(),
|
||||
js_payload,
|
||||
salt
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -39,8 +39,7 @@ mod salt;
|
||||
pub use anyhow::Result;
|
||||
pub use app::*;
|
||||
pub use tauri_api as api;
|
||||
pub use web_view::Handle;
|
||||
pub use web_view::WebView;
|
||||
pub use webview_rust_sys::{Webview, WebviewMut};
|
||||
|
||||
use std::process::Stdio;
|
||||
|
||||
@@ -61,20 +60,15 @@ pub fn spawn<F: FnOnce() -> () + Send + 'static>(task: F) {
|
||||
|
||||
/// Synchronously executes the given task
|
||||
/// and evaluates its Result to the JS promise described by the `callback` and `error` function names.
|
||||
pub fn execute_promise_sync<
|
||||
T: 'static,
|
||||
R: Serialize,
|
||||
F: FnOnce() -> crate::Result<R> + Send + 'static,
|
||||
>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn execute_promise_sync<R: Serialize, F: FnOnce() -> crate::Result<R> + Send + 'static>(
|
||||
webview: &mut Webview,
|
||||
task: F,
|
||||
callback: String,
|
||||
error: String,
|
||||
) -> crate::Result<()> {
|
||||
let handle = webview.handle();
|
||||
let callback_string =
|
||||
format_callback_result(task().map_err(|err| err.to_string()), callback, error)?;
|
||||
handle.dispatch(move |_webview| _webview.eval(callback_string.as_str()))?;
|
||||
webview.dispatch(move |w| w.eval(callback_string.as_str()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -83,17 +77,13 @@ pub fn execute_promise_sync<
|
||||
///
|
||||
/// If the Result `is_ok()`, the callback will be the `success_callback` function name and the argument will be the Ok value.
|
||||
/// If the Result `is_err()`, the callback will be the `error_callback` function name and the argument will be the Err value.
|
||||
pub fn execute_promise<
|
||||
T: 'static,
|
||||
R: Serialize,
|
||||
F: FnOnce() -> crate::Result<R> + Send + 'static,
|
||||
>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn execute_promise<R: Serialize, F: FnOnce() -> crate::Result<R> + Send + 'static>(
|
||||
webview: &mut Webview,
|
||||
task: F,
|
||||
success_callback: String,
|
||||
error_callback: String,
|
||||
) {
|
||||
let handle = webview.handle();
|
||||
let mut webview = webview.as_mut();
|
||||
POOL.with(|thread| {
|
||||
thread.execute(move || {
|
||||
let callback_string = match format_callback_result(
|
||||
@@ -104,16 +94,16 @@ pub fn execute_promise<
|
||||
Ok(callback_string) => callback_string,
|
||||
Err(e) => format_callback(error_callback, e.to_string()),
|
||||
};
|
||||
handle
|
||||
.dispatch(move |_webview| _webview.eval(callback_string.as_str()))
|
||||
.expect("Failed to dispatch promise callback")
|
||||
webview
|
||||
.dispatch(move |webview_ref| webview_ref.eval(callback_string.as_str()))
|
||||
.expect("Failed to dispatch promise callback");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Calls the given command and evaluates its output to the JS promise described by the `callback` and `error` function names.
|
||||
pub fn call<T: 'static>(
|
||||
webview: &mut WebView<'_, T>,
|
||||
pub fn call(
|
||||
webview: &mut Webview,
|
||||
command: String,
|
||||
args: Vec<String>,
|
||||
callback: String,
|
||||
@@ -128,11 +118,10 @@ pub fn call<T: 'static>(
|
||||
}
|
||||
|
||||
/// Closes the splashscreen.
|
||||
pub fn close_splashscreen<T: 'static>(webview_handle: &Handle<T>) -> crate::Result<()> {
|
||||
webview_handle.dispatch(|webview| {
|
||||
// send a signal to the runner so it knows that it should redirect to the main app content
|
||||
webview.eval(r#"window.external.invoke(JSON.stringify({ cmd: "closeSplashscreen" }))"#)
|
||||
})?;
|
||||
pub fn close_splashscreen(webview: &mut Webview) -> crate::Result<()> {
|
||||
// send a signal to the runner so it knows that it should redirect to the main app content
|
||||
webview.eval(r#"window.__TAURI_INVOKE_HANDLER__({ cmd: "closeSplashscreen" })"#);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
use web_view::WebView;
|
||||
use webview_rust_sys::Webview;
|
||||
|
||||
/// The plugin interface.
|
||||
pub trait Plugin {
|
||||
/// Callback invoked when the webview is created.
|
||||
#[allow(unused_variables)]
|
||||
fn created(&self, webview: &mut WebView<'_, ()>) {}
|
||||
fn created(&self, webview: &mut Webview) {}
|
||||
|
||||
/// Callback invoked when the webview is ready.
|
||||
#[allow(unused_variables)]
|
||||
fn ready(&self, webview: &mut WebView<'_, ()>) {}
|
||||
fn ready(&self, webview: &mut Webview) {}
|
||||
|
||||
/// Add invoke_handler API extension commands.
|
||||
#[allow(unused_variables)]
|
||||
fn extend_api(&self, webview: &mut WebView<'_, ()>, payload: &str) -> Result<bool, String> {
|
||||
fn extend_api(&self, webview: &mut Webview, payload: &str) -> Result<bool, String> {
|
||||
Err("unknown variant".to_string())
|
||||
}
|
||||
}
|
||||
@@ -37,19 +37,19 @@ fn run_plugin<T: FnMut(&Box<dyn Plugin>)>(mut callback: T) {
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn created(webview: &mut WebView<'_, ()>) {
|
||||
pub(crate) fn created(webview: &mut Webview) {
|
||||
run_plugin(|ext| {
|
||||
ext.created(webview);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn ready(webview: &mut WebView<'_, ()>) {
|
||||
pub(crate) fn ready(webview: &mut Webview) {
|
||||
run_plugin(|ext| {
|
||||
ext.ready(webview);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn extend_api(webview: &mut WebView<'_, ()>, arg: &str) -> Result<bool, String> {
|
||||
pub(crate) fn extend_api(webview: &mut Webview, arg: &str) -> Result<bool, String> {
|
||||
PLUGINS.with(|plugins| {
|
||||
let exts = plugins.lock().unwrap();
|
||||
for ext in exts.iter() {
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
},
|
||||
"security": {
|
||||
"csp": "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
|
||||
},
|
||||
"inliner": {
|
||||
"active": true
|
||||
}
|
||||
},
|
||||
"edge": true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user