Merge remote-tracking branch 'upstream/develop' into hs/upload-limits

This commit is contained in:
Will Hunt 2018-12-01 16:24:43 +00:00
commit 2b077b4f5d
142 changed files with 5235 additions and 671 deletions

View file

@ -33,7 +33,6 @@ import Autocompleter from '../../../autocomplete/Autocompleter';
const COMPOSER_SELECTED = 0;
export default class Autocomplete extends React.Component {
constructor(props) {
super(props);

View file

@ -416,11 +416,10 @@ module.exports = withMatrixClient(React.createClass({
onCryptoClicked: function(e) {
const event = this.props.mxEvent;
Modal.createTrackedDialogAsync('Encrypted Event Dialog', '', (cb) => {
require(['../../../async-components/views/dialogs/EncryptedEventDialog'], cb);
}, {
event: event,
});
Modal.createTrackedDialogAsync('Encrypted Event Dialog', '',
import('../../../async-components/views/dialogs/EncryptedEventDialog'),
{event},
);
},
onRequestKeysClick: function() {

View file

@ -107,7 +107,7 @@ module.exports = React.createClass({
// FIXME: do we want to factor out all image displaying between this and MImageBody - especially for lightboxing?
let image = p["og:image"];
let imageMaxWidth = 100, imageMaxHeight = 100;
const imageMaxWidth = 100; const imageMaxHeight = 100;
if (image && image.startsWith("mxc://")) {
image = MatrixClientPeg.get().mxcUrlToHttp(image, imageMaxWidth, imageMaxHeight);
}

View file

@ -712,7 +712,7 @@ module.exports = withMatrixClient(React.createClass({
if (!member || !member.membership || member.membership === 'leave') {
const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId();
const onInviteUserButton = async () => {
const onInviteUserButton = async() => {
try {
await cli.invite(roomId, member.userId);
} catch (err) {

View file

@ -447,7 +447,7 @@ module.exports = React.createClass({
return (
<div className="mx_MemberList">
{ inputBox }
<GeminiScrollbarWrapper autoshow={true} className="mx_MemberList_joined mx_MemberList_outerWrapper">
<GeminiScrollbarWrapper autoshow={true} className="mx_MemberList_joined">
<TruncatedList className="mx_MemberList_wrapper" truncateAt={this.state.truncateAtJoined}
createOverflowElement={this._createOverflowTileJoined}
getChildren={this._getChildrenJoined}

View file

@ -305,7 +305,7 @@ export default class MessageComposer extends React.Component {
);
}
let e2eImg, e2eTitle, e2eClass;
let e2eImg; let e2eTitle; let e2eClass;
const roomIsEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId);
if (roomIsEncrypted) {
// FIXME: show a /!\ if there are untrusted devices in the room...
@ -465,7 +465,7 @@ export default class MessageComposer extends React.Component {
className="mx_MessageComposer_formatbar_cancel mx_filterFlipColor"
src="img/icon-text-cancel.svg" />
</div>
</div>
</div>;
}
return (

View file

@ -67,7 +67,7 @@ const EMOJI_UNICODE_TO_SHORTNAME = mapUnicodeToShort();
const REGEX_EMOJI_WHITESPACE = new RegExp('(?:^|\\s)(' + asciiRegexp + ')\\s$');
const EMOJI_REGEX = new RegExp(unicodeRegexp, 'g');
const TYPING_USER_TIMEOUT = 10000, TYPING_SERVER_TIMEOUT = 30000;
const TYPING_USER_TIMEOUT = 10000; const TYPING_SERVER_TIMEOUT = 30000;
const ENTITY_TYPES = {
AT_ROOM_PILL: 'ATROOMPILL',
@ -175,8 +175,8 @@ export default class MessageComposerInput extends React.Component {
// see https://github.com/ianstormtaylor/slate/issues/762#issuecomment-304855095
this.direction = '';
this.plainWithMdPills = new PlainWithPillsSerializer({ pillFormat: 'md' });
this.plainWithIdPills = new PlainWithPillsSerializer({ pillFormat: 'id' });
this.plainWithMdPills = new PlainWithPillsSerializer({ pillFormat: 'md' });
this.plainWithIdPills = new PlainWithPillsSerializer({ pillFormat: 'id' });
this.plainWithPlainPills = new PlainWithPillsSerializer({ pillFormat: 'plain' });
this.md = new Md({
@ -544,7 +544,7 @@ export default class MessageComposerInput extends React.Component {
if (editorState.startText !== null) {
const text = editorState.startText.text;
const currentStartOffset = editorState.startOffset;
const currentStartOffset = editorState.selection.start.offset;
// Automatic replacement of plaintext emoji to Unicode emoji
if (SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji')) {
@ -558,11 +558,11 @@ export default class MessageComposerInput extends React.Component {
const range = Range.create({
anchor: {
key: editorState.selection.startKey,
key: editorState.startText.key,
offset: currentStartOffset - emojiMatch[1].length - 1,
},
focus: {
key: editorState.selection.startKey,
key: editorState.startText.key,
offset: currentStartOffset - 1,
},
});
@ -573,29 +573,42 @@ export default class MessageComposerInput extends React.Component {
}
// emojioneify any emoji
editorState.document.getTexts().forEach(node => {
if (node.text !== '' && HtmlUtils.containsEmoji(node.text)) {
let match;
while ((match = EMOJI_REGEX.exec(node.text)) !== null) {
const range = Range.create({
anchor: {
key: node.key,
offset: match.index,
},
focus: {
key: node.key,
offset: match.index + match[0].length,
},
});
const inline = Inline.create({
type: 'emoji',
data: { emojiUnicode: match[0] },
});
change = change.insertInlineAtRange(range, inline);
editorState = change.value;
let foundEmoji;
do {
foundEmoji = false;
for (const node of editorState.document.getTexts()) {
if (node.text !== '' && HtmlUtils.containsEmoji(node.text)) {
let match;
EMOJI_REGEX.lastIndex = 0;
while ((match = EMOJI_REGEX.exec(node.text)) !== null) {
const range = Range.create({
anchor: {
key: node.key,
offset: match.index,
},
focus: {
key: node.key,
offset: match.index + match[0].length,
},
});
const inline = Inline.create({
type: 'emoji',
data: { emojiUnicode: match[0] },
});
change = change.insertInlineAtRange(range, inline);
editorState = change.value;
// if we replaced an emoji, start again looking for more
// emoji in the new editor state since doing the replacement
// will change the node structure & offsets so we can't compute
// insertion ranges from node.key / match.index anymore.
foundEmoji = true;
break;
}
}
}
});
} while (foundEmoji);
// work around weird bug where inserting emoji via the macOS
// emoji picker can leave the selection stuck in the emoji's
@ -1065,7 +1078,7 @@ export default class MessageComposerInput extends React.Component {
// only look for commands if the first block contains simple unformatted text
// i.e. no pills or rich-text formatting and begins with a /.
let cmd, commandText;
let cmd; let commandText;
const firstChild = editorState.document.nodes.get(0);
const firstGrandChild = firstChild && firstChild.nodes.get(0);
if (firstChild && firstGrandChild &&
@ -1247,7 +1260,7 @@ export default class MessageComposerInput extends React.Component {
}
};
selectHistory = async (up) => {
selectHistory = async(up) => {
const delta = up ? -1 : 1;
// True if we are not currently selecting history, but composing a message
@ -1295,7 +1308,7 @@ export default class MessageComposerInput extends React.Component {
return true;
};
onTab = async (e) => {
onTab = async(e) => {
this.setState({
someCompletions: null,
});
@ -1317,7 +1330,7 @@ export default class MessageComposerInput extends React.Component {
up ? this.autocomplete.onUpArrow() : this.autocomplete.onDownArrow();
};
onEscape = async (e) => {
onEscape = async(e) => {
e.preventDefault();
if (this.autocomplete) {
this.autocomplete.onEscape(e);
@ -1336,7 +1349,7 @@ export default class MessageComposerInput extends React.Component {
/* If passed null, restores the original editor content from state.originalEditorState.
* If passed a non-null displayedCompletion, modifies state.originalEditorState to compute new state.editorState.
*/
setDisplayedCompletion = async (displayedCompletion: ?Completion): boolean => {
setDisplayedCompletion = async(displayedCompletion: ?Completion): boolean => {
const activeEditorState = this.state.originalEditorState || this.state.editorState;
if (displayedCompletion == null) {

View file

@ -44,9 +44,13 @@ module.exports = React.createClass({
error: PropTypes.object,
canPreview: PropTypes.bool,
spinner: PropTypes.bool,
room: PropTypes.object,
// When a spinner is present, a spinnerState can be specified to indicate the
// purpose of the spinner.
spinner: PropTypes.bool,
spinnerState: PropTypes.oneOf(["joining"]),
// The alias that was used to access this room, if appropriate
// If given, this will be how the room is referred to (eg.
// in error messages).
@ -89,11 +93,16 @@ module.exports = React.createClass({
},
render: function() {
let joinBlock, previewBlock;
let joinBlock; let previewBlock;
if (this.props.spinner || this.state.busy) {
const Spinner = sdk.getComponent("elements.Spinner");
let spinnerIntro = "";
if (this.props.spinnerState === "joining") {
spinnerIntro = _t("Joining room...");
}
return (<div className="mx_RoomPreviewBar">
<p className="mx_RoomPreviewBar_spinnerIntro">{ spinnerIntro }</p>
<Spinner />
</div>);
}

View file

@ -590,6 +590,11 @@ module.exports = React.createClass({
}
},
_openDevtools: function() {
const DevtoolsDialog = sdk.getComponent('dialogs.DevtoolsDialog');
Modal.createDialog(DevtoolsDialog, {roomId: this.props.room.roomId});
},
_renderEncryptionSection: function() {
const SettingsFlag = sdk.getComponent("elements.SettingsFlag");
@ -652,31 +657,31 @@ module.exports = React.createClass({
const userLevels = powerLevels.users || {};
const powerLevelDescriptors = {
users_default: {
"users_default": {
desc: _t('The default role for new room members is'),
defaultValue: 0,
},
events_default: {
"events_default": {
desc: _t('To send messages, you must be a'),
defaultValue: 0,
},
invite: {
"invite": {
desc: _t('To invite users into the room, you must be a'),
defaultValue: 50,
},
state_default: {
"state_default": {
desc: _t('To configure the room, you must be a'),
defaultValue: 50,
},
kick: {
"kick": {
desc: _t('To kick users, you must be a'),
defaultValue: 50,
},
ban: {
"ban": {
desc: _t('To ban users, you must be a'),
defaultValue: 50,
},
redact: {
"redact": {
desc: _t('To remove other users\' messages, you must be a'),
defaultValue: 50,
},
@ -942,6 +947,11 @@ module.exports = React.createClass({
</AccessibleButton>;
}
const devtoolsButton = SettingsStore.getValue("showDeveloperTools") ?
(<AccessibleButton className="mx_RoomSettings_devtoolsButton" onClick={this._openDevtools}>
{ _t("Open Devtools") }
</AccessibleButton>) : null;
return (
<div className="mx_RoomSettings">
@ -1055,6 +1065,7 @@ module.exports = React.createClass({
{ _t('Internal room ID: ') } <code>{ this.props.room.roomId }</code><br />
{ _t('Room version number: ') } <code>{ this.props.room.getVersion() }</code><br />
{ roomUpgradeButton }
{ devtoolsButton }
</div>
</div>
);