d28c1fcec0aca9505cc4de7bc07e08ae976ba1ff
tdreszer
  Tue May 31 18:51:29 2011 -0700
Drag and drop of tracks in image will now drag contiguous set of subtracks if dragging side button.  Occasional wierdness when dragging too fast.
diff --git src/hg/js/jquery.tablednd.js src/hg/js/jquery.tablednd.js
index 73e54fa..5fdb9ce 100644
--- src/hg/js/jquery.tablednd.js
+++ src/hg/js/jquery.tablednd.js
@@ -95,30 +95,33 @@
         // Set up the defaults if any
 
         this.each(function() {
             // This is bound to each matching table, set up the defaults and override with user options
             this.tableDnDConfig = jQuery.extend({
                 onDragStyle: null,
                 onDropStyle: null,
                 // Add in the default class for whileDragging
                 onDragClass: "tDnD_whileDrag",
                 onDrop: null,
                 onDragStart: null,
                 scrollAmount: 5,
                 serializeRegexp: /[^\-]*$/, // The regular expression to use to trim row IDs
                 serializeParamName: null, // If you want to specify another parameter name instead of the table ID
                 dragHandle: null, // If you give the name of a class here, then only Cells with this class will be draggable
+                dragObjects: [],   // UCSC: Allows setting multiple rows to be dragged at one time
+                downOffset: 0,     // UCSC: Dragging set, then offset Y to bottom of set
+                upOffset: 0,       // UCSC: Dragging set, then offset Y to bottom of set
                 dragStartIndex : 0
             }, options || {});
             // Now make the rows draggable
             jQuery.tableDnD.makeDraggable(this);
         });
 
         // Now we need to capture the mouse up and mouse move event
         // We can use bind so that we don't interfere with other event handlers
         jQuery(document)
             .bind('mousemove', jQuery.tableDnD.mousemove)
             .bind('mouseup', jQuery.tableDnD.mouseup);
 
         // Don't break the chain
         return this;
     },
@@ -130,31 +133,46 @@
             // We only need to add the event to the specified cells
             var cells = jQuery("td."+table.tableDnDConfig.dragHandle, table);
             cells.each(function() {
                 // The cell is bound to "this"
                 jQuery(this).mousedown(function(ev) {
                     if(ev.button > 1)
                         return true;
                     if(jQuery.tableDnD == undefined)
                         return false;
                     jQuery.tableDnD.dragObject = this.parentNode;
                     jQuery.tableDnD.currentTable = table;
                     jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev);
                     config.dragStartIndex = $(jQuery.tableDnD.dragObject).attr('rowIndex');
                     if (config.onDragStart) {
                         // Call the onDrop method if there is one
-                        config.onDragStart(ev, table, this);
+                        config.onDragStart(ev, table, this.parentNode);
+
+                        /////// UCSC
+                        config.downOffset = 0;
+                        config.upOffset = 0;
+                        if (config.dragObjects.length > 1) {
+                            for(var ix = 0; ix < config.dragObjects.length; ix++) {
+                                var row = config.dragObjects[ix];
+                                var rowIx = $(row).attr('rowIndex');
+                                if (rowIx < config.dragStartIndex)
+                                    config.upOffset -= $(row).height();
+                                else if (rowIx > config.dragStartIndex)
+                                    config.downOffset += $(row).height();
+                            }
+                        }
+                        /////// UCSC
                     }
                     return false;
                 });
             })
         } else {
             // For backwards compatibility, we add the event to the whole row
             var rows = jQuery("tr", table); // get all the rows as a wrapped set
             rows.each(function() {
                 // Iterate through each row, the row is bound to "this"
                 var row = jQuery(this);
                 if (! row.hasClass("nodrag")) {
                     row.mousedown(function(ev) {
                         if (ev.target.tagName == "TD") {
                             jQuery.tableDnD.dragObject = this;
                             jQuery.tableDnD.currentTable = table;
@@ -265,67 +283,105 @@
         if (mousePos.y-yOffset < config.scrollAmount) {
             window.scrollBy(0, -config.scrollAmount);
         } else {
             var windowHeight = window.innerHeight ? window.innerHeight
                     : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
             if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) {
                 window.scrollBy(0, config.scrollAmount);
             }
         }
 
 
         if (y != jQuery.tableDnD.oldY) {
             // work out if we're going up or down...
             var movingDown = y > jQuery.tableDnD.oldY;
             // update the old value
-            jQuery.tableDnD.oldY = y;
+            ////// UCSC  jQuery.tableDnD.oldY = y;  // Do this below, only when rows have moved.
             // update the style to show we're dragging
             if (config.onDragClass) {
+                ////// UCSC
+                if (config.dragObjects.length > 1)
+                    config.dragObjects.addClass(config.onDragClass);
+                else ////// UCSC
                     dragObj.addClass(config.onDragClass);
             } else {
+                ////// UCSC
+                if (config.dragObjects.length > 1)
+                    config.css(config.onDragStyle);
+                else ////// UCSC
                 dragObj.css(config.onDragStyle);
             }
             // If we're over a row then move the dragged row to there so that the user sees the
             // effect dynamically
             var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y);
+            ////// UCSC
+            if (config.dragObjects.length > 1) {
+                if (movingDown)
+                    currentRow = jQuery.tableDnD.findDropTargetRow(config.dragObjects[config.dragObjects.length - 1], y + config.downOffset);
+                else
+                    currentRow = jQuery.tableDnD.findDropTargetRow(config.dragObjects[0], y + config.upOffset);
+            } ////// UCSC
+
             if (currentRow) {
+                ////// UCSC
+                if (config.dragObjects.length > 1) {
+                        if (movingDown && config.dragObjects[config.dragObjects.length - 1] != currentRow) {
+                            try { // use try/catch because sometimes rows go missing when moving down
+                                $( currentRow ).insertBefore( $( config.dragObjects[0] ) );
+                                jQuery.tableDnD.oldY = y;
+                            }
+                            catch (err) { // just put them all back
+                                for(var ix=0;ix < config.dragObjects.length; ix++) {
+                                    $(config.dragObjects[ix]).insertBefore( currentRow );
+                                }
+                            }
+                        } else if (!movingDown && config.dragObjects[0] != currentRow) {
+                            $(config.dragObjects).insertBefore( currentRow );
+                            jQuery.tableDnD.oldY = y;
+                        }
+                } else {  ////// UCSC
+
                 // TODO worry about what happens when there are multiple TBODIES
                 if (movingDown && jQuery.tableDnD.dragObject != currentRow) {
                     jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling);
+                        jQuery.tableDnD.oldY = y;
                 } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) {
                     jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow);
+                        jQuery.tableDnD.oldY = y;
                 }
+
+                }   ////// UCSC
             }
         }
 
         return false;
     },
 
     /** We're only worried about the y position really, because we can only move rows up and down */
     findDropTargetRow: function(draggedRow, y) {
         var rows = jQuery.tableDnD.currentTable.rows;
         for (var i=0; i<rows.length; i++) {
             var row = rows[i];
             var rowY    = this.getPosition(row).y;
             var rowHeight = parseInt(row.offsetHeight)/2;
             if (row.offsetHeight == 0) {
                 rowY = this.getPosition(row.firstChild).y;
                 rowHeight = parseInt(row.firstChild.offsetHeight)/2;
             }
             // Because we always have to insert before, we need to offset the height a bit
             //////////if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) {
-            if ((y > rowY) && (y < (rowY + rowHeight))) { ////////// This was modified by tim because of tall tracks
+            if ((y > rowY) && (y < (rowY + rowHeight))) { ////////// UCSC This was modified by tim because of tall tracks
                 // that's the row we're over
                 // If it's the same as the current row, ignore it
                 if (row == draggedRow) {return null;}
                 var config = jQuery.tableDnD.currentTable.tableDnDConfig;
                 if (config.onAllowDrop) {
                     if (config.onAllowDrop(draggedRow, row)) {
                         return row;
                     } else {
                         return null;
                     }
                 } else {
                     // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic)
                     var nodrop = jQuery(row).hasClass("nodrop");
                     if (! nodrop) {
                         return row;
@@ -340,40 +396,49 @@
     },
 
     mouseup: function(e) {
         if(jQuery.tableDnD == undefined) {
             jQuery(document)
                 .unbind('mousemove')//, jQuery.tableDnD.mousemove);
                 .unbind('mouseup');//, jQuery.tableDnD.mouseup);
             return;
         }
         if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) {
             var droppedRow = jQuery.tableDnD.dragObject;
             var config = jQuery.tableDnD.currentTable.tableDnDConfig;
             // If we have a dragObject, then we need to release it,
             // The row will already have been moved to the right place so we just reset stuff
             if (config.onDragClass) {
+                ////// UCSC
+                if (config.dragObjects.length > 1)
+                    config.dragObjects.removeClass(config.onDragClass);
+                else ////// UCSC
                 jQuery(droppedRow).removeClass(config.onDragClass);
             } else {
+                ////// UCSC
+                if (config.dragObjects.length > 1)
+                    config.dragObjects.css(config.onDropStyle);
+                else ////// UCSC
                 jQuery(droppedRow).css(config.onDropStyle);
             }
             jQuery.tableDnD.dragObject   = null;
             if (config.onDrop) {
                 // Call the onDrop method if there is one
                 config.onDrop(jQuery.tableDnD.currentTable, droppedRow, config.dragStartIndex);
             }
             jQuery.tableDnD.currentTable = null; // let go of the table too
+            config.dragObjects = [];  ////// UCSC
         }
     },
 
     serialize: function() {
         if (jQuery.tableDnD.currentTable) {
             return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable);
         } else {
             return "Error: No Table id set, you need to set an id on your table and every row";
         }
     },
 
     serializeTable: function(table) {
         var result = "";
         var tableId = table.id;
         var rows = table.rows;