// ==UserScript== // @name 链接预览 // @name:zh-cn 链接预览 // @name:en Link Previewer // @namespace https://greasyfork.org/zh-CN/users/1073-hzhbest // @version 1.7 // @description 鼠标指向链接标识图标预览链接网页 // @description:zh-cn 鼠标指向链接标识图标预览链接网页 // @description:en Hovering to preview a link // @author hzhbest // @match http*://*/* // @exclude https://mega.nz/file/* // @exclude https://*.github.com/* // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @license MIT // @run-at document-end // @downloadURL none // ==/UserScript== // 1.7:增加切换点击还是悬停预览的菜单项 // todo: (function () { 'use strict'; // --------自定义区-------- // const minHgap = 50, minVgap = 80; // 预览窗距窗口边缘的右、下最小距离:像素 var winWidth = 700, winHeight = 550; // 预览窗默认宽、高:像素 const scale = 0.9; // 预览窗内页面放大率:(0~1] const animationtime = 0.5; // 动画时长:秒 const iconsize = 20; // 图标放大后大小:像素 const icontrpr = 0.7; // 图标放大后不透明度:(0~1) const pre = "░░░░░░ "; // 移动手柄显示:字符串 const delaysec = 1; // 触发预览等候延时:秒 const moredelaysec = 1; // 对超小链接增加等候延时:秒 var pinned = false; // 初始钉住状态:Boolean const preID = "__link__prev_win" // 预览窗id var onclk = 0; // 是否点击预览默认值:{0:否,1:是} const urlplaceArr = [ // 替换链接网址数组,{命名,网址正则,关键编号正则,替换网址模板} { name: "B站", scrurl: /bilibili\.com\//, coreID: /BV[^\?&\/]+/, // desturl: "https://player.bilibili.com/player.html?bvid=--coreID--&high_quality=1&autoplay=1" desturl: "https://www.bilibili.com/blackboard/html5mobileplayer.html?bvid=--coreID--&autoplay=1" }, /* { name: "油管", scrurl: /youtube\.com\//, coreID: /(?<=(watch\?v=|\/shorts\/))[^&\/]+/, desturl: "https://www.youtube.com/embed/--coreID--?si=Kjs9BPxNAwVzGPxm" } */ { name: "西瓜", scrurl: /ixigua\.com\//, coreID: /(?<=\/)\d+\?/, desturl: "https://www.ixigua.com/iframe/--coreID--autoplay=1" } ]; // --------自定义区结束--------// const ualen = urlplaceArr.length; const ixonimg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAoUlEQVQ4y8XSyw3CMBAE0AekkHTBBZGkCa40QA9AOVADEkGiEJfCxZEsk+8F5mLZs7Mzay3/xmpm3Tm7v9DCeqHhDhdU3UORkHVKJAi4osEJj5RME1SxiZ64De444J2SRVbcRjdZslsUP7Efa6BH3DkHHHOD9UxxG8VlXjTUoExit2MRh0YI2MZzFGMjTIr7EtQTf/I1zmbBWoe4E7OS/Q4fA1sbIN+Dzp4AAAAASUVORK5CYIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; const inonimg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAATr4AAE6+AGeOBvEAAAA3klEQVQ4y83SPUpDURAF4M8YooUiIi7BQBaQ2lqirZjnVrIFCwsLDbbZgLoAO8FC7EJcgNgZUpvYTOByee/513hguDB3zpm5cy5/xOovOI0qgUZJ5FjDBbbxnF5s4hHjLPYz8jVmOFwmm0n3PdzhJXIreM06H6OP23y0LbyjVzJ2C8O8c51AGwOsB/kqyEd1m00FephiF5dfkZs1Vp0H8RQ3kS/iHJV6mmADJziLRe4kAkXlpwgsMI8Y4AEHP3nCPTohtMTbdwUKdCtq5+HQpEzgA09R0K5xa5p8tH+CT7aEK2vlnm2YAAAAAElFTkSuQmCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; const loadimg = "data:image/png;base64,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"; const swt = [["hover", "click"], ["悬停", "点击"]]; const ntc = ["Switched to --swt-- preview mode", "已切换到--swt--预览模式"]; const gms = ["Toggle preview mode", "切换预览模式"]; //language detection const _L = (navigator.language.indexOf('zh-') == -1) ? 0 : 1; const isonclick = "Link_preview_on_click"; onclk = GM_getValue(isonclick, onclk); document.body.classList.toggle("__link_pre_clk", (onclk == 1)); // 全局点击样式标志 const domainregex = /(?<=:\/\/)[^\/]+/; const id = "__link__prev"; const css = ` /* 链接样式 */ a.__link__preved { outline: 3px solid #3e3ed3; } a.___prevlink.__pr { position: relative; } /* 图标样式 */ a.___prevlink>img.___previcon { width: 16px !important; height: 16px !important; opacity: 0%; transition: opacity 0.5s ease-out, background 0s; position: absolute; pointer-events: auto !important; display: inline-block !important; margin: 0 !important; } a.___prevlink>img.___previcon:hover { background: #3e3ed3 !important; transition: background ${delaysec}s !important; } body.__link_pre_clk a.___prevlink>img.___previcon:hover { background: #b33ed3 !important; transition: background 0s !important; } a.___prevlink>img.___previcon.__moredelay:hover, body.__link_pre_clk a.___prevlink>img.___previcon.__moredelay:hover { transition: background ${delaysec + moredelaysec}s !important; } *:hover>a.___prevlink>img.___previcon { opacity: 30%; } a.___prevlink:hover>img.___previcon { opacity: ${icontrpr}; background: white; border: 1px solid #8d8d8db1; transition: opacity 0.5s linear; z-index: 10008; transform: scale(${iconsize / 16}); } /* 预览窗样式 */ div#${preID} { opacity: 0; position: absolute; z-index: 10009; box-shadow: 1px 1px 7px 1px #717171; padding: 0; margin: 0; background-color: white; transition: ${animationtime}s ease; } div#${preID}.__close { transition: 0s !important; display: none; } div#${preID}.__loading { background: url(${loadimg}) no-repeat center center; background-color: #e7e7e7; box-shadow: 1px 1px 7px 1px #dba87c !important; } div#${preID}.__visible { opacity: 1; transition: 0.2s !important; } div#${preID}.visible .__link__prev_ifr { border: none; transform: scale(${scale}); max-width: unset !important; width: calc(100% / ${scale}); max-height: unset !important; height: calc(100% / ${scale}); } div#${preID}.__onmove, div#${preID}.__onsize, div#${preID}.__onpin{ transition: 0s !important; } div#${preID}.__onmove { /* opacity: 0.7; */ } div#${preID}.__pinned { box-shadow: 1px 1px 7px 1px #a36835; position: fixed; transition: 0s !important; } /* 关闭按钮样式 */ @keyframes rotating_button { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } div#${preID}>.__link__clos_btn { position: absolute; top: -10px; right: -10px; z-index: 10010; line-height: 24px; width: 24px; height: 24px; color: white; font-family: Consolas; font-size: 16px; text-align: center; background: #df2020; border: 1px solid black; border-radius: 50%; box-shadow: 1px 1px 5px #333; cursor: default; padding: 0 !important; margin: 0; } div#${preID}>.__link__clos_btn.__loading { animation: 3s linear 0s infinite rotating_button; background: #d76565; } div#${preID}>.__link__clos_btn.__loading:hover { animation: none; background: #df2020; } div#${preID}>.__link__clos_btn:hover { outline: 3px solid #be3737a2; } div#${preID}>.__link__clos_btn.__close { display: none; } /* 拖动手柄样式 */ div#${preID}>div.__link__prev_mv { position: absolute; top: -5px; left: 0px; z-index: 10010; height: 6px; width: 30px; border: 1px solid #242424; background: #3e3e3e; cursor: move; border-radius: 3px; overflow: hidden; max-width: 95%; font-size: 14px !important; color: #d7d7d7; line-height: 19px; display: grid; grid-template-columns: auto auto 1fr; } div#${preID}>div.__link__prev_mv>* { display: block; } div#${preID}:hover>div.__link__prev_mv { height: 20px; top: -20px; width: auto; } div#${preID}>div.__link__prev_mv:hover { color: #e0a52e; } div#${preID}.__onmove>div.__link__prev_mv { background: #6f6122; height: 30px; top: -20px; width: fit-content; } div#${preID}.__loading>div.__link__prev_mv { background: #aa9537; } div#${preID} .__link__prev_ttl { font-size: 14px !important; font-family: Arial; white-space: nowrap; margin: 0 3px; overflow: hidden; text-overflow: ellipsis; width: 100%; } div#${preID}>.__link__prev_rs { height: 4px; width: 4px; border: 1px solid #616161; color: #9a9276; font-size: 13px; position: absolute; right: 0; bottom: 0; z-index: 10011; background: #3e3e3e67; transition: 0.3s ease-out; font-size: 10px; line-height: 10px; overflow: hidden; cursor: nw-resize; } div#${preID}:hover>.__link__prev_rs { background: #3e3e3e; height: 12px; width: 12px; } div#${preID}>.__link__prev_rs:hover { border-color: #2c96e2af; height: 18px; width: 18px; } div#${preID}.__onsize>.__link__prev_rs { height: 40px; width: 60px; transition: 0s; color: #e0a52e } /* 钉住按钮样式 */ div#${preID} .__link__prev_pbtn { height: 18px; width: 20px !important; box-sizing: border-box; border-width: 0 1px; border-style: solid; vertical-align: bottom; margin: 0 4px; text-align: center; cursor: default; } div#${preID} .__link__prev_pbtn:hover { border-color: #f1db27; color: #f1db27; background: #ffffff36; } div#${preID} .__link__prev_pbtn:active { background: #ffffff82; } div#${preID}.__pinned .__link__prev_pbtn { background: #f5bc4f82; font-weight: 800; } `; addCSS(css, id); // 添加的style节点添加id,用于判断是否需重添加 window.addEventListener('load', function () { GM_registerMenuCommand(gms[_L], changemode); }, false); var previewwin, pre_ir, pinbtn, closebtn, movehand, titlebox, ondrag, resizehand, rsdrag; var timer, linkprev, linkprevOld, mousepos, vscale, moretimer; var site = location.host; makeprevwin(); setTimeout(function () { // 延时启动 document.addEventListener('mouseover', (evt) => { // 检查鼠标下的节点,查找链接添加图标 const t = evt.target; if (t.tagName == "A" && ispagelink(t)) { addIconTo([t]); } else { var links = getLinksInThreeLayer(t); addIconTo(links); } mousepos = { x: evt.x, y: evt.y }; }); // 设置监视器,若标题变化则重新加载 var watch = document.querySelector('title'); new (window.MutationObserver || window.WebKitMutationObserver)(function (mutations) { // console.log('标题变了', document.title); if (!document.querySelector("#" + id)) { addCSS(css, id); } if (!document.querySelector("#" + preID)) { makeprevwin(); } site = location.host; }).observe(watch, { childList: true, subtree: true, characterData: true }); }, 1000); function addIconTo(links) { // 往链接上添加图标;输入:链接的数组 var lnkl = links.length; var exl = 0; // console.log(lnkl); var previewEvent = function (evt, od) { // 触发预览 if (linkprevOld == evt.target.parentNode && isPrevVisual()) { return; } if (!!linkprev) { // 若有链接在预览中,去除其预览中状态 linkprev.classList.remove("__link__preved"); } linkprev = evt.target.parentNode; // 指定预览目标链接 setTimeout(() => { if (previewwin.classList.contains("__close")) { // 若预览窗关闭状态则移动到鼠标下 setWinPosit(mousepos.x, mousepos.y); } }, od); timer = setTimeout(previewlink, od); // 一秒后开启预览窗 } for (let i = 0; i < lnkl; i++) { const lnk = links[i]; if (lnk.classList.contains("___prevlink")) { // 跳过已处理的链接 continue; } lnk.classList.add("___prevlink"); if (window.getComputedStyle(lnk).position == "static") { // 若链接本身无position设置则添加定位样式 lnk.classList.add("__pr"); } var lnkposit = getTrueSize(lnk); // 获取链接占位 var lnklcposit = getLastChildSize(lnk); // 获取链接末个子节点的占位 var lcl, lcw; if (!lnklcposit) { lcl = lnkposit.l; lcw = lnkposit.w; } else { lcl = lnklcposit.l; lcw = lnklcposit.w; } var img; img = creaElemIn('img', lnk); // img.dataset.for = url; img.classList.add("___previcon"); var adl = lcl - lnkposit.l + lcw + 4; // 末子节点右边界右4像素;如果被父节点遮挡或自身隐藏 var adb = -0.3; if (lnkposit.r < (4 + iconsize) || window.getComputedStyle(lnk).overflow !== "visible") { adl = Math.min(adl, lnkposit.w - 5 - iconsize); // 则避开遮挡 adb = 0.05; } img.style.left = adl + "px"; img.style.bottom = adb + "lh"; if (domainregex.exec(lnk.href)[0] !== site) { // 站内还是站外链接 img.src = ixonimg; exl += 1; } else { img.src = inonimg; } if (lnkposit.w <= (iconsize * 10)) { // 链接宽度不大于十倍图标大小则增加延时 img.classList.add("__moredelay"); } img.addEventListener('mouseover', (evt) => { // 鼠标悬停图标上的动作 var etarget = evt.target; if (onclk == 1) { // 点击预览模式时,对小链接增加延时,延时后点击才预览 if (etarget.classList.contains("__moredelay")) { moretimer = setTimeout(() => { etarget.classList.add("__moredelayfin"); }, moredelaysec * 1000); } return; } var od = delaysec; if (evt.target.classList.contains("__moredelay")) { od += moredelaysec; } od *= 1000; previewEvent(evt, od); }); img.addEventListener('click', (evt) => { // 鼠标点击图标的动作 if (onclk == 0 || (evt.target.classList.contains("__moredelay") && !evt.target.classList.contains("__moredelayfin"))) { return; } clearTimeout(timer); evt.preventDefault(); evt.stopPropagation(); previewEvent(evt, 0); }); img.addEventListener('mouseleave', (evt) => { // 鼠标离开鼠标则清除计时 if (evt.target.classList.contains("__moredelayfin")) { evt.target.classList.remove("__moredelayfin"); } clearTimeout(timer); clearTimeout(moretimer); }); } //console.log("external link count:" + exl); window.addEventListener('mousedown', (e) => { // 点击页面的动作 var target = e.target; if (isPrevVisual() && !pinned && !previewwin.contains(target)) { hidepreview(e); // 若预览窗开启且非钉住状态且点击位置不在预览窗内则隐藏预览窗 } }, true); } function makeprevwin() { // 生成预览窗 previewwin = creaElemIn('div', document.body); previewwin.id = preID; previewwin.style.width = '300px'; // 显示前预览窗大小,显示时形成放大效果 previewwin.style.height = '200px'; previewwin.classList.add("__close"); // 初始状态关闭 movehand = creaElemIn('div', previewwin); // 移动手柄 movehand.classList.add("__link__prev_mv"); resizehand = creaElemIn('div', previewwin); // 调整大小手柄 resizehand.className = "__link__prev_rs"; var movehead = creaElemIn('div', movehand); // 移动手柄头 movehead.innerHTML = pre; pinbtn = creaElemIn('div', movehand); // 钉住按钮 pinbtn.className = "__link__prev_pbtn"; pinbtn.innerHTML = "T"; pinbtn.addEventListener('click', togglePin); titlebox = creaElemIn('div', movehand); // 标题栏 titlebox.className = "__link__prev_ttl"; pre_ir = creaElemIn('iframe', previewwin); // 预览容器iframe pre_ir.className = "__link__prev_ifr"; pre_ir.style.border = 0; pre_ir.style.maxHeight = "unset"; pre_ir.style.maxWidth = "unset"; closebtn = creaElemIn('div', previewwin); // 关闭按钮 closebtn.classList.add("__link__clos_btn"); closebtn.innerHTML = "✖"; closebtn.addEventListener('click', hidepreview); ondrag = endrag(previewwin, { x: 'left', y: 'top' }, movehand); // 绑定移动预览窗对象 ondrag.hook('__drag_begin', () => { // 绑定移动开始、结束状态样式 previewwin.classList.add("__onmove"); }); ondrag.hook('__drag_end', () => { previewwin.classList.remove("__onmove"); }); rsdrag = endrag(previewwin, { x: 'width', y: 'height' }, resizehand); // 绑定调整预览窗大小对象 rsdrag.hook('__dragging', () => { // 调整中更新iframe大小,记录预览窗大小 if (!!rsdrag.position) { // 未开始拖动前该对象不存在,判断避免编译出错 winWidth = rsdrag.position._x; winHeight = rsdrag.position._y; setIfrWinSize(winWidth, winHeight); } if (previewwin.classList.contains("__onsize")) { // 调整中显示当前大小(该状态需加入已开始判断) // console.log("dragging", rsdrag.position.x, rsdrag.position.y); resizehand.innerHTML = ` W: ${winWidth} px
H: ${winHeight} px `; } }); rsdrag.hook('__drag_begin', () => { // 绑定调整大小开始、结束状态样式、显示 previewwin.classList.add("__onsize"); }); rsdrag.hook('__drag_end', () => { previewwin.classList.remove("__onsize"); resizehand.innerHTML = ""; }); } function previewlink() { // 在预览窗中加载链接 // console.log('linkprev: ', linkprev); linkprev.classList.add("__link__preved"); linkprevOld = linkprev; // var url = linkprev.getAttribute('url') || linkprev.href; var url = linkprev.href; // console.log('url: ', url); vscale = scale; if (ualen > 0) { // 链接替换 for (let i = 0; i < ualen; i++) { const ur = urlplaceArr[i]; if (ur.scrurl.test(url)) { const urid = ur.coreID.exec(url); if (!!urid) { url = ur.desturl.replace("--coreID--", urid[0]); pre_ir.allow = "autoplay"; pre_ir.sandbox = "allow-top-navigation allow-same-origin allow-forms allow-scripts"; vscale = 1; break; } } } } pre_ir.src = url; // 加载页面,调整缩放 pre_ir.style.transform = "scale(" + vscale + ")"; pre_ir.style.height = 100 / vscale + "%"; pre_ir.style.width = 100 / vscale + "%"; previewwin.classList.toggle("__close", false); // 预览窗去除关闭、添加加载中状态 previewwin.classList.toggle("__loading", true); titlebox.innerHTML = linkprev.textContent; // 以链接文本为标题 titlebox.title = linkprev.textContent; var mx = mousepos.x, my = mousepos.y; setTimeout(() => { // 延时0.1秒(等待预览窗到位)显示、移动、大小 previewwin.classList.toggle("__visible", true); if (!pinned) { if (mx > (window.innerWidth - winWidth - minHgap)) { mx = mx - winWidth - 40; } if (my > (window.innerHeight - winHeight - minVgap)) { my = my - winHeight - 15; } setWinPosit(Math.max(minHgap, mx), Math.max(minVgap, my)); } setPrevWinSize(winWidth, winHeight); closebtn.classList.remove("__close"); closebtn.classList.add("__loading"); }, 100); pre_ir.onload = () => { // iframe加载完成后去除加载中状态 closebtn.classList.remove("__loading"); previewwin.classList.remove("__loading"); }; } function setWinPosit(l, t, toscreen) { // 根据屏幕位置设置预览窗网页位置;toscreen 为true则设为屏幕位置 var f = (toscreen) ? 0 : 1; previewwin.style.left = l + f * window.scrollX + 'px'; previewwin.style.top = t + f * window.scrollY + 'px'; } function setPrevWinSize(w, h) { // 设置预览窗口大小 previewwin.style.width = w + 'px'; previewwin.style.height = h + 'px'; setIfrWinSize(w, h); } function setIfrWinSize(w, h) { // 根据放大率设置iframe窗口大小 var f = (vscale == 1) ? 0 : (1 - vscale) / 2 * -1 / vscale; pre_ir.width = w / vscale; pre_ir.height = h / vscale; pre_ir.style.marginLeft = (w * f) + 'px'; pre_ir.style.marginTop = (h * f) + 'px'; } function togglePin() { // 切换钉住状态 pinned = !pinned; var p = previewwin.getBoundingClientRect(); // 获取预览窗当前位置 previewwin.classList.toggle('__onpin', true); // 钉住“切换中”状态,以避免取消钉住后过快恢复动画 previewwin.classList.toggle('__pinned', pinned); // 已钉住状态 setWinPosit(p.left, p.top, pinned); setTimeout(() => { previewwin.classList.toggle('__onpin', false); // 钉住“切换中”状态结束 }, 100); } function hidepreview(evt) { pinned = false; previewwin.classList.toggle('__pinned', pinned); setPrevWinSize(100, 100); // 预览窗缩小效果 pre_ir.src = ''; setWinPosit(evt.x, evt.y); // 在鼠标位置消失 previewwin.classList.remove('__visible'); linkprev.classList.remove('__link__preved'); // 去除链接高亮中状态 closebtn.classList.add("__close"); setTimeout(() => { // 动画效果完成后添加关闭状态 previewwin.classList.add("__close"); }, animationtime * 1000 + 10); } function isPrevVisual() { // 预览窗是否可见 return previewwin && previewwin.classList.contains('__visible'); } function getLinksInThreeLayer(elem) { // 对当前元素及其下两层的链接进行提取 return getLinksInChild(elem, 3); } function getLinksInChild(elem, lcnt) { // 递归提取元素中的链接 var lnks = []; if (elem.childNodes.length == 0) { return lnks; } else { elem.childNodes.forEach((cnode) => { if ((cnode.tagName == "A") && isvisible(cnode)) { if (ispagelink(cnode)) { lnks.push(cnode); } else { if (lcnt - 1 > 0) { lnks.concat(getLinksInChild(cnode, lcnt - 1)); } } } }); } return lnks; } function ispagelink(node) { // 若A节点是指向实网址(非js非锚点)返回true if (!node.href) { return false; } const h = node.href, l = location.href; if (h.indexOf('javascript:') == 0 || h.replace(l.split('#')[0], "").indexOf("#") == 0) { return false; } else { return true; } } function isvisible(node) { // 若节点非隐藏状态返回true var p = node.getBoundingClientRect(); if ((p.width == 0 && p.height == 0) || (p.top == 0 && p.bottom == 0)) { return false; } return true; } function changemode() { onclk = (onclk == 0) ? 1 : 0; const str = ntc[_L].replace('--swt--', swt[_L][onclk]); popupnotice(str); document.body.classList.toggle("__link_pre_clk", (onclk == 1)); GM_setValue(isonclick, onclk); } function popupnotice(str) { // 在页面内显示弹出通知 const vpos = 0.7, hpos = 0.5; let notice = creaElemIn('div', document.body); notice.innerHTML = str; notice.style = ` transform: translate(-50%,-50%); position: fixed; left: ${hpos * 100 + '%'}; top: ${vpos * 100 + '%'}; border: none; outline: 3px solid white; box-shadow: 0 4px 7px 4px #3f3f3f; background: black; color: white; font-family: Arial; font-size: 14pt; transition: opacity 0.5s; opacity: 0; padding: 20px; border-radius: 15px; z-index: 2000000; `; setTimeout(() => { notice.style.opacity = 0.8; }, 500); setTimeout(() => { notice.style.opacity = 0; }, 5500); setTimeout(() => { removeNode(notice); }, 6000); } function creaElemIn(tagname, destin) { //在 destin 内末尾创建元素 tagname return destin.appendChild(document.createElement(tagname)); } function removeNode(node) { if (!!node.parentNode) { node.parentNode.removeChild(node); } } function addCSS(css, cssid) { // 创建带id的 style 节点 let stylenode = creaElemIn('style', document.getElementsByTagName('head')[0]); stylenode.textContent = css; stylenode.type = 'text/css'; stylenode.id = cssid || ''; } function getLastChildSize(elem) { // 返回节点的最后一个子节点的实占位对象 var cs = elem.childNodes; if (cs.length == 0) { return false; } var lc = cs[cs.length - 1]; if (lc.nodeType == 3) { return getTextNodeSize(lc); } else { return getTrueSize(lc); } } // 输入元素,返回实占位对象{元素可见的宽、高、顶、左、一层父元素右侧余量} function getTrueSize(elem, posiz) { if (!posiz) { var p = elem.getBoundingClientRect(); posiz = { w: p.width, h: p.height, t: p.top, l: p.left, r: 0, }; } var pp = elem.parentNode.getBoundingClientRect(); var pr = posiz.l + posiz.w, pb = posiz.t + posiz.h; if (posiz.r == 0) posiz.r = pp.right - pr; // 父元素对当前元素的右侧余量 var isvi = { l: posiz.l < pp.right && posiz.l >= pp.left, // 子左在父左右之间 r: pr > pp.left && pr <= pp.right, // 子右在父左右之间 t: posiz.t < pp.bottom && posiz.t >= pp.top, // 子顶在父顶底之间 b: pb > pp.top && pb <= pp.bottom // 子底在父顶底之间 }; if (isvi.l && isvi.r && isvi.t && isvi.b) { // 子全在父之内,则返回子占位 return posiz; } else { var ppl = (isvi.l) ? posiz.l : pp.left; // 确定可见四边(在父之内按子,否则按父) var ppt = (isvi.t) ? posiz.t : pp.top; var ppr = (isvi.r) ? posiz.l + posiz.w : pp.right; var ppb = (isvi.b) ? posiz.t + posiz.h : pp.bottom; return getTrueSize(elem.parentNode, { w: ppr - ppl, h: ppb - ppt, t: ppt, l: ppl, r: posiz.r }); } } // 输入文本节点,返回实占位对象{文本节点的宽、高、顶、左、一层父元素右侧余量} function getTextNodeSize(textNode) { if (textNode.nodeType !== 3) { return false; } if (document.createRange) { var range = document.createRange(); range.selectNodeContents(textNode); if (range.getBoundingClientRect) { var rect = range.getBoundingClientRect(); if (rect) { var posit = { w: rect.width, h: rect.height, t: rect.top, l: rect.left, r: 0 }; return getTrueSize(textNode, posit); } } } return false; } // 对target拖动handle时,实现拖动的功能 // 输入:目标元素target,拖动位置参考系opt,拖动手柄handle // 输入opt:形如【{x:'right',y:'bottom'}】,或者width、height(右下角拖动) function endrag(target, opt, handle) { var p_x, p_y, isDragging; endrag = function (target, opt, handle) { return new endrag.proto(target, opt || {}, handle); } endrag.proto = function (target, opt, handle) { var self = this; this.target = target; this.style = target.style; this.handle = handle; var _x = opt.x !== 'right'; var _y = opt.y !== 'bottom'; this.x = opt.x; //_x ? 'left' : 'right'; this.y = opt.y; //_y ? 'top' : 'bottom'; // p_x = this.x; // p_y = this.y; this.xd = _x ? -1 : 1; this.yd = _y ? -1 : 1; this.computed_style = document.defaultView.getComputedStyle(target, ''); this.drag_begin = function (e) { self.__drag_begin(e); }; this.handle.addEventListener('mousedown', this.drag_begin, false); //only drag on handler this.dragging = function (e) { self.__dragging(e); }; document.addEventListener('mousemove', this.dragging, false); this.drag_end = function (e) { self.__drag_end(e); }; document.addEventListener('mouseup', this.drag_end, false); }; endrag.proto.prototype = { __drag_begin: function (e) { if (e.button == 0) { var _c = this.computed_style; this.isDragging = isDragging = true; this.position = { _x: parseFloat(_c[this.x]), _y: parseFloat(_c[this.y]), x: e.pageX, y: e.pageY }; e.preventDefault(); } }, __dragging: function (e) { if (!this.isDragging) return; var x = Math.floor(e.pageX), y = Math.floor(e.pageY), p = this.position; // prevent moving out of window var x_border = window.innerWidth - 40, y_border = window.innerHeight - 20; if (x - window.scrollX > x_border) x = window.scrollX + x_border; if (y - window.scrollY > y_border) y = window.scrollY + y_border; p._x = p._x + (p.x - x) * this.xd; p._y = p._y + (p.y - y) * this.yd; this.style[this.x] = p._x + 'px'; this.style[this.y] = p._y + 'px'; p.x = x; p.y = y; }, __drag_end: function (e) { if (e.button == 0) { if (this.isDragging) { this.isDragging = isDragging = false; } } }, hook: function (method, func) { if (typeof this[method] === 'function') { var o = this[method]; this[method] = function () { if (func.apply(this, arguments) === false) { return; } o.apply(this, arguments); }; } } }; return endrag(target, opt, handle); } })();