通用脚本重开启选取复制

破解锁右键,解除禁止复制、剪切、选择文本、右键菜单、文字复制、文字选取、图片右键等限制。增强功能:Alt键超连结文字选取。

目前为 2022-05-09 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name A Universal Script to Re-Enable the Selection and Copying
  3. // @name:zh-TW A Universal Script to Re-Enable the Selection and Copying
  4. // @name:zh-CN 通用脚本重开启选取复制
  5. // @version 1.8.1.1
  6. // @icon https://image.flaticon.com/icons/png/128/3848/3848147.png
  7. // @description Enables select, right-click, copy and drag on pages that disable them. Enhanced Feature: Alt Key HyperLink Text Selection
  8. // @description:zh-TW 破解鎖右鍵,解除禁止復制、剪切、選擇文本、右鍵菜單、文字複製、文字選取、圖片右鍵等限制。增強功能:Alt鍵超連結文字選取。
  9. // @description:zh-CN 破解锁右键,解除禁止复制、剪切、选择文本、右键菜单、文字复制、文字选取、图片右键等限制。增强功能:Alt键超连结文字选取。
  10. // @match http://*/*
  11. // @match https://*/*
  12. // @grant GM_registerMenuCommand
  13. // @grant GM_unregisterMenuCommand
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // @grant GM_addValueChangeListener
  17. // @grant GM_listValues
  18. // @run-at document-start
  19. // @namespace https://gf.qytechs.cn/users/371179
  20. // ==/UserScript==
  21. (function $$() {
  22. 'use strict';
  23. if (document == null || !document.documentElement) return window.requestAnimationFrame($$); // this is tampermonkey bug?? not sure
  24. //console.log('script at', location)
  25.  
  26. function $nil() {}
  27.  
  28. function isLatestBrowser(){
  29.  
  30. let res;
  31. try{
  32. let o ={$nil};
  33. o?.$nil();
  34. o=null;
  35. o?.$nil();
  36. res = true;
  37. }catch(e){}
  38. return !!res;
  39. }
  40. if(!isLatestBrowser()) throw 'Browser version before 2020-01-01 is not supported. Please update to the latest version.';
  41.  
  42. function isSupportAdvancedEventListener() {
  43. if ('_b1750' in $) return $._b1750
  44. var prop = 0;
  45. document.createAttribute('z').addEventListener('nil', $nil, {
  46. get passive() {
  47. prop++;
  48. },
  49. get once() {
  50. prop++;
  51. }
  52. });
  53. return ($._b1750 = prop == 2);
  54. }
  55.  
  56. function isSupportPassiveEventListener() {
  57. if ('_b1650' in $) return $._b1650
  58. var prop = 0;
  59. document.createAttribute('z').addEventListener('nil', $nil, {
  60. get passive() {
  61. prop++;
  62. }
  63. });
  64. return ($._b1650 = prop == 1);
  65. }
  66.  
  67. function inIframe () {
  68. try {
  69. return window.self !== window.top;
  70. } catch (e) {
  71. return true;
  72. }
  73. }
  74.  
  75. var getSelection = window.getSelection || Error()(),
  76. requestAnimationFrame = window.requestAnimationFrame || Error()(),
  77. getComputedStyle = window.getComputedStyle || Error()();
  78.  
  79. const $ = {
  80. utSelectionColorHack: 'msmtwejkzrqa',
  81. utTapHighlight: 'xfcklblvkjsj',
  82. utLpSelection: 'gykqyzwufxpz',
  83. utHoverBlock: 'meefgeibrtqx', //scc_emptyblock
  84. //utNonEmptyElm: 'ilkpvtsnwmjb',
  85. utNonEmptyElmPrevElm: 'jttkfplemwzo',
  86. utHoverTextWrap: 'oseksntfvucn',
  87. ksFuncReplacerNonFalse: '___dqzadwpujtct___',
  88. ksEventReturnValue: ' ___ndjfujndrlsx___',
  89. ksSetData: '___rgqclrdllmhr___',
  90. ksNonEmptyPlainText: '___grpvyosdjhuk___',
  91.  
  92. eh_capture_passive: () => isSupportPassiveEventListener() ? ($._eh_capture_passive = ($._eh_capture_passive || {
  93. capture: true,
  94. passive: true
  95. })) : true,
  96.  
  97. mAlert_DOWN: function() {}, //dummy function in case alert replacement is not valid
  98. mAlert_UP: function() {}, //dummy function in case alert replacement is not valid
  99.  
  100.  
  101. lpKeyPressing: false,
  102. lpKeyPressingPromise: Promise.resolve(),
  103.  
  104. isNum: (d) => (d > 0 || d < 0 || d === 0),
  105.  
  106. isAnySelection: function() {
  107. var sel = getSelection();
  108. return !sel ? null : (typeof sel.isCollapsed == 'boolean') ? !sel.isCollapsed : (sel.toString().length > 0);
  109. },
  110.  
  111. createCSSElement: function(cssStyle, container) {
  112. var css = document.createElement('style'); //slope: DOM throughout
  113. css.type = 'text/css';
  114. css.textContent = cssStyle;
  115. if (container) container.appendChild(css);
  116. return css;
  117. },
  118.  
  119. createFakeAlert: function(_alert) {
  120. if (typeof _alert != 'function') return null;
  121.  
  122. function alert(msg) {
  123. alert.__isDisabled__() ? console.log("alert msg disabled: ", msg) : _alert.apply(this, arguments);
  124. };
  125. alert.toString = () => "function alert() { [native code] }";
  126. return alert;
  127. },
  128.  
  129. createFuncReplacer: function(originalFunc, pName, resFX) {
  130. resFX = function(ev) {
  131. var res = originalFunc.apply(this, arguments);
  132. if (!this || this[pName] != resFX) return res; // if this is null or undefined, or this.onXXX is not this function
  133. if (res === false) return; // return undefined when "return false;"
  134. originalFunc[$.ksFuncReplacerNonFalse] = true;
  135. this[pName] = originalFunc; // restore original
  136. return res;
  137. }
  138. resFX.toString = () => originalFunc.toString();
  139. return resFX;
  140. },
  141.  
  142. listenerDisableAll: function(evt) {
  143. var elmNode = evt.target;
  144. var pName = 'on' + evt.type;
  145. evt = null;
  146. Promise.resolve().then(() => {
  147. while (elmNode && elmNode.nodeType > 0) { //i.e. HTMLDocument or HTMLElement
  148. var f = elmNode[pName];
  149. if (typeof f == 'function' && f[$.ksFuncReplacerNonFalse] !== true) {
  150. var nf = $.createFuncReplacer(f, pName);
  151. nf[$.ksFuncReplacerNonFalse] = true;
  152. elmNode[pName] = nf;
  153. }
  154. elmNode = elmNode.parentNode;
  155. }
  156. })
  157. },
  158.  
  159. onceCssHighlightSelection: () => {
  160. if (document.documentElement.hasAttribute($.utLpSelection)) return;
  161. $.onceCssHighlightSelection = null
  162. Promise.resolve().then(() => {
  163. var s = [...document.querySelectorAll('a,p,div,span,b,i,strong,li')].filter(elm => elm.childElementCount === 0); // randomly pick an element containing text only to avoid css style bug
  164. var elm = !s.length ? document.body : s[s.length >> 1];
  165. return elm
  166. }).then(elm => {
  167. var selectionStyle = getComputedStyle(elm, ':selection');
  168. if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(selectionStyle.getPropertyValue('background-color'))) document.documentElement.setAttribute($.utSelectionColorHack, "");
  169. return elm;
  170. }).then(elm => {
  171. var elmStyle = getComputedStyle(elm)
  172. if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(elmStyle.getPropertyValue('-webkit-tap-highlight-color'))) document.documentElement.setAttribute($.utTapHighlight, "");
  173. })
  174. },
  175.  
  176. clipDataProcess: function(clipboardData) {
  177.  
  178. if (!clipboardData) return;
  179. const evt = clipboardData[$.ksSetData]; //NOT NULL when preventDefault is called
  180. if (!evt || evt.clipboardData !== clipboardData) return;
  181. const plainText = clipboardData[$.ksNonEmptyPlainText]; //NOT NULL when setData is called with non empty input
  182. if (!plainText) return;
  183.  
  184. //BOTH preventDefault and setData are called.
  185.  
  186. if (evt.cancelable !== true || evt.defaultPrevented !== false) return;
  187. $.bypass = true;
  188. evt.preventDefault();
  189. $.bypass = false;
  190.  
  191.  
  192. var trimedSelectionText = getSelection().toString().trim()
  193.  
  194. if (trimedSelectionText) {
  195. //there is replacement data and the selection is not empty
  196. console.log({
  197. msg: "copy event - clipboardData replacement is allowed and the selection is not empty",
  198. oldText: trimedSelectionText,
  199. newText: plainText,
  200. })
  201. } else {
  202. //there is replacement data and the selection is empty
  203. console.log({
  204. msg: "copy event - clipboardData replacement is allowed and the selection is empty",
  205. oldText: trimedSelectionText,
  206. newText: plainText,
  207. })
  208. }
  209.  
  210. },
  211.  
  212. enableSelectClickCopy: function() {
  213. $.eyEvts = ['keydown', 'keyup', 'copy', 'contextmenu', 'select', 'selectstart', 'dragstart', 'beforecopy']; //slope: throughout
  214.  
  215. function isDeactivePreventDefault(evt) {
  216. if ($.bypass) return false;
  217. var j = $.eyEvts.indexOf(evt.type);
  218. switch (j) {
  219. case 6:
  220. if ($.enableDragging) return false;
  221. if (evt&&evt.target && evt.target.nodeType==1 && evt.target.hasAttribute('draggable')) {
  222. $.enableDragging = true;
  223. return false;
  224. }
  225. //if(evt.target.hasAttribute('draggable')&&evt.target!=window.getSelection().anchorNode)return false;
  226. return true;
  227. case 3:
  228. if (evt.target instanceof Element && (evt.target.textContent || "").trim().length === 0) return false; //exclude elements like video
  229. return true;
  230. case -1:
  231. return false;
  232. case 0:
  233. case 1:
  234. return (evt.keyCode == 67 && (evt.ctrlKey || evt.metaKey) && !evt.altKey && !evt.shiftKey && $.isAnySelection() === true);
  235. case 2:
  236. if (!('clipboardData' in evt && 'setData' in DataTransfer.prototype)) return true; // Event oncopy not supporting clipboardData
  237. if (evt.cancelable && evt.defaultPrevented === false) {} else return true;
  238.  
  239. if (evt.clipboardData[$.ksSetData] && evt.clipboardData[$.ksSetData] != evt) return true; //in case there is a bug
  240. evt.clipboardData[$.ksSetData] = evt;
  241.  
  242. $.clipDataProcess(evt.clipboardData);
  243.  
  244. return true; //preventDefault in clipDataProcess
  245.  
  246.  
  247. default:
  248. return true;
  249. }
  250. }
  251.  
  252. !(function($setData) {
  253. DataTransfer.prototype.setData = (function setData() {
  254.  
  255. if (arguments[0] == 'text/plain' && typeof arguments[1] == 'string') {
  256. if (arguments[1].trim().length > 0) {
  257. this[$.ksNonEmptyPlainText] = arguments[1]
  258. } else if (this[$.ksNonEmptyPlainText]) {
  259. arguments[1] = this[$.ksNonEmptyPlainText]
  260. }
  261. }
  262.  
  263. $.clipDataProcess(this)
  264.  
  265. let res = $setData.apply(this, arguments)
  266.  
  267. return res;
  268.  
  269. })
  270. })(DataTransfer.prototype.setData);
  271.  
  272. Object.defineProperties(DataTransfer.prototype, {
  273. [$.ksSetData]: { //store the event
  274. value: null,
  275. writable: true,
  276. enumerable: false,
  277. configurable: true
  278. },
  279. [$.ksNonEmptyPlainText]: { //store the text
  280. value: null,
  281. writable: true,
  282. enumerable: false,
  283. configurable: true
  284. }
  285. })
  286.  
  287.  
  288. Event.prototype.preventDefault = (function(f) {
  289. function preventDefault() {
  290. if (!isDeactivePreventDefault(this)) f.call(this);
  291. }
  292. preventDefault.toString = () => f.toString();
  293. return preventDefault;
  294. })(Event.prototype.preventDefault);
  295.  
  296. Object.defineProperty(Event.prototype, "returnValue", {
  297. get() {
  298. return $.ksEventReturnValue in this ? this[$.ksEventReturnValue] : true;
  299. },
  300. set(newValue) {
  301. if (newValue === false && !isDeactivePreventDefault(this)) this.preventDefault();
  302. this[$.ksEventReturnValue] = newValue;
  303. },
  304. enumerable: true,
  305. configurable: true
  306. });
  307.  
  308. for (var i = 2, eventsCount = $.eyEvts.length; i < eventsCount; i++) {
  309. document.addEventListener($.eyEvts[i], $.listenerDisableAll, true); // Capture Event; passive:false; expected occurrence COMPLETELY before Target Capture and Target Bubble
  310. }
  311.  
  312. // userscript bug ? window.alert not working
  313. let window = null;
  314. try{
  315. window = new Function('return window')();
  316. }catch(e){}
  317. if(window){
  318. let _alert = window.alert; //slope: temporary
  319. if (typeof _alert == 'function') {
  320. let _mAlert = $.createFakeAlert(_alert);
  321. if (_mAlert) {
  322. let clickBlockingTo = 0;
  323. _mAlert.__isDisabled__ = () => clickBlockingTo > +new Date;
  324. $.mAlert_DOWN = () => (clickBlockingTo = +new Date + 50);
  325. $.mAlert_UP = () => (clickBlockingTo = +new Date + 20);
  326. window.alert = _mAlert
  327. }
  328. _mAlert=null;
  329. }
  330. _alert=null;
  331. }
  332. window=null;
  333.  
  334. },
  335.  
  336. lpCheckPointer: function(targetElm) {
  337. if (targetElm && targetElm.nodeType == 1 && targetElm.matches('*:hover')) {
  338. if (getComputedStyle(targetElm).getPropertyValue('cursor') == 'pointer' && targetElm.textContent) return true;
  339. }
  340. return false;
  341. },
  342.  
  343. eventCancel: function(evt, toPreventDefault) {
  344. $.bypass = true;
  345. !toPreventDefault || evt.preventDefault()
  346. evt.stopPropagation();
  347. evt.stopImmediatePropagation();
  348. $.bypass = false;
  349. },
  350.  
  351. lpHoverBlocks:[],
  352. lpKeyAltLastPressAt:0,
  353. lpKeyAltPressInterval:0,
  354.  
  355. noPlayingVideo:function(){
  356.  
  357. // prevent poor video preformance
  358.  
  359. let noPlaying =true;
  360. for(const video of document.querySelectorAll('video[src]')){
  361.  
  362. if(video.paused===false) noPlaying=false;
  363.  
  364. }
  365. return noPlaying;
  366.  
  367.  
  368. },
  369.  
  370.  
  371. lpKeyDown: function(evt) {
  372.  
  373. if(!$.gm_lp_enable)return;
  374.  
  375. const isAltPress= (evt.key == "Alt" && evt.altKey && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey)
  376.  
  377.  
  378.  
  379.  
  380. if (isAltPress) {
  381.  
  382. $.lpKeyAltLastPressAt=+new Date;
  383.  
  384. let element=evt.target
  385.  
  386.  
  387. if($.lpKeyPressing == false && element && element.parentNode && !evt.repeat && $.noPlayingVideo()){
  388.  
  389. $.lpKeyPressing = true;
  390.  
  391. $.cid_lpKeyPressing=setInterval(()=>{
  392. if($.lpKeyAltLastPressAt+500<+new Date){
  393. $.lpCancelKeyPressAlt();
  394. }
  395. },137);
  396.  
  397. const rootNode = $.rootHTML(element);
  398. if (rootNode) {
  399. let tmp_wmEty = null;
  400.  
  401.  
  402. let wmTextWrap = new WeakMap();
  403.  
  404. $.lpKeyPressingPromise = $.lpKeyPressingPromise.then(() => {
  405. for (const elm of $.lpHoverBlocks) {
  406. elm.removeAttribute($.utNonEmptyElmPrevElm)
  407. elm.removeAttribute($.utHoverTextWrap)
  408. }
  409. $.lpHoverBlocks.length=0;
  410. }).then(() => {
  411. tmp_wmEty = new WeakMap(); // 1,2,3.....: non-empty elm, -1:empty elm
  412. const s = [...rootNode.querySelectorAll('*:not(button, textarea, input, script, noscript, style, link, img, br)')].filter((elm) => elm.childElementCount === 0 && (elm.textContent || '').trim().length > 0)
  413. for (const elm of s) tmp_wmEty.set(elm, 1);
  414. return s;
  415. }).then((s) => {
  416. let laterArr = [];
  417. let promises = [];
  418.  
  419. let promiseCallback = parentNode => {
  420. if (wmTextWrap.get(parentNode) !== null) return;
  421. const m = [...parentNode.children].some(elm => {
  422. const value = getComputedStyle(elm).getPropertyValue('z-index');
  423. if (typeof value == 'string' && value.length > 0) return $.isNum(+value)
  424. return false
  425. })
  426. wmTextWrap.set(parentNode, m)
  427. if (m) {
  428. $.lpHoverBlocks.push(parentNode);
  429. parentNode.setAttribute($.utHoverTextWrap, '')
  430. }
  431.  
  432. };
  433.  
  434. for (const elm of s) {
  435. let qElm = elm;
  436. let qi = 1;
  437. while (true) {
  438. let pElm = qElm.previousElementSibling;
  439. let anyEmptyHover = false;
  440. while (pElm) {
  441. if (tmp_wmEty.get(pElm) > 0) break;
  442. if (!pElm.matches(`button, textarea, input, script, noscript, style, link, img, br`) && (pElm.textContent || '').length === 0 && pElm.clientWidth * pElm.clientHeight > 0) {
  443. laterArr.push(pElm);
  444. anyEmptyHover = true;
  445. }
  446. pElm = pElm.previousElementSibling;
  447. }
  448. if (anyEmptyHover && !wmTextWrap.has(qElm.parentNode)) {
  449. wmTextWrap.set(qElm.parentNode, null)
  450. promises.push(Promise.resolve(qElm.parentNode).then(promiseCallback))
  451. }
  452. qElm = qElm.parentNode;
  453. if (!qElm || qElm === rootNode) break;
  454. qi++
  455. if (tmp_wmEty.get(qElm) > 0) break;
  456. tmp_wmEty.set(qElm, qi)
  457. }
  458. }
  459.  
  460. tmp_wmEty = null;
  461.  
  462. Promise.all(promises).then(() => {
  463. promises.length = 0;
  464. promises = null;
  465. promiseCallback = null;
  466. for (const pElm of laterArr) {
  467. let parentNode = pElm.parentNode
  468. if (wmTextWrap.get(parentNode) === true) {
  469. $.lpHoverBlocks.push(pElm);
  470. pElm.setAttribute($.utNonEmptyElmPrevElm, '');
  471. }
  472. }
  473. laterArr.length = 0;
  474. laterArr = null;
  475. wmTextWrap = null;
  476. })
  477. })
  478.  
  479. }
  480.  
  481. }
  482.  
  483.  
  484. }else if($.lpKeyPressing==true){
  485.  
  486. $.lpCancelKeyPressAlt();
  487.  
  488. }
  489.  
  490. },
  491. lpCancelKeyPressAlt:()=>{
  492. $.lpKeyPressing = false;
  493. if($.cid_lpKeyPressing>0) $.cid_lpKeyPressing=clearInterval($.cid_lpKeyPressing)
  494.  
  495. $.lpKeyPressingPromise = $.lpKeyPressingPromise.then(() => {
  496. for (const elm of $.lpHoverBlocks) {
  497. elm.removeAttribute($.utNonEmptyElmPrevElm)
  498. elm.removeAttribute($.utHoverTextWrap)
  499. }
  500. $.lpHoverBlocks.length=0;
  501. })
  502.  
  503.  
  504. setTimeout(function(){
  505. if($.lpMouseActive == 1){
  506. $.lpMouseUpClear();
  507. $.lpMouseActive=0;
  508. }
  509. },32);
  510.  
  511. },
  512. lpKeyUp: function(evt) {
  513.  
  514. if(!$.gm_lp_enable)return;
  515.  
  516. if ($.lpKeyPressing == true) {
  517. $.lpCancelKeyPressAlt();
  518. }
  519.  
  520.  
  521. },
  522.  
  523. lpAltRoots:[],
  524.  
  525. lpMouseDown: function(evt) {
  526.  
  527. if(!$.gm_lp_enable)return;
  528.  
  529. $.lpMouseActive = 0;
  530. if (evt.altKey && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && evt.button === 0 && $.noPlayingVideo()) {
  531. $.lpMouseActive = 1;
  532. $.eventCancel(evt, false);
  533. const rootNode = $.rootHTML(evt.target);
  534. $.lpAltRoots.push(rootNode);
  535. rootNode.setAttribute($.utLpSelection, '');
  536. }
  537. },
  538.  
  539. lpMouseUpClear:function(){
  540. for(const rootNode of $.lpAltRoots) rootNode.removeAttribute($.utLpSelection);
  541. $.lpAltRoots.length=0;
  542. if ($.onceCssHighlightSelection) window.requestAnimationFrame($.onceCssHighlightSelection);
  543. },
  544.  
  545. lpMouseUp: function(evt) {
  546.  
  547. if(!$.gm_lp_enable)return;
  548.  
  549. if ($.lpMouseActive == 1) {
  550. $.lpMouseActive = 2;
  551. $.eventCancel(evt, false);
  552. $.lpMouseUpClear();
  553. }
  554. },
  555.  
  556. lpClick: function(evt) {
  557.  
  558. if(!$.gm_lp_enable)return;
  559.  
  560. if ($.lpMouseActive == 2) {
  561. $.eventCancel(evt, false);
  562. }
  563. },
  564.  
  565. lpEnable: function() { // this is an optional feature for modern browser
  566. // the built-in browser feature has already disabled the default event behavior, the coding is just to ensure no "tailor-made behavior" occuring.
  567. document.addEventListener('keydown', $.lpKeyDown, {
  568. capture: true,
  569. passive: true
  570. })
  571. document.addEventListener('keyup', $.lpKeyUp, {
  572. capture: true,
  573. passive: true
  574. })
  575. document.addEventListener('mousedown', $.lpMouseDown, {
  576. capture: true,
  577. passive: true
  578. })
  579. document.addEventListener('mouseup', $.lpMouseUp, {
  580. capture: true,
  581. passive: true
  582. })
  583. document.addEventListener('click', $.lpClick, {
  584. capture: true,
  585. passive: true
  586. })
  587. },
  588.  
  589. rootHTML: (node) => {
  590.  
  591. if (!node || !(node.nodeType > 0)) return null;
  592. if (!node.ownerDocument) return node;
  593. let rootNode = node.getRootNode ? node.getRootNode() : null
  594. if (!rootNode) {
  595. let pElm = node;
  596. while (pElm) {
  597.  
  598. if (pElm.parentNode) pElm = pElm.parentNode;
  599. else break;
  600.  
  601. }
  602. rootNode = pElm;
  603. }
  604.  
  605.  
  606. rootNode = rootNode.querySelector('html') || node.ownerDocument.documentElement || null;
  607. return rootNode
  608.  
  609. },
  610.  
  611. mainEnableScript: () => {
  612. var cssStyleOnReady = `
  613. html, html *,
  614. html *::before, html *::after,
  615. html *:hover, html *:link, html *:visited, html *:active,
  616. html *[style], html *[class]{
  617. -khtml-user-select: auto !important; -moz-user-select: auto !important; -ms-user-select: auto !important;
  618. -webkit-touch-callout: default !important; -webkit-user-select: auto !important; user-select: auto !important;
  619. }
  620. *:hover>img[src]{pointer-events:auto !important;}
  621.  
  622. [${$.utSelectionColorHack}] :not(input):not(textarea)::selection{ background-color: Highlight !important; color: HighlightText !important;}
  623. [${$.utSelectionColorHack}] :not(input):not(textarea)::-moz-selection{ background-color: Highlight !important; color: HighlightText !important;}
  624. [${$.utTapHighlight}] *{ -webkit-tap-highlight-color: rgba(0, 0, 0, 0.18) !important;}
  625.  
  626. [${$.utHoverTextWrap}]>[${$.utNonEmptyElmPrevElm}]{pointer-events:none !important;}
  627. [${$.utHoverTextWrap}]>*{z-index:inherit !important;}
  628.  
  629. html[${$.utLpSelection}] *:hover, html[${$.utLpSelection}] *:hover * { cursor:text !important;}
  630. html[${$.utLpSelection}] :not(input):not(textarea)::selection {background-color: rgba(255, 156, 179,0.5) !important;}
  631. html[${$.utLpSelection}] :not(input):not(textarea)::-moz-selection {background-color: rgba(255, 156, 179,0.5) !important;}
  632.  
  633. img[${$.utHoverBlock}="4"]{display:none !important;}
  634. [${$.utHoverBlock}="7"]{padding:0 !important;overflow:hidden !important;}
  635. [${$.utHoverBlock}="7"]>img[${$.utHoverBlock}="4"]:first-child{
  636. display:inline-block !important;
  637. position: relative !important;
  638. top: auto !important;
  639. left: auto !important;
  640. bottom: auto !important;
  641. right: auto !important;
  642. opacity: 0 !important;
  643. padding: 0 !important;
  644. margin: 0 !important;
  645. width: 100% !important;
  646. height: 100% !important;
  647. outline: 0 !important;
  648. border: 0 !important;
  649. box-sizing: border-box !important;
  650. transform: initial !important;
  651. user-select:none !important;
  652. z-index:1 !important;
  653. float: left !important;
  654. cursor:inherit !important;
  655. pointer-events:inherit !important;
  656. border-radius: inherit !important;
  657. background:none !important;
  658. }
  659.  
  660. `.trim();
  661.  
  662. $.enableSelectClickCopy()
  663. $.createCSSElement(cssStyleOnReady, document.documentElement);
  664.  
  665. },
  666.  
  667. mainEvents: (listenerPress, listenerRelease) => {
  668. document.addEventListener("mousedown", listenerPress, true); // Capture Event; (desktop)
  669. document.addEventListener("contextmenu", listenerPress, true); // Capture Event; (desktop&mobile)
  670. document.addEventListener("mouseup", listenerRelease, false); // Bubble Event;
  671. },
  672.  
  673. disableHoverBlock: () => {
  674.  
  675. var nMap = new WeakMap()
  676.  
  677. function elmParam(elm) {
  678.  
  679. var mElm = nMap.get(elm);
  680. if (!mElm) nMap.set(elm, mElm = {});
  681. return mElm;
  682. }
  683.  
  684. function overlapArea(rect1, rect2) {
  685.  
  686. let l1 = {
  687. x: rect1.left,
  688. y: rect1.top
  689. }
  690.  
  691. let r1 = {
  692. x: rect1.right,
  693. y: rect1.bottom
  694. }
  695. let l2 = {
  696. x: rect2.left,
  697. y: rect2.top
  698. }
  699.  
  700. let r2 = {
  701. x: rect2.right,
  702. y: rect2.bottom
  703. }
  704.  
  705. // Area of 1st Rectangle
  706. let area1 = Math.abs(l1.x - r1.x) * Math.abs(l1.y - r1.y);
  707.  
  708. // Area of 2nd Rectangle
  709. let area2 = Math.abs(l2.x - r2.x) * Math.abs(l2.y - r2.y);
  710.  
  711. // Length of intersecting part i.e
  712. // start from max(l1.x, l2.x) of
  713. // x-coordinate and end at min(r1.x,
  714. // r2.x) x-coordinate by subtracting
  715. // start from end we get required
  716. // lengths
  717. let x_dist = Math.min(r1.x, r2.x) - Math.max(l1.x, l2.x);
  718. let y_dist = Math.min(r1.y, r2.y) - Math.max(l1.y, l2.y);
  719. let areaI = 0;
  720. if (x_dist > 0 && y_dist > 0) {
  721. areaI = x_dist * y_dist;
  722. }
  723.  
  724. return {
  725. area1,
  726. area2,
  727. areaI
  728. };
  729.  
  730.  
  731. }
  732.  
  733. function redirectEvent(event, toElement) {
  734.  
  735. toElement.dispatchEvent(new event.constructor(event.type, event));
  736. if (event.type != 'wheel') event.preventDefault();
  737. event.stopPropagation();
  738. }
  739.  
  740. const floatingBlockHover = new WeakMap();
  741.  
  742. let _nImgs = [];
  743.  
  744.  
  745. function nImgFunc() {
  746.  
  747. for (const s of _nImgs) {
  748. if (s.lastTime + 800 < +new Date) {
  749. s.lastTime = +new Date;
  750. return s.elm
  751. }
  752. }
  753.  
  754. let nImg = document.createElement('img');
  755. nImg.setAttribute('title', ' ');
  756. nImg.setAttribute('alt', ' ');
  757. nImg.onerror = function() {
  758. if (this.parentNode != null) this.parentNode.removeChild(this)
  759. }
  760. nImg.setAttribute($.utHoverBlock, '4');
  761. const handle = function(event) {
  762. if (this === event.target) {
  763. if (event.button != 2) redirectEvent(event, this.parentNode)
  764. Promise.resolve().then(() => {
  765. for (const s of _nImgs) {
  766. if (s.elm === this) {
  767. s.lastTime = +new Date
  768. }
  769. }
  770. })
  771. }
  772. }
  773. nImg.addEventListener('click', handle, true);
  774. nImg.addEventListener('mousedown', handle, true);
  775. nImg.addEventListener('mouseup', handle, true);
  776. nImg.addEventListener('mousemove', handle, true);
  777. nImg.addEventListener('mouseover', handle, true);
  778. nImg.addEventListener('mouseout', handle, true);
  779. nImg.addEventListener('mouseenter', handle, true);
  780. nImg.addEventListener('mouseleave', handle, true);
  781. //nImg.addEventListener('wheel', handle, $.eh_capture_passive());
  782. let resObj = {
  783. elm: nImg,
  784. lastTime: +new Date,
  785. cid_fade: 0
  786. }
  787. _nImgs.push(resObj)
  788.  
  789. return nImg;
  790.  
  791. }
  792.  
  793. const wmHoverUrl = new WeakMap();
  794. let lastMouseEnterElm = null;
  795. let lastMouseEnterAt = 0;
  796. let lastMouseEnterCid = 0;
  797.  
  798. function mouseEnter() {
  799. lastMouseEnterCid = 0;
  800.  
  801. if (+new Date - lastMouseEnterAt < 30) {
  802. lastMouseEnterCid = setTimeout(mouseEnter, 82)
  803. return;
  804. }
  805.  
  806. //if($.lpKeyPressing)return;
  807.  
  808. const targetElm = lastMouseEnterElm
  809.  
  810. Promise.resolve()
  811. .then(() => {
  812. if (targetElm && targetElm.parentNode) {} else {
  813. return;
  814. }
  815. if (floatingBlockHover.get(targetElm)) {
  816. let url = null
  817. if (targetElm.getAttribute($.utHoverBlock) == '7' && (url = wmHoverUrl.get(targetElm)) && targetElm.querySelector(`[${$.utHoverBlock}]`) == null) {
  818. let _nImg = nImgFunc();
  819. if (_nImg.parentNode !== targetElm) {
  820. _nImg.setAttribute('src', url);
  821. targetElm.insertBefore(_nImg, targetElm.firstChild);
  822. }
  823. }
  824. return;
  825. }
  826. floatingBlockHover.set(targetElm, 1);
  827. return 1;
  828. }).then((ayRes) => {
  829. if (!ayRes) return;
  830.  
  831. if (targetElm.nodeType != 1) return;
  832. if ("|SVG|IMG|HTML|BODY|VIDEO|AUDIO|BR|HEAD|NOSCRIPT|SCRIPT|STYLE|TEXTAREA|AREA|INPUT|FORM|BUTTON|".indexOf(`|${targetElm.nodeName}|`) >= 0) return;
  833.  
  834. const targetArea = targetElm.clientWidth * targetElm.clientHeight
  835.  
  836. if (targetArea > 0) {} else {
  837. return;
  838. }
  839.  
  840. const targetCSS = getComputedStyle(targetElm)
  841. const targetBgImage = targetCSS.getPropertyValue('background-image');
  842. let exec1 = null
  843.  
  844. if (targetBgImage != 'none' && (exec1 = /^\s*url\s*\("?([^"\)]+\b(\.gif|\.png|\.jpeg|\.jpg|\.webp)\b[^"\)]*)"?\)\s*$/i.exec(targetBgImage))) {
  845. if ((targetElm.textContent || "").trim().length > 0) return;
  846. const url = exec1[1];
  847. return url
  848.  
  849. // console.log(targetBgImage,[...exec1])
  850. }
  851.  
  852.  
  853.  
  854. if (targetCSS.getPropertyValue('position') == 'absolute' && +targetCSS.getPropertyValue('z-index') > 0) {} else {
  855. return;
  856. }
  857. if ((targetElm.textContent || "").trim().length > 0) return;
  858.  
  859. let possibleResults = [];
  860.  
  861. for (const imgElm of document.querySelectorAll('img[src]')) {
  862. const param = elmParam(imgElm)
  863. if (!param.area) {
  864. const area = imgElm.clientWidth * imgElm.clientHeight
  865. if (area > 0) param.area = area;
  866. }
  867. if (param.area > 0) {
  868. if (targetArea > param.area * 0.9) possibleResults.push(imgElm)
  869. }
  870. }
  871.  
  872. let i = 0;
  873. let j = 0;
  874. for (const imgElm of possibleResults) {
  875.  
  876. const cmpVal = targetElm.compareDocumentPosition(imgElm)
  877.  
  878. /*
  879.  
  880.  
  881. 1: The two nodes do not belong to the same document.
  882. 2: p1 is positioned after p2.
  883. 4: p1 is positioned before p2.
  884. 8: p1 is positioned inside p2.
  885. 16: p2 is positioned inside p1.
  886. 32: The two nodes has no relationship, or they are two attributes on the same element.
  887.  
  888. */
  889.  
  890. if (cmpVal & 8 || cmpVal & 16) return;
  891. if (cmpVal & 2) j++; // I<p
  892. else if (cmpVal & 4) break; // I>p
  893.  
  894.  
  895. i++;
  896.  
  897. }
  898.  
  899. // before: j-1 after: j
  900.  
  901. let indexBefore = j - 1;
  902. let indexAfter = j;
  903. if (indexBefore < 0) indexBefore = 0;
  904. if (indexAfter > possibleResults.length - 1) indexAfter = possibleResults.length - 1;
  905.  
  906. // setTimeout(function(){
  907. for (let i = indexBefore; i <= indexAfter; i++) {
  908. const s = possibleResults[i];
  909. const {
  910. area1,
  911. area2,
  912. areaI
  913. } = overlapArea(targetElm.getBoundingClientRect(), s.getBoundingClientRect())
  914. const criteria = area1 * 0.7
  915. if (areaI > 0.9 * area2) {
  916.  
  917.  
  918. return s.getAttribute('src')
  919.  
  920.  
  921. }
  922. }
  923. // },1000);
  924.  
  925. }).then((sUrl) => {
  926.  
  927. if (typeof sUrl != 'string') return;
  928.  
  929. //console.log(targetElm, targetElm.querySelectorAll('img').length)
  930.  
  931. // console.log(313, evt.target, s)
  932. let _nImg = nImgFunc();
  933.  
  934.  
  935. if (_nImg.parentNode !== targetElm) {
  936. _nImg.setAttribute('src', sUrl);
  937. targetElm.insertBefore(_nImg, targetElm.firstChild);
  938. wmHoverUrl.set(targetElm, sUrl);
  939. targetElm.setAttribute($.utHoverBlock, '7');
  940. }
  941.  
  942.  
  943.  
  944. })
  945.  
  946. }
  947.  
  948. document.addEventListener('mouseenter', function(evt) {
  949. if(!$.gm_disablehover_enable) return;
  950. lastMouseEnterElm = evt.target
  951. lastMouseEnterAt = +new Date;
  952. if (!lastMouseEnterCid) lastMouseEnterCid = setTimeout(mouseEnter, 82)
  953. }, $.eh_capture_passive())
  954.  
  955.  
  956.  
  957. },
  958.  
  959. acrAuxDown: function(evt) {
  960.  
  961. if(!$.gm_prevent_aux_click_enable) return;
  962.  
  963. if (evt.button === 1 ){
  964. let check = $.dmmMouseUpLast > $.dmmMouseDownLast && evt.timeStamp - $.dmmMouseUpLast < 40
  965. $.dmmMouseDownLast = evt.timeStamp;
  966. if( check ) {
  967. $.eventCancel(evt, true);
  968. }
  969. }
  970.  
  971. },
  972.  
  973. acrAuxUp: function(evt) {
  974. if(!$.gm_prevent_aux_click_enable) return;
  975.  
  976. if (evt.button === 1 ){
  977. let check = $.dmmMouseDownLast > $.dmmMouseUpLast && evt.timeStamp - $.dmmMouseDownLast < 40;
  978. $.dmmMouseUpLast = evt.timeStamp;
  979. if( check ) {
  980. $.dmmMouseUpCancel = evt.timeStamp;
  981. $.eventCancel(evt, true);
  982. }
  983. }
  984.  
  985. },
  986.  
  987.  
  988. acrAuxClick: function(evt) {
  989. if(!$.gm_prevent_aux_click_enable) return;
  990.  
  991. if (evt.button === 1 ){
  992. if( evt.timeStamp - $.dmmMouseUpCancel < 40 ) {
  993. $.eventCancel(evt, true);
  994. }
  995. }
  996.  
  997.  
  998. },
  999.  
  1000. preventAuxClickRepeat:function(){
  1001.  
  1002. document.addEventListener('mousedown', $.acrAuxDown, {
  1003. capture: true,
  1004. passive: false
  1005. })
  1006. document.addEventListener('mouseup', $.acrAuxUp, {
  1007. capture: true,
  1008. passive: false
  1009. })
  1010. document.addEventListener('auxclick', $.acrAuxClick, {
  1011. capture: true,
  1012. passive: false
  1013. })
  1014.  
  1015.  
  1016. },
  1017.  
  1018. MenuEnable: (
  1019. class MenuEnable{
  1020.  
  1021. constructor(textToEnable, textToDisable, callback, initalEnable){
  1022. this.textToEnable=textToEnable;
  1023. this.textToDisable=textToDisable;
  1024. this.callback=callback;
  1025. this.gx=this.gx.bind(this);
  1026. }
  1027.  
  1028. unregister(){
  1029. (this.h>=0)?(GM_unregisterMenuCommand(this.h), (this.h=0)):0;
  1030. }
  1031.  
  1032. register(text){
  1033. if(typeof text == 'string') this.showText = text;
  1034. text = this.showText;
  1035. if(typeof text != 'string') return;
  1036. this.h=GM_registerMenuCommand(text, this.gx);
  1037. }
  1038.  
  1039. a(o){
  1040.  
  1041. if(this.enabled===o.bEnable) return;
  1042. this.enabled = o.bEnable;
  1043. this.unregister();
  1044.  
  1045.  
  1046. let pr= 0 ;
  1047.  
  1048. if($.gm_status_fn_store && $.gm_status_fn_store.indexOf(this)>=0){
  1049.  
  1050. let store = $.gm_status_fn_store
  1051. let idx = store.indexOf(this)
  1052. let count = store.length;
  1053.  
  1054.  
  1055. if(idx>=0&&idx<=count-2){
  1056.  
  1057. console.log(idx, count)
  1058.  
  1059. for(let jdx=idx+1;jdx<count;jdx++){
  1060.  
  1061. store[jdx].unregister();
  1062. }
  1063.  
  1064. this.register (o.bText);
  1065.  
  1066. for(let jdx=idx+1;jdx<count;jdx++){
  1067.  
  1068. store[jdx].register();
  1069. }
  1070.  
  1071. pr=1;
  1072.  
  1073. }
  1074.  
  1075.  
  1076. }
  1077.  
  1078. if(!pr) this.register (o.bText);
  1079.  
  1080. this.callback(this.enabled, o.byUserInput);
  1081.  
  1082.  
  1083. }
  1084.  
  1085. enableNow(byUserInput){
  1086. this.a({
  1087. bEnable: true,
  1088. bText: this.textToDisable,
  1089. byUserInput
  1090. });
  1091.  
  1092. }
  1093.  
  1094. gx(){
  1095. if(this.enabled) this.disableNow(true);
  1096. else this.enableNow(true);
  1097.  
  1098. }
  1099.  
  1100. disableNow(byUserInput){
  1101. this.a({
  1102. bEnable: false,
  1103. bText: this.textToEnable,
  1104. byUserInput
  1105. });
  1106.  
  1107. }
  1108.  
  1109. toggle(enable, byUserInput){
  1110. enable?this.enableNow(byUserInput):this.disableNow(byUserInput);
  1111. }
  1112.  
  1113. }
  1114. ),
  1115.  
  1116. gm_status_fn: function(gm_name, textToEnable, textToDisable, callback){
  1117.  
  1118. let menuEnableName = gm_name + "$menuEnable";
  1119.  
  1120. function set_gm(enabled){
  1121. $[gm_name]=enabled;
  1122. let menuEnable = $[menuEnableName];
  1123. if( menuEnable ){
  1124. menuEnable.toggle(enabled)
  1125. };
  1126. callback(enabled)
  1127. }
  1128.  
  1129. set_gm(!!GM_getValue(gm_name));
  1130.  
  1131. GM_addValueChangeListener(gm_name,function(name, old_value, new_value, remote){
  1132.  
  1133. if(old_value === new_value) return;
  1134. if(new_value === $[gm_name]) return;
  1135. set_gm(new_value);
  1136.  
  1137. });
  1138.  
  1139. if(!inIframe()){
  1140.  
  1141. $.gm_status_fn_store=$.gm_status_fn_store||[];
  1142.  
  1143. $[menuEnableName]=new $.MenuEnable(textToEnable, textToDisable, (enabled) => {
  1144. GM_setValue(gm_name, !!enabled);
  1145. });
  1146.  
  1147. $.gm_status_fn_store.push($[menuEnableName]);
  1148.  
  1149. $[menuEnableName].toggle(!!GM_getValue(gm_name));
  1150.  
  1151. }
  1152.  
  1153.  
  1154.  
  1155. }
  1156.  
  1157. }
  1158.  
  1159. // $.holdingElm=null;
  1160.  
  1161. $.mainEnableScript();
  1162.  
  1163. if (isSupportAdvancedEventListener()) $.lpEnable(); // top capture event for alt-click
  1164.  
  1165. $.mainEvents(
  1166. function(evt) {
  1167. // $.holdingElm=evt.target;
  1168. // console.log('down',evt.target)
  1169. if ($.onceCssHighlightSelection) window.requestAnimationFrame($.onceCssHighlightSelection);
  1170. if (evt.button == 2 || evt.type == "contextmenu") $.mAlert_DOWN();
  1171. },
  1172. function(evt) {
  1173. // $.holdingElm=null;
  1174. // console.log('up',evt.target)
  1175. if (evt.button == 2) $.mAlert_UP();
  1176. if ($.enableDragging) {
  1177. $.enableDragging = false;
  1178. }
  1179. }
  1180. );
  1181.  
  1182. $.disableHoverBlock();
  1183. $.preventAuxClickRepeat();
  1184.  
  1185. console.log('userscript running - To Re-Enable Selection & Copying');
  1186.  
  1187.  
  1188. $.gm_status_fn("gm_lp_enable", "To Enable `Enhanced build-in Alt Text Selection`", "To Disable `Enhanced build-in Alt Text Selection`", ()=>{
  1189. // callback
  1190. });
  1191. $.gm_status_fn("gm_disablehover_enable", "To Enable `Hover on Image`", "To Disable `Hover on Image`", ()=>{
  1192. // callback
  1193. });
  1194. $.gm_status_fn("gm_prevent_aux_click_enable", "To Enable `Repetitive AuxClick Prevention`", "To Disable `Repetitive AuxClick Prevention`", ()=>{
  1195. // callback
  1196. });
  1197.  
  1198.  
  1199.  
  1200.  
  1201. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址