diff --git a/frontend-tools/video-js/src/components/controls/CustomChaptersOverlay.js b/frontend-tools/video-js/src/components/controls/CustomChaptersOverlay.js index 1a8bf798..ed8bf233 100644 --- a/frontend-tools/video-js/src/components/controls/CustomChaptersOverlay.js +++ b/frontend-tools/video-js/src/components/controls/CustomChaptersOverlay.js @@ -35,7 +35,7 @@ class CustomChaptersOverlay extends Component { const hh = Math.floor(totalSec / 3600); const mm = Math.floor((totalSec % 3600) / 60); const ss = totalSec % 60; - + return `${String(hh).padStart(2, '0')}:${String(mm).padStart(2, '0')}:${String(ss).padStart(2, '0')}`; } @@ -152,12 +152,13 @@ class CustomChaptersOverlay extends Component { const hh = Math.floor(totalSec / 3600); const mm = Math.floor((totalSec % 3600) / 60); const ss = totalSec % 60; - const timeStr = hh > 0 - ? `${String(hh).padStart(2, '0')}:${String(mm).padStart(2, '0')}:${String(ss).padStart(2, '0')}` - : `${String(mm).padStart(2, '0')}:${String(ss).padStart(2, '0')}`; + const timeStr = + hh > 0 + ? `${String(hh).padStart(2, '0')}:${String(mm).padStart(2, '0')}:${String(ss).padStart(2, '0')}` + : `${String(mm).padStart(2, '0')}:${String(ss).padStart(2, '0')}`; const titleEl = document.createElement('h4'); - titleEl.textContent = chapter.text; + titleEl.textContent = chapter.chapterTitle; const sub = document.createElement('div'); sub.className = 'meta-sub'; const dynamic = document.createElement('span'); @@ -189,26 +190,34 @@ class CustomChaptersOverlay extends Component { this.updateActiveItem(index); } }; - + // Track scrolling state for touch devices let touchStartY = 0; let touchStartTime = 0; - - item.addEventListener('touchstart', (e) => { - touchStartY = e.touches[0].clientY; - touchStartTime = Date.now(); - this.isScrolling = false; - }, { passive: true }); - - item.addEventListener('touchmove', (e) => { - const touchMoveY = e.touches[0].clientY; - const deltaY = Math.abs(touchMoveY - touchStartY); - // If user moved more than 10px vertically, consider it scrolling - if (deltaY > 10) { - this.isScrolling = true; - } - }, { passive: true }); - + + item.addEventListener( + 'touchstart', + (e) => { + touchStartY = e.touches[0].clientY; + touchStartTime = Date.now(); + this.isScrolling = false; + }, + { passive: true } + ); + + item.addEventListener( + 'touchmove', + (e) => { + const touchMoveY = e.touches[0].clientY; + const deltaY = Math.abs(touchMoveY - touchStartY); + // If user moved more than 10px vertically, consider it scrolling + if (deltaY > 10) { + this.isScrolling = true; + } + }, + { passive: true } + ); + item.addEventListener('touchend', seekFn, { passive: false }); item.addEventListener('click', seekFn); @@ -246,10 +255,13 @@ class CustomChaptersOverlay extends Component { if (el) el.classList.toggle('chapters-open', isHidden); try { - this.player().el().querySelectorAll('.vjs-menu').forEach((m) => { - m.classList.remove('vjs-lock-showing'); - m.style.display = 'none'; - }); + this.player() + .el() + .querySelectorAll('.vjs-menu') + .forEach((m) => { + m.classList.remove('vjs-lock-showing'); + m.style.display = 'none'; + }); } catch (e) {} } @@ -272,11 +284,13 @@ class CustomChaptersOverlay extends Component { currentChapterIndex = index; item.classList.add('selected'); if (handle) handle.textContent = '▶'; - if (dynamic) dynamic.textContent = dynamic.getAttribute('data-time-range') || this.getChapterTimeRange(chapter); + if (dynamic) + dynamic.textContent = dynamic.getAttribute('data-time-range') || this.getChapterTimeRange(chapter); } else { item.classList.remove('selected'); if (handle) handle.textContent = String(index + 1); - if (dynamic) dynamic.textContent = dynamic.getAttribute('data-time-range') || this.getChapterTimeRange(chapter); + if (dynamic) + dynamic.textContent = dynamic.getAttribute('data-time-range') || this.getChapterTimeRange(chapter); } }); diff --git a/frontend-tools/video-js/src/components/markers/ChapterMarkers.js b/frontend-tools/video-js/src/components/markers/ChapterMarkers.js index 88ebe505..cf89eb67 100644 --- a/frontend-tools/video-js/src/components/markers/ChapterMarkers.js +++ b/frontend-tools/video-js/src/components/markers/ChapterMarkers.js @@ -49,7 +49,7 @@ class ChapterMarkers extends Component { this.chaptersData.push({ startTime: cue.startTime, endTime: cue.endTime, - text: cue.text, + chapterTitle: cue.chapterTitle, }); } @@ -90,14 +90,14 @@ class ChapterMarkers extends Component { // Style the floating tooltip Object.assign(this.tooltip.style, { - position: 'absolute', + position: 'absolute', zIndex: '1000', bottom: '45px', transform: 'translateX(-50%)', display: 'none', minWidth: '160px', maxWidth: '200px', - width: 'auto', + width: 'auto', }); // Create stable DOM structure to avoid trembling @@ -130,9 +130,9 @@ class ChapterMarkers extends Component { this.chapterImage = videojs.dom.createEl('div', { className: 'chapter-image-sprite', }); - Object.assign(this.chapterImage.style, { + Object.assign(this.chapterImage.style, { display: 'block', - overflow: 'hidden', + overflow: 'hidden', }); // Append all elements to tooltip @@ -213,10 +213,10 @@ class ChapterMarkers extends Component { const startTime = formatTime(currentChapter.startTime); const endTime = formatTime(currentChapter.endTime); - const timeAtPosition = formatTime(currentTime); + // const timeAtPosition = formatTime(currentTime); // Update text content without rebuilding DOM - this.chapterTitle.textContent = currentChapter.text; + this.chapterTitle.textContent = currentChapter.chapterTitle; this.chapterInfo.textContent = `Chapter: ${startTime} - ${endTime}`; // this.positionInfo.textContent = `Position: ${timeAtPosition}`; @@ -344,7 +344,7 @@ class ChapterMarkers extends Component { const tooltip = videojs.dom.createEl('div', { className: 'vjs-chapter-marker-tooltip', }); - tooltip.textContent = cue.text; + tooltip.textContent = cue.chapterTitle; marker.appendChild(tooltip); // Add click handler to jump to chapter diff --git a/frontend-tools/video-js/src/components/video-player/VideoJSPlayer.jsx b/frontend-tools/video-js/src/components/video-player/VideoJSPlayer.jsx index 833d0025..cfd17229 100644 --- a/frontend-tools/video-js/src/components/video-player/VideoJSPlayer.jsx +++ b/frontend-tools/video-js/src/components/video-player/VideoJSPlayer.jsx @@ -40,9 +40,13 @@ function VideoJSPlayer({ videoId = 'default-video' }) { poster_url: 'https://demo.mediacms.io/media/original/thumbnails/user/markos/7dedcb56bde9463dbc0766768a99be0f_C8E5GFY.20250605_110647.mp4.jpg', chapter_data: [ - { startTime: '00:00:00.000', endTime: '00:00:24.295', text: 'A1 test' }, - { startTime: '00:00:24.295', endTime: '00:00:48.590', text: 'A2 of Marine Life' }, - { startTime: '00:00:48.590', endTime: '00:01:12.885', text: 'A3 Reef Ecosystems' }, + { startTime: '00:00:00.000', endTime: '00:00:24.295', chapterTitle: 'A1 test' }, + { startTime: '00:00:24.295', endTime: '00:00:48.590', chapterTitle: 'A2 of Marine Life' }, + { + startTime: '00:00:48.590', + endTime: '00:01:12.885', + chapterTitle: 'A3 Reef Ecosystems', + }, ], related_media: [ { @@ -1099,7 +1103,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) { const convertedData = rawChaptersData.map((chapter) => ({ startTime: convertTimeStringToSeconds(chapter.startTime), endTime: convertTimeStringToSeconds(chapter.endTime), - text: chapter.text, + chapterTitle: chapter.chapterTitle, })); return convertedData; @@ -1113,32 +1117,32 @@ function VideoJSPlayer({ videoId = 'default-video' }) { } return isDevMode ? [ - { startTime: '00:00:00.000', endTime: '00:00:04.000', text: 'Introduction' }, - { startTime: '00:00:05.000', endTime: '00:00:10.000', text: 'Overview of Marine Life' }, - { startTime: '00:00:10.000', endTime: '00:00:15.000', text: 'Coral Reef Ecosystems' }, - { startTime: '00:00:15.000', endTime: '00:00:20.000', text: 'Deep Sea Creatures' }, - { startTime: '00:00:20.000', endTime: '00:00:30.000', text: 'Ocean Conservation' }, - { startTime: '00:00:24.000', endTime: '00:00:32.000', text: 'Ocean Conservation' }, - { startTime: '00:00:32.000', endTime: '00:00:40.000', text: 'Climate Change Impact' }, - { startTime: '00:00:40.000', endTime: '00:00:48.000', text: 'Marine Protected Areas' }, - { startTime: '00:00:48.000', endTime: '00:00:56.000', text: 'Sustainable Fishing' }, - { startTime: '00:00:56.000', endTime: '00:00:64.000', text: 'Research Methods' }, - { startTime: '00:00:64.000', endTime: '00:00:72.000', text: 'Future Challenges' }, - { startTime: '00:00:72.000', endTime: '00:00:80.000', text: 'Conclusion' }, - { startTime: '00:00:80.000', endTime: '00:00:88.000', text: 'Marine Biodiversity Hotspots' }, - { startTime: '00:00:88.000', endTime: '00:00:96.000', text: 'Underwater Photography' }, - { startTime: '00:00:96.000', endTime: '00:01:04.000', text: 'Whale Migration Patterns' }, - { startTime: '00:01:04.000', endTime: '00:01:12.000', text: 'Plastic Pollution Crisis' }, - { startTime: '00:01:12.000', endTime: '00:01:20.000', text: 'Seagrass Meadows' }, - { startTime: '00:01:20.000', endTime: '00:01:28.000', text: 'Ocean Acidification' }, - { startTime: '00:01:28.000', endTime: '00:01:36.000', text: 'Marine Archaeology' }, - { startTime: '00:01:28.000', endTime: '00:01:36.000', text: 'Tidal Pool Ecosystems' }, - { startTime: '00:01:36.000', endTime: '00:01:44.000', text: 'Commercial Aquaculture' }, - { startTime: '00:01:44.000', endTime: '00:01:52.000', text: 'Ocean Exploration Technology' }, + { startTime: '00:00:00.000', endTime: '00:00:04.000', chapterTitle: 'Introduction' }, + { startTime: '00:00:05.000', endTime: '00:00:10.000', chapterTitle: 'Overview of Marine Life' }, + { startTime: '00:00:10.000', endTime: '00:00:15.000', chapterTitle: 'Coral Reef Ecosystems' }, + { startTime: '00:00:15.000', endTime: '00:00:20.000', chapterTitle: 'Deep Sea Creatures' }, + { startTime: '00:00:20.000', endTime: '00:00:30.000', chapterTitle: 'Ocean Conservation' }, + { startTime: '00:00:24.000', endTime: '00:00:32.000', chapterTitle: 'Ocean Conservation' }, + { startTime: '00:00:32.000', endTime: '00:00:40.000', chapterTitle: 'Climate Change Impact' }, + { startTime: '00:00:40.000', endTime: '00:00:48.000', chapterTitle: 'Marine Protected Areas' }, + { startTime: '00:00:48.000', endTime: '00:00:56.000', chapterTitle: 'Sustainable Fishing' }, + { startTime: '00:00:56.000', endTime: '00:00:64.000', chapterTitle: 'Research Methods' }, + { startTime: '00:00:64.000', endTime: '00:00:72.000', chapterTitle: 'Future Challenges' }, + { startTime: '00:00:72.000', endTime: '00:00:80.000', chapterTitle: 'Conclusion' }, + { startTime: '00:00:80.000', endTime: '00:00:88.000', chapterTitle: 'Marine Biodiversity Hotspots' }, + { startTime: '00:00:88.000', endTime: '00:00:96.000', chapterTitle: 'Marine Biodiversity test' }, + { startTime: '00:00:96.000', endTime: '00:01:04.000', chapterTitle: 'Whale Migration Patterns' }, + { startTime: '00:01:04.000', endTime: '00:01:12.000', chapterTitle: 'Plastic Pollution Crisis' }, + { startTime: '00:01:12.000', endTime: '00:01:20.000', chapterTitle: 'Seagrass Meadows' }, + { startTime: '00:01:20.000', endTime: '00:01:28.000', chapterTitle: 'Ocean Acidification' }, + { startTime: '00:01:28.000', endTime: '00:01:36.000', chapterTitle: 'Marine Archaeology' }, + { startTime: '00:01:28.000', endTime: '00:01:36.000', chapterTitle: 'Tidal Pool Ecosystems' }, + { startTime: '00:01:36.000', endTime: '00:01:44.000', chapterTitle: 'Commercial Aquaculture' }, + { startTime: '00:01:44.000', endTime: '00:01:52.000', chapterTitle: 'Ocean Exploration Technology' }, ].map((chapter) => ({ startTime: convertTimeStringToSeconds(chapter.startTime), endTime: convertTimeStringToSeconds(chapter.endTime), - text: chapter.text, + chapterTitle: chapter.chapterTitle, })) : []; }, [mediaData?.data?.chapter_data, isDevMode, convertChaptersData]);