@@ -35,6 +35,61 @@ interface textMarkup extends JQueryStatic {
3535window . addEventListener ( "message" , processDLRMessage , false ) ;
3636
3737let readerToolsInitialized : boolean = false ;
38+ let lastReaderToolSettingsContent : string | undefined ;
39+ const maxReaderSettingsLoadAttempts = 5 ;
40+
41+ // I'm not sure how copilot came to add this normalization. It claims that it is
42+ // useful defensiveness against some uncertainty about whether Axios will return
43+ // a string or an object.
44+ function normalizeReaderSettings ( rawSettings : unknown ) : ReaderSettings {
45+ if ( typeof rawSettings === "string" ) {
46+ return JSON . parse ( rawSettings ) as ReaderSettings ;
47+ }
48+ return rawSettings as ReaderSettings ;
49+ }
50+
51+ function tryNormalizeReaderSettings (
52+ rawSettings : unknown ,
53+ ) : ReaderSettings | undefined {
54+ try {
55+ const settings = normalizeReaderSettings ( rawSettings ) ;
56+ if ( ! settings ) {
57+ return undefined ;
58+ }
59+ return settings ;
60+ } catch {
61+ return undefined ;
62+ }
63+ }
64+
65+ function loadReaderSettingsWithRetry (
66+ attemptsRemaining : number ,
67+ onLoaded : ( settings : ReaderSettings ) => void ,
68+ onFailed : ( ) => void ,
69+ ) : void {
70+ get ( "readers/io/readerToolSettings" , ( settingsFileContent ) => {
71+ const normalizedSettings = tryNormalizeReaderSettings (
72+ settingsFileContent . data ,
73+ ) ;
74+ if ( normalizedSettings ) {
75+ onLoaded ( normalizedSettings ) ;
76+ return ;
77+ }
78+
79+ if ( attemptsRemaining > 1 ) {
80+ window . setTimeout ( ( ) => {
81+ loadReaderSettingsWithRetry (
82+ attemptsRemaining - 1 ,
83+ onLoaded ,
84+ onFailed ,
85+ ) ;
86+ } , 150 ) ;
87+ return ;
88+ }
89+
90+ onFailed ( ) ;
91+ } ) ;
92+ }
3893
3994function getSetupDialogWindow ( ) : Window | null {
4095 return ( < HTMLIFrameElement > (
@@ -226,18 +281,50 @@ export function beginInitializeLeveledReaderTool(): JQueryPromise<void> {
226281export function beginLoadSynphonySettings ( ) : JQueryPromise < void > {
227282 // make sure synphony is initialized
228283 const result = $ . Deferred < void > ( ) ;
284+ get ( "collection/defaultFont" , ( result ) => setDefaultFont ( result . data ) ) ;
229285 if ( readerToolsInitialized ) {
230- result . resolve ( ) ;
286+ // If we already initialized the reader tools, we still need to read the current data,
287+ // since now that we're using a single browser window for the whole workspace,
288+ // we could change books without reloading the window, and there is some dependence
289+ // of the data on the current book. So we read it one more time, and do some cleanup
290+ // if it is different from what we had before.
291+ loadReaderSettingsWithRetry (
292+ maxReaderSettingsLoadAttempts ,
293+ ( normalizedSettings ) => {
294+ const newSettingsContent = JSON . stringify ( normalizedSettings ) ;
295+ const shouldRefresh =
296+ newSettingsContent !== lastReaderToolSettingsContent ;
297+ if ( ! shouldRefresh ) {
298+ result . resolve ( ) ;
299+ return ;
300+ }
301+ beginRefreshEverything ( normalizedSettings ) . then ( ( ) => {
302+ lastReaderToolSettingsContent = newSettingsContent ;
303+ result . resolve ( ) ;
304+ } ) ;
305+ } ,
306+ ( ) => {
307+ readerToolsInitialized = false ;
308+ result . resolve ( ) ;
309+ } ,
310+ ) ;
231311 return result ;
232312 }
233313 readerToolsInitialized = true ;
234314
235- get ( "collection/defaultFont" , ( result ) => setDefaultFont ( result . data ) ) ;
236- get ( "readers/io/readerToolSettings" , ( settingsFileContent ) => {
237- initializeSynphony ( settingsFileContent . data ) ;
238- //console.log("done synphony init");
239- result . resolve ( ) ;
240- } ) ;
315+ loadReaderSettingsWithRetry (
316+ maxReaderSettingsLoadAttempts ,
317+ ( normalizedSettings ) => {
318+ lastReaderToolSettingsContent = JSON . stringify ( normalizedSettings ) ;
319+ initializeSynphony ( normalizedSettings ) ;
320+ //console.log("done synphony init");
321+ result . resolve ( ) ;
322+ } ,
323+ ( ) => {
324+ readerToolsInitialized = false ;
325+ result . resolve ( ) ;
326+ } ,
327+ ) ;
241328 return result ;
242329}
243330
@@ -248,7 +335,9 @@ export function beginLoadSynphonySettings(): JQueryPromise<void> {
248335 * @param settingsFileContent The content of the standard JSON) file that stores the Synphony settings for the collection.
249336 * @global {getTheOneReaderToolsModel()) ReaderToolsModel
250337 */
251- function initializeSynphony ( settingsFileContent : string ) : void {
338+ function initializeSynphony (
339+ settingsFileContent : ReaderSettings | string ,
340+ ) : void {
252341 const synphony = new ReadersSynphonyWrapper ( ) ;
253342 synphony . loadSettings ( settingsFileContent ) ;
254343 getTheOneReaderToolsModel ( ) . setSynphony ( synphony ) ;
@@ -460,6 +549,16 @@ export function resizeWordList(startTimeout: boolean = true): void {
460549 if ( div . length === 0 ) return ; // if not found, the tool was closed
461550
462551 const wordList : JQuery = div . find ( "#wordList" ) ;
552+ const wordListParent = wordList . parent ( ) ;
553+ const wordListParentElement = wordListParent . get ( 0 ) ;
554+ if (
555+ ! wordListParentElement ||
556+ ! wordListParentElement . isConnected ||
557+ ! wordListParentElement . ownerDocument ?. defaultView
558+ ) {
559+ return ;
560+ }
561+
463562 const currentHeight : number = div . height ( ) ;
464563 const currentWidth : number = wordList . width ( ) ;
465564
@@ -477,7 +576,12 @@ export function resizeWordList(startTimeout: boolean = true): void {
477576 readerToolsModel . previousHeight = currentHeight ;
478577 readerToolsModel . previousWidth = currentWidth ;
479578
480- const top = wordList . parent ( ) . position ( ) . top ;
579+ const parentPosition = wordListParent . position ( ) ;
580+ if ( ! parentPosition ) {
581+ return ;
582+ }
583+
584+ const top = parentPosition . top ;
481585
482586 const synphony = readerToolsModel . synphony ;
483587 if ( synphony . source ) {
@@ -504,7 +608,7 @@ export function resizeWordList(startTimeout: boolean = true): void {
504608
505609 if ( ht < 50 ) ht = 50 ;
506610
507- wordList . parent ( ) . css ( "height" , Math . floor ( ht ) + "px" ) ;
611+ wordListParent . css ( "height" , Math . floor ( ht ) + "px" ) ;
508612 }
509613 }
510614
@@ -515,13 +619,19 @@ export function resizeWordList(startTimeout: boolean = true): void {
515619}
516620
517621export function createToggle ( isForLeveled : boolean ) {
622+ const container = document . getElementById (
623+ `${ isForLeveled ? "leveled" : "decodable" } -reader-tool-toggle-react-container` ,
624+ ) ;
625+ if ( ! container ) {
626+ return ;
627+ }
628+
629+ // ReaderToolSwitch uses defaultChecked. Remount so it picks up current page
630+ // reader classes whenever we switch books/pages and reactivate the tool.
631+ ReactDOM . unmountComponentAtNode ( container ) ;
518632 ReactDOM . render (
519633 React . createElement ( ReaderToolSwitch , { isForLeveled } ) ,
520- document . getElementById (
521- `${
522- isForLeveled ? "leveled" : "decodable"
523- } -reader-tool-toggle-react-container`,
524- ) ,
634+ container ,
525635 ) ;
526636}
527637
0 commit comments