您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Synchronisiert Aktionen über Fenster/Tabs der gleichen Domain hinweg. Drücke C L O N E, um zu (de)aktivieren
// ==UserScript== // @name Doppelte Fenster // @name:en Clone windows // @namespace http://tampermonkey.net/ // @version 0.1 // @description Synchronisiert Aktionen über Fenster/Tabs der gleichen Domain hinweg. Drücke C L O N E, um zu (de)aktivieren // @description:en Synchronizes actions across windows and tabs with the same domain. Press C L O N E to disable/re-enable // @author Aloso // @match https://www.google.com // @include https://* // @include http://* // @grant none // ==/UserScript== (function () { "use strict"; let lsp = "ls-clone-windows-" + encodeURI(window.location.hostname) + "-"; let root = document.documentElement; let pressed = ""; let last_press = 0; let initialized = false; let scrolled_here = false; let clicked_here = false; let inputTed_here = false; const msgStyle = { backgroundColor: "white", color: "black", fontSize: "18px", lineHeight: "initial", textShadow: "none", border: "none", borderRadius: "4px", boxShadow: "0 1px 30px rgba(0, 0, 0, 0.5)", boxSizing: "border-box", position: "fixed", opacity: "1", transform: "none", right: "5px", top: "5px", padding: "15px 20px", zIndex: "100000" }; function msg(text) { let msg = document.createElement("div"); msg.innerHTML = text; for (let x in msgStyle) if (msgStyle.hasOwnProperty(x)) { msg.style[x] = msgStyle[x]; } document.body.appendChild(msg); setTimeout(() => document.body.removeChild(msg), 1300); } function keypress(event) { if (+new Date() - last_press > 600) pressed = ""; last_press = +new Date(); pressed += event.key; if (pressed.length > 5) pressed = pressed.substr(pressed.length - 5); if (pressed === "clone") { pressed = ""; if (!initialized) { init("event"); msg("<span style='color:#007b20'>CLONING ENABLED</span>"); } else { deInit(); msg("<span style='color:red'>CLONING DISABLED</span>"); } } } function storage(event) { if (event.newValue !== null && event.key.startsWith(lsp)) { let type = event.key.substring(lsp.length); if (type === "init") { if (!initialized) { init(); msg("<span style='color:#007b20'>CLONING ENABLED</span>"); } } else if (type === "forbid") { if (initialized) { deInit(); msg("<span style='color:red'>CLONING DISABLED</span>"); } } else if (initialized) { if (type === "scroll") { if (!scrolled_here) { let [x, y] = event.newValue.split(" ").map(x => +x); root.scrollTo(x, y); } scrolled_here = false; } else if (type === "click") { if (!clicked_here) { let [xs, ys, val] = event.newValue.split(" "); let x = +xs; let y = +ys; let el = document.elementFromPoint(x, y); if (el != null) { fireMouseEvent(el, "click", x, y); } } clicked_here = false; } else if (type === "input") { if (!inputTed_here) { let [xs, ys, val] = event.newValue.split(" "); let x = +xs; let y = +ys; val = decodeURIComponent(val); let el = document.elementFromPoint(x, y); if (el.nodeName === "INPUT" || el.nodeName === "TEXTAREA" || el.nodeName === "SELECT") { if (el.getAttribute("type") === "checkbox") { el.checked = val !== "false"; } else { el.value = val; } } } inputTed_here = false; } else if (type === "back") { window.removeEventListener("popstate", popstate); setTimeout(() => { while (event.state === lsp + "back") history.go(-1); history.go(-1); while (event.state === lsp + "back") history.go(-1); window.addEventListener("popstate", popstate); }, 80); } } } } function init(option) { initialized = true; if (option === "event") { localStorage.setItem(lsp + "init", "1"); } localStorage.removeItem(lsp + "forbid"); if (history.state !== lsp + "back") { history.pushState(lsp + "back", "Go back"); } } function deInit() { initialized = false; for (let x in localStorage) { if (x.startsWith(lsp) && localStorage.hasOwnProperty(x)) { localStorage.removeItem(x); } } localStorage.setItem(lsp + "forbid", "1"); } function scroller() { if (initialized) { scrolled_here = true; localStorage.setItem(lsp + "scroll", root.scrollLeft + " " + root.scrollTop); } } function clicker(event) { if (initialized) { clicked_here = true; let x = event.clientX; let y = event.clientY; localStorage.setItem(lsp + "click", x + " " + y); } } function inputTer(event) { if (initialized) { inputTed_here = true; let el = event.target; let rect = el.getBoundingClientRect(); let x = Math.round((rect.left + rect.right) / 2); let y = Math.round((rect.top + rect.bottom) / 2); let val; if (el.getAttribute("type") === "checkbox") { val = "" + el.checked; } else { val = "" + el.value; } localStorage.setItem(lsp + "input", x + " " + y + " " + encodeURIComponent(val)); } } function popstate(event) { window.removeEventListener("popstate", popstate); if (initialized) { localStorage.setItem(lsp + "back", "" + +new Date()); } while (event.state === lsp + "back") history.go(-1); history.go(-1); while (event.state === lsp + "back") history.go(-1); window.addEventListener("popstate", popstate); } root.addEventListener("keypress", keypress); root.addEventListener("click", clicker); window.addEventListener("scroll", scroller); window.addEventListener("input", inputTer); window.addEventListener("storage", storage); window.addEventListener("popstate", popstate); if (localStorage.getItem(lsp + "forbid") == null) { init("event"); } function fireMouseEvent(node, eventName, x, y) { node.dispatchEvent(new MouseEvent(eventName, { altKey: false, ctrlKey: false, shiftKey: false, metaKey: false, bubbles: true, cancelable: true, button: 0, detail: 1, x: x, y: y, clientX: x, clientY: y, })); } })();