リンクテキスト中の文字列を選択するGreasemonkey Script

最近開発の関係上アンカーテキスト中の文字列を選択する必要が増えてきました.
ところが,Firefoxではアンカーテキスト中の文字列を選択するには,

  • Altキーを押しながら選択
  • キャレットブラウズモード

の2種類しか(僕の知る限り)方法が無く,
ただ単にリンク中の文字列を選択するだけなのですが,これが意外とストレスのたまる作業だったりします.

そのためのGreasemonkeyスクリプトを探してみたのですが,
あまりこれだというscriptが無いようなので作成してみました.

インストール
anchor text selector (userscrits.org)

インストールすると,こんな文字列がこんな感じに選択できるようになります.

ソース
ざっと作成したので不具合等ありましたらコメントお願いいたします.
初めてのグリモンなのでソースはかなり汚いと思います….

// ==UserScript==
// @name           anchor text selector
// @namespace      http://rerank.jp
// @author         Takehiro Yamamoto <tyamamot at dl.kuis.kyoto-u.ac.jp>
// @description    This script enables user to select some text from a link 
// @include        *
// ==/UserScript==

(function(){

X = 0;
Y = 0;

//thresholds
offsetX = 5;
offsetY = 3;
function removeAnchor(anchor){
	if (anchor && anchor.tagName && anchor.tagName.toLowerCase() == "a"
				&& anchor.getAttribute('href')) {
		anchorNode = anchor;
		anchorHref = anchor.getAttribute('href');
		anchor.removeAttribute('href');
		anchorNode.addEventListener("mousemove",onAnchorMove,true);
		anchorNode.addEventListener("click",onAnchorClick,true);
	}		
}

function restoreAnchor(){
	if(anchorNode){
		anchorNode.setAttribute("href",anchorHref);
		anchorNode.removeEventListener('mousemove',onAnchorMove,true);
		anchorNode = null;
		anchorHref = null;
	}
}

function onMouseDown(event){
	if(event.which != 1) return;
	var sel = window.getSelection().toString();
	if(sel && sel.length > 0){
		return;
	}
	var element = event.target;
	var anchor = getAnchorNode(element,0);
	if(anchor){
		removeAnchor(anchor)
	}
	X = event.screenX;
	Y = event.screenY;
}

function onAnchorMove(event){
	if(event.which != 1) return;
	restoreAnchor();
}

function onAnchorClick(event){
	if(event.which != 1) return;
	var sel = window.getSelection().toString();
	restoreAnchor();
	if(sel && sel.length > 0){
		moveX = Math.abs(event.screenX - X);
		moveY = Math.abs(event.screenY - Y);
		if(moveX > offsetX || moveY > offsetY){
			event.target.removeEventListener('click',onAnchorClick,true);
			event.preventDefault();
		}
	}
}

function getAnchorNode(element,depth){
	if (depth > 5) return null;
	if(element && element.tagName && element.tagName.toLowerCase() == "a"){
		return element;
	}
	if(element.parentNode){
		return getAnchorNode(element.parentNode,depth + 1);
	}
	else{
		return null;
	}
}


window.addEventListener('load', function(event){
	document.body.addEventListener('mousedown',onMouseDown,true);
},true);
}());

2009年7月25日追記:
より精度良く動作するようにコードを修正