瀏覽代碼

Styling: Take offset into consideration when adding templates

JC Brand 4 年之前
父節點
當前提交
35db01d316
共有 3 個文件被更改,包括 83 次插入23 次删除
  1. 1 1
      spec/emojis.js
  2. 30 0
      spec/styling.js
  3. 52 22
      src/shared/message/text.js

+ 1 - 1
spec/emojis.js

@@ -5,7 +5,7 @@ const u = converse.env.utils;
 const original_timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
 const original_timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
 
 
 
 
-fdescribe("Emojis", function () {
+describe("Emojis", function () {
     describe("The emoji picker", function () {
     describe("The emoji picker", function () {
 
 
         beforeEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000));
         beforeEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000));

+ 30 - 0
spec/styling.js

@@ -300,6 +300,36 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
         await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
             '<blockquote> ```\n (println "Hello, world!")</blockquote>\n'+
             '<blockquote> ```\n (println "Hello, world!")</blockquote>\n'+
             'The entire blockquote is a preformatted text block, but this line is plaintext!');
             'The entire blockquote is a preformatted text block, but this line is plaintext!');
+
+        msg_text = '> Also, icons.js is loaded from /dist, instead of dist.\nhttps://conversejs.org/docs/html/configuration.html#assets-path'
+        msg = mock.createChatMessage(_converse, contact_jid, msg_text)
+        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> Also, icons.js is loaded from /dist, instead of dist.</blockquote>'+
+            '<a target="_blank" rel="noopener" href="https://conversejs.org/docs/html/configuration.html#assets-path">https://conversejs.org/docs/html/configuration.html#assets-path</a>');
+
+        msg_text = '> Where is it located?\ngeo:37.786971,-122.399677';
+        msg = mock.createChatMessage(_converse, contact_jid, msg_text)
+        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> Where is it located?</blockquote>'+
+            '<a target="_blank" rel="noopener" '+
+               'href="https://www.openstreetmap.org/?mlat=37.786971&amp;mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.786971&amp;mlon=-122.399677#map=18/37.786971/-122.399677</a>');
+
+        msg_text = '> What do you think of it?\n :poop:';
+        msg = mock.createChatMessage(_converse, contact_jid, msg_text)
+        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?</blockquote> <span title=":poop:">💩</span>');
         done();
         done();
     }));
     }));
 });
 });

+ 52 - 22
src/shared/message/text.js

@@ -57,7 +57,13 @@ export class MessageText extends String {
         this.payload = [];
         this.payload = [];
     }
     }
 
 
-    addHyperlinks (text) {
+    /**
+     * Look for `http` URIs and return templates that render them as URL links
+     * @param { String } text
+     * @param { Integer } offset - The index of the passed in text relative to
+     *  the start of the message body text.
+     */
+    addHyperlinks (text, offset) {
         const objs = [];
         const objs = [];
         try {
         try {
             const parse_options = { 'start': /\b(?:([a-z][a-z0-9.+-]*:\/\/)|xmpp:|mailto:|www\.)/gi };
             const parse_options = { 'start': /\b(?:([a-z][a-z0-9.+-]*:\/\/)|xmpp:|mailto:|www\.)/gi };
@@ -73,8 +79,8 @@ export class MessageText extends String {
             const url_text = text.slice(url_obj.start, url_obj.end);
             const url_text = text.slice(url_obj.start, url_obj.end);
             const filtered_url = u.filterQueryParamsFromURL(url_text);
             const filtered_url = u.filterQueryParamsFromURL(url_text);
             this.addTemplateResult(
             this.addTemplateResult(
-                url_obj.start,
-                url_obj.end,
+                url_obj.start+offset,
+                url_obj.end+offset,
                 this.show_images && u.isImageURL(url_text) && u.isImageDomainAllowed(url_text) ?
                 this.show_images && u.isImageURL(url_text) && u.isImageDomainAllowed(url_text) ?
                     u.convertToImageTag(filtered_url, this.onImgLoad, this.onImgClick) :
                     u.convertToImageTag(filtered_url, this.onImgLoad, this.onImgClick) :
                     u.convertUrlToHyperlink(filtered_url),
                     u.convertUrlToHyperlink(filtered_url),
@@ -82,35 +88,54 @@ export class MessageText extends String {
         });
         });
     }
     }
 
 
-    addMapURLs (text) {
+    /**
+     * Look for `geo` URIs and return templates that render them as URL links
+     * @param { String } text
+     * @param { Integer } offset - The index of the passed in text relative to
+     *  the start of the message body text.
+     */
+    addMapURLs (text, offset) {
         const regex = /geo:([\-0-9.]+),([\-0-9.]+)(?:,([\-0-9.]+))?(?:\?(.*))?/g;
         const regex = /geo:([\-0-9.]+),([\-0-9.]+)(?:,([\-0-9.]+))?(?:\?(.*))?/g;
         const matches = text.matchAll(regex);
         const matches = text.matchAll(regex);
         for (const m of matches) {
         for (const m of matches) {
             this.addTemplateResult(
             this.addTemplateResult(
-                m.index,
-                m.index+m.input.length,
+                m.index+offset,
+                m.index+m.input.length+offset,
                 u.convertUrlToHyperlink(m.input.replace(regex, _converse.geouri_replacement))
                 u.convertUrlToHyperlink(m.input.replace(regex, _converse.geouri_replacement))
             );
             );
         }
         }
     }
     }
 
 
-    async addEmojis (text) {
+    /**
+     * Look for emojis (shortnames or unicode) and add templates for rendering them.
+     * @param { String } text
+     * @param { Integer } offset - The index of the passed in text relative to
+     *  the start of the message body text.
+     */
+    async addEmojis (text, offset) {
         await api.emojis.initialize();
         await api.emojis.initialize();
         const references = [...getShortnameReferences(text.toString()), ...getCodePointReferences(text.toString())];
         const references = [...getShortnameReferences(text.toString()), ...getCodePointReferences(text.toString())];
         references.forEach(e => {
         references.forEach(e => {
             this.addTemplateResult(
             this.addTemplateResult(
-                e.begin,
-                e.end,
+                e.begin+offset,
+                e.end+offset,
                 getEmojiMarkup(e, {'add_title_wrapper': true})
                 getEmojiMarkup(e, {'add_title_wrapper': true})
             );
             );
         });
         });
     }
     }
 
 
-    addMentionReferences (text, offset) {
+    /**
+     * Look for mentions included as XEP-0372 references and add templates for
+     * rendering them.
+     * @param { String } text
+     * @param { Integer } offset - The index of the passed in text relative to
+     *  the start of the message body text.
+     */
+    addMentions (text, offset) {
         if (!this.model.collection) {
         if (!this.model.collection) {
             // This model doesn't belong to a collection anymore, so it must be
             // This model doesn't belong to a collection anymore, so it must be
             // have been removed in the meantime and can be ignored.
             // have been removed in the meantime and can be ignored.
-            log.debug('addMentionReferences: ignoring dangling model');
+            log.debug('addMentions: ignoring dangling model');
             return;
             return;
         }
         }
         const nick = this.model.collection.chatbox.get('nick');
         const nick = this.model.collection.chatbox.get('nick');
@@ -129,7 +154,11 @@ export class MessageText extends String {
         });
         });
     }
     }
 
 
-    addStylingReferences () {
+    /**
+     * Look for XEP-0393 styling directives and add templates for rendering
+     * them.
+     */
+    addStyling () {
         if (this.model.get('is_unstyled') || !api.settings.get('allow_message_styling')) {
         if (this.model.get('is_unstyled') || !api.settings.get('allow_message_styling')) {
             return;
             return;
         }
         }
@@ -184,19 +213,20 @@ export class MessageText extends String {
          */
          */
         await api.trigger('beforeMessageBodyTransformed', this, {'Synchronous': true});
         await api.trigger('beforeMessageBodyTransformed', this, {'Synchronous': true});
 
 
-        this.addStylingReferences();
+        this.addStyling();
         const payload = this.marshall();
         const payload = this.marshall();
-
-        let offset = this.offset;
+        let idx = 0; // The text index of the element in the payload
         for (const text of payload) {
         for (const text of payload) {
-            if (isString(text)) {
-                this.addHyperlinks(text);
-                this.addMapURLs(text);
-                await this.addEmojis(text);
-                this.addMentionReferences(text, offset);
-                offset += text.length;
+            if (!text) {
+                continue
+            } else if (isString(text)) {
+                this.addHyperlinks(text, idx);
+                this.addMapURLs(text, idx);
+                await this.addEmojis(text, idx);
+                this.addMentions(text, this.offset+idx);
+                idx += text.length;
             } else {
             } else {
-                offset += text.begin;
+                idx += text.end;
             }
             }
         }
         }