aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--README2
-rw-r--r--examples/config/config8
-rw-r--r--examples/data/scripts/follow.js (renamed from examples/data/scripts/follow_Numbers.js)76
-rw-r--r--examples/data/scripts/follow_Numbers_Strings.js212
5 files changed, 67 insertions, 233 deletions
diff --git a/AUTHORS b/AUTHORS
index 401fcb7..165eae0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -40,7 +40,7 @@ In alphabetical order:
Jake Probst <jake.probst@gmail.com> - uzbl_tabbed: multiline tablist
James S Wheaton (uranther) - zoom level, test framework
Jan Kolkmeier (jouz) - scrolling, link following
- Jason Woofenden (JasonWoof) - geometry=maximized
+ Jason Woofenden (JasonWoof) - geometry=maximized, link following
Laurence Withers (lwithers) - talk_to_socket
Mark Nevill - misc patches
Mason Larobina - uzbl-tabbed.py, cookie-daemon, event-manager&plugins, ...
diff --git a/README b/README
index 09fd240..0a22b55 100644
--- a/README
+++ b/README
@@ -354,6 +354,8 @@ file).
* `enforce_96_dpi`: Enforce a resolution of 96 DPI (default 1).
* `caret_browsing`: Whether the caret is enabled in the text portion of pages
(default 0).
+* `follow_hint_keys`: keys for keyboard-based navigation and link
+ highlighting
#### Constants (not dumpable or writeable)
diff --git a/examples/config/config b/examples/config/config
index eb17813..d58d0a5 100644
--- a/examples/config/config
+++ b/examples/config/config
@@ -295,9 +295,11 @@ set toggle_cmd_ins = @toggle_modes command insert
@cbind u = spawn @scripts_dir/load_url_from_bookmarks.sh
# --- Link following (similar to vimperator and konqueror) ---
-@cbind fl* = script @scripts_dir/follow_Numbers.js %s
-# Or number with strings instead of numbers:
-@cbind fL* = script @scripts_dir/follow_Numbers_Strings.js %s
+# Set custom keys you wish to use for navigation. Some common examples:
+set follow_hint_keys = qwerty
+#set follow_hint_keys = asdfghjkl;
+#set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234
+@cbind f* = script @scripts_dir/follow.js '%s @{follow_hint_keys}'
# --- Form filler binds ---
# this script allows you to configure (per domain) values to fill in form
diff --git a/examples/data/scripts/follow_Numbers.js b/examples/data/scripts/follow.js
index 00b279e..12b3765 100644
--- a/examples/data/scripts/follow_Numbers.js
+++ b/examples/data/scripts/follow.js
@@ -17,10 +17,6 @@ var doc = document;
var win = window;
var links = document.links;
var forms = document.forms;
-
-//Reset keycmd, modcmd and return to default mode.
-function clearKeycmd() { Uzbl.run('set mode ='); }
-
//Make onlick-links "clickable"
try {
HTMLElement.prototype.click = function() {
@@ -106,19 +102,21 @@ function generateHint(el, label) {
hint.style.fontWeight = 'bold';
hint.style.lineHeight = '9px';
hint.style.margin = '0px';
+ hint.style.width = 'auto'; // fix broken rendering on w3schools.com
hint.style.padding = '1px';
hint.style.position = 'absolute';
hint.style.zIndex = '1000';
+ // hint.style.textTransform = 'uppercase';
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';
- }
+ // var img = el.getElementsByTagName('img');
+ // if (img.length > 0) {
+ // hint.style.top = pos[1] + img[0].height / 2 - 6 + 'px';
+ // }
hint.style.textDecoration = 'none';
- hint.style.webkitBorderRadius = '6px';
+ // hint.style.webkitBorderRadius = '6px'; // slow
// Play around with this, pretty funny things to do :)
- hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)';
+ // hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)';
return hint;
}
//Here we choose what to do with an element if we
@@ -127,7 +125,6 @@ function generateHint(el, label) {
//but at least set the href of the link. (needs some improvements)
function clickElem(item) {
removeAllHints();
- clearKeycmd();
if (item) {
var name = item.tagName;
if (name == 'A') {
@@ -193,26 +190,66 @@ function reDrawHints(elems, chars) {
document.body.appendChild(hintdiv);
}
}
+// pass: number of keys
+// returns: key length
+function labelLength(n) {
+ var oldn = n;
+ var keylen = 0;
+ if(n < 2) {
+ return 1;
+ }
+ n -= 1; // our highest key will be n-1
+ while(n) {
+ keylen += 1;
+ n = Math.floor(n / charset.length);
+ }
+ return keylen;
+}
+// pass: number
+// returns: label
+function intToLabel(n) {
+ var label = '';
+ do {
+ label = charset.charAt(n % charset.length) + label;
+ n = Math.floor(n / charset.length);
+ } while(n);
+ return label;
+}
+// pass: label
+// returns: number
+function labelToInt(label) {
+ var n = 0;
+ var i;
+ for(i = 0; i < label.length; ++i) {
+ n *= charset.length;
+ n += charset.indexOf(label[i]);
+ }
+ return n;
+}
//Put it all together
function followLinks(follow) {
+ // if(follow.charAt(0) == 'l') {
+ // follow = follow.substr(1);
+ // charset = 'thsnlrcgfdbmwvz-/';
+ // }
var s = follow.split('');
- var linknr = parseInt(follow, 10);
+ var linknr = labelToInt(follow);
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 len = labelLength(elems[0].length);
var oldDiv = doc.getElementById(uzbldivid);
var leftover = [[], []];
- if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) {
+ if (s.length == len && linknr < elems[0].length && linknr >= 0) {
clickElem(elems[0][linknr]);
} else {
for (var j = 0; j < elems[0].length; j++) {
var b = true;
- var label = j + '';
+ var label = intToLabel(j);
var n = label.length;
for (n; n < len; n++) {
- label = '0' + label;
+ label = charset.charAt(0) + label;
}
for (var k = 0; k < s.length; k++) {
b = b && label.charAt(k) == s[k];
@@ -225,4 +262,9 @@ function followLinks(follow) {
reDrawHints(leftover, s.length);
}
}
-followLinks('%s');
+
+//Parse input: first argument is user input, second is defined hint keys.
+var args = '%s'.split(' ');
+var charset = args[1];
+
+followLinks(args[0]);
diff --git a/examples/data/scripts/follow_Numbers_Strings.js b/examples/data/scripts/follow_Numbers_Strings.js
deleted file mode 100644
index e50da5d..0000000
--- a/examples/data/scripts/follow_Numbers_Strings.js
+++ /dev/null
@@ -1,212 +0,0 @@
-var uzblid = 'uzbl_link_hint';
-var uzbldivid = uzblid + '_div_container';
-var doc = document;
-var win = window;
-var links = document.links;
-var forms = document.forms;
-
-//Reset keycmd, modcmd and return to default mode.
-function clearKeycmd() { Uzbl.run('set mode ='); }
-
-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();
- clearKeycmd();
- 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 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 = i + '';
- var n = label.length;
- for (n; n < len; n++) {
- label = '0' + 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 linknr = 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 (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) {
- clickElem(elems[0][linknr]);
- } 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 (linknr + 1 || s.length == 0) {
- reDrawHints(elems, len);
- } else {
- reDrawHints(leftover, len);
- }
- }
- }
-}
-followLinks('%s');