Merge branch 'master' of git://github.com/openlibrary/bookreader
authorscollett <stephanie.collett@ucop.edu>
Wed, 8 Jul 2009 19:01:07 +0000 (12:01 -0700)
committerscollett <stephanie.collett@ucop.edu>
Wed, 8 Jul 2009 19:01:07 +0000 (12:01 -0700)
1  2 
GnuBook/GnuBook.js

diff --combined GnuBook/GnuBook.js
@@@ -1,5 -1,5 +1,5 @@@
  /*
- Copyright(c)2008 Internet Archive. Software license AGPL version 3.
+ Copyright(c)2008-2009 Internet Archive. Software license AGPL version 3.
  
  This file is part of GnuBook.
  
@@@ -36,10 -36,10 +36,10 @@@ function GnuBook() 
      this.mode    = 1; //1 or 2
      this.ui = 'full'; // UI mode
      
-     this.displayedLeafs = []; 
-     //this.leafsToDisplay = [];
+     this.displayedIndices = [];       
+     //this.indicesToDisplay = [];
      this.imgs = {};
-     this.prefetchedImgs = {}; //an object with numeric keys cooresponding to leafNum
+     this.prefetchedImgs = {}; //an object with numeric keys cooresponding to page index
      
      this.timer     = null;
      this.animating = false;
@@@ -84,8 -84,10 +84,10 @@@ GnuBook.prototype.init = function() 
          startIndex = this.getPageIndex(params.page);
      }
      
-     if ('undefined' == typeof(startIndex)) {    
-         startIndex = this.leafNumToIndex(this.titleLeaf);
+     if ('undefined' == typeof(startIndex)) {
+         if ('undefined' != typeof(this.titleLeaf)) {
+             startIndex = this.leafNumToIndex(this.titleLeaf);
+         }
      }
      
      if ('undefined' == typeof(startIndex)) {
              //console.log('centering 1page view');
              e.data.centerPageView();
              $('#GBpageview').empty()
-             e.data.displayedLeafs = [];
+             e.data.displayedIndices = [];
              e.data.updateSearchHilites(); //deletes hilights but does not call remove()            
              e.data.loadLeafs();
          } else {
      } else {
          //this.resizePageView();
          
-         this.displayedLeafs=[0];
+         this.displayedIndices=[0];
          this.firstIndex = startIndex;
-         this.displayedLeafs = [this.firstIndex];
+         this.displayedIndices = [this.firstIndex];
          //console.log('titleLeaf: %d', this.titleLeaf);
-         //console.log('displayedLeafs: %s', this.displayedLeafs);
+         //console.log('displayedIndices: %s', this.displayedIndices);
          this.prepareTwoPageView();
          //if (this.auto) this.nextPage();
      }
@@@ -282,7 -284,7 +284,7 @@@ GnuBook.prototype.drawLeafsOnePage = fu
      var scrollBottom = scrollTop + $('#GBcontainer').height();
      //console.log('top=' + scrollTop + ' bottom='+scrollBottom);
      
-     var leafsToDisplay = [];
+     var indicesToDisplay = [];
      
      var i;
      var leafTop = 0;
          var bottomInView = (leafBottom >= scrollTop) && (leafBottom <= scrollBottom);
          var middleInView = (leafTop <=scrollTop) && (leafBottom>=scrollBottom);
          if (topInView | bottomInView | middleInView) {
-             //console.log('displayed: ' + this.displayedLeafs);
+             //console.log('displayed: ' + this.displayedIndices);
              //console.log('to display: ' + i);
-             leafsToDisplay.push(i);
+             indicesToDisplay.push(i);
          }
          leafTop += height +10;      
          leafBottom += 10;
      }
  
-     var firstLeafToDraw  = leafsToDisplay[0];
-     this.firstIndex      = firstLeafToDraw;
+     var firstIndexToDraw  = indicesToDisplay[0];
+     this.firstIndex      = firstIndexToDraw;
      
      // Update hash, but only if we're currently displaying a leaf
      // Hack that fixes #365790
-     if (this.displayedLeafs.length > 0) {
+     if (this.displayedIndices.length > 0) {
          this.updateLocationHash();
      }
  
-     if ((0 != firstLeafToDraw) && (1 < this.reduce)) {
-         firstLeafToDraw--;
-         leafsToDisplay.unshift(firstLeafToDraw);
+     if ((0 != firstIndexToDraw) && (1 < this.reduce)) {
+         firstIndexToDraw--;
+         indicesToDisplay.unshift(firstIndexToDraw);
      }
      
-     var lastLeafToDraw = leafsToDisplay[leafsToDisplay.length-1];
-     if ( ((this.numLeafs-1) != lastLeafToDraw) && (1 < this.reduce) ) {
-         leafsToDisplay.push(lastLeafToDraw+1);
+     var lastIndexToDraw = indicesToDisplay[indicesToDisplay.length-1];
+     if ( ((this.numLeafs-1) != lastIndexToDraw) && (1 < this.reduce) ) {
+         indicesToDisplay.push(lastIndexToDraw+1);
      }
      
      leafTop = 0;
      var i;
-     for (i=0; i<firstLeafToDraw; i++) {
+     for (i=0; i<firstIndexToDraw; i++) {
          leafTop += parseInt(this.getPageHeight(i)/this.reduce) +10;
      }
  
      var viewWidth = $('#GBcontainer').attr('scrollWidth');
  
  
-     for (i=0; i<leafsToDisplay.length; i++) {
-         var leafNum = leafsToDisplay[i];    
-         var height  = parseInt(this.getPageHeight(leafNum)/this.reduce); 
+     for (i=0; i<indicesToDisplay.length; i++) {
+         var index = indicesToDisplay[i];    
+         var height  = parseInt(this.getPageHeight(index)/this.reduce); 
  
-         if(-1 == jQuery.inArray(leafsToDisplay[i], this.displayedLeafs)) {            
-             var width   = parseInt(this.getPageWidth(leafNum)/this.reduce); 
-             //console.log("displaying leaf " + leafsToDisplay[i] + ' leafTop=' +leafTop);
+         if(-1 == jQuery.inArray(indicesToDisplay[i], this.displayedIndices)) {            
+             var width   = parseInt(this.getPageWidth(index)/this.reduce); 
+             //console.log("displaying leaf " + indicesToDisplay[i] + ' leafTop=' +leafTop);
              var div = document.createElement("div");
              div.className = 'GBpagediv1up';
-             div.id = 'pagediv'+leafNum;
+             div.id = 'pagediv'+index;
              div.style.position = "absolute";
              $(div).css('top', leafTop + 'px');
              var left = (viewWidth-width)>>1;
              $('#GBpageview').append(div);
  
              var img = document.createElement("img");
-             img.src = this.getPageURI(leafNum);
+             img.src = this.getPageURI(index);
              $(img).css('width', width+'px');
              $(img).css('height', height+'px');
              $(div).append(img);
  
          } else {
-             //console.log("not displaying " + leafsToDisplay[i] + ' score=' + jQuery.inArray(leafsToDisplay[i], this.displayedLeafs));            
+             //console.log("not displaying " + indicesToDisplay[i] + ' score=' + jQuery.inArray(indicesToDisplay[i], this.displayedIndices));            
          }
  
          leafTop += height +10;
  
      }
      
-     for (i=0; i<this.displayedLeafs.length; i++) {
-         if (-1 == jQuery.inArray(this.displayedLeafs[i], leafsToDisplay)) {
-             var leafNum = this.displayedLeafs[i];
-             //console.log('Removing leaf ' + leafNum);
-             //console.log('id='+'#pagediv'+leafNum+ ' top = ' +$('#pagediv'+leafNum).css('top'));
-             $('#pagediv'+leafNum).remove();
+     for (i=0; i<this.displayedIndices.length; i++) {
+         if (-1 == jQuery.inArray(this.displayedIndices[i], indicesToDisplay)) {
+             var index = this.displayedIndices[i];
+             //console.log('Removing leaf ' + index);
+             //console.log('id='+'#pagediv'+index+ ' top = ' +$('#pagediv'+index).css('top'));
+             $('#pagediv'+index).remove();
          } else {
-             //console.log('NOT Removing leaf ' + this.displayedLeafs[i]);
+             //console.log('NOT Removing leaf ' + this.displayedIndices[i]);
          }
      }
      
-     this.displayedLeafs = leafsToDisplay.slice();
+     this.displayedIndices = indicesToDisplay.slice();
      this.updateSearchHilites();
      
-     if (null != this.getPageNum(firstLeafToDraw))  {
+     if (null != this.getPageNum(firstIndexToDraw))  {
          $("#GBpagenum").val(this.getPageNum(this.currentIndex()));
      } else {
          $("#GBpagenum").val('');
@@@ -399,14 -401,14 +401,14 @@@ GnuBook.prototype.drawLeafsTwoPage = fu
      var scrollTop = $('#GBcontainer').attr('scrollTop');
      var scrollBottom = scrollTop + $('#GBcontainer').height();
      
-     //console.log('drawLeafsTwoPage: this.currrentLeafL ' + this.currentLeafL);
+     //console.log('drawLeafsTwoPage: this.currrentLeafL ' + this.currentIndexL);
      
-     var leafNum = this.currentLeafL;
-     var height  = this.getPageHeight(leafNum); 
-     var width   = this.getPageWidth(leafNum);
-     var handSide= this.getPageSide(leafNum);
+     var index = this.currentIndexL;
+     var height  = this.getPageHeight(index); 
+     var width   = this.getPageWidth(index);
+     var handSide= this.getPageSide(index);
  
-     var leafEdgeWidthL = this.leafEdgeWidth(leafNum);
+     var leafEdgeWidthL = this.leafEdgeWidth(index);
      var leafEdgeWidthR = this.twoPageEdgeW - leafEdgeWidthL;
      var bookCoverDivWidth = this.twoPageW*2+20 + this.twoPageEdgeW;
      var bookCoverDivLeft = ($('#GBcontainer').width() - bookCoverDivWidth) >> 1;
      //var right = left+scaledW;
      var right = $(this.twoPageDiv).width()-11-$(this.leafEdgeL).width()-scaledW;
  
-     var gutter = middle + this.gutterOffsetForIndex(this.currentLeafL);
+     var gutter = middle + this.gutterOffsetForIndex(this.currentIndexL);
      
-     this.prefetchImg(leafNum);
-     $(this.prefetchedImgs[leafNum]).css({
+     this.prefetchImg(index);
+     $(this.prefetchedImgs[index]).css({
          position: 'absolute',
          /*right:   gutter+'px',*/
          left: gutter-scaledW+'px',
          borderRight: '1px solid black',
          zIndex: 2
      }).appendTo('#GBcontainer');
-     //$('#GBcontainer').append(this.prefetchedImgs[leafNum]);
+     //$('#GBcontainer').append(this.prefetchedImgs[index]);
  
  
-     var leafNum = this.currentLeafR;
-     var height  = this.getPageHeight(leafNum); 
-     var width   = this.getPageWidth(leafNum);
+     var index = this.currentIndexR;
+     var height  = this.getPageHeight(index); 
+     var width   = this.getPageWidth(index);
      //    var left = ($('#GBcontainer').width() >> 1);
      left += scaledW;
  
      var scaledW = this.twoPageH*width/height;
-     this.prefetchImg(leafNum);
-     $(this.prefetchedImgs[leafNum]).css({
+     this.prefetchImg(index);
+     $(this.prefetchedImgs[index]).css({
          position: 'absolute',
          left:   gutter+'px',
          right: '',
          borderLeft: '1px solid black',
          zIndex: 2
      }).appendTo('#GBcontainer');
-     //$('#GBcontainer').append(this.prefetchedImgs[leafNum]);
+     //$('#GBcontainer').append(this.prefetchedImgs[index]);
          
  
-     this.displayedLeafs = [this.currentLeafL, this.currentLeafR];
+     this.displayedIndices = [this.currentIndexL, this.currentIndexR];
      this.setClickHandlers();
  
      this.updatePageNumBox2UP();
  // updatePageNumBox2UP
  //______________________________________________________________________________
  GnuBook.prototype.updatePageNumBox2UP = function() {
-     if (null != this.getPageNum(this.currentLeafL))  {
-         $("#GBpagenum").val(this.getPageNum(this.currentLeafL));
+     if (null != this.getPageNum(this.currentIndexL))  {
+         $("#GBpagenum").val(this.getPageNum(this.currentIndexL));
      } else {
          $("#GBpagenum").val('');
      }
@@@ -512,7 -514,7 +514,7 @@@ GnuBook.prototype.zoom1up = function(di
      this.resizePageView();
  
      $('#GBpageview').empty()
-     this.displayedLeafs = [];
+     this.displayedIndices = [];
      this.loadLeafs();
      
      $('#GBzoom').text(100/this.reduce);
@@@ -590,9 -592,9 +592,9 @@@ GnuBook.prototype.jumpToIndex = functio
          
          // By checking against min/max we do nothing if requested index
          // is current
-         if (index < Math.min(this.currentLeafL, this.currentLeafR)) {
+         if (index < Math.min(this.currentIndexL, this.currentIndexR)) {
              this.flipBackToIndex(index);
-         } else if (index > Math.max(this.currentLeafL, this.currentLeafR)) {
+         } else if (index > Math.max(this.currentIndexL, this.currentIndexR)) {
              this.flipFwdToIndex(index);
          }
  
@@@ -638,7 -640,7 +640,7 @@@ GnuBook.prototype.switchMode = function
  //______________________________________________________________________________
  GnuBook.prototype.prepareOnePageView = function() {
  
-     // var startLeaf = this.displayedLeafs[0];
+     // var startLeaf = this.displayedIndices[0];
      var startLeaf = this.currentIndex();
      
      $('#GBcontainer').empty();
      this.resizePageView();
      
      this.jumpToIndex(startLeaf);
-     this.displayedLeafs = [];
+     this.displayedIndices = [];
      
      this.drawLeafsOnePage();
      $('#GBzoom').text(100/this.reduce);
@@@ -674,7 -676,7 +676,7 @@@ GnuBook.prototype.prepareTwoPageView = 
      // one side of the spread because it is the first/last leaf,
      // foldouts, missing pages, etc
  
-     //var targetLeaf = this.displayedLeafs[0];
+     //var targetLeaf = this.displayedIndices[0];
      var targetLeaf = this.firstIndex;
  
      if (targetLeaf < this.firstDisplayableIndex()) {
          targetLeaf = this.lastDisplayableIndex();
      }
      
-     this.currentLeafL = null;
-     this.currentLeafR = null;
+     this.currentIndexL = null;
+     this.currentIndexR = null;
      this.pruneUnusedImgs();
      
      var currentSpreadIndices = this.getSpreadIndices(targetLeaf);
-     this.currentLeafL = currentSpreadIndices[0];
-     this.currentLeafR = currentSpreadIndices[1];
-     this.firstIndex = this.currentLeafL;
+     this.currentIndexL = currentSpreadIndices[0];
+     this.currentIndexR = currentSpreadIndices[1];
+     this.firstIndex = this.currentIndexL;
      
      this.calculateSpreadSize(); //sets this.twoPageW, twoPageH, and twoPageRatio
  
      // cover centered and fixed in the GBcontainer div the page images will meet
      // at the "gutter" which is generally offset from the center.
      var middle = ($('#GBcontainer').width() >> 1); // Middle of the GBcontainer div
-     //var gutter = middle+parseInt((2*this.currentLeafL - this.numLeafs)*this.twoPageEdgeW/this.numLeafs/2);
+     //var gutter = middle+parseInt((2*this.currentIndexL - this.numLeafs)*this.twoPageEdgeW/this.numLeafs/2);
      
-     var gutter = middle + this.gutterOffsetForIndex(this.currentLeafL);
+     var gutter = middle + this.gutterOffsetForIndex(this.currentIndexL);
      
-     var scaledWL = this.getPageWidth2UP(this.currentLeafL);
-     var scaledWR = this.getPageWidth2UP(this.currentLeafR);
-     var leafEdgeWidthL = this.leafEdgeWidth(this.currentLeafL);
+     var scaledWL = this.getPageWidth2UP(this.currentIndexL);
+     var scaledWR = this.getPageWidth2UP(this.currentIndexR);
+     var leafEdgeWidthL = this.leafEdgeWidth(this.currentIndexL);
      var leafEdgeWidthR = this.twoPageEdgeW - leafEdgeWidthL;
  
      //console.log('idealWidth='+idealWidth+' idealHeight='+idealHeight);
      //$('#GBcontainer').append('<div id="book_div_1" style="border: 1px solid rgb(68, 25, 17); width: ' + bookCoverDivWidth + 'px; height: '+bookCoverDivHeight+'px; visibility: visible; position: absolute; background-color: rgb(136, 51, 34); left: ' + bookCoverDivLeft + 'px; top: '+bookCoverDivTop+'px; -moz-border-radius-topleft: 7px; -moz-border-radius-topright: 7px; -moz-border-radius-bottomright: 7px; -moz-border-radius-bottomleft: 7px;"/>');
  
  
-     var height  = this.getPageHeight(this.currentLeafR); 
-     var width   = this.getPageWidth(this.currentLeafR);    
+     var height  = this.getPageHeight(this.currentIndexR); 
+     var width   = this.getPageWidth(this.currentIndexR);    
      var scaledW = this.twoPageH*width/height;
      
      this.leafEdgeR = document.createElement('div');
  
      this.prepareTwoPagePopUp();
  
-     this.displayedLeafs = [];
+     this.displayedIndices = [];
      
-     //this.leafsToDisplay=[firstLeaf, firstLeaf+1];
-     //console.log('leafsToDisplay: ' + this.leafsToDisplay[0] + ' ' + this.leafsToDisplay[1]);
+     //this.indicesToDisplay=[firstLeaf, firstLeaf+1];
+     //console.log('indicesToDisplay: ' + this.indicesToDisplay[0] + ' ' + this.indicesToDisplay[1]);
      
      this.drawLeafsTwoPage();
      this.updateSearchHilites2UP();
      
      this.prefetch();
-     $('#GBzoom').text((100*this.twoPageH/this.getPageHeight(this.currentLeafL)).toString().substr(0,4));
+     $('#GBzoom').text((100*this.twoPageH/this.getPageHeight(this.currentIndexL)).toString().substr(0,4));
  }
  
  // prepareTwoPagePopUp()
  //
- // This function prepares the "View leaf n" popup that shows while the mouse is
+ // This function prepares the "View Page n" popup that shows while the mouse is
  // over the left/right "stack of sheets" edges.  It also binds the mouse
  // events for these divs.
  //______________________________________________________________________________
@@@ -858,8 -860,8 +860,8 @@@ GnuBook.prototype.prepareTwoPagePopUp 
  
      $(this.leafEdgeR).bind('mousemove', this, function(e) {
  
-         var jumpLeaf = e.data.jumpIndexForRightEdgePageX(e.pageX);
-         $(e.data.twoPagePopUp).text('View Leaf '+jumpLeaf);
+         var jumpIndex = e.data.jumpIndexForRightEdgePageX(e.pageX);
+         $(e.data.twoPagePopUp).text('View ' + e.data.getPageName(jumpIndex));
          
          $(e.data.twoPagePopUp).css({
              left: e.pageX +5+ 'px',
  
      $(this.leafEdgeL).bind('mousemove', this, function(e) {
      
-         var jumpLeaf = e.data.jumpIndexForLeftEdgePageX(e.pageX);
-         $(e.data.twoPagePopUp).text('View Leaf '+jumpLeaf);
+         var jumpIndex = e.data.jumpIndexForLeftEdgePageX(e.pageX);
+         $(e.data.twoPagePopUp).text('View '+ e.data.getPageName(jumpIndex));
          
          $(e.data.twoPagePopUp).css({
              left: e.pageX - $(e.data.twoPagePopUp).width() - 30 + 'px',
  
  // calculateSpreadSize()
  //______________________________________________________________________________
- // Calculates 2-page spread dimensions based on this.currentLeafL and
- // this.currentLeafR
+ // Calculates 2-page spread dimensions based on this.currentIndexL and
+ // this.currentIndexR
  // This function sets this.twoPageH, twoPageW, and twoPageRatio
  
  GnuBook.prototype.calculateSpreadSize = function() {
-     var firstLeaf  = this.currentLeafL;
-     var secondLeaf = this.currentLeafR;
-     //console.log('first page is ' + firstLeaf);
+     var firstIndex  = this.currentIndexL;
+     var secondIndex = this.currentIndexR;
+     //console.log('first page is ' + firstIndex);
  
      var canon5Dratio = 1.5;
      
-     var firstLeafRatio  = this.getPageHeight(firstLeaf) / this.getPageWidth(firstLeaf);
-     var secondLeafRatio = this.getPageHeight(secondLeaf) / this.getPageWidth(secondLeaf);
-     //console.log('firstLeafRatio = ' + firstLeafRatio + ' secondLeafRatio = ' + secondLeafRatio);
+     var firstIndexRatio  = this.getPageHeight(firstIndex) / this.getPageWidth(firstIndex);
+     var secondIndexRatio = this.getPageHeight(secondIndex) / this.getPageWidth(secondIndex);
+     //console.log('firstIndexRatio = ' + firstIndexRatio + ' secondIndexRatio = ' + secondIndexRatio);
  
      var ratio;
-     if (Math.abs(firstLeafRatio - canon5Dratio) < Math.abs(secondLeafRatio - canon5Dratio)) {
-         ratio = firstLeafRatio;
-         //console.log('using firstLeafRatio ' + ratio);
+     if (Math.abs(firstIndexRatio - canon5Dratio) < Math.abs(secondIndexRatio - canon5Dratio)) {
+         ratio = firstIndexRatio;
+         //console.log('using firstIndexRatio ' + ratio);
      } else {
-         ratio = secondLeafRatio;
-         //console.log('using secondLeafRatio ' + ratio);
+         ratio = secondIndexRatio;
+         //console.log('using secondIndexRatio ' + ratio);
      }
  
      var totalLeafEdgeWidth = parseInt(this.numLeafs * 0.1);
@@@ -1040,7 -1042,7 +1042,7 @@@ GnuBook.prototype.last = function() 
  GnuBook.prototype.flipBackToIndex = function(index) {
      if (1 == this.mode) return;
  
-     var leftIndex = this.currentLeafL;
+     var leftIndex = this.currentIndexL;
      
      // $$$ Need to change this to be able to see first spread.
      //     See https://bugs.launchpad.net/gnubook/+bug/296788
  // Flips the page on the left towards the page on the right
  GnuBook.prototype.flipLeftToRight = function(newIndexL, newIndexR, gutter) {
  
-     var leftLeaf = this.currentLeafL;
+     var leftLeaf = this.currentIndexL;
      
-     var oldLeafEdgeWidthL = this.leafEdgeWidth(this.currentLeafL);
+     var oldLeafEdgeWidthL = this.leafEdgeWidth(this.currentIndexL);
      var newLeafEdgeWidthL = this.leafEdgeWidth(newIndexL);    
      var leafEdgeTmpW = oldLeafEdgeWidthL - newLeafEdgeWidthL;
      
              $(self.leafEdgeTmp).remove();
              self.leafEdgeTmp = null;
              
-             self.currentLeafL = newIndexL;
-             self.currentLeafR = newIndexR;
-             self.firstIndex = self.currentLeafL;
-             self.displayedLeafs = [newIndexL, newIndexR];
+             self.currentIndexL = newIndexL;
+             self.currentIndexR = newIndexR;
+             self.firstIndex = self.currentIndexL;
+             self.displayedIndices = [newIndexL, newIndexR];
              self.setClickHandlers();
              self.pruneUnusedImgs();
              self.prefetch();            
@@@ -1237,7 -1239,7 +1239,7 @@@ GnuBook.prototype.flipFwdToIndex = func
      }
  
      if (null == index) {
-         index = this.currentLeafR+2; // $$$ assumes indices are continuous
+         index = this.currentIndexR+2; // $$$ assumes indices are continuous
      }
      if (index > this.lastDisplayableIndex()) return;
  
  //______________________________________________________________________________
  // Flip from left to right and show the nextL and nextR indices on those sides
  GnuBook.prototype.flipRightToLeft = function(newIndexL, newIndexR, gutter) {
-     var oldLeafEdgeWidthL = this.leafEdgeWidth(this.currentLeafL);
+     var oldLeafEdgeWidthL = this.leafEdgeWidth(this.currentIndexL);
      var oldLeafEdgeWidthR = this.twoPageEdgeW-oldLeafEdgeWidthL;
      var newLeafEdgeWidthL = this.leafEdgeWidth(newIndexL);  
      var newLeafEdgeWidthR = this.twoPageEdgeW-newLeafEdgeWidthL;
  
      var top  = ($('#GBcontainer').height() - this.twoPageH) >> 1;                
  
-     var scaledW = this.getPageWidth2UP(this.currentLeafR);
+     var scaledW = this.getPageWidth2UP(this.currentIndexR);
  
      var middle     = ($('#GBcontainer').width() >> 1);
-     var currGutter = middle + this.gutterOffsetForIndex(this.currentLeafL);
+     var currGutter = middle + this.gutterOffsetForIndex(this.currentIndexL);
  
      this.leafEdgeTmp = document.createElement('div');
      $(this.leafEdgeTmp).css({
      //var scaledWR = this.getPageWidth2UP(newIndexR); // $$$ should be current instead?
      //var scaledWL = this.getPageWidth2UP(newIndexL); // $$$ should be current instead?
      
-     var currWidthL = this.getPageWidth2UP(this.currentLeafL);
-     var currWidthR = this.getPageWidth2UP(this.currentLeafR);
+     var currWidthL = this.getPageWidth2UP(this.currentIndexL);
+     var currWidthR = this.getPageWidth2UP(this.currentIndexR);
      var newWidthL = this.getPageWidth2UP(newIndexL);
      var newWidthR = this.getPageWidth2UP(newIndexR);
  
      this.removeSearchHilites();
      
      $(this.leafEdgeTmp).animate({left: gutter}, speed, 'easeInSine');    
-     $(this.prefetchedImgs[this.currentLeafR]).animate({width: '0px'}, speed, 'easeInSine', function() {
+     $(this.prefetchedImgs[this.currentIndexR]).animate({width: '0px'}, speed, 'easeInSine', function() {
          $(self.leafEdgeTmp).animate({left: gutter-newWidthL-leafEdgeTmpW+'px'}, speed, 'easeOutSine');    
          $(self.prefetchedImgs[newIndexL]).animate({width: newWidthL+'px'}, speed, 'easeOutSine', function() {
              $(self.prefetchedImgs[newIndexR]).css('zIndex', 2);
              $(self.leafEdgeTmp).remove();
              self.leafEdgeTmp = null;
              
-             self.currentLeafL = newIndexL;
-             self.currentLeafR = newIndexR;
-             self.firstIndex = self.currentLeafL;
-             self.displayedLeafs = [newIndexL, newIndexR];
+             self.currentIndexL = newIndexL;
+             self.currentIndexR = newIndexR;
+             self.firstIndex = self.currentIndexL;
+             self.displayedIndices = [newIndexL, newIndexR];
              self.setClickHandlers();            
              self.pruneUnusedImgs();
              self.prefetch();
  //______________________________________________________________________________
  GnuBook.prototype.setClickHandlers = function() {
      var self = this;
-     $(this.prefetchedImgs[this.currentLeafL]).click(function() {
+     $(this.prefetchedImgs[this.currentIndexL]).click(function() {
          //self.prevPage();
          self.autoStop();
          self.left();
      });
-     $(this.prefetchedImgs[this.currentLeafR]).click(function() {
+     $(this.prefetchedImgs[this.currentIndexR]).click(function() {
          //self.nextPage();'
          self.autoStop();
          self.right();        
  
  // prefetchImg()
  //______________________________________________________________________________
- GnuBook.prototype.prefetchImg = function(leafNum) {
-     if (undefined == this.prefetchedImgs[leafNum]) {    
-         //console.log('prefetching ' + leafNum);
+ GnuBook.prototype.prefetchImg = function(index) {
+     if (undefined == this.prefetchedImgs[index]) {    
+         //console.log('prefetching ' + index);
          var img = document.createElement("img");
-         img.src = this.getPageURI(leafNum);
-         this.prefetchedImgs[leafNum] = img;
+         img.src = this.getPageURI(index);
+         this.prefetchedImgs[index] = img;
      }
  }
  
@@@ -1500,9 -1502,9 +1502,9 @@@ GnuBook.prototype.prepareFlipRightToLef
  //     //TODO: we might have two left or two right leafs in a row (damaged book)
  //     //For now, assume that leafs are contiguous.
  //     
- //     //return [this.currentLeafL+2, this.currentLeafL+3];
- //     o.L = this.currentLeafL+2;
- //     o.R = this.currentLeafL+3;
+ //     //return [this.currentIndexL+2, this.currentIndexL+3];
+ //     o.L = this.currentIndexL+2;
+ //     o.R = this.currentIndexL+3;
  // }
  
  // getprevLeafs() -- NOT RTL AWARE
  //     //TODO: we might have two left or two right leafs in a row (damaged book)
  //     //For now, assume that leafs are contiguous.
  //     
- //     //return [this.currentLeafL-2, this.currentLeafL-1];
- //     o.L = this.currentLeafL-2;
- //     o.R = this.currentLeafL-1;
+ //     //return [this.currentIndexL-2, this.currentIndexL-1];
+ //     o.L = this.currentIndexL-2;
+ //     o.R = this.currentIndexL-1;
  // }
  
  // pruneUnusedImgs()
  //______________________________________________________________________________
  GnuBook.prototype.pruneUnusedImgs = function() {
-     //console.log('current: ' + this.currentLeafL + ' ' + this.currentLeafR);
+     //console.log('current: ' + this.currentIndexL + ' ' + this.currentIndexR);
      for (var key in this.prefetchedImgs) {
          //console.log('key is ' + key);
-         if ((key != this.currentLeafL) && (key != this.currentLeafR)) {
+         if ((key != this.currentIndexL) && (key != this.currentIndexR)) {
              //console.log('removing key '+ key);
              $(this.prefetchedImgs[key]).remove();
          }
-         if ((key < this.currentLeafL-4) || (key > this.currentLeafR+4)) {
+         if ((key < this.currentIndexL-4) || (key > this.currentIndexR+4)) {
              //console.log('deleting key '+ key);
              delete this.prefetchedImgs[key];
          }
  //______________________________________________________________________________
  GnuBook.prototype.prefetch = function() {
  
-     var lim = this.currentLeafL-4;
+     var lim = this.currentIndexL-4;
      var i;
      lim = Math.max(lim, 0);
-     for (i = lim; i < this.currentLeafL; i++) {
+     for (i = lim; i < this.currentIndexL; i++) {
          this.prefetchImg(i);
      }
      
-     if (this.numLeafs > (this.currentLeafR+1)) {
-         lim = Math.min(this.currentLeafR+4, this.numLeafs-1);
-         for (i=this.currentLeafR+1; i<=lim; i++) {
+     if (this.numLeafs > (this.currentIndexR+1)) {
+         lim = Math.min(this.currentIndexR+4, this.numLeafs-1);
+         for (i=this.currentIndexR+1; i<=lim; i++) {
              this.prefetchImg(i);
          }
      }
@@@ -1569,6 -1571,7 +1571,7 @@@ GnuBook.prototype.search = function(ter
        script.setAttribute("type", "text/javascript");
        script.setAttribute("src", 'http://'+this.server+'/GnuBook/flipbook_search_gb.php?url='+escape(this.bookPath+'/'+this.bookId+'_djvu.xml')+'&term='+term+'&format=XML&callback=gb.GBSearchCallback');
        document.getElementsByTagName('head')[0].appendChild(script);
+       $('#GnuBookSearchResults').html('Searching...');
  }
  
  // GBSearchCallback()
@@@ -1606,8 -1609,8 +1609,8 @@@ GnuBook.prototype.GBSearchCallback = fu
              
              var re = new RegExp (/_(\d{4})/);
              var reMatch = re.exec(pages[i].getAttribute('file'));
-             var leafNum = parseInt(reMatch[1], 10);
-             //var leafNum = parseInt(pages[i].getAttribute('file').substr(1), 10);
+             var index = parseInt(reMatch[1], 10);
+             //var index = parseInt(pages[i].getAttribute('file').substr(1), 10);
              
              var children = pages[i].childNodes;
              var context = '';
                  } else if ('WORD' == children[j].nodeName) {
                      context += '<b>'+children[j].firstChild.nodeValue+'</b>';
                      
-                     var index = this.leafNumToIndex(leafNum);
+                     var index = this.leafNumToIndex(index);
                      if (null != index) {
                          //coordinates are [left, bottom, right, top, [baseline]]
                          //we'll skip baseline for now...
                      }
                  }
              }
+             var pageName = this.getPageName(index);
              //TODO: remove hardcoded instance name
-             $('#GnuBookSearchResults').append('<li><b><a href="javascript:gb.jumpToIndex('+index+');">Leaf ' + leafNum + '</a></b> - ' + context+'</li>');
+             $('#GnuBookSearchResults').append('<li><b><a href="javascript:gb.jumpToIndex('+index+');">' + pageName + '</a></b> - ' + context + '</li>');
          }
      }
      $('#GnuBookSearchResults').append('</ul>');
@@@ -1655,7 -1659,7 +1659,7 @@@ GnuBook.prototype.updateSearchHilites1U
  
      for (var key in this.searchResults) {
          
-         if (-1 != jQuery.inArray(parseInt(key), this.displayedLeafs)) {
+         if (-1 != jQuery.inArray(parseInt(key), this.displayedIndices)) {
              var result = this.searchResults[key];
              if(null == result.div) {
                  result.div = document.createElement('div');
@@@ -1684,7 -1688,7 +1688,7 @@@ GnuBook.prototype.updateSearchHilites2U
  
      for (var key in this.searchResults) {
          key = parseInt(key, 10);
-         if (-1 != jQuery.inArray(key, this.displayedLeafs)) {
+         if (-1 != jQuery.inArray(key, this.displayedIndices)) {
              var result = this.searchResults[key];
              if(null == result.div) {
                  result.div = document.createElement('div');
              var reduce = this.twoPageH/height;
              var scaledW = parseInt(width*reduce);
              
-             var gutter = middle + this.gutterOffsetForIndex(this.currentLeafL);
+             var gutter = middle + this.gutterOffsetForIndex(this.currentIndexL);
              
              if ('L' == this.getPageSide(key)) {
                  var pageL = gutter-scaledW;
@@@ -1795,7 -1799,7 +1799,7 @@@ GnuBook.prototype.autoToggle = function
          this.autoTimer=setInterval(function(){
              if (self.animating) {return;}
              
-             if (Math.max(self.currentLeafL, self.currentLeafR) >= self.lastDisplayableIndex()) {
+             if (Math.max(self.currentIndexL, self.currentIndexR) >= self.lastDisplayableIndex()) {
                  self.flipBackToIndex(1); // $$$ really what we want?
              } else {            
                  self.flipFwdToIndex();
@@@ -1865,16 -1869,16 +1869,16 @@@ GnuBook.prototype.leafEdgeWidth = funct
  GnuBook.prototype.jumpIndexForLeftEdgePageX = function(pageX) {
      if ('rl' != this.pageProgression) {
          // LTR - flipping backward
-         var jumpLeaf = this.currentLeafL - ($(this.leafEdgeL).offset().left + $(this.leafEdgeL).width() - pageX) * 10;
-         // browser may have resized the div due to font size change -- see https://bugs.launchpad.net/gnubook/+bug/333570
-         jumpLeaf = Math.min(jumpLeaf, this.currentLeafL - 2);
-         jumpLeaf = Math.max(jumpLeaf, this.firstDisplayableIndex());
-         return jumpLeaf;
+         var jumpIndex = this.currentIndexL - ($(this.leafEdgeL).offset().left + $(this.leafEdgeL).width() - pageX) * 10;
+         // browser may have resized the div due to font size change -- see https://bugs.launchpad.net/gnubook/+bug/333570        
+         jumpIndex = GnuBook.util.clamp(Math.round(jumpIndex), this.firstDisplayableIndex(), this.currentIndexL - 2);
+         return jumpIndex;
      } else {
-         var jumpLeaf = this.currentLeafL + ($(this.leafEdgeL).offset().left + $(this.leafEdgeL).width() - pageX) * 10;
-         jumpLeaf = Math.max(jumpLeaf, this.currentLeafL + 2);
-         jumpLeaf = Math.min(jumpLeaf, this.lastDisplayableIndex());
-         return jumpLeaf;
+         var jumpIndex = this.currentIndexL + ($(this.leafEdgeL).offset().left + $(this.leafEdgeL).width() - pageX) * 10;
+         jumpIndex = GnuBook.util.clamp(Math.round(jumpIndex), this.currentIndexL + 2, this.lastDisplayableIndex());
+         return jumpIndex;
      }
  }
  
  GnuBook.prototype.jumpIndexForRightEdgePageX = function(pageX) {
      if ('rl' != this.pageProgression) {
          // LTR
-         var jumpLeaf = this.currentLeafR + (pageX - $(this.leafEdgeR).offset().left) * 10;
-         jumpLeaf = Math.max(jumpLeaf, this.currentLeafR + 2);
-         jumpLeaf = Math.min(jumpLeaf, this.lastDisplayableIndex());
-         return jumpLeaf;
+         var jumpIndex = this.currentIndexR + (pageX - $(this.leafEdgeR).offset().left) * 10;
+         jumpIndex = GnuBook.util.clamp(Math.round(jumpIndex), this.currentIndexR + 2, this.lastDisplayableIndex());
+         return jumpIndex;
      } else {
-         var jumpLeaf = this.currentLeafR - (pageX - $(this.leafEdgeR).offset().left) * 10;
-         jumpLeaf = Math.min(jumpLeaf, this.currentLeafR - 2);
-         jumpLeaf = Math.max(jumpLeaf, this.firstDisplayableIndex());
-         return jumpLeaf;
+         var jumpIndex = this.currentIndexR - (pageX - $(this.leafEdgeR).offset().left) * 10;
+         jumpIndex = GnuBook.util.clamp(Math.round(jumpIndex), this.firstDisplayableIndex(), this.currentIndexR - 2);
+         return jumpIndex;
      }
  }
  
@@@ -1901,7 -1903,7 +1903,7 @@@ GnuBook.prototype.initToolbar = functio
          + "<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'>25</span>%</span>"
 +        + " <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>"
      jToolbar.append("<span id='GBtoolbarbuttons' style='float: right'>"
          + "<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_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>"
+         + "<div class='GBtoolbarmode2' style='display: none'><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: none'><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);
@@@ -1966,11 -1968,11 +1968,11 @@@ GnuBook.prototype.switchToolbarMode = f
      if (1 == mode) {
          // 1-up     
          $('#GBtoolbar .GBtoolbarmode2').hide();
-         $('#GBtoolbar .GBtoolbarmode1').css('display', 'inline').show();
+         $('#GBtoolbar .GBtoolbarmode1').show().css('display', 'inline');
      } else {
          // 2-up
          $('#GBtoolbar .GBtoolbarmode1').hide();
-         $('#GBtoolbar .GBtoolbarmode2').css('display', 'inline').show();
+         $('#GBtoolbar .GBtoolbarmode2').show().css('display', 'inline');
      }
  }
  
@@@ -2108,6 -2110,7 +2110,7 @@@ GnuBook.prototype.updateFromParams = fu
              this.jumpToIndex(params.index);
          }
      } else if ('undefined' != typeof(params.page)) {
+         // $$$ this assumes page numbers are unique
          if (params.page != this.getPageNum(this.currentIndex())) {
              this.jumpToPage(params.page);
          }
@@@ -2227,16 -2230,30 +2230,30 @@@ GnuBook.prototype.fragmentFromParams = 
  
  // getPageIndex(pageNum)
  //________
- // Returns the index of the given page number, or undefined
+ // Returns the *highest* index the given page number, or undefined
  GnuBook.prototype.getPageIndex = function(pageNum) {
-     var pageIndex = undefined;
+     var pageIndices = this.getPageIndices(pageNum);
      
+     if (pageIndices.length > 0) {
+         return pageIndices[pageIndices.length - 1];
+     }
+     return undefined;
+ }
+ // getPageIndices(pageNum)
+ //________
+ // Returns an array (possibly empty) of the indices with the given page number
+ GnuBook.prototype.getPageIndices = function(pageNum) {
+     var indices = [];
      // Check for special "nXX" page number
      if (pageNum.slice(0,1) == 'n') {
          try {
              var pageIntStr = pageNum.slice(1, pageNum.length);
-             pageIndex = parseInt(pageIntStr);
-             return pageIndex;
+             var pageIndex = parseInt(pageIntStr);
+             indices.append(pageIndex);
+             return indices;
          } catch(err) {
              // Do nothing... will run through page names and see if one matches
          }
      var i;
      for (i=0; i<this.numLeafs; i++) {
          if (this.getPageNum(i) == pageNum) {
-             pageIndex = i;
-             return pageIndex;
+             indices.push(i);
          }
      }
+     
+     return indices;
+ }
  
-     return pageIndex;
+ // getPageName(index)
+ //________
+ // Returns the name of the page as it should be displayed in the user interface
+ GnuBook.prototype.getPageName = function(index) {
+     return 'Page ' + this.getPageNum(index);
  }
  
  // updateLocationHash
@@@ -2312,4 -2335,12 +2335,12 @@@ GnuBook.prototype.getEmbedURL = functio
  // Returns the embed code HTML fragment suitable for copy and paste
  GnuBook.prototype.getEmbedCode = function() {
      return "<iframe src='" + this.getEmbedURL() + "' width='480px' height='430px'></iframe>";
+ }
+ // Library functions
+ GnuBook.util = {
+     clamp: function(value, min, max) {
+         return Math.min(Math.max(value, min), max);
+     }
  }