diff --git a/CHANGES.md b/CHANGES.md
index 70da9e232..2aa61ffa9 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -16,6 +16,7 @@
- #2925: Fix missing disco-items in browser storage.
- #2936: Fix documentation about enable_smacks option, which is true by default.
- #3005: Fix MUC messages with a fallback body not rendering.
+- #3007: Fix links becoming text when a message is edited
## 9.1.1 (2022-05-05)
diff --git a/src/headless/plugins/chat/model.js b/src/headless/plugins/chat/model.js
index a289e5350..cf3ebb939 100644
--- a/src/headless/plugins/chat/model.js
+++ b/src/headless/plugins/chat/model.js
@@ -927,19 +927,18 @@ const ChatBox = ModelWithContact.extend({
const older_versions = message.get('older_versions') || {};
const edited_time = message.get('edited') || message.get('time');
older_versions[edited_time] = message.getMessageText();
- const plaintext = attrs.is_encrypted ? attrs.message : undefined;
message.save({
- 'body': attrs.body,
- 'message': attrs.body,
- 'correcting': false,
- 'edited': (new Date()).toISOString(),
- 'is_only_emojis': attrs.is_only_emojis,
- 'origin_id': u.getUniqueId(),
- 'received': undefined,
- 'references': attrs.references,
- older_versions,
- plaintext,
+ ...pick(attrs, ['body', 'is_only_emojis', 'media_urls', 'references', 'is_encrypted']),
+ ...{
+ 'correcting': false,
+ 'edited': (new Date()).toISOString(),
+ 'message': attrs.body,
+ 'origin_id': u.getUniqueId(),
+ 'received': undefined,
+ older_versions,
+ plaintext: attrs.is_encrypted ? attrs.message : undefined,
+ }
});
} else {
this.setEditable(attrs, (new Date()).toISOString());
diff --git a/src/headless/plugins/chat/utils.js b/src/headless/plugins/chat/utils.js
index 8adf76727..d86577b32 100644
--- a/src/headless/plugins/chat/utils.js
+++ b/src/headless/plugins/chat/utils.js
@@ -28,7 +28,7 @@ async function handleErrorMessage (stanza) {
return;
}
const chatbox = await api.chatboxes.get(from_jid);
- if (chatbox.get('type') === _converse.PRIVATE_CHAT_TYPE) {
+ if (chatbox?.get('type') === _converse.PRIVATE_CHAT_TYPE) {
chatbox?.handleErrorMessageStanza(stanza);
}
}
diff --git a/src/headless/shared/chat/utils.js b/src/headless/shared/chat/utils.js
index 5f4e6d894..2b662344c 100644
--- a/src/headless/shared/chat/utils.js
+++ b/src/headless/shared/chat/utils.js
@@ -60,10 +60,8 @@ export function getMediaURLs (arr, text, offset=0) {
/**
- * Determines whether the passed in message attributes represent a
- * message which corrects a previously received message, or an
- * older message which has already been corrected.
- * In both cases, update the corrected message accordingly.
+ * Determines whether the given attributes of an incoming message
+ * represent a XEP-0308 correction and, if so, handles it appropriately.
* @private
* @method _converse.ChatBox#handleCorrection
* @param { _converse.ChatBox | _converse.ChatRoom }
@@ -84,7 +82,7 @@ export async function handleCorrection (model, attrs) {
const message = model.messages.models.find(query);
if (!message) {
- attrs['older_versions'] = [];
+ attrs['older_versions'] = {};
return await model.createMessage(attrs); // eslint-disable-line no-return-await
}
diff --git a/src/plugins/chatview/tests/styling.js b/src/plugins/chatview/tests/styling.js
index ef074efba..f6f58722b 100644
--- a/src/plugins/chatview/tests/styling.js
+++ b/src/plugins/chatview/tests/styling.js
@@ -418,3 +418,100 @@ describe("An incoming chat Message", function () {
expect(true).toBe(true);
}));
});
+
+
+describe("An XEP-0393 styled message ", function () {
+
+ it("can be replaced with a correction and will still render properly",
+ mock.initConverse(['chatBoxesFetched'], {},
+ async function (_converse) {
+
+ await mock.waitForRoster(_converse, 'current', 1);
+ const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+ await mock.openChatBoxFor(_converse, contact_jid);
+ const view = _converse.chatboxviews.get(contact_jid);
+
+ const msg_text = `https://conversejs.org\nhttps://opkode.com`;
+ const msg_id = u.getUniqueId();
+ _converse.handleMessageStanza($msg({
+ 'from': contact_jid,
+ 'to': _converse.connection.jid,
+ 'type': 'chat',
+ 'id': msg_id,
+ }).c('body').t(msg_text).tree());
+ await new Promise(resolve => view.model.messages.once('rendered', resolve));
+ expect(view.querySelectorAll('.chat-msg').length).toBe(1);
+ expect(view.querySelector('.chat-msg__text').textContent)
+ .toBe('https://conversejs.org\nhttps://opkode.com');
+
+ await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 1);
+ const msg_el = view.querySelector('converse-chat-message-body');
+ await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
+ 'https://conversejs.org\n'+
+ 'https://opkode.com'
+ );
+
+ _converse.handleMessageStanza($msg({
+ 'from': contact_jid,
+ 'to': _converse.connection.jid,
+ 'type': 'chat',
+ 'id': u.getUniqueId(),
+ }).c('body').t(`A\nhttps://conversejs.org\n\nhttps://opkode.com`).up()
+ .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
+ await new Promise(resolve => view.model.messages.once('rendered', resolve));
+
+ expect(view.querySelectorAll('.chat-msg__text').length).toBe(1);
+ await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
+ 'A\nhttps://conversejs.org\n\n'+
+ 'https://opkode.com'
+ );
+ }));
+
+ it("can be sent as a correction by using the up arrow",
+ mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
+
+ await mock.waitForRoster(_converse, 'current', 1);
+ await mock.openControlBox(_converse);
+ const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+ await mock.openChatBoxFor(_converse, contact_jid)
+ const view = _converse.chatboxviews.get(contact_jid);
+ const textarea = view.querySelector('textarea.chat-textarea');
+ const message_form = view.querySelector('converse-message-form');
+
+ textarea.value = `https://conversejs.org\nhttps://opkode.com`;
+ message_form.onKeyDown({
+ target: textarea,
+ preventDefault: function preventDefault () {},
+ keyCode: 13 // Enter
+ });
+ await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
+
+ expect(view.querySelectorAll('.chat-msg').length).toBe(1);
+ const msg_el = view.querySelector('converse-chat-message-body');
+ expect(msg_el.innerHTML.replace(//g, '')).toBe(
+ 'https://conversejs.org\n'+
+ 'https://opkode.com'
+ );
+
+ expect(textarea.value).toBe('');
+ message_form.onKeyDown({
+ target: textarea,
+ keyCode: 38 // Up arrow
+ });
+
+ textarea.value = `A\nhttps://conversejs.org\n\nhttps://opkode.com`;
+ message_form.onKeyDown({
+ target: textarea,
+ preventDefault: function preventDefault () {},
+ keyCode: 13 // Enter
+ });
+ await new Promise(resolve => view.model.messages.once('rendered', resolve));
+
+ expect(view.querySelectorAll('.chat-msg__text').length).toBe(1);
+ await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
+ 'A\nhttps://conversejs.org\n\n'+
+ 'https://opkode.com'
+ );
+ }));
+
+});