Merge remote-tracking branch 'origin/experimental' into dbkr/sas

This commit is contained in:
David Baker 2019-01-23 17:32:18 +00:00
commit 6a90625d36
172 changed files with 1885 additions and 661 deletions

View file

@ -28,41 +28,56 @@ import { KeyCode } from '../../../Keyboard';
* @returns {Object} rendered react
*/
export default function AccessibleButton(props) {
const {element, onClick, children, ...restProps} = props;
restProps.onClick = onClick;
// We need to consume enter onKeyDown and space onKeyUp
// otherwise we are risking also activating other keyboard focusable elements
// that might receive focus as a result of the AccessibleButtonClick action
// It's because we are using html buttons at a few places e.g. inside dialogs
// And divs which we report as role button to assistive technologies.
// Browsers handle space and enter keypresses differently and we are only adjusting to the
// inconsistencies here
restProps.onKeyDown = function(e) {
if (e.keyCode === KeyCode.ENTER) {
e.stopPropagation();
e.preventDefault();
return onClick(e);
}
if (e.keyCode === KeyCode.SPACE) {
e.stopPropagation();
e.preventDefault();
}
};
restProps.onKeyUp = function(e) {
if (e.keyCode === KeyCode.SPACE) {
e.stopPropagation();
e.preventDefault();
return onClick(e);
}
if (e.keyCode === KeyCode.ENTER) {
e.stopPropagation();
e.preventDefault();
}
};
const {element, onClick, children, kind, disabled, ...restProps} = props;
if (!disabled) {
restProps.onClick = onClick;
// We need to consume enter onKeyDown and space onKeyUp
// otherwise we are risking also activating other keyboard focusable elements
// that might receive focus as a result of the AccessibleButtonClick action
// It's because we are using html buttons at a few places e.g. inside dialogs
// And divs which we report as role button to assistive technologies.
// Browsers handle space and enter keypresses differently and we are only adjusting to the
// inconsistencies here
restProps.onKeyDown = function(e) {
if (e.keyCode === KeyCode.ENTER) {
e.stopPropagation();
e.preventDefault();
return onClick(e);
}
if (e.keyCode === KeyCode.SPACE) {
e.stopPropagation();
e.preventDefault();
}
};
restProps.onKeyUp = function(e) {
if (e.keyCode === KeyCode.SPACE) {
e.stopPropagation();
e.preventDefault();
return onClick(e);
}
if (e.keyCode === KeyCode.ENTER) {
e.stopPropagation();
e.preventDefault();
}
};
}
restProps.tabIndex = restProps.tabIndex || "0";
restProps.role = "button";
restProps.className = (restProps.className ? restProps.className + " " : "") +
"mx_AccessibleButton";
if (kind) {
// We apply a hasKind class to maintain backwards compatibility with
// buttons which might not know about kind and break
restProps.className += " mx_AccessibleButton_hasKind mx_AccessibleButton_kind_" + kind;
}
if (disabled) {
restProps.className += " mx_AccessibleButton_disabled";
}
return React.createElement(element, restProps, children);
}
@ -76,6 +91,12 @@ AccessibleButton.propTypes = {
children: PropTypes.node,
element: PropTypes.string,
onClick: PropTypes.func.isRequired,
// The kind of button, similar to how Bootstrap works.
// See available classes for AccessibleButton for options.
kind: PropTypes.string,
disabled: PropTypes.bool,
};
AccessibleButton.defaultProps = {

View file

@ -150,7 +150,7 @@ export default React.createClass({
showAddress={this.props.showAddress}
justified={true}
networkName="vector"
networkUrl="img/search-icon-vector.svg"
networkUrl={require("../../../../res/img/search-icon-vector.svg")}
/>
</div>,
);

View file

@ -54,7 +54,7 @@ export default React.createClass({
address.avatarMxc, 25, 25, 'crop',
));
} else if (address.addressType === 'email') {
imgUrls.push('img/icon-email-user.svg');
imgUrls.push(require("../../../../res/img/icon-email-user.svg"));
}
// Removing networks for now as they're not really supported
@ -141,7 +141,7 @@ export default React.createClass({
if (this.props.canDismiss) {
dismiss = (
<div className="mx_AddressTile_dismiss" onClick={this.props.onDismissed} >
<TintableSvg src="img/icon-address-delete.svg" width="9" height="9" />
<TintableSvg src={require("../../../../res/img/icon-address-delete.svg")} width="9" height="9" />
</div>
);
}

View file

@ -47,7 +47,7 @@ export default class AppPermission extends React.Component {
return (
<div className='mx_AppPermissionWarning'>
<div className='mx_AppPermissionWarningImage'>
<img src='img/warning.svg' alt={_t('Warning!')} />
<img src={require("../../../../res/img/warning.svg")} alt={_t('Warning!')} />
</div>
<div className='mx_AppPermissionWarningText'>
<span className='mx_AppPermissionWarningTextLabel'>{ _t('Do you want to load widget from URL:') }</span> <span className='mx_AppPermissionWarningTextURL'>{ this.state.curlBase }</span>

View file

@ -582,19 +582,21 @@ export default class AppTile extends React.Component {
// editing is done in scalar
const showEditButton = Boolean(this._scalarClient && this._canUserModify());
const deleteWidgetLabel = this._deleteWidgetLabel();
let deleteIcon = 'img/cancel_green.svg';
let deleteIcon = require("../../../../res/img/cancel_green.svg");
let deleteClasses = 'mx_AppTileMenuBarWidget';
if (this._canUserModify()) {
deleteIcon = 'img/icon-delete-pink.svg';
deleteIcon = require("../../../../res/img/icon-delete-pink.svg");
deleteClasses += ' mx_AppTileMenuBarWidgetDelete';
}
// Picture snapshot - only show button when apps are maximised.
const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show;
const showPictureSnapshotIcon = 'img/camera_green.svg';
const popoutWidgetIcon = 'img/button-new-window.svg';
const reloadWidgetIcon = 'img/button-refresh.svg';
const windowStateIcon = (this.props.show ? 'img/minimize.svg' : 'img/maximize.svg');
const showPictureSnapshotIcon = require("../../../../res/img/camera_green.svg");
const popoutWidgetIcon = require("../../../../res/img/button-new-window.svg");
const reloadWidgetIcon = require("../../../../res/img/button-refresh.svg");
const minimizeIcon = require("../../../../res/img/minimize.svg");
const maximizeIcon = require("../../../../res/img/maximize.svg");
const windowStateIcon = (this.props.show ? minimizeIcon : maximizeIcon);
let appTileClass;
if (this.props.miniMode) {
@ -653,7 +655,7 @@ export default class AppTile extends React.Component {
{ /* Edit widget */ }
{ showEditButton && <TintableSvgButton
src="img/edit_green.svg"
src={require("../../../../res/img/edit_green.svg")}
className={"mx_AppTileMenuBarWidget " +
(this.props.showDelete ? "mx_AppTileMenuBarWidgetPadding" : "")}
title={_t('Edit')}

View file

@ -5,7 +5,7 @@ const AppWarning = (props) => {
return (
<div className='mx_AppPermissionWarning'>
<div className='mx_AppPermissionWarningImage'>
<img src='img/warning.svg' alt='' />
<img src={require("../../../../res/img/warning.svg")} alt='' />
</div>
<div className='mx_AppPermissionWarningText'>
<span className='mx_AppPermissionWarningTextLabel'>{ props.errorMsg }</span>

View file

@ -25,7 +25,7 @@ const CreateRoomButton = function(props) {
<ActionButton action="view_create_room"
mouseOverAction={props.callout ? "callout_create_room" : null}
label={_t("Create new room")}
iconPath="img/icons-create-room.svg"
iconPath={require("../../../../res/img/icons-create-room.svg")}
size={props.size}
tooltip={props.tooltip}
/>

View file

@ -62,13 +62,13 @@ const EditableItem = React.createClass({
{ this.props.onAdd ?
<div className="mx_EditableItem_addButton">
<img className="mx_filterFlipColor"
src="img/plus.svg" width="14" height="14"
src={require("../../../../res/img/plus.svg")} width="14" height="14"
alt={_t("Add")} onClick={this.onAdd} />
</div>
:
<div className="mx_EditableItem_removeButton">
<img className="mx_filterFlipColor"
src="img/cancel-small.svg" width="14" height="14"
src={require("../../../../res/img/cancel-small.svg")} width="14" height="14"
alt={_t("Delete")} onClick={this.onRemove} />
</div>
}

View file

@ -0,0 +1,54 @@
/*
Copyright 2019 New Vector Ltd
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';
export default class Field extends React.PureComponent {
static propTypes = {
// The field's ID, which binds the input and label together.
id: PropTypes.string.isRequired,
// The field's <input> type. Defaults to "text".
type: PropTypes.string,
// The field's label string.
label: PropTypes.string,
// The field's placeholder string.
placeholder: PropTypes.string,
// The type of field to create. Defaults to "input". Should be "input" or "select".
// To define options for a select, use <Field><option ... /></Field>
element: PropTypes.string,
// All other props pass through to the <input>.
}
render() {
const extraProps = Object.assign({}, this.props);
// Remove explicit properties that shouldn't be copied
delete extraProps.element;
delete extraProps.children;
// Set some defaults for the element
extraProps.type = extraProps.type || "text";
const element = this.props.element || "input";
const fieldInput = React.createElement(element, extraProps, this.props.children);
return <div className="mx_Field">
{fieldInput}
<label htmlFor={this.props.id}>{this.props.label}</label>
</div>;
}
}

View file

@ -24,7 +24,7 @@ const HomeButton = function(props) {
return (
<ActionButton action="view_home_page"
label={_t("Home")}
iconPath="img/icons-home.svg"
iconPath={require("../../../../res/img/icons-home.svg")}
size={props.size}
tooltip={props.tooltip}
/>

View file

@ -176,7 +176,7 @@ module.exports = React.createClass({
<img src={this.props.src} style={style} />
<div className="mx_ImageView_labelWrapper">
<div className="mx_ImageView_label">
<AccessibleButton className="mx_ImageView_cancel" onClick={ this.props.onFinished }><img src="img/cancel-white.svg" width="18" height="18" alt={ _t('Close') } /></AccessibleButton>
<AccessibleButton className="mx_ImageView_cancel" onClick={ this.props.onFinished }><img src={require("../../../../res/img/cancel-white.svg")} width="18" height="18" alt={ _t('Close') } /></AccessibleButton>
<div className="mx_ImageView_shim">
</div>
<div className="mx_ImageView_name">

View file

@ -26,7 +26,7 @@ module.exports = React.createClass({
return (
<div className="mx_InlineSpinner">
<img src="img/spinner.gif" width={w} height={h} className={imgClass} />
<img src={require("../../../../res/img/spinner.gif")} width={w} height={h} className={imgClass} />
</div>
);
},

View file

@ -80,7 +80,11 @@ export default class ManageIntegsButton extends React.Component {
});
if (this.state.scalarError && !this.scalarClient.hasCredentials()) {
integrationsWarningTriangle = <img src="img/warning.svg" title={_t('Integrations Error')} width="17" />;
integrationsWarningTriangle = <img
src={require("../../../../res/img/warning.svg")}
title={_t('Integrations Error')}
width="17"
/>;
// Popup shown when hovering over integrationsButton_error (via CSS)
integrationsErrorPopup = (
<span className="mx_RoomSettings_integrationsButton_errorPopup">
@ -91,7 +95,7 @@ export default class ManageIntegsButton extends React.Component {
integrationsButton = (
<AccessibleButton className={integrationsButtonClasses} onClick={this.onManageIntegrations} title={_t('Manage Integrations')}>
<TintableSvg src="img/feather-icons/grid.svg" width="20" height="20" />
<TintableSvg src={require("../../../../res/img/feather-icons/grid.svg")} width="20" height="20" />
{ integrationsWarningTriangle }
{ integrationsErrorPopup }
</AccessibleButton>

View file

@ -27,7 +27,7 @@ module.exports = React.createClass({
return (
<div className="mx_Spinner">
<div className="mx_Spinner_Msg">{ msg }</div>&nbsp;
<img src="img/spinner.gif" width={w} height={h} className={imgClass} />
<img src={require("../../../../res/img/spinner.gif")} width={w} height={h} className={imgClass} />
</div>
);
},

View file

@ -25,7 +25,7 @@ const RoomDirectoryButton = function(props) {
<ActionButton action="view_room_directory"
mouseOverAction={props.callout ? "callout_room_directory" : null}
label={_t("Room directory")}
iconPath="img/icons-directory.svg"
iconPath={require("../../../../res/img/icons-directory.svg")}
size={props.size}
tooltip={props.tooltip}
/>

View file

@ -24,7 +24,7 @@ const SettingsButton = function(props) {
return (
<ActionButton action="view_user_settings"
label={_t("Settings")}
iconPath="img/icons-settings.svg"
iconPath={require("../../../../res/img/icons-settings.svg")}
size={props.size}
tooltip={props.tooltip}
/>

View file

@ -27,7 +27,7 @@ module.exports = React.createClass({
const imgClass = this.props.imgClassName || "";
return (
<div className="mx_Spinner">
<img src="img/spinner.gif" width={w} height={h} className={imgClass} />
<img src={require("../../../../res/img/spinner.gif")} width={w} height={h} className={imgClass} />
</div>
);
},

View file

@ -25,7 +25,7 @@ const StartChatButton = function(props) {
<ActionButton action="view_create_chat"
mouseOverAction={props.callout ? "callout_start_chat" : null}
label={_t("Start chat")}
iconPath="img/icons-people.svg"
iconPath={require("../../../../res/img/icons-people.svg")}
size={props.size}
tooltip={props.tooltip}
/>