10 focus_color
= "#00ff00";
11 normal_color
= "#ffff99";
13 border
= "1px dotted #000000";
15 hint_foreground
= "#ffffff";
16 hint_background
= "#000088";
17 hint_border
= "2px dashed #000000";
19 hint_font
= "11px monospace bold";
22 horizontal_offset
= -10;
24 function Hint(element
) {
25 this.element
= element
;
26 this.rect
= element
.getBoundingClientRect();
28 function create_span(element
, h
, v
) {
29 var span
= document
.createElement("span");
30 var leftpos
= Math
.max((element
.rect
.left
+ document
.defaultView
.scrollX
), document
.defaultView
.scrollX
) + h
;
31 var toppos
= Math
.max((element
.rect
.top
+ document
.defaultView
.scrollY
), document
.defaultView
.scrollY
) + v
;
32 span
.style
.position
= "absolute";
33 span
.style
.left
= leftpos
+ "px";
34 span
.style
.top
= toppos
+ "px";
37 function create_hint(element
) {
38 var hint
= create_span(element
, horizontal_offset
, vertical_offset
- element
.rect
.height
/2);
39 hint
.style
.font
= hint_font
;
40 hint
.style
.color
= hint_foreground
;
41 hint
.style
.background
= hint_background
;
42 hint
.style
.opacity
= hint_opacity
;
43 hint
.style
.border
= hint_border
;
44 hint
.style
.zIndex
= 10001;
45 hint
.style
.visibility
= 'visible';
48 function create_overlay(element
) {
49 var overlay
= create_span(element
, 0, 0);
50 overlay
.style
.width
= element
.rect
.width
+ "px";
51 overlay
.style
.height
= element
.rect
.height
+ "px";
52 overlay
.style
.opacity
= opacity
;
53 overlay
.style
.backgroundColor
= normal_color
;
54 overlay
.style
.border
= border
;
55 overlay
.style
.zIndex
= 10000;
56 overlay
.style
.visibility
= 'visible';
57 overlay
.addEventListener( 'click', function() { click_element(element
); }, false );
61 this.hint
= create_hint(this);
62 this.overlay
= create_overlay(this);
64 function reload_hints(array
, input
, keep
) {
65 var length
= array
.length
;
66 var start
= length
< 10 ? 1 : length
< 100 ? 10 : 100;
67 var bestposition
= 37;
69 for (var i
=0; i
<length
; i
++) {
71 e
.overlay
.style
.backgroundColor
= normal_color
;
72 if (!e
.hint
.parentNode
&& !e
.hint
.firstchild
) {
73 var content
= document
.createTextNode(start
+ i
);
74 e
.hint
.appendChild(content
);
75 hints
.appendChild(e
.hint
);
78 e
.hint
.textContent
= start
+ i
;
80 if (!e
.overlay
.parentNode
&& !e
.overlay
.firstchild
) {
81 overlays
.appendChild(e
.overlay
);
83 if (input
&& bestposition
!= 0) {
84 // match word beginnings
85 var content
= e
.element
.textContent
.toLowerCase().split(" ");
86 for (var cl
=0; cl
<content
.length
; cl
++) {
87 if (content
[cl
].toLowerCase().indexOf(input
) == 0) {
88 if (cl
< bestposition
) {
97 active
= array
[lastpos
];
98 active
.overlay
.style
.backgroundColor
= focus_color
;
100 function click_element(e
) {
101 var mouseEvent
= document
.createEvent("MouseEvent");
102 mouseEvent
.initMouseEvent("click", true, true, window
, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
103 e
.element
.dispatchEvent(mouseEvent
);
106 function show_hints() {
107 document
.activeElement
.blur();
109 var res
= document
.body
.querySelectorAll('a, area, textarea, select, link, input:not([type=hidden]), button, frame, iframe');
110 hints
= document
.createElement("div");
111 overlays
= document
.createElement("div");
112 for (var i
=0; i
<res
.length
; i
++) {
113 var e
= new Hint(res
[i
]);
114 var rects
= e
.element
.getClientRects()[0];
116 if (!r
|| r
.top
> window
.innerHeight
|| r
.bottom
< 0 || r
.left
> window
.innerWidth
|| r
< 0 || !rects
) {
119 var style
= document
.defaultView
.getComputedStyle(e
.element
, null);
120 if (style
.getPropertyValue("visibility") != "visible" || style
.getPropertyValue("display") == "none") {
125 elements
.sort( function(a
,b
) { return a
.rect
.top
- b
.rect
.top
; });
126 active_arr
= elements
;
127 reload_hints(elements
);
128 document
.body
.appendChild(hints
);
129 document
.body
.appendChild(overlays
);
132 function is_input(element
) {
133 var e
= element
.element
;
134 var type
= e
.type
.toLowerCase();
135 if (e
.tagName
== "INPUT" || e
.tagName
== "TEXTAREA" ) {
136 if (type
== "radio" || type
== "checkbox") {
137 e
.checked
= !e
.checked
;
139 else if (type
== "submit" || type
== "reset" || type
== "button") {
140 click_element(element
);
149 function update_hints(input
) {
154 input
= input
.toLowerCase();
156 for (var i
=0; i
<active_arr
.length
; i
++) {
157 var e
= active_arr
[i
];
158 if (parseInt(input
) == input
) {
159 text_content
= e
.hint
.textContent
;
163 text_content
= e
.element
.textContent
.toLowerCase();
165 if (text_content
.match(input
)) {
169 e
.hint
.style
.visibility
= 'hidden';
170 e
.overlay
.style
.visibility
= 'hidden';
174 if (array
.length
== 0) {
178 if (array
.length
== 1) {
179 if (evaluate(array
[0])) {
180 return "__HINT_EVALUATED__"
183 reload_hints(array
, input
, keep
);
186 if (overlays
&& overlays
.parentNode
) {
187 overlays
.parentNode
.removeChild(overlays
);
189 if (hints
&& hints
.parentNode
) {
190 hints
.parentNode
.removeChild(hints
);
196 function evaluate(element
) {
198 var e
= element
.element
;
199 if (!is_input(element
) && e
.href
) {
200 if (e
.href
.match(/javascript:/) || (e
.type
.toLowerCase() == "button")) {
201 click_element(element
);
205 document
.location
= e
.href
;
212 function get_active() {
213 return evaluate(active
);
215 function focus(newpos
) {
216 active_arr
[lastpos
].overlay
.style
.backgroundColor
= normal_color
;
217 active_arr
[newpos
].overlay
.style
.backgroundColor
= focus_color
;
218 active
= active_arr
[newpos
];
221 function focus_next() {
222 var newpos
= lastpos
== active_arr
.length
-1 ? 0 : lastpos
+ 1;
225 function focus_prev() {
226 var newpos
= lastpos
== 0 ? active_arr
.length
-1 : lastpos
- 1;
230 function update(input
) {
231 input
= input
.replace(/(\d+)$/, " $1");
232 strings
= input
.split(" ");
233 if (input
.length
< last_input
.length
|| strings
.length
< last_strings
.length
) {
234 // user removed a char
237 for (var i
= 0; i
< strings
.length
; i
+= 1) {
238 update_hints(strings
[i
]);
241 update_hints(strings
[strings
.length
-1]);
244 last_strings
= strings
;