Merge remote-tracking branch 'upstream/develop' into travis/h1-h2-to-h3
This commit is contained in:
commit
28923cdb93
22 changed files with 196 additions and 97 deletions
|
@ -135,17 +135,24 @@ module.exports = function (config) {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
noParse: [
|
noParse: [
|
||||||
|
// for cross platform compatibility use [\\\/] as the path separator
|
||||||
|
// this ensures that the regex trips on both Windows and *nix
|
||||||
|
|
||||||
// don't parse the languages within highlight.js. They
|
// don't parse the languages within highlight.js. They
|
||||||
// cause stack overflows
|
// cause stack overflows
|
||||||
// (https://github.com/webpack/webpack/issues/1721), and
|
// (https://github.com/webpack/webpack/issues/1721), and
|
||||||
// there is no need for webpack to parse them - they can
|
// there is no need for webpack to parse them - they can
|
||||||
// just be included as-is.
|
// just be included as-is.
|
||||||
/highlight\.js\/lib\/languages/,
|
/highlight\.js[\\\/]lib[\\\/]languages/,
|
||||||
|
|
||||||
|
// olm takes ages for webpack to process, and it's already heavily
|
||||||
|
// optimised, so there is little to gain by us uglifying it.
|
||||||
|
/olm[\\\/](javascript[\\\/])?olm\.js$/,
|
||||||
|
|
||||||
// also disable parsing for sinon, because it
|
// also disable parsing for sinon, because it
|
||||||
// tries to do voodoo with 'require' which upsets
|
// tries to do voodoo with 'require' which upsets
|
||||||
// webpack (https://github.com/webpack/webpack/issues/304)
|
// webpack (https://github.com/webpack/webpack/issues/304)
|
||||||
/sinon\/pkg\/sinon\.js$/,
|
/sinon[\\\/]pkg[\\\/]sinon\.js$/,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|
|
@ -313,7 +313,7 @@ function _onAction(payload) {
|
||||||
console.error("Conference call failed: " + err);
|
console.error("Conference call failed: " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failed to set up conference call",
|
title: "Failed to set up conference call",
|
||||||
description: "Conference call failed.",
|
description: "Conference call failed. " + ((err && err.message) ? err.message : ""),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,9 +117,10 @@ export default React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.UP:
|
case KeyCode.UP:
|
||||||
case KeyCode.DOWN:
|
case KeyCode.DOWN:
|
||||||
if (ev.altKey) {
|
if (ev.altKey && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) {
|
||||||
var action = ev.keyCode == KeyCode.UP ?
|
var action = ev.keyCode == KeyCode.UP ?
|
||||||
'view_prev_room' : 'view_next_room';
|
'view_prev_room' : 'view_next_room';
|
||||||
dis.dispatch({action: action});
|
dis.dispatch({action: action});
|
||||||
|
@ -129,13 +130,15 @@ export default React.createClass({
|
||||||
|
|
||||||
case KeyCode.PAGE_UP:
|
case KeyCode.PAGE_UP:
|
||||||
case KeyCode.PAGE_DOWN:
|
case KeyCode.PAGE_DOWN:
|
||||||
|
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this._onScrollKeyPressed(ev);
|
this._onScrollKeyPressed(ev);
|
||||||
handled = true;
|
handled = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.HOME:
|
case KeyCode.HOME:
|
||||||
case KeyCode.END:
|
case KeyCode.END:
|
||||||
if (ev.ctrlKey) {
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this._onScrollKeyPressed(ev);
|
this._onScrollKeyPressed(ev);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
@ -153,6 +156,9 @@ export default React.createClass({
|
||||||
if (this.refs.roomView) {
|
if (this.refs.roomView) {
|
||||||
this.refs.roomView.handleScrollKey(ev);
|
this.refs.roomView.handleScrollKey(ev);
|
||||||
}
|
}
|
||||||
|
else if (this.refs.roomDirectory) {
|
||||||
|
this.refs.roomDirectory.handleScrollKey(ev);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
@ -213,6 +219,7 @@ export default React.createClass({
|
||||||
|
|
||||||
case PageTypes.RoomDirectory:
|
case PageTypes.RoomDirectory:
|
||||||
page_element = <RoomDirectory
|
page_element = <RoomDirectory
|
||||||
|
ref="roomDirectory"
|
||||||
collapsedRhs={this.props.collapse_rhs}
|
collapsedRhs={this.props.collapse_rhs}
|
||||||
config={this.props.config.roomDirectory}
|
config={this.props.config.roomDirectory}
|
||||||
/>;
|
/>;
|
||||||
|
|
|
@ -413,7 +413,7 @@ module.exports = React.createClass({
|
||||||
console.error("Failed to leave room " + payload.room_id + " " + err);
|
console.error("Failed to leave room " + payload.room_id + " " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failed to leave room",
|
title: "Failed to leave room",
|
||||||
description: "Server may be unavailable, overloaded, or you hit a bug."
|
description: (err && err.message ? err.message : "Server may be unavailable, overloaded, or you hit a bug."),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ var q = require("q");
|
||||||
var classNames = require("classnames");
|
var classNames = require("classnames");
|
||||||
var Matrix = require("matrix-js-sdk");
|
var Matrix = require("matrix-js-sdk");
|
||||||
|
|
||||||
|
var UserSettingsStore = require('../../UserSettingsStore');
|
||||||
var MatrixClientPeg = require("../../MatrixClientPeg");
|
var MatrixClientPeg = require("../../MatrixClientPeg");
|
||||||
var ContentMessages = require("../../ContentMessages");
|
var ContentMessages = require("../../ContentMessages");
|
||||||
var Modal = require("../../Modal");
|
var Modal = require("../../Modal");
|
||||||
|
@ -946,7 +947,7 @@ module.exports = React.createClass({
|
||||||
console.error("Failed to upload file " + file + " " + error);
|
console.error("Failed to upload file " + file + " " + error);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failed to upload file",
|
title: "Failed to upload file",
|
||||||
description: "Server may be unavailable, overloaded, or the file too big",
|
description: ((error && error.message) ? error.message : "Server may be unavailable, overloaded, or the file too big"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1033,7 +1034,7 @@ module.exports = React.createClass({
|
||||||
console.error("Search failed: " + error);
|
console.error("Search failed: " + error);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Search failed",
|
title: "Search failed",
|
||||||
description: "Server may be unavailable, overloaded, or search timed out :("
|
description: ((error && error.message) ? error.message : "Server may be unavailable, overloaded, or search timed out :("),
|
||||||
});
|
});
|
||||||
}).finally(function() {
|
}).finally(function() {
|
||||||
self.setState({
|
self.setState({
|
||||||
|
@ -1181,6 +1182,7 @@ module.exports = React.createClass({
|
||||||
console.log("updateTint from onCancelClick");
|
console.log("updateTint from onCancelClick");
|
||||||
this.updateTint();
|
this.updateTint();
|
||||||
this.setState({editingRoomSettings: false});
|
this.setState({editingRoomSettings: false});
|
||||||
|
dis.dispatch({action: 'focus_composer'});
|
||||||
},
|
},
|
||||||
|
|
||||||
onLeaveClick: function() {
|
onLeaveClick: function() {
|
||||||
|
@ -1726,7 +1728,7 @@ module.exports = React.createClass({
|
||||||
var messagePanel = (
|
var messagePanel = (
|
||||||
<TimelinePanel ref={this._gatherTimelinePanelRef}
|
<TimelinePanel ref={this._gatherTimelinePanelRef}
|
||||||
timelineSet={this.state.room.getUnfilteredTimelineSet()}
|
timelineSet={this.state.room.getUnfilteredTimelineSet()}
|
||||||
manageReadReceipts={true}
|
manageReadReceipts={!UserSettingsStore.getSyncedSetting('hideReadReceipts', false)}
|
||||||
manageReadMarkers={true}
|
manageReadMarkers={true}
|
||||||
hidden={hideMessagePanel}
|
hidden={hideMessagePanel}
|
||||||
highlightedEventId={this.props.highlightedEventId}
|
highlightedEventId={this.props.highlightedEventId}
|
||||||
|
|
|
@ -483,21 +483,25 @@ module.exports = React.createClass({
|
||||||
handleScrollKey: function(ev) {
|
handleScrollKey: function(ev) {
|
||||||
switch (ev.keyCode) {
|
switch (ev.keyCode) {
|
||||||
case KeyCode.PAGE_UP:
|
case KeyCode.PAGE_UP:
|
||||||
|
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this.scrollRelative(-1);
|
this.scrollRelative(-1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.PAGE_DOWN:
|
case KeyCode.PAGE_DOWN:
|
||||||
|
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this.scrollRelative(1);
|
this.scrollRelative(1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.HOME:
|
case KeyCode.HOME:
|
||||||
if (ev.ctrlKey) {
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this.scrollToTop();
|
this.scrollToTop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.END:
|
case KeyCode.END:
|
||||||
if (ev.ctrlKey) {
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -766,7 +766,9 @@ var TimelinePanel = React.createClass({
|
||||||
|
|
||||||
// jump to the live timeline on ctrl-end, rather than the end of the
|
// jump to the live timeline on ctrl-end, rather than the end of the
|
||||||
// timeline window.
|
// timeline window.
|
||||||
if (ev.ctrlKey && ev.keyCode == KeyCode.END) {
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey &&
|
||||||
|
ev.keyCode == KeyCode.END)
|
||||||
|
{
|
||||||
this.jumpToLiveTimeline();
|
this.jumpToLiveTimeline();
|
||||||
} else {
|
} else {
|
||||||
this.refs.messagePanel.handleScrollKey(ev);
|
this.refs.messagePanel.handleScrollKey(ev);
|
||||||
|
|
|
@ -31,10 +31,14 @@ var SdkConfig = require('../../SdkConfig');
|
||||||
import AccessibleButton from '../views/elements/AccessibleButton';
|
import AccessibleButton from '../views/elements/AccessibleButton';
|
||||||
|
|
||||||
// if this looks like a release, use the 'version' from package.json; else use
|
// if this looks like a release, use the 'version' from package.json; else use
|
||||||
// the git sha.
|
// the git sha. Prepend version with v, to look like riot-web version
|
||||||
const REACT_SDK_VERSION =
|
const REACT_SDK_VERSION = 'dist' in package_json ? `v${package_json.version}` : package_json.gitHead || '<local>';
|
||||||
'dist' in package_json ? package_json.version : package_json.gitHead || "<local>";
|
|
||||||
|
|
||||||
|
// Simple method to help prettify GH Release Tags and Commit Hashes.
|
||||||
|
const GHVersionUrl = function(repo, token) {
|
||||||
|
const uriTail = (token.startsWith('v') && token.includes('.')) ? `releases/tag/${token}` : `commit/${token}`;
|
||||||
|
return `https://github.com/${repo}/${uriTail}`;
|
||||||
|
}
|
||||||
|
|
||||||
// Enumerate some simple 'flip a bit' UI settings (if any).
|
// Enumerate some simple 'flip a bit' UI settings (if any).
|
||||||
// 'id' gives the key name in the im.vector.web.settings account data event
|
// 'id' gives the key name in the im.vector.web.settings account data event
|
||||||
|
@ -44,6 +48,14 @@ const SETTINGS_LABELS = [
|
||||||
id: 'autoplayGifsAndVideos',
|
id: 'autoplayGifsAndVideos',
|
||||||
label: 'Autoplay GIFs and videos',
|
label: 'Autoplay GIFs and videos',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'hideReadReceipts',
|
||||||
|
label: 'Hide read receipts'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'dontSendTypingNotifications',
|
||||||
|
label: "Don't send typing notifications",
|
||||||
|
},
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
id: 'alwaysShowTimestamps',
|
id: 'alwaysShowTimestamps',
|
||||||
|
@ -211,7 +223,7 @@ module.exports = React.createClass({
|
||||||
console.error("Failed to load user settings: " + error);
|
console.error("Failed to load user settings: " + error);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Can't load user settings",
|
title: "Can't load user settings",
|
||||||
description: "Server may be unavailable or overloaded",
|
description: ((error && error.message) ? error.message : "Server may be unavailable or overloaded"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -252,8 +264,8 @@ module.exports = React.createClass({
|
||||||
console.error("Failed to set avatar: " + err);
|
console.error("Failed to set avatar: " + err);
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to set avatar",
|
||||||
description: "Failed to set avatar."
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -271,7 +283,7 @@ module.exports = React.createClass({
|
||||||
</div>,
|
</div>,
|
||||||
button: "Sign out",
|
button: "Sign out",
|
||||||
extraButtons: [
|
extraButtons: [
|
||||||
<button className="mx_Dialog_primary"
|
<button key="export" className="mx_Dialog_primary"
|
||||||
onClick={this._onExportE2eKeysClicked}>
|
onClick={this._onExportE2eKeysClicked}>
|
||||||
Export E2E room keys
|
Export E2E room keys
|
||||||
</button>
|
</button>
|
||||||
|
@ -354,8 +366,8 @@ module.exports = React.createClass({
|
||||||
this.setState({email_add_pending: false});
|
this.setState({email_add_pending: false});
|
||||||
console.error("Unable to add email address " + email_address + " " + err);
|
console.error("Unable to add email address " + email_address + " " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Unable to add email address",
|
||||||
description: "Unable to add email address"
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ReactDOM.findDOMNode(this.refs.add_email_input).blur();
|
ReactDOM.findDOMNode(this.refs.add_email_input).blur();
|
||||||
|
@ -379,8 +391,8 @@ module.exports = React.createClass({
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Unable to remove contact information: " + err);
|
console.error("Unable to remove contact information: " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Unable to remove contact information",
|
||||||
description: "Unable to remove contact information",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
}).done();
|
}).done();
|
||||||
}
|
}
|
||||||
|
@ -420,8 +432,8 @@ module.exports = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Unable to verify email address: " + err);
|
console.error("Unable to verify email address: " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Unable to verify email address",
|
||||||
description: "Unable to verify email address",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -763,6 +775,20 @@ module.exports = React.createClass({
|
||||||
</div>;
|
</div>;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_showSpoiler: function(event) {
|
||||||
|
const target = event.target;
|
||||||
|
const hidden = target.getAttribute('data-spoiler');
|
||||||
|
|
||||||
|
target.innerHTML = hidden;
|
||||||
|
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNodeContents(target);
|
||||||
|
|
||||||
|
const selection = window.getSelection();
|
||||||
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(range);
|
||||||
|
},
|
||||||
|
|
||||||
nameForMedium: function(medium) {
|
nameForMedium: function(medium) {
|
||||||
if (medium == 'msisdn') return 'Phone';
|
if (medium == 'msisdn') return 'Phone';
|
||||||
return medium[0].toUpperCase() + medium.slice(1);
|
return medium[0].toUpperCase() + medium.slice(1);
|
||||||
|
@ -880,12 +906,12 @@ module.exports = React.createClass({
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
var olmVersion = MatrixClientPeg.get().olmVersion;
|
const olmVersion = MatrixClientPeg.get().olmVersion;
|
||||||
// If the olmVersion is not defined then either crypto is disabled, or
|
// If the olmVersion is not defined then either crypto is disabled, or
|
||||||
// we are using a version old version of olm. We assume the former.
|
// we are using a version old version of olm. We assume the former.
|
||||||
var olmVersionString = "<not-enabled>";
|
let olmVersionString = "<not-enabled>";
|
||||||
if (olmVersion !== undefined) {
|
if (olmVersion !== undefined) {
|
||||||
olmVersionString = olmVersion[0] + "." + olmVersion[1] + "." + olmVersion[2];
|
olmVersionString = `v${olmVersion[0]}.${olmVersion[1]}.${olmVersion[2]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -958,6 +984,9 @@ module.exports = React.createClass({
|
||||||
<div className="mx_UserSettings_advanced">
|
<div className="mx_UserSettings_advanced">
|
||||||
Logged in as {this._me}
|
Logged in as {this._me}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mx_UserSettings_advanced">
|
||||||
|
Access Token: <span className="mx_UserSettings_advanced_spoiler" onClick={this._showSpoiler} data-spoiler={ MatrixClientPeg.get().getAccessToken() }><click to reveal></span>
|
||||||
|
</div>
|
||||||
<div className="mx_UserSettings_advanced">
|
<div className="mx_UserSettings_advanced">
|
||||||
Homeserver is { MatrixClientPeg.get().getHomeserverUrl() }
|
Homeserver is { MatrixClientPeg.get().getHomeserverUrl() }
|
||||||
</div>
|
</div>
|
||||||
|
@ -965,8 +994,14 @@ module.exports = React.createClass({
|
||||||
Identity Server is { MatrixClientPeg.get().getIdentityServerUrl() }
|
Identity Server is { MatrixClientPeg.get().getIdentityServerUrl() }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_UserSettings_advanced">
|
<div className="mx_UserSettings_advanced">
|
||||||
matrix-react-sdk version: {REACT_SDK_VERSION}<br/>
|
matrix-react-sdk version: {(REACT_SDK_VERSION !== '<local>')
|
||||||
riot-web version: {this.state.vectorVersion !== null ? this.state.vectorVersion : 'unknown'}<br/>
|
? <a href={ GHVersionUrl('matrix-org/matrix-react-sdk', REACT_SDK_VERSION) }>{REACT_SDK_VERSION}</a>
|
||||||
|
: REACT_SDK_VERSION
|
||||||
|
}<br/>
|
||||||
|
riot-web version: {(this.state.vectorVersion !== null)
|
||||||
|
? <a href={ GHVersionUrl('vector-im/riot-web', this.state.vectorVersion.split('-')[0]) }>{this.state.vectorVersion}</a>
|
||||||
|
: 'unknown'
|
||||||
|
}<br/>
|
||||||
olm version: {olmVersionString}<br/>
|
olm version: {olmVersionString}<br/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -47,6 +47,16 @@ export default React.createClass({
|
||||||
children: React.PropTypes.node,
|
children: React.PropTypes.node,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentWillMount: function() {
|
||||||
|
this.priorActiveElement = document.activeElement;
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
if (this.priorActiveElement !== null) {
|
||||||
|
this.priorActiveElement.focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_onKeyDown: function(e) {
|
_onKeyDown: function(e) {
|
||||||
if (e.keyCode === KeyCode.ESCAPE) {
|
if (e.keyCode === KeyCode.ESCAPE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
|
@ -308,8 +308,8 @@ module.exports = React.createClass({
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to invite",
|
||||||
description: "Failed to invite",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
|
@ -321,8 +321,8 @@ module.exports = React.createClass({
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to invite user",
|
||||||
description: "Failed to invite user",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
|
@ -342,8 +342,8 @@ module.exports = React.createClass({
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to invite",
|
||||||
description: "Failed to invite",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
|
|
|
@ -50,6 +50,12 @@ export default React.createClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
if (this.props.focus) {
|
||||||
|
this.refs.button.focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
return (
|
return (
|
||||||
|
@ -59,7 +65,7 @@ export default React.createClass({
|
||||||
{this.props.description}
|
{this.props.description}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button className="mx_Dialog_primary" onClick={this.props.onFinished} autoFocus={this.props.focus}>
|
<button ref="button" className="mx_Dialog_primary" onClick={this.props.onFinished}>
|
||||||
{this.props.button}
|
{this.props.button}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -346,7 +346,7 @@ module.exports = React.createClass({
|
||||||
return (
|
return (
|
||||||
<span className="mx_MFileBody">
|
<span className="mx_MFileBody">
|
||||||
<div className="mx_MImageBody_download">
|
<div className="mx_MImageBody_download">
|
||||||
<a className="mx_ImageBody_downloadLink" href={contentUrl} target="_blank">
|
<a className="mx_ImageBody_downloadLink" href={contentUrl} download={fileName} target="_blank">
|
||||||
{ fileName }
|
{ fileName }
|
||||||
</a>
|
</a>
|
||||||
<div className="mx_MImageBody_size">
|
<div className="mx_MImageBody_size">
|
||||||
|
@ -360,7 +360,7 @@ module.exports = React.createClass({
|
||||||
return (
|
return (
|
||||||
<span className="mx_MFileBody">
|
<span className="mx_MFileBody">
|
||||||
<div className="mx_MImageBody_download">
|
<div className="mx_MImageBody_download">
|
||||||
<a href={contentUrl} target="_blank" rel="noopener">
|
<a href={contentUrl} download={fileName} target="_blank" rel="noopener">
|
||||||
<img src={tintedDownloadImageURL} width="12" height="14" ref="downloadImage"/>
|
<img src={tintedDownloadImageURL} width="12" height="14" ref="downloadImage"/>
|
||||||
Download {text}
|
Download {text}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -56,6 +56,7 @@ module.exports = React.createClass({
|
||||||
const ImageView = sdk.getComponent("elements.ImageView");
|
const ImageView = sdk.getComponent("elements.ImageView");
|
||||||
const params = {
|
const params = {
|
||||||
src: httpUrl,
|
src: httpUrl,
|
||||||
|
name: content.body && content.body.length > 0 ? content.body : 'Attachment',
|
||||||
mxEvent: this.props.mxEvent,
|
mxEvent: this.props.mxEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -284,6 +284,12 @@ module.exports = WithMatrixClient(React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
getReadAvatars: function() {
|
getReadAvatars: function() {
|
||||||
|
|
||||||
|
// return early if there are no read receipts
|
||||||
|
if (!this.props.readReceipts || this.props.readReceipts.length === 0) {
|
||||||
|
return (<span className="mx_EventTile_readAvatars"></span>);
|
||||||
|
}
|
||||||
|
|
||||||
const ReadReceiptMarker = sdk.getComponent('rooms.ReadReceiptMarker');
|
const ReadReceiptMarker = sdk.getComponent('rooms.ReadReceiptMarker');
|
||||||
const avatars = [];
|
const avatars = [];
|
||||||
const receiptOffset = 15;
|
const receiptOffset = 15;
|
||||||
|
|
|
@ -241,8 +241,8 @@ module.exports = WithMatrixClient(React.createClass({
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Kick error: " + err);
|
console.error("Kick error: " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to kick",
|
||||||
description: "Failed to kick user",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
).finally(()=>{
|
).finally(()=>{
|
||||||
|
|
|
@ -355,6 +355,7 @@ export default class MessageComposerInput extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
sendTyping(isTyping) {
|
sendTyping(isTyping) {
|
||||||
|
if (UserSettingsStore.getSyncedSetting('dontSendTypingNotifications', false)) return;
|
||||||
MatrixClientPeg.get().sendTyping(
|
MatrixClientPeg.get().sendTyping(
|
||||||
this.props.room.roomId,
|
this.props.room.roomId,
|
||||||
this.isTyping, TYPING_SERVER_TIMEOUT
|
this.isTyping, TYPING_SERVER_TIMEOUT
|
||||||
|
@ -509,7 +510,7 @@ export default class MessageComposerInput extends React.Component {
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Server error",
|
title: "Server error",
|
||||||
description: "Server unavailable, overloaded, or something else went wrong.",
|
description: ((err && err.message) ? err.message : "Server unavailable, overloaded, or something else went wrong."),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ var SlashCommands = require("../../../SlashCommands");
|
||||||
var Modal = require("../../../Modal");
|
var Modal = require("../../../Modal");
|
||||||
var MemberEntry = require("../../../TabCompleteEntries").MemberEntry;
|
var MemberEntry = require("../../../TabCompleteEntries").MemberEntry;
|
||||||
var sdk = require('../../../index');
|
var sdk = require('../../../index');
|
||||||
|
import UserSettingsStore from "../../../UserSettingsStore";
|
||||||
|
|
||||||
var dis = require("../../../dispatcher");
|
var dis = require("../../../dispatcher");
|
||||||
var KeyCode = require("../../../KeyCode");
|
var KeyCode = require("../../../KeyCode");
|
||||||
|
@ -311,7 +312,7 @@ export default React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Server error",
|
title: "Server error",
|
||||||
description: "Server unavailable, overloaded, or something else went wrong.",
|
description: ((err && err.message) ? err.message : "Server unavailable, overloaded, or something else went wrong."),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -420,6 +421,7 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
sendTyping: function(isTyping) {
|
sendTyping: function(isTyping) {
|
||||||
|
if (UserSettingsStore.getSyncedSetting('dontSendTypingNotifications', false)) return;
|
||||||
MatrixClientPeg.get().sendTyping(
|
MatrixClientPeg.get().sendTyping(
|
||||||
this.props.room.roomId,
|
this.props.room.roomId,
|
||||||
this.isTyping, TYPING_SERVER_TIMEOUT
|
this.isTyping, TYPING_SERVER_TIMEOUT
|
||||||
|
|
|
@ -75,7 +75,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
if (this.props.activeAgo >= 0) {
|
if (this.props.activeAgo >= 0) {
|
||||||
var ago = this.props.currentlyActive ? "now" : (this.getDuration(this.props.activeAgo) + " ago");
|
var ago = this.props.currentlyActive ? "" : "for " + (this.getDuration(this.props.activeAgo));
|
||||||
// var ago = this.getDuration(this.props.activeAgo) + " ago";
|
// var ago = this.getDuration(this.props.activeAgo) + " ago";
|
||||||
// if (this.props.currentlyActive) ago += " (now?)";
|
// if (this.props.currentlyActive) ago += " (now?)";
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -265,9 +265,16 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomStateMember: function(ev, state, member) {
|
onRoomStateMember: function(ev, state, member) {
|
||||||
|
if (ev.getStateKey() === MatrixClientPeg.get().credentials.userId &&
|
||||||
|
ev.getPrevContent() && ev.getPrevContent().membership === "invite")
|
||||||
|
{
|
||||||
|
this._delayedRefreshRoomList();
|
||||||
|
}
|
||||||
|
else {
|
||||||
constantTimeDispatcher.dispatch(
|
constantTimeDispatcher.dispatch(
|
||||||
"RoomTile.refresh", member.roomId, {}
|
"RoomTile.refresh", member.roomId, {}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomMemberName: function(ev, member) {
|
onRoomMemberName: function(ev, member) {
|
||||||
|
@ -449,11 +456,10 @@ module.exports = React.createClass({
|
||||||
var panel = ReactDOM.findDOMNode(this);
|
var panel = ReactDOM.findDOMNode(this);
|
||||||
if (!panel) return null;
|
if (!panel) return null;
|
||||||
|
|
||||||
if (panel.classList.contains('gm-prevented')) {
|
// empirically, if we have gm-prevented for some reason, the scroll node
|
||||||
return panel;
|
// is still the 3rd child (i.e. the view child). This looks to be due
|
||||||
} else {
|
// to vdh's improved resize updater logic...?
|
||||||
return panel.children[2]; // XXX: Fragile!
|
return panel.children[2]; // XXX: Fragile!
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_whenScrolling: function(e) {
|
_whenScrolling: function(e) {
|
||||||
|
@ -476,7 +482,7 @@ module.exports = React.createClass({
|
||||||
// Use the offset of the top of the scroll area from the window
|
// Use the offset of the top of the scroll area from the window
|
||||||
// as this is used to calculate the CSS fixed top position for the stickies
|
// as this is used to calculate the CSS fixed top position for the stickies
|
||||||
var scrollAreaOffset = scrollArea.getBoundingClientRect().top + window.pageYOffset;
|
var scrollAreaOffset = scrollArea.getBoundingClientRect().top + window.pageYOffset;
|
||||||
// Use the offset of the top of the componet from the window
|
// Use the offset of the top of the component from the window
|
||||||
// as this is used to calculate the CSS fixed top position for the stickies
|
// as this is used to calculate the CSS fixed top position for the stickies
|
||||||
var scrollAreaHeight = ReactDOM.findDOMNode(this).getBoundingClientRect().height;
|
var scrollAreaHeight = ReactDOM.findDOMNode(this).getBoundingClientRect().height;
|
||||||
|
|
||||||
|
@ -499,7 +505,7 @@ module.exports = React.createClass({
|
||||||
// Use the offset of the top of the scroll area from the window
|
// Use the offset of the top of the scroll area from the window
|
||||||
// as this is used to calculate the CSS fixed top position for the stickies
|
// as this is used to calculate the CSS fixed top position for the stickies
|
||||||
var scrollAreaOffset = scrollArea.getBoundingClientRect().top + window.pageYOffset;
|
var scrollAreaOffset = scrollArea.getBoundingClientRect().top + window.pageYOffset;
|
||||||
// Use the offset of the top of the componet from the window
|
// Use the offset of the top of the component from the window
|
||||||
// as this is used to calculate the CSS fixed top position for the stickies
|
// as this is used to calculate the CSS fixed top position for the stickies
|
||||||
var scrollAreaHeight = ReactDOM.findDOMNode(this).getBoundingClientRect().height;
|
var scrollAreaHeight = ReactDOM.findDOMNode(this).getBoundingClientRect().height;
|
||||||
|
|
||||||
|
@ -599,7 +605,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GeminiScrollbar className="mx_RoomList_scrollbar"
|
<GeminiScrollbar className="mx_RoomList_scrollbar"
|
||||||
autoshow={true} onScroll={ self._whenScrolling } ref="gemscroll">
|
autoshow={true} onScroll={ self._whenScrolling } onResize={ self._whenScrolling } ref="gemscroll">
|
||||||
<div className="mx_RoomList" onMouseOver={ this._onMouseOver }>
|
<div className="mx_RoomList" onMouseOver={ this._onMouseOver }>
|
||||||
<RoomSubList list={ self.state.lists['im.vector.fake.invite'] }
|
<RoomSubList list={ self.state.lists['im.vector.fake.invite'] }
|
||||||
label="Invites"
|
label="Invites"
|
||||||
|
|
|
@ -129,6 +129,8 @@ module.exports = React.createClass({
|
||||||
console.error("Failed to get room visibility: " + err);
|
console.error("Failed to get room visibility: " + err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.scalarClient = null;
|
||||||
|
if (SdkConfig.get().integrations_ui_url && SdkConfig.get().integrations_rest_url) {
|
||||||
this.scalarClient = new ScalarAuthClient();
|
this.scalarClient = new ScalarAuthClient();
|
||||||
this.scalarClient.connect().done(() => {
|
this.scalarClient.connect().done(() => {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
|
@ -137,6 +139,7 @@ module.exports = React.createClass({
|
||||||
scalar_error: err
|
scalar_error: err
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'ui_opacity',
|
action: 'ui_opacity',
|
||||||
|
@ -490,7 +493,7 @@ module.exports = React.createClass({
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
var IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
|
var IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
|
||||||
Modal.createDialog(IntegrationsManager, {
|
Modal.createDialog(IntegrationsManager, {
|
||||||
src: this.scalarClient.hasCredentials() ?
|
src: (this.scalarClient !== null && this.scalarClient.hasCredentials()) ?
|
||||||
this.scalarClient.getScalarInterfaceUrlForRoom(this.props.room.roomId) :
|
this.scalarClient.getScalarInterfaceUrlForRoom(this.props.room.roomId) :
|
||||||
null,
|
null,
|
||||||
onFinished: ()=>{
|
onFinished: ()=>{
|
||||||
|
@ -765,8 +768,10 @@ module.exports = React.createClass({
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
var integrationsButton;
|
let integrationsButton;
|
||||||
var integrationsError;
|
let integrationsError;
|
||||||
|
|
||||||
|
if (this.scalarClient !== null) {
|
||||||
if (this.state.showIntegrationsError && this.state.scalar_error) {
|
if (this.state.showIntegrationsError && this.state.scalar_error) {
|
||||||
console.error(this.state.scalar_error);
|
console.error(this.state.scalar_error);
|
||||||
integrationsError = (
|
integrationsError = (
|
||||||
|
@ -796,6 +801,7 @@ module.exports = React.createClass({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomSettings">
|
<div className="mx_RoomSettings">
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2016 OpenMarket Ltd
|
Copyright 2016 OpenMarket Ltd
|
||||||
|
Copyright 2017 Vector Creations Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -32,7 +33,10 @@ module.exports = React.createClass({
|
||||||
<div className="mx_TopUnreadMessagesBar">
|
<div className="mx_TopUnreadMessagesBar">
|
||||||
<div className="mx_TopUnreadMessagesBar_scrollUp"
|
<div className="mx_TopUnreadMessagesBar_scrollUp"
|
||||||
onClick={this.props.onScrollUpClick}>
|
onClick={this.props.onScrollUpClick}>
|
||||||
Jump to first unread message. <span style={{ textDecoration: 'underline' }} onClick={this.props.onCloseClick}>Mark all read</span>
|
<img src="img/scrollto.svg" width="24" height="24"
|
||||||
|
alt="Scroll to unread messages"
|
||||||
|
title="Scroll to unread messages"/>
|
||||||
|
Jump to first unread message.
|
||||||
</div>
|
</div>
|
||||||
<img className="mx_TopUnreadMessagesBar_close"
|
<img className="mx_TopUnreadMessagesBar_close"
|
||||||
src="img/cancel.svg" width="18" height="18"
|
src="img/cancel.svg" width="18" height="18"
|
||||||
|
|
|
@ -122,7 +122,7 @@ var escapeRegExp = function(string) {
|
||||||
// anyone else really should be using matrix.to.
|
// anyone else really should be using matrix.to.
|
||||||
matrixLinkify.VECTOR_URL_PATTERN = "^(?:https?:\/\/)?(?:"
|
matrixLinkify.VECTOR_URL_PATTERN = "^(?:https?:\/\/)?(?:"
|
||||||
+ escapeRegExp(window.location.host + window.location.pathname) + "|"
|
+ escapeRegExp(window.location.host + window.location.pathname) + "|"
|
||||||
+ "(?:www\\.)?(?:riot|vector)\\.im/(?:beta|staging|develop)/"
|
+ "(?:www\\.)?(?:riot|vector)\\.im/(?:app|beta|staging|develop)/"
|
||||||
+ ")(#.*)";
|
+ ")(#.*)";
|
||||||
|
|
||||||
matrixLinkify.MATRIXTO_URL_PATTERN = "^(?:https?:\/\/)?(?:www\\.)?matrix\\.to/#/((#|@|!).*)";
|
matrixLinkify.MATRIXTO_URL_PATTERN = "^(?:https?:\/\/)?(?:www\\.)?matrix\\.to/#/((#|@|!).*)";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue