// راه‌اندازی اولیه و هندلرهای رویداد اصلی window.onload = function() { startAnim('#animPreviewStatic'); initDB().then(() => { loadHome(); }); syncModeButtons(); initLanguagesList(); applyDemoLanguage('fa'); const timeline = document.getElementById('timelineScroll'); timeline.addEventListener('touchstart', () => { v.pause(); togglePlayIcon(false); }, {passive: true}); timeline.addEventListener('mousedown', () => { v.pause(); togglePlayIcon(false); }); // هماهنگ‌سازی حرکت انیمیشن ویژوالایزرها با وضعیت پخش و توقف ویدیو v.addEventListener('play', () => { const vBars = tEl.querySelectorAll('.v-bar'); vBars.forEach(b => b.style.animationPlayState = 'running'); }); v.addEventListener('pause', () => { const vBars = tEl.querySelectorAll('.v-bar'); vBars.forEach(b => b.style.animationPlayState = 'paused'); }); }; window.onresize = fit; // --- موتور زمان‌سنج هوشمند (High-Precision Sync) جایگزین v.ontimeupdate --- function runFastSync() { // فقط وقتی ویدیو در حال پخش است یا دستی جابجا می‌شود اجرا شود if (!v.paused || manualOverride) { const cur = v.currentTime; const timeDisplay = document.getElementById('globalTimeDisplay'); if (timeDisplay) { timeDisplay.innerText = `${formatTimeSimple(cur)} / ${formatTimeSimple(v.duration || 0)}`; } if (!v.paused) manualOverride = false; let foundWord = false; // اضافه کردن 0.1 ثانیه تلورانس برای دیده شدن کلمات آخر جمله for (let s = 0; s < state.segs.length; s++) { const seg = state.segs[s]; if (cur >= seg.start && cur < (seg.end + 0.1)) { if (seg.words) { for (let w = 0; w < seg.words.length; w++) { const word = seg.words[w]; // بررسی فعال بودن کلمه با دقت بالا و تلورانس شروع و پایان if (cur >= (word.start - 0.02) && cur < (word.end + 0.05)) { const uid = `${s}-${w}`; if (activeWordId !== uid) { activeWordId = uid; document.querySelectorAll('.word-chip').forEach(c => c.classList.remove('active')); const el = document.getElementById(`w-${uid}`); if(el) { el.classList.add('active'); if(!manualOverride) el.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); } updateSplitButton(); } foundWord = true; break; } } } } if (foundWord) break; } if (!foundWord && !manualOverride) { document.querySelectorAll('.word-chip').forEach(c => c.classList.remove('active')); activeWordId = null; const toolbar = document.getElementById('toolbar'); if (toolbar) toolbar.classList.remove('show'); } updateOverlayContent(cur); } // تکرار مداوم برای دقت ۶۰ فریم در ثانیه requestAnimationFrame(runFastSync); } // شروع به کار موتور همزمان با لود شدن صفحه requestAnimationFrame(runFastSync); // --- سیستم لمسی --- // ۱. ساخت کادر نامرئی بزرگ برای راحت‌تر گرفتن متن و کادر سفید هنگام لمس const touchAreaStyle = document.createElement('style'); touchAreaStyle.innerHTML = ` /* ایجاد یک حاشیه نامرئی ۱۰۰ پیکسلی دور متن تا کاربر راحت‌تر آن را بگیرد */ #activeText::before { content: ''; position: absolute; top: -100px; bottom: -100px; left: -100px; right: -100px; z-index: 999; } /* مستطیل سفید که هنگام جابجایی ظاهر می‌شود */ #activeText.is-dragging { outline: 2px solid #ffffff; outline-offset: 20px; border-radius: 8px; transition: outline 0.1s; } `; document.head.appendChild(touchAreaStyle); // قفل کردن رفتار پیش‌فرض مرورگر روی این المان تا صفحه اسکرول نشود tEl.style.touchAction = 'none'; tEl.addEventListener('touchstart', (e) => { // متوقف کردن ویدیو در صورت پخش بودن به محض لمس کادر if (v && !v.paused) { v.pause(); if (typeof togglePlayIcon === 'function') togglePlayIcon(false); } // غیرفعال کردن اکشن‌های بومی مرورگر از ریشه لمس برای فعالسازی زوم جاوااسکریپتی e.preventDefault(); e.stopPropagation(); if(e.touches.length === 1) { touchMode = 'drag'; initialY = e.touches[0].clientY; initialX = e.touches[0].clientX; initialBottom = state.st.y; initialXState = state.st.x || 0; tEl.classList.add('is-dragging'); } else if (e.touches.length === 2) { touchMode = 'pinch'; initialDist = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY); initialFontSize = state.st.fz; tEl.classList.add('is-dragging'); } }, {passive: false}); tEl.addEventListener('touchmove', (e) => { if (!touchMode) return; e.preventDefault(); e.stopPropagation(); // تشخیص هوشمند قرار گرفتن انگشت دوم در هر جای صفحه و سوییچ آنی به زوم if (e.touches.length === 2) { if (touchMode !== 'pinch') { touchMode = 'pinch'; initialDist = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY); initialFontSize = state.st.fz; } let dist = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY); if (initialDist > 0) { let newSize = initialFontSize * (dist / initialDist); state.st.fz = Math.round(Math.max(10, Math.min(150, newSize))); tEl.style.fontSize = state.st.fz + 'px'; syncUIWithState(); } } else if (touchMode === 'drag' && e.touches.length === 1) { let diffY = (initialY - e.touches[0].clientY) * 1.8; let newBottom = initialBottom + diffY; state.st.y = Math.round(newBottom); let diffX = (e.touches[0].clientX - initialX) * 1.5; let newX = initialXState + diffX; state.st.x = Math.round(newX); // اعمال تغییرات به صورت مستقیم و فوق‌روان tEl.style.bottom = state.st.y + 'px'; tEl.style.transform = `translateX(calc(-50% + ${state.st.x || 0}px))`; syncUIWithState(); } }, {passive: false}); tEl.addEventListener('touchend', () => { touchMode = null; // مخفی کردن کادر سفید tEl.classList.remove('is-dragging'); // ذخیره نهایی upd(); });