11import {
2- getCurrentTranslation ,
2+ playChapterAudio ,
3+ pauseChapterAudio ,
4+ resumeChapterAudio ,
5+ stopChapterAudio
6+ } from './modules/api.js' ;
7+ import {
38 initBookChapterControls ,
49 loadSelectedChapter ,
510 navigateFromURL ,
@@ -14,17 +19,6 @@ import {
1419 scrollToVerse ,
1520 setupFootnoteHandlers
1621} from './modules/passage.js'
17- import {
18- clearSearch ,
19- currentSearch ,
20- handlePDFUpload ,
21- navigateToSearchResult ,
22- renderPage ,
23- searchPDF ,
24- setupPDFCleanup ,
25- updateCustomPdfInfo ,
26- updatePDFZoom
27- } from './modules/pdf.js'
2822import {
2923 clearCache ,
3024 closeSettings ,
@@ -41,8 +35,7 @@ import {
4135 loadFromStorage ,
4236 saveToCookies ,
4337 saveToStorage ,
44- state ,
45- updateURL
38+ state
4639} from './modules/state.js'
4740import { closeStrongsPopup } from './modules/strongs.js'
4841import {
@@ -60,10 +53,6 @@ import {
6053 updateMarkdownPreview ,
6154 updateReferencePanel
6255} from './modules/ui.js'
63- if ( typeof pdfjsLib !== 'undefined' ) {
64- pdfjsLib . GlobalWorkerOptions . workerSrc =
65- 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js' ;
66- }
6756if ( typeof marked !== 'undefined' ) {
6857 marked . setOptions ( {
6958 breaks : true ,
@@ -117,20 +106,46 @@ function setupEventListeners() {
117106 . addEventListener ( 'click' , nextPassage ) ;
118107 document . getElementById ( 'randomPassageBtn' )
119108 . addEventListener ( 'click' , randomPassage ) ;
109+ const playBtn = document . querySelector ( '.play-audio-btn' ) ;
110+ const pauseBtn = document . querySelector ( '.pause-audio-btn' ) ;
111+ const stopBtn = document . querySelector ( '.stop-audio-btn' ) ;
112+ const narratorSelect = document . querySelector ( '.narrator-select' ) ;
113+ if ( playBtn ) {
114+ playBtn . addEventListener ( 'click' , ( ) => {
115+ if ( state . audioPlayer ?. isPaused ) {
116+ resumeChapterAudio ( ) ;
117+ } else if ( state . audioPlayer ?. isPlaying ) {
118+ pauseChapterAudio ( ) ;
119+ } else {
120+ const narrator = narratorSelect ?. value || state . settings . audioNarrator || 'gilbert' ;
121+ playChapterAudio ( narrator ) ;
122+ }
123+ } ) ;
124+ }
125+ if ( pauseBtn ) {
126+ pauseBtn . addEventListener ( 'click' , pauseChapterAudio ) ;
127+ }
128+ if ( stopBtn ) {
129+ stopBtn . addEventListener ( 'click' , stopChapterAudio ) ;
130+ }
131+ if ( narratorSelect ) {
132+ narratorSelect . addEventListener ( 'change' , ( e ) => {
133+ const newNarrator = e . target . value ;
134+ state . settings . audioNarrator = newNarrator ;
135+ saveToStorage ( ) ;
136+ if ( state . audioPlayer ) {
137+ stopChapterAudio ( ) ;
138+ }
139+ playChapterAudio ( newNarrator ) ;
140+ } ) ;
141+ }
120142 document . getElementById ( 'referencePanelToggle' )
121143 . addEventListener ( 'click' , toggleReferencePanel ) ;
122144 document . querySelectorAll ( '.sidebar-section-header' )
123145 . forEach ( h => h . addEventListener ( 'click' , ( ) => {
124146 const sec = h . dataset . section ;
125147 toggleSection ( sec ) ;
126148 } ) ) ;
127- document . getElementById ( 'referenceTranslation' ) . addEventListener ( 'change' , function ( ) {
128- const tempTranslation = this . value ;
129- const oldTranslation = state . settings . referenceVersion ;
130- state . settings . referenceVersion = tempTranslation ;
131- updateBibleGatewayVersion ( ) ;
132- state . settings . referenceVersion = oldTranslation ;
133- } ) ;
134149 document . addEventListener ( 'DOMContentLoaded' , makeToggleSticky ) ;
135150 document . querySelectorAll ( '.collapse-toggle' )
136151 . forEach ( btn => btn . addEventListener ( 'click' , function ( ) {
@@ -139,86 +154,18 @@ function setupEventListeners() {
139154 } ) ) ;
140155 document . getElementById ( 'referenceSource' )
141156 . addEventListener ( 'change' , updateReferencePanel ) ;
142- document . getElementById ( 'referenceTranslation' )
143- . addEventListener ( 'change' , updateReferencePanel ) ;
144- document . querySelector ( '.reference-panel-close' )
145- . addEventListener ( 'click' , toggleReferencePanel ) ;
146- document . getElementById ( 'prevPage' ) . addEventListener ( 'click' , async ( ) => {
147- if ( ! state . pdf . doc || state . pdf . currentPage <= 1 ) return ;
148- try {
149- if ( state . pdf . renderTask ) {
150- await state . pdf . renderTask . cancel ( ) ;
151- state . pdf . renderTask = null ;
152- }
153- state . pdf . currentPage -- ;
154- await renderPage ( state . pdf . currentPage ) ;
155- } catch ( err ) {
156- console . warn ( 'Error navigating to previous page:' , err ) ;
157- await loadPDF ( ) ;
158- }
159- } ) ;
160- document . getElementById ( 'nextPage' ) . addEventListener ( 'click' , async ( ) => {
161- if ( ! state . pdf . doc || state . pdf . currentPage >= state . pdf . doc . numPages ) return ;
162- try {
163- if ( state . pdf . renderTask ) {
164- await state . pdf . renderTask . cancel ( ) ;
165- state . pdf . renderTask = null ;
166- }
167- state . pdf . currentPage ++ ;
168- await renderPage ( state . pdf . currentPage ) ;
169- } catch ( err ) {
170- console . warn ( 'Error navigating to next page:' , err ) ;
171- await loadPDF ( ) ;
172- }
173- } ) ;
174- document . getElementById ( 'pageInput' ) . addEventListener ( 'change' , async ( ) => {
175- if ( ! state . pdf . doc ) {
176- document . getElementById ( 'pageInput' ) . value = state . pdf . currentPage ;
177- return ;
178- }
179- const inp = document . getElementById ( 'pageInput' ) ;
180- let p = parseInt ( inp . value , 10 ) ;
181- if ( Number . isNaN ( p ) ) {
182- inp . value = state . pdf . currentPage ;
183- return ;
184- }
185- p = Math . max ( 1 , Math . min ( p , state . pdf . doc . numPages ) ) ;
186- try {
187- state . pdf . currentPage = p ;
188- await renderPage ( p ) ;
189- } catch ( err ) {
190- console . warn ( 'Error navigating to page:' , err ) ;
191- inp . value = state . pdf . currentPage ;
192- await loadPDF ( ) ;
157+ document . getElementById ( 'referenceTranslation' ) . addEventListener ( 'change' , function ( ) {
158+ state . settings . referenceVersion = this . value ;
159+ updateBibleGatewayVersion ( ) ;
160+ saveToStorage ( ) ;
161+ const settingsDropdown = document . getElementById ( 'referenceVersionSetting' ) ;
162+ if ( settingsDropdown ) {
163+ settingsDropdown . value = this . value ;
193164 }
165+ updateReferencePanel ( ) ;
194166 } ) ;
195- document . getElementById ( 'zoomIn' ) . addEventListener ( 'click' , ( ) => {
196- if ( ! state . pdf . doc ) return ;
197- const newZoom = Math . min ( state . pdf . zoomLevel + 0.25 , 3.0 ) ;
198- updatePDFZoom ( newZoom ) ;
199- } ) ;
200- document . getElementById ( 'zoomOut' ) . addEventListener ( 'click' , ( ) => {
201- if ( ! state . pdf . doc ) return ;
202- const newZoom = Math . max ( state . pdf . zoomLevel - 0.25 , 0.5 ) ;
203- updatePDFZoom ( newZoom ) ;
204- } ) ;
205- document . getElementById ( 'pdfSearchBtn' ) . addEventListener ( 'click' , searchPDF ) ;
206- document . getElementById ( 'pdfSearchInput' ) . addEventListener ( 'keypress' , ( e ) => {
207- if ( e . key === 'Enter' ) searchPDF ( ) ;
208- } ) ;
209- document . getElementById ( 'clearSearchBtn' ) . addEventListener ( 'click' , clearSearch ) ;
210- const nextSearchBtn = document . getElementById ( 'nextSearchResult' ) ;
211- const prevSearchBtn = document . getElementById ( 'prevSearchResult' ) ;
212- if ( nextSearchBtn ) {
213- nextSearchBtn . addEventListener ( 'click' , ( ) => {
214- navigateToSearchResult ( currentSearch . currentResult + 1 ) ;
215- } ) ;
216- }
217- if ( prevSearchBtn ) {
218- prevSearchBtn . addEventListener ( 'click' , ( ) => {
219- navigateToSearchResult ( currentSearch . currentResult - 1 ) ;
220- } ) ;
221- }
167+ document . querySelector ( '.reference-panel-close' )
168+ . addEventListener ( 'click' , toggleReferencePanel ) ;
222169 document . getElementById ( 'notesInput' )
223170 . addEventListener ( 'input' , e => {
224171 state . notes = e . target . value ;
@@ -288,12 +235,6 @@ function setupEventListeners() {
288235 . addEventListener ( 'click' , clearCache ) ;
289236 document . getElementById ( 'deleteAllDataBtn' )
290237 . addEventListener ( 'click' , deleteAllData ) ;
291- document . getElementById ( 'settingsPdfUploadBtn' )
292- . addEventListener ( 'click' , ( ) => {
293- document . getElementById ( 'settingsPdfUpload' ) . click ( ) ;
294- } ) ;
295- document . getElementById ( 'settingsPdfUpload' )
296- . addEventListener ( 'change' , handlePDFUpload ) ;
297238 document . querySelectorAll ( '.color-theme-option' )
298239 . forEach ( opt => opt . addEventListener ( 'click' , ( ) => {
299240 const theme = opt . dataset . theme ;
@@ -316,34 +257,6 @@ function setupEventListeners() {
316257 }
317258 } ) ;
318259}
319- export function arrayBufferToBase64 ( buf ) {
320- let binary = '' ;
321- const bytes = new Uint8Array ( buf ) ;
322- const chunk = 0x8000 ;
323- for ( let i = 0 ; i < bytes . length ; i += chunk ) {
324- binary += String . fromCharCode . apply (
325- null ,
326- Array . from ( bytes . subarray ( i , i + chunk ) )
327- ) ;
328- }
329- return btoa ( binary ) ;
330- }
331- export function base64ToArrayBuffer ( b64 ) {
332- const bin = atob ( b64 ) ;
333- const arr = new Uint8Array ( bin . length ) ;
334- for ( let i = 0 ; i < bin . length ; i ++ ) {
335- arr [ i ] = bin . charCodeAt ( i ) ;
336- }
337- return arr . buffer ;
338- }
339- export function readFileAsArrayBuffer ( file ) {
340- return new Promise ( ( resolve , reject ) => {
341- const r = new FileReader ( ) ;
342- r . onload = e => resolve ( e . target . result ) ;
343- r . onerror = ( ) => reject ( new Error ( 'Failed to read file' ) ) ;
344- r . readAsArrayBuffer ( file ) ;
345- } ) ;
346- }
347260export function showLoading ( flag ) {
348261 document . getElementById ( 'loadingOverlay' ) . classList . toggle ( 'active' , flag ) ;
349262}
@@ -550,8 +463,6 @@ function navigateToHighlightedVerse(reference) {
550463 const [ , book , chapter , verse ] = match ;
551464 state . settings . manualBook = book ;
552465 state . settings . manualChapter = parseInt ( chapter ) ;
553- const translation = getCurrentTranslation ( ) ;
554- updateURL ( translation , book , chapter ) ;
555466 loadSelectedChapter ( book , chapter ) ;
556467 setTimeout ( ( ) => scrollToVerse ( verse ) , 500 ) ;
557468}
@@ -589,9 +500,9 @@ function refreshHighlightsModalTheme() {
589500 }
590501}
591502async function init ( ) {
503+ console . log ( 'Initializing app...' ) ;
592504 await loadFromStorage ( ) ;
593505 loadFromCookies ( ) ;
594- setupPDFCleanup ( ) ;
595506 const style = document . createElement ( 'style' ) ;
596507 style . textContent = offlineStyles ;
597508 document . head . appendChild ( style ) ;
@@ -608,27 +519,10 @@ async function init() {
608519 restorePanelStates ( ) ;
609520 updateDateTime ( ) ;
610521 initResizeHandles ( ) ;
611- updateCustomPdfInfo ( ) ;
612522 switchNotesView ( state . settings . notesView || 'text' ) ;
613523 updateBibleGatewayVersion ( ) ;
614524 setupEventListeners ( ) ;
615525 setInterval ( updateDateTime , 1_000 ) ;
616- const navigatedFromURL = navigateFromURL ( ) ;
617- if ( ! navigatedFromURL ) {
618- if ( window . location . pathname !== '/' ) {
619- const defaultParams = {
620- translation : 'BSB' ,
621- book : 'Genesis' ,
622- chapter : 1
623- } ;
624- window . history . replaceState (
625- defaultParams ,
626- '' ,
627- `?p=bsb/gen/1`
628- ) ;
629- loadPassage ( ) ;
630- }
631- }
632526 console . log ( 'App initialized successfully' ) ;
633527}
634528if ( document . readyState === 'loading' ) {
0 commit comments