// Page order presets for manga/comics // Auto-detect Japanese vs Western reading order // Feature Registration Pattern implementation import { ReaderContext } from "../core/reader-context"; export function init(context: ReaderContext): void { let state: PageOrderState | null = null; context.events.on( "reader:loaded", (detail: { totalPages: number; pageNames: string[] }) => { state = createPageOrderState(detail.totalPages, detail.pageNames); }, ); context.events.on("page-order:set", (detail: { mode: PageOrderMode }) => { if (state) { setPageOrderMode(state, detail.mode, context); } }); context.events.on("page-order:get", () => { if (state) { const order = getPageOrder(state); context.events.emit("page-order:current", { order }); } }); context.events.on( "page-order:reorder", (detail: { pageNumbers: number[] }) => { if (state) { const reordered = reorderPages(state, detail.pageNumbers); context.events.emit("page-order:reordered", { pages: reordered }); } }, ); context.events.on( "page-order:display-number", (detail: { actualPage: number }) => { if (state) { const displayPage = getDisplayPageNumber(state, detail.actualPage); context.events.emit("page-order:display-page", { displayPage }); } }, ); } type PageOrderMode = "auto" | "japanese" | "western"; interface PageOrderConfig { mode: PageOrderMode; detectedOrder: PageOrderMode; userOverride: boolean; } interface PageOrderState { config: PageOrderConfig; totalPages: number; } function detectPageOrder(pageNames: string[]): PageOrderMode { if (pageNames.length < 2) return "western"; const firstPage = pageNames[0].toLowerCase(); const lastPage = pageNames[pageNames.length - 1].toLowerCase(); const hasFrontCover = /cover|front|001/.test(firstPage); const hasBackCover = /back|end|最后的/.test(lastPage); if (hasFrontCover && !hasBackCover) { return "western"; } if (hasBackCover && !hasFrontCover) { return "japanese"; } const chapterMatches = pageNames.filter((n) => /ch-\d+|chapter/i.test(n)); if (chapterMatches.length > 0) { const firstChapter = chapterMatches[0]; const pageNum = parseInt(firstChapter.match(/\d+/)?.[0] || "0"); return pageNum > 0 ? "western" : "japanese"; } return "western"; } function createPageOrderState( totalPages: number, pageNames: string[], ): PageOrderState { const detectedOrder = detectPageOrder(pageNames); return { config: { mode: "auto", detectedOrder, userOverride: false, }, totalPages, }; } function setPageOrderMode( state: PageOrderState, mode: PageOrderMode, context: ReaderContext, ): PageOrderState { state.config = { ...state.config, mode, userOverride: mode !== "auto", }; const order = getPageOrder(state); context.events.emit("page-order:changed", { mode, order }); return state; } function getPageOrder(state: PageOrderState): PageOrderMode { if (state.config.mode === "auto") { return state.config.detectedOrder; } return state.config.mode; } function reorderPages(state: PageOrderState, pageNumbers: number[]): number[] { const order = getPageOrder(state); if (order === "japanese") { return [...pageNumbers].reverse(); } return pageNumbers; } function getDisplayPageNumber( state: PageOrderState, actualPage: number, ): number { const order = getPageOrder(state); if (order === "japanese") { return state.totalPages - actualPage + 1; } return actualPage; }