Skip to content

Commit 896e7b4

Browse files
committed
Fixed UI bug where book and chapter were not
updating along with the content when selecting a book and chapter from the dropdowns. Modified how the highlight popup shows verses (now ordered by book chronology). Fixed UI bug where state for highlighted filter was not updating (stuck on active). Added proper back/forward browser history navigation. Added logic to hide footnote container in Verse Analysis/Strong's popup when no footnotes are available.
1 parent 3c7bd24 commit 896e7b4

10 files changed

Lines changed: 227 additions & 114 deletions

File tree

main.js

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,12 @@ function showHighlightsModal() {
440440
overlay.classList.add('active');
441441
modal.classList.add('active');
442442
document.body.style.overflow = 'hidden';
443+
const filterButtons = document.querySelectorAll('.highlight-filter-btn');
444+
filterButtons.forEach(btn => btn.classList.remove('active'));
445+
const allButton = document.querySelector('.highlight-filter-btn[data-color="all"]');
446+
if (allButton) {
447+
allButton.classList.add('active');
448+
}
443449
renderHighlights('all');
444450
document.querySelectorAll('.highlight-filter-btn').forEach(btn => {
445451
btn.addEventListener('click', function() {
@@ -464,33 +470,62 @@ function renderHighlights(filterColor = 'all') {
464470
return;
465471
}
466472
let html = '';
467-
const versesByColor = {};
468-
Object.entries(highlights).forEach(([reference, color]) => {
469-
if (!versesByColor[color]) versesByColor[color] = [];
470-
versesByColor[color].push(reference);
471-
});
472-
Object.keys(versesByColor).forEach(color => {
473-
versesByColor[color].sort((a, b) => {
474-
const [bookA, chapA, verseA] = a.split(/[ :]/);
475-
const [bookB, chapB, verseB] = b.split(/[ :]/);
476-
const bookOrderA = BOOK_ORDER.indexOf(bookA);
477-
const bookOrderB = BOOK_ORDER.indexOf(bookB);
478-
if (bookOrderA !== bookOrderB) return bookOrderA - bookOrderB;
479-
if (parseInt(chapA) !== parseInt(chapB)) return parseInt(chapA) - parseInt(chapB);
480-
return parseInt(verseA) - parseInt(verseB);
473+
const sortableReferences = Object.keys(highlights).map(reference => {
474+
const match = reference.match(/^(\d*\s*\w+)\s+(\d+):(\d+)$/);
475+
if (!match) return null;
476+
let bookName = match[1].trim();
477+
const chapter = parseInt(match[2]);
478+
const verse = parseInt(match[3]);
479+
const color = highlights[reference];
480+
const bookParts = bookName.split(' ');
481+
let baseBookName = bookName;
482+
let bookNumber = '';
483+
if (bookParts.length > 1 && /^\d+$/.test(bookParts[0])) {
484+
bookNumber = bookParts[0];
485+
baseBookName = bookParts.slice(1).join(' ');
486+
}
487+
const bookIndex = BOOK_ORDER.findIndex(book => {
488+
const orderParts = book.split(' ');
489+
let orderBaseName = book;
490+
let orderNumber = '';
491+
if (orderParts.length > 1 && /^\d+$/.test(orderParts[0])) {
492+
orderNumber = orderParts[0];
493+
orderBaseName = orderParts.slice(1).join(' ');
494+
}
495+
return orderBaseName.toLowerCase() === baseBookName.toLowerCase() &&
496+
orderNumber === bookNumber;
481497
});
498+
return {
499+
reference,
500+
bookName,
501+
baseBookName,
502+
bookNumber,
503+
bookIndex,
504+
chapter,
505+
verse,
506+
color
507+
};
508+
}).filter(ref => ref !== null && ref.bookIndex !== -1);
509+
sortableReferences.sort((a, b) => {
510+
if (a.bookIndex !== b.bookIndex) {
511+
return a.bookIndex - b.bookIndex;
512+
}
513+
if (a.chapter !== b.chapter) {
514+
return a.chapter - b.chapter;
515+
}
516+
return a.verse - b.verse;
482517
});
483-
Object.entries(versesByColor).forEach(([color, references]) => {
484-
if (filterColor !== 'all' && filterColor !== color) return;
485-
references.forEach(reference => {
486-
const verseText = getVerseTextFromStorage(reference) || 'Verse text not available';
487-
html += `
488-
<div class="highlight-item ${color}" data-reference="${reference}" data-color="${color}">
489-
<div class="highlight-ref">${reference}</div>
490-
<div class="highlight-text">${verseText}</div>
491-
</div>
492-
`;
493-
});
518+
sortableReferences.forEach(ref => {
519+
if (filterColor !== 'all' && ref.color !== filterColor) {
520+
return;
521+
}
522+
const verseText = getVerseTextFromStorage(ref.reference) || 'Verse text not available';
523+
html += `
524+
<div class="highlight-item ${ref.color}" data-reference="${ref.reference}" data-color="${ref.color}">
525+
<div class="highlight-ref">${ref.reference}</div>
526+
<div class="highlight-text">${verseText}</div>
527+
</div>
528+
`;
494529
});
495530
highlightsList.innerHTML = html || '<div class="no-highlights">No highlights match the selected filter</div>';
496531
document.querySelectorAll('.highlight-item').forEach(item => {
@@ -581,6 +616,16 @@ async function init() {
581616
const navigatedFromURL = navigateFromURL();
582617
if (!navigatedFromURL) {
583618
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+
);
584629
loadPassage();
585630
}
586631
}

modules/navigation.js

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
} from '../main.js'
1212
import {
1313
displayPassage,
14-
extractVerseText
14+
extractVerseText,
15+
updateDisplayRef
1516
} from './passage.js'
1617
import {
1718
AVAILABLE_TRANSLATIONS,
@@ -52,6 +53,7 @@ export async function loadSelectedChapter(book = null, chapter = null) {
5253
const selChapter = chapter || document.getElementById('chapterSelect').value;
5354
const apiBook = getApiBookCode(selBook);
5455
document.title = `${selBook} ${selChapter} - Provinent Scripture Study`;
56+
updateDisplayRef(selBook, selChapter);
5557
try {
5658
showLoading(true);
5759
const apiTranslation = apiTranslationCode(state.settings.bibleTranslation);
@@ -219,15 +221,6 @@ export function getCurrentTranslation() {
219221
}
220222
export function navigateFromURL() {
221223
const urlParams = parseURL();
222-
if (!urlParams && !window.location.search) {
223-
const defaultParams = {
224-
translation: 'BSB',
225-
book: 'Genesis',
226-
chapter: 1
227-
};
228-
updateURL(defaultParams.translation, defaultParams.book, defaultParams.chapter);
229-
return loadDefaultPassage(defaultParams);
230-
}
231224
if (urlParams) {
232225
const isValidTranslation = AVAILABLE_TRANSLATIONS.includes(urlParams.translation);
233226
const bookAbbr = BOOK_NAME_TO_ABBREVIATION[urlParams.book];
@@ -254,6 +247,11 @@ export function navigateFromURL() {
254247
headerTitleEl.textContent = `Holy Bible: ${urlParams.translation}`;
255248
}
256249
loadSelectedChapter(urlParams.book, urlParams.chapter);
250+
window.history.replaceState(
251+
{ translation: urlParams.translation, book: urlParams.book, chapter: urlParams.chapter },
252+
'',
253+
window.location.search
254+
);
257255
return true;
258256
}
259257
}
@@ -283,7 +281,24 @@ function loadDefaultPassage(params) {
283281
return true;
284282
}
285283
export function setupPopStateListener() {
286-
window.addEventListener('popstate', navigateFromURL);
284+
window.addEventListener('popstate', (event) => {
285+
if (event.state) {
286+
const { translation, book, chapter } = event.state;
287+
state.settings.manualBook = book;
288+
state.settings.manualChapter = chapter;
289+
state.settings.bibleTranslation = translation;
290+
const bookSelect = document.getElementById('bookSelect');
291+
const chapterSelect = document.getElementById('chapterSelect');
292+
if (bookSelect) bookSelect.value = book;
293+
if (chapterSelect) {
294+
populateChapterDropdown(book);
295+
chapterSelect.value = chapter;
296+
}
297+
loadSelectedChapter(book, chapter);
298+
} else {
299+
navigateFromURL();
300+
}
301+
});
287302
}
288303
export function setupNavigationWithURL() {
289304
document.getElementById('bookSelect').addEventListener('change', (e) => {

modules/passage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ export function scrollToVerse(verseNumber) {
287287
}, 1000);
288288
}
289289
}
290-
function updateDisplayRef(book, chapter) {
290+
export function updateDisplayRef(book, chapter) {
291291
const displayRef = `${book} ${chapter}`;
292292
document.getElementById('passageReference').textContent = displayRef;
293293
state.currentPassageReference = displayRef;

modules/state.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { handleError } from '../main.js'
22
import { loadPDFFromIndexedDB } from './pdf.js'
3-
export const APP_VERSION = '1.1.06.2025.11.07';
3+
export const APP_VERSION = '1.1.07.2025.11.07';
44
let saveTimeout = null;
55
const SAVE_DEBOUNCE_MS = 500;
66
export const BOOK_ORDER = [
@@ -305,9 +305,8 @@ export function updateURL(translation, book, chapter) {
305305
const cleanBook = bookAbbr.toLowerCase();
306306
const cleanChapter = Math.max(1, parseInt(chapter) || 1);
307307
const newQuery = `?p=${cleanTranslation}/${cleanBook}/${cleanChapter}`;
308-
if (window.location.search !== newQuery) {
309-
window.history.replaceState({}, '', newQuery);
310-
}
308+
const newState = { translation, book, chapter };
309+
window.history.pushState(newState, '', newQuery);
311310
}
312311
export function parseURL() {
313312
const urlParams = new URLSearchParams(window.location.search);

modules/strongs.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ export function showStrongsReference(verseEl) {
4949
<div class="verse-text-display">
5050
${verseText}
5151
</div>
52-
<!-- Footnotes section for Strong's popup -->
53-
<div class="strongs-footnotes-container" id="strongsFootnotesContainer"></div>
52+
<!-- Footnotes section for Strong's popup - will be hidden if empty -->
53+
<div class="strongs-footnotes-container" id="strongsFootnotesContainer" style="display: none;"></div>
5454
<div class="embedded-resources">
5555
<div class="resource-frame">
5656
<div class="resource-frame-header">
@@ -178,9 +178,10 @@ function populateStrongsFootnotes(verseRef) {
178178
container.innerHTML = '';
179179
const verseFootnotes = state.footnotes[verseRef];
180180
if (!verseFootnotes || verseFootnotes.length === 0) {
181-
container.innerHTML = '<p style="opacity:0.7;text-align:center;padding:20px;">No footnotes available for this verse</p>';
181+
container.style.display = 'none';
182182
return;
183183
}
184+
container.style.display = 'block';
184185
container.innerHTML = `
185186
<hr class="footnotes-separator">
186187
<h4 class="footnotes-heading">Footnotes</h4>
@@ -194,7 +195,6 @@ function populateStrongsFootnotes(verseRef) {
194195
`;
195196
container.appendChild(footnoteDiv);
196197
});
197-
container.style.display = 'block';
198198
}
199199
function setupStrongsFootnoteHandlers() {
200200
document.querySelectorAll('#strongsFootnotesContainer .footnote-ref').forEach(ref => {

src/main.js

Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,16 @@ function showHighlightsModal() {
620620
modal.classList.add('active');
621621
document.body.style.overflow = 'hidden';
622622

623+
const filterButtons = document.querySelectorAll('.highlight-filter-btn');
624+
filterButtons.forEach(btn => btn.classList.remove('active'));
625+
626+
const allButton = document.querySelector('.highlight-filter-btn[data-color="all"]');
627+
if (allButton) {
628+
allButton.classList.add('active');
629+
}
630+
623631
renderHighlights('all');
624632

625-
// Add filter button listeners
626633
document.querySelectorAll('.highlight-filter-btn').forEach(btn => {
627634
btn.addEventListener('click', function() {
628635
document.querySelectorAll('.highlight-filter-btn').forEach(b => b.classList.remove('active'));
@@ -653,48 +660,77 @@ function renderHighlights(filterColor = 'all') {
653660
}
654661

655662
let html = '';
656-
const versesByColor = {};
657-
658-
// Group verses by color
659-
Object.entries(highlights).forEach(([reference, color]) => {
660-
if (!versesByColor[color]) versesByColor[color] = [];
661-
versesByColor[color].push(reference);
662-
});
663663

664-
// Sort verses within each color group
665-
Object.keys(versesByColor).forEach(color => {
666-
versesByColor[color].sort((a, b) => {
667-
// Sort by book, chapter, verse
668-
const [bookA, chapA, verseA] = a.split(/[ :]/);
669-
const [bookB, chapB, verseB] = b.split(/[ :]/);
664+
const sortableReferences = Object.keys(highlights).map(reference => {
665+
const match = reference.match(/^(\d*\s*\w+)\s+(\d+):(\d+)$/);
666+
if (!match) return null;
667+
668+
let bookName = match[1].trim();
669+
const chapter = parseInt(match[2]);
670+
const verse = parseInt(match[3]);
671+
const color = highlights[reference];
672+
673+
const bookParts = bookName.split(' ');
674+
let baseBookName = bookName;
675+
let bookNumber = '';
676+
677+
if (bookParts.length > 1 && /^\d+$/.test(bookParts[0])) {
678+
bookNumber = bookParts[0];
679+
baseBookName = bookParts.slice(1).join(' ');
680+
}
681+
682+
const bookIndex = BOOK_ORDER.findIndex(book => {
683+
const orderParts = book.split(' ');
684+
let orderBaseName = book;
685+
let orderNumber = '';
670686

671-
const bookOrderA = BOOK_ORDER.indexOf(bookA);
672-
const bookOrderB = BOOK_ORDER.indexOf(bookB);
687+
if (orderParts.length > 1 && /^\d+$/.test(orderParts[0])) {
688+
orderNumber = orderParts[0];
689+
orderBaseName = orderParts.slice(1).join(' ');
690+
}
673691

674-
if (bookOrderA !== bookOrderB) return bookOrderA - bookOrderB;
675-
if (parseInt(chapA) !== parseInt(chapB)) return parseInt(chapA) - parseInt(chapB);
676-
return parseInt(verseA) - parseInt(verseB);
692+
return orderBaseName.toLowerCase() === baseBookName.toLowerCase() &&
693+
orderNumber === bookNumber;
677694
});
695+
696+
return {
697+
reference,
698+
bookName,
699+
baseBookName,
700+
bookNumber,
701+
bookIndex,
702+
chapter,
703+
verse,
704+
color
705+
};
706+
}).filter(ref => ref !== null && ref.bookIndex !== -1);
707+
708+
sortableReferences.sort((a, b) => {
709+
if (a.bookIndex !== b.bookIndex) {
710+
return a.bookIndex - b.bookIndex;
711+
}
712+
if (a.chapter !== b.chapter) {
713+
return a.chapter - b.chapter;
714+
}
715+
return a.verse - b.verse;
678716
});
679717

680-
// Render verses
681-
Object.entries(versesByColor).forEach(([color, references]) => {
682-
if (filterColor !== 'all' && filterColor !== color) return;
718+
sortableReferences.forEach(ref => {
719+
if (filterColor !== 'all' && ref.color !== filterColor) {
720+
return;
721+
}
683722

684-
references.forEach(reference => {
685-
const verseText = getVerseTextFromStorage(reference) || 'Verse text not available';
686-
html += `
687-
<div class="highlight-item ${color}" data-reference="${reference}" data-color="${color}">
688-
<div class="highlight-ref">${reference}</div>
689-
<div class="highlight-text">${verseText}</div>
690-
</div>
691-
`;
692-
});
723+
const verseText = getVerseTextFromStorage(ref.reference) || 'Verse text not available';
724+
html += `
725+
<div class="highlight-item ${ref.color}" data-reference="${ref.reference}" data-color="${ref.color}">
726+
<div class="highlight-ref">${ref.reference}</div>
727+
<div class="highlight-text">${verseText}</div>
728+
</div>
729+
`;
693730
});
694731

695732
highlightsList.innerHTML = html || '<div class="no-highlights">No highlights match the selected filter</div>';
696733

697-
// Add click handlers to navigate to verses
698734
document.querySelectorAll('.highlight-item').forEach(item => {
699735
item.addEventListener('click', () => {
700736
const reference = item.dataset.reference;
@@ -838,10 +874,19 @@ async function init() {
838874
const navigatedFromURL = navigateFromURL();
839875
if (!navigatedFromURL) {
840876
if (window.location.pathname !== '/') {
877+
const defaultParams = {
878+
translation: 'BSB',
879+
book: 'Genesis',
880+
chapter: 1
881+
};
882+
window.history.replaceState(
883+
defaultParams,
884+
'',
885+
`?p=bsb/gen/1`
886+
);
841887
loadPassage();
842888
}
843889
}
844-
845890
console.log('App initialized successfully');
846891
}
847892

0 commit comments

Comments
 (0)