@testgorilla/tgo-typing-test 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/testgorilla-tgo-typing-test.mjs +4691 -0
- package/fesm2022/testgorilla-tgo-typing-test.mjs.map +1 -0
- package/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.d.ts +14 -0
- package/lib/components/tgo-typing-test/tgo-typing-test.component.d.ts +54 -0
- package/lib/helpers/config.d.ts +98 -0
- package/lib/helpers/constants/default-config.d.ts +3 -0
- package/lib/helpers/controllers/input-controller.d.ts +16 -0
- package/lib/helpers/controllers/quotes-controller.d.ts +20 -0
- package/lib/helpers/observables/config-event.d.ts +5 -0
- package/lib/helpers/observables/timer-event.d.ts +4 -0
- package/lib/helpers/states/active-page.d.ts +2 -0
- package/lib/helpers/states/composition.d.ts +10 -0
- package/lib/helpers/states/page-transition.d.ts +2 -0
- package/lib/helpers/states/slow-timer.d.ts +3 -0
- package/lib/helpers/states/test-active.d.ts +2 -0
- package/lib/helpers/states/time.d.ts +3 -0
- package/lib/helpers/test/caps-warning.d.ts +5 -0
- package/lib/helpers/test/caret.d.ts +11 -0
- package/lib/helpers/test/custom-text.d.ts +16 -0
- package/lib/helpers/test/english-punctuation.d.ts +3 -0
- package/lib/helpers/test/focus.d.ts +7 -0
- package/lib/helpers/test/manual-restart-tracker.d.ts +3 -0
- package/lib/helpers/test/out-of-focus.d.ts +4 -0
- package/lib/helpers/test/replay.d.ts +20 -0
- package/lib/helpers/test/test-input.d.ts +86 -0
- package/lib/helpers/test/test-logic.d.ts +25 -0
- package/lib/helpers/test/test-state.d.ts +7 -0
- package/lib/helpers/test/test-stats.d.ts +92 -0
- package/lib/helpers/test/test-timer.d.ts +6 -0
- package/lib/helpers/test/test-ui.d.ts +27 -0
- package/lib/helpers/test/test-words.d.ts +23 -0
- package/lib/helpers/test/timer-progress.d.ts +3 -0
- package/lib/helpers/test/weak-spot.d.ts +3 -0
- package/lib/helpers/test/wordset.d.ts +7 -0
- package/lib/utils/misc.d.ts +80 -0
- package/package.json +17 -4
- package/.eslintrc.json +0 -46
- package/jest.config.ts +0 -21
- package/ng-package.json +0 -15
- package/project.json +0 -36
- package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.html +0 -30
- package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.spec.ts +0 -250
- package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.ts +0 -47
- package/src/lib/components/tgo-typing-test/tgo-typing-test.component.html +0 -72
- package/src/lib/components/tgo-typing-test/tgo-typing-test.component.spec.ts +0 -699
- package/src/lib/components/tgo-typing-test/tgo-typing-test.component.ts +0 -287
- package/src/lib/helpers/config.ts +0 -28
- package/src/lib/helpers/constants/default-config.ts +0 -103
- package/src/lib/helpers/controllers/input-controller.ts +0 -710
- package/src/lib/helpers/controllers/quotes-controller.ts +0 -183
- package/src/lib/helpers/observables/banner-event.ts +0 -18
- package/src/lib/helpers/observables/config-event.ts +0 -31
- package/src/lib/helpers/observables/timer-event.ts +0 -18
- package/src/lib/helpers/states/active-page.ts +0 -9
- package/src/lib/helpers/states/composition.ts +0 -29
- package/src/lib/helpers/states/page-transition.ts +0 -9
- package/src/lib/helpers/states/slow-timer.ts +0 -16
- package/src/lib/helpers/states/test-active.ts +0 -9
- package/src/lib/helpers/states/time.ts +0 -13
- package/src/lib/helpers/test/caps-warning.ts +0 -50
- package/src/lib/helpers/test/caret.ts +0 -92
- package/src/lib/helpers/test/custom-text.ts +0 -73
- package/src/lib/helpers/test/english-punctuation.ts +0 -38
- package/src/lib/helpers/test/focus.ts +0 -39
- package/src/lib/helpers/test/manual-restart-tracker.ts +0 -13
- package/src/lib/helpers/test/out-of-focus.ts +0 -19
- package/src/lib/helpers/test/replay.ts +0 -265
- package/src/lib/helpers/test/test-input.ts +0 -320
- package/src/lib/helpers/test/test-logic.ts +0 -1039
- package/src/lib/helpers/test/test-state.ts +0 -17
- package/src/lib/helpers/test/test-stats.ts +0 -442
- package/src/lib/helpers/test/test-timer.ts +0 -209
- package/src/lib/helpers/test/test-ui.ts +0 -370
- package/src/lib/helpers/test/test-words.ts +0 -72
- package/src/lib/helpers/test/timer-progress.ts +0 -16
- package/src/lib/helpers/test/tts.ts +0 -42
- package/src/lib/helpers/test/weak-spot.ts +0 -74
- package/src/lib/helpers/test/wordset.ts +0 -109
- package/src/lib/styles/animations.scss +0 -101
- package/src/lib/styles/caret.scss +0 -108
- package/src/lib/styles/core.scss +0 -498
- package/src/lib/styles/index.scss +0 -19
- package/src/lib/styles/inputs.scss +0 -290
- package/src/lib/styles/popups.scss +0 -1311
- package/src/lib/styles/test.scss +0 -1008
- package/src/lib/styles/z_media-queries.scss +0 -848
- package/src/lib/types/types.d.ts +0 -731
- package/src/lib/utils/misc.ts +0 -776
- package/src/test-setup.ts +0 -20
- package/tsconfig.json +0 -16
- package/tsconfig.lib.json +0 -14
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -11
- /package/{src/assets → assets}/typing-test-languages/english.json +0 -0
- /package/{src/assets → assets}/typing-test-languages/english_punctuation.json +0 -0
- /package/{src/assets → assets}/typing-test-languages/quotes/english_version_1.json +0 -0
- /package/{src/assets → assets}/typing-test-languages/quotes/english_version_2.json +0 -0
- /package/{src/assets → assets}/typing-test-languages/quotes/filtered_sources.json +0 -0
- /package/{src/index.ts → index.d.ts} +0 -0
|
@@ -1,710 +0,0 @@
|
|
|
1
|
-
import * as TestLogic from '../test/test-logic';
|
|
2
|
-
import * as TestUI from '../test/test-ui';
|
|
3
|
-
import * as TestStats from '../test/test-stats';
|
|
4
|
-
import Config, * as UpdateConfig from '../config';
|
|
5
|
-
import * as Misc from '../../utils/misc';
|
|
6
|
-
import * as Caret from '../test/caret';
|
|
7
|
-
import * as CustomText from '../test/custom-text';
|
|
8
|
-
import * as TimerProgress from '../test/timer-progress';
|
|
9
|
-
import * as Focus from '../test/focus';
|
|
10
|
-
import * as Replay from '../test/replay';
|
|
11
|
-
import * as WeakSpot from '../test/weak-spot';
|
|
12
|
-
import * as TestActive from '../states/test-active';
|
|
13
|
-
import * as CompositionState from '../states/composition';
|
|
14
|
-
import * as TestInput from '../test/test-input';
|
|
15
|
-
import * as TestWords from '../test/test-words';
|
|
16
|
-
|
|
17
|
-
let dontInsertSpace = false;
|
|
18
|
-
const correctShiftUsed = true;
|
|
19
|
-
|
|
20
|
-
let wordsInput: HTMLInputElement;
|
|
21
|
-
|
|
22
|
-
function setWordsInput(value: string): void {
|
|
23
|
-
// Only change #wordsInput if it's not already the wanted value
|
|
24
|
-
// Avoids Safari triggering unneeded events, causing issues with
|
|
25
|
-
// dead keys.
|
|
26
|
-
if (value !== wordsInput.value) {
|
|
27
|
-
wordsInput.value = value;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function updateUI(): void {
|
|
32
|
-
const acc = Misc.roundTo2(TestStats.calculateAccuracy());
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function backspaceToPrevious(): void {
|
|
36
|
-
if (!TestActive.get()) return;
|
|
37
|
-
|
|
38
|
-
if (TestInput.input.history.length == 0 || TestUI.currentWordElementIndex == 0) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
(TestInput.input.history[TestWords.words.currentIndex - 1] ==
|
|
44
|
-
TestWords.words.get(TestWords.words.currentIndex - 1) &&
|
|
45
|
-
!Config.freedomMode) ||
|
|
46
|
-
document
|
|
47
|
-
.querySelectorAll('.word')
|
|
48
|
-
[TestWords.words.currentIndex - 1]?.classList.contains('hidden')
|
|
49
|
-
) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (Config.confidenceMode === 'on' || Config.confidenceMode === 'max') {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
TestInput.input.current = TestInput.input.popHistory();
|
|
58
|
-
TestInput.corrected.popHistory();
|
|
59
|
-
if (Config.funbox === 'nospace' || Config.funbox === 'arrows') {
|
|
60
|
-
TestInput.input.current = TestInput.input.current.slice(0, -1);
|
|
61
|
-
}
|
|
62
|
-
TestWords.words.decreaseCurrentIndex();
|
|
63
|
-
TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex - 1);
|
|
64
|
-
TestUI.updateActiveElement(true);
|
|
65
|
-
TestUI.updateWordElement();
|
|
66
|
-
|
|
67
|
-
Caret.updatePosition();
|
|
68
|
-
Replay.addReplayEvent('backWord');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function handleSpace(): void {
|
|
72
|
-
if (!TestActive.get()) return;
|
|
73
|
-
|
|
74
|
-
if (TestInput.input.current === '') return;
|
|
75
|
-
|
|
76
|
-
const currentWord = TestWords.words.getCurrent();
|
|
77
|
-
if (Config.funbox === 'layoutfluid' && Config.mode !== 'time') {
|
|
78
|
-
// here I need to check if Config.customLayoutFluid exists because of my scuffed solution of returning whenever value is undefined in the setCustomLayoutfluid function
|
|
79
|
-
const layouts = Config.customLayoutfluid
|
|
80
|
-
? Config.customLayoutfluid.split('#')
|
|
81
|
-
: ['qwerty', 'dvorak', 'colemak'];
|
|
82
|
-
let index = 0;
|
|
83
|
-
const outof = TestWords.words.length;
|
|
84
|
-
index = Math.floor((TestInput.input.history.length + 1) / (outof / layouts.length));
|
|
85
|
-
}
|
|
86
|
-
dontInsertSpace = true;
|
|
87
|
-
|
|
88
|
-
const burst = TestStats.calculateBurst();
|
|
89
|
-
TestInput.pushBurstToHistory(burst);
|
|
90
|
-
|
|
91
|
-
//correct word or in zen mode
|
|
92
|
-
const isWordCorrect = currentWord == TestInput.input.current || Config.mode == 'zen';
|
|
93
|
-
TestInput.incrementAccuracy(isWordCorrect);
|
|
94
|
-
if (isWordCorrect) {
|
|
95
|
-
TestInput.input.pushHistory();
|
|
96
|
-
TestWords.words.increaseCurrentIndex();
|
|
97
|
-
TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex + 1);
|
|
98
|
-
TestUI.updateActiveElement();
|
|
99
|
-
Caret.updatePosition();
|
|
100
|
-
TestInput.incrementKeypressCount();
|
|
101
|
-
TestInput.pushKeypressWord(TestWords.words.currentIndex);
|
|
102
|
-
Replay.addReplayEvent('submitCorrectWord');
|
|
103
|
-
} else {
|
|
104
|
-
TestInput.pushMissedWord(TestWords.words.getCurrent());
|
|
105
|
-
TestInput.incrementKeypressErrors();
|
|
106
|
-
const cil = TestInput.input.current.length;
|
|
107
|
-
if (cil <= TestWords.words.getCurrent().length) {
|
|
108
|
-
if (cil >= TestInput.corrected.current.length) {
|
|
109
|
-
TestInput.corrected.current += '_';
|
|
110
|
-
} else {
|
|
111
|
-
TestInput.corrected.current =
|
|
112
|
-
TestInput.corrected.current.substring(0, cil) +
|
|
113
|
-
'_' +
|
|
114
|
-
TestInput.corrected.current.substring(cil + 1);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (Config.stopOnError != 'off') {
|
|
118
|
-
if (Config.difficulty == 'expert' || Config.difficulty == 'master') {
|
|
119
|
-
//failed due to diff when pressing space
|
|
120
|
-
TestLogic.fail('difficulty');
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
if (Config.stopOnError == 'word') {
|
|
124
|
-
dontInsertSpace = false;
|
|
125
|
-
Replay.addReplayEvent('incorrectLetter', '_');
|
|
126
|
-
TestUI.updateWordElement(true);
|
|
127
|
-
Caret.updatePosition();
|
|
128
|
-
}
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
TestInput.input.pushHistory();
|
|
132
|
-
TestUI.highlightBadWord(TestUI.currentWordElementIndex, !Config.blindMode);
|
|
133
|
-
TestWords.words.increaseCurrentIndex();
|
|
134
|
-
TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex + 1);
|
|
135
|
-
TestUI.updateActiveElement();
|
|
136
|
-
Caret.updatePosition();
|
|
137
|
-
TestInput.incrementKeypressCount();
|
|
138
|
-
TestInput.pushKeypressWord(TestWords.words.currentIndex);
|
|
139
|
-
TestInput.updateLastKeypress();
|
|
140
|
-
if (Config.difficulty == 'expert' || Config.difficulty == 'master') {
|
|
141
|
-
TestLogic.fail('difficulty');
|
|
142
|
-
return;
|
|
143
|
-
} else if (TestWords.words.currentIndex == TestWords.words.length) {
|
|
144
|
-
//submitted last word that is incorrect
|
|
145
|
-
TestLogic.finish();
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
Replay.addReplayEvent('submitErrorWord');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
let wordLength;
|
|
152
|
-
if (Config.mode === 'zen') {
|
|
153
|
-
wordLength = TestInput.input.current.length;
|
|
154
|
-
} else {
|
|
155
|
-
wordLength = TestWords.words.getCurrent().length;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const flex = Misc.whorf(Config.minBurstCustomSpeed, wordLength);
|
|
159
|
-
|
|
160
|
-
TestInput.corrected.pushHistory();
|
|
161
|
-
|
|
162
|
-
if (
|
|
163
|
-
!Config.showAllLines ||
|
|
164
|
-
Config.mode == 'time' ||
|
|
165
|
-
(CustomText.isWordRandom && CustomText.word == 0) ||
|
|
166
|
-
CustomText.isTimeRandom
|
|
167
|
-
) {
|
|
168
|
-
const currentTop = Math.floor(
|
|
169
|
-
document.querySelectorAll<HTMLElement>('#words .word')[TestUI.currentWordElementIndex - 1]
|
|
170
|
-
.offsetTop
|
|
171
|
-
);
|
|
172
|
-
let nextTop;
|
|
173
|
-
try {
|
|
174
|
-
nextTop = Math.floor(
|
|
175
|
-
document.querySelectorAll<HTMLElement>('#words .word')[TestUI.currentWordElementIndex]
|
|
176
|
-
.offsetTop
|
|
177
|
-
);
|
|
178
|
-
} catch (e) {
|
|
179
|
-
nextTop = 0;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (nextTop > currentTop && !TestUI.lineTransition) {
|
|
183
|
-
TestUI.lineJump(currentTop);
|
|
184
|
-
}
|
|
185
|
-
} //end of line wrap
|
|
186
|
-
|
|
187
|
-
if (
|
|
188
|
-
Config.mode === 'words' ||
|
|
189
|
-
Config.mode === 'custom' ||
|
|
190
|
-
Config.mode === 'quote' ||
|
|
191
|
-
Config.mode === 'zen'
|
|
192
|
-
) {
|
|
193
|
-
TimerProgress.update();
|
|
194
|
-
}
|
|
195
|
-
if (
|
|
196
|
-
Config.mode == 'time' ||
|
|
197
|
-
Config.mode == 'words' ||
|
|
198
|
-
Config.mode == 'custom' ||
|
|
199
|
-
Config.mode == 'quote'
|
|
200
|
-
) {
|
|
201
|
-
TestLogic.addWord();
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function isCharCorrect(char: string, charIndex: number): boolean {
|
|
206
|
-
if (!correctShiftUsed) return false;
|
|
207
|
-
|
|
208
|
-
if (Config.mode == 'zen') {
|
|
209
|
-
return true;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const originalChar = TestWords.words.getCurrent()[charIndex];
|
|
213
|
-
|
|
214
|
-
if (originalChar == char) {
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (Config.language.split('_')[0] == 'russian') {
|
|
219
|
-
if ((char === 'е' || char === 'e') && originalChar == 'ё') {
|
|
220
|
-
return true;
|
|
221
|
-
}
|
|
222
|
-
if (char === 'ё' && (originalChar == 'е' || originalChar === 'e')) {
|
|
223
|
-
return true;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (Config.funbox === 'arrows') {
|
|
228
|
-
if ((char === 'w' || char === 'ArrowUp') && originalChar == '↑') {
|
|
229
|
-
return true;
|
|
230
|
-
}
|
|
231
|
-
if ((char === 's' || char === 'ArrowDown') && originalChar == '↓') {
|
|
232
|
-
return true;
|
|
233
|
-
}
|
|
234
|
-
if ((char === 'a' || char === 'ArrowLeft') && originalChar == '←') {
|
|
235
|
-
return true;
|
|
236
|
-
}
|
|
237
|
-
if ((char === 'd' || char === 'ArrowRight') && originalChar == '→') {
|
|
238
|
-
return true;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (
|
|
243
|
-
(char === `’` || char === '‘' || char === "'") &&
|
|
244
|
-
(originalChar == `’` || originalChar === '‘' || originalChar === "'")
|
|
245
|
-
) {
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (
|
|
250
|
-
(char === `"` || char === '”' || char == '“' || char === '„') &&
|
|
251
|
-
(originalChar == `"` || originalChar === '”' || originalChar === '“' || originalChar === '„')
|
|
252
|
-
) {
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
(char === '–' || char === '—' || char == '-') &&
|
|
258
|
-
(originalChar == '-' || originalChar === '–' || originalChar === '—')
|
|
259
|
-
) {
|
|
260
|
-
return true;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function handleChar(char: string, charIndex: number): void {
|
|
267
|
-
if (TestUI.resultCalculating || TestUI.resultVisible) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (char === '…') {
|
|
272
|
-
for (let i = 0; i < 3; i++) {
|
|
273
|
-
handleChar('.', charIndex + i);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (char === '\n' && (Config.funbox === '58008' || Config.funbox === 'tenKeyMode')) {
|
|
280
|
-
char = ' ';
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (char !== '\n' && char !== '\t' && /\s/.test(char)) {
|
|
284
|
-
if (Config.funbox === 'nospace' || Config.funbox === 'arrows') return;
|
|
285
|
-
handleSpace();
|
|
286
|
-
|
|
287
|
-
//insert space for expert and master or strict space,
|
|
288
|
-
//or for stop on error set to word,
|
|
289
|
-
//otherwise dont do anything
|
|
290
|
-
if (
|
|
291
|
-
Config.difficulty !== 'normal' ||
|
|
292
|
-
(Config.strictSpace && Config.mode !== 'zen') ||
|
|
293
|
-
Config.stopOnError === 'word'
|
|
294
|
-
) {
|
|
295
|
-
if (dontInsertSpace) {
|
|
296
|
-
dontInsertSpace = false;
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (Config.mode !== 'zen' && TestWords.words.getCurrent()[charIndex] !== '\n' && char === '\n') {
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
//start the test
|
|
309
|
-
if (!TestActive.get() && !TestLogic.startTest()) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
Focus.set(true);
|
|
314
|
-
Caret.stopAnimation();
|
|
315
|
-
|
|
316
|
-
const thisCharCorrect = isCharCorrect(char, charIndex);
|
|
317
|
-
|
|
318
|
-
if (thisCharCorrect && Config.mode !== 'zen') {
|
|
319
|
-
char = TestWords.words.getCurrent().charAt(charIndex);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (!thisCharCorrect && char === '\n') {
|
|
323
|
-
if (TestInput.input.current === '') return;
|
|
324
|
-
char = ' ';
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (TestInput.input.current === '') {
|
|
328
|
-
TestInput.setBurstStart(performance.now());
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const resultingWord =
|
|
332
|
-
TestInput.input.current.substring(0, charIndex) +
|
|
333
|
-
char +
|
|
334
|
-
TestInput.input.current.substring(charIndex + 1);
|
|
335
|
-
|
|
336
|
-
// If a trailing composed char is used, ignore it when counting accuracy
|
|
337
|
-
if (
|
|
338
|
-
!thisCharCorrect &&
|
|
339
|
-
Misc.trailingComposeChars.test(resultingWord) &&
|
|
340
|
-
CompositionState.getComposing()
|
|
341
|
-
) {
|
|
342
|
-
TestInput.input.current = resultingWord;
|
|
343
|
-
TestUI.updateWordElement();
|
|
344
|
-
Caret.updatePosition();
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// MonkeyPower.addPower(thisCharCorrect);
|
|
349
|
-
TestInput.incrementAccuracy(thisCharCorrect);
|
|
350
|
-
|
|
351
|
-
if (!thisCharCorrect) {
|
|
352
|
-
TestInput.incrementKeypressErrors();
|
|
353
|
-
TestInput.pushMissedWord(TestWords.words.getCurrent());
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
WeakSpot.updateScore(
|
|
357
|
-
Config.mode === 'zen' ? char : TestWords.words.getCurrent()[charIndex],
|
|
358
|
-
thisCharCorrect
|
|
359
|
-
);
|
|
360
|
-
|
|
361
|
-
if (!correctShiftUsed && Config.difficulty != 'master') return;
|
|
362
|
-
|
|
363
|
-
//update current corrected version. if its empty then add the current char. if its not then replace the last character with the currently pressed one / add it
|
|
364
|
-
if (TestInput.corrected.current === '') {
|
|
365
|
-
TestInput.corrected.current += resultingWord;
|
|
366
|
-
} else {
|
|
367
|
-
if (charIndex >= TestInput.corrected.current.length) {
|
|
368
|
-
TestInput.corrected.current += char;
|
|
369
|
-
} else if (!thisCharCorrect) {
|
|
370
|
-
TestInput.corrected.current =
|
|
371
|
-
TestInput.corrected.current.substring(0, charIndex) +
|
|
372
|
-
char +
|
|
373
|
-
TestInput.corrected.current.substring(charIndex + 1);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
TestInput.incrementKeypressCount();
|
|
378
|
-
TestInput.updateLastKeypress();
|
|
379
|
-
TestInput.pushKeypressWord(TestWords.words.currentIndex);
|
|
380
|
-
|
|
381
|
-
if (Config.difficulty !== 'master' && Config.stopOnError == 'letter' && !thisCharCorrect) {
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
Replay.addReplayEvent(thisCharCorrect ? 'correctLetter' : 'incorrectLetter', char);
|
|
386
|
-
|
|
387
|
-
//update the active word top, but only once
|
|
388
|
-
if (TestInput.input.current.length === 1 && TestWords.words.currentIndex === 0) {
|
|
389
|
-
TestUI.setActiveWordTop((<HTMLElement>document.querySelector('#words .active'))?.offsetTop);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
//max length of the input is 20 unless in zen mode then its 30
|
|
393
|
-
if (
|
|
394
|
-
(Config.mode === 'zen' && charIndex < 30) ||
|
|
395
|
-
(Config.mode !== 'zen' && charIndex < TestWords.words.getCurrent().length + 20)
|
|
396
|
-
) {
|
|
397
|
-
TestInput.input.current = resultingWord;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (!thisCharCorrect && Config.difficulty == 'master') {
|
|
401
|
-
TestInput.input.pushHistory();
|
|
402
|
-
TestInput.corrected.pushHistory();
|
|
403
|
-
TestLogic.fail('difficulty');
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
if (Config.mode != 'zen') {
|
|
408
|
-
//not applicable to zen mode
|
|
409
|
-
//auto stop the test if the last word is correct
|
|
410
|
-
const currentWord = TestWords.words.getCurrent();
|
|
411
|
-
const lastindex = TestWords.words.currentIndex;
|
|
412
|
-
if (
|
|
413
|
-
(currentWord == TestInput.input.current ||
|
|
414
|
-
(Config.quickEnd &&
|
|
415
|
-
currentWord.length == TestInput.input.current.length &&
|
|
416
|
-
Config.stopOnError == 'off')) &&
|
|
417
|
-
lastindex == TestWords.words.length - 1
|
|
418
|
-
) {
|
|
419
|
-
TestInput.input.pushHistory();
|
|
420
|
-
TestInput.corrected.pushHistory();
|
|
421
|
-
TestLogic.finish();
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
const activeWordTopBeforeJump = document.querySelector<HTMLElement>('#words .word.active')
|
|
427
|
-
?.offsetTop as number;
|
|
428
|
-
TestUI.updateWordElement();
|
|
429
|
-
|
|
430
|
-
if (!Config.hideExtraLetters) {
|
|
431
|
-
const newActiveTop = document.querySelector<HTMLElement>('#words .word.active')
|
|
432
|
-
?.offsetTop as number;
|
|
433
|
-
//stop the word jump by slicing off the last character, update word again
|
|
434
|
-
if (
|
|
435
|
-
activeWordTopBeforeJump < newActiveTop &&
|
|
436
|
-
!TestUI.lineTransition &&
|
|
437
|
-
TestInput.input.current.length > 1
|
|
438
|
-
) {
|
|
439
|
-
if (Config.mode == 'zen') {
|
|
440
|
-
const currentTop = Math.floor(
|
|
441
|
-
document.querySelectorAll<HTMLElement>('#words .word')[TestUI.currentWordElementIndex - 1]
|
|
442
|
-
?.offsetTop
|
|
443
|
-
) as number;
|
|
444
|
-
if (!Config.showAllLines) TestUI.lineJump(currentTop);
|
|
445
|
-
} else {
|
|
446
|
-
TestInput.input.current = TestInput.input.current.slice(0, -1);
|
|
447
|
-
TestUI.updateWordElement();
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
//simulate space press in nospace funbox
|
|
453
|
-
if (
|
|
454
|
-
((Config.funbox === 'nospace' || Config.funbox === 'arrows') &&
|
|
455
|
-
TestInput.input.current.length === TestWords.words.getCurrent().length) ||
|
|
456
|
-
(char === '\n' && thisCharCorrect)
|
|
457
|
-
) {
|
|
458
|
-
handleSpace();
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if (char !== '\n') {
|
|
462
|
-
Caret.updatePosition();
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
function handleTab(
|
|
467
|
-
event: { preventDefault: () => void; shiftKey: any },
|
|
468
|
-
popupVisible: boolean
|
|
469
|
-
): void {
|
|
470
|
-
if (TestUI.resultCalculating) {
|
|
471
|
-
event.preventDefault();
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
let shouldInsertTabCharacter = false;
|
|
476
|
-
|
|
477
|
-
if ((Config.mode == 'zen' && !event.shiftKey) || (TestWords.hasTab && !event.shiftKey)) {
|
|
478
|
-
shouldInsertTabCharacter = true;
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
export function setWordsInputElement(wordsElement: HTMLInputElement) {
|
|
483
|
-
wordsInput = wordsElement;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
export async function inputKeydown(event: any, wordsFocused: boolean) {
|
|
487
|
-
const allowTyping = !TestUI.resultVisible && (wordsFocused || event.key !== 'Enter');
|
|
488
|
-
|
|
489
|
-
//no space for tenKeyMode
|
|
490
|
-
if (Config.funbox === 'tenKeyMode' && event.keyCode === 32) {
|
|
491
|
-
event.preventDefault();
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
if (allowTyping && !wordsFocused && event.key !== 'Enter') {
|
|
495
|
-
TestUI.focusWords();
|
|
496
|
-
if (Config.showOutOfFocusWarning) {
|
|
497
|
-
event.preventDefault();
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
//tab
|
|
502
|
-
if (event.key == 'Tab') {
|
|
503
|
-
handleTab(event, false);
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
if (!allowTyping) return;
|
|
507
|
-
|
|
508
|
-
if (!event.isTrusted || TestUI.testRestarting) {
|
|
509
|
-
event.preventDefault();
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
if (TestInput.spacingDebug) {
|
|
514
|
-
console.log(
|
|
515
|
-
'spacing debug',
|
|
516
|
-
'keypress',
|
|
517
|
-
event.key,
|
|
518
|
-
'length',
|
|
519
|
-
TestInput.keypressTimings.spacing.array.length
|
|
520
|
-
);
|
|
521
|
-
}
|
|
522
|
-
TestInput.recordKeypressSpacing();
|
|
523
|
-
TestInput.setKeypressDuration(performance.now());
|
|
524
|
-
TestInput.setKeypressNotAfk();
|
|
525
|
-
|
|
526
|
-
//blocking firefox from going back in history with backspace
|
|
527
|
-
if (event.key === 'Backspace') {
|
|
528
|
-
const t = /INPUT|SELECT|TEXTAREA/i;
|
|
529
|
-
if (!t.test((event.target as unknown as Element).tagName)) {
|
|
530
|
-
event.preventDefault();
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
if (Config.confidenceMode === 'max') {
|
|
534
|
-
event.preventDefault();
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (Config.funbox !== 'arrows' && /Arrow/i.test(event.key)) {
|
|
540
|
-
event.preventDefault();
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
if (event.key === 'Backspace' && TestInput.input.current.length === 0) {
|
|
545
|
-
backspaceToPrevious();
|
|
546
|
-
if (TestInput.input.current) {
|
|
547
|
-
setWordsInput(' ' + TestInput.input.current + ' ');
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
if (event.key === 'Enter') {
|
|
552
|
-
if (event.shiftKey && Config.mode == 'zen') {
|
|
553
|
-
TestLogic.finish();
|
|
554
|
-
} else if (
|
|
555
|
-
event.shiftKey &&
|
|
556
|
-
((Config.mode == 'time' && Config.time === 0) ||
|
|
557
|
-
(Config.mode == 'words' && Config.words === 0))
|
|
558
|
-
) {
|
|
559
|
-
TestInput.setBailout(true);
|
|
560
|
-
TestLogic.finish();
|
|
561
|
-
} else {
|
|
562
|
-
handleChar('\n', TestInput.input.current.length);
|
|
563
|
-
setWordsInput(' ' + TestInput.input.current);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
//show dead keys
|
|
568
|
-
if (event.key === 'Dead' && !CompositionState.getComposing()) {
|
|
569
|
-
const word = document.querySelector<HTMLElement>('#words .word.active');
|
|
570
|
-
const len = TestInput.input.current.length; // have to do this because prettier wraps the line and causes an error
|
|
571
|
-
|
|
572
|
-
// Check to see if the letter actually exists to toggle it as dead
|
|
573
|
-
const deadLetter = word?.querySelectorAll('letter')[len];
|
|
574
|
-
if (deadLetter) {
|
|
575
|
-
deadLetter.classList.toggle('dead');
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
if (Config.funbox === 'arrows') {
|
|
580
|
-
let char = event.key;
|
|
581
|
-
if (['ArrowLeft', 'ArrowUp', 'ArrowRight', 'ArrowDown'].includes(char)) {
|
|
582
|
-
if (char === 'ArrowLeft') char = 'a';
|
|
583
|
-
if (char === 'ArrowRight') char = 'd';
|
|
584
|
-
if (char === 'ArrowDown') char = 's';
|
|
585
|
-
if (char === 'ArrowUp') char = 'w';
|
|
586
|
-
event.preventDefault();
|
|
587
|
-
handleChar(char, TestInput.input.current.length);
|
|
588
|
-
updateUI();
|
|
589
|
-
setWordsInput(' ' + TestInput.input.current);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
export function wordsInputKeyup(event: any) {
|
|
595
|
-
if (!event.isTrusted || TestUI.testRestarting) {
|
|
596
|
-
event.preventDefault();
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
if (TestUI.resultVisible) return;
|
|
601
|
-
const now = performance.now();
|
|
602
|
-
if (TestInput.keypressTimings.duration.current !== -1) {
|
|
603
|
-
const diff = Math.abs(TestInput.keypressTimings.duration.current - now);
|
|
604
|
-
TestInput.pushKeypressDuration(diff);
|
|
605
|
-
}
|
|
606
|
-
TestInput.setKeypressDuration(now);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
export function wordsInputBeforeinput(event: any) {
|
|
610
|
-
if (!event.isTrusted) return;
|
|
611
|
-
if ((event.target as HTMLInputElement).value === '') {
|
|
612
|
-
(event.target as HTMLInputElement).value = ' ';
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
export function wordsInputInput(event: any) {
|
|
617
|
-
if (!event.isTrusted || TestUI.testRestarting) {
|
|
618
|
-
(event.target as HTMLInputElement).value = ' ';
|
|
619
|
-
return;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
TestInput.setKeypressNotAfk();
|
|
623
|
-
|
|
624
|
-
const realInputValue = (event.target as HTMLInputElement).value.normalize();
|
|
625
|
-
const inputValue = realInputValue.slice(1);
|
|
626
|
-
|
|
627
|
-
// input will be modified even with the preventDefault() in
|
|
628
|
-
// beforeinput/keydown if it's part of a compose sequence. this undoes
|
|
629
|
-
// the effects of that and takes the input out of compose mode.
|
|
630
|
-
if (Config.layout !== 'default' && inputValue.length >= TestInput.input.current.length) {
|
|
631
|
-
setWordsInput(' ' + TestInput.input.current);
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
if (realInputValue.length === 0 && TestInput.input.current.length === 0) {
|
|
636
|
-
// fallback for when no Backspace keydown event (mobile)
|
|
637
|
-
backspaceToPrevious();
|
|
638
|
-
} else if (inputValue.length < TestInput.input.current.length) {
|
|
639
|
-
TestInput.input.current = inputValue;
|
|
640
|
-
TestUI.updateWordElement();
|
|
641
|
-
Caret.updatePosition();
|
|
642
|
-
if (!CompositionState.getComposing()) {
|
|
643
|
-
Replay.addReplayEvent('setLetterIndex', TestInput.input.current.length);
|
|
644
|
-
}
|
|
645
|
-
} else if (inputValue !== TestInput.input.current) {
|
|
646
|
-
let diffStart = 0;
|
|
647
|
-
while (inputValue[diffStart] === TestInput.input.current[diffStart]) {
|
|
648
|
-
diffStart++;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
for (let i = diffStart; i < inputValue.length; i++) {
|
|
652
|
-
handleChar(inputValue[i], i);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
setWordsInput(' ' + TestInput.input.current);
|
|
657
|
-
updateUI();
|
|
658
|
-
|
|
659
|
-
const statebefore = CompositionState.getComposing();
|
|
660
|
-
setTimeout(() => {
|
|
661
|
-
// checking composition state during the input event and on the next loop
|
|
662
|
-
// this is done because some browsers (e.g. Chrome) will fire the input
|
|
663
|
-
// event before the compositionend event.
|
|
664
|
-
// this ensures the UI is correct
|
|
665
|
-
|
|
666
|
-
const stateafter = CompositionState.getComposing();
|
|
667
|
-
if (statebefore !== stateafter) {
|
|
668
|
-
TestUI.updateWordElement();
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// force caret at end of input
|
|
672
|
-
// doing it on next cycle because Chromium on Android won't let me edit
|
|
673
|
-
// the selection inside the input event
|
|
674
|
-
if (
|
|
675
|
-
(event.target as HTMLInputElement).selectionStart !==
|
|
676
|
-
(event.target as HTMLInputElement).value.length &&
|
|
677
|
-
(!Misc.trailingComposeChars.test((event.target as HTMLInputElement).value) ||
|
|
678
|
-
((event.target as HTMLInputElement).selectionStart ?? 0) <
|
|
679
|
-
(event.target as HTMLInputElement).value.search(Misc.trailingComposeChars))
|
|
680
|
-
) {
|
|
681
|
-
(event.target as HTMLInputElement).selectionStart = (
|
|
682
|
-
event.target as HTMLInputElement
|
|
683
|
-
).selectionEnd = (event.target as HTMLInputElement).value.length;
|
|
684
|
-
}
|
|
685
|
-
}, 0);
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
export function wordsInputFocus(event: { target: HTMLInputElement }) {
|
|
689
|
-
(event.target as HTMLInputElement).selectionStart = (
|
|
690
|
-
event.target as HTMLInputElement
|
|
691
|
-
).selectionEnd = (event.target as HTMLInputElement).value.length;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
export function wordsInputCopy(event: { preventDefault: () => void }) {
|
|
695
|
-
event.preventDefault();
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
export function wordsInputPaste(event: { preventDefault: () => void }) {
|
|
699
|
-
event.preventDefault();
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
// Composing events
|
|
703
|
-
export function wordsInputCompositionstart() {
|
|
704
|
-
CompositionState.setComposing(true);
|
|
705
|
-
CompositionState.setStartPos(TestInput.input.current.length);
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
export function wordsInputCompositionend() {
|
|
709
|
-
CompositionState.setComposing(false);
|
|
710
|
-
}
|