This commit is contained in:
33333-33333 2026-07-18 22:15:26 +09:00
commit d163ceb291
76 changed files with 1385 additions and 524 deletions

View file

@ -134,7 +134,10 @@ function lineageFamilyHtml(component, index, family, signature = "") {
function lineageArchiveNeedsRender() {
const familyVersion = world.familyVersion || 0;
const familyDirty = Boolean(world.familyTreeDirty);
return !uiCache.archiveVersion || uiCache.archiveFamilyVersion !== familyVersion || familyDirty;
// A cancelled/cleared DOM must never make the family view permanently blank
// merely because the cached data version still matches the world.
const hasSnapshot = Boolean(ui.archiveContent?.firstElementChild);
return !hasSnapshot || !uiCache.archiveVersion || uiCache.archiveFamilyVersion !== familyVersion || familyDirty;
}
function lineageDeferArchiveIfOffscreen(hiddenInterval = 30000) {
@ -156,12 +159,18 @@ function lineageScheduleArchiveIdle(timeout = 1200) {
return true;
}
function renderArchive() {
function renderArchive(options = {}) {
if (!ui.archiveContent) return;
const userRequested = Boolean(options?.userRequested);
if (!userRequested && uiCache.activePanelTab !== "family") {
uiCache.archiveScheduled = false;
return;
}
if (userRequested) uiCache.archiveViewActivated = true;
// Auto update OFF now means "do not keep refreshing", not "hide the tree".
// Draw the current snapshot once so the family tree is always available under
// the event UI, then mark it stale when the family data changes.
if (typeof archiveAutoUpdateEnabled === "function" && !archiveAutoUpdateEnabled()) {
if (!userRequested && typeof archiveAutoUpdateEnabled === "function" && !archiveAutoUpdateEnabled()) {
uiCache.archiveScheduled = false;
if (uiCache.archiveVersion && world.familyTreeDirty) {
const hasRenderedGraph = Boolean(ui.archiveContent.querySelector(".lineage-family-tree, [data-family-tarinai-id]"));
@ -187,10 +196,10 @@ function renderArchive() {
return;
}
if (!lineageArchiveNeedsRender()) return;
if (lineageDeferArchiveIfOffscreen()) return;
if (!userRequested && lineageDeferArchiveIfOffscreen()) return;
const now = performance.now();
const minUpdateGap = 4800;
if (uiCache.archiveVersion && !uiCache.archiveRenderForce && now - (uiCache.archiveLastRenderedAt || 0) < minUpdateGap) {
if (!userRequested && uiCache.archiveVersion && !uiCache.archiveRenderForce && now - (uiCache.archiveLastRenderedAt || 0) < minUpdateGap) {
if (!uiCache.archiveRenderTimer) {
uiCache.archiveRenderTimer = setTimeout(() => {
uiCache.archiveRenderTimer = 0;
@ -315,6 +324,10 @@ function resetArchiveRenderState() {
}
function scheduleArchiveWindowRender() {
if (!uiCache.archiveViewActivated || uiCache.activePanelTab !== "family") {
uiCache.archiveScheduled = false;
return;
}
if (typeof archiveAutoUpdateEnabled === "function" && !archiveAutoUpdateEnabled()) {
uiCache.archiveScheduled = false;
if (world.familyTreeDirty) lineageSetArchiveStaleStatus(true);
@ -331,6 +344,7 @@ function scheduleArchiveWindowRender() {
}
function schedulePendingArchiveRender() {
if (!uiCache.archiveViewActivated || uiCache.activePanelTab !== "family") return;
if (typeof archiveAutoUpdateEnabled === "function" && !archiveAutoUpdateEnabled()) return;
if (!uiCache.archivePendingOffscreen) return;
if (!lineageArchiveNearViewport()) return;
@ -338,4 +352,27 @@ function schedulePendingArchiveRender() {
if (lineageArchiveNeedsRender()) scheduleArchiveWindowRender();
}
function cancelArchiveBackgroundRender() {
const wasRunning = Boolean(uiCache.archiveRenderRunning);
if (uiCache.archiveRenderTimer) {
clearTimeout(uiCache.archiveRenderTimer);
uiCache.archiveRenderTimer = 0;
}
// All asynchronous family-layout pumps validate this token before doing work.
// Invalidating it stops an in-progress offscreen build without discarding the
// reusable component HTML cache. An interrupted render is marked incomplete so
// the next explicit visit resumes with a clean render pass.
uiCache.archiveRenderToken = `paused:${performance.now()}`;
uiCache.archiveRenderRunning = false;
uiCache.archiveScheduled = false;
uiCache.archivePendingOffscreen = false;
uiCache.archivePendingDirtyAfterRun = false;
if (wasRunning) {
uiCache.archiveVersion = "";
uiCache.archiveFamilyVersion = null;
if (world) world.familyTreeDirty = true;
}
}
window.resetArchiveRenderState = resetArchiveRenderState;
window.cancelArchiveBackgroundRender = cancelArchiveBackgroundRender;