mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-03 10:11:15 +02:00
feat: expose api to run initialization scripts on all frames. (#13076)
* api!: expose api to run initialisation scripts on all frames. * remove breaking change, add new api instead. * Update .changes/init-script-on-all-frames.md Co-authored-by: Tony <68118705+Legend-Master@users.noreply.github.com> * use struct `InitializationScript` instead of tuple * Update crates/tauri-runtime/src/webview.rs Co-authored-by: Tony <68118705+Legend-Master@users.noreply.github.com> * Apply suggestions from code review * Update crates/tauri/src/webview/webview_window.rs --------- Co-authored-by: Tony <68118705+Legend-Master@users.noreply.github.com>
This commit is contained in:
9
.changes/init-script-on-all-frames.md
Normal file
9
.changes/init-script-on-all-frames.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
tauri: minor:feat
|
||||
tauri-runtime: minor:feat
|
||||
---
|
||||
|
||||
- add API to run initialization scripts on all frames
|
||||
- `WebviewBuilder::initialization_script_on_all_frames`
|
||||
- `WebviewWindowBuilder::initialization_script_on_all_frames`
|
||||
- `WebviewAttributes::initialization_script_on_all_frames`
|
||||
@@ -4557,7 +4557,8 @@ fn create_webview<T: UserEvent>(
|
||||
));
|
||||
|
||||
for script in webview_attributes.initialization_scripts {
|
||||
webview_builder = webview_builder.with_initialization_script(&script);
|
||||
webview_builder = webview_builder
|
||||
.with_initialization_script_for_main_only(&script.script, script.for_main_frame_only);
|
||||
}
|
||||
|
||||
for (scheme, protocol) in uri_scheme_protocols {
|
||||
|
||||
@@ -197,7 +197,15 @@ impl<T: UserEvent, R: Runtime<T>> PartialEq for DetachedWebview<T, R> {
|
||||
pub struct WebviewAttributes {
|
||||
pub url: WebviewUrl,
|
||||
pub user_agent: Option<String>,
|
||||
pub initialization_scripts: Vec<String>,
|
||||
/// A list of initialization javascript scripts to run when loading new pages.
|
||||
/// When webview load a new page, this initialization code will be executed.
|
||||
/// It is guaranteed that code is executed before `window.onload`.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Android on Wry:** The Android WebView does not provide an API for initialization scripts,
|
||||
/// so we prepend them to each HTML head. They are only implemented on custom protocol URLs.
|
||||
pub initialization_scripts: Vec<InitializationScript>,
|
||||
pub data_directory: Option<PathBuf>,
|
||||
pub drag_drop_handler_enabled: bool,
|
||||
pub clipboard: bool,
|
||||
@@ -307,10 +315,46 @@ impl WebviewAttributes {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the init script.
|
||||
/// Adds an init script for the main frame.
|
||||
///
|
||||
/// When webview load a new page, this initialization code will be executed.
|
||||
/// It is guaranteed that code is executed before `window.onload`.
|
||||
///
|
||||
/// This is executed only on the main frame.
|
||||
/// If you only want to run it in all frames, use [Self::initialization_script_on_all_frames] instead.
|
||||
///
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Android on Wry:** The Android WebView does not provide an API for initialization scripts,
|
||||
/// so we prepend them to each HTML head. They are only implemented on custom protocol URLs.
|
||||
#[must_use]
|
||||
pub fn initialization_script(mut self, script: &str) -> Self {
|
||||
self.initialization_scripts.push(script.to_string());
|
||||
self.initialization_scripts.push(InitializationScript {
|
||||
script: script.to_string(),
|
||||
for_main_frame_only: true,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an init script for all frames.
|
||||
///
|
||||
/// When webview load a new page, this initialization code will be executed.
|
||||
/// It is guaranteed that code is executed before `window.onload`.
|
||||
///
|
||||
/// This is executed on all frames, main frame and also sub frames.
|
||||
/// If you only want to run it in the main frame, use [Self::initialization_script] instead.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Android on Wry:** The Android WebView does not provide an API for initialization scripts,
|
||||
/// so we prepend them to each HTML head. They are only implemented on custom protocol URLs.
|
||||
#[must_use]
|
||||
pub fn initialization_script_on_all_frames(mut self, script: &str) -> Self {
|
||||
self.initialization_scripts.push(InitializationScript {
|
||||
script: script.to_string(),
|
||||
for_main_frame_only: false,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
@@ -499,3 +543,21 @@ impl WebviewAttributes {
|
||||
|
||||
/// IPC handler.
|
||||
pub type WebviewIpcHandler<T, R> = Box<dyn Fn(DetachedWebview<T, R>, Request<String>) + Send>;
|
||||
|
||||
/// An initialization script
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InitializationScript {
|
||||
/// The script to run
|
||||
pub script: String,
|
||||
/// Whether the script should be injected to main frame only
|
||||
pub for_main_frame_only: bool,
|
||||
}
|
||||
|
||||
impl InitializationScript {
|
||||
pub fn new(script: &str, for_main_frame_only: bool) -> Self {
|
||||
Self {
|
||||
script: script.to_owned(),
|
||||
for_main_frame_only,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::{
|
||||
use serde::Serialize;
|
||||
use serialize_to_javascript::{default_template, DefaultTemplate, Template};
|
||||
use tauri_runtime::{
|
||||
webview::{DetachedWebview, PendingWebview},
|
||||
webview::{DetachedWebview, InitializationScript, PendingWebview},
|
||||
window::DragDropEvent,
|
||||
};
|
||||
use tauri_utils::config::WebviewUrl;
|
||||
@@ -211,9 +211,15 @@ impl<R: Runtime> WebviewManager<R> {
|
||||
}
|
||||
}
|
||||
|
||||
webview_attributes
|
||||
.initialization_scripts
|
||||
.splice(0..0, all_initialization_scripts);
|
||||
webview_attributes.initialization_scripts.splice(
|
||||
0..0,
|
||||
all_initialization_scripts
|
||||
.into_iter()
|
||||
.map(|script| InitializationScript {
|
||||
script,
|
||||
for_main_frame_only: true,
|
||||
}),
|
||||
);
|
||||
|
||||
pending.webview_attributes = webview_attributes;
|
||||
|
||||
@@ -527,13 +533,17 @@ impl<R: Runtime> WebviewManager<R> {
|
||||
os_name: &'a str,
|
||||
}
|
||||
|
||||
pending.webview_attributes.initialization_scripts.push(
|
||||
HotkeyZoom {
|
||||
os_name: std::env::consts::OS,
|
||||
}
|
||||
.render_default(&Default::default())?
|
||||
.into_string(),
|
||||
)
|
||||
pending
|
||||
.webview_attributes
|
||||
.initialization_scripts
|
||||
.push(InitializationScript {
|
||||
script: HotkeyZoom {
|
||||
os_name: std::env::consts::OS,
|
||||
}
|
||||
.render_default(&Default::default())?
|
||||
.into_string(),
|
||||
for_main_frame_only: true,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "isolation")]
|
||||
|
||||
@@ -20,7 +20,7 @@ use tauri_runtime::{
|
||||
WindowDispatch,
|
||||
};
|
||||
use tauri_runtime::{
|
||||
webview::{DetachedWebview, PendingWebview, WebviewAttributes},
|
||||
webview::{DetachedWebview, InitializationScript, PendingWebview, WebviewAttributes},
|
||||
WebviewDispatch,
|
||||
};
|
||||
pub use tauri_utils::config::Color;
|
||||
@@ -634,9 +634,12 @@ impl<R: Runtime> WebviewBuilder<R> {
|
||||
/// Adds the provided JavaScript to a list of scripts that should be run after the global object has been created,
|
||||
/// but before the HTML document has been parsed and before any other script included by the HTML document is run.
|
||||
///
|
||||
/// Since it runs on all top-level document and child frame page navigations,
|
||||
/// Since it runs on all top-level document navigations,
|
||||
/// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
|
||||
///
|
||||
/// This is executed only on the main frame.
|
||||
/// If you only want to run it in all frames, use [Self::initialization_script_for_all_frames] instead.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
#[cfg_attr(
|
||||
@@ -671,7 +674,60 @@ fn main() {
|
||||
self
|
||||
.webview_attributes
|
||||
.initialization_scripts
|
||||
.push(script.to_string());
|
||||
.push(InitializationScript {
|
||||
script: script.to_string(),
|
||||
for_main_frame_only: true,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds the provided JavaScript to a list of scripts that should be run after the global object has been created,
|
||||
/// but before the HTML document has been parsed and before any other script included by the HTML document is run.
|
||||
///
|
||||
/// Since it runs on all top-level document navigations and also child frame page navigations,
|
||||
/// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
|
||||
///
|
||||
/// This is executed on all frames, main frame and also sub frames.
|
||||
/// If you only want to run it in the main frame, use [Self::initialization_script] instead.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
#[cfg_attr(
|
||||
feature = "unstable",
|
||||
doc = r####"
|
||||
```rust
|
||||
use tauri::{WindowBuilder, Runtime};
|
||||
|
||||
const INIT_SCRIPT: &str = r#"
|
||||
if (window.location.origin === 'https://tauri.app') {
|
||||
console.log("hello world from js init script");
|
||||
|
||||
window.__MY_CUSTOM_PROPERTY__ = { foo: 'bar' };
|
||||
}
|
||||
"#;
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.setup(|app| {
|
||||
let window = tauri::window::WindowBuilder::new(app, "label").build()?;
|
||||
let webview_builder = tauri::webview::WebviewBuilder::new("label", tauri::WebviewUrl::App("index.html".into()))
|
||||
.initialization_script_for_all_frames(INIT_SCRIPT);
|
||||
let webview = window.add_child(webview_builder, tauri::LogicalPosition::new(0, 0), window.inner_size().unwrap())?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
```
|
||||
"####
|
||||
)]
|
||||
#[must_use]
|
||||
pub fn initialization_script_for_all_frames(mut self, script: &str) -> Self {
|
||||
self
|
||||
.webview_attributes
|
||||
.initialization_scripts
|
||||
.push(InitializationScript {
|
||||
script: script.to_string(),
|
||||
for_main_frame_only: false,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
@@ -765,9 +765,12 @@ impl<R: Runtime, M: Manager<R>> WebviewWindowBuilder<'_, R, M> {
|
||||
/// Adds the provided JavaScript to a list of scripts that should be run after the global object has been created,
|
||||
/// but before the HTML document has been parsed and before any other script included by the HTML document is run.
|
||||
///
|
||||
/// Since it runs on all top-level document and child frame page navigations,
|
||||
/// Since it runs on all top-level document navigations (and also child frame page navigations, if you set `run_only_on_main_frame` to false),
|
||||
/// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
|
||||
///
|
||||
/// This is executed only on the main frame.
|
||||
/// If you only want to run it in all frames, use [Self::initialization_script_for_all_frames] instead.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
@@ -797,6 +800,45 @@ impl<R: Runtime, M: Manager<R>> WebviewWindowBuilder<'_, R, M> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds the provided JavaScript to a list of scripts that should be run after the global object has been created,
|
||||
/// but before the HTML document has been parsed and before any other script included by the HTML document is run.
|
||||
///
|
||||
/// Since it runs on all top-level document navigastions (and also child frame page navigations, if you set `run_only_on_main_frame` to false),
|
||||
/// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
|
||||
///
|
||||
/// This is executed on all frames, main frame and also sub frames.
|
||||
/// If you only want to run it in the main frame, use [Self::initialization_script] instead.
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri::{WebviewWindowBuilder, Runtime};
|
||||
///
|
||||
/// const INIT_SCRIPT: &str = r#"
|
||||
/// if (window.location.origin === 'https://tauri.app') {
|
||||
/// console.log("hello world from js init script");
|
||||
///
|
||||
/// window.__MY_CUSTOM_PROPERTY__ = { foo: 'bar' };
|
||||
/// }
|
||||
/// "#;
|
||||
///
|
||||
/// fn main() {
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let webview = tauri::WebviewWindowBuilder::new(app, "label", tauri::WebviewUrl::App("index.html".into()))
|
||||
/// .initialization_script_for_all_frames(INIT_SCRIPT)
|
||||
/// .build()?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn initialization_script_for_all_frames(mut self, script: &str) -> Self {
|
||||
self.webview_builder = self
|
||||
.webview_builder
|
||||
.initialization_script_for_all_frames(script);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the user agent for the webview
|
||||
#[must_use]
|
||||
pub fn user_agent(mut self, user_agent: &str) -> Self {
|
||||
|
||||
Reference in New Issue
Block a user