Skip to content

Commit 741ab7c

Browse files
committed
refactor: cache often used elements
1 parent 6475b42 commit 741ab7c

File tree

1 file changed

+59
-70
lines changed

1 file changed

+59
-70
lines changed

frontend/src/ts/test/test-ui.ts

Lines changed: 59 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ ConfigEvent.subscribe((eventKey, eventValue, nosave) => {
137137
if (eventKey === "burstHeatmap") void applyBurstHeatmap();
138138
});
139139

140+
const wordsEl = document.querySelector(".pageTest #words") as HTMLElement;
141+
const wordsWrapperEl = document.querySelector(
142+
".pageTest #wordsWrapper",
143+
) as HTMLElement;
144+
140145
export let activeWordTop = 0;
141146
export let lineTransition = false;
142147
export let currentTestLine = 0;
@@ -170,10 +175,9 @@ export function focusWords(force = false): void {
170175

171176
export function keepWordsInputInTheCenter(force = false): void {
172177
const wordsInput = getInputElement();
173-
const wordsWrapper = document.querySelector<HTMLElement>("#wordsWrapper");
174-
if (wordsInput === null || wordsWrapper === null) return;
178+
if (wordsInput === null || wordsWrapperEl === null) return;
175179

176-
const wordsWrapperHeight = wordsWrapper.offsetHeight;
180+
const wordsWrapperHeight = wordsWrapperEl.offsetHeight;
177181
const windowHeight = window.innerHeight;
178182

179183
// dont do anything if the wrapper can fit on screen
@@ -191,8 +195,8 @@ export function keepWordsInputInTheCenter(force = false): void {
191195
}
192196

193197
export function getWordElement(index: number): HTMLElement | null {
194-
const el = document.querySelector<HTMLElement>(
195-
`#words .word[data-wordindex='${index}']`,
198+
const el = wordsEl.querySelector<HTMLElement>(
199+
`.word[data-wordindex='${index}']`,
196200
);
197201
return el;
198202
}
@@ -205,7 +209,7 @@ export function updateActiveElement(
205209
backspace?: boolean,
206210
initial = false,
207211
): void {
208-
const active = document.querySelector("#words .active");
212+
const active = wordsEl.querySelector(".active");
209213
if (!backspace) {
210214
active?.classList.add("typed");
211215
}
@@ -434,47 +438,46 @@ function buildWordHTML(word: string, wordIndex: number): string {
434438

435439
function updateWordWrapperClasses(): void {
436440
if (Config.tapeMode !== "off") {
437-
$("#words").addClass("tape");
438-
$("#wordsWrapper").addClass("tape");
441+
wordsEl.classList.add("tape");
442+
wordsWrapperEl.classList.add("tape");
439443
} else {
440-
$("#words").removeClass("tape");
441-
$("#wordsWrapper").removeClass("tape");
444+
wordsEl.classList.remove("tape");
445+
wordsWrapperEl.classList.remove("tape");
442446
}
443447

444448
if (Config.blindMode) {
445-
$("#words").addClass("blind");
446-
$("#wordsWrapper").addClass("blind");
449+
wordsEl.classList.add("blind");
450+
wordsWrapperEl.classList.add("blind");
447451
} else {
448-
$("#words").removeClass("blind");
449-
$("#wordsWrapper").removeClass("blind");
452+
wordsEl.classList.remove("blind");
453+
wordsWrapperEl.classList.remove("blind");
450454
}
451455

452456
if (Config.indicateTypos === "below" || Config.indicateTypos === "both") {
453-
$("#words").addClass("indicateTyposBelow");
454-
$("#wordsWrapper").addClass("indicateTyposBelow");
457+
wordsEl.classList.add("indicateTyposBelow");
458+
wordsWrapperEl.classList.add("indicateTyposBelow");
455459
} else {
456-
$("#words").removeClass("indicateTyposBelow");
457-
$("#wordsWrapper").removeClass("indicateTyposBelow");
460+
wordsEl.classList.remove("indicateTyposBelow");
461+
wordsWrapperEl.classList.remove("indicateTyposBelow");
458462
}
459463

460464
if (Config.hideExtraLetters) {
461-
$("#words").addClass("hideExtraLetters");
462-
$("#wordsWrapper").addClass("hideExtraLetters");
465+
wordsEl.classList.add("hideExtraLetters");
466+
wordsWrapperEl.classList.add("hideExtraLetters");
463467
} else {
464-
$("#words").removeClass("hideExtraLetters");
465-
$("#wordsWrapper").removeClass("hideExtraLetters");
468+
wordsEl.classList.remove("hideExtraLetters");
469+
wordsWrapperEl.classList.remove("hideExtraLetters");
466470
}
467471

468472
const existing =
469-
$("#words")
470-
?.attr("class")
471-
?.split(/\s+/)
472-
?.filter((it) => !it.startsWith("highlight-")) ?? [];
473+
wordsEl?.className
474+
.split(/\s+/)
475+
.filter((className) => !className.startsWith("highlight-")) ?? [];
473476
if (Config.highlightMode !== null) {
474477
existing.push("highlight-" + Config.highlightMode.replaceAll("_", "-"));
475478
}
476479

477-
$("#words").attr("class", existing.join(" "));
480+
wordsEl.className = existing.join(" ");
478481

479482
updateWordsWidth();
480483
updateWordsWrapperHeight(true);
@@ -485,9 +488,7 @@ function updateWordWrapperClasses(): void {
485488
}
486489

487490
export function showWords(): void {
488-
const words = $("#words");
489-
490-
words.empty();
491+
wordsEl.innerHTML = "";
491492

492493
if (Config.mode === "zen") {
493494
appendEmptyWordElement();
@@ -496,7 +497,7 @@ export function showWords(): void {
496497
for (let i = 0; i < TestWords.words.length; i++) {
497498
wordsHTML += buildWordHTML(TestWords.words.get(i), i);
498499
}
499-
words.html(wordsHTML);
500+
wordsEl.innerHTML = wordsHTML;
500501
}
501502

502503
updateActiveElement(undefined, true);
@@ -507,7 +508,8 @@ export function showWords(): void {
507508
export function appendEmptyWordElement(
508509
index = TestInput.input.getHistory().length,
509510
): void {
510-
$("#words").append(
511+
wordsEl.insertAdjacentHTML(
512+
"beforeend",
511513
`<div class='word' data-wordindex='${index}'><letter class='invisible'>_</letter></div>`,
512514
);
513515
}
@@ -520,9 +522,8 @@ export function updateWordsInputPosition(): void {
520522
: TestState.isLanguageRightToLeft;
521523

522524
const el = getInputElement();
523-
const wrapperElement = document.querySelector<HTMLElement>("#wordsWrapper");
524525

525-
if (el === null || wrapperElement === null) return;
526+
if (el === null) return;
526527

527528
const activeWord = getActiveWordElement();
528529

@@ -551,7 +552,7 @@ export function updateWordsInputPosition(): void {
551552

552553
if (Config.tapeMode !== "off") {
553554
el.style.left = `${
554-
wrapperElement.offsetWidth * (Config.tapeMargin / 100)
555+
wordsWrapperEl.offsetWidth * (Config.tapeMargin / 100)
555556
}px`;
556557
} else {
557558
if (activeWord.offsetWidth < letterHeight && isTestRightToLeft) {
@@ -598,14 +599,13 @@ export async function centerActiveLine(): Promise<void> {
598599
export function updateWordsWrapperHeight(force = false): void {
599600
if (ActivePage.get() !== "test" || TestState.resultVisible) return;
600601
if (!force && Config.mode !== "custom") return;
601-
const wrapperEl = document.getElementById("wordsWrapper") as HTMLElement;
602602
const outOfFocusEl = document.querySelector(
603603
".outOfFocusWarning",
604604
) as HTMLElement;
605605
const activeWordEl = getActiveWordElement();
606606
if (!activeWordEl) return;
607607

608-
wrapperEl.classList.remove("hidden");
608+
wordsWrapperEl.classList.remove("hidden");
609609

610610
const wordComputedStyle = window.getComputedStyle(activeWordEl);
611611
const wordMargin =
@@ -622,15 +622,14 @@ export function updateWordsWrapperHeight(force = false): void {
622622

623623
if (showAllLines) {
624624
//allow the wrapper to grow and shink with the words
625-
wrapperEl.style.height = "";
625+
wordsWrapperEl.style.height = "";
626626
} else if (Config.mode === "zen") {
627627
//zen mode, showAllLines off
628-
wrapperEl.style.height = wordHeight * 2 + "px";
628+
wordsWrapperEl.style.height = wordHeight * 2 + "px";
629629
} else {
630630
if (Config.tapeMode === "off") {
631631
//tape off, showAllLines off, non-zen mode
632-
const wordElements =
633-
document.querySelectorAll<HTMLElement>("#words .word");
632+
const wordElements = wordsEl.querySelectorAll<HTMLElement>(".word");
634633
let lines = 0;
635634
let lastTop = 0;
636635
let wordIndex = 0;
@@ -650,15 +649,14 @@ export function updateWordsWrapperHeight(force = false): void {
650649
if (lines < 3) wrapperHeight = wrapperHeight * (3 / lines);
651650

652651
//limit to 3 lines
653-
wrapperEl.style.height = wrapperHeight + "px";
652+
wordsWrapperEl.style.height = wrapperHeight + "px";
654653
} else {
655654
//show 3 lines if tape mode is on and has newlines, otherwise use words height (because of indicate typos: below)
656655
if (TestWords.hasNewline) {
657-
wrapperEl.style.height = wordHeight * 3 + "px";
656+
wordsWrapperEl.style.height = wordHeight * 3 + "px";
658657
} else {
659-
const wordsHeight =
660-
document.getElementById("words")?.offsetHeight ?? wordHeight;
661-
wrapperEl.style.height = wordsHeight + "px";
658+
const wordsHeight = wordsEl.offsetHeight ?? wordHeight;
659+
wordsWrapperEl.style.height = wordsHeight + "px";
662660
}
663661
}
664662
}
@@ -670,8 +668,6 @@ function updateWordsMargin(): void {
670668
if (Config.tapeMode !== "off") {
671669
void scrollTape(true);
672670
} else {
673-
const wordsEl = document.getElementById("words") as HTMLElement;
674-
675671
$(wordsEl).stop(true, false);
676672

677673
const afterNewlineEls =
@@ -688,22 +684,22 @@ export function addWord(
688684
word: string,
689685
wordIndex = TestWords.words.length - 1,
690686
): void {
691-
$("#words").append(buildWordHTML(word, wordIndex));
687+
wordsEl.insertAdjacentHTML("beforeend", buildWordHTML(word, wordIndex));
692688
}
693689

694690
export function flipColors(tf: boolean): void {
695691
if (tf) {
696-
$("#words").addClass("flipped");
692+
wordsEl.classList.add("flipped");
697693
} else {
698-
$("#words").removeClass("flipped");
694+
wordsEl.classList.remove("flipped");
699695
}
700696
}
701697

702698
export function colorful(tc: boolean): void {
703699
if (tc) {
704-
$("#words").addClass("colorfulMode");
700+
wordsEl.classList.add("colorfulMode");
705701
} else {
706-
$("#words").removeClass("colorfulMode");
702+
wordsEl.classList.remove("colorfulMode");
707703
}
708704
}
709705

@@ -846,7 +842,8 @@ export async function updateActiveWordLetters(
846842
}
847843

848844
if (newlineafter)
849-
$("#words").append(
845+
wordsEl.insertAdjacentHTML(
846+
"beforeend",
850847
"<div class='beforeNewline'></div><div class='newline'></div><div class='afterNewline'></div>",
851848
);
852849
if (Config.tapeMode !== "off") {
@@ -887,10 +884,7 @@ export async function scrollTape(noAnimation = false): Promise<void> {
887884
? !TestState.isLanguageRightToLeft
888885
: TestState.isLanguageRightToLeft;
889886

890-
const wordsWrapperWidth = (
891-
document.querySelector("#wordsWrapper") as HTMLElement
892-
).offsetWidth;
893-
const wordsEl = document.getElementById("words") as HTMLElement;
887+
const wordsWrapperWidth = wordsWrapperEl.offsetWidth;
894888
const wordsChildrenArr = [...wordsEl.children] as HTMLElement[];
895889
const activeWordEl = getActiveWordElement();
896890
if (!activeWordEl) return;
@@ -1096,7 +1090,7 @@ export function updatePremid(): void {
10961090
}
10971091

10981092
function removeTestElements(lastElementIndexToRemove: number): void {
1099-
const wordsChildren = document.getElementById("words")?.children;
1093+
const wordsChildren = wordsEl.children;
11001094

11011095
if (wordsChildren === undefined) return;
11021096

@@ -1118,7 +1112,6 @@ export async function lineJump(
11181112
if (currentTestLine > 0 || force) {
11191113
const hideBound = currentTop;
11201114

1121-
const wordsEl = document.getElementById("words") as HTMLElement;
11221115
const activeWordEl = getActiveWordElement();
11231116
if (!activeWordEl) {
11241117
resolve();
@@ -1195,23 +1188,23 @@ export async function lineJump(
11951188

11961189
export function setRightToLeft(isEnabled: boolean): void {
11971190
if (isEnabled) {
1198-
$("#words").addClass("rightToLeftTest");
1191+
wordsEl.classList.add("rightToLeftTest");
11991192
$("#resultWordsHistory .words").addClass("rightToLeftTest");
12001193
$("#resultReplay .words").addClass("rightToLeftTest");
12011194
} else {
1202-
$("#words").removeClass("rightToLeftTest");
1195+
wordsEl.classList.remove("rightToLeftTest");
12031196
$("#resultWordsHistory .words").removeClass("rightToLeftTest");
12041197
$("#resultReplay .words").removeClass("rightToLeftTest");
12051198
}
12061199
}
12071200

12081201
export function setLigatures(isEnabled: boolean): void {
12091202
if (isEnabled || Config.mode === "custom" || Config.mode === "zen") {
1210-
$("#words").addClass("withLigatures");
1203+
wordsEl.classList.add("withLigatures");
12111204
$("#resultWordsHistory .words").addClass("withLigatures");
12121205
$("#resultReplay .words").addClass("withLigatures");
12131206
} else {
1214-
$("#words").removeClass("withLigatures");
1207+
wordsEl.classList.remove("withLigatures");
12151208
$("#resultWordsHistory .words").removeClass("withLigatures");
12161209
$("#resultReplay .words").removeClass("withLigatures");
12171210
}
@@ -1383,9 +1376,7 @@ export function toggleResultWords(noAnimation = false): void {
13831376
//show
13841377

13851378
if ($("#resultWordsHistory .words .word").length === 0) {
1386-
$("#words").html(
1387-
`<div class="preloader"><i class="fas fa-fw fa-spin fa-circle-notch"></i></div>`,
1388-
);
1379+
wordsEl.innerHTML = `<div class="preloader"><i class="fas fa-fw fa-spin fa-circle-notch"></i></div>`;
13891380
void loadWordsHistory().then(() => {
13901381
if (Config.burstHeatmap) {
13911382
void applyBurstHeatmap();
@@ -1785,9 +1776,7 @@ export async function afterTestWordChange(
17851776
}
17861777
} else if (direction === "back") {
17871778
if (Config.mode === "zen") {
1788-
const wordsChildren = [
1789-
...(document.querySelector("#words")?.children ?? []),
1790-
] as HTMLElement[];
1779+
const wordsChildren = [...(wordsEl.children ?? [])] as HTMLElement[];
17911780

17921781
let deleteElements = false;
17931782
for (const child of wordsChildren) {

0 commit comments

Comments
 (0)