feat: add GmeekExternal plugin (open external links in new tab)

This commit is contained in:
yeyangchen2009 2026-09-16 07:39:02 +08:00
parent 77a8aaa2b1
commit ccb4753756
1 changed files with 42 additions and 0 deletions

42
plugins/GmeekExternal.js Normal file
View File

@ -0,0 +1,42 @@
/* GmeekExternal —— 正文外链自动在新标签页打开
* 作用域:#postBody 内的 <a>(config 的 script 字段只注入文章页/固定页)
* 外链判定:交给 URL 构造器按 host 比较——绝对/协议相对/各种相对路径
* 都能正确归类,自己站点的绝对 URL 不会误判
* 安全:target=_blank 时补 rel=noopener(合并已有值,不覆盖)
* 不做:不自动加 nofollow(SEO 语义)、不强制 noreferrer(保留来源统计)
*/
(function () {
var body = document.getElementById('postBody');
if (!body) return;
var links = body.querySelectorAll('a[href]');
Array.prototype.forEach.call(links, function (a) {
var u = toUrl(a.getAttribute('href'));
if (!u) return; // 锚点/mailto/tel/javascript/非法值
if (u.hostname === location.hostname) return; // 站内链接原地跳
// 尊重作者显式声明(比如手写 target="_self")
if (!a.hasAttribute('target')) a.setAttribute('target', '_blank');
mergeRel(a, 'noopener');
});
function toUrl(href) {
if (!href) return null;
href = href.trim();
if (!href || href.charAt(0) === '#') return null;
if (/^(mailto|tel|javascript):/i.test(href)) return null;
try {
return new URL(href, location.href);
} catch (e) {
return null;
}
}
function mergeRel(a, token) {
var rels = (a.getAttribute('rel') || '').split(/[ \t]+/).filter(Boolean);
if (rels.indexOf(token) === -1) {
rels.push(token);
a.setAttribute('rel', rels.join(' '));
}
}
})();