// -----------------------------------------------------
// Title: Manage Access Keys
// version: 0.3
// Date: 2006-01-18
// Author: Gez Lemon
// Copyright (c) 2006, Juicy Studio
// Requires Greasemonkey 0.6.4
// -----------------------------------------------------
//
// ==UserScript==
// @name Manage Access Keys
// @namespace http://juicystudio.com/
// @description Reveals, and allows access keys to be set by the user.
// @include *
// ==/UserScript==

var bXML = (document.xmlVersion == null) ? false : true;
var strDomain = window.location.hostname;

var objBody = getElementsByName(document, 'body', bXML)[0];
var objHead = getElementsByName(document, 'head', bXML)[0];

if (!objBody || !objHead)
	return;

if (document.getElementById('jsgmAccessKeyContainer'))
	return;

objAccessKeys = document.evaluate("//*[@accesskey]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

if (!objAccessKeys.snapshotLength)
	return;

var objCSS = createElement('style');

objCSS.setAttribute('id', 'jsgmAccessKeyStyles');
objCSS.setAttribute('type', 'text/css');

var strCSS = getCSSString();

objCSS.appendChild(document.createTextNode(strCSS));
objHead.appendChild(objCSS);

document.addEventListener('keypress', toggleDisplay, false);

displayAccessKeys();

function displayAccessKeys()
{
	var objAccess = createElement('div', bXML);
	var objList = createElement('dl', bXML);
	
	for (var iCounter=0; iCounter<objAccessKeys.snapshotLength; iCounter++)
	{
		var strValue = '', strKey = '';
	
		var objKey = objAccessKeys.snapshotItem(iCounter);
	
		if (objKey.nodeName.toLowerCase() == 'input')
		{
			strLabel = document.evaluate("//label[@for='" + objKey.getAttribute('id') + "']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
			if (strLabel)
			{
				strValue = strLabel.title;
				if (!strValue)
					strValue = strLabel.textContent;
			}
		}
	
		if (!strValue && objKey.firstChild && objKey.firstChild.tagName)
		{
			if (objKey.firstChild.tagName.toLowerCase() == 'img')
			{
				strValue = objKey.firstChild.getAttribute('alt');
				if (!strValue)
					strValue = objKey.firstChild.getAttribute('title');
				if (!strValue)
					strValue = objKey.getAttribute('src');
			}
		}

		if (!strValue)
			strValue = objKey.textContent;
		if (!strValue)
			strValue = objKey.getAttribute('title');
		if (!strValue)
			strValue = objKey.getAttribute('alt');
		if (!strValue)
			strValue = objKey.getAttribute('name');
		if (!strValue)
			strValue = objKey.getAttribute('id');
		if (!strValue)
			strValue = objKey.getAttribute('href');
		if (!strValue)
			strValue = objKey.getAttribute('value');
		if (!strValue)
			strValue = objKey.getAttribute('Unknown');

		var strCookie = strValue.replace(/\W/ig, '');

		var objTerm = createElement('dt', bXML);
		var objDFN = createElement('dfn', bXML);
	
		
		strKey = objKey.getAttribute('accesskey').toUpperCase();
		strDisplayKey = readCookie(strCookie);

		if (!strDisplayKey)
		{
			createCookie(strCookie + 'orig', strKey, 365);
			strDisplayKey = strKey;
		}

		objKey.setAttribute('accesskey', strDisplayKey);
		objDFN.setAttribute('title', 'Access key: ' + strDisplayKey);
		objDFN.appendChild(document.createTextNode(strDisplayKey));
		
		objTerm.appendChild(objDFN);
	
		var objDefinition = createElement('dd');
	
		if (objKey.getAttribute('href'))
		{
			var objAnchor = createElement('a', bXML);
	
			objAnchor.appendChild(document.createTextNode(strValue));
			objAnchor.setAttribute('href', objKey.getAttribute('href'));
			objDefinition.appendChild(objAnchor);
		}
		else
			objDefinition.appendChild(document.createTextNode(strValue));
	
		objList.appendChild(objTerm);
		objList.appendChild(objDefinition);
	}
	
	var objEdit = createElement('input', bXML);

	objEdit.setAttribute('type', 'button');
	objEdit.setAttribute('value', 'Edit');
	objEdit.setAttribute('id', 'jsgmEdit');
	objEdit.addEventListener('keypress', jsgmEditKeys, false);
	objEdit.addEventListener('click', jsgmEditKeys, false);
	
	var objRestore = createElement('input', bXML);

	objRestore.setAttribute('type', 'button');
	objRestore.setAttribute('value', 'Restore Author Defaults');
	objRestore.setAttribute('id', 'jsgmRestore');
	objRestore.addEventListener('keypress', jsgmRestoreKeys, false);
	objRestore.addEventListener('click', jsgmRestoreKeys, false);
	
	objList.setAttribute('id', 'jsgmAccessKeyList');
	objExisting = document.getElementById('jsgmAccessKeyContainer');
	objAccess.setAttribute('id', 'jsgmAccessKeyContainer');
	objAccess.appendChild(objList);
	objAccess.appendChild(objEdit);
	objAccess.appendChild(objRestore);
	
	var objToggle = createElement('span', bXML);

	objToggle.setAttribute('id', 'jsgmToggle');
	objToggle.appendChild(document.createTextNode(' ['));

	var objKey = createElement('kbd', bXML);

	objKey.appendChild(document.createTextNode('SHIFT'));
	objToggle.appendChild(objKey);
	objToggle.appendChild(document.createTextNode(']+['));

	var objKey = createElement('kbd', bXML);

	objKey.appendChild(document.createTextNode('ESC'));
	objToggle.appendChild(objKey);
	objToggle.appendChild(document.createTextNode('] to toggle'));
	objAccess.appendChild(objToggle);

	if(objExisting == null)
		objBody.appendChild(objAccess);
	else
		objBody.replaceChild(objAccess, objExisting);
}

function getElementsByName(objNode, strElement, bXML)
{
	if (bXML)
		return objNode.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', strElement);
	else
		return objNode.getElementsByTagName(strElement);
}

function createElement(strElement, bXML)
{
	if (bXML)
		return document.createElementNS('http://www.w3.org/1999/xhtml', strElement);
	else
		return document.createElement(strElement);
}

function jsgmEditKeys(objEvent)
{
	if (objEvent && objEvent.type == 'keypress')
		if (objEvent.keyCode != 13 && objEvent.keyCode != 32)
			return true;

	var strKey, strContent;
	var objList = document.getElementById('jsgmAccessKeyList');

	do 
	{
		var objAccessKeys = getElementsByName(objList, 'dfn', bXML);

		for (var iCounter=0; iCounter<objAccessKeys.length; iCounter++)
		{
			var objDefinition = objAccessKeys[iCounter].parentNode.nextSibling.firstChild;
			var objInput = createElement('input', bXML);
			var objLabel = createElement('label',bXML);

			if (objDefinition.nodeType == 3)
				strContent = objDefinition.data;
			else
				strContent = objDefinition.firstChild.data;

			strKey = objAccessKeys[iCounter].firstChild.data;
			objInput.setAttribute('size', '1');
			objInput.setAttribute('maxlength', '1');
			objInput.setAttribute('value', strKey);
			objInput.setAttribute('size', '1');
			objInput.setAttribute('id', 'jsgm' + strKey);
			objInput.setAttribute('name', 'jsgm' + strKey);
			objInput.addEventListener('keypress', jsgmActivateKey, false);
			objLabel.setAttribute('for', 'jsgm' + strKey);
			objLabel.appendChild(document.createTextNode(strContent));
			objAccessKeys[iCounter].parentNode.replaceChild(objInput, objAccessKeys[iCounter]);
			objDefinition.parentNode.replaceChild(objLabel, objDefinition);
		}
	} while (objAccessKeys.length > 0);
	
	var objEdit = document.getElementById('jsgmEdit');
	objEdit.setAttribute('value', 'Update');
	objEdit.addEventListener('keypress', jsgmUpdateKeys, false);
	objEdit.addEventListener('click', jsgmUpdateKeys, false);

	if (objEvent && objEvent.preventDefault)
		objEvent.preventDefault();
}

function jsgmActivateKey(objEvent)
{
	if (objEvent && objEvent.type == 'keypress')
		if (objEvent.keyCode != 13 && objEvent.keyCode != 32)
			return true;
	
	document.getElementById('jsgmEdit').click();
}

function jsgmUpdateKeys(objEvent)
{
	if (objEvent && objEvent.type == 'keypress')
		if (objEvent.keyCode != 13 && objEvent.keyCode != 32)
			return true;

	var strValue, strCookie;
	var objList = document.getElementById('jsgmAccessKeyList');

	var objAccessKeys = getElementsByName(objList, 'input', bXML);

	for (var iCounter=0; iCounter<objAccessKeys.length; iCounter++)
	{
		var objDefinition = objAccessKeys[iCounter].parentNode.nextSibling.firstChild;

		if (objDefinition.nodeType == 3)
			strCookie = objDefinition.data.replace(/\W/ig, '');
		else
			strCookie = objDefinition.firstChild.data.replace(/\W/ig, '');

		strValue = objAccessKeys[iCounter].value;
		createCookie(strCookie, strValue, 365);
	}

	displayAccessKeys();
}

function jsgmRestoreKeys(objEvent)
{
	if (objEvent && objEvent.type == 'keypress')
		if (objEvent.keyCode != 13 && objEvent.keyCode != 32)
			return true;

	var strCookie;
	var objList = document.getElementById('jsgmAccessKeyList');

	var objAccessKeys = getElementsByName(objList, 'dfn', bXML);

	for (var iCounter=0; iCounter<objAccessKeys.length; iCounter++)
	{
		var objDefinition = objAccessKeys[iCounter].parentNode.nextSibling.firstChild;

		if (objDefinition.nodeType == 3)
			strCookie = objDefinition.data.replace(/\W/ig, '');
		else
			strCookie = objDefinition.firstChild.data.replace(/\W/ig, '');

		strOrig = readCookie(strCookie + 'orig');
		createCookie(strCookie, strOrig, 365);
	}

	displayAccessKeys();
}

function toggleDisplay(objEvent)
{
	if (objEvent.keyCode != 27)
		return true;

	if (objEvent.shiftKey)
	{
		var objContainer = document.getElementById('jsgmAccessKeyContainer');
	
		if (objContainer)
		{
			if (objContainer.style.display == 'block' || objContainer.style.display == '')
				objContainer.style.display = 'none';
			else
				objContainer.style.display = 'block';
		}
	}
}

function createCookie(strName, strValue, iDays)
{
	if (iDays)
	{
		var dtDate = new Date();
		dtDate.setTime(dtDate.getTime()+(iDays * 24 * 60 * 60 * 1000));
		var strExpires = '; expires=' + dtDate.toGMTString();
	}
	else
		var strExpires = '';

	document.cookie = strName + '=' + strValue + strExpires + '; path=/';
}

function readCookie(strName)
{
	var nameEQ = strName + '=';
	var arCookies = document.cookie.split(';');
	for(var iCounter=0; iCounter<arCookies.length; iCounter++)
	{
		var strCookie = arCookies[iCounter];
		while (strCookie.charAt(0)==' ')
			strCookie = strCookie.substring(1, strCookie.length);
		if (strCookie.indexOf(nameEQ) == 0)
			return strCookie.substring(nameEQ.length, strCookie.length);
	}
	return null;
}

function getCSSString()
{
	var strCSS = 'html body { margin-bottom: 6em; }' +
				'div#jsgmAccessKeyContainer' +
				'{' +
					'position: fixed;' +
					'display: block;' +
					'left: 0;' +
					'right: 0;' +
					'bottom: 0;' +
					'top: auto;' +
					'border-top: 5px double #630;' +
					'border-bottom: 5px double #630;' +
					'background: #ffc;' +
					'color: #000;' +
					'margin: 0;' +
					'padding: 0.2em 1em 0.5em 1em;' +
					'width: 100%;' +
					'font-family: arial, Verdana, helvetica, sans-serif;' +
					'font-size: 0.9em;' +
					'overflow: visible;' +
					'z-index: 99999;' +
					'text-align: left;' +
				'}' +
				'div#jsgmAccessKeyContainer dl' +
				'{' +
					'margin: 0;' +
					'padding: 0;' +
				'}' +
				'div#jsgmAccessKeyContainer dt, div#jsgmAccessKeyContainer dd' +
				'{' +
					'display: inline;' +
					'background-color: transparent;' +
					'color: #000;' +
					'margin: 0;' +
					'padding: 0;' +
				'}' +
				'div#jsgmAccessKeyContainer dd a' +
				'{' +
					'background-color: transparent;' +
					'color: #00c;' +
					'text-decoration: underline;' +
					'font-weight: normal;' +
				'}' +
				'div#jsgmAccessKeyContainer dd a:hover, div#jsgmAccessKeyContainer dd a:focus' +
				'{' +
					'background-color: #fc0;' +
					'color: #000;' +
					'text-decoration: underline;' +
				'}' +
				'div#jsgmAccessKeyContainer dd' +
				'{' +
					'margin: 0 0.5em;' +
					'font-weight: normal;' +
				'}' +
				'div#jsgmAccessKeyContainer dt { font-weight: bold; }' +
				'div#jsgmAccessKeyContainer input[type=button] { margin-right: 0.5em; }';

	return strCSS;
}
