link_hints.js (10651B)
1 /* based on chromium plugin code, adapted by Nibble<.gs@gmail.com> */ 2 var hint_num_str = ''; 3 var hint_elems = []; 4 var hint_open_in_new_tab = false; 5 var hint_enabled = false; 6 7 function hintMode(newtab){ 8 hint_enabled = true; 9 if (newtab) { 10 hint_open_in_new_tab = true; 11 } else { 12 hint_open_in_new_tab = false; 13 } 14 setHints(); 15 document.removeEventListener('keydown', initKeyBind, false); 16 document.addEventListener('keydown', hintHandler, false); 17 hint_num_str = ''; 18 } 19 20 function hintHandler(e){ 21 e.preventDefault(); //Stop Default Event 22 var pressedKey = get_key(e); 23 if (pressedKey == 'Enter') { 24 if (hint_num_str == '') 25 hint_num_str = '1'; 26 judgeHintNum(Number(hint_num_str)); 27 } else if (/[0-9]/.test(pressedKey) == false) { 28 removeHints(); 29 } else { 30 hint_num_str += pressedKey; 31 var hint_num = Number(hint_num_str); 32 if (hint_num * 10 > hint_elems.length + 1) { 33 judgeHintNum(hint_num); 34 } else { 35 var hint_elem = hint_elems[hint_num - 1]; 36 if (hint_elem != undefined && hint_elem.tagName.toLowerCase() == 'a') { 37 setHighlight(hint_elem, true); 38 } 39 } 40 } 41 } 42 43 function setHighlight(elem, is_active) { 44 if (is_active) { 45 var active_elem = document.body.querySelector('a[highlight=hint_active]'); 46 if (active_elem != undefined) 47 active_elem.setAttribute('highlight', 'hint_elem'); 48 elem.setAttribute('highlight', 'hint_active'); 49 } else { 50 elem.setAttribute('highlight', 'hint_elem'); 51 } 52 53 } 54 55 function setHintRules() { 56 if (document.styleSheets.length < 1) { 57 var style = document.createElement("style"); 58 style.appendChild(document.createTextNode("")); 59 document.head.appendChild(style); 60 } 61 var ss = document.styleSheets[0]; 62 ss.insertRule('a[highlight=hint_elem] {background-color: yellow}', 0); 63 ss.insertRule('a[highlight=hint_active] {background-color: lime}', 0); 64 } 65 66 function deleteHintRules() { 67 var ss = document.styleSheets[0]; 68 ss.deleteRule(0); 69 ss.deleteRule(0); 70 } 71 72 function judgeHintNum(hint_num) { 73 var hint_elem = hint_elems[hint_num - 1]; 74 if (hint_elem != undefined) { 75 execSelect(hint_elem); 76 } else { 77 removeHints(); 78 } 79 } 80 81 function execSelect(elem) { 82 var tag_name = elem.tagName.toLowerCase(); 83 var type = elem.type ? elem.type.toLowerCase() : ""; 84 if (tag_name == 'a' && elem.href != '') { 85 setHighlight(elem, true); 86 // TODO: ajax, <select> 87 if (hint_open_in_new_tab) 88 window.open(elem.href); 89 else location.href=elem.href; 90 91 } else if (tag_name == 'input' && (type == "submit" || type == "button" || type == "reset")) { 92 elem.click(); 93 } else if (tag_name == 'input' && (type == "radio" || type == "checkbox")) { 94 // TODO: toggle checkbox 95 elem.checked = !elem.checked; 96 } else if (tag_name == 'input' || tag_name == 'textarea') { 97 elem.focus(); 98 elem.setSelectionRange(elem.value.length, elem.value.length); 99 } 100 removeHints(); 101 } 102 103 function setHints() { 104 //setHintRules(); 105 var win_top = window.scrollY; 106 var win_bottom = win_top + window.innerHeight; 107 var win_left = window.scrollX; 108 var win_right = win_left + window.innerWidth; 109 // TODO: <area> 110 var elems = document.body.querySelectorAll('a, input:not([type=hidden]), textarea, select, button'); 111 var div = document.createElement('div'); 112 div.setAttribute('highlight', 'hints'); 113 document.body.appendChild(div); 114 for (var i = 0; i < elems.length; i++) { 115 var elem = elems[i]; 116 if (!isHintDisplay(elem)) 117 continue; 118 var pos = elem.getBoundingClientRect(); 119 var elem_top = win_top + pos.top; 120 var elem_bottom = win_top + pos.bottom; 121 var elem_left = win_left + pos.left; 122 var elem_right = win_left + pos.left; 123 if ( elem_bottom >= win_top && elem_top <= win_bottom) { 124 hint_elems.push(elem); 125 setHighlight(elem, false); 126 var span = document.createElement('span'); 127 span.style.cssText = [ 128 'left: ', elem_left, 'px;', 129 'top: ', elem_top, 'px;', 130 'position: absolute;', 131 'font-size: 13px;', 132 'background-color: ' + (hint_open_in_new_tab ? '#ff6600' : '#66aa88') + ';', 133 'color: #5511aa;', 134 'font-weight: bold;', 135 'padding: 0px 1px;', 136 'z-index: 100000;' 137 ].join(''); 138 span.innerHTML = hint_elems.length; 139 div.appendChild(span); 140 if (elem.tagName.toLowerCase() == 'a') { 141 if (hint_elems.length == 1) { 142 setHighlight(elem, true); 143 } else { 144 setHighlight(elem, false); 145 } 146 } 147 } 148 } 149 } 150 151 function isHintDisplay(elem) { 152 var pos = elem.getBoundingClientRect(); 153 return (pos.height != 0 && pos.width != 0); 154 } 155 156 function removeHints() { 157 if (!hint_enabled) 158 return; 159 hint_enabled = false; 160 // deleteHintRules(); 161 for (var i = 0; i < hint_elems.length; i++) { 162 hint_elems[i].removeAttribute('highlight'); 163 } 164 hint_elems = []; 165 hint_num_str = ''; 166 var div = document.body.querySelector('div[highlight=hints]'); 167 if (div != undefined) { 168 document.body.removeChild(div); 169 } 170 document.removeEventListener('keydown', hintHandler, false); 171 document.addEventListener('keydown', initKeyBind, false); 172 } 173 174 function addKeyBind( key, func, eve ){ 175 var pressedKey = get_key(eve); 176 if( pressedKey == key ){ 177 eve.preventDefault(); //Stop Default Event 178 eval(func); 179 } 180 } 181 182 document.addEventListener( 'keydown', initKeyBind, false ); 183 184 function initKeyBind(e){ 185 // the following function is written in easier_key.js 186 if (isEditable(e.target)) 187 return; 188 189 var t = e.target; 190 if( t.nodeType == 1){ 191 addKeyBind( 'f', 'hintMode()', e ); 192 addKeyBind( 'F', 'hintMode(true)', e ); 193 addKeyBind( 'C-c', 'removeHints()', e ); 194 } 195 } 196 197 var keyId = { 198 "U+0008" : "BackSpace", 199 "U+0009" : "Tab", 200 "U+0018" : "Cancel", 201 "U+001B" : "Esc", 202 "U+0020" : "Space", 203 "U+0021" : "!", 204 "U+0022" : "\"", 205 "U+0023" : "#", 206 "U+0024" : "$", 207 "U+0026" : "&", 208 "U+0027" : "'", 209 "U+0028" : "(", 210 "U+0029" : ")", 211 "U+002A" : "*", 212 "U+002B" : "+", 213 "U+002C" : ",", 214 "U+002D" : "-", 215 "U+002E" : ".", 216 "U+002F" : "/", 217 "U+0030" : "0", 218 "U+0031" : "1", 219 "U+0032" : "2", 220 "U+0033" : "3", 221 "U+0034" : "4", 222 "U+0035" : "5", 223 "U+0036" : "6", 224 "U+0037" : "7", 225 "U+0038" : "8", 226 "U+0039" : "9", 227 "U+003A" : ":", 228 "U+003B" : ";", 229 "U+003C" : "<", 230 "U+003D" : "=", 231 "U+003E" : ">", 232 "U+003F" : "?", 233 "U+0040" : "@", 234 "U+0041" : "a", 235 "U+0042" : "b", 236 "U+0043" : "c", 237 "U+0044" : "d", 238 "U+0045" : "e", 239 "U+0046" : "f", 240 "U+0047" : "g", 241 "U+0048" : "h", 242 "U+0049" : "i", 243 "U+004A" : "j", 244 "U+004B" : "k", 245 "U+004C" : "l", 246 "U+004D" : "m", 247 "U+004E" : "n", 248 "U+004F" : "o", 249 "U+0050" : "p", 250 "U+0051" : "q", 251 "U+0052" : "r", 252 "U+0053" : "s", 253 "U+0054" : "t", 254 "U+0055" : "u", 255 "U+0056" : "v", 256 "U+0057" : "w", 257 "U+0058" : "x", 258 "U+0059" : "y", 259 "U+005A" : "z", 260 //"U+005B" : "[", 261 //"U+005C" : "\\", 262 //"U+005D" : "]", 263 "U+00DB" : "[", 264 "U+00DC" : "\\", 265 "U+00DD" : "]", 266 "U+005E" : "^", 267 "U+005F" : "_", 268 "U+0060" : "`", 269 "U+007B" : "{", 270 "U+007C" : "|", 271 "U+007D" : "}", 272 "U+007F" : "Delete", 273 "U+00A1" : "¡", 274 "U+0300" : "CombGrave", 275 "U+0300" : "CombAcute", 276 "U+0302" : "CombCircum", 277 "U+0303" : "CombTilde", 278 "U+0304" : "CombMacron", 279 "U+0306" : "CombBreve", 280 "U+0307" : "CombDot", 281 "U+0308" : "CombDiaer", 282 "U+030A" : "CombRing", 283 "U+030B" : "CombDblAcute", 284 "U+030C" : "CombCaron", 285 "U+0327" : "CombCedilla", 286 "U+0328" : "CombOgonek", 287 "U+0345" : "CombYpogeg", 288 "U+20AC" : "€", 289 "U+3099" : "CombVoice", 290 "U+309A" : "CombSVoice", 291 } 292 293 function get_key(evt){ 294 var key = keyId[evt.keyIdentifier] || evt.keyIdentifier, 295 ctrl = evt.ctrlKey ? 'C-' : '', 296 meta = (evt.metaKey || evt.altKey) ? 'M-' : '', 297 shift = evt.shiftKey ? 'S-' : ''; 298 if (evt.shiftKey){ 299 if (/^[a-z]$/.test(key)) 300 return ctrl+meta+key.toUpperCase(); 301 if (/^[0-9]$/.test(key)) { 302 switch(key) { 303 // TODO 304 case "4": 305 key = "$"; 306 break; 307 }; 308 return key; 309 } 310 if (/^(Enter|Space|BackSpace|Tab|Esc|Home|End|Left|Right|Up|Down|PageUp|PageDown|F(\d\d?))$/.test(key)) 311 return ctrl+meta+shift+key; 312 } 313 return ctrl+meta+key; 314 }