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

Commit bdcb65d

Browse files
committed
Support and send the config over to capable widgets
For element-hq/element-web#12845
1 parent 26bda59 commit bdcb65d

File tree

5 files changed

+64
-6
lines changed

5 files changed

+64
-6
lines changed

src/FromWidgetPostMessageApi.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {MatrixClientPeg} from "./MatrixClientPeg";
2424
import RoomViewStore from "./stores/RoomViewStore";
2525
import {IntegrationManagers} from "./integrations/IntegrationManagers";
2626
import SettingsStore from "./settings/SettingsStore";
27+
import {Capability, KnownWidgetActions} from "./widgets/WidgetApi";
28+
import SdkConfig from "./SdkConfig";
2729

2830
const WIDGET_API_VERSION = '0.0.2'; // Current API version
2931
const SUPPORTED_WIDGET_API_VERSIONS = [
@@ -213,11 +215,18 @@ export default class FromWidgetPostMessageApi {
213215
const data = event.data.data;
214216
const val = data.value;
215217

216-
if (ActiveWidgetStore.widgetHasCapability(widgetId, 'm.always_on_screen')) {
218+
if (ActiveWidgetStore.widgetHasCapability(widgetId, Capability.AlwaysOnScreen)) {
217219
ActiveWidgetStore.setWidgetPersistence(widgetId, val);
218220
}
219221
} else if (action === 'get_openid') {
220222
// Handled by caller
223+
} else if (action === KnownWidgetActions.GetRiotWebConfig) {
224+
if (ActiveWidgetStore.widgetHasCapability(widgetId, Capability.GetRiotWebConfig)) {
225+
this.sendResponse(event, {
226+
api: INBOUND_API_NAME,
227+
config: SdkConfig.get(),
228+
});
229+
}
221230
} else {
222231
console.warn('Widget postMessage event unhandled');
223232
this.sendError(event, {message: 'The postMessage was unhandled'});

src/WidgetMessaging.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {MatrixClientPeg} from "./MatrixClientPeg";
2727
import SettingsStore from "./settings/SettingsStore";
2828
import WidgetOpenIDPermissionsDialog from "./components/views/dialogs/WidgetOpenIDPermissionsDialog";
2929
import WidgetUtils from "./utils/WidgetUtils";
30+
import {KnownWidgetActions} from "./widgets/WidgetApi";
3031

3132
if (!global.mxFromWidgetMessaging) {
3233
global.mxFromWidgetMessaging = new FromWidgetPostMessageApi();
@@ -75,6 +76,16 @@ export default class WidgetMessaging {
7576
});
7677
}
7778

79+
/**
80+
* Tells the widget that the client is ready to handle further widget requests.
81+
*/
82+
flagReadyToContinue() {
83+
return this.messageToWidget({
84+
api: OUTBOUND_API_NAME,
85+
action: KnownWidgetActions.ClientReady,
86+
});
87+
}
88+
7889
/**
7990
* Request a screenshot from a widget
8091
* @return {Promise} To be resolved with screenshot data when it has been generated

src/components/views/elements/AppTile.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,12 @@ export default class AppTile extends React.Component {
419419
if (this.props.onCapabilityRequest) {
420420
this.props.onCapabilityRequest(requestedCapabilities);
421421
}
422+
423+
// We only tell Jitsi widgets that we're ready because they're realistically the only ones
424+
// using this custom extension to the widget API.
425+
if (this.props.type === 'jitsi') {
426+
widgetMessaging.flagReadyToContinue();
427+
}
422428
}).catch((err) => {
423429
console.log(`Failed to get capabilities for widget type ${this.props.type}`, this.props.id, err);
424430
});

src/utils/WidgetUtils.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const WIDGET_WAIT_TIME = 20000;
2828
import SettingsStore from "../settings/SettingsStore";
2929
import ActiveWidgetStore from "../stores/ActiveWidgetStore";
3030
import {IntegrationManagers} from "../integrations/IntegrationManagers";
31+
import {Capability} from "../widgets/WidgetApi";
3132

3233
/**
3334
* Encodes a URI according to a set of template variables. Variables will be
@@ -454,12 +455,15 @@ export default class WidgetUtils {
454455
static getCapWhitelistForAppTypeInRoomId(appType, roomId) {
455456
const enableScreenshots = SettingsStore.getValue("enableWidgetScreenshots", roomId);
456457

457-
const capWhitelist = enableScreenshots ? ["m.capability.screenshot"] : [];
458+
const capWhitelist = enableScreenshots ? [Capability.Screenshot] : [];
458459

459460
// Obviously anyone that can add a widget can claim it's a jitsi widget,
460461
// so this doesn't really offer much over the set of domains we load
461462
// widgets from at all, but it probably makes sense for sanity.
462-
if (appType == 'jitsi') capWhitelist.push("m.always_on_screen");
463+
if (appType === 'jitsi') {
464+
capWhitelist.push(Capability.AlwaysOnScreen);
465+
capWhitelist.push(Capability.GetRiotWebConfig);
466+
}
463467

464468
return capWhitelist;
465469
}

src/widgets/WidgetApi.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export enum Capability {
2323
Screenshot = "m.capability.screenshot",
2424
Sticker = "m.sticker",
2525
AlwaysOnScreen = "m.always_on_screen",
26+
GetRiotWebConfig = "im.vector.web.riot_config",
2627
}
2728

2829
export enum KnownWidgetActions {
@@ -33,7 +34,10 @@ export enum KnownWidgetActions {
3334
UpdateVisibility = "visibility",
3435
ReceiveOpenIDCredentials = "openid_credentials",
3536
SetAlwaysOnScreen = "set_always_on_screen",
37+
GetRiotWebConfig = "im.vector.web.riot_config",
38+
ClientReady = "im.vector.ready",
3639
}
40+
3741
export type WidgetAction = KnownWidgetActions | string;
3842

3943
export enum WidgetApiType {
@@ -63,10 +67,15 @@ export interface FromWidgetRequest extends WidgetRequest {
6367
*/
6468
export class WidgetApi {
6569
private origin: string;
66-
private inFlightRequests: {[requestId: string]: (reply: FromWidgetRequest) => void} = {};
70+
private inFlightRequests: { [requestId: string]: (reply: FromWidgetRequest) => void } = {};
6771
private readyPromise: Promise<any>;
6872
private readyPromiseResolve: () => void;
6973

74+
/**
75+
* Set this to true if your widget is expecting a ready message from the client. False otherwise (default).
76+
*/
77+
public expectingExplicitReady = false;
78+
7079
constructor(currentUrl: string, private widgetId: string, private requestedCapabilities: string[]) {
7180
this.origin = new URL(currentUrl).origin;
7281

@@ -83,7 +92,14 @@ export class WidgetApi {
8392

8493
if (payload.action === KnownWidgetActions.GetCapabilities) {
8594
this.onCapabilitiesRequest(<ToWidgetRequest>payload);
95+
if (!this.expectingExplicitReady) {
96+
this.readyPromiseResolve();
97+
}
98+
} else if (payload.action === KnownWidgetActions.ClientReady) {
8699
this.readyPromiseResolve();
100+
101+
// Automatically acknowledge so we can move on
102+
this.replyToRequest(<ToWidgetRequest>payload, {});
87103
} else {
88104
console.warn(`[WidgetAPI] Got unexpected action: ${payload.action}`);
89105
}
@@ -126,15 +142,27 @@ export class WidgetApi {
126142
data: payload,
127143
response: {}, // Not used at this layer - it's used when the client responds
128144
};
129-
this.inFlightRequests[request.requestId] = callback;
145+
146+
if (callback) {
147+
this.inFlightRequests[request.requestId] = callback;
148+
}
130149

131150
console.log(`[WidgetAPI] Sending request: `, request);
132151
window.parent.postMessage(request, "*");
133152
}
134153

135154
public setAlwaysOnScreen(onScreen: boolean): Promise<any> {
136155
return new Promise<any>(resolve => {
137-
this.callAction(KnownWidgetActions.SetAlwaysOnScreen, {value: onScreen}, resolve);
156+
this.callAction(KnownWidgetActions.SetAlwaysOnScreen, {value: onScreen}, null);
157+
resolve(); // SetAlwaysOnScreen is currently fire-and-forget, but that could change.
158+
});
159+
}
160+
161+
public getRiotConfig(): Promise<any> {
162+
return new Promise<any>(resolve => {
163+
this.callAction(KnownWidgetActions.GetRiotWebConfig, {}, response => {
164+
resolve(response.response.config);
165+
});
138166
});
139167
}
140168
}

0 commit comments

Comments
 (0)