diff --git a/lib/client.js b/lib/client.js
index 903106bf4..55416c7a5 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -2131,7 +2131,7 @@ MatrixClient.prototype.scrollback = function(room, limit, callback) {
return self._http.authedRequest(callback, "GET", path, params);
}).done(function(res) {
var matrixEvents = utils.map(res.chunk, _PojoToMatrixEventMapper(self));
- room.addEventsToTimeline(matrixEvents, true);
+ room.addEventsToTimeline(matrixEvents, true, room.getLiveTimeline());
room.oldState.paginationToken = res.end;
if (res.chunk.length === 0) {
room.oldState.paginationToken = null;
diff --git a/lib/models/room.js b/lib/models/room.js
index 1ba737a8f..1d9d435f9 100644
--- a/lib/models/room.js
+++ b/lib/models/room.js
@@ -26,6 +26,18 @@ var utils = require("../utils");
var ContentRepo = require("../content-repo");
var EventTimeline = require("./event-timeline");
+
+// var DEBUG_SCROLL = false;
+var DEBUG_SCROLL = true;
+
+if (DEBUG_SCROLL) {
+ // 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 last 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,14 @@ 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 +542,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 +558,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,58 +614,85 @@ 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) {
- 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 (events[i].sender) {
- this.addReceipt(synthesizeReceipt(
- events[i].sender.userId, events[i], "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 (event.sender) {
+ this.addReceipt(synthesizeReceipt(
+ event.sender.userId, event, "m.read"
+ ), true);
}
};
@@ -855,20 +895,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 only.
+ *
* @throws If duplicateStrategy 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]);
@@ -879,41 +935,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);
}
}
};
diff --git a/lib/store/webstorage.js b/lib/store/webstorage.js
index 5cd452033..76d83924e 100644
--- a/lib/store/webstorage.js
+++ b/lib/store/webstorage.js
@@ -373,7 +373,7 @@ WebStorageStore.prototype.scrollback = function(room, limit) {
);
room.addEventsToTimeline(utils.map(scrollback, function(e) {
return new MatrixEvent(e);
- }), true);
+ }), true, room.getLiveTimeline());
this._tokens[room.storageToken] = {
earliestIndex: earliestIndex
@@ -594,7 +594,7 @@ function loadRoom(store, roomId, numEvents, tokenArray) {
index--;
}
// add events backwards to diverge old state correctly.
- room.addEventsToTimeline(recentEvents.reverse(), true);
+ room.addEventsToTimeline(recentEvents.reverse(), true, room.getLiveTimeline());
room.oldState.paginationToken = currentStateMap.pagination_token;
// set the token data to let us know which index this room instance is at
// for scrollback.
diff --git a/lib/sync.js b/lib/sync.js
index 45660461c..8ac1aaf1d 100644
--- a/lib/sync.js
+++ b/lib/sync.js
@@ -262,7 +262,8 @@ SyncApi.prototype.peek = function(roomId) {
// will overwrite the pagination token, so make sure it overwrites
// it with the right thing.
peekRoom.addEventsToTimeline(messages.reverse(), true,
- undefined, response.messages.start);
+ peekRoom.getLiveTimeline(),
+ response.messages.start);
client.store.storeRoom(peekRoom);
client.emit("Room", peekRoom);
@@ -328,7 +329,7 @@ SyncApi.prototype._peekPoll = function(roomId, token) {
return e.room_id === roomId;
}).map(self.client.getEventMapper());
var room = self.client.getRoom(roomId);
- room.addEvents(events);
+ room.addLiveEvents(events);
self._peekPoll(roomId, res.end);
}, function(err) {
console.error("[%s] Peek poll failed: %s", roomId, err);
@@ -717,7 +718,7 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
// XXX: should we be adding ephemeralEvents to the timeline?
// It feels like that for symmetry with room.addAccountData()
// there should be a room.addEphemeralEvents() or similar.
- room.addEvents(ephemeralEvents);
+ room.addLiveEvents(ephemeralEvents);
// we deliberately don't add accountData to the timeline
room.addAccountData(accountDataEvents);
@@ -993,7 +994,7 @@ SyncApi.prototype._processRoomEvents = function(room, stateEventList,
// execute the timeline events, this will begin to diverge the current state
// if the timeline has any state events in it.
- room.addEventsToTimeline(timelineEventList);
+ room.addLiveEvents(timelineEventList);
};
/**
diff --git a/spec/integ/matrix-client-methods.spec.js b/spec/integ/matrix-client-methods.spec.js
index 945591c7c..fb6567efe 100644
--- a/spec/integ/matrix-client-methods.spec.js
+++ b/spec/integ/matrix-client-methods.spec.js
@@ -34,7 +34,7 @@ describe("MatrixClient", function() {
it("should no-op if you've already joined a room", function() {
var roomId = "!foo:bar";
var room = new Room(roomId);
- room.addEvents([
+ room.addLiveEvents([
utils.mkMembership({
user: userId, room: roomId, mship: "join", event: true
})
diff --git a/spec/unit/room.spec.js b/spec/unit/room.spec.js
index fd365d069..4831ac6fa 100644
--- a/spec/unit/room.spec.js
+++ b/spec/unit/room.spec.js
@@ -82,7 +82,7 @@ describe("Room", function() {
});
});
- describe("addEvents", function() {
+ describe("addLiveEvents", function() {
var events = [
utils.mkMessage({
room: roomId, user: userA, msg: "changing room name", event: true
@@ -100,12 +100,12 @@ describe("Room", function() {
user_ids: [userA]
}
});
- room.addEvents([typing]);
+ room.addLiveEvents([typing]);
expect(room.currentState.setTypingEvent).toHaveBeenCalledWith(typing);
});
it("should throw if duplicateStrategy isn't 'replace' or 'ignore'", function() {
- expect(function() { room.addEvents(events, "foo"); }).toThrow();
+ expect(function() { room.addLiveEvents(events, "foo"); }).toThrow();
});
it("should replace a timeline event if dupe strategy is 'replace'", function() {
@@ -114,9 +114,9 @@ describe("Room", function() {
room: roomId, user: userA, msg: "dupe", event: true
});
dupe.event.event_id = events[0].getId();
- room.addEvents(events);
+ room.addLiveEvents(events);
expect(room.timeline[0]).toEqual(events[0]);
- room.addEvents([dupe], "replace");
+ room.addLiveEvents([dupe], "replace");
expect(room.timeline[0]).toEqual(dupe);
});
@@ -126,39 +126,13 @@ describe("Room", function() {
room: roomId, user: userA, msg: "dupe", event: true
});
dupe.event.event_id = events[0].getId();
- room.addEvents(events);
+ room.addLiveEvents(events);
expect(room.timeline[0]).toEqual(events[0]);
- room.addEvents([dupe], "ignore");
+ room.addLiveEvents([dupe], "ignore");
expect(room.timeline[0]).toEqual(events[0]);
});
- });
- describe("addEventsToTimeline", function() {
- var events = [
- utils.mkMessage({
- room: roomId, user: userA, msg: "changing room name", event: true
- }),
- utils.mkEvent({
- type: "m.room.name", room: roomId, user: userA, event: true,
- content: { name: "New Room Name" }
- })
- ];
-
- it("should be able to add events to the end", function() {
- room.addEventsToTimeline(events);
- expect(room.timeline.length).toEqual(2);
- expect(room.timeline[0]).toEqual(events[0]);
- expect(room.timeline[1]).toEqual(events[1]);
- });
-
- it("should be able to add events to the start", function() {
- room.addEventsToTimeline(events, true);
- expect(room.timeline.length).toEqual(2);
- expect(room.timeline[0]).toEqual(events[1]);
- expect(room.timeline[1]).toEqual(events[0]);
- });
-
- it("should emit 'Room.timeline' events when added to the end",
+ it("should emit 'Room.timeline' events",
function() {
var callCount = 0;
room.on("Room.timeline", function(event, emitRoom, toStart) {
@@ -168,99 +142,10 @@ describe("Room", function() {
expect(emitRoom).toEqual(room);
expect(toStart).toBeFalsy();
});
- room.addEventsToTimeline(events);
+ room.addLiveEvents(events);
expect(callCount).toEqual(2);
});
- it("should emit 'Room.timeline' events when added to the start",
- function() {
- var callCount = 0;
- room.on("Room.timeline", function(event, emitRoom, toStart) {
- callCount += 1;
- expect(room.timeline.length).toEqual(callCount);
- expect(event).toEqual(events[callCount - 1]);
- expect(emitRoom).toEqual(room);
- expect(toStart).toBe(true);
- });
- room.addEventsToTimeline(events, true);
- expect(callCount).toEqual(2);
- });
-
- it("should set event.sender for new and old events", function() {
- var sentinel = {
- userId: userA,
- membership: "join",
- name: "Alice"
- };
- var oldSentinel = {
- userId: userA,
- membership: "join",
- name: "Old Alice"
- };
- room.currentState.getSentinelMember.andCallFake(function(uid) {
- if (uid === userA) {
- return sentinel;
- }
- return null;
- });
- room.oldState.getSentinelMember.andCallFake(function(uid) {
- if (uid === userA) {
- return oldSentinel;
- }
- return null;
- });
-
- var newEv = utils.mkEvent({
- type: "m.room.name", room: roomId, user: userA, event: true,
- content: { name: "New Room Name" }
- });
- var oldEv = utils.mkEvent({
- type: "m.room.name", room: roomId, user: userA, event: true,
- content: { name: "Old Room Name" }
- });
- room.addEventsToTimeline([newEv]);
- expect(newEv.sender).toEqual(sentinel);
- room.addEventsToTimeline([oldEv], true);
- expect(oldEv.sender).toEqual(oldSentinel);
- });
-
- it("should set event.target for new and old m.room.member events",
- function() {
- var sentinel = {
- userId: userA,
- membership: "join",
- name: "Alice"
- };
- var oldSentinel = {
- userId: userA,
- membership: "join",
- name: "Old Alice"
- };
- room.currentState.getSentinelMember.andCallFake(function(uid) {
- if (uid === userA) {
- return sentinel;
- }
- return null;
- });
- room.oldState.getSentinelMember.andCallFake(function(uid) {
- if (uid === userA) {
- return oldSentinel;
- }
- return null;
- });
-
- var newEv = utils.mkMembership({
- room: roomId, mship: "invite", user: userB, skey: userA, event: true
- });
- var oldEv = utils.mkMembership({
- room: roomId, mship: "ban", user: userB, skey: userA, event: true
- });
- room.addEventsToTimeline([newEv]);
- expect(newEv.target).toEqual(sentinel);
- room.addEventsToTimeline([oldEv], true);
- expect(oldEv.target).toEqual(oldSentinel);
- });
-
it("should call setStateEvents on the right RoomState with the right " +
"forwardLooking value for new events", function() {
var events = [
@@ -274,7 +159,7 @@ describe("Room", function() {
}
})
];
- room.addEventsToTimeline(events);
+ room.addLiveEvents(events);
expect(room.currentState.setStateEvents).toHaveBeenCalledWith(
[events[0]]
);
@@ -286,33 +171,6 @@ describe("Room", function() {
expect(room.oldState.setStateEvents).not.toHaveBeenCalled();
});
-
- it("should call setStateEvents on the right RoomState with the right " +
- "forwardLooking value for old events", function() {
- var events = [
- utils.mkMembership({
- room: roomId, mship: "invite", user: userB, skey: userA, event: true
- }),
- utils.mkEvent({
- type: "m.room.name", room: roomId, user: userB, event: true,
- content: {
- name: "New room"
- }
- })
- ];
-
- room.addEventsToTimeline(events, true);
- expect(room.oldState.setStateEvents).toHaveBeenCalledWith(
- [events[0]]
- );
- expect(room.oldState.setStateEvents).toHaveBeenCalledWith(
- [events[1]]
- );
- expect(events[0].forwardLooking).toBe(false);
- expect(events[1].forwardLooking).toBe(false);
- expect(room.currentState.setStateEvents).not.toHaveBeenCalled();
- });
-
it("should synthesize read receipts for the senders of events", function() {
var sentinel = {
userId: userA,
@@ -325,7 +183,7 @@ describe("Room", function() {
}
return null;
});
- room.addEventsToTimeline(events);
+ room.addLiveEvents(events);
expect(room.getEventReadUpTo(userA)).toEqual(events[1].getId());
});
@@ -370,13 +228,155 @@ describe("Room", function() {
expect(room.timeline.length).toEqual(1);
// then the remoteEvent
- room.addEventsToTimeline([remoteEvent]);
+ room.addLiveEvents([remoteEvent]);
expect(room.timeline.length).toEqual(1);
expect(callCount).toEqual(2);
});
});
+ describe("addEventsToTimeline", function() {
+ var events = [
+ utils.mkMessage({
+ room: roomId, user: userA, msg: "changing room name", event: true
+ }),
+ utils.mkEvent({
+ type: "m.room.name", room: roomId, user: userA, event: true,
+ content: { name: "New Room Name" }
+ })
+ ];
+
+ it("should not be able to add events to the end", function() {
+ expect(function() {
+ room.addEventsToTimeline(events, false, room.getLiveTimeline())
+ }).toThrow();
+ });
+
+ it("should be able to add events to the start", function() {
+ room.addEventsToTimeline(events, true, room.getLiveTimeline());
+ expect(room.timeline.length).toEqual(2);
+ expect(room.timeline[0]).toEqual(events[1]);
+ expect(room.timeline[1]).toEqual(events[0]);
+ });
+
+ it("should emit 'Room.timeline' events when added to the start",
+ function() {
+ var callCount = 0;
+ room.on("Room.timeline", function(event, emitRoom, toStart) {
+ callCount += 1;
+ expect(room.timeline.length).toEqual(callCount);
+ expect(event).toEqual(events[callCount - 1]);
+ expect(emitRoom).toEqual(room);
+ expect(toStart).toBe(true);
+ });
+ room.addEventsToTimeline(events, true, room.getLiveTimeline());
+ expect(callCount).toEqual(2);
+ });
+ });
+
+ describe("event metadata handling", function() {
+ it("should set event.sender for new and old events", function() {
+ var sentinel = {
+ userId: userA,
+ membership: "join",
+ name: "Alice"
+ };
+ var oldSentinel = {
+ userId: userA,
+ membership: "join",
+ name: "Old Alice"
+ };
+ room.currentState.getSentinelMember.andCallFake(function(uid) {
+ if (uid === userA) {
+ return sentinel;
+ }
+ return null;
+ });
+ room.oldState.getSentinelMember.andCallFake(function(uid) {
+ if (uid === userA) {
+ return oldSentinel;
+ }
+ return null;
+ });
+
+ var newEv = utils.mkEvent({
+ type: "m.room.name", room: roomId, user: userA, event: true,
+ content: { name: "New Room Name" }
+ });
+ var oldEv = utils.mkEvent({
+ type: "m.room.name", room: roomId, user: userA, event: true,
+ content: { name: "Old Room Name" }
+ });
+ room.addLiveEvents([newEv]);
+ expect(newEv.sender).toEqual(sentinel);
+ room.addEventsToTimeline([oldEv], true, room.getLiveTimeline());
+ expect(oldEv.sender).toEqual(oldSentinel);
+ });
+
+ it("should set event.target for new and old m.room.member events",
+ function() {
+ var sentinel = {
+ userId: userA,
+ membership: "join",
+ name: "Alice"
+ };
+ var oldSentinel = {
+ userId: userA,
+ membership: "join",
+ name: "Old Alice"
+ };
+ room.currentState.getSentinelMember.andCallFake(function(uid) {
+ if (uid === userA) {
+ return sentinel;
+ }
+ return null;
+ });
+ room.oldState.getSentinelMember.andCallFake(function(uid) {
+ if (uid === userA) {
+ return oldSentinel;
+ }
+ return null;
+ });
+
+ var newEv = utils.mkMembership({
+ room: roomId, mship: "invite", user: userB, skey: userA, event: true
+ });
+ var oldEv = utils.mkMembership({
+ room: roomId, mship: "ban", user: userB, skey: userA, event: true
+ });
+ room.addLiveEvents([newEv]);
+ expect(newEv.target).toEqual(sentinel);
+ room.addEventsToTimeline([oldEv], true, room.getLiveTimeline());
+ expect(oldEv.target).toEqual(oldSentinel);
+ });
+
+ it("should call setStateEvents on the right RoomState with the right " +
+ "forwardLooking value for old events", function() {
+ var events = [
+ utils.mkMembership({
+ room: roomId, mship: "invite", user: userB, skey: userA, event: true
+ }),
+ utils.mkEvent({
+ type: "m.room.name", room: roomId, user: userB, event: true,
+ content: {
+ name: "New room"
+ }
+ })
+ ];
+
+ room.addEventsToTimeline(events, true, room.getLiveTimeline());
+ expect(room.oldState.setStateEvents).toHaveBeenCalledWith(
+ [events[0]]
+ );
+ expect(room.oldState.setStateEvents).toHaveBeenCalledWith(
+ [events[1]]
+ );
+ expect(events[0].forwardLooking).toBe(false);
+ expect(events[1].forwardLooking).toBe(false);
+ expect(room.currentState.setStateEvents).not.toHaveBeenCalled();
+ });
+ });
+
var resetTimelineTests = function(timelineSupport) {
var events = [
utils.mkMessage({
@@ -397,11 +397,11 @@ describe("Room", function() {
});
it("should copy state from previous timeline", function() {
- room.addEventsToTimeline([events[0], events[1]]);
+ room.addLiveEvents([events[0], events[1]]);
expect(room.getLiveTimeline().getEvents().length).toEqual(2);
room.resetLiveTimeline();
- room.addEventsToTimeline([events[2]]);
+ room.addLiveEvents([events[2]]);
var oldState = room.getLiveTimeline().getState(EventTimeline.BACKWARDS);
var newState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
expect(room.getLiveTimeline().getEvents().length).toEqual(1);
@@ -410,11 +410,11 @@ describe("Room", function() {
});
it("should reset the legacy timeline fields", function() {
- room.addEventsToTimeline([events[0], events[1]]);
+ room.addLiveEvents([events[0], events[1]]);
expect(room.timeline.length).toEqual(2);
room.resetLiveTimeline();
- room.addEventsToTimeline([events[2]]);
+ room.addLiveEvents([events[2]]);
var newLiveTimeline = room.getLiveTimeline();
expect(room.timeline).toEqual(newLiveTimeline.getEvents());
expect(room.oldState).toEqual(
@@ -443,7 +443,7 @@ describe("Room", function() {
it("should " + (timelineSupport ? "remember" : "forget") +
" old timelines", function() {
- room.addEventsToTimeline([events[0]]);
+ room.addLiveEvents([events[0]]);
expect(room.timeline.length).toEqual(1);
var firstLiveTimeline = room.getLiveTimeline();
room.resetLiveTimeline();
@@ -477,7 +477,7 @@ describe("Room", function() {
];
it("should handle events in the same timeline", function() {
- room.addEventsToTimeline(events);
+ room.addLiveEvents(events);
expect(room.compareEventOrdering(events[0].getId(),
events[1].getId()))
@@ -496,7 +496,7 @@ describe("Room", function() {
room.getLiveTimeline().setNeighbouringTimeline(oldTimeline, 'b');
room.addEventsToTimeline([events[0]], false, oldTimeline);
- room.addEventsToTimeline([events[1]]);
+ room.addLiveEvents([events[1]]);
expect(room.compareEventOrdering(events[0].getId(),
events[1].getId()))
@@ -510,7 +510,7 @@ describe("Room", function() {
var oldTimeline = room.addTimeline();
room.addEventsToTimeline([events[0]], false, oldTimeline);
- room.addEventsToTimeline([events[1]]);
+ room.addLiveEvents([events[1]]);
expect(room.compareEventOrdering(events[0].getId(),
events[1].getId()))
@@ -521,7 +521,7 @@ describe("Room", function() {
});
it("should return null for unknown events", function() {
- room.addEventsToTimeline(events);
+ room.addLiveEvents(events);
expect(room.compareEventOrdering(events[0].getId(), "xxx"))
.toBe(null);
@@ -1068,7 +1068,7 @@ describe("Room", function() {
}),
];
- room.addEventsToTimeline(events);
+ room.addLiveEvents(events);
var ts = 13787898424;
// check it initialises correctly
@@ -1159,9 +1159,9 @@ describe("Room", function() {
var eventC = utils.mkMessage({
room: roomId, user: userA, msg: "remote 2", event: true
});
- room.addEvents([eventA]);
+ room.addLiveEvents([eventA]);
room.addPendingEvent(eventB, "TXN1");
- room.addEvents([eventC]);
+ room.addLiveEvents([eventC]);
expect(room.timeline).toEqual(
[eventA, eventC]
);
@@ -1185,9 +1185,9 @@ describe("Room", function() {
var eventC = utils.mkMessage({
room: roomId, user: userA, msg: "remote 2", event: true
});
- room.addEvents([eventA]);
+ room.addLiveEvents([eventA]);
room.addPendingEvent(eventB, "TXN1");
- room.addEvents([eventC]);
+ room.addLiveEvents([eventC]);
expect(room.timeline).toEqual(
[eventA, eventB, eventC]
);