@@ -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+
140145export let activeWordTop = 0 ;
141146export let lineTransition = false ;
142147export let currentTestLine = 0 ;
@@ -170,10 +175,9 @@ export function focusWords(force = false): void {
170175
171176export 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
193197export 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
435439function 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
487490export 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 {
507508export 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> {
598599export 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
694690export 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
702698export 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
10981092function 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
11961189export 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
12081201export 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