Y-marker

Sets up keyboard shortcuts for placing bookmarks and navigation inside webpage.

当前为 2016-02-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Y-marker
  3. // @namespace trespassersW
  4. // @description Sets up keyboard shortcuts for placing bookmarks and navigation inside webpage.
  5. // @include http://*
  6. // @include https://*
  7. // @include file://*
  8. // ** about:config -> greasemonkey.fileIsGreaseable <- true
  9. // @version 16.02.22
  10. // @license MIT
  11. // @released 2013-12-11
  12. // @run-at document-end
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @grant GM_unsafeWindow
  16. // ==/UserScript==
  17. /*
  18. 16.02.22 [+] press Alt-Shift-0 twice to set starting Y-position for whole domain; [*] markers moved to GM_storage.
  19. * 13-12-12 click on msg removes all marks
  20. * 1.1 don't run in editable fields
  21. */
  22. (function(){ "use strict";
  23. if(top!=self || !document || !document.body ) return;
  24. var W = unsafeWindow || window; // localStorage doesn't live in sandbox?
  25. /* key kombinations to invoke the skript */
  26. var kShift = 1, kCtrl = 2, kAlt = 4, kWin = 8;
  27. var kJump = kAlt;
  28. var kMark = kAlt+kShift;
  29.  
  30. /* sec; 0 to disable; -1 status bar only */
  31. var tipShowtime = 2.2;
  32.  
  33. var kNobs = "-0123456789";
  34. var kKeys = {
  35. 173: 0, 48: 1, 49: 2, 50: 3, 51: 4, 52: 5, 53: 6, 54: 7, 55: 8, 56: 9, 57: 10,
  36. 189: 0, /* chrome, opera caps lock */
  37. 109: 0 /* opera */
  38. };
  39. var minus1="-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1";
  40. var LH=location.hostname || "Ym", LHP=LH+location.pathname;
  41.  
  42. function kNob(k){ return kNobs.charAt(k); }
  43.  
  44. var U=undefined, D=window.document;
  45. var _L= function() {};
  46. //_L=console.log.bind(console);
  47.  
  48. var statMsg;
  49. function msg(t,k, y){
  50. statMsg = "";
  51. if(U!==k)
  52. statMsg += "["+kNob(k)+"] ";
  53. if(U!==y)
  54. statMsg += ""+pt(y)+"% ";
  55. statMsg += t+ (noCoo ? "\u2262 ": "");
  56. }
  57.  
  58. var locStor,locStored;
  59. var noCoo;
  60. // see SQlite manager -> %FFpath%\webappstore.sqlite -> find -> key -> contains Ym#
  61.  
  62. try {
  63. locStor = W.localStorage;
  64. locStored=locStor.getItem("Ym#"+location.pathname);
  65. } catch(e){ locStor = locStored =null; };
  66. function pt(y) {
  67. try{
  68. y =Math.round(y*1000/(document.body.scrollHeight+1))/10;
  69. }catch(e){console.log("math\n"+e); return -1}
  70. return y;
  71. }
  72.  
  73. var Ym;
  74. var pz;
  75.  
  76. function ldYm(){
  77. var s;
  78. if(locStor && locStored){
  79. pz=locStored.split(",");
  80. svYm();
  81. locStor.removeItem("Ym#"+location.pathname);
  82. console.log('Ym: locS -> GM_S '+LHP);
  83. locStor = locStored = null;
  84. }
  85. s=GM_getValue(Ym,null);
  86. if(!s){ s=minus1;
  87. }else try{
  88. var y=JSON.parse(s);
  89. s=y[LHP] || y[LH] || minus1;
  90. }catch(e){console.log('ldYm: buggy data\n'+e)};
  91. pz=s.split(",");
  92. }
  93.  
  94. function svYm(d){
  95. var y={},s=pz.join(",");
  96. try{
  97. y=JSON.parse(GM_getValue(Ym,'{}'));
  98. }catch(e){console.log('svYm: buggy data\n'+e);}
  99. if(!d) y[LHP]= s;
  100. else{ // marker for whole domain
  101. y[LH]= s;
  102. }
  103. //_L((d?LH:LHP)+": saved "+s);
  104. GM_setValue(Ym,JSON.stringify(y));
  105. }
  106.  
  107. function rmYm(){
  108. var y={};
  109. try{
  110. y=JSON.parse(GM_getValue(Ym,'{}'));
  111. }catch(e){console.log('rmYm: buggy data\n'+e); y={}; }
  112. if(y[LH]) delete y[LH], _L("rmH: " +LH);
  113. if(y[LHP]) delete y[LHP], _L("rmHP: " +LHP);
  114. GM_setValue(Ym,JSON.stringify(y));
  115. pz=minus1.split(",");
  116. }
  117.  
  118. function jumpY(k){
  119. var y=pz[k];
  120. if(y > -1) {
  121. if( y!= scrollY ){
  122. pz[0] = scrollY;
  123. scroll(0,y);
  124. msg("jump",k,y);
  125. }else
  126. msg("here",k,y);
  127. return 1;
  128. }
  129. msg("none",k);
  130. return 0;
  131. }
  132.  
  133. function markY(k){
  134. var d="";
  135. if(k==1 && scrollY == pz[k] ) d="!";
  136. pz[k]=scrollY;
  137. if(k>=1)
  138. svYm(d);
  139. msg("mark"+d,k,pz[k]);
  140. return 1;
  141. }
  142.  
  143. var kMap= {16: kShift, 17:kCtrl, 18: kAlt, 91: kWin};
  144. var keyMod=0;
  145. var kkWin= (kMark | kJump) & kWin;
  146.  
  147. function klear(e) {
  148. var k= e.keyCode;
  149. if(!k) return;
  150. var km=kMap[k];
  151. if(km) {
  152. keyMod &= -1 ^ km;
  153. }
  154. }
  155.  
  156. function onKeydown(e) {
  157. try{
  158. var rc=0, k= e.keyCode;
  159. if(!k) return;
  160. // Don't run in input, select, textarea etc.
  161. var E = D.activeElement.tagName.toLowerCase();
  162. if (E == "input" || E == "select" || E == "textarea" ||
  163. (E=D.activeElement.contentEditable) == "true" ||
  164. E == "")
  165. { keyMod = 0; return; }
  166. var km =kMap[k]; // ff doesnt track metaKey. stsuko
  167. if(km) {
  168. keyMod |= km;
  169. if( kkWin && km === kWin ) //???
  170. e.preventDefault(), e.stopPropagation();
  171. return;
  172. }
  173. km=keyMod;
  174. if( U=== (k=kKeys[k]) ){ keyMod = 0; return; }
  175. if( km === kJump ) {
  176. rc = jumpY(k);
  177. }else if( km === kMark ) {
  178. rc = markY(k);
  179. }else {
  180. return;
  181. }
  182. statSay();
  183. if(rc) e.preventDefault(),e.stopPropagation();
  184. }catch(e){console.log('smth wromg\n'+e)};
  185. }
  186. function mk(p, t, id, s) {
  187. var e = D.createElement(t);
  188. e.id=id;
  189. e.style.cssText = s;
  190. return p.appendChild(e);
  191. };
  192.  
  193. /* RIP status bar replacement */
  194. var sb;
  195. function _css(){
  196. if(!sb) sb = mk(
  197. //D.body,
  198. D.documentElement, // 2014-06-30 ???!!1
  199. 'section', "Y-marker-userjs-inf",
  200. "position: fixed!important;\
  201. z-index: 214748!important;\
  202. top: 0px; right: 1px; bottom: auto; left: auto;\
  203. background: rgba(221,255,221,.75);\
  204. padding: 2px 3px 2px 8px; margin:0;\
  205. border: none;\
  206. border-radius: 12px 3px 3px 12px; \
  207. color: #131;\
  208. opacity: 1; display:none;\
  209. font: normal 12px/14px sans-serif !important;\
  210. text-shadow: #373 2px 2px 4px, #7F7 -2px -2px 4px;\
  211. cursor:no-drop;\
  212. "
  213. );
  214. /* click removes all */
  215. if(tipShowtime>0){
  216. sb.addEventListener("click",function (e) {
  217. rmYm(); //locStor.removeItem(Ym);
  218. ldYm(); noTout();
  219. },false);
  220. };
  221. }
  222.  
  223.  
  224. var tO;
  225. function onTout(){
  226. tO=0; sb.style.display="none";
  227. }
  228. function noTout(){
  229. if(tO) clearTimeout(tO), onTout();
  230. }
  231.  
  232. function statSay(t) {
  233. if(statMsg){
  234. _css();
  235. if(tipShowtime)
  236. W.status=statMsg;
  237. if(tipShowtime>0){
  238. noTout();
  239. sb.innerHTML= statMsg;
  240. sb.style.display="block";
  241. tO=setTimeout(onTout, (t? t: tipShowtime)*1000);
  242. }
  243. }
  244. statMsg="";
  245. }
  246.  
  247. Ym="Ym#";//+location.pathname;
  248.  
  249. ldYm();
  250. for(var k=1; k<2; k++){ /* pz.length */
  251. if(pz[k]>-1){
  252. scroll(0,pz[k]);
  253. msg('jump',k,pz[k]);
  254. statSay(5);
  255. break;
  256. }
  257. };
  258.  
  259. if(noCoo) msg(noCoo), statSay(5);
  260.  
  261. addEventListener("keydown",onKeydown,false);
  262. addEventListener("keyup",klear,false);
  263. })();