Compare commits

...

2 Commits

@ -1,49 +1,50 @@
'use strict'; "use strict";
const React = require('react');
const create = require('create-react-class');
const sanitize = require('sanitize-html');
const Event = require('./events/Event.js'); const Promise = require("bluebird");
const Info = require('./info.js'); const React = require("react");
const Input = require('./input.js'); const create = require("create-react-class");
const User = require('./events/user.js'); const sanitize = require("sanitize-html");
const Loading = require('./loading.js');
const Event = require("./events/Event.js");
const Info = require("./info.js");
const Input = require("./input.js");
const User = require("./events/user.js");
const Loading = require("./loading.js");
const generateJdenticon = require("../lib/generate-jdenticon"); const generateJdenticon = require("../lib/generate-jdenticon");
const groupEvents = require("../lib/group-events");
let eventFunctions = { let eventFunctions = {
plaintext: function() { plaintext: function() {
let plain = "unknown event";
if (this.type == "m.room.message") { if (this.type == "m.room.message") {
plain = this.content.body;
if (this.content.format == "org.matrix.custom.html") { if (this.content.format == "org.matrix.custom.html") {
plain = sanitize(this.content.formatted_body, {allowedTags: []}); return sanitize(this.content.formatted_body, {allowedTags: []});
} else {
return this.content.body;
} }
} } else if (this.type == "m.room.member") {
if (this.type == "m.room.member") {
if (this.content.membership == "invite") { if (this.content.membership == "invite") {
plain = `${this.sender} invited ${this.state_key}`; return `${this.sender} invited ${this.state_key}`;
} else if (this.content.membership == "join") { } else if (this.content.membership == "join") {
plain = `${this.state_key} joined the room`; return `${this.state_key} joined the room`;
} else if (this.content.membership == "leave") { } else if (this.content.membership == "leave") {
plain = `${this.state_key} left the room`; return `${this.state_key} left the room`;
} else if (this.content.membership == "kick") { } else if (this.content.membership == "kick") {
plain = `${this.sender} kicked ${this.state_key}`; return `${this.sender} kicked ${this.state_key}`;
} else if (this.content.membership == "ban") { } else if (this.content.membership == "ban") {
plain = `${this.sender} banned ${this.state_key}`; return `${this.sender} banned ${this.state_key}`;
} else {
return "unknown member event";
} }
} } else if (this.type == "m.room.avatar") {
if (this.type == "m.room.avatar") {
if (this.content.url.length > 0) { if (this.content.url.length > 0) {
plain = `${this.sender} changed the room avatar`; return `${this.sender} changed the room avatar`;
} }
} } else if (this.type == "m.room.name") {
if (this.type == "m.room.name") {
return `${this.sender} changed the room name to ${this.content.name}`; return `${this.sender} changed the room name to ${this.content.name}`;
} else {
return "unknown event";
} }
return plain;
} }
}; };
@ -59,114 +60,102 @@ let chat = create({
getSnapshotBeforeUpdate: function(_oldProps, _oldState) { getSnapshotBeforeUpdate: function(_oldProps, _oldState) {
let ref = this.state.ref; let ref = this.state.ref;
if (ref == null) {return null;}
if ((ref.scrollHeight - ref.offsetHeight) - ref.scrollTop < 100) { // Less than 100px from bottom if (ref != null && (ref.scrollHeight - ref.offsetHeight) - ref.scrollTop < 100) {
// Less than 100px from bottom
return true; return true;
} else {
return null;
} }
return null;
}, },
componentDidUpdate(prevProps, prevState, snapshot) { componentDidUpdate(prevProps, prevState, snapshot) {
let ref = this.state.ref; let ref = this.state.ref;
if (ref == null) {return;}
if (snapshot) { // scroll to bottom if (ref != null && snapshot) {
// scroll to bottom
ref.scrollTop = (ref.scrollHeight - ref.offsetHeight); ref.scrollTop = (ref.scrollHeight - ref.offsetHeight);
} }
}, },
setRef: function(ref) { setRef: function(ref) {
if (ref != null) { if (ref != null) {
this.setState({ref: ref}); this.setState({ ref: ref });
} }
}, },
onReplyClick: function(e) { onReplyClick: function(e) {
this.setState({replyEvent: e}); this.setState({ replyEvent: e });
}, },
paginateBackwards: function() { paginateBackwards: function() {
if (this.state.loading) { if (!this.state.loading) {
return; let client = this.props.client;
let timeline = client.getRoom(this.props.roomId).getLiveTimeline();
this.setState({loading: true});
return Promise.try(() => {
return client.paginateEventTimeline(timeline, {backwards: true});
}).then(() => {
this.setState({loading: false});
});
} }
let client = this.props.client;
client.paginateEventTimeline(client.getRoom(this.props.roomId).getLiveTimeline(), {backwards: true}).then(() => {
this.setState({loading: false});
});
this.setState({loading: true});
}, },
render: function() { render: function() {
let client = this.props.client; let client = this.props.client;
let empty = (
<div className="main">
</div>
);
if (this.props.roomId == undefined) {
//empty screen
return empty;
}
let room = client.getRoom(this.props.roomId);
if (room == null) {
return empty;
}
let messageGroups = { let empty = <div className="main" />;
current: [],
groups: [],
sender: "",
type: ""
};
// if the sender is the same, add it to the 'current' messageGroup, if not,
// push the old one to 'groups' and start with a new array.
let liveTimeline = room.getLiveTimeline();
let liveTimelineEvents = liveTimeline.getEvents();
let events = [];
if (liveTimelineEvents.length > 0) {
liveTimelineEvents.forEach((MatrixEvent) => {
let event = MatrixEvent.event;
event = Object.assign(event, eventFunctions);
if (event.sender == null) { // localecho messages
event.sender = event.user_id;
event.local = true;
}
if (event.sender != messageGroups.sender || event.type != messageGroups.type) {
messageGroups.sender = event.sender;
messageGroups.type = event.type;
if (messageGroups.current.length != 0) {
messageGroups.groups.push(messageGroups.current);
}
messageGroups.current = [];
}
messageGroups.current.push(event);
});
messageGroups.groups.push(messageGroups.current);
events = messageGroups.groups.map((events) => { if (this.props.roomId == null) {
return <EventGroup key={`${this.props.roomId}-${events[0].event_id}`} events={events} client={this.props.client} room={room} onReplyClick={this.onReplyClick}/>; //empty screen
}); return empty;
} } else {
//TODO: replace with something that only renders events in view let room = client.getRoom(this.props.roomId);
return ( if (room == null) {
<div className="main"> return empty;
<Info room={room} /> } else {
<div className="chat" ref={this.setRef}> let liveTimeline = room.getLiveTimeline();
<div className="events"> let liveTimelineEvents = liveTimeline.getEvents();
<div className="paginateBackwards" onClick={this.paginateBackwards}>
{this.state.loading ? let events = liveTimelineEvents.map((item) => {
<Loading/> : let event = item.event;
<span>load older messages</span>
} return Object.assign(
event,
eventFunctions,
(event.sender == null)
/* Whether this event is a local echo */
? { local: true, sender: event.user_id }
: null
);
});
let eventGroups = groupEvents(events);
//TODO: replace with something that only renders events in view
return (
<div className="main">
<Info room={room} />
<div className="chat" ref={this.setRef}>
<div className="events">
<div className="paginateBackwards" onClick={this.paginateBackwards}>
{this.state.loading ?
<Loading/> :
<span>load older messages</span>
}
</div>
{(eventGroups.map((group) => {
return <EventGroup key={`${this.props.roomId}-${group.events[0].event_id}`} events={group.events} client={this.props.client} room={room} onReplyClick={this.onReplyClick}/>;
}))}
</div>
</div> </div>
{events} <Input client={client} roomId={this.props.roomId} replyEvent={this.state.replyEvent} onReplyClick={this.onReplyClick}/>
</div> </div>
</div> );
<Input client={client} roomId={this.props.roomId} replyEvent={this.state.replyEvent} onReplyClick={this.onReplyClick}/> }
</div> }
);
} }
}); });

@ -0,0 +1,34 @@
"use strict";
module.exports = function groupEvents(events) {
let currentSender = "";
let currentType = "";
let currentEvents = [];
let eventGroups = [];
function finalizeGroup() {
if (currentEvents.length > 0) {
eventGroups.push({
sender: currentSender,
events: currentEvents
});
currentEvents = [];
}
}
events.forEach((event) => {
/* TODO: Eventually group multiple non-message events from a single user into a single event item as well, even when they are of different types */
if (event.sender !== currentSender || event.type !== currentType) {
finalizeGroup();
currentSender = event.sender;
currentType = event.type;
}
currentEvents.push(event);
});
finalizeGroup();
return eventGroups;
};

10257
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save