Merge pull request #3645 from matrix-org/travis/widget-menu
Move many widget options to a context menu
This commit is contained in:
commit
86783e4439
11 changed files with 234 additions and 171 deletions
|
@ -48,6 +48,7 @@
|
|||
@import "./views/context_menus/_StatusMessageContextMenu.scss";
|
||||
@import "./views/context_menus/_TagTileContextMenu.scss";
|
||||
@import "./views/context_menus/_TopLeftMenu.scss";
|
||||
@import "./views/context_menus/_WidgetContextMenu.scss";
|
||||
@import "./views/dialogs/_AddressPickerDialog.scss";
|
||||
@import "./views/dialogs/_Analytics.scss";
|
||||
@import "./views/dialogs/_ChangelogDialog.scss";
|
||||
|
|
36
res/css/views/context_menus/_WidgetContextMenu.scss
Normal file
36
res/css/views/context_menus/_WidgetContextMenu.scss
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright 2019 The Matrix.org Foundaction 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_WidgetContextMenu {
|
||||
padding: 6px;
|
||||
|
||||
.mx_WidgetContextMenu_option {
|
||||
padding: 3px 6px 3px 6px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mx_WidgetContextMenu_separator {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
border-right-style: none;
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
border-color: $menu-border-color;
|
||||
}
|
||||
}
|
|
@ -153,40 +153,12 @@ $AppsDrawerBodyHeight: 273px;
|
|||
background-color: $accent-color;
|
||||
}
|
||||
|
||||
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_reload {
|
||||
mask-image: url('$(res)/img/feather-customised/widget/refresh.svg');
|
||||
mask-size: 100%;
|
||||
}
|
||||
|
||||
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_popout {
|
||||
mask-image: url('$(res)/img/feather-customised/widget/external-link.svg');
|
||||
}
|
||||
|
||||
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_snapshot {
|
||||
mask-image: url('$(res)/img/feather-customised/widget/camera.svg');
|
||||
}
|
||||
|
||||
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_edit {
|
||||
mask-image: url('$(res)/img/feather-customised/widget/edit.svg');
|
||||
}
|
||||
|
||||
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_delete {
|
||||
mask-image: url('$(res)/img/feather-customised/widget/bin.svg');
|
||||
background-color: $warning-color;
|
||||
}
|
||||
|
||||
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_cancel {
|
||||
mask-image: url('$(res)/img/feather-customised/widget/x-circle.svg');
|
||||
}
|
||||
|
||||
/* delete ? */
|
||||
.mx_AppTileMenuBarWidget {
|
||||
cursor: pointer;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
padding: 1px;
|
||||
transition-duration: 500ms;
|
||||
border: 1px solid transparent;
|
||||
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_menu {
|
||||
mask-image: url('$(res)/img/icon_context.svg');
|
||||
}
|
||||
|
||||
.mx_AppTileMenuBarWidgetDelete {
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="11.014242"
|
||||
height="12"
|
||||
viewBox="0 0 11.014242 12"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="bin.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="750"
|
||||
inkscape:window-height="480"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
fit-margin-top="0.5"
|
||||
fit-margin-left="0.5"
|
||||
fit-margin-bottom="0.5"
|
||||
fit-margin-right="0.5"
|
||||
inkscape:zoom="19.666667"
|
||||
inkscape:cx="5.5071212"
|
||||
inkscape:cy="6"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg6" />
|
||||
<g
|
||||
id="g4"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
transform="translate(1.0071212)">
|
||||
<path
|
||||
d="M 0,3 H 9 M 8,3 v 7 A 1,1 0 0 1 7,11 H 2 A 1,1 0 0 1 1,10 V 3 M 2.5,3 V 2 a 1,1 0 0 1 1,-1 h 2 a 1,1 0 0 1 1,1 v 1 m -3,2.5 v 3 m 2,-3 v 3"
|
||||
id="path2"
|
||||
style="stroke:#000000;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2 KiB |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="11" viewBox="0 0 13 11">
|
||||
<g fill="none" fill-rule="evenodd" stroke="#212121" stroke-linecap="round" stroke-linejoin="round" transform="translate(1 1)">
|
||||
<path d="M11 8a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V2.5a1 1 0 0 1 1-1h2L4 0h3l1 1.5h2a1 1 0 0 1 1 1V8z"/>
|
||||
<circle cx="5.5" cy="5" r="2"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 378 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="11" viewBox="0 0 12 11">
|
||||
<g fill="none" fill-rule="evenodd" stroke="#212121" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10 6.33V9a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h2.67"/>
|
||||
<path d="M9 0l2 2-5 5H4V5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 324 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="11" viewBox="0 0 13 11">
|
||||
<g fill="none" fill-rule="evenodd" stroke="#212121" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 1.5v3H9M1 9.5v-3h3"/>
|
||||
<path d="M2.255 4A4.5 4.5 0 0 1 9.68 2.32L12 4.5m-11 2l2.32 2.18A4.5 4.5 0 0 0 10.745 7"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 346 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
|
||||
<g fill="none" fill-rule="evenodd" stroke="#212121" stroke-linecap="round" stroke-linejoin="round" transform="translate(1 1)">
|
||||
<circle cx="5" cy="5" r="5"/>
|
||||
<path d="M6.5 3.5l-3 3M3.5 3.5l3 3"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 315 B |
134
src/components/views/context_menus/WidgetContextMenu.js
Normal file
134
src/components/views/context_menus/WidgetContextMenu.js
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
Copyright 2019 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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import sdk from '../../../index';
|
||||
import {_t} from '../../../languageHandler';
|
||||
|
||||
export default class WidgetContextMenu extends React.Component {
|
||||
static propTypes = {
|
||||
onFinished: PropTypes.func,
|
||||
|
||||
// Callback for when the revoke button is clicked. Required.
|
||||
onRevokeClicked: PropTypes.func.isRequired,
|
||||
|
||||
// Callback for when the snapshot button is clicked. Button not shown
|
||||
// without a callback.
|
||||
onSnapshotClicked: PropTypes.func,
|
||||
|
||||
// Callback for when the reload button is clicked. Button not shown
|
||||
// without a callback.
|
||||
onReloadClicked: PropTypes.func,
|
||||
|
||||
// Callback for when the edit button is clicked. Button not shown
|
||||
// without a callback.
|
||||
onEditClicked: PropTypes.func,
|
||||
|
||||
// Callback for when the delete button is clicked. Button not shown
|
||||
// without a callback.
|
||||
onDeleteClicked: PropTypes.func,
|
||||
};
|
||||
|
||||
proxyClick(fn) {
|
||||
fn();
|
||||
if (this.props.onFinished) this.props.onFinished();
|
||||
}
|
||||
|
||||
// XXX: It's annoying that our context menus require us to hit onFinished() to close :(
|
||||
|
||||
onEditClicked = () => {
|
||||
this.proxyClick(this.props.onEditClicked);
|
||||
};
|
||||
|
||||
onReloadClicked = () => {
|
||||
this.proxyClick(this.props.onReloadClicked);
|
||||
};
|
||||
|
||||
onSnapshotClicked = () => {
|
||||
this.proxyClick(this.props.onSnapshotClicked);
|
||||
};
|
||||
|
||||
onDeleteClicked = () => {
|
||||
this.proxyClick(this.props.onDeleteClicked);
|
||||
};
|
||||
|
||||
onRevokeClicked = () => {
|
||||
this.proxyClick(this.props.onRevokeClicked);
|
||||
};
|
||||
|
||||
render() {
|
||||
const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
|
||||
|
||||
const options = [];
|
||||
|
||||
if (this.props.onEditClicked) {
|
||||
options.push(
|
||||
<AccessibleButton className='mx_WidgetContextMenu_option' onClick={this.onEditClicked} key='edit'>
|
||||
{_t("Edit")}
|
||||
</AccessibleButton>,
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.onReloadClicked) {
|
||||
options.push(
|
||||
<AccessibleButton className='mx_WidgetContextMenu_option' onClick={this.onReloadClicked}
|
||||
key='reload'>
|
||||
{_t("Reload")}
|
||||
</AccessibleButton>,
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.onSnapshotClicked) {
|
||||
options.push(
|
||||
<AccessibleButton className='mx_WidgetContextMenu_option' onClick={this.onSnapshotClicked}
|
||||
key='snap'>
|
||||
{_t("Take picture")}
|
||||
</AccessibleButton>,
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.onDeleteClicked) {
|
||||
options.push(
|
||||
<AccessibleButton className='mx_WidgetContextMenu_option' onClick={this.onDeleteClicked}
|
||||
key='delete'>
|
||||
{_t("Remove for everyone")}
|
||||
</AccessibleButton>,
|
||||
);
|
||||
}
|
||||
|
||||
// Push this last so it appears last. It's always present.
|
||||
options.push(
|
||||
<AccessibleButton className='mx_WidgetContextMenu_option' onClick={this.onRevokeClicked} key='revoke'>
|
||||
{_t("Remove for me")}
|
||||
</AccessibleButton>,
|
||||
);
|
||||
|
||||
// Put separators between the options
|
||||
if (options.length > 1) {
|
||||
const length = options.length;
|
||||
for (let i = 0; i < length - 1; i++) {
|
||||
const sep = <hr key={i} className="mx_WidgetContextMenu_separator" />;
|
||||
|
||||
// Insert backwards so the insertions don't affect our math on where to place them.
|
||||
// We also use our cached length to avoid worrying about options.length changing
|
||||
options.splice(length - 1 - i, 0, sep);
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="mx_WidgetContextMenu">{options}</div>;
|
||||
}
|
||||
}
|
|
@ -35,6 +35,7 @@ import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
|
|||
import classNames from 'classnames';
|
||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||
import {createMenu} from "../../structures/ContextualMenu";
|
||||
|
||||
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
||||
const ENABLE_REACT_PERF = false;
|
||||
|
@ -52,7 +53,7 @@ export default class AppTile extends React.Component {
|
|||
this._onLoaded = this._onLoaded.bind(this);
|
||||
this._onEditClick = this._onEditClick.bind(this);
|
||||
this._onDeleteClick = this._onDeleteClick.bind(this);
|
||||
this._onCancelClick = this._onCancelClick.bind(this);
|
||||
this._onRevokeClicked = this._onRevokeClicked.bind(this);
|
||||
this._onSnapshotClick = this._onSnapshotClick.bind(this);
|
||||
this.onClickMenuBar = this.onClickMenuBar.bind(this);
|
||||
this._onMinimiseClick = this._onMinimiseClick.bind(this);
|
||||
|
@ -271,7 +272,7 @@ export default class AppTile extends React.Component {
|
|||
return WidgetUtils.canUserModifyWidgets(this.props.room.roomId);
|
||||
}
|
||||
|
||||
_onEditClick(e) {
|
||||
_onEditClick() {
|
||||
console.log("Edit widget ID ", this.props.id);
|
||||
if (this.props.onEditClick) {
|
||||
this.props.onEditClick();
|
||||
|
@ -293,7 +294,7 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_onSnapshotClick(e) {
|
||||
_onSnapshotClick() {
|
||||
console.warn("Requesting widget snapshot");
|
||||
ActiveWidgetStore.getWidgetMessaging(this.props.id).getScreenshot()
|
||||
.catch((err) => {
|
||||
|
@ -360,13 +361,9 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_onCancelClick() {
|
||||
if (this.props.onDeleteClick) {
|
||||
this.props.onDeleteClick();
|
||||
} else {
|
||||
console.log("Revoke widget permissions - %s", this.props.id);
|
||||
this._revokeWidgetPermission();
|
||||
}
|
||||
_onRevokeClicked() {
|
||||
console.log("Revoke widget permissions - %s", this.props.id);
|
||||
this._revokeWidgetPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -544,18 +541,59 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_onPopoutWidgetClick(e) {
|
||||
_onPopoutWidgetClick() {
|
||||
// Using Object.assign workaround as the following opens in a new window instead of a new tab.
|
||||
// window.open(this._getSafeUrl(), '_blank', 'noopener=yes');
|
||||
Object.assign(document.createElement('a'),
|
||||
{ target: '_blank', href: this._getSafeUrl(), rel: 'noopener'}).click();
|
||||
}
|
||||
|
||||
_onReloadWidgetClick(e) {
|
||||
_onReloadWidgetClick() {
|
||||
// Reload iframe in this way to avoid cross-origin restrictions
|
||||
this.refs.appFrame.src = this.refs.appFrame.src;
|
||||
}
|
||||
|
||||
_getMenuOptions(ev) {
|
||||
// TODO: This block of code gets copy/pasted a lot. We should make that happen less.
|
||||
const menuOptions = {};
|
||||
const buttonRect = ev.target.getBoundingClientRect();
|
||||
// The window X and Y offsets are to adjust position when zoomed in to page
|
||||
const buttonLeft = buttonRect.left + window.pageXOffset;
|
||||
const buttonTop = buttonRect.top + window.pageYOffset;
|
||||
// Align the right edge of the menu to the left edge of the button
|
||||
menuOptions.right = window.innerWidth - buttonLeft;
|
||||
// Align the menu vertically on whichever side of the button has more
|
||||
// space available.
|
||||
if (buttonTop < window.innerHeight / 2) {
|
||||
menuOptions.top = buttonTop;
|
||||
} else {
|
||||
menuOptions.bottom = window.innerHeight - buttonTop;
|
||||
}
|
||||
return menuOptions;
|
||||
}
|
||||
|
||||
_onContextMenuClick = (ev) => {
|
||||
const WidgetContextMenu = sdk.getComponent('views.context_menus.WidgetContextMenu');
|
||||
const menuOptions = {
|
||||
...this._getMenuOptions(ev),
|
||||
|
||||
// A revoke handler is always required
|
||||
onRevokeClicked: this._onRevokeClicked,
|
||||
};
|
||||
|
||||
const canUserModify = this._canUserModify();
|
||||
const showEditButton = Boolean(this._scalarClient && canUserModify);
|
||||
const showDeleteButton = (this.props.showDelete === undefined || this.props.showDelete) && canUserModify;
|
||||
const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show;
|
||||
|
||||
if (showEditButton) menuOptions.onEditClicked = this._onEditClick;
|
||||
if (showDeleteButton) menuOptions.onDeleteClicked = this._onDeleteClick;
|
||||
if (showPictureSnapshotButton) menuOptions.onSnapshotClicked = this._onSnapshotClick;
|
||||
if (this.props.showReload) menuOptions.onReloadClicked = this._onReloadWidgetClick;
|
||||
|
||||
createMenu(WidgetContextMenu, menuOptions);
|
||||
};
|
||||
|
||||
render() {
|
||||
let appTileBody;
|
||||
|
||||
|
@ -565,7 +603,7 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
|
||||
// Note that there is advice saying allow-scripts shouldn't be used with allow-same-origin
|
||||
// because that would allow the iframe to prgramatically remove the sandbox attribute, but
|
||||
// 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 riot client: anything
|
||||
// hosted on the same origin as the client will get the same access as if you clicked
|
||||
// a link to it.
|
||||
|
@ -645,13 +683,6 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
// editing is done in scalar
|
||||
const canUserModify = this._canUserModify();
|
||||
const showEditButton = Boolean(this._scalarClient && canUserModify);
|
||||
const showDeleteButton = (this.props.showDelete === undefined || this.props.showDelete) && canUserModify;
|
||||
const showCancelButton = (this.props.showCancel === undefined || this.props.showCancel) && !showDeleteButton;
|
||||
// Picture snapshot - only show button when apps are maximised.
|
||||
const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show;
|
||||
const showMinimiseButton = this.props.showMinimise && this.props.show;
|
||||
const showMaximiseButton = this.props.showMinimise && !this.props.show;
|
||||
|
||||
|
@ -690,41 +721,17 @@ export default class AppTile extends React.Component {
|
|||
{ this.props.showTitle && this._getTileTitle() }
|
||||
</span>
|
||||
<span className="mx_AppTileMenuBarWidgets">
|
||||
{ /* Reload widget */ }
|
||||
{ this.props.showReload && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_reload"
|
||||
title={_t('Reload widget')}
|
||||
onClick={this._onReloadWidgetClick}
|
||||
/> }
|
||||
{ /* Popout widget */ }
|
||||
{ this.props.showPopout && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_popout"
|
||||
title={_t('Popout widget')}
|
||||
onClick={this._onPopoutWidgetClick}
|
||||
/> }
|
||||
{ /* Snapshot widget */ }
|
||||
{ showPictureSnapshotButton && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_snapshot"
|
||||
title={_t('Picture')}
|
||||
onClick={this._onSnapshotClick}
|
||||
/> }
|
||||
{ /* Edit widget */ }
|
||||
{ showEditButton && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_edit"
|
||||
title={_t('Edit')}
|
||||
onClick={this._onEditClick}
|
||||
/> }
|
||||
{ /* Delete widget */ }
|
||||
{ showDeleteButton && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_delete"
|
||||
title={_t('Delete widget')}
|
||||
onClick={this._onDeleteClick}
|
||||
/> }
|
||||
{ /* Cancel widget */ }
|
||||
{ showCancelButton && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_cancel"
|
||||
title={_t('Revoke widget access')}
|
||||
onClick={this._onCancelClick}
|
||||
{ /* Context menu */ }
|
||||
{ <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_menu"
|
||||
title={_t('More options')}
|
||||
onClick={this._onContextMenuClick}
|
||||
/> }
|
||||
</span>
|
||||
</div> }
|
||||
|
|
|
@ -1205,10 +1205,8 @@
|
|||
"An error ocurred whilst trying to remove the widget from the room": "An error ocurred whilst trying to remove the widget from the room",
|
||||
"Minimize apps": "Minimize apps",
|
||||
"Maximize apps": "Maximize apps",
|
||||
"Reload widget": "Reload widget",
|
||||
"Popout widget": "Popout widget",
|
||||
"Picture": "Picture",
|
||||
"Revoke widget access": "Revoke widget access",
|
||||
"More options": "More options",
|
||||
"Create new room": "Create new room",
|
||||
"Unblacklist": "Unblacklist",
|
||||
"Blacklist": "Blacklist",
|
||||
|
@ -1565,6 +1563,10 @@
|
|||
"Hide": "Hide",
|
||||
"Home": "Home",
|
||||
"Sign in": "Sign in",
|
||||
"Reload": "Reload",
|
||||
"Take picture": "Take picture",
|
||||
"Remove for everyone": "Remove for everyone",
|
||||
"Remove for me": "Remove for me",
|
||||
"powered by Matrix": "powered by Matrix",
|
||||
"This homeserver would like to make sure you are not a robot.": "This homeserver would like to make sure you are not a robot.",
|
||||
"Custom Server Options": "Custom Server Options",
|
||||
|
|
Loading…
Reference in a new issue