Create a gist now

Instantly share code, notes, and snippets.

// ==UserScript==
// @name Tfocus
// @namespace http://efcl.info/
// @include http://*
// @include https://*
// @require https://github.com/hatena/extract-content-javascript/raw/master/lib/extract-content-all.js
// ==/UserScript==
(function(_doc) {
// DEBUG ON/OFF
var DEBUG = true;
var SHORTCUT_KEY = "S-b"
// ショートカットの設定関数
// http://d.hatena.ne.jp/jimo1001/20090601/1243782686 を改変
function ShortcutKey(win) {
this.list = [];
this.init(win || window);
}
ShortcutKey.prototype.keys = {
8: 'BS',
9: 'TAB',
10: 'Enter',
13: 'Enter',
32: 'SPC',
27: 'ESC',
33: 'PageUp',
34: 'PageDown',
35: 'End',
36: 'Home',
37: 'Left',
38: 'Up',
39: 'Right',
40: 'Down',
45: 'Insert',
46: 'Delete',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12'
}
ShortcutKey.prototype.skeys = {
8: 'BS',
10: 'Enter',
13: 'Enter',
32: 'SPC'
}
ShortcutKey.prototype.mkeys = {
'altKey' : 'A',
'ctrlKey' : 'C',
'metaKey' : 'M',
'shiftKey' : 'S'
}
ShortcutKey.prototype.init = function(win) {
var self = this;
win.addEventListener('keydown', function(evt) {
var key = self.get(evt);
var inputReg = /^(?:input|textarea)$/;
self.list.forEach(function(a) {
if (a.key == key && (a.element == evt.target || a.element == evt.view) && !inputReg.test(evt.target.nodeName.toLowerCase())) {
a.func();
}
});
}, false);
}
ShortcutKey.prototype.add = function(elm, key, func) {
this.list.push(
{
'element' : elm,
'key' : key,
'func' : func
});
}
ShortcutKey.prototype.get = function(evt) {
var key = [], k = '';
for (mk in this.mkeys) {
if (evt[mk])
key.push(this.mkeys[mk]);
}
if (evt.which) {
k = this.keys[evt.which] || String.fromCharCode(evt.which).toLowerCase();
key.push(key.length ? '-' + k : k);
} else if (evt.keyCode) {
k = this.keys[evt.keyCode];
key.push(key.length ? '-' + k : k);
}
return key.join("");
}
// フレームパネルの作成
function makeFrame(callback/*(iframeTag, window, document)*/, name) {
function testInvasion() {
iframe.removeEventListener("load", done, true);
var message = ((new Date) - load.start) + "ms passed, ";
try { // probe for security violation error, in case mozilla struck a bug
var url = unsafeWindow.frames[framename].location.href;
message += url == "about:blank" ? "but we got the right document." : "and we incorrectly loaded " + url;
done();
}
catch(e) {
document.body.removeChild(iframe);
makeFrame(callback, name);
}
}
function done() {
clearTimeout(load.timeout);
var win = iframe.contentWindow
var doc = iframe.contentWindow.document;
// 自分自身のiframeを閉じるボタン
var xImg = document.createElement("img");
xImg.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAATElEQVQoka2RSQ4AIAgD+f+jp96M0aq49AgdUiB0qZCkONQ/EBAwDOrrU7A1uZqN2hodtNwRqNdz0VOg62+jzuDUcVzkf+/I6h28UQHjW25Gob5AIAAAAABJRU5ErkJggg=="
xImg.setAttribute("onclick", "document.getElementsByName(" + esframeName + ")[0].style.display='none';");
xImg.setAttribute("style", "background-color:red;border:3px;position:fixed;top:0px;right:0px;z-index:9999;");
doc.body.appendChild(xImg);
callback(iframe, win, doc);
}
var iframe = document.createElement("iframe");
var framename = iframe.name = typeof name != "undefined" ? name : ("pane" + (makeFrame.id = (makeFrame.id || 0) - 1));
iframe.setAttribute("style", "overflow:auto;z-index:1001; border:0; margin:0; padding:0;top:0; bottom:0; left:0;");
iframe.src = "about:blank";
iframe.addEventListener("load", done, true);
var frames = makeFrame.data || {};
var load = frames[framename] || {
start: new Date,
sleepFor: 400
};
load.timeout = setTimeout(testInvasion, load.sleepFor);
load.sleepFor *= 1.5;
frames[framename] = load;
makeFrame.data = frames;
// 苦し紛れのエスケープ
var esframeName = "'" + framename + "'";
document.body.appendChild(iframe);
}
// CSS装飾
var readPanel = {
iframe : null,
doc : null,
getCss: function() {
return String(<>
<![CDATA[
#tFocus{
margin-left:auto!important;
margin-right:auto!important;
background-color:#FFFFE0;
color:#222222;
line-height:24px;
font-size:16px!important;
padding:1.2em 1.5em 1.5em!important;
left:auto;
width:40em!important;
overflow:auto;
position:relative;
z-index:999;
}
]]></>);
},
create: function(ele) {
makeFrame(function(iframe, win, doc) {
readPanel.iframe = iframe;
readPanel.doc = doc;
readPanel.isShow = true;
iframe.width = iframe.height = "100%";
iframe.style.width = "100%";
iframe.style.position = "fixed";
readPanel.hideListen(win);
ele.setAttribute("id", 'tFocus');
readPanel.addCSS(doc, readPanel.getCss());
doc.body.appendChild(ele);
doc.body.focus();
}, "tFocus");
},
hideListen : function(win) {
win.addEventListener("keypress", function(e) {
var esc = (e.keyCode == 27);
if (esc) {
readPanel.toggle();
}
}, true);
var shortcut_iframe = new ShortcutKey(win);
shortcut_iframe.add(win, SHORTCUT_KEY, function(evt) {
readPanel.toggle();
});
},
show:function () {
readPanel.isShow = true;
readPanel.iframe.style.display = "block";
readPanel.doc.body.focus();
},
hide:function () {
readPanel.isShow = false;
readPanel.iframe.style.display = "none";
document.body.focus();
},
toggle :function(ele) {
if (readPanel.iframe) {
if (readPanel.isShow) {
this.hide();
} else {
this.show();
}
}
},
addCSS : function(context, css) {
if (!context) context = document;
if (context.createStyleSheet) { // for IE
var sheet = context.createStyleSheet();
sheet.cssText = css;
return sheet;
} else {
var sheet = context.createElement('style');
sheet.type = 'text/css';
var _root = context.getElementsByTagName('head')[0] || context.documentElement;
sheet.textContent = css;
return _root.appendChild(sheet).sheet;
}
}
}
/**
* Document構造分析
*/
var main = function() {
this.init.apply(this, arguments);
}
main.prototype.init = function(doc) {
this.document = this.extractDocument(doc);
this.mainNode;
if (this.document) {
this.isDocument = true;
this.mainNode = this.document.content.asNode().cloneNode(true);
} else {
this.isDocument = false;
}
}
// Documentの構造分析
main.prototype.extractDocument = function(doc) {
if (!this.document) {
var ex = new ExtractContentJS.LayeredExtractor();
ex.addHandler(ex.factory.getHandler('Heuristics'));
var res = ex.extract(doc);
if (res) {
return res;
} else {
return false;
}
} else {
return this.document;
}
}
// nodeを同じ大きさの空白ノードと置き換える。
main.prototype.replaceNode = function(node) {
var div = document.createElement("div");
div.id = "dummy_node";
div.style.width = this.mainNode.clientWidth;
div.style.height = this.mainNode.clientHeight;
this.mainNode.parentNode.replaceChild(div, this.mainNode);
}
// ショートカットの定義
var shortcut = new ShortcutKey();
shortcut.add(window, SHORTCUT_KEY, function(evt) {
if (readPanel.iframe) {
readPanel.toggle();
} else {
var res = new main(document);
if (res.isDocument) {
readPanel.create(res.mainNode);
}
}
});
// DEBUG - true
function log(m) {
if (typeof DEBUG != 'undefined' && DEBUG) {
if (unsafeWindow.console) {
unsafeWindow.console.log.apply(this, arguments);
} else {
console.log.apply(this, arguments);
}
}
}
})(document);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment