74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
import diff from "npm:fast-diff";
|
|
import { Packet } from "../proto.ts";
|
|
import { CausalTree, CausalTreeOp } from "../sync/ordt/causal-tree.ts";
|
|
import { PlainTextOperation, PlainTextORDT } from "../sync/ordt/plain-text.ts";
|
|
|
|
const textarea = document.querySelector("textarea")!;
|
|
|
|
const pt = new PlainTextORDT();
|
|
let me: string | undefined = undefined;
|
|
|
|
pt.onevent = event => {
|
|
if (event.at[0] === me) return;
|
|
textarea.value = pt.render()[0];
|
|
};
|
|
|
|
const socket = new WebSocket("/api/connect");
|
|
const initialized = Promise.withResolvers<Packet & { t: "init" }>();
|
|
|
|
socket.addEventListener("message", ev => {
|
|
const packet = JSON.parse(ev.data) as Packet;
|
|
if (packet.t === "init") {
|
|
for (const op of packet.ops) pt.apply(op);
|
|
initialized.resolve(packet);
|
|
} else if (packet.t === "op") {
|
|
pt.apply(packet.op);
|
|
}
|
|
});
|
|
|
|
const initPacket = await initialized.promise;
|
|
me = initPacket.you;
|
|
textarea.value = pt.render()[0];
|
|
|
|
textarea.addEventListener("input", () => {
|
|
const text = pt.render()[0];
|
|
const diffResults = diff(text, textarea.value, textarea.selectionStart);
|
|
let idx = 0;
|
|
for (const [id, str] of diffResults) {
|
|
if (id === diff.INSERT) {
|
|
let parentOp = pt.operations[pt.findOpAtTextIndex(idx)];
|
|
for (const glyph of str) {
|
|
const op: CausalTreeOp<PlainTextOperation> = {
|
|
type: "insert",
|
|
at: [me, ++pt.clock],
|
|
parent: parentOp,
|
|
sequence: glyph,
|
|
};
|
|
|
|
pt.apply(op);
|
|
socket.send(JSON.stringify(CausalTree.toWeakOp(op)));
|
|
|
|
parentOp = op;
|
|
idx += glyph.length;
|
|
}
|
|
}
|
|
if (id === diff.EQUAL) {
|
|
idx += str.length;
|
|
}
|
|
if (id === diff.DELETE) {
|
|
for (const glyph of str) {
|
|
const parentOp = pt.operations[pt.findOpAtTextIndex(idx + glyph.length)];
|
|
const op: CausalTreeOp<PlainTextOperation> = {
|
|
type: "delete",
|
|
at: [me, ++pt.clock],
|
|
parent: parentOp,
|
|
};
|
|
pt.apply(op);
|
|
socket.send(JSON.stringify(CausalTree.toWeakOp(op)));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(globalThis, "pt", { value: pt });
|
|
Object.defineProperty(globalThis, "textarea", { value: textarea });
|