@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
package/src/lib/utils/misc.ts
DELETED
|
@@ -1,776 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
|
|
3
|
-
import { MonkeyTypes } from '../types/types';
|
|
4
|
-
|
|
5
|
-
const QuoteNetworkErrorSubject = new BehaviorSubject<string>('');
|
|
6
|
-
|
|
7
|
-
export const QuoteNetworkErrorMessage = 'Text not loading.';
|
|
8
|
-
|
|
9
|
-
export function emitQuoteNetworkError(): void {
|
|
10
|
-
QuoteNetworkErrorSubject.next(QuoteNetworkErrorMessage);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const QuoteNetworkError$ = QuoteNetworkErrorSubject.asObservable();
|
|
14
|
-
|
|
15
|
-
function hexToHSL(hex: string): {
|
|
16
|
-
hue: number;
|
|
17
|
-
sat: number;
|
|
18
|
-
lgt: number;
|
|
19
|
-
string: string;
|
|
20
|
-
} {
|
|
21
|
-
// Convert hex to RGB first
|
|
22
|
-
let r: number;
|
|
23
|
-
let g: number;
|
|
24
|
-
let b: number;
|
|
25
|
-
if (hex.length == 4) {
|
|
26
|
-
r = ('0x' + hex[1] + hex[1]) as unknown as number;
|
|
27
|
-
g = ('0x' + hex[2] + hex[2]) as unknown as number;
|
|
28
|
-
b = ('0x' + hex[3] + hex[3]) as unknown as number;
|
|
29
|
-
} else if (hex.length == 7) {
|
|
30
|
-
r = ('0x' + hex[1] + hex[2]) as unknown as number;
|
|
31
|
-
g = ('0x' + hex[3] + hex[4]) as unknown as number;
|
|
32
|
-
b = ('0x' + hex[5] + hex[6]) as unknown as number;
|
|
33
|
-
} else {
|
|
34
|
-
r = 0x00;
|
|
35
|
-
g = 0x00;
|
|
36
|
-
b = 0x00;
|
|
37
|
-
}
|
|
38
|
-
// Then to HSL
|
|
39
|
-
r /= 255;
|
|
40
|
-
g /= 255;
|
|
41
|
-
b /= 255;
|
|
42
|
-
const cmin = Math.min(r, g, b);
|
|
43
|
-
const cmax = Math.max(r, g, b);
|
|
44
|
-
const delta = cmax - cmin;
|
|
45
|
-
let h = 0;
|
|
46
|
-
let s = 0;
|
|
47
|
-
let l = 0;
|
|
48
|
-
|
|
49
|
-
if (delta == 0) h = 0;
|
|
50
|
-
else if (cmax == r) h = ((g - b) / delta) % 6;
|
|
51
|
-
else if (cmax == g) h = (b - r) / delta + 2;
|
|
52
|
-
else h = (r - g) / delta + 4;
|
|
53
|
-
|
|
54
|
-
h = Math.round(h * 60);
|
|
55
|
-
|
|
56
|
-
if (h < 0) h += 360;
|
|
57
|
-
|
|
58
|
-
l = (cmax + cmin) / 2;
|
|
59
|
-
s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
|
|
60
|
-
s = +(s * 100).toFixed(1);
|
|
61
|
-
l = +(l * 100).toFixed(1);
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
hue: h,
|
|
65
|
-
sat: s,
|
|
66
|
-
lgt: l,
|
|
67
|
-
string: 'hsl(' + h + ',' + s + '%,' + l + '%)',
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function isColorLight(hex: string): boolean {
|
|
72
|
-
const hsl = hexToHSL(hex);
|
|
73
|
-
return hsl.lgt >= 50;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function isColorDark(hex: string): boolean {
|
|
77
|
-
const hsl = hexToHSL(hex);
|
|
78
|
-
return hsl.lgt < 50;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
let currentLanguage: MonkeyTypes.LanguageObject;
|
|
82
|
-
export async function getLanguage(lang: string): Promise<MonkeyTypes.LanguageObject> {
|
|
83
|
-
try {
|
|
84
|
-
if (currentLanguage == undefined || currentLanguage.name !== lang) {
|
|
85
|
-
console.log('getting language json');
|
|
86
|
-
await fetch(`/../assets/typing-test-languages/${lang}.json`)
|
|
87
|
-
.then(res => res.json())
|
|
88
|
-
.then(json => {
|
|
89
|
-
currentLanguage = json;
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
return currentLanguage;
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.error(`error getting language`);
|
|
95
|
-
console.error(e);
|
|
96
|
-
await fetch(`/../assets/typing-test-languages/english.json`)
|
|
97
|
-
.then(res => res.json())
|
|
98
|
-
.then(json => {
|
|
99
|
-
currentLanguage = json;
|
|
100
|
-
});
|
|
101
|
-
return currentLanguage;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export async function getCurrentLanguage(
|
|
106
|
-
languageName: string
|
|
107
|
-
): Promise<MonkeyTypes.LanguageObject> {
|
|
108
|
-
return await getLanguage(languageName);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function smooth(
|
|
112
|
-
arr: number[],
|
|
113
|
-
windowSize: number,
|
|
114
|
-
getter = (value: number): number => value
|
|
115
|
-
): number[] {
|
|
116
|
-
const get = getter;
|
|
117
|
-
const result = [];
|
|
118
|
-
|
|
119
|
-
for (let i = 0; i < arr.length; i += 1) {
|
|
120
|
-
const leftOffeset = i - windowSize;
|
|
121
|
-
const from = leftOffeset >= 0 ? leftOffeset : 0;
|
|
122
|
-
const to = i + windowSize + 1;
|
|
123
|
-
|
|
124
|
-
let count = 0;
|
|
125
|
-
let sum = 0;
|
|
126
|
-
for (let j = from; j < to && j < arr.length; j += 1) {
|
|
127
|
-
sum += get(arr[j]);
|
|
128
|
-
count += 1;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
result[i] = sum / count;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return result;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function stdDev(array: number[]): number {
|
|
138
|
-
try {
|
|
139
|
-
const n = array.length;
|
|
140
|
-
const mean = array.reduce((a, b) => a + b) / n;
|
|
141
|
-
return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n);
|
|
142
|
-
} catch (e) {
|
|
143
|
-
return 0;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function mean(array: number[]): number {
|
|
148
|
-
try {
|
|
149
|
-
return array.reduce((previous, current) => (current += previous)) / array.length;
|
|
150
|
-
} catch (e) {
|
|
151
|
-
return 0;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
//https://www.w3resource.com/javascript-exercises/fundamental/javascript-fundamental-exercise-88.php
|
|
156
|
-
export function median(arr: number[]): number {
|
|
157
|
-
try {
|
|
158
|
-
const mid = Math.floor(arr.length / 2),
|
|
159
|
-
nums = [...arr].sort((a, b) => a - b);
|
|
160
|
-
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
|
|
161
|
-
} catch (e) {
|
|
162
|
-
return 0;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export function getLastChar(word: string): string {
|
|
167
|
-
try {
|
|
168
|
-
return word.charAt(word.length - 1);
|
|
169
|
-
} catch {
|
|
170
|
-
return '';
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function capitalizeFirstLetterOfEachWord(str: string): string {
|
|
175
|
-
return str
|
|
176
|
-
.split(/ +/)
|
|
177
|
-
.map(s => s.charAt(0).toUpperCase() + s.slice(1))
|
|
178
|
-
.join(' ');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function isASCIILetter(c: string): boolean {
|
|
182
|
-
return c.length === 1 && /[a-z]/i.test(c);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export function kogasa(cov: number): number {
|
|
186
|
-
return 100 * (1 - Math.tanh(cov + Math.pow(cov, 3) / 3 + Math.pow(cov, 5) / 5));
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export function whorf(speed: number, wordlen: number): number {
|
|
190
|
-
return Math.min(speed, Math.floor(speed * Math.pow(1.03, -2 * (wordlen - 3))));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export function roundTo2(num: number): number {
|
|
194
|
-
return Math.round((num + Number.EPSILON) * 100) / 100;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export function findLineByLeastSquares(values_y: number[]): number[][] {
|
|
198
|
-
let sum_x = 0;
|
|
199
|
-
let sum_y = 0;
|
|
200
|
-
let sum_xy = 0;
|
|
201
|
-
let sum_xx = 0;
|
|
202
|
-
let count = 0;
|
|
203
|
-
|
|
204
|
-
/*
|
|
205
|
-
* We'll use those letiables for faster read/write access.
|
|
206
|
-
*/
|
|
207
|
-
let x = 0;
|
|
208
|
-
let y = 0;
|
|
209
|
-
const values_length = values_y.length;
|
|
210
|
-
|
|
211
|
-
/*
|
|
212
|
-
* Nothing to do.
|
|
213
|
-
*/
|
|
214
|
-
if (values_length === 0) {
|
|
215
|
-
return [[], []];
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/*
|
|
219
|
-
* Calculate the sum for each of the parts necessary.
|
|
220
|
-
*/
|
|
221
|
-
for (let v = 0; v < values_length; v++) {
|
|
222
|
-
x = v + 1;
|
|
223
|
-
y = values_y[v];
|
|
224
|
-
sum_x += x;
|
|
225
|
-
sum_y += y;
|
|
226
|
-
sum_xx += x * x;
|
|
227
|
-
sum_xy += x * y;
|
|
228
|
-
count++;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/*
|
|
232
|
-
* Calculate m and b for the formular:
|
|
233
|
-
* y = x * m + b
|
|
234
|
-
*/
|
|
235
|
-
const m = (count * sum_xy - sum_x * sum_y) / (count * sum_xx - sum_x * sum_x);
|
|
236
|
-
const b = sum_y / count - (m * sum_x) / count;
|
|
237
|
-
|
|
238
|
-
const returnpoint1 = [1, 1 * m + b];
|
|
239
|
-
const returnpoint2 = [values_length, values_length * m + b];
|
|
240
|
-
return [returnpoint1, returnpoint2];
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export function getGibberish(): string {
|
|
244
|
-
const randLen = randomIntFromRange(1, 7);
|
|
245
|
-
let ret = '';
|
|
246
|
-
for (let i = 0; i < randLen; i++) {
|
|
247
|
-
ret += String.fromCharCode(97 + randomIntFromRange(0, 25));
|
|
248
|
-
}
|
|
249
|
-
return ret;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
export function secondsToString(
|
|
253
|
-
sec: number,
|
|
254
|
-
alwaysShowMinutes = false,
|
|
255
|
-
alwaysShowHours = false,
|
|
256
|
-
delimiter: ':' | 'text' = ':',
|
|
257
|
-
showSeconds = true,
|
|
258
|
-
showDays = false
|
|
259
|
-
): string {
|
|
260
|
-
sec = Math.abs(sec);
|
|
261
|
-
let days = 0;
|
|
262
|
-
let hours;
|
|
263
|
-
if (showDays) {
|
|
264
|
-
days = Math.floor(sec / 86400);
|
|
265
|
-
hours = Math.floor((sec % 86400) / 3600);
|
|
266
|
-
} else {
|
|
267
|
-
hours = Math.floor(sec / 3600);
|
|
268
|
-
}
|
|
269
|
-
const minutes = Math.floor((sec % 3600) / 60);
|
|
270
|
-
const seconds = roundTo2((sec % 3600) % 60);
|
|
271
|
-
|
|
272
|
-
let daysString;
|
|
273
|
-
let hoursString;
|
|
274
|
-
let minutesString;
|
|
275
|
-
let secondsString;
|
|
276
|
-
|
|
277
|
-
if (showDays) {
|
|
278
|
-
days < 10 && delimiter !== 'text' ? (daysString = '0' + days) : (daysString = days);
|
|
279
|
-
}
|
|
280
|
-
hours < 10 && delimiter !== 'text' ? (hoursString = '0' + hours) : (hoursString = hours);
|
|
281
|
-
minutes < 10 && delimiter !== 'text'
|
|
282
|
-
? (minutesString = '0' + minutes)
|
|
283
|
-
: (minutesString = minutes);
|
|
284
|
-
seconds < 10 && (minutes > 0 || hours > 0 || alwaysShowMinutes) && delimiter !== 'text'
|
|
285
|
-
? (secondsString = '0' + seconds)
|
|
286
|
-
: (secondsString = seconds);
|
|
287
|
-
|
|
288
|
-
let ret = '';
|
|
289
|
-
if (days > 0 && showDays) {
|
|
290
|
-
ret += daysString;
|
|
291
|
-
if (delimiter === 'text') {
|
|
292
|
-
if (days == 1) {
|
|
293
|
-
ret += ' day ';
|
|
294
|
-
} else {
|
|
295
|
-
ret += ' days ';
|
|
296
|
-
}
|
|
297
|
-
} else {
|
|
298
|
-
ret += delimiter;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
if (hours > 0 || alwaysShowHours) {
|
|
302
|
-
ret += hoursString;
|
|
303
|
-
if (delimiter === 'text') {
|
|
304
|
-
if (hours == 1) {
|
|
305
|
-
ret += ' hour ';
|
|
306
|
-
} else {
|
|
307
|
-
ret += ' hours ';
|
|
308
|
-
}
|
|
309
|
-
} else {
|
|
310
|
-
ret += delimiter;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
if (minutes > 0 || hours > 0 || alwaysShowMinutes) {
|
|
314
|
-
ret += minutesString;
|
|
315
|
-
if (delimiter === 'text') {
|
|
316
|
-
if (minutes == 1) {
|
|
317
|
-
ret += ' minute ';
|
|
318
|
-
} else {
|
|
319
|
-
ret += ' minutes ';
|
|
320
|
-
}
|
|
321
|
-
} else if (showSeconds) {
|
|
322
|
-
ret += delimiter;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
if (showSeconds) {
|
|
326
|
-
ret += secondsString;
|
|
327
|
-
if (delimiter === 'text') {
|
|
328
|
-
if (seconds == 1) {
|
|
329
|
-
ret += ' second';
|
|
330
|
-
} else {
|
|
331
|
-
ret += ' seconds';
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
if (hours === 0 && minutes === 0 && !showSeconds && delimiter === 'text') {
|
|
336
|
-
ret = 'less than 1 minute';
|
|
337
|
-
}
|
|
338
|
-
return ret.trim();
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
export function getNumbers(len: number, start?: number): string {
|
|
342
|
-
const randLen = randomIntFromRange(start ? start : 1, len);
|
|
343
|
-
let ret = '';
|
|
344
|
-
for (let i = 0; i < randLen; i++) {
|
|
345
|
-
let randomNum;
|
|
346
|
-
if (i === 0) {
|
|
347
|
-
randomNum = randomIntFromRange(1, 9);
|
|
348
|
-
} else {
|
|
349
|
-
randomNum = randomIntFromRange(0, 9);
|
|
350
|
-
}
|
|
351
|
-
ret += randomNum.toString();
|
|
352
|
-
}
|
|
353
|
-
return ret;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
//convert numbers to arabic-indic
|
|
357
|
-
export function convertNumberToArabicIndic(numString: string): string {
|
|
358
|
-
const arabicIndic = '٠١٢٣٤٥٦٧٨٩';
|
|
359
|
-
let ret = '';
|
|
360
|
-
for (let i = 0; i < numString.length; i++) {
|
|
361
|
-
ret += arabicIndic[parseInt(numString[i])];
|
|
362
|
-
}
|
|
363
|
-
return ret;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
export function getSpecials(): string {
|
|
367
|
-
const randLen = randomIntFromRange(1, 7);
|
|
368
|
-
let ret = '';
|
|
369
|
-
const specials = [
|
|
370
|
-
'!',
|
|
371
|
-
'@',
|
|
372
|
-
'#',
|
|
373
|
-
'$',
|
|
374
|
-
'%',
|
|
375
|
-
'^',
|
|
376
|
-
'&',
|
|
377
|
-
'*',
|
|
378
|
-
'(',
|
|
379
|
-
')',
|
|
380
|
-
'-',
|
|
381
|
-
'_',
|
|
382
|
-
'=',
|
|
383
|
-
'+',
|
|
384
|
-
'{',
|
|
385
|
-
'}',
|
|
386
|
-
'[',
|
|
387
|
-
']',
|
|
388
|
-
"'",
|
|
389
|
-
'"',
|
|
390
|
-
'/',
|
|
391
|
-
'\\',
|
|
392
|
-
'|',
|
|
393
|
-
];
|
|
394
|
-
for (let i = 0; i < randLen; i++) {
|
|
395
|
-
ret += randomElementFromArray(specials);
|
|
396
|
-
}
|
|
397
|
-
return ret;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
export function getASCII(): string {
|
|
401
|
-
const randLen = randomIntFromRange(1, 10);
|
|
402
|
-
let ret = '';
|
|
403
|
-
for (let i = 0; i < randLen; i++) {
|
|
404
|
-
const ran = 33 + randomIntFromRange(0, 93);
|
|
405
|
-
ret += String.fromCharCode(ran);
|
|
406
|
-
}
|
|
407
|
-
return ret;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
export function getArrows(): string {
|
|
411
|
-
const arrowArray = ['←', '↑', '→', '↓'];
|
|
412
|
-
let arrowWord = '';
|
|
413
|
-
let lastchar;
|
|
414
|
-
for (let i = 0; i < 5; i++) {
|
|
415
|
-
let random = randomElementFromArray(arrowArray);
|
|
416
|
-
while (random === lastchar) {
|
|
417
|
-
random = randomElementFromArray(arrowArray);
|
|
418
|
-
}
|
|
419
|
-
lastchar = random;
|
|
420
|
-
arrowWord += random;
|
|
421
|
-
}
|
|
422
|
-
return arrowWord;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
export function getPositionString(number: number): string {
|
|
426
|
-
let numend = 'th';
|
|
427
|
-
const t = number % 10;
|
|
428
|
-
const h = number % 100;
|
|
429
|
-
if (t == 1 && h != 11) {
|
|
430
|
-
numend = 'st';
|
|
431
|
-
}
|
|
432
|
-
if (t == 2 && h != 12) {
|
|
433
|
-
numend = 'nd';
|
|
434
|
-
}
|
|
435
|
-
if (t == 3 && h != 13) {
|
|
436
|
-
numend = 'rd';
|
|
437
|
-
}
|
|
438
|
-
return number + numend;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
export function findGetParameter(parameterName: string, getOverride?: string): string | null {
|
|
442
|
-
let result = null;
|
|
443
|
-
let tmp = [];
|
|
444
|
-
|
|
445
|
-
let search = location.search;
|
|
446
|
-
if (getOverride) {
|
|
447
|
-
search = getOverride;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
search
|
|
451
|
-
.substr(1)
|
|
452
|
-
.split('&')
|
|
453
|
-
.forEach(function (item) {
|
|
454
|
-
tmp = item.split('=');
|
|
455
|
-
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
|
|
456
|
-
});
|
|
457
|
-
return result;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
export function objectToQueryString<T extends string | number | boolean>(
|
|
461
|
-
obj: Record<string, T | T[]>
|
|
462
|
-
): string {
|
|
463
|
-
const str = [];
|
|
464
|
-
for (const p in obj) {
|
|
465
|
-
if (Object.prototype.hasOwnProperty.call(obj, p)) {
|
|
466
|
-
// Arrays get encoded as a comma(%2C)-separated list
|
|
467
|
-
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p] as unknown as T));
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
return str.join('&');
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
declare global {
|
|
474
|
-
interface Document {
|
|
475
|
-
mozCancelFullScreen?: () => Promise<void>;
|
|
476
|
-
msRequestFullscreen?: () => Promise<void>;
|
|
477
|
-
msExitFullscreen?: () => Promise<void>;
|
|
478
|
-
webkitExitFullscreen?: () => Promise<void>;
|
|
479
|
-
mozFullScreenElement?: Element;
|
|
480
|
-
msFullscreenElement?: Element;
|
|
481
|
-
webkitFullscreenElement?: Element;
|
|
482
|
-
}
|
|
483
|
-
interface HTMLElement {
|
|
484
|
-
msRequestFullscreen?: () => Promise<void>;
|
|
485
|
-
mozRequestFullScreen?: () => Promise<void>;
|
|
486
|
-
webkitRequestFullscreen?: () => Promise<void>;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
export function toggleFullscreen(): void {
|
|
491
|
-
const elem = document.documentElement;
|
|
492
|
-
if (
|
|
493
|
-
!document.fullscreenElement &&
|
|
494
|
-
!document.mozFullScreenElement &&
|
|
495
|
-
!document.webkitFullscreenElement &&
|
|
496
|
-
!document.msFullscreenElement
|
|
497
|
-
) {
|
|
498
|
-
if (elem.requestFullscreen) {
|
|
499
|
-
elem.requestFullscreen();
|
|
500
|
-
} else if (elem.msRequestFullscreen) {
|
|
501
|
-
elem.msRequestFullscreen();
|
|
502
|
-
} else if (elem.mozRequestFullScreen) {
|
|
503
|
-
elem.mozRequestFullScreen();
|
|
504
|
-
} else if (elem.webkitRequestFullscreen) {
|
|
505
|
-
// @ts-expect-error - Element.ALLOW_KEYBOARD_INPUT is not defined
|
|
506
|
-
elem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
|
|
507
|
-
}
|
|
508
|
-
} else {
|
|
509
|
-
if (document.exitFullscreen) {
|
|
510
|
-
document.exitFullscreen();
|
|
511
|
-
} else if (document.msExitFullscreen) {
|
|
512
|
-
document.msExitFullscreen();
|
|
513
|
-
} else if (document.mozCancelFullScreen) {
|
|
514
|
-
document.mozCancelFullScreen();
|
|
515
|
-
} else if (document.webkitExitFullscreen) {
|
|
516
|
-
document.webkitExitFullscreen();
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
//credit: https://www.w3resource.com/javascript-exercises/javascript-string-exercise-32.php
|
|
522
|
-
export function remove_non_ascii(str: string): string {
|
|
523
|
-
if (str === null || str === '') return '';
|
|
524
|
-
else str = str.toString();
|
|
525
|
-
|
|
526
|
-
return str.replace(/[^\x20-\x7E]/g, '');
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
export function escapeRegExp(str: string): string {
|
|
530
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
export function escapeHTML(str: string): string {
|
|
534
|
-
str = str
|
|
535
|
-
.replace(/&/g, '&')
|
|
536
|
-
.replace(/</g, '<')
|
|
537
|
-
.replace(/>/g, '>')
|
|
538
|
-
.replace(/"/g, '"')
|
|
539
|
-
.replace(/'/g, ''');
|
|
540
|
-
|
|
541
|
-
return str;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
export function cleanTypographySymbols(textToClean: string): string {
|
|
545
|
-
const specials = {
|
|
546
|
-
'“': '"', // “ “
|
|
547
|
-
'”': '"', // ” ”
|
|
548
|
-
'’': "'", // ‘ ‘
|
|
549
|
-
'‘': "'", // ’ ’
|
|
550
|
-
',': ',', // ‚ ‚
|
|
551
|
-
'—': '-', // — —
|
|
552
|
-
'…': '...', // … …
|
|
553
|
-
'«': '<<',
|
|
554
|
-
'»': '>>',
|
|
555
|
-
'–': '-',
|
|
556
|
-
' ': ' ',
|
|
557
|
-
' ': ' ',
|
|
558
|
-
' ': ' ',
|
|
559
|
-
};
|
|
560
|
-
return textToClean.replace(
|
|
561
|
-
/[“”’‘—,…«»–\u2007\u202F\u00A0]/g,
|
|
562
|
-
char => specials[char as keyof typeof specials] || ''
|
|
563
|
-
);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
export function isUsernameValid(name: string): boolean {
|
|
567
|
-
if (name === null || name === undefined || name === '') return false;
|
|
568
|
-
if (/miodec/.test(name.toLowerCase())) return false;
|
|
569
|
-
if (/bitly/.test(name.toLowerCase())) return false;
|
|
570
|
-
if (name.length > 14) return false;
|
|
571
|
-
if (/^\..*/.test(name.toLowerCase())) return false;
|
|
572
|
-
return /^[0-9a-zA-Z_.-]+$/.test(name);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
export function mapRange(
|
|
576
|
-
x: number,
|
|
577
|
-
in_min: number,
|
|
578
|
-
in_max: number,
|
|
579
|
-
out_min: number,
|
|
580
|
-
out_max: number
|
|
581
|
-
): number {
|
|
582
|
-
let num = ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min;
|
|
583
|
-
|
|
584
|
-
if (out_min > out_max) {
|
|
585
|
-
if (num > out_min) {
|
|
586
|
-
num = out_min;
|
|
587
|
-
} else if (num < out_max) {
|
|
588
|
-
num = out_max;
|
|
589
|
-
}
|
|
590
|
-
} else {
|
|
591
|
-
if (num < out_min) {
|
|
592
|
-
num = out_min;
|
|
593
|
-
} else if (num > out_max) {
|
|
594
|
-
num = out_max;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return num;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
export function canQuickRestart(
|
|
601
|
-
mode: string,
|
|
602
|
-
words: number,
|
|
603
|
-
time: number,
|
|
604
|
-
CustomText: MonkeyTypes.CustomText
|
|
605
|
-
): boolean {
|
|
606
|
-
if (
|
|
607
|
-
(mode === 'words' && words < 1000) ||
|
|
608
|
-
(mode === 'time' && time < 3600) ||
|
|
609
|
-
mode === 'quote' ||
|
|
610
|
-
(mode === 'custom' && CustomText.isWordRandom && CustomText.word < 1000) ||
|
|
611
|
-
(mode === 'custom' && CustomText.isTimeRandom && CustomText.time < 3600) ||
|
|
612
|
-
(mode === 'custom' && !CustomText.isWordRandom && CustomText.text.length < 1000)
|
|
613
|
-
) {
|
|
614
|
-
return true;
|
|
615
|
-
} else {
|
|
616
|
-
return false;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
export function clearTimeouts(timeouts: (number | NodeJS.Timeout)[]): void {
|
|
621
|
-
timeouts.forEach(to => {
|
|
622
|
-
if (typeof to === 'number') clearTimeout(to);
|
|
623
|
-
else clearTimeout(to);
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
//https://stackoverflow.com/questions/1431094/how-do-i-replace-a-character-at-a-particular-index-in-javascript
|
|
628
|
-
export function setCharAt(str: string, index: number, chr: string): string {
|
|
629
|
-
if (index > str.length - 1) return str;
|
|
630
|
-
return str.substring(0, index) + chr + str.substring(index + 1);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
//https://stackoverflow.com/questions/273789/is-there-a-version-of-javascripts-string-indexof-that-allows-for-regular-expr
|
|
634
|
-
export function regexIndexOf(string: string, regex: RegExp, startpos: number): number {
|
|
635
|
-
const indexOf = string.substring(startpos || 0).search(regex);
|
|
636
|
-
return indexOf >= 0 ? indexOf + (startpos || 0) : indexOf;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
export function convertRGBtoHEX(rgb: string): string | undefined {
|
|
640
|
-
const match: RegExpMatchArray | null = rgb.match(/^rgb\((\d+), \s*(\d+), \s*(\d+)\)$/);
|
|
641
|
-
if (match === null) return;
|
|
642
|
-
if (match.length < 3) return;
|
|
643
|
-
function hexCode(i: string): string {
|
|
644
|
-
// Take the last 2 characters and convert
|
|
645
|
-
// them to Hexadecimal.
|
|
646
|
-
|
|
647
|
-
return ('0' + parseInt(i).toString(16)).slice(-2);
|
|
648
|
-
}
|
|
649
|
-
return '#' + hexCode(match[1]) + hexCode(match[2]) + hexCode(match[3]);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
653
|
-
interface LastIndex extends String {
|
|
654
|
-
lastIndexOfRegex(regex: RegExp): number;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
(String.prototype as unknown as LastIndex).lastIndexOfRegex = function (regex: RegExp): number {
|
|
658
|
-
const match = this.match(regex);
|
|
659
|
-
return match ? this.lastIndexOf(match[match.length - 1]) : -1;
|
|
660
|
-
};
|
|
661
|
-
|
|
662
|
-
export const trailingComposeChars = /[\u02B0-\u02FF`´^¨~]+$|⎄.*$/;
|
|
663
|
-
|
|
664
|
-
//https://stackoverflow.com/questions/36532307/rem-px-in-javascript
|
|
665
|
-
export function convertRemToPixels(rem: number): number {
|
|
666
|
-
return rem * parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
export function getMode2(config: MonkeyTypes.Config, randomQuote: MonkeyTypes.Quote): string {
|
|
670
|
-
const mode = config.mode;
|
|
671
|
-
if (mode === 'time') {
|
|
672
|
-
return config.time.toString();
|
|
673
|
-
} else if (mode === 'words') {
|
|
674
|
-
return config.words.toString();
|
|
675
|
-
} else if (mode === 'custom') {
|
|
676
|
-
return 'custom';
|
|
677
|
-
} else if (mode === 'zen') {
|
|
678
|
-
return 'zen';
|
|
679
|
-
} else if (mode === 'quote') {
|
|
680
|
-
return randomQuote.id.toString();
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
return '';
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
/**
|
|
687
|
-
* Gets an integer between min and max, both are inclusive.
|
|
688
|
-
* @param min
|
|
689
|
-
* @param max
|
|
690
|
-
* @returns Random integer betwen min and max.
|
|
691
|
-
*/
|
|
692
|
-
export function randomIntFromRange(min: number, max: number): number {
|
|
693
|
-
const minNorm = Math.ceil(min);
|
|
694
|
-
const maxNorm = Math.floor(max);
|
|
695
|
-
return Math.floor(Math.random() * (maxNorm - minNorm + 1) + minNorm);
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
/**
|
|
699
|
-
* Shuffle an array of elements using the Fisher–Yates algorithm.
|
|
700
|
-
* This function mutates the input array.
|
|
701
|
-
* @param elements
|
|
702
|
-
*/
|
|
703
|
-
export function shuffle<T>(elements: T[]): void {
|
|
704
|
-
for (let i = elements.length - 1; i > 0; --i) {
|
|
705
|
-
const j = randomIntFromRange(0, i);
|
|
706
|
-
const temp = elements[j];
|
|
707
|
-
elements[j] = elements[i];
|
|
708
|
-
elements[i] = temp;
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
export function randomElementFromArray<T>(array: T[]): T {
|
|
713
|
-
return array[randomIntFromRange(0, array.length - 1)];
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
export function randomElementFromObject<T extends object>(object: T): T[keyof T] {
|
|
717
|
-
return randomElementFromArray(Object.values(object));
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
export function createErrorMessage(error: unknown, message: string): string {
|
|
721
|
-
if (error instanceof Error) {
|
|
722
|
-
return `${message}: ${error.message}`;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
const objectWithMessage = error as { message?: string };
|
|
726
|
-
|
|
727
|
-
if (objectWithMessage?.message) {
|
|
728
|
-
return `${message}: ${objectWithMessage.message}`;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
return message;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
export async function getDiscordAvatarUrl(
|
|
735
|
-
discordId?: string,
|
|
736
|
-
discordAvatar?: string,
|
|
737
|
-
discordAvatarSize = 32
|
|
738
|
-
): Promise<string | null> {
|
|
739
|
-
if (!discordId || !discordAvatar) {
|
|
740
|
-
return null;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
// An invalid request to this URL will return a 404.
|
|
744
|
-
try {
|
|
745
|
-
const avatarUrl = `https://cdn.discordapp.com/avatars/${discordId}/${discordAvatar}.png?size=${discordAvatarSize}`;
|
|
746
|
-
|
|
747
|
-
const response = await fetch(avatarUrl);
|
|
748
|
-
if (!response.ok) {
|
|
749
|
-
return null;
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
return avatarUrl;
|
|
753
|
-
} catch (error) {
|
|
754
|
-
console.error(error);
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
return null;
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
export function getLevel(xp: number): number {
|
|
761
|
-
return (1 / 98) * (-151 + Math.sqrt(392 * xp + 22801)) + 1;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
export function getXpForLevel(level: number): number {
|
|
765
|
-
return 49 * (level - 1) + 100;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
export function abbreviateNumber(num: number): string {
|
|
769
|
-
if (num < 1000) {
|
|
770
|
-
return num.toString();
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
const exp = Math.floor(Math.log(num) / Math.log(1000));
|
|
774
|
-
const pre = 'kmbtqQsSond'.charAt(exp - 1);
|
|
775
|
-
return (num / Math.pow(1000, exp)).toFixed(1) + pre;
|
|
776
|
-
}
|