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
+ this.ttsPosition = -1; //chunk (paragraph) number
+ this.ttsBuffering = false;
+ this.ttsPoller = null;
+ this.ttsFormat = null;
return this;
};
// showEmbedCode()
//______________________________________________________________________________
BookReader.prototype.showEmbedCode = function() {
+ if (null != this.embedPopup) { // check if already showing
+ return;
+ }
+ this.autoStop();
+ this.ttsStop();
++
this.embedPopup = document.createElement("div");
$(this.embedPopup).css({
position: 'absolute',
}
}
+// 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(
+ '<div id="BRnav">'
+ + '<div id="BRpage">'
+ + '<button class="BRicon book_left"></button>'
+ + '<button class="BRicon book_right"></button>'
+ + '</div>'
+ + '<div id="BRnavpos">'
+ + '<div id="BRfiller"></div>'
+ + '<div id="BRpager">'
+ + '<div id="BRslider">'
+ + '<div id="slider"></div>'
+ + '<div id="pager"></div>'
+ // XXXmang update code to update pagenum
+ + '<div id="pagenum"><span>n141</span> / 325</div>'
+ + '</div>'
+ + '</div>'
+ + '<div id="BRnavline">'
+ + '<div class="BRnavend" id="BRnavleft"></div>'
+ + '<div class="BRnavend" id="BRnavright"></div>'
+ + '</div>'
+ + '</div>'
+ + '</div>'
+ );
+
+/*
+ <div class="searchChap" style="left:49%;" title="Search result">
+ <div class="query">
+ A related distinction is between the emotion and the results of the emotion, principally behaviors and <strong><a href="">emotional</a></strong> expressions. People often behave in certain ways as a direct result of their <strong><a href="">emotional</a></strong> state, such as crying, fighting or fleeing. <span>Page 163</span>
+ <div class="queryChap">IV. The Witch <span>|</span> Page 163</div>
+ </div>
+ </div>
+*/
+
+ /* $$$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');
+ });
+ });
+ */
+}
+
+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
+ $('<div class="search" style="left:' + percentThrough + ';" title="' + uiStringSearch + '"><div class="query">'
+ + queryString + '<span>' + uiStringPage + ' ' + pageNumber + '</span></div>')
+ .appendTo('#BRnavpos').bt({
+ contentSelector: '$(this).find(".query")',
+ trigger: 'click',
+ closeWhenOthersOpen: true,
+ cssStyles: {
+ 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: false,
+ 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
+ })
+ .hover(function(){
+ $(this).addClass('front');
+ },function(){
+ $(this).removeClass('front');
+ }
+ );
+}
+
+BookReader.prototype.removeSearchResults = function() {
+ $('#BRnavpos .search').remove();
+}
+
+BookReader.prototype.addChapter = function(chapterTitle, pageNumber, pageIndex) {
+ var uiStringPage = 'Page'; // i18n
+
+ var percentThrough = BookReader.util.cssPercentage(pageIndex, this.numLeafs);
+
+ $('<div class="chapter" style="left:' + percentThrough + ';"><div class="title">'
+ + chapterTitle + '<span>|</span> ' + uiStringPage + ' ' + pageNumber + '</div></div>')
+ .appendTo('#BRnavpos')
+ .data({'self': this, 'pageIndex': pageIndex })
+ .bt({
+ contentSelector: '$(this).find(".title")',
+ trigger: 'hover',
+ closeWhenOthersOpen: true,
+ cssStyles: {
+ backgroundColor: '#000',
+ border: '2px solid #e2dcc5',
+ borderBottom: 'none',
+ padding: '5px 10px',
+ fontFamily: '"Arial", sans-serif',
+ fontSize: '11px',
+ fontWeight: '700',
+ color: '#fff',
+ whiteSpace: 'nowrap'
+ },
+ shrinkToFit: true,
+ width: '200px',
+ padding: 0,
+ spikeGirth: 0,
+ spikeLength: 0,
+ overlap: '16px',
+ overlay: false,
+ killTitle: true,
+ textzIndex: 9999,
+ boxzIndex: 9998,
+ wrapperzIndex: 9997,
+ offsetParent: null,
+ positions: ['top'],
+ fill: 'black',
+ windowMargin: 10,
+ strokeWidth: 0,
+ cornerRadius: 0,
+ centerPointX: 0,
+ centerPointY: 0,
+ shadow: false
+ })
+ .hover( function() {
+ $(this).addClass('front');
+ }, function() {
+ $(this).removeClass('front');
+ }
+ )
+ .bind('click', function() {
+ $(this).data('self').jumpToIndex($(this).data('pageIndex'));
+ });
+}
+
+/*
+ * Remove all chapters.
+ */
+BookReader.prototype.removeChapters = function() {
+ $('#BRnavpos .chapter').remove();
+}
+
+/*
+ * Update the table of contents based on array of TOC entries.
+ */
+BookReader.prototype.updateTOC = function(tocEntries) {
+ this.removeChapters();
+ for (var i = 0; i < tocEntries.length; i++) {
+ this.addChapterFromEntry(tocEntries[i]);
+ }
+}
+
+/*
+ * Example table of contents entry - this format is defined by Open Library
+ * {
+ * "pagenum": "17",
+ * "level": 1,
+ * "label": "CHAPTER I",
+ * "type": {"key": "/type/toc_item"},
+ * "title": "THE COUNTRY AND THE MISSION"
+ * }
+ */
+BookReader.prototype.addChapterFromEntry = function(tocEntryObject) {
+ console.log(tocEntryObject);
+ var pageIndex = this.getPageIndex(tocEntryObject['pagenum']);
+ // Only add if we know where it is
+ if (pageIndex) {
+ this.addChapter(tocEntryObject['title'], tocEntryObject['pagenum'], pageIndex);
+ }
+ $('.chapter').each(function(){
+ $(this).hover(function(){
+ $(this).addClass('front');
+ },function(){
+ $(this).removeClass('front');
+ });
+ });
+ $('.search').each(function(){
+ $(this).hover(function(){
+ $(this).addClass('front');
+ },function(){
+ $(this).removeClass('front');
+ });
+ });
+ $('.searchChap').each(function(){
+ $(this).hover(function(){
+ $(this).addClass('front');
+ },function(){
+ $(this).removeClass('front');
+ });
+ });
+ $("#BRslider").draggable({axis:'x',containment:'parent'});
+ $("#BRzoombtn").draggable({axis:'y',containment:'parent'});
+ $("#BRslider").hover(
+ function(){
+ $("#pagenum").show();
+ },function(){
+ $("#pagenum").hide();
+ });
+}
+
BookReader.prototype.initToolbar = function(mode, ui) {
- $("#BookReader").append("<div id='BRtoolbar'>"
- + "<span id='BRtoolbarbuttons' style='float: right'>"
- + "<button class='BRicon rollover read_aloud' onclick='br.ttsToggle(); return false;'/>"
- + "<button class='BRicon print rollover' /> <button class='BRicon rollover embed' />"
- + "<form class='BRpageform' action='javascript:' onsubmit='br.jumpToPage(this.elements[0].value)'> <span class='label'>Page:<input id='BRpagenum' type='text' size='3' onfocus='br.autoStop();'></input></span></form>"
- + "<div class='BRtoolbarmode2' style='display: none'><button class='BRicon rollover book_leftmost' /><button class='BRicon rollover book_left' /><button class='BRicon rollover book_right' /><button class='BRicon rollover book_rightmost' /></div>"
- + "<div class='BRtoolbarmode1' style='display: none'><button class='BRicon rollover book_top' /><button class='BRicon rollover book_up' /> <button class='BRicon rollover book_down' /><button class='BRicon rollover book_bottom' /></div>"
- + "<div class='BRtoolbarmode3' style='display: none'><button class='BRicon rollover book_top' /><button class='BRicon rollover book_up' /> <button class='BRicon rollover book_down' /><button class='BRicon rollover book_bottom' /></div>"
- + "<button class='BRicon rollover play' /><button class='BRicon rollover pause' style='display: none' />"
+ // $$$mang should be contained within the BookReader div instead of body
+ $("body").append("<div id='BRtoolbar'>"
+ + "<span id='BRtoolbarbuttons'>"
+ /* XXXmang integrate search */
+ + "<form method='get' 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
+ + "<button class='BRicon info' onclick='br.switchMode(3); return false;'></button>"
+ + "<button class='BRicon share' onclick='br.switchMode(2); return false;'></button>"
- + "<button class='BRicon read modal'></button>"
++ + "<button class='BRicon read modal' onclick='br.ttsToggle(); return false;'></button>"
+ + "<button class='BRicon full'></button>"
+ "</span>"
+ "<span>"
}
// The final property here must NOT have a comma after it - IE7
}
-}
+
+
+ // ttsToggle()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsToggle = function () {
+ if (false == this.ttsPlaying) {
+ if(soundManager.supported()) {
+ this.ttsStart();
+ } else {
+ soundManager.onready(function(oStatus) {
+ if (oStatus.success) {
+ this.ttsStart();
+ } else {
+ alert('Could not load soundManger2, possibly due to FlashBlock. Audio playback is disabled');
+ }
+ }, this);
+ }
+ } else {
+ this.ttsStop();
+ }
+ }
+
+ // ttsStart()
+ //______________________________________________________________________________
+ 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';
+ if ($.browser.mozilla) {
+ this.ttsFormat = 'ogg';
+ }
+ this.ttsGetText(this.ttsIndex, 'ttsStartCB');
+ }
+
+ // ttsStop()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsStop = function () {
+ if (false == this.ttsPlaying) return;
+
+ if (soundManager.debugMode) console.log('stopping readaloud');
+ soundManager.stopAll();
+ soundManager.destroySound('chunk'+this.ttsIndex+'-'+this.ttsPosition);
+ this.ttsRemoveHilites();
+ this.ttsRemovePopup();
+
+ this.ttsPlaying = false;
+ this.ttsIndex = null; //leaf index
+ this.ttsPosition = -1; //chunk (paragraph) number
+ this.ttsBuffering = false;
+ this.ttsPoller = null;
+ }
+
+ // ttsGetText()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsGetText = function(index, callback) {
+ var url = 'http://'+this.server+'/BookReader/BookReaderGetTextWrapper.php?path='+this.bookPath+'_djvu.xml&page='+index;
+ this.ttsAjax = $.ajax({url:url, dataType:'jsonp', jsonpCallback:callback});
+ }
+
+ // ttsStartCB(): text-to-speech callback
+ //______________________________________________________________________________
+ BookReader.prototype.ttsStartCB = function (data) {
+ if (soundManager.debugMode) console.log('ttsStartCB got data: ' + data);
+ this.ttsChunks = data;
+ this.ttsHilites = [];
+
+ //deal with the page being blank
+ if (0 == data.length) {
+ if (soundManager.debugMode) console.log('first page is blank!');
+ if(this.ttsAdvance(true)) {
+ this.ttsGetText(this.ttsIndex, 'ttsStartCB');
+ }
+ return;
+ }
+
+ this.ttsShowPopup();
+
+ ///// whileloading: broken on safari
+ ///// onload fires on safari, but *after* the sound starts playing..
+ this.ttsPosition = -1;
+ var snd = soundManager.createSound({
+ 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...
+ });
+ snd.br = this;
+ snd.load();
+
+ this.ttsNextChunk();
+ }
+
+ // ttsShowPopup
+ //______________________________________________________________________________
+ BookReader.prototype.ttsShowPopup = function() {
+ if (soundManager.debugMode) console.log('ttsShowPopup index='+this.ttsIndex+' pos='+this.ttsPosition);
+
+ 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',
+ height: '20px',
+ }).attr('className', 'BRttsPopUp').appendTo('#BookReader');
+
+ htmlStr = ' ';
+
+ this.popup.innerHTML = htmlStr;
+ }
+
+ // ttsRemovePopup
+ //______________________________________________________________________________
+ BookReader.prototype.ttsRemovePopup = function() {
+ $(this.popup).remove();
+ this.popup=null;
+ }
+
+ // ttsNextPageCB
+ //______________________________________________________________________________
+ BookReader.prototype.ttsNextPageCB = function (data) {
+ this.ttsNextChunks = data;
+ if (soundManager.debugMode) console.log('preloaded next chunks.. data is ' + data);
+
+ if (true == this.ttsBuffering) {
+ if (soundManager.debugMode) console.log('ttsNextPageCB: ttsBuffering is true');
+ this.ttsBuffering = false;
+ }
+ }
+
+ // ttsLoadChunk
+ //______________________________________________________________________________
+ BookReader.prototype.ttsLoadChunk = function (page, pos, string) {
+ var snd = soundManager.createSound({
+ id: 'chunk'+page+'-'+pos,
+ url: 'http://'+this.server+'/BookReader/BookReaderGetTTS.php?string=' + escape(string) + '&format=.'+this.ttsFormat //the .ogg is to trick SoundManager2 to use the HTML5 audio player
+ });
+ snd.br = this;
+ snd.load()
+ }
+
+
+ // ttsNextChunk()
+ //______________________________________________________________________________
+ // This function into two parts: ttsNextChunk gets run before page flip animation
+ // and ttsNextChunkPhase2 get run after page flip animation.
+ // If a page flip is necessary, ttsAdvance() will return false so Phase2 isn't
+ // called. Instead, this.animationFinishedCallback is set, so that Phase2
+ // continues after animation is finished.
+
+ BookReader.prototype.ttsNextChunk = function () {
+ if (soundManager.debugMode) console.log('nextchunk pos=' + this.ttsPosition);
+
+ if (-1 != this.ttsPosition) {
+ soundManager.destroySound('chunk'+this.ttsIndex+'-'+this.ttsPosition);
+ }
+
+ this.ttsRemoveHilites(); //remove old hilights
+
+ var moreToPlay = this.ttsAdvance();
+
+ if (moreToPlay) {
+ this.ttsNextChunkPhase2();
+ }
+
+ //This function is called again when ttsPlay() has finished playback.
+ //If the next chunk of text has not yet finished loading, ttsPlay()
+ //will start polling until the next chunk is ready.
+ }
+
+ // ttsNextChunkPhase2()
+ //______________________________________________________________________________
+ // page flip animation has now completed
+ BookReader.prototype.ttsNextChunkPhase2 = function () {
+ if (null == this.ttsChunks) {
+ alert('error: ttsChunks is null?'); //TODO
+ return;
+ }
+
+ if (0 == this.ttsChunks.length) {
+ if (soundManager.debugMode) console.log('ttsNextChunk2: ttsChunks.length is zero.. hacking...');
+ this.ttsStartCB(this.ttsChunks);
+ return;
+ }
+
+ if (soundManager.debugMode) console.log('next chunk is ' + this.ttsPosition);
+
+ //prefetch next page of text
+ if (0 == this.ttsPosition) {
+ if (this.ttsIndex<(this.numLeafs-1)) {
+ this.ttsGetText(this.ttsIndex+1, 'ttsNextPageCB');
+ }
+ }
+
+ this.ttsPrefetchAudio();
+
+ this.ttsPlay();
+ }
+
+ // ttsAdvance()
+ //______________________________________________________________________________
+ // 1. advance ttsPosition
+ // 2. if necessary, advance ttsIndex, and copy ttsNextChunks to ttsChunks
+ // 3. if necessary, flip to current page, or scroll so chunk is visible
+ // 4. do something smart is ttsNextChunks has not yet finished preloading (TODO)
+ // 5. stop playing at end of book
+
+ BookReader.prototype.ttsAdvance = function (starting) {
+ this.ttsPosition++;
+
+ if (this.ttsPosition >= this.ttsChunks.length) {
+
+ if (this.ttsIndex == (this.numLeafs-1)) {
+ if (soundManager.debugMode) console.log('tts stop');
+ return false;
+ } else {
+ if ((null != this.ttsNextChunks) || (starting)) {
+ if (soundManager.debugMode) console.log('moving to next page!');
+ this.ttsIndex++;
+ this.ttsPosition = 0;
+ this.ttsChunks = this.ttsNextChunks;
+ this.ttsNextChunks = null;
+
+ //A page flip might be necessary. This code is confusing since
+ //ttsNextChunks might be null if we are starting on a blank page.
+ if (2 == this.mode) {
+ if ((this.ttsIndex != this.twoPage.currentIndexL) && (this.ttsIndex != this.twoPage.currentIndexR)) {
+ if (!starting) {
+ this.animationFinishedCallback = this.ttsNextChunkPhase2;
+ this.next();
+ return false;
+ } else {
+ this.next();
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ } else {
+ if (soundManager.debugMode) console.log('ttsAdvance: ttsNextChunks is null');
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // ttsPrefetchAudio()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsPrefetchAudio = function () {
+
+ if(false != this.ttsBuffering) {
+ alert('TTS Error: prefetch() called while content still buffering!');
+ return;
+ }
+
+ //preload next chunk
+ var nextPos = this.ttsPosition+1;
+ if (nextPos < this.ttsChunks.length) {
+ this.ttsLoadChunk(this.ttsIndex, nextPos, this.ttsChunks[nextPos][0]);
+ } else {
+ //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) {
+ if (0 != this.ttsNextChunks.length) {
+ this.ttsLoadChunk(this.ttsIndex+1, 0, this.ttsNextChunks[0][0]);
+ } else {
+ if (soundManager.debugMode) console.log('prefetchAudio(): ttsNextChunks is zero length!');
+ }
+ } else {
+ if (soundManager.debugMode) console.log('ttsNextChunks is null, not preloading next page');
+ this.ttsBuffering = true;
+ }
+ }
+
+ }
+
+ // ttsPlay()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsPlay = function () {
+
+ var chunk = this.ttsChunks[this.ttsPosition];
+ if (soundManager.debugMode) {
+ console.log('ttsPlay position = ' + this.ttsPosition);
+ console.log('chunk = ' + chunk);
+ console.log(this.ttsChunks);
+ }
+
+ //add new hilights
+ if (2 == this.mode) {
+ this.ttsHilite2UP(chunk);
+ } else {
+ this.ttsHilite1UP(chunk);
+ }
+
+ this.ttsScrollToChunk(chunk);
+
+ //play current chunk
+ if (false == this.ttsBuffering) {
+ soundManager.play('chunk'+this.ttsIndex+'-'+this.ttsPosition,{onfinish:function(){br.ttsNextChunk();}});
+ } else {
+ soundManager.play('chunk'+this.ttsIndex+'-'+this.ttsPosition,{onfinish:function(){br.ttsStartPolling();}});
+ }
+ }
+
+ // scrollToChunk()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsScrollToChunk = function(chunk) {
+ if (this.constMode1up != this.mode) return;
+
+ var leafTop = 0;
+ var h;
+ var i;
+ for (i=0; i<this.ttsIndex; i++) {
+ h = parseInt(this._getPageHeight(i)/this.reduce);
+ leafTop += h + this.padding;
+ }
+
+ var chunkTop = chunk[1][3]; //coords are in l,b,r,t order
+ var chunkBot = chunk[chunk.length-1][1];
+
+ var topOfFirstChunk = leafTop + chunkTop/this.reduce;
+ var botOfLastChunk = leafTop + chunkBot/this.reduce;
+
+ if (soundManager.debugMode) console.log('leafTop = ' + leafTop + ' topOfFirstChunk = ' + topOfFirstChunk + ' botOfLastChunk = ' + botOfLastChunk);
+
+ var containerTop = $('#BRcontainer').attr('scrollTop');
+ var containerBot = containerTop + $('#BRcontainer').height();
+ if (soundManager.debugMode) console.log('containerTop = ' + containerTop + ' containerBot = ' + containerBot);
+
+ if ((topOfFirstChunk < containerTop) || (botOfLastChunk > containerBot)) {
+ //jumpToIndex scrolls so that chunkTop is centered.. we want chunkTop at the top
+ //this.jumpToIndex(this.ttsIndex, null, chunkTop);
+ $('#BRcontainer').animate({scrollTop: topOfFirstChunk},'fast');
+ }
+ }
+
+ // ttsHilite1UP()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsHilite1UP = function(chunk) {
+ var i;
+ for (i=1; i<chunk.length; i++) {
+ //each rect is an array of l,b,r,t coords (djvu.xml ordering...)
+ var l = chunk[i][0];
+ var b = chunk[i][1];
+ var r = chunk[i][2];
+ var t = chunk[i][3];
+
+ var div = document.createElement('div');
+ this.ttsHilites.push(div);
+ $(div).attr('className', 'BookReaderSearchHilite').appendTo('#pagediv'+this.ttsIndex);
+
+ $(div).css({
+ width: (r-l)/this.reduce + 'px',
+ height: (b-t)/this.reduce + 'px',
+ left: l/this.reduce + 'px',
+ top: t/this.reduce +'px'
+ });
+ }
+
+ }
+
+ // ttsHilite2UP()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsHilite2UP = function (chunk) {
+ var i;
+ for (i=1; i<chunk.length; i++) {
+ //each rect is an array of l,b,r,t coords (djvu.xml ordering...)
+ var l = chunk[i][0];
+ var b = chunk[i][1];
+ var r = chunk[i][2];
+ var t = chunk[i][3];
+
+ var div = document.createElement('div');
+ this.ttsHilites.push(div);
+ $(div).attr('className', 'BookReaderSearchHilite').css('zIndex', 3).appendTo('#BRtwopageview');
+ this.setHilightCss2UP(div, this.ttsIndex, l, r, t, b);
+ }
+ }
+
+ // ttsRemoveHilites()
+ //______________________________________________________________________________
+ BookReader.prototype.ttsRemoveHilites = function (chunk) {
+ $(this.ttsHilites).remove();
+ this.ttsHilites = [];
+ }
+
+ // ttsStartPolling()
+ //______________________________________________________________________________
+ // Play of the current chunk has ended, but the next chunk has not yet been loaded.
+ // We need to wait for the text for the next page to be loaded, so we can
+ // load the next audio chunk
+ BookReader.prototype.ttsStartPolling = function () {
+ if (soundManager.debugMode) console.log('Starting the TTS poller...');
+ var self = this;
+ this.ttsPoller=setInterval(function(){
+ if (self.ttsBuffering) {return;}
+
+ if (soundManager.debugMode) console.log('TTS buffering finished!');
+ clearInterval(self.ttsPoller);
+ self.ttsPoller = null;
+ self.ttsPrefetchAudio();
+ self.ttsNextChunk();
+ },500);
++}