From a5098078e368903e44166c8cbf2361995a37b791 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 11 Aug 2022 21:27:16 +0300 Subject: embed.js: minor improvements * updated JSDoc * minor code cleanup --- src/main/assets/embed.js | 66 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 20 deletions(-) (limited to 'src/main') diff --git a/src/main/assets/embed.js b/src/main/assets/embed.js index 5e5d1fee..52ea39aa 100644 --- a/src/main/assets/embed.js +++ b/src/main/assets/embed.js @@ -116,10 +116,10 @@ function messageReplyReplace(messageId) { * Given "txt" message in unescaped plaintext with Juick markup, this function * returns escaped formatted HTML string. * - * @param {string} txt - * @param {string} messageId - current message id - * @param {boolean} isCode - * @returns {string} + * @param {string} txt text message + * @param {string} messageId current message id + * @param {boolean} isCode set when message contains *code tag + * @returns {string} formatted message */ function juickFormat(txt, messageId, isCode) { const urlRe = /(?:\[([^\]\[]+)\](?:\[([^\]]+)\]|\(((?:[a-z]+:\/\/|www\.|ftp\.)(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[-\w+*&@#/%=~|$?!:;,.])*(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[\w+*&@#/%=~|$]))\))|\b(?:[a-z]+:\/\/|www\.|ftp\.)(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[-\w+*&@#/%=~|$?!:;,.])*(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[\w+*&@#/%=~|$]))/gi; @@ -141,14 +141,39 @@ function juickFormat(txt, messageId, isCode) { { pr: 3, re: /\n/g, with: '
' }, ]); } +/** + * @external RegExpExecArray + */ + +/** + * @callback MakeNodeCallback + * @param { HTMLAnchorElement } aNode a DOM node of the link + * @param { RegExpExecArray } reResult Result of RegExp execution + * @param { HTMLDivElement} div target DOM element which can be updated by callback function + * @returns { HTMLDivElement } updated DOM element + */ + +/** + * @typedef { object } LinkFormatData + * @property { string } id Format identifier + * @property { string } name Format description + * @property { RegExp } re Regular expression to match expected hyperlinks + * @property { string } className list of CSS classes which + * will be added to the target DOM element + * @property { MakeNodeCallback } makeNode callback function called when a target link is matched + */ +/** + * Get supported embeddable formats + * + * @returns {LinkFormatData[]} list of supported formats + */ function getEmbeddableLinkTypes() { return [ { name: 'Jpeg and png images', id: 'embed_jpeg_and_png_images', className: 'picture compact', - ctsDefault: false, re: /\.(jpe?g|png|svg)(:[a-zA-Z]+)?(?:\?[\w&;\?=]*)?$/i, makeNode: function(aNode, reResult, div) { // dirty fix for dropbox urls @@ -161,7 +186,6 @@ function getEmbeddableLinkTypes() { name: 'Gif images', id: 'embed_gif_images', className: 'picture compact', - ctsDefault: true, re: /\.gif(:[a-zA-Z]+)?(?:\?[\w&;\?=]*)?$/i, makeNode: function(aNode, reResult, div) { div.innerHTML = ``; @@ -172,7 +196,6 @@ function getEmbeddableLinkTypes() { name: 'Video (webm, mp4, ogv)', id: 'embed_webm_and_mp4_videos', className: 'video compact', - ctsDefault: false, re: /\.(webm|mp4|m4v|ogv)(?:\?[\w&;\?=]*)?$/i, makeNode: function(aNode, reResult, div) { div.innerHTML = ``; @@ -183,7 +206,6 @@ function getEmbeddableLinkTypes() { name: 'Audio (mp3, ogg, weba, opus, m4a, oga, wav)', id: 'embed_sound_files', className: 'audio singleColumn', - ctsDefault: false, re: /\.(mp3|ogg|weba|opus|m4a|oga|wav)(?:\?[\w&;\?=]*)?$/i, makeNode: function(aNode, reResult, div) { div.innerHTML = ``; @@ -194,7 +216,6 @@ function getEmbeddableLinkTypes() { name: 'YouTube videos (and playlists)', id: 'embed_youtube_videos', className: 'youtube resizableV singleColumn', - ctsDefault: false, re: /^(?:https?:)?\/\/(?:www\.|m\.|gaming\.)?(?:youtu(?:(?:\.be\/|be\.com\/(?:v|embed)\/)([-\w]+)|be\.com\/watch)((?:(?:\?|&(?:amp;)?)(?:\w+=[-\.\w]*[-\w]))*)|youtube\.com\/playlist\?list=([-\w]*)(&(amp;)?[-\w\?=]*)?)/i, makeNode: function(aNode, reResult, div) { let [url, v, args, plist] = reResult; @@ -234,7 +255,6 @@ function getEmbeddableLinkTypes() { name: 'Vimeo videos', id: 'embed_vimeo_videos', className: 'vimeo resizableV', - ctsDefault: false, re: /^(?:https?:)?\/\/(?:www\.)?(?:player\.)?vimeo\.com\/(?:video\/|album\/[\d]+\/video\/)?([\d]+)/i, makeNode: function(aNode, reResult, div) { let iframe = makeIframe('//player.vimeo.com/video/' + reResult[1], '100%', '360px'); @@ -246,14 +266,13 @@ function getEmbeddableLinkTypes() { name: 'Twitter', id: 'embed_twitter_status', className: 'twi compact', - ctsDefault: false, re: /^(?:https?:)?\/\/(?:www\.)?(?:mobile\.)?twitter\.com\/([\w-]+)\/status(?:es)?\/([\d]+)/i, makeNode: function(aNode, reResult, div) { fetch('https://juick.com/srv/oembed?url=' + reResult[0]) - .then(response => response.json()) - .then(json => { - div.innerHTML = json.html; - }); + .then(response => response.json()) + .then(json => { + div.innerHTML = json.html; + }); return div; } }, @@ -261,7 +280,6 @@ function getEmbeddableLinkTypes() { name: 'Instagram media', id: 'embed_instagram_images', className: 'picture compact', - ctsDefault: true, re: /https?:\/\/www\.?instagram\.com(\/p\/\w+)\/?/i, makeNode: function(aNode, reResult, div) { let [url, postId] = reResult; @@ -274,7 +292,6 @@ function getEmbeddableLinkTypes() { name: 'Telegram posts', id: 'embed_telegram_posts', className: 'tg compact', - ctsDefault: true, re: /https?:\/\/t\.me\/(\S+)/i, makeNode: function(aNode, reResult, div) { let [url, post] = reResult; @@ -292,12 +309,21 @@ function getEmbeddableLinkTypes() { ]; } -function embedLink(aNode, linkTypes, container, afterNode) { +/** + * Embed a link + * + * @param { HTMLAnchorElement } aNode a DOM node of the link + * @param { LinkFormatData[] } linkTypes supported link types + * @param { HTMLElement } container a target DOM element with the link content + * @param { boolean } afterNode where to insert new DOM node + * @returns { boolean } `true` when some link was embedded + */ +function embedLink(aNode, linkTypes, container, afterNode = false) { let anyEmbed = false; let linkId = (aNode.href.replace(/^https?:/i, '').replace(/\'/gi, '')); let sameEmbed = container.querySelector(`*[data-linkid='${linkId}']`); // do not embed the same thing twice - if (sameEmbed === null) { - anyEmbed = [].some.call(linkTypes, function(linkType) { + if (!sameEmbed) { + anyEmbed = linkTypes.some((linkType) => { let reResult = linkType.re.exec(aNode.href); if (reResult) { if (linkType.match && (linkType.match(aNode, reResult) === false)) { return false; } -- cgit v1.2.3