<?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"
	xmlns:testRole="http://cita.uiuc.edu/2006/06/role"	
	xmlns:testState="http://cita.uiuc.edu/2006/06/state">
<head>

<link ref="meta" type="application/rdf+xml" title="RDF Definition for the checkboxgroup extended widget" href="http://cita.disability.uiuc.edu/software/mozilla/test/dhtml/src/rdf/exclusivecheckbox_reference/exclusivecheckbox_roles.php" />
<link ref="meta" type="application/rdf+xml" title="RDF Definition for some extended states" href="http://cita.disability.uiuc.edu/software/mozilla/test/dhtml/src/rdf/exclusivecheckbox_reference/exclusivecheckbox_states.php" />

<!--  This would be a better definition
<link ref="meta namespace http://cita.uiuc.edu/2006/06/role" type="application/rdf+xml" title="RDF Definition for the checkboxgroup extended widget" href="http://cita.disability.uiuc.edu/software/mozilla/test/dhtml/src/rdf/exclusivecheckbox_reference/exclusivecheckbox_roles.php" />
<link ref="meta namespace http://cita.uiuc.edu/2006/06/state" type="application/rdf+xml" title="RDF Definition for some extended states" href="http://cita.disability.uiuc.edu/software/mozilla/test/dhtml/src/rdf/exclusivecheckbox_reference/exclusivecheckbox_states.php" />
-->
<title>Complex RDF Widget Extension</title>

<script type="text/javascript" >
<![CDATA[

// Returns true if checkable event 
function isCheckable(event) {
	if ((event.type == "click" && event.button == 0) 
		|| (event.type == "keypress" && event.charCode == 32)
		|| ( (event.type == "keydown" || event.type == "keyup") && event.keyCode == 32 ) ) {
		
		if( event.target == event.currentTarget ) { 
			return true;
		}
	}
	return false;
}

function checkboxCheck(node) {
	node.setAttributeNS("http://www.w3.org/2005/07/aaa", "checked", "true");
}

// Sets the "checked" attribute to false
function checkboxUnCheck(node) {
	node.setAttributeNS("http://www.w3.org/2005/07/aaa", "checked", "false");
}

// Returns true if a node has the aaa state "checked" set
function isChecked(node) {
	if (node.getAttributeNS("http://www.w3.org/2005/07/aaa", "checked") == "true") {
		return true;
	}
	return false;
}

// returns true if node has role=radio
function isCheckbox(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(/checkbox$/) > -1 ) {
		return true;
	}
	return false;
}

// Adds the given className string on given DOM node
function addStyleClass(node, className) {
	var classStr = node.getAttribute("class");
	
	classStr = classStr + " " + className;
	node.setAttribute("class",classStr);
}

// Removes the given className string on given DOM node
function removeStyleClass(node, className) {
	var classStr = node.getAttribute("class");
	
	if(classStr == "" || classStr == null) {
		return;
	}
	
	classNameRegExp = new RegExp("^" + className + "\\s*", "g");
	classStr = classStr.replace(classNameRegExp,"");
	classNameRegExp = new RegExp("\\s+" + className, "g");
	classStr = classStr.replace(classNameRegExp,"");

	node.setAttribute("class",classStr);
}

// Handles click and keyboard events for the exclusive checkbox/checkboxgroup
function exclusiveCheckboxEvent(event) {
	if( isCheckable(event) ) {
		exclusiveCheck(event.target, flashConflicts);
		return false;  // Don't continue propagating event
	}
	return true;  // Browser can still use event
}

// If the maximum number of checks in this checkboxgroup has not been exceeded and 
// ... if no other checkbox in exclusivegroup is checked, this checkbox is checked.
// Elements that cause conflicts are passed in an array to the given conflict handling function 
// ... as well as the node under consideration.  Pass null if no handleConflicts function is to be used.
function exclusiveCheck(node, handleConflictsFunction) {
	if(isChecked(node)) {
		checkboxUnCheck(node);		
		return;
	}
	
	// compare number in group checked with max number
	var chboxGroup = getCheckboxParentGroup(node);
	if( getCheckedMax(chboxGroup) <= getNumChecked(chboxGroup) ) {
		// don't allow it
		if(handleConflictsFunction != null)	{
			handleConflictsFunction(node, new Array());  // empty array signifies a blameless conflict
		}
		return;
	}

	var groups = getExclusiveGroupIds(node);
	var members;
	var conflicts = new Array();
	chboxGroupMembers = getCheckboxGroupArray(chboxGroup, new Array());
	for( var i in groups ) {
		members = getExclusiveGroupMembers(chboxGroupMembers, groups[i]);
		for( var j in members ) {
			if( isChecked(members[j]) ) {
				conflicts.push(members[j]);
			}
		}
	}

	if( conflicts.length > 0 ) {
		if( handleConflictsFunction != null ) {
			handleConflictsFunction(node, conflicts);
			return;
		}
	}
	
	// If we made it to here, no conflicts.
	checkboxCheck(node);
}

// Returns an a array of checkbox controls in a group given a DOM checkboxgroup node
// checkboxArray is used in the recursion, the root call should pass in "new Array()"
function getCheckboxGroupArray(checkboxGroupNode, checkboxArray) {
	// Recursively search the tree below this node unless they are a checkboxgroup node
	for(var i=0; i<checkboxGroupNode.childNodes.length; i++) {
		childNode = checkboxGroupNode.childNodes[i];
		if(childNode.nodeType != childNode.ELEMENT_NODE) {
			continue;
		}

		if(isCheckboxGroup(childNode)) {
			return radioArray; // Don't descend
		} else if(isCheckbox(childNode)) {
			checkboxArray.push(childNode);
		}
		getCheckboxGroupArray(childNode, checkboxArray); // Descend
	}
	return checkboxArray;
}

// Returns the element with role "checkboxgroup" that contains this element or null if none found
function getCheckboxParentGroup(node) {
	if( node.parentNode == null ) {
		return null;
	} 
	node = node.parentNode;	

	if( isCheckboxGroup(node) ) {
		return(node);
	}

	return getCheckboxParentGroup(node);
}

// returns true if node has role=radio
function isCheckboxGroup(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(/checkboxgroup$/) > -1 ) {
		return true;
	}
	return false;
}

// Add the styling class "flash" to each conflicted element in the given array 
// ... for some time, then remove.
function flashConflicts(node, conflicts) {
	for( var i in conflicts ) {
		addStyleClass(conflicts[i], "flash");
	}
	
	// 1 second delay
	window.setTimeout(
		function() {
			for( var i in conflicts ) {
				removeStyleClass(conflicts[i], "flash");
			}
		}, 1000
	);
}

// returns the value of the checkedmax extended state on the extended checkboxgroup node
// the empty string is returned if the state is not provided or is empty.
function getCheckedMax(checkboxGroupNode) {
	// Attempt to match last part of string because of unrecognized-namespace-in-value issues
	return checkboxGroupNode.getAttributeNS("http://cita.uiuc.edu/2006/06/state", "checkedmax");
}

// gets all checkbox widgets in the given checkboxgroup (and not in 
// ... any other sub-checkboxgroup) and returns the total number checked.
function getNumChecked(checkboxGroupNode) {
	var checkboxes = getCheckboxGroupArray(checkboxGroupNode, new Array());
	
	var numChecked = 0;
	for(var i in checkboxes) {
		if( isChecked(checkboxes[i])) {
			numChecked++;
		}
	}
	return numChecked;
}

// Returns an array of strings that are the space-seperated exclusivegroup memberships
function getExclusiveGroupIds(node) {
	var ids = node.getAttributeNS("http://cita.uiuc.edu/2006/06/state", "exclusivegroup");
	return ids.split(" ");
}

// returns the members in the intersection of the given exclusivegroup id and 
// ... the exclusivegroup membership of the given array of elements
// An empty array is returned if there is no element with the exclusivegroup id
function getExclusiveGroupMembers(elementArray, id) {
	if(id=="") {return;} // don't count the empty string as a valid id

	var intersection = new Array();
	for( var i in elementArray ) {
		groupIds = getExclusiveGroupIds(elementArray[i]);
		for( var j in groupIds ) {
			if(groupIds[j]=="") {continue;} // don't count the empty string as a valid id
			if( id == groupIds[j] ) {
				intersection.push(elementArray[i]);
				break;
			}
		}
	}
	return intersection;
}

]]>
</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;
}

.checkbox[state|checked="true"]:before {
	content: url('../../images/checked.gif')
}

.checkbox:before {
	content: url('../../images/unchecked.gif')
}

.flash {
	background-color: #FF9999;
}</style>
</head>

<body>

<div id="content">

<h1 class="hide">Complex RDF Widget Extension</h1>


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


<div id="test">

<p id="instructions">Please select your work schedule preferences below.  
Each employee can work up to 3 shifts, only one shift on the weekend, and 
only one evening shift.</p>

<ul class="checkgroup" id="cgroup1" 
	x2:role="testRole:checkboxgroup"
	state:multiselectable="true"
	testState:checkedmax="3"
	state:describedby="instructions">
	
	<li class="checkbox" id="chbox1" x2:role="role:checkbox"
		state:checked="false"
		testState:exclusivegroup=""
		tabindex="0"
		onclick="exclusiveCheckboxEvent(event)" onkeypress="exclusiveCheckboxEvent(event)"
	>Tuesday Morning</li>

	<li class="checkbox" id="chbox2" x2:role="role:checkbox"
		state:checked="false"
		testState:exclusivegroup="evening"
		tabindex="0"
		onclick="exclusiveCheckboxEvent(event)" onkeypress="exclusiveCheckboxEvent(event)"
	>Tuesday Evening</li>
	
	<li class="checkbox" id="chbox3" x2:role="role:checkbox"
		state:checked="false"
		testState:exclusivegroup=""
		tabindex="0"
		onclick="exclusiveCheckboxEvent(event)" onkeypress="exclusiveCheckboxEvent(event)"
	>Thursday Morning</li>
	
	<li class="checkbox" id="chbox4" x2:role="role:checkbox"
		state:checked="false"
		testState:exclusivegroup="evening"
		tabindex="0"
		onclick="exclusiveCheckboxEvent(event)" onkeypress="exclusiveCheckboxEvent(event)"
	>Thursday Evening</li>
	
	<li class="checkbox" id="chbox5" x2:role="role:checkbox"
		state:checked="false"
		testState:exclusivegroup="weekend"
		tabindex="0"
		onclick="exclusiveCheckboxEvent(event)" onkeypress="exclusiveCheckboxEvent(event)"
	>Saturday Morning</li>
	
	<li class="checkbox" id="chbox6" x2:role="role:checkbox"
		state:checked="false"
		testState:exclusivegroup="weekend evening"
		tabindex="0"
		onclick="exclusiveCheckboxEvent(event)" onkeypress="exclusiveCheckboxEvent(event)"
	>Saturday Evening</li>
	
	<li class="checkbox" id="chbox7" x2:role="role:checkbox"
		state:checked="false"
		testState:exclusivegroup="weekend"
		tabindex="0"
		onclick="exclusiveCheckboxEvent(event)" onkeypress="exclusiveCheckboxEvent(event)"
	>Sunday Morning</li>
	
	<li class="checkbox" id="chbox8" x2:role="role:checkbox"
		state:checked="false"
		testState:exclusivegroup="weekend evening"
		tabindex="0"
		onclick="exclusiveCheckboxEvent(event)" onkeypress="exclusiveCheckboxEvent(event)"
	>Sunday Evening</li>
</ul>		

</div>

</div>

</body>
</html>


