const storyData = [ { start: 0.000, end: 12.693, text: "تَقِفُ سَنْدِيَانَةٌ 🌳 عَالِيَةٌ عَلَى مُرْتَفَعٍ، تُشْرِفُ عَلَى نَهْرٍ 🌊 غَزِيرِ الْمِيَاهِ، أَغْصَانُهَا 🍃 كَثِيفَةٌ، وَأَوْرَاقُهَا خَضْرَاءُ، وَسَاقُهَا طَوِيلَةٌ كَالْمِئْذَنَةِ فِي الِارْتِفَاعِ." }, { start: 12.693, end: 20.742, text: "تَتَنَقَّلُ عَلَيْهَا الْعَصَافِيرُ 🐦 مُغَرِّدَةً، وَيَجْلِسُ عِنْدَهَا الرُّعَاةُ وَالصَّيَّادُونَ لِيَرْتَاحُوا مِنَ التَّعَبِ." }, { start: 20.742, end: 29.782, text: "وَتَعِيشُ قَصَبَةٌ 🌾 مَعَ رَفِيقَتِهَا، عَلَى ضِفَّةِ هَذَا النَّهْرِ، تَنْظُرُ بِخَفَرٍ لِمِيَاهِهِ الْجَارِيَةِ، وَتَتَمَايَلُ مَعَ الْهَوَاءِ." }, { start: 29.782, end: 35.045, text: "قَالَتِ السَّنْدِيَانَةُ مَرَّةً لِلْقَصَبَةِ: مَا أَحْقَرَكِ أَيَّتُهَا الْقَصَبَةُ!" }, { start: 35.045, end: 42.599, text: "تَعِيشِينَ فِي هَذَا الْمُنْخَفَضِ، وَتَخْتَفِينَ وَرَاءَهُ طِيلَةَ النَّهَارِ، فَلَا تَرَيْنَ النُّورَ، وَمَا أَضْعَفَكِ!" }, { start: 42.599, end: 48.233, text: "لَا تَسْتَطِيعِينَ أَنْ تَحْمِلِي عُصْفُورًا، حَقًّا إِنَّ الطَّبِيعَةَ قَاسِيَةٌ عَلَيْكِ." }, { start: 48.233, end: 54.611, text: "قَالَتْ لَهَا الْقَصَبَةُ: أَنْتِ مَغْرُورَةٌ بِنَفْسِكِ، وَغُرُورُكِ 😌 هَذَا سَوْفَ يَقْضِي عَلَيْكِ." }, { start: 54.611, end: 74.177, text: "هَبَّتْ عَاصِفَةٌ 🌪️ قَوِيَّةٌ، فَتَأَرْجَحَتِ الْقَصَبَةُ مَعَ الْعَاصِفَةِ، وَتَمَكَّنَتْ بِفَضْلِ ذَلِكَ مِنَ الثَّبَاتِ، وَهِيَ تَمِيلُ يَمِينًا وَيَسَارًا، أَمَّا السَّنْدِيَانَةُ فَلَمْ تَسْتَطِعْ أَنْ تُقَاوِمَ الْعَاصِفَةَ، فَتَكَسَّرَتْ أَغْصَانُهَا، وَاقْتَلَعَتْهَا الْعَاصِفَةُ بِجِذْعِهَا 🌳 الضَّخْمِ." }, { start: 74.177, end: 83.000, text: "نَظَرَتِ الْقَصَبَةُ بِعَطْفٍ إِلَى السَّنْدِيَانَةِ، وَقَالَتْ لَهَا: هَذِهِ نَتِيجَةُ غُرُورِكِ، وَاحْتِقَارِكِ مَنْ هُوَ أَصْغَرُ مِنْكِ." } ]; const translations = { "سَنْدِيَانَةٌ": "Oak tree", "مُرْتَفَعٍ": "High ground", "نَهْرٍ": "River", "غَزِيرِ": "Abundant", "أَغْصَانُهَا": "Its branches", "كَثِيفَةٌ": "Dense", "أَوْرَاقُهَا": "Its leaves", "خَضْرَاءُ": "Green", "سَاقُهَا": "Its trunk", "طَوِيلَةٌ": "Tall", "كَالْمِئْذَنَةِ": "Like a minaret", "الِارْتِفَاعِ": "Height", "تَتَنَقَّلُ": "Move around", "الْعَصَافِيرُ": "Birds", "مُغَرِّدَةً": "Chirping", "الرُّعَاةُ": "Shepherds", "وَالصَّيَّادُونَ": "And hunters", "لِيَرْتَاحُوا": "To rest", "التَّعَبِ": "Fatigue", "قَصَبَةٌ": "Reed", "رَفِيقَتِهَا": "Its companion", "ضِفَّةِ": "Bank (of river)", "بِخَفَرٍ": "Shyly", "لِمِيَاهِهِ": "To its waters", "الْجَارِيَةِ": "Running", "وَتَتَمَايَلُ": "And sways", "الْهَوَاءِ": "The air / wind", "أَحْقَرَكِ": "How despicable you are", "الْمُنْخَفَضِ": "Lowland", "وَتَخْتَفِينَ": "And you hide", "وَرَاءَهُ": "Behind it", "طِيلَةَ": "Throughout", "النَّهَارِ": "The day", "النُّورَ": "The light", "أَضْعَفَكِ": "How weak you are", "تَحْمِلِي": "Carry", "عُصْفُورًا": "A bird", "الطَّبِيعَةَ": "Nature", "قَاسِيَةٌ": "Cruel / Harsh", "مَغْرُورَةٌ": "Arrogant", "بِنَفْسِكِ": "With yourself", "وَغُرُورُكِ": "And your arrogance", "يَقْضِي": "Will destroy / Finish", "هَبَّتْ": "Blew", "عَاصِفَةٌ": "Storm", "قَوِيَّةٌ": "Strong", "فَتَأَرْجَحَتِ": "So it swayed", "وَتَمَكَّنَتْ": "And it was able", "بِفَضْلِ": "Thanks to", "الثَّبَاتِ": "Steadiness / Stability", "تَمِيلُ": "Leans / Bends", "يَمِينًا": "Right", "وَيَسَارًا": "And left", "تُقَاوِمَ": "Resist", "فَتَكَسَّرَتْ": "So they broke", "وَاقْتَلَعَتْهَا": "And uprooted it", "بِجِذْعِهَا": "By its trunk", "الضَّخْمِ": "Huge", "بِعَطْفٍ": "With sympathy", "نَتِيجَةُ": "Result", "غُرُورِكِ": "Your arrogance", "وَاحْتِقَارِكِ": "And your contempt" }; const quizData = [ { question: "أين تعيش السنديانة؟ (Where does the oak tree live?)", options: [ { text: "على ضفة النهر (On the riverbank)", isCorrect: false }, { text: "في منخفض (In a lowland)", isCorrect: false }, { text: "على مرتفع (On a high ground)", isCorrect: true } ] }, { question: "ماذا حدث للسنديانة عندما هبت العاصفة؟ (What happened to the oak tree when the storm blew?)", options: [ { text: "تأرجحت مع العاصفة (Swayed with the storm)", isCorrect: false }, { text: "اقتلعتها العاصفة (The storm uprooted it)", isCorrect: true }, { text: "قاومت العاصفة (Resisted the storm)", isCorrect: false } ] }, { question: "ما هي الحكمة من القصة؟ (What is the moral of the story?)", options: [ { text: "الطبيعة قاسية (Nature is harsh)", isCorrect: false }, { text: "الغرور يقضي على صاحبه (Arrogance destroys its owner)", isCorrect: true }, { text: "النهر جميل (The river is beautiful)", isCorrect: false } ] } ]; document.addEventListener("DOMContentLoaded", () => { const textContentEl = document.getElementById("text-content"); const audioEl = document.getElementById("story-audio"); const playBtn = document.getElementById("play-btn"); const resetBtn = document.getElementById("reset-btn"); const progressBar = document.getElementById("progress-bar"); const progressContainer = document.getElementById("progress-container"); const tooltip = document.getElementById("word-tooltip"); const tooltipAr = document.getElementById("tooltip-ar"); const tooltipEn = document.getElementById("tooltip-en"); const tooltipArrow = document.getElementById("tooltip-arrow"); const quizContainer = document.getElementById("quiz-container"); let isPlaying = false; // Remove any character that is not an Arabic letter, diacritic or space function cleanWord(word) { return word.replace(/[^\u0600-\u06FF\s]/g, '').trim(); } // Render Text storyData.forEach((section, index) => { const wrapper = document.createElement("div"); wrapper.className = "paragraph-wrapper"; const imgName = index === 5 ? "Patagraph 6.png" : `paragraph ${index + 1}.png`; const img = document.createElement("img"); img.src = imgName; img.className = "paragraph-image"; img.alt = `صورة للفقرة ${index + 1}`; wrapper.appendChild(img); const sentenceSpan = document.createElement("div"); sentenceSpan.className = "sentence"; sentenceSpan.id = `sentence-${index}`; sentenceSpan.dataset.start = section.start; sentenceSpan.dataset.end = section.end; const words = section.text.split(" "); words.forEach((word) => { const wordSpan = document.createElement("span"); const clean = cleanWord(word); wordSpan.className = "word"; wordSpan.innerText = word + " "; if (translations[clean]) { wordSpan.classList.add("has-translation"); wordSpan.addEventListener("click", (e) => { e.stopPropagation(); const rect = wordSpan.getBoundingClientRect(); tooltipAr.innerText = clean; tooltipEn.innerText = translations[clean]; // Force layout measurement const tHeight = tooltip.offsetHeight; const tWidth = tooltip.offsetWidth; // Calculate center position const centerX = rect.left + window.scrollX + (rect.width / 2); let leftPos = centerX; // Keep tooltip within screen bounds const padding = 15; const minLeft = padding + (tWidth / 2); const maxLeft = window.innerWidth - padding - (tWidth / 2); if (leftPos < minLeft) leftPos = minLeft; if (leftPos > maxLeft) leftPos = maxLeft; tooltip.style.left = `${leftPos}px`; tooltip.style.top = `${rect.top + window.scrollY - tHeight - 15}px`; // Adjust arrow to point directly at the word, even if tooltip is shifted let arrowOffset = centerX - leftPos; const maxArrowOffset = (tWidth / 2) - 15; if (arrowOffset > maxArrowOffset) arrowOffset = maxArrowOffset; if (arrowOffset < -maxArrowOffset) arrowOffset = -maxArrowOffset; tooltipArrow.style.left = `calc(50% + ${arrowOffset}px)`; tooltip.classList.add("show"); }); } sentenceSpan.appendChild(wordSpan); }); wrapper.appendChild(sentenceSpan); textContentEl.appendChild(wrapper); }); // Audio Play/Pause playBtn.addEventListener("click", () => { if (isPlaying) { audioEl.pause(); playBtn.innerHTML = ' استمع للقصة'; } else { audioEl.play(); playBtn.innerHTML = ' إيقاف'; } isPlaying = !isPlaying; }); audioEl.addEventListener("ended", () => { isPlaying = false; playBtn.innerHTML = ' استمع للقصة'; progressBar.style.width = "0%"; }); // Reset Functionality resetBtn.addEventListener("click", () => { audioEl.pause(); audioEl.currentTime = 0; isPlaying = false; playBtn.innerHTML = ' استمع للقصة'; progressBar.style.width = "0%"; document.querySelectorAll(".sentence").forEach(el => el.classList.remove("active")); document.querySelectorAll(".option-btn").forEach(btn => { btn.classList.remove("correct", "wrong"); btn.disabled = false; }); document.querySelectorAll(".feedback").forEach(fb => { fb.classList.remove("show"); }); window.scrollTo({ top: 0, behavior: 'smooth' }); }); // Sync Audio with Text audioEl.addEventListener("timeupdate", () => { const currentTime = audioEl.currentTime; const duration = audioEl.duration; if (duration) { progressBar.style.width = `${(currentTime / duration) * 100}%`; } storyData.forEach((section, index) => { const sentenceEl = document.getElementById(`sentence-${index}`); if (currentTime >= section.start && currentTime < section.end) { sentenceEl.classList.add("active"); } else { sentenceEl.classList.remove("active"); } }); }); // Seek Audio progressContainer.addEventListener("click", (e) => { const rect = progressContainer.getBoundingClientRect(); const pos = (e.clientX - rect.left) / rect.width; audioEl.currentTime = pos * audioEl.duration; }); // Hide Tooltip on document interactions document.addEventListener("click", () => { tooltip.classList.remove("show"); }); window.addEventListener("scroll", () => { tooltip.classList.remove("show"); }); window.addEventListener("resize", () => { tooltip.classList.remove("show"); }); // Render Quiz quizData.forEach((q, index) => { const card = document.createElement("div"); card.className = "question-card"; const qText = document.createElement("div"); qText.className = "question-text"; qText.innerText = q.question; card.appendChild(qText); const optionsContainer = document.createElement("div"); optionsContainer.className = "options-container"; const feedback = document.createElement("div"); feedback.className = "feedback"; q.options.forEach(opt => { const btn = document.createElement("button"); btn.className = "option-btn"; btn.innerText = opt.text; btn.addEventListener("click", () => { // Remove existing classes Array.from(optionsContainer.children).forEach(c => { c.classList.remove("correct", "wrong"); c.disabled = true; }); if (opt.isCorrect) { btn.classList.add("correct"); feedback.innerText = "إجابة صحيحة! (Correct Answer!)"; feedback.style.color = "#155724"; } else { btn.classList.add("wrong"); feedback.innerText = "إجابة خاطئة (Wrong Answer). حاول مرة أخرى."; feedback.style.color = "#721c24"; // Highlight correct answer Array.from(optionsContainer.children).forEach((c, i) => { if (q.options[i].isCorrect) c.classList.add("correct"); }); } feedback.classList.add("show"); }); optionsContainer.appendChild(btn); }); card.appendChild(optionsContainer); card.appendChild(feedback); quizContainer.appendChild(card); }); });