Phase 16E.1 - Word Companion Runtime Performance Stabilisation

This commit is contained in:
Nick Beckley 2026-06-27 22:18:24 +01:00
parent d442de5837
commit 18f204460f
2 changed files with 62 additions and 6 deletions

View File

@ -196,6 +196,9 @@
let sceneTrackingMode = "Manual";
let sceneContextStale = false;
let selectionRefreshTimer = null;
let runtimeSelectionDirty = false;
let runtimeLastActivityAt = 0;
const runtimeIdleDelayMs = 1800;
let selectionHandlerRegistered = false;
let isAutoRefreshingScene = false;
let sceneWordCountSyncTimer = null;
@ -204,6 +207,7 @@
let lastSyncedWordCount = null;
let lastLinkedSceneTitle = "";
let lastLinkedChapterTitle = "";
let runtimeLastDebugAt = 0;
let currentSceneLinks = {
characters: [],
assets: [],
@ -211,6 +215,15 @@
primaryLocationId: null
};
const runtimeDebug = (message) => {
const now = Date.now();
if (now - runtimeLastDebugAt < 1000) {
return;
}
runtimeLastDebugAt = now;
console.debug(`[Word Companion Runtime] ${message}`);
};
const setOfficeStatus = (message) => {
if (officeStatus) {
officeStatus.textContent = message;
@ -337,6 +350,19 @@
};
const setCurrentStructure = (chapterTitle, sceneTitle, wordCount, chapterAnchorId = null, sceneAnchorId = null, chapterIndex = null) => {
const nextChapterTitle = chapterTitle || "";
const nextSceneTitle = sceneTitle || "";
const nextWordCount = Number.isInteger(wordCount) ? wordCount : null;
const nextChapterIndex = Number.isInteger(chapterIndex) && chapterIndex > 0 ? chapterIndex : null;
const nextChapterAnchorId = Number.isInteger(chapterAnchorId) && chapterAnchorId > 0 ? chapterAnchorId : null;
const nextSceneAnchorId = Number.isInteger(sceneAnchorId) && sceneAnchorId > 0 ? sceneAnchorId : null;
const unchanged = detectedChapterTitle === nextChapterTitle
&& detectedSceneTitle === nextSceneTitle
&& detectedSceneWordCount === nextWordCount
&& detectedChapterIndex === nextChapterIndex
&& detectedChapterAnchorId === nextChapterAnchorId
&& detectedSceneAnchorId === nextSceneAnchorId;
detectedChapterTitle = chapterTitle || "";
detectedSceneTitle = sceneTitle || "";
detectedSceneWordCount = Number.isInteger(wordCount) ? wordCount : null;
@ -344,6 +370,10 @@
detectedChapterAnchorId = Number.isInteger(chapterAnchorId) && chapterAnchorId > 0 ? chapterAnchorId : null;
detectedSceneAnchorId = Number.isInteger(sceneAnchorId) && sceneAnchorId > 0 ? sceneAnchorId : null;
if (unchanged) {
return;
}
if (currentChapter) {
currentChapter.textContent = chapterTitle || "Not detected";
}
@ -891,7 +921,10 @@
const setText = (element, value) => {
if (element) {
element.textContent = value;
const nextValue = value === null || value === undefined ? "" : String(value);
if (element.textContent !== nextValue) {
element.textContent = nextValue;
}
}
};
@ -1671,13 +1704,19 @@
const currentChapterItem = chapterForParagraphIndex(documentStructureCache, paragraphIndex);
const currentSceneItem = sceneForParagraphIndex(currentChapterItem, paragraphIndex);
const changed = currentChapterItem?.paragraphIndex !== documentStructureCache.currentChapter?.paragraphIndex
|| currentSceneItem?.paragraphIndex !== documentStructureCache.currentScene?.paragraphIndex;
const changed = currentChapterItem?.startParagraphIndex !== documentStructureCache.currentChapter?.startParagraphIndex
|| currentSceneItem?.startParagraphIndex !== documentStructureCache.currentScene?.startParagraphIndex
|| currentChapterItem?.anchorId !== documentStructureCache.currentChapter?.anchorId
|| currentSceneItem?.anchorId !== documentStructureCache.currentScene?.anchorId;
documentStructureCache.currentParagraphIndex = paragraphIndex;
documentStructureCache.currentChapter = currentChapterItem;
documentStructureCache.currentScene = currentSceneItem;
if (!changed) {
return false;
}
setCurrentStructure(
currentChapterItem?.title,
currentSceneItem?.title,
@ -2129,6 +2168,7 @@
const selectedIndex = findSelectedParagraphIndex(cache, selectionParagraphs.items);
documentStructureCache = cache;
applyRuntimeSelection(selectedIndex);
runtimeDebug("Cache rebuilt.");
return cache;
};
@ -4022,7 +4062,9 @@
};
const refreshCurrentSceneFromSelection = async () => {
selectionRefreshTimer = null;
if (isAutoRefreshingScene || !isAuthenticated || !selectedBook()) {
runtimeDebug("Runtime update skipped.");
return;
}
@ -4038,8 +4080,17 @@
return;
}
const idleForMs = Date.now() - runtimeLastActivityAt;
if (runtimeSelectionDirty && idleForMs < runtimeIdleDelayMs) {
runtimeDebug("Runtime update skipped (typing active).");
scheduleSelectionRefresh(runtimeIdleDelayMs - idleForMs);
return;
}
isAutoRefreshingScene = true;
runtimeSelectionDirty = false;
setSceneTrackingState("Live");
runtimeDebug("Runtime update executed.");
try {
const selectionParagraphs = await window.Word.run(async (context) => await readSelectionParagraphs(context));
@ -4071,14 +4122,19 @@
}
};
const scheduleSelectionRefresh = () => {
const scheduleSelectionRefresh = (delayMs = runtimeIdleDelayMs) => {
if (selectionRefreshTimer) {
window.clearTimeout(selectionRefreshTimer);
}
selectionRefreshTimer = window.setTimeout(refreshCurrentSceneFromSelection, 850);
selectionRefreshTimer = window.setTimeout(refreshCurrentSceneFromSelection, Math.max(0, delayMs));
runtimeDebug("Runtime update scheduled.");
};
const handleDocumentSelectionChanged = () => {
runtimeSelectionDirty = true;
runtimeLastActivityAt = Date.now();
clearPendingSceneWordCountSync();
runtimeDebug("Selection changed.");
scheduleSelectionRefresh();
};

File diff suppressed because one or more lines are too long