X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=BookReader%2FBookReader.js;h=2a59cd12287b86dbcbeec9b2fa0afd333e1f06df;hb=5019be45e497e0253665010fc509d47e0299ae35;hp=191617dfa925fcf69aa2cb1f64baa113a1b258a8;hpb=d1e690ada4709a4775b161a28c9283fa0902cd27;p=bookreader.git diff --git a/BookReader/BookReader.js b/BookReader/BookReader.js index 191617d..2a59cd1 100644 --- a/BookReader/BookReader.js +++ b/BookReader/BookReader.js @@ -36,16 +36,25 @@ This file is part of BookReader. // You must also add a numLeafs property before calling init(). function BookReader() { + + // Mode constants + this.constMode1up = 1; + this.constMode2up = 2; + this.constModeThumb = 3; + this.reduce = 4; - this.padding = 10; - this.mode = 1; //1, 2, 3 - this.ui = 'full'; // UI mode + this.padding = 10; // Padding in 1up + + this.mode = this.constMode1up; + this.ui = 'full'; // UI mode + this.uiAutoHide = false; // Controls whether nav/toolbar will autohide // thumbnail mode this.thumbWidth = 100; // will be overridden during prepareThumbnailView this.thumbRowBuffer = 2; // number of rows to pre-cache out a view this.thumbColumns = 6; // default this.thumbMaxLoading = 4; // number of thumbnails to load at once + this.thumbPadding = 10; // spacing between thumbnails this.displayedRows=[]; this.displayedIndices = []; @@ -62,7 +71,7 @@ function BookReader() { this.twoPagePopUp = null; this.leafEdgeTmp = null; this.embedPopup = null; - this.popup = null; + this.printPopup = null; this.searchTerm = ''; this.searchResults = {}; @@ -72,15 +81,15 @@ function BookReader() { this.lastDisplayableIndex2up = null; // We link to index.php to avoid redirect which breaks back button - this.logoURL = 'http://www.archive.org/index.php'; + // Should be overriden (before init) by custom implmentations. + this.logoURL = 'http://openlibrary.org'; - // Base URL for images + // Base URL for UI images - should be overriden (before init) by + // custom implementations. + // $$$ This is the same directory as the images referenced by relative + // path in the CSS. Would be better to automagically find that path. this.imagesBaseURL = '/bookreader/images/'; - // Mode constants - this.constMode1up = 1; - this.constMode2up = 2; - this.constModeThumb = 3; // Zoom levels // $$$ provide finer grained zooming @@ -98,12 +107,23 @@ function BookReader() { // Object to hold parameters related to 2up mode this.twoPage = { - coverInternalPadding: 10, // Width of cover - coverExternalPadding: 10, // Padding outside of cover - bookSpineDivWidth: 30, // Width of book spine $$$ consider sizing based on book length + coverInternalPadding: 0, // Width of cover + coverExternalPadding: 0, // Padding outside of cover + bookSpineDivWidth: 0, // Width of book spine $$$ consider sizing based on book length autofit: 'auto' }; + // This object/dictionary controls which optional features are enabled + // XXXmang in progress + this.features = { + // search + // read aloud + // open library entry + // table of contents + // embed/share ui + // info ui + }; + // Text-to-Speech params this.ttsPlaying = false; this.ttsIndex = null; //leaf index @@ -124,16 +144,25 @@ BookReader.prototype.init = function() { // Find start index and mode if set in location hash var params = this.paramsFromFragment(window.location.hash); + + // Sanitize/process parameters + + if ( !this.canSwitchToMode( this.mode ) ) { + this.mode = this.constMode1up; + } if ('undefined' != typeof(params.index)) { startIndex = params.index; } else if ('undefined' != typeof(params.page)) { startIndex = this.getPageIndex(params.page); } - + if ('undefined' == typeof(startIndex)) { if ('undefined' != typeof(this.titleLeaf)) { - startIndex = this.leafNumToIndex(this.titleLeaf); + // title leaf is known - but only use as default if book has a few pages + if (this.numLeafs > 2) { + startIndex = this.leafNumToIndex(this.titleLeaf); + } } } @@ -149,21 +178,25 @@ BookReader.prototype.init = function() { // search engine visibility document.title = this.shortTitle(50); - // Sanitize parameters - if ( !this.canSwitchToMode( this.mode ) ) { - this.mode = this.constMode1up; - } - $("#BookReader").empty(); this.initToolbar(this.mode, this.ui); // Build inside of toolbar div + $("#BookReader").append("
"); $("#BRcontainer").append("
"); + + // Autohide nav after showing for awhile + var self = this; + if (this.uiAutoHide) { + $(window).bind('load', function() { + setTimeout(function() { self.hideNavigation(); }, 3000); + }); + }; $("#BRcontainer").bind('scroll', this, function(e) { e.data.loadLeafs(); }); - + this.setupKeyListeners(); this.startLocationPolling(); @@ -235,6 +268,16 @@ BookReader.prototype.init = function() { // Enact other parts of initial params this.updateFromParams(params); + + // We init the nav bar after the params processing so that the nav slider knows where + // it should start (doesn't jump after init) + this.initNavbar(); + this.bindNavigationHandlers(); + + // Start AJAX request for OL data + if (this.getOpenLibraryRecord) { + this.getOpenLibraryRecord(this.gotOpenLibraryRecord); + } } BookReader.prototype.setupKeyListeners = function() { @@ -321,7 +364,6 @@ BookReader.prototype.bindGestures = function(jElement) { br.zoom(-1); } }); - } BookReader.prototype.setClickHandler2UP = function( element, data, handler) { @@ -484,7 +526,7 @@ BookReader.prototype.drawLeafsThumbnail = function( seekIndex ) { // Calculate the position of every thumbnail. $$$ cache instead of calculating on every draw for (i=0; i viewWidth){ + if (rightPos + (leafWidth + this.thumbPadding) > viewWidth){ currentRow++; rightPos = 0; leafIndex = 0; @@ -504,13 +546,13 @@ BookReader.prototype.drawLeafsThumbnail = function( seekIndex ) { if (leafHeight > leafMap[currentRow].height) { leafMap[currentRow].height = leafHeight; } - if (leafIndex===0) { bottomPos += this.padding + leafMap[currentRow].height; } - rightPos += leafWidth + this.padding; + if (leafIndex===0) { bottomPos += this.thumbPadding + leafMap[currentRow].height; } + rightPos += leafWidth + this.thumbPadding; if (rightPos > maxRight) { maxRight = rightPos; } leafIndex++; if (i == seekIndex) { - seekTop = bottomPos - this.padding - leafMap[currentRow].height; + seekTop = bottomPos - this.thumbPadding - leafMap[currentRow].height; } } @@ -537,7 +579,7 @@ BookReader.prototype.drawLeafsThumbnail = function( seekIndex ) { // Determine the thumbnails in view for (i=0; i= scrollTop) && (leafTop <= scrollBottom); var bottomInView = (leafBottom >= scrollTop) && (leafBottom <= scrollBottom); var middleInView = (leafTop <=scrollTop) && (leafBottom>=scrollBottom); @@ -595,7 +637,7 @@ BookReader.prototype.drawLeafsThumbnail = function( seekIndex ) { div.style.position = "absolute"; div.className = "BRpagedivthumb"; - left += this.padding; + left += this.thumbPadding; $(div).css('top', leafTop + 'px'); $(div).css('left', left+'px'); $(div).css('width', leafWidth+'px'); @@ -782,7 +824,6 @@ BookReader.prototype.drawLeafsTwoPage = function() { top: top+'px', height: this.twoPage.height +'px', // $$$ height forced the same for both pages width: this.twoPage.scaledWL + 'px', - borderRight: '1px solid black', zIndex: 2 }).appendTo('#BRtwopageview'); @@ -801,7 +842,6 @@ BookReader.prototype.drawLeafsTwoPage = function() { top: top+'px', height: this.twoPage.height + 'px', // $$$ height forced the same for both pages width: this.twoPage.scaledWR + 'px', - borderLeft: '1px solid black', zIndex: 2 }).appendTo('#BRtwopageview'); @@ -1079,7 +1119,7 @@ BookReader.prototype.zoomThumb = function(direction) { // Note: #BRpageview must already exist since its width is used to calculate the // thumbnail width BookReader.prototype.getThumbnailWidth = function(thumbnailColumns) { - var padding = (thumbnailColumns + 1) * this.padding; + var padding = (thumbnailColumns + 1) * this.thumbPadding; var width = ($('#BRpageview').width() - padding) / (thumbnailColumns + 0.5); // extra 0.5 is for some space at sides return parseInt(width); } @@ -1168,6 +1208,8 @@ BookReader.prototype.jumpToPage = function(pageNum) { //______________________________________________________________________________ BookReader.prototype.jumpToIndex = function(index, pageX, pageY) { + this.updateNavIndex(index); + if (this.constMode2up == this.mode) { this.autoStop(); @@ -1192,7 +1234,7 @@ BookReader.prototype.jumpToIndex = function(index, pageX, pageY) { for (i=0; i<(index+1); i++) { leafWidth = this.thumbWidth; - if (rightPos + (leafWidth + this.padding) > viewWidth){ + if (rightPos + (leafWidth + this.thumbPadding) > viewWidth){ rightPos = 0; rowHeight = 0; leafIndex = 0; @@ -1201,8 +1243,8 @@ BookReader.prototype.jumpToIndex = function(index, pageX, pageY) { 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; } - rightPos += leafWidth + this.padding; + if (leafIndex==0) { bottomPos += this.thumbPadding + rowHeight; } + rightPos += leafWidth + this.thumbPadding; leafIndex++; } this.firstIndex=index; @@ -1267,7 +1309,7 @@ BookReader.prototype.switchMode = function(mode) { this.removeSearchHilites(); this.mode = mode; - this.switchToolbarMode(mode); + //this.switchToolbarMode(mode); // reinstate scale if moving from thumbnail view if (this.pageScale != this.reduce) { @@ -1283,13 +1325,17 @@ BookReader.prototype.switchMode = function(mode) { this.reduce = this.quantizeReduce(this.reduce, this.onePage.reductionFactors); this.prepareOnePageView(); } else if (3 == mode) { + $('button.thumb').hide(); + $('button.twopg').show(); this.reduce = this.quantizeReduce(this.reduce, this.reductionFactors); this.prepareThumbnailView(); } else { // $$$ why don't we save autofit? - this.twoPage.autofit = null; // Take zoom level from other mode + // this.twoPage.autofit = null; // Take zoom level from other mode this.twoPageCalculateReductionFactors(); this.reduce = this.quantizeReduce(this.reduce, this.twoPage.reductionFactors); + $('button.thumb').show(); + $('button.twopg').hide(); this.prepareTwoPageView(); this.twoPageCenterView(0.5, 0.5); // $$$ TODO preserve center } @@ -1434,16 +1480,13 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc width: this.twoPage.bookCoverDivWidth + 'px', height: this.twoPage.bookCoverDivHeight+'px', visibility: 'visible', - position: 'absolute', - left: this.twoPage.bookCoverDivLeft + 'px', - top: this.twoPage.bookCoverDivTop+'px' }).appendTo('#BRtwopageview'); this.leafEdgeR = document.createElement('div'); this.leafEdgeR.className = 'BRleafEdgeR'; $(this.leafEdgeR).css({ width: this.twoPage.leafEdgeWidthR + 'px', - height: this.twoPage.height-1 + 'px', + height: this.twoPage.height + 'px', left: this.twoPage.gutter+this.twoPage.scaledWR+'px', top: this.twoPage.bookCoverDivTop+this.twoPage.coverInternalPadding+'px' }).appendTo('#BRtwopageview'); @@ -1452,7 +1495,7 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc this.leafEdgeL.className = 'BRleafEdgeL'; $(this.leafEdgeL).css({ width: this.twoPage.leafEdgeWidthL + 'px', - height: this.twoPage.height-1 + 'px', + height: this.twoPage.height + 'px', left: this.twoPage.bookCoverDivLeft+this.twoPage.coverInternalPadding+'px', top: this.twoPage.bookCoverDivTop+this.twoPage.coverInternalPadding+'px' }).appendTo('#BRtwopageview'); @@ -1479,7 +1522,7 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc top: this.twoPageFlipAreaTop() + 'px', cursor: 'w-resize', zIndex: 100 - }).bind('click', function(e) { + }).click(function(e) { self.left(); }).bind('mousedown', function(e) { e.preventDefault(); @@ -1496,7 +1539,7 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc top: this.twoPageFlipAreaTop() + 'px', cursor: 'e-resize', zIndex: 100 - }).bind('click', function(e) { + }).click(function(e) { self.right(); }).bind('mousedown', function(e) { e.preventDefault(); @@ -1565,7 +1608,7 @@ BookReader.prototype.prepareTwoPagePopUp = function() { // $$$ TODO: Make sure popup is positioned so that it is in view // (https://bugs.edge.launchpad.net/gnubook/+bug/327456) $(e.data.twoPagePopUp).css({ - left: e.pageX- $('#BRcontainer').offset().left + $('#BRcontainer').scrollLeft() + 20 + 'px', + left: e.pageX- $('#BRcontainer').offset().left + $('#BRcontainer').scrollLeft() - 100 + 'px', top: e.pageY - $('#BRcontainer').offset().top + $('#BRcontainer').scrollTop() + 'px' }); }); @@ -1578,7 +1621,7 @@ BookReader.prototype.prepareTwoPagePopUp = function() { // $$$ TODO: Make sure popup is positioned so that it is in view // (https://bugs.edge.launchpad.net/gnubook/+bug/327456) $(e.data.twoPagePopUp).css({ - left: e.pageX - $('#BRcontainer').offset().left + $('#BRcontainer').scrollLeft() - $(e.data.twoPagePopUp).width() - 25 + 'px', + left: e.pageX - $('#BRcontainer').offset().left + $('#BRcontainer').scrollLeft() - $(e.data.twoPagePopUp).width() + 100 + 'px', top: e.pageY-$('#BRcontainer').offset().top + $('#BRcontainer').scrollTop() + 'px' }); }); @@ -1622,7 +1665,7 @@ BookReader.prototype.calculateSpreadSize = function() { // Book cover // The width of the book cover div. The combined width of both pages, twice the width // of the book cover internal padding (2*10) and the page edges - this.twoPage.bookCoverDivWidth = this.twoPage.scaledWL + this.twoPage.scaledWR + 2 * this.twoPage.coverInternalPadding + this.twoPage.edgeWidth; + this.twoPage.bookCoverDivWidth = this.twoPageCoverWidth(this.twoPage.scaledWL + this.twoPage.scaledWR); // The height of the book cover div this.twoPage.bookCoverDivHeight = this.twoPage.height + 2 * this.twoPage.coverInternalPadding; @@ -1989,6 +2032,8 @@ BookReader.prototype.flipBackToIndex = function(index) { } //if (index<0) return; + this.updateNavIndex(index); + var previousIndices = this.getSpreadIndices(index); if (previousIndices[0] < this.firstDisplayableIndex() || previousIndices[1] < this.firstDisplayableIndex()) { @@ -2062,7 +2107,7 @@ BookReader.prototype.flipLeftToRight = function(newIndexL, newIndexR) { this.leafEdgeTmp.className = 'BRleafEdgeTmp'; $(this.leafEdgeTmp).css({ width: leafEdgeTmpW + 'px', - height: this.twoPage.height-1 + 'px', + height: this.twoPage.height + 'px', left: leftEdgeTmpLeft + 'px', top: top+'px', zIndex:1000 @@ -2161,7 +2206,7 @@ BookReader.prototype.flipLeftToRight = function(newIndexL, newIndexR) { BookReader.prototype.flipFwdToIndex = function(index) { if (this.animating) return; - + if (null != this.leafEdgeTmp) { alert('error: leafEdgeTmp should be null!'); return; @@ -2172,6 +2217,8 @@ BookReader.prototype.flipFwdToIndex = function(index) { } if (index > this.lastDisplayableIndex()) return; + this.updateNavIndex(index); + this.animating = true; var nextIndices = this.getSpreadIndices(index); @@ -2211,7 +2258,7 @@ BookReader.prototype.flipRightToLeft = function(newIndexL, newIndexR) { this.leafEdgeTmp.className = 'BRleafEdgeTmp'; $(this.leafEdgeTmp).css({ width: leafEdgeTmpW + 'px', - height: this.twoPage.height-1 + 'px', + height: this.twoPage.height + 'px', left: gutter+scaledW+'px', top: top+'px', zIndex:1000 @@ -2369,7 +2416,7 @@ BookReader.prototype.prepareFlipLeftToRight = function(prevL, prevR) { top: top+'px', height: this.twoPage.height, width: scaledW+'px', - borderRight: '1px solid black', + borderRight: '1px solid black', // XXXmang check zIndex: 1 } @@ -2385,8 +2432,8 @@ BookReader.prototype.prepareFlipLeftToRight = function(prevL, prevR) { right: '', top: top+'px', height: this.twoPage.height, - width: '0px', - borderLeft: '1px solid black', + borderLeft: '1px solid black', // XXXmang check + width: '0', zIndex: 2 } @@ -2422,7 +2469,6 @@ BookReader.prototype.prepareFlipRightToLeft = function(nextL, nextR) { top: top+'px', height: this.twoPage.height, width: scaledW+'px', - borderLeft: '1px solid black', zIndex: 1 }); @@ -2439,7 +2485,6 @@ BookReader.prototype.prepareFlipRightToLeft = function(nextL, nextR) { top: top+'px', height: this.twoPage.height, width: 0+'px', // Start at 0 width, then grow to the left - borderRight: '1px solid black', zIndex: 2 }); @@ -2951,29 +2996,75 @@ BookReader.prototype.showEmbedCode = function() { } this.autoStop(); this.ttsStop(); + this.embedPopup = document.createElement("div"); $(this.embedPopup).css({ position: 'absolute', - top: '20px', + top: ($('#BRcontainer').attr('clientHeight')-250)/2 + 'px', left: ($('#BRcontainer').attr('clientWidth')-400)/2 + 'px', width: '400px', - padding: "20px", - border: "3px double #999999", - zIndex: 3, - backgroundColor: "#fff" + height: '250px', + padding: '0', + fontSize: '12px', + color: '#333', + zIndex: 300, + border: '10px solid #615132', + backgroundColor: "#fff", + MozBorderRadius: '8px', + MozBoxShadow: '0 0 6px #000', + WebkitBorderRadius: '8px', + WebkitBoxShadow: '0 0 6px #000' }).appendTo('#BookReader'); - htmlStr = '

Embed Bookreader in your blog!

'; - htmlStr += '

The bookreader uses iframes for embedding. It will not work on web hosts that block iframes. The embed feature has been tested on blogspot.com blogs as well as self-hosted Wordpress blogs. This feature will NOT work on wordpress.com blogs.

'; - htmlStr += '

Embed Code:

'; - htmlStr += '

Close popup

'; + htmlStr = '

Embed Bookreader

'; + htmlStr += '

The bookreader uses iframes for embedding. It will not work on web hosts that block iframes. The embed feature has been tested on blogspot.com blogs as well as self-hosted Wordpress blogs. This feature will NOT work on wordpress.com blogs.

'; + htmlStr += ''; + htmlStr += 'Close'; this.embedPopup.innerHTML = htmlStr; - $(this.embedPopup).find('input').bind('click', function() { + $('#BookReader').append('
'); + $(this.embedPopup).find('textarea').click(function() { this.select(); }) + $(this.embedPopup).addClass("popped"); } +// showBookmarkCode() +//______________________________________________________________________________ +BookReader.prototype.showBookmarkCode = function() { + this.bookmarkPopup = document.createElement("div"); + $(this.bookmarkPopup).css({ + position: 'absolute', + top: ($('#BRcontainer').attr('clientHeight')-250)/2 + 'px', + left: ($('#BRcontainer').attr('clientWidth')-400)/2 + 'px', + width: '400px', + height: '250px', + padding: '0', + fontSize: '12px', + color: '#333', + zIndex: 300, + border: '10px solid #615132', + backgroundColor: "#fff", + MozBorderRadius: '8px', + MozBoxShadow: '0 0 6px #000', + WebkitBorderRadius: '8px', + WebkitBoxShadow: '0 0 6px #000' + }).appendTo('#BookReader'); + + htmlStr = '

Add a bookmark

'; + htmlStr += '

You can add a bookmark to any page in any book. If you elect to make your bookmark public, other readers will be able to see it. You must be logged in to your Open Library account to add bookmarks.

'; + htmlStr += '



'; + htmlStr += 'Close'; + + this.bookmarkPopup.innerHTML = htmlStr; + $('#BookReader').append('
'); + $(this.bookmarkPopup).find('textarea').click(function() { + this.select(); + }) + $(this.bookmarkPopup).addClass("popped"); +} + + // autoToggle() //______________________________________________________________________________ BookReader.prototype.autoToggle = function() { @@ -3134,32 +3225,353 @@ BookReader.prototype.jumpIndexForRightEdgePageX = function(pageX) { } } +// initNavbar +//______________________________________________________________________________ +// Initialize the navigation bar. +// $$$ this could also add the base elements to the DOM, so disabling the nav bar +// could be as simple as not calling this function +BookReader.prototype.initNavbar = function() { + // Setup nav / chapter / search results bar + + // $$$ should make this work inside the BookReader div (self-contained), rather than after + $('#BookReader').after( + '
' + + '
' + + '' + + '' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + ); + +/* +
+
+ A related distinction is between the emotion and the results of the emotion, principally behaviors and emotional expressions. People often behave in certain ways as a direct result of their emotional state, such as crying, fighting or fleeing. Page 163 +
IV. The Witch | Page 163
+
+
+*/ + + /* $$$mang search results and chapters should automatically coalesce + $('.searchChap').bt({ + contentSelector: '$(this).find(".query")', + trigger: 'click', + closeWhenOthersOpen: true, + cssStyles: { + width: '250px', + padding: '10px 10px 15px', + backgroundColor: '#fff', + border: '3px solid #e2dcc5', + borderBottom: 'none', + fontFamily: '"Lucida Grande","Arial",sans-serif', + fontSize: '12px', + lineHeight: '18px', + color: '#615132' + }, + shrinkToFit: false, + width: '230px', + padding: 0, + spikeGirth: 0, + spikeLength: 0, + overlap: '10px', + overlay: false, + killTitle: true, + textzIndex: 9999, + boxzIndex: 9998, + wrapperzIndex: 9997, + offsetParent: null, + positions: ['top'], + fill: 'white', + windowMargin: 10, + strokeWidth: 3, + strokeStyle: '#e2dcc5', + cornerRadius: 0, + centerPointX: 0, + centerPointY: 0, + shadow: false + }); + $('.searchChap').each(function(){ + $(this).hover(function(){ + $(this).addClass('front'); + },function(){ + $(this).removeClass('front'); + }); + }); + */ + var self = this; + $('#BRpager').slider({ + animate: true, + min: 0, + max: this.numLeafs - 1, + value: this.currentIndex() + }) + .bind('slide', function(event, ui){ + self.updateNavPageNum(ui.value); + $("#pagenum").show(); + return true; + }) + .bind('slidechange', function(event, ui) { + $("#pagenum").hide(); + + // recursion prevention for jumpToIndex + if ( $(this).data('swallowchange') ) { + $(this).data('swallowchange', false); + } else { + self.jumpToIndex(ui.value); + } + return true; + }) + .hover(function() { + // $$$ not working on iPad + $("#pagenum").show(); + },function(){ + $("#pagenum").hide(); + } + ); + + //append icon to handle + var handleHelper = $('#BRpager .ui-slider-handle') + // $$$mang update logic for setting the page number label -- use page numbers if available + .append('
'); + //.wrap('
').parent(); // XXXmang is this used for hiding the tooltip? + + $('.BRicon.book_left').bind('click', function() { + self.left(); + }); + $('.BRicon.book_right').bind('click', function() { + self.right(); + }); + + this.updateNavPageNum(this.currentIndex()); + + $("#BRzoombtn").draggable({axis:'y',containment:'parent'}); +} + +BookReader.prototype.updateNavPageNum = function(index) { + var pageNum = this.getPageNum(index); + var pageStr; + if (pageNum[0] == 'n') { // funny index + pageStr = index + ' / ' + this.numLeafs; + } else { + pageStr = 'Page ' + pageNum; + } + + $('#pagenum .currentpage').text(pageStr); +} + +/* + * Update the nav bar display - does not cause navigation. + */ +BookReader.prototype.updateNavIndex = function(index) { + // We want to update the value, but normally moving the slider + // triggers jumpToIndex which triggers this method + $('#BRpager').data('swallowchange', true).slider('value', index); +} + +BookReader.prototype.addSearchResult = function(queryString, pageNumber, pageIndex) { + var uiStringSearch = "Search result"; // i18n + var uiStringPage = "Page"; // i18n + + var percentThrough = BookReader.util.cssPercentage(pageIndex, this.numLeafs); + + // $$$mang add click-through to page + $('" - + "" - + "  "+this.bookTitle+"" - + "" + + "
" + + "
" + + "" + + "
" + + "
" + + "
" + + "
" + + "" + + "
" + "
"); this.updateToolbarZoom(this.reduce); // Pretty format @@ -3180,11 +3592,15 @@ BookReader.prototype.initToolbar = function(mode, ui) { 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', - '.thumbnail_mode': 'Thumbnail view', + '.onepg': 'One-page view', + '.twopg': 'Two-page view', + '.thumb': 'Thumbnail view', '.print': 'Print this page', - '.embed': 'Embed bookreader', + '.embed': 'Embed BookReader', + '.link': 'Link to this book (and page)', + '.bookmark': 'Bookmark this page', + '.read': 'Allow BookReader to read this aloud', + '.full': 'Show fullscreen', '.book_left': 'Flip left', '.book_right': 'Flip right', '.book_up': 'Page up', @@ -3209,11 +3625,19 @@ BookReader.prototype.initToolbar = function(mode, ui) { // Hide mode buttons and autoplay if 2up is not available // $$$ if we end up with more than two modes we should show the applicable buttons if ( !this.canSwitchToMode(this.constMode2up) ) { - jToolbar.find('.one_page_mode, .two_page_mode, .play, .pause').hide(); + jToolbar.find('.two_page_mode, .play, .pause').hide(); + } + if ( !this.canSwitchToMode(this.constModeThumb) ) { + jToolbar.find('.thumbnail_mode').hide(); + } + + // Hide one page button if it is the only mode available + if ( ! (this.canSwitchToMode(this.constMode2up) || this.canSwitchToMode(this.constModeThumb)) ) { + jToolbar.find('.one_page_mode').hide(); } // Switch to requested mode -- binds other click handlers - this.switchToolbarMode(mode); + //this.switchToolbarMode(mode); } @@ -3251,12 +3675,12 @@ BookReader.prototype.bindToolbarNavHandlers = function(jToolbar) { var self = this; // closure - jToolbar.find('.book_left').bind('click', function(e) { + jToolbar.find('.book_left').click(function(e) { self.left(); return false; }); - jToolbar.find('.book_right').bind('click', function(e) { + jToolbar.find('.book_right').click(function(e) { self.right(); return false; }); @@ -3279,45 +3703,66 @@ BookReader.prototype.bindToolbarNavHandlers = function(jToolbar) { return false; }); - jToolbar.find('.print').bind('click', function(e) { + jToolbar.find('.print').click(function(e) { self.printPage(); return false; }); - jToolbar.find('.embed').bind('click', function(e) { + jToolbar.find('.embed').click(function(e) { self.showEmbedCode(); return false; }); - jToolbar.find('.play').bind('click', function(e) { + jToolbar.find('.bookmark').click(function(e) { + self.showBookmarkCode(); + return false; + }); + + jToolbar.find('.play').click(function(e) { self.autoToggle(); return false; }); - jToolbar.find('.pause').bind('click', function(e) { + jToolbar.find('.pause').click(function(e) { self.autoToggle(); return false; }); - jToolbar.find('.book_top').bind('click', function(e) { + jToolbar.find('.book_top').click(function(e) { self.first(); return false; }); - jToolbar.find('.book_bottom').bind('click', function(e) { + jToolbar.find('.book_bottom').click(function(e) { self.last(); return false; }); - jToolbar.find('.book_leftmost').bind('click', function(e) { + jToolbar.find('.book_leftmost').click(function(e) { self.leftmost(); return false; }); - jToolbar.find('.book_rightmost').bind('click', function(e) { + jToolbar.find('.book_rightmost').click(function(e) { self.rightmost(); return false; }); + + jToolbar.find('.read').click(function(e) { + self.ttsToggle(); + return false; + }); + + // $$$mang cleanup + $('#BRzoomer .zoom_in').bind('click', function() { + self.zoom(1); + return false; + }); + + $('#BRzoomer .zoom_out').bind('click', function() { + self.zoom(-1); + return false; + }); } // updateToolbarZoom(reduce) @@ -3346,6 +3791,78 @@ BookReader.prototype.updateToolbarZoom = function(reduce) { $('#BRzoom').text(value); } +// bindNavigationHandlers +//______________________________________________________________________________ +// Bind navigation handlers +BookReader.prototype.bindNavigationHandlers = function() { + $('#BookReader').die('mousemove.navigation').live('mousemove.navigation', + { 'br': this }, + this.navigationMousemoveHandler + ); +} + +// unbindNavigationHandlers +//______________________________________________________________________________ +// Unbind navigation handlers +BookReader.prototype.unbindNavigationHandlers = function() { + $('#BookReader').die('mousemove.navigation'); +} + +// navigationMousemoveHandler +//______________________________________________________________________________ +// Handle mousemove related to navigation. Bind at #BookReader level to allow autohide. +BookReader.prototype.navigationMousemoveHandler = function(event) { + // $$$ possibly not great to be calling this for every mousemove + + if (event.data['br'].uiAutoHide) { + var navkey = $(document).height() - 75; + if ((event.pageY < 76) || (event.pageY > navkey)) { + // inside or near navigation elements + event.data['br'].hideNavigation(); + } else { + event.data['br'].showNavigation(); + } + } +} + +// navigationIsVisible +//______________________________________________________________________________ +// Returns true if the navigation elements are currently visible +BookReader.prototype.navigationIsVisible = function() { + // $$$ doesn't account for transitioning states, nav must be fully visible to return true + var toolpos = $('#BRtoolbar').offset(); + var tooltop = toolpos.top; + if (tooltop == 0) { + return true; + } + return false; +} + +// hideNavigation +//______________________________________________________________________________ +// Hide navigation elements, if visible +BookReader.prototype.hideNavigation = function() { + // Check if navigation is showing + if (this.navigationIsVisible()) { + // $$$ don't hardcode height + $('#BRtoolbar').animate({top:-60}); + $('#BRnav').animate({bottom:-60}); + $('#BRzoomer').animate({right:-26}); + } +} + +// showNavigation +//______________________________________________________________________________ +// Show navigation elements +BookReader.prototype.showNavigation = function() { + // Check if navigation is hidden + if (!this.navigationIsVisible()) { + $('#BRtoolbar').animate({top:0}); + $('#BRnav').animate({bottom:0}); + $('#BRzoomer').animate({right:0}); + } +} + // firstDisplayableIndex //______________________________________________________________________________ // Returns the index of the first visible page, dependent on the mode. @@ -3679,11 +4196,11 @@ BookReader.prototype.startLocationPolling = function() { //________ // Returns true if we can switch to the requested mode BookReader.prototype.canSwitchToMode = function(mode) { - if (mode == this.constMode2up) { + if (mode == this.constMode2up || mode == this.constModeThumb) { // check there are enough pages to display // $$$ this is a workaround for the mis-feature that we can't display // short books in 2up mode - if (this.numLeafs < 6) { + if (this.numLeafs < 2) { return false; } } @@ -3760,6 +4277,22 @@ BookReader.prototype._getPageURI = function(index, reduce, rotate) { return this.getPageURI(index, reduce, rotate); } +/* + * Update based on received record from Open Library. + */ +BookReader.prototype.gotOpenLibraryRecord = function(self, olObject) { + // $$$ could refactor this so that 'this' is available + if (olObject) { + if (olObject['table_of_contents']) { + self.updateTOC(olObject['table_of_contents']); + } + } + + // $$$mang cleanup + $('#BRreturn a').attr('href', 'http://openlibrary.org' + olObject.key); + +} + // Library functions BookReader.util = { disableSelect: function(jObject) { @@ -3778,6 +4311,11 @@ BookReader.util = { return Math.min(Math.max(value, min), max); }, + // Given value and maximum, calculate a percentage suitable for CSS + cssPercentage: function(value, max) { + return parseInt(((value + 0.0) / max) * 100) + '%'; + }, + notInArray: function(value, array) { // inArray returns -1 or undefined if value not in array return ! (jQuery.inArray(value, array) >= 0); @@ -3813,7 +4351,7 @@ BookReader.prototype.ttsToggle = function () { if (oStatus.success) { this.ttsStart(); } else { - alert('Could not load soundManger2, possibly due to FlashBlock. Audio playback is disabled'); + alert('Could not load soundManager2, possibly due to FlashBlock. Audio playback is disabled'); } }, this); } @@ -3826,6 +4364,8 @@ BookReader.prototype.ttsToggle = function () { //______________________________________________________________________________ BookReader.prototype.ttsStart = function () { if (soundManager.debugMode) console.log('starting readAloud'); + if (this.constModeThumb == this.mode) this.switchMode(this.constMode1up); + this.ttsPlaying = true; this.ttsIndex = this.currentIndex(); this.ttsFormat = 'mp3'; @@ -3902,8 +4442,8 @@ BookReader.prototype.ttsShowPopup = function() { this.popup = document.createElement("div"); $(this.popup).css({ top: $('#BRtoolbar').height() + 'px', - left: $('.read_aloud').position().left + 'px', - width: $('#BRtoolbar').width()-$('.read_aloud').position().left + 'px', + left: $('#BookReader').width()-220 + 'px', + width: '220px', height: '20px', }).attr('className', 'BRttsPopUp').appendTo('#BookReader'); @@ -4067,7 +4607,6 @@ BookReader.prototype.ttsPrefetchAudio = function () { //for a short page, preload might nt have yet returned.. if (soundManager.debugMode) console.log('preloading chunk 0 from next page, index='+(this.ttsIndex+1)); if (null != this.ttsNextChunks) { - console.log(this.ttsNextChunks); if (0 != this.ttsNextChunks.length) { this.ttsLoadChunk(this.ttsIndex+1, 0, this.ttsNextChunks[0][0]); } else { @@ -4208,4 +4747,4 @@ BookReader.prototype.ttsStartPolling = function () { self.ttsPrefetchAudio(); self.ttsNextChunk(); },500); -} \ No newline at end of file +}