<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"
 	xmlns:x2="http://www.w3.org/TR/xhtml2"
	xmlns:role="http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#"
	xmlns:state="http://www.w3.org/2005/07/aaa">
<head>

<title>Reference Implementation</title>

<script type="text/javascript" >
<![CDATA[

// Changes the focus to the given element
// Adapted from mozilla.org's dhtml widgets examples
// modified so that the focused node must have an id
// FIXME: Should merge this and setFocus.js
function setFocusId(node) {
	if(node) {
		if(typeof node.focus == 'undefined') {
			// Mozilla 1.7 doesn't support focusing some elements while Firefox 1.5 does
		} else {		
			// Prevents ugly global variable use
			setTimeout("document.getElementById('" + node.id + "').focus()", 0);
		}
	}
}

// returns an alert DOM subtree that displays the given alertBody and the given dismissText on the dismisal link. 
// alertBody may be a string of alert text, or a DOM subtree to be used as the alert body message (wouldn't innerHTML be nice, here!)
// elementToFocusOnClose indicates which DOM element should recieve focus when the alert box closes.  If this 
// ... is null, the alert will focus the last non-alert-related focused DOM element.
// insertAfterElement is where the first alert box is placed, subsequent alerts follow the previous alert box
// FIXME: Should think about managing tab order better.  Tabbing away from the alert or closing it should take 
// ... you to a field that likely was related to the alert event, or at least to where you were before the alert.
// ... this should be able to be done through tabindex.
// FIXME: elementToFocusOnClose currently unimplemented
function insertAlertDialog(alertBody, dismissText, insertBeforeElement, elementToFocusOnClose) {

	// Remove old alert if displayed
	var temp;
	if((temp = getAlertInDocument()) != null) {
		temp.parentNode.removeChild(temp);
	}

	var xhtmlNS = "http://www.w3.org/1999/xhtml";

	// construct the alert DOM subtree
	var alertTitleNode = document.createElementNS(xhtmlNS,"h2");
	alertTitleNode.setAttribute("class","off");
	alertTitleNode.appendChild(document.createTextNode("Alert"));

	var alertBodyNode;
	if(typeof alertBody == "string") {
		alertBodyNode = document.createElementNS(xhtmlNS,"p");
		alertBodyNode.appendChild(document.createTextNode(alertBody));
	} else {
		alertBodyNode = alertBody;
	}

	var alertDismissNode = document.createElementNS(xhtmlNS,"input");
	alertDismissNode.setAttribute("type","button");
	alertDismissNode.setAttribute("value",dismissText);
	alertDismissNode.setAttribute("tabindex","0");	
	alertDismissNode.addEventListener("click",function(e) {dismissAlertHandler(e,elementToFocusOnClose);},false);
	alertDismissNode.addEventListener("keydown",function(e) {dismissAlertHandler(e,elementToFocusOnClose);},false);
	
	var alertBodyDiv = document.createElementNS(xhtmlNS,"div");
	alertBodyDiv.setAttribute("class","alertbody");
	alertBodyDiv.appendChild(alertTitleNode);
	alertBodyDiv.appendChild(alertBodyNode);

	var alertDismiss = document.createElementNS(xhtmlNS,"div");
	alertDismiss.setAttribute("class","alertdismiss");
	alertDismiss.appendChild(alertDismissNode);

	var alertNode = document.createElementNS(xhtmlNS,"div");
	alertNode.setAttribute("id","alert");
	alertNode.addEventListener("blur",unsetImportantHandler,false);
	// FIXME: We don't need xhtml2 namespace, but for now...
	alertNode.setAttributeNS("http://www.w3.org/TR/xhtml2","role","role:alert");
	alertNode.setAttributeNS("http://www.w3.org/2005/07/aaa","important","true");		
	alertNode.setAttribute("tabindex","0");
	alertNode.setAttribute("class","alert");	

	alertNode.appendChild(alertBodyDiv);
	alertNode.appendChild(alertDismiss);	

	insertBeforeElement.parentNode.insertBefore(alertNode,insertBeforeElement);
	setFocusId(alertNode);

/* Constructs something like the following:
<div id="alert" class="alert" onblur="unsetImportant(event)">
	<div style="width:100%;position:absolute">
	 	<h2 class="off">Alert:</h2>
		<p>Alert text</p>
	</div>
	<div style="position:absolute;width:100%;bottom:0;margin-bottom:1em">
		<input tabindex="0" type="button" value="OK" onclick="dismissAlert(event)" onblur="dismissAlert(event)"/>
	</div>
</div>
*/
}

function dismissAlertHandler(event, elementToFocusOnDismiss) {
	if (event.type == "keydown") {
		if (event.keyCode != event.DOM_VK_RETURN) {
			return; // take action only on enter key (or mouse click)
		}
	}

	var alertNode = getParentAlert(event.target);
	alertNode.parentNode.removeChild(alertNode);
	alertDisplayed=false;
	
	setFocusId(elementToFocusOnDismiss);
}

function unsetImportantHandler(event) {
	event.target.setAttributeNS("http://www.w3.org/2005/07/aaa","important","false");
}

// returns true if given node has the alert role
function isAlert(node) {
	// Attempt to match last part of string because of unrecognized-namespace-in-value issues
	if( node.getAttributeNS("http://www.w3.org/TR/xhtml2", "role").search(/alert$/) > -1 ) {
		return true;
	}
	return false;
}

// returns the element marked with the alert role that contains the given node or null if no alert exists
function getParentAlert(node) {
	if( isAlert(node) ) {
		return node
	}
	
	if(node.parentNode == null) {
		return null; // Hit the top of the DOM
	}
	
	return getParentAlert(node.parentNode);
}

// returns an element with an "alert" role is in the subtree defined by the given element, null if none found
// If no element is specified, this function will check all of the current document elements
// FIXME: should use xpath
function getAlertInDocument(element) {
	if(typeof element == "undefined") {
		element = document.documentElement;
	}
	
	if(isAlert(element)) {
		return element;
	}
	
	for(var i=0; i<element.childNodes.length; i++) {
		if(element.childNodes[i].nodeType == element.ELEMENT_NODE) {
			if((retval = getAlertInDocument(element.childNodes[i])) == null) {
				continue;
			} else {
				return(retval);
			}
		}
	}
	return(null);
}/*
 * Specific to example html and logic
 */

var secretNumber = Math.floor(Math.random() * 100);
var numGuesses = 0;
var notNumericalRegExp = new RegExp("\\D|^$"); // matches a non-numerical character or empty string

// Evaluates user action that produced event and possibly activates an alert as appropriate
function guess(event, textfieldId) {
	if (event.type == "keydown") {
		if (event.keyCode != event.DOM_VK_RETURN) {
			return; // take action only on enter key (or mouse click)
		}
	}

	// Example logic
	var t = document.getElementById(textfieldId);
	if( notNumericalRegExp.test(t.value) ) { 
		insertAlertDialog("Enter a number between 0 and 99", "Ok", t, t);
		return;
	}

	if( parseInt(t.value) > secretNumber ) {
		insertAlertDialog("Too high", "Ok", t, t);
		numGuesses++;		
	} else if( parseInt(t.value) < secretNumber ) {
		insertAlertDialog("Too low", "Ok", t, t);
		numGuesses++;		
	} else if( parseInt(t.value) == secretNumber ) {
		insertAlertDialog("Correct in " + numGuesses + "!", "Ok", t, t);
	} 
}

]]>
</script>

<style type="text/css">
@namespace x2    url("http://www.w3.org/TR/xhtml2");
@namespace role  url("http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#");
@namespace state url("http://www.w3.org/2005/07/aaa");
ul.hlist {
	list-style: none;
	margin: 1em;
	padding: 0;
	display: inline;
}

ul.hlist li	{
	display: inline;
	margin: 1em;
	padding: 0;	
}

p.inline {
	display: inline;
	margin: 1em;	
}

div#content {
	position: absolute;
	top: 0;
	left: 0;
}

.hide {
/*
	visibility: hidden;
	height: 0;
	width: 0;
	padding: 0;
	margin: 0;
	display: inline;
	*/
	display: none;
}

li.testItem {
	margin: 0;
}

iframe.short {
	margin-top: 1em;
	height: 3em;
}

iframe.textfieldShort {
	margin-top: 1em;
	height: 8em;
}

iframe.comboboxShort {
	margin-top: 1em;
	height: 11em;
}

iframe.rdfShort {
	margin-top: 1em;
	height: 14em;	
}

iframe.treeShort {
	margin-top: 1em;
	height: 20em;	
}

iframe.sliderShort {
	margin-top: 1em;
	height: 5em;	
}

h3.info {
	display: inline;
	margin: 0;
	padding: 0;
}

div.alert {
	position: absolute;
	z-index: 100;
	
	min-width: 20em;
	min-height: 12em;

	margin: 2em;

	background-color: white;
	color: black;
	text-align: center;
	border-width: .5em;
	border-color: black;
	border-style: solid;
}

div.alertbody {
	width: 100%;
	position: absolute;
	margin-top: 1em;
}

div.alertdismiss {
	position: absolute;
	width: 100%;
	bottom: 0;
	margin-bottom: 1em;
}

.off {
	display: none;
}

</style>
</head>

<body>

<div id="content">

<h1 class="hide">Reference Implementation</h1>


<h2 class="hide">Test</h2>


<div id="test">

<label for="guess">Guess what number I'm thinking of:</label> 
<input id="guess" type="text" size="2" maxlength="2" />
<input id="submitguess" type="button" value="guess" onclick="guess(event,'guess')" onkeydown="guess(event,'guess')"/>

<p>The suggested coding practice is to indicate the alert metaphor by focusing an element with an "alert" role and an "important" state set.
When an element with the "alert" role attribute is focused without an "important" state set, it is should be 
considered an old alert and no longer worth special action/interruption/notification</p>

</div>
</div>

</body>
</html>
