Skip to content

Instantly share code, notes, and snippets.

@satyr
Created April 2, 2009 10:44
Show Gist options
  • Save satyr/89131 to your computer and use it in GitHub Desktop.
Save satyr/89131 to your computer and use it in GitHub Desktop.
yet another Hit-a-Hint / use keyconfig for better performances
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)
var sbw = (document.getElementById('sidebar').contentDocument
.getElementById('web-panels-browser').contentWindow);
var sbt = document.getElementById('sidebar-title');
document.getElementById('xxx_key__hit@hint').oncommand({hah: {
window: sbw,
sign: {
run: function(){ this._ = sbt.value },
put: function(msg){ sbt.value = msg },
end: function(){
sbt.value = this._;
var lm = document.commandDispatcher.focusedElement;
try { if(lm.selectionEnd >= 0) return } catch(_){}
content.focus();
},
}}});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment