您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enables select, right-click, copy and drag on pages that disable them. Additional Feature: Long Press Text Selection
当前为
- // ==UserScript==
- // @name A Universal Script to Re-Enable the Selection and Copying
- // @name:zh-TW A Universal Script to Re-Enable the Selection and Copying
- // @version 1.6.1
- // @description Enables select, right-click, copy and drag on pages that disable them. Additional Feature: Long Press Text Selection
- // @description:zh-TW 解除禁止復制、剪切、選擇文本、右鍵菜單的限制。破解鎖右鍵、文字複製、文字選取。額外功能:長按文字選取。
- // @include /^https?\:\/\//
- // @grant none
- // @run-at document-start
- // @namespace https://greasyfork.org/users/371179
- // ==/UserScript==
- 'use strict';
- (function $$($) {
- console.log('script at', location + " #1")
- if (document == null || !document.documentElement) return window.requestAnimationFrame($$); // this is tampermonkey bug?? not sure
- console.log('script at', location + " #2")
- function isSupportAdvancedEventListener() {
- if ('_b1750' in $) return $._b1750
- var prop = 0;
- document.createAttribute('z').addEventListener('', null, {
- get passive() {
- prop++;
- },
- get once() {
- prop++;
- }
- });
- return ($._b1750 = prop == 2);
- }
- var mKey = 'dqzadwpujtct';
- var _ksNonFalseFunc = '___nff_' + mKey + '___',
- _ksReturnValue = '___returnValue_' + mKey + '___';
- $ = {
- utSelectionColorHack: 'msmtwejkzrqa',
- utTapHighlight: 'xfcklblvkjsj',
- mAlert_DOWN: function() {}, //dummy function in case alert replacement is not valid
- mAlert_UP: function() {}, //dummy function in case alert replacement is not valid
- isAnySelection: function() {
- var sel = (window.getSelection || function() {})();
- return !sel ? null : (typeof sel.isCollapsed == 'boolean') ? !sel.isCollapsed : (sel.toString().length > 0);
- },
- createCSSElement: function(cssStyle, container) {
- var css = document.createElement('style'); //slope: DOM throughout
- css.type = 'text/css';
- css.innerHTML = cssStyle;
- if (container) container.appendChild(css);
- return css;
- },
- createFakeAlert: function(_alert) {
- if (typeof _alert != 'function') return null;
- function alert(msg) {
- setTimeout(() => (alert.__isDisabled__() ? console.log("alert msg disabled: ", msg) : _alert.apply(this, arguments)), 9);
- };
- alert.toString = () => "function alert() { [native code] }";
- return alert;
- },
- createFuncReplacer: function(originalFunc, pName, resFX) {
- resFX = function(ev) {
- var res = originalFunc.apply(this, arguments);
- if (!this || this[pName] != resFX) return res; // if this is null or undefined, or this.onXXX is not this function
- if (res === false) return; // return undefined when "return false;"
- originalFunc[_ksNonFalseFunc] = true;
- this[pName] = originalFunc; // restore original
- return res;
- }
- resFX.toString = () => originalFunc.toString();
- return resFX;
- },
- listenerDisableAll: function(evt) {
- var elmNode = evt.target;
- while (elmNode && elmNode.nodeType > 0) { //i.e. HTMLDocument or HTMLElement
- var pName = 'on' + evt.type
- var f = elmNode[pName];
- if (typeof f == 'function' && f[_ksNonFalseFunc] !== true) {
- var nf = $.createFuncReplacer(f, pName);
- nf[_ksNonFalseFunc] = true;
- elmNode[pName] = nf;
- }
- elmNode = elmNode.parentNode;
- }
- },
- onceCssHighlightSelection: () => {
- $.onceCssHighlightSelection = null
- 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
- var elm = !s.length ? document.body : s[s.length >> 1];
- var selectionStyle = window.getComputedStyle(elm, ':selection');
- if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(selectionStyle.backgroundColor)) document.documentElement.setAttribute($.utSelectionColorHack, "");
- var elmStyle = window.getComputedStyle(elm)
- if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(elmStyle.webkitTapHighlightColor)) document.documentElement.setAttribute($.utTapHighlight, "");
- },
- replacementSetData:function(_setData,evt) {
- evt.clipboardData[$.ksSetData] = _setData;
- function setData() {
- var res = _setData.apply(this, arguments);
- if (evt.clipboardData === this && this.setData === setData && evt.cancelable && evt.defaultPrevented === false) {
- evt.preventDefault();
- if (evt.defaultPrevented === true) {
- this.setData = _setData;
- delete this[$.ksSetData];
- }
- }
- return res;
- }
- setData.toString = () => _setData.toString();
- evt.clipboardData.setData = setData;
- },
- enableSelectClickCopy: function() {
- $.eyEvts = ['keydown', 'keyup', 'copy', 'contextmenu', 'select', 'selectstart', 'dragstart', 'beforecopy']; //slope: throughout
- function getClipText(evt) {
- var text;
- var clip = (evt.originalEvent || evt).clipboardData;
- if (clip) {
- text = clip.getData('text/plain') || clip.getData('text/html');
- } else {
- text = window.clipboardData.getData("text") || null;
- }
- return text;
- }
- function isDeactivePreventDefault(evt) {
- if ($.bypass) return false;
- var j = $.eyEvts.indexOf(evt.type);
- switch (j) {
- case -1:
- return false;
- case 0:
- case 1:
- return (evt.keyCode == 67 && (evt.ctrlKey || evt.metaKey) && !evt.altKey && !evt.shiftKey && $.isAnySelection() === true);
- case 2:
- var dataTypeString = ((evt.clipboardData || {}).types || [])[0];
- // see the richtext hack in https://www.cleancss.com/css-beautify/
- // see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/copy_event
- // see https://w3c.github.io/clipboard-apis/#widl-ClipboardEvent-clipboardData
- if (!dataTypeString) {
- $.ksSetData = 'rgqclrdllmhr'
- if (!evt.clipboardData[$.ksSetData] && evt.cancelable && evt.defaultPrevented === false) {
- $.replacementSetData(evt.clipboardData.setData,evt);
- }
- //no replacement data
- return true;
- } else if (window.getSelection().toString().trim()) {
- //there is replacement data and the selection is not empty
- console.log("copy event - clipboardData replacement is allowed and the selection is not empty", window.getSelection().toString().trim())
- return false;
- } else {
- //there is replacement data and the selection is empty
- return false;
- }
- default:
- return true;
- }
- }
- Event.prototype.preventDefault = (function(f) {
- return function preventDefault() {
- if (!isDeactivePreventDefault(this)) f.apply(this);
- }
- })(Event.prototype.preventDefault);
- Event.prototype.preventDefault.toString = () => "function preventDefault() { [native code] }"
- Object.defineProperty(Event.prototype, "returnValue", {
- get() {
- return _ksReturnValue in this ? this[_ksReturnValue] : true;
- },
- set(newValue) {
- if (!isDeactivePreventDefault(this) && newValue === false) this.preventDefault();
- this[_ksReturnValue] = newValue;
- },
- enumerable: true,
- configurable: true
- });
- for (var i = 2, eventsCount = $.eyEvts.length; i < eventsCount; i++) {
- document.addEventListener($.eyEvts[i], $.listenerDisableAll, true); // Capture Event; passive:false; expected occurrence COMPLETELY before Target Capture and Target Bubble
- }
- var _alert = window.alert; //slope: temporary
- if (typeof _alert == 'function') {
- var _mAlert = $.createFakeAlert(_alert);
- if (_mAlert) {
- var lastClickAt = 0;
- _mAlert.__isDisabled__ = () => lastClickAt + 50 > +new Date;
- $.mAlert_DOWN = () => (lastClickAt = +new Date);
- $.mAlert_UP = () => (lastClickAt = 0);
- window.alert = _mAlert
- }
- }
- },
- mainEnableScript: () => {
- var vv = 'gykqyzwufxpz';
- var cssStyleOnReady = `
- *, body *, div, span, body *::before, body *::after, *:hover, *:link, *:visited, *:active , *[style], *[class]{
- -khtml-user-select: auto !important; -moz-user-select: auto !important; -ms-user-select: auto !important;
- -webkit-touch-callout: default !important; -webkit-user-select: auto !important; user-select: auto !important;
- }
- a:hover, a:hover *{
- -khtml-user-select: text !important; -moz-user-select: text !important;-ms-user-select: text !important;
- -webkit-user-select: text !important; user-select: text !important;
- }
- html[${vv}] *:hover, html[${vv}] *:hover * { cursor:text !important;}
- html[${vv}] :not(input):not(textarea)::selection {background-color: rgba(255, 156, 179,0.5) !important;}
- html body *:hover>img[src]{pointer-events:auto;}
- [${$.utSelectionColorHack}] :not(input):not(textarea)::selection{ background-color: Highlight !important; color: HighlightText !important;}
- [${$.utSelectionColorHack}] :not(input):not(textarea)::-moz-selection{ background-color: Highlight !important; color: HighlightText !important;}
- [${$.utTapHighlight}] *{ -webkit-tap-highlight-color: rgba(0, 0, 0, 0.18) !important;}
- `.trim();
- $.enableSelectClickCopy()
- $.createCSSElement(cssStyleOnReady, document.documentElement);
- },
- mainEvents: (listenerPress, listenerRelease) => {
- (["mousedown", "click", "dblclick", "contextmenu"]).forEach(function(event) {
- document.addEventListener(event, listenerPress, true); // Capture Event; passive:false; ensure the occurrence of 1st capture event COMPLETELY before executing other listeners
- });
- document.addEventListener("mouseup", listenerRelease, false); // Bubble Event; passive: true/false; order for releasing is insignificant
- }
- }
- $.mainEnableScript();
- $.mainEvents(function(evt) {
- if ($.onceCssHighlightSelection) window.requestAnimationFrame($.onceCssHighlightSelection);
- if (evt.type != "contextmenu" && evt.which != 3) return;
- if ($.cid_mouseup > 0) $.cid_mouseup = clearTimeout($.cid_mouseup);
- $.mAlert_DOWN();
- },
- function(evt) {
- if (evt.which != 3) return;
- $.cid_mouseup = setTimeout($.mAlert_UP, 17);
- });
- console.log('userscript running - To Re-Enable Selection & Copying');
- if (isSupportAdvancedEventListener() && 'assign' in Object) {
- // this is optional feature for modern browser
- function checkPointer(targetElm) {
- if(targetElm && targetElm.nodeType==1 && targetElm.matches('*:hover')){
- var style = getComputedStyle(targetElm)
- if (style.cursor == 'pointer' && targetElm.textContent) return true;
- }
- return false;
- }
- var longPressForcedCopy = false;
- var selectionChange = null;
- var cid_timer = 0;
- Object.assign($, {
- lpTimerFunc:function() {
- cid_timer = 0;
- if (!($.isAnySelection() && selectionChange == null) && checkPointer($.lp_targetElm)) { // NOT pressing the selection area
- document.documentElement.setAttribute('gykqyzwufxpz', '');
- longPressForcedCopy = true;
- }
- },
- lpMouseDown: function(evt) {
- $.lp_targetElm=evt.target;
- selectionChange = null;
- longPressForcedCopy = false;
- //console.log('mousedown')
- cid_timer = setTimeout($.lpTimerFunc, 300)
- },
- lpMouseUp: function(evt) {
- //console.log('mouseup')
- if (cid_timer) cid_timer = clearTimeout(cid_timer)
- if (longPressForcedCopy) document.documentElement.removeAttribute('gykqyzwufxpz')
- if (longPressForcedCopy && selectionChange === true) {
- $.bypass = true;
- evt.preventDefault()
- evt.stopPropagation();
- evt.stopImmediatePropagation();
- $.bypass = false;
- }
- setTimeout(function() {
- longPressForcedCopy = false;
- selectionChange = null;
- }, 50);
- },
- lpClick: function(evt) {
- if (longPressForcedCopy && selectionChange === true) {
- $.bypass = true;
- evt.preventDefault()
- evt.stopPropagation();
- evt.stopImmediatePropagation();
- $.bypass = false;
- }
- longPressForcedCopy = false;
- selectionChange = null;
- },
- lpDragStart: function(evt) {
- //console.log('dragstart')
- if (cid_timer) cid_timer = clearTimeout(cid_timer)
- if (longPressForcedCopy && $.isAnySelection()) { //drag the selected text
- document.documentElement.removeAttribute('gykqyzwufxpz')
- longPressForcedCopy = false;
- } else if (longPressForcedCopy) {
- $.bypass = true;
- evt.preventDefault()
- evt.stopPropagation();
- evt.stopImmediatePropagation();
- $.bypass = false;
- }
- },
- lpDragEnd: function(evt) {
- //console.log('dragend')
- if (cid_timer) cid_timer = clearTimeout(cid_timer)
- if (longPressForcedCopy) document.documentElement.removeAttribute('gykqyzwufxpz')
- longPressForcedCopy = false;
- },
- lpSelectionChange: function(evt) {
- selectionChange = $.isAnySelection() //first selection change shall be to empty
- if (selectionChange === true) {
- cid_timer = clearTimeout(cid_timer)
- }
- }
- });
- document.addEventListener('mousedown', $.lpMouseDown, {
- capture: true,
- passive: true
- })
- document.addEventListener('mouseup', $.lpMouseUp, {
- capture: true,
- passive: false
- })
- document.addEventListener('click', $.lpClick, {
- capture: true,
- passive: false
- })
- document.addEventListener('dragstart', $.lpDragStart, {
- capture: true,
- passive: false
- })
- document.addEventListener('dragend', $.lpDragEnd, {
- capture: true,
- passive: true
- })
- document.addEventListener('selectionchange', $.lpSelectionChange, {
- passive: true
- })
- }
- })();