Przeglądaj źródła

chatview: Scroll down on image load

JC Brand 5 lat temu
rodzic
commit
91c130752c

+ 2 - 2
spec/messages.js

@@ -1,4 +1,4 @@
-/*global mock */
+/*global mock, converse */
 
 const { Promise, Strophe, $msg, dayjs, sizzle, _ } = converse.env;
 const u = converse.env.utils;
@@ -999,7 +999,7 @@ describe("A Chat Message", function () {
         expect(view.model.sendMessage).toHaveBeenCalled();
         const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
         await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '').trim() ==
-            `<a target="_blank" rel="noopener" href="https://conversejs.org/logo/non-existing.svg">https://conversejs.org/logo/non-existing.svg</a>`);
+            `<a target="_blank" rel="noopener" href="https://conversejs.org/logo/non-existing.svg">https://conversejs.org/logo/non-existing.svg</a>`, 1000);
         done();
     }));
 

+ 15 - 3
src/templates/directives/body.js

@@ -102,7 +102,7 @@ function addMapURLs (text) {
 }
 
 
-function addHyperlinks (text) {
+function addHyperlinks (text, onImgLoad) {
     const objs = [];
     try {
         const parse_options = { 'start': /\b(?:([a-z][a-z0-9.+-]*:\/\/)|xmpp:|mailto:|www\.)/gi };
@@ -120,7 +120,7 @@ function addHyperlinks (text) {
         text.addTemplateResult(
             url_obj.start,
             url_obj.end,
-            show_images && u.isImageURL(url_text) ? u.convertToImageTag(url_text) : u.convertUrlToHyperlink(url_text),
+            show_images && u.isImageURL(url_text) ? u.convertToImageTag(url_text, onImgLoad) : u.convertUrlToHyperlink(url_text),
         );
     });
 }
@@ -161,9 +161,21 @@ class MessageBodyRenderer {
     constructor (component) {
         this.model = component.model;
         this.component = component;
+        this.chatview = u.ancestor(this.component, 'converse-chat-message')?.chatview;
+        // We jot down whether we were scrolled down before rendering, because when an
+        // image loads, it triggers 'scroll' and the chat will be marked as scrolled,
+        // which is technically true, but not what we want because the user
+        // didn't initiate the scrolling.
+        this.scrolled = this.chatview.model.get('scrolled');
         this.text = this.component.model.getMessageText();
     }
 
+    scrollDownOnImageLoad () {
+        if (!this.scrolled) {
+            this.chatview.scrollDown();
+        }
+    }
+
     async transform () {
         const text = new MessageText(this.text);
         /**
@@ -179,7 +191,7 @@ class MessageBodyRenderer {
          */
         await api.trigger('beforeMessageBodyTransformed', this.model, text, {'Synchronous': true});
 
-        addHyperlinks(text);
+        addHyperlinks(text, () => this.scrollDownOnImageLoad());
         addMapURLs(text);
         await addEmojis(text);
         addReferences(text, this.model);

+ 3 - 2
src/templates/directives/image.js

@@ -1,7 +1,8 @@
+import { converse } from "@converse/headless/converse-core";
 import { directive, html } from "lit-html";
 
 
-export const renderImage = directive(url => part => {
+export const renderImage = directive((url, onLoad) => part => {
     function onError () {
         part.setValue(converse.env.utils.convertUrlToHyperlink(url));
         part.commit();
@@ -11,6 +12,6 @@ export const renderImage = directive(url => part => {
                 class="chat-image__link"
                 target="_blank"
                 rel="noopener"
-            ><img class="chat-image img-thumbnail" src="${url}" @error=${onError}/></a>`
+            ><img class="chat-image img-thumbnail" src="${url}" @error=${onError} @load=${onLoad}/></a>`
     );
 });

+ 1 - 1
src/templates/image.js

@@ -1,4 +1,4 @@
 import { html } from "lit-html";
 import { renderImage } from "./directives/image.js";
 
-export default (o) => html`${renderImage(o.url)}`;
+export default (o) => html`${renderImage(o.url, o.onLoad)}`;

+ 6 - 3
src/utils/html.js

@@ -290,15 +290,18 @@ u.escapeHTML = function (string) {
 };
 
 
-u.convertToImageTag = function (url) {
+u.convertToImageTag = function (url, onLoad) {
     const uri = getURI(url);
     const img_url_without_ext = ['imgur.com', 'pbs.twimg.com'].includes(uri.hostname());
     if (u.isImageURL(url) || img_url_without_ext) {
         if (img_url_without_ext) {
             const format = (uri.hostname() === 'pbs.twimg.com') ? uri.search(true).format : 'png';
-            return tpl_image({'url': uri.removeSearch(/.*/).toString() + `.${format}`});
+            return tpl_image({
+                onLoad,
+                'url': uri.removeSearch(/.*/).toString() + `.${format}`
+            });
         } else {
-            return tpl_image({url});
+            return tpl_image({url, onLoad});
         }
     }
 }