Browse Source

Styling: Fix offsetting of mentions mixed in with styles

JC Brand 4 years ago
parent
commit
af2df84fc1
3 changed files with 54 additions and 14 deletions
  1. 29 0
      spec/styling.js
  2. 1 2
      src/shared/message/styling.js
  3. 24 12
      src/shared/message/text.js

+ 29 - 0
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 &gt; 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, '') ===
+            `<blockquote>What do you think of it <span class="mention">romeo</span>?</blockquote>\n Did you see this <span class="mention">romeo</span>?`);
         done();
     }));
 });

+ 1 - 2
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);

+ 24 - 12
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 `<message>` 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