Skip to content

Commit

Permalink
feat: plugin::Builder closes #2959 (#3005)
Browse files Browse the repository at this point in the history
Co-authored-by: Amr Bashir <48618675+amrbashir@users.noreply.github.com>
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
  • Loading branch information
3 people committed Feb 7, 2022
1 parent 10e3190 commit 9aed299
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changes/plugin-builder.md
@@ -0,0 +1,5 @@
---
"tauri": minor
---

Add a `plugin::Builder` struct to make plugin creation more convenient.
143 changes: 141 additions & 2 deletions core/tauri/src/plugin.rs
Expand Up @@ -5,8 +5,8 @@
//! The Tauri plugin extension to expand Tauri functionality.

use crate::{
runtime::Runtime, utils::config::PluginConfig, AppHandle, Invoke, PageLoadPayload, RunEvent,
Window,
runtime::Runtime, utils::config::PluginConfig, AppHandle, Invoke, InvokeHandler, OnPageLoad,
PageLoadPayload, RunEvent, Window,
};
use serde_json::Value as JsonValue;
use tauri_macros::default_runtime;
Expand Down Expand Up @@ -53,6 +53,145 @@ pub trait Plugin<R: Runtime>: Send {
fn extend_api(&mut self, invoke: Invoke<R>) {}
}

type SetupHook<R> = dyn Fn(&AppHandle<R>) -> Result<()> + Send + Sync;
type OnWebviewReady<R> = dyn Fn(Window<R>) + Send + Sync;
type OnEvent<R> = dyn Fn(&AppHandle<R>, &RunEvent) + Send + Sync;

/// Builds a [`TauriPlugin`].
pub struct Builder<R: Runtime> {
name: &'static str,
invoke_handler: Box<InvokeHandler<R>>,
setup: Box<SetupHook<R>>,
js_init_script: Option<String>,
on_page_load: Box<OnPageLoad<R>>,
on_webview_ready: Box<OnWebviewReady<R>>,
on_event: Box<OnEvent<R>>,
}

impl<R: Runtime> Builder<R> {
/// Creates a new Plugin builder.
pub fn new(name: &'static str) -> Self {
Self {
name,
setup: Box::new(|_| Ok(())),
js_init_script: None,
invoke_handler: Box::new(|_| ()),
on_page_load: Box::new(|_, _| ()),
on_webview_ready: Box::new(|_| ()),
on_event: Box::new(|_, _| ()),
}
}

/// Defines the JS message handler callback.
pub fn invoke_handler<F>(mut self, invoke_handler: F) -> Self
where
F: Fn(Invoke<R>) + Send + Sync + 'static,
{
self.invoke_handler = Box::new(invoke_handler);
self
}

/// The JS script to evaluate on webview initialization.
/// The script is wrapped into its own context with `(function () { /* your script here */ })();`,
/// so global variables must be assigned to `window` instead of implicity declared.
///
/// It's guaranteed that this script is executed before the page is loaded.
pub fn js_init_script(mut self, js_init_script: String) -> Self {
self.js_init_script = Some(js_init_script);
self
}

/// Define a closure that can setup plugin specific state.
pub fn setup<F>(mut self, setup: F) -> Self
where
F: Fn(&AppHandle<R>) -> Result<()> + Send + Sync + 'static,
{
self.setup = Box::new(setup);
self
}

/// Callback invoked when the webview performs a navigation to a page.
pub fn on_page_load<F>(mut self, on_page_load: F) -> Self
where
F: Fn(Window<R>, PageLoadPayload) + Send + Sync + 'static,
{
self.on_page_load = Box::new(on_page_load);
self
}

/// Callback invoked when the webview is created.
pub fn on_webview_ready<F>(mut self, on_webview_ready: F) -> Self
where
F: Fn(Window<R>) + Send + Sync + 'static,
{
self.on_webview_ready = Box::new(on_webview_ready);
self
}

/// Callback invoked when the event loop receives a new event.
pub fn on_event<F>(mut self, on_event: F) -> Self
where
F: Fn(&AppHandle<R>, &RunEvent) + Send + Sync + 'static,
{
self.on_event = Box::new(on_event);
self
}

/// Builds the [TauriPlugin].
pub fn build(self) -> TauriPlugin<R> {
TauriPlugin {
name: self.name,
invoke_handler: self.invoke_handler,
setup: self.setup,
js_init_script: self.js_init_script,
on_page_load: self.on_page_load,
on_webview_ready: self.on_webview_ready,
on_event: self.on_event,
}
}
}

/// Plugin struct that is returned by the [`PluginBuilder`]. Should only be constructed through the builder.
pub struct TauriPlugin<R: Runtime> {
name: &'static str,
invoke_handler: Box<InvokeHandler<R>>,
setup: Box<SetupHook<R>>,
js_init_script: Option<String>,
on_page_load: Box<OnPageLoad<R>>,
on_webview_ready: Box<OnWebviewReady<R>>,
on_event: Box<OnEvent<R>>,
}

impl<R: Runtime> Plugin<R> for TauriPlugin<R> {
fn name(&self) -> &'static str {
self.name
}

fn initialize(&mut self, app: &AppHandle<R>, _: JsonValue) -> Result<()> {
(self.setup)(app)
}

fn initialization_script(&self) -> Option<String> {
self.js_init_script.clone()
}

fn created(&mut self, window: Window<R>) {
(self.on_webview_ready)(window)
}

fn on_page_load(&mut self, window: Window<R>, payload: PageLoadPayload) {
(self.on_page_load)(window, payload)
}

fn on_event(&mut self, app: &AppHandle<R>, event: &RunEvent) {
(self.on_event)(app, event)
}

fn extend_api(&mut self, invoke: Invoke<R>) {
(self.invoke_handler)(invoke)
}
}

/// Plugin collection type.
#[default_runtime(crate::Wry, wry)]
pub(crate) struct PluginStore<R: Runtime> {
Expand Down

0 comments on commit 9aed299

Please sign in to comment.