Elias207 commited on
Commit
00a5ac4
·
verified ·
1 Parent(s): e1ad0ff

Update static/js/editor.js

Browse files
Files changed (1) hide show
  1. static/js/editor.js +81 -49
static/js/editor.js CHANGED
@@ -210,77 +210,105 @@ function highlightWord(sIdx, wIdx, showToolbar) {
210
  // ============================================
211
 
212
  function initTrimmerUI(startT, endT, minLimit, maxLimit) {
213
- // تنظیم محدودیت‌های سراسری بر اساس کلمات قبل و بعد
214
  trimMinLimit = minLimit;
215
  trimMaxLimit = maxLimit;
216
  trimViewDuration = trimMaxLimit - trimMinLimit;
217
 
218
- // اگر فاصله خیلی کم بود، حداقل یک مقدار ناچیز برای جلوگیری از تقسیم بر صفر
219
- if(trimViewDuration <= 0.01) trimViewDuration = 0.01;
220
 
221
  // اعمال مقادیر اولیه به UI
222
  updateTrimmerVisuals();
223
 
224
- // ستاپ ایونت لیسنرها برای درگ کردن
225
  const handleL = document.getElementById('handleLeft');
226
  const handleR = document.getElementById('handleRight');
227
 
228
- const setupDrag = (elem, type) => {
229
- const startDrag = (e) => {
230
- e.preventDefault();
231
- e.stopPropagation();
232
- activeDragHandle = type;
233
- document.addEventListener('mousemove', onDrag);
234
- document.addEventListener('mouseup', endDrag);
235
- document.addEventListener('touchmove', onDrag, {passive: false});
236
- document.addEventListener('touchend', endDrag);
237
- };
238
- elem.onmousedown = startDrag;
239
- elem.ontouchstart = startDrag;
 
240
  };
241
 
242
- if(handleL) setupDrag(handleL, 'left');
243
- if(handleR) setupDrag(handleR, 'right');
 
 
 
 
 
 
 
244
  }
245
 
246
  function onDrag(e) {
247
  if (!activeDragHandle) return;
248
- e.preventDefault();
 
 
249
  e.stopPropagation();
250
 
251
  const strip = document.getElementById('timelineStrip');
252
  if (!strip) return;
253
 
254
  const rect = strip.getBoundingClientRect();
255
- const clientX = e.touches ? e.touches[0].clientX : e.clientX;
256
 
257
- // محاسبه درصد مکان انگشت/ماوس روی نوار
258
- // 0% = trimMinLimit, 100% = trimMaxLimit
 
 
 
 
 
 
 
259
  let percent = (clientX - rect.left) / rect.width;
 
 
260
  percent = Math.max(0, Math.min(1, percent));
261
 
262
  // تبدیل درصد به زمان واقعی
263
  let newTime = trimMinLimit + (percent * trimViewDuration);
264
 
 
 
 
265
  if (activeDragHandle === 'left') {
266
- // تغییر زمان شروع (Left Handle)
267
- // نباید کمتر از حد مجاز (trimMinLimit) باشد (که با Math.max(0...) کنترل شد)
268
- // نباید بیشتر از زمان پایان فعلی باشد (با یک فاصله ایمن کوچک)
269
  if (newTime >= tempEndTime - 0.05) newTime = tempEndTime - 0.05;
 
270
 
271
- tempStartTime = parseFloat(newTime.toFixed(2));
272
  } else {
273
- // تغییر زمان پایان (Right Handle)
274
- // نباید کمتر از زمان شروع فعلی باشد
 
275
  if (newTime <= tempStartTime + 0.05) newTime = tempStartTime + 0.05;
 
276
 
277
- tempEndTime = parseFloat(newTime.toFixed(2));
278
  }
279
 
 
280
  updateTrimmerVisuals();
281
  }
282
 
283
- function endDrag() {
 
 
 
284
  activeDragHandle = null;
285
  document.removeEventListener('mousemove', onDrag);
286
  document.removeEventListener('mouseup', endDrag);
@@ -290,23 +318,29 @@ function endDrag() {
290
 
291
  function updateTrimmerVisuals() {
292
  // نمایش متنی زمان
293
- document.getElementById('trimStartDisp').innerText = formatTimeMs(tempStartTime);
294
- document.getElementById('trimEndDisp').innerText = formatTimeMs(tempEndTime);
 
 
 
295
 
296
- // محاسبه موقعیت هندل‌ها (درصد نسبت به طول کل بازه مجاز)
297
- const leftP = ((tempStartTime - trimMinLimit) / trimViewDuration) * 100;
298
- const rightP = ((tempEndTime - trimMinLimit) / trimViewDuration) * 100;
 
 
 
 
299
 
300
  const handleL = document.getElementById('handleLeft');
301
  const handleR = document.getElementById('handleRight');
302
  const track = document.getElementById('trackActive');
303
 
304
- if(handleL && handleR && track) {
305
- handleL.style.left = `${leftP}%`;
306
- // هندل راست را هم با left پوزیشن می‌دهیم چون در کانتینر ابسولوت است
307
- handleR.style.left = `${rightP}%`;
308
-
309
- // نوار رنگی وسط از موقعیت چپ شروع میشه و عرضش تفاضل دو درصد است
310
  track.style.left = `${leftP}%`;
311
  track.style.width = `${rightP - leftP}%`;
312
  }
@@ -321,13 +355,12 @@ function formatTimeMs(t) {
321
 
322
  // تابع پخش دقیق بازه انتخاب شده
323
  function playPreviewWord() {
324
- if (!activeWordId && (tempStartTime === undefined)) return;
325
 
326
- // توقف پخش قبلی
327
  if(previewInterval) clearInterval(previewInterval);
328
  v.pause();
329
 
330
- // شروع دقیقا از زمان تنظیم شده (نه زمان ذخیره شده قبلی)
331
  v.currentTime = tempStartTime;
332
 
333
  const icon1 = document.getElementById('btnPreviewPlay')?.querySelector('i');
@@ -338,7 +371,7 @@ function playPreviewWord() {
338
 
339
  v.play().then(() => {
340
  previewInterval = setInterval(() => {
341
- // اگر به زمان پایان تنظیم شده رسید، متوقف شو
342
  if(v.currentTime >= tempEndTime) {
343
  v.pause();
344
  clearInterval(previewInterval);
@@ -346,8 +379,8 @@ function playPreviewWord() {
346
  if(icon1) icon1.className = "fa-solid fa-play";
347
  if(icon2) icon2.className = "fa-solid fa-play";
348
 
349
- // برگرداندن هد به زمان پایان برای نمایش فریم آخر
350
- v.currentTime = tempEndTime - 0.01;
351
  }
352
  }, 15);
353
  }).catch(e => console.log("Play interrupted", e));
@@ -386,11 +419,10 @@ function confirmTimeChanges() {
386
  const [sIdx, wIdx] = activeWordId.split('-').map(Number);
387
  const seg = state.segs[sIdx];
388
 
389
- // اعمال زمان‌های جدید
390
  seg.words[wIdx].start = tempStartTime;
391
  seg.words[wIdx].end = tempEndTime;
392
 
393
- // اصلاح مرزهای سگمنت والد
394
  if (wIdx === 0 && tempStartTime < seg.start) seg.start = tempStartTime;
395
  if (wIdx === seg.words.length - 1 && tempEndTime > seg.end) seg.end = tempEndTime;
396
 
 
210
  // ============================================
211
 
212
  function initTrimmerUI(startT, endT, minLimit, maxLimit) {
213
+ // تنظیم محدودیت‌های سراسری
214
  trimMinLimit = minLimit;
215
  trimMaxLimit = maxLimit;
216
  trimViewDuration = trimMaxLimit - trimMinLimit;
217
 
218
+ // جلوگیری از خطای تقسیم بر صفر
219
+ if(trimViewDuration <= 0.001) trimViewDuration = 1;
220
 
221
  // اعمال مقادیر اولیه به UI
222
  updateTrimmerVisuals();
223
 
224
+ // هندلرهای درگ با پشتیبانی بهتر از موبایل
225
  const handleL = document.getElementById('handleLeft');
226
  const handleR = document.getElementById('handleRight');
227
 
228
+ // تابع کمکی برای شروع درگ
229
+ const startDrag = (e, type) => {
230
+ // جلوگیری از اسکرول صفحه هنگام لمس هندل
231
+ if(e.cancelable) e.preventDefault();
232
+ e.stopPropagation();
233
+
234
+ activeDragHandle = type;
235
+
236
+ // اضافه کردن لیسنرها به کل داکیومنت برای اینکه اگر انگشت از روی هندل رد شد، درگ قطع نشود
237
+ document.addEventListener('mousemove', onDrag);
238
+ document.addEventListener('mouseup', endDrag);
239
+ document.addEventListener('touchmove', onDrag, {passive: false});
240
+ document.addEventListener('touchend', endDrag);
241
  };
242
 
243
+ // اتصال رویدادها
244
+ if(handleL) {
245
+ handleL.onmousedown = (e) => startDrag(e, 'left');
246
+ handleL.ontouchstart = (e) => startDrag(e, 'left');
247
+ }
248
+ if(handleR) {
249
+ handleR.onmousedown = (e) => startDrag(e, 'right');
250
+ handleR.ontouchstart = (e) => startDrag(e, 'right');
251
+ }
252
  }
253
 
254
  function onDrag(e) {
255
  if (!activeDragHandle) return;
256
+
257
+ // جلوگیری از رفتارهای پیش‌فرض مرورگر (مثل رفرش یا اسکرول)
258
+ if(e.cancelable) e.preventDefault();
259
  e.stopPropagation();
260
 
261
  const strip = document.getElementById('timelineStrip');
262
  if (!strip) return;
263
 
264
  const rect = strip.getBoundingClientRect();
 
265
 
266
+ // دریافت موقعیت X چه با موس چه با تاچ
267
+ let clientX;
268
+ if (e.touches && e.touches.length > 0) {
269
+ clientX = e.touches[0].clientX;
270
+ } else {
271
+ clientX = e.clientX;
272
+ }
273
+
274
+ // محاسبه درصد دقیق مکان انگشت روی نوار
275
  let percent = (clientX - rect.left) / rect.width;
276
+
277
+ // محدود کردن درصد بین 0 و 1 (که از کادر بیرون نزند)
278
  percent = Math.max(0, Math.min(1, percent));
279
 
280
  // تبدیل درصد به زمان واقعی
281
  let newTime = trimMinLimit + (percent * trimViewDuration);
282
 
283
+ // گرد کردن برای دقت 2 رقم اعشار
284
+ newTime = Math.round(newTime * 100) / 100;
285
+
286
  if (activeDragHandle === 'left') {
287
+ // محدودیت هندل چپ:
288
+ // 1. نباید از پایان جلو بزند (حداقل فاصله 0.05)
289
+ // 2. نباید از حد مجاز (کلمه قبل) کمتر شود
290
  if (newTime >= tempEndTime - 0.05) newTime = tempEndTime - 0.05;
291
+ if (newTime < trimMinLimit) newTime = trimMinLimit;
292
 
293
+ tempStartTime = newTime;
294
  } else {
295
+ // مح��ودیت هندل راست:
296
+ // 1. نباید از شروع عقب بیاید
297
+ // 2. نباید از حد مجاز (کلمه بعد) بیشتر شود
298
  if (newTime <= tempStartTime + 0.05) newTime = tempStartTime + 0.05;
299
+ if (newTime > trimMaxLimit) newTime = trimMaxLimit;
300
 
301
+ tempEndTime = newTime;
302
  }
303
 
304
+ // بروزرسانی آنی گرافیک
305
  updateTrimmerVisuals();
306
  }
307
 
308
+ function endDrag(e) {
309
+ if(!activeDragHandle) return;
310
+ if(e && e.cancelable) e.preventDefault();
311
+
312
  activeDragHandle = null;
313
  document.removeEventListener('mousemove', onDrag);
314
  document.removeEventListener('mouseup', endDrag);
 
318
 
319
  function updateTrimmerVisuals() {
320
  // نمایش متنی زمان
321
+ const tStartDisp = document.getElementById('trimStartDisp');
322
+ const tEndDisp = document.getElementById('trimEndDisp');
323
+
324
+ if(tStartDisp) tStartDisp.innerText = formatTimeMs(tempStartTime);
325
+ if(tEndDisp) tEndDisp.innerText = formatTimeMs(tempEndTime);
326
 
327
+ // محاسبه درصدها برای CSS
328
+ let leftP = ((tempStartTime - trimMinLimit) / trimViewDuration) * 100;
329
+ let rightP = ((tempEndTime - trimMinLimit) / trimViewDuration) * 100;
330
+
331
+ // اطمینان از اینکه درصدها بین 0 تا 100 هستند
332
+ leftP = Math.max(0, Math.min(100, leftP));
333
+ rightP = Math.max(0, Math.min(100, rightP));
334
 
335
  const handleL = document.getElementById('handleLeft');
336
  const handleR = document.getElementById('handleRight');
337
  const track = document.getElementById('trackActive');
338
 
339
+ // اعمال استایل‌ها
340
+ if(handleL) handleL.style.left = `${leftP}%`;
341
+ if(handleR) handleR.style.left = `${rightP}%`;
342
+
343
+ if(track) {
 
344
  track.style.left = `${leftP}%`;
345
  track.style.width = `${rightP - leftP}%`;
346
  }
 
355
 
356
  // تابع پخش دقیق بازه انتخاب شده
357
  function playPreviewWord() {
358
+ if ((tempStartTime === undefined) || (tempEndTime === undefined)) return;
359
 
 
360
  if(previewInterval) clearInterval(previewInterval);
361
  v.pause();
362
 
363
+ // پرش به لحظه شروع تنظیم شده
364
  v.currentTime = tempStartTime;
365
 
366
  const icon1 = document.getElementById('btnPreviewPlay')?.querySelector('i');
 
371
 
372
  v.play().then(() => {
373
  previewInterval = setInterval(() => {
374
+ // اگر زمان فعلی از زمان پایان رد شد، متوقف کن
375
  if(v.currentTime >= tempEndTime) {
376
  v.pause();
377
  clearInterval(previewInterval);
 
379
  if(icon1) icon1.className = "fa-solid fa-play";
380
  if(icon2) icon2.className = "fa-solid fa-play";
381
 
382
+ // برگرداندن به زمان پایان برای نمایش فریم آخر
383
+ v.currentTime = tempEndTime;
384
  }
385
  }, 15);
386
  }).catch(e => console.log("Play interrupted", e));
 
419
  const [sIdx, wIdx] = activeWordId.split('-').map(Number);
420
  const seg = state.segs[sIdx];
421
 
422
+ // اعمال تغییرات
423
  seg.words[wIdx].start = tempStartTime;
424
  seg.words[wIdx].end = tempEndTime;
425
 
 
426
  if (wIdx === 0 && tempStartTime < seg.start) seg.start = tempStartTime;
427
  if (wIdx === seg.words.length - 1 && tempEndTime > seg.end) seg.end = tempEndTime;
428