2026-04-27 11:33:20 +01:00
|
|
|
/*
|
|
|
|
|
Copyright 2026 Element Creations Ltd.
|
|
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
|
|
|
Please see LICENSE files in the repository root for full details.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-05-18 22:41:38 +01:00
|
|
|
import {
|
|
|
|
|
type ComposerApi as ModuleComposerApi,
|
|
|
|
|
type ComposerApiFileUploadOption,
|
|
|
|
|
type ComposerApiTarget,
|
|
|
|
|
} from "@element-hq/element-web-module-api";
|
|
|
|
|
import { TypedEventEmitter } from "matrix-js-sdk/src/matrix";
|
2026-04-27 11:33:20 +01:00
|
|
|
|
|
|
|
|
import type { MatrixDispatcher } from "../dispatcher/dispatcher";
|
|
|
|
|
import { Action } from "../dispatcher/actions";
|
2026-05-18 22:41:38 +01:00
|
|
|
import { ComposerType, type ComposerInsertPayload } from "../dispatcher/payloads/ComposerInsertPayload";
|
|
|
|
|
import { TimelineRenderingType } from "../contexts/RoomContext";
|
|
|
|
|
import type { ComposerInsertFilesPayload } from "../dispatcher/payloads/ComposerInsertFilePayload";
|
2026-04-27 11:33:20 +01:00
|
|
|
|
2026-05-18 22:41:38 +01:00
|
|
|
export enum ModuleComposerApiEvents {
|
|
|
|
|
UploaderOptionsChanged = "uploaderOptionsChanged",
|
|
|
|
|
}
|
2026-04-27 11:33:20 +01:00
|
|
|
|
2026-05-18 22:41:38 +01:00
|
|
|
interface ModuleComposerApiEventsMap {
|
|
|
|
|
[ModuleComposerApiEvents.UploaderOptionsChanged]: (option: ComposerApiFileUploadOption) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class ComposerApi
|
|
|
|
|
extends TypedEventEmitter<ModuleComposerApiEvents, ModuleComposerApiEventsMap>
|
|
|
|
|
implements ModuleComposerApi
|
|
|
|
|
{
|
|
|
|
|
private readonly configuredFileUploadOptions = new Map<string, ComposerApiFileUploadOption>();
|
|
|
|
|
|
|
|
|
|
public constructor(private readonly dispatcher: MatrixDispatcher) {
|
|
|
|
|
super();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* List of possible file upload options.
|
|
|
|
|
*/
|
|
|
|
|
public get fileUploadOptions(): ComposerApiFileUploadOption[] {
|
|
|
|
|
return [...this.configuredFileUploadOptions.values()];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public addFileUploadOption(option: ComposerApiFileUploadOption): void {
|
|
|
|
|
if (this.configuredFileUploadOptions.has(option.type)) {
|
|
|
|
|
throw new Error(`Option "${option.type}" already exists`);
|
|
|
|
|
}
|
|
|
|
|
if (option.type === "local") {
|
|
|
|
|
throw new Error(`Option "local" is reserved`);
|
|
|
|
|
}
|
|
|
|
|
this.configuredFileUploadOptions.set(option.type, option);
|
|
|
|
|
this.emit(ModuleComposerApiEvents.UploaderOptionsChanged, option);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public openFileUploadConfirmation(files: File[], view: ComposerApiTarget = { view: "room" }): void {
|
|
|
|
|
if (!["room", "thread"].includes(view.view)) {
|
|
|
|
|
throw new Error(`Invalid view '${view.view}'`);
|
|
|
|
|
}
|
|
|
|
|
this.dispatcher.dispatch({
|
|
|
|
|
action: Action.ComposerFileInsert,
|
|
|
|
|
files,
|
|
|
|
|
timelineRenderingType: view.view === "room" ? TimelineRenderingType.Room : TimelineRenderingType.Thread,
|
|
|
|
|
} satisfies ComposerInsertFilesPayload);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public insertPlaintextIntoComposer(plaintext: string, view: ComposerApiTarget = { view: "room" }): void {
|
|
|
|
|
if (!["room", "thread"].includes(view.view)) {
|
|
|
|
|
throw new Error(`Invalid view '${view.view}'`);
|
|
|
|
|
}
|
2026-04-27 11:33:20 +01:00
|
|
|
this.dispatcher.dispatch({
|
|
|
|
|
action: Action.ComposerInsert,
|
|
|
|
|
text: plaintext,
|
2026-05-18 22:41:38 +01:00
|
|
|
timelineRenderingType: view.view === "room" ? TimelineRenderingType.Room : TimelineRenderingType.Thread,
|
|
|
|
|
// We only support send.
|
|
|
|
|
composerType: ComposerType.Send,
|
2026-04-27 11:33:20 +01:00
|
|
|
} satisfies ComposerInsertPayload);
|
|
|
|
|
}
|
|
|
|
|
}
|