make icon setting configurable
[uzbl-mobile] / examples / scripts / linkfollow.js
index 382d33d..a348af9 100644 (file)
@@ -2,28 +2,43 @@
 // requires http://github.com/DuClare/uzbl/commit/6c11777067bdb8aac09bba78d54caea04f85e059
 //
 // first, it needs to be loaded before every time it is used.
-// One way would be to use something like load_start_handler to send
-// "act script /usr/share/examples/scripts/linkfollow.js"
-// (currently, it is recommended to use load_finish_handler since the JS code seems to get
-// flushed. Using a load_start_handler with a 1s delay works but not always)
+// One way would be to use the load_commit_handler:
+// set load_commit_handler = sh 'echo "script /usr/share/uzbl/examples/scripts/linkfollow.js" > "$4"'
 //
 // when script is loaded, it can be invoked with
-// bind f* = js hints.set("%s")
-// bind f_ = js hints.follow("%s")
+// bind f* = js hints.set("%s",   hints.open)
+// bind f_ = js hints.follow("%s",hints.open)
 //
 // At the moment, it may be useful to have way of forcing uzbl to load the script
-// bind :lf = script /usr/share/examples/scripts/linkfollow.js
+// bind :lf = script /usr/share/uzbl/examples/scripts/linkfollow.js
 //
-// To enable hint highlighting, add:
+// The default style for the hints are pretty ugly, so it is recommended to add the following
+// to config file
 // set stylesheet_uri = /usr/share/uzbl/examples/data/style.css
 //
 // based on follow_Numbers.js
 //
 // TODO: fix styling for the first element
-// TODO: load the script as soon as the DOM is ready
+// TODO: emulate mouseover events when visiting some elements
+// TODO: rewrite the element->action handling
 
 
 function Hints(){
+
+  // Settings
+  ////////////////////////////////////////////////////////////////////////////
+
+  // if set to true, you must explicitly call hints.follow(), otherwise it will
+  // follow the link if there is only one matching result
+  var requireReturn = true;
+
+  // Case sensitivity flag
+  var matchCase = "i";
+
+  // For case sensitive matching, uncomment:
+  // var matchCase = "";
+
+
   var uzblid = 'uzbl_hint';
   var uzblclass = 'uzbl_highlight';
   var uzblclassfirst = 'uzbl_h_first';
@@ -45,18 +60,14 @@ function Hints(){
       up += el.offsetTop;
       left += el.offsetLeft;
     }
-    return [up, left, width, height];
+    return {up: up, left: left, width: width, height: height};
   }
 
-  function elementInViewport(offset) {
-    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 elementInViewport(p) {
+    return  (p.up < window.pageYOffset + window.innerHeight && 
+            p.left < window.pageXOffset + window.innerWidth && 
+            (p.up + p.height) > window.pageYOffset && 
+            (p.left + p.width) > window.pageXOffset);
   }
 
   function isVisible(el) {
@@ -74,17 +85,26 @@ function Hints(){
     return isVisible(el.parentNode);
   }
 
-  var hintable = "//a[@href] | //img | //input";
+  // the vimperator defaults minus the xhtml elements, since it gave DOM errors
+  var hintable = " //*[@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";
 
   function Matcher(str){
     var numbers = str.replace(/[^\d]/g,"");
-    var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,"i")});
+    var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,matchCase)});
     this.test = test;
     this.toString = toString;
     this.numbers = numbers;
+    function matchAgainst(element){
+      if(element.node.nodeName == "INPUT"){
+        return element.node.value;
+      } else {
+        return element.node.textContent;
+      }
+    }
     function test(element) {
       // test all the regexp
-      return words.every(function (regex) { return element.node.textContent.match(regex)});
+      var item = matchAgainst(element);
+      return words.every(function (regex) { return item.match(regex)});
     }
   }
 
@@ -93,8 +113,10 @@ function Hints(){
     this.node = node;
     this.isHinted = false;
     this.position = pos;
+    this.num = 0;
 
     this.addHint = function (labelNum) {
+      // TODO: fix uzblclassfirst
       if(!this.isHinted){
         this.node.className += " " + uzblclass;
       }
@@ -104,8 +126,8 @@ function Hints(){
       var hintNode = doc.createElement('div');
       hintNode.name = uzblid;
       hintNode.innerText = labelNum;
-      hintNode.style.left = this.position[1] + 'px';
-      hintNode.style.top =  this.position[0] + 'px';
+      hintNode.style.left = this.position.left + 'px';
+      hintNode.style.top =  this.position.up + 'px';
       hintNode.style.position = "absolute";
       doc.body.firstChild.appendChild(hintNode);
         
@@ -156,7 +178,7 @@ function Hints(){
     }
   }
 
-  function update(str) {
+  function update(str,openFun) {
     var match = new Matcher(str);
     hintdiv = createHintDiv();
     var i = 1;
@@ -167,11 +189,16 @@ function Hints(){
       } else {
         n.removeHint();
       }});
+    if(!requireReturn){
+      if(i==2){ //only been incremented once
+        follow(str,openFun);
+      }
+    }
   }
 
-  function hint(str){
+  function hint(str,openFun){
     if(str.length == 0) init();
-    update(str);
+    update(str,openFun);
   }
 
   function keyPressHandler(e) {
@@ -183,9 +210,28 @@ function Hints(){
     }
   }
 
-  function follow(str){
-    var m = new Matcher(str);
+  this.openNewWindow = function(item){
+    // TODO: this doesn't work yet
+    item.className += " uzbl_follow";
+    window.open(item.href,"uzblnew","");
+  }
+  this.open = function(item){
+    simulateMouseOver(item);
+    item.className += " uzbl_follow";
+    window.location = item.href;
+  }
 
+  function simulateMouseOver(item){
+    var evt = doc.createEvent("MouseEvents");
+    evt.initMouseEvent("MouseOver",true,true,
+        doc.defaultView,1,0,0,0,0,
+        false,false,false,false,0,null);
+    return item.dispatchEvent(evt);
+  }
+
+
+  function follow(str,openFunction){
+    var m = new Matcher(str);
     var items = visible.filter(function (n) { return n.isHinted });
     clear();
     var num = parseInt(m.numbers,10);
@@ -195,13 +241,10 @@ function Hints(){
       var item = items[0].node;
     }
     if (item) {
-      item.style.borderStyle = "dotted";
-      item.style.borderWidth = "thin";
-
       var name = item.tagName;
       if (name == 'A') {
         if(item.click) {item.click()};
-        window.location = item.href;
+          openFunction(item);
       } else if (name == 'INPUT') {
         var type = item.getAttribute('type').toUpperCase();
         if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') {
@@ -215,15 +258,14 @@ function Hints(){
         item.select();
       } else {
         item.click();
-        window.location = item.href;
+        openFunction(item);
       }
     }
   }
 }
 
 var hints = new Hints();
-//document.attachEvent("onKeyUp",hints.keyPressHandler);
 
-// vim:set et tw=2:
+// vim:set et sw=2: