vimprobable/hinting.js

201 lines
8.7 KiB
JavaScript

/*
(c) 2009 by Leon Winter
(c) 2009, 2010 by Hannes Schueller
(c) 2010 by Hans-Peter Deifel
see LICENSE file
*/
function vimprobable_clearfocus() {
if(document.activeElement && document.activeElement.blur)
document.activeElement.blur();
}
function vimprobable_show_hints(inputText) {
if (document.getElementsByTagName("body")[0] !== null && typeof(document.getElementsByTagName("body")[0]) == "object") {
var height = window.innerHeight;
var width = window.innerWidth;
var scrollX = document.defaultView.scrollX;
var scrollY = document.defaultView.scrollY;
/* prefixing html: will result in namespace error */
var hinttags;
if (typeof(inputText) == "undefined" || inputText == "") {
hinttags = "//*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select";
} else {
/* only elements which match the text entered so far */
hinttags = "//*[(@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href) and contains(., '" + inputText + "')] | //input[not(@type='hidden') and contains(., '" + inputText + "')] | //a[contains(., '" + inputText + "')] | //area[contains(., '" + inputText + "')] | //iframe[contains(@name, '" + inputText + "')] | //textarea[contains(., '" + inputText + "')] | //button[contains(@value, '" + inputText + "')] | //select[contains(., '" + inputText + "')]";
}
/* iterator type isn't suitable here, because: "DOMException NVALID_STATE_ERR: The document has been mutated since the result was returned." */
var r = document.evaluate(hinttags, document,
function(p) {
return 'http://www.w3.org/1999/xhtml';
}, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
div = document.createElement("div");
/* due to the different XPath result type, we will need two counter variables */
vimprobable_j = 0;
var i;
vimprobable_a = [];
vimprobable_colors = [];
vimprobable_backgrounds = [];
for (i = 0; i < r.snapshotLength; i++)
{
var elem = r.snapshotItem(i);
rect = elem.getBoundingClientRect();
if (!rect || rect.top > height || rect.bottom < 0 || rect.left > width || rect.right < 0 || !(elem.getClientRects()[0]))
continue;
var computedStyle = document.defaultView.getComputedStyle(elem, null);
if (computedStyle.getPropertyValue("visibility") != "visible" || computedStyle.getPropertyValue("display") == "none")
continue;
var leftpos = Math.max((rect.left + scrollX), scrollX);
var toppos = Math.max((rect.top + scrollY), scrollY);
vimprobable_a.push(elem);
/* making this block DOM compliant */
var hint = document.createElement("span");
hint.setAttribute("class", "hinting_mode_hint");
hint.setAttribute("id", "vimprobablehint" + vimprobable_j);
hint.style.position = "absolute";
hint.style.left = leftpos + "px";
hint.style.top = toppos + "px";
hint.style.background = "red";
hint.style.color = "#fff";
hint.style.font = "bold 10px monospace";
hint.style.zIndex = "99";
var text = document.createTextNode(vimprobable_j + 1);
hint.appendChild(text);
div.appendChild(hint);
/* remember site-defined colour of this element */
vimprobable_colors[vimprobable_j] = elem.style.color;
vimprobable_backgrounds[vimprobable_j] = elem.style.background;
/* make the link black to ensure it's readable */
elem.style.color = "#000";
elem.style.background = "#ff0";
vimprobable_j++;
}
i = 0;
while (typeof(vimprobable_a[i]) != "undefined") {
vimprobable_a[i].className += " hinting_mode_hint";
i++;
}
document.getElementsByTagName("body")[0].appendChild(div);
vimprobable_clearfocus();
vimprobable_h = null;
if (i == 1) {
/* just one hinted element - might as well follow it */
return vimprobable_fire(1);
}
}
}
function vimprobable_fire(n)
{
if (typeof(vimprobable_a[n - 1]) != "undefined") {
el = vimprobable_a[n - 1];
tag = el.nodeName.toLowerCase();
vimprobable_clear();
if(tag == "iframe" || tag == "frame" || tag == "textarea" || tag == "input" && (el.type == "text" || el.type == "password" || el.type == "checkbox" || el.type == "radio") || tag == "select") {
el.focus();
if (tag == "textarea" || tag == "input")
console.log('insertmode_on');
} else {
if (el.onclick) {
var evObj = document.createEvent('MouseEvents');
evObj.initMouseEvent('click', true, true, window, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, null);
el.dispatchEvent(evObj);
} else if (el.href) {
if (el.href.match(/^javascript:/)) {
var evObj = document.createEvent('MouseEvents');
evObj.initMouseEvent('click', true, true, window, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, null);
el.dispatchEvent(evObj);
} else {
/* send signal to open link */
return "open;" + el.href;
}
} else {
var evObj = document.createEvent('MouseEvents');
evObj.initMouseEvent('click', true, true, window, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, null);
el.dispatchEvent(evObj);
}
}
}
}
function vimprobable_cleanup()
{
for(e in vimprobable_a) {
if (typeof(vimprobable_a[e].className) != "undefined") {
vimprobable_a[e].className = vimprobable_a[e].className.replace(/hinting_mode_hint/,'');
/* reset to site-defined colour */
vimprobable_a[e].style.color = vimprobable_colors[e];
vimprobable_a[e].style.background = vimprobable_backgrounds[e];
}
}
div.parentNode.removeChild(div);
window.onkeyup = null;
}
function vimprobable_clear()
{
vimprobable_cleanup();
console.log("hintmode_off")
}
function vimprobable_update_hints(n)
{
if(vimprobable_h != null) {
vimprobable_h.className = vimprobable_h.className.replace("_focus","");
vimprobable_h.style.background = "#ff0";
}
if (vimprobable_j - 1 < n * 10 && typeof(vimprobable_a[n - 1]) != "undefined") {
/* return signal to follow the link */
return "fire;" + n;
} else {
if (typeof(vimprobable_a[n - 1]) != "undefined") {
(vimprobable_h = vimprobable_a[n - 1]).className = vimprobable_a[n - 1].className.replace("hinting_mode_hint", "hinting_mode_hint_focus");
vimprobable_h.style.background = "#8f0";
}
}
}
function vimprobable_focus_input()
{
if (document.getElementsByTagName("body")[0] !== null && typeof(document.getElementsByTagName("body")[0]) == "object") {
/* prefixing html: will result in namespace error */
var hinttags = "//input[@type='text'] | //input[@type='password'] | //textarea";
var r = document.evaluate(hinttags, document,
function(p) {
return 'http://www.w3.org/1999/xhtml';
}, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var i;
var j = 0;
var k = 0;
var first = null;
for (i = 0; i < r.snapshotLength; i++) {
var elem = r.snapshotItem(i);
if (k == 0) {
if (elem.style.display != "none" && elem.style.visibility != "hidden") {
first = elem;
} else {
k--;
}
}
if (j == 1 && elem.style.display != "none" && elem.style.visibility != "hidden") {
elem.focus();
var tag = elem.nodeName.toLowerCase();
if (tag == "textarea" || tag == "input")
console.log('insertmode_on');
break;
} else {
if (elem == document.activeElement)
j = 1;
}
k++;
}
if (j == 0) {
/* no appropriate field found focused - focus the first one */
if (first !== null) {
first.focus();
var tag = elem.nodeName.toLowerCase();
if (tag == "textarea" || tag == "input")
console.log('insertmode_on');
}
}
}
}