Skip to content

Commit 50a7897

Browse files
authored
Update script.js
1 parent bcdfe91 commit 50a7897

1 file changed

Lines changed: 139 additions & 131 deletions

File tree

script.js

Lines changed: 139 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,39 @@ let previousWord = null;
44
let voice = null;
55
let currentMode = "easy";
66
let filteredWords = [];
7-
let wordStats = {}; // { word: { failures: 0, successes: 0 } }
7+
let wordStats = {}; // Track {word: {failures: 0, successes: 0}}
88

9-
/* ===== Sound Feedback ===== */
10-
const clickSound = new Audio("click.wav"); // Put click.wav in same folder
9+
// ===== Sound effect =====
10+
const clickSound = new Audio("click.wav");
1111

12-
/* ===== Glow Helper ===== */
13-
function triggerGlow(btn) {
14-
if (!btn) return;
15-
btn.classList.remove("button-glow");
16-
void btn.offsetWidth; // Force reflow
17-
btn.classList.add("button-glow");
18-
clickSound.currentTime = 0;
19-
clickSound.play();
20-
}
12+
// ===== License Popup Logic =====
13+
const licensePopup = document.getElementById("licensePopup");
14+
const closePopupBtn = document.getElementById("closePopup");
15+
const dontShowCheckbox = document.getElementById("dontShowAgain");
2116

22-
/* ===== Stats & Word Logic ===== */
23-
function isEasyWord(word) {
24-
return word.length <= 7;
17+
// Show popup if user hasn't opted out
18+
if (!localStorage.getItem("hideLicensePopup")) {
19+
licensePopup.style.display = "flex";
2520
}
2621

22+
// Close popup function
23+
closePopupBtn.onclick = () => {
24+
triggerGlow(closePopupBtn);
25+
if (dontShowCheckbox.checked) {
26+
localStorage.setItem("hideLicensePopup", "true");
27+
}
28+
licensePopup.style.display = "none";
29+
clickSound.play();
30+
};
31+
32+
// ===== Word Stats Storage =====
2733
function loadWordStats() {
28-
const stored = localStorage.getItem("spellingBeeWordStats");
34+
const stored = localStorage.getItem('spellingBeeWordStats');
2935
wordStats = stored ? JSON.parse(stored) : {};
3036
}
3137

3238
function saveWordStats() {
33-
localStorage.setItem("spellingBeeWordStats", JSON.stringify(wordStats));
39+
localStorage.setItem('spellingBeeWordStats', JSON.stringify(wordStats));
3440
}
3541

3642
function initWordStat(word) {
@@ -67,12 +73,32 @@ function manuallyAddToPractice(word) {
6773
alert(`"${word}" has been added to practice mode!`);
6874
}
6975

76+
function clearCache() {
77+
if (confirm("Are you sure? This will delete all your progress and your unlock status.")) {
78+
localStorage.removeItem('spellingBeeWordStats');
79+
localStorage.removeItem("hideLicensePopup");
80+
wordStats = {};
81+
currentMode = "easy";
82+
previousWord = null;
83+
document.getElementById("difficultyMode").value = "easy";
84+
filterWordsByMode();
85+
updatePracticeModeLabel();
86+
pickWord();
87+
alert("Cache cleared! Your progress has been reset.");
88+
}
89+
}
90+
91+
// ===== Word Filtering / Practice Mode =====
92+
function getStruggleWords() {
93+
return words.map(w => w.word).filter(word => isTrulyStruggling(word));
94+
}
95+
7096
function getUniqueWordsWithFailures() {
71-
return Object.keys(wordStats).filter((w) => wordStats[w].failures > 0).length;
97+
return Object.keys(wordStats).filter(word => wordStats[word].failures > 0).length;
7298
}
7399

74100
function getUniqueStrugglingWords() {
75-
return Object.keys(wordStats).filter(isTrulyStruggling).length;
101+
return Object.keys(wordStats).filter(word => isTrulyStruggling(word)).length;
76102
}
77103

78104
function isPracticeModeUnlocked() {
@@ -83,42 +109,20 @@ function shouldRelock() {
83109
return getUniqueStrugglingWords() < 10 && currentMode === "practice";
84110
}
85111

86-
function getStruggleWords() {
87-
return words.map((w) => w.word).filter(isTrulyStruggling);
88-
}
89-
90-
/* ===== Filter Words ===== */
91-
function filterWordsByMode() {
92-
if (currentMode === "easy") {
93-
filteredWords = words.filter((w) => isEasyWord(w.word));
94-
} else if (currentMode === "hard") {
95-
filteredWords = words.filter((w) => !isEasyWord(w.word));
96-
} else if (currentMode === "practice") {
97-
if (!isPracticeModeUnlocked()) {
98-
currentMode = "easy";
99-
filteredWords = words.filter((w) => isEasyWord(w.word));
100-
return;
101-
}
102-
const strugglingList = getStruggleWords();
103-
filteredWords = words.filter((w) => strugglingList.includes(w.word));
104-
}
105-
}
106-
107-
/* ===== Practice Mode Label ===== */
108112
function updatePracticeModeLabel() {
109113
const practiceOption = document.getElementById("practiceOption");
110114
if (!practiceOption) return;
111115

112116
const warningText = document.getElementById("practiceWarning");
113117

114118
if (isPracticeModeUnlocked()) {
115-
practiceOption.textContent = "Practice (Unlocked)";
119+
practiceOption.textContent = `Practice (Unlocked)`;
116120
practiceOption.style.fontWeight = "bold";
117121
practiceOption.style.color = "green";
118122
} else {
119-
practiceOption.textContent = "Practice (Locked)";
120-
practiceOption.style.fontWeight = "";
123+
practiceOption.textContent = `Practice (Locked)`;
121124
practiceOption.style.color = "";
125+
practiceOption.style.fontWeight = "";
122126
}
123127

124128
if (currentMode === "practice") {
@@ -128,15 +132,46 @@ function updatePracticeModeLabel() {
128132
}
129133
}
130134

131-
/* ===== Pick Word ===== */
135+
function filterWordsByMode() {
136+
if (currentMode === "easy") {
137+
filteredWords = words.filter(w => w.word.length <= 7);
138+
} else if (currentMode === "hard") {
139+
filteredWords = words.filter(w => w.word.length > 7);
140+
} else if (currentMode === "practice") {
141+
if (!isPracticeModeUnlocked()) {
142+
currentMode = "easy";
143+
filteredWords = words.filter(w => w.word.length <= 7);
144+
return;
145+
}
146+
const strugglingList = getStruggleWords();
147+
filteredWords = words.filter(w => strugglingList.includes(w.word));
148+
}
149+
}
150+
151+
// ===== Load words =====
152+
fetch("words.json")
153+
.then(res => res.json())
154+
.then(data => {
155+
words = data;
156+
loadWordStats();
157+
updatePracticeModeLabel();
158+
filterWordsByMode();
159+
pickWord();
160+
});
161+
162+
// ===== Pick Word =====
132163
function pickWord() {
133164
if (filteredWords.length === 0) {
134-
document.getElementById("feedback").textContent =
135-
currentMode === "practice"
136-
? getUniqueWordsWithFailures() < 15
137-
? `Get 15 words wrong first to unlock Practice mode! You've got ${getUniqueWordsWithFailures()}/15.`
138-
: "Great job! No struggling words yet. Keep practicing!"
139-
: "No words available for this difficulty.";
165+
if (currentMode === "practice") {
166+
const wrongWords = getUniqueWordsWithFailures();
167+
if (wrongWords < 15) {
168+
document.getElementById("feedback").textContent = `Get 15 words wrong first to unlock Practice mode! You've got ${wrongWords}/15.`;
169+
} else {
170+
document.getElementById("feedback").textContent = "Great job! No struggling words yet. Keep practicing!";
171+
}
172+
} else {
173+
document.getElementById("feedback").textContent = "No words available for this difficulty.";
174+
}
140175
return;
141176
}
142177

@@ -151,124 +186,97 @@ function pickWord() {
151186
document.getElementById("feedback").textContent = "";
152187
}
153188

154-
/* ===== Text-to-Speech ===== */
155-
function speak(text) {
189+
// ===== Speech =====
190+
function speak(text, rate = 0.85) {
156191
speechSynthesis.cancel();
157192
const utterance = new SpeechSynthesisUtterance(text);
158-
utterance.rate = 0.85;
193+
utterance.rate = rate;
159194
utterance.voice = voice;
160195
speechSynthesis.speak(utterance);
161196
}
162197

163-
speechSynthesis.onvoiceschanged = () => {
198+
function loadVoices() {
164199
const voices = speechSynthesis.getVoices();
165-
voice = voices.find((v) => v.lang === "en-US") || voices[0];
166-
};
200+
voice = voices.find(v => v.lang === "en-US") || voices[0];
201+
}
202+
speechSynthesis.onvoiceschanged = loadVoices;
203+
204+
// ===== Button Glow + Sound =====
205+
function triggerGlow(button) {
206+
button.classList.add("button-glow");
207+
clickSound.currentTime = 0;
208+
clickSound.play();
209+
setTimeout(() => button.classList.remove("button-glow"), 300);
210+
}
211+
212+
document.querySelectorAll("button").forEach((btn) => {
213+
if (btn.id !== "closePopup") {
214+
btn.addEventListener("click", () => triggerGlow(btn));
215+
}
216+
});
167217

168-
/* ===== Button & Input Events ===== */
218+
// ===== Button Events =====
169219
document.getElementById("sayWord").onclick = () => speak(current.word);
170-
document.getElementById("saySlow").onclick = () => {
171-
const u = new SpeechSynthesisUtterance(current.word);
172-
u.rate = 0.35;
173-
u.voice = voice;
174-
speechSynthesis.speak(u);
175-
};
220+
document.getElementById("saySlow").onclick = () => speak(current.word, 0.35);
176221
document.getElementById("saySentence").onclick = () => speak(current.sentence);
177222
document.getElementById("sayDefinition").onclick = () => speak(current.definition);
178223

179224
document.getElementById("check").onclick = () => {
180-
triggerGlow(document.getElementById("check"));
181225
const guess = document.getElementById("answer").value.trim().toLowerCase();
182-
if (guess === current.word.toLowerCase()) {
183-
document.getElementById("feedback").textContent = "Correct!";
184-
document.getElementById("feedback").style.color = "green";
226+
const correct = current.word.toLowerCase();
227+
const feedback = document.getElementById("feedback");
228+
229+
if (guess === correct) {
230+
feedback.textContent = "Correct!";
231+
feedback.style.color = "green";
185232
recordSuccess(current.word);
186233
} else {
187-
document.getElementById("feedback").textContent = `Incorrect! The correct spelling is ${current.word}`;
188-
document.getElementById("feedback").style.color = "red";
234+
feedback.textContent = `Incorrect! The correct spelling is ${current.word}`;
235+
feedback.style.color = "red";
189236
recordFailure(current.word);
190237
}
191-
192238
updatePracticeModeLabel();
193239

194240
if (shouldRelock()) {
195241
currentMode = "easy";
196242
document.getElementById("difficultyMode").value = "easy";
197243
filterWordsByMode();
198244
pickWord();
199-
alert(
200-
"Practice mode re-locked! You have fewer than 10 struggling words. Master more words to unlock it again!"
201-
);
245+
alert("Practice mode re-locked! You have fewer than 10 struggling words. Master more words to unlock it again!");
202246
updatePracticeModeLabel();
203247
}
204248
};
205249

206-
document.getElementById("next").onclick = () => {
207-
triggerGlow(document.getElementById("next"));
208-
pickWord();
209-
};
210-
211-
document.getElementById("addToPractice").onclick = () => {
212-
if (current) manuallyAddToPractice(current.word);
213-
};
214-
215-
document.getElementById("clearCache").onclick = () => {
216-
if (
217-
confirm(
218-
"Are you sure? This will delete all your progress and your unlock status."
219-
)
220-
) {
221-
localStorage.removeItem("spellingBeeWordStats");
222-
wordStats = {};
223-
currentMode = "easy";
224-
document.getElementById("difficultyMode").value = "easy";
225-
filterWordsByMode();
226-
pickWord();
227-
alert("Cache cleared! Progress reset.");
228-
}
229-
};
250+
document.getElementById("next").onclick = pickWord;
251+
document.getElementById("addToPractice").onclick = () => current && manuallyAddToPractice(current.word);
252+
document.getElementById("clearCache").onclick = clearCache;
230253

254+
// ===== Mode Selector =====
231255
document.getElementById("difficultyMode").onchange = (e) => {
232-
const selected = e.target.value;
233-
if (selected === "practice" && !isPracticeModeUnlocked()) {
234-
alert(
235-
`Practice mode unlocks after getting 15 words wrong!\nYou've got ${getUniqueWordsWithFailures()}/15.`
236-
);
237-
e.target.value = currentMode;
256+
const selectedMode = e.target.value;
257+
258+
if (selectedMode === "practice" && !isPracticeModeUnlocked()) {
259+
const wrongWords = getUniqueWordsWithFailures();
260+
alert(`Practice mode unlocks after getting 15 words wrong!\nYou've got ${wrongWords}/15.`);
261+
document.getElementById("difficultyMode").value = currentMode;
238262
return;
239263
}
240-
currentMode = selected;
264+
265+
currentMode = selectedMode;
241266
filterWordsByMode();
242267
updatePracticeModeLabel();
243268
pickWord();
244269
};
245270

246-
/* ===== Keyboard Shortcuts ===== */
271+
// ===== Keyboard Shortcuts =====
247272
document.addEventListener("keydown", (e) => {
248-
if (e.key === "Enter") {
249-
e.preventDefault();
250-
document.getElementById("check").click();
251-
}
252-
if (e.key === "Shift") {
253-
e.preventDefault();
254-
document.getElementById("next").click();
255-
}
256-
});
257-
258-
/* ===== Glow on all buttons (except popup) ===== */
259-
document.querySelectorAll("button").forEach((btn) => {
260-
if (btn.id !== "closePopup") {
261-
btn.addEventListener("click", () => triggerGlow(btn));
273+
if (e.target.tagName === "INPUT") {
274+
if (e.key === "Enter") {
275+
e.preventDefault();
276+
document.getElementById("check").click();
277+
} else if (e.key === "Shift") {
278+
e.preventDefault();
279+
document.getElementById("next").click();
280+
}
262281
}
263282
});
264-
265-
/* ===== Load Words ===== */
266-
fetch("words.json")
267-
.then((res) => res.json())
268-
.then((data) => {
269-
words = data;
270-
loadWordStats();
271-
updatePracticeModeLabel();
272-
filterWordsByMode();
273-
pickWord();
274-
});

0 commit comments

Comments
 (0)