mirror of
https://github.com/element-hq/element-web
synced 2024-11-23 09:46:09 +03:00
Initial Modal Widget work tweaks MSC2790
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
342f1d5b43
commit
44bc8fc67e
10 changed files with 294 additions and 243 deletions
|
@ -74,6 +74,7 @@
|
|||
@import "./views/dialogs/_InviteDialog.scss";
|
||||
@import "./views/dialogs/_KeyboardShortcutsDialog.scss";
|
||||
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
|
||||
@import "./views/dialogs/_ModalWidgetDialog.scss";
|
||||
@import "./views/dialogs/_NewSessionReviewDialog.scss";
|
||||
@import "./views/dialogs/_RoomSettingsDialog.scss";
|
||||
@import "./views/dialogs/_RoomSettingsDialogBridges.scss";
|
||||
|
|
23
res/css/views/dialogs/_ModalWidgetDialog.scss
Normal file
23
res/css/views/dialogs/_ModalWidgetDialog.scss
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
Copyright 2020 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.
|
||||
*/
|
||||
|
||||
.mx_ModalWidgetDialog {
|
||||
.mx_ModalWidgetDialog_buttons {
|
||||
.mx_AccessibleButton + .mx_AccessibleButton {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,8 +26,7 @@ import {IntegrationManagers} from "./integrations/IntegrationManagers";
|
|||
import SettingsStore from "./settings/SettingsStore";
|
||||
import {Capability, KnownWidgetActions} from "./widgets/WidgetApi";
|
||||
import {objectClone} from "./utils/objects";
|
||||
import {Action} from "./dispatcher/actions";
|
||||
import {TempWidgetStore} from "./stores/TempWidgetStore";
|
||||
import {ModalWidgetStore} from "./stores/ModalWidgetStore";
|
||||
|
||||
const WIDGET_API_VERSION = '0.0.2'; // Current API version
|
||||
const SUPPORTED_WIDGET_API_VERSIONS = [
|
||||
|
@ -220,12 +219,16 @@ export default class FromWidgetPostMessageApi {
|
|||
if (ActiveWidgetStore.widgetHasCapability(widgetId, Capability.AlwaysOnScreen)) {
|
||||
ActiveWidgetStore.setWidgetPersistence(widgetId, val);
|
||||
}
|
||||
} else if (action === 'get_openid'
|
||||
|| action === KnownWidgetActions.CloseWidget) {
|
||||
} else if (action === 'get_openid' || action === KnownWidgetActions.CloseModalWidget) {
|
||||
// Handled by caller
|
||||
} else if (action === KnownWidgetActions.OpenTempWidget) {
|
||||
TempWidgetStore.instance.openTempWidget(event.data.data, widgetId);
|
||||
this.sendResponse(event, {}); // ack
|
||||
} else if (action === KnownWidgetActions.OpenModalWidget) {
|
||||
if (ModalWidgetStore.instance.canOpenModalWidget()) {
|
||||
ModalWidgetStore.instance.openModalWidget(event.data.data, widgetId);
|
||||
this.sendResponse(event, {}); // ack
|
||||
} else {
|
||||
this.sendError(event, {message: 'Unable to open modal at this time'}); // nak
|
||||
}
|
||||
} else {
|
||||
console.warn('Widget postMessage event unhandled');
|
||||
this.sendError(event, {message: 'The postMessage was unhandled'});
|
||||
|
|
|
@ -38,7 +38,7 @@ export interface IModal<T extends any[]> {
|
|||
close(...args: T): void;
|
||||
}
|
||||
|
||||
interface IHandle<T extends any[]> {
|
||||
export interface IHandle<T extends any[]> {
|
||||
finished: Promise<T>;
|
||||
close(...args: T): void;
|
||||
}
|
||||
|
|
|
@ -147,33 +147,33 @@ export default class WidgetMessaging {
|
|||
});
|
||||
}
|
||||
|
||||
sendThemeInfo(themeInfo: any) {
|
||||
return this.messageToWidget({
|
||||
api: OUTBOUND_API_NAME,
|
||||
action: KnownWidgetActions.UpdateThemeInfo,
|
||||
data: themeInfo,
|
||||
}).catch((error) => {
|
||||
console.error("Failed to send theme info: ", error);
|
||||
});
|
||||
}
|
||||
|
||||
sendWidgetConfig(widgetConfig: any) {
|
||||
return this.messageToWidget({
|
||||
api: OUTBOUND_API_NAME,
|
||||
action: KnownWidgetActions.SendWidgetConfig,
|
||||
action: KnownWidgetActions.GetWidgetConfig,
|
||||
data: widgetConfig,
|
||||
}).catch((error) => {
|
||||
console.error("Failed to send widget info: ", error);
|
||||
});
|
||||
}
|
||||
|
||||
sendTempCloseInfo(info: any) {
|
||||
sendModalButtonClicked(id: string) {
|
||||
return this.messageToWidget({
|
||||
api: OUTBOUND_API_NAME,
|
||||
action: KnownWidgetActions.ClosedWidgetResponse,
|
||||
action: KnownWidgetActions.ButtonClicked,
|
||||
data: {id},
|
||||
}).catch((error) => {
|
||||
console.error("Failed to send modal widget button clicked: ", error);
|
||||
});
|
||||
}
|
||||
|
||||
sendModalCloseInfo(info: any) {
|
||||
return this.messageToWidget({
|
||||
api: OUTBOUND_API_NAME,
|
||||
action: KnownWidgetActions.CloseModalWidget,
|
||||
data: info,
|
||||
}).catch((error) => {
|
||||
console.error("Failed to send temp widget close info: ", error);
|
||||
console.error("Failed to send modal widget close info: ", error);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
138
src/components/views/dialogs/ModalWidgetDialog.tsx
Normal file
138
src/components/views/dialogs/ModalWidgetDialog.tsx
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import BaseDialog from './BaseDialog';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import WidgetMessaging from "../../../WidgetMessaging";
|
||||
import {ButtonKind, IButton, KnownWidgetActions} from "../../../widgets/WidgetApi";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
||||
interface IModalWidget {
|
||||
type: string;
|
||||
url: string;
|
||||
name: string;
|
||||
data: any;
|
||||
waitForIframeLoad?: boolean;
|
||||
buttons?: IButton[];
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
widgetDefinition: IModalWidget;
|
||||
sourceWidgetId: string;
|
||||
onFinished(success: boolean, data?: any): void;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
messaging?: WidgetMessaging;
|
||||
}
|
||||
|
||||
const MAX_BUTTONS = 3;
|
||||
|
||||
export default class ModalWidgetDialog extends React.PureComponent<IProps, IState> {
|
||||
private appFrame: React.RefObject<HTMLIFrameElement> = React.createRef();
|
||||
|
||||
state: IState = {};
|
||||
|
||||
private getWidgetId() {
|
||||
return `modal_${this.props.sourceWidgetId}`;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
// TODO: Don't violate every principle of widget creation
|
||||
const messaging = new WidgetMessaging(
|
||||
this.getWidgetId(),
|
||||
this.props.widgetDefinition.url,
|
||||
this.props.widgetDefinition.url, // TODO templating and such
|
||||
true,
|
||||
this.appFrame.current.contentWindow,
|
||||
);
|
||||
this.setState({messaging});
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.state.messaging.fromWidget.removeListener(KnownWidgetActions.CloseModalWidget, this.onWidgetClose);
|
||||
this.state.messaging.stop();
|
||||
}
|
||||
|
||||
private onLoad = () => {
|
||||
this.state.messaging.getCapabilities().then(caps => {
|
||||
console.log("Requested capabilities: ", caps);
|
||||
this.state.messaging.sendWidgetConfig(this.props.widgetDefinition.data);
|
||||
});
|
||||
this.state.messaging.fromWidget.addListener(KnownWidgetActions.CloseModalWidget, this.onWidgetClose);
|
||||
};
|
||||
|
||||
private onWidgetClose = (req) => {
|
||||
this.props.onFinished(true, req.data);
|
||||
}
|
||||
|
||||
public render() {
|
||||
// TODO: Don't violate every single security principle
|
||||
|
||||
const widgetUrl = this.props.widgetDefinition.url
|
||||
+ `?widgetId=${this.getWidgetId()}&parentUrl=${encodeURIComponent(window.location.href)}`;
|
||||
|
||||
let buttons;
|
||||
if (this.props.widgetDefinition.buttons) {
|
||||
// show first button rightmost for a more natural specification
|
||||
buttons = this.props.widgetDefinition.buttons.slice(0, MAX_BUTTONS).reverse().map(def => {
|
||||
let kind = "secondary";
|
||||
switch (def.kind) {
|
||||
case ButtonKind.Primary:
|
||||
kind = "primary";
|
||||
break;
|
||||
case ButtonKind.Secondary:
|
||||
kind = "primary_outline";
|
||||
break
|
||||
case ButtonKind.Danger:
|
||||
kind = "danger";
|
||||
break;
|
||||
}
|
||||
|
||||
const onClick = () => {
|
||||
this.state.messaging.sendModalButtonClicked(def.id);
|
||||
};
|
||||
|
||||
return <AccessibleButton key={def.id} kind={kind} onClick={onClick}>
|
||||
{ def.label }
|
||||
</AccessibleButton>;
|
||||
});
|
||||
}
|
||||
|
||||
return <BaseDialog
|
||||
title={this.props.widgetDefinition.name || _t("Modal Widget")}
|
||||
className="mx_ModalWidgetDialog"
|
||||
contentId="mx_Dialog_content"
|
||||
onFinished={this.props.onFinished}
|
||||
hasCancel={false}
|
||||
>
|
||||
<div>
|
||||
<iframe
|
||||
ref={this.appFrame}
|
||||
sandbox="allow-forms allow-scripts"
|
||||
width={700} // TODO
|
||||
height={450} // TODO
|
||||
src={widgetUrl}
|
||||
onLoad={this.onLoad}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx_ModalWidgetDialog_buttons" style={{float: "right"}}>
|
||||
{ buttons }
|
||||
</div>
|
||||
</BaseDialog>;
|
||||
}
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import BaseDialog from './BaseDialog';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import WidgetMessaging from "../../../WidgetMessaging";
|
||||
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
|
||||
import Field from "../elements/Field";
|
||||
import { KnownWidgetActions } from "../../../widgets/WidgetApi";
|
||||
import ActiveWidgetStore from "../../../stores/ActiveWidgetStore";
|
||||
|
||||
interface IState {
|
||||
messaging?: WidgetMessaging;
|
||||
|
||||
androidMode: boolean;
|
||||
darkTheme: boolean;
|
||||
accentColor: string;
|
||||
}
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
widgetDefinition: {url: string, data: any};
|
||||
sourceWidgetId: string;
|
||||
}
|
||||
|
||||
// TODO: Make a better dialog
|
||||
|
||||
export default class TempWidgetDialog extends React.PureComponent<IProps, IState> {
|
||||
private appFrame: React.RefObject<HTMLIFrameElement> = React.createRef();
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
androidMode: false,
|
||||
darkTheme: false,
|
||||
accentColor: "#03b381",
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
// TODO: Don't violate every principle of widget creation
|
||||
const messaging = new WidgetMessaging(
|
||||
"TEMP_ID",
|
||||
this.props.widgetDefinition.url,
|
||||
this.props.widgetDefinition.url,
|
||||
false,
|
||||
this.appFrame.current.contentWindow,
|
||||
);
|
||||
this.setState({messaging});
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.state.messaging.fromWidget.removeListener(KnownWidgetActions.CloseWidget, this.onWidgetClose);
|
||||
this.state.messaging.stop();
|
||||
}
|
||||
|
||||
private onLoad = () => {
|
||||
this.state.messaging.getCapabilities().then(caps => {
|
||||
console.log("Requested capabilities: ", caps);
|
||||
this.sendTheme();
|
||||
this.state.messaging.sendWidgetConfig(this.props.widgetDefinition.data);
|
||||
});
|
||||
this.state.messaging.fromWidget.addListener(KnownWidgetActions.CloseWidget, this.onWidgetClose);
|
||||
};
|
||||
|
||||
private sendTheme() {
|
||||
if (!this.state.messaging) return;
|
||||
this.state.messaging.sendThemeInfo({
|
||||
clientName: this.state.androidMode ? "element-android" : "element-web",
|
||||
isDark: this.state.darkTheme,
|
||||
accentColor: this.state.accentColor,
|
||||
});
|
||||
}
|
||||
|
||||
public static sendExitData(sourceWidgetId: string, success: boolean, data?: any) {
|
||||
const sourceMessaging = ActiveWidgetStore.getWidgetMessaging(sourceWidgetId);
|
||||
if (!sourceMessaging) {
|
||||
console.error("No source widget messaging for temp widget");
|
||||
return;
|
||||
}
|
||||
sourceMessaging.sendTempCloseInfo({success, ...data});
|
||||
}
|
||||
|
||||
private onWidgetClose = (req) => {
|
||||
this.props.onFinished(true);
|
||||
TempWidgetDialog.sendExitData(this.props.sourceWidgetId, true, req.data);
|
||||
}
|
||||
|
||||
private onClientToggleChanged = (androidMode) => {
|
||||
this.setState({androidMode}, () => this.sendTheme());
|
||||
};
|
||||
|
||||
private onDarkThemeChanged = (darkTheme) => {
|
||||
this.setState({darkTheme}, () => this.sendTheme());
|
||||
};
|
||||
|
||||
private onAccentColorChanged = (ev) => {
|
||||
this.setState({accentColor: ev.target.value}, () => this.sendTheme());
|
||||
};
|
||||
|
||||
public render() {
|
||||
// TODO: Don't violate every single security principle
|
||||
|
||||
const widgetUrl = this.props.widgetDefinition.url
|
||||
+ "?widgetId=TEMP_ID&parentUrl=" + encodeURIComponent(window.location.href);
|
||||
|
||||
return <BaseDialog
|
||||
title={_t("Widget Proof of Concept Dashboard")}
|
||||
className='mx_TempWidgetDialog'
|
||||
contentId='mx_Dialog_content'
|
||||
onFinished={this.props.onFinished}
|
||||
hasCancel={false}
|
||||
>
|
||||
<div>
|
||||
<LabelledToggleSwitch
|
||||
label={ _t("Look like Android")}
|
||||
onChange={this.onClientToggleChanged}
|
||||
value={this.state.androidMode}
|
||||
/>
|
||||
<LabelledToggleSwitch
|
||||
label={ _t("Look like dark theme")}
|
||||
onChange={this.onDarkThemeChanged}
|
||||
value={this.state.darkTheme}
|
||||
/>
|
||||
<Field
|
||||
value={this.state.accentColor}
|
||||
label={_t('Accent Colour')}
|
||||
onChange={this.onAccentColorChanged}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<iframe
|
||||
ref={this.appFrame}
|
||||
width={700} height={450}
|
||||
src={widgetUrl}
|
||||
onLoad={this.onLoad}
|
||||
/>
|
||||
</div>
|
||||
</BaseDialog>;
|
||||
}
|
||||
}
|
86
src/stores/ModalWidgetStore.ts
Normal file
86
src/stores/ModalWidgetStore.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
|
||||
import defaultDispatcher from "../dispatcher/dispatcher";
|
||||
import { ActionPayload } from "../dispatcher/payloads";
|
||||
import Modal, {IHandle, IModal} from "../Modal";
|
||||
import ModalWidgetDialog from "../components/views/dialogs/ModalWidgetDialog";
|
||||
import ActiveWidgetStore from "../stores/ActiveWidgetStore";
|
||||
|
||||
interface IState {
|
||||
modal?: IModal<any>;
|
||||
openedFromId?: string;
|
||||
}
|
||||
|
||||
export class ModalWidgetStore extends AsyncStoreWithClient<IState> {
|
||||
private static internalInstance = new ModalWidgetStore();
|
||||
private modalInstance: IHandle<void[]> = null;
|
||||
private openSourceWidgetId: string = null;
|
||||
|
||||
private constructor() {
|
||||
super(defaultDispatcher, {});
|
||||
}
|
||||
|
||||
public static get instance(): ModalWidgetStore {
|
||||
return ModalWidgetStore.internalInstance;
|
||||
}
|
||||
|
||||
protected async onAction(payload: ActionPayload): Promise<any> {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public canOpenModalWidget = () => {
|
||||
return !this.modalInstance;
|
||||
};
|
||||
|
||||
public openModalWidget = (requestData: any, sourceWidgetId: string) => {
|
||||
if (this.modalInstance) return;
|
||||
this.openSourceWidgetId = sourceWidgetId;
|
||||
this.modalInstance = Modal.createTrackedDialog('Modal Widget', '', ModalWidgetDialog, {
|
||||
widgetDefinition: {...requestData},
|
||||
sourceWidgetId: sourceWidgetId,
|
||||
onFinished: (success: boolean, data?: any) => {
|
||||
if (!success) {
|
||||
this.closeModalWidget(sourceWidgetId, {
|
||||
"m.exited": true,
|
||||
});
|
||||
} else {
|
||||
this.closeModalWidget(sourceWidgetId, data);
|
||||
}
|
||||
|
||||
this.openSourceWidgetId = null;
|
||||
this.modalInstance = null;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
public closeModalWidget = (sourceWidgetId: string, data?: any) => {
|
||||
if (!this.modalInstance) return;
|
||||
if (this.openSourceWidgetId === sourceWidgetId) {
|
||||
this.openSourceWidgetId = null;
|
||||
this.modalInstance.close();
|
||||
this.modalInstance = null;
|
||||
|
||||
const sourceMessaging = ActiveWidgetStore.getWidgetMessaging(sourceWidgetId);
|
||||
if (!sourceMessaging) {
|
||||
console.error("No source widget messaging for modal widget");
|
||||
return;
|
||||
}
|
||||
sourceMessaging.sendModalCloseInfo(data);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
|
||||
import defaultDispatcher from "../dispatcher/dispatcher";
|
||||
import { ActionPayload } from "../dispatcher/payloads";
|
||||
import Modal, { IModal } from "../Modal";
|
||||
import TempWidgetDialog from "../components/views/dialogs/TempWidgetDialog";
|
||||
|
||||
interface IState {
|
||||
modal?: IModal<any>;
|
||||
openedFromId?: string;
|
||||
}
|
||||
|
||||
export class TempWidgetStore extends AsyncStoreWithClient<IState> {
|
||||
private static internalInstance = new TempWidgetStore();
|
||||
|
||||
private constructor() {
|
||||
super(defaultDispatcher, {});
|
||||
}
|
||||
|
||||
public static get instance(): TempWidgetStore {
|
||||
return TempWidgetStore.internalInstance;
|
||||
}
|
||||
|
||||
protected async onAction(payload: ActionPayload): Promise<any> {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public openTempWidget(requestData: any, sourceWidgetId: string) {
|
||||
Modal.createTrackedDialog('Temp Widget', '', TempWidgetDialog, {
|
||||
widgetDefinition: {...requestData},
|
||||
sourceWidgetId: sourceWidgetId,
|
||||
onFinished: (success) => {
|
||||
if (!success) {
|
||||
TempWidgetDialog.sendExitData(sourceWidgetId, false);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ export enum Capability {
|
|||
Screenshot = "m.capability.screenshot",
|
||||
Sticker = "m.sticker",
|
||||
AlwaysOnScreen = "m.always_on_screen",
|
||||
Modals = "m.modals",
|
||||
ReceiveTerminate = "im.vector.receive_terminate",
|
||||
}
|
||||
|
||||
|
@ -39,12 +40,10 @@ export enum KnownWidgetActions {
|
|||
SetAlwaysOnScreen = "set_always_on_screen",
|
||||
ClientReady = "im.vector.ready",
|
||||
Terminate = "im.vector.terminate",
|
||||
|
||||
OpenTempWidget = "io.element.start_temp",
|
||||
UpdateThemeInfo = "io.element.theme_info",
|
||||
SendWidgetConfig = "io.element.widget_config",
|
||||
CloseWidget = "io.element.exit",
|
||||
ClosedWidgetResponse = "io.element.exit_response",
|
||||
OpenModalWidget = "open_modal",
|
||||
CloseModalWidget = "close_modal",
|
||||
GetWidgetConfig = "widget_config",
|
||||
ButtonClicked = "button_clicked",
|
||||
}
|
||||
|
||||
export type WidgetAction = KnownWidgetActions | string;
|
||||
|
@ -78,6 +77,18 @@ export interface OpenIDCredentials {
|
|||
expiresIn: number;
|
||||
}
|
||||
|
||||
export enum ButtonKind {
|
||||
Primary = "m.primary",
|
||||
Secondary = "m.secondary",
|
||||
Danger = "m.danger",
|
||||
}
|
||||
|
||||
export interface IButton {
|
||||
id: "m.close" | string;
|
||||
label: string;
|
||||
kind: ButtonKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Element <--> Widget interactions for embedded/standalone widgets.
|
||||
*
|
||||
|
@ -140,9 +151,7 @@ export class WidgetApi extends EventEmitter {
|
|||
// Save OpenID credentials
|
||||
this.setOpenIDCredentials(<ToWidgetRequest>payload);
|
||||
this.replyToRequest(<ToWidgetRequest>payload, {});
|
||||
} else if (payload.action === KnownWidgetActions.UpdateThemeInfo
|
||||
|| payload.action === KnownWidgetActions.SendWidgetConfig
|
||||
|| payload.action === KnownWidgetActions.ClosedWidgetResponse) {
|
||||
} else if (payload.action === KnownWidgetActions.GetWidgetConfig) {
|
||||
// Finalization needs to be async, so postpone with a promise
|
||||
let finalizePromise = Promise.resolve();
|
||||
const wait = (promise) => {
|
||||
|
@ -236,16 +245,16 @@ export class WidgetApi extends EventEmitter {
|
|||
});
|
||||
}
|
||||
|
||||
public closeWidget(exitData: any): Promise<any> {
|
||||
public closeModalWidget(exitData: any): Promise<any> {
|
||||
return new Promise<any>(resolve => {
|
||||
this.callAction(KnownWidgetActions.CloseWidget, exitData, null);
|
||||
this.callAction(KnownWidgetActions.CloseModalWidget, exitData, null);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
public openTempWidget(url: string, data: any): Promise<any> {
|
||||
public openModalWidget(url: string, name: string, buttons: IButton[], data: any): Promise<any> {
|
||||
return new Promise<any>(resolve => {
|
||||
this.callAction(KnownWidgetActions.OpenTempWidget, {url, data}, null);
|
||||
this.callAction(KnownWidgetActions.OpenModalWidget, {url, name, buttons, data}, null);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue