You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Make local echo work for threads (#2026)
This commit is contained in:
@ -23,7 +23,7 @@ describe("MatrixClient retrying", function() {
|
|||||||
);
|
);
|
||||||
httpBackend = testClient.httpBackend;
|
httpBackend = testClient.httpBackend;
|
||||||
client = testClient.client;
|
client = testClient.client;
|
||||||
room = new Room(roomId);
|
room = new Room(roomId, client, userId);
|
||||||
client.store.storeRoom(room);
|
client.store.storeRoom(room);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,7 +50,10 @@ describe("MatrixClient retrying", function() {
|
|||||||
|
|
||||||
it("should mark events as EventStatus.CANCELLED when cancelled", function() {
|
it("should mark events as EventStatus.CANCELLED when cancelled", function() {
|
||||||
// send a couple of events; the second will be queued
|
// send a couple of events; the second will be queued
|
||||||
const p1 = client.sendMessage(roomId, "m1").then(function(ev) {
|
const p1 = client.sendMessage(roomId, {
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"body": "m1",
|
||||||
|
}).then(function(ev) {
|
||||||
// we expect the first message to fail
|
// we expect the first message to fail
|
||||||
throw new Error('Message 1 unexpectedly sent successfully');
|
throw new Error('Message 1 unexpectedly sent successfully');
|
||||||
}, (e) => {
|
}, (e) => {
|
||||||
@ -60,7 +63,10 @@ describe("MatrixClient retrying", function() {
|
|||||||
// XXX: it turns out that the promise returned by this message
|
// XXX: it turns out that the promise returned by this message
|
||||||
// never gets resolved.
|
// never gets resolved.
|
||||||
// https://github.com/matrix-org/matrix-js-sdk/issues/496
|
// https://github.com/matrix-org/matrix-js-sdk/issues/496
|
||||||
client.sendMessage(roomId, "m2");
|
client.sendMessage(roomId, {
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"body": "m2",
|
||||||
|
});
|
||||||
|
|
||||||
// both events should be in the timeline at this point
|
// both events should be in the timeline at this point
|
||||||
const tl = room.getLiveTimeline().getEvents();
|
const tl = room.getLiveTimeline().getEvents();
|
||||||
@ -88,7 +94,7 @@ describe("MatrixClient retrying", function() {
|
|||||||
}).respond(400); // fail the first message
|
}).respond(400); // fail the first message
|
||||||
|
|
||||||
// wait for the localecho of ev1 to be updated
|
// wait for the localecho of ev1 to be updated
|
||||||
const p3 = new Promise((resolve, reject) => {
|
const p3 = new Promise<void>((resolve, reject) => {
|
||||||
room.on("Room.localEchoUpdated", (ev0) => {
|
room.on("Room.localEchoUpdated", (ev0) => {
|
||||||
if (ev0 === ev1) {
|
if (ev0 === ev1) {
|
||||||
resolve();
|
resolve();
|
326
src/client.ts
326
src/client.ts
@ -689,6 +689,12 @@ interface IRoomsKeysResponse {
|
|||||||
}
|
}
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
|
// We're using this constant for methods overloading and inspect whether a variable
|
||||||
|
// contains an eventId or not. This was required to ensure backwards compatibility
|
||||||
|
// of methods for threads
|
||||||
|
// Probably not the most graceful solution but does a good enough job for now
|
||||||
|
const EVENT_ID_PREFIX = "$";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Matrix Client. Only directly construct this if you want to use
|
* Represents a Matrix Client. Only directly construct this if you want to use
|
||||||
* custom modules. Normally, {@link createClient} should be used
|
* custom modules. Normally, {@link createClient} should be used
|
||||||
@ -3392,10 +3398,11 @@ export class MatrixClient extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {string} eventType
|
* @param {string} eventType
|
||||||
* @param {Object} content
|
* @param {Object} content
|
||||||
* @param {string} txnId Optional.
|
* @param {string} txnId Optional.
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to an empty object {}
|
* @return {Promise} Resolves: to an empty object {}
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3405,20 +3412,45 @@ export class MatrixClient extends EventEmitter {
|
|||||||
content: IContent,
|
content: IContent,
|
||||||
txnId?: string,
|
txnId?: string,
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendEvent(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
eventType: string,
|
||||||
|
content: IContent,
|
||||||
|
txnId?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendEvent(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
eventType: string | IContent,
|
||||||
|
content: IContent | string,
|
||||||
|
txnId?: string | Callback,
|
||||||
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
return this.sendCompleteEvent(roomId, { type: eventType, content }, txnId, callback);
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
|
callback = txnId as Callback;
|
||||||
|
txnId = content as string;
|
||||||
|
content = eventType as IContent;
|
||||||
|
eventType = threadId;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
|
return this.sendCompleteEvent(roomId, threadId, { type: eventType, content }, txnId as string, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {object} eventObject An object with the partial structure of an event, to which event_id, user_id, room_id and origin_server_ts will be added.
|
* @param {object} eventObject An object with the partial structure of an event, to which event_id, user_id, room_id and origin_server_ts will be added.
|
||||||
* @param {string} txnId Optional.
|
* @param {string} txnId Optional.
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to an empty object {}
|
* @return {Promise} Resolves: to an empty object {}
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
private sendCompleteEvent(
|
private sendCompleteEvent(
|
||||||
roomId: string,
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
eventObject: any,
|
eventObject: any,
|
||||||
txnId?: string,
|
txnId?: string,
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
@ -3444,6 +3476,10 @@ export class MatrixClient extends EventEmitter {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const room = this.getRoom(roomId);
|
const room = this.getRoom(roomId);
|
||||||
|
const thread = room?.threads.get(threadId);
|
||||||
|
if (thread) {
|
||||||
|
localEvent.setThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
// if this is a relation or redaction of an event
|
// if this is a relation or redaction of an event
|
||||||
// that hasn't been sent yet (e.g. with a local id starting with a ~)
|
// that hasn't been sent yet (e.g. with a local id starting with a ~)
|
||||||
@ -3460,12 +3496,12 @@ export class MatrixClient extends EventEmitter {
|
|||||||
const type = localEvent.getType();
|
const type = localEvent.getType();
|
||||||
logger.log(`sendEvent of type ${type} in ${roomId} with txnId ${txnId}`);
|
logger.log(`sendEvent of type ${type} in ${roomId} with txnId ${txnId}`);
|
||||||
|
|
||||||
localEvent.setTxnId(txnId);
|
localEvent.setTxnId(txnId as string);
|
||||||
localEvent.setStatus(EventStatus.SENDING);
|
localEvent.setStatus(EventStatus.SENDING);
|
||||||
|
|
||||||
// add this event immediately to the local store as 'sending'.
|
// add this event immediately to the local store as 'sending'.
|
||||||
if (room) {
|
if (room) {
|
||||||
room.addPendingEvent(localEvent, txnId);
|
room.addPendingEvent(localEvent, txnId as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
// addPendingEvent can change the state to NOT_SENT if it believes
|
// addPendingEvent can change the state to NOT_SENT if it believes
|
||||||
@ -3655,7 +3691,7 @@ export class MatrixClient extends EventEmitter {
|
|||||||
* supplied.
|
* supplied.
|
||||||
* @param {object|module:client.callback} cbOrOpts
|
* @param {object|module:client.callback} cbOrOpts
|
||||||
* Options to pass on, may contain `reason`.
|
* Options to pass on, may contain `reason`.
|
||||||
* Can be callback for backwards compatibility.
|
* Can be callback for backwards compatibility. Deprecated
|
||||||
* @return {Promise} Resolves: TODO
|
* @return {Promise} Resolves: TODO
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3664,22 +3700,43 @@ export class MatrixClient extends EventEmitter {
|
|||||||
eventId: string,
|
eventId: string,
|
||||||
txnId?: string,
|
txnId?: string,
|
||||||
cbOrOpts?: Callback | IRedactOpts,
|
cbOrOpts?: Callback | IRedactOpts,
|
||||||
|
);
|
||||||
|
public redactEvent(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
eventId: string,
|
||||||
|
txnId?: string,
|
||||||
|
cbOrOpts?: Callback | IRedactOpts,
|
||||||
|
);
|
||||||
|
public redactEvent(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
eventId: string,
|
||||||
|
txnId?: string | Callback | IRedactOpts,
|
||||||
|
cbOrOpts?: Callback | IRedactOpts,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
|
cbOrOpts = txnId as (Callback | IRedactOpts);
|
||||||
|
txnId = eventId;
|
||||||
|
eventId = threadId;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
const opts = typeof (cbOrOpts) === 'object' ? cbOrOpts : {};
|
const opts = typeof (cbOrOpts) === 'object' ? cbOrOpts : {};
|
||||||
const reason = opts.reason;
|
const reason = opts.reason;
|
||||||
const callback = typeof (cbOrOpts) === 'function' ? cbOrOpts : undefined;
|
const callback = typeof (cbOrOpts) === 'function' ? cbOrOpts : undefined;
|
||||||
return this.sendCompleteEvent(roomId, {
|
return this.sendCompleteEvent(roomId, threadId, {
|
||||||
type: EventType.RoomRedaction,
|
type: EventType.RoomRedaction,
|
||||||
content: { reason: reason },
|
content: { reason: reason },
|
||||||
redacts: eventId,
|
redacts: eventId,
|
||||||
}, txnId, callback);
|
}, txnId as string, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {Object} content
|
* @param {Object} content
|
||||||
* @param {string} txnId Optional.
|
* @param {string} txnId Optional.
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to an ISendEventResponse object
|
* @return {Promise} Resolves: to an ISendEventResponse object
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3688,19 +3745,47 @@ export class MatrixClient extends EventEmitter {
|
|||||||
content: IContent,
|
content: IContent,
|
||||||
txnId?: string,
|
txnId?: string,
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
content: IContent,
|
||||||
|
txnId?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null | IContent,
|
||||||
|
content: IContent | string,
|
||||||
|
txnId?: string | Callback,
|
||||||
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
|
if (typeof threadId !== "string" && threadId !== null) {
|
||||||
|
callback = txnId as Callback;
|
||||||
|
txnId = content as string;
|
||||||
|
content = threadId as IContent;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
if (utils.isFunction(txnId)) {
|
if (utils.isFunction(txnId)) {
|
||||||
callback = txnId as any as Callback; // for legacy
|
callback = txnId as any as Callback; // for legacy
|
||||||
txnId = undefined;
|
txnId = undefined;
|
||||||
}
|
}
|
||||||
return this.sendEvent(roomId, EventType.RoomMessage, content, txnId, callback);
|
return this.sendEvent(
|
||||||
|
roomId,
|
||||||
|
threadId as (string | null),
|
||||||
|
EventType.RoomMessage,
|
||||||
|
content as IContent,
|
||||||
|
txnId as string,
|
||||||
|
callback,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {string} body
|
* @param {string} body
|
||||||
* @param {string} txnId Optional.
|
* @param {string} txnId Optional.
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to an empty object {}
|
* @return {Promise} Resolves: to an empty object {}
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3709,29 +3794,76 @@ export class MatrixClient extends EventEmitter {
|
|||||||
body: string,
|
body: string,
|
||||||
txnId?: string,
|
txnId?: string,
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendTextMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
txnId?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendTextMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
txnId?: string | Callback,
|
||||||
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
|
callback = txnId as Callback;
|
||||||
|
txnId = body;
|
||||||
|
body = threadId;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
const content = ContentHelpers.makeTextMessage(body);
|
const content = ContentHelpers.makeTextMessage(body);
|
||||||
return this.sendMessage(roomId, content, txnId, callback);
|
return this.sendMessage(roomId, threadId, content, txnId as string, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {string} body
|
* @param {string} body
|
||||||
* @param {string} txnId Optional.
|
* @param {string} txnId Optional.
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to a ISendEventResponse object
|
* @return {Promise} Resolves: to a ISendEventResponse object
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public sendNotice(roomId: string, body: string, txnId?: string, callback?: Callback): Promise<ISendEventResponse> {
|
public sendNotice(
|
||||||
|
roomId: string,
|
||||||
|
body: string,
|
||||||
|
txnId?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendNotice(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
txnId?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendNotice(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
txnId?: string | Callback,
|
||||||
|
callback?: Callback,
|
||||||
|
): Promise<ISendEventResponse> {
|
||||||
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
|
callback = txnId as Callback;
|
||||||
|
txnId = body;
|
||||||
|
body = threadId;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
const content = ContentHelpers.makeNotice(body);
|
const content = ContentHelpers.makeNotice(body);
|
||||||
return this.sendMessage(roomId, content, txnId, callback);
|
return this.sendMessage(roomId, threadId, content, txnId as string, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {string} body
|
* @param {string} body
|
||||||
* @param {string} txnId Optional.
|
* @param {string} txnId Optional.
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to a ISendEventResponse object
|
* @return {Promise} Resolves: to a ISendEventResponse object
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3740,17 +3872,38 @@ export class MatrixClient extends EventEmitter {
|
|||||||
body: string,
|
body: string,
|
||||||
txnId?: string,
|
txnId?: string,
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendEmoteMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
txnId?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendEmoteMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
txnId?: string | Callback,
|
||||||
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
|
callback = txnId as Callback;
|
||||||
|
txnId = body;
|
||||||
|
body = threadId;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
const content = ContentHelpers.makeEmoteMessage(body);
|
const content = ContentHelpers.makeEmoteMessage(body);
|
||||||
return this.sendMessage(roomId, content, txnId, callback);
|
return this.sendMessage(roomId, threadId, content, txnId as string, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
* @param {Object} info
|
* @param {Object} info
|
||||||
* @param {string} text
|
* @param {string} text
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to a ISendEventResponse object
|
* @return {Promise} Resolves: to a ISendEventResponse object
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3758,9 +3911,32 @@ export class MatrixClient extends EventEmitter {
|
|||||||
roomId: string,
|
roomId: string,
|
||||||
url: string,
|
url: string,
|
||||||
info?: IImageInfo,
|
info?: IImageInfo,
|
||||||
text = "Image",
|
text?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendImageMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
url: string,
|
||||||
|
info?: IImageInfo,
|
||||||
|
text?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendImageMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
url: string | IImageInfo,
|
||||||
|
info?: IImageInfo | string,
|
||||||
|
text: Callback | string = "Image",
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
|
callback = text as Callback;
|
||||||
|
text = info as string || "Image";
|
||||||
|
info = url as IImageInfo;
|
||||||
|
url = threadId as string;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
if (utils.isFunction(text)) {
|
if (utils.isFunction(text)) {
|
||||||
callback = text as any as Callback; // legacy
|
callback = text as any as Callback; // legacy
|
||||||
text = undefined;
|
text = undefined;
|
||||||
@ -3771,15 +3947,16 @@ export class MatrixClient extends EventEmitter {
|
|||||||
info: info,
|
info: info,
|
||||||
body: text,
|
body: text,
|
||||||
};
|
};
|
||||||
return this.sendMessage(roomId, content, undefined, callback);
|
return this.sendMessage(roomId, threadId, content, undefined, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
* @param {Object} info
|
* @param {Object} info
|
||||||
* @param {string} text
|
* @param {string} text
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to a ISendEventResponse object
|
* @return {Promise} Resolves: to a ISendEventResponse object
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3787,9 +3964,32 @@ export class MatrixClient extends EventEmitter {
|
|||||||
roomId: string,
|
roomId: string,
|
||||||
url: string,
|
url: string,
|
||||||
info?: IImageInfo,
|
info?: IImageInfo,
|
||||||
text = "Sticker",
|
text?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendStickerMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
url: string,
|
||||||
|
info?: IImageInfo,
|
||||||
|
text?: string,
|
||||||
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendStickerMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
url: string | IImageInfo,
|
||||||
|
info?: IImageInfo | string,
|
||||||
|
text: Callback | string = "Sticker",
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
|
callback = text as Callback;
|
||||||
|
text = info as string || "Sticker";
|
||||||
|
info = url as IImageInfo;
|
||||||
|
url = threadId as string;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
if (utils.isFunction(text)) {
|
if (utils.isFunction(text)) {
|
||||||
callback = text as any as Callback; // legacy
|
callback = text as any as Callback; // legacy
|
||||||
text = undefined;
|
text = undefined;
|
||||||
@ -3799,14 +3999,15 @@ export class MatrixClient extends EventEmitter {
|
|||||||
info: info,
|
info: info,
|
||||||
body: text,
|
body: text,
|
||||||
};
|
};
|
||||||
return this.sendEvent(roomId, EventType.Sticker, content, undefined, callback);
|
return this.sendEvent(roomId, threadId, EventType.Sticker, content, undefined, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {string} body
|
* @param {string} body
|
||||||
* @param {string} htmlBody
|
* @param {string} htmlBody
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to a ISendEventResponse object
|
* @return {Promise} Resolves: to a ISendEventResponse object
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3815,16 +4016,36 @@ export class MatrixClient extends EventEmitter {
|
|||||||
body: string,
|
body: string,
|
||||||
htmlBody: string,
|
htmlBody: string,
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendHtmlMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
htmlBody: string,
|
||||||
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendHtmlMessage(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
htmlBody: string | Callback,
|
||||||
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
const content = ContentHelpers.makeHtmlMessage(body, htmlBody);
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
return this.sendMessage(roomId, content, undefined, callback);
|
callback = htmlBody as Callback;
|
||||||
|
htmlBody = body as string;
|
||||||
|
body = threadId;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
|
const content = ContentHelpers.makeHtmlMessage(body, htmlBody as string);
|
||||||
|
return this.sendMessage(roomId, threadId, content, undefined, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
* @param {string} body
|
* @param {string} body
|
||||||
* @param {string} htmlBody
|
* @param {string} htmlBody
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to a ISendEventResponse object
|
* @return {Promise} Resolves: to a ISendEventResponse object
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3833,16 +4054,37 @@ export class MatrixClient extends EventEmitter {
|
|||||||
body: string,
|
body: string,
|
||||||
htmlBody: string,
|
htmlBody: string,
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendHtmlNotice(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
htmlBody: string,
|
||||||
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendHtmlNotice(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
htmlBody: string | Callback,
|
||||||
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
const content = ContentHelpers.makeHtmlNotice(body, htmlBody);
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
return this.sendMessage(roomId, content, undefined, callback);
|
callback = htmlBody as Callback;
|
||||||
|
htmlBody = body as string;
|
||||||
|
body = threadId;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
|
const content = ContentHelpers.makeHtmlNotice(body, htmlBody as string);
|
||||||
|
return this.sendMessage(roomId, threadId, content, undefined, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomId
|
* @param {string} roomId
|
||||||
|
* @param {string} threadId
|
||||||
* @param {string} body
|
* @param {string} body
|
||||||
* @param {string} htmlBody
|
* @param {string} htmlBody
|
||||||
* @param {module:client.callback} callback Optional.
|
* @param {module:client.callback} callback Optional. Deprecated
|
||||||
* @return {Promise} Resolves: to a ISendEventResponse object
|
* @return {Promise} Resolves: to a ISendEventResponse object
|
||||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
@ -3851,9 +4093,29 @@ export class MatrixClient extends EventEmitter {
|
|||||||
body: string,
|
body: string,
|
||||||
htmlBody: string,
|
htmlBody: string,
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
|
);
|
||||||
|
public sendHtmlEmote(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
htmlBody: string,
|
||||||
|
callback?: Callback,
|
||||||
|
)
|
||||||
|
public sendHtmlEmote(
|
||||||
|
roomId: string,
|
||||||
|
threadId: string | null,
|
||||||
|
body: string,
|
||||||
|
htmlBody: string | Callback,
|
||||||
|
callback?: Callback,
|
||||||
): Promise<ISendEventResponse> {
|
): Promise<ISendEventResponse> {
|
||||||
const content = ContentHelpers.makeHtmlEmote(body, htmlBody);
|
if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
|
||||||
return this.sendMessage(roomId, content, undefined, callback);
|
callback = htmlBody as Callback;
|
||||||
|
htmlBody = body as string;
|
||||||
|
body = threadId;
|
||||||
|
threadId = null;
|
||||||
|
}
|
||||||
|
const content = ContentHelpers.makeHtmlEmote(body, htmlBody as string);
|
||||||
|
return this.sendMessage(roomId, threadId, content, undefined, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +28,7 @@ import { Room } from "./room";
|
|||||||
import { Filter } from "../filter";
|
import { Filter } from "../filter";
|
||||||
import { EventType, RelationType } from "../@types/event";
|
import { EventType, RelationType } from "../@types/event";
|
||||||
import { RoomState } from "./room-state";
|
import { RoomState } from "./room-state";
|
||||||
|
import { Thread } from "./thread";
|
||||||
|
|
||||||
// var DEBUG = false;
|
// var DEBUG = false;
|
||||||
const DEBUG = true;
|
const DEBUG = true;
|
||||||
@ -153,18 +154,18 @@ export class EventTimelineSet extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
|
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
|
||||||
*/
|
*/
|
||||||
public getPendingEvents(): MatrixEvent[] {
|
public getPendingEvents(thread?: Thread): MatrixEvent[] {
|
||||||
if (!this.room || !this.displayPendingEvents) {
|
if (!this.room || !this.displayPendingEvents) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pendingEvents = this.room.getPendingEvents(thread);
|
||||||
if (this.filter) {
|
if (this.filter) {
|
||||||
return this.filter.filterRoomTimeline(this.room.getPendingEvents());
|
return this.filter.filterRoomTimeline(pendingEvents);
|
||||||
} else {
|
} else {
|
||||||
return this.room.getPendingEvents();
|
return pendingEvents;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the live timeline for this room.
|
* Get the live timeline for this room.
|
||||||
*
|
*
|
||||||
|
@ -225,12 +225,6 @@ export class Room extends EventEmitter {
|
|||||||
this.reEmitter = new ReEmitter(this);
|
this.reEmitter = new ReEmitter(this);
|
||||||
|
|
||||||
opts.pendingEventOrdering = opts.pendingEventOrdering || PendingEventOrdering.Chronological;
|
opts.pendingEventOrdering = opts.pendingEventOrdering || PendingEventOrdering.Chronological;
|
||||||
if (["chronological", "detached"].indexOf(opts.pendingEventOrdering) === -1) {
|
|
||||||
throw new Error(
|
|
||||||
"opts.pendingEventOrdering MUST be either 'chronological' or " +
|
|
||||||
"'detached'. Got: '" + opts.pendingEventOrdering + "'",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.name = roomId;
|
this.name = roomId;
|
||||||
|
|
||||||
@ -241,7 +235,7 @@ export class Room extends EventEmitter {
|
|||||||
|
|
||||||
this.fixUpLegacyTimelineFields();
|
this.fixUpLegacyTimelineFields();
|
||||||
|
|
||||||
if (this.opts.pendingEventOrdering == "detached") {
|
if (this.opts.pendingEventOrdering === PendingEventOrdering.Detached) {
|
||||||
this.pendingEventList = [];
|
this.pendingEventList = [];
|
||||||
const serializedPendingEventList = client.sessionStore.store.getItem(pendingEventsKey(this.roomId));
|
const serializedPendingEventList = client.sessionStore.store.getItem(pendingEventsKey(this.roomId));
|
||||||
if (serializedPendingEventList) {
|
if (serializedPendingEventList) {
|
||||||
@ -452,14 +446,16 @@ export class Room extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
|
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
|
||||||
*/
|
*/
|
||||||
public getPendingEvents(): MatrixEvent[] {
|
public getPendingEvents(thread?: Thread): MatrixEvent[] {
|
||||||
if (this.opts.pendingEventOrdering !== "detached") {
|
if (this.opts.pendingEventOrdering !== PendingEventOrdering.Detached) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Cannot call getPendingEvents with pendingEventOrdering == " +
|
"Cannot call getPendingEvents with pendingEventOrdering == " +
|
||||||
this.opts.pendingEventOrdering);
|
this.opts.pendingEventOrdering);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.pendingEventList;
|
return this.pendingEventList.filter(event => {
|
||||||
|
return !thread || thread.id === event.threadRootId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -469,7 +465,7 @@ export class Room extends EventEmitter {
|
|||||||
* @return {boolean} True if an element was removed.
|
* @return {boolean} True if an element was removed.
|
||||||
*/
|
*/
|
||||||
public removePendingEvent(eventId: string): boolean {
|
public removePendingEvent(eventId: string): boolean {
|
||||||
if (this.opts.pendingEventOrdering !== "detached") {
|
if (this.opts.pendingEventOrdering !== PendingEventOrdering.Detached) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Cannot call removePendingEvent with pendingEventOrdering == " +
|
"Cannot call removePendingEvent with pendingEventOrdering == " +
|
||||||
this.opts.pendingEventOrdering);
|
this.opts.pendingEventOrdering);
|
||||||
@ -495,7 +491,7 @@ export class Room extends EventEmitter {
|
|||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
public hasPendingEvent(eventId: string): boolean {
|
public hasPendingEvent(eventId: string): boolean {
|
||||||
if (this.opts.pendingEventOrdering !== "detached") {
|
if (this.opts.pendingEventOrdering !== PendingEventOrdering.Detached) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,7 +505,7 @@ export class Room extends EventEmitter {
|
|||||||
* @return {MatrixEvent}
|
* @return {MatrixEvent}
|
||||||
*/
|
*/
|
||||||
public getPendingEvent(eventId: string): MatrixEvent | null {
|
public getPendingEvent(eventId: string): MatrixEvent | null {
|
||||||
if (this.opts.pendingEventOrdering !== "detached") {
|
if (this.opts.pendingEventOrdering !== PendingEventOrdering.Detached) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,7 +852,13 @@ export class Room extends EventEmitter {
|
|||||||
* the given event, or null if unknown
|
* the given event, or null if unknown
|
||||||
*/
|
*/
|
||||||
public getTimelineForEvent(eventId: string): EventTimeline {
|
public getTimelineForEvent(eventId: string): EventTimeline {
|
||||||
return this.getUnfilteredTimelineSet().getTimelineForEvent(eventId);
|
const event = this.findEventById(eventId);
|
||||||
|
const thread = this.findThreadForEvent(event);
|
||||||
|
if (thread) {
|
||||||
|
return thread.timelineSet.getLiveTimeline();
|
||||||
|
} else {
|
||||||
|
return this.getUnfilteredTimelineSet().getTimelineForEvent(eventId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1403,13 +1405,6 @@ export class Room extends EventEmitter {
|
|||||||
* unique transaction id.
|
* unique transaction id.
|
||||||
*/
|
*/
|
||||||
public addPendingEvent(event: MatrixEvent, txnId: string): void {
|
public addPendingEvent(event: MatrixEvent, txnId: string): void {
|
||||||
// TODO: Enable "pending events" for threads
|
|
||||||
// There's a fair few things to update to make them work with Threads
|
|
||||||
// Will get back to it when the plan is to build a more polished UI ready for production
|
|
||||||
if (this.client?.supportsExperimentalThreads() && event.threadRootId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.status !== EventStatus.SENDING && event.status !== EventStatus.NOT_SENT) {
|
if (event.status !== EventStatus.SENDING && event.status !== EventStatus.NOT_SENT) {
|
||||||
throw new Error("addPendingEvent called on an event with status " +
|
throw new Error("addPendingEvent called on an event with status " +
|
||||||
event.status);
|
event.status);
|
||||||
@ -1426,8 +1421,8 @@ export class Room extends EventEmitter {
|
|||||||
EventTimeline.setEventMetadata(event, this.getLiveTimeline().getState(EventTimeline.FORWARDS), false);
|
EventTimeline.setEventMetadata(event, this.getLiveTimeline().getState(EventTimeline.FORWARDS), false);
|
||||||
|
|
||||||
this.txnToEvent[txnId] = event;
|
this.txnToEvent[txnId] = event;
|
||||||
|
const thread = this.threads.get(event.threadRootId);
|
||||||
if (this.opts.pendingEventOrdering == "detached") {
|
if (this.opts.pendingEventOrdering === PendingEventOrdering.Detached && !thread) {
|
||||||
if (this.pendingEventList.some((e) => e.status === EventStatus.NOT_SENT)) {
|
if (this.pendingEventList.some((e) => e.status === EventStatus.NOT_SENT)) {
|
||||||
logger.warn("Setting event as NOT_SENT due to messages in the same state");
|
logger.warn("Setting event as NOT_SENT due to messages in the same state");
|
||||||
event.setStatus(EventStatus.NOT_SENT);
|
event.setStatus(EventStatus.NOT_SENT);
|
||||||
@ -1446,7 +1441,7 @@ export class Room extends EventEmitter {
|
|||||||
let redactedEvent = this.pendingEventList &&
|
let redactedEvent = this.pendingEventList &&
|
||||||
this.pendingEventList.find(e => e.getId() === redactId);
|
this.pendingEventList.find(e => e.getId() === redactId);
|
||||||
if (!redactedEvent) {
|
if (!redactedEvent) {
|
||||||
redactedEvent = this.getUnfilteredTimelineSet().findEventById(redactId);
|
redactedEvent = this.findEventById(redactId);
|
||||||
}
|
}
|
||||||
if (redactedEvent) {
|
if (redactedEvent) {
|
||||||
redactedEvent.markLocallyRedacted(event);
|
redactedEvent.markLocallyRedacted(event);
|
||||||
@ -1454,16 +1449,21 @@ export class Room extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < this.timelineSets.length; i++) {
|
if (thread) {
|
||||||
const timelineSet = this.timelineSets[i];
|
thread.timelineSet.addEventToTimeline(event,
|
||||||
if (timelineSet.getFilter()) {
|
thread.timelineSet.getLiveTimeline(), false);
|
||||||
if (timelineSet.getFilter().filterRoomTimeline([event]).length) {
|
} else {
|
||||||
|
for (let i = 0; i < this.timelineSets.length; i++) {
|
||||||
|
const timelineSet = this.timelineSets[i];
|
||||||
|
if (timelineSet.getFilter()) {
|
||||||
|
if (timelineSet.getFilter().filterRoomTimeline([event]).length) {
|
||||||
|
timelineSet.addEventToTimeline(event,
|
||||||
|
timelineSet.getLiveTimeline(), false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
timelineSet.addEventToTimeline(event,
|
timelineSet.addEventToTimeline(event,
|
||||||
timelineSet.getLiveTimeline(), false);
|
timelineSet.getLiveTimeline(), false);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
timelineSet.addEventToTimeline(event,
|
|
||||||
timelineSet.getLiveTimeline(), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1521,16 +1521,21 @@ export class Room extends EventEmitter {
|
|||||||
* @param {module:models/event.MatrixEvent} event the relation event that needs to be aggregated.
|
* @param {module:models/event.MatrixEvent} event the relation event that needs to be aggregated.
|
||||||
*/
|
*/
|
||||||
private aggregateNonLiveRelation(event: MatrixEvent): void {
|
private aggregateNonLiveRelation(event: MatrixEvent): void {
|
||||||
// TODO: We should consider whether this means it would be a better
|
const thread = this.findThreadForEvent(event);
|
||||||
// design to lift the relations handling up to the room instead.
|
if (thread) {
|
||||||
for (let i = 0; i < this.timelineSets.length; i++) {
|
thread.timelineSet.aggregateRelations(event);
|
||||||
const timelineSet = this.timelineSets[i];
|
} else {
|
||||||
if (timelineSet.getFilter()) {
|
// TODO: We should consider whether this means it would be a better
|
||||||
if (timelineSet.getFilter().filterRoomTimeline([event]).length) {
|
// design to lift the relations handling up to the room instead.
|
||||||
|
for (let i = 0; i < this.timelineSets.length; i++) {
|
||||||
|
const timelineSet = this.timelineSets[i];
|
||||||
|
if (timelineSet.getFilter()) {
|
||||||
|
if (timelineSet.getFilter().filterRoomTimeline([event]).length) {
|
||||||
|
timelineSet.aggregateRelations(event);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
timelineSet.aggregateRelations(event);
|
timelineSet.aggregateRelations(event);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
timelineSet.aggregateRelations(event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1571,11 +1576,16 @@ export class Room extends EventEmitter {
|
|||||||
// any, which is good, because we don't want to try decoding it again).
|
// any, which is good, because we don't want to try decoding it again).
|
||||||
localEvent.handleRemoteEcho(remoteEvent.event);
|
localEvent.handleRemoteEcho(remoteEvent.event);
|
||||||
|
|
||||||
for (let i = 0; i < this.timelineSets.length; i++) {
|
const thread = this.threads.get(remoteEvent.threadRootId);
|
||||||
const timelineSet = this.timelineSets[i];
|
if (thread) {
|
||||||
|
thread.timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < this.timelineSets.length; i++) {
|
||||||
|
const timelineSet = this.timelineSets[i];
|
||||||
|
|
||||||
// if it's already in the timeline, update the timeline map. If it's not, add it.
|
// if it's already in the timeline, update the timeline map. If it's not, add it.
|
||||||
timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
|
timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit("Room.localEchoUpdated", localEvent, this,
|
this.emit("Room.localEchoUpdated", localEvent, this,
|
||||||
@ -1608,7 +1618,7 @@ export class Room extends EventEmitter {
|
|||||||
|
|
||||||
// SENT races against /sync, so we have to special-case it.
|
// SENT races against /sync, so we have to special-case it.
|
||||||
if (newStatus == EventStatus.SENT) {
|
if (newStatus == EventStatus.SENT) {
|
||||||
const timeline = this.getUnfilteredTimelineSet().eventIdToTimeline(newEventId);
|
const timeline = this.getTimelineForEvent(newEventId);
|
||||||
if (timeline) {
|
if (timeline) {
|
||||||
// we've already received the event via the event stream.
|
// we've already received the event via the event stream.
|
||||||
// nothing more to do here.
|
// nothing more to do here.
|
||||||
@ -1636,11 +1646,16 @@ export class Room extends EventEmitter {
|
|||||||
// update the event id
|
// update the event id
|
||||||
event.replaceLocalEventId(newEventId);
|
event.replaceLocalEventId(newEventId);
|
||||||
|
|
||||||
// if the event was already in the timeline (which will be the case if
|
const thread = this.findThreadForEvent(event);
|
||||||
// opts.pendingEventOrdering==chronological), we need to update the
|
if (thread) {
|
||||||
// timeline map.
|
thread.timelineSet.replaceEventId(oldEventId, newEventId);
|
||||||
for (let i = 0; i < this.timelineSets.length; i++) {
|
} else {
|
||||||
this.timelineSets[i].replaceEventId(oldEventId, newEventId);
|
// if the event was already in the timeline (which will be the case if
|
||||||
|
// opts.pendingEventOrdering==chronological), we need to update the
|
||||||
|
// timeline map.
|
||||||
|
for (let i = 0; i < this.timelineSets.length; i++) {
|
||||||
|
this.timelineSets[i].replaceEventId(oldEventId, newEventId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (newStatus == EventStatus.CANCELLED) {
|
} else if (newStatus == EventStatus.CANCELLED) {
|
||||||
// remove it from the pending event list, or the timeline.
|
// remove it from the pending event list, or the timeline.
|
||||||
|
@ -55,11 +55,20 @@ export class Thread extends TypedEventEmitter<ThreadEvent> {
|
|||||||
this.timelineSet = new EventTimelineSet(this.room, {
|
this.timelineSet = new EventTimelineSet(this.room, {
|
||||||
unstableClientRelationAggregation: true,
|
unstableClientRelationAggregation: true,
|
||||||
timelineSupport: true,
|
timelineSupport: true,
|
||||||
pendingEvents: false,
|
pendingEvents: true,
|
||||||
});
|
});
|
||||||
events.forEach(event => this.addEvent(event));
|
events.forEach(event => this.addEvent(event));
|
||||||
|
|
||||||
|
room.on("Room.localEchoUpdated", this.onEcho);
|
||||||
|
room.on("Room.timeline", this.onEcho);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onEcho = (event: MatrixEvent) => {
|
||||||
|
if (this.timelineSet.eventIdToTimeline(event.getId())) {
|
||||||
|
this.emit(ThreadEvent.Update, this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an event to the thread and updates
|
* Add an event to the thread and updates
|
||||||
* the tail/root references if needed
|
* the tail/root references if needed
|
||||||
|
Reference in New Issue
Block a user