Unfurls: gracefully handle missing OGP data
This commit is contained in:
parent
5b3d03bc63
commit
54d6a6af56
@ -47,6 +47,44 @@ describe("A Groupchat Message", function () {
|
||||
done();
|
||||
}));
|
||||
|
||||
it("will render an unfurl with limited OGP data", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
|
||||
/* Some sites don't include ogp data such as title, description and
|
||||
* url. This test is to check that we fall back gracefully */
|
||||
const nick = 'romeo';
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
|
||||
const message_stanza = u.toStanza(`
|
||||
<message xmlns="jabber:client" type="groupchat" from="${muc_jid}/arzu" xml:lang="en" to="${_converse.jid}" id="eda6c790-b4f3-4c07-b5e2-13fff99e6c04">
|
||||
<body>https://mempool.space</body>
|
||||
<active xmlns="http://jabber.org/protocol/chatstates"/>
|
||||
<origin-id xmlns="urn:xmpp:sid:0" id="eda6c790-b4f3-4c07-b5e2-13fff99e6c04"/>
|
||||
<stanza-id xmlns="urn:xmpp:sid:0" by="${muc_jid}" id="8f7613cc-27d4-40ca-9488-da25c4baf92a"/>
|
||||
<markable xmlns="urn:xmpp:chat-markers:0"/>
|
||||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(message_stanza));
|
||||
const el = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
||||
expect(el.textContent).toBe('https://mempool.space');
|
||||
|
||||
const metadata_stanza = u.toStanza(`
|
||||
<message xmlns="jabber:client" from="${muc_jid}" to="${_converse.jid}" type="groupchat">
|
||||
<apply-to xmlns="urn:xmpp:fasten:0" id="eda6c790-b4f3-4c07-b5e2-13fff99e6c04">
|
||||
<meta xmlns="http://www.w3.org/1999/xhtml" property="og:image" content="https://conversejs.org/dist/images/custom_emojis/converse.png" />
|
||||
<meta xmlns="http://www.w3.org/1999/xhtml" property="og:image:type" content="image/png" />
|
||||
<meta xmlns="http://www.w3.org/1999/xhtml" property="og:image:width" content="1000" />
|
||||
<meta xmlns="http://www.w3.org/1999/xhtml" property="og:image:height" content="500" />
|
||||
</apply-to>
|
||||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(metadata_stanza));
|
||||
|
||||
const unfurl = await u.waitUntil(() => view.querySelector('converse-message-unfurl'));
|
||||
expect(unfurl.querySelector('.card-img-top').getAttribute('src')).toBe('https://conversejs.org/dist/images/custom_emojis/converse.png');
|
||||
expect(unfurl.querySelector('.card-body')).toBe(null);
|
||||
expect(unfurl.querySelector('a')).toBe(null);
|
||||
done();
|
||||
}));
|
||||
|
||||
it("will render multiple unfurls based on OGP data", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
|
||||
const nick = 'romeo';
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
|
@ -5,20 +5,39 @@
|
||||
.conversejs {
|
||||
@import "bootstrap/scss/card";
|
||||
|
||||
.message {
|
||||
.card--unfurl {
|
||||
margin: 1em 0;
|
||||
@include media-breakpoint-down(sm) {
|
||||
max-width: 95%;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
max-width: 75%;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
max-width: 66%;
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
max-width: 50%;
|
||||
converse-chats {
|
||||
&.converse-embedded,
|
||||
&.converse-fullscreen {
|
||||
.message {
|
||||
.card--unfurl {
|
||||
margin: 1em 0;
|
||||
@include media-breakpoint-down(sm) {
|
||||
max-width: 95%;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
max-width: 75%;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
max-width: 66%;
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.conversejs {
|
||||
converse-chats {
|
||||
&.converse-overlayed,
|
||||
&.converse-mobile {
|
||||
.message {
|
||||
.card--unfurl {
|
||||
margin: 1em 0;
|
||||
max-width: 95%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,31 @@
|
||||
import { html } from 'lit';
|
||||
import { converse } from "@converse/headless/core";
|
||||
import { getURI } from 'utils/html.js';
|
||||
import { html } from 'lit';
|
||||
const u = converse.env.utils;
|
||||
|
||||
function isValidURL (url) {
|
||||
// We don't consider relative URLs as valid
|
||||
return !!getURI(url).host();
|
||||
}
|
||||
|
||||
function isValidImage (image) {
|
||||
return image && u.isImageDomainAllowed(image) && isValidURL(image);
|
||||
}
|
||||
|
||||
const tpl_url_wrapper = (o, wrapped_template) =>
|
||||
(o.url && isValidURL(o.url)) ?
|
||||
html`<a href="${o.url}" target="_blank" rel="noopener">${wrapped_template(o)}</a>` : tpl_image(o);
|
||||
|
||||
const tpl_image = (o) => html`<img class="card-img-top" src="${o.image}" @load=${o.onload}/>`;
|
||||
|
||||
export default (o) => {
|
||||
return html`<div class="card card--unfurl">
|
||||
${ o.image && u.isImageDomainAllowed(o.image) ? html`<a href="${o.url}" target="_blank" rel="noopener"><img class="card-img-top" src="${o.image}" @load=${o.onload}/></a>` : '' }
|
||||
<div class="card-body">
|
||||
<a href="${o.url}" target="_blank" rel="noopener"><h5 class="card-title">${o.title}</h5></a>
|
||||
<p class="card-text"><converse-rich-text text=${o.description}></converse-rich-text></p>
|
||||
<p class="card-text"><a href="${o.url}" target="_blank" rel="noopener">${u.getURI(o.url).domain()}</a></p>
|
||||
</div>
|
||||
${ isValidImage(o.image) ? tpl_url_wrapper(o, tpl_image) : '' }
|
||||
${ (o.title || o.description || o.url) ? html`
|
||||
<div class="card-body">
|
||||
${ o.title ? tpl_url_wrapper(o, o => html`<h5 class="card-title">${o.title}</h5>`) : ''}
|
||||
${ o.description ? html`<p class="card-text"><converse-rich-text text=${o.description}></converse-rich-text></p>` : '' }
|
||||
${ o.url ? html`<p class="card-text"><a href="${o.url}" target="_blank" rel="noopener">${u.getURI(o.url).domain()}</a></p>` : '' }
|
||||
</div>` : '' }
|
||||
</div>`;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ function slideOutWrapup (el) {
|
||||
el.style.height = "";
|
||||
}
|
||||
|
||||
function getURI (url) {
|
||||
export function getURI (url) {
|
||||
try {
|
||||
return (url instanceof URI) ? url : (new URI(url));
|
||||
} catch (error) {
|
||||
|
Loading…
Reference in New Issue
Block a user