// ==UserScript==
// @name           Helgon.net access keys
// @namespace      http://www.lysator.liu.se/~jhs/userscript
// @description    Adds keyboard shortcuts to menu entries and prev/next links (Alt+< and Alt+z) for gallery items, diary entries and subpages ("Visar sida: 1 [2] 3") at Helgon.net.
// @include        http://*helgon.net/*
// ==/UserScript==

// Registers all dynamically allocated keyboard bindings (avoiding duplicates)
var reserved = { '<':1, Z:1 };

// Makes a shortcut < and Z respectively for passed link nodes, nicely colored.
function prev( node ) { short( node, '<', '#FFC0CB' ); }
function next( node ) { short( node, 'Z', '#90EE90' ); }

// Make a shortcut `key' for link node `node', colored in (HTML color) `color'.
// Only `node' is mandatory; keys will be allocated by node contents (first not
// already bound letter of the link text content) and a color will only be set,
// if passed along (pass null as the key, if you want to set color but no key).
// (won't register any key at all, if all available letters were already taken)
function short( node, key, color )
{
  var accesskey = 'Alt+'; // browsers have different ideas about accesskeys
  if( navigator.userAgent.match( /opera/i ) )
    accesskey = 'Shift+Esc followed by ';
  else if( navigator.userAgent.match( /macintosh/i ) )
    accesskey = 'Control+';

  if( !key )
  {
    var letters = node.textContent.replace( /\W/g, '' ), i; // first word char
    for( i=0; i<letters.length; i++ )
    {
      key = letters.charAt( i ); // will this letter do?
      if( !reserved[key.toLowerCase()] ) break; // found the first free letter
      key = null; // try, try again!
    }
    if( !key ) return; // too bad; don't do anything at all.
  }
  var re = new RegExp( '((<[^>]*>)*[^<'+key+']*)'+key, 'i' ); // find our key
  node.innerHTML = node.innerHTML.replace( re, '$1<u>'+key+'</u>' ); // mark!
  reserved[key.toLowerCase()] = 1; // taken!
  node.title = 'Hotkey: '+ accesskey + key.toLowerCase(); // usability hint
  node.accessKey = key.toUpperCase();
  if( color ) node.style.color = color; // colorize the link as applicable
}

// Find all Header links and assign access keys to them by link text content

var trs = document.getElementsByTagName( 'tr' ), as, i, a;
for( i=0; i<trs.length; i++ )
  if( trs[i].className.match( 'middleframe' ) )
  {
    as = trs[i].getElementsByTagName( 'a' );
    for( i=0; i<as.length; i++ )
      short( as[i] );
    break;
  }

// Find previous/next links

as = document.links;
for( i = 0; i < as.length; i++ )
{
  a = as[i];
  if( a.href.match( 'ction=prev' ) ) prev( a );
  if( a.href.match( 'ction=next' ) ) next( a );
}

// Find subpages

textnodes = document.evaluate("//text()", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

for( i=0; i<textnodes.snapshotLength; i++ )
{
  node = textnodes.snapshotItem(i);
  s = node.data;
  if( s.match( 'Visar sida:' ) )
  {
    var subpageCell = node.parentNode; // the subpage cell
    as = subpageCell.getElementsByTagName('a'); // Find all subpage links
    for( i=0; i<as.length; i++ )
    {
      if( location.href == as[i].href ) // found the current page
      {
	if( i )
	  prev( as[i-1] );
	if( i<as.length-1 )
	  next( as[i+1] );
	return;
      }
    }
    // if we still haven't found anything, then we must be on the first page
    return next( as[1] );  // no need to loop through any more text nodes
  }
}
