forked from microsoft/Web-Dev-For-Beginners
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
112 lines (95 loc) · 3.63 KB
/
index.js
File metadata and controls
112 lines (95 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Typing Game - Modern ES6+ Version
// Quotes pool
const quotes = [
"When you have eliminated the impossible, whatever remains, however improbable, must be the truth.",
"There is nothing more deceptive than an obvious fact.",
"I ought to know by this time that when a fact appears to be opposed to a long train of deductions it invariably proves to be capable of bearing some other interpretation.",
"I never make exceptions. An exception disproves the rule.",
"What one man can invent another can discover.",
"Nothing clears up a case so much as stating it to another person.",
"Education never ends, Watson. It is a series of lessons, with the greatest for the last."
];
// State
let words = [];
let wordIndex = 0;
let startTime = 0;
// UI Elements
const quoteElement = document.querySelector("#quote");
const messageElement = document.querySelector("#message");
const typedValueElement = document.querySelector("#typed-value");
const startButton = document.querySelector("#start");
// Messages system
const messages = {
success: (seconds, wpm) => `🎉 Congratulations! You finished in ${seconds.toFixed(2)} seconds (${wpm} WPM).`,
error: "⚠️ Oops! There's a mistake.",
start: "⌨️ Start typing to begin the game."
};
// Utility: pick random quote
const getRandomQuote = () => quotes[Math.floor(Math.random() * quotes.length)];
// Utility: render quote as spans
const renderQuote = (quote) => {
quoteElement.innerHTML = quote
.split(" ")
.map((word, i) => `<span ${i === 0 ? 'class="highlight"' : ""}>${word}</span>`)
.join(" ");
};
// Utility: highlight current word
const highlightWord = (index) => {
[...quoteElement.children].forEach((el, i) => {
el.classList.toggle("highlight", i === index);
});
};
// Game start
const startGame = () => {
const quote = getRandomQuote();
words = quote.split(" ");
wordIndex = 0;
renderQuote(quote);
messageElement.textContent = messages.start;
typedValueElement.value = "";
typedValueElement.focus();
startTime = Date.now();
};
// Typing logic
const handleTyping = () => {
const currentWord = words[wordIndex];
const typedValue = typedValueElement.value;
if (typedValue === currentWord && wordIndex === words.length - 1) {
// Game finished
const elapsedTime = (Date.now() - startTime) / 1000;
const elapsedMinutes = elapsedTime / 60;
const wordCount = words.length;
const wpm = (wordCount / elapsedMinutes).toFixed(2);
messageElement.textContent = messages.success(elapsedTime, wpm);
typedValueElement.disabled = true;
document.getElementById("reset").style.display = "inline-block";
document.getElementById("start").style.display = "none";
} else if (typedValue.endsWith(" ") && typedValue.trim() === currentWord) {
// Word completed
typedValueElement.value = "";
wordIndex++;
highlightWord(wordIndex);
} else if (currentWord.startsWith(typedValue)) {
// Correct so far
typedValueElement.classList.remove("error");
} else {
// Error
typedValueElement.classList.add("error");
messageElement.textContent = messages.error;
}
};
// Event Listeners
startButton.addEventListener("click", startGame);
typedValueElement.addEventListener("input", handleTyping);
// Default state
messageElement.textContent = "👉 Click Start to begin!";
const resetButton = document.getElementById("reset");
resetButton.addEventListener("click", () => {
// Reset game state
typedValueElement.disabled = false;
typedValueElement.value = "";
messageElement.textContent = "👉 Click Start to begin!";
quoteElement.innerHTML = "";
startButton.style.display = "inline-block";
resetButton.style.display = "none";
});