diff --git a/CHANGES.md b/CHANGES.md
index 451f0828aa..6d8f5401f5 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -4,7 +4,7 @@
### Github Issues
- #122: Set horizontal layout direction based on the language
-- #317: Add the ability to render audio streams. New config option [show_self_in_roster](https://conversejs.org/docs/html/configuration.html#show-self-in-roster)
+- #317: Add the ability to render audio streams. New config option [fetch_url_headers](https://conversejs.org/docs/html/configuration.html#fetch-url-headers)
- #698: Add support for MUC private messages
- #1021: Message from non-roster contacts don't appear in fullscreen view_mode
- #1038: Support setting node config manually
diff --git a/src/plugins/chatview/tests/message-audio.js b/src/plugins/chatview/tests/message-audio.js
index b266835aab..95a943e9bd 100644
--- a/src/plugins/chatview/tests/message-audio.js
+++ b/src/plugins/chatview/tests/message-audio.js
@@ -46,25 +46,6 @@ describe("A Chat Message", function () {
expect(msg.querySelector('audio').src).toEqual(message);
}));
- xit("will render audio stream",
- mock.initConverse(['chatBoxesFetched'],
- { fetch_url_headers: true },
- async function (_converse) {
-
- await mock.waitForRoster(_converse, 'current', 1);
- const message = 'https://differentdrumz.radioca.st/stream/1/';
-
- const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
- await mock.openChatBoxFor(_converse, contact_jid);
- const view = _converse.chatboxviews.get(contact_jid);
- await mock.sendMessage(view, message);
- await u.waitUntil(() => view.querySelectorAll('.chat-content audio').length, 1000)
- const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
- expect(msg.innerHTML.replace(//g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual(
- ``+
- `${message}`);
- }));
-
it("will render Spotify player for Spotify URLs",
mock.initConverse(['chatBoxesFetched'],
{ embed_3rd_party_media_players: true, view_mode: 'fullscreen' },
diff --git a/src/plugins/chatview/tests/message-videos.js b/src/plugins/chatview/tests/message-videos.js
index dfa388e5bc..509f5e4304 100644
--- a/src/plugins/chatview/tests/message-videos.js
+++ b/src/plugins/chatview/tests/message-videos.js
@@ -16,17 +16,13 @@ describe("A chat message containing video URLs", function () {
await mock.sendMessage(view, message);
await u.waitUntil(() => view.querySelectorAll('.chat-content video').length, 1000)
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
- expect(msg.innerHTML.replace(//g, '').trim()).toEqual(
- ``+
- `${message}`);
+ expect(msg.querySelector('video').src).toEqual(message);
message += "?param1=val1¶m2=val2";
await mock.sendMessage(view, message);
await u.waitUntil(() => view.querySelectorAll('.chat-content video').length === 2, 1000);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
- expect(msg.innerHTML.replace(//g, '').trim()).toEqual(
- ``+
- `${Strophe.xmlescape(message)}`);
+ expect(msg.querySelector('video').src).toEqual(message);
}));
it("will not render videos if render_media is false",
@@ -64,9 +60,7 @@ describe("A chat message containing video URLs", function () {
await mock.sendMessage(view, message);
await u.waitUntil(() => view.querySelectorAll('.chat-content video').length, 1000)
const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
- expect(msg.innerHTML.replace(//g, '').trim()).toEqual(
- ``+
- `${message}`);
+ expect(msg.querySelector('video').src).toEqual(message);
}));
it("will allow the user to toggle visibility of rendered videos",
diff --git a/src/plugins/chatview/tests/oob.js b/src/plugins/chatview/tests/oob.js
index cbabad362b..8a9de76e30 100644
--- a/src/plugins/chatview/tests/oob.js
+++ b/src/plugins/chatview/tests/oob.js
@@ -82,9 +82,7 @@ describe("A Chat Message", function () {
expect(msg.classList.length).toBe(1);
expect(msg.textContent).toEqual('Have you seen this funny video?');
const media = view.querySelector('.chat-msg .chat-msg__media');
- expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "").replace(//g, '')).toEqual(
- ``+
- `${Strophe.xmlescape(url)}`);
+ expect(media.querySelector('video').getAttribute('src')).toBe(url);
// If the and contents is the same, don't duplicate.
stanza = u.toStanza(`
diff --git a/src/shared/directives/image.js b/src/shared/directives/image.js
index 14f7a21660..cabb5d641d 100644
--- a/src/shared/directives/image.js
+++ b/src/shared/directives/image.js
@@ -7,25 +7,46 @@ import { getHyperlinkTemplate } from 'utils/html.js';
const { URI } = converse.env;
const { isURLWithImageExtension } = u;
-
class ImageDirective extends AsyncDirective {
-
- render (src, href, onLoad, onClick) {
- return href ?
- html`${ this.renderImage(src, href, onLoad, onClick) }` :
- this.renderImage(src, href, onLoad, onClick);
+ /**
+ * @param {string} src - The source URL of the image.
+ * @param {string} [href] - The optional hyperlink for the image.
+ * @param {Function} [onLoad] - Callback function to be called once the image has loaded.
+ * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
+ * @returns {import('lit').TemplateResult}
+ */
+ render(src, href, onLoad, onClick) {
+ return href
+ ? html`${this.renderImage(src, href, onLoad, onClick)}`
+ : this.renderImage(src, href, onLoad, onClick);
}
- renderImage (src, href, onLoad, onClick) {
+ /**
+ * @param {string} src - The source URL of the image.
+ * @param {string} [href] - The optional hyperlink for the image.
+ * @param {Function} [onLoad] - Callback function to be called once the image has loaded.
+ * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
+ * @returns {import('lit').TemplateResult}
+ */
+ renderImage(src, href, onLoad, onClick) {
return html` this.onError(src, href, onLoad, onClick)}
- @load="${onLoad}"/>`;
+ loading="lazy"
+ src="${src}"
+ @click=${onClick}
+ @error=${() => this.onError(src, href, onLoad, onClick)}
+ @load="${onLoad}"/>`;
}
- onError (src, href, onLoad, onClick) {
+ /**
+ * Handles errors that occur during image loading.
+ * @param {string} src - The source URL of the image that failed to load.
+ * @param {string} [href] - The optional hyperlink for the image.
+ * @param {Function} [onLoad] - Callback function to be called once the image has loaded.
+ * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
+ */
+ onError(src, href, onLoad, onClick) {
if (isURLWithImageExtension(src)) {
href && this.setValue(getHyperlinkTemplate(href));
} else {
diff --git a/src/shared/texture/texture.js b/src/shared/texture/texture.js
index 2d45849dc9..fcf170fa33 100644
--- a/src/shared/texture/texture.js
+++ b/src/shared/texture/texture.js
@@ -153,7 +153,7 @@ export class Texture extends String {
} else {
if (this.shouldRenderMedia(url_text, 'audio') && api.settings.get('fetch_url_headers')) {
const headers = await getHeaders(url_text);
- if (headers.get('content-type')?.startsWith('audio')) {
+ if (headers?.get('content-type')?.startsWith('audio')) {
template = tplAudio(filtered_url, this.hide_media_urls, headers.get('Icy-Name'));
}
}
diff --git a/src/templates/video.js b/src/templates/video.js
index fd80311ed0..caa68eb65f 100644
--- a/src/templates/video.js
+++ b/src/templates/video.js
@@ -4,7 +4,10 @@ import { html } from 'lit';
* @param {string} url
* @param {boolean} [hide_url]
*/
-export default (url, hide_url) =>
- html`${hide_url
- ? ''
- : html`${url}`}`;
+export default (url, hide_url) => {
+ const { hostname } = new URL(url);
+ return html``;
+}
diff --git a/src/types/shared/directives/image.d.ts b/src/types/shared/directives/image.d.ts
index f30c5f4382..378225a5c5 100644
--- a/src/types/shared/directives/image.d.ts
+++ b/src/types/shared/directives/image.d.ts
@@ -7,11 +7,32 @@
* @param { Function } onLoad - A callback function to be called once the image has loaded.
* @param { Function } onClick - A callback function to be called once the image has been clicked.
*/
-export const renderImage: (src?: any, href?: any, onLoad?: any, onClick?: any) => import("lit/async-directive.js").DirectiveResult;
+export const renderImage: (src: string, href?: string, onLoad?: Function, onClick?: Function) => import("lit/async-directive.js").DirectiveResult;
declare class ImageDirective extends AsyncDirective {
- render(src: any, href: any, onLoad: any, onClick: any): import("lit").TemplateResult<1>;
- renderImage(src: any, href: any, onLoad: any, onClick: any): import("lit").TemplateResult<1>;
- onError(src: any, href: any, onLoad: any, onClick: any): void;
+ /**
+ * @param {string} src - The source URL of the image.
+ * @param {string} [href] - The optional hyperlink for the image.
+ * @param {Function} [onLoad] - Callback function to be called once the image has loaded.
+ * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
+ * @returns {import('lit').TemplateResult}
+ */
+ render(src: string, href?: string, onLoad?: Function, onClick?: Function): import("lit").TemplateResult;
+ /**
+ * @param {string} src - The source URL of the image.
+ * @param {string} [href] - The optional hyperlink for the image.
+ * @param {Function} [onLoad] - Callback function to be called once the image has loaded.
+ * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
+ * @returns {import('lit').TemplateResult}
+ */
+ renderImage(src: string, href?: string, onLoad?: Function, onClick?: Function): import("lit").TemplateResult;
+ /**
+ * Handles errors that occur during image loading.
+ * @param {string} src - The source URL of the image that failed to load.
+ * @param {string} [href] - The optional hyperlink for the image.
+ * @param {Function} [onLoad] - Callback function to be called once the image has loaded.
+ * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
+ */
+ onError(src: string, href?: string, onLoad?: Function, onClick?: Function): void;
}
import { AsyncDirective } from 'lit/async-directive.js';
export {};