Drag and Drop Navigation Menu
Drag and Drop Example 2
Keyboard Shortcuts
- Tab: Move between slideshow and pictures
- Space: Pick up / Drop picture
- Left/Right Arrow: Move between slides
- Escape: Cancel picture grab
- Delete: Delete focused slide from slide show
- Backspace: Delete focused slide from slide show
ARIA Roles and Properties
- Roles:
role="application"
role="listbox"
role="option"
- States and properties:
aria-labeledby
aria-disabled
aria-grabbed
aria-dropeffect
aria-selected
HTML Source Code
Show HTML Source Code: draganddrop2.inc
<div role="application">
<script type="text/javascript">
slides = new SlideArray("slides");
widgets.add(slides);
slide1 = new Slide("slide1");
slides.add( slide1 );
slide2 = new Slide("slide2");
slides.add( slide2 );
slide3 = new Slide("slide3");
slides.add( slide3 );
var pictures = new DragablePictureArray("pictures", slides);
widgets.add( pictures );
picture1 = new DragablePicture("picture1");
pictures.add(picture1);
picture2 = new DragablePicture("picture2");
pictures.add(picture2);
picture3 = new DragablePicture("picture3");
pictures.add(picture3);
picture4 = new DragablePicture("picture4");
pictures.add(picture4);
picture5 = new DragablePicture("picture5");
pictures.add(picture5);
</script>
<H3>Available Pictures:</H3>
<ul id="pictures" class="pictures" tabindex="0" role="listbox">
<li id="picture1"
role="option"
aria-grabbed="false"
aria-labelledby="picture1-label"
tabindex="-1">
<img
role="presentation"
src="images/B170.jpg"
alt="Picture of the National Museum of Natural History"
width="91px"
height="80px"/>
<span
class="hidden"
id="picture1-label">
Picture of the National Museum of Natural History
</span>
</li>
<li id="picture2"
role="option"
aria-grabbed="false"
aria-labelledby="picture2-label"
tabindex="-1">
<img
role="presentation"
src="images/B175.jpg"
alt="Picture of The Castle, the Smithsonian's headquarters"
width="91px"
height="80px"/>
<span
class="hidden"
id="picture2-label">
Picture of "The Castle", the Smithsonian's headquarters</span>
</li>
<li id="picture3"
role="option"
aria-grabbed="false"
aria-labelledby="picture3-label"
tabindex="-1">
<img role="presentation" src="images/C200.jpg"
alt="Picture of the J. Edgar Hoover Building, the FBI's headquarters"
width="91px" height="80px"/>
<span class="hidden" id="picture3-label">Picture of the J. Edgar Hoover Building, the
FBI's headquarters</span>
</li>
<li id="picture4"
role="option"
aria-grabbed="false"
aria-labelledby="picture4-label"
tabindex="-1">
<img role="presentation" src="images/C295.jpg"
alt="Picture of a water feature at the Franklin Delano Roosevelt Memorial Park"
width="91px" height="80px"/>
<span class="hidden" id="picture4-label">Picture of a water feature at the Franklin
Delano Roosevelt Memorial Park</span>
</li>
<li id="picture5"
role="option"
aria-grabbed="false"
aria-labelledby="picture5-label"
tabindex="-1">
<img role="presentation" src="images/D300.jpg"
alt="Picture of another water feature at the FDR Memorial Park" width="91px"
height="80px"/>
<span class="hidden" id="picture5-label">Picture of another water feature at the FDR
Memorial Park</span>
</li>
</ul>
<h3 id="slides-label">Slideshow</h3>
<ul class="slides"
id="slides"
aria-labelledby="slides-label slides-num"
role="listbox"
tabindex="0">
<li id="slide1"
role="option"
class="insert"
aria-dropeffect="none"
aria-labelledby="slide1-label"
tabindex="-1">
<span class="hidden" id="slide1-label">Insert as slide 1</span>
</li>
<li id="slide2"
role="option"
class="slide"
aria-grabbed="false"
aria-labelledby="slide2-label slide2-caption"
tabindex="-1">
<img role="presentation"
src="images/D300.jpg"
alt="Picture of another water feature at the FDR Memorial Park"
width="91px"
height="80px"
/>
<span class="hidden" id="slide2-caption">Picture of another water feature at the FDR Memorial Park</span>
<span class="hidden" id="slide2-label">Slide 1</span>
</li>
<li id="slide3"
role="option"
class="insert"
aria-dropeffect="none"
aria-labelledby="slide3-label"
tabindex="-1">
<span class="hidden" id="slide3-label">Insert as slide 2</span>
</li>
</ul>
<div id="slides-num" class="hidden">There are no slides in the show</div>
<p class="caption"><label for="caption">Slide Caption: </label><input id="caption" type="text" size="50"/> <input id="set_caption" type="button" value="Update Caption"/></p>
<ol id="test1"></ol>
<ol id="test2"></ol>
</div>
Javascript Source Code
Show Javascript Source Code: globals.js
<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";
// **********************************************
// *
// * Commonly used helper functions
// *
// **********************************************
/**
*
* nextSiblingElement
*
* @contructor
*/
function nextSiblingElement( node ) {
var next_node = node.nextSibling;
while( next_node
&& (next_node.nodeType != Node.ELEMENT_NODE) ) {
next_node = next_node.nextSibling;
} // endwhile
return next_node;
}
/**
*
* previousSiblingElement
*
* @param ( node ) node object for which you are looking for the next sibling element node
*
* @return ( node) next sibling or "null"
*/
function previousSiblingElement( node ) {
var next_node = node.previousSibling;
while( next_node
&& (next_node.nodeType != Node.ELEMENT_NODE) ) {
next_node = next_node.previousSibling;
} // endwhile
return next_node;
}
/**
*
* firstChildElement
*
* @param ( node ) node object for which you are looking for the first child element node
*
* @return ( node) next sibling or "null"
*/
function firstChildElement( node ) {
var next_node = node.firstChild;
while( next_node
&& (next_node.nodeType != Node.ELEMENT_NODE) ) {
next_node = next_node.nextSibling;
} // endwhile
return next_node;
}
/**
*
* getTextContentOfNode
*
* @contructor
*/
function getTextContentOfNode( node ) {
var next_node = node.firstChild;
var str = "";
while( next_node ) {
if( (next_node.nodeType == Node.TEXT_NODE ) &&
(next_node.length > 0 )
)
str += next_node.data;
next_node = next_node.nextSibling;
} // endwhile
return str;
}
/**
*
* setTextContentOfNode
*
* @contructor
*/
function setTextContentOfNode( node, text ) {
// Generate a new text node with the text value
var text_node = document.createTextNode(text);
// Remove child nodes to remove text
while (node.firstChild) {
node.removeChild(node.firstChild);
} // while
// Append new text to the container element
node.appendChild( text_node );
}
</script>
Show Javascript Source Code: browser.js
<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;
return e.keyCode;
}
/**
* OnClick Event Simulator
*
* @param ( node ) DOM node object
* @return nothing
*/
if( document.createEvent ) {
// 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
WebBrowser.prototype.simulateOnClickEvent = function( node ) {
var e = document.createEventObject();
node.fireEvent( "onclick", e );
} // endif
}
if ( document.addEventListener ) {
// If a web standards based browser implement this function
WebBrowser.prototype.setMouseCapture = function( node, clickHandler, downHandler, moveHandler, upHandler ) {
if( clickHandler )
document.addEventListener( "click", clickHandler, true );
if( downHandler )
document.addEventListener( "mousedown", downHandler, true );
if( moveHandler )
document.addEventListener( "mousemove", moveHandler, true );
if( upHandler)
document.addEventListener( "mouseup", upHandler, true );
}
WebBrowser.prototype.releaseMouseCapture = function( node, clickHandler, downHandler, moveHandler, upHandler ) {
if( upHandler)
document.removeEventListener( "mouseup", upHandler, true );
if( moveHandler )
document.removeEventListener( "mousemove", moveHandler, true );
if( downHandler )
document.removeEventListener( "mousedown", downHandler, true );
if( clickHandler )
document.removeEventListener( "click", clickHandler, true );
}
} else {
// If a Microsoft IE based browser implement this function
WebBrowser.prototype.setMouseCapture = function( node, clickHandler, downHandler, moveHandler, upHandler ) {
node.setCapture();
if( clickHandler)
node.attachEvent( "onclick", clickHandler );
if( downHandler)
node.attachEvent( "onmousedown", downHandler );
if( moveHandler )
node.attachEvent( "onmousemove", moveHandler );
if( upHandler )
node.attachEvent( "onmouseup", upHandler );
} // endif
WebBrowser.prototype.releaseMouseCapture = function( node, clickHandler, downHandler, moveHandler, upHandler ) {
if( upHandler )
node.detachEvent( "onmouseup", upHandler );
if( moveHandler )
node.detachEvent( "onmousemove", moveHandler );
if( downHandler)
node.detachEvent( "onmousedown", downHandler );
if( clickHandler)
node.detachEvent( "onclick", clickHandler );
node.releaseCapture();
} // endif
}
if (typeof document.documentElement.setAttributeNS != 'undefined') {
WebBrowser.prototype.stopPropagation = function( event ) {
if( event.stopPropagation )
event.stopPropagation();
if( event.preventDefault )
event.preventDefault();
return false;
}
WebBrowser.prototype.target = function( event ) {
return event.target;
}
WebBrowser.prototype.attrName = function( event ) {
return event.attrName;
}
WebBrowser.prototype.testAttrName = function( event , attrName) {
return event.attrName == attrName;
}
WebBrowser.prototype.charCode = function(event) {
return event.charCode;
}
WebBrowser.prototype.calculateOffsetLeft = function( node ) {
return node.offsetLeft;
}
WebBrowser.prototype.calculateOffsetTop = function( node ) {
return node.offsetTop;
}
WebBrowser.prototype.pageX = function( e ) {
return e.pageX;
}
WebBrowser.prototype.pageY = function( e ) {
return e.pageY;
}
WebBrowser.prototype.setNodePosition = function(node,left,top) {
node.style.left = left+"px";
node.style.top = top+"px";
}
} else {
WebBrowser.prototype.stopPropagation = function( event ) {
event.cancelBubble = true;
event.returnValue = false;
return false;
}
WebBrowser.prototype.charCode = function(event) {
return window.browser.keyCode( event );
}
WebBrowser.prototype.target = function( event ) {
return event.srcElement;
}
WebBrowser.prototype.attrName = function( event ) {
return event.propertyName;
}
WebBrowser.prototype.testAttrName = function( event , attrName) {
var str = attrName;
if( attrName.indexOf("aria-") >=0 ) {
str = attrName.replace(/aria-/,"");
var node = document.getElementById('test1');
if( node )
node.innerHTML = str.substr(0,1).toUpperCase();
var len = str.length;
str = "aria" + str.substr(0,1).toUpperCase() + str.substr(1, len);
var node = document.getElementById('test2');
// if( node )
// node.innerHTML = node.innerHTML + "<li>" + str + "</li>";
}
return event.propertyName == str;
}
WebBrowser.prototype.calculateOffsetLeft = function(node) {
var offset = 0;
while( node ) {
offset += node.offsetLeft;
node = node.offsetParent;
}
return offset;
}
WebBrowser.prototype.calculateOffsetTop = function(node) {
var offset = 0;
while( node ) {
offset = offset + node.offsetTop;
node = node.offsetParent;
}
return offset;
}
WebBrowser.prototype.pageX = function( e ) {
return e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
}
WebBrowser.prototype.pageY = function( e ) {
return e.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
}
WebBrowser.prototype.setNodePosition = function(node,left,top) {
offsetx = 0;
offsety = 0;
nnode = node.offsetParent
while( nnode ) {
offsetx = offsetx + nnode.offsetLeft;
offsety = offsety + nnode.offsetTop;
nnode = nnode.offsetParent;
}
node.style.left = left-offsetx+"px";
node.style.top = top-offsety+"px";
}
};
if (document.addEventListener) {
// Functions for W3C Standards compliant implementation of adding event handlers
WebBrowser.prototype.addEvent = function(elmTarget, sEventName, fCallback) {
elmTarget.addEventListener(sEventName, fCallback, false);
returnValue = true;
};
WebBrowser.prototype.removeEvent = function(elmTarget, sEventName, fCallback) {
elmTarget.removeEventListener(sEventName, fCallback, false);
returnValue = true;
};
WebBrowser.prototype.addChangeEvent = function(elmTarget, fCallback) {
elmTarget.addEventListener("DOMAttrModified", fCallback, false);
returnValue = true;
};
} else {
if(document.attachEvent) {
// IE Specific Event handler functions
WebBrowser.prototype.addEvent = function(elmTarget, sEventName, fCallback) {
returnValue = elmTarget.attachEvent('on' + sEventName, fCallback);
};
WebBrowser.prototype.removeEvent = function(elmTarget, sEventName, fCallback) {
returnValue = elmTarget.detachEvent('on' + sEventName, fCallback);
};
WebBrowser.prototype.addChangeEvent = function(elmTarget, fCallback) {
returnValue = elmTarget.attachEvent("onpropertychange", fCallback);
};
} else {
// For browsers that do not support W3C or IE event functions
WebBrowser.prototype.addEvent = function(elmTarget, sEventName, fCallback) {
return false;
};
WebBrowser.prototype.removeEvent = function(elmTarget, sEventName, fCallback) {
return false;
};
WebBrowser.prototype.addChangeEvent = function(elmTarget, fCallback) {
return false;
};
}
}
var browser = new WebBrowser();
</script>
Show Javascript Source Code: widgets.js
<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
*/
Widgets.prototype.add = function(obj) {
this.widgets[this.widgets.length] = obj;
}
/**
* 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();
}
var widgets = new Widgets();
function initApp() {
widgets.init();
}
</script>
Show Javascript Source Code: draganddrop2.js
<script type="text/javascript">
/**
*
* The SlideShow object is used to maintain information about a slide show
*
* @constructor
*/
function SlideArray( id ) {
this.id = id;
this.slides = new Array();
this.node_grab = null;
this.slide_selected = 0;
} // end SlideArray
/**
* init is a subclass of SlideShow and is used to initialize the event handlers and
* slide objects.
*
* @member SlideArray
*
* @return none
*/
SlideArray.prototype.init = function() {
this.node = document.getElementById( this.id );
for(var i = 0; i < this.slides.length; i++ ) {
this.slides[i].init();
} // endfor
var obj = this;
// Add event handlers keyboard
browser.addEvent(this.node, "keydown", function(event) {handleSlideArrayKeyDownEvent(event, obj);}, false);
browser.addEvent(this.node, "mousedown", function(event) {handleSlideArrayMouseDownEvent(event, obj);}, false);
// Add event handlers for moving picture into the slide show
browser.addEvent(this.node, "focus", function(event) {handleSlideArrayFocusEvent(event, obj);}, false);
var node = document.getElementById("set_caption");
// Add event handler to the caption editing box
browser.addEvent( node, "click", function(event) {handleCaptionClickEvent(event, obj);}, false);
}
/**
* add is a subclass of SlideShow and is used to provide a reference to all
* Slide objects.
*
* @member SlideShow
*
* @return none
*/
SlideArray.prototype.add = function( obj ) {
// add picture to array
this.slides[this.slides.length] = obj;
}
/**
*
* The Slide object is used to maintain information about a slide
*
* @constructor
*/
function Slide( id ) {
this.id = id;
} // end SlideShow
/**
*
* The Slide object is used to maintain information about a slide
*
* @constructor
*/
Slide.prototype.init = function () {
this.node = document.getElementById( this.id );
var obj = this;
// Add event handlers for moving picture into the slide show
browser.addEvent(this.node, "focus", function(event) {handleSlideFocusEvent(event, obj);}, false);
//
browser.addChangeEvent( this.node, function(event) {handleSlideChangeEvent(event, obj);});
} // end SlideShow
/**
* handleSlideChangeEvent
*
* @param ( Slide object ) slide
*
* @return none
*/
function handleSlideChangeEvent( event, slide ) {
// If IE get the IE event object
var e = event || window.event;
// Check which attributes changed and if they are aria attribute kick IE to update styling
if( browser.testAttrName(e, "aria-selected") ||
browser.testAttrName(e, "aria-grabbed") ||
browser.testAttrName(e, "aria-dropeffect")
) {
// Kick IE to update styling
slide.node.className += "";
}
return browser.stopPropagation(e);
}
/**
* handleSlideMouseDownEvent is called by event handlers to initialize listbox
*
* @param ( SlideArray object ) slide_array
*
* @return none
*/
function handleSlideArrayMouseDownEvent( event, slide_array ) {
var e = event || window.event;
var node = browser.target(e);
if( node.tagName != "LI" )
node = node.parentNode;
var index = slideArrayGetSlideIndex( slide_array, node );
slideArraySelect( slide_array, index , 1 );
return browser.stopPropagation( e );
}
/**
* handleSlideArrayFocusEvent
*
* @param ( SlideArray object ) slide_array
*
* @return none
*/
function handleSlideArrayFocusEvent( event, slide_array ) {
var e = event || window.event;
slideArraySelect( slide_array, 0, 1 );
return browser.stopPropagation( e );
}
/**
* handleSlideFocusEvent
*
* @param ( Slide object ) slide
*
* @return none
*/
function handleSlideFocusEvent( event, slide ) {
var e = event || window.event;
var node_caption = document.getElementById("caption");
var nodes = slide.node.getElementsByTagName("span");
if( nodes.length > 1 ) {
node_caption.value = nodes[0].innerHTML;
node_caption.readOnly = false;
} else {
node_caption.value = "";
node_caption.readOnly = true;
}
return browser.stopPropagation( e );
}
/**
* handleCaptionClickEvent
*
* @param ( SlideArray object ) slide_array
*
* @return none
*/
function handleCaptionClickEvent( event, slide_array ) {
var e = event || window.event;
var node_caption = document.getElementById("caption");
if( node_caption.readOnly == false ) {
slide_array.slides[slide_array.slide_selected].node.getElementsByTagName("span")[0].innerHTML = node_caption.value;
}
return browser.stopPropagation( e );
}
/**
* handleSlideArrayKeyDownEvent processes keys associated with a radio button group
*
* @param ( event ) event is the event handler for the event
* @param ( SlideArray object ) slide_array
*
* @return false if keyboard event was used by SlideArray, else true
*/
function handleSlideArrayKeyDownEvent( event, slide_array ) {
// If IE get the IE event object
var e = event || window.event;
// If any modifier keys are pressed do not process this event
if( e.altKey || e.ctrlKey || e.shiftKey )
return true;
switch( e.keyCode ) {
case KEY_SPACE:
// Pressing space will pickup the current picture
slideArrayInsertDragablePicture( slide_array, slide_array.slides[slide_array.slide_selected].node );
return browser.stopPropagation( e );
break;
case KEY_RIGHT:
case KEY_DOWN:
slideArraySelect( slide_array, (slide_array.slide_selected + 1), 1);
// Tell browser we handled this event and not to process any other actions
return browser.stopPropagation( e );
break;
case KEY_LEFT:
case KEY_UP:
slideArraySelect( slide_array, (slide_array.slide_selected - 1), 1);
// Tell browser we handled this event and not to process any other actions
return browser.stopPropagation( e );
break;
} // end switch
return true;
} // end handleSlideArrayKeyDownEvent
/**
* slideArraySelect is called by event handlers to select one of the picutres in the array
*
* @param ( SlideArray Object )
* @param ( integer ) index Index of slide to be selected
* @param ( integer ) focus_flag If value is set to 1 then keyboard focus will be moved to the selected slide
*
* @return none
*/
function slideArraySelect( slide_array, index, focus_flag ) {
// Check to see if index is larger than the number of picutre, if so wrap to first picutre
if( index >= slide_array.slides.length )
index = 0;
// Check to see if index is less than zero, if so wrap to last radio button
if( index < 0)
index = slide_array.slides.length - 1;
// Check to make sure the index value is valid before changing states
if( (index >= 0 ) && (index < slide_array.slides.length) ) {
// Set all pictures to not grabbed and not focused
// Tabindex is set to -1 so the control can still receive focus, but is removed from tab order
for(var i = 0; i < slide_array.slides.length; i++ ) {
slide_array.slides[i].node.setAttribute("aria-selected","false");
// Make sure item is not the deafult tab stop
slide_array.slides[i].node.tabIndex = -1;
} // endfor
// Set picture based on the index value
// CSS selectors based on the "aria-selected" attribute change the visual rendering
// Tabindex is set to 0 so the picture is part of the tab order
slide_array.slides[index].node.setAttribute("aria-selected","true");
slide_array.slides[index].node.tabIndex = 0;
// Check focus flag to see if keyboard focus should be moved to selected control
if( focus_flag == 1 ) {
slide_array.slides[index].node.focus();
// keep track of the last radio button with focus
slide_array.slide_focus = index;
} // end if
// Keep track of the last slide selected
slide_array.slide_selected = index;
// Once an option is selected the SlideArray is removed from tab order by setting its tabindex to -1
slide_array.node.tabIndex = -1;
} // endif
} // end slideArraySelect
/**
* slideshowSetDropEffect
*
* @param ( SlideShow Object )
* @param ( String ) drop_effect_value is a string to set the drop effect
* @param ( node ) node_grab is a reference to the grabbed node
*
* @return none
*/
function slideArraySetDropEffect( slide_array, dropeffect_value, node_grab ) {
for(var i = 0; i < slide_array.slides.length; i++ ) {
if( slide_array.slides[i].node.getAttribute("aria-dropeffect") != null &&
slide_array.slides[i].node.getAttribute("aria-dropeffect") != dropeffect_value) {
slide_array.slides[i].node.setAttribute("aria-dropeffect", dropeffect_value );
// var node = document.getElementById("test1");
// node.innerHTML = node.innerHTML + "<li>" + i + ": " + dropeffect_value + "</l>";
} // end if
} // end for
if( (slide_array.node_grab != null) &&
(slide_array.node_grab.node != null) &&
(slide_array.node_grab.node.getAttribute("aria-grabbed") != "false")
)
{
slide_array.node_grab.node.setAttribute("aria-grabbed", "false");
} // endif
slide_array.node_grab = node_grab;
} // end slideArraySetDropEffect
/**
* slideArrayCreateInsertSlide
*
* @param ( string ) slide_num
*
* @return node
*/
function slideArrayCreateInsertSlide( slide_num ) {
var node_li = document.createElement("li");
var node_span = document.createElement("span");
var node_text = document.createTextNode("Insert as slide " + slide_num);
node_span.appendChild( node_text );
node_span.className = "hidden"
node_span.id = "slide" + slide_num + "-label";
node_li.appendChild( node_span );
node_li.setAttribute("role", "option");
node_li.setAttribute("aria-labelledby", node_span.id );
node_li.setAttribute("aria-dropeffect", "none" );
node_li.id = "slide" + slide_num;
node_li.className = "insert";
node_li.tabIndex = "-1";
return node_li;
}
/**
* slideArrayGetSlideIndex
*
* @param ( SlideArray Obj) slide_array
* @param ( Node Obj) node_insert
*
* @return int
*/
function slideArrayGetSlideIndex( slide_array, node_insert ) {
for(var i = 0; i < slide_array.slides.length; i++ ) {
if( slide_array.slides[i].node.id == node_insert.id )
break;
} // endfor
if( i < slide_array.slides.length )
return i;
else
return 0;
} // slideArrayGetSlideIndex
/**
* slideArrayDropDragablePicture
*
* @param ( SlideShow Object )
*
* @return none
*/
function slideArrayInsertDragablePicture( slide_array, node_insert ) {
// Check to make sure there is a picture has been grabed
if( slide_array.node_grab != null ) {
// Check to see if it is an insert slide
if(node_insert.getAttribute("aria-dropeffect") == "copy") {
// Copy picture
var node_copy = slide_array.node_grab.node.cloneNode("true");
slide_array.slide_selected = slideArrayGetSlideIndex( slide_array, node_insert);
var slide_num = new Number(slide_array.slide_selected) + 2;
node_copy.id = "slide" + slide_num;
var str = "slide" + slide_num + "-label slide" + slide_num + "-caption";
node_copy.setAttribute("aria-labelledby", str);
node_copy.className = "slide";
node_copy.tabIndex = 0;
if( (node_attr = node_copy.getAttributeNode("aria-grabbed")) != null )
node_copy.removeAttributeNode( node_attr );
var node_span = node_copy.getElementsByTagName("span")[0];
node_span.id = "slide" + slide_num + "-caption";
// Create label for slide number
node_span = document.createElement("span");
node_span.id = "slide" + slide_num + "-label";
node_span.className = "hidden"
var node_text = document.createTextNode("Slide " + slide_num)
node_span.appendChild( node_text );
node_copy.appendChild( node_span );
// get new inset node to put after picture
slide_num = new Number(slide_num) + 1;
node_insert_new = slideArrayCreateInsertSlide( slide_num );
slide_num = new Number(slide_num) + 1;
var node_next_pic = nextSiblingElement(node_insert);
if( node_next_pic != null )
var node_next_insert = nextSiblingElement( node_next_pic );
node_parent = node_insert.parentNode;
while ( node_next_pic ) {
var node_temp = node_insert_new;
node_copy = node_parent.replaceChild( node_copy, node_next_pic );
node_insert_new = node_parent.replaceChild( node_insert_new, node_next_insert );
if( node_copy != null ) {
node_copy.id = "slide" + slide_num;
str = "slide" + slide_num + "label slide" + slide_num + "caption";
node_copy.setAttribute("aria-labelledby", str );
node_copy.getElementsByTagName("span")[0].id = "slide" + slide_num + "-caption";
node_copy.getElementsByTagName("span")[1].id = "slide" + slide_num + "-label";
node_copy.getElementsByTagName("span")[1].innerHTML = "Slide " + slide_num;
slide_num = new Number(slide_num) + 1;
if( node_insert_new != null) {
node_insert_new.id = "slide" + slide_num;
str = "slide" + slide_num + "-label";
node_insert_new.setAttribute("aria-labelledby", str );
node_insert_new.getElementsByTagName("span")[0].id = "slide" + slide_num + "-label";
node_insert_new.getElementsByTagName("span")[0].innerHTML = "Slide " + slide_num;
slide_num = new Number(slide_num) + 1;
} // endif
node_next_pic = nextSiblingElement( node_temp );
if( node_next_pic != null )
node_next_insert = nextSiblingElement( node_next_pic );
} else {
node_next_pic = null;
} // endif
} // end while
node_parent.appendChild( node_copy );
node_parent.appendChild( node_insert_new );
// Calculate new slides for slide array
slide_array.slides = new Array();
node_temp = firstChildElement( node_parent );
while( node_temp != null ) {
var new_slide = new Slide(node_temp.id);
new_slide.init();
slide_array.add( new_slide );
node_temp = nextSiblingElement( node_temp );
} // end while
// Remove drag effect information
slideArraySetDropEffect( slide_array, "none", null );
// set selected option
slideArraySelect( slide_array, (slide_array.slide_selected + 1), 1 );
} // endif
} // endif
} // end slideArraySetDropEffect
/**
*
* The DragablePicture object is used to maintain information about a dragabel picture widget
*
* @constructor
*/
function DragablePictureArray( id, obj ) {
this.id = id;
this.pictures = new Array();
this.slide_array = obj;
this.picture_selected = -1;
this.picture_drag = null;
} // end DragablePicture
/**
* init is a subclass of DragablePicturesArray and is used to initialize the event handlers and
* dragable picture objects.
*
* @member DragablePictureArray
*
* @return none
*/
DragablePictureArray.prototype.init = function() {
this.node = document.getElementById(this.id);
for( var i = 0; i < this.pictures.length; i++ ) {
var obj1 = this.slide_array;
this.pictures[i].init( obj1 );
} // endfor
var obj = this;
// Add event handlers for moving picture into the slide show
browser.addEvent(this.node, "keydown", function(event) {handleDragablePictureArrayKeyDownEvent(event, obj);}, false);
// Add event handlers for moving picture into the slide show
browser.addEvent(this.node, "focus", function(event) {handleDragablePictureArrayFocusEvent(event, obj);}, false);
}
/**
* add is a subclass of DragablePicturesArray and is used to provide a reference to all
* dragable picture objects.
*
* @member DragablePictureArray
*
* @return none
*/
DragablePictureArray.prototype.add = function( obj ) {
// add picture to array
this.pictures[this.pictures.length] = obj;
}
/**
*
* The DragablePicture object is used to maintain information about a dragabel picture widget
*
* @constructor
*/
function DragablePicture( id ) {
this.id = id;
} // end DragablePicture
/**
* init is a subclass of DragablePicture is used to initialize the event handlers and
* dragable picture.
*
* @member DragablePicture
*
* @return none
*/
DragablePicture.prototype.init = function( slide_array ) {
this.node = document.getElementById( this.id );
this.slide_array = slide_array;
var obj = this;
browser.addEvent(this.node, "mousedown", function(event) {handleDragablePictureMouseDownEvent(event, obj);}, false);
// Add event handlers for updating style for IE 7.0+
browser.addChangeEvent(this.node, function(event) {handleDragablePictureModifyEvent(event, obj); });
} // end DragablePicture.prototype.init
/**
* handleDragablePictureModifyEvent processes keys associated with a checkbox
*
* @param ( event ) event is the event handler for the event
* @param ( Checkbox object ) checkbox is the Checkbox object that is the target of the keyboard event
*
* @return false to stop event propagation if mouse event was used by checkbox, else true
*/
function handleDragablePictureModifyEvent(event, dragable_picture){
// If IE get the IE event object
var e = event || window.event;
// Check which attributes changed and if they are aria attribute kick IE to update styling
if( browser.testAttrName(e, "aria-selected") ||
browser.testAttrName(e, "aria-grabbed")
) {
// Kick IE to update styling
dragable_picture.node.className += "";
if( browser.testAttrName(e, "aria-grabbed" ) ) {
// var node = document.getElementById("test1");
// node.innerHTML = node.innerHTML + "<li>" + e.attrName + "</l>";
if( dragable_picture.node.getAttribute("aria-grabbed") == "true" )
slideArraySetDropEffect( dragable_picture.slide_array, "copy", dragable_picture );
else
slideArraySetDropEffect( dragable_picture.slide_array, "none", null );
} // endif
} // endif
return browser.stopPropagation(e);
} // end handleDragablePictureModifyEvent
/**
* handleDragablePictureArrayKeyDownEvent processes keys associated with a radio button group
*
* @param ( event ) event is the event handler for the event
* @param ( DragablePicture object ) dragable_picture is the DragablePicture object that is the target of the keyboard event
*
* @return false if keyboard event was used by DragablePicture, else true
*/
function handleDragablePictureArrayKeyDownEvent( event, dragable_picture_array ) {
// If IE get the IE event object
var e = event || window.event;
// If any modifier keys are pressed do not process this event
if( e.altKey || e.ctrlKey || e.shiftKey )
return true;
switch( e.keyCode ) {
case KEY_SPACE:
// Pressing space will pickup the current picture
dragablePictureArrayGrab( dragable_picture_array );
return browser.stopPropagation( e );
break;
case KEY_RIGHT:
case KEY_DOWN:
dragablePictureArraySelect( dragable_picture_array, (dragable_picture_array.picture_selected + 1), 1);
// Tell browser we handled this event and not to process any other actions
return browser.stopPropagation( e );
break;
case KEY_LEFT:
case KEY_UP:
dragablePictureArraySelect( dragable_picture_array, (dragable_picture_array.picture_selected - 1), 1);
// Tell browser we handled this event and not to process any other actions
return browser.stopPropagation( e );
break;
} // end switch
return true;
} // end handleDragablePictureKeyDownEvent
/**
* handleDragablePictureMouseDownEvent
*
* @param ( event ) event is the event handler for the event
* @param ( DragablePicture object ) dragable_picture
*
* @return false if keyboard event was used by DragablePicture, else true
*/
function handleDragablePictureMouseDownEvent( event, dragable_picture ) {
// If IE get the IE event object
var e = event || window.event;
dragable_picture.mouse_down = true;
dragable_picture.move_function = function( event ) { handleDragablePictureMouseMoveEvent(event, dragable_picture ); };
dragable_picture.up_function = function( event ) { handleDragablePictureMouseUpEvent(event, dragable_picture ); };
// get a copy of the picture
dragable_picture.node.appendChild( dragable_picture.node.getElementsByTagName("img")[0].cloneNode("false") );
dragable_picture.node_drag_image = dragable_picture.node.getElementsByTagName("img")[1];
dragable_picture.node_drag_image.style.position = "absolute";
dragable_picture.node_drag_image.style.top = Math.round( browser.pageY( e ) ) + "px";
dragable_picture.node_drag_image.style.left = Math.round( browser.pageX( e ) ) + "px";
dragable_picture.node.setAttribute("aria-grabbed","true");
browser.setMouseCapture( dragable_picture.node, null, null, dragable_picture.move_function, dragable_picture.up_function );
// Tell browser we handled this event and not to process any other actions
return browser.stopPropagation( e );
}
/**
* handleDragablePictureMouseMoveEvent
*
* @param ( event ) event is the event handler for the event
* @param ( DragablePicture object ) dragable_picture
*
* @return false if keyboard event was used by DragablePicture, else true
*/
function handleDragablePictureMouseMoveEvent( event, dragable_picture ) {
// If IE get the IE event object
var e = event || window.event;
if ( e.type == "mousemove" && dragable_picture.mouse_down) {
var pointer_page_y = Math.round( browser.pageY( e) );
var pointer_page_x = Math.round( browser.pageX( e) );
dragable_picture.node_drag_image.style.top = pointer_page_y + "px";
dragable_picture.node_drag_image.style.left = pointer_page_x + "px";
} // endif
// Tell browser we handled this event and not to process any other actions
return browser.stopPropagation( e );
}
/**
* handleDragablePictureMouseUpEvent
*
* @param ( event ) event is the event handler for the event
* @param ( DragablePicture object ) dragable_picture
*
* @return false if keyboard event was used by DragablePicture, else true
*/
function handleDragablePictureMouseUpEvent( event, dragable_picture ) {
// If IE get the IE event object
var e = event || window.event;
dragable_picture.mouse_down = false;
var node = dragable_picture.node.getElementsByTagName("img")[1];
if( node )
dragable_picture.node.removeChild(node);
if( (browser.target(e).getAttribute("aria-dropeffect") != null) &&
(browser.target(e).getAttribute("aria-dropeffect") != "none" )
) {
slideArrayInsertDragablePicture( dragable_picture.slide_array, browser.target(e) );
} // endif
browser.releaseMouseCapture( dragable_picture.node, null, null, dragable_picture.move_function, dragable_picture.up_function );
dragable_picture.node.setAttribute("aria-grabbed","false");
// Tell browser we handled this event and not to process any other actions
return browser.stopPropagation( e );
}
/**
* handleDragablePictureArrayFocusEvent is called by event handlers to initialize listbox
*
* @param ( dragable_picture object ) radio_group Radio Group to change selected radio button
*
* @return none
*/
function handleDragablePictureArrayFocusEvent( event, dragable_picture_array ) {
var e = event || window.event;
dragablePictureArraySelect( dragable_picture_array, 0 , 1 );
return browser.stopPropagation( e );
}
/**
* dragablePictureArrayGrab is called by event handlers to grab the selected picutre in the array
*
* @param ( dragable_picture object ) radio_group Radio Group to change selected radio button
* @param ( integer ) index Index of picture to be selected
* @param ( integer ) focus_flag If value is set to 1 then keyboard focus will be moved to the selected radio button
*
* @return none
*/
function dragablePictureArrayGrab( dragable_picture_array ) {
if( (dragable_picture_array.picture_selected >= 0 ) &&
(dragable_picture_array.picture_selected < dragable_picture_array.pictures.length )
) {
var node_picture = dragable_picture_array.pictures[dragable_picture_array.picture_selected].node;
node_picture.setAttribute("aria-grabbed","true");
} // endif
} // end dragablePictureArrayGrab
/**
* dragablePictureArraySelect is called by event handlers to select one of the pictures in the array
*
* @param ( dragable_picture object ) radio_group Radio Group to change selected radio button
* @param ( integer ) index Index of picture to be selected
* @param ( integer ) focus_flag If value is set to 1 then keyboard focus will be moved to the selected radio button
*
* @return none
*/
function dragablePictureArraySelect( dragable_picture_array, index, focus_flag ) {
// Check to see if index is larger than the number of picutre, if so wrap to first picutre
if( index >= dragable_picture_array.pictures.length )
index = 0;
// Check to see if index is less than zero, if so wrap to last radio button
if( index < 0)
index = dragable_picture_array.pictures.length - 1;
// Check to make sure the index value is valid before changing states
if( (index >= 0 ) && (index < dragable_picture_array.pictures.length) ) {
// Set all pictures to not grabbed and not focused
// Tabindex is set to -1 so the control can still receive focus, but is removed from tab order
for(var i = 0; i < dragable_picture_array.pictures.length; i++ ) {
dragable_picture_array.pictures[i].node.setAttribute("aria-grabbed","false");
dragable_picture_array.pictures[i].node.setAttribute("aria-selected","false");
// Make sure item is not the deafult tab stop
dragable_picture_array.pictures[i].node.tabIndex = -1;
} // endfor
// Set picture based on the index value
// CSS selectors based on the "aria-selected" attribute change the visual rendering
// Tabindex is set to 0 so the picture is part of the tab order
dragable_picture_array.pictures[index].node.setAttribute("aria-selected","true");
dragable_picture_array.pictures[index].node.tabIndex = 0;
// Check focus flag to see if keyboard focus should be moved to selected control
if( focus_flag == 1 ) {
dragable_picture_array.pictures[index].node.focus();
// keep track of the last radio button with focus
dragable_picture_array.pictures.picture_focus = index;
} // end if
// Keep track of the last radio button selected
// Once a Radio button is selected the RadioGroup is removed from tab order by setting its tabindex to -1
dragable_picture_array.picture_selected = index;
dragable_picture_array.node.tabIndex = -1;
// Reset the dropable items in the SlideArray
} // endif
} // end dragablePictureArraySelect
</script>
CSS Source Code
Show CSS Source Code: draganddrop2.css
<style type="text/css">
/* CSS Document */
.hidden {
visibility: hidden;
position: absolute;
}
ul.pictures li,
il.copy {
display: inline;
list-style: none;
}
ul.pictures li:focus img,
ul.pictures li:active img,
ul.pictures li:hover img {
border: black 3px solid;
}
ul.pictures li img {
margin: 0;
padding: 1px;
border: white 3px solid;
}
ul.pictures li[aria-grabbed="true"] img,
li.copy {
margin: 0;
padding: 1px;
border: green 3px solid;
}
ul.slides {
width: 90%;
height: 100px;
border: 2px solid black;
padding: 0px;
margin: 0;
padding: 0;
padding-left: 2px;
}
ul.slides li.slide {
list-style: none;
list-style-position:inside;
float: left;
margin: 0;
padding: 0;
}
ul.slides li.slide img {
margin: 0;
margin-top: 6px;
border: white 2px solid;
padding: 1px;
}
ul.slides li.insert {
list-style: none;
margin: 2px 0px 2px 0px;
float: left;
height: 91px;
width: 2px;
border: white 2px solid;
padding: 1px;
background-color: #666666;
}
ul.slides li[aria-dropeffect="copy"]{
background-color: green;
}
ul.slides li[aria-dropeffect="copy"]:hover {
border: black 2px solid;
}
ul.slides li.insert:focus,
ul.slides li.insert:active,
ul.slidesli.insert:hover {
border: green 2px solid;
background-color: #CCCCCC;
}
ul.slides li[aria-dropeffect="none"]:focus,
ul.slides li[aria-dropeffect="none"]:active {
border: black 2px solid;
background-color: #CCCCCC;
}
ul.slides li.slide:focus img,
ul.slides li.slide:active img {
border: black 2px solid;
}
p.caption {
clear: both;
}
</style>
Validate DOM (HTML5)