mirror of
https://github.com/element-hq/element-web
synced 2024-11-27 11:47:23 +03:00
Merge branch 'develop' into travis/granular
This commit is contained in:
commit
69939e2fe3
21 changed files with 697 additions and 229 deletions
|
@ -22,7 +22,7 @@ import classNames from 'classnames';
|
||||||
import { _t } from 'matrix-react-sdk/lib/languageHandler';
|
import { _t } from 'matrix-react-sdk/lib/languageHandler';
|
||||||
import sdk from 'matrix-react-sdk';
|
import sdk from 'matrix-react-sdk';
|
||||||
import dis from 'matrix-react-sdk/lib/dispatcher';
|
import dis from 'matrix-react-sdk/lib/dispatcher';
|
||||||
import MatrixClient from 'matrix-js-sdk';
|
import { MatrixClient } from 'matrix-js-sdk';
|
||||||
import Analytics from 'matrix-react-sdk/lib/Analytics';
|
import Analytics from 'matrix-react-sdk/lib/Analytics';
|
||||||
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';
|
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';
|
||||||
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
|
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
|
||||||
|
@ -90,6 +90,7 @@ module.exports = React.createClass({
|
||||||
RoomMemberList: 'RoomMemberList',
|
RoomMemberList: 'RoomMemberList',
|
||||||
GroupMemberList: 'GroupMemberList',
|
GroupMemberList: 'GroupMemberList',
|
||||||
GroupRoomList: 'GroupRoomList',
|
GroupRoomList: 'GroupRoomList',
|
||||||
|
GroupRoomInfo: 'GroupRoomInfo',
|
||||||
FilePanel: 'FilePanel',
|
FilePanel: 'FilePanel',
|
||||||
NotificationPanel: 'NotificationPanel',
|
NotificationPanel: 'NotificationPanel',
|
||||||
RoomMemberInfo: 'RoomMemberInfo',
|
RoomMemberInfo: 'RoomMemberInfo',
|
||||||
|
@ -205,7 +206,6 @@ module.exports = React.createClass({
|
||||||
} else if (this.props.groupId) {
|
} else if (this.props.groupId) {
|
||||||
this.setState({
|
this.setState({
|
||||||
phase: this.Phase.GroupMemberList,
|
phase: this.Phase.GroupMemberList,
|
||||||
groupId: payload.groupId,
|
|
||||||
member: payload.member,
|
member: payload.member,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -213,13 +213,20 @@ module.exports = React.createClass({
|
||||||
} else if (payload.action === "view_group") {
|
} else if (payload.action === "view_group") {
|
||||||
this.setState({
|
this.setState({
|
||||||
phase: this.Phase.GroupMemberList,
|
phase: this.Phase.GroupMemberList,
|
||||||
groupId: payload.groupId,
|
|
||||||
member: null,
|
member: null,
|
||||||
});
|
});
|
||||||
|
} else if (payload.action === "view_group_room") {
|
||||||
|
this.setState({
|
||||||
|
phase: this.Phase.GroupRoomInfo,
|
||||||
|
groupRoomId: payload.groupRoomId,
|
||||||
|
});
|
||||||
|
} else if (payload.action === "view_group_room_list") {
|
||||||
|
this.setState({
|
||||||
|
phase: this.Phase.GroupRoomList,
|
||||||
|
});
|
||||||
} else if (payload.action === "view_group_user") {
|
} else if (payload.action === "view_group_user") {
|
||||||
this.setState({
|
this.setState({
|
||||||
phase: this.Phase.GroupMemberInfo,
|
phase: this.Phase.GroupMemberInfo,
|
||||||
groupId: payload.groupId,
|
|
||||||
member: payload.member,
|
member: payload.member,
|
||||||
});
|
});
|
||||||
} else if (payload.action === "view_room") {
|
} else if (payload.action === "view_room") {
|
||||||
|
@ -242,6 +249,7 @@ module.exports = React.createClass({
|
||||||
const GroupMemberList = sdk.getComponent('groups.GroupMemberList');
|
const GroupMemberList = sdk.getComponent('groups.GroupMemberList');
|
||||||
const GroupMemberInfo = sdk.getComponent('groups.GroupMemberInfo');
|
const GroupMemberInfo = sdk.getComponent('groups.GroupMemberInfo');
|
||||||
const GroupRoomList = sdk.getComponent('groups.GroupRoomList');
|
const GroupRoomList = sdk.getComponent('groups.GroupRoomList');
|
||||||
|
const GroupRoomInfo = sdk.getComponent('groups.GroupRoomInfo');
|
||||||
|
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||||
|
|
||||||
|
@ -305,7 +313,7 @@ module.exports = React.createClass({
|
||||||
analytics={['Right Panel', 'Group Member List Button', 'click']}
|
analytics={['Right Panel', 'Group Member List Button', 'click']}
|
||||||
/>,
|
/>,
|
||||||
<HeaderButton key="_roomsButton" title={_t('Rooms')} iconSrc="img/icons-room.svg"
|
<HeaderButton key="_roomsButton" title={_t('Rooms')} iconSrc="img/icons-room.svg"
|
||||||
isHighlighted={this.state.phase === this.Phase.GroupRoomList}
|
isHighlighted={[this.Phase.GroupRoomList, this.Phase.GroupRoomInfo].includes(this.state.phase)}
|
||||||
clickPhase={this.Phase.GroupRoomList}
|
clickPhase={this.Phase.GroupRoomList}
|
||||||
analytics={['Right Panel', 'Group Room List Button', 'click']}
|
analytics={['Right Panel', 'Group Room List Button', 'click']}
|
||||||
/>,
|
/>,
|
||||||
|
@ -340,6 +348,11 @@ module.exports = React.createClass({
|
||||||
groupMember={this.state.member}
|
groupMember={this.state.member}
|
||||||
groupId={this.props.groupId}
|
groupId={this.props.groupId}
|
||||||
key={this.state.member.user_id} />;
|
key={this.state.member.user_id} />;
|
||||||
|
} else if (this.state.phase == this.Phase.GroupRoomInfo) {
|
||||||
|
panel = <GroupRoomInfo
|
||||||
|
groupRoomId={this.state.groupRoomId}
|
||||||
|
groupId={this.props.groupId}
|
||||||
|
key={this.state.groupRoomId} />;
|
||||||
} else if (this.state.phase == this.Phase.NotificationPanel) {
|
} else if (this.state.phase == this.Phase.NotificationPanel) {
|
||||||
panel = <NotificationPanel />;
|
panel = <NotificationPanel />;
|
||||||
} else if (this.state.phase == this.Phase.FilePanel) {
|
} else if (this.state.phase == this.Phase.FilePanel) {
|
||||||
|
|
|
@ -409,7 +409,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
perms = null;
|
perms = null;
|
||||||
if (guestRead || guestJoin) {
|
if (guestRead || guestJoin) {
|
||||||
perms = <div className="mx_RoomDirectory_perms">{guestRead} {guestJoin}</div>;
|
perms = <div className="mx_RoomDirectory_perms">{guestRead}{guestJoin}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
var topic = rooms[i].topic || '';
|
var topic = rooms[i].topic || '';
|
||||||
|
|
|
@ -246,10 +246,14 @@ var RoomSubList = React.createClass({
|
||||||
roomNotificationCount: function(truncateAt) {
|
roomNotificationCount: function(truncateAt) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
if (this.props.isInvite) {
|
||||||
|
return [0, true];
|
||||||
|
}
|
||||||
|
|
||||||
return this.props.list.reduce(function(result, room, index) {
|
return this.props.list.reduce(function(result, room, index) {
|
||||||
if (truncateAt === undefined || index >= truncateAt) {
|
if (truncateAt === undefined || index >= truncateAt) {
|
||||||
var roomNotifState = RoomNotifs.getRoomNotifsState(room.roomId);
|
var roomNotifState = RoomNotifs.getRoomNotifsState(room.roomId);
|
||||||
var highlight = room.getUnreadNotificationCount('highlight') > 0 || self.props.isInvite;
|
var highlight = room.getUnreadNotificationCount('highlight') > 0;
|
||||||
var notificationCount = room.getUnreadNotificationCount();
|
var notificationCount = room.getUnreadNotificationCount();
|
||||||
|
|
||||||
const notifBadges = notificationCount > 0 && self._shouldShowNotifBadge(roomNotifState);
|
const notifBadges = notificationCount > 0 && self._shouldShowNotifBadge(roomNotifState);
|
||||||
|
@ -394,7 +398,8 @@ var RoomSubList = React.createClass({
|
||||||
var subListNotifCount = subListNotifications[0];
|
var subListNotifCount = subListNotifications[0];
|
||||||
var subListNotifHighlight = subListNotifications[1];
|
var subListNotifHighlight = subListNotifications[1];
|
||||||
|
|
||||||
var roomCount = this.props.list.length > 0 ? this.props.list.length : '';
|
var totalTiles = this.props.list.length + (this.props.extraTiles || []).length;
|
||||||
|
var roomCount = totalTiles > 0 ? totalTiles : '';
|
||||||
|
|
||||||
var chevronClasses = classNames({
|
var chevronClasses = classNames({
|
||||||
'mx_RoomSubList_chevron': true,
|
'mx_RoomSubList_chevron': true,
|
||||||
|
|
|
@ -15,35 +15,24 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import sdk from 'matrix-react-sdk';
|
import sdk from 'matrix-react-sdk';
|
||||||
import { _t } from 'matrix-react-sdk/lib/languageHandler';
|
import { _t } from 'matrix-react-sdk/lib/languageHandler';
|
||||||
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
||||||
|
|
||||||
class SendCustomEvent extends React.Component {
|
class DevtoolsComponent extends React.Component {
|
||||||
static propTypes = {
|
static contextTypes = {
|
||||||
roomId: React.PropTypes.string.isRequired,
|
roomId: PropTypes.string.isRequired,
|
||||||
onBack: React.PropTypes.func.isRequired,
|
|
||||||
|
|
||||||
eventType: React.PropTypes.string.isRequired,
|
|
||||||
evContent: React.PropTypes.string.isRequired,
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
class GenericEditor extends DevtoolsComponent {
|
||||||
eventType: '',
|
// static propTypes = {onBack: PropTypes.func.isRequired};
|
||||||
evContent: '{\n\n}',
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
this._send = this._send.bind(this);
|
|
||||||
this.onBack = this.onBack.bind(this);
|
|
||||||
this._onChange = this._onChange.bind(this);
|
this._onChange = this._onChange.bind(this);
|
||||||
|
this.onBack = this.onBack.bind(this);
|
||||||
this.state = {
|
|
||||||
message: null,
|
|
||||||
input_eventType: this.props.eventType,
|
|
||||||
input_evContent: this.props.evContent,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onBack() {
|
onBack() {
|
||||||
|
@ -54,6 +43,10 @@ class SendCustomEvent extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onChange(e) {
|
||||||
|
this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value});
|
||||||
|
}
|
||||||
|
|
||||||
_buttons() {
|
_buttons() {
|
||||||
return <div className="mx_Dialog_buttons">
|
return <div className="mx_Dialog_buttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
@ -61,19 +54,64 @@ class SendCustomEvent extends React.Component {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textInput(id, label) {
|
||||||
|
return <div className="mx_DevTools_inputRow">
|
||||||
|
<div className="mx_DevTools_inputLabelCell">
|
||||||
|
<label htmlFor={id}>{ label }</label>
|
||||||
|
</div>
|
||||||
|
<div className="mx_DevTools_inputCell">
|
||||||
|
<input id={id} onChange={this._onChange} value={this.state[id]} size="32" />
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendCustomEvent extends GenericEditor {
|
||||||
|
static getLabel() { return _t('Send Custom Event'); }
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onBack: PropTypes.func.isRequired,
|
||||||
|
forceStateEvent: PropTypes.bool,
|
||||||
|
inputs: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this._send = this._send.bind(this);
|
||||||
|
|
||||||
|
const {eventType, stateKey, evContent} = Object.assign({
|
||||||
|
eventType: '',
|
||||||
|
stateKey: '',
|
||||||
|
evContent: '{\n\n}',
|
||||||
|
}, this.props.inputs);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isStateEvent: Boolean(this.props.forceStateEvent),
|
||||||
|
|
||||||
|
eventType,
|
||||||
|
stateKey,
|
||||||
|
evContent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
send(content) {
|
send(content) {
|
||||||
return MatrixClientPeg.get().sendEvent(this.props.roomId, this.state.input_eventType, content);
|
const cli = MatrixClientPeg.get();
|
||||||
|
if (this.state.isStateEvent) {
|
||||||
|
return cli.sendStateEvent(this.context.roomId, this.state.eventType, content, this.state.stateKey);
|
||||||
|
} else {
|
||||||
|
return cli.sendEvent(this.context.roomId, this.state.eventType, content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _send() {
|
async _send() {
|
||||||
if (this.state.input_eventType === '') {
|
if (this.state.eventType === '') {
|
||||||
this.setState({ message: _t('You must specify an event type!') });
|
this.setState({ message: _t('You must specify an event type!') });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let message;
|
let message;
|
||||||
try {
|
try {
|
||||||
const content = JSON.parse(this.state.input_evContent);
|
const content = JSON.parse(this.state.evContent);
|
||||||
await this.send(content);
|
await this.send(content);
|
||||||
message = _t('Event sent!');
|
message = _t('Event sent!');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -82,14 +120,6 @@ class SendCustomEvent extends React.Component {
|
||||||
this.setState({ message });
|
this.setState({ message });
|
||||||
}
|
}
|
||||||
|
|
||||||
_additionalFields() {
|
|
||||||
return <div />;
|
|
||||||
}
|
|
||||||
|
|
||||||
_onChange(e) {
|
|
||||||
this.setState({[`input_${e.target.id}`]: e.target.value});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.message) {
|
if (this.state.message) {
|
||||||
return <div>
|
return <div>
|
||||||
|
@ -102,87 +132,176 @@ class SendCustomEvent extends React.Component {
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
{ this._additionalFields() }
|
{ this.textInput('eventType', _t('Event Type')) }
|
||||||
<div className="mx_TextInputDialog_label">
|
{ this.state.isStateEvent && this.textInput('stateKey', _t('State Key')) }
|
||||||
<label htmlFor="eventType"> { _t('Event Type') } </label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input id="eventType" onChange={this._onChange} value={this.state.input_eventType} className="mx_TextInputDialog_input" size="64" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mx_TextInputDialog_label">
|
<br />
|
||||||
|
|
||||||
|
<div className="mx_UserSettings_profileLabelCell">
|
||||||
<label htmlFor="evContent"> { _t('Event Content') } </label>
|
<label htmlFor="evContent"> { _t('Event Content') } </label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<textarea id="evContent" onChange={this._onChange} value={this.state.input_evContent} className="mx_TextInputDialog_input" cols="63" rows="5" />
|
<textarea id="evContent" onChange={this._onChange} value={this.state.evContent} className="mx_TextInputDialog_input" cols="63" rows="5" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ this._buttons() }
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
{ !this.state.message && <button onClick={this._send}>{ _t('Send') }</button> }
|
||||||
|
{ !this.state.message && !this.props.forceStateEvent && <div style={{float: "right"}}>
|
||||||
|
<input id="isStateEvent" className="mx_DevTools_tgl mx_DevTools_tgl-flip" type="checkbox" onChange={this._onChange} checked={this.state.isStateEvent} />
|
||||||
|
<label className="mx_DevTools_tgl-btn" data-tg-off="Event" data-tg-on="State Event" htmlFor="isStateEvent" />
|
||||||
|
</div> }
|
||||||
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SendCustomStateEvent extends SendCustomEvent {
|
class SendAccountData extends GenericEditor {
|
||||||
|
static getLabel() { return _t('Send Account Data'); }
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
roomId: React.PropTypes.string.isRequired,
|
isRoomAccountData: PropTypes.bool,
|
||||||
onBack: React.PropTypes.func.isRequired,
|
forceMode: PropTypes.bool,
|
||||||
|
inputs: PropTypes.object,
|
||||||
eventType: React.PropTypes.string.isRequired,
|
|
||||||
evContent: React.PropTypes.string.isRequired,
|
|
||||||
stateKey: React.PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
eventType: '',
|
|
||||||
evContent: '{\n\n}',
|
|
||||||
stateKey: '',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
this.state['input_stateKey'] = this.props.stateKey;
|
this._send = this._send.bind(this);
|
||||||
|
|
||||||
|
const {eventType, evContent} = Object.assign({
|
||||||
|
eventType: '',
|
||||||
|
evContent: '{\n\n}',
|
||||||
|
}, this.props.inputs);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isRoomAccountData: Boolean(this.props.isRoomAccountData),
|
||||||
|
|
||||||
|
eventType,
|
||||||
|
evContent,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
send(content) {
|
send(content) {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
return cli.sendStateEvent(this.props.roomId, this.state.input_eventType, content, this.state.input_stateKey);
|
if (this.state.isRoomAccountData) {
|
||||||
|
return cli.setRoomAccountData(this.context.roomId, this.state.eventType, content);
|
||||||
|
}
|
||||||
|
return cli.setAccountData(this.state.eventType, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
_additionalFields() {
|
async _send() {
|
||||||
|
if (this.state.eventType === '') {
|
||||||
|
this.setState({ message: _t('You must specify an event type!') });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message;
|
||||||
|
try {
|
||||||
|
const content = JSON.parse(this.state.evContent);
|
||||||
|
await this.send(content);
|
||||||
|
message = _t('Event sent!');
|
||||||
|
} catch (e) {
|
||||||
|
message = _t('Failed to send custom event.') + ' (' + e.toString() + ')';
|
||||||
|
}
|
||||||
|
this.setState({ message });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.message) {
|
||||||
|
return <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
{ this.state.message }
|
||||||
|
</div>
|
||||||
|
{ this._buttons() }
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<div className="mx_TextInputDialog_label">
|
<div className="mx_Dialog_content">
|
||||||
<label htmlFor="stateKey"> { _t('State Key') } </label>
|
{ this.textInput('eventType', _t('Event Type')) }
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div className="mx_UserSettings_profileLabelCell">
|
||||||
|
<label htmlFor="evContent"> { _t('Event Content') } </label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<textarea id="evContent" onChange={this._onChange} value={this.state.evContent} className="mx_TextInputDialog_input" cols="63" rows="5" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="mx_Dialog_buttons">
|
||||||
<input id="stateKey" onChange={this._onChange} value={this.state.input_stateKey} className="mx_TextInputDialog_input" size="64" />
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
{ !this.state.message && <button onClick={this._send}>{ _t('Send') }</button> }
|
||||||
|
{ !this.state.message && <div style={{float: "right"}}>
|
||||||
|
<input id="isRoomAccountData" className="mx_DevTools_tgl mx_DevTools_tgl-flip" type="checkbox" onChange={this._onChange} checked={this.state.isRoomAccountData} disabled={this.props.forceMode} />
|
||||||
|
<label className="mx_DevTools_tgl-btn" data-tg-off="Account Data" data-tg-on="Room Data" htmlFor="isRoomAccountData" />
|
||||||
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoomStateExplorer extends React.Component {
|
class FilteredList extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
setMode: React.PropTypes.func.isRequired,
|
children: PropTypes.any,
|
||||||
roomId: React.PropTypes.string.isRequired,
|
};
|
||||||
onBack: React.PropTypes.func.isRequired,
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.onQuery = this.onQuery.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
query: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onQuery(ev) {
|
||||||
|
this.setState({ query: ev.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChildren() {
|
||||||
|
if (this.state.query) {
|
||||||
|
const lowerQuery = this.state.query.toLowerCase();
|
||||||
|
return this.props.children.filter((child) => child.key.toLowerCase().includes(lowerQuery));
|
||||||
|
}
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <div>
|
||||||
|
<input size="64"
|
||||||
|
onChange={this.onQuery}
|
||||||
|
value={this.state.query}
|
||||||
|
placeholder={_t('Filter results')}
|
||||||
|
className="mx_TextInputDialog_input mx_DevTools_RoomStateExplorer_query" />
|
||||||
|
{ this.filterChildren() }
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoomStateExplorer extends DevtoolsComponent {
|
||||||
|
static getLabel() { return _t('Explore Room State'); }
|
||||||
|
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onBack: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
const room = MatrixClientPeg.get().getRoom(this.context.roomId);
|
||||||
this.roomStateEvents = room.currentState.events;
|
this.roomStateEvents = room.currentState.events;
|
||||||
|
|
||||||
this.onBack = this.onBack.bind(this);
|
this.onBack = this.onBack.bind(this);
|
||||||
this.editEv = this.editEv.bind(this);
|
this.editEv = this.editEv.bind(this);
|
||||||
this.onQuery = this.onQuery.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
state = {
|
this.state = {
|
||||||
query: '',
|
eventType: null,
|
||||||
eventType: null,
|
event: null,
|
||||||
event: null,
|
editing: false,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
browseEventType(eventType) {
|
browseEventType(eventType) {
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -197,7 +316,9 @@ class RoomStateExplorer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBack() {
|
onBack() {
|
||||||
if (this.state.event) {
|
if (this.state.editing) {
|
||||||
|
this.setState({ editing: false });
|
||||||
|
} else if (this.state.event) {
|
||||||
this.setState({ event: null });
|
this.setState({ event: null });
|
||||||
} else if (this.state.eventType) {
|
} else if (this.state.eventType) {
|
||||||
this.setState({ eventType: null });
|
this.setState({ eventType: null });
|
||||||
|
@ -207,20 +328,19 @@ class RoomStateExplorer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
editEv() {
|
editEv() {
|
||||||
const ev = this.state.event;
|
this.setState({ editing: true });
|
||||||
this.props.setMode(SendCustomStateEvent, {
|
|
||||||
eventType: ev.getType(),
|
|
||||||
evContent: JSON.stringify(ev.getContent(), null, '\t'),
|
|
||||||
stateKey: ev.getStateKey(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onQuery(ev) {
|
|
||||||
this.setState({ query: ev.target.value });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.event) {
|
if (this.state.event) {
|
||||||
|
if (this.state.editing) {
|
||||||
|
return <SendCustomEvent forceStateEvent={true} onBack={this.onBack} inputs={{
|
||||||
|
eventType: this.state.event.getType(),
|
||||||
|
evContent: JSON.stringify(this.state.event.getContent(), null, '\t'),
|
||||||
|
stateKey: this.state.event.getStateKey(),
|
||||||
|
}} />;
|
||||||
|
}
|
||||||
|
|
||||||
return <div className="mx_ViewSource">
|
return <div className="mx_ViewSource">
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
<pre>{ JSON.stringify(this.state.event.event, null, 2) }</pre>
|
<pre>{ JSON.stringify(this.state.event.event, null, 2) }</pre>
|
||||||
|
@ -234,11 +354,9 @@ class RoomStateExplorer extends React.Component {
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
|
|
||||||
|
const classes = 'mx_DevTools_RoomStateExplorer_button';
|
||||||
if (this.state.eventType === null) {
|
if (this.state.eventType === null) {
|
||||||
Object.keys(this.roomStateEvents).forEach((evType) => {
|
Object.keys(this.roomStateEvents).forEach((evType) => {
|
||||||
// Skip this entry if does not contain search query
|
|
||||||
if (this.state.query && !evType.toLowerCase().includes(this.state.query.toLowerCase())) return;
|
|
||||||
|
|
||||||
const stateGroup = this.roomStateEvents[evType];
|
const stateGroup = this.roomStateEvents[evType];
|
||||||
const stateKeys = Object.keys(stateGroup);
|
const stateKeys = Object.keys(stateGroup);
|
||||||
|
|
||||||
|
@ -249,7 +367,7 @@ class RoomStateExplorer extends React.Component {
|
||||||
onClickFn = this.onViewSourceClick(stateGroup[stateKeys[0]]);
|
onClickFn = this.onViewSourceClick(stateGroup[stateKeys[0]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.push(<button className="mx_DevTools_RoomStateExplorer_button" key={evType} onClick={onClickFn}>
|
rows.push(<button className={classes} key={evType} onClick={onClickFn}>
|
||||||
{ evType }
|
{ evType }
|
||||||
</button>);
|
</button>);
|
||||||
});
|
});
|
||||||
|
@ -257,12 +375,8 @@ class RoomStateExplorer extends React.Component {
|
||||||
const evType = this.state.eventType;
|
const evType = this.state.eventType;
|
||||||
const stateGroup = this.roomStateEvents[evType];
|
const stateGroup = this.roomStateEvents[evType];
|
||||||
Object.keys(stateGroup).forEach((stateKey) => {
|
Object.keys(stateGroup).forEach((stateKey) => {
|
||||||
// Skip this entry if does not contain search query
|
|
||||||
if (this.state.query && !stateKey.toLowerCase().includes(this.state.query.toLowerCase())) return;
|
|
||||||
|
|
||||||
const ev = stateGroup[stateKey];
|
const ev = stateGroup[stateKey];
|
||||||
rows.push(<button className="mx_DevTools_RoomStateExplorer_button" key={stateKey}
|
rows.push(<button className={classes} key={stateKey} onClick={this.onViewSourceClick(ev)}>
|
||||||
onClick={this.onViewSourceClick(ev)}>
|
|
||||||
{ stateKey }
|
{ stateKey }
|
||||||
</button>);
|
</button>);
|
||||||
});
|
});
|
||||||
|
@ -270,8 +384,9 @@ class RoomStateExplorer extends React.Component {
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
<input onChange={this.onQuery} placeholder={_t('Filter results')} size="64" className="mx_TextInputDialog_input mx_DevTools_RoomStateExplorer_query" value={this.state.query} />
|
<FilteredList>
|
||||||
{ rows }
|
{ rows }
|
||||||
|
</FilteredList>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
@ -280,40 +395,157 @@ class RoomStateExplorer extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class DevtoolsDialog extends React.Component {
|
class AccountDataExplorer extends DevtoolsComponent {
|
||||||
|
static getLabel() { return _t('Explore Account Data'); }
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
roomId: React.PropTypes.string.isRequired,
|
onBack: PropTypes.func.isRequired,
|
||||||
onFinished: React.PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
constructor(props, context) {
|
||||||
mode: null,
|
super(props, context);
|
||||||
modeArgs: {},
|
|
||||||
|
this.onBack = this.onBack.bind(this);
|
||||||
|
this.editEv = this.editEv.bind(this);
|
||||||
|
this._onChange = this._onChange.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isRoomAccountData: false,
|
||||||
|
event: null,
|
||||||
|
editing: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getData() {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
if (this.state.isRoomAccountData) {
|
||||||
|
return cli.getRoom(this.context.roomId).accountData;
|
||||||
|
}
|
||||||
|
return cli.store.accountData;
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewSourceClick(event) {
|
||||||
|
return () => {
|
||||||
|
this.setState({ event });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onBack() {
|
||||||
|
if (this.state.editing) {
|
||||||
|
this.setState({ editing: false });
|
||||||
|
} else if (this.state.event) {
|
||||||
|
this.setState({ event: null });
|
||||||
|
} else {
|
||||||
|
this.props.onBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onChange(e) {
|
||||||
|
this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value});
|
||||||
|
}
|
||||||
|
|
||||||
|
editEv() {
|
||||||
|
this.setState({ editing: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.event) {
|
||||||
|
if (this.state.editing) {
|
||||||
|
return <SendAccountData isRoomAccountData={this.state.isRoomAccountData} onBack={this.onBack} inputs={{
|
||||||
|
eventType: this.state.event.getType(),
|
||||||
|
evContent: JSON.stringify(this.state.event.getContent(), null, '\t'),
|
||||||
|
}} forceMode={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className="mx_ViewSource">
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<pre>{ JSON.stringify(this.state.event.event, null, 2) }</pre>
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
<button onClick={this.editEv}>{ _t('Edit') }</button>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = [];
|
||||||
|
|
||||||
|
const classes = 'mx_DevTools_RoomStateExplorer_button';
|
||||||
|
|
||||||
|
const data = this.getData();
|
||||||
|
Object.keys(data).forEach((evType) => {
|
||||||
|
const ev = data[evType];
|
||||||
|
rows.push(<button className={classes} key={evType} onClick={this.onViewSourceClick(ev)}>
|
||||||
|
{ evType }
|
||||||
|
</button>);
|
||||||
|
});
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<FilteredList>
|
||||||
|
{ rows }
|
||||||
|
</FilteredList>
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
{ !this.state.message && <div style={{float: "right"}}>
|
||||||
|
<input id="isRoomAccountData" className="mx_DevTools_tgl mx_DevTools_tgl-flip" type="checkbox" onChange={this._onChange} checked={this.state.isRoomAccountData} />
|
||||||
|
<label className="mx_DevTools_tgl-btn" data-tg-off="Account Data" data-tg-on="Room Data" htmlFor="isRoomAccountData" />
|
||||||
|
</div> }
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Entries = [
|
||||||
|
SendCustomEvent,
|
||||||
|
RoomStateExplorer,
|
||||||
|
SendAccountData,
|
||||||
|
AccountDataExplorer,
|
||||||
|
];
|
||||||
|
|
||||||
|
export default class DevtoolsDialog extends React.Component {
|
||||||
|
static childContextTypes = {
|
||||||
|
roomId: PropTypes.string.isRequired,
|
||||||
|
// client: PropTypes.instanceOf(MatixClient),
|
||||||
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
roomId: PropTypes.string.isRequired,
|
||||||
|
onFinished: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
this.onBack = this.onBack.bind(this);
|
this.onBack = this.onBack.bind(this);
|
||||||
this.setMode = this.setMode.bind(this);
|
|
||||||
this.onCancel = this.onCancel.bind(this);
|
this.onCancel = this.onCancel.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
mode: null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this._unmounted = true;
|
this._unmounted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getChildContext() {
|
||||||
|
return { roomId: this.props.roomId };
|
||||||
|
}
|
||||||
|
|
||||||
_setMode(mode) {
|
_setMode(mode) {
|
||||||
return () => {
|
return () => {
|
||||||
this.setMode(mode);
|
this.setState({ mode });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setMode(mode, modeArgs={}) {
|
|
||||||
this.setState({ mode, modeArgs });
|
|
||||||
}
|
|
||||||
|
|
||||||
onBack() {
|
onBack() {
|
||||||
this.setState({ mode: null });
|
if (this.prevMode) {
|
||||||
|
this.setState({ mode: this.prevMode });
|
||||||
|
this.prevMode = null;
|
||||||
|
} else {
|
||||||
|
this.setState({ mode: null });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onCancel() {
|
onCancel() {
|
||||||
|
@ -324,14 +556,27 @@ export default class DevtoolsDialog extends React.Component {
|
||||||
let body;
|
let body;
|
||||||
|
|
||||||
if (this.state.mode) {
|
if (this.state.mode) {
|
||||||
body =
|
|
||||||
<this.state.mode {...this.props} {...this.state.modeArgs} onBack={this.onBack} setMode={this.setMode} />;
|
|
||||||
} else {
|
|
||||||
body = <div>
|
body = <div>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_DevTools_label_left">{ this.state.mode.getLabel() }</div>
|
||||||
<button onClick={this._setMode(SendCustomEvent)}>{ _t('Send Custom Event') }</button>
|
<div className="mx_DevTools_label_right">Room ID: { this.props.roomId }</div>
|
||||||
<button onClick={this._setMode(SendCustomStateEvent)}>{ _t('Send Custom State Event') }</button>
|
<div className="mx_DevTools_label_bottom" />
|
||||||
<button onClick={this._setMode(RoomStateExplorer)}>{ _t('Explore Room State') }</button>
|
<this.state.mode onBack={this.onBack} />
|
||||||
|
</div>;
|
||||||
|
} else {
|
||||||
|
const classes = "mx_DevTools_RoomStateExplorer_button";
|
||||||
|
body = <div>
|
||||||
|
<div>
|
||||||
|
<div className="mx_DevTools_label_left">{ _t('Toolbox') }</div>
|
||||||
|
<div className="mx_DevTools_label_right">Room ID: { this.props.roomId }</div>
|
||||||
|
<div className="mx_DevTools_label_bottom" />
|
||||||
|
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
{ Entries.map((Entry) => {
|
||||||
|
const label = Entry.getLabel();
|
||||||
|
const onClick = this._setMode(Entry);
|
||||||
|
return <button className={classes} key={label} onClick={onClick}>{ label }</button>;
|
||||||
|
}) }
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={this.onCancel}>{ _t('Cancel') }</button>
|
<button onClick={this.onCancel}>{ _t('Cancel') }</button>
|
||||||
|
@ -342,7 +587,6 @@ export default class DevtoolsDialog extends React.Component {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
return (
|
return (
|
||||||
<BaseDialog className="mx_QuestionDialog" onFinished={this.props.onFinished} title={_t('Developer Tools')}>
|
<BaseDialog className="mx_QuestionDialog" onFinished={this.props.onFinished} title={_t('Developer Tools')}>
|
||||||
<div>Room ID: { this.props.roomId }</div>
|
|
||||||
{ body }
|
{ body }
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
|
|
33
src/components/views/elements/InlineSpinner.js
Normal file
33
src/components/views/elements/InlineSpinner.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const React = require('react');
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'InlineSpinner',
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var w = this.props.w || 16;
|
||||||
|
var h = this.props.h || 16;
|
||||||
|
var imgClass = this.props.imgClassName || "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx_InlineSpinner">
|
||||||
|
<img src="img/spinner.gif" width={w} height={h} className={imgClass}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
|
@ -70,6 +70,7 @@
|
||||||
"What's new?": "What's new?",
|
"What's new?": "What's new?",
|
||||||
"A new version of Riot is available.": "A new version of Riot is available.",
|
"A new version of Riot is available.": "A new version of Riot is available.",
|
||||||
"To return to your account in future you need to <u>set a password</u>": "To return to your account in future you need to <u>set a password</u>",
|
"To return to your account in future you need to <u>set a password</u>": "To return to your account in future you need to <u>set a password</u>",
|
||||||
|
"Toolbox": "Toolbox",
|
||||||
"Set Password": "Set Password",
|
"Set Password": "Set Password",
|
||||||
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
|
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
|
||||||
"Checking for an update...": "Checking for an update...",
|
"Checking for an update...": "Checking for an update...",
|
||||||
|
@ -106,7 +107,8 @@
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
"Filter results": "Filter results",
|
"Filter results": "Filter results",
|
||||||
"Send Custom Event": "Send Custom Event",
|
"Send Custom Event": "Send Custom Event",
|
||||||
"Send Custom State Event": "Send Custom State Event",
|
"Send Account Data": "Send Account Data",
|
||||||
|
"Explore Account Data": "Explore Account Data",
|
||||||
"Explore Room State": "Explore Room State",
|
"Explore Room State": "Explore Room State",
|
||||||
"Developer Tools": "Developer Tools",
|
"Developer Tools": "Developer Tools",
|
||||||
"You have successfully set a password!": "You have successfully set a password!",
|
"You have successfully set a password!": "You have successfully set a password!",
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
@import "./matrix-react-sdk/views/elements/_ProgressBar.scss";
|
@import "./matrix-react-sdk/views/elements/_ProgressBar.scss";
|
||||||
@import "./matrix-react-sdk/views/elements/_RichText.scss";
|
@import "./matrix-react-sdk/views/elements/_RichText.scss";
|
||||||
@import "./matrix-react-sdk/views/elements/_RoleButton.scss";
|
@import "./matrix-react-sdk/views/elements/_RoleButton.scss";
|
||||||
@import "./matrix-react-sdk/views/groups/_GroupInviteTile.scss";
|
|
||||||
@import "./matrix-react-sdk/views/groups/_GroupRoomList.scss";
|
@import "./matrix-react-sdk/views/groups/_GroupRoomList.scss";
|
||||||
@import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss";
|
@import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss";
|
||||||
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
|
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
|
||||||
|
@ -55,6 +54,8 @@
|
||||||
@import "./matrix-react-sdk/views/rooms/_MemberInfo.scss";
|
@import "./matrix-react-sdk/views/rooms/_MemberInfo.scss";
|
||||||
@import "./matrix-react-sdk/views/rooms/_MemberList.scss";
|
@import "./matrix-react-sdk/views/rooms/_MemberList.scss";
|
||||||
@import "./matrix-react-sdk/views/rooms/_MessageComposer.scss";
|
@import "./matrix-react-sdk/views/rooms/_MessageComposer.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_PinnedEventTile.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_PinnedEventsPanel.scss";
|
||||||
@import "./matrix-react-sdk/views/rooms/_PresenceLabel.scss";
|
@import "./matrix-react-sdk/views/rooms/_PresenceLabel.scss";
|
||||||
@import "./matrix-react-sdk/views/rooms/_RoomHeader.scss";
|
@import "./matrix-react-sdk/views/rooms/_RoomHeader.scss";
|
||||||
@import "./matrix-react-sdk/views/rooms/_RoomList.scss";
|
@import "./matrix-react-sdk/views/rooms/_RoomList.scss";
|
||||||
|
@ -68,8 +69,6 @@
|
||||||
@import "./matrix-react-sdk/views/voip/_CallView.scss";
|
@import "./matrix-react-sdk/views/voip/_CallView.scss";
|
||||||
@import "./matrix-react-sdk/views/voip/_IncomingCallbox.scss";
|
@import "./matrix-react-sdk/views/voip/_IncomingCallbox.scss";
|
||||||
@import "./matrix-react-sdk/views/voip/_VideoView.scss";
|
@import "./matrix-react-sdk/views/voip/_VideoView.scss";
|
||||||
@import "./matrix-react-sdk/views/rooms/_PinnedEventsPanel.scss";
|
|
||||||
@import "./matrix-react-sdk/views/rooms/_PinnedEventTile.scss";
|
|
||||||
@import "./vector-web/_fonts.scss";
|
@import "./vector-web/_fonts.scss";
|
||||||
@import "./vector-web/structures/_CompatibilityPage.scss";
|
@import "./vector-web/structures/_CompatibilityPage.scss";
|
||||||
@import "./vector-web/structures/_HomePage.scss";
|
@import "./vector-web/structures/_HomePage.scss";
|
||||||
|
@ -86,6 +85,7 @@
|
||||||
@import "./vector-web/views/dialogs/_SetPasswordDialog.scss";
|
@import "./vector-web/views/dialogs/_SetPasswordDialog.scss";
|
||||||
@import "./vector-web/views/directory/_NetworkDropdown.scss";
|
@import "./vector-web/views/directory/_NetworkDropdown.scss";
|
||||||
@import "./vector-web/views/elements/_ImageView.scss";
|
@import "./vector-web/views/elements/_ImageView.scss";
|
||||||
|
@import "./vector-web/views/elements/_InlineSpinner.scss";
|
||||||
@import "./vector-web/views/elements/_Spinner.scss";
|
@import "./vector-web/views/elements/_Spinner.scss";
|
||||||
@import "./vector-web/views/globals/_MatrixToolbar.scss";
|
@import "./vector-web/views/globals/_MatrixToolbar.scss";
|
||||||
@import "./vector-web/views/messages/_DateSeparator.scss";
|
@import "./vector-web/views/messages/_DateSeparator.scss";
|
||||||
|
|
|
@ -68,7 +68,7 @@ limitations under the License.
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GroupView_header_name:hover div:not(.mx_GroupView_editable) {
|
.mx_GroupView_header_isUserMember .mx_GroupView_header_name:hover div:not(.mx_GroupView_editable) {
|
||||||
color: $accent-color;
|
color: $accent-color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,7 @@ limitations under the License.
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
border-top: 1px solid $primary-hairline-color;
|
border-top: 1px solid $primary-hairline-color;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GroupView .mx_RoomView_messageListWrapper {
|
.mx_GroupView .mx_RoomView_messageListWrapper {
|
||||||
|
|
|
@ -18,6 +18,9 @@ limitations under the License.
|
||||||
max-width: 960px;
|
max-width: 960px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MyGroups .mx_RoomHeader_simpleHeader {
|
.mx_MyGroups .mx_RoomHeader_simpleHeader {
|
||||||
|
@ -61,10 +64,26 @@ limitations under the License.
|
||||||
/* Until the button is wired up */
|
/* Until the button is wired up */
|
||||||
.mx_MyGroups_joinBox {
|
.mx_MyGroups_joinBox {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
|
||||||
|
/* When joinBox wraps onto its own row, it should take up zero height so
|
||||||
|
that there isn't an awkward gap between MyGroups_createBox and
|
||||||
|
MyGroups_content.
|
||||||
|
*/
|
||||||
|
height: 0px;
|
||||||
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MyGroups_content {
|
.mx_MyGroups_content {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
|
|
||||||
|
flex: 1 0 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MyGroups_content h3 {
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MyGroups_placeholder {
|
.mx_MyGroups_placeholder {
|
||||||
|
@ -75,19 +94,22 @@ limitations under the License.
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MyGroups_joinedGroups {
|
.mx_MyGroups_joinedGroups .gm-scroll-view {
|
||||||
|
border-top: 1px solid $primary-hairline-color;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-flow: wrap;
|
flex-flow: wrap;
|
||||||
justify-content: space-around;
|
align-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MyGroups_joinedGroups .mx_GroupTile {
|
.mx_MyGroups_joinedGroups .gm-scroll-view .mx_GroupTile {
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
flex: 1 0 25%;
|
max-width: 33%;
|
||||||
|
flex: 1 0 300px;
|
||||||
height: 75px;
|
height: 75px;
|
||||||
margin-bottom: 15px;
|
margin: 10px 0px;
|
||||||
margin-right: 10px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -100,6 +122,12 @@ limitations under the License.
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_GroupTile_profile h3.mx_GroupTile_name,
|
||||||
|
.mx_GroupTile_profile .mx_GroupTile_groupId,
|
||||||
|
.mx_GroupTile_profile .mx_GroupTile_desc {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_GroupTile_profile h3.mx_GroupTile_name {
|
.mx_GroupTile_profile h3.mx_GroupTile_name {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
|
|
@ -33,3 +33,30 @@ limitations under the License.
|
||||||
background-color: $primary-bg-color;
|
background-color: $primary-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_CreateGroupDialog_input_hasPrefixAndSuffix {
|
||||||
|
border-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CreateGroupDialog_input_group {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CreateGroupDialog_prefix,
|
||||||
|
.mx_CreateGroupDialog_suffix {
|
||||||
|
height: 35px;
|
||||||
|
padding: 0px 5px;
|
||||||
|
line-height: 37px;
|
||||||
|
background-color: $input-border-color;
|
||||||
|
border: 1px solid $input-border-color;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CreateGroupDialog_prefix {
|
||||||
|
border-right: 0px;
|
||||||
|
border-radius: 3px 0px 0px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CreateGroupDialog_suffix {
|
||||||
|
border-left: 0px;
|
||||||
|
border-radius: 0px 3px 3px 0px;
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
// --Matthew
|
// --Matthew
|
||||||
|
|
||||||
.mx_UserPill,
|
.mx_UserPill,
|
||||||
.mx_RoomPill {
|
.mx_RoomPill,
|
||||||
|
.mx_AtRoomPill {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
@ -24,7 +25,8 @@
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_highlight .mx_EventTile_content .markdown-body a.mx_UserPill_me {
|
.mx_EventTile_highlight .mx_EventTile_content .markdown-body a.mx_UserPill_me,
|
||||||
|
.mx_EventTile_content .mx_AtRoomPill {
|
||||||
color: $accent-fg-color;
|
color: $accent-fg-color;
|
||||||
background-color: $mention-user-pill-bg-color;
|
background-color: $mention-user-pill-bg-color;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
|
@ -39,7 +41,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_UserPill .mx_BaseAvatar,
|
.mx_UserPill .mx_BaseAvatar,
|
||||||
.mx_RoomPill .mx_BaseAvatar {
|
.mx_RoomPill .mx_BaseAvatar,
|
||||||
|
.mx_AtRoomPill .mx_BaseAvatar {
|
||||||
position: relative;
|
position: relative;
|
||||||
left: -3px;
|
left: -3px;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.mx_GroupInviteTile {
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
display: block;
|
|
||||||
height: 34px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_GroupInviteTile_nameContainer {
|
|
||||||
display: inline-block;
|
|
||||||
width: 180px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_GroupInviteTile_avatarContainer {
|
|
||||||
display: inline-block;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
padding-left: 16px;
|
|
||||||
padding-right: 6px;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_GroupInviteTile_name {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: 165px;
|
|
||||||
vertical-align: middle;
|
|
||||||
padding-left: 6px;
|
|
||||||
padding-right: 6px;
|
|
||||||
padding-top: 2px;
|
|
||||||
padding-bottom: 3px;
|
|
||||||
color: $roomtile-name-color;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_GroupInviteTile_badge {
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
position: absolute;
|
|
||||||
right: 8px; /*gutter */
|
|
||||||
top: 9px;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: $accent-fg-color;
|
|
||||||
background-color: $group-alert-color;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 10px;
|
|
||||||
text-align: center;
|
|
||||||
padding-top: 1px;
|
|
||||||
padding-left: 4px;
|
|
||||||
padding-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,18 +19,3 @@ limitations under the License.
|
||||||
color: $primary-fg-color;
|
color: $primary-fg-color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GroupRoomTile_delete {
|
|
||||||
opacity: 0.4;
|
|
||||||
position: absolute;
|
|
||||||
top: 6px;
|
|
||||||
right: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_GroupRoomTile:hover > .mx_GroupRoomTile_delete {
|
|
||||||
display: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ limitations under the License.
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 2px 10px;
|
padding: 2px 10px;
|
||||||
// background-color: $e2e-verified-color;
|
// background-color: $e2e-verified-color;
|
||||||
// border-bottom: 1px solid $primary-hairline-color;
|
border-bottom: 1px solid $primary-hairline-color;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ limitations under the License.
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
max-width: 135px;
|
max-width: 155px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EntityTile_details {
|
.mx_EntityTile_details {
|
||||||
|
|
|
@ -94,3 +94,19 @@ limitations under the License.
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_MemberInfo label {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MemberInfo label .mx_MemberInfo_label_text {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 180px;
|
||||||
|
vertical-align: text-top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MemberInfo input[type="radio"] {
|
||||||
|
vertical-align: -2px;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -232,3 +232,17 @@ limitations under the License.
|
||||||
.mx_RoomHeader_voipButtons {
|
.mx_RoomHeader_voipButtons {
|
||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_RoomHeader_pinnedButton {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomHeader_unreadPinsIndicator {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 4px;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: $warning-color;
|
||||||
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ $mention-user-pill-bg-color: #ff0064;
|
||||||
$other-user-pill-bg-color: rgba(0, 0, 0, 0.1);
|
$other-user-pill-bg-color: rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
// groups
|
// groups
|
||||||
$group-alert-color: #774f7e;
|
|
||||||
$group-my-groups-placeholder-bg: #f7f7f7;
|
$group-my-groups-placeholder-bg: #f7f7f7;
|
||||||
$group-my-groups-placeholder-fg: #888;
|
$group-my-groups-placeholder-fg: #888;
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,7 @@ limitations under the License.
|
||||||
display: inline;
|
display: inline;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
border-radius: 11px;
|
border-radius: 11px;
|
||||||
background-color: $plinth-bg-color;
|
background-color: $plinth-bg-color;
|
||||||
|
|
|
@ -17,3 +17,150 @@ limitations under the License.
|
||||||
.mx_DevTools_RoomStateExplorer_button, .mx_DevTools_RoomStateExplorer_query {
|
.mx_DevTools_RoomStateExplorer_button, .mx_DevTools_RoomStateExplorer_query {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_label_left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_label_right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_label_bottom {
|
||||||
|
clear: both;
|
||||||
|
border-bottom: 1px solid #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_inputRow
|
||||||
|
{
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_inputLabelCell
|
||||||
|
{
|
||||||
|
padding-bottom: 21px;
|
||||||
|
display: table-cell;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_inputCell {
|
||||||
|
display: table-cell;
|
||||||
|
padding-bottom: 21px;
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_inputCell input
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid $input-underline-color;
|
||||||
|
padding: 0;
|
||||||
|
width: 240px;
|
||||||
|
color: $input-fg-color;
|
||||||
|
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_tgl {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
// add default box-sizing for this scope
|
||||||
|
&,
|
||||||
|
&:after,
|
||||||
|
&:before,
|
||||||
|
& *,
|
||||||
|
& *:after,
|
||||||
|
& *:before,
|
||||||
|
& + .mx_DevTools_tgl-btn {
|
||||||
|
box-sizing: border-box;
|
||||||
|
&::selection {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .mx_DevTools_tgl-btn {
|
||||||
|
outline: 0;
|
||||||
|
display: block;
|
||||||
|
width: 7em;
|
||||||
|
height: 2em;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
&:after,
|
||||||
|
&:before {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
width: 50%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:checked + .mx_DevTools_tgl-btn:after {
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DevTools_tgl-flip {
|
||||||
|
+ .mx_DevTools_tgl-btn {
|
||||||
|
padding: 2px;
|
||||||
|
transition: all .2s ease;
|
||||||
|
font-family: sans-serif;
|
||||||
|
perspective: 100px;
|
||||||
|
&:after,
|
||||||
|
&:before {
|
||||||
|
display: inline-block;
|
||||||
|
transition: all .4s ease;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
line-height: 2em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: attr(data-tg-on);
|
||||||
|
background: #02C66F;
|
||||||
|
transform: rotateY(-180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
background: #FF3A19;
|
||||||
|
content: attr(data-tg-off);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:before {
|
||||||
|
transform: rotateY(-20deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:checked + .mx_DevTools_tgl-btn {
|
||||||
|
&:before {
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
transform: rotateY(0);
|
||||||
|
left: 0;
|
||||||
|
background: #7FC6A6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:after {
|
||||||
|
transform: rotateY(20deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.mx_InlineSpinner {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_InlineSpinner img {
|
||||||
|
margin: 0px 6px;
|
||||||
|
vertical-align: -3px;
|
||||||
|
}
|
Loading…
Reference in a new issue