Merge remote-tracking branch 'origin/develop' into travis/settings-cleanup-1

This commit is contained in:
Travis Ralston 2019-02-25 09:40:50 -07:00
commit 4801b25f77
16 changed files with 111 additions and 93 deletions

View file

@ -249,12 +249,6 @@ textarea {
box-shadow: none;
}
/* View Source Dialog overide */
.mx_Dialog_wrapper.mx_Dialog_viewsource .mx_Dialog {
padding-left: 10px;
padding-right: 10px;
}
.mx_Dialog {
background-color: $primary-bg-color;
color: $light-fg-color;

View file

@ -14,6 +14,19 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_ViewSource_label_left {
float: left;
}
.mx_ViewSource_label_right {
float: right;
}
.mx_ViewSource_label_bottom {
clear: both;
border-bottom: 1px solid #e5e5e5;
}
.mx_ViewSource pre {
text-align: left;
font-size: 12px;

View file

@ -40,6 +40,7 @@ limitations under the License.
}
.mx_WhoIsTypingTile_remainingAvatarPlaceholder {
position: relative;
display: inline-block;
color: #acacac;
background-color: #ddd;

View file

@ -113,4 +113,29 @@ export default class BasePlatform {
reload() {
throw new Error("reload not implemented!");
}
supportsAutoLaunch(): boolean {
return false;
}
// XXX: Surely this should be a setting like any other?
async getAutoLaunchEnabled(): boolean {
return false;
}
async setAutoLaunchEnabled(enabled: boolean): void {
throw new Error("Unimplemented");
}
supportsMinimizeToTray(): boolean {
return false;
}
async getMinimizeToTrayEnabled(): boolean {
return false;
}
async setMinimizeToTrayEnabled(enabled: boolean): void {
throw new Error("Unimplemented");
}
}

View file

@ -34,6 +34,7 @@ import GroupStore from '../../stores/GroupStore';
import FlairStore from '../../stores/FlairStore';
import { showGroupAddRoomDialog } from '../../GroupAddressPicker';
import {makeGroupPermalink, makeUserPermalink} from "../../matrix-to";
import {Group} from "matrix-js-sdk";
const LONG_DESC_PLACEHOLDER = _td(
`<h1>HTML for your community's page</h1>
@ -569,7 +570,7 @@ export default React.createClass({
_onShareClick: function() {
const ShareDialog = sdk.getComponent("dialogs.ShareDialog");
Modal.createTrackedDialog('share community dialog', '', ShareDialog, {
target: this._matrixClient.getGroup(this.props.groupId),
target: this._matrixClient.getGroup(this.props.groupId) || new Group(this.props.groupId),
});
},

View file

@ -26,6 +26,7 @@ import dis from '../../dispatcher';
import VectorConferenceHandler from '../../VectorConferenceHandler';
import TagPanelButtons from './TagPanelButtons';
import SettingsStore from '../../settings/SettingsStore';
import {_t} from "../../languageHandler";
const LeftPanel = React.createClass({
@ -212,6 +213,7 @@ const LeftPanel = React.createClass({
);
const searchBox = (<SearchBox
placeholder={ _t('Filter room names') }
onSearch={ this.onSearch }
onCleared={ this.onSearchCleared }
collapsed={this.props.collapsed} />);

View file

@ -537,12 +537,12 @@ module.exports = React.createClass({
case 'picture_snapshot':
this.uploadFile(payload.file);
break;
case 'notifier_enabled':
case 'upload_failed':
// 413: File was too big or upset the server in some way.
if(payload.error.http_status === 413) {
if (payload.error && payload.error.http_status === 413) {
this._fetchMediaConfig(true);
}
case 'notifier_enabled':
case 'upload_started':
case 'upload_finished':
this.forceUpdate();
@ -1305,7 +1305,10 @@ module.exports = React.createClass({
},
onSearchClick: function() {
this.setState({ searching: true, showingPinned: false });
this.setState({
searching: !this.state.searching,
showingPinned: false,
});
},
onCancelSearchClick: function() {

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,12 +15,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
import React from 'react';
import { _t } from '../../languageHandler';
import PropTypes from 'prop-types';
import { KeyCode } from '../../Keyboard';
import sdk from '../../index';
import dis from '../../dispatcher';
import { throttle } from 'lodash';
import AccessibleButton from '../../components/views/elements/AccessibleButton';
@ -28,8 +26,10 @@ module.exports = React.createClass({
displayName: 'SearchBox',
propTypes: {
onSearch: React.PropTypes.func,
onCleared: React.PropTypes.func,
onSearch: PropTypes.func,
onCleared: PropTypes.func,
className: PropTypes.string,
placeholder: PropTypes.string.isRequired,
},
getInitialState: function() {
@ -102,21 +102,22 @@ module.exports = React.createClass({
const clearButton = this.state.searchTerm.length > 0 ?
(<AccessibleButton key="button"
className="mx_SearchBox_closeButton"
onClick={ () => {this._clearSearch("button")} }>
</AccessibleButton>) : undefined;
onClick={ () => {this._clearSearch("button"); } }>
</AccessibleButton>) : undefined;
const className = this.props.className || "";
return (
<div className="mx_SearchBox mx_textinput">
<input
key="searchfield"
type="text"
ref="search"
className="mx_textinput_icon mx_textinput_search"
className={"mx_textinput_icon mx_textinput_search " + className}
value={ this.state.searchTerm }
onFocus={ this._onFocus }
onChange={ this.onChange }
onKeyDown={ this._onKeyDown }
placeholder={ _t('Filter room names') }
placeholder={ this.props.placeholder }
/>
{ clearButton }
</div>

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,11 +15,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
import React from 'react';
import PropTypes from 'prop-types';
import SyntaxHighlight from '../views/elements/SyntaxHighlight';
import {_t} from "../../languageHandler";
import sdk from "../../index";
module.exports = React.createClass({
@ -27,31 +28,24 @@ module.exports = React.createClass({
propTypes: {
content: PropTypes.object.isRequired,
onFinished: PropTypes.func.isRequired,
},
componentDidMount: function() {
document.addEventListener("keydown", this.onKeyDown);
},
componentWillUnmount: function() {
document.removeEventListener("keydown", this.onKeyDown);
},
onKeyDown: function(ev) {
if (ev.keyCode == 27) { // escape
ev.stopPropagation();
ev.preventDefault();
this.props.onFinished();
}
roomId: PropTypes.string.isRequired,
eventId: PropTypes.string.isRequired,
},
render: function() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
return (
<div className="mx_ViewSource">
<SyntaxHighlight className="json">
{ JSON.stringify(this.props.content, null, 2) }
</SyntaxHighlight>
</div>
<BaseDialog className="mx_ViewSource" onFinished={this.props.onFinished} title={_t('View Source')}>
<div className="mx_ViewSource_label_left">Room ID: { this.props.roomId }</div>
<div className="mx_ViewSource_label_right">Event ID: { this.props.eventId }</div>
<div className="mx_ViewSource_label_bottom" />
<div className="mx_Dialog_content">
<SyntaxHighlight className="json">
{ JSON.stringify(this.props.content, null, 2) }
</SyntaxHighlight>
</div>
</BaseDialog>
);
},
});

View file

@ -66,7 +66,7 @@ module.exports = React.createClass({
}
const scriptTag = document.createElement('script');
scriptTag.setAttribute(
'src', `${protocol}//www.google.com/recaptcha/api.js?onload=mx_on_recaptcha_loaded&render=explicit`,
'src', `${protocol}//www.recaptcha.net/recaptcha/api.js?onload=mx_on_recaptcha_loaded&render=explicit`,
);
this.refs.recaptchaContainer.appendChild(scriptTag);
}

View file

@ -98,6 +98,8 @@ module.exports = React.createClass({
onViewSourceClick: function() {
const ViewSource = sdk.getComponent('structures.ViewSource');
Modal.createTrackedDialog('View Event Source', '', ViewSource, {
roomId: this.props.mxEvent.getRoomId(),
eventId: this.props.mxEvent.getId(),
content: this.props.mxEvent.event,
}, 'mx_Dialog_viewsource');
this.closeMenu();
@ -106,6 +108,8 @@ module.exports = React.createClass({
onViewClearSourceClick: function() {
const ViewSource = sdk.getComponent('structures.ViewSource');
Modal.createTrackedDialog('View Clear Event Source', '', ViewSource, {
roomId: this.props.mxEvent.getRoomId(),
eventId: this.props.mxEvent.getId(),
// FIXME: _clearEvent is private
content: this.props.mxEvent._clearEvent,
}, 'mx_Dialog_viewsource');
@ -211,7 +215,8 @@ module.exports = React.createClass({
},
render: function() {
const eventStatus = this.props.mxEvent.status;
const mxEvent = this.props.mxEvent;
const eventStatus = mxEvent.status;
let resendButton;
let redactButton;
let cancelButton;
@ -251,8 +256,8 @@ module.exports = React.createClass({
);
}
if (isSent && this.props.mxEvent.getType() === 'm.room.message') {
const content = this.props.mxEvent.getContent();
if (isSent && mxEvent.getType() === 'm.room.message') {
const content = mxEvent.getContent();
if (content.msgtype && content.msgtype !== 'm.bad.encrypted' && content.hasOwnProperty('body')) {
forwardButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onForwardClick}>
@ -282,7 +287,7 @@ module.exports = React.createClass({
</div>
);
if (this.props.mxEvent.getType() !== this.props.mxEvent.getWireType()) {
if (mxEvent.getType() !== mxEvent.getWireType()) {
viewClearSourceButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onViewClearSourceClick}>
{ _t('View Decrypted Source') }
@ -303,8 +308,11 @@ module.exports = React.createClass({
// XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID)
const permalinkButton = (
<div className="mx_MessageContextMenu_field">
<a href={makeEventPermalink(this.props.mxEvent.getRoomId(), this.props.mxEvent.getId())}
target="_blank" rel="noopener" onClick={this.onPermalinkClick}>{ _t('Share Message') }</a>
<a href={makeEventPermalink(mxEvent.getRoomId(), mxEvent.getId())}
target="_blank" rel="noopener" onClick={this.onPermalinkClick}>
{ mxEvent.isRedacted() || mxEvent.getType() !== 'm.room.message'
? _t('Share Permalink') : _t('Share Message') }
</a>
</div>
);
@ -318,12 +326,12 @@ module.exports = React.createClass({
// Bridges can provide a 'external_url' to link back to the source.
if (
typeof(this.props.mxEvent.event.content.external_url) === "string" &&
isUrlPermitted(this.props.mxEvent.event.content.external_url)
typeof(mxEvent.event.content.external_url) === "string" &&
isUrlPermitted(mxEvent.event.content.external_url)
) {
externalURLButton = (
<div className="mx_MessageContextMenu_field">
<a href={this.props.mxEvent.event.content.external_url}
<a href={mxEvent.event.content.external_url}
rel="noopener" target="_blank" onClick={this.closeMenu}>{ _t('Source URL') }</a>
</div>
);

View file

@ -321,6 +321,9 @@ module.exports = withMatrixClient(React.createClass({
const {tile, replyThread} = this.refs;
let e2eInfoCallback = null;
if (this.props.mxEvent.isEncrypted()) e2eInfoCallback = () => this.onCryptoClicked();
ContextualMenu.createMenu(MessageContextMenu, {
chevronOffset: 10,
mxEvent: this.props.mxEvent,
@ -328,7 +331,7 @@ module.exports = withMatrixClient(React.createClass({
top: y,
eventTileOps: tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined,
collapseReplyThread: replyThread && replyThread.canCollapse() ? replyThread.collapse : undefined,
e2eInfoCallback: () => this.onCryptoClicked(),
e2eInfoCallback: e2eInfoCallback,
onFinished: function() {
self.setState({menu: false});
},

View file

@ -339,12 +339,11 @@ module.exports = React.createClass({
return nameA.localeCompare(nameB);
},
onSearchQueryChanged: function(ev) {
const q = ev.target.value;
onSearchQueryChanged: function(searchQuery) {
this.setState({
searchQuery: q,
filteredJoinedMembers: this._filterMembers(this.state.members, 'join', q),
filteredInvitedMembers: this._filterMembers(this.state.members, 'invite', q),
searchQuery,
filteredJoinedMembers: this._filterMembers(this.state.members, 'join', searchQuery),
filteredInvitedMembers: this._filterMembers(this.state.members, 'invite', searchQuery),
});
},
@ -438,6 +437,7 @@ module.exports = React.createClass({
return <div className="mx_MemberList"><Spinner /></div>;
}
const SearchBox = sdk.getComponent('structures.SearchBox');
const TruncatedList = sdk.getComponent("elements.TruncatedList");
const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper");
@ -445,7 +445,6 @@ module.exports = React.createClass({
const room = cli.getRoom(this.props.roomId);
let inviteButton;
if (room && room.getMyMembership() === 'join') {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
inviteButton =
<AccessibleButton className="mx_MemberList_invite" onClick={this.onInviteButtonClick}>
@ -477,9 +476,10 @@ module.exports = React.createClass({
{ invitedSection }
</div>
</GeminiScrollbarWrapper>
<input className="mx_MemberList_query mx_textinput_icon mx_textinput_search" id="mx_MemberList_query" type="text"
onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
placeholder={_t('Filter room members')} />
<SearchBox className="mx_MemberList_query mx_textinput_icon mx_textinput_search"
placeholder={ _t('Filter room members') }
onSearch={ this.onSearchQueryChanged } />
</div>
);
},

View file

@ -362,34 +362,6 @@ export default class MessageComposer extends React.Component {
const canSendMessages = !this.state.tombstone &&
this.props.room.maySendMessage();
// TODO: Remove temporary logging for riot-web#7838
// Note: we rip apart the power level event ourselves because we don't want to
// log too much data about it - just the bits we care about. Many of the variables
// logged here are to help figure out where in the stack the 'cannot post in room'
// warning is coming from. This means logging various numbers from the PL event to
// verify RoomState._maySendEventOfType is doing the right thing.
const room = this.props.room;
const plEvent = room.currentState.getStateEvents('m.room.power_levels', '');
let plEventString = "<no power level event>";
if (plEvent) {
const content = plEvent.getContent();
if (!content) {
plEventString = "<no event content>";
} else {
const stringifyFalsey = (v) => v === null ? '<null>' : (v === undefined ? '<undefined>' : v);
const actualUserPl = stringifyFalsey(content.users ? content.users[room.myUserId] : "<no users in content>");
const usersPl = stringifyFalsey(content.users_default);
const actualEventPl = stringifyFalsey(content.events ? content.events['m.room.message'] : "<no events in content>");
const eventPl = stringifyFalsey(content.events_default);
plEventString = `actualUserPl=${actualUserPl} defaultUserPl=${usersPl} actualEventPl=${actualEventPl} defaultEventPl=${eventPl}`;
}
}
console.log(
`[riot-web#7838] renderComposer() hasTombstone=${!!this.state.tombstone} maySendMessage=${room.maySendMessage()}` +
` myMembership=${room.getMyMembership()} maySendEvent=${room.currentState.maySendEvent('m.room.message', room.myUserId)}` +
` myUserId=${room.myUserId} roomId=${room.roomId} hasPlEvent=${!!plEvent} powerLevels='${plEventString}'`
);
if (canSendMessages) {
// This also currently includes the call buttons. Really we should
// check separately for whether we can call, but this is slightly
@ -469,8 +441,6 @@ export default class MessageComposer extends React.Component {
</div>
</div>);
} else {
// TODO: Remove temporary logging for riot-web#7838
console.log("[riot-web#7838] Falling back to showing cannot post in room error");
controls.push(
<div key="controls_error" className="mx_MessageComposer_noperm_error">
{ _t('You do not have permission to post to this room') }

View file

@ -170,6 +170,7 @@ module.exports = React.createClass({
width={24}
height={24}
resizeMethod="crop"
viewUserOnClick={true}
/>
);
});

View file

@ -540,6 +540,7 @@
"Labs": "Labs",
"Notifications": "Notifications",
"Start automatically after system login": "Start automatically after system login",
"Close button should minimize window to tray": "Close button should minimize window to tray",
"Preferences": "Preferences",
"Composer": "Composer",
"Timeline": "Timeline",
@ -1202,6 +1203,7 @@
"View Decrypted Source": "View Decrypted Source",
"Unhide Preview": "Unhide Preview",
"Share Message": "Share Message",
"Share Permalink": "Share Permalink",
"Quote": "Quote",
"Source URL": "Source URL",
"Collapse Reply Thread": "Collapse Reply Thread",