wip: lots of changes to diffing
This commit is contained in:
1 parent
56e7eb83a9
commit
ff0a3d1c83
24 files changed
+617
-672
No files matched your search
@@ -1,99 +0,0 @@
|
||||
class OPTABLE {
|
||||
PushRoot(self, edit) {
|
||||
const id = edit.root;
|
||||
const node = self.nodes[id];
|
||||
self.stack.push(node);
|
||||
}
|
||||
AppendChild(self, edit) {
|
||||
// todo: prevent merging of text nodes
|
||||
const node = self.pop();
|
||||
self.top().appendChild(node);
|
||||
}
|
||||
ReplaceWith(self, edit) {
|
||||
const newNode = self.pop();
|
||||
const oldNode = self.pop();
|
||||
oldNode.replaceWith(newNode);
|
||||
self.stack.push(newNode);
|
||||
}
|
||||
Remove(self, edit) {
|
||||
const node = self.stack.pop();
|
||||
node.remove();
|
||||
}
|
||||
RemoveAllChildren(self, edit) {
|
||||
// todo - we never actually call this one
|
||||
}
|
||||
CreateTextNode(self, edit) {
|
||||
self.stack.push(document.createTextNode(edit.text));
|
||||
}
|
||||
CreateElement(self, edit) {
|
||||
const tagName = edit.tag;
|
||||
console.log(`creating element! ${edit}`);
|
||||
self.stack.push(document.createElement(tagName));
|
||||
}
|
||||
CreateElementNs(self, edit) {
|
||||
self.stack.push(document.createElementNS(edit.ns, edit.tag));
|
||||
}
|
||||
CreatePlaceholder(self, edit) {
|
||||
self.stack.push(document.createElement("pre"));
|
||||
}
|
||||
NewEventListener(self, edit) {
|
||||
// todo
|
||||
}
|
||||
RemoveEventListener(self, edit) {
|
||||
// todo
|
||||
}
|
||||
SetText(self, edit) {
|
||||
self.top().textContent = edit.text;
|
||||
}
|
||||
SetAttribute(self, edit) {
|
||||
const name = edit.field;
|
||||
const value = edit.value;
|
||||
const node = self.top(self.stack);
|
||||
node.setAttribute(name, value);
|
||||
|
||||
// Some attributes are "volatile" and don't work through `setAttribute`.
|
||||
if ((name === "value", self)) {
|
||||
node.value = value;
|
||||
}
|
||||
if ((name === "checked", self)) {
|
||||
node.checked = true;
|
||||
}
|
||||
if ((name === "selected", self)) {
|
||||
node.selected = true;
|
||||
}
|
||||
}
|
||||
RemoveAttribute(self, edit) {
|
||||
const name = edit.field;
|
||||
const node = self.top(self.stack);
|
||||
node.removeAttribute(name);
|
||||
|
||||
// Some attributes are "volatile" and don't work through `removeAttribute`.
|
||||
if ((name === "value", self)) {
|
||||
node.value = null;
|
||||
}
|
||||
if ((name === "checked", self)) {
|
||||
node.checked = false;
|
||||
}
|
||||
if ((name === "selected", self)) {
|
||||
node.selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// const op_table = new OPTABLE();
|
||||
// const interpreter = new Interpreter(window.document.body);
|
||||
|
||||
// function EditListReceived(rawEditList) {
|
||||
// let editList = JSON.parse(rawEditList);
|
||||
// console.warn("hnelllo");
|
||||
// editList.forEach(function (edit, index) {
|
||||
// console.log(edit);
|
||||
// op_table[edit.type](interpreter, edit);
|
||||
// });
|
||||
// }
|
||||
|
||||
// async function rinalize() {
|
||||
// console.log("initialize...");
|
||||
// let edits = await rpc.call("initiate");
|
||||
// console.error(edits);
|
||||
// }
|
||||
@@ -1,81 +0,0 @@
|
||||
class OPTABLE {
|
||||
PushRoot(self, edit) {
|
||||
const id = edit.root;
|
||||
const node = self.nodes[id];
|
||||
self.stack.push(node);
|
||||
}
|
||||
AppendChild(self, edit) {
|
||||
// todo: prevent merging of text nodes
|
||||
const node = self.pop();
|
||||
self.top().appendChild(node);
|
||||
}
|
||||
ReplaceWith(self, edit) {
|
||||
const newNode = self.pop();
|
||||
const oldNode = self.pop();
|
||||
oldNode.replaceWith(newNode);
|
||||
self.stack.push(newNode);
|
||||
}
|
||||
Remove(self, edit) {
|
||||
const node = self.stack.pop();
|
||||
node.remove();
|
||||
}
|
||||
RemoveAllChildren(self, edit) {
|
||||
// todo - we never actually call this one
|
||||
}
|
||||
CreateTextNode(self, edit) {
|
||||
self.stack.push(document.createTextNode(edit.text));
|
||||
}
|
||||
CreateElement(self, edit) {
|
||||
const tagName = edit.tag;
|
||||
console.log(`creating element! ${edit}`);
|
||||
self.stack.push(document.createElement(tagName));
|
||||
}
|
||||
CreateElementNs(self, edit) {
|
||||
self.stack.push(document.createElementNS(edit.ns, edit.tag));
|
||||
}
|
||||
CreatePlaceholder(self, edit) {
|
||||
self.stack.push(document.createElement("pre"));
|
||||
}
|
||||
NewEventListener(self, edit) {
|
||||
// todo
|
||||
}
|
||||
RemoveEventListener(self, edit) {
|
||||
// todo
|
||||
}
|
||||
SetText(self, edit) {
|
||||
self.top().textContent = edit.text;
|
||||
}
|
||||
SetAttribute(self, edit) {
|
||||
const name = edit.field;
|
||||
const value = edit.value;
|
||||
const node = self.top(self.stack);
|
||||
node.setAttribute(name, value);
|
||||
|
||||
// Some attributes are "volatile" and don't work through `setAttribute`.
|
||||
if ((name === "value", self)) {
|
||||
node.value = value;
|
||||
}
|
||||
if ((name === "checked", self)) {
|
||||
node.checked = true;
|
||||
}
|
||||
if ((name === "selected", self)) {
|
||||
node.selected = true;
|
||||
}
|
||||
}
|
||||
RemoveAttribute(self, edit) {
|
||||
const name = edit.field;
|
||||
const node = self.top(self.stack);
|
||||
node.removeAttribute(name);
|
||||
|
||||
// Some attributes are "volatile" and don't work through `removeAttribute`.
|
||||
if ((name === "value", self)) {
|
||||
node.value = null;
|
||||
}
|
||||
if ((name === "checked", self)) {
|
||||
node.checked = false;
|
||||
}
|
||||
if ((name === "selected", self)) {
|
||||
node.selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,11 +36,11 @@ impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
|
||||
}
|
||||
|
||||
fn append_children(&mut self, many: u32) {
|
||||
self.edits.push(AppendChild);
|
||||
self.edits.push(AppendChildren { many });
|
||||
}
|
||||
|
||||
fn replace_with(&mut self, many: u32) {
|
||||
self.edits.push(ReplaceWith);
|
||||
self.edits.push(ReplaceWith { many });
|
||||
}
|
||||
|
||||
fn remove(&mut self) {
|
||||
|
||||
+139
-126
@@ -3,136 +3,149 @@
|
||||
|
||||
<head>
|
||||
<!-- <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" /> -->
|
||||
|
||||
<script>
|
||||
class Interpreter {
|
||||
constructor(root) {
|
||||
this.stack = [root];
|
||||
this.listeners = {};
|
||||
this.lastNodeWasText = false;
|
||||
this.nodes = {
|
||||
0: root
|
||||
};
|
||||
}
|
||||
|
||||
top() {
|
||||
return this.stack[this.stack.length - 1];
|
||||
}
|
||||
|
||||
pop() {
|
||||
return this.stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
class OPTABLE {
|
||||
PushRoot(self, edit) {
|
||||
const id = edit.root;
|
||||
const node = self.nodes[id];
|
||||
self.stack.push(node);
|
||||
}
|
||||
AppendChildren(self, edit) {
|
||||
let root = self.stack[self.stack.length - (edit.many + 1)];
|
||||
for (let i = 0; i < edit.many; i++) {
|
||||
console.log("popping ", i, edit.many);
|
||||
let node = self.pop();
|
||||
root.appendChild(node);
|
||||
}
|
||||
}
|
||||
ReplaceWith(self, edit) {
|
||||
|
||||
let root = self.stack[self.stack.length - (edit.many + 1)];
|
||||
let els = [];
|
||||
|
||||
for (let i = 0; i < edit.many; i++) {
|
||||
els.push(self.pop());
|
||||
}
|
||||
|
||||
root.replaceWith(...els);
|
||||
}
|
||||
Remove(self, edit) {
|
||||
const node = self.stack.pop();
|
||||
node.remove();
|
||||
}
|
||||
RemoveAllChildren(self, edit) {
|
||||
}
|
||||
CreateTextNode(self, edit) {
|
||||
self.stack.push(document.createTextNode(edit.text));
|
||||
}
|
||||
CreateElement(self, edit) {
|
||||
const tagName = edit.tag;
|
||||
console.log(`creating element: `, edit);
|
||||
self.stack.push(document.createElement(tagName));
|
||||
}
|
||||
CreateElementNs(self, edit) {
|
||||
self.stack.push(document.createElementNS(edit.ns, edit.tag));
|
||||
}
|
||||
CreatePlaceholder(self, edit) {
|
||||
const a = `self.stack.push(document.createElement("pre"))`;
|
||||
self.stack.push(document.createComment("vroot"));
|
||||
}
|
||||
NewEventListener(self, edit) {
|
||||
}
|
||||
RemoveEventListener(self, edit) {
|
||||
}
|
||||
SetText(self, edit) {
|
||||
self.top().textContent = edit.text;
|
||||
}
|
||||
SetAttribute(self, edit) {
|
||||
const name = edit.field;
|
||||
const value = edit.value;
|
||||
const node = self.top(self.stack);
|
||||
node.setAttribute(name, value);
|
||||
|
||||
if ((name === "value", self)) {
|
||||
node.value = value;
|
||||
}
|
||||
if ((name === "checked", self)) {
|
||||
node.checked = true;
|
||||
}
|
||||
if ((name === "selected", self)) {
|
||||
node.selected = true;
|
||||
}
|
||||
}
|
||||
RemoveAttribute(self, edit) {
|
||||
const name = edit.field;
|
||||
const node = self.top(self.stack);
|
||||
node.removeAttribute(name);
|
||||
|
||||
if ((name === "value", self)) {
|
||||
node.value = null;
|
||||
}
|
||||
if ((name === "checked", self)) {
|
||||
node.checked = false;
|
||||
}
|
||||
if ((name === "selected", self)) {
|
||||
node.selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function EditListReceived(rawEditList) {
|
||||
let editList = JSON.parse(rawEditList);
|
||||
console.warn("hnelllo");
|
||||
editList.forEach(function (edit, index) {
|
||||
console.log(edit);
|
||||
op_table[edit.type](interpreter, edit);
|
||||
});
|
||||
}
|
||||
|
||||
const op_table = new OPTABLE();
|
||||
|
||||
async function initialize() {
|
||||
const reply = await rpc.call('initiate');
|
||||
const interpreter = new Interpreter(window.document.getElementById("app").firstChild);
|
||||
console.log(reply);
|
||||
|
||||
for (let x = 0; x < reply.length; x++) {
|
||||
let edit = reply[x];
|
||||
console.log(edit);
|
||||
op_table[edit.type](interpreter, edit);
|
||||
}
|
||||
|
||||
console.log("stack completed: ", interpreter.stack);
|
||||
}
|
||||
console.log("initializing...");
|
||||
initialize();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
<body>
|
||||
<div></div>
|
||||
<div id="app">
|
||||
_
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
class Interpreter {
|
||||
constructor(root) {
|
||||
this.stack = [root];
|
||||
this.listeners = {
|
||||
|
||||
};
|
||||
this.lastNodeWasText = false;
|
||||
this.nodes = {
|
||||
0: root
|
||||
};
|
||||
}
|
||||
|
||||
top() {
|
||||
return this.stack[this.stack.length - 1];
|
||||
}
|
||||
|
||||
pop() {
|
||||
return this.stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class OPTABLE {
|
||||
PushRoot(self, edit) {
|
||||
const id = edit.root;
|
||||
const node = self.nodes[id];
|
||||
self.stack.push(node);
|
||||
}
|
||||
AppendChild(self, edit) {
|
||||
const node = self.pop();
|
||||
self.top().appendChild(node);
|
||||
}
|
||||
ReplaceWith(self, edit) {
|
||||
const newNode = self.pop();
|
||||
const oldNode = self.pop();
|
||||
oldNode.replaceWith(newNode);
|
||||
self.stack.push(newNode);
|
||||
}
|
||||
Remove(self, edit) {
|
||||
const node = self.stack.pop();
|
||||
node.remove();
|
||||
}
|
||||
RemoveAllChildren(self, edit) {
|
||||
}
|
||||
CreateTextNode(self, edit) {
|
||||
self.stack.push(document.createTextNode(edit.text));
|
||||
}
|
||||
CreateElement(self, edit) {
|
||||
const tagName = edit.tag;
|
||||
console.log(`creating element: `, edit);
|
||||
self.stack.push(document.createElement(tagName));
|
||||
}
|
||||
CreateElementNs(self, edit) {
|
||||
self.stack.push(document.createElementNS(edit.ns, edit.tag));
|
||||
}
|
||||
CreatePlaceholder(self, edit) {
|
||||
self.stack.push(document.createElement("pre"));
|
||||
}
|
||||
NewEventListener(self, edit) {
|
||||
}
|
||||
RemoveEventListener(self, edit) {
|
||||
}
|
||||
SetText(self, edit) {
|
||||
self.top().textContent = edit.text;
|
||||
}
|
||||
SetAttribute(self, edit) {
|
||||
const name = edit.field;
|
||||
const value = edit.value;
|
||||
const node = self.top(self.stack);
|
||||
node.setAttribute(name, value);
|
||||
|
||||
if ((name === "value", self)) {
|
||||
node.value = value;
|
||||
}
|
||||
if ((name === "checked", self)) {
|
||||
node.checked = true;
|
||||
}
|
||||
if ((name === "selected", self)) {
|
||||
node.selected = true;
|
||||
}
|
||||
}
|
||||
RemoveAttribute(self, edit) {
|
||||
const name = edit.field;
|
||||
const node = self.top(self.stack);
|
||||
node.removeAttribute(name);
|
||||
|
||||
if ((name === "value", self)) {
|
||||
node.value = null;
|
||||
}
|
||||
if ((name === "checked", self)) {
|
||||
node.checked = false;
|
||||
}
|
||||
if ((name === "selected", self)) {
|
||||
node.selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function EditListReceived(rawEditList) {
|
||||
let editList = JSON.parse(rawEditList);
|
||||
console.warn("hnelllo");
|
||||
editList.forEach(function (edit, index) {
|
||||
console.log(edit);
|
||||
op_table[edit.type](interpreter, edit);
|
||||
});
|
||||
}
|
||||
|
||||
const op_table = new OPTABLE();
|
||||
const interpreter = new Interpreter(window.document.body);
|
||||
|
||||
async function initialize() {
|
||||
const reply = await rpc.call('initiate');
|
||||
console.log(reply);
|
||||
reply.forEach(function (edit, index) {
|
||||
console.log(edit);
|
||||
op_table[edit.type](interpreter, edit);
|
||||
});
|
||||
}
|
||||
console.log("initializing...");
|
||||
initialize();
|
||||
</script>
|
||||
|
||||
|
||||
</html>
|
||||
+25
-11
@@ -47,6 +47,15 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
|
||||
root: FC<T>,
|
||||
props: T,
|
||||
user_builder: impl FnOnce(WindowBuilder) -> WindowBuilder,
|
||||
) -> anyhow::Result<()> {
|
||||
Self::run_with_edits(root, props, user_builder, None)
|
||||
}
|
||||
|
||||
pub fn run_with_edits(
|
||||
root: FC<T>,
|
||||
props: T,
|
||||
user_builder: impl FnOnce(WindowBuilder) -> WindowBuilder,
|
||||
redits: Option<Vec<DomEdit<'static>>>,
|
||||
) -> anyhow::Result<()> {
|
||||
use wry::{
|
||||
application::{
|
||||
@@ -72,21 +81,26 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
|
||||
.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();
|
||||
let edits = if let Some(edits) = &redits {
|
||||
serde_json::to_value(edits).unwrap()
|
||||
} else {
|
||||
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());
|
||||
// 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()
|
||||
// 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());
|
||||
edits
|
||||
};
|
||||
|
||||
// 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)))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user