Support and send the config over to capable widgets
For https://github.com/vector-im/riot-web/pull/12845pull/21833/head
							parent
							
								
									26bda5933b
								
							
						
					
					
						commit
						bdcb65de77
					
				|  | @ -24,6 +24,8 @@ import {MatrixClientPeg} from "./MatrixClientPeg"; | |||
| import RoomViewStore from "./stores/RoomViewStore"; | ||||
| import {IntegrationManagers} from "./integrations/IntegrationManagers"; | ||||
| import SettingsStore from "./settings/SettingsStore"; | ||||
| import {Capability, KnownWidgetActions} from "./widgets/WidgetApi"; | ||||
| import SdkConfig from "./SdkConfig"; | ||||
| 
 | ||||
| const WIDGET_API_VERSION = '0.0.2'; // Current API version
 | ||||
| const SUPPORTED_WIDGET_API_VERSIONS = [ | ||||
|  | @ -213,11 +215,18 @@ export default class FromWidgetPostMessageApi { | |||
|             const data = event.data.data; | ||||
|             const val = data.value; | ||||
| 
 | ||||
|             if (ActiveWidgetStore.widgetHasCapability(widgetId, 'm.always_on_screen')) { | ||||
|             if (ActiveWidgetStore.widgetHasCapability(widgetId, Capability.AlwaysOnScreen)) { | ||||
|                 ActiveWidgetStore.setWidgetPersistence(widgetId, val); | ||||
|             } | ||||
|         } else if (action === 'get_openid') { | ||||
|             // Handled by caller
 | ||||
|         } else if (action === KnownWidgetActions.GetRiotWebConfig) { | ||||
|             if (ActiveWidgetStore.widgetHasCapability(widgetId, Capability.GetRiotWebConfig)) { | ||||
|                 this.sendResponse(event, { | ||||
|                     api: INBOUND_API_NAME, | ||||
|                     config: SdkConfig.get(), | ||||
|                 }); | ||||
|             } | ||||
|         } else { | ||||
|             console.warn('Widget postMessage event unhandled'); | ||||
|             this.sendError(event, {message: 'The postMessage was unhandled'}); | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ import {MatrixClientPeg} from "./MatrixClientPeg"; | |||
| import SettingsStore from "./settings/SettingsStore"; | ||||
| import WidgetOpenIDPermissionsDialog from "./components/views/dialogs/WidgetOpenIDPermissionsDialog"; | ||||
| import WidgetUtils from "./utils/WidgetUtils"; | ||||
| import {KnownWidgetActions} from "./widgets/WidgetApi"; | ||||
| 
 | ||||
| if (!global.mxFromWidgetMessaging) { | ||||
|     global.mxFromWidgetMessaging = new FromWidgetPostMessageApi(); | ||||
|  | @ -75,6 +76,16 @@ export default class WidgetMessaging { | |||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Tells the widget that the client is ready to handle further widget requests. | ||||
|      */ | ||||
|     flagReadyToContinue() { | ||||
|         return this.messageToWidget({ | ||||
|             api: OUTBOUND_API_NAME, | ||||
|             action: KnownWidgetActions.ClientReady, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Request a screenshot from a widget | ||||
|      * @return {Promise} To be resolved with screenshot data when it has been generated | ||||
|  |  | |||
|  | @ -419,6 +419,12 @@ export default class AppTile extends React.Component { | |||
|             if (this.props.onCapabilityRequest) { | ||||
|                 this.props.onCapabilityRequest(requestedCapabilities); | ||||
|             } | ||||
| 
 | ||||
|             // We only tell Jitsi widgets that we're ready because they're realistically the only ones
 | ||||
|             // using this custom extension to the widget API.
 | ||||
|             if (this.props.type === 'jitsi') { | ||||
|                 widgetMessaging.flagReadyToContinue(); | ||||
|             } | ||||
|         }).catch((err) => { | ||||
|             console.log(`Failed to get capabilities for widget type ${this.props.type}`, this.props.id, err); | ||||
|         }); | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ const WIDGET_WAIT_TIME = 20000; | |||
| import SettingsStore from "../settings/SettingsStore"; | ||||
| import ActiveWidgetStore from "../stores/ActiveWidgetStore"; | ||||
| import {IntegrationManagers} from "../integrations/IntegrationManagers"; | ||||
| import {Capability} from "../widgets/WidgetApi"; | ||||
| 
 | ||||
| /** | ||||
|  * Encodes a URI according to a set of template variables. Variables will be | ||||
|  | @ -454,12 +455,15 @@ export default class WidgetUtils { | |||
|     static getCapWhitelistForAppTypeInRoomId(appType, roomId) { | ||||
|         const enableScreenshots = SettingsStore.getValue("enableWidgetScreenshots", roomId); | ||||
| 
 | ||||
|         const capWhitelist = enableScreenshots ? ["m.capability.screenshot"] : []; | ||||
|         const capWhitelist = enableScreenshots ? [Capability.Screenshot] : []; | ||||
| 
 | ||||
|         // Obviously anyone that can add a widget can claim it's a jitsi widget,
 | ||||
|         // so this doesn't really offer much over the set of domains we load
 | ||||
|         // widgets from at all, but it probably makes sense for sanity.
 | ||||
|         if (appType == 'jitsi') capWhitelist.push("m.always_on_screen"); | ||||
|         if (appType === 'jitsi') { | ||||
|             capWhitelist.push(Capability.AlwaysOnScreen); | ||||
|             capWhitelist.push(Capability.GetRiotWebConfig); | ||||
|         } | ||||
| 
 | ||||
|         return capWhitelist; | ||||
|     } | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ export enum Capability { | |||
|     Screenshot = "m.capability.screenshot", | ||||
|     Sticker = "m.sticker", | ||||
|     AlwaysOnScreen = "m.always_on_screen", | ||||
|     GetRiotWebConfig = "im.vector.web.riot_config", | ||||
| } | ||||
| 
 | ||||
| export enum KnownWidgetActions { | ||||
|  | @ -33,7 +34,10 @@ export enum KnownWidgetActions { | |||
|     UpdateVisibility = "visibility", | ||||
|     ReceiveOpenIDCredentials = "openid_credentials", | ||||
|     SetAlwaysOnScreen = "set_always_on_screen", | ||||
|     GetRiotWebConfig = "im.vector.web.riot_config", | ||||
|     ClientReady = "im.vector.ready", | ||||
| } | ||||
| 
 | ||||
| export type WidgetAction = KnownWidgetActions | string; | ||||
| 
 | ||||
| export enum WidgetApiType { | ||||
|  | @ -63,10 +67,15 @@ export interface FromWidgetRequest extends WidgetRequest { | |||
|  */ | ||||
| export class WidgetApi { | ||||
|     private origin: string; | ||||
|     private inFlightRequests: {[requestId: string]: (reply: FromWidgetRequest) => void} = {}; | ||||
|     private inFlightRequests: { [requestId: string]: (reply: FromWidgetRequest) => void } = {}; | ||||
|     private readyPromise: Promise<any>; | ||||
|     private readyPromiseResolve: () => void; | ||||
| 
 | ||||
|     /** | ||||
|      * Set this to true if your widget is expecting a ready message from the client. False otherwise (default). | ||||
|      */ | ||||
|     public expectingExplicitReady = false; | ||||
| 
 | ||||
|     constructor(currentUrl: string, private widgetId: string, private requestedCapabilities: string[]) { | ||||
|         this.origin = new URL(currentUrl).origin; | ||||
| 
 | ||||
|  | @ -83,7 +92,14 @@ export class WidgetApi { | |||
| 
 | ||||
|                 if (payload.action === KnownWidgetActions.GetCapabilities) { | ||||
|                     this.onCapabilitiesRequest(<ToWidgetRequest>payload); | ||||
|                     if (!this.expectingExplicitReady) { | ||||
|                         this.readyPromiseResolve(); | ||||
|                     } | ||||
|                 } else if (payload.action === KnownWidgetActions.ClientReady) { | ||||
|                     this.readyPromiseResolve(); | ||||
| 
 | ||||
|                     // Automatically acknowledge so we can move on
 | ||||
|                     this.replyToRequest(<ToWidgetRequest>payload, {}); | ||||
|                 } else { | ||||
|                     console.warn(`[WidgetAPI] Got unexpected action: ${payload.action}`); | ||||
|                 } | ||||
|  | @ -126,7 +142,10 @@ export class WidgetApi { | |||
|             data: payload, | ||||
|             response: {}, // Not used at this layer - it's used when the client responds
 | ||||
|         }; | ||||
|         this.inFlightRequests[request.requestId] = callback; | ||||
| 
 | ||||
|         if (callback) { | ||||
|             this.inFlightRequests[request.requestId] = callback; | ||||
|         } | ||||
| 
 | ||||
|         console.log(`[WidgetAPI] Sending request: `, request); | ||||
|         window.parent.postMessage(request, "*"); | ||||
|  | @ -134,7 +153,16 @@ export class WidgetApi { | |||
| 
 | ||||
|     public setAlwaysOnScreen(onScreen: boolean): Promise<any> { | ||||
|         return new Promise<any>(resolve => { | ||||
|             this.callAction(KnownWidgetActions.SetAlwaysOnScreen, {value: onScreen}, resolve); | ||||
|             this.callAction(KnownWidgetActions.SetAlwaysOnScreen, {value: onScreen}, null); | ||||
|             resolve(); // SetAlwaysOnScreen is currently fire-and-forget, but that could change.
 | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public getRiotConfig(): Promise<any> { | ||||
|         return new Promise<any>(resolve => { | ||||
|             this.callAction(KnownWidgetActions.GetRiotWebConfig, {}, response => { | ||||
|                 resolve(response.response.config); | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Travis Ralston
						Travis Ralston