@testgorilla/tgo-typing-test 0.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/.eslintrc.json +45 -0
- package/README.md +95 -0
- package/jest.config.ts +21 -0
- package/ng-package.json +15 -0
- package/package.json +20 -0
- package/project.json +36 -0
- package/src/assets/typing-test-languages/english.json +207 -0
- package/src/assets/typing-test-languages/english_punctuation.json +18 -0
- package/src/assets/typing-test-languages/quotes/english_version_1.json +35291 -0
- package/src/assets/typing-test-languages/quotes/english_version_2.json +720 -0
- package/src/assets/typing-test-languages/quotes/filtered_sources.json +79 -0
- package/src/index.ts +2 -0
- package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.html +30 -0
- package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.spec.ts +250 -0
- package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.ts +48 -0
- package/src/lib/components/tgo-typing-test/tgo-typing-test.component.html +72 -0
- package/src/lib/components/tgo-typing-test/tgo-typing-test.component.spec.ts +699 -0
- package/src/lib/components/tgo-typing-test/tgo-typing-test.component.ts +294 -0
- package/src/lib/helpers/config.ts +28 -0
- package/src/lib/helpers/constants/default-config.ts +103 -0
- package/src/lib/helpers/controllers/input-controller.ts +710 -0
- package/src/lib/helpers/controllers/quotes-controller.ts +183 -0
- package/src/lib/helpers/observables/banner-event.ts +18 -0
- package/src/lib/helpers/observables/config-event.ts +31 -0
- package/src/lib/helpers/observables/timer-event.ts +18 -0
- package/src/lib/helpers/states/active-page.ts +9 -0
- package/src/lib/helpers/states/composition.ts +29 -0
- package/src/lib/helpers/states/page-transition.ts +9 -0
- package/src/lib/helpers/states/slow-timer.ts +16 -0
- package/src/lib/helpers/states/test-active.ts +9 -0
- package/src/lib/helpers/states/time.ts +13 -0
- package/src/lib/helpers/test/caps-warning.ts +50 -0
- package/src/lib/helpers/test/caret.ts +92 -0
- package/src/lib/helpers/test/custom-text.ts +73 -0
- package/src/lib/helpers/test/english-punctuation.ts +38 -0
- package/src/lib/helpers/test/focus.ts +39 -0
- package/src/lib/helpers/test/manual-restart-tracker.ts +13 -0
- package/src/lib/helpers/test/out-of-focus.ts +19 -0
- package/src/lib/helpers/test/replay.ts +265 -0
- package/src/lib/helpers/test/test-input.ts +320 -0
- package/src/lib/helpers/test/test-logic.ts +1039 -0
- package/src/lib/helpers/test/test-state.ts +17 -0
- package/src/lib/helpers/test/test-stats.ts +442 -0
- package/src/lib/helpers/test/test-timer.ts +209 -0
- package/src/lib/helpers/test/test-ui.ts +370 -0
- package/src/lib/helpers/test/test-words.ts +72 -0
- package/src/lib/helpers/test/timer-progress.ts +16 -0
- package/src/lib/helpers/test/tts.ts +42 -0
- package/src/lib/helpers/test/weak-spot.ts +74 -0
- package/src/lib/helpers/test/wordset.ts +109 -0
- package/src/lib/styles/animations.scss +101 -0
- package/src/lib/styles/caret.scss +108 -0
- package/src/lib/styles/core.scss +498 -0
- package/src/lib/styles/index.scss +19 -0
- package/src/lib/styles/inputs.scss +290 -0
- package/src/lib/styles/popups.scss +1311 -0
- package/src/lib/styles/test.scss +1008 -0
- package/src/lib/styles/z_media-queries.scss +848 -0
- package/src/lib/types/types.d.ts +731 -0
- package/src/lib/utils/misc.ts +776 -0
- package/src/test-setup.ts +1 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +14 -0
- package/tsconfig.lib.prod.json +9 -0
- package/tsconfig.spec.json +11 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sources":[
|
|
3
|
+
"Thing Explainer: Complicated Stuff in Simple Words",
|
|
4
|
+
"Don Quixote",
|
|
5
|
+
"The Good Place",
|
|
6
|
+
"Star Trek: Generations",
|
|
7
|
+
"The Lord of The Rings",
|
|
8
|
+
"Thus Spoke Zarathustra: A Book for None and All",
|
|
9
|
+
"The Two Towers",
|
|
10
|
+
"Richard Feynman",
|
|
11
|
+
"The Joy of Painting",
|
|
12
|
+
"The Fellowship of the Ring",
|
|
13
|
+
"The Lord of the Rings: The Two Towers",
|
|
14
|
+
"The Complete Calvin and Hobbes",
|
|
15
|
+
"So Long, and Thanks for All the Fish",
|
|
16
|
+
"Elon Musk: Tesla, SpaceX, and the Quest for a Fantastic Future",
|
|
17
|
+
"It's Not Rocket Science: 7 Game-Changing Traits for Uncommon Success",
|
|
18
|
+
"Lord of the Rings: The Return of the King",
|
|
19
|
+
"Discourse on Method",
|
|
20
|
+
"The Hitchhiker's Guide to the Galaxy",
|
|
21
|
+
"Star Trek",
|
|
22
|
+
"The Hobbit",
|
|
23
|
+
"Hitchhiker's Guide to the Galaxy",
|
|
24
|
+
"Moby Dick",
|
|
25
|
+
"Harry Potter and the Philosopher's Stone",
|
|
26
|
+
"Charlotte's Web",
|
|
27
|
+
"Ratatouille",
|
|
28
|
+
"The First Philosophers: The Presocratics and the Sophists",
|
|
29
|
+
"Ollie's Lost",
|
|
30
|
+
"Harry Potter and the Half-Blood Prince",
|
|
31
|
+
"Shrek",
|
|
32
|
+
"Notting Hill",
|
|
33
|
+
"The Power of Meaning",
|
|
34
|
+
"Electronics For Dummies",
|
|
35
|
+
"Philosophy of Social Science (Dimensions of Philosophy) 5th Edition",
|
|
36
|
+
"Agricultural Geology",
|
|
37
|
+
"War and Peace",
|
|
38
|
+
"On Food and Cooking: The Science and Lore of the Kitchen",
|
|
39
|
+
"Return of the Jedi",
|
|
40
|
+
"The Greatest Cases Of Sherlock Holmes",
|
|
41
|
+
"The Rust Programming Language",
|
|
42
|
+
"Freakonomics",
|
|
43
|
+
"How Not to Be Wrong: The Power of Mathematical Thinking",
|
|
44
|
+
"Back to the Future",
|
|
45
|
+
"Economics in One Lesson",
|
|
46
|
+
"The Empire Strikes Back",
|
|
47
|
+
"Magnets and Motors: Teacher's Guide",
|
|
48
|
+
"Interstellar",
|
|
49
|
+
"The Wizard of Oz",
|
|
50
|
+
"Back To The Future - Part 2",
|
|
51
|
+
"Super Mario 64 Player's Guide",
|
|
52
|
+
"Harry Potter and the Goblet of Fire",
|
|
53
|
+
"Improving Reading Skills",
|
|
54
|
+
"Physics for Game Developers",
|
|
55
|
+
"Cracking the Coding Interview",
|
|
56
|
+
"Star Trek: The Next Generation",
|
|
57
|
+
"2001: A SPACE ODYSSEY",
|
|
58
|
+
"The Thermodynamics of Pizza",
|
|
59
|
+
"Computing Machinery and Intelligence",
|
|
60
|
+
"Astronomy: A Beginner's Guide to the Universe (7th Edition)",
|
|
61
|
+
"Cars",
|
|
62
|
+
"Essentials of Economics",
|
|
63
|
+
"Tom Sawyer",
|
|
64
|
+
"Holidays on Ice",
|
|
65
|
+
"SpongeBob SquarePants",
|
|
66
|
+
"Paper Mario: Color Splash",
|
|
67
|
+
"The Complete Project Manager",
|
|
68
|
+
"Classical Mythology",
|
|
69
|
+
"Scooby-Doo! Mystery Incorporated",
|
|
70
|
+
"Dr. Seuss' How the Grinch Stole Christmas!",
|
|
71
|
+
"Willy Wonka, Charlie and the Chocolate Factory",
|
|
72
|
+
"Dr. Doofenshmirtz, Phineas and Ferb",
|
|
73
|
+
"Heinz Doofenshmirtz, Phineas and Ferb",
|
|
74
|
+
"The Behaviour of the Domestic Cat by John W.S. Bradshaw",
|
|
75
|
+
"Hiccup, How To Train Your Dragon 2",
|
|
76
|
+
"Plato: Five Dialogues",
|
|
77
|
+
"TestGorilla"
|
|
78
|
+
]
|
|
79
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<div id="centerContent">
|
|
2
|
+
<div id="middle" #middle>
|
|
3
|
+
<div class="page pageTest active">
|
|
4
|
+
<div id="result" tabindex="0">
|
|
5
|
+
<div class="bottom" style="grid-column: 1/3">
|
|
6
|
+
<div id="resultReplay">
|
|
7
|
+
<div class="title">
|
|
8
|
+
Watch replay
|
|
9
|
+
<span
|
|
10
|
+
id="playpauseReplayButton"
|
|
11
|
+
class="textButton"
|
|
12
|
+
aria-label="Start replay"
|
|
13
|
+
data-balloon-pos="up"
|
|
14
|
+
style="display: inline-block"
|
|
15
|
+
(click)="playpauseReplayButtonClick()"
|
|
16
|
+
#toggleButton
|
|
17
|
+
>
|
|
18
|
+
<div id="key" class="Play" #playpauseelem>{{ playpauseelem.className }}</div>
|
|
19
|
+
</span>
|
|
20
|
+
<p id="replayStopwatch" #replayStopwatch>0s</p>
|
|
21
|
+
</div>
|
|
22
|
+
<div id="wordsWrapper">
|
|
23
|
+
<div id="replayWords" class="words"></div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { ElementRef } from '@angular/core';
|
|
3
|
+
import { TgoTypingReplayInputComponent } from './tgo-typing-replay-input.component';
|
|
4
|
+
import * as config from '../../helpers/config';
|
|
5
|
+
import * as replay from '../../helpers/test/replay';
|
|
6
|
+
|
|
7
|
+
jest.mock('../../helpers/config');
|
|
8
|
+
jest.mock('../../helpers/test/replay');
|
|
9
|
+
|
|
10
|
+
describe('TgoTypingReplayInputComponent', () => {
|
|
11
|
+
let component: TgoTypingReplayInputComponent;
|
|
12
|
+
let fixture: ComponentFixture<TgoTypingReplayInputComponent>;
|
|
13
|
+
|
|
14
|
+
const mockReplayExport = JSON.stringify({
|
|
15
|
+
wordsList: ['word1', 'word2', 'word3'],
|
|
16
|
+
replayData: [
|
|
17
|
+
{ timestamp: 0, char: 'w' },
|
|
18
|
+
{ timestamp: 100, char: 'o' },
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
jest.clearAllMocks();
|
|
24
|
+
|
|
25
|
+
TestBed.configureTestingModule({
|
|
26
|
+
imports: [TgoTypingReplayInputComponent],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
fixture = TestBed.createComponent(TgoTypingReplayInputComponent);
|
|
30
|
+
component = fixture.componentInstance;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('when initialized', () => {
|
|
34
|
+
it('should create the component', () => {
|
|
35
|
+
expect(component).toBeDefined();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should have default funbox value', () => {
|
|
39
|
+
expect(component.funbox).toBe('none');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('#ngOnInit', () => {
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
component.replayExport = mockReplayExport;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should parse the replayExport JSON string', () => {
|
|
49
|
+
component.ngOnInit();
|
|
50
|
+
|
|
51
|
+
expect(component.replayExportData).toEqual({
|
|
52
|
+
wordsList: ['word1', 'word2', 'word3'],
|
|
53
|
+
replayData: [
|
|
54
|
+
{ timestamp: 0, char: 'w' },
|
|
55
|
+
{ timestamp: 100, char: 'o' },
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should call setFunbox with the funbox input value', () => {
|
|
61
|
+
component.funbox = 'custom-funbox';
|
|
62
|
+
|
|
63
|
+
component.ngOnInit();
|
|
64
|
+
|
|
65
|
+
expect(config.setFunbox).toHaveBeenCalledWith('custom-funbox');
|
|
66
|
+
expect(config.setFunbox).toHaveBeenCalledTimes(1);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should call replayGetWordsList with parsed wordsList', () => {
|
|
70
|
+
component.ngOnInit();
|
|
71
|
+
|
|
72
|
+
expect(replay.replayGetWordsList).toHaveBeenCalledWith(['word1', 'word2', 'word3']);
|
|
73
|
+
expect(replay.replayGetWordsList).toHaveBeenCalledTimes(1);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should call setReplayData with parsed replayData', () => {
|
|
77
|
+
component.ngOnInit();
|
|
78
|
+
|
|
79
|
+
expect(replay.setReplayData).toHaveBeenCalledWith([
|
|
80
|
+
{ timestamp: 0, char: 'w' },
|
|
81
|
+
{ timestamp: 100, char: 'o' },
|
|
82
|
+
]);
|
|
83
|
+
expect(replay.setReplayData).toHaveBeenCalledTimes(1);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('when replayExport contains different data', () => {
|
|
87
|
+
it('should handle empty wordsList and replayData', () => {
|
|
88
|
+
component.replayExport = JSON.stringify({
|
|
89
|
+
wordsList: [],
|
|
90
|
+
replayData: [],
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
component.ngOnInit();
|
|
94
|
+
|
|
95
|
+
expect(replay.replayGetWordsList).toHaveBeenCalledWith([]);
|
|
96
|
+
expect(replay.setReplayData).toHaveBeenCalledWith([]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should handle large wordsList', () => {
|
|
100
|
+
const largeWordsList = Array.from({ length: 100 }, (_, i) => `word${i}`);
|
|
101
|
+
component.replayExport = JSON.stringify({
|
|
102
|
+
wordsList: largeWordsList,
|
|
103
|
+
replayData: [],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
component.ngOnInit();
|
|
107
|
+
|
|
108
|
+
expect(replay.replayGetWordsList).toHaveBeenCalledWith(largeWordsList);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('#ngAfterViewInit', () => {
|
|
114
|
+
let mockToggleButtonElement: HTMLElement;
|
|
115
|
+
let mockReplayStopwatchElement: HTMLElement;
|
|
116
|
+
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
component.replayExport = mockReplayExport;
|
|
119
|
+
component.ngOnInit();
|
|
120
|
+
|
|
121
|
+
// Create mock elements
|
|
122
|
+
mockToggleButtonElement = document.createElement('button');
|
|
123
|
+
mockReplayStopwatchElement = document.createElement('div');
|
|
124
|
+
|
|
125
|
+
// Mock ViewChild ElementRef
|
|
126
|
+
component.toggleButton = {
|
|
127
|
+
nativeElement: mockToggleButtonElement,
|
|
128
|
+
} as ElementRef;
|
|
129
|
+
component.replayStopwatch = {
|
|
130
|
+
nativeElement: mockReplayStopwatchElement,
|
|
131
|
+
} as ElementRef;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should call setToggleButton with toggleButton native element', () => {
|
|
135
|
+
component.ngAfterViewInit();
|
|
136
|
+
|
|
137
|
+
expect(replay.setToggleButton).toHaveBeenCalledWith(mockToggleButtonElement);
|
|
138
|
+
expect(replay.setToggleButton).toHaveBeenCalledTimes(1);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should call setReplayStopwatch with replayStopwatch native element', () => {
|
|
142
|
+
component.ngAfterViewInit();
|
|
143
|
+
|
|
144
|
+
expect(replay.setReplayStopwatch).toHaveBeenCalledWith(mockReplayStopwatchElement);
|
|
145
|
+
expect(replay.setReplayStopwatch).toHaveBeenCalledTimes(1);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should call initializeReplayPrompt', () => {
|
|
149
|
+
component.ngAfterViewInit();
|
|
150
|
+
|
|
151
|
+
expect(replay.initializeReplayPrompt).toHaveBeenCalledTimes(1);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should call loadOldReplay', () => {
|
|
155
|
+
component.ngAfterViewInit();
|
|
156
|
+
|
|
157
|
+
expect(replay.loadOldReplay).toHaveBeenCalledTimes(1);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should call playReplay', () => {
|
|
161
|
+
component.ngAfterViewInit();
|
|
162
|
+
|
|
163
|
+
expect(replay.playReplay).toHaveBeenCalledTimes(1);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should call replay initialization functions in correct order', () => {
|
|
167
|
+
const callOrder: string[] = [];
|
|
168
|
+
|
|
169
|
+
jest.mocked(replay.setToggleButton).mockImplementation(() => {
|
|
170
|
+
callOrder.push('setToggleButton');
|
|
171
|
+
});
|
|
172
|
+
jest.mocked(replay.setReplayStopwatch).mockImplementation(() => {
|
|
173
|
+
callOrder.push('setReplayStopwatch');
|
|
174
|
+
});
|
|
175
|
+
jest.mocked(replay.initializeReplayPrompt).mockImplementation(() => {
|
|
176
|
+
callOrder.push('initializeReplayPrompt');
|
|
177
|
+
});
|
|
178
|
+
jest.mocked(replay.loadOldReplay).mockImplementation(() => {
|
|
179
|
+
callOrder.push('loadOldReplay');
|
|
180
|
+
return 0;
|
|
181
|
+
});
|
|
182
|
+
jest.mocked(replay.playReplay).mockImplementation(() => {
|
|
183
|
+
callOrder.push('playReplay');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
component.ngAfterViewInit();
|
|
187
|
+
|
|
188
|
+
expect(callOrder).toEqual([
|
|
189
|
+
'setToggleButton',
|
|
190
|
+
'setReplayStopwatch',
|
|
191
|
+
'initializeReplayPrompt',
|
|
192
|
+
'loadOldReplay',
|
|
193
|
+
'playReplay',
|
|
194
|
+
]);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('#playpauseReplayButtonClick', () => {
|
|
199
|
+
it('should call the imported playpauseReplayButtonClick function', () => {
|
|
200
|
+
component.playpauseReplayButtonClick();
|
|
201
|
+
|
|
202
|
+
expect(replay.playpauseReplayButtonClick).toHaveBeenCalledTimes(1);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should call playpauseReplayButtonClick on multiple invocations', () => {
|
|
206
|
+
component.playpauseReplayButtonClick();
|
|
207
|
+
component.playpauseReplayButtonClick();
|
|
208
|
+
component.playpauseReplayButtonClick();
|
|
209
|
+
|
|
210
|
+
expect(replay.playpauseReplayButtonClick).toHaveBeenCalledTimes(3);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
describe('when component lifecycle is complete', () => {
|
|
215
|
+
let mockToggleButtonElement: HTMLElement;
|
|
216
|
+
let mockReplayStopwatchElement: HTMLElement;
|
|
217
|
+
|
|
218
|
+
beforeEach(() => {
|
|
219
|
+
component.replayExport = mockReplayExport;
|
|
220
|
+
component.funbox = 'test-funbox';
|
|
221
|
+
|
|
222
|
+
mockToggleButtonElement = document.createElement('button');
|
|
223
|
+
mockReplayStopwatchElement = document.createElement('div');
|
|
224
|
+
|
|
225
|
+
component.toggleButton = {
|
|
226
|
+
nativeElement: mockToggleButtonElement,
|
|
227
|
+
} as ElementRef;
|
|
228
|
+
component.replayStopwatch = {
|
|
229
|
+
nativeElement: mockReplayStopwatchElement,
|
|
230
|
+
} as ElementRef;
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should initialize and setup replay completely', () => {
|
|
234
|
+
// Simulate full lifecycle
|
|
235
|
+
component.ngOnInit();
|
|
236
|
+
component.ngAfterViewInit();
|
|
237
|
+
|
|
238
|
+
// Verify all initialization steps were called
|
|
239
|
+
expect(config.setFunbox).toHaveBeenCalledWith('test-funbox');
|
|
240
|
+
expect(replay.replayGetWordsList).toHaveBeenCalled();
|
|
241
|
+
expect(replay.setReplayData).toHaveBeenCalled();
|
|
242
|
+
expect(replay.setToggleButton).toHaveBeenCalledWith(mockToggleButtonElement);
|
|
243
|
+
expect(replay.setReplayStopwatch).toHaveBeenCalledWith(mockReplayStopwatchElement);
|
|
244
|
+
expect(replay.initializeReplayPrompt).toHaveBeenCalled();
|
|
245
|
+
expect(replay.loadOldReplay).toHaveBeenCalled();
|
|
246
|
+
expect(replay.playReplay).toHaveBeenCalled();
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
|
|
2
|
+
import { setFunbox } from '../../helpers/config';
|
|
3
|
+
import {
|
|
4
|
+
initializeReplayPrompt,
|
|
5
|
+
loadOldReplay,
|
|
6
|
+
playpauseReplayButtonClick,
|
|
7
|
+
playReplay,
|
|
8
|
+
replayGetWordsList,
|
|
9
|
+
setReplayData,
|
|
10
|
+
setReplayStopwatch,
|
|
11
|
+
setToggleButton,
|
|
12
|
+
} from '../../helpers/test/replay';
|
|
13
|
+
import { CommonModule } from '@angular/common';
|
|
14
|
+
|
|
15
|
+
@Component({
|
|
16
|
+
selector: 'tgo-typing-replay-input',
|
|
17
|
+
standalone: true,
|
|
18
|
+
imports: [CommonModule],
|
|
19
|
+
templateUrl: './tgo-typing-replay-input.component.html',
|
|
20
|
+
styleUrls: ['../../styles/index.scss'],
|
|
21
|
+
})
|
|
22
|
+
export class TgoTypingReplayInputComponent implements OnInit {
|
|
23
|
+
@Input() replayExport: any;
|
|
24
|
+
@Input() funbox = 'none';
|
|
25
|
+
replayExportData: any;
|
|
26
|
+
|
|
27
|
+
@ViewChild('toggleButton') toggleButton!: ElementRef;
|
|
28
|
+
@ViewChild('replayStopwatch') replayStopwatch!: ElementRef;
|
|
29
|
+
|
|
30
|
+
ngOnInit(): void {
|
|
31
|
+
this.replayExportData = JSON.parse(this.replayExport);
|
|
32
|
+
setFunbox(this.funbox);
|
|
33
|
+
replayGetWordsList(this.replayExportData['wordsList']);
|
|
34
|
+
setReplayData(this.replayExportData['replayData']);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
ngAfterViewInit() {
|
|
38
|
+
setToggleButton(this.toggleButton.nativeElement);
|
|
39
|
+
setReplayStopwatch(this.replayStopwatch.nativeElement);
|
|
40
|
+
initializeReplayPrompt();
|
|
41
|
+
loadOldReplay();
|
|
42
|
+
playReplay();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
playpauseReplayButtonClick() {
|
|
46
|
+
playpauseReplayButtonClick();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<div id="centerContent">
|
|
2
|
+
<div id="middle" #middle>
|
|
3
|
+
<div class="page pageTest active">
|
|
4
|
+
<div id="typingTest">
|
|
5
|
+
<div id="capsWarning" [ngClass]="{ hidden: (showCaps$ | async) === false }" #capsWarning>
|
|
6
|
+
Caps Lock
|
|
7
|
+
</div>
|
|
8
|
+
<div id="memoryTimer">Time left to memorise all words: 0s</div>
|
|
9
|
+
<div id="testModesNotice"></div>
|
|
10
|
+
<input
|
|
11
|
+
id="wordsInput"
|
|
12
|
+
class=""
|
|
13
|
+
tabindex="0"
|
|
14
|
+
type="text"
|
|
15
|
+
autocomplete="off"
|
|
16
|
+
autocapitalize="off"
|
|
17
|
+
autocorrect="off"
|
|
18
|
+
data-gramm="false"
|
|
19
|
+
data-gramm_editor="false"
|
|
20
|
+
data-enable-grammarly="false"
|
|
21
|
+
list="autocompleteOff"
|
|
22
|
+
(keyup)="wordsInputKeyup($event)"
|
|
23
|
+
(beforeinput)="wordsInputBeforeinput($event)"
|
|
24
|
+
(input)="wordsInputInput($event)"
|
|
25
|
+
(focus)="wordsInputFocus($event)"
|
|
26
|
+
(focusout)="wordsInputFocusOut()"
|
|
27
|
+
(copy)="wordsInputCopy($event)"
|
|
28
|
+
(paste)="wordsInputPaste($event)"
|
|
29
|
+
(compositionstart)="wordsInputCompositionstart()"
|
|
30
|
+
(compositionend)="wordsInputCompositionend()"
|
|
31
|
+
#wordsInput
|
|
32
|
+
/>
|
|
33
|
+
@if (showMiniTimerAndLiveWpm) {
|
|
34
|
+
<div id="miniTimerAndLiveWpm" class="timerMain size2">
|
|
35
|
+
<div class="time" [@fadeIn]="(showTimer$ | async) ? 'show' : 'hide'">
|
|
36
|
+
{{ timeLeft$ | async }}
|
|
37
|
+
</div>
|
|
38
|
+
<div class="wpm hidden">60</div>
|
|
39
|
+
<div class="acc hidden">100%</div>
|
|
40
|
+
<div class="burst hidden">1</div>
|
|
41
|
+
</div>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@if (outOfFocusShow$ | async) {
|
|
45
|
+
<div class="outOfFocusWarning">
|
|
46
|
+
Click or press any key to focus
|
|
47
|
+
</div>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@if (errorEvent | async; as errorMessage) {
|
|
51
|
+
<div class="errorWarning">
|
|
52
|
+
{{ errorMessage }} Reload the page or <a href="https://candidates.testgorilla.com/hc/en-us/requests/new" target="_blank">contact support</a>.
|
|
53
|
+
</div>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
<div id="wordsWrapper" translate="no" #wordsWrapper (click)="wordsWrapperClick()">
|
|
57
|
+
<div id="paceCaret" class="default size2 hidden"></div>
|
|
58
|
+
@if (showCaret$ | async) {
|
|
59
|
+
<div id="caret" [@updatePositionCaret]="{
|
|
60
|
+
value: state,
|
|
61
|
+
params: { caretTopPos: caretTop, caretLeftPos: caretLeft }
|
|
62
|
+
}"
|
|
63
|
+
[ngStyle]="{ 'animation-name': (caretAnimation$ | async) }" class="default size2">
|
|
64
|
+
</div>
|
|
65
|
+
}
|
|
66
|
+
<div id="words" class="size2" #words [ngClass]="{ blurred: (outOfFocusShow$ | async) }"></div>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|