vidply 1.0.26 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/dev/{vidply.HLSRenderer-X46P47LY.js → vidply.HLSRenderer-ENLZE4QS.js} +13 -8
  2. package/dist/dev/vidply.HLSRenderer-ENLZE4QS.js.map +7 -0
  3. package/dist/dev/{vidply.HTML5Renderer-LXQ3I45Q.js → vidply.HTML5Renderer-6SBDI6S2.js} +2 -2
  4. package/dist/dev/vidply.SoundCloudRenderer-CD7VJKNS.js +280 -0
  5. package/dist/dev/vidply.SoundCloudRenderer-CD7VJKNS.js.map +7 -0
  6. package/dist/dev/{vidply.VimeoRenderer-DCETT5IZ.js → vidply.VimeoRenderer-VPH4RNES.js} +17 -4
  7. package/dist/dev/vidply.VimeoRenderer-VPH4RNES.js.map +7 -0
  8. package/dist/dev/{vidply.YouTubeRenderer-QLMMD757.js → vidply.YouTubeRenderer-6MGKEFTZ.js} +14 -6
  9. package/dist/dev/vidply.YouTubeRenderer-6MGKEFTZ.js.map +7 -0
  10. package/dist/dev/{vidply.chunk-UEIJOJH6.js → vidply.chunk-BCOFCT6U.js} +4 -1
  11. package/dist/dev/vidply.chunk-BCOFCT6U.js.map +7 -0
  12. package/dist/dev/vidply.esm.js +288 -12
  13. package/dist/dev/vidply.esm.js.map +2 -2
  14. package/dist/legacy/vidply.js +609 -23
  15. package/dist/legacy/vidply.js.map +3 -3
  16. package/dist/legacy/vidply.min.js +1 -1
  17. package/dist/legacy/vidply.min.meta.json +26 -13
  18. package/dist/prod/vidply.HLSRenderer-CBXZ4RF2.min.js +6 -0
  19. package/dist/prod/{vidply.HTML5Renderer-XJCSUETP.min.js → vidply.HTML5Renderer-MY7XDV7R.min.js} +1 -1
  20. package/dist/prod/vidply.SoundCloudRenderer-MOR2CUFH.min.js +6 -0
  21. package/dist/prod/vidply.VimeoRenderer-3HBMM2WR.min.js +6 -0
  22. package/dist/prod/vidply.YouTubeRenderer-MFC2GMAC.min.js +6 -0
  23. package/dist/prod/vidply.chunk-OXXPY2XB.min.js +6 -0
  24. package/dist/prod/vidply.esm.min.js +6 -6
  25. package/dist/vidply.css +51 -0
  26. package/dist/vidply.esm.min.meta.json +56 -28
  27. package/dist/vidply.min.css +1 -1
  28. package/package.json +1 -1
  29. package/src/core/Player.js +117 -8
  30. package/src/features/PlaylistManager.js +312 -4
  31. package/src/renderers/HLSRenderer.js +17 -9
  32. package/src/renderers/HTML5Renderer.js +5 -0
  33. package/src/renderers/SoundCloudRenderer.js +355 -0
  34. package/src/renderers/VimeoRenderer.js +20 -4
  35. package/src/renderers/YouTubeRenderer.js +12 -6
  36. package/src/styles/vidply.css +51 -0
  37. package/dist/dev/vidply.HLSRenderer-X46P47LY.js.map +0 -7
  38. package/dist/dev/vidply.VimeoRenderer-DCETT5IZ.js.map +0 -7
  39. package/dist/dev/vidply.YouTubeRenderer-QLMMD757.js.map +0 -7
  40. package/dist/dev/vidply.chunk-UEIJOJH6.js.map +0 -7
  41. package/dist/prod/vidply.HLSRenderer-LDXSMWTI.min.js +0 -6
  42. package/dist/prod/vidply.VimeoRenderer-P3PU27S7.min.js +0 -6
  43. package/dist/prod/vidply.YouTubeRenderer-DGKKWB5M.min.js +0 -6
  44. package/dist/prod/vidply.chunk-BQBGEJF7.min.js +0 -6
  45. /package/dist/dev/{vidply.HTML5Renderer-LXQ3I45Q.js.map → vidply.HTML5Renderer-6SBDI6S2.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/EventEmitter.js", "../../src/controls/ControlBar.js", "../../src/utils/PerformanceUtils.js", "../../src/controls/CaptionManager.js", "../../src/controls/KeyboardManager.js", "../../src/core/Player.js", "../../src/features/PlaylistManager.js", "../../src/index.js"],
4
- "sourcesContent": ["/**\r\n * Simple EventEmitter implementation\r\n */\r\n\r\nexport class EventEmitter {\r\n constructor() {\r\n this.events = {};\r\n }\r\n\r\n on(event, listener) {\r\n if (!this.events[event]) {\r\n this.events[event] = [];\r\n }\r\n this.events[event].push(listener);\r\n return this;\r\n }\r\n\r\n once(event, listener) {\r\n const onceListener = (...args) => {\r\n listener(...args);\r\n this.off(event, onceListener);\r\n };\r\n return this.on(event, onceListener);\r\n }\r\n\r\n off(event, listener) {\r\n if (!this.events[event]) return this;\r\n \r\n if (!listener) {\r\n delete this.events[event];\r\n } else {\r\n this.events[event] = this.events[event].filter(l => l !== listener);\r\n }\r\n \r\n return this;\r\n }\r\n\r\n emit(event, ...args) {\r\n if (!this.events[event]) return this;\r\n \r\n this.events[event].forEach(listener => {\r\n listener(...args);\r\n });\r\n \r\n return this;\r\n }\r\n\r\n removeAllListeners() {\r\n this.events = {};\r\n return this;\r\n }\r\n}\r\n\r\n", "/**\n * Control Bar Component\n */\n\nimport {DOMUtils} from '../utils/DOMUtils.js';\nimport {TimeUtils} from '../utils/TimeUtils.js';\nimport {createIconElement} from '../icons/Icons.js';\nimport {i18n} from '../i18n/i18n.js';\nimport {focusElement, focusFirstElement} from '../utils/FocusUtils.js';\n\nexport class ControlBar {\n constructor(player) {\n this.player = player;\n this.element = null;\n this.controls = {};\n this.hideTimeout = null;\n this.isDraggingProgress = false;\n this.isDraggingVolume = false;\n this.openMenu = null; // Track currently open menu\n this.openMenuButton = null; // Track button that opened the menu\n\n this.init();\n }\n\n init() {\n this.createElement();\n this.createControls();\n this.attachEvents();\n this.setupAutoHide();\n this.setupOverflowDetection();\n }\n\n // Helper method to check if we're on a mobile device\n isMobile() {\n return window.innerWidth < 768;\n }\n\n // Helper method to detect touch devices\n isTouchDevice() {\n return (\n ('ontouchstart' in window) ||\n (navigator.maxTouchPoints > 0) ||\n (navigator.msMaxTouchPoints > 0)\n );\n }\n\n // Smart menu positioning to avoid overflow\n positionMenu(menu, button, immediate = false) {\n const isMobile = this.isMobile();\n const isOverflowMenu = menu.classList.contains(`${this.player.options.classPrefix}-overflow-menu-list`);\n const isFullscreen = this.player.state.fullscreen;\n \n // In fullscreen, menu is appended to player container, so use fixed positioning\n if (isFullscreen && menu.parentElement === this.player.container) {\n const doFullscreenPositioning = () => {\n const buttonRect = button.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n const containerRect = this.player.container.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n \n // Position relative to player container\n const buttonCenterX = buttonRect.left + buttonRect.width / 2 - containerRect.left;\n const buttonTop = buttonRect.top - containerRect.top;\n const buttonBottom = buttonRect.bottom - containerRect.top;\n \n const spaceAbove = buttonRect.top - containerRect.top;\n const spaceBelow = containerRect.bottom - buttonRect.bottom;\n \n // Position menu above button by default\n if (spaceAbove >= menuRect.height + 20 || spaceAbove > spaceBelow) {\n menu.style.bottom = `${containerRect.height - buttonTop + 8}px`;\n menu.style.top = 'auto';\n menu.classList.remove('vidply-menu-below');\n } else {\n // Position below if more space there\n menu.style.top = `${buttonBottom + 8}px`;\n menu.style.bottom = 'auto';\n menu.classList.add('vidply-menu-below');\n }\n \n // Horizontal positioning\n if (isOverflowMenu) {\n // Overflow menu aligns to right\n const buttonRight = buttonRect.right - containerRect.left;\n menu.style.right = `${containerRect.width - buttonRight}px`;\n menu.style.left = 'auto';\n menu.style.transform = 'none';\n } else {\n // Other menus center on button\n menu.style.left = `${buttonCenterX}px`;\n menu.style.right = 'auto';\n menu.style.transform = 'translateX(-50%)';\n }\n };\n \n if (immediate) {\n doFullscreenPositioning();\n } else {\n requestAnimationFrame(doFullscreenPositioning);\n }\n return;\n }\n \n if (isMobile) {\n // On mobile, ensure menus stay within viewport\n const isVolumeMenu = menu.classList.contains(`${this.player.options.classPrefix}-volume-menu`);\n \n const doMobilePositioning = () => {\n // Get the button's parent container (controls-left or controls-right)\n const parentContainer = button.parentElement;\n if (!parentContainer) return;\n \n const buttonRect = button.getBoundingClientRect();\n const parentRect = parentContainer.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n \n // Volume menu should be centered on its button\n if (isVolumeMenu) {\n // Calculate button position relative to parent\n const buttonCenterX = buttonRect.left + buttonRect.width / 2 - parentRect.left;\n \n // Center menu on button\n menu.style.left = `${buttonCenterX}px`;\n menu.style.right = 'auto';\n menu.style.transform = 'translateX(-50%)';\n return;\n }\n \n // Check if menu overflows viewport\n if (menuRect.right > viewportWidth) {\n menu.style.left = 'auto';\n menu.style.right = '10px';\n menu.style.transform = 'none';\n }\n \n if (menuRect.left < 0) {\n menu.style.left = '10px';\n menu.style.right = 'auto';\n menu.style.transform = 'none';\n }\n \n // Ensure menu doesn't go off top or bottom\n if (menuRect.top < 10) {\n menu.style.top = '10px';\n }\n \n if (menuRect.bottom > viewportHeight - 10) {\n menu.style.bottom = '10px';\n menu.style.top = 'auto';\n }\n };\n \n if (immediate) {\n doMobilePositioning();\n } else {\n requestAnimationFrame(doMobilePositioning);\n }\n return;\n }\n\n // Desktop: Smart positioning\n // Menu is now a sibling of the button, within controls-left or controls-right container\n // These containers have position: relative, so menus position relative to them\n \n const doPositioning = () => {\n const buttonRect = button.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n \n // Get the button's parent container (controls-left or controls-right)\n const parentContainer = button.parentElement;\n if (!parentContainer) return;\n \n const parentRect = parentContainer.getBoundingClientRect();\n \n // Calculate position relative to parent container\n const buttonCenterX = buttonRect.left + buttonRect.width / 2 - parentRect.left;\n const buttonBottom = buttonRect.bottom - parentRect.top;\n const buttonTop = buttonRect.top - parentRect.top;\n \n const spaceAbove = buttonRect.top;\n const spaceBelow = viewportHeight - buttonRect.bottom;\n \n // Position menu above button by default\n let menuTop = buttonTop - menuRect.height - 8;\n let menuBottom = null;\n \n // Prefer above, but switch to below if not enough space\n if (spaceAbove < menuRect.height + 20 && spaceBelow > spaceAbove) {\n menuTop = null;\n // Calculate bottom position relative to parent container\n // bottom: X means X pixels from the bottom of the positioned parent\n // We want the menu to be 8px below the button\n const parentHeight = parentRect.bottom - parentRect.top;\n menuBottom = parentHeight - buttonBottom + 8;\n menu.classList.add('vidply-menu-below');\n } else {\n menu.classList.remove('vidply-menu-below');\n }\n \n // Calculate horizontal position\n let menuLeft = 'auto';\n let menuRight = 'auto';\n let transformX = 'translateX(0)';\n \n // For overflow menu, always align to the right edge\n if (isOverflowMenu) {\n menuLeft = 'auto';\n menuRight = 0;\n transformX = 'translateX(0)';\n } else {\n // For other menus, center on button by default\n menuLeft = buttonCenterX - menuRect.width / 2;\n \n // Check horizontal overflow\n const menuLeftAbsolute = buttonRect.left + buttonRect.width / 2 - menuRect.width / 2;\n if (menuLeftAbsolute < 10) {\n // Too far left, align to left edge of parent\n menuLeft = 0;\n transformX = 'translateX(0)';\n } else if (menuLeftAbsolute + menuRect.width > viewportWidth - 10) {\n // Too far right, align to right edge of parent\n menuLeft = 'auto';\n menuRight = 0;\n transformX = 'translateX(0)';\n } else {\n // Center on button\n menuLeft = buttonCenterX;\n transformX = 'translateX(-50%)';\n }\n }\n \n // Apply calculated positions\n if (menuTop !== null) {\n menu.style.top = `${menuTop}px`;\n menu.style.bottom = 'auto';\n } else if (menuBottom !== null) {\n menu.style.top = 'auto';\n menu.style.bottom = `${menuBottom}px`;\n }\n \n if (menuLeft !== 'auto') {\n menu.style.left = `${menuLeft}px`;\n menu.style.right = 'auto';\n } else {\n menu.style.left = 'auto';\n menu.style.right = `${menuRight}px`;\n }\n \n menu.style.transform = transformX;\n };\n \n if (immediate) {\n // Position immediately (synchronously) - used when menu is first shown\n doPositioning();\n } else {\n // Use requestAnimationFrame to ensure layout is stable before positioning\n requestAnimationFrame(() => {\n setTimeout(doPositioning, 10); // Small delay to ensure layout is stable\n });\n }\n }\n\n // Helper method to insert menu into DOM (handles fullscreen vs normal mode)\n insertMenuIntoDOM(menu, button) {\n // Ensure menu has an ID for aria-controls relationship\n if (!menu.id) {\n menu.id = `vidply-menu-${Math.random().toString(36).substr(2, 9)}`;\n }\n \n // Set ARIA attributes for screen reader users (WCAG 4.1.2)\n button.setAttribute('aria-controls', menu.id);\n button.setAttribute('aria-haspopup', 'true');\n \n // In fullscreen, append menu to player container to escape video-wrapper stacking context\n // This allows menus to appear above the playlist panel\n // Otherwise, keep it after the button for WCAG compliance\n const isFullscreen = this.player.state.fullscreen;\n if (isFullscreen) {\n // Append to player container as sibling to playlist panel\n this.player.container.appendChild(menu);\n // Store reference to button for positioning\n menu.dataset.triggerButton = button.getAttribute('aria-label') || 'button';\n } else {\n // Insert menu right after the button in the DOM for keyboard navigation\n button.insertAdjacentElement('afterend', menu);\n }\n }\n\n // Helper method to attach close-on-outside-click behavior to menus\n attachMenuCloseHandler(menu, button, preventCloseOnInteraction = false) {\n // Close any previously open menu and clean up its handlers\n if (this.openMenu && this.openMenu !== menu && this.openMenuButton) {\n // Remove previous button's blur handler if it exists\n if (this.openMenuButton._vidplyBlurHandler) {\n this.openMenuButton.removeEventListener('blur', this.openMenuButton._vidplyBlurHandler);\n delete this.openMenuButton._vidplyBlurHandler;\n }\n if (this.openMenuButton._vidplyMousedownHandler) {\n this.openMenuButton.removeEventListener('mousedown', this.openMenuButton._vidplyMousedownHandler);\n delete this.openMenuButton._vidplyMousedownHandler;\n }\n \n // Close previous menu without returning focus\n if (this.openMenu && document.contains(this.openMenu)) {\n this.openMenu.remove();\n } else if (this.openMenu && this.openMenu.parentNode) {\n this.openMenu.parentNode.removeChild(this.openMenu);\n }\n if (this.openMenuButton) {\n this.openMenuButton.setAttribute('aria-expanded', 'false');\n }\n }\n \n // Track this menu as open\n this.openMenu = menu;\n this.openMenuButton = button;\n \n // Position menu smartly\n this.positionMenu(menu, button);\n \n // Set aria-expanded to true when menu opens\n if (button) {\n button.setAttribute('aria-expanded', 'true');\n }\n \n // Add focus handler to button to close menu when focus leaves to another control bar button\n // But only if it's a keyboard navigation (Tab), not a click\n let isClickingButton = false;\n let blurHandlerActive = true;\n \n const handleButtonMousedown = () => {\n isClickingButton = true;\n // Temporarily disable blur handler when clicking\n blurHandlerActive = false;\n setTimeout(() => {\n isClickingButton = false;\n blurHandlerActive = true;\n }, 200);\n };\n button.addEventListener('mousedown', handleButtonMousedown);\n button._vidplyMousedownHandler = handleButtonMousedown; // Store for cleanup\n \n const handleButtonBlur = (e) => {\n // If blur handler is disabled (during click) or this is a click, don't close the menu\n if (!blurHandlerActive || isClickingButton) {\n return;\n }\n \n // Check if this menu is still the open menu (might have been replaced)\n if (this.openMenu !== menu) {\n return;\n }\n \n // Store the related target (where focus is going) before async operations\n const relatedTarget = e.relatedTarget;\n \n // Use requestAnimationFrame to check where focus went after browser handles focus\n requestAnimationFrame(() => {\n setTimeout(() => {\n // Check again if blur handler is still active and menu is still open\n if (!blurHandlerActive || this.openMenu !== menu) {\n return;\n }\n \n const activeElement = document.activeElement;\n \n // Don't close if focus is still within the menu\n if (menu.contains(activeElement)) {\n return;\n }\n \n // Don't close if focus moved to sign language or transcript windows\n const signLanguageWrapper = this.player.signLanguageWrapper;\n const transcriptWindow = this.player.transcriptManager?.transcriptWindow;\n if ((signLanguageWrapper && signLanguageWrapper.contains(activeElement)) ||\n (transcriptWindow && transcriptWindow.contains(activeElement))) {\n return;\n }\n \n // If focus moved to another button in the control bar, close the menu\n const controlBarButtons = this.element.querySelectorAll('button');\n const isFocusOnAnotherButton = Array.from(controlBarButtons).includes(activeElement) && activeElement !== button;\n \n // Also check relatedTarget in case activeElement hasn't updated yet\n const isRelatedTargetAnotherButton = relatedTarget && Array.from(controlBarButtons).includes(relatedTarget) && relatedTarget !== button;\n \n // Close menu if focus moved to another control bar button (without returning focus)\n if (isFocusOnAnotherButton || isRelatedTargetAnotherButton) {\n // Double-check this menu is still the open menu\n if (this.openMenu !== menu) {\n return;\n }\n \n // Just remove the menu, don't touch focus at all\n if (menu && document.contains(menu)) {\n menu.remove();\n } else if (menu && menu.parentNode) {\n menu.parentNode.removeChild(menu);\n }\n if (button) {\n button.setAttribute('aria-expanded', 'false');\n }\n // Clear tracking\n if (this.openMenu === menu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n button.removeEventListener('blur', handleButtonBlur);\n button.removeEventListener('mousedown', handleButtonMousedown);\n delete button._vidplyBlurHandler;\n delete button._vidplyMousedownHandler;\n }\n }, 10); // Small delay to ensure focus has fully moved\n });\n };\n button.addEventListener('blur', handleButtonBlur);\n button._vidplyBlurHandler = handleButtonBlur; // Store for cleanup\n \n const closeMenuAndUpdateAria = () => {\n this.closeMenuAndReturnFocus(menu, button);\n };\n \n // Store document handlers for cleanup\n let documentClickHandler = null;\n let documentEscapeHandler = null;\n \n setTimeout(() => {\n documentClickHandler = (e) => {\n // If this menu has form controls, don't close when clicking inside\n if (preventCloseOnInteraction && menu.contains(e.target)) {\n return;\n }\n\n // Check if click is outside menu and button\n // Also check if this menu is still the open menu\n if (this.openMenu === menu && !menu.contains(e.target) && !button.contains(e.target)) {\n closeMenuAndUpdateAria();\n if (documentClickHandler) {\n document.removeEventListener('click', documentClickHandler);\n }\n if (documentEscapeHandler) {\n document.removeEventListener('keydown', documentEscapeHandler);\n }\n }\n };\n\n documentEscapeHandler = (e) => {\n if (e.key === 'Escape' && this.openMenu === menu) {\n e.preventDefault();\n e.stopPropagation();\n // Close menu and return focus to the button that opened it\n this.closeMenuAndReturnFocus(menu, button, true);\n if (documentClickHandler) {\n document.removeEventListener('click', documentClickHandler);\n }\n if (documentEscapeHandler) {\n document.removeEventListener('keydown', documentEscapeHandler);\n }\n }\n };\n\n document.addEventListener('click', documentClickHandler);\n document.addEventListener('keydown', documentEscapeHandler);\n }, 100);\n }\n\n // Helper method to close menu and return focus to button\n closeMenuAndReturnFocus(menu, button, returnFocus = true) {\n if (menu) {\n // Remove menu from DOM - use remove() which works reliably\n if (document.contains(menu)) {\n menu.remove();\n } else if (menu.parentNode) {\n // Fallback if menu is not in document but has parent\n menu.parentNode.removeChild(menu);\n }\n }\n if (button) {\n button.setAttribute('aria-expanded', 'false');\n // Clean up aria-controls since menu is removed (optional, but cleaner)\n // Note: Keeping it doesn't cause issues, but removing it is semantically correct\n // when the referenced element no longer exists\n if (menu && menu.id) {\n button.removeAttribute('aria-controls');\n }\n // Only return focus if explicitly requested (not when tabbing away)\n if (returnFocus) {\n // Use requestAnimationFrame to ensure DOM updates are complete before focusing\n // This prevents focus from jumping to next/previous button\n requestAnimationFrame(() => {\n setTimeout(() => {\n if (button && document.contains(button)) {\n button.focus({ preventScroll: true });\n }\n }, 0);\n });\n }\n }\n // Clear tracking\n if (this.openMenu === menu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n }\n \n // Close any open menu when tabbing to another button or clicking another button\n closeOpenMenu() {\n if (this.openMenu && this.openMenuButton) {\n // Close without returning focus (user is tabbing to next element or clicking another button)\n if (this.openMenu && document.contains(this.openMenu)) {\n this.openMenu.remove();\n } else if (this.openMenu && this.openMenu.parentNode) {\n this.openMenu.parentNode.removeChild(this.openMenu);\n }\n if (this.openMenuButton) {\n this.openMenuButton.setAttribute('aria-expanded', 'false');\n }\n // Clear tracking\n this.openMenu = null;\n this.openMenuButton = null;\n }\n }\n\n // Helper method to add keyboard navigation to menus (arrow keys)\n attachMenuKeyboardNavigation(menu, button) {\n const menuItems = Array.from(menu.querySelectorAll(`.${this.player.options.classPrefix}-menu-item`));\n \n if (menuItems.length === 0) return;\n\n const handleKeyDown = (e) => {\n const currentIndex = menuItems.indexOf(document.activeElement);\n \n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n e.stopPropagation(); // Prevent volume/seek actions\n const nextIndex = (currentIndex + 1) % menuItems.length;\n menuItems[nextIndex].focus({ preventScroll: false });\n menuItems[nextIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n break;\n \n case 'ArrowUp':\n e.preventDefault();\n e.stopPropagation(); // Prevent volume/seek actions\n const prevIndex = (currentIndex - 1 + menuItems.length) % menuItems.length;\n menuItems[prevIndex].focus({ preventScroll: false });\n menuItems[prevIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n break;\n \n case 'ArrowLeft':\n case 'ArrowRight':\n // Prevent seeking when in menu (but allow menu to handle if needed)\n e.preventDefault();\n e.stopPropagation();\n break;\n \n case 'Home':\n e.preventDefault();\n e.stopPropagation();\n menuItems[0].focus({ preventScroll: false });\n menuItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n break;\n \n case 'End':\n e.preventDefault();\n e.stopPropagation();\n menuItems[menuItems.length - 1].focus({ preventScroll: false });\n menuItems[menuItems.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n break;\n \n case 'Enter':\n case ' ':\n e.preventDefault();\n e.stopPropagation(); // Prevent event from reaching KeyboardManager\n if (document.activeElement && menuItems.includes(document.activeElement)) {\n document.activeElement.click();\n // Menu will be closed by the click handler, but ensure focus returns\n focusElement(button, { delay: 0 });\n }\n break;\n \n case 'Escape':\n e.preventDefault();\n e.stopPropagation(); // Prevent event from reaching KeyboardManager\n // Close menu and return focus to the button that opened it\n this.closeMenuAndReturnFocus(menu, button, true);\n break;\n }\n };\n\n menu.addEventListener('keydown', handleKeyDown);\n }\n\n createElement() {\n this.element = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-controls`,\n attributes: {\n 'role': 'region',\n 'aria-label': i18n.t('player.label') + ' controls'\n }\n });\n }\n\n createControls() {\n // Progress bar and time display wrapper\n const progressTimeWrapper = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-time-wrapper`\n });\n\n // Progress bar container\n if (this.player.options.progressBar) {\n this.createProgressBar();\n progressTimeWrapper.appendChild(this.controls.progress);\n }\n\n // Time display (right beside progress bar)\n if (this.player.options.currentTime || this.player.options.duration) {\n progressTimeWrapper.appendChild(this.createTimeDisplay());\n }\n\n this.element.appendChild(progressTimeWrapper);\n\n // Button container\n const buttonContainer = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-controls-buttons`\n });\n\n // Left buttons\n const leftButtons = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-controls-left`\n });\n\n // Previous track button (if playlist)\n if (this.player.playlistManager) {\n leftButtons.appendChild(this.createPreviousButton());\n }\n\n // Play/Pause button\n if (this.player.options.playPauseButton) {\n leftButtons.appendChild(this.createPlayPauseButton());\n }\n\n // Restart button (right beside play button)\n leftButtons.appendChild(this.createRestartButton());\n\n // Next track button (if playlist)\n if (this.player.playlistManager) {\n leftButtons.appendChild(this.createNextButton());\n }\n\n // Rewind button (not shown in playlist mode)\n if (!this.player.playlistManager) {\n leftButtons.appendChild(this.createRewindButton());\n }\n\n // Forward button (not shown in playlist mode)\n if (!this.player.playlistManager) {\n leftButtons.appendChild(this.createForwardButton());\n }\n\n // Volume control\n if (this.player.options.volumeControl) {\n // On touch devices: simple mute button (hardware buttons control volume)\n // On desktop: full volume control with slider\n if (this.isTouchDevice()) {\n leftButtons.appendChild(this.createMuteButton());\n } else {\n leftButtons.appendChild(this.createVolumeControl());\n }\n }\n\n // Right buttons\n this.rightButtons = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-controls-right`\n });\n\n // Check for available features\n const hasChapters = this.hasChapterTracks();\n const hasCaptions = this.hasCaptionTracks();\n const hasQualityLevels = this.hasQualityLevels();\n const hasAudioDescription = this.hasAudioDescription();\n\n // Priority order (lower number = higher priority, stays visible longer)\n // Desktop (>768px):\n // Priority 1: Play, Volume, Captions, Speed, Fullscreen\n // Priority 2: Audio Description, Quality \n // Priority 3: Chapters, Caption Style, Transcript, Sign Language, PiP\n // Smaller screens (<768px):\n // Priority 1: Play, Volume, Progress (only left controls visible)\n // Priority 3: ALL right-side buttons go to overflow menu\n\n // 1. Chapters button\n if (this.player.options.chaptersButton && hasChapters) {\n const btn = this.createChaptersButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 2. Captions button\n if (this.player.options.captionsButton && hasCaptions) {\n const btn = this.createCaptionsButton();\n btn.dataset.overflowPriority = '1';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 3. Caption styling button\n if (this.player.options.captionStyleButton && hasCaptions) {\n const btn = this.createCaptionStyleButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 4. Playback speed button\n if (this.player.options.speedButton) {\n const btn = this.createSpeedButton();\n btn.dataset.overflowPriority = '1';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 5. Audio Description button\n if (this.player.options.audioDescriptionButton && hasAudioDescription) {\n const btn = this.createAudioDescriptionButton();\n btn.dataset.overflowPriority = '2';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 6. Transcript button\n if (this.player.options.transcriptButton && hasCaptions) {\n const btn = this.createTranscriptButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 6.5 Playlist toggle button (for playlists)\n if (this.player.playlistManager && this.player.options.playlistToggleButton !== false) {\n const btn = this.createPlaylistToggleButton();\n btn.dataset.overflowPriority = '2';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 7. Sign Language button\n const hasSignLanguage = this.hasSignLanguage();\n if (this.player.options.signLanguageButton && hasSignLanguage) {\n const btn = this.createSignLanguageButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // Quality button (before fullscreen)\n if (this.player.options.qualityButton && hasQualityLevels) {\n const btn = this.createQualityButton();\n btn.dataset.overflowPriority = '2';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // PiP button (before fullscreen)\n if (this.player.options.pipButton && 'pictureInPictureEnabled' in document) {\n const btn = this.createPipButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 8. Fullscreen button (last)\n // Don't show fullscreen button for audio players\n const isAudioPlayer = this.player.element.tagName.toLowerCase() === 'audio';\n if (this.player.options.fullscreenButton && !isAudioPlayer) {\n const btn = this.createFullscreenButton();\n btn.dataset.overflowPriority = '1';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // Create overflow menu button (initially hidden)\n this.overflowMenuButton = this.createOverflowMenuButton();\n this.overflowMenuButton.style.display = 'none';\n this.rightButtons.appendChild(this.overflowMenuButton);\n\n buttonContainer.appendChild(leftButtons);\n buttonContainer.appendChild(this.rightButtons);\n this.element.appendChild(buttonContainer);\n \n // Ensure all buttons have title attributes\n this.ensureButtonTooltips(buttonContainer);\n }\n \n /**\n * Ensure all buttons in the controls have title attributes\n * Uses aria-label as title if title is not present\n */\n ensureButtonTooltips(container) {\n const buttons = container.querySelectorAll('button');\n buttons.forEach(button => {\n // Skip if tooltip already exists\n if (button.querySelector(`.${this.player.options.classPrefix}-tooltip`)) {\n return;\n }\n \n // Skip if button text already exists\n if (button.querySelector(`.${this.player.options.classPrefix}-button-text`)) {\n return;\n }\n \n // Skip menu items - they already have visible text\n if (button.getAttribute('role') === 'menuitem' || \n button.classList.contains(`${this.player.options.classPrefix}-settings-item`) ||\n button.classList.contains(`${this.player.options.classPrefix}-menu-item`) ||\n button.classList.contains(`${this.player.options.classPrefix}-transcript-settings-item`) ||\n button.classList.contains(`${this.player.options.classPrefix}-sign-language-settings-item`) ||\n button.classList.contains(`${this.player.options.classPrefix}-popup-settings-item`)) {\n return;\n }\n \n const ariaLabel = button.getAttribute('aria-label');\n if (ariaLabel) {\n // Add tooltip (aria-hidden popover)\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n }\n });\n }\n\n // Helper methods to check for available features\n hasChapterTracks() {\n const textTracks = this.player.element.textTracks;\n for (let i = 0; i < textTracks.length; i++) {\n if (textTracks[i].kind === 'chapters') {\n return true;\n }\n }\n return false;\n }\n\n hasCaptionTracks() {\n const textTracks = this.player.element.textTracks;\n for (let i = 0; i < textTracks.length; i++) {\n if (textTracks[i].kind === 'captions' || textTracks[i].kind === 'subtitles') {\n return true;\n }\n }\n return false;\n }\n\n hasQualityLevels() {\n // Check if renderer supports quality selection\n if (this.player.renderer && this.player.renderer.getQualities) {\n const qualities = this.player.renderer.getQualities();\n return qualities && qualities.length > 1;\n }\n return false;\n }\n\n hasAudioDescription() {\n // Check for audio-described video source OR description tracks\n if (this.player.audioDescriptionSrc && this.player.audioDescriptionSrc.length > 0) {\n return true;\n }\n \n // Check for description tracks\n const textTracks = Array.from(this.player.element.textTracks || []);\n return textTracks.some(track => track.kind === 'descriptions');\n }\n\n hasSignLanguage() {\n // Check for single source or multiple sources\n const hasSingleSource = this.player.signLanguageSrc && this.player.signLanguageSrc.length > 0;\n const hasMultipleSources = this.player.signLanguageSources && Object.keys(this.player.signLanguageSources).length > 0;\n return hasSingleSource || hasMultipleSources;\n }\n\n createProgressBar() {\n const progressContainer = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-container`,\n attributes: {\n 'role': 'slider',\n 'aria-label': i18n.t('player.progress'),\n 'aria-valuemin': '0',\n 'aria-valuemax': '100',\n 'aria-valuenow': '0',\n 'tabindex': '0'\n }\n });\n\n // Buffered progress\n this.controls.buffered = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-buffered`\n });\n\n // Played progress\n this.controls.played = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-played`\n });\n\n // Progress handle\n this.controls.progressHandle = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-handle`\n });\n\n // Tooltip\n this.controls.progressTooltip = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-tooltip`\n });\n\n progressContainer.appendChild(this.controls.buffered);\n progressContainer.appendChild(this.controls.played);\n this.controls.played.appendChild(this.controls.progressHandle);\n progressContainer.appendChild(this.controls.progressTooltip);\n\n this.controls.progress = progressContainer;\n\n // Progress bar events\n this.setupProgressBarEvents();\n }\n\n setupProgressBarEvents() {\n const progress = this.controls.progress;\n\n const updateProgress = (clientX) => {\n const rect = progress.getBoundingClientRect();\n // Guard against division by zero if progress bar has no width\n const percent = rect.width > 0 ? Math.max(0, Math.min(1, (clientX - rect.left) / rect.width)) : 0;\n const duration = this.player.state.duration || 0;\n const time = percent * duration;\n return {percent, time};\n };\n\n // Mouse events\n progress.addEventListener('mousedown', (e) => {\n this.isDraggingProgress = true;\n const {time} = updateProgress(e.clientX);\n this.player.seek(time);\n });\n\n document.addEventListener('mousemove', (e) => {\n if (this.isDraggingProgress) {\n const {time} = updateProgress(e.clientX);\n this.player.seek(time);\n }\n });\n\n document.addEventListener('mouseup', () => {\n this.isDraggingProgress = false;\n });\n\n // Hover tooltip\n progress.addEventListener('mousemove', (e) => {\n if (!this.isDraggingProgress) {\n const {time} = updateProgress(e.clientX);\n // Update tooltip text content instead of aria-label (divs shouldn't have aria-label)\n this.controls.progressTooltip.textContent = TimeUtils.formatTime(time);\n this.controls.progressTooltip.style.left = `${e.clientX - progress.getBoundingClientRect().left}px`;\n this.controls.progressTooltip.style.display = 'block';\n }\n });\n\n progress.addEventListener('mouseleave', () => {\n this.controls.progressTooltip.style.display = 'none';\n });\n\n // Keyboard navigation\n progress.addEventListener('keydown', (e) => {\n if (e.key === 'ArrowLeft') {\n e.preventDefault();\n this.player.seekBackward(5);\n } else if (e.key === 'ArrowRight') {\n e.preventDefault();\n this.player.seekForward(5);\n }\n });\n\n // Touch events\n progress.addEventListener('touchstart', (e) => {\n this.isDraggingProgress = true;\n const touch = e.touches[0];\n const {time} = updateProgress(touch.clientX);\n this.player.seek(time);\n });\n\n progress.addEventListener('touchmove', (e) => {\n if (this.isDraggingProgress) {\n e.preventDefault();\n const touch = e.touches[0];\n const {time} = updateProgress(touch.clientX);\n this.player.seek(time);\n }\n });\n\n progress.addEventListener('touchend', () => {\n this.isDraggingProgress = false;\n });\n }\n\n createPlayPauseButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-play-pause`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.play')\n }\n });\n\n button.appendChild(createIconElement('play'));\n\n button.addEventListener('click', () => {\n this.player.toggle();\n });\n\n this.controls.playPause = button;\n return button;\n }\n\n createRestartButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-restart`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.restart')\n }\n });\n\n button.appendChild(createIconElement('restart'));\n\n button.addEventListener('click', () => {\n this.player.seek(0);\n this.player.play();\n });\n\n return button;\n }\n\n createPreviousButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-previous`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.previous')\n }\n });\n\n button.appendChild(createIconElement('skipPrevious'));\n\n button.addEventListener('click', () => {\n if (this.player.playlistManager) {\n this.player.playlistManager.previous();\n }\n });\n\n // Update button state\n const updateState = () => {\n if (this.player.playlistManager) {\n button.disabled = !this.player.playlistManager.hasPrevious() && !this.player.playlistManager.options.loop;\n }\n };\n this.player.on('playlisttrackchange', updateState);\n updateState();\n\n this.controls.previous = button;\n return button;\n }\n\n createNextButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-next`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.next')\n }\n });\n\n button.appendChild(createIconElement('skipNext'));\n\n button.addEventListener('click', () => {\n if (this.player.playlistManager) {\n this.player.playlistManager.next();\n }\n });\n\n // Update button state\n const updateState = () => {\n if (this.player.playlistManager) {\n button.disabled = !this.player.playlistManager.hasNext() && !this.player.playlistManager.options.loop;\n }\n };\n this.player.on('playlisttrackchange', updateState);\n updateState();\n\n this.controls.next = button;\n return button;\n }\n\n createPlaylistToggleButton() {\n // Get unique panel ID from playlist manager\n const panelId = this.player.playlistManager ? `${this.player.playlistManager.uniqueId}-panel` : 'vidply-playlist-panel';\n \n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-playlist-toggle`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.playlist'),\n 'aria-expanded': 'false',\n 'aria-pressed': 'false',\n 'aria-controls': panelId\n }\n });\n\n button.appendChild(createIconElement('playlist'));\n\n button.addEventListener('click', () => {\n if (this.player.playlistManager) {\n this.player.playlistManager.togglePanel();\n }\n });\n\n this.controls.playlistToggle = button;\n return button;\n }\n\n createRewindButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-rewind`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.rewindSeconds', { seconds: 15 })\n }\n });\n\n button.appendChild(createIconElement('rewind'));\n\n button.addEventListener('click', () => {\n this.player.seekBackward(15);\n });\n\n return button;\n }\n\n createForwardButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-forward`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.forwardSeconds', { seconds: 15 })\n }\n });\n\n button.appendChild(createIconElement('forward'));\n\n button.addEventListener('click', () => {\n this.player.seekForward(15);\n });\n\n return button;\n }\n\n createMuteButton() {\n // Simple mute/unmute button for touch devices\n const muteButton = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-mute`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.mute')\n }\n });\n\n muteButton.appendChild(createIconElement('volumeHigh'));\n\n // Simply toggle mute on click/touch\n muteButton.addEventListener('click', () => {\n this.player.toggleMute();\n });\n\n this.controls.mute = muteButton;\n\n return muteButton;\n }\n\n createVolumeControl() {\n // Mute/Volume button with slider (desktop)\n const muteButton = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-mute`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.volume'),\n 'aria-expanded': 'false'\n }\n });\n\n muteButton.appendChild(createIconElement('volumeHigh'));\n\n // Toggle mute on right click, show volume slider on left click\n muteButton.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n this.player.toggleMute();\n });\n\n muteButton.addEventListener('click', () => {\n this.showVolumeSlider(muteButton);\n });\n\n this.controls.mute = muteButton;\n\n return muteButton;\n }\n\n showVolumeSlider(button) {\n // Remove existing slider if any\n const existingSlider = document.querySelector(`.${this.player.options.classPrefix}-volume-menu`);\n if (existingSlider) {\n existingSlider.remove();\n button.setAttribute('aria-expanded', 'false');\n return;\n }\n\n // Volume menu container\n const volumeMenu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-menu ${this.player.options.classPrefix}-menu`\n });\n\n const volumeSlider = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-slider`,\n attributes: {\n 'role': 'slider',\n 'aria-label': i18n.t('player.volume'),\n 'aria-valuemin': '0',\n 'aria-valuemax': '100',\n 'aria-valuenow': String(Math.round(this.player.state.volume * 100)),\n 'tabindex': '0'\n }\n });\n\n const volumeTrack = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-track`\n });\n\n const volumeFill = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-fill`\n });\n \n // Set initial fill height based on current volume\n const initialVolumePercent = this.player.state.volume * 100;\n volumeFill.style.height = `${initialVolumePercent}%`;\n\n const volumeHandle = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-handle`\n });\n\n volumeTrack.appendChild(volumeFill);\n volumeFill.appendChild(volumeHandle);\n volumeSlider.appendChild(volumeTrack);\n volumeMenu.appendChild(volumeSlider);\n\n // Volume slider events\n const updateVolume = (clientY) => {\n const rect = volumeTrack.getBoundingClientRect();\n const percent = Math.max(0, Math.min(1, 1 - ((clientY - rect.top) / rect.height)));\n this.player.setVolume(percent);\n };\n\n // Mouse events\n volumeSlider.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n this.isDraggingVolume = true;\n updateVolume(e.clientY);\n });\n\n document.addEventListener('mousemove', (e) => {\n if (this.isDraggingVolume) {\n updateVolume(e.clientY);\n }\n });\n\n document.addEventListener('mouseup', () => {\n this.isDraggingVolume = false;\n });\n\n // Touch events for iOS and mobile devices\n volumeSlider.addEventListener('touchstart', (e) => {\n e.stopPropagation();\n e.preventDefault();\n this.isDraggingVolume = true;\n const touch = e.touches[0];\n updateVolume(touch.clientY);\n }, { passive: false });\n\n volumeSlider.addEventListener('touchmove', (e) => {\n if (this.isDraggingVolume) {\n e.preventDefault();\n const touch = e.touches[0];\n updateVolume(touch.clientY);\n }\n }, { passive: false });\n\n volumeSlider.addEventListener('touchend', (e) => {\n e.stopPropagation();\n e.preventDefault();\n this.isDraggingVolume = false;\n }, { passive: false });\n\n volumeSlider.addEventListener('touchcancel', () => {\n this.isDraggingVolume = false;\n });\n\n // Keyboard volume control\n volumeSlider.addEventListener('keydown', (e) => {\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n this.player.setVolume(Math.min(1, this.player.state.volume + 0.1));\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n this.player.setVolume(Math.max(0, this.player.state.volume - 0.1));\n } else if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n // Close menu and return focus to button\n this.closeMenuAndReturnFocus(volumeMenu, button, true);\n }\n });\n\n // Prevent menu from closing when interacting with slider\n volumeMenu.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n \n // Prevent menu from closing on touch events\n volumeMenu.addEventListener('touchstart', (e) => {\n e.stopPropagation();\n });\n \n volumeMenu.addEventListener('touchmove', (e) => {\n e.stopPropagation();\n });\n \n volumeMenu.addEventListener('touchend', (e) => {\n e.stopPropagation();\n });\n\n // Position menu first (before it's visible) to prevent jumping\n volumeMenu.style.visibility = 'hidden';\n volumeMenu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(volumeMenu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(volumeMenu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n volumeMenu.style.visibility = 'visible';\n });\n\n this.controls.volumeSlider = volumeSlider;\n this.controls.volumeFill = volumeFill;\n\n // Focus the volume slider for keyboard accessibility\n focusElement(volumeSlider, { delay: 50 });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(volumeMenu, button, true);\n }\n\n createTimeDisplay() {\n const container = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-time`,\n attributes: {\n 'role': 'group',\n 'aria-label': i18n.t('time.display')\n }\n });\n\n // Current time - visual text hidden, accessible text provided via sr-only span\n this.controls.currentTimeDisplay = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-current-time`\n });\n \n // Create visual text inside, hidden from screen readers\n const currentTimeVisual = DOMUtils.createElement('span', {\n textContent: '00:00',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n const currentTimeAccessible = DOMUtils.createElement('span', {\n className: 'vidply-sr-only',\n textContent: i18n.t('time.seconds', { count: 0 })\n });\n\n this.controls.currentTimeDisplay.appendChild(currentTimeVisual);\n this.controls.currentTimeDisplay.appendChild(currentTimeAccessible);\n this.controls.currentTimeVisual = currentTimeVisual;\n this.controls.currentTimeAccessible = currentTimeAccessible;\n\n const separator = DOMUtils.createElement('span', {\n textContent: ' / ',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n\n // Duration - visual text hidden, accessible text provided via sr-only span\n this.controls.durationDisplay = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-duration`\n });\n \n // Create visual text inside, hidden from screen readers\n const durationVisual = DOMUtils.createElement('span', {\n textContent: '00:00',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n const durationAccessible = DOMUtils.createElement('span', {\n className: 'vidply-sr-only',\n textContent: i18n.t('time.durationPrefix') + i18n.t('time.seconds', { count: 0 })\n });\n\n this.controls.durationDisplay.appendChild(durationVisual);\n this.controls.durationDisplay.appendChild(durationAccessible);\n this.controls.durationVisual = durationVisual;\n this.controls.durationAccessible = durationAccessible;\n\n container.appendChild(this.controls.currentTimeDisplay);\n container.appendChild(separator);\n container.appendChild(this.controls.durationDisplay);\n\n return container;\n }\n\n createChaptersButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-chapters`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.chapters'),\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('chapters'));\n\n button.addEventListener('click', () => {\n this.showChaptersMenu(button);\n });\n\n this.controls.chapters = button;\n return button;\n }\n\n showChaptersMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-chapters-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-chapters-menu ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('player.chapters')\n }\n });\n\n // Get chapter tracks\n const chapterTracks = Array.from(this.player.element.textTracks).filter(\n track => track.kind === 'chapters'\n );\n\n if (chapterTracks.length === 0) {\n // No chapters available\n const noChaptersItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noChapters'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noChaptersItem);\n } else {\n const chapterTrack = chapterTracks[0];\n\n // Ensure track is in 'hidden' mode to load cues\n if (chapterTrack.mode === 'disabled') {\n chapterTrack.mode = 'hidden';\n }\n\n if (!chapterTrack.cues || chapterTrack.cues.length === 0) {\n // Cues not loaded yet - wait for them to load\n const loadingItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.loadingChapters'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(loadingItem);\n\n // Listen for track load event\n const onTrackLoad = () => {\n // Remove loading message and rebuild menu\n menu.remove();\n this.showChaptersMenu(button);\n };\n\n chapterTrack.addEventListener('load', onTrackLoad, {once: true});\n\n // Also try again after a short delay as fallback\n setTimeout(() => {\n if (chapterTrack.cues && chapterTrack.cues.length > 0 && document.contains(menu)) {\n menu.remove();\n this.showChaptersMenu(button);\n }\n }, 500);\n } else {\n // Display chapters\n const cues = chapterTrack.cues;\n for (let i = 0; i < cues.length; i++) {\n const cue = cues[i];\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n const timeLabel = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-chapter-time`,\n textContent: TimeUtils.formatTime(cue.startTime),\n attributes: {\n 'aria-label': TimeUtils.formatDuration(cue.startTime)\n }\n });\n\n const titleLabel = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-chapter-title`,\n textContent: cue.text\n });\n\n item.appendChild(timeLabel);\n item.appendChild(document.createTextNode(' '));\n item.appendChild(titleLabel);\n\n item.addEventListener('click', () => {\n this.player.seek(cue.startTime);\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n }\n \n // Add keyboard navigation\n this.attachMenuKeyboardNavigation(menu, button);\n \n // Focus first item\n setTimeout(() => {\n const firstItem = menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (firstItem) {\n firstItem.focus({ preventScroll: true });\n }\n }, 0);\n }\n }\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n }\n\n createQualityButton() {\n const ariaLabel = i18n.t('player.quality');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-quality`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('hd'));\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n // Add quality indicator text\n const qualityText = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-quality-text`,\n textContent: ''\n });\n button.appendChild(qualityText);\n\n button.addEventListener('click', () => {\n this.showQualityMenu(button);\n });\n\n this.controls.quality = button;\n this.controls.qualityText = qualityText;\n \n // Update quality indicator after a short delay to ensure renderer is ready\n setTimeout(() => this.updateQualityIndicator(), 500);\n \n return button;\n }\n\n showQualityMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-quality-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-quality-menu ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('player.quality')\n }\n });\n\n // Check if renderer supports quality selection\n if (this.player.renderer && this.player.renderer.getQualities) {\n const qualities = this.player.renderer.getQualities();\n const currentQuality = this.player.renderer.getCurrentQuality ? this.player.renderer.getCurrentQuality() : -1;\n const isHLS = this.player.renderer.hls !== undefined;\n\n if (qualities.length === 0) {\n // No qualities available\n const noQualityItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.autoQuality'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noQualityItem);\n } else {\n let activeItem = null;\n \n // Auto quality option (only for HLS)\n if (isHLS) {\n const autoItem = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.auto'),\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n // Check if auto is currently selected\n const isAuto = this.player.renderer.hls && this.player.renderer.hls.currentLevel === -1;\n if (isAuto) {\n autoItem.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n autoItem.appendChild(createIconElement('check'));\n activeItem = autoItem;\n }\n\n autoItem.addEventListener('click', () => {\n if (this.player.renderer.switchQuality) {\n this.player.renderer.switchQuality(-1); // -1 for auto\n }\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(autoItem);\n }\n\n // Quality options\n qualities.forEach(quality => {\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: quality.name || `${quality.height}p`,\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n // Highlight current quality\n if (quality.index === currentQuality) {\n item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n item.appendChild(createIconElement('check'));\n activeItem = item;\n }\n\n item.addEventListener('click', () => {\n if (this.player.renderer.switchQuality) {\n this.player.renderer.switchQuality(quality.index);\n }\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n });\n \n // Add keyboard navigation\n this.attachMenuKeyboardNavigation(menu, button);\n \n // Focus active item or first item\n setTimeout(() => {\n const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (focusTarget) {\n focusTarget.focus({ preventScroll: true });\n }\n }, 0);\n }\n } else {\n // No quality support\n const noSupportItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noQuality'),\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noSupportItem);\n }\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n }\n\n createCaptionStyleButton() {\n const ariaLabel = i18n.t('player.captionStyling');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-caption-style`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n });\n\n // Create \"Aa\" text icon for styling\n const textIcon = DOMUtils.createElement('span', {\n textContent: 'Aa',\n style: {\n fontSize: '14px',\n fontWeight: 'bold'\n }\n });\n button.appendChild(textIcon);\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n button.addEventListener('click', () => {\n this.showCaptionStyleMenu(button);\n });\n\n this.controls.captionStyle = button;\n return button;\n }\n\n showCaptionStyleMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-caption-style-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-caption-style-menu ${this.player.options.classPrefix}-menu ${this.player.options.classPrefix}-settings-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('player.captionStyling')\n }\n });\n\n // Prevent menu from closing when clicking inside\n menu.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n // Check if there are any caption tracks\n if (!this.player.captionManager || this.player.captionManager.tracks.length === 0) {\n // Show \"No captions available\" message\n const noTracksItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noCaptions'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default', padding: '12px 16px'}\n });\n menu.appendChild(noTracksItem);\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button, true);\n return;\n }\n\n // Font Size\n const fontSizeGroup = this.createStyleControl(\n i18n.t('styleLabels.fontSize'),\n 'captionsFontSize',\n [\n {label: i18n.t('fontSizes.small'), value: '87.5%'},\n {label: i18n.t('fontSizes.normal'), value: '100%'},\n {label: i18n.t('fontSizes.large'), value: '125%'},\n {label: i18n.t('fontSizes.xlarge'), value: '150%'}\n ]\n );\n menu.appendChild(fontSizeGroup);\n\n // Font Family\n const fontFamilyGroup = this.createStyleControl(\n i18n.t('styleLabels.font'),\n 'captionsFontFamily',\n [\n {label: i18n.t('fontFamilies.sansSerif'), value: 'sans-serif'},\n {label: i18n.t('fontFamilies.serif'), value: 'serif'},\n {label: i18n.t('fontFamilies.monospace'), value: 'monospace'}\n ]\n );\n menu.appendChild(fontFamilyGroup);\n\n // Text Color\n const colorGroup = this.createColorControl(i18n.t('styleLabels.textColor'), 'captionsColor');\n menu.appendChild(colorGroup);\n\n // Background Color\n const bgColorGroup = this.createColorControl(i18n.t('styleLabels.background'), 'captionsBackgroundColor');\n menu.appendChild(bgColorGroup);\n\n // Opacity\n const opacityGroup = this.createOpacityControl(i18n.t('styleLabels.opacity'), 'captionsOpacity');\n menu.appendChild(opacityGroup);\n\n // Set min-width for caption style menu\n menu.style.minWidth = '220px';\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click (but not when interacting with controls)\n this.attachMenuCloseHandler(menu, button, true);\n\n // Auto-focus the first style select element\n focusFirstElement(menu, `.${this.player.options.classPrefix}-style-select`);\n }\n\n createStyleControl(label, property, options) {\n const group = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-style-group`\n });\n\n // Generate unique ID for the control\n const controlId = `${this.player.options.classPrefix}-${property}-${Date.now()}`;\n\n const labelEl = DOMUtils.createElement('label', {\n textContent: label,\n attributes: {\n 'for': controlId\n },\n style: {\n display: 'block',\n fontSize: '12px',\n marginBottom: '4px',\n color: 'rgba(255,255,255,0.7)'\n }\n });\n group.appendChild(labelEl);\n\n const select = DOMUtils.createElement('select', {\n className: `${this.player.options.classPrefix}-style-select`,\n attributes: {\n 'id': controlId\n },\n style: {\n width: '100%',\n padding: '6px',\n background: 'var(--vidply-white)',\n border: '1px solid var(--vidply-white-10)',\n borderRadius: '4px',\n color: 'var(--vidply-black)',\n fontSize: '13px'\n }\n });\n\n const currentValue = this.player.options[property];\n options.forEach(opt => {\n const option = DOMUtils.createElement('option', {\n textContent: opt.label,\n attributes: {value: opt.value}\n });\n if (opt.value === currentValue) {\n option.selected = true;\n }\n select.appendChild(option);\n });\n\n // Prevent clicks from closing the menu\n select.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n });\n\n select.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n select.addEventListener('change', (e) => {\n e.stopPropagation();\n this.player.options[property] = e.target.value;\n if (this.player.captionManager) {\n this.player.captionManager.setCaptionStyle(\n property.replace('captions', '').charAt(0).toLowerCase() + property.replace('captions', '').slice(1),\n e.target.value\n );\n }\n });\n\n group.appendChild(select);\n return group;\n }\n\n createColorControl(label, property) {\n const group = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-style-group`\n });\n\n // Generate unique ID for the control\n const controlId = `${this.player.options.classPrefix}-${property}-${Date.now()}`;\n\n const labelEl = DOMUtils.createElement('label', {\n textContent: label,\n attributes: {\n 'for': controlId\n },\n style: {\n display: 'block',\n fontSize: '12px',\n marginBottom: '4px',\n color: 'rgba(255,255,255,0.7)'\n }\n });\n group.appendChild(labelEl);\n\n const input = DOMUtils.createElement('input', {\n attributes: {\n 'id': controlId,\n type: 'color',\n value: this.player.options[property]\n },\n style: {\n width: '100%',\n height: '32px',\n padding: '2px',\n background: 'rgba(255,255,255,0.1)',\n border: '1px solid rgba(255,255,255,0.2)',\n borderRadius: '4px',\n cursor: 'pointer'\n }\n });\n\n // Prevent clicks from closing the menu\n input.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n });\n\n input.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n input.addEventListener('change', (e) => {\n e.stopPropagation();\n this.player.options[property] = e.target.value;\n if (this.player.captionManager) {\n this.player.captionManager.setCaptionStyle(\n property.replace('captions', '').charAt(0).toLowerCase() + property.replace('captions', '').slice(1),\n e.target.value\n );\n }\n });\n\n group.appendChild(input);\n return group;\n }\n\n createOpacityControl(label, property) {\n const group = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-style-group`\n });\n\n // Generate unique ID for the control\n const controlId = `${this.player.options.classPrefix}-${property}-${Date.now()}`;\n\n const labelContainer = DOMUtils.createElement('div', {\n style: {\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: '4px'\n }\n });\n\n const labelEl = DOMUtils.createElement('label', {\n textContent: label,\n attributes: {\n 'for': controlId\n },\n style: {\n fontSize: '12px',\n color: 'rgba(255,255,255,0.7)'\n }\n });\n\n const valueEl = DOMUtils.createElement('span', {\n textContent: Math.round(this.player.options[property] * 100) + '%',\n style: {\n fontSize: '12px',\n color: 'rgba(255,255,255,0.7)'\n }\n });\n\n labelContainer.appendChild(labelEl);\n labelContainer.appendChild(valueEl);\n group.appendChild(labelContainer);\n\n const input = DOMUtils.createElement('input', {\n attributes: {\n 'id': controlId,\n type: 'range',\n min: '0',\n max: '1',\n step: '0.1',\n value: String(this.player.options[property])\n },\n style: {\n width: '100%',\n cursor: 'pointer'\n }\n });\n\n // Prevent clicks from closing the menu\n input.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n });\n\n input.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n input.addEventListener('input', (e) => {\n e.stopPropagation();\n const value = parseFloat(e.target.value);\n valueEl.textContent = Math.round(value * 100) + '%';\n this.player.options[property] = value;\n if (this.player.captionManager) {\n this.player.captionManager.setCaptionStyle(\n property.replace('captions', '').charAt(0).toLowerCase() + property.replace('captions', '').slice(1),\n value\n );\n }\n });\n\n group.appendChild(input);\n return group;\n }\n\n createSpeedButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-speed`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.speed'),\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('speed'));\n\n const speedText = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-speed-text`,\n textContent: '1x'\n });\n button.appendChild(speedText);\n\n button.addEventListener('click', () => {\n this.showSpeedMenu(button);\n });\n\n this.controls.speed = button;\n this.controls.speedText = speedText;\n return button;\n }\n\n formatSpeedLabel(speed) {\n // Special case: 1x is \"Normal\" (translated)\n if (speed === 1) {\n return i18n.t('speeds.normal');\n }\n \n // For other speeds, format with locale-specific decimal separator\n const speedStr = speed.toLocaleString(i18n.getLanguage(), {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2\n });\n \n return `${speedStr}×`;\n }\n\n showSpeedMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-speed-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-speed-menu ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu'\n }\n });\n\n const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n let activeItem = null;\n\n speeds.forEach(speed => {\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: this.formatSpeedLabel(speed),\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n if (speed === this.player.state.playbackSpeed) {\n item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n item.appendChild(createIconElement('check'));\n activeItem = item;\n }\n\n item.addEventListener('click', () => {\n this.player.setPlaybackSpeed(speed);\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n });\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Add keyboard navigation\n this.attachMenuKeyboardNavigation(menu, button);\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n\n // Focus the active item or first item\n setTimeout(() => {\n const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (focusTarget) {\n focusTarget.focus({ preventScroll: true });\n }\n }, 0);\n }\n\n createCaptionsButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-captions-button`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.captions'),\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('captionsOff'));\n\n button.addEventListener('click', () => {\n this.showCaptionsMenu(button);\n });\n\n this.controls.captions = button;\n return button;\n }\n\n showCaptionsMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-captions-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-captions-menu ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('captions.select')\n }\n });\n\n // Check if there are any caption tracks\n if (!this.player.captionManager || this.player.captionManager.tracks.length === 0) {\n // Show \"No captions available\" message\n const noTracksItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noCaptions'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noTracksItem);\n\n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n return;\n }\n\n let activeItem = null;\n\n // Off option\n const offItem = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('captions.off'),\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n if (!this.player.state.captionsEnabled) {\n offItem.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n offItem.appendChild(createIconElement('check'));\n activeItem = offItem;\n }\n\n offItem.addEventListener('click', () => {\n this.player.disableCaptions();\n this.updateCaptionsButton();\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(offItem);\n\n // Available tracks\n const tracks = this.player.captionManager.getAvailableTracks();\n tracks.forEach(track => {\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: track.label,\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'lang': track.language,\n 'tabindex': '-1'\n }\n });\n\n // Check if this is the current track\n if (this.player.state.captionsEnabled &&\n this.player.captionManager.currentTrack === this.player.captionManager.tracks[track.index]) {\n item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n item.appendChild(createIconElement('check'));\n activeItem = item;\n }\n\n item.addEventListener('click', () => {\n this.player.captionManager.switchTrack(track.index);\n this.updateCaptionsButton();\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n });\n\n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n\n // Add keyboard navigation for the menu\n this.attachMenuKeyboardNavigation(menu, button);\n\n // Close menu on outside click and Escape key\n this.attachMenuCloseHandler(menu, button);\n\n // Focus the active item or the first item\n setTimeout(() => {\n const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (focusTarget) {\n focusTarget.focus({ preventScroll: true });\n }\n }, 0);\n }\n\n updateCaptionsButton() {\n if (!this.controls.captions) return;\n\n const icon = this.controls.captions.querySelector('.vidply-icon');\n const isEnabled = this.player.state.captionsEnabled;\n\n icon.innerHTML = isEnabled ?\n createIconElement('captions').innerHTML :\n createIconElement('captionsOff').innerHTML;\n\n }\n\n createTranscriptButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-transcript`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.transcript'),\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('transcript'));\n\n button.addEventListener('click', async () => {\n await this.player.toggleTranscript();\n this.updateTranscriptButton();\n });\n\n this.controls.transcript = button;\n return button;\n }\n\n updateTranscriptButton() {\n if (!this.controls.transcript) return;\n\n const isVisible = this.player.transcriptManager && this.player.transcriptManager.isVisible;\n this.controls.transcript.setAttribute('aria-expanded', isVisible ? 'true' : 'false');\n }\n\n createAudioDescriptionButton() {\n const ariaLabel = i18n.t('player.audioDescription');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-audio-description`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'role': 'switch',\n 'aria-checked': 'false'\n }\n });\n\n button.appendChild(createIconElement('audioDescription'));\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n button.addEventListener('click', async () => {\n await this.player.toggleAudioDescription();\n this.updateAudioDescriptionButton();\n });\n\n this.controls.audioDescription = button;\n return button;\n }\n\n updateAudioDescriptionButton() {\n if (!this.controls.audioDescription) return;\n\n const icon = this.controls.audioDescription.querySelector('.vidply-icon');\n const isEnabled = this.player.state.audioDescriptionEnabled;\n\n icon.innerHTML = isEnabled ?\n createIconElement('audioDescriptionOn').innerHTML :\n createIconElement('audioDescription').innerHTML;\n\n this.controls.audioDescription.setAttribute('aria-checked', isEnabled ? 'true' : 'false');\n // Keep aria-label static - let aria-checked convey the state for switch role\n // The label describes what the control is, not what action it performs\n }\n\n createSignLanguageButton() {\n const ariaLabel = i18n.t('player.signLanguage');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-sign-language`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('signLanguage'));\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n button.addEventListener('click', () => {\n this.player.toggleSignLanguage();\n this.updateSignLanguageButton();\n });\n\n this.controls.signLanguage = button;\n return button;\n }\n\n updateSignLanguageButton() {\n if (!this.controls.signLanguage) return;\n\n const icon = this.controls.signLanguage.querySelector('.vidply-icon');\n const isEnabled = this.player.state.signLanguageEnabled;\n\n icon.innerHTML = isEnabled ?\n createIconElement('signLanguageOn').innerHTML :\n createIconElement('signLanguage').innerHTML;\n\n this.controls.signLanguage.setAttribute('aria-expanded', isEnabled ? 'true' : 'false');\n this.controls.signLanguage.setAttribute('aria-label',\n isEnabled ? i18n.t('signLanguage.hide') : i18n.t('signLanguage.show')\n );\n }\n\n /**\n * Update accessibility buttons visibility based on current track data.\n * Called when loading a new playlist track to show/hide buttons accordingly.\n */\n updateAccessibilityButtons() {\n const hasAudioDescription = this.hasAudioDescription();\n const hasSignLanguage = this.hasSignLanguage();\n \n // Handle Audio Description button\n if (hasAudioDescription) {\n // Create button if it doesn't exist\n if (!this.controls.audioDescription && this.player.options.audioDescriptionButton !== false) {\n const btn = this.createAudioDescriptionButton();\n btn.dataset.overflowPriority = '2';\n btn.dataset.overflowPriorityMobile = '3';\n // Insert before transcript or playlist toggle button\n const transcriptBtn = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-transcript`);\n const playlistBtn = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-playlist-toggle`);\n const insertBefore = transcriptBtn || playlistBtn || null;\n if (insertBefore) {\n this.rightButtons.insertBefore(btn, insertBefore);\n } else {\n this.rightButtons.appendChild(btn);\n }\n // Re-setup overflow menu after adding button\n this.setupOverflowMenu();\n }\n // Show button\n if (this.controls.audioDescription) {\n this.controls.audioDescription.style.display = '';\n }\n } else {\n // Hide button if no audio description available\n if (this.controls.audioDescription) {\n this.controls.audioDescription.style.display = 'none';\n }\n }\n \n // Handle Sign Language button\n if (hasSignLanguage) {\n // Create button if it doesn't exist\n if (!this.controls.signLanguage && this.player.options.signLanguageButton !== false) {\n const btn = this.createSignLanguageButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n // Insert before quality or fullscreen button\n const qualityBtn = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-quality`);\n const fullscreenBtn = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-fullscreen`);\n const insertBefore = qualityBtn || fullscreenBtn || null;\n if (insertBefore) {\n this.rightButtons.insertBefore(btn, insertBefore);\n } else {\n this.rightButtons.appendChild(btn);\n }\n // Re-setup overflow menu after adding button\n this.setupOverflowMenu();\n }\n // Show button\n if (this.controls.signLanguage) {\n this.controls.signLanguage.style.display = '';\n }\n } else {\n // Hide button if no sign language available\n if (this.controls.signLanguage) {\n this.controls.signLanguage.style.display = 'none';\n }\n }\n }\n\n createSettingsButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-settings`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.settings')\n }\n });\n\n button.appendChild(createIconElement('settings'));\n\n button.addEventListener('click', () => {\n this.player.showSettings();\n });\n\n return button;\n }\n\n createPipButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-pip`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.pip')\n }\n });\n\n button.appendChild(createIconElement('pip'));\n\n button.addEventListener('click', () => {\n this.player.togglePiP();\n });\n\n return button;\n }\n\n createFullscreenButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-fullscreen`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.fullscreen')\n }\n });\n\n button.appendChild(createIconElement('fullscreen'));\n\n button.addEventListener('click', () => {\n this.player.toggleFullscreen();\n });\n\n this.controls.fullscreen = button;\n return button;\n }\n\n attachEvents() {\n // Update controls based on player state\n this.player.on('play', () => this.updatePlayPauseButton());\n this.player.on('pause', () => this.updatePlayPauseButton());\n this.player.on('timeupdate', () => this.updateProgress());\n this.player.on('loadedmetadata', () => {\n this.updateDuration();\n this.ensureQualityButton();\n this.updateQualityIndicator();\n });\n this.player.on('volumechange', () => this.updateVolumeDisplay());\n this.player.on('progress', () => this.updateBuffered());\n this.player.on('playbackspeedchange', () => this.updateSpeedDisplay());\n this.player.on('fullscreenchange', () => this.updateFullscreenButton());\n this.player.on('captionsenabled', () => this.updateCaptionsButton());\n this.player.on('captionsdisabled', () => this.updateCaptionsButton());\n this.player.on('audiodescriptionenabled', () => this.updateAudioDescriptionButton());\n this.player.on('audiodescriptiondisabled', () => this.updateAudioDescriptionButton());\n this.player.on('signlanguageenabled', () => this.updateSignLanguageButton());\n this.player.on('signlanguagedisabled', () => this.updateSignLanguageButton());\n this.player.on('qualitychange', () => this.updateQualityIndicator());\n this.player.on('hlslevelswitched', () => this.updateQualityIndicator());\n this.player.on('hlsmanifestparsed', () => {\n this.ensureQualityButton();\n this.updateQualityIndicator();\n });\n }\n\n updatePlayPauseButton() {\n if (!this.controls.playPause) return;\n\n const icon = this.controls.playPause.querySelector('.vidply-icon');\n const isPlaying = this.player.state.playing;\n\n icon.innerHTML = isPlaying ?\n createIconElement('pause').innerHTML :\n createIconElement('play').innerHTML;\n\n const newAriaLabel = isPlaying ? i18n.t('player.pause') : i18n.t('player.play');\n this.controls.playPause.setAttribute('aria-label', newAriaLabel);\n // Update tooltip to match aria-label\n DOMUtils.attachTooltip(this.controls.playPause, newAriaLabel, this.player.options.classPrefix);\n }\n\n updateProgress() {\n if (!this.controls.played) return;\n\n const currentTime = this.player.state.currentTime || 0;\n const duration = this.player.state.duration || 0;\n \n // Guard against division by zero and ensure valid percentage\n const percent = duration > 0 ? Math.min(100, Math.max(0, (currentTime / duration) * 100)) : 0;\n \n this.controls.played.style.width = `${percent}%`;\n this.controls.progress.setAttribute('aria-valuenow', String(Math.round(percent)));\n \n // Set aria-valuetext to announce both percentage and time for screen readers\n const currentTimeText = TimeUtils.formatDuration(this.player.state.currentTime);\n const durationText = TimeUtils.formatDuration(this.player.state.duration);\n this.controls.progress.setAttribute('aria-valuetext', \n `${Math.round(percent)}%, ${currentTimeText} ${i18n.t('time.of')} ${durationText}`);\n\n if (this.controls.currentTimeVisual) {\n const currentTime = this.player.state.currentTime;\n // Update visual text (hidden from screen readers)\n this.controls.currentTimeVisual.textContent = TimeUtils.formatTime(currentTime);\n if (this.controls.currentTimeAccessible) {\n this.controls.currentTimeAccessible.textContent = TimeUtils.formatDuration(currentTime);\n }\n }\n }\n\n updateDuration() {\n if (this.controls.durationVisual) {\n const duration = this.player.state.duration;\n // Update visual text (hidden from screen readers)\n this.controls.durationVisual.textContent = TimeUtils.formatTime(duration);\n if (this.controls.durationAccessible) {\n this.controls.durationAccessible.textContent = i18n.t('time.durationPrefix') + TimeUtils.formatDuration(duration);\n }\n }\n }\n\n updateVolumeDisplay() {\n const percent = this.player.state.volume * 100;\n\n // Update volume fill bar if it exists\n if (this.controls.volumeFill) {\n this.controls.volumeFill.style.height = `${percent}%`;\n }\n \n // Update volume slider aria-valuenow if it exists\n if (this.controls.volumeSlider) {\n this.controls.volumeSlider.setAttribute('aria-valuenow', String(Math.round(percent)));\n }\n\n // Update mute button icon (should always work even if slider not shown)\n if (this.controls.mute) {\n const icon = this.controls.mute.querySelector('.vidply-icon');\n if (icon) {\n let iconName;\n\n if (this.player.state.muted || this.player.state.volume === 0) {\n iconName = 'volumeMuted';\n } else if (this.player.state.volume < 0.3) {\n iconName = 'volumeLow';\n } else if (this.player.state.volume < 0.7) {\n iconName = 'volumeMedium';\n } else {\n iconName = 'volumeHigh';\n }\n\n icon.innerHTML = createIconElement(iconName).innerHTML;\n\n const newMuteAriaLabel =\n this.player.state.muted ? i18n.t('player.unmute') : i18n.t('player.mute');\n this.controls.mute.setAttribute('aria-label', newMuteAriaLabel);\n // Update tooltip to match aria-label\n DOMUtils.attachTooltip(this.controls.mute, newMuteAriaLabel, this.player.options.classPrefix);\n }\n }\n\n // Update volume slider attribute if it exists\n if (this.controls.volumeSlider) {\n this.controls.volumeSlider.setAttribute('aria-valuenow', String(Math.round(percent)));\n }\n }\n\n updateBuffered() {\n if (!this.controls.buffered || !this.player.element.buffered || this.player.element.buffered.length === 0) return;\n\n const buffered = this.player.element.buffered.end(this.player.element.buffered.length - 1);\n const percent = (buffered / this.player.state.duration) * 100;\n this.controls.buffered.style.width = `${percent}%`;\n }\n\n updateSpeedDisplay() {\n if (this.controls.speedText) {\n this.controls.speedText.textContent = `${this.player.state.playbackSpeed}x`;\n }\n }\n\n updateFullscreenButton() {\n if (!this.controls.fullscreen) return;\n\n const icon = this.controls.fullscreen.querySelector('.vidply-icon');\n const isFullscreen = this.player.state.fullscreen;\n\n icon.innerHTML = isFullscreen ?\n createIconElement('fullscreenExit').innerHTML :\n createIconElement('fullscreen').innerHTML;\n\n this.controls.fullscreen.setAttribute('aria-label',\n isFullscreen ? i18n.t('player.exitFullscreen') : i18n.t('player.fullscreen')\n );\n }\n\n /**\n * Ensure quality button exists if qualities are available\n * This is called after renderer initialization to dynamically add the button\n */\n ensureQualityButton() {\n // Skip if quality button is disabled\n if (!this.player.options.qualityButton) return;\n \n // Skip if button already exists\n if (this.controls.quality) return;\n \n // Check if qualities are now available\n if (!this.hasQualityLevels()) return;\n \n // Create and insert the quality button before the speed button\n const qualityButton = this.createQualityButton();\n \n // Find the speed button or caption style button to insert before\n const speedButton = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-speed`);\n const captionStyleButton = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-caption-style`);\n const insertBefore = captionStyleButton || speedButton;\n \n if (insertBefore) {\n this.rightButtons.insertBefore(qualityButton, insertBefore);\n } else {\n // If no reference button, add it at the beginning of right buttons\n this.rightButtons.insertBefore(qualityButton, this.rightButtons.firstChild);\n }\n \n this.player.log('Quality button added dynamically', 'info');\n }\n\n updateQualityIndicator() {\n if (!this.controls.qualityText) return;\n if (!this.player.renderer || !this.player.renderer.getQualities) return;\n\n const qualities = this.player.renderer.getQualities();\n if (qualities.length === 0) {\n this.controls.qualityText.textContent = '';\n return;\n }\n\n // Get current quality\n let currentQualityText = '';\n \n // Check if it's HLS with auto mode\n if (this.player.renderer.hls && this.player.renderer.hls.currentLevel === -1) {\n currentQualityText = 'Auto';\n } else if (this.player.renderer.getCurrentQuality) {\n const currentIndex = this.player.renderer.getCurrentQuality();\n const currentQuality = qualities.find(q => q.index === currentIndex);\n if (currentQuality) {\n currentQualityText = currentQuality.height ? `${currentQuality.height}p` : '';\n }\n }\n\n this.controls.qualityText.textContent = currentQualityText;\n }\n\n setupAutoHide() {\n if (this.player.element.tagName !== 'VIDEO') return;\n\n const showControls = () => {\n this.element.classList.add(`${this.player.options.classPrefix}-controls-visible`);\n this.player.container.classList.add(`${this.player.options.classPrefix}-controls-visible`);\n this.player.state.controlsVisible = true;\n\n clearTimeout(this.hideTimeout);\n\n if (this.player.state.playing) {\n // Use longer delay in fullscreen mode for better mobile UX\n const delay = this.player.state.fullscreen \n ? this.player.options.hideControlsDelay * 1.5 \n : this.player.options.hideControlsDelay;\n \n this.hideTimeout = setTimeout(() => {\n this.element.classList.remove(`${this.player.options.classPrefix}-controls-visible`);\n this.player.container.classList.remove(`${this.player.options.classPrefix}-controls-visible`);\n this.player.state.controlsVisible = false;\n }, delay);\n }\n };\n\n // Mouse and touch events to show controls\n this.player.container.addEventListener('mousemove', showControls);\n this.player.container.addEventListener('touchstart', showControls);\n this.player.container.addEventListener('touchmove', showControls); // Also show on touch drag/swipe\n this.player.container.addEventListener('click', showControls);\n this.player.container.addEventListener('tap', showControls); // Some mobile browsers use tap event\n\n // Show controls on focus\n this.element.addEventListener('focusin', showControls);\n\n // Always show when paused\n this.player.on('pause', () => {\n showControls();\n clearTimeout(this.hideTimeout);\n });\n\n this.player.on('play', () => {\n showControls();\n });\n\n // Show controls when entering fullscreen (especially important for mobile landscape)\n this.player.on('enterfullscreen', () => {\n showControls();\n // In fullscreen, keep controls visible longer initially\n if (this.player.state.fullscreen) {\n clearTimeout(this.hideTimeout);\n this.hideTimeout = setTimeout(() => {\n if (this.player.state.playing) {\n this.element.classList.remove(`${this.player.options.classPrefix}-controls-visible`);\n this.player.container.classList.remove(`${this.player.options.classPrefix}-controls-visible`);\n this.player.state.controlsVisible = false;\n }\n }, this.player.options.hideControlsDelay * 2); // Double the delay in fullscreen\n }\n });\n\n // Initial state\n showControls();\n }\n\n createOverflowMenuButton() {\n const ariaLabel = i18n.t('player.moreOptions');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-overflow-menu`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('moreVertical'));\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n button.addEventListener('click', () => {\n this.showOverflowMenu(button);\n });\n\n this.controls.overflowMenu = button;\n return button;\n }\n\n showOverflowMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-overflow-menu-list`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-overflow-menu-list ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('player.moreOptions')\n }\n });\n\n // Get all overflow buttons (those currently hidden)\n const overflowButtons = Array.from(this.rightButtons.querySelectorAll('button[data-in-overflow=\"true\"]'));\n\n if (overflowButtons.length === 0) {\n // No overflow items\n const noItemsText = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noMoreOptions'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noItemsText);\n } else {\n // Create menu items for each overflow button\n overflowButtons.forEach(btn => {\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n // Get button label\n const label = btn.getAttribute('aria-label') || btn.getAttribute('title') || '';\n \n // Copy icon if present (SVG icon or text icon like \"Aa\")\n const icon = btn.querySelector('.vidply-icon');\n if (icon) {\n const iconClone = icon.cloneNode(true);\n item.appendChild(iconClone);\n } else {\n // Check for text icon (like caption styling \"Aa\")\n const firstChild = btn.querySelector('span');\n if (firstChild && firstChild.textContent && firstChild.textContent.length <= 3) {\n const iconClone = firstChild.cloneNode(true);\n iconClone.classList.add('vidply-icon'); // Add icon class for consistent styling\n item.appendChild(iconClone);\n }\n }\n \n const labelSpan = DOMUtils.createElement('span', {\n textContent: label\n });\n item.appendChild(labelSpan);\n\n // When clicked, trigger the original button's click\n item.addEventListener('click', (e) => {\n // Store the overflow menu item as the positioning reference\n // This allows submenus to position relative to the visible menu item\n this._overflowMenuItemRef = item;\n \n // Temporarily make the original button visible for positioning\n const originalDisplay = btn.style.display;\n btn.style.display = '';\n btn.style.visibility = 'hidden'; // Keep it invisible but in layout\n \n // Trigger the button's menu\n btn.click();\n \n // Restore original state after menu is positioned\n setTimeout(() => {\n btn.style.display = originalDisplay;\n btn.style.visibility = '';\n this._overflowMenuItemRef = null;\n }, 100);\n \n // Close overflow menu\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n });\n\n // Add keyboard navigation\n this.attachMenuKeyboardNavigation(menu, button);\n\n // Focus first item\n setTimeout(() => {\n const firstItem = menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (firstItem && firstItem.tagName === 'BUTTON') {\n firstItem.focus({ preventScroll: true });\n }\n }, 0);\n }\n\n // Position menu first (before it's visible) to prevent jumping\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n }\n\n setupOverflowDetection() {\n // Check for overflow after layout is stable\n const checkOverflow = () => {\n // Check screen size and orientation\n const isDesktop = window.innerWidth >= 768;\n const isLandscape = window.innerHeight < window.innerWidth;\n const isFullscreen = this.player.state.fullscreen;\n const isLandscapeFullscreen = isLandscape && isFullscreen;\n \n if (!this.rightButtons || this.rightButtons.children.length === 0) {\n // Hide overflow button if no buttons exist\n if (this.overflowMenuButton) {\n this.overflowMenuButton.style.display = 'none';\n }\n return;\n }\n\n // Get all buttons (except the overflow menu button itself)\n const allButtons = Array.from(this.rightButtons.children).filter(\n btn => !btn.classList.contains(`${this.player.options.classPrefix}-overflow-menu`)\n );\n\n if (allButtons.length === 0) {\n // Hide overflow button if no buttons exist\n if (this.overflowMenuButton) {\n this.overflowMenuButton.style.display = 'none';\n }\n return;\n }\n\n // Determine if we should use overflow menu\n // Only use overflow on mobile portrait (width < 768px and not in landscape)\n // In landscape mode, always show all buttons (even on mobile) to ensure fullscreen button is accessible\n const shouldUseOverflow = !isDesktop && !isLandscape;\n \n if (this.player.options.debug) {\n console.log('Overflow detection:', {\n isDesktop,\n isFullscreen,\n isLandscape,\n isLandscapeFullscreen,\n shouldUseOverflow,\n width: window.innerWidth,\n height: window.innerHeight\n });\n }\n\n // If we shouldn't use overflow menu, show all buttons and hide overflow button\n if (!shouldUseOverflow) {\n allButtons.forEach(btn => {\n btn.dataset.inOverflow = 'false';\n btn.style.display = '';\n });\n // Always hide overflow menu button\n if (this.overflowMenuButton) {\n this.overflowMenuButton.style.display = 'none';\n }\n if (this.player.options.debug) {\n console.log('No overflow menu needed - all buttons visible, overflow button hidden');\n }\n return;\n }\n \n // Continue with overflow detection for mobile portrait only\n if (this.player.options.debug) {\n console.log('Mobile portrait - checking for overflow...');\n }\n\n // First, make all buttons visible to measure their actual widths\n allButtons.forEach(btn => {\n btn.style.display = '';\n });\n\n // Get available width\n const containerWidth = this.rightButtons.offsetWidth;\n const overflowButtonWidth = 50; // Reserve space for overflow button + gap\n const availableWidth = containerWidth - overflowButtonWidth;\n\n // Calculate total width needed for all buttons including gaps\n let totalWidth = 0;\n const buttonWidths = allButtons.map(btn => {\n const style = getComputedStyle(btn);\n const width = btn.offsetWidth + \n parseInt(style.marginLeft || 0) + \n parseInt(style.marginRight || 0);\n totalWidth += width;\n return {btn, width};\n });\n\n // Add gap widths (8px per gap between buttons)\n const gapWidth = 8;\n totalWidth += (allButtons.length - 1) * gapWidth;\n\n // Check if overflow is needed\n const isSmallScreen = window.innerWidth < 768;\n const needsOverflow = totalWidth > availableWidth || isSmallScreen || (isLandscapeFullscreen && !isDesktop); // Always overflow on mobile and mobile landscape fullscreen\n\n // Debug logging\n if (this.player.options.debug) {\n console.log('Overflow detection:', {\n containerWidth,\n availableWidth,\n totalWidth,\n needsOverflow,\n isSmallScreen,\n reason: isSmallScreen ? 'mobile screen' : (totalWidth > availableWidth ? 'not enough space' : 'enough space'),\n buttonCount: allButtons.length\n });\n }\n\n if (needsOverflow) {\n // Use responsive priorities based on screen size\n const isSmallScreen = window.innerWidth < 768;\n const priorityAttr = isSmallScreen ? 'overflowPriorityMobile' : 'overflowPriority';\n \n if (this.player.options.debug) {\n console.log(`Using ${isSmallScreen ? 'mobile' : 'desktop'} priorities (width: ${window.innerWidth}px)`);\n }\n \n // Sort buttons by priority (highest priority last)\n const sortedButtons = buttonWidths.sort((a, b) => {\n const priorityA = parseInt(a.btn.dataset[priorityAttr] || a.btn.dataset.overflowPriority || '1');\n const priorityB = parseInt(b.btn.dataset[priorityAttr] || b.btn.dataset.overflowPriority || '1');\n return priorityB - priorityA; // Higher priority = lower number = later in array\n });\n\n // Hide buttons starting with lowest priority until fits\n let currentWidth = totalWidth;\n let movedToOverflow = 0;\n\n for (const {btn, width} of sortedButtons) {\n const priority = parseInt(btn.dataset[priorityAttr] || btn.dataset.overflowPriority || '1');\n const buttonLabel = btn.getAttribute('aria-label') || 'unknown';\n \n // Never hide priority 1 buttons\n if (priority === 1) {\n btn.dataset.inOverflow = 'false';\n btn.style.display = '';\n continue;\n }\n\n // On mobile, hide all non-priority-1 buttons (priority 2 and 3)\n // On desktop, only hide if not enough space\n const shouldHide = isSmallScreen ? (priority > 1) : (currentWidth > availableWidth);\n\n if (shouldHide) {\n // Move to overflow\n btn.dataset.inOverflow = 'true';\n btn.style.display = 'none';\n currentWidth -= width;\n movedToOverflow++;\n if (this.player.options.debug) {\n console.log(` → Hiding button: ${buttonLabel} (priority ${priority}, ${isSmallScreen ? 'mobile' : 'desktop'})`);\n }\n } else {\n // Keep visible\n btn.dataset.inOverflow = 'false';\n btn.style.display = '';\n }\n }\n\n // Show overflow menu button if we moved any buttons\n if (this.player.options.debug) {\n console.log('Overflow button exists?', !!this.overflowMenuButton);\n }\n \n if (!this.overflowMenuButton) {\n console.error('Overflow menu button not found!');\n return;\n }\n \n if (movedToOverflow > 0) {\n this.overflowMenuButton.style.display = '';\n if (this.player.options.debug) {\n console.log('Showing overflow menu button -', movedToOverflow, 'buttons moved');\n }\n } else {\n this.overflowMenuButton.style.display = 'none';\n if (this.player.options.debug) {\n console.log('Hiding overflow menu button - all buttons fit');\n }\n }\n } else {\n // No overflow needed - show all buttons\n allButtons.forEach(btn => {\n btn.dataset.inOverflow = 'false';\n btn.style.display = '';\n });\n this.overflowMenuButton.style.display = 'none';\n }\n };\n\n // Check on resize\n const resizeObserver = new ResizeObserver(() => {\n requestAnimationFrame(checkOverflow);\n });\n resizeObserver.observe(this.rightButtons);\n\n // Check on window resize\n window.addEventListener('resize', () => {\n requestAnimationFrame(checkOverflow);\n });\n\n // Check on fullscreen changes (important for desktop/tablet fullscreen)\n this.player.on('fullscreenchange', () => {\n // Use setTimeout to ensure fullscreen state is fully updated\n setTimeout(() => {\n requestAnimationFrame(checkOverflow);\n }, 50);\n });\n\n // Initial checks at multiple intervals to ensure layout is stable\n // Some browsers need more time for font loading, CSS rendering, etc.\n requestAnimationFrame(() => {\n checkOverflow();\n setTimeout(() => checkOverflow(), 100);\n setTimeout(() => checkOverflow(), 300);\n setTimeout(() => checkOverflow(), 500);\n });\n\n // Also check when fonts are loaded\n if (document.fonts && document.fonts.ready) {\n document.fonts.ready.then(() => {\n requestAnimationFrame(checkOverflow);\n });\n }\n\n // Store for cleanup\n this.overflowResizeObserver = resizeObserver;\n }\n\n show() {\n this.element.style.display = '';\n }\n\n hide() {\n this.element.style.display = 'none';\n }\n\n destroy() {\n if (this.hideTimeout) {\n clearTimeout(this.hideTimeout);\n }\n\n if (this.overflowResizeObserver) {\n this.overflowResizeObserver.disconnect();\n }\n\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n }\n}\n\n", "/**\r\n * Performance Utilities\r\n */\r\n\r\n/**\r\n * Debounce function - limits how often a function can be called\r\n * @param {Function} func - Function to debounce\r\n * @param {number} wait - Wait time in milliseconds\r\n * @returns {Function} Debounced function\r\n */\r\nexport function debounce(func, wait = 100) {\r\n let timeout;\r\n return function executedFunction(...args) {\r\n const later = () => {\r\n clearTimeout(timeout);\r\n func(...args);\r\n };\r\n clearTimeout(timeout);\r\n timeout = setTimeout(later, wait);\r\n };\r\n}\r\n\r\n/**\r\n * Throttle function - ensures function is called at most once per interval\r\n * @param {Function} func - Function to throttle\r\n * @param {number} limit - Time limit in milliseconds\r\n * @returns {Function} Throttled function\r\n */\r\nexport function throttle(func, limit = 100) {\r\n let inThrottle;\r\n return function executedFunction(...args) {\r\n if (!inThrottle) {\r\n func(...args);\r\n inThrottle = true;\r\n setTimeout(() => inThrottle = false, limit);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Check if current viewport is mobile size\r\n * @param {number} breakpoint - Mobile breakpoint in pixels (default 768)\r\n * @returns {boolean} True if mobile\r\n */\r\nexport function isMobile(breakpoint = 768) {\r\n return window.innerWidth < breakpoint;\r\n}\r\n\r\n/**\r\n * Request animation frame with timeout fallback\r\n * @param {Function} callback - Function to call\r\n * @param {number} timeout - Timeout in ms (default 100)\r\n */\r\nexport function rafWithTimeout(callback, timeout = 100) {\r\n let called = false;\r\n \r\n const execute = () => {\r\n if (!called) {\r\n called = true;\r\n callback();\r\n }\r\n };\r\n \r\n requestAnimationFrame(execute);\r\n setTimeout(execute, timeout);\r\n}\r\n\r\n", "/**\n * Caption/Subtitle Manager\n */\n\nimport {DOMUtils} from '../utils/DOMUtils.js';\nimport {i18n} from '../i18n/i18n.js';\nimport {StorageManager} from '../utils/StorageManager.js';\nimport {debounce, isMobile, rafWithTimeout} from '../utils/PerformanceUtils.js';\n\nexport class CaptionManager {\n constructor(player) {\n this.player = player;\n this.element = null;\n this.tracks = [];\n this.currentTrack = null;\n this.currentCue = null;\n \n // Storage manager\n this.storage = new StorageManager('vidply');\n \n // Load saved preferences\n this.loadSavedPreferences();\n\n this.init();\n }\n \n loadSavedPreferences() {\n const saved = this.storage.getCaptionPreferences();\n if (saved) {\n // Override player options with saved preferences\n if (saved.fontSize) this.player.options.captionsFontSize = saved.fontSize;\n if (saved.fontFamily) this.player.options.captionsFontFamily = saved.fontFamily;\n if (saved.color) this.player.options.captionsColor = saved.color;\n if (saved.backgroundColor) this.player.options.captionsBackgroundColor = saved.backgroundColor;\n if (saved.opacity !== undefined) this.player.options.captionsOpacity = saved.opacity;\n }\n }\n \n saveCaptionPreferences() {\n this.storage.saveCaptionPreferences({\n fontSize: this.player.options.captionsFontSize,\n fontFamily: this.player.options.captionsFontFamily,\n color: this.player.options.captionsColor,\n backgroundColor: this.player.options.captionsBackgroundColor,\n opacity: this.player.options.captionsOpacity\n });\n }\n\n init() {\n this.createElement();\n this.loadTracks();\n this.attachEvents();\n\n // Only enable captions via captionsDefault option if no default track was found\n // (loadTracks() already enables tracks with the default attribute)\n if (this.player.options.captionsDefault && this.tracks.length > 0 && !this.currentTrack) {\n this.enable();\n }\n }\n\n createElement() {\n this.element = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-captions`,\n attributes: {\n 'role': 'region',\n 'aria-label': i18n.t('player.captions')\n }\n });\n\n // Apply caption styles\n this.updateStyles();\n\n // Append to videoWrapper if it exists, otherwise to container\n const target = this.player.videoWrapper || this.player.container;\n target.appendChild(this.element);\n }\n\n loadTracks() {\n const textTracks = this.player.element.textTracks;\n let defaultTrackIndex = -1;\n\n for (let i = 0; i < textTracks.length; i++) {\n const track = textTracks[i];\n\n if (track.kind === 'subtitles' || track.kind === 'captions') {\n // Check if this track has the default attribute\n const trackElement = this.player.findTrackElement(track);\n const isDefault = trackElement && trackElement.hasAttribute('default');\n \n this.tracks.push({\n track: track,\n language: track.language,\n label: track.label,\n kind: track.kind,\n index: i,\n isDefault: isDefault\n });\n\n // Set all tracks to 'hidden' mode (not 'disabled' or 'showing')\n // 'hidden' mode loads cues and fires events, but doesn't show native captions\n // This is important even for default tracks - we want custom caption display\n if (track.mode === 'showing') {\n // If browser set it to 'showing' (e.g., for default tracks), change to 'hidden'\n track.mode = 'hidden';\n } else if (track.mode === 'disabled') {\n // If disabled, set to 'hidden' to load cues\n track.mode = 'hidden';\n } else {\n // Ensure it's 'hidden' (might already be, but be explicit)\n track.mode = 'hidden';\n }\n \n if (isDefault) {\n defaultTrackIndex = this.tracks.length - 1;\n }\n }\n }\n \n // If a default track was found, enable it\n // Use a small delay to ensure tracks are ready\n if (defaultTrackIndex >= 0) {\n requestAnimationFrame(() => {\n this.enable(defaultTrackIndex);\n });\n }\n }\n\n attachEvents() {\n this.player.on('timeupdate', () => {\n this.updateCaptions();\n });\n\n this.player.on('captionschange', () => {\n this.updateStyles();\n });\n \n // Debounced resize handler to avoid excessive recalculations\n this.debouncedPositionCaptions = debounce(() => {\n this.positionCaptionsOnMobile();\n }, 150);\n \n window.addEventListener('resize', this.debouncedPositionCaptions);\n \n // Recalculate on fullscreen change with RAF\n this.player.on('enterfullscreen', () => {\n rafWithTimeout(() => this.positionCaptionsOnMobile(), 100);\n });\n \n this.player.on('exitfullscreen', () => {\n rafWithTimeout(() => this.positionCaptionsOnMobile(), 100);\n });\n }\n\n enable(trackIndex = 0) {\n if (this.tracks.length === 0) {\n return;\n }\n\n // Disable current track\n if (this.currentTrack && this.currentTrack.track) {\n // Remove cuechange listener from old track\n if (this.cueChangeHandler) {\n this.currentTrack.track.removeEventListener('cuechange', this.cueChangeHandler);\n }\n this.currentTrack.track.mode = 'hidden';\n }\n\n // Enable selected track\n const selectedTrack = this.tracks[trackIndex];\n\n if (selectedTrack && selectedTrack.track) {\n // Set to 'hidden' not 'showing' to prevent browser from displaying native captions\n // We'll handle the display ourselves\n // But we need to set mode to 'hidden' to load cues\n selectedTrack.track.mode = 'hidden';\n this.currentTrack = selectedTrack;\n this.player.state.captionsEnabled = true;\n \n // Set lang attribute for screen readers to pronounce text correctly\n if (selectedTrack.language) {\n this.element.setAttribute('lang', selectedTrack.language);\n }\n\n // Remove any existing cuechange listener from this track\n if (this.cueChangeHandler) {\n selectedTrack.track.removeEventListener('cuechange', this.cueChangeHandler);\n }\n\n // Add event listener for cue changes\n this.cueChangeHandler = () => {\n this.updateCaptions();\n };\n selectedTrack.track.addEventListener('cuechange', this.cueChangeHandler);\n\n // Force track to load if it's not already loaded\n // If track is not ready, wait for it to load\n const ensureTrackReady = () => {\n if (selectedTrack.track.readyState < 2) {\n // Track not loaded yet, wait for load event\n const onTrackLoad = () => {\n selectedTrack.track.removeEventListener('load', onTrackLoad);\n selectedTrack.track.removeEventListener('error', onTrackLoad);\n // Force initial update after track loads\n requestAnimationFrame(() => {\n if (this.currentTrack && this.currentTrack.track === selectedTrack.track) {\n this.updateCaptions();\n }\n });\n };\n selectedTrack.track.addEventListener('load', onTrackLoad, { once: true });\n selectedTrack.track.addEventListener('error', onTrackLoad, { once: true });\n } else {\n // Track already loaded, force initial update\n requestAnimationFrame(() => {\n if (this.currentTrack && this.currentTrack.track === selectedTrack.track) {\n this.updateCaptions();\n }\n });\n }\n };\n\n // Use requestAnimationFrame to ensure track is ready\n requestAnimationFrame(() => {\n if (this.currentTrack && this.currentTrack.track === selectedTrack.track) {\n ensureTrackReady();\n }\n });\n\n this.player.emit('captionsenabled', selectedTrack);\n }\n }\n\n disable() {\n if (this.currentTrack) {\n this.currentTrack.track.mode = 'hidden';\n this.currentTrack = null;\n }\n\n this.element.style.display = 'none';\n this.element.innerHTML = '';\n this.element.removeAttribute('lang');\n this.currentCue = null;\n this.player.state.captionsEnabled = false;\n this.player.emit('captionsdisabled');\n }\n\n updateCaptions() {\n if (!this.currentTrack || !this.currentTrack.track) {\n return;\n }\n\n // Ensure track mode is set to 'hidden' (not 'disabled') to receive cue updates\n // 'hidden' mode loads cues and fires cuechange events, but doesn't show native captions\n // If track is 'disabled', it won't have activeCues or fire events\n if (this.currentTrack.track.mode === 'disabled') {\n this.currentTrack.track.mode = 'hidden';\n }\n\n // Ensure track is in 'hidden' mode (not 'showing') for custom caption display\n if (this.currentTrack.track.mode === 'showing') {\n this.currentTrack.track.mode = 'hidden';\n }\n\n // Check if track has cues loaded\n if (!this.currentTrack.track.activeCues) {\n // If no activeCues property, track might not be ready yet\n // Try to access cues directly\n if (this.currentTrack.track.cues && this.currentTrack.track.cues.length > 0) {\n // Track has cues but no active ones yet - this is normal\n // Clear any existing caption\n if (this.currentCue) {\n this.element.innerHTML = '';\n this.element.style.display = 'none';\n this.currentCue = null;\n }\n }\n return;\n }\n\n const activeCues = this.currentTrack.track.activeCues;\n const isAudioPlayer = this.player.element.tagName.toLowerCase() === 'audio';\n\n if (activeCues.length > 0) {\n const cue = activeCues[0];\n\n // Only update if the cue has changed\n if (this.currentCue !== cue) {\n this.currentCue = cue;\n\n // Parse and display cue text\n let text = cue.text;\n\n // Handle VTT formatting\n text = this.parseVTTFormatting(text);\n\n // Audio players: transcript-style accumulation\n if (isAudioPlayer) {\n // Remove highlight from previous active cue\n const existingCues = this.element.querySelectorAll(`.${this.player.options.classPrefix}-caption-cue`);\n existingCues.forEach(el => el.classList.remove(`${this.player.options.classPrefix}-caption-active`));\n \n // Check if this cue is already displayed\n const cueId = `cue-${cue.startTime}-${cue.endTime}`;\n let cueElement = this.element.querySelector(`[data-cue-id=\"${cueId}\"]`);\n \n if (!cueElement) {\n // Create new cue element\n cueElement = document.createElement('div');\n cueElement.className = `${this.player.options.classPrefix}-caption-cue`;\n cueElement.setAttribute('data-cue-id', cueId);\n cueElement.innerHTML = DOMUtils.sanitizeHTML(text);\n this.element.appendChild(cueElement);\n }\n \n // Highlight active cue\n cueElement.classList.add(`${this.player.options.classPrefix}-caption-active`);\n \n // Scroll to active cue smoothly - center it for better visibility\n requestAnimationFrame(() => {\n if (cueElement) {\n cueElement.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n });\n } else {\n // Video players: replace content as before\n this.element.innerHTML = DOMUtils.sanitizeHTML(text);\n }\n\n // Make sure it's visible when there's content\n this.element.style.display = 'block';\n \n // Position captions above controls on mobile\n this.positionCaptionsOnMobile();\n\n this.player.emit('captionchange', cue);\n }\n } else if (this.currentCue) {\n // Clear caption when no active cues (video players only)\n if (!isAudioPlayer) {\n this.element.innerHTML = '';\n this.element.style.display = 'none';\n }\n this.currentCue = null;\n }\n }\n \n positionCaptionsOnMobile() {\n if (!this.element || this.element.style.display === 'none') {\n return;\n }\n \n const isFullscreen = this.player.state?.fullscreen || false;\n const mobile = isMobile();\n \n if (!mobile && !isFullscreen) {\n // Reset to CSS defaults on desktop\n this.element.style.bottom = '';\n return;\n }\n \n const controls = this.player.controlBar?.element;\n if (!controls) {\n return;\n }\n \n // Use requestAnimationFrame to ensure layout is complete\n requestAnimationFrame(() => {\n if (!this.element || this.element.style.display === 'none') {\n return;\n }\n \n const controlsRect = controls.getBoundingClientRect();\n const wrapperRect = this.player.videoWrapper.getBoundingClientRect();\n const bottomOffset = wrapperRect.bottom - controlsRect.top + 16;\n \n this.element.style.bottom = `${bottomOffset}px`;\n \n if (this.player.options.debug) {\n console.log('[VidPly] Caption position:', {\n mobile,\n isFullscreen,\n controlsHeight: controlsRect.height,\n bottomOffset: `${bottomOffset}px`\n });\n }\n });\n }\n\n parseVTTFormatting(text) {\n // Basic VTT tag support\n text = text.replace(/<c[^>]*>(.*?)<\\/c>/g, '<span class=\"caption-class\">$1</span>');\n text = text.replace(/<b>(.*?)<\\/b>/g, '<strong>$1</strong>');\n text = text.replace(/<i>(.*?)<\\/i>/g, '<em>$1</em>');\n text = text.replace(/<u>(.*?)<\\/u>/g, '<u>$1</u>');\n\n // Voice tags\n text = text.replace(/<v\\s+([^>]+)>(.*?)<\\/v>/g, '<span class=\"caption-voice\" data-voice=\"$1\">$2</span>');\n\n return text;\n }\n\n updateStyles() {\n if (!this.element) return;\n\n const options = this.player.options;\n\n this.element.style.fontSize = options.captionsFontSize;\n this.element.style.fontFamily = options.captionsFontFamily;\n this.element.style.color = options.captionsColor;\n this.element.style.backgroundColor = this.hexToRgba(\n options.captionsBackgroundColor,\n options.captionsOpacity\n );\n }\n\n hexToRgba(hex, alpha) {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (result) {\n return `rgba(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}, ${alpha})`;\n }\n return hex;\n }\n\n setCaptionStyle(property, value) {\n switch (property) {\n case 'fontSize':\n this.player.options.captionsFontSize = value;\n break;\n case 'fontFamily':\n this.player.options.captionsFontFamily = value;\n break;\n case 'color':\n this.player.options.captionsColor = value;\n break;\n case 'backgroundColor':\n this.player.options.captionsBackgroundColor = value;\n break;\n case 'opacity':\n this.player.options.captionsOpacity = value;\n break;\n }\n\n this.updateStyles();\n this.saveCaptionPreferences();\n this.player.emit('captionschange');\n }\n\n getAvailableTracks() {\n return this.tracks.map((t, index) => ({\n index,\n language: t.language,\n label: t.label || t.language,\n kind: t.kind\n }));\n }\n\n switchTrack(trackIndex) {\n if (trackIndex >= 0 && trackIndex < this.tracks.length) {\n this.disable();\n this.enable(trackIndex);\n }\n }\n\n destroy() {\n this.disable();\n\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n }\n}\n\n", "/**\r\n * Keyboard Accessibility Manager\r\n */\r\n\r\nexport class KeyboardManager {\r\n constructor(player) {\r\n this.player = player;\r\n this.shortcuts = player.options.keyboardShortcuts;\r\n \r\n this.init();\r\n }\r\n\r\n init() {\r\n this.attachEvents();\r\n }\r\n\r\n attachEvents() {\r\n // Listen for keyboard events on the player container using CAPTURE phase\r\n // This ensures we intercept events before they reach child elements\r\n this.player.container.addEventListener('keydown', (e) => {\r\n this.handleKeydown(e);\r\n }, true); // Use capture phase\r\n\r\n // Make player container focusable\r\n if (!this.player.container.hasAttribute('tabindex')) {\r\n this.player.container.setAttribute('tabindex', '0');\r\n }\r\n }\r\n\r\n handleKeydown(e) {\r\n // Don't handle if target is an input element\r\n if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.tagName === 'SELECT') {\r\n return;\r\n }\r\n \r\n // Don't handle if focus is inside a menu (let menu handle its own keyboard navigation)\r\n const activeElement = document.activeElement;\r\n if (activeElement) {\r\n const menu = activeElement.closest('.vidply-menu, [role=\"menu\"]');\r\n if (menu) {\r\n return; // Let the menu handle keyboard events\r\n }\r\n \r\n // Don't handle if focus is on a playlist button (let playlist handle navigation)\r\n const playlistButton = activeElement.closest('.vidply-playlist-item-button');\r\n if (playlistButton) {\r\n return; // Let the playlist handle keyboard events\r\n }\r\n }\r\n\r\n const key = e.key;\r\n let handled = false;\r\n\r\n // Special handling for ESC key - exit fullscreen (especially for iOS pseudo-fullscreen)\r\n if (key === 'Escape' && this.player.state.fullscreen) {\r\n this.player.exitFullscreen();\r\n e.preventDefault();\r\n e.stopPropagation();\r\n return;\r\n }\r\n\r\n // Check each shortcut category\r\n for (const [action, keys] of Object.entries(this.shortcuts)) {\r\n if (keys.includes(key)) {\r\n handled = this.executeAction(action, e);\r\n if (handled) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.announceAction(action);\r\n break;\r\n }\r\n }\r\n }\r\n \r\n // Log unhandled keys for debugging (in development)\r\n if (!handled && this.player.options.debug) {\r\n console.log('[VidPly] Unhandled key:', e.key, 'code:', e.code, 'shiftKey:', e.shiftKey);\r\n }\r\n }\r\n\r\n executeAction(action, event) {\r\n switch (action) {\r\n case 'play-pause':\r\n this.player.toggle();\r\n return true;\r\n\r\n case 'volume-up':\r\n this.player.setVolume(Math.min(1, this.player.state.volume + 0.1));\r\n return true;\r\n\r\n case 'volume-down':\r\n this.player.setVolume(Math.max(0, this.player.state.volume - 0.1));\r\n return true;\r\n\r\n case 'seek-forward':\r\n this.player.seekForward();\r\n return true;\r\n\r\n case 'seek-backward':\r\n this.player.seekBackward();\r\n return true;\r\n\r\n case 'mute':\r\n this.player.toggleMute();\r\n return true;\r\n\r\n case 'fullscreen':\r\n this.player.toggleFullscreen();\r\n return true;\r\n\r\n case 'captions':\r\n // If only one caption track, toggle on/off\r\n // If multiple tracks, open caption menu\r\n if (this.player.captionManager && this.player.captionManager.tracks.length > 1) {\r\n // Get captions button from control bar\r\n const captionsButton = this.player.controlBar && this.player.controlBar.controls.captions;\r\n if (captionsButton) {\r\n this.player.controlBar.showCaptionsMenu(captionsButton);\r\n } else {\r\n // Fallback to toggle if button doesn't exist\r\n this.player.toggleCaptions();\r\n }\r\n } else {\r\n this.player.toggleCaptions();\r\n }\r\n return true;\r\n\r\n case 'caption-style-menu':\r\n // Open caption style menu\r\n if (this.player.controlBar && this.player.controlBar.controls.captionStyle) {\r\n this.player.controlBar.showCaptionStyleMenu(this.player.controlBar.controls.captionStyle);\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'speed-up':\r\n this.player.setPlaybackSpeed(\r\n Math.min(2, this.player.state.playbackSpeed + 0.25)\r\n );\r\n return true;\r\n\r\n case 'speed-down':\r\n this.player.setPlaybackSpeed(\r\n Math.max(0.25, this.player.state.playbackSpeed - 0.25)\r\n );\r\n return true;\r\n\r\n case 'speed-menu':\r\n // Open speed menu\r\n if (this.player.controlBar && this.player.controlBar.controls.speed) {\r\n this.player.controlBar.showSpeedMenu(this.player.controlBar.controls.speed);\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'quality-menu':\r\n // Open quality menu\r\n if (this.player.controlBar && this.player.controlBar.controls.quality) {\r\n this.player.controlBar.showQualityMenu(this.player.controlBar.controls.quality);\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'chapters-menu':\r\n // Open chapters menu\r\n if (this.player.controlBar && this.player.controlBar.controls.chapters) {\r\n this.player.controlBar.showChaptersMenu(this.player.controlBar.controls.chapters);\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'transcript-toggle':\r\n // Toggle transcript\r\n if (this.player.transcriptManager) {\r\n this.player.transcriptManager.toggleTranscript();\r\n return true;\r\n }\r\n return false;\r\n\r\n default:\r\n return false;\r\n }\r\n }\r\n\r\n announceAction(action) {\r\n if (!this.player.options.screenReaderAnnouncements) return;\r\n\r\n let message = '';\r\n\r\n switch (action) {\r\n case 'play-pause':\r\n message = this.player.state.playing ? 'Playing' : 'Paused';\r\n break;\r\n case 'volume-up':\r\n message = `Volume ${Math.round(this.player.state.volume * 100)}%`;\r\n break;\r\n case 'volume-down':\r\n message = `Volume ${Math.round(this.player.state.volume * 100)}%`;\r\n break;\r\n case 'mute':\r\n message = this.player.state.muted ? 'Muted' : 'Unmuted';\r\n break;\r\n case 'fullscreen':\r\n message = this.player.state.fullscreen ? 'Fullscreen' : 'Exit fullscreen';\r\n break;\r\n case 'captions':\r\n message = this.player.state.captionsEnabled ? 'Captions on' : 'Captions off';\r\n break;\r\n case 'speed-up':\r\n case 'speed-down':\r\n message = `Speed ${this.player.state.playbackSpeed}x`;\r\n break;\r\n }\r\n\r\n if (message) {\r\n this.announce(message);\r\n }\r\n }\r\n\r\n announce(message, priority = 'polite') {\r\n // Create or get announcement element\r\n let announcer = document.getElementById('vidply-announcer');\r\n \r\n if (!announcer) {\r\n announcer = document.createElement('div');\r\n announcer.id = 'vidply-announcer';\r\n announcer.className = 'vidply-sr-only';\r\n announcer.setAttribute('aria-live', priority);\r\n announcer.setAttribute('aria-atomic', 'true');\r\n announcer.style.cssText = `\r\n position: absolute;\r\n left: -10000px;\r\n width: 1px;\r\n height: 1px;\r\n overflow: hidden;\r\n `;\r\n document.body.appendChild(announcer);\r\n }\r\n\r\n // Clear and set new message\r\n announcer.textContent = '';\r\n setTimeout(() => {\r\n announcer.textContent = message;\r\n }, 100);\r\n }\r\n\r\n updateShortcut(action, keys) {\r\n if (Array.isArray(keys)) {\r\n this.shortcuts[action] = keys;\r\n }\r\n }\r\n\r\n destroy() {\r\n // Event listeners are automatically removed when the container is destroyed\r\n }\r\n}\r\n\r\n", "/**\n * VidPly - Universal Video Player\n * Main Player Class\n */\n\nimport {EventEmitter} from '../utils/EventEmitter.js';\nimport {DOMUtils} from '../utils/DOMUtils.js';\nimport {ControlBar} from '../controls/ControlBar.js';\nimport {CaptionManager} from '../controls/CaptionManager.js';\nimport {KeyboardManager} from '../controls/KeyboardManager.js';\nimport {HTML5Renderer} from '../renderers/HTML5Renderer.js';\nimport {createPlayOverlay, createIconElement} from '../icons/Icons.js';\nimport {i18n} from '../i18n/i18n.js';\nimport {StorageManager} from '../utils/StorageManager.js';\nimport {DraggableResizable} from '../utils/DraggableResizable.js';\nimport {createMenuItem, attachMenuKeyboardNavigation, focusFirstMenuItem} from '../utils/MenuUtils.js';\nimport {createLabeledSelect, preventDragOnElement} from '../utils/FormUtils.js';\nimport {debounce, isMobile, rafWithTimeout} from '../utils/PerformanceUtils.js';\n\n// Static counter for unique player instances\nlet playerInstanceCounter = 0;\n\nexport class Player extends EventEmitter {\n constructor(element, options = {}) {\n super();\n\n this.element = typeof element === 'string' ? document.querySelector(element) : element;\n if (!this.element) {\n throw new Error('VidPly: Element not found');\n }\n\n // Assign unique instance ID\n playerInstanceCounter++;\n this.instanceId = playerInstanceCounter;\n\n // Auto-create media element if a non-media element is provided\n if (this.element.tagName !== 'VIDEO' && this.element.tagName !== 'AUDIO') {\n const mediaType = options.mediaType || 'video';\n const mediaElement = document.createElement(mediaType);\n\n // Copy attributes from the div to the media element\n Array.from(this.element.attributes).forEach(attr => {\n if (attr.name !== 'id' && attr.name !== 'class' && !attr.name.startsWith('data-')) {\n mediaElement.setAttribute(attr.name, attr.value);\n }\n });\n\n // Copy any track elements from the div\n const tracks = this.element.querySelectorAll('track');\n tracks.forEach(track => {\n mediaElement.appendChild(track.cloneNode(true));\n });\n\n // Clear the div and insert the media element\n this.element.innerHTML = '';\n this.element.appendChild(mediaElement);\n\n // Update element reference to the actual media element\n this.element = mediaElement;\n }\n\n // Default options\n this.options = {\n // Display\n width: null,\n height: null,\n poster: null,\n responsive: true,\n fillContainer: false,\n\n // Playback\n autoplay: false,\n loop: false,\n muted: false,\n volume: 0.8,\n playbackSpeed: 1.0,\n preload: 'metadata',\n startTime: 0,\n playsInline: true, // Enable inline playback on iOS (prevents native fullscreen)\n\n // Controls\n controls: true,\n hideControlsDelay: 3000,\n playPauseButton: true,\n progressBar: true,\n currentTime: true,\n duration: true,\n volumeControl: true,\n muteButton: true,\n chaptersButton: true,\n qualityButton: true,\n captionStyleButton: true,\n speedButton: true,\n captionsButton: true,\n transcriptButton: true,\n fullscreenButton: true,\n pipButton: false,\n\n // Seeking\n seekInterval: 10,\n seekIntervalLarge: 30,\n\n // Captions\n captions: true,\n captionsDefault: false,\n captionsFontSize: '100%',\n captionsFontFamily: 'sans-serif',\n captionsColor: '#FFFFFF',\n captionsBackgroundColor: '#000000',\n captionsOpacity: 0.8,\n\n // Audio Description\n audioDescription: true,\n audioDescriptionSrc: null, // URL to audio-described version\n audioDescriptionButton: true,\n\n // Sign Language\n signLanguage: true,\n signLanguageSrc: null, // URL to sign language video\n signLanguageButton: true,\n signLanguagePosition: 'bottom-right', // Position: 'bottom-right', 'bottom-left', 'top-right', 'top-left'\n\n // Transcripts\n transcript: false,\n transcriptPosition: 'external',\n transcriptContainer: null,\n\n // Keyboard\n keyboard: true,\n keyboardShortcuts: {\n 'play-pause': [' ', 'p', 'k'],\n 'volume-up': ['ArrowUp'],\n 'volume-down': ['ArrowDown'],\n 'seek-forward': ['ArrowRight'],\n 'seek-backward': ['ArrowLeft'],\n 'mute': ['m'],\n 'fullscreen': ['f'],\n 'captions': ['c'],\n 'caption-style-menu': ['a'],\n 'speed-up': ['>'],\n 'speed-down': ['<'],\n 'speed-menu': ['s'],\n 'quality-menu': ['q'],\n 'chapters-menu': ['j'],\n 'transcript-toggle': ['t']\n },\n\n // Accessibility\n ariaLabels: {},\n screenReaderAnnouncements: true,\n highContrast: false,\n focusHighlight: true,\n metadataAlerts: {},\n metadataHashtags: {},\n\n // Languages\n language: 'en',\n languages: ['en'],\n\n // Advanced\n debug: false,\n classPrefix: 'vidply',\n iconType: 'svg',\n pauseOthersOnPlay: true,\n\n // Callbacks\n onReady: null,\n onPlay: null,\n onPause: null,\n onEnded: null,\n onTimeUpdate: null,\n onVolumeChange: null,\n onError: null,\n\n ...options\n };\n\n this.options.metadataAlerts = this.options.metadataAlerts || {};\n this.options.metadataHashtags = this.options.metadataHashtags || {};\n\n // Storage manager\n this.storage = new StorageManager('vidply');\n \n // Load saved player preferences\n const savedPrefs = this.storage.getPlayerPreferences();\n if (savedPrefs) {\n if (savedPrefs.volume !== undefined) this.options.volume = savedPrefs.volume;\n if (savedPrefs.playbackSpeed !== undefined) this.options.playbackSpeed = savedPrefs.playbackSpeed;\n if (savedPrefs.muted !== undefined) this.options.muted = savedPrefs.muted;\n }\n \n // State\n this.state = {\n ready: false,\n playing: false,\n paused: true,\n ended: false,\n buffering: false,\n seeking: false,\n muted: this.options.muted,\n volume: this.options.volume,\n currentTime: 0,\n duration: 0,\n playbackSpeed: this.options.playbackSpeed,\n fullscreen: false,\n pip: false,\n captionsEnabled: this.options.captionsDefault,\n currentCaption: null,\n controlsVisible: true,\n audioDescriptionEnabled: false,\n signLanguageEnabled: false\n };\n\n // Store original source for toggling\n this.originalSrc = null;\n this.audioDescriptionSrc = this.options.audioDescriptionSrc;\n this.signLanguageSrc = this.options.signLanguageSrc;\n this.signLanguageSources = this.options.signLanguageSources || {}; // Map of lang codes to video URLs\n this.currentSignLanguage = null; // Current selected sign language code\n this.signLanguageVideo = null;\n // Store references to source elements with audio description attributes\n this.audioDescriptionSourceElement = null;\n this.originalAudioDescriptionSource = null;\n // Store caption tracks that should be swapped for audio description\n this.audioDescriptionCaptionTracks = [];\n this._audioDescriptionDesiredState = false;\n\n // DOM query cache (for performance optimization)\n this._textTracksCache = null;\n this._textTracksDirty = true;\n this._sourceElementsCache = null;\n this._sourceElementsDirty = true;\n this._trackElementsCache = null;\n this._trackElementsDirty = true;\n\n // Timeout management (for cleanup)\n this.timeouts = new Set();\n\n // Components\n this.container = null;\n this.renderer = null;\n this.controlBar = null;\n this.captionManager = null;\n this.keyboardManager = null;\n this.settingsDialog = null;\n \n // Metadata handling\n this.metadataCueChangeHandler = null;\n this.metadataAlertHandlers = new Map();\n\n // Initialize\n this.init();\n }\n\n async init() {\n try {\n this.log('Initializing VidPly player');\n\n // Load custom language files if specified\n if (this.options.languageFiles) {\n try {\n await i18n.loadLanguagesFromUrls(this.options.languageFiles);\n } catch (error) {\n console.warn('Failed to load some language files:', error);\n }\n }\n\n // Load single language file if specified (for backwards compatibility)\n if (this.options.languageFile && this.options.languageFileUrl) {\n try {\n await i18n.loadLanguageFromUrl(this.options.languageFile, this.options.languageFileUrl);\n this.log(`Custom language file loaded for ${this.options.languageFile}`);\n } catch (error) {\n console.warn(`Failed to load language file for ${this.options.languageFile}:`, error);\n }\n }\n\n // Auto-detect language from HTML lang attribute if not explicitly set\n if (!this.options.language || this.options.language === 'en') {\n const htmlLang = this.detectHtmlLanguage();\n if (htmlLang) {\n this.options.language = htmlLang;\n this.log(`Auto-detected language from HTML: ${htmlLang}`);\n }\n }\n\n // Ensure we have a language set (default to 'en' if not set)\n if (!this.options.language) {\n this.options.language = 'en';\n }\n\n // Ensure requested language is available (loads built-ins on demand)\n await i18n.ensureLanguage(this.options.language);\n\n // Set language\n i18n.setLanguage(this.options.language);\n\n // Create container\n this.createContainer();\n\n // Detect and initialize renderer (only if source exists)\n const src = this.element.src || this.element.querySelector('source')?.src;\n if (src) {\n await this.initializeRenderer();\n } else {\n this.log('No initial source - waiting for playlist or manual load');\n }\n\n // Create controls\n if (this.options.controls) {\n this.controlBar = new ControlBar(this);\n this.videoWrapper.appendChild(this.controlBar.element);\n }\n\n // Initialize captions\n if (this.options.captions) {\n this.captionManager = new CaptionManager(this);\n }\n\n // Initialize transcript lazily unless explicitly requested\n if (this.options.transcript) {\n await this.ensureTranscriptManager();\n }\n \n // Always set up metadata track handling (independent of transcript)\n this.setupMetadataHandling();\n\n // Initialize keyboard controls\n if (this.options.keyboard) {\n this.keyboardManager = new KeyboardManager(this);\n }\n\n // Setup responsive handlers\n this.setupResponsiveHandlers();\n\n // Set initial state\n if (this.options.startTime > 0) {\n this.seek(this.options.startTime);\n }\n\n // Apply volume and mute settings after renderer is initialized\n // Use requestAnimationFrame to ensure renderer is fully ready\n requestAnimationFrame(() => {\n if (this.options.muted) {\n this.mute();\n } else if (this.renderer && this.renderer.media) {\n // Ensure media element is not muted if options say it shouldn't be\n this.renderer.setMuted(false);\n }\n\n if (this.options.volume !== 0.8) {\n this.setVolume(this.options.volume);\n } else if (this.renderer && this.renderer.media) {\n // Ensure volume is set even if it's the default\n this.renderer.setVolume(this.options.volume);\n }\n });\n\n // Mark as ready\n this.state.ready = true;\n this.emit('ready');\n\n if (this.options.onReady) {\n this.options.onReady.call(this);\n }\n\n // Autoplay if enabled\n if (this.options.autoplay) {\n this.play();\n }\n\n this.log('Player initialized successfully');\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Ensure the transcript manager is available, creating it on demand.\n * This keeps initial load fast when transcripts are not needed.\n */\n async ensureTranscriptManager() {\n if (this.transcriptManager) {\n return this.transcriptManager;\n }\n\n if (!this.options.transcript && !this.options.transcriptButton) {\n return null;\n }\n\n const module = await import('../controls/TranscriptManager.js');\n const Manager = module.TranscriptManager || module.default;\n\n if (!Manager) {\n return null;\n }\n\n this.transcriptManager = new Manager(this);\n return this.transcriptManager;\n }\n\n /**\n * Toggle transcript visibility, lazily creating the manager if necessary.\n */\n async toggleTranscript() {\n const manager = await this.ensureTranscriptManager();\n if (!manager) return;\n\n manager.toggleTranscript();\n if (this.controlBar) {\n this.controlBar.updateTranscriptButton();\n }\n }\n\n /**\n * Detect language from HTML lang attribute\n * @returns {string|null} Language code if available in translations or as built-in, null otherwise\n */\n detectHtmlLanguage() {\n // Try to get lang from html element\n const htmlLang = document.documentElement.lang || document.documentElement.getAttribute('lang');\n\n if (!htmlLang) {\n return null;\n }\n\n // Normalize the language code (e.g., \"en-US\" -> \"en\", \"de-DE\" -> \"de\")\n const normalizedLang = htmlLang.toLowerCase().split('-')[0];\n\n // Check if this language is available in our translations (already loaded)\n if (i18n.translations[normalizedLang]) {\n return normalizedLang;\n }\n\n // Check if this language is available as a built-in that can be loaded on demand\n if (i18n.builtInLanguageLoaders && i18n.builtInLanguageLoaders[normalizedLang]) {\n return normalizedLang;\n }\n\n // Language not available, will fallback to English\n this.log(`Language \"${htmlLang}\" not available, using English as fallback`);\n return null; // Return null instead of 'en' to let the default language handling work\n }\n\n createContainer() {\n // Create main container with unique label for multiple players on same page\n const playerLabel = this.instanceId > 1 \n ? `${i18n.t('player.label')} ${this.instanceId}`\n : i18n.t('player.label');\n \n this.container = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-player`,\n attributes: {\n 'role': 'application',\n 'aria-label': playerLabel,\n 'tabindex': '0'\n }\n });\n\n // Add media type class\n const mediaType = this.element.tagName.toLowerCase();\n this.container.classList.add(`${this.options.classPrefix}-${mediaType}`);\n\n // Add responsive class\n if (this.options.responsive) {\n this.container.classList.add(`${this.options.classPrefix}-responsive`);\n }\n\n // Create video wrapper (for proper positioning of controls)\n this.videoWrapper = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-video-wrapper`\n });\n\n // Wrap original element\n this.element.parentNode.insertBefore(this.container, this.element);\n \n // Create track artwork element for single audio files (before video wrapper)\n // This shows the poster/artwork above the audio player (similar to playlists)\n if (this.element.tagName === 'AUDIO' && this.options.poster) {\n this.trackArtworkElement = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-track-artwork`,\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n this.trackArtworkElement.style.backgroundImage = `url(${this.options.poster})`;\n this.container.appendChild(this.trackArtworkElement);\n }\n \n this.container.appendChild(this.videoWrapper);\n this.videoWrapper.appendChild(this.element);\n\n // Hide native controls and set dimensions\n this.element.controls = false;\n this.element.removeAttribute('controls');\n this.element.setAttribute('tabindex', '-1'); // Remove from tab order\n this.element.style.width = '100%';\n this.element.style.height = '100%';\n\n // Enable inline playback on iOS (prevents native fullscreen)\n // This allows custom controls to work on iOS devices\n if (this.element.tagName === 'VIDEO' && this.options.playsInline) {\n this.element.setAttribute('playsinline', '');\n this.element.playsInline = true; // Property version\n }\n\n // Set dimensions\n if (this.options.width) {\n this.container.style.width = typeof this.options.width === 'number'\n ? `${this.options.width}px`\n : this.options.width;\n }\n\n if (this.options.height) {\n this.container.style.height = typeof this.options.height === 'number'\n ? `${this.options.height}px`\n : this.options.height;\n }\n\n // Set poster (convert relative paths to absolute URLs)\n if (this.options.poster && this.element.tagName === 'VIDEO') {\n this.element.poster = this.resolvePosterPath(this.options.poster);\n }\n\n // Create centered play button overlay (only for video)\n if (this.element.tagName === 'VIDEO') {\n this.createPlayButtonOverlay();\n }\n \n // Store reference to player on element for easy access\n this.element.vidply = this;\n \n // Add to static instances array\n Player.instances.push(this);\n\n // Make video/audio element clickable to toggle play/pause\n this.element.style.cursor = 'pointer';\n this.element.addEventListener('click', (e) => {\n // Prevent if clicking on native controls (shouldn't happen but just in case)\n if (e.target === this.element) {\n this.toggle();\n }\n });\n\n this.on('play', () => {\n // Hide poster immediately when playing\n this.hidePosterOverlay();\n });\n\n this.on('timeupdate', () => {\n // Hide poster when video has started playing (currentTime > 0)\n if (this.state.currentTime > 0) {\n this.hidePosterOverlay();\n }\n });\n\n // Also hide poster on loadeddata event (when first frame is loaded)\n this.element.addEventListener('loadeddata', () => {\n if (this.state.playing || this.state.currentTime > 0) {\n this.hidePosterOverlay();\n }\n }, { once: true });\n }\n\n createPlayButtonOverlay() {\n // Create complete SVG play button from Icons.js\n this.playButtonOverlay = createPlayOverlay();\n\n // Add click handler\n this.playButtonOverlay.addEventListener('click', () => {\n this.toggle();\n });\n\n // Add to video wrapper\n this.videoWrapper.appendChild(this.playButtonOverlay);\n\n // Show/hide based on play state\n this.on('play', () => {\n this.playButtonOverlay.style.opacity = '0';\n this.playButtonOverlay.style.pointerEvents = 'none';\n });\n\n this.on('pause', () => {\n this.playButtonOverlay.style.opacity = '1';\n this.playButtonOverlay.style.pointerEvents = 'auto';\n this.positionPlayOverlayOnMobile();\n });\n\n this.on('ended', () => {\n this.playButtonOverlay.style.opacity = '1';\n this.playButtonOverlay.style.pointerEvents = 'auto';\n this.positionPlayOverlayOnMobile();\n });\n \n // Debounced resize handler\n this.debouncedPositionPlayOverlay = debounce(() => {\n this.positionPlayOverlayOnMobile();\n }, 150);\n \n window.addEventListener('resize', this.debouncedPositionPlayOverlay);\n \n this.on('loadedmetadata', () => {\n this.positionPlayOverlayOnMobile();\n });\n \n // Recalculate on fullscreen change with RAF\n this.on('enterfullscreen', () => {\n rafWithTimeout(() => this.positionPlayOverlayOnMobile(), 100);\n });\n \n this.on('exitfullscreen', () => {\n rafWithTimeout(() => this.positionPlayOverlayOnMobile(), 100);\n });\n }\n \n positionPlayOverlayOnMobile() {\n if (!this.playButtonOverlay || this.element.tagName !== 'VIDEO') {\n return;\n }\n \n const mobile = isMobile();\n \n if (!mobile) {\n // Reset to CSS defaults on desktop\n this.playButtonOverlay.style.top = '';\n return;\n }\n \n const videoRect = this.element.getBoundingClientRect();\n const wrapperRect = this.videoWrapper.getBoundingClientRect();\n const videoCenter = (videoRect.top - wrapperRect.top) + (videoRect.height / 2);\n \n this.playButtonOverlay.style.top = `${videoCenter}px`;\n }\n\n async initializeRenderer() {\n const src = this.element.src || this.element.querySelector('source')?.src;\n\n if (!src) {\n throw new Error('No media source found');\n }\n\n // Check for source elements with audio description attributes\n const sourceElements = this.sourceElements;\n for (const sourceEl of sourceElements) {\n const descSrc = sourceEl.getAttribute('data-desc-src');\n const origSrc = sourceEl.getAttribute('data-orig-src');\n \n if (descSrc || origSrc) {\n // Found a source element with audio description attributes\n // Store the first one as reference, but we'll search all of them when toggling\n if (!this.audioDescriptionSourceElement) {\n this.audioDescriptionSourceElement = sourceEl;\n }\n \n if (origSrc) {\n // Store the original src from the attribute for this source\n if (!this.originalAudioDescriptionSource) {\n this.originalAudioDescriptionSource = origSrc;\n }\n // Store the original src from the first source element that has data-orig-src\n if (!this.originalSrc) {\n this.originalSrc = origSrc;\n }\n } else {\n // If data-orig-src is not set, use the current src attribute\n const currentSrcAttr = sourceEl.getAttribute('src');\n if (!this.originalAudioDescriptionSource && currentSrcAttr) {\n this.originalAudioDescriptionSource = currentSrcAttr;\n }\n if (!this.originalSrc && currentSrcAttr) {\n this.originalSrc = currentSrcAttr;\n }\n }\n \n // Store audio description source from data-desc-src (use first one found)\n if (descSrc && !this.audioDescriptionSrc) {\n this.audioDescriptionSrc = descSrc;\n }\n // Continue checking all source elements to ensure we capture all audio description sources\n }\n }\n\n // Check for caption/subtitle tracks with audio description versions\n // Only tracks with explicit data-desc-src attribute are swapped (no auto-detection to avoid 404 errors)\n // Description tracks (kind=\"descriptions\") are NOT swapped - they're for transcripts\n const trackElements = this.trackElements;\n trackElements.forEach(trackEl => {\n const trackKind = trackEl.getAttribute('kind');\n const trackDescSrc = trackEl.getAttribute('data-desc-src');\n \n // Only handle caption/subtitle tracks (not description tracks)\n // Description tracks stay as-is since they're for transcripts\n // Include captions, subtitles, and chapters tracks that can be swapped for audio description\n if (trackKind === 'captions' || trackKind === 'subtitles' || trackKind === 'chapters') {\n if (trackDescSrc) {\n // Found a track with explicit data-desc-src - this is the described version\n this.audioDescriptionCaptionTracks.push({\n trackElement: trackEl,\n originalSrc: trackEl.getAttribute('src'),\n describedSrc: trackDescSrc,\n originalTrackSrc: trackEl.getAttribute('data-orig-src') || trackEl.getAttribute('src'),\n explicit: true // Explicitly defined, so we should validate it\n });\n this.log(`Found explicit described ${trackKind} track: ${trackEl.getAttribute('src')} -> ${trackDescSrc}`);\n }\n // Note: Auto-detection disabled to avoid 404 console errors\n // If you want described tracks, add data-desc-src attribute to the track element\n }\n // Description tracks (kind=\"descriptions\") are ignored - they remain unchanged for transcripts\n });\n\n // Store original source for audio description toggling (fallback if not set above)\n if (!this.originalSrc) {\n this.originalSrc = src;\n }\n\n // Detect media type and lazily load heavy renderers\n let rendererClass = HTML5Renderer;\n\n if (src.includes('youtube.com') || src.includes('youtu.be')) {\n const module = await import('../renderers/YouTubeRenderer.js');\n rendererClass = module.YouTubeRenderer || module.default;\n } else if (src.includes('vimeo.com')) {\n const module = await import('../renderers/VimeoRenderer.js');\n rendererClass = module.VimeoRenderer || module.default;\n } else if (src.includes('.m3u8')) {\n const module = await import('../renderers/HLSRenderer.js');\n rendererClass = module.HLSRenderer || module.default;\n }\n\n this.log(`Using ${rendererClass?.name || 'HTML5Renderer'} renderer`);\n this.renderer = new rendererClass(this);\n await this.renderer.init();\n \n // Invalidate cache after renderer initialization (tracks may have changed)\n this.invalidateTrackCache();\n }\n\n /**\n * Get cached text tracks array\n * @returns {Array} Array of text tracks\n */\n get textTracks() {\n if (!this._textTracksCache || this._textTracksDirty) {\n this._textTracksCache = Array.from(this.element.textTracks || []);\n this._textTracksDirty = false;\n }\n return this._textTracksCache;\n }\n\n /**\n * Get cached source elements array\n * @returns {Array} Array of source elements\n */\n get sourceElements() {\n if (!this._sourceElementsCache || this._sourceElementsDirty) {\n this._sourceElementsCache = Array.from(this.element.querySelectorAll('source'));\n this._sourceElementsDirty = false;\n }\n return this._sourceElementsCache;\n }\n\n /**\n * Get cached track elements array\n * @returns {Array} Array of track elements\n */\n get trackElements() {\n if (!this._trackElementsCache || this._trackElementsDirty) {\n this._trackElementsCache = Array.from(this.element.querySelectorAll('track'));\n this._trackElementsDirty = false;\n }\n return this._trackElementsCache;\n }\n\n /**\n * Invalidate DOM query cache (call when tracks/sources change)\n */\n invalidateTrackCache() {\n this._textTracksDirty = true;\n this._trackElementsDirty = true;\n this._sourceElementsDirty = true;\n }\n\n /**\n * Find a text track by kind and optionally language\n * @param {string} kind - Track kind (captions, subtitles, descriptions, chapters, metadata)\n * @param {string} [language] - Optional language code\n * @returns {TextTrack|null} Found track or null\n */\n findTextTrack(kind, language = null) {\n const tracks = this.textTracks;\n if (language) {\n return tracks.find(t => t.kind === kind && t.language === language);\n }\n return tracks.find(t => t.kind === kind);\n }\n\n /**\n * Find a source element by attribute\n * @param {string} attribute - Attribute name (e.g., 'data-desc-src')\n * @param {string} [value] - Optional attribute value\n * @returns {Element|null} Found source element or null\n */\n findSourceElement(attribute, value = null) {\n const sources = this.sourceElements;\n if (value) {\n return sources.find(el => el.getAttribute(attribute) === value);\n }\n return sources.find(el => el.hasAttribute(attribute));\n }\n\n /**\n * Find a track element by its associated TextTrack\n * @param {TextTrack} track - The TextTrack object\n * @returns {Element|null} Found track element or null\n */\n findTrackElement(track) {\n return this.trackElements.find(el => el.track === track);\n }\n\n /**\n * Convert relative poster path to absolute URL\n * @param {string} posterPath - Poster path (relative or absolute)\n * @returns {string} Absolute URL\n */\n resolvePosterPath(posterPath) {\n if (!posterPath) {\n return posterPath;\n }\n \n // If already absolute (starts with http://, https://, or /), return as-is\n if (posterPath.match(/^(https?:|\\/)/)) {\n return posterPath;\n }\n \n // Convert relative path to absolute URL\n try {\n const posterUrl = new URL(posterPath, window.location.href);\n return posterUrl.href;\n } catch (e) {\n // If URL constructor fails, return as-is\n return posterPath;\n }\n }\n\n showPosterOverlay() {\n if (!this.videoWrapper || this.element.tagName !== 'VIDEO') {\n return;\n }\n\n const poster =\n this.element.getAttribute('poster') ||\n this.element.poster ||\n this.options.poster;\n\n if (!poster) {\n return;\n }\n\n // Resolve relative paths to absolute URLs\n const resolvedPoster = this.resolvePosterPath(poster);\n this.videoWrapper.style.setProperty('--vidply-poster-image', `url(\"${resolvedPoster}\")`);\n this.videoWrapper.classList.add('vidply-forced-poster');\n }\n\n hidePosterOverlay() {\n if (!this.videoWrapper) {\n return;\n }\n\n this.videoWrapper.classList.remove('vidply-forced-poster');\n this.videoWrapper.style.removeProperty('--vidply-poster-image');\n }\n\n /**\n * Set a managed timeout that will be cleaned up on destroy\n * @param {Function} callback - Callback function\n * @param {number} delay - Delay in milliseconds\n * @returns {number} Timeout ID\n */\n setManagedTimeout(callback, delay) {\n const timeoutId = setTimeout(() => {\n this.timeouts.delete(timeoutId);\n callback();\n }, delay);\n this.timeouts.add(timeoutId);\n return timeoutId;\n }\n\n /**\n * Clear a managed timeout\n * @param {number} timeoutId - Timeout ID to clear\n */\n clearManagedTimeout(timeoutId) {\n if (timeoutId) {\n clearTimeout(timeoutId);\n this.timeouts.delete(timeoutId);\n }\n }\n\n /**\n * Load new media source (for playlists)\n * @param {Object} config - Media configuration\n * @param {string} config.src - Media source URL\n * @param {string} config.type - Media MIME type\n * @param {string} [config.poster] - Poster image URL\n * @param {Array} [config.tracks] - Text tracks (captions, chapters, etc.)\n * @param {string} [config.audioDescriptionSrc] - Audio description video URL\n * @param {string} [config.signLanguageSrc] - Sign language video URL\n */\n async load(config) {\n try {\n this.log('Loading new media:', config.src);\n\n // Pause current playback\n if (this.renderer) {\n this.pause();\n }\n\n // Save scroll position to prevent browser from auto-scrolling when loading new media\n const scrollX = window.scrollX || window.pageXOffset;\n const scrollY = window.scrollY || window.pageYOffset;\n\n // Clear existing text tracks\n const existingTracks = this.trackElements;\n existingTracks.forEach(track => track.remove());\n this.invalidateTrackCache();\n\n // Update media element\n this.element.src = config.src;\n\n if (config.type) {\n this.element.type = config.type;\n }\n\n if (config.poster && this.element.tagName === 'VIDEO') {\n this.element.poster = this.resolvePosterPath(config.poster);\n }\n\n // Add new text tracks\n if (config.tracks && config.tracks.length > 0) {\n config.tracks.forEach(trackConfig => {\n const track = document.createElement('track');\n track.src = trackConfig.src;\n track.kind = trackConfig.kind || 'captions';\n track.srclang = trackConfig.srclang || 'en';\n track.label = trackConfig.label || trackConfig.srclang;\n\n if (trackConfig.default) {\n track.default = true;\n }\n\n // Insert tracks at the beginning (before any flow content) for HTML5 validity\n const firstChild = this.element.firstChild;\n if (firstChild && firstChild.nodeType === Node.ELEMENT_NODE && firstChild.tagName !== 'TRACK') {\n this.element.insertBefore(track, firstChild);\n } else {\n this.element.appendChild(track);\n }\n });\n this.invalidateTrackCache();\n }\n \n // Remember accessibility feature states before switching tracks\n const wasSignLanguageEnabled = this.state.signLanguageEnabled;\n const wasAudioDescriptionEnabled = this.state.audioDescriptionEnabled;\n \n // Update sources from config FIRST (before hiding features)\n this.audioDescriptionSrc = config.audioDescriptionSrc || null;\n this.signLanguageSrc = config.signLanguageSrc || null;\n \n // Update original source for toggling\n this.originalSrc = config.src;\n \n // Hide accessibility features that were enabled (must happen AFTER updating sources)\n if (wasAudioDescriptionEnabled) {\n this.disableAudioDescription();\n }\n if (wasSignLanguageEnabled) {\n this.disableSignLanguage();\n }\n\n // Check if we need to change renderer type\n const shouldChangeRenderer = this.shouldChangeRenderer(config.src);\n\n // Destroy old renderer if changing types\n if (shouldChangeRenderer && this.renderer) {\n this.renderer.destroy();\n this.renderer = null;\n }\n\n // Initialize or reinitialize renderer\n if (!this.renderer || shouldChangeRenderer) {\n await this.initializeRenderer();\n } else {\n // Just reload the current renderer with the updated element\n this.renderer.media = this.element; // Update media reference\n this.element.load();\n }\n \n // Restore scroll position immediately after loading to prevent auto-scroll\n window.scrollTo(scrollX, scrollY);\n\n // Reinitialize caption manager to pick up new tracks\n if (this.captionManager) {\n this.captionManager.destroy();\n this.captionManager = new CaptionManager(this);\n }\n \n // Reinitialize transcript manager to pick up new tracks\n if (this.transcriptManager) {\n const wasTranscriptVisible = this.transcriptManager.isVisible;\n this.transcriptManager.destroy();\n this.transcriptManager = null;\n\n await this.ensureTranscriptManager();\n \n // Only restore transcript visibility if new track has captions\n if (wasTranscriptVisible && this.controlBar && this.controlBar.hasCaptionTracks()) {\n this.transcriptManager?.showTranscript();\n }\n }\n \n // Update control bar to show/hide feature buttons based on new tracks\n if (this.controlBar) {\n this.updateControlBar();\n }\n \n // Restore scroll position after control bar update (may have caused micro-scrolls)\n window.scrollTo(scrollX, scrollY);\n \n // Restore accessibility features if they were enabled and available in new track\n if (wasSignLanguageEnabled && this.signLanguageSrc) {\n // Small delay to ensure player and control bar are ready\n setTimeout(() => {\n this.enableSignLanguage();\n // Restore scroll after sign language is shown\n window.scrollTo(scrollX, scrollY);\n }, 150);\n }\n \n if (wasAudioDescriptionEnabled && this.audioDescriptionSrc) {\n // Small delay to ensure player is ready\n setTimeout(() => {\n this.enableAudioDescription();\n // Restore scroll after audio description is enabled\n window.scrollTo(scrollX, scrollY);\n }, 150);\n }\n\n this.emit('sourcechange', config);\n this.log('Media loaded successfully');\n\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Check if we need to change renderer type\n * @param {string} src - New source URL\n * @returns {boolean}\n */\n /**\n * Update control bar to refresh button visibility based on available features\n */\n updateControlBar() {\n if (!this.controlBar) return;\n \n const controlBar = this.controlBar;\n \n // Clear existing controls content\n controlBar.element.innerHTML = '';\n \n // Recreate controls with updated feature detection\n controlBar.createControls();\n \n // Reattach events for the new controls\n controlBar.attachEvents();\n controlBar.setupAutoHide();\n controlBar.setupOverflowDetection();\n }\n \n shouldChangeRenderer(src) {\n if (!this.renderer) return true;\n\n const isYouTube = src.includes('youtube.com') || src.includes('youtu.be');\n const isVimeo = src.includes('vimeo.com');\n const isHLS = src.includes('.m3u8');\n\n const currentRendererName = this.renderer.constructor.name;\n\n if (isYouTube && currentRendererName !== 'YouTubeRenderer') return true;\n if (isVimeo && currentRendererName !== 'VimeoRenderer') return true;\n if (isHLS && currentRendererName !== 'HLSRenderer') return true;\n if (!isYouTube && !isVimeo && !isHLS && currentRendererName !== 'HTML5Renderer') return true;\n\n return false;\n }\n\n // Playback controls\n play() {\n if (this.renderer) {\n this.renderer.play();\n }\n }\n\n pause() {\n if (this.renderer) {\n this.renderer.pause();\n }\n }\n\n stop() {\n this.pause();\n this.seek(0);\n }\n\n toggle() {\n if (this.state.playing) {\n this.pause();\n } else {\n this.play();\n }\n }\n\n seek(time) {\n if (this.renderer) {\n this.renderer.seek(time);\n }\n }\n\n seekForward(interval = this.options.seekInterval) {\n this.seek(Math.min(this.state.currentTime + interval, this.state.duration));\n }\n\n seekBackward(interval = this.options.seekInterval) {\n this.seek(Math.max(this.state.currentTime - interval, 0));\n }\n\n // Volume controls\n setVolume(volume) {\n const newVolume = Math.max(0, Math.min(1, volume));\n if (this.renderer) {\n this.renderer.setVolume(newVolume);\n }\n this.state.volume = newVolume;\n\n // If volume is increased above 0 and currently muted, unmute\n if (newVolume > 0 && this.state.muted) {\n this.state.muted = false;\n if (this.renderer) {\n this.renderer.setMuted(false);\n }\n this.emit('volumechange');\n }\n \n this.savePlayerPreferences();\n }\n\n getVolume() {\n return this.state.volume;\n }\n\n mute() {\n if (this.renderer) {\n this.renderer.setMuted(true);\n }\n this.state.muted = true;\n this.savePlayerPreferences();\n this.emit('volumechange');\n }\n\n unmute() {\n if (this.renderer) {\n this.renderer.setMuted(false);\n }\n this.state.muted = false;\n this.savePlayerPreferences();\n this.emit('volumechange');\n }\n\n toggleMute() {\n if (this.state.muted) {\n this.unmute();\n } else {\n this.mute();\n }\n }\n\n // Playback speed\n setPlaybackSpeed(speed) {\n const newSpeed = Math.max(0.25, Math.min(2, speed));\n if (this.renderer) {\n this.renderer.setPlaybackSpeed(newSpeed);\n }\n this.state.playbackSpeed = newSpeed;\n this.savePlayerPreferences();\n this.emit('playbackspeedchange', newSpeed);\n }\n\n getPlaybackSpeed() {\n return this.state.playbackSpeed;\n }\n \n // Save player preferences to localStorage\n savePlayerPreferences() {\n this.storage.savePlayerPreferences({\n volume: this.state.volume,\n muted: this.state.muted,\n playbackSpeed: this.state.playbackSpeed\n });\n }\n\n // Fullscreen\n enterFullscreen() {\n const elem = this.container;\n let fullscreenPromise = null;\n\n // Detect iOS/iPadOS to avoid native fullscreen conflicts\n const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || \n (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);\n \n // On iOS/iPadOS, always use pseudo-fullscreen to avoid video element native fullscreen\n if (isIOS) {\n this._enablePseudoFullscreen();\n return;\n }\n\n // Try to use native Fullscreen API on other platforms\n if (elem.requestFullscreen) {\n fullscreenPromise = elem.requestFullscreen();\n } else if (elem.webkitRequestFullscreen) {\n fullscreenPromise = elem.webkitRequestFullscreen();\n } else if (elem.mozRequestFullScreen) {\n fullscreenPromise = elem.mozRequestFullScreen();\n } else if (elem.msRequestFullscreen) {\n fullscreenPromise = elem.msRequestFullscreen();\n }\n\n // Handle promise-based API (modern browsers)\n if (fullscreenPromise && fullscreenPromise.catch) {\n fullscreenPromise.catch((err) => {\n // Fullscreen API failed, use pseudo-fullscreen fallback\n this.log('Fullscreen API failed, using pseudo-fullscreen:', err.message);\n this._enablePseudoFullscreen();\n });\n }\n\n // For browsers without Fullscreen API support, use pseudo-fullscreen\n if (!elem.requestFullscreen && !elem.webkitRequestFullscreen && \n !elem.mozRequestFullScreen && !elem.msRequestFullscreen) {\n this._enablePseudoFullscreen();\n } else {\n // Optimistically set state (will be corrected by fullscreenChangeHandler if it fails)\n this.state.fullscreen = true;\n this.container.classList.add(`${this.options.classPrefix}-fullscreen`);\n this.emit('fullscreenchange', true);\n }\n }\n\n exitFullscreen() {\n // Check if we're in native fullscreen\n const isInNativeFullscreen = !!(\n document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement\n );\n\n if (isInNativeFullscreen) {\n // Exit native fullscreen\n if (document.exitFullscreen) {\n document.exitFullscreen();\n } else if (document.webkitExitFullscreen) {\n document.webkitExitFullscreen();\n } else if (document.mozCancelFullScreen) {\n document.mozCancelFullScreen();\n } else if (document.msExitFullscreen) {\n document.msExitFullscreen();\n }\n } else {\n // We're in pseudo-fullscreen, exit it manually\n this._disablePseudoFullscreen();\n }\n\n this.state.fullscreen = false;\n this.container.classList.remove(`${this.options.classPrefix}-fullscreen`);\n this.emit('fullscreenchange', false);\n }\n\n toggleFullscreen() {\n if (this.state.fullscreen) {\n this.exitFullscreen();\n } else {\n this.enterFullscreen();\n }\n }\n\n // Pseudo-fullscreen fallback for iOS and browsers without Fullscreen API\n _enablePseudoFullscreen() {\n this.state.fullscreen = true;\n this.container.classList.add(`${this.options.classPrefix}-fullscreen`);\n \n // Store current scroll position for restoration later\n this._originalScrollX = window.scrollX || window.pageXOffset;\n this._originalScrollY = window.scrollY || window.pageYOffset;\n \n // Prevent body scrolling while in pseudo-fullscreen\n this._originalBodyOverflow = document.body.style.overflow;\n this._originalBodyPosition = document.body.style.position;\n this._originalBodyWidth = document.body.style.width;\n this._originalBodyHeight = document.body.style.height;\n this._originalHtmlOverflow = document.documentElement.style.overflow;\n \n document.body.style.overflow = 'hidden';\n document.body.style.width = '100%';\n document.body.style.height = '100%';\n document.documentElement.style.overflow = 'hidden';\n \n // On iOS, also lock the viewport and scroll to top\n this._originalViewport = document.querySelector('meta[name=\"viewport\"]')?.getAttribute('content');\n const viewport = document.querySelector('meta[name=\"viewport\"]');\n if (viewport) {\n viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');\n }\n \n // Scroll to top on iOS to prevent positioning issues\n window.scrollTo(0, 0);\n \n this.emit('fullscreenchange', true);\n this.emit('enterfullscreen');\n }\n\n _disablePseudoFullscreen() {\n // Restore body scrolling\n if (this._originalBodyOverflow !== undefined) {\n document.body.style.overflow = this._originalBodyOverflow;\n delete this._originalBodyOverflow;\n }\n if (this._originalBodyPosition !== undefined) {\n document.body.style.position = this._originalBodyPosition;\n delete this._originalBodyPosition;\n }\n if (this._originalBodyWidth !== undefined) {\n document.body.style.width = this._originalBodyWidth;\n delete this._originalBodyWidth;\n }\n if (this._originalBodyHeight !== undefined) {\n document.body.style.height = this._originalBodyHeight;\n delete this._originalBodyHeight;\n }\n if (this._originalHtmlOverflow !== undefined) {\n document.documentElement.style.overflow = this._originalHtmlOverflow;\n delete this._originalHtmlOverflow;\n }\n \n // Restore viewport settings\n if (this._originalViewport !== undefined) {\n const viewport = document.querySelector('meta[name=\"viewport\"]');\n if (viewport) {\n viewport.setAttribute('content', this._originalViewport);\n }\n delete this._originalViewport;\n }\n \n // Restore scroll position\n if (this._originalScrollX !== undefined && this._originalScrollY !== undefined) {\n window.scrollTo(this._originalScrollX, this._originalScrollY);\n delete this._originalScrollX;\n delete this._originalScrollY;\n }\n \n this.emit('exitfullscreen');\n }\n\n // Picture-in-Picture\n enterPiP() {\n if (this.element.requestPictureInPicture) {\n this.element.requestPictureInPicture();\n this.state.pip = true;\n this.emit('pipchange', true);\n }\n }\n\n exitPiP() {\n if (document.pictureInPictureElement) {\n document.exitPictureInPicture();\n this.state.pip = false;\n this.emit('pipchange', false);\n }\n }\n\n togglePiP() {\n if (this.state.pip) {\n this.exitPiP();\n } else {\n this.enterPiP();\n }\n }\n\n // Captions\n enableCaptions() {\n if (this.captionManager) {\n this.captionManager.enable();\n this.state.captionsEnabled = true;\n }\n }\n\n disableCaptions() {\n if (this.captionManager) {\n this.captionManager.disable();\n this.state.captionsEnabled = false;\n }\n }\n\n toggleCaptions() {\n if (this.state.captionsEnabled) {\n this.disableCaptions();\n } else {\n this.enableCaptions();\n }\n }\n\n /**\n * Check if a track file exists\n * @param {string} url - Track file URL\n * @returns {Promise<boolean>} - True if file exists\n */\n async validateTrackExists(url) {\n try {\n const response = await fetch(url, { method: 'HEAD', cache: 'no-cache' });\n return response.ok;\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Strip VTT formatting tags from caption text\n * @param {string} text - Caption text with VTT formatting\n * @returns {string} Plain text without formatting\n */\n stripVTTFormatting(text) {\n if (!text) return '';\n return text\n .replace(/<[^>]+>/g, '') // Remove all HTML/VTT tags\n .replace(/\\n/g, ' ') // Replace newlines with spaces\n .trim()\n .toLowerCase(); // Normalize to lowercase for comparison\n }\n\n /**\n * Find matching caption time based on text content\n * Useful for syncing between videos of different lengths (e.g., with/without audio description)\n * @param {string} targetText - Caption text to search for\n * @param {Array} tracks - Array of caption tracks to search in\n * @returns {number|null} Start time of matching caption, or null if not found\n */\n findMatchingCaptionTime(targetText, tracks) {\n if (!targetText || !tracks || tracks.length === 0) {\n return null;\n }\n\n const normalizedTarget = this.stripVTTFormatting(targetText);\n \n // Search through all caption/subtitle tracks\n for (const trackInfo of tracks) {\n if (trackInfo.kind !== 'captions' && trackInfo.kind !== 'subtitles') {\n continue;\n }\n\n const track = trackInfo.track;\n if (!track || !track.cues) {\n continue;\n }\n\n // Search through all cues in this track\n for (let i = 0; i < track.cues.length; i++) {\n const cue = track.cues[i];\n const cueText = this.stripVTTFormatting(cue.text);\n \n // Check for exact match or very similar match (at least 80% of words match)\n if (cueText === normalizedTarget) {\n return cue.startTime;\n }\n \n // Fuzzy matching: check if most words match\n const targetWords = normalizedTarget.split(/\\s+/).filter(w => w.length > 2);\n const cueWords = cueText.split(/\\s+/).filter(w => w.length > 2);\n \n if (targetWords.length > 0 && cueWords.length > 0) {\n const matchingWords = targetWords.filter(word => cueWords.includes(word));\n const matchRatio = matchingWords.length / targetWords.length;\n \n // If 80% or more words match, consider it a match\n if (matchRatio >= 0.8) {\n return cue.startTime;\n }\n }\n }\n }\n\n return null;\n }\n\n // Audio Description\n async enableAudioDescription() {\n // Check if we have source elements with data-desc-src (even if audioDescriptionSrc is not set)\n const hasSourceElementsWithDesc = this.sourceElements.some(el => el.getAttribute('data-desc-src'));\n const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;\n \n if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {\n console.warn('VidPly: No audio description source, source elements, or tracks provided');\n return;\n }\n\n // Store current playback state\n // Use element.currentTime directly, not state, as state may not be up-to-date\n const currentTime = this.element.currentTime;\n const wasPlaying = this.state.playing;\n const shouldKeepPoster = !wasPlaying && currentTime === 0;\n \n // Try to find the current caption text for synchronization\n // This helps when switching between videos of different lengths\n let currentCaptionText = null;\n if (this.captionManager && this.captionManager.currentTrack) {\n const track = this.captionManager.currentTrack.track;\n if (track && track.activeCues && track.activeCues.length > 0) {\n const activeCue = track.activeCues[0];\n currentCaptionText = this.stripVTTFormatting(activeCue.text);\n }\n }\n \n // Store poster to preserve it during source swap\n // Convert relative paths to absolute URLs to prevent resolution issues\n const posterValue = this.resolvePosterPath(\n this.element.getAttribute('poster') || \n this.element.poster || \n this.options.poster\n );\n\n if (shouldKeepPoster) {\n this.showPosterOverlay();\n }\n\n // Store swapped tracks for transcript reload (declare at function scope)\n let swappedTracksForTranscript = [];\n\n // Switch to audio-described version\n // If we have a source element with audio description attributes, update that instead\n if (this.audioDescriptionSourceElement) {\n const currentSrc = this.element.currentSrc || this.element.src;\n \n // Find the source element that matches the currently active source\n const sourceElements = this.sourceElements;\n let sourceElementToUpdate = null;\n let descSrc = this.audioDescriptionSrc;\n \n for (const sourceEl of sourceElements) {\n const sourceSrc = sourceEl.getAttribute('src');\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\n \n // Check if this source matches the current source (by filename)\n // Match by full path or just filename\n const sourceFilename = sourceSrc ? sourceSrc.split('/').pop() : '';\n const currentFilename = currentSrc ? currentSrc.split('/').pop() : '';\n \n if (currentSrc && (currentSrc === sourceSrc || \n currentSrc.includes(sourceSrc) || \n currentSrc.includes(sourceFilename) ||\n (sourceFilename && currentFilename === sourceFilename))) {\n sourceElementToUpdate = sourceEl;\n if (descSrcAttr) {\n descSrc = descSrcAttr;\n } else if (sourceSrc) {\n // If no data-desc-src, try to construct it from the source\n // But prefer the stored audioDescriptionSrc if available\n descSrc = this.audioDescriptionSrc || descSrc;\n }\n break;\n }\n }\n \n // If we didn't find a match, use the stored source element\n if (!sourceElementToUpdate) {\n sourceElementToUpdate = this.audioDescriptionSourceElement;\n // Ensure we have the correct descSrc from the stored element\n const storedDescSrc = sourceElementToUpdate.getAttribute('data-desc-src');\n if (storedDescSrc) {\n descSrc = storedDescSrc;\n }\n }\n \n // Swap caption tracks to described versions BEFORE loading\n if (this.audioDescriptionCaptionTracks.length > 0) {\n // Swap tracks: validate explicit tracks, but try auto-detected tracks without validation\n // This avoids 404 errors while still allowing auto-detection to work\n const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {\n if (trackInfo.trackElement && trackInfo.describedSrc) {\n // Only validate explicitly defined tracks (to confirm they exist)\n // Auto-detected tracks are used without validation (browser will handle missing files gracefully)\n if (trackInfo.explicit === true) {\n try {\n const exists = await this.validateTrackExists(trackInfo.describedSrc);\n return { trackInfo, exists };\n } catch (error) {\n // Silently handle validation errors\n return { trackInfo, exists: false };\n }\n } else {\n // This shouldn't happen since auto-detection is disabled\n // But if it does, don't validate to avoid 404s\n return { trackInfo, exists: false };\n }\n }\n return { trackInfo, exists: false };\n });\n \n const validationResults = await Promise.all(validationPromises);\n const tracksToSwap = validationResults.filter(result => result.exists);\n \n if (tracksToSwap.length > 0) {\n // Store original track modes before removing tracks\n const trackModes = new Map();\n tracksToSwap.forEach(({ trackInfo }) => {\n const textTrack = trackInfo.trackElement.track;\n if (textTrack) {\n trackModes.set(trackInfo, {\n wasShowing: textTrack.mode === 'showing',\n wasHidden: textTrack.mode === 'hidden'\n });\n } else {\n trackModes.set(trackInfo, {\n wasShowing: false,\n wasHidden: false\n });\n }\n });\n \n // Store all track information before removing\n const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {\n const oldSrc = trackInfo.trackElement.getAttribute('src');\n const parent = trackInfo.trackElement.parentNode;\n const nextSibling = trackInfo.trackElement.nextSibling;\n \n // Store all attributes from the old track\n const attributes = {};\n Array.from(trackInfo.trackElement.attributes).forEach(attr => {\n attributes[attr.name] = attr.value;\n });\n \n return {\n trackInfo,\n oldSrc,\n parent,\n nextSibling,\n attributes\n };\n });\n \n // Remove ALL old tracks first to force browser to clear TextTrack objects\n tracksToReadd.forEach(({ trackInfo }) => {\n trackInfo.trackElement.remove();\n });\n \n // Force browser to process the removal by calling load()\n this.element.load();\n \n // Wait for browser to process the removal, then add new tracks\n // Use await to ensure this completes before continuing\n await new Promise(resolve => {\n setTimeout(() => {\n tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {\n swappedTracksForTranscript.push(trackInfo);\n \n // Create a completely new track element (not a clone) to force browser to create new TextTrack\n const newTrackElement = document.createElement('track');\n newTrackElement.setAttribute('src', trackInfo.describedSrc);\n \n // Copy all attributes except src and data-desc-src\n Object.keys(attributes).forEach(attrName => {\n if (attrName !== 'src' && attrName !== 'data-desc-src') {\n newTrackElement.setAttribute(attrName, attributes[attrName]);\n }\n });\n \n // Insert new track element\n if (nextSibling && nextSibling.parentNode) {\n parent.insertBefore(newTrackElement, nextSibling);\n } else {\n parent.appendChild(newTrackElement);\n }\n \n // Update reference to the new track element\n trackInfo.trackElement = newTrackElement;\n });\n \n this.invalidateTrackCache();\n \n // Wait for loadedmetadata event before accessing new TextTrack objects\n const setupNewTracks = () => {\n // Wait a bit more for browser to fully process the new track elements\n this.setManagedTimeout(() => {\n swappedTracksForTranscript.forEach((trackInfo) => {\n const trackElement = trackInfo.trackElement;\n const newTextTrack = trackElement.track;\n \n if (newTextTrack) {\n // Get original mode from stored map\n const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };\n \n // Set mode to load the new track\n newTextTrack.mode = 'hidden'; // Use hidden to load cues without showing\n \n // Restore original mode after track loads\n // Note: CaptionManager will handle enabling captions separately\n const restoreMode = () => {\n if (modeInfo.wasShowing) {\n // Set to hidden - CaptionManager will set it to showing when it enables\n newTextTrack.mode = 'hidden';\n } else if (modeInfo.wasHidden) {\n newTextTrack.mode = 'hidden';\n } else {\n newTextTrack.mode = 'disabled';\n }\n };\n \n // Wait for track to load\n if (newTextTrack.readyState >= 2) { // LOADED\n restoreMode();\n } else {\n newTextTrack.addEventListener('load', restoreMode, { once: true });\n newTextTrack.addEventListener('error', restoreMode, { once: true });\n }\n }\n });\n }, 300); // Additional wait for browser to process track elements\n };\n \n // Wait for loadedmetadata event which fires when browser processes track elements\n if (this.element.readyState >= 1) { // HAVE_METADATA\n // Already loaded, wait a bit and setup\n setTimeout(setupNewTracks, 200);\n } else {\n this.element.addEventListener('loadedmetadata', setupNewTracks, { once: true });\n // Fallback timeout\n setTimeout(setupNewTracks, 2000);\n }\n \n resolve();\n }, 100);\n }); // Wait 100ms after first load() before adding new tracks\n \n const skippedCount = validationResults.length - tracksToSwap.length;\n }\n }\n \n // Update all source elements that have data-desc-src to their described versions\n // Force browser to pick up changes by removing and re-adding source elements\n // Get source elements (may have been defined in if block above, but get fresh list here)\n const allSourceElements = this.sourceElements;\n const sourcesToUpdate = [];\n \n allSourceElements.forEach((sourceEl) => {\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\n const currentSrc = sourceEl.getAttribute('src');\n \n if (descSrcAttr) {\n const type = sourceEl.getAttribute('type');\n let origSrc = sourceEl.getAttribute('data-orig-src');\n \n // Store current src as data-orig-src if not already set\n if (!origSrc) {\n origSrc = currentSrc;\n }\n \n // Store info for re-adding with described src\n sourcesToUpdate.push({\n src: descSrcAttr, // Use described version\n type: type,\n origSrc: origSrc,\n descSrc: descSrcAttr\n });\n } else {\n // Source element without data-desc-src - keep as-is\n const type = sourceEl.getAttribute('type');\n const src = sourceEl.getAttribute('src');\n sourcesToUpdate.push({\n src: src,\n type: type,\n origSrc: null,\n descSrc: null\n });\n }\n });\n \n // Remove src attribute if present (video with src can't have source elements per HTML spec)\n const hasSrcAttribute = this.element.hasAttribute('src');\n const srcValue = hasSrcAttribute ? this.element.getAttribute('src') : null;\n if (hasSrcAttribute) {\n this.element.removeAttribute('src');\n }\n \n // Remove all source elements\n allSourceElements.forEach(sourceEl => {\n sourceEl.remove();\n });\n \n // Re-add them with updated src attributes (described versions)\n sourcesToUpdate.forEach(sourceInfo => {\n const newSource = document.createElement('source');\n newSource.setAttribute('src', sourceInfo.src);\n if (sourceInfo.type) {\n newSource.setAttribute('type', sourceInfo.type);\n }\n if (sourceInfo.origSrc) {\n newSource.setAttribute('data-orig-src', sourceInfo.origSrc);\n }\n if (sourceInfo.descSrc) {\n newSource.setAttribute('data-desc-src', sourceInfo.descSrc);\n }\n const firstTrack = this.element.querySelector('track');\n if (firstTrack) {\n this.element.insertBefore(newSource, firstTrack);\n } else {\n this.element.appendChild(newSource);\n }\n });\n\n // Ensure cached source references are refreshed after rebuilding the list\n this._sourceElementsDirty = true;\n this._sourceElementsCache = null;\n \n // Preserve poster before reload\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n \n // Force reload by calling load() on the element\n // This should pick up the new src attributes from the re-added source elements\n // and also reload the track elements\n this.element.load();\n \n // Wait for new source to load metadata\n await new Promise((resolve) => {\n const onLoadedMetadata = () => {\n this.element.removeEventListener('loadedmetadata', onLoadedMetadata);\n resolve();\n };\n \n if (this.element.readyState >= 1) {\n // Metadata already loaded\n resolve();\n } else {\n this.element.addEventListener('loadedmetadata', onLoadedMetadata);\n }\n });\n \n // Wait a bit more for tracks to be recognized and loaded after video metadata loads\n await new Promise(resolve => setTimeout(resolve, 300));\n\n // If we need to seek and/or play, wait for enough data to be loaded\n if (currentTime > 0 || wasPlaying) {\n await new Promise((resolve) => {\n const onCanPlay = () => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n };\n \n // Check if already ready\n if (this.element.readyState >= 3) { // HAVE_FUTURE_DATA or better\n resolve();\n } else {\n // Wait for canplay or canplaythrough\n this.element.addEventListener('canplay', onCanPlay, { once: true });\n this.element.addEventListener('canplaythrough', onCanPlay, { once: true });\n \n // Fallback timeout in case events don't fire\n setTimeout(() => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n }, 3000);\n }\n });\n }\n\n // Try to find matching caption in the new track for better synchronization\n let syncTime = currentTime;\n if (currentCaptionText && this.captionManager && this.captionManager.tracks.length > 0) {\n // Wait a bit for tracks to load\n await new Promise(resolve => setTimeout(resolve, 500));\n \n // Find the matching caption in the described video's track\n const matchingTime = this.findMatchingCaptionTime(currentCaptionText, this.captionManager.tracks);\n if (matchingTime !== null) {\n syncTime = matchingTime;\n if (this.options.debug) {\n console.log(`[VidPly] Syncing via caption: ${currentTime}s -> ${syncTime}s`);\n }\n }\n }\n\n // Restore playback position (avoid forcing first frame if still at start)\n if (syncTime > 0) {\n this.seek(syncTime);\n // Wait a bit for seek to complete\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n if (wasPlaying) {\n await this.play();\n // Hide poster when playing - use setTimeout to ensure play event has fired\n this.setManagedTimeout(() => {\n this.hidePosterOverlay();\n }, 100);\n } else {\n // Explicitly pause the video if it wasn't playing\n // This ensures it's in a clean paused state after load()\n this.pause();\n if (!shouldKeepPoster) {\n this.hidePosterOverlay();\n }\n }\n\n // Update state and emit event\n if (!this._audioDescriptionDesiredState) {\n return;\n }\n this.state.audioDescriptionEnabled = true;\n this.emit('audiodescriptionenabled');\n } else {\n // Fallback to updating element src directly\n // Swap caption tracks to described versions BEFORE loading\n if (this.audioDescriptionCaptionTracks.length > 0) {\n // Swap tracks: validate explicit tracks, but try auto-detected tracks without validation\n const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {\n if (trackInfo.trackElement && trackInfo.describedSrc) {\n // Only validate explicitly defined tracks\n // Auto-detected tracks are used without validation (no 404s)\n if (trackInfo.explicit === true) {\n try {\n const exists = await this.validateTrackExists(trackInfo.describedSrc);\n return { trackInfo, exists };\n } catch (error) {\n return { trackInfo, exists: false };\n }\n } else {\n // This shouldn't happen since auto-detection is disabled\n return { trackInfo, exists: false };\n }\n }\n return { trackInfo, exists: false };\n });\n \n const validationResults = await Promise.all(validationPromises);\n const tracksToSwap = validationResults.filter(result => result.exists);\n \n if (tracksToSwap.length > 0) {\n // Store original track modes before removing tracks\n const trackModes = new Map();\n tracksToSwap.forEach(({ trackInfo }) => {\n const textTrack = trackInfo.trackElement.track;\n if (textTrack) {\n trackModes.set(trackInfo, {\n wasShowing: textTrack.mode === 'showing',\n wasHidden: textTrack.mode === 'hidden'\n });\n } else {\n trackModes.set(trackInfo, {\n wasShowing: false,\n wasHidden: false\n });\n }\n });\n \n // Store all track information before removing\n const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {\n const oldSrc = trackInfo.trackElement.getAttribute('src');\n const parent = trackInfo.trackElement.parentNode;\n const nextSibling = trackInfo.trackElement.nextSibling;\n \n // Store all attributes from the old track\n const attributes = {};\n Array.from(trackInfo.trackElement.attributes).forEach(attr => {\n attributes[attr.name] = attr.value;\n });\n \n return {\n trackInfo,\n oldSrc,\n parent,\n nextSibling,\n attributes\n };\n });\n \n // Remove ALL old tracks first to force browser to clear TextTrack objects\n tracksToReadd.forEach(({ trackInfo }) => {\n trackInfo.trackElement.remove();\n });\n \n // Force browser to process the removal by calling load()\n this.element.load();\n \n // Wait for browser to process the removal, then add new tracks\n setTimeout(() => {\n tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {\n swappedTracksForTranscript.push(trackInfo);\n \n // Create a completely new track element (not a clone) to force browser to create new TextTrack\n const newTrackElement = document.createElement('track');\n newTrackElement.setAttribute('src', trackInfo.describedSrc);\n \n // Copy all attributes except src and data-desc-src\n Object.keys(attributes).forEach(attrName => {\n if (attrName !== 'src' && attrName !== 'data-desc-src') {\n newTrackElement.setAttribute(attrName, attributes[attrName]);\n }\n });\n \n // Insert new track element at the beginning (before any flow content) for HTML5 validity\n const firstChild = parent.firstChild;\n if (firstChild && firstChild.nodeType === Node.ELEMENT_NODE && firstChild.tagName !== 'TRACK') {\n parent.insertBefore(newTrackElement, firstChild);\n } else if (nextSibling && nextSibling.parentNode) {\n parent.insertBefore(newTrackElement, nextSibling);\n } else {\n parent.appendChild(newTrackElement);\n }\n \n // Update reference to the new track element\n trackInfo.trackElement = newTrackElement;\n });\n \n // After all new tracks are added, force browser to reload media element again\n this.element.load();\n \n // Wait for loadedmetadata event before accessing new TextTrack objects\n const setupNewTracks = () => {\n // Wait a bit more for browser to fully process the new track elements\n setTimeout(() => {\n swappedTracksForTranscript.forEach((trackInfo) => {\n const trackElement = trackInfo.trackElement;\n const newTextTrack = trackElement.track;\n \n if (newTextTrack) {\n // Get original mode from stored map\n const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };\n \n // Set mode to load the new track\n newTextTrack.mode = 'hidden'; // Use hidden to load cues without showing\n \n // Restore original mode after track loads\n const restoreMode = () => {\n if (modeInfo.wasShowing) {\n // Set to hidden - CaptionManager will set it to showing when it enables\n newTextTrack.mode = 'hidden';\n } else if (modeInfo.wasHidden) {\n newTextTrack.mode = 'hidden';\n } else {\n newTextTrack.mode = 'disabled';\n }\n };\n \n // Wait for track to load\n if (newTextTrack.readyState >= 2) { // LOADED\n restoreMode();\n } else {\n newTextTrack.addEventListener('load', restoreMode, { once: true });\n newTextTrack.addEventListener('error', restoreMode, { once: true });\n }\n }\n });\n }, 300); // Additional wait for browser to process track elements\n };\n \n // Wait for loadedmetadata event which fires when browser processes track elements\n if (this.element.readyState >= 1) { // HAVE_METADATA\n // Already loaded, wait a bit and setup\n setTimeout(setupNewTracks, 200);\n } else {\n this.element.addEventListener('loadedmetadata', setupNewTracks, { once: true });\n // Fallback timeout\n setTimeout(setupNewTracks, 2000);\n }\n }, 100); // Wait 100ms after first load() before adding new tracks\n }\n }\n \n // Check if we have source elements with data-desc-src (fallback method)\n const fallbackSourceElements = this.sourceElements;\n const hasSourceElementsWithDesc = fallbackSourceElements.some(el => el.getAttribute('data-desc-src'));\n \n if (hasSourceElementsWithDesc) {\n const fallbackSourcesToUpdate = [];\n \n fallbackSourceElements.forEach((sourceEl) => {\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\n const currentSrc = sourceEl.getAttribute('src');\n \n if (descSrcAttr) {\n const type = sourceEl.getAttribute('type');\n let origSrc = sourceEl.getAttribute('data-orig-src');\n \n if (!origSrc) {\n origSrc = currentSrc;\n }\n \n fallbackSourcesToUpdate.push({\n src: descSrcAttr,\n type: type,\n origSrc: origSrc,\n descSrc: descSrcAttr\n });\n } else {\n const type = sourceEl.getAttribute('type');\n const src = sourceEl.getAttribute('src');\n fallbackSourcesToUpdate.push({\n src: src,\n type: type,\n origSrc: null,\n descSrc: null\n });\n }\n });\n \n // Remove all source elements\n fallbackSourceElements.forEach(sourceEl => {\n sourceEl.remove();\n });\n \n // Re-add them with updated src attributes\n fallbackSourcesToUpdate.forEach(sourceInfo => {\n const newSource = document.createElement('source');\n newSource.setAttribute('src', sourceInfo.src);\n if (sourceInfo.type) {\n newSource.setAttribute('type', sourceInfo.type);\n }\n if (sourceInfo.origSrc) {\n newSource.setAttribute('data-orig-src', sourceInfo.origSrc);\n }\n if (sourceInfo.descSrc) {\n newSource.setAttribute('data-desc-src', sourceInfo.descSrc);\n }\n this.element.appendChild(newSource);\n });\n \n // Preserve poster before reload\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n \n // Force reload\n this.element.load();\n this.invalidateTrackCache();\n } else {\n // Fallback to updating element src directly (for videos without source elements)\n // Preserve poster before changing src\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n this.element.src = this.audioDescriptionSrc;\n }\n }\n\n // Wait for new source to load metadata\n await new Promise((resolve) => {\n const onLoadedMetadata = () => {\n this.element.removeEventListener('loadedmetadata', onLoadedMetadata);\n resolve();\n };\n \n if (this.element.readyState >= 1) {\n // Metadata already loaded\n resolve();\n } else {\n this.element.addEventListener('loadedmetadata', onLoadedMetadata);\n }\n });\n\n // If we need to seek and/or play, wait for enough data to be loaded\n if (currentTime > 0 || wasPlaying) {\n await new Promise((resolve) => {\n const onCanPlay = () => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n };\n \n // Check if already ready\n if (this.element.readyState >= 3) { // HAVE_FUTURE_DATA or better\n resolve();\n } else {\n // Wait for canplay or canplaythrough\n this.element.addEventListener('canplay', onCanPlay, { once: true });\n this.element.addEventListener('canplaythrough', onCanPlay, { once: true });\n \n // Fallback timeout in case events don't fire\n setTimeout(() => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n }, 3000);\n }\n });\n }\n\n // Hide poster if video hasn't started yet (poster should hide when we seek or play)\n if (this.element.tagName === 'VIDEO' && currentTime === 0 && !wasPlaying) {\n // Force poster to hide by doing a minimal seek or loading first frame\n // Setting readyState check or seeking to 0.001 seconds will hide the poster\n if (this.element.readyState >= 1) { // HAVE_METADATA\n // Seek to a tiny fraction to trigger poster hiding without actually moving\n this.element.currentTime = 0.001;\n // Then seek back to 0 after a brief moment to ensure poster stays hidden\n this.setManagedTimeout(() => {\n this.element.currentTime = 0;\n }, 10);\n }\n }\n\n // Try to find matching caption in the new track for better synchronization\n let syncTime = currentTime;\n if (currentCaptionText && this.captionManager && this.captionManager.tracks.length > 0) {\n // Wait a bit for tracks to load\n await new Promise(resolve => setTimeout(resolve, 500));\n \n // Find the matching caption in the described video's track\n const matchingTime = this.findMatchingCaptionTime(currentCaptionText, this.captionManager.tracks);\n if (matchingTime !== null) {\n syncTime = matchingTime;\n if (this.options.debug) {\n console.log(`[VidPly] Syncing via caption: ${currentTime}s -> ${syncTime}s`);\n }\n }\n }\n\n // Restore playback position (avoid forcing first frame if still at start)\n if (syncTime > 0) {\n this.seek(syncTime);\n // Wait a bit for seek to complete\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n if (wasPlaying) {\n await this.play();\n // Hide poster when playing - use setTimeout to ensure play event has fired\n this.setManagedTimeout(() => {\n this.hidePosterOverlay();\n }, 100);\n } else {\n // Explicitly pause the video if it wasn't playing\n // This ensures it's in a clean paused state after load()\n this.pause();\n if (!shouldKeepPoster) {\n this.hidePosterOverlay();\n }\n }\n\n // Reload CaptionManager tracks if tracks were swapped (so it has fresh references)\n if (swappedTracksForTranscript.length > 0 && this.captionManager) {\n // Store if captions were enabled and which track\n const wasCaptionsEnabled = this.state.captionsEnabled;\n let currentTrackInfo = null;\n if (this.captionManager.currentTrack) {\n const currentTrackIndex = this.captionManager.tracks.findIndex(t => t.track === this.captionManager.currentTrack.track);\n if (currentTrackIndex >= 0) {\n currentTrackInfo = {\n language: this.captionManager.tracks[currentTrackIndex].language,\n kind: this.captionManager.tracks[currentTrackIndex].kind\n };\n }\n }\n \n // Wait for new tracks to be available and loaded, then reload\n // Use a longer timeout and wait for track load events\n const reloadTracks = () => {\n // Reload tracks to get fresh references to new TextTrack objects\n this.captionManager.tracks = [];\n this.captionManager.loadTracks();\n \n // Re-enable captions if they were enabled before\n if (wasCaptionsEnabled && currentTrackInfo && this.captionManager.tracks.length > 0) {\n // Find the track by language and kind to match the swapped track\n const matchingTrackIndex = this.captionManager.tracks.findIndex(t => \n t.language === currentTrackInfo.language && t.kind === currentTrackInfo.kind\n );\n \n if (matchingTrackIndex >= 0) {\n const trackToEnable = this.captionManager.tracks[matchingTrackIndex];\n // Wait for track to load its cues before enabling\n if (trackToEnable.track.readyState >= 2) {\n // Track is already loaded\n this.captionManager.enable(matchingTrackIndex);\n } else {\n // Wait for track to load\n const onTrackLoad = () => {\n trackToEnable.track.removeEventListener('load', onTrackLoad);\n trackToEnable.track.removeEventListener('error', onTrackLoad);\n if (this.captionManager && this.captionManager.tracks.includes(trackToEnable)) {\n this.captionManager.enable(matchingTrackIndex);\n }\n };\n trackToEnable.track.addEventListener('load', onTrackLoad, { once: true });\n trackToEnable.track.addEventListener('error', onTrackLoad, { once: true });\n // Set mode to 'hidden' to trigger loading\n trackToEnable.track.mode = 'hidden';\n // Fallback timeout\n setTimeout(() => {\n if (this.captionManager && this.captionManager.tracks.includes(trackToEnable)) {\n this.captionManager.enable(matchingTrackIndex);\n }\n }, 1000);\n }\n } else if (this.captionManager.tracks.length > 0) {\n // Fallback: enable first track\n const firstTrack = this.captionManager.tracks[0];\n if (firstTrack.track.readyState >= 2) {\n this.captionManager.enable(0);\n } else {\n const onTrackLoad = () => {\n firstTrack.track.removeEventListener('load', onTrackLoad);\n firstTrack.track.removeEventListener('error', onTrackLoad);\n if (this.captionManager && this.captionManager.tracks.includes(firstTrack)) {\n this.captionManager.enable(0);\n }\n };\n firstTrack.track.addEventListener('load', onTrackLoad, { once: true });\n firstTrack.track.addEventListener('error', onTrackLoad, { once: true });\n firstTrack.track.mode = 'hidden';\n setTimeout(() => {\n if (this.captionManager && this.captionManager.tracks.includes(firstTrack)) {\n this.captionManager.enable(0);\n }\n }, 1000);\n }\n }\n }\n };\n \n // Wait for tracks to be processed by the browser\n setTimeout(reloadTracks, 600);\n }\n\n // Reload transcript if visible (after video metadata loaded, tracks should be available)\n // Reload regardless of whether caption tracks were swapped, in case tracks changed\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n // Wait for tracks to load after source swap\n // If tracks were swapped, wait for them to load; otherwise wait a bit for any track changes\n const swappedTracks = typeof swappedTracksForTranscript !== 'undefined' ? swappedTracksForTranscript : [];\n \n if (swappedTracks.length > 0) {\n // Wait for swapped tracks to load their new cues\n // Since we re-added track elements and called load(), wait for loadedmetadata event\n // which is when the browser processes track elements\n const onMetadataLoaded = () => {\n // Get fresh track references from the video element's textTracks collection\n // This ensures we get the actual textTrack objects that the browser created\n // Invalidate cache first to get fresh tracks after swap\n this.invalidateTrackCache();\n const allTextTracks = this.textTracks;\n \n // Find the tracks that match our swapped tracks by language and kind\n // Match by checking the track element's src attribute\n const freshTracks = swappedTracks.map((trackInfo) => {\n const trackEl = trackInfo.trackElement;\n const expectedSrc = trackEl.getAttribute('src');\n const srclang = trackEl.getAttribute('srclang');\n const kind = trackEl.getAttribute('kind');\n \n // Find matching track in textTracks collection\n // First try to match by the track element reference\n let foundTrack = allTextTracks.find(track => trackEl.track === track);\n \n // If not found, try matching by language and kind, but verify src\n if (!foundTrack) {\n foundTrack = allTextTracks.find(track => {\n if (track.language === srclang && \n (track.kind === kind || (kind === 'captions' && track.kind === 'subtitles'))) {\n // Verify the src matches\n const trackElementForTrack = this.findTrackElement(track);\n if (trackElementForTrack) {\n const actualSrc = trackElementForTrack.getAttribute('src');\n if (actualSrc === expectedSrc) {\n return true;\n }\n }\n }\n return false;\n });\n }\n \n // Verify the track element's src matches what we expect\n if (foundTrack) {\n const trackElement = this.findTrackElement(foundTrack);\n if (trackElement && trackElement.getAttribute('src') !== expectedSrc) {\n return null;\n }\n }\n \n return foundTrack;\n }).filter(Boolean);\n \n if (freshTracks.length === 0) {\n // Fallback: just reload after delay - transcript manager will find tracks itself\n this.setManagedTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n this.transcriptManager.loadTranscriptData();\n }\n }, 1000);\n return;\n }\n \n // Ensure tracks are in hidden mode to load cues for transcript\n freshTracks.forEach(track => {\n if (track.mode === 'disabled') {\n track.mode = 'hidden';\n }\n });\n \n let loadedCount = 0;\n const checkLoaded = () => {\n loadedCount++;\n if (loadedCount >= freshTracks.length) {\n // Give a bit more time for cues to be fully parsed\n // Also ensure we're getting the latest TextTrack references\n this.setManagedTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n // Force transcript manager to get fresh track references\n // Clear any cached track references by forcing a fresh read\n // The transcript manager will find tracks from this.element.textTracks\n // which should now have the new TextTrack objects with the described captions\n \n // Verify the tracks have the correct src before reloading transcript\n this.invalidateTrackCache();\n const allTextTracks = this.textTracks;\n const swappedTrackSrcs = swappedTracks.map(t => t.describedSrc);\n const hasCorrectTracks = freshTracks.some(track => {\n const trackEl = this.findTrackElement(track);\n return trackEl && swappedTrackSrcs.includes(trackEl.getAttribute('src'));\n });\n \n if (hasCorrectTracks || freshTracks.length > 0) {\n this.transcriptManager.loadTranscriptData();\n }\n }\n }, 800); // Increased wait time to ensure cues are fully loaded\n }\n };\n \n freshTracks.forEach(track => {\n // Ensure track is in hidden mode to load cues (required for transcript)\n if (track.mode === 'disabled') {\n track.mode = 'hidden';\n }\n \n // Check if track has cues loaded\n // Verify the track element's src matches the expected described src\n const trackElementForTrack = this.findTrackElement(track);\n const actualSrc = trackElementForTrack ? trackElementForTrack.getAttribute('src') : null;\n \n // Find the expected src from swappedTracks\n const expectedTrackInfo = swappedTracks.find(t => {\n const tEl = t.trackElement;\n return tEl && (tEl.track === track || \n (tEl.getAttribute('srclang') === track.language && \n tEl.getAttribute('kind') === track.kind));\n });\n const expectedSrc = expectedTrackInfo ? expectedTrackInfo.describedSrc : null;\n \n // Only proceed if the src matches (or we can't verify)\n if (expectedSrc && actualSrc && actualSrc !== expectedSrc) {\n // Wrong track, skip it\n checkLoaded(); // Count it as loaded to not block\n return;\n }\n \n if (track.readyState >= 2 && track.cues && track.cues.length > 0) { // LOADED with cues\n // Track already loaded with cues\n checkLoaded();\n } else {\n // Force track to load by setting mode\n if (track.mode === 'disabled') {\n track.mode = 'hidden';\n }\n \n // Wait for track to load\n const onTrackLoad = () => {\n // Wait a bit for cues to be fully parsed\n this.setManagedTimeout(checkLoaded, 300);\n };\n \n if (track.readyState >= 2) {\n // Already loaded, but might not have cues yet\n // Wait a bit and check again\n this.setManagedTimeout(() => {\n if (track.cues && track.cues.length > 0) {\n checkLoaded();\n } else {\n // Still no cues, wait for load event\n track.addEventListener('load', onTrackLoad, { once: true });\n }\n }, 100);\n } else {\n track.addEventListener('load', onTrackLoad, { once: true });\n track.addEventListener('error', () => {\n // Even on error, try to reload transcript\n checkLoaded();\n }, { once: true });\n }\n }\n });\n };\n \n // Wait for loadedmetadata event which fires when browser processes track elements\n // Also wait for the tracks to be fully processed after the second load()\n const waitForTracks = () => {\n // Wait a bit more to ensure new TextTrack objects are created\n this.setManagedTimeout(() => {\n if (this.element.readyState >= 1) { // HAVE_METADATA\n onMetadataLoaded();\n } else {\n this.element.addEventListener('loadedmetadata', onMetadataLoaded, { once: true });\n // Fallback timeout\n this.setManagedTimeout(onMetadataLoaded, 2000);\n }\n }, 500); // Wait 500ms after second load() for tracks to be processed\n };\n \n waitForTracks();\n \n // Fallback timeout - longer to ensure tracks are loaded\n setTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n this.transcriptManager.loadTranscriptData();\n }\n }, 5000);\n } else {\n // No tracks swapped, just wait a bit and reload\n setTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n this.transcriptManager.loadTranscriptData();\n }\n }, 800);\n }\n }\n\n if (!shouldKeepPoster) {\n this.hidePosterOverlay();\n }\n\n if (!this._audioDescriptionDesiredState) {\n return;\n }\n\n this.state.audioDescriptionEnabled = true;\n this.emit('audiodescriptionenabled');\n }\n\n async disableAudioDescription() {\n if (!this.originalSrc) {\n return;\n }\n\n // Store current playback state\n // Use element.currentTime directly, not state, as state may not be up-to-date\n const currentTime = this.element.currentTime;\n const wasPlaying = this.state.playing;\n \n // Try to find the current caption text for synchronization\n // This helps when switching between videos of different lengths\n let currentCaptionText = null;\n if (this.captionManager && this.captionManager.currentTrack) {\n const track = this.captionManager.currentTrack.track;\n if (track && track.activeCues && track.activeCues.length > 0) {\n const activeCue = track.activeCues[0];\n currentCaptionText = this.stripVTTFormatting(activeCue.text);\n }\n }\n \n // Store poster to preserve it during source swap\n // Convert relative paths to absolute URLs to prevent resolution issues\n const posterValue = this.resolvePosterPath(\n this.element.getAttribute('poster') || \n this.element.poster || \n this.options.poster\n );\n\n // Swap caption/chapter tracks back to original versions BEFORE loading\n // Store swapped tracks for transcript reload\n let swappedTracksForTranscript = [];\n if (this.audioDescriptionCaptionTracks.length > 0) {\n // Store track information before removing\n const tracksToRestore = this.audioDescriptionCaptionTracks.map((trackInfo) => {\n const trackElement = trackInfo.trackElement;\n if (!trackElement || !trackElement.parentNode) {\n return null;\n }\n \n const parent = trackElement.parentNode;\n const nextSibling = trackElement.nextSibling;\n \n // Store all attributes from the current track\n const attributes = {};\n Array.from(trackElement.attributes).forEach(attr => {\n attributes[attr.name] = attr.value;\n });\n \n return {\n trackInfo,\n parent,\n nextSibling,\n attributes\n };\n }).filter(Boolean);\n \n // Remove all current track elements\n tracksToRestore.forEach(({ trackInfo }) => {\n if (trackInfo.trackElement && trackInfo.trackElement.parentNode) {\n trackInfo.trackElement.remove();\n }\n });\n \n // Force browser to process the removal\n this.element.load();\n \n // Wait for browser to process the removal, then add original tracks back\n // Use await instead of setTimeout to ensure this completes before continuing\n await new Promise(resolve => {\n setTimeout(() => {\n tracksToRestore.forEach(({ trackInfo, parent, nextSibling, attributes }) => {\n swappedTracksForTranscript.push(trackInfo);\n \n // Create a new track element with the original src\n const newTrackElement = document.createElement('track');\n newTrackElement.setAttribute('src', trackInfo.originalTrackSrc);\n \n // Copy all attributes except src and data-desc-src\n Object.keys(attributes).forEach(attrName => {\n if (attrName !== 'src' && attrName !== 'data-desc-src') {\n newTrackElement.setAttribute(attrName, attributes[attrName]);\n }\n });\n \n // Keep data-desc-src for future swaps\n if (trackInfo.describedSrc) {\n newTrackElement.setAttribute('data-desc-src', trackInfo.describedSrc);\n }\n \n // Insert new track element\n if (nextSibling && nextSibling.parentNode) {\n parent.insertBefore(newTrackElement, nextSibling);\n } else {\n parent.appendChild(newTrackElement);\n }\n \n // Update reference to the new track element\n trackInfo.trackElement = newTrackElement;\n });\n \n this.invalidateTrackCache();\n resolve();\n }, 100);\n });\n }\n \n // Swap source elements back to original versions\n // Check if we have source elements with data-orig-src\n const allSourceElements = this.sourceElements;\n const hasSourceElementsToSwap = allSourceElements.some(el => el.getAttribute('data-orig-src'));\n \n if (hasSourceElementsToSwap) {\n const sourcesToRestore = [];\n \n allSourceElements.forEach((sourceEl) => {\n const origSrcAttr = sourceEl.getAttribute('data-orig-src');\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\n \n if (origSrcAttr) {\n // Swap back to original src\n const type = sourceEl.getAttribute('type');\n sourcesToRestore.push({\n src: origSrcAttr, // Use original version\n type: type,\n origSrc: origSrcAttr,\n descSrc: descSrcAttr // Keep data-desc-src for future swaps\n });\n } else {\n // Keep as-is (no data-orig-src means it wasn't swapped)\n const type = sourceEl.getAttribute('type');\n const src = sourceEl.getAttribute('src');\n sourcesToRestore.push({\n src: src,\n type: type,\n origSrc: null,\n descSrc: descSrcAttr\n });\n }\n });\n \n // Remove src attribute if present (video with src can't have source elements per HTML spec)\n const hasSrcAttribute = this.element.hasAttribute('src');\n const srcValue = hasSrcAttribute ? this.element.getAttribute('src') : null;\n if (hasSrcAttribute) {\n this.element.removeAttribute('src');\n }\n \n // Remove all source elements\n allSourceElements.forEach(sourceEl => {\n sourceEl.remove();\n });\n \n // Re-add them with original src attributes\n sourcesToRestore.forEach(sourceInfo => {\n const newSource = document.createElement('source');\n newSource.setAttribute('src', sourceInfo.src);\n if (sourceInfo.type) {\n newSource.setAttribute('type', sourceInfo.type);\n }\n if (sourceInfo.origSrc) {\n newSource.setAttribute('data-orig-src', sourceInfo.origSrc);\n }\n if (sourceInfo.descSrc) {\n newSource.setAttribute('data-desc-src', sourceInfo.descSrc);\n }\n const firstTrack = this.element.querySelector('track');\n if (firstTrack) {\n this.element.insertBefore(newSource, firstTrack);\n } else {\n this.element.appendChild(newSource);\n }\n });\n\n // Ensure cached source references are refreshed after rebuilding the list\n this._sourceElementsDirty = true;\n this._sourceElementsCache = null;\n \n // Preserve poster before reload\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n \n // Force reload\n this.element.load();\n } else {\n // Fallback to updating element src directly (for videos without source elements)\n // Preserve poster before changing src\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;\n this.element.src = originalSrcToUse;\n this.element.load();\n }\n\n // Wait for new source to load metadata\n await new Promise((resolve) => {\n const onLoadedMetadata = () => {\n this.element.removeEventListener('loadedmetadata', onLoadedMetadata);\n resolve();\n };\n \n if (this.element.readyState >= 1) {\n // Metadata already loaded\n resolve();\n } else {\n this.element.addEventListener('loadedmetadata', onLoadedMetadata);\n }\n });\n\n // If we need to seek and/or play, wait for enough data to be loaded\n if (currentTime > 0 || wasPlaying) {\n await new Promise((resolve) => {\n const onCanPlay = () => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n };\n \n // Check if already ready\n if (this.element.readyState >= 3) { // HAVE_FUTURE_DATA or better\n resolve();\n } else {\n // Wait for canplay or canplaythrough\n this.element.addEventListener('canplay', onCanPlay, { once: true });\n this.element.addEventListener('canplaythrough', onCanPlay, { once: true });\n \n // Fallback timeout in case events don't fire\n setTimeout(() => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n }, 3000);\n }\n });\n }\n\n // Try to find matching caption in the new track for better synchronization\n let syncTime = currentTime;\n if (currentCaptionText && this.captionManager && this.captionManager.tracks.length > 0) {\n // Wait a bit for tracks to load\n await new Promise(resolve => setTimeout(resolve, 500));\n \n // Find the matching caption in the regular video's track\n const matchingTime = this.findMatchingCaptionTime(currentCaptionText, this.captionManager.tracks);\n if (matchingTime !== null) {\n syncTime = matchingTime;\n if (this.options.debug) {\n console.log(`[VidPly] Syncing via caption: ${currentTime}s -> ${syncTime}s`);\n }\n }\n }\n\n if (syncTime > 0) {\n this.seek(syncTime);\n // Wait a bit for seek to complete\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n if (wasPlaying) {\n await this.play();\n this.hidePosterOverlay();\n } else {\n // Explicitly pause the video if it wasn't playing\n // This ensures it's in a clean paused state after load()\n this.pause();\n if (!wasPlaying && syncTime === 0) {\n this.showPosterOverlay();\n } else {\n this.hidePosterOverlay();\n }\n }\n\n // Reload CaptionManager tracks if tracks were swapped (so it has fresh references)\n if (swappedTracksForTranscript.length > 0 && this.captionManager) {\n // Store if captions were enabled and which track\n const wasCaptionsEnabled = this.state.captionsEnabled;\n let currentTrackInfo = null;\n if (this.captionManager.currentTrack) {\n const currentTrackIndex = this.captionManager.tracks.findIndex(t => t.track === this.captionManager.currentTrack.track);\n if (currentTrackIndex >= 0) {\n currentTrackInfo = {\n language: this.captionManager.tracks[currentTrackIndex].language,\n kind: this.captionManager.tracks[currentTrackIndex].kind\n };\n }\n }\n \n // Wait for tracks to be processed by the browser\n const reloadTracks = () => {\n // Reload tracks to get fresh references to new TextTrack objects\n this.captionManager.tracks = [];\n this.captionManager.loadTracks();\n \n // Re-enable captions if they were enabled before\n if (wasCaptionsEnabled && currentTrackInfo && this.captionManager.tracks.length > 0) {\n // Find the track by language and kind to match the swapped track\n const matchingTrackIndex = this.captionManager.tracks.findIndex(t => \n t.language === currentTrackInfo.language && t.kind === currentTrackInfo.kind\n );\n \n if (matchingTrackIndex >= 0) {\n const trackToEnable = this.captionManager.tracks[matchingTrackIndex];\n // Wait for track to load its cues before enabling\n if (trackToEnable.track.readyState >= 2) {\n // Track is already loaded\n this.captionManager.enable(matchingTrackIndex);\n } else {\n // Wait for track to load\n const onTrackLoad = () => {\n trackToEnable.track.removeEventListener('load', onTrackLoad);\n trackToEnable.track.removeEventListener('error', onTrackLoad);\n if (this.captionManager && this.captionManager.tracks.includes(trackToEnable)) {\n this.captionManager.enable(matchingTrackIndex);\n }\n };\n trackToEnable.track.addEventListener('load', onTrackLoad, { once: true });\n trackToEnable.track.addEventListener('error', onTrackLoad, { once: true });\n // Set mode to 'hidden' to trigger loading\n trackToEnable.track.mode = 'hidden';\n // Fallback timeout\n setTimeout(() => {\n if (this.captionManager && this.captionManager.tracks.includes(trackToEnable)) {\n this.captionManager.enable(matchingTrackIndex);\n }\n }, 1000);\n }\n } else if (this.captionManager.tracks.length > 0) {\n // Fallback: enable first track\n const firstTrack = this.captionManager.tracks[0];\n if (firstTrack.track.readyState >= 2) {\n this.captionManager.enable(0);\n } else {\n const onTrackLoad = () => {\n firstTrack.track.removeEventListener('load', onTrackLoad);\n firstTrack.track.removeEventListener('error', onTrackLoad);\n if (this.captionManager && this.captionManager.tracks.includes(firstTrack)) {\n this.captionManager.enable(0);\n }\n };\n firstTrack.track.addEventListener('load', onTrackLoad, { once: true });\n firstTrack.track.addEventListener('error', onTrackLoad, { once: true });\n firstTrack.track.mode = 'hidden';\n setTimeout(() => {\n if (this.captionManager && this.captionManager.tracks.includes(firstTrack)) {\n this.captionManager.enable(0);\n }\n }, 1000);\n }\n }\n }\n };\n \n // Wait for tracks to be processed by the browser\n setTimeout(reloadTracks, 600);\n }\n\n // Reload transcript if visible (after video metadata loaded, tracks should be available)\n // Reload regardless of whether caption tracks were swapped, in case tracks changed\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n // Wait for tracks to load after source swap\n this.setManagedTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n this.transcriptManager.loadTranscriptData();\n }\n }, 500);\n }\n\n if (this._audioDescriptionDesiredState) {\n return;\n }\n\n this.state.audioDescriptionEnabled = false;\n this.emit('audiodescriptiondisabled');\n }\n\n async toggleAudioDescription() {\n // Check if we have description tracks or audio-described video\n const descriptionTrack = this.findTextTrack('descriptions');\n \n // Check if we have audio-described video source (either from options or source elements with data-desc-src)\n const hasAudioDescriptionSrc = this.audioDescriptionSrc || \n this.sourceElements.some(el => el.getAttribute('data-desc-src'));\n \n if (descriptionTrack && hasAudioDescriptionSrc) {\n // We have both: toggle description track AND swap caption tracks/sources\n if (this.state.audioDescriptionEnabled) {\n this._audioDescriptionDesiredState = false;\n // Disable: toggle description track off and swap captions/sources back\n descriptionTrack.mode = 'hidden';\n await this.disableAudioDescription();\n } else {\n this._audioDescriptionDesiredState = true;\n // Enable: swap caption tracks/sources and toggle description track on\n await this.enableAudioDescription();\n // Wait for tracks to be ready after source swap, then enable description track\n // Use a longer timeout to ensure tracks are loaded after source swap\n const enableDescriptionTrack = () => {\n this.invalidateTrackCache();\n const descTrack = this.findTextTrack('descriptions');\n if (descTrack) {\n // Set to 'hidden' first if it's in 'disabled' mode, then to 'showing'\n if (descTrack.mode === 'disabled') {\n descTrack.mode = 'hidden';\n // Use setTimeout to ensure the browser processes the mode change\n this.setManagedTimeout(() => {\n descTrack.mode = 'showing';\n }, 50);\n } else {\n descTrack.mode = 'showing';\n }\n } else if (this.element.readyState < 2) {\n // Tracks not ready yet, wait a bit more\n this.setManagedTimeout(enableDescriptionTrack, 100);\n }\n };\n // Wait for metadata to load first\n if (this.element.readyState >= 1) {\n this.setManagedTimeout(enableDescriptionTrack, 200);\n } else {\n this.element.addEventListener('loadedmetadata', () => {\n this.setManagedTimeout(enableDescriptionTrack, 200);\n }, { once: true });\n }\n }\n } else if (descriptionTrack) {\n // Only description track, no audio-described video source to swap\n // Toggle description track\n if (descriptionTrack.mode === 'showing') {\n this._audioDescriptionDesiredState = false;\n descriptionTrack.mode = 'hidden';\n this.state.audioDescriptionEnabled = false;\n this.emit('audiodescriptiondisabled');\n } else {\n this._audioDescriptionDesiredState = true;\n descriptionTrack.mode = 'showing';\n this.state.audioDescriptionEnabled = true;\n this.emit('audiodescriptionenabled');\n }\n } else if (hasAudioDescriptionSrc) {\n // Use audio-described video source (no description track)\n if (this.state.audioDescriptionEnabled) {\n this._audioDescriptionDesiredState = false;\n await this.disableAudioDescription();\n } else {\n this._audioDescriptionDesiredState = true;\n await this.enableAudioDescription();\n }\n }\n }\n\n // Sign Language\n enableSignLanguage() {\n // Determine available sign language sources\n const hasMultipleSources = Object.keys(this.signLanguageSources).length > 0;\n const hasSingleSource = !!this.signLanguageSrc;\n \n if (!hasMultipleSources && !hasSingleSource) {\n console.warn('No sign language video source provided');\n return;\n }\n\n if (this.signLanguageWrapper) {\n // Already exists, just show it\n this.signLanguageWrapper.style.display = 'block';\n this.state.signLanguageEnabled = true;\n this.emit('signlanguageenabled');\n \n // Focus the settings button after wrapper is shown\n // Use setManagedTimeout to ensure it's properly scheduled\n this.setManagedTimeout(() => {\n if (this.signLanguageSettingsButton && document.contains(this.signLanguageSettingsButton)) {\n this.signLanguageSettingsButton.focus({ preventScroll: true });\n }\n }, 150);\n return;\n }\n \n // Determine initial sign language\n let initialLang = null;\n let initialSrc = null;\n \n if (hasMultipleSources) {\n // Try to sync with current caption language\n if (this.captionManager && this.captionManager.currentTrack) {\n const captionLang = this.captionManager.currentTrack.language?.toLowerCase().split('-')[0];\n if (captionLang && this.signLanguageSources[captionLang]) {\n initialLang = captionLang;\n initialSrc = this.signLanguageSources[captionLang];\n }\n }\n \n // If no match, try player language\n if (!initialLang && this.options.language) {\n const playerLang = this.options.language.toLowerCase().split('-')[0];\n if (this.signLanguageSources[playerLang]) {\n initialLang = playerLang;\n initialSrc = this.signLanguageSources[playerLang];\n }\n }\n \n // If still no match, use first available\n if (!initialLang) {\n initialLang = Object.keys(this.signLanguageSources)[0];\n initialSrc = this.signLanguageSources[initialLang];\n }\n \n this.currentSignLanguage = initialLang;\n } else {\n // Single source fallback\n initialSrc = this.signLanguageSrc;\n }\n\n // Create wrapper container\n this.signLanguageWrapper = document.createElement('div');\n this.signLanguageWrapper.className = 'vidply-sign-language-wrapper';\n this.signLanguageWrapper.setAttribute('tabindex', '0');\n this.signLanguageWrapper.setAttribute('aria-label', i18n.t('player.signLanguageDragResize'));\n\n // Create header (draggable)\n this.signLanguageHeader = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-language-header`,\n attributes: {\n 'tabindex': '0'\n }\n });\n\n // Header left side (title)\n const headerLeft = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-language-header-left`\n });\n\n const title = DOMUtils.createElement('h3', {\n textContent: i18n.t('player.signLanguageVideo')\n });\n\n // Settings button (before language selector)\n const settingsAriaLabel = i18n.t('player.signLanguageSettings');\n this.signLanguageSettingsButton = DOMUtils.createElement('button', {\n className: `${this.options.classPrefix}-sign-language-settings`,\n attributes: {\n 'type': 'button',\n 'aria-label': settingsAriaLabel,\n 'aria-expanded': 'false'\n }\n });\n this.signLanguageSettingsButton.appendChild(createIconElement('settings'));\n DOMUtils.attachTooltip(this.signLanguageSettingsButton, settingsAriaLabel, this.options.classPrefix);\n this.signLanguageSettingsHandlers = {\n settingsClick: (e) => {\n e.preventDefault();\n e.stopPropagation();\n // Stop the document click handler from interfering\n if (this.signLanguageDocumentClickHandler) {\n // Temporarily disable document click handler\n const wasJustOpened = this.signLanguageSettingsMenuJustOpened;\n this.signLanguageSettingsMenuJustOpened = true;\n setTimeout(() => {\n this.signLanguageSettingsMenuJustOpened = wasJustOpened;\n }, 100);\n }\n if (this.signLanguageSettingsMenuVisible) {\n this.hideSignLanguageSettingsMenu();\n } else {\n this.showSignLanguageSettingsMenu();\n }\n },\n settingsKeydown: (e) => {\n // D key to toggle keyboard drag mode\n if (e.key === 'd' || e.key === 'D') {\n e.preventDefault();\n e.stopPropagation();\n this.toggleSignLanguageKeyboardDragMode();\n }\n // R key to toggle resize mode\n else if (e.key === 'r' || e.key === 'R') {\n e.preventDefault();\n e.stopPropagation();\n this.toggleSignLanguageResizeMode();\n }\n // Escape to close menu if open\n else if (e.key === 'Escape' && this.signLanguageSettingsMenuVisible) {\n e.preventDefault();\n e.stopPropagation();\n this.hideSignLanguageSettingsMenu();\n }\n }\n };\n this.signLanguageSettingsButton.addEventListener('click', this.signLanguageSettingsHandlers.settingsClick);\n this.signLanguageSettingsButton.addEventListener('keydown', this.signLanguageSettingsHandlers.settingsKeydown);\n headerLeft.appendChild(this.signLanguageSettingsButton);\n\n // Language selector (if multiple sources available)\n this.signLanguageSelector = null;\n if (hasMultipleSources) {\n const selectId = `${this.options.classPrefix}-sign-language-select-${Date.now()}`;\n \n // Create options array\n const options = Object.keys(this.signLanguageSources).map(langCode => ({\n value: langCode,\n text: this.getSignLanguageLabel(langCode),\n selected: langCode === initialLang\n }));\n \n const { label: signLanguageLabel, select: signLanguageSelector } = createLabeledSelect({\n classPrefix: this.options.classPrefix,\n labelClass: `${this.options.classPrefix}-sign-language-label`,\n selectClass: `${this.options.classPrefix}-sign-language-select`,\n labelText: 'settings.language',\n selectId: selectId,\n options: options,\n onChange: (e) => {\n e.stopPropagation(); // Prevent event from bubbling\n const selectedLang = e.target.value;\n this.switchSignLanguage(selectedLang);\n }\n });\n \n this.signLanguageSelector = signLanguageSelector;\n \n // Wrap label and select in a container for horizontal layout\n const signLanguageSelectorWrapper = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-language-selector-wrapper`\n });\n signLanguageSelectorWrapper.appendChild(signLanguageLabel);\n signLanguageSelectorWrapper.appendChild(this.signLanguageSelector);\n \n // Prevent drag when interacting with wrapper\n preventDragOnElement(signLanguageSelectorWrapper);\n \n headerLeft.appendChild(signLanguageSelectorWrapper);\n }\n\n headerLeft.appendChild(title);\n \n // Close button\n const closeAriaLabel = i18n.t('player.closeSignLanguage');\n const closeButton = DOMUtils.createElement('button', {\n className: `${this.options.classPrefix}-sign-language-close`,\n attributes: {\n 'type': 'button',\n 'aria-label': closeAriaLabel\n }\n });\n closeButton.appendChild(createIconElement('close'));\n DOMUtils.attachTooltip(closeButton, closeAriaLabel, this.options.classPrefix);\n closeButton.addEventListener('click', () => {\n this.disableSignLanguage();\n // Return focus to sign language button if available\n if (this.controlBar && this.controlBar.controls && this.controlBar.controls.signLanguage) {\n setTimeout(() => {\n this.controlBar.controls.signLanguage.focus({ preventScroll: true });\n }, 0);\n }\n });\n\n this.signLanguageHeader.appendChild(headerLeft);\n this.signLanguageHeader.appendChild(closeButton);\n \n // Initialize settings menu state\n this.signLanguageSettingsMenuVisible = false;\n this.signLanguageSettingsMenu = null;\n this.signLanguageSettingsMenuJustOpened = false;\n this.signLanguageResizeOptionButton = null;\n this.signLanguageResizeOptionText = null;\n this.signLanguageDragOptionButton = null;\n this.signLanguageDragOptionText = null;\n this.signLanguageDocumentClickHandler = null;\n this.signLanguageDocumentClickHandlerAdded = false;\n\n // Create sign language video element\n this.signLanguageVideo = document.createElement('video');\n this.signLanguageVideo.className = 'vidply-sign-language-video';\n this.signLanguageVideo.src = initialSrc;\n this.signLanguageVideo.setAttribute('aria-label', i18n.t('player.signLanguage'));\n this.signLanguageVideo.muted = true; // Sign language video should be muted\n \n // Enable inline playback on iOS (prevents native fullscreen)\n this.signLanguageVideo.setAttribute('playsinline', '');\n\n // Create resize handles (8 directions like transcript)\n this.signLanguageResizeHandles = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'].map(dir => {\n const handle = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-resize-handle ${this.options.classPrefix}-sign-resize-${dir}`,\n attributes: {\n 'data-direction': dir,\n 'data-vidply-managed-resize': 'true',\n 'aria-hidden': 'true'\n }\n });\n handle.style.display = 'none';\n return handle;\n });\n\n // Append header, video and handles to wrapper\n this.signLanguageWrapper.appendChild(this.signLanguageHeader);\n this.signLanguageWrapper.appendChild(this.signLanguageVideo);\n this.signLanguageResizeHandles.forEach(handle => this.signLanguageWrapper.appendChild(handle));\n\n // Set width FIRST to ensure proper dimensions\n const saved = this.storage.getSignLanguagePreferences();\n if (saved && saved.size && saved.size.width) {\n this.signLanguageWrapper.style.width = saved.size.width;\n } else {\n this.signLanguageWrapper.style.width = '280px'; // Default width\n }\n // Height is always auto to maintain aspect ratio\n this.signLanguageWrapper.style.height = 'auto';\n \n // Position is always calculated fresh - use option or default to bottom-right\n this.signLanguageDesiredPosition = this.options.signLanguagePosition || 'bottom-right';\n\n // Add to main player container (NOT videoWrapper) to avoid overflow:hidden clipping\n this.container.appendChild(this.signLanguageWrapper);\n\n // Set position immediately after appending\n requestAnimationFrame(() => {\n this.constrainSignLanguagePosition();\n });\n\n // Sync with main video\n this.signLanguageVideo.currentTime = this.state.currentTime;\n if (!this.state.paused) {\n this.signLanguageVideo.play();\n }\n\n // Setup drag and resize\n this.setupSignLanguageInteraction();\n\n // Create bound handlers to store references for cleanup\n this.signLanguageHandlers = {\n play: () => {\n if (this.signLanguageVideo) {\n this.signLanguageVideo.play();\n }\n },\n pause: () => {\n if (this.signLanguageVideo) {\n this.signLanguageVideo.pause();\n }\n },\n timeupdate: () => {\n if (this.signLanguageVideo && Math.abs(this.signLanguageVideo.currentTime - this.state.currentTime) > 0.5) {\n this.signLanguageVideo.currentTime = this.state.currentTime;\n }\n },\n ratechange: () => {\n if (this.signLanguageVideo) {\n this.signLanguageVideo.playbackRate = this.state.playbackSpeed;\n }\n }\n };\n\n // Sync playback\n this.on('play', this.signLanguageHandlers.play);\n this.on('pause', this.signLanguageHandlers.pause);\n this.on('timeupdate', this.signLanguageHandlers.timeupdate);\n this.on('ratechange', this.signLanguageHandlers.ratechange);\n \n // Sync sign language when captions change (if multiple sources available)\n if (hasMultipleSources) {\n this.signLanguageHandlers.captionChange = () => {\n if (this.captionManager && this.captionManager.currentTrack && this.signLanguageSelector) {\n const captionLang = this.captionManager.currentTrack.language?.toLowerCase().split('-')[0];\n if (captionLang && this.signLanguageSources[captionLang] && this.currentSignLanguage !== captionLang) {\n this.switchSignLanguage(captionLang);\n // Update selector\n this.signLanguageSelector.value = captionLang;\n }\n }\n };\n // Listen to captionsenabled which fires when a track is enabled (including when switching)\n this.on('captionsenabled', this.signLanguageHandlers.captionChange);\n }\n\n this.state.signLanguageEnabled = true;\n this.emit('signlanguageenabled');\n \n // Focus the settings button after wrapper is appended to DOM\n // Use setManagedTimeout to ensure it's properly scheduled\n this.setManagedTimeout(() => {\n if (this.signLanguageSettingsButton && document.contains(this.signLanguageSettingsButton)) {\n this.signLanguageSettingsButton.focus({ preventScroll: true });\n }\n }, 150);\n }\n\n disableSignLanguage() {\n // Hide settings menu if open\n if (this.signLanguageSettingsMenuVisible) {\n this.hideSignLanguageSettingsMenu({ focusButton: false });\n }\n \n if (this.signLanguageWrapper) {\n this.signLanguageWrapper.style.display = 'none';\n }\n this.state.signLanguageEnabled = false;\n this.emit('signlanguagedisabled');\n }\n\n toggleSignLanguage() {\n if (this.state.signLanguageEnabled) {\n this.disableSignLanguage();\n } else {\n this.enableSignLanguage();\n }\n }\n\n setupSignLanguageInteraction() {\n if (!this.signLanguageWrapper) return;\n\n // Check if we're on mobile and not in fullscreen\n const isMobile = window.innerWidth < 768;\n const isFullscreen = this.state.fullscreen;\n \n // On mobile devices (< 768px), only enable drag/resize in fullscreen\n // On desktop/tablets (>= 768px), always enable drag/resize\n if (isMobile && !isFullscreen) {\n // Destroy existing instance if exiting fullscreen on mobile\n if (this.signLanguageDraggable) {\n this.signLanguageDraggable.destroy();\n this.signLanguageDraggable = null;\n }\n return; // No drag/resize on mobile when not in fullscreen\n }\n\n // If already initialized, don't re-initialize\n if (this.signLanguageDraggable) {\n return;\n }\n\n // Create DraggableResizable utility with touch support\n // Use header as drag handle instead of video\n this.signLanguageDraggable = new DraggableResizable(this.signLanguageWrapper, {\n dragHandle: this.signLanguageHeader,\n resizeHandles: this.signLanguageResizeHandles,\n constrainToViewport: true,\n maintainAspectRatio: true,\n minWidth: 150,\n minHeight: 100,\n classPrefix: `${this.options.classPrefix}-sign`,\n keyboardDragKey: 'd',\n keyboardResizeKey: 'r',\n keyboardStep: 10,\n keyboardStepLarge: 50,\n pointerResizeIndicatorText: i18n.t('player.signLanguageResizeActive'),\n onPointerResizeToggle: (enabled) => {\n // Update resize handles visibility\n this.signLanguageResizeHandles.forEach(handle => {\n handle.style.display = enabled ? 'block' : 'none';\n });\n },\n onDragStart: (e) => {\n // Don't drag if clicking on close button, settings button, language selector, or settings menu\n if (e.target.closest(`.${this.options.classPrefix}-sign-language-close`) ||\n e.target.closest(`.${this.options.classPrefix}-sign-language-settings`) ||\n e.target.closest(`.${this.options.classPrefix}-sign-language-select`) ||\n e.target.closest(`.${this.options.classPrefix}-sign-language-label`) ||\n e.target.closest(`.${this.options.classPrefix}-sign-language-settings-menu`)) {\n return false; // Prevent drag\n }\n return true; // Allow drag\n }\n });\n\n // Add custom keyboard handler for special keys (Escape, Home)\n this.signLanguageCustomKeyHandler = (e) => {\n const key = e.key.toLowerCase();\n \n // Don't handle keys if settings menu is open (let menu handle them)\n if (this.signLanguageSettingsMenuVisible) {\n return;\n }\n \n if (key === 'home') {\n e.preventDefault();\n e.stopPropagation();\n if (this.signLanguageDraggable) {\n if (this.signLanguageDraggable.pointerResizeMode) {\n this.signLanguageDraggable.disablePointerResizeMode();\n }\n this.signLanguageDraggable.manuallyPositioned = false;\n this.constrainSignLanguagePosition();\n }\n return;\n }\n \n if (key === 'r') {\n e.preventDefault();\n e.stopPropagation();\n const enabled = this.toggleSignLanguageResizeMode();\n if (enabled) {\n this.signLanguageWrapper.focus({ preventScroll: true });\n }\n return;\n }\n \n if (key === 'escape') {\n e.preventDefault();\n e.stopPropagation();\n // Exit resize mode if active\n if (this.signLanguageDraggable && this.signLanguageDraggable.pointerResizeMode) {\n this.signLanguageDraggable.disablePointerResizeMode();\n return;\n }\n // Exit keyboard drag mode if active\n if (this.signLanguageDraggable && this.signLanguageDraggable.keyboardDragMode) {\n this.signLanguageDraggable.disableKeyboardDragMode();\n return;\n }\n // Close video if no modes are active\n this.disableSignLanguage();\n // Return focus to sign language button if available\n if (this.controlBar && this.controlBar.controls && this.controlBar.controls.signLanguage) {\n setTimeout(() => {\n this.controlBar.controls.signLanguage.focus({ preventScroll: true });\n }, 0);\n }\n return;\n }\n };\n \n this.signLanguageWrapper.addEventListener('keydown', this.signLanguageCustomKeyHandler);\n\n // Store for cleanup\n this.signLanguageInteractionHandlers = {\n draggable: this.signLanguageDraggable,\n headerKeyHandler: this.signLanguageHeaderKeyHandler,\n customKeyHandler: this.signLanguageCustomKeyHandler\n };\n }\n\n toggleSignLanguageKeyboardDragMode() {\n if (this.signLanguageDraggable) {\n const wasEnabled = this.signLanguageDraggable.keyboardDragMode;\n this.signLanguageDraggable.toggleKeyboardDragMode();\n const isEnabled = this.signLanguageDraggable.keyboardDragMode;\n if (!wasEnabled && isEnabled) {\n this.enableSignLanguageMoveMode();\n }\n // Update drag option state\n this.updateSignLanguageDragOptionState();\n }\n }\n\n enableSignLanguageMoveMode() {\n // Add visual feedback for move mode\n this.signLanguageWrapper.classList.add(`${this.options.classPrefix}-sign-move-mode`);\n \n // Update resize option state in case menu is open\n this.updateSignLanguageResizeOptionState();\n \n // Remove after 2 seconds\n setTimeout(() => {\n this.signLanguageWrapper.classList.remove(`${this.options.classPrefix}-sign-move-mode`);\n }, 2000);\n }\n\n toggleSignLanguageResizeMode({ focus = true } = {}) {\n if (!this.signLanguageDraggable) {\n return false;\n }\n\n if (this.signLanguageDraggable.pointerResizeMode) {\n this.signLanguageDraggable.disablePointerResizeMode({ focus });\n this.updateSignLanguageResizeOptionState();\n return false;\n }\n\n this.signLanguageDraggable.enablePointerResizeMode({ focus });\n this.updateSignLanguageResizeOptionState();\n return true;\n }\n\n getSignLanguageLabel(langCode) {\n // Get language label from i18n or use language code\n const langNames = {\n 'en': 'English',\n 'de': 'Deutsch',\n 'es': 'Español',\n 'fr': 'Français',\n 'it': 'Italiano',\n 'ja': '日本語',\n 'pt': 'Português',\n 'ar': 'العربية',\n 'hi': 'हिन्दी'\n };\n return langNames[langCode] || langCode.toUpperCase();\n }\n\n switchSignLanguage(langCode) {\n if (!this.signLanguageSources[langCode] || !this.signLanguageVideo) {\n return;\n }\n \n const currentTime = this.signLanguageVideo.currentTime;\n const wasPlaying = !this.signLanguageVideo.paused;\n \n this.signLanguageVideo.src = this.signLanguageSources[langCode];\n this.currentSignLanguage = langCode;\n \n // Restore playback state\n this.signLanguageVideo.currentTime = currentTime;\n if (wasPlaying) {\n this.signLanguageVideo.play().catch(() => {\n // Ignore play errors\n });\n }\n \n this.emit('signlanguagelanguagechanged', langCode);\n }\n\n showSignLanguageSettingsMenu() {\n // Set flag to prevent immediate closing\n this.signLanguageSettingsMenuJustOpened = true;\n setTimeout(() => {\n this.signLanguageSettingsMenuJustOpened = false;\n }, 350);\n \n // Add document click handler on FIRST menu open (not at window creation)\n if (!this.signLanguageDocumentClickHandlerAdded) {\n this.signLanguageDocumentClickHandler = (e) => {\n // Ignore if menu was just opened (prevents immediate closing)\n if (this.signLanguageSettingsMenuJustOpened) {\n return;\n }\n \n // Ignore clicks on the settings button itself or its children\n if (this.signLanguageSettingsButton && \n (this.signLanguageSettingsButton === e.target || this.signLanguageSettingsButton.contains(e.target))) {\n return;\n }\n \n // Ignore clicks on the settings menu items\n if (this.signLanguageSettingsMenu && this.signLanguageSettingsMenu.contains(e.target)) {\n return;\n }\n \n // Close menu if clicking outside\n if (this.signLanguageSettingsMenuVisible) {\n this.hideSignLanguageSettingsMenu();\n }\n };\n setTimeout(() => {\n document.addEventListener('mousedown', this.signLanguageDocumentClickHandler, true); // Use mousedown in capture phase\n this.signLanguageDocumentClickHandlerAdded = true;\n }, 300);\n }\n \n if (this.signLanguageSettingsMenu) {\n this.signLanguageSettingsMenu.style.display = 'block';\n this.signLanguageSettingsMenuVisible = true;\n if (this.signLanguageSettingsButton) {\n this.signLanguageSettingsButton.setAttribute('aria-expanded', 'true');\n }\n // Always re-attach keyboard navigation handler when reopening\n this.signLanguageSettingsMenuKeyHandler = attachMenuKeyboardNavigation(\n this.signLanguageSettingsMenu,\n this.signLanguageSettingsButton,\n `.${this.options.classPrefix}-sign-language-settings-item`,\n () => this.hideSignLanguageSettingsMenu({ focusButton: true })\n );\n // Reposition menu in case window was moved (async for repositioning)\n this.positionSignLanguageSettingsMenu();\n this.updateSignLanguageDragOptionState();\n this.updateSignLanguageResizeOptionState();\n focusFirstMenuItem(this.signLanguageSettingsMenu, `.${this.options.classPrefix}-sign-language-settings-item`);\n return;\n }\n \n // Create settings menu\n this.signLanguageSettingsMenu = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-language-settings-menu`,\n attributes: {\n 'role': 'menu'\n }\n });\n\n // Keyboard drag option\n const keyboardDragOption = createMenuItem({\n classPrefix: this.options.classPrefix,\n itemClass: `${this.options.classPrefix}-sign-language-settings-item`,\n icon: 'move',\n label: 'player.enableSignDragMode',\n hasTextClass: true,\n onClick: () => {\n this.toggleSignLanguageKeyboardDragMode();\n this.hideSignLanguageSettingsMenu();\n }\n });\n keyboardDragOption.setAttribute('role', 'switch');\n keyboardDragOption.setAttribute('aria-checked', 'false');\n // Remove any tooltips from menu items (they have visible text)\n const dragTooltip = keyboardDragOption.querySelector(`.${this.options.classPrefix}-tooltip`);\n if (dragTooltip) dragTooltip.remove();\n const dragButtonText = keyboardDragOption.querySelector(`.${this.options.classPrefix}-button-text`);\n if (dragButtonText) dragButtonText.remove();\n this.signLanguageDragOptionButton = keyboardDragOption;\n this.signLanguageDragOptionText = keyboardDragOption.querySelector(`.${this.options.classPrefix}-settings-text`);\n this.updateSignLanguageDragOptionState();\n\n // Resize option\n const resizeOption = createMenuItem({\n classPrefix: this.options.classPrefix,\n itemClass: `${this.options.classPrefix}-sign-language-settings-item`,\n icon: 'resize',\n label: 'player.enableSignResizeMode',\n hasTextClass: true,\n onClick: (event) => {\n event.preventDefault();\n event.stopPropagation();\n \n const enabled = this.toggleSignLanguageResizeMode({ focus: false });\n \n if (enabled) {\n this.hideSignLanguageSettingsMenu({ focusButton: false });\n // Focus sign language wrapper after handles appear\n setTimeout(() => {\n if (this.signLanguageWrapper) {\n this.signLanguageWrapper.focus({ preventScroll: true });\n }\n }, 20);\n } else {\n this.hideSignLanguageSettingsMenu({ focusButton: true });\n }\n }\n });\n resizeOption.setAttribute('role', 'switch');\n resizeOption.setAttribute('aria-checked', 'false');\n // Remove any tooltips from menu items (they have visible text)\n const resizeTooltip = resizeOption.querySelector(`.${this.options.classPrefix}-tooltip`);\n if (resizeTooltip) resizeTooltip.remove();\n const resizeButtonText = resizeOption.querySelector(`.${this.options.classPrefix}-button-text`);\n if (resizeButtonText) resizeButtonText.remove();\n this.signLanguageResizeOptionButton = resizeOption;\n this.signLanguageResizeOptionText = resizeOption.querySelector(`.${this.options.classPrefix}-settings-text`);\n this.updateSignLanguageResizeOptionState();\n\n // Close option\n const closeOption = createMenuItem({\n classPrefix: this.options.classPrefix,\n itemClass: `${this.options.classPrefix}-sign-language-settings-item`,\n icon: 'close',\n label: 'transcript.closeMenu',\n onClick: () => {\n this.hideSignLanguageSettingsMenu();\n }\n });\n // Remove any tooltips from menu items (they have visible text)\n const closeTooltip = closeOption.querySelector(`.${this.options.classPrefix}-tooltip`);\n if (closeTooltip) closeTooltip.remove();\n const closeButtonText = closeOption.querySelector(`.${this.options.classPrefix}-button-text`);\n if (closeButtonText) closeButtonText.remove();\n\n this.signLanguageSettingsMenu.appendChild(keyboardDragOption);\n this.signLanguageSettingsMenu.appendChild(resizeOption);\n this.signLanguageSettingsMenu.appendChild(closeOption);\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n this.signLanguageSettingsMenu.style.visibility = 'hidden';\n this.signLanguageSettingsMenu.style.display = 'block';\n \n // Insert menu right after the button in the DOM (like control bar menus)\n if (this.signLanguageSettingsButton && this.signLanguageSettingsButton.parentNode) {\n this.signLanguageSettingsButton.insertAdjacentElement('afterend', this.signLanguageSettingsMenu);\n } else if (this.signLanguageWrapper) {\n // Fallback: append to wrapper if button parent not available\n this.signLanguageWrapper.appendChild(this.signLanguageSettingsMenu);\n }\n \n // Position the menu relative to the settings button (immediately while hidden)\n this.positionSignLanguageSettingsMenuImmediate();\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n if (this.signLanguageSettingsMenu) {\n this.signLanguageSettingsMenu.style.visibility = 'visible';\n }\n });\n \n // Add keyboard navigation\n this.signLanguageSettingsMenuKeyHandler = attachMenuKeyboardNavigation(\n this.signLanguageSettingsMenu,\n this.signLanguageSettingsButton,\n `.${this.options.classPrefix}-sign-language-settings-item`,\n () => this.hideSignLanguageSettingsMenu({ focusButton: true })\n );\n \n // Set the menu as visible and display it\n this.signLanguageSettingsMenuVisible = true;\n // this.signLanguageSettingsMenu.style.display = 'block'; // Already set above\n \n // Update aria-expanded\n if (this.signLanguageSettingsButton) {\n this.signLanguageSettingsButton.setAttribute('aria-expanded', 'true');\n }\n this.updateSignLanguageDragOptionState();\n this.updateSignLanguageResizeOptionState();\n \n // Focus first menu item\n focusFirstMenuItem(this.signLanguageSettingsMenu, `.${this.options.classPrefix}-sign-language-settings-item`);\n }\n\n hideSignLanguageSettingsMenu({ focusButton = true } = {}) {\n if (this.signLanguageSettingsMenu) {\n this.signLanguageSettingsMenu.style.display = 'none';\n this.signLanguageSettingsMenuVisible = false;\n this.signLanguageSettingsMenuJustOpened = false;\n \n // Remove keyboard handler\n if (this.signLanguageSettingsMenuKeyHandler) {\n this.signLanguageSettingsMenu.removeEventListener('keydown', this.signLanguageSettingsMenuKeyHandler);\n this.signLanguageSettingsMenuKeyHandler = null;\n }\n \n // Reset tabindex on menu items\n const menuItems = Array.from(this.signLanguageSettingsMenu.querySelectorAll(`.${this.options.classPrefix}-sign-language-settings-item`));\n menuItems.forEach(item => {\n item.setAttribute('tabindex', '-1');\n });\n \n // Update aria-expanded\n if (this.signLanguageSettingsButton) {\n this.signLanguageSettingsButton.setAttribute('aria-expanded', 'false');\n if (focusButton) {\n // Return focus to settings button\n this.signLanguageSettingsButton.focus({ preventScroll: true });\n }\n }\n }\n }\n\n positionSignLanguageSettingsMenuImmediate() {\n if (!this.signLanguageSettingsMenu || !this.signLanguageSettingsButton) return;\n \n // Position immediately (synchronously) - used when menu is first shown\n const buttonRect = this.signLanguageSettingsButton.getBoundingClientRect();\n const menuRect = this.signLanguageSettingsMenu.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n \n // Get the parent container (headerLeft) as the positioning container (like control bar menus)\n const parentContainer = this.signLanguageSettingsButton.parentElement;\n if (!parentContainer) return;\n \n const parentRect = parentContainer.getBoundingClientRect();\n \n // Calculate position relative to parent container\n const buttonCenterX = buttonRect.left + buttonRect.width / 2 - parentRect.left;\n const buttonBottom = buttonRect.bottom - parentRect.top;\n const buttonTop = buttonRect.top - parentRect.top;\n \n const spaceAbove = buttonRect.top;\n const spaceBelow = viewportHeight - buttonRect.bottom;\n \n // Position menu below button by default\n let menuTop = buttonBottom + 8;\n let menuBottom = null;\n \n // Prefer below, but switch to above if not enough space\n if (spaceBelow < menuRect.height + 20 && spaceAbove > spaceBelow) {\n menuTop = null;\n const parentHeight = parentRect.bottom - parentRect.top;\n menuBottom = parentHeight - buttonTop + 8;\n this.signLanguageSettingsMenu.classList.add('vidply-menu-above');\n } else {\n this.signLanguageSettingsMenu.classList.remove('vidply-menu-above');\n }\n \n // Calculate horizontal position (center on button)\n let menuLeft = buttonCenterX - menuRect.width / 2;\n let menuRight = 'auto';\n let transformX = 'translateX(0)';\n \n const menuLeftAbsolute = buttonRect.left + buttonRect.width / 2 - menuRect.width / 2;\n if (menuLeftAbsolute < 10) {\n menuLeft = 0;\n transformX = 'translateX(0)';\n } else if (menuLeftAbsolute + menuRect.width > viewportWidth - 10) {\n menuLeft = 'auto';\n menuRight = 0;\n transformX = 'translateX(0)';\n } else {\n menuLeft = buttonCenterX;\n transformX = 'translateX(-50%)';\n }\n \n // Apply calculated positions\n if (menuTop !== null) {\n this.signLanguageSettingsMenu.style.top = `${menuTop}px`;\n this.signLanguageSettingsMenu.style.bottom = 'auto';\n } else if (menuBottom !== null) {\n this.signLanguageSettingsMenu.style.top = 'auto';\n this.signLanguageSettingsMenu.style.bottom = `${menuBottom}px`;\n }\n \n if (menuLeft !== 'auto') {\n this.signLanguageSettingsMenu.style.left = `${menuLeft}px`;\n this.signLanguageSettingsMenu.style.right = 'auto';\n } else {\n this.signLanguageSettingsMenu.style.left = 'auto';\n this.signLanguageSettingsMenu.style.right = `${menuRight}px`;\n }\n \n this.signLanguageSettingsMenu.style.transform = transformX;\n }\n \n positionSignLanguageSettingsMenu() {\n if (!this.signLanguageSettingsMenu || !this.signLanguageSettingsButton || !this.signLanguageWrapper) return;\n \n // Use requestAnimationFrame to ensure layout is stable before positioning (for repositioning)\n requestAnimationFrame(() => {\n setTimeout(() => {\n this.positionSignLanguageSettingsMenuImmediate();\n }, 10); // Small delay to ensure layout is stable\n });\n }\n\n attachSignLanguageSettingsMenuKeyboardNavigation() {\n if (!this.signLanguageSettingsMenu) return;\n \n // Remove existing handler if any\n if (this.signLanguageSettingsMenuKeyHandler) {\n this.signLanguageSettingsMenu.removeEventListener('keydown', this.signLanguageSettingsMenuKeyHandler);\n }\n \n this.signLanguageSettingsMenuKeyHandler = attachMenuKeyboardNavigation(\n this.signLanguageSettingsMenu,\n this.signLanguageSettingsButton,\n `.${this.options.classPrefix}-sign-language-settings-item`,\n () => this.hideSignLanguageSettingsMenu({ focusButton: true })\n );\n }\n\n updateSignLanguageDragOptionState() {\n if (!this.signLanguageDragOptionButton) {\n return;\n }\n \n const isEnabled = !!(this.signLanguageDraggable && this.signLanguageDraggable.keyboardDragMode);\n const text = isEnabled\n ? i18n.t('player.disableSignDragMode')\n : i18n.t('player.enableSignDragMode');\n const ariaLabel = isEnabled\n ? i18n.t('player.disableSignDragModeAria')\n : i18n.t('player.enableSignDragModeAria');\n\n this.signLanguageDragOptionButton.setAttribute('aria-checked', isEnabled ? 'true' : 'false');\n this.signLanguageDragOptionButton.setAttribute('aria-label', ariaLabel);\n\n if (this.signLanguageDragOptionText) {\n this.signLanguageDragOptionText.textContent = text;\n }\n }\n\n updateSignLanguageResizeOptionState() {\n if (!this.signLanguageResizeOptionButton) {\n return;\n }\n \n const isEnabled = !!(this.signLanguageDraggable && this.signLanguageDraggable.pointerResizeMode);\n const text = isEnabled\n ? i18n.t('player.disableSignResizeMode')\n : i18n.t('player.enableSignResizeMode');\n const ariaLabel = isEnabled\n ? i18n.t('player.disableSignResizeModeAria')\n : i18n.t('player.enableSignResizeModeAria');\n\n this.signLanguageResizeOptionButton.setAttribute('aria-checked', isEnabled ? 'true' : 'false');\n this.signLanguageResizeOptionButton.setAttribute('aria-label', ariaLabel);\n\n if (this.signLanguageResizeOptionText) {\n this.signLanguageResizeOptionText.textContent = text;\n }\n }\n\n constrainSignLanguagePosition() {\n if (!this.signLanguageWrapper || !this.videoWrapper) return;\n \n // Don't auto-position if user has manually positioned it\n if (this.signLanguageDraggable && this.signLanguageDraggable.manuallyPositioned) {\n return;\n }\n \n // Ensure width is set\n if (!this.signLanguageWrapper.style.width || this.signLanguageWrapper.style.width === '') {\n this.signLanguageWrapper.style.width = '280px'; // Default width\n }\n \n // Get videoWrapper position relative to the player CONTAINER (where sign language video is attached)\n const videoWrapperRect = this.videoWrapper.getBoundingClientRect();\n const containerRect = this.container.getBoundingClientRect();\n const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();\n \n // Calculate videoWrapper's position and dimensions relative to container\n const videoWrapperLeft = videoWrapperRect.left - containerRect.left;\n const videoWrapperTop = videoWrapperRect.top - containerRect.top;\n const videoWrapperWidth = videoWrapperRect.width;\n const videoWrapperHeight = videoWrapperRect.height;\n \n // Use estimated height if video hasn't loaded yet (16:9 aspect ratio)\n let wrapperWidth = wrapperRect.width || 280;\n let wrapperHeight = wrapperRect.height || ((280 * 9) / 16); // Estimate based on 16:9 aspect ratio\n \n let left, top;\n const margin = 16; // Margin from edges\n const controlsHeight = 95; // Height of controls when visible\n \n // Always calculate fresh position based on desired location (relative to videoWrapper)\n const position = this.signLanguageDesiredPosition || 'bottom-right';\n \n switch (position) {\n case 'bottom-right':\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n break;\n case 'bottom-left':\n left = videoWrapperLeft + margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n break;\n case 'top-right':\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + margin;\n break;\n case 'top-left':\n left = videoWrapperLeft + margin;\n top = videoWrapperTop + margin;\n break;\n default:\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n }\n \n // Constrain to videoWrapper bounds (ensuring it stays above controls)\n left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));\n top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));\n \n // Apply constrained position\n this.signLanguageWrapper.style.left = `${left}px`;\n this.signLanguageWrapper.style.top = `${top}px`;\n this.signLanguageWrapper.style.right = 'auto';\n this.signLanguageWrapper.style.bottom = 'auto';\n // Remove position classes if any were applied\n this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter(c => c.startsWith('vidply-sign-position-')));\n }\n\n saveSignLanguagePreferences() {\n if (!this.signLanguageWrapper) return;\n \n // Only save width - position is always calculated fresh to bottom-right\n this.storage.saveSignLanguagePreferences({\n size: {\n width: this.signLanguageWrapper.style.width\n // Height is auto - maintained by aspect ratio\n }\n });\n }\n\n cleanupSignLanguage() {\n // Hide settings menu if open\n if (this.signLanguageSettingsMenuVisible) {\n this.hideSignLanguageSettingsMenu({ focusButton: false });\n }\n \n // Remove document click handler\n if (this.signLanguageDocumentClickHandler && this.signLanguageDocumentClickHandlerAdded) {\n document.removeEventListener('mousedown', this.signLanguageDocumentClickHandler, true);\n this.signLanguageDocumentClickHandlerAdded = false;\n this.signLanguageDocumentClickHandler = null;\n }\n \n // Remove settings menu event listeners\n if (this.signLanguageSettingsHandlers) {\n if (this.signLanguageSettingsButton) {\n this.signLanguageSettingsButton.removeEventListener('click', this.signLanguageSettingsHandlers.settingsClick);\n this.signLanguageSettingsButton.removeEventListener('keydown', this.signLanguageSettingsHandlers.settingsKeydown);\n }\n this.signLanguageSettingsHandlers = null;\n }\n \n // Remove event listeners\n if (this.signLanguageHandlers) {\n this.off('play', this.signLanguageHandlers.play);\n this.off('pause', this.signLanguageHandlers.pause);\n this.off('timeupdate', this.signLanguageHandlers.timeupdate);\n this.off('ratechange', this.signLanguageHandlers.ratechange);\n if (this.signLanguageHandlers.captionChange) {\n this.off('captionsenabled', this.signLanguageHandlers.captionChange);\n }\n this.signLanguageHandlers = null;\n }\n\n // Remove event listeners\n if (this.signLanguageInteractionHandlers) {\n if (this.signLanguageHeader && this.signLanguageInteractionHandlers.headerKeyHandler) {\n this.signLanguageHeader.removeEventListener('keydown', this.signLanguageInteractionHandlers.headerKeyHandler);\n }\n if (this.signLanguageWrapper && this.signLanguageInteractionHandlers.customKeyHandler) {\n this.signLanguageWrapper.removeEventListener('keydown', this.signLanguageInteractionHandlers.customKeyHandler);\n }\n }\n\n // Destroy draggable utility\n if (this.signLanguageDraggable) {\n if (this.signLanguageDraggable.pointerResizeMode) {\n this.signLanguageDraggable.disablePointerResizeMode();\n }\n this.signLanguageDraggable.destroy();\n this.signLanguageDraggable = null;\n }\n \n // Clear interaction handlers reference\n this.signLanguageInteractionHandlers = null;\n\n // Remove video and wrapper elements\n if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {\n if (this.signLanguageVideo) {\n this.signLanguageVideo.pause();\n this.signLanguageVideo.src = '';\n }\n this.signLanguageWrapper.parentNode.removeChild(this.signLanguageWrapper);\n }\n this.signLanguageWrapper = null;\n this.signLanguageVideo = null;\n this.signLanguageSettingsButton = null;\n this.signLanguageSettingsMenu = null;\n }\n\n // Settings\n // Settings dialog removed - using individual control buttons instead\n showSettings() {\n console.warn('[VidPly] Settings dialog has been removed. Use individual control buttons (speed, captions, etc.)');\n }\n\n hideSettings() {\n // No-op - settings dialog removed\n }\n\n // Utility methods\n getCurrentTime() {\n return this.state.currentTime;\n }\n\n getDuration() {\n return this.state.duration;\n }\n\n isPlaying() {\n return this.state.playing;\n }\n\n isPaused() {\n return this.state.paused;\n }\n\n isEnded() {\n return this.state.ended;\n }\n\n isMuted() {\n return this.state.muted;\n }\n\n isFullscreen() {\n return this.state.fullscreen;\n }\n\n // Error handling\n handleError(error) {\n this.log('Error:', error, 'error');\n this.emit('error', error);\n\n if (this.options.onError) {\n this.options.onError.call(this, error);\n }\n }\n\n // Logging\n log(...messages) {\n if (!this.options.debug) {\n return;\n }\n\n let type = 'log';\n if (messages.length > 0) {\n const potentialType = messages[messages.length - 1];\n if (typeof potentialType === 'string' && console[potentialType]) {\n type = potentialType;\n messages = messages.slice(0, -1);\n }\n }\n\n if (messages.length === 0) {\n messages = [''];\n }\n\n if (typeof console[type] === 'function') {\n console[type]('[VidPly]', ...messages);\n } else {\n console.log('[VidPly]', ...messages);\n }\n }\n\n // Setup responsive handlers\n setupResponsiveHandlers() {\n // Use ResizeObserver for efficient resize tracking\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const width = entry.contentRect.width;\n\n // Update control bar for viewport\n if (this.controlBar && typeof this.controlBar.updateControlsForViewport === 'function') {\n this.controlBar.updateControlsForViewport(width);\n }\n\n // Update transcript positioning\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n this.transcriptManager.positionTranscript();\n }\n }\n });\n\n this.resizeObserver.observe(this.container);\n } else {\n // Fallback to window resize event\n this.resizeHandler = () => {\n const width = this.container.clientWidth;\n\n if (this.controlBar && typeof this.controlBar.updateControlsForViewport === 'function') {\n this.controlBar.updateControlsForViewport(width);\n }\n\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n // Only auto-position if user hasn't manually moved it\n if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {\n this.transcriptManager.positionTranscript();\n }\n }\n };\n\n window.addEventListener('resize', this.resizeHandler);\n }\n\n // Also listen for orientation changes on mobile\n if (window.matchMedia) {\n this.orientationHandler = (e) => {\n // Wait for layout to settle\n setTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n // Only auto-position if user hasn't manually moved it\n if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {\n this.transcriptManager.positionTranscript();\n }\n }\n }, 100);\n };\n\n const orientationQuery = window.matchMedia('(orientation: portrait)');\n if (orientationQuery.addEventListener) {\n orientationQuery.addEventListener('change', this.orientationHandler);\n } else if (orientationQuery.addListener) {\n // Fallback for older browsers\n orientationQuery.addListener(this.orientationHandler);\n }\n\n this.orientationQuery = orientationQuery;\n }\n\n // Listen for native fullscreen change events (e.g., when user presses ESC)\n this.fullscreenChangeHandler = () => {\n const isFullscreen = !!(\n document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement\n );\n\n // Only update if state has changed\n if (this.state.fullscreen !== isFullscreen) {\n this.state.fullscreen = isFullscreen;\n \n if (isFullscreen) {\n this.container.classList.add(`${this.options.classPrefix}-fullscreen`);\n } else {\n this.container.classList.remove(`${this.options.classPrefix}-fullscreen`);\n // Clean up pseudo-fullscreen state when exiting\n this._disablePseudoFullscreen();\n }\n \n this.emit('fullscreenchange', isFullscreen);\n \n // Update fullscreen button icon\n if (this.controlBar) {\n this.controlBar.updateFullscreenButton();\n }\n \n // Reposition sign language video after fullscreen transition\n if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== 'none') {\n // Re-setup drag/drop when entering/exiting fullscreen on mobile devices\n // This enables drag/resize when entering fullscreen on mobile\n const isMobile = window.innerWidth < 768;\n if (isMobile) {\n this.setupSignLanguageInteraction();\n }\n \n // Use setTimeout to ensure layout has updated after fullscreen transition\n // Longer delay to account for CSS transition animations and layout recalculation\n this.setManagedTimeout(() => {\n // Use requestAnimationFrame to ensure the browser has fully rendered the layout\n requestAnimationFrame(() => {\n // Clear saved size and reset to default for the new container size\n this.storage.saveSignLanguagePreferences({ size: null });\n this.signLanguageDesiredPosition = 'bottom-right';\n // Reset to default width for the new container\n this.signLanguageWrapper.style.width = isFullscreen ? '400px' : '280px';\n this.constrainSignLanguagePosition();\n });\n }, 500);\n }\n }\n };\n\n // Add listeners for all vendor-prefixed fullscreenchange events\n document.addEventListener('fullscreenchange', this.fullscreenChangeHandler);\n document.addEventListener('webkitfullscreenchange', this.fullscreenChangeHandler);\n document.addEventListener('mozfullscreenchange', this.fullscreenChangeHandler);\n document.addEventListener('MSFullscreenChange', this.fullscreenChangeHandler);\n }\n\n // Cleanup\n destroy() {\n this.log('Destroying player');\n\n if (this.renderer) {\n this.renderer.destroy();\n }\n\n if (this.controlBar) {\n this.controlBar.destroy();\n }\n\n if (this.captionManager) {\n this.captionManager.destroy();\n }\n\n if (this.keyboardManager) {\n this.keyboardManager.destroy();\n }\n\n if (this.transcriptManager) {\n this.transcriptManager.destroy();\n }\n\n // Cleanup sign language video and listeners\n this.cleanupSignLanguage();\n\n // Cleanup play overlay button\n if (this.playButtonOverlay && this.playButtonOverlay.parentNode) {\n this.playButtonOverlay.remove();\n this.playButtonOverlay = null;\n }\n\n // Cleanup resize observer\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n // Cleanup window resize handler\n if (this.resizeHandler) {\n window.removeEventListener('resize', this.resizeHandler);\n this.resizeHandler = null;\n }\n\n // Cleanup orientation change handler\n if (this.orientationQuery && this.orientationHandler) {\n if (this.orientationQuery.removeEventListener) {\n this.orientationQuery.removeEventListener('change', this.orientationHandler);\n } else if (this.orientationQuery.removeListener) {\n this.orientationQuery.removeListener(this.orientationHandler);\n }\n this.orientationQuery = null;\n this.orientationHandler = null;\n }\n\n // Cleanup fullscreen change handler\n if (this.fullscreenChangeHandler) {\n document.removeEventListener('fullscreenchange', this.fullscreenChangeHandler);\n document.removeEventListener('webkitfullscreenchange', this.fullscreenChangeHandler);\n document.removeEventListener('mozfullscreenchange', this.fullscreenChangeHandler);\n document.removeEventListener('MSFullscreenChange', this.fullscreenChangeHandler);\n this.fullscreenChangeHandler = null;\n }\n\n // Cleanup all managed timeouts\n this.timeouts.forEach(timeoutId => clearTimeout(timeoutId));\n this.timeouts.clear();\n\n // Cleanup metadata handling\n if (this.metadataCueChangeHandler) {\n const textTracks = this.textTracks;\n const metadataTrack = textTracks.find(track => track.kind === 'metadata');\n if (metadataTrack) {\n metadataTrack.removeEventListener('cuechange', this.metadataCueChangeHandler);\n }\n this.metadataCueChangeHandler = null;\n }\n\n if (this.metadataAlertHandlers && this.metadataAlertHandlers.size > 0) {\n this.metadataAlertHandlers.forEach(({ button, handler }) => {\n if (button && handler) {\n button.removeEventListener('click', handler);\n }\n });\n this.metadataAlertHandlers.clear();\n }\n\n // Remove container\n if (this.container && this.container.parentNode) {\n this.container.parentNode.insertBefore(this.element, this.container);\n this.container.parentNode.removeChild(this.container);\n }\n\n this.removeAllListeners();\n }\n\n /**\n * Setup metadata track handling\n * This enables metadata tracks and listens for cue changes to trigger actions\n */\n setupMetadataHandling() {\n const setupMetadata = () => {\n const textTracks = this.textTracks;\n const metadataTrack = textTracks.find(track => track.kind === 'metadata');\n \n if (metadataTrack) {\n // Enable the metadata track so cuechange events fire\n // Use 'hidden' mode so it doesn't display anything, but events still work\n if (metadataTrack.mode === 'disabled') {\n metadataTrack.mode = 'hidden';\n }\n \n // Remove existing listener if any\n if (this.metadataCueChangeHandler) {\n metadataTrack.removeEventListener('cuechange', this.metadataCueChangeHandler);\n }\n \n // Add event listener for cue changes\n this.metadataCueChangeHandler = () => {\n const activeCues = Array.from(metadataTrack.activeCues || []);\n if (activeCues.length > 0) {\n // Debug logging\n if (this.options.debug) {\n this.log('[Metadata] Active cues:', activeCues.map(c => ({\n start: c.startTime,\n end: c.endTime,\n text: c.text\n })));\n }\n }\n activeCues.forEach(cue => {\n this.handleMetadataCue(cue);\n });\n };\n \n metadataTrack.addEventListener('cuechange', this.metadataCueChangeHandler);\n \n // Debug: Log metadata track setup\n if (this.options.debug) {\n const cueCount = metadataTrack.cues ? metadataTrack.cues.length : 0;\n this.log('[Metadata] Track enabled,', cueCount, 'cues available');\n }\n } else if (this.options.debug) {\n this.log('[Metadata] No metadata track found');\n }\n };\n \n // Try immediately\n setupMetadata();\n \n // Also try after loadedmetadata event (tracks might not be ready yet)\n this.on('loadedmetadata', setupMetadata);\n }\n\n normalizeMetadataSelector(selector) {\n if (!selector) {\n return null;\n }\n const trimmed = selector.trim();\n if (!trimmed) {\n return null;\n }\n if (trimmed.startsWith('#') || trimmed.startsWith('.') || trimmed.startsWith('[')) {\n return trimmed;\n }\n return `#${trimmed}`;\n }\n\n resolveMetadataConfig(map, key) {\n if (!map || !key) {\n return null;\n }\n if (Object.prototype.hasOwnProperty.call(map, key)) {\n return map[key];\n }\n const withoutHash = key.replace(/^#/, '');\n if (Object.prototype.hasOwnProperty.call(map, withoutHash)) {\n return map[withoutHash];\n }\n return null;\n }\n\n cacheMetadataAlertContent(element, config = {}) {\n if (!element) {\n return;\n }\n const titleSelector = config.titleSelector || '[data-vidply-alert-title], h3, header';\n const messageSelector = config.messageSelector || '[data-vidply-alert-message], p';\n\n const titleEl = element.querySelector(titleSelector);\n if (titleEl && !titleEl.dataset.vidplyAlertTitleOriginal) {\n titleEl.dataset.vidplyAlertTitleOriginal = titleEl.textContent.trim();\n }\n\n const messageEl = element.querySelector(messageSelector);\n if (messageEl && !messageEl.dataset.vidplyAlertMessageOriginal) {\n messageEl.dataset.vidplyAlertMessageOriginal = messageEl.textContent.trim();\n }\n }\n\n restoreMetadataAlertContent(element, config = {}) {\n if (!element) {\n return;\n }\n const titleSelector = config.titleSelector || '[data-vidply-alert-title], h3, header';\n const messageSelector = config.messageSelector || '[data-vidply-alert-message], p';\n\n const titleEl = element.querySelector(titleSelector);\n if (titleEl && titleEl.dataset.vidplyAlertTitleOriginal) {\n titleEl.textContent = titleEl.dataset.vidplyAlertTitleOriginal;\n }\n\n const messageEl = element.querySelector(messageSelector);\n if (messageEl && messageEl.dataset.vidplyAlertMessageOriginal) {\n messageEl.textContent = messageEl.dataset.vidplyAlertMessageOriginal;\n }\n }\n\n focusMetadataTarget(target, fallbackElement = null) {\n if (!target || target === 'none') {\n return;\n }\n\n if (target === 'alert' && fallbackElement) {\n fallbackElement.focus({ preventScroll: true });\n return;\n }\n\n if (target === 'player') {\n if (this.container) {\n this.container.focus({ preventScroll: true });\n }\n return;\n }\n\n if (target === 'media') {\n this.element.focus({ preventScroll: true });\n return;\n }\n\n if (target === 'playButton') {\n const playButton = this.controlBar?.controls?.playPause;\n if (playButton) {\n playButton.focus({ preventScroll: true });\n }\n return;\n }\n\n if (typeof target === 'string') {\n const targetElement = document.querySelector(target);\n if (targetElement) {\n if (targetElement.tabIndex === -1 && !targetElement.hasAttribute('tabindex')) {\n targetElement.setAttribute('tabindex', '-1');\n }\n targetElement.focus({ preventScroll: true });\n }\n }\n }\n\n handleMetadataAlert(selector, options = {}) {\n if (!selector) {\n return;\n }\n\n const config = this.resolveMetadataConfig(this.options.metadataAlerts, selector) || {};\n const element = options.element || document.querySelector(selector);\n\n if (!element) {\n if (this.options.debug) {\n this.log('[Metadata] Alert element not found:', selector);\n }\n return;\n }\n\n if (this.options.debug) {\n this.log('[Metadata] Handling alert', selector, { reason: options.reason, config });\n }\n\n this.cacheMetadataAlertContent(element, config);\n\n if (!element.dataset.vidplyAlertOriginalDisplay) {\n element.dataset.vidplyAlertOriginalDisplay = element.style.display || '';\n }\n\n if (!element.dataset.vidplyAlertDisplay) {\n element.dataset.vidplyAlertDisplay = config.display || 'block';\n }\n\n const shouldShow = options.show !== undefined ? options.show : (config.show !== false);\n if (shouldShow) {\n const displayValue = config.display || element.dataset.vidplyAlertDisplay || 'block';\n element.style.display = displayValue;\n element.hidden = false;\n element.removeAttribute('hidden');\n element.setAttribute('aria-hidden', 'false');\n element.setAttribute('data-vidply-alert-active', 'true');\n }\n\n const shouldReset = config.resetContent !== false && options.reason === 'focus';\n if (shouldReset) {\n this.restoreMetadataAlertContent(element, config);\n }\n\n const shouldFocus = options.focus !== undefined\n ? options.focus\n : (config.focusOnShow ?? (options.reason !== 'focus'));\n\n if (shouldShow && shouldFocus) {\n if (element.tabIndex === -1 && !element.hasAttribute('tabindex')) {\n element.setAttribute('tabindex', '-1');\n }\n element.focus({ preventScroll: true });\n }\n\n if (shouldShow && config.autoScroll !== false && options.autoScroll !== false) {\n element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n }\n\n const continueSelector = config.continueButton;\n if (continueSelector) {\n let continueButton = null;\n if (continueSelector === 'self') {\n continueButton = element;\n } else if (element.matches(continueSelector)) {\n continueButton = element;\n } else {\n continueButton = element.querySelector(continueSelector) || document.querySelector(continueSelector);\n }\n\n if (continueButton && !this.metadataAlertHandlers.has(selector)) {\n const handler = () => {\n const hideOnContinue = config.hideOnContinue !== false;\n if (hideOnContinue) {\n const originalDisplay = element.dataset.vidplyAlertOriginalDisplay || '';\n element.style.display = config.hideDisplay || originalDisplay || 'none';\n element.setAttribute('aria-hidden', 'true');\n element.removeAttribute('data-vidply-alert-active');\n }\n\n if (config.resume !== false && this.state.paused) {\n this.play();\n }\n\n const focusTarget = config.focusTarget || 'playButton';\n this.setManagedTimeout(() => {\n this.focusMetadataTarget(focusTarget, element);\n }, config.focusDelay ?? 100);\n };\n\n continueButton.addEventListener('click', handler);\n this.metadataAlertHandlers.set(selector, { button: continueButton, handler });\n }\n }\n\n return element;\n }\n\n handleMetadataHashtags(hashtags) {\n if (!Array.isArray(hashtags) || hashtags.length === 0) {\n return;\n }\n\n const configMap = this.options.metadataHashtags;\n if (!configMap) {\n return;\n }\n\n hashtags.forEach(tag => {\n const config = this.resolveMetadataConfig(configMap, tag);\n if (!config) {\n return;\n }\n\n const selector = this.normalizeMetadataSelector(config.alert || config.selector || config.target);\n if (!selector) {\n return;\n }\n\n const element = document.querySelector(selector);\n if (!element) {\n if (this.options.debug) {\n this.log('[Metadata] Hashtag target not found:', selector);\n }\n return;\n }\n\n if (this.options.debug) {\n this.log('[Metadata] Handling hashtag', tag, { selector, config });\n }\n\n this.cacheMetadataAlertContent(element, config);\n\n if (config.title) {\n const titleSelector = config.titleSelector || '[data-vidply-alert-title], h3, header';\n const titleEl = element.querySelector(titleSelector);\n if (titleEl) {\n titleEl.textContent = config.title;\n }\n }\n\n if (config.message) {\n const messageSelector = config.messageSelector || '[data-vidply-alert-message], p';\n const messageEl = element.querySelector(messageSelector);\n if (messageEl) {\n messageEl.textContent = config.message;\n }\n }\n\n const show = config.show !== false;\n const focus = config.focus !== undefined ? config.focus : false;\n\n this.handleMetadataAlert(selector, {\n element,\n show,\n focus,\n autoScroll: config.autoScroll,\n reason: 'hashtag'\n });\n });\n }\n\n /**\n * Handle individual metadata cues\n * Parses metadata text and emits events or triggers actions\n */\n handleMetadataCue(cue) {\n const text = cue.text.trim();\n \n // Debug logging\n if (this.options.debug) {\n this.log('[Metadata] Processing cue:', {\n time: cue.startTime,\n text: text\n });\n }\n \n // Emit a generic metadata event that developers can listen to\n this.emit('metadata', {\n time: cue.startTime,\n endTime: cue.endTime,\n text: text,\n cue: cue\n });\n\n // Parse for specific commands (examples based on wwa_meta.vtt format)\n if (text.includes('PAUSE')) {\n // Automatically pause the video\n if (!this.state.paused) {\n if (this.options.debug) {\n this.log('[Metadata] Pausing video at', cue.startTime);\n }\n this.pause();\n }\n // Also emit event for developers who want to listen\n this.emit('metadata:pause', { time: cue.startTime, text: text });\n }\n\n // Parse for focus directives\n const focusMatch = text.match(/FOCUS:([\\w#-]+)/);\n if (focusMatch) {\n const targetSelector = focusMatch[1];\n const normalizedSelector = this.normalizeMetadataSelector(targetSelector);\n // Automatically focus the target element\n const targetElement = normalizedSelector ? document.querySelector(normalizedSelector) : null;\n if (targetElement) {\n if (this.options.debug) {\n this.log('[Metadata] Focusing element:', normalizedSelector);\n }\n // Make element focusable if it isn't already\n if (targetElement.tabIndex === -1 && !targetElement.hasAttribute('tabindex')) {\n targetElement.setAttribute('tabindex', '-1');\n }\n // Use setTimeout to ensure DOM is ready\n this.setManagedTimeout(() => {\n targetElement.focus({ preventScroll: true });\n }, 10);\n } else if (this.options.debug) {\n this.log('[Metadata] Element not found:', normalizedSelector || targetSelector);\n }\n // Also emit event for developers who want to listen\n this.emit('metadata:focus', { \n time: cue.startTime, \n target: targetSelector,\n selector: normalizedSelector,\n element: targetElement,\n text: text \n });\n\n if (normalizedSelector) {\n this.handleMetadataAlert(normalizedSelector, {\n element: targetElement,\n reason: 'focus'\n });\n }\n }\n\n // Parse for hashtag references\n const hashtags = text.match(/#[\\w-]+/g);\n if (hashtags) {\n if (this.options.debug) {\n this.log('[Metadata] Hashtags found:', hashtags);\n }\n this.emit('metadata:hashtags', {\n time: cue.startTime,\n hashtags: hashtags,\n text: text\n });\n\n this.handleMetadataHashtags(hashtags);\n }\n }\n}\n\n// Static instances tracker for pause others functionality\nPlayer.instances = [];\n\n", "/**\n * VidPly Playlist Manager\n * Manages playlists for audio and video content\n */\n\nimport { DOMUtils } from '../utils/DOMUtils.js';\nimport { createIconElement } from '../icons/Icons.js';\nimport { i18n } from '../i18n/i18n.js';\nimport { TimeUtils } from '../utils/TimeUtils.js';\n\n// Static counter for unique IDs\nlet playlistInstanceCounter = 0;\n\nexport class PlaylistManager {\n constructor(player, options = {}) {\n this.player = player;\n this.tracks = [];\n this.initialTracks = Array.isArray(options.tracks) ? options.tracks : [];\n this.currentIndex = -1;\n \n // Generate unique instance ID for this playlist\n this.instanceId = ++playlistInstanceCounter;\n this.uniqueId = `vidply-playlist-${this.instanceId}`;\n \n // Options\n this.options = {\n autoAdvance: options.autoAdvance !== false, // Default true\n autoPlayFirst: options.autoPlayFirst !== false, // Default true - auto-play first track on load\n loop: options.loop || false,\n showPanel: options.showPanel !== false, // Default true\n ...options\n };\n \n // UI elements\n this.container = null;\n this.playlistPanel = null;\n this.trackInfoElement = null;\n this.navigationFeedback = null; // Live region for keyboard navigation feedback\n this.isPanelVisible = this.options.showPanel !== false;\n \n // Track change guard to prevent cascade of next() calls\n this.isChangingTrack = false;\n \n // Bind methods\n this.handleTrackEnd = this.handleTrackEnd.bind(this);\n this.handleTrackError = this.handleTrackError.bind(this);\n \n // Register this playlist manager with the player\n this.player.playlistManager = this;\n \n // Initialize\n this.init();\n \n // Update controls to add playlist buttons\n this.updatePlayerControls();\n \n // Load tracks if provided in options (after UI is ready)\n if (this.initialTracks.length > 0) {\n this.loadPlaylist(this.initialTracks);\n }\n }\n \n init() {\n // Listen for track end\n this.player.on('ended', this.handleTrackEnd);\n this.player.on('error', this.handleTrackError);\n \n // Listen for playback state changes to show/hide playlist in fullscreen\n this.player.on('play', this.handlePlaybackStateChange.bind(this));\n this.player.on('pause', this.handlePlaybackStateChange.bind(this));\n this.player.on('ended', this.handlePlaybackStateChange.bind(this));\n // Use fullscreenchange event which is what the player actually emits\n this.player.on('fullscreenchange', this.handleFullscreenChange.bind(this));\n \n // Listen for audio description state changes to update duration displays\n this.player.on('audiodescriptionenabled', this.handleAudioDescriptionChange.bind(this));\n this.player.on('audiodescriptiondisabled', this.handleAudioDescriptionChange.bind(this));\n \n // Create UI if needed\n if (this.options.showPanel) {\n this.createUI();\n }\n \n // Check for data-playlist attribute on player container (only if tracks weren't provided in options)\n if (this.tracks.length === 0 && this.initialTracks.length === 0) {\n this.loadPlaylistFromAttribute();\n }\n }\n \n /**\n * Load playlist from data-playlist attribute if present\n */\n loadPlaylistFromAttribute() {\n // Check the original wrapper element for data-playlist\n // Structure: #audio-player -> .vidply-player -> .vidply-video-wrapper -> <audio>\n // So we need to go up 3 levels\n if (!this.player.element || !this.player.element.parentElement) {\n console.log('VidPly Playlist: No player element found');\n return;\n }\n \n const videoWrapper = this.player.element.parentElement; // .vidply-video-wrapper\n const playerContainer = videoWrapper.parentElement; // .vidply-player\n const originalElement = playerContainer ? playerContainer.parentElement : null; // #audio-player (original div)\n \n if (!originalElement) {\n console.log('VidPly Playlist: No original element found');\n return;\n }\n \n // Load playlist options from data attributes\n this.loadOptionsFromAttributes(originalElement);\n \n const playlistData = originalElement.getAttribute('data-playlist');\n if (!playlistData) {\n console.log('VidPly Playlist: No data-playlist attribute found');\n return;\n }\n \n console.log('VidPly Playlist: Found data-playlist attribute, parsing...');\n try {\n const tracks = JSON.parse(playlistData);\n if (Array.isArray(tracks) && tracks.length > 0) {\n console.log(`VidPly Playlist: Loaded ${tracks.length} tracks from data-playlist`);\n this.loadPlaylist(tracks);\n } else {\n console.warn('VidPly Playlist: data-playlist is not a valid array or is empty');\n }\n } catch (error) {\n console.error('VidPly Playlist: Failed to parse data-playlist attribute', error);\n }\n }\n \n /**\n * Load playlist options from data attributes\n * @param {HTMLElement} element - Element to read attributes from\n */\n loadOptionsFromAttributes(element) {\n // data-playlist-auto-advance\n const autoAdvance = element.getAttribute('data-playlist-auto-advance');\n if (autoAdvance !== null) {\n this.options.autoAdvance = autoAdvance === 'true';\n }\n \n // data-playlist-auto-play-first\n const autoPlayFirst = element.getAttribute('data-playlist-auto-play-first');\n if (autoPlayFirst !== null) {\n this.options.autoPlayFirst = autoPlayFirst === 'true';\n }\n \n // data-playlist-loop\n const loop = element.getAttribute('data-playlist-loop');\n if (loop !== null) {\n this.options.loop = loop === 'true';\n }\n \n // data-playlist-show-panel\n const showPanel = element.getAttribute('data-playlist-show-panel');\n if (showPanel !== null) {\n this.options.showPanel = showPanel === 'true';\n }\n \n console.log('VidPly Playlist: Options from attributes:', this.options);\n }\n \n /**\n * Update player controls to add playlist navigation buttons\n */\n updatePlayerControls() {\n if (!this.player.controlBar) return;\n \n const controlBar = this.player.controlBar;\n \n // Clear existing controls content (except the element itself)\n controlBar.element.innerHTML = '';\n \n // Recreate controls with playlist buttons now available\n controlBar.createControls();\n \n // Reattach events for the new controls\n controlBar.attachEvents();\n controlBar.setupAutoHide();\n }\n \n /**\n * Load a playlist\n * @param {Array} tracks - Array of track objects\n */\n loadPlaylist(tracks) {\n this.tracks = tracks;\n this.currentIndex = -1;\n \n // Add playlist class to container\n if (this.container) {\n this.container.classList.add('vidply-has-playlist');\n }\n \n // Update UI\n if (this.playlistPanel) {\n this.renderPlaylist();\n }\n \n // Auto-play first track (if enabled)\n if (tracks.length > 0) {\n if (this.options.autoPlayFirst) {\n this.play(0);\n } else {\n // Load first track without playing\n this.loadTrack(0);\n }\n }\n \n // Update visibility based on current state\n this.updatePlaylistVisibilityInFullscreen();\n }\n \n /**\n * Load a track without playing\n * @param {number} index - Track index\n */\n loadTrack(index) {\n if (index < 0 || index >= this.tracks.length) {\n console.warn('VidPly Playlist: Invalid track index', index);\n return;\n }\n \n const track = this.tracks[index];\n \n // Set guard flag to prevent cascade of next() calls during track change\n this.isChangingTrack = true;\n \n // Update current index\n this.currentIndex = index;\n \n // Load track into player\n this.player.load({\n src: track.src,\n type: track.type,\n poster: track.poster,\n tracks: track.tracks || [],\n audioDescriptionSrc: track.audioDescriptionSrc || null,\n signLanguageSrc: track.signLanguageSrc || null\n });\n \n // Update UI\n this.updateTrackInfo(track);\n this.updatePlaylistUI();\n \n // Emit event\n this.player.emit('playlisttrackchange', {\n index: index,\n item: track,\n total: this.tracks.length\n });\n \n // Clear guard flag after a short delay to ensure track is loaded\n setTimeout(() => {\n this.isChangingTrack = false;\n }, 150);\n }\n \n /**\n * Play a specific track\n * @param {number} index - Track index\n * @param {boolean} userInitiated - Whether this was triggered by user action (default: false)\n */\n play(index, userInitiated = false) {\n if (index < 0 || index >= this.tracks.length) {\n console.warn('VidPly Playlist: Invalid track index', index);\n return;\n }\n \n const track = this.tracks[index];\n \n // Set guard flag to prevent cascade of next() calls during track change\n this.isChangingTrack = true;\n \n // Update current index\n this.currentIndex = index;\n \n // Load track into player\n this.player.load({\n src: track.src,\n type: track.type,\n poster: track.poster,\n tracks: track.tracks || [],\n audioDescriptionSrc: track.audioDescriptionSrc || null,\n signLanguageSrc: track.signLanguageSrc || null\n });\n \n // Update UI\n this.updateTrackInfo(track);\n this.updatePlaylistUI();\n \n // Emit event\n this.player.emit('playlisttrackchange', {\n index: index,\n item: track,\n total: this.tracks.length\n });\n \n // Auto-play and clear guard flag after playback starts\n setTimeout(() => {\n this.player.play();\n // Clear guard flag after a short delay to ensure track has started\n setTimeout(() => {\n this.isChangingTrack = false;\n }, 50);\n }, 100);\n }\n \n /**\n * Play next track\n */\n next() {\n let nextIndex = this.currentIndex + 1;\n \n if (nextIndex >= this.tracks.length) {\n if (this.options.loop) {\n nextIndex = 0;\n } else {\n return;\n }\n }\n \n this.play(nextIndex);\n }\n \n /**\n * Play previous track\n */\n previous() {\n let prevIndex = this.currentIndex - 1;\n \n if (prevIndex < 0) {\n if (this.options.loop) {\n prevIndex = this.tracks.length - 1;\n } else {\n return;\n }\n }\n \n this.play(prevIndex);\n }\n \n /**\n * Handle track end\n */\n handleTrackEnd() {\n // Don't auto-advance if we're already in the process of changing tracks\n // This prevents a cascade of next() calls when loading a new track triggers an 'ended' event\n if (this.isChangingTrack) {\n return;\n }\n \n if (this.options.autoAdvance) {\n this.next();\n }\n }\n \n /**\n * Handle track error\n */\n handleTrackError(e) {\n console.error('VidPly Playlist: Track error', e);\n \n // Try next track\n if (this.options.autoAdvance) {\n setTimeout(() => {\n this.next();\n }, 1000);\n }\n }\n \n /**\n * Handle playback state changes (for fullscreen playlist visibility)\n */\n handlePlaybackStateChange() {\n this.updatePlaylistVisibilityInFullscreen();\n }\n \n /**\n * Handle fullscreen state changes\n */\n handleFullscreenChange() {\n // Use a small delay to ensure fullscreen state is fully applied\n setTimeout(() => {\n this.updatePlaylistVisibilityInFullscreen();\n }, 50);\n }\n \n /**\n * Handle audio description state changes\n * Updates duration displays to show audio-described version duration when AD is enabled\n */\n handleAudioDescriptionChange() {\n const currentTrack = this.getCurrentTrack();\n if (!currentTrack) return;\n \n // Update the track info display with the appropriate duration\n this.updateTrackInfo(currentTrack);\n \n // Update the playlist UI to reflect duration changes (aria-labels)\n this.updatePlaylistUI();\n \n // Update visual duration elements in playlist panel\n this.updatePlaylistDurations();\n }\n \n /**\n * Update the visual duration displays in the playlist panel\n * Called when audio description state changes\n */\n updatePlaylistDurations() {\n if (!this.playlistPanel) return;\n \n const items = this.playlistPanel.querySelectorAll('.vidply-playlist-item');\n \n items.forEach((item, index) => {\n const track = this.tracks[index];\n if (!track) return;\n \n const effectiveDuration = this.getEffectiveDuration(track);\n const trackDuration = effectiveDuration ? TimeUtils.formatTime(effectiveDuration) : '';\n \n // Update duration badge on thumbnail (if exists)\n const durationBadge = item.querySelector('.vidply-playlist-duration-badge');\n if (durationBadge) {\n durationBadge.textContent = trackDuration;\n }\n \n // Update inline duration (if exists)\n const inlineDuration = item.querySelector('.vidply-playlist-item-duration');\n if (inlineDuration) {\n inlineDuration.textContent = trackDuration;\n }\n });\n }\n \n /**\n * Get the effective duration for a track based on audio description state\n * @param {Object} track - Track object\n * @returns {number|null} - Duration in seconds or null if not available\n */\n getEffectiveDuration(track) {\n if (!track) return null;\n \n const isAudioDescriptionEnabled = this.player.state.audioDescriptionEnabled;\n \n // If audio description is enabled and track has audioDescriptionDuration, use it\n if (isAudioDescriptionEnabled && track.audioDescriptionDuration) {\n return track.audioDescriptionDuration;\n }\n \n // Otherwise use regular duration\n return track.duration || null;\n }\n \n /**\n * Update playlist visibility based on fullscreen and playback state\n * In fullscreen: show when paused/not started, hide when playing\n * Outside fullscreen: respect original panel visibility setting\n */\n updatePlaylistVisibilityInFullscreen() {\n if (!this.playlistPanel || !this.tracks.length) return;\n \n const isFullscreen = this.player.state.fullscreen;\n const isPlaying = this.player.state.playing;\n \n if (isFullscreen) {\n // In fullscreen: show only when not playing (paused or not started)\n // Check playing state explicitly since paused might not be set initially\n if (!isPlaying) {\n this.playlistPanel.classList.add('vidply-playlist-fullscreen-visible');\n this.playlistPanel.style.display = 'block';\n } else {\n this.playlistPanel.classList.remove('vidply-playlist-fullscreen-visible');\n // Add a smooth fade out with delay to match CSS transition\n setTimeout(() => {\n // Double-check state hasn't changed before hiding\n if (this.player.state.playing && this.player.state.fullscreen) {\n this.playlistPanel.style.display = 'none';\n }\n }, 300); // Match CSS transition duration\n }\n } else {\n // Outside fullscreen: restore original behavior\n this.playlistPanel.classList.remove('vidply-playlist-fullscreen-visible');\n if (this.isPanelVisible && this.tracks.length > 0) {\n this.playlistPanel.style.display = 'block';\n } else {\n this.playlistPanel.style.display = 'none';\n }\n }\n }\n \n /**\n * Create playlist UI\n */\n createUI() {\n // Find player container\n this.container = this.player.container;\n \n if (!this.container) {\n console.warn('VidPly Playlist: No container found');\n return;\n }\n \n // Create track artwork element (shows album art/poster for audio playlists)\n // Only create for audio players\n if (this.player.element.tagName === 'AUDIO') {\n this.trackArtworkElement = DOMUtils.createElement('div', {\n className: 'vidply-track-artwork',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n this.trackArtworkElement.style.display = 'none';\n \n // Insert before video wrapper\n const videoWrapper = this.container.querySelector('.vidply-video-wrapper');\n if (videoWrapper) {\n this.container.insertBefore(this.trackArtworkElement, videoWrapper);\n } else {\n this.container.appendChild(this.trackArtworkElement);\n }\n }\n \n // Create track info element (shows current track)\n this.trackInfoElement = DOMUtils.createElement('div', {\n className: 'vidply-track-info',\n attributes: {\n role: 'status'\n }\n });\n this.trackInfoElement.style.display = 'none';\n \n this.container.appendChild(this.trackInfoElement);\n \n // Create navigation feedback live region\n this.navigationFeedback = DOMUtils.createElement('div', {\n className: 'vidply-sr-only',\n attributes: {\n role: 'status',\n 'aria-live': 'polite',\n 'aria-atomic': 'true'\n }\n });\n this.container.appendChild(this.navigationFeedback);\n \n // Create playlist panel with proper landmark\n this.playlistPanel = DOMUtils.createElement('div', {\n className: 'vidply-playlist-panel',\n attributes: {\n id: `${this.uniqueId}-panel`,\n role: 'region',\n 'aria-label': i18n.t('playlist.title'),\n 'aria-labelledby': `${this.uniqueId}-heading`\n }\n });\n this.playlistPanel.style.display = this.isPanelVisible ? 'none' : 'none'; // Will be shown when playlist is loaded\n \n this.container.appendChild(this.playlistPanel);\n }\n \n /**\n * Update track info display\n */\n updateTrackInfo(track) {\n if (!this.trackInfoElement) return;\n \n const trackNumber = this.currentIndex + 1;\n const totalTracks = this.tracks.length;\n const trackTitle = track.title || i18n.t('playlist.untitled');\n const trackArtist = track.artist || '';\n \n // Use effective duration (audio description duration when AD is enabled)\n const effectiveDuration = this.getEffectiveDuration(track);\n const trackDuration = effectiveDuration ? TimeUtils.formatTime(effectiveDuration) : '';\n const trackDurationReadable = effectiveDuration ? TimeUtils.formatDuration(effectiveDuration) : '';\n \n // Screen reader announcement - include duration if available\n const artistPart = trackArtist ? i18n.t('playlist.by') + trackArtist : '';\n const durationPart = trackDurationReadable ? `. ${trackDurationReadable}` : '';\n const announcement = i18n.t('playlist.nowPlaying', {\n current: trackNumber,\n total: totalTracks,\n title: trackTitle,\n artist: artistPart\n }) + durationPart;\n \n const trackOfText = i18n.t('playlist.trackOf', {\n current: trackNumber,\n total: totalTracks\n });\n \n // Build duration HTML if available\n const durationHtml = trackDuration \n ? `<span class=\"vidply-track-duration\" aria-hidden=\"true\">${DOMUtils.escapeHTML(trackDuration)}</span>` \n : '';\n \n // Get description if available\n const trackDescription = track.description || '';\n \n this.trackInfoElement.innerHTML = `\n <span class=\"vidply-sr-only\">${DOMUtils.escapeHTML(announcement)}</span>\n <div class=\"vidply-track-header\" aria-hidden=\"true\">\n <span class=\"vidply-track-number\">${DOMUtils.escapeHTML(trackOfText)}</span>\n ${durationHtml}\n </div>\n <div class=\"vidply-track-title\" aria-hidden=\"true\">${DOMUtils.escapeHTML(trackTitle)}</div>\n ${trackArtist ? `<div class=\"vidply-track-artist\" aria-hidden=\"true\">${DOMUtils.escapeHTML(trackArtist)}</div>` : ''}\n ${trackDescription ? `<div class=\"vidply-track-description\" aria-hidden=\"true\">${DOMUtils.escapeHTML(trackDescription)}</div>` : ''}\n `;\n \n this.trackInfoElement.style.display = 'block';\n \n // Update track artwork if available (for audio playlists)\n this.updateTrackArtwork(track);\n }\n \n /**\n * Update track artwork display (for audio playlists)\n */\n updateTrackArtwork(track) {\n if (!this.trackArtworkElement) return;\n \n // If track has a poster/artwork, show it\n if (track.poster) {\n this.trackArtworkElement.style.backgroundImage = `url(${track.poster})`;\n this.trackArtworkElement.style.display = 'block';\n } else {\n // No artwork available, hide the element\n this.trackArtworkElement.style.display = 'none';\n }\n }\n \n /**\n * Render playlist\n */\n renderPlaylist() {\n if (!this.playlistPanel) return;\n \n // Clear existing\n this.playlistPanel.innerHTML = '';\n \n // Create header\n const header = DOMUtils.createElement('h2', {\n className: 'vidply-playlist-header',\n attributes: {\n id: `${this.uniqueId}-heading`\n }\n });\n header.textContent = `${i18n.t('playlist.title')} (${this.tracks.length})`;\n this.playlistPanel.appendChild(header);\n \n // Add keyboard instructions (visually hidden)\n const instructions = DOMUtils.createElement('div', {\n className: 'vidply-sr-only',\n attributes: {\n id: `${this.uniqueId}-keyboard-instructions`\n }\n });\n instructions.textContent = 'Playlist navigation: Use Up and Down arrow keys to move between tracks. Press Page Up or Page Down to skip 5 tracks. Press Home to go to first track, End to go to last track. Press Enter or Space to play the selected track.';\n this.playlistPanel.appendChild(instructions);\n \n // Create list (proper ul element)\n const list = DOMUtils.createElement('ul', {\n className: 'vidply-playlist-list',\n attributes: {\n role: 'listbox',\n 'aria-labelledby': `${this.uniqueId}-heading`,\n 'aria-describedby': `${this.uniqueId}-keyboard-instructions`\n }\n });\n \n this.tracks.forEach((track, index) => {\n const item = this.createPlaylistItem(track, index);\n list.appendChild(item);\n });\n \n this.playlistPanel.appendChild(list);\n \n // Show panel if it should be visible\n if (this.isPanelVisible) {\n this.playlistPanel.style.display = 'block';\n }\n }\n \n /**\n * Create playlist item element\n */\n createPlaylistItem(track, index) {\n const trackPosition = i18n.t('playlist.trackOf', {\n current: index + 1,\n total: this.tracks.length\n });\n const trackTitle = track.title || i18n.t('playlist.trackUntitled', { number: index + 1 });\n const trackArtist = track.artist ? i18n.t('playlist.by') + track.artist : '';\n \n // Use effective duration (audio description duration when AD is enabled)\n const effectiveDuration = this.getEffectiveDuration(track);\n const trackDuration = effectiveDuration ? TimeUtils.formatTime(effectiveDuration) : '';\n const trackDurationReadable = effectiveDuration ? TimeUtils.formatDuration(effectiveDuration) : '';\n const isActive = index === this.currentIndex;\n \n // Build accessible label for screen readers\n // With role=\"option\" and aria-checked, screen reader will announce selection state\n // Position is already announced via aria-posinset/aria-setsize\n // Format: \"Title by Artist. 3 minutes, 45 seconds.\"\n let ariaLabel = `${trackTitle}${trackArtist}`;\n if (trackDurationReadable) {\n ariaLabel += `. ${trackDurationReadable}`;\n }\n \n // Create list item container (semantic HTML)\n const item = DOMUtils.createElement('li', {\n className: isActive ? 'vidply-playlist-item vidply-playlist-item-active' : 'vidply-playlist-item',\n attributes: {\n 'data-playlist-index': index\n }\n });\n \n // Create button wrapper for interactive content\n const button = DOMUtils.createElement('button', {\n className: 'vidply-playlist-item-button',\n attributes: {\n type: 'button',\n role: 'option',\n tabIndex: index === 0 ? 0 : -1, // Only first item is in tab order initially\n 'aria-label': ariaLabel,\n 'aria-posinset': index + 1,\n 'aria-setsize': this.tracks.length,\n 'aria-checked': isActive ? 'true' : 'false'\n }\n });\n \n // Add aria-current if active\n if (isActive) {\n button.setAttribute('aria-current', 'true');\n button.setAttribute('tabIndex', '0'); // Active item should always be tabbable\n }\n \n // Thumbnail container with optional duration badge\n const thumbnailContainer = DOMUtils.createElement('span', {\n className: 'vidply-playlist-thumbnail-container',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n \n // Thumbnail or icon\n const thumbnail = DOMUtils.createElement('span', {\n className: 'vidply-playlist-thumbnail'\n });\n \n if (track.poster) {\n thumbnail.style.backgroundImage = `url(${track.poster})`;\n } else {\n // Show music/speaker icon for audio tracks\n const icon = createIconElement('music');\n icon.classList.add('vidply-playlist-thumbnail-icon');\n thumbnail.appendChild(icon);\n }\n \n thumbnailContainer.appendChild(thumbnail);\n \n // Duration badge on thumbnail (like YouTube) - only show if there's a poster\n if (trackDuration && track.poster) {\n const durationBadge = DOMUtils.createElement('span', {\n className: 'vidply-playlist-duration-badge'\n });\n durationBadge.textContent = trackDuration;\n thumbnailContainer.appendChild(durationBadge);\n }\n \n button.appendChild(thumbnailContainer);\n \n // Info section (title, artist, description)\n const info = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-info',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n \n // Title row with optional inline duration (for when no thumbnail)\n const titleRow = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-title-row'\n });\n \n const title = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-title'\n });\n title.textContent = trackTitle;\n titleRow.appendChild(title);\n \n // Inline duration (shown when no poster/thumbnail)\n if (trackDuration && !track.poster) {\n const inlineDuration = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-duration'\n });\n inlineDuration.textContent = trackDuration;\n titleRow.appendChild(inlineDuration);\n }\n \n info.appendChild(titleRow);\n \n // Artist\n if (track.artist) {\n const artist = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-artist'\n });\n artist.textContent = track.artist;\n info.appendChild(artist);\n }\n \n // Description (truncated)\n if (track.description) {\n const description = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-description'\n });\n description.textContent = track.description;\n info.appendChild(description);\n }\n \n button.appendChild(info);\n \n // Play icon\n const playIcon = createIconElement('play');\n playIcon.classList.add('vidply-playlist-item-icon');\n playIcon.setAttribute('aria-hidden', 'true');\n button.appendChild(playIcon);\n \n // Click handler\n button.addEventListener('click', () => {\n this.play(index, true); // User-initiated\n });\n \n // Keyboard handler\n button.addEventListener('keydown', (e) => {\n this.handlePlaylistItemKeydown(e, index);\n });\n \n // Append button to list item\n item.appendChild(button);\n \n return item;\n }\n \n /**\n * Handle keyboard navigation in playlist items\n */\n handlePlaylistItemKeydown(e, index) {\n const buttons = Array.from(this.playlistPanel.querySelectorAll('.vidply-playlist-item-button'));\n let newIndex = -1;\n let announcement = '';\n \n switch(e.key) {\n case 'Enter':\n case ' ':\n e.preventDefault();\n e.stopPropagation();\n this.play(index, true); // User-initiated\n return; // No need to move focus\n \n case 'ArrowDown':\n e.preventDefault();\n e.stopPropagation();\n // Move to next item\n if (index < buttons.length - 1) {\n newIndex = index + 1;\n } else {\n // At the end, announce boundary\n announcement = `End of playlist. ${buttons.length} of ${buttons.length}.`;\n }\n break;\n \n case 'ArrowUp':\n e.preventDefault();\n e.stopPropagation();\n // Move to previous item\n if (index > 0) {\n newIndex = index - 1;\n } else {\n // At the beginning, announce boundary\n announcement = 'Beginning of playlist. 1 of ' + buttons.length + '.';\n }\n break;\n \n case 'PageDown':\n e.preventDefault();\n e.stopPropagation();\n // Move 5 items down (or to end)\n newIndex = Math.min(index + 5, buttons.length - 1);\n if (newIndex === buttons.length - 1 && index !== newIndex) {\n announcement = `Jumped to last track. ${newIndex + 1} of ${buttons.length}.`;\n }\n break;\n \n case 'PageUp':\n e.preventDefault();\n e.stopPropagation();\n // Move 5 items up (or to beginning)\n newIndex = Math.max(index - 5, 0);\n if (newIndex === 0 && index !== newIndex) {\n announcement = `Jumped to first track. 1 of ${buttons.length}.`;\n }\n break;\n \n case 'Home':\n e.preventDefault();\n e.stopPropagation();\n // Move to first item\n newIndex = 0;\n if (index !== 0) {\n announcement = `First track. 1 of ${buttons.length}.`;\n }\n break;\n \n case 'End':\n e.preventDefault();\n e.stopPropagation();\n // Move to last item\n newIndex = buttons.length - 1;\n if (index !== buttons.length - 1) {\n announcement = `Last track. ${buttons.length} of ${buttons.length}.`;\n }\n break;\n }\n \n // Update tab indices for roving tabindex pattern\n if (newIndex !== -1 && newIndex !== index) {\n buttons[index].setAttribute('tabIndex', '-1');\n buttons[newIndex].setAttribute('tabIndex', '0');\n buttons[newIndex].focus({ preventScroll: false });\n \n // Scroll the focused item into view (same behavior as mouse interaction)\n const item = buttons[newIndex].closest('.vidply-playlist-item');\n if (item) {\n item.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n }\n }\n \n // Announce navigation feedback\n if (announcement && this.navigationFeedback) {\n this.navigationFeedback.textContent = announcement;\n // Clear after a short delay to allow for repeated announcements\n setTimeout(() => {\n if (this.navigationFeedback) {\n this.navigationFeedback.textContent = '';\n }\n }, 1000);\n }\n }\n \n /**\n * Update playlist UI (highlight current track)\n */\n updatePlaylistUI() {\n if (!this.playlistPanel) return;\n \n const items = this.playlistPanel.querySelectorAll('.vidply-playlist-item');\n const buttons = this.playlistPanel.querySelectorAll('.vidply-playlist-item-button');\n \n items.forEach((item, index) => {\n const button = buttons[index];\n if (!button) return;\n \n const track = this.tracks[index];\n const trackPosition = i18n.t('playlist.trackOf', {\n current: index + 1,\n total: this.tracks.length\n });\n const trackTitle = track.title || i18n.t('playlist.trackUntitled', { number: index + 1 });\n const trackArtist = track.artist ? i18n.t('playlist.by') + track.artist : '';\n \n // Use effective duration (audio description duration when AD is enabled)\n const effectiveDuration = this.getEffectiveDuration(track);\n const trackDurationReadable = effectiveDuration ? TimeUtils.formatDuration(effectiveDuration) : '';\n \n if (index === this.currentIndex) {\n // Update list item styling\n item.classList.add('vidply-playlist-item-active');\n \n // Update button ARIA attributes\n button.setAttribute('aria-current', 'true');\n button.setAttribute('aria-checked', 'true');\n button.setAttribute('tabIndex', '0'); // Active item should be tabbable\n \n // Simplified aria-label - status and actions are announced via ARIA roles\n let ariaLabel = `${trackTitle}${trackArtist}`;\n if (trackDurationReadable) {\n ariaLabel += `. ${trackDurationReadable}`;\n }\n button.setAttribute('aria-label', ariaLabel);\n \n // Scroll into view within playlist panel (uses 'nearest' to minimize page scroll)\n item.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n } else {\n // Update list item styling\n item.classList.remove('vidply-playlist-item-active');\n \n // Update button ARIA attributes\n button.removeAttribute('aria-current');\n button.setAttribute('aria-checked', 'false');\n button.setAttribute('tabIndex', '-1'); // Remove from tab order (use arrow keys)\n \n // Simplified aria-label - status and actions are announced via ARIA roles\n let ariaLabel = `${trackTitle}${trackArtist}`;\n if (trackDurationReadable) {\n ariaLabel += `. ${trackDurationReadable}`;\n }\n button.setAttribute('aria-label', ariaLabel);\n }\n });\n }\n \n /**\n * Get current track\n */\n getCurrentTrack() {\n return this.tracks[this.currentIndex] || null;\n }\n \n /**\n * Get playlist info\n */\n getPlaylistInfo() {\n return {\n currentIndex: this.currentIndex,\n totalTracks: this.tracks.length,\n currentTrack: this.getCurrentTrack(),\n hasNext: this.hasNext(),\n hasPrevious: this.hasPrevious()\n };\n }\n \n /**\n * Check if there is a next track\n */\n hasNext() {\n if (this.options.loop) return true;\n return this.currentIndex < this.tracks.length - 1;\n }\n \n /**\n * Check if there is a previous track\n */\n hasPrevious() {\n if (this.options.loop) return true;\n return this.currentIndex > 0;\n }\n \n /**\n * Add track to playlist\n */\n addTrack(track) {\n this.tracks.push(track);\n \n if (this.playlistPanel) {\n this.renderPlaylist();\n }\n }\n \n /**\n * Remove track from playlist\n */\n removeTrack(index) {\n if (index < 0 || index >= this.tracks.length) return;\n \n this.tracks.splice(index, 1);\n \n // Adjust current index if needed\n if (index < this.currentIndex) {\n this.currentIndex--;\n } else if (index === this.currentIndex) {\n // Current track was removed, play next or stop\n if (this.currentIndex >= this.tracks.length) {\n this.currentIndex = this.tracks.length - 1;\n }\n \n if (this.currentIndex >= 0) {\n this.play(this.currentIndex);\n }\n }\n \n if (this.playlistPanel) {\n this.renderPlaylist();\n }\n }\n \n /**\n * Clear playlist\n */\n clear() {\n this.tracks = [];\n this.currentIndex = -1;\n \n if (this.playlistPanel) {\n this.playlistPanel.innerHTML = '';\n this.playlistPanel.style.display = 'none';\n }\n \n if (this.trackInfoElement) {\n this.trackInfoElement.innerHTML = '';\n this.trackInfoElement.style.display = 'none';\n }\n \n if (this.trackArtworkElement) {\n this.trackArtworkElement.style.backgroundImage = '';\n this.trackArtworkElement.style.display = 'none';\n }\n }\n \n /**\n * Toggle playlist panel visibility\n * @param {boolean} show - Optional: force show (true) or hide (false)\n * @returns {boolean} - New visibility state\n */\n togglePanel(show) {\n if (!this.playlistPanel) return false;\n \n // Determine new state\n const shouldShow = show !== undefined ? show : this.playlistPanel.style.display === 'none';\n \n if (shouldShow) {\n this.playlistPanel.style.display = 'block';\n this.isPanelVisible = true;\n \n // Focus first item if playlist has tracks\n if (this.tracks.length > 0) {\n setTimeout(() => {\n const firstItem = this.playlistPanel.querySelector('.vidply-playlist-item[tabindex=\"0\"]');\n if (firstItem) {\n firstItem.focus({ preventScroll: true });\n }\n }, 100);\n }\n \n // Update toggle button state if it exists\n if (this.player.controlBar && this.player.controlBar.controls.playlistToggle) {\n this.player.controlBar.controls.playlistToggle.setAttribute('aria-expanded', 'true');\n this.player.controlBar.controls.playlistToggle.setAttribute('aria-pressed', 'true');\n }\n } else {\n this.playlistPanel.style.display = 'none';\n this.isPanelVisible = false;\n \n // Update toggle button state if it exists\n if (this.player.controlBar && this.player.controlBar.controls.playlistToggle) {\n this.player.controlBar.controls.playlistToggle.setAttribute('aria-expanded', 'false');\n this.player.controlBar.controls.playlistToggle.setAttribute('aria-pressed', 'false');\n \n // Return focus to toggle button\n this.player.controlBar.controls.playlistToggle.focus({ preventScroll: true });\n }\n }\n \n return this.isPanelVisible;\n }\n \n /**\n * Show playlist panel\n */\n showPanel() {\n return this.togglePanel(true);\n }\n \n /**\n * Hide playlist panel\n */\n hidePanel() {\n return this.togglePanel(false);\n }\n \n /**\n * Destroy playlist manager\n */\n destroy() {\n // Remove event listeners\n this.player.off('ended', this.handleTrackEnd);\n this.player.off('error', this.handleTrackError);\n \n // Remove UI\n if (this.trackArtworkElement) {\n this.trackArtworkElement.remove();\n }\n \n if (this.trackInfoElement) {\n this.trackInfoElement.remove();\n }\n \n if (this.playlistPanel) {\n this.playlistPanel.remove();\n }\n \n // Clear data\n this.clear();\n }\n}\n\nexport default PlaylistManager;\n", "/**\r\n * VidPly - Universal Video Player\r\n * Main Entry Point\r\n */\r\n\r\nimport { Player } from './core/Player.js';\r\nimport { PlaylistManager } from './features/PlaylistManager.js';\r\n\r\n// Auto-initialize players\r\nfunction initializePlayers() {\r\n const elements = document.querySelectorAll('[data-vidply]');\r\n \r\n elements.forEach(element => {\r\n // Parse options from data attribute (JSON format)\r\n const options = element.dataset.vidplyOptions \r\n ? JSON.parse(element.dataset.vidplyOptions)\r\n : {};\r\n \r\n // Parse individual data attributes and merge with options\r\n // This allows for easier HTML-based configuration\r\n const dataOptions = parseDataAttributes(element.dataset);\r\n const mergedOptions = { ...dataOptions, ...options };\r\n \r\n // Create player instance\r\n new Player(element, mergedOptions);\r\n });\r\n}\r\n\r\n// Helper function to parse data attributes into options\r\nfunction parseDataAttributes(dataset) {\r\n const options = {};\r\n \r\n // Map of data attribute names to option keys (camelCase conversion)\r\n const attributeMap = {\r\n // Sign Language\r\n 'signLanguageSrc': 'signLanguageSrc',\r\n 'signLanguageButton': 'signLanguageButton',\r\n 'signLanguagePosition': 'signLanguagePosition',\r\n \r\n // Audio Description\r\n 'audioDescriptionSrc': 'audioDescriptionSrc',\r\n 'audioDescriptionButton': 'audioDescriptionButton',\r\n \r\n // Other common options\r\n 'autoplay': 'autoplay',\r\n 'loop': 'loop',\r\n 'muted': 'muted',\r\n 'controls': 'controls',\r\n 'poster': 'poster',\r\n 'width': 'width',\r\n 'height': 'height',\r\n 'language': 'language',\r\n 'captions': 'captions',\r\n 'captionsDefault': 'captionsDefault',\r\n 'transcript': 'transcript',\r\n 'transcriptButton': 'transcriptButton',\r\n 'keyboard': 'keyboard',\r\n 'responsive': 'responsive',\r\n 'pipButton': 'pipButton',\r\n 'fullscreenButton': 'fullscreenButton'\r\n };\r\n \r\n // Parse each data attribute\r\n Object.keys(attributeMap).forEach(dataKey => {\r\n const optionKey = attributeMap[dataKey];\r\n const value = dataset[dataKey];\r\n \r\n if (value !== undefined) {\r\n // Convert string values to appropriate types\r\n if (value === 'true') {\r\n options[optionKey] = true;\r\n } else if (value === 'false') {\r\n options[optionKey] = false;\r\n } else if (!isNaN(value) && value !== '') {\r\n options[optionKey] = Number(value);\r\n } else {\r\n options[optionKey] = value;\r\n }\r\n }\r\n });\r\n \r\n // Parse sign language sources with language codes (e.g., data-sign-language-src-en, data-sign-language-src-de)\r\n // In dataset, hyphens become camelCase: data-sign-language-src-en -> signLanguageSrcEn\r\n const signLanguageSources = {};\r\n Object.keys(dataset).forEach(key => {\r\n if (key.startsWith('signLanguageSrc') && key !== 'signLanguageSrc') {\r\n // Extract language code from key (e.g., 'signLanguageSrcEn' -> 'en', 'signLanguageSrcDe' -> 'de')\r\n // Handle both single and multi-word language codes\r\n const langMatch = key.match(/^signLanguageSrc([A-Z][a-z]*)$/);\r\n if (langMatch) {\r\n const langCode = langMatch[1].toLowerCase();\r\n signLanguageSources[langCode] = dataset[key];\r\n }\r\n }\r\n });\r\n \r\n if (Object.keys(signLanguageSources).length > 0) {\r\n options.signLanguageSources = signLanguageSources;\r\n // If there's also a single signLanguageSrc, use it as default/fallback\r\n if (dataset.signLanguageSrc && !options.signLanguageSrc) {\r\n options.signLanguageSrc = dataset.signLanguageSrc;\r\n }\r\n }\r\n \r\n // Handle language file attributes\r\n // Support for multiple language files: data-vidply-language-files='{\"pt\": \"path/to/pt.json\", \"it\": \"path/to/it.json\"}'\r\n if (dataset.vidplyLanguageFiles) {\r\n try {\r\n options.languageFiles = JSON.parse(dataset.vidplyLanguageFiles);\r\n } catch (e) {\r\n console.warn('Invalid JSON in data-vidply-language-files:', e);\r\n }\r\n }\r\n \r\n // Support for single language file: data-vidply-language-file='{\"pt\": \"path/to/pt.json\"}'\r\n // or data-vidply-language-file-code=\"pt\" + data-vidply-language-file-url=\"path/to/pt.json\"\r\n if (dataset.vidplyLanguageFile) {\r\n try {\r\n const parsed = JSON.parse(dataset.vidplyLanguageFile);\r\n // If it's an object, treat it as languageFiles\r\n if (typeof parsed === 'object' && parsed !== null) {\r\n options.languageFiles = parsed;\r\n }\r\n } catch (e) {\r\n // If parsing fails, check for separate code and URL attributes\r\n if (dataset.vidplyLanguageFileCode && dataset.vidplyLanguageFileUrl) {\r\n options.languageFile = dataset.vidplyLanguageFileCode;\r\n options.languageFileUrl = dataset.vidplyLanguageFileUrl;\r\n }\r\n }\r\n } else if (dataset.vidplyLanguageFileCode && dataset.vidplyLanguageFileUrl) {\r\n // Support separate attributes for single language file\r\n options.languageFile = dataset.vidplyLanguageFileCode;\r\n options.languageFileUrl = dataset.vidplyLanguageFileUrl;\r\n }\r\n \r\n return options;\r\n}\r\n\r\n// Auto-initialize on DOM ready\r\nif (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', initializePlayers);\r\n} else {\r\n initializePlayers();\r\n}\r\n\r\n// Export for manual initialization\r\nexport { Player, PlaylistManager };\r\nexport default Player;\r\n\r\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\r\n * Simple EventEmitter implementation\r\n */\r\n\r\nexport class EventEmitter {\r\n constructor() {\r\n this.events = {};\r\n }\r\n\r\n on(event, listener) {\r\n if (!this.events[event]) {\r\n this.events[event] = [];\r\n }\r\n this.events[event].push(listener);\r\n return this;\r\n }\r\n\r\n once(event, listener) {\r\n const onceListener = (...args) => {\r\n listener(...args);\r\n this.off(event, onceListener);\r\n };\r\n return this.on(event, onceListener);\r\n }\r\n\r\n off(event, listener) {\r\n if (!this.events[event]) return this;\r\n \r\n if (!listener) {\r\n delete this.events[event];\r\n } else {\r\n this.events[event] = this.events[event].filter(l => l !== listener);\r\n }\r\n \r\n return this;\r\n }\r\n\r\n emit(event, ...args) {\r\n if (!this.events[event]) return this;\r\n \r\n this.events[event].forEach(listener => {\r\n listener(...args);\r\n });\r\n \r\n return this;\r\n }\r\n\r\n removeAllListeners() {\r\n this.events = {};\r\n return this;\r\n }\r\n}\r\n\r\n", "/**\n * Control Bar Component\n */\n\nimport {DOMUtils} from '../utils/DOMUtils.js';\nimport {TimeUtils} from '../utils/TimeUtils.js';\nimport {createIconElement} from '../icons/Icons.js';\nimport {i18n} from '../i18n/i18n.js';\nimport {focusElement, focusFirstElement} from '../utils/FocusUtils.js';\n\nexport class ControlBar {\n constructor(player) {\n this.player = player;\n this.element = null;\n this.controls = {};\n this.hideTimeout = null;\n this.isDraggingProgress = false;\n this.isDraggingVolume = false;\n this.openMenu = null; // Track currently open menu\n this.openMenuButton = null; // Track button that opened the menu\n\n this.init();\n }\n\n init() {\n this.createElement();\n this.createControls();\n this.attachEvents();\n this.setupAutoHide();\n this.setupOverflowDetection();\n }\n\n // Helper method to check if we're on a mobile device\n isMobile() {\n return window.innerWidth < 768;\n }\n\n // Helper method to detect touch devices\n isTouchDevice() {\n return (\n ('ontouchstart' in window) ||\n (navigator.maxTouchPoints > 0) ||\n (navigator.msMaxTouchPoints > 0)\n );\n }\n\n // Smart menu positioning to avoid overflow\n positionMenu(menu, button, immediate = false) {\n const isMobile = this.isMobile();\n const isOverflowMenu = menu.classList.contains(`${this.player.options.classPrefix}-overflow-menu-list`);\n const isFullscreen = this.player.state.fullscreen;\n \n // In fullscreen, menu is appended to player container, so use fixed positioning\n if (isFullscreen && menu.parentElement === this.player.container) {\n const doFullscreenPositioning = () => {\n const buttonRect = button.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n const containerRect = this.player.container.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n \n // Position relative to player container\n const buttonCenterX = buttonRect.left + buttonRect.width / 2 - containerRect.left;\n const buttonTop = buttonRect.top - containerRect.top;\n const buttonBottom = buttonRect.bottom - containerRect.top;\n \n const spaceAbove = buttonRect.top - containerRect.top;\n const spaceBelow = containerRect.bottom - buttonRect.bottom;\n \n // Position menu above button by default\n if (spaceAbove >= menuRect.height + 20 || spaceAbove > spaceBelow) {\n menu.style.bottom = `${containerRect.height - buttonTop + 8}px`;\n menu.style.top = 'auto';\n menu.classList.remove('vidply-menu-below');\n } else {\n // Position below if more space there\n menu.style.top = `${buttonBottom + 8}px`;\n menu.style.bottom = 'auto';\n menu.classList.add('vidply-menu-below');\n }\n \n // Horizontal positioning\n if (isOverflowMenu) {\n // Overflow menu aligns to right\n const buttonRight = buttonRect.right - containerRect.left;\n menu.style.right = `${containerRect.width - buttonRight}px`;\n menu.style.left = 'auto';\n menu.style.transform = 'none';\n } else {\n // Other menus center on button\n menu.style.left = `${buttonCenterX}px`;\n menu.style.right = 'auto';\n menu.style.transform = 'translateX(-50%)';\n }\n };\n \n if (immediate) {\n doFullscreenPositioning();\n } else {\n requestAnimationFrame(doFullscreenPositioning);\n }\n return;\n }\n \n if (isMobile) {\n // On mobile, ensure menus stay within viewport\n const isVolumeMenu = menu.classList.contains(`${this.player.options.classPrefix}-volume-menu`);\n \n const doMobilePositioning = () => {\n // Get the button's parent container (controls-left or controls-right)\n const parentContainer = button.parentElement;\n if (!parentContainer) return;\n \n const buttonRect = button.getBoundingClientRect();\n const parentRect = parentContainer.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n \n // Volume menu should be centered on its button\n if (isVolumeMenu) {\n // Calculate button position relative to parent\n const buttonCenterX = buttonRect.left + buttonRect.width / 2 - parentRect.left;\n \n // Center menu on button\n menu.style.left = `${buttonCenterX}px`;\n menu.style.right = 'auto';\n menu.style.transform = 'translateX(-50%)';\n return;\n }\n \n // Check if menu overflows viewport\n if (menuRect.right > viewportWidth) {\n menu.style.left = 'auto';\n menu.style.right = '10px';\n menu.style.transform = 'none';\n }\n \n if (menuRect.left < 0) {\n menu.style.left = '10px';\n menu.style.right = 'auto';\n menu.style.transform = 'none';\n }\n \n // Ensure menu doesn't go off top or bottom\n if (menuRect.top < 10) {\n menu.style.top = '10px';\n }\n \n if (menuRect.bottom > viewportHeight - 10) {\n menu.style.bottom = '10px';\n menu.style.top = 'auto';\n }\n };\n \n if (immediate) {\n doMobilePositioning();\n } else {\n requestAnimationFrame(doMobilePositioning);\n }\n return;\n }\n\n // Desktop: Smart positioning\n // Menu is now a sibling of the button, within controls-left or controls-right container\n // These containers have position: relative, so menus position relative to them\n \n const doPositioning = () => {\n const buttonRect = button.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n \n // Get the button's parent container (controls-left or controls-right)\n const parentContainer = button.parentElement;\n if (!parentContainer) return;\n \n const parentRect = parentContainer.getBoundingClientRect();\n \n // Calculate position relative to parent container\n const buttonCenterX = buttonRect.left + buttonRect.width / 2 - parentRect.left;\n const buttonBottom = buttonRect.bottom - parentRect.top;\n const buttonTop = buttonRect.top - parentRect.top;\n \n const spaceAbove = buttonRect.top;\n const spaceBelow = viewportHeight - buttonRect.bottom;\n \n // Position menu above button by default\n let menuTop = buttonTop - menuRect.height - 8;\n let menuBottom = null;\n \n // Prefer above, but switch to below if not enough space\n if (spaceAbove < menuRect.height + 20 && spaceBelow > spaceAbove) {\n menuTop = null;\n // Calculate bottom position relative to parent container\n // bottom: X means X pixels from the bottom of the positioned parent\n // We want the menu to be 8px below the button\n const parentHeight = parentRect.bottom - parentRect.top;\n menuBottom = parentHeight - buttonBottom + 8;\n menu.classList.add('vidply-menu-below');\n } else {\n menu.classList.remove('vidply-menu-below');\n }\n \n // Calculate horizontal position\n let menuLeft = 'auto';\n let menuRight = 'auto';\n let transformX = 'translateX(0)';\n \n // For overflow menu, always align to the right edge\n if (isOverflowMenu) {\n menuLeft = 'auto';\n menuRight = 0;\n transformX = 'translateX(0)';\n } else {\n // For other menus, center on button by default\n menuLeft = buttonCenterX - menuRect.width / 2;\n \n // Check horizontal overflow\n const menuLeftAbsolute = buttonRect.left + buttonRect.width / 2 - menuRect.width / 2;\n if (menuLeftAbsolute < 10) {\n // Too far left, align to left edge of parent\n menuLeft = 0;\n transformX = 'translateX(0)';\n } else if (menuLeftAbsolute + menuRect.width > viewportWidth - 10) {\n // Too far right, align to right edge of parent\n menuLeft = 'auto';\n menuRight = 0;\n transformX = 'translateX(0)';\n } else {\n // Center on button\n menuLeft = buttonCenterX;\n transformX = 'translateX(-50%)';\n }\n }\n \n // Apply calculated positions\n if (menuTop !== null) {\n menu.style.top = `${menuTop}px`;\n menu.style.bottom = 'auto';\n } else if (menuBottom !== null) {\n menu.style.top = 'auto';\n menu.style.bottom = `${menuBottom}px`;\n }\n \n if (menuLeft !== 'auto') {\n menu.style.left = `${menuLeft}px`;\n menu.style.right = 'auto';\n } else {\n menu.style.left = 'auto';\n menu.style.right = `${menuRight}px`;\n }\n \n menu.style.transform = transformX;\n };\n \n if (immediate) {\n // Position immediately (synchronously) - used when menu is first shown\n doPositioning();\n } else {\n // Use requestAnimationFrame to ensure layout is stable before positioning\n requestAnimationFrame(() => {\n setTimeout(doPositioning, 10); // Small delay to ensure layout is stable\n });\n }\n }\n\n // Helper method to insert menu into DOM (handles fullscreen vs normal mode)\n insertMenuIntoDOM(menu, button) {\n // Ensure menu has an ID for aria-controls relationship\n if (!menu.id) {\n menu.id = `vidply-menu-${Math.random().toString(36).substr(2, 9)}`;\n }\n \n // Set ARIA attributes for screen reader users (WCAG 4.1.2)\n button.setAttribute('aria-controls', menu.id);\n button.setAttribute('aria-haspopup', 'true');\n \n // In fullscreen, append menu to player container to escape video-wrapper stacking context\n // This allows menus to appear above the playlist panel\n // Otherwise, keep it after the button for WCAG compliance\n const isFullscreen = this.player.state.fullscreen;\n if (isFullscreen) {\n // Append to player container as sibling to playlist panel\n this.player.container.appendChild(menu);\n // Store reference to button for positioning\n menu.dataset.triggerButton = button.getAttribute('aria-label') || 'button';\n } else {\n // Insert menu right after the button in the DOM for keyboard navigation\n button.insertAdjacentElement('afterend', menu);\n }\n }\n\n // Helper method to attach close-on-outside-click behavior to menus\n attachMenuCloseHandler(menu, button, preventCloseOnInteraction = false) {\n // Close any previously open menu and clean up its handlers\n if (this.openMenu && this.openMenu !== menu && this.openMenuButton) {\n // Remove previous button's blur handler if it exists\n if (this.openMenuButton._vidplyBlurHandler) {\n this.openMenuButton.removeEventListener('blur', this.openMenuButton._vidplyBlurHandler);\n delete this.openMenuButton._vidplyBlurHandler;\n }\n if (this.openMenuButton._vidplyMousedownHandler) {\n this.openMenuButton.removeEventListener('mousedown', this.openMenuButton._vidplyMousedownHandler);\n delete this.openMenuButton._vidplyMousedownHandler;\n }\n \n // Close previous menu without returning focus\n if (this.openMenu && document.contains(this.openMenu)) {\n this.openMenu.remove();\n } else if (this.openMenu && this.openMenu.parentNode) {\n this.openMenu.parentNode.removeChild(this.openMenu);\n }\n if (this.openMenuButton) {\n this.openMenuButton.setAttribute('aria-expanded', 'false');\n }\n }\n \n // Track this menu as open\n this.openMenu = menu;\n this.openMenuButton = button;\n \n // Position menu smartly\n this.positionMenu(menu, button);\n \n // Set aria-expanded to true when menu opens\n if (button) {\n button.setAttribute('aria-expanded', 'true');\n }\n \n // Add focus handler to button to close menu when focus leaves to another control bar button\n // But only if it's a keyboard navigation (Tab), not a click\n let isClickingButton = false;\n let blurHandlerActive = true;\n \n const handleButtonMousedown = () => {\n isClickingButton = true;\n // Temporarily disable blur handler when clicking\n blurHandlerActive = false;\n setTimeout(() => {\n isClickingButton = false;\n blurHandlerActive = true;\n }, 200);\n };\n button.addEventListener('mousedown', handleButtonMousedown);\n button._vidplyMousedownHandler = handleButtonMousedown; // Store for cleanup\n \n const handleButtonBlur = (e) => {\n // If blur handler is disabled (during click) or this is a click, don't close the menu\n if (!blurHandlerActive || isClickingButton) {\n return;\n }\n \n // Check if this menu is still the open menu (might have been replaced)\n if (this.openMenu !== menu) {\n return;\n }\n \n // Store the related target (where focus is going) before async operations\n const relatedTarget = e.relatedTarget;\n \n // Use requestAnimationFrame to check where focus went after browser handles focus\n requestAnimationFrame(() => {\n setTimeout(() => {\n // Check again if blur handler is still active and menu is still open\n if (!blurHandlerActive || this.openMenu !== menu) {\n return;\n }\n \n const activeElement = document.activeElement;\n \n // Don't close if focus is still within the menu\n if (menu.contains(activeElement)) {\n return;\n }\n \n // Don't close if focus moved to sign language or transcript windows\n const signLanguageWrapper = this.player.signLanguageWrapper;\n const transcriptWindow = this.player.transcriptManager?.transcriptWindow;\n if ((signLanguageWrapper && signLanguageWrapper.contains(activeElement)) ||\n (transcriptWindow && transcriptWindow.contains(activeElement))) {\n return;\n }\n \n // If focus moved to another button in the control bar, close the menu\n const controlBarButtons = this.element.querySelectorAll('button');\n const isFocusOnAnotherButton = Array.from(controlBarButtons).includes(activeElement) && activeElement !== button;\n \n // Also check relatedTarget in case activeElement hasn't updated yet\n const isRelatedTargetAnotherButton = relatedTarget && Array.from(controlBarButtons).includes(relatedTarget) && relatedTarget !== button;\n \n // Close menu if focus moved to another control bar button (without returning focus)\n if (isFocusOnAnotherButton || isRelatedTargetAnotherButton) {\n // Double-check this menu is still the open menu\n if (this.openMenu !== menu) {\n return;\n }\n \n // Just remove the menu, don't touch focus at all\n if (menu && document.contains(menu)) {\n menu.remove();\n } else if (menu && menu.parentNode) {\n menu.parentNode.removeChild(menu);\n }\n if (button) {\n button.setAttribute('aria-expanded', 'false');\n }\n // Clear tracking\n if (this.openMenu === menu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n button.removeEventListener('blur', handleButtonBlur);\n button.removeEventListener('mousedown', handleButtonMousedown);\n delete button._vidplyBlurHandler;\n delete button._vidplyMousedownHandler;\n }\n }, 10); // Small delay to ensure focus has fully moved\n });\n };\n button.addEventListener('blur', handleButtonBlur);\n button._vidplyBlurHandler = handleButtonBlur; // Store for cleanup\n \n const closeMenuAndUpdateAria = () => {\n this.closeMenuAndReturnFocus(menu, button);\n };\n \n // Store document handlers for cleanup\n let documentClickHandler = null;\n let documentEscapeHandler = null;\n \n setTimeout(() => {\n documentClickHandler = (e) => {\n // If this menu has form controls, don't close when clicking inside\n if (preventCloseOnInteraction && menu.contains(e.target)) {\n return;\n }\n\n // Check if click is outside menu and button\n // Also check if this menu is still the open menu\n if (this.openMenu === menu && !menu.contains(e.target) && !button.contains(e.target)) {\n closeMenuAndUpdateAria();\n if (documentClickHandler) {\n document.removeEventListener('click', documentClickHandler);\n }\n if (documentEscapeHandler) {\n document.removeEventListener('keydown', documentEscapeHandler);\n }\n }\n };\n\n documentEscapeHandler = (e) => {\n if (e.key === 'Escape' && this.openMenu === menu) {\n e.preventDefault();\n e.stopPropagation();\n // Close menu and return focus to the button that opened it\n this.closeMenuAndReturnFocus(menu, button, true);\n if (documentClickHandler) {\n document.removeEventListener('click', documentClickHandler);\n }\n if (documentEscapeHandler) {\n document.removeEventListener('keydown', documentEscapeHandler);\n }\n }\n };\n\n document.addEventListener('click', documentClickHandler);\n document.addEventListener('keydown', documentEscapeHandler);\n }, 100);\n }\n\n // Helper method to close menu and return focus to button\n closeMenuAndReturnFocus(menu, button, returnFocus = true) {\n if (menu) {\n // Remove menu from DOM - use remove() which works reliably\n if (document.contains(menu)) {\n menu.remove();\n } else if (menu.parentNode) {\n // Fallback if menu is not in document but has parent\n menu.parentNode.removeChild(menu);\n }\n }\n if (button) {\n button.setAttribute('aria-expanded', 'false');\n // Clean up aria-controls since menu is removed (optional, but cleaner)\n // Note: Keeping it doesn't cause issues, but removing it is semantically correct\n // when the referenced element no longer exists\n if (menu && menu.id) {\n button.removeAttribute('aria-controls');\n }\n // Only return focus if explicitly requested (not when tabbing away)\n if (returnFocus) {\n // Use requestAnimationFrame to ensure DOM updates are complete before focusing\n // This prevents focus from jumping to next/previous button\n requestAnimationFrame(() => {\n setTimeout(() => {\n if (button && document.contains(button)) {\n button.focus({ preventScroll: true });\n }\n }, 0);\n });\n }\n }\n // Clear tracking\n if (this.openMenu === menu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n }\n \n // Close any open menu when tabbing to another button or clicking another button\n closeOpenMenu() {\n if (this.openMenu && this.openMenuButton) {\n // Close without returning focus (user is tabbing to next element or clicking another button)\n if (this.openMenu && document.contains(this.openMenu)) {\n this.openMenu.remove();\n } else if (this.openMenu && this.openMenu.parentNode) {\n this.openMenu.parentNode.removeChild(this.openMenu);\n }\n if (this.openMenuButton) {\n this.openMenuButton.setAttribute('aria-expanded', 'false');\n }\n // Clear tracking\n this.openMenu = null;\n this.openMenuButton = null;\n }\n }\n\n // Helper method to add keyboard navigation to menus (arrow keys)\n attachMenuKeyboardNavigation(menu, button) {\n const menuItems = Array.from(menu.querySelectorAll(`.${this.player.options.classPrefix}-menu-item`));\n \n if (menuItems.length === 0) return;\n\n const handleKeyDown = (e) => {\n const currentIndex = menuItems.indexOf(document.activeElement);\n \n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n e.stopPropagation(); // Prevent volume/seek actions\n const nextIndex = (currentIndex + 1) % menuItems.length;\n menuItems[nextIndex].focus({ preventScroll: false });\n menuItems[nextIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n break;\n \n case 'ArrowUp':\n e.preventDefault();\n e.stopPropagation(); // Prevent volume/seek actions\n const prevIndex = (currentIndex - 1 + menuItems.length) % menuItems.length;\n menuItems[prevIndex].focus({ preventScroll: false });\n menuItems[prevIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n break;\n \n case 'ArrowLeft':\n case 'ArrowRight':\n // Prevent seeking when in menu (but allow menu to handle if needed)\n e.preventDefault();\n e.stopPropagation();\n break;\n \n case 'Home':\n e.preventDefault();\n e.stopPropagation();\n menuItems[0].focus({ preventScroll: false });\n menuItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n break;\n \n case 'End':\n e.preventDefault();\n e.stopPropagation();\n menuItems[menuItems.length - 1].focus({ preventScroll: false });\n menuItems[menuItems.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n break;\n \n case 'Enter':\n case ' ':\n e.preventDefault();\n e.stopPropagation(); // Prevent event from reaching KeyboardManager\n if (document.activeElement && menuItems.includes(document.activeElement)) {\n document.activeElement.click();\n // Menu will be closed by the click handler, but ensure focus returns\n focusElement(button, { delay: 0 });\n }\n break;\n \n case 'Escape':\n e.preventDefault();\n e.stopPropagation(); // Prevent event from reaching KeyboardManager\n // Close menu and return focus to the button that opened it\n this.closeMenuAndReturnFocus(menu, button, true);\n break;\n }\n };\n\n menu.addEventListener('keydown', handleKeyDown);\n }\n\n createElement() {\n this.element = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-controls`,\n attributes: {\n 'role': 'region',\n 'aria-label': i18n.t('player.label') + ' controls'\n }\n });\n }\n\n createControls() {\n // Progress bar and time display wrapper\n const progressTimeWrapper = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-time-wrapper`\n });\n\n // Progress bar container\n if (this.player.options.progressBar) {\n this.createProgressBar();\n progressTimeWrapper.appendChild(this.controls.progress);\n }\n\n // Time display (right beside progress bar)\n if (this.player.options.currentTime || this.player.options.duration) {\n progressTimeWrapper.appendChild(this.createTimeDisplay());\n }\n\n this.element.appendChild(progressTimeWrapper);\n\n // Button container\n const buttonContainer = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-controls-buttons`\n });\n\n // Left buttons\n const leftButtons = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-controls-left`\n });\n\n // Previous track button (if playlist)\n if (this.player.playlistManager) {\n leftButtons.appendChild(this.createPreviousButton());\n }\n\n // Play/Pause button\n if (this.player.options.playPauseButton) {\n leftButtons.appendChild(this.createPlayPauseButton());\n }\n\n // Restart button (right beside play button)\n leftButtons.appendChild(this.createRestartButton());\n\n // Next track button (if playlist)\n if (this.player.playlistManager) {\n leftButtons.appendChild(this.createNextButton());\n }\n\n // Rewind button (not shown in playlist mode)\n if (!this.player.playlistManager) {\n leftButtons.appendChild(this.createRewindButton());\n }\n\n // Forward button (not shown in playlist mode)\n if (!this.player.playlistManager) {\n leftButtons.appendChild(this.createForwardButton());\n }\n\n // Volume control\n if (this.player.options.volumeControl) {\n // On touch devices: simple mute button (hardware buttons control volume)\n // On desktop: full volume control with slider\n if (this.isTouchDevice()) {\n leftButtons.appendChild(this.createMuteButton());\n } else {\n leftButtons.appendChild(this.createVolumeControl());\n }\n }\n\n // Right buttons\n this.rightButtons = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-controls-right`\n });\n\n // Check for available features\n const hasChapters = this.hasChapterTracks();\n const hasCaptions = this.hasCaptionTracks();\n const hasQualityLevels = this.hasQualityLevels();\n const hasAudioDescription = this.hasAudioDescription();\n\n // Priority order (lower number = higher priority, stays visible longer)\n // Desktop (>768px):\n // Priority 1: Play, Volume, Captions, Speed, Fullscreen\n // Priority 2: Audio Description, Quality \n // Priority 3: Chapters, Caption Style, Transcript, Sign Language, PiP\n // Smaller screens (<768px):\n // Priority 1: Play, Volume, Progress (only left controls visible)\n // Priority 3: ALL right-side buttons go to overflow menu\n\n // 1. Chapters button\n if (this.player.options.chaptersButton && hasChapters) {\n const btn = this.createChaptersButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 2. Captions button\n if (this.player.options.captionsButton && hasCaptions) {\n const btn = this.createCaptionsButton();\n btn.dataset.overflowPriority = '1';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 3. Caption styling button\n if (this.player.options.captionStyleButton && hasCaptions) {\n const btn = this.createCaptionStyleButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 4. Playback speed button\n if (this.player.options.speedButton) {\n const btn = this.createSpeedButton();\n btn.dataset.overflowPriority = '1';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 5. Audio Description button\n if (this.player.options.audioDescriptionButton && hasAudioDescription) {\n const btn = this.createAudioDescriptionButton();\n btn.dataset.overflowPriority = '2';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 6. Transcript button\n if (this.player.options.transcriptButton && hasCaptions) {\n const btn = this.createTranscriptButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 6.5 Playlist toggle button (for playlists)\n if (this.player.playlistManager && this.player.options.playlistToggleButton !== false) {\n const btn = this.createPlaylistToggleButton();\n btn.dataset.overflowPriority = '2';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 7. Sign Language button\n const hasSignLanguage = this.hasSignLanguage();\n if (this.player.options.signLanguageButton && hasSignLanguage) {\n const btn = this.createSignLanguageButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // Quality button (before fullscreen)\n if (this.player.options.qualityButton && hasQualityLevels) {\n const btn = this.createQualityButton();\n btn.dataset.overflowPriority = '2';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // PiP button (before fullscreen)\n if (this.player.options.pipButton && 'pictureInPictureEnabled' in document) {\n const btn = this.createPipButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // 8. Fullscreen button (last)\n // Don't show fullscreen button for audio players\n const isAudioPlayer = this.player.element.tagName.toLowerCase() === 'audio';\n if (this.player.options.fullscreenButton && !isAudioPlayer) {\n const btn = this.createFullscreenButton();\n btn.dataset.overflowPriority = '1';\n btn.dataset.overflowPriorityMobile = '3';\n this.rightButtons.appendChild(btn);\n }\n\n // Create overflow menu button (initially hidden)\n this.overflowMenuButton = this.createOverflowMenuButton();\n this.overflowMenuButton.style.display = 'none';\n this.rightButtons.appendChild(this.overflowMenuButton);\n\n buttonContainer.appendChild(leftButtons);\n buttonContainer.appendChild(this.rightButtons);\n this.element.appendChild(buttonContainer);\n \n // Ensure all buttons have title attributes\n this.ensureButtonTooltips(buttonContainer);\n }\n \n /**\n * Ensure all buttons in the controls have title attributes\n * Uses aria-label as title if title is not present\n */\n ensureButtonTooltips(container) {\n const buttons = container.querySelectorAll('button');\n buttons.forEach(button => {\n // Skip if tooltip already exists\n if (button.querySelector(`.${this.player.options.classPrefix}-tooltip`)) {\n return;\n }\n \n // Skip if button text already exists\n if (button.querySelector(`.${this.player.options.classPrefix}-button-text`)) {\n return;\n }\n \n // Skip menu items - they already have visible text\n if (button.getAttribute('role') === 'menuitem' || \n button.classList.contains(`${this.player.options.classPrefix}-settings-item`) ||\n button.classList.contains(`${this.player.options.classPrefix}-menu-item`) ||\n button.classList.contains(`${this.player.options.classPrefix}-transcript-settings-item`) ||\n button.classList.contains(`${this.player.options.classPrefix}-sign-language-settings-item`) ||\n button.classList.contains(`${this.player.options.classPrefix}-popup-settings-item`)) {\n return;\n }\n \n const ariaLabel = button.getAttribute('aria-label');\n if (ariaLabel) {\n // Add tooltip (aria-hidden popover)\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n }\n });\n }\n\n // Helper methods to check for available features\n hasChapterTracks() {\n const textTracks = this.player.element.textTracks;\n for (let i = 0; i < textTracks.length; i++) {\n if (textTracks[i].kind === 'chapters') {\n return true;\n }\n }\n return false;\n }\n\n hasCaptionTracks() {\n const textTracks = this.player.element.textTracks;\n for (let i = 0; i < textTracks.length; i++) {\n if (textTracks[i].kind === 'captions' || textTracks[i].kind === 'subtitles') {\n return true;\n }\n }\n return false;\n }\n\n hasQualityLevels() {\n // Check if renderer supports quality selection\n if (this.player.renderer && this.player.renderer.getQualities) {\n const qualities = this.player.renderer.getQualities();\n return qualities && qualities.length > 1;\n }\n return false;\n }\n\n hasAudioDescription() {\n // Check for audio-described video source OR description tracks\n if (this.player.audioDescriptionSrc && this.player.audioDescriptionSrc.length > 0) {\n return true;\n }\n \n // Check for description tracks\n const textTracks = Array.from(this.player.element.textTracks || []);\n return textTracks.some(track => track.kind === 'descriptions');\n }\n\n hasSignLanguage() {\n // Check for single source or multiple sources\n const hasSingleSource = this.player.signLanguageSrc && this.player.signLanguageSrc.length > 0;\n const hasMultipleSources = this.player.signLanguageSources && Object.keys(this.player.signLanguageSources).length > 0;\n return hasSingleSource || hasMultipleSources;\n }\n\n createProgressBar() {\n const progressContainer = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-container`,\n attributes: {\n 'role': 'slider',\n 'aria-label': i18n.t('player.progress'),\n 'aria-valuemin': '0',\n 'aria-valuemax': '100',\n 'aria-valuenow': '0',\n 'tabindex': '0'\n }\n });\n\n // Buffered progress\n this.controls.buffered = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-buffered`\n });\n\n // Played progress\n this.controls.played = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-played`\n });\n\n // Progress handle\n this.controls.progressHandle = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-handle`\n });\n\n // Tooltip\n this.controls.progressTooltip = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-progress-tooltip`\n });\n\n progressContainer.appendChild(this.controls.buffered);\n progressContainer.appendChild(this.controls.played);\n this.controls.played.appendChild(this.controls.progressHandle);\n progressContainer.appendChild(this.controls.progressTooltip);\n\n this.controls.progress = progressContainer;\n\n // Progress bar events\n this.setupProgressBarEvents();\n }\n\n setupProgressBarEvents() {\n const progress = this.controls.progress;\n\n const updateProgress = (clientX) => {\n const rect = progress.getBoundingClientRect();\n // Guard against division by zero if progress bar has no width\n const percent = rect.width > 0 ? Math.max(0, Math.min(1, (clientX - rect.left) / rect.width)) : 0;\n const duration = this.player.state.duration || 0;\n const time = percent * duration;\n return {percent, time};\n };\n\n // Mouse events\n progress.addEventListener('mousedown', (e) => {\n this.isDraggingProgress = true;\n const {time} = updateProgress(e.clientX);\n this.player.seek(time);\n });\n\n document.addEventListener('mousemove', (e) => {\n if (this.isDraggingProgress) {\n const {time} = updateProgress(e.clientX);\n this.player.seek(time);\n }\n });\n\n document.addEventListener('mouseup', () => {\n this.isDraggingProgress = false;\n });\n\n // Hover tooltip\n progress.addEventListener('mousemove', (e) => {\n if (!this.isDraggingProgress) {\n const {time} = updateProgress(e.clientX);\n // Update tooltip text content instead of aria-label (divs shouldn't have aria-label)\n this.controls.progressTooltip.textContent = TimeUtils.formatTime(time);\n this.controls.progressTooltip.style.left = `${e.clientX - progress.getBoundingClientRect().left}px`;\n this.controls.progressTooltip.style.display = 'block';\n }\n });\n\n progress.addEventListener('mouseleave', () => {\n this.controls.progressTooltip.style.display = 'none';\n });\n\n // Keyboard navigation\n progress.addEventListener('keydown', (e) => {\n if (e.key === 'ArrowLeft') {\n e.preventDefault();\n this.player.seekBackward(5);\n } else if (e.key === 'ArrowRight') {\n e.preventDefault();\n this.player.seekForward(5);\n }\n });\n\n // Touch events\n progress.addEventListener('touchstart', (e) => {\n this.isDraggingProgress = true;\n const touch = e.touches[0];\n const {time} = updateProgress(touch.clientX);\n this.player.seek(time);\n });\n\n progress.addEventListener('touchmove', (e) => {\n if (this.isDraggingProgress) {\n e.preventDefault();\n const touch = e.touches[0];\n const {time} = updateProgress(touch.clientX);\n this.player.seek(time);\n }\n });\n\n progress.addEventListener('touchend', () => {\n this.isDraggingProgress = false;\n });\n }\n\n createPlayPauseButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-play-pause`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.play')\n }\n });\n\n button.appendChild(createIconElement('play'));\n\n button.addEventListener('click', () => {\n this.player.toggle();\n });\n\n this.controls.playPause = button;\n return button;\n }\n\n createRestartButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-restart`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.restart')\n }\n });\n\n button.appendChild(createIconElement('restart'));\n\n button.addEventListener('click', () => {\n this.player.seek(0);\n this.player.play();\n });\n\n return button;\n }\n\n createPreviousButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-previous`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.previous')\n }\n });\n\n button.appendChild(createIconElement('skipPrevious'));\n\n button.addEventListener('click', () => {\n if (this.player.playlistManager) {\n this.player.playlistManager.previous();\n }\n });\n\n // Update button state\n const updateState = () => {\n if (this.player.playlistManager) {\n button.disabled = !this.player.playlistManager.hasPrevious() && !this.player.playlistManager.options.loop;\n }\n };\n this.player.on('playlisttrackchange', updateState);\n updateState();\n\n this.controls.previous = button;\n return button;\n }\n\n createNextButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-next`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.next')\n }\n });\n\n button.appendChild(createIconElement('skipNext'));\n\n button.addEventListener('click', () => {\n if (this.player.playlistManager) {\n this.player.playlistManager.next();\n }\n });\n\n // Update button state\n const updateState = () => {\n if (this.player.playlistManager) {\n button.disabled = !this.player.playlistManager.hasNext() && !this.player.playlistManager.options.loop;\n }\n };\n this.player.on('playlisttrackchange', updateState);\n updateState();\n\n this.controls.next = button;\n return button;\n }\n\n createPlaylistToggleButton() {\n // Get unique panel ID from playlist manager\n const panelId = this.player.playlistManager ? `${this.player.playlistManager.uniqueId}-panel` : 'vidply-playlist-panel';\n \n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-playlist-toggle`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.playlist'),\n 'aria-expanded': 'false',\n 'aria-pressed': 'false',\n 'aria-controls': panelId\n }\n });\n\n button.appendChild(createIconElement('playlist'));\n\n button.addEventListener('click', () => {\n if (this.player.playlistManager) {\n this.player.playlistManager.togglePanel();\n }\n });\n\n this.controls.playlistToggle = button;\n return button;\n }\n\n createRewindButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-rewind`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.rewindSeconds', { seconds: 15 })\n }\n });\n\n button.appendChild(createIconElement('rewind'));\n\n button.addEventListener('click', () => {\n this.player.seekBackward(15);\n });\n\n return button;\n }\n\n createForwardButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-forward`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.forwardSeconds', { seconds: 15 })\n }\n });\n\n button.appendChild(createIconElement('forward'));\n\n button.addEventListener('click', () => {\n this.player.seekForward(15);\n });\n\n return button;\n }\n\n createMuteButton() {\n // Simple mute/unmute button for touch devices\n const muteButton = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-mute`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.mute')\n }\n });\n\n muteButton.appendChild(createIconElement('volumeHigh'));\n\n // Simply toggle mute on click/touch\n muteButton.addEventListener('click', () => {\n this.player.toggleMute();\n });\n\n this.controls.mute = muteButton;\n\n return muteButton;\n }\n\n createVolumeControl() {\n // Mute/Volume button with slider (desktop)\n const muteButton = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-mute`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.volume'),\n 'aria-expanded': 'false'\n }\n });\n\n muteButton.appendChild(createIconElement('volumeHigh'));\n\n // Toggle mute on right click, show volume slider on left click\n muteButton.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n this.player.toggleMute();\n });\n\n muteButton.addEventListener('click', () => {\n this.showVolumeSlider(muteButton);\n });\n\n this.controls.mute = muteButton;\n\n return muteButton;\n }\n\n showVolumeSlider(button) {\n // Remove existing slider if any\n const existingSlider = document.querySelector(`.${this.player.options.classPrefix}-volume-menu`);\n if (existingSlider) {\n existingSlider.remove();\n button.setAttribute('aria-expanded', 'false');\n return;\n }\n\n // Volume menu container\n const volumeMenu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-menu ${this.player.options.classPrefix}-menu`\n });\n\n const volumeSlider = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-slider`,\n attributes: {\n 'role': 'slider',\n 'aria-label': i18n.t('player.volume'),\n 'aria-valuemin': '0',\n 'aria-valuemax': '100',\n 'aria-valuenow': String(Math.round(this.player.state.volume * 100)),\n 'tabindex': '0'\n }\n });\n\n const volumeTrack = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-track`\n });\n\n const volumeFill = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-fill`\n });\n \n // Set initial fill height based on current volume\n const initialVolumePercent = this.player.state.volume * 100;\n volumeFill.style.height = `${initialVolumePercent}%`;\n\n const volumeHandle = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-volume-handle`\n });\n\n volumeTrack.appendChild(volumeFill);\n volumeFill.appendChild(volumeHandle);\n volumeSlider.appendChild(volumeTrack);\n volumeMenu.appendChild(volumeSlider);\n\n // Volume slider events\n const updateVolume = (clientY) => {\n const rect = volumeTrack.getBoundingClientRect();\n const percent = Math.max(0, Math.min(1, 1 - ((clientY - rect.top) / rect.height)));\n this.player.setVolume(percent);\n };\n\n // Mouse events\n volumeSlider.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n this.isDraggingVolume = true;\n updateVolume(e.clientY);\n });\n\n document.addEventListener('mousemove', (e) => {\n if (this.isDraggingVolume) {\n updateVolume(e.clientY);\n }\n });\n\n document.addEventListener('mouseup', () => {\n this.isDraggingVolume = false;\n });\n\n // Touch events for iOS and mobile devices\n volumeSlider.addEventListener('touchstart', (e) => {\n e.stopPropagation();\n e.preventDefault();\n this.isDraggingVolume = true;\n const touch = e.touches[0];\n updateVolume(touch.clientY);\n }, { passive: false });\n\n volumeSlider.addEventListener('touchmove', (e) => {\n if (this.isDraggingVolume) {\n e.preventDefault();\n const touch = e.touches[0];\n updateVolume(touch.clientY);\n }\n }, { passive: false });\n\n volumeSlider.addEventListener('touchend', (e) => {\n e.stopPropagation();\n e.preventDefault();\n this.isDraggingVolume = false;\n }, { passive: false });\n\n volumeSlider.addEventListener('touchcancel', () => {\n this.isDraggingVolume = false;\n });\n\n // Keyboard volume control\n volumeSlider.addEventListener('keydown', (e) => {\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n this.player.setVolume(Math.min(1, this.player.state.volume + 0.1));\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n this.player.setVolume(Math.max(0, this.player.state.volume - 0.1));\n } else if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n // Close menu and return focus to button\n this.closeMenuAndReturnFocus(volumeMenu, button, true);\n }\n });\n\n // Prevent menu from closing when interacting with slider\n volumeMenu.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n \n // Prevent menu from closing on touch events\n volumeMenu.addEventListener('touchstart', (e) => {\n e.stopPropagation();\n });\n \n volumeMenu.addEventListener('touchmove', (e) => {\n e.stopPropagation();\n });\n \n volumeMenu.addEventListener('touchend', (e) => {\n e.stopPropagation();\n });\n\n // Position menu first (before it's visible) to prevent jumping\n volumeMenu.style.visibility = 'hidden';\n volumeMenu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(volumeMenu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(volumeMenu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n volumeMenu.style.visibility = 'visible';\n });\n\n this.controls.volumeSlider = volumeSlider;\n this.controls.volumeFill = volumeFill;\n\n // Focus the volume slider for keyboard accessibility\n focusElement(volumeSlider, { delay: 50 });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(volumeMenu, button, true);\n }\n\n createTimeDisplay() {\n const container = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-time`,\n attributes: {\n 'role': 'group',\n 'aria-label': i18n.t('time.display')\n }\n });\n\n // Current time - visual text hidden, accessible text provided via sr-only span\n this.controls.currentTimeDisplay = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-current-time`\n });\n \n // Create visual text inside, hidden from screen readers\n const currentTimeVisual = DOMUtils.createElement('span', {\n textContent: '00:00',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n const currentTimeAccessible = DOMUtils.createElement('span', {\n className: 'vidply-sr-only',\n textContent: i18n.t('time.seconds', { count: 0 })\n });\n\n this.controls.currentTimeDisplay.appendChild(currentTimeVisual);\n this.controls.currentTimeDisplay.appendChild(currentTimeAccessible);\n this.controls.currentTimeVisual = currentTimeVisual;\n this.controls.currentTimeAccessible = currentTimeAccessible;\n\n const separator = DOMUtils.createElement('span', {\n textContent: ' / ',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n\n // Duration - visual text hidden, accessible text provided via sr-only span\n this.controls.durationDisplay = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-duration`\n });\n \n // Create visual text inside, hidden from screen readers\n const durationVisual = DOMUtils.createElement('span', {\n textContent: '00:00',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n const durationAccessible = DOMUtils.createElement('span', {\n className: 'vidply-sr-only',\n textContent: i18n.t('time.durationPrefix') + i18n.t('time.seconds', { count: 0 })\n });\n\n this.controls.durationDisplay.appendChild(durationVisual);\n this.controls.durationDisplay.appendChild(durationAccessible);\n this.controls.durationVisual = durationVisual;\n this.controls.durationAccessible = durationAccessible;\n\n container.appendChild(this.controls.currentTimeDisplay);\n container.appendChild(separator);\n container.appendChild(this.controls.durationDisplay);\n\n return container;\n }\n\n createChaptersButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-chapters`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.chapters'),\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('chapters'));\n\n button.addEventListener('click', () => {\n this.showChaptersMenu(button);\n });\n\n this.controls.chapters = button;\n return button;\n }\n\n showChaptersMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-chapters-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-chapters-menu ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('player.chapters')\n }\n });\n\n // Get chapter tracks\n const chapterTracks = Array.from(this.player.element.textTracks).filter(\n track => track.kind === 'chapters'\n );\n\n if (chapterTracks.length === 0) {\n // No chapters available\n const noChaptersItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noChapters'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noChaptersItem);\n } else {\n const chapterTrack = chapterTracks[0];\n\n // Ensure track is in 'hidden' mode to load cues\n if (chapterTrack.mode === 'disabled') {\n chapterTrack.mode = 'hidden';\n }\n\n if (!chapterTrack.cues || chapterTrack.cues.length === 0) {\n // Cues not loaded yet - wait for them to load\n const loadingItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.loadingChapters'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(loadingItem);\n\n // Listen for track load event\n const onTrackLoad = () => {\n // Remove loading message and rebuild menu\n menu.remove();\n this.showChaptersMenu(button);\n };\n\n chapterTrack.addEventListener('load', onTrackLoad, {once: true});\n\n // Also try again after a short delay as fallback\n setTimeout(() => {\n if (chapterTrack.cues && chapterTrack.cues.length > 0 && document.contains(menu)) {\n menu.remove();\n this.showChaptersMenu(button);\n }\n }, 500);\n } else {\n // Display chapters\n const cues = chapterTrack.cues;\n for (let i = 0; i < cues.length; i++) {\n const cue = cues[i];\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n const timeLabel = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-chapter-time`,\n textContent: TimeUtils.formatTime(cue.startTime),\n attributes: {\n 'aria-label': TimeUtils.formatDuration(cue.startTime)\n }\n });\n\n const titleLabel = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-chapter-title`,\n textContent: cue.text\n });\n\n item.appendChild(timeLabel);\n item.appendChild(document.createTextNode(' '));\n item.appendChild(titleLabel);\n\n item.addEventListener('click', () => {\n this.player.seek(cue.startTime);\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n }\n \n // Add keyboard navigation\n this.attachMenuKeyboardNavigation(menu, button);\n \n // Focus first item\n setTimeout(() => {\n const firstItem = menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (firstItem) {\n firstItem.focus({ preventScroll: true });\n }\n }, 0);\n }\n }\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n }\n\n createQualityButton() {\n const ariaLabel = i18n.t('player.quality');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-quality`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('hd'));\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n // Add quality indicator text\n const qualityText = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-quality-text`,\n textContent: ''\n });\n button.appendChild(qualityText);\n\n button.addEventListener('click', () => {\n this.showQualityMenu(button);\n });\n\n this.controls.quality = button;\n this.controls.qualityText = qualityText;\n \n // Update quality indicator after a short delay to ensure renderer is ready\n setTimeout(() => this.updateQualityIndicator(), 500);\n \n return button;\n }\n\n showQualityMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-quality-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-quality-menu ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('player.quality')\n }\n });\n\n // Check if renderer supports quality selection\n if (this.player.renderer && this.player.renderer.getQualities) {\n const qualities = this.player.renderer.getQualities();\n const currentQuality = this.player.renderer.getCurrentQuality ? this.player.renderer.getCurrentQuality() : -1;\n const isHLS = this.player.renderer.hls !== undefined;\n\n if (qualities.length === 0) {\n // No qualities available\n const noQualityItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.autoQuality'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noQualityItem);\n } else {\n let activeItem = null;\n \n // Auto quality option (only for HLS)\n if (isHLS) {\n const autoItem = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.auto'),\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n // Check if auto is currently selected\n const isAuto = this.player.renderer.hls && this.player.renderer.hls.currentLevel === -1;\n if (isAuto) {\n autoItem.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n autoItem.appendChild(createIconElement('check'));\n activeItem = autoItem;\n }\n\n autoItem.addEventListener('click', () => {\n if (this.player.renderer.switchQuality) {\n this.player.renderer.switchQuality(-1); // -1 for auto\n }\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(autoItem);\n }\n\n // Quality options\n qualities.forEach(quality => {\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: quality.name || `${quality.height}p`,\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n // Highlight current quality\n if (quality.index === currentQuality) {\n item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n item.appendChild(createIconElement('check'));\n activeItem = item;\n }\n\n item.addEventListener('click', () => {\n if (this.player.renderer.switchQuality) {\n this.player.renderer.switchQuality(quality.index);\n }\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n });\n \n // Add keyboard navigation\n this.attachMenuKeyboardNavigation(menu, button);\n \n // Focus active item or first item\n setTimeout(() => {\n const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (focusTarget) {\n focusTarget.focus({ preventScroll: true });\n }\n }, 0);\n }\n } else {\n // No quality support\n const noSupportItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noQuality'),\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noSupportItem);\n }\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n }\n\n createCaptionStyleButton() {\n const ariaLabel = i18n.t('player.captionStyling');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-caption-style`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n });\n\n // Create \"Aa\" text icon for styling\n const textIcon = DOMUtils.createElement('span', {\n textContent: 'Aa',\n style: {\n fontSize: '14px',\n fontWeight: 'bold'\n }\n });\n button.appendChild(textIcon);\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n button.addEventListener('click', () => {\n this.showCaptionStyleMenu(button);\n });\n\n this.controls.captionStyle = button;\n return button;\n }\n\n showCaptionStyleMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-caption-style-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-caption-style-menu ${this.player.options.classPrefix}-menu ${this.player.options.classPrefix}-settings-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('player.captionStyling')\n }\n });\n\n // Prevent menu from closing when clicking inside\n menu.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n // Check if there are any caption tracks\n if (!this.player.captionManager || this.player.captionManager.tracks.length === 0) {\n // Show \"No captions available\" message\n const noTracksItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noCaptions'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default', padding: '12px 16px'}\n });\n menu.appendChild(noTracksItem);\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button, true);\n return;\n }\n\n // Font Size\n const fontSizeGroup = this.createStyleControl(\n i18n.t('styleLabels.fontSize'),\n 'captionsFontSize',\n [\n {label: i18n.t('fontSizes.small'), value: '87.5%'},\n {label: i18n.t('fontSizes.normal'), value: '100%'},\n {label: i18n.t('fontSizes.large'), value: '125%'},\n {label: i18n.t('fontSizes.xlarge'), value: '150%'}\n ]\n );\n menu.appendChild(fontSizeGroup);\n\n // Font Family\n const fontFamilyGroup = this.createStyleControl(\n i18n.t('styleLabels.font'),\n 'captionsFontFamily',\n [\n {label: i18n.t('fontFamilies.sansSerif'), value: 'sans-serif'},\n {label: i18n.t('fontFamilies.serif'), value: 'serif'},\n {label: i18n.t('fontFamilies.monospace'), value: 'monospace'}\n ]\n );\n menu.appendChild(fontFamilyGroup);\n\n // Text Color\n const colorGroup = this.createColorControl(i18n.t('styleLabels.textColor'), 'captionsColor');\n menu.appendChild(colorGroup);\n\n // Background Color\n const bgColorGroup = this.createColorControl(i18n.t('styleLabels.background'), 'captionsBackgroundColor');\n menu.appendChild(bgColorGroup);\n\n // Opacity\n const opacityGroup = this.createOpacityControl(i18n.t('styleLabels.opacity'), 'captionsOpacity');\n menu.appendChild(opacityGroup);\n\n // Set min-width for caption style menu\n menu.style.minWidth = '220px';\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click (but not when interacting with controls)\n this.attachMenuCloseHandler(menu, button, true);\n\n // Auto-focus the first style select element\n focusFirstElement(menu, `.${this.player.options.classPrefix}-style-select`);\n }\n\n createStyleControl(label, property, options) {\n const group = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-style-group`\n });\n\n // Generate unique ID for the control\n const controlId = `${this.player.options.classPrefix}-${property}-${Date.now()}`;\n\n const labelEl = DOMUtils.createElement('label', {\n textContent: label,\n attributes: {\n 'for': controlId\n },\n style: {\n display: 'block',\n fontSize: '12px',\n marginBottom: '4px',\n color: 'rgba(255,255,255,0.7)'\n }\n });\n group.appendChild(labelEl);\n\n const select = DOMUtils.createElement('select', {\n className: `${this.player.options.classPrefix}-style-select`,\n attributes: {\n 'id': controlId\n },\n style: {\n width: '100%',\n padding: '6px',\n background: 'var(--vidply-white)',\n border: '1px solid var(--vidply-white-10)',\n borderRadius: '4px',\n color: 'var(--vidply-black)',\n fontSize: '13px'\n }\n });\n\n const currentValue = this.player.options[property];\n options.forEach(opt => {\n const option = DOMUtils.createElement('option', {\n textContent: opt.label,\n attributes: {value: opt.value}\n });\n if (opt.value === currentValue) {\n option.selected = true;\n }\n select.appendChild(option);\n });\n\n // Prevent clicks from closing the menu\n select.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n });\n\n select.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n select.addEventListener('change', (e) => {\n e.stopPropagation();\n this.player.options[property] = e.target.value;\n if (this.player.captionManager) {\n this.player.captionManager.setCaptionStyle(\n property.replace('captions', '').charAt(0).toLowerCase() + property.replace('captions', '').slice(1),\n e.target.value\n );\n }\n });\n\n group.appendChild(select);\n return group;\n }\n\n createColorControl(label, property) {\n const group = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-style-group`\n });\n\n // Generate unique ID for the control\n const controlId = `${this.player.options.classPrefix}-${property}-${Date.now()}`;\n\n const labelEl = DOMUtils.createElement('label', {\n textContent: label,\n attributes: {\n 'for': controlId\n },\n style: {\n display: 'block',\n fontSize: '12px',\n marginBottom: '4px',\n color: 'rgba(255,255,255,0.7)'\n }\n });\n group.appendChild(labelEl);\n\n const input = DOMUtils.createElement('input', {\n attributes: {\n 'id': controlId,\n type: 'color',\n value: this.player.options[property]\n },\n style: {\n width: '100%',\n height: '32px',\n padding: '2px',\n background: 'rgba(255,255,255,0.1)',\n border: '1px solid rgba(255,255,255,0.2)',\n borderRadius: '4px',\n cursor: 'pointer'\n }\n });\n\n // Prevent clicks from closing the menu\n input.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n });\n\n input.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n input.addEventListener('change', (e) => {\n e.stopPropagation();\n this.player.options[property] = e.target.value;\n if (this.player.captionManager) {\n this.player.captionManager.setCaptionStyle(\n property.replace('captions', '').charAt(0).toLowerCase() + property.replace('captions', '').slice(1),\n e.target.value\n );\n }\n });\n\n group.appendChild(input);\n return group;\n }\n\n createOpacityControl(label, property) {\n const group = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-style-group`\n });\n\n // Generate unique ID for the control\n const controlId = `${this.player.options.classPrefix}-${property}-${Date.now()}`;\n\n const labelContainer = DOMUtils.createElement('div', {\n style: {\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: '4px'\n }\n });\n\n const labelEl = DOMUtils.createElement('label', {\n textContent: label,\n attributes: {\n 'for': controlId\n },\n style: {\n fontSize: '12px',\n color: 'rgba(255,255,255,0.7)'\n }\n });\n\n const valueEl = DOMUtils.createElement('span', {\n textContent: Math.round(this.player.options[property] * 100) + '%',\n style: {\n fontSize: '12px',\n color: 'rgba(255,255,255,0.7)'\n }\n });\n\n labelContainer.appendChild(labelEl);\n labelContainer.appendChild(valueEl);\n group.appendChild(labelContainer);\n\n const input = DOMUtils.createElement('input', {\n attributes: {\n 'id': controlId,\n type: 'range',\n min: '0',\n max: '1',\n step: '0.1',\n value: String(this.player.options[property])\n },\n style: {\n width: '100%',\n cursor: 'pointer'\n }\n });\n\n // Prevent clicks from closing the menu\n input.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n });\n\n input.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n input.addEventListener('input', (e) => {\n e.stopPropagation();\n const value = parseFloat(e.target.value);\n valueEl.textContent = Math.round(value * 100) + '%';\n this.player.options[property] = value;\n if (this.player.captionManager) {\n this.player.captionManager.setCaptionStyle(\n property.replace('captions', '').charAt(0).toLowerCase() + property.replace('captions', '').slice(1),\n value\n );\n }\n });\n\n group.appendChild(input);\n return group;\n }\n\n createSpeedButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-speed`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.speed'),\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('speed'));\n\n const speedText = DOMUtils.createElement('span', {\n className: `${this.player.options.classPrefix}-speed-text`,\n textContent: '1x'\n });\n button.appendChild(speedText);\n\n button.addEventListener('click', () => {\n this.showSpeedMenu(button);\n });\n\n this.controls.speed = button;\n this.controls.speedText = speedText;\n return button;\n }\n\n formatSpeedLabel(speed) {\n // Special case: 1x is \"Normal\" (translated)\n if (speed === 1) {\n return i18n.t('speeds.normal');\n }\n \n // For other speeds, format with locale-specific decimal separator\n const speedStr = speed.toLocaleString(i18n.getLanguage(), {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2\n });\n \n return `${speedStr}×`;\n }\n\n showSpeedMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-speed-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-speed-menu ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu'\n }\n });\n\n const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n let activeItem = null;\n\n speeds.forEach(speed => {\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: this.formatSpeedLabel(speed),\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n if (speed === this.player.state.playbackSpeed) {\n item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n item.appendChild(createIconElement('check'));\n activeItem = item;\n }\n\n item.addEventListener('click', () => {\n this.player.setPlaybackSpeed(speed);\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n });\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Add keyboard navigation\n this.attachMenuKeyboardNavigation(menu, button);\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n\n // Focus the active item or first item\n setTimeout(() => {\n const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (focusTarget) {\n focusTarget.focus({ preventScroll: true });\n }\n }, 0);\n }\n\n createCaptionsButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-captions-button`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.captions'),\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('captionsOff'));\n\n button.addEventListener('click', () => {\n this.showCaptionsMenu(button);\n });\n\n this.controls.captions = button;\n return button;\n }\n\n showCaptionsMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-captions-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n // Clear tracking if this was the open menu\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-captions-menu ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('captions.select')\n }\n });\n\n // Check if there are any caption tracks\n if (!this.player.captionManager || this.player.captionManager.tracks.length === 0) {\n // Show \"No captions available\" message\n const noTracksItem = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noCaptions'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noTracksItem);\n\n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n return;\n }\n\n let activeItem = null;\n\n // Off option\n const offItem = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('captions.off'),\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n if (!this.player.state.captionsEnabled) {\n offItem.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n offItem.appendChild(createIconElement('check'));\n activeItem = offItem;\n }\n\n offItem.addEventListener('click', () => {\n this.player.disableCaptions();\n this.updateCaptionsButton();\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(offItem);\n\n // Available tracks\n const tracks = this.player.captionManager.getAvailableTracks();\n tracks.forEach(track => {\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: track.label,\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'lang': track.language,\n 'tabindex': '-1'\n }\n });\n\n // Check if this is the current track\n if (this.player.state.captionsEnabled &&\n this.player.captionManager.currentTrack === this.player.captionManager.tracks[track.index]) {\n item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);\n item.appendChild(createIconElement('check'));\n activeItem = item;\n }\n\n item.addEventListener('click', () => {\n this.player.captionManager.switchTrack(track.index);\n this.updateCaptionsButton();\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n });\n\n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n\n // Add keyboard navigation for the menu\n this.attachMenuKeyboardNavigation(menu, button);\n\n // Close menu on outside click and Escape key\n this.attachMenuCloseHandler(menu, button);\n\n // Focus the active item or the first item\n setTimeout(() => {\n const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (focusTarget) {\n focusTarget.focus({ preventScroll: true });\n }\n }, 0);\n }\n\n updateCaptionsButton() {\n if (!this.controls.captions) return;\n\n const icon = this.controls.captions.querySelector('.vidply-icon');\n const isEnabled = this.player.state.captionsEnabled;\n\n icon.innerHTML = isEnabled ?\n createIconElement('captions').innerHTML :\n createIconElement('captionsOff').innerHTML;\n\n }\n\n createTranscriptButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-transcript`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.transcript'),\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('transcript'));\n\n button.addEventListener('click', async () => {\n await this.player.toggleTranscript();\n this.updateTranscriptButton();\n });\n\n this.controls.transcript = button;\n return button;\n }\n\n updateTranscriptButton() {\n if (!this.controls.transcript) return;\n\n const isVisible = this.player.transcriptManager && this.player.transcriptManager.isVisible;\n this.controls.transcript.setAttribute('aria-expanded', isVisible ? 'true' : 'false');\n }\n\n createAudioDescriptionButton() {\n const ariaLabel = i18n.t('player.audioDescription');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-audio-description`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'role': 'switch',\n 'aria-checked': 'false'\n }\n });\n\n button.appendChild(createIconElement('audioDescription'));\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n button.addEventListener('click', async () => {\n await this.player.toggleAudioDescription();\n this.updateAudioDescriptionButton();\n });\n\n this.controls.audioDescription = button;\n return button;\n }\n\n updateAudioDescriptionButton() {\n if (!this.controls.audioDescription) return;\n\n const icon = this.controls.audioDescription.querySelector('.vidply-icon');\n const isEnabled = this.player.state.audioDescriptionEnabled;\n\n icon.innerHTML = isEnabled ?\n createIconElement('audioDescriptionOn').innerHTML :\n createIconElement('audioDescription').innerHTML;\n\n this.controls.audioDescription.setAttribute('aria-checked', isEnabled ? 'true' : 'false');\n // Keep aria-label static - let aria-checked convey the state for switch role\n // The label describes what the control is, not what action it performs\n }\n\n createSignLanguageButton() {\n const ariaLabel = i18n.t('player.signLanguage');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-sign-language`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('signLanguage'));\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n button.addEventListener('click', () => {\n this.player.toggleSignLanguage();\n this.updateSignLanguageButton();\n });\n\n this.controls.signLanguage = button;\n return button;\n }\n\n updateSignLanguageButton() {\n if (!this.controls.signLanguage) return;\n\n const icon = this.controls.signLanguage.querySelector('.vidply-icon');\n const isEnabled = this.player.state.signLanguageEnabled;\n\n icon.innerHTML = isEnabled ?\n createIconElement('signLanguageOn').innerHTML :\n createIconElement('signLanguage').innerHTML;\n\n this.controls.signLanguage.setAttribute('aria-expanded', isEnabled ? 'true' : 'false');\n this.controls.signLanguage.setAttribute('aria-label',\n isEnabled ? i18n.t('signLanguage.hide') : i18n.t('signLanguage.show')\n );\n }\n\n /**\n * Update accessibility buttons visibility based on current track data.\n * Called when loading a new playlist track to show/hide buttons accordingly.\n */\n updateAccessibilityButtons() {\n const hasAudioDescription = this.hasAudioDescription();\n const hasSignLanguage = this.hasSignLanguage();\n \n // Handle Audio Description button\n if (hasAudioDescription) {\n // Create button if it doesn't exist\n if (!this.controls.audioDescription && this.player.options.audioDescriptionButton !== false) {\n const btn = this.createAudioDescriptionButton();\n btn.dataset.overflowPriority = '2';\n btn.dataset.overflowPriorityMobile = '3';\n // Insert before transcript or playlist toggle button\n const transcriptBtn = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-transcript`);\n const playlistBtn = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-playlist-toggle`);\n const insertBefore = transcriptBtn || playlistBtn || null;\n if (insertBefore) {\n this.rightButtons.insertBefore(btn, insertBefore);\n } else {\n this.rightButtons.appendChild(btn);\n }\n // Re-setup overflow menu after adding button\n this.setupOverflowMenu();\n }\n // Show button\n if (this.controls.audioDescription) {\n this.controls.audioDescription.style.display = '';\n }\n } else {\n // Hide button if no audio description available\n if (this.controls.audioDescription) {\n this.controls.audioDescription.style.display = 'none';\n }\n }\n \n // Handle Sign Language button\n if (hasSignLanguage) {\n // Create button if it doesn't exist\n if (!this.controls.signLanguage && this.player.options.signLanguageButton !== false) {\n const btn = this.createSignLanguageButton();\n btn.dataset.overflowPriority = '3';\n btn.dataset.overflowPriorityMobile = '3';\n // Insert before quality or fullscreen button\n const qualityBtn = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-quality`);\n const fullscreenBtn = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-fullscreen`);\n const insertBefore = qualityBtn || fullscreenBtn || null;\n if (insertBefore) {\n this.rightButtons.insertBefore(btn, insertBefore);\n } else {\n this.rightButtons.appendChild(btn);\n }\n // Re-setup overflow menu after adding button\n this.setupOverflowMenu();\n }\n // Show button\n if (this.controls.signLanguage) {\n this.controls.signLanguage.style.display = '';\n }\n } else {\n // Hide button if no sign language available\n if (this.controls.signLanguage) {\n this.controls.signLanguage.style.display = 'none';\n }\n }\n }\n\n createSettingsButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-settings`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.settings')\n }\n });\n\n button.appendChild(createIconElement('settings'));\n\n button.addEventListener('click', () => {\n this.player.showSettings();\n });\n\n return button;\n }\n\n createPipButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-pip`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.pip')\n }\n });\n\n button.appendChild(createIconElement('pip'));\n\n button.addEventListener('click', () => {\n this.player.togglePiP();\n });\n\n return button;\n }\n\n createFullscreenButton() {\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-fullscreen`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.fullscreen')\n }\n });\n\n button.appendChild(createIconElement('fullscreen'));\n\n button.addEventListener('click', () => {\n this.player.toggleFullscreen();\n });\n\n this.controls.fullscreen = button;\n return button;\n }\n\n attachEvents() {\n // Update controls based on player state\n this.player.on('play', () => this.updatePlayPauseButton());\n this.player.on('pause', () => this.updatePlayPauseButton());\n this.player.on('timeupdate', () => this.updateProgress());\n this.player.on('loadedmetadata', () => {\n this.updateDuration();\n this.ensureQualityButton();\n this.updateQualityIndicator();\n });\n this.player.on('volumechange', () => this.updateVolumeDisplay());\n this.player.on('progress', () => this.updateBuffered());\n this.player.on('playbackspeedchange', () => this.updateSpeedDisplay());\n this.player.on('fullscreenchange', () => this.updateFullscreenButton());\n this.player.on('captionsenabled', () => this.updateCaptionsButton());\n this.player.on('captionsdisabled', () => this.updateCaptionsButton());\n this.player.on('audiodescriptionenabled', () => this.updateAudioDescriptionButton());\n this.player.on('audiodescriptiondisabled', () => this.updateAudioDescriptionButton());\n this.player.on('signlanguageenabled', () => this.updateSignLanguageButton());\n this.player.on('signlanguagedisabled', () => this.updateSignLanguageButton());\n this.player.on('qualitychange', () => this.updateQualityIndicator());\n this.player.on('hlslevelswitched', () => this.updateQualityIndicator());\n this.player.on('hlsmanifestparsed', () => {\n this.ensureQualityButton();\n this.updateQualityIndicator();\n });\n }\n\n updatePlayPauseButton() {\n if (!this.controls.playPause) return;\n\n const icon = this.controls.playPause.querySelector('.vidply-icon');\n const isPlaying = this.player.state.playing;\n\n icon.innerHTML = isPlaying ?\n createIconElement('pause').innerHTML :\n createIconElement('play').innerHTML;\n\n const newAriaLabel = isPlaying ? i18n.t('player.pause') : i18n.t('player.play');\n this.controls.playPause.setAttribute('aria-label', newAriaLabel);\n // Update tooltip to match aria-label\n DOMUtils.attachTooltip(this.controls.playPause, newAriaLabel, this.player.options.classPrefix);\n }\n\n updateProgress() {\n if (!this.controls.played) return;\n\n const currentTime = this.player.state.currentTime || 0;\n const duration = this.player.state.duration || 0;\n \n // Guard against division by zero and ensure valid percentage\n const percent = duration > 0 ? Math.min(100, Math.max(0, (currentTime / duration) * 100)) : 0;\n \n this.controls.played.style.width = `${percent}%`;\n this.controls.progress.setAttribute('aria-valuenow', String(Math.round(percent)));\n \n // Set aria-valuetext to announce both percentage and time for screen readers\n const currentTimeText = TimeUtils.formatDuration(this.player.state.currentTime);\n const durationText = TimeUtils.formatDuration(this.player.state.duration);\n this.controls.progress.setAttribute('aria-valuetext', \n `${Math.round(percent)}%, ${currentTimeText} ${i18n.t('time.of')} ${durationText}`);\n\n if (this.controls.currentTimeVisual) {\n const currentTime = this.player.state.currentTime;\n // Update visual text (hidden from screen readers)\n this.controls.currentTimeVisual.textContent = TimeUtils.formatTime(currentTime);\n if (this.controls.currentTimeAccessible) {\n this.controls.currentTimeAccessible.textContent = TimeUtils.formatDuration(currentTime);\n }\n }\n }\n\n updateDuration() {\n if (this.controls.durationVisual) {\n const duration = this.player.state.duration;\n // Update visual text (hidden from screen readers)\n this.controls.durationVisual.textContent = TimeUtils.formatTime(duration);\n if (this.controls.durationAccessible) {\n this.controls.durationAccessible.textContent = i18n.t('time.durationPrefix') + TimeUtils.formatDuration(duration);\n }\n }\n }\n\n updateVolumeDisplay() {\n const percent = this.player.state.volume * 100;\n\n // Update volume fill bar if it exists\n if (this.controls.volumeFill) {\n this.controls.volumeFill.style.height = `${percent}%`;\n }\n \n // Update volume slider aria-valuenow if it exists\n if (this.controls.volumeSlider) {\n this.controls.volumeSlider.setAttribute('aria-valuenow', String(Math.round(percent)));\n }\n\n // Update mute button icon (should always work even if slider not shown)\n if (this.controls.mute) {\n const icon = this.controls.mute.querySelector('.vidply-icon');\n if (icon) {\n let iconName;\n\n if (this.player.state.muted || this.player.state.volume === 0) {\n iconName = 'volumeMuted';\n } else if (this.player.state.volume < 0.3) {\n iconName = 'volumeLow';\n } else if (this.player.state.volume < 0.7) {\n iconName = 'volumeMedium';\n } else {\n iconName = 'volumeHigh';\n }\n\n icon.innerHTML = createIconElement(iconName).innerHTML;\n\n const newMuteAriaLabel =\n this.player.state.muted ? i18n.t('player.unmute') : i18n.t('player.mute');\n this.controls.mute.setAttribute('aria-label', newMuteAriaLabel);\n // Update tooltip to match aria-label\n DOMUtils.attachTooltip(this.controls.mute, newMuteAriaLabel, this.player.options.classPrefix);\n }\n }\n\n // Update volume slider attribute if it exists\n if (this.controls.volumeSlider) {\n this.controls.volumeSlider.setAttribute('aria-valuenow', String(Math.round(percent)));\n }\n }\n\n updateBuffered() {\n if (!this.controls.buffered || !this.player.element.buffered || this.player.element.buffered.length === 0) return;\n\n const buffered = this.player.element.buffered.end(this.player.element.buffered.length - 1);\n const percent = (buffered / this.player.state.duration) * 100;\n this.controls.buffered.style.width = `${percent}%`;\n }\n\n updateSpeedDisplay() {\n if (this.controls.speedText) {\n this.controls.speedText.textContent = `${this.player.state.playbackSpeed}x`;\n }\n }\n\n updateFullscreenButton() {\n if (!this.controls.fullscreen) return;\n\n const icon = this.controls.fullscreen.querySelector('.vidply-icon');\n const isFullscreen = this.player.state.fullscreen;\n\n icon.innerHTML = isFullscreen ?\n createIconElement('fullscreenExit').innerHTML :\n createIconElement('fullscreen').innerHTML;\n\n this.controls.fullscreen.setAttribute('aria-label',\n isFullscreen ? i18n.t('player.exitFullscreen') : i18n.t('player.fullscreen')\n );\n }\n\n /**\n * Ensure quality button exists if qualities are available\n * This is called after renderer initialization to dynamically add the button\n */\n ensureQualityButton() {\n // Skip if quality button is disabled\n if (!this.player.options.qualityButton) return;\n \n // Skip if button already exists\n if (this.controls.quality) return;\n \n // Check if qualities are now available\n if (!this.hasQualityLevels()) return;\n \n // Create and insert the quality button before the speed button\n const qualityButton = this.createQualityButton();\n \n // Find the speed button or caption style button to insert before\n const speedButton = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-speed`);\n const captionStyleButton = this.rightButtons.querySelector(`.${this.player.options.classPrefix}-caption-style`);\n const insertBefore = captionStyleButton || speedButton;\n \n if (insertBefore) {\n this.rightButtons.insertBefore(qualityButton, insertBefore);\n } else {\n // If no reference button, add it at the beginning of right buttons\n this.rightButtons.insertBefore(qualityButton, this.rightButtons.firstChild);\n }\n \n this.player.log('Quality button added dynamically', 'info');\n }\n\n updateQualityIndicator() {\n if (!this.controls.qualityText) return;\n if (!this.player.renderer || !this.player.renderer.getQualities) return;\n\n const qualities = this.player.renderer.getQualities();\n if (qualities.length === 0) {\n this.controls.qualityText.textContent = '';\n return;\n }\n\n // Get current quality\n let currentQualityText = '';\n \n // Check if it's HLS with auto mode\n if (this.player.renderer.hls && this.player.renderer.hls.currentLevel === -1) {\n currentQualityText = 'Auto';\n } else if (this.player.renderer.getCurrentQuality) {\n const currentIndex = this.player.renderer.getCurrentQuality();\n const currentQuality = qualities.find(q => q.index === currentIndex);\n if (currentQuality) {\n currentQualityText = currentQuality.height ? `${currentQuality.height}p` : '';\n }\n }\n\n this.controls.qualityText.textContent = currentQualityText;\n }\n\n setupAutoHide() {\n if (this.player.element.tagName !== 'VIDEO') return;\n\n const showControls = () => {\n this.element.classList.add(`${this.player.options.classPrefix}-controls-visible`);\n this.player.container.classList.add(`${this.player.options.classPrefix}-controls-visible`);\n this.player.state.controlsVisible = true;\n\n clearTimeout(this.hideTimeout);\n\n if (this.player.state.playing) {\n // Use longer delay in fullscreen mode for better mobile UX\n const delay = this.player.state.fullscreen \n ? this.player.options.hideControlsDelay * 1.5 \n : this.player.options.hideControlsDelay;\n \n this.hideTimeout = setTimeout(() => {\n this.element.classList.remove(`${this.player.options.classPrefix}-controls-visible`);\n this.player.container.classList.remove(`${this.player.options.classPrefix}-controls-visible`);\n this.player.state.controlsVisible = false;\n }, delay);\n }\n };\n\n // Mouse and touch events to show controls\n this.player.container.addEventListener('mousemove', showControls);\n this.player.container.addEventListener('touchstart', showControls);\n this.player.container.addEventListener('touchmove', showControls); // Also show on touch drag/swipe\n this.player.container.addEventListener('click', showControls);\n this.player.container.addEventListener('tap', showControls); // Some mobile browsers use tap event\n\n // Show controls on focus\n this.element.addEventListener('focusin', showControls);\n\n // Always show when paused\n this.player.on('pause', () => {\n showControls();\n clearTimeout(this.hideTimeout);\n });\n\n this.player.on('play', () => {\n showControls();\n });\n\n // Show controls when entering fullscreen (especially important for mobile landscape)\n this.player.on('enterfullscreen', () => {\n showControls();\n // In fullscreen, keep controls visible longer initially\n if (this.player.state.fullscreen) {\n clearTimeout(this.hideTimeout);\n this.hideTimeout = setTimeout(() => {\n if (this.player.state.playing) {\n this.element.classList.remove(`${this.player.options.classPrefix}-controls-visible`);\n this.player.container.classList.remove(`${this.player.options.classPrefix}-controls-visible`);\n this.player.state.controlsVisible = false;\n }\n }, this.player.options.hideControlsDelay * 2); // Double the delay in fullscreen\n }\n });\n\n // Initial state\n showControls();\n }\n\n createOverflowMenuButton() {\n const ariaLabel = i18n.t('player.moreOptions');\n const button = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-overflow-menu`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n });\n\n button.appendChild(createIconElement('moreVertical'));\n DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);\n\n button.addEventListener('click', () => {\n this.showOverflowMenu(button);\n });\n\n this.controls.overflowMenu = button;\n return button;\n }\n\n showOverflowMenu(button) {\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${this.player.options.classPrefix}-overflow-menu-list`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n if (this.openMenu === existingMenu) {\n this.openMenu = null;\n this.openMenuButton = null;\n }\n return;\n }\n\n const menu = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-overflow-menu-list ${this.player.options.classPrefix}-menu`,\n attributes: {\n 'role': 'menu',\n 'aria-label': i18n.t('player.moreOptions')\n }\n });\n\n // Get all overflow buttons (those currently hidden)\n const overflowButtons = Array.from(this.rightButtons.querySelectorAll('button[data-in-overflow=\"true\"]'));\n\n if (overflowButtons.length === 0) {\n // No overflow items\n const noItemsText = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noMoreOptions'),\n attributes: {\n 'role': 'menuitem'\n },\n style: {opacity: '0.5', cursor: 'default'}\n });\n menu.appendChild(noItemsText);\n } else {\n // Create menu items for each overflow button\n overflowButtons.forEach(btn => {\n const item = DOMUtils.createElement('button', {\n className: `${this.player.options.classPrefix}-menu-item`,\n attributes: {\n 'type': 'button',\n 'role': 'menuitem',\n 'tabindex': '-1'\n }\n });\n\n // Get button label\n const label = btn.getAttribute('aria-label') || btn.getAttribute('title') || '';\n \n // Copy icon if present (SVG icon or text icon like \"Aa\")\n const icon = btn.querySelector('.vidply-icon');\n if (icon) {\n const iconClone = icon.cloneNode(true);\n item.appendChild(iconClone);\n } else {\n // Check for text icon (like caption styling \"Aa\")\n const firstChild = btn.querySelector('span');\n if (firstChild && firstChild.textContent && firstChild.textContent.length <= 3) {\n const iconClone = firstChild.cloneNode(true);\n iconClone.classList.add('vidply-icon'); // Add icon class for consistent styling\n item.appendChild(iconClone);\n }\n }\n \n const labelSpan = DOMUtils.createElement('span', {\n textContent: label\n });\n item.appendChild(labelSpan);\n\n // When clicked, trigger the original button's click\n item.addEventListener('click', (e) => {\n // Store the overflow menu item as the positioning reference\n // This allows submenus to position relative to the visible menu item\n this._overflowMenuItemRef = item;\n \n // Temporarily make the original button visible for positioning\n const originalDisplay = btn.style.display;\n btn.style.display = '';\n btn.style.visibility = 'hidden'; // Keep it invisible but in layout\n \n // Trigger the button's menu\n btn.click();\n \n // Restore original state after menu is positioned\n setTimeout(() => {\n btn.style.display = originalDisplay;\n btn.style.visibility = '';\n this._overflowMenuItemRef = null;\n }, 100);\n \n // Close overflow menu\n this.closeMenuAndReturnFocus(menu, button);\n });\n\n menu.appendChild(item);\n });\n\n // Add keyboard navigation\n this.attachMenuKeyboardNavigation(menu, button);\n\n // Focus first item\n setTimeout(() => {\n const firstItem = menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);\n if (firstItem && firstItem.tagName === 'BUTTON') {\n firstItem.focus({ preventScroll: true });\n }\n }, 0);\n }\n\n // Position menu first (before it's visible) to prevent jumping\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n \n // Insert menu into DOM (handles fullscreen positioning)\n this.insertMenuIntoDOM(menu, button);\n \n // Position immediately (synchronously) while hidden\n this.positionMenu(menu, button, true);\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n // Close menu on outside click\n this.attachMenuCloseHandler(menu, button);\n }\n\n setupOverflowDetection() {\n // Check for overflow after layout is stable\n const checkOverflow = () => {\n // Check screen size and orientation\n const isDesktop = window.innerWidth >= 768;\n const isLandscape = window.innerHeight < window.innerWidth;\n const isFullscreen = this.player.state.fullscreen;\n const isLandscapeFullscreen = isLandscape && isFullscreen;\n \n if (!this.rightButtons || this.rightButtons.children.length === 0) {\n // Hide overflow button if no buttons exist\n if (this.overflowMenuButton) {\n this.overflowMenuButton.style.display = 'none';\n }\n return;\n }\n\n // Get all buttons (except the overflow menu button itself)\n const allButtons = Array.from(this.rightButtons.children).filter(\n btn => !btn.classList.contains(`${this.player.options.classPrefix}-overflow-menu`)\n );\n\n if (allButtons.length === 0) {\n // Hide overflow button if no buttons exist\n if (this.overflowMenuButton) {\n this.overflowMenuButton.style.display = 'none';\n }\n return;\n }\n\n // Determine if we should use overflow menu\n // Only use overflow on mobile portrait (width < 768px and not in landscape)\n // In landscape mode, always show all buttons (even on mobile) to ensure fullscreen button is accessible\n const shouldUseOverflow = !isDesktop && !isLandscape;\n \n if (this.player.options.debug) {\n console.log('Overflow detection:', {\n isDesktop,\n isFullscreen,\n isLandscape,\n isLandscapeFullscreen,\n shouldUseOverflow,\n width: window.innerWidth,\n height: window.innerHeight\n });\n }\n\n // If we shouldn't use overflow menu, show all buttons and hide overflow button\n if (!shouldUseOverflow) {\n allButtons.forEach(btn => {\n btn.dataset.inOverflow = 'false';\n btn.style.display = '';\n });\n // Always hide overflow menu button\n if (this.overflowMenuButton) {\n this.overflowMenuButton.style.display = 'none';\n }\n if (this.player.options.debug) {\n console.log('No overflow menu needed - all buttons visible, overflow button hidden');\n }\n return;\n }\n \n // Continue with overflow detection for mobile portrait only\n if (this.player.options.debug) {\n console.log('Mobile portrait - checking for overflow...');\n }\n\n // First, make all buttons visible to measure their actual widths\n allButtons.forEach(btn => {\n btn.style.display = '';\n });\n\n // Get available width\n const containerWidth = this.rightButtons.offsetWidth;\n const overflowButtonWidth = 50; // Reserve space for overflow button + gap\n const availableWidth = containerWidth - overflowButtonWidth;\n\n // Calculate total width needed for all buttons including gaps\n let totalWidth = 0;\n const buttonWidths = allButtons.map(btn => {\n const style = getComputedStyle(btn);\n const width = btn.offsetWidth + \n parseInt(style.marginLeft || 0) + \n parseInt(style.marginRight || 0);\n totalWidth += width;\n return {btn, width};\n });\n\n // Add gap widths (8px per gap between buttons)\n const gapWidth = 8;\n totalWidth += (allButtons.length - 1) * gapWidth;\n\n // Check if overflow is needed\n const isSmallScreen = window.innerWidth < 768;\n const needsOverflow = totalWidth > availableWidth || isSmallScreen || (isLandscapeFullscreen && !isDesktop); // Always overflow on mobile and mobile landscape fullscreen\n\n // Debug logging\n if (this.player.options.debug) {\n console.log('Overflow detection:', {\n containerWidth,\n availableWidth,\n totalWidth,\n needsOverflow,\n isSmallScreen,\n reason: isSmallScreen ? 'mobile screen' : (totalWidth > availableWidth ? 'not enough space' : 'enough space'),\n buttonCount: allButtons.length\n });\n }\n\n if (needsOverflow) {\n // Use responsive priorities based on screen size\n const isSmallScreen = window.innerWidth < 768;\n const priorityAttr = isSmallScreen ? 'overflowPriorityMobile' : 'overflowPriority';\n \n if (this.player.options.debug) {\n console.log(`Using ${isSmallScreen ? 'mobile' : 'desktop'} priorities (width: ${window.innerWidth}px)`);\n }\n \n // Sort buttons by priority (highest priority last)\n const sortedButtons = buttonWidths.sort((a, b) => {\n const priorityA = parseInt(a.btn.dataset[priorityAttr] || a.btn.dataset.overflowPriority || '1');\n const priorityB = parseInt(b.btn.dataset[priorityAttr] || b.btn.dataset.overflowPriority || '1');\n return priorityB - priorityA; // Higher priority = lower number = later in array\n });\n\n // Hide buttons starting with lowest priority until fits\n let currentWidth = totalWidth;\n let movedToOverflow = 0;\n\n for (const {btn, width} of sortedButtons) {\n const priority = parseInt(btn.dataset[priorityAttr] || btn.dataset.overflowPriority || '1');\n const buttonLabel = btn.getAttribute('aria-label') || 'unknown';\n \n // Never hide priority 1 buttons\n if (priority === 1) {\n btn.dataset.inOverflow = 'false';\n btn.style.display = '';\n continue;\n }\n\n // On mobile, hide all non-priority-1 buttons (priority 2 and 3)\n // On desktop, only hide if not enough space\n const shouldHide = isSmallScreen ? (priority > 1) : (currentWidth > availableWidth);\n\n if (shouldHide) {\n // Move to overflow\n btn.dataset.inOverflow = 'true';\n btn.style.display = 'none';\n currentWidth -= width;\n movedToOverflow++;\n if (this.player.options.debug) {\n console.log(` → Hiding button: ${buttonLabel} (priority ${priority}, ${isSmallScreen ? 'mobile' : 'desktop'})`);\n }\n } else {\n // Keep visible\n btn.dataset.inOverflow = 'false';\n btn.style.display = '';\n }\n }\n\n // Show overflow menu button if we moved any buttons\n if (this.player.options.debug) {\n console.log('Overflow button exists?', !!this.overflowMenuButton);\n }\n \n if (!this.overflowMenuButton) {\n console.error('Overflow menu button not found!');\n return;\n }\n \n if (movedToOverflow > 0) {\n this.overflowMenuButton.style.display = '';\n if (this.player.options.debug) {\n console.log('Showing overflow menu button -', movedToOverflow, 'buttons moved');\n }\n } else {\n this.overflowMenuButton.style.display = 'none';\n if (this.player.options.debug) {\n console.log('Hiding overflow menu button - all buttons fit');\n }\n }\n } else {\n // No overflow needed - show all buttons\n allButtons.forEach(btn => {\n btn.dataset.inOverflow = 'false';\n btn.style.display = '';\n });\n this.overflowMenuButton.style.display = 'none';\n }\n };\n\n // Check on resize\n const resizeObserver = new ResizeObserver(() => {\n requestAnimationFrame(checkOverflow);\n });\n resizeObserver.observe(this.rightButtons);\n\n // Check on window resize\n window.addEventListener('resize', () => {\n requestAnimationFrame(checkOverflow);\n });\n\n // Check on fullscreen changes (important for desktop/tablet fullscreen)\n this.player.on('fullscreenchange', () => {\n // Use setTimeout to ensure fullscreen state is fully updated\n setTimeout(() => {\n requestAnimationFrame(checkOverflow);\n }, 50);\n });\n\n // Initial checks at multiple intervals to ensure layout is stable\n // Some browsers need more time for font loading, CSS rendering, etc.\n requestAnimationFrame(() => {\n checkOverflow();\n setTimeout(() => checkOverflow(), 100);\n setTimeout(() => checkOverflow(), 300);\n setTimeout(() => checkOverflow(), 500);\n });\n\n // Also check when fonts are loaded\n if (document.fonts && document.fonts.ready) {\n document.fonts.ready.then(() => {\n requestAnimationFrame(checkOverflow);\n });\n }\n\n // Store for cleanup\n this.overflowResizeObserver = resizeObserver;\n }\n\n show() {\n this.element.style.display = '';\n }\n\n hide() {\n this.element.style.display = 'none';\n }\n\n destroy() {\n if (this.hideTimeout) {\n clearTimeout(this.hideTimeout);\n }\n\n if (this.overflowResizeObserver) {\n this.overflowResizeObserver.disconnect();\n }\n\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n }\n}\n\n", "/**\r\n * Performance Utilities\r\n */\r\n\r\n/**\r\n * Debounce function - limits how often a function can be called\r\n * @param {Function} func - Function to debounce\r\n * @param {number} wait - Wait time in milliseconds\r\n * @returns {Function} Debounced function\r\n */\r\nexport function debounce(func, wait = 100) {\r\n let timeout;\r\n return function executedFunction(...args) {\r\n const later = () => {\r\n clearTimeout(timeout);\r\n func(...args);\r\n };\r\n clearTimeout(timeout);\r\n timeout = setTimeout(later, wait);\r\n };\r\n}\r\n\r\n/**\r\n * Throttle function - ensures function is called at most once per interval\r\n * @param {Function} func - Function to throttle\r\n * @param {number} limit - Time limit in milliseconds\r\n * @returns {Function} Throttled function\r\n */\r\nexport function throttle(func, limit = 100) {\r\n let inThrottle;\r\n return function executedFunction(...args) {\r\n if (!inThrottle) {\r\n func(...args);\r\n inThrottle = true;\r\n setTimeout(() => inThrottle = false, limit);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Check if current viewport is mobile size\r\n * @param {number} breakpoint - Mobile breakpoint in pixels (default 768)\r\n * @returns {boolean} True if mobile\r\n */\r\nexport function isMobile(breakpoint = 768) {\r\n return window.innerWidth < breakpoint;\r\n}\r\n\r\n/**\r\n * Request animation frame with timeout fallback\r\n * @param {Function} callback - Function to call\r\n * @param {number} timeout - Timeout in ms (default 100)\r\n */\r\nexport function rafWithTimeout(callback, timeout = 100) {\r\n let called = false;\r\n \r\n const execute = () => {\r\n if (!called) {\r\n called = true;\r\n callback();\r\n }\r\n };\r\n \r\n requestAnimationFrame(execute);\r\n setTimeout(execute, timeout);\r\n}\r\n\r\n", "/**\n * Caption/Subtitle Manager\n */\n\nimport {DOMUtils} from '../utils/DOMUtils.js';\nimport {i18n} from '../i18n/i18n.js';\nimport {StorageManager} from '../utils/StorageManager.js';\nimport {debounce, isMobile, rafWithTimeout} from '../utils/PerformanceUtils.js';\n\nexport class CaptionManager {\n constructor(player) {\n this.player = player;\n this.element = null;\n this.tracks = [];\n this.currentTrack = null;\n this.currentCue = null;\n \n // Storage manager\n this.storage = new StorageManager('vidply');\n \n // Load saved preferences\n this.loadSavedPreferences();\n\n this.init();\n }\n \n loadSavedPreferences() {\n const saved = this.storage.getCaptionPreferences();\n if (saved) {\n // Override player options with saved preferences\n if (saved.fontSize) this.player.options.captionsFontSize = saved.fontSize;\n if (saved.fontFamily) this.player.options.captionsFontFamily = saved.fontFamily;\n if (saved.color) this.player.options.captionsColor = saved.color;\n if (saved.backgroundColor) this.player.options.captionsBackgroundColor = saved.backgroundColor;\n if (saved.opacity !== undefined) this.player.options.captionsOpacity = saved.opacity;\n }\n }\n \n saveCaptionPreferences() {\n this.storage.saveCaptionPreferences({\n fontSize: this.player.options.captionsFontSize,\n fontFamily: this.player.options.captionsFontFamily,\n color: this.player.options.captionsColor,\n backgroundColor: this.player.options.captionsBackgroundColor,\n opacity: this.player.options.captionsOpacity\n });\n }\n\n init() {\n this.createElement();\n this.loadTracks();\n this.attachEvents();\n\n // Only enable captions via captionsDefault option if no default track was found\n // (loadTracks() already enables tracks with the default attribute)\n if (this.player.options.captionsDefault && this.tracks.length > 0 && !this.currentTrack) {\n this.enable();\n }\n }\n\n createElement() {\n this.element = DOMUtils.createElement('div', {\n className: `${this.player.options.classPrefix}-captions`,\n attributes: {\n 'role': 'region',\n 'aria-label': i18n.t('player.captions')\n }\n });\n\n // Apply caption styles\n this.updateStyles();\n\n // Append to videoWrapper if it exists, otherwise to container\n const target = this.player.videoWrapper || this.player.container;\n target.appendChild(this.element);\n }\n\n loadTracks() {\n const textTracks = this.player.element.textTracks;\n let defaultTrackIndex = -1;\n\n for (let i = 0; i < textTracks.length; i++) {\n const track = textTracks[i];\n\n if (track.kind === 'subtitles' || track.kind === 'captions') {\n // Check if this track has the default attribute\n const trackElement = this.player.findTrackElement(track);\n const isDefault = trackElement && trackElement.hasAttribute('default');\n \n this.tracks.push({\n track: track,\n language: track.language,\n label: track.label,\n kind: track.kind,\n index: i,\n isDefault: isDefault\n });\n\n // Set all tracks to 'hidden' mode (not 'disabled' or 'showing')\n // 'hidden' mode loads cues and fires events, but doesn't show native captions\n // This is important even for default tracks - we want custom caption display\n if (track.mode === 'showing') {\n // If browser set it to 'showing' (e.g., for default tracks), change to 'hidden'\n track.mode = 'hidden';\n } else if (track.mode === 'disabled') {\n // If disabled, set to 'hidden' to load cues\n track.mode = 'hidden';\n } else {\n // Ensure it's 'hidden' (might already be, but be explicit)\n track.mode = 'hidden';\n }\n \n if (isDefault) {\n defaultTrackIndex = this.tracks.length - 1;\n }\n }\n }\n \n // If a default track was found, enable it\n // Use a small delay to ensure tracks are ready\n if (defaultTrackIndex >= 0) {\n requestAnimationFrame(() => {\n this.enable(defaultTrackIndex);\n });\n }\n }\n\n attachEvents() {\n this.player.on('timeupdate', () => {\n this.updateCaptions();\n });\n\n this.player.on('captionschange', () => {\n this.updateStyles();\n });\n \n // Debounced resize handler to avoid excessive recalculations\n this.debouncedPositionCaptions = debounce(() => {\n this.positionCaptionsOnMobile();\n }, 150);\n \n window.addEventListener('resize', this.debouncedPositionCaptions);\n \n // Recalculate on fullscreen change with RAF\n this.player.on('enterfullscreen', () => {\n rafWithTimeout(() => this.positionCaptionsOnMobile(), 100);\n });\n \n this.player.on('exitfullscreen', () => {\n rafWithTimeout(() => this.positionCaptionsOnMobile(), 100);\n });\n }\n\n enable(trackIndex = 0) {\n if (this.tracks.length === 0) {\n return;\n }\n\n // Disable current track\n if (this.currentTrack && this.currentTrack.track) {\n // Remove cuechange listener from old track\n if (this.cueChangeHandler) {\n this.currentTrack.track.removeEventListener('cuechange', this.cueChangeHandler);\n }\n this.currentTrack.track.mode = 'hidden';\n }\n\n // Enable selected track\n const selectedTrack = this.tracks[trackIndex];\n\n if (selectedTrack && selectedTrack.track) {\n // Set to 'hidden' not 'showing' to prevent browser from displaying native captions\n // We'll handle the display ourselves\n // But we need to set mode to 'hidden' to load cues\n selectedTrack.track.mode = 'hidden';\n this.currentTrack = selectedTrack;\n this.player.state.captionsEnabled = true;\n \n // Set lang attribute for screen readers to pronounce text correctly\n if (selectedTrack.language) {\n this.element.setAttribute('lang', selectedTrack.language);\n }\n\n // Remove any existing cuechange listener from this track\n if (this.cueChangeHandler) {\n selectedTrack.track.removeEventListener('cuechange', this.cueChangeHandler);\n }\n\n // Add event listener for cue changes\n this.cueChangeHandler = () => {\n this.updateCaptions();\n };\n selectedTrack.track.addEventListener('cuechange', this.cueChangeHandler);\n\n // Force track to load if it's not already loaded\n // If track is not ready, wait for it to load\n const ensureTrackReady = () => {\n if (selectedTrack.track.readyState < 2) {\n // Track not loaded yet, wait for load event\n const onTrackLoad = () => {\n selectedTrack.track.removeEventListener('load', onTrackLoad);\n selectedTrack.track.removeEventListener('error', onTrackLoad);\n // Force initial update after track loads\n requestAnimationFrame(() => {\n if (this.currentTrack && this.currentTrack.track === selectedTrack.track) {\n this.updateCaptions();\n }\n });\n };\n selectedTrack.track.addEventListener('load', onTrackLoad, { once: true });\n selectedTrack.track.addEventListener('error', onTrackLoad, { once: true });\n } else {\n // Track already loaded, force initial update\n requestAnimationFrame(() => {\n if (this.currentTrack && this.currentTrack.track === selectedTrack.track) {\n this.updateCaptions();\n }\n });\n }\n };\n\n // Use requestAnimationFrame to ensure track is ready\n requestAnimationFrame(() => {\n if (this.currentTrack && this.currentTrack.track === selectedTrack.track) {\n ensureTrackReady();\n }\n });\n\n this.player.emit('captionsenabled', selectedTrack);\n }\n }\n\n disable() {\n if (this.currentTrack) {\n this.currentTrack.track.mode = 'hidden';\n this.currentTrack = null;\n }\n\n this.element.style.display = 'none';\n this.element.innerHTML = '';\n this.element.removeAttribute('lang');\n this.currentCue = null;\n this.player.state.captionsEnabled = false;\n this.player.emit('captionsdisabled');\n }\n\n updateCaptions() {\n if (!this.currentTrack || !this.currentTrack.track) {\n return;\n }\n\n // Ensure track mode is set to 'hidden' (not 'disabled') to receive cue updates\n // 'hidden' mode loads cues and fires cuechange events, but doesn't show native captions\n // If track is 'disabled', it won't have activeCues or fire events\n if (this.currentTrack.track.mode === 'disabled') {\n this.currentTrack.track.mode = 'hidden';\n }\n\n // Ensure track is in 'hidden' mode (not 'showing') for custom caption display\n if (this.currentTrack.track.mode === 'showing') {\n this.currentTrack.track.mode = 'hidden';\n }\n\n // Check if track has cues loaded\n if (!this.currentTrack.track.activeCues) {\n // If no activeCues property, track might not be ready yet\n // Try to access cues directly\n if (this.currentTrack.track.cues && this.currentTrack.track.cues.length > 0) {\n // Track has cues but no active ones yet - this is normal\n // Clear any existing caption\n if (this.currentCue) {\n this.element.innerHTML = '';\n this.element.style.display = 'none';\n this.currentCue = null;\n }\n }\n return;\n }\n\n const activeCues = this.currentTrack.track.activeCues;\n const isAudioPlayer = this.player.element.tagName.toLowerCase() === 'audio';\n\n if (activeCues.length > 0) {\n const cue = activeCues[0];\n\n // Only update if the cue has changed\n if (this.currentCue !== cue) {\n this.currentCue = cue;\n\n // Parse and display cue text\n let text = cue.text;\n\n // Handle VTT formatting\n text = this.parseVTTFormatting(text);\n\n // Audio players: transcript-style accumulation\n if (isAudioPlayer) {\n // Remove highlight from previous active cue\n const existingCues = this.element.querySelectorAll(`.${this.player.options.classPrefix}-caption-cue`);\n existingCues.forEach(el => el.classList.remove(`${this.player.options.classPrefix}-caption-active`));\n \n // Check if this cue is already displayed\n const cueId = `cue-${cue.startTime}-${cue.endTime}`;\n let cueElement = this.element.querySelector(`[data-cue-id=\"${cueId}\"]`);\n \n if (!cueElement) {\n // Create new cue element\n cueElement = document.createElement('div');\n cueElement.className = `${this.player.options.classPrefix}-caption-cue`;\n cueElement.setAttribute('data-cue-id', cueId);\n cueElement.innerHTML = DOMUtils.sanitizeHTML(text);\n this.element.appendChild(cueElement);\n }\n \n // Highlight active cue\n cueElement.classList.add(`${this.player.options.classPrefix}-caption-active`);\n \n // Scroll to active cue smoothly - center it for better visibility\n requestAnimationFrame(() => {\n if (cueElement) {\n cueElement.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n });\n } else {\n // Video players: replace content as before\n this.element.innerHTML = DOMUtils.sanitizeHTML(text);\n }\n\n // Make sure it's visible when there's content\n this.element.style.display = 'block';\n \n // Position captions above controls on mobile\n this.positionCaptionsOnMobile();\n\n this.player.emit('captionchange', cue);\n }\n } else if (this.currentCue) {\n // Clear caption when no active cues (video players only)\n if (!isAudioPlayer) {\n this.element.innerHTML = '';\n this.element.style.display = 'none';\n }\n this.currentCue = null;\n }\n }\n \n positionCaptionsOnMobile() {\n if (!this.element || this.element.style.display === 'none') {\n return;\n }\n \n const isFullscreen = this.player.state?.fullscreen || false;\n const mobile = isMobile();\n \n if (!mobile && !isFullscreen) {\n // Reset to CSS defaults on desktop\n this.element.style.bottom = '';\n return;\n }\n \n const controls = this.player.controlBar?.element;\n if (!controls) {\n return;\n }\n \n // Use requestAnimationFrame to ensure layout is complete\n requestAnimationFrame(() => {\n if (!this.element || this.element.style.display === 'none') {\n return;\n }\n \n const controlsRect = controls.getBoundingClientRect();\n const wrapperRect = this.player.videoWrapper.getBoundingClientRect();\n const bottomOffset = wrapperRect.bottom - controlsRect.top + 16;\n \n this.element.style.bottom = `${bottomOffset}px`;\n \n if (this.player.options.debug) {\n console.log('[VidPly] Caption position:', {\n mobile,\n isFullscreen,\n controlsHeight: controlsRect.height,\n bottomOffset: `${bottomOffset}px`\n });\n }\n });\n }\n\n parseVTTFormatting(text) {\n // Basic VTT tag support\n text = text.replace(/<c[^>]*>(.*?)<\\/c>/g, '<span class=\"caption-class\">$1</span>');\n text = text.replace(/<b>(.*?)<\\/b>/g, '<strong>$1</strong>');\n text = text.replace(/<i>(.*?)<\\/i>/g, '<em>$1</em>');\n text = text.replace(/<u>(.*?)<\\/u>/g, '<u>$1</u>');\n\n // Voice tags\n text = text.replace(/<v\\s+([^>]+)>(.*?)<\\/v>/g, '<span class=\"caption-voice\" data-voice=\"$1\">$2</span>');\n\n return text;\n }\n\n updateStyles() {\n if (!this.element) return;\n\n const options = this.player.options;\n\n this.element.style.fontSize = options.captionsFontSize;\n this.element.style.fontFamily = options.captionsFontFamily;\n this.element.style.color = options.captionsColor;\n this.element.style.backgroundColor = this.hexToRgba(\n options.captionsBackgroundColor,\n options.captionsOpacity\n );\n }\n\n hexToRgba(hex, alpha) {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (result) {\n return `rgba(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}, ${alpha})`;\n }\n return hex;\n }\n\n setCaptionStyle(property, value) {\n switch (property) {\n case 'fontSize':\n this.player.options.captionsFontSize = value;\n break;\n case 'fontFamily':\n this.player.options.captionsFontFamily = value;\n break;\n case 'color':\n this.player.options.captionsColor = value;\n break;\n case 'backgroundColor':\n this.player.options.captionsBackgroundColor = value;\n break;\n case 'opacity':\n this.player.options.captionsOpacity = value;\n break;\n }\n\n this.updateStyles();\n this.saveCaptionPreferences();\n this.player.emit('captionschange');\n }\n\n getAvailableTracks() {\n return this.tracks.map((t, index) => ({\n index,\n language: t.language,\n label: t.label || t.language,\n kind: t.kind\n }));\n }\n\n switchTrack(trackIndex) {\n if (trackIndex >= 0 && trackIndex < this.tracks.length) {\n this.disable();\n this.enable(trackIndex);\n }\n }\n\n destroy() {\n this.disable();\n\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n }\n}\n\n", "/**\r\n * Keyboard Accessibility Manager\r\n */\r\n\r\nexport class KeyboardManager {\r\n constructor(player) {\r\n this.player = player;\r\n this.shortcuts = player.options.keyboardShortcuts;\r\n \r\n this.init();\r\n }\r\n\r\n init() {\r\n this.attachEvents();\r\n }\r\n\r\n attachEvents() {\r\n // Listen for keyboard events on the player container using CAPTURE phase\r\n // This ensures we intercept events before they reach child elements\r\n this.player.container.addEventListener('keydown', (e) => {\r\n this.handleKeydown(e);\r\n }, true); // Use capture phase\r\n\r\n // Make player container focusable\r\n if (!this.player.container.hasAttribute('tabindex')) {\r\n this.player.container.setAttribute('tabindex', '0');\r\n }\r\n }\r\n\r\n handleKeydown(e) {\r\n // Don't handle if target is an input element\r\n if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.tagName === 'SELECT') {\r\n return;\r\n }\r\n \r\n // Don't handle if focus is inside a menu (let menu handle its own keyboard navigation)\r\n const activeElement = document.activeElement;\r\n if (activeElement) {\r\n const menu = activeElement.closest('.vidply-menu, [role=\"menu\"]');\r\n if (menu) {\r\n return; // Let the menu handle keyboard events\r\n }\r\n \r\n // Don't handle if focus is on a playlist button (let playlist handle navigation)\r\n const playlistButton = activeElement.closest('.vidply-playlist-item-button');\r\n if (playlistButton) {\r\n return; // Let the playlist handle keyboard events\r\n }\r\n }\r\n\r\n const key = e.key;\r\n let handled = false;\r\n\r\n // Special handling for ESC key - exit fullscreen (especially for iOS pseudo-fullscreen)\r\n if (key === 'Escape' && this.player.state.fullscreen) {\r\n this.player.exitFullscreen();\r\n e.preventDefault();\r\n e.stopPropagation();\r\n return;\r\n }\r\n\r\n // Check each shortcut category\r\n for (const [action, keys] of Object.entries(this.shortcuts)) {\r\n if (keys.includes(key)) {\r\n handled = this.executeAction(action, e);\r\n if (handled) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.announceAction(action);\r\n break;\r\n }\r\n }\r\n }\r\n \r\n // Log unhandled keys for debugging (in development)\r\n if (!handled && this.player.options.debug) {\r\n console.log('[VidPly] Unhandled key:', e.key, 'code:', e.code, 'shiftKey:', e.shiftKey);\r\n }\r\n }\r\n\r\n executeAction(action, event) {\r\n switch (action) {\r\n case 'play-pause':\r\n this.player.toggle();\r\n return true;\r\n\r\n case 'volume-up':\r\n this.player.setVolume(Math.min(1, this.player.state.volume + 0.1));\r\n return true;\r\n\r\n case 'volume-down':\r\n this.player.setVolume(Math.max(0, this.player.state.volume - 0.1));\r\n return true;\r\n\r\n case 'seek-forward':\r\n this.player.seekForward();\r\n return true;\r\n\r\n case 'seek-backward':\r\n this.player.seekBackward();\r\n return true;\r\n\r\n case 'mute':\r\n this.player.toggleMute();\r\n return true;\r\n\r\n case 'fullscreen':\r\n this.player.toggleFullscreen();\r\n return true;\r\n\r\n case 'captions':\r\n // If only one caption track, toggle on/off\r\n // If multiple tracks, open caption menu\r\n if (this.player.captionManager && this.player.captionManager.tracks.length > 1) {\r\n // Get captions button from control bar\r\n const captionsButton = this.player.controlBar && this.player.controlBar.controls.captions;\r\n if (captionsButton) {\r\n this.player.controlBar.showCaptionsMenu(captionsButton);\r\n } else {\r\n // Fallback to toggle if button doesn't exist\r\n this.player.toggleCaptions();\r\n }\r\n } else {\r\n this.player.toggleCaptions();\r\n }\r\n return true;\r\n\r\n case 'caption-style-menu':\r\n // Open caption style menu\r\n if (this.player.controlBar && this.player.controlBar.controls.captionStyle) {\r\n this.player.controlBar.showCaptionStyleMenu(this.player.controlBar.controls.captionStyle);\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'speed-up':\r\n this.player.setPlaybackSpeed(\r\n Math.min(2, this.player.state.playbackSpeed + 0.25)\r\n );\r\n return true;\r\n\r\n case 'speed-down':\r\n this.player.setPlaybackSpeed(\r\n Math.max(0.25, this.player.state.playbackSpeed - 0.25)\r\n );\r\n return true;\r\n\r\n case 'speed-menu':\r\n // Open speed menu\r\n if (this.player.controlBar && this.player.controlBar.controls.speed) {\r\n this.player.controlBar.showSpeedMenu(this.player.controlBar.controls.speed);\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'quality-menu':\r\n // Open quality menu\r\n if (this.player.controlBar && this.player.controlBar.controls.quality) {\r\n this.player.controlBar.showQualityMenu(this.player.controlBar.controls.quality);\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'chapters-menu':\r\n // Open chapters menu\r\n if (this.player.controlBar && this.player.controlBar.controls.chapters) {\r\n this.player.controlBar.showChaptersMenu(this.player.controlBar.controls.chapters);\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'transcript-toggle':\r\n // Toggle transcript\r\n if (this.player.transcriptManager) {\r\n this.player.transcriptManager.toggleTranscript();\r\n return true;\r\n }\r\n return false;\r\n\r\n default:\r\n return false;\r\n }\r\n }\r\n\r\n announceAction(action) {\r\n if (!this.player.options.screenReaderAnnouncements) return;\r\n\r\n let message = '';\r\n\r\n switch (action) {\r\n case 'play-pause':\r\n message = this.player.state.playing ? 'Playing' : 'Paused';\r\n break;\r\n case 'volume-up':\r\n message = `Volume ${Math.round(this.player.state.volume * 100)}%`;\r\n break;\r\n case 'volume-down':\r\n message = `Volume ${Math.round(this.player.state.volume * 100)}%`;\r\n break;\r\n case 'mute':\r\n message = this.player.state.muted ? 'Muted' : 'Unmuted';\r\n break;\r\n case 'fullscreen':\r\n message = this.player.state.fullscreen ? 'Fullscreen' : 'Exit fullscreen';\r\n break;\r\n case 'captions':\r\n message = this.player.state.captionsEnabled ? 'Captions on' : 'Captions off';\r\n break;\r\n case 'speed-up':\r\n case 'speed-down':\r\n message = `Speed ${this.player.state.playbackSpeed}x`;\r\n break;\r\n }\r\n\r\n if (message) {\r\n this.announce(message);\r\n }\r\n }\r\n\r\n announce(message, priority = 'polite') {\r\n // Create or get announcement element\r\n let announcer = document.getElementById('vidply-announcer');\r\n \r\n if (!announcer) {\r\n announcer = document.createElement('div');\r\n announcer.id = 'vidply-announcer';\r\n announcer.className = 'vidply-sr-only';\r\n announcer.setAttribute('aria-live', priority);\r\n announcer.setAttribute('aria-atomic', 'true');\r\n announcer.style.cssText = `\r\n position: absolute;\r\n left: -10000px;\r\n width: 1px;\r\n height: 1px;\r\n overflow: hidden;\r\n `;\r\n document.body.appendChild(announcer);\r\n }\r\n\r\n // Clear and set new message\r\n announcer.textContent = '';\r\n setTimeout(() => {\r\n announcer.textContent = message;\r\n }, 100);\r\n }\r\n\r\n updateShortcut(action, keys) {\r\n if (Array.isArray(keys)) {\r\n this.shortcuts[action] = keys;\r\n }\r\n }\r\n\r\n destroy() {\r\n // Event listeners are automatically removed when the container is destroyed\r\n }\r\n}\r\n\r\n", "/**\n * VidPly - Universal Video Player\n * Main Player Class\n */\n\nimport {EventEmitter} from '../utils/EventEmitter.js';\nimport {DOMUtils} from '../utils/DOMUtils.js';\nimport {ControlBar} from '../controls/ControlBar.js';\nimport {CaptionManager} from '../controls/CaptionManager.js';\nimport {KeyboardManager} from '../controls/KeyboardManager.js';\nimport {HTML5Renderer} from '../renderers/HTML5Renderer.js';\nimport {createPlayOverlay, createIconElement} from '../icons/Icons.js';\nimport {i18n} from '../i18n/i18n.js';\nimport {StorageManager} from '../utils/StorageManager.js';\nimport {DraggableResizable} from '../utils/DraggableResizable.js';\nimport {createMenuItem, attachMenuKeyboardNavigation, focusFirstMenuItem} from '../utils/MenuUtils.js';\nimport {createLabeledSelect, preventDragOnElement} from '../utils/FormUtils.js';\nimport {debounce, isMobile, rafWithTimeout} from '../utils/PerformanceUtils.js';\n\n// Static counter for unique player instances\nlet playerInstanceCounter = 0;\n\nexport class Player extends EventEmitter {\n constructor(element, options = {}) {\n super();\n\n this.element = typeof element === 'string' ? document.querySelector(element) : element;\n if (!this.element) {\n throw new Error('VidPly: Element not found');\n }\n\n // Assign unique instance ID\n playerInstanceCounter++;\n this.instanceId = playerInstanceCounter;\n\n // Auto-create media element if a non-media element is provided\n if (this.element.tagName !== 'VIDEO' && this.element.tagName !== 'AUDIO') {\n const mediaType = options.mediaType || 'video';\n const mediaElement = document.createElement(mediaType);\n\n // Copy attributes from the div to the media element\n Array.from(this.element.attributes).forEach(attr => {\n if (attr.name !== 'id' && attr.name !== 'class' && !attr.name.startsWith('data-')) {\n mediaElement.setAttribute(attr.name, attr.value);\n }\n });\n\n // Copy any track elements from the div\n const tracks = this.element.querySelectorAll('track');\n tracks.forEach(track => {\n mediaElement.appendChild(track.cloneNode(true));\n });\n\n // Clear the div and insert the media element\n this.element.innerHTML = '';\n this.element.appendChild(mediaElement);\n\n // Update element reference to the actual media element\n this.element = mediaElement;\n }\n \n // Store original element reference for mixed media swapping\n // This allows us to swap between video and audio elements in mixed playlists\n this._originalElement = this.element;\n\n // Default options\n this.options = {\n // Display\n width: null,\n height: null,\n poster: null,\n responsive: true,\n fillContainer: false,\n\n // Playback\n autoplay: false,\n loop: false,\n muted: false,\n volume: 0.8,\n playbackSpeed: 1.0,\n preload: 'metadata',\n startTime: 0,\n playsInline: true, // Enable inline playback on iOS (prevents native fullscreen)\n\n // Controls\n controls: true,\n hideControlsDelay: 3000,\n playPauseButton: true,\n progressBar: true,\n currentTime: true,\n duration: true,\n volumeControl: true,\n muteButton: true,\n chaptersButton: true,\n qualityButton: true,\n captionStyleButton: true,\n speedButton: true,\n captionsButton: true,\n transcriptButton: true,\n fullscreenButton: true,\n pipButton: false,\n\n // Seeking\n seekInterval: 10,\n seekIntervalLarge: 30,\n\n // Captions\n captions: true,\n captionsDefault: false,\n captionsFontSize: '100%',\n captionsFontFamily: 'sans-serif',\n captionsColor: '#FFFFFF',\n captionsBackgroundColor: '#000000',\n captionsOpacity: 0.8,\n\n // Audio Description\n audioDescription: true,\n audioDescriptionSrc: null, // URL to audio-described version\n audioDescriptionButton: true,\n\n // Sign Language\n signLanguage: true,\n signLanguageSrc: null, // URL to sign language video\n signLanguageButton: true,\n signLanguagePosition: 'bottom-right', // Position: 'bottom-right', 'bottom-left', 'top-right', 'top-left'\n\n // Transcripts\n transcript: false,\n transcriptPosition: 'external',\n transcriptContainer: null,\n\n // Keyboard\n keyboard: true,\n keyboardShortcuts: {\n 'play-pause': [' ', 'p', 'k'],\n 'volume-up': ['ArrowUp'],\n 'volume-down': ['ArrowDown'],\n 'seek-forward': ['ArrowRight'],\n 'seek-backward': ['ArrowLeft'],\n 'mute': ['m'],\n 'fullscreen': ['f'],\n 'captions': ['c'],\n 'caption-style-menu': ['a'],\n 'speed-up': ['>'],\n 'speed-down': ['<'],\n 'speed-menu': ['s'],\n 'quality-menu': ['q'],\n 'chapters-menu': ['j'],\n 'transcript-toggle': ['t']\n },\n\n // Accessibility\n ariaLabels: {},\n screenReaderAnnouncements: true,\n highContrast: false,\n focusHighlight: true,\n metadataAlerts: {},\n metadataHashtags: {},\n\n // Languages\n language: 'en',\n languages: ['en'],\n\n // Advanced\n debug: false,\n classPrefix: 'vidply',\n iconType: 'svg',\n pauseOthersOnPlay: true,\n\n // Callbacks\n onReady: null,\n onPlay: null,\n onPause: null,\n onEnded: null,\n onTimeUpdate: null,\n onVolumeChange: null,\n onError: null,\n\n ...options\n };\n\n this.options.metadataAlerts = this.options.metadataAlerts || {};\n this.options.metadataHashtags = this.options.metadataHashtags || {};\n\n // Storage manager\n this.storage = new StorageManager('vidply');\n \n // Load saved player preferences\n const savedPrefs = this.storage.getPlayerPreferences();\n if (savedPrefs) {\n if (savedPrefs.volume !== undefined) this.options.volume = savedPrefs.volume;\n if (savedPrefs.playbackSpeed !== undefined) this.options.playbackSpeed = savedPrefs.playbackSpeed;\n if (savedPrefs.muted !== undefined) this.options.muted = savedPrefs.muted;\n }\n \n // State\n this.state = {\n ready: false,\n playing: false,\n paused: true,\n ended: false,\n buffering: false,\n seeking: false,\n muted: this.options.muted,\n volume: this.options.volume,\n currentTime: 0,\n duration: 0,\n playbackSpeed: this.options.playbackSpeed,\n fullscreen: false,\n pip: false,\n captionsEnabled: this.options.captionsDefault,\n currentCaption: null,\n controlsVisible: true,\n audioDescriptionEnabled: false,\n signLanguageEnabled: false\n };\n\n // Store original source for toggling\n this.originalSrc = null;\n this.audioDescriptionSrc = this.options.audioDescriptionSrc;\n this.signLanguageSrc = this.options.signLanguageSrc;\n this.signLanguageSources = this.options.signLanguageSources || {}; // Map of lang codes to video URLs\n this.currentSignLanguage = null; // Current selected sign language code\n this.signLanguageVideo = null;\n // Store references to source elements with audio description attributes\n this.audioDescriptionSourceElement = null;\n this.originalAudioDescriptionSource = null;\n // Store caption tracks that should be swapped for audio description\n this.audioDescriptionCaptionTracks = [];\n this._audioDescriptionDesiredState = false;\n\n // DOM query cache (for performance optimization)\n this._textTracksCache = null;\n this._textTracksDirty = true;\n this._sourceElementsCache = null;\n this._sourceElementsDirty = true;\n this._trackElementsCache = null;\n this._trackElementsDirty = true;\n\n // Timeout management (for cleanup)\n this.timeouts = new Set();\n\n // Components\n this.container = null;\n this.renderer = null;\n this.controlBar = null;\n this.captionManager = null;\n this.keyboardManager = null;\n this.settingsDialog = null;\n \n // Metadata handling\n this.metadataCueChangeHandler = null;\n this.metadataAlertHandlers = new Map();\n\n // Initialize\n this.init();\n }\n\n async init() {\n try {\n this.log('Initializing VidPly player');\n\n // Load custom language files if specified\n if (this.options.languageFiles) {\n try {\n await i18n.loadLanguagesFromUrls(this.options.languageFiles);\n } catch (error) {\n console.warn('Failed to load some language files:', error);\n }\n }\n\n // Load single language file if specified (for backwards compatibility)\n if (this.options.languageFile && this.options.languageFileUrl) {\n try {\n await i18n.loadLanguageFromUrl(this.options.languageFile, this.options.languageFileUrl);\n this.log(`Custom language file loaded for ${this.options.languageFile}`);\n } catch (error) {\n console.warn(`Failed to load language file for ${this.options.languageFile}:`, error);\n }\n }\n\n // Auto-detect language from HTML lang attribute if not explicitly set\n if (!this.options.language || this.options.language === 'en') {\n const htmlLang = this.detectHtmlLanguage();\n if (htmlLang) {\n this.options.language = htmlLang;\n this.log(`Auto-detected language from HTML: ${htmlLang}`);\n }\n }\n\n // Ensure we have a language set (default to 'en' if not set)\n if (!this.options.language) {\n this.options.language = 'en';\n }\n\n // Ensure requested language is available (loads built-ins on demand)\n await i18n.ensureLanguage(this.options.language);\n\n // Set language\n i18n.setLanguage(this.options.language);\n\n // Create container\n this.createContainer();\n\n // Detect and initialize renderer (only if source exists)\n const src = this.element.src || this.element.querySelector('source')?.src;\n if (src) {\n await this.initializeRenderer();\n } else {\n this.log('No initial source - waiting for playlist or manual load');\n }\n\n // Create controls\n if (this.options.controls) {\n this.controlBar = new ControlBar(this);\n this.videoWrapper.appendChild(this.controlBar.element);\n }\n\n // Initialize captions\n if (this.options.captions) {\n this.captionManager = new CaptionManager(this);\n }\n\n // Initialize transcript lazily unless explicitly requested\n if (this.options.transcript) {\n await this.ensureTranscriptManager();\n }\n \n // Always set up metadata track handling (independent of transcript)\n this.setupMetadataHandling();\n\n // Initialize keyboard controls\n if (this.options.keyboard) {\n this.keyboardManager = new KeyboardManager(this);\n }\n\n // Setup responsive handlers\n this.setupResponsiveHandlers();\n\n // Set initial state\n if (this.options.startTime > 0) {\n this.seek(this.options.startTime);\n }\n\n // Apply volume and mute settings after renderer is initialized\n // Use requestAnimationFrame to ensure renderer is fully ready\n requestAnimationFrame(() => {\n if (this.options.muted) {\n this.mute();\n } else if (this.renderer && this.renderer.media) {\n // Ensure media element is not muted if options say it shouldn't be\n this.renderer.setMuted(false);\n }\n\n if (this.options.volume !== 0.8) {\n this.setVolume(this.options.volume);\n } else if (this.renderer && this.renderer.media) {\n // Ensure volume is set even if it's the default\n this.renderer.setVolume(this.options.volume);\n }\n });\n\n // Mark as ready\n this.state.ready = true;\n this.emit('ready');\n\n if (this.options.onReady) {\n this.options.onReady.call(this);\n }\n\n // Autoplay if enabled\n if (this.options.autoplay) {\n this.play();\n }\n\n this.log('Player initialized successfully');\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Ensure the transcript manager is available, creating it on demand.\n * This keeps initial load fast when transcripts are not needed.\n */\n async ensureTranscriptManager() {\n if (this.transcriptManager) {\n return this.transcriptManager;\n }\n\n if (!this.options.transcript && !this.options.transcriptButton) {\n return null;\n }\n\n const module = await import('../controls/TranscriptManager.js');\n const Manager = module.TranscriptManager || module.default;\n\n if (!Manager) {\n return null;\n }\n\n this.transcriptManager = new Manager(this);\n return this.transcriptManager;\n }\n\n /**\n * Toggle transcript visibility, lazily creating the manager if necessary.\n */\n async toggleTranscript() {\n const manager = await this.ensureTranscriptManager();\n if (!manager) return;\n\n manager.toggleTranscript();\n if (this.controlBar) {\n this.controlBar.updateTranscriptButton();\n }\n }\n\n /**\n * Detect language from HTML lang attribute\n * @returns {string|null} Language code if available in translations or as built-in, null otherwise\n */\n detectHtmlLanguage() {\n // Try to get lang from html element\n const htmlLang = document.documentElement.lang || document.documentElement.getAttribute('lang');\n\n if (!htmlLang) {\n return null;\n }\n\n // Normalize the language code (e.g., \"en-US\" -> \"en\", \"de-DE\" -> \"de\")\n const normalizedLang = htmlLang.toLowerCase().split('-')[0];\n\n // Check if this language is available in our translations (already loaded)\n if (i18n.translations[normalizedLang]) {\n return normalizedLang;\n }\n\n // Check if this language is available as a built-in that can be loaded on demand\n if (i18n.builtInLanguageLoaders && i18n.builtInLanguageLoaders[normalizedLang]) {\n return normalizedLang;\n }\n\n // Language not available, will fallback to English\n this.log(`Language \"${htmlLang}\" not available, using English as fallback`);\n return null; // Return null instead of 'en' to let the default language handling work\n }\n\n createContainer() {\n // Create main container with unique label for multiple players on same page\n const playerLabel = this.instanceId > 1 \n ? `${i18n.t('player.label')} ${this.instanceId}`\n : i18n.t('player.label');\n \n this.container = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-player`,\n attributes: {\n 'role': 'application',\n 'aria-label': playerLabel,\n 'tabindex': '0'\n }\n });\n\n // Add media type class\n const mediaType = this.element.tagName.toLowerCase();\n this.container.classList.add(`${this.options.classPrefix}-${mediaType}`);\n\n // Add responsive class\n if (this.options.responsive) {\n this.container.classList.add(`${this.options.classPrefix}-responsive`);\n }\n\n // Create video wrapper (for proper positioning of controls)\n this.videoWrapper = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-video-wrapper`\n });\n\n // Wrap original element\n this.element.parentNode.insertBefore(this.container, this.element);\n \n // Create track artwork element for single audio files (before video wrapper)\n // This shows the poster/artwork above the audio player (similar to playlists)\n if (this.element.tagName === 'AUDIO' && this.options.poster) {\n this.trackArtworkElement = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-track-artwork`,\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n this.trackArtworkElement.style.backgroundImage = `url(${this.options.poster})`;\n this.container.appendChild(this.trackArtworkElement);\n }\n \n this.container.appendChild(this.videoWrapper);\n this.videoWrapper.appendChild(this.element);\n\n // Hide native controls and set dimensions\n this.element.controls = false;\n this.element.removeAttribute('controls');\n this.element.setAttribute('tabindex', '-1'); // Remove from tab order\n this.element.style.width = '100%';\n this.element.style.height = '100%';\n\n // Enable inline playback on iOS (prevents native fullscreen)\n // This allows custom controls to work on iOS devices\n if (this.element.tagName === 'VIDEO' && this.options.playsInline) {\n this.element.setAttribute('playsinline', '');\n this.element.playsInline = true; // Property version\n }\n\n // Set dimensions\n if (this.options.width) {\n this.container.style.width = typeof this.options.width === 'number'\n ? `${this.options.width}px`\n : this.options.width;\n }\n\n if (this.options.height) {\n this.container.style.height = typeof this.options.height === 'number'\n ? `${this.options.height}px`\n : this.options.height;\n }\n\n // Set poster (convert relative paths to absolute URLs)\n if (this.options.poster && this.element.tagName === 'VIDEO') {\n this.element.poster = this.resolvePosterPath(this.options.poster);\n }\n\n // Create centered play button overlay (only for video)\n if (this.element.tagName === 'VIDEO') {\n this.createPlayButtonOverlay();\n }\n \n // Store reference to player on element for easy access\n this.element.vidply = this;\n \n // Add to static instances array\n Player.instances.push(this);\n\n // Make video/audio element clickable to toggle play/pause\n this.element.style.cursor = 'pointer';\n this.element.addEventListener('click', (e) => {\n // Prevent if clicking on native controls (shouldn't happen but just in case)\n if (e.target === this.element) {\n this.toggle();\n }\n });\n\n this.on('play', () => {\n // Hide poster immediately when playing\n this.hidePosterOverlay();\n });\n\n this.on('timeupdate', () => {\n // Hide poster when video has started playing (currentTime > 0)\n if (this.state.currentTime > 0) {\n this.hidePosterOverlay();\n }\n });\n\n // Also hide poster on loadeddata event (when first frame is loaded)\n this.element.addEventListener('loadeddata', () => {\n if (this.state.playing || this.state.currentTime > 0) {\n this.hidePosterOverlay();\n }\n }, { once: true });\n }\n\n createPlayButtonOverlay() {\n // Create complete SVG play button from Icons.js\n this.playButtonOverlay = createPlayOverlay();\n\n // Add click handler\n this.playButtonOverlay.addEventListener('click', () => {\n this.toggle();\n });\n\n // Add to video wrapper\n this.videoWrapper.appendChild(this.playButtonOverlay);\n\n // Show/hide based on play state\n this.on('play', () => {\n this.playButtonOverlay.style.opacity = '0';\n this.playButtonOverlay.style.pointerEvents = 'none';\n });\n\n this.on('pause', () => {\n this.playButtonOverlay.style.opacity = '1';\n this.playButtonOverlay.style.pointerEvents = 'auto';\n this.positionPlayOverlayOnMobile();\n });\n\n this.on('ended', () => {\n this.playButtonOverlay.style.opacity = '1';\n this.playButtonOverlay.style.pointerEvents = 'auto';\n this.positionPlayOverlayOnMobile();\n });\n \n // Debounced resize handler\n this.debouncedPositionPlayOverlay = debounce(() => {\n this.positionPlayOverlayOnMobile();\n }, 150);\n \n window.addEventListener('resize', this.debouncedPositionPlayOverlay);\n \n this.on('loadedmetadata', () => {\n this.positionPlayOverlayOnMobile();\n });\n \n // Recalculate on fullscreen change with RAF\n this.on('enterfullscreen', () => {\n rafWithTimeout(() => this.positionPlayOverlayOnMobile(), 100);\n });\n \n this.on('exitfullscreen', () => {\n rafWithTimeout(() => this.positionPlayOverlayOnMobile(), 100);\n });\n }\n \n positionPlayOverlayOnMobile() {\n if (!this.playButtonOverlay || this.element.tagName !== 'VIDEO') {\n return;\n }\n \n const mobile = isMobile();\n \n if (!mobile) {\n // Reset to CSS defaults on desktop\n this.playButtonOverlay.style.top = '';\n return;\n }\n \n const videoRect = this.element.getBoundingClientRect();\n const wrapperRect = this.videoWrapper.getBoundingClientRect();\n const videoCenter = (videoRect.top - wrapperRect.top) + (videoRect.height / 2);\n \n this.playButtonOverlay.style.top = `${videoCenter}px`;\n }\n\n async initializeRenderer() {\n // Use pending source for external renderers, or get from element for HTML5\n let src = this._pendingSource || this.element.src || this.element.querySelector('source')?.src;\n\n if (!src) {\n throw new Error('No media source found');\n }\n \n // Store the current source for renderers to access\n this.currentSource = src;\n \n // Clear pending source after using it\n this._pendingSource = null;\n\n // Check for source elements with audio description attributes\n const sourceElements = this.sourceElements;\n for (const sourceEl of sourceElements) {\n const descSrc = sourceEl.getAttribute('data-desc-src');\n const origSrc = sourceEl.getAttribute('data-orig-src');\n \n if (descSrc || origSrc) {\n // Found a source element with audio description attributes\n // Store the first one as reference, but we'll search all of them when toggling\n if (!this.audioDescriptionSourceElement) {\n this.audioDescriptionSourceElement = sourceEl;\n }\n \n if (origSrc) {\n // Store the original src from the attribute for this source\n if (!this.originalAudioDescriptionSource) {\n this.originalAudioDescriptionSource = origSrc;\n }\n // Store the original src from the first source element that has data-orig-src\n if (!this.originalSrc) {\n this.originalSrc = origSrc;\n }\n } else {\n // If data-orig-src is not set, use the current src attribute\n const currentSrcAttr = sourceEl.getAttribute('src');\n if (!this.originalAudioDescriptionSource && currentSrcAttr) {\n this.originalAudioDescriptionSource = currentSrcAttr;\n }\n if (!this.originalSrc && currentSrcAttr) {\n this.originalSrc = currentSrcAttr;\n }\n }\n \n // Store audio description source from data-desc-src (use first one found)\n if (descSrc && !this.audioDescriptionSrc) {\n this.audioDescriptionSrc = descSrc;\n }\n // Continue checking all source elements to ensure we capture all audio description sources\n }\n }\n\n // Check for caption/subtitle tracks with audio description versions\n // Only tracks with explicit data-desc-src attribute are swapped (no auto-detection to avoid 404 errors)\n // Description tracks (kind=\"descriptions\") are NOT swapped - they're for transcripts\n const trackElements = this.trackElements;\n trackElements.forEach(trackEl => {\n const trackKind = trackEl.getAttribute('kind');\n const trackDescSrc = trackEl.getAttribute('data-desc-src');\n \n // Only handle caption/subtitle tracks (not description tracks)\n // Description tracks stay as-is since they're for transcripts\n // Include captions, subtitles, and chapters tracks that can be swapped for audio description\n if (trackKind === 'captions' || trackKind === 'subtitles' || trackKind === 'chapters') {\n if (trackDescSrc) {\n // Found a track with explicit data-desc-src - this is the described version\n this.audioDescriptionCaptionTracks.push({\n trackElement: trackEl,\n originalSrc: trackEl.getAttribute('src'),\n describedSrc: trackDescSrc,\n originalTrackSrc: trackEl.getAttribute('data-orig-src') || trackEl.getAttribute('src'),\n explicit: true // Explicitly defined, so we should validate it\n });\n this.log(`Found explicit described ${trackKind} track: ${trackEl.getAttribute('src')} -> ${trackDescSrc}`);\n }\n // Note: Auto-detection disabled to avoid 404 console errors\n // If you want described tracks, add data-desc-src attribute to the track element\n }\n // Description tracks (kind=\"descriptions\") are ignored - they remain unchanged for transcripts\n });\n\n // Store original source for audio description toggling (fallback if not set above)\n if (!this.originalSrc) {\n this.originalSrc = src;\n }\n\n // Detect media type and lazily load heavy renderers\n let rendererClass = HTML5Renderer;\n\n if (src.includes('youtube.com') || src.includes('youtu.be')) {\n const module = await import('../renderers/YouTubeRenderer.js');\n rendererClass = module.YouTubeRenderer || module.default;\n } else if (src.includes('vimeo.com')) {\n const module = await import('../renderers/VimeoRenderer.js');\n rendererClass = module.VimeoRenderer || module.default;\n } else if (src.includes('.m3u8')) {\n const module = await import('../renderers/HLSRenderer.js');\n rendererClass = module.HLSRenderer || module.default;\n } else if (src.includes('soundcloud.com') || src.includes('api.soundcloud.com')) {\n const module = await import('../renderers/SoundCloudRenderer.js');\n rendererClass = module.SoundCloudRenderer || module.default;\n }\n\n this.log(`Using ${rendererClass?.name || 'HTML5Renderer'} renderer`);\n this.renderer = new rendererClass(this);\n await this.renderer.init();\n \n // Invalidate cache after renderer initialization (tracks may have changed)\n this.invalidateTrackCache();\n }\n\n /**\n * Get cached text tracks array\n * @returns {Array} Array of text tracks\n */\n get textTracks() {\n if (!this._textTracksCache || this._textTracksDirty) {\n this._textTracksCache = Array.from(this.element.textTracks || []);\n this._textTracksDirty = false;\n }\n return this._textTracksCache;\n }\n\n /**\n * Get cached source elements array\n * @returns {Array} Array of source elements\n */\n get sourceElements() {\n if (!this._sourceElementsCache || this._sourceElementsDirty) {\n this._sourceElementsCache = Array.from(this.element.querySelectorAll('source'));\n this._sourceElementsDirty = false;\n }\n return this._sourceElementsCache;\n }\n\n /**\n * Get cached track elements array\n * @returns {Array} Array of track elements\n */\n get trackElements() {\n if (!this._trackElementsCache || this._trackElementsDirty) {\n this._trackElementsCache = Array.from(this.element.querySelectorAll('track'));\n this._trackElementsDirty = false;\n }\n return this._trackElementsCache;\n }\n\n /**\n * Invalidate DOM query cache (call when tracks/sources change)\n */\n invalidateTrackCache() {\n this._textTracksDirty = true;\n this._trackElementsDirty = true;\n this._sourceElementsDirty = true;\n }\n\n /**\n * Find a text track by kind and optionally language\n * @param {string} kind - Track kind (captions, subtitles, descriptions, chapters, metadata)\n * @param {string} [language] - Optional language code\n * @returns {TextTrack|null} Found track or null\n */\n findTextTrack(kind, language = null) {\n const tracks = this.textTracks;\n if (language) {\n return tracks.find(t => t.kind === kind && t.language === language);\n }\n return tracks.find(t => t.kind === kind);\n }\n\n /**\n * Find a source element by attribute\n * @param {string} attribute - Attribute name (e.g., 'data-desc-src')\n * @param {string} [value] - Optional attribute value\n * @returns {Element|null} Found source element or null\n */\n findSourceElement(attribute, value = null) {\n const sources = this.sourceElements;\n if (value) {\n return sources.find(el => el.getAttribute(attribute) === value);\n }\n return sources.find(el => el.hasAttribute(attribute));\n }\n\n /**\n * Find a track element by its associated TextTrack\n * @param {TextTrack} track - The TextTrack object\n * @returns {Element|null} Found track element or null\n */\n findTrackElement(track) {\n return this.trackElements.find(el => el.track === track);\n }\n\n /**\n * Convert relative poster path to absolute URL\n * @param {string} posterPath - Poster path (relative or absolute)\n * @returns {string} Absolute URL\n */\n resolvePosterPath(posterPath) {\n if (!posterPath) {\n return posterPath;\n }\n \n // If already absolute (starts with http://, https://, or /), return as-is\n if (posterPath.match(/^(https?:|\\/)/)) {\n return posterPath;\n }\n \n // Convert relative path to absolute URL\n try {\n const posterUrl = new URL(posterPath, window.location.href);\n return posterUrl.href;\n } catch (e) {\n // If URL constructor fails, return as-is\n return posterPath;\n }\n }\n\n showPosterOverlay() {\n if (!this.videoWrapper || this.element.tagName !== 'VIDEO') {\n return;\n }\n\n const poster =\n this.element.getAttribute('poster') ||\n this.element.poster ||\n this.options.poster;\n\n if (!poster) {\n return;\n }\n\n // Resolve relative paths to absolute URLs\n const resolvedPoster = this.resolvePosterPath(poster);\n this.videoWrapper.style.setProperty('--vidply-poster-image', `url(\"${resolvedPoster}\")`);\n this.videoWrapper.classList.add('vidply-forced-poster');\n \n // Apply audio content class (16:3 aspect ratio) for audio in video player\n if (this._isAudioContent && this.container) {\n this.container.classList.add('vidply-audio-content');\n } else if (this.container) {\n this.container.classList.remove('vidply-audio-content');\n }\n }\n\n hidePosterOverlay() {\n if (!this.videoWrapper) {\n return;\n }\n\n this.videoWrapper.classList.remove('vidply-forced-poster');\n this.videoWrapper.style.removeProperty('--vidply-poster-image');\n \n // Note: vidply-audio-content is not removed here because it should persist\n // for the duration of audio content playback, not just poster display\n }\n\n /**\n * Set a managed timeout that will be cleaned up on destroy\n * @param {Function} callback - Callback function\n * @param {number} delay - Delay in milliseconds\n * @returns {number} Timeout ID\n */\n setManagedTimeout(callback, delay) {\n const timeoutId = setTimeout(() => {\n this.timeouts.delete(timeoutId);\n callback();\n }, delay);\n this.timeouts.add(timeoutId);\n return timeoutId;\n }\n\n /**\n * Clear a managed timeout\n * @param {number} timeoutId - Timeout ID to clear\n */\n clearManagedTimeout(timeoutId) {\n if (timeoutId) {\n clearTimeout(timeoutId);\n this.timeouts.delete(timeoutId);\n }\n }\n\n /**\n * Load new media source (for playlists)\n * @param {Object} config - Media configuration\n * @param {string} config.src - Media source URL\n * @param {string} config.type - Media MIME type\n * @param {string} [config.poster] - Poster image URL\n * @param {Array} [config.tracks] - Text tracks (captions, chapters, etc.)\n * @param {string} [config.audioDescriptionSrc] - Audio description video URL\n * @param {string} [config.signLanguageSrc] - Sign language video URL\n */\n /**\n * Check if a source URL requires an external renderer (YouTube, Vimeo, SoundCloud, HLS)\n * @param {string} src - Source URL\n * @returns {boolean}\n */\n isExternalRendererUrl(src) {\n if (!src) return false;\n return src.includes('youtube.com') || \n src.includes('youtu.be') || \n src.includes('vimeo.com') || \n src.includes('soundcloud.com') || \n src.includes('api.soundcloud.com') ||\n src.includes('.m3u8');\n }\n\n async load(config) {\n try {\n this.log('Loading new media:', config.src);\n\n // Pause current playback\n if (this.renderer) {\n this.pause();\n }\n\n // Save scroll position to prevent browser from auto-scrolling when loading new media\n const scrollX = window.scrollX || window.pageXOffset;\n const scrollY = window.scrollY || window.pageYOffset;\n\n // Clear existing text tracks\n const existingTracks = this.trackElements;\n existingTracks.forEach(track => track.remove());\n this.invalidateTrackCache();\n\n // Check if this is an external renderer URL\n const isExternalRenderer = this.isExternalRendererUrl(config.src);\n \n // Set flag early to suppress any errors that might fire during the transition\n // This prevents HTML5 element errors from triggering playlist auto-advance\n if (isExternalRenderer) {\n this._switchingRenderer = true;\n }\n\n // Only set src on HTML5 element for non-external sources\n // External renderers (YouTube, Vimeo, SoundCloud, HLS) handle their own media loading\n if (!isExternalRenderer) {\n this.element.src = config.src;\n\n if (config.type) {\n this.element.type = config.type;\n }\n } else {\n // For external renderers, clear the src to prevent HTML5 element errors\n // but store the URL for the renderer to use\n // DO NOT call load() here - it will trigger an error event on an element without a valid source\n this.element.removeAttribute('src');\n // Also clear any source elements to prevent errors\n const sources = this.element.querySelectorAll('source');\n sources.forEach(s => s.removeAttribute('src'));\n }\n \n // Store the source URL for external renderers to access\n this._pendingSource = config.src;\n \n // Track if current content is audio (for poster aspect ratio)\n this._isAudioContent = config.type && config.type.startsWith('audio/');\n \n // Apply or remove audio content class (16:3 aspect ratio for audio in video player)\n if (this.container) {\n if (this._isAudioContent) {\n this.container.classList.add('vidply-audio-content');\n } else {\n this.container.classList.remove('vidply-audio-content');\n }\n }\n \n // Handle poster display based on content type\n if (config.poster && this.element.tagName === 'VIDEO') {\n if (this._isAudioContent) {\n // For audio in video player: use CSS poster overlay with 16:3 aspect ratio\n this.element.removeAttribute('poster');\n if (this.videoWrapper) {\n const resolvedPoster = this.resolvePosterPath(config.poster);\n this.videoWrapper.style.setProperty('--vidply-poster-image', `url(\"${resolvedPoster}\")`);\n this.videoWrapper.classList.add('vidply-forced-poster');\n }\n } else {\n // For video: use normal poster and remove overlay\n this.element.poster = this.resolvePosterPath(config.poster);\n if (this.videoWrapper) {\n this.videoWrapper.classList.remove('vidply-forced-poster');\n this.videoWrapper.style.removeProperty('--vidply-poster-image');\n }\n }\n }\n\n // Add new text tracks\n if (config.tracks && config.tracks.length > 0) {\n config.tracks.forEach(trackConfig => {\n const track = document.createElement('track');\n track.src = trackConfig.src;\n track.kind = trackConfig.kind || 'captions';\n track.srclang = trackConfig.srclang || 'en';\n track.label = trackConfig.label || trackConfig.srclang;\n\n if (trackConfig.default) {\n track.default = true;\n }\n\n // Insert tracks at the beginning (before any flow content) for HTML5 validity\n const firstChild = this.element.firstChild;\n if (firstChild && firstChild.nodeType === Node.ELEMENT_NODE && firstChild.tagName !== 'TRACK') {\n this.element.insertBefore(track, firstChild);\n } else {\n this.element.appendChild(track);\n }\n });\n this.invalidateTrackCache();\n }\n \n // Remember accessibility feature states before switching tracks\n const wasSignLanguageEnabled = this.state.signLanguageEnabled;\n const wasAudioDescriptionEnabled = this.state.audioDescriptionEnabled;\n \n // Update sources from config FIRST (before hiding features)\n this.audioDescriptionSrc = config.audioDescriptionSrc || null;\n this.signLanguageSrc = config.signLanguageSrc || null;\n \n // Update original source for toggling\n this.originalSrc = config.src;\n \n // Hide accessibility features that were enabled (must happen AFTER updating sources)\n if (wasAudioDescriptionEnabled) {\n this.disableAudioDescription();\n }\n if (wasSignLanguageEnabled) {\n this.disableSignLanguage();\n }\n\n // Check if we need to change renderer type\n const shouldChangeRenderer = this.shouldChangeRenderer(config.src);\n\n // Destroy old renderer if changing types\n if (shouldChangeRenderer && this.renderer) {\n this.renderer.destroy();\n this.renderer = null;\n }\n\n // Initialize or reinitialize renderer\n if (!this.renderer || shouldChangeRenderer) {\n await this.initializeRenderer();\n } else {\n // Just reload the current renderer with the updated element\n this.renderer.media = this.element; // Update media reference\n this.element.load();\n }\n \n // Clear the renderer switching flag after a delay to catch async errors\n // This prevents errors from the old renderer's event queue from causing issues\n if (isExternalRenderer) {\n setTimeout(() => {\n this._switchingRenderer = false;\n }, 500);\n } else {\n this._switchingRenderer = false;\n }\n \n // Restore scroll position immediately after loading to prevent auto-scroll\n window.scrollTo(scrollX, scrollY);\n\n // Reinitialize caption manager to pick up new tracks\n if (this.captionManager) {\n this.captionManager.destroy();\n this.captionManager = new CaptionManager(this);\n }\n \n // Reinitialize transcript manager to pick up new tracks\n if (this.transcriptManager) {\n const wasTranscriptVisible = this.transcriptManager.isVisible;\n this.transcriptManager.destroy();\n this.transcriptManager = null;\n\n await this.ensureTranscriptManager();\n \n // Only restore transcript visibility if new track has captions\n if (wasTranscriptVisible && this.controlBar && this.controlBar.hasCaptionTracks()) {\n this.transcriptManager?.showTranscript();\n }\n }\n \n // Update control bar to show/hide feature buttons based on new tracks\n if (this.controlBar) {\n this.updateControlBar();\n }\n \n // Restore scroll position after control bar update (may have caused micro-scrolls)\n window.scrollTo(scrollX, scrollY);\n \n // Restore accessibility features if they were enabled and available in new track\n if (wasSignLanguageEnabled && this.signLanguageSrc) {\n // Small delay to ensure player and control bar are ready\n setTimeout(() => {\n this.enableSignLanguage();\n // Restore scroll after sign language is shown\n window.scrollTo(scrollX, scrollY);\n }, 150);\n }\n \n if (wasAudioDescriptionEnabled && this.audioDescriptionSrc) {\n // Small delay to ensure player is ready\n setTimeout(() => {\n this.enableAudioDescription();\n // Restore scroll after audio description is enabled\n window.scrollTo(scrollX, scrollY);\n }, 150);\n }\n\n this.emit('sourcechange', config);\n this.log('Media loaded successfully');\n\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Check if we need to change renderer type\n * @param {string} src - New source URL\n * @returns {boolean}\n */\n /**\n * Update control bar to refresh button visibility based on available features\n */\n updateControlBar() {\n if (!this.controlBar) return;\n \n const controlBar = this.controlBar;\n \n // Clear existing controls content\n controlBar.element.innerHTML = '';\n \n // Recreate controls with updated feature detection\n controlBar.createControls();\n \n // Reattach events for the new controls\n controlBar.attachEvents();\n controlBar.setupAutoHide();\n controlBar.setupOverflowDetection();\n }\n \n shouldChangeRenderer(src) {\n if (!this.renderer) return true;\n\n const isYouTube = src.includes('youtube.com') || src.includes('youtu.be');\n const isVimeo = src.includes('vimeo.com');\n const isHLS = src.includes('.m3u8');\n const isSoundCloud = src.includes('soundcloud.com') || src.includes('api.soundcloud.com');\n\n const currentRendererName = this.renderer.constructor.name;\n\n if (isYouTube && currentRendererName !== 'YouTubeRenderer') return true;\n if (isVimeo && currentRendererName !== 'VimeoRenderer') return true;\n if (isHLS && currentRendererName !== 'HLSRenderer') return true;\n if (isSoundCloud && currentRendererName !== 'SoundCloudRenderer') return true;\n if (!isYouTube && !isVimeo && !isHLS && !isSoundCloud && currentRendererName !== 'HTML5Renderer') return true;\n\n return false;\n }\n\n // Playback controls\n play() {\n if (this.renderer) {\n this.renderer.play();\n }\n }\n\n pause() {\n if (this.renderer) {\n this.renderer.pause();\n }\n }\n\n stop() {\n this.pause();\n this.seek(0);\n }\n\n toggle() {\n if (this.state.playing) {\n this.pause();\n } else {\n this.play();\n }\n }\n\n seek(time) {\n if (this.renderer) {\n this.renderer.seek(time);\n }\n }\n\n seekForward(interval = this.options.seekInterval) {\n this.seek(Math.min(this.state.currentTime + interval, this.state.duration));\n }\n\n seekBackward(interval = this.options.seekInterval) {\n this.seek(Math.max(this.state.currentTime - interval, 0));\n }\n\n // Volume controls\n setVolume(volume) {\n const newVolume = Math.max(0, Math.min(1, volume));\n if (this.renderer) {\n this.renderer.setVolume(newVolume);\n }\n this.state.volume = newVolume;\n\n // If volume is increased above 0 and currently muted, unmute\n if (newVolume > 0 && this.state.muted) {\n this.state.muted = false;\n if (this.renderer) {\n this.renderer.setMuted(false);\n }\n this.emit('volumechange');\n }\n \n this.savePlayerPreferences();\n }\n\n getVolume() {\n return this.state.volume;\n }\n\n mute() {\n if (this.renderer) {\n this.renderer.setMuted(true);\n }\n this.state.muted = true;\n this.savePlayerPreferences();\n this.emit('volumechange');\n }\n\n unmute() {\n if (this.renderer) {\n this.renderer.setMuted(false);\n }\n this.state.muted = false;\n this.savePlayerPreferences();\n this.emit('volumechange');\n }\n\n toggleMute() {\n if (this.state.muted) {\n this.unmute();\n } else {\n this.mute();\n }\n }\n\n // Playback speed\n setPlaybackSpeed(speed) {\n const newSpeed = Math.max(0.25, Math.min(2, speed));\n if (this.renderer) {\n this.renderer.setPlaybackSpeed(newSpeed);\n }\n this.state.playbackSpeed = newSpeed;\n this.savePlayerPreferences();\n this.emit('playbackspeedchange', newSpeed);\n }\n\n getPlaybackSpeed() {\n return this.state.playbackSpeed;\n }\n \n // Save player preferences to localStorage\n savePlayerPreferences() {\n this.storage.savePlayerPreferences({\n volume: this.state.volume,\n muted: this.state.muted,\n playbackSpeed: this.state.playbackSpeed\n });\n }\n\n // Fullscreen\n enterFullscreen() {\n const elem = this.container;\n let fullscreenPromise = null;\n\n // Detect iOS/iPadOS to avoid native fullscreen conflicts\n const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || \n (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);\n \n // On iOS/iPadOS, always use pseudo-fullscreen to avoid video element native fullscreen\n if (isIOS) {\n this._enablePseudoFullscreen();\n return;\n }\n\n // Try to use native Fullscreen API on other platforms\n if (elem.requestFullscreen) {\n fullscreenPromise = elem.requestFullscreen();\n } else if (elem.webkitRequestFullscreen) {\n fullscreenPromise = elem.webkitRequestFullscreen();\n } else if (elem.mozRequestFullScreen) {\n fullscreenPromise = elem.mozRequestFullScreen();\n } else if (elem.msRequestFullscreen) {\n fullscreenPromise = elem.msRequestFullscreen();\n }\n\n // Handle promise-based API (modern browsers)\n if (fullscreenPromise && fullscreenPromise.catch) {\n fullscreenPromise.catch((err) => {\n // Fullscreen API failed, use pseudo-fullscreen fallback\n this.log('Fullscreen API failed, using pseudo-fullscreen:', err.message);\n this._enablePseudoFullscreen();\n });\n }\n\n // For browsers without Fullscreen API support, use pseudo-fullscreen\n if (!elem.requestFullscreen && !elem.webkitRequestFullscreen && \n !elem.mozRequestFullScreen && !elem.msRequestFullscreen) {\n this._enablePseudoFullscreen();\n } else {\n // Optimistically set state (will be corrected by fullscreenChangeHandler if it fails)\n this.state.fullscreen = true;\n this.container.classList.add(`${this.options.classPrefix}-fullscreen`);\n this.emit('fullscreenchange', true);\n }\n }\n\n exitFullscreen() {\n // Check if we're in native fullscreen\n const isInNativeFullscreen = !!(\n document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement\n );\n\n if (isInNativeFullscreen) {\n // Exit native fullscreen\n if (document.exitFullscreen) {\n document.exitFullscreen();\n } else if (document.webkitExitFullscreen) {\n document.webkitExitFullscreen();\n } else if (document.mozCancelFullScreen) {\n document.mozCancelFullScreen();\n } else if (document.msExitFullscreen) {\n document.msExitFullscreen();\n }\n } else {\n // We're in pseudo-fullscreen, exit it manually\n this._disablePseudoFullscreen();\n }\n\n this.state.fullscreen = false;\n this.container.classList.remove(`${this.options.classPrefix}-fullscreen`);\n this.emit('fullscreenchange', false);\n }\n\n toggleFullscreen() {\n if (this.state.fullscreen) {\n this.exitFullscreen();\n } else {\n this.enterFullscreen();\n }\n }\n\n // Pseudo-fullscreen fallback for iOS and browsers without Fullscreen API\n _enablePseudoFullscreen() {\n this.state.fullscreen = true;\n this.container.classList.add(`${this.options.classPrefix}-fullscreen`);\n \n // Store current scroll position for restoration later\n this._originalScrollX = window.scrollX || window.pageXOffset;\n this._originalScrollY = window.scrollY || window.pageYOffset;\n \n // Prevent body scrolling while in pseudo-fullscreen\n this._originalBodyOverflow = document.body.style.overflow;\n this._originalBodyPosition = document.body.style.position;\n this._originalBodyWidth = document.body.style.width;\n this._originalBodyHeight = document.body.style.height;\n this._originalHtmlOverflow = document.documentElement.style.overflow;\n \n document.body.style.overflow = 'hidden';\n document.body.style.width = '100%';\n document.body.style.height = '100%';\n document.documentElement.style.overflow = 'hidden';\n \n // On iOS, also lock the viewport and scroll to top\n this._originalViewport = document.querySelector('meta[name=\"viewport\"]')?.getAttribute('content');\n const viewport = document.querySelector('meta[name=\"viewport\"]');\n if (viewport) {\n viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');\n }\n \n // Scroll to top on iOS to prevent positioning issues\n window.scrollTo(0, 0);\n \n this.emit('fullscreenchange', true);\n this.emit('enterfullscreen');\n }\n\n _disablePseudoFullscreen() {\n // Restore body scrolling\n if (this._originalBodyOverflow !== undefined) {\n document.body.style.overflow = this._originalBodyOverflow;\n delete this._originalBodyOverflow;\n }\n if (this._originalBodyPosition !== undefined) {\n document.body.style.position = this._originalBodyPosition;\n delete this._originalBodyPosition;\n }\n if (this._originalBodyWidth !== undefined) {\n document.body.style.width = this._originalBodyWidth;\n delete this._originalBodyWidth;\n }\n if (this._originalBodyHeight !== undefined) {\n document.body.style.height = this._originalBodyHeight;\n delete this._originalBodyHeight;\n }\n if (this._originalHtmlOverflow !== undefined) {\n document.documentElement.style.overflow = this._originalHtmlOverflow;\n delete this._originalHtmlOverflow;\n }\n \n // Restore viewport settings\n if (this._originalViewport !== undefined) {\n const viewport = document.querySelector('meta[name=\"viewport\"]');\n if (viewport) {\n viewport.setAttribute('content', this._originalViewport);\n }\n delete this._originalViewport;\n }\n \n // Restore scroll position\n if (this._originalScrollX !== undefined && this._originalScrollY !== undefined) {\n window.scrollTo(this._originalScrollX, this._originalScrollY);\n delete this._originalScrollX;\n delete this._originalScrollY;\n }\n \n this.emit('exitfullscreen');\n }\n\n // Picture-in-Picture\n enterPiP() {\n if (this.element.requestPictureInPicture) {\n this.element.requestPictureInPicture();\n this.state.pip = true;\n this.emit('pipchange', true);\n }\n }\n\n exitPiP() {\n if (document.pictureInPictureElement) {\n document.exitPictureInPicture();\n this.state.pip = false;\n this.emit('pipchange', false);\n }\n }\n\n togglePiP() {\n if (this.state.pip) {\n this.exitPiP();\n } else {\n this.enterPiP();\n }\n }\n\n // Captions\n enableCaptions() {\n if (this.captionManager) {\n this.captionManager.enable();\n this.state.captionsEnabled = true;\n }\n }\n\n disableCaptions() {\n if (this.captionManager) {\n this.captionManager.disable();\n this.state.captionsEnabled = false;\n }\n }\n\n toggleCaptions() {\n if (this.state.captionsEnabled) {\n this.disableCaptions();\n } else {\n this.enableCaptions();\n }\n }\n\n /**\n * Check if a track file exists\n * @param {string} url - Track file URL\n * @returns {Promise<boolean>} - True if file exists\n */\n async validateTrackExists(url) {\n try {\n const response = await fetch(url, { method: 'HEAD', cache: 'no-cache' });\n return response.ok;\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Strip VTT formatting tags from caption text\n * @param {string} text - Caption text with VTT formatting\n * @returns {string} Plain text without formatting\n */\n stripVTTFormatting(text) {\n if (!text) return '';\n return text\n .replace(/<[^>]+>/g, '') // Remove all HTML/VTT tags\n .replace(/\\n/g, ' ') // Replace newlines with spaces\n .trim()\n .toLowerCase(); // Normalize to lowercase for comparison\n }\n\n /**\n * Find matching caption time based on text content\n * Useful for syncing between videos of different lengths (e.g., with/without audio description)\n * @param {string} targetText - Caption text to search for\n * @param {Array} tracks - Array of caption tracks to search in\n * @returns {number|null} Start time of matching caption, or null if not found\n */\n findMatchingCaptionTime(targetText, tracks) {\n if (!targetText || !tracks || tracks.length === 0) {\n return null;\n }\n\n const normalizedTarget = this.stripVTTFormatting(targetText);\n \n // Search through all caption/subtitle tracks\n for (const trackInfo of tracks) {\n if (trackInfo.kind !== 'captions' && trackInfo.kind !== 'subtitles') {\n continue;\n }\n\n const track = trackInfo.track;\n if (!track || !track.cues) {\n continue;\n }\n\n // Search through all cues in this track\n for (let i = 0; i < track.cues.length; i++) {\n const cue = track.cues[i];\n const cueText = this.stripVTTFormatting(cue.text);\n \n // Check for exact match or very similar match (at least 80% of words match)\n if (cueText === normalizedTarget) {\n return cue.startTime;\n }\n \n // Fuzzy matching: check if most words match\n const targetWords = normalizedTarget.split(/\\s+/).filter(w => w.length > 2);\n const cueWords = cueText.split(/\\s+/).filter(w => w.length > 2);\n \n if (targetWords.length > 0 && cueWords.length > 0) {\n const matchingWords = targetWords.filter(word => cueWords.includes(word));\n const matchRatio = matchingWords.length / targetWords.length;\n \n // If 80% or more words match, consider it a match\n if (matchRatio >= 0.8) {\n return cue.startTime;\n }\n }\n }\n }\n\n return null;\n }\n\n // Audio Description\n async enableAudioDescription() {\n // Check if we have source elements with data-desc-src (even if audioDescriptionSrc is not set)\n const hasSourceElementsWithDesc = this.sourceElements.some(el => el.getAttribute('data-desc-src'));\n const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;\n \n if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {\n console.warn('VidPly: No audio description source, source elements, or tracks provided');\n return;\n }\n\n // Store current playback state\n // Use element.currentTime directly, not state, as state may not be up-to-date\n const currentTime = this.element.currentTime;\n const wasPlaying = this.state.playing;\n const shouldKeepPoster = !wasPlaying && currentTime === 0;\n \n // Try to find the current caption text for synchronization\n // This helps when switching between videos of different lengths\n let currentCaptionText = null;\n if (this.captionManager && this.captionManager.currentTrack) {\n const track = this.captionManager.currentTrack.track;\n if (track && track.activeCues && track.activeCues.length > 0) {\n const activeCue = track.activeCues[0];\n currentCaptionText = this.stripVTTFormatting(activeCue.text);\n }\n }\n \n // Store poster to preserve it during source swap\n // Convert relative paths to absolute URLs to prevent resolution issues\n const posterValue = this.resolvePosterPath(\n this.element.getAttribute('poster') || \n this.element.poster || \n this.options.poster\n );\n\n if (shouldKeepPoster) {\n this.showPosterOverlay();\n }\n\n // Store swapped tracks for transcript reload (declare at function scope)\n let swappedTracksForTranscript = [];\n\n // Switch to audio-described version\n // If we have a source element with audio description attributes, update that instead\n if (this.audioDescriptionSourceElement) {\n const currentSrc = this.element.currentSrc || this.element.src;\n \n // Find the source element that matches the currently active source\n const sourceElements = this.sourceElements;\n let sourceElementToUpdate = null;\n let descSrc = this.audioDescriptionSrc;\n \n for (const sourceEl of sourceElements) {\n const sourceSrc = sourceEl.getAttribute('src');\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\n \n // Check if this source matches the current source (by filename)\n // Match by full path or just filename\n const sourceFilename = sourceSrc ? sourceSrc.split('/').pop() : '';\n const currentFilename = currentSrc ? currentSrc.split('/').pop() : '';\n \n if (currentSrc && (currentSrc === sourceSrc || \n currentSrc.includes(sourceSrc) || \n currentSrc.includes(sourceFilename) ||\n (sourceFilename && currentFilename === sourceFilename))) {\n sourceElementToUpdate = sourceEl;\n if (descSrcAttr) {\n descSrc = descSrcAttr;\n } else if (sourceSrc) {\n // If no data-desc-src, try to construct it from the source\n // But prefer the stored audioDescriptionSrc if available\n descSrc = this.audioDescriptionSrc || descSrc;\n }\n break;\n }\n }\n \n // If we didn't find a match, use the stored source element\n if (!sourceElementToUpdate) {\n sourceElementToUpdate = this.audioDescriptionSourceElement;\n // Ensure we have the correct descSrc from the stored element\n const storedDescSrc = sourceElementToUpdate.getAttribute('data-desc-src');\n if (storedDescSrc) {\n descSrc = storedDescSrc;\n }\n }\n \n // Swap caption tracks to described versions BEFORE loading\n if (this.audioDescriptionCaptionTracks.length > 0) {\n // Swap tracks: validate explicit tracks, but try auto-detected tracks without validation\n // This avoids 404 errors while still allowing auto-detection to work\n const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {\n if (trackInfo.trackElement && trackInfo.describedSrc) {\n // Only validate explicitly defined tracks (to confirm they exist)\n // Auto-detected tracks are used without validation (browser will handle missing files gracefully)\n if (trackInfo.explicit === true) {\n try {\n const exists = await this.validateTrackExists(trackInfo.describedSrc);\n return { trackInfo, exists };\n } catch (error) {\n // Silently handle validation errors\n return { trackInfo, exists: false };\n }\n } else {\n // This shouldn't happen since auto-detection is disabled\n // But if it does, don't validate to avoid 404s\n return { trackInfo, exists: false };\n }\n }\n return { trackInfo, exists: false };\n });\n \n const validationResults = await Promise.all(validationPromises);\n const tracksToSwap = validationResults.filter(result => result.exists);\n \n if (tracksToSwap.length > 0) {\n // Store original track modes before removing tracks\n const trackModes = new Map();\n tracksToSwap.forEach(({ trackInfo }) => {\n const textTrack = trackInfo.trackElement.track;\n if (textTrack) {\n trackModes.set(trackInfo, {\n wasShowing: textTrack.mode === 'showing',\n wasHidden: textTrack.mode === 'hidden'\n });\n } else {\n trackModes.set(trackInfo, {\n wasShowing: false,\n wasHidden: false\n });\n }\n });\n \n // Store all track information before removing\n const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {\n const oldSrc = trackInfo.trackElement.getAttribute('src');\n const parent = trackInfo.trackElement.parentNode;\n const nextSibling = trackInfo.trackElement.nextSibling;\n \n // Store all attributes from the old track\n const attributes = {};\n Array.from(trackInfo.trackElement.attributes).forEach(attr => {\n attributes[attr.name] = attr.value;\n });\n \n return {\n trackInfo,\n oldSrc,\n parent,\n nextSibling,\n attributes\n };\n });\n \n // Remove ALL old tracks first to force browser to clear TextTrack objects\n tracksToReadd.forEach(({ trackInfo }) => {\n trackInfo.trackElement.remove();\n });\n \n // Force browser to process the removal by calling load()\n this.element.load();\n \n // Wait for browser to process the removal, then add new tracks\n // Use await to ensure this completes before continuing\n await new Promise(resolve => {\n setTimeout(() => {\n tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {\n swappedTracksForTranscript.push(trackInfo);\n \n // Create a completely new track element (not a clone) to force browser to create new TextTrack\n const newTrackElement = document.createElement('track');\n newTrackElement.setAttribute('src', trackInfo.describedSrc);\n \n // Copy all attributes except src and data-desc-src\n Object.keys(attributes).forEach(attrName => {\n if (attrName !== 'src' && attrName !== 'data-desc-src') {\n newTrackElement.setAttribute(attrName, attributes[attrName]);\n }\n });\n \n // Insert new track element\n if (nextSibling && nextSibling.parentNode) {\n parent.insertBefore(newTrackElement, nextSibling);\n } else {\n parent.appendChild(newTrackElement);\n }\n \n // Update reference to the new track element\n trackInfo.trackElement = newTrackElement;\n });\n \n this.invalidateTrackCache();\n \n // Wait for loadedmetadata event before accessing new TextTrack objects\n const setupNewTracks = () => {\n // Wait a bit more for browser to fully process the new track elements\n this.setManagedTimeout(() => {\n swappedTracksForTranscript.forEach((trackInfo) => {\n const trackElement = trackInfo.trackElement;\n const newTextTrack = trackElement.track;\n \n if (newTextTrack) {\n // Get original mode from stored map\n const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };\n \n // Set mode to load the new track\n newTextTrack.mode = 'hidden'; // Use hidden to load cues without showing\n \n // Restore original mode after track loads\n // Note: CaptionManager will handle enabling captions separately\n const restoreMode = () => {\n if (modeInfo.wasShowing) {\n // Set to hidden - CaptionManager will set it to showing when it enables\n newTextTrack.mode = 'hidden';\n } else if (modeInfo.wasHidden) {\n newTextTrack.mode = 'hidden';\n } else {\n newTextTrack.mode = 'disabled';\n }\n };\n \n // Wait for track to load\n if (newTextTrack.readyState >= 2) { // LOADED\n restoreMode();\n } else {\n newTextTrack.addEventListener('load', restoreMode, { once: true });\n newTextTrack.addEventListener('error', restoreMode, { once: true });\n }\n }\n });\n }, 300); // Additional wait for browser to process track elements\n };\n \n // Wait for loadedmetadata event which fires when browser processes track elements\n if (this.element.readyState >= 1) { // HAVE_METADATA\n // Already loaded, wait a bit and setup\n setTimeout(setupNewTracks, 200);\n } else {\n this.element.addEventListener('loadedmetadata', setupNewTracks, { once: true });\n // Fallback timeout\n setTimeout(setupNewTracks, 2000);\n }\n \n resolve();\n }, 100);\n }); // Wait 100ms after first load() before adding new tracks\n \n const skippedCount = validationResults.length - tracksToSwap.length;\n }\n }\n \n // Update all source elements that have data-desc-src to their described versions\n // Force browser to pick up changes by removing and re-adding source elements\n // Get source elements (may have been defined in if block above, but get fresh list here)\n const allSourceElements = this.sourceElements;\n const sourcesToUpdate = [];\n \n allSourceElements.forEach((sourceEl) => {\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\n const currentSrc = sourceEl.getAttribute('src');\n \n if (descSrcAttr) {\n const type = sourceEl.getAttribute('type');\n let origSrc = sourceEl.getAttribute('data-orig-src');\n \n // Store current src as data-orig-src if not already set\n if (!origSrc) {\n origSrc = currentSrc;\n }\n \n // Store info for re-adding with described src\n sourcesToUpdate.push({\n src: descSrcAttr, // Use described version\n type: type,\n origSrc: origSrc,\n descSrc: descSrcAttr\n });\n } else {\n // Source element without data-desc-src - keep as-is\n const type = sourceEl.getAttribute('type');\n const src = sourceEl.getAttribute('src');\n sourcesToUpdate.push({\n src: src,\n type: type,\n origSrc: null,\n descSrc: null\n });\n }\n });\n \n // Remove src attribute if present (video with src can't have source elements per HTML spec)\n const hasSrcAttribute = this.element.hasAttribute('src');\n const srcValue = hasSrcAttribute ? this.element.getAttribute('src') : null;\n if (hasSrcAttribute) {\n this.element.removeAttribute('src');\n }\n \n // Remove all source elements\n allSourceElements.forEach(sourceEl => {\n sourceEl.remove();\n });\n \n // Re-add them with updated src attributes (described versions)\n sourcesToUpdate.forEach(sourceInfo => {\n const newSource = document.createElement('source');\n newSource.setAttribute('src', sourceInfo.src);\n if (sourceInfo.type) {\n newSource.setAttribute('type', sourceInfo.type);\n }\n if (sourceInfo.origSrc) {\n newSource.setAttribute('data-orig-src', sourceInfo.origSrc);\n }\n if (sourceInfo.descSrc) {\n newSource.setAttribute('data-desc-src', sourceInfo.descSrc);\n }\n const firstTrack = this.element.querySelector('track');\n if (firstTrack) {\n this.element.insertBefore(newSource, firstTrack);\n } else {\n this.element.appendChild(newSource);\n }\n });\n\n // Ensure cached source references are refreshed after rebuilding the list\n this._sourceElementsDirty = true;\n this._sourceElementsCache = null;\n \n // Preserve poster before reload\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n \n // Force reload by calling load() on the element\n // This should pick up the new src attributes from the re-added source elements\n // and also reload the track elements\n this.element.load();\n \n // Wait for new source to load metadata\n await new Promise((resolve) => {\n const onLoadedMetadata = () => {\n this.element.removeEventListener('loadedmetadata', onLoadedMetadata);\n resolve();\n };\n \n if (this.element.readyState >= 1) {\n // Metadata already loaded\n resolve();\n } else {\n this.element.addEventListener('loadedmetadata', onLoadedMetadata);\n }\n });\n \n // Wait a bit more for tracks to be recognized and loaded after video metadata loads\n await new Promise(resolve => setTimeout(resolve, 300));\n\n // If we need to seek and/or play, wait for enough data to be loaded\n if (currentTime > 0 || wasPlaying) {\n await new Promise((resolve) => {\n const onCanPlay = () => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n };\n \n // Check if already ready\n if (this.element.readyState >= 3) { // HAVE_FUTURE_DATA or better\n resolve();\n } else {\n // Wait for canplay or canplaythrough\n this.element.addEventListener('canplay', onCanPlay, { once: true });\n this.element.addEventListener('canplaythrough', onCanPlay, { once: true });\n \n // Fallback timeout in case events don't fire\n setTimeout(() => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n }, 3000);\n }\n });\n }\n\n // Try to find matching caption in the new track for better synchronization\n let syncTime = currentTime;\n if (currentCaptionText && this.captionManager && this.captionManager.tracks.length > 0) {\n // Wait a bit for tracks to load\n await new Promise(resolve => setTimeout(resolve, 500));\n \n // Find the matching caption in the described video's track\n const matchingTime = this.findMatchingCaptionTime(currentCaptionText, this.captionManager.tracks);\n if (matchingTime !== null) {\n syncTime = matchingTime;\n if (this.options.debug) {\n console.log(`[VidPly] Syncing via caption: ${currentTime}s -> ${syncTime}s`);\n }\n }\n }\n\n // Restore playback position (avoid forcing first frame if still at start)\n if (syncTime > 0) {\n this.seek(syncTime);\n // Wait a bit for seek to complete\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n if (wasPlaying) {\n await this.play();\n // Hide poster when playing - use setTimeout to ensure play event has fired\n this.setManagedTimeout(() => {\n this.hidePosterOverlay();\n }, 100);\n } else {\n // Explicitly pause the video if it wasn't playing\n // This ensures it's in a clean paused state after load()\n this.pause();\n if (!shouldKeepPoster) {\n this.hidePosterOverlay();\n }\n }\n\n // Update state and emit event\n if (!this._audioDescriptionDesiredState) {\n return;\n }\n this.state.audioDescriptionEnabled = true;\n this.emit('audiodescriptionenabled');\n } else {\n // Fallback to updating element src directly\n // Swap caption tracks to described versions BEFORE loading\n if (this.audioDescriptionCaptionTracks.length > 0) {\n // Swap tracks: validate explicit tracks, but try auto-detected tracks without validation\n const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {\n if (trackInfo.trackElement && trackInfo.describedSrc) {\n // Only validate explicitly defined tracks\n // Auto-detected tracks are used without validation (no 404s)\n if (trackInfo.explicit === true) {\n try {\n const exists = await this.validateTrackExists(trackInfo.describedSrc);\n return { trackInfo, exists };\n } catch (error) {\n return { trackInfo, exists: false };\n }\n } else {\n // This shouldn't happen since auto-detection is disabled\n return { trackInfo, exists: false };\n }\n }\n return { trackInfo, exists: false };\n });\n \n const validationResults = await Promise.all(validationPromises);\n const tracksToSwap = validationResults.filter(result => result.exists);\n \n if (tracksToSwap.length > 0) {\n // Store original track modes before removing tracks\n const trackModes = new Map();\n tracksToSwap.forEach(({ trackInfo }) => {\n const textTrack = trackInfo.trackElement.track;\n if (textTrack) {\n trackModes.set(trackInfo, {\n wasShowing: textTrack.mode === 'showing',\n wasHidden: textTrack.mode === 'hidden'\n });\n } else {\n trackModes.set(trackInfo, {\n wasShowing: false,\n wasHidden: false\n });\n }\n });\n \n // Store all track information before removing\n const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {\n const oldSrc = trackInfo.trackElement.getAttribute('src');\n const parent = trackInfo.trackElement.parentNode;\n const nextSibling = trackInfo.trackElement.nextSibling;\n \n // Store all attributes from the old track\n const attributes = {};\n Array.from(trackInfo.trackElement.attributes).forEach(attr => {\n attributes[attr.name] = attr.value;\n });\n \n return {\n trackInfo,\n oldSrc,\n parent,\n nextSibling,\n attributes\n };\n });\n \n // Remove ALL old tracks first to force browser to clear TextTrack objects\n tracksToReadd.forEach(({ trackInfo }) => {\n trackInfo.trackElement.remove();\n });\n \n // Force browser to process the removal by calling load()\n this.element.load();\n \n // Wait for browser to process the removal, then add new tracks\n setTimeout(() => {\n tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {\n swappedTracksForTranscript.push(trackInfo);\n \n // Create a completely new track element (not a clone) to force browser to create new TextTrack\n const newTrackElement = document.createElement('track');\n newTrackElement.setAttribute('src', trackInfo.describedSrc);\n \n // Copy all attributes except src and data-desc-src\n Object.keys(attributes).forEach(attrName => {\n if (attrName !== 'src' && attrName !== 'data-desc-src') {\n newTrackElement.setAttribute(attrName, attributes[attrName]);\n }\n });\n \n // Insert new track element at the beginning (before any flow content) for HTML5 validity\n const firstChild = parent.firstChild;\n if (firstChild && firstChild.nodeType === Node.ELEMENT_NODE && firstChild.tagName !== 'TRACK') {\n parent.insertBefore(newTrackElement, firstChild);\n } else if (nextSibling && nextSibling.parentNode) {\n parent.insertBefore(newTrackElement, nextSibling);\n } else {\n parent.appendChild(newTrackElement);\n }\n \n // Update reference to the new track element\n trackInfo.trackElement = newTrackElement;\n });\n \n // After all new tracks are added, force browser to reload media element again\n this.element.load();\n \n // Wait for loadedmetadata event before accessing new TextTrack objects\n const setupNewTracks = () => {\n // Wait a bit more for browser to fully process the new track elements\n setTimeout(() => {\n swappedTracksForTranscript.forEach((trackInfo) => {\n const trackElement = trackInfo.trackElement;\n const newTextTrack = trackElement.track;\n \n if (newTextTrack) {\n // Get original mode from stored map\n const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };\n \n // Set mode to load the new track\n newTextTrack.mode = 'hidden'; // Use hidden to load cues without showing\n \n // Restore original mode after track loads\n const restoreMode = () => {\n if (modeInfo.wasShowing) {\n // Set to hidden - CaptionManager will set it to showing when it enables\n newTextTrack.mode = 'hidden';\n } else if (modeInfo.wasHidden) {\n newTextTrack.mode = 'hidden';\n } else {\n newTextTrack.mode = 'disabled';\n }\n };\n \n // Wait for track to load\n if (newTextTrack.readyState >= 2) { // LOADED\n restoreMode();\n } else {\n newTextTrack.addEventListener('load', restoreMode, { once: true });\n newTextTrack.addEventListener('error', restoreMode, { once: true });\n }\n }\n });\n }, 300); // Additional wait for browser to process track elements\n };\n \n // Wait for loadedmetadata event which fires when browser processes track elements\n if (this.element.readyState >= 1) { // HAVE_METADATA\n // Already loaded, wait a bit and setup\n setTimeout(setupNewTracks, 200);\n } else {\n this.element.addEventListener('loadedmetadata', setupNewTracks, { once: true });\n // Fallback timeout\n setTimeout(setupNewTracks, 2000);\n }\n }, 100); // Wait 100ms after first load() before adding new tracks\n }\n }\n \n // Check if we have source elements with data-desc-src (fallback method)\n const fallbackSourceElements = this.sourceElements;\n const hasSourceElementsWithDesc = fallbackSourceElements.some(el => el.getAttribute('data-desc-src'));\n \n if (hasSourceElementsWithDesc) {\n const fallbackSourcesToUpdate = [];\n \n fallbackSourceElements.forEach((sourceEl) => {\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\n const currentSrc = sourceEl.getAttribute('src');\n \n if (descSrcAttr) {\n const type = sourceEl.getAttribute('type');\n let origSrc = sourceEl.getAttribute('data-orig-src');\n \n if (!origSrc) {\n origSrc = currentSrc;\n }\n \n fallbackSourcesToUpdate.push({\n src: descSrcAttr,\n type: type,\n origSrc: origSrc,\n descSrc: descSrcAttr\n });\n } else {\n const type = sourceEl.getAttribute('type');\n const src = sourceEl.getAttribute('src');\n fallbackSourcesToUpdate.push({\n src: src,\n type: type,\n origSrc: null,\n descSrc: null\n });\n }\n });\n \n // Remove all source elements\n fallbackSourceElements.forEach(sourceEl => {\n sourceEl.remove();\n });\n \n // Re-add them with updated src attributes\n fallbackSourcesToUpdate.forEach(sourceInfo => {\n const newSource = document.createElement('source');\n newSource.setAttribute('src', sourceInfo.src);\n if (sourceInfo.type) {\n newSource.setAttribute('type', sourceInfo.type);\n }\n if (sourceInfo.origSrc) {\n newSource.setAttribute('data-orig-src', sourceInfo.origSrc);\n }\n if (sourceInfo.descSrc) {\n newSource.setAttribute('data-desc-src', sourceInfo.descSrc);\n }\n this.element.appendChild(newSource);\n });\n \n // Preserve poster before reload\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n \n // Force reload\n this.element.load();\n this.invalidateTrackCache();\n } else {\n // Fallback to updating element src directly (for videos without source elements)\n // Preserve poster before changing src\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n this.element.src = this.audioDescriptionSrc;\n }\n }\n\n // Wait for new source to load metadata\n await new Promise((resolve) => {\n const onLoadedMetadata = () => {\n this.element.removeEventListener('loadedmetadata', onLoadedMetadata);\n resolve();\n };\n \n if (this.element.readyState >= 1) {\n // Metadata already loaded\n resolve();\n } else {\n this.element.addEventListener('loadedmetadata', onLoadedMetadata);\n }\n });\n\n // If we need to seek and/or play, wait for enough data to be loaded\n if (currentTime > 0 || wasPlaying) {\n await new Promise((resolve) => {\n const onCanPlay = () => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n };\n \n // Check if already ready\n if (this.element.readyState >= 3) { // HAVE_FUTURE_DATA or better\n resolve();\n } else {\n // Wait for canplay or canplaythrough\n this.element.addEventListener('canplay', onCanPlay, { once: true });\n this.element.addEventListener('canplaythrough', onCanPlay, { once: true });\n \n // Fallback timeout in case events don't fire\n setTimeout(() => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n }, 3000);\n }\n });\n }\n\n // Hide poster if video hasn't started yet (poster should hide when we seek or play)\n if (this.element.tagName === 'VIDEO' && currentTime === 0 && !wasPlaying) {\n // Force poster to hide by doing a minimal seek or loading first frame\n // Setting readyState check or seeking to 0.001 seconds will hide the poster\n if (this.element.readyState >= 1) { // HAVE_METADATA\n // Seek to a tiny fraction to trigger poster hiding without actually moving\n this.element.currentTime = 0.001;\n // Then seek back to 0 after a brief moment to ensure poster stays hidden\n this.setManagedTimeout(() => {\n this.element.currentTime = 0;\n }, 10);\n }\n }\n\n // Try to find matching caption in the new track for better synchronization\n let syncTime = currentTime;\n if (currentCaptionText && this.captionManager && this.captionManager.tracks.length > 0) {\n // Wait a bit for tracks to load\n await new Promise(resolve => setTimeout(resolve, 500));\n \n // Find the matching caption in the described video's track\n const matchingTime = this.findMatchingCaptionTime(currentCaptionText, this.captionManager.tracks);\n if (matchingTime !== null) {\n syncTime = matchingTime;\n if (this.options.debug) {\n console.log(`[VidPly] Syncing via caption: ${currentTime}s -> ${syncTime}s`);\n }\n }\n }\n\n // Restore playback position (avoid forcing first frame if still at start)\n if (syncTime > 0) {\n this.seek(syncTime);\n // Wait a bit for seek to complete\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n if (wasPlaying) {\n await this.play();\n // Hide poster when playing - use setTimeout to ensure play event has fired\n this.setManagedTimeout(() => {\n this.hidePosterOverlay();\n }, 100);\n } else {\n // Explicitly pause the video if it wasn't playing\n // This ensures it's in a clean paused state after load()\n this.pause();\n if (!shouldKeepPoster) {\n this.hidePosterOverlay();\n }\n }\n\n // Reload CaptionManager tracks if tracks were swapped (so it has fresh references)\n if (swappedTracksForTranscript.length > 0 && this.captionManager) {\n // Store if captions were enabled and which track\n const wasCaptionsEnabled = this.state.captionsEnabled;\n let currentTrackInfo = null;\n if (this.captionManager.currentTrack) {\n const currentTrackIndex = this.captionManager.tracks.findIndex(t => t.track === this.captionManager.currentTrack.track);\n if (currentTrackIndex >= 0) {\n currentTrackInfo = {\n language: this.captionManager.tracks[currentTrackIndex].language,\n kind: this.captionManager.tracks[currentTrackIndex].kind\n };\n }\n }\n \n // Wait for new tracks to be available and loaded, then reload\n // Use a longer timeout and wait for track load events\n const reloadTracks = () => {\n // Reload tracks to get fresh references to new TextTrack objects\n this.captionManager.tracks = [];\n this.captionManager.loadTracks();\n \n // Re-enable captions if they were enabled before\n if (wasCaptionsEnabled && currentTrackInfo && this.captionManager.tracks.length > 0) {\n // Find the track by language and kind to match the swapped track\n const matchingTrackIndex = this.captionManager.tracks.findIndex(t => \n t.language === currentTrackInfo.language && t.kind === currentTrackInfo.kind\n );\n \n if (matchingTrackIndex >= 0) {\n const trackToEnable = this.captionManager.tracks[matchingTrackIndex];\n // Wait for track to load its cues before enabling\n if (trackToEnable.track.readyState >= 2) {\n // Track is already loaded\n this.captionManager.enable(matchingTrackIndex);\n } else {\n // Wait for track to load\n const onTrackLoad = () => {\n trackToEnable.track.removeEventListener('load', onTrackLoad);\n trackToEnable.track.removeEventListener('error', onTrackLoad);\n if (this.captionManager && this.captionManager.tracks.includes(trackToEnable)) {\n this.captionManager.enable(matchingTrackIndex);\n }\n };\n trackToEnable.track.addEventListener('load', onTrackLoad, { once: true });\n trackToEnable.track.addEventListener('error', onTrackLoad, { once: true });\n // Set mode to 'hidden' to trigger loading\n trackToEnable.track.mode = 'hidden';\n // Fallback timeout\n setTimeout(() => {\n if (this.captionManager && this.captionManager.tracks.includes(trackToEnable)) {\n this.captionManager.enable(matchingTrackIndex);\n }\n }, 1000);\n }\n } else if (this.captionManager.tracks.length > 0) {\n // Fallback: enable first track\n const firstTrack = this.captionManager.tracks[0];\n if (firstTrack.track.readyState >= 2) {\n this.captionManager.enable(0);\n } else {\n const onTrackLoad = () => {\n firstTrack.track.removeEventListener('load', onTrackLoad);\n firstTrack.track.removeEventListener('error', onTrackLoad);\n if (this.captionManager && this.captionManager.tracks.includes(firstTrack)) {\n this.captionManager.enable(0);\n }\n };\n firstTrack.track.addEventListener('load', onTrackLoad, { once: true });\n firstTrack.track.addEventListener('error', onTrackLoad, { once: true });\n firstTrack.track.mode = 'hidden';\n setTimeout(() => {\n if (this.captionManager && this.captionManager.tracks.includes(firstTrack)) {\n this.captionManager.enable(0);\n }\n }, 1000);\n }\n }\n }\n };\n \n // Wait for tracks to be processed by the browser\n setTimeout(reloadTracks, 600);\n }\n\n // Reload transcript if visible (after video metadata loaded, tracks should be available)\n // Reload regardless of whether caption tracks were swapped, in case tracks changed\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n // Wait for tracks to load after source swap\n // If tracks were swapped, wait for them to load; otherwise wait a bit for any track changes\n const swappedTracks = typeof swappedTracksForTranscript !== 'undefined' ? swappedTracksForTranscript : [];\n \n if (swappedTracks.length > 0) {\n // Wait for swapped tracks to load their new cues\n // Since we re-added track elements and called load(), wait for loadedmetadata event\n // which is when the browser processes track elements\n const onMetadataLoaded = () => {\n // Get fresh track references from the video element's textTracks collection\n // This ensures we get the actual textTrack objects that the browser created\n // Invalidate cache first to get fresh tracks after swap\n this.invalidateTrackCache();\n const allTextTracks = this.textTracks;\n \n // Find the tracks that match our swapped tracks by language and kind\n // Match by checking the track element's src attribute\n const freshTracks = swappedTracks.map((trackInfo) => {\n const trackEl = trackInfo.trackElement;\n const expectedSrc = trackEl.getAttribute('src');\n const srclang = trackEl.getAttribute('srclang');\n const kind = trackEl.getAttribute('kind');\n \n // Find matching track in textTracks collection\n // First try to match by the track element reference\n let foundTrack = allTextTracks.find(track => trackEl.track === track);\n \n // If not found, try matching by language and kind, but verify src\n if (!foundTrack) {\n foundTrack = allTextTracks.find(track => {\n if (track.language === srclang && \n (track.kind === kind || (kind === 'captions' && track.kind === 'subtitles'))) {\n // Verify the src matches\n const trackElementForTrack = this.findTrackElement(track);\n if (trackElementForTrack) {\n const actualSrc = trackElementForTrack.getAttribute('src');\n if (actualSrc === expectedSrc) {\n return true;\n }\n }\n }\n return false;\n });\n }\n \n // Verify the track element's src matches what we expect\n if (foundTrack) {\n const trackElement = this.findTrackElement(foundTrack);\n if (trackElement && trackElement.getAttribute('src') !== expectedSrc) {\n return null;\n }\n }\n \n return foundTrack;\n }).filter(Boolean);\n \n if (freshTracks.length === 0) {\n // Fallback: just reload after delay - transcript manager will find tracks itself\n this.setManagedTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n this.transcriptManager.loadTranscriptData();\n }\n }, 1000);\n return;\n }\n \n // Ensure tracks are in hidden mode to load cues for transcript\n freshTracks.forEach(track => {\n if (track.mode === 'disabled') {\n track.mode = 'hidden';\n }\n });\n \n let loadedCount = 0;\n const checkLoaded = () => {\n loadedCount++;\n if (loadedCount >= freshTracks.length) {\n // Give a bit more time for cues to be fully parsed\n // Also ensure we're getting the latest TextTrack references\n this.setManagedTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n // Force transcript manager to get fresh track references\n // Clear any cached track references by forcing a fresh read\n // The transcript manager will find tracks from this.element.textTracks\n // which should now have the new TextTrack objects with the described captions\n \n // Verify the tracks have the correct src before reloading transcript\n this.invalidateTrackCache();\n const allTextTracks = this.textTracks;\n const swappedTrackSrcs = swappedTracks.map(t => t.describedSrc);\n const hasCorrectTracks = freshTracks.some(track => {\n const trackEl = this.findTrackElement(track);\n return trackEl && swappedTrackSrcs.includes(trackEl.getAttribute('src'));\n });\n \n if (hasCorrectTracks || freshTracks.length > 0) {\n this.transcriptManager.loadTranscriptData();\n }\n }\n }, 800); // Increased wait time to ensure cues are fully loaded\n }\n };\n \n freshTracks.forEach(track => {\n // Ensure track is in hidden mode to load cues (required for transcript)\n if (track.mode === 'disabled') {\n track.mode = 'hidden';\n }\n \n // Check if track has cues loaded\n // Verify the track element's src matches the expected described src\n const trackElementForTrack = this.findTrackElement(track);\n const actualSrc = trackElementForTrack ? trackElementForTrack.getAttribute('src') : null;\n \n // Find the expected src from swappedTracks\n const expectedTrackInfo = swappedTracks.find(t => {\n const tEl = t.trackElement;\n return tEl && (tEl.track === track || \n (tEl.getAttribute('srclang') === track.language && \n tEl.getAttribute('kind') === track.kind));\n });\n const expectedSrc = expectedTrackInfo ? expectedTrackInfo.describedSrc : null;\n \n // Only proceed if the src matches (or we can't verify)\n if (expectedSrc && actualSrc && actualSrc !== expectedSrc) {\n // Wrong track, skip it\n checkLoaded(); // Count it as loaded to not block\n return;\n }\n \n if (track.readyState >= 2 && track.cues && track.cues.length > 0) { // LOADED with cues\n // Track already loaded with cues\n checkLoaded();\n } else {\n // Force track to load by setting mode\n if (track.mode === 'disabled') {\n track.mode = 'hidden';\n }\n \n // Wait for track to load\n const onTrackLoad = () => {\n // Wait a bit for cues to be fully parsed\n this.setManagedTimeout(checkLoaded, 300);\n };\n \n if (track.readyState >= 2) {\n // Already loaded, but might not have cues yet\n // Wait a bit and check again\n this.setManagedTimeout(() => {\n if (track.cues && track.cues.length > 0) {\n checkLoaded();\n } else {\n // Still no cues, wait for load event\n track.addEventListener('load', onTrackLoad, { once: true });\n }\n }, 100);\n } else {\n track.addEventListener('load', onTrackLoad, { once: true });\n track.addEventListener('error', () => {\n // Even on error, try to reload transcript\n checkLoaded();\n }, { once: true });\n }\n }\n });\n };\n \n // Wait for loadedmetadata event which fires when browser processes track elements\n // Also wait for the tracks to be fully processed after the second load()\n const waitForTracks = () => {\n // Wait a bit more to ensure new TextTrack objects are created\n this.setManagedTimeout(() => {\n if (this.element.readyState >= 1) { // HAVE_METADATA\n onMetadataLoaded();\n } else {\n this.element.addEventListener('loadedmetadata', onMetadataLoaded, { once: true });\n // Fallback timeout\n this.setManagedTimeout(onMetadataLoaded, 2000);\n }\n }, 500); // Wait 500ms after second load() for tracks to be processed\n };\n \n waitForTracks();\n \n // Fallback timeout - longer to ensure tracks are loaded\n setTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n this.transcriptManager.loadTranscriptData();\n }\n }, 5000);\n } else {\n // No tracks swapped, just wait a bit and reload\n setTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n this.transcriptManager.loadTranscriptData();\n }\n }, 800);\n }\n }\n\n if (!shouldKeepPoster) {\n this.hidePosterOverlay();\n }\n\n if (!this._audioDescriptionDesiredState) {\n return;\n }\n\n this.state.audioDescriptionEnabled = true;\n this.emit('audiodescriptionenabled');\n }\n\n async disableAudioDescription() {\n if (!this.originalSrc) {\n return;\n }\n\n // Store current playback state\n // Use element.currentTime directly, not state, as state may not be up-to-date\n const currentTime = this.element.currentTime;\n const wasPlaying = this.state.playing;\n \n // Try to find the current caption text for synchronization\n // This helps when switching between videos of different lengths\n let currentCaptionText = null;\n if (this.captionManager && this.captionManager.currentTrack) {\n const track = this.captionManager.currentTrack.track;\n if (track && track.activeCues && track.activeCues.length > 0) {\n const activeCue = track.activeCues[0];\n currentCaptionText = this.stripVTTFormatting(activeCue.text);\n }\n }\n \n // Store poster to preserve it during source swap\n // Convert relative paths to absolute URLs to prevent resolution issues\n const posterValue = this.resolvePosterPath(\n this.element.getAttribute('poster') || \n this.element.poster || \n this.options.poster\n );\n\n // Swap caption/chapter tracks back to original versions BEFORE loading\n // Store swapped tracks for transcript reload\n let swappedTracksForTranscript = [];\n if (this.audioDescriptionCaptionTracks.length > 0) {\n // Store track information before removing\n const tracksToRestore = this.audioDescriptionCaptionTracks.map((trackInfo) => {\n const trackElement = trackInfo.trackElement;\n if (!trackElement || !trackElement.parentNode) {\n return null;\n }\n \n const parent = trackElement.parentNode;\n const nextSibling = trackElement.nextSibling;\n \n // Store all attributes from the current track\n const attributes = {};\n Array.from(trackElement.attributes).forEach(attr => {\n attributes[attr.name] = attr.value;\n });\n \n return {\n trackInfo,\n parent,\n nextSibling,\n attributes\n };\n }).filter(Boolean);\n \n // Remove all current track elements\n tracksToRestore.forEach(({ trackInfo }) => {\n if (trackInfo.trackElement && trackInfo.trackElement.parentNode) {\n trackInfo.trackElement.remove();\n }\n });\n \n // Force browser to process the removal\n this.element.load();\n \n // Wait for browser to process the removal, then add original tracks back\n // Use await instead of setTimeout to ensure this completes before continuing\n await new Promise(resolve => {\n setTimeout(() => {\n tracksToRestore.forEach(({ trackInfo, parent, nextSibling, attributes }) => {\n swappedTracksForTranscript.push(trackInfo);\n \n // Create a new track element with the original src\n const newTrackElement = document.createElement('track');\n newTrackElement.setAttribute('src', trackInfo.originalTrackSrc);\n \n // Copy all attributes except src and data-desc-src\n Object.keys(attributes).forEach(attrName => {\n if (attrName !== 'src' && attrName !== 'data-desc-src') {\n newTrackElement.setAttribute(attrName, attributes[attrName]);\n }\n });\n \n // Keep data-desc-src for future swaps\n if (trackInfo.describedSrc) {\n newTrackElement.setAttribute('data-desc-src', trackInfo.describedSrc);\n }\n \n // Insert new track element\n if (nextSibling && nextSibling.parentNode) {\n parent.insertBefore(newTrackElement, nextSibling);\n } else {\n parent.appendChild(newTrackElement);\n }\n \n // Update reference to the new track element\n trackInfo.trackElement = newTrackElement;\n });\n \n this.invalidateTrackCache();\n resolve();\n }, 100);\n });\n }\n \n // Swap source elements back to original versions\n // Check if we have source elements with data-orig-src\n const allSourceElements = this.sourceElements;\n const hasSourceElementsToSwap = allSourceElements.some(el => el.getAttribute('data-orig-src'));\n \n if (hasSourceElementsToSwap) {\n const sourcesToRestore = [];\n \n allSourceElements.forEach((sourceEl) => {\n const origSrcAttr = sourceEl.getAttribute('data-orig-src');\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\n \n if (origSrcAttr) {\n // Swap back to original src\n const type = sourceEl.getAttribute('type');\n sourcesToRestore.push({\n src: origSrcAttr, // Use original version\n type: type,\n origSrc: origSrcAttr,\n descSrc: descSrcAttr // Keep data-desc-src for future swaps\n });\n } else {\n // Keep as-is (no data-orig-src means it wasn't swapped)\n const type = sourceEl.getAttribute('type');\n const src = sourceEl.getAttribute('src');\n sourcesToRestore.push({\n src: src,\n type: type,\n origSrc: null,\n descSrc: descSrcAttr\n });\n }\n });\n \n // Remove src attribute if present (video with src can't have source elements per HTML spec)\n const hasSrcAttribute = this.element.hasAttribute('src');\n const srcValue = hasSrcAttribute ? this.element.getAttribute('src') : null;\n if (hasSrcAttribute) {\n this.element.removeAttribute('src');\n }\n \n // Remove all source elements\n allSourceElements.forEach(sourceEl => {\n sourceEl.remove();\n });\n \n // Re-add them with original src attributes\n sourcesToRestore.forEach(sourceInfo => {\n const newSource = document.createElement('source');\n newSource.setAttribute('src', sourceInfo.src);\n if (sourceInfo.type) {\n newSource.setAttribute('type', sourceInfo.type);\n }\n if (sourceInfo.origSrc) {\n newSource.setAttribute('data-orig-src', sourceInfo.origSrc);\n }\n if (sourceInfo.descSrc) {\n newSource.setAttribute('data-desc-src', sourceInfo.descSrc);\n }\n const firstTrack = this.element.querySelector('track');\n if (firstTrack) {\n this.element.insertBefore(newSource, firstTrack);\n } else {\n this.element.appendChild(newSource);\n }\n });\n\n // Ensure cached source references are refreshed after rebuilding the list\n this._sourceElementsDirty = true;\n this._sourceElementsCache = null;\n \n // Preserve poster before reload\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n \n // Force reload\n this.element.load();\n } else {\n // Fallback to updating element src directly (for videos without source elements)\n // Preserve poster before changing src\n if (posterValue && this.element.tagName === 'VIDEO') {\n this.element.poster = posterValue;\n }\n const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;\n this.element.src = originalSrcToUse;\n this.element.load();\n }\n\n // Wait for new source to load metadata\n await new Promise((resolve) => {\n const onLoadedMetadata = () => {\n this.element.removeEventListener('loadedmetadata', onLoadedMetadata);\n resolve();\n };\n \n if (this.element.readyState >= 1) {\n // Metadata already loaded\n resolve();\n } else {\n this.element.addEventListener('loadedmetadata', onLoadedMetadata);\n }\n });\n\n // If we need to seek and/or play, wait for enough data to be loaded\n if (currentTime > 0 || wasPlaying) {\n await new Promise((resolve) => {\n const onCanPlay = () => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n };\n \n // Check if already ready\n if (this.element.readyState >= 3) { // HAVE_FUTURE_DATA or better\n resolve();\n } else {\n // Wait for canplay or canplaythrough\n this.element.addEventListener('canplay', onCanPlay, { once: true });\n this.element.addEventListener('canplaythrough', onCanPlay, { once: true });\n \n // Fallback timeout in case events don't fire\n setTimeout(() => {\n this.element.removeEventListener('canplay', onCanPlay);\n this.element.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n }, 3000);\n }\n });\n }\n\n // Try to find matching caption in the new track for better synchronization\n let syncTime = currentTime;\n if (currentCaptionText && this.captionManager && this.captionManager.tracks.length > 0) {\n // Wait a bit for tracks to load\n await new Promise(resolve => setTimeout(resolve, 500));\n \n // Find the matching caption in the regular video's track\n const matchingTime = this.findMatchingCaptionTime(currentCaptionText, this.captionManager.tracks);\n if (matchingTime !== null) {\n syncTime = matchingTime;\n if (this.options.debug) {\n console.log(`[VidPly] Syncing via caption: ${currentTime}s -> ${syncTime}s`);\n }\n }\n }\n\n if (syncTime > 0) {\n this.seek(syncTime);\n // Wait a bit for seek to complete\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n if (wasPlaying) {\n await this.play();\n this.hidePosterOverlay();\n } else {\n // Explicitly pause the video if it wasn't playing\n // This ensures it's in a clean paused state after load()\n this.pause();\n if (!wasPlaying && syncTime === 0) {\n this.showPosterOverlay();\n } else {\n this.hidePosterOverlay();\n }\n }\n\n // Reload CaptionManager tracks if tracks were swapped (so it has fresh references)\n if (swappedTracksForTranscript.length > 0 && this.captionManager) {\n // Store if captions were enabled and which track\n const wasCaptionsEnabled = this.state.captionsEnabled;\n let currentTrackInfo = null;\n if (this.captionManager.currentTrack) {\n const currentTrackIndex = this.captionManager.tracks.findIndex(t => t.track === this.captionManager.currentTrack.track);\n if (currentTrackIndex >= 0) {\n currentTrackInfo = {\n language: this.captionManager.tracks[currentTrackIndex].language,\n kind: this.captionManager.tracks[currentTrackIndex].kind\n };\n }\n }\n \n // Wait for tracks to be processed by the browser\n const reloadTracks = () => {\n // Reload tracks to get fresh references to new TextTrack objects\n this.captionManager.tracks = [];\n this.captionManager.loadTracks();\n \n // Re-enable captions if they were enabled before\n if (wasCaptionsEnabled && currentTrackInfo && this.captionManager.tracks.length > 0) {\n // Find the track by language and kind to match the swapped track\n const matchingTrackIndex = this.captionManager.tracks.findIndex(t => \n t.language === currentTrackInfo.language && t.kind === currentTrackInfo.kind\n );\n \n if (matchingTrackIndex >= 0) {\n const trackToEnable = this.captionManager.tracks[matchingTrackIndex];\n // Wait for track to load its cues before enabling\n if (trackToEnable.track.readyState >= 2) {\n // Track is already loaded\n this.captionManager.enable(matchingTrackIndex);\n } else {\n // Wait for track to load\n const onTrackLoad = () => {\n trackToEnable.track.removeEventListener('load', onTrackLoad);\n trackToEnable.track.removeEventListener('error', onTrackLoad);\n if (this.captionManager && this.captionManager.tracks.includes(trackToEnable)) {\n this.captionManager.enable(matchingTrackIndex);\n }\n };\n trackToEnable.track.addEventListener('load', onTrackLoad, { once: true });\n trackToEnable.track.addEventListener('error', onTrackLoad, { once: true });\n // Set mode to 'hidden' to trigger loading\n trackToEnable.track.mode = 'hidden';\n // Fallback timeout\n setTimeout(() => {\n if (this.captionManager && this.captionManager.tracks.includes(trackToEnable)) {\n this.captionManager.enable(matchingTrackIndex);\n }\n }, 1000);\n }\n } else if (this.captionManager.tracks.length > 0) {\n // Fallback: enable first track\n const firstTrack = this.captionManager.tracks[0];\n if (firstTrack.track.readyState >= 2) {\n this.captionManager.enable(0);\n } else {\n const onTrackLoad = () => {\n firstTrack.track.removeEventListener('load', onTrackLoad);\n firstTrack.track.removeEventListener('error', onTrackLoad);\n if (this.captionManager && this.captionManager.tracks.includes(firstTrack)) {\n this.captionManager.enable(0);\n }\n };\n firstTrack.track.addEventListener('load', onTrackLoad, { once: true });\n firstTrack.track.addEventListener('error', onTrackLoad, { once: true });\n firstTrack.track.mode = 'hidden';\n setTimeout(() => {\n if (this.captionManager && this.captionManager.tracks.includes(firstTrack)) {\n this.captionManager.enable(0);\n }\n }, 1000);\n }\n }\n }\n };\n \n // Wait for tracks to be processed by the browser\n setTimeout(reloadTracks, 600);\n }\n\n // Reload transcript if visible (after video metadata loaded, tracks should be available)\n // Reload regardless of whether caption tracks were swapped, in case tracks changed\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n // Wait for tracks to load after source swap\n this.setManagedTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {\n this.transcriptManager.loadTranscriptData();\n }\n }, 500);\n }\n\n if (this._audioDescriptionDesiredState) {\n return;\n }\n\n this.state.audioDescriptionEnabled = false;\n this.emit('audiodescriptiondisabled');\n }\n\n async toggleAudioDescription() {\n // Check if we have description tracks or audio-described video\n const descriptionTrack = this.findTextTrack('descriptions');\n \n // Check if we have audio-described video source (either from options or source elements with data-desc-src)\n const hasAudioDescriptionSrc = this.audioDescriptionSrc || \n this.sourceElements.some(el => el.getAttribute('data-desc-src'));\n \n if (descriptionTrack && hasAudioDescriptionSrc) {\n // We have both: toggle description track AND swap caption tracks/sources\n if (this.state.audioDescriptionEnabled) {\n this._audioDescriptionDesiredState = false;\n // Disable: toggle description track off and swap captions/sources back\n descriptionTrack.mode = 'hidden';\n await this.disableAudioDescription();\n } else {\n this._audioDescriptionDesiredState = true;\n // Enable: swap caption tracks/sources and toggle description track on\n await this.enableAudioDescription();\n // Wait for tracks to be ready after source swap, then enable description track\n // Use a longer timeout to ensure tracks are loaded after source swap\n const enableDescriptionTrack = () => {\n this.invalidateTrackCache();\n const descTrack = this.findTextTrack('descriptions');\n if (descTrack) {\n // Set to 'hidden' first if it's in 'disabled' mode, then to 'showing'\n if (descTrack.mode === 'disabled') {\n descTrack.mode = 'hidden';\n // Use setTimeout to ensure the browser processes the mode change\n this.setManagedTimeout(() => {\n descTrack.mode = 'showing';\n }, 50);\n } else {\n descTrack.mode = 'showing';\n }\n } else if (this.element.readyState < 2) {\n // Tracks not ready yet, wait a bit more\n this.setManagedTimeout(enableDescriptionTrack, 100);\n }\n };\n // Wait for metadata to load first\n if (this.element.readyState >= 1) {\n this.setManagedTimeout(enableDescriptionTrack, 200);\n } else {\n this.element.addEventListener('loadedmetadata', () => {\n this.setManagedTimeout(enableDescriptionTrack, 200);\n }, { once: true });\n }\n }\n } else if (descriptionTrack) {\n // Only description track, no audio-described video source to swap\n // Toggle description track\n if (descriptionTrack.mode === 'showing') {\n this._audioDescriptionDesiredState = false;\n descriptionTrack.mode = 'hidden';\n this.state.audioDescriptionEnabled = false;\n this.emit('audiodescriptiondisabled');\n } else {\n this._audioDescriptionDesiredState = true;\n descriptionTrack.mode = 'showing';\n this.state.audioDescriptionEnabled = true;\n this.emit('audiodescriptionenabled');\n }\n } else if (hasAudioDescriptionSrc) {\n // Use audio-described video source (no description track)\n if (this.state.audioDescriptionEnabled) {\n this._audioDescriptionDesiredState = false;\n await this.disableAudioDescription();\n } else {\n this._audioDescriptionDesiredState = true;\n await this.enableAudioDescription();\n }\n }\n }\n\n // Sign Language\n enableSignLanguage() {\n // Determine available sign language sources\n const hasMultipleSources = Object.keys(this.signLanguageSources).length > 0;\n const hasSingleSource = !!this.signLanguageSrc;\n \n if (!hasMultipleSources && !hasSingleSource) {\n console.warn('No sign language video source provided');\n return;\n }\n\n if (this.signLanguageWrapper) {\n // Already exists, just show it\n this.signLanguageWrapper.style.display = 'block';\n this.state.signLanguageEnabled = true;\n this.emit('signlanguageenabled');\n \n // Focus the settings button after wrapper is shown\n // Use setManagedTimeout to ensure it's properly scheduled\n this.setManagedTimeout(() => {\n if (this.signLanguageSettingsButton && document.contains(this.signLanguageSettingsButton)) {\n this.signLanguageSettingsButton.focus({ preventScroll: true });\n }\n }, 150);\n return;\n }\n \n // Determine initial sign language\n let initialLang = null;\n let initialSrc = null;\n \n if (hasMultipleSources) {\n // Try to sync with current caption language\n if (this.captionManager && this.captionManager.currentTrack) {\n const captionLang = this.captionManager.currentTrack.language?.toLowerCase().split('-')[0];\n if (captionLang && this.signLanguageSources[captionLang]) {\n initialLang = captionLang;\n initialSrc = this.signLanguageSources[captionLang];\n }\n }\n \n // If no match, try player language\n if (!initialLang && this.options.language) {\n const playerLang = this.options.language.toLowerCase().split('-')[0];\n if (this.signLanguageSources[playerLang]) {\n initialLang = playerLang;\n initialSrc = this.signLanguageSources[playerLang];\n }\n }\n \n // If still no match, use first available\n if (!initialLang) {\n initialLang = Object.keys(this.signLanguageSources)[0];\n initialSrc = this.signLanguageSources[initialLang];\n }\n \n this.currentSignLanguage = initialLang;\n } else {\n // Single source fallback\n initialSrc = this.signLanguageSrc;\n }\n\n // Create wrapper container\n this.signLanguageWrapper = document.createElement('div');\n this.signLanguageWrapper.className = 'vidply-sign-language-wrapper';\n this.signLanguageWrapper.setAttribute('tabindex', '0');\n this.signLanguageWrapper.setAttribute('aria-label', i18n.t('player.signLanguageDragResize'));\n\n // Create header (draggable)\n this.signLanguageHeader = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-language-header`,\n attributes: {\n 'tabindex': '0'\n }\n });\n\n // Header left side (title)\n const headerLeft = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-language-header-left`\n });\n\n const title = DOMUtils.createElement('h3', {\n textContent: i18n.t('player.signLanguageVideo')\n });\n\n // Settings button (before language selector)\n const settingsAriaLabel = i18n.t('player.signLanguageSettings');\n this.signLanguageSettingsButton = DOMUtils.createElement('button', {\n className: `${this.options.classPrefix}-sign-language-settings`,\n attributes: {\n 'type': 'button',\n 'aria-label': settingsAriaLabel,\n 'aria-expanded': 'false'\n }\n });\n this.signLanguageSettingsButton.appendChild(createIconElement('settings'));\n DOMUtils.attachTooltip(this.signLanguageSettingsButton, settingsAriaLabel, this.options.classPrefix);\n this.signLanguageSettingsHandlers = {\n settingsClick: (e) => {\n e.preventDefault();\n e.stopPropagation();\n // Stop the document click handler from interfering\n if (this.signLanguageDocumentClickHandler) {\n // Temporarily disable document click handler\n const wasJustOpened = this.signLanguageSettingsMenuJustOpened;\n this.signLanguageSettingsMenuJustOpened = true;\n setTimeout(() => {\n this.signLanguageSettingsMenuJustOpened = wasJustOpened;\n }, 100);\n }\n if (this.signLanguageSettingsMenuVisible) {\n this.hideSignLanguageSettingsMenu();\n } else {\n this.showSignLanguageSettingsMenu();\n }\n },\n settingsKeydown: (e) => {\n // D key to toggle keyboard drag mode\n if (e.key === 'd' || e.key === 'D') {\n e.preventDefault();\n e.stopPropagation();\n this.toggleSignLanguageKeyboardDragMode();\n }\n // R key to toggle resize mode\n else if (e.key === 'r' || e.key === 'R') {\n e.preventDefault();\n e.stopPropagation();\n this.toggleSignLanguageResizeMode();\n }\n // Escape to close menu if open\n else if (e.key === 'Escape' && this.signLanguageSettingsMenuVisible) {\n e.preventDefault();\n e.stopPropagation();\n this.hideSignLanguageSettingsMenu();\n }\n }\n };\n this.signLanguageSettingsButton.addEventListener('click', this.signLanguageSettingsHandlers.settingsClick);\n this.signLanguageSettingsButton.addEventListener('keydown', this.signLanguageSettingsHandlers.settingsKeydown);\n headerLeft.appendChild(this.signLanguageSettingsButton);\n\n // Language selector (if multiple sources available)\n this.signLanguageSelector = null;\n if (hasMultipleSources) {\n const selectId = `${this.options.classPrefix}-sign-language-select-${Date.now()}`;\n \n // Create options array\n const options = Object.keys(this.signLanguageSources).map(langCode => ({\n value: langCode,\n text: this.getSignLanguageLabel(langCode),\n selected: langCode === initialLang\n }));\n \n const { label: signLanguageLabel, select: signLanguageSelector } = createLabeledSelect({\n classPrefix: this.options.classPrefix,\n labelClass: `${this.options.classPrefix}-sign-language-label`,\n selectClass: `${this.options.classPrefix}-sign-language-select`,\n labelText: 'settings.language',\n selectId: selectId,\n options: options,\n onChange: (e) => {\n e.stopPropagation(); // Prevent event from bubbling\n const selectedLang = e.target.value;\n this.switchSignLanguage(selectedLang);\n }\n });\n \n this.signLanguageSelector = signLanguageSelector;\n \n // Wrap label and select in a container for horizontal layout\n const signLanguageSelectorWrapper = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-language-selector-wrapper`\n });\n signLanguageSelectorWrapper.appendChild(signLanguageLabel);\n signLanguageSelectorWrapper.appendChild(this.signLanguageSelector);\n \n // Prevent drag when interacting with wrapper\n preventDragOnElement(signLanguageSelectorWrapper);\n \n headerLeft.appendChild(signLanguageSelectorWrapper);\n }\n\n headerLeft.appendChild(title);\n \n // Close button\n const closeAriaLabel = i18n.t('player.closeSignLanguage');\n const closeButton = DOMUtils.createElement('button', {\n className: `${this.options.classPrefix}-sign-language-close`,\n attributes: {\n 'type': 'button',\n 'aria-label': closeAriaLabel\n }\n });\n closeButton.appendChild(createIconElement('close'));\n DOMUtils.attachTooltip(closeButton, closeAriaLabel, this.options.classPrefix);\n closeButton.addEventListener('click', () => {\n this.disableSignLanguage();\n // Return focus to sign language button if available\n if (this.controlBar && this.controlBar.controls && this.controlBar.controls.signLanguage) {\n setTimeout(() => {\n this.controlBar.controls.signLanguage.focus({ preventScroll: true });\n }, 0);\n }\n });\n\n this.signLanguageHeader.appendChild(headerLeft);\n this.signLanguageHeader.appendChild(closeButton);\n \n // Initialize settings menu state\n this.signLanguageSettingsMenuVisible = false;\n this.signLanguageSettingsMenu = null;\n this.signLanguageSettingsMenuJustOpened = false;\n this.signLanguageResizeOptionButton = null;\n this.signLanguageResizeOptionText = null;\n this.signLanguageDragOptionButton = null;\n this.signLanguageDragOptionText = null;\n this.signLanguageDocumentClickHandler = null;\n this.signLanguageDocumentClickHandlerAdded = false;\n\n // Create sign language video element\n this.signLanguageVideo = document.createElement('video');\n this.signLanguageVideo.className = 'vidply-sign-language-video';\n this.signLanguageVideo.src = initialSrc;\n this.signLanguageVideo.setAttribute('aria-label', i18n.t('player.signLanguage'));\n this.signLanguageVideo.muted = true; // Sign language video should be muted\n \n // Enable inline playback on iOS (prevents native fullscreen)\n this.signLanguageVideo.setAttribute('playsinline', '');\n\n // Create resize handles (8 directions like transcript)\n this.signLanguageResizeHandles = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'].map(dir => {\n const handle = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-resize-handle ${this.options.classPrefix}-sign-resize-${dir}`,\n attributes: {\n 'data-direction': dir,\n 'data-vidply-managed-resize': 'true',\n 'aria-hidden': 'true'\n }\n });\n handle.style.display = 'none';\n return handle;\n });\n\n // Append header, video and handles to wrapper\n this.signLanguageWrapper.appendChild(this.signLanguageHeader);\n this.signLanguageWrapper.appendChild(this.signLanguageVideo);\n this.signLanguageResizeHandles.forEach(handle => this.signLanguageWrapper.appendChild(handle));\n\n // Set width FIRST to ensure proper dimensions\n const saved = this.storage.getSignLanguagePreferences();\n if (saved && saved.size && saved.size.width) {\n this.signLanguageWrapper.style.width = saved.size.width;\n } else {\n this.signLanguageWrapper.style.width = '280px'; // Default width\n }\n // Height is always auto to maintain aspect ratio\n this.signLanguageWrapper.style.height = 'auto';\n \n // Position is always calculated fresh - use option or default to bottom-right\n this.signLanguageDesiredPosition = this.options.signLanguagePosition || 'bottom-right';\n\n // Add to main player container (NOT videoWrapper) to avoid overflow:hidden clipping\n this.container.appendChild(this.signLanguageWrapper);\n\n // Set position immediately after appending\n requestAnimationFrame(() => {\n this.constrainSignLanguagePosition();\n });\n\n // Sync with main video\n this.signLanguageVideo.currentTime = this.state.currentTime;\n if (!this.state.paused) {\n this.signLanguageVideo.play();\n }\n\n // Setup drag and resize\n this.setupSignLanguageInteraction();\n\n // Create bound handlers to store references for cleanup\n this.signLanguageHandlers = {\n play: () => {\n if (this.signLanguageVideo) {\n this.signLanguageVideo.play();\n }\n },\n pause: () => {\n if (this.signLanguageVideo) {\n this.signLanguageVideo.pause();\n }\n },\n timeupdate: () => {\n if (this.signLanguageVideo && Math.abs(this.signLanguageVideo.currentTime - this.state.currentTime) > 0.5) {\n this.signLanguageVideo.currentTime = this.state.currentTime;\n }\n },\n ratechange: () => {\n if (this.signLanguageVideo) {\n this.signLanguageVideo.playbackRate = this.state.playbackSpeed;\n }\n }\n };\n\n // Sync playback\n this.on('play', this.signLanguageHandlers.play);\n this.on('pause', this.signLanguageHandlers.pause);\n this.on('timeupdate', this.signLanguageHandlers.timeupdate);\n this.on('ratechange', this.signLanguageHandlers.ratechange);\n \n // Sync sign language when captions change (if multiple sources available)\n if (hasMultipleSources) {\n this.signLanguageHandlers.captionChange = () => {\n if (this.captionManager && this.captionManager.currentTrack && this.signLanguageSelector) {\n const captionLang = this.captionManager.currentTrack.language?.toLowerCase().split('-')[0];\n if (captionLang && this.signLanguageSources[captionLang] && this.currentSignLanguage !== captionLang) {\n this.switchSignLanguage(captionLang);\n // Update selector\n this.signLanguageSelector.value = captionLang;\n }\n }\n };\n // Listen to captionsenabled which fires when a track is enabled (including when switching)\n this.on('captionsenabled', this.signLanguageHandlers.captionChange);\n }\n\n this.state.signLanguageEnabled = true;\n this.emit('signlanguageenabled');\n \n // Focus the settings button after wrapper is appended to DOM\n // Use setManagedTimeout to ensure it's properly scheduled\n this.setManagedTimeout(() => {\n if (this.signLanguageSettingsButton && document.contains(this.signLanguageSettingsButton)) {\n this.signLanguageSettingsButton.focus({ preventScroll: true });\n }\n }, 150);\n }\n\n disableSignLanguage() {\n // Hide settings menu if open\n if (this.signLanguageSettingsMenuVisible) {\n this.hideSignLanguageSettingsMenu({ focusButton: false });\n }\n \n if (this.signLanguageWrapper) {\n this.signLanguageWrapper.style.display = 'none';\n }\n this.state.signLanguageEnabled = false;\n this.emit('signlanguagedisabled');\n }\n\n toggleSignLanguage() {\n if (this.state.signLanguageEnabled) {\n this.disableSignLanguage();\n } else {\n this.enableSignLanguage();\n }\n }\n\n setupSignLanguageInteraction() {\n if (!this.signLanguageWrapper) return;\n\n // Check if we're on mobile and not in fullscreen\n const isMobile = window.innerWidth < 768;\n const isFullscreen = this.state.fullscreen;\n \n // On mobile devices (< 768px), only enable drag/resize in fullscreen\n // On desktop/tablets (>= 768px), always enable drag/resize\n if (isMobile && !isFullscreen) {\n // Destroy existing instance if exiting fullscreen on mobile\n if (this.signLanguageDraggable) {\n this.signLanguageDraggable.destroy();\n this.signLanguageDraggable = null;\n }\n return; // No drag/resize on mobile when not in fullscreen\n }\n\n // If already initialized, don't re-initialize\n if (this.signLanguageDraggable) {\n return;\n }\n\n // Create DraggableResizable utility with touch support\n // Use header as drag handle instead of video\n this.signLanguageDraggable = new DraggableResizable(this.signLanguageWrapper, {\n dragHandle: this.signLanguageHeader,\n resizeHandles: this.signLanguageResizeHandles,\n constrainToViewport: true,\n maintainAspectRatio: true,\n minWidth: 150,\n minHeight: 100,\n classPrefix: `${this.options.classPrefix}-sign`,\n keyboardDragKey: 'd',\n keyboardResizeKey: 'r',\n keyboardStep: 10,\n keyboardStepLarge: 50,\n pointerResizeIndicatorText: i18n.t('player.signLanguageResizeActive'),\n onPointerResizeToggle: (enabled) => {\n // Update resize handles visibility\n this.signLanguageResizeHandles.forEach(handle => {\n handle.style.display = enabled ? 'block' : 'none';\n });\n },\n onDragStart: (e) => {\n // Don't drag if clicking on close button, settings button, language selector, or settings menu\n if (e.target.closest(`.${this.options.classPrefix}-sign-language-close`) ||\n e.target.closest(`.${this.options.classPrefix}-sign-language-settings`) ||\n e.target.closest(`.${this.options.classPrefix}-sign-language-select`) ||\n e.target.closest(`.${this.options.classPrefix}-sign-language-label`) ||\n e.target.closest(`.${this.options.classPrefix}-sign-language-settings-menu`)) {\n return false; // Prevent drag\n }\n return true; // Allow drag\n }\n });\n\n // Add custom keyboard handler for special keys (Escape, Home)\n this.signLanguageCustomKeyHandler = (e) => {\n const key = e.key.toLowerCase();\n \n // Don't handle keys if settings menu is open (let menu handle them)\n if (this.signLanguageSettingsMenuVisible) {\n return;\n }\n \n if (key === 'home') {\n e.preventDefault();\n e.stopPropagation();\n if (this.signLanguageDraggable) {\n if (this.signLanguageDraggable.pointerResizeMode) {\n this.signLanguageDraggable.disablePointerResizeMode();\n }\n this.signLanguageDraggable.manuallyPositioned = false;\n this.constrainSignLanguagePosition();\n }\n return;\n }\n \n if (key === 'r') {\n e.preventDefault();\n e.stopPropagation();\n const enabled = this.toggleSignLanguageResizeMode();\n if (enabled) {\n this.signLanguageWrapper.focus({ preventScroll: true });\n }\n return;\n }\n \n if (key === 'escape') {\n e.preventDefault();\n e.stopPropagation();\n // Exit resize mode if active\n if (this.signLanguageDraggable && this.signLanguageDraggable.pointerResizeMode) {\n this.signLanguageDraggable.disablePointerResizeMode();\n return;\n }\n // Exit keyboard drag mode if active\n if (this.signLanguageDraggable && this.signLanguageDraggable.keyboardDragMode) {\n this.signLanguageDraggable.disableKeyboardDragMode();\n return;\n }\n // Close video if no modes are active\n this.disableSignLanguage();\n // Return focus to sign language button if available\n if (this.controlBar && this.controlBar.controls && this.controlBar.controls.signLanguage) {\n setTimeout(() => {\n this.controlBar.controls.signLanguage.focus({ preventScroll: true });\n }, 0);\n }\n return;\n }\n };\n \n this.signLanguageWrapper.addEventListener('keydown', this.signLanguageCustomKeyHandler);\n\n // Store for cleanup\n this.signLanguageInteractionHandlers = {\n draggable: this.signLanguageDraggable,\n headerKeyHandler: this.signLanguageHeaderKeyHandler,\n customKeyHandler: this.signLanguageCustomKeyHandler\n };\n }\n\n toggleSignLanguageKeyboardDragMode() {\n if (this.signLanguageDraggable) {\n const wasEnabled = this.signLanguageDraggable.keyboardDragMode;\n this.signLanguageDraggable.toggleKeyboardDragMode();\n const isEnabled = this.signLanguageDraggable.keyboardDragMode;\n if (!wasEnabled && isEnabled) {\n this.enableSignLanguageMoveMode();\n }\n // Update drag option state\n this.updateSignLanguageDragOptionState();\n }\n }\n\n enableSignLanguageMoveMode() {\n // Add visual feedback for move mode\n this.signLanguageWrapper.classList.add(`${this.options.classPrefix}-sign-move-mode`);\n \n // Update resize option state in case menu is open\n this.updateSignLanguageResizeOptionState();\n \n // Remove after 2 seconds\n setTimeout(() => {\n this.signLanguageWrapper.classList.remove(`${this.options.classPrefix}-sign-move-mode`);\n }, 2000);\n }\n\n toggleSignLanguageResizeMode({ focus = true } = {}) {\n if (!this.signLanguageDraggable) {\n return false;\n }\n\n if (this.signLanguageDraggable.pointerResizeMode) {\n this.signLanguageDraggable.disablePointerResizeMode({ focus });\n this.updateSignLanguageResizeOptionState();\n return false;\n }\n\n this.signLanguageDraggable.enablePointerResizeMode({ focus });\n this.updateSignLanguageResizeOptionState();\n return true;\n }\n\n getSignLanguageLabel(langCode) {\n // Get language label from i18n or use language code\n const langNames = {\n 'en': 'English',\n 'de': 'Deutsch',\n 'es': 'Español',\n 'fr': 'Français',\n 'it': 'Italiano',\n 'ja': '日本語',\n 'pt': 'Português',\n 'ar': 'العربية',\n 'hi': 'हिन्दी'\n };\n return langNames[langCode] || langCode.toUpperCase();\n }\n\n switchSignLanguage(langCode) {\n if (!this.signLanguageSources[langCode] || !this.signLanguageVideo) {\n return;\n }\n \n const currentTime = this.signLanguageVideo.currentTime;\n const wasPlaying = !this.signLanguageVideo.paused;\n \n this.signLanguageVideo.src = this.signLanguageSources[langCode];\n this.currentSignLanguage = langCode;\n \n // Restore playback state\n this.signLanguageVideo.currentTime = currentTime;\n if (wasPlaying) {\n this.signLanguageVideo.play().catch(() => {\n // Ignore play errors\n });\n }\n \n this.emit('signlanguagelanguagechanged', langCode);\n }\n\n showSignLanguageSettingsMenu() {\n // Set flag to prevent immediate closing\n this.signLanguageSettingsMenuJustOpened = true;\n setTimeout(() => {\n this.signLanguageSettingsMenuJustOpened = false;\n }, 350);\n \n // Add document click handler on FIRST menu open (not at window creation)\n if (!this.signLanguageDocumentClickHandlerAdded) {\n this.signLanguageDocumentClickHandler = (e) => {\n // Ignore if menu was just opened (prevents immediate closing)\n if (this.signLanguageSettingsMenuJustOpened) {\n return;\n }\n \n // Ignore clicks on the settings button itself or its children\n if (this.signLanguageSettingsButton && \n (this.signLanguageSettingsButton === e.target || this.signLanguageSettingsButton.contains(e.target))) {\n return;\n }\n \n // Ignore clicks on the settings menu items\n if (this.signLanguageSettingsMenu && this.signLanguageSettingsMenu.contains(e.target)) {\n return;\n }\n \n // Close menu if clicking outside\n if (this.signLanguageSettingsMenuVisible) {\n this.hideSignLanguageSettingsMenu();\n }\n };\n setTimeout(() => {\n document.addEventListener('mousedown', this.signLanguageDocumentClickHandler, true); // Use mousedown in capture phase\n this.signLanguageDocumentClickHandlerAdded = true;\n }, 300);\n }\n \n if (this.signLanguageSettingsMenu) {\n this.signLanguageSettingsMenu.style.display = 'block';\n this.signLanguageSettingsMenuVisible = true;\n if (this.signLanguageSettingsButton) {\n this.signLanguageSettingsButton.setAttribute('aria-expanded', 'true');\n }\n // Always re-attach keyboard navigation handler when reopening\n this.signLanguageSettingsMenuKeyHandler = attachMenuKeyboardNavigation(\n this.signLanguageSettingsMenu,\n this.signLanguageSettingsButton,\n `.${this.options.classPrefix}-sign-language-settings-item`,\n () => this.hideSignLanguageSettingsMenu({ focusButton: true })\n );\n // Reposition menu in case window was moved (async for repositioning)\n this.positionSignLanguageSettingsMenu();\n this.updateSignLanguageDragOptionState();\n this.updateSignLanguageResizeOptionState();\n focusFirstMenuItem(this.signLanguageSettingsMenu, `.${this.options.classPrefix}-sign-language-settings-item`);\n return;\n }\n \n // Create settings menu\n this.signLanguageSettingsMenu = DOMUtils.createElement('div', {\n className: `${this.options.classPrefix}-sign-language-settings-menu`,\n attributes: {\n 'role': 'menu'\n }\n });\n\n // Keyboard drag option\n const keyboardDragOption = createMenuItem({\n classPrefix: this.options.classPrefix,\n itemClass: `${this.options.classPrefix}-sign-language-settings-item`,\n icon: 'move',\n label: 'player.enableSignDragMode',\n hasTextClass: true,\n onClick: () => {\n this.toggleSignLanguageKeyboardDragMode();\n this.hideSignLanguageSettingsMenu();\n }\n });\n keyboardDragOption.setAttribute('role', 'switch');\n keyboardDragOption.setAttribute('aria-checked', 'false');\n // Remove any tooltips from menu items (they have visible text)\n const dragTooltip = keyboardDragOption.querySelector(`.${this.options.classPrefix}-tooltip`);\n if (dragTooltip) dragTooltip.remove();\n const dragButtonText = keyboardDragOption.querySelector(`.${this.options.classPrefix}-button-text`);\n if (dragButtonText) dragButtonText.remove();\n this.signLanguageDragOptionButton = keyboardDragOption;\n this.signLanguageDragOptionText = keyboardDragOption.querySelector(`.${this.options.classPrefix}-settings-text`);\n this.updateSignLanguageDragOptionState();\n\n // Resize option\n const resizeOption = createMenuItem({\n classPrefix: this.options.classPrefix,\n itemClass: `${this.options.classPrefix}-sign-language-settings-item`,\n icon: 'resize',\n label: 'player.enableSignResizeMode',\n hasTextClass: true,\n onClick: (event) => {\n event.preventDefault();\n event.stopPropagation();\n \n const enabled = this.toggleSignLanguageResizeMode({ focus: false });\n \n if (enabled) {\n this.hideSignLanguageSettingsMenu({ focusButton: false });\n // Focus sign language wrapper after handles appear\n setTimeout(() => {\n if (this.signLanguageWrapper) {\n this.signLanguageWrapper.focus({ preventScroll: true });\n }\n }, 20);\n } else {\n this.hideSignLanguageSettingsMenu({ focusButton: true });\n }\n }\n });\n resizeOption.setAttribute('role', 'switch');\n resizeOption.setAttribute('aria-checked', 'false');\n // Remove any tooltips from menu items (they have visible text)\n const resizeTooltip = resizeOption.querySelector(`.${this.options.classPrefix}-tooltip`);\n if (resizeTooltip) resizeTooltip.remove();\n const resizeButtonText = resizeOption.querySelector(`.${this.options.classPrefix}-button-text`);\n if (resizeButtonText) resizeButtonText.remove();\n this.signLanguageResizeOptionButton = resizeOption;\n this.signLanguageResizeOptionText = resizeOption.querySelector(`.${this.options.classPrefix}-settings-text`);\n this.updateSignLanguageResizeOptionState();\n\n // Close option\n const closeOption = createMenuItem({\n classPrefix: this.options.classPrefix,\n itemClass: `${this.options.classPrefix}-sign-language-settings-item`,\n icon: 'close',\n label: 'transcript.closeMenu',\n onClick: () => {\n this.hideSignLanguageSettingsMenu();\n }\n });\n // Remove any tooltips from menu items (they have visible text)\n const closeTooltip = closeOption.querySelector(`.${this.options.classPrefix}-tooltip`);\n if (closeTooltip) closeTooltip.remove();\n const closeButtonText = closeOption.querySelector(`.${this.options.classPrefix}-button-text`);\n if (closeButtonText) closeButtonText.remove();\n\n this.signLanguageSettingsMenu.appendChild(keyboardDragOption);\n this.signLanguageSettingsMenu.appendChild(resizeOption);\n this.signLanguageSettingsMenu.appendChild(closeOption);\n\n // Position menu first (before it's visible) to prevent jumping\n // Set menu to invisible temporarily\n this.signLanguageSettingsMenu.style.visibility = 'hidden';\n this.signLanguageSettingsMenu.style.display = 'block';\n \n // Insert menu right after the button in the DOM (like control bar menus)\n if (this.signLanguageSettingsButton && this.signLanguageSettingsButton.parentNode) {\n this.signLanguageSettingsButton.insertAdjacentElement('afterend', this.signLanguageSettingsMenu);\n } else if (this.signLanguageWrapper) {\n // Fallback: append to wrapper if button parent not available\n this.signLanguageWrapper.appendChild(this.signLanguageSettingsMenu);\n }\n \n // Position the menu relative to the settings button (immediately while hidden)\n this.positionSignLanguageSettingsMenuImmediate();\n \n // Make menu visible after positioning\n requestAnimationFrame(() => {\n if (this.signLanguageSettingsMenu) {\n this.signLanguageSettingsMenu.style.visibility = 'visible';\n }\n });\n \n // Add keyboard navigation\n this.signLanguageSettingsMenuKeyHandler = attachMenuKeyboardNavigation(\n this.signLanguageSettingsMenu,\n this.signLanguageSettingsButton,\n `.${this.options.classPrefix}-sign-language-settings-item`,\n () => this.hideSignLanguageSettingsMenu({ focusButton: true })\n );\n \n // Set the menu as visible and display it\n this.signLanguageSettingsMenuVisible = true;\n // this.signLanguageSettingsMenu.style.display = 'block'; // Already set above\n \n // Update aria-expanded\n if (this.signLanguageSettingsButton) {\n this.signLanguageSettingsButton.setAttribute('aria-expanded', 'true');\n }\n this.updateSignLanguageDragOptionState();\n this.updateSignLanguageResizeOptionState();\n \n // Focus first menu item\n focusFirstMenuItem(this.signLanguageSettingsMenu, `.${this.options.classPrefix}-sign-language-settings-item`);\n }\n\n hideSignLanguageSettingsMenu({ focusButton = true } = {}) {\n if (this.signLanguageSettingsMenu) {\n this.signLanguageSettingsMenu.style.display = 'none';\n this.signLanguageSettingsMenuVisible = false;\n this.signLanguageSettingsMenuJustOpened = false;\n \n // Remove keyboard handler\n if (this.signLanguageSettingsMenuKeyHandler) {\n this.signLanguageSettingsMenu.removeEventListener('keydown', this.signLanguageSettingsMenuKeyHandler);\n this.signLanguageSettingsMenuKeyHandler = null;\n }\n \n // Reset tabindex on menu items\n const menuItems = Array.from(this.signLanguageSettingsMenu.querySelectorAll(`.${this.options.classPrefix}-sign-language-settings-item`));\n menuItems.forEach(item => {\n item.setAttribute('tabindex', '-1');\n });\n \n // Update aria-expanded\n if (this.signLanguageSettingsButton) {\n this.signLanguageSettingsButton.setAttribute('aria-expanded', 'false');\n if (focusButton) {\n // Return focus to settings button\n this.signLanguageSettingsButton.focus({ preventScroll: true });\n }\n }\n }\n }\n\n positionSignLanguageSettingsMenuImmediate() {\n if (!this.signLanguageSettingsMenu || !this.signLanguageSettingsButton) return;\n \n // Position immediately (synchronously) - used when menu is first shown\n const buttonRect = this.signLanguageSettingsButton.getBoundingClientRect();\n const menuRect = this.signLanguageSettingsMenu.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n \n // Get the parent container (headerLeft) as the positioning container (like control bar menus)\n const parentContainer = this.signLanguageSettingsButton.parentElement;\n if (!parentContainer) return;\n \n const parentRect = parentContainer.getBoundingClientRect();\n \n // Calculate position relative to parent container\n const buttonCenterX = buttonRect.left + buttonRect.width / 2 - parentRect.left;\n const buttonBottom = buttonRect.bottom - parentRect.top;\n const buttonTop = buttonRect.top - parentRect.top;\n \n const spaceAbove = buttonRect.top;\n const spaceBelow = viewportHeight - buttonRect.bottom;\n \n // Position menu below button by default\n let menuTop = buttonBottom + 8;\n let menuBottom = null;\n \n // Prefer below, but switch to above if not enough space\n if (spaceBelow < menuRect.height + 20 && spaceAbove > spaceBelow) {\n menuTop = null;\n const parentHeight = parentRect.bottom - parentRect.top;\n menuBottom = parentHeight - buttonTop + 8;\n this.signLanguageSettingsMenu.classList.add('vidply-menu-above');\n } else {\n this.signLanguageSettingsMenu.classList.remove('vidply-menu-above');\n }\n \n // Calculate horizontal position (center on button)\n let menuLeft = buttonCenterX - menuRect.width / 2;\n let menuRight = 'auto';\n let transformX = 'translateX(0)';\n \n const menuLeftAbsolute = buttonRect.left + buttonRect.width / 2 - menuRect.width / 2;\n if (menuLeftAbsolute < 10) {\n menuLeft = 0;\n transformX = 'translateX(0)';\n } else if (menuLeftAbsolute + menuRect.width > viewportWidth - 10) {\n menuLeft = 'auto';\n menuRight = 0;\n transformX = 'translateX(0)';\n } else {\n menuLeft = buttonCenterX;\n transformX = 'translateX(-50%)';\n }\n \n // Apply calculated positions\n if (menuTop !== null) {\n this.signLanguageSettingsMenu.style.top = `${menuTop}px`;\n this.signLanguageSettingsMenu.style.bottom = 'auto';\n } else if (menuBottom !== null) {\n this.signLanguageSettingsMenu.style.top = 'auto';\n this.signLanguageSettingsMenu.style.bottom = `${menuBottom}px`;\n }\n \n if (menuLeft !== 'auto') {\n this.signLanguageSettingsMenu.style.left = `${menuLeft}px`;\n this.signLanguageSettingsMenu.style.right = 'auto';\n } else {\n this.signLanguageSettingsMenu.style.left = 'auto';\n this.signLanguageSettingsMenu.style.right = `${menuRight}px`;\n }\n \n this.signLanguageSettingsMenu.style.transform = transformX;\n }\n \n positionSignLanguageSettingsMenu() {\n if (!this.signLanguageSettingsMenu || !this.signLanguageSettingsButton || !this.signLanguageWrapper) return;\n \n // Use requestAnimationFrame to ensure layout is stable before positioning (for repositioning)\n requestAnimationFrame(() => {\n setTimeout(() => {\n this.positionSignLanguageSettingsMenuImmediate();\n }, 10); // Small delay to ensure layout is stable\n });\n }\n\n attachSignLanguageSettingsMenuKeyboardNavigation() {\n if (!this.signLanguageSettingsMenu) return;\n \n // Remove existing handler if any\n if (this.signLanguageSettingsMenuKeyHandler) {\n this.signLanguageSettingsMenu.removeEventListener('keydown', this.signLanguageSettingsMenuKeyHandler);\n }\n \n this.signLanguageSettingsMenuKeyHandler = attachMenuKeyboardNavigation(\n this.signLanguageSettingsMenu,\n this.signLanguageSettingsButton,\n `.${this.options.classPrefix}-sign-language-settings-item`,\n () => this.hideSignLanguageSettingsMenu({ focusButton: true })\n );\n }\n\n updateSignLanguageDragOptionState() {\n if (!this.signLanguageDragOptionButton) {\n return;\n }\n \n const isEnabled = !!(this.signLanguageDraggable && this.signLanguageDraggable.keyboardDragMode);\n const text = isEnabled\n ? i18n.t('player.disableSignDragMode')\n : i18n.t('player.enableSignDragMode');\n const ariaLabel = isEnabled\n ? i18n.t('player.disableSignDragModeAria')\n : i18n.t('player.enableSignDragModeAria');\n\n this.signLanguageDragOptionButton.setAttribute('aria-checked', isEnabled ? 'true' : 'false');\n this.signLanguageDragOptionButton.setAttribute('aria-label', ariaLabel);\n\n if (this.signLanguageDragOptionText) {\n this.signLanguageDragOptionText.textContent = text;\n }\n }\n\n updateSignLanguageResizeOptionState() {\n if (!this.signLanguageResizeOptionButton) {\n return;\n }\n \n const isEnabled = !!(this.signLanguageDraggable && this.signLanguageDraggable.pointerResizeMode);\n const text = isEnabled\n ? i18n.t('player.disableSignResizeMode')\n : i18n.t('player.enableSignResizeMode');\n const ariaLabel = isEnabled\n ? i18n.t('player.disableSignResizeModeAria')\n : i18n.t('player.enableSignResizeModeAria');\n\n this.signLanguageResizeOptionButton.setAttribute('aria-checked', isEnabled ? 'true' : 'false');\n this.signLanguageResizeOptionButton.setAttribute('aria-label', ariaLabel);\n\n if (this.signLanguageResizeOptionText) {\n this.signLanguageResizeOptionText.textContent = text;\n }\n }\n\n constrainSignLanguagePosition() {\n if (!this.signLanguageWrapper || !this.videoWrapper) return;\n \n // Don't auto-position if user has manually positioned it\n if (this.signLanguageDraggable && this.signLanguageDraggable.manuallyPositioned) {\n return;\n }\n \n // Ensure width is set\n if (!this.signLanguageWrapper.style.width || this.signLanguageWrapper.style.width === '') {\n this.signLanguageWrapper.style.width = '280px'; // Default width\n }\n \n // Get videoWrapper position relative to the player CONTAINER (where sign language video is attached)\n const videoWrapperRect = this.videoWrapper.getBoundingClientRect();\n const containerRect = this.container.getBoundingClientRect();\n const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();\n \n // Calculate videoWrapper's position and dimensions relative to container\n const videoWrapperLeft = videoWrapperRect.left - containerRect.left;\n const videoWrapperTop = videoWrapperRect.top - containerRect.top;\n const videoWrapperWidth = videoWrapperRect.width;\n const videoWrapperHeight = videoWrapperRect.height;\n \n // Use estimated height if video hasn't loaded yet (16:9 aspect ratio)\n let wrapperWidth = wrapperRect.width || 280;\n let wrapperHeight = wrapperRect.height || ((280 * 9) / 16); // Estimate based on 16:9 aspect ratio\n \n let left, top;\n const margin = 16; // Margin from edges\n const controlsHeight = 95; // Height of controls when visible\n \n // Always calculate fresh position based on desired location (relative to videoWrapper)\n const position = this.signLanguageDesiredPosition || 'bottom-right';\n \n switch (position) {\n case 'bottom-right':\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n break;\n case 'bottom-left':\n left = videoWrapperLeft + margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n break;\n case 'top-right':\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + margin;\n break;\n case 'top-left':\n left = videoWrapperLeft + margin;\n top = videoWrapperTop + margin;\n break;\n default:\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n }\n \n // Constrain to videoWrapper bounds (ensuring it stays above controls)\n left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));\n top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));\n \n // Apply constrained position\n this.signLanguageWrapper.style.left = `${left}px`;\n this.signLanguageWrapper.style.top = `${top}px`;\n this.signLanguageWrapper.style.right = 'auto';\n this.signLanguageWrapper.style.bottom = 'auto';\n // Remove position classes if any were applied\n this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter(c => c.startsWith('vidply-sign-position-')));\n }\n\n saveSignLanguagePreferences() {\n if (!this.signLanguageWrapper) return;\n \n // Only save width - position is always calculated fresh to bottom-right\n this.storage.saveSignLanguagePreferences({\n size: {\n width: this.signLanguageWrapper.style.width\n // Height is auto - maintained by aspect ratio\n }\n });\n }\n\n cleanupSignLanguage() {\n // Hide settings menu if open\n if (this.signLanguageSettingsMenuVisible) {\n this.hideSignLanguageSettingsMenu({ focusButton: false });\n }\n \n // Remove document click handler\n if (this.signLanguageDocumentClickHandler && this.signLanguageDocumentClickHandlerAdded) {\n document.removeEventListener('mousedown', this.signLanguageDocumentClickHandler, true);\n this.signLanguageDocumentClickHandlerAdded = false;\n this.signLanguageDocumentClickHandler = null;\n }\n \n // Remove settings menu event listeners\n if (this.signLanguageSettingsHandlers) {\n if (this.signLanguageSettingsButton) {\n this.signLanguageSettingsButton.removeEventListener('click', this.signLanguageSettingsHandlers.settingsClick);\n this.signLanguageSettingsButton.removeEventListener('keydown', this.signLanguageSettingsHandlers.settingsKeydown);\n }\n this.signLanguageSettingsHandlers = null;\n }\n \n // Remove event listeners\n if (this.signLanguageHandlers) {\n this.off('play', this.signLanguageHandlers.play);\n this.off('pause', this.signLanguageHandlers.pause);\n this.off('timeupdate', this.signLanguageHandlers.timeupdate);\n this.off('ratechange', this.signLanguageHandlers.ratechange);\n if (this.signLanguageHandlers.captionChange) {\n this.off('captionsenabled', this.signLanguageHandlers.captionChange);\n }\n this.signLanguageHandlers = null;\n }\n\n // Remove event listeners\n if (this.signLanguageInteractionHandlers) {\n if (this.signLanguageHeader && this.signLanguageInteractionHandlers.headerKeyHandler) {\n this.signLanguageHeader.removeEventListener('keydown', this.signLanguageInteractionHandlers.headerKeyHandler);\n }\n if (this.signLanguageWrapper && this.signLanguageInteractionHandlers.customKeyHandler) {\n this.signLanguageWrapper.removeEventListener('keydown', this.signLanguageInteractionHandlers.customKeyHandler);\n }\n }\n\n // Destroy draggable utility\n if (this.signLanguageDraggable) {\n if (this.signLanguageDraggable.pointerResizeMode) {\n this.signLanguageDraggable.disablePointerResizeMode();\n }\n this.signLanguageDraggable.destroy();\n this.signLanguageDraggable = null;\n }\n \n // Clear interaction handlers reference\n this.signLanguageInteractionHandlers = null;\n\n // Remove video and wrapper elements\n if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {\n if (this.signLanguageVideo) {\n this.signLanguageVideo.pause();\n this.signLanguageVideo.src = '';\n }\n this.signLanguageWrapper.parentNode.removeChild(this.signLanguageWrapper);\n }\n this.signLanguageWrapper = null;\n this.signLanguageVideo = null;\n this.signLanguageSettingsButton = null;\n this.signLanguageSettingsMenu = null;\n }\n\n // Settings\n // Settings dialog removed - using individual control buttons instead\n showSettings() {\n console.warn('[VidPly] Settings dialog has been removed. Use individual control buttons (speed, captions, etc.)');\n }\n\n hideSettings() {\n // No-op - settings dialog removed\n }\n\n // Utility methods\n getCurrentTime() {\n return this.state.currentTime;\n }\n\n getDuration() {\n return this.state.duration;\n }\n\n isPlaying() {\n return this.state.playing;\n }\n\n isPaused() {\n return this.state.paused;\n }\n\n isEnded() {\n return this.state.ended;\n }\n\n isMuted() {\n return this.state.muted;\n }\n\n isFullscreen() {\n return this.state.fullscreen;\n }\n\n // Error handling\n handleError(error) {\n // Suppress errors during renderer switching\n // This prevents cascade of errors when HTML5 element is cleared for external renderers\n if (this._switchingRenderer) {\n this.log('Suppressing error during renderer switch:', error, 'debug');\n return;\n }\n \n this.log('Error:', error, 'error');\n this.emit('error', error);\n\n if (this.options.onError) {\n this.options.onError.call(this, error);\n }\n }\n\n // Logging\n log(...messages) {\n if (!this.options.debug) {\n return;\n }\n\n let type = 'log';\n if (messages.length > 0) {\n const potentialType = messages[messages.length - 1];\n if (typeof potentialType === 'string' && console[potentialType]) {\n type = potentialType;\n messages = messages.slice(0, -1);\n }\n }\n\n if (messages.length === 0) {\n messages = [''];\n }\n\n if (typeof console[type] === 'function') {\n console[type]('[VidPly]', ...messages);\n } else {\n console.log('[VidPly]', ...messages);\n }\n }\n\n // Setup responsive handlers\n setupResponsiveHandlers() {\n // Use ResizeObserver for efficient resize tracking\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const width = entry.contentRect.width;\n\n // Update control bar for viewport\n if (this.controlBar && typeof this.controlBar.updateControlsForViewport === 'function') {\n this.controlBar.updateControlsForViewport(width);\n }\n\n // Update transcript positioning\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n this.transcriptManager.positionTranscript();\n }\n }\n });\n\n this.resizeObserver.observe(this.container);\n } else {\n // Fallback to window resize event\n this.resizeHandler = () => {\n const width = this.container.clientWidth;\n\n if (this.controlBar && typeof this.controlBar.updateControlsForViewport === 'function') {\n this.controlBar.updateControlsForViewport(width);\n }\n\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n // Only auto-position if user hasn't manually moved it\n if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {\n this.transcriptManager.positionTranscript();\n }\n }\n };\n\n window.addEventListener('resize', this.resizeHandler);\n }\n\n // Also listen for orientation changes on mobile\n if (window.matchMedia) {\n this.orientationHandler = (e) => {\n // Wait for layout to settle\n setTimeout(() => {\n if (this.transcriptManager && this.transcriptManager.isVisible) {\n // Only auto-position if user hasn't manually moved it\n if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {\n this.transcriptManager.positionTranscript();\n }\n }\n }, 100);\n };\n\n const orientationQuery = window.matchMedia('(orientation: portrait)');\n if (orientationQuery.addEventListener) {\n orientationQuery.addEventListener('change', this.orientationHandler);\n } else if (orientationQuery.addListener) {\n // Fallback for older browsers\n orientationQuery.addListener(this.orientationHandler);\n }\n\n this.orientationQuery = orientationQuery;\n }\n\n // Listen for native fullscreen change events (e.g., when user presses ESC)\n this.fullscreenChangeHandler = () => {\n const isFullscreen = !!(\n document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement\n );\n\n // Only update if state has changed\n if (this.state.fullscreen !== isFullscreen) {\n this.state.fullscreen = isFullscreen;\n \n if (isFullscreen) {\n this.container.classList.add(`${this.options.classPrefix}-fullscreen`);\n } else {\n this.container.classList.remove(`${this.options.classPrefix}-fullscreen`);\n // Clean up pseudo-fullscreen state when exiting\n this._disablePseudoFullscreen();\n }\n \n this.emit('fullscreenchange', isFullscreen);\n \n // Update fullscreen button icon\n if (this.controlBar) {\n this.controlBar.updateFullscreenButton();\n }\n \n // Reposition sign language video after fullscreen transition\n if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== 'none') {\n // Re-setup drag/drop when entering/exiting fullscreen on mobile devices\n // This enables drag/resize when entering fullscreen on mobile\n const isMobile = window.innerWidth < 768;\n if (isMobile) {\n this.setupSignLanguageInteraction();\n }\n \n // Use setTimeout to ensure layout has updated after fullscreen transition\n // Longer delay to account for CSS transition animations and layout recalculation\n this.setManagedTimeout(() => {\n // Use requestAnimationFrame to ensure the browser has fully rendered the layout\n requestAnimationFrame(() => {\n // Clear saved size and reset to default for the new container size\n this.storage.saveSignLanguagePreferences({ size: null });\n this.signLanguageDesiredPosition = 'bottom-right';\n // Reset to default width for the new container\n this.signLanguageWrapper.style.width = isFullscreen ? '400px' : '280px';\n this.constrainSignLanguagePosition();\n });\n }, 500);\n }\n }\n };\n\n // Add listeners for all vendor-prefixed fullscreenchange events\n document.addEventListener('fullscreenchange', this.fullscreenChangeHandler);\n document.addEventListener('webkitfullscreenchange', this.fullscreenChangeHandler);\n document.addEventListener('mozfullscreenchange', this.fullscreenChangeHandler);\n document.addEventListener('MSFullscreenChange', this.fullscreenChangeHandler);\n }\n\n // Cleanup\n destroy() {\n this.log('Destroying player');\n\n if (this.renderer) {\n this.renderer.destroy();\n }\n\n if (this.controlBar) {\n this.controlBar.destroy();\n }\n\n if (this.captionManager) {\n this.captionManager.destroy();\n }\n\n if (this.keyboardManager) {\n this.keyboardManager.destroy();\n }\n\n if (this.transcriptManager) {\n this.transcriptManager.destroy();\n }\n\n // Cleanup sign language video and listeners\n this.cleanupSignLanguage();\n\n // Cleanup play overlay button\n if (this.playButtonOverlay && this.playButtonOverlay.parentNode) {\n this.playButtonOverlay.remove();\n this.playButtonOverlay = null;\n }\n\n // Cleanup resize observer\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n // Cleanup window resize handler\n if (this.resizeHandler) {\n window.removeEventListener('resize', this.resizeHandler);\n this.resizeHandler = null;\n }\n\n // Cleanup orientation change handler\n if (this.orientationQuery && this.orientationHandler) {\n if (this.orientationQuery.removeEventListener) {\n this.orientationQuery.removeEventListener('change', this.orientationHandler);\n } else if (this.orientationQuery.removeListener) {\n this.orientationQuery.removeListener(this.orientationHandler);\n }\n this.orientationQuery = null;\n this.orientationHandler = null;\n }\n\n // Cleanup fullscreen change handler\n if (this.fullscreenChangeHandler) {\n document.removeEventListener('fullscreenchange', this.fullscreenChangeHandler);\n document.removeEventListener('webkitfullscreenchange', this.fullscreenChangeHandler);\n document.removeEventListener('mozfullscreenchange', this.fullscreenChangeHandler);\n document.removeEventListener('MSFullscreenChange', this.fullscreenChangeHandler);\n this.fullscreenChangeHandler = null;\n }\n\n // Cleanup all managed timeouts\n this.timeouts.forEach(timeoutId => clearTimeout(timeoutId));\n this.timeouts.clear();\n\n // Cleanup metadata handling\n if (this.metadataCueChangeHandler) {\n const textTracks = this.textTracks;\n const metadataTrack = textTracks.find(track => track.kind === 'metadata');\n if (metadataTrack) {\n metadataTrack.removeEventListener('cuechange', this.metadataCueChangeHandler);\n }\n this.metadataCueChangeHandler = null;\n }\n\n if (this.metadataAlertHandlers && this.metadataAlertHandlers.size > 0) {\n this.metadataAlertHandlers.forEach(({ button, handler }) => {\n if (button && handler) {\n button.removeEventListener('click', handler);\n }\n });\n this.metadataAlertHandlers.clear();\n }\n\n // Remove container\n if (this.container && this.container.parentNode) {\n this.container.parentNode.insertBefore(this.element, this.container);\n this.container.parentNode.removeChild(this.container);\n }\n\n this.removeAllListeners();\n }\n\n /**\n * Setup metadata track handling\n * This enables metadata tracks and listens for cue changes to trigger actions\n */\n setupMetadataHandling() {\n const setupMetadata = () => {\n const textTracks = this.textTracks;\n const metadataTrack = textTracks.find(track => track.kind === 'metadata');\n \n if (metadataTrack) {\n // Enable the metadata track so cuechange events fire\n // Use 'hidden' mode so it doesn't display anything, but events still work\n if (metadataTrack.mode === 'disabled') {\n metadataTrack.mode = 'hidden';\n }\n \n // Remove existing listener if any\n if (this.metadataCueChangeHandler) {\n metadataTrack.removeEventListener('cuechange', this.metadataCueChangeHandler);\n }\n \n // Add event listener for cue changes\n this.metadataCueChangeHandler = () => {\n const activeCues = Array.from(metadataTrack.activeCues || []);\n if (activeCues.length > 0) {\n // Debug logging\n if (this.options.debug) {\n this.log('[Metadata] Active cues:', activeCues.map(c => ({\n start: c.startTime,\n end: c.endTime,\n text: c.text\n })));\n }\n }\n activeCues.forEach(cue => {\n this.handleMetadataCue(cue);\n });\n };\n \n metadataTrack.addEventListener('cuechange', this.metadataCueChangeHandler);\n \n // Debug: Log metadata track setup\n if (this.options.debug) {\n const cueCount = metadataTrack.cues ? metadataTrack.cues.length : 0;\n this.log('[Metadata] Track enabled,', cueCount, 'cues available');\n }\n } else if (this.options.debug) {\n this.log('[Metadata] No metadata track found');\n }\n };\n \n // Try immediately\n setupMetadata();\n \n // Also try after loadedmetadata event (tracks might not be ready yet)\n this.on('loadedmetadata', setupMetadata);\n }\n\n normalizeMetadataSelector(selector) {\n if (!selector) {\n return null;\n }\n const trimmed = selector.trim();\n if (!trimmed) {\n return null;\n }\n if (trimmed.startsWith('#') || trimmed.startsWith('.') || trimmed.startsWith('[')) {\n return trimmed;\n }\n return `#${trimmed}`;\n }\n\n resolveMetadataConfig(map, key) {\n if (!map || !key) {\n return null;\n }\n if (Object.prototype.hasOwnProperty.call(map, key)) {\n return map[key];\n }\n const withoutHash = key.replace(/^#/, '');\n if (Object.prototype.hasOwnProperty.call(map, withoutHash)) {\n return map[withoutHash];\n }\n return null;\n }\n\n cacheMetadataAlertContent(element, config = {}) {\n if (!element) {\n return;\n }\n const titleSelector = config.titleSelector || '[data-vidply-alert-title], h3, header';\n const messageSelector = config.messageSelector || '[data-vidply-alert-message], p';\n\n const titleEl = element.querySelector(titleSelector);\n if (titleEl && !titleEl.dataset.vidplyAlertTitleOriginal) {\n titleEl.dataset.vidplyAlertTitleOriginal = titleEl.textContent.trim();\n }\n\n const messageEl = element.querySelector(messageSelector);\n if (messageEl && !messageEl.dataset.vidplyAlertMessageOriginal) {\n messageEl.dataset.vidplyAlertMessageOriginal = messageEl.textContent.trim();\n }\n }\n\n restoreMetadataAlertContent(element, config = {}) {\n if (!element) {\n return;\n }\n const titleSelector = config.titleSelector || '[data-vidply-alert-title], h3, header';\n const messageSelector = config.messageSelector || '[data-vidply-alert-message], p';\n\n const titleEl = element.querySelector(titleSelector);\n if (titleEl && titleEl.dataset.vidplyAlertTitleOriginal) {\n titleEl.textContent = titleEl.dataset.vidplyAlertTitleOriginal;\n }\n\n const messageEl = element.querySelector(messageSelector);\n if (messageEl && messageEl.dataset.vidplyAlertMessageOriginal) {\n messageEl.textContent = messageEl.dataset.vidplyAlertMessageOriginal;\n }\n }\n\n focusMetadataTarget(target, fallbackElement = null) {\n if (!target || target === 'none') {\n return;\n }\n\n if (target === 'alert' && fallbackElement) {\n fallbackElement.focus({ preventScroll: true });\n return;\n }\n\n if (target === 'player') {\n if (this.container) {\n this.container.focus({ preventScroll: true });\n }\n return;\n }\n\n if (target === 'media') {\n this.element.focus({ preventScroll: true });\n return;\n }\n\n if (target === 'playButton') {\n const playButton = this.controlBar?.controls?.playPause;\n if (playButton) {\n playButton.focus({ preventScroll: true });\n }\n return;\n }\n\n if (typeof target === 'string') {\n const targetElement = document.querySelector(target);\n if (targetElement) {\n if (targetElement.tabIndex === -1 && !targetElement.hasAttribute('tabindex')) {\n targetElement.setAttribute('tabindex', '-1');\n }\n targetElement.focus({ preventScroll: true });\n }\n }\n }\n\n handleMetadataAlert(selector, options = {}) {\n if (!selector) {\n return;\n }\n\n const config = this.resolveMetadataConfig(this.options.metadataAlerts, selector) || {};\n const element = options.element || document.querySelector(selector);\n\n if (!element) {\n if (this.options.debug) {\n this.log('[Metadata] Alert element not found:', selector);\n }\n return;\n }\n\n if (this.options.debug) {\n this.log('[Metadata] Handling alert', selector, { reason: options.reason, config });\n }\n\n this.cacheMetadataAlertContent(element, config);\n\n if (!element.dataset.vidplyAlertOriginalDisplay) {\n element.dataset.vidplyAlertOriginalDisplay = element.style.display || '';\n }\n\n if (!element.dataset.vidplyAlertDisplay) {\n element.dataset.vidplyAlertDisplay = config.display || 'block';\n }\n\n const shouldShow = options.show !== undefined ? options.show : (config.show !== false);\n if (shouldShow) {\n const displayValue = config.display || element.dataset.vidplyAlertDisplay || 'block';\n element.style.display = displayValue;\n element.hidden = false;\n element.removeAttribute('hidden');\n element.setAttribute('aria-hidden', 'false');\n element.setAttribute('data-vidply-alert-active', 'true');\n }\n\n const shouldReset = config.resetContent !== false && options.reason === 'focus';\n if (shouldReset) {\n this.restoreMetadataAlertContent(element, config);\n }\n\n const shouldFocus = options.focus !== undefined\n ? options.focus\n : (config.focusOnShow ?? (options.reason !== 'focus'));\n\n if (shouldShow && shouldFocus) {\n if (element.tabIndex === -1 && !element.hasAttribute('tabindex')) {\n element.setAttribute('tabindex', '-1');\n }\n element.focus({ preventScroll: true });\n }\n\n if (shouldShow && config.autoScroll !== false && options.autoScroll !== false) {\n element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n }\n\n const continueSelector = config.continueButton;\n if (continueSelector) {\n let continueButton = null;\n if (continueSelector === 'self') {\n continueButton = element;\n } else if (element.matches(continueSelector)) {\n continueButton = element;\n } else {\n continueButton = element.querySelector(continueSelector) || document.querySelector(continueSelector);\n }\n\n if (continueButton && !this.metadataAlertHandlers.has(selector)) {\n const handler = () => {\n const hideOnContinue = config.hideOnContinue !== false;\n if (hideOnContinue) {\n const originalDisplay = element.dataset.vidplyAlertOriginalDisplay || '';\n element.style.display = config.hideDisplay || originalDisplay || 'none';\n element.setAttribute('aria-hidden', 'true');\n element.removeAttribute('data-vidply-alert-active');\n }\n\n if (config.resume !== false && this.state.paused) {\n this.play();\n }\n\n const focusTarget = config.focusTarget || 'playButton';\n this.setManagedTimeout(() => {\n this.focusMetadataTarget(focusTarget, element);\n }, config.focusDelay ?? 100);\n };\n\n continueButton.addEventListener('click', handler);\n this.metadataAlertHandlers.set(selector, { button: continueButton, handler });\n }\n }\n\n return element;\n }\n\n handleMetadataHashtags(hashtags) {\n if (!Array.isArray(hashtags) || hashtags.length === 0) {\n return;\n }\n\n const configMap = this.options.metadataHashtags;\n if (!configMap) {\n return;\n }\n\n hashtags.forEach(tag => {\n const config = this.resolveMetadataConfig(configMap, tag);\n if (!config) {\n return;\n }\n\n const selector = this.normalizeMetadataSelector(config.alert || config.selector || config.target);\n if (!selector) {\n return;\n }\n\n const element = document.querySelector(selector);\n if (!element) {\n if (this.options.debug) {\n this.log('[Metadata] Hashtag target not found:', selector);\n }\n return;\n }\n\n if (this.options.debug) {\n this.log('[Metadata] Handling hashtag', tag, { selector, config });\n }\n\n this.cacheMetadataAlertContent(element, config);\n\n if (config.title) {\n const titleSelector = config.titleSelector || '[data-vidply-alert-title], h3, header';\n const titleEl = element.querySelector(titleSelector);\n if (titleEl) {\n titleEl.textContent = config.title;\n }\n }\n\n if (config.message) {\n const messageSelector = config.messageSelector || '[data-vidply-alert-message], p';\n const messageEl = element.querySelector(messageSelector);\n if (messageEl) {\n messageEl.textContent = config.message;\n }\n }\n\n const show = config.show !== false;\n const focus = config.focus !== undefined ? config.focus : false;\n\n this.handleMetadataAlert(selector, {\n element,\n show,\n focus,\n autoScroll: config.autoScroll,\n reason: 'hashtag'\n });\n });\n }\n\n /**\n * Handle individual metadata cues\n * Parses metadata text and emits events or triggers actions\n */\n handleMetadataCue(cue) {\n const text = cue.text.trim();\n \n // Debug logging\n if (this.options.debug) {\n this.log('[Metadata] Processing cue:', {\n time: cue.startTime,\n text: text\n });\n }\n \n // Emit a generic metadata event that developers can listen to\n this.emit('metadata', {\n time: cue.startTime,\n endTime: cue.endTime,\n text: text,\n cue: cue\n });\n\n // Parse for specific commands (examples based on wwa_meta.vtt format)\n if (text.includes('PAUSE')) {\n // Automatically pause the video\n if (!this.state.paused) {\n if (this.options.debug) {\n this.log('[Metadata] Pausing video at', cue.startTime);\n }\n this.pause();\n }\n // Also emit event for developers who want to listen\n this.emit('metadata:pause', { time: cue.startTime, text: text });\n }\n\n // Parse for focus directives\n const focusMatch = text.match(/FOCUS:([\\w#-]+)/);\n if (focusMatch) {\n const targetSelector = focusMatch[1];\n const normalizedSelector = this.normalizeMetadataSelector(targetSelector);\n // Automatically focus the target element\n const targetElement = normalizedSelector ? document.querySelector(normalizedSelector) : null;\n if (targetElement) {\n if (this.options.debug) {\n this.log('[Metadata] Focusing element:', normalizedSelector);\n }\n // Make element focusable if it isn't already\n if (targetElement.tabIndex === -1 && !targetElement.hasAttribute('tabindex')) {\n targetElement.setAttribute('tabindex', '-1');\n }\n // Use setTimeout to ensure DOM is ready\n this.setManagedTimeout(() => {\n targetElement.focus({ preventScroll: true });\n }, 10);\n } else if (this.options.debug) {\n this.log('[Metadata] Element not found:', normalizedSelector || targetSelector);\n }\n // Also emit event for developers who want to listen\n this.emit('metadata:focus', { \n time: cue.startTime, \n target: targetSelector,\n selector: normalizedSelector,\n element: targetElement,\n text: text \n });\n\n if (normalizedSelector) {\n this.handleMetadataAlert(normalizedSelector, {\n element: targetElement,\n reason: 'focus'\n });\n }\n }\n\n // Parse for hashtag references\n const hashtags = text.match(/#[\\w-]+/g);\n if (hashtags) {\n if (this.options.debug) {\n this.log('[Metadata] Hashtags found:', hashtags);\n }\n this.emit('metadata:hashtags', {\n time: cue.startTime,\n hashtags: hashtags,\n text: text\n });\n\n this.handleMetadataHashtags(hashtags);\n }\n }\n}\n\n// Static instances tracker for pause others functionality\nPlayer.instances = [];\n\n", "/**\n * VidPly Playlist Manager\n * Manages playlists for audio and video content\n */\n\nimport { DOMUtils } from '../utils/DOMUtils.js';\nimport { createIconElement } from '../icons/Icons.js';\nimport { i18n } from '../i18n/i18n.js';\nimport { TimeUtils } from '../utils/TimeUtils.js';\n\n// Static counter for unique IDs\nlet playlistInstanceCounter = 0;\n\nexport class PlaylistManager {\n constructor(player, options = {}) {\n this.player = player;\n this.tracks = [];\n this.initialTracks = Array.isArray(options.tracks) ? options.tracks : [];\n this.currentIndex = -1;\n \n // Generate unique instance ID for this playlist\n this.instanceId = ++playlistInstanceCounter;\n this.uniqueId = `vidply-playlist-${this.instanceId}`;\n \n // Options\n this.options = {\n autoAdvance: options.autoAdvance !== false, // Default true\n autoPlayFirst: options.autoPlayFirst !== false, // Default true - auto-play first track on load\n loop: options.loop || false,\n showPanel: options.showPanel !== false, // Default true\n recreatePlayers: options.recreatePlayers || false, // New: recreate player for each track type\n ...options\n };\n \n // UI elements\n this.container = null;\n this.playlistPanel = null;\n this.trackInfoElement = null;\n this.navigationFeedback = null; // Live region for keyboard navigation feedback\n this.isPanelVisible = this.options.showPanel !== false;\n \n // Track change guard to prevent cascade of next() calls\n this.isChangingTrack = false;\n \n // Store the host element for player recreation\n this.hostElement = options.hostElement || null;\n this.PlayerClass = options.PlayerClass || null;\n \n // Bind methods\n this.handleTrackEnd = this.handleTrackEnd.bind(this);\n this.handleTrackError = this.handleTrackError.bind(this);\n \n // Register this playlist manager with the player\n this.player.playlistManager = this;\n \n // Initialize\n this.init();\n \n // Update controls to add playlist buttons\n this.updatePlayerControls();\n \n // Load tracks if provided in options (after UI is ready)\n if (this.initialTracks.length > 0) {\n this.loadPlaylist(this.initialTracks);\n }\n }\n \n /**\n * Determine the media type for a track\n * @param {Object} track - Track object\n * @returns {string} - 'audio', 'video', 'youtube', 'vimeo', 'soundcloud', 'hls'\n */\n getTrackMediaType(track) {\n const src = track.src || '';\n \n if (src.includes('youtube.com') || src.includes('youtu.be')) {\n return 'youtube';\n }\n if (src.includes('vimeo.com')) {\n return 'vimeo';\n }\n if (src.includes('soundcloud.com') || src.includes('api.soundcloud.com')) {\n return 'soundcloud';\n }\n if (src.includes('.m3u8')) {\n return 'hls';\n }\n if (track.type && track.type.startsWith('audio/')) {\n return 'audio';\n }\n // Default to video for video types or unknown\n return 'video';\n }\n \n /**\n * Recreate the player with the appropriate element type for the track\n * @param {Object} track - Track to load\n * @param {boolean} autoPlay - Whether to auto-play after creation\n */\n async recreatePlayerForTrack(track, autoPlay = false) {\n if (!this.hostElement || !this.PlayerClass) {\n console.warn('VidPly Playlist: Cannot recreate player - missing hostElement or PlayerClass');\n return false;\n }\n \n const mediaType = this.getTrackMediaType(track);\n // SoundCloud uses an iframe widget, so it doesn't need an audio element\n // Only local audio files need an actual <audio> element\n const elementType = (mediaType === 'audio') ? 'audio' : 'video';\n \n // Store playlist panel state\n const wasVisible = this.isPanelVisible;\n const savedTracks = [...this.tracks]; // Keep track data\n const savedIndex = this.currentIndex;\n \n // Detach all playlist UI elements from DOM (keep references)\n // These will be reattached to the new player container\n if (this.trackArtworkElement && this.trackArtworkElement.parentNode) {\n this.trackArtworkElement.parentNode.removeChild(this.trackArtworkElement);\n }\n if (this.trackInfoElement && this.trackInfoElement.parentNode) {\n this.trackInfoElement.parentNode.removeChild(this.trackInfoElement);\n }\n if (this.navigationFeedback && this.navigationFeedback.parentNode) {\n this.navigationFeedback.parentNode.removeChild(this.navigationFeedback);\n }\n if (this.playlistPanel && this.playlistPanel.parentNode) {\n this.playlistPanel.parentNode.removeChild(this.playlistPanel);\n }\n \n // Remove event listeners before destroying\n if (this.player) {\n this.player.off('ended', this.handleTrackEnd);\n this.player.off('error', this.handleTrackError);\n this.player.destroy();\n }\n \n // Clear the host element\n this.hostElement.innerHTML = '';\n \n // Create new media element with appropriate type\n const mediaElement = document.createElement(elementType);\n mediaElement.setAttribute('preload', 'metadata');\n \n // For video elements with local media, set poster\n if (elementType === 'video' && track.poster && \n (mediaType === 'video' || mediaType === 'hls')) {\n mediaElement.setAttribute('poster', track.poster);\n }\n \n // For external renderers (YouTube, Vimeo, SoundCloud, HLS), don't add source\n // The renderer will handle the source directly\n const isExternalRenderer = ['youtube', 'vimeo', 'soundcloud', 'hls'].includes(mediaType);\n \n if (!isExternalRenderer) {\n // Add source for HTML5 media\n const source = document.createElement('source');\n source.src = track.src;\n if (track.type) {\n source.type = track.type;\n }\n mediaElement.appendChild(source);\n \n // Add tracks (captions, chapters, etc.)\n if (track.tracks && track.tracks.length > 0) {\n track.tracks.forEach(trackConfig => {\n const trackEl = document.createElement('track');\n trackEl.src = trackConfig.src;\n trackEl.kind = trackConfig.kind || 'captions';\n trackEl.srclang = trackConfig.srclang || 'en';\n trackEl.label = trackConfig.label || trackConfig.srclang;\n if (trackConfig.default) {\n trackEl.default = true;\n }\n mediaElement.appendChild(trackEl);\n });\n }\n }\n \n this.hostElement.appendChild(mediaElement);\n \n // Create new player with the media element\n // Pass the source for external renderers via options\n const playerOptions = {\n mediaType: elementType,\n poster: track.poster,\n audioDescriptionSrc: track.audioDescriptionSrc || null,\n audioDescriptionDuration: track.audioDescriptionDuration || null,\n signLanguageSrc: track.signLanguageSrc || null\n };\n \n this.player = new this.PlayerClass(mediaElement, playerOptions);\n \n // Re-register playlist manager\n this.player.playlistManager = this;\n \n // Wait for player to be ready\n await new Promise(resolve => {\n this.player.on('ready', resolve);\n });\n \n // Re-attach event listeners\n this.player.on('ended', this.handleTrackEnd);\n this.player.on('error', this.handleTrackError);\n \n // Re-attach all playlist UI elements to the new player's container\n if (this.player.container) {\n // Track artwork goes before video wrapper\n if (this.trackArtworkElement) {\n const videoWrapper = this.player.container.querySelector('.vidply-video-wrapper');\n if (videoWrapper) {\n this.player.container.insertBefore(this.trackArtworkElement, videoWrapper);\n } else {\n this.player.container.appendChild(this.trackArtworkElement);\n }\n }\n // Track info\n if (this.trackInfoElement) {\n this.player.container.appendChild(this.trackInfoElement);\n }\n // Navigation feedback (screen reader only)\n if (this.navigationFeedback) {\n this.player.container.appendChild(this.navigationFeedback);\n }\n // Playlist panel\n if (this.playlistPanel) {\n this.player.container.appendChild(this.playlistPanel);\n }\n }\n \n // Update container reference\n this.container = this.player.container;\n \n // Update controls (adds playlist prev/next buttons)\n this.updatePlayerControls();\n \n // Restore tracks data (we kept it during recreation)\n this.tracks = savedTracks;\n this.currentIndex = savedIndex;\n \n // Update playlist UI to reflect current state\n this.updatePlaylistUI();\n \n // Restore playlist panel visibility\n this.isPanelVisible = wasVisible;\n if (this.playlistPanel) {\n this.playlistPanel.style.display = wasVisible ? '' : 'none';\n }\n \n // For external renderers, load the track via player.load()\n // For HTML5, the source is already set on the element\n if (isExternalRenderer) {\n this.player.load({\n src: track.src,\n type: track.type,\n poster: track.poster,\n tracks: track.tracks || [],\n audioDescriptionSrc: track.audioDescriptionSrc || null,\n signLanguageSrc: track.signLanguageSrc || null\n });\n } else {\n // For HTML5 media, also load to set up accessibility features\n this.player.load({\n src: track.src,\n type: track.type,\n poster: track.poster,\n tracks: track.tracks || [],\n audioDescriptionSrc: track.audioDescriptionSrc || null,\n signLanguageSrc: track.signLanguageSrc || null\n });\n }\n \n // Auto-play if requested\n if (autoPlay) {\n setTimeout(() => {\n this.player.play();\n }, 100);\n }\n \n return true;\n }\n \n init() {\n // Listen for track end\n this.player.on('ended', this.handleTrackEnd);\n this.player.on('error', this.handleTrackError);\n \n // Listen for playback state changes to show/hide playlist in fullscreen\n this.player.on('play', this.handlePlaybackStateChange.bind(this));\n this.player.on('pause', this.handlePlaybackStateChange.bind(this));\n this.player.on('ended', this.handlePlaybackStateChange.bind(this));\n // Use fullscreenchange event which is what the player actually emits\n this.player.on('fullscreenchange', this.handleFullscreenChange.bind(this));\n \n // Listen for audio description state changes to update duration displays\n this.player.on('audiodescriptionenabled', this.handleAudioDescriptionChange.bind(this));\n this.player.on('audiodescriptiondisabled', this.handleAudioDescriptionChange.bind(this));\n \n // Create UI if needed\n if (this.options.showPanel) {\n this.createUI();\n }\n \n // Check for data-playlist attribute on player container (only if tracks weren't provided in options)\n if (this.tracks.length === 0 && this.initialTracks.length === 0) {\n this.loadPlaylistFromAttribute();\n }\n }\n \n /**\n * Load playlist from data-playlist attribute if present\n */\n loadPlaylistFromAttribute() {\n // Check the original wrapper element for data-playlist\n // Structure: #audio-player -> .vidply-player -> .vidply-video-wrapper -> <audio>\n // So we need to go up 3 levels\n if (!this.player.element || !this.player.element.parentElement) {\n console.log('VidPly Playlist: No player element found');\n return;\n }\n \n const videoWrapper = this.player.element.parentElement; // .vidply-video-wrapper\n const playerContainer = videoWrapper.parentElement; // .vidply-player\n const originalElement = playerContainer ? playerContainer.parentElement : null; // #audio-player (original div)\n \n if (!originalElement) {\n console.log('VidPly Playlist: No original element found');\n return;\n }\n \n // Load playlist options from data attributes\n this.loadOptionsFromAttributes(originalElement);\n \n const playlistData = originalElement.getAttribute('data-playlist');\n if (!playlistData) {\n console.log('VidPly Playlist: No data-playlist attribute found');\n return;\n }\n \n console.log('VidPly Playlist: Found data-playlist attribute, parsing...');\n try {\n const tracks = JSON.parse(playlistData);\n if (Array.isArray(tracks) && tracks.length > 0) {\n console.log(`VidPly Playlist: Loaded ${tracks.length} tracks from data-playlist`);\n this.loadPlaylist(tracks);\n } else {\n console.warn('VidPly Playlist: data-playlist is not a valid array or is empty');\n }\n } catch (error) {\n console.error('VidPly Playlist: Failed to parse data-playlist attribute', error);\n }\n }\n \n /**\n * Load playlist options from data attributes\n * @param {HTMLElement} element - Element to read attributes from\n */\n loadOptionsFromAttributes(element) {\n // data-playlist-auto-advance\n const autoAdvance = element.getAttribute('data-playlist-auto-advance');\n if (autoAdvance !== null) {\n this.options.autoAdvance = autoAdvance === 'true';\n }\n \n // data-playlist-auto-play-first\n const autoPlayFirst = element.getAttribute('data-playlist-auto-play-first');\n if (autoPlayFirst !== null) {\n this.options.autoPlayFirst = autoPlayFirst === 'true';\n }\n \n // data-playlist-loop\n const loop = element.getAttribute('data-playlist-loop');\n if (loop !== null) {\n this.options.loop = loop === 'true';\n }\n \n // data-playlist-show-panel\n const showPanel = element.getAttribute('data-playlist-show-panel');\n if (showPanel !== null) {\n this.options.showPanel = showPanel === 'true';\n }\n \n console.log('VidPly Playlist: Options from attributes:', this.options);\n }\n \n /**\n * Update player controls to add playlist navigation buttons\n */\n updatePlayerControls() {\n if (!this.player.controlBar) return;\n \n const controlBar = this.player.controlBar;\n \n // Clear existing controls content (except the element itself)\n controlBar.element.innerHTML = '';\n \n // Recreate controls with playlist buttons now available\n controlBar.createControls();\n \n // Reattach events for the new controls\n controlBar.attachEvents();\n controlBar.setupAutoHide();\n }\n \n /**\n * Load a playlist\n * @param {Array} tracks - Array of track objects\n */\n loadPlaylist(tracks) {\n this.tracks = tracks;\n this.currentIndex = -1;\n \n // Add playlist class to container\n if (this.container) {\n this.container.classList.add('vidply-has-playlist');\n }\n \n // Update UI\n if (this.playlistPanel) {\n this.renderPlaylist();\n }\n \n // Auto-play first track (if enabled)\n if (tracks.length > 0) {\n if (this.options.autoPlayFirst) {\n this.play(0);\n } else {\n // Load first track without playing\n this.loadTrack(0);\n }\n }\n \n // Update visibility based on current state\n this.updatePlaylistVisibilityInFullscreen();\n }\n \n /**\n * Load a track without playing\n * @param {number} index - Track index\n */\n async loadTrack(index) {\n if (index < 0 || index >= this.tracks.length) {\n console.warn('VidPly Playlist: Invalid track index', index);\n return;\n }\n \n const track = this.tracks[index];\n \n // Set guard flag to prevent cascade of next() calls during track change\n this.isChangingTrack = true;\n \n // Update current index\n this.currentIndex = index;\n \n // Check if we should recreate the player for this track type\n if (this.options.recreatePlayers && this.hostElement && this.PlayerClass) {\n const currentMediaType = this.player ? \n (this.player.element.tagName === 'AUDIO' ? 'audio' : 'video') : null;\n const newMediaType = this.getTrackMediaType(track);\n const newElementType = (newMediaType === 'audio' || newMediaType === 'soundcloud') ? 'audio' : 'video';\n \n // Recreate if element type is different\n if (currentMediaType !== newElementType) {\n await this.recreatePlayerForTrack(track, false);\n // Update UI after recreation\n this.updateTrackInfo(track);\n this.updatePlaylistUI();\n \n // Emit event\n this.player.emit('playlisttrackchange', {\n index: index,\n item: track,\n total: this.tracks.length\n });\n \n // Clear guard flag\n setTimeout(() => {\n this.isChangingTrack = false;\n }, 150);\n return;\n }\n }\n \n // Load track into player (normal path)\n this.player.load({\n src: track.src,\n type: track.type,\n poster: track.poster,\n tracks: track.tracks || [],\n audioDescriptionSrc: track.audioDescriptionSrc || null,\n signLanguageSrc: track.signLanguageSrc || null\n });\n \n // Update UI\n this.updateTrackInfo(track);\n this.updatePlaylistUI();\n \n // Emit event\n this.player.emit('playlisttrackchange', {\n index: index,\n item: track,\n total: this.tracks.length\n });\n \n // Clear guard flag after a short delay to ensure track is loaded\n setTimeout(() => {\n this.isChangingTrack = false;\n }, 150);\n }\n \n /**\n * Play a specific track\n * @param {number} index - Track index\n * @param {boolean} userInitiated - Whether this was triggered by user action (default: false)\n */\n async play(index, userInitiated = false) {\n if (index < 0 || index >= this.tracks.length) {\n console.warn('VidPly Playlist: Invalid track index', index);\n return;\n }\n \n const track = this.tracks[index];\n \n // Set guard flag to prevent cascade of next() calls during track change\n this.isChangingTrack = true;\n \n // Update current index\n this.currentIndex = index;\n \n // Check if we should recreate the player for this track type\n if (this.options.recreatePlayers && this.hostElement && this.PlayerClass) {\n const currentMediaType = this.player ? \n (this.player.element.tagName === 'AUDIO' ? 'audio' : 'video') : null;\n const newMediaType = this.getTrackMediaType(track);\n const newElementType = (newMediaType === 'audio' || newMediaType === 'soundcloud') ? 'audio' : 'video';\n \n // Recreate if element type is different\n if (currentMediaType !== newElementType) {\n await this.recreatePlayerForTrack(track, true); // true = autoPlay\n // Update UI after recreation\n this.updateTrackInfo(track);\n this.updatePlaylistUI();\n \n // Emit event\n this.player.emit('playlisttrackchange', {\n index: index,\n item: track,\n total: this.tracks.length\n });\n \n // Clear guard flag\n setTimeout(() => {\n this.isChangingTrack = false;\n }, 150);\n return;\n }\n }\n \n // Load track into player (normal path)\n this.player.load({\n src: track.src,\n type: track.type,\n poster: track.poster,\n tracks: track.tracks || [],\n audioDescriptionSrc: track.audioDescriptionSrc || null,\n signLanguageSrc: track.signLanguageSrc || null\n });\n \n // Update UI\n this.updateTrackInfo(track);\n this.updatePlaylistUI();\n \n // Emit event\n this.player.emit('playlisttrackchange', {\n index: index,\n item: track,\n total: this.tracks.length\n });\n \n // Auto-play and clear guard flag after playback starts\n setTimeout(() => {\n this.player.play();\n // Clear guard flag after a short delay to ensure track has started\n setTimeout(() => {\n this.isChangingTrack = false;\n }, 50);\n }, 100);\n }\n \n /**\n * Play next track\n */\n next() {\n let nextIndex = this.currentIndex + 1;\n \n if (nextIndex >= this.tracks.length) {\n if (this.options.loop) {\n nextIndex = 0;\n } else {\n return;\n }\n }\n \n this.play(nextIndex);\n }\n \n /**\n * Play previous track\n */\n previous() {\n let prevIndex = this.currentIndex - 1;\n \n if (prevIndex < 0) {\n if (this.options.loop) {\n prevIndex = this.tracks.length - 1;\n } else {\n return;\n }\n }\n \n this.play(prevIndex);\n }\n \n /**\n * Handle track end\n */\n handleTrackEnd() {\n // Don't auto-advance if we're already in the process of changing tracks\n // This prevents a cascade of next() calls when loading a new track triggers an 'ended' event\n if (this.isChangingTrack) {\n return;\n }\n \n if (this.options.autoAdvance) {\n this.next();\n }\n }\n \n /**\n * Check if a source URL requires an external renderer\n * @param {string} src - Source URL\n * @returns {boolean}\n */\n isExternalRendererUrl(src) {\n if (!src) return false;\n return src.includes('youtube.com') || \n src.includes('youtu.be') || \n src.includes('vimeo.com') || \n src.includes('soundcloud.com') || \n src.includes('api.soundcloud.com') ||\n src.includes('.m3u8');\n }\n\n /**\n * Handle track error\n */\n handleTrackError(e) {\n // Don't auto-advance for external renderer tracks\n // External renderers (YouTube, Vimeo, SoundCloud, HLS) may trigger HTML5 errors\n // that should be ignored since the external renderer handles playback\n const currentTrack = this.getCurrentTrack();\n if (currentTrack && currentTrack.src && this.isExternalRendererUrl(currentTrack.src)) {\n // Silently ignore errors for external renderer tracks\n return;\n }\n \n // Don't auto-advance if we're in the process of changing tracks\n // This prevents a cascade of next() calls when switching between renderer types\n if (this.isChangingTrack) {\n return;\n }\n \n console.error('VidPly Playlist: Track error', e);\n \n // Try next track\n if (this.options.autoAdvance) {\n setTimeout(() => {\n this.next();\n }, 1000);\n }\n }\n \n /**\n * Handle playback state changes (for fullscreen playlist visibility)\n */\n handlePlaybackStateChange() {\n this.updatePlaylistVisibilityInFullscreen();\n }\n \n /**\n * Handle fullscreen state changes\n */\n handleFullscreenChange() {\n // Use a small delay to ensure fullscreen state is fully applied\n setTimeout(() => {\n this.updatePlaylistVisibilityInFullscreen();\n }, 50);\n }\n \n /**\n * Handle audio description state changes\n * Updates duration displays to show audio-described version duration when AD is enabled\n */\n handleAudioDescriptionChange() {\n const currentTrack = this.getCurrentTrack();\n if (!currentTrack) return;\n \n // Update the track info display with the appropriate duration\n this.updateTrackInfo(currentTrack);\n \n // Update the playlist UI to reflect duration changes (aria-labels)\n this.updatePlaylistUI();\n \n // Update visual duration elements in playlist panel\n this.updatePlaylistDurations();\n }\n \n /**\n * Update the visual duration displays in the playlist panel\n * Called when audio description state changes\n */\n updatePlaylistDurations() {\n if (!this.playlistPanel) return;\n \n const items = this.playlistPanel.querySelectorAll('.vidply-playlist-item');\n \n items.forEach((item, index) => {\n const track = this.tracks[index];\n if (!track) return;\n \n const effectiveDuration = this.getEffectiveDuration(track);\n const trackDuration = effectiveDuration ? TimeUtils.formatTime(effectiveDuration) : '';\n \n // Update duration badge on thumbnail (if exists)\n const durationBadge = item.querySelector('.vidply-playlist-duration-badge');\n if (durationBadge) {\n durationBadge.textContent = trackDuration;\n }\n \n // Update inline duration (if exists)\n const inlineDuration = item.querySelector('.vidply-playlist-item-duration');\n if (inlineDuration) {\n inlineDuration.textContent = trackDuration;\n }\n });\n }\n \n /**\n * Get the effective duration for a track based on audio description state\n * @param {Object} track - Track object\n * @returns {number|null} - Duration in seconds or null if not available\n */\n getEffectiveDuration(track) {\n if (!track) return null;\n \n const isAudioDescriptionEnabled = this.player.state.audioDescriptionEnabled;\n \n // If audio description is enabled and track has audioDescriptionDuration, use it\n if (isAudioDescriptionEnabled && track.audioDescriptionDuration) {\n return track.audioDescriptionDuration;\n }\n \n // Otherwise use regular duration\n return track.duration || null;\n }\n \n /**\n * Update playlist visibility based on fullscreen and playback state\n * In fullscreen: show when paused/not started, hide when playing\n * Outside fullscreen: respect original panel visibility setting\n */\n updatePlaylistVisibilityInFullscreen() {\n if (!this.playlistPanel || !this.tracks.length) return;\n \n const isFullscreen = this.player.state.fullscreen;\n const isPlaying = this.player.state.playing;\n \n if (isFullscreen) {\n // In fullscreen: show only when not playing (paused or not started)\n // Check playing state explicitly since paused might not be set initially\n if (!isPlaying) {\n this.playlistPanel.classList.add('vidply-playlist-fullscreen-visible');\n this.playlistPanel.style.display = 'block';\n } else {\n this.playlistPanel.classList.remove('vidply-playlist-fullscreen-visible');\n // Add a smooth fade out with delay to match CSS transition\n setTimeout(() => {\n // Double-check state hasn't changed before hiding\n if (this.player.state.playing && this.player.state.fullscreen) {\n this.playlistPanel.style.display = 'none';\n }\n }, 300); // Match CSS transition duration\n }\n } else {\n // Outside fullscreen: restore original behavior\n this.playlistPanel.classList.remove('vidply-playlist-fullscreen-visible');\n if (this.isPanelVisible && this.tracks.length > 0) {\n this.playlistPanel.style.display = 'block';\n } else {\n this.playlistPanel.style.display = 'none';\n }\n }\n }\n \n /**\n * Create playlist UI\n */\n createUI() {\n // Find player container\n this.container = this.player.container;\n \n if (!this.container) {\n console.warn('VidPly Playlist: No container found');\n return;\n }\n \n // Create track artwork element (shows album art/poster for audio playlists)\n // Only create for audio players\n if (this.player.element.tagName === 'AUDIO') {\n this.trackArtworkElement = DOMUtils.createElement('div', {\n className: 'vidply-track-artwork',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n this.trackArtworkElement.style.display = 'none';\n \n // Insert before video wrapper\n const videoWrapper = this.container.querySelector('.vidply-video-wrapper');\n if (videoWrapper) {\n this.container.insertBefore(this.trackArtworkElement, videoWrapper);\n } else {\n this.container.appendChild(this.trackArtworkElement);\n }\n }\n \n // Create track info element (shows current track)\n this.trackInfoElement = DOMUtils.createElement('div', {\n className: 'vidply-track-info',\n attributes: {\n role: 'status'\n }\n });\n this.trackInfoElement.style.display = 'none';\n \n this.container.appendChild(this.trackInfoElement);\n \n // Create navigation feedback live region\n this.navigationFeedback = DOMUtils.createElement('div', {\n className: 'vidply-sr-only',\n attributes: {\n role: 'status',\n 'aria-live': 'polite',\n 'aria-atomic': 'true'\n }\n });\n this.container.appendChild(this.navigationFeedback);\n \n // Create playlist panel with proper landmark\n this.playlistPanel = DOMUtils.createElement('div', {\n className: 'vidply-playlist-panel',\n attributes: {\n id: `${this.uniqueId}-panel`,\n role: 'region',\n 'aria-label': i18n.t('playlist.title'),\n 'aria-labelledby': `${this.uniqueId}-heading`\n }\n });\n this.playlistPanel.style.display = this.isPanelVisible ? 'none' : 'none'; // Will be shown when playlist is loaded\n \n this.container.appendChild(this.playlistPanel);\n }\n \n /**\n * Update track info display\n */\n updateTrackInfo(track) {\n if (!this.trackInfoElement) return;\n \n const trackNumber = this.currentIndex + 1;\n const totalTracks = this.tracks.length;\n const trackTitle = track.title || i18n.t('playlist.untitled');\n const trackArtist = track.artist || '';\n \n // Use effective duration (audio description duration when AD is enabled)\n const effectiveDuration = this.getEffectiveDuration(track);\n const trackDuration = effectiveDuration ? TimeUtils.formatTime(effectiveDuration) : '';\n const trackDurationReadable = effectiveDuration ? TimeUtils.formatDuration(effectiveDuration) : '';\n \n // Screen reader announcement - include duration if available\n const artistPart = trackArtist ? i18n.t('playlist.by') + trackArtist : '';\n const durationPart = trackDurationReadable ? `. ${trackDurationReadable}` : '';\n const announcement = i18n.t('playlist.nowPlaying', {\n current: trackNumber,\n total: totalTracks,\n title: trackTitle,\n artist: artistPart\n }) + durationPart;\n \n const trackOfText = i18n.t('playlist.trackOf', {\n current: trackNumber,\n total: totalTracks\n });\n \n // Build duration HTML if available\n const durationHtml = trackDuration \n ? `<span class=\"vidply-track-duration\" aria-hidden=\"true\">${DOMUtils.escapeHTML(trackDuration)}</span>` \n : '';\n \n // Get description if available\n const trackDescription = track.description || '';\n \n this.trackInfoElement.innerHTML = `\n <span class=\"vidply-sr-only\">${DOMUtils.escapeHTML(announcement)}</span>\n <div class=\"vidply-track-header\" aria-hidden=\"true\">\n <span class=\"vidply-track-number\">${DOMUtils.escapeHTML(trackOfText)}</span>\n ${durationHtml}\n </div>\n <div class=\"vidply-track-title\" aria-hidden=\"true\">${DOMUtils.escapeHTML(trackTitle)}</div>\n ${trackArtist ? `<div class=\"vidply-track-artist\" aria-hidden=\"true\">${DOMUtils.escapeHTML(trackArtist)}</div>` : ''}\n ${trackDescription ? `<div class=\"vidply-track-description\" aria-hidden=\"true\">${DOMUtils.escapeHTML(trackDescription)}</div>` : ''}\n `;\n \n this.trackInfoElement.style.display = 'block';\n \n // Update track artwork if available (for audio playlists)\n this.updateTrackArtwork(track);\n }\n \n /**\n * Update track artwork display (for audio playlists)\n */\n updateTrackArtwork(track) {\n if (!this.trackArtworkElement) return;\n \n // If track has a poster/artwork, show it\n if (track.poster) {\n this.trackArtworkElement.style.backgroundImage = `url(${track.poster})`;\n this.trackArtworkElement.style.display = 'block';\n } else {\n // No artwork available, hide the element\n this.trackArtworkElement.style.display = 'none';\n }\n }\n \n /**\n * Render playlist\n */\n renderPlaylist() {\n if (!this.playlistPanel) return;\n \n // Clear existing\n this.playlistPanel.innerHTML = '';\n \n // Create header\n const header = DOMUtils.createElement('h2', {\n className: 'vidply-playlist-header',\n attributes: {\n id: `${this.uniqueId}-heading`\n }\n });\n header.textContent = `${i18n.t('playlist.title')} (${this.tracks.length})`;\n this.playlistPanel.appendChild(header);\n \n // Add keyboard instructions (visually hidden)\n const instructions = DOMUtils.createElement('div', {\n className: 'vidply-sr-only',\n attributes: {\n id: `${this.uniqueId}-keyboard-instructions`\n }\n });\n instructions.textContent = 'Playlist navigation: Use Up and Down arrow keys to move between tracks. Press Page Up or Page Down to skip 5 tracks. Press Home to go to first track, End to go to last track. Press Enter or Space to play the selected track.';\n this.playlistPanel.appendChild(instructions);\n \n // Create list (proper ul element)\n const list = DOMUtils.createElement('ul', {\n className: 'vidply-playlist-list',\n attributes: {\n role: 'listbox',\n 'aria-labelledby': `${this.uniqueId}-heading`,\n 'aria-describedby': `${this.uniqueId}-keyboard-instructions`\n }\n });\n \n this.tracks.forEach((track, index) => {\n const item = this.createPlaylistItem(track, index);\n list.appendChild(item);\n });\n \n this.playlistPanel.appendChild(list);\n \n // Show panel if it should be visible\n if (this.isPanelVisible) {\n this.playlistPanel.style.display = 'block';\n }\n }\n \n /**\n * Create playlist item element\n */\n createPlaylistItem(track, index) {\n const trackPosition = i18n.t('playlist.trackOf', {\n current: index + 1,\n total: this.tracks.length\n });\n const trackTitle = track.title || i18n.t('playlist.trackUntitled', { number: index + 1 });\n const trackArtist = track.artist ? i18n.t('playlist.by') + track.artist : '';\n \n // Use effective duration (audio description duration when AD is enabled)\n const effectiveDuration = this.getEffectiveDuration(track);\n const trackDuration = effectiveDuration ? TimeUtils.formatTime(effectiveDuration) : '';\n const trackDurationReadable = effectiveDuration ? TimeUtils.formatDuration(effectiveDuration) : '';\n const isActive = index === this.currentIndex;\n \n // Build accessible label for screen readers\n // With role=\"option\" and aria-checked, screen reader will announce selection state\n // Position is already announced via aria-posinset/aria-setsize\n // Format: \"Title by Artist. 3 minutes, 45 seconds.\"\n let ariaLabel = `${trackTitle}${trackArtist}`;\n if (trackDurationReadable) {\n ariaLabel += `. ${trackDurationReadable}`;\n }\n \n // Create list item container (semantic HTML)\n const item = DOMUtils.createElement('li', {\n className: isActive ? 'vidply-playlist-item vidply-playlist-item-active' : 'vidply-playlist-item',\n attributes: {\n 'data-playlist-index': index\n }\n });\n \n // Create button wrapper for interactive content\n const button = DOMUtils.createElement('button', {\n className: 'vidply-playlist-item-button',\n attributes: {\n type: 'button',\n role: 'option',\n tabIndex: index === 0 ? 0 : -1, // Only first item is in tab order initially\n 'aria-label': ariaLabel,\n 'aria-posinset': index + 1,\n 'aria-setsize': this.tracks.length,\n 'aria-checked': isActive ? 'true' : 'false'\n }\n });\n \n // Add aria-current if active\n if (isActive) {\n button.setAttribute('aria-current', 'true');\n button.setAttribute('tabIndex', '0'); // Active item should always be tabbable\n }\n \n // Thumbnail container with optional duration badge\n const thumbnailContainer = DOMUtils.createElement('span', {\n className: 'vidply-playlist-thumbnail-container',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n \n // Thumbnail or icon\n const thumbnail = DOMUtils.createElement('span', {\n className: 'vidply-playlist-thumbnail'\n });\n \n if (track.poster) {\n thumbnail.style.backgroundImage = `url(${track.poster})`;\n } else {\n // Show music/speaker icon for audio tracks\n const icon = createIconElement('music');\n icon.classList.add('vidply-playlist-thumbnail-icon');\n thumbnail.appendChild(icon);\n }\n \n thumbnailContainer.appendChild(thumbnail);\n \n // Duration badge on thumbnail (like YouTube) - only show if there's a poster\n if (trackDuration && track.poster) {\n const durationBadge = DOMUtils.createElement('span', {\n className: 'vidply-playlist-duration-badge'\n });\n durationBadge.textContent = trackDuration;\n thumbnailContainer.appendChild(durationBadge);\n }\n \n button.appendChild(thumbnailContainer);\n \n // Info section (title, artist, description)\n const info = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-info',\n attributes: {\n 'aria-hidden': 'true'\n }\n });\n \n // Title row with optional inline duration (for when no thumbnail)\n const titleRow = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-title-row'\n });\n \n const title = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-title'\n });\n title.textContent = trackTitle;\n titleRow.appendChild(title);\n \n // Inline duration (shown when no poster/thumbnail)\n if (trackDuration && !track.poster) {\n const inlineDuration = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-duration'\n });\n inlineDuration.textContent = trackDuration;\n titleRow.appendChild(inlineDuration);\n }\n \n info.appendChild(titleRow);\n \n // Artist\n if (track.artist) {\n const artist = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-artist'\n });\n artist.textContent = track.artist;\n info.appendChild(artist);\n }\n \n // Description (truncated)\n if (track.description) {\n const description = DOMUtils.createElement('span', {\n className: 'vidply-playlist-item-description'\n });\n description.textContent = track.description;\n info.appendChild(description);\n }\n \n button.appendChild(info);\n \n // Play icon\n const playIcon = createIconElement('play');\n playIcon.classList.add('vidply-playlist-item-icon');\n playIcon.setAttribute('aria-hidden', 'true');\n button.appendChild(playIcon);\n \n // Click handler\n button.addEventListener('click', () => {\n this.play(index, true); // User-initiated\n });\n \n // Keyboard handler\n button.addEventListener('keydown', (e) => {\n this.handlePlaylistItemKeydown(e, index);\n });\n \n // Append button to list item\n item.appendChild(button);\n \n return item;\n }\n \n /**\n * Handle keyboard navigation in playlist items\n */\n handlePlaylistItemKeydown(e, index) {\n const buttons = Array.from(this.playlistPanel.querySelectorAll('.vidply-playlist-item-button'));\n let newIndex = -1;\n let announcement = '';\n \n switch(e.key) {\n case 'Enter':\n case ' ':\n e.preventDefault();\n e.stopPropagation();\n this.play(index, true); // User-initiated\n return; // No need to move focus\n \n case 'ArrowDown':\n e.preventDefault();\n e.stopPropagation();\n // Move to next item\n if (index < buttons.length - 1) {\n newIndex = index + 1;\n } else {\n // At the end, announce boundary\n announcement = `End of playlist. ${buttons.length} of ${buttons.length}.`;\n }\n break;\n \n case 'ArrowUp':\n e.preventDefault();\n e.stopPropagation();\n // Move to previous item\n if (index > 0) {\n newIndex = index - 1;\n } else {\n // At the beginning, announce boundary\n announcement = 'Beginning of playlist. 1 of ' + buttons.length + '.';\n }\n break;\n \n case 'PageDown':\n e.preventDefault();\n e.stopPropagation();\n // Move 5 items down (or to end)\n newIndex = Math.min(index + 5, buttons.length - 1);\n if (newIndex === buttons.length - 1 && index !== newIndex) {\n announcement = `Jumped to last track. ${newIndex + 1} of ${buttons.length}.`;\n }\n break;\n \n case 'PageUp':\n e.preventDefault();\n e.stopPropagation();\n // Move 5 items up (or to beginning)\n newIndex = Math.max(index - 5, 0);\n if (newIndex === 0 && index !== newIndex) {\n announcement = `Jumped to first track. 1 of ${buttons.length}.`;\n }\n break;\n \n case 'Home':\n e.preventDefault();\n e.stopPropagation();\n // Move to first item\n newIndex = 0;\n if (index !== 0) {\n announcement = `First track. 1 of ${buttons.length}.`;\n }\n break;\n \n case 'End':\n e.preventDefault();\n e.stopPropagation();\n // Move to last item\n newIndex = buttons.length - 1;\n if (index !== buttons.length - 1) {\n announcement = `Last track. ${buttons.length} of ${buttons.length}.`;\n }\n break;\n }\n \n // Update tab indices for roving tabindex pattern\n if (newIndex !== -1 && newIndex !== index) {\n buttons[index].setAttribute('tabIndex', '-1');\n buttons[newIndex].setAttribute('tabIndex', '0');\n buttons[newIndex].focus({ preventScroll: false });\n \n // Scroll the focused item into view (same behavior as mouse interaction)\n const item = buttons[newIndex].closest('.vidply-playlist-item');\n if (item) {\n item.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n }\n }\n \n // Announce navigation feedback\n if (announcement && this.navigationFeedback) {\n this.navigationFeedback.textContent = announcement;\n // Clear after a short delay to allow for repeated announcements\n setTimeout(() => {\n if (this.navigationFeedback) {\n this.navigationFeedback.textContent = '';\n }\n }, 1000);\n }\n }\n \n /**\n * Update playlist UI (highlight current track)\n */\n updatePlaylistUI() {\n if (!this.playlistPanel) return;\n \n const items = this.playlistPanel.querySelectorAll('.vidply-playlist-item');\n const buttons = this.playlistPanel.querySelectorAll('.vidply-playlist-item-button');\n \n items.forEach((item, index) => {\n const button = buttons[index];\n if (!button) return;\n \n const track = this.tracks[index];\n const trackPosition = i18n.t('playlist.trackOf', {\n current: index + 1,\n total: this.tracks.length\n });\n const trackTitle = track.title || i18n.t('playlist.trackUntitled', { number: index + 1 });\n const trackArtist = track.artist ? i18n.t('playlist.by') + track.artist : '';\n \n // Use effective duration (audio description duration when AD is enabled)\n const effectiveDuration = this.getEffectiveDuration(track);\n const trackDurationReadable = effectiveDuration ? TimeUtils.formatDuration(effectiveDuration) : '';\n \n if (index === this.currentIndex) {\n // Update list item styling\n item.classList.add('vidply-playlist-item-active');\n \n // Update button ARIA attributes\n button.setAttribute('aria-current', 'true');\n button.setAttribute('aria-checked', 'true');\n button.setAttribute('tabIndex', '0'); // Active item should be tabbable\n \n // Simplified aria-label - status and actions are announced via ARIA roles\n let ariaLabel = `${trackTitle}${trackArtist}`;\n if (trackDurationReadable) {\n ariaLabel += `. ${trackDurationReadable}`;\n }\n button.setAttribute('aria-label', ariaLabel);\n \n // Scroll into view within playlist panel (uses 'nearest' to minimize page scroll)\n item.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n } else {\n // Update list item styling\n item.classList.remove('vidply-playlist-item-active');\n \n // Update button ARIA attributes\n button.removeAttribute('aria-current');\n button.setAttribute('aria-checked', 'false');\n button.setAttribute('tabIndex', '-1'); // Remove from tab order (use arrow keys)\n \n // Simplified aria-label - status and actions are announced via ARIA roles\n let ariaLabel = `${trackTitle}${trackArtist}`;\n if (trackDurationReadable) {\n ariaLabel += `. ${trackDurationReadable}`;\n }\n button.setAttribute('aria-label', ariaLabel);\n }\n });\n }\n \n /**\n * Get current track\n */\n getCurrentTrack() {\n return this.tracks[this.currentIndex] || null;\n }\n \n /**\n * Get playlist info\n */\n getPlaylistInfo() {\n return {\n currentIndex: this.currentIndex,\n totalTracks: this.tracks.length,\n currentTrack: this.getCurrentTrack(),\n hasNext: this.hasNext(),\n hasPrevious: this.hasPrevious()\n };\n }\n \n /**\n * Check if there is a next track\n */\n hasNext() {\n if (this.options.loop) return true;\n return this.currentIndex < this.tracks.length - 1;\n }\n \n /**\n * Check if there is a previous track\n */\n hasPrevious() {\n if (this.options.loop) return true;\n return this.currentIndex > 0;\n }\n \n /**\n * Add track to playlist\n */\n addTrack(track) {\n this.tracks.push(track);\n \n if (this.playlistPanel) {\n this.renderPlaylist();\n }\n }\n \n /**\n * Remove track from playlist\n */\n removeTrack(index) {\n if (index < 0 || index >= this.tracks.length) return;\n \n this.tracks.splice(index, 1);\n \n // Adjust current index if needed\n if (index < this.currentIndex) {\n this.currentIndex--;\n } else if (index === this.currentIndex) {\n // Current track was removed, play next or stop\n if (this.currentIndex >= this.tracks.length) {\n this.currentIndex = this.tracks.length - 1;\n }\n \n if (this.currentIndex >= 0) {\n this.play(this.currentIndex);\n }\n }\n \n if (this.playlistPanel) {\n this.renderPlaylist();\n }\n }\n \n /**\n * Clear playlist\n */\n clear() {\n this.tracks = [];\n this.currentIndex = -1;\n \n if (this.playlistPanel) {\n this.playlistPanel.innerHTML = '';\n this.playlistPanel.style.display = 'none';\n }\n \n if (this.trackInfoElement) {\n this.trackInfoElement.innerHTML = '';\n this.trackInfoElement.style.display = 'none';\n }\n \n if (this.trackArtworkElement) {\n this.trackArtworkElement.style.backgroundImage = '';\n this.trackArtworkElement.style.display = 'none';\n }\n }\n \n /**\n * Toggle playlist panel visibility\n * @param {boolean} show - Optional: force show (true) or hide (false)\n * @returns {boolean} - New visibility state\n */\n togglePanel(show) {\n if (!this.playlistPanel) return false;\n \n // Determine new state\n const shouldShow = show !== undefined ? show : this.playlistPanel.style.display === 'none';\n \n if (shouldShow) {\n this.playlistPanel.style.display = 'block';\n this.isPanelVisible = true;\n \n // Focus first item if playlist has tracks\n if (this.tracks.length > 0) {\n setTimeout(() => {\n const firstItem = this.playlistPanel.querySelector('.vidply-playlist-item[tabindex=\"0\"]');\n if (firstItem) {\n firstItem.focus({ preventScroll: true });\n }\n }, 100);\n }\n \n // Update toggle button state if it exists\n if (this.player.controlBar && this.player.controlBar.controls.playlistToggle) {\n this.player.controlBar.controls.playlistToggle.setAttribute('aria-expanded', 'true');\n this.player.controlBar.controls.playlistToggle.setAttribute('aria-pressed', 'true');\n }\n } else {\n this.playlistPanel.style.display = 'none';\n this.isPanelVisible = false;\n \n // Update toggle button state if it exists\n if (this.player.controlBar && this.player.controlBar.controls.playlistToggle) {\n this.player.controlBar.controls.playlistToggle.setAttribute('aria-expanded', 'false');\n this.player.controlBar.controls.playlistToggle.setAttribute('aria-pressed', 'false');\n \n // Return focus to toggle button\n this.player.controlBar.controls.playlistToggle.focus({ preventScroll: true });\n }\n }\n \n return this.isPanelVisible;\n }\n \n /**\n * Show playlist panel\n */\n showPanel() {\n return this.togglePanel(true);\n }\n \n /**\n * Hide playlist panel\n */\n hidePanel() {\n return this.togglePanel(false);\n }\n \n /**\n * Destroy playlist manager\n */\n destroy() {\n // Remove event listeners\n this.player.off('ended', this.handleTrackEnd);\n this.player.off('error', this.handleTrackError);\n \n // Remove UI\n if (this.trackArtworkElement) {\n this.trackArtworkElement.remove();\n }\n \n if (this.trackInfoElement) {\n this.trackInfoElement.remove();\n }\n \n if (this.playlistPanel) {\n this.playlistPanel.remove();\n }\n \n // Clear data\n this.clear();\n }\n}\n\nexport default PlaylistManager;\n", "/**\r\n * VidPly - Universal Video Player\r\n * Main Entry Point\r\n */\r\n\r\nimport { Player } from './core/Player.js';\r\nimport { PlaylistManager } from './features/PlaylistManager.js';\r\n\r\n// Auto-initialize players\r\nfunction initializePlayers() {\r\n const elements = document.querySelectorAll('[data-vidply]');\r\n \r\n elements.forEach(element => {\r\n // Parse options from data attribute (JSON format)\r\n const options = element.dataset.vidplyOptions \r\n ? JSON.parse(element.dataset.vidplyOptions)\r\n : {};\r\n \r\n // Parse individual data attributes and merge with options\r\n // This allows for easier HTML-based configuration\r\n const dataOptions = parseDataAttributes(element.dataset);\r\n const mergedOptions = { ...dataOptions, ...options };\r\n \r\n // Create player instance\r\n new Player(element, mergedOptions);\r\n });\r\n}\r\n\r\n// Helper function to parse data attributes into options\r\nfunction parseDataAttributes(dataset) {\r\n const options = {};\r\n \r\n // Map of data attribute names to option keys (camelCase conversion)\r\n const attributeMap = {\r\n // Sign Language\r\n 'signLanguageSrc': 'signLanguageSrc',\r\n 'signLanguageButton': 'signLanguageButton',\r\n 'signLanguagePosition': 'signLanguagePosition',\r\n \r\n // Audio Description\r\n 'audioDescriptionSrc': 'audioDescriptionSrc',\r\n 'audioDescriptionButton': 'audioDescriptionButton',\r\n \r\n // Other common options\r\n 'autoplay': 'autoplay',\r\n 'loop': 'loop',\r\n 'muted': 'muted',\r\n 'controls': 'controls',\r\n 'poster': 'poster',\r\n 'width': 'width',\r\n 'height': 'height',\r\n 'language': 'language',\r\n 'captions': 'captions',\r\n 'captionsDefault': 'captionsDefault',\r\n 'transcript': 'transcript',\r\n 'transcriptButton': 'transcriptButton',\r\n 'keyboard': 'keyboard',\r\n 'responsive': 'responsive',\r\n 'pipButton': 'pipButton',\r\n 'fullscreenButton': 'fullscreenButton'\r\n };\r\n \r\n // Parse each data attribute\r\n Object.keys(attributeMap).forEach(dataKey => {\r\n const optionKey = attributeMap[dataKey];\r\n const value = dataset[dataKey];\r\n \r\n if (value !== undefined) {\r\n // Convert string values to appropriate types\r\n if (value === 'true') {\r\n options[optionKey] = true;\r\n } else if (value === 'false') {\r\n options[optionKey] = false;\r\n } else if (!isNaN(value) && value !== '') {\r\n options[optionKey] = Number(value);\r\n } else {\r\n options[optionKey] = value;\r\n }\r\n }\r\n });\r\n \r\n // Parse sign language sources with language codes (e.g., data-sign-language-src-en, data-sign-language-src-de)\r\n // In dataset, hyphens become camelCase: data-sign-language-src-en -> signLanguageSrcEn\r\n const signLanguageSources = {};\r\n Object.keys(dataset).forEach(key => {\r\n if (key.startsWith('signLanguageSrc') && key !== 'signLanguageSrc') {\r\n // Extract language code from key (e.g., 'signLanguageSrcEn' -> 'en', 'signLanguageSrcDe' -> 'de')\r\n // Handle both single and multi-word language codes\r\n const langMatch = key.match(/^signLanguageSrc([A-Z][a-z]*)$/);\r\n if (langMatch) {\r\n const langCode = langMatch[1].toLowerCase();\r\n signLanguageSources[langCode] = dataset[key];\r\n }\r\n }\r\n });\r\n \r\n if (Object.keys(signLanguageSources).length > 0) {\r\n options.signLanguageSources = signLanguageSources;\r\n // If there's also a single signLanguageSrc, use it as default/fallback\r\n if (dataset.signLanguageSrc && !options.signLanguageSrc) {\r\n options.signLanguageSrc = dataset.signLanguageSrc;\r\n }\r\n }\r\n \r\n // Handle language file attributes\r\n // Support for multiple language files: data-vidply-language-files='{\"pt\": \"path/to/pt.json\", \"it\": \"path/to/it.json\"}'\r\n if (dataset.vidplyLanguageFiles) {\r\n try {\r\n options.languageFiles = JSON.parse(dataset.vidplyLanguageFiles);\r\n } catch (e) {\r\n console.warn('Invalid JSON in data-vidply-language-files:', e);\r\n }\r\n }\r\n \r\n // Support for single language file: data-vidply-language-file='{\"pt\": \"path/to/pt.json\"}'\r\n // or data-vidply-language-file-code=\"pt\" + data-vidply-language-file-url=\"path/to/pt.json\"\r\n if (dataset.vidplyLanguageFile) {\r\n try {\r\n const parsed = JSON.parse(dataset.vidplyLanguageFile);\r\n // If it's an object, treat it as languageFiles\r\n if (typeof parsed === 'object' && parsed !== null) {\r\n options.languageFiles = parsed;\r\n }\r\n } catch (e) {\r\n // If parsing fails, check for separate code and URL attributes\r\n if (dataset.vidplyLanguageFileCode && dataset.vidplyLanguageFileUrl) {\r\n options.languageFile = dataset.vidplyLanguageFileCode;\r\n options.languageFileUrl = dataset.vidplyLanguageFileUrl;\r\n }\r\n }\r\n } else if (dataset.vidplyLanguageFileCode && dataset.vidplyLanguageFileUrl) {\r\n // Support separate attributes for single language file\r\n options.languageFile = dataset.vidplyLanguageFileCode;\r\n options.languageFileUrl = dataset.vidplyLanguageFileUrl;\r\n }\r\n \r\n return options;\r\n}\r\n\r\n// Auto-initialize on DOM ready\r\nif (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', initializePlayers);\r\n} else {\r\n initializePlayers();\r\n}\r\n\r\n// Export for manual initialization\r\nexport { Player, PlaylistManager };\r\nexport default Player;\r\n\r\n"],
5
+ "mappings": "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",
6
6
  "names": ["isMobile", "currentTime", "isSmallScreen", "currentSrc", "syncTime", "hasSourceElementsWithDesc", "allTextTracks", "isMobile"]
7
7
  }