The importance of keyboard navigation

by therider

While browsing online portfolios of a few well known photographers I noticed how desperately those fancy designs needed a very basic feature – keyboard navigation. Thanks to the deluge of digital photos everywhere and the tendency of people to upload a gazillion of them after every party or a trip, we no more have the time or patience to point and click the “next” link. Picasa, smugmug and facebook among a few others have already put this most important feature in place, making it a pleasure to browse images quickly. Too bad flickr did not yet, but it is nothing a greasemonkey userscript can’t fix.

Then I wanted this on my own photoblog as well. I thought about using jQuery but since pixelpost uses prototype, I looked up the syntax and quickly came up with this small piece of code:

Event.observe(document, "keypress", function(e) {
  // 37 for left, 39 for right
  var cur = location.href;
  var prev = $$("#image-nav-prevlink a")[0].href;
  var next = $$("#image-nav-nextlink a")[0].href;
  switch(e.keyCode) {
    case 37:
      if(cur != prev) { location.href = prev; }
      break;
    case 39:
      if(cur != next) { location.href = next; }
      break;
  }
});

10 minutes of effort. 10x better usability.


Update: I made a flickr photostream navigator userscript in a similar fashion but had a critical bug. When an input box is focused, arrow keys should not trigger another page load. The same bug is present in the above code as well. Thanks to my good friend Francesco for catching this early. I fixed them both. The above code after correction looks like:

var PB = { Globals:{} };
PB.Globals.inputHasFocus = false;

Event.observe(document, "keydown", function(e) {
  // console.log("any input has focus: " + PB.Globals.inputHasFocus);
  if(PB.Globals.inputHasFocus) { return; }
  // 37 for left, 39 for right
  var cur = location.href;
  var prev = $$("#image-nav-prevlink a")[0].href;
  var next = $$("#image-nav-nextlink a")[0].href;
  switch(e.keyCode) {
    case 37:
      // for some reason the inactive link looks like "...showimage="
      if(cur != prev && prev.match("showimage=[0-9]")) { location.href = prev; }
      break;
    case 39:
      if(cur != next && next.match("showimage=[0-9]")) { location.href = next; }
      break;
  }
});

Event.observe(window, "load", function() {
  $$("input.input, textarea").each(function(inp){
    inp.observe('focus', function(e){
      // console.log(e);
      PB.Globals.inputHasFocus = true;
    });
    inp.observe('blur', function(e){
      // console.log(e);
      PB.Globals.inputHasFocus = false;
    });
  });
});
About these ads