/*
Copyright (c) 2009, www.redips.net  All rights reserved.
Code licensed under the BSD License: http://www.redips.net/license/

http://www.redips.net/javascript/drag-and-drop-table-content/
version 1.4.2
Sep 01, 2009.



Modified by TableFare to strip out everything except the window scrolling functionality


*/


// parameters that can be changed
var hover_color = '#E7AB83';	// hover color
var bound       = 25;					// bound width for autoscroll
var speed       = 100;					// scroll speed in milliseconds
var forbid      = 'forbid';		// cell class name where draggable element can not be dropped
var trash       = 'trash';		// cell class name where draggable element will be destroyed
var trash_ask   = true;				// confirm object deletion (ask a question "Are you sure?" before delete)
var drop_option = 'multiple';	// drop_option has three options: multiple, single and switch

// other parameters
var obj = false;                        // draggable object
var obj_margin;            						  // space from clicked point to the object bounds (top, right, bottom, left)
var mouseButton = 0;										// if mouseButton == 1 then first mouse button is pressed
var mouseX, mouseY;    			            // mouse coordinates (used in onmousedown, onmousemove and autoscroll)
var window_width= 0, window_height=0;   // window width and height (parameters are set in onload and onresize event handler)
var scroll_width, scroll_height;        // scroll width and height of the window (it is usually greater then window)
var edgeX=0, edgeY=0;                   // autoscroll bound values (closer to the page edge, faster scroll) calculated in onmousemove handler
var bgcolor_old; 										    // old cell background color
var tables;                             // table offsets and row offsets (initialized in onload event)
var autoscrollX_flag=autoscrollY_flag=0;// needed to prevent multiple calls of autoscrollX and autoscrollY from onmousemove event handler
var moved_flag = 0;

// selected, previous and started table, row and cell
var table = table_old = table_source = null;
var row   = row_old   = row_source   = null;
var cell  = cell_old  = cell_source  = null;



//
// event handlers
//


// onLoad event
window.onload = function (){
	// set initial window width/height, scroll width/height and define onresize event handler
	// onresize event handler calls calculate columns
	var divs = document.getElementById('lm_left').getElementsByTagName('div');

	// attach onmousedown event handler only to DIV elements that have "drag" in class name
	// allow other div elements inside <div id="drag" ...
	for (var i=0; i<divs.length; i++) 
		if (divs[i].className.indexOf('spicelist') > -1) 
			divs[i].onmousedown = handler_onmousedown;
	// dissable text selection for IE (but not for the form elements)
//	document.onselectstart = function(e) {var evt = e || window.event; if (!isFormElement(evt)) return false}

	handler_onresize();
	window.onresize = handler_onresize;
}



// onresize window event handler
// this event handler sets window_width and window_height variables used in onmousemove handler
function handler_onresize(){
	// Non-IE
  if (typeof(window.innerWidth) == 'number'){
    window_width  = window.innerWidth;
    window_height = window.innerHeight;
  }
  // IE 6+ in 'standards compliant mode'
  else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)){
    window_width  = document.documentElement.clientWidth;
    window_height = document.documentElement.clientHeight;
  }
  // IE 4 compatible
  else if (document.body && (document.body.clientWidth || document.body.clientHeight)){
    window_width  = document.body.clientWidth;
    window_height = document.body.clientHeight;
  }
  // set scroll size (onresize, onload and onmouseup event)
	scroll_width  = document.documentElement.scrollWidth;
	scroll_height = document.documentElement.scrollHeight;
	// calculate colums and rows offset (cells dimensions)
}



// onmousedown handler
function handler_onmousedown(e){
	// define event (cross browser)
	var evt = e || window.event;
	// enable control for form elements
	// enable control for form elements
	if (isFormElement(evt)) return true;

	// set a reference to the moved object and z-index (if object is not of "clone" type)
	obj = this;

	// set clicked position
	mouseX = evt.clientX;
	mouseY = evt.clientY;
	// define pressed mouse button
	if (evt.which) mouseButton = evt.which;
	else           mouseButton = evt.button;
	// activate onmousemove and onmouseup event handlers on document level
	// if left mouse button is pressed
	if (mouseButton == 1){
		moved_flag = 0; // set moved_flag (if need to clone object in handler_onmousemove)
		document.onmousemove = handler_onmousemove;
		document.onmouseup   = handler_onmouseup;

	}
	// define object offset
	var offset = box_offset(obj);

	// calculate ofsset from the clicked point inside element to the
	// top, right, bottom and left side of the element
//	obj_margin = [mouseY-offset[0], offset[1]-mouseX, offset[2]-mouseY, mouseX-offset[3]];
	obj_margin = [3,3,3,3];

	// disable text selection
	return false;
}



// onmouseup handler
function handler_onmouseup(e){
	// reset mouseButton variable
	mouseButton = 0;
	// reset left and top styles
	obj.style.left = 0;
	obj.style.top  = 0;
	// return z-index
	obj.style.zIndex = 10;
	// detach onmousemove and onmouseup events
	document.onmousemove = null;
	document.onmouseup   = null;
	// document.body.scroll... only works in compatibility (aka quirks) mode,
	// for standard mode, use: document.documentElement.scroll...
	scroll_width  = document.documentElement.scrollWidth;
	scroll_height = document.documentElement.scrollHeight;	
	// reset autoscroll flags
	autoscrollX_flag = autoscrollY_flag = 0;
	// reset old positions
}



// onmousemove handler for the document level
// activated after left mouse button is pressed on draggable element
function handler_onmousemove(e){
	// define event (FF & IE)
	var evt = e || window.event;
	if (moved_flag == 0){
//		myhandler_moved();
	}
	// set moved_flag
	moved_flag = 1;
	// set left and top styles for the moved element if element is inside window
	// this conditions will stop element on window bounds
	if (evt.clientX > obj_margin[3] && evt.clientX < window_width - obj_margin[1])  obj.style.left = (evt.clientX - mouseX) + "px";
	if (evt.clientY > obj_margin[0] && evt.clientY < window_height - obj_margin[2])	obj.style.top  = (evt.clientY - mouseY) + "px";



	// test if is still first mouse button pressed (in case when user release mouse button out of a window)
	if (evt.which) mouseButton = evt.which;
	else           mouseButton = evt.button;
	// if first mouse button is released
	if (mouseButton != 1){handler_onmouseup(evt);	return;}	
	// calculate horizontally crossed page bound
	edgeX = bound - (window_width/2  > evt.clientX ? evt.clientX-obj_margin[3] : window_width - evt.clientX - obj_margin[1]);
	// if element crosses page bound then set scroll direction and call auto scroll 
	if (edgeX > 0){
		// in case when object is only half visible (page is scrolled on that object)
		if (edgeX > bound) edgeX = bound;
		// set scroll direction: negative - left, positive - right
		edgeX *= evt.clientX < window_width/2 ? -1 : 1; 
		// remove onscroll event handler and call autoscrollY function only once
		if (autoscrollX_flag++ == 0) {window.onscroll = null; autoscrollX()}
	}
	else edgeX = 0;
	// calculate vertically crossed page bound
	edgeY = bound - (window_height/2 > evt.clientY ? evt.clientY-obj_margin[0] : window_height - evt.clientY - obj_margin[2]);
	// if element crosses page bound then set scroll direction and call auto scroll
	if (edgeY > 0){
		// in case when object is only half visible (page is scrolled on that object)
		if (edgeY > bound) edgeY = bound;
		// set scroll direction: negative - up, positive - down
		edgeY *= evt.clientY < window_height/2 ? -1 : 1;
		// remove onscroll event handler and call autoscrollY function only once
		if (autoscrollY_flag++ == 0) {window.onscroll = null; autoscrollY()}
	}
	else edgeY = 0;
}



//
// auto scroll functions
//



// horizontal auto scroll function
function autoscrollX(call){
	// define old scroll position and current scroll position
	var old = 0; 
	var scrollPosition = getScrollPosition('X');
	// mouse button should be pressed and
	// if moved element is over left or right margin
	// scroll_width - window_width returns maximum horizontal scroll position
	if (mouseButton == 1 && ((edgeX < 0 && scrollPosition > 0) || (edgeX > 0 && scrollPosition < (scroll_width - window_width)))){
		// horizontal window scroll 
		window.scrollBy(edgeX, 0);
		// set previous scroll position and new after window is scrolled
		old = scrollPosition;
		scrollPosition = getScrollPosition('X');
		// set style left for the moved element
		obj.style.left = (parseInt(obj.style.left) + scrollPosition - old) + "px";
		// move X point
		mouseX -= scrollPosition - old; 
		// recursive autoscroll call 
		setTimeout("autoscrollX('recursive')", speed);
	}
	// autoscroll stopped by moving element out of the page edge
	// or element faced maximum position (left or right)
	else{
		// recalculate cell positions if call was function itself (spare CPU if moving object across bound)
		// return onscroll event handler and reset auto scroll flag
		autoscrollX_flag = 0;
	}
}



// vertical auto scroll function
function autoscrollY(call){
	var top;     // top style
	var old = 0; // define old scroll position
	// define current scroll position
	var scrollPosition = getScrollPosition('Y');
	// mouse button should be pressed and 
	// if moved element is over page top or page bottom
	// scroll_height - window_height returns maximum vertical scroll position
	if (mouseButton == 1 && ((edgeY < 0 && scrollPosition > 0) || (edgeY > 0 && scrollPosition < (scroll_height - window_height)))){
		// vertical window scroll 
		window.scrollBy(0, edgeY);
		// set previous scroll position and new after window is scrolled
		old = scrollPosition;
		scrollPosition = getScrollPosition('Y');
		// set top style of the object
		top = (isNaN(parseInt(obj.style.top)) ? 0 : parseInt(obj.style.top));
		// set style top for the moved element
		obj.style.top = (top + scrollPosition - old) + "px";
		// move Y point
		mouseY -= scrollPosition - old; 
		// recursive autoscroll call 
		setTimeout("autoscrollY('recursive')", speed);
	}
	// autoscroll stopped by moving element out of the page edge
	// or element faced maximum position (top or bottom)
	else{
		// recalculate cell positions if call was function itself (spare CPU if moving object across bound)

		// return onscroll event handler and reset auto scroll flag
		autoscrollY_flag = 0;
	}
}



// function returns scroll position for X or Y scrollbar
// input parameter is dimension (X or Y)
function getScrollPosition(d){
	var scrollX, scrollY; // define scroll position variables
	// Netscape compliant
  if (typeof(window.pageYOffset) == 'number'){
    scrollX = window.pageXOffset;
    scrollY = window.pageYOffset;
  }
  // DOM compliant
  else if (document.body && (document.body.scrollLeft || document.body.scrollTop)){
    scrollX = document.body.scrollLeft;
    scrollY = document.body.scrollTop;
  }
  // IE6 standards compliant mode
  else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)){
    scrollX = document.documentElement.scrollLeft;
    scrollY = document.documentElement.scrollTop;
  }
  // needed for IE6 (when vertical scroll bar was on the top)
  else scrollX = scrollY = 0;
  // return scroll position
  if (d == 'X') return scrollX;
  else          return scrollY
}



 // calculate object (box) offset (top, right, bottom, left)
// function returns array of box bounds
// used in calculate_cells and onmousedown event handler
function box_offset(box){
	var oLeft = 0 - getScrollPosition('X'); // define offset left (take care of scroll position)
	var oTop  = 0 - getScrollPosition('Y'); // define offset top (take care od scroll position)
	// remember box object
	var box_old = box;
	// loop to the root element and return box offset (top, right, bottom, left)
	do {oLeft += box.offsetLeft; oTop += box.offsetTop} while (box = box.offsetParent);
	// return box offset array
	//       top               right,                     bottom             left
	return [ oTop, oLeft + box_old.offsetWidth, oTop + box_old.offsetHeight, oLeft ];
}


// function returns true or false if source tag name is form element
function isFormElement(evt){
	// declare form element and source tag name
	var formElement;
	var srcName;
	// set source tag name for IE and FF
	if (evt.srcElement)	srcName = evt.srcElement.tagName;
	else                srcName = evt.target.tagName;
	// set flag (true or false) for form elements
	switch(srcName){
		case 'INPUT':
		case 'SELECT':
		case 'OPTION':
			formElement = true;
			break;
		default:
			formElement = false;
	}
	// return formElement flag
 	return formElement;
}

