Browse Source

Open images in a modal

JC Brand 5 years ago
parent
commit
6a6d080679

+ 5 - 0
sass/_core.scss

@@ -100,6 +100,11 @@ body.converse-fullscreen {
         background-color: #EEE !important;
     }
 
+    .fit-content {
+        width: fit-content !important;
+        max-width: fit-content !important;
+    }
+
     .nopadding {
         padding: 0 !important;
     }

+ 13 - 1
src/components/message-body.js

@@ -1,17 +1,29 @@
 import { CustomElement } from './element.js';
 import { renderBodyText } from './../templates/directives/body';
 import { api } from "@converse/headless/converse-core";
+import ImageModal from '../modals/image.js';
+
 
 export default class MessageBody extends CustomElement {
 
     static get properties () {
         return {
-            is_me_message: { type: Boolean },
             model: { type: Object },
+            is_me_message: { type: Boolean },
             text: { type: String },
         }
     }
 
+    showImageModal (ev) {
+        ev.preventDefault();
+        if (this.image_modal === undefined) {
+            this.image_modal = new ImageModal();
+        }
+        this.image_modal.src = ev.target.src;
+        this.image_modal.render();
+        this.image_modal.show(ev);
+    }
+
     render () {
         return renderBodyText(this);
     }

+ 9 - 0
src/modals/image.js

@@ -0,0 +1,9 @@
+import { BootstrapModal } from "../converse-modal.js";
+import tpl_image_modal from "../templates/image_modal.js";
+
+
+export default BootstrapModal.extend({
+    toHTML () {
+        return tpl_image_modal({'src': this.src});
+    }
+});

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

@@ -102,7 +102,7 @@ function addMapURLs (text) {
 }
 
 
-function addHyperlinks (text, onImgLoad) {
+function addHyperlinks (text, onImgLoad, onImgClick) {
     const objs = [];
     try {
         const parse_options = { 'start': /\b(?:([a-z][a-z0-9.+-]*:\/\/)|xmpp:|mailto:|www\.)/gi };
@@ -120,7 +120,9 @@ function addHyperlinks (text, onImgLoad) {
         text.addTemplateResult(
             url_obj.start,
             url_obj.end,
-            show_images && u.isImageURL(url_text) ? u.convertToImageTag(url_text, onImgLoad) : u.convertUrlToHyperlink(url_text),
+            show_images && u.isImageURL(url_text) ?
+                u.convertToImageTag(url_text, onImgLoad, onImgClick) :
+                u.convertUrlToHyperlink(url_text),
         );
     });
 }
@@ -191,7 +193,11 @@ class MessageBodyRenderer {
          */
         await api.trigger('beforeMessageBodyTransformed', this.model, text, {'Synchronous': true});
 
-        addHyperlinks(text, () => this.scrollDownOnImageLoad());
+        addHyperlinks(
+            text,
+            () => this.scrollDownOnImageLoad(),
+            ev => this.component.showImageModal(ev)
+        );
         addMapURLs(text);
         await addEmojis(text);
         addReferences(text, this.model);

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

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

+ 22 - 0
src/templates/image_modal.js

@@ -0,0 +1,22 @@
+import { html } from "lit-html";
+import { __ } from '@converse/headless/i18n';
+import { modal_close_button, modal_header_close_button } from "./buttons"
+
+
+const i18n_image = __('Image: ');
+
+
+export default (o) => html`
+    <div class="modal-dialog fit-content" role="document">
+        <div class="modal-content fit-content">
+            <div class="modal-header">
+                <h4 class="modal-title" id="message-versions-modal-label">${i18n_image}<a target="_blank" rel="noopener" href="${o.src}">${o.src}</a></h4>
+                ${modal_header_close_button}
+            </div>
+            <div class="modal-body fit-content">
+                <img class="chat-image" src="${o.src}"/>
+            </div>
+            <div class="modal-footer">${modal_close_button}</div>
+        </div>
+    </div>
+`;

+ 3 - 2
src/utils/html.js

@@ -290,18 +290,19 @@ u.escapeHTML = function (string) {
 };
 
 
-u.convertToImageTag = function (url, onLoad) {
+u.convertToImageTag = function (url, onLoad, onClick) {
     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({
+                onClick,
                 onLoad,
                 'url': uri.removeSearch(/.*/).toString() + `.${format}`
             });
         } else {
-            return tpl_image({url, onLoad});
+            return tpl_image({url, onClick, onLoad});
         }
     }
 }