// ==UserScript==
// @name 页内弹窗打开新帖
// @namespace http://tampermonkey.net/
// @version 1.9.1
// @description 点击论坛帖子链接,在弹窗中加载内容 (移除侧边栏功能)
// @author AI
// @match https://www.tgb.cn/user/blog/*
// @match https://www.tgb.cn/blog/*
// @match https://www.tgb.cn/*
// @match https://shuo.tgb.cn/livenews/*
// @match https://www.wnflb2023.com/forum*
// @match https://www.52pojie.cn/forum.php?*
// @match *://1cili.com/*
// @match https://linux.do/*
// @match https://github.com/*/*/issues
// @match *://s.9cili.mom/*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @connect *
// @license MIT
// @downloadURL https://update.greasyfork.icu/scripts/535799/%E9%A1%B5%E5%86%85%E5%BC%B9%E7%AA%97%E6%89%93%E5%BC%80%E6%96%B0%E5%B8%96.user.js
// @updateURL https://update.greasyfork.icu/scripts/535799/%E9%A1%B5%E5%86%85%E5%BC%B9%E7%AA%97%E6%89%93%E5%BC%80%E6%96%B0%E5%B8%96.meta.js
// ==/UserScript==
(function() {
'use strict';
// 添加全局样式 (unchanged)
GM_addStyle(`
/* 基础链接样式优化 */
.suh a, table tr td a, th.common a {
cursor: pointer;
transition: color 0.2s ease-in-out, text-shadow 0.2s ease-in-out;
text-decoration: none;
position: relative;
color: inherit;
}
.suh a:hover, table tr td a:hover, th.common a.xst:hover {
color: #2979ff;
text-shadow: 0 0 5px rgba(41, 121, 255, 0.3);
}
/* 面板核心样式 (弹窗模式) */
#popup-content-panel {
position: fixed;
z-index: 10000;
background-color: #fff;
box-shadow: 0 5px 35px rgba(0, 0, 0, 0.15);
display: flex;
flex-direction: column;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
overflow: hidden;
opacity: 0;
pointer-events: none;
width: 84vw;
height: 96vh;
max-width: 1080px;
max-height: 840px;
top: 50%;
left: 50%;
border: 1px solid #ccc;
border-radius: 8px;
transform: translate(-50%, -50%) scale(0.95);
transition: opacity 0.3s ease, transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
#popup-content-panel.visible {
opacity: 1;
pointer-events: auto;
transform: translate(-50%, -50%) scale(1);
}
/* 面板头部 */
#popup-panel-header {
display: flex; justify-content: space-between; align-items: center;
padding: 10px 12px;
background-color: #f9f9f9;
border-bottom: 1px solid #e0e0e0; height: 52px; min-height: 52px; box-sizing: border-box;
cursor: grab;
}
#popup-panel-header:active {
cursor: grabbing;
}
#popup-panel-title {
font-size: 16px;
font-weight: 500; color: #333;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
max-width: calc(100% - 130px);
user-select: none;
}
#popup-panel-actions { display: flex; gap: 5px; }
.popup-panel-btn {
background-color: transparent; border: 1px solid transparent; border-radius: 4px;
padding: 5px 7px;
cursor: pointer; display: flex; align-items: center; justify-content: center;
transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out, transform 0.1s ease-in-out;
color: #555;
}
.popup-panel-btn svg { width: 16px; height: 16px; }
.popup-panel-btn:hover { background-color: #e9e9e9; color: #333; }
.popup-panel-btn:active { transform: translateY(0.5px); background-color: #dcdcdc; }
.popup-panel-btn svg { pointer-events: none; }
#popup-panel-close:hover { color: #d32f2f; }
#popup-panel-refresh:hover, #popup-panel-open-in-new:hover,
#popup-panel-maximize:hover { color: #1976d2; }
/* 内容区域 */
#popup-content-area {
flex: 1; overflow-y: auto; position: relative;
background-color: #fff; padding: 15px; box-sizing: border-box; scroll-behavior: smooth;
}
#popup-content-area.iframe-direct-load {
padding: 0; /* Remove padding when iframe loads src directly */
}
/* 加载与错误状态 */
#popup-panel-loading { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: #777; padding: 25px; }
.spinner { width: 36px; height: 36px; margin-bottom: 18px; border: 3px solid rgba(41, 121, 255, 0.2); border-radius: 50%; border-top: 3px solid #2979ff; animation: spin 0.8s cubic-bezier(0.68, -0.55, 0.27, 1.55) infinite; }
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
#popup-panel-error { padding: 35px; color: #c62828; text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; box-sizing: border-box; }
#popup-panel-error h3 { margin-top: 18px; margin-bottom: 12px; font-weight: 500; font-size: 1.2em; }
#popup-panel-error p { margin-bottom: 22px; color: #777; max-width: 420px; line-height: 1.6; }
#popup-panel-error button { padding: 11px 22px; background: #2979ff; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: 500; transition: background 0.15s ease-in-out, transform 0.1s ease-in-out, box-shadow 0.15s ease-in-out; }
#popup-panel-error button:hover { background: #4d90fe; transform: translateY(-0.5px); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); }
/* Iframe */
#popup-panel-iframe { width: 100%; height: 100%; border: none; background-color: white; }
/* 链接视觉提示 (unchanged from v1.7) */
.popup-trigger::after, th.common::after, a.xst::after {
content: ''; /* Material Symbols Outlined: open_in_new_down */
font-family: 'Material Symbols Outlined';
position: absolute; right: 8px; top: 50%;
transform: translateY(-50%); font-size: 16px; opacity: 0;
transition: opacity 0.2s ease-in-out, transform 0.15s ease-in-out;
pointer-events: none;
}
div.items-content-tittle.popup-trigger { position: relative; }
div.items-content-tittle.popup-trigger::after {
right: 5px;
}
div.tittle_data.popup-trigger { position: relative; padding-right: 25px; }
div.tittle_data.popup-trigger::after {
right: 5px;
}
div.items-content-remark.popup-trigger {
position: relative;
padding-right: 25px;
}
div.items-content-remark.popup-trigger::after {
right: 5px;
}
div.items-content-tittle.popup-trigger {
padding-right: 25px;
}
.popup-trigger:hover::after,
th.common:hover::after,
a.xst:hover::after,
div.items-content-tittle.popup-trigger:hover::after,
div.tittle_data.popup-trigger:hover::after,
div.items-content-remark.popup-trigger:hover::after {
opacity: 0.7; transform: translateY(-50%) scale(1.05);
}
th.common { position: relative; }
a.xst { position: relative; display: inline-block; transition: color 0.15s ease-in-out, padding-right 0.15s ease-in-out; padding-right: 20px; }
a.xst:hover { color: #2979ff; padding-right: 25px; }
a.xst::after { right: 0; }
/* 遮罩层 (unchanged) */
#popup-panel-overlay {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.2);
opacity: 0; z-index: 9998;
transition: opacity 0.3s ease-in-out;
pointer-events: none;
backdrop-filter: blur(3px);
}
#popup-panel-overlay.visible {
opacity: 1;
pointer-events: auto;
}
`);
// SVG 图标定义 (unchanged)
const ICONS = {
close: '',
external: '',
refresh: '',
maximize: '',
minimize: ''
};
// 全局变量 (unchanged)
let currentUrl = "";
let isFullScreen = false;
let panelPreFullScreenDimensions = {};
let maximizeBtnElement;
// --- Panel Creation and Management Functions (unchanged) ---
function createOverlay() {
if (document.getElementById("popup-panel-overlay")) return document.getElementById("popup-panel-overlay");
const overlay = document.createElement("div");
overlay.id = "popup-panel-overlay";
overlay.addEventListener("click", closePanel);
document.body.appendChild(overlay);
return overlay;
}
function createContentPanel() {
if (document.getElementById("popup-content-panel")) return document.getElementById("popup-content-panel");
createOverlay();
const popupPanel = document.createElement("div");
popupPanel.id = "popup-content-panel";
const header = document.createElement("div");
header.id = "popup-panel-header";
const title = document.createElement("div");
title.id = "popup-panel-title";
const actions = document.createElement("div");
actions.id = "popup-panel-actions";
const refreshBtn = document.createElement("button");
refreshBtn.id = "popup-panel-refresh"; refreshBtn.className = "popup-panel-btn";
refreshBtn.innerHTML = ICONS.refresh; refreshBtn.title = "刷新内容 (R)";
refreshBtn.onclick = () => { if (currentUrl) loadContent(currentUrl); };
maximizeBtnElement = document.createElement("button");
maximizeBtnElement.id = "popup-panel-maximize"; maximizeBtnElement.className = "popup-panel-btn";
maximizeBtnElement.onclick = toggleFullScreen;
const openBtn = document.createElement("button");
openBtn.id = "popup-panel-open-in-new"; openBtn.className = "popup-panel-btn";
openBtn.innerHTML = ICONS.external; openBtn.title = "在新标签页打开";
openBtn.onclick = () => { if (currentUrl) window.open(currentUrl, "_blank"); };
const closeBtn = document.createElement("button");
closeBtn.id = "popup-panel-close"; closeBtn.className = "popup-panel-btn";
closeBtn.innerHTML = ICONS.close; closeBtn.title = "关闭 (Esc)";
closeBtn.onclick = closePanel;
const contentArea = document.createElement("div");
contentArea.id = "popup-content-area";
actions.appendChild(refreshBtn);
actions.appendChild(maximizeBtnElement);
actions.appendChild(openBtn);
actions.appendChild(closeBtn);
header.appendChild(title);
header.appendChild(actions);
popupPanel.appendChild(header);
popupPanel.appendChild(contentArea);
document.body.appendChild(popupPanel);
document.addEventListener("keydown", (e) => {
const panel = document.getElementById("popup-content-panel");
if (panel && panel.classList.contains("visible")) {
if (e.key === "Escape") closePanel();
else if (e.key === "f" || e.key === "F") toggleFullScreen();
else if (e.key === "r" || e.key === "R") {
if (currentUrl && !e.ctrlKey && !e.metaKey) {
e.preventDefault(); loadContent(currentUrl);
}
}
}
});
header.addEventListener("dblclick", (e) => {
if (e.target.closest('button')) return;
toggleFullScreen();
});
return popupPanel;
}
function updateMaximizeButtonIcon() {
if (maximizeBtnElement) {
maximizeBtnElement.innerHTML = isFullScreen ? ICONS.minimize : ICONS.maximize;
maximizeBtnElement.title = isFullScreen ? "恢复 (F)" : "全屏 (F)";
}
}
function toggleFullScreen() {
const popupPanel = document.getElementById("popup-content-panel");
if (!popupPanel) return;
if (!isFullScreen) {
panelPreFullScreenDimensions = {
width: popupPanel.style.width, height: popupPanel.style.height,
top: popupPanel.style.top, left: popupPanel.style.left,
transform: popupPanel.style.transform, borderRadius: popupPanel.style.borderRadius,
maxWidth: popupPanel.style.maxWidth, maxHeight: popupPanel.style.maxHeight
};
popupPanel.style.transition = 'none';
Object.assign(popupPanel.style, {
width: "100vw", height: "100vh", top: "0px", left: "0px",
transform: "none", borderRadius: "0px", maxWidth: "none", maxHeight: "none",
zIndex: "10002"
});
void popupPanel.offsetWidth;
popupPanel.style.transition = '';
isFullScreen = true;
} else {
popupPanel.style.transition = 'none';
Object.assign(popupPanel.style, {
width: panelPreFullScreenDimensions.width || '', height: panelPreFullScreenDimensions.height || '',
top: panelPreFullScreenDimensions.top || '', left: panelPreFullScreenDimensions.left || '',
transform: panelPreFullScreenDimensions.transform || '', borderRadius: panelPreFullScreenDimensions.borderRadius || '',
maxWidth: panelPreFullScreenDimensions.maxWidth || '', maxHeight: panelPreFullScreenDimensions.maxHeight || '',
zIndex: "10000"
});
void popupPanel.offsetWidth;
popupPanel.style.transition = '';
isFullScreen = false;
}
updateMaximizeButtonIcon();
}
function closePanel() {
const popupPanel = document.getElementById("popup-content-panel");
const overlay = document.getElementById("popup-panel-overlay");
if (!popupPanel) return;
if (isFullScreen) toggleFullScreen();
popupPanel.classList.remove("visible");
if (overlay) overlay.classList.remove("visible");
setTimeout(() => {
const contentArea = document.getElementById("popup-content-area");
if (contentArea) contentArea.innerHTML = "";
currentUrl = "";
}, 350);
}
function showPanel(titleText, urlToLoad) {
const popupPanel = createContentPanel();
const overlay = document.getElementById("popup-panel-overlay");
currentUrl = urlToLoad;
document.getElementById("popup-panel-title").textContent = titleText || "查看内容";
popupPanel.classList.remove('visible');
Object.assign(popupPanel.style, {
width: '', height: '', top: '', left: '', transform: '',
maxWidth: '', maxHeight: '', borderRadius: '', zIndex: ''
});
isFullScreen = false;
updateMaximizeButtonIcon();
requestAnimationFrame(() => {
popupPanel.classList.add("visible");
if (overlay) overlay.classList.add("visible");
});
return document.getElementById("popup-content-area");
}
function showLoading(container) {
container.classList.remove('iframe-direct-load');
container.innerHTML = `
`;
}
function showError(container, message) {
container.classList.remove('iframe-direct-load');
const escapedUrl = currentUrl ? currentUrl.replace(/'/g, "\\'") : '';
container.innerHTML = `
`;
}
function loadContent(url) {
const contentArea = document.getElementById("popup-content-area");
if (!contentArea) return;
contentArea.classList.remove('iframe-direct-load'); // Reset class
contentArea.innerHTML = ""; // Clear previous content before showing loading or iframe
if (url.includes("linux.do")) {
console.log(`[PopupViewer] Attempting direct iframe load for: ${url}`);
showLoading(contentArea); // Show spinner HTML
const iframe = document.createElement("iframe");
iframe.id = "popup-panel-iframe";
iframe.sandbox = "allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts";
// Note: allow-top-navigation and allow-popups-to-escape-sandbox are omitted to prevent breaking out
let loadTimeoutCleared = false;
const loadTimeout = setTimeout(() => {
if (loadTimeoutCleared) return;
loadTimeoutCleared = true;
console.warn(`[PopupViewer] Timeout waiting for ${url} to load directly.`);
if (document.getElementById('popup-panel-loading')) {
showError(contentArea, `加载 ${url} 超时或被阻止。请尝试在新标签页打开。`);
}
}, 15000); // 15 seconds timeout
iframe.onload = () => {
if (loadTimeoutCleared) return; // Avoid acting if timeout already processed this
loadTimeoutCleared = true;
clearTimeout(loadTimeout);
console.log(`[PopupViewer] iframe onload event for ${url}.`);
// The iframe has loaded. Remove spinner and ensure iframe is styled.
// The spinner was the content of contentArea. Now replace it.
const loadingSpinner = document.getElementById('popup-panel-loading');
if (loadingSpinner && loadingSpinner.parentNode === contentArea) {
contentArea.removeChild(loadingSpinner);
}
// If the iframe isn't already in contentArea (e.g., if an error cleared it, though unlikely here),
// or if something else replaced the spinner, ensure the iframe is the sole content.
if (!contentArea.contains(iframe)) {
contentArea.innerHTML = ''; // Clear anything else
contentArea.appendChild(iframe);
}
contentArea.classList.add('iframe-direct-load');
};
iframe.onerror = () => {
if (loadTimeoutCleared) return;
loadTimeoutCleared = true;
clearTimeout(loadTimeout);
console.error(`[PopupViewer] Error loading ${url} directly into iframe via onerror.`);
showError(contentArea, `加载 ${url} 失败。`);
};
// Replace the loading spinner content with the iframe element itself.
// Setting iframe.src will trigger the load.
contentArea.innerHTML = ''; // Clear spinner HTML
contentArea.appendChild(iframe);
iframe.src = url; // Set src AFTER appending to ensure onload/onerror are attached
return;
}
// Default method for other sites (GM_xmlhttpRequest)
showLoading(contentArea);
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: (response) => {
if (response.status === 200) {
try {
contentArea.innerHTML = ""; // Clear loading message
const iframe = document.createElement("iframe");
iframe.id = "popup-panel-iframe";
iframe.sandbox = "allow-forms allow-modals allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts";
contentArea.appendChild(iframe);
const iframeDoc = iframe.contentWindow.document;
iframeDoc.open();
let baseHref = url;
try {
const urlObj = new URL(url);
baseHref = urlObj.origin ? `${urlObj.origin}${urlObj.pathname}` : urlObj.pathname;
} catch (e) {
console.warn("Could not create base URL from:", url, e);
}
iframeDoc.write(`Content${response.responseText}`);
iframeDoc.close();
iframe.onload = () => {
try {
const links = iframeDoc.querySelectorAll("a[href]");
links.forEach(link => {
link.target = "_blank";
try {
if (!link.getAttribute('href')?.startsWith('javascript:')) {
const absoluteUrl = new URL(link.getAttribute('href'), iframeDoc.baseURI).href;
link.href = absoluteUrl;
}
} catch (e) { /* console.warn("Could not absolutize URL:", link.getAttribute('href'), e); */ }
});
const style = iframeDoc.createElement('style');
style.textContent = `body { font-family: Segoe UI, sans-serif; padding: 10px; word-wrap: break-word; overflow-wrap: break-word; } img, video, iframe { max-width: 100%; height: auto; } a { color: #007bff; text-decoration: none; } a:hover { text-decoration: underline; } a:visited { color: #6a0dad; }`;
iframeDoc.head.appendChild(style);
} catch (iframeError) {
console.error("Error manipulating iframe content:", iframeError);
}
};
if (iframe.contentWindow && iframe.contentWindow.document.readyState === 'complete') {
iframe.onload();
}
} catch (error) {
showError(contentArea, "内容解析失败: " + error.message);
console.error("Error processing content:", error);
}
} else {
showError(contentArea, `加载失败 (HTTP ${response.status})`);
}
},
onerror: (error) => {
showError(contentArea, "网络请求失败");
console.error("GM_xmlhttpRequest error:", error);
},
});
}
// --- Refactored Link Handling Logic (unchanged from v1.6) ---
function isLinkSamePageAnchor(href) {
try {
const currentLoc = new URL(window.location.href);
const linkLoc = new URL(href, window.location.href);
return linkLoc.origin === currentLoc.origin &&
linkLoc.pathname === currentLoc.pathname &&
linkLoc.hash &&
linkLoc.href !== currentLoc.href;
} catch (e) {
return false;
}
}
function activateLinkInPanel(event, clickedElement, title, urlToOpen) {
event.preventDefault();
event.stopPropagation();
showPanel(title, urlToOpen);
loadContent(urlToOpen);
}
function handleForumLink_XST(event) {
const link = event.target.closest("a.xst");
if (link && link.href && !link.href.startsWith('javascript:')) {
if (isLinkSamePageAnchor(link.href)) {
return false;
}
const title = link.textContent.trim() || "查看帖子";
const resolvedUrl = new URL(link.href, window.location.origin).href;
activateLinkInPanel(event, link, title, resolvedUrl);
return true;
}
return false;
}
function handleTGBGenericItemClick(event) {
const clickedElement = event.target;
const titleDiv = clickedElement.closest('div.items-content-tittle.popup-trigger');
const remarkDiv = clickedElement.closest('div.items-content-remark.popup-trigger');
const targetContainer = titleDiv || remarkDiv;
if (!targetContainer || !targetContainer.closest('div.items-list-content')) {
return false;
}
const hostname = window.location.hostname;
const pathname = window.location.pathname;
if (!(hostname === "www.tgb.cn" && !pathname.startsWith("/blog/") && !pathname.startsWith("/user/blog/"))) {
return false;
}
let linkElement = null;
let urlToOpen = null;
let titleText = "";
if (targetContainer.parentElement.tagName === 'A') {
linkElement = targetContainer.parentElement;
const href = linkElement.getAttribute('href');
if (href && !href.startsWith('javascript:')) {
try { urlToOpen = new URL(href, window.location.origin).href; } catch (e) { console.warn("Error resolving href in TGB Generic (parent A):", href, e); }
}
titleText = linkElement.title || targetContainer.textContent.trim() || "淘股吧内容";
} else {
linkElement = targetContainer.querySelector('a');
if (linkElement) {
const dataHref = linkElement.dataset.href;
const href = linkElement.getAttribute('href');
if (dataHref) {
try { urlToOpen = new URL(dataHref, window.location.origin).href; } catch (e) { console.warn("Error resolving data-href in TGB Generic (child A):", dataHref, e); }
}
if (!urlToOpen && href && !href.startsWith('javascript:')) {
try { urlToOpen = new URL(href, window.location.origin).href; } catch (e) { console.warn("Error resolving href in TGB Generic (child A fallback):", href, e); }
}
titleText = linkElement.title || linkElement.textContent.trim() || targetContainer.textContent.trim() || "淘股吧内容";
}
}
if (linkElement && urlToOpen && !isLinkSamePageAnchor(urlToOpen)) {
activateLinkInPanel(event, linkElement, titleText, urlToOpen);
return true;
}
return false;
}
const COMMON_SITE_HANDLERS = [
{
name: "GitHub Issues",
condition: (hostname, pathname) => hostname === "github.com" && pathname.includes("/issues"),
linkSelector: 'a.IssuePullRequestTitle-module__ListItemTitle_1--_xOfg',
parentSelector: 'div.IssueRow-module__row--XmR1f',
titleExtractor: (el) => el.textContent.trim() || "查看 GitHub Issue",
},
{
name: "Linux.do Topics",
condition: (hostname, pathname) => hostname === "linux.do",
linkSelector: 'a.title.raw-link.raw-topic-link',
parentSelector: 'tr.topic-list-item',
titleExtractor: (el) => el.textContent.trim() || "查看主题",
},
{
name: "TGB Shuo Livenews",
condition: (hostname, pathname) => hostname === "shuo.tgb.cn" && pathname.startsWith("/livenews/"),
linkSelector: 'div.items-content-tittle a',
parentSelector: 'div.items-list-content',
titleExtractor: (el) => el.textContent.trim() || "查看资讯",
},
{
name: "TGB Blog",
condition: (hostname, pathname) => hostname === "www.tgb.cn" && pathname.startsWith("/blog/"),
linkSelector: 'div.tittle_data a',
parentSelector: 'div.article_tittle',
titleExtractor: (el) => el.title || el.textContent.trim() || "查看博客",
}
];
function handleLinkClick(event) {
if (event.target.closest("#popup-content-panel") && !event.target.closest('.popup-panel-btn')) {
return;
}
const currentHostname = window.location.hostname;
const currentPathname = window.location.pathname;
if (handleForumLink_XST(event)) return;
if (handleTGBGenericItemClick(event)) return;
if (currentHostname.includes("cili.")) {
const target = event.target;
const tableRow = target.closest("tr");
if (tableRow) {
const firstTd = tableRow.querySelector("td:first-child");
if (firstTd && firstTd.contains(target)) {
const linkCell = firstTd.querySelector("a");
if (linkCell && linkCell.href && !linkCell.href.startsWith('javascript:')) {
const resolvedUrl = new URL(linkCell.href, window.location.origin).href;
if (isLinkSamePageAnchor(resolvedUrl)) {
return;
}
let title = (linkCell.querySelector("b")?.textContent || linkCell.textContent).trim() || "查看内容";
activateLinkInPanel(event, linkCell, title, resolvedUrl);
return;
}
}
}
}
for (const handler of COMMON_SITE_HANDLERS) {
if (handler.condition(currentHostname, currentPathname)) {
const linkElement = event.target.closest(handler.linkSelector) ||
(event.target.matches(handler.linkSelector) ? event.target : null);
if (linkElement && (!handler.parentSelector || linkElement.closest(handler.parentSelector))) {
let resolvedUrl;
const hrefAttr = linkElement.getAttribute('href');
if (hrefAttr && !hrefAttr.startsWith('javascript:')) {
try {
resolvedUrl = new URL(hrefAttr, window.location.origin).href;
} catch(e) {
console.warn("Error resolving href for common handler link:", hrefAttr, e);
resolvedUrl = null;
}
}
if (!resolvedUrl) {
continue;
}
if (isLinkSamePageAnchor(resolvedUrl)) {
return;
}
const title = handler.titleExtractor(linkElement);
activateLinkInPanel(event, linkElement, title, resolvedUrl);
return;
}
}
}
const targetSuhTd = event.target.closest("td.suh");
if (targetSuhTd) {
const link = event.target.closest("a") || targetSuhTd.querySelector("a");
if (link && link.href && !link.href.startsWith('javascript:')) {
const resolvedUrl = new URL(link.href, window.location.origin).href;
if (isLinkSamePageAnchor(resolvedUrl)) {
return;
}
const title = link.title || link.textContent.trim() || "查看内容";
activateLinkInPanel(event, link, title, resolvedUrl);
return;
}
}
}
// --- Link Enhancement Functions (unchanged from v1.6) ---
function enhanceCiliLinks() {
if (!window.location.hostname.includes("cili.")) return;
document.querySelectorAll("tr").forEach(row => {
const firstCell = row.querySelector("td:first-child");
const link = firstCell ? firstCell.querySelector("a") : null;
if (firstCell && link && link.href && !link.href.startsWith('javascript:')) {
if (isLinkSamePageAnchor(new URL(link.href, window.location.origin).href)) return;
firstCell.classList.add("popup-trigger");
}
});
}
function enhanceForumLinks() {
document.querySelectorAll("a.xst").forEach(link => {
if (link.href && !link.href.startsWith('javascript:')) {
if (isLinkSamePageAnchor(new URL(link.href, window.location.origin).href)) return;
const th = link.closest("th.common, th.new, th.lock");
if (th && !th.classList.contains('common')) {
th.classList.add("common");
}
}
});
}
function enhanceTgbShuoLinks() {
if (!(window.location.hostname === "shuo.tgb.cn" && window.location.pathname.startsWith("/livenews/"))) return;
document.querySelectorAll('div.items-content-tittle').forEach(titleDiv => {
const link = titleDiv.querySelector('a');
if (link && link.href && !link.href.startsWith('javascript:')) {
if (isLinkSamePageAnchor(new URL(link.href, window.location.origin).href)) return;
titleDiv.classList.add("popup-trigger");
}
});
}
function enhanceTgbBlogLinks() {
if (!(window.location.hostname === "www.tgb.cn" && window.location.pathname.startsWith("/blog/"))) return;
document.querySelectorAll('div.article_tittle').forEach(articleTitleDiv => {
const titleDataDiv = articleTitleDiv.querySelector('div.tittle_data');
const link = titleDataDiv ? titleDataDiv.querySelector('a') : null;
if (titleDataDiv && link && link.href && !link.href.startsWith('javascript:')) {
if (isLinkSamePageAnchor(new URL(link.href, window.location.origin).href)) return;
titleDataDiv.classList.add("popup-trigger");
}
});
}
function enhanceTgbGenericItemLinks() {
const hostname = window.location.hostname;
const pathname = window.location.pathname;
if (!(hostname === "www.tgb.cn" && !pathname.startsWith("/blog/") && !pathname.startsWith("/user/blog/"))) {
return;
}
document.querySelectorAll('div.items-content-tittle, div.items-content-remark').forEach(containerDiv => {
if (!containerDiv.closest('div.items-list-content')) return;
let linkElement = null;
let resolvedUrl = null;
const innerLink = containerDiv.querySelector('a');
if (innerLink) {
const dataHref = innerLink.dataset.href;
const href = innerLink.getAttribute('href');
if (dataHref) {
try { resolvedUrl = new URL(dataHref, window.location.origin).href; linkElement = innerLink; } catch (e) {}
}
if (!resolvedUrl && href && !href.startsWith('javascript:')) {
try { resolvedUrl = new URL(href, window.location.origin).href; linkElement = innerLink; } catch (e) {}
}
}
if (!linkElement && containerDiv.parentElement.tagName === 'A') {
const parentLink = containerDiv.parentElement;
const href = parentLink.getAttribute('href');
if (href && !href.startsWith('javascript:')) {
try { resolvedUrl = new URL(href, window.location.origin).href; linkElement = parentLink; } catch (e) {}
}
}
if (linkElement && resolvedUrl && !isLinkSamePageAnchor(resolvedUrl)) {
containerDiv.classList.add("popup-trigger");
}
});
}
// --- Initialization ---
function init() {
const materialFontLink = document.createElement('link');
materialFontLink.href = 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200';
materialFontLink.rel = 'stylesheet';
document.head.appendChild(materialFontLink);
document.addEventListener("click", handleLinkClick, true);
const runEnhancements = () => {
enhanceCiliLinks();
enhanceForumLinks();
enhanceTgbShuoLinks();
enhanceTgbBlogLinks();
enhanceTgbGenericItemLinks();
};
runEnhancements();
const observer = new MutationObserver(runEnhancements);
observer.observe(document.body, { childList: true, subtree: true });
console.log("内容弹窗查看器 (Refactored v1.9) 已启用");
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();