Working on getting WKWebView working again - close
This commit is contained in:
parent
c1da7b1b37
commit
e4f96b4ab5
|
@ -69,13 +69,13 @@ pub mod prelude {
|
||||||
pub use crate::networking::URLRequest;
|
pub use crate::networking::URLRequest;
|
||||||
|
|
||||||
pub use crate::window::{
|
pub use crate::window::{
|
||||||
Window, /*WindowController,*/ WindowDelegate
|
Window, WindowConfig, WindowDelegate
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "webview")]
|
#[cfg(feature = "webview")]
|
||||||
pub use crate::webview::{
|
pub use crate::webview::{
|
||||||
WebView, WebViewConfig, WebViewController
|
WebView, WebViewConfig, WebViewDelegate
|
||||||
};
|
};
|
||||||
|
|
||||||
//pub use crate::view::{View, ViewController, ViewDelegate};
|
pub use crate::view::{View, ViewDelegate};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use objc_id::Id;
|
||||||
|
|
||||||
use crate::foundation::{id, NSString};
|
use crate::foundation::{id, NSString};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct URLRequest {
|
pub struct URLRequest {
|
||||||
pub inner: Id<Object>
|
pub inner: Id<Object>
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::{Class, Object};
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use crate::foundation::{id, YES, NO, NSArray, NSString};
|
use crate::foundation::{id, YES, NO, NSArray, NSString};
|
||||||
|
@ -28,6 +28,16 @@ pub use traits::ViewDelegate;
|
||||||
|
|
||||||
pub(crate) static VIEW_DELEGATE_PTR: &str = "rstViewDelegatePtr";
|
pub(crate) static VIEW_DELEGATE_PTR: &str = "rstViewDelegatePtr";
|
||||||
|
|
||||||
|
/// A helper method for instantiating view classes and applying default settings to them.
|
||||||
|
fn allocate_view(registration_fn: fn() -> *const Class) -> id {
|
||||||
|
unsafe {
|
||||||
|
let view: id = msg_send![registration_fn(), new];
|
||||||
|
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||||
|
let _: () = msg_send![view, setWantsLayer:YES];
|
||||||
|
view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A clone-able handler to a `ViewController` reference in the Objective C runtime. We use this
|
/// A clone-able handler to a `ViewController` reference in the Objective C runtime. We use this
|
||||||
/// instead of a stock `View` for easier recordkeeping, since it'll need to hold the `View` on that
|
/// instead of a stock `View` for easier recordkeeping, since it'll need to hold the `View` on that
|
||||||
/// side anyway.
|
/// side anyway.
|
||||||
|
@ -77,12 +87,7 @@ impl Default for View {
|
||||||
impl View {
|
impl View {
|
||||||
/// Returns a default `View`, suitable for
|
/// Returns a default `View`, suitable for
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let view: id = unsafe {
|
let view = allocate_view(register_view_class);
|
||||||
let view: id = msg_send![register_view_class(), new];
|
|
||||||
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
||||||
let _: () = msg_send![view, setWantsLayer:YES];
|
|
||||||
view
|
|
||||||
};
|
|
||||||
|
|
||||||
View {
|
View {
|
||||||
internal_callback_ptr: None,
|
internal_callback_ptr: None,
|
||||||
|
@ -111,11 +116,11 @@ impl<T> View<T> where T: ViewDelegate + 'static {
|
||||||
Rc::into_raw(cloned)
|
Rc::into_raw(cloned)
|
||||||
};
|
};
|
||||||
|
|
||||||
let view = unsafe {
|
let view = allocate_view(register_view_class_with_delegate::<T>);
|
||||||
let view: id = msg_send![register_view_class_with_delegate::<T>(), new];
|
unsafe {
|
||||||
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
//let view: id = msg_send![register_view_class_with_delegate::<T>(), new];
|
||||||
|
//let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||||
(&mut *view).set_ivar(VIEW_DELEGATE_PTR, internal_callback_ptr as usize);
|
(&mut *view).set_ivar(VIEW_DELEGATE_PTR, internal_callback_ptr as usize);
|
||||||
view
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut view = View {
|
let mut view = View {
|
||||||
|
|
|
@ -4,6 +4,7 @@ use objc::{msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use crate::foundation::{id, BOOL, YES, NO, NSInteger};
|
use crate::foundation::{id, BOOL, YES, NO, NSInteger};
|
||||||
use crate::networking::URLRequest;
|
use crate::networking::URLRequest;
|
||||||
|
use crate::webview::enums::NavigationType;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NavigationAction {
|
pub struct NavigationAction {
|
||||||
|
@ -42,7 +43,6 @@ impl NavigationResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub struct OpenPanelParameters {
|
pub struct OpenPanelParameters {
|
||||||
pub allows_directories: bool,
|
pub allows_directories: bool,
|
||||||
|
|
|
@ -12,51 +12,13 @@ use objc::runtime::{Class, Object, Sel};
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use crate::foundation::{id, nil, YES, NO, CGRect, NSString, NSArray, NSInteger};
|
use crate::foundation::{id, nil, YES, NO, CGRect, NSString, NSArray, NSInteger};
|
||||||
use crate::constants::{WEBVIEW_VAR, WEBVIEW_CONFIG_VAR, WEBVIEW_CONTROLLER_PTR};
|
use crate::webview::{WEBVIEW_DELEGATE_PTR, WebViewDelegate};
|
||||||
use crate::geometry::Rect;
|
use crate::webview::actions::{NavigationAction, NavigationResponse, OpenPanelParameters};
|
||||||
use crate::view::traits::ViewController;
|
use crate::webview::enums::{NavigationPolicy, NavigationResponsePolicy};
|
||||||
use crate::webview::action::{NavigationAction, NavigationResponse};
|
|
||||||
use crate::webview::traits::WebViewController;
|
|
||||||
|
|
||||||
/// Loads and configures ye old WKWebView/View for this controller.
|
|
||||||
extern fn load_view<T: ViewController + WebViewController>(this: &mut Object, _: Sel) {
|
|
||||||
unsafe {
|
|
||||||
let configuration: id = *this.get_ivar(WEBVIEW_CONFIG_VAR);
|
|
||||||
|
|
||||||
// Technically private!
|
|
||||||
#[cfg(feature = "webview-downloading")]
|
|
||||||
let process_pool: id = msg_send![configuration, processPool];
|
|
||||||
#[cfg(feature = "webview-downloading")]
|
|
||||||
let _: () = msg_send![process_pool, _setDownloadDelegate:&*this];
|
|
||||||
|
|
||||||
let zero: CGRect = Rect::zero().into();
|
|
||||||
let webview_alloc: id = msg_send![class!(WKWebView), alloc];
|
|
||||||
let webview: id = msg_send![webview_alloc, initWithFrame:zero configuration:configuration];
|
|
||||||
let _: () = msg_send![webview, setWantsLayer:YES];
|
|
||||||
let _: () = msg_send![webview, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
||||||
|
|
||||||
// Provide an easy way to grab this later
|
|
||||||
(*this).set_ivar(WEBVIEW_VAR, webview);
|
|
||||||
|
|
||||||
// Clean this up to be safe, as WKWebView makes a copy and we don't need it anymore.
|
|
||||||
(*this).set_ivar(WEBVIEW_CONFIG_VAR, nil);
|
|
||||||
|
|
||||||
let _: () = msg_send![this, setView:webview];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to connect delegates - doing this in `loadView` can be... bug-inducing.
|
|
||||||
extern fn view_did_load<T: ViewController + WebViewController>(this: &Object, _: Sel) {
|
|
||||||
unsafe {
|
|
||||||
let webview: id = *this.get_ivar(WEBVIEW_VAR);
|
|
||||||
let _: () = msg_send![webview, setNavigationDelegate:&*this];
|
|
||||||
let _: () = msg_send![webview, setUIDelegate:&*this];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called when an `alert()` from the underlying `WKWebView` is fired. Will call over to your
|
/// Called when an `alert()` from the underlying `WKWebView` is fired. Will call over to your
|
||||||
/// `WebViewController`, where you should handle the event.
|
/// `WebViewController`, where you should handle the event.
|
||||||
extern fn alert<T: WebViewController + 'static>(_: &Object, _: Sel, _: id, s: id, _: id, complete: id) {
|
extern fn alert<T: WebViewDelegate>(_: &Object, _: Sel, _: id, s: id, _: id, complete: id) {
|
||||||
let alert = NSString::wrap(s).to_str();
|
let alert = NSString::wrap(s).to_str();
|
||||||
println!("Alert: {}", alert);
|
println!("Alert: {}", alert);
|
||||||
|
|
||||||
|
@ -68,7 +30,7 @@ extern fn alert<T: WebViewController + 'static>(_: &Object, _: Sel, _: id, s: id
|
||||||
}
|
}
|
||||||
|
|
||||||
/*unsafe {
|
/*unsafe {
|
||||||
let ptr: usize = *this.get_ivar(WEBVIEW_CONTROLLER_PTR);
|
let ptr: usize = *this.get_ivar(WEBVIEW_DELEGATE_PTR);
|
||||||
let webview = ptr as *const T;
|
let webview = ptr as *const T;
|
||||||
(*webview).alert(alert);
|
(*webview).alert(alert);
|
||||||
}*/
|
}*/
|
||||||
|
@ -81,21 +43,21 @@ extern fn alert<T: WebViewController + 'static>(_: &Object, _: Sel, _: id, s: id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when a message has been passed from the underlying `WKWebView`.
|
/// Fires when a message has been passed from the underlying `WKWebView`.
|
||||||
extern fn on_message<T: WebViewController + 'static>(this: &Object, _: Sel, _: id, script_message: id) {
|
extern fn on_message<T: WebViewDelegate>(this: &Object, _: Sel, _: id, script_message: id) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let name = NSString::wrap(msg_send![script_message, name]).to_str();
|
let name = NSString::wrap(msg_send![script_message, name]).to_str();
|
||||||
let body = NSString::wrap(msg_send![script_message, body]).to_str();
|
let body = NSString::wrap(msg_send![script_message, body]).to_str();
|
||||||
|
|
||||||
let ptr: usize = *this.get_ivar(WEBVIEW_CONTROLLER_PTR);
|
let ptr: usize = *this.get_ivar(WEBVIEW_DELEGATE_PTR);
|
||||||
let webview = ptr as *const T;
|
let webview = ptr as *const T;
|
||||||
(*webview).on_message(name, body);
|
(*webview).on_message(name, body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
||||||
extern fn decide_policy_for_action<T: WebViewController + 'static>(this: &Object, _: Sel, _: id, action: id, handler: usize) {
|
extern fn decide_policy_for_action<T: WebViewDelegate>(this: &Object, _: Sel, _: id, action: id, handler: usize) {
|
||||||
let webview = unsafe {
|
let webview = unsafe {
|
||||||
let ptr: usize = *this.get_ivar(WEBVIEW_CONTROLLER_PTR);
|
let ptr: usize = *this.get_ivar(WEBVIEW_DELEGATE_PTR);
|
||||||
let webview = ptr as *const T;
|
let webview = ptr as *const T;
|
||||||
&*webview
|
&*webview
|
||||||
};
|
};
|
||||||
|
@ -111,9 +73,9 @@ extern fn decide_policy_for_action<T: WebViewController + 'static>(this: &Object
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
||||||
extern fn decide_policy_for_response<T: WebViewController + 'static>(this: &Object, _: Sel, _: id, response: id, handler: usize) {
|
extern fn decide_policy_for_response<T: WebViewDelegate>(this: &Object, _: Sel, _: id, response: id, handler: usize) {
|
||||||
let webview = unsafe {
|
let webview = unsafe {
|
||||||
let ptr: usize = *this.get_ivar(WEBVIEW_CONTROLLER_PTR);
|
let ptr: usize = *this.get_ivar(WEBVIEW_DELEGATE_PTR);
|
||||||
let webview = ptr as *const T;
|
let webview = ptr as *const T;
|
||||||
&*webview
|
&*webview
|
||||||
};
|
};
|
||||||
|
@ -126,9 +88,9 @@ extern fn decide_policy_for_response<T: WebViewController + 'static>(this: &Obje
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
||||||
extern fn run_open_panel<T: WebViewController + 'static>(this: &Object, _: Sel, _: id, params: id, _: id, handler: usize) {
|
extern fn run_open_panel<T: WebViewDelegate>(this: &Object, _: Sel, _: id, params: id, _: id, handler: usize) {
|
||||||
let webview = unsafe {
|
let webview = unsafe {
|
||||||
let ptr: usize = *this.get_ivar(WEBVIEW_CONTROLLER_PTR);
|
let ptr: usize = *this.get_ivar(WEBVIEW_DELEGATE_PTR);
|
||||||
let webview = ptr as *const T;
|
let webview = ptr as *const T;
|
||||||
&*webview
|
&*webview
|
||||||
};
|
};
|
||||||
|
@ -139,7 +101,7 @@ extern fn run_open_panel<T: WebViewController + 'static>(this: &Object, _: Sel,
|
||||||
match urls {
|
match urls {
|
||||||
Some(u) => {
|
Some(u) => {
|
||||||
let nsurls: NSArray = u.iter().map(|s| {
|
let nsurls: NSArray = u.iter().map(|s| {
|
||||||
let s = NSString::new(&s);
|
let s = NSString::new(s);
|
||||||
msg_send![class!(NSURL), URLWithString:s]
|
msg_send![class!(NSURL), URLWithString:s]
|
||||||
}).collect::<Vec<id>>().into();
|
}).collect::<Vec<id>>().into();
|
||||||
|
|
||||||
|
@ -155,9 +117,9 @@ extern fn run_open_panel<T: WebViewController + 'static>(this: &Object, _: Sel,
|
||||||
/// response is upgraded to BecomeDownload. Only called when explicitly linked since it's a private
|
/// response is upgraded to BecomeDownload. Only called when explicitly linked since it's a private
|
||||||
/// API.
|
/// API.
|
||||||
#[cfg(feature = "webview-downloading")]
|
#[cfg(feature = "webview-downloading")]
|
||||||
extern fn handle_download<T: WebViewController + 'static>(this: &Object, _: Sel, download: id, suggested_filename: id, handler: usize) {
|
extern fn handle_download<T: WebViewDelegate>(this: &Object, _: Sel, download: id, suggested_filename: id, handler: usize) {
|
||||||
let webview = unsafe {
|
let webview = unsafe {
|
||||||
let ptr: usize = *this.get_ivar(WEBVIEW_CONTROLLER_PTR);
|
let ptr: usize = *this.get_ivar(WEBVIEW_DELEGATE_PTR);
|
||||||
let webview = ptr as *const T;
|
let webview = ptr as *const T;
|
||||||
&*webview
|
&*webview
|
||||||
};
|
};
|
||||||
|
@ -179,27 +141,34 @@ extern fn handle_download<T: WebViewController + 'static>(this: &Object, _: Sel,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Registers an `NSViewController` that we effectively turn into a `WebViewController`. Acts as
|
/// Registers an `NSViewController` that we effectively turn into a `WebViewController`. Acts as
|
||||||
/// both a subclass of `NSViewController` and a delegate of the held `WKWebView` (for the various
|
/// both a subclass of `NSViewController` and a delegate of the held `WKWebView` (for the various
|
||||||
/// varieties of delegates needed there).
|
/// varieties of delegates needed there).
|
||||||
pub fn register_controller_class<
|
pub fn register_webview_class() -> *const Class {
|
||||||
T: ViewController + WebViewController + 'static,
|
|
||||||
>() -> *const Class {
|
|
||||||
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
||||||
static INIT: Once = Once::new();
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
INIT.call_once(|| unsafe {
|
||||||
let superclass = Class::get("NSViewController").unwrap();
|
let superclass = class!(WKWebView);
|
||||||
let mut decl = ClassDecl::new("RSTWebViewController", superclass).unwrap();
|
let decl = ClassDecl::new("RSTWebView", superclass).unwrap();
|
||||||
|
VIEW_CLASS = decl.register();
|
||||||
|
});
|
||||||
|
|
||||||
decl.add_ivar::<id>(WEBVIEW_CONFIG_VAR);
|
unsafe { VIEW_CLASS }
|
||||||
decl.add_ivar::<id>(WEBVIEW_VAR);
|
}
|
||||||
decl.add_ivar::<usize>(WEBVIEW_CONTROLLER_PTR);
|
|
||||||
|
|
||||||
// NSViewController
|
/// Registers an `NSViewController` that we effectively turn into a `WebViewController`. Acts as
|
||||||
decl.add_method(sel!(loadView), load_view::<T> as extern fn(&mut Object, _));
|
/// both a subclass of `NSViewController` and a delegate of the held `WKWebView` (for the various
|
||||||
decl.add_method(sel!(viewDidLoad), view_did_load::<T> as extern fn(&Object, _));
|
/// varieties of delegates needed there).
|
||||||
|
pub fn register_webview_delegate_class<T: WebViewDelegate>() -> *const Class {
|
||||||
|
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
||||||
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
|
INIT.call_once(|| unsafe {
|
||||||
|
let superclass = class!(NSObject);
|
||||||
|
let mut decl = ClassDecl::new("RSTWebViewDelegate", superclass).unwrap();
|
||||||
|
|
||||||
|
decl.add_ivar::<usize>(WEBVIEW_DELEGATE_PTR);
|
||||||
|
|
||||||
// WKNavigationDelegate
|
// WKNavigationDelegate
|
||||||
decl.add_method(sel!(webView:decidePolicyForNavigationAction:decisionHandler:), decide_policy_for_action::<T> as extern fn(&Object, _, _, id, usize));
|
decl.add_method(sel!(webView:decidePolicyForNavigationAction:decisionHandler:), decide_policy_for_action::<T> as extern fn(&Object, _, _, id, usize));
|
||||||
|
@ -214,7 +183,7 @@ pub fn register_controller_class<
|
||||||
|
|
||||||
// WKDownloadDelegate is a private class on macOS that handles downloading (saving) files.
|
// WKDownloadDelegate is a private class on macOS that handles downloading (saving) files.
|
||||||
// It's absurd that this is still private in 2020. This probably couldn't get into the app
|
// It's absurd that this is still private in 2020. This probably couldn't get into the app
|
||||||
// store, so... screw it, fine for now.
|
// store, so... screw it, feature-gate it.
|
||||||
#[cfg(feature = "webview-downloading")]
|
#[cfg(feature = "webview-downloading")]
|
||||||
decl.add_method(sel!(_download:decideDestinationWithSuggestedFilename:completionHandler:), handle_download::<T> as extern fn(&Object, _, id, id, usize));
|
decl.add_method(sel!(_download:decideDestinationWithSuggestedFilename:completionHandler:), handle_download::<T> as extern fn(&Object, _, id, id, usize));
|
||||||
|
|
|
@ -5,7 +5,7 @@ use objc_id::Id;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use crate::foundation::{id, YES, NSString};
|
use crate::foundation::{id, YES, NO, NSString};
|
||||||
use crate::webview::enums::InjectAt;
|
use crate::webview::enums::InjectAt;
|
||||||
|
|
||||||
/// A wrapper for `WKWebViewConfiguration`. Holds (retains) pointers for the Objective-C runtime
|
/// A wrapper for `WKWebViewConfiguration`. Holds (retains) pointers for the Objective-C runtime
|
||||||
|
@ -63,4 +63,12 @@ impl WebViewConfig {
|
||||||
let _: () = msg_send![preferences, setValue:yes forKey:key];
|
let _: () = msg_send![preferences, setValue:yes forKey:key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn attach_handlers(&self, target: id) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_inner(self) -> id {
|
||||||
|
&mut *self.objc
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use crate::foundation::NSInteger;
|
use crate::foundation::NSInteger;
|
||||||
|
|
||||||
/// Describes a navigation type from within the `WebView`.
|
/// Describes a navigation type from within the `WebView`.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum NavigationType {
|
pub enum NavigationType {
|
||||||
/// A user activated a link.
|
/// A user activated a link.
|
||||||
LinkActivated,
|
LinkActivated,
|
||||||
|
@ -23,21 +24,21 @@ pub enum NavigationType {
|
||||||
Other
|
Other
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NSInteger> for NavigationType {
|
impl From<NavigationType> for NSInteger {
|
||||||
fn from(i: NSInteger) -> Self {
|
fn from(nav_type: NavigationType) -> Self {
|
||||||
match i {
|
match nav_type {
|
||||||
-1 => NavigationType::Other,
|
NavigationType::Other => -1,
|
||||||
0 => NavigationType::LinkActivated,
|
NavigationType::LinkActivated => 0,
|
||||||
1 => NavigationType::FormSubmitted,
|
NavigationType::FormSubmitted => 1,
|
||||||
2 => NavigationType::BackForward,
|
NavigationType::BackForward => 2,
|
||||||
3 => NavigationType::Reload,
|
NavigationType::Reload => 3,
|
||||||
4 => NavigationType::FormResubmitted,
|
NavigationType::FormResubmitted => 4
|
||||||
e => { panic!("Unsupported navigation type: {}", e); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the policy for a given navigation.
|
/// Describes the policy for a given navigation.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum NavigationPolicy {
|
pub enum NavigationPolicy {
|
||||||
/// Should be canceled.
|
/// Should be canceled.
|
||||||
Cancel,
|
Cancel,
|
||||||
|
@ -47,8 +48,8 @@ pub enum NavigationPolicy {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NavigationPolicy> for NSInteger {
|
impl From<NavigationPolicy> for NSInteger {
|
||||||
fn into(self) -> Self {
|
fn from(policy: NavigationPolicy) -> Self {
|
||||||
match self {
|
match policy {
|
||||||
NavigationPolicy::Cancel => 0,
|
NavigationPolicy::Cancel => 0,
|
||||||
NavigationPolicy::Allow => 1
|
NavigationPolicy::Allow => 1
|
||||||
}
|
}
|
||||||
|
@ -56,6 +57,7 @@ impl From<NavigationPolicy> for NSInteger {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes a response policy for a given navigation.
|
/// Describes a response policy for a given navigation.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum NavigationResponsePolicy {
|
pub enum NavigationResponsePolicy {
|
||||||
/// Should be canceled.
|
/// Should be canceled.
|
||||||
Cancel,
|
Cancel,
|
||||||
|
@ -70,8 +72,8 @@ pub enum NavigationResponsePolicy {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NavigationResponsePolicy> for NSInteger {
|
impl From<NavigationResponsePolicy> for NSInteger {
|
||||||
fn into(self) -> Self {
|
fn from(policy: NavigationResponsePolicy) -> Self {
|
||||||
match self {
|
match policy {
|
||||||
NavigationResponsePolicy::Cancel => 0,
|
NavigationResponsePolicy::Cancel => 0,
|
||||||
NavigationResponsePolicy::Allow => 1,
|
NavigationResponsePolicy::Allow => 1,
|
||||||
|
|
||||||
|
@ -82,6 +84,7 @@ impl From<NavigationResponsePolicy> for NSInteger {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dictates where a given user script should be injected.
|
/// Dictates where a given user script should be injected.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum InjectAt {
|
pub enum InjectAt {
|
||||||
/// Inject at the start of the document.
|
/// Inject at the start of the document.
|
||||||
Start = 0,
|
Start = 0,
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
//! A `WebViewHandle` represents an underlying `WKWebView`. You're passed a reference to one during your
|
|
||||||
//! `WebViewController::did_load()` method. This method is safe to store and use, however as it's
|
|
||||||
//! UI-specific it's not thread safe.
|
|
||||||
//!
|
|
||||||
//! You can use this struct to configure how a view should look and layout. It implements
|
|
||||||
//! AutoLayout - for more information, see the AutoLayout tutorial.
|
|
||||||
|
|
||||||
use objc_id::ShareId;
|
|
||||||
use objc::runtime::Object;
|
|
||||||
use objc::{msg_send, sel, sel_impl};
|
|
||||||
|
|
||||||
use crate::foundation::{id, YES, NSArray, NSString};
|
|
||||||
use crate::color::Color;
|
|
||||||
use crate::constants::BACKGROUND_COLOR;
|
|
||||||
use crate::layout::{Layout, LayoutAnchorX, LayoutAnchorY, LayoutAnchorDimension};
|
|
||||||
use crate::pasteboard::PasteboardType;
|
|
||||||
|
|
||||||
/// A clone-able handler to a `ViewController` reference in the Objective C runtime. We use this
|
|
||||||
/// instead of a stock `WKWebView` for easier recordkeeping, since it'll need to hold the `WKWebView` on that
|
|
||||||
/// side anyway.
|
|
||||||
#[derive(Debug, Default, Clone)]
|
|
||||||
pub struct WebViewHandle {
|
|
||||||
/// A pointer to the Objective-C runtime view controller.
|
|
||||||
pub objc: Option<ShareId<Object>>,
|
|
||||||
|
|
||||||
/// A pointer to the Objective-C runtime top layout constraint.
|
|
||||||
pub top: LayoutAnchorY,
|
|
||||||
|
|
||||||
/// A pointer to the Objective-C runtime leading layout constraint.
|
|
||||||
pub leading: LayoutAnchorX,
|
|
||||||
|
|
||||||
/// A pointer to the Objective-C runtime trailing layout constraint.
|
|
||||||
pub trailing: LayoutAnchorX,
|
|
||||||
|
|
||||||
/// A pointer to the Objective-C runtime bottom layout constraint.
|
|
||||||
pub bottom: LayoutAnchorY,
|
|
||||||
|
|
||||||
/// A pointer to the Objective-C runtime width layout constraint.
|
|
||||||
pub width: LayoutAnchorDimension,
|
|
||||||
|
|
||||||
/// A pointer to the Objective-C runtime height layout constraint.
|
|
||||||
pub height: LayoutAnchorDimension,
|
|
||||||
|
|
||||||
/// A pointer to the Objective-C runtime center X layout constraint.
|
|
||||||
pub center_x: LayoutAnchorX,
|
|
||||||
|
|
||||||
/// A pointer to the Objective-C runtime center Y layout constraint.
|
|
||||||
pub center_y: LayoutAnchorY
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebViewHandle {
|
|
||||||
pub(crate) fn new(object: ShareId<Object>) -> Self {
|
|
||||||
let view: id = unsafe {
|
|
||||||
msg_send![&*object, view]
|
|
||||||
};
|
|
||||||
|
|
||||||
WebViewHandle {
|
|
||||||
objc: Some(object),
|
|
||||||
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
|
|
||||||
leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }),
|
|
||||||
trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }),
|
|
||||||
bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }),
|
|
||||||
width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }),
|
|
||||||
height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }),
|
|
||||||
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
|
||||||
center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,133 +4,222 @@
|
||||||
//! - `WKWebView`
|
//! - `WKWebView`
|
||||||
//! - `WKUIDelegate`
|
//! - `WKUIDelegate`
|
||||||
//! - `WKScriptMessageHandler`
|
//! - `WKScriptMessageHandler`
|
||||||
//! - `NSViewController`
|
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::{Class, Object};
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use crate::foundation::{id, nil, YES, NO, NSString};
|
use crate::foundation::{id, nil, YES, NO, CGRect, NSString};
|
||||||
use crate::constants::WEBVIEW_CONTROLLER_PTR;
|
use crate::geometry::Rect;
|
||||||
use crate::webview::controller::register_controller_class;
|
use crate::layout::{Layout, LayoutAnchorX, LayoutAnchorY, LayoutAnchorDimension};
|
||||||
|
|
||||||
pub mod actions;
|
pub mod actions;
|
||||||
|
pub mod enums;
|
||||||
|
|
||||||
pub(crate) mod controller;
|
pub(crate) mod class;
|
||||||
|
use class::{register_webview_class, register_webview_class_with_delegate};
|
||||||
//pub(crate) mod process_pool;
|
//pub(crate) mod process_pool;
|
||||||
|
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
pub use traits::WebViewController;
|
pub use traits::WebViewDelegate;
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub use config::WebViewConfig;
|
pub use config::WebViewConfig;
|
||||||
|
|
||||||
/// A `View` wraps two different controllers - one on the Objective-C/Cocoa side, which forwards
|
pub(crate) static WEBVIEW_DELEGATE_PTR: &str = "rstWebViewDelegatePtr";
|
||||||
/// calls into your supplied `ViewController` trait object. This involves heap allocation, but all
|
|
||||||
/// of Cocoa is essentially Heap'd, so... well, enjoy.
|
fn allocate_webview(
|
||||||
#[derive(Clone)]
|
config: WebViewConfig,
|
||||||
pub struct WebView<T> {
|
delegate: Option<&Object>
|
||||||
internal_callback_ptr: *const RefCell<T>,
|
) -> id {
|
||||||
pub objc_controller: WebViewHandle,
|
unsafe {
|
||||||
pub controller: Rc<RefCell<T>>
|
let configuration = config.into_inner();
|
||||||
|
|
||||||
|
if let Some(delegate) = objc_delegate {
|
||||||
|
// Technically private!
|
||||||
|
#[cfg(feature = "webview-downloading")]
|
||||||
|
let process_pool: id = msg_send![configuration, processPool];
|
||||||
|
#[cfg(feature = "webview-downloading")]
|
||||||
|
let _: () = msg_send![process_pool, _setDownloadDelegate:*delegate];
|
||||||
|
|
||||||
|
// add handlers
|
||||||
|
for
|
||||||
|
}
|
||||||
|
|
||||||
|
let zero: CGRect = Rect::zero().into();
|
||||||
|
let webview_alloc: id = msg_send![register_webview_class(), alloc];
|
||||||
|
let webview: id = msg_send![webview_alloc, initWithFrame:zero configuration:configuration];
|
||||||
|
|
||||||
|
let _: () = msg_send![webview, setWantsLayer:YES];
|
||||||
|
let _: () = msg_send![webview, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||||
|
let _: () = msg_send![webview, setNavigationDelegate:webview];
|
||||||
|
let _: () = msg_send![webview, setUIDelegate:webview];
|
||||||
|
|
||||||
|
webview
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> WebView<T> where T: WebViewController + 'static {
|
pub struct WebView<T = ()> {
|
||||||
/// Allocates and configures a `ViewController` in the Objective-C/Cocoa runtime that maps over
|
/// A pointer to the Objective-C runtime view controller.
|
||||||
/// to your supplied view controller.
|
pub objc: ShareId<Object>,
|
||||||
pub fn new(controller: T) -> Self {
|
|
||||||
let config = controller.config();
|
/// We need to store the underlying delegate separately from the `WKWebView` - this is a where
|
||||||
let controller = Rc::new(RefCell::new(controller));
|
/// we do so.
|
||||||
|
pub objc_delegate: Option<ShareId<Object>>,
|
||||||
|
|
||||||
|
/// An internal callback pointer that we use in delegate loopbacks. Default implementations
|
||||||
|
/// don't require this.
|
||||||
|
pub(crate) internal_callback_ptr: Option<*const RefCell<T>>,
|
||||||
|
|
||||||
|
/// A pointer to the delegate for this view.
|
||||||
|
pub delegate: Option<Rc<RefCell<T>>>,
|
||||||
|
|
||||||
|
/// A pointer to the Objective-C runtime top layout constraint.
|
||||||
|
pub top: LayoutAnchorY,
|
||||||
|
|
||||||
|
/// A pointer to the Objective-C runtime leading layout constraint.
|
||||||
|
pub leading: LayoutAnchorX,
|
||||||
|
|
||||||
|
/// A pointer to the Objective-C runtime trailing layout constraint.
|
||||||
|
pub trailing: LayoutAnchorX,
|
||||||
|
|
||||||
|
/// A pointer to the Objective-C runtime bottom layout constraint.
|
||||||
|
pub bottom: LayoutAnchorY,
|
||||||
|
|
||||||
|
/// A pointer to the Objective-C runtime width layout constraint.
|
||||||
|
pub width: LayoutAnchorDimension,
|
||||||
|
|
||||||
|
/// A pointer to the Objective-C runtime height layout constraint.
|
||||||
|
pub height: LayoutAnchorDimension,
|
||||||
|
|
||||||
|
/// A pointer to the Objective-C runtime center X layout constraint.
|
||||||
|
pub center_x: LayoutAnchorX,
|
||||||
|
|
||||||
|
/// A pointer to the Objective-C runtime center Y layout constraint.
|
||||||
|
pub center_y: LayoutAnchorY
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WebView {
|
||||||
|
fn default() -> Self {
|
||||||
|
WebView::new(WebViewConfig::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebView {
|
||||||
|
pub fn new(config: WebViewConfig) -> Self {
|
||||||
|
let view = allocate_webview(register_webview_class, config, None);
|
||||||
|
|
||||||
|
WebView {
|
||||||
|
internal_callback_ptr: None,
|
||||||
|
delegate: None,
|
||||||
|
objc_delegate: None,
|
||||||
|
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
|
||||||
|
leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }),
|
||||||
|
trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }),
|
||||||
|
bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }),
|
||||||
|
width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }),
|
||||||
|
height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }),
|
||||||
|
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
||||||
|
center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }),
|
||||||
|
objc: unsafe { ShareId::from_ptr(view) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> WebView<T> where T: WebViewDelegate + 'static {
|
||||||
|
/// Initializes a new WebView with a given `WebViewDelegate`. This enables you to respond to events
|
||||||
|
/// and customize the view as a module, similar to class-based systems.
|
||||||
|
pub fn with(config: WebViewConfig, delegate: T) -> WebView<T> {
|
||||||
|
let delegate = Rc::new(RefCell::new(delegate));
|
||||||
|
|
||||||
let internal_callback_ptr = {
|
let internal_callback_ptr = {
|
||||||
let cloned = Rc::clone(&controller);
|
let cloned = Rc::clone(&delegate);
|
||||||
Rc::into_raw(cloned)
|
Rc::into_raw(cloned)
|
||||||
};
|
};
|
||||||
|
|
||||||
let handle = WebViewHandle::new(unsafe {
|
let objc_delegate = unsafe {
|
||||||
let view_controller: id = msg_send![register_controller_class::<T>(), new];
|
let objc_delegate: id = msg_send![register_webview_delegate_class::<T>, new];
|
||||||
(&mut *view_controller).set_ivar(WEBVIEW_CONTROLLER_PTR, internal_callback_ptr as usize);
|
(&mut *objc_delegate).set_ivar(WEBVIEW_DELEGATE_PTR, internal_callback_ptr as usize);
|
||||||
|
ShareId::from_ptr(objc_delegate)
|
||||||
// WKWebView isn't really great to subclass, so we don't bother here unlike other
|
};
|
||||||
// widgets in this framework. Just set and forget.
|
|
||||||
let frame: CGRect = Rect::zero().into();
|
let view = allocate_webview(config, Some(&objc_delegate));
|
||||||
let alloc: id = msg_send![class!(WKWebView), alloc];
|
|
||||||
let view: id = msg_send![alloc, initWithFrame:frame configuration:&*config.0];
|
let mut view = WebView {
|
||||||
let _: () = msg_send![&*view_controller, setView:view];
|
internal_callback_ptr: Some(internal_callback_ptr),
|
||||||
|
delegate: None,
|
||||||
ShareId::from_ptr(view_controller)
|
objc_delegate: Some(objc_delegate),
|
||||||
});
|
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
|
||||||
|
leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }),
|
||||||
|
trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }),
|
||||||
|
bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }),
|
||||||
|
width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }),
|
||||||
|
height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }),
|
||||||
|
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
||||||
|
center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }),
|
||||||
|
objc: unsafe { ShareId::from_ptr(view) },
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut vc = controller.borrow_mut();
|
let mut delegate = delegate.borrow_mut();
|
||||||
(*vc).did_load(handle.clone());
|
(*delegate).did_load(view.clone_as_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
WebView {
|
view.delegate = Some(delegate);
|
||||||
internal_callback_ptr: internal_callback_ptr,
|
view
|
||||||
objc_controller: handle,
|
|
||||||
controller: controller
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_background_color(&self, color: Color) {
|
|
||||||
self.objc_controller.set_background_color(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_for_dragged_types(&self, types: &[PasteboardType]) {
|
|
||||||
self.objc_controller.register_for_dragged_types(types);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top(&self) -> &LayoutAnchorY {
|
|
||||||
&self.objc_controller.top
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn leading(&self) -> &LayoutAnchorX {
|
|
||||||
&self.objc_controller.leading
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trailing(&self) -> &LayoutAnchorX {
|
|
||||||
&self.objc_controller.trailing
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bottom(&self) -> &LayoutAnchorY {
|
|
||||||
&self.objc_controller.bottom
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn width(&self) -> &LayoutAnchorDimension {
|
|
||||||
&self.objc_controller.width
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn height(&self) -> &LayoutAnchorDimension {
|
|
||||||
&self.objc_controller.height
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Layout for View<T> {
|
impl<T> WebView<T> {
|
||||||
|
/// An internal method that returns a clone of this object, sans references to the delegate or
|
||||||
|
/// callback pointer. We use this in calling `did_load()` - implementing delegates get a way to
|
||||||
|
/// reference, customize and use the view but without the trickery of holding pieces of the
|
||||||
|
/// delegate - the `View` is the only true holder of those.
|
||||||
|
pub(crate) fn clone_as_handle(&self) -> WebView {
|
||||||
|
WebView {
|
||||||
|
internal_callback_ptr: None,
|
||||||
|
delegate: None,
|
||||||
|
top: self.top.clone(),
|
||||||
|
leading: self.leading.clone(),
|
||||||
|
trailing: self.trailing.clone(),
|
||||||
|
bottom: self.bottom.clone(),
|
||||||
|
width: self.width.clone(),
|
||||||
|
height: self.height.clone(),
|
||||||
|
center_x: self.center_x.clone(),
|
||||||
|
center_y: self.center_y.clone(),
|
||||||
|
objc: self.objc.clone(),
|
||||||
|
objc_delegate: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Layout for WebView<T> {
|
||||||
/// Returns the Objective-C object used for handling the view heirarchy.
|
/// Returns the Objective-C object used for handling the view heirarchy.
|
||||||
fn get_backing_node(&self) -> Option<ShareId<Object>> {
|
fn get_backing_node(&self) -> ShareId<Object> {
|
||||||
self.objc_controller.objc.clone()
|
self.objc.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_subview<V: Layout>(&self, subview: &V) {
|
fn add_subview<V: Layout>(&self, subview: &V) {
|
||||||
self.objc_controller.add_subview(subview);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::fmt::Debug for View<T> {
|
impl<T> std::fmt::Debug for WebView<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "View ({:p})", self)
|
write!(f, "WebView ({:p})", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for View<T> {
|
impl<T> Drop for WebView<T> {
|
||||||
/// A bit of extra cleanup for delegate callback pointers.
|
/// A bit of extra cleanup for delegate callback pointers.
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = Rc::from_raw(self.internal_callback_ptr);
|
if let Some(ptr) = self.internal_callback_ptr {
|
||||||
|
let _ = Rc::from_raw(ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,16 @@
|
||||||
//! `WKWebView`. It allows you to do things such as handle opening a file (for uploads or
|
//! `WKWebView`. It allows you to do things such as handle opening a file (for uploads or
|
||||||
//! in-browser-processing), handling navigation actions or JS message callbacks, and so on.
|
//! in-browser-processing), handling navigation actions or JS message callbacks, and so on.
|
||||||
|
|
||||||
use crate::webview::config::WebViewConfig;
|
use crate::webview::WebView;
|
||||||
use crate::webview::enums::{
|
use crate::webview::actions::{NavigationAction, NavigationResponse, OpenPanelParameters};
|
||||||
NavigationAction, NavigationPolicy,
|
use crate::webview::enums::{NavigationPolicy, NavigationResponsePolicy};
|
||||||
NavigationResponse, NavigationResponsePolicy,
|
|
||||||
OpenPanelParameters
|
|
||||||
};
|
|
||||||
use crate::webview::handle::WebViewHandle;
|
|
||||||
|
|
||||||
/// You can implement this on structs to handle callbacks from the underlying `WKWebView`.
|
/// You can implement this on structs to handle callbacks from the underlying `WKWebView`.
|
||||||
pub trait WebViewController {
|
pub trait WebViewDelegate {
|
||||||
/// Due to a quirk in how the underlying `WKWebView` works, the configuration object must be
|
|
||||||
/// set up before initializing anything. To enable this, you can implement this method and
|
|
||||||
/// return whatever `WebViewConfig` object you want.
|
|
||||||
///
|
|
||||||
/// By default, this returns `WebViewConfig::default()`.
|
|
||||||
fn configure(&mut self) -> WebViewConfig { WebViewConfig::default() }
|
|
||||||
|
|
||||||
/// Called when the View is ready to work with. You're passed a `ViewHandle` - this is safe to
|
/// Called when the View is ready to work with. You're passed a `ViewHandle` - this is safe to
|
||||||
/// store and use repeatedly, but it's not thread safe - any UI calls must be made from the
|
/// store and use repeatedly, but it's not thread safe - any UI calls must be made from the
|
||||||
/// main thread!
|
/// main thread!
|
||||||
fn did_load(&mut self, _view: WebViewHandle) {}
|
fn did_load(&mut self, _webview: WebView) {}
|
||||||
|
|
||||||
/// Called when this is about to be added to the view heirarchy.
|
/// Called when this is about to be added to the view heirarchy.
|
||||||
fn will_appear(&self) {}
|
fn will_appear(&self) {}
|
||||||
|
|
Loading…
Reference in a new issue