Remove Restrictions and Restore Default Behavior

Allows you select, cut, copy, paste, save and open the DevTools on any website.

目前為 2024-05-03 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Remove Restrictions and Restore Default Behavior
  3. // @name:zh-CN 解除网页限制,恢复默认行为
  4. // @name:en-US Remove Restrictions and Restore Default Behavior
  5. // @namespace http://hl-bo.github.io/namespaces/user-script/remove-limits
  6. // @source https://github.com/HL-Bo/user-script
  7. // @supportURL https://github.com/HL-Bo/user-script/issues
  8. // @version 2.1
  9. // @license AGPLv3
  10. // @description Allows you select, cut, copy, paste, save and open the DevTools on any website.
  11. // @description:zh-CN 恢复选择、剪切、复制、粘贴、保存、右键菜单和打开开发者工具的默认行为。
  12. // @description:en-US Allows you select, cut, copy, paste, save and open the DevTools on any website.
  13. // @author HL-Bo
  14. // @match *://*/**
  15. // @exclude *://vscode.dev/**
  16. // @exclude *://github.com/*/*/edit/**
  17. // @exclude *://gitee.com/*/*/edit/**
  18. // @exclude *://codeberg.org/*/*/_edit/**
  19. // @exclude *://www.figma.com/file/**
  20. // @exclude *://www.notion.so/**
  21. // @exclude *://outlook.live.com/**
  22. // @exclude *://mail.netease.com/**
  23. // @exclude *://mail.163.com/**
  24. // @exclude *://mail.126.com/**
  25. // @exclude *://www.yeah.net/**
  26. // @exclude *://mail.qq.com/**
  27. // @exclude *://uutool.cn/*
  28. // @exclude *://anytexteditor.com/*/online-notepad
  29. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAspJREFUWEfVl89PE1EQx7/TdpcabKFAoEKQH22ktEYSqRevXiRijEr8cSDe/DNM9D/xhPFn4oF4MeBZuJi0SiiQikTjD2gLCLS7jNmFLt2mu/uWYtB36G73zWQ+b2bevDeEijE5Od/Q3ut5CNA9gMOVc3bvG7+3MLeYRU9nhxqP9r2WURoPh8ObIvpUKTSbzkww6I6IYqWMAdAVxmCkF8z8zk/KFREIA2BmbilGu7tpZpigRGCqATQdAk3LKI46QRjGZtOZ6wx6KWKwWqYWgCbDzNN+UmwhDID3HxduEuP5UQKIQPx1gDJEnpTRoRqJaQnw/dcqVvPrANf2iST50N/dCSKCVQjMmjyVg3K1GsISILvyFT/X8pYRkXw+nD3TD4/HIwigp+ZUDkUThG0I9MVbeIAq9srW9g7SmSW0t4ZwPjHglEZvf3xZGkkmk6W93bI/qpNQUVVs7xRtPOBFgyzr88yM1PwidoolRE53oS3UbAuhMo8Mx/re2ALMZ5dRWLcuZlrsh2JReL1e3ZiWB5nsMlR118kDII/39v2xy09tAQobm8jrALVjIEsSOtpaTMZKioLVXAHaU/OK1fAAt65duvjMFsBxGXUIMGHswmDkhS2AtpK1wnodZg5UQ8EAWpqDxgchgIXPK8gdEUBzMKAnZ3kIAWgxLCmq9T4U9g1B8nn1gvV/ARx7CI49CYVDfAhBoSR0KkTidglNgUYETza6S0KtrO5VwvqHBhDt6XYH4HQYucHyN8jw7Z8Z+uElUgl1QePHjbkqWao4cvenhACcLiRukNpCTejpOuUuBE5XMmEAAlqaAmhvPTg5hTwgbOAQgv8mQD2NiVsnEPjGcDz6ynQfmPkwFyPJd6jWzA0AEZhLSjx5buCTCUD7M5temGDAdXPqCgB4MhyP3C3rmBrRVColb5H/kdv2XAyAvgH8+ARvP0gkEsZ1+w+ixcUwoQ+80AAAAABJRU5ErkJggg==
  30. // @grant none
  31. // @run-at document-start
  32. // ==/UserScript==
  33.  
  34. (function () {
  35. 'use strict';
  36. console.info('Start the installation of user-script/remove-limits');
  37.  
  38. // 尝试禁用 debugger
  39. // 仅在 eval('debugger') 或 setInterval('debugger', sec) 构造前执行才能阻止
  40. try {
  41. Function.prototype.__constructor_back = Function.prototype.constructor;
  42. Function.prototype.constructor = function () {
  43. if (arguments && typeof arguments[0] === 'string') {
  44. if ('debugger' === arguments[0]) {
  45. console.debug('Disable an function which may execute debugger');
  46. return;
  47. }
  48. }
  49. return Function.prototype.__constructor_back.apply(this, arguments);
  50. }
  51. } catch (error) { } finally { }
  52.  
  53. let setEventListener = function (element, event_name, listener) {
  54. if (element.rl_events) {
  55. if (element.rl_events.has(event_name)) {
  56. element.removeEventListener(event_name, element.rl_events.get(event_name));
  57. }
  58. } else {
  59. element.rl_events = new Map();
  60. }
  61. element.rl_events.set(event_name, listener);
  62. element.addEventListener(event_name, listener);
  63. }
  64. let returnEventAllowed = function (event, event_name) {
  65. try {
  66. event.returnValue = true;
  67. } catch (error) { } finally { }
  68. if (event_name !== null) {
  69. console.debug(`Allow ${event_name}`);
  70. }
  71. };
  72. let allowEvent = function (element, event_name) {
  73. setEventListener(element, event_name, function (event) { returnEventAllowed(event, event_name); return true; });
  74. };
  75. let onKeyEvents = function (event) {
  76. let keyCode = event.keyCode || event.which || event.charCode;
  77. let ctrlKey = event.ctrlKey || event.metaKey;
  78. let shiftKey = event.shiftKey;
  79. if (ctrlKey && (keyCode == 65 || keyCode == 88 || keyCode == 67 || keyCode == 86 || keyCode == 83 || keyCode == 85)) {
  80. // Ctrl+A (select-all), Ctrl+X (cut), Ctrl+C (copy), Ctrl+V (paste), Ctrl+S (save), Ctrl+U (view-source)
  81. returnEventAllowed(event, 'hotkey');
  82. } else if (ctrlKey && shiftKey && (keyCode == 73 || keyCode == 74 || keyCode == 67)) {
  83. // Ctrl+Shift+I (devtools), Ctrl+Shift+J (console), Ctrl+Shift+C (elements)
  84. returnEventAllowed(event, 'hotkey (DevTools)');
  85. } else if (keyCode && keyCode == 123) { // F12
  86. returnEventAllowed(event, 'hotkey (F12)');
  87. }
  88. return true;
  89. };
  90. let allowKeyEvents = function (element, event_name) {
  91. setEventListener(element, event_name, onKeyEvents);
  92. };
  93. let allowElement = function (element) {
  94. try { element.oncopy = null; } catch (error) { } finally { allowEvent(element, 'copy'); }
  95. // 取消通过 JavaScript 实现的禁止文字选择
  96. try { element.onselectstart = null; } catch (error) { } finally { allowEvent(element, 'selectstart'); }
  97. // 取消通过 JavaScript 实现的禁止右键菜单
  98. try { element.oncontextmenu = null; } catch (error) { } finally { allowEvent(element, 'contextmenu'); }
  99. // 取消通过 JavaScript 实现的禁止剪切实现的禁止复制
  100. try { element.oncut = null; } catch (error) { } finally { allowEvent(element, 'cut'); }
  101. // 取消通过 JavaScript 实现的禁止粘贴
  102. try { element.onpaste = null; } catch (error) { } finally { allowEvent(element, 'paste'); }
  103. // 取消通过 CSS 实现的禁止选中
  104. try { element.style.webkitUserSelect = 'auto'; } catch (error) { } finally { } // Firefox
  105. try { element.style.userSelect = 'auto'; } catch (error) { } finally { } // Chrome
  106. // 取消通过 JavaScript 实现的禁用快捷键
  107. try { element.onkeypress = null; } catch (error) { } finally { allowKeyEvents(element, 'keypress'); }
  108. try { element.onkeydown = null; } catch (error) { } finally { allowKeyEvents(element, 'keydown'); }
  109. try { element.onkeyup = null; } catch (error) { } finally { allowKeyEvents(element, 'keyup'); }
  110. // 取消通过 JavaScript 实现的页面离开检测
  111. try { element.onvisibilitychange = null; } catch (error) { } finally { allowEvent(element, 'visibilitychange'); }
  112. try { element.onmouseout = null; } catch (error) { } finally { allowEvent(element, 'mouseout'); }
  113. try { element.onmouseleave = null; } catch (error) { } finally { allowEvent(element, 'mouseleave'); }
  114. }
  115. // let removeAllListeners = function (old_element) {
  116. // let new_element = old_element.cloneNode(true);
  117. // old_element.parentNode.replaceChild(new_element, old_element);
  118. // };
  119. let removeHiddenElements = function (element, recursion) {
  120. if (element.style.display == 'none' || element.style.visibility == 'hidden') {
  121. console.info(`Remove <${element.tagName} id='${element.id}' class='${element.className}' />`);
  122. element.remove();
  123. } else if (recursion) {
  124. for (let i = 0; i < element.children.length; i++) {
  125. removeHiddenElements(element.children.item(i), recursion);
  126. }
  127. }
  128. };
  129. let getMainContainerElement = function () {
  130. // 获取正文节点
  131. let main_container_element = null;
  132. if (document) {
  133. if (main_container_element === null) { // 检查 main 标签
  134. let elements = document.getElementsByTagName('main');
  135. if (elements.length > 0) { main_container_element = elements[0]; }
  136. }
  137. if (main_container_element === null) { // 检查 id='main' 的标签
  138. main_container_element = document.getElementById('main');
  139. }
  140. if (main_container_element === null) { // 检查 id='content' 的标签
  141. main_container_element = document.getElementById('content');
  142. }
  143. if (main_container_element === null) { // 检查 id='contents' 的标签
  144. main_container_element = document.getElementById('contents');
  145. }
  146. if (main_container_element === null) { // 检查 class='main' 的标签
  147. let elements = document.getElementsByClassName('main');
  148. if (elements.length > 0) { main_container_element = elements[0]; }
  149. }
  150. if (main_container_element === null) { // 检查 class='content' 的标签
  151. let elements = document.getElementsByClassName('content');
  152. if (elements.length > 0) { main_container_element = elements[0]; }
  153. }
  154. if (main_container_element === null) { // 检查 class='contents' 的标签
  155. let elements = document.getElementsByClassName('contents');
  156. if (elements.length > 0) { main_container_element = elements[0]; }
  157. }
  158. }
  159. return main_container_element;
  160. };
  161.  
  162. // 对抗延迟运行(即在此脚本执行后运行)的禁用程序和循环执行的禁用程序,
  163. setInterval( // 每 0.2 秒执行一次。
  164. (function () {
  165. if (document) {
  166. try { allowElement(document); } catch (error) { } finally { }
  167. }
  168. }), 200
  169. );
  170. setInterval( // 每 0.3 秒执行一次。
  171. (function () {
  172. if (document) {
  173. try { allowElement(document.body); } catch (error) { } finally { }
  174. }
  175. }), 300
  176. );
  177. setInterval( // 每 0.5 秒执行一次。
  178. (function () {
  179. let mce = getMainContainerElement()
  180. if (document && mce) {
  181. try { allowElement(mce); } catch (error) { } finally { }
  182. }
  183. }), 500
  184. );
  185.  
  186. // 对抗延迟运行(即在此脚本执行后运行)的混淆程序和循环执行的混淆程序,
  187. setTimeout(
  188. // 延迟 0.6 秒,有助于动态加载的内容的显示。
  189. function () {
  190. console.debug('Start scanning for hidden elements');
  191. setInterval(
  192. // 每 2 秒执行一次。
  193. function () {
  194. if (document) {
  195. // 移除正文中的不可见元素
  196. try {
  197. let mce = getMainContainerElement()
  198. // 移除不可见元素
  199. if (mce) {
  200. removeHiddenElements(mce, true);
  201. }
  202. } catch (error) { } finally { }
  203. }
  204. }, 2000
  205. );
  206. }, 600
  207. )
  208.  
  209. console.debug('Complete the installation of user-script/remove-limits');
  210. })();