motr/pkg/embed/main.js

159 lines
4.3 KiB
JavaScript

// MessageChannel for WASM communication
let wasmChannel;
let wasmPort;
async function initWasmChannel() {
wasmChannel = new MessageChannel();
wasmPort = wasmChannel.port1;
// Setup message handling from WASM
wasmPort.onmessage = (event) => {
const { type, data } = event.data;
switch (type) {
case "WASM_READY":
console.log("WASM is ready");
document.dispatchEvent(new CustomEvent("wasm-ready"));
break;
case "RESPONSE":
handleWasmResponse(data);
break;
case "SYNC_COMPLETE":
handleSyncComplete(data);
break;
}
};
}
// Initialize WebAssembly and Service Worker
async function init() {
try {
// Register service worker
if ("serviceWorker" in navigator) {
const registration = await navigator.serviceWorker.register("./sw.js");
console.log("ServiceWorker registered");
// Wait for the service worker to be ready
await navigator.serviceWorker.ready;
// Initialize MessageChannel
await initWasmChannel();
// Send the MessageChannel port to the service worker
navigator.serviceWorker.controller.postMessage(
{
type: "PORT_INITIALIZATION",
port: wasmChannel.port2,
},
[wasmChannel.port2],
);
// Register for periodic sync if available
if ("periodicSync" in registration) {
try {
await registration.periodicSync.register("wasm-sync", {
minInterval: 24 * 60 * 60 * 1000, // 24 hours
});
} catch (error) {
console.log("Periodic sync could not be registered:", error);
}
}
}
// Initialize HTMX with custom config
htmx.config.withCredentials = true;
htmx.config.wsReconnectDelay = "full-jitter";
// Override HTMX's internal request handling
htmx.config.beforeRequest = function (config) {
// Add request ID for tracking
const requestId = "req_" + Date.now();
config.headers["X-Wasm-Request-ID"] = requestId;
// If offline, handle through service worker
if (!navigator.onLine) {
return false; // Let service worker handle it
}
return true;
};
// Handle HTMX after request
htmx.config.afterRequest = function (config) {
// Additional processing after request if needed
};
// Handle HTMX errors
htmx.config.errorHandler = function (error) {
console.error("HTMX Error:", error);
};
} catch (error) {
console.error("Initialization failed:", error);
}
}
function handleWasmResponse(data) {
const { requestId, response } = data;
// Process the WASM response
// This might update the UI or trigger HTMX swaps
const targetElement = document.querySelector(
`[data-request-id="${requestId}"]`,
);
if (targetElement) {
htmx.process(targetElement);
}
}
function handleSyncComplete(data) {
const { url } = data;
// Handle successful sync
// Maybe refresh the relevant part of the UI
htmx.trigger("body", "sync:complete", { url });
}
// Handle offline status changes
window.addEventListener("online", () => {
document.body.classList.remove("offline");
// Trigger sync when back online
if (wasmPort) {
wasmPort.postMessage({ type: "SYNC_REQUEST" });
}
});
window.addEventListener("offline", () => {
document.body.classList.add("offline");
});
// Custom event handlers for HTMX
document.addEventListener("htmx:beforeRequest", (event) => {
const { elt, xhr } = event.detail;
// Add request tracking
const requestId = xhr.headers["X-Wasm-Request-ID"];
elt.setAttribute("data-request-id", requestId);
});
document.addEventListener("htmx:afterRequest", (event) => {
const { elt, successful } = event.detail;
if (successful) {
elt.removeAttribute("data-request-id");
}
});
// Initialize everything when the page loads
document.addEventListener("DOMContentLoaded", init);
// Export functions that might be needed by WASM
window.wasmBridge = {
triggerUIUpdate: function (selector, content) {
const target = document.querySelector(selector);
if (target) {
htmx.process(
htmx.parse(content).forEach((node) => target.appendChild(node)),
);
}
},
showNotification: function (message, type = "info") {
// Implement notification system
console.log(`${type}: ${message}`);
},
};