1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-28 05:03:59 +03:00
This commit is contained in:
Matthew Hodgson
2016-09-08 00:18:17 +01:00
parent dac820f957
commit fc495a5f1e
7 changed files with 125 additions and 42 deletions

View File

@@ -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;
};

View File

@@ -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));

View File

@@ -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.
*
* <p>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) {
*
* <p>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 <code>opts.pendingEventOrdering</code> 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];

View File

@@ -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

View File

@@ -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);
};
@@ -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"
);
}
}