Created
March 16, 2009 12:11
-
-
Save satyr/79857 to your computer and use it in GitHub Desktop.
yet another Hit-a-Hint implementation
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
| // ==UserScript== function cmd_ | |
| // @name hit@hint | |
| // @description pseudo Hit-a-Hint for Ubiquity/Greasemonkey | |
| // @namespace http://d.hatena.ne.jp/murky-satyr | |
| // @include * | |
| // ==/UserScript== | |
| function pageLoad_HatH(doc, win){ if((win = doc.defaultView) === win.top){{} | |
| HatH(win, doc, { | |
| key: 'asdfghjkl', | |
| bind: { | |
| go: ['C_\\', 29 /* unconvert */], | |
| ok: 'S_return C_return', //does default action, then continues hint-mode | |
| bs: ['back_space', 29], //undo | |
| click: ';', dblclick: ':', | |
| mouseup: '[', mousedown: ']', | |
| mouseover: ',', mouseout: '.', | |
| }, | |
| css: ''+<><![CDATA[ | |
| $pan { | |
| 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} | |
| $pan.hit {background-color:#fcf} | |
| ]]></>, | |
| /// each hint's offset from its associated element | |
| offset: {x: -3, y: -2}, | |
| /// base point of screen (set negative values to allow overflowed elements) | |
| origin: {x: -6, y: -4}, | |
| /// xpath fragments for specific URIs | |
| xpath: { | |
| '^': | |
| 'a[@href] img[@onclick] input[not(@type="hidden")] textarea select button', | |
| '^http://\\w\\.hatena\\.ne\\.jp/': | |
| ['img[@class="hatena-star-comment-button"]', 'img[@title="Add Star"]'], | |
| '^http://www\\.google\\.com/reader/': | |
| ['div[contains(concat(" ",@class," ")," lhn-button ")'+ | |
| ' or contains(concat(" ",@class," ")," goog-button ")]'], | |
| }, | |
| /// guide | |
| //sign: {__noSuchMethod__: isNaN}, | |
| })}} | |
| this.CmdUtils || pageLoad_HatH(document); | |
| function HatH(window, document, | |
| {id, key, css, bind, sign, xpath, offset, origin}){ | |
| const KeyEvent = document.createEvent('KeyEvents'), | |
| K = (key || 'asdfghjkl').split(''), L = K.length; | |
| Bind = bind || {go: 'C_z', ok: 'RETURN'}, | |
| ID = id || 'HatH', IDD = ID +'Div', IDS = ID +'Style', | |
| {x: OffsetX, y: OffsetY} = offset || {x: -8, y: -8}, | |
| {x: OriginX, y: OriginY} = origin || {x: -4, y: -4}, | |
| XPath = mixpath(xpath).map(function(s) this + s +'|'+ this +'xhtml:' + s, | |
| '/html/body/descendant::').join('|'), | |
| CSS = (css.replace(/\$/g, '#'+ IDD +'>s') | |
| .replace(/([^;\s])\s*\}/g, '$1;}').replace(/;/g, ' !important;')), | |
| Sign = sign || { | |
| new: function SNew(){ this._ = document.title; this.put('') }, | |
| put: function SPut(txt, lmn){ | |
| var msg = '@'+ txt; | |
| if(lmn){ | |
| var name = lmn.nodeName.toUpperCase(); | |
| msg += (' '+ (name === 'INPUT' ? lmn.type.toUpperCase() : name) + | |
| ' '+ (lmn.href || lmn.src || lmn.value || '') + | |
| ' '+ (lmn.title || lmn.alt || lmn.textContent || '')); | |
| } | |
| document.title = msg; | |
| }, | |
| end: function SEnd(){ document.title = this._ }, | |
| }, | |
| Hints = { | |
| Hint: { | |
| set on(b)(this.span.className = b ? (this.item.focus(), 'hit') : '', b), | |
| }, | |
| txt: '', | |
| new: function HNew(){ this.dic = {}, this.len = 0 }, | |
| end: function HEnd(){ this.dic = this.len = null }, | |
| add: function HAdd(span, item){ | |
| var n = this.len++; | |
| this.dic[span.textContent = K[n] || (K[n] = K[~-(n / L)] + K[n % L])] | |
| = {__proto__: this.Hint, span: span, 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){ | |
| this.css(doc); | |
| var box = doc.createElement('div'), {max} = Math, i = -1, | |
| xpr = doc.evaluate(XPath, doc, nsr, 7, null), l = xpr.snapshotLength; | |
| while(++i < l){ | |
| var lmn = xpr.snapshotItem(i), stl = win.getComputedStyle(lmn, null); | |
| if(stl.visibility === 'hidden' || stl.opacity === '0') continue; | |
| 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 spn = doc.createElement('span'); | |
| spn.setAttribute( | |
| 'style', ('left:'+ max(0, left + win.scrollX + OffsetX) +'px'+ | |
| ';top:'+ max(0, top + win.scrollY + OffsetY) +'px')); | |
| this.add(box.appendChild(spn), lmn); | |
| } | |
| box.id = IDD; | |
| doc.body.appendChild(box); | |
| }, | |
| sweep: function HSweep(doc){ | |
| var box = doc.getElementById(IDD); | |
| box && doc.body.removeChild(box); | |
| }, | |
| css: function HCss(doc){ | |
| if(doc.getElementById(IDS)) return; | |
| var style = doc.createElement('style'); | |
| style.innerHTML = CSS, | |
| doc.body.appendChild(style).id = IDS; | |
| }, | |
| }, | |
| Do = (['click', 'dblclick', 'mouseup', 'mousedown', 'mouseover', 'mouseout'] | |
| .reduce(function(d, h)(d[h] = mouser(h), d), | |
| {$: input, go: begin, ok: unhit, bs: back})), | |
| Runner = handler({go: Bind.go}); | |
| Hitter = (function()(delete Bind.go, | |
| Bind.$ = [k.charCodeAt() for each(k in K)], | |
| handler(Bind, end)))(); | |
| cast(function(win){ win.addEventListener('keypress', Runner, true) }); | |
| function start(win, doc){ | |
| win.removeEventListener('keypress', Runner, true); | |
| doc.getElementsByTagName('frameset').length || Hints.spray(win, doc); | |
| win.addEventListener('keypress', Hitter, true); | |
| } | |
| function reset(win, doc){ | |
| win.removeEventListener('keypress', Hitter, true); | |
| Hints.sweep(doc); | |
| win.addEventListener('keypress', Runner, true); | |
| } | |
| function begin(){ | |
| Sign.new(); | |
| Hints.new(); | |
| cast(start); | |
| } | |
| function end(){ | |
| cast(reset); | |
| Hints.end(); | |
| Sign.end(); | |
| return true; | |
| } | |
| function hit(txt)(Hints.set(txt) | |
| ? (Sign.put(Hints.txt, Hints.now.item), true) | |
| : (Sign.put(''), false)); | |
| function input(e){ | |
| var key = String.fromCharCode(e.keyCode || e.which); | |
| hit(Hints.txt + key) || hit(key); | |
| } | |
| function unhit() !hit(); | |
| function back(){ Hints.txt ? hit(Hints.txt.slice(0, -1)) : end() } | |
| function mouser(type){ | |
| var detail = type === 'dblclick' ? 2 : 1; | |
| return function mouse(e){ | |
| var lm = Hints.now.item; | |
| var me = document.createEvent('MouseEvents'); | |
| me.initMouseEvent(type, 1, 1, e.view, detail, | |
| e.screenX, e.screenY, e.clientX, e.clientY, | |
| e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, | |
| 1, lm); | |
| lm.dispatchEvent(me); | |
| } | |
| } | |
| function cast(fn){ | |
| fn(window, document); | |
| Array.forEach(window.frames, function(window){ | |
| try { var {document} = window } catch(_){ return } | |
| fn(window, document); | |
| }); | |
| } | |
| function handler(dic, els){ | |
| const F = {__noSuchMethod__: els || function() true}, | |
| C = 9, A = 10, S = 11, M = 12, Modic = {C_:1<<C,A_:1<<A,S_:1<<S,M_:1<<M}; | |
| for(var d in dic) for each(var k in arr(dic[d])) | |
| F[typeof k === 'number' ? k : translate(k)] = Do[d]; | |
| return function(e){ | |
| with(e) F[ctrlKey << C | altKey << A | shiftKey << S | metaKey << M | | |
| (keyCode || which)](e) || preventDefault(stopPropagation()); | |
| } | |
| function translate(key){ | |
| if(/^(?:[CAM]_)*[A-Z!\"#$%&\'()=~|`+*{}<>?]$/.test(key)) key = 'S_'+ key; | |
| return key.match(/[CASM]_|.+/giy).reduce(acc, 0); | |
| } | |
| function acc(n, k) n | (k.length === 1 && k.charCodeAt() || | |
| Modic[k = k.toUpperCase()] || | |
| KeyEvent['DOM_VK_'+ k]); | |
| } | |
| function arr(x) x == null ? [] : x.map ? x : x.match ? x.match(/\S+/g) : [x]; | |
| function nsr(p) p === 'xhtml' && 'http://www.w3.org/1999/xhtml'; | |
| function mixpath(xps){ | |
| var {URL} = document, a = [], {push} = a; | |
| for(var k in xps) ~URL.search(k) && push.apply(a, arr(xps[k])); | |
| return a; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment