vidply 1.1.19 → 1.2.1

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 (168) hide show
  1. package/README.md +13 -6
  2. package/dist/dev/{vidply.AudioDescriptionManager-NRMNKZAL.js → vidply.AudioDescriptionManager-6RFVF27Z.js} +281 -23
  3. package/dist/dev/vidply.AudioDescriptionManager-6RFVF27Z.js.map +7 -0
  4. package/dist/dev/vidply.CaptionStyleMenu-R2SCQ6VP.js +300 -0
  5. package/dist/dev/vidply.CaptionStyleMenu-R2SCQ6VP.js.map +7 -0
  6. package/dist/dev/{vidply.DASHRenderer-SYXX6RRS.js → vidply.DASHRenderer-EOVEW73H.js} +39 -32
  7. package/dist/dev/vidply.DASHRenderer-EOVEW73H.js.map +7 -0
  8. package/dist/dev/{vidply.FloatingPlayerManager-HJVGUQLT.js → vidply.FloatingPlayerManager-V5XQWS75.js} +10 -5
  9. package/dist/dev/vidply.FloatingPlayerManager-V5XQWS75.js.map +7 -0
  10. package/dist/dev/{vidply.HLSRenderer-YAFEUBMC.js → vidply.HLSRenderer-ZBEFVH5W.js} +80 -45
  11. package/dist/dev/vidply.HLSRenderer-ZBEFVH5W.js.map +7 -0
  12. package/dist/dev/vidply.HTML5Renderer-P7ICKYU4.js +12 -0
  13. package/dist/dev/{vidply.SignLanguageManager-ZZ6DIDTP.js → vidply.SignLanguageManager-7IAJOVF6.js} +14 -13
  14. package/dist/dev/vidply.SignLanguageManager-7IAJOVF6.js.map +7 -0
  15. package/dist/dev/{vidply.SoundCloudRenderer-OFBGL7UV.js → vidply.SoundCloudRenderer-OA7QQYGN.js} +30 -18
  16. package/dist/dev/vidply.SoundCloudRenderer-OA7QQYGN.js.map +7 -0
  17. package/dist/dev/{vidply.TranscriptManager-4553RRA6.js → vidply.TranscriptManager-BPM3T23L.js} +24 -21
  18. package/dist/dev/vidply.TranscriptManager-BPM3T23L.js.map +7 -0
  19. package/dist/dev/{vidply.VimeoRenderer-EVW2RNSF.js → vidply.VimeoRenderer-BRHFYPNJ.js} +8 -9
  20. package/dist/dev/vidply.VimeoRenderer-BRHFYPNJ.js.map +7 -0
  21. package/dist/dev/{vidply.YouTubeRenderer-PZHT3GMF.js → vidply.YouTubeRenderer-HRTN4EJ5.js} +10 -25
  22. package/dist/dev/vidply.YouTubeRenderer-HRTN4EJ5.js.map +7 -0
  23. package/dist/dev/vidply.chunk-5IK3IC5V.js +57 -0
  24. package/dist/dev/vidply.chunk-5IK3IC5V.js.map +7 -0
  25. package/dist/dev/{vidply.chunk-RQGZAPWY.js → vidply.chunk-C55OBT5H.js} +5 -2
  26. package/dist/dev/vidply.chunk-C55OBT5H.js.map +7 -0
  27. package/dist/dev/vidply.chunk-HOYEMJSD.js +87 -0
  28. package/dist/dev/vidply.chunk-HOYEMJSD.js.map +7 -0
  29. package/dist/dev/{vidply.chunk-24QLI7ZK.js → vidply.chunk-JAKZNGOR.js} +2 -2
  30. package/dist/dev/vidply.chunk-JAKZNGOR.js.map +7 -0
  31. package/dist/dev/{vidply.chunk-AQDY6B5B.js → vidply.chunk-LDVFAFGC.js} +15 -48
  32. package/dist/dev/vidply.chunk-LDVFAFGC.js.map +7 -0
  33. package/dist/dev/{vidply.chunk-KMACPXZ5.js → vidply.chunk-NSMAZCMB.js} +10 -9
  34. package/dist/dev/vidply.chunk-NSMAZCMB.js.map +7 -0
  35. package/dist/dev/{vidply.chunk-MQAA3FKI.js → vidply.chunk-RQG3MA7W.js} +2 -2
  36. package/dist/dev/vidply.chunk-RQG3MA7W.js.map +7 -0
  37. package/dist/dev/{vidply.chunk-QF77EYBM.js → vidply.chunk-UHMVDBDB.js} +7 -4
  38. package/dist/dev/{vidply.chunk-QF77EYBM.js.map → vidply.chunk-UHMVDBDB.js.map} +2 -2
  39. package/dist/dev/{vidply.chunk-TM5HFGG5.js → vidply.chunk-W5BR65JY.js} +35 -19
  40. package/dist/dev/vidply.chunk-W5BR65JY.js.map +7 -0
  41. package/dist/dev/{vidply.chunk-PTYRD6ZP.js → vidply.chunk-XAK3DPTO.js} +28 -24
  42. package/dist/dev/vidply.chunk-XAK3DPTO.js.map +7 -0
  43. package/dist/dev/{vidply.chunk-NUTGO3RK.js → vidply.chunk-YVCYQZJI.js} +6 -6
  44. package/dist/dev/vidply.chunk-YVCYQZJI.js.map +7 -0
  45. package/dist/dev/{vidply.de-27ZM6TOB.js → vidply.de-5W5LBFSJ.js} +2 -2
  46. package/dist/dev/{vidply.es-XNGJJLWC.js → vidply.es-SHDAT6L6.js} +2 -2
  47. package/dist/dev/vidply.esm.js +270 -391
  48. package/dist/dev/vidply.esm.js.map +2 -2
  49. package/dist/dev/{vidply.fr-AVZKPUBH.js → vidply.fr-2JANOMNB.js} +2 -2
  50. package/dist/dev/{vidply.ja-IZK2UXDC.js → vidply.ja-WWMSTEJH.js} +2 -2
  51. package/dist/legacy/vidply.js +1185 -565
  52. package/dist/legacy/vidply.js.map +4 -4
  53. package/dist/legacy/vidply.min.js +2 -2
  54. package/dist/legacy/vidply.min.meta.json +157 -56
  55. package/dist/prod/vidply.AudioDescriptionManager-YTDVDQBO.min.js +6 -0
  56. package/dist/prod/vidply.CaptionStyleMenu-2AFF3HF2.min.js +6 -0
  57. package/dist/prod/vidply.DASHRenderer-URDOTOKS.min.js +6 -0
  58. package/dist/prod/{vidply.FloatingPlayerManager-FNM5V76W.min.js → vidply.FloatingPlayerManager-QUBFK7CQ.min.js} +2 -2
  59. package/dist/prod/vidply.HLSRenderer-46KNUVAB.min.js +6 -0
  60. package/dist/prod/vidply.HTML5Renderer-7TQDMIGY.min.js +6 -0
  61. package/dist/prod/vidply.SignLanguageManager-H4C36EVL.min.js +6 -0
  62. package/dist/prod/vidply.SoundCloudRenderer-OYSWMW7D.min.js +6 -0
  63. package/dist/prod/vidply.TranscriptManager-BA3DAS63.min.js +6 -0
  64. package/dist/prod/vidply.VimeoRenderer-NF3COTHU.min.js +6 -0
  65. package/dist/prod/vidply.YouTubeRenderer-UCQKYIJ4.min.js +6 -0
  66. package/dist/prod/vidply.chunk-2HNCP64N.min.js +6 -0
  67. package/dist/prod/vidply.chunk-6ECBIYVI.min.js +6 -0
  68. package/dist/prod/vidply.chunk-7S5AFTST.min.js +6 -0
  69. package/dist/prod/vidply.chunk-EUOA2DJK.min.js +6 -0
  70. package/dist/prod/vidply.chunk-G6KGXNEW.min.js +6 -0
  71. package/dist/prod/{vidply.chunk-WE6VR5E2.min.js → vidply.chunk-JPMAK3NS.min.js} +1 -1
  72. package/dist/prod/{vidply.chunk-D7PUX3IJ.min.js → vidply.chunk-L4O44K63.min.js} +1 -1
  73. package/dist/prod/vidply.chunk-M76ABMKB.min.js +6 -0
  74. package/dist/prod/vidply.chunk-WRVDVD33.min.js +6 -0
  75. package/dist/prod/{vidply.chunk-HKXIYL5T.min.js → vidply.chunk-X2FQEQYR.min.js} +2 -2
  76. package/dist/prod/vidply.chunk-XXUH7ADU.min.js +6 -0
  77. package/dist/prod/{vidply.de-RZ2FVGU4.min.js → vidply.de-JMCATTKZ.min.js} +1 -1
  78. package/dist/prod/{vidply.es-KUCGSMAA.min.js → vidply.es-YVG37V7Z.min.js} +1 -1
  79. package/dist/prod/vidply.esm.min.js +2 -2
  80. package/dist/prod/{vidply.fr-2FOZ6M7L.min.js → vidply.fr-OGKGN2R4.min.js} +1 -1
  81. package/dist/prod/{vidply.ja-5H6AMU2R.min.js → vidply.ja-Z6DS7QLS.min.js} +1 -1
  82. package/dist/vidply.css +5796 -5892
  83. package/dist/vidply.esm.min.meta.json +430 -241
  84. package/dist/vidply.min.css +1 -1
  85. package/package.json +95 -92
  86. package/src/controls/CaptionManager.ts +11 -4
  87. package/src/controls/CaptionStyleMenu.ts +370 -0
  88. package/src/controls/ControlBar.ts +93 -403
  89. package/src/controls/KeyboardManager.ts +78 -2
  90. package/src/controls/SettingsDialog.ts +32 -2
  91. package/src/controls/TranscriptManager.ts +12 -10
  92. package/src/core/AudioDescriptionManager.ts +114 -23
  93. package/src/core/DescriptionSpeechManager.ts +232 -0
  94. package/src/core/FloatingPlayerManager.ts +674 -663
  95. package/src/core/MetadataAlertsManager.ts +2 -1
  96. package/src/core/Player.ts +97 -33
  97. package/src/core/PseudoFullscreen.ts +4 -2
  98. package/src/core/SignLanguageManager.ts +9 -7
  99. package/src/features/PlaylistManager.ts +56 -30
  100. package/src/i18n/translations.ts +28 -28
  101. package/src/icons/Icons.ts +167 -167
  102. package/src/index.ts +4 -1
  103. package/src/renderers/DASHRenderer.ts +39 -30
  104. package/src/renderers/HLSRenderer.ts +99 -53
  105. package/src/renderers/HTML5Renderer.ts +389 -382
  106. package/src/renderers/SoundCloudRenderer.ts +33 -18
  107. package/src/renderers/VimeoRenderer.ts +298 -298
  108. package/src/renderers/YouTubeRenderer.ts +290 -305
  109. package/src/styles/vidply.css +5796 -5892
  110. package/src/types/events.ts +2 -0
  111. package/src/types/globals.d.ts +313 -279
  112. package/src/types/index.ts +4 -4
  113. package/src/types/options.ts +3 -0
  114. package/src/types/renderer.ts +58 -63
  115. package/src/types/state.ts +24 -24
  116. package/src/utils/DOMUtils.ts +4 -3
  117. package/src/utils/DownloadInfo.ts +2 -2
  118. package/src/utils/DraggableResizable.ts +997 -994
  119. package/src/utils/EventEmitter.ts +59 -59
  120. package/src/utils/FocusUtils.ts +26 -26
  121. package/src/utils/FormUtils.ts +95 -95
  122. package/src/utils/MenuFactory.ts +483 -461
  123. package/src/utils/MenuUtils.ts +190 -172
  124. package/src/utils/PerformanceUtils.ts +63 -40
  125. package/src/utils/ResizeHandles.ts +58 -58
  126. package/src/utils/ScriptLoader.ts +137 -0
  127. package/src/utils/SettingsMenuFactory.ts +289 -276
  128. package/src/utils/StorageManager.ts +4 -1
  129. package/src/utils/TimeUtils.ts +67 -67
  130. package/src/utils/WindowComponents.ts +250 -250
  131. package/dist/dev/vidply.AudioDescriptionManager-NRMNKZAL.js.map +0 -7
  132. package/dist/dev/vidply.DASHRenderer-SYXX6RRS.js.map +0 -7
  133. package/dist/dev/vidply.FloatingPlayerManager-HJVGUQLT.js.map +0 -7
  134. package/dist/dev/vidply.HLSRenderer-YAFEUBMC.js.map +0 -7
  135. package/dist/dev/vidply.HTML5Renderer-ITDUMSTL.js +0 -12
  136. package/dist/dev/vidply.SignLanguageManager-ZZ6DIDTP.js.map +0 -7
  137. package/dist/dev/vidply.SoundCloudRenderer-OFBGL7UV.js.map +0 -7
  138. package/dist/dev/vidply.TranscriptManager-4553RRA6.js.map +0 -7
  139. package/dist/dev/vidply.VimeoRenderer-EVW2RNSF.js.map +0 -7
  140. package/dist/dev/vidply.YouTubeRenderer-PZHT3GMF.js.map +0 -7
  141. package/dist/dev/vidply.chunk-24QLI7ZK.js.map +0 -7
  142. package/dist/dev/vidply.chunk-AQDY6B5B.js.map +0 -7
  143. package/dist/dev/vidply.chunk-KMACPXZ5.js.map +0 -7
  144. package/dist/dev/vidply.chunk-MQAA3FKI.js.map +0 -7
  145. package/dist/dev/vidply.chunk-NUTGO3RK.js.map +0 -7
  146. package/dist/dev/vidply.chunk-PTYRD6ZP.js.map +0 -7
  147. package/dist/dev/vidply.chunk-RQGZAPWY.js.map +0 -7
  148. package/dist/dev/vidply.chunk-TM5HFGG5.js.map +0 -7
  149. package/dist/prod/vidply.AudioDescriptionManager-QVL4TD4R.min.js +0 -6
  150. package/dist/prod/vidply.DASHRenderer-DVBO6JRL.min.js +0 -6
  151. package/dist/prod/vidply.HLSRenderer-AHFQI64X.min.js +0 -6
  152. package/dist/prod/vidply.HTML5Renderer-WNGD745H.min.js +0 -6
  153. package/dist/prod/vidply.SignLanguageManager-E65WKF37.min.js +0 -6
  154. package/dist/prod/vidply.SoundCloudRenderer-XD3TMM5O.min.js +0 -6
  155. package/dist/prod/vidply.TranscriptManager-6JM6CJTM.min.js +0 -6
  156. package/dist/prod/vidply.VimeoRenderer-7L6RWMWE.min.js +0 -6
  157. package/dist/prod/vidply.YouTubeRenderer-ZAQTBKM4.min.js +0 -6
  158. package/dist/prod/vidply.chunk-3L3VQFPN.min.js +0 -6
  159. package/dist/prod/vidply.chunk-5644WA3F.min.js +0 -6
  160. package/dist/prod/vidply.chunk-6DG7I4DA.min.js +0 -6
  161. package/dist/prod/vidply.chunk-OFMLXH4A.min.js +0 -6
  162. package/dist/prod/vidply.chunk-VX4CE6WF.min.js +0 -6
  163. package/dist/prod/vidply.chunk-W5YQ5TEO.min.js +0 -6
  164. /package/dist/dev/{vidply.HTML5Renderer-ITDUMSTL.js.map → vidply.HTML5Renderer-P7ICKYU4.js.map} +0 -0
  165. /package/dist/dev/{vidply.de-27ZM6TOB.js.map → vidply.de-5W5LBFSJ.js.map} +0 -0
  166. /package/dist/dev/{vidply.es-XNGJJLWC.js.map → vidply.es-SHDAT6L6.js.map} +0 -0
  167. /package/dist/dev/{vidply.fr-AVZKPUBH.js.map → vidply.fr-2JANOMNB.js.map} +0 -0
  168. /package/dist/dev/{vidply.ja-IZK2UXDC.js.map → vidply.ja-WWMSTEJH.js.map} +0 -0
@@ -0,0 +1,300 @@
1
+ /*!
2
+ * VidPly v1.2.1 - Universal, Accessible Video Player
3
+ * (c) 2026 Matthias Peltzer
4
+ * Released under GPL-2.0-or-later License
5
+ */
6
+ import {
7
+ focusFirstElement
8
+ } from "./vidply.chunk-JAKZNGOR.js";
9
+ import {
10
+ DOMUtils,
11
+ i18n
12
+ } from "./vidply.chunk-NSMAZCMB.js";
13
+
14
+ // src/controls/CaptionStyleMenu.ts
15
+ function captionStylePropertyName(property) {
16
+ const stripped = property.replace("captions", "");
17
+ return stripped.charAt(0).toLowerCase() + stripped.slice(1);
18
+ }
19
+ function createStyleControl(player, label, property, options) {
20
+ const group = DOMUtils.createElement("div", {
21
+ className: `${player.options.classPrefix}-style-group`
22
+ });
23
+ const controlId = `${player.options.classPrefix}-${property}-${Date.now()}`;
24
+ const labelEl = DOMUtils.createElement("label", {
25
+ textContent: label,
26
+ attributes: {
27
+ "for": controlId
28
+ },
29
+ style: {
30
+ display: "block",
31
+ fontSize: "12px",
32
+ marginBottom: "4px",
33
+ color: "rgba(255,255,255,0.7)"
34
+ }
35
+ });
36
+ group.appendChild(labelEl);
37
+ const select = DOMUtils.createElement("select", {
38
+ className: `${player.options.classPrefix}-style-select`,
39
+ attributes: {
40
+ "id": controlId
41
+ },
42
+ style: {
43
+ width: "100%",
44
+ padding: "6px",
45
+ background: "var(--vidply-white)",
46
+ border: "1px solid var(--vidply-white-10)",
47
+ borderRadius: "4px",
48
+ color: "var(--vidply-black)",
49
+ fontSize: "13px"
50
+ }
51
+ });
52
+ const currentValue = player.options[property];
53
+ options.forEach((opt) => {
54
+ const option = DOMUtils.createElement("option", {
55
+ textContent: opt.label,
56
+ attributes: { value: opt.value }
57
+ });
58
+ if (opt.value === currentValue) {
59
+ option.selected = true;
60
+ }
61
+ select.appendChild(option);
62
+ });
63
+ select.addEventListener("mousedown", (e) => {
64
+ e.stopPropagation();
65
+ });
66
+ select.addEventListener("click", (e) => {
67
+ e.stopPropagation();
68
+ });
69
+ select.addEventListener("change", (e) => {
70
+ e.stopPropagation();
71
+ player.options[property] = e.target.value;
72
+ if (player.captionManager) {
73
+ player.captionManager.setCaptionStyle(
74
+ captionStylePropertyName(property),
75
+ e.target.value
76
+ );
77
+ }
78
+ });
79
+ group.appendChild(select);
80
+ return group;
81
+ }
82
+ function createColorControl(player, label, property) {
83
+ const group = DOMUtils.createElement("div", {
84
+ className: `${player.options.classPrefix}-style-group`
85
+ });
86
+ const controlId = `${player.options.classPrefix}-${property}-${Date.now()}`;
87
+ const labelEl = DOMUtils.createElement("label", {
88
+ textContent: label,
89
+ attributes: {
90
+ "for": controlId
91
+ },
92
+ style: {
93
+ display: "block",
94
+ fontSize: "12px",
95
+ marginBottom: "4px",
96
+ color: "rgba(255,255,255,0.7)"
97
+ }
98
+ });
99
+ group.appendChild(labelEl);
100
+ const input = DOMUtils.createElement("input", {
101
+ attributes: {
102
+ "id": controlId,
103
+ type: "color",
104
+ value: String(player.options[property] ?? "")
105
+ },
106
+ style: {
107
+ width: "100%",
108
+ height: "32px",
109
+ padding: "2px",
110
+ background: "rgba(255,255,255,0.1)",
111
+ border: "1px solid rgba(255,255,255,0.2)",
112
+ borderRadius: "4px",
113
+ cursor: "pointer"
114
+ }
115
+ });
116
+ input.addEventListener("mousedown", (e) => {
117
+ e.stopPropagation();
118
+ });
119
+ input.addEventListener("click", (e) => {
120
+ e.stopPropagation();
121
+ });
122
+ input.addEventListener("change", (e) => {
123
+ e.stopPropagation();
124
+ player.options[property] = e.target.value;
125
+ if (player.captionManager) {
126
+ player.captionManager.setCaptionStyle(
127
+ captionStylePropertyName(property),
128
+ e.target.value
129
+ );
130
+ }
131
+ });
132
+ group.appendChild(input);
133
+ return group;
134
+ }
135
+ function createOpacityControl(player, label, property) {
136
+ const group = DOMUtils.createElement("div", {
137
+ className: `${player.options.classPrefix}-style-group`
138
+ });
139
+ const controlId = `${player.options.classPrefix}-${property}-${Date.now()}`;
140
+ const labelContainer = DOMUtils.createElement("div", {
141
+ style: {
142
+ display: "flex",
143
+ justifyContent: "space-between",
144
+ marginBottom: "4px"
145
+ }
146
+ });
147
+ const labelEl = DOMUtils.createElement("label", {
148
+ textContent: label,
149
+ attributes: {
150
+ "for": controlId
151
+ },
152
+ style: {
153
+ fontSize: "12px",
154
+ color: "rgba(255,255,255,0.7)"
155
+ }
156
+ });
157
+ const valueEl = DOMUtils.createElement("span", {
158
+ textContent: Math.round(Number(player.options[property] ?? 0) * 100) + "%",
159
+ style: {
160
+ fontSize: "12px",
161
+ color: "rgba(255,255,255,0.7)"
162
+ }
163
+ });
164
+ labelContainer.appendChild(labelEl);
165
+ labelContainer.appendChild(valueEl);
166
+ group.appendChild(labelContainer);
167
+ const input = DOMUtils.createElement("input", {
168
+ attributes: {
169
+ "id": controlId,
170
+ type: "range",
171
+ min: "0",
172
+ max: "1",
173
+ step: "0.1",
174
+ value: String(player.options[property])
175
+ },
176
+ style: {
177
+ width: "100%",
178
+ cursor: "pointer"
179
+ }
180
+ });
181
+ input.addEventListener("mousedown", (e) => {
182
+ e.stopPropagation();
183
+ });
184
+ input.addEventListener("click", (e) => {
185
+ e.stopPropagation();
186
+ });
187
+ input.addEventListener("input", (e) => {
188
+ e.stopPropagation();
189
+ const value = parseFloat(e.target.value);
190
+ valueEl.textContent = Math.round(value * 100) + "%";
191
+ player.options[property] = value;
192
+ if (player.captionManager) {
193
+ player.captionManager.setCaptionStyle(
194
+ captionStylePropertyName(property),
195
+ value
196
+ );
197
+ }
198
+ });
199
+ group.appendChild(input);
200
+ return group;
201
+ }
202
+ function showCaptionStyleMenu(controlBar, button) {
203
+ const player = controlBar.player;
204
+ const existingMenu = document.querySelector(`.${player.options.classPrefix}-caption-style-menu`);
205
+ if (existingMenu) {
206
+ existingMenu.remove();
207
+ button.setAttribute("aria-expanded", "false");
208
+ if (controlBar.openMenu === existingMenu) {
209
+ controlBar.openMenu = null;
210
+ controlBar.openMenuButton = null;
211
+ }
212
+ return;
213
+ }
214
+ const menuLabelId = `${player.options.classPrefix}-caption-style-label-${player.instanceId || ""}`;
215
+ const menu = DOMUtils.createElement("div", {
216
+ className: `${player.options.classPrefix}-caption-style-menu ${player.options.classPrefix}-menu ${player.options.classPrefix}-settings-menu`,
217
+ attributes: {
218
+ "role": "dialog",
219
+ "aria-modal": "false",
220
+ "aria-labelledby": menuLabelId
221
+ }
222
+ });
223
+ const visuallyHiddenLabel = DOMUtils.createElement("h2", {
224
+ textContent: i18n.t("player.captionStyling"),
225
+ attributes: { id: menuLabelId, class: `${player.options.classPrefix}-sr-only` },
226
+ style: {
227
+ position: "absolute",
228
+ width: "1px",
229
+ height: "1px",
230
+ padding: "0",
231
+ margin: "-1px",
232
+ overflow: "hidden",
233
+ clip: "rect(0,0,0,0)",
234
+ whiteSpace: "nowrap",
235
+ border: "0"
236
+ }
237
+ });
238
+ menu.appendChild(visuallyHiddenLabel);
239
+ menu.addEventListener("click", (e) => {
240
+ e.stopPropagation();
241
+ });
242
+ if (!player.captionManager || player.captionManager.tracks.length === 0) {
243
+ const noTracksItem = DOMUtils.createElement("div", {
244
+ className: `${player.options.classPrefix}-menu-item`,
245
+ textContent: i18n.t("player.noCaptions"),
246
+ attributes: {
247
+ "role": "status"
248
+ },
249
+ style: { opacity: "0.5", cursor: "default", padding: "12px 16px" }
250
+ });
251
+ menu.appendChild(noTracksItem);
252
+ menu.style.visibility = "hidden";
253
+ menu.style.display = "block";
254
+ controlBar.insertMenuIntoDOM(menu, button);
255
+ controlBar.positionMenu(menu, button, true);
256
+ requestAnimationFrame(() => {
257
+ menu.style.visibility = "visible";
258
+ });
259
+ controlBar.attachMenuCloseHandler(menu, button, true);
260
+ return;
261
+ }
262
+ menu.appendChild(createStyleControl(
263
+ player,
264
+ i18n.t("styleLabels.fontSize"),
265
+ "captionsFontSize",
266
+ [
267
+ { label: i18n.t("fontSizes.small"), value: "87.5%" },
268
+ { label: i18n.t("fontSizes.normal"), value: "100%" },
269
+ { label: i18n.t("fontSizes.large"), value: "125%" },
270
+ { label: i18n.t("fontSizes.xlarge"), value: "150%" }
271
+ ]
272
+ ));
273
+ menu.appendChild(createStyleControl(
274
+ player,
275
+ i18n.t("styleLabels.font"),
276
+ "captionsFontFamily",
277
+ [
278
+ { label: i18n.t("fontFamilies.sansSerif"), value: "sans-serif" },
279
+ { label: i18n.t("fontFamilies.serif"), value: "serif" },
280
+ { label: i18n.t("fontFamilies.monospace"), value: "monospace" }
281
+ ]
282
+ ));
283
+ menu.appendChild(createColorControl(player, i18n.t("styleLabels.textColor"), "captionsColor"));
284
+ menu.appendChild(createColorControl(player, i18n.t("styleLabels.background"), "captionsBackgroundColor"));
285
+ menu.appendChild(createOpacityControl(player, i18n.t("styleLabels.opacity"), "captionsOpacity"));
286
+ menu.style.minWidth = "220px";
287
+ menu.style.visibility = "hidden";
288
+ menu.style.display = "block";
289
+ controlBar.insertMenuIntoDOM(menu, button);
290
+ controlBar.positionMenu(menu, button, true);
291
+ requestAnimationFrame(() => {
292
+ menu.style.visibility = "visible";
293
+ });
294
+ controlBar.attachMenuCloseHandler(menu, button, true);
295
+ focusFirstElement(menu, `.${player.options.classPrefix}-style-select`);
296
+ }
297
+ export {
298
+ showCaptionStyleMenu
299
+ };
300
+ //# sourceMappingURL=vidply.CaptionStyleMenu-R2SCQ6VP.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/controls/CaptionStyleMenu.ts"],
4
+ "sourcesContent": ["/**\n * Caption-style menu (font size/family, text & background color, opacity).\n *\n * Extracted from ControlBar and loaded on demand via dynamic import() so the\n * builder code for this relatively rarely-opened panel is not part of the\n * always-loaded core bundle. ControlBar.showCaptionStyleMenu() awaits this\n * module the first time the panel is opened.\n */\n\nimport { DOMUtils } from '../utils/DOMUtils.js';\nimport { i18n } from '../i18n/i18n.js';\nimport { focusFirstElement } from '../utils/FocusUtils.js';\nimport type { ControlBar } from './ControlBar.js';\nimport type { Player } from '../core/Player.js';\n\nfunction captionStylePropertyName(property: string): string {\n const stripped = property.replace('captions', '');\n return stripped.charAt(0).toLowerCase() + stripped.slice(1);\n}\n\nfunction createStyleControl(\n player: Player,\n label: string,\n property: string,\n options: Array<{ label: string; value: string }>\n): HTMLElement {\n const group = DOMUtils.createElement('div', {\n className: `${player.options.classPrefix}-style-group`\n });\n\n const controlId = `${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: `${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 = 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 as HTMLOptionElement).selected = true;\n }\n select.appendChild(option);\n });\n\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 player.options[property] = (e.target as HTMLSelectElement).value;\n if (player.captionManager) {\n player.captionManager.setCaptionStyle(\n captionStylePropertyName(property),\n (e.target as HTMLSelectElement).value\n );\n }\n });\n\n group.appendChild(select);\n return group;\n}\n\nfunction createColorControl(player: Player, label: string, property: string): HTMLElement {\n const group = DOMUtils.createElement('div', {\n className: `${player.options.classPrefix}-style-group`\n });\n\n const controlId = `${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: String(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 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 player.options[property] = (e.target as HTMLInputElement).value;\n if (player.captionManager) {\n player.captionManager.setCaptionStyle(\n captionStylePropertyName(property),\n (e.target as HTMLInputElement).value\n );\n }\n });\n\n group.appendChild(input);\n return group;\n}\n\nfunction createOpacityControl(player: Player, label: string, property: string): HTMLElement {\n const group = DOMUtils.createElement('div', {\n className: `${player.options.classPrefix}-style-group`\n });\n\n const controlId = `${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(Number(player.options[property] ?? 0) * 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(player.options[property])\n },\n style: {\n width: '100%',\n cursor: 'pointer'\n }\n });\n\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 as HTMLInputElement).value);\n valueEl.textContent = Math.round(value * 100) + '%';\n player.options[property] = value;\n if (player.captionManager) {\n player.captionManager.setCaptionStyle(\n captionStylePropertyName(property),\n value\n );\n }\n });\n\n group.appendChild(input);\n return group;\n}\n\n/**\n * Build and show the caption-style dialog for the given ControlBar. Mirrors\n * the toggle/positioning behavior of the other ControlBar menus by delegating\n * back to the ControlBar's shared DOM-insertion / positioning / close helpers.\n */\nexport function showCaptionStyleMenu(controlBar: ControlBar, button: HTMLElement): void {\n const player = controlBar.player;\n\n // Remove existing menu if any (toggle behavior)\n const existingMenu = document.querySelector(`.${player.options.classPrefix}-caption-style-menu`);\n if (existingMenu) {\n existingMenu.remove();\n button.setAttribute('aria-expanded', 'false');\n if (controlBar.openMenu === existingMenu) {\n controlBar.openMenu = null;\n controlBar.openMenuButton = null;\n }\n return;\n }\n\n // The caption-style panel contains form controls (selects, color\n // inputs, sliders), not single-action menuitems. Modeling it as a\n // dialog yields correct semantics for AT and matches the\n // SettingsDialog pattern.\n const menuLabelId = `${player.options.classPrefix}-caption-style-label-${player.instanceId || ''}`;\n const menu = DOMUtils.createElement('div', {\n className: `${player.options.classPrefix}-caption-style-menu ${player.options.classPrefix}-menu ${player.options.classPrefix}-settings-menu`,\n attributes: {\n 'role': 'dialog',\n 'aria-modal': 'false',\n 'aria-labelledby': menuLabelId\n }\n });\n const visuallyHiddenLabel = DOMUtils.createElement('h2', {\n textContent: i18n.t('player.captionStyling'),\n attributes: { id: menuLabelId, class: `${player.options.classPrefix}-sr-only` },\n style: {\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0,0,0,0)',\n whiteSpace: 'nowrap',\n border: '0'\n }\n });\n menu.appendChild(visuallyHiddenLabel);\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 (!player.captionManager || player.captionManager.tracks.length === 0) {\n // Show \"No captions available\" message\n const noTracksItem = DOMUtils.createElement('div', {\n className: `${player.options.classPrefix}-menu-item`,\n textContent: i18n.t('player.noCaptions'),\n attributes: {\n 'role': 'status'\n },\n style: { opacity: '0.5', cursor: 'default', padding: '12px 16px' }\n });\n menu.appendChild(noTracksItem);\n\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n\n controlBar.insertMenuIntoDOM(menu, button);\n controlBar.positionMenu(menu, button, true);\n\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n controlBar.attachMenuCloseHandler(menu, button, true);\n return;\n }\n\n // Font Size\n menu.appendChild(createStyleControl(\n player,\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\n // Font Family\n menu.appendChild(createStyleControl(\n player,\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\n // Text Color\n menu.appendChild(createColorControl(player, i18n.t('styleLabels.textColor'), 'captionsColor'));\n\n // Background Color\n menu.appendChild(createColorControl(player, i18n.t('styleLabels.background'), 'captionsBackgroundColor'));\n\n // Opacity\n menu.appendChild(createOpacityControl(player, i18n.t('styleLabels.opacity'), 'captionsOpacity'));\n\n // Set min-width for caption style menu\n menu.style.minWidth = '220px';\n\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n\n controlBar.insertMenuIntoDOM(menu, button);\n controlBar.positionMenu(menu, button, true);\n\n requestAnimationFrame(() => {\n menu.style.visibility = 'visible';\n });\n\n controlBar.attachMenuCloseHandler(menu, button, true);\n\n // Auto-focus the first style select element\n focusFirstElement(menu, `.${player.options.classPrefix}-style-select`);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,8 +1,11 @@
1
1
  /*!
2
- * VidPly v1.1.19 - Universal, Accessible Video Player
2
+ * VidPly v1.2.1 - Universal, Accessible Video Player
3
3
  * (c) 2026 Matthias Peltzer
4
4
  * Released under GPL-2.0-or-later License
5
5
  */
6
+ import {
7
+ loadScriptOnce
8
+ } from "./vidply.chunk-HOYEMJSD.js";
6
9
 
7
10
  // src/renderers/DASHRenderer.ts
8
11
  var DASHRenderer = class {
@@ -22,6 +25,11 @@ var DASHRenderer = class {
22
25
  _pendingTimeouts;
23
26
  _ttmlDiv;
24
27
  _manifestUrl;
28
+ // Detaches all media listeners (attachMediaEvents) in destroy().
29
+ _listenerController;
30
+ // Deferred 'ready' handler from updateCaptionButtonsForStreaming, removed on
31
+ // destroy if it never fired.
32
+ _pendingReadyHandler;
25
33
  constructor(player) {
26
34
  this.player = player;
27
35
  this.media = player.element;
@@ -38,6 +46,8 @@ var DASHRenderer = class {
38
46
  this._pendingTimeouts = [];
39
47
  this._ttmlDiv = null;
40
48
  this._manifestUrl = null;
49
+ this._listenerController = new AbortController();
50
+ this._pendingReadyHandler = null;
41
51
  }
42
52
  async init() {
43
53
  this.player.log("Using dash.js for DASH support");
@@ -52,7 +62,7 @@ var DASHRenderer = class {
52
62
  const sourceElements = Array.from(this.media.querySelectorAll("source"));
53
63
  let originalSrc = null;
54
64
  if (sourceElements.length > 0) {
55
- originalSrc = sourceElements[0].getAttribute("src");
65
+ originalSrc = sourceElements[0]?.getAttribute("src") ?? null;
56
66
  sourceElements.forEach((source) => source.remove());
57
67
  this.player.log("Removed <source> elements for HTML5 validity (dash.js uses MSE)");
58
68
  }
@@ -167,18 +177,7 @@ var DASHRenderer = class {
167
177
  const defaultUrl = "https://cdn.jsdelivr.net/npm/dashjs@5.2.0/dist/modern/umd/dash.all.min.js";
168
178
  const url = this.player.options.dashScriptUrl || defaultUrl;
169
179
  const integrity = this.player.options.dashScriptIntegrity;
170
- return new Promise((resolve, reject) => {
171
- const script = document.createElement("script");
172
- script.src = url;
173
- if (integrity) {
174
- script.integrity = integrity;
175
- script.crossOrigin = "anonymous";
176
- script.referrerPolicy = "no-referrer";
177
- }
178
- script.onload = () => resolve();
179
- script.onerror = () => reject(new Error("Failed to load dash.js"));
180
- document.head.appendChild(script);
181
- });
180
+ return loadScriptOnce(url, { integrity });
182
181
  }
183
182
  _setTimeout(fn, delay) {
184
183
  const id = setTimeout(() => {
@@ -269,7 +268,7 @@ var DASHRenderer = class {
269
268
  if (!textTracks) return total;
270
269
  for (let i = 0; i < textTracks.length; i++) {
271
270
  const track = textTracks[i];
272
- if ((track.kind === "subtitles" || track.kind === "captions") && !track._vidplyStale && track.cues) {
271
+ if (track && (track.kind === "subtitles" || track.kind === "captions") && !track._vidplyStale && track.cues) {
273
272
  total += track.cues.length;
274
273
  }
275
274
  }
@@ -386,7 +385,7 @@ var DASHRenderer = class {
386
385
  let count = 0;
387
386
  for (let i = 0; i < tracks.length; i++) {
388
387
  const track = tracks[i];
389
- if ((track.kind === "subtitles" || track.kind === "captions") && !track._vidplyStale) {
388
+ if (track && (track.kind === "subtitles" || track.kind === "captions") && !track._vidplyStale) {
390
389
  count++;
391
390
  }
392
391
  }
@@ -438,22 +437,25 @@ var DASHRenderer = class {
438
437
  }
439
438
  const onReady = () => {
440
439
  this.player.off("ready", onReady);
440
+ this._pendingReadyHandler = null;
441
441
  doUpdate();
442
442
  };
443
+ this._pendingReadyHandler = onReady;
443
444
  this.player.on("ready", onReady);
444
445
  }
445
446
  attachMediaEvents() {
447
+ const { signal } = this._listenerController;
446
448
  this.media.addEventListener("loadedmetadata", () => {
447
449
  this.player.state.duration = this.media.duration;
448
450
  this.player.emit("loadedmetadata");
449
- });
451
+ }, { signal });
450
452
  this.media.addEventListener("durationchange", () => {
451
453
  const duration = this.media.duration;
452
454
  if (duration && isFinite(duration) && duration > 0) {
453
455
  this.player.state.duration = duration;
454
456
  this.player.emit("durationchange", duration);
455
457
  }
456
- });
458
+ }, { signal });
457
459
  this.media.addEventListener("play", () => {
458
460
  this.player.state.playing = true;
459
461
  this.player.state.paused = false;
@@ -462,7 +464,7 @@ var DASHRenderer = class {
462
464
  if (this.player.options.onPlay) {
463
465
  this.player.options.onPlay.call(this.player);
464
466
  }
465
- });
467
+ }, { signal });
466
468
  this.media.addEventListener("pause", () => {
467
469
  this.player.state.playing = false;
468
470
  this.player.state.paused = true;
@@ -470,7 +472,7 @@ var DASHRenderer = class {
470
472
  if (this.player.options.onPause) {
471
473
  this.player.options.onPause.call(this.player);
472
474
  }
473
- });
475
+ }, { signal });
474
476
  this.media.addEventListener("ended", () => {
475
477
  this.player.state.playing = false;
476
478
  this.player.state.paused = true;
@@ -483,19 +485,19 @@ var DASHRenderer = class {
483
485
  this.player.seek(0);
484
486
  this.player.play();
485
487
  }
486
- });
488
+ }, { signal });
487
489
  this.media.addEventListener("timeupdate", () => {
488
490
  this.player.state.currentTime = this.media.currentTime;
489
491
  this.player.emit("timeupdate", this.media.currentTime);
490
492
  if (this.player.options.onTimeUpdate) {
491
493
  this.player.options.onTimeUpdate.call(this.player, this.media.currentTime);
492
494
  }
493
- });
495
+ }, { signal });
494
496
  this.media.addEventListener("volumechange", () => {
495
497
  this.player.state.volume = this.media.volume;
496
498
  this.player.state.muted = this.media.muted;
497
499
  this.player.emit("volumechange", this.media.volume);
498
- });
500
+ }, { signal });
499
501
  this.media.addEventListener("seeking", () => {
500
502
  this.player.state.seeking = true;
501
503
  this.player.emit("seeking");
@@ -503,22 +505,22 @@ var DASHRenderer = class {
503
505
  this.player.state.buffering = true;
504
506
  this.player.emit("waiting");
505
507
  }
506
- });
508
+ }, { signal });
507
509
  this.media.addEventListener("seeked", () => {
508
510
  this.player.state.seeking = false;
509
511
  this.player.emit("seeked");
510
- });
512
+ }, { signal });
511
513
  this.media.addEventListener("waiting", () => {
512
514
  this.player.state.buffering = true;
513
515
  this.player.emit("waiting");
514
- });
516
+ }, { signal });
515
517
  this.media.addEventListener("canplay", () => {
516
518
  this.player.state.buffering = false;
517
519
  this.player.emit("canplay");
518
- });
520
+ }, { signal });
519
521
  this.media.addEventListener("error", () => {
520
522
  this.player.handleError(this.media.error);
521
- });
523
+ }, { signal });
522
524
  }
523
525
  handleDashError(e) {
524
526
  const wrapped = e;
@@ -633,7 +635,7 @@ var DASHRenderer = class {
633
635
  const bitrate = Number(rep.bandwidth || rep.bitrate) || 0;
634
636
  const kb = bitrate > 0 ? Math.round(bitrate / 1e3) : 0;
635
637
  let name;
636
- if (height > 0 && heightCounts2[height] > 1 && kb > 0) {
638
+ if (height > 0 && (heightCounts2[height] ?? 0) > 1 && kb > 0) {
637
639
  name = `${height}p (${kb} kbps)`;
638
640
  } else if (height > 0) {
639
641
  name = `${height}p`;
@@ -662,7 +664,7 @@ var DASHRenderer = class {
662
664
  const bitrate = Number(info.bitrate) || 0;
663
665
  const kb = bitrate > 0 ? Math.round(bitrate / 1e3) : 0;
664
666
  let name;
665
- if (height > 0 && heightCounts[height] > 1 && kb > 0) {
667
+ if (height > 0 && (heightCounts[height] ?? 0) > 1 && kb > 0) {
666
668
  name = `${height}p (${kb} kbps)`;
667
669
  } else if (height > 0) {
668
670
  name = `${height}p`;
@@ -815,6 +817,11 @@ var DASHRenderer = class {
815
817
  this._pendingTimeouts = [];
816
818
  this._stopCueUpdatePolling();
817
819
  this._lastKnownCueCount = 0;
820
+ this._listenerController.abort();
821
+ if (this._pendingReadyHandler) {
822
+ this.player.off("ready", this._pendingReadyHandler);
823
+ this._pendingReadyHandler = null;
824
+ }
818
825
  if (this._captionEnabledHandler) {
819
826
  this.player.off("captionsenabled", this._captionEnabledHandler);
820
827
  this._captionEnabledHandler = null;
@@ -830,7 +837,7 @@ var DASHRenderer = class {
830
837
  const textTracks = this.media.textTracks;
831
838
  for (let i = 0; i < textTracks.length; i++) {
832
839
  const track = textTracks[i];
833
- if (track.kind === "subtitles" || track.kind === "captions") {
840
+ if (track && (track.kind === "subtitles" || track.kind === "captions")) {
834
841
  track._vidplyStale = true;
835
842
  track.mode = "disabled";
836
843
  }
@@ -855,4 +862,4 @@ var DASHRenderer = class {
855
862
  export {
856
863
  DASHRenderer
857
864
  };
858
- //# sourceMappingURL=vidply.DASHRenderer-SYXX6RRS.js.map
865
+ //# sourceMappingURL=vidply.DASHRenderer-EOVEW73H.js.map