diff --git a/lib/filter-component.js b/lib/filter-component.js index 6c1e289f6..98f8fd7d7 100644 --- a/lib/filter-component.js +++ b/lib/filter-component.js @@ -18,6 +18,13 @@ limitations under the License. * @module filter-component */ +/** + * Checks if a value matches a given field value, which may be a * terminated + * wildcard pattern. + * @param {String} actual_value The value to be compared + * @param {String} filter_value The filter pattern to be compared + * @return {bool} true if the actual_value matches the filter_value + */ function _matches_wildcard(actual_value, filter_value) { if (filter_value.endsWith("*")) { var type_prefix = filter_value.slice(0, -1); @@ -29,10 +36,15 @@ function _matches_wildcard(actual_value, filter_value) { } /** - * A FilterComponent is a section of a Filter definition which defines the + * FilterComponent is a section of a Filter definition which defines the * types, rooms, senders filters etc to be applied to a particular type of resource. + * This is all ported over from synapse's Filter object. * - * This is all ported from synapse's Filter object. + * N.B. that synapse refers to these as 'Filters', and what js-sdk refers to as + * 'Filters' are referred to as 'FilterCollections'. + * + * @constructor + * @param {Object} the definition of this filter JSON, e.g. { 'contains_url': true } */ function FilterComponent(filter_json) { this.filter_json = filter_json; @@ -51,11 +63,11 @@ function FilterComponent(filter_json) { /** * Checks with the filter component matches the given event - * - * Takes a MatrixEvent object + * @param {MatrixEvent} event event to be checked against the filter + * @return {bool} true if the event matches the filter */ FilterComponent.prototype.check = function(event) { - return this.checkFields( + return this._checkFields( event.getRoomId(), event.getSender(), event.getType(), @@ -64,9 +76,14 @@ FilterComponent.prototype.check = function(event) { }; /** - * Checks whether the filter matches the given event fields. + * Checks whether the filter component matches the given event fields. + * @param {String} room_id the room_id for the event being checked + * @param {String} sender the sender of the event being checked + * @param {String} event_type the type of the event being checked + * @param {String} contains_url whether the event contains a content.url field + * @return {bool} true if the event fields match the filter */ -FilterComponent.prototype.checkFields = +FilterComponent.prototype._checkFields = function(room_id, sender, event_type, contains_url) { var literal_keys = { @@ -102,10 +119,20 @@ FilterComponent.prototype.checkFields = return true; }; +/** + * Filters a list of events down to those which match this filter component + * @param {MatrixEvent[]} events Events to be checked againt the filter component + * @return {MatrixEvent[]} events which matched the filter component + */ FilterComponent.prototype.filter = function(events) { return events.filter(this.check, this); }; +/** + * Returns the limit field for a given filter component, providing a default of + * 10 if none is otherwise specified. Cargo-culted from Synapse. + * @return {Number} the limit for this filter component. + */ FilterComponent.prototype.limit = function() { return this.filter_json.limit !== undefined ? this.filter_json.limit : 10; }; diff --git a/lib/filter.js b/lib/filter.js index d1d31a0bc..1aa892960 100644 --- a/lib/filter.js +++ b/lib/filter.js @@ -127,11 +127,16 @@ Filter.prototype.setDefinition = function(definition) { ); // don't bother porting this from synapse yet: - // this._room_state_filter = new FilterComponent(room_filter_json.state || {}); - // this._room_ephemeral_filter = new FilterComponent(room_filter_json.ephemeral || {}); - // this._room_account_data_filter = new FilterComponent(room_filter_json.account_data || {}); - // this._presence_filter = new FilterComponent(definition.presence || {}); - // this._account_data_filter = new FilterComponent(definition.account_data || {}); + // this._room_state_filter = + // new FilterComponent(room_filter_json.state || {}); + // this._room_ephemeral_filter = + // new FilterComponent(room_filter_json.ephemeral || {}); + // this._room_account_data_filter = + // new FilterComponent(room_filter_json.account_data || {}); + // this._presence_filter = + // new FilterComponent(definition.presence || {}); + // this._account_data_filter = + // new FilterComponent(definition.account_data || {}); }; /** @@ -145,6 +150,8 @@ Filter.prototype.getRoomTimelineFilterComponent = function() { /** * Filter the list of events based on whether they are allowed in a timeline * based on this filter + * @param {MatrixEvent[]} events the list of events being filtered + * @return {MatrixEvent[]} the list of events which match the filter */ Filter.prototype.filterRoomTimeline = function(events) { return this._room_timeline_filter.filter(this._room_filter.filter(events)); diff --git a/lib/models/event-timeline-set.js b/lib/models/event-timeline-set.js index 5cdec4c21..abc1d9386 100644 --- a/lib/models/event-timeline-set.js +++ b/lib/models/event-timeline-set.js @@ -41,8 +41,7 @@ if (DEBUG) { * be continuous. Each timeline lists a series of events, as well as tracking * the room state at the start and the end of the timeline (if appropriate). * It also tracks forward and backward pagination tokens, as well as containing - * links to the - * next timeline in the sequence. + * links to the next timeline in the sequence. * *
There is one special timeline - the 'live' timeline, which represents the * timeline to which events are being added in real-time as they are received @@ -52,6 +51,13 @@ if (DEBUG) { * *
In order that we can find events from their ids later, we also maintain a
* map from event_id to timeline and index.
+ *
+ * @constructor
+ * @param {?String} roomId the roomId of this timelineSet's room, if any
+ * @param {?Room} room the optional room for this timelineSet
+ * @param {Object} opts hash of options inherited from Room.
+ * opts.timelineSupport gives whether timeline support is enabled
+ * opts.filter is the filter object, if any, for this timelineSet.
*/
function EventTimelineSet(roomId, room, opts) {
this.roomId = roomId;
@@ -69,15 +75,17 @@ function EventTimelineSet(roomId, room, opts) {
utils.inherits(EventTimelineSet, EventEmitter);
/**
- * Get the filter object this timeline list is filtered on
+ * Get the filter object this timeline set is filtered on, if any
+ * @return {?Filter} the optional filter for this timelineSet
*/
EventTimelineSet.prototype.getFilter = function() {
return this._filter;
};
/**
- * Set the filter object this timeline list is filtered on
+ * Set the filter object this timeline set is filtered on
* (passed to the server when paginating via /messages).
+ * @param {Filter} filter the filter for this timelineSet
*/
EventTimelineSet.prototype.setFilter = function(filter) {
this._filter = filter;
@@ -93,7 +101,9 @@ EventTimelineSet.prototype.setFilter = function(filter) {
* @throws If opts.pendingEventOrdering was not 'detached'
*/
EventTimelineSet.prototype.getPendingEvents = function() {
- if (!this.room) return [];
+ if (!this.room) {
+ return [];
+ }
if (this._filter) {
return this._filter.filterRoomTimeline(this.room.getPendingEvents());
@@ -108,14 +118,25 @@ EventTimelineSet.prototype.getPendingEvents = function() {
*
* @return {module:models/event-timeline~EventTimeline} live timeline
*/
-EventTimelineSet.prototype.getLiveTimeline = function(filterId) {
+EventTimelineSet.prototype.getLiveTimeline = function() {
return this._liveTimeline;
};
+/**
+ * Return the timeline (if any) this event is in.
+ * @param {String} eventId the eventId being sought
+ * @return {module:models/event-timeline~EventTimeline} timeline
+ */
EventTimelineSet.prototype.eventIdToTimeline = function(eventId) {
return this._eventIdToTimeline[eventId];
};
+/**
+ * Track a new event as if it were in the same timeline as an old event,
+ * replacing it.
+ * @param {String} oldEventId event ID of the original event
+ * @param {String} newEventId event ID of the replacement event
+ */
EventTimelineSet.prototype.replaceEventId = function(oldEventId, newEventId) {
var existingTimeline = this._eventIdToTimeline[oldEventId];
if (existingTimeline) {
@@ -387,7 +408,10 @@ EventTimelineSet.prototype.addEventsToTimeline = function(events, toStartOfTimel
};
/**
- * Add event to the live timeline
+ * Add an event to the end of this live timeline.
+ *
+ * @param {MatrixEvent} event Event to be added
+ * @param {string?} duplicateStrategy 'ignore' or 'replace'
*/
EventTimelineSet.prototype.addLiveEvent = function(event, duplicateStrategy) {
if (this._filter) {
@@ -441,10 +465,9 @@ EventTimelineSet.prototype.addLiveEvent = function(event, duplicateStrategy) {
* @param {boolean} toStartOfTimeline
*
* @fires module:client~MatrixClient#event:"Room.timeline"
- *
- * @private
*/
-EventTimelineSet.prototype.addEventToTimeline = function(event, timeline, toStartOfTimeline) {
+EventTimelineSet.prototype.addEventToTimeline = function(event, timeline,
+ toStartOfTimeline) {
var eventId = event.getId();
timeline.addEvent(event, toStartOfTimeline);
this._eventIdToTimeline[eventId] = timeline;
@@ -454,10 +477,23 @@ EventTimelineSet.prototype.addEventToTimeline = function(event, timeline, toStar
liveEvent: !toStartOfTimeline && timeline == this._liveTimeline,
timelineSet: this,
};
- this.emit("Room.timeline", event, this.room, Boolean(toStartOfTimeline), false, data);
+ this.emit("Room.timeline", event, this.room,
+ Boolean(toStartOfTimeline), false, data);
};
-EventTimelineSet.prototype.replaceOrAddEvent = function(localEvent, oldEventId, newEventId) {
+/**
+ * Replaces event with ID oldEventId with one with newEventId, if oldEventId is
+ * recognised. Otherwise, add to the live timeline.
+ *
+ * @param {MatrixEvent} localEvent the new event to be added to the timeline
+ * @param {String} oldEventId the ID of the original event
+ * @param {boolean} newEventId the ID of the replacement event
+ *
+ * @fires module:client~MatrixClient#event:"Room.timeline"
+ */
+EventTimelineSet.prototype.replaceOrAddEvent = function(localEvent, oldEventId,
+ newEventId) {
+ // XXX: why don't we infer newEventId from localEvent?
var existingTimeline = this._eventIdToTimeline[oldEventId];
if (existingTimeline) {
delete this._eventIdToTimeline[oldEventId];
diff --git a/lib/models/event-timeline.js b/lib/models/event-timeline.js
index 3a12f26db..b885e0469 100644
--- a/lib/models/event-timeline.js
+++ b/lib/models/event-timeline.js
@@ -94,7 +94,7 @@ EventTimeline.prototype.getRoomId = function() {
/**
* Get the filter for this timeline's timelineSet (if any)
- * @return {Filter}} filter
+ * @return {Filter} filter
*/
EventTimeline.prototype.getFilter = function() {
return this._eventTimelineSet.getFilter();
@@ -262,6 +262,10 @@ EventTimeline.prototype.addEvent = function(event, atStart) {
/**
* Static helper method to set sender and target properties
+ *
+ * @param {MatrixEvent} event the event whose metadata is to be set
+ * @param {RoomState} stateContext the room state to be queried
+ * @param {bool} toStartOfTimeline if true the event's forwardLooking flag is set false
*/
EventTimeline.setEventMetadata = function(event, stateContext, toStartOfTimeline) {
// set sender and target properties
diff --git a/lib/models/room.js b/lib/models/room.js
index ee6b07433..467e26d83 100644
--- a/lib/models/room.js
+++ b/lib/models/room.js
@@ -151,8 +151,8 @@ function Room(roomId, opts) {
// all our per-room timeline lists. the first one is the unfiltered ones;
// the subsequent ones are the filtered ones in no particular order.
- this._timelineSets = [ new EventTimelineSet(roomId, this, opts) ];
- reEmit(this, this._timelineSets[0], [ "Room.timeline" ]);
+ this._timelineSets = [new EventTimelineSet(roomId, this, opts)];
+ reEmit(this, this._timelineSets[0], ["Room.timeline"]);
this._fixUpLegacyTimelineFields();
@@ -193,7 +193,7 @@ Room.prototype.getPendingEvents = function() {
*
* @return {module:models/event-timeline~EventTimeline} live timeline
*/
-Room.prototype.getLiveTimeline = function(filterId) {
+Room.prototype.getLiveTimeline = function() {
return this._timelineSets[0].getLiveTimeline();
};
@@ -227,19 +227,23 @@ Room.prototype._fixUpLegacyTimelineFields = function() {
// state at the start and end of that timeline. These are more
// for backwards-compatibility than anything else.
this.timeline = this._timelineSets[0].getLiveTimeline().getEvents();
- this.oldState = this._timelineSets[0].getLiveTimeline().getState(EventTimeline.BACKWARDS);
- this.currentState = this._timelineSets[0].getLiveTimeline().getState(EventTimeline.FORWARDS);
+ this.oldState = this._timelineSets[0].getLiveTimeline()
+ .getState(EventTimeline.BACKWARDS);
+ this.currentState = this._timelineSets[0].getLiveTimeline()
+ .getState(EventTimeline.FORWARDS);
};
/**
- * Return the timeline sets for this room
+ * Return the timeline sets for this room.
+ * @return {EventTimelineSet[]} array of timeline sets for this room
*/
Room.prototype.getTimelineSets = function() {
return this._timelineSets;
};
/**
- * Return the notification timeline set for this room
+ * Return the shared notification timeline set
+ * @return {EventTimelineSet} notification timeline set
*/
Room.prototype.getNotifTimelineSet = function() {
return this._notifTimelineSet;
@@ -252,7 +256,6 @@ Room.prototype.getNotifTimelineSet = function() {
* @return {?module:models/event-timeline~EventTimeline} timeline containing
* the given event, or null if unknown
*/
-
Room.prototype.getTimelineForEvent = function(eventId) {
return this._timelineSets[0].getTimelineForEvent(eventId);
};
@@ -466,7 +469,7 @@ Room.prototype.getOrCreateFilteredTimelineSet = function(filter) {
}
var opts = Object.assign({ filter: filter }, this._opts);
var timelineSet = new EventTimelineSet(this.roomId, this, opts);
- reEmit(this, timelineSet, [ "Room.timeline" ]);
+ reEmit(this, timelineSet, ["Room.timeline"]);
this._filteredTimelineSets[filter.filterId] = timelineSet;
this._timelineSets.push(timelineSet);
@@ -501,6 +504,8 @@ Room.prototype.getOrCreateFilteredTimelineSet = function(filter) {
/**
* Forget the timelineSet for this room with the given filter
+ *
+ * @param {Filter} filter the filter whose timelineSet is to be forgotten
*/
Room.prototype.removeFilteredTimelineSet = function(filter) {
var timelineSet = this._filteredTimelineSets[filter.filterId];
@@ -634,14 +639,17 @@ Room.prototype.addPendingEvent = function(event, txnId) {
var timelineSet = this._timelineSets[i];
if (timelineSet.getFilter()) {
if (this._filter.filterRoomTimeline([event]).length) {
- timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), false);
+ timelineSet.addEventToTimeline(event,
+ timelineSet.getLiveTimeline(), false);
}
}
else {
- timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), false);
+ timelineSet.addEventToTimeline(event,
+ timelineSet.getLiveTimeline(), false);
}
}
- // notifications are receive-only, so we don't need to worry about this._notifTimelineSet.
+ // notifications are receive-only, so we don't need to worry
+ // about this._notifTimelineSet.
}
this.emit("Room.localEchoUpdated", event, this, null, null);
@@ -823,13 +831,14 @@ Room.prototype.addLiveEvents = function(events, duplicateStrategy) {
var liveTimeline = this._timelineSets[i].getLiveTimeline();
if (liveTimeline.getPaginationToken(EventTimeline.FORWARDS)) {
throw new Error(
- "live timeline "+i+" is no longer live - it has a pagination token (" +
- liveTimeline.getPaginationToken(EventTimeline.FORWARDS) + ")"
+ "live timeline " + i + " is no longer live - it has a pagination token " +
+ "(" + liveTimeline.getPaginationToken(EventTimeline.FORWARDS) + ")"
);
}
if (liveTimeline.getNeighbouringTimeline(EventTimeline.FORWARDS)) {
throw new Error(
- "live timeline "+i+" is no longer live - it has a neighbouring timeline"
+ "live timeline " + i + " is no longer live - " +
+ "it has a neighbouring timeline"
);
}
}
diff --git a/spec/unit/event-timeline.spec.js b/spec/unit/event-timeline.spec.js
index 9a7aba2ae..25b748648 100644
--- a/spec/unit/event-timeline.spec.js
+++ b/spec/unit/event-timeline.spec.js
@@ -16,7 +16,7 @@ describe("EventTimeline", function() {
beforeEach(function() {
utils.beforeEach(this);
- timeline = new EventTimeline({ roomId : roomId });
+ timeline = new EventTimeline({ roomId: roomId });
});
describe("construction", function() {
diff --git a/spec/unit/timeline-window.spec.js b/spec/unit/timeline-window.spec.js
index f33e9451c..ce87f13c0 100644
--- a/spec/unit/timeline-window.spec.js
+++ b/spec/unit/timeline-window.spec.js
@@ -18,7 +18,7 @@ function createTimeline(numEvents, baseIndex) {
if (numEvents === undefined) { numEvents = 3; }
if (baseIndex === undefined) { baseIndex = 1; }
- var timeline = new EventTimeline({ roomId : ROOM_ID });
+ var timeline = new EventTimeline({ roomId: ROOM_ID });
// add the events after the baseIndex first
addEventsToTimeline(timeline, numEvents - baseIndex, false);