﻿// drag.js - Drag-and-drop functionality, with code to handle Apple mobile devices
//
// To make any clickable element draggable, set its CSS position property to "relative" and add
// the following to your Javascript:
//
//		DragHandler.attach(itemid, [dragbegin], [drag], [dragend]);
//
//  For example:
//
//		<head>
//		<script type="text/javascript" src="drag.js"></script>
//		</head>
//		<body>
//		<form name="frm" action="" method="post">
//			<button id="dragme" type="button" style="position:relative;">Drag me</button>
//		</form>
//		<script type="text/javascript">
//			window.onload = DragHandler.attach(document.frm.dragme, null, null, null);
//		</script>
//		</body>
//
// You can attach to as many objects as you'd like to make draggable.
//
// Arguments 2-4 can be used to specify callback functions to add special processing
// (such as "snapping" or color/z-level changes) for drag-begin, drag, and drag-end, respectively.
// These functions are passed the item and the current relative x,y position.
//
// - Duff Kurland
//   June 1, 2010
//   based on code from http://www.webtoolkit.info/javascript-drag-and-drop.html

var DragHandler = {
 
	// private property.
	_oElem : null,
 
	// public method. Attach drag handler to an element.
	attach : function(oElem, pubBeg, pubDrag, pubEnd) {
		oElem.onmousedown = DragHandler._dragBegin;
		oElem.ontouchstart = DragHandler._dragBegin;

		// callbacks
		oElem.dragBegin = pubBeg  ? pubBeg  : new Function();
		oElem.drag      = pubDrag ? pubDrag : new Function();
		oElem.dragEnd   = pubEnd  ? pubEnd  : new Function();
		return oElem;
	},
 
	// private method. Begin drag process.
	_dragBegin : function(e) {
		var oElem = DragHandler._oElem = this;
 
		if (isNaN(parseInt(oElem.style.left))) { oElem.style.left = '0px'; }
		if (isNaN(parseInt(oElem.style.top)))  { oElem.style.top  = '0px'; }
 
		e = e || window.event;					// Cope with IE and non-IE browsers

		if (e.type == 'touchstart') {
			var touches = e.changedTouches;	
			e = touches[0];						// Use iPad "touch" event for position info
		}		
		oElem.mouseX = e.clientX;				// Record starting mouse position
		oElem.mouseY = e.clientY;
 
		var x = parseInt(oElem.style.left);
		var y = parseInt(oElem.style.top);
		oElem.dragBegin(oElem, x, y);				// Invoke callback, if any
 
		document.onmousemove = DragHandler._drag;	// Intercept mouse move/up while dragging
		document.onmouseup   = DragHandler._dragEnd;

		document.ontouchmove = DragHandler._drag;	// Intercept touchmove/end as well
		document.ontouchend  = DragHandler._dragEnd;
		document.ontouchcancel  = DragHandler._dragEnd;

		return false;
	},

	// private method. Drag (move) element.
	_drag : function(e) {
		var oElem = DragHandler._oElem;
 
		var x = parseInt(oElem.style.left);
		var y = parseInt(oElem.style.top);
 
		e = e || window.event;					// Cope with IE and non-IE browsers

		if (e.type == 'touchmove') {
			var touches = e.changedTouches;
			e = touches[0];						// Use iPad "touch" event for position info
		}		
		oElem.style.left = x + (e.clientX - oElem.mouseX) + 'px';
		oElem.style.top = y + (e.clientY - oElem.mouseY) + 'px';
		oElem.mouseX = e.clientX;				// Record new mouse position
		oElem.mouseY = e.clientY;
 
		oElem.drag(oElem, x, y);				// Invoke callback, if any

		return false;
	},
 
	// private method. Stop drag process.
	_dragEnd : function(e /*debug*/) {
		var oElem = DragHandler._oElem;
 
		var x = parseInt(oElem.style.left);
		var y = parseInt(oElem.style.top);
 
		oElem.dragEnd(oElem, x, y);				// Invoke callback, if any
 
		document.onmousemove = null;			// Clear mouse event handlers
		document.onmouseup   = null;

		document.ontouchmove     = null;		// Clear "touch" event handlers
		document.ontouchend      = null;
		document.ontouchcancel   = null;

		DragHandler._oElem   = null;			// Nothing being dragged
		return false;
	}
}

// End of drag.js
