Open images in a modal

This commit is contained in:
JC Brand 2020-07-14 15:45:16 +02:00
parent 6b62b51f11
commit 6a6d080679
8 changed files with 64 additions and 9 deletions

View File

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

View File

@ -1,17 +1,29 @@
import { CustomElement } from './element.js'; import { CustomElement } from './element.js';
import { renderBodyText } from './../templates/directives/body'; import { renderBodyText } from './../templates/directives/body';
import { api } from "@converse/headless/converse-core"; import { api } from "@converse/headless/converse-core";
import ImageModal from '../modals/image.js';
export default class MessageBody extends CustomElement { export default class MessageBody extends CustomElement {
static get properties () { static get properties () {
return { return {
is_me_message: { type: Boolean },
model: { type: Object }, model: { type: Object },
is_me_message: { type: Boolean },
text: { type: String }, 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 () { render () {
return renderBodyText(this); return renderBodyText(this);
} }

9
src/modals/image.js Normal file
View File

@ -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});
}
});

View File

@ -102,7 +102,7 @@ function addMapURLs (text) {
} }
function addHyperlinks (text, onImgLoad) { function addHyperlinks (text, onImgLoad, onImgClick) {
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 };
@ -120,7 +120,9 @@ function addHyperlinks (text, onImgLoad) {
text.addTemplateResult( text.addTemplateResult(
url_obj.start, url_obj.start,
url_obj.end, 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}); await api.trigger('beforeMessageBodyTransformed', this.model, text, {'Synchronous': true});
addHyperlinks(text, () => this.scrollDownOnImageLoad()); addHyperlinks(
text,
() => this.scrollDownOnImageLoad(),
ev => this.component.showImageModal(ev)
);
addMapURLs(text); addMapURLs(text);
await addEmojis(text); await addEmojis(text);
addReferences(text, this.model); addReferences(text, this.model);

View File

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

View File

@ -1,4 +1,4 @@
import { html } from "lit-html"; import { html } from "lit-html";
import { renderImage } from "./directives/image.js"; 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)}`;

View File

@ -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>
`;

View File

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