src/models/room.js
function Room(roomId, client, myUserId, opts) {
    opts = opts || {};
    opts.pendingEventOrdering = opts.pendingEventOrdering || "chronological";

    this.reEmitter = new ReEmitter(this);

    if (["chronological", "detached"].indexOf(opts.pendingEventOrdering) === -1) {
        throw new Error(
            "opts.pendingEventOrdering MUST be either 'chronological' or " +
            "'detached'. Got: '" + opts.pendingEventOrdering + "'",
        );
    }

    this.myUserId = myUserId;
    this.roomId = roomId;
    this.name = roomId;
    this.tags = {
        // $tagName: { $metadata: $value },
        // $tagName: { $metadata: $value },
    };
    this.accountData = {
        // $eventType: $event
    };
    this.summary = null;
    this.storageToken = opts.storageToken;
    this._opts = opts;
    this._txnToEvent = {}; // Pending in-flight requests { string: MatrixEvent }
    // receipts should clobber based on receipt_type and user_id pairs hence
    // the form of this structure. This is sub-optimal for the exposed APIs
    // which pass in an event ID and get back some receipts, so we also store
    // a pre-cached list for this purpose.
    this._receipts = {
        // receipt_type: {
        //   user_id: {
        //     eventId: <event_id>,
        //     data: <receipt_data>
        //   }
        // }
    };
    this._receiptCacheByEventId = {
        // $event_id: [{
        //   type: $type,
        //   userId: $user_id,
        //   data: <receipt data>
        // }]
    };
    // only receipts that came from the server, not synthesized ones
    this._realReceipts = {};

    this._notificationCounts = {};

    // all our per-room timeline sets. the first one is the unfiltered ones;
    // the subsequent ones are the filtered ones in no particular order.
    this._timelineSets = [new EventTimelineSet(this, opts)];
    this.reEmitter.reEmit(this.getUnfilteredTimelineSet(),
           ["Room.timeline", "Room.timelineReset"]);

    this._fixUpLegacyTimelineFields();

    // any filtered timeline sets we're maintaining for this room
    this._filteredTimelineSets = {
        // filter_id: timelineSet
    };

    if (this._opts.pendingEventOrdering == "detached") {
        this._pendingEventList = [];
    }

    // read by megolm; boolean value - null indicates "use global value"
    this._blacklistUnverifiedDevices = null;
    this._selfMembership = null;
    this._summaryHeroes = null;
    // awaited by getEncryptionTargetMembers while room members are loading

    this._client = client;
    if (!this._opts.lazyLoadMembers) {
        this._membersPromise = Promise.resolve();
    } else {
        this._membersPromise = null;
    }
}
function Room(roomId, client, myUserId, opts) {
    opts = opts || {};
    opts.pendingEventOrdering = opts.pendingEventOrdering || "chronological";

    this.reEmitter = new ReEmitter(this);

    if (["chronological", "detached"].indexOf(opts.pendingEventOrdering) === -1) {
        throw new Error(
            "opts.pendingEventOrdering MUST be either 'chronological' or " +
            "'detached'. Got: '" + opts.pendingEventOrdering + "'",
        );
    }

    this.myUserId = myUserId;
    this.roomId = roomId;
    this.name = roomId;
    this.tags = {
        // $tagName: { $metadata: $value },
        // $tagName: { $metadata: $value },
    };
    this.accountData = {
        // $eventType: $event
    };
    this.summary = null;
    this.storageToken = opts.storageToken;
    this._opts = opts;
    this._txnToEvent = {}; // Pending in-flight requests { string: MatrixEvent }
    // receipts should clobber based on receipt_type and user_id pairs hence
    // the form of this structure. This is sub-optimal for the exposed APIs
    // which pass in an event ID and get back some receipts, so we also store
    // a pre-cached list for this purpose.
    this._receipts = {
        // receipt_type: {
        //   user_id: {
        //     eventId: <event_id>,
        //     data: <receipt_data>
        //   }
        // }
    };
    this._receiptCacheByEventId = {
        // $event_id: [{
        //   type: $type,
        //   userId: $user_id,
        //   data: <receipt data>
        // }]
    };
    // only receipts that came from the server, not synthesized ones
    this._realReceipts = {};

    this._notificationCounts = {};

    // all our per-room timeline sets. the first one is the unfiltered ones;
    // the subsequent ones are the filtered ones in no particular order.
    this._timelineSets = [new EventTimelineSet(this, opts)];
    this.reEmitter.reEmit(this.getUnfilteredTimelineSet(),
           ["Room.timeline", "Room.timelineReset"]);

    this._fixUpLegacyTimelineFields();

    // any filtered timeline sets we're maintaining for this room
    this._filteredTimelineSets = {
        // filter_id: timelineSet
    };

    if (this._opts.pendingEventOrdering == "detached") {
        this._pendingEventList = [];
    }

    // read by megolm; boolean value - null indicates "use global value"
    this._blacklistUnverifiedDevices = null;
    this._selfMembership = null;
    this._summaryHeroes = null;
    // awaited by getEncryptionTargetMembers while room members are loading

    this._client = client;
    if (!this._opts.lazyLoadMembers) {
        this._membersPromise = Promise.resolve();
    } else {
        this._membersPromise = null;
    }
}
function Room ( roomId , client , myUserId , opts ) { opts = opts || { } ; opts . pendingEventOrdering = opts . pendingEventOrdering || "chronological" ; this . reEmitter = new ReEmitter ( this ) ; if ( [ "chronological" , "detached" ] . indexOf ( opts . pendingEventOrdering ) === - 1 ) { throw new Error ( "opts.pendingEventOrdering MUST be either 'chronological' or " + "'detached'. Got: '" + opts . pendingEventOrdering + "'" , ) ; } this . myUserId = myUserId ; this . roomId = roomId ; this . name = roomId ; this . tags = { // $tagName: { $metadata: $value }, // $tagName: { $metadata: $value }, } ; this . accountData = { // $eventType: $event } ; this . summary = null ; this . storageToken = opts . storageToken ; this . _opts = opts ; this . _txnToEvent = { } ; // Pending in-flight requests { string: MatrixEvent } // receipts should clobber based on receipt_type and user_id pairs hence // the form of this structure. This is sub-optimal for the exposed APIs // which pass in an event ID and get back some receipts, so we also store // a pre-cached list for this purpose. this . _receipts = { // receipt_type: { //   user_id: { //     eventId: <event_id>, //     data: <receipt_data> //   } // } } ; this . _receiptCacheByEventId = { // $event_id: [{ //   type: $type, //   userId: $user_id, //   data: <receipt data> // }] } ; // only receipts that came from the server, not synthesized ones this . _realReceipts = { } ; this . _notificationCounts = { } ; // all our per-room timeline sets. the first one is the unfiltered ones; // the subsequent ones are the filtered ones in no particular order. this . _timelineSets = [ new EventTimelineSet ( this , opts ) ] ; this . reEmitter . reEmit ( this . getUnfilteredTimelineSet ( ) , [ "Room.timeline" , "Room.timelineReset" ] ) ; this . _fixUpLegacyTimelineFields ( ) ; // any filtered timeline sets we're maintaining for this room this . _filteredTimelineSets = { // filter_id: timelineSet } ; if ( this . _opts . pendingEventOrdering == "detached" ) { this . _pendingEventList = [ ] ; } // read by megolm; boolean value - null indicates "use global value" this . _blacklistUnverifiedDevices = null ; this . _selfMembership = null ; this . _summaryHeroes = null ; // awaited by getEncryptionTargetMembers while room members are loading this . _client = client ; if ( ! this . _opts . lazyLoadMembers ) { this . _membersPromise = Promise . resolve ( ) ; } else { this . _membersPromise = null ; } }
Construct a new Room.

<p>For a room, we store an ordered sequence of timelines, which may or may not
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. It also tracks
forward and backward pagination tokens, as well as containing 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
from the /sync API. Note that you should not retain references to this
timeline - even if it is the current timeline right now, it may not remain
so if the server gives us a timeline gap in /sync.

<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
@alias module:models/room
@param {string} roomId Required. The ID of this room.
@param {MatrixClient} client Required. The client, used to lazy load members.
@param {string} myUserId Required. The ID of the syncing user.
@param {Object=} opts Configuration options
@param {*} opts.storageToken Optional. The token which a data store can use
to remember the state of the room. What this means is dependent on the store
implementation.

@param {String=} opts.pendingEventOrdering Controls where pending messages
appear in a room's timeline. If "<b>chronological</b>", messages will appear
in the timeline when the call to <code>sendEvent</code> was made. If
"<b>detached</b>", pending messages will appear in a separate list,
accessbile via {@link module:models/room#getPendingEvents}. Default:
"chronological".

@param {boolean} [opts.timelineSupport = false] Set to true to enable improved
timeline support.

@prop {string} roomId The ID of this room.
@prop {string} name The human-readable display name for this room.
@prop {Array<MatrixEvent>} timeline The live event timeline for this room,
with the oldest event at index 0. Present for backwards compatibility -
prefer getLiveTimeline().getEvents().
@prop {object} tags Dict of room tags; the keys are the tag name and the values
are any metadata associated with the tag - e.g. { "fav" : { order: 1 } }
@prop {object} accountData Dict of per-room account_data events; the keys are the
event type and the values are the events.
@prop {RoomState} oldState The state of the room at the time of the oldest
event in the live timeline. Present for backwards compatibility -
prefer getLiveTimeline().getState(EventTimeline.BACKWARDS).
@prop {RoomState} currentState The state of the room at the time of the
newest event in the timeline. Present for backwards compatibility -
prefer getLiveTimeline().getState(EventTimeline.FORWARDS).
@prop {RoomSummary} summary The room summary.
@prop {*} storageToken A token which a data store can use to remember
the state of the room.
Construct a new Room .