Spaces:
Running
Running
Update index.html
Browse files- index.html +71 -45
index.html
CHANGED
|
@@ -615,27 +615,25 @@
|
|
| 615 |
// --- 學習模式核心邏輯 ---
|
| 616 |
const displayCard = () => {
|
| 617 |
if (wordsForCurrentMode.length === 0 && quizQueue.length === 0) return;
|
| 618 |
-
|
| 619 |
-
const isReview = currentMode === 'review';
|
| 620 |
-
const isSpeed = currentMode === 'speed';
|
| 621 |
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
} else if (isSpeed) {
|
| 626 |
-
card = currentSpeedCard;
|
| 627 |
-
} else {
|
| 628 |
-
if (quizQueue.length === 0) return;
|
| 629 |
-
card = quizQueue[0];
|
| 630 |
-
}
|
| 631 |
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 637 |
|
| 638 |
-
const setContent = () => {
|
| 639 |
flashcardContainer.style.cursor = 'default';
|
| 640 |
[speakBtn, speakSlowBtn].forEach(btn => btn.classList.add('hidden'));
|
| 641 |
feedbackDisplay.textContent = '';
|
|
@@ -665,6 +663,7 @@
|
|
| 665 |
progressDisplay.textContent = `第 ${currentCardIndex + 1}/${wordsForCurrentMode.length} 張`;
|
| 666 |
prevBtn.disabled = currentCardIndex === 0;
|
| 667 |
nextBtn.disabled = currentCardIndex === wordsForCurrentMode.length - 1;
|
|
|
|
| 668 |
break;
|
| 669 |
case 'zh-en': case 'hard':
|
| 670 |
frontText = card.chinese; backText = card.english; break;
|
|
@@ -682,7 +681,13 @@
|
|
| 682 |
setTimeout(() => answerInput.focus(), 100);
|
| 683 |
};
|
| 684 |
|
| 685 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 686 |
};
|
| 687 |
|
| 688 |
const setupLearningView = (mode) => {
|
|
@@ -750,21 +755,30 @@
|
|
| 750 |
|
| 751 |
let correctAnswer;
|
| 752 |
let answerLang;
|
| 753 |
-
|
| 754 |
-
if (
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
switch (effectiveMode) {
|
| 758 |
-
case 'zh-en':
|
| 759 |
-
case 'listen':
|
| 760 |
correctAnswer = card.english.split('(')[0].trim();
|
| 761 |
answerLang = 'en';
|
| 762 |
-
|
| 763 |
-
case 'en-zh':
|
| 764 |
-
case 'review':
|
| 765 |
correctAnswer = card.chinese.split('(')[0].trim();
|
| 766 |
answerLang = 'zh';
|
| 767 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 768 |
}
|
| 769 |
|
| 770 |
let isCorrect;
|
|
@@ -774,8 +788,6 @@
|
|
| 774 |
} else if (answerLang === 'zh') {
|
| 775 |
const possibleAnswers = correctAnswer.split(/[;;]/).map(a => a.trim());
|
| 776 |
isCorrect = possibleAnswers.some(ans => userAnswer.trim().includes(ans) && ans !== '');
|
| 777 |
-
} else {
|
| 778 |
-
isCorrect = userAnswer.trim().toLowerCase() === correctAnswer.trim().toLowerCase();
|
| 779 |
}
|
| 780 |
|
| 781 |
if (isCorrect) {
|
|
@@ -785,7 +797,10 @@
|
|
| 785 |
feedbackDisplay.classList.remove('text-red-500');
|
| 786 |
feedbackDisplay.classList.add('text-green-600');
|
| 787 |
triggerConfetti();
|
| 788 |
-
|
|
|
|
|
|
|
|
|
|
| 789 |
|
| 790 |
if (wordIndex !== -1) words[wordIndex].proficiency = (words[wordIndex].proficiency || 0) + 1;
|
| 791 |
|
|
@@ -793,18 +808,11 @@
|
|
| 793 |
currentScore++;
|
| 794 |
scoreDisplay.textContent = `得分: ${currentScore}`;
|
| 795 |
setTimeout(startSpeedCard, 500);
|
| 796 |
-
} else {
|
| 797 |
-
|
| 798 |
|
| 799 |
setTimeout(() => {
|
| 800 |
-
if (
|
| 801 |
-
if (currentCardIndex < wordsForCurrentMode.length - 1) {
|
| 802 |
-
currentCardIndex++;
|
| 803 |
-
displayCard();
|
| 804 |
-
} else {
|
| 805 |
-
feedbackDisplay.textContent = '恭喜你,全部複習完了!';
|
| 806 |
-
}
|
| 807 |
-
} else if (quizQueue.length > 0) {
|
| 808 |
displayCard();
|
| 809 |
} else {
|
| 810 |
feedbackDisplay.textContent = '恭喜你,全部完成了!';
|
|
@@ -818,6 +826,11 @@
|
|
| 818 |
}
|
| 819 |
}, 1500);
|
| 820 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 821 |
} else { // Incorrect answer
|
| 822 |
quizIncorrectCount++;
|
| 823 |
updateHintButtonVisibility();
|
|
@@ -835,7 +848,9 @@
|
|
| 835 |
} else if (isReview) {
|
| 836 |
feedbackDisplay.textContent = '答錯了!';
|
| 837 |
feedbackDisplay.classList.add('text-red-500');
|
| 838 |
-
flashcardContainer.classList.
|
|
|
|
|
|
|
| 839 |
setTimeout(() => { answerInput.classList.remove('shake'); }, 820);
|
| 840 |
} else { // Other quiz modes
|
| 841 |
answerInput.disabled = true;
|
|
@@ -953,7 +968,18 @@
|
|
| 953 |
btn.addEventListener('click', () => setupLearningView(btn.dataset.mode));
|
| 954 |
});
|
| 955 |
backToMenuBtn.addEventListener('click', () => { clearInterval(timerInterval); showView('menu'); });
|
| 956 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 957 |
prevBtn.addEventListener('click', () => { if (currentCardIndex > 0) { currentCardIndex--; displayCard(); }});
|
| 958 |
nextBtn.addEventListener('click', () => { if (currentCardIndex < wordsForCurrentMode.length - 1) { currentCardIndex++; displayCard(); }});
|
| 959 |
quizForm.addEventListener('submit', (e) => { e.preventDefault(); checkAnswer(); });
|
|
|
|
| 615 |
// --- 學習模式核心邏輯 ---
|
| 616 |
const displayCard = () => {
|
| 617 |
if (wordsForCurrentMode.length === 0 && quizQueue.length === 0) return;
|
|
|
|
|
|
|
|
|
|
| 618 |
|
| 619 |
+
const updateCardContent = () => {
|
| 620 |
+
const isReview = currentMode === 'review';
|
| 621 |
+
const isSpeed = currentMode === 'speed';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 622 |
|
| 623 |
+
let card;
|
| 624 |
+
if (isReview) {
|
| 625 |
+
card = wordsForCurrentMode[currentCardIndex];
|
| 626 |
+
} else if (isSpeed) {
|
| 627 |
+
card = currentSpeedCard;
|
| 628 |
+
} else {
|
| 629 |
+
if (quizQueue.length === 0) return;
|
| 630 |
+
card = quizQueue[0];
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
if (!isReview && !isSpeed) {
|
| 634 |
+
setProgress(wordsForCurrentMode.length - quizQueue.length, wordsForCurrentMode.length);
|
| 635 |
+
}
|
| 636 |
|
|
|
|
| 637 |
flashcardContainer.style.cursor = 'default';
|
| 638 |
[speakBtn, speakSlowBtn].forEach(btn => btn.classList.add('hidden'));
|
| 639 |
feedbackDisplay.textContent = '';
|
|
|
|
| 663 |
progressDisplay.textContent = `第 ${currentCardIndex + 1}/${wordsForCurrentMode.length} 張`;
|
| 664 |
prevBtn.disabled = currentCardIndex === 0;
|
| 665 |
nextBtn.disabled = currentCardIndex === wordsForCurrentMode.length - 1;
|
| 666 |
+
answerInput.placeholder = "請輸入中文答案...";
|
| 667 |
break;
|
| 668 |
case 'zh-en': case 'hard':
|
| 669 |
frontText = card.chinese; backText = card.english; break;
|
|
|
|
| 681 |
setTimeout(() => answerInput.focus(), 100);
|
| 682 |
};
|
| 683 |
|
| 684 |
+
if (flashcardContainer.classList.contains('flipped')) {
|
| 685 |
+
flashcardContainer.classList.remove('flipped');
|
| 686 |
+
// Wait for the flip animation (0.6s) to mostly complete before changing content
|
| 687 |
+
setTimeout(updateCardContent, 600);
|
| 688 |
+
} else {
|
| 689 |
+
updateCardContent();
|
| 690 |
+
}
|
| 691 |
};
|
| 692 |
|
| 693 |
const setupLearningView = (mode) => {
|
|
|
|
| 755 |
|
| 756 |
let correctAnswer;
|
| 757 |
let answerLang;
|
| 758 |
+
|
| 759 |
+
if (isReview) {
|
| 760 |
+
const isFlipped = flashcardContainer.classList.contains('flipped');
|
| 761 |
+
if(isFlipped) { // Chinese side showing, user should type English
|
|
|
|
|
|
|
|
|
|
| 762 |
correctAnswer = card.english.split('(')[0].trim();
|
| 763 |
answerLang = 'en';
|
| 764 |
+
} else { // English side showing, user should type Chinese
|
|
|
|
|
|
|
| 765 |
correctAnswer = card.chinese.split('(')[0].trim();
|
| 766 |
answerLang = 'zh';
|
| 767 |
+
}
|
| 768 |
+
} else {
|
| 769 |
+
let effectiveMode = currentMode;
|
| 770 |
+
if (isSpeed) effectiveMode = currentSpeedQuestionType;
|
| 771 |
+
if (currentMode === 'hard') effectiveMode = 'zh-en';
|
| 772 |
+
switch (effectiveMode) {
|
| 773 |
+
case 'zh-en': case 'listen':
|
| 774 |
+
correctAnswer = card.english.split('(')[0].trim();
|
| 775 |
+
answerLang = 'en';
|
| 776 |
+
break;
|
| 777 |
+
case 'en-zh':
|
| 778 |
+
correctAnswer = card.chinese.split('(')[0].trim();
|
| 779 |
+
answerLang = 'zh';
|
| 780 |
+
break;
|
| 781 |
+
}
|
| 782 |
}
|
| 783 |
|
| 784 |
let isCorrect;
|
|
|
|
| 788 |
} else if (answerLang === 'zh') {
|
| 789 |
const possibleAnswers = correctAnswer.split(/[;;]/).map(a => a.trim());
|
| 790 |
isCorrect = possibleAnswers.some(ans => userAnswer.trim().includes(ans) && ans !== '');
|
|
|
|
|
|
|
| 791 |
}
|
| 792 |
|
| 793 |
if (isCorrect) {
|
|
|
|
| 797 |
feedbackDisplay.classList.remove('text-red-500');
|
| 798 |
feedbackDisplay.classList.add('text-green-600');
|
| 799 |
triggerConfetti();
|
| 800 |
+
|
| 801 |
+
if (!flashcardContainer.classList.contains('flipped')) {
|
| 802 |
+
flashcardContainer.classList.add('flipped');
|
| 803 |
+
}
|
| 804 |
|
| 805 |
if (wordIndex !== -1) words[wordIndex].proficiency = (words[wordIndex].proficiency || 0) + 1;
|
| 806 |
|
|
|
|
| 808 |
currentScore++;
|
| 809 |
scoreDisplay.textContent = `得分: ${currentScore}`;
|
| 810 |
setTimeout(startSpeedCard, 500);
|
| 811 |
+
} else if (!isReview) {
|
| 812 |
+
quizQueue.shift();
|
| 813 |
|
| 814 |
setTimeout(() => {
|
| 815 |
+
if (quizQueue.length > 0) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 816 |
displayCard();
|
| 817 |
} else {
|
| 818 |
feedbackDisplay.textContent = '恭喜你,全部完成了!';
|
|
|
|
| 826 |
}
|
| 827 |
}, 1500);
|
| 828 |
}
|
| 829 |
+
// For review mode, do nothing to auto-advance. Let user click next.
|
| 830 |
+
if (isReview) {
|
| 831 |
+
answerInput.disabled = false;
|
| 832 |
+
submitBtn.disabled = false;
|
| 833 |
+
}
|
| 834 |
} else { // Incorrect answer
|
| 835 |
quizIncorrectCount++;
|
| 836 |
updateHintButtonVisibility();
|
|
|
|
| 848 |
} else if (isReview) {
|
| 849 |
feedbackDisplay.textContent = '答錯了!';
|
| 850 |
feedbackDisplay.classList.add('text-red-500');
|
| 851 |
+
if (!flashcardContainer.classList.contains('flipped')) {
|
| 852 |
+
flashcardContainer.classList.add('flipped');
|
| 853 |
+
}
|
| 854 |
setTimeout(() => { answerInput.classList.remove('shake'); }, 820);
|
| 855 |
} else { // Other quiz modes
|
| 856 |
answerInput.disabled = true;
|
|
|
|
| 968 |
btn.addEventListener('click', () => setupLearningView(btn.dataset.mode));
|
| 969 |
});
|
| 970 |
backToMenuBtn.addEventListener('click', () => { clearInterval(timerInterval); showView('menu'); });
|
| 971 |
+
|
| 972 |
+
flashcardContainer.addEventListener('click', () => {
|
| 973 |
+
if (currentMode === 'review') {
|
| 974 |
+
flashcardContainer.classList.toggle('flipped');
|
| 975 |
+
const isFlipped = flashcardContainer.classList.contains('flipped');
|
| 976 |
+
answerInput.placeholder = isFlipped ? "請輸入英文答案..." : "請輸入中文答案...";
|
| 977 |
+
answerInput.value = '';
|
| 978 |
+
feedbackDisplay.textContent = '';
|
| 979 |
+
setTimeout(() => answerInput.focus(), 100);
|
| 980 |
+
}
|
| 981 |
+
});
|
| 982 |
+
|
| 983 |
prevBtn.addEventListener('click', () => { if (currentCardIndex > 0) { currentCardIndex--; displayCard(); }});
|
| 984 |
nextBtn.addEventListener('click', () => { if (currentCardIndex < wordsForCurrentMode.length - 1) { currentCardIndex++; displayCard(); }});
|
| 985 |
quizForm.addEventListener('submit', (e) => { e.preventDefault(); checkAnswer(); });
|