Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Add customisation point for declaring widget variables
Browse files Browse the repository at this point in the history
Fixes element-hq/element-web#18035 (indirectly; issue is on a non-standard version of Element).

This has an isReady() step because the variable usage code path cannot be made async, so instead we let the async loading state happen in the prepare() stage. This is required for the intended usecase.
  • Loading branch information
turt2live committed Jul 26, 2021
1 parent 86a4e3a commit 9d5472d
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 3 deletions.
53 changes: 53 additions & 0 deletions src/customisations/WidgetVariables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Populate this class with the details of your customisations when copying it.
import { ITemplateParams } from "matrix-widget-api";

/**
* Provides a partial set of the variables needed to render any widget. If
* variables are missing or not provided then they will be filled with the
* application-determined defaults.
*
* This will not be called until after isReady() resolves.
* @returns {Partial<Omit<ITemplateParams, "widgetRoomId">>} The variables.
*/
function provideVariables(): Partial<Omit<ITemplateParams, "widgetRoomId">> {
return {};
}

/**
* Resolves to whether or not the customisation point is ready for variables
* to be provided. This will block widgets being rendered.
* @returns {Promise<boolean>} Resolves when ready.
*/
async function isReady(): Promise<void> {
return; // default no waiting
}

// This interface summarises all available customisation points and also marks
// them all as optional. This allows customisers to only define and export the
// customisations they need while still maintaining type safety.
export interface IWidgetVariablesCustomisations {
provideVariables?: typeof provideVariables;

// If not provided, the app will assume that the customisation is always ready.
isReady?: typeof isReady;
}

// A real customisation module will define and export one or more of the
// customisation points that make up the interface above.
export const WidgetVariableCustomisations: IWidgetVariablesCustomisations = {};
17 changes: 14 additions & 3 deletions src/stores/widgets/StopGapWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ import {getCustomTheme} from "../../theme";
import CountlyAnalytics from "../../CountlyAnalytics";
import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { ELEMENT_CLIENT_ID } from "../../identifiers";
import { getUserLanguage } from "../../languageHandler";
import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables";

// TODO: Destroy all of this code

Expand Down Expand Up @@ -188,13 +191,18 @@ export class StopGapWidget extends EventEmitter {
return this.runUrlTemplate({asPopout: true});
}

private runUrlTemplate(opts = {asPopout: false}): string {
const templated = this.mockWidget.getCompleteUrl({
private runUrlTemplate(opts = { asPopout: false }): string {
const fromCustomisation = WidgetVariableCustomisations?.provideVariables?.() ?? {};
const defaults: ITemplateParams = {
widgetRoomId: this.roomId,
currentUserId: MatrixClientPeg.get().getUserId(),
userDisplayName: OwnProfileStore.instance.displayName,
userHttpAvatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(),
}, opts?.asPopout);
clientId: ELEMENT_CLIENT_ID,
clientTheme: SettingsStore.getValue("theme"),
clientLanguage: getUserLanguage(),
};
const templated = this.mockWidget.getCompleteUrl(Object.assign(defaults, fromCustomisation), opts?.asPopout);

const parsed = new URL(templated);

Expand Down Expand Up @@ -358,6 +366,9 @@ export class StopGapWidget extends EventEmitter {
}

public async prepare(): Promise<void> {
// Ensure the variables are ready for us to be rendered before continuing
await (WidgetVariableCustomisations?.isReady?.() ?? Promise.resolve());

if (this.scalarToken) return;
const existingMessaging = WidgetMessagingStore.instance.getMessaging(this.mockWidget);
if (existingMessaging) this.messaging = existingMessaging;
Expand Down

0 comments on commit 9d5472d

Please sign in to comment.