diff --git a/tampermonkey/hn_url_highlighter_with_preview.js b/tampermonkey/hn_url_highlighter_with_preview.js new file mode 100644 index 0000000..f630ee7 --- /dev/null +++ b/tampermonkey/hn_url_highlighter_with_preview.js @@ -0,0 +1,108 @@ +// ==UserScript== +// @name Hacker News URL Highlighter with Preview +// @namespace https://news.ycombinator.com/ +// @version 1.3 +// @description Highlights URLs in comments on Hacker News, lists them in a panel, and provides export functionality. Hover previews only in comments. +// @author MorganGeek +// @match https://news.ycombinator.com/item?id=* +// @grant GM_xmlhttpRequest +// @grant GM_setClipboard +// @connect * +// @run-at document-end +// ==/UserScript== + +(function () { + 'use strict'; + + // Create a floating panel for displaying URLs + const panel = document.createElement('div'); + panel.id = 'url-panel'; + panel.style.position = 'fixed'; + panel.style.top = '10px'; + panel.style.right = '10px'; + panel.style.backgroundColor = '#fff'; + panel.style.border = '1px solid #ccc'; + panel.style.borderRadius = '5px'; + panel.style.padding = '10px'; + panel.style.boxShadow = '0px 0px 10px rgba(0,0,0,0.2)'; + panel.style.maxHeight = '80vh'; + panel.style.overflowY = 'auto'; + panel.style.zIndex = 1000; + panel.innerHTML = '

URLs

'; + document.body.appendChild(panel); + + // Tooltip for previews + const tooltip = document.createElement('div'); + tooltip.id = 'url-tooltip'; + tooltip.style.position = 'absolute'; + tooltip.style.backgroundColor = '#fff'; + tooltip.style.border = '1px solid #ccc'; + tooltip.style.borderRadius = '5px'; + tooltip.style.padding = '5px'; + tooltip.style.boxShadow = '0px 0px 10px rgba(0,0,0,0.2)'; + tooltip.style.maxWidth = '300px'; + tooltip.style.display = 'none'; + tooltip.style.zIndex = 1001; + document.body.appendChild(tooltip); + + const urlSet = new Set(); + + // Extract URLs from comments and highlight them + const comments = document.querySelectorAll('.commtext'); + comments.forEach(comment => { + const links = comment.querySelectorAll('a[href]'); + links.forEach(link => { + const url = link.href; + if (!urlSet.has(url)) { + urlSet.add(url); + link.style.backgroundColor = '#ffff99'; // Highlight the link + + // Add the URL to the floating panel + const listItem = document.createElement('li'); + listItem.textContent = url; + listItem.style.marginBottom = '5px'; + listItem.style.wordWrap = 'break-word'; + listItem.style.cursor = 'pointer'; + listItem.dataset.url = url; + document.getElementById('url-list').appendChild(listItem); + } + + // Add hover preview functionality to comment links + link.addEventListener('mouseover', () => { + GM_xmlhttpRequest({ + method: 'GET', + url: url, + onload: response => { + tooltip.innerHTML = ''; + const parser = new DOMParser(); + const doc = parser.parseFromString(response.responseText, 'text/html'); + const title = doc.querySelector('title') ? doc.querySelector('title').innerText : 'No Title'; + const description = doc.querySelector('meta[name="description"]') ? doc.querySelector('meta[name="description"]').content : 'No Description'; + + tooltip.innerHTML = `${title}

${description}

`; + tooltip.style.display = 'block'; + }, + onerror: () => { + tooltip.innerHTML = 'Preview unavailable'; + tooltip.style.display = 'block'; + } + }); + + const rect = link.getBoundingClientRect(); + tooltip.style.top = `${rect.bottom + window.scrollY + 5}px`; + tooltip.style.left = `${rect.left + window.scrollX}px`; + }); + + link.addEventListener('mouseout', () => { + tooltip.style.display = 'none'; + }); + }); + }); + + // Handle the Copy URLs button + document.getElementById('copy-urls').addEventListener('click', () => { + const urlArray = Array.from(urlSet); + GM_setClipboard(urlArray.join('\n'), 'text'); + alert('URLs copied to clipboard!'); + }); +})();