Skip to content

Instantly share code, notes, and snippets.

@mzp
Created November 21, 2008 03:51
Show Gist options
  • Save mzp/27341 to your computer and use it in GitHub Desktop.
Save mzp/27341 to your computer and use it in GitHub Desktop.
CrossFire for GM
// ==UserScript==
// @name opera focus imitation
// @namespace
// @description this script imitate focus on opera by shift + cursor key
// @include *
// ==/UserScript==
// 問題:位置取得の効率が悪すぎる
// 要素が重なっていると隣の要素として判定ができない
// iframe 内には入れない、または出れない
window.addEventListener('load',function(){
var border_width = 4;
//for Greasemonkey
var KeyEvent = {
DOM_VK_SHIFT: 16,
DOM_VK_CONTROL: 17,
DOM_VK_ALT: 18,
DOM_VK_LEFT: 37,
DOM_VK_UP: 38,
DOM_VK_RIGHT: 39,
DOM_VK_DOWN: 40
};
var selectedObj=null; //現在選択されている要素
var selected=false; //現在要素が選択(強調)されているかどうか
var aObjs=[]; //aObjの配列
var oDiv;//強調時の囲い
var Direction = {
LEFT:0,
UP:1,
RIGHT:2,
DOWN:3
};
//window.innnerWidth 表示領域の幅
//window.innnerHeight 表示領域の高さ
//document.body.scrollWidth ドキュメント全体の幅
//document.body.scrollHeight ドキュメント全体の高さ
//window.pageXOffset 現在の横スクロール量
//window.pageYOffset 現在の縦スクロール量
function aObj(aElm){
this.elm=aElm;
//elm.offsetWidth エレメントの幅
//elm.offsetHeight エレメントの高さ
this.x=0;//body上のx位置
this.y=0;//body上のy位置
this.getPosition();//x,yに現在位置取得
//GM_log(this.elm.tagName+this.x+this.y+this.isInWindow());
//this.em=false;//強調しているかどうか
//getPositionX()表示領域内のx位置
//getPositionY()表示領域内のy位置
//isInWindow()表示領域内にあるかどうか(bool)
//emphasis()強調表示
//this.elm.onblur = onBlurHandler_aObj;
}
function getPositionX_aObj(){
return this.x-window.pageXOffset;
}
aObj.prototype.getPositionX = getPositionX_aObj;
function getPositionY_aObj(){
return this.y-window.pageYOffset;
}
aObj.prototype.getPositionY = getPositionY_aObj;
function isInWindow_aObj(){
//var ix = this.getPositionX();
//var iy = this.getPositionY();
this.getPosition();
if( this.y > window.pageYOffset + window.innerHeight
|| this.y + this.elm.offsetHeight < window.pageYOffset
|| this.x > window.pageXOffset + window.innerWidth
|| this.x + this.elm.offsetWidth < window.pageXOffset
)
return false;
else
return true;
}
aObj.prototype.isInWindow = isInWindow_aObj;
function emphasis_aObj(){
if(!oDiv){
oDiv = document.createElement('div');
oDiv.style.border= border_width + "px solid royalblue";
oDiv.style.position="absolute";
oDiv.style.zIndex="65535";
document.body.appendChild(oDiv);
}
//GM_log(this+this.elm.offsetWidth);
oDiv.style.display="block";
oDiv.style.width=(this.elm.offsetWidth+8)+"px";
oDiv.style.height=(this.elm.offsetHeight+8)+"px";
oDiv.style.top=this.y-4-border_width + "px";
oDiv.style.left=this.x-4-border_width +"px";
this.elm.focus();
//this.em=true;
//this.elm.onblur = onBlurHandler_aObj;
}
aObj.prototype.emphasis = emphasis_aObj;
function noemphasis_aObj(){
//this.elm.blur();
//this.em=false;
}
aObj.prototype.noemphasis = noemphasis_aObj;
function onBlurHandler_aObj(){
if(oDiv)oDiv.style.display="none";
selected = false;
}
//onresize 位置情報の再取得
//body上の位置情報の取得関数
function getPosition_aObj(){
var elmtmp=this.elm;
this.x=0;
this.y=0;
while(elmtmp){
this.x+=elmtmp.offsetLeft;
this.y+=elmtmp.offsetTop;
elmtmp=elmtmp.offsetParent;
}
}
aObj.prototype.getPosition = getPosition_aObj;
/******************************************************************/
//関数の省略
function getById(str){
return document.getElementById(str);
}
function xpath(query) {
var results = document.evaluate(query, document, null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var nodes = new Array();
for(var i=0; i<results.snapshotLength; i++){
nodes.push(results.snapshotItem(i));
}
return nodes;
}
//すべてのリンクをaObjにする
function makeAObjs(){
//var alinks= document.getElementsByTagName("a");
var alinks = xpath("//a[@href]");
//GM_log("alength="+alinks.snapshotLength);
for(var i=0;i<alinks.length;i++){
aObjs[i]=new aObj(alinks[i]);
}
selectedObj=aObjs[0];
selectedObj.elm.addEventListener("blur", onBlurHandler_aObj, true);
GM_log("main end"+selectedObj);
//GM_log(document.body.scrollWidth+" "+document.body.scrollWidth*document.body.scrollWidth);
//GM_log(document.body.scrollHeight+" "+document.body.scrollHeight*document.body.scrollHeight);
//GM_log(document.body.scrollWidth*document.body.scrollWidth+document.body.scrollHeight*document.body.scrollHeight);
}
//表示領域上の一番上(左)のオブジェクトを返す
//上下左右に対応させたい
function findFirstElm(){
var objpre=null;
var xpre=document.body.scrollHeight;
var ypre=document.body.scrollWidth;
//GM_log("in findFirstElm " + aObj);
for(var i=0;i<aObjs.length;i++){
aObjs[i].getPosition();
if(aObjs[i].isInWindow()&&checkVisible(aObjs[i])){
if( (ypre>aObjs[i].y)
|| ((ypre==aObjs[i].y)&&(xpre>aObjs[i].x)) ){
objpre=aObjs[i];
xpre=aObjs[i].x;
ypre=aObjs[i].y;
}
}
}
//GM_log("out findFirstElm");
return objpre;
}
function move(direction){
var i;
var nextObj;
//var moveFunc=[moveup,moveright,movedown,moveleft];
var moveOffset=[];
moveOffset[Direction.UP]=[0,-50];
moveOffset[Direction.RIGHT]=[50,0];
moveOffset[Direction.DOWN]=[0,50];
moveOffset[Direction.LEFT]=[-50,0];
if(selectedObj.isInWindow()){
//GM_log(selected);
if(selected==true){
//次のオブジェクトへ
//nextObj=moveFunc[sw]();
nextObj=nearestObj(selectedObj,aObjs,direction);
if(nextObj==null){
//スクロール
window.scrollBy(moveOffset[direction][0],moveOffset[direction][1]);
}else{
selectedObj.elm.removeEventListener("blur", onBlurHandler_aObj, true);
selectedObj.noemphasis();
selectedObj=nextObj;
selectedObj.elm.addEventListener("blur", onBlurHandler_aObj, true);
selectedObj.emphasis();
}
}else{
//selectedObjを強調
selectedObj.emphasis();
selected=true;
}
}else{
//一番上(左)のオブジェクトを探す
nextObj=findFirstElm();
if(nextObj==null){
//スクロールさせる
window.scrollBy(moveOffset[direction][0],moveOffset[direction][1]);
}else{
//selectedObjを強調
selectedObj.elm.removeEventListener("blur", onBlurHandler_aObj, true);
selectedObj.noemphasis();
selectedObj=nextObj;
selectedObj.elm.addEventListener("blur", onBlurHandler_aObj, true);
selectedObj.emphasis();
selected=true;
}
}
}
//objが可視かどうか
//可視ならばtrue、不可視ならばfalseを返す
function checkVisible(obj){
elm=obj.elm;
while(elm.tagName!='HTML'){
var style = document.defaultView.getComputedStyle(elm,'');
//GM_log(elm.tagName+" "+elm.innerHTML+" "+style.display+" "+style.visibility);
if(style.display == "none"||style.visibility == "hidden"){
return false;
}
elm=elm.parentNode;
}
return true;
}
//objAがobjBより左にあれば、その距離を正の値で返す
//objAとobjBがX座標で重なっていれば、0を返す
//objAがobjBより右にあれば、その距離を負の値で返す
function checkPositionX(objA,objB){
if(objA.x<objB.x){
if(objA.x+objA.elm.offsetWidth<objB.x){
return objB.x-(objA.x+objA.elm.offsetWidth);
}
}else{
if(objB.x+objB.elm.offsetWidth<objA.x){
return (objB.x+objB.elm.offsetWidth)-objA.x;
}
}
return 0;
}
//objAがobjBより上にあれば、その距離を正の値で返す
//objAとobjBがY座標で重なっていれば、0を返す
//objAがobjBより下にあれば、その距離を負の値で返す
function checkPositionY(objA,objB){
if(objA.y<objB.y){
if(objA.y+objA.elm.offsetHeight<objB.y){
return objB.y-(objA.y+objA.elm.offsetHeight);
}
}else{
if(objB.y+objB.elm.offsetHeight<objA.y){
return (objB.y+objB.elm.offsetHeight)-objA.y;
}
}
return 0;
}
//Aからみて、Bがdirectionの方向にあるとき、その距離(x+y)を返す
//方向が違うとき-1を返す
function checkDistance(objA,objB,direction){
var x=checkPositionX(objA,objB);
var y=checkPositionY(objA,objB);
if((direction==Direction.LEFT && x<0 && Math.abs(x)>Math.abs(y))
||(direction==Direction.UP && y<0 && Math.abs(y)>Math.abs(x))
||(direction==Direction.RIGHT && x>Math.abs(y))
||(direction==Direction.DOWN && y>Math.abs(x))
){
return Math.abs(x)+Math.abs(y);
}else{
return -1;
}
}
//objからみてdirectionの方向にある一番近いオブジェクトをobjlist[]の中から選んで返す
//direction方向に一つもなければnullを返す
function nearestObj(obj,objlist,direction){
var retobjdis = document.body.scrollWidth+document.body.scrollHeight;
var retobj = null;
var distmp = 0;
for(var i=0;i<objlist.length;i++){
distmp=checkDistance(obj,objlist[i],direction);
//GM_log(distmp+" "+retobjdis);
if(objlist[i].isInWindow()&&distmp>=0&&retobjdis>distmp&&checkVisible(objlist[i])){
retobjdis = distmp;
retobj = objlist[i];
}
}
//GM_log(obj.elm.innerHTML+" - "+retobjdis);
return retobj;
}
/******************************************************************/
/******************************************************************/
function onResizeHandler(){
GM_log("resize");
for(var i=0;i<aObjs.length;i++){
aObjs[i].getPosition();
}
}
function onKeyDownHandler(ev){
switch (ev.keyCode){
case KeyEvent.DOM_VK_UP:
//GM_log("updown "+ev.keyCode);
if(ev.shiftKey){
move(Direction.UP);
ev.preventDefault();
}
break;
case KeyEvent.DOM_VK_RIGHT:
//GM_log("rightdown "+ev.keyCode);
if(ev.shiftKey){
move(Direction.RIGHT);
ev.preventDefault();
}
break;
case KeyEvent.DOM_VK_DOWN:
if(ev.shiftKey){
move(Direction.DOWN);
ev.preventDefault();
}
break;
case KeyEvent.DOM_VK_LEFT:
if(ev.shiftKey){
move(Direction.LEFT);
ev.preventDefault();
}
break;
default:
break;
}
}
//window.addEventListener('load',onLoadHandler,true);
//document.addEventListener('keyup',onKeyHandler['up'],true);
document.addEventListener('keydown',onKeyDownHandler,true);
window.addEventListener('resize',onResizeHandler,true);
//window.onload=onLoadHandler;
//document.onkeyup = onKeyUpHandler;
//document.onkeydown = onKeyDownHandler;
makeAObjs();
},true);// ==UserScript==
// @name opera focus imitation
// @namespace
// @description this script imitate focus on opera by shift + cursor key
// @include *
// ==/UserScript==
// 問題:位置取得の効率が悪すぎる
// 要素が重なっていると隣の要素として判定ができない
// iframe 内には入れない、または出れない
window.addEventListener('load',function(){
var border_width = 4;
//for Greasemonkey
var KeyEvent = {
DOM_VK_SHIFT: 16,
DOM_VK_CONTROL: 17,
DOM_VK_ALT: 18,
DOM_VK_LEFT: 37,
DOM_VK_UP: 38,
DOM_VK_RIGHT: 39,
DOM_VK_DOWN: 40
};
var selectedObj=null; //現在選択されている要素
var selected=false; //現在要素が選択(強調)されているかどうか
var aObjs=[]; //aObjの配列
var oDiv;//強調時の囲い
var Direction = {
LEFT:0,
UP:1,
RIGHT:2,
DOWN:3
};
//window.innnerWidth 表示領域の幅
//window.innnerHeight 表示領域の高さ
//document.body.scrollWidth ドキュメント全体の幅
//document.body.scrollHeight ドキュメント全体の高さ
//window.pageXOffset 現在の横スクロール量
//window.pageYOffset 現在の縦スクロール量
function aObj(aElm){
this.elm=aElm;
//elm.offsetWidth エレメントの幅
//elm.offsetHeight エレメントの高さ
this.x=0;//body上のx位置
this.y=0;//body上のy位置
this.getPosition();//x,yに現在位置取得
//GM_log(this.elm.tagName+this.x+this.y+this.isInWindow());
//this.em=false;//強調しているかどうか
//getPositionX()表示領域内のx位置
//getPositionY()表示領域内のy位置
//isInWindow()表示領域内にあるかどうか(bool)
//emphasis()強調表示
//this.elm.onblur = onBlurHandler_aObj;
}
function getPositionX_aObj(){
return this.x-window.pageXOffset;
}
aObj.prototype.getPositionX = getPositionX_aObj;
function getPositionY_aObj(){
return this.y-window.pageYOffset;
}
aObj.prototype.getPositionY = getPositionY_aObj;
function isInWindow_aObj(){
//var ix = this.getPositionX();
//var iy = this.getPositionY();
this.getPosition();
if( this.y > window.pageYOffset + window.innerHeight
|| this.y + this.elm.offsetHeight < window.pageYOffset
|| this.x > window.pageXOffset + window.innerWidth
|| this.x + this.elm.offsetWidth < window.pageXOffset
)
return false;
else
return true;
}
aObj.prototype.isInWindow = isInWindow_aObj;
function emphasis_aObj(){
if(!oDiv){
oDiv = document.createElement('div');
oDiv.style.border= border_width + "px solid royalblue";
oDiv.style.position="absolute";
oDiv.style.zIndex="65535";
document.body.appendChild(oDiv);
}
//GM_log(this+this.elm.offsetWidth);
oDiv.style.display="block";
oDiv.style.width=(this.elm.offsetWidth+8)+"px";
oDiv.style.height=(this.elm.offsetHeight+8)+"px";
oDiv.style.top=this.y-4-border_width + "px";
oDiv.style.left=this.x-4-border_width +"px";
this.elm.focus();
//this.em=true;
//this.elm.onblur = onBlurHandler_aObj;
}
aObj.prototype.emphasis = emphasis_aObj;
function noemphasis_aObj(){
//this.elm.blur();
//this.em=false;
}
aObj.prototype.noemphasis = noemphasis_aObj;
function onBlurHandler_aObj(){
if(oDiv)oDiv.style.display="none";
selected = false;
}
//onresize 位置情報の再取得
//body上の位置情報の取得関数
function getPosition_aObj(){
var elmtmp=this.elm;
this.x=0;
this.y=0;
while(elmtmp){
this.x+=elmtmp.offsetLeft;
this.y+=elmtmp.offsetTop;
elmtmp=elmtmp.offsetParent;
}
}
aObj.prototype.getPosition = getPosition_aObj;
/******************************************************************/
//関数の省略
function getById(str){
return document.getElementById(str);
}
function xpath(query) {
var results = document.evaluate(query, document, null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var nodes = new Array();
for(var i=0; i<results.snapshotLength; i++){
nodes.push(results.snapshotItem(i));
}
return nodes;
}
//すべてのリンクをaObjにする
function makeAObjs(){
//var alinks= document.getElementsByTagName("a");
var alinks = xpath("//a[@href]");
//GM_log("alength="+alinks.snapshotLength);
for(var i=0;i<alinks.length;i++){
aObjs[i]=new aObj(alinks[i]);
}
selectedObj=aObjs[0];
selectedObj.elm.addEventListener("blur", onBlurHandler_aObj, true);
GM_log("main end"+selectedObj);
//GM_log(document.body.scrollWidth+" "+document.body.scrollWidth*document.body.scrollWidth);
//GM_log(document.body.scrollHeight+" "+document.body.scrollHeight*document.body.scrollHeight);
//GM_log(document.body.scrollWidth*document.body.scrollWidth+document.body.scrollHeight*document.body.scrollHeight);
}
//表示領域上の一番上(左)のオブジェクトを返す
//上下左右に対応させたい
function findFirstElm(){
var objpre=null;
var xpre=document.body.scrollHeight;
var ypre=document.body.scrollWidth;
//GM_log("in findFirstElm " + aObj);
for(var i=0;i<aObjs.length;i++){
aObjs[i].getPosition();
if(aObjs[i].isInWindow()&&checkVisible(aObjs[i])){
if( (ypre>aObjs[i].y)
|| ((ypre==aObjs[i].y)&&(xpre>aObjs[i].x)) ){
objpre=aObjs[i];
xpre=aObjs[i].x;
ypre=aObjs[i].y;
}
}
}
//GM_log("out findFirstElm");
return objpre;
}
function move(direction){
var i;
var nextObj;
//var moveFunc=[moveup,moveright,movedown,moveleft];
var moveOffset=[];
moveOffset[Direction.UP]=[0,-50];
moveOffset[Direction.RIGHT]=[50,0];
moveOffset[Direction.DOWN]=[0,50];
moveOffset[Direction.LEFT]=[-50,0];
if(selectedObj.isInWindow()){
//GM_log(selected);
if(selected==true){
//次のオブジェクトへ
//nextObj=moveFunc[sw]();
nextObj=nearestObj(selectedObj,aObjs,direction);
if(nextObj==null){
//スクロール
window.scrollBy(moveOffset[direction][0],moveOffset[direction][1]);
}else{
selectedObj.elm.removeEventListener("blur", onBlurHandler_aObj, true);
selectedObj.noemphasis();
selectedObj=nextObj;
selectedObj.elm.addEventListener("blur", onBlurHandler_aObj, true);
selectedObj.emphasis();
}
}else{
//selectedObjを強調
selectedObj.emphasis();
selected=true;
}
}else{
//一番上(左)のオブジェクトを探す
nextObj=findFirstElm();
if(nextObj==null){
//スクロールさせる
window.scrollBy(moveOffset[direction][0],moveOffset[direction][1]);
}else{
//selectedObjを強調
selectedObj.elm.removeEventListener("blur", onBlurHandler_aObj, true);
selectedObj.noemphasis();
selectedObj=nextObj;
selectedObj.elm.addEventListener("blur", onBlurHandler_aObj, true);
selectedObj.emphasis();
selected=true;
}
}
}
//objが可視かどうか
//可視ならばtrue、不可視ならばfalseを返す
function checkVisible(obj){
elm=obj.elm;
while(elm.tagName!='HTML'){
var style = document.defaultView.getComputedStyle(elm,'');
//GM_log(elm.tagName+" "+elm.innerHTML+" "+style.display+" "+style.visibility);
if(style.display == "none"||style.visibility == "hidden"){
return false;
}
elm=elm.parentNode;
}
return true;
}
//objAがobjBより左にあれば、その距離を正の値で返す
//objAとobjBがX座標で重なっていれば、0を返す
//objAがobjBより右にあれば、その距離を負の値で返す
function checkPositionX(objA,objB){
if(objA.x<objB.x){
if(objA.x+objA.elm.offsetWidth<objB.x){
return objB.x-(objA.x+objA.elm.offsetWidth);
}
}else{
if(objB.x+objB.elm.offsetWidth<objA.x){
return (objB.x+objB.elm.offsetWidth)-objA.x;
}
}
return 0;
}
//objAがobjBより上にあれば、その距離を正の値で返す
//objAとobjBがY座標で重なっていれば、0を返す
//objAがobjBより下にあれば、その距離を負の値で返す
function checkPositionY(objA,objB){
if(objA.y<objB.y){
if(objA.y+objA.elm.offsetHeight<objB.y){
return objB.y-(objA.y+objA.elm.offsetHeight);
}
}else{
if(objB.y+objB.elm.offsetHeight<objA.y){
return (objB.y+objB.elm.offsetHeight)-objA.y;
}
}
return 0;
}
//Aからみて、Bがdirectionの方向にあるとき、その距離(x+y)を返す
//方向が違うとき-1を返す
function checkDistance(objA,objB,direction){
var x=checkPositionX(objA,objB);
var y=checkPositionY(objA,objB);
if((direction==Direction.LEFT && x<0 && Math.abs(x)>Math.abs(y))
||(direction==Direction.UP && y<0 && Math.abs(y)>Math.abs(x))
||(direction==Direction.RIGHT && x>Math.abs(y))
||(direction==Direction.DOWN && y>Math.abs(x))
){
return Math.abs(x)+Math.abs(y);
}else{
return -1;
}
}
//objからみてdirectionの方向にある一番近いオブジェクトをobjlist[]の中から選んで返す
//direction方向に一つもなければnullを返す
function nearestObj(obj,objlist,direction){
var retobjdis = document.body.scrollWidth+document.body.scrollHeight;
var retobj = null;
var distmp = 0;
for(var i=0;i<objlist.length;i++){
distmp=checkDistance(obj,objlist[i],direction);
//GM_log(distmp+" "+retobjdis);
if(objlist[i].isInWindow()&&distmp>=0&&retobjdis>distmp&&checkVisible(objlist[i])){
retobjdis = distmp;
retobj = objlist[i];
}
}
//GM_log(obj.elm.innerHTML+" - "+retobjdis);
return retobj;
}
/******************************************************************/
/******************************************************************/
function onResizeHandler(){
GM_log("resize");
for(var i=0;i<aObjs.length;i++){
aObjs[i].getPosition();
}
}
function onKeyDownHandler(ev){
switch (ev.keyCode){
case KeyEvent.DOM_VK_UP:
//GM_log("updown "+ev.keyCode);
if(ev.shiftKey){
move(Direction.UP);
ev.preventDefault();
}
break;
case KeyEvent.DOM_VK_RIGHT:
//GM_log("rightdown "+ev.keyCode);
if(ev.shiftKey){
move(Direction.RIGHT);
ev.preventDefault();
}
break;
case KeyEvent.DOM_VK_DOWN:
if(ev.shiftKey){
move(Direction.DOWN);
ev.preventDefault();
}
break;
case KeyEvent.DOM_VK_LEFT:
if(ev.shiftKey){
move(Direction.LEFT);
ev.preventDefault();
}
break;
default:
break;
}
}
//window.addEventListener('load',onLoadHandler,true);
//document.addEventListener('keyup',onKeyHandler['up'],true);
document.addEventListener('keydown',onKeyDownHandler,true);
window.addEventListener('resize',onResizeHandler,true);
//window.onload=onLoadHandler;
//document.onkeyup = onKeyUpHandler;
//document.onkeydown = onKeyDownHandler;
makeAObjs();
},true);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment