You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-12-01 04:43:29 +03:00
Merge branch 'develop' into matthew/syjs-28
This commit is contained in:
@@ -26,6 +26,18 @@ var utils = require("../utils");
|
||||
var ContentRepo = require("../content-repo");
|
||||
var EventTimeline = require("./event-timeline");
|
||||
|
||||
|
||||
// var DEBUG = false;
|
||||
var DEBUG = true;
|
||||
|
||||
if (DEBUG) {
|
||||
// using bind means that we get to keep useful line numbers in the console
|
||||
var debuglog = console.log.bind(console);
|
||||
} else {
|
||||
var debuglog = function() {};
|
||||
}
|
||||
|
||||
|
||||
function synthesizeReceipt(userId, event, receiptType) {
|
||||
// console.log("synthesizing receipt for "+event.getId());
|
||||
// This is really ugly because JS has no way to express an object literal
|
||||
@@ -416,8 +428,8 @@ Room.prototype.addTimeline = function() {
|
||||
* (oldest) instead of the end (newest) of the timeline. If true, the oldest
|
||||
* event will be the <b>last</b> element of 'events'.
|
||||
*
|
||||
* @param {module:models/event-timeline~EventTimeline=} timeline timeline to
|
||||
* add events to. If not given, events will be added to the live timeline
|
||||
* @param {module:models/event-timeline~EventTimeline} timeline timeline to
|
||||
* add events to.
|
||||
*
|
||||
* @param {string=} paginationToken token for the next batch of events
|
||||
*
|
||||
@@ -427,13 +439,16 @@ Room.prototype.addTimeline = function() {
|
||||
Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline,
|
||||
timeline, paginationToken) {
|
||||
if (!timeline) {
|
||||
timeline = this._liveTimeline;
|
||||
throw new Error(
|
||||
"'timeline' not specified for Room.addEventsToTimeline"
|
||||
);
|
||||
}
|
||||
|
||||
if (!toStartOfTimeline && timeline == this._liveTimeline) {
|
||||
// special treatment for live events
|
||||
this._addLiveEvents(events);
|
||||
return;
|
||||
throw new Error(
|
||||
"Room.addEventsToTimeline cannot be used for adding events to " +
|
||||
"the live timeline - use Room.addLiveEvents instead"
|
||||
);
|
||||
}
|
||||
|
||||
var direction = toStartOfTimeline ? EventTimeline.BACKWARDS :
|
||||
@@ -529,7 +544,7 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline,
|
||||
lastEventWasNew = false;
|
||||
|
||||
if (existingTimeline == timeline) {
|
||||
console.log("Event " + eventId + " already in timeline " + timeline);
|
||||
debuglog("Event " + eventId + " already in timeline " + timeline);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -545,10 +560,10 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline,
|
||||
// that would happen, so I'm going to ignore it for now.
|
||||
//
|
||||
if (existingTimeline == neighbour) {
|
||||
console.log("Event " + eventId + " in neighbouring timeline - " +
|
||||
debuglog("Event " + eventId + " in neighbouring timeline - " +
|
||||
"switching to " + existingTimeline);
|
||||
} else {
|
||||
console.log("Event " + eventId + " already in a different " +
|
||||
debuglog("Event " + eventId + " already in a different " +
|
||||
"timeline " + existingTimeline);
|
||||
}
|
||||
timeline = existingTimeline;
|
||||
@@ -601,69 +616,95 @@ Room.prototype._addEventToTimeline = function(event, timeline, toStartOfTimeline
|
||||
|
||||
|
||||
/**
|
||||
* Add some events to the end of this room's live timeline. Will fire
|
||||
* "Room.timeline" for each event added.
|
||||
* Add an event to the end of this room's live timeline. Will fire
|
||||
* "Room.timeline"..
|
||||
*
|
||||
* @param {MatrixEvent[]} events A list of events to add.
|
||||
* @param {MatrixEvent} event Event to be added
|
||||
* @param {string?} duplicateStrategy 'ignore' or 'replace'
|
||||
* @fires module:client~MatrixClient#event:"Room.timeline"
|
||||
* @private
|
||||
*/
|
||||
Room.prototype._addLiveEvents = function(events) {
|
||||
// var now = Date.now();
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
if (events[i].getType() === "m.room.redaction") {
|
||||
var redactId = events[i].event.redacts;
|
||||
Room.prototype._addLiveEvent = function(event, duplicateStrategy) {
|
||||
if (event.getType() === "m.room.redaction") {
|
||||
var redactId = event.event.redacts;
|
||||
|
||||
// if we know about this event, redact its contents now.
|
||||
var redactedEvent = this.findEventById(redactId);
|
||||
if (redactedEvent) {
|
||||
redactedEvent.makeRedacted(events[i]);
|
||||
this.emit("Room.redaction", events[i], this);
|
||||
// if we know about this event, redact its contents now.
|
||||
var redactedEvent = this.findEventById(redactId);
|
||||
if (redactedEvent) {
|
||||
redactedEvent.makeRedacted(event);
|
||||
this.emit("Room.redaction", event, this);
|
||||
|
||||
// TODO: we stash user displaynames (among other things) in
|
||||
// RoomMember objects which are then attached to other events
|
||||
// (in the sender and target fields). We should get those
|
||||
// RoomMember objects to update themselves when the events that
|
||||
// they are based on are changed.
|
||||
// TODO: we stash user displaynames (among other things) in
|
||||
// RoomMember objects which are then attached to other events
|
||||
// (in the sender and target fields). We should get those
|
||||
// RoomMember objects to update themselves when the events that
|
||||
// they are based on are changed.
|
||||
}
|
||||
|
||||
// NB: We continue to add the redaction event to the timeline so
|
||||
// clients can say "so and so redacted an event" if they wish to. Also
|
||||
// this may be needed to trigger an update.
|
||||
}
|
||||
|
||||
if (event.getUnsigned().transaction_id) {
|
||||
var existingEvent = this._txnToEvent[event.getUnsigned().transaction_id];
|
||||
if (existingEvent) {
|
||||
// remote echo of an event we sent earlier
|
||||
this._handleRemoteEcho(event, existingEvent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var timeline = this._eventIdToTimeline[event.getId()];
|
||||
if (timeline) {
|
||||
if (duplicateStrategy === "replace") {
|
||||
debuglog("Room._addLiveEvent: replacing duplicate event " +
|
||||
event.getId());
|
||||
var tlEvents = timeline.getEvents();
|
||||
for (var j = 0; j < tlEvents.length; j++) {
|
||||
if (tlEvents[j].getId() === event.getId()) {
|
||||
// still need to set the right metadata on this event
|
||||
setEventMetadata(
|
||||
event,
|
||||
timeline.getState(EventTimeline.FORWARDS),
|
||||
false
|
||||
);
|
||||
|
||||
if (!tlEvents[j].encryptedType) {
|
||||
tlEvents[j] = event;
|
||||
}
|
||||
|
||||
// XXX: we need to fire an event when this happens.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// NB: We continue to add the redaction event to the timeline so
|
||||
// clients can say "so and so redacted an event" if they wish to. Also
|
||||
// this may be needed to trigger an update.
|
||||
} else {
|
||||
debuglog("Room._addLiveEvent: ignoring duplicate event " +
|
||||
event.getId());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (events[i].getUnsigned().transaction_id) {
|
||||
var existingEvent = this._txnToEvent[events[i].getUnsigned().transaction_id];
|
||||
if (existingEvent) {
|
||||
// remote echo of an event we sent earlier
|
||||
this._handleRemoteEcho(events[i], existingEvent);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// TODO: pass through filter to see if this should be added to the timeline.
|
||||
this._addEventToTimeline(event, this._liveTimeline, false);
|
||||
|
||||
if (!this._eventIdToTimeline[events[i].getId()]) {
|
||||
// TODO: pass through filter to see if this should be added to the timeline.
|
||||
this._addEventToTimeline(events[i], this._liveTimeline, false);
|
||||
}
|
||||
// synthesize and inject implicit read receipts
|
||||
// Done after adding the event because otherwise the app would get a read receipt
|
||||
// pointing to an event that wasn't yet in the timeline
|
||||
if (event.sender) {
|
||||
this.addReceipt(synthesizeReceipt(
|
||||
event.sender.userId, event, "m.read"
|
||||
), true);
|
||||
|
||||
// synthesize and inject implicit read receipts
|
||||
// Done after adding the event because otherwise the app would get a read receipt
|
||||
// pointing to an event that wasn't yet in the timeline
|
||||
if (events[i].sender) {
|
||||
this.addReceipt(synthesizeReceipt(
|
||||
events[i].sender.userId, events[i], "m.read"
|
||||
), true);
|
||||
// also, any live events from a user should be taken as implicit
|
||||
// presence information: evidence that they are currently active.
|
||||
// ...except in a world where we use 'user.currentlyActive' to reduce
|
||||
// presence spam, this isn't very useful - we'll get a transition when
|
||||
// they are no longer currently active anyway. so comment it out for now.
|
||||
|
||||
// also, any live events from a user should be taken as implicit
|
||||
// presence information: evidence that they are currently active.
|
||||
// ...except in a world where we use 'user.currentlyActive' to reduce
|
||||
// presence spam, this isn't very useful - we'll get a transition when
|
||||
// they are no longer currently active anyway. so comment it out for now.
|
||||
|
||||
// var user = this.currentState.getMember(events[i].sender.userId);
|
||||
// user.lastActiveAgo = 0;
|
||||
// user.lastPresenceTs = now;
|
||||
}
|
||||
// var user = this.currentState.getMember(events[i].sender.userId);
|
||||
// user.lastActiveAgo = 0;
|
||||
// user.lastPresenceTs = Date.now();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -866,20 +907,36 @@ Room.prototype.updatePendingEvent = function(event, newStatus, newEventId) {
|
||||
* Add some events to this room. This can include state events, message
|
||||
* events and typing notifications. These events are treated as "live" so
|
||||
* they will go to the end of the timeline.
|
||||
*
|
||||
* @param {MatrixEvent[]} events A list of events to add.
|
||||
*
|
||||
* @param {string} duplicateStrategy Optional. Applies to events in the
|
||||
* timeline only. If this is not specified, no duplicate suppression is
|
||||
* performed (this improves performance). If this is 'replace' then if a
|
||||
* duplicate is encountered, the event passed to this function will replace the
|
||||
* existing event in the timeline. If this is 'ignore', then the event passed to
|
||||
* timeline only. If this is 'replace' then if a duplicate is encountered, the
|
||||
* event passed to this function will replace the existing event in the
|
||||
* timeline. If this is not specified, or is 'ignore', then the event passed to
|
||||
* this function will be ignored entirely, preserving the existing event in the
|
||||
* timeline. Events are identical based on their event ID <b>only</b>.
|
||||
*
|
||||
* @throws If <code>duplicateStrategy</code> is not falsey, 'replace' or 'ignore'.
|
||||
*/
|
||||
Room.prototype.addEvents = function(events, duplicateStrategy) {
|
||||
Room.prototype.addLiveEvents = function(events, duplicateStrategy) {
|
||||
if (duplicateStrategy && ["replace", "ignore"].indexOf(duplicateStrategy) === -1) {
|
||||
throw new Error("duplicateStrategy MUST be either 'replace' or 'ignore'");
|
||||
}
|
||||
|
||||
// sanity check that the live timeline is still live
|
||||
if (this._liveTimeline.getPaginationToken(EventTimeline.FORWARDS)) {
|
||||
throw new Error(
|
||||
"live timeline is no longer live - it has a pagination token (" +
|
||||
this._liveTimeline.getPaginationToken(EventTimeline.FORWARDS) + ")"
|
||||
);
|
||||
}
|
||||
if (this._liveTimeline.getNeighbouringTimeline(EventTimeline.FORWARDS)) {
|
||||
throw new Error(
|
||||
"live timeline is no longer live - it has a neighbouring timeline"
|
||||
);
|
||||
}
|
||||
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
if (events[i].getType() === "m.typing") {
|
||||
this.currentState.setTypingEvent(events[i]);
|
||||
@@ -890,41 +947,9 @@ Room.prototype.addEvents = function(events, duplicateStrategy) {
|
||||
// N.B. account_data is added directly by /sync to avoid
|
||||
// having to maintain an event.isAccountData() here
|
||||
else {
|
||||
var timeline = this._eventIdToTimeline[events[i].getId()];
|
||||
if (timeline && duplicateStrategy) {
|
||||
// is there a duplicate?
|
||||
var shouldIgnore = false;
|
||||
var tlEvents = timeline.getEvents();
|
||||
for (var j = 0; j < tlEvents.length; j++) {
|
||||
if (tlEvents[j].getId() === events[i].getId()) {
|
||||
if (duplicateStrategy === "replace") {
|
||||
// still need to set the right metadata on this event
|
||||
setEventMetadata(
|
||||
events[i],
|
||||
timeline.getState(EventTimeline.FORWARDS),
|
||||
false
|
||||
);
|
||||
|
||||
if (!tlEvents[j].encryptedType) {
|
||||
tlEvents[j] = events[i];
|
||||
}
|
||||
// skip the insert so we don't add this event twice.
|
||||
// Don't break in case we replace multiple events.
|
||||
shouldIgnore = true;
|
||||
}
|
||||
else if (duplicateStrategy === "ignore") {
|
||||
shouldIgnore = true;
|
||||
break; // stop searching, we're skipping the insert
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldIgnore) {
|
||||
continue; // skip the insertion of this event.
|
||||
}
|
||||
}
|
||||
// TODO: We should have a filter to say "only add state event
|
||||
// types X Y Z to the timeline".
|
||||
this._addLiveEvents([events[i]]);
|
||||
this._addLiveEvent(events[i], duplicateStrategy);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user