소스 검색

Don't set the URL object on the metadata

The data gets persisted, resulting in the error:

```
Uncaught (in promise) DataCloneError: Failed to execute 'put' on 'IDBObjectStore': URL object could not be cloned.
```
JC Brand 4 달 전
부모
커밋
8bb0e800b2

+ 1 - 2
src/headless/types/utils/types.d.ts

@@ -17,7 +17,6 @@ export type MediaURLMetadata = {
     is_encrypted?: boolean;
     end?: number;
     start?: number;
-    url: URL;
-    url_text: string;
+    url: string;
 };
 //# sourceMappingURL=types.d.ts.map

+ 1 - 2
src/headless/utils/types.ts

@@ -19,6 +19,5 @@ export type MediaURLMetadata = {
     is_encrypted?: boolean;
     end?: number;
     start?: number;
-    url: URL;
-    url_text: string;
+    url: string;
 };

+ 11 - 19
src/headless/utils/url.js

@@ -188,26 +188,25 @@ export function getMediaURLsMetadata(text, offset = 0) {
         withinString(
             text,
             /**
-             * @param {string} url_text
+             * @param {string} url
              * @param {number} start
              * @param {number} end
              * @returns {string|undefined}
              */
-            (url_text, start, end) => {
-                if (url_text.startsWith("_")) {
-                    url_text = url_text.slice(1);
+            (url, start, end) => {
+                if (url.startsWith("_")) {
+                    url = url.slice(1);
                     start += 1;
                 }
-                if (url_text.endsWith("_")) {
-                    url_text = url_text.slice(0, url_text.length - 1);
+                if (url.endsWith("_")) {
+                    url = url.slice(0, url.length - 1);
                     end -= 1;
                 }
 
-                const url = getURL(url_text);
-                if (url) {
-                    objs.push({ url_text, url, start: start + offset, end: end + offset });
+                if (isValidURL(url)) {
+                    objs.push({ url, start: start + offset, end: end + offset });
                 }
-                return url_text;
+                return url;
             }
         );
     } catch (error) {
@@ -219,7 +218,7 @@ export function getMediaURLsMetadata(text, offset = 0) {
         is_audio: isAudioURL(o.url),
         is_image: isImageURL(o.url),
         is_video: isVideoURL(o.url),
-        is_encrypted: isEncryptedFileURL(o.url_text),
+        is_encrypted: isEncryptedFileURL(o.url),
     }));
     return media_urls.length ? { media_urls } : {};
 }
@@ -235,16 +234,9 @@ export function getMediaURLs(arr, text) {
             if (o.start < 0 || o.start >= text.length) {
                 return null;
             }
-            const url_text = text.substring(o.start, o.end);
-            let url = null;
-            try {
-                url = getURL(url_text);
-            } catch (e) {
-                log.error(e);
-            }
+            const url = text.substring(o.start, o.end);
             return {
                 ...o,
-                url_text,
                 url,
             };
         })

+ 5 - 4
src/shared/chat/message-actions.js

@@ -1,6 +1,3 @@
-/**
- * @typedef {module:headless-shared-parsers.MediaURLMetadata} MediaURLData
- */
 import { html } from 'lit';
 import { until } from 'lit/directives/until.js';
 import { api, log, _converse, u, constants } from '@converse/headless';
@@ -24,6 +21,10 @@ const { CHATROOMS_TYPE } = constants;
  */
 
 class MessageActions extends CustomElement {
+    /**
+     * @typedef {import('@converse/headless/types/utils/types').MediaURLMetadata} MediaURLMetadata
+     */
+
     static get properties () {
         return {
             is_retracted: { type: Boolean },
@@ -255,7 +256,7 @@ class MessageActions extends CustomElement {
             .filter(o => isMediaURLDomainAllowed(o));
 
         const url_strings = getMediaURLs(this.model.get('media_urls') || [], this.model.get('body'));
-        const media_urls = /** @type {MediaURLData[]} */(url_strings.filter(o => isMediaURLDomainAllowed(o)));
+        const media_urls = /** @type {MediaURLMetadata[]} */(url_strings.filter(o => isMediaURLDomainAllowed(o)));
         return [...new Set([...media_urls.map(o => o.url), ...unfurls_to_show.map(o => o.url)])];
     }
 

+ 16 - 14
src/shared/texture/texture.js

@@ -53,6 +53,10 @@ const {
  * rich features.
  */
 export class Texture extends String {
+    /**
+     * @typedef {import('@converse/headless/types/utils/types').MediaURLMetadata} MediaURLMetadata
+     */
+
     /**
      * Create a new {@link Texture} instance.
      * @param {string} text - The text to be annotated
@@ -83,8 +87,6 @@ export class Texture extends String {
      * @param {Function} [options.onImgClick] - Callback for when an inline rendered image has been clicked
      * @param {Function} [options.onImgLoad] - Callback for when an inline rendered image has been loaded
      * @param {boolean} [options.hide_media_urls] - Callback for when an inline rendered image has been loaded
-     *
-     * @typedef {module:headless-shared-parsers.MediaURLMetadata} MediaURLMetadata
      */
     constructor(text, offset = 0, options = {}) {
         super(text);
@@ -125,16 +127,16 @@ export class Texture extends String {
 
     /**
      * Look for `http` URIs and return templates that render them as URL links
-     * @param {import('utils/url').MediaURLData} url_obj
+     * @param {MediaURLMetadata} url_obj
      * @returns {Promise<string|import('lit').TemplateResult>}
      */
     async addHyperlinkTemplate(url_obj) {
-        const { url_text } = url_obj;
-        const filtered_url = filterQueryParamsFromURL(url_text);
+        const { url } = url_obj;
+        const filtered_url = filterQueryParamsFromURL(url);
         let template;
-        if (isGIFURL(url_text) && this.shouldRenderMedia(url_text, "image")) {
+        if (isGIFURL(url) && this.shouldRenderMedia(url, "image")) {
             template = tplGif(filtered_url, this.hide_media_urls);
-        } else if (isImageURL(url_text) && this.shouldRenderMedia(url_text, "image")) {
+        } else if (isImageURL(url) && this.shouldRenderMedia(url, "image")) {
             template = tplImage({
                 src: filtered_url,
                 // XXX: bit of an abuse of `hide_media_urls`, might want a dedicated option here
@@ -142,16 +144,16 @@ export class Texture extends String {
                 onClick: this.onImgClick,
                 onLoad: this.onImgLoad,
             });
-        } else if (isVideoURL(url_text) && this.shouldRenderMedia(url_text, "video")) {
+        } else if (isVideoURL(url) && this.shouldRenderMedia(url, "video")) {
             template = tplVideo(filtered_url, this.hide_media_urls);
-        } else if (isAudioURL(url_text) && this.shouldRenderMedia(url_text, "audio")) {
+        } else if (isAudioURL(url) && this.shouldRenderMedia(url, "audio")) {
             template = tplAudio(filtered_url, this.hide_media_urls);
-        } else if (api.settings.get("embed_3rd_party_media_players") && isSpotifyTrack(url_text)) {
-            const song_id = url_text.split("/track/")[1];
-            template = tplSpotify(song_id, url_text, this.hide_media_urls);
+        } else if (api.settings.get("embed_3rd_party_media_players") && isSpotifyTrack(url)) {
+            const song_id = url.split("/track/")[1];
+            template = tplSpotify(song_id, url, this.hide_media_urls);
         } else {
-            if (this.shouldRenderMedia(url_text, "audio") && api.settings.get("fetch_url_headers")) {
-                const headers = await getHeaders(url_text);
+            if (this.shouldRenderMedia(url, "audio") && api.settings.get("fetch_url_headers")) {
+                const headers = await getHeaders(url);
                 if (headers?.get("content-type")?.startsWith("audio")) {
                     template = tplAudio(filtered_url, this.hide_media_urls, headers.get("Icy-Name"));
                 }

+ 0 - 1
src/types/shared/chat/message-actions.d.ts

@@ -1,4 +1,3 @@
-export type MediaURLData = any;
 /**
  * An object which represents a message action (as shown in the message dropdown);
  */

+ 8 - 7
src/types/shared/texture/texture.d.ts

@@ -23,6 +23,9 @@ export function getDirectiveTemplate(d: string, text: string, offset: number, op
  * rich features.
  */
 export class Texture extends String {
+    /**
+     * @typedef {import('@converse/headless/types/utils/types').MediaURLMetadata} MediaURLMetadata
+     */
     /**
      * Create a new {@link Texture} instance.
      * @param {string} text - The text to be annotated
@@ -53,8 +56,6 @@ export class Texture extends String {
      * @param {Function} [options.onImgClick] - Callback for when an inline rendered image has been clicked
      * @param {Function} [options.onImgLoad] - Callback for when an inline rendered image has been loaded
      * @param {boolean} [options.hide_media_urls] - Callback for when an inline rendered image has been loaded
-     *
-     * @typedef {module:headless-shared-parsers.MediaURLMetadata} MediaURLMetadata
      */
     constructor(text: string, offset?: number, options?: {
         nick?: string;
@@ -62,7 +63,7 @@ export class Texture extends String {
         embed_audio?: boolean;
         embed_videos?: boolean;
         mentions?: any[];
-        media_urls?: any[];
+        media_urls?: import("@converse/headless/types/utils/types").MediaURLMetadata[];
         show_images?: boolean;
         show_me_message?: boolean;
         onImgClick?: Function;
@@ -72,7 +73,7 @@ export class Texture extends String {
     embed_audio: boolean;
     embed_videos: boolean;
     mentions: any[];
-    media_urls: any[];
+    media_urls: import("@converse/headless/types/utils/types").MediaURLMetadata[];
     nick: string;
     offset: number;
     onImgClick: Function;
@@ -83,7 +84,7 @@ export class Texture extends String {
         embed_audio?: boolean;
         embed_videos?: boolean;
         mentions?: any[];
-        media_urls?: any[];
+        media_urls?: import("@converse/headless/types/utils/types").MediaURLMetadata[];
         show_images?: boolean;
         show_me_message?: boolean;
         onImgClick?: Function;
@@ -102,10 +103,10 @@ export class Texture extends String {
     shouldRenderMedia(url: string, type: "audio" | "image" | "video"): any;
     /**
      * Look for `http` URIs and return templates that render them as URL links
-     * @param {import('utils/url').MediaURLData} url_obj
+     * @param {MediaURLMetadata} url_obj
      * @returns {Promise<string|import('lit').TemplateResult>}
      */
-    addHyperlinkTemplate(url_obj: import("utils/url").MediaURLData): Promise<string | import("lit").TemplateResult>;
+    addHyperlinkTemplate(url_obj: import("@converse/headless/types/utils/types").MediaURLMetadata): Promise<string | import("lit").TemplateResult>;
     /**
      * Look for `http` URIs and return templates that render them as URL links
      * @param {string} text

+ 1 - 2
src/types/utils/index.d.ts

@@ -86,7 +86,7 @@ declare const _default: {
 } & import("headless/types/utils/index.js").CommonUtils & import("headless/types/utils/index.js").PluginUtils & {
     isDomainWhitelisted(whitelist: string[], url: string | URL): boolean;
     isDomainAllowed(url: string | URL, setting: string): boolean;
-    isMediaURLDomainAllowed(o: MediaURLData): boolean;
+    isMediaURLDomainAllowed(o: import("headless/types/utils/types.js").MediaURLMetadata): boolean;
     shouldRenderMediaFromURL(url_text: string, type: "audio" | "image" | "video"): any;
     filterQueryParamsFromURL(url: string): string;
     getNameAndValue(field: HTMLInputElement | HTMLSelectElement): {
@@ -274,7 +274,6 @@ declare const _default: {
     getAuthorStyle(occupant: any): string | TemplateResult;
 };
 export default _default;
-import * as url from "./url.js";
 import * as html from "./html.js";
 import * as file from "./file.js";
 import * as color from "./color.js";

+ 2 - 3
src/types/utils/url.d.ts

@@ -11,10 +11,10 @@ export function isDomainAllowed(url: string | URL, setting: string): boolean;
 /**
  * Accepts a {@link MediaURLData} object and then checks whether its domain is
  * allowed for rendering in the chat.
- * @param {MediaURLData} o
+ * @param {import('@converse/headless/types/utils/types').MediaURLMetadata} o
  * @returns {boolean}
  */
-export function isMediaURLDomainAllowed(o: MediaURLData): boolean;
+export function isMediaURLDomainAllowed(o: import("@converse/headless/types/utils/types").MediaURLMetadata): boolean;
 /**
  * @param {string} url_text
  * @param {"audio"|"image"|"video"} type
@@ -27,5 +27,4 @@ export function shouldRenderMediaFromURL(url_text: string, type: "audio" | "imag
  * @return {string}
  */
 export function filterQueryParamsFromURL(url: string): string;
-export type MediaURLData = any;
 //# sourceMappingURL=url.d.ts.map

+ 1 - 4
src/utils/url.js

@@ -1,6 +1,3 @@
-/**
- * @typedef {module:headless-shared-chat-utils.MediaURLData} MediaURLData
- */
 import { api, log, u } from "@converse/headless";
 
 /**
@@ -36,7 +33,7 @@ export function isDomainAllowed(url, setting) {
 /**
  * Accepts a {@link MediaURLData} object and then checks whether its domain is
  * allowed for rendering in the chat.
- * @param {MediaURLData} o
+ * @param {import('@converse/headless/types/utils/types').MediaURLMetadata} o
  * @returns {boolean}
  */
 export function isMediaURLDomainAllowed(o) {