matrix-react-sdk
Version:
SDK for matrix.org using React
641 lines (624 loc) • 120 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _matrixWidgetApi = require("matrix-widget-api");
var _matrix = require("matrix-js-sdk/src/matrix");
var _types = require("matrix-js-sdk/src/types");
var _logger = require("matrix-js-sdk/src/logger");
var _WidgetLifecycle = require("@matrix-org/react-sdk-module-api/lib/lifecycles/WidgetLifecycle");
var _overflowHorizontal = _interopRequireDefault(require("@vector-im/compound-design-tokens/assets/web/icons/overflow-horizontal"));
var _AccessibleButton = _interopRequireDefault(require("./AccessibleButton"));
var _languageHandler = require("../../../languageHandler");
var _AppPermission = _interopRequireDefault(require("./AppPermission"));
var _AppWarning = _interopRequireDefault(require("./AppWarning"));
var _Spinner = _interopRequireDefault(require("./Spinner"));
var _dispatcher = _interopRequireDefault(require("../../../dispatcher/dispatcher"));
var _ActiveWidgetStore = _interopRequireDefault(require("../../../stores/ActiveWidgetStore"));
var _SettingsStore = _interopRequireDefault(require("../../../settings/SettingsStore"));
var _ContextMenu = require("../../structures/ContextMenu");
var _PersistedElement = _interopRequireWildcard(require("./PersistedElement"));
var _WidgetType = require("../../../widgets/WidgetType");
var _StopGapWidget = require("../../../stores/widgets/StopGapWidget");
var _WidgetContextMenu = require("../context_menus/WidgetContextMenu");
var _WidgetAvatar = _interopRequireDefault(require("../avatars/WidgetAvatar"));
var _LegacyCallHandler = _interopRequireDefault(require("../../../LegacyCallHandler"));
var _WidgetStore = require("../../../stores/WidgetStore");
var _minimiseCollapse = require("../../../../res/img/element-icons/minimise-collapse.svg");
var _maximiseExpand = require("../../../../res/img/element-icons/maximise-expand.svg");
var _minusButton = require("../../../../res/img/element-icons/minus-button.svg");
var _externalLink = require("../../../../res/img/feather-customised/widget/external-link.svg");
var _WidgetLayoutStore = require("../../../stores/widgets/WidgetLayoutStore");
var _OwnProfileStore = require("../../../stores/OwnProfileStore");
var _AsyncStore = require("../../../stores/AsyncStore");
var _WidgetUtils = _interopRequireDefault(require("../../../utils/WidgetUtils"));
var _MatrixClientContext = _interopRequireDefault(require("../../../contexts/MatrixClientContext"));
var _actions = require("../../../dispatcher/actions");
var _ElementWidgetCapabilities = require("../../../stores/widgets/ElementWidgetCapabilities");
var _WidgetMessagingStore = require("../../../stores/widgets/WidgetMessagingStore");
var _SDKContext = require("../../../contexts/SDKContext");
var _ModuleRunner = require("../../../modules/ModuleRunner");
var _UrlUtils = require("../../../utils/UrlUtils");
var _RightPanelStore = _interopRequireDefault(require("../../../stores/right-panel/RightPanelStore.ts"));
var _RightPanelStorePhases = require("../../../stores/right-panel/RightPanelStorePhases.ts");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /*
Copyright 2024 New Vector Ltd.
Copyright 2020-2022 The Matrix.org Foundation C.I.C.
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2018 New Vector Ltd
Copyright 2017 Vector Creations Ltd
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
class AppTile extends _react.default.Component {
constructor(_props, context) {
super(_props, context);
// Tiles in miniMode are floating, and therefore not docked
(0, _defineProperty2.default)(this, "contextMenuButton", /*#__PURE__*/(0, _react.createRef)());
(0, _defineProperty2.default)(this, "iframe", void 0);
// ref to the iframe (callback style)
(0, _defineProperty2.default)(this, "allowedWidgetsWatchRef", void 0);
(0, _defineProperty2.default)(this, "persistKey", void 0);
(0, _defineProperty2.default)(this, "sgWidget", void 0);
(0, _defineProperty2.default)(this, "dispatcherRef", void 0);
(0, _defineProperty2.default)(this, "unmounted", false);
(0, _defineProperty2.default)(this, "watchUserReady", () => {
if (_OwnProfileStore.OwnProfileStore.instance.isProfileInfoFetched) {
return;
}
_OwnProfileStore.OwnProfileStore.instance.once(_AsyncStore.UPDATE_EVENT, this.onUserReady);
});
(0, _defineProperty2.default)(this, "onUserReady", () => {
this.setState({
isUserProfileReady: true
});
});
// This is a function to make the impact of calling SettingsStore slightly less
(0, _defineProperty2.default)(this, "hasPermissionToLoad", props => {
if (this.usingLocalWidget()) return true;
if (!props.room) return true; // user widgets always have permissions
const opts = {
approved: undefined
};
_ModuleRunner.ModuleRunner.instance.invoke(_WidgetLifecycle.WidgetLifecycle.PreLoadRequest, opts, new _StopGapWidget.ElementWidget(this.props.app));
if (opts.approved) return true;
const currentlyAllowedWidgets = _SettingsStore.default.getValue("allowedWidgets", props.room.roomId);
const allowed = (0, _WidgetStore.isAppWidget)(props.app) && props.app.eventId !== undefined && (currentlyAllowedWidgets[props.app.eventId] ?? false);
return allowed || props.userId === props.creatorUserId;
});
(0, _defineProperty2.default)(this, "onMyMembership", (room, membership) => {
if ((membership === _types.KnownMembership.Leave || membership === _types.KnownMembership.Ban) && room.roomId === this.props.room?.roomId) {
this.onUserLeftRoom();
}
});
(0, _defineProperty2.default)(this, "onAllowedWidgetsChange", () => {
const hasPermissionToLoad = this.hasPermissionToLoad(this.props);
if (this.state.hasPermissionToLoad && !hasPermissionToLoad) {
// Force the widget to be non-persistent (able to be deleted/forgotten)
_ActiveWidgetStore.default.instance.destroyPersistentWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null);
_PersistedElement.default.destroyElement(this.persistKey);
this.sgWidget?.stopMessaging();
}
this.setState({
hasPermissionToLoad
});
});
(0, _defineProperty2.default)(this, "iframeRefChange", ref => {
this.iframe = ref;
if (this.unmounted) return;
if (ref) {
this.startMessaging();
} else {
this.resetWidget(this.props);
}
});
(0, _defineProperty2.default)(this, "onWidgetReady", () => {
this.setState({
loading: false
});
});
(0, _defineProperty2.default)(this, "updateRequiresClient", () => {
this.setState({
requiresClient: !!this.sgWidget?.widgetApi?.hasCapability(_ElementWidgetCapabilities.ElementWidgetCapabilities.RequiresClient)
});
});
(0, _defineProperty2.default)(this, "onAction", payload => {
switch (payload.action) {
case "m.sticker":
if (payload.widgetId === this.props.app.id && this.sgWidget?.widgetApi?.hasCapability(_matrixWidgetApi.MatrixCapabilities.StickerSending)) {
_dispatcher.default.dispatch({
action: "post_sticker_message",
data: _objectSpread(_objectSpread({}, payload.data), {}, {
threadId: this.props.threadId
})
});
_dispatcher.default.dispatch({
action: "stickerpicker_close"
});
} else {
_logger.logger.warn("Ignoring sticker message. Invalid capability");
}
break;
case _actions.Action.AfterLeaveRoom:
if (payload.room_id === this.props.room?.roomId) {
// call this before we get it echoed down /sync, so it doesn't hang around as long and look jarring
this.onUserLeftRoom();
}
break;
}
});
(0, _defineProperty2.default)(this, "grantWidgetPermission", () => {
const roomId = this.props.room?.roomId;
const eventId = (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.eventId : undefined;
_logger.logger.info("Granting permission for widget to load: " + eventId);
const current = _SettingsStore.default.getValue("allowedWidgets", roomId);
if (eventId !== undefined) current[eventId] = true;
const level = _SettingsStore.default.firstSupportedLevel("allowedWidgets");
_SettingsStore.default.setValue("allowedWidgets", roomId ?? null, level, current).then(() => {
this.setState({
hasPermissionToLoad: true
});
// Fetch a token for the integration manager, now that we're allowed to
this.startWidget();
}).catch(err => {
_logger.logger.error(err);
// We don't really need to do anything about this - the user will just hit the button again.
});
});
// TODO replace with full screen interactions
(0, _defineProperty2.default)(this, "onPopoutWidgetClick", () => {
// Ensure Jitsi conferences are closed on pop-out, to not confuse the user to join them
// twice from the same computer, which Jitsi can have problems with (audio echo/gain-loop).
if (_WidgetType.WidgetType.JITSI.matches(this.props.app.type)) {
this.reload();
}
// Using Object.assign workaround as the following opens in a new window instead of a new tab.
// window.open(this._getPopoutUrl(), '_blank', 'noopener=yes');
Object.assign(document.createElement("a"), {
target: "_blank",
href: this.sgWidget?.popoutUrl,
rel: "noreferrer noopener"
}).click();
});
(0, _defineProperty2.default)(this, "onToggleMaximisedClick", () => {
if (!this.props.room) return; // ignore action - it shouldn't even be visible
const targetContainer = _WidgetLayoutStore.WidgetLayoutStore.instance.isInContainer(this.props.room, this.props.app, _WidgetLayoutStore.Container.Center) ? _WidgetLayoutStore.Container.Top : _WidgetLayoutStore.Container.Center;
_WidgetLayoutStore.WidgetLayoutStore.instance.moveToContainer(this.props.room, this.props.app, targetContainer);
// If the right panel has a timeline, but we're about to show the timeline in the main view, pop the right panel
if (targetContainer === _WidgetLayoutStore.Container.Top && _RightPanelStore.default.instance.currentCardForRoom(this.props.room.roomId).phase === _RightPanelStorePhases.RightPanelPhases.Timeline) {
_RightPanelStore.default.instance.popCard(this.props.room.roomId);
}
});
(0, _defineProperty2.default)(this, "onMinimiseClicked", () => {
if (!this.props.room) return; // ignore action - it shouldn't even be visible
_WidgetLayoutStore.WidgetLayoutStore.instance.moveToContainer(this.props.room, this.props.app, _WidgetLayoutStore.Container.Right);
});
(0, _defineProperty2.default)(this, "onContextMenuClick", () => {
this.setState({
menuDisplayed: true
});
});
(0, _defineProperty2.default)(this, "closeContextMenu", () => {
this.setState({
menuDisplayed: false
});
});
if (!this.props.miniMode) {
_ActiveWidgetStore.default.instance.dockWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null);
}
// The key used for PersistedElement
this.persistKey = (0, _PersistedElement.getPersistKey)(_WidgetUtils.default.getWidgetUid(this.props.app));
try {
this.sgWidget = new _StopGapWidget.StopGapWidget(this.props);
this.setupSgListeners();
} catch (e) {
_logger.logger.log("Failed to construct widget", e);
this.sgWidget = null;
}
this.state = this.getNewState(_props);
}
onUserLeftRoom() {
const isActiveWidget = _ActiveWidgetStore.default.instance.getWidgetPersistence(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null);
if (isActiveWidget) {
// We just left the room that the active widget was from.
if (this.props.room && _SDKContext.SdkContextClass.instance.roomViewStore.getRoomId() !== this.props.room.roomId) {
// If we are not actively looking at the room then destroy this widget entirely.
this.endWidgetActions();
} else if (_WidgetType.WidgetType.JITSI.matches(this.props.app.type)) {
// If this was a Jitsi then reload to end call.
this.reload();
} else {
// Otherwise just cancel its persistence.
_ActiveWidgetStore.default.instance.destroyPersistentWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null);
}
}
}
determineInitialRequiresClientState() {
try {
const mockWidget = new _StopGapWidget.ElementWidget(this.props.app);
const widgetApi = _WidgetMessagingStore.WidgetMessagingStore.instance.getMessaging(mockWidget, this.props.room?.roomId);
if (widgetApi) {
// Load value from existing API to prevent resetting the requiresClient value on layout changes.
return widgetApi.hasCapability(_ElementWidgetCapabilities.ElementWidgetCapabilities.RequiresClient);
}
} catch {
// fallback to true
}
// requiresClient is initially set to true. This avoids the broken state of the popout
// button being visible (for an instance) and then disappearing when the widget is loaded.
// requiresClient <-> hide the popout button
return true;
}
/**
* Set initial component state when the App wUrl (widget URL) is being updated.
* Component props *must* be passed (rather than relying on this.props).
* @param {Object} newProps The new properties of the component
* @return {Object} Updated component state to be set with setState
*/
getNewState(newProps) {
return {
initialising: true,
// True while we are mangling the widget URL
// Don't show loading at all if the widget is ready once the IFrame is loaded (waitForIframeLoad = true).
// We only need the loading screen if the widget sends a contentLoaded event (waitForIframeLoad = false).
loading: !this.props.waitForIframeLoad && !_PersistedElement.default.isMounted(this.persistKey),
// Assume that widget has permission to load if we are the user who
// added it to the room, or if explicitly granted by the user
hasPermissionToLoad: this.hasPermissionToLoad(newProps),
isUserProfileReady: _OwnProfileStore.OwnProfileStore.instance.isProfileInfoFetched,
error: null,
menuDisplayed: false,
requiresClient: this.determineInitialRequiresClientState(),
hasContextMenuOptions: (0, _WidgetContextMenu.showContextMenu)(this.context, this.props.room, newProps.app, newProps.userWidget, !newProps.userWidget, newProps.onDeleteClick)
};
}
isMixedContent() {
const parentContentProtocol = window.location.protocol;
const u = (0, _UrlUtils.parseUrl)(this.props.app.url);
const childContentProtocol = u.protocol;
if (parentContentProtocol === "https:" && childContentProtocol !== "https:") {
_logger.logger.warn("Refusing to load mixed-content app:", parentContentProtocol, childContentProtocol, window.location, this.props.app.url);
return true;
}
return false;
}
componentDidMount() {
// Only fetch IM token on mount if we're showing and have permission to load
if (this.sgWidget && this.state.hasPermissionToLoad) {
this.startWidget();
}
this.watchUserReady();
if (this.props.room) {
this.context.on(_matrix.RoomEvent.MyMembership, this.onMyMembership);
}
this.allowedWidgetsWatchRef = _SettingsStore.default.watchSetting("allowedWidgets", null, this.onAllowedWidgetsChange);
// Widget action listeners
this.dispatcherRef = _dispatcher.default.register(this.onAction);
}
componentWillUnmount() {
this.unmounted = true;
if (!this.props.miniMode) {
_ActiveWidgetStore.default.instance.undockWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null);
}
// Only tear down the widget if no other component is keeping it alive,
// because we support moving widgets between containers, in which case
// another component will keep it loaded throughout the transition
if (!_ActiveWidgetStore.default.instance.isLive(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null)) {
this.endWidgetActions();
}
// Widget action listeners
if (this.dispatcherRef) _dispatcher.default.unregister(this.dispatcherRef);
if (this.props.room) {
this.context.off(_matrix.RoomEvent.MyMembership, this.onMyMembership);
}
if (this.allowedWidgetsWatchRef) _SettingsStore.default.unwatchSetting(this.allowedWidgetsWatchRef);
_OwnProfileStore.OwnProfileStore.instance.removeListener(_AsyncStore.UPDATE_EVENT, this.onUserReady);
}
setupSgListeners() {
this.sgWidget?.on("ready", this.onWidgetReady);
this.sgWidget?.on("error:preparing", this.updateRequiresClient);
// emits when the capabilities have been set up or changed
this.sgWidget?.on("capabilitiesNotified", this.updateRequiresClient);
}
stopSgListeners() {
if (!this.sgWidget) return;
this.sgWidget?.off("ready", this.onWidgetReady);
this.sgWidget.off("error:preparing", this.updateRequiresClient);
this.sgWidget.off("capabilitiesNotified", this.updateRequiresClient);
}
resetWidget(newProps) {
this.sgWidget?.stopMessaging();
this.stopSgListeners();
try {
this.sgWidget = new _StopGapWidget.StopGapWidget(newProps);
this.setupSgListeners();
this.startWidget();
} catch (e) {
_logger.logger.error("Failed to construct widget", e);
this.sgWidget = null;
}
}
startWidget() {
this.sgWidget?.prepare().then(() => {
if (this.unmounted) return;
this.setState({
initialising: false
});
});
}
startMessaging() {
try {
this.sgWidget?.startMessaging(this.iframe);
} catch (e) {
_logger.logger.error("Failed to start widget", e);
}
}
componentDidUpdate(prevProps) {
if (prevProps.app.url !== this.props.app.url) {
this.getNewState(this.props);
if (this.state.hasPermissionToLoad) {
this.resetWidget(this.props);
}
}
}
/**
* Ends all widget interaction, such as cancelling calls and disabling webcams.
* @private
* @returns {Promise<*>} Resolves when the widget is terminated, or timeout passed.
*/
async endWidgetActions() {
// widget migration dev note: async to maintain signature
// HACK: This is a really dirty way to ensure that Jitsi cleans up
// its hold on the webcam. Without this, the widget holds a media
// stream open, even after death. See https://github.com/vector-im/element-web/issues/7351
if (this.iframe) {
// In practice we could just do `+= ''` to trick the browser
// into thinking the URL changed, however I can foresee this
// being optimized out by a browser. Instead, we'll just point
// the iframe at a page that is reasonably safe to use in the
// event the iframe doesn't wink away.
// This is relative to where the Element instance is located.
this.iframe.src = "about:blank";
}
if (_WidgetType.WidgetType.JITSI.matches(this.props.app.type) && this.props.room) {
_LegacyCallHandler.default.instance.hangupCallApp(this.props.room.roomId);
}
// Delete the widget from the persisted store for good measure.
_PersistedElement.default.destroyElement(this.persistKey);
_ActiveWidgetStore.default.instance.destroyPersistentWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null);
this.sgWidget?.stopMessaging({
forceDestroy: true
});
}
formatAppTileName() {
let appTileName = "No name";
if (this.props.app.name && this.props.app.name.trim()) {
appTileName = this.props.app.name.trim();
}
return appTileName;
}
/**
* Whether we're using a local version of the widget rather than loading the
* actual widget URL
* @returns {bool} true If using a local version of the widget
*/
usingLocalWidget() {
return _WidgetType.WidgetType.JITSI.matches(this.props.app.type);
}
getTileTitle() {
const name = this.formatAppTileName();
const titleSpacer = /*#__PURE__*/_react.default.createElement("span", null, "\xA0-\xA0");
let title = "";
if (this.props.widgetPageTitle && this.props.widgetPageTitle !== this.formatAppTileName()) {
title = this.props.widgetPageTitle;
}
return /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement(_WidgetAvatar.default, {
app: this.props.app,
size: "20px"
}), /*#__PURE__*/_react.default.createElement("h3", null, name), /*#__PURE__*/_react.default.createElement("span", null, title ? titleSpacer : "", title));
}
reload() {
this.endWidgetActions().then(() => {
// reset messaging
this.resetWidget(this.props);
this.startMessaging();
if (this.iframe && this.sgWidget) {
// Reload iframe
this.iframe.src = this.sgWidget.embedUrl;
}
});
}
render() {
let appTileBody;
// Note that there is advice saying allow-scripts shouldn't be used with allow-same-origin
// because that would allow the iframe to programmatically remove the sandbox attribute, but
// this would only be for content hosted on the same origin as the element client: anything
// hosted on the same origin as the client will get the same access as if you clicked
// a link to it.
const sandboxFlags = "allow-forms allow-popups allow-popups-to-escape-sandbox " + "allow-same-origin allow-scripts allow-presentation allow-downloads";
// Additional iframe feature permissions
// (see - https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-permissions-in-cross-origin-iframes and https://wicg.github.io/feature-policy/)
const iframeFeatures = "microphone; camera; encrypted-media; autoplay; display-capture; clipboard-write; " + "clipboard-read;";
const appTileBodyClass = (0, _classnames.default)({
"mx_AppTileBody": true,
"mx_AppTileBody--large": !this.props.miniMode,
"mx_AppTileBody--mini": this.props.miniMode,
"mx_AppTileBody--loading": this.state.loading,
// We don't want mx_AppTileBody (rounded corners) for call widgets
"mx_AppTileBody--call": this.props.app.type === _WidgetType.WidgetType.CALL.preferred
});
const appTileBodyStyles = {};
if (this.props.pointerEvents) {
appTileBodyStyles.pointerEvents = this.props.pointerEvents;
}
const loadingElement = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AppTileBody_fadeInSpinner"
}, /*#__PURE__*/_react.default.createElement(_Spinner.default, {
message: (0, _languageHandler._t)("common|loading")
}));
const widgetTitle = _WidgetUtils.default.getWidgetName(this.props.app);
if (this.sgWidget === null) {
appTileBody = /*#__PURE__*/_react.default.createElement("div", {
className: appTileBodyClass,
style: appTileBodyStyles
}, /*#__PURE__*/_react.default.createElement(_AppWarning.default, {
errorMsg: (0, _languageHandler._t)("widget|error_loading")
}));
} else if (!this.state.hasPermissionToLoad && this.props.room) {
// only possible for room widgets, can assert this.props.room here
const isEncrypted = this.context.isRoomEncrypted(this.props.room.roomId);
appTileBody = /*#__PURE__*/_react.default.createElement("div", {
className: appTileBodyClass,
style: appTileBodyStyles
}, /*#__PURE__*/_react.default.createElement(_AppPermission.default, {
roomId: this.props.room.roomId,
creatorUserId: this.props.creatorUserId,
url: this.sgWidget.embedUrl,
isRoomEncrypted: isEncrypted,
onPermissionGranted: this.grantWidgetPermission
}));
} else if (this.state.initialising || !this.state.isUserProfileReady) {
appTileBody = /*#__PURE__*/_react.default.createElement("div", {
className: appTileBodyClass,
style: appTileBodyStyles
}, loadingElement);
} else {
if (this.isMixedContent()) {
appTileBody = /*#__PURE__*/_react.default.createElement("div", {
className: appTileBodyClass,
style: appTileBodyStyles
}, /*#__PURE__*/_react.default.createElement(_AppWarning.default, {
errorMsg: (0, _languageHandler._t)("widget|error_mixed_content")
}));
} else {
appTileBody = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
className: appTileBodyClass,
style: appTileBodyStyles
}, this.state.loading && loadingElement, /*#__PURE__*/_react.default.createElement("iframe", {
title: widgetTitle,
allow: iframeFeatures,
ref: this.iframeRefChange,
src: this.sgWidget.embedUrl,
allowFullScreen: true,
sandbox: sandboxFlags
})), this.props.overlay);
if (!this.props.userWidget) {
// All room widgets can theoretically be allowed to remain on screen, so we
// wrap them all in a PersistedElement from the get-go. If we wait, the iframe
// will be re-mounted later, which means the widget has to start over, which is
// bad.
// Also wrap the PersistedElement in a div to fix the height, otherwise
// AppTile's border is in the wrong place
// For persisted apps in PiP we want the zIndex to be higher then for other persisted apps (100)
// otherwise there are issues that the PiP view is drawn UNDER another widget (Persistent app) when dragged around.
const zIndexAboveOtherPersistentElements = 101;
appTileBody = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AppTile_persistedWrapper"
}, /*#__PURE__*/_react.default.createElement(_PersistedElement.default, {
zIndex: this.props.miniMode ? zIndexAboveOtherPersistentElements : 9,
persistKey: this.persistKey,
moveRef: this.props.movePersistedElement
}, appTileBody));
}
}
}
let appTileClasses;
if (this.props.miniMode) {
appTileClasses = {
mx_AppTile_mini: true
};
} else if (this.props.fullWidth) {
appTileClasses = {
mx_AppTileFullWidth: true
};
} else {
appTileClasses = {
mx_AppTile: true
};
}
appTileClasses = (0, _classnames.default)(appTileClasses);
let contextMenu;
if (this.state.menuDisplayed) {
contextMenu = /*#__PURE__*/_react.default.createElement(_WidgetContextMenu.WidgetContextMenu, (0, _extends2.default)({}, (0, _ContextMenu.aboveLeftOf)(this.contextMenuButton.current.getBoundingClientRect()), {
app: this.props.app,
onFinished: this.closeContextMenu,
showUnpin: !this.props.userWidget,
userWidget: this.props.userWidget,
onEditClick: this.props.onEditClick,
onDeleteClick: this.props.onDeleteClick
}));
}
const layoutButtons = [];
if (this.props.showLayoutButtons) {
const isMaximised = this.props.room && _WidgetLayoutStore.WidgetLayoutStore.instance.isInContainer(this.props.room, this.props.app, _WidgetLayoutStore.Container.Center);
layoutButtons.push( /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
key: "toggleMaximised",
className: "mx_AppTileMenuBar_widgets_button",
title: isMaximised ? (0, _languageHandler._t)("widget|unmaximise") : (0, _languageHandler._t)("action|maximise"),
onClick: this.onToggleMaximisedClick
}, isMaximised ? /*#__PURE__*/_react.default.createElement(_minimiseCollapse.Icon, {
className: "mx_Icon mx_Icon_12"
}) : /*#__PURE__*/_react.default.createElement(_maximiseExpand.Icon, {
className: "mx_Icon mx_Icon_12"
})));
layoutButtons.push( /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
key: "minimise",
className: "mx_AppTileMenuBar_widgets_button",
title: (0, _languageHandler._t)("action|minimise"),
onClick: this.onMinimiseClicked
}, /*#__PURE__*/_react.default.createElement(_minusButton.Icon, {
className: "mx_Icon mx_Icon_12"
})));
}
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
className: appTileClasses,
id: this.props.app.id
}, this.props.showMenubar && /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AppTileMenuBar"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_AppTileMenuBar_title",
style: {
pointerEvents: this.props.handleMinimisePointerEvents ? "all" : "none"
}
}, this.props.showTitle && this.getTileTitle()), /*#__PURE__*/_react.default.createElement("span", {
className: "mx_AppTileMenuBar_widgets"
}, layoutButtons, this.props.showPopout && !this.state.requiresClient && /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
className: "mx_AppTileMenuBar_widgets_button",
title: (0, _languageHandler._t)("widget|popout"),
onClick: this.onPopoutWidgetClick
}, /*#__PURE__*/_react.default.createElement(_externalLink.Icon, {
className: "mx_Icon mx_Icon_12 mx_Icon--stroke"
})), this.state.hasContextMenuOptions && /*#__PURE__*/_react.default.createElement(_ContextMenu.ContextMenuButton, {
className: "mx_AppTileMenuBar_widgets_button",
label: (0, _languageHandler._t)("common|options"),
isExpanded: this.state.menuDisplayed,
ref: this.contextMenuButton,
onClick: this.onContextMenuClick
}, /*#__PURE__*/_react.default.createElement(_overflowHorizontal.default, {
className: "mx_Icon mx_Icon_12"
})))), appTileBody), contextMenu);
}
}
exports.default = AppTile;
(0, _defineProperty2.default)(AppTile, "contextType", _MatrixClientContext.default);
(0, _defineProperty2.default)(AppTile, "defaultProps", {
waitForIframeLoad: true,
showMenubar: true,
showTitle: true,
showPopout: true,
handleMinimisePointerEvents: false,
userWidget: false,
miniMode: false,
threadId: null,
showLayoutButtons: true
});
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfY2xhc3NuYW1lcyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfbWF0cml4V2lkZ2V0QXBpIiwiX21hdHJpeCIsIl90eXBlcyIsIl9sb2dnZXIiLCJfV2lkZ2V0TGlmZWN5Y2xlIiwiX292ZXJmbG93SG9yaXpvbnRhbCIsIl9BY2Nlc3NpYmxlQnV0dG9uIiwiX2xhbmd1YWdlSGFuZGxlciIsIl9BcHBQZXJtaXNzaW9uIiwiX0FwcFdhcm5pbmciLCJfU3Bpbm5lciIsIl9kaXNwYXRjaGVyIiwiX0FjdGl2ZVdpZGdldFN0b3JlIiwiX1NldHRpbmdzU3RvcmUiLCJfQ29udGV4dE1lbnUiLCJfUGVyc2lzdGVkRWxlbWVudCIsIl9XaWRnZXRUeXBlIiwiX1N0b3BHYXBXaWRnZXQiLCJfV2lkZ2V0Q29udGV4dE1lbnUiLCJfV2lkZ2V0QXZhdGFyIiwiX0xlZ2FjeUNhbGxIYW5kbGVyIiwiX1dpZGdldFN0b3JlIiwiX21pbmltaXNlQ29sbGFwc2UiLCJfbWF4aW1pc2VFeHBhbmQiLCJfbWludXNCdXR0b24iLCJfZXh0ZXJuYWxMaW5rIiwiX1dpZGdldExheW91dFN0b3JlIiwiX093blByb2ZpbGVTdG9yZSIsIl9Bc3luY1N0b3JlIiwiX1dpZGdldFV0aWxzIiwiX01hdHJpeENsaWVudENvbnRleHQiLCJfYWN0aW9ucyIsIl9FbGVtZW50V2lkZ2V0Q2FwYWJpbGl0aWVzIiwiX1dpZGdldE1lc3NhZ2luZ1N0b3JlIiwiX1NES0NvbnRleHQiLCJfTW9kdWxlUnVubmVyIiwiX1VybFV0aWxzIiwiX1JpZ2h0UGFuZWxTdG9yZSIsIl9SaWdodFBhbmVsU3RvcmVQaGFzZXMiLCJfZ2V0UmVxdWlyZVdpbGRjYXJkQ2FjaGUiLCJlIiwiV2Vha01hcCIsInIiLCJ0IiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJoYXMiLCJnZXQiLCJuIiwiX19wcm90b19fIiwiYSIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwidSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImkiLCJzZXQiLCJvd25LZXlzIiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJBcHBUaWxlIiwiUmVhY3QiLCJDb21wb25lbnQiLCJjb25zdHJ1Y3RvciIsInByb3BzIiwiY29udGV4dCIsImNyZWF0ZVJlZiIsIk93blByb2ZpbGVTdG9yZSIsImluc3RhbmNlIiwiaXNQcm9maWxlSW5mb0ZldGNoZWQiLCJvbmNlIiwiVVBEQVRFX0VWRU5UIiwib25Vc2VyUmVhZHkiLCJzZXRTdGF0ZSIsImlzVXNlclByb2ZpbGVSZWFkeSIsInVzaW5nTG9jYWxXaWRnZXQiLCJyb29tIiwib3B0cyIsImFwcHJvdmVkIiwidW5kZWZpbmVkIiwiTW9kdWxlUnVubmVyIiwiaW52b2tlIiwiV2lkZ2V0TGlmZWN5Y2xlIiwiUHJlTG9hZFJlcXVlc3QiLCJFbGVtZW50V2lkZ2V0IiwiYXBwIiwiY3VycmVudGx5QWxsb3dlZFdpZGdldHMiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJyb29tSWQiLCJhbGxvd2VkIiwiaXNBcHBXaWRnZXQiLCJldmVudElkIiwidXNlcklkIiwiY3JlYXRvclVzZXJJZCIsIm1lbWJlcnNoaXAiLCJLbm93bk1lbWJlcnNoaXAiLCJMZWF2ZSIsIkJhbiIsIm9uVXNlckxlZnRSb29tIiwiaGFzUGVybWlzc2lvblRvTG9hZCIsInN0YXRlIiwiQWN0aXZlV2lkZ2V0U3RvcmUiLCJkZXN0cm95UGVyc2lzdGVudFdpZGdldCIsImlkIiwiUGVyc2lzdGVkRWxlbWVudCIsImRlc3Ryb3lFbGVtZW50IiwicGVyc2lzdEtleSIsInNnV2lkZ2V0Iiwic3RvcE1lc3NhZ2luZyIsInJlZiIsImlmcmFtZSIsInVubW91bnRlZCIsInN0YXJ0TWVzc2FnaW5nIiwicmVzZXRXaWRnZXQiLCJsb2FkaW5nIiwicmVxdWlyZXNDbGllbnQiLCJ3aWRnZXRBcGkiLCJoYXNDYXBhYmlsaXR5IiwiRWxlbWVudFdpZGdldENhcGFiaWxpdGllcyIsIlJlcXVpcmVzQ2xpZW50IiwicGF5bG9hZCIsImFjdGlvbiIsIndpZGdldElkIiwiTWF0cml4Q2FwYWJpbGl0aWVzIiwiU3RpY2tlclNlbmRpbmciLCJkaXMiLCJkaXNwYXRjaCIsImRhdGEiLCJ0aHJlYWRJZCIsImxvZ2dlciIsIndhcm4iLCJBY3Rpb24iLCJBZnRlckxlYXZlUm9vbSIsInJvb21faWQiLCJpbmZvIiwiY3VycmVudCIsImxldmVsIiwiZmlyc3RTdXBwb3J0ZWRMZXZlbCIsInNldFZhbHVlIiwidGhlbiIsInN0YXJ0V2lkZ2V0IiwiY2F0Y2giLCJlcnIiLCJlcnJvciIsIldpZGdldFR5cGUiLCJKSVRTSSIsIm1hdGNoZXMiLCJ0eXBlIiwicmVsb2FkIiwiYXNzaWduIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50IiwidGFyZ2V0IiwiaHJlZiIsInBvcG91dFVybCIsInJlbCIsImNsaWNrIiwidGFyZ2V0Q29udGFpbmVyIiwiV2lkZ2V0TGF5b3V0U3RvcmUiLCJpc0luQ29udGFpbmVyIiwiQ29udGFpbmVyIiwiQ2VudGVyIiwiVG9wIiwibW92ZVRvQ29udGFpbmVyIiwiUmlnaHRQYW5lbFN0b3JlIiwiY3VycmVudENhcmRGb3JSb29tIiwicGhhc2UiLCJSaWdodFBhbmVsUGhhc2VzIiwiVGltZWxpbmUiLCJwb3BDYXJkIiwiUmlnaHQiLCJtZW51RGlzcGxheWVkIiwibWluaU1vZGUiLCJkb2NrV2lkZ2V0IiwiZ2V0UGVyc2lzdEtleSIsIldpZGdldFV0aWxzIiwiZ2V0V2lkZ2V0VWlkIiwiU3RvcEdhcFdpZGdldCIsInNldHVwU2dMaXN0ZW5lcnMiLCJsb2ciLCJnZXROZXdTdGF0ZSIsImlzQWN0aXZlV2lkZ2V0IiwiZ2V0V2lkZ2V0UGVyc2lzdGVuY2UiLCJTZGtDb250ZXh0Q2xhc3MiLCJyb29tVmlld1N0b3JlIiwiZ2V0Um9vbUlkIiwiZW5kV2lkZ2V0QWN0aW9ucyIsImRldGVybWluZUluaXRpYWxSZXF1aXJlc0NsaWVudFN0YXRlIiwibW9ja1dpZGdldCIsIldpZGdldE1lc3NhZ2luZ1N0b3JlIiwiZ2V0TWVzc2FnaW5nIiwibmV3UHJvcHMiLCJpbml0aWFsaXNpbmciLCJ3YWl0Rm9ySWZyYW1lTG9hZCIsImlzTW91bnRlZCIsImhhc0NvbnRleHRNZW51T3B0aW9ucyIsInNob3dDb250ZXh0TWVudSIsInVzZXJXaWRnZXQiLCJvbkRlbGV0ZUNsaWNrIiwiaXNNaXhlZENvbnRlbnQiLCJwYXJlbnRDb250ZW50UHJvdG9jb2wiLCJ3aW5kb3ciLCJsb2NhdGlvbiIsInByb3RvY29sIiwicGFyc2VVcmwiLCJ1cmwiLCJjaGlsZENvbnRlbnRQcm90b2NvbCIsImNvbXBvbmVudERpZE1vdW50Iiwid2F0Y2hVc2VyUmVhZHkiLCJvbiIsIlJvb21FdmVudCIsIk15TWVtYmVyc2hpcCIsIm9uTXlNZW1iZXJzaGlwIiwiYWxsb3dlZFdpZGdldHNXYXRjaFJlZiIsIndhdGNoU2V0dGluZyIsIm9uQWxsb3dlZFdpZGdldHNDaGFuZ2UiLCJkaXNwYXRjaGVyUmVmIiwicmVnaXN0ZXIiLCJvbkFjdGlvbiIsImNvbXBvbmVudFdpbGxVbm1vdW50IiwidW5kb2NrV2lkZ2V0IiwiaXNMaXZlIiwidW5yZWdpc3RlciIsIm9mZiIsInVud2F0Y2hTZXR0aW5nIiwicmVtb3ZlTGlzdGVuZXIiLCJvbldpZGdldFJlYWR5IiwidXBkYXRlUmVxdWlyZXNDbGllbnQiLCJzdG9wU2dMaXN0ZW5lcnMiLCJwcmVwYXJlIiwiY29tcG9uZW50RGlkVXBkYXRlIiwicHJldlByb3BzIiwic3JjIiwiTGVnYWN5Q2FsbEhhbmRsZXIiLCJoYW5ndXBDYWxsQXBwIiwiZm9yY2VEZXN0cm95IiwiZm9ybWF0QXBwVGlsZU5hbWUiLCJhcHBUaWxlTmFtZSIsIm5hbWUiLCJ0cmltIiwiZ2V0VGlsZVRpdGxlIiwidGl0bGVTcGFjZXIiLCJ0aXRsZSIsIndpZGdldFBhZ2VUaXRsZSIsInNpemUiLCJlbWJlZFVybCIsInJlbmRlciIsImFwcFRpbGVCb2R5Iiwic2FuZGJveEZsYWdzIiwiaWZyYW1lRmVhdHVyZXMiLCJhcHBUaWxlQm9keUNsYXNzIiwiY2xhc3NOYW1lcyIsIkNBTEwiLCJwcmVmZXJyZWQiLCJhcHBUaWxlQm9keVN0eWxlcyIsInBvaW50ZXJFdmVudHMiLCJsb2FkaW5nRWxlbWVudCIsImNsYXNzTmFtZSIsIm1lc3NhZ2UiLCJfdCIsIndpZGdldFRpdGxlIiwiZ2V0V2lkZ2V0TmFtZSIsInN0eWxlIiwiZXJyb3JNc2ciLCJpc0VuY3J5cHRlZCIsImlzUm9vbUVuY3J5cHRlZCIsIm9uUGVybWlzc2lvbkdyYW50ZWQiLCJncmFudFdpZGdldFBlcm1pc3Npb24iLCJGcmFnbWVudCIsImFsbG93IiwiaWZyYW1lUmVmQ2hhbmdlIiwiYWxsb3dGdWxsU2NyZWVuIiwic2FuZGJveCIsIm92ZXJsYXkiLCJ6SW5kZXhBYm92ZU90aGVyUGVyc2lzdGVudEVsZW1lbnRzIiwiekluZGV4IiwibW92ZVJlZiIsIm1vdmVQZXJzaXN0ZWRFbGVtZW50IiwiYXBwVGlsZUNsYXNzZXMiLCJteF9BcHBUaWxlX21pbmkiLCJmdWxsV2lkdGgiLCJteF9BcHBUaWxlRnVsbFdpZHRoIiwibXhfQXBwVGlsZSIsImNvbnRleHRNZW51IiwiV2lkZ2V0Q29udGV4dE1lbnUiLCJfZXh0ZW5kczIiLCJhYm92ZUxlZnRPZiIsImNvbnRleHRNZW51QnV0dG9uIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0Iiwib25GaW5pc2hlZCIsImNsb3NlQ29udGV4dE1lbnUiLCJzaG93VW5waW4iLCJvbkVkaXRDbGljayIsImxheW91dEJ1dHRvbnMiLCJzaG93TGF5b3V0QnV0dG9ucyIsImlzTWF4aW1pc2VkIiwia2V5Iiwib25DbGljayIsIm9uVG9nZ2xlTWF4aW1pc2VkQ2xpY2siLCJJY29uIiwib25NaW5pbWlzZUNsaWNrZWQiLCJzaG93TWVudWJhciIsImhhbmRsZU1pbmltaXNlUG9pbnRlckV2ZW50cyIsInNob3dUaXRsZSIsInNob3dQb3BvdXQiLCJvblBvcG91dFdpZGdldENsaWNrIiwiQ29udGV4dE1lbnVCdXR0b24iLCJsYWJlbCIsImlzRXhwYW5kZWQiLCJvbkNvbnRleHRNZW51Q2xpY2siLCJleHBvcnRzIiwiTWF0cml4Q2xpZW50Q29udGV4dCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL2VsZW1lbnRzL0FwcFRpbGUudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIwLTIwMjIgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cbkNvcHlyaWdodCAyMDE5IE1pY2hhZWwgVGVsYXR5bnNraSA8N3QzY2hndXlAZ21haWwuY29tPlxuQ29weXJpZ2h0IDIwMTggTmV3IFZlY3RvciBMdGRcbkNvcHlyaWdodCAyMDE3IFZlY3RvciBDcmVhdGlvbnMgTHRkXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCBSZWFjdCwgeyBDb250ZXh0VHlwZSwgY3JlYXRlUmVmLCBDU1NQcm9wZXJ0aWVzLCBNdXRhYmxlUmVmT2JqZWN0LCBSZWFjdE5vZGUgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCBjbGFzc05hbWVzIGZyb20gXCJjbGFzc25hbWVzXCI7XG5pbXBvcnQgeyBJV2lkZ2V0LCBNYXRyaXhDYXBhYmlsaXRpZXMgfSBmcm9tIFwibWF0cml4LXdpZGdldC1hcGlcIjtcbmltcG9ydCB7IFJvb20sIFJvb21FdmVudCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IEtub3duTWVtYmVyc2hpcCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy90eXBlc1wiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgQXBwcm92YWxPcHRzLCBXaWRnZXRMaWZlY3ljbGUgfSBmcm9tIFwiQG1hdHJpeC1vcmcvcmVhY3Qtc2RrLW1vZHVsZS1hcGkvbGliL2xpZmVjeWNsZXMvV2lkZ2V0TGlmZWN5Y2xlXCI7XG5pbXBvcnQgRWxsaXBzaXNJY29uIGZyb20gXCJAdmVjdG9yLWltL2NvbXBvdW5kLWRlc2lnbi10b2tlbnMvYXNzZXRzL3dlYi9pY29ucy9vdmVyZmxvdy1ob3Jpem9udGFsXCI7XG5cbmltcG9ydCBBY2Nlc3NpYmxlQnV0dG9uIGZyb20gXCIuL0FjY2Vzc2libGVCdXR0b25cIjtcbmltcG9ydCB7IF90IH0gZnJvbSBcIi4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IEFwcFBlcm1pc3Npb24gZnJvbSBcIi4vQXBwUGVybWlzc2lvblwiO1xuaW1wb3J0IEFwcFdhcm5pbmcgZnJvbSBcIi4vQXBwV2FybmluZ1wiO1xuaW1wb3J0IFNwaW5uZXIgZnJvbSBcIi4vU3Bpbm5lclwiO1xuaW1wb3J0IGRpcyBmcm9tIFwiLi4vLi4vLi4vZGlzcGF0Y2hlci9kaXNwYXRjaGVyXCI7XG5pbXBvcnQgQWN0aXZlV2lkZ2V0U3RvcmUgZnJvbSBcIi4uLy4uLy4uL3N0b3Jlcy9BY3RpdmVXaWRnZXRTdG9yZVwiO1xuaW1wb3J0IFNldHRpbmdzU3RvcmUgZnJvbSBcIi4uLy4uLy4uL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7IGFib3ZlTGVmdE9mLCBDb250ZXh0TWVudUJ1dHRvbiB9IGZyb20gXCIuLi8uLi9zdHJ1Y3R1cmVzL0NvbnRleHRNZW51XCI7XG5pbXBvcnQgUGVyc2lzdGVkRWxlbWVudCwgeyBnZXRQZXJzaXN0S2V5IH0gZnJvbSBcIi4vUGVyc2lzdGVkRWxlbWVudFwiO1xuaW1wb3J0IHsgV2lkZ2V0VHlwZSB9IGZyb20gXCIuLi8uLi8uLi93aWRnZXRzL1dpZGdldFR5cGVcIjtcbmltcG9ydCB7IEVsZW1lbnRXaWRnZXQsIFN0b3BHYXBXaWRnZXQgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3dpZGdldHMvU3RvcEdhcFdpZGdldFwiO1xuaW1wb3J0IHsgc2hvd0NvbnRleHRNZW51LCBXaWRnZXRDb250ZXh0TWVudSB9IGZyb20gXCIuLi9jb250ZXh0X21lbnVzL1dpZGdldENvbnRleHRNZW51XCI7XG5pbXBvcnQgV2lkZ2V0QXZhdGFyIGZyb20gXCIuLi9hdmF0YXJzL1dpZGdldEF2YXRhclwiO1xuaW1wb3J0IExlZ2FjeUNhbGxIYW5kbGVyIGZyb20gXCIuLi8uLi8uLi9MZWdhY3lDYWxsSGFuZGxlclwiO1xuaW1wb3J0IHsgSUFwcCwgaXNBcHBXaWRnZXQgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL1dpZGdldFN0b3JlXCI7XG5pbXBvcnQgeyBJY29uIGFzIENvbGxhcHNlSWNvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi9yZXMvaW1nL2VsZW1lbnQtaWNvbnMvbWluaW1pc2UtY29sbGFwc2Uuc3ZnXCI7XG5pbXBvcnQgeyBJY29uIGFzIE1heGltaXNlSWNvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi9yZXMvaW1nL2VsZW1lbnQtaWNvbnMvbWF4aW1pc2UtZXhwYW5kLnN2Z1wiO1xuaW1wb3J0IHsgSWNvbiBhcyBNaW5pbWlzZUljb24gfSBmcm9tIFwiLi4vLi4vLi4vLi4vcmVzL2ltZy9lbGVtZW50LWljb25zL21pbnVzLWJ1dHRvbi5zdmdcIjtcbmltcG9ydCB7IEljb24gYXMgUG9wb3V0SWNvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi9yZXMvaW1nL2ZlYXRoZXItY3VzdG9taXNlZC93aWRnZXQvZXh0ZXJuYWwtbGluay5zdmdcIjtcbmltcG9ydCB7IENvbnRhaW5lciwgV2lkZ2V0TGF5b3V0U3RvcmUgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3dpZGdldHMvV2lkZ2V0TGF5b3V0U3RvcmVcIjtcbmltcG9ydCB7IE93blByb2ZpbGVTdG9yZSB9IGZyb20gXCIuLi8uLi8uLi9zdG9yZXMvT3duUHJvZmlsZVN0b3JlXCI7XG5pbXBvcnQgeyBVUERBVEVfRVZFTlQgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL0FzeW5jU3RvcmVcIjtcbmltcG9ydCBXaWRnZXRVdGlscyBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvV2lkZ2V0VXRpbHNcIjtcbmltcG9ydCBNYXRyaXhDbGllbnRDb250ZXh0IGZyb20gXCIuLi8uLi8uLi9jb250ZXh0cy9NYXRyaXhDbGllbnRDb250ZXh0XCI7XG5pbXBvcnQgeyBBY3Rpb25QYXlsb2FkIH0gZnJvbSBcIi4uLy4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHNcIjtcbmltcG9ydCB7IEFjdGlvbiB9IGZyb20gXCIuLi8uLi8uLi9kaXNwYXRjaGVyL2FjdGlvbnNcIjtcbmltcG9ydCB7IEVsZW1lbnRXaWRnZXRDYXBhYmlsaXRpZXMgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3dpZGdldHMvRWxlbWVudFdpZGdldENhcGFiaWxpdGllc1wiO1xuaW1wb3J0IHsgV2lkZ2V0TWVzc2FnaW5nU3RvcmUgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3dpZGdldHMvV2lkZ2V0TWVzc2FnaW5nU3RvcmVcIjtcbmltcG9ydCB7IFNka0NvbnRleHRDbGFzcyB9IGZyb20gXCIuLi8uLi8uLi9jb250ZXh0cy9TREtDb250ZXh0XCI7XG5pbXBvcnQgeyBNb2R1bGVSdW5uZXIgfSBmcm9tIFwiLi4vLi4vLi4vbW9kdWxlcy9Nb2R1bGVSdW5uZXJcIjtcbmltcG9ydCB7IHBhcnNlVXJsIH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL1VybFV0aWxzXCI7XG5pbXBvcnQgUmlnaHRQYW5lbFN0b3JlIGZyb20gXCIuLi8uLi8uLi9zdG9yZXMvcmlnaHQtcGFuZWwvUmlnaHRQYW5lbFN0b3JlLnRzXCI7XG5pbXBvcnQgeyBSaWdodFBhbmVsUGhhc2VzIH0gZnJvbSBcIi4uLy4uLy4uL3N0b3Jlcy9yaWdodC1wYW5lbC9SaWdodFBhbmVsU3RvcmVQaGFzZXMudHNcIjtcblxuaW50ZXJmYWNlIElQcm9wcyB7XG4gICAgYXBwOiBJV2lkZ2V0IHwgSUFwcDtcbiAgICAvLyBJZiByb29tIGlzIG5vdCBzcGVjaWZpZWQgdGhlbiBpdCBpcyBhbiBhY2NvdW50IGxldmVsIHdpZGdldFxuICAgIC8vIHdoaWNoIGJ5cGFzc2VzIHBlcm1pc3Npb24gcHJvbXB0cyBhcyBpdCB3YXMgYWRkZWQgZXhwbGljaXRseSBieSB0aGF0IHVzZXJcbiAgICByb29tPzogUm9vbTtcbiAgICB0aHJlYWRJZD86IHN0cmluZyB8IG51bGw7XG4gICAgLy8gU3BlY2lmeWluZyAnZnVsbFdpZHRoJyBhcyB0cnVlIHdpbGwgcmVuZGVyIHRoZSBhcHAgdGlsZSB0byBmaWxsIHRoZSB3aWR0aCBvZiB0aGUgYXBwIGRyYXdlciBjb250YWluZXIuXG4gICAgLy8gVGhpcyBzaG91bGQgYmUgc2V0IHRvIHRydWUgd2hlbiB0aGVyZSBpcyBvbmx5IG9uZSB3aWRnZXQgaW4gdGhlIGFwcCBkcmF3ZXIsIG90aGVyd2lzZSBpdCBzaG91bGQgYmUgZmFsc2UuXG4gICAgZnVsbFdpZHRoPzogYm9vbGVhbjtcbiAgICAvLyBPcHRpb25hbC4gSWYgc2V0LCByZW5kZXJzIGEgc21hbGxlciB2aWV3IG9mIHRoZSB3aWRnZXRcbiAgICBtaW5pTW9kZT86IGJvb2xlYW47XG4gICAgLy8gVXNlcklkIG9mIHRoZSBjdXJyZW50IHVzZXJcbiAgICB1c2VySWQ6IHN0cmluZztcbiAgICAvLyBVc2VySWQgb2YgdGhlIGVudGl0eSB0aGF0IGFkZGVkIC8gbW9kaWZpZWQgdGhlIHdpZGdldFxuICAgIGNyZWF0b3JVc2VySWQ6IHN0cmluZztcbiAgICB3YWl0Rm9ySWZyYW1lTG9hZDogYm9vbGVhbjtcbiAgICBzaG93TWVudWJhcj86IGJvb2xlYW47XG4gICAgLy8gT3B0aW9uYWwgb25FZGl0Q2xpY2tIYW5kbGVyIChvdmVycmlkZXMgZGVmYXVsdCBiZWhhdmlvdXIpXG4gICAgb25FZGl0Q2xpY2s/OiAoKSA9PiB2b2lkO1xuICAgIC8vIE9wdGlvbmFsIG9uRGVsZXRlQ2xpY2tIYW5kbGVyIChvdmVycmlkZXMgZGVmYXVsdCBiZWhhdmlvdXIpXG4gICAgb25EZWxldGVDbGljaz86ICgpID0+IHZvaWQ7XG4gICAgLy8gT3B0aW9uYWxseSBoaWRlIHRoZSB0aWxlIHRpdGxlXG4gICAgc2hvd1RpdGxlPzogYm9vbGVhbjtcbiAgICAvLyBPcHRpb25hbGx5IGhhbmRsZSBtaW5pbWlzZSBidXR0b24gcG9pbnRlciBldmVudHMgKGRlZmF1bHQgZmFsc2UpXG4gICAgaGFuZGxlTWluaW1pc2VQb2ludGVyRXZlbnRzPzogYm9vbGVhbjtcbiAgICAvLyBPcHRpb25hbGx5IGhpZGUgdGhlIHBvcG91dCB3aWRnZXQgaWNvblxuICAgIHNob3dQb3BvdXQ/OiBib29sZWFuO1xuICAgIC8vIElzIHRoaXMgYW4gaW5zdGFuY2Ugb2YgYSB1c2VyIHdpZGdldFxuICAgIHVzZXJXaWRnZXQ6IGJvb2xlYW47XG4gICAgLy8gc2V0cyB0aGUgcG9pbnRlci1ldmVudHMgcHJvcGVydHkgb24gdGhlIGlmcmFtZVxuICAgIHBvaW50ZXJFdmVudHM/OiBDU1NQcm9wZXJ0aWVzW1wicG9pbnRlckV2ZW50c1wiXTtcbiAgICB3aWRnZXRQYWdlVGl0bGU/OiBzdHJpbmc7XG4gICAgc2hvd0xheW91dEJ1dHRvbnM/OiBib29sZWFuO1xuICAgIC8vIEhhbmRsZSB0byBtYW51YWxseSBub3RpZnkgdGhlIFBlcnNpc3RlZEVsZW1lbnQgdGhhdCBpdCBuZWVkcyB0byBtb3ZlXG4gICAgbW92ZVBlcnNpc3RlZEVsZW1lbnQ/OiBNdXRhYmxlUmVmT2JqZWN0PCgoKSA9PiB2b2lkKSB8IHVuZGVmaW5lZD47XG4gICAgLy8gQW4gZWxlbWVudCB0byByZW5kZXIgYWZ0ZXIgdGhlIGlmcmFtZSBhcyBhbiBvdmVybGF5XG4gICAgb3ZlcmxheT86IFJlYWN0Tm9kZTtcbiAgICAvLyBJZiBkZWZpbmVkIHRoaXMgYXN5bmMgbWV0aG9kIHdpbGwgYmUgY2FsbGVkIHdoZW4gdGhlIHdpZGdldCByZXF1ZXN0cyB0byBiZWNvbWUgc3RpY2t5LlxuICAgIC8vIEl0IHdpbGwgb25seSBiZWNvbWUgc3RpY2t5IG9uY2UgdGhlIHJldHVybmVkIHByb21pc2UgcmVzb2x2ZXMuXG4gICAgLy8gVGhpcyBpcyB1c2VmdWwgYmVjYXVzZTogV2lkZ2V0IEIgaXMgc3RpY2t5LiBNYWtpbmcgd2lkZ2V0IEEgc3RpY2t5IHdpbGwga2lsbCB3aWRnZXQgQiBpbW1lZGlhdGVseS5cbiAgICAvLyBUaGlzIHByb21pc2UgYWxsb3dzIHRvIGRvIFdpZGdldCBCIHJlbGF0ZWQgY2xlYW51cCBiZWZvcmUgV2lkZ2V0IEEgYmVjb21lcyBzdGlja3kuIChlLmcuIGhhbmd1cCBhIFZvaXAgY2FsbClcbiAgICBzdGlja3lQcm9taXNlPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuaW50ZXJmYWNlIElTdGF0ZSB7XG4gICAgaW5pdGlhbGlzaW5nOiBib29sZWFuOyAvLyBUcnVlIHdoaWxlIHdlIGFyZSBtYW5nbGluZyB0aGUgd2lkZ2V0IFVSTFxuICAgIC8vIFRydWUgd2hpbGUgdGhlIGlmcmFtZSBjb250ZW50IGlzIGxvYWRpbmdcbiAgICBsb2FkaW5nOiBib29sZWFuO1xuICAgIC8vIEFzc3VtZSB0aGF0IHdpZGdldCBoYXMgcGVybWlzc2lvbiB0byBsb2FkIGlmIHdlIGFyZSB0aGUgdXNlciB3aG9cbiAgICAvLyBhZGRlZCBpdCB0byB0aGUgcm9vbSwgb3IgaWYgZXhwbGljaXRseSBncmFudGVkIGJ5IHRoZSB1c2VyXG4gICAgaGFzUGVybWlzc2lvblRvTG9hZDogYm9vbGVhbjtcbiAgICAvLyBXYWl0IGZvciB1c2VyIHByb2ZpbGUgbG9hZCB0byBkaXNwbGF5IGNvcnJlY3QgbmFtZVxuICAgIGlzVXNlclByb2ZpbGVSZWFkeTogYm9vbGVhbjtcbiAgICBlcnJvcjogRXJyb3IgfCBudWxsO1xuICAgIG1lbnVEaXNwbGF5ZWQ6IGJvb2xlYW47XG4gICAgcmVxdWlyZXNDbGllbnQ6IGJvb2xlYW47XG4gICAgaGFzQ29udGV4dE1lbnVPcHRpb25zOiBib29sZWFuO1xufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBBcHBUaWxlIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50PElQcm9wcywgSVN0YXRlPiB7XG4gICAgcHVibGljIHN0YXRpYyBjb250ZXh0VHlwZSA9IE1hdHJpeENsaWVudENvbnRleHQ7XG4gICAgcHVibGljIGRlY2xhcmUgY29udGV4dDogQ29udGV4dFR5cGU8dHlwZW9mIE1hdHJpeENsaWVudENvbnRleHQ+O1xuXG4gICAgcHVibGljIHN0YXRpYyBkZWZhdWx0UHJvcHM6IFBhcnRpYWw8SVByb3BzPiA9IHtcbiAgICAgICAgd2FpdEZvcklmcmFtZUxvYWQ6IHRydWUsXG4gICAgICAgIHNob3dNZW51YmFyOiB0cnVlLFxuICAgICAgICBzaG93VGl0bGU6IHRydWUsXG4gICAgICAgIHNob3dQb3BvdXQ6IHRydWUsXG4gICAgICAgIGhhbmRsZU1pbmltaXNlUG9pbnRlckV2ZW50czogZmFsc2UsXG4gICAgICAgIHVzZXJXaWRnZXQ6IGZhbHNlLFxuICAgICAgICBtaW5pTW9kZTogZmFsc2UsXG4gICAgICAgIHRocmVhZElkOiBudWxsLFxuICAgICAgICBzaG93TGF5b3V0QnV0dG9uczogdHJ1ZSxcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBjb250ZXh0TWVudUJ1dHRvbiA9IGNyZWF0ZVJlZjxhbnk+KCk7XG4gICAgcHJpdmF0ZSBpZnJhbWU/OiBIVE1MSUZyYW1lRWxlbWVudDsgLy8gcmVmIHRvIHRoZSBpZnJhbWUgKGNhbGxiYWNrIHN0eWxlKVxuICAgIHByaXZhdGUgYWxsb3dlZFdpZGdldHNXYXRjaFJlZj86IHN0cmluZztcbiAgICBwcml2YXRlIHBlcnNpc3RLZXk6IHN0cmluZztcbiAgICBwcml2YXRlIHNnV2lkZ2V0OiBTdG9wR2FwV2lkZ2V0IHwgbnVsbDtcbiAgICBwcml2YXRlIGRpc3BhdGNoZXJSZWY/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSB1bm1vdW50ZWQgPSBmYWxzZTtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcm9wczogSVByb3BzLCBjb250ZXh0OiBDb250ZXh0VHlwZTx0eXBlb2YgTWF0cml4Q2xpZW50Q29udGV4dD4pIHtcbiAgICAgICAgc3VwZXIocHJvcHMsIGNvbnRleHQpO1xuXG4gICAgICAgIC8vIFRpbGVzIGluIG1pbmlNb2RlIGFyZSBmbG9hdGluZywgYW5kIHRoZXJlZm9yZSBub3QgZG9ja2VkXG4gICAgICAgIGlmICghdGhpcy5wcm9wcy5taW5pTW9kZSkge1xuICAgICAgICAgICAgQWN0aXZlV2lkZ2V0U3RvcmUuaW5zdGFuY2UuZG9ja1dpZGdldChcbiAgICAgICAgICAgICAgICB0aGlzLnByb3BzLmFwcC5pZCxcbiAgICAgICAgICAgICAgICBpc0FwcFdpZGdldCh0aGlzLnByb3BzLmFwcCkgPyB0aGlzLnByb3BzLmFwcC5yb29tSWQgOiBudWxsLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRoZSBrZXkgdXNlZCBmb3IgUGVyc2lzdGVkRWxlbWVudFxuICAgICAgICB0aGlzLnBlcnNpc3RLZXkgPSBnZXRQZXJzaXN0S2V5KFdpZGdldFV0aWxzLmdldFdpZGdldFVpZCh0aGlzLnByb3BzLmFwcCkpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgdGhpcy5zZ1dpZGdldCA9IG5ldyBTdG9wR2FwV2lkZ2V0KHRoaXMucHJvcHMpO1xuICAgICAgICAgICAgdGhpcy5zZXR1cFNnTGlzdGVuZXJzKCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGxvZ2dlci5sb2coXCJGYWlsZWQgdG8gY29uc3RydWN0IHdpZGdldFwiLCBlKTtcbiAgICAgICAgICAgIHRoaXMuc2dXaWRnZXQgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zdGF0ZSA9IHRoaXMuZ2V0TmV3U3RhdGUocHJvcHMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgd2F0Y2hVc2VyUmVhZHkgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIGlmIChPd25Qcm9maWxlU3RvcmUuaW5zdGFuY2UuaXNQcm9maWxlSW5mb0ZldGNoZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBPd25Qcm9maWxlU3RvcmUuaW5zdGFuY2Uub25jZShVUERBVEVfRVZFTlQsIHRoaXMub25Vc2VyUmVhZHkpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uVXNlclJlYWR5ID0gKCk6IHZvaWQgPT4ge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHsgaXNVc2VyUHJvZmlsZVJlYWR5OiB0cnVlIH0pO1xuICAgIH07XG5cbiAgICAvLyBU