<script type="text/javascript">
/**
*
* The Globale Variables
*/
if (!window.Node) {
var Node = { // If there is no Node object, define one
ELEMENT_NODE: 1, // with the following properties and values.
ATTRIBUTE_NODE: 2, // Note that these are HTML node types only.
TEXT_NODE: 3, // For XML-specific nodes, you need to add
COMMENT_NODE: 8, // other constants here.
DOCUMENT_NODE: 9,
DOCUMENT_FRAGMENT_NODE: 11
}
}
var KEY_PAGEUP = 33;
var KEY_PAGEDOWN = 34;
var KEY_END = 35;
var KEY_HOME = 36;
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT = 39;
var KEY_DOWN = 40;
var KEY_SPACE = 32;
var KEY_TAB = 9;
var KEY_BACKSPACE = 8;
var KEY_DELETE = 46;
var KEY_ENTER = 13;
var KEY_INSERT = 45;
var KEY_ESCAPE = 27;
var KEY_F1 = 112;
var KEY_F2 = 113;
var KEY_F3 = 114;
var KEY_F4 = 115;
var KEY_F5 = 116;
var KEY_F6 = 117;
var KEY_F7 = 118;
var KEY_F8 = 119;
var KEY_F9 = 120;
var KEY_F10 = 121;
var KEY_M = 77;
var NS_XHTML = "http://www.w3.org/1999/xhtml"
var NS_STATE = "http://www.w3.org/2005/07/aaa";
/**
*
* previousSiblingElement
*
* @param ( node ) node object for which you are looking for the next sibling element node
*
* @return ( node) next sibling or "null"
*/
/**
*
* firstChildElement
*
* @param ( node ) node object for which you are looking for the first child element node
*
* @return ( node) next sibling or "null"
*/
<script type="text/javascript">
// JavaScript Document
// This module is to abstract browser dependencies
// This makes the widget code cleaner and earier to read by making most browser specfic coding
// in one place rather han scatered throghot documents
var ARIA_STATE = "aria-";
//
// WebBrowser object to abstract accessibility API differences between web standards supporting browsers and Internet Explorer 7.0
//
// The state variable keeps track of current state of checkbox
function WebBrowser() {
}
//
// keyCode is a function to get the keycode from a keypress event
//
// @param ( event object) event is an event object
//
// @return ( keycode )
WebBrowser.prototype.keyCode = function( event ) {
var e = event || window.event;
// If a web standards based browser implement this function
WebBrowser.prototype.simulateOnClickEvent = function( node ) {
// W3C DOM Events way to trigger a "click" event
var e = document.createEvent('MouseEvents');
e.initEvent( 'click', true, true );
node.dispatchEvent( e );
}
} else {
// If a Microsoft IE based browser implement this function
// For browsers that do not support W3C or IE event functions
WebBrowser.prototype.addEvent = function(elmTarget, sEventName, fCallback) {
return false;
};
<script type="text/javascript">
// JavaScript Document
// Widgets is a way to initialize widgets in the ARIA examples
function Widgets() {
this.widgets = new Array();
}
/**
* add is member of the Widgets Object
* and used add a widget ot the list of widgets to be intitialized
* as part of the onload event
* The controls array is the list of controls to initialize
* @member Enable
* @return none
*/
/**
* init is member of the Widgets Object
* and is called by the onload event to initialize widgets in the web resource
* The controls array is the list of controls to initialize
* @member Enable
* @return none
*/
Widgets.prototype.init = function() {
for(var i = 0; i < this.widgets.length; i++ )
this.widgets[i].init();
}
<script type="text/javascript">
/**
*
*/
/**
* @projectDescription A library of javascript functions to make Accessability Rich drag and drop widgets
* @author Russell Llewellyn Jones
* @version 1.0
*/
var dragObject = null;
var dragObjectKB = null;
var offsetx;
var offsety;
/**
* This function is called when something is dropped onto a dropbasket.
* It does nothing, but exists so users of this library can define functions that will be called.
* @param {Object, Dragable} dragable is the dragable that was dropped
* @param {Object, DropBasket} basket is the drop basket that something was dropped onto.
* @param {Boolean} mouse is whether the mouse is being used as opposed to the keyboard
*/
var onBasketDrop = function(dragable,basket) {};
/**
* This function is called when the user tries to drop something onto a dropbasket,
* but there is nothing to be dropped.
* It does nothing, but exists so users of this library can define functions that will be called.
* @param {DropBasket Object} basket is the dropbasket that something was dropped onto.
*/
var onBasketNoDrop = function(basket) {};
/**
* This function is called when the user grabs a dragable
* It does nothing, but exists so users of this library can define functions that will be called.
* @param {Dragable object} dragable
*/
var onDragableGrab = function(dragable) {};
/**
* This function is called when the user moves the mouse pointer over a dropbasket
* or a basket gains keyboard focus.
* It does nothing, but exists so users of this library can define functions that will be called.
* @param {Object, Dragable} dragable is a dragable that has been grabbed (can be null)
* @param {Object, DropBasket} basket is the dropbasket that the mouse pointer has entered
* @param {Boolean} mouse is whether the mouse is being used as opposed to the keyboard
*/
var onBasketOver = function(dragable,basket,mouse) {};
/**
* This function is called when the user moves the mouse pointer while it is over a dropbasket.
* It does nothing, but exists so users of this library can define functions that will be called.
* @param {Object, Dragable} dragable is a dragable that has been grabbed (can be null)
* @param {Object, DropBasket} basket is the dropbasket that the mouse pointer is over
* @param {Object, event} event is the mouse move event that was sent to the basket
*/
var onBasketHover = function(dragable,basket,event) {};
/**
* This function is called when the mouse pointer leaves dropbasket or a basket looses keyboard focus.
* It does nothing, but exists so users of this library can define functions that will be called.
* @param {Object, Dragable} dragable is a dragable that has been grabbed (can be null)
* @param {Object, DropBasket} basket is the dropbasket that the mouse pointer has entered
*/
var onBasketOut = function(dragable,basket) {};
/**
* This function is called when the user drops a dragable somewhere that is not a drop basket.
* It is also called if the user presses escape to drop a dragable.
* It does nothing, but exists so users of this library can define functions that will be called.
* @param {Object, Dragable} dragable is a dragable that has been grabbed (can be null)
* @param {Object, DropBasket} basket is the dropbasket that the mouse pointer has entered
*/
var onBadDrop = function(dragable) {};
//onBasketHover is set to null because deciding whether to call it is a rigorous process,
//so if it is null it will save CPU time
onBasketHover = null;
/**
* This function creates an object that can be used to find the mouse position
* @param {Object, Event} e
* @returns {Object} an object with an x and a y property
*/
mouseGetPosition = function (e) {
//The functions used to find the mouse position are abstracted, for multi-browser compatability
return {x:browser.pageX(e), y:browser.pageY(e)};
}
/**
* This function is called when the mouse moves.
* If there is an object being dragged with the mouse it is moved.
* @param {Object, Event} event
*/
mouseMove = function (event) {
//Abstract the event object, for multi-browser compatability
var e = event || window.event;
//Find the mouse position
var mousePosition = mouseGetPosition(e);
//Check whether the onBasketHover function has been defined
if (onBasketHover) {
//Cycle through all the widgets
for (var o = 0; o < widgets.widgets.length; o++) {
//This function is occasionally called before the widgets are created, and weird bugs occur
//The next two lines prevent these bugs
if (!widgets.widgets[o].node)
break;
//Check whether the node is a dropBasket
if (widgets.widgets[o].constructor == DropBasket) {
//Find the location of the widget. This is abstracted, for multi-browser compatability
var offsetTop = browser.calculateOffsetTop(widgets.widgets[o].node);
var offsetLeft = browser.calculateOffsetLeft(widgets.widgets[o].node);
//Check whether the mouse is over the widget
if (mousePosition.x > offsetLeft && mousePosition.x < offsetLeft+widgets.widgets[o].node.offsetWidth && mousePosition.y > offsetTop && mousePosition.y < offsetTop+widgets.widgets[o].node.offsetHeight) {
//Call the onBasketHover function
onBasketHover(dragObject,widgets.widgets[o],e);
}
}
}
}
//Check whether anything is being dragged with the mouse
if (dragObject) {
//Tell the browser to keep track of it's absolute location
if (dragObject.node.style.position != 'absolute')
dragObject.node.style.position = 'absolute';
//Move it to the position of the mouse
dragObject.node.style.top = (mousePosition.y+offsety) + "px";
dragObject.node.style.left = (mousePosition.x+offsetx) + "px";
//Stop the propagation of this event. This is abstracted, for multi-browser compatability
return browser.stopPropagation(e);
}
}
/**
* This function is called when the mouse button is released.
* If there is an object being dragged it releases it.
* If an object is released onto a drop basket, it calls the onBasketDrop function
* @param {Event Object} event
*/
mouseUp = function (event) {
//Abstract the event object, for multi-browser compatability
var e = event || window.event;
//Check whether anything is being dragged with the mouse
if (dragObject) {
//Find the mouse position
var mousePosition = mouseGetPosition(e);
//Tell the browser to keep track of the widget's absolute location
if (dragObject.node.style.position != 'absolute')
dragObject.node.style.position = 'absolute';
//The following for block finds whether the widget is being dropped on a basket
var basketObject = null;
//Cycle through all the widgets
for (var o = 0; o < widgets.widgets.length; o++) {
//Check whether the node is a dropBasket
if (widgets.widgets[o].constructor == DropBasket) {
//Find the location of the widget. This is abstracted, for multi-browser compatability
var offsetTop = browser.calculateOffsetTop(widgets.widgets[o].node);
var offsetLeft = browser.calculateOffsetLeft(widgets.widgets[o].node);
//Check whether the mouse is over the basket
if (mousePosition.x > offsetLeft && mousePosition.x < offsetLeft+widgets.widgets[o].node.offsetWidth && mousePosition.y > offsetTop && mousePosition.y < offsetTop+widgets.widgets[o].node.offsetHeight) {
//Choose this basket
basketObject = widgets.widgets[o];
break;
}
}
}
//Check whether an basket that is not disabled was found was found
if (basketObject && !basketObject.disabled) {
//Check whether the dragable should be copied or referenced, instead of moved
if (basketObject.node.getAttribute("aria-dropeffect") != "move") {
//Move the dragable back to it's original position
browser.setNodePosition(dragObject.node,dragObject.initial_x,dragObject.initial_y);
}
//Check whether the dragable should be copied, instead of moved or referenced
if (basketObject.node.getAttribute("aria-dropeffect") == "copy") {
//Find how many dragables are already in the dropbasket
var i = basketObject.contents.length;
//Add a copy of the dragable to the contents array of the dropbasket
//Note: only the node of the object is copied, the dragable widget is not;
//therefore, the copied node is not dragable.
//To turn this node into a dragable widget see the 2nd drag and drop example at
//http://test.cita.uiuc.edu/aria/
basketObject.contents.push(dragObject.node.cloneNode(true));
//Add the copied node to the webpage
basketObject.node.appendChild(basketObject.contents[i]);
//Tell the browser to keep track of it's absolute location
if (basketObject.contents[i].style.position != 'absolute')
basketObject.contents[i].style.position = 'absolute';
//Do not allow the browser to give focus to the copied node
//To undo this, use the removeAttribute function
basketObject.contents[i].setAttribute("aria-disabled","true");
//Remove the copied node's class
basketObject.contents[i].className = "";
//Tell Assistive technologies that you cannot grab this node
//To undo this set aria-grab to supported
basketObject.contents[i].setAttribute("aria-grabbed", "false");
//Move the copied node to the location that the dragable was dropped. This is abstracted, for multi-browser compatability
browser.setNodePosition(basketObject.contents[i],mousePosition.x+offsetx,mousePosition.y+offsety);
}
//Call the onBasketDrop function
onBasketDrop(dragObject,basketObject,true);
//If dragable is not dropped on a basket
} else {
//Check if the user is not allowed to move the dragable anywhere on the page (default
if (dragObject.basketOnly) {
//Move the dragable back to it's original position
browser.setNodePosition(dragObject.node,dragObject.initial_x,dragObject.initial_y);
//Call the onBadDrop function
onBadDrop(dragObject);
}
}
//Tell the application that nothing is being dragged
dragObject = null;
//Cycle through all the widgets
for (var o = 0; o < widgets.widgets.length; o++) {
//Check whether the widget is a dropbasket
if (widgets.widgets[o].constructor == DropBasket) {
// Set the ARIA drop-effect to none
widgets.widgets[o].node.setAttribute("aria-dropeffect", "none");
//Get rid of the "available" class in the dropbasket
var i = widgets.widgets[o].node.className.indexOf(" available");
if (i != -1) {
var s = widgets.widgets[o].node.className.substr(0,i);
s += widgets.widgets[o].node.className.substr(i+10);
widgets.widgets[o].node.className = s;
}
}
}
}
}
/**
* Create a new Dragable
* @classDescription This is a class for widgets that can be dragged.
* @param {String} id is the id that points to the html Element that will be a dragable
* @constructor
*/
function Dragable( id ) {
this.id = id;
}
/**
* Create a new DropBasket
* @classDescription This is a class for widgets that can have Dragables dropped on them.
* @param {String} id is the id that points to the html Element that will be a drop basket
* @constructor
*/
function DropBasket( id ) {
this.id = id;
}
/**
* Create a new Grid
* @classDescription This is a class for html tables that can be navigated with a keyboard.
* @param {String} id is the id that points to the html Element that will be a grid
* @constructor
*/
function Grid( id ) {
this.id = id;
}
/**
* This function is called when a Dragable is clicked on.
* @param {Object,Event} event
* @param {Object,Dragable} dragable
*/
function handleDragableMouseDownEvent(event,dragable) {
//Check whether the dragable is disabled
if (!dragable.disabled) {
//Abstract the event object, for multi-browser compatability
var e = event || window.event;
if (e.cancelBubble)
return;
//Tell the application that this object is being dragged
dragObject = dragable;
//Cycle through all the widgets
for (var o = 0; o < widgets.widgets.length; o++) {
if (widgets.widgets[o].constructor == DropBasket && !widgets.widgets[o].disabled) {
// Set aria-dropped effect to move
widgets.widgets[o].node.setAttribute("aria-dropeffect", "copy");
//Add the "available" class to nondisabled dropbaskets
widgets.widgets[o].node.className += " available";
}
}
//Find the mouse position
var mousePosition = mouseGetPosition(e);
//Find the position of the mouse relative to what is being dragged
offsetx = browser.calculateOffsetLeft(dragObject.node)-mousePosition.x;
offsety = browser.calculateOffsetTop(dragObject.node)-mousePosition.y;
//Call the onDragableGrab function
onDragableGrab(dragable);
}
//Stop the propagation of this event. This is abstracted, for multi-browser compatability
return browser.stopPropagation(e);
}
/**
* This function is used to add a focus event to a cell.
* It is needed because Javascript does not have block scope.
* @param {integer} row
* @param {integer} cell
* @method
*/
Grid.prototype.addCellEvent = function (row,cell) {
var c = cell;
var r = row;
var o = this;
//Add focus and blur events to the cells of the grid
browser.addEvent(this.node.rows[r].cells[c], "focus", function(event){handleCellFocusEvent(event,o,r,c);},false);
browser.addEvent(this.node.rows[r].cells[c], "blur", function(event){handleCellBlurEvent(event,o,r,c);},false);
}
/**
* This function is called when the widgets are initiated.
* It attatches a node to the grid; counts the rows and columns in the grid;
* and adds keydown, focus, and blur events to the grid.
* @method
*/
Grid.prototype.init = function () {
//Find the widget's node
this.node = document.getElementById(this.id);
//Count the rows and columns in the grid
this.rows = this.node.rows.length;
this.columns = this.node.rows[0].cells.length;
//Are the following lines unnecessary?
//this.row = 0;
//this.cell = 0;
//Add focus and blur events to the cells of the grid
var o = this;
var r;
var c;
for (r = 0; r < this.rows; r++) {
for (c = 0; c < this.columns; c++) {
this.addCellEvent(r,c);
}
}
//Add focus and keydown events to the grid
browser.addEvent(this.node, "keydown", function(event){handleGridKeyDownEvent(event,o);},false);
browser.addEvent(this.node, "focus", function(event){handleGridFocusEvent(event,o);},false);
}
/**
* This function is called when the widgets are initiated.
* It attaches a node to the drop basket, creates an array to contain objects copied into the basket,
* and adds events to the drop basket.
* @method
*/
DropBasket.prototype.init = function () {
//Find the widget's node
this.node = document.getElementById(this.id);
var o = this;
//Create an array to keep track of objects that have been dropped on this basket
this.contents = new Array();
//Add focus, blur, keydown, mouseover, and mouseout events to the dropbasket
browser.addEvent(this.node, "keydown", function(event){handleDropBasketKeyDownEvent(event,o);},false);
browser.addEvent(this.node, "focus", function(event){handleDropBasketFocusEvent(event,o);},false);
browser.addEvent(this.node, "blur", function(event){handleDropBasketBlurEvent(event,o);},false);
browser.addEvent(this.node, "mouseover", function(event){handleDropBasketMouseOverEvent(event,o);},false);
browser.addEvent(this.node, "mouseout", function(event){handleDropBasketMouseOutEvent(event,o);},false);
}
/**
* This function is called when the widgets are initiated.
* It attatches a node to the dragable, detects the initial location of the dragable,
* and adds mousedown and keydown events to the dragable.
* @method
*/
Dragable.prototype.init = function () {
//Find the widget's node
this.node = document.getElementById(this.id);
var o = this;
//Add mousedown, focus, blur, and keydown events to the dropbasket
browser.addEvent(this.node, "mousedown", function(event){handleDragableMouseDownEvent(event,o);},false);
browser.addEvent(this.node, "keydown", function(event){handleDragableKeyDownEvent(event,o);},false);
browser.addEvent(this.node, "focus", function(event){handleDragableFocusEvent(event,o);},false);
browser.addEvent(this.node, "blur", function(event){handleDragableBlurEvent(event,o);},false);
//Find the widget's initial position
this.initial_x = browser.calculateOffsetLeft(this.node);
this.initial_y = browser.calculateOffsetTop(this.node);
//Have widgets naturally snap back to position if not dropped on a Drop Basket
this.basketOnly = true;
}
/**
* handleESC event is called when a key is pressed.
* If the escape key is pressed and a dragable has been grabbed with the keyboard,
* it is dropped
* @param {Object,Event} event
*/
handleESCEvent = function (event) {
//Abstract the event object, for multi-browser compatability
var e = event || window.event;
switch( browser.keyCode(e) ) {
case KEY_ESCAPE:
//Check whether anything is being dragged with the keyboard
if (dragObjectKB != null) {
//Tell the browser to keep track of it's absolute location
if (dragObjectKB.node.style.position != 'absolute')
dragObjectKB.node.style.position = 'absolute';
//Move the dragable back to it's original position
browser.setNodePosition(dragObjectKB.node,dragObjectKB.initial_x,dragObjectKB.initial_y);
//Tell assistive technologies that the dragable is not being dragged anymore
dragObjectKB.node.setAttribute("aria-grabbed", "true");
dragObjectKB.node.className = "";
//Call the onBadDrop function
onBadDrop(dragObjectKB);
//Tell the application that nothing is being dragged with the keyboard
dragObjectKB = null;
//Cycle through all the widgets
for (var o = 0; o < widgets.widgets.length; o++) {
//Check whether the widget is a dropbasket
if (widgets.widgets[o].constructor == DropBasket) {
// Set aria-dropeffect to none
widgets.widgets[o].node.setAttribute("aria-dropeffect", "none");
//Get rid of the "available" class in the dropbasket
var i = widgets.widgets[o].node.className.indexOf(" available");
if (i != -1) {
var s = widgets.widgets[o].node.className.substr(0,i);
s += widgets.widgets[o].node.className.substr(i+10);
widgets.widgets[o].node.className = s;
}
}
}
//Stop the propagation of this event. This is abstracted, for multi-browser compatability
return browser.stopPropagation(e);
}
break;
}
}
/**
* This function is called when a keydown event is sent to a drop basket.
* If space is pressed, and a dragable has been picked up using the keyboard, it will be dropped on the drop basket
* @param {Object,Event} event
* @param {Object,DropBasket} basket
*/
handleDropBasketKeyDownEvent = function(event,basket) {
//Abstract the event object, for multi-browser compatability
var e = event || window.event;
switch( browser.keyCode(e) ) {
case KEY_SPACE:
//If there is an object being dragged with the keyboard and the dropbasket is not disabled
if (dragObjectKB != null && !basket.disabled) {
//Tell the browser to keep track of it's absolute location
if (dragObjectKB.node.style.position != 'absolute')
dragObjectKB.node.style.position = 'absolute';
//Check whether the dragable should be copied or referenced, instead of moved
if (basket.node.getAttribute("aria-dropeffect") != "move") {
//Move the dragable back to it's original position
browser.setNodePosition(dragObjectKB.node,dragObjectKB.initial_x,dragObjectKB.initial_y);
}
//Check whether the dragable should be copied, instead of moved or referenced
if (basket.node.getAttribute("aria-dropeffect") == "copy") {
//Find how many dragables are already in the dropbasket
var i = basket.contents.length;
//Add a copy of the dragable to the contents array of the dropbasket
//Note: only the node of the object is copied, the dragable widget is not;
//therefore, the copied node is not dragable.
//To turn this node into a dragable widget see the 2nd drag and drop example at
//http://test.cita.uiuc.edu/aria/
basket.contents.push(dragObjectKB.node.cloneNode(true));
//Add the copied node to the webpage
basket.node.appendChild(basket.contents[i]);
//Do not allow the browser to give focus to the copied node
//To undo this, use the removeAttribute function
basket.contents[i].setAttribute("aria-disabled","true");
//Remove the copied node's class
basket.contents[i].className = "";
//Tell Assistive technologies that you cannot grab this node
//To undo this set aria-grab to supported
basket.contents[i].setAttribute("aria-grabbed", "false");
//Set the position of the copied node to the center of the dropbasket
browser.setNodePosition(basket.contents[i],browser.calculateOffsetLeft(basket.node)+basket.node.offsetWidth/2-dragObjectKB.node.offsetWidth/2,browser.calculateOffsetTop(basket.node)+basket.node.offsetHeight/2-dragObjectKB.node.offsetHeight/2);
}
//Call onBasketDrop
onBasketDrop(dragObjectKB,basket,false);
//Tell assistive technologies that the dragable is not being dragged anymore
dragObjectKB.node.setAttribute("aria-grabbed", "true");
//Remove the copied node's class
dragObjectKB.node.className = "";
//Tell the application that nothing is being dragged with the keyboard
dragObjectKB = null;
//Cycle through all the widgets
for (var o = 0; o < widgets.widgets.length; o++) {
//Check whether the widget is a dropbasket
if (widgets.widgets[o].constructor == DropBasket) {
// Remove the aria-dropeffect attribute
widgets.widgets[o].node.setAttribute("aria-dropeffect", "none");
//Get rid of the "available" class in the dropbasket
var i = widgets.widgets[o].node.className.indexOf(" available");
if (i != -1) {
var s = widgets.widgets[o].node.className.substr(0,i);
s += widgets.widgets[o].node.className.substr(i+10);
widgets.widgets[o].node.className = s;
}
}
}
} else {
//Call the onBasketNoDrop function
onBasketNoDrop();
}
//Stop the propagation of this event. This is abstracted, for multi-browser compatability
return browser.stopPropagation(e);
break;
}
}
/**
* This function is called when a dragable is sent a keydown event.
* If space is pressed, the dragable is picked up.
* @param {Event Object} event
* @param {Dragable Object} dragable
* @returns false if the key was not space
*/
handleDragableKeyDownEvent = function(event, dragable) {
//If IE get the IE event object
var e = event || window.event;
if (e.cancelBubble)
return;
switch( browser.keyCode(e) ) {
case KEY_SPACE:
//Check whether the dragable is disabled
if (!dragable.disabled) {
//Check whether anything is being dragged with the keyboard
if (dragObjectKB != null) {
//Call the onBadDrop function
onBadDrop(dragObjectKB);
//Don't focus on the previously grabbed dragable
dragable.node.focus();
//Tell assistive technologies that any previously grabbed dragable is dropped
dragObjectKB.node.setAttribute("aria-grabbed", "true");
dragObjectKB.node.className = "";
}
//Tell the application that this widget is being dragged with the keyboard
dragObjectKB = dragable;
//Add the available class to all dropbaskets that are not disabled
for (var o = 0; o < widgets.widgets.length; o++) {
if (widgets.widgets[o].constructor == DropBasket && !widgets.widgets[o].disabled)
// Mark the widgets that can receive a X or O
widgets.widgets[o].node.setAttribute("aria-dropeffect", "copy");
// Provide visual styling to the cells
widgets.widgets[o].node.className += " available";
}
//Tell assistive technologies that the dragable is grabbed
dragable.node.setAttribute("aria-grabbed", "true");
//Change the styling of the grabable to indicate it is grabbed
dragable.node.className = "grabbed";
//Call the onDragableGrab function
onDragableGrab(dragable);
//Stop the propagation of this event. This is abstracted, for multi-browser compatability
return browser.stopPropagation(e);
}
break;
}
return false;
}
/**
* This is called when a grid is sent a keydown event.
* If an arrow key is pressed, the selected cell changes,
* otherwise the event is resent to the selected cell.
* @param {Object,Event} event
* @param {Object,Grid} grid
*/
handleGridKeyDownEvent = function(event, grid) {
// If IE get the IE event object
var e = event || window.event;
switch( browser.keyCode(e) ) {
case KEY_DOWN:
if (grid.row+1 < grid.rows)
grid.row++;
grid.node.rows[grid.row].cells[grid.cell].focus();
return browser.stopPropagation(e);
break;
case KEY_RIGHT:
if (grid.cell+1 < grid.columns)
grid.cell++;
grid.node.rows[grid.row].cells[grid.cell].focus();
return browser.stopPropagation(e);
break;
case KEY_UP:
if (grid.row > 0)
grid.row--;
grid.node.rows[grid.row].cells[grid.cell].focus();
return browser.stopPropagation(e);
break;
case KEY_LEFT:
if (grid.cell > 0)
grid.cell--;
grid.node.rows[grid.row].cells[grid.cell].focus();
return browser.stopPropagation(e);
break;
}
}
/**
* This function is called when the grid is sent a focus event.
* @param {Object,Event} event
* @param {Object,Grid} grid
*/
handleGridFocusEvent = function(event, grid) {
var e = event || window.event;
//Focus on the top left cell
grid.row = 0;
grid.cell = 0;
grid.node.tabIndex = -1;
grid.node_last_cell = null;
grid.node.rows[grid.row].cells[grid.cell].focus();
return browser.stopPropagation(e);
}
/**
* This function is called when the grid is sent a blur event.
* @param {Object,Event} event
* @param {Object,Grid} grid
*/
handleCellBlurEvent = function(event, grid, row, cell) {
//If IE get the IE event object
var e = event || window.event;
//Find the node of the cell
var c = grid.node.rows[row].cells[cell];
//Get rid of the focus class
c.className.replace(/focus/,"");
return browser.stopPropagation(e);
}
/**
* This function is called when the cell is sent a focus event.
* @param {Object,Event} event
* @param {Object,Grid} grid
* @param {integer} row
* @param {integer} cell
*/
handleCellFocusEvent = function(event,grid,row,cell) {
//If IE get the IE event object
var e = event || window.event;
//Tell the grid which cell is focused
grid.row = row;
grid.cell = cell;
//Find the node of the cell
var c = grid.node.rows[grid.row].cells[grid.cell];
//Add the focus class
c.className += ' focus';
//If the cell is a dropbasket, call the corresponding dropbasket event
var basket = null;
for (var o = 0; o < widgets.widgets.length; o++) {
if (widgets.widgets[o].node == c)
basket = widgets.widgets[o];
}
if (basket && basket.constructor == DropBasket)
handleDropBasketFocusEvent(event,basket);
return browser.stopPropagation(e);
}
/**
* This fucntion is called when a DropBasket is sent a focus event
* @param {Object,Event} event
* @param {Object,DropBasket} basket
*/
handleDropBasketFocusEvent = function(event,basket) {
//If IE get the IE event object
var e = event || window.event;
if (e.cancelBubble)
return;
//If there is a widget being dragged with the keyboard that can be dropped on the dropbasket
if (dragObjectKB && !basket.disabled) {
//Move the dragable to be centered over the dropbasket
if (dragObjectKB.node.style.position != 'absolute')
dragObjectKB.node.style.position = 'absolute';
browser.setNodePosition(dragObjectKB.node,browser.calculateOffsetLeft(basket.node)+basket.node.offsetWidth/2-dragObjectKB.node.offsetWidth/2,browser.calculateOffsetTop(basket.node)+basket.node.offsetHeight/2-dragObjectKB.node.offsetHeight/2);
}
//Call the onBasketOver event
onBasketOver(dragObjectKB,basket,false,e);
}
/**
* This fucntion is called when a DropBasket is sent a mouseover event
* @param {Object,Event} event
* @param {Object,DropBasket} basket
*/
handleDropBasketMouseOverEvent = function(event,basket) {
//If IE get the IE event object
var e = event || window.event;
//Call the onBasketOver event
onBasketOver(dragObject,basket,true,e);
}
handleDropBasketMouseOutEvent = function(event,basket) {
//If IE get the IE event object
var e = event || window.event;
//Call the onBasketOut event
onBasketOut(dragObject,basket);
}
handleDropBasketBlurEvent = function(event,basket) {
//If there was a dragable hovering over the basket, move it bask to its original position
if (dragObjectKB && !basket.disabled) {
browser.setNodePosition(dragObjectKB.node,dragObjectKB.initial_x,dragObjectKB.initial_y);
}
//Call the onBasketOut event
onBasketOut(dragObject,basket);
}
handleDragableFocusEvent = function(event,dragable) {
var e = event || window.event;
if (e.cancelBubble)
return;
if (dragable.node.classnName == "")
dragable.node.className += " ";
dragable.node.className += ' focus';
return browser.stopPropagation(e);
}
handleDragableBlurEvent = function(event,dragable) {
var e = event || window.event;
if (e.cancelBubble)
return;
var i = dragable.node.className.indexOf(" focus");
if (i != -1 || (i = dragable.node.className.indexOf("focus")) != -1) {
var s = dragable.node.className.substr(0,i);
s += dragable.node.className.substr(i+6);
dragable.node.className = s;
}
return browser.stopPropagation(e);
}
//Add keydown, mouseup, and mousemove events to the entire document
browser.addEvent(document,"keydown", function(event) {handleESCEvent(event);},false);
browser.addEvent(document,"mouseup", function(event) {mouseUp(event);},false);
browser.addEvent(document,"mousemove", function(event) {mouseMove(event);},false); </script>
//The Tic Tac Toe Game
var games = 0;
var turn;
//When the user clicks the Start button
gameStart = function () {
//Set it to O's turn
turn = 1;
//If there is anything being dragged with the keyboard, drop it
if (dragObjectKB) {
dragObjectKB.node.setAttribute("aria-grabbed", "true");
dragObjectKB.node.className = "";
dragObjectKB = null;
for (o in widgets.widgets) {
if (widgets.widgets[o].constructor == DropBasket) {
var i = widgets.widgets[o].node.className.indexOf(" available");
if (i != -1) {
var s = widgets.widgets[o].node.className.substr(0,i);
s += widgets.widgets[o].node.className.substr(i+10);
widgets.widgets[o].node.className = s;
}
}
}
}
//Check whether any games have been played
if (games == 0) {
//Add an onBasketDrop function
onBasketDrop = function (dragable,basket) {
//Set the position of the copied node to the center of the dropbasket
browser.setNodePosition(basket.contents.slice(-1).pop(),browser.calculateOffsetLeft(basket.node)+basket.node.offsetWidth/2-dragable.node.offsetWidth/2,browser.calculateOffsetTop(basket.node)+basket.node.offsetHeight/2-dragable.node.offsetHeight/2);
//Disable the copied gamepiece and the place it was dropped
dragable.disabled = true;
basket.disabled = true;
// Update cell information
// Change the label of the cell to say what it now contains
var node_label = document.getElementById(basket.node.getAttribute("aria-labelledby"));
var str_label = node_label.firstChild.data;
str_label = str_label.substr(0,str_label.indexOf("Cell"));
if (dragable.node.getAttribute("id") == "ex") {
basket.game_value = 1;
str_label += "Cell contains an X";
} else {
basket.game_value = 2;
str_label += "Cell contains an O";
}
node_label.firstChild.data = str_label;
gameTurn();
}
//Add an onBasketNoDrop function
onBasketNoDrop = function (dragable,basket) {
//If tries to use the keyboard to drop on basket, but nothing is picked up
//alert the user that they need to pick something up
if (turn) {
document.getElementById("out").value = "You need to pick up an O";
} else {
document.getElementById("out").value = "You need to pick up an X";
}
}
}
//Cycle through all the widgets
for (o in widgets.widgets) {
//Check whether the widget is a dropbasket
if (widgets.widgets[o].constructor == DropBasket) {
//Get rid of anything in the game grid
widgets.widgets[o].game_value = 0;
while (widgets.widgets[o].contents.length > 0)
widgets.widgets[o].node.removeChild(widgets.widgets[o].contents.pop());
//Get rid of any winner or dubwinner class
i = widgets.widgets[o].node.className.indexOf(" winner");
if (i != -1) {
s = widgets.widgets[o].node.className.substr(0,i);
s += widgets.widgets[o].node.className.substr(i+7);
widgets.widgets[o].node.className = s;
}
i = widgets.widgets[o].node.className.indexOf(" dubwinner");
if (i != -1) {
s = widgets.widgets[o].node.className.substr(0,i);
s += widgets.widgets[o].node.className.substr(i+10);
widgets.widgets[o].node.className = s;
}
}
//Enable all widgets
widgets.widgets[o].disabled = false;
widgets.widgets[o].node.setAttribute("aria-disabled", "false");
}
//Add one to the number of games
games++;
//Start the first turn
gameTurn();
}
//This function is used to add the winner class to a cell
wincell = function (row,column) {
c = cell[row][column].node;
var i = c.className.indexOf(" winner");
if (i == -1) {
c.className += " winner";
} else {
s = c.className.substr(0,i);
s += c.className.substr(i+7);
c.className = s + " dubwinner";
}
}
gameTurn = function () {
var w = false;
//Check whether anyone has gotten 3 in a row
for (i in cell) {
var r = 0
for (ii in cell[i]) {
if (cell[i][ii].game_value == 0)
break;
else if (r == 0)
r = cell[i][ii].game_value;
else if (cell[i][ii].game_value != r)
break;
else if (ii == 2) {
wincell(i,0);
wincell(i,1);
wincell(i,2);
w = true;
}
}
}
//Check whether anyone has gotten 3 in a column
for (ii = 0; ii < 3; ii++) {
var c = 0;
for (i in cell) {
if (cell[i][ii].game_value == 0)
break;
else if (c == 0)
c = cell[i][ii].game_value;
else if (cell[i][ii].game_value != c)
break;
else if (i == 2) {
wincell(0,ii);
wincell(1,ii);
wincell(2,ii);
w = true;
}
}
}
//Check whether anyone has filled the descending diagonal
if (cell[0][0].game_value != 0 && cell[0][0].game_value == cell[1][1].game_value && cell[1][1].game_value == cell[2][2].game_value) {
wincell(0,0);
wincell(1,1);
wincell(2,2);
w = true;
}
//Check whether anyone has filled the ascending diagonal
if (cell[0][2].game_value != 0 && cell[0][2].game_value == cell[1][1].game_value && cell[1][1].game_value == cell[2][0].game_value) {
wincell(0,2);
wincell(1,1);
wincell(2,0);
w = true;
}
//If anyone has won
if (w) {
if (turn)
document.getElementById("out").value = "O Wins";
else
document.getElementById("out").value = "X Wins";
//Disable all widgets
for (o in widgets.widgets) {
widgets.widgets[o].disabled = true;
widgets.widgets[o].node.setAttribute("aria-disabled", "true");
}
//Don't do the rest of the function
return;
}
//If all the squares are filled, it's a cat's game
cat:
for (i in cell) {
for (ii in cell[i]) {
if (cell[i][ii].game_value == 0)
break cat;
if (i == 2 && ii == 2) {
document.getElementById("out").value = "Cat's Game";
//Don't do the rest of the function
return;
}
}
}
//Switch whose turn it is
turn = !turn;
if (turn)
document.getElementById("out").value = "O's Turn";
else
document.getElementById("out").value = "X's Turn";
for (o in widgets.widgets) {
if (widgets.widgets[o].constructor == Dragable) {
if (widgets.widgets[o].node.getAttribute("id") == "ex")
widgets.widgets[o].disabled = turn;
else
widgets.widgets[o].disabled = !turn;
widgets.widgets[o].node.setAttribute("aria-disabled", widgets.widgets[o].disabled);
}
}
} </script>