sgur
10/30/2013 - 6:29 PM

LinkDragSelectionForChrome.user.js

// ==UserScript==
// @name           LinkDragSelectionForChrome
// @description    Opera like link selection for chrome.
// @namespace      http://d.hatena.ne.jp/Griever/
// @author         Griever
// @license        MIT License
// @match          http://*/*
// @match          https://*/*
// @version        0.0.1
// ==/UserScript==

function LinkDragSelection(){
	this.init.apply(this, arguments);
}
LinkDragSelection.prototype = {
	moved_flag: false,
	init: function(event) {
		this.range = document.caretRangeFromPoint(event.pageX - scrollX, event.pageY - scrollY);
		var sel = getSelection();
		if (!sel.isCollapsed && sel.getRangeAt(0).isPointInRange(this.range.startContainer, this.range.startOffset))
			return;
		this.screenX = event.screenX;
		this.screenY = event.screenY;
		addEventListener("mousemove", this, false);
		addEventListener("mouseup", this, false);
	},
	uninit: function() {
		removeEventListener("mousemove", this, false);
		removeEventListener("mouseup", this, false);
		removeEventListener("dragstart", this, false);
		setTimeout(function() {
			removeEventListener("click", this, false);
		}.bind(this), 100);
	},
	handleEvent: function(event) {
		switch(event.type){
			case "mousemove":
				if (this.moved_flag) {
					var range = document.caretRangeFromPoint(event.pageX - scrollX, event.pageY - scrollY);
					if (range)
						getSelection().extend(range.startContainer, range.startOffset);
				} else {
					this.moveX = event.screenX;
					this.moveY = event.screenY;
					this.checkXY();
				}
				break;
			case "mouseup":
				this.uninit();
				break;
			case "dragstart":
				event.currentTarget.removeEventListener(event.type, this, false);
				if (this.moved_flag) {
					event.preventDefault();
					event.stopPropagation();
				} else {
					this.checkXY();
				}
				break;
			case "click":
				event.currentTarget.removeEventListener(event.type, this, false);
				if (!getSelection().isCollapsed) {
					event.preventDefault();
					event.stopPropagation();
				}
				break;
		}
	},
	selectionStart: function() {
		this.moved_flag = true;
		getSelection().collapse(this.range.startContainer, this.range.startOffset);
		addEventListener("dragstart", this, false);
		addEventListener("click", this, false);
	},
	checkXY: function() {
		var x = Math.abs(this.screenX - this.moveX);
		var y = Math.abs(this.screenY - this.moveY);
		if (x >= 5 && x > y) {
			this.selectionStart();
		} else if (y >= 5) {
			this.uninit();
		}
	},
};

addEventListener("mousedown", function(event) {
	if (event.button != 0 || event.ctrlKey || event.altKey || event.shiftKey) return;
	if (!event.target.webkitMatchesSelector('a[href], a[href] *')) return;
	new LinkDragSelection(event);
}, false);