From ca3c8fc10bffc0c1fe45a0827c5f996fb2dd1ed1 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sat, 20 Aug 2022 10:28:52 +0200 Subject: [PATCH] Fixes #3007 Bugfix: Links in message become text when the message is edited --- CHANGES.md | 1 + src/headless/plugins/chat/model.js | 21 +++--- src/headless/plugins/chat/utils.js | 2 +- src/headless/shared/chat/utils.js | 8 +-- src/plugins/chatview/tests/styling.js | 97 +++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 17 deletions(-) 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' + ); + })); + +});