69 lines
2.5 KiB
TypeScript
69 lines
2.5 KiB
TypeScript
/*
|
|||
|
|
Copyright 2026 Lotus Guild
|
||
|
|
|
||
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||
|
|
Please see LICENSE in the repository root for full details.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Shared helpers for the Lotus fork's widget extensions.
|
||
|
|
*
|
||
|
|
* Everything here is **opt-in**: each feature is gated behind a `lotus*` URL
|
||
|
|
* param that the Lotus host (cinny) appends to the widget iframe URL. With no
|
||
|
|
* param present, none of this code changes Element Call's behaviour — which
|
||
|
|
* keeps the fork a minimal, additive, easy-to-rebase diff over upstream.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { logger } from "matrix-js-sdk/lib/logger";
|
||
|
|
|
||
|
|
import { widget } from "../widget";
|
||
|
|
|
||
|
|
/** Custom widget actions used between the Lotus host and this fork. */
|
||
|
|
export enum LotusWidgetActions {
|
||
|
|
/** fromWidget: in-call per-participant speaking / mute state. */
|
||
|
|
CallState = "io.lotus.call_state",
|
||
|
|
/** toWidget: pin/spotlight (or clear) a participant. */
|
||
|
|
FocusParticipant = "io.lotus.focus_participant",
|
||
|
|
/** toWidget: mix an audio clip into the local published mic track. */
|
||
|
|
InjectAudio = "io.lotus.inject_audio",
|
||
|
|
}
|
||
|
|
|
||
|
|
let cachedParams: URLSearchParams | undefined;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Read a URL param from either the query string or the hash fragment (Element
|
||
|
|
* Call passes widget params via both depending on host), without depending on
|
||
|
|
* EC's own `getUrlParams` parser (keeps the rebase surface small).
|
||
|
|
*/
|
||
|
|
export function lotusParam(name: string): string | null {
|
||
|
|
if (!cachedParams) {
|
||
|
|
cachedParams = new URLSearchParams(window.location.search);
|
||
|
|
const hash = window.location.hash.replace(/^#\/?/, "");
|
||
|
|
const hashQuery = hash.includes("?") ? hash.slice(hash.indexOf("?") + 1) : "";
|
||
|
|
for (const [k, v] of new URLSearchParams(hashQuery)) {
|
||
|
|
if (!cachedParams.has(k)) cachedParams.append(k, v);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return cachedParams.get(name);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Whether a boolean-ish Lotus feature flag is enabled. */
|
||
|
|
export function lotusFlag(name: string): boolean {
|
||
|
|
const v = lotusParam(name);
|
||
|
|
return v === "1" || v === "true";
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Send a fromWidget message to the Lotus host, swallowing the inevitable
|
||
|
|
* rejection when the host hasn't (yet) registered a handler for it. Returns
|
||
|
|
* true if the widget transport was available to attempt the send.
|
||
|
|
*/
|
||
|
|
export function lotusSendToHost(action: LotusWidgetActions, data: unknown): boolean {
|
||
|
|
const api = widget?.api;
|
||
|
|
if (!api) return false;
|
||
|
|
void api.transport.send(action, data as Record<string, unknown>).catch((e) => {
|
||
|
|
logger.debug(`[lotus] host did not ack ${action}`, e);
|
||
|
|
});
|
||
|
|
return true;
|
||
|
|
}
|