Skip to content

Commit e63d8d7

Browse files
committed
Testing Bionic Test mode on Blogs
Still some bugs, but generally works Bionic Reading seems to help some Autistic & ADHD individuals to read faster
1 parent 3ca4052 commit e63d8d7

8 files changed

Lines changed: 289 additions & 13 deletions

File tree

docs/js/ProcStackGitio.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,16 @@ if( searchParams.has('scale') ){
179179

180180
// -- -- -- -- --
181181

182+
// I should add a "isMobile" callback on pxlNav boot, but for now -
183+
let isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( navigator.userAgent );
184+
185+
// -- -- -- -- --
186+
182187
// Create the main page manager
183188
// - Not related to pxlNav -
184189
const procPages = new ProcPageManager();
185190
procPages.setVersion( pxlNavVersion );
191+
procPages.setMobile( isMobile );
186192
// Set the Meta Data per page
187193
// Page changes will update the meta data automatically if the page is in the list
188194
//procPages.setPageMetaData( ProcPageMetaData );

docs/js/blog/blogEntryBase.js

Lines changed: 202 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,41 @@ export const baseEntryStruct = () =>{
2020
export 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&nbsp;</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&nbsp;</span>Typical';
318+
}else{
319+
buttonObj.innerHTML = '<span class="hideOnMobile">To&nbsp;</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 = /(&nbsp;|[</](br|div|span|p|)|(class.+>))/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 & &nbsp;
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();

docs/js/procPages/ProcPage.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export class ProcPage {
6464
* @param {Object} [contentObject.sections] - Section definitions
6565
*/
6666
constructor( contentObject ){
67+
this.isMobile = false;
6768
this.metaData = contentObject.metaData || {};
6869
this.visible = contentObject.hasOwnProperty('visible') ? contentObject.visible : true;
6970
this.id = contentObject.id || null;
@@ -170,6 +171,12 @@ export class ProcPage {
170171
}
171172

172173
// -- -- --
174+
175+
setMobile( isMobile ){
176+
this.isMobile = isMobile;
177+
}
178+
179+
// -- -- --
173180

174181
/**
175182
* Set page metadata
@@ -968,9 +975,10 @@ export class ProcPage {
968975
}
969976

970977
if( builtObjs['blog'] != null ){
971-
972978
this.sectionData[sectionName].blogManager = builtObjs['blog'];
973-
979+
builtObjs['blog'].blogEntries.forEach(( entry )=>{
980+
entry.setMobile( this.isMobile );
981+
});
974982
}
975983

976984
this.sectionData[sectionName].isLoaded = true;

docs/js/procPages/ProcPageManager.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export class ProcPageManager {
3737
*/
3838
constructor(originUrl) {
3939
this.originUrl = originUrl || window.location.origin;
40+
this.isMobile = false;
4041
this.mainDiv = null;
4142
this.curPage = null;
4243
this.curRoom = null;
@@ -206,6 +207,12 @@ export class ProcPageManager {
206207

207208
return depthPrefix;
208209
}
210+
211+
setMobile( isMobile ){
212+
this.isMobile = isMobile;
213+
}
214+
215+
// -- -- --
209216

210217
/**
211218
* @method init
@@ -622,6 +629,8 @@ export class ProcPageManager {
622629
if( !listingKeys.includes(pageKey) ){
623630
this.pageListing[pageKey] = Object.assign({}, this.defaultPageListing);
624631
}
632+
633+
pageData[pageKey].setMobile( this.isMobile );
625634

626635
this.pageListing[pageKey][ "pageData" ] = pageData[pageKey];
627636
if( pageData[pageKey].hasOwnProperty("metaData") ){

docs/pages/aiDev/aiNotes.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ export const pageListingData = {
5151
5252
<br>No LLMs here.
5353
<br>These are my own rambly-ass thoughts.
54+
55+
<br>
56+
<br>If you are Autistic or ADHD,
57+
<br>Try <span class="textName">Bionic Reading</span> mode; it may help you read faster.
5458
</div>
5559
5660
<br><br><br><div class='procPagesAIDevBar'></div>

0 commit comments

Comments
 (0)