38 lines
1.5 KiB
TypeScript
38 lines
1.5 KiB
TypeScript
import { EventTimelineSet, MatrixEvent } from 'matrix-js-sdk';
|
|||
|
|
import { getEventEdits, trimReplyFromBody } from './room';
|
||
|
|
import { DiffToken, wordDiff } from './wordDiff';
|
||
|
|
|
||
|
|
const isPlainText = (content: Record<string, unknown> | undefined): content is { body: string } =>
|
||
|
|
!!content &&
|
||
|
|
typeof content.body === 'string' &&
|
||
|
|
content.format === undefined &&
|
||
|
|
content.formatted_body === undefined;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* [Gitea #144] Word diff of the *last* edit to `mEvent`: the newest edit's body
|
||
|
|
* against the one it replaced (an earlier edit, or the original). Only for
|
||
|
|
* plain-text bodies — formatted edits return `undefined` and the caller falls
|
||
|
|
* back to the history viewer.
|
||
|
|
*/
|
||
|
|
export function getLastEditDiff(
|
||
|
|
mEvent: MatrixEvent,
|
||
|
|
timelineSet: EventTimelineSet,
|
||
|
|
): DiffToken[] | undefined {
|
||
|
|
const eventId = mEvent.getId();
|
||
|
|
if (!eventId) return undefined;
|
||
|
|
const relations = getEventEdits(timelineSet, eventId, mEvent.getType());
|
||
|
|
if (!relations) return undefined;
|
||
|
|
const edits = relations
|
||
|
|
.getRelations()
|
||
|
|
.filter((e) => e.getSender() === mEvent.getSender())
|
||
|
|
.sort((m1, m2) => m2.getTs() - m1.getTs());
|
||
|
|
const latest = edits[0];
|
||
|
|
if (!latest) return undefined;
|
||
|
|
const after = latest.getContent()['m.new_content'] as Record<string, unknown> | undefined;
|
||
|
|
const before = (edits[1]?.getContent()['m.new_content'] ?? mEvent.getContent()) as
|
||
|
|
| Record<string, unknown>
|
||
|
|
| undefined;
|
||
|
|
if (!isPlainText(after) || !isPlainText(before)) return undefined;
|
||
|
|
return wordDiff(trimReplyFromBody(before.body), trimReplyFromBody(after.body));
|
||
|
|
}
|