The schedule modal took only a plain body and rebuilt {body, msgtype},
dropping formatted_body, m.mentions and m.relates_to. It now receives
the full IContent; an unedited body is sent verbatim, an edited body
drops the now-stale formatted_body but keeps mentions and the reply/
thread relation. Reschedule from the tray preserves them too.
Unit-tested (mergeScheduledBody).
Fixes #36
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
53 lines
2.1 KiB
TypeScript
53 lines
2.1 KiB
TypeScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { IContent } from 'matrix-js-sdk';
|
|
import { mergeScheduledBody } from './ScheduleMessageModal';
|
|
|
|
// [Gitea #36] Pure merge of the modal textarea back into the composer-built
|
|
// content: verbatim when unedited, body-only replacement (rich HTML dropped,
|
|
// mentions + relation kept) when edited.
|
|
|
|
const richContent: IContent = {
|
|
msgtype: 'm.text',
|
|
body: 'hello **bold** @alice',
|
|
format: 'org.matrix.custom.html',
|
|
formatted_body: 'hello <b>bold</b> <a href="https://matrix.to/#/@alice:x">alice</a>',
|
|
'm.mentions': { user_ids: ['@alice:x'] },
|
|
'm.relates_to': {
|
|
'm.in_reply_to': { event_id: '$reply' },
|
|
rel_type: 'm.thread',
|
|
event_id: '$root',
|
|
is_falling_back: false,
|
|
},
|
|
};
|
|
|
|
test('mergeScheduledBody returns the content verbatim when the body is unedited', () => {
|
|
assert.equal(mergeScheduledBody(richContent, richContent.body), richContent);
|
|
// Whitespace-only differences (the textarea value is trimmed) still count as unedited.
|
|
assert.equal(mergeScheduledBody(richContent, ` ${richContent.body}\n`), richContent);
|
|
});
|
|
|
|
test('mergeScheduledBody drops stale formatting but keeps mentions and relation on edit', () => {
|
|
const merged = mergeScheduledBody(richContent, 'edited text ');
|
|
assert.deepEqual(merged, {
|
|
msgtype: 'm.text',
|
|
body: 'edited text',
|
|
'm.mentions': { user_ids: ['@alice:x'] },
|
|
'm.relates_to': richContent['m.relates_to'],
|
|
});
|
|
assert.equal('format' in merged, false);
|
|
assert.equal('formatted_body' in merged, false);
|
|
// Input is not mutated.
|
|
assert.equal(richContent.formatted_body !== undefined, true);
|
|
});
|
|
|
|
test('mergeScheduledBody builds a bare text content when opened blank', () => {
|
|
assert.deepEqual(mergeScheduledBody(null, ' hi '), { body: 'hi', msgtype: 'm.text' });
|
|
assert.deepEqual(mergeScheduledBody(undefined, 'hi'), { body: 'hi', msgtype: 'm.text' });
|
|
});
|
|
|
|
test('mergeScheduledBody preserves a non-text msgtype on edit', () => {
|
|
const merged = mergeScheduledBody({ msgtype: 'm.emote', body: 'waves' }, 'nods');
|
|
assert.deepEqual(merged, { msgtype: 'm.emote', body: 'nods' });
|
|
});
|