X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=BookReader%2FBookReader.js;h=1569a09934cce1e423f0874c704c14cbabf025f4;hb=b0f47345947c6d219901ce482cb9447b12607eae;hp=36032e71e4f8a397fe7f1e0a2174adf67d66ae94;hpb=deb3ca5365e0d7301a760efe6fee8ba4798272c5;p=bookreader.git diff --git a/BookReader/BookReader.js b/BookReader/BookReader.js index 36032e7..1569a09 100644 --- a/BookReader/BookReader.js +++ b/BookReader/BookReader.js @@ -93,12 +93,22 @@ function BookReader() { // Zoom levels // $$$ provide finer grained zooming + /* this.reductionFactors = [ {reduce: 0.5, autofit: null}, {reduce: 1, autofit: null}, {reduce: 2, autofit: null}, {reduce: 4, autofit: null}, {reduce: 8, autofit: null}, {reduce: 16, autofit: null} ]; + */ + /* The autofit code ensures that fit to width and fit to height will be available */ + this.reductionFactors = [ {reduce: 0.5, autofit: null}, + {reduce: 1, autofit: null}, + {reduce: 2, autofit: null}, + {reduce: 3, autofit: null}, + {reduce: 4, autofit: null}, + {reduce: 6, autofit: null} ]; + // Object to hold parameters related to 1up mode this.onePage = { @@ -109,7 +119,7 @@ function BookReader() { this.twoPage = { coverInternalPadding: 0, // Width of cover coverExternalPadding: 0, // Padding outside of cover - bookSpineDivWidth: 0, // Width of book spine $$$ consider sizing based on book length + bookSpineDivWidth: 64, // Width of book spine $$$ consider sizing based on book length autofit: 'auto' }; @@ -179,20 +189,11 @@ BookReader.prototype.init = function() { document.title = this.shortTitle(50); $("#BookReader").empty(); - - this.initToolbar(this.mode, this.ui); // Build inside of toolbar div - $("#BookReader").append("
"); + 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(); }); @@ -202,6 +203,7 @@ BookReader.prototype.init = function() { $(window).bind('resize', this, function(e) { //console.log('resize!'); + if (1 == e.data.mode) { //console.log('centering 1page view'); if (e.data.autofit) { @@ -255,9 +257,7 @@ BookReader.prototype.init = function() { this.firstIndex = startIndex; this.prepareThumbnailView(); this.jumpToIndex(startIndex); - } else { - //this.resizePageView(); - + } else { this.displayedIndices=[0]; this.firstIndex = startIndex; this.displayedIndices = [this.firstIndex]; @@ -271,13 +271,21 @@ BookReader.prototype.init = function() { // 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(); + if (this.ui == "embed") { + this.initEmbedNavbar(); + } else { + this.initNavbar(); + } this.bindNavigationHandlers(); + // Set strings in the UI + this.initUIStrings(); + // Start AJAX request for OL data if (this.getOpenLibraryRecord) { this.getOpenLibraryRecord(this.gotOpenLibraryRecord); } + } BookReader.prototype.setupKeyListeners = function() { @@ -370,7 +378,7 @@ BookReader.prototype.setClickHandler2UP = function( element, data, handler) { //console.log('setting handler'); //console.log(element.tagName); - $(element).unbind('tap').bind('tap', data, function(e) { + $(element).unbind('click').bind('click', data, function(e) { handler(e); }); } @@ -465,6 +473,7 @@ BookReader.prototype.drawLeafsOnePage = function() { var img = document.createElement("img"); img.src = this._getPageURI(index, this.reduce, 0); + $(img).addClass('BRnoselect'); $(img).css('width', width+'px'); $(img).css('height', height+'px'); $(div).append(img); @@ -656,10 +665,8 @@ BookReader.prototype.drawLeafsThumbnail = function( seekIndex ) { self.firstIndex = $(this).data('leaf'); self.switchMode(self.constMode1up); event.preventDefault(); - }); - - // $$$ we don't actually go to this URL (click is handled in handler above) - link.href = '#page/' + (this.getPageNum(leaf)) +'/mode/1up' ; + event.stopPropagation(); + }); $(div).append(link); $('#BRpageview').append(div); @@ -694,11 +701,9 @@ BookReader.prototype.drawLeafsThumbnail = function( seekIndex ) { $('#pagediv'+index).remove(); } } else { - /* - var mRow = this.displayedRows[i]; - var mLeafs = '[' + [leaf.num for each (leaf in leafMap[mRow].leafs)] + ']'; - console.log('NOT Removing row ' + mRow + ' ' + mLeafs); - */ + // var mRow = this.displayedRows[i]; + // var mLeafs = '[' + [leaf.num for each (leaf in leafMap[mRow].leafs)] + ']'; + // console.log('NOT Removing row ' + mRow + ' ' + mLeafs); } } @@ -1353,8 +1358,6 @@ BookReader.prototype.switchMode = function(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 } @@ -1473,7 +1476,7 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc $('#BRcontainer').append('
'); // Attaches to first child, so must come after we add the page view - $('#BRcontainer').dragscrollable(); + //$('#BRcontainer').dragscrollable(); this.bindGestures($('#BRcontainer')); // $$$ calculate first then set @@ -1498,7 +1501,7 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc $(this.twoPage.coverDiv).attr('id', 'BRbookcover').css({ width: this.twoPage.bookCoverDivWidth + 'px', height: this.twoPage.bookCoverDivHeight+'px', - visibility: 'visible', + visibility: 'visible' }).appendTo('#BRtwopageview'); this.leafEdgeR = document.createElement('div'); @@ -1520,10 +1523,10 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc }).appendTo('#BRtwopageview'); div = document.createElement('div'); - $(div).attr('id', 'BRbookspine').css({ + $(div).attr('id', 'BRgutter').css({ width: this.twoPage.bookSpineDivWidth+'px', height: this.twoPage.bookSpineDivHeight+'px', - left: this.twoPage.bookSpineDivLeft+'px', + left: (this.twoPage.gutter - this.twoPage.bookSpineDivWidth*0.5)+'px', top: this.twoPage.bookSpineDivTop+'px' }).appendTo('#BRtwopageview'); @@ -1571,7 +1574,7 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc //this.indicesToDisplay=[firstLeaf, firstLeaf+1]; //console.log('indicesToDisplay: ' + this.indicesToDisplay[0] + ' ' + this.indicesToDisplay[1]); - + this.drawLeafsTwoPage(); this.updateToolbarZoom(this.reduce); @@ -1666,7 +1669,7 @@ BookReader.prototype.calculateSpreadSize = function() { // set based on reduction factor spreadSize = this.getSpreadSizeFromReduce(firstIndex, secondIndex, this.reduce); } - + // Both pages together this.twoPage.height = spreadSize.height; this.twoPage.width = spreadSize.width; @@ -1738,7 +1741,7 @@ BookReader.prototype.getIdealSpreadSize = function(firstIndex, secondIndex) { height: this._getPageHeight(secondIndex), width: this._getPageWidth(secondIndex) } - + var firstIndexRatio = first.height / first.width; var secondIndexRatio = second.height / second.width; //console.log('firstIndexRatio = ' + firstIndexRatio + ' secondIndexRatio = ' + secondIndexRatio); @@ -1746,10 +1749,8 @@ BookReader.prototype.getIdealSpreadSize = function(firstIndex, secondIndex) { var ratio; if (Math.abs(firstIndexRatio - canon5Dratio) < Math.abs(secondIndexRatio - canon5Dratio)) { ratio = firstIndexRatio; - //console.log('using firstIndexRatio ' + ratio); } else { ratio = secondIndexRatio; - //console.log('using secondIndexRatio ' + ratio); } var totalLeafEdgeWidth = parseInt(this.numLeafs * 0.1); @@ -1807,6 +1808,20 @@ BookReader.prototype.twoPageGetAutofitReduce = function() { return spreadSize.reduce; } +// twoPageIsZoomedIn +//______________________________________________________________________________ +// Returns true if the pages extend past the edge of the view +BookReader.prototype.twoPageIsZoomedIn = function() { + var autofitReduce = this.twoPageGetAutofitReduce(); + var isZoomedIn = false; + if (this.twoPage.autofit != 'auto') { + if (this.reduce < this.twoPageGetAutofitReduce()) { + isZoomedIn = true; + } + } + return isZoomedIn; +} + BookReader.prototype.onePageGetAutofitWidth = function() { var widthPadding = 20; return (this.getMedianPageSize().width + 0.0) / ($('#BRcontainer').attr('clientWidth') - widthPadding * 2); @@ -2176,6 +2191,8 @@ BookReader.prototype.flipLeftToRight = function(newIndexL, newIndexR) { //console.log(' and now leafEdgeTmp to left: gutter+newWidthR ' + (gutter + newWidthR)); $(self.leafEdgeTmp).animate({left: gutter+newWidthR+'px'}, self.flipSpeed, 'easeOutSine'); + + $('#BRgutter').css({left: (gutter - self.twoPage.bookSpineDivWidth*0.5)+'px'}); //console.log(' animating newIndexR ' + newIndexR + ' to ' + newWidthR + ' from ' + $(self.prefetchedImgs[newIndexR]).width()); $(self.prefetchedImgs[newIndexR]).animate({width: newWidthR+'px'}, self.flipSpeed, 'easeOutSine', function() { @@ -2197,7 +2214,7 @@ BookReader.prototype.flipLeftToRight = function(newIndexL, newIndexR) { $(self.twoPage.coverDiv).css({ width: self.twoPageCoverWidth(newWidthL+newWidthR)+'px', left: gutter-newWidthL-newLeafEdgeWidthL-self.twoPage.coverInternalPadding+'px' - }); + }); $(self.leafEdgeTmp).remove(); self.leafEdgeTmp = null; @@ -2276,7 +2293,6 @@ BookReader.prototype.willChangeToIndex = function(index) { // Update navbar position icon - leads page change animation this.updateNavIndex(index); - } // flipRightToLeft(nextL, nextR, gutter) @@ -2325,6 +2341,7 @@ BookReader.prototype.flipRightToLeft = function(newIndexL, newIndexR) { $(this.leafEdgeTmp).animate({left: gutter}, speed, 'easeInSine'); $(this.prefetchedImgs[this.twoPage.currentIndexR]).animate({width: '0px'}, speed, 'easeInSine', function() { + $('#BRgutter').css({left: (gutter - self.twoPage.bookSpineDivWidth*0.5)+'px'}); $(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); @@ -2338,8 +2355,8 @@ BookReader.prototype.flipRightToLeft = function(newIndexL, newIndexR) { $(self.twoPage.coverDiv).css({ width: self.twoPageCoverWidth(newWidthL+newWidthR)+'px', left: gutter - newWidthL - newLeafEdgeWidthL - self.twoPage.coverInternalPadding + 'px' - }); - + }); + $(self.leafEdgeTmp).remove(); self.leafEdgeTmp = null; @@ -2377,8 +2394,15 @@ BookReader.prototype.setMouseHandlers2UP = function() { this.setClickHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexL], { self: this }, function(e) { - e.data.self.ttsStop(); - e.data.self.left(); + if (e.button == 2) { + // right click + return true; + } + + if (! e.data.self.twoPageIsZoomedIn()) { + e.data.self.ttsStop(); + e.data.self.left(); + } e.preventDefault(); } ); @@ -2386,8 +2410,15 @@ BookReader.prototype.setMouseHandlers2UP = function() { this.setClickHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexR], { self: this }, function(e) { - e.data.self.ttsStop(); - e.data.self.right(); + if (e.button == 2) { + // right click + return true; + } + + if (! e.data.self.twoPageIsZoomedIn()) { + e.data.self.ttsStop(); + e.data.self.right(); + } e.preventDefault(); } ); @@ -2411,7 +2442,7 @@ BookReader.prototype.prefetchImg = function(index) { if (loadImage) { //console.log('prefetching ' + index); var img = document.createElement("img"); - img.className = 'BRpageimage'; + $(img).addClass('BRpageimage').addClass('BRnoselect'); if (index < 0 || index > (this.numLeafs - 1) ) { // Facing page at beginning or end, or beyond $(img).css({ @@ -2452,14 +2483,13 @@ BookReader.prototype.prepareFlipLeftToRight = function(prevL, prevR) { //console.log(' prevL.left: ' + (gutter - scaledW) + 'px'); //console.log(' changing prevL ' + prevL + ' to left: ' + (gutter-scaledW) + ' width: ' + scaledW); - leftCSS = { + var leftCSS = { position: 'absolute', left: gutter-scaledW+'px', right: '', // clear right property top: top+'px', height: this.twoPage.height, width: scaledW+'px', - borderRight: '1px solid black', // XXXmang check zIndex: 1 } @@ -2469,13 +2499,12 @@ BookReader.prototype.prepareFlipLeftToRight = function(prevL, prevR) { //console.log(' changing prevR ' + prevR + ' to left: ' + gutter + ' width: 0'); - rightCSS = { + var rightCSS = { position: 'absolute', left: gutter+'px', right: '', top: top+'px', height: this.twoPage.height, - borderLeft: '1px solid black', // XXXmang check width: '0', zIndex: 2 } @@ -2636,8 +2665,11 @@ BookReader.prototype.getPageWidth2UP = function(index) { //______________________________________________________________________________ BookReader.prototype.search = function(term) { //console.log('search called with term=' + term); + + $('#textSrch').blur(); //cause mobile safari to hide the keyboard + var url = 'http://'+this.server.replace(/:.+/, ''); //remove the port and userdir - url += '/~edward/inside_jsonp.php?item_id='+this.bookId; + url += '/fulltext/inside.php?item_id='+this.bookId; url += '&doc='+this.subPrefix; //TODO: test with subitem url += '&path='+this.bookPath.replace(new RegExp('/'+this.subPrefix+'$'), ''); //remove subPrefix from end of path url += '&q='+escape(term); @@ -2648,26 +2680,30 @@ BookReader.prototype.search = function(term) { this.removeSearchResults(); this.showProgressPopup(' Search results will appear below...'); - this.ttsAjax = $.ajax({url:url, dataType:'jsonp', jsonpCallback:'BRSearchCallback'}); + $.ajax({url:url, dataType:'jsonp', jsonpCallback:'br.BRSearchCallback'}); } // BRSearchCallback() //______________________________________________________________________________ -// Unfortunately, we can't pass 'br.searchCallback' to our search service, -// because it can't handle the '.' -function BRSearchCallback(results) { +BookReader.prototype.BRSearchCallback = function(results) { //console.log('got ' + results.matches.length + ' results'); br.removeSearchResults(); br.searchResults = results; //console.log(br.searchResults); if (0 == results.matches.length) { - $(br.popup).text('No matches were found.'); + var errStr = 'No matches were found.'; + var timeout = 1000; + if (false === results.indexed) { + errStr = "

This book isn't in the search engine yet.

Please drop us a line so we can fix it. Thanks!

"; + timeout = 5000; + } + $(br.popup).html(errStr); setTimeout(function(){ $(br.popup).fadeOut('slow', function() { br.removeProgressPopup(); }) - },1000); + },timeout); return; } @@ -2862,9 +2898,10 @@ BookReader.prototype.updateSearchHilites2UP = function() { var i, j; for (i=0; i= 0) { if (null == box.div) { //create a div for the search highlight, and stash it in the box object @@ -2962,56 +2999,9 @@ BookReader.prototype.getPrintURI = function() { return '/bookreader/print.php?' + options; } -/* iframe implementation -BookReader.prototype.getPrintFrameContent = function(index) { - // We fit the image based on an assumed A4 aspect ratio. A4 is a bit taller aspect than - // 8.5x11 so we should end up not overflowing on either paper size. - var paperAspect = 8.5 / 11; - var imageAspect = this._getPageWidth(index) / this._getPageHeight(index); - - var rotate = 0; - - // Rotate if possible and appropriate, to get larger image size on printed page - if (this.canRotatePage(index)) { - if (imageAspect > 1 && imageAspect > paperAspect) { - // more wide than square, and more wide than paper - rotate = 90; - imageAspect = 1/imageAspect; - } - } - - var fitAttrs; - if (imageAspect > paperAspect) { - // wider than paper, fit width - fitAttrs = 'width="95%"'; - } else { - // taller than paper, fit height - fitAttrs = 'height="95%"'; - } - - var imageURL = this._getPageURI(index, 1, rotate); - var iframeStr = '' + this.bookTitle + ''; - iframeStr += '
'; - iframeStr += ''; - iframeStr += '
'; - iframeStr += ''; - - return iframeStr; -} - -BookReader.prototype.updatePrintFrame = function(delta) { - var newIndex = this.indexToPrint + delta; - newIndex = BookReader.util.clamp(newIndex, 0, this.numLeafs - 1); - if (newIndex == this.indexToPrint) { - return; - } - this.indexToPrint = newIndex; - var doc = BookReader.util.getIFrameDocument($('#printFrame')[0]); - $('body', doc).html(this.getPrintFrameContent(this.indexToPrint)); -} -*/ - // showEmbedCode() +// +// Note: Has been replaced by the share dialog //______________________________________________________________________________ BookReader.prototype.showEmbedCode = function() { if (null != this.embedPopup) { // check if already showing @@ -3092,6 +3082,8 @@ BookReader.prototype.showBookmarkCode = function() { //______________________________________________________________________________ BookReader.prototype.autoToggle = function() { + this.ttsStop(); + var bComingFrom1up = false; if (2 != this.mode) { bComingFrom1up = true; @@ -3256,14 +3248,14 @@ BookReader.prototype.jumpIndexForRightEdgePageX = function(pageX) { 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( + $('#BookReader').append( '
' + '
' // Page turn buttons + '' + '' + '' - + '' + // $$$ not yet implemented + //+ '' + '' + '' + '' @@ -3281,61 +3273,6 @@ BookReader.prototype.initNavbar = function() { + '
' ); -/* -
-
- 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, @@ -3343,12 +3280,13 @@ BookReader.prototype.initNavbar = function() { max: this.numLeafs - 1, value: this.currentIndex() }) - .bind('slide', function(event, ui){ + .bind('slide', function(event, ui) { self.updateNavPageNum(ui.value); $("#pagenum").show(); return true; }) .bind('slidechange', function(event, ui) { + self.updateNavPageNum(ui.value); // hiding now but will show later $("#pagenum").hide(); // recursion prevention for jumpToIndex @@ -3373,24 +3311,36 @@ BookReader.prototype.initNavbar = function() { .append('
'); //.wrap('
').parent(); // XXXmang is this used for hiding the tooltip? - // $$$mang, why are these set both here and in bindNavigationHandlers? - $('.BRicon.book_left').bind('click', function() { - self.ttsStop(); - self.left(); - }); - $('.BRicon.book_right').bind('click', function() { - self.ttsStop(); - self.right(); - }); - this.updateNavPageNum(this.currentIndex()); $("#BRzoombtn").draggable({axis:'y',containment:'parent'}); - //XXXmang remove once done testing - //this.addSearchResult("There is a place where the sidewalk ends And before the street begins, And there the grass grows soft and white, And there the sun burns crimson bright,And there the moon-bird rests from his flight To cool in the peppermint wind.", "20", 31); - //this.addSearchResult("There is a place where the sidewalk BEGINS And there the moon-bird rests from his flight To cool in the peppermint wind.", "60", 71); + /* Initial hiding + $('#BRtoolbar').delay(3000).animate({top:-40}); + $('#BRnav').delay(3000).animate({bottom:-53}); + changeArrow(); + $('.BRnavCntl').delay(3000).animate({height:'43px'}).delay(1000).animate({opacity:.25},1000); + */ +} + +// initEmbedNavbar +//______________________________________________________________________________ +// Initialize the navigation bar when embedded +BookReader.prototype.initEmbedNavbar = function() { + var thisLink = (window.location + '').replace('?ui=embed',''); // IA-specific + $('#BookReader').append( + '
' + + "" + + '' + + '' + + '' + + "" + + "" + + "" + + '
' + ); + $('#BRembedreturn a').text(this.bookTitle); } BookReader.prototype.updateNavPageNum = function(index) { @@ -3466,6 +3416,9 @@ BookReader.prototype.addSearchResult = function(queryString, pageIndex) { shadow: false }) .hover( function() { + // remove from other markers then turn on just for this + // XXX should be done when nav slider moves + $('.search,.chapter').removeClass('front'); $(this).addClass('front'); }, function() { $(this).removeClass('front'); @@ -3530,6 +3483,8 @@ BookReader.prototype.addChapter = function(chapterTitle, pageNumber, pageIndex) shadow: false }) .hover( function() { + // remove hover effect from other markers then turn on just for this + $('.search,.chapter').removeClass('front'); $(this).addClass('front'); }, function() { $(this).removeClass('front'); @@ -3597,26 +3552,30 @@ BookReader.prototype.addChapterFromEntry = function(tocEntryObject) { } BookReader.prototype.initToolbar = function(mode, ui) { + if (ui == "embed") { + return; // No toolbar at top in embed mode + } // $$$mang should be contained within the BookReader div instead of body - var readIcon = '' + var readIcon = ''; if (!navigator.userAgent.match(/mobile/i)) { readIcon = ""; } - - $("body").append( + + $("#BookReader").append( "
" + "" - /* XXXmang integrate search */ - + "
" - // XXXmang icons incorrect or handlers wrong + + "
" + + "" + + "" + "" + "" + readIcon - + "" + //+ "" + "
" + "" - + "Back to" + this.bookTitle + "" + + "Back to" + this.bookTitle + "" // XXX escape + + "
" + "
" /* + "
" @@ -3631,6 +3590,9 @@ BookReader.prototype.initToolbar = function(mode, ui) { + "
" */ ); + + $('#BRtoolbar .BRnavCntl').addClass('BRup'); + $('#BRtoolbar .pause').hide(); this.updateToolbarZoom(this.reduce); // Pretty format @@ -3643,44 +3605,7 @@ BookReader.prototype.initToolbar = function(mode, ui) { // We build in mode 2 jToolbar.append(); - - // Navigation handlers will be bound after all UI is in place -- makes moving icons between - // the toolbar and nav bar easier - - // 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', - '.onepg': 'One-page view', - '.twopg': 'Two-page view', - '.thumb': 'Thumbnail view', - '.print': 'Print this page', - '.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', - '.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]); - } - + // 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) ) { @@ -3694,12 +3619,58 @@ BookReader.prototype.initToolbar = function(mode, ui) { if ( ! (this.canSwitchToMode(this.constMode2up) || this.canSwitchToMode(this.constModeThumb)) ) { jToolbar.find('.one_page_mode').hide(); } + + // $$$ Don't hardcode ids + var self = this; + jToolbar.find('.share').colorbox({inline: true, opacity: "0.5", href: "#BRshare", onLoad: function() { self.autoStop(); self.ttsStop(); } }); + jToolbar.find('.info').colorbox({inline: true, opacity: "0.5", href: "#BRinfo", onLoad: function() { self.autoStop(); self.ttsStop(); } }); + $('
').append(this.blankShareDiv()).append(this.blankInfoDiv()).appendTo($('body')); + + $('#BRinfo .BRfloatTitle a').attr( {'href': this.bookUrl} ).text(this.bookTitle).addClass('title'); + + // These functions can be overridden + this.buildInfoDiv($('#BRinfo')); + this.buildShareDiv($('#BRshare')); + // Switch to requested mode -- binds other click handlers //this.switchToolbarMode(mode); } +BookReader.prototype.blankInfoDiv = function() { + return $([ + '
', + '
About this book', + 'Close', + '
', + '
', + '
', + '
', + '
', + '
', + '

', + '
', + '
', + '
', + '', + '
'].join('\n') + ); +} + +BookReader.prototype.blankShareDiv = function() { + return $([ + '
', + '
', + 'Share', + 'Close', + '
', + '
'].join('\n') + ); +} + // switchToolbarMode //______________________________________________________________________________ @@ -3778,11 +3749,13 @@ BookReader.prototype.bindNavigationHandlers = function() { }); jIcons.filter('.book_left').click(function(e) { + self.ttsStop(); self.left(); return false; }); jIcons.filter('.book_right').click(function(e) { + self.ttsStop(); self.right(); return false; }); @@ -3809,7 +3782,8 @@ BookReader.prototype.bindNavigationHandlers = function() { self.printPage(); return false; }); - + + // Note: Functionality has been replaced by .share jIcons.filter('.embed').click(function(e) { self.showEmbedCode(); return false; @@ -3867,15 +3841,77 @@ BookReader.prototype.bindNavigationHandlers = function() { return false; }); - // XXX fix integration - $('#booksearch').bind('submit', function() { - self.search($('#textSrch').val()); + jIcons.filter('.full').bind('click', function() { + if (self.ui == 'embed') { + // $$$ bit of a hack, IA-specific + var url = (window.location + '').replace("?ui=embed",""); + window.open(url); + } + + // Not implemented + }); + + $('.BRnavCntl').click( + function(){ + if ($('#BRnavCntlBtm').hasClass('BRdn')) { + $('#BRtoolbar').animate({top:-40}); + $('#BRnav').animate({bottom:-55}); + $('#BRnavCntlBtm').addClass('BRup').removeClass('BRdn'); + $('#BRnavCntlTop').addClass('BRdn').removeClass('BRup'); + $('#BRnavCntlBtm.BRnavCntl').animate({height:'45px'}); + $('.BRnavCntl').delay(1000).animate({opacity:.25},1000); + } else { + $('#BRtoolbar').animate({top:0}); + $('#BRnav').animate({bottom:0}); + $('#BRnavCntlBtm').addClass('BRdn').removeClass('BRup'); + $('#BRnavCntlTop').addClass('BRup').removeClass('BRdn'); + $('#BRnavCntlBtm.BRnavCntl').animate({height:'30px'}); + $('.BRvavCntl').animate({opacity:1}) + }; + } + ); + $('#BRnavCntlBtm').mouseover(function(){ + if ($(this).hasClass('BRup')) { + $('.BRnavCntl').animate({opacity:1},250); + }; + }); + $('#BRnavCntlBtm').mouseleave(function(){ + if ($(this).hasClass('BRup')) { + $('.BRnavCntl').animate({opacity:.25},250); + }; + }); + $('#BRnavCntlTop').mouseover(function(){ + if ($(this).hasClass('BRdn')) { + $('.BRnavCntl').animate({opacity:1},250); + }; + }); + $('#BRnavCntlTop').mouseleave(function(){ + if ($(this).hasClass('BRdn')) { + $('.BRnavCntl').animate({opacity:.25},250); + }; }); + + this.initSwipeData(); $('#BookReader').die('mousemove.navigation').live('mousemove.navigation', { 'br': this }, this.navigationMousemoveHandler ); + + $('.BRpageimage').die('mousedown.swipe').live('mousedown.swipe', + { 'br': this }, + this.swipeMousedownHandler + ) + .die('mousemove.swipe').live('mousemove.swipe', + { 'br': this }, + this.swipeMousemoveHandler + ) + .die('mouseup.swipe').live('mouseup.swipe', + { 'br': this }, + this.swipeMouseupHandler + ); + + this.bindMozTouchHandlers(); } // unbindNavigationHandlers @@ -3902,6 +3938,125 @@ BookReader.prototype.navigationMousemoveHandler = function(event) { } } +BookReader.prototype.initSwipeData = function(clientX, clientY) { + /* + * Based on the really quite awesome "Today's Guardian" at http://guardian.gyford.com/ + */ + this._swipe = { + mightBeSwiping: false, + didSwipe: false, + mightBeDraggin: false, + didDrag: false, + startTime: (new Date).getTime(), + startX: clientX, + startY: clientY, + lastX: clientX, + lastY: clientY, + deltaX: 0, + deltaY: 0, + deltaT: 0 + } +} + +BookReader.prototype.swipeMousedownHandler = function(event) { + //console.log('swipe mousedown'); + //console.log(event); + + var self = event.data['br']; + self.initSwipeData(event.clientX, event.clientY); + self._swipe.mightBeSwiping = true; + self._swipe.mightBeDragging = true; + + // We should be the last bubble point for the page images + // Disable image drag and select, but keep right-click + if ($(event.originalTarget).hasClass('BRpageimage') && event.button != 2) { + event.preventDefault(); + } +} + +BookReader.prototype.swipeMousemoveHandler = function(event) { + //console.log('swipe move ' + event.clientX + ',' + event.clientY); + + var _swipe = event.data['br']._swipe; + if (! _swipe.mightBeSwiping) { + return; + } + + // Update swipe data + _swipe.deltaX = event.clientX - _swipe.startX; + _swipe.deltaY = event.clientY - _swipe.startY; + _swipe.deltaT = (new Date).getTime() - _swipe.startTime; + + var absX = Math.abs(_swipe.deltaX); + var absY = Math.abs(_swipe.deltaY); + + // Minimum distance in the amount of tim to trigger the swipe + var minSwipeLength = Math.min($('#BookReader').width() / 5, 80); + var maxSwipeTime = 400; + + // Check for horizontal swipe + if (absX > absY && (absX > minSwipeLength) && _swipe.deltaT < maxSwipeTime) { + //console.log('swipe! ' + _swipe.deltaX + ',' + _swipe.deltaY + ' ' + _swipe.deltaT + 'ms'); + + _swipe.mightBeSwiping = false; // only trigger once + _swipe.didSwipe = true; + if (event.data['br'].mode == event.data['br'].constMode2up) { + if (_swipe.deltaX < 0) { + event.data['br'].right(); + } else { + event.data['br'].left(); + } + } + } + + if ( _swipe.deltaT > maxSwipeTime && !_swipe.didSwipe) { + if (_swipe.mightBeDragging) { + // Dragging + _swipe.didDrag = true; + $('#BRcontainer') + .scrollTop($('#BRcontainer').scrollTop() - event.clientY + _swipe.lastY) + .scrollLeft($('#BRcontainer').scrollLeft() - event.clientX + _swipe.lastX); + } + } + _swipe.lastX = event.clientX; + _swipe.lastY = event.clientY; +} +BookReader.prototype.swipeMouseupHandler = function(event) { + var _swipe = event.data['br']._swipe; + //console.log('swipe mouseup - did swipe ' + _swipe.didSwipe); + _swipe.mightBeSwiping = false; + _swipe.mightBeDragging = false; + if (_swipe.didSwipe || _swipe.didDrag) { + // Swallow event if completed swipe gesture + event.preventDefault(); + event.stopPropagation(); + } +} + +BookReader.prototype.bindMozTouchHandlers = function() { + var self = this; + + // Currently only want touch handlers in 2up + $('#BookReader').bind('MozTouchDown', function(event) { + //console.log('MozTouchDown ' + event.originalEvent.streamId + ' ' + event.target + ' ' + event.clientX + ',' + event.clientY); + if (this.mode == this.constMode2up) { + event.preventDefault(); + } + }) + .bind('MozTouchMove', function(event) { + //console.log('MozTouchMove - ' + event.originalEvent.streamId + ' ' + event.target + ' ' + event.clientX + ',' + event.clientY) + if (this.mode == this.constMode2up) { + event.preventDefault(); + } + }) + .bind('MozTouchUp', function(event) { + //console.log('MozTouchUp - ' + event.originalEvent.streamId + ' ' + event.target + ' ' + event.clientX + ',' + event.clientY); + if (this.mode = this.constMode2up) { + event.preventDefault(); + } + }); +} + // navigationIsVisible //______________________________________________________________________________ // Returns true if the navigation elements are currently visible @@ -3940,6 +4095,16 @@ BookReader.prototype.showNavigation = function() { } } +// changeArrow +//______________________________________________________________________________ +// Change the nav bar arrow +function changeArrow(){ + setTimeout(function(){ + $('#BRnavCntlBtm').removeClass('BRdn').addClass('BRup'); + },3000); +}; + + // firstDisplayableIndex //______________________________________________________________________________ // Returns the index of the first visible page, dependent on the mode. @@ -4145,8 +4310,10 @@ BookReader.prototype.fragmentFromParams = function(params) { if ('undefined' != typeof(params.page)) { fragments.push('page', params.page); } else { - // Don't have page numbering -- use index instead - fragments.push('page', 'n' + params.index); + if ('undefined' != typeof(params.index)) { + // Don't have page numbering but we do have the index + fragments.push('page', 'n' + params.index); + } } // $$$ highlight @@ -4374,15 +4541,23 @@ BookReader.prototype._getPageURI = function(index, reduce, rotate) { BookReader.prototype.gotOpenLibraryRecord = function(self, olObject) { // $$$ could refactor this so that 'this' is available if (olObject) { + // console.log(olObject); if (olObject['table_of_contents']) { // XXX check here that TOC is valid self.updateTOC(olObject['table_of_contents']); } - } - - // $$$mang cleanup - $('#BRreturn a').attr('href', 'http://openlibrary.org' + olObject.key); + // $$$mang cleanup + self.bookUrl = 'http://openlibrary.org' + olObject.key; + self.bookTitle = olObject['title']; + $('#BRreturn a').attr( {'href': self.bookUrl, 'title': "Go to this book's page on Open Library" } ); + $('#BRreturn a').text(self.bookTitle); + $('#BookReader .logo').attr('title', 'Go to Open Library'); // i18n + + $('#BRinfo').remove(); + $('#BRshare').after(self.blankInfoDiv()); + self.buildInfoDiv($('#BRinfo')); + } } // Library functions @@ -4419,6 +4594,15 @@ BookReader.util = { return (outer.document || outer); }, + escapeHTML: function (str) { + return( + str.replace(/&/g,'&'). + replace(/>/g,'>'). + replace(/Copy and paste one of these options to share this book elsewhere.

', + '
', + '
', + '', + '', + '
', + '
', + '', + '', + '
', + '
', + '', + '
', + '', + '', + '', + '
', + '', + '

NOTE: We\'ve tested EMBED on blogspot.com blogs as well as self-hosted Wordpress blogs. This feature will NOT work on wordpress.com blogs.

', + '
', + '
', + '', + '
', + '
'].join('\n')); + + jForm.appendTo(jShareDiv); + + jForm.find('input').bind('change', function() { + var form = $(this).parents('form:first'); + var params = {}; + params.mode = $(form.find('input[name=pages]:checked')).val(); + if (form.find('input[name=thispage]').attr('checked')) { + params.page = self.getPageNum(self.currentIndex()); + } + + // console.log(params); + form.find('.BRframeEmbed').val(self.getEmbedCode()); + }) + jForm.find('input[name=thispage]').trigger('change'); + jForm.find('input, textarea').bind('focus', function() { + this.select(); }); + + jForm.appendTo(jShareDiv); + jForm = ''; // closure + +} +// Should be overridden +BookReader.prototype.buildInfoDiv = function(jInfoDiv) +{ + jInfoDiv.find('.BRfloatTitle a').attr({'href': this.bookUrl, 'alt': this.bookTitle}).text(this.bookTitle); +} + +// Can be overriden +BookReader.prototype.initUIStrings = function() +{ + // Navigation handlers will be bound after all UI is in place -- makes moving icons between + // the toolbar and nav bar easier + + // Setup tooltips -- later we could load these from a file for i18n + var titles = { '.logo': 'Go to Archive.org', // $$$ update after getting OL record + '.zoom_in': 'Zoom in', + '.zoom_out': 'Zoom out', + '.onepg': 'One-page view', + '.twopg': 'Two-page view', + '.thumb': 'Thumbnail view', + '.print': 'Print this page', + '.embed': 'Embed BookReader', + '.link': 'Link to this book (and page)', + '.bookmark': 'Bookmark this page', + '.read': 'Read this book aloud', + '.share': 'Share this book', + '.info': 'About this book', + '.full': 'Show fullscreen', + '.book_left': 'Flip left', + '.book_right': 'Flip right', + '.book_up': 'Page up', + '.book_down': 'Page down', + '.play': 'Play', + '.pause': 'Pause', + '.BRdn': 'Show/hide nav bar', // Would have to keep updating on state change to have just "Hide nav bar" + '.BRup': 'Show/hide nav bar', + '.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) { + if (titles.hasOwnProperty(icon)) { + $('#BookReader').find(icon).attr('title', titles[icon]); + } + } +}