674124b7df5f6ed346d129958d9d884b0a493a65
tdreszer
  Wed Jun 1 16:45:10 2011 -0700
Painful work to stop leaking subtrack rows when dragging set.  Temporarily checking in commented out debug code because of the pain to get here.
diff --git src/hg/js/jquery.tablednd.js src/hg/js/jquery.tablednd.js
index 37e53cf..af1251b 100644
--- src/hg/js/jquery.tablednd.js
+++ src/hg/js/jquery.tablednd.js
@@ -98,30 +98,31 @@
             // 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
+                mouseMoving: false,// UCSC: Prevent overlapping calls to mouse move
                 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;
     },
@@ -248,131 +249,174 @@
 
         ///////return {x:left, y:top};
         return {x:left, y:top, height:eHeight};  ///////////// Height was added by tim because of tall tracks
     },
 
     mousemove: function(ev) {
         if(jQuery.tableDnD == undefined) {
             jQuery(document)
                 .unbind('mousemove')//, jQuery.tableDnD.mousemove);
                 .unbind('mouseup');//, jQuery.tableDnD.mouseup);
             return;
         }
         if (jQuery.tableDnD.dragObject == null) {
             return;
         }
+        ////////// UCSC
+        if (jQuery.tableDnD.currentTable.mouseMoving == true)
+            return;
+        jQuery.tableDnD.currentTable.mouseMoving = true;
+        ////////// UCSC
 
         var dragObj = jQuery(jQuery.tableDnD.dragObject);
         var config = jQuery.tableDnD.currentTable.tableDnDConfig;
         var mousePos = jQuery.tableDnD.mouseCoords(ev);
         var y = mousePos.y - jQuery.tableDnD.mouseOffset.y;
+        ////////// UCSC added truncation and ignoring old zero
+        y = y.toPrecision();
+        if (jQuery.tableDnD.oldY == 0) {
+            jQuery.tableDnD.oldY = y;
+        }
+        ////////// UCSC
+
         //auto scroll the window
         var yOffset = window.pageYOffset;
         if (document.all) {
             // Windows version
             //yOffset=document.body.scrollTop;
             if (typeof document.compatMode != 'undefined' &&
                     document.compatMode != 'BackCompat') {
                 yOffset = document.documentElement.scrollTop;
             }
             else if (typeof document.body != 'undefined') {
                 yOffset=document.body.scrollTop;
             }
 
         }
 
         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) {
+        ///// UCSC if (y != jQuery.tableDnD.oldY) {
+        if (Math.abs(y - jQuery.tableDnD.oldY) > 8) { //// UCSC some minimal move before handling
             // work out if we're going up or down...
             var movingDown = y > jQuery.tableDnD.oldY;
             // update the old value
             ////// 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
+            // While dragObjects is the set, the order could vary from table order.  Therefore us rowIndexes.
+            var rows = jQuery.tableDnD.currentTable.rows;
+            var firstDragRowIx = 9999; // Discover indexes
+            var lastDragRowIx = 0;
+
             if (config.dragObjects.length > 1) {
+                for (var ix=0;ix < config.dragObjects.length;ix++) {
+                    var thisIx = $( config.dragObjects[ix] ).attr('rowIndex');
+                    if (firstDragRowIx > thisIx)
+                        firstDragRowIx = thisIx;
+                    if (lastDragRowIx < thisIx)
+                        lastDragRowIx = thisIx;
+                }
                 if (movingDown)
-                    currentRow = jQuery.tableDnD.findDropTargetRow(config.dragObjects[config.dragObjects.length - 1], y + config.downOffset);
+                    currentRow = jQuery.tableDnD.findDropTargetRow(rows[lastDragRowIx], y + config.downOffset);
                 else
-                    currentRow = jQuery.tableDnD.findDropTargetRow(config.dragObjects[0], y + config.upOffset);
+                    currentRow = jQuery.tableDnD.findDropTargetRow(rows[firstDragRowIx], 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
-                                // can't just insert currentRow above, because there may be more than one row that needs to move up
-                                //$( currentRow ).insertBefore( $( config.dragObjects[0] ) );
-                                var curRowIx = $( currentRow ).attr('rowIndex');
-                                if (curRowIx == (jQuery.tableDnD.currentTable.rows.length - 1)) {
-                                    // Even though this is method is bad on fast drags,
-                                    // getting to the end seems to only work on slow moves anyway.
-                                    // plus numerous other strateges failed to get this to work at all.
-                                    $( currentRow ).insertBefore( $( config.dragObjects[0] ) );
-                                } else
-                                    $(config.dragObjects).insertBefore( $(currentRow).next() );
-                                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 );
+                    var targetRowIx = $( currentRow ).attr('rowIndex');
+                    if (targetRowIx >= 0 && targetRowIx < rows.length) {
+
+                        if (movingDown) { // && config.dragObjects[config.dragObjects.length - 1] != currentRow) {
+                            // A whole new tack:  since movingUp never fails, always move target (and others) up
+                            if ((lastDragRowIx - firstDragRowIx) == (config.dragObjects.length - 1)
+                            &&  firstDragRowIx >= 0
+                            &&  lastDragRowIx < targetRowIx) {
+                                var plusIx=0;
+                                for(var ix=lastDragRowIx+1; ix <= targetRowIx; ix++) {
+                                    //try { // use try/catch because sometimes rows go missing when moving
+                                        $( rows[ix] ).insertBefore( $( rows[firstDragRowIx + plusIx] ) );
+                                        plusIx++;
+                                    //} catch (err) {
+                                    //    warn('movingDown: lastDragRowIx:'+lastDragRowIx+' targetRowIx:'+targetRowIx+' y:'+y+' oldY:'+jQuery.tableDnD.oldY+'<BR>' + err);
+                                    //}
                                 }
+                                jQuery.tableDnD.oldY = y;
+                            } //else
+                              //  warn('down blocked: targetRowIx:'+targetRowIx+' dragRows:'+firstDragRowIx+'-'+lastDragRowIx+'  y:'+y+' oldY:'+jQuery.tableDnD.oldY);
+
+                        } else if (!movingDown) { // && config.dragObjects[0] != currentRow) {
+                            if ((lastDragRowIx - firstDragRowIx) == (config.dragObjects.length - 1)
+                            &&  firstDragRowIx >= 0
+                            &&  firstDragRowIx > targetRowIx) {
+                                var plusIx=0;
+                                for(var ix=firstDragRowIx; ix <= lastDragRowIx; ix++) {
+                                    //try { // use try/catch because sometimes rows go missing when moving
+                                        $(rows[ix]).insertBefore( rows[targetRowIx + plusIx] );
+                                        plusIx++;
+                                    //} catch (err) { // just put them all back
+                                    //    warn('movingUp: targetRowIx:'+targetRowIx+' dragRows:'+firstDragRowIx+'-'+lastDragRowIx+'  y:'+y+' oldY:'+jQuery.tableDnD.oldY+'<BR>' + err);
+                                    //}
                             }
-                        } else if (!movingDown && config.dragObjects[0] != currentRow) {
-                            $(config.dragObjects).insertBefore( currentRow );
                             jQuery.tableDnD.oldY = y;
+                            } //else
+                              //  warn('up blocked: targetRowIx:'+targetRowIx+' dragRows:'+firstDragRowIx+'-'+lastDragRowIx+'  y:'+y+' oldY:'+jQuery.tableDnD.oldY);
                         }
+                    } else
+                        warn('blocked: targetRowIx:'+targetRowIx+' dragRows:'+firstDragRowIx+'-'+lastDragRowIx+'  y:'+y+' oldY:'+jQuery.tableDnD.oldY);
                 } 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;
                     }
+                    jQuery.tableDnD.oldY = y;
 
                 }   ////// UCSC
             }
         }
+        jQuery.tableDnD.currentTable.mouseMoving = false;  ////////// 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;
             }