// -----------------------------------------------------
// Title: Twitter Focus
// version: 0.1
// Date: 2009-01-11
// Author: Gez Lemon
// Copyright (c) 2009, Juicy Studio
// Requires Greasemonkey 0.6.4 or higher
// -----------------------------------------------------
//
// ==UserScript==
// @name Twitter Focus
// @namespace http://juicystudio.com/
// @description Puts the favourite and reply icons into the tab order, and removes redundant anchors from tab order.
// @include http://twitter.com/*
// ==/UserScript==

// CSS to hide the context information, such as "this update", and the name of the user
function getCSSString()
{
	var strCSS = 'span.context' +
				'{' +
					'position: absolute !important;' +
					'left: -999em !important;' +
					'width: 1em !important;' +
					'overflow: hidden;' +
				'}';

	return strCSS;
}

// Function to get elements by class name
function getElementsByClassName(objElement, strTagName, strClassName)
{
	var objCollection = objElement.getElementsByTagName(strTagName);
	var arReturn = [];
	var strClass, arClass, iClass;

	for (var iCounter=0; iCounter<objCollection.length; iCounter++)
	{
		strClass = objCollection[iCounter].className;
		if (strClass)
		{
			arClass = strClass.split(' ');
			for (iClass=0; iClass<arClass.length; iClass++)
			{
				if (arClass[iClass] == strClassName)
				{
					arReturn.push(objCollection[iCounter]);
					break;
				}
			}
		}
	}

	return (arReturn);
}

// Toggle favourite links
function toggleFave(objEvent)
{
	var objAnchor = objEvent.target;

	if (objAnchor.firstChild.data.substr(0, 1) == 'F')
	{
		objAnchor.replaceChild(document.createTextNode('Un-favorite'), objAnchor.firstChild);
	}
	else
	{
		objAnchor.replaceChild(document.createTextNode('Favorite'), objAnchor.firstChild);
	}
}

function makeFocusable(objTimeline)
{
	var objAvatar, objActions, objAnchors, objContext;
	var strFirst, strRest, arSentence;
	var iCounter, iInner, iWord, iLimit, iAnchorLength, iWordLength;

	objAvatar = objTimeline.getElementsByTagName('img');
	objActions = getElementsByClassName(objTimeline, '*', 'actions');
	iLimit = objAvatar.length;

	// Remove link around the avatars from the keyboard tab order
	for (iCounter=0; iCounter<iLimit; iCounter++)
	{
		objAvatar[iCounter].parentNode.setAttribute('tabindex', '-1');
	}

	iLimit = objActions.length;

	// Make reply and favorite links keyboard accessible
	for (iCounter=0; iCounter<iLimit; iCounter++)
	{
		objActions[iCounter].removeAttribute('class');
		objAnchors = objActions[iCounter].getElementsByTagName('a');
		iAnchorLength = objAnchors.length;

		// Find links in the actions section
		for (iInner=0; iInner<iAnchorLength; iInner++)
		{
			// Move the accessible text from the title attribute into the link phrase
			arSentence = objAnchors[iInner].getAttribute('title').split(' ');
			// First word is the action
			strFirst = arSentence[0].substr(0, 1).toUpperCase() + arSentence[0].substr(1, arSentence[0].length) + ' ';
			// The rest of the sentence contains the context
			strRest = '';
			iWordLength = arSentence.length;
			for (iWord=1; iWord<iWordLength; iWord++)
			{
				strRest += ' ' + arSentence[iWord];
			}

			// Put the context in a span (hidden with CSS)
			objContext = document.createElement('span');
			objContext.appendChild(document.createTextNode(strRest));
			objContext.setAttribute('class', 'context');

			objAnchors[iInner].removeAttribute('title');
			objAnchors[iInner].replaceChild(document.createTextNode(strFirst), objAnchors[iInner].firstChild);
			objAnchors[iInner].appendChild(objContext);

			// Set anchor to put in keyboard tab order if missing
			if (!objAnchors[iInner].getAttribute('href'))
			{
				objAnchors[iInner].setAttribute('href', '#');
				objAnchors[iInner].parentNode.insertBefore(document.createElement('br'), objAnchors[iInner].nextSibling);
				// Add event handler to toggle text
				objAnchors[iInner].addEventListener('click', toggleFave, false);
			}
		}
	}
}

function updateTweets(objEvent)
{
	var objTimeline;

	if (objEvent.target.nodeType == 1)
	{
		objTimeline = document.getElementById('timeline');
		makeFocusable(objTimeline);
	}
}

function setup()
{
	var objTimeline = document.getElementById('timeline');
	var objHead = document.getElementsByTagName('head')[0];
	var objCSS = document.createElement('style');
	var strCSS = getCSSString();

	// Add CSS to hide contextual information
	objCSS.setAttribute('type', 'text/css');

	objCSS.appendChild(document.createTextNode(strCSS));
	objHead.appendChild(objCSS);

	if (!objTimeline)
	{
		return 1;
	}

	// Single tweets are already keyboard acccessible
	if (document.getElementById('tabMenu') || document.getElementById('primary_nav'))
	{
		makeFocusable(objTimeline);
		document.addEventListener("DOMNodeInserted", updateTweets, false);
		document.addEventListener("DOMSubtreeModified", updateTweets, false);
	}

	return 1;
}

// Setup the basic Twitter page.
setup();