this.printPopup = null;
this.searchTerm = '';
- this.searchResults = {};
+ this.searchResults = null;
this.firstIndex = null;
// 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 = {
$("#BookReader").empty();
this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
-
- $("#BookReader").append("<div id='BRcontainer'></div>");
+ $("#BookReader").append("<div id='BRcontainer' dir='ltr'></div>");
$("#BRcontainer").append("<div id='BRpageview'></div>");
- // 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();
});
$(window).bind('resize', this, function(e) {
//console.log('resize!');
+
if (1 == e.data.mode) {
//console.log('centering 1page view');
if (e.data.autofit) {
this.firstIndex = startIndex;
this.prepareThumbnailView();
this.jumpToIndex(startIndex);
- } else {
- //this.resizePageView();
-
+ } else {
this.displayedIndices=[0];
this.firstIndex = startIndex;
this.displayedIndices = [this.firstIndex];
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() {
//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);
});
}
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);
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);
$('#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);
}
}
this.willChangeToIndex(index);
+ this.ttsStop();
+
if (this.constMode2up == this.mode) {
this.autoStop();
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 {
// 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
}
$('#BRcontainer').append('<div id="BRtwopageview"></div>');
// Attaches to first child, so must come after we add the page view
- $('#BRcontainer').dragscrollable();
+ //$('#BRcontainer').dragscrollable();
this.bindGestures($('#BRcontainer'));
// $$$ calculate first then set
$(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');
//this.indicesToDisplay=[firstLeaf, firstLeaf+1];
//console.log('indicesToDisplay: ' + this.indicesToDisplay[0] + ' ' + this.indicesToDisplay[1]);
-
+
this.drawLeafsTwoPage();
this.updateToolbarZoom(this.reduce);
// 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;
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);
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);
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);
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();
}
);
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();
}
);
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({
- 'background-color': 'transparent'
+ 'background-color': '#efefef'
});
}
img.src = pageURI;
// search()
//______________________________________________________________________________
BookReader.prototype.search = function(term) {
- term = term.replace(/\//g, ' '); // strip slashes
- this.searchTerm = term;
- $('#BookReaderSearchScript').remove();
- var script = document.createElement("script");
- script.setAttribute('id', 'BookReaderSearchScript');
- script.setAttribute("type", "text/javascript");
- script.setAttribute("src", 'http://'+this.server+'/BookReader/flipbook_search_br.php?url='+escape(this.bookPath + '_djvu.xml')+'&term='+term+'&format=XML&callback=br.BRSearchCallback');
- document.getElementsByTagName('head')[0].appendChild(script);
- $('#BookReaderSearchBox').val(term);
- $('#BookReaderSearchResults').html('Searching...');
-}
-
-// searchNew()
-//______________________________________________________________________________
-BookReader.prototype.searchNew = function(term) {
- //console.log('searchNew called with term=' + 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);
- //console.log('search url='+url);
- this.ttsAjax = $.ajax({url:url, dataType:'jsonp', jsonpCallback:'BRSearchCallbackNew'});
+ //console.log('search url='+url);
+
+ term = term.replace(/\//g, ' '); // strip slashes, since this goes in the url
+ this.searchTerm = term;
+
+ this.removeSearchResults();
+ this.showProgressPopup('<img id="searchmarker" src="'+this.imagesBaseURL + 'marker_srch-on.png'+'"> Search results will appear below...');
+ this.ttsAjax = $.ajax({url:url, dataType:'jsonp', jsonpCallback:'br.BRSearchCallback'});
}
-// Unfortunately, we can't pass 'br.searchCallback' to our search service,
-// because it can't handle the '.'
-function BRSearchCallbackNew(results) {
+// BRSearchCallback()
+//______________________________________________________________________________
+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.');
+ setTimeout(function(){
+ $(br.popup).fadeOut('slow', function() {
+ br.removeProgressPopup();
+ })
+ },1000);
+ return;
+ }
+
var i;
for (i=0; i<results.matches.length; i++) {
br.addSearchResult(results.matches[i].text, br.leafNumToIndex(results.matches[i].par[0].page));
}
+ br.updateSearchHilites();
+ br.removeProgressPopup();
}
-// BRSearchCallback()
-//______________________________________________________________________________
-BookReader.prototype.BRSearchCallback = function(txt) {
- //alert(txt);
- if (jQuery.browser.msie) {
- var dom=new ActiveXObject("Microsoft.XMLDOM");
- dom.async="false";
- dom.loadXML(txt);
- } else {
- var parser = new DOMParser();
- var dom = parser.parseFromString(txt, "text/xml");
- }
-
- $('#BookReaderSearchResults').empty();
- $('#BookReaderSearchResults').append('<ul>');
-
- for (var key in this.searchResults) {
- if (null != this.searchResults[key].div) {
- $(this.searchResults[key].div).remove();
- }
- delete this.searchResults[key];
- }
-
- var pages = dom.getElementsByTagName('PAGE');
-
- if (0 == pages.length) {
- // $$$ it would be nice to echo the (sanitized) search result here
- $('#BookReaderSearchResults').append('<li>No search results found</li>');
- } else {
- for (var i = 0; i < pages.length; i++){
- //console.log(pages[i].getAttribute('file').substr(1) +'-'+ parseInt(pages[i].getAttribute('file').substr(1), 10));
-
-
- var re = new RegExp (/_(\d{4})\.djvu/);
- var reMatch = re.exec(pages[i].getAttribute('file'));
- var index = parseInt(reMatch[1], 10);
- //var index = parseInt(pages[i].getAttribute('file').substr(1), 10);
-
- var children = pages[i].childNodes;
- var context = '';
- for (var j=0; j<children.length; j++) {
- //console.log(j + ' - ' + children[j].nodeName);
- //console.log(children[j].firstChild.nodeValue);
- if ('CONTEXT' == children[j].nodeName) {
- context += children[j].firstChild.nodeValue;
- } else if ('WORD' == children[j].nodeName) {
- context += '<b>'+children[j].firstChild.nodeValue+'</b>';
-
- var index = this.leafNumToIndex(index);
- if (null != index) {
- //coordinates are [left, bottom, right, top, [baseline]]
- //we'll skip baseline for now...
- var coords = children[j].getAttribute('coords').split(',',4);
- if (4 == coords.length) {
- this.searchResults[index] = {'l':parseInt(coords[0]), 'b':parseInt(coords[1]), 'r':parseInt(coords[2]), 't':parseInt(coords[3]), 'div':null};
- }
- }
- }
- }
- var pageName = this.getPageName(index);
- var middleX = (this.searchResults[index].l + this.searchResults[index].r) >> 1;
- var middleY = (this.searchResults[index].t + this.searchResults[index].b) >> 1;
- //TODO: remove hardcoded instance name
- $('#BookReaderSearchResults').append('<li><b><a href="javascript:br.jumpToIndex('+index+','+middleX+','+middleY+');">' + pageName + '</a></b> - ' + context + '</li>');
- }
- }
- $('#BookReaderSearchResults').append('</ul>');
-
- // $$$ update again for case of loading search URL in new browser window (search box may not have been ready yet)
- $('#BookReaderSearchBox').val(this.searchTerm);
-
- this.updateSearchHilites();
-}
// updateSearchHilites()
//______________________________________________________________________________
// showSearchHilites1UP()
//______________________________________________________________________________
BookReader.prototype.updateSearchHilites1UP = function() {
-
- for (var key in this.searchResults) {
-
- if (jQuery.inArray(parseInt(key), this.displayedIndices) >= 0) {
- var result = this.searchResults[key];
- if (null == result.div) {
- result.div = document.createElement('div');
- $(result.div).attr('className', 'BookReaderSearchHilite').appendTo('#pagediv'+key);
- //console.log('appending ' + key);
- }
- $(result.div).css({
- width: (result.r-result.l)/this.reduce + 'px',
- height: (result.b-result.t)/this.reduce + 'px',
- left: (result.l)/this.reduce + 'px',
- top: (result.t)/this.reduce +'px'
- });
-
- } else {
- //console.log(key + ' not displayed');
- this.searchResults[key].div=null;
+ var results = this.searchResults;
+ if (null == results) return;
+ var i, j;
+ for (i=0; i<results.matches.length; i++) {
+ //console.log(results.matches[i].par[0]);
+ for (j=0; j<results.matches[i].par[0].boxes.length; j++) {
+ var box = results.matches[i].par[0].boxes[j];
+ var pageIndex = this.leafNumToIndex(box.page);
+ if (jQuery.inArray(pageIndex, this.displayedIndices) >= 0) {
+ if (null == box.div) {
+ //create a div for the search highlight, and stash it in the box object
+ box.div = document.createElement('div');
+ $(box.div).attr('className', 'BookReaderSearchHilite').appendTo('#pagediv'+pageIndex);
+ }
+ $(box.div).css({
+ width: (box.r-box.l)/this.reduce + 'px',
+ height: (box.b-box.t)/this.reduce + 'px',
+ left: (box.l)/this.reduce + 'px',
+ top: (box.t)/this.reduce +'px'
+ });
+ } else {
+ if (null != box.div) {
+ //console.log('removing search highlight div');
+ $(box.div).remove();
+ box.div=null;
+ }
+ }
}
}
+
}
+
// twoPageGutter()
//______________________________________________________________________________
// Returns the position of the gutter (line between the page images)
});
}
-// showSearchHilites2UP()
+// showSearchHilites2UPNew()
//______________________________________________________________________________
BookReader.prototype.updateSearchHilites2UP = function() {
-
- for (var key in this.searchResults) {
- key = parseInt(key, 10);
- if (jQuery.inArray(key, this.displayedIndices) >= 0) {
- var result = this.searchResults[key];
- if (null == result.div) {
- result.div = document.createElement('div');
- $(result.div).attr('className', 'BookReaderSearchHilite').css('zIndex', 3).appendTo('#BRtwopageview');
- //console.log('appending ' + key);
- }
-
- this.setHilightCss2UP(result.div, key, result.l, result.r, result.t, result.b);
-
- } else {
- //console.log(key + ' not displayed');
- if (null != this.searchResults[key].div) {
- //console.log('removing ' + key);
- $(this.searchResults[key].div).remove();
+ //console.log('updateSearchHilites2UP results = ' + this.searchResults);
+ var results = this.searchResults;
+ if (null == results) return;
+ var i, j;
+ for (i=0; i<results.matches.length; i++) {
+ //console.log(results.matches[i].par[0]);
+ //TODO: loop over all par objects
+ var pageIndex = this.leafNumToIndex(results.matches[i].par[0].page);
+ for (j=0; j<results.matches[i].par[0].boxes.length; j++) {
+ var box = results.matches[i].par[0].boxes[j];
+ if (jQuery.inArray(pageIndex, this.displayedIndices) >= 0) {
+ if (null == box.div) {
+ //create a div for the search highlight, and stash it in the box object
+ box.div = document.createElement('div');
+ $(box.div).attr('className', 'BookReaderSearchHilite').css('zIndex', 3).appendTo('#BRtwopageview');
+ //console.log('appending new div');
+ }
+ this.setHilightCss2UP(box.div, pageIndex, box.l, box.r, box.t, box.b);
+ } else {
+ if (null != box.div) {
+ //console.log('removing search highlight div');
+ $(box.div).remove();
+ box.div=null;
+ }
}
- this.searchResults[key].div=null;
}
}
+
}
// setHilightCss2UP()
// removeSearchHilites()
//______________________________________________________________________________
BookReader.prototype.removeSearchHilites = function() {
- for (var key in this.searchResults) {
- if (null != this.searchResults[key].div) {
- $(this.searchResults[key].div).remove();
- this.searchResults[key].div=null;
- }
- }
+ var results = this.searchResults;
+ if (null == results) return;
+ var i, j;
+ for (i=0; i<results.matches.length; i++) {
+ for (j=0; j<results.matches[i].par[0].boxes.length; j++) {
+ var box = results.matches[i].par[0].boxes[j];
+ if (null != box.div) {
+ $(box.div).remove();
+ box.div=null;
+ }
+ }
+ }
}
+
// printPage
//______________________________________________________________________________
BookReader.prototype.printPage = function() {
//______________________________________________________________________________
BookReader.prototype.autoToggle = function() {
+ this.ttsStop();
+
var bComingFrom1up = false;
if (2 != this.mode) {
bComingFrom1up = true;
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(
'<div id="BRnav">'
+ '<div id="BRpage">' // Page turn buttons
+ + '<button class="BRicon onepg"></button>'
+ + '<button class="BRicon twopg"></button>'
+ + '<button class="BRicon thumb"></button>'
+ // $$$ not yet implemented
+ //+ '<button class="BRicon fit"></button>'
+ + '<button class="BRicon zoom_in"></button>'
+ + '<button class="BRicon zoom_out"></button>'
+ '<button class="BRicon book_left"></button>'
+ '<button class="BRicon book_right"></button>'
+ '</div>'
+ '<div class="BRnavend" id="BRnavright"></div>'
+ '</div>'
+ '</div>'
+ + '<div id="BRnavCntlBtm" class="BRnavCntl BRdn"></div>'
+ '</div>'
);
.append('<div id="pagenum"><span class="currentpage"></span></div>');
//.wrap('<div class="ui-handle-helper-parent"></div>').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();
});
$("#BRzoombtn").draggable({axis:'y',containment:'parent'});
- //XXXmang remove once done testing
- //this.addSearchResult("There is a place where the <strong>sidewalk</strong> 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 <strong>sidewalk</strong> 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);
+ */
}
BookReader.prototype.updateNavPageNum = function(index) {
var re = new RegExp('{{{(.+?)}}}', 'g');
queryString = queryString.replace(re, '<a href="#" onclick="br.jumpToIndex('+pageIndex+'); return false;">$1</a>')
- $('<div class="search" style="left:' + percentThrough + ';" title="' + uiStringSearch + '"><div class="query">'
+ var marker = $('<div class="search" style="top:'+(-$('#BRcontainer').height())+'px; left:' + percentThrough + ';" title="' + uiStringSearch + '"><div class="query">'
+ queryString + '<span>' + uiStringPage + ' ' + pageNumber + '</span></div>')
.data({'self': this, 'pageIndex': pageIndex })
.appendTo('#BRnavline').bt({
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');
.bind('click', function() {
$(this).data('self').jumpToIndex($(this).data('pageIndex'));
});
+
+ $(marker).animate({top:'-25px'}, 'slow');
}
BookReader.prototype.removeSearchResults = function() {
+ this.removeSearchHilites(); //be sure to set all box.divs to null
$('#BRnavpos .search').remove();
}
closeWhenOthersOpen: true,
cssStyles: {
padding: '12px 14px',
- //backgroundColor: '#000',
- backgroundColor: '#444', // To set it off slightly from the chapter marker
+ backgroundColor: '#000',
border: '4px solid #e2dcc5',
//borderBottom: 'none',
fontFamily: '"Arial", sans-serif',
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');
BookReader.prototype.initToolbar = function(mode, ui) {
// $$$mang should be contained within the BookReader div instead of body
- var readIcon = ''
+ var readIcon = '';
if (!navigator.userAgent.match(/mobile/i)) {
readIcon = "<button class='BRicon read modal'></button>";
}
- $("body").append(
+ $("#BookReader").append(
"<div id='BRtoolbar'>"
+ "<span id='BRtoolbarbuttons'>"
- /* XXXmang integrate search */
- + "<form action='javascript:' id='booksearch'><input type='search' id='textSrch' name='textSrch' val='' placeholder='Search inside'/><button type='submit' id='btnSrch' name='btnSrch'>GO</button></form>"
- // XXXmang icons incorrect or handlers wrong
+ + "<form action='javascript:br.search($(\"#textSrch\").val());' id='booksearch'><input type='search' id='textSrch' name='textSrch' val='' placeholder='Search inside'/><button type='submit' id='btnSrch' name='btnSrch'>GO</button></form>"
+ + "<button class='BRicon play'></button>"
+ + "<button class='BRicon pause'></button>"
+ "<button class='BRicon info'></button>"
+ "<button class='BRicon share'></button>"
+ readIcon
- + "<button class='BRicon full'></button>"
+ //+ "<button class='BRicon full'></button>"
+ "</span>"
+ "<span><a class='logo' href='" + this.logoURL + "'></a></span>"
+ "<span id='BRreturn'><span>Back to</span><a href='" + this.bookUrl + "'>" + this.bookTitle + "</a></span>"
+ + "<div id='BRnavCntlTop' class='BRnabrbuvCntl'></div>"
+ "</div>"
-
+ /*
+ "<div id='BRzoomer'>"
+ "<div id='BRzoompos'>"
+ "<button class='BRicon zoom_out'></button>"
+ "</div>"
+ "<button class='BRicon zoom_in'></button>"
+ "</div>"
- + "</div>");
+ + "</div>"
+ */
+ );
+
+ $('#BRtoolbar .BRnavCntl').addClass('BRup');
+ $('#BRtoolbar .pause').hide();
this.updateToolbarZoom(this.reduce); // Pretty format
// We build in mode 2
jToolbar.append();
-
- this.bindToolbarNavHandlers(jToolbar);
-
- // Setup tooltips -- later we could load these from a file for i18n
- var titles = { '.logo': 'Go to Archive.org',
- '.zoom_in': 'Zoom in',
- '.zoom_out': 'Zoom out',
- '.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) ) {
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.ttsStop(); } });
+ jToolbar.find('.info').colorbox({inline: true, opacity: "0.5", href: "#BRinfo", onLoad: function() { self.ttsStop(); } });
+
+ $('<div style="display: none;"></div>').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 $([
+ '<div class="BRfloat" id="BRinfo">',
+ '<div class="BRfloatHead">About this book',
+ '<a class="floatShut" href="javascript:;" onclick="$.fn.colorbox.close();"><span class="shift">Close</span></a>',
+ '</div>',
+ '<div class="BRfloatBody">',
+ '<div class="BRfloatCover">',
+ '</div>',
+ '<div class="BRfloatMeta">',
+ '<div class="BRfloatTitle">',
+ '<h2><a/></h2>',
+ '</div>',
+ '</div>',
+ '</div>',
+ '<div class="BRfloatFoot">',
+ '<a href="http://openlibrary.org/dev/docs/bookreader">About the BookReader</a>',
+ '</div>',
+ '</div>'].join('\n')
+ );
+}
+
+BookReader.prototype.blankShareDiv = function() {
+ return $([
+ '<div class="BRfloat" id="BRshare">',
+ '<div class="BRfloatHead">',
+ 'Share',
+ '<a class="floatShut" href="javascript:;" onclick="$.fn.colorbox.close();"><span class="shift">Close</span></a>',
+ '</div>',
+ '</div>'].join('\n')
+ );
+}
+
// switchToolbarMode
//______________________________________________________________________________
}
}
-// bindToolbarNavHandlers
+// updateToolbarZoom(reduce)
+//______________________________________________________________________________
+// Update the displayed zoom factor based on reduction factor
+BookReader.prototype.updateToolbarZoom = function(reduce) {
+ var value;
+ var autofit = null;
+
+ // $$$ TODO preserve zoom/fit for each mode
+ if (this.mode == this.constMode2up) {
+ autofit = this.twoPage.autofit;
+ } else {
+ autofit = this.onePage.autofit;
+ }
+
+ if (autofit) {
+ value = autofit.slice(0,1).toUpperCase() + autofit.slice(1);
+ } else {
+ value = (100 / reduce).toFixed(2);
+ // Strip trailing zeroes and decimal if all zeroes
+ value = value.replace(/0+$/,'');
+ value = value.replace(/\.$/,'');
+ value += '%';
+ }
+ $('#BRzoom').text(value);
+}
+
+// bindNavigationHandlers
//______________________________________________________________________________
-// Binds the toolbar handlers
-BookReader.prototype.bindToolbarNavHandlers = function(jToolbar) {
+// Bind navigation handlers
+BookReader.prototype.bindNavigationHandlers = function() {
var self = this; // closure
+ jIcons = $('.BRicon');
+
+ jIcons.filter('.onepg').bind('click', function(e) {
+ self.switchMode(self.constMode1up);
+ });
+
+ jIcons.filter('.twopg').bind('click', function(e) {
+ self.switchMode(self.constMode2up);
+ });
+
+ jIcons.filter('.thumb').bind('click', function(e) {
+ self.switchMode(self.constModeThumb);
+ });
+
+ jIcons.filter('.fit').bind('fit', function(e) {
+ // XXXmang implement autofit zoom
+ });
- jToolbar.find('.book_left').click(function(e) {
+ jIcons.filter('.book_left').click(function(e) {
self.left();
return false;
});
- jToolbar.find('.book_right').click(function(e) {
+ jIcons.filter('.book_right').click(function(e) {
self.right();
return false;
});
- jToolbar.find('.book_up').bind('click', function(e) {
+ jIcons.filter('.book_up').bind('click', function(e) {
if ($.inArray(self.mode, [self.constMode1up, self.constModeThumb]) >= 0) {
self.scrollUp();
} else {
return false;
});
- jToolbar.find('.book_down').bind('click', function(e) {
+ jIcons.filter('.book_down').bind('click', function(e) {
if ($.inArray(self.mode, [self.constMode1up, self.constModeThumb]) >= 0) {
self.scrollDown();
} else {
return false;
});
- jToolbar.find('.print').click(function(e) {
+ jIcons.filter('.print').click(function(e) {
self.printPage();
return false;
});
- jToolbar.find('.embed').click(function(e) {
+ jIcons.filter('.embed').click(function(e) {
self.showEmbedCode();
return false;
});
- jToolbar.find('.bookmark').click(function(e) {
+ jIcons.filter('.bookmark').click(function(e) {
self.showBookmarkCode();
return false;
});
- jToolbar.find('.play').click(function(e) {
+ jIcons.filter('.play').click(function(e) {
self.autoToggle();
return false;
});
- jToolbar.find('.pause').click(function(e) {
+ jIcons.filter('.pause').click(function(e) {
self.autoToggle();
return false;
});
- jToolbar.find('.book_top').click(function(e) {
+ jIcons.filter('.book_top').click(function(e) {
self.first();
return false;
});
- jToolbar.find('.book_bottom').click(function(e) {
+ jIcons.filter('.book_bottom').click(function(e) {
self.last();
return false;
});
- jToolbar.find('.book_leftmost').click(function(e) {
+ jIcons.filter('.book_leftmost').click(function(e) {
self.leftmost();
return false;
});
- jToolbar.find('.book_rightmost').click(function(e) {
+ jIcons.filter('.book_rightmost').click(function(e) {
self.rightmost();
return false;
});
- jToolbar.find('.read').click(function(e) {
+ jIcons.filter('.read').click(function(e) {
self.ttsToggle();
return false;
});
- // $$$mang cleanup
- $('#BRzoomer .zoom_in').bind('click', function() {
+ jIcons.filter('.zoom_in').bind('click', function() {
+ self.ttsStop();
self.zoom(1);
return false;
});
- $('#BRzoomer .zoom_out').bind('click', function() {
+ jIcons.filter('.zoom_out').bind('click', function() {
+ self.ttsStop();
self.zoom(-1);
return false;
});
- $('#booksearch').bind('submit', function() {
- self.searchNew($('#textSrch').val());
+ $('.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);
+ };
});
-
-}
-
-// updateToolbarZoom(reduce)
-//______________________________________________________________________________
-// Update the displayed zoom factor based on reduction factor
-BookReader.prototype.updateToolbarZoom = function(reduce) {
- var value;
- var autofit = null;
- // $$$ TODO preserve zoom/fit for each mode
- if (this.mode == this.constMode2up) {
- autofit = this.twoPage.autofit;
- } else {
- autofit = this.onePage.autofit;
- }
- if (autofit) {
- value = autofit.slice(0,1).toUpperCase() + autofit.slice(1);
- } else {
- value = (100 / reduce).toFixed(2);
- // Strip trailing zeroes and decimal if all zeroes
- value = value.replace(/0+$/,'');
- value = value.replace(/\.$/,'');
- value += '%';
- }
- $('#BRzoom').text(value);
-}
-
-// bindNavigationHandlers
-//______________________________________________________________________________
-// Bind navigation handlers
-BookReader.prototype.bindNavigationHandlers = function() {
+ 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
}
}
+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
// $$$ don't hardcode height
$('#BRtoolbar').animate({top:-60});
$('#BRnav').animate({bottom:-60});
- $('#BRzoomer').animate({right:-26});
+ //$('#BRzoomer').animate({right:-26});
}
}
if (!this.navigationIsVisible()) {
$('#BRtoolbar').animate({top:0});
$('#BRnav').animate({bottom:0});
- $('#BRzoomer').animate({right:0});
+ //$('#BRzoomer').animate({right:0});
}
}
+// 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.
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
// searchHighlightVisible
//________
// Returns true if a search highlight is currently being displayed
-BookReader.prototype.searchHighlightVisible = function() {
+BookReader.prototype.searchHighlightVisible = function() {
+ var results = this.searchResults;
+ if (null == results) return false;
+
if (this.constMode2up == this.mode) {
- if (this.searchResults[this.twoPage.currentIndexL]
- || this.searchResults[this.twoPage.currentIndexR]) {
- return true;
- }
- } else { // 1up
- if (this.searchResults[this.currentIndex()]) {
- return true;
+ var visiblePages = Array(this.twoPage.currentIndexL, this.twoPage.currentIndexR);
+ } else if (this.constMode1up == this.mode) {
+ var visiblePages = Array();
+ visiblePages[0] = this.currentIndex();
+ } else {
+ return false;
+ }
+
+ var i, j;
+ for (i=0; i<results.matches.length; i++) {
+ //console.log(results.matches[i].par[0]);
+ for (j=0; j<results.matches[i].par[0].boxes.length; j++) {
+ var box = results.matches[i].par[0].boxes[j];
+ var pageIndex = this.leafNumToIndex(box.page);
+ if (jQuery.inArray(pageIndex, visiblePages) >= 0) {
+ return true;
+ }
}
}
+
return false;
}
// Returns the page URI or transparent image if out of range
BookReader.prototype._getPageURI = function(index, reduce, rotate) {
if (index < 0 || index >= this.numLeafs) { // Synthesize page
- return this.imagesBaseURL + "/transparent.png";
+ return this.imagesBaseURL + "transparent.png";
}
if ('undefined' == typeof(reduce)) {
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', this.bookUrl);
+ $('#BookReader .logo').attr('title', 'Go to Open Library'); // i18n
+
+ $('#BRinfo').remove();
+ $('#BRshare').after(self.blankInfoDiv());
+ self.buildInfoDiv($('#BRinfo'));
+ }
}
// Library functions
return (outer.document || outer);
},
+ escapeHTML: function (str) {
+ return(
+ str.replace(/&/g,'&').
+ replace(/>/g,'>').
+ replace(/</g,'<').
+ replace(/"/g,'"')
+ );
+ },
+
decodeURIComponentPlus: function(value) {
// Decodes a URI component and converts '+' to ' '
return decodeURIComponent(value).replace(/\+/g, ' ');
// ttsToggle()
//______________________________________________________________________________
BookReader.prototype.ttsToggle = function () {
+
+ this.autoStop();
+
if (false == this.ttsPlaying) {
this.ttsPlaying = true;
- this.ttsShowPopup();
+ this.showProgressPopup('Loading audio...');
if(soundManager.supported()) {
this.ttsStart();
} else {
soundManager.stopAll();
soundManager.destroySound('chunk'+this.ttsIndex+'-'+this.ttsPosition);
this.ttsRemoveHilites();
- this.ttsRemovePopup();
+ this.removeProgressPopup();
this.ttsPlaying = false;
this.ttsIndex = null; //leaf index
return;
}
- this.ttsShowPopup();
+ this.showProgressPopup('Loading audio...');
///// whileloading: broken on safari
///// onload fires on safari, but *after* the sound starts playing..
id: 'chunk'+this.ttsIndex+'-0',
//url: 'http://home.us.archive.org/~rkumar/arctic.ogg',
url: 'http://'+this.server+'/BookReader/BookReaderGetTTS.php?string=' + escape(data[0][0]) + '&format=.'+this.ttsFormat, //the .ogg is to trick SoundManager2 to use the HTML5 audio player
- whileloading: function(){if (this.bytesLoaded == this.bytesTotal) this.br.ttsRemovePopup();}, //onload never fires in FF...
- onload: function(){this.br.ttsRemovePopup();} //whileloading never fires in safari...
+ whileloading: function(){if (this.bytesLoaded == this.bytesTotal) this.br.removeProgressPopup();}, //onload never fires in FF...
+ onload: function(){this.br.removeProgressPopup();} //whileloading never fires in safari...
});
snd.br = this;
snd.load();
this.ttsNextChunk();
}
-// ttsShowPopup
+// showProgressPopup
//______________________________________________________________________________
-BookReader.prototype.ttsShowPopup = function() {
- if (soundManager.debugMode) console.log('ttsShowPopup index='+this.ttsIndex+' pos='+this.ttsPosition);
+BookReader.prototype.showProgressPopup = function(msg) {
+ //if (soundManager.debugMode) console.log('showProgressPopup index='+this.ttsIndex+' pos='+this.ttsPosition);
if (this.popup) return;
this.popup = document.createElement("div");
$(this.popup).css({
- top: $('#BRtoolbar').height() + 'px',
- left: $('#BookReader').width()-220 + 'px',
- width: '220px',
- height: '20px',
- }).attr('className', 'BRttsPopUp').appendTo('#BookReader');
+ top: ($('#BookReader').height()*0.5-100) + 'px',
+ left: ($('#BookReader').width()-300)*0.5 + 'px'
+ }).attr('className', 'BRprogresspopup');
- htmlStr = ' ';
+ var bar = document.createElement("div");
+ $(bar).css({
+ height: '20px'
+ }).attr('className', 'BRprogressbar');
+ $(this.popup).append(bar);
- this.popup.innerHTML = htmlStr;
+ if (msg) {
+ var msgdiv = document.createElement("div");
+ msgdiv.innerHTML = msg;
+ $(this.popup).append(msgdiv);
+ }
+
+ $(this.popup).appendTo('#BookReader');
}
-// ttsRemovePopup
+// removeProgressPopup
//______________________________________________________________________________
-BookReader.prototype.ttsRemovePopup = function() {
+BookReader.prototype.removeProgressPopup = function() {
$(this.popup).remove();
this.popup=null;
}
self.ttsNextChunk();
},500);
}
+
+BookReader.prototype.buildShareDiv = function(jShareDiv)
+{
+ var pageView = document.location + '';
+ var bookView = (pageView + '').replace(/#.*/,'');
+ var self = this;
+
+ var jForm = $([
+ '<p>Copy and paste one of these options to share this book elsewhere.</p>',
+ '<form method="post" action="">',
+ '<fieldset>',
+ '<label for="pageview">Link to this page view:</label>',
+ '<input type="text" name="pageview" id="pageview" value="' + pageView + '"/>',
+ '</fieldset>',
+ '<fieldset>',
+ '<label for="booklink">Link to the book:</label>',
+ '<input type="text" name="booklink" id="booklink" value="' + bookView + '"/>',
+ '</fieldset>',
+ '<fieldset>',
+ '<label for="iframe">Embed a mini Book Reader:</label>',
+ '<fieldset class="sub">',
+ '<label class="sub">',
+ '<input type="radio" name="pages" value="' + this.constMode1up + '" checked="checked"/>',
+ '1 page',
+ '</label>',
+ '<label class="sub">',
+ '<input type="radio" name="pages" value="' + this.constMode2up + '"/>',
+ '2 pages',
+ '</label>',
+ '<label class="sub">',
+ '<input type="checkbox" name="thispage" value="thispage"/>',
+ 'Open to this page?',
+ '</label>',
+ '</fieldset>',
+ '<textarea cols="30" rows="4" name="iframe" class="BRframeEmbed"></textarea>',
+ '<p class="meta"><strong>NOTE:</strong> We\'ve tested EMBED on blogspot.com blogs as well as self-hosted Wordpress blogs. This feature will NOT work on wordpress.com blogs.</p>',
+ '</fieldset>',
+ '<fieldset class="center">',
+ '<button type="button" onclick="$.fn.colorbox.close();">Finished</button>',
+ '</fieldset>',
+ '</form>'].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);
+ var embedLink = self.getEmbedURL( params );
+ form.find('.BRframeEmbed').val('<iframe src="' + embedLink + '" width="480" height="480"></iframe>');
+ })
+ 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]);
+ }
+ }
+}