Use modified dragscrollable plugin from http://github.com/raganwald/iGesture. Add...
[bookreader.git] / BookReader / BookReader.js
index 8d7963c..1e2eabd 100644 (file)
@@ -83,6 +83,7 @@ function BookReader() {
     this.constModeThumb = 3;
     
     // Zoom levels
+    // $$$ provide finer grained zooming
     this.reductionFactors = [0.5, 1, 2, 4, 8, 16];
 
     // Object to hold parameters related to 2up mode
@@ -140,6 +141,7 @@ BookReader.prototype.init = function() {
     }
     
     $("#BookReader").empty();
+        
     this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
     $("#BookReader").append("<div id='BRcontainer'></div>");
     $("#BRcontainer").append("<div id='BRpageview'></div>");
@@ -147,7 +149,7 @@ BookReader.prototype.init = function() {
     $("#BRcontainer").bind('scroll', this, function(e) {
         e.data.loadLeafs();
     });
-
+    
     this.setupKeyListeners();
     this.startLocationPolling();
 
@@ -196,8 +198,8 @@ BookReader.prototype.init = function() {
     // $$$ refactor this so it's enough to set the first index and call preparePageView
     //     (get rid of mode-specific logic at this point)
     if (1 == this.mode) {
-        this.resizePageView();
         this.firstIndex = startIndex;
+        this.prepareOnePageView();
         this.jumpToIndex(startIndex);
     } else if (3 == this.mode) {
         this.firstIndex = startIndex;
@@ -290,162 +292,27 @@ BookReader.prototype.drawLeafs = function() {
     
 }
 
-// setDragHandler()
+// bindGestures(jElement)
 //______________________________________________________________________________
-BookReader.prototype.setDragHandler = function(div) {
-    div.dragging = false;
-
-    $(div).unbind('mousedown').bind('mousedown', function(e) {
-        e.preventDefault();
-        
-        //console.log('mousedown at ' + e.pageY);
-
-        this.dragging = true;
-        this.prevMouseX = e.pageX;
-        this.prevMouseY = e.pageY;
-    
-        var startX    = e.pageX;
-        var startY    = e.pageY;
-        var startTop  = $('#BRcontainer').attr('scrollTop');
-        var startLeft =  $('#BRcontainer').attr('scrollLeft');
-
-    });
-        
-    $(div).unbind('mousemove').bind('mousemove', function(ee) {
-        ee.preventDefault();
-
-        // console.log('mousemove ' + ee.pageX + ',' + ee.pageY);
-        
-        var offsetX = ee.pageX - this.prevMouseX;
-        var offsetY = ee.pageY - this.prevMouseY;
-        
-        if (this.dragging) {
-            $('#BRcontainer').attr('scrollTop', $('#BRcontainer').attr('scrollTop') - offsetY);
-            $('#BRcontainer').attr('scrollLeft', $('#BRcontainer').attr('scrollLeft') - offsetX);
-        }
-        
-        this.prevMouseX = ee.pageX;
-        this.prevMouseY = ee.pageY;
-        
-    });
-    
-    $(div).unbind('mouseup').bind('mouseup', function(ee) {
-        ee.preventDefault();
-        //console.log('mouseup');
-
-        this.dragging = false;
-    });
-    
-    $(div).unbind('mouseleave').bind('mouseleave', function(e) {
-        e.preventDefault();
-        //console.log('mouseleave');
-
-        this.dragging = false;        
-    });
-    
-    $(div).unbind('mouseenter').bind('mouseenter', function(e) {
-        e.preventDefault();
-        //console.log('mouseenter');
-        
-        this.dragging = false;
-    });
-}
+BookReader.prototype.bindGestures = function(jElement) {
 
-// setDragHandler2UP()
-//______________________________________________________________________________
-BookReader.prototype.setDragHandler2UP = function(div) {
-    div.dragging = false;
-    
-    $(div).unbind('mousedown').bind('mousedown', function(e) {
+    jElement.unbind('gesturechange').bind('gesturechange', function(e) {
         e.preventDefault();
-        
-        //console.log('mousedown at ' + e.pageY);
-
-        this.dragStart = {x: e.pageX, y: e.pageY };
-        this.mouseDown = true;
-        this.dragging = false; // wait until drag distance
-        this.prevMouseX = e.pageX;
-        this.prevMouseY = e.pageY;
-    
-        var startX    = e.pageX;
-        var startY    = e.pageY;
-        var startTop  = $('#BRcontainer').attr('scrollTop');
-        var startLeft =  $('#BRcontainer').attr('scrollLeft');
-
-    });
-        
-    $(div).unbind('mousemove').bind('mousemove', function(ee) {
-        ee.preventDefault();
-
-        // console.log('mousemove ' + ee.pageX + ',' + ee.pageY);
-        
-        var offsetX = ee.pageX - this.prevMouseX;
-        var offsetY = ee.pageY - this.prevMouseY;
-        
-        var minDragDistance = 5; // $$$ constant
-
-        var distance = Math.max(Math.abs(offsetX), Math.abs(offsetY));
-                
-        if (this.mouseDown && (distance > minDragDistance)) {
-            //console.log('drag start!');
-            
-            this.dragging = true;
+        if (e.originalEvent.scale > 1.5) {
+            br.zoom(1);
+        } else if (e.originalEvent.scale < 0.6) {
+            br.zoom(-1);
         }
-        
-        if (this.dragging) {        
-            $('#BRcontainer').attr('scrollTop', $('#BRcontainer').attr('scrollTop') - offsetY);
-            $('#BRcontainer').attr('scrollLeft', $('#BRcontainer').attr('scrollLeft') - offsetX);
-            this.prevMouseX = ee.pageX;
-            this.prevMouseY = ee.pageY;
-        }
-        
-        
-    });
-    
-    /*
-    $(div).unbind('mouseup').bind('mouseup', function(ee) {
-        ee.preventDefault();
-        //console.log('mouseup');
-
-        this.dragging = false;
-        this.mouseDown = false;
     });
-    */
-    
-    
-    $(div).unbind('mouseleave').bind('mouseleave', function(e) {
-        e.preventDefault();
-        //console.log('mouseleave');
-
-        this.dragging = false;  
-        this.mouseDown = false;
-    });
-    
-    $(div).unbind('mouseenter').bind('mouseenter', function(e) {
-        e.preventDefault();
-        //console.log('mouseenter');
         
-        this.dragging = false;
-        this.mouseDown = false;
-    });
 }
 
 BookReader.prototype.setClickHandler2UP = function( element, data, handler) {
     //console.log('setting handler');
     //console.log(element.tagName);
     
-    $(element).unbind('click').bind('click', data, function(e) {
-        e.preventDefault();
-        
-        //console.log('click!');
-        
-        if (this.mouseDown && (!this.dragging)) {
-            //console.log('click not dragging!');
-            handler(e);
-        }
-        
-        this.dragging = false;
-        this.mouseDown = false;
+    $(element).unbind('tap').bind('tap', data, function(e) {
+        handler(e);
     });
 }
 
@@ -530,8 +397,6 @@ BookReader.prototype.drawLeafsOnePage = function() {
             $(div).css('height', height+'px');
             //$(div).text('loading...');
             
-            this.setDragHandler(div);
-            
             $('#BRpageview').append(div);
 
             var img = document.createElement("img");
@@ -574,10 +439,12 @@ BookReader.prototype.drawLeafsOnePage = function() {
 
 // drawLeafsThumbnail()
 //______________________________________________________________________________
-BookReader.prototype.drawLeafsThumbnail = function() {
+// If seekIndex is defined, the view will be drawn with that page visible (without any
+// animated scrolling)
+BookReader.prototype.drawLeafsThumbnail = function( seekIndex ) {
     //alert('drawing leafs!');
     this.timer = null;
-
+    
     var viewWidth = $('#BRcontainer').attr('scrollWidth') - 20; // width minus buffer
 
     //console.log('top=' + scrollTop + ' bottom='+scrollBottom);
@@ -593,6 +460,9 @@ BookReader.prototype.drawLeafsThumbnail = function() {
     var leafMap = [];
     
     var self = this;
+    
+    // Will be set to top of requested seek index, if set
+    var seekTop;
 
     // Calculate the position of every thumbnail.  $$$ cache instead of calculating on every draw
     for (i=0; i<this.numLeafs; i++) {
@@ -621,12 +491,22 @@ BookReader.prototype.drawLeafsThumbnail = function() {
         rightPos += leafWidth + this.padding;
         if (rightPos > maxRight) { maxRight = rightPos; }
         leafIndex++;
+        
+        if (i == seekIndex) {
+            seekTop = bottomPos - this.padding - leafMap[currentRow].height;
+        }
     }
 
     // reset the bottom position based on thumbnails
     $('#BRpageview').height(bottomPos);
 
     var pageViewBuffer = Math.floor(($('#BRcontainer').attr('scrollWidth') - maxRight) / 2) - 14;
+
+    // If seekTop is defined, seeking was requested and target found
+    if (typeof(seekTop) != 'undefined') {
+        $('#BRcontainer').scrollTop( seekTop );
+    }
+        
     var scrollTop = $('#BRcontainer').attr('scrollTop');
     var scrollBottom = scrollTop + $('#BRcontainer').height();
 
@@ -708,7 +588,7 @@ BookReader.prototype.drawLeafsThumbnail = function() {
                 // link to page in single page mode
                 link = document.createElement("a");
                 $(link).data('leaf', leaf);
-                $(link).bind('click', function(event) {
+                $(link).bind('tap', function(event) {
                     self.firstIndex = $(this).data('leaf');
                     self.switchMode(self.constMode1up);
                     event.preventDefault();
@@ -1004,6 +884,20 @@ BookReader.prototype.resizePageView = function() {
     //     e.g. does not preserve position in thumbnail mode
     //     See http://bugs.launchpad.net/bookreader/+bug/552972
     
+    switch (this.mode) {
+        case this.constMode1up:
+        case this.constMode2up:
+            this.resizePageView1up();
+            break;
+        case this.constModeThumb:
+            this.prepareThumbnailView( this.currentIndex() );
+            break;
+        default:
+            alert('Resize not implemented for this mode');
+    }
+}
+
+BookReader.prototype.resizePageView1up = function() {
     var i;
     var viewHeight = 0;
     //var viewWidth  = $('#BRcontainer').width(); //includes scrollBar
@@ -1029,7 +923,7 @@ BookReader.prototype.resizePageView = function() {
         if (width>viewWidth) viewWidth=width;
     }
     $('#BRpageview').height(viewHeight);
-    $('#BRpageview').width(viewWidth);    
+    $('#BRpageview').width(viewWidth);
 
     var newCenterY = scrollRatio*viewHeight;
     var newTop = Math.max(0, Math.floor( newCenterY - $('#BRcontainer').height()/2 ));
@@ -1044,14 +938,12 @@ BookReader.prototype.resizePageView = function() {
     
     //this.centerPageView();
     this.loadLeafs();
-    
-    // $$$ jump to index here? index is not preserved when resizing in thumb mode
-    
-    // Not really needed until there is 1up autofit
+        
     this.removeSearchHilites();
     this.updateSearchHilites();
 }
 
+
 // centerX1up()
 //______________________________________________________________________________
 // Returns the current offset of the viewport center in scaled document coordinates.
@@ -1138,7 +1030,6 @@ BookReader.prototype.zoomThumb = function(direction) {
     
     if (this.thumbColumns != oldColumns) {
         this.prepareThumbnailView();
-        this.jumpToIndex(this.currentIndex());
     }
 }
 
@@ -1273,8 +1164,7 @@ BookReader.prototype.jumpToIndex = function(index, pageX, pageY) {
                 leafIndex = 0;
             }
 
-            // $$$ leaf is not defined in this function -- leaking in from somewhere else            
-            leafHeight = parseInt((this.getPageHeight(leaf)*this.thumbWidth)/this.getPageWidth(leaf), 10);
+            leafHeight = parseInt((this.getPageHeight(leafIndex)*this.thumbWidth)/this.getPageWidth(leafIndex), 10);
             if (leafHeight > rowHeight) { rowHeight = leafHeight; }
             if (leafIndex==0) { leafTop = bottomPos; }
             if (leafIndex==0) { bottomPos += this.padding + rowHeight; }
@@ -1351,7 +1241,6 @@ BookReader.prototype.switchMode = function(mode) {
     } else if (3 == mode) {
         this.reduce = this.quantizeReduce(this.reduce);
         this.prepareThumbnailView();
-        this.jumpToIndex(this.currentIndex());
     } else {
         // $$$ why don't we save autofit?
         this.twoPage.autofit = false; // Take zoom level from other mode
@@ -1368,19 +1257,24 @@ BookReader.prototype.prepareOnePageView = function() {
 
     // var startLeaf = this.displayedIndices[0];
     var startLeaf = this.currentIndex();
-    
+        
     $('#BRcontainer').empty();
     $('#BRcontainer').css({
         overflowY: 'scroll',
         overflowX: 'auto'
     });
-    
+        
     $("#BRcontainer").append("<div id='BRpageview'></div>");
+
+    // Attaches to first child - child must be present
+    $('#BRcontainer').dragscrollable();
+    this.bindGestures($('#BRcontainer'));
+
     // $$$ keep select enabled for now since disabling it breaks keyboard
     //     nav in FF 3.6 (https://bugs.edge.launchpad.net/bookreader/+bug/544666)
     // BookReader.util.disableSelect($('#BRpageview'));
     
-    this.resizePageView();
+    this.resizePageView();    
     
     this.jumpToIndex(startLeaf);
     this.displayedIndices = [];
@@ -1397,23 +1291,24 @@ BookReader.prototype.prepareThumbnailView = function() {
         overflowY: 'scroll',
         overflowX: 'auto'
     });
-    
+        
     $("#BRcontainer").append("<div id='BRpageview'></div>");
+    
+    $('#BRcontainer').dragscrollable();
+    this.bindGestures($('#BRcontainer'));
 
     // $$$ keep select enabled for now since disabling it breaks keyboard
     //     nav in FF 3.6 (https://bugs.edge.launchpad.net/bookreader/+bug/544666)
     // BookReader.util.disableSelect($('#BRpageview'));
     
-    var startLeaf = this.currentIndex();
     this.thumbWidth = this.getThumbnailWidth(this.thumbColumns);
     this.reduce = this.getPageWidth(0)/this.thumbWidth;
 
-    this.resizePageView();
-    
     this.displayedRows = [];
+
+    // Draw leafs with current index directly in view (no animating to the index)
+    this.drawLeafsThumbnail( this.currentIndex() );
     
-    // $$$ resizePageView will do a delayed load -- this will make it happen faster
-    this.drawLeafsThumbnail();
 }
 
 // prepareTwoPageView()
@@ -1466,6 +1361,10 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc
     // Add the two page view
     // $$$ Can we get everything set up and then append?
     $('#BRcontainer').append('<div id="BRtwopageview"></div>');
+    
+    // Attaches to first child, so must come after we add the page view
+    $('#BRcontainer').dragscrollable();
+    this.bindGestures($('#BRcontainer'));
 
     // $$$ calculate first then set
     $('#BRtwopageview').css( {
@@ -1863,27 +1762,6 @@ BookReader.prototype.setCurrentIndex = function(index) {
     this.firstIndex = index;
 }
 
-/*
-// Returns the current index if visible, or the logically current visible
-// thumbnail
-BookReader.prototype.currentIndexOrVisibleThumb = function() {
-    // XXX finish implementation
-    var index = this.currentIndex();
-    if (!this.indexIsVisbleThumb(this.currentIndex()) {
-        // XXX search for visible
-    }
-    return index;
-}
-
-// Returns true if the given index is visible
-BookReader.prototype.indexIsVisibleThumb = function(index, onlyCompletelyVisible = true) {
-    // XXX implement
-    // $$$ I'd prefer to go through a stored leaf map instead of DOM
-    
-    
-}
-*/
-
 
 // right()
 //______________________________________________________________________________
@@ -2322,32 +2200,19 @@ BookReader.prototype.flipRightToLeft = function(newIndexL, newIndexR) {
 // setMouseHandlers2UP
 //______________________________________________________________________________
 BookReader.prototype.setMouseHandlers2UP = function() {
-    /*
-    $(this.prefetchedImgs[this.twoPage.currentIndexL]).bind('dblclick', function() {
-        //self.prevPage();
-        self.autoStop();
-        self.left();
-    });
-    $(this.prefetchedImgs[this.twoPage.currentIndexR]).bind('dblclick', function() {
-        //self.nextPage();'
-        self.autoStop();
-        self.right();        
-    });
-    */
-    
-    this.setDragHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexL] );
     this.setClickHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexL],
         { self: this },
         function(e) {
             e.data.self.left();
+            e.preventDefault();
         }
     );
         
-    this.setDragHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexR] );
     this.setClickHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexR],
         { self: this },
         function(e) {
             e.data.self.right();
+            e.preventDefault();
         }
     );
 }
@@ -3256,7 +3121,7 @@ BookReader.prototype.initToolbar = function(mode, ui) {
     
     this.updateToolbarZoom(this.reduce); // Pretty format
         
-    if (ui == "embed") {
+    if (ui == "embed" || ui == "touch") {
         $("#BookReader a.logo").attr("target","_blank");
     }