Merge branch 'develop' into bwindels/redesign

This commit is contained in:
Bruno Windels 2018-10-16 11:57:44 +02:00
commit 6878ce3c6a
89 changed files with 2635 additions and 1287 deletions

View file

@ -319,7 +319,7 @@ const LoggedInView = React.createClass({
), true);
},
_onClick: function(ev) {
_onMouseDown: function(ev) {
// When the panels are disabled, clicking on them results in a mouse event
// which bubbles to certain elements in the tree. When this happens, close
// any settings page that is currently open (user/room/group).
@ -330,11 +330,37 @@ const LoggedInView = React.createClass({
targetClasses.has('mx_MatrixChat_middlePanel') ||
targetClasses.has('mx_RoomView')
) {
dis.dispatch({ action: 'close_settings' });
this.setState({
mouseDown: {
x: ev.pageX,
y: ev.pageY,
},
});
}
}
},
_onMouseUp: function(ev) {
if (!this.state.mouseDown) return;
const deltaX = ev.pageX - this.state.mouseDown.x;
const deltaY = ev.pageY - this.state.mouseDown.y;
const distance = Math.sqrt((deltaX * deltaX) + (deltaY + deltaY));
const maxRadius = 5; // People shouldn't be straying too far, hopefully
// Note: we track how far the user moved their mouse to help
// combat against https://github.com/vector-im/riot-web/issues/7158
if (distance < maxRadius) {
// This is probably a real click, and not a drag
dis.dispatch({ action: 'close_settings' });
}
// Always clear the mouseDown state to ensure we don't accidentally
// use stale values due to the mouseDown checks.
this.setState({mouseDown: null});
},
render: function() {
const LeftPanel = sdk.getComponent('structures.LeftPanel');
const RightPanel = sdk.getComponent('structures.RightPanel');
@ -478,7 +504,7 @@ const LoggedInView = React.createClass({
}
return (
<div className='mx_MatrixChat_wrapper' aria-hidden={this.props.hideToSRUsers} onClick={this._onClick}>
<div className='mx_MatrixChat_wrapper' aria-hidden={this.props.hideToSRUsers} onMouseDown={this._onMouseDown} onMouseUp={this._onMouseUp}>
{ topBar }
<DragDropContext onDragEnd={this._onDragEnd}>
<div className={bodyClasses}>

View file

@ -48,6 +48,10 @@ import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
import { startAnyRegistrationFlow } from "../../Registration.js";
import { messageForSyncError } from '../../utils/ErrorUtils';
// Disable warnings for now: we use deprecated bluebird functions
// and need to migrate, but they spam the console with warnings.
Promise.config({warnings: false});
/** constants for MatrixChat.state.view */
const VIEWS = {
// a special initial state which is only used at startup, while we are
@ -286,6 +290,14 @@ export default React.createClass({
register_hs_url: paramHs,
});
}
// Set a default IS with query param `is_url`
const paramIs = this.props.startingFragmentQueryParams.is_url;
if (paramIs) {
console.log('Setting register_is_url ', paramIs);
this.setState({
register_is_url: paramIs,
});
}
// a thing to call showScreen with once login completes. this is kept
// outside this.state because updating it should never trigger a
@ -1253,8 +1265,11 @@ export default React.createClass({
// its own dispatch).
dis.dispatch({action: 'sync_state', prevState, state});
if (state === "ERROR") {
self.setState({syncError: data.error});
if (state === "ERROR" || state === "RECONNECTING") {
if (data.error instanceof Matrix.InvalidStoreError) {
Lifecycle.handleInvalidStoreError(data.error);
}
self.setState({syncError: data.error || true});
} else if (self.state.syncError) {
self.setState({syncError: null});
}
@ -1730,10 +1745,14 @@ export default React.createClass({
}
if (this.state.view === VIEWS.LOGGED_IN) {
// store errors stop the client syncing and require user intervention, so we'll
// be showing a dialog. Don't show anything else.
const isStoreError = this.state.syncError && this.state.syncError instanceof Matrix.InvalidStoreError;
// `ready` and `view==LOGGED_IN` may be set before `page_type` (because the
// latter is set via the dispatcher). If we don't yet have a `page_type`,
// keep showing the spinner for now.
if (this.state.ready && this.state.page_type) {
if (this.state.ready && this.state.page_type && !isStoreError) {
/* for now, we stuff the entirety of our props and state into the LoggedInView.
* we should go through and figure out what we actually need to pass down, as well
* as using something like redux to avoid having a billion bits of state kicking around.
@ -1755,7 +1774,7 @@ export default React.createClass({
// we think we are logged in, but are still waiting for the /sync to complete
const Spinner = sdk.getComponent('elements.Spinner');
let errorBox;
if (this.state.syncError) {
if (this.state.syncError && !isStoreError) {
errorBox = <div className="mx_MatrixChat_syncError">
{messageForSyncError(this.state.syncError)}
</div>;

View file

@ -542,7 +542,7 @@ module.exports = React.createClass({
},
// get a list of read receipts that should be shown next to this event
// Receipts are objects which have a 'roomMember' and 'ts'.
// Receipts are objects which have a 'userId', 'roomMember' and 'ts'.
_getReadReceiptsForEvent: function(event) {
const myUserId = MatrixClientPeg.get().credentials.userId;
@ -560,10 +560,8 @@ module.exports = React.createClass({
return; // ignore ignored users
}
const member = room.getMember(r.userId);
if (!member) {
return; // ignore unknown user IDs
}
receipts.push({
userId: r.userId,
roomMember: member,
ts: r.data ? r.data.ts : 0,
});

View file

@ -51,6 +51,7 @@ class HeaderButton extends React.Component {
return <AccessibleButton
aria-label={this.props.title}
aria-expanded={this.props.isHighlighted}
title={this.props.title}
className="mx_RightPanel_headerButton"
onClick={this.onClick} >
@ -345,11 +346,11 @@ module.exports = React.createClass({
// being put in the RoomHeader or GroupView header, so only show the minimise
// button on these 2 screens or you won't be able to re-expand the panel.
headerButtons.push(
<div className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" key="_minimizeButton"
<AccessibleButton className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" key="_minimizeButton"
title={_t("Hide panel")} aria-label={_t("Hide panel")} onClick={this.onCollapseClick}
>
<TintableSvg src="img/minimise.svg" width="10" height="16" />
</div>,
<TintableSvg src="img/minimise.svg" width="10" height="16" alt="" />
</AccessibleButton>,
);
}

View file

@ -223,14 +223,15 @@ module.exports = React.createClass({
);
}
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
if (!this.props.atEndOfLiveTimeline) {
return (
<div className="mx_RoomStatusBar_scrollDownIndicator"
<AccessibleButton className="mx_RoomStatusBar_scrollDownIndicator"
onClick={this.props.onScrollToBottomClick}>
<img src="img/scrolldown.svg" width="24" height="24"
alt={_t("Scroll to bottom of page")}
title={_t("Scroll to bottom of page")} />
</div>
</AccessibleButton>
);
}
@ -385,7 +386,7 @@ module.exports = React.createClass({
}
return <div className="mx_RoomStatusBar_connectionLostBar">
<img src="img/warning.svg" width="24" height="23" title={_t("Warning")} alt={_t("Warning")} />
<img src="img/warning.svg" width="24" height="23" title={_t("Warning")} alt="" />
<div>
<div className="mx_RoomStatusBar_connectionLostBar_title">
{ title }
@ -485,7 +486,9 @@ module.exports = React.createClass({
<div className="mx_RoomStatusBar_indicator">
{ indicator }
</div>
{ content }
<div role="alert">
{ content }
</div>
</div>
);
},

View file

@ -195,6 +195,8 @@ module.exports = React.createClass({
editingRoomSettings: RoomViewStore.isEditingSettings(),
};
if (this.state.editingRoomSettings && !newState.editingRoomSettings) dis.dispatch({action: 'focus_composer'});
// Temporary logging to diagnose https://github.com/vector-im/riot-web/issues/4307
console.log(
'RVS update:',

View file

@ -804,7 +804,7 @@ module.exports = React.createClass({
}
return (
<div>
<h3>{ _t("Debug Logs Submission") }</h3>
<h3>{ _t("Submit Debug Logs") }</h3>
<div className="mx_UserSettings_section">
<p>{
_t( "If you've submitted a bug via GitHub, debug logs can help " +
@ -832,9 +832,9 @@ module.exports = React.createClass({
<br />
{ _t('Privacy is important to us, so we don\'t collect any personal'
+ ' or identifiable data for our analytics.') }
<div className="mx_UserSettings_advanced_spoiler" onClick={Analytics.showDetailsModal}>
<AccessibleButton className="mx_UserSettings_advanced_spoiler" onClick={Analytics.showDetailsModal}>
{ _t('Learn more about how we use analytics.') }
</div>
</AccessibleButton>
{ ANALYTICS_SETTINGS.map( this._renderDeviceSetting ) }
</div>
</div>;
@ -1066,9 +1066,9 @@ module.exports = React.createClass({
_renderWebRtcDeviceSettings: function() {
if (this.state.mediaDevices === false) {
return (
<p className="mx_UserSettings_link" onClick={this._requestMediaPermissions}>
<AccessibleButton element="p" className="mx_UserSettings_link" onClick={this._requestMediaPermissions}>
{ _t('Missing Media Permissions, click here to request.') }
</p>
</AccessibleButton>
);
} else if (!this.state.mediaDevices) return;
@ -1235,7 +1235,7 @@ module.exports = React.createClass({
/>
</div>
<div className="mx_UserSettings_threepidButton mx_filterFlipColor">
<img src="img/cancel-small.svg" width="14" height="14" alt={_t("Remove")}
<AccessibleButton element="img" src="img/cancel-small.svg" width="14" height="14" alt={_t("Remove")}
onClick={onRemoveClick} />
</div>
</div>
@ -1260,7 +1260,7 @@ module.exports = React.createClass({
onValueChanged={this._onAddEmailEditFinished} />
</div>
<div className="mx_UserSettings_threepidButton mx_filterFlipColor">
<img src="img/plus.svg" width="14" height="14" alt={_t("Add")} onClick={this._addEmail} />
<AccessibleButton element="img" src="img/plus.svg" width="14" height="14" alt={_t("Add")} onClick={this._addEmail} />
</div>
</div>
);
@ -1329,13 +1329,13 @@ module.exports = React.createClass({
</div>
<div className="mx_UserSettings_avatarPicker">
<div className="mx_UserSettings_avatarPicker_remove" onClick={this.onAvatarRemoveClick}>
<AccessibleButton className="mx_UserSettings_avatarPicker_remove" onClick={this.onAvatarRemoveClick}>
<img src="img/cancel.svg"
width="15" height="15"
className="mx_filterFlipColor"
alt={_t("Remove avatar")}
title={_t("Remove avatar")} />
</div>
</AccessibleButton>
<div onClick={this.onAvatarPickerClick} className="mx_UserSettings_avatarPicker_imgContainer">
<ChangeAvatar ref="changeAvatar" initialAvatarUrl={avatarUrl}
showUploadSection={false} className="mx_UserSettings_avatarPicker_img" />
@ -1396,11 +1396,11 @@ module.exports = React.createClass({
</div>
<div className="mx_UserSettings_advanced">
{ _t('Access Token:') + ' ' }
<span className="mx_UserSettings_advanced_spoiler"
<AccessibleButton element="span" className="mx_UserSettings_advanced_spoiler"
onClick={this._showSpoiler}
data-spoiler={MatrixClientPeg.get().getAccessToken()}>
&lt;{ _t("click to reveal") }&gt;
</span>
</AccessibleButton>
</div>
<div className="mx_UserSettings_advanced">
{ _t("Homeserver is") } { MatrixClientPeg.get().getHomeserverUrl() }

View file

@ -321,6 +321,12 @@ module.exports = React.createClass({
case "RegistrationForm.ERR_PHONE_NUMBER_INVALID":
errMsg = _t('This doesn\'t look like a valid phone number.');
break;
case "RegistrationForm.ERR_MISSING_EMAIL":
errMsg = _t('An email address is required to register on this homeserver.');
break;
case "RegistrationForm.ERR_MISSING_PHONE_NUMBER":
errMsg = _t('A phone number is required to register on this homeserver.');
break;
case "RegistrationForm.ERR_USERNAME_INVALID":
errMsg = _t('User names may only contain letters, numbers, dots, hyphens and underscores.');
break;