fix(reader): render full book in continuous mode with smooth chapter jumping and scroll tracking
This commit is contained in:
1 parent
21d94acf4e
commit
0c5951df8d
1 file changed
+147
-62
+147
-62
@@ -147,6 +147,8 @@ export async function openBook(bookId, specificChapterIdx = null, updateHash = t
|
|||||||
const readerBookTitle = document.getElementById('reader-book-title');
|
const readerBookTitle = document.getElementById('reader-book-title');
|
||||||
const readerBookAuthor = document.getElementById('reader-book-author');
|
const readerBookAuthor = document.getElementById('reader-book-author');
|
||||||
const readerChapterSelect = document.getElementById('reader-chapter-select');
|
const readerChapterSelect = document.getElementById('reader-chapter-select');
|
||||||
|
const readerPrevChBtn = document.getElementById('reader-prev-ch-btn');
|
||||||
|
const readerNextChBtn = document.getElementById('reader-next-ch-btn');
|
||||||
const readerContentBody = document.getElementById('reader-content-body');
|
const readerContentBody = document.getElementById('reader-content-body');
|
||||||
|
|
||||||
if (readerView) readerView.classList.remove('hidden');
|
if (readerView) readerView.classList.remove('hidden');
|
||||||
@@ -164,16 +166,22 @@ export async function openBook(bookId, specificChapterIdx = null, updateHash = t
|
|||||||
if (currentBook && currentBook.id === bookId) {
|
if (currentBook && currentBook.id === bookId) {
|
||||||
if (specificChapterIdx !== null && specificChapterIdx !== undefined && !isNaN(specificChapterIdx)) {
|
if (specificChapterIdx !== null && specificChapterIdx !== undefined && !isNaN(specificChapterIdx)) {
|
||||||
if (specificChapterIdx !== currentChapterIndex) {
|
if (specificChapterIdx !== currentChapterIndex) {
|
||||||
if (readerSettings.flowMode === 'continuous' || loadedChaptersSet.has(specificChapterIdx)) {
|
currentChapterIndex = specificChapterIdx;
|
||||||
currentChapterIndex = specificChapterIdx;
|
if (readerChapterSelect) readerChapterSelect.value = currentChapterIndex;
|
||||||
if (readerChapterSelect) readerChapterSelect.value = currentChapterIndex;
|
updateChapterSelectIcons();
|
||||||
|
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
||||||
|
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
||||||
|
|
||||||
|
if (readerSettings.flowMode === 'continuous') {
|
||||||
const target = document.getElementById(`chapter-anchor-${specificChapterIdx}`)
|
const target = document.getElementById(`chapter-anchor-${specificChapterIdx}`)
|
||||||
|| (readerContentBody && readerContentBody.querySelector(`[data-chapter-idx="${specificChapterIdx}"]`));
|
|| (readerContentBody && readerContentBody.querySelector(`[data-chapter-idx="${specificChapterIdx}"]`));
|
||||||
if (target) {
|
if (target) {
|
||||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
scrollToElement(target, true);
|
||||||
|
} else {
|
||||||
|
renderContinuousBook(specificChapterIdx);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
renderChapter(specificChapterIdx, 0, 0, 0);
|
renderChapter(specificChapterIdx, null, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,32 +272,30 @@ export function buildChapterDOM(chapterIdx, knownWordsMap, isContinuous = false)
|
|||||||
const chapter = currentBook.chapters[chapterIdx] || { title: '', content: '' };
|
const chapter = currentBook.chapters[chapterIdx] || { title: '', content: '' };
|
||||||
const frag = document.createDocumentFragment();
|
const frag = document.createDocumentFragment();
|
||||||
|
|
||||||
if (chapter.title || isContinuous) {
|
if (chapterIdx > 0 || isContinuous) {
|
||||||
if (isContinuous || chapterIdx > 0) {
|
const divider = document.createElement('div');
|
||||||
const divider = document.createElement('div');
|
divider.className = 'reader-chapter-divider';
|
||||||
divider.className = 'reader-chapter-divider';
|
divider.id = `chapter-anchor-${chapterIdx}`;
|
||||||
divider.id = `chapter-anchor-${chapterIdx}`;
|
divider.setAttribute('data-chapter-idx', chapterIdx.toString());
|
||||||
divider.setAttribute('data-chapter-idx', chapterIdx.toString());
|
|
||||||
|
|
||||||
const badge = document.createElement('span');
|
const badge = document.createElement('span');
|
||||||
badge.className = 'divider-badge';
|
badge.className = 'divider-badge';
|
||||||
badge.textContent = `Глава ${chapterIdx + 1} из ${currentBook.chapters.length}`;
|
badge.textContent = `Глава ${chapterIdx + 1} из ${currentBook.chapters.length}`;
|
||||||
|
|
||||||
const titleEl = document.createElement('h2');
|
const titleEl = document.createElement('h2');
|
||||||
titleEl.className = 'divider-title';
|
titleEl.className = 'divider-title';
|
||||||
titleEl.textContent = chapter.title || `Глава ${chapterIdx + 1}`;
|
titleEl.textContent = chapter.title || `Глава ${chapterIdx + 1}`;
|
||||||
|
|
||||||
divider.appendChild(badge);
|
divider.appendChild(badge);
|
||||||
divider.appendChild(titleEl);
|
divider.appendChild(titleEl);
|
||||||
frag.appendChild(divider);
|
frag.appendChild(divider);
|
||||||
} else if (chapter.title) {
|
} else {
|
||||||
const h = document.createElement('h2');
|
const h = document.createElement('h2');
|
||||||
h.textContent = chapter.title;
|
h.textContent = chapter.title || `Глава 1`;
|
||||||
h.setAttribute('data-block-idx', '0');
|
h.setAttribute('data-block-idx', '0');
|
||||||
h.setAttribute('data-chapter-idx', chapterIdx.toString());
|
h.setAttribute('data-chapter-idx', '0');
|
||||||
h.id = `chapter-anchor-${chapterIdx}`;
|
h.id = `chapter-anchor-0`;
|
||||||
frag.appendChild(h);
|
frag.appendChild(h);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const blocks = parseContentBlocks(chapter.content);
|
const blocks = parseContentBlocks(chapter.content);
|
||||||
@@ -481,7 +487,7 @@ export function buildChapterFooterDOM(chapterIdx) {
|
|||||||
nextBtn.onclick = () => {
|
nextBtn.onclick = () => {
|
||||||
if (readerSettings.flowMode === 'continuous') {
|
if (readerSettings.flowMode === 'continuous') {
|
||||||
const target = document.getElementById(`chapter-anchor-${nextCh}`);
|
const target = document.getElementById(`chapter-anchor-${nextCh}`);
|
||||||
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
if (target) scrollToElement(target, true);
|
||||||
} else if (readerSettings.autoLoadNext) {
|
} else if (readerSettings.autoLoadNext) {
|
||||||
appendNextChapter(nextCh, true);
|
appendNextChapter(nextCh, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -500,6 +506,28 @@ export function buildChapterFooterDOM(chapterIdx) {
|
|||||||
return footer;
|
return footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function scrollToElement(targetEl, smooth = true) {
|
||||||
|
const readerScrollArea = document.getElementById('reader-scroll-area');
|
||||||
|
if (!targetEl || !readerScrollArea) return;
|
||||||
|
const containerTop = readerScrollArea.getBoundingClientRect().top;
|
||||||
|
const elTop = targetEl.getBoundingClientRect().top;
|
||||||
|
const targetScroll = readerScrollArea.scrollTop + (elTop - containerTop - 10);
|
||||||
|
readerScrollArea.scrollTo({
|
||||||
|
top: Math.max(0, targetScroll),
|
||||||
|
behavior: smooth ? 'smooth' : 'auto'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateChapterSelectIcons() {
|
||||||
|
const readerChapterSelect = document.getElementById('reader-chapter-select');
|
||||||
|
if (!readerChapterSelect || !readerChapterSelect.options || !currentBook || !currentBook.chapters) return;
|
||||||
|
for (let i = 0; i < readerChapterSelect.options.length; i++) {
|
||||||
|
const rawTitle = currentBook.chapters[i]?.title || `Глава ${i + 1}`;
|
||||||
|
const icon = i < currentChapterIndex ? '✔ ' : (i === currentChapterIndex ? '▶ ' : '○ ');
|
||||||
|
readerChapterSelect.options[i].textContent = `${icon}${rawTitle}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function appendNextChapter(nextCh, smoothScroll = false) {
|
export function appendNextChapter(nextCh, smoothScroll = false) {
|
||||||
if (!currentBook || !currentBook.chapters || nextCh >= currentBook.chapters.length) return;
|
if (!currentBook || !currentBook.chapters || nextCh >= currentBook.chapters.length) return;
|
||||||
const readerContentBody = document.getElementById('reader-content-body');
|
const readerContentBody = document.getElementById('reader-content-body');
|
||||||
@@ -511,7 +539,7 @@ export function appendNextChapter(nextCh, smoothScroll = false) {
|
|||||||
if (loadedChaptersSet.has(nextCh)) {
|
if (loadedChaptersSet.has(nextCh)) {
|
||||||
if (smoothScroll) {
|
if (smoothScroll) {
|
||||||
const target = document.getElementById(`chapter-anchor-${nextCh}`);
|
const target = document.getElementById(`chapter-anchor-${nextCh}`);
|
||||||
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
if (target) scrollToElement(target, true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -543,7 +571,7 @@ export function appendNextChapter(nextCh, smoothScroll = false) {
|
|||||||
if (smoothScroll) {
|
if (smoothScroll) {
|
||||||
const anchor = document.getElementById(`chapter-anchor-${nextCh}`);
|
const anchor = document.getElementById(`chapter-anchor-${nextCh}`);
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
anchor.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
scrollToElement(anchor, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -555,10 +583,13 @@ export function renderContinuousBook(targetChapter = 0, restoreScrollTop = null,
|
|||||||
const readerPrevChBtn = document.getElementById('reader-prev-ch-btn');
|
const readerPrevChBtn = document.getElementById('reader-prev-ch-btn');
|
||||||
const readerNextChBtn = document.getElementById('reader-next-ch-btn');
|
const readerNextChBtn = document.getElementById('reader-next-ch-btn');
|
||||||
const readerContentBody = document.getElementById('reader-content-body');
|
const readerContentBody = document.getElementById('reader-content-body');
|
||||||
|
const readerScrollArea = document.getElementById('reader-scroll-area');
|
||||||
|
|
||||||
currentChapterIndex = Math.max(0, Math.min(targetChapter, currentBook.chapters.length - 1));
|
currentChapterIndex = Math.max(0, Math.min(targetChapter, currentBook.chapters.length - 1));
|
||||||
if (readerChapterSelect) readerChapterSelect.value = currentChapterIndex;
|
if (readerChapterSelect) readerChapterSelect.value = currentChapterIndex;
|
||||||
|
|
||||||
|
updateChapterSelectIcons();
|
||||||
|
|
||||||
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
||||||
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
||||||
|
|
||||||
@@ -572,16 +603,37 @@ export function renderContinuousBook(targetChapter = 0, restoreScrollTop = null,
|
|||||||
if (c.term) knownWordsMap.set(c.term.trim().toLowerCase(), c);
|
if (c.term) knownWordsMap.set(c.term.trim().toLowerCase(), c);
|
||||||
});
|
});
|
||||||
|
|
||||||
loadedChaptersSet.add(currentChapterIndex);
|
const totalChapters = currentBook.chapters.length;
|
||||||
const chFrag = buildChapterDOM(currentChapterIndex, knownWordsMap, false);
|
const docFrag = document.createDocumentFragment();
|
||||||
readerContentBody.appendChild(chFrag);
|
|
||||||
|
|
||||||
const footer = buildChapterFooterDOM(currentChapterIndex);
|
for (let ch = 0; ch < totalChapters; ch++) {
|
||||||
if (footer) {
|
loadedChaptersSet.add(ch);
|
||||||
readerContentBody.appendChild(footer);
|
const chFrag = buildChapterDOM(ch, knownWordsMap, ch > 0);
|
||||||
|
docFrag.appendChild(chFrag);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyScroll(restoreAnchorIdx, restoreScrollTop, restoreFraction, currentChapterIndex);
|
const finishFooter = buildChapterFooterDOM(totalChapters - 1);
|
||||||
|
if (finishFooter) {
|
||||||
|
docFrag.appendChild(finishFooter);
|
||||||
|
}
|
||||||
|
|
||||||
|
readerContentBody.appendChild(docFrag);
|
||||||
|
|
||||||
|
// Apply scroll: either restored from storage/arguments or to target chapter anchor
|
||||||
|
if (restoreScrollTop !== null || restoreFraction !== null || restoreAnchorIdx !== null) {
|
||||||
|
applyScroll(restoreAnchorIdx, restoreScrollTop, restoreFraction, currentChapterIndex);
|
||||||
|
} else if (currentChapterIndex > 0) {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const targetAnchor = document.getElementById(`chapter-anchor-${currentChapterIndex}`);
|
||||||
|
if (targetAnchor) {
|
||||||
|
scrollToElement(targetAnchor, false);
|
||||||
|
}
|
||||||
|
updateReaderProgressBar();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (readerScrollArea) readerScrollArea.scrollTop = 0;
|
||||||
|
updateReaderProgressBar();
|
||||||
|
}
|
||||||
|
|
||||||
const posToSave = (restoreFraction !== null && restoreFraction > 0) ? restoreFraction : 0;
|
const posToSave = (restoreFraction !== null && restoreFraction > 0) ? restoreFraction : 0;
|
||||||
api.books.saveProgress(currentBook.id, { current_chapter: currentChapterIndex, current_position: posToSave })
|
api.books.saveProgress(currentBook.id, { current_chapter: currentChapterIndex, current_position: posToSave })
|
||||||
@@ -604,14 +656,7 @@ export function renderChapter(index, restoreScrollTop = null, restoreFraction =
|
|||||||
currentChapterIndex = Math.max(0, Math.min(index, currentBook.chapters.length - 1));
|
currentChapterIndex = Math.max(0, Math.min(index, currentBook.chapters.length - 1));
|
||||||
if (readerChapterSelect) readerChapterSelect.value = currentChapterIndex;
|
if (readerChapterSelect) readerChapterSelect.value = currentChapterIndex;
|
||||||
|
|
||||||
// Refresh status icons in chapter select
|
updateChapterSelectIcons();
|
||||||
if (readerChapterSelect && readerChapterSelect.options) {
|
|
||||||
for (let i = 0; i < readerChapterSelect.options.length; i++) {
|
|
||||||
const rawTitle = currentBook.chapters[i]?.title || `Глава ${i + 1}`;
|
|
||||||
const icon = i < currentChapterIndex ? '✔ ' : (i === currentChapterIndex ? '▶ ' : '○ ');
|
|
||||||
readerChapterSelect.options[i].textContent = `${icon}${rawTitle}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
||||||
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
||||||
@@ -1245,13 +1290,13 @@ export function getActiveVisibleChapter() {
|
|||||||
const readerScrollArea = document.getElementById('reader-scroll-area');
|
const readerScrollArea = document.getElementById('reader-scroll-area');
|
||||||
const readerContentBody = document.getElementById('reader-content-body');
|
const readerContentBody = document.getElementById('reader-content-body');
|
||||||
if (!readerScrollArea || !readerContentBody) return currentChapterIndex;
|
if (!readerScrollArea || !readerContentBody) return currentChapterIndex;
|
||||||
const dividers = readerContentBody.querySelectorAll('[data-chapter-idx]');
|
const anchors = readerContentBody.querySelectorAll('[id^="chapter-anchor-"]');
|
||||||
if (!dividers || dividers.length === 0) return currentChapterIndex;
|
if (!anchors || anchors.length === 0) return currentChapterIndex;
|
||||||
|
|
||||||
const containerTop = readerScrollArea.getBoundingClientRect().top;
|
const containerTop = readerScrollArea.getBoundingClientRect().top;
|
||||||
let activeIdx = currentChapterIndex;
|
let activeIdx = 0;
|
||||||
|
|
||||||
for (let el of dividers) {
|
for (let el of anchors) {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
if (rect.top <= containerTop + 140) {
|
if (rect.top <= containerTop + 140) {
|
||||||
const ch = parseInt(el.getAttribute('data-chapter-idx'), 10);
|
const ch = parseInt(el.getAttribute('data-chapter-idx'), 10);
|
||||||
@@ -1313,6 +1358,7 @@ export function handleReaderScroll() {
|
|||||||
if (activeCh !== null && activeCh !== undefined && activeCh !== currentChapterIndex) {
|
if (activeCh !== null && activeCh !== undefined && activeCh !== currentChapterIndex) {
|
||||||
currentChapterIndex = activeCh;
|
currentChapterIndex = activeCh;
|
||||||
if (readerChapterSelect) readerChapterSelect.value = currentChapterIndex;
|
if (readerChapterSelect) readerChapterSelect.value = currentChapterIndex;
|
||||||
|
updateChapterSelectIcons();
|
||||||
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
||||||
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
||||||
|
|
||||||
@@ -1323,8 +1369,8 @@ export function handleReaderScroll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Infinite scroll: auto-append next chapter in continuous mode or chapters mode with autoload
|
// 2. Infinite scroll: auto-append next chapter in chapters mode with autoload
|
||||||
if ((readerSettings.flowMode === 'continuous' || (readerSettings.flowMode === 'chapters' && readerSettings.autoLoadNext)) && !isAppendingChapter) {
|
if (readerSettings.flowMode === 'chapters' && readerSettings.autoLoadNext && !isAppendingChapter) {
|
||||||
const distanceToBottom = readerScrollArea.scrollHeight - (readerScrollArea.scrollTop + readerScrollArea.clientHeight);
|
const distanceToBottom = readerScrollArea.scrollHeight - (readerScrollArea.scrollTop + readerScrollArea.clientHeight);
|
||||||
if (distanceToBottom < 700) {
|
if (distanceToBottom < 700) {
|
||||||
const loadedArr = Array.from(loadedChaptersSet);
|
const loadedArr = Array.from(loadedChaptersSet);
|
||||||
@@ -1674,7 +1720,11 @@ export function initReader() {
|
|||||||
saveReaderSettings();
|
saveReaderSettings();
|
||||||
updateReaderSettingsUI();
|
updateReaderSettingsUI();
|
||||||
if (currentBook) {
|
if (currentBook) {
|
||||||
renderChapter(currentChapterIndex, 0, 0, 0);
|
if (readerSettings.flowMode === 'continuous') {
|
||||||
|
renderContinuousBook(currentChapterIndex);
|
||||||
|
} else {
|
||||||
|
renderChapter(currentChapterIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1876,15 +1926,28 @@ export function initReader() {
|
|||||||
readerChapterSelect.addEventListener('change', () => {
|
readerChapterSelect.addEventListener('change', () => {
|
||||||
const ch = parseInt(readerChapterSelect.value, 10);
|
const ch = parseInt(readerChapterSelect.value, 10);
|
||||||
if (!currentBook) return;
|
if (!currentBook) return;
|
||||||
if (readerSettings.flowMode === 'continuous' || loadedChaptersSet.has(ch)) {
|
|
||||||
|
if (readerSettings.flowMode === 'continuous') {
|
||||||
currentChapterIndex = ch;
|
currentChapterIndex = ch;
|
||||||
|
updateChapterSelectIcons();
|
||||||
|
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
||||||
|
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
||||||
|
|
||||||
const target = document.getElementById(`chapter-anchor-${ch}`)
|
const target = document.getElementById(`chapter-anchor-${ch}`)
|
||||||
|| (readerContentBody && readerContentBody.querySelector(`[data-chapter-idx="${ch}"]`));
|
|| (readerContentBody && readerContentBody.querySelector(`[data-chapter-idx="${ch}"]`));
|
||||||
if (target) {
|
if (target) {
|
||||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
scrollToElement(target, true);
|
||||||
return;
|
} else {
|
||||||
|
renderContinuousBook(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const desiredHash = `#reader/book/${currentBook.id}/ch/${ch}`;
|
||||||
|
if (window.location.hash !== desiredHash) {
|
||||||
|
history.replaceState(null, '', desiredHash);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.hash = `#reader/book/${currentBook.id}/ch/${ch}`;
|
window.location.hash = `#reader/book/${currentBook.id}/ch/${ch}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1893,15 +1956,26 @@ export function initReader() {
|
|||||||
readerPrevChBtn.addEventListener('click', () => {
|
readerPrevChBtn.addEventListener('click', () => {
|
||||||
if (currentBook && currentChapterIndex > 0) {
|
if (currentBook && currentChapterIndex > 0) {
|
||||||
const prev = currentChapterIndex - 1;
|
const prev = currentChapterIndex - 1;
|
||||||
if (readerSettings.flowMode === 'continuous' || loadedChaptersSet.has(prev)) {
|
if (readerSettings.flowMode === 'continuous') {
|
||||||
currentChapterIndex = prev;
|
currentChapterIndex = prev;
|
||||||
if (readerChapterSelect) readerChapterSelect.value = prev;
|
if (readerChapterSelect) readerChapterSelect.value = prev;
|
||||||
|
updateChapterSelectIcons();
|
||||||
|
readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
||||||
|
if (readerNextChBtn) readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
||||||
|
|
||||||
const target = document.getElementById(`chapter-anchor-${prev}`)
|
const target = document.getElementById(`chapter-anchor-${prev}`)
|
||||||
|| (readerContentBody && readerContentBody.querySelector(`[data-chapter-idx="${prev}"]`));
|
|| (readerContentBody && readerContentBody.querySelector(`[data-chapter-idx="${prev}"]`));
|
||||||
if (target) {
|
if (target) {
|
||||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
scrollToElement(target, true);
|
||||||
return;
|
} else {
|
||||||
|
renderContinuousBook(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const desiredHash = `#reader/book/${currentBook.id}/ch/${prev}`;
|
||||||
|
if (window.location.hash !== desiredHash) {
|
||||||
|
history.replaceState(null, '', desiredHash);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
window.location.hash = `#reader/book/${currentBook.id}/ch/${prev}`;
|
window.location.hash = `#reader/book/${currentBook.id}/ch/${prev}`;
|
||||||
}
|
}
|
||||||
@@ -1912,15 +1986,26 @@ export function initReader() {
|
|||||||
readerNextChBtn.addEventListener('click', () => {
|
readerNextChBtn.addEventListener('click', () => {
|
||||||
if (currentBook && currentBook.chapters && currentChapterIndex < currentBook.chapters.length - 1) {
|
if (currentBook && currentBook.chapters && currentChapterIndex < currentBook.chapters.length - 1) {
|
||||||
const next = currentChapterIndex + 1;
|
const next = currentChapterIndex + 1;
|
||||||
if (readerSettings.flowMode === 'continuous' || loadedChaptersSet.has(next)) {
|
if (readerSettings.flowMode === 'continuous') {
|
||||||
currentChapterIndex = next;
|
currentChapterIndex = next;
|
||||||
if (readerChapterSelect) readerChapterSelect.value = next;
|
if (readerChapterSelect) readerChapterSelect.value = next;
|
||||||
|
updateChapterSelectIcons();
|
||||||
|
if (readerPrevChBtn) readerPrevChBtn.disabled = currentChapterIndex <= 0;
|
||||||
|
readerNextChBtn.disabled = currentChapterIndex >= currentBook.chapters.length - 1;
|
||||||
|
|
||||||
const target = document.getElementById(`chapter-anchor-${next}`)
|
const target = document.getElementById(`chapter-anchor-${next}`)
|
||||||
|| (readerContentBody && readerContentBody.querySelector(`[data-chapter-idx="${next}"]`));
|
|| (readerContentBody && readerContentBody.querySelector(`[data-chapter-idx="${next}"]`));
|
||||||
if (target) {
|
if (target) {
|
||||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
scrollToElement(target, true);
|
||||||
return;
|
} else {
|
||||||
|
renderContinuousBook(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const desiredHash = `#reader/book/${currentBook.id}/ch/${next}`;
|
||||||
|
if (window.location.hash !== desiredHash) {
|
||||||
|
history.replaceState(null, '', desiredHash);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (readerSettings.flowMode === 'chapters' && readerSettings.autoLoadNext) {
|
if (readerSettings.flowMode === 'chapters' && readerSettings.autoLoadNext) {
|
||||||
appendNextChapter(next, true);
|
appendNextChapter(next, true);
|
||||||
|
|||||||
Reference in new issue
Block a user