3.2.0

This example shows how to Drag and Drop Rows in a v2.0 Grid to change the row order

I hacked away at other examples and finally have a very basic example of reordering rows in a grid using drag and drop. This works in V2.0 beta 4.

Give it a try and please post enhancements. To make it easy to save to your hard drive I have uploaded it to:
http://epixpro.com/aw/dragdroprow.txt

Save that file to your ActiveWidgets directory as a html file.

Here is the code (keeping my fingers crossed that it will post right)

<html> 
<head> 
    <script src="runtime/lib/aw.js"></script> 
    <link href="runtime/styles/xp/aw.css" rel="stylesheet"></link> 
</head> 
<body> 
This is a very simple drag and drop example to move rows. <b>Click and drag a cell to move a row to a new location</b>.
<hr>
<style> 
    #myGrid { width: 600px; height:350px;  margin: 0px; padding: 0px} 
    #myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;} 
    #myGrid .aw-alternate-odd  .aw-column-0 {background: #E0E0E0;} 
    #myGrid .aw-alternate-even {background: #E7E7D6;} 
    #myGrid .aw-alternate-odd  {background: #F7F3E7;} 
    #myGrid .aw-rows-selected {background: #316ac5;}
    #myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;}
</style> 

<script> 

    var HeaderText = ["Number","Description"]; 
    var CellText = [ 
        ["1","Description 1"], 
        ["2","Description 2"], 
        ["3","Description 3"], 
        ["4","Description 4"], 
        ["5","Description 5"], 
        ["6","Description 6"], 
        ["7","Description 7"], 
        ["8","Description 8"], 
        ["9","Description 9"], 
        ["10","Description 10"], 
        ["11","Description 11"], 
        ["12","Description 12"], 
        ["13","Description 13"], 
        ["14","Description 14"], 
        ["15","Description 15"]
    ]; 

    var obj = new AW.UI.Grid;

    obj.setId("myGrid");  // necessary for CSS rules 
    obj.setHeaderText(HeaderText); 
    obj.setCellText(CellText); 
    obj.setColumnCount(2); 
    obj.setRowCount(15); 

    // DISABLE SORTING - This simple example will not work if sorted
    obj.onHeaderClicked = function(event,index){return 'disabled'};

    obj.setSelectionMode("single-row");

    document.write(obj); 

    // THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS
    obj.onCellMouseDown        = function(event, column, row){ if (column>0) dragstart(event, column, row) }; 
    obj.onCellMouseUp        = function(event, column, row){ dragstop(column, row) }; 


    // DRAGGING FUNCTIONS
    var startrow, endrow
     
    function dragstart(e, column, row){ 
        startrow=row;
        window.status = "Drag Start Row:"+row;
    } 
     
    function dragstop(column, row){ 

        if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=null; 
        stoprow=row;
        window.status = window.status + " dragstop row=" + stoprow;

        // NOTE: THE TIMES 1 (*1) IN ALL CODE BELOW 
        // IS TO MAKE SURE JAVASCRIPT TREATS THE VARS
        // AS NUMBERS INSTEAD OF STRINGS
        //
        // THIS CODE ONLY WORKS FOR A GRID BASED ON AN ARRAY.
        // IT USES THE "splice" COMMAND TO ADD AND DELETE
        // ROWS DIRECTLY IN THE ARRAY.
        //
        // ex. splice (start position, num of rows to delete, optional data to insert)
        // To delete 1 row use splice(rowindex,1)
        // To add a row without deleting another use spice(rowindex,0,newdata)

        // GET CONTENTS OF DRAG ROW... NOTE THIS GETS THE ENTIRE ROW
        // SUCH AS ["7","Description 7"]
        var startrowcontents = CellText[startrow];

        if ( (stoprow*1) > (startrow*1)) {
            // DRAG AND DROP IN DOWNWARD DIRECTION
            CellText.splice((stoprow*1)+1,0,startrowcontents); //INSERT DRAG ROW BELOW DROP ROW
            CellText.splice(startrow,1); // DELETE DRAG ROW

        // DRAG AND DROP IN UPWARD DIRECTION
        } else if ((stoprow*1) < (startrow*1)) {
            CellText.splice((stoprow*1),0,startrowcontents); // INSERT DRAG ROW ABOVE DROP ROW
            CellText.splice((startrow*1)+1,1); // DELETE DRAG ROW, NOTE IT IS PUSHED DOWN 1 BECAUSE OF THE INSERT ABOVE

        // DRAG AND DROP TO SAME ROW (IGNORE)
        } else { 
            window.status = "Don't Move ... Start and Stop Row are the same ("+startrow+","+stoprow+")"; 
        }

        // FYI... IF YOU WANTED TO HARD CODE THE DATA TO INSERT IT WOULD LOOK LIKE THIS
        //  CellText.splice(stoprow,0,["17","Description 17"]);

        obj.refresh();
    } 

</script> 

<hr>
I tested it using AW 2.0 beta 4 and IE and Firefox 1.0. It has several limitations
<ul>
<li>Only works on ARRAY based grid.
<li>Array is manipulated directly using splice. I wanted to use addRow and deleteRow but I couldn't figure out how to set the insert location for addRow (it was always inserting at the end of the grid).
<li>No visual feedback when dragging the row ... please someone figure out how to add that :)
<li>Sorting is not supported so it is disabled
</ul>

</body> 
</html>


I hope this is a good starting point and useful for others. I found some great 1.0 examples on the forum but not much for 2.0. All you great coders out there please submit a more generic and flexible example :)

Thanks!
Rob Francis
February 1,
Rob, nice example. This will give others a place to start from. Do I have your permission to post this to the Demo page on my site. www.FriendsOfAW.com?

Thanks for the fine effort!
Jim Hunter
February 1,
Hey Jim ... yes please post it over there for me!

Rob Francis
February 1,
I have it added now so if anyone want to see the demo but doesn't want to go through the trouble of editing the file to fit your computer, you can check it out at:

http://friendsofaw.com/nuke/modules.php?name=Demos

Thanks Rob!
Jim Hunter
February 1,
Great example!!! Before looking at this code I was always thinking that drag-and-drop is something very complex :-)
Alex (ActiveWidgets)
February 1,
To make it working with RC1 add #myGrid {-moz-user-select: none} to the style block.
Alex (ActiveWidgets)
February 1,
Alex ... That worked! Plus a quick run through of my other V2 code is looking good under RC1 too.

I also added a add row and delete row button to this example with the code below:

Added this Javascript
function del(){
      var insertindex=obj.getCurrentRow();
          CellText.splice(insertindex,1);
      obj.setRowCount(obj.getRowCount()-1);

      obj.refresh();
    }


    function add(){
      var insertindex=obj.getCurrentRow();
          CellText.splice((insertindex*1)+1,0,["new","new"]);

      obj.setRowCount(obj.getRowCount()+1);

      obj.refresh();

    }


Added this HTML
<button onclick="add()">add row below current</button>
<button onclick="del()">delete current row</button>


The full updated version is at:
http://www.epixpro.com/aw/dragdroprow.txt
Rob Francis
February 1,
Hi Rob,
Thanks , it's a Nice & very useful Sample:
I just discovered a small bug in this sample ( it happens after dragging any row in col-1 and then do a row-drag in col-0 "intend to be disabled").
It can be easy solved by doing a little change in oncellMouseDown/oncellMouseUp functions by:

// THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS
    obj.onCellMouseDown        = function(event, column, row){ 
    if (column>0) {dragstart(event, column, row) }
    else { startrow = null }
    }; 
    obj.onCellMouseUp        = function(event, column, row){
     if (startrow) { dragstop(column, row) }
      };



And here is (as requested) ;-) my first attempt to add a visual row-drag-effect :
It is based on a great Austin Mayberry's sample page enhancement drag-drop-columns (which I'm currently triyng to convert too )
(but in this case adapted for rows and V2.0):
/javascript.forum.3258.21/dropdown-grid-template.html

( Did not test it a lot (especially inside div/table and many other situations, so could be buggy also).
Please report any issue found:
HTH

var RowsArea = obj.getRowsTemplate();
var mouseCelldown = false;
var RowTarget;
var CellTarget;
var TopRowTG;
var rightScroll;
var bottomScroll;

/*****************/
 var dragColStart = function(event) {       

if(!AW.ie) {  CellTarget = event.target  }
else{ CellTarget = event.srcElement  }

 var sECId = CellTarget.id ;
 if (sECId.indexOf("-box-text") > 0 ){ RowTarget = CellTarget.parentNode.parentNode }
else { RowTarget = CellTarget.parentNode }

rightScroll = obj.getScrollLeft();
bottomScroll = obj.getScrollTop();

TopRowTG = RowTarget.parentNode.firstChild;

RowTarget.width=RowTarget.offsetWidth;
RowTarget.height=RowTarget.offsetHeight;

///get column number
 var arrofcolumns = CellTarget.id.split("-");

//disable row-drag visual effect on some rows (IN CURRENT SAMPLE ROW 0 IS DISABLED)
if ( arrofcolumns[2] >0 ){	mouseCelldown = true }
else {mouseCelldown = false }
}

/********************************/	

var dragCol = function(event) {

if(!AW.ie) { var x = event.pageX  ; var y = event.pageY ; }
else{ var x = event.screenX ; var y=event.screenY }

var DragRow = document.getElementById('DragRow');
if(DragRow) {  

  if(!AW.ie){ 
  if(rightScroll==0){ DragRow.style.left = x - AW.getLeft(CellTarget)  - obj.getSelectorWidth() }
  else{ DragRow.style.left = x   + rightScroll - AW.getLeft(CellTarget) - obj.getSelectorWidth() }
  if(bottomScroll==0){ DragRow.style.top = y - AW.getTop(TopRowTG) + 3; }
  else{ DragRow.style.top = y + bottomScroll - AW.getTop(TopRowTG) + 3 }
  }
  
  if( AW.ie){ 
 DragRow.style.left = x - window.screenLeft  - AW.getLeft(CellTarget) -  obj.getSelectorWidth() + 8 ;
 DragRow.style.top = y - window.screenTop - AW.getTop(TopRowTG) + 3 ;
  }
    }

else if(mouseCelldown){

var DragRow = RowTarget.cloneNode(true)
DragRow.id = "DragRow";
DragRow.style.position = "absolute";
DragRow.style.width = RowTarget.width;
DragRow.style.height = RowTarget.height;
DragRow.style.zIndex = 1000000;
DragRow.style.MozOpacity = 0.7; 
DragRow.style.filter = "alpha(opacity=70)" 

RowTarget.parentNode.appendChild(DragRow);
  }
 }
/***********************/
obj.setEvent("onmousemove", dragCol);
RowsArea.setEvent("onmousedown", dragColStart);

Carlos
February 9,
Uppps SORRY, Comented line:
//disable row-drag visual effect on some rows (IN CURRENT SAMPLE ROW 0 IS DISABLED)
Should say COLUMNS
February 9,
Hi Carlos,

Thanks for the bug fix... actually the code that disables (ignores) column zero is left over from the sample I started with. I didn't intend that have that in there but I missed it :)

I would really like to see your visual feedback enhancement but I can't get it to work. I tried adding it to my sample but I must have something wrong.

Can you post the full example.

Thanks!
Rob Francis
February 9,
I forgot to say that documnet.write(obj) must be at the bottom of all, (if not the first click on the grid does not fire the visual-e), but after that any dragging works . Could be this ???
I could not locate any other change than I commented your line :
// if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=null;
But if I un-commet it works also.
Anyway here is the complete sample :
Carlos.
<html>  
<head>  
<script src="../../runtime/lib/aw.js"></script>
    <link href="../../runtime/styles/xp/aw.css" rel="stylesheet"></link>
</head>  
<body> 
This is a very simple drag and drop example to move rows. <b>Click and drag a cell to move a row to a new location</b>.
<hr>
<style> 
    #myGrid { width: 300px; height:150px;  margin: 0px; padding: 0px} 
    #myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;} 
    #myGrid .aw-alternate-odd  .aw-column-0 {background: #E0E0E0;} 
    #myGrid .aw-alternate-even {background: #E7E7D6;} 
    #myGrid .aw-alternate-odd  {background: #F7F3E7;} 
    #myGrid .aw-rows-selected {background: #316ac5;}
    #myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;}
    #myGrid {-moz-user-select: none}
</style> 
<script> 
    var HeaderText = ["Number","Description"]; 
    var CellText = [ 
        ["1","Description 1"], 
        ["2","Description 2"], 
        ["3","Description 3"], 
        ["4","Description 4"], 
        ["5","Description 5"], 
        ["6","Description 6"], 
        ["7","Description 7"], 
        ["8","Description 8"], 
        ["9","Description 9"], 
        ["10","Description 10"], 
        ["11","Description 11"], 
        ["12","Description 12"], 
        ["13","Description 13"], 
        ["14","Description 14"], 
        ["15","Description 15"]
    ]; 

    var obj = new AW.UI.Grid;

    obj.setId("myGrid");  // necessary for CSS rules 
    obj.setHeaderText(HeaderText); 
    obj.setCellText(CellText); 
    obj.setColumnCount(2); 
    obj.setRowCount(15); 

    // DISABLE SORTING - This simple example will not work if sorted
    obj.onHeaderClicked = function(event,index){return 'disabled'};

    obj.setSelectionMode("single-row");

    obj.setSelectorVisible(true);
//	obj.setSelectorResizable(true);
    obj.setSelectorWidth(25);

//	obj.setControlSize(100, 200);	// width, height
//	obj.setControlPosition(327, 50);	// left, top - adds 'position:absolute'

//    document.write(obj); 

    // THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS
    obj.onCellMouseDown        = function(event, column, row){ 
    if (column>0) {dragstart(event, column, row) }
    else { startrow = null }
    }; 
    obj.onCellMouseUp        = function(event, column, row){
     if (startrow) { dragstop(column, row) }
      }; 


    // DRAGGING FUNCTIONS
    var startrow, endrow ;
    
    /**********************/
    
        function dragstart(e, column, row){ 
        startrow=row;
        window.status = "Drag Start Row:"+row;
 }       

    function dragstop(column, row){ 

//        if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=null; 
        stoprow=row;
        window.status = window.status + " dragstop row=" + stoprow;

        // NOTE: THE TIMES 1 (*1) IN ALL CODE BELOW 
        // IS TO MAKE SURE JAVASCRIPT TREATS THE VARS
        // AS NUMBERS INSTEAD OF STRINGS
        //
        // THIS CODE ONLY WORKS FOR A GRID BASED ON AN ARRAY.
        // IT USES THE "splice" COMMAND TO ADD AND DELETE
        // ROWS DIRECTLY IN THE ARRAY.
        //
        // ex. splice (start position, num of rows to delete, optional data to insert)
        // To delete 1 row use splice(rowindex,1)
        // To add a row without deleting another use spice(rowindex,0,newdata)

        // GET CONTENTS OF DRAG ROW... NOTE THIS GETS THE ENTIRE ROW
        // SUCH AS ["7","Description 7"]
        var startrowcontents = CellText[startrow];

        if ( (stoprow*1) > (startrow*1)) {
            // DRAG AND DROP IN DOWNWARD DIRECTION
            CellText.splice((stoprow*1)+1,0,startrowcontents); //INSERT DRAG ROW BELOW DROP ROW
            CellText.splice(startrow,1); // DELETE DRAG ROW

        // DRAG AND DROP IN UPWARD DIRECTION
        } else if ((stoprow*1) < (startrow*1)) {
            CellText.splice((stoprow*1),0,startrowcontents); // INSERT DRAG ROW ABOVE DROP ROW
            CellText.splice((startrow*1)+1,1); // DELETE DRAG ROW, NOTE IT IS PUSHED DOWN 1 BECAUSE OF THE INSERT ABOVE

        // DRAG AND DROP TO SAME ROW (IGNORE)
        } else { 
            window.status = "Don't Move ... Start and Stop Row are the same ("+startrow+","+stoprow+")"; 
        }

        // FYI... IF YOU WANTED TO HARD CODE THE DATA TO INSERT IT WOULD LOOK LIKE THIS
        //  CellText.splice(stoprow,0,["17","Description 17"]);


    obj.setSelectedRows([stoprow]);
    mouseCelldown = false;
        obj.refresh();
    } 

    function del(){
      var insertindex=obj.getCurrentRow();
          CellText.splice(insertindex,1);
      obj.setRowCount(obj.getRowCount()-1);

      obj.refresh();
    }

    function add(){
      var insertindex=obj.getCurrentRow();
          CellText.splice((insertindex*1)+1,0,["new","new"]);

      obj.setRowCount(obj.getRowCount()+1);

      obj.refresh();

    }

/************************/

var RowsArea = obj.getRowsTemplate(); 
var mouseCelldown = false; 
var RowTarget; 
var CellTarget; 
var TopRowTG; 
var rightScroll; 
var bottomScroll; 

/*****************/ 
 var dragColStart = function(event) {        

if(!AW.ie) {  CellTarget = event.target  } 
else{ CellTarget = event.srcElement  } 

 var sECId = CellTarget.id ; 
 if (sECId.indexOf("-box-text") > 0 ){ RowTarget = CellTarget.parentNode.parentNode } 
else { RowTarget = CellTarget.parentNode } 

rightScroll = obj.getScrollLeft(); 
bottomScroll = obj.getScrollTop(); 

TopRowTG = RowTarget.parentNode.firstChild; 

RowTarget.width=RowTarget.offsetWidth; 
RowTarget.height=RowTarget.offsetHeight; 

///get column number 
 var arrofcolumns = CellTarget.id.split("-"); 

//disable row-drag visual effect on some COLUMNS (IN CURRENT SAMPLE DRAG IN COLUMN-0 IS DISABLED) 
if ( arrofcolumns[2] >0 ){    mouseCelldown = true } 
else {mouseCelldown = false } 
} 

/********************************/     

var dragCol = function(event) { 

if(!AW.ie) { var x = event.pageX  ; var y = event.pageY ; } 
else{ var x = event.screenX ; var y=event.screenY } 

var DragRow = document.getElementById('DragRow'); 
if(DragRow) {   

  if(!AW.ie){  
  if(rightScroll==0){ DragRow.style.left = x - AW.getLeft(CellTarget)  - obj.getSelectorWidth() } 
  else{ DragRow.style.left = x   + rightScroll - AW.getLeft(CellTarget) - obj.getSelectorWidth() } 
  if(bottomScroll==0){ DragRow.style.top = y - AW.getTop(TopRowTG) + 3; } 
  else{ DragRow.style.top = y + bottomScroll - AW.getTop(TopRowTG) + 3 } 
  } 
   
  if( AW.ie){  
 DragRow.style.left = x - window.screenLeft  - AW.getLeft(CellTarget) -  obj.getSelectorWidth() + 8 ; 
 DragRow.style.top = y - window.screenTop - AW.getTop(TopRowTG) + 3 ; 
  } 
    } 

else if(mouseCelldown){ 

var DragRow = RowTarget.cloneNode(true) 
DragRow.id = "DragRow"; 
DragRow.style.position = "absolute"; 
DragRow.style.width = RowTarget.width; 
DragRow.style.height = RowTarget.height; 
DragRow.style.zIndex = 1000000; 
DragRow.style.MozOpacity = 0.7;  
DragRow.style.filter = "alpha(opacity=70)"  

RowTarget.parentNode.appendChild(DragRow); 
  } 
 } 
/***********************/ 
obj.setEvent("onmousemove", dragCol); 
RowsArea.setEvent("onmousedown", dragColStart); 
        
    
  document.write(obj);

</script> 
<br>
<button onclick="add()">add row below current</button>
<button onclick="del()">delete current row</button>
<hr>
I tested it using AW 2.0 beta 4 and IE and Firefox 1.0. It has several limitations
<ul>
<li>Only works on ARRAY based grid.
<li>Array is manipulated directly using splice. I wanted to use addRow and deleteRow but I couldn't figure out how to set the insert location for addRow (it was always inserting at the end of the grid).
<li>No visual feedback when dragging the row ... please someone figure out how to add that :)
<li>Sorting is not supported so it is disabled
</ul>
</body> 
</script>
</html>
February 9,
Outstanding Carlos! This is exactly what I was hoping for.

I've made one more enhancement but it still has bugs... if you have time please help.

The code below contains my original sample PLUS your visual feedback PLUS auto scroll. The auto scroll lets you (for example) drag row 1 all the way down to row 15. Since row 15 is not visible the grid has to scroll as you get near the bottom.

The problem is if you go past the bottom of the grid then your visual feedback disappears. I think it is a problem with RowTarget.parentNode returning null.

<html>   
<head>   
<script src="../../runtime/lib/aw.js"></script> 
    <link href="../../runtime/styles/xp/aw.css" rel="stylesheet"></link> 
</head>   
<body>  
This is a very simple drag and drop example to move rows. <b>Click and drag a cell to move a row to a new location</b>. 
<hr> 
<style>  
    #myGrid { width: 300px; height:150px;  margin: 0px; padding: 0px}  
    #myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;}  
    #myGrid .aw-alternate-odd  .aw-column-0 {background: #E0E0E0;}  
    #myGrid .aw-alternate-even {background: #E7E7D6;}  
    #myGrid .aw-alternate-odd  {background: #F7F3E7;}  
    #myGrid .aw-rows-selected {background: #316ac5;} 
    #myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;} 
    #myGrid {-moz-user-select: none} 
</style>  
<script>  
    var HeaderText = ["Number","Description"];  
    var CellText = [  
        ["1","Description 1"],  
        ["2","Description 2"],  
        ["3","Description 3"],  
        ["4","Description 4"],  
        ["5","Description 5"],  
        ["6","Description 6"],  
        ["7","Description 7"],  
        ["8","Description 8"],  
        ["9","Description 9"],  
        ["10","Description 10"],  
        ["11","Description 11"],  
        ["12","Description 12"],  
        ["13","Description 13"],  
        ["14","Description 14"],  
        ["15","Description 15"] 
    ];  

    var obj = new AW.UI.Grid; 

    obj.setId("myGrid");  // necessary for CSS rules  
    obj.setHeaderText(HeaderText);  
    obj.setCellText(CellText);  
    obj.setColumnCount(2);  
    obj.setRowCount(15);  

    // DISABLE SORTING - This simple example will not work if sorted 
    obj.onHeaderClicked = function(event,index){return 'disabled'}; 

    obj.setSelectionMode("single-row"); 

    obj.setSelectorVisible(true); 
//    obj.setSelectorResizable(true); 
    obj.setSelectorWidth(25); 

//    obj.setControlSize(100, 200);    // width, height 
//    obj.setControlPosition(327, 50);    // left, top - adds 'position:absolute' 

//    document.write(obj);  

    // THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS 
    obj.onCellMouseDown        = function(event, column, row){  
    if (column>0) {dragstart(event, column, row) } 
    else { startrow = null } 
    };  
    obj.onCellMouseUp        = function(event, column, row){ 
     if (startrow) { dragstop(column, row) } 
      };  


    // DRAGGING FUNCTIONS 
    var startrow, endrow ; 
    var dragapproved=false 
    var offsetx, offsety, tmpx, tmpy, maxx, maxy,scrollupy, scrolldowny 
     
    /**********************/ 
     
        function dragstart(e, column, row){  
        dragapproved=true; 
        startrow=row; 
        offsety=event.clientY;  
    scrollupy=obj.getHeaderHeight()+80;
    scrolldowny=document.getElementById("myGrid").offsetHeight+20;
        tmpy=obj.getScrollTop(); 
        maxy=obj.getScrollHeight() - document.getElementById("myGrid").offsetHeight + 18; 
//        if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=dragdrop 
        window.status = "Drag Start Row:"+row; 
 }        


    function dragdrop(e){ 
        if (dragapproved&&event.button==1){ 
    if (event.clientY<scrollupy) {
        window.status="go backwards Y: "+event.clientY;
        y=obj.getScrollTop()-20;
            if (y<0) y=0; 
            obj.setScrollTop(y); 
    }

    if (event.clientY>scrolldowny) {
        window.status="go to: "+event.clientY;
            obj.setScrollTop(obj.getScrollTop()+20); 
        y=obj.getScrollTop()+20;
            if (y>maxy)y=maxy; 
            obj.setScrollTop(y); 
    }
        } 
    }


    function dragstop(column, row){  

        dragapproved=false; 

//        if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=null; 
        stoprow=row; 
        window.status = window.status + " dragstop row=" + stoprow; 

        // NOTE: THE TIMES 1 (*1) IN ALL CODE BELOW  
        // IS TO MAKE SURE JAVASCRIPT TREATS THE VARS 
        // AS NUMBERS INSTEAD OF STRINGS 
        // 
        // THIS CODE ONLY WORKS FOR A GRID BASED ON AN ARRAY. 
        // IT USES THE "splice" COMMAND TO ADD AND DELETE 
        // ROWS DIRECTLY IN THE ARRAY. 
        // 
        // ex. splice (start position, num of rows to delete, optional data to insert) 
        // To delete 1 row use splice(rowindex,1) 
        // To add a row without deleting another use spice(rowindex,0,newdata) 

        // GET CONTENTS OF DRAG ROW... NOTE THIS GETS THE ENTIRE ROW 
        // SUCH AS ["7","Description 7"] 
        var startrowcontents = CellText[startrow]; 

        if ( (stoprow*1) > (startrow*1)) { 
            // DRAG AND DROP IN DOWNWARD DIRECTION 
            CellText.splice((stoprow*1)+1,0,startrowcontents); //INSERT DRAG ROW BELOW DROP ROW 
            CellText.splice(startrow,1); // DELETE DRAG ROW 

        // DRAG AND DROP IN UPWARD DIRECTION 
        } else if ((stoprow*1) < (startrow*1)) { 
            CellText.splice((stoprow*1),0,startrowcontents); // INSERT DRAG ROW ABOVE DROP ROW 
            CellText.splice((startrow*1)+1,1); // DELETE DRAG ROW, NOTE IT IS PUSHED DOWN 1 BECAUSE OF THE INSERT ABOVE 

        // DRAG AND DROP TO SAME ROW (IGNORE) 
        } else {  
            window.status = "Don't Move ... Start and Stop Row are the same ("+startrow+","+stoprow+")";  
        } 

        // FYI... IF YOU WANTED TO HARD CODE THE DATA TO INSERT IT WOULD LOOK LIKE THIS 
        //  CellText.splice(stoprow,0,["17","Description 17"]); 


    obj.setSelectedRows([stoprow]); 
    mouseCelldown = false; 
        obj.refresh(); 
    }  

    function del(){ 
      var insertindex=obj.getCurrentRow(); 
          CellText.splice(insertindex,1); 
      obj.setRowCount(obj.getRowCount()-1); 

      obj.refresh(); 
    } 

    function add(){ 
      var insertindex=obj.getCurrentRow(); 
          CellText.splice((insertindex*1)+1,0,["new","new"]); 

      obj.setRowCount(obj.getRowCount()+1); 

      obj.refresh(); 

    } 

/************************/ 

var RowsArea = obj.getRowsTemplate();  
var mouseCelldown = false;  
var RowTarget;  
var CellTarget;  
var TopRowTG;  
var rightScroll;  
var bottomScroll;  

/*****************/  
 var dragColStart = function(event) {         

if(!AW.ie) {  CellTarget = event.target  }  
else{ CellTarget = event.srcElement  }  

 var sECId = CellTarget.id ;  
 if (sECId.indexOf("-box-text") > 0 ){ RowTarget = CellTarget.parentNode.parentNode }  
else { RowTarget = CellTarget.parentNode }  


rightScroll = obj.getScrollLeft();  
bottomScroll = obj.getScrollTop();  

TopRowTG = RowTarget.parentNode.firstChild;  

RowTarget.width=RowTarget.offsetWidth;  
RowTarget.height=RowTarget.offsetHeight;  

///get column number  
 var arrofcolumns = CellTarget.id.split("-");  

//disable row-drag visual effect on some COLUMNS (IN CURRENT SAMPLE DRAG IN COLUMN-0 IS DISABLED)  
if ( arrofcolumns[2] >0 ){    mouseCelldown = true }  
else {mouseCelldown = false }  
}  


/********************************/      

var dragCol = function(event) {  



        if (dragapproved&&event.button==1){ 
    if (event.clientY<scrollupy) {
        window.status="go backwards Y: "+event.clientY;
        y=obj.getScrollTop()-20;
            if (y<0) y=0; 
            obj.setScrollTop(y); 
    }

    if (event.clientY>scrolldowny) {
        window.status="go to: "+event.clientY;
            obj.setScrollTop(obj.getScrollTop()+20); 
        y=obj.getScrollTop()+20;
            if (y>maxy)y=maxy; 
            obj.setScrollTop(y); 
    }
        } 



if(!AW.ie) { var x = event.pageX  ; var y = event.pageY ; }  
else{ var x = event.screenX ; var y=event.screenY }  

var DragRow = document.getElementById('DragRow');  
if(DragRow) {    

  if(!AW.ie){   
  if(rightScroll==0){ DragRow.style.left = x - AW.getLeft(CellTarget)  - obj.getSelectorWidth() }  
  else{ DragRow.style.left = x   + rightScroll - AW.getLeft(CellTarget) - obj.getSelectorWidth() }  
  if(bottomScroll==0){ DragRow.style.top = y - AW.getTop(TopRowTG) + 3; }  
  else{ DragRow.style.top = y + bottomScroll - AW.getTop(TopRowTG) + 3 }  
  }  
    
  if( AW.ie){   
 DragRow.style.left = x - window.screenLeft  - AW.getLeft(CellTarget) -  obj.getSelectorWidth() + 8 ;  
 DragRow.style.top = y - window.screenTop - AW.getTop(TopRowTG) + 3 ;  
  }  
    }  

else if(mouseCelldown){  

var DragRow = RowTarget.cloneNode(true)  ;
DragRow.id = "DragRow";  
DragRow.style.position = "absolute";  
DragRow.style.width = RowTarget.width;  
DragRow.style.height = RowTarget.height;  
DragRow.style.zIndex = 1000000;  
DragRow.style.MozOpacity = 0.7;   
DragRow.style.filter = "alpha(opacity=70)"   
RowTarget.parentNode.appendChild(DragRow);}

 }  
/***********************/  
obj.setEvent("onmousemove", dragCol);  
RowsArea.setEvent("onmousedown", dragColStart);  
         
     
  document.write(obj); 

</script>  
<br> 
<button onclick="add()">add row below current</button> 
<button onclick="del()">delete current row</button> 
<hr> 
I tested it using AW 2.0 beta 4 and IE and Firefox 1.0. It has several limitations 
<ul> 
<li>Only works on ARRAY based grid. 
<li>Array is manipulated directly using splice. I wanted to use addRow and deleteRow but I couldn't figure out how to set the insert location for addRow (it was always inserting at the end of the grid). 
<li>No visual feedback when dragging the row ... please someone figure out how to add that :) 
<li>Sorting is not supported so it is disabled 
</ul> 
</body>  
</script> 
</html>
Rob Francis
February 9,
P.S. - I should have cleaned the code above up better. The function 'dragdrop' is not needed or called. Instead, I copied that code into your 'dragCol' function.
Rob Francis
February 9,
This is just elegant and fun, Thanks both of you!!!

Perhaps if you added {cursor: move} then back to {cursor: crosshair}
and something like {border-top: 3px dotted green;} at the Cell or Row Drop point... It would make an even more dramatic effect.


Anyway, Great fun! thanks so much..
thanks
-g
G. Cayman
February 9,
Rob, I discover something interesting.
First "sorry" there is a small bug in my code (but very important) for your pourpose:
Because RowsTemplate is repainted during scroll the dragging-row-div must be appended one more level up. (that's why it disappears)
so, the row:
RowTarget.parentNode.appendChild(DragRow);
should be:
RowTarget.parentNode.parentNode.appendChild(DragRow);

And the other : (lucky me "by casuality") is disable virtual mode:
obj.setVirtualMode(false);
Please, tell me if it works for you with your last-posted code, and without changing anything more.
Thanks
Carlos
February 9,
Hi Carlos... Those changes took care of the error. Thanks!

FYI - I just tried it under FF (1.0) and my auto scroll code isn't working there. Everything else works though.
Rob Francis
February 9,
Forget, the new parentNode., it is just the virtualmode.
I think.-- :)
Yeah, for FF need to play with event.pageY plus scroll.
Carlos
February 9,
Yes, virtualmode was the culprit.

BTW everyone, for the Add and Del item buttons I'm going to change the code to use obj.getSelectedRows([0]) instead of obj.getCurrentRow(). Those values are not always the same and it make more sense to me to operate on the selected row.
Rob Francis
February 9,
Not sure why, but the dragging row is still disappearing above middle of row-1 ( when entering upper mid row-1 and entire row-0 is not shown)
Make it sense for you??
Carlos
February 9,
Carlos, I can't duplicate your problem but maybe I'm just not understanding it. The dragging row is always visible during the drag for me.

Also, if you let the mouseup when you are no longer on the grid then the dragging row is still visible. Not a big problem but I don't understand how the dragging row is hidden in the first place.
Rob Francis
February 9,
I can confirm that it's happening ( only tested under IE)
When you drag any row to row-0 it disappears, but (moving cursor down) at middle of row-1 appear again.
(maybe is the zone you defined for starting auto-scroll)

I think there is some kind of confict with both "y" variables ,and is the same hiding issue that is produced while dragging-scrolling (up or down)
(i.e. you can see dragging-row only if scroll is stoped, but not when moving).

About your second theme, not sure how to hide it when mouseup outside the grid (even outside rows-area), well of course you can try with..
RowTarget.parentNode.removeChild(DragRow);
(WHILE YOU CAN SEE IT ..IT EXIST) ;-)
I say that becase when trying to adapt the original sample to yours I notice something curious, (although in the original exist a mouseup event with above line ) I forgot to add it at end of your function - obj.onCellMouseUp

( maybe I ask myself the same question as you now)
How is it hidden if no removeChild is present ??

So, instead (the supposed correct line) I put this testing block and notice that was removed:
var DragRow = document.getElementById('DragRow');
if(DragRow) { alert('dragging row still exist')}
else{ alert('dragging row does NOT exist') }

So seems that it only exist while the variable mouseCelldown=true;
and it isn't set to false anywhere ( ghost again ??) :)
( seriouslly only exist inside dragCol function )... but why ?
I might be wrong here, (or getting crazy) :-)

The funny thing is that I am creating samples that I can not understand.

Hmmm, sounds really bad...I will try to do some more test on both things
Cheers

Carlos
February 9,
Thanks for the update Carlos. I'm fixing the auto scroll so it will work for FireFox and the code will be a little cleaner. I will post it when I'm done and the code will be cleaner (just one "y" variable).

Maybe that will help with the problem you are seeing.
Rob Francis
February 9,
Here is fairly cleaned up version. It will auto scroll in FireFox. I also added comments, renamed vars, etc to make it easier for others to understand.

Carlos... let me know if you still have the problem you mentioned above.

<html>
<head>
<script src="../../runtime/lib/aw.js"></script>
    <link href="../../runtime/styles/xp/aw.css" rel="stylesheet"></link>
</head>
<body>
This is a very simple drag and drop example to move rows.<br>
<b>Click and drag a cell to move a row to a new location</b>.
<hr>
<style>
    #myGrid { width: 300px; height:150px;  margin: 0px; padding: 0px}
    #myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;}
    #myGrid .aw-alternate-odd  .aw-column-0 {background: #E0E0E0;}
    #myGrid .aw-alternate-even {background: #E7E7D6;}
    #myGrid .aw-alternate-odd  {background: #F7F3E7;}
    #myGrid .aw-rows-selected {background: #316ac5;}
    #myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;}
    #myGrid {-moz-user-select: none}
</style>
<script>
    var HeaderText = ["Number","Description"];
    var CellText = [
        ["1","Description 1"],
        ["2","Description 2"],
        ["3","Description 3"],
        ["4","Description 4"],
        ["5","Description 5"],
        ["6","Description 6"],
        ["7","Description 7"],
        ["8","Description 8"],
        ["9","Description 9"],
        ["10","Description 10"],
        ["11","Description 11"],
        ["12","Description 12"],
        ["13","Description 13"],
        ["14","Description 14"],
        ["15","Description 15"]
    ];

    var obj = new AW.UI.Grid;

    obj.setId("myGrid");
    obj.setHeaderText(HeaderText);
    obj.setCellText(CellText);
    obj.setColumnCount(2);
    obj.setRowCount(15);
    obj.setVirtualMode(false);

    // DISABLE SORTING - This simple example will not work if sorted
    obj.onHeaderClicked = function(event,index){return 'disabled'};

    obj.setSelectionMode("single-row");
    obj.setSelectorVisible(true);
    obj.setSelectorWidth(25);


    /**********************/
    function DeleteSelectedRow(){
      var insertindex=obj.getSelectedRows([0]);
      CellText.splice(insertindex,1);
      obj.setRowCount(obj.getRowCount()-1);
      obj.refresh();
    }

    /**********************/
    function AddNewRowBelowSelectedRow(){
      var insertindex=obj.getSelectedRows([0]);
      CellText.splice((insertindex*1)+1,0,["new","new"]);
      obj.setRowCount(obj.getRowCount()+1);
      obj.refresh();
    }


    // DRAGGING FUNCTIONS
    var startrow, endrow ;
    var MaxScrollTop;
    var RowsArea = obj.getRowsTemplate();
    var mouseCelldown = false;
    var RowTarget;
    var CellTarget;
    var TopRowTG;
    var rightScroll;
    var bottomScroll;

    /**********************/
    // BEGIN DRAG & DROP - THIS RECORDS THE STARTING (DRAG) ROW
    function dragstart(e, column, row){
      startrow=row;
      MaxScrollTop=obj.getScrollHeight() - document.getElementById("myGrid").offsetHeight + 18;
    }

    /**********************/
    // END DRAG & DROP - THIS CODE MOVES THE DRAG ROW TO THE DROP LOCATION
    function dragstop(column, row){

        mouseCelldown=false;
        stoprow=row;

        // NOTE: THE TIMES 1 (*1) IN ALL CODE BELOW
        // IS TO MAKE SURE JAVASCRIPT TREATS THE VARS
        // AS NUMBERS INSTEAD OF STRINGS
        //
        // THIS CODE ONLY WORKS FOR A GRID BASED ON AN ARRAY.
        // IT USES THE "splice" COMMAND TO ADD AND DELETE
        // ROWS DIRECTLY IN THE ARRAY.
        //
        // ex. splice (start position, num of rows to delete, optional data to insert)
        // To delete 1 row use splice(rowindex,1)
        // To add a row without deleting another use spice(rowindex,0,newdata)

        // GET CONTENTS OF DRAG ROW... NOTE THIS GETS THE ENTIRE ROW
        // SUCH AS ["7","Description 7"]
        var startrowcontents = CellText[startrow];

        if ( (stoprow*1) > (startrow*1)) {
            // DRAG AND DROP IN DOWNWARD DIRECTION
            CellText.splice((stoprow*1)+1,0,startrowcontents); //INSERT DRAG ROW BELOW DROP ROW
            CellText.splice(startrow,1); // DELETE DRAG ROW

        // DRAG AND DROP IN UPWARD DIRECTION
        } else if ((stoprow*1) < (startrow*1)) {
            CellText.splice((stoprow*1),0,startrowcontents); // INSERT DRAG ROW ABOVE DROP ROW
            CellText.splice((startrow*1)+1,1); // DELETE DRAG ROW, NOTE IT IS PUSHED DOWN 1 BECAUSE OF THE INSERT ABOVE
        }

        // FYI... IF YOU WANTED TO HARD CODE THE DATA TO INSERT IT WOULD LOOK LIKE THIS
        //  CellText.splice(stoprow,0,["17","Description 17"]);

        obj.setSelectedRows([stoprow]);
        obj.refresh();
    }


    /**********************/
    // BEGIN DRAG & DROP - CREATES THE VISUAL FEEDBACK ROW
    // THAT IS DISPLAYED WHILE ROW IS BEING DRAGGED
    var dragRowStart = function(event) {

        if(!AW.ie) {  CellTarget = event.target  }
        else{ CellTarget = event.srcElement  }

        var sECId = CellTarget.id ;
        if (sECId.indexOf("-box-text") > 0 ){
          RowTarget = CellTarget.parentNode.parentNode }
        else {
          RowTarget = CellTarget.parentNode;
        }

        rightScroll = obj.getScrollLeft();
        bottomScroll = obj.getScrollTop();

        TopRowTG = RowTarget.parentNode.firstChild;

        RowTarget.width=RowTarget.offsetWidth;
        RowTarget.height=RowTarget.offsetHeight;

        mouseCelldown = true;
    }


    /**********************/
    // DRAG IN PROGRESS -
    // 1) MOVES THE VISUAL FEEDBACK ROW
    // 2) AUTO SCROLLS THE GRID IF NEEDED
    var dragRowMouseMove = function(event) {

      var NewFeedbackRowTop=0;
      var NewFeedbackRowLeft=0;

      bottomScroll = obj.getScrollTop();

      if(!AW.ie) { var x1 = event.pageX  ; var y1 = event.pageY ; }
      else{ var x1 = event.clientX ; var y1=event.clientY }

      if(!AW.ie) { var x = event.pageX  ; var y = event.pageY ; }
      else{ var x = event.screenX ; var y=event.screenY }

      var FeedbackRow = document.getElementById('FeedbackRow');
      if(FeedbackRow) {

        /* Calculate FEEDBACK ROW location in IE */
        if( AW.ie){
          NewFeedbackRowLeft = x - window.screenLeft  - AW.getLeft(CellTarget) -  obj.getSelectorWidth() + 8 ;
          NewFeedbackRowTop = y - window.screenTop - AW.getTop(TopRowTG) + 3 ;
        }

        /* Calculate FEEDBACK ROW location in FireFox */
        if(!AW.ie){
          if(rightScroll==0){ NewFeedbackRowLeft = x - AW.getLeft(CellTarget)  - obj.getSelectorWidth() }
          else{ NewFeedbackRowLeft = x   + rightScroll - AW.getLeft(CellTarget) - obj.getSelectorWidth() }

          if(bottomScroll==0){ NewFeedbackRowTop = y - AW.getTop(TopRowTG) + 3; }
          else{ NewFeedbackRowTop = y + bottomScroll - AW.getTop(TopRowTG) + 3 }
        }

        FeedbackRow.style.top=NewFeedbackRowTop;

        // NOTE --- Remove line below to prevent
        // feedback row from moving horizontally
        FeedbackRow.style.left=NewFeedbackRowLeft;
      }

      else if(mouseCelldown){

        var FeedbackRow = RowTarget.cloneNode(true)  ;
        FeedbackRow.id = "FeedbackRow";
        FeedbackRow.style.position = "absolute";
        FeedbackRow.style.width = RowTarget.width;
        FeedbackRow.style.height = RowTarget.height;
        FeedbackRow.style.zIndex = 1000000;
        FeedbackRow.style.MozOpacity = 0.7;
        FeedbackRow.style.filter = "alpha(opacity=70)"

        // CHOSE IF YOU WANT THE FEEDBACK ROW TO BE SHIFTED ONE COLUMN TO THE RIGHT
        // OR SHOULD IT START AT THE SAME HORIZONTAL LOCATION AS THE DRAG ROW
        // This is more noticable when the feedback row is not allowed to move
        // horizontally (comment out line "FeedbackRow.style.left=NewFeedbackRowLeft"
        // in dragRowMouseMove function above.
        //
        RowTarget.parentNode.parentNode.appendChild(FeedbackRow); // Same Level
        //RowTarget.parentNode.parentNode.appendChild(FeedbackRow); // Shifted Right
      }


      /* ---- START AUTO SCROLL CODE ---- */
      if (mouseCelldown){

        var GridHeight=150;
        var ScrollZoneSize=20;
        var NewScrollTop;

        /* Near Top, Scroll grid up if possible */
        if (NewFeedbackRowTop<obj.getScrollTop()+ScrollZoneSize) {
          NewScrollTop=obj.getScrollTop()-ScrollZoneSize;
          if (NewScrollTop<0) NewScrollTop=0;
          obj.setScrollTop(NewScrollTop);
        }

        /* Near Bottom, Scroll grid down if possible */
        if (NewFeedbackRowTop>GridHeight+obj.getScrollTop()-obj.getHeaderHeight()-ScrollZoneSize) {
          obj.setScrollTop(obj.getScrollTop()+ScrollZoneSize);
          NewScrollTop=obj.getScrollTop()+ScrollZoneSize;
          if (NewScrollTop>MaxScrollTop) NewScrollTop=MaxScrollTop;
          obj.setScrollTop(NewScrollTop);
        }
      }
      /* ---- END AUTO SCROLL CODE ---- */

    }


    /***********************/
    // THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS
    obj.onCellMouseDown     = function(event, column, row){ dragstart(event, column, row) };
    obj.onCellMouseUp       = function(event, column, row){ if (startrow) { dragstop(column, row) }};
    obj.setEvent("onmousemove", dragRowMouseMove);
    RowsArea.setEvent("onmousedown", dragRowStart);

    document.write(obj);

</script>

<br>
<button onclick="AddNewRowBelowSelectedRow()">Add New Row Below Selected Row</button>
<button onclick="DeleteSelectedRow()">Delete Selected Row</button>
<hr>
This has been tested using AW 2.0 (standard/final) and IE and Firefox 1.0. It has some limitations
<ul>
<li>Only works on ARRAY based grid.
<li>Array is manipulated directly using splice (instead of addRow / deleteRow).
<li>Sorting is not supported so it is disabled
</ul>

</body>
</script>
</html>
Rob Francis
February 9,
Opps ... The line of code that reads:

//RowTarget.parentNode.parentNode.appendChild(FeedbackRow); // Shifted Right


Should be:

//RowTarget.parentNode.appendChild(FeedbackRow); // Shifted Right


I forgot to remove one of the ".parentNode" to shift it.
Rob Francis
February 9,
Great !! Fantastic !!
Rob, You'r a Genius,
Now hiden bug on auto-scroll areas no longer happens, and runs perfect under FF.

Maybe a "next step" to consider is drag-drop between two side by side
grids (just one of my crazy Ideas) -- ;-)
Thanks
Carlos
February 10,
#@!#(%& , Sorry again, cause I was confusing you with a hiden-row-bug that does not exist --- I forgot my own fix while testing!!! virtialmode, anyway did you notice that with your last version it is almost working well without it ???
And a very small issue - the scroll-down zone differs if horiz-scrollbar is painted or not. ( resize first colum untill it apear to test it)
(but I don't know an easy way to ask when it is )
Thks
Carlos
February 11,
Hi Carlos,

Opps, I thought I had the virtualmode=false in the sample ... I didn't mean to leave that out and I have it in my real code. Sorry.

Good catch on the scroll bar adjustment... try this code:

/* ---- START AUTO SCROLL CODE ---- */
      if (mouseCelldown){

        var GridHeight=150;
        var ScrollZoneSize=20;
        var NewScrollTop;
    var HorizontalScrollBarAdjustment=20;

    
    /* If Horizontal Scroll Bar is not present then set adjustment to 0 */
    if ( obj.getScrollWidth()-document.getElementById("myGrid").offsetWidth+2 <= 0 ) { HorizontalScrollBarAdjustment=0 }

        /* Near Top, Scroll grid up if possible */
        if (NewFeedbackRowTop<obj.getScrollTop()+ScrollZoneSize) {
          NewScrollTop=obj.getScrollTop()-ScrollZoneSize;
          if (NewScrollTop<0) NewScrollTop=0;
          obj.setScrollTop(NewScrollTop);
        }

        /* Near Bottom, Scroll grid down if possible */
        if (NewFeedbackRowTop>GridHeight+obj.getScrollTop()-obj.getHeaderHeight()-ScrollZoneSize-HorizontalScrollBarAdjustment) {
          obj.setScrollTop(obj.getScrollTop()+ScrollZoneSize);
          NewScrollTop=obj.getScrollTop()+ScrollZoneSize;
          if (NewScrollTop>MaxScrollTop) NewScrollTop=MaxScrollTop;
          obj.setScrollTop(NewScrollTop);
        }
      }
      /* ---- END AUTO SCROLL CODE ---- */
Rob Francis
February 11,
I've improved this section of code. When reaching the max scroll down the old version would still do the setScrollTop call so the screen would flicker. This version only does the call when the value has changed.

/* ---- START AUTO SCROLL CODE ---- */
      if (mouseCelldown){

        var GridHeight=150;
        var ScrollZoneSize=20;
        var NewScrollTop;
    var HorizontalScrollBarAdjustment=20;

    
    /* If Horizontal Scroll Bar is not present then set adjustment to 0 */
    if ( obj.getScrollWidth()-document.getElementById("myGrid").offsetWidth+2 <= 0 ) { HorizontalScrollBarAdjustment=0 }

        /* Near Top, Scroll grid up if possible */
        if (NewFeedbackRowTop<obj.getScrollTop()+ScrollZoneSize) {
          NewScrollTop=obj.getScrollTop()-ScrollZoneSize;
          if (NewScrollTop<0) NewScrollTop=0;
          obj.setScrollTop(NewScrollTop);
        }

        /* Near Bottom, Scroll grid down if possible */
        if (NewFeedbackRowTop>GridHeight+obj.getScrollTop()-obj.getHeaderHeight()-ScrollZoneSize-HorizontalScrollBarAdjustment) {
            NewScrollTop=obj.getScrollTop()+ScrollZoneSize;
            if (NewScrollTop>MaxScrollTop) NewScrollTop=MaxScrollTop;
            if (NewScrollTop>=obj.getScrollTop()) obj.setScrollTop(NewScrollTop);
        }
      }
      /* ---- END AUTO SCROLL CODE ---- */


Also, Geoff ... I liked your suggestions earlier about changing the border (ex. 3px) to highlight the drop point and to also change the cursor. I gave this a try but it requires using obj.refresh which breaks the visual feedback row. Another possible way to do it would be to put that in the mouseover style. However, the drop location is above if dragging up and below if dragging down.

Rob Francis
February 11,
Rob, e-mail me the updated code and I'll get it put up on the demo page. I think the version that's up there is a few versions old.

Thanks
Jim Hunter (www.FriendsOfAW.com)
February 11,
Rob,
Yes cursor is a tricky little thing I could not make it work, but it sure would be cute!!!
For moving down can't you just use border botton instead of top...


BTW: my personal preference is to always put a DROP above (or below) which ever direction you move... (just seems more natural... to me)
I'm pretty sure that is the way most applications do it, say for example moving Bookmarks in FF...

-geoff

G Cayman
February 11,
Rob, was my fault, If you revise the post history will notice that after virtualmode fix was mentioned your next sample contains it.

I Realize that the whole /* ---- START AUTO SCROLL CODE ---- */ block dont need the if (mouseCelldown){ condition if you put it all before the block:
else if(mouseCelldown){
var FeedbackRow = ..............
Just trying to reduce the if's ( the less conditions .. the faster it can scroll) for cases of hundreds of rows ;-)

For a more "dramatic" effect I would suggest add something like:
FeedbackRow.style.background = "lightblue";
FeedbackRow.style.color = "yellow";
FeedbackRow.style.height = RowTarget.height + 4 ; // or (-2)
Carlos
February 11,
Hi Geoff,

As far as drop location ...

If you are dropping above the starting location then I insert it above the mouseover row. This ensures you can drop it in position #1.

If you are dropping below the starting location then I insert it below the mouseover row. This ensures you can drop it in the last position.

You could change the code to always drop either above or below. If you did that then the mouseover style could include the 3px border.

I tried to do it using setStyle so I could could account for the variable drop location but that doesn't work since the change won't show without a refresh.

Jim ... I will send you the updated code
Rob Francis
February 11,
When I said "put it all before the block:.... "
I mean at the end of the block:
if(FeedbackRow) {
Carlos
February 11,
Anyway I might be wrong here too ( coul be only IE rendering performance) cause under FF the scrolling is pretty fast.
Carlos
February 11,
Here is the full updated code for the sample.

Jim, please use this to update the demo on your site.

Carlos, that 'if statement' is needed. Without it there would be a bug when clicking on the scroll bar... and if it is combined with the other 'if' then it becomes tied to the existance of FeedbackRow.

<html> 
<head> 
<script src="../../runtime/lib/aw.js"></script> 
    <link href="../../runtime/styles/xp/aw.css" rel="stylesheet"></link> 
</head> 
<body> 
This is a drag and drop example to move rows.<br> 
<b>Click and drag a cell to move a row to a new location</b>. 
<hr> 
<style> 
    #myGrid { width: 300px; height:150px;  margin: 0px; padding: 0px} 
    #myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;} 
    #myGrid .aw-alternate-odd  .aw-column-0 {background: #E0E0E0;} 
    #myGrid .aw-alternate-even {background: #E7E7D6;} 
    #myGrid .aw-alternate-odd  {background: #F7F3E7;} 
    #myGrid .aw-rows-selected {background: #316ac5;} 
    #myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;} 
    #myGrid .aw-rows-selected .aw-column-0 {color: red;} 
    #myGrid .aw-mouseover-row {background: lightblue} 
    #myGrid .aw-mouseover-row .aw-column-0 {background: lightblue}
    #myGrid {-moz-user-select: none} 
</style> 
<script> 
    var HeaderText = ["Number","Description"]; 
    var CellText = [ 
        ["1","Description 1"], 
        ["2","Description 2"], 
        ["3","Description 3"], 
        ["4","Description 4"], 
        ["5","Description 5"], 
        ["6","Description 6"], 
        ["7","Description 7"], 
        ["8","Description 8"], 
        ["9","Description 9"], 
        ["10","Description 10"], 
        ["11","Description 11"], 
        ["12","Description 12"], 
        ["13","Description 13"], 
        ["14","Description 14"], 
        ["15","Description 15"] 
    ]; 

    var obj = new AW.UI.Grid; 

    obj.setId("myGrid"); 
    obj.setHeaderText(HeaderText); 
    obj.setCellText(CellText); 
    obj.setColumnCount(2); 
    obj.setRowCount(15); 
    obj.setVirtualMode(false); 

    // DISABLE SORTING - This simple example will not work if sorted 
    obj.onHeaderClicked = function(event,index){return 'disabled'}; 

    obj.setSelectionMode("single-row"); 
    obj.setSelectorVisible(true); 
    obj.setSelectorWidth(25); 


    /**********************/ 
    function DeleteSelectedRow(){ 
      var insertindex=obj.getSelectedRows([0]); 
      CellText.splice(insertindex,1); 
      obj.setRowCount(obj.getRowCount()-1); 
      obj.refresh(); 
    } 

    /**********************/ 
    function AddNewRowBelowSelectedRow(){ 
      var insertindex=obj.getSelectedRows([0]); 
      CellText.splice((insertindex*1)+1,0,["new","new"]); 
      obj.setRowCount(obj.getRowCount()+1); 
      obj.refresh(); 
    } 


    // DRAGGING FUNCTIONS 
    var startrow, endrow ; 
    var MaxScrollTop; 
    var RowsArea = obj.getRowsTemplate(); 
    var mouseCelldown = false; 
    var RowTarget; 
    var CellTarget; 
    var TopRowTG; 
    var rightScroll; 
    var bottomScroll; 

    /**********************/ 
    // BEGIN DRAG & DROP - THIS RECORDS THE STARTING (DRAG) ROW 
    function dragstart(e, column, row){ 
      startrow=row; 
      MaxScrollTop=obj.getScrollHeight() - document.getElementById("myGrid").offsetHeight + 18; 
    } 

    /**********************/ 
    // END DRAG & DROP - THIS CODE MOVES THE DRAG ROW TO THE DROP LOCATION 
    function dragstop(column, row){ 

        mouseCelldown=false; 
        stoprow=row; 

        // NOTE: THE TIMES 1 (*1) IN ALL CODE BELOW 
        // IS TO MAKE SURE JAVASCRIPT TREATS THE VARS 
        // AS NUMBERS INSTEAD OF STRINGS 
        // 
        // THIS CODE ONLY WORKS FOR A GRID BASED ON AN ARRAY. 
        // IT USES THE "splice" COMMAND TO ADD AND DELETE 
        // ROWS DIRECTLY IN THE ARRAY. 
        // 
        // ex. splice (start position, num of rows to delete, optional data to insert) 
        // To delete 1 row use splice(rowindex,1) 
        // To add a row without deleting another use spice(rowindex,0,newdata) 

        // GET CONTENTS OF DRAG ROW... NOTE THIS GETS THE ENTIRE ROW 
        // SUCH AS ["7","Description 7"] 
        var startrowcontents = CellText[startrow]; 

        if ( (stoprow*1) > (startrow*1)) { 
            // DRAG AND DROP IN DOWNWARD DIRECTION 
            CellText.splice((stoprow*1)+1,0,startrowcontents); //INSERT DRAG ROW BELOW DROP ROW 
            CellText.splice(startrow,1); // DELETE DRAG ROW 

        // DRAG AND DROP IN UPWARD DIRECTION 
        } else if ((stoprow*1) < (startrow*1)) { 
            CellText.splice((stoprow*1),0,startrowcontents); // INSERT DRAG ROW ABOVE DROP ROW 
            CellText.splice((startrow*1)+1,1); // DELETE DRAG ROW, NOTE IT IS PUSHED DOWN 1 BECAUSE OF THE INSERT ABOVE 
        } 

        // FYI... IF YOU WANTED TO HARD CODE THE DATA TO INSERT IT WOULD LOOK LIKE THIS 
        //  CellText.splice(stoprow,0,["17","Description 17"]); 

        obj.setSelectedRows([stoprow]); 
        obj.refresh(); 
    } 


    /**********************/ 
    // BEGIN DRAG & DROP - CAPTURE DATA NEEDED TO CREATE THE 
    // VISUAL FEEDBACK ROW THAT IS DISPLAYED WHILE ROW IS BEING DRAGGED 
    var dragRowStart = function(event) { 

        if(!AW.ie) {  CellTarget = event.target  } 
        else{ CellTarget = event.srcElement  } 

        var sECId = CellTarget.id ; 
        if (sECId.indexOf("-box-text") > 0 ){ 
          RowTarget = CellTarget.parentNode.parentNode } 
        else { 
          RowTarget = CellTarget.parentNode; 
        } 

        rightScroll = obj.getScrollLeft(); 
        bottomScroll = obj.getScrollTop(); 

        TopRowTG = RowTarget.parentNode.firstChild; 

        RowTarget.width=RowTarget.offsetWidth; 
        RowTarget.height=RowTarget.offsetHeight; 

        mouseCelldown = true; 
    } 


    /**********************/ 
    // DRAG IN PROGRESS - 
    // 1) MOVES THE VISUAL FEEDBACK ROW 
    // 2) AUTO SCROLLS THE GRID IF NEEDED 
    var dragRowMouseMove = function(event) { 

      var NewFeedbackRowTop=0; 
      var NewFeedbackRowLeft=0; 

      bottomScroll = obj.getScrollTop(); 

      if(!AW.ie) { var x1 = event.pageX  ; var y1 = event.pageY ; } 
      else{ var x1 = event.clientX ; var y1=event.clientY } 

      if(!AW.ie) { var x = event.pageX  ; var y = event.pageY ; } 
      else{ var x = event.screenX ; var y=event.screenY } 


      var FeedbackRow = document.getElementById('FeedbackRow'); 


      if(FeedbackRow) { 

    /************************************/
    /* This block of code moves the     */
        /* feedback row to follow the mouse */
    /************************************/

        /* Calculate FEEDBACK ROW location in IE */ 
        if( AW.ie){ 
          NewFeedbackRowLeft = x - window.screenLeft  - AW.getLeft(CellTarget) -  obj.getSelectorWidth() + 8 ; 
          NewFeedbackRowTop = y - window.screenTop - AW.getTop(TopRowTG) + 3 ; 
        } 

        /* Calculate FEEDBACK ROW location in FireFox */ 
        if(!AW.ie){ 
          if(rightScroll==0){ NewFeedbackRowLeft = x - AW.getLeft(CellTarget)  - obj.getSelectorWidth() } 
          else{ NewFeedbackRowLeft = x   + rightScroll - AW.getLeft(CellTarget) - obj.getSelectorWidth() } 

          if(bottomScroll==0){ NewFeedbackRowTop = y - AW.getTop(TopRowTG) + 3; } 
          else{ NewFeedbackRowTop = y + bottomScroll - AW.getTop(TopRowTG) + 3 } 
        } 

        FeedbackRow.style.top=NewFeedbackRowTop; 

        // NOTE --- Remove line below to prevent 
        // feedback row from moving horizontally 
        if ( document.getElementById('allowhorizonalmove').checked==true) {
           FeedbackRow.style.left=NewFeedbackRowLeft; 
        }

      } 

      else if (mouseCelldown) { 


    /***********************************************/
    /* This block of code CREATES the feedback row */
        /* at the beginning of the drag operation      */
    /***********************************************/

        var FeedbackRow = RowTarget.cloneNode(true)  ; 
        FeedbackRow.id = "FeedbackRow"; 
        FeedbackRow.style.position = "absolute"; 
        FeedbackRow.style.width = RowTarget.width; 
        FeedbackRow.style.height = RowTarget.height; 
        FeedbackRow.style.zIndex = 1000000; 
        FeedbackRow.style.MozOpacity = 0.7; 
        FeedbackRow.style.filter = "alpha(opacity=70)" 
        FeedbackRow.style.background = "black"; 
        FeedbackRow.style.color="yellow";
        FeedbackRow.style.padding = "1"; 

        // CHOSE IF YOU WANT THE FEEDBACK ROW TO BE SHIFTED ONE COLUMN TO THE RIGHT 
        // OR SHOULD IT START AT THE SAME HORIZONTAL LOCATION AS THE DRAG ROW 
        // This is more noticable when the feedback row is not allowed to move 
        // horizontally (comment out line "FeedbackRow.style.left=NewFeedbackRowLeft" 
        // in dragRowMouseMove function above. 
        // 
        RowTarget.parentNode.parentNode.appendChild(FeedbackRow); // Same Level 
        //RowTarget.parentNode.appendChild(FeedbackRow); // Shifted Right 
 
     } 


      /* ---- START AUTO SCROLL CODE ---- */ 
      if (mouseCelldown){ 

        var GridHeight=150; 
        var ScrollZoneSize=20; 
        var NewScrollTop; 
        var HorizontalScrollBarAdjustment=20; 

     
        /* If Horizontal Scroll Bar is not present then set adjustment to 0 */ 
        if ( obj.getScrollWidth()-document.getElementById("myGrid").offsetWidth+2 <= 0 ) { HorizontalScrollBarAdjustment=0 } 

        /* Near Top, Scroll grid up if possible */ 
        if (NewFeedbackRowTop<obj.getScrollTop()+ScrollZoneSize) { 
          NewScrollTop=obj.getScrollTop()-ScrollZoneSize; 
          if (NewScrollTop<0) NewScrollTop=0; 
          obj.setScrollTop(NewScrollTop); 
        } 

        /* Near Bottom, Scroll grid down if possible */ 
        if (NewFeedbackRowTop>GridHeight+obj.getScrollTop()-obj.getHeaderHeight()-ScrollZoneSize-HorizontalScrollBarAdjustment) { 
            NewScrollTop=obj.getScrollTop()+ScrollZoneSize; 
            if (NewScrollTop>MaxScrollTop) NewScrollTop=MaxScrollTop; 
            if (NewScrollTop>=obj.getScrollTop()) obj.setScrollTop(NewScrollTop); 
        } 
      } 
      /* ---- END AUTO SCROLL CODE ---- */ 

    } 


    /***********************/ 
    // THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS 
    obj.onCellMouseDown     = function(event, column, row){ dragstart(event, column, row) }; 
    obj.onCellMouseUp       = function(event, column, row){ if (startrow) { dragstop(column, row) }}; 
    obj.setEvent("onmousemove", dragRowMouseMove); 
    RowsArea.setEvent("onmousedown", dragRowStart); 

    document.write(obj); 

</script> 
<INPUT TYPE=CHECKBOX NAME="allowhorizonalmove"> Allow Horizontal Move of Drag Feedback Row
<br> 
<button onclick="AddNewRowBelowSelectedRow()">Add New Row Below Selected Row</button> 
<button onclick="DeleteSelectedRow()">Delete Selected Row</button> 
<hr> 


This has been tested using AW 2.0 (standard/final) and IE and Firefox 1.0. It has some limitations 
<ul> 
<li>Only works on ARRAY based grid. 
<li>Array is manipulated directly using splice (instead of addRow / deleteRow). 
<li>Sorting is not supported so it is disabled 
</ul> 

</body> 
</script> 
</html>
Rob Francis
February 11,
Opps (again) ...

The auto scroll doesn't work in FireFox because I forgot to add the ID tag for the check box.

The line:

<INPUT TYPE=CHECKBOX NAME="allowhorizonalmove">


Should be:

<INPUT TYPE=CHECKBOX NAME="allowhorizonalmove" id="allowhorizonalmove">
Rob Francis
February 12,
Rob, A different version with ( No need to define gridHeight manually and also I removed NewFeedbackRowXXX )
Note:// new variables and some renamed [xg for x1] , [downScroll for bottomScroll] (new ones are defined at the top).

var RowsArea = obj.getRowsTemplate();  
var mouseCelldown = false;  
var RowTarget;  
var CellTarget;  
var TopRowTG;  
var rightScroll;  
var downScroll; 

 var GridHeight;   
 var GridTop ;  
 var  MaxScrollTop;
 var ScrollZoneSize=21;  
 var HorizSBarAdj=20;  
 var staticXpos;
 var NewScrollTop;
 
/*****************/  
 var dragColStart = function(event) {   
 
if(!AW.ie) { CellTarget = event.target }  
else{ CellTarget = event.srcElement }  

 var sECId = CellTarget.id ;  
 if (sECId.indexOf("-box-text") > 0 ){ RowTarget = CellTarget.parentNode.parentNode }  
else { RowTarget = CellTarget.parentNode }  

rightScroll = obj.getScrollLeft();  
downScroll = obj.getScrollTop();  

TopRowTG = RowTarget.parentNode.firstChild;  

RowTarget.width=RowTarget.offsetWidth;  
RowTarget.height=RowTarget.offsetHeight;  

GridTop = document.getElementById("myGrid").offsetTop + obj.getHeaderHeight(); ;
GridHeight = document.getElementById("myGrid").offsetHeight ;
staticXpos =  document.getElementById("myGrid").offsetLeft - AW.getLeft(TopRowTG)  ;
MaxScrollTop = obj.getScrollHeight() - GridHeight  + 18; 

if(!AW.ie) { 
 staticXpos = document.getElementById("myGrid").offsetLeft + rightScroll - AW.getLeft(TopRowTG) ;
}

///get column number  
 var arrofcolumns = CellTarget.id.split("-");  

 mouseCelldown = true
}  

/********************************/      

var dragCol = function(event) {  

      if(!AW.ie) { var xg = event.pageX  ; var yg = event.pageY ; }  
      else{ var xg = event.clientX ; var yg=event.clientY }  

      if(!AW.ie) { var x = event.pageX  ; var y = event.pageY ; }  
      else{ var x = event.screenX ; var y=event.screenY }  

var DragRow = document.getElementById('DragRow');  
if(DragRow) {   

   	      //// ---- START AUTO SCROLL CODE ---- ////  
        //// If Horizontal Scroll Bar is not present then set adjustment to 0 //// 
        if ( obj.getScrollWidth()-document.getElementById("myGrid").offsetWidth+3 <= 0 ) { HorizSBarAdj=0 }  
        
        //// Near Top, Scroll grid up if possible ////  
        if ( yg < GridTop + ScrollZoneSize  ) {  
          NewScrollTop =  obj.getScrollTop() - ScrollZoneSize  ;  
          if (NewScrollTop < 0) NewScrollTop=0;  
          obj.setScrollTop(NewScrollTop);  
        } 
        
           ///// Near Bottom, Scroll grid down if possible ////  
        if ( yg > GridTop + GridHeight - obj.getHeaderHeight() - ScrollZoneSize - HorizSBarAdj ) {  
            NewScrollTop = obj.getScrollTop()+ScrollZoneSize ;  
            if (NewScrollTop > MaxScrollTop) NewScrollTop = MaxScrollTop;  
            if (NewScrollTop >= obj.getScrollTop()) obj.setScrollTop(NewScrollTop);  
        }  
              //// ---- END AUTO SCROLL CODE ---- /////  

        if(!AW.ie){  
 DragRow.style.top = y + obj.getScrollTop() - AW.getTop(TopRowTG) + 3
 DragRow.style.left = x - AW.getLeft(CellTarget)  - obj.getSelectorWidth() ;
  }  
    
  if( AW.ie){   
 DragRow.style.top = y - window.screenTop - AW.getTop(TopRowTG) + 3 ;
 DragRow.style.left = x - window.screenLeft  - AW.getLeft(CellTarget) - obj.getSelectorWidth() ;  
  }  

        // NOTE --- Remove line below to prevent feedback row from moving horizontally  
        DragRow.style.left = staticXpos;  


//  if ( document.getElementById('allowhorizonalmove').checked==true) { 
//   DragRow.style.left = staticXpos;  
//   } 

    } 

else if(mouseCelldown){  

var DragRow = RowTarget.cloneNode(true)  
DragRow.id = "DragRow";  
DragRow.style.position = "absolute";  
DragRow.style.width = RowTarget.width;  
DragRow.style.height = RowTarget.height;  
DragRow.style.zIndex = 1000000;  
DragRow.style.MozOpacity = 0.7;   
DragRow.style.filter = "alpha(opacity=70)"; 
DragRow.style.background = "black";  
DragRow.style.color="yellow"; 
DragRow.style.padding = "1";  

RowTarget.parentNode.appendChild(DragRow); 
  } 
 }  
/***********************/  
obj.setEvent("onmousemove", dragCol);  
RowsArea.setEvent("onmousedown", dragColStart);  

 document.write(obj);
Carlos
February 14,
Hi Carlos,

I knew the grid height didn't need to be hard coded but I couldn't figure out the right call at that time... thanks.

Also, I sent you a PM on FriendsofAw.com
Rob Francis
February 14,
Hi carlos and Rob,

great example
I will start with that and try to modify it, to be able to "drag-drop between two side by side grids".
it's not a crazy dreams, it's just what I need to do.
Lucho
February 23,
Hi Lucho,

Many people would like to have an example of drag and drop between grids. Thanks in advance for working on it.

Rob
Rob Francis
February 23,
Since I'm no more inside the same grid, I cannot have the FeedbackRow being an actual row of the grid, so instead I use a simple div, but the onmouseup event is fired on that div and not on my target grid.

Is there a way to forward a mouseup event to the grid to get a
grid.onCellMouseUp(event,row,col), or should I work around to find the row and col ?

If my FeedbackRow div is empty then my target grid get the mouse up event and add the row
Lucho
February 23,
I have a first version that works with Firefox (haven't tried IE)
the FeedbackRow is very basic, it would be great to be able to use something like you had in your example, and I've also cut for now the auto scrolldown in the target grid.
So you drag from the left to the right.

I'm thinking it would be better to keep one extra empty row, so it's easier to drop at the bottom when the list scrolls. Or can we say to the grid to scroll like if there was 16 rows when they are actually 15 ?

Eventually I will add the drag and drop in the target grid for the user to re-order.

btw why does the sort doesn't work ?




<html> 
<head> 
<script src="../../runtime/lib/aw.js"></script> 
    <link href="../../runtime/styles/xp/aw.css" rel="stylesheet"></link> 
</head> 
<body> 
This is a drag and drop example between 2 grids.<br> 
<b>Click and drag a cell to move a row from the left grid to the right grid</b>. 
<hr> <BR><BR>
<style> 
    #myGrid { width: 300px; height:150px;  margin: 0px; padding: 0px} 
    #myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;} 
    #myGrid .aw-alternate-odd  .aw-column-0 {background: #E0E0E0;} 
    #myGrid .aw-alternate-even {background: #E7E7D6;} 
    #myGrid .aw-alternate-odd  {background: #F7F3E7;} 
    #myGrid .aw-rows-selected {background: #316ac5;} 
    #myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;} 
    #myGrid .aw-rows-selected .aw-column-0 {color: red;} 
    #myGrid .aw-mouseover-row {background: lightblue} 
    #myGrid .aw-mouseover-row .aw-column-0 {background: lightblue}
    #myGrid {-moz-user-select: none}
     
    #myTarget { width: 300px; height:150px;  margin: 0px; padding: 0px} 
    #myTarget .aw-alternate-even .aw-column-0 {background: #E0E0E0;} 
    #myTarget .aw-alternate-odd  .aw-column-0 {background: #E0E0E0;} 
    #myTarget .aw-alternate-even {background: #E7E7D6;} 
    #myTarget .aw-alternate-odd  {background: #F7F3E7;} 
    #myTarget .aw-rows-selected {background: #316ac5;} 
    #myTarget .aw-rows-selected .aw-column-1 {background: #316ac5;} 
    #myTarget .aw-rows-selected .aw-column-0 {color: red;} 
    #myTarget .aw-mouseover-row {background: lightblue} 
    #myTarget .aw-mouseover-row .aw-column-0 {background: lightblue}
    #myTarget {-moz-user-select: none} 

</style> 
<div id="englob" onmousemove="dragRowMouseMove(event)" >
<script> 
    var HeaderText = ["Number","Description"]; 
    var CellText = [ 
        ["1","Description 1"], 
        ["2","Description 2"], 
        ["3","Description 3"], 
        ["4","Description 4"], 
        ["5","Description 5"], 
        ["6","Description 6"], 
        ["7","Description 7"], 
        ["8","Description 8"], 
        ["9","Description 9"], 
        ["10","Description 10"], 
        ["11","Description 11"], 
        ["12","Description 12"], 
        ["13","Description 13"], 
        ["14","Description 14"], 
        ["15","Description 15"] 
    ]; 
    
    var TargetCellText = [[]]; //If i don't specify that we have an array of array here, it will put the array in the first column

    var obj = new AW.UI.Grid; 

    obj.setId("myGrid"); 
    obj.setHeaderText(HeaderText); 
    obj.setCellText(CellText); 
    obj.setColumnCount(2); 
    obj.setRowCount(15); 
    obj.setVirtualMode(false); 

    // DISABLE SORTING - This simple example will not work if sorted 
    obj.onHeaderClicked = function(event,index){return 'disabled'}; 

    obj.setSelectionMode("single-row"); 
    obj.setSelectorVisible(true); 
    obj.setSelectorWidth(25); 


    var target = new AW.UI.Grid; 
    target.setId("myTarget"); 
    target.setHeaderText(HeaderText);    
    target.setCellText(TargetCellText);  
    target.setColumnCount(2); 
    target.setRowCount(1); 
    target.setVirtualMode(false); 
    

    // DISABLE SORTING - This simple example will not work if sorted 
    target.onHeaderClicked = function(event,index){return 'disabled'}; 

    target.setSelectionMode("single-row"); 
    target.setSelectorVisible(true); 
    target.setSelectorWidth(25); 



    /**********************/ 
    function DeleteSelectedRow(){ 
      var insertindex=obj.getSelectedRows([0]); 
      CellText.splice(insertindex,1); 
      obj.setRowCount(obj.getRowCount()-1); 
      obj.refresh(); 
    } 

    /**********************/ 
    function AddNewRowBelowSelectedRow(){ 
      var insertindex=obj.getSelectedRows([0]); 
      CellText.splice((insertindex*1)+1,0,["new","new"]); 
      obj.setRowCount(obj.getRowCount()+1); 
      obj.refresh(); 
    } 


    // DRAGGING FUNCTIONS 
    var startrow; 
    
    /**********************/ 
    // BEGIN DRAG & DROP - THIS RECORDS THE STARTING (DRAG) ROW 
    function dragstart(e, column, row){ 
      startrow=row;           
      
      var FeedbackRow = document.getElementById('FeedbackRow');       
      FeedbackRow.style.display="";       
      dragRowMouseMove(e);
      var content = '<table width="300"><tr><td>'+CellText[row][0]+'</td><td>'+CellText[row][1]+'</td></tr></table>';      
      FeedbackRow.innerHTML=content;
    } 

    /**********************/ 
    // END DRAG & DROP - THIS CODE MOVES THE DRAG ROW TO THE DROP LOCATION 
    function dragstop(){ 
      startrow=undefined;
      var FeedbackRow = document.getElementById('FeedbackRow');       
      FeedbackRow.style.display="none";        
    } 


     var dragRowMouseMove = function(event) {      
     
       var FeedbackRow = document.getElementById('FeedbackRow'); 
      if (FeedbackRow.style.display!="none")
      { 
           // DRAG IN PROGRESS - 
           // 1) MOVES THE VISUAL FEEDBACK ROW 
           // 2) AUTO SCROLLS THE TARGET GRID IF NEEDED 
           
           if(!AW.ie) { var x = event.pageX  ; var y = event.pageY ; } 
           else{ var x = event.screenX ; var y=event.screenY } 

       FeedbackRow.style.top=y-18; 
       FeedbackRow.style.left=x-100; 
       document.getElementById('debug').innerHTML="x="+x +" y="+y;
      }       	      
    } 


    /***********************/ 
    // THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS 
    obj.onCellMouseDown     = function(event, column, row){ dragstart(event, column, row)   }; 
    obj.onCellMouseUp       = function(event, column, row){ if (startrow) dragstop()  };     
    obj.setEvent("onmousemove", dragRowMouseMove);     

    var yDropMin=0;
    var yDropMax=0;
    var xDropMin=0;
    var xDropMax=0;
    var rowHeight=0;

    target.onCellMouseUpForward = function(event) {
       if(!AW.ie) { var x = event.pageX  ; var y = event.pageY ; } 
       else{ var x = event.screenX ; var y=event.screenY } 
       
       // check if the mouse up is in the target grid       
       var gridHeight=150;
       var gridWidth=300;
       var selectorWidth=0;
       if (target.getSelectorVisible())
       {
            selectorWidth=target.getSelectorWidth();
       }

       if (yDropMin==0)
       {
          var el = target.getCellTemplate(0, 0).element();    
          rowHeight =el.offsetHeight;                
          yDropMin = AW.getTop(el); // y of first row 
          yDropMax = yDropMin - target.getHeaderHeight()+gridHeight;
          xDropMin = AW.getLeft(el); // x of first row 
          xDropMax = xDropMin + gridWidth-selectorWidth; // x of first row           
       }

       if (x>xDropMin && x<xDropMax && y>yDropMin && y<yDropMax)
       {
          // mouse up is in the grid, compute row and forward event             
          // we need to tinker that with the position of the scrollbar
          target.onCellMouseUp(event,0,Math.round((y-yDropMin+target.getScrollTop())/rowHeight));                     
       }           
    
    }

    target.onCellMouseUp = function(event, column, row) {    
    if (startrow) {                        	   
           if (TargetCellText[0][0]==undefined)
           {        
            TargetCellText[0][0]=CellText[startrow][0];
                TargetCellText[0][1]=CellText[startrow][1];
           }
           else
           {
       	       var insertindex=row;        	   
       	       if (insertindex>target.getRowCount()-1)
       	       {
       	           insertindex=target.getRowCount();
       	       }
       	       //alert("add val from row " + startrow + " at row " + row  +" insert index= " + insertindex );
       	          	
       	       TargetCellText.splice((insertindex*1),0,CellText[startrow]); 
       	       target.setRowCount(target.getRowCount()+1);        	       
       	   }
           
           target.refresh(); 
           dragstop();
       	} 
    
    }; 
    
    document.write(obj); 
    document.write(target); 
    document.onmouseup = function () { // stop draging the row when onmouseup happens out of the grids
        if (startrow) { dragstop() ;  }
    }
    

</script> 
<br> 
<button onclick="AddNewRowBelowSelectedRow()">Add New Row Below Selected Row</button> 
<button onclick="DeleteSelectedRow()">Delete Selected Row</button> 
<hr> 


This has been tested using AW 2.0 (standard/final) and IE and Firefox 1.0. It has some limitations 
<ul> 
<li>Only works on ARRAY based grid. 
<li>Array is manipulated directly using splice (instead of addRow / deleteRow). 
<li>Sorting is not supported so it is disabled 
</ul> 
</div>

<div id="FeedbackRow" style="position:absolute;display:none" onmouseup="target.onCellMouseUpForward(event)">
</div>

<div id="debug">
</div>

<div id="debug2">
</div>
</body> 
</script> 
</html>
Lucho
February 23,
Hi Lucho,

Great job! I ran it under IE and the only glitch compared to FF is the feedback row is not in the same spot. Other than that it works fine in IE.

Sorting is disabled in the original because I didn't think it would work with the way I was splicing the data source array. You can enable sorting and give it a try. The line is:

// DISABLE SORTING - This simple example will not work if sorted
obj.onHeaderClicked = function(event,index){return 'disabled'};

Rob Francis
February 23,
Hi Lucho,

I forgot to suggest that when you make the next revision to your sample please post it as a brand new thread. It is a great example and I'm worried that it will get lost in this thread. As the title you could use something like "Example of Drag and Drop between 2 grids" so it is easy to find.

Thanks again.
Rob Francis
February 24,
Rob, to keep your sample compatible with sorting you need to do something like:
(just replace the whole dragstop function whith all this)
var SortedIndices=[]; 
     
///// clone indices array & fill (when empty)/////////
  for (i=0;i<CellText.length;i++){ SortedIndices.push(i) } 
   
    ///////// WHEN HEADER CLICKED ////////////
  obj.onHeaderClicked = function(event, index){
  window.setTimeout(function(){
  SortedIndices = obj.getRowIndices();
  },30);
   }

    // END DRAG & DROP - THIS CODE MOVES THE DRAG ROW TO THE DROP LOCATION  
    function dragstop(column, row){  

        mouseCelldown=false;  
        stoprow=row;  

        var startrowcontents = CellText[startrow];  

var indexfrom ;
var  indexto ;

   for (i=0;i<SortedIndices.length;i++){ 
if(SortedIndices[i] == startrow){ indexfrom = i }
if(SortedIndices[i] == stoprow){ indexto = i }
}

var rowmoved = SortedIndices[indexfrom];

var x=indexfrom;
if(indexfrom<indexto){
 while( x<indexto ){ SortedIndices[x]=SortedIndices[x+1] ; x++ ; }
 }

if(indexfrom>indexto){
 while( x>indexto ){ SortedIndices[x]=SortedIndices[x-1] ; x-- ; }
 }
 
 SortedIndices[indexto]=rowmoved ;
 
  obj.setRowIndices(SortedIndices);
    obj.setSelectedRows([stoprow]);  
    }

Carlos
February 26,
Also Add & Delete functions need some new code:

function DeleteSelectedRow(){  
 var insertindex=obj.getSelectedRows();
    for (i=0;i<SortedIndices.length;i++){ 
if(SortedIndices[i] == insertindex){ SortedIndices.splice(i, 1); }
}
 obj.setRowCount(obj.getRowCount()-1);
  obj.setRowIndices(SortedIndices);
    }  

    /**********************/  
       
   function AddNewRowBelowSelectedRow(){  
      var insertindex=obj.getSelectedRows();  
      CellText.push(["new","new"])
    for (i=0;i<SortedIndices.length;i++){ 
if(SortedIndices[i] == insertindex){ SortedIndices.splice( i+1, 0, CellText.length-1 ); }
}
      obj.setRowCount(obj.getRowCount()+1);  
        obj.setRowIndices(SortedIndices);
    }
Carlos
February 26,
Thanks Carlos.

For my use (drag and drop rows in 1 grid), it doesn't make sense for me to allow sorting since I want the user to set the row order. I also create the array in the proper initial order. However, maybe for other people they can think of a reason to enable the sorting.

Also, in Lucho's example (drag and drop rows between 2 grids) it could be very useful. Hopefully your changes will help him too.
Rob Francis
February 26,
sounds great, hope I will have time to look at that today or tomorrow.
Lucho
February 28,
Hey Rob,

A question please. In your drag-and-drop example as hosted on friendsofaw.com, you have two functions that start things off: dragstart(e, column, row) and dragRowStart(event).

As far as I can tell, the "e" argument passes to dragstart() has the same srcElement as the "event" passed to dragRowStart(). In which case, I don't understand why the two methods can't be combined into one.

Perhaps is a browser-dependency thing?

Thanks in advance.
LostInSpace
April 6,
Hi

I want to implement the same type of functionalities in a grid for my web application.My webapplication is a J2EE presentation component and we use using JSP/Struts based architechture.Is the grid be fully functional with JSP/Struts

I want both drag and drop as well as I want to add the nested Grid to my web application.I saw the drag and drop in Rows.Can this be implemented in columns?

Thanks
Vikramaditya Garg
vikramaditya.garg@fidelity.co.in


Vikramaditya Garg
April 13,
Hi Vikramaditya!

I got the same request as you.
Have you found anything yet?

Has anybody got a code snippet for changing the column order?
If so, please let me know

Thanks
Nice regards
Werner
register@sosgmbh.at
Werner
April 14,
Hi LostInSpace,

Sorry for the slow reply. I haven't been on this forum for awhile because I've got the AW code pretty stable in my project and am working on other parts now :)

The sample above was hacked together using multiple other sample from the forum. If you think those can be combined then give it a try. I didn't spend too much time trying to optimize it.

Good luck,
Rob
Rob Francis
April 20,
Very cool stuff - 1 thing that would make this thing really great for sorting purposes would be if you could drag and drop multiple rows at a time. For example, if you could click on the selectors in "multi-row" mode to select which ones you wanted to drag. Then, when you actually clicked on one of the cells it started dragging. That way, if you wanted to move the top two rows to the bottom you could do it with one move, not two. What do you think?
Chris
May 19,
Hi,

I found what it seems a bug in this wonderful drag-and-drop script:

When there are a few lines in the grid and there is a blank space below them, if you click over the blank space, the script tries to drag all the lines of the script.

You can reproduce this behaviuor in the demo of this script in http://friendsofaw.com/nuke/modules.php?name=Demos when you delete all rows except two or three and click on the blank space of the grid. When you move the mouse all the rows of the grid move also.

I will try to find how to control this, but write this post in case someone knows better this piece of code and can do it faster than me.

Regards.
joakinen
June 22,
joakinen, thanks to point this "bug", there should be several ways to avoid it, my first approach is:
( add this new line at bottom of dragRowStart to break the process if no row is clicked)

var dragRowStart = function(event) { 
.....
.....
         mouseCelldown = true; 

    // this line is new    
       if (sECId.indexOf("-rows") > 0 ){ mouseCelldown = false }
    } ]

Carlos
June 23,
Thanks Carlos, the patch works like a charm!

A question: Is compatible the editing of cells with this drag & drop script? I don't know why the field edit facilities don't work if I add the drag & drop code to my grid...

joakinen
June 28,

Hi,

When you make this grid editable, some strange things happen.
Another bug? I think that the onCellMouseDown/onCellMouseUp events triggered to control the drag&drop process seems to interfere with the editing process.

Steps to reproduce this behaviour using the script published in FriendsOfAW:

STEP 1:change the line
var obj = new AW.UI.Grid;

to this
var obj = new AW.Grid.Extended;


STEP 2: change this line
obj.setSelectionMode("single-row");

to this
obj.setSelectionMode("single-cell");


STEP 3: add this line
obj.setCellEditable(true);



At this point you have editing enabled in the grid, but it works in a weird way: to enter the editing mode in a cell you have to follow this 3-step process: [1] click on the cell, [2] doubleclick on the same cell, and [3] press F2. If you click on the cell and then press F2 (the usual way) nothing happens.

Now if you comment the lines following the comment "THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS", like this

//obj.onCellMouseDown     = function(event, column, row){ dragstart(event, column, row) };
//obj.onCellMouseUp       = function(event, column, row){ if (startrow) { dragstop(column, row) }};
//obj.setEvent("onmousemove", dragRowMouseMove);
//RowsArea.setEvent("onmousedown", dragRowStart);


then editing works perfectly (click & F2) but, of course, you have no drag&drop.

It seems that when I click on a cell to edit it, such click doesn't reach the edit events and is processed only by the drag&drop events. This behaviour is somehow broken by doubleclicking in the cell.

What is the solution to this to make compatible the click&drag action with click&edit?

Regards.
joakinen
July 10,
Hmmmm, any budget to afront it ?? ;-)
Not easy, but after a fast evaluation I think doable, but may require some tests and time (currently not in my priority list) :-(

I would start removing obj.onCellMouseDown/Up and placing its lines inside current events.
HTH
Carlos
July 11,
Perhaps checking inside tj.onCellMouseDown/Up hat SHIFT or ALT is pressed to fireup the drag&drop events and that the basic clicks keep linked to the edit events?
joakinen
July 12,
Not sure, but I see a risk going that direction, Think that the doubleclick event trapped by edition is a combination of two single clicks
(therefore the onCellMouseDown/Up events are "locking" it and fired first)
I maintain my last point, and would remove it ( Although I know that it means rebuild half of this sample and construct a new Drop )
Thanks
Carlos
July 12,

This topic is archived.

See also:


Back to support forum