From d1ae7c0766c1e3319b4a75164123ffd364fd2389 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Fri, 28 Oct 2022 15:17:47 +0300 Subject: Merge `embed.js` from Next version --- vnext/src/ui/Avatar.js | 1 + vnext/src/ui/Thread.js | 2 +- vnext/src/utils/embed.js | 64 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/vnext/src/ui/Avatar.js b/vnext/src/ui/Avatar.js index 0ec679df..04ec5910 100644 --- a/vnext/src/ui/Avatar.js +++ b/vnext/src/ui/Avatar.js @@ -15,6 +15,7 @@ import './Avatar.css'; /** * Avatar component + * * @param {AvatarProps} props */ function Avatar({ user, style, link, children }) { diff --git a/vnext/src/ui/Thread.js b/vnext/src/ui/Thread.js index 20ea0a3c..0f0f88e3 100644 --- a/vnext/src/ui/Thread.js +++ b/vnext/src/ui/Thread.js @@ -8,7 +8,7 @@ import Spinner from './Spinner'; import { getMessages, comment, update } from '../api'; /** - * @type import('../api').Message + * @type { import('../api').Message } */ const emptyMessage = {}; diff --git a/vnext/src/utils/embed.js b/vnext/src/utils/embed.js index f7f55eb7..e1fc28dd 100644 --- a/vnext/src/utils/embed.js +++ b/vnext/src/utils/embed.js @@ -1,3 +1,9 @@ +function htmlEscape(html) { + return html.replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +} function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); @@ -13,12 +19,6 @@ function removeAllFrom(fromNode) { for (let c; c = fromNode.lastChild; ) { fromNode.removeChild(c); } } -function htmlEscape(html) { - let textarea = document.createElement('textarea'); - textarea.textContent = html; - return textarea.innerHTML; -} - // rules :: [{pr: number, re: RegExp, with: string}] // rules :: [{pr: number, re: RegExp, with: Function}] // rules :: [{pr: number, re: RegExp, brackets: true, with: [string, string]}] @@ -89,7 +89,10 @@ function makeResizable(element, calcHeight) { function extractDomain(url) { const domainRe = /^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/i; - return domainRe.exec(url)[1]; + let result = domainRe.exec(url) || []; + if (result.length > 0) { + return result[1]; + } } function urlReplace(match, p1, p2, p3) { @@ -120,7 +123,7 @@ function messageReplyReplace(messageId) { * @param {string} txt * @param {string} messageId - current message id * @param {boolean} isCode - * @returns {string} + * @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; @@ -196,7 +199,7 @@ function getEmbeddableLinkTypes() { 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; + let [v, args, plist] = reResult; let iframeUrl; if (plist) { iframeUrl = '//www.youtube-nocookie.com/embed/videoseries?list=' + plist; @@ -212,7 +215,7 @@ function getEmbeddableLinkTypes() { }; if (pp.t) { const tre = /^(?:(\d+)|(?:(\d+)h)?(?:(\d+)m)?(\d+)s|(?:(\d+)h)?(\d+)m|(\d+)h)$/i; - let [, t, h, m, s, h1, m1, h2] = tre.exec(pp.t); + let [, t, h, m, s, h1, m1, h2] = tre.exec(pp.t) || []; embedArgs['start'] = (+t) || ((+(h || h1 || h2 || 0))*60*60 + (+(m || m1 || 0))*60 + (+(s || 0))); } if (pp.list) { @@ -248,14 +251,14 @@ function getEmbeddableLinkTypes() { ctsDefault: false, re: /^(?:https?:)?\/\/(?:www\.)?(?:mobile\.)?twitter\.com\/([\w-]+)\/status(?:es)?\/([\d]+)/i, makeNode: function(aNode, reResult, div) { - let [url, userId, postId] = reResult; + let [url] = reResult; url = url.replace('mobile.',''); div.innerHTML = `
`; - if (window.twttr) { + if (window['twttr']) { // https://developer.twitter.com/en/docs/twitter-for-websites/javascript-api/guides/scripting-loading-and-initialization - window.twttr.widgets.load(div); + window['twttr'].widgets.load(div); } else { // innerHTML cannot insert scripts, so... let script = document.createElement('script'); @@ -264,6 +267,24 @@ function getEmbeddableLinkTypes() { div.appendChild(script); } + return div; + } + }, + { + name: 'Telegram posts', + id: 'embed_telegram_posts', + className: 'tg compact', + re: /https?:\/\/t\.me\/(\S+)/i, + makeNode: function(aNode, reResult, div) { + let [url, post] = reResult; + // innerHTML cannot insert scripts, so... + let script = document.createElement('script'); + script.src = 'https://telegram.org/js/telegram-widget.js?18'; + script.setAttribute('data-telegram-post', post); + script.setAttribute('data-tme-mode', 'data-tme-mode'); + script.setAttribute('data-width', '100%'); + script.charset = 'utf-8'; + div.appendChild(script); return div; } } @@ -316,7 +337,6 @@ function embedLinks(aNodes, container) { * @param {string} allLinksSelector */ export function embedLinksToX(x, beforeNodeSelector, allLinksSelector) { - let isCtsPost = false; let allLinks = x.querySelectorAll(allLinksSelector); let existingContainer = x.querySelector('div.embedContainer'); @@ -334,6 +354,9 @@ export function embedLinksToX(x, beforeNodeSelector, allLinksSelector) { } } +/** + * Embed links to articles + */ function embedLinksToArticles() { let beforeNodeSelector = 'nav.l'; let allLinksSelector = 'p:not(.ir) a, pre a'; @@ -342,6 +365,9 @@ function embedLinksToArticles() { }); } +/** + * Embed links to post + */ function embedLinksToPost() { let beforeNodeSelector = '.msg-txt + *'; let allLinksSelector = '.msg-txt a'; @@ -350,6 +376,16 @@ function embedLinksToPost() { }); } +/** + * @external NodeListOf + */ + +/** + * Embed URLs to container + * + * @param {NodeListOf} urls + * @param {HTMLDivElement} embedContainer + */ export function embedUrls(urls, embedContainer) { embedLinks(urls, embedContainer); } -- cgit v1.2.3