Replaced hardcoded Zoom percentage in the toolbar with dynamic percentage based on...
[bookreader.git] / GnuBook / GnuBook.js
index f6e36fe..09edc22 100644 (file)
@@ -18,7 +18,7 @@ This file is part of GnuBook.
     
     The GnuBook source is hosted at http://github.com/openlibrary/bookreader/
 
-    archive.org cvs $Revision: 1.68 $ $Date: 2009-03-04 22:00:31 $
+    archive.org cvs $Revision: 1.73 $ $Date: 2009-05-01 22:37:11 $
 */
 
 // GnuBook()
@@ -56,6 +56,9 @@ function GnuBook() {
     
     this.lastDisplayableIndex2up = null;
     
+    // We link to index.php to avoid redirect which breaks back button
+    this.logoURL = 'http://www.archive.org/index.php';
+    
 };
 
 // init()
@@ -68,23 +71,12 @@ GnuBook.prototype.init = function() {
             startLeaf = "#" + this.leafNumToIndex(this.titleLeaf);
         }
     }
-    var title = this.bookTitle.substr(0,50);
-    if (this.bookTitle.length>50) title += '...';
     
     // Ideally this would be set in the HTML/PHP for better search engine visibility but
     // it takes some time to locate the item and retrieve the metadata
-    document.title = title;
+    document.title = this.shortTitle(50);
     
     $("#GnuBook").empty();
-    // XXXmang hook up logo to url action
-    $("#GnuBook").append("<div id='GBtoolbar'><span style='float:left;'><button class='GBicon logo' />"
-        + " <button class='GBicon rollover zoom_out' onclick='gb.zoom1up(-1); return false;'/>" 
-        + "<button class='GBicon rollover zoom_in' onclick='gb.zoom1up(1); return false;'/>"
-        + " <span class='label'>Zoom: <span id='GBzoom'>25</span>%</span>"
-        + " <button class='GBicon rollover script' onclick='gb.switchMode(1); return false;'/>"
-        + " <button class='GBicon rollover book_open' onclick='gb.switchMode(2); return false;'/>"
-        + "&nbsp;&nbsp; <a class='GBblack title' href='"+this.bookUrl+"' target='_blank'>"+title+"</a>"
-        + "</span></div>");
     this.initToolbar(this.mode); // Build inside of toolbar div
     $("#GnuBook").append("<div id='GBcontainer'></div>");
     $("#GBcontainer").append("<div id='GBpageview'></div>");
@@ -94,7 +86,6 @@ GnuBook.prototype.init = function() {
     });
 
     this.setupKeyListeners();
-    this.setupRollovers();
 
     $(window).bind('resize', this, function(e) {
         //console.log('resize!');
@@ -110,6 +101,10 @@ GnuBook.prototype.init = function() {
             e.data.prepareTwoPageView();
         }
     });
+    
+    $('.GBpagediv1up').bind('mousedown', this, function(e) {
+        //console.log('mousedown!');
+    });
 
     if (1 == this.mode) {
         this.resizePageView();
@@ -164,10 +159,10 @@ GnuBook.prototype.setupKeyListeners = function() {
                 }
                 break;
             case KEY_END:
-                self.end();
+                self.last();
                 break;
             case KEY_HOME:
-                self.home();
+                self.first();
                 break;
             case KEY_LEFT:
                 if (self.keyboardNavigationIsDisabled(e)) {
@@ -199,6 +194,58 @@ GnuBook.prototype.drawLeafs = function() {
     }
 }
 
+// setDragHandler1up()
+//______________________________________________________________________________
+GnuBook.prototype.setDragHandler1up = function(div) {
+    div.dragging = false;
+
+    $(div).bind('mousedown', function(e) {
+        //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  = $('#GBcontainer').attr('scrollTop');
+        var startLeft =  $('#GBcontainer').attr('scrollLeft');
+
+        return false;
+    });
+        
+    $(div).bind('mousemove', function(ee) {
+        //console.log('mousemove ' + startY);
+        
+        var offsetX = ee.pageX - this.prevMouseX;
+        var offsetY = ee.pageY - this.prevMouseY;
+        
+        if (this.dragging) {
+            $('#GBcontainer').attr('scrollTop', $('#GBcontainer').attr('scrollTop') - offsetY);
+            $('#GBcontainer').attr('scrollLeft', $('#GBcontainer').attr('scrollLeft') - offsetX);
+        }
+        
+        this.prevMouseX = ee.pageX;
+        this.prevMouseY = ee.pageY;
+        
+        return false;
+    });
+    
+    $(div).bind('mouseup', function(ee) {
+        //console.log('mouseup');
+
+        this.dragging = false;
+        return false;
+    });
+    
+    $(div).bind('mouseleave', function(e) {
+        //console.log('mouseleave');
+
+        //$(this).unbind('mousemove mouseup');
+        this.dragging = false;
+        
+    });
+}
 
 // drawLeafsOnePage()
 //______________________________________________________________________________
@@ -275,6 +322,8 @@ GnuBook.prototype.drawLeafsOnePage = function() {
             $(div).css('height', height+'px');
             //$(div).text('loading...');
             
+            this.setDragHandler1up(div);
+            
             $('#GBpageview').append(div);
 
             var img = document.createElement("img");
@@ -574,12 +623,20 @@ GnuBook.prototype.prepareOnePageView = function() {
         overflowX: 'auto'
     });
     
-    $("#GBcontainer").append("<div id='GBpageview'></div>");
+    var gbPageView = $("#GBcontainer").append("<div id='GBpageview'></div>");
     this.resizePageView();
     this.jumpToIndex(startLeaf);
     this.displayedLeafs = [];    
     this.drawLeafsOnePage();
-    $('#GBzoom').text(100/this.reduce);    
+    $('#GBzoom').text(100/this.reduce);
+    
+    // Bind mouse handlers
+    // Disable mouse click to avoid selected/highlighted page images - bug 354239
+    gbPageView.bind('mousedown', function(e) {
+        return false;
+    })
+    // Special hack for IE7
+    gbPageView[0].onselectstart = function(e) { return false; };
 }
 
 // prepareTwoPageView()
@@ -669,7 +726,7 @@ GnuBook.prototype.prepareTwoPageView = function() {
         borderStyle: 'solid solid solid none',
         borderColor: 'rgb(51, 51, 34)',
         borderWidth: '1px 1px 1px 0px',
-        background: 'transparent url(images/right-edges.png) repeat scroll 0% 0%',
+        background: 'transparent url(images/right_edges.png) repeat scroll 0% 0%',
         width: leafEdgeWidthR + 'px',
         height: this.twoPageH-1 + 'px',
         /*right: '10px',*/
@@ -684,7 +741,7 @@ GnuBook.prototype.prepareTwoPageView = function() {
         borderStyle: 'solid none solid solid',
         borderColor: 'rgb(51, 51, 34)',
         borderWidth: '1px 0px 1px 1px',
-        background: 'transparent url(images/left-edges.png) repeat scroll 0% 0%',
+        background: 'transparent url(images/left_edges.png) repeat scroll 0% 0%',
         width: leafEdgeWidthL + 'px',
         height: this.twoPageH-1 + 'px',
         left: bookCoverDivLeft+10+'px',
@@ -858,6 +915,17 @@ GnuBook.prototype.right = function() {
     }
 }
 
+// rightmost()
+//______________________________________________________________________________
+// Flip to the rightmost page
+GnuBook.prototype.rightmost = function() {
+    if ('rl' != this.pageProgression) {
+        gb.last();
+    } else {
+        gb.first();
+    }
+}
+
 // left()
 //______________________________________________________________________________
 // Flip the left page over onto the right.
@@ -871,8 +939,20 @@ GnuBook.prototype.left = function() {
     }
 }
 
+// leftmost()
+//______________________________________________________________________________
+// Flip to the leftmost page
+GnuBook.prototype.leftmost = function() {
+    if ('rl' != this.pageProgression) {
+        gb.first();
+    } else {
+        gb.last();
+    }
+}
+
 // next()
 //______________________________________________________________________________
+// Navigate to next page
 GnuBook.prototype.next = function() {
     if (2 == this.mode) {
         this.autoStop();
@@ -886,6 +966,7 @@ GnuBook.prototype.next = function() {
 
 // prev()
 //______________________________________________________________________________
+// Navigate to previous page
 GnuBook.prototype.prev = function() {
     if (2 == this.mode) {
         this.autoStop();
@@ -897,16 +978,17 @@ GnuBook.prototype.prev = function() {
     }
 }
 
-GnuBook.prototype.home = function() {
-    if (2 == this.mode) {
-        this.jumpToIndex(2);
-    }
-    else {
-        this.jumpToIndex(0);
-    }
+// first()
+//______________________________________________________________________________
+// Navigate to first displayable page
+GnuBook.prototype.first = function() {
+    this.jumpToIndex(this.firstDisplayableIndex());
 }
 
-GnuBook.prototype.end = function() {
+// last()
+//______________________________________________________________________________
+// Navigate to last displayable page
+GnuBook.prototype.last = function() {
     if (2 == this.mode) {
         this.jumpToIndex(this.lastDisplayableIndex());
     }
@@ -925,7 +1007,7 @@ GnuBook.prototype.flipBackToIndex = function(index) {
     
     // $$$ Need to change this to be able to see first spread.
     //     See https://bugs.launchpad.net/gnubook/+bug/296788
-    if (leftIndex <= 2) return;
+    if (leftIndex <= 1) return;
     if (this.animating) return;
 
     if (null != this.leafEdgeTmp) {
@@ -1014,7 +1096,7 @@ GnuBook.prototype.flipLeftToRight = function(newIndexL, newIndexR, gutter) {
         borderStyle: 'solid none solid solid',
         borderColor: 'rgb(51, 51, 34)',
         borderWidth: '1px 0px 1px 1px',
-        background: 'transparent url(images/left-edges.png) repeat scroll 0% 0%',
+        background: 'transparent url(images/left_edges.png) repeat scroll 0% 0%',
         width: leafEdgeTmpW + 'px',
         height: this.twoPageH-1 + 'px',
         left: leftEdgeTmpLeft + 'px',
@@ -1157,7 +1239,7 @@ GnuBook.prototype.flipRightToLeft = function(newIndexL, newIndexR, gutter) {
         borderStyle: 'solid none solid solid',
         borderColor: 'rgb(51, 51, 34)',
         borderWidth: '1px 0px 1px 1px',
-        background: 'transparent url(images/left-edges.png) repeat scroll 0% 0%',
+        background: 'transparent url(images/left_edges.png) repeat scroll 0% 0%',
         width: leafEdgeTmpW + 'px',
         height: this.twoPageH-1 + 'px',
         left: currGutter+scaledW+'px',
@@ -1656,7 +1738,8 @@ GnuBook.prototype.autoToggle = function() {
             this.flipFwdToIndex();        
         }
 
-        $('#autoImg').removeClass('play').addClass('pause');
+        $('#GBtoolbar .play').hide();
+        $('#GBtoolbar .pause').show();
         this.autoTimer=setInterval(function(){
             if (self.animating) {return;}
             
@@ -1677,7 +1760,8 @@ GnuBook.prototype.autoStop = function() {
     if (null != this.autoTimer) {
         clearInterval(this.autoTimer);
         this.flipSpeed = 'fast';
-        $('#autoImg').removeClass('pause').addClass('play');
+        $('#GBtoolbar .pause').hide();
+        $('#GBtoolbar .play').show();
         this.autoTimer = null;
     }
 }
@@ -1761,26 +1845,56 @@ GnuBook.prototype.jumpIndexForRightEdgePageX = function(pageX) {
 }
 
 GnuBook.prototype.initToolbar = function(mode) {
+    $("#GnuBook").append("<div id='GBtoolbar'><span style='float:left;'>"
+        + "<a class='GBicon logo rollover' href='" + this.logoURL + "'>&nbsp;</a>"
+        + " <button class='GBicon rollover zoom_out' onclick='gb.zoom1up(-1); return false;'/>" 
+        + "<button class='GBicon rollover zoom_in' onclick='gb.zoom1up(1); return false;'/>"
+        + " <span class='label'>Zoom: <span id='GBzoom'>"+100/this.reduce+"</span>%</span>"
+        + " <button class='GBicon rollover one_page_mode' onclick='gb.switchMode(1); return false;'/>"
+        + " <button class='GBicon rollover two_page_mode' onclick='gb.switchMode(2); return false;'/>"
+        + "&nbsp;&nbsp;<a class='GBblack title' href='"+this.bookUrl+"' target='_blank'>"+this.shortTitle(50)+"</a>"
+        + "</span></div>");
+
     // $$$ turn this into a member variable
     var jToolbar = $('#GBtoolbar'); // j prefix indicates jQuery object
     
     // We build in mode 2
     jToolbar.append("<span id='GBtoolbarbuttons' style='float: right'>"
-        + "<button class='GBicon rollover page_code' />"
+        + "<button class='GBicon rollover embed' />"
         + "<form class='GBpageform' action='javascript:' onsubmit='gb.jumpToPage(this.elements[0].value)'> <span class='label'>Page:<input id='GBpagenum' type='text' size='3' onfocus='gb.autoStop();'></input></span></form>"
-        + "<div class='GBtoolbarmode2' style='display: inline'><button class='GBicon rollover book_left' /><button class='GBicon rollover book_right' /></div>"
-        + "<div class='GBtoolbarmode1' style='display: hidden'><button class='GBicon rollover book_up' /> <button class='GBicon rollover book_down' /></div>"
-        + "<button class='GBicon rollover play' id='autoImg' /></span>");
-
-    // Bind the non-changing click handlers
-    jToolbar.find('.page_code').bind('click', function(e) {
-        gb.showEmbedCode();
-        return false;
-    });
-    jToolbar.find('.play').bind('click', function(e) {
-        gb.autoToggle();
-        return false;
-    });
+        + "<div class='GBtoolbarmode2' style='display: inline'><button class='GBicon rollover book_leftmost' /><button class='GBicon rollover book_left' /><button class='GBicon rollover book_right' /><button class='GBicon rollover book_rightmost' /></div>"
+        + "<div class='GBtoolbarmode1' style='display: hidden'><button class='GBicon rollover book_top' /><button class='GBicon rollover book_up' /> <button class='GBicon rollover book_down' /><button class='GBicon rollover book_bottom' /></div>"
+        + "<button class='GBicon rollover play' /><button class='GBicon rollover pause' style='display: none' /></span>");
+
+    this.bindToolbarNavHandlers(jToolbar);
+    
+    // Setup tooltips -- later we could load these from a file for i18n
+    var titles = { '.logo': 'Go to Archive.org',
+                   '.zoom_in': 'Zoom in',
+                   '.zoom_out': 'Zoom out',
+                   '.one_page_mode': 'One-page view',
+                   '.two_page_mode': 'Two-page view',
+                   '.embed': 'Embed bookreader',
+                   '.book_left': 'Flip left',
+                   '.book_right': 'Flip right',
+                   '.book_up': 'Page up',
+                   '.book_down': 'Page down',
+                   '.play': 'Play',
+                   '.pause': 'Pause',
+                   '.book_top': 'First page',
+                   '.book_bottom': 'Last page'
+                  };
+    if ('rl' == this.pageProgression) {
+        titles['.book_leftmost'] = 'Last page';
+        titles['.book_rightmost'] = 'First page';
+    } else { // LTR
+        titles['.book_leftmost'] = 'First page';
+        titles['.book_rightmost'] = 'Last page';
+    }
+                  
+    for (var icon in titles) {
+        jToolbar.find(icon).attr('title', titles[icon]);
+    }
 
     // Switch to requested mode -- binds other click handlers
     this.switchToolbarMode(mode);
@@ -1802,8 +1916,6 @@ GnuBook.prototype.switchToolbarMode = function(mode) {
         $('#GBtoolbar .GBtoolbarmode1').hide();
         $('#GBtoolbar .GBtoolbarmode2').css('display', 'inline').show();
     }
-    
-    this.bindToolbarNavHandlers($('#GBtoolbar'));
 }
 
 // bindToolbarNavHandlers
@@ -1811,29 +1923,60 @@ GnuBook.prototype.switchToolbarMode = function(mode) {
 // Binds the toolbar handlers
 GnuBook.prototype.bindToolbarNavHandlers = function(jToolbar) {
 
-    jToolbar.find('.book_left').unbind('click')
-        .bind('click', function(e) {
-            gb.left();
-            return false;
-         });
+    jToolbar.find('.book_left').bind('click', function(e) {
+        gb.left();
+        return false;
+    });
          
-    jToolbar.find('.book_right').unbind('click')
-        .bind('click', function(e) {
-            gb.right();
-            return false;
-        });
+    jToolbar.find('.book_right').bind('click', function(e) {
+        gb.right();
+        return false;
+    });
+        
+    jToolbar.find('.book_up').bind('click', function(e) {
+        gb.prev();
+        return false;
+    });        
         
-    jToolbar.find('.book_up').unbind('click')
-        .bind('click', function(e) {
-            gb.prev();
-            return false;
-        });        
+    jToolbar.find('.book_down').bind('click', function(e) {
+        gb.next();
+        return false;
+    });
         
-    jToolbar.find('.book_down').unbind('click')
-        .bind('click', function(e) {
-            gb.next();
-            return false;
-        });      
+    jToolbar.find('.embed').bind('click', function(e) {
+        gb.showEmbedCode();
+        return false;
+    });
+
+    jToolbar.find('.play').bind('click', function(e) {
+        gb.autoToggle();
+        return false;
+    });
+
+    jToolbar.find('.pause').bind('click', function(e) {
+        gb.autoToggle();
+        return false;
+    });
+    
+    jToolbar.find('.book_top').bind('click', function(e) {
+        gb.first();
+        return false;
+    });
+
+    jToolbar.find('.book_bottom').bind('click', function(e) {
+        gb.last();
+        return false;
+    });
+    
+    jToolbar.find('.book_leftmost').bind('click', function(e) {
+        gb.leftmost();
+        return false;
+    });
+  
+    jToolbar.find('.book_rightmost').bind('click', function(e) {
+        gb.rightmost();
+        return false;
+    });
 }
 
 // firstDisplayableIndex
@@ -1844,8 +1987,12 @@ GnuBook.prototype.bindToolbarNavHandlers = function(jToolbar) {
 GnuBook.prototype.firstDisplayableIndex = function() {
     if (this.mode == 0) {
         return 0;
-    } else {
-        return 1; // $$$ we assume there are enough pages... we need logic for very short books
+    } else { // two page mode
+        if (this.getPageSide(0) == 'L') {
+            return 0;
+        } else {
+            return 1; // $$$ we assume there are enough pages... we need logic for very short books
+        }
     }
 }
 
@@ -1873,21 +2020,15 @@ GnuBook.prototype.lastDisplayableIndex = function() {
     }
 }
 
-// setupRollovers
-//______________________________________________________________________________
-// Set up rollover behaviour for icons
-GnuBook.prototype.setupRollovers = function() {
-
-    // TODO precache
-    
-    // XXXmang this doesn't quite work because when we change classes the explicitly set
-    //         url stays with the element
-    // On hover we change the base to rollover.  We switch back on off-hover.
-    $('#GnuBook .rollover').hover( function() {
-        console.log('hover in ' + this); //XXX
-        $(this).css('backgroundImage', $(this).css('backgroundImage').replace('_base', '_rollover'));
-    }, function () {
-        console.log('hover out ' + this); //XXX
-        $(this).css('backgroundImage', $(this).css('backgroundImage').replace('_rollover', '_base'));
-    });
+// shortTitle(maximumCharacters)
+//________
+// Returns a shortened version of the title with the maximum number of characters
+GnuBook.prototype.shortTitle = function(maximumCharacters) {
+    if (this.bookTitle.length < maximumCharacters) {
+        return this.bookTitle;
+    }
+    
+    var title = this.bookTitle.substr(0, maximumCharacters - 3);
+    title += '...';
+    return title;
 }
\ No newline at end of file