Files
MangaCircus/public/reading-clock-core.js
T

33 lines
1.6 KiB
JavaScript

'use strict';
// Shared pure policy. No speed limit; credit only loaded pages actually observed,
// not pages skipped between two scroll positions. Coordinates never leave reader.
(function (root) {
const IDLE_MS = 30000, EXPOSURE_MS = 100;
function exposureTracker() {
const seen = new Set(), exposures = new Map();
function update(pages, now, active) {
const visible = new Set(active ? pages.filter(page => page.loaded).map(page => page.index) : []);
for (const [page, entry] of exposures) {
if (entry.visible) entry.ms += Math.max(0, now - entry.at);
entry.at = now; entry.visible = visible.has(page);
if (entry.ms >= EXPOSURE_MS) { seen.add(page); exposures.delete(page); }
}
for (const page of visible) if (!seen.has(page) && !exposures.has(page)) exposures.set(page, { ms: 0, at: now, visible: true });
return seen;
}
return { seen, update };
}
function stateFor({ visible, focused, lastInputAt, now, owned, view }) {
if (!visible) return 'hidden';
if (!focused) return 'unfocused';
if (now - lastInputAt >= IDLE_MS) return 'idle';
if (!owned) return 'other-tab';
if (view.atEnd) return 'finished';
if (view.pages.some(page => page.loaded)) return 'reading';
return view.pages.some(page => !page.failed) || !view.pages.length ? 'loading' : 'page-error';
}
const policy = { IDLE_MS, EXPOSURE_MS, exposureTracker, stateFor };
if (typeof module !== 'undefined' && module.exports) module.exports = policy;
else root.ReadingClockPolicy = policy;
})(typeof window === 'undefined' ? globalThis : window);