Select like opera

Select texts insider links, support firefox and chrome

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

You will need to install an extension such as Tampermonkey to install this script.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name					Select like opera
// @author					lkytal
// @namespace				Lkytal
// @homepage				https://lkytal.github.io/
// @homepageURL				https://lkytal.github.io/GM
// @icon					https://github.com/lkytal/GM/raw/master/icons/def.ico
// @version					1.2.2
// @description				Select texts insider links, support firefox and chrome
// @license					AGPL
// @include					*
// @grant					unsafeWindow
// @grant					GM_getValue
// @grant					GM_setValue
// @run-at					document-end
// @charset					UTF-8
// @supportURL				https://github.com/lkytal/GM/issues
// ==/UserScript==

var selectLikeOpera = function () {
	var findHTMLAnchor = function (node) {
		if (node.nodeType === 3) node = node.parentNode;
		do {
			if (node.constructor === HTMLAnchorElement) return node;
		} while ((node = node.parentNode) && node !== document.body);
		return null;
	};

	var preventEvent = function (e) {
		e.preventDefault();
		e.stopPropagation();
		return false;
	};

	var rangeOperator = (function () {
		var notFirefox = navigator.userAgent.indexOf("Firefox") == -1;

		return {
			createRange: function (x, y) {
				if (notFirefox) {
					return document.caretRangeFromPoint(x, y);
				}
				else {
					var range = document.createRange();
					var position = document.caretPositionFromPoint(x, y);
					range.setStart(position.offsetNode, position.offset);
					return range;
				}
			},
			rangeAttr: (notFirefox ? '-webkit-user-select' : '-moz-user-select')
		}
	})();

	var setStyle = (function () {
		var styleList = [
			{
				p: rangeOperator.rangeAttr,
				v: 'text'
			},
			{
				p: 'outline-width',
				v: 0
			}
		];

		var node;
		var s;
		return function (_node) {
			if (_node) {
				node = _node, s = [];
				for (var i = styleList.length - 1; i >= 0; i -= 1) {
					s.push([node.style.getPropertyValue(styleList[i].p), node.style.getPropertyPriority(styleList[i].p)]);
					node.style.setProperty(styleList[i].p, styleList[i].v, 'important');
				}
			}
			else if (node) {
				for (var i = styleList.length; i-- > 0;) {
					node.style.removeProperty(styleList[i].p);
					if (s[i][0] !== null) node.style.setProperty(styleList[i].p, s[i][0], s[i][1]);
				}
				node = s = null;
			}
		}
	})();

	var toggleEvent = function (events, bAdd) {
		if (bAdd === undefined) bAdd = true;
		if (events.constructor !== Array) events = [events];

		for (var i = 0, len = events.length; i < len; i += 1) {
			if (bAdd) {
				document.addEventListener(events[i], eventList[events[i]], true);
			}
			else {
				document.removeEventListener(events[i], eventList[events[i]], true);
			}
		}
	};

	var removeEvent = function (a) {
		toggleEvent(a, false);
	};

	var position, q, u, v, z, resetState = function () {
		q = v = true;
		u = z = false;
	};

	var nodeInfo, selection = document.getSelection();

	let selectEvent = function (e) {
		if (e.which < 2) {
			resetState();
			var x = e.clientX,
				y = e.clientY;
			if (selection.rangeCount > 0) {
				var selectedRange = selection.getRangeAt(0);
				if (!selectedRange.collapsed) {
					var newRange = rangeOperator.createRange(x, y);
					if (newRange && selectedRange.isPointInRange(newRange.startContainer, newRange.startOffset)) return;
				}
			}
			setStyle();
			var target = e.target;
			var node = findHTMLAnchor(target);
			if (!node) node = target.nodeType !== 3 ? target : target.parentNode;
			if (node.constructor === HTMLCanvasElement || node.textContent === '') return;
			var range = node.getBoundingClientRect();
			nodeInfo = {
				n: node,
				x: Math.round(range.left),
				y: Math.round(range.top),
				c: 0
			};
			position = {
				x: x,
				y: y
			};
			toggleEvent(['mousemove', 'mouseup', 'dragend', 'dragstart']);
			setStyle(node);
		}
	};

	var D = 3, K = 0.8;
	var eventList = {
		'mousemove': function (e) {
			if (nodeInfo) {
				if (nodeInfo.c++ < 12) {
					var rect = nodeInfo.n.getBoundingClientRect();
					if (Math.round(rect.left) !== nodeInfo.x || Math.round(rect.top) !== nodeInfo.y) {
						removeEvent(['mousemove', 'mouseup', 'dragend', 'dragstart', 'click']);
						setStyle();
						selection.removeAllRanges();
						return;
					}
				}
				else {
					nodeInfo = null;
				}
			}
			var x = e.clientX,
				y = e.clientY;
			if (v) {
				selection.removeAllRanges();
				var offset = x > position.x ? -2 : 2;
				var newRange = rangeOperator.createRange(x + offset, y);
				if (newRange) {
					selection.addRange(newRange);
					v = false;
				}
			}
			if (q) {
				var c = Math.abs(position.x - x),
					d = Math.abs(position.y - y);
				u = d === 0 || c / d > K;
				if (c > D || d > D) {
					q = false;
					z = true;
					toggleEvent('click');
				}
			}
			if (u) {
				var newRange = rangeOperator.createRange(x, y);
				if (newRange) selection.extend(newRange.startContainer, newRange.startOffset);
			}
		},
		'dragstart': function (e) {
			removeEvent('dragstart');
			if (u) return preventEvent(e);
		},
		'mouseup': function (e) {
			removeEvent(['mousemove', 'mouseup', 'dragstart', 'dragend']);
			if (!u && z) z = false;
			setTimeout(function () {
				removeEvent('click');
			}, 25);
		},
		'dragend': function (e) {
			removeEvent(['dragend', 'mousemove', 'mouseup']);
		},
		'click': function (e) {
			removeEvent('click');
			if (z) return preventEvent(e);
		}
	};

	document.addEventListener('mousedown', selectEvent, true);
};

setTimeout(selectLikeOpera, 100);