最近论坛出了nested 浏览方式写了一个脚本可开启关闭
- 内容介绍
- 文章标签
- 相关推荐
介绍:
- 开启后替换话题链接并自动重定向到
/nested/topic/xxx?sort=old - 替换页面DOM 链接,不会二次跳转
- 首次安装弹窗引导,可选启用或稍后
油猴脚本如下
// ==UserScript==
// @name Linux.do Nested View Redirector
// @namespace http://tampermonkey.net/
// @version 1.5
// @description 自动将 linux.do 的话题链接重定向为 nested 视图并按旧到新排序
// @author sunbigfly
// @match https://linux.do/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const STORAGE_KEY = 'nested_redirector_enabled';
const WELCOME_KEY = 'nested_redirector_welcomed';
function isEnabled() {
return localStorage.getItem(STORAGE_KEY) === '1';
}
// ========== 首次安装弹窗 ==========
if (!localStorage.getItem(WELCOME_KEY)) {
document.addEventListener('DOMContentLoaded', function() {
const overlay = document.createElement('div');
Object.assign(overlay.style, {
position: 'fixed', top: '0', left: '0', width: '100%', height: '100%',
background: 'rgba(0,0,0,0.4)', zIndex: '99999',
display: 'flex', alignItems: 'center', justifyContent: 'center',
backdropFilter: 'blur(4px)', WebkitBackdropFilter: 'blur(4px)',
});
const box = document.createElement('div');
Object.assign(box.style, {
background: '#fff', borderRadius: '16px', padding: '32px',
maxWidth: '380px', width: '90%',
boxShadow: '0 24px 48px rgba(0,0,0,0.12), 0 4px 12px rgba(0,0,0,0.08)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
color: '#1a1a1a', lineHeight: '1.5',
animation: 'nested-fadein 0.2s ease-out',
});
const style = document.createElement('style');
style.textContent = `
@keyframes nested-fadein {
from { opacity: 0; transform: scale(0.96) translateY(8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
`;
document.head.appendChild(style);
box.innerHTML = `
<div style="font-size:15px; font-weight:600; color:#111; margin-bottom:16px;">
Nested View Redirector
</div>
<div style="font-size:13px; color:#555; margin-bottom:24px;">
话题页自动切换为嵌套视图,按时间正序排列。<br>
支持所有打开方式,包括中键和右键新标签页。
</div>
<div style="display:flex; gap:8px;">
<button id="nested-welcome-enable" style="
flex:1; padding:10px 0; border:none; border-radius:10px;
background:#1a1a1a; color:#fff; font-size:13px; font-weight:500;
cursor:pointer; transition: opacity 0.15s;
">启用</button>
<button id="nested-welcome-later" style="
flex:1; padding:10px 0; border:1px solid #e0e0e0; border-radius:10px;
background:transparent; color:#666; font-size:13px; font-weight:500;
cursor:pointer; transition: background 0.15s;
">稍后</button>
</div>
<div style="margin-top:14px; font-size:11px; color:#aaa; text-align:center;">
可随时通过右下角开关切换
</div>
`;
overlay.appendChild(box);
document.body.appendChild(overlay);
function close() {
overlay.remove();
localStorage.setItem(WELCOME_KEY, '1');
}
document.getElementById('nested-welcome-enable').addEventListener('click', function() {
localStorage.setItem(STORAGE_KEY, '1');
close();
location.reload();
});
document.getElementById('nested-welcome-later').addEventListener('click', close);
overlay.addEventListener('click', function(e) { if (e.target === overlay) close(); });
});
}
// ========== 悬浮开关 ==========
function createToggle() {
const enabled = isEnabled();
const btn = document.createElement('div');
Object.assign(btn.style, {
position: 'fixed', bottom: '20px', right: '20px', zIndex: '99998',
width: '40px', height: '40px', borderRadius: '50%',
background: enabled ? '#1a1a1a' : '#d4d4d4',
display: 'flex', alignItems: 'center', justifyContent: 'center',
cursor: 'pointer', boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
transition: 'background 0.2s, transform 0.15s',
});
btn.title = enabled ? '点击关闭 Nested 重定向' : '点击启用 Nested 重定向';
// 用 SVG 替代 emoji
btn.innerHTML = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/>
<polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/>
<line x1="4" y1="4" x2="9" y2="9"/>
</svg>`;
btn.addEventListener('mouseenter', () => btn.style.transform = 'scale(1.08)');
btn.addEventListener('mouseleave', () => btn.style.transform = 'scale(1)');
btn.addEventListener('click', function() {
localStorage.setItem(STORAGE_KEY, isEnabled() ? '0' : '1');
location.reload();
});
document.body.appendChild(btn);
}
if (document.body) createToggle();
else document.addEventListener('DOMContentLoaded', createToggle);
// ========== 核心逻辑(仅启用时执行) ==========
if (!isEnabled()) return;
const TOPIC_REGEX = /\/t\/(?:[^/]+\/)?(\d+)(?:\/\d+)?\/?(?:[?#].*)?$/;
function getNestedPath(url) {
try {
const u = new URL(url, location.origin);
if (u.hostname !== 'linux.do' || u.pathname.startsWith('/nested/')) return null;
const match = u.pathname.match(TOPIC_REGEX);
if (match) return `https://linux.do/nested/topic/${match[1]}?sort=old`;
} catch(e) {}
return null;
}
const currentTarget = getNestedPath(location.href);
if (currentTarget) { location.replace(currentTarget); return; }
function rewriteLink(a) {
if (!a.getAttribute('href')) return;
const target = getNestedPath(a.href);
if (!target || a.href === target) return;
if (!a.dataset.originalHref) a.dataset.originalHref = a.href;
a.href = target;
}
function rewriteAll(root) {
(root || document).querySelectorAll('a[href*="/t/"]').forEach(rewriteLink);
}
let rafId = null;
function scheduleRewrite() {
if (!rafId) rafId = requestAnimationFrame(() => { rafId = null; rewriteAll(); });
}
const observer = new MutationObserver(function(mutations) {
for (const m of mutations) {
if (m.addedNodes.length || (m.type === 'attributes' && m.target.tagName === 'A')) {
scheduleRewrite(); return;
}
}
});
function init() {
rewriteAll();
observer.observe(document.body, {
childList: true, subtree: true, attributes: true, attributeFilter: ['href'],
});
setInterval(() => rewriteAll(), 2000);
}
if (document.body) init();
else document.addEventListener('DOMContentLoaded', init);
['pushState', 'replaceState'].forEach(method => {
const original = history[method];
history[method] = function(state, title, url) {
if (url) {
const target = getNestedPath(new URL(url, location.origin).href);
if (target) { location.href = target; return; }
}
const ret = original.apply(this, arguments);
scheduleRewrite();
return ret;
};
});
window.addEventListener('popstate', function() {
const target = getNestedPath(location.href);
if (target) location.replace(target);
else scheduleRewrite();
});
})();
--【壹】--:
介绍:
- 开启后替换话题链接并自动重定向到
/nested/topic/xxx?sort=old - 替换页面DOM 链接,不会二次跳转
- 首次安装弹窗引导,可选启用或稍后
油猴脚本如下
// ==UserScript==
// @name Linux.do Nested View Redirector
// @namespace http://tampermonkey.net/
// @version 1.5
// @description 自动将 linux.do 的话题链接重定向为 nested 视图并按旧到新排序
// @author sunbigfly
// @match https://linux.do/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const STORAGE_KEY = 'nested_redirector_enabled';
const WELCOME_KEY = 'nested_redirector_welcomed';
function isEnabled() {
return localStorage.getItem(STORAGE_KEY) === '1';
}
// ========== 首次安装弹窗 ==========
if (!localStorage.getItem(WELCOME_KEY)) {
document.addEventListener('DOMContentLoaded', function() {
const overlay = document.createElement('div');
Object.assign(overlay.style, {
position: 'fixed', top: '0', left: '0', width: '100%', height: '100%',
background: 'rgba(0,0,0,0.4)', zIndex: '99999',
display: 'flex', alignItems: 'center', justifyContent: 'center',
backdropFilter: 'blur(4px)', WebkitBackdropFilter: 'blur(4px)',
});
const box = document.createElement('div');
Object.assign(box.style, {
background: '#fff', borderRadius: '16px', padding: '32px',
maxWidth: '380px', width: '90%',
boxShadow: '0 24px 48px rgba(0,0,0,0.12), 0 4px 12px rgba(0,0,0,0.08)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
color: '#1a1a1a', lineHeight: '1.5',
animation: 'nested-fadein 0.2s ease-out',
});
const style = document.createElement('style');
style.textContent = `
@keyframes nested-fadein {
from { opacity: 0; transform: scale(0.96) translateY(8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
`;
document.head.appendChild(style);
box.innerHTML = `
<div style="font-size:15px; font-weight:600; color:#111; margin-bottom:16px;">
Nested View Redirector
</div>
<div style="font-size:13px; color:#555; margin-bottom:24px;">
话题页自动切换为嵌套视图,按时间正序排列。<br>
支持所有打开方式,包括中键和右键新标签页。
</div>
<div style="display:flex; gap:8px;">
<button id="nested-welcome-enable" style="
flex:1; padding:10px 0; border:none; border-radius:10px;
background:#1a1a1a; color:#fff; font-size:13px; font-weight:500;
cursor:pointer; transition: opacity 0.15s;
">启用</button>
<button id="nested-welcome-later" style="
flex:1; padding:10px 0; border:1px solid #e0e0e0; border-radius:10px;
background:transparent; color:#666; font-size:13px; font-weight:500;
cursor:pointer; transition: background 0.15s;
">稍后</button>
</div>
<div style="margin-top:14px; font-size:11px; color:#aaa; text-align:center;">
可随时通过右下角开关切换
</div>
`;
overlay.appendChild(box);
document.body.appendChild(overlay);
function close() {
overlay.remove();
localStorage.setItem(WELCOME_KEY, '1');
}
document.getElementById('nested-welcome-enable').addEventListener('click', function() {
localStorage.setItem(STORAGE_KEY, '1');
close();
location.reload();
});
document.getElementById('nested-welcome-later').addEventListener('click', close);
overlay.addEventListener('click', function(e) { if (e.target === overlay) close(); });
});
}
// ========== 悬浮开关 ==========
function createToggle() {
const enabled = isEnabled();
const btn = document.createElement('div');
Object.assign(btn.style, {
position: 'fixed', bottom: '20px', right: '20px', zIndex: '99998',
width: '40px', height: '40px', borderRadius: '50%',
background: enabled ? '#1a1a1a' : '#d4d4d4',
display: 'flex', alignItems: 'center', justifyContent: 'center',
cursor: 'pointer', boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
transition: 'background 0.2s, transform 0.15s',
});
btn.title = enabled ? '点击关闭 Nested 重定向' : '点击启用 Nested 重定向';
// 用 SVG 替代 emoji
btn.innerHTML = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/>
<polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/>
<line x1="4" y1="4" x2="9" y2="9"/>
</svg>`;
btn.addEventListener('mouseenter', () => btn.style.transform = 'scale(1.08)');
btn.addEventListener('mouseleave', () => btn.style.transform = 'scale(1)');
btn.addEventListener('click', function() {
localStorage.setItem(STORAGE_KEY, isEnabled() ? '0' : '1');
location.reload();
});
document.body.appendChild(btn);
}
if (document.body) createToggle();
else document.addEventListener('DOMContentLoaded', createToggle);
// ========== 核心逻辑(仅启用时执行) ==========
if (!isEnabled()) return;
const TOPIC_REGEX = /\/t\/(?:[^/]+\/)?(\d+)(?:\/\d+)?\/?(?:[?#].*)?$/;
function getNestedPath(url) {
try {
const u = new URL(url, location.origin);
if (u.hostname !== 'linux.do' || u.pathname.startsWith('/nested/')) return null;
const match = u.pathname.match(TOPIC_REGEX);
if (match) return `https://linux.do/nested/topic/${match[1]}?sort=old`;
} catch(e) {}
return null;
}
const currentTarget = getNestedPath(location.href);
if (currentTarget) { location.replace(currentTarget); return; }
function rewriteLink(a) {
if (!a.getAttribute('href')) return;
const target = getNestedPath(a.href);
if (!target || a.href === target) return;
if (!a.dataset.originalHref) a.dataset.originalHref = a.href;
a.href = target;
}
function rewriteAll(root) {
(root || document).querySelectorAll('a[href*="/t/"]').forEach(rewriteLink);
}
let rafId = null;
function scheduleRewrite() {
if (!rafId) rafId = requestAnimationFrame(() => { rafId = null; rewriteAll(); });
}
const observer = new MutationObserver(function(mutations) {
for (const m of mutations) {
if (m.addedNodes.length || (m.type === 'attributes' && m.target.tagName === 'A')) {
scheduleRewrite(); return;
}
}
});
function init() {
rewriteAll();
observer.observe(document.body, {
childList: true, subtree: true, attributes: true, attributeFilter: ['href'],
});
setInterval(() => rewriteAll(), 2000);
}
if (document.body) init();
else document.addEventListener('DOMContentLoaded', init);
['pushState', 'replaceState'].forEach(method => {
const original = history[method];
history[method] = function(state, title, url) {
if (url) {
const target = getNestedPath(new URL(url, location.origin).href);
if (target) { location.href = target; return; }
}
const ret = original.apply(this, arguments);
scheduleRewrite();
return ret;
};
});
window.addEventListener('popstate', function() {
const target = getNestedPath(location.href);
if (target) location.replace(target);
else scheduleRewrite();
});
})();
介绍:
- 开启后替换话题链接并自动重定向到
/nested/topic/xxx?sort=old - 替换页面DOM 链接,不会二次跳转
- 首次安装弹窗引导,可选启用或稍后
油猴脚本如下
// ==UserScript==
// @name Linux.do Nested View Redirector
// @namespace http://tampermonkey.net/
// @version 1.5
// @description 自动将 linux.do 的话题链接重定向为 nested 视图并按旧到新排序
// @author sunbigfly
// @match https://linux.do/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const STORAGE_KEY = 'nested_redirector_enabled';
const WELCOME_KEY = 'nested_redirector_welcomed';
function isEnabled() {
return localStorage.getItem(STORAGE_KEY) === '1';
}
// ========== 首次安装弹窗 ==========
if (!localStorage.getItem(WELCOME_KEY)) {
document.addEventListener('DOMContentLoaded', function() {
const overlay = document.createElement('div');
Object.assign(overlay.style, {
position: 'fixed', top: '0', left: '0', width: '100%', height: '100%',
background: 'rgba(0,0,0,0.4)', zIndex: '99999',
display: 'flex', alignItems: 'center', justifyContent: 'center',
backdropFilter: 'blur(4px)', WebkitBackdropFilter: 'blur(4px)',
});
const box = document.createElement('div');
Object.assign(box.style, {
background: '#fff', borderRadius: '16px', padding: '32px',
maxWidth: '380px', width: '90%',
boxShadow: '0 24px 48px rgba(0,0,0,0.12), 0 4px 12px rgba(0,0,0,0.08)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
color: '#1a1a1a', lineHeight: '1.5',
animation: 'nested-fadein 0.2s ease-out',
});
const style = document.createElement('style');
style.textContent = `
@keyframes nested-fadein {
from { opacity: 0; transform: scale(0.96) translateY(8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
`;
document.head.appendChild(style);
box.innerHTML = `
<div style="font-size:15px; font-weight:600; color:#111; margin-bottom:16px;">
Nested View Redirector
</div>
<div style="font-size:13px; color:#555; margin-bottom:24px;">
话题页自动切换为嵌套视图,按时间正序排列。<br>
支持所有打开方式,包括中键和右键新标签页。
</div>
<div style="display:flex; gap:8px;">
<button id="nested-welcome-enable" style="
flex:1; padding:10px 0; border:none; border-radius:10px;
background:#1a1a1a; color:#fff; font-size:13px; font-weight:500;
cursor:pointer; transition: opacity 0.15s;
">启用</button>
<button id="nested-welcome-later" style="
flex:1; padding:10px 0; border:1px solid #e0e0e0; border-radius:10px;
background:transparent; color:#666; font-size:13px; font-weight:500;
cursor:pointer; transition: background 0.15s;
">稍后</button>
</div>
<div style="margin-top:14px; font-size:11px; color:#aaa; text-align:center;">
可随时通过右下角开关切换
</div>
`;
overlay.appendChild(box);
document.body.appendChild(overlay);
function close() {
overlay.remove();
localStorage.setItem(WELCOME_KEY, '1');
}
document.getElementById('nested-welcome-enable').addEventListener('click', function() {
localStorage.setItem(STORAGE_KEY, '1');
close();
location.reload();
});
document.getElementById('nested-welcome-later').addEventListener('click', close);
overlay.addEventListener('click', function(e) { if (e.target === overlay) close(); });
});
}
// ========== 悬浮开关 ==========
function createToggle() {
const enabled = isEnabled();
const btn = document.createElement('div');
Object.assign(btn.style, {
position: 'fixed', bottom: '20px', right: '20px', zIndex: '99998',
width: '40px', height: '40px', borderRadius: '50%',
background: enabled ? '#1a1a1a' : '#d4d4d4',
display: 'flex', alignItems: 'center', justifyContent: 'center',
cursor: 'pointer', boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
transition: 'background 0.2s, transform 0.15s',
});
btn.title = enabled ? '点击关闭 Nested 重定向' : '点击启用 Nested 重定向';
// 用 SVG 替代 emoji
btn.innerHTML = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/>
<polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/>
<line x1="4" y1="4" x2="9" y2="9"/>
</svg>`;
btn.addEventListener('mouseenter', () => btn.style.transform = 'scale(1.08)');
btn.addEventListener('mouseleave', () => btn.style.transform = 'scale(1)');
btn.addEventListener('click', function() {
localStorage.setItem(STORAGE_KEY, isEnabled() ? '0' : '1');
location.reload();
});
document.body.appendChild(btn);
}
if (document.body) createToggle();
else document.addEventListener('DOMContentLoaded', createToggle);
// ========== 核心逻辑(仅启用时执行) ==========
if (!isEnabled()) return;
const TOPIC_REGEX = /\/t\/(?:[^/]+\/)?(\d+)(?:\/\d+)?\/?(?:[?#].*)?$/;
function getNestedPath(url) {
try {
const u = new URL(url, location.origin);
if (u.hostname !== 'linux.do' || u.pathname.startsWith('/nested/')) return null;
const match = u.pathname.match(TOPIC_REGEX);
if (match) return `https://linux.do/nested/topic/${match[1]}?sort=old`;
} catch(e) {}
return null;
}
const currentTarget = getNestedPath(location.href);
if (currentTarget) { location.replace(currentTarget); return; }
function rewriteLink(a) {
if (!a.getAttribute('href')) return;
const target = getNestedPath(a.href);
if (!target || a.href === target) return;
if (!a.dataset.originalHref) a.dataset.originalHref = a.href;
a.href = target;
}
function rewriteAll(root) {
(root || document).querySelectorAll('a[href*="/t/"]').forEach(rewriteLink);
}
let rafId = null;
function scheduleRewrite() {
if (!rafId) rafId = requestAnimationFrame(() => { rafId = null; rewriteAll(); });
}
const observer = new MutationObserver(function(mutations) {
for (const m of mutations) {
if (m.addedNodes.length || (m.type === 'attributes' && m.target.tagName === 'A')) {
scheduleRewrite(); return;
}
}
});
function init() {
rewriteAll();
observer.observe(document.body, {
childList: true, subtree: true, attributes: true, attributeFilter: ['href'],
});
setInterval(() => rewriteAll(), 2000);
}
if (document.body) init();
else document.addEventListener('DOMContentLoaded', init);
['pushState', 'replaceState'].forEach(method => {
const original = history[method];
history[method] = function(state, title, url) {
if (url) {
const target = getNestedPath(new URL(url, location.origin).href);
if (target) { location.href = target; return; }
}
const ret = original.apply(this, arguments);
scheduleRewrite();
return ret;
};
});
window.addEventListener('popstate', function() {
const target = getNestedPath(location.href);
if (target) location.replace(target);
else scheduleRewrite();
});
})();
--【壹】--:
介绍:
- 开启后替换话题链接并自动重定向到
/nested/topic/xxx?sort=old - 替换页面DOM 链接,不会二次跳转
- 首次安装弹窗引导,可选启用或稍后
油猴脚本如下
// ==UserScript==
// @name Linux.do Nested View Redirector
// @namespace http://tampermonkey.net/
// @version 1.5
// @description 自动将 linux.do 的话题链接重定向为 nested 视图并按旧到新排序
// @author sunbigfly
// @match https://linux.do/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const STORAGE_KEY = 'nested_redirector_enabled';
const WELCOME_KEY = 'nested_redirector_welcomed';
function isEnabled() {
return localStorage.getItem(STORAGE_KEY) === '1';
}
// ========== 首次安装弹窗 ==========
if (!localStorage.getItem(WELCOME_KEY)) {
document.addEventListener('DOMContentLoaded', function() {
const overlay = document.createElement('div');
Object.assign(overlay.style, {
position: 'fixed', top: '0', left: '0', width: '100%', height: '100%',
background: 'rgba(0,0,0,0.4)', zIndex: '99999',
display: 'flex', alignItems: 'center', justifyContent: 'center',
backdropFilter: 'blur(4px)', WebkitBackdropFilter: 'blur(4px)',
});
const box = document.createElement('div');
Object.assign(box.style, {
background: '#fff', borderRadius: '16px', padding: '32px',
maxWidth: '380px', width: '90%',
boxShadow: '0 24px 48px rgba(0,0,0,0.12), 0 4px 12px rgba(0,0,0,0.08)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
color: '#1a1a1a', lineHeight: '1.5',
animation: 'nested-fadein 0.2s ease-out',
});
const style = document.createElement('style');
style.textContent = `
@keyframes nested-fadein {
from { opacity: 0; transform: scale(0.96) translateY(8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
`;
document.head.appendChild(style);
box.innerHTML = `
<div style="font-size:15px; font-weight:600; color:#111; margin-bottom:16px;">
Nested View Redirector
</div>
<div style="font-size:13px; color:#555; margin-bottom:24px;">
话题页自动切换为嵌套视图,按时间正序排列。<br>
支持所有打开方式,包括中键和右键新标签页。
</div>
<div style="display:flex; gap:8px;">
<button id="nested-welcome-enable" style="
flex:1; padding:10px 0; border:none; border-radius:10px;
background:#1a1a1a; color:#fff; font-size:13px; font-weight:500;
cursor:pointer; transition: opacity 0.15s;
">启用</button>
<button id="nested-welcome-later" style="
flex:1; padding:10px 0; border:1px solid #e0e0e0; border-radius:10px;
background:transparent; color:#666; font-size:13px; font-weight:500;
cursor:pointer; transition: background 0.15s;
">稍后</button>
</div>
<div style="margin-top:14px; font-size:11px; color:#aaa; text-align:center;">
可随时通过右下角开关切换
</div>
`;
overlay.appendChild(box);
document.body.appendChild(overlay);
function close() {
overlay.remove();
localStorage.setItem(WELCOME_KEY, '1');
}
document.getElementById('nested-welcome-enable').addEventListener('click', function() {
localStorage.setItem(STORAGE_KEY, '1');
close();
location.reload();
});
document.getElementById('nested-welcome-later').addEventListener('click', close);
overlay.addEventListener('click', function(e) { if (e.target === overlay) close(); });
});
}
// ========== 悬浮开关 ==========
function createToggle() {
const enabled = isEnabled();
const btn = document.createElement('div');
Object.assign(btn.style, {
position: 'fixed', bottom: '20px', right: '20px', zIndex: '99998',
width: '40px', height: '40px', borderRadius: '50%',
background: enabled ? '#1a1a1a' : '#d4d4d4',
display: 'flex', alignItems: 'center', justifyContent: 'center',
cursor: 'pointer', boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
transition: 'background 0.2s, transform 0.15s',
});
btn.title = enabled ? '点击关闭 Nested 重定向' : '点击启用 Nested 重定向';
// 用 SVG 替代 emoji
btn.innerHTML = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/>
<polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/>
<line x1="4" y1="4" x2="9" y2="9"/>
</svg>`;
btn.addEventListener('mouseenter', () => btn.style.transform = 'scale(1.08)');
btn.addEventListener('mouseleave', () => btn.style.transform = 'scale(1)');
btn.addEventListener('click', function() {
localStorage.setItem(STORAGE_KEY, isEnabled() ? '0' : '1');
location.reload();
});
document.body.appendChild(btn);
}
if (document.body) createToggle();
else document.addEventListener('DOMContentLoaded', createToggle);
// ========== 核心逻辑(仅启用时执行) ==========
if (!isEnabled()) return;
const TOPIC_REGEX = /\/t\/(?:[^/]+\/)?(\d+)(?:\/\d+)?\/?(?:[?#].*)?$/;
function getNestedPath(url) {
try {
const u = new URL(url, location.origin);
if (u.hostname !== 'linux.do' || u.pathname.startsWith('/nested/')) return null;
const match = u.pathname.match(TOPIC_REGEX);
if (match) return `https://linux.do/nested/topic/${match[1]}?sort=old`;
} catch(e) {}
return null;
}
const currentTarget = getNestedPath(location.href);
if (currentTarget) { location.replace(currentTarget); return; }
function rewriteLink(a) {
if (!a.getAttribute('href')) return;
const target = getNestedPath(a.href);
if (!target || a.href === target) return;
if (!a.dataset.originalHref) a.dataset.originalHref = a.href;
a.href = target;
}
function rewriteAll(root) {
(root || document).querySelectorAll('a[href*="/t/"]').forEach(rewriteLink);
}
let rafId = null;
function scheduleRewrite() {
if (!rafId) rafId = requestAnimationFrame(() => { rafId = null; rewriteAll(); });
}
const observer = new MutationObserver(function(mutations) {
for (const m of mutations) {
if (m.addedNodes.length || (m.type === 'attributes' && m.target.tagName === 'A')) {
scheduleRewrite(); return;
}
}
});
function init() {
rewriteAll();
observer.observe(document.body, {
childList: true, subtree: true, attributes: true, attributeFilter: ['href'],
});
setInterval(() => rewriteAll(), 2000);
}
if (document.body) init();
else document.addEventListener('DOMContentLoaded', init);
['pushState', 'replaceState'].forEach(method => {
const original = history[method];
history[method] = function(state, title, url) {
if (url) {
const target = getNestedPath(new URL(url, location.origin).href);
if (target) { location.href = target; return; }
}
const ret = original.apply(this, arguments);
scheduleRewrite();
return ret;
};
});
window.addEventListener('popstate', function() {
const target = getNestedPath(location.href);
if (target) location.replace(target);
else scheduleRewrite();
});
})();

