Skip to content

Commit

Permalink
Refactored BibleBlock
Browse files Browse the repository at this point in the history
  • Loading branch information
jonbitgood committed Dec 12, 2024
1 parent cd33241 commit d94e9de
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 200 deletions.
2 changes: 1 addition & 1 deletion dist/AudioPlayer.NoDefaults.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/AudioPlayer.NoDefaults.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/AudioPlayer.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/AudioPlayer.min.js.map

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions src/AudioPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import {
initBibleList,
handleBibleButtonClick,
initBookList,
updateBookList,
} from "./AudioPlayerBibleList.js";
import { handleBookChange } from "./AudioPlayerBibleList.js";
import { handleBookChange, updateBookList } from "./AudioPlayerChapterList.js";

export default class AudioPlayer {
constructor(containerId, options) {
Expand Down
189 changes: 2 additions & 187 deletions src/AudioPlayerBibleList.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { elem, parseTimestampToSeconds } from './AudioPlayerHelpers.js'
import { elem } from './AudioPlayerHelpers.js'
import { fuzzySearch } from './AudioPlayerSearch.js';
import {selectBible, setCurrentChapter} from './AudioPlayerProviders.js'
import { handleChapterChange, chapterList } from './AudioPlayerChapterList.js';
import { updateCurrentBibleBlock, updateBookList, handleChapterChange, chapterList } from './AudioPlayerChapterList.js';

export function initBibleList(ctx) {
ctx.bibleListContainer.innerHTML = '';
Expand Down Expand Up @@ -79,161 +79,6 @@ export async function handleBibleButtonClick(ctx, bible) {
}
}

export function updateCurrentBibleBlock(ctx, bible) {
ctx.bibleBlock.innerHTML = '';
ctx.bibleBlock.className = ctx.class.bibleBlock;

const bibleBlockInfoWrap = elem('div', {className: ctx.class.bibleBlockInfoWrap})
const bibleBlockLanguageGroup = elem('div', {className: ctx.class.bibleBlockLanguageGroup})
bibleBlockLanguageGroup.appendChild(elem('div', { className: ctx.class.bibleBlockIso, innerText: bible.iso }));
bibleBlockLanguageGroup.appendChild(elem('div', { innerText: bible.cn }));
bibleBlockInfoWrap.append(bibleBlockLanguageGroup)

const bibleBlockTitleGroup = elem('div', {className: ctx.class.bibleBlockTitleGroup})
bibleBlockTitleGroup.appendChild(elem('div', {className: ctx.class.bibleBlockTitle,innerText: bible.tt}));
if (bible.tv && bible.tv !== bible.tt) {
bibleBlockTitleGroup.appendChild(elem('div', { className: ctx.class.bibleBlockVernacular, innerText: bible.tv }));
}
bibleBlockInfoWrap.appendChild(bibleBlockTitleGroup)

const chapterBookSelectWrapper = elem('div', {className: ctx.class.selectBookChapterWrap})
const bookSelect = elem('select', { className: ctx.class.selectBook });
if (ctx.currentBooks && ctx.currentBooks.data) {
ctx.currentBooks.data.forEach(book => {
const option = elem('option', {
value: book.book_id,
innerText: book.name,
selected: (book.book_id === ctx.currentBook.book_id)
});
bookSelect.appendChild(option);
});
}
bookSelect.addEventListener('change', (event) => {
handleBookChange(ctx, event.target.value)
});
const chapterSelect = elem('select', { className: ctx.class.selectChapter });
if (ctx.currentBook && ctx.currentBook.chapters) {
ctx.currentBook.chapters.forEach(chapter => {
const option = elem('option', {
value: chapter,
innerText: chapter,
selected: (chapter == ctx.currentChapter.number)
});
chapterSelect.appendChild(option);
});
}
chapterSelect.addEventListener('change', (event) => handleChapterChange(ctx, ctx.currentBook, parseInt(event.target.value)))
chapterBookSelectWrapper.appendChild(bookSelect);
chapterBookSelectWrapper.appendChild(chapterSelect);

if (ctx.currentChapter && ctx.currentChapter.timestamps && Array.isArray(ctx.currentChapter.timestamps)) {
const verseSelect = elem('select', { className: ctx.class.selectVerse });

ctx.currentChapter.timestamps.forEach((timestamp, index) => {
const verseNumber = index + 1;
const option = elem('option', {
value: verseNumber,
innerText: `${verseNumber}`
});
verseSelect.appendChild(option);
});

verseSelect.addEventListener('change', (event) => {
const selectedVerse = parseInt(event.target.value);
const verseIndex = selectedVerse - 1;
if (ctx.currentChapter.timestamps && ctx.currentChapter.timestamps[verseIndex]) {
const tsStr = ctx.currentChapter.timestamps[verseIndex];
const verseTime = parseTimestampToSeconds(tsStr);
ctx.audio.currentTime = verseTime;
}
});

const verseColonSeparator = elem('div',{innerText:':',className:ctx.class.selectVerseSeparator})
chapterBookSelectWrapper.appendChild(verseColonSeparator)
chapterBookSelectWrapper.appendChild(verseSelect);
ctx.verseSelect = verseSelect;
}

if (ctx.verseSelect) {
let lastSelectedVerse = null;
ctx.audio.addEventListener('timeupdate', () => {
const currentTime = ctx.audio.currentTime;
const verseTimes = ctx.currentChapter.timestamps;
let currentVerseIndex = -1;
for (let i = 0; i < verseTimes.length; i++) {
if (currentTime >= parseTimestampToSeconds(verseTimes[i])) {
currentVerseIndex = i;
} else {
break;
}
}

// Only update the select if the verse actually changed
if (currentVerseIndex !== -1 && currentVerseIndex !== lastSelectedVerse) {
lastSelectedVerse = currentVerseIndex;
// Verses are 1-based in the select, so add 1
ctx.verseSelect.value = currentVerseIndex + 1;
}
});
}

ctx.bookSelect = bookSelect
ctx.chapterSelect = chapterSelect

const bibleBlockButtonGroup = elem('div', {className: ctx.class.bibleBlockButtonGroup})
bibleBlockButtonGroup.appendChild(elem('button', {
innerHTML: ctx.icons.bibles,
className: ctx.class.bibleListNavButton,
onclick: () => {
ctx.view = 'bible';
ctx.render();
}
}))
if (ctx.view === "chapter") {
bibleBlockButtonGroup.appendChild(elem('button', {
innerHTML: ctx.icons.books,
className: ctx.class.bookListNavButton,
onclick: () => {
ctx.view = 'book';
updateBookList(ctx);
ctx.render();
}
}));
}
if (ctx.view === "book") {
bibleBlockButtonGroup.appendChild(elem('button', {
innerHTML: ctx.icons.chapters,
className: ctx.class.chapterListNavButton,
onclick: () => {
ctx.view = 'chapter';
chapterList(ctx);
ctx.render();
}
}));
}
bibleBlockInfoWrap.append(bibleBlockButtonGroup)
ctx.bibleBlock.append(bibleBlockInfoWrap)
ctx.bibleBlock.appendChild(chapterBookSelectWrapper)
updateBookList(ctx);
}

export function handleBookChange(ctx, bookId, chapter = 1) {
const selectedBook = ctx.currentBooks.data.find(book => book.book_id === bookId);
if (!selectedBook) return;

setCurrentChapter(selectedBook, chapter);
const url = new URL(window.location);
url.searchParams.set('bookId', selectedBook.book_id);
window.history.replaceState({}, '', url);

ctx.query = '';
ctx.chapterListContainer.style.display = "block";
ctx.view = "chapter";
ctx.currentBook = selectedBook;

chapterList(ctx);
updateCurrentBibleBlock(ctx, ctx.currentBible);
}

export function initBookList(ctx) {
const searchInput = elem('input', {
Expand All @@ -256,34 +101,4 @@ export function initBookList(ctx) {
updateBookList(ctx);
}

export function createBookButton(ctx, book) {
const button = elem('button', {
className: `${book.book_id} ${ctx.class.bookListButton} ${((ctx.currentBook.book_id == book.book_id) ? ctx.class.bookListButtonActive : '')}`,
ariaLabel: book.name,
onclick: () => handleBookChange(ctx, book.book_id)
});
button.dataset.bookId = book.book_id;
const contentContainer = elem('div');
contentContainer.append(
elem('h2', { className: ctx.class.bookListTitle, textContent: book.name }),
elem('h3', { className: ctx.class.bookListId, textContent: book.book_id })
);
button.appendChild(contentContainer);
return button;
}

export function updateBookList(ctx) {
const bookListGrid = ctx.bookListGrid;
bookListGrid.innerHTML = '';
if (ctx.resultsBooks && ctx.resultsBooks.length && ctx.query !== '') {
ctx.resultsBooks.forEach(result => {
bookListGrid.appendChild(createBookButton(ctx, result.item));
});
} else if (ctx.currentBooks && ctx.query === '') {
if (ctx.currentBooks['data']) {
ctx.currentBooks['data'].forEach(book => {
bookListGrid.appendChild(createBookButton(ctx, book));
});
}
}
}
167 changes: 166 additions & 1 deletion src/AudioPlayerChapterList.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,170 @@
import { elem } from "./AudioPlayerHelpers.js";
import { setCurrentChapter } from "./AudioPlayerProviders.js";
import { elem, parseTimestampToSeconds } from './AudioPlayerHelpers.js'
import { createBibleBlockButtons } from "./AudioPlayerNavigation.js";


export function updateCurrentBibleBlock(ctx, bible) {
ctx.bibleBlock.innerHTML = '';
ctx.bibleBlock.className = ctx.class.bibleBlock;
const bibleBlockInfoWrap = createBibleBlockInfoWrap(ctx, bible);
const chapterBookSelectWrapper = elem('div', { className: ctx.class.selectBookChapterWrap });
chapterBookSelectWrapper.append(createBookSelector(ctx), createChapterSelector(ctx));
createVerseSelector(ctx, chapterBookSelectWrapper);
bibleBlockInfoWrap.append(createBibleBlockButtons(ctx));
ctx.bibleBlock.append(bibleBlockInfoWrap,chapterBookSelectWrapper);
updateBookList(ctx);
}

function createBibleBlockInfoWrap(ctx, bible) {
const bibleBlockInfoWrap = elem('div', { className: ctx.class.bibleBlockInfoWrap });
const bibleBlockLanguageGroup = elem('div', { className: ctx.class.bibleBlockLanguageGroup });
bibleBlockLanguageGroup.append(
elem('div', { className: ctx.class.bibleBlockIso, innerText: bible.iso }),
elem('div', { innerText: bible.cn })
);
bibleBlockInfoWrap.append(bibleBlockLanguageGroup);
const bibleBlockTitleGroup = elem('div', { className: ctx.class.bibleBlockTitleGroup });
bibleBlockTitleGroup.appendChild(elem('div', { className: ctx.class.bibleBlockTitle, innerText: bible.tt }));
if (bible.tv && bible.tv !== bible.tt) {
bibleBlockTitleGroup.appendChild(elem('div', { className: ctx.class.bibleBlockVernacular, innerText: bible.tv }));
}
bibleBlockInfoWrap.appendChild(bibleBlockTitleGroup);
return bibleBlockInfoWrap;
}

export function updateBookList(ctx) {
const bookListGrid = ctx.bookListGrid;
bookListGrid.innerHTML = '';
if (ctx.resultsBooks && ctx.resultsBooks.length && ctx.query !== '') {
ctx.resultsBooks.forEach(result => {
bookListGrid.appendChild(createBookButton(ctx, result.item));
});
} else if (ctx.currentBooks && ctx.query === '') {
if (ctx.currentBooks['data']) {
ctx.currentBooks['data'].forEach(book => {
bookListGrid.appendChild(createBookButton(ctx, book));
});
}
}
}

export function createBookButton(ctx, book) {
const button = elem('button', {
className: `${book.book_id} ${ctx.class.bookListButton} ${((ctx.currentBook.book_id == book.book_id) ? ctx.class.bookListButtonActive : '')}`,
ariaLabel: book.name,
onclick: () => handleBookChange(ctx, book.book_id)
});
button.dataset.bookId = book.book_id;
const contentContainer = elem('div');
contentContainer.append(
elem('h2', { className: ctx.class.bookListTitle, textContent: book.name }),
elem('h3', { className: ctx.class.bookListId, textContent: book.book_id })
);
button.appendChild(contentContainer);
return button;
}

export function handleBookChange(ctx, bookId, chapter = 1) {
const selectedBook = ctx.currentBooks.data.find(book => book.book_id === bookId);
if (!selectedBook) return;

setCurrentChapter(selectedBook, chapter);
const url = new URL(window.location);
url.searchParams.set('bookId', selectedBook.book_id);
window.history.replaceState({}, '', url);

ctx.query = '';
ctx.chapterListContainer.style.display = "block";
ctx.view = "chapter";
ctx.currentBook = selectedBook;

chapterList(ctx);
updateCurrentBibleBlock(ctx, ctx.currentBible);
}

function createBookSelector(ctx) {
const bookSelect = elem('select', { className: ctx.class.selectBook });
if (ctx.currentBooks && ctx.currentBooks.data) {
ctx.currentBooks.data.forEach(book => {
const option = elem('option', {
value: book.book_id,
innerText: book.name,
selected: (book.book_id === ctx.currentBook.book_id)
});
bookSelect.appendChild(option);
});
}
bookSelect.addEventListener('change', (event) => {
handleBookChange(ctx, event.target.value);
});
ctx.bookSelect = bookSelect;
return bookSelect;
}

function createChapterSelector(ctx) {
const chapterSelect = elem('select', { className: ctx.class.selectChapter });
if (ctx.currentBook && ctx.currentBook.chapters) {
ctx.currentBook.chapters.forEach(chapter => {
const option = elem('option', {
value: chapter,
innerText: chapter,
selected: (chapter == ctx.currentChapter.number)
});
chapterSelect.appendChild(option);
});
}
chapterSelect.addEventListener('change', (event) =>
handleChapterChange(ctx, ctx.currentBook, parseInt(event.target.value))
);
ctx.chapterSelect = chapterSelect;
return chapterSelect;
}

function createVerseSelector(ctx, chapterBookSelectWrapper) {
if (!ctx.currentChapter || !ctx.currentChapter.timestamps || ctx.currentChapter.timestamps.length == 0) return;
const verseSelect = elem('select', { className: ctx.class.selectVerse });
ctx.currentChapter.timestamps.forEach((timestamp, index) => {
const verseNumber = index + 1;
const option = elem('option', {
value: verseNumber,
innerText: `${verseNumber}`
});
verseSelect.appendChild(option);
});
verseSelect.addEventListener('change', (event) => {
const selectedVerse = parseInt(event.target.value, 10);
const verseIndex = selectedVerse - 1;
if (ctx.currentChapter.timestamps && ctx.currentChapter.timestamps[verseIndex]) {
const tsStr = ctx.currentChapter.timestamps[verseIndex];
const verseTime = parseTimestampToSeconds(tsStr);
ctx.audio.currentTime = verseTime;
}
});
const verseColonSeparator = elem('div', {innerText: ':',className: ctx.class.selectVerseSeparator});
chapterBookSelectWrapper.append(verseColonSeparator,verseSelect);
ctx.verseSelect = verseSelect;
addVerseHighlightOnTimeUpdate(ctx);
}

function addVerseHighlightOnTimeUpdate(ctx) {
let lastSelectedVerse = null;
ctx.audio.addEventListener('timeupdate', () => {
const currentTime = ctx.audio.currentTime;
const verseTimes = ctx.currentChapter.timestamps;
let currentVerseIndex = -1;
for (let i = 0; i < verseTimes.length; i++) {
if (currentTime >= parseTimestampToSeconds(verseTimes[i])) {
currentVerseIndex = i;
} else {
break;
}
}
if (currentVerseIndex !== -1 && currentVerseIndex !== lastSelectedVerse) {
lastSelectedVerse = currentVerseIndex;
ctx.verseSelect.value = currentVerseIndex + 1;
}
});
}

export function chapterList(ctx) {
ctx.chapterListContainer.innerHTML = '';
Expand Down
Loading

0 comments on commit d94e9de

Please sign in to comment.