diff options
Diffstat (limited to 'includes/external/matrix/node_modules/matrix-js-sdk/src/models/event-timeline.ts')
-rw-r--r-- | includes/external/matrix/node_modules/matrix-js-sdk/src/models/event-timeline.ts | 458 |
1 files changed, 0 insertions, 458 deletions
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/src/models/event-timeline.ts b/includes/external/matrix/node_modules/matrix-js-sdk/src/models/event-timeline.ts deleted file mode 100644 index d1ba321..0000000 --- a/includes/external/matrix/node_modules/matrix-js-sdk/src/models/event-timeline.ts +++ /dev/null @@ -1,458 +0,0 @@ -/* -Copyright 2016 - 2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { logger } from "../logger"; -import { IMarkerFoundOptions, RoomState } from "./room-state"; -import { EventTimelineSet } from "./event-timeline-set"; -import { MatrixEvent } from "./event"; -import { Filter } from "../filter"; -import { EventType } from "../@types/event"; - -export interface IInitialiseStateOptions extends Pick<IMarkerFoundOptions, "timelineWasEmpty"> { - // This is a separate interface without any extra stuff currently added on - // top of `IMarkerFoundOptions` just because it feels like they have - // different concerns. One shouldn't necessarily look to add to - // `IMarkerFoundOptions` just because they want to add an extra option to - // `initialiseState`. -} - -export interface IAddEventOptions extends Pick<IMarkerFoundOptions, "timelineWasEmpty"> { - /** Whether to insert the new event at the start of the timeline where the - * oldest events are (timeline is in chronological order, oldest to most - * recent) */ - toStartOfTimeline: boolean; - /** The state events to reconcile metadata from */ - roomState?: RoomState; -} - -export enum Direction { - Backward = "b", - Forward = "f", -} - -export class EventTimeline { - /** - * Symbolic constant for methods which take a 'direction' argument: - * refers to the start of the timeline, or backwards in time. - */ - public static readonly BACKWARDS = Direction.Backward; - - /** - * Symbolic constant for methods which take a 'direction' argument: - * refers to the end of the timeline, or forwards in time. - */ - public static readonly FORWARDS = Direction.Forward; - - /** - * Static helper method to set sender and target properties - * - * @param event - the event whose metadata is to be set - * @param stateContext - the room state to be queried - * @param toStartOfTimeline - if true the event's forwardLooking flag is set false - */ - public static setEventMetadata(event: MatrixEvent, stateContext: RoomState, toStartOfTimeline: boolean): void { - // When we try to generate a sentinel member before we have that member - // in the members object, we still generate a sentinel but it doesn't - // have a membership event, so test to see if events.member is set. We - // check this to avoid overriding non-sentinel members by sentinel ones - // when adding the event to a filtered timeline - if (!event.sender?.events?.member) { - event.sender = stateContext.getSentinelMember(event.getSender()!); - } - if (!event.target?.events?.member && event.getType() === EventType.RoomMember) { - event.target = stateContext.getSentinelMember(event.getStateKey()!); - } - - if (event.isState()) { - // room state has no concept of 'old' or 'current', but we want the - // room state to regress back to previous values if toStartOfTimeline - // is set, which means inspecting prev_content if it exists. This - // is done by toggling the forwardLooking flag. - if (toStartOfTimeline) { - event.forwardLooking = false; - } - } - } - - private readonly roomId: string | null; - private readonly name: string; - private events: MatrixEvent[] = []; - private baseIndex = 0; - - private startState?: RoomState; - private endState?: RoomState; - // If we have a roomId then we delegate pagination token storage to the room state objects `startState` and - // `endState`, but for things like the notification timeline which mix multiple rooms we store the tokens ourselves. - private startToken: string | null = null; - private endToken: string | null = null; - - private prevTimeline: EventTimeline | null = null; - private nextTimeline: EventTimeline | null = null; - public paginationRequests: Record<Direction, Promise<boolean> | null> = { - [Direction.Backward]: null, - [Direction.Forward]: null, - }; - - /** - * Construct a new EventTimeline - * - * <p>An EventTimeline represents a contiguous sequence of events in a room. - * - * <p>As well as keeping track of the events themselves, it stores the state of - * the room at the beginning and end of the timeline, and pagination tokens for - * going backwards and forwards in the timeline. - * - * <p>In order that clients can meaningfully maintain an index into a timeline, - * the EventTimeline object tracks a 'baseIndex'. This starts at zero, but is - * incremented when events are prepended to the timeline. The index of an event - * relative to baseIndex therefore remains constant. - * - * <p>Once a timeline joins up with its neighbour, they are linked together into a - * doubly-linked list. - * - * @param eventTimelineSet - the set of timelines this is part of - */ - public constructor(private readonly eventTimelineSet: EventTimelineSet) { - this.roomId = eventTimelineSet.room?.roomId ?? null; - if (this.roomId) { - this.startState = new RoomState(this.roomId); - this.endState = new RoomState(this.roomId); - } - - // this is used by client.js - this.paginationRequests = { b: null, f: null }; - - this.name = this.roomId + ":" + new Date().toISOString(); - } - - /** - * Initialise the start and end state with the given events - * - * <p>This can only be called before any events are added. - * - * @param stateEvents - list of state events to initialise the - * state with. - * @throws Error if an attempt is made to call this after addEvent is called. - */ - public initialiseState(stateEvents: MatrixEvent[], { timelineWasEmpty }: IInitialiseStateOptions = {}): void { - if (this.events.length > 0) { - throw new Error("Cannot initialise state after events are added"); - } - - this.startState?.setStateEvents(stateEvents, { timelineWasEmpty }); - this.endState?.setStateEvents(stateEvents, { timelineWasEmpty }); - } - - /** - * Forks the (live) timeline, taking ownership of the existing directional state of this timeline. - * All attached listeners will keep receiving state updates from the new live timeline state. - * The end state of this timeline gets replaced with an independent copy of the current RoomState, - * and will need a new pagination token if it ever needs to paginate forwards. - - * @param direction - EventTimeline.BACKWARDS to get the state at the - * start of the timeline; EventTimeline.FORWARDS to get the state at the end - * of the timeline. - * - * @returns the new timeline - */ - public forkLive(direction: Direction): EventTimeline { - const forkState = this.getState(direction); - const timeline = new EventTimeline(this.eventTimelineSet); - timeline.startState = forkState?.clone(); - // Now clobber the end state of the new live timeline with that from the - // previous live timeline. It will be identical except that we'll keep - // using the same RoomMember objects for the 'live' set of members with any - // listeners still attached - timeline.endState = forkState; - // Firstly, we just stole the current timeline's end state, so it needs a new one. - // Make an immutable copy of the state so back pagination will get the correct sentinels. - this.endState = forkState?.clone(); - return timeline; - } - - /** - * Creates an independent timeline, inheriting the directional state from this timeline. - * - * @param direction - EventTimeline.BACKWARDS to get the state at the - * start of the timeline; EventTimeline.FORWARDS to get the state at the end - * of the timeline. - * - * @returns the new timeline - */ - public fork(direction: Direction): EventTimeline { - const forkState = this.getState(direction); - const timeline = new EventTimeline(this.eventTimelineSet); - timeline.startState = forkState?.clone(); - timeline.endState = forkState?.clone(); - return timeline; - } - - /** - * Get the ID of the room for this timeline - * @returns room ID - */ - public getRoomId(): string | null { - return this.roomId; - } - - /** - * Get the filter for this timeline's timelineSet (if any) - * @returns filter - */ - public getFilter(): Filter | undefined { - return this.eventTimelineSet.getFilter(); - } - - /** - * Get the timelineSet for this timeline - * @returns timelineSet - */ - public getTimelineSet(): EventTimelineSet { - return this.eventTimelineSet; - } - - /** - * Get the base index. - * - * <p>This is an index which is incremented when events are prepended to the - * timeline. An individual event therefore stays at the same index in the array - * relative to the base index (although note that a given event's index may - * well be less than the base index, thus giving that event a negative relative - * index). - */ - public getBaseIndex(): number { - return this.baseIndex; - } - - /** - * Get the list of events in this context - * - * @returns An array of MatrixEvents - */ - public getEvents(): MatrixEvent[] { - return this.events; - } - - /** - * Get the room state at the start/end of the timeline - * - * @param direction - EventTimeline.BACKWARDS to get the state at the - * start of the timeline; EventTimeline.FORWARDS to get the state at the end - * of the timeline. - * - * @returns state at the start/end of the timeline - */ - public getState(direction: Direction): RoomState | undefined { - if (direction == EventTimeline.BACKWARDS) { - return this.startState; - } else if (direction == EventTimeline.FORWARDS) { - return this.endState; - } else { - throw new Error("Invalid direction '" + direction + "'"); - } - } - - /** - * Get a pagination token - * - * @param direction - EventTimeline.BACKWARDS to get the pagination - * token for going backwards in time; EventTimeline.FORWARDS to get the - * pagination token for going forwards in time. - * - * @returns pagination token - */ - public getPaginationToken(direction: Direction): string | null { - if (this.roomId) { - return this.getState(direction)!.paginationToken; - } else if (direction === Direction.Backward) { - return this.startToken; - } else { - return this.endToken; - } - } - - /** - * Set a pagination token - * - * @param token - pagination token - * - * @param direction - EventTimeline.BACKWARDS to set the pagination - * token for going backwards in time; EventTimeline.FORWARDS to set the - * pagination token for going forwards in time. - */ - public setPaginationToken(token: string | null, direction: Direction): void { - if (this.roomId) { - this.getState(direction)!.paginationToken = token; - } else if (direction === Direction.Backward) { - this.startToken = token; - } else { - this.endToken = token; - } - } - - /** - * Get the next timeline in the series - * - * @param direction - EventTimeline.BACKWARDS to get the previous - * timeline; EventTimeline.FORWARDS to get the next timeline. - * - * @returns previous or following timeline, if they have been - * joined up. - */ - public getNeighbouringTimeline(direction: Direction): EventTimeline | null { - if (direction == EventTimeline.BACKWARDS) { - return this.prevTimeline; - } else if (direction == EventTimeline.FORWARDS) { - return this.nextTimeline; - } else { - throw new Error("Invalid direction '" + direction + "'"); - } - } - - /** - * Set the next timeline in the series - * - * @param neighbour - previous/following timeline - * - * @param direction - EventTimeline.BACKWARDS to set the previous - * timeline; EventTimeline.FORWARDS to set the next timeline. - * - * @throws Error if an attempt is made to set the neighbouring timeline when - * it is already set. - */ - public setNeighbouringTimeline(neighbour: EventTimeline, direction: Direction): void { - if (this.getNeighbouringTimeline(direction)) { - throw new Error( - "timeline already has a neighbouring timeline - " + - "cannot reset neighbour (direction: " + - direction + - ")", - ); - } - - if (direction == EventTimeline.BACKWARDS) { - this.prevTimeline = neighbour; - } else if (direction == EventTimeline.FORWARDS) { - this.nextTimeline = neighbour; - } else { - throw new Error("Invalid direction '" + direction + "'"); - } - - // make sure we don't try to paginate this timeline - this.setPaginationToken(null, direction); - } - - /** - * Add a new event to the timeline, and update the state - * - * @param event - new event - * @param options - addEvent options - */ - public addEvent(event: MatrixEvent, { toStartOfTimeline, roomState, timelineWasEmpty }: IAddEventOptions): void; - /** - * @deprecated In favor of the overload with `IAddEventOptions` - */ - public addEvent(event: MatrixEvent, toStartOfTimeline: boolean, roomState?: RoomState): void; - public addEvent( - event: MatrixEvent, - toStartOfTimelineOrOpts: boolean | IAddEventOptions, - roomState?: RoomState, - ): void { - let toStartOfTimeline = !!toStartOfTimelineOrOpts; - let timelineWasEmpty: boolean | undefined; - if (typeof toStartOfTimelineOrOpts === "object") { - ({ toStartOfTimeline, roomState, timelineWasEmpty } = toStartOfTimelineOrOpts); - } else if (toStartOfTimelineOrOpts !== undefined) { - // Deprecation warning - // FIXME: Remove after 2023-06-01 (technical debt) - logger.warn( - "Overload deprecated: " + - "`EventTimeline.addEvent(event, toStartOfTimeline, roomState?)` " + - "is deprecated in favor of the overload with `EventTimeline.addEvent(event, IAddEventOptions)`", - ); - } - - if (!roomState) { - roomState = toStartOfTimeline ? this.startState : this.endState; - } - - const timelineSet = this.getTimelineSet(); - - if (timelineSet.room) { - EventTimeline.setEventMetadata(event, roomState!, toStartOfTimeline); - - // modify state but only on unfiltered timelineSets - if (event.isState() && timelineSet.room.getUnfilteredTimelineSet() === timelineSet) { - roomState?.setStateEvents([event], { timelineWasEmpty }); - // it is possible that the act of setting the state event means we - // can set more metadata (specifically sender/target props), so try - // it again if the prop wasn't previously set. It may also mean that - // the sender/target is updated (if the event set was a room member event) - // so we want to use the *updated* member (new avatar/name) instead. - // - // However, we do NOT want to do this on member events if we're going - // back in time, else we'll set the .sender value for BEFORE the given - // member event, whereas we want to set the .sender value for the ACTUAL - // member event itself. - if (!event.sender || (event.getType() === EventType.RoomMember && !toStartOfTimeline)) { - EventTimeline.setEventMetadata(event, roomState!, toStartOfTimeline); - } - } - } - - let insertIndex: number; - - if (toStartOfTimeline) { - insertIndex = 0; - } else { - insertIndex = this.events.length; - } - - this.events.splice(insertIndex, 0, event); // insert element - if (toStartOfTimeline) { - this.baseIndex++; - } - } - - /** - * Remove an event from the timeline - * - * @param eventId - ID of event to be removed - * @returns removed event, or null if not found - */ - public removeEvent(eventId: string): MatrixEvent | null { - for (let i = this.events.length - 1; i >= 0; i--) { - const ev = this.events[i]; - if (ev.getId() == eventId) { - this.events.splice(i, 1); - if (i < this.baseIndex) { - this.baseIndex--; - } - return ev; - } - } - return null; - } - - /** - * Return a string to identify this timeline, for debugging - * - * @returns name for this timeline - */ - public toString(): string { - return this.name; - } -} |