Skip to content

Instantly share code, notes, and snippets.

@Griever
Created May 7, 2012 12:53
Show Gist options
  • Save Griever/2627603 to your computer and use it in GitHub Desktop.
Save Griever/2627603 to your computer and use it in GitHub Desktop.
LDRize like JK scroll.
思いつきで作った LDRize みたいに "J","K" でスクロールできるスクリプト。
とりあえず Firefox 専用。
// ==UserScript==
// @name JK Walker
// @description LDRize like JK scroll.
// @namespace http://d.hatena.ne.jp/Griever/
// @license MIT License
// @compatibility Firefox 12
// @version 0.0.1
// @include http://**
// @include https://*
// @exclude http://reader.livedoor.com/*
// @exclude http://fastladder.com/*
// @exclude http://www.google.co.jp/reader/*
// @exclude https://www.google.co.jp/reader/*
// @exclude http://translate.google.*
// @exclude http://maps.google.*
// @exclude http://twitter.com/*
// @exclude https://twitter.com/*
// @exclude http://b.hatena.ne.jp/*
// ==/UserScript==
var SITEINFO = [
{ url: '^https?://www\\.google\\.[^/]+/.'
,target: 'h3, #pnnext, a[href^="/imgres?"], .autopagerize_link'
}
,{ url: '^https?://realtime\\.search\\.yahoo\\.[^/]+/.'
,target: 'div.cnt, a#btn_TSp_1',
}
,{ url: '^https?://blog\\.search\\.yahoo\\.[^/]+/.'
,target: 'h2, span.m:last-child',
}
,{ url: '^https?://[\\w.]+\\.yahoo\\.[^/]+/.'
,target: 'h3, span.m:last-child, a[target="imagewin"], div.item'
}
,{ url: '^https?://mobile\\.twitter\\.com'
,target: '[id^="tweet_"]'
}
,{ url: '^https?://github\\.com/'
,target: 'td.content > a'
}
,{ url: '^https?://www\\.youtube\\.com/'
,target: 'h2, .browse-item, .result-item, .yt-uix-pager-next'
}
,{ url: '^http://seiga\\.nicovideo\\.jp/'
,target: '.illust_list_img, .illust_area ~ * a[rel="next"] '
}
,{ url: '^http://live\\.nicovideo\\.jp/'
,target: '.detail, a[rel="next"]'
}
,{ url: '^http://\\w+\\.nicovideo\\.jp/'
,target: 'div[class^="thumb_col_"], a[href^="/mylist/"], .illust_list_img'
}
];
var MICROFORMAT = {
target: 'h2, h3, h4, h5, h6, section, dt, .autopagerize_link',
through: ''
};
function JKWalkerClass(win, info) {
this.win = win;
this.doc = win.document;
this._target = info.target || MICROFORMAT.target;
this._through = info.through || MICROFORMAT.through;
this.addStyle();
this.treeWalker = this.doc.createTreeWalker(this.doc, 1, this.filter.bind(this), false); // NodeFilter.SHOW_ELEMENT
this.doc.addEventListener('keypress', this, false);
}
JKWalkerClass.prototype = {
_input : 'textarea, input[type="text"], input:not([type]), input[type="password"], input[type="search"]',
filter: function(node) {
if (node.mozMatchesSelector(this._target) &&
(!this._through || !node.mozMatchesSelector(this._through)) &&
node.offsetHeight)
return 1;// NodeFilter.FILTER_ACCEPT
return 3;// NodeFilter.FILTER_SKIP;
},
handleEvent: function(event) {
switch(event.type) {
case 'keypress':
if (event.ctrlKey || event.shiftKey || event.altKey) return;
if (event.target.mozMatchesSelector(this._input)) return;
if (event.charCode === 106) {//j
this.find(false);
} else if (event.charCode === 107) {//k
this.find(true);
} else if (event.charCode === 111) {//o
var anchor = this.doc.activeElement;
if (this.lastFocusedNode != anchor) return;
if (!anchor.href || /^javascript|^mailto/i.test(anchor.href)) return;
GM_openInTab(anchor.href);
} else {
return;
}
event.preventDefault();
event.stopPropagation();
break;
}
},
find: function(isPrev) {
// 最後にクリックした位置を探す
var sel = this.win.getSelection();
if (sel.focusNode) {
this.treeWalker.currentNode = isPrev ? sel.anchorNode : sel.focusNode;
}
var node;
if (isPrev) {
node = this.treeWalker.previousNode();
if (!node) {
this.treeWalker.currentNode = this.doc.body.lastChild;
node = this.treeWalker.previousNode();
}
} else {
node = this.treeWalker.nextNode();
if (!node) {
this.treeWalker.currentNode = this.doc.body;
node = this.treeWalker.nextNode();
}
}
if (!node) return;
this.treeWalker.currentNode = node;
this.scrollTo(node);
this.focusAndHighlight(node);
sel.collapse(node, 0);
},
scrollTo: function(node, isPrev) {
var rect = node.getBoundingClientRect();
var t = parseInt(rect.top - (Math.max(this.win.innerHeight - rect.height, 0)) / 2, 10);
var l = parseInt(rect.left - (Math.max(this.win.innerWidth - rect.width, 0)) / 2, 10);
this.win.scrollBy(l, t);
},
focusAndHighlight: function(node) {
var anchor = this.doc.evaluate('descendant-or-self::a[@href]|ancestor-or-self::a[@href]',
node, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (anchor && !/^mailto/.test(anchor.href)) {
anchor.focus();
this.lastFocusedNode = anchor;
}
node.setAttribute("jkwalker_focus", "true");
this.win.setTimeout(function() {
node.removeAttribute('jkwalker_focus');
}, 400);
},
addStyle: function() {
this.style = this.doc.createElement('style');
this.style.type = 'text/css';
this.style.appendChild(this.doc.createTextNode(<![CDATA[
[jkwalker_focus] {
outline: 3px solid magenta !important;
outline-offset: -2px !important;
}
[jkwalker_focus] :focus {
outline: 2px dotted red !important;
outline-offset: -1px !important;
}
]]>.toString()));
(this.doc.head || this.doc.documentElement).appendChild(this.style);
},
};
function launch() {
var url = document.URL;
var isLaunched = SITEINFO.some(function(info){
try {
if (new RegExp(info.url).test(url)) {
window.jk = new JKWalkerClass(window, info);
return true;
}
} catch (e) {
GM_log('error at ' + info.url + '\n' + e);
}
});
if (!isLaunched)
window.jk = new JKWalkerClass(window, MICROFORMAT);
}
launch();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment