mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-11-09 17:08:58 -05:00
Improve subtitles menu and button behavior in VideoJS
Adds direct access to the subtitles submenu from the subtitles button, updates the button's active state based on subtitle selection, and dispatches a custom event on subtitle state changes. Also cleans up unused static video.js files and enables the SubtitlesButton CSS.
This commit is contained in:
parent
c4551c4050
commit
76e85d2577
@ -819,6 +819,7 @@ class CustomSettingsMenu extends Component {
|
|||||||
|
|
||||||
this.speedSubmenu.style.display = 'none'; // Hide submenu when main menu toggles
|
this.speedSubmenu.style.display = 'none'; // Hide submenu when main menu toggles
|
||||||
if (this.qualitySubmenu) this.qualitySubmenu.style.display = 'none';
|
if (this.qualitySubmenu) this.qualitySubmenu.style.display = 'none';
|
||||||
|
if (this.subtitlesSubmenu) this.subtitlesSubmenu.style.display = 'none';
|
||||||
const btnEl = this.settingsButton?.el();
|
const btnEl = this.settingsButton?.el();
|
||||||
if (btnEl) {
|
if (btnEl) {
|
||||||
if (!isVisible) {
|
if (!isVisible) {
|
||||||
@ -829,6 +830,28 @@ class CustomSettingsMenu extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to open settings directly to subtitles submenu
|
||||||
|
openSubtitlesMenu() {
|
||||||
|
// First ensure settings overlay is visible
|
||||||
|
this.settingsOverlay.classList.add('show');
|
||||||
|
this.settingsOverlay.style.display = 'block';
|
||||||
|
|
||||||
|
// Hide other submenus and show subtitles submenu
|
||||||
|
this.speedSubmenu.style.display = 'none';
|
||||||
|
if (this.qualitySubmenu) this.qualitySubmenu.style.display = 'none';
|
||||||
|
if (this.subtitlesSubmenu) {
|
||||||
|
this.subtitlesSubmenu.style.display = 'flex';
|
||||||
|
// Refresh the submenu to ensure it's up to date
|
||||||
|
this.refreshSubtitlesSubmenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark settings button as active
|
||||||
|
const btnEl = this.settingsButton?.el();
|
||||||
|
if (btnEl) {
|
||||||
|
btnEl.classList.add('settings-clicked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleSpeedChange(speed, speedOption) {
|
handleSpeedChange(speed, speedOption) {
|
||||||
// Update player speed
|
// Update player speed
|
||||||
this.player().playbackRate(speed);
|
this.player().playbackRate(speed);
|
||||||
@ -1062,6 +1085,12 @@ class CustomSettingsMenu extends Component {
|
|||||||
this.userPreferences.setPreference('subtitleLanguage', lang || null, true);
|
this.userPreferences.setPreference('subtitleLanguage', lang || null, true);
|
||||||
this.userPreferences.setPreference('subtitleEnabled', !!lang, true); // for iphones
|
this.userPreferences.setPreference('subtitleEnabled', !!lang, true); // for iphones
|
||||||
|
|
||||||
|
// Trigger a custom event to notify other components about subtitle state change
|
||||||
|
const subtitleChangeEvent = new CustomEvent('subtitleStateChanged', {
|
||||||
|
detail: { enabled: !!lang, language: lang },
|
||||||
|
});
|
||||||
|
window.dispatchEvent(subtitleChangeEvent);
|
||||||
|
|
||||||
// Update UI selection
|
// Update UI selection
|
||||||
this.subtitlesSubmenu.querySelectorAll('.subtitle-option').forEach((opt) => {
|
this.subtitlesSubmenu.querySelectorAll('.subtitle-option').forEach((opt) => {
|
||||||
opt.classList.remove('active');
|
opt.classList.remove('active');
|
||||||
@ -1078,8 +1107,16 @@ class CustomSettingsMenu extends Component {
|
|||||||
const currentSubtitlesDisplay = this.settingsOverlay.querySelector('.current-subtitles');
|
const currentSubtitlesDisplay = this.settingsOverlay.querySelector('.current-subtitles');
|
||||||
if (currentSubtitlesDisplay) currentSubtitlesDisplay.textContent = label;
|
if (currentSubtitlesDisplay) currentSubtitlesDisplay.textContent = label;
|
||||||
|
|
||||||
// Close only the subtitles submenu (keep overlay open)
|
// Close the entire settings overlay after subtitle selection
|
||||||
|
this.settingsOverlay.classList.remove('show');
|
||||||
|
this.settingsOverlay.style.display = 'none';
|
||||||
this.subtitlesSubmenu.style.display = 'none';
|
this.subtitlesSubmenu.style.display = 'none';
|
||||||
|
|
||||||
|
// Remove active state from settings button
|
||||||
|
const btnEl = this.settingsButton?.el();
|
||||||
|
if (btnEl) {
|
||||||
|
btnEl.classList.remove('settings-clicked');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreSubtitlePreference() {
|
restoreSubtitlePreference() {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import videojs from 'video.js';
|
|||||||
import 'video.js/dist/video-js.css';
|
import 'video.js/dist/video-js.css';
|
||||||
// import '../../VideoJS.css';
|
// import '../../VideoJS.css';
|
||||||
import '../../styles/embed.css';
|
import '../../styles/embed.css';
|
||||||
// import '../controls/SubtitlesButton.css';
|
import '../controls/SubtitlesButton.css';
|
||||||
import './VideoJSPlayer.css';
|
import './VideoJSPlayer.css';
|
||||||
import './VideoJSPlayerRoundedCorners.css';
|
import './VideoJSPlayerRoundedCorners.css';
|
||||||
import '../controls/ButtonTooltips.css';
|
import '../controls/ButtonTooltips.css';
|
||||||
@ -42,8 +42,8 @@ const enableStandardButtonTooltips = (player) => {
|
|||||||
// volumePanel: 'Volume', // Removed - no tooltip for volume
|
// volumePanel: 'Volume', // Removed - no tooltip for volume
|
||||||
fullscreenToggle: () => (player.isFullscreen() ? 'Exit fullscreen' : 'Fullscreen'),
|
fullscreenToggle: () => (player.isFullscreen() ? 'Exit fullscreen' : 'Fullscreen'),
|
||||||
pictureInPictureToggle: 'Picture-in-picture',
|
pictureInPictureToggle: 'Picture-in-picture',
|
||||||
subtitlesButton: 'Subtitles/CC',
|
subtitlesButton: '',
|
||||||
captionsButton: '',
|
captionsButton: 'Captions',
|
||||||
subsCapsButton: '',
|
subsCapsButton: '',
|
||||||
chaptersButton: 'Chapters',
|
chaptersButton: 'Chapters',
|
||||||
audioTrackButton: 'Audio tracks',
|
audioTrackButton: 'Audio tracks',
|
||||||
@ -1176,7 +1176,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
media_type: 'video',
|
media_type: 'video',
|
||||||
original_media_url:
|
original_media_url:
|
||||||
'/media/original/user/markos/db52140de7204022a1e5f08e078b4ec6.UniversityofCopenhagenMærskTower.mp4',
|
'/media/original/user/markos/db52140de7204022a1e5f08e078b4ec6.UniversityofCopenhagenMærskTower.mp4',
|
||||||
_hls_info: {
|
hls_info: {
|
||||||
master_file: '/media/hls/5073e97457004961a163c5b504e2d7e8/master.m3u8',
|
master_file: '/media/hls/5073e97457004961a163c5b504e2d7e8/master.m3u8',
|
||||||
'240_iframe': '/media/hls/5073e97457004961a163c5b504e2d7e8/media-1/iframes.m3u8',
|
'240_iframe': '/media/hls/5073e97457004961a163c5b504e2d7e8/media-1/iframes.m3u8',
|
||||||
'480_iframe': '/media/hls/5073e97457004961a163c5b504e2d7e8/media-2/iframes.m3u8',
|
'480_iframe': '/media/hls/5073e97457004961a163c5b504e2d7e8/media-2/iframes.m3u8',
|
||||||
@ -1189,7 +1189,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
'144_playlist': '/media/hls/5073e97457004961a163c5b504e2d7e8/media-4/stream.m3u8',
|
'144_playlist': '/media/hls/5073e97457004961a163c5b504e2d7e8/media-4/stream.m3u8',
|
||||||
'360_playlist': '/media/hls/5073e97457004961a163c5b504e2d7e8/media-5/stream.m3u8',
|
'360_playlist': '/media/hls/5073e97457004961a163c5b504e2d7e8/media-5/stream.m3u8',
|
||||||
},
|
},
|
||||||
hls_info: {},
|
// hls_info: {},
|
||||||
/* hls_info: {
|
/* hls_info: {
|
||||||
master_file: '/media/hls/c1ab03cab3bb46b5854a5e217cfe3013/master.m3u8',
|
master_file: '/media/hls/c1ab03cab3bb46b5854a5e217cfe3013/master.m3u8',
|
||||||
'240_iframe': '/media/hls/c1ab03cab3bb46b5854a5e217cfe3013/media-1/iframes.m3u8',
|
'240_iframe': '/media/hls/c1ab03cab3bb46b5854a5e217cfe3013/media-1/iframes.m3u8',
|
||||||
@ -2116,7 +2116,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
descriptionsButton: false,
|
descriptionsButton: false,
|
||||||
|
|
||||||
// Subtitles (CC) button should be visible
|
// Subtitles (CC) button should be visible
|
||||||
subtitlesButton: false, // hasSubtitles && !isTouchDevice ? true : false,
|
subtitlesButton: hasSubtitles ? true : false, // hasSubtitles && !isTouchDevice ? true : false,
|
||||||
|
|
||||||
// Captions button (keep disabled to avoid duplicate with subtitles)
|
// Captions button (keep disabled to avoid duplicate with subtitles)
|
||||||
captionsButton: hasSubtitles ? true : false,
|
captionsButton: hasSubtitles ? true : false,
|
||||||
@ -2989,7 +2989,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
// END: Implement autoplay toggle button
|
// END: Implement autoplay toggle button
|
||||||
|
|
||||||
// Make menus clickable instead of hover-only
|
// Make menus clickable instead of hover-only
|
||||||
/* setTimeout(() => {
|
setTimeout(() => {
|
||||||
const setupClickableMenus = () => {
|
const setupClickableMenus = () => {
|
||||||
// Find all menu buttons (subtitles, etc.) - exclude chaptersButton as it has custom overlay
|
// Find all menu buttons (subtitles, etc.) - exclude chaptersButton as it has custom overlay
|
||||||
const menuButtons = ['subtitlesButton', 'playbackRateMenuButton'];
|
const menuButtons = ['subtitlesButton', 'playbackRateMenuButton'];
|
||||||
@ -3049,6 +3049,74 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
const menu = el.querySelector('.vjs-menu');
|
const menu = el.querySelector('.vjs-menu');
|
||||||
if (menu) menu.style.display = 'none';
|
if (menu) menu.style.display = 'none';
|
||||||
|
|
||||||
|
// Different behavior for subtitles button - open settings menu directly
|
||||||
|
if (n === 'subtitlesButton') {
|
||||||
|
// Subtitles button opens settings menu directly to subtitles
|
||||||
|
const openSubtitlesSettings = (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
// Open settings menu directly to subtitles submenu
|
||||||
|
if (
|
||||||
|
customComponents.current.settingsMenu &&
|
||||||
|
customComponents.current.settingsMenu.openSubtitlesMenu
|
||||||
|
) {
|
||||||
|
customComponents.current.settingsMenu.openSubtitlesMenu();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
el.addEventListener('click', openSubtitlesSettings, { capture: true });
|
||||||
|
|
||||||
|
// Add mobile touch support for subtitles button
|
||||||
|
el.addEventListener(
|
||||||
|
'touchend',
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
openSubtitlesSettings(e);
|
||||||
|
},
|
||||||
|
{ passive: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply red underline based on localStorage subtitleEnabled
|
||||||
|
const updateSubtitleButtonState = () => {
|
||||||
|
const subtitleEnabled =
|
||||||
|
userPreferences.current.getPreference('subtitleEnabled');
|
||||||
|
if (subtitleEnabled) {
|
||||||
|
el.classList.add('vjs-subs-active');
|
||||||
|
} else {
|
||||||
|
el.classList.remove('vjs-subs-active');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial state
|
||||||
|
updateSubtitleButtonState();
|
||||||
|
|
||||||
|
// Listen for subtitle changes to update the red underline
|
||||||
|
playerRef.current.on('texttrackchange', updateSubtitleButtonState);
|
||||||
|
|
||||||
|
// Listen for custom subtitle state changes from settings menu
|
||||||
|
const handleSubtitleStateChange = () => {
|
||||||
|
updateSubtitleButtonState();
|
||||||
|
};
|
||||||
|
window.addEventListener('subtitleStateChanged', handleSubtitleStateChange);
|
||||||
|
|
||||||
|
// Also listen for storage changes to update button state
|
||||||
|
const handleStorageChange = () => {
|
||||||
|
updateSubtitleButtonState();
|
||||||
|
};
|
||||||
|
window.addEventListener('storage', handleStorageChange);
|
||||||
|
|
||||||
|
// Clean up event listeners when player is disposed
|
||||||
|
playerRef.current.on('dispose', () => {
|
||||||
|
window.removeEventListener(
|
||||||
|
'subtitleStateChanged',
|
||||||
|
handleSubtitleStateChange
|
||||||
|
);
|
||||||
|
window.removeEventListener('storage', handleStorageChange);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Other buttons (captions, subsCaps) keep the original toggle behavior
|
||||||
const toggleSubs = (ev) => {
|
const toggleSubs = (ev) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
@ -3069,11 +3137,16 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
el.classList.remove('vjs-subs-active');
|
el.classList.remove('vjs-subs-active');
|
||||||
// Do not change saved language on quick toggle off; save enabled=false
|
// Do not change saved language on quick toggle off; save enabled=false
|
||||||
try {
|
try {
|
||||||
userPreferences.current.setPreference('subtitleEnabled', false, true);
|
userPreferences.current.setPreference(
|
||||||
|
'subtitleEnabled',
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
} else {
|
} else {
|
||||||
// Show using previously chosen language only; do not change it
|
// Show using previously chosen language only; do not change it
|
||||||
const preferred = userPreferences.current.getPreference('subtitleLanguage');
|
const preferred =
|
||||||
|
userPreferences.current.getPreference('subtitleLanguage');
|
||||||
if (!preferred) {
|
if (!preferred) {
|
||||||
// If no language chosen yet, enable first available and save it
|
// If no language chosen yet, enable first available and save it
|
||||||
let first = null;
|
let first = null;
|
||||||
@ -3132,7 +3205,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
|
|
||||||
el.addEventListener('click', toggleSubs, { capture: true });
|
el.addEventListener('click', toggleSubs, { capture: true });
|
||||||
|
|
||||||
// Add mobile touch support
|
// Add mobile touch support for subtitles button
|
||||||
el.addEventListener(
|
el.addEventListener(
|
||||||
'touchend',
|
'touchend',
|
||||||
(e) => {
|
(e) => {
|
||||||
@ -3142,6 +3215,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
},
|
},
|
||||||
{ passive: false }
|
{ passive: false }
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Sync underline state on external changes
|
// Sync underline state on external changes
|
||||||
playerRef.current.on('texttrackchange', () => {
|
playerRef.current.on('texttrackchange', () => {
|
||||||
@ -3175,8 +3249,8 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// setupClickableMenus();
|
setupClickableMenus();
|
||||||
}, 1500); */
|
}, 1500);
|
||||||
|
|
||||||
// BEGIN: Add chapter markers and sprite preview to progress control
|
// BEGIN: Add chapter markers and sprite preview to progress control
|
||||||
if (progressControl && seekBar) {
|
if (progressControl && seekBar) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user