this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Micro optimizations

+61 -61
+61 -61
src/utils/enhance-content.js
··· 10 10 const dom = document.createElement('div'); 11 11 dom.innerHTML = enhancedContent; 12 12 const hasLink = /<a/i.test(enhancedContent); 13 - const hasCodeBlock = enhancedContent.indexOf('```') !== -1; 13 + const hasCodeBlock = enhancedContent.includes('```'); 14 14 15 15 if (hasLink) { 16 16 // Add target="_blank" to all links with no target="_blank" 17 17 // E.g. `note` in `account` 18 - const noTargetBlankLinks = Array.from( 19 - dom.querySelectorAll('a:not([target="_blank"])'), 20 - ); 18 + const noTargetBlankLinks = dom.querySelectorAll('a:not([target="_blank"])'); 21 19 noTargetBlankLinks.forEach((link) => { 22 20 link.setAttribute('target', '_blank'); 23 21 }); 24 22 25 23 // Remove all classes except `u-url`, `mention`, `hashtag` 26 - const links = Array.from(dom.querySelectorAll('a[class]')); 24 + const links = dom.querySelectorAll('a[class]'); 27 25 links.forEach((link) => { 28 - Array.from(link.classList).forEach((c) => { 26 + link.classList.forEach((c) => { 29 27 if (!whitelistLinkClasses.includes(c)) { 30 28 link.classList.remove(c); 31 29 } ··· 35 33 36 34 // Add 'has-url-text' to all links that contains a url 37 35 if (hasLink) { 38 - const links = Array.from(dom.querySelectorAll('a[href]')); 36 + const links = dom.querySelectorAll('a[href]'); 39 37 links.forEach((link) => { 40 38 if (/^https?:\/\//i.test(link.textContent.trim())) { 41 39 link.classList.add('has-url-text'); ··· 45 43 46 44 // Spanify un-spanned mentions 47 45 if (hasLink) { 48 - const links = Array.from(dom.querySelectorAll('a[href]')); 46 + const links = dom.querySelectorAll('a[href]'); 49 47 const usernames = []; 50 48 links.forEach((link) => { 51 49 const text = link.innerText.trim(); ··· 56 54 const [_, username, domain] = text.split('@'); 57 55 if (!hasChildren) { 58 56 if ( 59 - !usernames.find(([u]) => u === username) || 60 - usernames.find(([u, d]) => u === username && d === domain) 57 + !usernames.some(([u]) => u === username) || 58 + usernames.some(([u, d]) => u === username && d === domain) 61 59 ) { 62 60 link.innerHTML = `@<span>${username}</span>`; 63 61 usernames.push([username, domain]); ··· 79 77 // ====== 80 78 // Convert :shortcode: to <img /> 81 79 let textNodes; 82 - if (enhancedContent.indexOf(':') !== -1) { 80 + if (enhancedContent.includes(':')) { 83 81 textNodes = extractTextNodes(dom); 84 82 textNodes.forEach((node) => { 85 83 let html = node.nodeValue ··· 90 88 html = emojifyText(html, emojis); 91 89 } 92 90 fauxDiv.innerHTML = html; 93 - const nodes = Array.from(fauxDiv.childNodes); 94 - node.replaceWith(...nodes); 91 + // const nodes = [...fauxDiv.childNodes]; 92 + node.replaceWith(...fauxDiv.childNodes); 95 93 }); 96 94 } 97 95 ··· 99 97 // =========== 100 98 // Convert ```code``` to <pre><code>code</code></pre> 101 99 if (hasCodeBlock) { 102 - const blocks = Array.from(dom.querySelectorAll('p')).filter((p) => 100 + const blocks = [...dom.querySelectorAll('p')].filter((p) => 103 101 /^```[^]+```$/g.test(p.innerText.trim()), 104 102 ); 105 103 blocks.forEach((block) => { ··· 113 111 114 112 // Convert multi-paragraph code blocks to <pre><code>code</code></pre> 115 113 if (hasCodeBlock) { 116 - const paragraphs = Array.from(dom.querySelectorAll('p')); 114 + const paragraphs = [...dom.querySelectorAll('p')]; 117 115 // Filter out paragraphs with ``` in beginning only 118 116 const codeBlocks = paragraphs.filter((p) => /^```/g.test(p.innerText)); 119 117 // For each codeBlocks, get all paragraphs until the last paragraph with ``` at the end only ··· 153 151 // INLINE CODE 154 152 // =========== 155 153 // Convert `code` to <code>code</code> 156 - if (enhancedContent.indexOf('`') !== -1) { 154 + if (enhancedContent.includes('`')) { 157 155 textNodes = extractTextNodes(dom); 158 156 textNodes.forEach((node) => { 159 157 let html = node.nodeValue ··· 164 162 html = html.replaceAll(/(`[^]+?`)/g, '<code>$1</code>'); 165 163 } 166 164 fauxDiv.innerHTML = html; 167 - const nodes = Array.from(fauxDiv.childNodes); 168 - node.replaceWith(...nodes); 165 + // const nodes = [...fauxDiv.childNodes]; 166 + node.replaceWith(...fauxDiv.childNodes); 169 167 }); 170 168 } 171 169 ··· 188 186 ); 189 187 } 190 188 fauxDiv.innerHTML = html; 191 - const nodes = Array.from(fauxDiv.childNodes); 192 - node.replaceWith(...nodes); 189 + // const nodes = [...fauxDiv.childNodes]; 190 + node.replaceWith(...fauxDiv.childNodes); 193 191 }); 194 192 } 195 193 196 194 // HASHTAG STUFFING 197 195 // ================ 198 196 // Get the <p> that contains a lot of hashtags, add a class to it 199 - if (enhancedContent.indexOf('#') !== -1) { 197 + if (enhancedContent.includes('#')) { 200 198 let prevIndex = null; 201 - const hashtagStuffedParagraphs = Array.from( 202 - dom.querySelectorAll('p'), 203 - ).filter((p, index) => { 204 - let hashtagCount = 0; 205 - for (let i = 0; i < p.childNodes.length; i++) { 206 - const node = p.childNodes[i]; 199 + const hashtagStuffedParagraphs = [...dom.querySelectorAll('p')].filter( 200 + (p, index) => { 201 + let hashtagCount = 0; 202 + for (let i = 0; i < p.childNodes.length; i++) { 203 + const node = p.childNodes[i]; 207 204 208 - if (node.nodeType === Node.TEXT_NODE) { 209 - const text = node.textContent.trim(); 210 - if (text !== '') { 211 - return false; 212 - } 213 - } else if (node.tagName === 'BR') { 214 - // Ignore <br /> 215 - } else if (node.tagName === 'A') { 216 - const linkText = node.textContent.trim(); 217 - if (!linkText || !linkText.startsWith('#')) { 218 - return false; 205 + if (node.nodeType === Node.TEXT_NODE) { 206 + const text = node.textContent.trim(); 207 + if (text !== '') { 208 + return false; 209 + } 210 + } else if (node.tagName === 'BR') { 211 + // Ignore <br /> 212 + } else if (node.tagName === 'A') { 213 + const linkText = node.textContent.trim(); 214 + if (!linkText || !linkText.startsWith('#')) { 215 + return false; 216 + } else { 217 + hashtagCount++; 218 + } 219 219 } else { 220 - hashtagCount++; 220 + return false; 221 221 } 222 - } else { 223 - return false; 222 + } 223 + // Only consider "stuffing" if: 224 + // - there are more than 3 hashtags 225 + // - there are more than 1 hashtag in adjacent paragraphs 226 + if (hashtagCount > 3) { 227 + prevIndex = index; 228 + return true; 224 229 } 225 - } 226 - // Only consider "stuffing" if: 227 - // - there are more than 3 hashtags 228 - // - there are more than 1 hashtag in adjacent paragraphs 229 - if (hashtagCount > 3) { 230 - prevIndex = index; 231 - return true; 232 - } 233 - if (hashtagCount > 1 && prevIndex && index === prevIndex + 1) { 234 - prevIndex = index; 235 - return true; 236 - } 237 - }); 230 + if (hashtagCount > 1 && prevIndex && index === prevIndex + 1) { 231 + prevIndex = index; 232 + return true; 233 + } 234 + }, 235 + ); 238 236 if (hashtagStuffedParagraphs?.length) { 239 237 hashtagStuffedParagraphs.forEach((p) => { 240 238 p.classList.add('hashtag-stuffing'); ··· 291 289 ); 292 290 function extractTextNodes(dom, opts = {}) { 293 291 const textNodes = []; 292 + const rejectFilterMap = Object.assign( 293 + {}, 294 + defaultRejectFilterMap, 295 + opts.rejectFilter?.reduce((acc, cur) => { 296 + acc[cur] = true; 297 + return acc; 298 + }, {}), 299 + ); 294 300 const walk = document.createTreeWalker( 295 301 dom, 296 302 NodeFilter.SHOW_TEXT, 297 303 { 298 304 acceptNode(node) { 299 - if (defaultRejectFilterMap[node.parentNode.nodeName]) { 300 - return NodeFilter.FILTER_REJECT; 301 - } 302 - if ( 303 - opts.rejectFilter && 304 - opts.rejectFilter.includes(node.parentNode.nodeName) 305 - ) { 305 + if (rejectFilterMap[node.parentNode.nodeName]) { 306 306 return NodeFilter.FILTER_REJECT; 307 307 } 308 308 return NodeFilter.FILTER_ACCEPT;