/*\
|*| Version : 0.92
|*| Author  : Chaitanya Yinti
|*| Contact : yinti@users.sourceforge.net
|*| WebSite : http://dhtmlgrid.sourceforge.net/
|*|
|*| Feel free to use this script under the terms of the GNU General Public
|*| License, as long as you do not remove or alter this notice.
\*/

	/*************************************\
	|       Start of Config Param         |
	\*************************************/
	// Color used for hilighting a selected row
	var clrHilight = 'blue';

	// Set this to false if you want 'click to select' and
	// 'doubleclick to Edit' mode
	var blnPointToSelect = false;

	// Full path of the blank image used to hide the sort images 
	var strBlankImage = "blank.gif";

	// Full path of the up image used on sort asc
	var strUpImage = "up.gif";	

	// Full path of the up image used on sort des
	var strDownImage = "down.gif";

	// The width of the images used to indicate the asc/des sort
	var intImgWidth = 12;

	// The height of the images used to indicate the asc/des sort
	var intImgHeight = 13;	
	/*************************************\
	|           End of Config Param       |
	\*************************************/

	/*************************************\
	|           Globals start             |
	\*************************************/

	// Stores the last used object during sort
	var objLastClick = -1;

	// Stores the text being edited
	var txtOld = "";

	// Stores the total table width
	var intTotalWidth = 0;

	// Stores the flag used by capturemouse
	var blnMouseOver = false;	

	// Stores the div being moved
	var objDivToMove = null;

	// Stores the number of coloumns; initialized in init ()
	var intColCount = 0;

	// Stores the row element currently selected
	var objRowSelected = null;

	//THE element which holds the table... 
	var element = null;
	
	// THE element which holds the div (in stead of the iframe)
	var divtable = null;
	
	var tabpressed = 0;
	/*************************************\
	|           Globals end               |
	\*************************************/

	/*********************TODO*****************************\
	 prototype setCapture/releaseCapture PROPERLY
	 Get rid of isIE, isNS4 completely ...
	 Extend keycapture to navigate the table on up/down arrow
	 Fix escape/unescape on text change
	\******************************************************/
		
	/*\
	|*| The entry point. This will 
	|*|		Attache all the appropriate functions to the table
	|*|		Call function to create the IMG elems used during the sorting
	|*|		call function to init the DIV elems that are used for moving
	|*|		call function to init the DIV elems used for about box
	\*/
	function init (tableName, divName)
	{
		//Handle all javascript errors 
		//window.onerror = handleError;

		isIE = (navigator.appVersion.indexOf ("MSIE") != -1);
		isNS4 = (document.layers) ? true : false;
		isNS6 = (!document.layers) && (navigator.userAgent.indexOf ('Netscape')!=-1);

		if ((isNS4) && (!isNS6)) alert ("Currently only supports NN 6 and above");

		if (document.getElementById)
		{
			element = document.getElementById (tableName);
			divtable = document.getElementById (divName);
		}	
		else	//TODO: Need to test this piece of code still. Happens only in NN4 so far 
		{
			eval (element = "document." + tableName);
			eval (divtable = "document." + divName);
		}	

		if (element == null || divtable == null)
		{
			//return alert ("Error: Not able to get table element ");
			return "";
		}	

		if (element.tagName != 'TABLE')
		{
			//return alert ("Error: Not able to control element " + element.tagName);
			return "";
		}		

		initNNFunctions ();

		if (blnPointToSelect)
		{
			element.attachEvent ('onmouseover', selectRow);
			element.attachEvent   ('onclick', onClickCell);
		}
		else
		{
			element.attachEvent ('onclick', selectRow);
			element.attachEvent ('ondblclick', onClickCell);
		}

		//document.attachEvent ('onkeydown' , captureDelKey);

		//Need this fix for IE only .. so element.focus is stubbed in NN
		//element.focus ();
	
		//initSortImages ();
		initDiv ();
		initAbout ();
		
		return "";
	}

	/*\
	|*| This function removes the textnodes from the table rows.
	|*| This cleanup work is needed to get rid of the EXTRA textnodes that NN gives
	\*/

	function removeTextNodes (t)
	{
		for (var i = 0; t.childNodes[i] ; i++)
		{
			if (!t.childNodes[i].tagName)
			{
				 t.childNodes[i].parentNode.removeChild (t.childNodes[i]);
			}
			else
			{
				for (var j = 0; t.childNodes[i].childNodes[j] ; j++)
				{
					if (!t.childNodes[i].childNodes[j].tagName) 
						t.childNodes[i].childNodes[j].parentNode.removeChild (t.childNodes[i].childNodes[j]);
				}
			}
		}

	}

	/*\
	|*| This function adds the blank images to the head row of the table
	\*/
	function initSortImages ()
	{
		if (!element.tHead) return;
		removeTextNodes (element.tHead);
		var theadrow = element.tHead.childNodes[0]; //Assume just one Head row

		if (isIE) theadrow.style.cursor = "hand";
		else theadrow.style.cursor = "pointer";

		removeTextNodes (theadrow.parentNode);
		intColCount = theadrow.childNodes.length;

		for (var i = 0; i < intColCount; i++) 
		{
			objImg = document.createElement ("IMG");

			objImg.setAttribute ("src", strBlankImage);
			objImg.setAttribute ("id", "srtImg" + i);
			objImg.setAttribute ("width", intImgWidth);
			objImg.setAttribute ("height", intImgHeight);
			objImg.setAttribute ("align", "right");
			objImg.setAttribute ("valign", "middle");
			objImg.setAttribute ("border", 0);

			clickCell = theadrow.childNodes[i];
			clickCell.selectIndex = i;
			clickCell.insertAdjacentElement ("afterBegin", objImg);
			clickCell.style.width = clickCell.width;
		}
	}

	/*\
	|*| This will only be called once during initIALIZATION
	|*| This will create the DIV elems at the end of each col and
	|*| attach all the functions needed to resize the coloumns
	\*/
	function initDiv ()
	{
		var objLast = element, objDiv;
		removeTextNodes (element.tBodies[0]);

		for (var i = 1; i <= intColCount; i++)
		{	
			objDiv = document.createElement ("DIV");
			objDiv.setAttribute ('id', "DragMark" + (i - 1));
			objDiv.setAttribute ('name',  i);		//Used to track the TDs that have to be moved
			objDiv.style.position = "absolute";
			objDiv.style.top = 0; 

			var objTD = element.tHead.childNodes[0].childNodes[i - 1];
			if (!objTD || objTD.tagName != "TD") return;

			var intColWidth = (getRealPos (objTD) - 0) + (objTD.width - 0);

			objDiv.style.left = intColWidth - 3 ;
			objDiv.style.width = 6 + parseInt(element.border);
			objDiv.style.height = (element.tBodies[0].childNodes.length + 1) * objTD.offsetHeight;
			// for debugging only
			//objDiv.style.backgroundColor = clrHilight;
			
			//To make it more beautiful in IE 6	
			if (navigator.appVersion.indexOf ("MSIE 6.0") != -1)
				objDiv.style.cursor = "col-resize";
			else
				objDiv.style.cursor = "crosshair";

			objDiv.attachEvent ('onmouseover', flagTrue);
			objDiv.attachEvent ('onmousedown', captureMouse);
			objDiv.attachEvent ('onmousemove', resizeColoumn);
			objDiv.attachEvent ('onmouseup', releaseMouse);
			objDiv.attachEvent ('onmouseout', flagFalse);

			objLast.insertAdjacentElement ("afterEnd", objDiv);
			objLast = objDiv;
		}
	}

	/*\
	|*| This function will be fired onmouseover of the DIVs
	|*| Set the flag to true indicating that the mouse is over the DIV
	\*/
	function flagTrue ()
	{
		blnMouseOver = true;
	}

	/*\
	|*| This function will be fired onmousedown on the DIVs
	|*| Capture all the mosue events if mousedown is fired inside the DIV
	\*/
	function captureMouse ()
	{
		if (blnMouseOver)
		{
			objDivToMove = window.event.srcElement;
			objDivToMove.setCapture ();
		}
	}

	/*\
	|*| This function will be fired onmousemove of the DIVs
	|*| This will be used as a ondrag function... thanks to IE 5
	\*/
	function resizeColoumn ()
	{
		//If mouse button is down, objDivToMove will be valid... we can move/resize
		if (!objDivToMove) return;

		var intTDNum = objDivToMove.name - 1;
		var thead = element.tHead;

		if (!thead) return;

		var objTD = thead.childNodes[0].childNodes[intTDNum];

		if (!objTD || objTD.tagName != "TD") return;

		var intCurWidth = objTD.offsetWidth;
		var newX = window.event.clientX;
		//var newX = window.event.x;
		var intNewWidth = newX - objTD.offsetLeft;

		//TODO: who decided that the minimum col widhth is 50px?
		if (intNewWidth < 50) return;
		//Check to see if the table widht is more than the width of the window
		//Need that 20px buffer in IE to prevent scroll bars from appearing
		if (element.document.body.offsetWidth - 20 < element.offsetWidth - intCurWidth + intNewWidth) return;

		objTD.style.width = intNewWidth;

		var objDiv = objDivToMove;
		//Will be ± 1 depending on which side the mouse moved
		//will be used to move all the DIVs remaining on the right
		var intDivMove = newX - objDiv.offsetLeft;
		objDiv.style.left = newX;

		//Move all the remaining DIVs on the right
		for (var i = 1; i < intColCount - intTDNum; i++)
		{				
			objDiv = objDiv.nextSibling;
			objDiv.style.left = objDiv.offsetLeft + intDivMove ;
		}
	}

	/*\
	|*| This function will be fired onmouseup
	|*| Release all the mouse events of the DIV
	\*/
	function releaseMouse ()
	{
		objDivToMove.releaseCapture ();
		objDivToMove = null;
	}

	/*\
	|*| This function will be fired onmouseout of the DIV
	|*| Set the flag indicating that the mouse is NOT over the DIV
	\*/
	function flagFalse ()
	{
		blnMouseOver = false;
	}

	/*\
	|*| This function will be called once during initIALIZATION
	|*| This will create DIV elm after the table to display the ABOUT informationA
	\*/
	function initAbout ()
	{
		objDiv = window.document.createElement ("DIV");
		objDiv.id = "About";
		objDiv.style.position = "absolute";
		objDiv.style.top = 0; 
		objDiv.style.left = 0 ;
		objDiv.align = "center";
		//element.document.body.offsetWidth ==> width of the IFRAME in IE
		objDiv.style.width = element.document.body.offsetWidth;
		objDiv.style.height = element.document.body.offsetHeight;
		objDiv.style.backgroundColor = "#0000FF";
		objDiv.style.color = "#FFFF00";
		objDiv.style.visibility = "hidden";
		objDiv.insertAdjacentText ("afterBegin", "DHTML Grid ver 0.92\n\n" + "");

		var objInput = document.createElement ("INPUT");
		objInput.id = "cmdAbout";
		objInput.title = "Ok";
		objInput.value = "Ok";
		objInput.align = "center";
		objInput.valign = "middle";
		objInput.style.height = "20px";
		objInput.style.width = "102px";
		objInput.type = "button";
		objInput.attachEvent ("onclick", about);

		objDiv.insertAdjacentElement ("beforeEnd", objInput);
		element.insertAdjacentElement ("afterEnd", objDiv);
	}

	/*\
	|*| Hilights the row on mouseover. This also sets the "previous row selected" to normal
	\*/
	function selectRow ()
	{
		var srcElem = getEventRow ();

		if (srcElem.tagName != "TR") return;
		if (objRowSelected)
		{
			objRowSelected.style.backgroundColor = '';
			objRowSelected = null;
		}
		if (srcElem.rowIndex > 0)
		{
			srcElem.style.backgroundColor = clrHilight;
			objRowSelected = srcElem;
		}
		
		var tableElem = srcElem.parentNode;
		while (tableElem.tagName != "TABLE")
		{
			tableElem = tableElem.parentNode;
		}
		//tableElem.focus();
		//element.focus ();
		
	}

	/*\
	|*| Entry point for all the click events on the table
	\*/
	function onClickCell ()
	{
		var srcElem = getEventRow();
		var objSrcElm = getEventCell();
		
		var tableElem = srcElem.parentNode;
		while (tableElem.tagName != "TABLE")
		{
			tableElem = tableElem.parentNode;
		}
	
		// no edit if:
		// - row is not selected
		// - rowindex is 0 (columnheader)
		// - cell is not editable
		if (srcElem.tagName != "TR") return;
		if (srcElem.rowIndex == 0)  return;
		if (!isEditable(tableElem.id, srcElem.rowIndex, objSrcElm.cellIndex))  return;
		onEdit (objSrcElm);
	}

	/*\
	|*| Capture the key press event, on del key see if a row is selected and delete
	\*/
	function captureDelKey ()
	{
		var keyPressed = event.keyCode;
		
		var srcElem = window.event.srcElement;
		if ((keyPressed == 46) && (srcElem.tagName != "INPUT") && (objRowSelected))
		{
			deleteRow (objRowSelected.rowIndex - 1);
			objRowSelected = null;
		}
	}

	/*\
	|*| detach all the events attached to the element and call other cleanup functions
	\*/
	function cleanup ()
	{
		element.detachEvent ('onmouseover', selectRow);
		element.detachEvent ('onclick', onClickCell);
		cleanupDiv ();
		cleanupAbout ();
	}

	/*\
	|*| Used by cleanup to clean the DIVs created for moving the Cols
	|*| detach all the events and delete the elements here
	\*/
	function cleanupDiv ()
	{
		var objDiv;
		for (var i = 1; i <= intColCount; i++)
		{	
			objDiv = element.document.getElementById ("DragMark" + (i - 1));
			objDiv.detachEvent ('onmouseover', flagTrue);
			objDiv.detachEvent ('onmousedown', captureMouse);
			objDiv.detachEvent ('onmousemove', resizeColoumn);
			objDiv.detachEvent ('onmouseup', releaseMouse);
			objDiv.detachEvent ('onmouseout', flagFalse);
			objDiv.removeNode (true);
		}
	}

	/*\
	|*| Detach all the events and Delete the elms related to the about box here
	\*/
	function cleanupAbout ()
	{
		element.document.getElementById ("About").removeNode (true);
	}

	/*\
	|*| This is THE function which does all the real sorting of the rows
	|*| First get rid of all the text-node elements that NN returns for spaces in the tables
	|*| then sort the contents based on which coloumn is clicked
	\*/
	function insertionSort (t, iRowEnd, fReverse, iColumn)
	{
		var textRowInsert, textRowCurrent, eRowInsert, eRowWalk;
		removeTextNodes (t);
		for (var iRowInsert = 1 ; iRowInsert <= iRowEnd ; iRowInsert++)
		{
			if (iColumn)
			{
				if (typeof (t.childNodes[iRowInsert].childNodes[iColumn]) != "undefined")
		 			textRowInsert = t.childNodes[iRowInsert].childNodes[iColumn].innerText;
				else
					textRowInsert = "";
			}
			else
			{
				textRowInsert = t.childNodes[iRowInsert].innerText;
			}

			for (var iRowWalk = 0 ; iRowWalk < iRowInsert ; iRowWalk++)
			{
				if (iColumn)
				{
					if (typeof (t.childNodes[iRowWalk].childNodes[iColumn]) != "undefined")
						textRowCurrent = t.childNodes[iRowWalk].childNodes[iColumn].innerText;
					else
						textRowCurrent = "";
				}
				else
				{
					textRowCurrent = t.childNodes[iRowWalk].innerText;
				}
				if ((!fReverse && textRowInsert < textRowCurrent) || (fReverse && textRowInsert > textRowCurrent))
				{
					eRowInsert = t.childNodes[iRowInsert];
					eRowWalk = t.childNodes[iRowWalk];
					t.insertBefore (eRowInsert, eRowWalk);
					iRowWalk = iRowInsert;
				}
			}
		}
	}

	/*\
	|*|	This function is called when there is a click event on the top
	|*|	row
	\*/
	function sort ()
	{
		var srcElem = getEventCell ();
		if (srcElem.tagName != "TD") return;

		var thead = element.tHead;	
		// clear the sort images in the head
		var imgcol = thead.getElementsByTagName ("IMG");
		for (var x = 0; x < imgcol.length; x++) 
		{
			imgcol[x].setAttribute('src', strBlankImage);
		}

		if (objLastClick == srcElem.selectIndex)
		{
			if (reverse == false)
			{
				srcElem.childNodes[0].setAttribute ('src', strDownImage);
				reverse = true;
			}
			else 
			{
				srcElem.childNodes[0].setAttribute ('src', strUpImage);
				reverse = false;
			}
		}
		else
		{
			reverse = false;
			objLastClick = srcElem.selectIndex;
			srcElem.childNodes[0].setAttribute ('arc', strUpImage);

		}
		tbody = element.tBodies [0];
		insertionSort (tbody, tbody.rows.length-1, reverse, srcElem.selectIndex);
	}

	/*\
	|*| This function is called when focus is lost on the text box
	|*| that is used to read user input. Validate the contents of the
	|*| input box and write them back to the table cell
	\*/
	function focusLost ()
	{
	  var myKeyCode = event.keyCode;
	  
		var objSrcElm = window.event.srcElement; 
		var value = "";
		
		if (objSrcElm.value == "") value = "&nbsp;";
		else 
		{
		  //value = unescape (objSrcElm.value);
		  value = objSrcElm.value;
		}
		
		// here we calculate the row calculations
		//var row = getEventRow();
		var srcElem = objSrcElm.parentNode;
		while (srcElem.tagName != "TABLE")
		{
		  if (srcElem.tagName == "TR") row = srcElem;
			srcElem = srcElem.parentNode;
		}
		
		var numReg = "^[0-9]*[,.]*[0-9]+$";
		var regex = new RegExp(numReg);
		
		if (typeof (calculation[srcElem.id]["row"][row.rowIndex]) == "object")
		{
		  if (calculation[srcElem.id]["row"][row.rowIndex][row.childNodes.length] == "summate" ||
		      calculation[srcElem.id]["row"][row.rowIndex][row.childNodes.length] == "substract" ||
		      calculation[srcElem.id]["row"][row.rowIndex][row.childNodes.length] == "multiply" ||
		      calculation[srcElem.id]["row"][row.rowIndex][row.childNodes.length] == "divide")
		  {
		    var calc = getCalcType(calculation[srcElem.id]["row"][row.rowIndex][row.childNodes.length]);
		    var calcstring = "";
		    
		    if (headers[srcElem.id]) start = 1;
		    else start = 0;
		    
		    for (i=start;i<(row.childNodes.length-1);i++)
		    {
		      if (i > start) calcstring += calc;
		      if (i == objSrcElm.parentNode.cellIndex)
		      {
		        if (regex.test(value)) calcstring += value.replace(",", ".");
		        else
		        {
		          if (calc != "/") calcstring += '0';
		          else calcstring += '1';
		        }
		      }
		      else
		      {
		        if (regex.test(row.childNodes[i].innerHTML)) calcstring += row.childNodes[i].innerHTML.replace(",", ".");
		        else
		        {
		          if (calc != "/") calcstring += '0';
		          else calcstring += '1';
		        }
		      }
		    }
		    var total = eval(calcstring);
		    if (row.childNodes[row.childNodes.length-1].cellIndex != objSrcElm.parentNode.cellIndex) row.childNodes[row.childNodes.length-1].innerHTML = Math.round(total*100)/100;
		  }
		}
		
		// here we calculate the column calculations
		if (typeof(calculation[srcElem.id]["column"][srcElem.rows.length]) == "object")
		{
		  if (calculation[srcElem.id]["column"][srcElem.rows.length][objSrcElm.parentNode.cellIndex] == "summate" ||
		      calculation[srcElem.id]["column"][srcElem.rows.length][objSrcElm.parentNode.cellIndex] == "substract" ||
		      calculation[srcElem.id]["column"][srcElem.rows.length][objSrcElm.parentNode.cellIndex] == "multiply" ||
		      calculation[srcElem.id]["column"][srcElem.rows.length][objSrcElm.parentNode.cellIndex] == "divide")
		  {
		    var calc = getCalcType(calculation[srcElem.id]["column"][srcElem.rows.length][objSrcElm.parentNode.cellIndex]);
		    var calcstring = "";
		    var parent = objSrcElm.parentNode;
		    
		    for (i=1;i<(srcElem.rows.length-1);i++)
		    {
		      if (i > 1) calcstring += calc;
		      if (srcElem.rows[i].rowIndex == parent.parentNode.rowIndex)
		      {
		        if (regex.test(value)) calcstring += value.replace(",", ".");
		        else
		        {
		          if (calc != "/") calcstring += '0';
		          else calcstring += '1';
		        }
		      }
		      else
		      {
		        if (regex.test(srcElem.rows[i].childNodes[objSrcElm.parentNode.cellIndex].innerHTML)) calcstring += srcElem.rows[i].childNodes[objSrcElm.parentNode.cellIndex].innerHTML.replace(",", ".");
		        else
		        {
		          if (calc != "/") calcstring += '0';
		          else calcstring += '1';
		        }
		      }
		    }
		    var total = eval(calcstring);
		    if (srcElem.rows[srcElem.rows.length-1].childNodes[objSrcElm.parentNode.cellIndex].cellIndex != objSrcElm.parentNode.cellIndex ||
		        srcElem.rows[srcElem.rows.length-1].rowIndex != parent.parentNode.rowIndex) 
		    {    
		      srcElem.rows[srcElem.rows.length-1].childNodes[objSrcElm.parentNode.cellIndex].innerHTML = Math.round(total*100)/100;
		    }
		  }
		  
		  // here we calculate the total column if necessary
		  if (calculation[srcElem.id]["column"][srcElem.rows.length][row.childNodes.length-1] == "summate" ||
		      calculation[srcElem.id]["column"][srcElem.rows.length][row.childNodes.length-1] == "substract" ||
		      calculation[srcElem.id]["column"][srcElem.rows.length][row.childNodes.length-1] == "multiply" ||
		      calculation[srcElem.id]["column"][srcElem.rows.length][row.childNodes.length-1] == "divide")
		  {
		    var calc = getCalcType(calculation[srcElem.id]["column"][srcElem.rows.length][row.childNodes.length-1]);
		    var calcstring = "";
		    var parent = objSrcElm.parentNode;
		    
		    for (i=1;i<(srcElem.rows.length-1);i++)
		    {
		      if (i > 1) calcstring += calc;
		      
		      var html = srcElem.rows[i].childNodes[row.childNodes.length-1].innerHTML;
		      if (html.substr(1,5) == "INPUT" || html.substr(1,5) == "input")
		      {
		        if (regex.test(value)) calcstring += value.replace(",", ".");
		        else
		        {
		          if (calc != "/") calcstring += '0';
		          else calcstring += '1';
		        }
		      }
		      else
		      {
		        if (regex.test(srcElem.rows[i].childNodes[row.childNodes.length-1].innerHTML)) calcstring += srcElem.rows[i].childNodes[row.childNodes.length-1].innerHTML.replace(",", ".");
		        else
		        {
		          if (calc != "/") calcstring += '0';
		          else calcstring += '1';
		        }
		      }
		    }
		    var total = eval(calcstring);
		    if (srcElem.rows[srcElem.rows.length-1].childNodes[row.childNodes.length-1].cellIndex != objSrcElm.parentNode.cellIndex ||
		        srcElem.rows[srcElem.rows.length-1].rowIndex != parent.parentNode.rowIndex) srcElem.rows[srcElem.rows.length-1].childNodes[row.childNodes.length-1].innerHTML = Math.round(total*100)/100;
		  }
		}
		
		var cellIndex = objSrcElm.parentNode.cellIndex;
		objSrcElm.parentNode.innerHTML = value;
		
		calculateFields();
		
    if (tabpressed)
    {	 
      tabpressed = 0; 
		  // find the first cell in this table that does not have a calculation or a defaultvalue
      for (i=0;i<srcElem.rows.length;i++)
      {
        for (j=0;j<srcElem.rows[i].childNodes.length;j++)
        {
          // check if this cell comes after the selected cell
          if (srcElem.rows[i].rowIndex > row.rowIndex || (srcElem.rows[i].rowIndex == row.rowIndex && srcElem.rows[i].childNodes[j].cellIndex > cellIndex))
          {
        		if (isEditable(srcElem.id, srcElem.rows[i].rowIndex,srcElem.rows[i].childNodes[j].cellIndex))
        		{
        		  onEdit(srcElem.rows[i].childNodes[j]);
        		  return;
        		}
          }
        }
      }
    }
	}
	
	function getCalcType(type)
	{
	  var calc = "";
	  switch (type)
	  {
	    case "summate":
	      calc = "+";
	      break;
	    case "substract":
	      calc = "-";
	      break;
	    case "multiply":
	      calc = "*";
	      break;
	    case "divide":
	      calc = "/";
	      break;
	  }
	  return calc;
	}

	/*\
	|*| This function is called when user clicks on a cell other than
	|*| the top row.
	|*| Show the content of the cell in an input box
	\*/
	function onEdit (srcElem)
	{
		if (srcElem.tagName != "TD") return;
		if (srcElem.firstChild && srcElem.firstChild.tagName == "INPUT") return;
		
		txtOld = srcElem.innerHTML;
    if (txtOld == "&nbsp;") txtOld = "";
		srcElem.innerHTML = ""; 

		var objInput = document.createElement ("INPUT");
		objInput.style.width = "100%";//srcElem.clientWidth;
		objInput.type = "text";
		//objInput.value = "" + escape(txtOld);
		objInput.value = "" + txtOld;
		//objInput.attachEvent ("onfocusout", focusLost);
		//the above onfocusout works fine in IE 6 but not in IE 5 so...
		objInput.attachEvent ("onblur", focusLost);
		objInput.attachEvent ("onkeydown", function() { checkForEnter(srcElem) });

		srcElem.insertAdjacentElement ("beforeEnd", objInput);

		objInput.focus ();
	}

	/*\
	|*| This function is used to add a row at the end of the tabl
	|*| Once the rows are added it calls the function to change the height
	|*|  of the DIVs that are used for resizing the table.
	\*/
	function addRow ()
	{
		var objTR = divtable.document.createElement ("TR");
		var objTD = divtable.document.createElement ("TD");

		for (var i = 0; i < addRow.arguments.length; i++) 
		{
			objTD = divtable.document.createElement ("TD");
			//objTD.appendChild (divtable.document.createTextNode ((arguments[i]=="")?"null":arguments[i]));
			objTD.innerHTML = ((arguments[i]=="")?"&nbsp;":arguments[i]);
			objTR.insertAdjacentElement ("beforeEnd", objTD);
		}

		objTBody = element.tBodies [0];
		objTBody.insertAdjacentElement ("beforeEnd", objTR);

		resizeDivs ();
	}
	

	/*\
	|*| The function deletes the last row by calling the deleteRow function 
	|*|  with the table row count
	\*/
	function deleteLastRow ()
	{
		removeTextNodes (element.tBodies[0]);
		this.deleteRow (element.tBodies[0].childNodes.length - 1);
	}
	
	function deleteCurrentRow()
	{
	  if (objRowSelected)
	  {
	    var tbody = objRowSelected.parentNode;
	    if (tbody.parentNode.id == element.id)
	  	{
		  	deleteRow (objRowSelected.rowIndex - 1);
			  objRowSelected.style.backgroundColor = '';
			  objRowSelected = null;
		  }
	  }  
	}

	/*\
	|*| The function checks if the rownum passed is a valid row 
	|*|  and deletes it 
	|*| This also calls the resizeDivs function to reduce the height
	|*|  of the DIVs that are used in resizing the table
	\*/
	function deleteRow (rowNum)
	{
		var tbody = element.tBodies [0];
		if (!tbody || rowNum < 0) return;

		removeTextNodes (tbody);
		tbody.childNodes[rowNum].removeNode (true);
		resizeDivs ();
	}

	/*\
	|*| This will be called on everkeypress event of the input box
	|*| This raises the focuslost event if the user hits enter
	\*/
	function checkForEnter (Cell)
	{
		if (event.keyCode == 13 || event.keyCode == 9)
		{
		  tabpressed = 1;
		}
	}
	
	function isEditable(tableid, rowindex, cellindex)
	{  
    // check if cell is editable
    // cell is not editable if:
    // - rowindex is 0 and rowheader 
    // - cell has row calculation
    // - cell or row has columncalculation
    // - cell has defaultvalue
    var editable = 1;
    
    if (cellindex == 0 && headers[tableid]) editable = 0;
		if (typeof (calculation[tableid]["row"][rowindex]) == "object")
		{
		  if (calculation[tableid]["row"][rowindex][cellindex+1] == "summate" ||
		      calculation[tableid]["row"][rowindex][cellindex+1] == "substract" ||
		      calculation[tableid]["row"][rowindex][cellindex+1] == "multiply" ||
		      calculation[tableid]["row"][rowindex][cellindex+1] == "divide")
		    editable = 0;  
		}  
		if (typeof (calculation[tableid]["column"][rowindex+1]) == "object")
		{
		  if (calculation[tableid]["column"][rowindex+1][cellindex] == "summate" ||
		      calculation[tableid]["column"][rowindex+1][cellindex] == "substract" ||
		      calculation[tableid]["column"][rowindex+1][cellindex] == "multiply" ||
		      calculation[tableid]["column"][rowindex+1][cellindex] == "divide")
		    editable = 0;
		  // check if we are in the last row
		  if (typeof (calculation[tableid]["row"]) == "object")
		  {
  		  if ((rowindex+1) == (calculation[tableid]["row"].length-1))
  		  {
  		    for (k=headers[tableid];k<calculation[tableid]["column"][rowindex+1].length;k++)
  		    {
  		      if (calculation[tableid]["column"][rowindex+1][k] == "summate" ||
  		          calculation[tableid]["column"][rowindex+1][k] == "substract" ||
  		          calculation[tableid]["column"][rowindex+1][k] == "multiply" ||
  		          calculation[tableid]["column"][rowindex+1][k] == "divide")
  		      editable = 0;
  		    }
  		  }
		  }
		}  
		if (typeof (editfields[tableid][rowindex]) == "object")
		{
		  if (editfields[tableid][rowindex][cellindex] != "") editable = 0;
		}
		return editable;
	}

	/*\
	|*| Toggle the About div section
	\*/
	function about ()
	{
		if (element.document.getElementById ("About").style.visibility == "hidden")
			element.document.getElementById ("About").style.visibility = "visible";
		else
			element.document.getElementById ("About").style.visibility = "hidden";
	}

	/*\
	|*| Need this as IE 5 doesnt give the offsetLeft property properly
	\*/
	function getRealPos (elm)
	{
		intPos = 0;
		elm = elm.previousSibling;
		while ((elm!= null) && (elm.tagName!="BODY"))
		{
	 		intPos += elm.width - 0;
			elm = elm.previousSibling;
		}
		return intPos;
	}

	/*\
	|*| Return the TR elem on which an event has fireed
	\*/
	function getEventRow ()
	{
		var srcElem = window.event.srcElement;
		//crawl up to find the row
		while (srcElem.tagName != "TR" && srcElem.tagName != "TABLE")
		{
			srcElem = srcElem.parentNode;
		}
		return srcElem;
	}

	/*\
	|*| Return the TD elem on which an event has fireed
	\*/
	function getEventCell ()
	{
		var srcElem = window.event.srcElement;
		//crawl up the tree to find the table col
		while (srcElem.tagName != "TD" && srcElem.tagName != "TABLE")
		{
			srcElem = srcElem.parentNode;
		}
		return srcElem;
	}

	/*\
	|*| This funtion is used to change the height of the DIVs that are used to drag the cols
	|*| Used when a row is added or deleted.
	\*/
	function resizeDivs ()
	{
		for (var i = 0; i < intColCount; i++)
		{	
			var objDiv = element.document.getElementById ("DragMark" + (i));
			var objTD = element.tHead.childNodes[0].childNodes[i];

			if ((!objDiv) || (!objTD) || (objTD.tagName != "TD")) return;
			objDiv.style.height = (element.tBodies[0].childNodes.length + 1) * (objTD.offsetHeight - 1);
		}
	}

	/*\
	|*| Function to handle erros. Displayes a request to contact along with the error messagei, filename and line
	\*/
	function handleError (err, url, line)
	{
		alert ('Oops, something went wrong.\n' +
			 'Please contact yinti AT users DOT sourceforge DOT net with the following text\n' + 
			 'Error text: ' + err + '\n' + 
			 'Location  : ' + url + '\n' +
			 'Line no   : ' + line + '\n');
		 return true;
        }

  /*\
  |*| Function to prototype all the functions needed by NN to emulate the functionality of IE
  \*/
  function initNNFunctions ()
  {
    if ((self.Node) && (self.Node.prototype))
    {
      Node.prototype.removeNode = NNRemoveNode;

      Element.addMethods({insertAdjacentText: NNInsertAdjacentText});
      Element.addMethods({insertAdjacentElement: NNInsertAdjacentElement});
      Element.addMethods({insert__Adj: NNInsertAdj});
      Element.addMethods({attachEvent: NNAttachEvent});
      Element.addMethods({detachEvent: NNDetachEvent});
      Element.addMethods({setCapture: NNSetCapture});
      Element.addMethods({releaseCapture: NNReleaseCapture});
      Element.prototype.__defineGetter__('document', NNDocumentGetter);

      Element.addMethods('HTMLElement', {focus: NNNullFunction});
      Element.addMethods('HTMLElement', {attachEvent: NNAttachEvent});
      Element.addMethods('HTMLElement', {detachEvent: NNDetachEvent});
      HTMLElement.prototype.__defineGetter__('innerText', NNInnerTextGetter);
      HTMLElement.prototype.__defineSetter__('innerText', NNInnerTextSetter);

      Element.addMethods('HTMLDocument', {attachEvent: NNAttachEvent});
      Element.addMethods('HTMLDocument', {detachEvent: NNDetachEvent});

      Event.prototype.__defineGetter__('keyCode', NNKeyCodeGetter);
    }
  }

	/*\
	|*|
	\*/
	function NNRemoveNode (a1)
	{
		var p = this.parentNode;
		if (p&&!a1)
		{
			var df = document.createDocumentFragment ();
			for (var a = 0; a < this.childNodes.length; a++)
			{
				df.appendChild (this.childNodes[a])
			}
			p.insertBefore (df , this)
		}
		return p?p.removeChild (this):this;
	}

	/*\
	|*|
	\*/
	function NNInsertAdjacentText (el, a1 , a2)
	{
		var t = document.createTextNode (a2||"")
		el.insert__Adj (a1 , t);
	}

	/*\
	|*|
	\*/
	function NNInsertAdjacentElement (el, a1 , a2)
	{
		el.insert__Adj (a1 , a2);
		return a2;
	}

	/*\
	|*|
	\*/
	function NNInsertAdj (el, a1 , a2)
	{
		var p = el.parentNode;
		var s = a1.toLowerCase ();
		if (s == "beforebegin"){p.insertBefore (a2 , el)}
		if (s == "afterend"){p.insertBefore (a2 , el.nextSibling)}
		if (s == "afterbegin"){el.insertBefore (a2 , el.childNodes[0])}
		if (s == "beforeend"){el.appendChild (a2)}
	}

	/*\
	|*| Fuction to simulate attachEvent
	\*/
	function NNAttachEvent (el, strEvent, funcHandle)
	{
		var shortTypeName = strEvent.replace (/on/, "");
		funcHandle._ieEmuEventHandler = function (e)
		{
			window.event = e;
			window.event.srcElement = e.target;
			return funcHandle ();
		};
		el.addEventListener (shortTypeName, funcHandle._ieEmuEventHandler, false);
	}

	/*\
	|*| Fuction to simulate detachEvent
	\*/
	function NNDetachEvent (el, strEvent, funcHandle)
	{
		var shortTypeName = strEvent.replace (/on/, "");
		if (typeof funcHandle._ieEmuEventHandler == "function")
			el.removeEventListener (shortTypeName, funcHandle._ieEmuEventHandler, false);
		else
			el.removeEventListener (shortTypeName, funcHandle, true);
	}

	/*\
	|*| A HUGE HACK to getaway with the lack of setcapture in NN
	\*/
	function NNSetCapture ()
	{
		//TODO: FIX THIS FIRST BEFORE ANYTHING ELSE!! MAJOR HACK FOR NOW
		document.attachEvent ('onmousemove', resizeColoumn);
		document.attachEvent ('onmouseup', releaseMouse);
	}

	/*\
	|*| A HUGE HACK to getaway with the lack of releasecapture in NN
	\*/
	function NNReleaseCapture ()
	{
		//TODO: FIX THIS SECOND THEN GO TO EVERYTHING ELSE! 
		document.detachEvent ('onmousemove', resizeColoumn);
		document.detachEvent ('onmouseup', releaseMouse);
	}

	/*\
	|*| Empty function used to remove any functions not needed in NN
	\*/
	function NNNullFunction () { /*Nothing here*/ }

	/*\
	|*| return the innerhtml by replacing all the <TAGNAME> from the string
	\*/
	function NNInnerTextGetter ()
	{
		return this.innerHTML.replace (/<[^>]+>/g,"");
	}

	/*\
	|*| Add the text as a textnode to the element
	\*/
	function NNInnerTextSetter (txtStr)
	{
		var parsedText = document.createTextNode (txtStr);
		this.innerHTML = "";
		this.appendChild (parsedText);
	}

	/*\
	|*| Function to simulate event.keyCode
	\*/
	function NNKeyCodeGetter ()
	{
		return this.which;
	}

	/*\
	|*| Function to simulate element.document
	\*/
	function NNDocumentGetter ()
	{
		return this.ownerDocument;
	}
	
	function get_html(nom_editor)
  {
    var obj_ed = document.getElementById(nom_editor);
    var cont = obj_ed.innerHTML;
    //var texto = "" + cont
    //texto = strip_body(texto);
    return cont;
  }


