Click here to Skip to main content
15,895,709 members
Articles / Web Development / HTML

AJAX DataGrid

Rate me:
Please Sign up or sign in to vote.
4.57/5 (23 votes)
5 Jun 20074 min read 110.4K   2K   105  
This article demonstrates the use of the AJAX technique in tandem with the JavaScript DataGrid from my previous article.
   
   
   function GolikGrid(gridId,columnsWSize, gridHeight , gridWidth ,idHolder) 
   {

      /****** Constants *****/
      var asc = "asc";
      var desc = "desc";
      var styleCellData  =     "border-right:solid 2px white;      padding-top:5px;background-color: white;     font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;white-space:nowrap";
      var styleCellAlterData = "border-right:solid 2px whitesmoke; padding-top:5px;background-color: whitesmoke;font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;white-space:nowrap";
      var styleCellSelectedData  = "border-right:solid 2px DarkBlue;padding-top:5px;background-color: DarkBlue;color:white;font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;white-space:nowrap";
      
      
      var styleHeaderCellData = "font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;font-weight:bold;border-bottom:groove 2px lightgrey;border-right:groove 2px lightgrey;background-color:lightgrey;white-space:nowrap;" 
      var styleDragHeaderCellData = "filter:progid:DXImageTransform.Microsoft.Alpha( Opacity=40);font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;font-weight:bold;border:solid 1px black;background-color:darkgray;white-space:nowrap;"; 
      
      var styleHighlightLeftHeaderData  = "font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;font-weight:bold;border-bottom:groove 2px lightgrey;border-right:groove 2px lightgrey;border-left:solid 2px blue; background-color:lightgrey;white-space:nowrap;";
      var styleHighlightRightHeaderData = "font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;font-weight:bold;border-bottom:groove 2px lightgrey;border-right:solid 2px  blue;background-color:lightgrey;white-space:nowrap;"; 
     
      var styleStubHeaderCellData = "background-color:lightgrey;white-space:nowrap;border-bottom:groove 2px lightgrey;border-right:solid 2px lightgrey;font-size:11px;";  
      var styleStubCellData = "background-color: white;font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;white-space:nowrap;border-right:solid 2px white";
      var styleStubCellAlterData = "background-color: whitesmoke;font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;white-space:nowrap;border-right:solid 2px whitesmoke";
      
      var styleUpdateInput = "font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;border:solid 1px DarkGray";
      var styleUpdateCancelBtn = "font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;background-color:silver";
      
      var styleAddInput = "font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;border:solid 1px DarkGray";
      var styleAddCancelBtn = "font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;background-color:silver";
      
      var styleMenuItem = "padding-left:5px; padding-right:5px;padding-top:3px;padding-bottom:2px;white-space:nowrap;background-color:lightgrey;" 
      var styleMenuSelectedItem = "padding-left:5px; padding-right:5px;padding-top:3px;padding-bottom:2px;white-space:nowrap;background-color:DarkBlue;color:white;"
      var styleMenu = "width:120px;border-right:groove 2px lightgrey;border-left:groove 2px white;border-top:groove 2px white;border-bottom:groove 2px lightgrey;font-family: Verdana, Arial, 'Microsoft Sans Serif';font-size:11px;cursor:pointer";
      
      
      var scrollBarColor = "silver";
      var headerResizePointer = 'col-resize';
      var headerDragPointer = 'move'; 
      var minColumnSize = 25;
      var junkFault = 2;
      var defaultColumnSize = 100;
      var maxChildDepth = 10;
      var maxRowsCount = 300;
      var stubColumnSize = 150;
      var updateBtnOffset = 5;
      //offset between cursor and dragging column
      var offsetDragDrop = 35;
      //delay in pixel to start dragDrop
      var pixelDelayDragDrop = 20;
      var columnLeftOffset = 5;
      var sortArrowFontSize = 10;
      var sortPointerOffset = 8;
      var ascPointer = "↑";
      var descPointer ="&#8595";
      var defaultGridHeight = 500;
      var defaultGridWidth = 500;
      var defaultGridId="uxGolikGrid"
      if(gridId!=null)
         defaultGridId = gridId;
      //Constants
          
      var dataSource = new DataSource();
      var view = new View(idHolder,columnsWSize,dataSource);
      var controller = new Controller(view, dataSource , this);
      /************ Delegates *************/
      this.onRowUpdated; 
      this.onRowAdded;
      
      this.getDataSource = function()
      {
     
          return dataSource;
       
     }
     
     this.getSelectedRowId = function()
     {  
        return view.selectedRowId;
     }
     
     this.dataBind = function()
     {
        //fire event 
        controller.onDataBind();
        
     }
     this.setItemMenu = function(menuItems)
     { 
       //fire event
       controller.onSetItemMenu(menuItems);
     }
     
     this.setGridMenu = function(menuItems)
     {
       controller.onSetGridMenu(menuItems);
     }
     this.removeRow = function(rowId)
     { //fire event
       controller.onRemoveRow(rowId);
     }
     
      
     this.updateRow = function(rowId)
     { //fire event
       controller.onUpdateRow(rowId);
     
     }
     this.addRow = function()
     {
        //fire event
        controller.onAddRow();
     }
      
       
     
      /********** Utility ************/
      function isGridChild(child)
      {
         
           var gridHolder = document.getElementById(defaultGridId);
           var tries = 0;
           while(child!=gridHolder)
           { 
                 if(child.parentElement==null)
                    return false;
                 if(tries==maxChildDepth)
                    return false;
                 child = child.parentElement;
                 tries++;
                 
           }
           return true;
      
      } 
      
    
      function junkTextToWSize(str , wSize , cssText)
      { 
          var textLabel = document.getElementById("uxTextLabel");
          if(textLabel==null)
          {
            textLabel = document.createElement("<span>");
            textLabel.id = "uxTextLabel"; 
            document.body.appendChild(textLabel);
           
          }
          textLabel.innerText = str;
          textLabel.style.cssText = cssText;
          textLabel.style.visibility = "hidden";
          textLabel.style.position = "absolute"; 
          
          if(textLabel.offsetWidth>=(wSize-junkFault))
          {
              textLabel.innerText = "..."+textLabel.innerText
              while(textLabel.offsetWidth>=(wSize-junkFault))
              {
                  textLabel.innerText = textLabel.innerText.substr(0,textLabel.innerText.length-1);
                
              }
              var retString = textLabel.innerText.substr(3,textLabel.innerText.length-3)+"...";
              return retString;
              
          }
          else 
            return str;
      
            
        } 
      
      
      /******** View class *******/
      function View(idHolder,columnsWSize,dataSrc)
      {
       
       /****** Init ******/
       var dataSource = dataSrc;
       this.selectedRowId = null;
       gridHeight = (gridHeight==null)?defaultGridHeight:gridHeight;
       gridWidth = (gridWidth==null)?defaultGridWidth:gridWidth;
       var holder = document.createElement("<div id='"+defaultGridId+"' style='display:inline;width:"+gridWidth+";height:"+gridHeight+"' >");
       if(idHolder==null)
         document.body.appendChild(holder);
       else
         document.getElementById(idHolder).appendChild(holder); 
         
       var grid  = document.createElement("<div oncontextmenu='return false;' >")
       holder.appendChild(grid); 
       
    
       var width = holder.offsetWidth;
       var height = holder.offsetHeight;
       
       var headerContent = document.createElement("<table cellspacing='0' cellpadding='0' style='display:inline;position:relative;font-size:1px;' >");
       //create the temp stub cell to count offsetHeight of header
       var stubTextCell = headerContent.insertRow().insertCell();
       stubTextCell.style.cssText = styleHeaderCellData;
       stubTextCell.innerHTML = "&nbsp;<span style='font-size:"+sortArrowFontSize+"' >"+ascPointer+"<span>"; 
       var header = document.createElement("<div  onselectstart='return false;' style='cursor:pointer;white-space:nowrap;width:"+width+";height:1px;overflow-x:hidden;' >");
       header.appendChild(headerContent);
       grid.appendChild(header);
  
       var dataHeight = height - header.offsetHeight 
       //remove temp stub cell
       headerContent.deleteRow(0);
       var dataContent = document.createElement("<table cellspacing='0' border='0' cellpadding='0' style='display:inline;position:relative;font-size:1px;'  >");
       var data = document.createElement("<div  style='width:"+width+";height:"+dataHeight+";overflow:scroll;scrollbar-base-color:"+scrollBarColor+"' >");
       data.appendChild(dataContent);
       grid.appendChild(data);
   
   
        
       //set the stub for header 
       var stubScrollWidth = data.offsetWidth - data.clientWidth; 
       var stub = document.createElement("<table cellspacing='0' style='display:inline;font-size:1px;height:100% ' cellpadding='0' >");
       var stubCell = stub.insertRow().insertCell();
       stubCell.style.cssText = styleStubHeaderCellData;
       stubCell.innerHTML="&nbsp;"
       stubCell.style.width = stubScrollWidth;
       stub.style.width = stubScrollWidth;
       header.appendChild(stub);
      
       /****** Delegates ******/
       this.sortEventHandler;
       this.startResizeColumnEventHandler;
       this.startDragColumnEventHandler;
       this.rowMenuClickedEventHandler;
       this.rowUpdateClickedEventHandler;
       this.rowUpdateKeyEnteredEventHandler;
       this.rowUpdateCancelClickedEventHandler;
       this.rowAddMenuClickedEventHandler;
       this.rowAddClikedEventHandler;
       this.rowAddCancelClickedEventHandler;
       this.rowAddKeyEnteredEventHandler;
       this.gridContextMenuClickedEventHandler;
       this.dataClickedEventHandler;
       this.dataScrollEventHandler;
       
       /****** Methods ******/
       this.dataBind = function()
       {          
            this.clearView();
            var headerItems = dataSource.getHeaderItems();
            for(var index=0;index < headerItems.length; index++)
            {
               this.addHeaderItem(headerItems[index]);
              
            }
            var rowItems = dataSource.getRowItems();
            for(var index=0; index < rowItems.length; index++)
            {
               this.addRowItem(rowItems[index]);
            }
            //fixing the layout
            this.fixCellLabels();
            this.fixHeaderSortItem();
       }
       
       this.bindEvents = function()
       {     //we have to call this function to bind events, we can do it only after 
             //controller class implements these handlers. So these events can only be initialized
             //on controller creation.  
             data.onclick  = this.dataClickedEventHandler;
             data.onscroll = this.dataScrollEventHandler;
             data.oncontextmenu = this.gridContextMenuClickedEventHandler;
       
       }
       
       this.sortItems = function()
       {
        
      
            function getRowById(rowId)
            {
               for(var index=0; index < dataContent.rows.length; index++)
               {
                   if(dataContent.rows[index].rowId == rowId )
                      return dataContent.rows[index];
               }
                
            }
            
            //force grid to be not in write state
            //otherwise sorting is impossible as 
            //one need to have junked labels
            this.setGridUnselectedState();
            this.setGridReadState();
            var rowItems = dataSource.getRowItems();
            for(var index=0; index < rowItems.length; index++)
            {
                 if(rowItems[index].rowId == dataContent.rows[index].rowId)
                    continue;
                    
                 var row = getRowById(rowItems[index].rowId);
                 
                
                
                
                 var rowId  =  dataContent.rows[index].rowId;
                 dataContent.rows[index].rowId = row.rowId;
                 row.rowId = rowId;
                 
                 for(var index1 = 0; index1< dataContent.rows[index].cells.length-1; index1++)
                 {
                 
                    var innerText = dataContent.rows[index].cells[index1].firstChild.children[1].innerText;
                    var title = dataContent.rows[index].cells[index1].firstChild.children[1].title;
                    
                    dataContent.rows[index].cells[index1].firstChild.children[1].innerText = row.cells[index1].firstChild.children[1].innerText;
                    dataContent.rows[index].cells[index1].firstChild.children[1].title =  row.cells[index1].firstChild.children[1].title;
                    
                    row.cells[index1].firstChild.children[1].innerText = innerText;
                    row.cells[index1].firstChild.children[1].title = title;
                     
                  }
            }
            this.fixHeaderSortItem();
       
       }
     
       this.isRowWriteState = function(rowId)
       {
          
           for(var index=0;index<dataContent.rows.length;index++)
           {  //if the stub column has buttons that means the row is in write state
              if(dataContent.rows[index].cells[dataContent.rows[index].cells.length-1].firstChild.children[1]!=null && dataContent.rows[index].rowId == rowId)
                  return true;
              
              
           }
           
       
       }
       
       this.setRowSelectedState  = function(rowId)
       { 
          for(var index=0; index < dataContent.rows.length; index++)
          {
             if(dataContent.rows[index].rowId==rowId)
             {   
              
                 for(var index1 = 0; index1 < dataContent.rows[index].cells.length; index1++)
                 {   
                     var width = dataContent.rows[index].cells[index1].style.width;
                     dataContent.rows[index].cells[index1].style.cssText = styleCellSelectedData;
                     dataContent.rows[index].cells[index1].style.width = width;
                 }
                 break;
             }
             
          }
         this.selectedRowId = rowId;
        
         
       }
       
       
       
       this.setGridReadState = function()
       {
       
           for(var index=0;index<dataContent.rows.length;index++)
           {  //if the stub column has buttons that means the row is in write state
              if(dataContent.rows[index].cells[dataContent.rows[index].cells.length-1].firstChild.children[1]!=null)
              {
                 this.setRowReadState(dataContent.rows[index].rowId);
              }
              
           }
       
       }
       this.setGridNotAddState = function()
       {  
       
           if(data.children.length==2)
              data.children[0].parentElement.removeChild(data.children[0]);
        
       } 
       
       
       this.setGridUnselectedState = function()
       { 
          if(this.selectedRowId==null)
            return;
              
          for(var index=0; index < dataContent.rows.length; index++)
          {
                
             if(dataContent.rows[index].rowId==this.selectedRowId)   
             {
               for(var index1 = 0; index1 < dataContent.rows[index].cells.length; index1++)
               {
                  
                     var width = dataContent.rows[index].cells[index1].style.width;
                     dataContent.rows[index].cells[index1].style.cssText = (index % 2 != 0)?styleCellAlterData:styleCellData;
                     dataContent.rows[index].cells[index1].style.width = width;
               }
               break;
             }
             
             
          }
          this.selectedRowId = null;
       
       }
       
       this.saveAddedRowItem = function()
       {  
          //check if there is add row in grid
          if(data.children.length==2)
          { 
                var obj = new Object();
                for(var index=0;index < data.children[0].rows[0].cells.length-1;index++)
                {    
                    var cellValue = data.children[0].rows[0].cells[index].firstChild.children[1].value;
                    obj[index] = cellValue;
                    obj[headerContent.rows[0].cells[index].firstChild.children[1].title] = cellValue; 
                }
                return obj;
          }
          return null;
       }
       
       this.saveUpdatedRowItem = function(rowId)
       {
           var rowUpdate = null;
           for(var index=0; index < dataContent.rows.length; index++)
           {
              if(dataContent.rows[index].rowId==rowId)
                 { 
                    rowUpdate = dataContent.rows[index];
                    break;
                  } 
           }
           if(rowUpdate==null)
             return;
           if(rowUpdate.cells[rowUpdate.cells.length-1].firstChild.children[1]==null)
             //that means the row is in read state, this function should be called only at write state
              return null; 
           
           var obj = new Object();
           for(var index=0; index < rowUpdate.cells.length-1;index++)
           { 
               rowUpdate.cells[index].firstChild.children[1].title = rowUpdate.cells[index].firstChild.children[1].value; 
               obj[headerContent.rows[0].cells[index].firstChild.children[1].title] = rowUpdate.cells[index].firstChild.children[1].value;
               obj[index] = rowUpdate.cells[index].firstChild.children[1].value;  
           }
           obj.id = rowId;
           return obj;
       }
       
       this.setRowReadState = function(rowId)
       {
           var rowUpdate = null;
           for(var index=0; index < dataContent.rows.length; index++)
           {
              if(dataContent.rows[index].rowId==rowId)
                 { 
                    rowUpdate = dataContent.rows[index];
                    break;
                  } 
           }
           if(rowUpdate==null)
             return;
           if(rowUpdate.cells[rowUpdate.cells.length-1].firstChild.children[1]==null)
             //if the stub column hasn't buttons that means the row is already in read state
             return;
           
           for(var index=0; index < rowUpdate.cells.length-1;index++)
           {
              var title = rowUpdate.cells[index].firstChild.children[1].title;
              var text  = document.createElement("<span>");
              text.innerText = title;
              text.title = title;
              rowUpdate.cells[index].firstChild.children[1].parentElement.removeChild( rowUpdate.cells[index].firstChild.children[1]);
              rowUpdate.cells[index].firstChild.appendChild(text);
               
           }
           
           while(rowUpdate.cells[rowUpdate.cells.length-1].firstChild.children[1]!=null)
           {
              rowUpdate.cells[rowUpdate.cells.length-1].firstChild.children[1].parentElement.removeChild(rowUpdate.cells[rowUpdate.cells.length-1].firstChild.children[1]);
           }
           this.fixCellLabels(rowId);
         
       }
       
       this.setRowAddState = function()
       { 
       
       
           if(data.children.length==2)
             //do nothing as the add row already exists
               return;
           
           
           var addTable = document.createElement("<table style='position:relative;' cellspacing='0'  cellpadding='0' border='0' >");
           data.insertAdjacentElement("afterBegin",addTable);
           var addRow = addTable.insertRow();
           addRow.oncontextmenu = this.rowAddMenuClickedEventHandler;
           
           for(var index=0; index < headerContent.rows[0].cells.length-1; index++)
           { 
              
                var cell = addRow.insertCell();
                cell.style.cssText = styleCellAlterData;
                cell.style.width = parseInt(headerContent.rows[0].cells[index].style.width);  
                
                var holder = document.createElement("<span>");
                holder.style.whiteSpace = "nowrap";   
                cell.appendChild(holder);
                
                var offsetItem  = document.createElement("<span>");
                offsetItem.innerHTML = "&nbsp;";
                offsetItem.style.width = columnLeftOffset; 
                holder.appendChild(offsetItem);
                
                var input = document.createElement("<input type='text' >");
                input.style.cssText = styleAddInput;
                input.style.width = parseInt(headerContent.rows[0].cells[index].style.width)-columnLeftOffset;
                input.onkeydown = this.rowAddKeyEnteredEventHandler;
                holder.appendChild(input);
                if(index==0)
                    input.focus();
             
           }  
           
          
          var stubCell = addRow.insertCell();
          stubCell.style.cssText = styleStubCellAlterData;
          stubCell.style.width= headerContent.rows[0].cells[headerContent.rows[0].cells.length-1].style.width;
          var holder = document.createElement("<span>"); 
          holder.style.whiteSpace = "nowrap"; 
          offsetItem = document.createElement("<span>");
          offsetItem.innerHTML = "&nbsp;";
          offsetItem.style.width = columnLeftOffset;
          holder.appendChild(offsetItem);
          stubCell.appendChild(holder);
          addTable.style.width = headerContent.style.width;
         
          var addInput = document.createElement("<input type='button' value='Add' >");
          var cancelInput = document.createElement("<input type='button' value='Cancel' >");
          addInput.style.cssText = styleUpdateCancelBtn;
          addInput.style.width   = (stubColumnSize-updateBtnOffset-columnLeftOffset)/2;  
          cancelInput.style.cssText = styleUpdateCancelBtn;
          cancelInput.style.width   = (stubColumnSize-updateBtnOffset-columnLeftOffset)/2;
          addInput.onclick = this.rowAddClikedEventHandler;;
          cancelInput.onclick = this.rowAddCancelClickedEventHandler;
         
          
          var offset = document.createElement("<span>");
          offset.innerHTML = "&nbsp;";
          offset.style.width = updateBtnOffset;
           
          addRow.cells[addRow.cells.length-1].firstChild.appendChild(addInput);
          addRow.cells[addRow.cells.length-1].firstChild.appendChild(offset);
          addRow.cells[addRow.cells.length-1].firstChild.appendChild(cancelInput);
          
         
       }
       
       this.setRowWriteState = function(rowId)
       {  
           var rowUpdate = null;
           for(var index=0; index < dataContent.rows.length; index++)
           {
              if(dataContent.rows[index].rowId==rowId)
                 { 
                    rowUpdate = dataContent.rows[index];
                    break;
                  } 
           }
           if(rowUpdate==null)
              return
           if(rowUpdate.cells[rowUpdate.cells.length-1].firstChild.children[1]!=null)
             //if the stub column has buttons that means the row is already in write state
              return;
                 
           for(var index=0; index < rowUpdate.cells.length-1;index++)
           {
              var title = rowUpdate.cells[index].firstChild.children[1].title;
              var input = document.createElement("<input type='text'  >");
              input.onkeydown = this.rowUpdateKeyEnteredEventHandler;
              input.rowId = rowId;
              input.value = title;
              input.title = title;
              input.style.cssText = styleUpdateInput;
              input.style.width = parseInt(rowUpdate.cells[index].style.width)-columnLeftOffset;
              rowUpdate.cells[index].firstChild.children[1].parentElement.removeChild( rowUpdate.cells[index].firstChild.children[1]);
              rowUpdate.cells[index].firstChild.appendChild(input);
              if(index==0)
                 input.focus();
              
              
           }
           
           
          var updateInput = document.createElement("<input type='button' value='Update' >");
          var cancelInput = document.createElement("<input type='button' value='Cancel' >");
          updateInput.style.cssText = styleUpdateCancelBtn;
          updateInput.style.width   = (stubColumnSize-updateBtnOffset-columnLeftOffset)/2;  
          cancelInput.style.cssText = styleUpdateCancelBtn;
          cancelInput.style.width   = (stubColumnSize-updateBtnOffset-columnLeftOffset)/2;
          updateInput.onclick = this.rowUpdateClickedEventHandler;
          cancelInput.onclick = this.rowUpdateCancelClickedEventHandler;
          updateInput.rowId = rowId;
          cancelInput.rowId = rowId;
          
          var offset = document.createElement("<span>");
          offset.innerHTML = "&nbsp;";
          offset.style.width = updateBtnOffset;
           
          rowUpdate.cells[rowUpdate.cells.length-1].firstChild.appendChild(updateInput);
          rowUpdate.cells[rowUpdate.cells.length-1].firstChild.appendChild(offset);
          rowUpdate.cells[rowUpdate.cells.length-1].firstChild.appendChild(cancelInput);
          
          
       }
       
       this.removeRow = function(rowId)
       { 
          if(this.selectedRowId==rowId) 
                this.selectedRowId=null;
             
              
          for(index=0; index < dataContent.rows.length; index++)
          {
               if(dataContent.rows[index].rowId == rowId)
               {
                    dataContent.rows[index].parentElement.removeChild(dataContent.rows[index]);
                    break;
                }
          }
          
          
          for(index=0; index < dataContent.rows.length; index++)
          {
             for(index1=0; index1 < dataContent.rows[index].cells.length; index1++)
             {   
                 var width = dataContent.rows[index].cells[index1].style.width;
                 dataContent.rows[index].cells[index1].style.cssText = (index % 2 != 0)?styleCellAlterData:styleCellData;
                 dataContent.rows[index].cells[index1].style.width = width;
             }
          }
          
       }
       
       this.stopDragColumn = function(columnNumber)
       {
       
               if(document.getElementById("uxDragColumn")!=null)
               { 
                 header.removeChild(document.getElementById("uxDragColumn"));
               }
               //fix the headers
               for(var index=0; index < headerContent.rows[0].cells.length-1;index++)
               {    
                    
                      var width =  headerContent.rows[0].cells[index].style.width;
                      var headerItem =  headerContent.rows[0].cells[index];
                      headerItem.style.cssText = styleHeaderCellData;;
                      headerItem.style.width = width;
              }
           
             
       
       }
       
       //drag column to specified offset and count a new cell 
       this.dragColumn = function(columnNumber, offsetLeft)
       {
      
              //fix the headers
              for(var index=0; index < headerContent.rows[0].cells.length-1;index++)
              {    
                    
                      var width =  headerContent.rows[0].cells[index].style.width;
                      var headerItem =  headerContent.rows[0].cells[index];
                      headerItem.style.cssText = styleHeaderCellData;;
                      headerItem.style.width = width;
              }
              
              if(document.getElementById("uxDragColumn")==null)
              { 
                 //set the style for draging column 
                 var dragColumn = document.createElement("<table cellspacing='0' cellpadding='0' border='0' style='display:inline' >");
                 var cell = dragColumn.insertRow().insertCell(); 
                 dragColumn.id= "uxDragColumn";
                 dragColumn.style.position = "relative"; 
                 dragColumn.style.display = "inline";
                 cell.style.cssText = styleDragHeaderCellData;
                 var stubCell =  dragColumn.rows[0].insertCell();
                 stubCell.innerText = "hey";
                 stubCell.style.cssText = styleDragHeaderCellData;
                 stubCell.style.visibility = "hidden";
                 var sortArrow = document.createElement("<span>");
                 sortArrow.style.width = sortPointerOffset;
                 sortArrow.style.fontSize = sortArrowFontSize;
                 sortArrow.innerHTML =(dataSource.getSortDirection()==asc)?ascPointer:descPointer;
                 stubCell.appendChild(sortArrow); 
                 header.appendChild(dragColumn);
                               
               }
               var dragColumn = document.getElementById("uxDragColumn"); 
               //set private properties of dragging column
               var columnLabel  =  headerContent.rows[0].cells[columnNumber].firstChild.children[1].innerText; 
               dragColumn.rows[0].cells[0].innerText = columnLabel;
               dragColumn.rows[0].cells[0].width = parseInt(headerContent.rows[0].cells[columnNumber].style.width); 
               var headerOffset =  parseInt(header.children[0].style.width) + parseInt(header.children[1].style.width); 
               headerContent.rows[0].cells[columnNumber].style.cursor = headerDragPointer;
               var newCellIndex = null;
               for(var index=0; index < header.firstChild.rows[0].cells.length-1;index++)
                  { 
                        var headerItem =  header.firstChild.rows[0].cells[index];
                        var headerItemWidth = parseInt(headerItem.style.width);
                        var headerItemOffsetLeft = headerItem.offsetLeft;
                        var headerItemOffsetRight = headerItemOffsetLeft + headerItemWidth;
                        if(offsetLeft>headerItemOffsetLeft && offsetLeft<headerItemOffsetRight)
                        {
                         
                         
                               if(this.cellIndex != headerItem.cellIndex)
                               { 
                                   //get the x relative to headerItem
                                   var x = offsetLeft-headerItem.offsetLeft;            
                                   var relativeTo =  headerItemWidth/x;
                                  if(relativeTo<2)
                                    {  
                                          var width = headerItem.style.width;
                                          headerItem.style.cssText = styleHighlightRightHeaderData; 
                                          headerItem.style.width = width;
                                          newCellIndex = headerItem.cellIndex+1;
                                     } 
                                     else
                                     {  
                                          if(headerItem.cellIndex!=0){
                                           var previousHeaderItem = header.firstChild.rows[0].cells[headerItem.cellIndex-1];
                                           var width = previousHeaderItem.style.width; 
                                           previousHeaderItem.style.cssText = styleHighlightRightHeaderData;       
                                           previousHeaderItem.style.width = width;
                                           newCellIndex = headerItem.cellIndex;
                                         }
                                         else
                                         {
                                         
                                              var width = headerItem.style.width;
                                              headerItem.style.cssText = styleHighlightLeftHeaderData; 
                                              headerItem.style.width = width;
                                              newCellIndex = headerItem.cellIndex;
                                          
                                         } 
       
                                     } 
                                   break;
                               }
                               
                           
                          
                        }
                    
                    }// for(var index=0; index < header.firstChild.rows[0].cells.length-1;index++)
      
               dragColumn.style.left = offsetLeft - headerOffset+offsetDragDrop;
               return newCellIndex; 
             
       
       
       }
       
       
       this.resizeColumn = function(columnNumber,width)
       {
           
           
           //resize columns, and restore the text labels
           headerContent.rows[0].cells[columnNumber].style.width = width; 
           headerContent.rows[0].cells[columnNumber].firstChild.children[1].innerText = headerContent.rows[0].cells[columnNumber].firstChild.children[1].title; 
           if(data.children.length==2)
           {  
              //that means that add row is exists in grid 
              var addTable = data.children[0]; 
              addTable.rows[0].cells[columnNumber].firstChild.children[1].style.width = width-columnLeftOffset; 
              addTable.rows[0].cells[columnNumber].style.width = width;   
             
           }
           
           for(var index=0; index < dataContent.rows.length;index++)
           {
           
               if(dataContent.rows[index].cells[columnNumber].firstChild.children[1].tagName=="SPAN")
               {
               
                 
                 dataContent.rows[index].cells[columnNumber].firstChild.children[1].innerText = dataContent.rows[index].cells[columnNumber].firstChild.children[1].title;
               
               }
               else
                 if(dataContent.rows[index].cells[columnNumber].firstChild.children[1].tagName=="INPUT")
                   {
                    
                    dataContent.rows[index].cells[columnNumber].firstChild.children[1].style.width = width-columnLeftOffset; 
                  }
              dataContent.rows[index].cells[columnNumber].style.width=width;
           }
           
          
          
          this.fixCellLabels();
           
          
       }
       
       this.fixHeaderScrolling = function()
       {
            header.scrollLeft = data.scrollLeft;
       
       }
       this.fixHeaderSortItem = function()
       {
          
           //set sorting arrow
          for(var index = 0; index < headerContent.rows[0].cells.length; index++)
          {
             
            if(headerContent.rows[0].cells[index].firstChild.children[2]!=null)
               headerContent.rows[0].cells[index].firstChild.children[2].parentElement.removeChild(headerContent.rows[0].cells[index].firstChild.children[2]);
                        
             
          }
          
          var sortArrow =  document.createElement("<span>");  
          sortArrow.style.width = sortPointerOffset;
          sortArrow.style.fontSize = sortArrowFontSize;
          if(dataSource.getSortDirection()==asc)
                sortArrow.innerHTML = ascPointer; 
              else
                sortArrow.innerHTML = descPointer;
          headerContent.rows[0].cells[dataSource.getSortIndex()].firstChild.appendChild(sortArrow);
              
       }
       
       this.fixCellLabels = function(supposedRowId)
       {
        
           //fix the stub at the end of grid 
           var headerWidth =  parseInt(header.style.width);
           var headerContentWidth =  countDataCellsWidth()+stubColumnSize+parseInt(headerContent.rows[0].cells[headerContent.rows[0].cells.length-1].style.borderRightWidth);
           if(headerWidth>headerContentWidth)
           {
           
                headerContent.rows[0].cells[headerContent.rows[0].cells.length-1].style.width = (headerWidth-headerContentWidth-stubScrollWidth)+stubColumnSize;
                if(data.children.length==2)
                {    
        
                     var addTable = data.children[0];
                     addTable.rows[0].cells[addTable.rows[0].cells.length-1].style.width = (headerWidth - headerContentWidth-stubScrollWidth)+stubColumnSize;
                   
                }
                for(var index=0; index<dataContent.rows.length; index++)
                { 
                   var stubDataCell =  dataContent.rows[index].cells[dataContent.rows[index].cells.length-1];
                   stubDataCell.style.width = (headerWidth - headerContentWidth-stubScrollWidth)+stubColumnSize;
                 
                }
           }  
            
           else
              if(headerWidth<headerContentWidth)
              {
           
                  headerContent.rows[0].cells[headerContent.rows[0].cells.length-1].style.width = stubColumnSize;
                  if(data.children.length==2)
                  {
                     var addTable = data.children[0];
                     addTable.rows[0].cells[addTable.rows[0].cells.length-1].style.width = stubColumnSize;
                  }
                  for(var index=0; index<dataContent.rows.length; index++)
                  { 
                    var stubDataCell =  dataContent.rows[index].cells[dataContent.rows[index].cells.length-1];
                    stubDataCell.style.width = stubColumnSize;
                  }
                 
                  
 
           
              }
         
           var totalGridWidth =  countGridWidth();
           headerContent.style.width = totalGridWidth;
           dataContent.style.width = totalGridWidth;
           if(data.children.length==2)
               data.children[0].style.width = totalGridWidth;
          
           
           
          
           
           
           //fix the cells' labels
          for(var index=0; index < headerContent.rows[0].cells.length-1; index++)
          {
          
               var width = parseInt(headerContent.rows[0].cells[index].style.width);
               var actualWidth = headerContent.rows[0].cells[index].offsetWidth - parseInt(headerContent.rows[0].cells[index].style.borderRightWidth);
               
               if(actualWidth > width)
               { 
                
                  if(dataSource.getSortIndex()!=index)
                    headerContent.rows[0].cells[index].firstChild.children[1].innerText = junkTextToWSize(headerContent.rows[0].cells[index].firstChild.children[1].title,width-columnLeftOffset,styleHeaderCellData); 
                  else
                    headerContent.rows[0].cells[index].firstChild.children[1].innerText = junkTextToWSize(headerContent.rows[0].cells[index].firstChild.children[1].title,width-(columnLeftOffset+sortPointerOffset),styleHeaderCellData); 
                   
                  
               }
          
          }
    
           
          if(dataContent.rows.length>0)
          {   
              
              var supposedIndex = -1;
              for(var index=0; index < dataContent.rows[0].cells.length-1; index++)
              {  
                  
                   var width = parseInt(dataContent.rows[0].cells[index].style.width);
                   var actualWidth = dataContent.rows[0].cells[index].offsetWidth - parseInt(dataContent.rows[0].cells[index].style.borderRightWidth);
                   if(actualWidth > width)
                   { 
                     //alert("actualWidth:"+actualWidth+";width"+width+";index"+index);
                     if(supposedRowId!=null)
                     { 
                         if(supposedIndex == -1)
                         { 
                              //first find the supposed row index that causes the offset of cells
                              for(var index3=0; index3 < dataContent.rows.length; index3++) 
                              {
                                  if(dataContent.rows[index3].rowId == supposedRowId)
                                  {
                                      supposedIndex = index3;
                                      break;
                                  }
                              }
                          }         
                         //junk the supposed row 
                        if(dataContent.rows[supposedIndex].cells[index].firstChild.children[1].tagName=="SPAN")
                           dataContent.rows[supposedIndex].cells[index].firstChild.children[1].innerText = junkTextToWSize(dataContent.rows[supposedIndex].cells[index].firstChild.children[1].title,width-columnLeftOffset,(supposedIndex % 2 != 0)?styleCellAlterData:styleCellData);  
                        else
                         if(dataContent.rows[supposedIndex].cells[index].firstChild.children[1].tagName=="INPUT")
                             continue;
                     
                          
                          if((dataContent.rows[0].cells[index].offsetWidth - parseInt(dataContent.rows[0].cells[index].style.borderRightWidth))<= width)
                          { 
                            
                             continue;
                          }
                      }//if(supposedRowId!=null)
                          
                     for(var index1 = 0; index1 < dataContent.rows.length; index1++ )
                     {   
                        if(supposedIndex == index1)
                           continue;
                        if(dataContent.rows[index1].cells[index].firstChild.children[1].tagName=="SPAN")
                           dataContent.rows[index1].cells[index].firstChild.children[1].innerText = junkTextToWSize(dataContent.rows[index1].cells[index].firstChild.children[1].title,width-columnLeftOffset,(index1 % 2 != 0)?styleCellAlterData:styleCellData);  
                        else
                         if(dataContent.rows[index1].cells[index].firstChild.children[1].tagName=="INPUT")
                            continue;
                         
                        
                         if((dataContent.rows[0].cells[index].offsetWidth - parseInt(dataContent.rows[0].cells[index].style.borderRightWidth))<= width)
                           { 
                             
                             break;
                           }
                           
                     }
                 }//if(actualWidth > width)
               }//for(var index=0; index < dataContent.rows[0].cells.length-1; index++)
           }
         
          
           
          
          
            
           
       }
      
      
      
       
       
       
       
      
      
       this.changeColumnOrder = function(sourceOrder,destinationOrder)
       {
       
             
              //replace header columns
              var sourceColumn =  headerContent.rows[0].cells[sourceOrder];
              var destinationColumn = headerContent.rows[0].insertCell(destinationOrder);
              for(var index=0; index<sourceColumn.children.length; index++)
              {
              
                    destinationColumn.appendChild(sourceColumn.children[index]);              
                                         
              }
              
              destinationColumn.onmousedown = this.startDragColumnEventHandler;
              destinationColumn.ondblclick = this.sortEventHandler;
              destinationColumn.oncontextmenu = this.gridContextMenuClickedEventHandler;
              destinationColumn.style.cssText = sourceColumn.style.cssText;
              destinationColumn.style.width = sourceColumn.style.width;
              
              if(destinationOrder>sourceOrder) 
                   headerContent.rows[0].deleteCell(sourceOrder);   
              else 
                   headerContent.rows[0].deleteCell(sourceOrder+1);   
                  
                       
              for(var index=0; index < headerContent.rows[0].cells.length; index++ )
              {
                    if(headerContent.rows[0].cells[index].firstChild.children[2]!=null)
                    {//that means that it's header cell containing sort arrow
                       dataSource.setSortIndex(index)
                       break;  
                    }
              }  
                  
             //replace add columns
              if(data.children.length==2)
              {
                  var addTable = data.children[0]; 
                   
                  var sourceColumn = addTable.rows[0].cells[sourceOrder];
                  var destinationColumn = addTable.rows[0].insertCell(destinationOrder);
                  for(var index=0; index<sourceColumn.children.length; index++)
                  {
              
                       destinationColumn.appendChild(sourceColumn.children[index]);              
                                         
                  } 
                  destinationColumn.style.cssText = sourceColumn.style.cssText;
                  destinationColumn.style.width = sourceColumn.style.width;
                  if(destinationOrder>sourceOrder)
                      addTable.rows[0].deleteCell(sourceOrder);   
                  else
                      addTable.rows[0].deleteCell(sourceOrder+1);     
                   
                 
             }
             
             
              //replace data columns
              for(var index=0; index<dataContent.rows.length;index++)
              {
                 
                   var sourceColumn = dataContent.rows[index].cells[sourceOrder]; 
                   var destinationColumn = dataContent.rows[index].insertCell(destinationOrder);
                   for(var index1=0; index1<sourceColumn.children.length; index1++)
                   {
              
                       destinationColumn.appendChild(sourceColumn.children[index1]);              
                                         
                   }
       
                   destinationColumn.style.cssText = sourceColumn.style.cssText;
                   destinationColumn.style.width = sourceColumn.style.width;
                   
                   if(destinationOrder>sourceOrder)
                      dataContent.rows[index].deleteCell(sourceOrder);   
                   else
                      dataContent.rows[index].deleteCell(sourceOrder+1);   
                       
                 
              }
              
             
              
                    
       }
      
      
       function countGridWidth()
       {
          var width=0;
          for(var index=0;index<headerContent.rows[0].cells.length;index++)
          {
             
                var borderWidth  = parseInt(headerContent.rows[0].cells[index].style.borderRightWidth);
                borderWidth = isNaN(borderWidth)?0:borderWidth;
                width+=parseInt(headerContent.rows[0].cells[index].style.width)+borderWidth;  
            
          }
          return width;
          
       } 
       
       function countDataCellsWidth()
       {
         
          var width=0;
          for(var index=0;index<headerContent.rows[0].cells.length-1;index++)
          {
             
               var borderWidth  = parseInt(headerContent.rows[0].cells[index].style.borderRightWidth);
               borderWidth = isNaN(borderWidth)?0:borderWidth;
               width+=parseInt(headerContent.rows[0].cells[index].style.width)+borderWidth;    
            
          }
          return width;
         
         
       }
       
       
       
       this.addHeaderItem = function(headerText)
       {
       
          if(headerContent.rows.length==0)
            headerContent.insertRow();
            
          if(headerContent.rows[0].cells.length==0)
          {
             var stubCell = headerContent.rows[0].insertCell(); 
             stubCell.style.cssText = styleStubHeaderCellData
             stubCell.style.width = stubColumnSize; 
             stubCell.oncontextmenu = this.gridContextMenuClickedEventHandler;
             var holder = document.createElement("<span>");
             holder.style.whiteSpace = "nowrap";
             var resizeCol = document.createElement("<span>");
             resizeCol.innerHTML="&nbsp;";
             resizeCol.style.cursor=headerResizePointer;
             resizeCol.style.width=columnLeftOffset;
             resizeCol.onmousedown= this.startResizeColumnEventHandler; 
             resizeCol.ondblclick = function(){event.cancelBubble=true;};
             holder.appendChild(resizeCol);       
             var headerEntry = document.createElement("<span>");
             headerEntry.innerHTML = "&nbsp;";
             holder.appendChild(headerEntry);       
             stubCell.appendChild(holder);
          } 
        
        
        
          
          var cell = headerContent.rows[0].insertCell(headerContent.rows[0].cells.length-1);
          var width = (columnsWSize[cell.cellIndex]==null)?defaultColumnSize:columnsWSize[cell.cellIndex]; 
          if(width<minColumnSize)
              width = minColumnSize;
          cell.style.cssText = styleHeaderCellData    
          cell.style.width = width;
          cell.onmousedown = this.startDragColumnEventHandler;
          cell.ondblclick = this.sortEventHandler;
          cell.oncontextmenu = this.gridContextMenuClickedEventHandler;
          var holder = document.createElement("<span>");
          holder.style.whiteSpace = "nowrap"; 
          var resizeCol = document.createElement("<span>");
          resizeCol.innerHTML="&nbsp;";
          resizeCol.style.width=columnLeftOffset;
          resizeCol.style.cursor= headerResizePointer;
          resizeCol.ondblclick = function(){event.cancelBubble=true;};
          resizeCol.onmousedown= this.startResizeColumnEventHandler;
          holder.appendChild(resizeCol);
          var headerEntry = document.createElement("<span>");
          headerEntry.title = headerText; 
          headerEntry.innerText = headerText;
          holder.appendChild(headerEntry);       
          cell.appendChild(holder);
          
       }
       
    
       this.addRowItem = function(rowData)
       {
         
          var row = dataContent.insertRow();
          row.rowId = rowData.rowId;
          row.oncontextmenu = this.rowMenuClickedEventHandler;
          var isAlter = false;
          if(row.rowIndex % 2 != 0)
             isAlter = true; 
          
          for(var index=0; index < headerContent.rows[0].cells.length-1; index++)
          {  
             var width = (columnsWSize[index]==null)?defaultColumnSize:columnsWSize[index];
             if(width<minColumnSize)
                width = minColumnSize;
             var cell = row.insertCell(); 
             cell.style.cssText =(isAlter)?styleCellAlterData:styleCellData;
             cell.style.width = width; 
             var holder = document.createElement("<span>");
             holder.style.whiteSpace = "nowrap";   
             var offsetItem  = document.createElement("<span>");
             offsetItem.innerHTML = "&nbsp;";
             offsetItem.style.width = columnLeftOffset;  
             holder.appendChild(offsetItem);
             var dataEntry = document.createElement("<span>");
             dataEntry.innerText = (rowData[index]==null)?" ":rowData[index];
             dataEntry.title=(rowData[index]==null)?"":rowData[index]; 
             holder.appendChild(dataEntry);
             cell.appendChild(holder);            
            
             
          }
          
          var stubCell = dataContent.rows[dataContent.rows.length-1].insertCell();
          stubCell.style.cssText =(isAlter)?styleStubCellAlterData:styleStubCellData;
          stubCell.style.width=stubColumnSize;
          var holder = document.createElement("<span>"); 
          holder.style.whiteSpace = "nowrap"; 
          offsetItem = document.createElement("<span>");
          offsetItem.innerHTML = "&nbsp;";
          offsetItem.style.width = columnLeftOffset;
          holder.appendChild(offsetItem);
          stubCell.appendChild(holder);
           
        }
       
    
    
       
       this.clearView = function()
       {    
            if(headerContent.rows.length>0)
               headerContent.deleteRow();
            
            while(dataContent.rows.length!=0)
            {
                 dataContent.deleteRow();         
            }
       
       }
       
       
     }//View class
     
     /******** Menu View class **********/
     function MenuView(menuItems)
     {
         var menuContent = document.body.appendChild(document.createElement("<table border='0' cellspacing='0' cellpadding='0' onselectstart='return false;' oncontextmenu='return false;' >"));
         menuContent.style.cssText = styleMenu;
         menuContent.style.display = "none";
         menuContent.style.position = "absolute";
         var thisRef = this;
         for(key in menuItems)
         {
            var menuItem = menuContent.insertRow().insertCell();
            menuItem.innerText = key;
            menuItem.onclick = function()
            {
               menuItems[this.innerText]();
               menuContent.style.display = 'none';    
            }
            menuItem.style.cssText = styleMenuItem;
         }
        
         
         this.onMouseMove = function()
         {
            if(event.srcElement.tagName=="TD")
            {
              thisRef.select(event.srcElement.parentElement.rowIndex);
            }
         
         }
         this.onMouseLeave = function()
         {
             if(event.srcElement.tagName=="TABLE")
            {
              thisRef.deselect();
            }
         
         
         }
         menuContent.onmousemove = this.onMouseMove;
         menuContent.onmouseleave = this.onMouseLeave; 
         
         this.show = function()
         { 
            
           menuContent.style.display = "inline";
           menuContent.style.left = event.clientX;
           menuContent.style.top = event.clientY;
           
          
           
         }
         this.hide = function()
         {
           this.deselect();
           menuContent.style.display = "none";
           
         }
         
         this.deselect = function()
         {
            for(index=0; index < menuContent.rows.length; index++)
            {
              menuContent.rows[index].cells[0].style.cssText = styleMenuItem;
            }
         }
         
         this.select = function(index)
         {
           this.deselect();
           menuContent.rows[index].cells[0].style.cssText = styleMenuSelectedItem;   
            
         }
        
     }//MenuView
     
    
     /******** DataSource class *********/
     function DataSource()
     {
       
        /****** Init ******/
        var dataHeaders = new Array();
        var dataRows = new Array();
        var sortDirection= asc;
        var sortIndex = 0; 
        /******* Methods *******/
        
        function sortItems(data1,data2)
        {
            
            var data1Value = data1[sortIndex];
            var data2Value = data2[sortIndex];
            
            if(data1Value==null)
                data1Value = "";
            
            if(data2Value==null)
                data2Value = "";
           data1Value = data1Value.toUpperCase();
           data2Value = data2Value.toUpperCase();
                
               
            if(sortDirection==asc)
            {
              
               if(data1Value<data2Value)
                   return -1;
               else 
                  if(data1Value>data2Value)
                     return 1;
                   else 
                     return 0;      
            }
            else 
            {
                
               if(data1Value>data2Value)
                   return -1;
               else 
                  if(data1Value<data2Value)
                     return 1;
                       else 
                     return 0;   
               
            }
        
        }
        this.clear = function()
        {
           dataHeaders = new Array();
           dataRows = new Array();
           sortDirection= asc;
           sortIndex = 0; 
        }
        
        this.changeColumnOrder = function(sourceOrder, destinationOrder)
        {
      
             
             
             
               
             var sourceHeader  = dataHeaders[sourceOrder];
             var newDataHeaders = new Array();
             for(var index=0; index < dataHeaders.length; index++)
             {
                 if(index == sourceOrder)
                   continue;
                 if(index == destinationOrder)
                     newDataHeaders.push(sourceHeader);           
                newDataHeaders.push(dataHeaders[index]);           
                 
             }
           
            if(destinationOrder==dataHeaders.length)
                newDataHeaders.push(sourceHeader);           
                
             
             dataHeaders = newDataHeaders;
      
            
            for(var index=0;index<dataRows.length;index++)
            {
               var dataRow = dataRows[index]; 
               var sourceData = dataRow[sourceOrder];
               var newDataRow = new Array();
               for(var index1=0; index1<dataRow.length; index1++)
               {
                   if(index1==sourceOrder)
                     continue;
                   if(index1 == destinationOrder)
                      newDataRow.push(sourceData);
                   newDataRow.push(dataRow[index1]);   
                   
                   
               }  
               
               if(destinationOrder==dataRow.length)
                  newDataRow.push(sourceData); 
               newDataRow.rowId = dataRow.rowId;   
               dataRows[index] = newDataRow;
           
            }
           
           
                          
      
     
            
        }
        
        this.updateRow = function(obj)
        {
           for(index=0; index < dataRows.length; index++)
           {
               if(dataRows[index].rowId==obj.id)
               {
                    for(var index1=0;index1<dataRows[index].length;index1++)
                    {
                       dataRows[index][index1] = obj[index1];
                    }
               }
                 
           }
        
        }
        
        this.removeRow = function(rowId)
        { 
        
           for(index=0; index < dataRows.length; index++)
           {
               if(dataRows[index].rowId==rowId)
                   dataRows.splice(index,1);
                 
           }
                       
        }
        
        this.getSortIndex = function()
        {
           return sortIndex;
        }
        
        this.setSortIndex = function(value)
        { 
           sortIndex = value;
        }
        
        this.getSortDirection = function()
        {
           return sortDirection;
        } 
        
        this.setSortDirection = function(value)
        {
          sortDirection = value; 
        }
        
       
        this.addRowItem = function(rowId , arr)
        {
            if(maxRowsCount == dataRows.length)
              alert("Unable to add row to the data source object due to the max number rows is "+maxRowsCount+".");  
            else{
                for(var index=0; index<dataRows.length; index++)
                {
                   if(dataRows[index].rowId == rowId)
                   {
                     alert("Unable to add row due to row Id - "+rowId+" already exists.");
                     return;  
                   }
                }
                arr.rowId = rowId;
                dataRows.push(arr);
             }
        }
        this.addHeaderItem = function(headerText)
        {  
          dataHeaders.push(headerText);
           
        }
        this.getRowItems = function()
        {
           return  dataRows.sort(sortItems); 
        }
        this.getHeaderItems = function()
        {
           return dataHeaders;
        }
        
     
     }//DataSource class
     
     /********** Controller class ***********/
     function Controller(view , dataSource , grid)
     {
     
       
         var itemMenu = null;
         var gridMenu = null;
         var thisRef = this;
         this.hideAllMenu  = function()
         {
            if(itemMenu!=null)
               itemMenu.hide();
            if(gridMenu!=null)
               gridMenu.hide();
         }
         this.showItemMenu = function()
         {
             if(itemMenu!=null)
               itemMenu.show();
          
         }
         this.showGridMenu = function()
         {
            if(gridMenu!=null)
               gridMenu.show();
            
         }
         
         this.onSetItemMenu = function (menuItems)
         {   
            itemMenu = new MenuView(menuItems);
         }
         
         this.onSetGridMenu = function(menuItems)
         {
         
            gridMenu = new MenuView(menuItems);   
           
         }
         
         /********** Grid View Events ****************/
         this.onDataBind = function()
         {   
            
             view.dataBind();
         }
         
        
       
        
         
         this.onRemoveRow = function(rowId)
         { 
            view.removeRow(rowId);
            dataSource.removeRow(rowId);
             
         }
         
         this.onUpdateRow = function(rowID)
         {
            view.setGridUnselectedState();
            view.setRowWriteState(rowID);
              
         }
         
         this.onAddRow = function()
         { 
            view.setGridUnselectedState();
            view.setRowAddState();
         }
         
         
         view.dataClickedEventHandler = function()
         {
            thisRef.hideAllMenu();
            view.setGridUnselectedState();
            event.cancelBubble = true; 
            
         }
         
         view.rowUpdateKeyEnteredEventHandler = function()
         {
            if(event.keyCode == 13 )
             {
                var obj = view.saveUpdatedRowItem(this.rowId);
                view.setRowReadState(this.rowId);
                dataSource.updateRow(obj);
                if(grid.onRowUpdated!=null)
                   grid.onRowUpdated(obj);
             }
             else
              if(event.keyCode == 27)
              {
                view.setRowReadState(this.rowId);
                
                 
              }
              event.cancelBubble = true; 
            
           
         } 
         view.rowUpdateClickedEventHandler = function()
         {
             var obj = view.saveUpdatedRowItem(this.rowId);
             view.setRowReadState(this.rowId);
             dataSource.updateRow(this.rowId,obj);
              if(grid.onRowUpdated!=null)
                   grid.onRowUpdated(obj);
             event.cancelBubble = true; 
         
          }
         
         view.rowUpdateCancelClickedEventHandler = function()
         {
             view.setRowReadState(this.rowId);
             event.cancelBubble = true; 
         }
         
         view.rowAddClikedEventHandler = function()
         {
             var obj = view.saveAddedRowItem();
             view.setGridNotAddState();
             if(grid.onRowAdded!=null)
                   grid.onRowAdded(obj);
             event.cancelBubble = true; 
            
         }
         view.rowAddCancelClickedEventHandler = function()
         {
             view.setGridNotAddState();
             event.cancelBubble = true; 
        
         }
         view.rowAddKeyEnteredEventHandler = function()
         {
             
        
             if(event.keyCode == 13 )
             { 
                var obj = view.saveAddedRowItem();
                view.setGridNotAddState();
                if(grid.onRowAdded!=null)
                   grid.onRowAdded(obj);
             }
              else
              if(event.keyCode == 27)
              {
                 view.setGridNotAddState();
                 
              }
              event.cancelBubble = true; 
        }
         
         
         view.rowAddMenuClickedEventHandler = function()
         {  
            event.cancelBubble = true; 
            //do nothing 
         }
    
         view.rowMenuClickedEventHandler = function(rowId)
         {   
               if(!view.isRowWriteState(this.rowId)){
                thisRef.hideAllMenu();
                thisRef.showItemMenu();
                view.setGridUnselectedState();
                view.setRowSelectedState(this.rowId);
              }
              event.cancelBubble = true; 
              return false;
         }
         
         view.gridContextMenuClickedEventHandler = function()
         {  
            thisRef.hideAllMenu();
             view.setGridUnselectedState();
            thisRef.showGridMenu();
            event.cancelBubble = true; 
            return false;
         }
        
       
         view.sortEventHandler = function()
         { 
             event.cancelBubble = true; 
             var columnIndex = this.cellIndex;
             if(columnIndex == dataSource.getSortIndex())
             {
               if(dataSource.getSortDirection()==asc)
                  dataSource.setSortDirection(desc);
               else
                  dataSource.setSortDirection(asc);
                  
             }
             else{
               dataSource.setSortIndex(columnIndex);
               dataSource.setSortDirection(asc);
             }
             
         
            
             
             thisRef.hideAllMenu();
             view.setGridUnselectedState();  
             view.sortItems();
             event.cancelBubble = true;
            
            
         }
         
         view.dataScrollEventHandler = function()
         {
           thisRef.hideAllMenu();
           view.setGridUnselectedState();   
           view.fixHeaderScrolling();
           event.cancelBubble = true;
          
         }
         
         view.startResizeColumnEventHandler = function()
         {   
           
           thisRef.hideAllMenu();
           view.setGridUnselectedState();   
           function onResizeColumnEventHandler()
             {
                   event.cancelBubble = true;
                   if(!isGridChild(event.srcElement))
                   { 
                       this.click();
                       return;
                   }
                  //force to release capture if header index is the first cell
                  if(this.parentElement.parentElement.cellIndex==0)
                  {  
                        this.click();
                        return;
                  }
                  var sizableColumn = this.parentElement.parentElement.parentElement.cells[this.parentElement.parentElement.cellIndex-1];
                  var newWidth = parseInt(sizableColumn.style.width)+event.screenX-this.previousX;
                  this.previousX = event.screenX; 
                  
                  if(newWidth<minColumnSize)
                     newWidth = minColumnSize;
                  view.resizeColumn(sizableColumn.cellIndex,newWidth);
                   
                 
              
              
            }
         
         
            function onResizeLeaveColumnEventHandler()
            {
               event.cancelBubble = true; 
               this.onmousemove = null;
               this.onclick= null; 
               this.releaseCapture();
               
          
           
            }
            
          if(event.button==1)
          { 
             
            this.onmousemove = onResizeColumnEventHandler;
            this.onclick= onResizeLeaveColumnEventHandler; 
            this.previousX = event.screenX
            this.setCapture(false);
             
           
           }
           
          event.cancelBubble = true; 
       
       }
        
        
        view.startDragColumnEventHandler = function()
        {
             
           thisRef.hideAllMenu();
           view.setGridUnselectedState();   
          
           function onPrepareDrag()
           {
            if(this.previous==null)
             {   
                event.cancelBubble = true;
                this.previous  = event.screenX;
                 
             }
             var span = this.previous-event.screenX;
             if(span > pixelDelayDragDrop || span < -pixelDelayDragDrop)
             { 
                  this.onmousemove = onDragColumn;
                  this.previous = null;
             } 
           }
           
           function onDragColumn()
           {
           
             
              event.cancelBubble = true;
              if(!isGridChild(event.srcElement))
              {   
                  this.newCellIndex = null;
                  this.click();
                  return;
              }
             
              this.newCellIndex =  view.dragColumn(this.cellIndex,event.x);
             
             
              
           }
           
          
          
           function onDragColumnLeave()
           {
               
              
               event.cancelBubble = true;
               view.stopDragColumn(this.cellIndex);
               this.onmousemove = null;
               this.onclick = null;
               this.releaseCapture();
             
               //replace columns in dataSource and view
               var cellIndex = this.cellIndex;
               var newCellIndex = this.newCellIndex;
               if(newCellIndex!=null)
               {   
                  view.changeColumnOrder(cellIndex,newCellIndex);
                  dataSource.changeColumnOrder(cellIndex,newCellIndex);
               }
               this.newCellIndex = null;
               
              
           }
           if(event.button==1)
           { 
            
             this.setCapture(false); 
             this.onmousemove = onPrepareDrag;
             this.onclick = onDragColumnLeave;
            } 
            
         
           event.cancelBubble = true; 
           
        } 
        
        
        view.bindEvents();
     
     }//Controller class
     
      
    
     
     
        
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Belarus Belarus
Andrew Golik is a software professional working in Minsk, Belarus.
He enjoys design infrastructures based on object oriented paradigm. His programming experience includes ASP, ASP.NET, .NET, COM, JAVA, PHP, DHTML, AJAX, blah blah blah....

Andrew Golik's Blog

Comments and Discussions