// ==UserScript==
// @name:en-us Show new tab open icon (with Violent Monkey menu settings)
// @name 显示新标签页打开图标(带暴力猴菜单设置)
// @namespace https://violentmonkey.github.io/
// @version 1.7
// @description:en-us Show arrow icon when hovering over a link if it will be opened in a new tab, support to set icon size, position, color, transparency and stroke in Violence Monkey menu, etc.
// @description 鼠标悬停在链接上时,如果会在新标签页打开,则显示箭头图标,支持在暴力猴菜单中设置图标大小、位置、颜色、透明度和描边等
// @match *://*/*
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @license GNU GPLv3
// ==/UserScript==
(function() {
'use strict';
// 默认图标
const defaultIcon = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWV4dGVybmFsLWxpbmsiPjxwYXRoIGQ9Ik0xNSAzaDZ2NiIvPjxwYXRoIGQ9Ik0xMCAxNCAyMSAzIi8+PHBhdGggZD0iTTE4IDEzdjZhMiAyIDAgMCAxLTIgMkg1YTIgMiAwIDAgMS0yLTJWOGEyIDIgMCAwIDEgMi0yaDYiLz48L3N2Zz4=";
// 从存储中读取设置,或使用默认值
const settings = {
iconUrl: GM_getValue("iconUrl", defaultIcon),
size: GM_getValue("size", 24),
offsetX: GM_getValue("offsetX", 10),
offsetY: GM_getValue("offsetY", 10),
iconOpacity: GM_getValue("iconOpacity", 0.5),
outlineSize: GM_getValue("outlineSize", 2),
outlineColor: GM_getValue("outlineColor", "black"),
outlineOpacity: GM_getValue("outlineOpacity", 1),
invertForDarkMode: GM_getValue("invertForDarkMode", true)
};
// 创建图标元素
const icon = document.createElement("div");
icon.style.position = "absolute";
icon.style.width = `${settings.size}px`;
icon.style.height = `${settings.size}px`;
icon.style.backgroundImage = `url(${settings.iconUrl})`;
icon.style.backgroundSize = "contain";
icon.style.pointerEvents = "none";
icon.style.zIndex = "10000";
icon.style.opacity = settings.iconOpacity;
icon.style.display = "none";
updateIconFilter();
document.body.appendChild(icon);
// 监听鼠标悬停事件
document.addEventListener("mouseover", (event) => {
const link = event.target.closest("a");
if (link && link.target === "_blank") {
icon.style.display = "block";
} else {
icon.style.display = "none";
}
});
// 跟随鼠标移动
document.addEventListener("mousemove", (event) => {
icon.style.left = `${event.pageX + settings.offsetX}px`;
icon.style.top = `${event.pageY + settings.offsetY}px`;
});
// 隐藏图标
document.addEventListener("mouseout", (event) => {
if (event.target.closest("a")) {
icon.style.display = "none";
}
});
// 暴力猴菜单设置
GM_registerMenuCommand("设置图标 URL", () => {
const iconUrl = prompt("请输入图标的 Data URL:", settings.iconUrl);
if (iconUrl) {
settings.iconUrl = iconUrl;
GM_setValue("iconUrl", iconUrl);
icon.style.backgroundImage = `url(${iconUrl})`;
}
});
GM_registerMenuCommand("设置图标大小", () => {
const size = prompt("请输入图标大小(像素):", settings.size);
if (size) {
settings.size = parseInt(size, 10);
GM_setValue("size", settings.size);
icon.style.width = `${settings.size}px`;
icon.style.height = `${settings.size}px`;
}
});
GM_registerMenuCommand("设置横向偏移", () => {
const offsetX = prompt("请输入横向偏移(像素):", settings.offsetX);
if (offsetX) {
settings.offsetX = parseInt(offsetX, 10);
GM_setValue("offsetX", settings.offsetX);
}
});
GM_registerMenuCommand("设置纵向偏移", () => {
const offsetY = prompt("请输入纵向偏移(像素):", settings.offsetY);
if (offsetY) {
settings.offsetY = parseInt(offsetY, 10);
GM_setValue("offsetY", settings.offsetY);
}
});
GM_registerMenuCommand("设置透明度", () => {
const opacity = prompt("请输入透明度(0-1):", settings.iconOpacity);
if (opacity) {
settings.iconOpacity = parseFloat(opacity);
GM_setValue("iconOpacity", settings.iconOpacity);
icon.style.opacity = settings.iconOpacity;
}
});
GM_registerMenuCommand("设置描边大小", () => {
const outlineSize = prompt("请输入描边大小(像素):", settings.outlineSize);
if (outlineSize) {
settings.outlineSize = parseInt(outlineSize, 10);
GM_setValue("outlineSize", settings.outlineSize);
updateIconFilter();
}
});
GM_registerMenuCommand("设置描边颜色", () => {
const outlineColor = prompt("请输入描边颜色(CSS颜色):", settings.outlineColor);
if (outlineColor) {
settings.outlineColor = outlineColor;
GM_setValue("outlineColor", settings.outlineColor);
updateIconFilter();
}
});
GM_registerMenuCommand("设置描边透明度", () => {
const outlineOpacity = prompt("请输入描边透明度(0-1):", settings.outlineOpacity);
if (outlineOpacity) {
settings.outlineOpacity = parseFloat(outlineOpacity);
GM_setValue("outlineOpacity", settings.outlineOpacity);
updateIconFilter();
}
});
GM_registerMenuCommand("启用夜间模式反色", () => {
settings.invertForDarkMode = !settings.invertForDarkMode;
GM_setValue("invertForDarkMode", settings.invertForDarkMode);
updateIconFilter();
});
// 更新图标滤镜(用于描边和夜间模式反色)
function updateIconFilter() {
const invertFilter = settings.invertForDarkMode && window.matchMedia("(prefers-color-scheme: dark)").matches ? "invert(1)" : "";
icon.style.filter = `drop-shadow(0 0 ${settings.outlineSize}px ${settings.outlineColor}) opacity(${settings.outlineOpacity}) ${invertFilter}`;
}
// 监听系统颜色主题变化
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", updateIconFilter);
})();