/*
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.6.0
Oct 12, 2009.
*/


// parameters that can be changed
var hover_color   = '#e7ab83';  // hover color #E7AB83
var bound         = 25;					// bound width for autoscroll
var speed         = 20;					// 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
var delete_cloned = true;       // delete cloned div if the cloned div is dragged outside of any table
var mark_cname = 'mark';		// (string) class name for marked cells (default is 'mark')
var	marked_cell = 'deny';	// (string) allow or deny access to the marked cell (values are 'allow' or 'deny' - default is 'deny')
var marked_exception = [];		// (array) DIVid -> classname, defined DIV elements that can be placed to the certain marked table cell

// 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;                       // if object is moved, flag gets value 1  
var cloned_flag=0;                      // if object is cloned, flag gets value 1
var cloned_id=0													// needed for increment ID of cloned elements

// 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;
var XmlHttp;

function CreateXmlHttp()
{
    try
    {
        XmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch(e)
    {
        try
        {
	        XmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        } 
        catch(oc)
        {
	        XmlHttp = null;
        }
    }
    if(!XmlHttp && typeof XMLHttpRequest != "undefined") 
    {
        XmlHttp = new XMLHttpRequest();
    }
}
       
// onLoad event
window.onload = function (){
   
   SetMonth('E');
    
if(document.getElementById('drag'))
{
    
    
	// collect tables inside div with id=drag
	tables = document.getElementById('drag').getElementsByTagName('table');
	// set initial window width/height, scroll width/height and define onresize event handler
	// onresize event handler calls calculate columns
	handler_onresize();
	window.onresize = handler_onresize;
	// collect div elements inside tables (draggable elements)
	var divs = document.getElementById('drag').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('drag') > -1) 
			divs[i].onmousedown = handler_onmousedown;
	// collect images inside div=drag to prevent default action of onmousemove event (needed for IE to enable dragging on image)
	var imgs = document.getElementById('drag').getElementsByTagName('img');
	// set onmousemove event for images
	for (var i=0; i<imgs.length; i++) imgs[i].onmousemove = function(){return false};
	// 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}
	// attach onscroll event (needed for recalculating table cells positions)
	window.onscroll = calculate_cells;
}
}



// 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)
	calculate_cells();  
}

// onmousedown handler
function handler_onmousedown(e){
 
	// define event (cross browser)
	var evt = e || window.event;
	// enable control for form elements
	if (isFormElement(evt)) return true;
	// set reference to the clicked object
	//*** if you want earlier js then comment this condition
	 if(document.getElementById('tdCaptcha_div').className=="forbid")
	 {
	     //document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.backgroundColor =hover_color;
	      
	      document.getElementById('tdrightCaptcha').className ="imgchange";
	      var destination_cell;
	      //destination_cell = tables[table].rows[row].cells[cell];
//	     
//	      if(destination_cell==null)
//	      {
//	        try
//	        {
//	          
//	          destination_cell.insertBefore(obj,null); 
//	        }
//	        catch(ex)
//	        {
//	        
//	        }
//	      }
	     function handleError(){return true;}window.onerror = handleError;
          destination_cell.insertBefore(obj,null); 
	     obj.className="forbid";
	     
	     //obj=destination_cell;
	 }
	obj = this;
	
	// set high z-index if object isn't "clone" type - clone object is motionless
	if (obj.className.indexOf('clone') == -1) obj.style.zIndex = 999;
	// set clicked position
	mouseX = evt.clientX;
	mouseY = evt.clientY;
	// set current table, row and cell
	set_tcr(evt);
	//alert(cell);
	// remember start position (table, row and cell)
	table_source = table;
	row_source   = row;
	cell_source  = cell;
	// 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; // reset moved_flag (needed for clone object in handler_onmousemove)
		cloned_flag = 0; // reset cloned_flag
		document.onmousemove = handler_onmousemove;
		document.onmouseup   = handler_onmouseup;
		myhandler_clicked(); // call myhandler
	}
	// remember background cell color
	//bgcolor_old = tables[table].rows[row].cells[cell].style.backgroundColor;
	// 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]];
	// disable text selection
	return false;
}



// onmouseup handler
function handler_onmouseup(e){

	// define destination and source table cell
	var destination_cell, source_cell;
	// define destination elements and destination elements length needed for switching table cells
	// destination_elements_length is needed because nodeList objects in the DOM are live 
	// please see http://www.redips.net/javascript/nodelist-objects-are-live/
	var destination_elements, destination_elements_length;
	// reset mouseButton variable
	mouseButton = 0;
	// reset left and top styles
	//*** if you want earlier js then uncomment this ** lines
	//obj.style.left = 0;
	//obj.style.top  = 0;
	// return z-index
	//obj.style.zIndex = 10;
	// if object was dropped inside table then define a new location for destination cell
	if (table < tables.length)	
	{
	 destination_cell = tables[table].rows[row].cells[cell];
//	 if(cell_source==1)
//	 {
//	      destination_cell = tables[table].rows[row].cells[cell];
//	      destination_cell.insertBefore(obj,null);
//		  obj.className ="forbid";
//		 document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.backgroundColor =hover_color;
//		  return;
//	 }
//	 else
//	    destination_cell = tables[table_source].rows[row_source].cells[cell_source];
	}
	else // or use the last possible location (object was dropped outside table)
	{
	   
	    obj.style.left = 0;
	    obj.style.top  = 0;
	    obj.style.zIndex = 10;
//	   document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.opacity=="0.3"
//	    document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.filter="alpha(opacity=40)";
	   //document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.backgroundColor =hover_color;
	    destination_cell = tables[table_old].rows[row_old].cells[cell_old];
	 }
		
	// return background color for destination color (cell had hover color)
	if(destination_cell!=undefined)
	{
	//changes for hover color
	//destination_cell.style.backgroundColor = bgcolor_old;
	// 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
	table_old = row_old = cell_old = null;
	// element was not moved - button was clicked and released
	// call myhandler_notmoved handler and place clicked element to the bottom of TD (if table cell contains more than one element)
	if (moved_flag == 0){
 if( document.getElementById('tdrightCaptcha').className == "imgchange")
		  {
	        destination_cell.insertBefore(obj,null);
		    obj.className ="forbid";
		  }
		obj.style.left = 0;
	    obj.style.top  = 0;
	    obj.style.zIndex = 10;
		myhandler_notmoved();
		
		//destination_cell.appendChild(obj);
	}
	// remove cloned object if dropped to the start position
	else if(cloned_flag == 1 && table_source == table && row_source == row && cell_source == cell){
		obj.parentNode.removeChild(obj);
		myhandler_notcloned();
	}
	// remove cloned div if the cloned div is dragged to a point outside of any table and delete_cloned flag is true
	else if(cloned_flag == 1 && delete_cloned == true && table >= tables.length){
		obj.parentNode.removeChild(obj);
		myhandler_notcloned();
	}
	// remove object if destination cell has "trash" in class name
	else if (destination_cell.className.indexOf(trash) > -1){
		// remove child from DOM (node still exists in memory)
		obj.parentNode.removeChild(obj);
		// if parameter trash_ask is "true", confirm deletion (function trash_delete is at bottom of this script)
		if (trash_ask) setTimeout(trash_delete, 10);
		// else call myhandler_deleted handler (reference to the obj still exists)
		else myhandler_deleted();
	}
	// if ordinary element was clicked and left button was released, but element is placed inside unmovable table cell
		else if (table === null || row === null || cell === null) {
			myhandler_notmoved();
		}	
	// switch source and destination content
	else if (drop_option == 'multiple'){
	    //if dropping to blank div
	   // if(destination_cell.innerHTML=='')return;
	    if (destination_cell.parentNode.className.indexOf('forbid') > -1) 
	    {  
	       document.getElementById('tdrightCaptcha').style.backgroundColor ="";
	      
	       document.getElementById('tdrightCaptcha').className ="imgbg"
		    document.getElementById('hdnDesId').value="";
	       return;
	    }
	    
		//source_cell = tables[table_source].rows[row_source].cells[cell_source];
		
		
		// remove dragged element from DOM (source cell) - node still exists in memory
	//	obj.parentNode.removeChild(obj);
		// move object from the destination to the source cell
		destination_elements        = destination_cell.getElementsByTagName('DIV');
		destination_elements_length = destination_elements.length
		for (var i=0; i< destination_elements_length; i++){
			//source_cell.appendChild(destination_elements[0]); // '0', not 'i' because NodeList objects in the DOM are live
		//source_cell.appendChild();

		if (destination_elements[i].className.indexOf('forbid') > -1)
		{ 
		   
		   //document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').className="forbid";
		   //*** if you want earlier js then comment thisif else condition there should be no bg color
		    if( document.getElementById('tdrightCaptcha').className == "imgchange")
		      {
		          document.getElementById('tdrightCaptcha').className ="imgchange";
		         document.getElementById('tdCaptcha_div').style.display="none";  
		         document.getElementById('tdCaptcha_div').className="forbid";
    		    
		      }
		
		  else  if(document.getElementById('tdrightCaptcha').className == "imgbg")
		  {
		  	obj.style.left = 0;
	        obj.style.top  = 0;
	        obj.style.zIndex = 10;
	         document.getElementById('tdrightCaptcha').className ="imgbg"
		  }
		  
		  else
		  {
		    //document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.backgroundColor ="";
		  }
          //document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.backgroundColor ="";
		   return;
		 }
		
		}
		// and finaly, append dragged object to the destination table cell
      //document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha');
		 if(( document.getElementById('tdrightCaptcha').className =="imgchange"))
		      {
		      		        //document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.backgroundColor =hover_color;
		         document.getElementById('tdCaptcha_div').className ="imgchange";
		         document.getElementById('hdnDesId').value="1";
		         document.getElementById('tdCaptcha_div').style.display="none";  
		         document.getElementById('tdCaptcha_div').className="forbid";
	             var right = (obj.getBoundingClientRect()).right;
	             var left = (obj.getBoundingClientRect()).left;
//		         
//		        var tdright=(document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').getBoundingClientRect()).right;
//		        
//		         var tdleft=(document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').getBoundingClientRect()).left;
//		  
                 
    		      //obj.className ="forbid";
    		      

		      }
		      else
		      {
                	destination_cell.insertBefore(obj,null);
		            obj.className ="forbid";
		      }
		      return;
		
		destination_cell.insertBefore(obj,null);
		obj.className ="forbid";
		//destination_cell.remove();
		// myhandler_dropped();
		
//		 document.getElementById('ctl00_cphContent_ctrlblog_hdnDesId').value="1";
//		 document.getElementById('tdCaptcha_div').style.display="none"; 
          document.getElementById('tdrightCaptcha').className ="imgchange";
//		  document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.backgroundColor =hover_color;
//		   document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.bgColor =hover_color;
		   document.getElementById('tdCaptcha_div').style.border=" ";
		 //destination_cell.style.backgroundColor = hover_color;
		
		if (destination_elements_length) 
		{
		//alert('coni');
		//myhandler_moved();
		}
		else
		{
		// alert('conf');
         //destination_cell.appendChild(obj);
		
		 
		 }
		
		
	}
	// else call myhandler and append object to the cell
	else{
		myhandler_dropped();
		//destination_cell.appendChild(obj);
	}
	// force naughty browsers (IE6, IE7 ...) to redraw source and destination row (element.className = element.className does the trick)
	tables[table_source].rows[row_source].className = tables[table_source].rows[row_source].className;
	//destination_cell.parentNode.className = destination_cell.parentNode.className;
	// recalculate table cells and scrollers because cell content could change row dimensions 
	calculate_cells();
}
}














// 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 isn't set and object has clone in class name, then duplicate object, set cloned flag and call myhandler_cloned
	if (moved_flag == 0 && obj.className.indexOf('clone') > -1){
		clone_obj();
		cloned_flag = 1;
		myhandler_cloned();
	}
	// object is only moved, call myhandler_moved
	else 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";
	// set current table, row and cell
	set_tcr(evt);
	// if new location is inside table and new location is different then old location
	// set background colors for the previous and new table cell
	if (table < tables.length && (table != table_old || cell != cell_old || row != row_old))
	{
		// set cell background color to the previous cell
		if (table_old != null && row_old != null && cell_old != null)
			//tables[table_old].rows[row_old].cells[cell_old].style.backgroundColor = bgcolor_old;
			
		// remember background color before setting the new background color
		
		//bgcolor_old = tables[table].rows[row].cells[cell].style.backgroundColor;
		
		// set background color to the current table cell
//       alert(tables[table].rows[row].cells[cell].offsetLeft);
//		 if(tables[table].rows[row].cells[cell].offsetLeft > 256 && tables[table].rows[row].cells[cell].offsetLeft < 257 )
//	    {
//	        tables[table].rows[row].cells[cell].style.backgroundColor = hover_color;
//		    tables[table].rows[row].cells[cell].style.bgColor = hover_color;
//		  
//		}
//		else
//		{
//		tables[table].rows[row].cells[cell].style.backgroundColor = "";
//		  tables[table].rows[row].cells[cell].style.bgColor = "";
//		
//		}
		
		// remember current position (for table, row and cell)
		//table_old=table; row_old=row; cell_old=cell;
		if( document.getElementById('tdrightCaptcha').style.backgroundColor =="")
		{
		         
		           document.getElementById('tdrightCaptcha').className ="imgchange";
//            document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.opacity="0.3"; 
	           //document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.border="solid 2px black";
//	            document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.filter="alpha(opacity=40)";
//		    document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.backgroundColor = hover_color;
//		    document.getElementById('ctl00_cphContent_ctrlblog_tdrightCaptcha').style.bgColor = hover_color;
		 }   
		 table_old=table; row_old=row; cell_old=0;
		
	}
	else
	{
	       document.getElementById('tdrightCaptcha').style.backgroundColor ="";
		   document.getElementById('tdrightCaptcha').style.bgColor ="";
		    document.getElementById('tdrightCaptcha').className ="imgbg";
	}
	

	
	// 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;
	// stop all propagation of the event in the bubbling phase.
	// (save system resources by turning off bubbling)
	evt.cancelBubble = true;
	if (evt.stopPropagation) evt.stopPropagation();
}



//
// 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)
		if (call == 'recursive') calculate_cells();
		// return onscroll event handler and reset auto scroll flag
		window.onscroll  = calculate_cells;
		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)
		if (call == 'recursive') calculate_cells();
		// return onscroll event handler and reset auto scroll flag
		window.onscroll  = calculate_cells;
		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
}



//
// other functions
//



// calculate table colums and row offsets (cells dimensions) 
function calculate_cells(){
	// local variables used in for loops
	var i, j;
	// open loop for each HTML table inside id=drag (tables variable is initialized in onload event)
	for (i=0; i<tables.length; i++){
		// define row offsets variable
		var row_offset = new Array();
		// collect table rows and initialize row offsets array
		var tr = tables[i].getElementsByTagName('tr');
		// backward loop has better perfomance
		for (j=tr.length-1; j>=0; j--) row_offset[j] = box_offset(tr[j]);
		// save table informations (table offset and row offsets)
		tables[i].offset     = box_offset(tables[i]);
		tables[i].row_offset = row_offset;
	}
}



// function sets current table, row and cell
// please note that variables used in this function (table, cell and row)
// are defined at the beginning of the script (global scope) 
function set_tcr(evt){
	// define variables for left & right cell offset
	var offsetLeft, offsetRight;
	// define current cell (needed for some test at the function bottom)
	var cell_current;
	// find table below draggable object
	for (table=0; table < tables.length; table++){
		// mouse pointer is inside table
		if (tables[table].offset[3] < evt.clientX  &&  evt.clientX < tables[table].offset[1] &&	
				tables[table].offset[0] < evt.clientY  &&  evt.clientY < tables[table].offset[2]){
					// row offsets for the selected table (row bounds)
					var row_offset = tables[table].row_offset;
					// find the current row (loop will stop at the current row; row_offset[row][0] is row top offset)
					for (row=0; row<row_offset.length-1 && row_offset[row][0] < evt.clientY; row++)
						if (evt.clientY <= row_offset[row][2]) break;
					// do loop - needed for rowspaned cells (if there is any)
					do{
						// set the number of cells in the selected row
						var cells = tables[table].rows[row].cells.length - 1;
						// find current cell (X mouse position between cell offset left and right)
						for (cell = cells; cell >= 0; cell--){
							// row left offset + cell left offset
							offsetLeft = row_offset[row][3] + tables[table].rows[row].cells[cell].offsetLeft;
							// cell right offset is left offset + cell width  
							offsetRight = offsetLeft + tables[table].rows[row].cells[cell].offsetWidth;
							// is mouse pointer is between left and right offset, then cell is found
							if (offsetLeft <= evt.clientX && evt.clientX < offsetRight) break;
						}
					} // mouse pointer is inside table but cell not found (hmm, rowspaned cell - try in upper row)
					while (cell == -1 && row-- > 0)
					// set current cell
					if(row>-1)
					{
					    cell_current = tables[table].rows[row].cells[cell];
					    // if current cell is marked as 'forbid', then return previous location
					    if (cell_current.className.indexOf(forbid) > -1) {table=table_old; row=row_old; cell=cell_old; break;}
					    // if drop_option == single and current cell has child nodes then test if cell is occupied
					    if (drop_option == 'single' &&	cell_current.childNodes.length > 0){
						    // if cell has only one node and that is text node then break - because this is empty cell
						    if (cell_current.childNodes.length == 1 && cell_current.firstChild.nodeType == 3) break;
						    // define and set has_content flag to false
						    var has_content = false;
						    // open loop for each child node and jump out if 'drag' className found
						    for (var i=cell_current.childNodes.length-1; i>=0 ; i--){
							    if (cell_current.childNodes[i].className && cell_current.childNodes[i].className.indexOf('drag') > -1) {has_content = true; break;} 
						    }
						    // if cell has content and old position exists ...
						    if (has_content && table_old != null && row_old != null && cell_old != null){
							    // .. and current position is different then source position then return previous position
							    if (table_source != table || row_source != row || cell_source != cell) {table=table_old; row=row_old; cell=cell_old; break;}
						    }
					    }
					}
					// break table loop 
					break;
		}
	}
}



// 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 ];
}



// clone object
function clone_obj(){
	// clone object and append to the div element (id="obj_new")
	var obj_new = obj.cloneNode(true);
	//document.getElementById('obj_new').appendChild(obj_new);
	// offset of the original object
	var offset = box_offset(obj);
	// offset of the new object (cloned)
	var offset_dragged = box_offset(obj_new);
	// calculate top and left offset of the new object
	obj_new.style.top   = (offset[0] - offset_dragged[0]) + "px";
	obj_new.style.left  = (offset[3] - offset_dragged[3]) + "px";
	// set onmouse down event for the new object
	obj_new.onmousedown = handler_onmousedown;
	// remove clone from the class name of the new object
	obj_new.className = obj_new.className.replace('clone', '');
	// append 'd' to the innerHTML of the new object 'Clone' -> 'Cloned'
	obj_new.innerHTML += 'd';
	// set id for cloned element
	obj_new.id = 'c' + cloned_id;
	// increment cloned_id
	cloned_id++;
	// set new position because div is appended to div id="obj_new"
	mouseX -= parseInt(obj_new.style.left);
	mouseY -= parseInt(obj_new.style.top);	
	// set reference to the new object	
	obj = obj_new;
}



// delete object
function trash_delete(){
	var div_text = 'element'; // div content (inner text)
	var border;               // border color (green or blue)
	// find the border color of DIV element (t1 - green, t2 - blue, t3 - orange)
	if (obj.className.indexOf('t1') > 0)      border = 'green';
	else if (obj.className.indexOf('t2') > 0) border = 'blue';
	else border = 'orange';
	// set div text (cross browser)
	if (obj.getElementsByTagName('INPUT').length || obj.getElementsByTagName('SELECT').length)
		div_text = 'form element';
	else if (obj.innerText || obj.textContent)
		div_text = '"' + (obj.innerText || obj.textContent) + '"';
	// ask if user is sure
	if (confirm('Delete '+div_text+' ('+border+') from\n table '+table_source+', row '+row_source+' and column '+cell_source+'?')){
		// yes, user is sure only call myhandler_deleted function
		myhandler_deleted();
	}
	// user is unsure - do undelete
	else{
		// append removed object to the source table cell
		//tables[table_source].rows[row_source].cells[cell_source].appendChild(obj);
		// and recalculate table cells because undelete can change row dimensions 
		calculate_cells();
		// call undeleted handler
		myhandler_undeleted();	
	}
}



// 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':
		case 'TEXTAREA':
		case 'DIV':
		case 'SPAN':
		case 'STRONG':
			formElement = true;
			break;
		default:
			formElement = false;
	}
	// return formElement flag
 	return formElement;
}

// used for myhandlers demo to print events in message box 
function message(text){
	//document.getElementById('message').innerHTML = text;
}

//
// handlers
// Here you can put custom JavaScript code instead of demo code.
// In each function you can use "obj" reference to the dragged object.
// Definition of all handler functions should exist, but can be empty if not needed.
// For example, if you don't need myhandler_notmoved handler, then handler code should look:
// function myhandler_notmoved() {}
//


function myhandler_clicked()   {message('Clicked');}
function myhandler_moved()     {message('Moved');}
function myhandler_notmoved()  {message('Not moved');}
function myhandler_dropped()   {message('Dropped');}
function myhandler_switched()  {message('Switched');}
function myhandler_cloned()    {message('Cloned');}
function myhandler_notcloned() {message('Not cloned');}
function myhandler_deleted()   {message('Deleted');}
function myhandler_undeleted() {message('Undeleted');}
