Arabic-Story1 / script.js
Hma47's picture
Upload 14 files
1616c48 verified
Raw History Blame Contribute Delete
15.8 kB
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 = '<svg viewBox="0 0 24 24" width="24" height="24"><path fill="currentColor" d="M8 5v14l11-7z"/></svg> ุงุณุชู…ุน ู„ู„ู‚ุตุฉ';
} else {
audioEl.play();
playBtn.innerHTML = '<svg viewBox="0 0 24 24" width="24" height="24"><path fill="currentColor" d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg> ุฅูŠู‚ุงู';
}
isPlaying = !isPlaying;
});
audioEl.addEventListener("ended", () => {
isPlaying = false;
playBtn.innerHTML = '<svg viewBox="0 0 24 24" width="24" height="24"><path fill="currentColor" d="M8 5v14l11-7z"/></svg> ุงุณุชู…ุน ู„ู„ู‚ุตุฉ';
progressBar.style.width = "0%";
});
// Reset Functionality
resetBtn.addEventListener("click", () => {
audioEl.pause();
audioEl.currentTime = 0;
isPlaying = false;
playBtn.innerHTML = '<svg viewBox="0 0 24 24" width="24" height="24"><path fill="currentColor" d="M8 5v14l11-7z"/></svg> ุงุณุชู…ุน ู„ู„ู‚ุตุฉ';
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);
});
});