english-easy/js/script.js

354 lines
10 KiB
JavaScript

// Mobile menu toggle
document.addEventListener('DOMContentLoaded', function() {
const toggle = document.querySelector('.menu-toggle');
const navList = document.querySelector('.nav-list');
if (toggle) {
toggle.addEventListener('click', function() {
navList.classList.toggle('open');
});
}
// Close menu on link click
const navLinks = document.querySelectorAll('.nav-list a');
navLinks.forEach(function(link) {
link.addEventListener('click', function() {
if (navList) navList.classList.remove('open');
});
});
// Highlight active page in nav
const currentPage = window.location.pathname.split('/').pop() || 'index.html';
navLinks.forEach(function(link) {
const href = link.getAttribute('href');
if (href === currentPage) {
link.classList.add('active');
}
});
});
// --- Exercises ---
function checkExercise(btn) {
const exercise = btn.closest('.exercise');
const selected = exercise.querySelector('input[type="radio"]:checked');
const feedback = exercise.querySelector('.feedback');
if (!selected) {
feedback.textContent = 'Please select an answer!';
feedback.className = 'feedback wrong';
feedback.style.display = 'block';
return;
}
const options = exercise.querySelectorAll('.option');
options.forEach(function(opt) {
opt.classList.remove('correct', 'wrong');
});
const parent = selected.closest('.option');
const isCorrect = selected.value === 'true';
if (isCorrect) {
parent.classList.add('correct');
feedback.textContent = 'Correct!';
feedback.className = 'feedback correct';
} else {
parent.classList.add('wrong');
feedback.textContent = 'Try again!';
feedback.className = 'feedback wrong';
// Show correct answer
options.forEach(function(opt) {
const radio = opt.querySelector('input[type="radio"]');
if (radio && radio.value === 'true') {
opt.classList.add('correct');
}
});
}
feedback.style.display = 'block';
}
function checkFill(input) {
const exercise = input.closest('.exercise');
const answer = input.getAttribute('data-answer');
const feedback = exercise.querySelector('.feedback');
input.classList.remove('correct', 'wrong');
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
input.classList.add('correct');
feedback.textContent = 'Correct!';
feedback.className = 'feedback correct';
} else {
input.classList.add('wrong');
feedback.textContent = 'Try again! Correct answer: ' + answer;
feedback.className = 'feedback wrong';
}
feedback.style.display = 'block';
}
function checkTranslate(btn) {
const exercise = btn.closest('.exercise');
const input = exercise.querySelector('input[type="text"]');
const feedback = exercise.querySelector('.feedback');
const answer = input.getAttribute('data-answer');
input.classList.remove('correct', 'wrong');
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
input.classList.add('correct');
feedback.textContent = 'Correct!';
feedback.className = 'feedback correct';
} else {
input.classList.add('wrong');
feedback.textContent = 'Try again! Correct answer: ' + answer;
feedback.className = 'feedback wrong';
}
feedback.style.display = 'block';
}
function checkMatch(btn) {
const exercise = btn.closest('.exercise');
const inputs = exercise.querySelectorAll('input[type="text"]');
const feedback = exercise.querySelector('.feedback');
let allCorrect = true;
inputs.forEach(function(input) {
const answer = input.getAttribute('data-answer');
input.classList.remove('correct', 'wrong');
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
input.classList.add('correct');
} else {
input.classList.add('wrong');
allCorrect = false;
}
});
if (allCorrect) {
feedback.textContent = 'All correct! Great job!';
feedback.className = 'feedback correct';
} else {
feedback.textContent = 'Some answers are wrong. Try again!';
feedback.className = 'feedback wrong';
}
feedback.style.display = 'block';
}
// --- Tests ---
function checkTest() {
let score = 0;
const total = document.querySelectorAll('.test-question').length;
const questions = document.querySelectorAll('.test-question');
questions.forEach(function(q) {
const selected = q.querySelector('input[type="radio"]:checked');
if (selected && selected.value === 'true') {
score++;
}
});
const resultBox = document.getElementById('test-result');
const scoreDisplay = document.getElementById('score');
scoreDisplay.textContent = score + '/' + total;
resultBox.classList.add('show');
// Scroll to result
resultBox.scrollIntoView({ behavior: 'smooth' });
}
// --- Contact form ---
function submitForm(event) {
event.preventDefault();
const message = document.getElementById('form-message');
message.classList.add('show');
document.getElementById('contact-form').reset();
setTimeout(function() {
message.classList.remove('show');
}, 5000);
}
// --- Pronunciation ---
function speakWord(word, rate) {
if (!window.speechSynthesis) {
alert('Speech synthesis is not supported in your browser.');
return;
}
window.speechSynthesis.cancel();
var utterance = new SpeechSynthesisUtterance(word);
utterance.lang = 'en-US';
utterance.rate = rate || 0.9;
utterance.pitch = 1;
window.speechSynthesis.speak(utterance);
}
function repeatWord(btn) {
var word = btn.getAttribute('data-word');
speakWord(word, 0.8);
btn.textContent = '🔊 Playing...';
setTimeout(function() { btn.textContent = '🔊 Listen'; }, 1500);
}
function speakSlow(btn) {
var word = btn.getAttribute('data-word');
speakWord(word, 0.4);
btn.textContent = '🐢 Slow...';
setTimeout(function() { btn.innerHTML = '🐢 Slow'; }, 2000);
}
function checkDictation(input) {
var exercise = input.closest('.exercise');
var answer = input.getAttribute('data-answer');
var feedback = exercise.querySelector('.feedback');
input.classList.remove('correct', 'wrong');
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
input.classList.add('correct');
feedback.textContent = 'Correct! Great listening!';
feedback.className = 'feedback correct';
} else {
input.classList.add('wrong');
feedback.textContent = 'Not quite. The correct word is: ' + answer;
feedback.className = 'feedback wrong';
}
feedback.style.display = 'block';
}
function speakPhrase(btn) {
var phrase = btn.getAttribute('data-phrase');
speakWord(phrase, 0.8);
btn.textContent = '🔊 Playing...';
setTimeout(function() { btn.innerHTML = '🔊 Hear Phrase'; }, 1500);
}
// --- Daily Reminder at 20:00 ---
(function() {
var LS_KEY = 'english_easy_daily';
var TOAST_SHOWN = false;
function getToday() {
return new Date().toDateString();
}
function getStreak() {
var data = JSON.parse(localStorage.getItem(LS_KEY) || '{"streak":0,"lastDate":""}');
var yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
var yesterdayStr = yesterday.toDateString();
var today = getToday();
if (data.lastDate === today) {
// already done today
} else if (data.lastDate === yesterdayStr) {
// consecutive day
} else if (data.lastDate && data.lastDate !== today) {
data.streak = 0;
}
return data;
}
function saveStreak(data) {
data.lastDate = getToday();
localStorage.setItem(LS_KEY, JSON.stringify(data));
}
function showDailyToast() {
if (TOAST_SHOWN) return;
TOAST_SHOWN = true;
var data = getStreak();
var existing = document.querySelector('.daily-toast');
if (existing) existing.remove();
var toast = document.createElement('div');
toast.className = 'daily-toast';
var streakHTML = '';
if (data.streak > 0) {
streakHTML = '<div class="streak">🔥 Day ' + data.streak + ' streak!</div>';
}
toast.innerHTML =
'<div class="toast-header">' +
'<div class="toast-title">⏰ Daily Practice</div>' +
'<button class="toast-close" onclick="this.closest(\'.daily-toast\').remove()">✕</button>' +
'</div>' +
streakHTML +
'<p>It\'s time for your daily English practice! Spend 5 minutes on an exercise or test.</p>' +
'<div class="toast-actions">' +
'<a href="exercises.html" class="btn" onclick="saveStreakFunc()">Practice Now</a>' +
'<button class="btn btn-outline" onclick="this.closest(\'.daily-toast\').remove()">Later</button>' +
'</div>';
document.body.appendChild(toast);
// trigger animation
setTimeout(function() { toast.classList.add('show'); }, 100);
// also try browser notification
if ('Notification' in window && Notification.permission === 'granted') {
new Notification('English Easy — Daily Practice', {
body: 'Time for your daily English practice! 5 minutes is all you need.',
icon: '/images/icon.png'
});
}
}
// Expose saveStreak for the toast button
window.saveStreakFunc = function() {
var data = getStreak();
data.streak = (data.streak || 0) + 1;
saveStreak(data);
};
// Request notification permission
function requestNotifPermission() {
if ('Notification' in window && Notification.permission === 'default') {
Notification.requestPermission();
}
}
function checkDailyReminder() {
var now = new Date();
var hours = now.getHours();
var minutes = now.getMinutes();
var data = getStreak();
// Show if it's >= 20:00 and we haven't shown today
if (hours >= 20 && data.lastDate !== getToday()) {
showDailyToast();
return true;
}
return false;
}
// Check on page load
document.addEventListener('DOMContentLoaded', function() {
requestNotifPermission();
checkDailyReminder();
// Check every 30 seconds if it's 20:00
setInterval(function() {
var now = new Date();
if (now.getHours() === 20 && now.getMinutes() === 0) {
checkDailyReminder();
}
}, 30000);
});
})();
// --- Vocabulary filter ---
function filterVocab(category, btn) {
const rows = document.querySelectorAll('.vocab-row');
const buttons = document.querySelectorAll('.category-btn');
buttons.forEach(function(b) { b.classList.remove('active'); });
if (btn) btn.classList.add('active');
rows.forEach(function(row) {
if (category === 'all' || row.getAttribute('data-category') === category) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
}