O'Reilly Hacks
oreilly.comO'Reilly NetworkSafari BookshelfConferences Sign In/My Account | View Cart   
Book List Learning Lab PDFs O'Reilly Gear Newsletters Press Room Jobs  


 
Buy the book!
Greasemonkey Hacks
By Mark Pilgrim
November 2005
More Info

HACK
#76
Make Google More Accessible for Low-Vision Users
Change Google's layout to make it easier for low-vision users to read
The Code
[Discuss (0) | Link to this hack]

As a class of disabilities, low-vision users are often ignored by accessibility experts. However, accessibility expert Joe Clark has recently published his research into the needs of web users with limited vision. He pioneered a technique known as the zoom layout: a special alternate style applied to a web page that specifically caters to low-vision users.

As I was learning about zoom layouts, it occurred to me that this would be a perfect application of Greasemonkey. (Actually, that thought occurs to me a lot these days.) This hack is my first attempt at transforming a site into a zoom layout.

TIP

You can read more about zoom layouts at http://www.alistapart.com/articles/lowvision/ and http://joeclark.org/atmedia/atmedia-NOTES-2.html.

Running the Hack

After installing the user script (Tools → Install This User Script), go to http://www.google.com. The normally spartan search form has been magnified and simplified even further, as shown in .

Accessibility studies have shown that low-vision users have an easier time reading light text on a dark background, so therefore the page is displayed as white-on-navy. Unvisited links are displayed in yellow; visited links are displayed in light green. The hack removes several elements from the page, including the Advanced Search link, plus any advertisements for Google services or other messages that occasionally appear below the search box.

Figure 1. Google home page, zoomed

When you execute a search, the search results are displayed differently, as shown in and , with the following notable differences:

Figure 2. Google search results, zoomed

Figure 3. Bottom of Google search results, zoomed

If you click the Images link at the top of the page to search for the same keywords in Google Image Search, you will see that the image search results have been similarly hacked, as shown in .

Figure 4. Google image results, zoomed

As with the web search results, the top navigation has been simplified, the number of results is more prominent, and the "Goooooooogle" navigation bar has been replaced by a single "More results" link that moves to the next page of images. The image thumbnails themselves cannot be magnified, since Google provides them only in a specific size.

The Code

This user script runs on several specific Google pages:

TIP

This hack is written to be cross-browser compatible. It works in Firefox with Greasemonkey, in Internet Explorer 6 for Windows with Turnabout, and in Opera 8 with its built-in support for User JavaScript. You can download Turnabout at http://reifysoft.com/turnabout.php, and Opera at http://www.opera.com.

Save the following user script as zoom-google.user.js:

	// ==UserScript==
	// @name		Zoom Google
	// @namespace	http://diveintomark.org/projects/greasemonkey/
	// @description make Google more accessible to low-vision users
	// @include		http://www.google.tld/
	// @include		http://www.google.tld/?*

	// @include http://www.google.tld/webhp*
	// @include http://www.google.tld/imghp*
	// @include http://www.google.tld/search*
	// @include http://images.google.tld/
	// @include http://images.google.tld/?*
	// @include http://images.google.tld/images*
	// ==/UserScript==

	function addGlobalStyle(css) {
		var elmHead, elmStyle;
		elmHead = document.getElementsByTagName('head')[0];
		elmStyle = document.createElement('style');
		elmStyle.type = 'text/css';
		elmHead.appendChild(elmStyle);
		elmStyle.innerHTML = css;
	}

	function getElementsByClassName(sTag, sClassName) {
		sClassName = sClassName.toLowerCase( ) + ' ';
		var arElements = document.getElementsByTagName(sTag);
		var iMax = arElements.length;
		var arResults = new Array( );
		for (var i = 0; i < iMax; i++) {
			var elm = arElements[i];
			var sThisClassName = elm.className;
			if (!sThisClassName) { continue; }
			sThisClassName = sThisClassName.toLowerCase( ) + ' ';
			if (sThisClassName.indexOf(sClassName) != -1) {
				arResults.push(elm);
			}	
		}
		return arResults;
	}

	function removeFontTags( ) {
		// remove font tags
		var arFonts = document.getElementsByTagName('font');
		for (var i = arFonts.length - 1; i >= 0; i--) {
			var elmFont = arFonts[i];
			var elmSpan = document.createElement('span');
			elmSpan.innerHTML = elmFont.innerHTML;
			elmFont.parentNode.replaceChild(elmSpan, elmFont);
		}
	}

	function zoomStyle( ) {
		addGlobalStyle('body { margin: 30px; } \n' +
	'body, td { font-size: large ! important; } \n' +
	'html>body, html>body td { font-size: x-large ! important; } \n' +
	'body, div, td { background: navy ! important; ' +
		'color: white ! important; } \n' +
	'a:link { background: transparent ! important; ' +
		'color: yellow ! important; } \n' +

	'a:visited { background: transparent ! important; ' +
		'color: lime ! important; } \n' +
	'a.fl { background: transparent ! important; ' +
		'color: white ! important; } \n' +
	'input { font-size: large ! important; } \n' +
	'html>body input { font-size: x-large ! important; } \n' +
	'.g { width: auto ! important; } \n' +
	'.n a, .n .i { font-size: large ! important; } \n' +
	'html>body .n a, html.body .n .i { font-size: x-large ! important; } \n' +
	'.j { width: auto ! important; }');
	}

	function accHomePage( ) {
		// remove personalized header, if any
		var arTable = document.getElementsByTagName('table');
		for (var i = arTable.length - 1; i >= 0; i--) {
			var elmTable = arTable = ar
			var html = elmTable.innerHTML;
			if (/\/accounts\/Logout/.test(html)) {
				elmTable.parentNode.removeChild(elmTable);
			}
		}

		// simplify logo
		var arImages = document.getElementsByTagName('img');
		for (var i = arImages.length - 1; i >= 0; i--) {
			var elmLogo = arImages[i];
			if (elmLogo.alt) {
				var elmTextLogo = document.createElement('h1');
				elmTextLogo.style.fontSize = '400%';
				var sAlt = /Firefox/.test(elmLogo.alt) ? '' : elmLogo.alt;
				elmTextLogo.appendChild(document.createTextNode(sAlt));
				elmLogo.parentNode.replaceChild(elmTextLogo, elmLogo);
				var elmLink = elmTextLogo.parentNode;
				while (elmLink.nodeName != 'BODY' &&
				elmLink.nodeName != 'HTML' &&
				elmLink.nodeName != 'A') {
				elmLink = elmLink.parentNode;
				}
				elmLink.style.textDecoration = 'none';
			} else {
				elmLogo.parentNode.removeChild(elmLogo);
			}
		}
		// simplify search form
		if (document.forms.length) {
			var arTD = document.getElementsByTagName('td');
			for (var i = arTD.length - 1; i >= 0; i--) {
				var elmTD = arTD[i];
				if (/Advanced/.test(elmTD.innerHTML)) {
				elmTD.innerHTML = '';

				}
			}
		}
	}

	function accSearchResults( ) {
		// simplify logo
		var elmLogo = document.getElementsByTagName('img')[0];
		var elmTextLogo = document.createElement('h1');
		elmTextLogo.appendChild(document.createTextNode('Google'));
		elmTextLogo.style.marginTop = '0.2em';
		elmTextLogo.style.marginRight = '0.3em';
		elmLogo.parentNode.replaceChild(elmTextLogo, elmLogo);
		elmTextLogo.parentNode.style.textDecoration = 'none';

		// simplify top form
		var elmAdvancedWrapper = document.getElementsByTagName('table')[3];
		var elmAdvanced = elmAdvancedWrapper.getElementsByTagName('td')[1];
		elmAdvanced.parentNode.removeChild(elmAdvanced);

		// remove "tip" if present
		var elmTip = document.getElementsByTagName('table')[7];
		if (/Tip/.test(elmTip.innerHTML)) {
			elmTip.parentNode.removeChild(elmTip);
		}

		// remove ads, if any
		var aw1 = document.getElementById('aw1');
		while (aw1) {
			var table = aw1.parentNode;
			while (table.nodeName != 'TABLE') {
				table = table.parentNode;
			}
			table.parentNode.removeChild(table);
			aw1 = document.getElementById('aw1');
		}
		var tpa1 = document.getElementById('tpa1');
		if (tpa1) {
			while (tpa1.nodeName != 'DIV' && tpa1.nodeName != 'P') {
				tpa1 = tpa1.parentNode;
			}
			tpa1.parentNode.removeChild(tpa1);
		}
		var tpa2 = document.getElementById('tpa2');
		if (tpa2) {
			while (tpa2.nodeName != 'DIV' && tpa2.nodeName != 'P') {
				tpa2 = tpa2.parentNode;
			}
			tpa2.parentNode.removeChild(tpa2);
		}
		addGlobalStyle('iframe[name="google_ads_frame"] { ' +
			'display: none ! important }');

		// simplify results count
		var elmDivider = document.getElementsByTagName('table')[5];
		elmDivider.parentNode.removeChild(elmDivider);
		var elmResultsContainer = document.getElementsByTagName('table')[5];
		var arTD = elmResultsContainer.getElementsByTagName('td');
		if (arTD.length > 1) {
			var sResults = arTD[1].textContent;
			var iParen = sResults.indexOf('(');
			if (iParen != -1) {
				sResults = sResults.substring(0, iParen);
			}
			var iDef = sResults.indexOf('[');
			if (iDef != -1) {
				sResults = sResults.substring(0, iDef);
			}
			var elmResults = document.createElement('h2');
			elmResults.appendChild(document.createTextNode(sResults));
			elmResultsContainer.parentNode.replaceChild(elmResults,
				elmResultsContainer);
		} else {
			elmResultsContainer.parentNode.removeChild(elmResultsContainer);
		}

		// make search results use real headers
		var arResults = getElementsByClassName('p', 'g');
		for (var i = arResults.length - 1; i >= 0; i--) {
			var elmResult = arResults[i];
			var arLink = elmResult.getElementsByTagName('a');
			if (!arLink.length) { continue; }
			var elmLink = arLink[0];
			var elmWrapper = document.createElement('div');
			var elmHeader = document.createElement('h3');
			elmHeader.style.margin = elmHeader.style.padding = 0;
			elmHeader.innerHTML = '<a href="' + elmLink.href + '">' +
				elmLink.innerHTML + '</a>';
			var elmContent = elmResult.cloneNode(true);
			elmContent.innerHTML = elmContent.innerHTML.replace(/<nobr>/g, '');
			arLink = elmContent.getElementsByTagName('a');
			if (!arLink.length) { continue; }
			elmLink = arLink[0];
			elmContent.removeChild(elmLink);
			elmContent.style.marginTop = 0;
			elmWrapper.appendChild(elmHeader);
			elmWrapper.appendChild(elmContent);
			elmResult.parentNode.replaceChild(elmWrapper, elmResult);
		}

		// simplify next page link
		var arFont = document.getElementsByTagName('font');
		for (var i = arFont.length - 1; i >= 0; i--) {
			var elmFont = arFont[i];

		var html = elmFont.innerHTML;
		if (/Result\&nbsp\;Page\:/.test(html)) {
			var elmTable = elmFont.parentNode;	
			while (elmTable.nodeName != 'TABLE') {
				elmTable = elmTable = elm
			}
			var arTD = elmTable.getElementsByTagName('td');
			if (arTD.length) {
				var elmTD = arTD[arTD.length - 1];
				var arNext = elmTD.getElementsByTagName('a');
				if (arNext.length) {
				var elmNext = arNext[0];
				var elmTextNext = document.createElement('center');
				elmTextNext.innerHTML = '<p style="font-size: ' +	
				'xx-large; margin-bottom: 4em;">b><a href="' +
				elmNext.href + '">More Results  ' +
				'&rarr;</a></b></p>';
				elmTable.parentNode.replaceChild(elmTextNext,		
				elmTable);
				}
			}
			break;
		}
	}

	// remove bottom ads
	var arCenter = document.getElementsByTagName('center');
	if (arCenter.length > 1) {
		var elmCenter = arCenter[1];
		elmCenter.parentNode.removeChild(elmCenter);
		elmCenter = arCenter[0];
		for (var i = 0; i < 4; i++) {
			elmCenter.innerHTML = elmCenter.innerHTML.replace(/<br>/, '');
		}
	}

}

document.forms.namedItem('f') && accHomePage( );
document.forms.namedItem('gs') && accSearchResults( );
removeFontTags( );
zoomStyle( );


O'Reilly Home | Privacy Policy

© 2007 O'Reilly Media, Inc.
Website: | Customer Service: | Book issues:

All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.