mirror of
https://github.com/SchildiChat/element-web.git
synced 2024-10-01 01:26:12 -04:00
Merge branch 'vector' into irc-style-commands
This commit is contained in:
commit
c8caf34777
@ -28,6 +28,7 @@ div.error {
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #80cef4;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
margin-top: 16px;
|
||||
|
@ -27,11 +27,10 @@ limitations under the License.
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_leftRow {
|
||||
display: table-row;
|
||||
height: 48px;
|
||||
|
||||
-webkit-box-ordinal-group: 1;
|
||||
@ -44,7 +43,6 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_RoomHeader_rightRow {
|
||||
display: table-row;
|
||||
height: 48px;
|
||||
background-color: #fff;
|
||||
border-radius: 48px;
|
||||
@ -88,6 +86,7 @@ limitations under the License.
|
||||
|
||||
.mx_RoomHeader_avatar {
|
||||
display: table-cell;
|
||||
width: 48px;
|
||||
height: 50px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ limitations under the License.
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
vertical-align: middle;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_avatar img {
|
||||
@ -38,6 +38,12 @@ limitations under the License.
|
||||
background-color: #dbdbdb;
|
||||
}
|
||||
|
||||
.mx_RoomTile_nameBadge {
|
||||
display: table;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_name {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
@ -45,8 +51,13 @@ limitations under the License.
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mx_RoomTile_badgeCell {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_badge {
|
||||
float: right;
|
||||
background-color: #80cef4;
|
||||
color: #fff;
|
||||
border-radius: 26px;
|
||||
|
@ -44,7 +44,6 @@ limitations under the License.
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
|
||||
/* background-color: #0ff; */
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
@ -64,7 +64,6 @@ limitations under the License.
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-bottom: 60px;
|
||||
/* background-color: #ff0; */
|
||||
|
||||
overflow-y: scroll;
|
||||
}
|
||||
@ -78,6 +77,14 @@ limitations under the License.
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mx_RoomView_MessageList h2 {
|
||||
clear: both;
|
||||
margin-top: 32px;
|
||||
margin-bottom: 8px;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid #a8dbf3;
|
||||
}
|
||||
|
||||
.mx_RoomView_invitePrompt {
|
||||
}
|
||||
|
||||
|
56
skins/base/views/molecules/DateSeparator.js
Normal file
56
skins/base/views/molecules/DateSeparator.js
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket 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.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var days = [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday"
|
||||
];
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'DateSeparator',
|
||||
render: function() {
|
||||
var date = new Date(this.props.ts);
|
||||
var today = new Date();
|
||||
var yesterday = new Date();
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
var label;
|
||||
if (date.toDateString() === today.toDateString()) {
|
||||
label = "Today";
|
||||
}
|
||||
else if (date.toDateString() === yesterday.toDateString()) {
|
||||
label = "Yesterday";
|
||||
}
|
||||
else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
|
||||
label = days[date.getDay()];
|
||||
}
|
||||
else {
|
||||
label = date.toDateString();
|
||||
}
|
||||
|
||||
return (
|
||||
<h2>{ label }</h2>
|
||||
);
|
||||
}
|
||||
});
|
@ -52,12 +52,14 @@ module.exports = React.createClass({
|
||||
|
||||
render: function() {
|
||||
// XXX: for now, just cheekily borrow the css from message tile...
|
||||
var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null;
|
||||
|
||||
return (
|
||||
<div className="mx_MessageTile">
|
||||
<div className="mx_MessageTile_avatar">
|
||||
<img src={ this.props.mxEvent.target ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.mxEvent.target, 40, 40, "crop") : null } width="40" height="40"/>
|
||||
</div>
|
||||
<MessageTimestamp ts={this.props.mxEvent.getTs()} />
|
||||
{ timestamp }
|
||||
<span className="mx_SenderProfile"></span>
|
||||
<span className="mx_MessageTile_content">
|
||||
{this.getMemberEventText()}
|
||||
|
@ -17,14 +17,20 @@ limitations under the License.
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
var RoomHeaderController = require("../../../../src/controllers/molecules/RoomHeader");
|
||||
var EditableText = ComponentBroker.get("atoms/EditableText");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomHeader',
|
||||
mixins: [RoomHeaderController],
|
||||
|
||||
onNameChange: function(new_name) {
|
||||
MatrixClientPeg.get().setRoomName(this.props.room.roomId, new_name);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
|
||||
@ -52,7 +58,9 @@ module.exports = React.createClass({
|
||||
<img src={ MatrixClientPeg.get().getAvatarUrlForRoom(this.props.room, 48, 48, "crop") } width="48" height="48"/>
|
||||
</div>
|
||||
<div className="mx_RoomHeader_info">
|
||||
<div className="mx_RoomHeader_name">{ this.props.room.name }</div>
|
||||
<div className="mx_RoomHeader_name">
|
||||
<EditableText initalValue={this.props.room.name} onValueChanged={this.onNameChange} />
|
||||
</div>
|
||||
{ topic }
|
||||
</div>
|
||||
</div>
|
||||
@ -76,4 +84,3 @@ module.exports = React.createClass({
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -43,10 +43,17 @@ module.exports = React.createClass({
|
||||
else if (this.props.unread) {
|
||||
badge = <div className="mx_RoomTile_badge">1</div>;
|
||||
}
|
||||
var nameCell;
|
||||
if (badge) {
|
||||
nameCell = <div className="mx_RoomTile_nameBadge"><div className="mx_RoomTile_name">{name}</div><div className="mx_RoomTile_badgeCell">{badge}</div></div>;
|
||||
}
|
||||
else {
|
||||
nameCell = <div className="mx_RoomTile_name">{name}</div>;
|
||||
}
|
||||
return (
|
||||
<div className={classes} onClick={this.onClick}>
|
||||
<div className="mx_RoomTile_avatar"><img src={ MatrixClientPeg.get().getAvatarUrlForRoom(this.props.room, 40, 40, "crop") } width="40" height="40"/></div>
|
||||
<div className="mx_RoomTile_name">{name}{ badge }</div>
|
||||
{ nameCell }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ limitations under the License.
|
||||
var React = require('react');
|
||||
|
||||
var ComponentBroker = require("../../../../src/ComponentBroker");
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
var ProgressBar = ComponentBroker.get("molecules/ProgressBar");
|
||||
var Loader = require("react-loader");
|
||||
@ -28,15 +29,44 @@ var LoginController = require("../../../../src/controllers/templates/Login");
|
||||
var ServerConfig = ComponentBroker.get("molecules/ServerConfig");
|
||||
|
||||
module.exports = React.createClass({
|
||||
DEFAULT_HS_URL: 'https://matrix.org',
|
||||
DEFAULT_IS_URL: 'https://matrix.org',
|
||||
|
||||
displayName: 'Login',
|
||||
mixins: [LoginController],
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
serverConfigVisible: false
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.onHSChosen();
|
||||
this.customHsUrl = this.DEFAULT_HS_URL;
|
||||
this.customIsUrl = this.DEFAULT_IS_URL;
|
||||
},
|
||||
|
||||
getHsUrl: function() {
|
||||
return this.refs.serverConfig.getHsUrl();
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.customHsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_HS_URL;
|
||||
}
|
||||
},
|
||||
|
||||
getIsUrl: function() {
|
||||
return this.refs.serverConfig.getIsUrl();
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.customIsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_IS_URL;
|
||||
}
|
||||
},
|
||||
|
||||
onServerConfigVisibleChange: function(ev) {
|
||||
this.setState({
|
||||
serverConfigVisible: ev.target.checked
|
||||
}, this.onHsUrlChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -49,15 +79,46 @@ module.exports = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
onHsUrlChanged: function() {
|
||||
this.customHsUrl = this.refs.serverConfig.getHsUrl();
|
||||
this.customIsUrl = this.refs.serverConfig.getIsUrl();
|
||||
MatrixClientPeg.replaceUsingUrls(
|
||||
this.getHsUrl(),
|
||||
this.getIsUrl()
|
||||
);
|
||||
this.setState({
|
||||
hs_url: this.getHsUrl(),
|
||||
is_url: this.getIsUrl()
|
||||
});
|
||||
// XXX: HSes do not have to offer password auth, so we
|
||||
// need to update and maybe show a different component
|
||||
// when a new HS is entered.
|
||||
/*if (this.updateHsTimeout) {
|
||||
clearTimeout(this.updateHsTimeout);
|
||||
}
|
||||
var self = this;
|
||||
this.updateHsTimeout = setTimeout(function() {
|
||||
self.onHSChosen();
|
||||
}, 500);*/
|
||||
},
|
||||
|
||||
componentForStep: function(step) {
|
||||
switch (step) {
|
||||
case 'choose_hs':
|
||||
var serverConfigStyle = {};
|
||||
if (!this.state.serverConfigVisible) {
|
||||
serverConfigStyle.display = 'none';
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={this.onHSChosen}>
|
||||
<ServerConfig ref="serverConfig" />
|
||||
<input type="submit" value="Continue" />
|
||||
</form>
|
||||
<input type="checkbox" value={this.state.serverConfigVisible} onChange={this.onServerConfigVisibleChange} />
|
||||
Use custom server options (advanced)
|
||||
<div style={serverConfigStyle}>
|
||||
<ServerConfig ref="serverConfig"
|
||||
defaultHsUrl={this.customHsUrl} defaultIsUrl={this.customIsUrl}
|
||||
onHsUrlChanged={this.onHsUrlChanged}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
// XXX: clearly these should be separate organisms
|
||||
@ -67,6 +128,7 @@ module.exports = React.createClass({
|
||||
<form onSubmit={this.onUserPassEntered}>
|
||||
<input ref="user" type="text" placeholder="username" /><br />
|
||||
<input ref="pass" type="password" placeholder="password" /><br />
|
||||
{this.componentForStep('choose_hs')}
|
||||
<input type="submit" value="Log in" />
|
||||
</form>
|
||||
</div>
|
||||
@ -94,7 +156,6 @@ module.exports = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_Login">
|
||||
<ProgressBar value={this.state.currentStep} max={this.state.totalSteps} />
|
||||
{this.loginContent()}
|
||||
</div>
|
||||
);
|
||||
|
@ -39,6 +39,11 @@ module.exports = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.customHsUrl = this.DEFAULT_HS_URL;
|
||||
this.customIsUrl = this.DEFAULT_IS_URL;
|
||||
},
|
||||
|
||||
getRegFormVals: function() {
|
||||
return {
|
||||
email: this.refs.email.getDOMNode().value,
|
||||
@ -50,7 +55,7 @@ module.exports = React.createClass({
|
||||
|
||||
getHsUrl: function() {
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.refs.serverConfig.getHsUrl();
|
||||
return this.customHsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_HS_URL;
|
||||
}
|
||||
@ -58,7 +63,7 @@ module.exports = React.createClass({
|
||||
|
||||
getIsUrl: function() {
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.refs.serverConfig.getIsUrl();
|
||||
return this.customIsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_IS_URL;
|
||||
}
|
||||
@ -82,6 +87,8 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
onServerUrlChanged: function(newUrl) {
|
||||
this.customHsUrl = this.refs.serverConfig.getHsUrl();
|
||||
this.customIsUrl = this.refs.serverConfig.getIsUrl();
|
||||
this.forceUpdate();
|
||||
},
|
||||
|
||||
@ -104,7 +111,7 @@ module.exports = React.createClass({
|
||||
Use custom server options (advanced)
|
||||
<div style={serverConfigStyle}>
|
||||
<ServerConfig ref="serverConfig"
|
||||
defaultHsUrl={this.default_hs_url} defaultIsUrl={this.DEFAULT_IS_URL}
|
||||
defaultHsUrl={this.customHsUrl} defaultIsUrl={this.customIsUrl}
|
||||
onHsUrlChanged={this.onServerUrlChanged} onIsUrlChanged={this.onServerUrlChanged} />
|
||||
</div>
|
||||
<br />
|
||||
|
@ -98,6 +98,7 @@ require('../skins/base/views/organisms/RightPanel');
|
||||
require('../skins/base/views/molecules/RoomCreate');
|
||||
require('../skins/base/views/molecules/RoomDropTarget');
|
||||
require('../skins/base/views/molecules/DirectoryMenu');
|
||||
require('../skins/base/views/molecules/DateSeparator');
|
||||
require('../skins/base/views/atoms/voip/VideoFeed');
|
||||
require('../skins/base/views/molecules/voip/VideoView');
|
||||
require('../skins/base/views/molecules/voip/CallView');
|
||||
|
@ -62,6 +62,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
roomMembers: function(limit) {
|
||||
if (!this.props.roomId) return {};
|
||||
var cli = MatrixClientPeg.get();
|
||||
var all_members = cli.getRoom(this.props.roomId).currentState.members;
|
||||
var all_user_ids = Object.keys(all_members);
|
||||
|
@ -36,6 +36,8 @@ var tileTypes = {
|
||||
'm.call.hangup': ComponentBroker.get('molecules/voip/MCallHangupTile')
|
||||
};
|
||||
|
||||
var DateSeparator = ComponentBroker.get('molecules/DateSeparator');
|
||||
|
||||
module.exports = {
|
||||
getInitialState: function() {
|
||||
return {
|
||||
@ -231,22 +233,33 @@ module.exports = {
|
||||
var TileType = tileTypes[mxEv.getType()];
|
||||
var continuation = false;
|
||||
var last = false;
|
||||
var dateSeparator = null;
|
||||
if (i == this.state.room.timeline.length - 1) {
|
||||
last = true;
|
||||
}
|
||||
if (i > 0 &&
|
||||
count < this.state.messageCap - 1 &&
|
||||
this.state.room.timeline[i].sender &&
|
||||
this.state.room.timeline[i - 1].sender &&
|
||||
this.state.room.timeline[i].sender.userId ===
|
||||
if (i > 0 && count < this.state.messageCap - 1) {
|
||||
if (this.state.room.timeline[i].sender &&
|
||||
this.state.room.timeline[i - 1].sender &&
|
||||
this.state.room.timeline[i].sender.userId ===
|
||||
this.state.room.timeline[i - 1].sender.userId)
|
||||
{
|
||||
continuation = true;
|
||||
}
|
||||
{
|
||||
continuation = true;
|
||||
}
|
||||
|
||||
var ts0 = this.state.room.timeline[i - 1].getTs();
|
||||
var ts1 = this.state.room.timeline[i].getTs();
|
||||
if (new Date(ts0).toDateString() !== new Date(ts1).toDateString()) {
|
||||
dateSeparator = <DateSeparator key={ts1} ts={ts1}/>;
|
||||
continuation = false;
|
||||
}
|
||||
}
|
||||
if (!TileType) continue;
|
||||
ret.unshift(
|
||||
<TileType key={mxEv.getId()} mxEvent={mxEv} continuation={continuation} last={last}/>
|
||||
);
|
||||
if (dateSeparator) {
|
||||
ret.unshift(dateSeparator);
|
||||
}
|
||||
++count;
|
||||
}
|
||||
return ret;
|
||||
|
@ -38,8 +38,7 @@ module.exports = {
|
||||
this.setState({ step: step, errorText: '', busy: false });
|
||||
},
|
||||
|
||||
onHSChosen: function(ev) {
|
||||
ev.preventDefault();
|
||||
onHSChosen: function() {
|
||||
MatrixClientPeg.replaceUsingUrls(
|
||||
this.getHsUrl(),
|
||||
this.getIsUrl()
|
||||
|
@ -337,6 +337,14 @@ module.exports = {
|
||||
});
|
||||
} else if (error.httpStatus == 401) {
|
||||
newState.errorText = "Authorisation failed!";
|
||||
} else if (error.httpStatus >= 400 && error.httpStatus < 500) {
|
||||
newState.errorText = "Registration failed!";
|
||||
} else if (error.httpStatus >= 500 && error.httpStatus < 600) {
|
||||
newState.errorText = "Server error during registration!";
|
||||
} else if (error.name == "M_MISSING_PARAM") {
|
||||
// The HS hasn't remembered the login params from
|
||||
// the first try when the login email was sent.
|
||||
newState.errorText = "This home server does not support resuming registration.";
|
||||
}
|
||||
self.setState(newState);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user