Factor out stuff commnon to all timeline events into EventTile: makes timestamp & edit button etc appear on everything, not just messages.

This commit is contained in:
David Baker 2015-10-21 17:52:34 +01:00
parent 3d3680e42f
commit 1f3a6e408c
6 changed files with 163 additions and 111 deletions

View file

@ -356,23 +356,20 @@ module.exports = {
}, },
getEventTiles: function() { getEventTiles: function() {
var tileTypes = {
'm.room.message': sdk.getComponent('molecules.MessageTile'),
'm.room.member' : sdk.getComponent('molecules.EventAsTextTile'),
'm.call.invite' : sdk.getComponent('molecules.EventAsTextTile'),
'm.call.answer' : sdk.getComponent('molecules.EventAsTextTile'),
'm.call.hangup' : sdk.getComponent('molecules.EventAsTextTile'),
'm.room.topic' : sdk.getComponent('molecules.EventAsTextTile'),
};
var DateSeparator = sdk.getComponent('molecules.DateSeparator'); var DateSeparator = sdk.getComponent('molecules.DateSeparator');
var ret = []; var ret = [];
var count = 0; var count = 0;
var EventTile = sdk.getComponent('molecules.EventTile');
for (var i = this.state.room.timeline.length-1; i >= 0 && count < this.state.messageCap; --i) { for (var i = this.state.room.timeline.length-1; i >= 0 && count < this.state.messageCap; --i) {
var mxEv = this.state.room.timeline[i]; var mxEv = this.state.room.timeline[i];
var TileType = tileTypes[mxEv.getType()];
if (!EventTile.supportsEventType(mxEv.getType())) {
continue;
}
var continuation = false; var continuation = false;
var last = false; var last = false;
var dateSeparator = null; var dateSeparator = null;
@ -401,13 +398,12 @@ module.exports = {
if (i === 1) { // n.b. 1, not 0, as the 0th event is an m.room.create and so doesn't show on the timeline if (i === 1) { // n.b. 1, not 0, as the 0th event is an m.room.create and so doesn't show on the timeline
var ts1 = this.state.room.timeline[i].getTs(); var ts1 = this.state.room.timeline[i].getTs();
dateSeparator = <DateSeparator key={ts1} ts={ts1}/>; dateSeparator = <li key={ts1}><DateSeparator ts={ts1}/></li>;
continuation = false; continuation = false;
} }
if (!TileType) continue;
ret.unshift( ret.unshift(
<li key={mxEv.getId()}><TileType mxEvent={mxEv} continuation={continuation} last={last}/></li> <li key={mxEv.getId()}><EventTile mxEvent={mxEv} continuation={continuation} last={last}/></li>
); );
if (dateSeparator) { if (dateSeparator) {
ret.unshift(dateSeparator); ret.unshift(dateSeparator);

View file

@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_MessageTile { .mx_EventTile {
max-width: 100%; max-width: 100%;
clear: both; clear: both;
margin-top: 32px; margin-top: 32px;
margin-left: 56px; margin-left: 56px;
} }
.mx_MessageTile_avatar { .mx_EventTile_avatar {
padding-left: 12px; padding-left: 12px;
padding-right: 12px; padding-right: 12px;
margin-left: -64px; margin-left: -64px;
@ -29,17 +29,17 @@ limitations under the License.
float: left; float: left;
} }
.mx_MessageTile_avatar img { .mx_EventTile_avatar img {
background-color: #dbdbdb; background-color: #dbdbdb;
border-radius: 20px; border-radius: 20px;
border: 0px; border: 0px;
} }
.mx_MessageTile_continuation { .mx_EventTile_continuation {
margin-top: 8px ! important; margin-top: 8px ! important;
} }
.mx_MessageTile .mx_SenderProfile { .mx_EventTile .mx_SenderProfile {
color: #454545; color: #454545;
opacity: 0.5; opacity: 0.5;
font-size: 14px; font-size: 14px;
@ -47,35 +47,35 @@ limitations under the License.
display: block; display: block;
} }
.mx_MessageTile .mx_MessageTimestamp { .mx_EventTile .mx_MessageTimestamp {
color: #454545; color: #454545;
opacity: 0.5; opacity: 0.5;
font-size: 14px; font-size: 14px;
float: right; float: right;
} }
.mx_MessageTile_content { .mx_EventTile_content {
padding-right: 100px; padding-right: 100px;
display: block; display: block;
} }
.mx_MessageTile_notice .mx_MessageTile_content { .mx_EventTile_notice .mx_MessageTile_content {
opacity: 0.5; opacity: 0.5;
} }
.mx_MessageTile_sending { .mx_EventTile_sending {
color: #ddd; color: #ddd;
} }
.mx_MessageTile_notSent { .mx_EventTile_notSent {
color: #f11; color: #f11;
} }
.mx_MessageTile_highlight { .mx_EventTile_highlight {
color: #FF0064; color: #FF0064;
} }
.mx_MessageTile_msgOption { .mx_EventTile_msgOption {
float: right; float: right;
} }
@ -83,29 +83,30 @@ limitations under the License.
display: none; display: none;
} }
.mx_MessageTile_last .mx_MessageTimestamp { .mx_EventTile_last .mx_MessageTimestamp {
display: block; display: block;
} }
.mx_MessageTile:hover .mx_MessageTimestamp { .mx_EventTile:hover .mx_MessageTimestamp {
display: block; display: block;
} }
.mx_MessageTile_editButton { .mx_EventTile_editButton {
float: right; float: right;
display: none; display: none;
border: 0px; border: 0px;
outline: none; outline: none;
margin-right: 3px;
} }
.mx_MessageTile:hover .mx_MessageTile_editButton { .mx_EventTile:hover .mx_EventTile_editButton {
display: inline-block; display: inline-block;
} }
.mx_MessageTile.menu .mx_MessageTile_editButton { .mx_EventTile.menu .mx_EventTile_editButton {
display: inline-block; display: inline-block;
} }
.mx_MessageTile.menu .mx_MessageTimestamp { .mx_EventTile.menu .mx_MessageTimestamp {
display: inline-block; display: inline-block;
} }

View file

@ -41,6 +41,7 @@ skin['molecules.ChangeDisplayName'] = require('./views/molecules/ChangeDisplayNa
skin['molecules.ChangePassword'] = require('./views/molecules/ChangePassword'); skin['molecules.ChangePassword'] = require('./views/molecules/ChangePassword');
skin['molecules.DateSeparator'] = require('./views/molecules/DateSeparator'); skin['molecules.DateSeparator'] = require('./views/molecules/DateSeparator');
skin['molecules.EventAsTextTile'] = require('./views/molecules/EventAsTextTile'); skin['molecules.EventAsTextTile'] = require('./views/molecules/EventAsTextTile');
skin['molecules.EventTile'] = require('./views/molecules/EventTile');
skin['molecules.MatrixToolbar'] = require('./views/molecules/MatrixToolbar'); skin['molecules.MatrixToolbar'] = require('./views/molecules/MatrixToolbar');
skin['molecules.MemberInfo'] = require('./views/molecules/MemberInfo'); skin['molecules.MemberInfo'] = require('./views/molecules/MemberInfo');
skin['molecules.MemberTile'] = require('./views/molecules/MemberTile'); skin['molecules.MemberTile'] = require('./views/molecules/MemberTile');

View file

@ -36,15 +36,8 @@ module.exports = React.createClass({
var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null; var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null;
var avatar = this.props.mxEvent.sender ? <MemberAvatar member={this.props.mxEvent.sender} /> : null; var avatar = this.props.mxEvent.sender ? <MemberAvatar member={this.props.mxEvent.sender} /> : null;
return ( return (
<div className="mx_MessageTile mx_MessageTile_notice"> <div className="mx_EventAsTextTile">
<div className="mx_MessageTile_avatar">
{ avatar }
</div>
{ timestamp }
<span className="mx_SenderProfile"></span>
<span className="mx_MessageTile_content">
{TextForEvent.textForEvent(this.props.mxEvent)} {TextForEvent.textForEvent(this.props.mxEvent)}
</span>
</div> </div>
); );
}, },

View file

@ -0,0 +1,131 @@
/*
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 classNames = require("classnames");
var sdk = require('matrix-react-sdk')
var EventTileController = require('matrix-react-sdk/lib/controllers/molecules/EventTile')
var ContextualMenu = require('../../../../ContextualMenu');
var eventTileTypes = {
'm.room.message': 'molecules.MessageTile',
'm.room.member' : 'molecules.EventAsTextTile',
'm.call.invite' : 'molecules.EventAsTextTile',
'm.call.answer' : 'molecules.EventAsTextTile',
'm.call.hangup' : 'molecules.EventAsTextTile',
'm.room.topic' : 'molecules.EventAsTextTile',
};
module.exports = React.createClass({
displayName: 'EventTile',
mixins: [EventTileController],
statics: {
supportsEventType: function(et) {
return eventTileTypes[et] !== undefined;
}
},
getInitialState: function() {
return {menu: false};
},
onEditClicked: function(e) {
var MessageContextMenu = sdk.getComponent('molecules.MessageContextMenu');
var buttonRect = e.target.getBoundingClientRect()
var x = window.innerWidth - buttonRect.left;
var y = buttonRect.top + (e.target.height / 2);
var self = this;
ContextualMenu.createMenu(MessageContextMenu, {
mxEvent: this.props.mxEvent,
right: x,
top: y,
onFinished: function() {
self.setState({menu: false});
}
});
this.setState({menu: true});
},
render: function() {
var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp');
var SenderProfile = sdk.getComponent('molecules.SenderProfile');
var MemberAvatar = sdk.getComponent('atoms.MemberAvatar');
var UnknownMessageTile = sdk.getComponent('molecules.UnknownMessageTile');
var content = this.props.mxEvent.getContent();
var msgtype = content.msgtype;
var EventTileType = sdk.getComponent(eventTileTypes[this.props.mxEvent.getType()]);
// This shouldn't happen: the caller should check we support this type
// before trying to instantiate us
if (!EventTileType) {
return null;
}
var classes = classNames({
mx_EventTile: true,
mx_EventTile_sending: ['sending', 'queued'].indexOf(
this.props.mxEvent.status
) !== -1,
mx_EventTile_notSent: this.props.mxEvent.status == 'not_sent',
mx_EventTile_highlight: this.shouldHighlight(),
mx_EventTile_continuation: this.props.continuation,
mx_EventTile_last: this.props.last,
menu: this.state.menu
});
var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />
var editButton = (
<input
type="image" src="img/edit.png" alt="Edit"
className="mx_EventTile_editButton" onClick={this.onEditClicked}
/>
);
var aux = null;
if (msgtype === 'm.image') aux = "sent an image";
else if (msgtype === 'm.video') aux = "sent a video";
else if (msgtype === 'm.file') aux = "uploaded a file";
var avatar, sender;
if (!this.props.continuation) {
if (this.props.mxEvent.sender) {
avatar = (
<div className="mx_EventTile_avatar">
<MemberAvatar member={this.props.mxEvent.sender} />
</div>
);
}
sender = <SenderProfile mxEvent={this.props.mxEvent} aux={aux} />;
}
return (
<div className={classes}>
{ avatar }
{ sender }
<div>
{ timestamp }
{ editButton }
<EventTileType mxEvent={this.props.mxEvent} />
</div>
</div>
);
},
});

View file

@ -28,28 +28,7 @@ module.exports = React.createClass({
displayName: 'MessageTile', displayName: 'MessageTile',
mixins: [MessageTileController], mixins: [MessageTileController],
onEditClicked: function(e) {
var MessageContextMenu = sdk.getComponent('molecules.MessageContextMenu');
var buttonRect = e.target.getBoundingClientRect()
var x = window.innerWidth - buttonRect.left;
var y = buttonRect.top + (e.target.height / 2);
var self = this;
ContextualMenu.createMenu(MessageContextMenu, {
mxEvent: this.props.mxEvent,
right: x,
top: y,
onFinished: function() {
self.setState({menu: false});
}
});
this.setState({menu: true});
},
render: function() { render: function() {
var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp');
var SenderProfile = sdk.getComponent('molecules.SenderProfile');
var MemberAvatar = sdk.getComponent('atoms.MemberAvatar');
var UnknownMessageTile = sdk.getComponent('molecules.UnknownMessageTile'); var UnknownMessageTile = sdk.getComponent('molecules.UnknownMessageTile');
var tileTypes = { var tileTypes = {
@ -66,56 +45,7 @@ module.exports = React.createClass({
if (msgtype && tileTypes[msgtype]) { if (msgtype && tileTypes[msgtype]) {
TileType = tileTypes[msgtype]; TileType = tileTypes[msgtype];
} }
var classes = classNames({
mx_MessageTile: true,
mx_MessageTile_sending: ['sending', 'queued'].indexOf(
this.props.mxEvent.status
) !== -1,
mx_MessageTile_notSent: this.props.mxEvent.status == 'not_sent',
mx_MessageTile_highlight: this.shouldHighlight(),
mx_MessageTile_continuation: this.props.continuation,
mx_MessageTile_last: this.props.last,
menu: this.state.menu
});
var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />
var editButton = (
<input
type="image" src="img/edit.png" alt="Edit"
className="mx_MessageTile_editButton" onClick={this.onEditClicked}
/>
);
var aux = null; return <TileType mxEvent={this.props.mxEvent} />;
if (msgtype === 'm.image') aux = "sent an image";
else if (msgtype === 'm.video') aux = "sent a video";
else if (msgtype === 'm.file') aux = "uploaded a file";
var avatar, sender, resend;
if (!this.props.continuation) {
if (this.props.mxEvent.sender) {
avatar = (
<div className="mx_MessageTile_avatar">
<MemberAvatar member={this.props.mxEvent.sender} />
</div>
);
}
sender = <SenderProfile mxEvent={this.props.mxEvent} aux={aux} />;
}
if (this.props.mxEvent.status === "not_sent" && !this.state.resending) {
resend = <button className="mx_MessageTile_msgOption" onClick={this.onResend}>
Resend
</button>;
}
return (
<div className={classes}>
{ avatar }
{ sender }
<div>
{ timestamp }
{ editButton }
<TileType mxEvent={this.props.mxEvent} />
</div>
</div>
);
}, },
}); });