Doppelte Fenster

Synchronisiert Aktionen über Fenster/Tabs der gleichen Domain hinweg. Drücke C L O N E, um zu (de)aktivieren

  1. // ==UserScript==
  2. // @name Doppelte Fenster
  3. // @name:en Clone windows
  4. // @namespace http://tampermonkey.net/
  5. // @version 0.1
  6. // @description Synchronisiert Aktionen über Fenster/Tabs der gleichen Domain hinweg. Drücke C L O N E, um zu (de)aktivieren
  7. // @description:en Synchronizes actions across windows and tabs with the same domain. Press C L O N E to disable/re-enable
  8. // @author Aloso
  9. // @match https://www.google.com
  10. // @include https://*
  11. // @include http://*
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. "use strict";
  17. let lsp = "ls-clone-windows-" + encodeURI(window.location.hostname) + "-";
  18. let root = document.documentElement;
  19. let pressed = "";
  20. let last_press = 0;
  21. let initialized = false;
  22. let scrolled_here = false;
  23. let clicked_here = false;
  24. let inputTed_here = false;
  25. const msgStyle = {
  26. backgroundColor: "white",
  27. color: "black",
  28. fontSize: "18px",
  29. lineHeight: "initial",
  30. textShadow: "none",
  31. border: "none",
  32. borderRadius: "4px",
  33. boxShadow: "0 1px 30px rgba(0, 0, 0, 0.5)",
  34. boxSizing: "border-box",
  35. position: "fixed",
  36. opacity: "1",
  37. transform: "none",
  38. right: "5px",
  39. top: "5px",
  40. padding: "15px 20px",
  41. zIndex: "100000"
  42. };
  43. function msg(text) {
  44. let msg = document.createElement("div");
  45. msg.innerHTML = text;
  46. for (let x in msgStyle) if (msgStyle.hasOwnProperty(x)) {
  47. msg.style[x] = msgStyle[x];
  48. }
  49. document.body.appendChild(msg);
  50. setTimeout(() => document.body.removeChild(msg), 1300);
  51. }
  52. function keypress(event) {
  53. if (+new Date() - last_press > 600) pressed = "";
  54. last_press = +new Date();
  55.  
  56. pressed += event.key;
  57. if (pressed.length > 5) pressed = pressed.substr(pressed.length - 5);
  58. if (pressed === "clone") {
  59. pressed = "";
  60. if (!initialized) {
  61. init("event");
  62. msg("<span style='color:#007b20'>CLONING ENABLED</span>");
  63. } else {
  64. deInit();
  65. msg("<span style='color:red'>CLONING DISABLED</span>");
  66. }
  67. }
  68. }
  69. function storage(event) {
  70. if (event.newValue !== null && event.key.startsWith(lsp)) {
  71. let type = event.key.substring(lsp.length);
  72. if (type === "init") {
  73. if (!initialized) {
  74. init();
  75. msg("<span style='color:#007b20'>CLONING ENABLED</span>");
  76. }
  77. } else if (type === "forbid") {
  78. if (initialized) {
  79. deInit();
  80. msg("<span style='color:red'>CLONING DISABLED</span>");
  81. }
  82. } else if (initialized) {
  83. if (type === "scroll") {
  84. if (!scrolled_here) {
  85. let [x, y] = event.newValue.split(" ").map(x => +x);
  86. root.scrollTo(x, y);
  87. }
  88. scrolled_here = false;
  89. } else if (type === "click") {
  90. if (!clicked_here) {
  91. let [xs, ys, val] = event.newValue.split(" ");
  92. let x = +xs;
  93. let y = +ys;
  94. let el = document.elementFromPoint(x, y);
  95. if (el != null) {
  96. fireMouseEvent(el, "click", x, y);
  97. }
  98. }
  99. clicked_here = false;
  100. } else if (type === "input") {
  101. if (!inputTed_here) {
  102. let [xs, ys, val] = event.newValue.split(" ");
  103. let x = +xs;
  104. let y = +ys;
  105. val = decodeURIComponent(val);
  106. let el = document.elementFromPoint(x, y);
  107. if (el.nodeName === "INPUT" || el.nodeName === "TEXTAREA" || el.nodeName === "SELECT") {
  108. if (el.getAttribute("type") === "checkbox") {
  109. el.checked = val !== "false";
  110. } else {
  111. el.value = val;
  112. }
  113. }
  114. }
  115. inputTed_here = false;
  116. } else if (type === "back") {
  117. window.removeEventListener("popstate", popstate);
  118. setTimeout(() => {
  119. while (event.state === lsp + "back") history.go(-1);
  120. history.go(-1);
  121. while (event.state === lsp + "back") history.go(-1);
  122. window.addEventListener("popstate", popstate);
  123. }, 80);
  124. }
  125. }
  126. }
  127. }
  128. function init(option) {
  129. initialized = true;
  130. if (option === "event") {
  131. localStorage.setItem(lsp + "init", "1");
  132. }
  133. localStorage.removeItem(lsp + "forbid");
  134. if (history.state !== lsp + "back") {
  135. history.pushState(lsp + "back", "Go back");
  136. }
  137. }
  138. function deInit() {
  139. initialized = false;
  140. for (let x in localStorage) {
  141. if (x.startsWith(lsp) && localStorage.hasOwnProperty(x)) {
  142. localStorage.removeItem(x);
  143. }
  144. }
  145. localStorage.setItem(lsp + "forbid", "1");
  146. }
  147. function scroller() {
  148. if (initialized) {
  149. scrolled_here = true;
  150. localStorage.setItem(lsp + "scroll", root.scrollLeft + " " + root.scrollTop);
  151. }
  152. }
  153. function clicker(event) {
  154. if (initialized) {
  155. clicked_here = true;
  156. let x = event.clientX;
  157. let y = event.clientY;
  158. localStorage.setItem(lsp + "click", x + " " + y);
  159. }
  160. }
  161.  
  162. function inputTer(event) {
  163. if (initialized) {
  164. inputTed_here = true;
  165. let el = event.target;
  166. let rect = el.getBoundingClientRect();
  167. let x = Math.round((rect.left + rect.right) / 2);
  168. let y = Math.round((rect.top + rect.bottom) / 2);
  169. let val;
  170. if (el.getAttribute("type") === "checkbox") {
  171. val = "" + el.checked;
  172. } else {
  173. val = "" + el.value;
  174. }
  175. localStorage.setItem(lsp + "input", x + " " + y + " " + encodeURIComponent(val));
  176. }
  177. }
  178. function popstate(event) {
  179. window.removeEventListener("popstate", popstate);
  180. if (initialized) {
  181. localStorage.setItem(lsp + "back", "" + +new Date());
  182. }
  183. while (event.state === lsp + "back") history.go(-1);
  184. history.go(-1);
  185. while (event.state === lsp + "back") history.go(-1);
  186. window.addEventListener("popstate", popstate);
  187. }
  188. root.addEventListener("keypress", keypress);
  189. root.addEventListener("click", clicker);
  190. window.addEventListener("scroll", scroller);
  191. window.addEventListener("input", inputTer);
  192. window.addEventListener("storage", storage);
  193. window.addEventListener("popstate", popstate);
  194.  
  195. if (localStorage.getItem(lsp + "forbid") == null) {
  196. init("event");
  197. }
  198. function fireMouseEvent(node, eventName, x, y) {
  199. node.dispatchEvent(new MouseEvent(eventName, {
  200. altKey: false,
  201. ctrlKey: false,
  202. shiftKey: false,
  203. metaKey: false,
  204. bubbles: true,
  205. cancelable: true,
  206. button: 0,
  207. detail: 1,
  208. x: x,
  209. y: y,
  210. clientX: x,
  211. clientY: y,
  212. }));
  213. }
  214.  
  215. })();