Feat: move webview logic into library

This commit is contained in:
Jonathan Kelley committed 2021-02-25 18:44:00 -05:00
1 parent 18a7a1f9c4
commit 32b45e5ba1
10 files changed
+249 -514

No files matched your search

-3
View File
@@ -1,3 +0,0 @@
// This file interperets incoming edit messages into the page and renders them.
// This is written in javascript to be slightly easier to work with (instead of having to pre-compile the wasm)
// One day, we'll probably using wasmbindgen for the inner, but a javascripty one is fine too.
+43 -143
View File
@@ -1,152 +1,52 @@
//! An example where the dioxus vdom is running in a native thread, interacting with webview
//! Content is passed from the native thread into the webview
use std::{
borrow::BorrowMut,
rc::Rc,
sync::{mpsc::channel, Arc},
};
use dioxus_core::prelude::*;
// use async_std::{channel, task::block_on};
use dioxus_core::{dodriodiff::DiffMachine, prelude::bumpalo::Bump, prelude::*, scope};
use scope::Scope;
use web_view::Handle;
static HTML_CONTENT: &'static str = include_str!("./index.html");
enum InnerEvent {
Initiate(Handle<()>),
}
// async_std::task::spawn(async {
// #[async_std::main]
fn main() -> anyhow::Result<()> {
let (sender, receiver) = channel::<InnerEvent>();
// let (sender, receiver) = channel::unbounded::<InnerEvent>();
// let task = async_std::task::spawn(async move {
let mut view = web_view::builder()
.title("My Project")
.content(web_view::Content::Html(HTML_CONTENT))
.size(320, 480)
.resizable(true)
.debug(true)
.user_data(())
.invoke_handler(|view, arg| {
// todo: handle events here
println!("handling invoker");
let handle = view.handle();
sender.send(InnerEvent::Initiate(handle));
Ok(())
})
.build()
.unwrap();
println!("building the diff");
let bump = Bump::new();
let mut diff_machine = DiffMachine::new(&bump);
let old = html! {<div> </div>}(&bump);
// let mut scope = Scope::new(TEST, (), None);
// scope.run::<()>();
let new = html! {
<div>
<div class="flex items-center justify-center flex-col">
<div class="flex items-center justify-center">
<div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
// Title
<div class="font-bold text-xl">
"Jon's awesome site!!11"
</div>
// Subtext / description
<div class="text-sm text-gray-500">
"He worked so hard on it :)"
</div>
<div class="flex flex-row items-center justify-center mt-6">
// Main number
<div class="font-medium text-6xl">
"1337"
fn main(){
dioxus_webview::launch(
// Customize the webview
|builder| {
builder
.title("Test Dioxus App")
.size(320, 480)
.resizable(true)
.debug(true)
},
// Props
(),
// Draw the root component
|ctx, _props| {
ctx.view(html! {
<div>
<div class="flex items-center justify-center flex-col">
<div class="flex items-center justify-center">
<div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
// Title
<div class="font-bold text-xl"> "Jon's awesome site!!11" </div>
// Subtext / description
<div class="text-sm text-gray-500"> "He worked so hard on it :)" </div>
<div class="flex flex-row items-center justify-center mt-6">
// Main number
<div class="font-medium text-6xl">
"1337"
</div>
</div>
// Try another
<div class="flex flex-row justify-between mt-6">
<a href="http://localhost:8080/fib/{}" class="underline">
"Legit made my own React"
</a>
</div>
</div>
</div>
// Try another
<div class="flex flex-row justify-between mt-6">
// <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
"Legit made my own React"
// </a>
</div>
</div>
</div>
</div>
</div>
}(&bump);
diff_machine.diff_node(&old, &new);
let edits = diff_machine.consume();
let ready_edits = serde_json::to_string(&edits)?;
let ref_edits = Arc::new(ready_edits);
loop {
view.step().expect("should not fail");
// if let Some(evt) = receiver.try_recv() {}
if let Ok(event) = receiver.try_recv() {
match event {
InnerEvent::Initiate(handle) => {
// println!("awesome, things worked");
let ediits = ref_edits.clone();
// println!("{}", ediits);
handle
.dispatch(move |view| {
view.eval(format!("EditListReceived(`{}`);", ediits).as_str())?;
Ok(())
})
.expect("Dispatch failed");
// let g = handle.();
}
}
}
// let event = receiver.try_recv();
// view.eval("alert('omg');")?;
// view.step().expect("webview should not fail")?;
}
})
},
).expect("Webview finished");
}
// static TEST: FC<()> = |ctx, props| {
// ctx.view(html! {
// <div>
// <div class="flex items-center justify-center flex-col">
// <div class="flex items-center justify-center">
// <div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
// // Title
// <div class="font-bold text-xl">
// "Jon's awesome site!!11"
// </div>
// // Subtext / description
// <div class="text-sm text-gray-500">
// "He worked so hard on it :)"
// </div>
// <div class="flex flex-row items-center justify-center mt-6">
// // Main number
// <div class="font-medium text-6xl">
// "1337"
// </div>
// </div>
// // Try another
// <div class="flex flex-row justify-between mt-6">
// // <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
// "Legit made my own React"
// // </a>
// </div>
// </div>
// </div>
// </div>
// </div>
// })
// };
-324
View File
@@ -1,324 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
<meta charset="UTF-8" />
<link
href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"
rel="stylesheet"
/>
</head>
<body>
<div></div>
</body>
<script>
// #[derive(Debug, serde::Serialize, serde::Deserialize)]
// pub enum Edit<'d> {
// SetText { text: &'d str },
// RemoveSelfAndNextSiblings {},
// ReplaceWith,
// SetAttribute { name: &'d str, value: &'d str },
// RemoveAttribute { name: &'d str },
// PushReverseChild { n: u32 },
// PopPushChild { n: u32 },
// Pop,
// AppendChild,
// CreateTextNode { text: &'d str },
// CreateElement { tag_name: &'d str },
// NewEventListener { event_type: &'d str, a: u32, b: u32 },
// UpdateEventListener { event_type: &'d str, a: u32, b: u32 },
// RemoveEventListener { event_type: &'d str },
// CreateElementNs { tag_name: &'d str, ns: &'d str },
// SaveChildrenToTemporaries { temp: u32, start: u32, end: u32 },
// PushChild { n: u32 },
// PushTemporary { temp: u32 },
// InsertBefore,
// PopPushReverseChild { n: u32 },
// RemoveChild { n: u32 },
// SetClass { class_name: &'d str },
// }
// const interpreter = new Interpreter();
class Interpreter {
constructor(root) {
this.stack = [root];
}
top() {
return this.stack[this.stack.length - 1];
}
pop() {
return this.stack.pop();
}
}
class OPTABLE {
// 0
SetText(edit, interp) {
interp.top(interp.stack).textContent = edit.text;
}
// 1
RemoveSelfAndNextSiblings(edit) {
const node = interp.pop();
let sibling = node.nextSibling;
while (sibling) {
const temp = sibling.nextSibling;
sibling.remove();
sibling = temp;
}
node.remove();
}
// 2
ReplaceWith(edit, interp) {
const newNode = interp.pop();
const oldNode = interp.pop();
oldNode.replaceWith(newNode);
interp.stack.push(newNode);
}
// 3
SetAttribute(edit, interp) {
const name = edit.name;
const value = edit.value;
const node = interp.top(interp.stack);
node.setAttribute(name, value);
// Some attributes are "volatile" and don't work through `setAttribute`.
if ((name === "value", interp)) {
node.value = value;
}
if ((name === "checked", interp)) {
node.checked = true;
}
if ((name === "selected", interp)) {
node.selected = true;
}
}
// 4
RemoveAttribute(edit, interp) {
const name = edit.name;
const node = interp.top(interp.stack);
node.removeAttribute(name);
// Some attributes are "volatile" and don't work through `removeAttribute`.
if ((name === "value", interp)) {
node.value = null;
}
if ((name === "checked", interp)) {
node.checked = false;
}
if ((name === "selected", interp)) {
node.selected = false;
}
}
// 5
PushReverseChild(edit, interp) {
const n = edit.n;
const parent = interp.top(interp.stack);
const children = parent.childNodes;
const child = children[children.length - n - 1];
interp.stack.push(child);
}
// 6
PopPushChild(edit, interp) {
const n = edit.n;
interp.pop();
const parent = interp.top(interp.stack);
const children = parent.childNodes;
const child = children[n];
interp.stack.push(child);
}
// 7
Pop(edit, interp) {
interp.pop();
}
// 8
AppendChild(edit, interp) {
console.log(interp.stack);
const child = interp.pop();
console.log(interp.stack);
interp.top().appendChild(child);
}
// 9
CreateTextNode(edit, interp) {
// interp.stack.push(document.createTextNode("asd"));
console.log(interp.stack);
interp.stack.push(document.createTextNode(edit.text));
console.log(interp.stack);
}
// 10
CreateElement(edit, interp) {
const tagName = edit.tag_name;
interp.stack.push(document.createElement(tagName));
}
// 11
NewEventListener(edit, interp) {
// todo!
const eventId = mem32[i++];
const eventType = interp.getCachedString(eventId);
const a = mem32[i++];
const b = mem32[i++];
const el = interp.top(interp.stack);
el.addEventListener(eventType, interp.eventHandler);
el[`dodrio-a-${eventType}`] = a;
el[`dodrio-b-${eventType}`] = b;
}
// 12
UpdateEventListener(edit, interp) {
// todo!
const eventId = mem32[i++];
const eventType = interp.getCachedString(eventId);
const el = interp.top(interp.stack);
el[`dodrio-a-${eventType}`] = mem32[i++];
el[`dodrio-b-${eventType}`] = mem32[i++];
}
// 13
RemoveEventListener(edit, interp) {
// todo!
const eventId = mem32[i++];
const eventType = interp.getCachedString(eventId);
const el = interp.top(interp.stack);
el.removeEventListener(eventType, interp.eventHandler);
}
// 14
AddCachedString(edit, interp) {
// todo!
const pointer = mem32[i++];
const length = mem32[i++];
const id = mem32[i++];
const str = string(mem8, pointer, length);
interp.addCachedString(str, id);
}
// 15
DropCachedString(edit, interp) {
// todo!
const id = mem32[i++];
interp.dropCachedString(id);
}
// 16
CreateElementNS(edit, interp) {
// const tagNameId = mem32[i++];
// const tagName = interp.getCachedString(tagNameId);
// const nsId = mem32[i++];
// const ns = interp.getCachedString(nsId);
interp.stack.push(document.createElementNS(edit.ns, edit.tag_name));
}
// 17
SaveChildrenToTemporaries(edit, interp) {
// let temp = mem32[i++];
// const start = mem32[i++];
// const end = mem32[i++];
let temp = edit.temp;
const start = edit.start;
const end = edit.end;
const parent = interp.top(interp.stack);
const children = parent.childNodes;
for (let i = start; i < end; i++, interp) {
interp.temporaries[temp++] = children[i];
}
}
// 18
PushChild(edit, interp) {
const parent = interp.top(interp.stack);
// const n = mem32[i++];
const n = edit.n;
const child = parent.childNodes[n];
interp.stack.push(child);
}
// 19
PushTemporary(edit, interp) {
// const temp = mem32[i++];
const temp = edit.temp;
interp.stack.push(interp.temporaries[temp]);
}
// 20
InsertBefore(edit, interp) {
const before = interp.pop();
const after = interp.pop();
after.parentNode.insertBefore(before, after);
interp.stack.push(before);
}
// 21
PopPushReverseChild(edit, interp) {
// const n = mem32[i++];
const n = edit.n;
interp.pop();
const parent = interp.top(interp.stack);
const children = parent.childNodes;
const child = children[children.length - n - 1];
interp.stack.push(child);
}
// 22
RemoveChild(edit, interp) {
// const n = mem32[i++];
const n = edit.n;
const parent = interp.top(interp.stack);
const child = parent.childNodes[n];
child.remove();
}
// 23
SetClass(edit, interp) {
// const classId = mem32[i++];
const className = edit.class_name;
interp.top(interp.stack).className = className;
}
// 24
SaveTemplate(edit, interp) {
const id = mem32[i++];
const template = interp.top(interp.stack);
interp.saveTemplate(id, template.cloneNode(true));
}
// 25
PushTemplate(edit, interp) {
const id = mem32[i++];
const template = interp.getTemplate(id);
interp.stack.push(template.cloneNode(true));
}
}
let op = new OPTABLE();
const c = window.document.body.firstChild;
console.log("First child");
console.log(c);
const interpreter = new Interpreter(window.document.body);
function EditListReceived(rawEditList) {
let editList = JSON.parse(rawEditList);
console.log(editList);
editList.forEach(function (edit, index) {
// console.log("processing edit");
const name = edit.type;
console.log(name);
const f = op[name];
f(edit, interpreter);
});
}
external.invoke("initiate");
</script>
</html>