NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Y-marker // @namespace trespassersW // @description Sets up keyboard shortcuts for placing bookmarks and navigation inside webpage. // @include http://* // @include https://* // @include file://* // ** about:config -> greasemonkey.fileIsGreaseable <- true // @version 16.03.04 // @license MIT // @released 2013-12-11 // @run-at document-end // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant unsafeWindow // ==/UserScript== /* 16.03.04 bookmarklets works in chrome 16.02.26 [+] hotkey configuration dialogue invoked from GM menu; [+] Bookmarlets interface: javascript:postMessage('Y-marker0','*') - jump to bookmark # 0 javascript:postMessage('Y-marker0=','*') - set up bookmark #0 16.02.22 [+] press Alt-Shift-0 twice to set starting Y-position for whole domain; * 13-12-12 click on msg removes all marks * 1.1 don't run in editable fields */ (function(){ "use strict"; if(top!=self || !document || !document.body ) return; var W = unsafeWindow || window; // localStorage doesn't live in sandbox? /* key kombinations to invoke the skript */ var kShift = 1, kCtrl = 2, kAlt = 4, kWin = 8; var kJump = kAlt; var kMark = kAlt+kShift; /* sec; 0 to disable; -1 status bar only */ var tipShowtime = 2.2; var kNobs = "-0123456789"; var kKeys = { 173: 0, 48: 1, 49: 2, 50: 3, 51: 4, 52: 5, 53: 6, 54: 7, 55: 8, 56: 9, 57: 10, 189: 0, /* chrome, opera caps lock */ 109: 0 /* opera */ }; var minus1="-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1", min1=minus1.split(','); var LH=location.hostname || "Ym", LHP=LH+location.pathname; function kNob(k){ return kNobs.charAt(k); } var U=undefined, D=window.document; var _L= function() {}; //_L=console.log.bind(console); var statMsg; function msg(t,k, y){ statMsg = ""; if(U!==k) statMsg += "["+kNob(k)+"] "; if(U!==y) statMsg += ""+pt(y)+"% "; statMsg += t; } var locStor,locStored; // see SQlite manager -> %FFpath%\webappstore.sqlite -> find -> key -> contains Ym# try { locStor = W.localStorage; locStored=locStor.getItem("Ym#"+location.pathname); } catch(e){ locStor = locStored =null; }; function pt(y) { try{ y =Math.round(y*1000/(document.body.scrollHeight+1))/10; if(y>111.1) y=111.1; }catch(e){console.log("math\n"+e); return -1} return y; } var Ym; var pz; function ldYm(){ var s,t,y; if(locStor && locStored){ pz=locStored.split(","); svYm(); locStor.removeItem("Ym#"+location.pathname); console.log('Ym: locS -> GM_S '+LHP); locStor = locStored = null; } s=GM_getValue(Ym,null); if(!s){ s=minus1; }else { try{ y=JSON.parse(s); }catch(e){console.log('ldYm: buggy data\n'+e)}; s=y[LHP] || y[LH] || minus1; } pz=s.split(","); if(y && (y=y['#HotKeys#'])){ kJump = +y[0], kMark = +y[1]; } } function svYm(d){ var y={},s=pz.join(","); try{ y=JSON.parse(GM_getValue(Ym,'{}')); }catch(e){console.log('svYm: buggy data\n'+e);} if(!d) y[LHP]= s; else if(d==='#'){ y['#HotKeys#']=[kJump,kMark]; }else{ // marker for whole domain y[LH]= s; } GM_setValue(Ym,JSON.stringify(y)); } function rmYm(){ var y={}; try{ y=JSON.parse(GM_getValue(Ym,'{}')); }catch(e){console.log('rmYm: buggy data\n'+e); y={}; } if(y[LH]) delete y[LH], _L("rmH: " +LH); if(y[LHP]) delete y[LHP], _L("rmHP: " +LHP); GM_setValue(Ym,JSON.stringify(y)); pz=min1; } function jumpY(k){ var y=pz[k]; if(y > -1) { if( y!= scrollY ){ pz[0] = scrollY; scroll(0,y); msg("jump",k,y); }else msg("here",k,y); return 1; } msg("none",k); return 0; } function markY(k){ var d=""; if(k==1 && scrollY == pz[k] ) d="!"; pz[k]=scrollY; if(k>=1) svYm(d); msg("mark"+d,k,pz[k]); return 1; } var kMap= {16: kShift, 17:kCtrl, 18: kAlt, 91: kWin}; var keyMod=0; var kkWin= (kMark | kJump) & kWin; function klear(e) { var k= e.keyCode; if(!k) return; var km=kMap[k]; if(km) { keyMod &= -1 ^ km; } } function onKeydown(e) { try{ var rc=0, k= e.keyCode; if(!k) return; // Don't run in input, select, textarea etc. var E = D.activeElement.tagName.toLowerCase(); if (E == "input" || E == "select" || E == "textarea" || (E=D.activeElement.contentEditable) == "true" || E == "") { keyMod = 0; return; } var km =kMap[k]; // ff doesnt track metaKey. stsuko if(km) { keyMod |= km; if( kkWin && km === kWin ) //??? e.preventDefault(), e.stopPropagation(); return; } km=keyMod; if( U=== (k=kKeys[k]) ){ keyMod = 0; return; } if( km === kJump ) { rc = jumpY(k); }else if( km === kMark ) { rc = markY(k); }else { return; } statSay(); if(rc) e.preventDefault(),e.stopPropagation(); }catch(e){console.log('smth wromg\n'+e)}; } function mk(p, t, id, s) { var e = D.createElement(t); e.id=id; e.style.cssText = s; return p.appendChild(e); }; /* RIP status bar replacement */ var sb; function _css(){ if(!sb) sb = mk( //D.body, D.documentElement, // 2014-06-30 ???!!1 'section', "Y-marker-userjs-inf", "position: fixed!important;\ z-index: 214748!important;\ top: 0px; right: 1px; bottom: auto; left: auto;\ background: rgba(221,255,221,.75)!important;\ padding: 2px 3px 2px 8px; margin:0;\ border: none;\ border-radius: 12px 3px 3px 12px;\ color: #131!important;\ opacity: 1; display:none;\ font: normal 12px/14px sans-serif !important;\ text-shadow: #373 2px 2px 4px, #7F7 -2px -2px 4px;\ cursor:no-drop;\ " ); /* click removes all */ if(tipShowtime>0){ sb.addEventListener("click",function (e) { rmYm(); //locStor.removeItem(Ym); ldYm(); noTout(); },false); }; } var tO; function onTout(){ tO=0; sb.style.display="none"; } function noTout(){ if(tO) clearTimeout(tO), onTout(); } function statSay(t) { if(statMsg){ _css(); if(tipShowtime) W.status=statMsg; if(tipShowtime>0){ noTout(); sb.innerHTML= statMsg; sb.style.display="block"; tO=setTimeout(onTout, (t? t: tipShowtime)*1000); } } statMsg=""; } Ym="Ym#";//+location.pathname; ldYm(); for(var k=1; k<2; k++){ /* pz.length */ if(pz[k]>-1){ scroll(0,pz[k]); msg('jump',k,pz[k]); statSay(5); break; } }; function $i(id, parent){ return (parent || document).getElementById(id) } var hk; function saveHk(){ function K(id, b) { return $i('Ym-bt'+id).checked? b: 0 } kJump=K('JS',kShift)|K('JA',kAlt)|K('JW',kWin)|K('JC',kCtrl); kMark=K('MS',kShift)|K('MA',kAlt)|K('MW',kWin)|K('MC',kCtrl); svYm('#'); } function setKeys(){ function J(j){return kJump&j? 'checked': ''} function M(m){return kMark&m? 'checked': ''} if(hk) hk.parentNode.removeChild(hk); hk = D.createElement('section'); hk.style.cssText = "position: fixed!important;\ z-index: 214748!important;\ top: 10px; left: 16px; bottom: auto; right: auto;\ background: rgb(221,255,221)!important;\ padding: 4px; margin:0;\ border: 1px solid #131;\ border-radius: 3px; \ color: #131!important;\ opacity: 1; display:block;\ font: normal 12px/14px sans-serif !important;\ "; hk.innerHTML=('\ <form style="padding:0;margin:0"><b>\ <center style="padding-bottom:.5em">Y-marker hotkeys</center></b>\ <b style="width:3em;display:inline-block;">Jump</b>: \ Shift<input type=checkbox id=Ym-btJS '+J(kShift)+'> \ Alt<input type=checkbox id=Ym-btJA '+J(kAlt)+'> \ Win<input type=checkbox id=Ym-btJW '+J(kWin)+'> \ Ctrl<input type=checkbox id=Ym-btJC '+J(kCtrl)+'> <br>\ <b style="width:3em;display:inline-block;">Mark</b>: \ Shift<input type=checkbox id=Ym-btMS '+M(kShift)+'> \ Alt<input type=checkbox id=Ym-btMA '+M(kAlt)+'> \ Win<input type=checkbox id=Ym-btMW '+M(kWin)+'> \ Ctrl<input type=checkbox id=Ym-btMC '+M(kCtrl)+'><hr><center>\ <input type="button" tabIndex=1 value="Save" id="Ym-btSave"> \ <input type="button" tabIndex=2 value="Cancel" id="Ym-btCancel">\ </center></form>\ '); hk.addEventListener("click",function(e){ var t= e.target,c=0; if(!t || !t.id) return; if(t.id=="Ym-btSave")try{ c=1; saveHk(); }catch(e){console.log("Ym: problem in hotkey dialog\n"+e)} else if(t.id=="Ym-btCancel"){ c=1; } if(c){ e.preventDefault(), e.stopPropagation(); hk.parentNode.removeChild(hk),hk=null; } },false); D.documentElement.appendChild(hk); } function wMsg(e){ //event.source!=window in Chrome if(typeof e.data==='string' && e.data.substr(0,8)==='Y-marker'){ e.stopPropagation(); if(e.data === 'Y-marker hotkeys') return setKeys(); var m=e.data.match(/Y-marker\s*([0-9-])(\=?)/); var p = (m[1]==='-')?0: +m[1]+1; if(m[2]) markY(p); else jumpY(p); statSay(); } } addEventListener("keydown",onKeydown,false); addEventListener("keyup",klear,false); GM_registerMenuCommand("Y-marker hotkeys", setKeys); window.addEventListener("message", wMsg, false); })();