User Tools

Site Tools


configurable-jump

Configurable Jump

Description

Hacked version of the standard fl<num> script for navigating links. Afterall, who rests his fingers on the numpad. This script makes it possible to map your home row eg “aoeuidhtns” instead of “1234567890” thus making browsing more effective.

Javescript

var uzblid = 'uzbl_link_hint';
var uzbldivid = uzblid + '_div_container';
var doc = document;
var win = window;
var links = document.links;
var forms = document.forms;

//This variable is important: It configures what keys you want to use for jumping Eg:
//var charEnum = '0123456789'
//This string _has_ to be 10 units long!
var charEnum = 'hutenosadi'

try {
    HTMLElement.prototype.click = function() {
        if (typeof this.onclick == 'function') {
            this.onclick({
                type: 'click'
            });
        }
    };
} catch(e) {}
function keyPressHandler(e) {
    var kC = window.event ? event.keyCode: e.keyCode;
    var Esc = window.event ? 27 : e.DOM_VK_ESCAPE;
    if (kC == Esc) {
        removeAllHints();
    }
}
function elementPosition(el) {
    var up = el.offsetTop;
    var left = el.offsetLeft;
    var width = el.offsetWidth;
    var height = el.offsetHeight;
    while (el.offsetParent) {
        el = el.offsetParent;
        up += el.offsetTop;
        left += el.offsetLeft;
    }
    return [up, left, width, height];
}
function isVisible(el) {
    if (el == doc) {
        return true;
    }
    if (!el) {
        return false;
    }
    if (!el.parentNode) {
        return false;
    }
    if (el.style) {
        if (el.style.display == 'none') {
            return false;
        }
        if (el.style.visibility == 'hidden') {
            return false;
        }
    }
    return isVisible(el.parentNode);
}
function elementInViewport(el) {
    offset = elementPosition(el);
    var up = offset[0];
    var left = offset[1];
    var width = offset[2];
    var height = offset[3];
    return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset;
}
function removeAllHints() {
    var elements = doc.getElementById(uzbldivid);
    if (elements) {
        elements.parentNode.removeChild(elements);
    }
}
function generateHint(el, label) {
    var pos = elementPosition(el);
    var hint = doc.createElement('div');
    hint.setAttribute('name', uzblid);
    hint.innerText = label;
    hint.style.display = 'inline';
    hint.style.backgroundColor = '#B9FF00';
    hint.style.border = '2px solid #4A6600';
    hint.style.color = 'black';
    hint.style.zIndex = '1000';
    hint.style.fontSize = '9px';
    hint.style.fontWeight = 'bold';
    hint.style.lineHeight = '9px';
    hint.style.margin = '0px';
    hint.style.padding = '1px';
    hint.style.position = 'absolute';
    hint.style.left = pos[1] + 'px';
    hint.style.top = pos[0] + 'px';
    var img = el.getElementsByTagName('img');
    if (img.length > 0) {
        hint.style.left = pos[1] + img[0].width / 2 + 'px';
    }
    hint.style.textDecoration = 'none';
    hint.style.webkitBorderRadius = '6px';
    hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)';
    return hint;
}
function clickElem(item) {
    removeAllHints();
    if (item) {
        var name = item.tagName;
        if (name == 'A') {
            item.click();
            window.location = item.href;
        } else if (name == 'INPUT') {
            var type = item.getAttribute('type').toUpperCase();
            if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') {
                item.focus();
                item.select();
            } else {
                item.click();
            }
        } else if (name == 'TEXTAREA' || name == 'SELECT') {
            item.focus();
            item.select();
        } else {
            item.click();
            window.location = item.href;
        }
    }
}
function addLinks() {
    res = [[], []];
    for (var l = 0; l < links.length; l++) {
        var li = links[l];
        if (isVisible(li) && elementInViewport(li)) {
            res[0].push(li);
            res[1].push(li.innerText.toLowerCase());
        }
    }
    return res;
}
function addFormElems() {
    res = [[], []];
    for (var f = 0; f < forms.length; f++) {
        for (var e = 0; e < forms[f].elements.length; e++) {
            var el = forms[f].elements[e];
            if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) {
                res[0].push(el);
                if (el.getAttribute('value')) {
                    res[1].push(el.getAttribute('value').toLowerCase());
                } else {
                    res[1].push(el.getAttribute('name').toLowerCase());
                }
            }
        }
    }
    return res;
}
function genHintStr(i){
	strI = i + '';
	tmpHintStr = '';
	for (var x = 0; x < strI.length; x++){
		tmpHintStr = tmpHintStr + charEnum[strI[x]];
	}
	return tmpHintStr;
}
function readHintStr(strHint){
	var tmpHintInt = '';
	for (var x = 0; x <= strHint.length; x++){
		tmpHintInt = tmpHintInt + ((charEnum.indexOf(strHint[x])) + '');
	}
	return parseInt(tmpHintInt);
}

function reDrawHints(elems, len) {
    var hintdiv = doc.createElement('div');
    hintdiv.setAttribute('id', uzbldivid);
    hintdiv.style.opacity = '0.0';
    for (var i = 0; i < elems[0].length; i++) {
        var label = genHintStr(i);
        var n = label.length;
        for (n; n < len; n++) {
            label = 'h' + label;
        }
        if (elems[0][i]) {
            var h = generateHint(elems[0][i], label);
            hintdiv.appendChild(h);
        }
    }
    if (document.body) {
        document.body.appendChild(hintdiv);
        hintdiv.style.opacity = '0.7'
    }
}
function followLinks(follow) {
    var s = follow.split('');
    var linkId = follow;//parseInt(follow, 10);
    if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)');
    var linkelems = addLinks();
    var formelems = addFormElems();
    var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])];
    var len = (elems[0].length + '').length;
    var oldDiv = doc.getElementById(uzbldivid);
    var leftover = [[], []];
    //if (linkId + 1 && s.length == len && linkId < elems[0].length && linkId >= 0) {
    //    clickElem(elems[0][linkId]);
    //alert(readHintStr(linkId));
    //alert(readHintStr(linkId) + 1 && s.length == len && readHintStr(linkId) < elems[0].length && readHintStr(linkId) >= 0);
    if (readHintStr(linkId) + 1 && s.length == len && readHintStr(linkId) < elems[0].length && readHintStr(linkId) >= 0) {
        clickElem(elems[0][readHintStr(linkId)]);
    } else {
        for (var j = 0; j < elems[0].length; j++) {
            var b = true;
            for (var k = 0; k < s.length; k++) {
                b = b && elems[1][j].charAt(k) == s[k];
            }
            if (!b) {
                elems[0][j] = null;
                elems[1][j] = null;
            } else {
                leftover[0].push(elems[0][j]);
                leftover[1].push(elems[1][j]);
            }
        }
        if (leftover[0].length == 1) {
            clickElem(leftover[0][0]);
        } else if (!oldDiv) {
            if (linkId + 1 || s.length == 0) {
                reDrawHints(elems, len);
            } else {
                reDrawHints(leftover, len);
            }
        }
    }
}
followLinks('%s');

CONFIGURATION

change the charEnum variable in tho top of the script to the 10 keys you want to use. Important, the string has to be 10 units long.

Update

Since the follow_numbers.js script that comes with uzbl is still maturing, I created a minimalistic set of changes that can be easily applied into its current version.

First you need to define the desired characters that will be substituted for digits. Must be exactly 10 elements long:

var trans = ['j','f','k','d','l','s','u','r','m','c'];

You should insert it somewhere near the top, where the globals are defined.

Next, you locate the line that sets the text of the hint within the generateHint function, which looks like so:

hint.innerText = label;

and you precede it with the following code:

label = '' + label;
var s = '';
for(var x = 0; x < label.length; x++){
    s += trans[label[x]];
}
label = s;

And last, you stick the following right at the beginning of the followLinks function:

if(follow){
    var i = '';
    for(var x = 0; x < follow.length; x++){
        i += '' + trans.indexOf(follow[x]);
    }
    follow = i;
}

And you're done.

configurable-jump.txt · Last modified: 2016/08/31 14:10 (external edit)