Something went wrong. Try again.
Rewild Your Web
Something went wrong. Try again.
2.6 kB · 88 lines
JavaScript
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889// SPDX-License-Identifier: AGPL-3.0-or-later
/** * The homescreen's link to the mobile shell. * * The homescreen is carousel tab #0, a real webview. It cannot see the shell's * services and the shell cannot call into it. The one channel between * them is the MessagePort the splash screen already posts in at boot. * * That port is kept open to process 2 messages: * * - `visibility`, so live tiles can suspend when the homescreen is not the * view on screen. The page cannot work this out alone: it is always visible * *within its own webview*, and the container's opacity lives in the shell's * document, not this one. * TODO: check if page visibility can ve used instead. * - `open`, which carries a title. `window.open(url, "_blank")` works and is * the fallback, but the view arrives as an *adopted* webview with no title, * so tabs from the homescreen show up unlabelled. */
class ShellLink extends EventTarget { constructor() { super(); this._port = null; this._ready = false; /* The port and readiness race in both directions: the document can finish rendering before the splash posts the port, or after. Track them apart and let whichever lands second do the send. */ window.addEventListener("message", (event) => { if (event.data?.type === "splash-port" && event.ports?.length) { this._adopt(event.ports[0]); } }); }
_adopt(port) { this._port = port; port.onmessage = (event) => this._receive(event.data); if (this._ready) { this._sendReady(); } }
_receive(message) { if (!message?.type) { return; } this.dispatchEvent(new CustomEvent(message.type, { detail: message })); }
_sendReady() { try { this._port.postMessage({ type: "homescreen-ready" }); } catch (error) { console.error("[Homescreen] Failed to signal ready:", error); } }
/** Dismiss the splash. Safe to call before the port arrives. */ signalReady() { this._ready = true; if (this._port) { this._sendReady(); } }
/** * Open a URL in a new view. */ open(url, title = "") { if (this._port) { try { this._port.postMessage({ type: "open", url, title }); return; } catch (error) { console.warn( "[Homescreen] Port send failed, using window.open:", error, ); } } // No port (or it died): still open the view, just without the title. window.open(url, "_blank"); }}
export const shell = new ShellLink();