Fix message reorder issue after edit (#2300)
* keep message in place after edition by assigning previous message original timestamp * update time displayed to keep current behaviour * add test to check a message remains in the same position of the history after being edited * briefly describe pr changes in changelog
This commit is contained in:
parent
5a4fbe12a9
commit
15f5b185c3
@ -36,6 +36,7 @@ Soon we'll deprecate the latter, so prepare now.
|
|||||||
- #2220: fix rendering of emojis in case `use_system_emojis == false` (again).
|
- #2220: fix rendering of emojis in case `use_system_emojis == false` (again).
|
||||||
- #2092: fixes room list update loop when having the `locked_muc_domain` truthy or `'hidden'`
|
- #2092: fixes room list update loop when having the `locked_muc_domain` truthy or `'hidden'`
|
||||||
- #2285: Rename config option `muc_hats_from_vcard` to [muc_hats](https://conversejs.org/docs/html/configuration.html#muc-hats). Now accepts a list instead of a boolean and allows for more flexible choices regarding user badges.
|
- #2285: Rename config option `muc_hats_from_vcard` to [muc_hats](https://conversejs.org/docs/html/configuration.html#muc-hats). Now accepts a list instead of a boolean and allows for more flexible choices regarding user badges.
|
||||||
|
- #2300: Fix message reorder issue after message correction.
|
||||||
- #2304: Custom emojis (stickers) images not shown
|
- #2304: Custom emojis (stickers) images not shown
|
||||||
- #2307: BootstrapModal is not accessible to plugins
|
- #2307: BootstrapModal is not accessible to plugins
|
||||||
- #2308: Allow getHats method to be overriden in the `overrides` object in plugins.
|
- #2308: Allow getHats method to be overriden in the `overrides` object in plugins.
|
||||||
|
@ -592,6 +592,102 @@ describe("A Groupchat Message", function () {
|
|||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it("keeps the same position in history after a correction",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||||
|
const view = _converse.api.chatviews.get(muc_jid);
|
||||||
|
const stanza = $pres({
|
||||||
|
to: 'romeo@montague.lit/_converse.js-29092160',
|
||||||
|
from: 'coven@chat.shakespeare.lit/newguy'
|
||||||
|
})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': 'newguy@montague.lit/_converse.js-290929789',
|
||||||
|
'role': 'participant'
|
||||||
|
}).tree();
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
|
const msg_id = u.getUniqueId();
|
||||||
|
|
||||||
|
// Receiving the first message
|
||||||
|
await view.model.handleMessageStanza($msg({
|
||||||
|
'from': 'lounge@montague.lit/newguy',
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'groupchat',
|
||||||
|
'id': msg_id,
|
||||||
|
}).c('body').t('But soft, what light through yonder airlock breaks?').tree());
|
||||||
|
|
||||||
|
// Receiving own message to check order against
|
||||||
|
await view.model.handleMessageStanza($msg({
|
||||||
|
'from': 'lounge@montague.lit/romeo',
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'groupchat',
|
||||||
|
'id': msg_id,
|
||||||
|
}).c('body').t('But soft, what light through yonder airlock breaks?').tree());
|
||||||
|
|
||||||
|
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
|
||||||
|
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||||
|
expect(view.el.querySelectorAll('.chat-msg__text')[0].textContent)
|
||||||
|
.toBe('But soft, what light through yonder airlock breaks?');
|
||||||
|
expect(view.el.querySelectorAll('.chat-msg__text')[1].textContent)
|
||||||
|
.toBe('But soft, what light through yonder airlock breaks?');
|
||||||
|
|
||||||
|
// First message correction
|
||||||
|
await view.model.handleMessageStanza($msg({
|
||||||
|
'from': 'lounge@montague.lit/newguy',
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'groupchat',
|
||||||
|
'id': u.getUniqueId(),
|
||||||
|
}).c('body').t('But soft, what light through yonder chimney breaks?').up()
|
||||||
|
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
|
||||||
|
|
||||||
|
await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
|
||||||
|
'But soft, what light through yonder chimney breaks?', 500);
|
||||||
|
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||||
|
await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
|
||||||
|
|
||||||
|
// Second message correction
|
||||||
|
await view.model.handleMessageStanza($msg({
|
||||||
|
'from': 'lounge@montague.lit/newguy',
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'groupchat',
|
||||||
|
'id': u.getUniqueId(),
|
||||||
|
}).c('body').t('But soft, what light through yonder window breaks?').up()
|
||||||
|
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
|
||||||
|
|
||||||
|
// Second own message
|
||||||
|
await view.model.handleMessageStanza($msg({
|
||||||
|
'from': 'lounge@montague.lit/romeo',
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'groupchat',
|
||||||
|
'id': u.getUniqueId(),
|
||||||
|
}).c('body').t('But soft, what light through yonder window breaks?').tree());
|
||||||
|
|
||||||
|
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text')[0].textContent ===
|
||||||
|
'But soft, what light through yonder window breaks?', 500);
|
||||||
|
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text').length === 3);
|
||||||
|
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text')[2].textContent ===
|
||||||
|
'But soft, what light through yonder window breaks?', 500);
|
||||||
|
|
||||||
|
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
|
||||||
|
expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||||
|
const edit = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
|
||||||
|
edit.click();
|
||||||
|
const modal = await u.waitUntil(() => view.el.querySelectorAll('converse-chat-message')[0].message_versions_modal);
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
const older_msgs = modal.el.querySelectorAll('.older-msg');
|
||||||
|
expect(older_msgs.length).toBe(2);
|
||||||
|
expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
|
||||||
|
expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
|
||||||
|
expect(older_msgs[1].childNodes[0].nodeName).toBe('TIME');
|
||||||
|
expect(older_msgs[1].childNodes[2].textContent).toBe('But soft, what light through yonder chimney breaks?');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
it("can be sent as a correction by using the up arrow",
|
it("can be sent as a correction by using the up arrow",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched'], {},
|
['rosterGroupsFetched'], {},
|
||||||
|
@ -63,7 +63,7 @@ export default class Message extends CustomElement {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const format = api.settings.get('time_format');
|
const format = api.settings.get('time_format');
|
||||||
this.pretty_time = dayjs(this.time).format(format);
|
this.pretty_time = dayjs(this.edited || this.time).format(format);
|
||||||
if (this.show_spinner) {
|
if (this.show_spinner) {
|
||||||
return tpl_spinner();
|
return tpl_spinner();
|
||||||
} else if (this.model.get('file') && !this.model.get('oob_url')) {
|
} else if (this.model.get('file') && !this.model.get('oob_url')) {
|
||||||
@ -264,7 +264,7 @@ export default class Message extends CustomElement {
|
|||||||
renderAvatarByline () {
|
renderAvatarByline () {
|
||||||
return html`
|
return html`
|
||||||
${ this.hats.map(h => html`<span class="badge badge-secondary">${h.title}</span>`) }
|
${ this.hats.map(h => html`<span class="badge badge-secondary">${h.title}</span>`) }
|
||||||
<time timestamp="${this.time}" class="chat-msg__time">${this.pretty_time}</time>
|
<time timestamp="${this.edited || this.time}" class="chat-msg__time">${this.pretty_time}</time>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,9 +744,14 @@ converse.plugins.add('converse-chat', {
|
|||||||
message.save({'older_versions': older_versions});
|
message.save({'older_versions': older_versions});
|
||||||
} else {
|
} else {
|
||||||
// This is a correction of an earlier message we already received
|
// This is a correction of an earlier message we already received
|
||||||
older_versions[message.get('time')] = message.get('message');
|
if(Object.keys(older_versions).length) {
|
||||||
|
older_versions[message.get('edited')] = message.get('message');
|
||||||
|
}else {
|
||||||
|
older_versions[message.get('time')] = message.get('message');
|
||||||
|
}
|
||||||
attrs = Object.assign(attrs, {'older_versions': older_versions});
|
attrs = Object.assign(attrs, {'older_versions': older_versions});
|
||||||
delete attrs['id']; // Delete id, otherwise a new cache entry gets created
|
delete attrs['id']; // Delete id, otherwise a new cache entry gets created
|
||||||
|
attrs['time'] = message.get('time');
|
||||||
message.save(attrs);
|
message.save(attrs);
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
|
@ -28,7 +28,7 @@ export default (o) => {
|
|||||||
<div class="chat-msg__body chat-msg__body--${o.message_type} ${o.received ? 'chat-msg__body--received' : '' } ${o.is_delayed ? 'chat-msg__body--delayed' : '' }">
|
<div class="chat-msg__body chat-msg__body--${o.message_type} ${o.received ? 'chat-msg__body--received' : '' } ${o.is_delayed ? 'chat-msg__body--delayed' : '' }">
|
||||||
<div class="chat-msg__message">
|
<div class="chat-msg__message">
|
||||||
${ (o.is_me_message) ? html`
|
${ (o.is_me_message) ? html`
|
||||||
<time timestamp="${o.time}" class="chat-msg__time">${o.pretty_time}</time>
|
<time timestamp="${o.edited || o.time}" class="chat-msg__time">${o.pretty_time}</time>
|
||||||
<span class="chat-msg__author">${ o.is_me_message ? '**' : ''}${o.username}</span> ` : '' }
|
<span class="chat-msg__author">${ o.is_me_message ? '**' : ''}${o.username}</span> ` : '' }
|
||||||
${ o.is_retracted ? o.renderRetraction() : o.renderMessageText() }
|
${ o.is_retracted ? o.renderRetraction() : o.renderMessageText() }
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user