@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,183 +0,0 @@
|
|
|
1
|
-
import { subscribe } from '../observables/config-event';
|
|
2
|
-
import { shuffle } from '../../utils/misc';
|
|
3
|
-
import { MonkeyTypes } from '../../types/types';
|
|
4
|
-
|
|
5
|
-
interface Quote {
|
|
6
|
-
text: string;
|
|
7
|
-
source: string;
|
|
8
|
-
length: number;
|
|
9
|
-
id: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface QuoteData {
|
|
13
|
-
language: string;
|
|
14
|
-
quotes: Quote[];
|
|
15
|
-
groups: number[][];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface QuoteCollection {
|
|
19
|
-
quotes: MonkeyTypes.Quote[];
|
|
20
|
-
length: number;
|
|
21
|
-
language: string | null;
|
|
22
|
-
groups: MonkeyTypes.Quote[][];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface FilteredSources {
|
|
26
|
-
sources: string[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const defaultQuoteCollection: QuoteCollection = {
|
|
30
|
-
quotes: [],
|
|
31
|
-
length: 0,
|
|
32
|
-
language: null,
|
|
33
|
-
groups: [],
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
function normalizeLanguage(language: string): string {
|
|
37
|
-
return language.replace(/_\d*k$/g, '');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
class QuotesController {
|
|
41
|
-
private quoteCollection: QuoteCollection = defaultQuoteCollection;
|
|
42
|
-
|
|
43
|
-
private quoteQueue: MonkeyTypes.Quote[] = [];
|
|
44
|
-
private queueIndex = 0;
|
|
45
|
-
|
|
46
|
-
async getQuotes(
|
|
47
|
-
language: string,
|
|
48
|
-
testVersion: number,
|
|
49
|
-
quoteLengths?: number[]
|
|
50
|
-
): Promise<QuoteCollection> {
|
|
51
|
-
const normalizedLanguage = normalizeLanguage(language);
|
|
52
|
-
|
|
53
|
-
if (this.quoteCollection.language !== normalizedLanguage) {
|
|
54
|
-
try {
|
|
55
|
-
const data: QuoteData = await fetch(
|
|
56
|
-
`/../assets/typing-test-languages/quotes/${normalizedLanguage}_version_${testVersion}.json`
|
|
57
|
-
).then(res => res.json());
|
|
58
|
-
|
|
59
|
-
const filteredSources: FilteredSources = await fetch(
|
|
60
|
-
`/../assets/typing-test-languages/quotes/filtered_sources.json`
|
|
61
|
-
).then(res => res.json());
|
|
62
|
-
|
|
63
|
-
if (data.quotes === undefined || data.quotes.length === 0) {
|
|
64
|
-
return defaultQuoteCollection;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.quoteCollection = {
|
|
68
|
-
quotes: [],
|
|
69
|
-
length: data.quotes.length,
|
|
70
|
-
groups: [],
|
|
71
|
-
language: data.language,
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Transform JSON Quote schema to MonkeyTypes Quote schema
|
|
75
|
-
data.quotes.forEach((quote: Quote) => {
|
|
76
|
-
const monkeyTypeQuote: MonkeyTypes.Quote = {
|
|
77
|
-
text: quote.text,
|
|
78
|
-
source: quote.source,
|
|
79
|
-
length: quote.length,
|
|
80
|
-
id: quote.id,
|
|
81
|
-
language: data.language,
|
|
82
|
-
group: 0,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
this.quoteCollection.quotes.push(monkeyTypeQuote);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
if (filteredSources) {
|
|
89
|
-
this.quoteCollection.quotes = this.quoteCollection.quotes.filter(quote =>
|
|
90
|
-
filteredSources.sources.includes(quote.source)
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
data.groups.forEach((quoteGroup, groupIndex) => {
|
|
95
|
-
const lower = quoteGroup[0];
|
|
96
|
-
const upper = quoteGroup[1];
|
|
97
|
-
|
|
98
|
-
this.quoteCollection.groups[groupIndex] = this.quoteCollection.quotes.filter(quote => {
|
|
99
|
-
if (quote.length >= lower && quote.length <= upper) {
|
|
100
|
-
quote.group = groupIndex;
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
return false;
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
if (quoteLengths !== undefined) {
|
|
108
|
-
this.updateQuoteQueue(quoteLengths);
|
|
109
|
-
}
|
|
110
|
-
} catch (e) {
|
|
111
|
-
if (!defaultQuoteCollection.quotes.length) {
|
|
112
|
-
throw e;
|
|
113
|
-
}
|
|
114
|
-
return defaultQuoteCollection;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return this.quoteCollection;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
getQuoteById(id: number): MonkeyTypes.Quote | undefined {
|
|
122
|
-
const targetQuote = this.quoteCollection.quotes.find((quote: MonkeyTypes.Quote) => {
|
|
123
|
-
return quote.id === id;
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
return targetQuote;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
updateQuoteQueue(quoteGroups: number[]): void {
|
|
130
|
-
this.quoteQueue = [];
|
|
131
|
-
|
|
132
|
-
quoteGroups.forEach(group => {
|
|
133
|
-
if (group < 0) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
this.quoteCollection.groups[group]?.forEach(quote => {
|
|
137
|
-
this.quoteQueue.push(quote);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
shuffle(this.quoteQueue);
|
|
142
|
-
this.queueIndex = 0;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
getRandomQuote(): MonkeyTypes.Quote | null {
|
|
146
|
-
if (this.quoteQueue.length === 0) {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (this.queueIndex >= this.quoteQueue.length) {
|
|
151
|
-
this.queueIndex = 0;
|
|
152
|
-
shuffle(this.quoteQueue);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const randomQuote = this.quoteQueue[this.queueIndex];
|
|
156
|
-
|
|
157
|
-
this.queueIndex += 1;
|
|
158
|
-
|
|
159
|
-
return randomQuote;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
getCurrentQuote(): MonkeyTypes.Quote | null {
|
|
163
|
-
if (this.quoteQueue.length === 0) {
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return this.quoteQueue[this.queueIndex];
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
resetQuotes() {
|
|
171
|
-
this.quoteCollection = defaultQuoteCollection;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const quoteController = new QuotesController();
|
|
176
|
-
|
|
177
|
-
subscribe((key, newValue) => {
|
|
178
|
-
if (key === 'quoteLength') {
|
|
179
|
-
quoteController.updateQuoteQueue(newValue as number[]);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
export default quoteController;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
type SubscribeFunction = () => void;
|
|
2
|
-
|
|
3
|
-
const subscribers: SubscribeFunction[] = [];
|
|
4
|
-
|
|
5
|
-
export function subscribe(fn: SubscribeFunction): void {
|
|
6
|
-
subscribers.push(fn);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function dispatch(): void {
|
|
10
|
-
subscribers.forEach((fn) => {
|
|
11
|
-
try {
|
|
12
|
-
fn();
|
|
13
|
-
} catch (e) {
|
|
14
|
-
console.error("Banner event subscriber threw an error");
|
|
15
|
-
console.error(e);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { MonkeyTypes } from '../../types/types';
|
|
2
|
-
type SubscribeFunction = (
|
|
3
|
-
key: string,
|
|
4
|
-
newValue?: MonkeyTypes.ConfigValues,
|
|
5
|
-
nosave?: boolean,
|
|
6
|
-
previousValue?: MonkeyTypes.ConfigValues,
|
|
7
|
-
fullConfig?: MonkeyTypes.Config
|
|
8
|
-
) => void;
|
|
9
|
-
|
|
10
|
-
const subscribers: SubscribeFunction[] = [];
|
|
11
|
-
|
|
12
|
-
export function subscribe(fn: SubscribeFunction): void {
|
|
13
|
-
subscribers.push(fn);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function dispatch(
|
|
17
|
-
key: string,
|
|
18
|
-
newValue?: MonkeyTypes.ConfigValues,
|
|
19
|
-
nosave?: boolean,
|
|
20
|
-
previousValue?: MonkeyTypes.ConfigValues,
|
|
21
|
-
fullConfig?: MonkeyTypes.Config
|
|
22
|
-
): void {
|
|
23
|
-
subscribers.forEach(fn => {
|
|
24
|
-
try {
|
|
25
|
-
fn(key, newValue, nosave, previousValue, fullConfig);
|
|
26
|
-
} catch (e) {
|
|
27
|
-
console.error('Config event subscriber threw an error');
|
|
28
|
-
console.error(e);
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
type SubscribeFunction = (key: string, value?: string, value2?: string) => void;
|
|
2
|
-
|
|
3
|
-
const subscribers: SubscribeFunction[] = [];
|
|
4
|
-
|
|
5
|
-
export function subscribe(fn: SubscribeFunction): void {
|
|
6
|
-
subscribers.push(fn);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function dispatch(key: string, value?: string, value2?: string): void {
|
|
10
|
-
subscribers.forEach((fn) => {
|
|
11
|
-
try {
|
|
12
|
-
fn(key, value, value2);
|
|
13
|
-
} catch (e) {
|
|
14
|
-
console.error("Timer event subscriber threw an error");
|
|
15
|
-
console.error(e);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
interface CompositionState {
|
|
2
|
-
composing: boolean;
|
|
3
|
-
startPos: number;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
const compositionState = {
|
|
7
|
-
composing: false,
|
|
8
|
-
startPos: -1,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export function get(): CompositionState {
|
|
12
|
-
return compositionState;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function getComposing(): boolean {
|
|
16
|
-
return compositionState.composing;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function getStartPos(): number {
|
|
20
|
-
return compositionState.startPos;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function setComposing(isComposing: boolean): void {
|
|
24
|
-
compositionState.composing = isComposing;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function setStartPos(pos: number): void {
|
|
28
|
-
compositionState.startPos = pos;
|
|
29
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
let slowTimer = false;
|
|
2
|
-
|
|
3
|
-
export function set(): void {
|
|
4
|
-
if (slowTimer) return;
|
|
5
|
-
slowTimer = true;
|
|
6
|
-
console.error('Slow timer, disabling animations');
|
|
7
|
-
// Notifications.add("Slow timer detected", -1, 5);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function clear(): void {
|
|
11
|
-
slowTimer = false;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function get(): boolean {
|
|
15
|
-
return slowTimer;
|
|
16
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
import Config from '../../helpers/config';
|
|
3
|
-
export let capsState = false;
|
|
4
|
-
|
|
5
|
-
export const showCaps = new BehaviorSubject<boolean>(false);
|
|
6
|
-
|
|
7
|
-
function show(): void {
|
|
8
|
-
showCaps.next(true);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function hide(): void {
|
|
12
|
-
showCaps.next(false);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function capsKeydown(event: KeyboardEvent) {
|
|
16
|
-
if (event.getModifierState('CapsLock')) {
|
|
17
|
-
capsState = true;
|
|
18
|
-
} else {
|
|
19
|
-
capsState = false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
if (Config.capsLockWarning && capsState) {
|
|
24
|
-
show();
|
|
25
|
-
} else {
|
|
26
|
-
hide();
|
|
27
|
-
}
|
|
28
|
-
} catch {
|
|
29
|
-
console.error('Error showing caps warning');
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function capsKeyup(event: KeyboardEvent) {
|
|
34
|
-
// filthy fix but optional chaining refuses to work
|
|
35
|
-
if (event.getModifierState('CapsLock')) {
|
|
36
|
-
capsState = true;
|
|
37
|
-
} else {
|
|
38
|
-
capsState = false;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
if (Config.capsLockWarning && capsState) {
|
|
43
|
-
show();
|
|
44
|
-
} else {
|
|
45
|
-
hide();
|
|
46
|
-
}
|
|
47
|
-
} catch {
|
|
48
|
-
console.error('Error showing caps warning');
|
|
49
|
-
}
|
|
50
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import * as Misc from '../../utils/misc';
|
|
2
|
-
import Config from '../config';
|
|
3
|
-
import * as TestInput from './test-input';
|
|
4
|
-
import * as SlowTimer from '../states/slow-timer';
|
|
5
|
-
import { BehaviorSubject } from 'rxjs';
|
|
6
|
-
|
|
7
|
-
export let caretAnimating = true;
|
|
8
|
-
export const caretShow = new BehaviorSubject<boolean>(true);
|
|
9
|
-
export const caretAnimation = new BehaviorSubject<string>('caretFlashSmooth');
|
|
10
|
-
export const caretLeft = new BehaviorSubject<number>(0);
|
|
11
|
-
export const caretTop = new BehaviorSubject<number>(0);
|
|
12
|
-
|
|
13
|
-
export function stopAnimation(): void {
|
|
14
|
-
if (caretAnimating === true) {
|
|
15
|
-
caretAnimation.next('none');
|
|
16
|
-
caretAnimating = false;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function startAnimation(): void {
|
|
21
|
-
if (caretAnimating === false) {
|
|
22
|
-
if (Config.smoothCaret && !SlowTimer.get()) {
|
|
23
|
-
caretAnimation.next('caretFlashSmooth');
|
|
24
|
-
} else {
|
|
25
|
-
caretAnimation.next('caretFlashHard');
|
|
26
|
-
}
|
|
27
|
-
caretAnimating = true;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function hide(): void {
|
|
32
|
-
caretShow.next(false);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export async function updatePosition(): Promise<void> {
|
|
36
|
-
let caretWidth = Math.round(document.querySelector('#caret')?.getBoundingClientRect().width ?? 0);
|
|
37
|
-
|
|
38
|
-
if (['block', 'outline', 'underline'].includes(Config.caretStyle)) {
|
|
39
|
-
caretWidth /= 3;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const inputLen = TestInput.input.current.length;
|
|
43
|
-
|
|
44
|
-
let currentLetterIndex = inputLen - 1;
|
|
45
|
-
if (currentLetterIndex == -1) {
|
|
46
|
-
currentLetterIndex = 0;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const currentWordNodeList = document?.querySelector('#words .active')?.querySelectorAll('letter');
|
|
50
|
-
|
|
51
|
-
if (!currentWordNodeList) return;
|
|
52
|
-
|
|
53
|
-
let currentLetter: HTMLElement = currentWordNodeList[currentLetterIndex] as HTMLElement;
|
|
54
|
-
if (inputLen > currentWordNodeList.length) {
|
|
55
|
-
currentLetter = currentWordNodeList[currentWordNodeList.length - 1] as HTMLElement;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const currentLanguage = await Misc.getCurrentLanguage(Config.language);
|
|
59
|
-
const isLanguageLeftToRight = currentLanguage.leftToRight;
|
|
60
|
-
const currentLetterPosLeft = isLanguageLeftToRight
|
|
61
|
-
? currentLetter.offsetLeft
|
|
62
|
-
: currentLetter.offsetLeft + (currentLetter.getBoundingClientRect().width ?? 0);
|
|
63
|
-
const currentLetterPosTop = currentLetter.offsetTop;
|
|
64
|
-
const letterHeight = currentLetter.getBoundingClientRect().height as number;
|
|
65
|
-
let newTop = 0;
|
|
66
|
-
let newLeft = 0;
|
|
67
|
-
|
|
68
|
-
newTop = currentLetterPosTop - Math.round(letterHeight / 5);
|
|
69
|
-
|
|
70
|
-
if (inputLen == 0) {
|
|
71
|
-
newLeft = isLanguageLeftToRight
|
|
72
|
-
? currentLetterPosLeft - caretWidth / 2
|
|
73
|
-
: currentLetterPosLeft + caretWidth / 2;
|
|
74
|
-
} else {
|
|
75
|
-
newLeft = isLanguageLeftToRight
|
|
76
|
-
? currentLetterPosLeft +
|
|
77
|
-
(currentLetter.getBoundingClientRect().width as number) -
|
|
78
|
-
caretWidth / 2
|
|
79
|
-
: currentLetterPosLeft -
|
|
80
|
-
(currentLetter.getBoundingClientRect().width as number) +
|
|
81
|
-
caretWidth / 2;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
caretTop.next(newTop);
|
|
85
|
-
caretLeft.next(newLeft);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function show(): void {
|
|
89
|
-
caretShow.next(true);
|
|
90
|
-
updatePosition();
|
|
91
|
-
startAnimation();
|
|
92
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
export let text = [
|
|
2
|
-
"The",
|
|
3
|
-
"quick",
|
|
4
|
-
"brown",
|
|
5
|
-
"fox",
|
|
6
|
-
"jumps",
|
|
7
|
-
"over",
|
|
8
|
-
"the",
|
|
9
|
-
"lazy",
|
|
10
|
-
"dog",
|
|
11
|
-
];
|
|
12
|
-
export let isWordRandom = false;
|
|
13
|
-
export let isTimeRandom = false;
|
|
14
|
-
export let word = -1;
|
|
15
|
-
export let time = -1;
|
|
16
|
-
export let delimiter = " ";
|
|
17
|
-
|
|
18
|
-
export function setText(txt: string[]): void {
|
|
19
|
-
text = txt;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function setIsWordRandom(val: boolean): void {
|
|
23
|
-
isWordRandom = val;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function setIsTimeRandom(val: boolean): void {
|
|
27
|
-
isTimeRandom = val;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function setTime(val: number): void {
|
|
31
|
-
time = val;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function setWord(val: number): void {
|
|
35
|
-
word = val;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function setDelimiter(val: string): void {
|
|
39
|
-
delimiter = val;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
type CustomTextObject = Record<string, string>;
|
|
43
|
-
|
|
44
|
-
export function getCustomText(name: string): string[] {
|
|
45
|
-
const customText = getCustomTextObject();
|
|
46
|
-
|
|
47
|
-
return customText[name].split(/ +/);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function setCustomText(name: string, text: string | string[]): void {
|
|
51
|
-
const customText = getCustomTextObject();
|
|
52
|
-
|
|
53
|
-
if (typeof text === "string") customText[name] = text;
|
|
54
|
-
else customText[name] = text.join(" ");
|
|
55
|
-
|
|
56
|
-
window.localStorage.setItem("customText", JSON.stringify(customText));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function deleteCustomText(name: string): void {
|
|
60
|
-
const customText = getCustomTextObject();
|
|
61
|
-
|
|
62
|
-
if (customText[name]) delete customText[name];
|
|
63
|
-
|
|
64
|
-
window.localStorage.setItem("customText", JSON.stringify(customText));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function getCustomTextObject(): CustomTextObject {
|
|
68
|
-
return JSON.parse(window.localStorage.getItem("customText") ?? "{}");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function getCustomTextNames(): string[] {
|
|
72
|
-
return Object.keys(getCustomTextObject());
|
|
73
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
let pairsList: string[] = [];
|
|
2
|
-
|
|
3
|
-
export async function getList(): Promise<string[]> {
|
|
4
|
-
if (pairsList.length === 0) {
|
|
5
|
-
return fetch("/../assets/typing-test-languages/english_punctuation.json")
|
|
6
|
-
.then(res => res.json())
|
|
7
|
-
.then(json => {
|
|
8
|
-
pairsList = json;
|
|
9
|
-
return pairsList;
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
return pairsList;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Check if word is in the group of pairs so it can be replaced
|
|
16
|
-
export async function check(word: string): Promise<boolean> {
|
|
17
|
-
const list = await getList();
|
|
18
|
-
if (
|
|
19
|
-
list.find((a) => word.match(RegExp(`^([\\W]*${a[0]}[\\W]*)$`, "gi"))) ===
|
|
20
|
-
undefined
|
|
21
|
-
) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function replace(word: string): Promise<string> {
|
|
28
|
-
const list = await getList();
|
|
29
|
-
const replacement = list.find((a) =>
|
|
30
|
-
word.match(RegExp(`^([\\W]*${a[0]}[\\W]*)$`, "gi"))
|
|
31
|
-
);
|
|
32
|
-
return replacement
|
|
33
|
-
? word.replace(
|
|
34
|
-
RegExp(`^(?:([\\W]*)(${replacement[0]})([\\W]*))$`, "gi"),
|
|
35
|
-
replacement[1]
|
|
36
|
-
)
|
|
37
|
-
: word;
|
|
38
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import * as Caret from './caret';
|
|
2
|
-
|
|
3
|
-
const unfocusPx = 3;
|
|
4
|
-
let state = false;
|
|
5
|
-
let middle: HTMLElement;
|
|
6
|
-
let capsWarning: HTMLElement;
|
|
7
|
-
|
|
8
|
-
export function setMiddleElement(middleElem: HTMLElement) {
|
|
9
|
-
middle = middleElem;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function setCapsWarningElement(capsWarningElem: HTMLElement) {
|
|
13
|
-
capsWarning = capsWarningElem;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function set(foc: boolean, withCursor = false): void {
|
|
17
|
-
if (foc && !state) {
|
|
18
|
-
state = true;
|
|
19
|
-
Caret.stopAnimation();
|
|
20
|
-
middle.classList.add('focus');
|
|
21
|
-
capsWarning.classList.add('focus');
|
|
22
|
-
} else if (!foc && state) {
|
|
23
|
-
state = false;
|
|
24
|
-
Caret.startAnimation();
|
|
25
|
-
middle.classList.remove('focus');
|
|
26
|
-
capsWarning.classList.remove('focus');
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function mousemove(event: { movementX: number; movementY: number }) {
|
|
31
|
-
if (!state) return;
|
|
32
|
-
// To avoid mouse/desk vibration from creating a flashy effect, we'll unfocus @ >5px instead of >0px
|
|
33
|
-
if (
|
|
34
|
-
middle.classList.contains('focus') &&
|
|
35
|
-
(event.movementX > unfocusPx || event.movementY > unfocusPx)
|
|
36
|
-
) {
|
|
37
|
-
set(false);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
import * as Misc from '../../utils/misc';
|
|
3
|
-
|
|
4
|
-
const outOfFocusTimeouts: (number | NodeJS.Timeout)[] = [];
|
|
5
|
-
|
|
6
|
-
export const outOfFocusShow = new BehaviorSubject<boolean>(false);
|
|
7
|
-
|
|
8
|
-
export function hide(): void {
|
|
9
|
-
outOfFocusShow.next(false);
|
|
10
|
-
Misc.clearTimeouts(outOfFocusTimeouts);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function show(): void {
|
|
14
|
-
outOfFocusTimeouts.push(
|
|
15
|
-
setTimeout(() => {
|
|
16
|
-
outOfFocusShow.next(true);
|
|
17
|
-
}, 1000)
|
|
18
|
-
);
|
|
19
|
-
}
|