b090e775a94315cf1fe9baab62e847a89c47eed6
tdreszer
  Thu Aug 4 17:34:04 2011 -0700
Restricted dragScroll to within the north-south boundaries and used the desired grabbing hands cursors.
diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index d8dabba..a17da3a 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -987,53 +987,58 @@
     }
 
     // globals across all panImages
     portalWidth     = $(pan).width();
     // globals to one panImage
     var newX        = 0;
     var mouseDownX  = 0;
     var mouseIsDown = false;
     var beyondImage = false;
     var atEdge      = false;
 
     initialize();
 
     function initialize(){
 
-        pan.css( 'cursor', 'w-resize');
+        pan.css('cursor',"url(../images/grabbing.cur)"); // Trick to preload
+        pan.css('cursor',"url(../images/grabber.cur),w-resize");
 
         pan.mousedown(function(e){
              if (e.which > 1 || e.button > 1 || e.shiftKey || e.ctrlKey)
                  return true;
             if(mouseIsDown == false) {
                 mouseIsDown = true;
                 mouseDownX = e.clientX;
                 atEdge = (!beyondImage && (prevX >= leftLimit || prevX <= rightLimit));
                 $(document).bind('mousemove',panner);
                 $(document).bind( 'mouseup', panMouseUp);  // Will exec only once
                 return false;
             }
         });
     }
 
     function panner(e) {
         //if(!e) e = window.event;
         if ( mouseIsDown ) {
             var relativeX = (e.clientX - mouseDownX);
 
             if(relativeX != 0) {
+                if (blockUseMap == false) {
+                    // need to throw up a z-index div.  Wait mask?
+                    dragMaskShow();
                 blockUseMap = true;
+                }
                 var decelerator = 1;
                 var wingSize    = 1000; // 0 stops the scroll at the edges.
                 // Remeber that offsetX (prevX) is negative
                 newX = prevX + relativeX;
                 if ( newX >= leftLimit ) { // scrolled all the way to the left
                     if(atEdge) {  // Do not drag straight off edge.  Force second drag
                         beyondImage = true;
                         newX = leftLimit + (newX - leftLimit)/decelerator;// slower
                         if( newX >= leftLimit + wingSize) // Don't go too far over the edge!
                         newX =  leftLimit + wingSize;
                     } else
                         newX = leftLimit;
 
                 } else if ( newX < rightLimit ) { // scrolled all the way to the right
                     if(atEdge) {  // Do not drag straight off edge.  Force second drag
@@ -1048,50 +1053,68 @@
                     beyondImage = false; // could have scrolled back without mouse up
 
                 newX = panUpdatePosition(newX,true);
                 var nowPos = newX.toString() + "px";
                 $(".panImg").css( {'left': nowPos });
                 $('.tdData').css( {'backgroundPosition': nowPos } );
                 if (!only1xScrolling)
                     panAdjustHeight(newX);  // NOTE: This will dynamically resize image while scrolling.  Do we want to?
             }
         }
     }
     function panMouseUp(e) {  // Must be a separate function instead of pan.mouseup event.
         //if(!e) e = window.event;
         if(mouseIsDown) {
 
+            dragMaskClear();
             $(document).unbind('mousemove',panner);
             $(document).unbind('mouseup',panMouseUp);
             mouseIsDown = false;
+            setTimeout('blockUseMap=false;',50); // Necessary incase the selectEnd was over a map item. select takes precedence.
+
+            // Outside image?  Then abandon.
+            var curY = e.clientY;
+            var imgTbl = $('#imgTbl');
+            var imgTop = $(imgTbl).position().top;
+            if (curY < imgTop || curY > imgTop + $(imgTbl).height()) {
+                atEdge = false;
+                beyondImage = false;
+                //warn ('curY:'+curY+ ' top:'+imgTop+' bottom:'+imgTop + $(imgTbl).innerHeight());
+                panUpdatePosition(prevX,false);   // FIXME: This should revert to a saved position!!
+                var oldPos = prevX.toString() + "px";
+                $(".panImg").css( {'left': oldPos });
+                $('.tdData').css( {'backgroundPosition': oldPos } );
+                return true;
+            }
 
-            // Talk to tim about this.
+            // Do we need to fetch anything?
             if(beyondImage) {
                 if(inPlaceUpdate) {
                     var pos = parsePosition(getPosition());
                     navigateInPlace("position=" + encodeURIComponent(pos.chrom + ":" + pos.start + "-" + pos.end));
                 } else {
                     document.TrackHeaderForm.submit();
                 }
                 return true; // Make sure the setTimeout below is not called.
             }
+
+            // Just a normal scroll within a >1X image
             if(prevX != newX) {
                 //if (!only1xScrolling)
                 //    panAdjustHeight(newX); // NOTE: This will resize image after scrolling.  Do we want to while scrolling?
                 prevX = newX;
             }
-            setTimeout('blockUseMap=false;',50); // Necessary incase the selectEnd was over a map item. select takes precedence.
         }
     }
     });  // end of this.each(function(){
 
     function panUpdatePosition(newOffsetX,bounded)
     {
         // Updates the 'position/search" display with change due to panning
         var portalWidthBases = hgTracks.imgBoxPortalEnd - hgTracks.imgBoxPortalStart;
         var portalScrolledX  = (hgTracks.imgBoxPortalOffsetX+hgTracks.imgBoxLeftLabel) + newOffsetX;
         var recalculate = false;
 
         var newPortalStart = hgTracks.imgBoxPortalStart - Math.round(portalScrolledX*hgTracks.imgBoxBasesPerPixel); // As offset goes down, bases seen goes up!
         if( newPortalStart < hgTracks.chromStart && bounded) {     // Stay within bounds
             newPortalStart = hgTracks.chromStart;
             recalculate = true;
@@ -1181,30 +1204,57 @@
                     var btn = $("#p_btn_"+imgId[2]);
                     if( btn.length > 0) {
                         $(btn).height( span.bottom - span.top + titlePx);
                     } else {
                         btn = $("#img_btn_"+imgId[2]);
                         if( btn.length > 0) {
                             $(btn).parent().height( span.bottom - span.top + titlePx);
                             $(btn).css( {'top': top.toString() + "px" });
                         }
                     }
                 }
             }
         });
     }
 
+    function dragMaskShow() {   // Sets up the waitMask to block page manipulation until cleared
+
+        var imgTbl = $('#imgTbl');
+        // Find or create the waitMask (which masks the whole page)
+        var  dragMask = $('div#dragMask');
+        if( dragMask == undefined || dragMask.length == 0) {
+            $(imgTbl).prepend("<div id='dragMask' class='waitMask'></div>");
+            dragMask = $('div#dragMask');
+        }
+
+        $('body').css('cursor','not-allowed')
+        $(dragMask).css('cursor',"url(../images/grabbing.cur),w-resize");
+        //$(dragMask).css({opacity:0.4,backgroundColor:'gray'}); // temporarily so I can see it
+        $(dragMask).css({display:'block',zIndex:5,top: $(imgTbl).position().top, height: $(imgTbl).height() + 'px' });
+
+        return dragMask;  // The caller could add css if they wanted.
+    }
+
+    function dragMaskClear() {        // Clears the waitMask
+        $('body').css('cursor','auto')
+        var  dragMask = $('#dragMask');
+        if( dragMask != undefined )
+            $(dragMask).hide();
+    }
+
+
+
 };
 
 /////////////////////////////////////////////////////
 
 function saveMouseOffset(ev)
 {   // Save the mouse offset associated with this event
     originalMouseOffset = {x: ev.clientX, y: ev.clientY};
 }
 
 function mouseHasMoved(ev)
 {   // return true if mouse has moved a significant amount
     var minPixels = 10;
     var movedX = ev.clientX - originalMouseOffset.x;
     var movedY = ev.clientY - originalMouseOffset.y;
     if ( arguments.length == 2) {