aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/assets/embed.js66
1 files changed, 46 insertions, 20 deletions
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: '<br/>' },
]);
}
+/**
+ * @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 = `<a href="${aNode.href}"><img src="${aNode.href}"></a>`;
@@ -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 = `<video src="${aNode.href}" title="${aNode.href}" controls></video>`;
@@ -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 = `<audio src="${aNode.href}" title="${aNode.href}" controls></audio>`;
@@ -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; }