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:
parent
3d3680e42f
commit
1f3a6e408c
6 changed files with 163 additions and 111 deletions
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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');
|
||||||
|
|
|
@ -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">
|
{TextForEvent.textForEvent(this.props.mxEvent)}
|
||||||
{ avatar }
|
|
||||||
</div>
|
|
||||||
{ timestamp }
|
|
||||||
<span className="mx_SenderProfile"></span>
|
|
||||||
<span className="mx_MessageTile_content">
|
|
||||||
{TextForEvent.textForEvent(this.props.mxEvent)}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
131
src/skins/vector/views/molecules/EventTile.js
Normal file
131
src/skins/vector/views/molecules/EventTile.js
Normal 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>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
|
@ -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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue