vidply 1.2.0 → 1.2.3

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 (167) hide show
  1. package/README.md +974 -946
  2. package/dist/dev/{vidply.AudioDescriptionManager-R47Q4YR4.js → vidply.AudioDescriptionManager-JYYLK5KB.js} +275 -19
  3. package/dist/dev/vidply.AudioDescriptionManager-JYYLK5KB.js.map +7 -0
  4. package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js → vidply.CaptionStyleMenu-47RCKQF5.js} +4 -4
  5. package/dist/dev/{vidply.DASHRenderer-PWEMC3BT.js → vidply.DASHRenderer-VEJ4HDHO.js} +3 -3
  6. package/dist/dev/vidply.DASHRenderer-VEJ4HDHO.js.map +7 -0
  7. package/dist/dev/{vidply.FloatingPlayerManager-PKNNNAS2.js → vidply.FloatingPlayerManager-C2UVRPZY.js} +5 -5
  8. package/dist/dev/vidply.FloatingPlayerManager-C2UVRPZY.js.map +7 -0
  9. package/dist/dev/{vidply.HLSRenderer-E7RQ74HI.js → vidply.HLSRenderer-ZVBK2TNQ.js} +4 -4
  10. package/dist/dev/vidply.HLSRenderer-ZVBK2TNQ.js.map +7 -0
  11. package/dist/dev/vidply.HTML5Renderer-HLRQUOCU.js +12 -0
  12. package/dist/dev/{vidply.SignLanguageManager-FET5FQZ7.js → vidply.SignLanguageManager-FLUCBW5H.js} +8 -8
  13. package/dist/dev/vidply.SignLanguageManager-FLUCBW5H.js.map +7 -0
  14. package/dist/dev/{vidply.SoundCloudRenderer-RVSJZODO.js → vidply.SoundCloudRenderer-MGMAJ7NK.js} +3 -3
  15. package/dist/dev/vidply.SoundCloudRenderer-MGMAJ7NK.js.map +7 -0
  16. package/dist/dev/{vidply.TranscriptManager-5GXOQCLX.js → vidply.TranscriptManager-Y2RYXHJW.js} +10 -10
  17. package/dist/dev/vidply.TranscriptManager-Y2RYXHJW.js.map +7 -0
  18. package/dist/dev/{vidply.VimeoRenderer-ER2LSBBW.js → vidply.VimeoRenderer-RQFQD7OE.js} +3 -3
  19. package/dist/dev/vidply.VimeoRenderer-RQFQD7OE.js.map +7 -0
  20. package/dist/dev/{vidply.YouTubeRenderer-NFTOWJAB.js → vidply.YouTubeRenderer-EU2BARZF.js} +3 -3
  21. package/dist/dev/vidply.YouTubeRenderer-EU2BARZF.js.map +7 -0
  22. package/dist/dev/{vidply.chunk-BNFIUL2Z.js → vidply.chunk-6LYZYI5G.js} +3 -3
  23. package/dist/dev/vidply.chunk-6LYZYI5G.js.map +7 -0
  24. package/dist/dev/{vidply.chunk-NQPURMQY.js → vidply.chunk-A4ESEOQ2.js} +6 -6
  25. package/dist/dev/vidply.chunk-A4ESEOQ2.js.map +7 -0
  26. package/dist/dev/{vidply.chunk-W25HUCHS.js → vidply.chunk-CGYIED2I.js} +2 -2
  27. package/dist/dev/vidply.chunk-CGYIED2I.js.map +7 -0
  28. package/dist/dev/{vidply.chunk-SK4V2DAU.js → vidply.chunk-HZ7UOKOU.js} +3 -3
  29. package/dist/dev/{vidply.chunk-RZWZGDV7.js → vidply.chunk-I6EDRYGJ.js} +33 -6
  30. package/dist/dev/vidply.chunk-I6EDRYGJ.js.map +7 -0
  31. package/dist/dev/{vidply.chunk-64WXMTGL.js → vidply.chunk-JKMQGLCJ.js} +5 -5
  32. package/dist/dev/vidply.chunk-JKMQGLCJ.js.map +7 -0
  33. package/dist/dev/{vidply.chunk-DZSDO3B7.js → vidply.chunk-JZNZX32Z.js} +2 -2
  34. package/dist/dev/{vidply.chunk-VMSQAZM7.js → vidply.chunk-P25MRJ6O.js} +2 -2
  35. package/dist/dev/{vidply.chunk-6RQA4ROD.js → vidply.chunk-PRFNESYA.js} +2 -2
  36. package/dist/dev/{vidply.chunk-KI7C3QVL.js → vidply.chunk-UI3RYCVF.js} +4 -3
  37. package/dist/dev/vidply.chunk-UI3RYCVF.js.map +7 -0
  38. package/dist/dev/{vidply.chunk-JJ47NO24.js → vidply.chunk-UNFGMABP.js} +2 -2
  39. package/dist/dev/vidply.chunk-UNFGMABP.js.map +7 -0
  40. package/dist/dev/{vidply.de-4YAT7FFM.js → vidply.de-VAUVSQXC.js} +29 -2
  41. package/dist/dev/vidply.de-VAUVSQXC.js.map +7 -0
  42. package/dist/dev/{vidply.es-LEWIRUBH.js → vidply.es-G65HFWO6.js} +29 -2
  43. package/dist/dev/vidply.es-G65HFWO6.js.map +7 -0
  44. package/dist/dev/vidply.esm.js +648 -35
  45. package/dist/dev/vidply.esm.js.map +3 -3
  46. package/dist/dev/{vidply.fr-Q4GV2NOE.js → vidply.fr-MJNOZELM.js} +29 -2
  47. package/dist/dev/vidply.fr-MJNOZELM.js.map +7 -0
  48. package/dist/dev/{vidply.ja-S6ITA6WU.js → vidply.ja-INMDHIYJ.js} +29 -2
  49. package/dist/dev/vidply.ja-INMDHIYJ.js.map +7 -0
  50. package/dist/legacy/vidply.js +1062 -34
  51. package/dist/legacy/vidply.js.map +3 -3
  52. package/dist/legacy/vidply.min.js +2 -2
  53. package/dist/legacy/vidply.min.meta.json +127 -55
  54. package/dist/prod/vidply.AudioDescriptionManager-EKWUNOPE.min.js +6 -0
  55. package/dist/prod/{vidply.CaptionStyleMenu-M3KVQWB5.min.js → vidply.CaptionStyleMenu-JTWSNHRQ.min.js} +2 -2
  56. package/dist/prod/{vidply.DASHRenderer-DN3S27AV.min.js → vidply.DASHRenderer-CIDAHFWM.min.js} +2 -2
  57. package/dist/prod/{vidply.FloatingPlayerManager-SKAZ4J43.min.js → vidply.FloatingPlayerManager-VZXHPCPM.min.js} +2 -2
  58. package/dist/prod/{vidply.HLSRenderer-62HH4YTK.min.js → vidply.HLSRenderer-Q6EFYKID.min.js} +2 -2
  59. package/dist/prod/vidply.HTML5Renderer-XRDJUTOO.min.js +6 -0
  60. package/dist/prod/{vidply.SignLanguageManager-V3OBTSSF.min.js → vidply.SignLanguageManager-JUOSA5AM.min.js} +2 -2
  61. package/dist/prod/{vidply.SoundCloudRenderer-CXRVZIAJ.min.js → vidply.SoundCloudRenderer-7ODD46PO.min.js} +2 -2
  62. package/dist/prod/{vidply.TranscriptManager-SYM3DFUY.min.js → vidply.TranscriptManager-4B2QKYGQ.min.js} +2 -2
  63. package/dist/prod/{vidply.VimeoRenderer-72TWRYFQ.min.js → vidply.VimeoRenderer-MR3UYLY7.min.js} +2 -2
  64. package/dist/prod/{vidply.YouTubeRenderer-UMHEV3KD.min.js → vidply.YouTubeRenderer-ITRTC7NR.min.js} +2 -2
  65. package/dist/prod/{vidply.chunk-YEENJS3Q.min.js → vidply.chunk-3EEDXU4T.min.js} +2 -2
  66. package/dist/prod/{vidply.chunk-P4UXOHWA.min.js → vidply.chunk-5HTX5QXW.min.js} +1 -1
  67. package/dist/prod/{vidply.chunk-ABPXVDLZ.min.js → vidply.chunk-6OGHHIYP.min.js} +2 -2
  68. package/dist/prod/{vidply.chunk-UK7YGOB5.min.js → vidply.chunk-GUPGMFUZ.min.js} +2 -2
  69. package/dist/prod/{vidply.chunk-WX3MVEAL.min.js → vidply.chunk-MWEBITCP.min.js} +1 -1
  70. package/dist/prod/{vidply.chunk-2TB6MUHO.min.js → vidply.chunk-PL3P3JHR.min.js} +1 -1
  71. package/dist/prod/{vidply.chunk-EKEYJWMG.min.js → vidply.chunk-QQZGV7TD.min.js} +2 -2
  72. package/dist/prod/{vidply.chunk-Z3YDSA7O.min.js → vidply.chunk-U5IRRYG5.min.js} +1 -1
  73. package/dist/prod/{vidply.chunk-TM6AXJVD.min.js → vidply.chunk-VKHV4QHA.min.js} +2 -2
  74. package/dist/prod/{vidply.chunk-P3PQBY7N.min.js → vidply.chunk-XA4M574A.min.js} +1 -1
  75. package/dist/prod/{vidply.chunk-RI3X7WHK.min.js → vidply.chunk-ZPTV4JEP.min.js} +2 -2
  76. package/dist/prod/{vidply.de-BCHXRQ53.min.js → vidply.de-UZHFCEZU.min.js} +2 -2
  77. package/dist/prod/{vidply.es-PICAKMZD.min.js → vidply.es-BOISUV2S.min.js} +2 -2
  78. package/dist/prod/vidply.esm.min.js +2 -2
  79. package/dist/prod/{vidply.fr-ZILI7CDR.min.js → vidply.fr-ICSMKPFM.min.js} +2 -2
  80. package/dist/prod/{vidply.ja-5WQ4OK4J.min.js → vidply.ja-VQ2HKGAY.min.js} +2 -2
  81. package/dist/vidply.css +5852 -5796
  82. package/dist/vidply.esm.min.meta.json +204 -149
  83. package/dist/vidply.min.css +1 -1
  84. package/package.json +11 -11
  85. package/src/controls/CaptionManager.ts +598 -598
  86. package/src/controls/ControlBar.ts +4191 -4159
  87. package/src/controls/KeyboardHelp.ts +326 -0
  88. package/src/controls/KeyboardManager.ts +387 -383
  89. package/src/controls/SettingsDialog.ts +488 -488
  90. package/src/controls/TranscriptManager.ts +2426 -2426
  91. package/src/core/AudioDescriptionManager.ts +863 -774
  92. package/src/core/DescriptionSpeechManager.ts +232 -0
  93. package/src/core/FloatingPlayerManager.ts +674 -674
  94. package/src/core/LazyInit.ts +80 -80
  95. package/src/core/MediaSessionManager.ts +341 -0
  96. package/src/core/MetadataAlertsManager.ts +514 -514
  97. package/src/core/Player.ts +2973 -2872
  98. package/src/core/PosterManager.ts +169 -169
  99. package/src/core/PseudoFullscreen.ts +179 -179
  100. package/src/core/ResponsiveManager.ts +231 -231
  101. package/src/core/ResumeManager.ts +236 -236
  102. package/src/core/SignLanguageManager.ts +1308 -1308
  103. package/src/core/ThemeManager.ts +157 -157
  104. package/src/features/PlaylistManager.ts +1838 -1827
  105. package/src/i18n/i18n.ts +223 -223
  106. package/src/i18n/languages/de.ts +244 -217
  107. package/src/i18n/languages/en.ts +245 -218
  108. package/src/i18n/languages/es.ts +241 -214
  109. package/src/i18n/languages/fr.ts +241 -214
  110. package/src/i18n/languages/ja.ts +241 -214
  111. package/src/icons/Icons.ts +168 -167
  112. package/src/index.ts +196 -193
  113. package/src/renderers/DASHRenderer.ts +1077 -1077
  114. package/src/renderers/HLSRenderer.ts +944 -944
  115. package/src/renderers/HTML5Renderer.ts +389 -389
  116. package/src/renderers/SoundCloudRenderer.ts +437 -437
  117. package/src/renderers/VimeoRenderer.ts +298 -298
  118. package/src/renderers/YouTubeRenderer.ts +290 -290
  119. package/src/styles/vidply.css +5852 -5796
  120. package/src/types/events.ts +128 -122
  121. package/src/types/globals.d.ts +313 -313
  122. package/src/types/options.ts +199 -182
  123. package/src/types/renderer.ts +58 -58
  124. package/src/utils/DOMUtils.ts +281 -281
  125. package/src/utils/DownloadInfo.ts +171 -171
  126. package/src/utils/DraggablePanel.ts +539 -539
  127. package/src/utils/DraggablePanelMenu.ts +195 -195
  128. package/src/utils/DraggableResizable.ts +997 -997
  129. package/src/utils/EventEmitter.ts +59 -59
  130. package/src/utils/FormUtils.ts +95 -95
  131. package/src/utils/MenuFactory.ts +483 -483
  132. package/src/utils/Sanitize.ts +70 -70
  133. package/src/utils/SettingsMenuFactory.ts +289 -289
  134. package/src/utils/StorageManager.ts +287 -287
  135. package/src/utils/TrackLabelUtils.ts +52 -52
  136. package/src/utils/UrlSafe.ts +69 -69
  137. package/src/utils/VideoFrameCapture.ts +114 -114
  138. package/src/utils/WindowComponents.ts +250 -250
  139. package/dist/dev/vidply.AudioDescriptionManager-R47Q4YR4.js.map +0 -7
  140. package/dist/dev/vidply.DASHRenderer-PWEMC3BT.js.map +0 -7
  141. package/dist/dev/vidply.FloatingPlayerManager-PKNNNAS2.js.map +0 -7
  142. package/dist/dev/vidply.HLSRenderer-E7RQ74HI.js.map +0 -7
  143. package/dist/dev/vidply.HTML5Renderer-BU4QJJJY.js +0 -12
  144. package/dist/dev/vidply.SignLanguageManager-FET5FQZ7.js.map +0 -7
  145. package/dist/dev/vidply.SoundCloudRenderer-RVSJZODO.js.map +0 -7
  146. package/dist/dev/vidply.TranscriptManager-5GXOQCLX.js.map +0 -7
  147. package/dist/dev/vidply.VimeoRenderer-ER2LSBBW.js.map +0 -7
  148. package/dist/dev/vidply.YouTubeRenderer-NFTOWJAB.js.map +0 -7
  149. package/dist/dev/vidply.chunk-64WXMTGL.js.map +0 -7
  150. package/dist/dev/vidply.chunk-BNFIUL2Z.js.map +0 -7
  151. package/dist/dev/vidply.chunk-JJ47NO24.js.map +0 -7
  152. package/dist/dev/vidply.chunk-KI7C3QVL.js.map +0 -7
  153. package/dist/dev/vidply.chunk-NQPURMQY.js.map +0 -7
  154. package/dist/dev/vidply.chunk-RZWZGDV7.js.map +0 -7
  155. package/dist/dev/vidply.chunk-W25HUCHS.js.map +0 -7
  156. package/dist/dev/vidply.de-4YAT7FFM.js.map +0 -7
  157. package/dist/dev/vidply.es-LEWIRUBH.js.map +0 -7
  158. package/dist/dev/vidply.fr-Q4GV2NOE.js.map +0 -7
  159. package/dist/dev/vidply.ja-S6ITA6WU.js.map +0 -7
  160. package/dist/prod/vidply.AudioDescriptionManager-RHLIJW5C.min.js +0 -6
  161. package/dist/prod/vidply.HTML5Renderer-IU5T3WEW.min.js +0 -6
  162. /package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js.map → vidply.CaptionStyleMenu-47RCKQF5.js.map} +0 -0
  163. /package/dist/dev/{vidply.HTML5Renderer-BU4QJJJY.js.map → vidply.HTML5Renderer-HLRQUOCU.js.map} +0 -0
  164. /package/dist/dev/{vidply.chunk-SK4V2DAU.js.map → vidply.chunk-HZ7UOKOU.js.map} +0 -0
  165. /package/dist/dev/{vidply.chunk-DZSDO3B7.js.map → vidply.chunk-JZNZX32Z.js.map} +0 -0
  166. /package/dist/dev/{vidply.chunk-VMSQAZM7.js.map → vidply.chunk-P25MRJ6O.js.map} +0 -0
  167. /package/dist/dev/{vidply.chunk-6RQA4ROD.js.map → vidply.chunk-PRFNESYA.js.map} +0 -0
@@ -1,250 +1,250 @@
1
- /**
2
- * Window Components Factory
3
- * Creates standardized UI components for floating windows (headers, selectors, controls)
4
- * Note: This only creates DOM elements. For drag/resize behavior, use DraggableResizable class.
5
- */
6
-
7
- import { DOMUtils } from './DOMUtils.js';
8
- import { createIconElement } from '../icons/Icons.js';
9
- import { i18n } from '../i18n/i18n.js';
10
-
11
- interface WindowHeaderOptions {
12
- classPrefix: string;
13
- headerClass: string;
14
- titleText: string;
15
- showSettings?: boolean;
16
- onSettingsClick?: ((e: Event) => void) | null;
17
- onClose?: ((e: Event) => void) | null;
18
- leftContent?: HTMLElement[];
19
- }
20
-
21
- interface HeaderSelectorOption {
22
- value: string;
23
- text: string;
24
- selected?: boolean;
25
- }
26
-
27
- interface HeaderSelectorOptions {
28
- classPrefix: string;
29
- selectClass: string;
30
- labelText: string;
31
- selectId: string;
32
- options?: HeaderSelectorOption[];
33
- onChange?: ((e: Event) => void) | null;
34
- }
35
-
36
- interface AutoscrollCheckboxOptions {
37
- classPrefix: string;
38
- labelClass: string;
39
- textClass: string;
40
- checkboxId: string;
41
- labelText: string;
42
- checked?: boolean;
43
- onChange?: ((e: Event) => void) | null;
44
- }
45
-
46
- /**
47
- * Create a window header element (used as drag handle)
48
- * @param {Object} options - Header options
49
- * @param {string} options.classPrefix - Class prefix
50
- * @param {string} options.headerClass - Specific header class name
51
- * @param {string} options.titleText - Title text (will be visually hidden)
52
- * @param {boolean} options.showSettings - Whether to show settings button
53
- * @param {Function} options.onSettingsClick - Settings button click handler
54
- * @param {Function} options.onClose - Close button click handler
55
- * @param {Array} options.leftContent - Array of additional elements for left side
56
- * @returns {Object} Object containing header element and button references
57
- */
58
- export function createWindowHeader({
59
- classPrefix,
60
- headerClass,
61
- titleText,
62
- showSettings = false,
63
- onSettingsClick = null,
64
- onClose = null,
65
- leftContent = []
66
- }: WindowHeaderOptions): {
67
- header: HTMLElement;
68
- settingsButton: HTMLElement | null;
69
- closeButton: HTMLElement;
70
- leftSide: HTMLElement;
71
- } {
72
- // Create header container
73
- const header = DOMUtils.createElement('div', {
74
- className: `${classPrefix}-draggable-header ${headerClass}`,
75
- attributes: {
76
- 'role': 'heading',
77
- 'aria-level': '2',
78
- 'tabindex': '0'
79
- }
80
- });
81
-
82
- // Create left side container
83
- const leftSide = DOMUtils.createElement('div', {
84
- className: `${headerClass}-left`
85
- });
86
-
87
- // Add settings button if requested
88
- let settingsButton = null;
89
- if (showSettings && onSettingsClick) {
90
- const settingsAriaLabel = i18n.t('settings.title');
91
- settingsButton = DOMUtils.createElement('button', {
92
- className: `${classPrefix}-icon-button ${headerClass}-settings`,
93
- attributes: {
94
- 'type': 'button',
95
- 'aria-label': settingsAriaLabel
96
- }
97
- });
98
- settingsButton.appendChild(createIconElement('settings'));
99
- DOMUtils.attachTooltip(settingsButton, settingsAriaLabel, classPrefix);
100
- settingsButton.addEventListener('click', onSettingsClick);
101
- leftSide.appendChild(settingsButton);
102
- }
103
-
104
- // Add custom left content
105
- leftContent.forEach(element => {
106
- if (element) {
107
- leftSide.appendChild(element);
108
- }
109
- });
110
-
111
- // Create title (visually hidden but accessible)
112
- const title = DOMUtils.createElement('h3', {
113
- textContent: titleText
114
- });
115
- leftSide.appendChild(title);
116
-
117
- // Create close button
118
- const closeAriaLabel = i18n.t('player.close');
119
- const closeButton = DOMUtils.createElement('button', {
120
- className: `${classPrefix}-icon-button ${headerClass}-close`,
121
- attributes: {
122
- 'type': 'button',
123
- 'aria-label': closeAriaLabel
124
- }
125
- });
126
- closeButton.appendChild(createIconElement('close'));
127
- DOMUtils.attachTooltip(closeButton, closeAriaLabel, classPrefix);
128
- if (onClose) {
129
- closeButton.addEventListener('click', onClose);
130
- }
131
-
132
- // Assemble header
133
- header.appendChild(leftSide);
134
- header.appendChild(closeButton);
135
-
136
- return {
137
- header,
138
- settingsButton,
139
- closeButton,
140
- leftSide
141
- };
142
- }
143
-
144
- /**
145
- * Create a language/track selector for header
146
- * @param {Object} options - Selector options
147
- * @param {string} options.classPrefix - Class prefix
148
- * @param {string} options.selectClass - CSS class for select element
149
- * @param {string} options.labelText - Label text (i18n key)
150
- * @param {string} options.selectId - Select element ID
151
- * @param {Array} options.options - Array of {value, text, selected} objects
152
- * @param {Function} options.onChange - Change event handler
153
- * @returns {Object} Object with label and select elements
154
- */
155
- export function createHeaderSelector({
156
- classPrefix: _classPrefix,
157
- selectClass,
158
- labelText,
159
- selectId,
160
- options = [],
161
- onChange = null
162
- }: HeaderSelectorOptions): { label: HTMLElement; select: HTMLElement } {
163
- const label = DOMUtils.createElement('label', {
164
- className: `${selectClass}-label`,
165
- textContent: i18n.t(labelText),
166
- attributes: {
167
- 'for': selectId
168
- }
169
- });
170
-
171
- const select = DOMUtils.createElement('select', {
172
- className: selectClass,
173
- attributes: {
174
- 'id': selectId
175
- }
176
- });
177
-
178
- // Add options
179
- options.forEach(opt => {
180
- const option = DOMUtils.createElement('option', {
181
- textContent: opt.text,
182
- attributes: {
183
- 'value': opt.value
184
- }
185
- });
186
- if (opt.selected) {
187
- (option as HTMLOptionElement).selected = true;
188
- }
189
- select.appendChild(option);
190
- });
191
-
192
- // Add change handler
193
- if (onChange) {
194
- select.addEventListener('change', onChange);
195
- }
196
-
197
- return { label, select };
198
- }
199
-
200
- /**
201
- * Create an autoscroll checkbox for header
202
- * @param {Object} options - Checkbox options
203
- * @param {string} options.classPrefix - Class prefix
204
- * @param {string} options.labelClass - CSS class for label
205
- * @param {string} options.textClass - CSS class for text span
206
- * @param {string} options.checkboxId - Checkbox element ID
207
- * @param {string} options.labelText - Label text (i18n key)
208
- * @param {boolean} options.checked - Initial checked state
209
- * @param {Function} options.onChange - Change event handler
210
- * @returns {HTMLElement} Label element containing checkbox
211
- */
212
- export function createAutoscrollCheckbox({
213
- classPrefix: _classPrefix,
214
- labelClass,
215
- textClass,
216
- checkboxId,
217
- labelText,
218
- checked = true,
219
- onChange = null
220
- }: AutoscrollCheckboxOptions): HTMLElement {
221
- const label = DOMUtils.createElement('label', {
222
- className: labelClass,
223
- attributes: {
224
- 'for': checkboxId
225
- }
226
- });
227
-
228
- const checkbox = DOMUtils.createElement('input', {
229
- attributes: {
230
- 'type': 'checkbox',
231
- 'id': checkboxId,
232
- 'checked': checked ? 'checked' : undefined
233
- }
234
- });
235
-
236
- const text = DOMUtils.createElement('span', {
237
- className: textClass,
238
- textContent: i18n.t(labelText)
239
- });
240
-
241
- if (onChange) {
242
- checkbox.addEventListener('change', onChange);
243
- }
244
-
245
- label.appendChild(checkbox);
246
- label.appendChild(text);
247
-
248
- return label;
249
- }
250
-
1
+ /**
2
+ * Window Components Factory
3
+ * Creates standardized UI components for floating windows (headers, selectors, controls)
4
+ * Note: This only creates DOM elements. For drag/resize behavior, use DraggableResizable class.
5
+ */
6
+
7
+ import { DOMUtils } from './DOMUtils.js';
8
+ import { createIconElement } from '../icons/Icons.js';
9
+ import { i18n } from '../i18n/i18n.js';
10
+
11
+ interface WindowHeaderOptions {
12
+ classPrefix: string;
13
+ headerClass: string;
14
+ titleText: string;
15
+ showSettings?: boolean;
16
+ onSettingsClick?: ((e: Event) => void) | null;
17
+ onClose?: ((e: Event) => void) | null;
18
+ leftContent?: HTMLElement[];
19
+ }
20
+
21
+ interface HeaderSelectorOption {
22
+ value: string;
23
+ text: string;
24
+ selected?: boolean;
25
+ }
26
+
27
+ interface HeaderSelectorOptions {
28
+ classPrefix: string;
29
+ selectClass: string;
30
+ labelText: string;
31
+ selectId: string;
32
+ options?: HeaderSelectorOption[];
33
+ onChange?: ((e: Event) => void) | null;
34
+ }
35
+
36
+ interface AutoscrollCheckboxOptions {
37
+ classPrefix: string;
38
+ labelClass: string;
39
+ textClass: string;
40
+ checkboxId: string;
41
+ labelText: string;
42
+ checked?: boolean;
43
+ onChange?: ((e: Event) => void) | null;
44
+ }
45
+
46
+ /**
47
+ * Create a window header element (used as drag handle)
48
+ * @param {Object} options - Header options
49
+ * @param {string} options.classPrefix - Class prefix
50
+ * @param {string} options.headerClass - Specific header class name
51
+ * @param {string} options.titleText - Title text (will be visually hidden)
52
+ * @param {boolean} options.showSettings - Whether to show settings button
53
+ * @param {Function} options.onSettingsClick - Settings button click handler
54
+ * @param {Function} options.onClose - Close button click handler
55
+ * @param {Array} options.leftContent - Array of additional elements for left side
56
+ * @returns {Object} Object containing header element and button references
57
+ */
58
+ export function createWindowHeader({
59
+ classPrefix,
60
+ headerClass,
61
+ titleText,
62
+ showSettings = false,
63
+ onSettingsClick = null,
64
+ onClose = null,
65
+ leftContent = []
66
+ }: WindowHeaderOptions): {
67
+ header: HTMLElement;
68
+ settingsButton: HTMLElement | null;
69
+ closeButton: HTMLElement;
70
+ leftSide: HTMLElement;
71
+ } {
72
+ // Create header container
73
+ const header = DOMUtils.createElement('div', {
74
+ className: `${classPrefix}-draggable-header ${headerClass}`,
75
+ attributes: {
76
+ 'role': 'heading',
77
+ 'aria-level': '2',
78
+ 'tabindex': '0'
79
+ }
80
+ });
81
+
82
+ // Create left side container
83
+ const leftSide = DOMUtils.createElement('div', {
84
+ className: `${headerClass}-left`
85
+ });
86
+
87
+ // Add settings button if requested
88
+ let settingsButton = null;
89
+ if (showSettings && onSettingsClick) {
90
+ const settingsAriaLabel = i18n.t('settings.title');
91
+ settingsButton = DOMUtils.createElement('button', {
92
+ className: `${classPrefix}-icon-button ${headerClass}-settings`,
93
+ attributes: {
94
+ 'type': 'button',
95
+ 'aria-label': settingsAriaLabel
96
+ }
97
+ });
98
+ settingsButton.appendChild(createIconElement('settings'));
99
+ DOMUtils.attachTooltip(settingsButton, settingsAriaLabel, classPrefix);
100
+ settingsButton.addEventListener('click', onSettingsClick);
101
+ leftSide.appendChild(settingsButton);
102
+ }
103
+
104
+ // Add custom left content
105
+ leftContent.forEach(element => {
106
+ if (element) {
107
+ leftSide.appendChild(element);
108
+ }
109
+ });
110
+
111
+ // Create title (visually hidden but accessible)
112
+ const title = DOMUtils.createElement('h3', {
113
+ textContent: titleText
114
+ });
115
+ leftSide.appendChild(title);
116
+
117
+ // Create close button
118
+ const closeAriaLabel = i18n.t('player.close');
119
+ const closeButton = DOMUtils.createElement('button', {
120
+ className: `${classPrefix}-icon-button ${headerClass}-close`,
121
+ attributes: {
122
+ 'type': 'button',
123
+ 'aria-label': closeAriaLabel
124
+ }
125
+ });
126
+ closeButton.appendChild(createIconElement('close'));
127
+ DOMUtils.attachTooltip(closeButton, closeAriaLabel, classPrefix);
128
+ if (onClose) {
129
+ closeButton.addEventListener('click', onClose);
130
+ }
131
+
132
+ // Assemble header
133
+ header.appendChild(leftSide);
134
+ header.appendChild(closeButton);
135
+
136
+ return {
137
+ header,
138
+ settingsButton,
139
+ closeButton,
140
+ leftSide
141
+ };
142
+ }
143
+
144
+ /**
145
+ * Create a language/track selector for header
146
+ * @param {Object} options - Selector options
147
+ * @param {string} options.classPrefix - Class prefix
148
+ * @param {string} options.selectClass - CSS class for select element
149
+ * @param {string} options.labelText - Label text (i18n key)
150
+ * @param {string} options.selectId - Select element ID
151
+ * @param {Array} options.options - Array of {value, text, selected} objects
152
+ * @param {Function} options.onChange - Change event handler
153
+ * @returns {Object} Object with label and select elements
154
+ */
155
+ export function createHeaderSelector({
156
+ classPrefix: _classPrefix,
157
+ selectClass,
158
+ labelText,
159
+ selectId,
160
+ options = [],
161
+ onChange = null
162
+ }: HeaderSelectorOptions): { label: HTMLElement; select: HTMLElement } {
163
+ const label = DOMUtils.createElement('label', {
164
+ className: `${selectClass}-label`,
165
+ textContent: i18n.t(labelText),
166
+ attributes: {
167
+ 'for': selectId
168
+ }
169
+ });
170
+
171
+ const select = DOMUtils.createElement('select', {
172
+ className: selectClass,
173
+ attributes: {
174
+ 'id': selectId
175
+ }
176
+ });
177
+
178
+ // Add options
179
+ options.forEach(opt => {
180
+ const option = DOMUtils.createElement('option', {
181
+ textContent: opt.text,
182
+ attributes: {
183
+ 'value': opt.value
184
+ }
185
+ });
186
+ if (opt.selected) {
187
+ (option as HTMLOptionElement).selected = true;
188
+ }
189
+ select.appendChild(option);
190
+ });
191
+
192
+ // Add change handler
193
+ if (onChange) {
194
+ select.addEventListener('change', onChange);
195
+ }
196
+
197
+ return { label, select };
198
+ }
199
+
200
+ /**
201
+ * Create an autoscroll checkbox for header
202
+ * @param {Object} options - Checkbox options
203
+ * @param {string} options.classPrefix - Class prefix
204
+ * @param {string} options.labelClass - CSS class for label
205
+ * @param {string} options.textClass - CSS class for text span
206
+ * @param {string} options.checkboxId - Checkbox element ID
207
+ * @param {string} options.labelText - Label text (i18n key)
208
+ * @param {boolean} options.checked - Initial checked state
209
+ * @param {Function} options.onChange - Change event handler
210
+ * @returns {HTMLElement} Label element containing checkbox
211
+ */
212
+ export function createAutoscrollCheckbox({
213
+ classPrefix: _classPrefix,
214
+ labelClass,
215
+ textClass,
216
+ checkboxId,
217
+ labelText,
218
+ checked = true,
219
+ onChange = null
220
+ }: AutoscrollCheckboxOptions): HTMLElement {
221
+ const label = DOMUtils.createElement('label', {
222
+ className: labelClass,
223
+ attributes: {
224
+ 'for': checkboxId
225
+ }
226
+ });
227
+
228
+ const checkbox = DOMUtils.createElement('input', {
229
+ attributes: {
230
+ 'type': 'checkbox',
231
+ 'id': checkboxId,
232
+ 'checked': checked ? 'checked' : undefined
233
+ }
234
+ });
235
+
236
+ const text = DOMUtils.createElement('span', {
237
+ className: textClass,
238
+ textContent: i18n.t(labelText)
239
+ });
240
+
241
+ if (onChange) {
242
+ checkbox.addEventListener('change', onChange);
243
+ }
244
+
245
+ label.appendChild(checkbox);
246
+ label.appendChild(text);
247
+
248
+ return label;
249
+ }
250
+
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/core/AudioDescriptionManager.ts"],
4
- "sourcesContent": ["/**\r\n * Audio Description Manager\r\n * Handles audio-described video source switching and caption track swapping\r\n */\r\n\r\nimport { CaptionManager } from '../controls/CaptionManager.js';\r\nimport type { Player } from './Player.js';\r\n\r\n/**\r\n * Caption-track entry tracked by the audio-description manager. Each\r\n * entry pairs a `<track>` element with its described/original source\r\n * URLs so the manager can swap the rendered captions when the user\r\n * toggles audio description.\r\n */\r\ninterface CaptionTrackInfo {\r\n trackElement: HTMLTrackElement;\r\n originalSrc: string | null;\r\n describedSrc: string;\r\n originalTrackSrc: string | null;\r\n explicit: boolean;\r\n}\r\n\r\nexport class AudioDescriptionManager {\r\n player: Player;\r\n captionTracks: CaptionTrackInfo[];\r\n desiredState: boolean;\r\n enabled: boolean;\r\n originalSource: string | null;\r\n sourceElement: Element | null;\r\n src: string | null;\r\n\r\n constructor(player: Player) {\r\n this.player = player;\r\n \r\n // State\r\n this.enabled = false;\r\n this.desiredState = false;\r\n \r\n // Sources\r\n this.src = player.options.audioDescriptionSrc;\r\n this.sourceElement = null;\r\n this.originalSource = null;\r\n this.captionTracks = [];\r\n }\r\n\r\n /**\r\n * Initialize audio description from source elements\r\n * Called during player initialization\r\n */\r\n initFromSourceElements(sourceElements: Element[], trackElements: Element[]) {\r\n // Check for source elements with audio description attributes\r\n for (const sourceEl of sourceElements) {\r\n const descSrc = sourceEl.getAttribute('data-desc-src');\r\n const origSrc = sourceEl.getAttribute('data-orig-src');\r\n \r\n if (descSrc || origSrc) {\r\n if (!this.sourceElement) {\r\n this.sourceElement = sourceEl;\r\n }\r\n \r\n if (origSrc) {\r\n if (!this.originalSource) {\r\n this.originalSource = origSrc;\r\n }\r\n if (!this.player.originalSrc) {\r\n this.player.originalSrc = origSrc;\r\n }\r\n } else {\r\n const currentSrcAttr = sourceEl.getAttribute('src');\r\n if (!this.originalSource && currentSrcAttr) {\r\n this.originalSource = currentSrcAttr;\r\n }\r\n if (!this.player.originalSrc && currentSrcAttr) {\r\n this.player.originalSrc = currentSrcAttr;\r\n }\r\n }\r\n \r\n if (descSrc && !this.src) {\r\n this.src = descSrc;\r\n }\r\n }\r\n }\r\n\r\n // Check for text tracks with audio description versions\r\n trackElements.forEach((trackEl: Element) => {\r\n const trackKind = trackEl.getAttribute('kind');\r\n const trackDescSrc = trackEl.getAttribute('data-desc-src');\r\n\r\n if ((trackKind === 'captions' || trackKind === 'subtitles' ||\r\n trackKind === 'chapters' || trackKind === 'descriptions') &&\r\n trackDescSrc && trackEl instanceof HTMLTrackElement) {\r\n this.captionTracks.push({\r\n trackElement: trackEl,\r\n originalSrc: trackEl.getAttribute('src'),\r\n describedSrc: trackDescSrc,\r\n originalTrackSrc: trackEl.getAttribute('data-orig-src') || trackEl.getAttribute('src'),\r\n explicit: true\r\n });\r\n this.player.log(`Found explicit described ${trackKind} track: ${trackEl.getAttribute('src')} -> ${trackDescSrc}`);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Check if audio description is available\r\n */\r\n isAvailable() {\r\n const hasSourceElementsWithDesc = this.player.sourceElements.some(\r\n (el: Element) => el.getAttribute('data-desc-src')\r\n );\r\n return Boolean(this.src || hasSourceElementsWithDesc || this.captionTracks.length > 0);\r\n }\r\n\r\n /**\r\n * Enable audio description\r\n */\r\n async enable() {\r\n const hasSourceElementsWithDesc = this.player.sourceElements.some(\r\n (el: Element) => el.getAttribute('data-desc-src')\r\n );\r\n const hasTracksWithDesc = this.captionTracks.length > 0;\r\n \r\n if (!this.src && !hasSourceElementsWithDesc && !hasTracksWithDesc) {\r\n console.warn('VidPly: No audio description source, source elements, or tracks provided');\r\n return;\r\n }\r\n\r\n this.desiredState = true;\r\n\r\n // Store current state for restoration\r\n const currentTime = this.player.state.currentTime;\r\n const wasPlaying = this.player.state.playing;\r\n const posterValue = (this.player.element as HTMLVideoElement).poster || \r\n this.player.element.getAttribute('poster') || \r\n this.player.options.poster;\r\n const shouldKeepPoster = currentTime < 0.1 && !wasPlaying;\r\n\r\n // Get current caption text for synchronization\r\n const currentCaptionText = this._getCurrentCaptionText();\r\n\r\n // Switch to audio-described version based on what's available\r\n if (this.sourceElement) {\r\n // Use source element approach (data-desc-src on <source> elements)\r\n await this._enableWithSourceElement(currentTime, wasPlaying, posterValue, shouldKeepPoster, currentCaptionText);\r\n } else if (this.src) {\r\n // Use direct src approach (audioDescriptionSrc option)\r\n await this._enableWithDirectSrc(currentTime, wasPlaying, posterValue, shouldKeepPoster);\r\n } else if (hasTracksWithDesc) {\r\n // Only caption tracks with descriptions - swap tracks without changing video source\r\n await this._swapCaptionTracks(true);\r\n this.enabled = true;\r\n this.player.emit('audiodescriptionenabled');\r\n }\r\n // If none of the above, we already returned at the top check\r\n }\r\n\r\n /**\r\n * Disable audio description\r\n */\r\n async disable() {\r\n this.desiredState = false;\r\n\r\n // If we only had caption tracks (no video source swap), just swap tracks back\r\n const hasTracksWithDesc = this.captionTracks.length > 0;\r\n if (!this.sourceElement && !this.src && hasTracksWithDesc) {\r\n await this._swapCaptionTracks(false);\r\n this.enabled = false;\r\n this.player.emit('audiodescriptiondisabled');\r\n return;\r\n }\r\n\r\n if (!this.player.originalSrc) {\r\n return;\r\n }\r\n\r\n // Store current state\r\n const currentTime = this.player.state.currentTime;\r\n const wasPlaying = this.player.state.playing;\r\n const posterValue = (this.player.element as HTMLVideoElement).poster || \r\n this.player.element.getAttribute('poster') || \r\n this.player.options.poster;\r\n const shouldKeepPoster = currentTime < 0.1 && !wasPlaying;\r\n\r\n // Get current caption for sync\r\n const currentCaptionText = this._getCurrentCaptionText();\r\n\r\n if (this.sourceElement) {\r\n await this._disableWithSourceElement(currentTime, wasPlaying, posterValue, shouldKeepPoster, currentCaptionText);\r\n } else if (this.src) {\r\n await this._disableWithDirectSrc(currentTime, wasPlaying, posterValue);\r\n }\r\n }\r\n\r\n /**\r\n * Toggle audio description\r\n */\r\n async toggle() {\r\n const descriptionTrack = this.player.findTextTrack('descriptions');\r\n const hasAudioDescriptionSrc = this.isAvailable();\r\n \r\n if (descriptionTrack && !hasAudioDescriptionSrc) {\r\n // Toggle description track playback\r\n if (descriptionTrack.mode === 'showing') {\r\n descriptionTrack.mode = 'hidden';\r\n this.enabled = false;\r\n this.player.emit('audiodescriptiondisabled');\r\n } else {\r\n descriptionTrack.mode = 'showing';\r\n this.enabled = true;\r\n this.player.emit('audiodescriptionenabled');\r\n }\r\n } else if (descriptionTrack && hasAudioDescriptionSrc) {\r\n // Toggle both\r\n if (this.enabled) {\r\n this.desiredState = false;\r\n await this.disable();\r\n } else {\r\n descriptionTrack.mode = 'showing';\r\n this.desiredState = true;\r\n await this.enable();\r\n }\r\n } else if (hasAudioDescriptionSrc) {\r\n // Toggle source\r\n if (this.enabled) {\r\n this.desiredState = false;\r\n await this.disable();\r\n } else {\r\n this.desiredState = true;\r\n await this.enable();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get current caption text for synchronization\r\n */\r\n _getCurrentCaptionText() {\r\n if (this.player.captionManager && \r\n this.player.captionManager.currentTrack && \r\n this.player.captionManager.currentCue) {\r\n return this.player.captionManager.currentCue.text;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Validate that a track URL exists. Bounded by the player's lifecycle\r\n * AbortController + an 8s timeout so a torn-down player cannot leak\r\n * the request.\r\n */\r\n async _validateTrackExists(url: string): Promise<boolean> {\r\n if (typeof url !== 'string' || !url) return false;\r\n const signals: AbortSignal[] = [];\r\n const lifecycle = (this.player as { lifecycleSignal?: AbortSignal }).lifecycleSignal;\r\n if (lifecycle) signals.push(lifecycle);\r\n if (typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function') {\r\n signals.push(AbortSignal.timeout(8000));\r\n }\r\n let signal: AbortSignal | undefined;\r\n if (signals.length === 1) signal = signals[0];\r\n else if (signals.length > 1) {\r\n const anyFn = (AbortSignal as { any?: (s: AbortSignal[]) => AbortSignal }).any;\r\n signal = anyFn ? anyFn(signals) : signals[0];\r\n }\r\n try {\r\n const response = await fetch(url, { method: 'HEAD', signal });\r\n return response.ok;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Swap caption tracks to described versions\r\n */\r\n async _swapCaptionTracks(toDescribed = true) {\r\n if (this.captionTracks.length === 0) return [];\r\n\r\n const swappedTracks: CaptionTrackInfo[] = [];\r\n \r\n const validationPromises = this.captionTracks.map(async (trackInfo) => {\r\n if (trackInfo.trackElement && trackInfo.describedSrc) {\r\n if (trackInfo.explicit === true) {\r\n const url = toDescribed ? trackInfo.describedSrc : trackInfo.originalSrc;\r\n if (!url) return { trackInfo, exists: false };\r\n try {\r\n const exists = await this._validateTrackExists(url);\r\n return { trackInfo, exists };\r\n } catch {\r\n return { trackInfo, exists: false };\r\n }\r\n }\r\n }\r\n return { trackInfo, exists: false };\r\n });\r\n \r\n const validationResults = await Promise.all(validationPromises);\r\n const tracksToSwap = validationResults.filter(result => result.exists);\r\n \r\n if (tracksToSwap.length > 0) {\r\n // Store track modes before removing\r\n const trackModes = new Map();\r\n tracksToSwap.forEach(({ trackInfo }) => {\r\n const textTrack = trackInfo.trackElement.track;\r\n if (textTrack) {\r\n trackModes.set(trackInfo, {\r\n wasShowing: textTrack.mode === 'showing',\r\n wasHidden: textTrack.mode === 'hidden'\r\n });\r\n } else {\r\n trackModes.set(trackInfo, { wasShowing: false, wasHidden: false });\r\n }\r\n });\r\n \r\n // Store track info and remove\r\n const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {\r\n const attributes: Record<string, string> = {};\r\n Array.from(trackInfo.trackElement.attributes).forEach((attr: Attr) => {\r\n attributes[attr.name] = attr.value;\r\n });\r\n \r\n const result = {\r\n trackInfo,\r\n oldSrc: trackInfo.trackElement.getAttribute('src'),\r\n parent: trackInfo.trackElement.parentNode,\r\n nextSibling: trackInfo.trackElement.nextSibling,\r\n attributes\r\n };\r\n \r\n trackInfo.trackElement.remove();\r\n return result;\r\n });\r\n \r\n // Force browser to process removal\r\n this.player.element.load();\r\n \r\n // Re-add tracks with new src. Use a managed timeout so the swap\r\n // is cancelled (and won't mutate a torn-down player) on destroy.\r\n await new Promise<void>(resolve => {\r\n this.player.setManagedTimeout(() => {\r\n tracksToReadd.forEach(({ trackInfo, parent, nextSibling, attributes }) => {\r\n const newSrc = toDescribed ? trackInfo.describedSrc : trackInfo.originalSrc;\r\n if (!newSrc) {\r\n // Skip tracks without a usable src; no swap can occur.\r\n return;\r\n }\r\n swappedTracks.push(trackInfo);\r\n\r\n const newTrackElement = document.createElement('track');\r\n newTrackElement.setAttribute('src', newSrc);\r\n \r\n Object.keys(attributes).forEach(attrName => {\r\n const attrValue = attributes[attrName];\r\n if (attrName !== 'src' && attrName !== 'data-desc-src' && attrValue !== undefined) {\r\n newTrackElement.setAttribute(attrName, attrValue);\r\n }\r\n });\r\n \r\n // Use the player's video element as parent if the original parent is null\r\n const targetParent = parent || this.player.element;\r\n \r\n if (nextSibling && nextSibling.parentNode) {\r\n targetParent.insertBefore(newTrackElement, nextSibling);\r\n } else {\r\n targetParent.appendChild(newTrackElement);\r\n }\r\n \r\n trackInfo.trackElement = newTrackElement;\r\n });\r\n \r\n this.player.invalidateTrackCache();\r\n \r\n // Setup new tracks\r\n const setupNewTracks = () => {\r\n this.player.setManagedTimeout(() => {\r\n swappedTracks.forEach((trackInfo) => {\r\n const trackElement = trackInfo.trackElement;\r\n const newTextTrack = trackElement.track;\r\n if (newTextTrack) {\r\n const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };\r\n newTextTrack.mode = 'hidden';\r\n\r\n const restoreMode = () => {\r\n if (modeInfo.wasShowing || modeInfo.wasHidden) {\r\n newTextTrack.mode = 'hidden';\r\n } else {\r\n newTextTrack.mode = 'disabled';\r\n }\r\n };\r\n\r\n // `readyState` and the `load`/`error`\r\n // events live on `<track>`, not on\r\n // the underlying TextTrack object.\r\n if (trackElement.readyState >= 2) {\r\n restoreMode();\r\n } else {\r\n trackElement.addEventListener('load', restoreMode, { once: true });\r\n trackElement.addEventListener('error', restoreMode, { once: true });\r\n }\r\n }\r\n });\r\n }, 300);\r\n };\r\n \r\n if (this.player.element.readyState >= 1) {\r\n this.player.setManagedTimeout(setupNewTracks, 200);\r\n } else {\r\n this.player.element.addEventListener('loadedmetadata', setupNewTracks, { once: true });\r\n this.player.setManagedTimeout(setupNewTracks, 2000);\r\n }\r\n \r\n resolve();\r\n }, 100);\r\n });\r\n }\r\n \r\n return swappedTracks;\r\n }\r\n\r\n /**\r\n * Update source elements to described versions\r\n */\r\n _updateSourceElements(toDescribed = true) {\r\n const sourceElements = this.player.sourceElements;\r\n const sourcesToUpdate: Array<{ src: string | null; type: string | null; origSrc: string | null; descSrc: string | null }> = [];\r\n \r\n sourceElements.forEach((sourceEl: Element) => {\r\n const descSrcAttr = sourceEl.getAttribute('data-desc-src');\r\n const currentSrc = sourceEl.getAttribute('src');\r\n \r\n if (descSrcAttr) {\r\n const type = sourceEl.getAttribute('type');\r\n const origSrc = sourceEl.getAttribute('data-orig-src') || currentSrc;\r\n \r\n sourcesToUpdate.push({\r\n src: toDescribed ? descSrcAttr : origSrc,\r\n type,\r\n origSrc,\r\n descSrc: descSrcAttr\r\n });\r\n } else {\r\n sourcesToUpdate.push({\r\n src: sourceEl.getAttribute('src'),\r\n type: sourceEl.getAttribute('type'),\r\n origSrc: null,\r\n descSrc: null\r\n });\r\n }\r\n });\r\n \r\n // Remove src attribute if present\r\n if (this.player.element.hasAttribute('src')) {\r\n this.player.element.removeAttribute('src');\r\n }\r\n \r\n // Remove all source elements\r\n sourceElements.forEach((sourceEl: Element) => sourceEl.remove());\r\n \r\n // Re-add with updated src\r\n sourcesToUpdate.forEach((sourceInfo) => {\r\n if (!sourceInfo.src) {\r\n return;\r\n }\r\n const newSource = document.createElement('source');\r\n newSource.setAttribute('src', sourceInfo.src);\r\n if (sourceInfo.type) {\r\n newSource.setAttribute('type', sourceInfo.type);\r\n }\r\n if (sourceInfo.origSrc) {\r\n newSource.setAttribute('data-orig-src', sourceInfo.origSrc);\r\n }\r\n if (sourceInfo.descSrc) {\r\n newSource.setAttribute('data-desc-src', sourceInfo.descSrc);\r\n }\r\n \r\n const firstTrack = this.player.element.querySelector('track');\r\n if (firstTrack) {\r\n this.player.element.insertBefore(newSource, firstTrack);\r\n } else {\r\n this.player.element.appendChild(newSource);\r\n }\r\n });\r\n \r\n this.player._sourceElementsDirty = true;\r\n this.player._sourceElementsCache = null;\r\n }\r\n\r\n /**\r\n * Wait for media to be ready\r\n */\r\n async _waitForMediaReady(needSeek = false) {\r\n // Wait for metadata\r\n await new Promise<void>((resolve) => {\r\n if (this.player.element.readyState >= 1) {\r\n resolve();\r\n } else {\r\n const onLoad = () => {\r\n this.player.element.removeEventListener('loadedmetadata', onLoad);\r\n resolve();\r\n };\r\n this.player.element.addEventListener('loadedmetadata', onLoad);\r\n }\r\n });\r\n \r\n // Wait for tracks\r\n await new Promise(resolve => setTimeout(resolve, 300));\r\n \r\n // Wait for playback if needed\r\n if (needSeek) {\r\n await new Promise<void>((resolve) => {\r\n if (this.player.element.readyState >= 3) {\r\n resolve();\r\n } else {\r\n const onCanPlay = () => {\r\n this.player.element.removeEventListener('canplay', onCanPlay);\r\n this.player.element.removeEventListener('canplaythrough', onCanPlay);\r\n resolve();\r\n };\r\n this.player.element.addEventListener('canplay', onCanPlay, { once: true });\r\n this.player.element.addEventListener('canplaythrough', onCanPlay, { once: true });\r\n setTimeout(() => {\r\n this.player.element.removeEventListener('canplay', onCanPlay);\r\n this.player.element.removeEventListener('canplaythrough', onCanPlay);\r\n resolve();\r\n }, 3000);\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Restore playback state after source change\r\n */\r\n async _restorePlaybackState(currentTime: number, wasPlaying: boolean, shouldKeepPoster: boolean, currentCaptionText: string | null) {\r\n // Try to find matching caption for sync\r\n let syncTime = currentTime;\r\n if (currentCaptionText && this.player.captionManager && this.player.captionManager.tracks.length > 0) {\r\n await new Promise(resolve => setTimeout(resolve, 500));\r\n const matchingTime = this.player.findMatchingCaptionTime(\r\n currentCaptionText, \r\n this.player.captionManager.tracks\r\n );\r\n if (matchingTime !== null) {\r\n syncTime = matchingTime;\r\n if (this.player.options.debug) {\r\n this.player.log(`[VidPly] Syncing via caption: ${currentTime}s -> ${syncTime}s`);\r\n }\r\n }\r\n }\r\n \r\n // Seek\r\n if (syncTime > 0) {\r\n this.player.seek(syncTime);\r\n await new Promise(resolve => setTimeout(resolve, 100));\r\n }\r\n \r\n // Play/pause\r\n if (wasPlaying) {\r\n await this.player.play();\r\n this.player.setManagedTimeout(() => {\r\n this.player.hidePosterOverlay();\r\n }, 100);\r\n } else {\r\n this.player.pause();\r\n if (!shouldKeepPoster) {\r\n this.player.hidePosterOverlay();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Enable with source element method\r\n */\r\n async _enableWithSourceElement(currentTime: number, wasPlaying: boolean, posterValue: string | null, shouldKeepPoster: boolean, currentCaptionText: string | null) {\r\n // Swap caption tracks\r\n await this._swapCaptionTracks(true);\r\n \r\n // Update source elements\r\n this._updateSourceElements(true);\r\n \r\n // Preserve poster\r\n if (posterValue && this.player.element.tagName === 'VIDEO') {\r\n (this.player.element as HTMLVideoElement).poster = posterValue;\r\n }\r\n \r\n // Reload\r\n this.player.element.load();\r\n \r\n // Wait for ready\r\n await this._waitForMediaReady(currentTime > 0 || wasPlaying);\r\n \r\n // Restore playback\r\n await this._restorePlaybackState(currentTime, wasPlaying, shouldKeepPoster, currentCaptionText);\r\n \r\n // Update state\r\n if (!this.desiredState) return;\r\n this.enabled = true;\r\n this.player.state.audioDescriptionEnabled = true;\r\n this.player.emit('audiodescriptionenabled');\r\n \r\n // Reload transcript if visible\r\n this._reloadTranscript();\r\n }\r\n\r\n /**\r\n * Enable with direct src method\r\n */\r\n async _enableWithDirectSrc(currentTime: number, wasPlaying: boolean, posterValue: string | null, shouldKeepPoster: boolean) {\r\n // Swap caption tracks\r\n await this._swapCaptionTracks(true);\r\n \r\n // Set poster\r\n if (posterValue && this.player.element.tagName === 'VIDEO') {\r\n (this.player.element as HTMLVideoElement).poster = posterValue;\r\n }\r\n \r\n // Set src (this method should only be called when this.src exists)\r\n if (!this.src) return;\r\n this.player.element.src = this.src;\r\n \r\n // Wait and restore\r\n await this._waitForMediaReady(currentTime > 0 || wasPlaying);\r\n \r\n if (currentTime > 0) {\r\n this.player.seek(currentTime);\r\n await new Promise(resolve => setTimeout(resolve, 100));\r\n }\r\n \r\n if (wasPlaying) {\r\n await this.player.play();\r\n } else {\r\n this.player.pause();\r\n if (!shouldKeepPoster) {\r\n this.player.hidePosterOverlay();\r\n }\r\n }\r\n \r\n if (!this.desiredState) return;\r\n this.enabled = true;\r\n this.player.state.audioDescriptionEnabled = true;\r\n this.player.emit('audiodescriptionenabled');\r\n \r\n // Reload transcript if visible\r\n this._reloadTranscript();\r\n }\r\n\r\n /**\r\n * Disable with source element method\r\n */\r\n async _disableWithSourceElement(currentTime: number, wasPlaying: boolean, posterValue: string | null, shouldKeepPoster: boolean, currentCaptionText: string | null) {\r\n // Swap caption tracks back\r\n await this._swapCaptionTracks(false);\r\n \r\n // Update source elements\r\n this._updateSourceElements(false);\r\n \r\n // Preserve poster\r\n if (posterValue && this.player.element.tagName === 'VIDEO') {\r\n (this.player.element as HTMLVideoElement).poster = posterValue;\r\n }\r\n \r\n // Reload\r\n this.player.element.load();\r\n this.player.invalidateTrackCache();\r\n \r\n // Wait for ready\r\n await this._waitForMediaReady(currentTime > 0 || wasPlaying);\r\n \r\n // Restore playback\r\n await this._restorePlaybackState(currentTime, wasPlaying, shouldKeepPoster, currentCaptionText);\r\n \r\n // Reinitialize caption manager\r\n if (this.player.captionManager) {\r\n this.player.captionManager.destroy();\r\n this.player.captionManager = new CaptionManager(this.player);\r\n }\r\n \r\n // Update state\r\n if (this.desiredState) return;\r\n this.enabled = false;\r\n this.player.state.audioDescriptionEnabled = false;\r\n this.player.emit('audiodescriptiondisabled');\r\n \r\n // Reload transcript if visible\r\n this._reloadTranscript();\r\n }\r\n\r\n /**\r\n * Disable with direct src method\r\n */\r\n async _disableWithDirectSrc(currentTime: number, wasPlaying: boolean, posterValue: string | null) {\r\n // Swap caption tracks back\r\n await this._swapCaptionTracks(false);\r\n \r\n // Set poster\r\n if (posterValue && this.player.element.tagName === 'VIDEO') {\r\n (this.player.element as HTMLVideoElement).poster = posterValue;\r\n }\r\n \r\n // Restore original src\r\n const originalSrcToUse = this.originalSource || this.player.originalSrc;\r\n if (!originalSrcToUse) {\r\n return;\r\n }\r\n this.player.element.src = originalSrcToUse;\r\n this.player.element.load();\r\n \r\n // Wait and restore\r\n await this._waitForMediaReady(currentTime > 0 || wasPlaying);\r\n \r\n if (currentTime > 0) {\r\n this.player.seek(currentTime);\r\n }\r\n \r\n if (wasPlaying) {\r\n await this.player.play();\r\n }\r\n \r\n if (this.desiredState) return;\r\n this.enabled = false;\r\n this.player.state.audioDescriptionEnabled = false;\r\n this.player.emit('audiodescriptiondisabled');\r\n \r\n // Reload transcript if visible\r\n this._reloadTranscript();\r\n }\r\n\r\n /**\r\n * Reload transcript after audio description state change\r\n */\r\n _reloadTranscript() {\r\n if (this.player.transcriptManager && this.player.transcriptManager.isVisible) {\r\n // Wait for tracks to load after source swap\r\n this.player.setManagedTimeout(() => {\r\n if (this.player.transcriptManager && this.player.transcriptManager.loadTranscriptData) {\r\n this.player.transcriptManager.loadTranscriptData();\r\n }\r\n }, 800);\r\n }\r\n }\r\n\r\n /**\r\n * Update sources (called when playlist changes)\r\n */\r\n updateSources(audioDescriptionSrc: string | null | undefined) {\r\n this.src = audioDescriptionSrc || null;\r\n // Reset state for new playlist item\r\n this.enabled = false;\r\n this.desiredState = false;\r\n this.sourceElement = null;\r\n this.originalSource = null;\r\n this.captionTracks = [];\r\n }\r\n \r\n /**\r\n * Reinitialize from current player elements (called after playlist loads new tracks)\r\n */\r\n reinitialize() {\r\n this.player.invalidateTrackCache();\r\n this.initFromSourceElements(this.player.sourceElements, this.player.trackElements);\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy() {\r\n this.enabled = false;\r\n this.desiredState = false;\r\n this.captionTracks = [];\r\n this.sourceElement = null;\r\n this.originalSource = null;\r\n }\r\n}\r\n\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }