diff --git a/spec/styling.js b/spec/styling.js index 2c7af7ff1..19c121aa5 100644 --- a/spec/styling.js +++ b/spec/styling.js @@ -355,6 +355,35 @@ describe("An incoming chat Message", function () { msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === 'hello world > this is not a quote'); + + msg_text = '> What do you think of it romeo?\n Did you see this romeo?'; + msg = $msg({ + from: contact_jid, + to: _converse.connection.jid, + type: 'chat', + id: (new Date()).getTime() + }).c('body').t(msg_text).up() + .c('reference', { + 'xmlns':'urn:xmpp:reference:0', + 'begin':'26', + 'end':'31', + 'type':'mention', + 'uri': _converse.bare_jid + }) + .c('reference', { + 'xmlns':'urn:xmpp:reference:0', + 'begin':'51', + 'end':'56', + 'type':'mention', + 'uri': _converse.bare_jid + }).nodeTree; + await _converse.handleMessageStanza(msg); + + await new Promise(resolve => view.model.messages.once('rendered', resolve)); + msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop(); + expect(msg_el.innerText).toBe(msg_text); + await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === + `
What do you think of it romeo?
\n Did you see this romeo?`); done(); })); }); diff --git a/src/shared/message/styling.js b/src/shared/message/styling.js index 0b21788b3..ed92f2dff 100644 --- a/src/shared/message/styling.js +++ b/src/shared/message/styling.js @@ -150,8 +150,7 @@ export function getDirectiveTemplate (d, text, model, offset) { if (isQuoteDirective(d)) { const newtext = text .replace(/\n>/g, '\n') // Don't show the directive itself - .replace(/\n$/, '') // Trim line-break at the end - .replace(/^ /, ''); // Trim leading space inside codeblock + .replace(/\n$/, ''); // Trim line-break at the end return template(newtext, model, offset); } else { return template(text, model, offset); diff --git a/src/shared/message/text.js b/src/shared/message/text.js index d1b26a91a..37988a122 100644 --- a/src/shared/message/text.js +++ b/src/shared/message/text.js @@ -34,7 +34,7 @@ export class MessageText extends String { /** * Create a new {@link MessageText} instance. - * @param { String } text - The plain text that was received from the `` stanza. + * @param { String } text - The text to be annotated * @param { Message } model - The model representing the message to which * this MessageText instance belongs * @param { Integer } offset - The offset of this particular piece of text @@ -140,15 +140,15 @@ export class MessageText extends String { const nick = this.model.collection.chatbox.get('nick'); this.model.get('references')?.forEach(ref => { const begin = Number(ref.begin)-offset; - if (begin >= text.length) { + if (begin < 0 || begin >= offset+text.length) { return; } const end = Number(ref.end)-offset; const mention = text.slice(begin, end); if (mention === nick) { - this.addTemplateResult(begin, end, tpl_mention_with_nick({mention})); + this.addTemplateResult(begin+offset, end+offset, tpl_mention_with_nick({mention})); } else { - this.addTemplateResult(begin, end, tpl_mention({mention})); + this.addTemplateResult(begin+offset, end+offset, tpl_mention({mention})); } }); } @@ -167,12 +167,19 @@ export class MessageText extends String { while (i < this.length) { const { d, length } = getDirectiveAndLength(this, i); if (d && length) { - const begin = d === '```' ? i+d.length+1 : i+d.length; + const is_quote = isQuoteDirective(d); const end = i+length; - const slice_end = isQuoteDirective(d) ? end : end-d.length; + const slice_end = is_quote ? end : end-d.length; + let slice_begin = d === '```' ? i+d.length+1 : i+d.length; + if (is_quote && this[slice_begin] === ' ') { + // Trim leading space inside codeblock + slice_begin += 1; + } + const offset = slice_begin; + const text = this.slice(slice_begin, slice_end); references.push({ 'begin': i, - 'template': getDirectiveTemplate(d, this.slice(begin, slice_end), this.model, i+d.length), + 'template': getDirectiveTemplate(d, text, this.model, offset), end, }); i = end; @@ -198,7 +205,7 @@ export class MessageText extends String { * instance and add references via the passed in function. * @param { Function } func */ - addReferences (func) { + addAnnotations (func) { const payload = this.marshall(); let idx = 0; // The text index of the element in the payload for (const text of payload) { @@ -235,12 +242,12 @@ export class MessageText extends String { await api.trigger('beforeMessageBodyTransformed', this, {'Synchronous': true}); this.addStyling(); - this.addReferences(this.addMentions); - this.addReferences(this.addHyperlinks); - this.addReferences(this.addMapURLs); + this.addAnnotations(this.addMentions); + this.addAnnotations(this.addHyperlinks); + this.addAnnotations(this.addMapURLs); await api.emojis.initialize(); - this.addReferences(this.addEmojis); + this.addAnnotations(this.addEmojis); /** * Synchronous event which provides a hook for transforming a chat message's body text @@ -288,6 +295,11 @@ export class MessageText extends String { return convertASCII2Emoji(text.replace(/\n\n+/g, '\n\n')); } + /** + * Take the annotations and return an array of text and TemplateResult + * instances to be rendered to the DOM. + * @method MessageText#marshall + */ marshall () { let list = [this.toString()]; this.references