examples: webview and async
This commit is contained in:
1 parent
99d94b69ab
commit
eb82051000
13 files changed
+355
-57
No files matched your search
@@ -9,17 +9,32 @@ use dioxus_core::{
|
||||
};
|
||||
use DomEdit::*;
|
||||
|
||||
pub struct WebviewRegistry {}
|
||||
|
||||
impl WebviewRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebviewDom<'bump> {
|
||||
pub edits: Vec<DomEdit<'bump>>,
|
||||
pub node_counter: u64,
|
||||
pub registry: WebviewRegistry,
|
||||
}
|
||||
impl WebviewDom<'_> {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(registry: WebviewRegistry) -> Self {
|
||||
Self {
|
||||
edits: Vec::new(),
|
||||
node_counter: 0,
|
||||
registry,
|
||||
}
|
||||
}
|
||||
|
||||
// Finish using the dom (for its edit list) and give back the node and event registry
|
||||
pub fn consume(self) -> WebviewRegistry {
|
||||
self.registry
|
||||
}
|
||||
}
|
||||
impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
|
||||
fn push_root(&mut self, root: dioxus_core::virtual_dom::RealDomNode) {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
/// Escape a string to pass it into JavaScript.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use web_view::WebView;
|
||||
/// # use std::mem;
|
||||
/// #
|
||||
/// # let mut view: WebView<()> = unsafe { mem::uninitialized() };
|
||||
/// #
|
||||
/// let string = "Hello, world!";
|
||||
///
|
||||
/// // Calls the function callback with "Hello, world!" as its parameter.
|
||||
///
|
||||
/// view.eval(&format!("callback({});", web_view::escape(string)));
|
||||
/// ```
|
||||
pub fn escape(string: &str) -> Escaper {
|
||||
Escaper(string)
|
||||
}
|
||||
|
||||
// "All code points may appear literally in a string literal except for the
|
||||
// closing quote code points, U+005C (REVERSE SOLIDUS), U+000D (CARRIAGE
|
||||
// RETURN), U+2028 (LINE SEPARATOR), U+2029 (PARAGRAPH SEPARATOR), and U+000A
|
||||
// (LINE FEED)." - ES6 Specification
|
||||
|
||||
pub struct Escaper<'a>(&'a str);
|
||||
|
||||
const SPECIAL: &[char] = &[
|
||||
'\n', // U+000A (LINE FEED)
|
||||
'\r', // U+000D (CARRIAGE RETURN)
|
||||
'\'', // U+0027 (APOSTROPHE)
|
||||
'\\', // U+005C (REVERSE SOLIDUS)
|
||||
'\u{2028}', // U+2028 (LINE SEPARATOR)
|
||||
'\u{2029}', // U+2029 (PARAGRAPH SEPARATOR)
|
||||
];
|
||||
|
||||
impl<'a> fmt::Display for Escaper<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let &Escaper(mut string) = self;
|
||||
|
||||
f.write_char('\'')?;
|
||||
|
||||
while !string.is_empty() {
|
||||
if let Some(i) = string.find(SPECIAL) {
|
||||
if i > 0 {
|
||||
f.write_str(&string[..i])?;
|
||||
}
|
||||
|
||||
let mut chars = string[i..].chars();
|
||||
|
||||
f.write_str(match chars.next().unwrap() {
|
||||
'\n' => "\\n",
|
||||
'\r' => "\\r",
|
||||
'\'' => "\\'",
|
||||
'\\' => "\\\\",
|
||||
'\u{2028}' => "\\u2028",
|
||||
'\u{2029}' => "\\u2029",
|
||||
_ => unreachable!(),
|
||||
})?;
|
||||
|
||||
string = chars.as_str();
|
||||
} else {
|
||||
f.write_str(string)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
f.write_char('\'')?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let plain = "ABC \n\r' abc \\ \u{2028} \u{2029}123";
|
||||
let escaped = escape(plain).to_string();
|
||||
assert!(escaped == "'ABC \\n\\r\\' abc \\\\ \\u2028 \\u2029123'");
|
||||
}
|
||||
@@ -5,9 +5,6 @@
|
||||
<!-- <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" /> -->
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
|
||||
<body>
|
||||
<div></div>
|
||||
</body>
|
||||
@@ -16,7 +13,9 @@
|
||||
class Interpreter {
|
||||
constructor(root) {
|
||||
this.stack = [root];
|
||||
this.listeners = {};
|
||||
this.listeners = {
|
||||
|
||||
};
|
||||
this.lastNodeWasText = false;
|
||||
this.nodes = {
|
||||
0: root
|
||||
|
||||
+51
-23
@@ -1,4 +1,5 @@
|
||||
use std::borrow::BorrowMut;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
@@ -10,6 +11,7 @@ use wry::{
|
||||
};
|
||||
|
||||
mod dom;
|
||||
mod escape;
|
||||
|
||||
static HTML_CONTENT: &'static str = include_str!("./index.html");
|
||||
|
||||
@@ -59,33 +61,57 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
|
||||
|
||||
let window = user_builder(WindowBuilder::new()).build(&event_loop)?;
|
||||
|
||||
let mut vdom = VirtualDom::new_with_props(root, props);
|
||||
let mut real_dom = dom::WebviewDom::new();
|
||||
vdom.rebuild(&mut real_dom)?;
|
||||
let vir = VirtualDom::new_with_props(root, props);
|
||||
|
||||
let edits = Arc::new(RwLock::new(Some(serde_json::to_value(real_dom.edits)?)));
|
||||
|
||||
// let ref_edits = Arc::new(serde_json::to_string(&real_dom.edits)?);
|
||||
|
||||
let handler = move |window: &Window, mut req: RpcRequest| {
|
||||
//
|
||||
let d = edits.clone();
|
||||
match req.method.as_str() {
|
||||
"initiate" => {
|
||||
let mut ed = d.write().unwrap();
|
||||
let edits = match ed.as_mut() {
|
||||
Some(ed) => Some(ed.take()),
|
||||
None => None,
|
||||
};
|
||||
Some(RpcResponse::new_result(req.id.take(), edits))
|
||||
}
|
||||
_ => todo!("this message failed"),
|
||||
}
|
||||
};
|
||||
// todo: combine these or something
|
||||
let vdom = Arc::new(RwLock::new(vir));
|
||||
let registry = Arc::new(RwLock::new(Some(WebviewRegistry::new())));
|
||||
|
||||
let webview = WebViewBuilder::new(window)?
|
||||
.with_url(&format!("data:text/html,{}", HTML_CONTENT))?
|
||||
.with_rpc_handler(handler)
|
||||
.with_rpc_handler(move |window: &Window, mut req: RpcRequest| {
|
||||
match req.method.as_str() {
|
||||
"initiate" => {
|
||||
let mut lock = vdom.write().unwrap();
|
||||
let mut reg_lock = registry.write().unwrap();
|
||||
|
||||
// Create the thin wrapper around the registry to collect the edits into
|
||||
let mut real = dom::WebviewDom::new(reg_lock.take().unwrap());
|
||||
|
||||
// Serialize the edit stream
|
||||
let edits = {
|
||||
lock.rebuild(&mut real).unwrap();
|
||||
serde_json::to_value(&real.edits).unwrap()
|
||||
};
|
||||
|
||||
// Give back the registry into its slot
|
||||
*reg_lock = Some(real.consume());
|
||||
|
||||
// Return the edits into the webview runtime
|
||||
Some(RpcResponse::new_result(req.id.take(), Some(edits)))
|
||||
}
|
||||
"user_event" => {
|
||||
let mut lock = vdom.write().unwrap();
|
||||
let mut reg_lock = registry.write().unwrap();
|
||||
|
||||
// Create the thin wrapper around the registry to collect the edits into
|
||||
let mut real = dom::WebviewDom::new(reg_lock.take().unwrap());
|
||||
|
||||
// Serialize the edit stream
|
||||
let edits = {
|
||||
lock.rebuild(&mut real).unwrap();
|
||||
serde_json::to_value(&real.edits).unwrap()
|
||||
};
|
||||
|
||||
// Give back the registry into its slot
|
||||
*reg_lock = Some(real.consume());
|
||||
|
||||
// Return the edits into the webview runtime
|
||||
Some(RpcResponse::new_result(req.id.take(), Some(edits)))
|
||||
}
|
||||
_ => todo!("this message failed"),
|
||||
}
|
||||
})
|
||||
.build()?;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
@@ -173,6 +199,8 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::dom::WebviewRegistry;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct MessageParameters {
|
||||
message: String,
|
||||
|
||||
Reference in new issue
Block a user