Checkpoint WebGL book playback refactor state

This commit is contained in:
2026-06-10 01:07:22 +02:00
parent 171cafeb65
commit b41340151d
8 changed files with 824 additions and 370 deletions
+24 -7
View File
@@ -94,7 +94,7 @@ class BookPaginationModule extends BaseModule {
this.pages = this.buildPages([]);
this.spreads = this.buildSpreadsFromPages(this.pages);
this.currentSpreadIndex = 0;
this.publish({ reason: 'initial-title-spread', allowFutureUnrendered: true });
this.publish({ reason: 'initial-title-spread', visibility: 'future-ready' });
this.reportProgress(100, 'Book pagination ready');
return true;
}
@@ -146,7 +146,7 @@ class BookPaginationModule extends BaseModule {
: renderedSpreadIndex >= 0
? renderedSpreadIndex
: Math.max(0, Math.min(this.currentSpreadIndex, Math.max(0, this.spreads.length - 1)));
this.publish({ reason: 'history-refresh', allowFutureUnrendered: true });
this.publish({ reason: 'history-refresh', visibility: 'future-ready' });
}
getContinuationBlockId(latestBlockId = 0, latestRenderedBlockId = 0) {
@@ -187,7 +187,7 @@ class BookPaginationModule extends BaseModule {
spreadIndex: cached.targetSpread?.index ?? this.currentSpreadIndex,
latestBlockId: pendingBlockId,
latestRenderedBlockId,
preloadOnly: false,
phase: 'activate',
reusedPreparedPagination: true
}
}));
@@ -240,7 +240,7 @@ class BookPaginationModule extends BaseModule {
spreadIndex: targetSpread?.index ?? this.currentSpreadIndex,
latestBlockId: pendingBlockId,
latestRenderedBlockId,
preloadOnly: options.activate === false
phase: options.activate === false ? 'prepare' : 'activate'
}
}));
return targetSpread || (options.activate === false ? preparedSpreads[0] : this.getCurrentSpread());
@@ -371,7 +371,8 @@ class BookPaginationModule extends BaseModule {
buildSpreadsFromPages(pages = []) {
const spreads = [];
const linesPerPage = this.getLinesPerPage();
pages.forEach((page, pageIndex) => {
const normalizedPages = this.normalizePagesForSpreads(pages);
normalizedPages.forEach((page, pageIndex) => {
const spreadIndex = Math.floor(pageIndex / 2);
const side = pageIndex % 2 === 0 ? 'left' : 'right';
if (!spreads[spreadIndex]) {
@@ -398,6 +399,22 @@ class BookPaginationModule extends BaseModule {
return spreads.filter(Boolean);
}
normalizePagesForSpreads(pages = []) {
const source = Array.isArray(pages) ? pages : [];
const lastPageIndex = source.reduce((max, page, index) => {
const explicitIndex = Number(page?.index);
return Math.max(max, Number.isFinite(explicitIndex) ? explicitIndex : index);
}, 1);
const lastSpreadRightIndex = Math.max(1, lastPageIndex % 2 === 0 ? lastPageIndex + 1 : lastPageIndex);
const normalized = [];
for (let index = 0; index <= lastSpreadRightIndex; index += 1) {
normalized[index] = source[index] || this.createBlankPage(index, {
section: index < 3 ? 'frontmatter' : 'body'
});
}
return normalized;
}
applyPageReserveDirective(block = {}) {
const directive = block?.metadata?.pageReserve || block?.pageReserve || null;
const blockId = Number(block?.blockId || block?.metadata?.blockId || 0);
@@ -967,7 +984,7 @@ class BookPaginationModule extends BaseModule {
setCurrentSpread(index = 0) {
this.currentSpreadIndex = Math.max(0, Math.min(Math.round(Number(index || 0)), Math.max(0, this.spreads.length - 1)));
this.publish({ reason: 'set-current-spread', allowFutureUnrendered: true });
this.publish({ reason: 'set-current-spread', visibility: 'future-ready' });
return this.currentSpreadIndex;
}
@@ -982,7 +999,7 @@ class BookPaginationModule extends BaseModule {
latestBlockId: this.latestBlockId,
latestRenderedBlockId: this.latestRenderedBlockId,
reason: options.reason || 'publish',
allowFutureUnrendered: options.allowFutureUnrendered === true
visibility: options.visibility || 'current'
}
}));
}