Created
April 2, 2009 10:44
-
-
Save satyr/89131 to your computer and use it in GitHub Desktop.
yet another Hit-a-Hint / use keyconfig for better performances
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
javascript:[{/* hit@hint for keyconfig/bookmarklet */ | |
keys: 'hjkluiopnm', | |
bind: { | |
ok: 'C_return', /*does default action, continuing hint-mode*/ | |
undo: 'back_space \\', | |
click: '; C_;', | |
click2: '@', | |
dblclick: ':', | |
mouseup: '[', mousedown: ']', | |
mouseover: ',', mouseout: '.', | |
}, | |
css: ''+ <><![CDATA[ | |
$ { | |
position:absolute; z-index:2147483647; | |
color:#000; background-color:#ef7; opacity:0.7; | |
font:bold 9pt/1 "Consolas",monospace; text-transform:uppercase; | |
margin:0; padding:0 1px; border:1px solid #aaa;} | |
$.hit {background-color:#fcf;} | |
]]></>, | |
/* css queries for specific URIs */ | |
query: { | |
'^': | |
'a[href], input, textarea, option, button', | |
'^http://\\w\\.hatena\\.ne\\.jp/': | |
'img.hatena-star-comment-button, img[title="Add Star"]', | |
'^https?://(?:www\\.google\\.com/reader/|mail\\.google\\.com/mail/)': | |
'.goog-button, .goog-menu-button, .lhn-button, .section-button, .link', | |
}, | |
/* each hint's offset from its associated element */ | |
offset: {x: -16, y: 0}, | |
/* base point of screen (set negative values to allow overflowed elements) */ | |
origin: {x: -6, y: -4}, | |
/* sign: {__noSuchMethod__: isNaN}, */ | |
}, | |
function HatH(window, {keys, bind, css, query, offset, origin, sign}){ | |
const StartTime = Date.now(), | |
{document} = window, | |
KeyEvent = document.createEvent('KeyEvents'), | |
K = (keys = keys.toUpperCase()).split(''), L = K.length, | |
ID = 'HatH'+ StartTime, | |
{x: OffsetX, y: OffsetY} = offset || {x: -8, y: -8}, | |
{x: OriginX, y: OriginY} = origin || {x: -4, y: -4}, | |
Query = qmix(query), | |
CSS = css.replace(/\$/g, '#'+ ID +'>*').replace(/;/g, ' !important;'), | |
Sign = { | |
__proto__: sign || { | |
run: function SRun(){ this._ = document.title }, | |
put: function SPut(msg){ document.title = msg }, | |
end: function SEnd(){ document.title = this._ }, | |
}, | |
show: function SPut(txt, lmn){ | |
var msg = '@'+ txt; | |
if(lmn){ | |
var name = lmn.nodeName.toLowerCase(); | |
msg += (' '+ ((name === 'INPUT' ? lmn.type.toLowerCase() : name) + | |
(lmn.id ? '#'+ lmn.id : '')) + | |
' '+ (lmn.href || lmn.src || lmn.value || '') + | |
' '+ (lmn.title || lmn.alt || lmn.textContent || '')); | |
} | |
this.put(msg); | |
}, | |
}, | |
Hint = {set on(b){ | |
if(!(this.hint.className = b ? 'hit' : '')) return; | |
var {item} = this; | |
if(/^option$/i.test(item.nodeName)){ | |
var sl = item.parentNode; | |
sl.selectedIndex = Array.indexOf(sl.options, item); | |
item = sl; | |
} | |
item.focus(); | |
}}, | |
Hints = { | |
txt: '', | |
run: function HRun(){ this.dic = {}; this.len = 0 }, | |
end: function HEnd(){ this.dic = this.len = null }, | |
add: function HAdd(hint, item){ | |
var n = this.len++; | |
this.dic[hint.textContent = K[n] || (K[n] = K[~-(n / L)] + K[n % L])] | |
= {__proto__: Hint, hint: hint, item: item}; | |
}, | |
get now() this.dic[this.txt], | |
set: function HSet(t){ | |
var h = this.now; | |
if(h) h.on = false; | |
return this.txt = (h = this.dic[t]) ? h.on = t : ''; | |
}, | |
spray: function HSpray(win, doc){ | |
var box = doc.createElement('hs'); | |
box.appendChild(doc.createElement('style')).innerHTML = CSS; | |
var {max} = Math, i = -1, dic = {__proto__: null}, lmn, xy; | |
var lmns = doc.body.querySelectorAll(Query); | |
while((lmn = lmns[++i])){ | |
var {top, right, bottom, left} = lmn.getBoundingClientRect(); | |
if(left >= right || top >= bottom || | |
OriginX > left || OriginY > top || | |
right > win.innerWidth - OriginX || | |
bottom > win.innerHeight - OriginY) continue; | |
var h = doc.createElement('h'); | |
var x = max(0, left + OffsetX) + scrollX; | |
var y = max(0, top + OffsetY) + scrollY; | |
while((xy = x +','+ y) in dic) y += 12; | |
dic[xy] = 1; | |
h.setAttribute('style', 'left:'+ x +'px'+ ';top:'+ y +'px'); | |
this.add(box.appendChild(h), lmn); | |
} | |
doc.body.appendChild(box).id = ID; | |
}, | |
sweep: function HSweep(doc){ | |
var box = doc.getElementById(ID); | |
box && doc.body.removeChild(box); | |
}, | |
}, | |
Acts = { | |
input: function input(e){ | |
var key = String.fromCharCode(e.which || e.keyCode).toUpperCase(); | |
hit(Hints.txt + key) || hit(key); | |
}, | |
ok: function ok() !hit(), | |
undo: function undo(){ Hints.txt ? hit(Hints.txt.slice(0, -1)) : end() }, | |
__noSuchMethod__: end, | |
}; | |
for(var act in new Iterator(bind, true)) | |
if(/click|mouse/.test(act)) Acts[act] = mouser(act); | |
bind.input = | |
Array.map(keys + keys.toLowerCase(), function(k) k.charCodeAt()); | |
Acts.handleEvent = handler(bind); | |
Sign.run(); | |
Hints.run(); | |
cast.call(start, window); | |
Sign.show(Hints.len +'hints ('+ (Date.now() - StartTime) +'ms)'); | |
function start(win, doc){ | |
Hints.spray(win, doc); | |
win.addEventListener('keypress', Acts, true); | |
} | |
function reset(win, doc){ | |
win.removeEventListener('keypress', Acts, true); | |
Hints.sweep(doc); | |
} | |
function end(){ | |
cast.call(reset, window); | |
Hints.end(); | |
Sign.end(); | |
return true; | |
} | |
function hit(txt)( | |
Sign.show(txt = Hints.set(txt), txt && Hints.now.item), txt); | |
function mouser(type){ | |
var [type, btn] = /^[a-z]+(?=(\d?))/(type); | |
var detail = (type === 'dblclick') + 1; | |
return function mouse(e){ | |
var lm = Hints.now.item; | |
var me = lm.ownerDocument.createEvent('MouseEvents'); | |
me.initMouseEvent(type, 1, 1, window, detail, | |
e.screenX, e.screenY, e.clientX, e.clientY, | |
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, | |
+btn, lm); | |
lm.dispatchEvent(me); | |
/click$/.test(type) && end(); | |
}; | |
} | |
function cast(win){ | |
try { var doc = win.document } catch(_){} | |
if(doc && doc.body instanceof HTMLBodyElement){ | |
Array.forEach(doc.getElementsByTagName('select'), select); | |
this(win, doc); | |
} | |
Array.forEach(win, cast, this); | |
} | |
function select(sl){ | |
var doc = sl.ownerDocument; | |
var me = doc.createEvent('MouseEvents'); | |
me.initMouseEvent('mousedown', 0, 0, doc.defaultView, | |
1, 0,0, 0,0, 0,0,0,0, 0, null); | |
sl.dispatchEvent(me); | |
} | |
function handler(dic){ | |
const F = {__proto__: null}, | |
C = 9, A = 10, M = 11, Modic = {C_:1<<C,A_:1<<A,M_:1<<M}; | |
function translate(key) key.match(/[CAM]_|.+/igy).reduce(acc, 0); | |
function acc(n, k) n | (k.length === 1 && k.charCodeAt() || | |
Modic[k = k.toUpperCase()] || | |
KeyEvent['DOM_VK_'+ k]); | |
function add(m, k) | |
F[typeof k === 'number' ? k : translate(k)] = m; | |
function arr(x) | |
x == null ? [] : x.map ? x : x.split ? x.split(/\s+/) : [x]; | |
for(var [meth, ks] in new Iterator(dic)) arr(ks).reduce(add, meth); | |
return function handle(e){ with(e){ | |
var m = F[ctrlKey<<C | altKey<<A | metaKey<<M | (which || keyCode)]; | |
this[m](e, shiftKey) || preventDefault(stopPropagation()); | |
}} | |
} | |
function qmix(qs){ | |
var {URL} = document; | |
return [qs[q] for(q in qs) if(~URL.search(q))].join(','); | |
} | |
}, | |
function(w, ex){ | |
if(ex) ({window: w, sign: this[0].sign}) = ex; | |
w.focus(); | |
this[1](w, this[0]); | |
}] [2](window.content || top, typeof event === "object" && event.hah) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment