@@ -20,17 +20,41 @@ export const baseEntryStruct = () =>{
2020export class blogEntry {
2121 constructor ( parent , entryData ) {
2222 this . id = null ;
23+ this . isMobile = false ;
2324 this . parent = parent ;
2425 //this.rawEntryData = entryData; // I have no need for it yet, but maybe
2526 this . title = entryData . title ;
2627 this . marked = entryData . marked || ENTRY_MARK_ENUM . NONE ;
2728 this . date = entryData . date ;
2829 this . body = entryData . body ;
2930 this . tags = entryData . tags ;
30-
31+
32+ // -- -- --
33+ // Bionic Reading Data & State
34+ // Neurodivergent Text Mode for Autism & ADHD
35+ // Bolded initial letters of words to allow the brain to fill in the rest of the word for easier reading.
36+ // https://bionic-reading.com/
37+
38+ this . autoBuildBionic = true ;
39+ this . bionicMode = false ;
40+ this . isBionicTextBuilding = false ;
41+
42+ this . bionicPercentConversion = .5 ; // Percent of the word to convert to bold
43+ this . bionicPercentConversion_desktop = .5 ;
44+ this . bionicPercentConversion_mobile = .35 ;
45+ this . bionicBuildWaitTime = 50 ; // MS Waittime between building chunks of bionic text
46+ this . bionicBuildRunMax = 10 ; // Number of lines of text to convert per wait time timeout into bionic text, avoids thread locking the browser on long entries.
47+ this . body_bionic_toProcess = entryData . body . split ( '\n' ) ; // To Convert; Unprocessed body -> bionic conversion
48+ this . body_bionic = null ; // Built on demand
49+ this . body_typical = entryData . body ;
50+ this . bionicTimeout = null ;
51+
52+ // -- -- --
53+
3154 this . readTimes = null ;
3255
3356 this . blogEntryObj = null ;
57+ this . accessibilityObj = null ;
3458 this . titleObj = null ;
3559 this . dateObj = null ;
3660 this . bodyObj = null ;
@@ -51,6 +75,27 @@ export class blogEntry{
5175 setParent ( parent ) {
5276 this . parent = parent ;
5377 }
78+ setMobile ( isMobile ) {
79+ this . isMobile = ! ! isMobile ;
80+ if ( this . isMobile ) {
81+ this . bionicPercentConversion = this . bionicPercentConversion_mobile ;
82+ } else {
83+ this . bionicPercentConversion = this . bionicPercentConversion_desktop ;
84+ }
85+
86+ // Re-trigger Bionic Text Building from scratch
87+ // TODO : I should pass bionic build through the pageManager, but for now, I'm just re-running it.
88+ if ( this . isBionicTextBuilding ) {
89+ clearTimeout ( this . bionicTimeout ) ;
90+ this . isBionicTextBuilding = false ;
91+ this . body_bionic = null ;
92+ this . body_bionic_toProcess = this . body . split ( '\n' ) ;
93+ this . buildBionicBody ( ) ;
94+ }
95+ }
96+
97+ // -- -- --
98+
5499 build ( parent = null ) {
55100 let parentObj = parent ;
56101 if ( parentObj == null ) {
@@ -100,7 +145,7 @@ export class blogEntry{
100145 // Accessibility Buttons; Font Size +/- for now
101146 let plusBtn = document . createElement ( 'button' ) ;
102147 plusBtn . classList . add ( 'blogEntryAccessibilityButtonStyle' ) ;
103- plusBtn . classList . add ( 'procPagesNavSectionStyle ' ) ;
148+ plusBtn . classList . add ( 'accessibilitySectionStyle ' ) ;
104149 plusBtn . classList . add ( 'procPagesButtonStyle' ) ;
105150 plusBtn . classList . add ( 'procPagesSectionNavColor' ) ;
106151 //procPagesNavSectionStyle procPagesButtonStyle procPagesSectionNavColor aiDevPage-sectionNavButtonStyle
@@ -110,14 +155,34 @@ export class blogEntry{
110155 plusBtn . addEventListener ( 'click' , ( e ) => { this . resizeText ( .2 ) ; } ) ;
111156 let minusBtn = document . createElement ( 'button' ) ;
112157 minusBtn . classList . add ( 'blogEntryAccessibilityButtonStyle' ) ;
113- minusBtn . classList . add ( 'procPagesNavSectionStyle ' ) ;
158+ minusBtn . classList . add ( 'accessibilitySectionStyle ' ) ;
114159 minusBtn . classList . add ( 'procPagesButtonStyle' ) ;
115160 minusBtn . classList . add ( 'procPagesSectionNavColor' ) ;
116161 minusBtn . innerHTML = '-' ;
117162 minusBtn . title = 'Decrease Font Size' ;
118163 this . accessibilityObj . appendChild ( minusBtn ) ;
119164 minusBtn . addEventListener ( 'click' , ( e ) => { this . resizeText ( - .2 ) ; } ) ;
165+
166+ // Bionic Reading Toggle
167+ // Neurodivergent Text Mode for Autism & ADHD
168+ // Bolded initial letters of words to allow the brain to fill in the rest of the word for easier reading.
169+ // https://bionic-reading.com/
170+ let bionicButton = document . createElement ( 'button' ) ;
171+ bionicButton . classList . add ( 'blogEntryAccessibilityButtonStyle' ) ;
172+ bionicButton . classList . add ( 'accessibilitySectionStyle' ) ;
173+ bionicButton . classList . add ( 'procPagesButtonStyle' ) ;
174+ bionicButton . classList . add ( 'procPagesSectionNavColor' ) ;
175+ bionicButton . classList . add ( 'bionicToggleButtonStyle' ) ;
176+ bionicButton . innerHTML = '<span class="hideOnMobile">To </span>Bionic' ;
177+ bionicButton . title = 'Toggle Bionic Reading' ;
178+ this . accessibilityObj . appendChild ( bionicButton ) ;
179+ bionicButton . addEventListener ( 'click' , ( e ) => { this . toggleBionicReading ( bionicButton ) ; } ) ;
180+
181+
120182 // -- -- --
183+
184+ // Build title row
185+
121186 this . titleRowObj . appendChild ( this . titleObj ) ;
122187 this . titleRowObj . appendChild ( this . dateObj ) ;
123188 this . titleRowObj . appendChild ( this . readTimeBodyObj ) ;
@@ -163,8 +228,18 @@ export class blogEntry{
163228 this . blogEntryObj . appendChild ( this . commentObj ) ;
164229
165230 parentObj . appendChild ( this . blogEntryObj ) ;
231+
232+
233+ // -- -- --
234+
235+ // Initialize Bionic Text Conversion
236+ if ( this . autoBuildBionic ) {
237+ this . buildBionicBody ( ) ;
238+ }
166239 }
167240
241+ // -- -- --
242+
168243 getReadTimes ( text ) {
169244 // Average is 200-250 words per minute,
170245 // But I was a slow reader when I was younger.
@@ -205,6 +280,8 @@ export class blogEntry{
205280 }
206281 return retVal ;
207282 }
283+
284+ // -- -- --
208285
209286 resizeText ( dir ) {
210287 let currentSize = this . bodyObj . style . fontSize ;
@@ -213,6 +290,128 @@ export class blogEntry{
213290 this . bodyObj . style . fontSize = toSize + 'em' ;
214291 }
215292
293+ // -- -- --
294+
295+ toggleBionicReading ( buttonObj = null ) {
296+
297+ let isBuilding = this . isBionicTextBuilding ;
298+ if ( this . isBionicTextBuilding ) {
299+ if ( this . bionicTimeout ) {
300+ clearTimeout ( this . bionicTimeout ) ;
301+ }
302+ this . isBionicTextBuilding = false ;
303+ }
304+
305+ this . bionicMode = ! this . bionicMode ;
306+
307+ // End processing and process the rest of the toProcess bionic body text
308+ if ( this . bionicMode && this . verifyBionicBuilt ( ) ) {
309+ this . bodyObj . innerHTML = this . body_bionic ;
310+ } else {
311+ this . bodyObj . innerHTML = this . body_typical ;
312+ }
313+
314+ // Update button text
315+ if ( buttonObj ) {
316+ if ( this . bionicMode ) {
317+ buttonObj . innerHTML = '<span class="hideOnMobile">To </span>Typical' ;
318+ } else {
319+ buttonObj . innerHTML = '<span class="hideOnMobile">To </span>Bionic' ;
320+ }
321+ }
322+ }
323+
324+ // Process line chunks of the body text into bionic text,
325+ // Building up `this.body_bionic` until all lines are processed.
326+ buildBionicBody ( ) {
327+ this . isBionicTextBuilding = true ;
328+
329+ let selectedLines = this . body_bionic_toProcess . splice ( 0 , this . bionicBuildRunMax ) ;
330+ this . processBionicLines ( selectedLines ) ;
331+ if ( this . body_bionic_toProcess . length > 0 ) {
332+ this . bionicTimeout = setTimeout ( ( ) => { this . buildBionicBody ( ) ; } , this . bionicBuildWaitTime ) ;
333+ } else {
334+ this . isBionicTextBuilding = false ;
335+ this . body_bionic_toProcess = null ;
336+ this . bionicTimeout = null ;
337+ }
338+ }
339+
340+ // Process a provided array of lines into bionic text
341+ // This will process all lines if the full `this.body_bionic_toProcess` is provided
342+ processBionicLines ( lines ) {
343+ let keepMatch = / ( & n b s p ; | [ < / ] ( b r | d i v | s p a n | p | ) | ( c l a s s .+ > ) ) / g;
344+ if ( lines . length === 0 ) {
345+ this . isBionicTextBuilding = false ;
346+ return ;
347+ }
348+ let toProcess = lines . splice ( 0 , this . bionicBuildRunMax ) ;
349+ toProcess . forEach ( ( line ) => {
350+ let textBreaks = line . split ( ' ' ) ;
351+ let convertedLine = textBreaks . map ( word => {
352+ // Find and return HTML tags &
353+ let hasMatch = word . match ( keepMatch ) ;
354+ if ( hasMatch != null && hasMatch . length > 0 ) {
355+ return word ;
356+ }
357+
358+ // Find dashes in word
359+ let hyph = word . split ( '-' ) ;
360+ if ( hyph . length > 1 ) {
361+ return hyph . map ( part => this . convertToBionic ( part ) ) . join ( '-' ) ;
362+ }
363+
364+ hyph = word . split ( '+' ) ;
365+ if ( hyph . length > 1 ) {
366+ return hyph . map ( part => this . convertToBionic ( part ) ) . join ( '+' ) ;
367+ }
368+
369+ // Convert word to bionic
370+ return this . convertToBionic ( word ) ;
371+ } ) . join ( ' ' ) ;
372+ if ( this . body_bionic == null ) {
373+ this . body_bionic = convertedLine ;
374+ } else {
375+ this . body_bionic += '\n' + convertedLine ;
376+ }
377+ } ) ;
378+ }
379+
380+ // Verify if the body needs to be fully processed in one go
381+ // The user clicked the Bionic button before processing finished
382+ verifyBionicBuilt ( ) {
383+ if ( this . body_bionic_toProcess != null && this . body_bionic_toProcess . length > 0 ) {
384+ clearTimeout ( this . bionicTimeout ) ;
385+ this . processBionicLines ( this . body_bionic_toProcess ) ;
386+ this . body_bionic_toProcess = null ;
387+ this . isBionicTextBuilding = false ;
388+ }
389+ return true ;
390+ }
391+
392+ // Bolden the first X% of the word, minimum 1 letter
393+ // Percentage set in `this.bionicPercentConversion`
394+ convertToBionic ( text ) {
395+ if ( text . trim ( ) . length === 0 ) {
396+ return text ;
397+ }
398+ let matchReg = / (? ! .* [ < > ] ) ( [ \d \D ] ) / g;
399+ let matchOnce = text . match ( matchReg ) ;
400+ if ( matchOnce == null ) {
401+ return text ;
402+ }
403+
404+ let stringRun = Math . ceil ( text . length * this . bionicPercentConversion ) ;
405+ stringRun = Math . max ( stringRun , 1 ) ;
406+
407+ let retVal = "" ;
408+ retVal += `<span class="textBold">${ text . substring ( 0 , stringRun ) } </span>` ;
409+ retVal += text . substring ( stringRun ) ;
410+ return retVal ;
411+ }
412+
413+ // -- -- --
414+
216415 show ( ) {
217416 this . blogEntryObj . style . display = 'block' ;
218417 this . updateURL ( ) ;
0 commit comments