//---------------------
//Variable declaration
//---------------------
var jsWebGrids = new Array(); // Used top keep track of more than 1 grid on a page
var curCell; // Used for column resizing
var nav = '';

//----------------------
//Function to trim space
//----------------------
String.prototype.trim = function ()
{
   return this.replace(/^(\s|\xA0)+|(\s|\xA0)+$/g, "");
};

//-------------------------------------
//Function to trim space from left side
//-------------------------------------
String.prototype.ltrim = function ()
{
   return this.replace(/^(\s|\xA0)+/, "");
};

//--------------------------------------
//Function to trim space from right side
//--------------------------------------
String.prototype.rtrim = function ()
{
   return this.replace(/(\s|\xA0)+$/, "");
};

//---------------------------------
//Function to get string ends with
//---------------------------------
String.prototype.endsWith = function (str)
{
   return (this.match(str + "$") == str)
};

//-----------------------------------
//Function to replace all in a string
//-----------------------------------
String.prototype.ReplaceAll = function (stringToFind, stringToReplace)
{
   var temp = this;
   var index = temp.indexOf(stringToFind);

   while (index != -1)
   {
      temp = temp.replace(stringToFind, stringToReplace);
      index = temp.indexOf(stringToFind);
   }

   return temp;
};

//------------------------------------
//Function to get characters from left
//------------------------------------
String.prototype.Left = function (noOfCharacters)
{
   if (noOfCharacters <= 0)
      return "";
   else if (noOfCharacters > String(this).length)
      return this;
   else
      return String(this).substring(0, noOfCharacters);
};

//-------------------------------------
//Function to get characters from right
//-------------------------------------
String.prototype.Right = function (noOfCharacters)
{
   if (noOfCharacters <= 0)
      return "";
   else if (noOfCharacters > String(this).length)
      return this;
   else
   {
      var iLen = String(this).length;
      return String(this).substring(iLen, iLen - noOfCharacters);
   }
};

//---------------------------------
//Function to trim string from left
//---------------------------------
String.prototype.LTrim = function ()
{
   for (var k = 0; k < this.length && this.charAt(k) <= " "; k++);
   return this.substring(k, this.length);
};

//----------------------------------
//Function to trim string from right
//----------------------------------
String.prototype.RTrim = function ()
{
   for (var j = this.length - 1; j >= 0 && this.charAt(j) <= " "; j--);
   return this.substring(0, j + 1);
};

//--------------------------------------
//Function to trim string from both side
//--------------------------------------
String.prototype.Trim = function ()
{
   return this.LTrim().RTrim();
};

/*--------------------------------------------------------------------------------------------------------------------------------------
Description : Grid Object

Properties     
1. GridID - Holds grid id [main DIV container]

Events
1. rowClickEvent(rowID or rowID[]) - Holds event handler fired when a row is clicked
2. rowDoubleClickEvent(rowID) - Holds event handler fired when a row is double clicked
3. rowChangedEvent(rowID) - Holds event handler fired when a row value has changed
4. columnClickEvent(columnIndex, columnName, sortDir) - Holds event handler fired when a column header is clicked

Methods
1. getColumnDataType(columnIndex or columnName or columnObject) - Function to get column's datatype
2. deleteRow(rowID or rowObject) - Method to delete a single row
3. deleteSelectedRows() - Function to set delete property for the selected rows
4. getRowSelectionType - Function to get the current row selection type [Single / Multiple]
5. getSelectedRowCount - Function to get selected row count
6. getColumnIndex(columnName) - Function to get column index
7. getCellValue(rowID, colIndex) - Function to get the cell value
8. getCellValueByColName(rowID, colName) - Function to get the cell value
9. findRowsByCellValue(colName, value) - Function to find and return an array of rowIDs for all rows that contain the supplied value
10. getRowCount() - Function to get the total number of rows in the grid
11. getFirstRowID() - Function to get the first row's rowID
12. getLastRowID() - Function to get the last row's rowID
13. clearGridRows() - Function to clear the row from the grid
14. clearGrid() - Function to clear the whole grid [Rows and columns]
15. selectRowByIndex(rowIndex) - Function to set selected row by index
16. selectRowByRowID(rowID) - Function to set selected row by row ID
17. getSelectedRows() - Function to get an array of selected row's rowIDs
18. setSelectedRows(rowArray) - Function to set selected rows from an array of rowIDs
19. sizeColumn(cellIndex, width) - Function to set column size
20. setEditableFlag(trueFalse) - Function to enable/disable editing on grid
21. addNewRow() - Function to add new row to the grid
22. popGridFromJson(jsonString, optional async, optional processAfter, optional makeColumnsFit [true/false]) - Function to build grid's rows from the JSON string
23. popGridColumns(gridColumnJSON) - Function to build grid's columns from the JSON
24. setNextSelectedRow() - Function to select the next row
25. refreshGrid() - Function refresh the grid [call initCellWidth and initGrid method]
26. setColumnAsSorted(colName, direction) - Function to make the column appear sorted without sorting
27. getSelectedRowIndex() - Function to get the current selected row index
28. clearAllColumnSorts() - Function to remove all column sort information (does not resort table)
29. makeColumnsFit() - Function to make the columns fit within the width of the grid keeping the column width proportions
30. findRowsByCellValues(nameValues) - Function to find and return an array of rowIDs for all rows that contain the supplied values from a NameValue List
31. serializeData(onlyModified) - Function to serialize the grid data (all or only the modified)
32. setCellValue(rowIndex, colIndex, value) - Function to set a cell value for a given row index and column index
33. setCellValueByColName(rowIndex, colName, value) - Function to set a cell value for a given row index and column name
34. getRowIndex(rowID) - Function to get the row index for a given row ID
35. getRowID(RowIndex) - Function to get the row ID for a given row index
36. setCellEditable(rowID, column, editableFlag) - Function to set/override cell editable property
37. scrollToSelectedRow() - Scrolls the first selected row into view
38. scrollToRowID(rowID) - Scrolls the row represented by the given RowID into view.
39. scrollToRowIndex(rowIndex) - Scrolls the row represented by the given rowIndex into view.
40. insertRow(jsonString, index) - Inserts the provided row at the location indicated by the Index.
41. commitChanges() - Applies changes to rows making all row's row state equal Not Modified.
42. removeRowByRowID(rowID) - Removes a row represented by the RowID. This is different from Deleting a row.
43. removeRowByRowIndex(rowIndex) - Removes a row represented by the RowIndex. This is different from Deleting a row.
44. clearSelectedRows() - Function to clear selected rows.
----------------------------------------------------------------------------------------------------------------------------------------*/
function jsWebGrid(gridId, options)
{
   this.rowClickEvent = null;
   this.rowDoubleClickEvent = null;
   this.rowChangedEvent = null;
   this.columnClickEvent = null;

   this.md = 0;
   this.os = null;
   this.GridID = gridId;
   this.sortAsc = '';
   this.sortDsc = '';
   this.sortMethod = '';
   this.sortDir = '';
   this.sortAscImage = '';
   this.sortDscImage = '';
   this.rowClass = '';
   this.altRowClass = '';
   this.selectedRowClass = '';
   this.Options = null;
   this.selectedRowIDs = null;
   this.currentlySelectedRow = null;
   this.sortedColumns = new Array();
   var self = this;
   var calendar = new gridCalendar(gridId);
   var currentEdit;
   var cellOldValue = '';
   var cellNewValue = '';
   var initWidth = '';
   var widthOffset = null;
   var markForColumnFit = false;
   var selectedRows = new Array();

   if (options)
   {
      try
      {
         this.Options = eval('(' + options + ')');
      } catch (err) { }
   }

   this.show = function ()
   {
      document.getElementById(self.GridID).style.display = '';
      self.refreshGrid();
   };

   this.hide = function ()
   {
      document.getElementById(self.GridID).style.display = 'none';
   };

   this.removeRowByRowID = function (rowID)
   {
      var row = self._getRowByRowID(rowID);
      row.parentNode.removeChild(row);
   };

   this.removeRowByRowIndex = function (rowIndex)
   {
      var tbl = this.getGridBody();
      var row = tbl.rows[rowIndex];
      row.parentNode.removeChild(row);
   };

   this.getColumnDataType = function (elem)
   {
      if (typeof elem == 'number')
         elem = self.getGridHeader().rows[0].cells[elem];
      else if (typeof elem == 'string')
         elem = self.getColumnIndex(elem);
      try
      {
         var td = getParent(elem, 'td');
         var colIndex = getCellIndex(td);
         var hr = self.getGridHeader().rows[0];
         var c = hr.cells[colIndex];
         var dt = c.getAttribute('datatype');
         if (dt)
            return dt;
         else
            return 'SingleLineText';
      } catch (err) { return 'SingleLineText'; }
   };


   this.__encode = function (value)
   {
      var newValue = value.ReplaceAll('<', '&lt;').ReplaceAll('>', '&gt;');
      return newValue;
   };

   this.__decode = function (value)
   {
      var newValue = value.ReplaceAll('&lt;', '<').ReplaceAll('&gt;', '>');
      return newValue;
   };

   this.getColumnAttribute = function (elem, attribute)
   {
      if (typeof elem == 'number')
         elem = self.getGridHeader().rows[0].cells[elem];
      else if (typeof elem == 'string')
         elem = self.getColumnIndex(elem);
      try
      {
         var td = getParent(elem, 'td');
         var colIndex = getCellIndex(td);
         var hr = self.getGridHeader().rows[0];
         var c = hr.cells[colIndex];
         var dt = c.getAttribute(attribute);
         if (dt)
            return dt;
         else
            return '';
      } catch (err) { return ''; }
   };

   this._setChangedModeFlag = function (e)
   {
      if (!e) e = window.event;
      var cell = e.target != null ? e.target : e.srcElement;
      if (cell.nodeType == 3) cell = cell.parentNode; // defeat Safari bug
      var gridId = GetGridID(cell);
      if (cell.tagName.toLowerCase() != 'td')
         cell = getParent(cell, 'td');

      var row = getParent(cell, 'tr');
      var val = row.getAttribute('rowid').toString();
      if (val.endsWith('_added'))
      {
         row.setAttribute('rowid', val);
      }
      else if (!val.endsWith('_modified'))
      {
         val += '_modified';
         row.setAttribute('rowid', val);
      }
      if (self.rowChangedEvent)
         self.rowChangedEvent(row.getAttribute('rowid').toString());
   };

   this.hideEdit = function (cell)
   {
      if (cell.getAttribute('controlAdded'))
      {
         var value = null;
         var inp = null;
         var dataType = this.getColumnDataType(cell);
         if (dataType) dataType = dataType.toLowerCase();
         if (dataType == 'multilinetext')
         {
            inp = cell.getElementsByTagName('textarea')[0];
            if (!inp) return;
            cell.innerHTML = self.__encode(inp.value).replace(/\r\n/g, "<br />").replace(/\n/g, "<br />");
         }
         else if (dataType == 'dropdownlist')
         {
            var sel = cell.getElementsByTagName('select')[0];
            if (!sel) return;
            var si = sel.selectedIndex;
            var val = sel.options[si].value;
            var txt = sel.options[si].text;
            sel.style.display = 'none';
            cell.innerHTML = '<nobr>' + self.__encode(txt) + '</nobr>';
            cell.setAttribute('value', val);
         }
         else if (dataType == 'date')
         {
            inp = cell.getElementsByTagName('input')[0];
            if (!inp) return;
            if (document.getElementById('hidCalender').value == 1)
            {
               inp = cell.getElementsByTagName('input')[0];
               if (inp)
                  inp.select();
               return;
            }
            else
            {
               inp = cell.getElementsByTagName('input')[0];
               if (!inp) return;
               cell.innerHTML = "<nobr>" + inp.value + "</nobr>";
            }
         }
         else if (dataType == 'boolean')
         {
            inp = cell.getElementsByTagName('input')[0];
         }
         else
         {
            inp = cell.getElementsByTagName('input')[0];
            if (!inp) return;
            cell.innerHTML = "<nobr>" + self.__encode(inp.value) + "</nobr>";
         }
         cell.setAttribute('controlAdded', '');
      }
   };

   this._removeControl = function (e)
   {
      if (!e) e = window.event;
      var cell = e.target != null ? e.target : e.srcElement;
      if (cell.nodeType == 3) cell = cell.parentNode; // defeat Safari bug

      var gridId = GetGridID(cell);
      if (cell.tagName.toLowerCase() != 'td')
         cell = getParent(cell, 'td');
      self.hideEdit(cell);
   };

   this._startEdit = function (e)
   {
      if (!e) e = window.event;
      var cell = e.target != null ? e.target : e.srcElement;
      if (cell.nodeType == 3) cell = cell.parentNode; // defeat Safari bug

      var gridId = GetGridID(cell);
      if (cell.tagName.toLowerCase() != 'td')
         cell = getParent(cell, 'td');

      if (document.getElementById(gridId).getAttribute('editable') == "true")
         self.showEdit(cell, false);
   };

   this.showEdit = function (cell, oldCell)
   {
      if (cell.getElementsByTagName('td') && cell.getElementsByTagName('td').length > 0) return;
      if (document.getElementById('hidCalender'))
         document.getElementById('hidCalender').value = '';
      if (!oldCell)
         oldCell = currentEdit;
      var grid = document.getElementById(this.GridID);
      var innerTextValue;
      if (!cell)
         return;
      var grdID = this.GridID;
      var hr = self.getGridHeader().rows[0];
      var dataType = this.getColumnDataType(cell);
      if (!dataType) return;
      dataType = dataType.toLowerCase();
      if (grid.getAttribute('editable') == "false")
         return;
      var x = getCellIndex(cell);
      if (hr.cells[x].getAttribute('editable') && hr.cells[x].getAttribute('editable').toLowerCase() != 'true')
      {
         if (!cell.getAttribute('NonEditable') || cell.getAttribute('NonEditable').toLowerCase() == 'true')
            return;
      }
      var row = getParent(cell, 'tr');
      var y = row.getAttribute('rowid').toString();

      var id = '';
      if (dataType != 'boolean' && dataType != 'dropdownlist')
      {
         if (!cell.getAttribute('controlAdded'))
         {
            innerTextValue = self.__decode(self.getCellText(cell));
            var maxLength = self.getColumnAttribute(cell, 'maxlength');
            if (maxLength)
               maxLength = ' maxlength="' + maxLength + '" ';

            if (dataType == 'singlelinetext')
            {
               id = 'SLTtempInput' + x + '_' + y;
               cell.innerHTML = "<input id=\"" + id + "\" style=\"width:95%;\" type=\"text\" " + maxLength + " value=\"" + innerTextValue + "\"/>";
            }
            else if (dataType == 'multilinetext')
            {
               id = 'MLTtempInput' + x + '_' + y;
               cell.innerHTML = "<textarea id=\"" + id + "\" style=\"width:95%;\" " + maxLength + " type=\"text\">" + innerTextValue + "</textarea>";
            }
            else if (dataType == 'decimal')
            {
               id = 'DECtempInput' + x + '_' + y;
               cell.innerHTML = "<input id=\"" + id + "\" style=\"width:95%;\" type=\"text\" " + maxLength + " value=\"" + innerTextValue + "\"/>";
            }
            else if (dataType == 'wholenumber')
            {
               id = 'WNtempInput' + x + '_' + y;
               cell.innerHTML = "<input id=\"" + id + "\" style=\"width:95%;\" type=\"text\" " + maxLength + " value=\"" + innerTextValue + "\"/>";
            }
            else if (dataType == 'date')
            {
               id = 'DTtempInput' + x + '_' + y;
               cell.innerHTML = "<input id=\"" + id + "\" style=\"width:95%;\" type=\"text\" " + maxLength + " value=\"" + innerTextValue + "\" " + " maxlength=\"10\"/>" +
                                     "<input id=\"hidCalender\" type=\"hidden\" />";
            }
            if (document.getElementById(id))
            {
               cell.setAttribute('controlAdded', 'true');
               addEvent(document.getElementById(id), 'keydown', self._editElementKeyPress);
               addEvent(document.getElementById(id), 'blur', self._removeControl);
               addEvent(document.getElementById(id), 'change', function (e)
               {
                  self._setChangedModeFlag(e);
                  self._SerializeServerData();
               });
               if (dataType == 'decimal')
               {
                  document.getElementById(id).onkeydown = function (e)
                  {
                     return validateNumericControl(e, 'Decimal', this, '3');
                  };
                  document.getElementById(id).onkeyup = function (e)
                  {
                     return validateNumericControl(e, 'Decimal', this, '3');
                  };
               }
               if (dataType == 'wholenumber')
               {
                  document.getElementById(id).onkeydown = function (e)
                  {
                     return validateNumericControl(e, 'WholeNumber', this, '3');
                  };
                  document.getElementById(id).onkeyup = function (e)
                  {
                     return validateNumericControl(e, 'WholeNumber', this, '3');
                  };
               }
               document.getElementById(id).focus();
               document.getElementById(id).select();
               if (dataType == 'date')
               {
                  addEvent(document.getElementById(id), 'keyup', function (e)
                  {
                     e = window.event || e;
                     if (e.keyCode == 9)
                        return calendar.gcalHide();
                     if (e.keyCode == 40)
                     {
                        document.getElementById('hidCalender').value = 1;
                        return calendar.gcalShow(document.getElementById(id), e);
                     }
                     if (e.keyCode == 38)
                        return calendar.gcalHide();
                     return maskDateField(this);
                  });
                  addEvent(document.getElementById(id), 'keypress', function (e)
                  {
                     e = window.event || e;
                     if (e.keyCode == 9)
                        return false;
                     return allowDateNumeric();
                  });
                  addEvent(document.getElementById(id), 'keydown', function (e)
                  {
                     e = window.event || e;
                     self._editElementKeyPress;
                     if (e.keyCode == 9)
                        calendar.gcalHide();
                  });
                  addEvent(document.getElementById(id), 'click', function (e)
                  {
                     document.getElementById('hidCalender').value = 1;
                     calendar.gcalShow(document.getElementById(id), e);
                  });
               }
            }
         }
      }
      else if (dataType == 'boolean')
      {
         var cb = cell.getElementsByTagName('input')[0];
         removeEvent(cb, 'keydown', self._editElementKeyPress);
         addEvent(cb, 'keydown', self._editElementKeyPress);
         setTimeout(function () { cb.focus(); }, 1);
      }
      else if (dataType == 'dropdownlist')
      {
         if (!cell.getAttribute('controlAdded'))
         {
            var ddl = document.getElementById(grdID + '_col_' + getCellIndex(cell)).cloneNode(true);
            ddl.id = grdID + '_ddl_' + getCellIndex(cell);
            var val = cell.getAttribute('value');
            ddl.value = val;
            cell.innerHTML = '';
            ddl.style.display = 'inline';
            ddl.style.width = '95%';
            ddl.onchange = self._setChangedModeFlag;
            ddl.onblur = self._removeControl;
            ddl.onkeydown = self._editElementKeyPress;
            cell.setAttribute('controlAdded', 'true');
            cell.appendChild(ddl);
            ddl.focus();
         }
      }
      currentEdit = cell;
      if (oldCell && oldCell != cell)
      {
         if (!document.all)
            self.hideEdit(oldCell);
      }
   };

   this.deleteRow = function (row)
   {
      var tbl = this.getGridBody();
      if (typeof row == 'string')
      {
         var l = tbl.rows.length;
         for (var r = 0; r < l; r++)
         {
            if (tbl.rows[r].getAttribute('rowid').toString() == row)
            {
               row = tbl.rows[r];
               break;
            }
         }
      }

      var sr = this.getSelectedRows();
      this._doRowDelete(row);

      if (!this.isHidden(document.getElementById(this.GridID)))
         this.initCellWidth();
      this.colorAltRows();
      this.setSelectedRows(sr);
      this._SerializeServerData();
   };

   this._doRowDelete = function (row)
   {
      var tbl = this.getGridBody();
      var ri = row.getAttribute('rowid').toString();
      if (!ri.endsWith('_deleted'))
         ri += '_deleted';
      row.setAttribute('rowid', ri);
      row.style.display = 'none';

      row.className = row.getAttribute('origCL');
      row.setAttribute('origCL', '');

      var tb = tbl.getElementsByTagName('tbody')[0];
      if (!tb)
         tb = bdy;
      tb.appendChild(row);
      var delCount = self.getRowCount();
      if (delCount == tbl.rows.length)
         self.addDummyRow();

      if (self.rowChangedEvent)
         self.rowChangedEvent(row.getAttribute('rowid').toString());
   };

   this.deleteSelectedRows = function (noConfirmMessage)
   {
      if (typeof noConfirmMessage == 'undefined')
         noConfirmMessage = false;

      var grid = document.getElementById(this.GridID);
      if (grid.getAttribute('editable').toLowerCase() == 'false')
         return;
      if (!self.selectedRowIDs)
      {
         window.alert('No row has been selected, please select a row to delete.');
         return;
      }

      var deleteConfirm = false;

      if (noConfirmMessage)
         deleteConfirm = true;
      else
      {
         if (window.confirm('Are you sure you want to delete this record ?'))
            deleteConfirm = true;
      }

      if (deleteConfirm)
      {
         var sr = self.getSelectedRows();
         var tbl = self.getGridBody();
         for (var r = tbl.rows.length - 1; r >= 0; r--)
         {
            for (var c = sr.length - 1; c > -1; c--)
            {
               var ri = tbl.rows[r].getAttribute('rowid').toString();
               if (ri == sr[c] && ri.endsWith('deleted') == false)
               {
                  self._doRowDelete(tbl.rows[r]);
               }
            }
         }
         tbl.style.borderBottom = '1px solid black';
         self.selectedRowIDs = null;
         selectedRows = new Array();
         if (!self.isHidden(document.getElementById(self.GridID)))
            self.initCellWidth();
         self.colorAltRows();
         self._SerializeServerData();
      }
   };

   this._getRowByRowID = function (rowID)
   {
      var tbl = self.getGridBody();
      var l = tbl.rows.length;
      for (var r = 0; r < l; r++)
      {
         if (tbl.rows[r].getAttribute('rowid').toString() == rowID)
            return tbl.rows[r];
      }
      return null;
   };

   this.initGrid = function (gridID)
   {
      try
      {
         if (this.GridID)
            gridID = this.GridID;
         var grid = document.getElementById(gridID);
         if (!initWidth)
            initWidth = grid.style.width;

         //grid.onselectstart = function() { return false; } // ie
         /*grid.onmousedown = function()
         {
         var grid = document.getElementById(gridID);
         if (grid.getAttribute('editable') && grid.getAttribute('editable').toLowerCase() == 'true')
         return true;
         return false;
         } // mozilla*/

         if (this.isHidden(grid))
            return;
         var check = grid.getAttribute('init');
         if (check)
            return;
         var ht = this.getGridHeader();
         var bt = this.getGridBody();
         var htc = this.getGridHeaderBox();
         var btc = this.getGridBodyBox();
         removeEvent(btc, 'scroll', self.scroller);
         addEvent(btc, 'scroll', self.scroller);
         var i = 0;
         var l = ht.rows[0].cells.length;
         for (i = 0; i < l; i++)
         {
            removeEvent(ht.rows[0].cells[i], 'mousedown', self._processMouseDown);
            removeEvent(ht.rows[0].cells[i], 'mousemove', self._processColumnSizing);
            addEvent(ht.rows[0].cells[i], 'mousedown', self._processMouseDown);
            addEvent(ht.rows[0].cells[i], 'mousemove', self._processColumnSizing);
         }
         var cbs = bt.getElementsByTagName('input');
         l = cbs.length;
         for (i = 0; i < l; i++)
         {
            if (cbs[i].type && cbs[i].type.toLowerCase() == 'checkbox')
            {
               removeEvent(cbs[i], 'keydown', self._editElementKeyPress);
               removeEvent(cbs[i], 'mousedown', self._SerializeServerData);
               removeEvent(cbs[i], 'click', self._setChangedModeFlag);
               addEvent(cbs[i], 'keydown', self._editElementKeyPress);
               addEvent(cbs[i], 'mousedown', self._SerializeServerData);
               addEvent(cbs[i], 'click', self._setChangedModeFlag);
            }
            if (cbs[i].type && (cbs[i].type.toLowerCase() == 'image' || cbs[i].type.toLowerCase() == 'button'))
            {
               cbs[i].onclick = self.__columnButtonClick;
            }
         }

         removeEvent(bt, 'click', self._selectRow);
         removeEvent(bt, 'dblclick', self._dblClick);
         removeEvent(bt, 'click', self._startEdit);
         addEvent(bt, 'click', self._selectRow);
         addEvent(bt, 'dblclick', self._dblClick);
         addEvent(bt, 'click', self._startEdit);

         var grdTbl = getParent(grid, 'table');
         if (grdTbl.style.width.indexOf('%') > -1)
         {
            var wdt = grdTbl.offsetWidth;
            grdTbl.style.width = wdt + 'px';
         }

         btc.style.height = (grid.offsetHeight - ht.offsetHeight) + 'px';
         this.initColumnWidths();
         if (!this.isHidden(document.getElementById(this.GridID)))
            self.initCellWidth();

         if (self.Options)
            this.restoreGridDisplay();

         grid.setAttribute('init', 'true');
         jsWebGrids[gridID] = this;
         this._SerializeServerData();
      } catch (e) { };
   };

   this.initColumnWidths = function ()
   {
      var grid = document.getElementById(self.GridID);
      //grid.style.width = '';
      grid.style.width = initWidth;
      var gridWidth = grid.offsetWidth - 2;
      var sbw = getScrollBarWidth();
      gridWidth -= sbw;
      var ht = this.getGridHeader();
      var bt = this.getGridBody();
      var row = ht.rows[0];
      var l = row.cells.length;
      for (var i = 0; i < l; i++)
      {
         var iWidth = row.cells[i].getAttribute('initwidth');
         if (!iWidth) continue;
         var cellWidth = parseInt(iWidth, 10);
         if (iWidth.indexOf('%') > -1 && row.cells[i].style.display != 'none')
         {
            var newWidth = Math.round(gridWidth * (cellWidth / 100)) - 1;
            self.setWidth(row.cells[i], newWidth);
            row.cells[i].setAttribute('initwidth', '');
         }
         else if (row.cells[i].style.display != 'none')
         {
            if (cellWidth < 10)
               cellWidth = 10;
            row.cells[i].style.width = cellWidth + 'px';
         }
      }
   };

   this.makeColumnsFit = function ()
   {
      if (self.isHidden(document.getElementById(self.GridID)))
      {
         markForColumnFit = true;
         return;
      }
      markForColumnFit = false;
      var grid = document.getElementById(self.GridID);
      //grid.style.width = '';
      grid.style.width = initWidth;
      var gridWidth = grid.offsetWidth - 2;
      var sbw = getScrollBarWidth();
      gridWidth -= sbw;
      var ht = this.getGridHeader();
      var bt = this.getGridBody();
      var row = ht.rows[0];
      var oldWidth = 0;
      var i = 0;
      var l = row.cells.length;
      for (i = 0; i < l; i++)
      {
         if (row.cells[i].style.display != 'none')
            oldWidth += parseInt(row.cells[i].style.width, 10);
      }
      l = row.cells.length;
      for (i = 0; i < l; i++)
      {
         if (row.cells[i].style.display && row.cells[i].style.display == 'none')
            continue;
         var cellWidth = parseInt(row.cells[i].style.width, 10);
         var newWidth = Math.round(gridWidth * (cellWidth / oldWidth)) - 1;
         self.setWidth(row.cells[i], newWidth);
         row.cells[i].setAttribute('initwidth', '');
      }
      if (self.getRowCount() > 0)
         self.initCellWidth();
   };

   this.restoreGridDisplay = function ()
   {
      var i = 0;
      var l = 0;
      var hdr = this.getGridHeader().rows[0];
      var bdy = this.getGridBody().rows;
      if (self.Options.rowClass)
         this.rowClass = self.Options.rowClass;
      if (self.Options.altRowClass)
         this.altRowClass = self.Options.altRowClass;
      if (self.Options.selectedRowClass)
         this.selectedRowClass = self.Options.selectedRowClass;
      if (self.Options.sortASCImage)
         this.sortAscImage = self.Options.sortASCImage;
      if (self.Options.sortDESCImage)
         this.sortDscImage = self.Options.sortDESCImage;
      if (self.Options.sortDirection && self.Options.sortColumn && self.Options.clientSort && self.Options.clientSort.toLowerCase() == 'true')
      {
         var sortCell = this.getGridHeader().rows[0].cells[self.Options.sortColumn];
         var si;
         if (self.Options.sortDirection.toLowerCase() == 'asc')
            si = this.sortAscImage;
         else
            si = this.sortDscImage;
         sortCell.setAttribute('sortDir', self.Options.sortDirection);
         this.getHiddenInput('_SortDirection').value = self.Options.sortDirection + '_' + getCellIndex(sortCell);
         setTimeout(function () { try { self.addImageToCell(sortCell, si); } catch (e) { } }, 100);
      }
      if (self.Options.scrollLeft)
         this.getGridBodyBox().scrollLeft = self.Options.scrollLeft;
      if (self.Options.scrollTop)
         this.getGridBodyBox().scrollTop = self.Options.scrollTop;
      if (self.Options.selectedRows && self.Options.selectedRows.length > 0)
      {
         this.setSelectedRowsByPos(self.Options.selectedRows);
      }
      if (self.Options.columnClickLink && hdr && self.Options.clientSort && self.Options.clientSort.toLowerCase() == 'false')
      {
         l = hdr.cells.length;
         for (i = 0; i < l; i++)
         {
            removeEvent(hdr.cells[i], 'click', self._processServerColumnClick);
            addEvent(hdr.cells[i], 'click', self._processServerColumnClick);
         }
      }
      if (self.Options.columnSorts && hdr && self.Options.clientSort && self.Options.clientSort.toLowerCase() == 'false')
      {
         this.getHiddenInput('_ColumnSorts').value = '';
         l = hdr.cells.length;
         for (i = 0; i < l; i++)
         {
            hdr.cells[i].setAttribute('sortDir', self.Options.columnSorts[i]);
            this.getHiddenInput('_ColumnSorts').value += self.Options.columnSorts[i];
            if (i < hdr.cells.length - 1)
               this.getHiddenInput('_ColumnSorts').value += ',';
            si = '';
            if (self.Options.columnSorts[i].toLowerCase() == 'asc')
               si = this.sortAscImage;
            else if (self.Options.columnSorts[i].toLowerCase() == 'dsc')
               si = this.sortDscImage;
            if (si.length > 0)
               self.addImageToCell(hdr.cells[i], si);
         }
      }
   };

   this._dblClick = function (e)
   {
      var grid = document.getElementById(self.GridID);
      if (grid.getAttribute('editable') && grid.getAttribute('editable').toLowerCase() == 'true')
         return;
      if (!e) e = window.event;
      var row = e.target != null ? e.target : e.srcElement;
      if (row.nodeType == 3) row = row.parentNode; // defeat Safari bug

      if (row.tagName.toLowerCase() != 'tr')
         row = getParent(row, 'tr');
      if (self.rowDoubleClickEvent)
         self.rowDoubleClickEvent(row.getAttribute('rowid').toString());
      eval(self.Options.rowDoubleClickLink);
   };

   this.getRowSelectionType = function ()
   {
      if (self.Options.rowSelection)
         return self.Options.rowSelection;
      else
         return 'Single';
   };

   this.getSelectedRowCount = function ()
   {
      if (this.selectedRowIDs)
         return this.selectedRowIDs.length;
      else
         return 0;
   };

   this.getColumnIndex = function (columnName)
   {
      var cols = this.getGridHeader().rows[0].cells;
      var l = cols.length;
      for (var hc = 0; hc < l; hc++)
      {
         if (columnName.toLowerCase() == cols[hc].getAttribute('columnname').toLowerCase())
            return hc;
      }
      return -1;
   };

   this.getCellValue = function (rowID, colIndex)
   {
      var dt = this.getGridBody();
      var l = dt.rows.length;
      for (var r = 0; r < dt.rows.length; r++)
      {
         var rowIDValue = dt.rows[r].getAttribute('rowid').toString();

         if (rowIDValue.split('_').length > 0)
            rowIDValue = rowIDValue.split('_')[0];

         if (rowIDValue == rowID)
            return self.getCellText(dt.rows[r].cells[colIndex]);
      }
      return '';
   };

   this.getCellValueByColName = function (rowID, colName)
   {
      var colIndex = self.getColumnIndex(colName);
      var dt = this.getGridBody();
      var l = dt.rows.length;
      for (var r = 0; r < l; r++)
      {
         var rowIDValue = dt.rows[r].getAttribute('rowid').toString();

         if (rowIDValue.split('_').length > 0)
            rowIDValue = rowIDValue.split('_')[0];

         if (rowIDValue == rowID)
            return self.getCellText(dt.rows[r].cells[colIndex]);
      }
      return '';
   };

   this.setCellValueByColName = function (rowIndex, colName, value)
   {
      var colIndex = self.getColumnIndex(colName);
      self.setCellValue(rowIndex, colIndex, value);
   };

   this.setCellValue = function (rowIndex, colIndex, value)
   {
      var dt = this.getGridBody();
      var cell = dt.rows[rowIndex].cells[colIndex];
      if (!cell) return;
      if (getParent(cell, 'tr') && getParent(cell, 'tr').getAttribute('rowid').toString().indexOf('_deleted') > -1) return;
      var dataType = this.getColumnDataType(cell);
      if (dataType) dataType = dataType.toLowerCase();
      if (dataType == 'multilinetext')
      {
         cell.innerHTML = value.replace(/\r\n/g, "<br />").replace(/\n/g, "<br />");
      }
      else if (dataType == 'button')
         return;
      else if (dataType == 'dropdownlist')
      {
         var grdID = this.GridID;
         var sel = document.getElementById(grdID + '_col_' + colIndex).cloneNode(true);
         if (!sel) return;
         sel.value = value;
         var si = sel.selectedIndex;
         var val = sel.options[si].value;
         var txt = sel.options[si].text;
         cell.innerHTML = '<nobr>' + txt + '</nobr>';
         cell.setAttribute('value', value);
      }
      else if (dataType == 'boolean')
      {
         value = value.toString();
         inp = cell.getElementsByTagName('input')[0];
         if (value && (value.toLowerCase() == 'true' || value.toLowerCase() == 'on'))
            inp.checked = true;
         else
            inp.checked = false;
      }
      else
      {
         cell.innerHTML = "<nobr>" + value + "</nobr>";
      }
   };

   this.findRowsByCellValue = function (colName, value)
   {
      var rowIDs = new Array();
      var colIndex = self.getColumnIndex(colName);
      var dt = this.getGridBody();
      var l = dt.rows.length;
      for (var r = 0; r < l; r++)
      {
         if (dt.rows[r].style.display != 'none')
         {
            var cellValue = self.getCellText(dt.rows[r].cells[colIndex]);
            if (cellValue.toString().toLowerCase().trim() == value.toString().toLowerCase().trim())
               rowIDs[rowIDs.length] = dt.rows[r].getAttribute('rowid').toString();
         }
      }
      return rowIDs;
   };

   this.findRowsByCellValues = function (nameValues)
   {
      var rowIDs = new Array();
      var dt = this.getGridBody();
      var chk = false;
      var l = dt.rows.length;
      for (var r = 0; r < l; r++)
      {
         if (dt.rows[r].style.display != 'none')
         {
            chk = false;
            var nvl = nameValues.length;
            for (var name in nameValues)
            {
               var colIndex = self.getColumnIndex(name);
               if (colIndex < 0) continue;
               var cellValue = self.getCellText(dt.rows[r].cells[colIndex]);
               if (cellValue.toString().toLowerCase().trim() == nameValues[name].toString().toLowerCase().trim())
                  chk = true;
               else
               {
                  chk = false;
                  break;
               }
            }
            if (chk)
               rowIDs[rowIDs.length] = dt.rows[r].getAttribute('rowid').toString();
         }
      }
      return rowIDs;
   };

   this.getRowCount = function ()
   {
      var cnt = 0;
      var dt = this.getGridBody();
      var l = dt.rows.length;
      if (l > 0)
      {
         if (dt.rows[0].getAttribute('rowid').toString().toLowerCase() != 'dummy')
         {
            for (var r = 0; r < l; r++)
            {
               if (dt.rows[r].style.display != 'none')
                  cnt++;
            }
         }
      }
      return cnt;
   };

   this.getFirstRowID = function ()
   {
      var cnt = 0;
      var dt = this.getGridBody();
      if (dt.rows.length <= 0) return;
      var l = dt.rows.length;
      for (var r = 0; r < l; r++)
      {
         if (dt.rows[r].getAttribute('rowid').toString().toLowerCase() != 'dummy')
         {
            var id = dt.rows[r].getAttribute('rowid').toString();
            if (!id) return '';
            return id;
         }
      }
      return null;
   };

   this.getLastRowID = function ()
   {
      var dt = this.getGridBody();
      var id = '';
      for (var r = dt.rows.length - 1; r >= 0; r--)
      {
         if (dt.rows[r].style.display != 'none' && dt.rows[r].getAttribute('rowid').toString().toLowerCase() != 'dummy')
         {
            id = dt.rows[r].getAttribute('rowid').toString();
            break;
         }
      }
      if (!id) return '';
      return id;
   };

   this.getRowIndex = function (rowID)
   {
      if (!rowID) return null;
      var tbl = self.getGridBody();
      var l = tbl.rows.length;
      for (var r = 0; r < l; r++)
      {
         if (tbl.rows[r].getAttribute('rowid').toString() == rowID)
            return r;
      }
      return null;
   };

   this.getRowID = function (rowIndex)
   {
      if (!rowIndex) return '';
      if (rowIndex < 0) return '';
      var dt = this.getGridBody();
      var l = dt.rows.length;
      if (rowIndex >= l) return '';
      var id = '';
      if (dt.rows[rowIndex].style.display != 'none' && dt.rows[rowIndex].getAttribute('rowid').toString().toLowerCase() != 'dummy')
      {
         id = dt.rows[rowIndex].getAttribute('rowid').toString();
      }
      if (!id) return '';
      return id;
   };

   this.serializeData = function (onlyModified)
   {
      if (typeof onlyModified == 'undefined')
         onlyModified = false;

      var dt = this.getGridBody();
      var cols = this.getGridHeader().rows[0].cells;
      var hasRows = false;
      var ca = '{columns:[';
      var l = cols.length;
      for (var hc = 0; hc < l; hc++)
      {
         ca += '"' + cols[hc].getAttribute('columnname') + '"';
         if (hc < cols.length - 1)
            ca += ', ';
      }
      ca += ']';
      ca += ', rows:[';
      if (dt.rows.length > 0)
      {
         l = dt.rows.length;
         for (var r = 0; r < l; r++)
         {
            if (dt.rows[r].getAttribute('rowid').toString().toLowerCase() == 'dummy')
               continue;
            if (dt.rows[r].getAttribute('rowid').toString().indexOf('_') == -1)
            {
               if (onlyModified)
                  continue;
            }

            hasRows = true;
            ca += this.SerializeRow(dt.rows[r]);
            if (r < dt.rows.length - 1)
               ca += ', ';
         }
      }
      if (onlyModified)
      {
         if (ca.RTrim().Right(1) == ',')
            ca = ca.substring(0, ca.lastIndexOf(','));
      }
      ca += ']';
      ca += '}';
      return ca;
   };


   this._SerializeServerData = function ()
   {
      var dt = this.getGridBody();
      var cols = this.getGridHeader().rows[0].cells;
      var hasRows = false;
      var ca = '{columns:[';
      var l = cols.length;
      for (var hc = 0; hc < l; hc++)
      {
         ca += '"' + cols[hc].getAttribute('columnname') + '"';
         if (hc < cols.length - 1)
            ca += ', ';
      }
      ca += ']';
      ca += ', rows:[';
      if (dt.rows.length > 0)
      {
         l = dt.rows.length;
         for (var r = 0; r < l; r++)
         {
            if (dt.rows[r].getAttribute('rowid').toString().toLowerCase() == 'dummy')
               continue;
            var rowID = dt.rows[r].getAttribute('rowid').toString();
            if (rowID.indexOf('_') == -1)
            {
               var rowString = '{rowID:"' + rowID + '", data:[]}';
               ca += rowString;
            }
            else
            {
               hasRows = true;
               ca += this.SerializeRow(dt.rows[r]);
            }
            if (r < dt.rows.length - 1)
               ca += ', ';
         }
      }
      ca += ']';
      ca += '}';
      this.getHiddenInput('_DataJSON').value = ca;
   };

   this.commitChanges = function ()
   {
      var dt = this.getGridBody();
      if (dt.rows.length > 0)
      {
         for (var r = dt.rows.length - 1; r >= 0; r--)
         {
            var rowID = dt.rows[r].getAttribute('rowid').toString();
            if (rowID)
            {
               var loc = rowID.lastIndexOf('_');
               if (loc > -1)
               {
                  var mod = rowID.substring(loc);
                  if (mod.toLowerCase() == '_added' || mod.toLowerCase() == '_modified')
                  {
                     loc = rowID.indexOf('_');
                     dt.rows[r].setAttribute('rowid', rowID.substring(0, loc));
                  }
                  else if (mod.toLowerCase() == '_deleted')
                  {
                     dt.rows[r].parentNode.removeChild(dt.rows[r]);
                  }
               }
            }
         }
      }
   };

   this.SerializeRow = function (row)
   {
      var val = '';
      var cols = row.cells;
      var rw = '{rowID:"';
      rw += row.getAttribute('rowid').toString();
      rw += '", data:[';
      var l = cols.length;
      for (var hc = 0; hc < l; hc++)
      {
         var dt = this.getColumnDataType(cols[hc]);
         if (dt && dt.toLowerCase() == 'dropdownlist')
            val = cols[hc].getAttribute('value');
         else if (dt && dt.toLowerCase() == 'button')
         {
            var inp = cols[hc].getElementsByTagName('input')[0];
            if (inp.getAttribute('type').toLowerCase() == 'image')
               val = inp.getAttribute('src');
            else
               val = inp.getAttribute('value');
         }
         else if (dt && dt.toLowerCase() == 'html')
         {
            var inp = cols[hc].getElementsByTagName('input')[0];
            if (inp && inp.type == 'text')
               val = inp.value;
            else
               val = '';
         }
         else
            val = self.escapeQuote(self.getCellText(cols[hc]).replace("<br />", /\r\n/g));
         rw += ('"' + val + '"').replace('null', '').replace('&nbsp;', '');
         if (hc < cols.length - 1)
            rw += ', ';
      }
      rw += ']}';
      return rw;
   };

   this.escapeQuote = function (val)
   {
      val = val.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
      var newVal = val.replace(/\&/gi, '%26');
      newVal = newVal.replace(/\"/gi, '&quot;');
      newVal = newVal.replace(/\n/gi, '&nl;');
      newVal = newVal.replace(/\r/gi, '&cr;');
      newVal = newVal.replace(/\t/gi, '&tab;');
      newVal = newVal.replace(/\\/gi, '&bs;');

      newVal = newVal.replace(/\&quot\;/gi, '\\"');
      newVal = newVal.replace(/\&nl\;/gi, '\\n');
      newVal = newVal.replace(/\&cr\;/gi, '\\r');
      newVal = newVal.replace(/\&tab\;/gi, '\\t');
      newVal = newVal.replace(/\&bs\;/gi, '\\\\');
      newVal = newVal.replace(/\%26/gi, '&');

      return newVal;
   };

   this._processServerColumnClick = function (e)
   {
      if (!e) e = window.event;
      var cell = e.target != null ? e.target : e.srcElement;
      if (cell.nodeType == 3) cell = cell.parentNode; // defeat Safari bug

      if (cell.tagName.toLowerCase() != 'td')
         cell = getParent(cell, 'td');
      if (cell.style.cursor == "w-resize") return;
      var hdr = self.getGridHeader().rows[0];
      cell = getParent(cell, 'td');
      self.getHiddenInput('_ColumnSorts').value = '';
      var l = hdr.cells.length;
      for (var i = 0; i < l; i++)
      {
         self.getHiddenInput('_ColumnSorts').value += hdr.cells[i].getAttribute('sortDir');
         if (i < hdr.cells.length - 1)
            self.getHiddenInput('_ColumnSorts').value += ',';
      }
      var ssd = self.Options.columnClickLink;
      ssd = ssd.replace('{0}', getCellIndex(cell));
      eval(ssd);
   };

   this._processColumnSizing = function (e)
   {
      if (!e) e = window.event;
      var cell = e.target != null ? e.target : e.srcElement;
      if (cell.nodeType == 3) cell = cell.parentNode; // defeat Safari bug

      var x = e.clientX;
      var y = e.clientY;
      if (!cell)
         cell = curCell;
      if (cell.tagName.toLowerCase() != 'td')
         cell = getParent(cell, 'td');
      if (curCell && self.md == 1)
         cell = curCell;
      if (!cell) return;
      self.os = self.getGridHeaderBox().scrollLeft;

      var cx = (x - self.findLeftByObject(cell)) + self.os;
      var cy = y - (self.findTopByObject(cell) - document.documentElement.scrollTop);
      if (self.md == 0 && cell.getAttribute('sizable') && cell.getAttribute('sizable').toLowerCase() == 'true')
      {
         var wdth = cell.offsetWidth;
         var hght = cell.offsetHeight;
         if (cx > (wdth - 5) && cx < wdth && cy > 0 && cy < hght)
            cell.style.cursor = "w-resize";
         else
            cell.style.cursor = 'pointer';
      }
      else if (self.md == 1)
      {
         if (cx > 20)
         {
            curCell.style.width = cx + 'px';
            var grid = document.getElementById(self.GridID);
            //grid.style.width = '';
            grid.style.width = initWidth;
         }
      }
   };

   this._processMouseUp = function (e)
   {
      self.os = 0;
      self.md = 0;
      removeEvent(document.documentElement, 'mousemove', self._processColumnSizing);
      removeEvent(document.documentElement, 'mouseup', self._processMouseUp);
      if (!self.isHidden(document.getElementById(self.GridID)))
         self.initCellWidth();
      setTimeout(function () { self.scroller(); }, 1);
      curCell = null;
   };

   this._processMouseDown = function (e)
   {
      if (!e) e = window.event;
      var cell = e.target != null ? e.target : e.srcElement;
      if (cell.nodeType == 3) cell = cell.parentNode; // defeat Safari bug

      if (cell.tagName.toLowerCase() != 'td')
         cell = getParent(cell, 'td');
      curCell = cell;
      if (cell.style.cursor == 'w-resize')
      {
         self.md = 1;
         removeEvent(document.documentElement, 'mousemove', self._processColumnSizing);
         removeEvent(document.documentElement, 'mouseup', self._processMouseUp);
         addEvent(document.documentElement, 'mousemove', self._processColumnSizing);
         addEvent(document.documentElement, 'mouseup', self._processMouseUp);
      }
      else
      {
         this.md = 0;
         if (self.columnClickEvent)
            self.columnClickEvent(getCellIndex(cell), cell.getAttribute('columnname'), cell.getAttribute('sortDir'));

         if (self.Options.clientSort && self.Options.clientSort.toLowerCase() == 'true')
         {
            self.sortColumn(cell);
            if (self.selectedRowIDs && self.selectedRowIDs.length > 0)
               self.setSelectedRows(self.selectedRowIDs);
         }
      }
      return false;
   };

   this.__columnButtonClick = function (e)
   {
      if (!e) e = window.event;
      var btn = e.target != null ? e.target : e.srcElement;
      if (btn.nodeType == 3) btn = btn.parentNode; // defeat Safari bug
      var cell = getParent(btn, 'td');
      var row = getParent(btn, 'tr');
      var val;
      if (btn.getAttribute('type').toLowerCase() == 'image')
         val = btn.getAttribute('src');
      else
         val = btn.getAttribute('value');
      var cellIndex = getCellIndex(cell);
      var hr = self.getGridHeader().rows[0];
      var evt = hr.cells[cellIndex].getAttribute('buttonclickevent');
      evt = eval(evt);
      evt(row.getAttribute('rowid').toString(), cellIndex, val);
      eval(evt);
      return false;
   };

   this.clearAllColumnSorts = function ()
   {
      var r = this.getGridHeader().rows[0];
      var l = r.cells.length;
      for (var i = 0; i < l; i++)
      {
         self.removeImageFromCell(r.cells[i]);
         r.cells[i].setAttribute('sortDir', '');
      }
      self.sortedColumns = new Array();
   };

   this.sortColumn = function (cell, direction)
   {
      var r = this.getGridHeader().rows[0];
      var l = r.cells.length;
      for (var i = 0; i < l; i++)
      {
         if (r.cells[i] != cell)
         {
            self.removeImageFromCell(r.cells[i]);
            r.cells[i].setAttribute('sortDir', '');
         }
      }
      sortMethod = cell.getAttribute('datatype');
      var dir = cell.getAttribute('sortDir');
      if (direction)
      {
         dir = (direction && direction.toLowerCase() == 'asc') ? 'dsc' : 'asc';
      }
      if (dir && dir.toLowerCase() == 'asc')
      {
         cell.setAttribute('sortDir', 'DSC');
         this.sortTable(getCellIndex(cell), 'dsc');
         this.getHiddenInput('_SortDirection').value = 'DSC_' + getCellIndex(cell);
         self.addImageToCell(cell, this.sortDscImage);
      }
      else
      {
         cell.setAttribute('sortDir', 'ASC');
         this.sortTable(getCellIndex(cell), 'asc');
         this.getHiddenInput('_SortDirection').value = 'ASC_' + getCellIndex(cell);
         self.addImageToCell(cell, this.sortAscImage);
      }
      cell.setAttribute('isSorted', 'true');

      if (!this.isHidden(document.getElementById(this.GridID)))
         this.initCellWidth();
      setTimeout(function () { self.scroller(); }, 1);
      this._SerializeServerData();
      self.sortedColumns = self.buildSortedColumnList(cell.getAttribute('columnname'), cell.getAttribute('sortDir'));
      self.resetSortedColumns();
   };

   this.sortTable = function (intColx, sortDirx)
   {
      var ts = new TableSorter(this.getGridBody().id);
      var desc;
      if (sortDirx && sortDirx.toLowerCase() == 'asc')
         desc = false;
      else
         desc = true;
      ts.sortTable(intColx, sortMethod, desc);
      this.colorAltRows();
   };

   this.setColumnAsSorted = function (colName, direction)
   {
      var cell;
      var r = this.getGridHeader().rows[0];
      var l = r.cells.length;
      for (var i = 0; i < l; i++)
      {
         if (r.cells[i].getAttribute('columnname').toLowerCase() == colName.toLowerCase())
         {
            self.removeImageFromCell(r.cells[i]);
            r.cells[i].setAttribute('sortDir', '');
            r.cells[i].setAttribute('isSorted', 'false');
            cell = r.cells[i];
            break;
         }
      }
      if (!cell) return;
      var dir = direction;
      if (dir && dir.toLowerCase() == 'dsc')
      {
         cell.setAttribute('sortDir', 'DSC');
         this.getHiddenInput('_SortDirection').value = 'DSC_' + getCellIndex(cell);
         self.addImageToCell(cell, this.sortDscImage);
      }
      else
      {
         cell.setAttribute('sortDir', 'ASC');
         this.getHiddenInput('_SortDirection').value = 'ASC_' + getCellIndex(cell);
         self.addImageToCell(cell, this.sortAscImage);
      }
      cell.setAttribute('isSorted', 'true');

      if (!this.isHidden(document.getElementById(this.GridID)))
         this.initCellWidth();
      setTimeout(function () { self.scroller(); }, 1);
      self.sortedColumns = self.buildSortedColumnList(cell.getAttribute('columnname'), cell.getAttribute('sortDir'));
      self.resetSortedColumns();
   };

   this.colorAltRows = function ()
   {
      var arrRows = this.getGridBody().rows;
      var ind = 0;
      var l = arrRows.length;
      for (i = 0; i < l; i++)
      {
         if (arrRows[i].getAttribute('rowid').toString().indexOf('_deleted') < 0)
         {
            arrRows[i].className = (ind % 2 == 0) ? this.rowClass : this.altRowClass;
            ind++;
         }
      }
   };

   this.findLeftByObject = function (obj)
   {
      var curleft = 0;
      if (obj.offsetParent)
      {
         do
         {
            curleft += obj.offsetLeft;
            obj = obj.offsetParent
         } while (obj);
      }
      return curleft;
   };

   this.findTopByObject = function (obj)
   {
      var curtop = 0;
      if (obj.offsetParent)
      {
         do
         {
            curtop += obj.offsetTop;
            obj = obj.offsetParent
         } while (obj);
      }
      return curtop;
   };

   this._getBaseID = function ()
   {
      var id = '';
      var i = self.GridID.lastIndexOf('_');
      if (i < 0)
         id = self.GridID;
      else
         id = self.GridID.substring(i + 1);
      return id;
   };

   this.initCellWidth = function ()
   {
      var colWidths = '';
      var hdr = this.getGridHeader();
      var bdy = this.getGridBody();
      var hb = this.getGridHeaderBox();
      var bb = this.getGridBodyBox();
      var sbw = getScrollBarWidth();
      var rc = 0, delCount = 0;
      var grid = document.getElementById(self.GridID);
      var gridWidth = grid.offsetWidth;
      //grid.style.width = '';
      grid.style.width = initWidth;
      bb.style.height = (grid.offsetHeight - hb.offsetHeight) + 'px';
      bb.style.width = '100%';
      if (bb.offsetHeight > bdy.offsetHeight)
         sbw = 0;
      hb.style.width = (bb.offsetWidth - sbw) + 'px';
      //grid.style.width = '';
      grid.style.width = initWidth;
      if (hdr.rows.length <= 0)
         return;
      var srt = 0;
      var end = hdr.rows[0].cells.length;
      if (bdy.rows.length > 0 && bdy.rows[0].cells.length > 0)
      {
         for (var c = srt; c < end; c++)
         {
            var wid = 0;
            if (bdy.rows[0].cells[c] && bdy.rows[0].cells[c].style && bdy.rows[0].cells[c].style.width && hdr.rows[0].cells[c].style.width == bdy.rows[0].cells[c].style.width)
            {
               wid = hdr.rows[0].cells[c].style.width;
               if (!wid || wid == NaN) wid = '0';
               colWidths += parseInt(wid) + '|';
               continue;
            }
            var w = hdr.rows[0].cells[c].style.width;
            wid = hdr.rows[0].cells[c].style.width;
            if (!w || w == NaN) w = '0';
            colWidths += parseInt(w) + '|';
            if (hdr.rows[0].cells[c].style.display == 'none') continue;
            var l = bdy.rows.length;
            for (var r = 0; r < l; r++)
            {
               if (bdy.rows[r].cells[c])
                  bdy.rows[r].cells[c].style.width = w;
            }
         }
      }
      this.getHiddenInput('_ColumnWidths').value = colWidths;
      //grid.style.width = '';
      grid.style.width = initWidth;
   };

   this.addDummyRow = function ()
   {
      var grdHeader = this.getGridHeader();
      var grdBody = this.getGridBody();
      var tbody = grdBody.getElementsByTagName('tbody')[0];
      var row = document.createElement('tr');
      row.setAttribute('rowid', 'Dummy')
      var l = grdHeader.rows[0].cells.length;
      for (var i = 0; i < l; i++)
      {
         cell = document.createElement('td');
         cell.height = '1px';
         if (grdHeader.rows[0].cells[i].style.display && grdHeader.rows[0].cells[i].style.display == 'none')
            cell.style.display = 'none';
         cell.style.width = grdHeader.rows[0].cells[i].style.width;
         row.appendChild(cell);
      }
      if (grdBody.rows.length > 0)
         tbody.insertBefore(row, tbody.getElementsByTagName('tr')[0]);
      else
         tbody.appendChild(row);
      grdBody.style.borderBottom = '';
      return false;
   };

   this.clearGridRows = function ()
   {
      bWorking = false;
      var grdHeader = this.getGridHeader();
      var bb = this.getGridBodyBox();
      try
      {
         bb.scrollLeft = 0;
         bb.scrollTop = 0;
      } catch (e) { }
      if (grdHeader)
      {
         if (grdHeader.rows.length > 0)
         {
            this._SerializeServerData();
            var tblBody = self.getGridBody();
            var oldBody = tblBody.getElementsByTagName('tbody')[0];
            var newBody = document.createElement('tbody');
            tblBody.replaceChild(newBody, oldBody);
            self.addDummyRow();
            selectedRows = new Array();
            self.getHiddenInput('_SelectedRows').value = '';
            self.selectedRowIDs = null;
            if (!this.isHidden(document.getElementById(this.GridID)))
               this.initCellWidth();
            return false;
         }
      }
   };

   function getScrollBarWidth()
   {
      var inner = document.createElement('p');
      inner.style.width = '100%';
      inner.style.height = '200px';

      var outer = document.createElement('div');
      outer.style.position = 'absolute';
      outer.style.top = '0px';
      outer.style.left = '0px';
      outer.style.visibility = 'hidden';
      outer.style.width = '200px';
      outer.style.height = '150px';
      outer.style.overflow = 'hidden';
      outer.appendChild(inner);

      document.body.appendChild(outer);
      var w1 = inner.offsetWidth;
      outer.style.overflow = 'scroll';
      var w2 = inner.offsetWidth;
      if (w1 == w2) w2 = outer.clientWidth;
      document.body.removeChild(outer);

      return (w1 - w2);
   };

   this.scroller = function ()
   {
      self.getGridHeaderBox().scrollLeft = self.getGridBodyBox().scrollLeft;

      var grd = document.getElementById(self.GridID);
      var inputs = grd.getElementsByTagName('input');
      var l = inputs.length;
      for (var i = 0; i < l; i++)
      {
         var iid = inputs[i].id;
         if (iid.toLowerCase().indexOf('_scrollleft') >= 0)
            document.getElementById(iid).value = self.getGridBodyBox().scrollLeft;
         else if (iid.toLowerCase().indexOf('_scrolltop') >= 0)
            document.getElementById(iid).value = self.getGridBodyBox().scrollTop;
      }
   };

   this.clearSelectedRows = function ()
   {
      for (var r = 0, l = selectedRows.length; r < l; r++)
      {
         if (selectedRows[r].getAttribute('origCL'))
         {
            selectedRows[r].className = selectedRows[r].getAttribute('origCL');
            selectedRows[r].setAttribute('origCL', '');
         }
      }
      selectedRows = new Array();
      self.selectedRowIDs = self.getSelectedRows();
      self.getHiddenInput('_SelectedRows').value = self.selectedRowIDs.join(',');
   };

   this._selectRow = function (e)
   {
      if (!e) e = window.event;
      var cell = e.target != null ? e.target : e.srcElement;
      if (cell.nodeType == 3) cell = cell.parentNode; // defeat Safari bug

      if (cell.tagName.toLowerCase() != 'td')
         cell = getParent(cell, 'td');
      self.selectRowByCell(cell, e);
   };

   this.selectRowByCell = function (cell, e)
   {
      if (self.getRowSelectionType().toLowerCase() == 'none') return;
      if (self.getRowSelectionType().toLowerCase() != 'single')
      {
         if (e)
         {
            if (e.shiftKey)
            {
               self.selectMultipleRows(cell, 'range');
               return;
            }
            else if (e.ctrlKey)
            {
               self.selectMultipleRows(cell, 'add');
               return;
            }
         }
      }

      var tbl = self.getGridBody();

      if (getParent(cell, 'table') != tbl)
         return;

      for (var r = 0, l = selectedRows.length; r < l; r++)
      {
         if (selectedRows[r].getAttribute('origCL'))
         {
            selectedRows[r].className = selectedRows[r].getAttribute('origCL');
            selectedRows[r].setAttribute('origCL', '');
         }
      }
      if (cell.tagName.toLowerCase() != 'tr')
         cell = getParent(cell, 'tr');
      self.currentlySelectedRow = cell;
      selectedRows = new Array();
      selectedRows[selectedRows.length] = cell;
      cell.setAttribute('origCL', cell.className);
      cell.className = self.selectedRowClass;
      self.selectedRowIDs = self.getSelectedRows();
      self.getHiddenInput('_SelectedRows').value = self.selectedRowIDs.join(',');
      if (self.rowClickEvent)
         self.rowClickEvent(self.selectedRowIDs);
   };

   this.selectMultipleRows = function (elem, type)
   {
      var grid = document.getElementById(self.GridID);
      if (grid.getAttribute('editable') && grid.getAttribute('editable').toLowerCase() == 'true')
         return;
      var curIndex = this.currentlySelectedRow.rowIndex;
      if (!curIndex) curIndex = 0;
      if (elem.tagName.toLowerCase() != 'tr')
         elem = getParent(elem, 'tr');
      var strt;
      var end;
      this.currentlySelectedRow = elem;
      if (type && type.toLowerCase() == 'range')
      {
         if (elem.rowIndex > curIndex)
         {
            strt = curIndex;
            end = elem.rowIndex;
         }
         else
         {
            strt = elem.rowIndex;
            end = curIndex;
         }
         var tbl = this.getGridBody();
         for (var i = strt; i <= end; i++)
         {
            if (tbl.rows[i].className && tbl.rows[i].className != this.selectedRowClass)
            {
               var ri = tbl.rows[i].getAttribute('rowid').toString();
               if (!ri.endsWith('_deleted'))
               {
                  tbl.rows[i].setAttribute('origCL', tbl.rows[i].className);
                  tbl.rows[i].className = this.selectedRowClass;
                  selectedRows[selectedRows.length] = tbl.rows[i];
               }
            }
         }
      }
      else
      {
         if (elem.getAttribute('origCL') && elem.getAttribute('origCL') != elem.className)
         {
            elem.className = elem.getAttribute('origCL');
            elem.setAttribute('origCL', '');
         }
         else
         {
            elem.setAttribute('origCL', elem.className);
            elem.className = this.selectedRowClass;
            selectedRows[selectedRows.length] = elem;
         }
      }

      this.selectedRowIDs = this.getSelectedRows();
      this.getHiddenInput('_SelectedRows').value = this.selectedRowIDs.join(',');
      if (self.rowClickEvent)
         self.rowClickEvent(this.selectedRowIDs);
   };


   this.selectRowByIndex = function (index)
   {
      var tbl = this.getGridBody();
      this.selectRowByCell(tbl.rows[index], null);
   };

   this.selectRowByRowID = function (rowID)
   {
      var elem = null;
      var tbl = this.getGridBody();
      var l = tbl.rows.length;
      for (var r = 0; r < l; r++)
      {
         if (tbl.rows[r].getAttribute('rowid').toString())
         {
            if (rowID == tbl.rows[r].getAttribute('rowid').toString())
            {
               elem = tbl.rows[r];
               break;
            }
         }
      }
      if (!elem) return;
      if (elem.tagName.toLowerCase() != 'tr')
         elem = getParent(elem, 'tr');
      this.selectRowByCell(elem, null);
   };

   this.getSelectedRows = function ()
   {
      var rowArray = new Array();
      var ind = 0;
      var tbl = this.getGridBody();
      for (var r = 0, l = selectedRows.length; r < l; r++)
      {
         if (selectedRows[r].className == this.selectedRowClass && (!selectedRows[r].getAttribute('rowid').toString().endsWith('_deleted')))
         {
            rowArray[ind] = selectedRows[r].getAttribute('rowid').toString();
            ind++;
         }
      }
      return rowArray;
   };

   this.getSelectedRowIndex = function ()
   {
      var rowArray = new Array();
      var ind = 0;
      var tbl = this.getGridBody();
      if (selectedRows.length > 0)
         return selectedRows[0].rowIndex;
      return '';
   };


   this.setSelectedRows = function (rowArray)
   {
      if (this.isHidden(document.getElementById(this.GridID)))
         return;
      var l = rowArray.length;
      for (var r = 0; r < l; r++)
      {
         if (!rowArray[r].endsWith('_deleted'))
            this.selectRowByRowID(rowArray[r]);
      }
      return rowArray;
   };

   this.setSelectedRowsByPos = function (rowIndexArray)
   {
      var tbl = this.getGridBody();
      var l = rowIndexArray.length;
      for (var r = 0; r < l; r++)
      {
         if (r == 0)
            this.selectRowByCell(tbl.rows[rowIndexArray[r]], null);
         else
            this.selectMultipleRows(tbl.rows[rowIndexArray[r]], 'add');
      }
   };

   this.sizeColumn = function (cellIndex, width)
   {
      var tbl = this.getGridHeader();
      var w = width;
      self.setWidth(tbl.rows[0].cells[cellIndex], width);
      if (!this.isHidden(document.getElementById(this.GridID)))
         this.initCellWidth();
   };

   this.getHiddenInput = function (backID)
   {
      var grd = document.getElementById(this.GridID);
      var inputs = grd.getElementsByTagName('input');
      var l = inputs.length;
      for (var i = 0; i < l; i++)
      {
         var iid = inputs[i].id;
         if (iid.toLowerCase().indexOf(backID.toLowerCase()) >= 0)
            return inputs[i];
      }
      return null;
   };

   this.getGridHeader = function ()
   {
      var elem = document.getElementById(this.GridID);
      var tbl = elem.getElementsByTagName('table')[0];
      return tbl;
   };

   this.getGridBody = function ()
   {
      var elem = document.getElementById(this.GridID);
      var tbl = elem.getElementsByTagName('table')[1];
      return tbl;
   };

   this.getGridHeaderBox = function ()
   {
      var elem = document.getElementById(this.GridID);
      var tbl = elem.getElementsByTagName('table')[0];
      return getParent(tbl, 'div');
   };

   this.getGridBodyBox = function ()
   {
      var elem = document.getElementById(this.GridID);
      var tbl = elem.getElementsByTagName('table')[1];
      return getParent(tbl, 'div');
   };

   this.isHidden = function (elem)
   {
      var cnt = 0;
      while (true)
      {
         cnt++;
         var test = elem.style.display;
         if (!test)
            test = 'zzzzzz';
         if (test.toLowerCase() == 'none')
            return true;
         test = elem.style.visibility;
         if (!test)
            test = 'zzzzzz';
         if (test.toLowerCase() == 'hidden')
            return true;
         test = elem.tagName;
         if (!test)
            test = 'zzzzzz';
         if (test.toLowerCase() == 'body')
            break;
         if (cnt > 1000)
            break;
         elem = elem.parentNode;
      }
      return false;
   };

   this.setEditableFlag = function (trueFalse)
   {
      if (typeof trueFalse == 'undefined')
         trueFalse = false;
      var i;
      var grid = document.getElementById(this.GridID);
      grid.setAttribute('editable', trueFalse.toString());
      var inputs = grid.getElementsByTagName('input');

      if (trueFalse)
         grid.onselectstart = function () { return true; } // ie
      else
         grid.onselectstart = function () { return false; } // ie


      var l = inputs.length;
      for (i = 0; i < l; i++)
      {
         if (inputs[i].type && inputs[i].type.toLowerCase() == 'checkbox')
         {
            if (trueFalse)
            {
               if (inputs[i].disabled)
                  inputs[i].disabled = !trueFalse;
            }
            else
            {
               if (!inputs[i].disabled)
                  inputs[i].disabled = !trueFalse;
            }
         }
      }

      return false;
   };

   this.addNewRow = function ()
   {
      var grid = document.getElementById(this.GridID);
      if (grid.getAttribute('editable').toLowerCase() == 'false')
         return;
      var grdHeader = this.getGridHeader();
      var grdBody = this.getGridBody();
      var chkBox = null, row = null, cell = null, resetWidth = false;

      if (grdBody.rows.length > 0)
      {
         if (grdBody.rows[0].getAttribute('rowid') && grdBody.rows[0].getAttribute('rowid').toString().toLowerCase() == 'dummy')
         {
            grdBody.getElementsByTagName('tbody')[0].removeChild(grdBody.getElementsByTagName('tbody')[0].getElementsByTagName('tr')[0]);
            resetWidth = true;
         }
      }

      if (grdBody)
      {
         row = document.createElement('tr');
         row.className = ((grdBody.rows.length % 2) == 0) ? 'normalRow' : 'altRow';
         row.setAttribute('rowid', grdBody.rows.length.toString() + '_added');
      }

      if (grdHeader)
      {
         if (grdHeader.rows.length > 0)
         {
            var l = grdHeader.rows[0].cells.length;
            for (var i = 0; i < l; i++)
            {
               cell = document.createElement('td');
               if (grdHeader.rows[0].cells[i].getAttribute('datatype') && grdHeader.rows[0].cells[i].getAttribute('datatype').toLowerCase() == 'boolean')
               {
                  cell.className = 'bodyCell cellCenter';
                  chkBox = document.createElement('input');
                  chkBox.type = 'checkbox';
                  addEvent(chkBox, 'click', self._setChangedModeFlag);
                  addEvent(chkBox, 'mousedown', self._SerializeServerData);
                  cell.appendChild(chkBox);
               }
               else
               {
                  cell.className = 'bodyCell';
                  cell.height = '20px';
               }
               if (grdHeader.rows[0].cells[i].style.display && grdHeader.rows[0].cells[i].style.display == 'none')
                  cell.style.display = 'none';
               cell.style.width = grdHeader.rows[0].cells[i].style.width;
               row.appendChild(cell);
            }
         }
      }
      grdBody.getElementsByTagName('tbody')[0].appendChild(row);
      if (!this.isHidden(document.getElementById(this.GridID)))
      {
         if (resetWidth)
            this.initCellWidth();
         getParent(row, 'div').scrollTop = row.offsetTop;
         self.selectRowByIndex(grdBody.rows.length - 1);
      }
      grdBody.style.borderBottom = '1px solid black';
      self._SerializeServerData();
      if (self.rowChangedEvent)
         self.rowChangedEvent(row.getAttribute('rowid').toString());
   };

   this.popGridFromJson = function (jsonString, async, processAfter, makeColumnsFit)
   {
      if (typeof processAfter != 'undefined')
         runAfter = processAfter;
      if (typeof makeColumnsFit == 'undefined')
         makeColumnsFit = false;
      if (typeof async == 'undefined' || !async)
         self.__popGridFromJsonSync(jsonString, makeColumnsFit);
      else
         self.__popGridFromJsonAsync(jsonString, makeColumnsFit);
   };

   var runAfter;
   var bWorking = false;
   var jsonEval;
   var i = 0, resetWidth = null;
   var trueCheckBoxes = new Array();
   this.__popGridFromJsonAsync = function (jsonString, makeColumnsFit, start)
   {
      if (typeof start == 'undefined')
         start = false;
      if (typeof makeColumnsFit == 'undefined')
         makeColumnsFit = false;
      var row = null, cell = null, noBreak = null;
      var grdHeader = this.getGridHeader();
      var grdBody = this.getGridBody();
      var deletedRows = new Array();
      if (!start)
      {
         if (bWorking) return;
         i = 0;
         jsonEval = (jsonString != '') ? eval('(' + jsonString + ')') : null;
         if (jsonEval && jsonEval.rows.length > 0)
         {
            //            self.clearGridRows();
            if (jsonEval.rows.length == 1 && jsonEval.rows[0].rowID.toLowerCase() == 'dummy')
               return false;
            if (grdBody.rows.length > 0)
            {
               if (grdBody.rows[0].getAttribute('rowid') && grdBody.rows[0].getAttribute('rowid').toString().toLowerCase() == 'dummy')
               {
                  grdBody.getElementsByTagName('tbody')[0].removeChild(grdBody.getElementsByTagName('tbody')[0].getElementsByTagName('tr')[0]);
                  resetWidth = true;
               }
            }
         }
         bWorking = true;
      }

      if (!bWorking) return;
      if (grdBody.getElementsByTagName('tbody')[0])
         grdBody = grdBody.getElementsByTagName('tbody')[0];

      var count = 0;
      var l = jsonEval.rows.length;
      for (; i < l; i++)
      {
         if (count >= 25)
            break;
         if (jsonEval.rows[i].rowID.split('_').length > 0)
         {
            if (jsonEval.rows[i].rowID.endsWith('_deleted'))
            {
               deletedRows[deletedRows.length] = jsonEval.rows[i];
               continue;
            }
         }
         //Skip dummy row
         if (jsonEval.rows[i].rowID.toLowerCase() == 'dummy')
            continue;
         trueCheckBoxes = new Array();
         var newRow = this._newRow(jsonEval.rows[i], i)
         grdBody.appendChild(newRow);
         for (c = 0, tl = trueCheckBoxes.length; c < tl; c++)
            trueCheckBoxes[c].checked = true;
         count++;
      }

      if (i < l)
         setTimeout(function ()
         {
            if (makeColumnsFit && i <= 25)
               self.makeColumnsFit();
            self.__popGridFromJsonAsync('', makeColumnsFit, true);
         }, 0);
      else
      {
         //Add dummy row in case of no rows
         if (grdBody.rows.length == 0)
            this.addDummyRow();
         //Add deleted row at the bottom
         l = deletedRows.length;
         for (i = 0; i < l; i++)
         {
            var newRow = this._newRow(deletedRows[i])
            newRow.style.display = 'none';
            grdBody.appendChild(newRow);
         }
         //Set the bottom border
         if (l > 0)
            grdBody.parentNode.style.borderBottom = '1px solid black';
         self.initGrid(this.GridID);
         if (!this.isHidden(document.getElementById(this.GridID)))
         {
            if (resetWidth)
               this.initCellWidth();
         }
         bWorking = false;
         trueCheckBoxes = new Array();
         if (makeColumnsFit)
            self.makeColumnsFit();
         self._SerializeServerData();
         if (typeof runAfter != 'undefined')
            try { runAfter(); runAfter = function () { } } catch (e) { }
      }
   };

   this.__popGridFromJsonSync = function (jsonString, makeColumnsFit)
   {
      if (typeof makeColumnsFit == 'undefined')
         makeColumnsFit = false;
      var row = null, cell = null, noBreak = null, resetWidth = null;
      jsonEval = (jsonString != '') ? eval('(' + jsonString + ')') : null;
      var grdHeader = this.getGridHeader();
      var grdBody = this.getGridBody();
      trueCheckBoxes = new Array();
      var deletedRows = new Array();
      i = 0;
      var newBody = document.createElement('tbody');
      if (jsonEval && jsonEval.rows.length > 0)
      {
         //         self.clearGridRows();
         if (jsonEval.rows.length == 1 && jsonEval.rows[0].rowID.toLowerCase() == 'dummy')
            return false;
         if (grdBody.rows.length > 0)
         {
            if (grdBody.rows[0].getAttribute('rowid') && grdBody.rows[0].getAttribute('rowid').toString().toLowerCase() == 'dummy')
            {
               grdBody.getElementsByTagName('tbody')[0].removeChild(grdBody.getElementsByTagName('tbody')[0].getElementsByTagName('tr')[0]);
               resetWidth = true;
            }
         }
         var l = jsonEval.rows.length;
         for (i = 0; i < l; i++)
         {
            if (jsonEval.rows[i].rowID.split('_').length > 0)
            {
               if (jsonEval.rows[i].rowID.endsWith('_deleted'))
               {
                  deletedRows[deletedRows.length] = jsonEval.rows[i];
                  continue;
               }
            }
            //Skip dummy row
            if (jsonEval.rows[i].rowID.toLowerCase() == 'dummy')
               continue;

            var newRow = this._newRow(jsonEval.rows[i], i)
            newBody.appendChild(newRow);
         }
         //Add dummy row in case of no rows
         if (newBody.childNodes.length == 0)
            this.addDummyRow();
         //Add deleted row at the bottom
         l = deletedRows.length;
         for (i = 0; i < l; i++)
         {
            var newRow = this._newRow(deletedRows[i])
            newRow.style.display = 'none';
            newBody.appendChild(newRow);
         }
         //Set the bottom border
         if (l > 0)
            grdBody.parentNode.style.borderBottom = '1px solid black';

         grdBody.getElementsByTagName('tbody')[0].parentNode.replaceChild(newBody, grdBody.getElementsByTagName('tbody')[0]);

         l = trueCheckBoxes.length;
         for (i = 0; i < l; i++)
            trueCheckBoxes[i].checked = true;
         self.initGrid(this.GridID);
         if (!this.isHidden(document.getElementById(this.GridID)))
         {
            if (resetWidth)
               this.initCellWidth();
         }
      }
      if (makeColumnsFit)
         self.makeColumnsFit();
      self._SerializeServerData();
      trueCheckBoxes = new Array();
      if (typeof runAfter != 'undefined')
         try { runAfter(); runAfter = function () { } } catch (e) { }
      return false;
   };

   this.insertRow = function (jsonString, index)
   {
      jsonEval = null;
      if (typeof jsonString == 'string')
         jsonEval = (jsonString != '') ? eval('(' + jsonString + ')') : null;
      else
         jsonEval = jsonString;
      if (!jsonEval) return;
      if (typeof jsonEval.rows != 'undefined' && jsonEval.rows != null && jsonEval.rows.length > 0)
         jsonEval = jsonEval.rows[0];
      if (typeof jsonEval.rowID == 'undefined' || jsonEval.rowID == null) return;

      var grdBody = self.getGridBody();
      var tbody, newRow, flags = '', lastIndex = 0;
      if (grdBody.getElementsByTagName('tbody')[0])
         tbody = grdBody.getElementsByTagName('tbody')[0];
      else
         tbody = grdBody;

      var lri = self.getLastRowID();
      if ((lri != null && lri != '') || lri > 0)
         lastIndex = self.getRowIndex(lri);
      if (jsonEval.rowID.indexOf('_') >= 0)
      {
         var idx = jsonEval.rowID.indexOf('_');
         flags = jsonEval.rowID.substr(idx);
      }
      jsonEval.rowID = (grdBody.rows.length + 1) + flags;

      if (jsonEval.rowID.toLowerCase().indexOf('_deleted') >= 0)
      {
         newRow = self._newRow(jsonEval)
         newRow.style.display = 'none';
         tbody.appendChild(newRow);
         return;
      }

      if (grdBody.rows.length > 0)
      {
         if (grdBody.rows[0].getAttribute('rowid') && grdBody.rows[0].getAttribute('rowid').toString().toLowerCase() == 'dummy')
         {
            grdBody.getElementsByTagName('tbody')[0].removeChild(grdBody.getElementsByTagName('tbody')[0].getElementsByTagName('tr')[0]);
            index--;
         }
      }

      if (index > lastIndex && index > grdBody.rows.length - 1)
      {
         newRow = self._newRow(jsonEval)
         tbody.appendChild(newRow);
      }
      else
      {
         newRow = self._newRow(jsonEval)
         tbody.insertBefore(newRow, grdBody.rows[index]);
      }
      self.colorAltRows();
      self._SerializeServerData();
      trueCheckBoxes = new Array();
   };

   this._newRow = function (newRow, rowIndex)
   {
      if (typeof rowIndex == 'undefined')
         rowIndex = 0;

      var row = null, cell = null, noBreak = null, resetWidth = null;
      var grdHeader = this.getGridHeader();
      var grdBody = this.getGridBody();
      row = document.createElement('tr');
      var rowCount = grdBody.rows.length;
      row.setAttribute('rowid', rowCount); // newRow.rowID);
      row.className = (rowIndex % 2 == 0) ? self.Options.rowClass : self.Options.altRowClass;
      var ll = newRow.data.length;
      for (var col = 0; col < ll; col++)
      {
         noBreak = document.createElement('nobr');
         cell = document.createElement('td');
         if (self.Options.bodyCellClass)
            cell.className = self.Options.bodyCellClass;
         if (grdHeader.rows[0].cells[col].getAttribute('columnclassname'))
            cell.className += ' ' + grdHeader.rows[0].cells[col].getAttribute('columnclassname');
         cell.style.display = grdHeader.rows[0].cells[col].style.display;
         cell.style.width = grdHeader.rows[0].cells[col].style.width;

         if (grdHeader.rows[0].cells[col].getAttribute('datatype') && grdHeader.rows[0].cells[col].getAttribute('datatype').toLowerCase() == 'dropdownlist')
         {
            var ddl = document.getElementById(this.GridID).getElementsByTagName('select');
            if (ddl.length > 0)
            {
               var lll = ddl.length;
               for (var len = 0; len < lll; len++)
               {
                  if (ddl[len].getAttribute('colindex') == col)
                  {
                     cell.setAttribute('value', newRow.data[col]);
                     noBreak.innerHTML = self.__encode(GetDropdownItemText(ddl[len], newRow.data[col]));
                     cell.appendChild(noBreak);
                     break;
                  }
               }
            }
         }
         else if (grdHeader.rows[0].cells[col].getAttribute('datatype') && grdHeader.rows[0].cells[col].getAttribute('datatype').toLowerCase() == 'multilinetext')
         {
            cell.innerHTML = self.__encode(newRow.data[col]).replace('\r\n', '<br/>').replace('\n', '<br/>');
         }
         else if (grdHeader.rows[0].cells[col].getAttribute('datatype') && grdHeader.rows[0].cells[col].getAttribute('datatype').toLowerCase() == 'button')
         {
            if (grdHeader.rows[0].cells[col].getAttribute('buttontype') && grdHeader.rows[0].cells[col].getAttribute('buttontype').toLowerCase() == 'image')
               cell.innerHTML = '<input type="image" style="cursor:pointer;" src="' + self.__encode(newRow.data[col]) + '" />';
            else
               cell.innerHTML = '<input type="button" value="' + self.__encode(newRow.data[col]) + '" />';
            var btn = cell.getElementsByTagName('input')[0];
            btn.onclick = self.__columnButtonClick;
         }
         else if (grdHeader.rows[0].cells[col].getAttribute('datatype') && grdHeader.rows[0].cells[col].getAttribute('datatype').toLowerCase() == 'html')
         {
            cell.innerHTML = newRow.data[col];
            try
            {
               var img = cell.getElementsByTagName('img')[0];
               if (img)
               {
                  var clk = img.getAttribute('onclick');
                  if (clk)
                     eval('(img.onclick = ' + clk.substr(0, clk.indexOf('(')) + ')');
               }
            } catch (e) { }
         }
         else if (grdHeader.rows[0].cells[col].getAttribute('datatype') && grdHeader.rows[0].cells[col].getAttribute('datatype').toLowerCase() == 'boolean')
         {
            var grid = document.getElementById(this.GridID);
            chkBox = document.createElement('input');
            chkBox.type = 'checkbox';
            if (grid.getAttribute('editable') == "false")
               chkBox.disabled = true;
            addEvent(chkBox, 'keydown', self._editElementKeyPress);
            addEvent(chkBox, 'click', self._setChangedModeFlag);
            addEvent(chkBox, 'mousedown', self._SerializeServerData);
            cell.appendChild(noBreak.appendChild(chkBox));
            if (newRow.data[col] && newRow.data[col].toString().toLowerCase() == 'true')
               trueCheckBoxes[trueCheckBoxes.length] = chkBox;
         }
         else
         {
            noBreak.innerHTML = self.__encode(newRow.data[col]);
            cell.appendChild(noBreak);
         }
         row.appendChild(cell);
      }

      return row;
   };

   this.clearGrid = function ()
   {
      self.clearGridRows();

      //Clear column row
      var grdHeader = this.getGridHeader();
      var bb = this.getGridBodyBox();
      try
      {
         bb.scrollLeft = 0;
         bb.scrollTop = 0;
      } catch (e) { }
      if (grdHeader)
      {
         if (grdHeader.rows.length > 0)
         {
            var l = grdHeader.rows[0].cells.length;
            for (var i = 0; i < l; i++)
            {
               //Remove dropdown control
               if (grdHeader.rows[0].cells[i].getAttribute('datatype') && grdHeader.rows[0].cells[i].getAttribute('datatype').toLowerCase() == 'dropdownlist')
                  document.getElementById(this.GridID).removeChild(document.getElementById(this.GridID + '_col_' + i));
            }
            var row = grdHeader.getElementsByTagName('tr')[0];
            var tb = grdHeader.getElementsByTagName('tbody')[0];
            if (row && tb)
               tb.removeChild(row);
         }
      }
   };

   this.popGridColumns = function (gridColumnJSON)
   {
      var grdHeader = this.getGridHeader();
      if (grdHeader)
      {
         if (grdHeader.rows.length == 0)
         {
            var objGridColumns = eval('(' + gridColumnJSON + ')');
            var l = objGridColumns.GridInfo.ColumnInfo.length;
            for (i = 0; i < l; i++)
            {
               if (objGridColumns.GridInfo.ColumnInfo[i].DataType && objGridColumns.GridInfo.ColumnInfo[i].DataType.toLowerCase() == 'dropdownlist')
               {
                  var select = document.createElement('select');
                  select.setAttribute('id', objGridColumns.GridInfo.GridID + '_col_' + i);
                  select.style.cssText = 'display:none;';
                  select.setAttribute('colindex', i);
                  var ll = objGridColumns.GridInfo.ColumnInfo[i].ValueList.length;
                  for (j = 0; j < ll; j++)
                  {
                     var option = document.createElement('option');
                     option.setAttribute('value', objGridColumns.GridInfo.ColumnInfo[i].ValueList[j].Key);
                     option.innerHTML = objGridColumns.GridInfo.ColumnInfo[i].ValueList[j].Value;
                     select.appendChild(option);
                  }
                  document.getElementById(this.GridID).appendChild(select);
               }
            }

            var trGridColumnsTable = document.createElement('tr');
            trGridColumnsTable.className = objGridColumns.GridInfo.HeaderRowClass;
            l = objGridColumns.GridInfo.ColumnInfo.length;
            for (i = 0; i < l; i++)
            {
               var tdGridColumnsTable = document.createElement('td');
               tdGridColumnsTable.setAttribute('columnname', objGridColumns.GridInfo.ColumnInfo[i].ColumnName);
               tdGridColumnsTable.setAttribute('datatype', objGridColumns.GridInfo.ColumnInfo[i].DataType);
               tdGridColumnsTable.setAttribute('editable', objGridColumns.GridInfo.ColumnInfo[i].Editable);
               tdGridColumnsTable.setAttribute('sizable', objGridColumns.GridInfo.ColumnInfo[i].Sizable);
               tdGridColumnsTable.setAttribute('columnclassname', objGridColumns.GridInfo.ColumnInfo[i].ColumnClassName);
               tdGridColumnsTable.setAttribute('buttontype', objGridColumns.GridInfo.ColumnInfo[i].ButtonType);
               tdGridColumnsTable.setAttribute('buttonclickevent', objGridColumns.GridInfo.ColumnInfo[i].ButtonClickEvent);
               if (objGridColumns.GridInfo.ColumnInfo[i].DataType.toLowerCase() == 'button')
                  tdGridColumnsTable.setAttribute('editable', 'false');
               if (objGridColumns.GridInfo.ColumnInfo[i].Visible.toLowerCase() == 'true')
                  tdGridColumnsTable.style.cssText = objGridColumns.GridInfo.ColumnInfo[i].ColumnCellStyle + 'width: 100px;';
               else
                  tdGridColumnsTable.style.cssText = objGridColumns.GridInfo.ColumnInfo[i].ColumnCellStyle + 'width: 100px;display:none;';
               tdGridColumnsTable.setAttribute('initwidth', objGridColumns.GridInfo.ColumnInfo[i].Width);

               tdGridColumnsTable.className = objGridColumns.GridInfo.HeaderCellClassName + ' ' + objGridColumns.GridInfo.ColumnInfo[i].ColumnClassName;
               var nobr = document.createElement('nobr');
               nobr.innerHTML = self.__decode(objGridColumns.GridInfo.ColumnInfo[i].HeaderText);

               tdGridColumnsTable.appendChild(nobr);
               trGridColumnsTable.appendChild(tdGridColumnsTable);
            }

            this.getGridHeader().getElementsByTagName('tbody')[0].appendChild(trGridColumnsTable);

            document.getElementById(this.GridID).setAttribute('init', '');
            self.initGrid(this.GridID);
         }
         else
         {
            window.alert('Please clear the grid first.');
         }
      }
   };

   this.setNextSelectedRow = function ()
   {
      var array = new Array();
      if (this.selectedRowIDs)
      {
         if (this.selectedRowIDs.length != 0)
         {
            self.Options.rowSelection = 'Single';
            array[0] = parseInt(this.selectedRowIDs[this.selectedRowIDs.length - 1]) + 1;
            this.selectedRowIDs = null;
            this.selectedRowIDs = array;
         }
      }
      else
      {
         array[0] = 0;
         this.selectedRowIDs = array;
      }
   };

   this.refreshGrid = function ()
   {
      self.initGrid(self.GridID);
      if (self.selectedRowIDs || self.selectedRowIDs == 0)
      {
         if (self.selectedRowIDs.length != 0)
         {
            self.selectRowByRowID(self.selectedRowIDs);
         }
      }
      if (markForColumnFit)
         self.makeColumnsFit();
      if (!self.isHidden(document.getElementById(self.GridID)))
         self.initCellWidth();
   };

   this.scrollToSelectedRow = function ()
   {
      try
      {
         var rows = self.getSelectedRows();
         if (!rows || rows.length <= 0) return;
         var row = self._getRowByRowID(rows[0]);
         var btc = self.getGridBodyBox();
         var st = btc.scrollTop;
         if (row.offsetTop < st || row.offsetTop > st + btc.offsetHeight - row.offsetHeight)
            btc.scrollTop = row.offsetTop;
      } catch (e) { };

   };

   this.scrollToRowID = function (rowID)
   {
      try
      {
         var row = self._getRowByRowID(rowID);
         var btc = self.getGridBodyBox();
         var st = btc.scrollTop;
         if (row.offsetTop < st || row.offsetTop > st + btc.offsetHeight - row.offsetHeight)
            btc.scrollTop = row.offsetTop;
      } catch (e) { };

   };

   this.scrollToRowIndex = function (rowIndex)
   {
      try
      {
         var rows = self.getGridBody().rows;
         if (!rows || rows.length <= 0) return;
         var row = rows[rowIndex];
         var btc = self.getGridBodyBox();
         var st = btc.scrollTop;
         if (row.offsetTop < st || row.offsetTop > st + btc.offsetHeight - row.offsetHeight)
            btc.scrollTop = row.offsetTop;
      } catch (e) { };

   };

   this.buildSortedColumnList = function (columnName, sortOrder)
   {
      var sortColumnsArray = new Array();
      sortColumnsArray = self.sortedColumns;
      self.sortedColumns = null;

      if (sortColumnsArray)
      {
         var l = sortColumnsArray.length;
         for (i = l - 1; i >= 0; i--)
         {
            if (sortColumnsArray[i].split('|')[0] == columnName)
               sortColumnsArray.splice(i, 1);
         }
      }
      sortColumnsArray.push(columnName + '|' + sortOrder);

      return sortColumnsArray;
   };

   this.resetSortedColumns = function ()
   {
      var grdHeader = self.getGridHeader();

      if (grdHeader)
      {
         if (grdHeader.rows.length > 0)
         {
            var l = grdHeader.rows[0].cells.length;
            for (var i = 0; i < l; i++)
            {
               grdHeader.rows[0].cells[i].setAttribute('isSorted', '');
            }
         }
      }
   };

   this.setWidth = function (elem, width)
   {
      var dif = 0;
      elem.style.width = width + 'px';
      dif = elem.offsetWidth - width;

      if (dif < 0)
         width = width + dif;
      else if (dif > 0)
         width = width - dif;
      if (width <= 10)
         width = 10;
      elem.style.width = width + 'px';
      return width;
   };

   this.setHeight = function (elem, height)
   {
      var dif = 0;
      elem.style.height = height + 'px';
      dif = elem.offsetHeight - height;

      if (dif < 0)
         elem.style.height = (height + dif) + 'px';
      else if (dif > 0)
         elem.style.height = (height - dif) + 'px';
   };


   //------------------------------------
   //Function to add image tag to a cell
   //------------------------------------
   this.addImageToCell = function (cell, img)
   {
      var c = cell.getElementsByTagName('nobr');
      if (c && c.length > 0)
      {
         c = c[0];

         var len = c.getElementsByTagName('img').length;
         for (i = 0; i < len; i++)
         {
            var imgObj = c.getElementsByTagName('img')[i];
            c.removeChild(imgObj);
         }

         var t = self.getCellText(c).ReplaceAll('&nbsp;', '');
         c.innerHTML = t + '&nbsp;&nbsp;';
         var imag = document.createElement('img');
         imag.src = img;
         c.appendChild(imag);
      }
      else
      {
         c = cell.innerText;
         var nb = document.createElement('nobr');
         cell.innerHTML = '';
         nb.innerHTML = c;
         cell.appendChild(nb);
         self.addImageToCell(cell, img);
      }
   };

   //----------------------------------------
   //Function to remove image tag from a cell
   //----------------------------------------
   this.removeImageFromCell = function (cell)
   {
      var c = cell.getElementsByTagName('nobr');
      if (c && c.length > 0)
      {
         c = c[0];

         var len = c.getElementsByTagName('img').length;
         for (i = 0; i < len; i++)
         {
            var imgObj = c.getElementsByTagName('img')[i];
            c.removeChild(imgObj);
         }

         var t = self.getCellText(c).trim();
         c.innerHTML = t.trim().ReplaceAll('&nbsp;', '');
      }
      else
      {
         c = self.getCellText(c).trim();
         var nb = document.createElement('nobr');
         cell.innerHTML = '';
         nb.innerHTML = c;
         cell.appendChild(nb);
      }
   };

   this._editElementKeyPress = function (e)
   {
      if (!e) e = window.event;
      var elem = e.target != null ? e.target : e.srcElement;
      if (elem.nodeType == 3) elem = elem.parentNode; // defeat Safari bug

      var gridId = GetGridID(elem);
      if (e.keyCode && e.keyCode == 9)
      {
         var hr = self.getGridHeader().rows[0];
         var cell = getParent(elem, 'td');
         var x = getCellIndex(cell);
         var row = getParent(cell, 'tr');
         var y = row.rowIndex;
         var tbl = getParent(row, 'tbody');
         if (!tbl)
            tbl = getParent(row, 'table');

         var xx = 0;
         while (xx == 0 || tbl.rows[y].cells[x].style.display == 'none' || tbl.rows[y].style.display == 'none' || (hr.cells[x].getAttribute('editable') && hr.cells[x].getAttribute('editable').toLowerCase() != 'true'))
         {
            if (x >= row.cells.length - 1)
            {
               x = 0;
               y++;
            }
            else
               x++;
            if (y > tbl.rows.length - 1)
            {
               elem.blur();
               return true;
            };
            xx++;
         }
         nav = '{"x":' + x + ',"y":' + y + '}';
         var n = eval('(' + nav + ')');
         var inp;
         var oldDataType = self.getColumnDataType(cell);
         if (oldDataType.toLowerCase() == 'multilinetext')
            inp = cell.getElementsByTagName('textarea')[0];
         else if (oldDataType.toLowerCase() == 'dropdownlist')
            inp = cell.getElementsByTagName('select')[0];
         else
            inp = cell.getElementsByTagName('input')[0];
         if (!document.all)
         {
            try
            {
               removeEvent(inp, 'blur', self._removeControl);
            } catch (err) { inp.onblur = null; }
         }
         if (document.all)
            document.focus();
         setTimeout(function () { try { self.showEdit(tbl.rows[n.y].cells[n.x], cell); } catch (e) { } }, 100);
         return false;
      }

      return true;
   };

   this.getCellText = function (elem)
   {
      var inps = elem.getElementsByTagName('input');
      if (inps.length > 0)
      {
         if (inps[0].type.toLowerCase() == 'checkbox')
         {
            if (inps[0].checked == true)
               return 'true';
            else
               return 'false';
         }
         if (inps[0].type.toLowerCase() == 'text')
            return inps[0].value;
      }
      else if (elem.getElementsByTagName('select').length > 0)
         return elem.getElementsByTagName('select')[0].value;
      else if (elem.getElementsByTagName('textarea').length > 0)
         return elem.getElementsByTagName('textarea')[0].value;
      else
      {
         if (elem)
         {
            elem = elem.innerHTML;
            elem = elem.ReplaceAll("<NOBR>", "").ReplaceAll("</NOBR>", "").ReplaceAll("<BR>", "\r\n").ReplaceAll("<BR />", "\r\n");
            return elem.ReplaceAll("<nobr>", "").ReplaceAll("</nobr>", "").ReplaceAll("<br>", "\r\n").ReplaceAll("<br />", "\r\n");
         }
      }

      return '';
   };

   this.setCellEditable = function (rowID, column, editableFlag)
   {
      if (typeof column == 'string')
         column = this.getColumnIndex(column);

      var row = this._getRowByRowID(rowID);
      var cell = row.cells[column];

      if (editableFlag)
         cell.setAttribute('NonEditable', 'false');
      else
         cell.setAttribute('NonEditable', 'true');
   };

   this.initGrid(gridId);
}

//------------------------------------------------
//Function to get Text of the item in the dropdown
//------------------------------------------------
function GetDropdownItemText(dropdownList, item)
{
   try
   {
      var ddlItemLength = dropdownList.options.length;

      for (index = 0; index < ddlItemLength; index++)
      {
         if (dropdownList[index].value == item)
            return dropdownList[index].text;
      }

      return '';
   }
   catch (e) { return ''; }
}

//---------------------------------------
// Function to get Grid Div ID by element
//---------------------------------------
function GetGridID(elem)
{
   try
   {
      var cnt = 0;
      while (true)
      {
         cnt++;
         var test = elem.className;
         if (!test)
            test = 'zzzzzz';
         if (test.toLowerCase() == 'gridbox')
            break;
         if (cnt > 1000)
            break;
         elem = elem.parentNode;
      }
      return elem.id;
   } catch (e) { return ''; }
}

//---------------------------------------------------
//Function to get first parent object with given tag
//---------------------------------------------------
function getParent(el, pTagName)
{
   if (!el)
      return null;
   else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
      return el;
   else
      return getParent(el.parentNode, pTagName);
}

function getChild(el, pTagName)
{
   if (!el)
      return null;
   else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
      return el;
   else
      return getChild(el.firstChild, pTagName);
}

//--------------------------------------------
// Function to add event for both IE & Mozilla
//--------------------------------------------
function addEvent(obj, type, fn)
{
   try
   {
      if (obj.addEventListener)
         obj.addEventListener(type, fn, false);
      else if (obj.attachEvent)
      {
         obj["e" + type + fn] = fn;
         obj[type + fn] = function () { try { obj["e" + type + fn](window.event); } catch (e) { } }
         obj.attachEvent("on" + type, obj[type + fn]);
      }
   } catch (e) { }
}

//-----------------------------------------------
// Function to remove event for both IE & Mozilla
//-----------------------------------------------
function removeEvent(obj, type, fn)
{
   try
   {
      if (obj.removeEventListener)
         obj.removeEventListener(type, fn, false);
      else if (obj.detachEvent)
      {
         obj.detachEvent("on" + type, obj[type + fn]);
         obj[type + fn] = null;
         obj["e" + type + fn] = null;
      }
   } catch (e) { }
}

//---------------------------------------------
//Function to validate numeric datatype control
//---------------------------------------------
function validateNumericControl(evt, numericMode, txtControl, decimalPlace)
{
   var e = window.event || evt; // for trans-browser compatibility
   var charCode = e.which || e.keyCode;
   var splChar = '!@#$%^&*()'; var i = 0; var minus = '-';
   var txtvalue;
   txtvalue = txtControl.value;

   //Signed Int and UnSigned Int && Signed Decimal and UnSigned Decimal
   if ((charCode >= 48 && charCode <= 57) || (charCode >= 96 && charCode <= 105) ||
       (charCode == 8) || (charCode == 46) || (charCode == 35) || (charCode == 36) ||
       (charCode == 37) || (charCode == 39) || (charCode == 9))
   {
      while (i < txtvalue.length) //Check for special characters '!@#$%^&*()'
      {
         if (splChar.indexOf(txtvalue.charAt(i)) != -1)
         {
            txtControl.value = txtControl.value.replace(txtvalue.charAt(i), '');
         }
         i++;
      }
      if (decimalPlace && decimalPlace != 0 && txtvalue.indexOf('.') != -1) //Limit Decimal places
      {
         if ((txtvalue.length - (txtvalue.indexOf('.') + 1)) > parseInt(decimalPlace))
         {
            txtControl.value = txtControl.value.substring(0, (txtvalue.indexOf('.') + parseInt(decimalPlace) + 1));
         }
      }
      return true;
   }

   //Signed Decimal
   if (numericMode.toLowerCase() == 'decimal')
   {
      if (charCode == 190 || charCode == 110)
      {
         if (txtvalue.indexOf('.') == -1)
            return true;
         else
            return false;
      }
   }

   //Signed Int and Signed Decimal
   if (numericMode.toLowerCase() == 'wholenumber' || numericMode.toLowerCase() == 'decimal')
   {
      if (charCode == 189 || charCode == 109)
      {
         if (txtvalue.indexOf(minus) == -1)
            return true;
         if (txtvalue.indexOf(minus, 1) > 0)
         {
            while (i < txtvalue.length)
            {
               if (txtvalue.charAt(i) == minus)
               {
                  txtControl.value = txtControl.value.replace(minus, '');
               }
               i++;
            }

            if (txtvalue.charAt(0) == minus)
            {
               txtControl.value = minus + txtControl.value;
            }
         }
      }
   }
   if (charCode >= 65 && charCode <= 90)
   {
      return false;
   }
   else
   {
      return false;
   }
}

//-------------------------------------------------
//Function to mask date field [Format : MM/DD/YYYY]
//------------------------------------------------- 
function maskDateField(obj)
{
   date = obj.value
   if (/[^\d\/]|(\/\/)/g.test(date)) { obj.value = obj.value.replace(/[^\d\/]/g, ''); obj.value = obj.value.replace(/\/{2}/g, '/'); return; }
   if (/^\d{2}$/.test(date)) { obj.value = obj.value + '/'; return; }
   if (/^\d{2}\/\d{2}$/.test(date)) { obj.value = obj.value + '/'; return; }
   if (!/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(date)) return;
   return false;
}

//-----------------------------------------------------
//Function to allow Numbers & "/" only for date control
//-----------------------------------------------------
function allowDateNumeric(evt)
{
   var e = event || evt; // for trans-browser compatibility
   var charCode = e.which || e.keyCode;
   if (charCode > 31 && (charCode < 47 || charCode > 57))
      return false;

   return true;
}

//-----------------------------------------------------------
//Function to get cell index of both hidden & non-hidden cell
//-----------------------------------------------------------
function getCellIndex(cell)
{
   cell = getParent(cell, 'td');
   var row = getParent(cell, 'tr');
   var l = row.cells.length;
   for (var o = 0; o < l; o++)
   {
      if (row.cells[o] == cell)
         return o;
   }
   return -1;
}

//--------------------------
//Function to sort the table
//--------------------------
function TableSorter(tableID)
{
   // global variables
   this.parent = null;            // 'parent' node
   this.items = new Array();      // array of 'child' nodes
   this.col = 0;                  // column for sorting
   this.dataType = null;
   this.tableId = tableID;

   this.sortTable = function (columnIndex, colType, desc)
   {
      // parent node identified by id="tableid"
      this.parent = document.getElementById(this.tableId);
      this.dataType = colType;
      this.col = columnIndex;

      // parent node for sorting rows must be TBODY and not TABLE
      if (this.parent.nodeName != "TBODY")
         this.parent = this.parent.getElementsByTagName("TBODY")[0];
      if (this.parent.nodeName != "TBODY")
         return false;

      // assert: parent is now a TBODY node
      this.items = this.parent.getElementsByTagName("TR");
      var N = this.items.length;

      // bubble sort - not very efficient but ok for short lists
      for (var j = N - 1; j > 0; j--)
      {
         for (var i = 0; i < j; i++)
         {
            if (this.compare(this.getCellText(i + 1), this.getCellText(i), desc))
            {

               var v1 = this.getCheckBoxValues(this.items[i + 1]);
               var v2 = this.getCheckBoxValues(this.items[i]);
               this.exchange(i + 1, i);
               this.setCheckBoxValues(this.items[i], v1);
               this.setCheckBoxValues(this.items[i + 1], v2);
            }
         }
      }
      return true;
   };

   this.getCheckBoxValues = function (row)
   {
      var cbs = [];
      var inputs = row.getElementsByTagName('input');
      var l = inputs.length;
      for (var i = 0; i < l; i++)
      {
         if (inputs[i].type.toLowerCase() == 'checkbox')
         {
            cbs[i] = inputs[i].checked;
         }
      }
      return cbs;
   };

   this.setCheckBoxValues = function (row, values)
   {
      var inputs = row.getElementsByTagName('input');
      var l = inputs.length;
      for (var i = 0; i < l; i++)
      {
         if (inputs[i].type.toLowerCase() == 'checkbox')
         {
            inputs[i].checked = values[i];
         }
      }
   };

   this.getCellText = function (i)
   {
      var node = this.items[i].getElementsByTagName("TD")[this.col];
      if (node.childNodes.length == 0) return "";

      if (this.dataType.toLowerCase() == 'boolean')
      {
         var inp = node.getElementsByTagName('input')[0];
         if (inp.type.toLowerCase() == 'checkbox')
         {
            if (inp.checked == true)
               return 'true';
            else
               return 'false';
         }
      }
      else
      {
         while (node && node.nodeType != 3)
         {
            if (node.childNodes[0])
               node = node.childNodes[0];
            else
               node = null;
         }
         if (node)
            return node.nodeValue.trim();
      }
      return '';
   };

   this.compare = function (val1, val2, desc)
   {
      switch (this.dataType.toLowerCase())
      {
         case "wholenumber":
            val1 = parseInt(val1);
            val2 = parseInt(val2);
            break;
         case "decimal":
            val1 = parseFloat(val1);
            val2 = parseFloat(val2);
            break;
         case "date":
            val1 = new Date(val1);
            val2 = new Date(val2);
            break;
      }
      return (desc) ? val1 > val2 : val1 < val2;
   };

   this.exchange = function (i, j)
   {
      // exchange adjacent items
      this.parent.insertBefore(this.items[i], this.items[j]);
   };
}
