Skip to content

Commit 2d878b8

Browse files
authored
fix(commandline): improve caching to fix stale checkmark and UI state (@byseif21, @fehmer) (monkeytypegame#6586)
### Description Previously, when selecting a language via the text button on the test page, the checkmark (fa-check) in the commandline language list wouldn't update until a page refresh. This was due to the commandline's caching mechanism not detecting changes triggered outside its own control. Although it first appeared to be a language-specific issue, it was later identified that the caching logic was generally insufficient — it didn’t account for updates to the active command state or configuration flags like usingSingleList. ## Solution Fixed the caching logic in the commandline module by tracking a more complete internal state. The system now correctly detects changes in the command list, active state, and configuration, and rebuilds the list UI when necessary. ## Technical Details - The commandline uses a caching mechanism (`lastList`) to avoid rebuilding the HTML if the list hasn't changed done in monkeytypegame#6559 - Replaced the old lastList cache with a new lastState object that stores: the list of commands, each with its isActive flag, the usingSingleList configuration flag - Improved the cache comparison logic, uses areSortedArraysEqual to compare command lists including active state ,compares the usingSingleList flag - Previously, this cache wasn't being cleared when the language changed through the text button - Now we clear the cache on changes, forcing a rebuild of the list with the correct checkmark ## Performance Impact - Minimal performance impact - The list is only rebuilt when: 1. The language actually changes 2. The list content changes 3. The input value changes - The caching mechanism still prevents unnecessary rebuilds in all other cases ## Testing - [x] Language selection through text button updates checkmark immediately - [x] Language selection through commandline works as before - [x] No unnecessary rebuilds when language hasn't changed - [x] Checkmark appears next to correct language in all cases
1 parent 5695245 commit 2d878b8

File tree

1 file changed

+50
-37
lines changed

1 file changed

+50
-37
lines changed

frontend/src/ts/commandline/commandline.ts

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ let subgroupOverride: CommandsSubgroup | null = null;
3939
let isAnimating = false;
4040
let lastSingleListModeInputValue = "";
4141

42+
type CommandWithActiveState = Omit<Command, "active"> & { isActive: boolean };
43+
44+
let lastState:
45+
| {
46+
list: CommandWithActiveState[];
47+
usingSingleList: boolean;
48+
}
49+
| undefined;
50+
4251
function removeCommandlineBackground(): void {
4352
$("#commandLine").addClass("noBackground");
4453
if (Config.showOutOfFocusWarning) {
@@ -328,7 +337,7 @@ function hideCommands(): void {
328337
throw new Error("Commandline element not found");
329338
}
330339
element.innerHTML = "";
331-
lastList = undefined;
340+
lastState = undefined;
332341
}
333342

334343
let cachedSingleSubgroup: CommandsSubgroup | null = null;
@@ -353,8 +362,6 @@ async function getList(): Promise<Command[]> {
353362
return (await getSubgroup()).list;
354363
}
355364

356-
let lastList: Command[] | undefined;
357-
358365
async function showCommands(): Promise<void> {
359366
const element = document.querySelector("#commandLine .suggestions");
360367
if (element === null) {
@@ -366,11 +373,42 @@ async function showCommands(): Promise<void> {
366373
return;
367374
}
368375

369-
const list = (await getList()).filter((c) => c.found === true);
370-
if (lastList && areSortedArraysEqual(list, lastList)) {
376+
const subgroup = await getSubgroup();
377+
378+
const list = subgroup.list
379+
.filter((c) => c.found === true)
380+
.map((command) => {
381+
let isActive = false;
382+
if (command.active !== undefined) {
383+
isActive = command.active();
384+
} else {
385+
const configKey = command.configKey ?? subgroup.configKey;
386+
if (configKey !== undefined) {
387+
if (command.configValueMode === "include") {
388+
isActive = (Config[configKey] as unknown[]).includes(
389+
command.configValue
390+
);
391+
} else {
392+
isActive = Config[configKey] === command.configValue;
393+
}
394+
}
395+
}
396+
const { active: _active, ...restOfCommand } = command;
397+
return { ...restOfCommand, isActive } as CommandWithActiveState;
398+
});
399+
400+
if (
401+
lastState &&
402+
usingSingleList === lastState.usingSingleList &&
403+
areSortedArraysEqual(list, lastState.list)
404+
) {
371405
return;
372406
}
373-
lastList = list;
407+
408+
lastState = {
409+
list: list,
410+
usingSingleList: usingSingleList,
411+
};
374412

375413
let html = "";
376414
let index = 0;
@@ -387,38 +425,13 @@ async function showCommands(): Promise<void> {
387425
icon = `<i class="fas fa-fw ${icon}"></i>`;
388426
}
389427
let configIcon = "";
390-
const configKey = command.configKey ?? (await getSubgroup()).configKey;
391-
if (command.active !== undefined) {
392-
if (command.active()) {
393-
firstActive = firstActive ?? index;
394-
configIcon = `<i class="fas fa-fw fa-check"></i>`;
395-
} else {
396-
configIcon = `<i class="fas fa-fw"></i>`;
397-
}
398-
} else if (configKey !== undefined) {
399-
let isActive;
400-
401-
if (command.configValueMode === "include") {
402-
isActive = (
403-
Config[configKey] as (
404-
| string
405-
| number
406-
| boolean
407-
| number[]
408-
| undefined
409-
)[]
410-
).includes(command.configValue);
411-
} else {
412-
isActive = Config[configKey] === command.configValue;
413-
}
414-
415-
if (isActive) {
416-
firstActive = firstActive ?? index;
417-
configIcon = `<i class="fas fa-fw fa-check"></i>`;
418-
} else {
419-
configIcon = `<i class="fas fa-fw"></i>`;
420-
}
428+
if (command.isActive) {
429+
firstActive = firstActive ?? index;
430+
configIcon = `<i class="fas fa-fw fa-check"></i>`;
431+
} else {
432+
configIcon = `<i class="fas fa-fw"></i>`;
421433
}
434+
422435
const iconHTML = `<div class="icon">${
423436
usingSingleList || configIcon === "" ? icon : configIcon
424437
}</div>`;

0 commit comments

Comments
 (0)