Skip to content

Commit

Permalink
feat: add find-in-page, closes #585
Browse files Browse the repository at this point in the history
  • Loading branch information
keiya01 committed May 23, 2022
1 parent 494a110 commit 863a1c5
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changes/add-find-in-page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": minor
---

Add find-in-page feature.
75 changes: 75 additions & 0 deletions examples/find_in_page.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use wry::webview::FindInPageOption;

fn main() -> wry::Result<()> {
use wry::{
application::{
event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
},
webview::WebViewBuilder,
};

#[derive(Debug)]
enum UserEvent {
FindInPage(String),
}

let event_loop: EventLoop<UserEvent> = EventLoop::with_user_event();
let proxy = event_loop.create_proxy();
let window = WindowBuilder::new()
.with_title("Hello World")
.build(&event_loop)?;
let webview = WebViewBuilder::new(window)?
.with_html(
r#"
<input placeholder="Find text"/>
<button>find</button>
<p>Tauri is a toolkit that helps developers make applications for the major desktop platforms - using virtually any frontend framework in existence. The core is built with Rust, and the CLI leverages Node.js making Tauri a genuinely polyglot approach to creating and maintaining great apps. If you want to know more about the technical details, then please visit the Introduction. If you want to know more about this project's philosophy - then keep reading.</p>
<script>
document.querySelector("button").addEventListener("click", () => {
const text = document.querySelector("input").value;
window.ipc.postMessage(text);
});
</script>
"#,
)?
.with_ipc_handler(move |_, text: String| {
proxy
.send_event(UserEvent::FindInPage(text.clone()))
.unwrap();
});

#[cfg(debug_assertions)]
let webview = webview.with_devtools(true);

let webview = webview.build()?;

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;

match event {
Event::NewEvents(StartCause::Init) => println!("Wry has started!"),
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
Event::UserEvent(UserEvent::FindInPage(text)) => {
webview.find_in_page(
text,
FindInPageOption {
case_sensitive: true,
max_match_count: 100,
..FindInPageOption::default()
},
|found| println!("Is found: {}", found),
);
}
_ => (),
}
});
}
8 changes: 7 additions & 1 deletion src/webview/android/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::HashSet, ffi::c_void, ptr::null_mut, rc::Rc, sync::RwLock};

use crate::{application::window::Window, Result};
use crate::{application::window::Window, webview::FindInPageOption, Result};

use super::{WebContext, WebViewAttributes};

Expand Down Expand Up @@ -120,6 +120,12 @@ impl InnerWebView {
}

pub fn zoom(&self, scale_factor: f64) {}

pub fn find_in_page<F>(&self, _string: String, _option: FindInPageOption, _f: F)
where
F: Fn(bool) + 'static,
{
}
}

pub struct UnsafeIpc(*mut c_void);
Expand Down
27 changes: 27 additions & 0 deletions src/webview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,20 @@ impl WebView {
self.webview.zoom(scale_factor);
}

/// Searches for the specified string in the WebView content.
///
/// ## Platform-specific:
///
/// - **Windows / Android**: Not supported.
/// - **macOS**: available on macOS 10.15.4+ only.
/// - **iOS**: available on iOS 13.4+ only.
pub fn find_in_page<F>(&self, string: String, option: FindInPageOption, f: F)
where
F: Fn(bool) + 'static,
{
self.webview.find_in_page(string, option, f);
}

#[cfg(target_os = "android")]
pub fn run(self, env: JNIEnv, jclass: JClass, jobject: JObject) -> jobject {
self.webview.run(env, jclass, jobject).unwrap()
Expand All @@ -528,6 +542,19 @@ impl WebView {
}
}

/// A configuration for `find_in_page`.
#[derive(Default)]
pub struct FindInPageOption {
/// Indicate the search direction.
pub backwards: bool,
/// Match the search string in a case-sensitive.
pub case_sensitive: bool,
/// Wrap around to the other side of the page.
pub wraps: bool,
/// For Linux only, Maximum number of search strings to highlight.
pub max_match_count: u32,
}

/// An event enumeration sent to [`FileDropHandler`].
#[non_exhaustive]
#[derive(Debug, Serialize, Clone)]
Expand Down
43 changes: 41 additions & 2 deletions src/webview/webkitgtk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use gio::Cancellable;
use glib::signal::Inhibit;
use gtk::prelude::*;
use webkit2gtk::{
traits::*, NavigationPolicyDecision, PolicyDecisionType, UserContentInjectedFrames, UserScript,
traits::*, FindController, FindControllerBuilder, FindControllerExt, FindOptions,
NavigationPolicyDecision, PolicyDecisionType, UserContentInjectedFrames, UserScript,
UserScriptInjectionTime, WebView, WebViewBuilder,
};
use webkit2gtk_sys::{
Expand All @@ -31,7 +32,7 @@ pub use web_context::WebContextImpl;

use crate::{
application::{platform::unix::*, window::Window},
webview::{web_context::WebContext, WebViewAttributes},
webview::{web_context::WebContext, FindInPageOption, WebViewAttributes},
Error, Result,
};

Expand All @@ -42,6 +43,7 @@ pub struct InnerWebView {
pub(crate) webview: Rc<WebView>,
#[cfg(any(debug_assertions, feature = "devtools"))]
is_inspector_open: Arc<AtomicBool>,
find_controller: Rc<FindController>,
}

impl InnerWebView {
Expand Down Expand Up @@ -294,10 +296,17 @@ impl InnerWebView {
is_inspector_open
};

let find_controller = {
let builder = FindControllerBuilder::new();
let controller = builder.web_view(&*webview).build();
Rc::new(controller)
};

let w = Self {
webview,
#[cfg(any(debug_assertions, feature = "devtools"))]
is_inspector_open,
find_controller,
};

// Initialize message handler
Expand Down Expand Up @@ -390,6 +399,36 @@ impl InnerWebView {
pub fn zoom(&self, scale_factor: f64) {
WebViewExt::set_zoom_level(&*self.webview, scale_factor);
}

pub fn find_in_page<F>(&self, string: String, option: FindInPageOption, f: F)
where
F: Fn(bool) + 'static,
{
let mut flags = FindOptions::NONE;
if option.backwards {
flags |= FindOptions::BACKWARDS;
}
if !option.case_sensitive {
flags |= FindOptions::CASE_INSENSITIVE;
}
if option.wraps {
flags |= FindOptions::WRAP_AROUND;
}

self
.find_controller
.search(&string, flags.bits(), option.max_match_count);

let handler = Rc::new(Box::new(f));
let found = handler.clone();

self
.find_controller
.connect_failed_to_find_text(move |_| (*handler)(false));
self
.find_controller
.connect_found_text(move |_, _| (*found)(true));
}
}

pub fn platform_webview_version() -> Result<String> {
Expand Down
8 changes: 7 additions & 1 deletion src/webview/webview2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
mod file_drop;

use crate::{
webview::{WebContext, WebViewAttributes},
webview::{FindInPageOption, WebContext, WebViewAttributes},
Error, Result,
};

Expand Down Expand Up @@ -621,6 +621,12 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_
pub fn zoom(&self, scale_factor: f64) {
let _ = unsafe { self.controller.SetZoomFactor(scale_factor) };
}

pub fn find_in_page<F>(&self, _string: String, _option: FindInPageOption, _f: F)
where
F: Fn(bool) + 'static,
{
}
}

pub fn platform_webview_version() -> Result<String> {
Expand Down
19 changes: 18 additions & 1 deletion src/webview/wkwebview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
mod file_drop;
mod web_context;

use block::ConcreteBlock;
pub use web_context::WebContextImpl;

#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -43,7 +44,7 @@ use crate::{
dpi::{LogicalSize, PhysicalSize},
window::Window,
},
webview::{FileDropEvent, WebContext, WebViewAttributes},
webview::{FileDropEvent, FindInPageOption, WebContext, WebViewAttributes},
Result,
};

Expand Down Expand Up @@ -608,6 +609,22 @@ r#"Object.defineProperty(window, 'ipc', {
let _: () = msg_send![self.webview, setPageZoom: scale_factor];
}
}

pub fn find_in_page<F>(&self, string: String, option: FindInPageOption, f: F)
where
F: Fn(bool) + 'static,
{
unsafe {
let config: id = msg_send![class!(WKFindConfiguration), new];
let _: () = msg_send![config, setBackwards: option.backwards];
let _: () = msg_send![config, setCaseSensitive: option.case_sensitive];
let _: () = msg_send![config, setWraps: option.wraps];
let _: () = msg_send![self.webview, findString: NSString::new(&string) withConfiguration: config completionHandler:ConcreteBlock::new(|result: id| {
let match_found: BOOL = msg_send![result, matchFound];
f(match_found == YES);
})];
}
}
}

pub fn platform_webview_version() -> Result<String> {
Expand Down

0 comments on commit 863a1c5

Please sign in to comment.