vidply 1.0.28 → 1.0.29
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.
- package/dist/dev/{vidply.TranscriptManager-QSF2PWUN.js → vidply.TranscriptManager-T677KF4N.js} +4 -5
- package/dist/dev/{vidply.TranscriptManager-QSF2PWUN.js.map → vidply.TranscriptManager-T677KF4N.js.map} +2 -2
- package/dist/dev/{vidply.chunk-SRM7VNHG.js → vidply.chunk-GS2JX5RQ.js} +136 -95
- package/dist/dev/vidply.chunk-GS2JX5RQ.js.map +7 -0
- package/dist/dev/vidply.esm.js +1674 -310
- package/dist/dev/vidply.esm.js.map +4 -4
- package/dist/legacy/vidply.js +1776 -348
- package/dist/legacy/vidply.js.map +4 -4
- package/dist/legacy/vidply.min.js +1 -1
- package/dist/legacy/vidply.min.meta.json +92 -24
- package/dist/prod/vidply.TranscriptManager-WFZSW6NR.min.js +6 -0
- package/dist/prod/vidply.chunk-LGTJRPUL.min.js +6 -0
- package/dist/prod/vidply.esm.min.js +8 -8
- package/dist/vidply.esm.min.meta.json +92 -24
- package/package.json +1 -1
- package/src/controls/ControlBar.js +3 -7
- package/src/controls/TranscriptManager.js +7 -7
- package/src/core/AudioDescriptionManager.js +701 -0
- package/src/core/Player.js +4776 -4921
- package/src/core/SignLanguageManager.js +1134 -0
- package/src/utils/DOMUtils.js +153 -114
- package/src/utils/MenuFactory.js +374 -0
- package/dist/dev/vidply.TranscriptManager-GZKY44ON.js +0 -1744
- package/dist/dev/vidply.TranscriptManager-GZKY44ON.js.map +0 -7
- package/dist/dev/vidply.TranscriptManager-UTJBQC5B.js +0 -1744
- package/dist/dev/vidply.TranscriptManager-UTJBQC5B.js.map +0 -7
- package/dist/dev/vidply.chunk-5663PYKK.js +0 -1631
- package/dist/dev/vidply.chunk-5663PYKK.js.map +0 -7
- package/dist/dev/vidply.chunk-SRM7VNHG.js.map +0 -7
- package/dist/dev/vidply.chunk-UH5MTGKF.js +0 -1630
- package/dist/dev/vidply.chunk-UH5MTGKF.js.map +0 -7
- package/dist/dev/vidply.de-RXAJM5QE.js +0 -181
- package/dist/dev/vidply.de-RXAJM5QE.js.map +0 -7
- package/dist/dev/vidply.de-THBIMP4S.js +0 -180
- package/dist/dev/vidply.de-THBIMP4S.js.map +0 -7
- package/dist/dev/vidply.es-6VWDNNNL.js +0 -180
- package/dist/dev/vidply.es-6VWDNNNL.js.map +0 -7
- package/dist/dev/vidply.es-SADVLJTQ.js +0 -181
- package/dist/dev/vidply.es-SADVLJTQ.js.map +0 -7
- package/dist/dev/vidply.fr-V3VAYBBT.js +0 -181
- package/dist/dev/vidply.fr-V3VAYBBT.js.map +0 -7
- package/dist/dev/vidply.fr-WHTWCHWT.js +0 -180
- package/dist/dev/vidply.fr-WHTWCHWT.js.map +0 -7
- package/dist/dev/vidply.ja-BFQNPOFI.js +0 -180
- package/dist/dev/vidply.ja-BFQNPOFI.js.map +0 -7
- package/dist/dev/vidply.ja-KL2TLZGJ.js +0 -181
- package/dist/dev/vidply.ja-KL2TLZGJ.js.map +0 -7
- package/dist/prod/vidply.TranscriptManager-DZ2WZU3K.min.js +0 -6
- package/dist/prod/vidply.TranscriptManager-E5QHGFIR.min.js +0 -6
- package/dist/prod/vidply.TranscriptManager-UZ6DUFB6.min.js +0 -6
- package/dist/prod/vidply.chunk-5DWTMWEO.min.js +0 -6
- package/dist/prod/vidply.chunk-IBNYTGGM.min.js +0 -6
- package/dist/prod/vidply.chunk-MBUR3U5L.min.js +0 -6
- package/dist/prod/vidply.de-HGJBCLLE.min.js +0 -6
- package/dist/prod/vidply.de-SWFW4HYT.min.js +0 -6
- package/dist/prod/vidply.es-7BJ2DJAY.min.js +0 -6
- package/dist/prod/vidply.es-CZEBXCZN.min.js +0 -6
- package/dist/prod/vidply.fr-DPVR5DFY.min.js +0 -6
- package/dist/prod/vidply.fr-HFOL7MWA.min.js +0 -6
- package/dist/prod/vidply.ja-PEBVWKVH.min.js +0 -6
- package/dist/prod/vidply.ja-QTVU5C25.min.js +0 -6
package/dist/legacy/vidply.js
CHANGED
|
@@ -34,15 +34,21 @@
|
|
|
34
34
|
var init_DOMUtils = __esm({
|
|
35
35
|
"src/utils/DOMUtils.js"() {
|
|
36
36
|
DOMUtils = {
|
|
37
|
+
/**
|
|
38
|
+
* Create an element with options
|
|
39
|
+
* @param {string} tag - HTML tag name
|
|
40
|
+
* @param {Object} options - Element options
|
|
41
|
+
* @returns {HTMLElement}
|
|
42
|
+
*/
|
|
37
43
|
createElement(tag, options = {}) {
|
|
38
44
|
const element = document.createElement(tag);
|
|
39
45
|
if (options.className) {
|
|
40
46
|
element.className = options.className;
|
|
41
47
|
}
|
|
42
48
|
if (options.attributes) {
|
|
43
|
-
Object.entries(options.attributes)
|
|
49
|
+
for (const [key, value] of Object.entries(options.attributes)) {
|
|
44
50
|
element.setAttribute(key, value);
|
|
45
|
-
}
|
|
51
|
+
}
|
|
46
52
|
}
|
|
47
53
|
if (options.innerHTML) {
|
|
48
54
|
element.innerHTML = options.innerHTML;
|
|
@@ -54,150 +60,190 @@
|
|
|
54
60
|
Object.assign(element.style, options.style);
|
|
55
61
|
}
|
|
56
62
|
if (options.children) {
|
|
57
|
-
options.children
|
|
63
|
+
for (const child of options.children) {
|
|
58
64
|
if (child) element.appendChild(child);
|
|
59
|
-
}
|
|
65
|
+
}
|
|
60
66
|
}
|
|
61
67
|
return element;
|
|
62
68
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
},
|
|
68
|
-
removeClass(element, className) {
|
|
69
|
-
if (element && className) {
|
|
70
|
-
element.classList.remove(className);
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
toggleClass(element, className) {
|
|
74
|
-
if (element && className) {
|
|
75
|
-
element.classList.toggle(className);
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
hasClass(element, className) {
|
|
79
|
-
return element && element.classList.contains(className);
|
|
80
|
-
},
|
|
69
|
+
/**
|
|
70
|
+
* Show element (remove display:none)
|
|
71
|
+
* @param {HTMLElement} element
|
|
72
|
+
*/
|
|
81
73
|
show(element) {
|
|
82
|
-
|
|
83
|
-
element.style.display = "";
|
|
84
|
-
}
|
|
74
|
+
(element == null ? void 0 : element.style) && (element.style.display = "");
|
|
85
75
|
},
|
|
76
|
+
/**
|
|
77
|
+
* Hide element
|
|
78
|
+
* @param {HTMLElement} element
|
|
79
|
+
*/
|
|
86
80
|
hide(element) {
|
|
87
|
-
|
|
88
|
-
element.style.display = "none";
|
|
89
|
-
}
|
|
81
|
+
(element == null ? void 0 : element.style) && (element.style.display = "none");
|
|
90
82
|
},
|
|
91
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Fade in element using CSS transitions (GPU accelerated)
|
|
85
|
+
* @param {HTMLElement} element
|
|
86
|
+
* @param {number} duration - Duration in ms
|
|
87
|
+
* @param {Function} [onComplete] - Callback when complete
|
|
88
|
+
*/
|
|
89
|
+
fadeIn(element, duration = 300, onComplete) {
|
|
92
90
|
if (!element) return;
|
|
93
91
|
element.style.opacity = "0";
|
|
94
92
|
element.style.display = "";
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
93
|
+
element.style.transition = "opacity ".concat(duration, "ms ease");
|
|
94
|
+
element.offsetHeight;
|
|
95
|
+
element.style.opacity = "1";
|
|
96
|
+
if (onComplete) {
|
|
97
|
+
const cleanup = () => {
|
|
98
|
+
element.removeEventListener("transitionend", cleanup);
|
|
99
|
+
onComplete();
|
|
100
|
+
};
|
|
101
|
+
element.addEventListener("transitionend", cleanup, { once: true });
|
|
102
|
+
setTimeout(cleanup, duration + 50);
|
|
103
|
+
}
|
|
106
104
|
},
|
|
107
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Fade out element using CSS transitions (GPU accelerated)
|
|
107
|
+
* @param {HTMLElement} element
|
|
108
|
+
* @param {number} duration - Duration in ms
|
|
109
|
+
* @param {Function} [onComplete] - Callback when complete
|
|
110
|
+
*/
|
|
111
|
+
fadeOut(element, duration = 300, onComplete) {
|
|
108
112
|
if (!element) return;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
element.style.opacity = opacity;
|
|
116
|
-
if (progress < duration) {
|
|
117
|
-
requestAnimationFrame(animate);
|
|
118
|
-
} else {
|
|
119
|
-
element.style.display = "none";
|
|
120
|
-
}
|
|
113
|
+
element.style.transition = "opacity ".concat(duration, "ms ease");
|
|
114
|
+
element.style.opacity = "0";
|
|
115
|
+
const cleanup = () => {
|
|
116
|
+
element.removeEventListener("transitionend", cleanup);
|
|
117
|
+
element.style.display = "none";
|
|
118
|
+
if (onComplete) onComplete();
|
|
121
119
|
};
|
|
122
|
-
|
|
120
|
+
element.addEventListener("transitionend", cleanup, { once: true });
|
|
121
|
+
setTimeout(cleanup, duration + 50);
|
|
123
122
|
},
|
|
123
|
+
/**
|
|
124
|
+
* Get element's offset position and dimensions
|
|
125
|
+
* @param {HTMLElement} element
|
|
126
|
+
* @returns {Object} { top, left, width, height }
|
|
127
|
+
*/
|
|
124
128
|
offset(element) {
|
|
125
|
-
if (!element) return { top: 0, left: 0 };
|
|
129
|
+
if (!element) return { top: 0, left: 0, width: 0, height: 0 };
|
|
126
130
|
const rect = element.getBoundingClientRect();
|
|
127
131
|
return {
|
|
128
|
-
top: rect.top + window.
|
|
129
|
-
left: rect.left + window.
|
|
132
|
+
top: rect.top + window.scrollY,
|
|
133
|
+
left: rect.left + window.scrollX,
|
|
130
134
|
width: rect.width,
|
|
131
135
|
height: rect.height
|
|
132
136
|
};
|
|
133
137
|
},
|
|
138
|
+
/**
|
|
139
|
+
* Escape HTML special characters
|
|
140
|
+
* @param {string} str - String to escape
|
|
141
|
+
* @returns {string} Escaped string
|
|
142
|
+
*/
|
|
134
143
|
escapeHTML(str) {
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
144
|
+
const escapeMap = {
|
|
145
|
+
"&": "&",
|
|
146
|
+
"<": "<",
|
|
147
|
+
">": ">",
|
|
148
|
+
'"': """,
|
|
149
|
+
"'": "'"
|
|
150
|
+
};
|
|
151
|
+
return str.replace(/[&<>"']/g, (char) => escapeMap[char]);
|
|
138
152
|
},
|
|
153
|
+
/**
|
|
154
|
+
* Basic HTML sanitization for VTT captions
|
|
155
|
+
* Allows safe formatting tags, removes dangerous content
|
|
156
|
+
* @param {string} html - HTML string to sanitize
|
|
157
|
+
* @returns {string} Sanitized HTML
|
|
158
|
+
*/
|
|
139
159
|
sanitizeHTML(html) {
|
|
140
|
-
const temp = document.createElement("div");
|
|
141
160
|
const safeHtml = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, "").replace(/on\w+\s*=/gi, "").replace(/javascript:/gi, "");
|
|
161
|
+
const temp = document.createElement("div");
|
|
142
162
|
temp.innerHTML = safeHtml;
|
|
143
163
|
return temp.innerHTML;
|
|
144
164
|
},
|
|
145
165
|
/**
|
|
146
|
-
* Create a tooltip element
|
|
166
|
+
* Create a tooltip element (aria-hidden)
|
|
147
167
|
* @param {string} text - Tooltip text
|
|
148
|
-
* @param {string} classPrefix - Class prefix
|
|
149
|
-
* @returns {HTMLElement}
|
|
168
|
+
* @param {string} classPrefix - Class prefix
|
|
169
|
+
* @returns {HTMLElement}
|
|
150
170
|
*/
|
|
151
171
|
createTooltip(text, classPrefix = "vidply") {
|
|
152
|
-
|
|
172
|
+
return this.createElement("span", {
|
|
153
173
|
className: "".concat(classPrefix, "-tooltip"),
|
|
154
174
|
textContent: text,
|
|
155
|
-
attributes: {
|
|
156
|
-
"aria-hidden": "true"
|
|
157
|
-
}
|
|
175
|
+
attributes: { "aria-hidden": "true" }
|
|
158
176
|
});
|
|
159
|
-
return tooltip;
|
|
160
177
|
},
|
|
161
178
|
/**
|
|
162
|
-
* Attach a tooltip to an element
|
|
163
|
-
* @param {HTMLElement} element -
|
|
179
|
+
* Attach a tooltip to an element with hover/focus behavior
|
|
180
|
+
* @param {HTMLElement} element - Target element
|
|
164
181
|
* @param {string} text - Tooltip text
|
|
165
|
-
* @param {string} classPrefix - Class prefix
|
|
182
|
+
* @param {string} classPrefix - Class prefix
|
|
166
183
|
*/
|
|
167
184
|
attachTooltip(element, text, classPrefix = "vidply") {
|
|
185
|
+
var _a;
|
|
168
186
|
if (!element || !text) return;
|
|
169
|
-
|
|
170
|
-
if (existingTooltip) {
|
|
171
|
-
existingTooltip.remove();
|
|
172
|
-
}
|
|
187
|
+
(_a = element.querySelector(".".concat(classPrefix, "-tooltip"))) == null ? void 0 : _a.remove();
|
|
173
188
|
const tooltip = this.createTooltip(text, classPrefix);
|
|
174
189
|
element.appendChild(tooltip);
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
element.addEventListener("
|
|
182
|
-
element.addEventListener("mouseleave", hideTooltip);
|
|
183
|
-
element.addEventListener("focus", showTooltip);
|
|
184
|
-
element.addEventListener("blur", hideTooltip);
|
|
190
|
+
const visibleClass = "".concat(classPrefix, "-tooltip-visible");
|
|
191
|
+
const show = () => tooltip.classList.add(visibleClass);
|
|
192
|
+
const hide = () => tooltip.classList.remove(visibleClass);
|
|
193
|
+
element.addEventListener("mouseenter", show);
|
|
194
|
+
element.addEventListener("mouseleave", hide);
|
|
195
|
+
element.addEventListener("focus", show);
|
|
196
|
+
element.addEventListener("blur", hide);
|
|
185
197
|
},
|
|
186
198
|
/**
|
|
187
|
-
* Create
|
|
199
|
+
* Create button text element (visible when CSS disabled)
|
|
188
200
|
* @param {string} text - Button text
|
|
189
|
-
* @param {string} classPrefix - Class prefix
|
|
190
|
-
* @returns {HTMLElement}
|
|
201
|
+
* @param {string} classPrefix - Class prefix
|
|
202
|
+
* @returns {HTMLElement}
|
|
191
203
|
*/
|
|
192
204
|
createButtonText(text, classPrefix = "vidply") {
|
|
193
|
-
|
|
205
|
+
return this.createElement("span", {
|
|
194
206
|
className: "".concat(classPrefix, "-button-text"),
|
|
195
207
|
textContent: text,
|
|
196
|
-
attributes: {
|
|
197
|
-
"aria-hidden": "true"
|
|
198
|
-
}
|
|
208
|
+
attributes: { "aria-hidden": "true" }
|
|
199
209
|
});
|
|
200
|
-
|
|
210
|
+
},
|
|
211
|
+
/**
|
|
212
|
+
* Add class to element (null-safe)
|
|
213
|
+
* @param {HTMLElement} element
|
|
214
|
+
* @param {string} className
|
|
215
|
+
*/
|
|
216
|
+
addClass(element, className) {
|
|
217
|
+
var _a;
|
|
218
|
+
(_a = element == null ? void 0 : element.classList) == null ? void 0 : _a.add(className);
|
|
219
|
+
},
|
|
220
|
+
/**
|
|
221
|
+
* Remove class from element (null-safe)
|
|
222
|
+
* @param {HTMLElement} element
|
|
223
|
+
* @param {string} className
|
|
224
|
+
*/
|
|
225
|
+
removeClass(element, className) {
|
|
226
|
+
var _a;
|
|
227
|
+
(_a = element == null ? void 0 : element.classList) == null ? void 0 : _a.remove(className);
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* Toggle class on element (null-safe)
|
|
231
|
+
* @param {HTMLElement} element
|
|
232
|
+
* @param {string} className
|
|
233
|
+
*/
|
|
234
|
+
toggleClass(element, className) {
|
|
235
|
+
var _a;
|
|
236
|
+
(_a = element == null ? void 0 : element.classList) == null ? void 0 : _a.toggle(className);
|
|
237
|
+
},
|
|
238
|
+
/**
|
|
239
|
+
* Check if element has class (null-safe)
|
|
240
|
+
* @param {HTMLElement} element
|
|
241
|
+
* @param {string} className
|
|
242
|
+
* @returns {boolean}
|
|
243
|
+
*/
|
|
244
|
+
hasClass(element, className) {
|
|
245
|
+
var _a, _b;
|
|
246
|
+
return (_b = (_a = element == null ? void 0 : element.classList) == null ? void 0 : _a.contains(className)) != null ? _b : false;
|
|
201
247
|
}
|
|
202
248
|
};
|
|
203
249
|
}
|
|
@@ -3268,8 +3314,7 @@
|
|
|
3268
3314
|
descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
3269
3315
|
}
|
|
3270
3316
|
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3271
|
-
|
|
3272
|
-
if (!captionTrack && !hasDescriptionTrack && !metadataTrack) {
|
|
3317
|
+
if (!captionTrack && !descriptionTrack && !metadataTrack) {
|
|
3273
3318
|
this.showNoTranscriptMessage();
|
|
3274
3319
|
return;
|
|
3275
3320
|
}
|
|
@@ -3307,7 +3352,7 @@
|
|
|
3307
3352
|
allCues.push({ cue, type: "caption" });
|
|
3308
3353
|
});
|
|
3309
3354
|
}
|
|
3310
|
-
if (descriptionTrack && descriptionTrack.cues
|
|
3355
|
+
if (descriptionTrack && descriptionTrack.cues) {
|
|
3311
3356
|
Array.from(descriptionTrack.cues).forEach((cue) => {
|
|
3312
3357
|
allCues.push({ cue, type: "description" });
|
|
3313
3358
|
});
|
|
@@ -5501,6 +5546,35 @@
|
|
|
5501
5546
|
init_Icons();
|
|
5502
5547
|
init_i18n();
|
|
5503
5548
|
init_FocusUtils();
|
|
5549
|
+
|
|
5550
|
+
// src/utils/PerformanceUtils.js
|
|
5551
|
+
function debounce(func, wait = 100) {
|
|
5552
|
+
let timeout;
|
|
5553
|
+
return function executedFunction(...args) {
|
|
5554
|
+
const later = () => {
|
|
5555
|
+
clearTimeout(timeout);
|
|
5556
|
+
func(...args);
|
|
5557
|
+
};
|
|
5558
|
+
clearTimeout(timeout);
|
|
5559
|
+
timeout = setTimeout(later, wait);
|
|
5560
|
+
};
|
|
5561
|
+
}
|
|
5562
|
+
function isMobile(breakpoint = 768) {
|
|
5563
|
+
return window.innerWidth < breakpoint;
|
|
5564
|
+
}
|
|
5565
|
+
function rafWithTimeout(callback, timeout = 100) {
|
|
5566
|
+
let called = false;
|
|
5567
|
+
const execute = () => {
|
|
5568
|
+
if (!called) {
|
|
5569
|
+
called = true;
|
|
5570
|
+
callback();
|
|
5571
|
+
}
|
|
5572
|
+
};
|
|
5573
|
+
requestAnimationFrame(execute);
|
|
5574
|
+
setTimeout(execute, timeout);
|
|
5575
|
+
}
|
|
5576
|
+
|
|
5577
|
+
// src/controls/ControlBar.js
|
|
5504
5578
|
var ControlBar = class {
|
|
5505
5579
|
constructor(player) {
|
|
5506
5580
|
this.player = player;
|
|
@@ -5520,17 +5594,13 @@
|
|
|
5520
5594
|
this.setupAutoHide();
|
|
5521
5595
|
this.setupOverflowDetection();
|
|
5522
5596
|
}
|
|
5523
|
-
// Helper method to check if we're on a mobile device
|
|
5524
|
-
isMobile() {
|
|
5525
|
-
return window.innerWidth < 768;
|
|
5526
|
-
}
|
|
5527
5597
|
// Helper method to detect touch devices
|
|
5528
5598
|
isTouchDevice() {
|
|
5529
5599
|
return "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
|
|
5530
5600
|
}
|
|
5531
5601
|
// Smart menu positioning to avoid overflow
|
|
5532
5602
|
positionMenu(menu, button, immediate = false) {
|
|
5533
|
-
const
|
|
5603
|
+
const mobile = isMobile();
|
|
5534
5604
|
const isOverflowMenu = menu.classList.contains("".concat(this.player.options.classPrefix, "-overflow-menu-list"));
|
|
5535
5605
|
const isFullscreen = this.player.state.fullscreen;
|
|
5536
5606
|
if (isFullscreen && menu.parentElement === this.player.container) {
|
|
@@ -5571,7 +5641,7 @@
|
|
|
5571
5641
|
}
|
|
5572
5642
|
return;
|
|
5573
5643
|
}
|
|
5574
|
-
if (
|
|
5644
|
+
if (mobile) {
|
|
5575
5645
|
const isVolumeMenu = menu.classList.contains("".concat(this.player.options.classPrefix, "-volume-menu"));
|
|
5576
5646
|
const doMobilePositioning = () => {
|
|
5577
5647
|
const parentContainer = button.parentElement;
|
|
@@ -7944,35 +8014,6 @@
|
|
|
7944
8014
|
init_DOMUtils();
|
|
7945
8015
|
init_i18n();
|
|
7946
8016
|
init_StorageManager();
|
|
7947
|
-
|
|
7948
|
-
// src/utils/PerformanceUtils.js
|
|
7949
|
-
function debounce(func, wait = 100) {
|
|
7950
|
-
let timeout;
|
|
7951
|
-
return function executedFunction(...args) {
|
|
7952
|
-
const later = () => {
|
|
7953
|
-
clearTimeout(timeout);
|
|
7954
|
-
func(...args);
|
|
7955
|
-
};
|
|
7956
|
-
clearTimeout(timeout);
|
|
7957
|
-
timeout = setTimeout(later, wait);
|
|
7958
|
-
};
|
|
7959
|
-
}
|
|
7960
|
-
function isMobile(breakpoint = 768) {
|
|
7961
|
-
return window.innerWidth < breakpoint;
|
|
7962
|
-
}
|
|
7963
|
-
function rafWithTimeout(callback, timeout = 100) {
|
|
7964
|
-
let called = false;
|
|
7965
|
-
const execute = () => {
|
|
7966
|
-
if (!called) {
|
|
7967
|
-
called = true;
|
|
7968
|
-
callback();
|
|
7969
|
-
}
|
|
7970
|
-
};
|
|
7971
|
-
requestAnimationFrame(execute);
|
|
7972
|
-
setTimeout(execute, timeout);
|
|
7973
|
-
}
|
|
7974
|
-
|
|
7975
|
-
// src/controls/CaptionManager.js
|
|
7976
8017
|
var CaptionManager = class {
|
|
7977
8018
|
constructor(player) {
|
|
7978
8019
|
this.player = player;
|
|
@@ -8504,37 +8545,1511 @@
|
|
|
8504
8545
|
init_DraggableResizable();
|
|
8505
8546
|
init_MenuUtils();
|
|
8506
8547
|
init_FormUtils();
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
this.
|
|
8512
|
-
|
|
8513
|
-
|
|
8548
|
+
|
|
8549
|
+
// src/core/AudioDescriptionManager.js
|
|
8550
|
+
var AudioDescriptionManager = class {
|
|
8551
|
+
constructor(player) {
|
|
8552
|
+
this.player = player;
|
|
8553
|
+
this.enabled = false;
|
|
8554
|
+
this.desiredState = false;
|
|
8555
|
+
this.src = player.options.audioDescriptionSrc;
|
|
8556
|
+
this.sourceElement = null;
|
|
8557
|
+
this.originalSource = null;
|
|
8558
|
+
this.captionTracks = [];
|
|
8559
|
+
}
|
|
8560
|
+
/**
|
|
8561
|
+
* Initialize audio description from source elements
|
|
8562
|
+
* Called during player initialization
|
|
8563
|
+
*/
|
|
8564
|
+
initFromSourceElements(sourceElements, trackElements) {
|
|
8565
|
+
for (const sourceEl of sourceElements) {
|
|
8566
|
+
const descSrc = sourceEl.getAttribute("data-desc-src");
|
|
8567
|
+
const origSrc = sourceEl.getAttribute("data-orig-src");
|
|
8568
|
+
if (descSrc || origSrc) {
|
|
8569
|
+
if (!this.sourceElement) {
|
|
8570
|
+
this.sourceElement = sourceEl;
|
|
8571
|
+
}
|
|
8572
|
+
if (origSrc) {
|
|
8573
|
+
if (!this.originalSource) {
|
|
8574
|
+
this.originalSource = origSrc;
|
|
8575
|
+
}
|
|
8576
|
+
if (!this.player.originalSrc) {
|
|
8577
|
+
this.player.originalSrc = origSrc;
|
|
8578
|
+
}
|
|
8579
|
+
} else {
|
|
8580
|
+
const currentSrcAttr = sourceEl.getAttribute("src");
|
|
8581
|
+
if (!this.originalSource && currentSrcAttr) {
|
|
8582
|
+
this.originalSource = currentSrcAttr;
|
|
8583
|
+
}
|
|
8584
|
+
if (!this.player.originalSrc && currentSrcAttr) {
|
|
8585
|
+
this.player.originalSrc = currentSrcAttr;
|
|
8586
|
+
}
|
|
8587
|
+
}
|
|
8588
|
+
if (descSrc && !this.src) {
|
|
8589
|
+
this.src = descSrc;
|
|
8590
|
+
}
|
|
8591
|
+
}
|
|
8514
8592
|
}
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8593
|
+
trackElements.forEach((trackEl) => {
|
|
8594
|
+
const trackKind = trackEl.getAttribute("kind");
|
|
8595
|
+
const trackDescSrc = trackEl.getAttribute("data-desc-src");
|
|
8596
|
+
if ((trackKind === "captions" || trackKind === "subtitles" || trackKind === "chapters" || trackKind === "descriptions") && trackDescSrc) {
|
|
8597
|
+
this.captionTracks.push({
|
|
8598
|
+
trackElement: trackEl,
|
|
8599
|
+
originalSrc: trackEl.getAttribute("src"),
|
|
8600
|
+
describedSrc: trackDescSrc,
|
|
8601
|
+
originalTrackSrc: trackEl.getAttribute("data-orig-src") || trackEl.getAttribute("src"),
|
|
8602
|
+
explicit: true
|
|
8603
|
+
});
|
|
8604
|
+
this.player.log("Found explicit described ".concat(trackKind, " track: ").concat(trackEl.getAttribute("src"), " -> ").concat(trackDescSrc));
|
|
8605
|
+
}
|
|
8606
|
+
});
|
|
8607
|
+
}
|
|
8608
|
+
/**
|
|
8609
|
+
* Check if audio description is available
|
|
8610
|
+
*/
|
|
8611
|
+
isAvailable() {
|
|
8612
|
+
const hasSourceElementsWithDesc = this.player.sourceElements.some(
|
|
8613
|
+
(el) => el.getAttribute("data-desc-src")
|
|
8614
|
+
);
|
|
8615
|
+
return !!(this.src || hasSourceElementsWithDesc || this.captionTracks.length > 0);
|
|
8616
|
+
}
|
|
8617
|
+
/**
|
|
8618
|
+
* Enable audio description
|
|
8619
|
+
*/
|
|
8620
|
+
async enable() {
|
|
8621
|
+
const hasSourceElementsWithDesc = this.player.sourceElements.some(
|
|
8622
|
+
(el) => el.getAttribute("data-desc-src")
|
|
8623
|
+
);
|
|
8624
|
+
const hasTracksWithDesc = this.captionTracks.length > 0;
|
|
8625
|
+
if (!this.src && !hasSourceElementsWithDesc && !hasTracksWithDesc) {
|
|
8626
|
+
console.warn("VidPly: No audio description source, source elements, or tracks provided");
|
|
8627
|
+
return;
|
|
8628
|
+
}
|
|
8629
|
+
this.desiredState = true;
|
|
8630
|
+
const currentTime = this.player.state.currentTime;
|
|
8631
|
+
const wasPlaying = this.player.state.playing;
|
|
8632
|
+
const posterValue = this.player.element.poster || this.player.element.getAttribute("poster") || this.player.options.poster;
|
|
8633
|
+
const shouldKeepPoster = currentTime < 0.1 && !wasPlaying;
|
|
8634
|
+
const currentCaptionText = this._getCurrentCaptionText();
|
|
8635
|
+
if (this.sourceElement) {
|
|
8636
|
+
await this._enableWithSourceElement(currentTime, wasPlaying, posterValue, shouldKeepPoster, currentCaptionText);
|
|
8637
|
+
} else {
|
|
8638
|
+
await this._enableWithDirectSrc(currentTime, wasPlaying, posterValue, shouldKeepPoster);
|
|
8639
|
+
}
|
|
8640
|
+
}
|
|
8641
|
+
/**
|
|
8642
|
+
* Disable audio description
|
|
8643
|
+
*/
|
|
8644
|
+
async disable() {
|
|
8645
|
+
if (!this.player.originalSrc) {
|
|
8646
|
+
return;
|
|
8647
|
+
}
|
|
8648
|
+
this.desiredState = false;
|
|
8649
|
+
const currentTime = this.player.state.currentTime;
|
|
8650
|
+
const wasPlaying = this.player.state.playing;
|
|
8651
|
+
const posterValue = this.player.element.poster || this.player.element.getAttribute("poster") || this.player.options.poster;
|
|
8652
|
+
const shouldKeepPoster = currentTime < 0.1 && !wasPlaying;
|
|
8653
|
+
const currentCaptionText = this._getCurrentCaptionText();
|
|
8654
|
+
if (this.sourceElement) {
|
|
8655
|
+
await this._disableWithSourceElement(currentTime, wasPlaying, posterValue, shouldKeepPoster, currentCaptionText);
|
|
8656
|
+
} else {
|
|
8657
|
+
await this._disableWithDirectSrc(currentTime, wasPlaying, posterValue);
|
|
8658
|
+
}
|
|
8659
|
+
}
|
|
8660
|
+
/**
|
|
8661
|
+
* Toggle audio description
|
|
8662
|
+
*/
|
|
8663
|
+
async toggle() {
|
|
8664
|
+
const descriptionTrack = this.player.findTextTrack("descriptions");
|
|
8665
|
+
const hasAudioDescriptionSrc = this.isAvailable();
|
|
8666
|
+
if (descriptionTrack && !hasAudioDescriptionSrc) {
|
|
8667
|
+
if (descriptionTrack.mode === "showing") {
|
|
8668
|
+
descriptionTrack.mode = "hidden";
|
|
8669
|
+
this.enabled = false;
|
|
8670
|
+
this.player.emit("audiodescriptiondisabled");
|
|
8671
|
+
} else {
|
|
8672
|
+
descriptionTrack.mode = "showing";
|
|
8673
|
+
this.enabled = true;
|
|
8674
|
+
this.player.emit("audiodescriptionenabled");
|
|
8675
|
+
}
|
|
8676
|
+
} else if (descriptionTrack && hasAudioDescriptionSrc) {
|
|
8677
|
+
if (this.enabled) {
|
|
8678
|
+
this.desiredState = false;
|
|
8679
|
+
await this.disable();
|
|
8680
|
+
} else {
|
|
8681
|
+
descriptionTrack.mode = "showing";
|
|
8682
|
+
this.desiredState = true;
|
|
8683
|
+
await this.enable();
|
|
8684
|
+
}
|
|
8685
|
+
} else if (hasAudioDescriptionSrc) {
|
|
8686
|
+
if (this.enabled) {
|
|
8687
|
+
this.desiredState = false;
|
|
8688
|
+
await this.disable();
|
|
8689
|
+
} else {
|
|
8690
|
+
this.desiredState = true;
|
|
8691
|
+
await this.enable();
|
|
8692
|
+
}
|
|
8693
|
+
}
|
|
8694
|
+
}
|
|
8695
|
+
/**
|
|
8696
|
+
* Get current caption text for synchronization
|
|
8697
|
+
*/
|
|
8698
|
+
_getCurrentCaptionText() {
|
|
8699
|
+
if (this.player.captionManager && this.player.captionManager.currentTrack && this.player.captionManager.currentCue) {
|
|
8700
|
+
return this.player.captionManager.currentCue.text;
|
|
8701
|
+
}
|
|
8702
|
+
return null;
|
|
8703
|
+
}
|
|
8704
|
+
/**
|
|
8705
|
+
* Validate that a track URL exists
|
|
8706
|
+
*/
|
|
8707
|
+
async _validateTrackExists(url) {
|
|
8708
|
+
try {
|
|
8709
|
+
const response = await fetch(url, { method: "HEAD" });
|
|
8710
|
+
return response.ok;
|
|
8711
|
+
} catch (e) {
|
|
8712
|
+
return false;
|
|
8713
|
+
}
|
|
8714
|
+
}
|
|
8715
|
+
/**
|
|
8716
|
+
* Swap caption tracks to described versions
|
|
8717
|
+
*/
|
|
8718
|
+
async _swapCaptionTracks(toDescribed = true) {
|
|
8719
|
+
if (this.captionTracks.length === 0) return [];
|
|
8720
|
+
const swappedTracks = [];
|
|
8721
|
+
const validationPromises = this.captionTracks.map(async (trackInfo) => {
|
|
8722
|
+
if (trackInfo.trackElement && trackInfo.describedSrc) {
|
|
8723
|
+
if (trackInfo.explicit === true) {
|
|
8724
|
+
try {
|
|
8725
|
+
const exists = await this._validateTrackExists(
|
|
8726
|
+
toDescribed ? trackInfo.describedSrc : trackInfo.originalSrc
|
|
8727
|
+
);
|
|
8728
|
+
return { trackInfo, exists };
|
|
8729
|
+
} catch (e) {
|
|
8730
|
+
return { trackInfo, exists: false };
|
|
8731
|
+
}
|
|
8732
|
+
}
|
|
8733
|
+
}
|
|
8734
|
+
return { trackInfo, exists: false };
|
|
8735
|
+
});
|
|
8736
|
+
const validationResults = await Promise.all(validationPromises);
|
|
8737
|
+
const tracksToSwap = validationResults.filter((result) => result.exists);
|
|
8738
|
+
if (tracksToSwap.length > 0) {
|
|
8739
|
+
const trackModes = /* @__PURE__ */ new Map();
|
|
8740
|
+
tracksToSwap.forEach(({ trackInfo }) => {
|
|
8741
|
+
const textTrack = trackInfo.trackElement.track;
|
|
8742
|
+
if (textTrack) {
|
|
8743
|
+
trackModes.set(trackInfo, {
|
|
8744
|
+
wasShowing: textTrack.mode === "showing",
|
|
8745
|
+
wasHidden: textTrack.mode === "hidden"
|
|
8746
|
+
});
|
|
8747
|
+
} else {
|
|
8748
|
+
trackModes.set(trackInfo, { wasShowing: false, wasHidden: false });
|
|
8523
8749
|
}
|
|
8524
8750
|
});
|
|
8525
|
-
const
|
|
8526
|
-
|
|
8527
|
-
|
|
8751
|
+
const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {
|
|
8752
|
+
const attributes = {};
|
|
8753
|
+
Array.from(trackInfo.trackElement.attributes).forEach((attr) => {
|
|
8754
|
+
attributes[attr.name] = attr.value;
|
|
8755
|
+
});
|
|
8756
|
+
const result = {
|
|
8757
|
+
trackInfo,
|
|
8758
|
+
oldSrc: trackInfo.trackElement.getAttribute("src"),
|
|
8759
|
+
parent: trackInfo.trackElement.parentNode,
|
|
8760
|
+
nextSibling: trackInfo.trackElement.nextSibling,
|
|
8761
|
+
attributes
|
|
8762
|
+
};
|
|
8763
|
+
trackInfo.trackElement.remove();
|
|
8764
|
+
return result;
|
|
8528
8765
|
});
|
|
8529
|
-
this.element.
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8766
|
+
this.player.element.load();
|
|
8767
|
+
await new Promise((resolve) => {
|
|
8768
|
+
setTimeout(() => {
|
|
8769
|
+
tracksToReadd.forEach(({ trackInfo, parent, nextSibling, attributes }) => {
|
|
8770
|
+
swappedTracks.push(trackInfo);
|
|
8771
|
+
const newTrackElement = document.createElement("track");
|
|
8772
|
+
const newSrc = toDescribed ? trackInfo.describedSrc : trackInfo.originalSrc;
|
|
8773
|
+
newTrackElement.setAttribute("src", newSrc);
|
|
8774
|
+
Object.keys(attributes).forEach((attrName) => {
|
|
8775
|
+
if (attrName !== "src" && attrName !== "data-desc-src") {
|
|
8776
|
+
newTrackElement.setAttribute(attrName, attributes[attrName]);
|
|
8777
|
+
}
|
|
8778
|
+
});
|
|
8779
|
+
const targetParent = parent || this.player.element;
|
|
8780
|
+
if (nextSibling && nextSibling.parentNode) {
|
|
8781
|
+
targetParent.insertBefore(newTrackElement, nextSibling);
|
|
8782
|
+
} else {
|
|
8783
|
+
targetParent.appendChild(newTrackElement);
|
|
8784
|
+
}
|
|
8785
|
+
trackInfo.trackElement = newTrackElement;
|
|
8786
|
+
});
|
|
8787
|
+
this.player.invalidateTrackCache();
|
|
8788
|
+
const setupNewTracks = () => {
|
|
8789
|
+
this.player.setManagedTimeout(() => {
|
|
8790
|
+
swappedTracks.forEach((trackInfo) => {
|
|
8791
|
+
const newTextTrack = trackInfo.trackElement.track;
|
|
8792
|
+
if (newTextTrack) {
|
|
8793
|
+
const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };
|
|
8794
|
+
newTextTrack.mode = "hidden";
|
|
8795
|
+
const restoreMode = () => {
|
|
8796
|
+
if (modeInfo.wasShowing || modeInfo.wasHidden) {
|
|
8797
|
+
newTextTrack.mode = "hidden";
|
|
8798
|
+
} else {
|
|
8799
|
+
newTextTrack.mode = "disabled";
|
|
8800
|
+
}
|
|
8801
|
+
};
|
|
8802
|
+
if (newTextTrack.readyState >= 2) {
|
|
8803
|
+
restoreMode();
|
|
8804
|
+
} else {
|
|
8805
|
+
newTextTrack.addEventListener("load", restoreMode, { once: true });
|
|
8806
|
+
newTextTrack.addEventListener("error", restoreMode, { once: true });
|
|
8807
|
+
}
|
|
8808
|
+
}
|
|
8809
|
+
});
|
|
8810
|
+
}, 300);
|
|
8811
|
+
};
|
|
8812
|
+
if (this.player.element.readyState >= 1) {
|
|
8813
|
+
setTimeout(setupNewTracks, 200);
|
|
8814
|
+
} else {
|
|
8815
|
+
this.player.element.addEventListener("loadedmetadata", setupNewTracks, { once: true });
|
|
8816
|
+
setTimeout(setupNewTracks, 2e3);
|
|
8817
|
+
}
|
|
8818
|
+
resolve();
|
|
8819
|
+
}, 100);
|
|
8820
|
+
});
|
|
8821
|
+
}
|
|
8822
|
+
return swappedTracks;
|
|
8823
|
+
}
|
|
8824
|
+
/**
|
|
8825
|
+
* Update source elements to described versions
|
|
8826
|
+
*/
|
|
8827
|
+
_updateSourceElements(toDescribed = true) {
|
|
8828
|
+
const sourceElements = this.player.sourceElements;
|
|
8829
|
+
const sourcesToUpdate = [];
|
|
8830
|
+
sourceElements.forEach((sourceEl) => {
|
|
8831
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
8832
|
+
const currentSrc = sourceEl.getAttribute("src");
|
|
8833
|
+
if (descSrcAttr) {
|
|
8834
|
+
const type = sourceEl.getAttribute("type");
|
|
8835
|
+
let origSrc = sourceEl.getAttribute("data-orig-src") || currentSrc;
|
|
8836
|
+
sourcesToUpdate.push({
|
|
8837
|
+
src: toDescribed ? descSrcAttr : origSrc,
|
|
8838
|
+
type,
|
|
8839
|
+
origSrc,
|
|
8840
|
+
descSrc: descSrcAttr
|
|
8841
|
+
});
|
|
8842
|
+
} else {
|
|
8843
|
+
sourcesToUpdate.push({
|
|
8844
|
+
src: sourceEl.getAttribute("src"),
|
|
8845
|
+
type: sourceEl.getAttribute("type"),
|
|
8846
|
+
origSrc: null,
|
|
8847
|
+
descSrc: null
|
|
8848
|
+
});
|
|
8849
|
+
}
|
|
8850
|
+
});
|
|
8851
|
+
if (this.player.element.hasAttribute("src")) {
|
|
8852
|
+
this.player.element.removeAttribute("src");
|
|
8853
|
+
}
|
|
8854
|
+
sourceElements.forEach((sourceEl) => sourceEl.remove());
|
|
8855
|
+
sourcesToUpdate.forEach((sourceInfo) => {
|
|
8856
|
+
const newSource = document.createElement("source");
|
|
8857
|
+
newSource.setAttribute("src", sourceInfo.src);
|
|
8858
|
+
if (sourceInfo.type) {
|
|
8859
|
+
newSource.setAttribute("type", sourceInfo.type);
|
|
8860
|
+
}
|
|
8861
|
+
if (sourceInfo.origSrc) {
|
|
8862
|
+
newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
|
|
8863
|
+
}
|
|
8864
|
+
if (sourceInfo.descSrc) {
|
|
8865
|
+
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
8866
|
+
}
|
|
8867
|
+
const firstTrack = this.player.element.querySelector("track");
|
|
8868
|
+
if (firstTrack) {
|
|
8869
|
+
this.player.element.insertBefore(newSource, firstTrack);
|
|
8870
|
+
} else {
|
|
8871
|
+
this.player.element.appendChild(newSource);
|
|
8872
|
+
}
|
|
8873
|
+
});
|
|
8874
|
+
this.player._sourceElementsDirty = true;
|
|
8875
|
+
this.player._sourceElementsCache = null;
|
|
8876
|
+
}
|
|
8877
|
+
/**
|
|
8878
|
+
* Wait for media to be ready
|
|
8879
|
+
*/
|
|
8880
|
+
async _waitForMediaReady(needSeek = false) {
|
|
8881
|
+
await new Promise((resolve) => {
|
|
8882
|
+
if (this.player.element.readyState >= 1) {
|
|
8883
|
+
resolve();
|
|
8884
|
+
} else {
|
|
8885
|
+
const onLoad = () => {
|
|
8886
|
+
this.player.element.removeEventListener("loadedmetadata", onLoad);
|
|
8887
|
+
resolve();
|
|
8888
|
+
};
|
|
8889
|
+
this.player.element.addEventListener("loadedmetadata", onLoad);
|
|
8890
|
+
}
|
|
8891
|
+
});
|
|
8892
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
8893
|
+
if (needSeek) {
|
|
8894
|
+
await new Promise((resolve) => {
|
|
8895
|
+
if (this.player.element.readyState >= 3) {
|
|
8896
|
+
resolve();
|
|
8897
|
+
} else {
|
|
8898
|
+
const onCanPlay = () => {
|
|
8899
|
+
this.player.element.removeEventListener("canplay", onCanPlay);
|
|
8900
|
+
this.player.element.removeEventListener("canplaythrough", onCanPlay);
|
|
8901
|
+
resolve();
|
|
8902
|
+
};
|
|
8903
|
+
this.player.element.addEventListener("canplay", onCanPlay, { once: true });
|
|
8904
|
+
this.player.element.addEventListener("canplaythrough", onCanPlay, { once: true });
|
|
8905
|
+
setTimeout(() => {
|
|
8906
|
+
this.player.element.removeEventListener("canplay", onCanPlay);
|
|
8907
|
+
this.player.element.removeEventListener("canplaythrough", onCanPlay);
|
|
8908
|
+
resolve();
|
|
8909
|
+
}, 3e3);
|
|
8910
|
+
}
|
|
8911
|
+
});
|
|
8912
|
+
}
|
|
8913
|
+
}
|
|
8914
|
+
/**
|
|
8915
|
+
* Restore playback state after source change
|
|
8916
|
+
*/
|
|
8917
|
+
async _restorePlaybackState(currentTime, wasPlaying, shouldKeepPoster, currentCaptionText) {
|
|
8918
|
+
let syncTime = currentTime;
|
|
8919
|
+
if (currentCaptionText && this.player.captionManager && this.player.captionManager.tracks.length > 0) {
|
|
8920
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
8921
|
+
const matchingTime = this.player.findMatchingCaptionTime(
|
|
8922
|
+
currentCaptionText,
|
|
8923
|
+
this.player.captionManager.tracks
|
|
8924
|
+
);
|
|
8925
|
+
if (matchingTime !== null) {
|
|
8926
|
+
syncTime = matchingTime;
|
|
8927
|
+
if (this.player.options.debug) {
|
|
8928
|
+
this.player.log("[VidPly] Syncing via caption: ".concat(currentTime, "s -> ").concat(syncTime, "s"));
|
|
8929
|
+
}
|
|
8930
|
+
}
|
|
8931
|
+
}
|
|
8932
|
+
if (syncTime > 0) {
|
|
8933
|
+
this.player.seek(syncTime);
|
|
8934
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
8935
|
+
}
|
|
8936
|
+
if (wasPlaying) {
|
|
8937
|
+
await this.player.play();
|
|
8938
|
+
this.player.setManagedTimeout(() => {
|
|
8939
|
+
this.player.hidePosterOverlay();
|
|
8940
|
+
}, 100);
|
|
8941
|
+
} else {
|
|
8942
|
+
this.player.pause();
|
|
8943
|
+
if (!shouldKeepPoster) {
|
|
8944
|
+
this.player.hidePosterOverlay();
|
|
8945
|
+
}
|
|
8946
|
+
}
|
|
8947
|
+
}
|
|
8948
|
+
/**
|
|
8949
|
+
* Enable with source element method
|
|
8950
|
+
*/
|
|
8951
|
+
async _enableWithSourceElement(currentTime, wasPlaying, posterValue, shouldKeepPoster, currentCaptionText) {
|
|
8952
|
+
await this._swapCaptionTracks(true);
|
|
8953
|
+
this._updateSourceElements(true);
|
|
8954
|
+
if (posterValue && this.player.element.tagName === "VIDEO") {
|
|
8955
|
+
this.player.element.poster = posterValue;
|
|
8956
|
+
}
|
|
8957
|
+
this.player.element.load();
|
|
8958
|
+
await this._waitForMediaReady(currentTime > 0 || wasPlaying);
|
|
8959
|
+
await this._restorePlaybackState(currentTime, wasPlaying, shouldKeepPoster, currentCaptionText);
|
|
8960
|
+
if (!this.desiredState) return;
|
|
8961
|
+
this.enabled = true;
|
|
8962
|
+
this.player.state.audioDescriptionEnabled = true;
|
|
8963
|
+
this.player.emit("audiodescriptionenabled");
|
|
8964
|
+
this._reloadTranscript();
|
|
8965
|
+
}
|
|
8966
|
+
/**
|
|
8967
|
+
* Enable with direct src method
|
|
8968
|
+
*/
|
|
8969
|
+
async _enableWithDirectSrc(currentTime, wasPlaying, posterValue, shouldKeepPoster) {
|
|
8970
|
+
await this._swapCaptionTracks(true);
|
|
8971
|
+
if (posterValue && this.player.element.tagName === "VIDEO") {
|
|
8972
|
+
this.player.element.poster = posterValue;
|
|
8973
|
+
}
|
|
8974
|
+
this.player.element.src = this.src;
|
|
8975
|
+
await this._waitForMediaReady(currentTime > 0 || wasPlaying);
|
|
8976
|
+
if (currentTime > 0) {
|
|
8977
|
+
this.player.seek(currentTime);
|
|
8978
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
8979
|
+
}
|
|
8980
|
+
if (wasPlaying) {
|
|
8981
|
+
await this.player.play();
|
|
8982
|
+
} else {
|
|
8983
|
+
this.player.pause();
|
|
8984
|
+
if (!shouldKeepPoster) {
|
|
8985
|
+
this.player.hidePosterOverlay();
|
|
8986
|
+
}
|
|
8987
|
+
}
|
|
8988
|
+
if (!this.desiredState) return;
|
|
8989
|
+
this.enabled = true;
|
|
8990
|
+
this.player.state.audioDescriptionEnabled = true;
|
|
8991
|
+
this.player.emit("audiodescriptionenabled");
|
|
8992
|
+
this._reloadTranscript();
|
|
8993
|
+
}
|
|
8994
|
+
/**
|
|
8995
|
+
* Disable with source element method
|
|
8996
|
+
*/
|
|
8997
|
+
async _disableWithSourceElement(currentTime, wasPlaying, posterValue, shouldKeepPoster, currentCaptionText) {
|
|
8998
|
+
await this._swapCaptionTracks(false);
|
|
8999
|
+
this._updateSourceElements(false);
|
|
9000
|
+
if (posterValue && this.player.element.tagName === "VIDEO") {
|
|
9001
|
+
this.player.element.poster = posterValue;
|
|
9002
|
+
}
|
|
9003
|
+
this.player.element.load();
|
|
9004
|
+
this.player.invalidateTrackCache();
|
|
9005
|
+
await this._waitForMediaReady(currentTime > 0 || wasPlaying);
|
|
9006
|
+
await this._restorePlaybackState(currentTime, wasPlaying, shouldKeepPoster, currentCaptionText);
|
|
9007
|
+
if (this.player.captionManager) {
|
|
9008
|
+
this.player.captionManager.destroy();
|
|
9009
|
+
this.player.captionManager = new CaptionManager(this.player);
|
|
9010
|
+
}
|
|
9011
|
+
if (this.desiredState) return;
|
|
9012
|
+
this.enabled = false;
|
|
9013
|
+
this.player.state.audioDescriptionEnabled = false;
|
|
9014
|
+
this.player.emit("audiodescriptiondisabled");
|
|
9015
|
+
this._reloadTranscript();
|
|
9016
|
+
}
|
|
9017
|
+
/**
|
|
9018
|
+
* Disable with direct src method
|
|
9019
|
+
*/
|
|
9020
|
+
async _disableWithDirectSrc(currentTime, wasPlaying, posterValue) {
|
|
9021
|
+
await this._swapCaptionTracks(false);
|
|
9022
|
+
if (posterValue && this.player.element.tagName === "VIDEO") {
|
|
9023
|
+
this.player.element.poster = posterValue;
|
|
9024
|
+
}
|
|
9025
|
+
const originalSrcToUse = this.originalSource || this.player.originalSrc;
|
|
9026
|
+
this.player.element.src = originalSrcToUse;
|
|
9027
|
+
this.player.element.load();
|
|
9028
|
+
await this._waitForMediaReady(currentTime > 0 || wasPlaying);
|
|
9029
|
+
if (currentTime > 0) {
|
|
9030
|
+
this.player.seek(currentTime);
|
|
9031
|
+
}
|
|
9032
|
+
if (wasPlaying) {
|
|
9033
|
+
await this.player.play();
|
|
9034
|
+
}
|
|
9035
|
+
if (this.desiredState) return;
|
|
9036
|
+
this.enabled = false;
|
|
9037
|
+
this.player.state.audioDescriptionEnabled = false;
|
|
9038
|
+
this.player.emit("audiodescriptiondisabled");
|
|
9039
|
+
this._reloadTranscript();
|
|
9040
|
+
}
|
|
9041
|
+
/**
|
|
9042
|
+
* Reload transcript after audio description state change
|
|
9043
|
+
*/
|
|
9044
|
+
_reloadTranscript() {
|
|
9045
|
+
if (this.player.transcriptManager && this.player.transcriptManager.isVisible) {
|
|
9046
|
+
this.player.setManagedTimeout(() => {
|
|
9047
|
+
if (this.player.transcriptManager && this.player.transcriptManager.loadTranscriptData) {
|
|
9048
|
+
this.player.transcriptManager.loadTranscriptData();
|
|
9049
|
+
}
|
|
9050
|
+
}, 800);
|
|
9051
|
+
}
|
|
9052
|
+
}
|
|
9053
|
+
/**
|
|
9054
|
+
* Update sources (called when playlist changes)
|
|
9055
|
+
*/
|
|
9056
|
+
updateSources(audioDescriptionSrc) {
|
|
9057
|
+
this.src = audioDescriptionSrc || null;
|
|
9058
|
+
this.enabled = false;
|
|
9059
|
+
this.desiredState = false;
|
|
9060
|
+
this.sourceElement = null;
|
|
9061
|
+
this.originalSource = null;
|
|
9062
|
+
this.captionTracks = [];
|
|
9063
|
+
}
|
|
9064
|
+
/**
|
|
9065
|
+
* Reinitialize from current player elements (called after playlist loads new tracks)
|
|
9066
|
+
*/
|
|
9067
|
+
reinitialize() {
|
|
9068
|
+
this.player.invalidateTrackCache();
|
|
9069
|
+
this.initFromSourceElements(this.player.sourceElements, this.player.trackElements);
|
|
9070
|
+
}
|
|
9071
|
+
/**
|
|
9072
|
+
* Cleanup
|
|
9073
|
+
*/
|
|
9074
|
+
destroy() {
|
|
9075
|
+
this.enabled = false;
|
|
9076
|
+
this.desiredState = false;
|
|
9077
|
+
this.captionTracks = [];
|
|
9078
|
+
this.sourceElement = null;
|
|
9079
|
+
this.originalSource = null;
|
|
9080
|
+
}
|
|
9081
|
+
};
|
|
9082
|
+
|
|
9083
|
+
// src/core/SignLanguageManager.js
|
|
9084
|
+
init_DOMUtils();
|
|
9085
|
+
init_Icons();
|
|
9086
|
+
init_i18n();
|
|
9087
|
+
init_DraggableResizable();
|
|
9088
|
+
init_MenuUtils();
|
|
9089
|
+
init_FormUtils();
|
|
9090
|
+
var SignLanguageManager = class {
|
|
9091
|
+
constructor(player) {
|
|
9092
|
+
this.player = player;
|
|
9093
|
+
this.src = player.options.signLanguageSrc;
|
|
9094
|
+
this.sources = player.options.signLanguageSources || {};
|
|
9095
|
+
this.currentLanguage = null;
|
|
9096
|
+
this.desiredPosition = player.options.signLanguagePosition || "bottom-right";
|
|
9097
|
+
this.wrapper = null;
|
|
9098
|
+
this.header = null;
|
|
9099
|
+
this.video = null;
|
|
9100
|
+
this.selector = null;
|
|
9101
|
+
this.settingsButton = null;
|
|
9102
|
+
this.settingsMenu = null;
|
|
9103
|
+
this.resizeHandles = [];
|
|
9104
|
+
this.enabled = false;
|
|
9105
|
+
this.settingsMenuVisible = false;
|
|
9106
|
+
this.settingsMenuJustOpened = false;
|
|
9107
|
+
this.documentClickHandlerAdded = false;
|
|
9108
|
+
this.handlers = null;
|
|
9109
|
+
this.settingsHandlers = null;
|
|
9110
|
+
this.interactionHandlers = null;
|
|
9111
|
+
this.draggable = null;
|
|
9112
|
+
this.documentClickHandler = null;
|
|
9113
|
+
this.settingsMenuKeyHandler = null;
|
|
9114
|
+
this.customKeyHandler = null;
|
|
9115
|
+
this.dragOptionButton = null;
|
|
9116
|
+
this.dragOptionText = null;
|
|
9117
|
+
this.resizeOptionButton = null;
|
|
9118
|
+
this.resizeOptionText = null;
|
|
9119
|
+
}
|
|
9120
|
+
/**
|
|
9121
|
+
* Check if sign language is available
|
|
9122
|
+
*/
|
|
9123
|
+
isAvailable() {
|
|
9124
|
+
return Object.keys(this.sources).length > 0 || !!this.src;
|
|
9125
|
+
}
|
|
9126
|
+
/**
|
|
9127
|
+
* Enable sign language video
|
|
9128
|
+
*/
|
|
9129
|
+
enable() {
|
|
9130
|
+
const hasMultipleSources = Object.keys(this.sources).length > 0;
|
|
9131
|
+
const hasSingleSource = !!this.src;
|
|
9132
|
+
if (!hasMultipleSources && !hasSingleSource) {
|
|
9133
|
+
console.warn("No sign language video source provided");
|
|
9134
|
+
return;
|
|
9135
|
+
}
|
|
9136
|
+
if (this.wrapper) {
|
|
9137
|
+
this.wrapper.style.display = "block";
|
|
9138
|
+
this.enabled = true;
|
|
9139
|
+
this.player.state.signLanguageEnabled = true;
|
|
9140
|
+
this.player.emit("signlanguageenabled");
|
|
9141
|
+
this.player.setManagedTimeout(() => {
|
|
9142
|
+
if (this.settingsButton && document.contains(this.settingsButton)) {
|
|
9143
|
+
this.settingsButton.focus({ preventScroll: true });
|
|
9144
|
+
}
|
|
9145
|
+
}, 150);
|
|
9146
|
+
return;
|
|
9147
|
+
}
|
|
9148
|
+
let initialLang = null;
|
|
9149
|
+
let initialSrc = null;
|
|
9150
|
+
if (hasMultipleSources) {
|
|
9151
|
+
initialLang = this._determineInitialLanguage();
|
|
9152
|
+
initialSrc = this.sources[initialLang];
|
|
9153
|
+
this.currentLanguage = initialLang;
|
|
9154
|
+
} else {
|
|
9155
|
+
initialSrc = this.src;
|
|
9156
|
+
}
|
|
9157
|
+
this._createWrapper();
|
|
9158
|
+
this._createHeader(hasMultipleSources, initialLang);
|
|
9159
|
+
this._createVideo(initialSrc);
|
|
9160
|
+
this._createResizeHandles();
|
|
9161
|
+
this.wrapper.appendChild(this.header);
|
|
9162
|
+
this.wrapper.appendChild(this.video);
|
|
9163
|
+
this.resizeHandles.forEach((handle) => this.wrapper.appendChild(handle));
|
|
9164
|
+
this._applyInitialSize();
|
|
9165
|
+
this.player.container.appendChild(this.wrapper);
|
|
9166
|
+
requestAnimationFrame(() => {
|
|
9167
|
+
this.constrainPosition();
|
|
9168
|
+
});
|
|
9169
|
+
this.video.currentTime = this.player.state.currentTime;
|
|
9170
|
+
if (!this.player.state.paused) {
|
|
9171
|
+
this.video.play();
|
|
9172
|
+
}
|
|
9173
|
+
this._setupInteraction();
|
|
9174
|
+
this._setupEventHandlers(hasMultipleSources);
|
|
9175
|
+
this.enabled = true;
|
|
9176
|
+
this.player.state.signLanguageEnabled = true;
|
|
9177
|
+
this.player.emit("signlanguageenabled");
|
|
9178
|
+
this.player.setManagedTimeout(() => {
|
|
9179
|
+
if (this.settingsButton && document.contains(this.settingsButton)) {
|
|
9180
|
+
this.settingsButton.focus({ preventScroll: true });
|
|
9181
|
+
}
|
|
9182
|
+
}, 150);
|
|
9183
|
+
}
|
|
9184
|
+
/**
|
|
9185
|
+
* Disable sign language video
|
|
9186
|
+
*/
|
|
9187
|
+
disable() {
|
|
9188
|
+
if (this.settingsMenuVisible) {
|
|
9189
|
+
this.hideSettingsMenu({ focusButton: false });
|
|
9190
|
+
}
|
|
9191
|
+
if (this.wrapper) {
|
|
9192
|
+
this.wrapper.style.display = "none";
|
|
9193
|
+
}
|
|
9194
|
+
this.enabled = false;
|
|
9195
|
+
this.player.state.signLanguageEnabled = false;
|
|
9196
|
+
this.player.emit("signlanguagedisabled");
|
|
9197
|
+
}
|
|
9198
|
+
/**
|
|
9199
|
+
* Toggle sign language video
|
|
9200
|
+
*/
|
|
9201
|
+
toggle() {
|
|
9202
|
+
if (this.enabled) {
|
|
9203
|
+
this.disable();
|
|
9204
|
+
} else {
|
|
9205
|
+
this.enable();
|
|
9206
|
+
}
|
|
9207
|
+
}
|
|
9208
|
+
/**
|
|
9209
|
+
* Switch to a different sign language
|
|
9210
|
+
*/
|
|
9211
|
+
switchLanguage(langCode) {
|
|
9212
|
+
if (!this.sources[langCode] || !this.video) {
|
|
9213
|
+
return;
|
|
9214
|
+
}
|
|
9215
|
+
const currentTime = this.video.currentTime;
|
|
9216
|
+
const wasPlaying = !this.video.paused;
|
|
9217
|
+
this.video.src = this.sources[langCode];
|
|
9218
|
+
this.currentLanguage = langCode;
|
|
9219
|
+
this.video.currentTime = currentTime;
|
|
9220
|
+
if (wasPlaying) {
|
|
9221
|
+
this.video.play().catch(() => {
|
|
9222
|
+
});
|
|
9223
|
+
}
|
|
9224
|
+
this.player.emit("signlanguagelanguagechanged", langCode);
|
|
9225
|
+
}
|
|
9226
|
+
/**
|
|
9227
|
+
* Get language label
|
|
9228
|
+
*/
|
|
9229
|
+
getLanguageLabel(langCode) {
|
|
9230
|
+
const langNames = {
|
|
9231
|
+
"en": "English",
|
|
9232
|
+
"de": "Deutsch",
|
|
9233
|
+
"es": "Español",
|
|
9234
|
+
"fr": "Français",
|
|
9235
|
+
"it": "Italiano",
|
|
9236
|
+
"ja": "日本語",
|
|
9237
|
+
"pt": "Português",
|
|
9238
|
+
"ar": "العربية",
|
|
9239
|
+
"hi": "हिन्दी"
|
|
9240
|
+
};
|
|
9241
|
+
return langNames[langCode] || langCode.toUpperCase();
|
|
9242
|
+
}
|
|
9243
|
+
/**
|
|
9244
|
+
* Determine initial sign language
|
|
9245
|
+
*/
|
|
9246
|
+
_determineInitialLanguage() {
|
|
9247
|
+
var _a;
|
|
9248
|
+
if (this.player.captionManager && this.player.captionManager.currentTrack) {
|
|
9249
|
+
const captionLang = (_a = this.player.captionManager.currentTrack.language) == null ? void 0 : _a.toLowerCase().split("-")[0];
|
|
9250
|
+
if (captionLang && this.sources[captionLang]) {
|
|
9251
|
+
return captionLang;
|
|
9252
|
+
}
|
|
9253
|
+
}
|
|
9254
|
+
if (this.player.options.language) {
|
|
9255
|
+
const playerLang = this.player.options.language.toLowerCase().split("-")[0];
|
|
9256
|
+
if (this.sources[playerLang]) {
|
|
9257
|
+
return playerLang;
|
|
9258
|
+
}
|
|
9259
|
+
}
|
|
9260
|
+
return Object.keys(this.sources)[0];
|
|
9261
|
+
}
|
|
9262
|
+
/**
|
|
9263
|
+
* Create wrapper element
|
|
9264
|
+
*/
|
|
9265
|
+
_createWrapper() {
|
|
9266
|
+
this.wrapper = document.createElement("div");
|
|
9267
|
+
this.wrapper.className = "vidply-sign-language-wrapper";
|
|
9268
|
+
this.wrapper.setAttribute("tabindex", "0");
|
|
9269
|
+
this.wrapper.setAttribute("aria-label", i18n.t("player.signLanguageDragResize"));
|
|
9270
|
+
}
|
|
9271
|
+
/**
|
|
9272
|
+
* Create header element
|
|
9273
|
+
*/
|
|
9274
|
+
_createHeader(hasMultipleSources, initialLang) {
|
|
9275
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9276
|
+
this.header = DOMUtils.createElement("div", {
|
|
9277
|
+
className: "".concat(classPrefix, "-sign-language-header"),
|
|
9278
|
+
attributes: { "tabindex": "0" }
|
|
9279
|
+
});
|
|
9280
|
+
const headerLeft = DOMUtils.createElement("div", {
|
|
9281
|
+
className: "".concat(classPrefix, "-sign-language-header-left")
|
|
9282
|
+
});
|
|
9283
|
+
const title = DOMUtils.createElement("h3", {
|
|
9284
|
+
textContent: i18n.t("player.signLanguageVideo")
|
|
9285
|
+
});
|
|
9286
|
+
this._createSettingsButton(headerLeft);
|
|
9287
|
+
if (hasMultipleSources) {
|
|
9288
|
+
this._createLanguageSelector(headerLeft, initialLang);
|
|
9289
|
+
}
|
|
9290
|
+
headerLeft.appendChild(title);
|
|
9291
|
+
const closeButton = this._createCloseButton();
|
|
9292
|
+
this.header.appendChild(headerLeft);
|
|
9293
|
+
this.header.appendChild(closeButton);
|
|
9294
|
+
this.settingsMenuVisible = false;
|
|
9295
|
+
this.settingsMenu = null;
|
|
9296
|
+
this.settingsMenuJustOpened = false;
|
|
9297
|
+
}
|
|
9298
|
+
/**
|
|
9299
|
+
* Create settings button
|
|
9300
|
+
*/
|
|
9301
|
+
_createSettingsButton(container) {
|
|
9302
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9303
|
+
const ariaLabel = i18n.t("player.signLanguageSettings");
|
|
9304
|
+
this.settingsButton = DOMUtils.createElement("button", {
|
|
9305
|
+
className: "".concat(classPrefix, "-sign-language-settings"),
|
|
9306
|
+
attributes: {
|
|
9307
|
+
"type": "button",
|
|
9308
|
+
"aria-label": ariaLabel,
|
|
9309
|
+
"aria-expanded": "false"
|
|
9310
|
+
}
|
|
9311
|
+
});
|
|
9312
|
+
this.settingsButton.appendChild(createIconElement("settings"));
|
|
9313
|
+
DOMUtils.attachTooltip(this.settingsButton, ariaLabel, classPrefix);
|
|
9314
|
+
this.settingsHandlers = {
|
|
9315
|
+
click: (e) => {
|
|
9316
|
+
e.preventDefault();
|
|
9317
|
+
e.stopPropagation();
|
|
9318
|
+
if (this.documentClickHandler) {
|
|
9319
|
+
this.settingsMenuJustOpened = true;
|
|
9320
|
+
setTimeout(() => {
|
|
9321
|
+
this.settingsMenuJustOpened = false;
|
|
9322
|
+
}, 100);
|
|
9323
|
+
}
|
|
9324
|
+
if (this.settingsMenuVisible) {
|
|
9325
|
+
this.hideSettingsMenu();
|
|
9326
|
+
} else {
|
|
9327
|
+
this.showSettingsMenu();
|
|
9328
|
+
}
|
|
9329
|
+
},
|
|
9330
|
+
keydown: (e) => {
|
|
9331
|
+
if (e.key === "d" || e.key === "D") {
|
|
9332
|
+
e.preventDefault();
|
|
9333
|
+
e.stopPropagation();
|
|
9334
|
+
this.toggleKeyboardDragMode();
|
|
9335
|
+
} else if (e.key === "r" || e.key === "R") {
|
|
9336
|
+
e.preventDefault();
|
|
9337
|
+
e.stopPropagation();
|
|
9338
|
+
this.toggleResizeMode();
|
|
9339
|
+
} else if (e.key === "Escape" && this.settingsMenuVisible) {
|
|
9340
|
+
e.preventDefault();
|
|
9341
|
+
e.stopPropagation();
|
|
9342
|
+
this.hideSettingsMenu();
|
|
9343
|
+
}
|
|
9344
|
+
}
|
|
9345
|
+
};
|
|
9346
|
+
this.settingsButton.addEventListener("click", this.settingsHandlers.click);
|
|
9347
|
+
this.settingsButton.addEventListener("keydown", this.settingsHandlers.keydown);
|
|
9348
|
+
container.appendChild(this.settingsButton);
|
|
9349
|
+
}
|
|
9350
|
+
/**
|
|
9351
|
+
* Create language selector
|
|
9352
|
+
*/
|
|
9353
|
+
_createLanguageSelector(container, initialLang) {
|
|
9354
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9355
|
+
const selectId = "".concat(classPrefix, "-sign-language-select-").concat(Date.now());
|
|
9356
|
+
const options = Object.keys(this.sources).map((langCode) => ({
|
|
9357
|
+
value: langCode,
|
|
9358
|
+
text: this.getLanguageLabel(langCode),
|
|
9359
|
+
selected: langCode === initialLang
|
|
9360
|
+
}));
|
|
9361
|
+
const { label, select } = createLabeledSelect({
|
|
9362
|
+
classPrefix,
|
|
9363
|
+
labelClass: "".concat(classPrefix, "-sign-language-label"),
|
|
9364
|
+
selectClass: "".concat(classPrefix, "-sign-language-select"),
|
|
9365
|
+
labelText: "settings.language",
|
|
9366
|
+
selectId,
|
|
9367
|
+
options,
|
|
9368
|
+
onChange: (e) => {
|
|
9369
|
+
e.stopPropagation();
|
|
9370
|
+
this.switchLanguage(e.target.value);
|
|
9371
|
+
}
|
|
9372
|
+
});
|
|
9373
|
+
this.selector = select;
|
|
9374
|
+
const selectorWrapper = DOMUtils.createElement("div", {
|
|
9375
|
+
className: "".concat(classPrefix, "-sign-language-selector-wrapper")
|
|
9376
|
+
});
|
|
9377
|
+
selectorWrapper.appendChild(label);
|
|
9378
|
+
selectorWrapper.appendChild(this.selector);
|
|
9379
|
+
preventDragOnElement(selectorWrapper);
|
|
9380
|
+
container.appendChild(selectorWrapper);
|
|
9381
|
+
}
|
|
9382
|
+
/**
|
|
9383
|
+
* Create close button
|
|
9384
|
+
*/
|
|
9385
|
+
_createCloseButton() {
|
|
9386
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9387
|
+
const ariaLabel = i18n.t("player.closeSignLanguage");
|
|
9388
|
+
const closeButton = DOMUtils.createElement("button", {
|
|
9389
|
+
className: "".concat(classPrefix, "-sign-language-close"),
|
|
9390
|
+
attributes: {
|
|
9391
|
+
"type": "button",
|
|
9392
|
+
"aria-label": ariaLabel
|
|
9393
|
+
}
|
|
9394
|
+
});
|
|
9395
|
+
closeButton.appendChild(createIconElement("close"));
|
|
9396
|
+
DOMUtils.attachTooltip(closeButton, ariaLabel, classPrefix);
|
|
9397
|
+
closeButton.addEventListener("click", () => {
|
|
9398
|
+
var _a, _b;
|
|
9399
|
+
this.disable();
|
|
9400
|
+
if ((_b = (_a = this.player.controlBar) == null ? void 0 : _a.controls) == null ? void 0 : _b.signLanguage) {
|
|
9401
|
+
setTimeout(() => {
|
|
9402
|
+
this.player.controlBar.controls.signLanguage.focus({ preventScroll: true });
|
|
9403
|
+
}, 0);
|
|
9404
|
+
}
|
|
9405
|
+
});
|
|
9406
|
+
return closeButton;
|
|
9407
|
+
}
|
|
9408
|
+
/**
|
|
9409
|
+
* Create video element
|
|
9410
|
+
*/
|
|
9411
|
+
_createVideo(src) {
|
|
9412
|
+
this.video = document.createElement("video");
|
|
9413
|
+
this.video.className = "vidply-sign-language-video";
|
|
9414
|
+
this.video.src = src;
|
|
9415
|
+
this.video.setAttribute("aria-label", i18n.t("player.signLanguage"));
|
|
9416
|
+
this.video.muted = true;
|
|
9417
|
+
this.video.setAttribute("playsinline", "");
|
|
9418
|
+
}
|
|
9419
|
+
/**
|
|
9420
|
+
* Create resize handles
|
|
9421
|
+
*/
|
|
9422
|
+
_createResizeHandles() {
|
|
9423
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9424
|
+
this.resizeHandles = ["n", "s", "e", "w", "ne", "nw", "se", "sw"].map((dir) => {
|
|
9425
|
+
const handle = DOMUtils.createElement("div", {
|
|
9426
|
+
className: "".concat(classPrefix, "-sign-resize-handle ").concat(classPrefix, "-sign-resize-").concat(dir),
|
|
9427
|
+
attributes: {
|
|
9428
|
+
"data-direction": dir,
|
|
9429
|
+
"data-vidply-managed-resize": "true",
|
|
9430
|
+
"aria-hidden": "true"
|
|
9431
|
+
}
|
|
9432
|
+
});
|
|
9433
|
+
handle.style.display = "none";
|
|
9434
|
+
return handle;
|
|
9435
|
+
});
|
|
9436
|
+
}
|
|
9437
|
+
/**
|
|
9438
|
+
* Apply initial size
|
|
9439
|
+
*/
|
|
9440
|
+
_applyInitialSize() {
|
|
9441
|
+
var _a;
|
|
9442
|
+
const saved = this.player.storage.getSignLanguagePreferences();
|
|
9443
|
+
if ((_a = saved == null ? void 0 : saved.size) == null ? void 0 : _a.width) {
|
|
9444
|
+
this.wrapper.style.width = saved.size.width;
|
|
9445
|
+
} else {
|
|
9446
|
+
this.wrapper.style.width = "280px";
|
|
9447
|
+
}
|
|
9448
|
+
this.wrapper.style.height = "auto";
|
|
9449
|
+
}
|
|
9450
|
+
/**
|
|
9451
|
+
* Setup interaction (drag and resize)
|
|
9452
|
+
*/
|
|
9453
|
+
_setupInteraction() {
|
|
9454
|
+
const isMobile2 = window.innerWidth < 768;
|
|
9455
|
+
const isFullscreen = this.player.state.fullscreen;
|
|
9456
|
+
if (isMobile2 && !isFullscreen) {
|
|
9457
|
+
if (this.draggable) {
|
|
9458
|
+
this.draggable.destroy();
|
|
9459
|
+
this.draggable = null;
|
|
9460
|
+
}
|
|
9461
|
+
return;
|
|
9462
|
+
}
|
|
9463
|
+
if (this.draggable) return;
|
|
9464
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9465
|
+
this.draggable = new DraggableResizable(this.wrapper, {
|
|
9466
|
+
dragHandle: this.header,
|
|
9467
|
+
resizeHandles: this.resizeHandles,
|
|
9468
|
+
constrainToViewport: true,
|
|
9469
|
+
maintainAspectRatio: true,
|
|
9470
|
+
minWidth: 150,
|
|
9471
|
+
minHeight: 100,
|
|
9472
|
+
classPrefix: "".concat(classPrefix, "-sign"),
|
|
9473
|
+
keyboardDragKey: "d",
|
|
9474
|
+
keyboardResizeKey: "r",
|
|
9475
|
+
keyboardStep: 10,
|
|
9476
|
+
keyboardStepLarge: 50,
|
|
9477
|
+
pointerResizeIndicatorText: i18n.t("player.signLanguageResizeActive"),
|
|
9478
|
+
onPointerResizeToggle: (enabled) => {
|
|
9479
|
+
this.resizeHandles.forEach((handle) => {
|
|
9480
|
+
handle.style.display = enabled ? "block" : "none";
|
|
9481
|
+
});
|
|
9482
|
+
},
|
|
9483
|
+
onDragStart: (e) => {
|
|
9484
|
+
if (e.target.closest(".".concat(classPrefix, "-sign-language-close")) || e.target.closest(".".concat(classPrefix, "-sign-language-settings")) || e.target.closest(".".concat(classPrefix, "-sign-language-select")) || e.target.closest(".".concat(classPrefix, "-sign-language-label")) || e.target.closest(".".concat(classPrefix, "-sign-language-settings-menu"))) {
|
|
9485
|
+
return false;
|
|
9486
|
+
}
|
|
9487
|
+
return true;
|
|
9488
|
+
}
|
|
9489
|
+
});
|
|
9490
|
+
this._setupCustomKeyHandler();
|
|
9491
|
+
this.interactionHandlers = {
|
|
9492
|
+
draggable: this.draggable,
|
|
9493
|
+
customKeyHandler: this.customKeyHandler
|
|
9494
|
+
};
|
|
9495
|
+
}
|
|
9496
|
+
/**
|
|
9497
|
+
* Setup custom keyboard handler
|
|
9498
|
+
*/
|
|
9499
|
+
_setupCustomKeyHandler() {
|
|
9500
|
+
this.customKeyHandler = (e) => {
|
|
9501
|
+
var _a, _b, _c, _d;
|
|
9502
|
+
const key = e.key.toLowerCase();
|
|
9503
|
+
if (this.settingsMenuVisible) return;
|
|
9504
|
+
if (key === "home") {
|
|
9505
|
+
e.preventDefault();
|
|
9506
|
+
e.stopPropagation();
|
|
9507
|
+
if (this.draggable) {
|
|
9508
|
+
if (this.draggable.pointerResizeMode) {
|
|
9509
|
+
this.draggable.disablePointerResizeMode();
|
|
9510
|
+
}
|
|
9511
|
+
this.draggable.manuallyPositioned = false;
|
|
9512
|
+
this.constrainPosition();
|
|
9513
|
+
}
|
|
9514
|
+
return;
|
|
9515
|
+
}
|
|
9516
|
+
if (key === "r") {
|
|
9517
|
+
e.preventDefault();
|
|
9518
|
+
e.stopPropagation();
|
|
9519
|
+
if (this.toggleResizeMode()) {
|
|
9520
|
+
this.wrapper.focus({ preventScroll: true });
|
|
9521
|
+
}
|
|
9522
|
+
return;
|
|
9523
|
+
}
|
|
9524
|
+
if (key === "escape") {
|
|
9525
|
+
e.preventDefault();
|
|
9526
|
+
e.stopPropagation();
|
|
9527
|
+
if ((_a = this.draggable) == null ? void 0 : _a.pointerResizeMode) {
|
|
9528
|
+
this.draggable.disablePointerResizeMode();
|
|
9529
|
+
return;
|
|
9530
|
+
}
|
|
9531
|
+
if ((_b = this.draggable) == null ? void 0 : _b.keyboardDragMode) {
|
|
9532
|
+
this.draggable.disableKeyboardDragMode();
|
|
9533
|
+
return;
|
|
9534
|
+
}
|
|
9535
|
+
this.disable();
|
|
9536
|
+
if ((_d = (_c = this.player.controlBar) == null ? void 0 : _c.controls) == null ? void 0 : _d.signLanguage) {
|
|
9537
|
+
setTimeout(() => {
|
|
9538
|
+
this.player.controlBar.controls.signLanguage.focus({ preventScroll: true });
|
|
9539
|
+
}, 0);
|
|
9540
|
+
}
|
|
9541
|
+
}
|
|
9542
|
+
};
|
|
9543
|
+
this.wrapper.addEventListener("keydown", this.customKeyHandler);
|
|
9544
|
+
}
|
|
9545
|
+
/**
|
|
9546
|
+
* Setup event handlers
|
|
9547
|
+
*/
|
|
9548
|
+
_setupEventHandlers(hasMultipleSources) {
|
|
9549
|
+
this.handlers = {
|
|
9550
|
+
play: () => {
|
|
9551
|
+
if (this.video) this.video.play();
|
|
9552
|
+
},
|
|
9553
|
+
pause: () => {
|
|
9554
|
+
if (this.video) this.video.pause();
|
|
9555
|
+
},
|
|
9556
|
+
timeupdate: () => {
|
|
9557
|
+
if (this.video && Math.abs(this.video.currentTime - this.player.state.currentTime) > 0.5) {
|
|
9558
|
+
this.video.currentTime = this.player.state.currentTime;
|
|
9559
|
+
}
|
|
9560
|
+
},
|
|
9561
|
+
ratechange: () => {
|
|
9562
|
+
if (this.video) this.video.playbackRate = this.player.state.playbackSpeed;
|
|
9563
|
+
}
|
|
9564
|
+
};
|
|
9565
|
+
this.player.on("play", this.handlers.play);
|
|
9566
|
+
this.player.on("pause", this.handlers.pause);
|
|
9567
|
+
this.player.on("timeupdate", this.handlers.timeupdate);
|
|
9568
|
+
this.player.on("ratechange", this.handlers.ratechange);
|
|
9569
|
+
if (hasMultipleSources) {
|
|
9570
|
+
this.handlers.captionChange = () => {
|
|
9571
|
+
var _a, _b;
|
|
9572
|
+
if (((_a = this.player.captionManager) == null ? void 0 : _a.currentTrack) && this.selector) {
|
|
9573
|
+
const captionLang = (_b = this.player.captionManager.currentTrack.language) == null ? void 0 : _b.toLowerCase().split("-")[0];
|
|
9574
|
+
if (captionLang && this.sources[captionLang] && this.currentLanguage !== captionLang) {
|
|
9575
|
+
this.switchLanguage(captionLang);
|
|
9576
|
+
this.selector.value = captionLang;
|
|
9577
|
+
}
|
|
9578
|
+
}
|
|
9579
|
+
};
|
|
9580
|
+
this.player.on("captionsenabled", this.handlers.captionChange);
|
|
9581
|
+
}
|
|
9582
|
+
}
|
|
9583
|
+
/**
|
|
9584
|
+
* Constrain position within video wrapper
|
|
9585
|
+
*/
|
|
9586
|
+
constrainPosition() {
|
|
9587
|
+
var _a;
|
|
9588
|
+
if (!this.wrapper || !this.player.videoWrapper) return;
|
|
9589
|
+
if ((_a = this.draggable) == null ? void 0 : _a.manuallyPositioned) return;
|
|
9590
|
+
if (!this.wrapper.style.width) {
|
|
9591
|
+
this.wrapper.style.width = "280px";
|
|
9592
|
+
}
|
|
9593
|
+
const videoWrapperRect = this.player.videoWrapper.getBoundingClientRect();
|
|
9594
|
+
const containerRect = this.player.container.getBoundingClientRect();
|
|
9595
|
+
const wrapperRect = this.wrapper.getBoundingClientRect();
|
|
9596
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
9597
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
9598
|
+
const videoWrapperWidth = videoWrapperRect.width;
|
|
9599
|
+
const videoWrapperHeight = videoWrapperRect.height;
|
|
9600
|
+
let wrapperWidth = wrapperRect.width || 280;
|
|
9601
|
+
let wrapperHeight = wrapperRect.height || 280 * 9 / 16;
|
|
9602
|
+
let left, top;
|
|
9603
|
+
const margin = 16;
|
|
9604
|
+
const controlsHeight = 95;
|
|
9605
|
+
const position = this.desiredPosition || "bottom-right";
|
|
9606
|
+
switch (position) {
|
|
9607
|
+
case "bottom-right":
|
|
9608
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
9609
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
9610
|
+
break;
|
|
9611
|
+
case "bottom-left":
|
|
9612
|
+
left = videoWrapperLeft + margin;
|
|
9613
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
9614
|
+
break;
|
|
9615
|
+
case "top-right":
|
|
9616
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
9617
|
+
top = videoWrapperTop + margin;
|
|
9618
|
+
break;
|
|
9619
|
+
case "top-left":
|
|
9620
|
+
left = videoWrapperLeft + margin;
|
|
9621
|
+
top = videoWrapperTop + margin;
|
|
9622
|
+
break;
|
|
9623
|
+
default:
|
|
9624
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
9625
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
9626
|
+
}
|
|
9627
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));
|
|
9628
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));
|
|
9629
|
+
this.wrapper.style.left = "".concat(left, "px");
|
|
9630
|
+
this.wrapper.style.top = "".concat(top, "px");
|
|
9631
|
+
this.wrapper.style.right = "auto";
|
|
9632
|
+
this.wrapper.style.bottom = "auto";
|
|
9633
|
+
}
|
|
9634
|
+
/**
|
|
9635
|
+
* Show settings menu
|
|
9636
|
+
*/
|
|
9637
|
+
showSettingsMenu() {
|
|
9638
|
+
var _a;
|
|
9639
|
+
this.settingsMenuJustOpened = true;
|
|
9640
|
+
setTimeout(() => {
|
|
9641
|
+
this.settingsMenuJustOpened = false;
|
|
9642
|
+
}, 350);
|
|
9643
|
+
this._addDocumentClickHandler();
|
|
9644
|
+
if (this.settingsMenu) {
|
|
9645
|
+
this.settingsMenu.style.display = "block";
|
|
9646
|
+
this.settingsMenuVisible = true;
|
|
9647
|
+
(_a = this.settingsButton) == null ? void 0 : _a.setAttribute("aria-expanded", "true");
|
|
9648
|
+
this._attachMenuKeyboardNavigation();
|
|
9649
|
+
this._positionSettingsMenu();
|
|
9650
|
+
this._updateDragOptionState();
|
|
9651
|
+
this._updateResizeOptionState();
|
|
9652
|
+
focusFirstMenuItem(this.settingsMenu, ".".concat(this.player.options.classPrefix, "-sign-language-settings-item"));
|
|
9653
|
+
return;
|
|
9654
|
+
}
|
|
9655
|
+
this._createSettingsMenu();
|
|
9656
|
+
}
|
|
9657
|
+
/**
|
|
9658
|
+
* Hide settings menu
|
|
9659
|
+
*/
|
|
9660
|
+
hideSettingsMenu({ focusButton = true } = {}) {
|
|
9661
|
+
if (this.settingsMenu) {
|
|
9662
|
+
this.settingsMenu.style.display = "none";
|
|
9663
|
+
this.settingsMenuVisible = false;
|
|
9664
|
+
this.settingsMenuJustOpened = false;
|
|
9665
|
+
if (this.settingsMenuKeyHandler) {
|
|
9666
|
+
this.settingsMenu.removeEventListener("keydown", this.settingsMenuKeyHandler);
|
|
9667
|
+
this.settingsMenuKeyHandler = null;
|
|
9668
|
+
}
|
|
9669
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9670
|
+
const menuItems = Array.from(this.settingsMenu.querySelectorAll(".".concat(classPrefix, "-sign-language-settings-item")));
|
|
9671
|
+
menuItems.forEach((item) => item.setAttribute("tabindex", "-1"));
|
|
9672
|
+
if (this.settingsButton) {
|
|
9673
|
+
this.settingsButton.setAttribute("aria-expanded", "false");
|
|
9674
|
+
if (focusButton) {
|
|
9675
|
+
this.settingsButton.focus({ preventScroll: true });
|
|
9676
|
+
}
|
|
9677
|
+
}
|
|
9678
|
+
}
|
|
9679
|
+
}
|
|
9680
|
+
/**
|
|
9681
|
+
* Add document click handler
|
|
9682
|
+
*/
|
|
9683
|
+
_addDocumentClickHandler() {
|
|
9684
|
+
if (this.documentClickHandlerAdded) return;
|
|
9685
|
+
this.documentClickHandler = (e) => {
|
|
9686
|
+
if (this.settingsMenuJustOpened) return;
|
|
9687
|
+
if (this.settingsButton && (this.settingsButton === e.target || this.settingsButton.contains(e.target))) {
|
|
9688
|
+
return;
|
|
9689
|
+
}
|
|
9690
|
+
if (this.settingsMenu && this.settingsMenu.contains(e.target)) {
|
|
9691
|
+
return;
|
|
9692
|
+
}
|
|
9693
|
+
if (this.settingsMenuVisible) {
|
|
9694
|
+
this.hideSettingsMenu();
|
|
9695
|
+
}
|
|
9696
|
+
};
|
|
9697
|
+
setTimeout(() => {
|
|
9698
|
+
document.addEventListener("mousedown", this.documentClickHandler, true);
|
|
9699
|
+
this.documentClickHandlerAdded = true;
|
|
9700
|
+
}, 300);
|
|
9701
|
+
}
|
|
9702
|
+
/**
|
|
9703
|
+
* Create settings menu
|
|
9704
|
+
*/
|
|
9705
|
+
_createSettingsMenu() {
|
|
9706
|
+
var _a, _b;
|
|
9707
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9708
|
+
this.settingsMenu = DOMUtils.createElement("div", {
|
|
9709
|
+
className: "".concat(classPrefix, "-sign-language-settings-menu"),
|
|
9710
|
+
attributes: { "role": "menu" }
|
|
9711
|
+
});
|
|
9712
|
+
const dragOption = createMenuItem({
|
|
9713
|
+
classPrefix,
|
|
9714
|
+
itemClass: "".concat(classPrefix, "-sign-language-settings-item"),
|
|
9715
|
+
icon: "move",
|
|
9716
|
+
label: "player.enableSignDragMode",
|
|
9717
|
+
hasTextClass: true,
|
|
9718
|
+
onClick: () => {
|
|
9719
|
+
this.toggleKeyboardDragMode();
|
|
9720
|
+
this.hideSettingsMenu();
|
|
9721
|
+
}
|
|
9722
|
+
});
|
|
9723
|
+
dragOption.setAttribute("role", "switch");
|
|
9724
|
+
dragOption.setAttribute("aria-checked", "false");
|
|
9725
|
+
this._removeTooltipFromMenuItem(dragOption);
|
|
9726
|
+
this.dragOptionButton = dragOption;
|
|
9727
|
+
this.dragOptionText = dragOption.querySelector(".".concat(classPrefix, "-settings-text"));
|
|
9728
|
+
this._updateDragOptionState();
|
|
9729
|
+
const resizeOption = createMenuItem({
|
|
9730
|
+
classPrefix,
|
|
9731
|
+
itemClass: "".concat(classPrefix, "-sign-language-settings-item"),
|
|
9732
|
+
icon: "resize",
|
|
9733
|
+
label: "player.enableSignResizeMode",
|
|
9734
|
+
hasTextClass: true,
|
|
9735
|
+
onClick: (event) => {
|
|
9736
|
+
event.preventDefault();
|
|
9737
|
+
event.stopPropagation();
|
|
9738
|
+
const enabled = this.toggleResizeMode({ focus: false });
|
|
9739
|
+
if (enabled) {
|
|
9740
|
+
this.hideSettingsMenu({ focusButton: false });
|
|
9741
|
+
setTimeout(() => {
|
|
9742
|
+
if (this.wrapper) this.wrapper.focus({ preventScroll: true });
|
|
9743
|
+
}, 20);
|
|
9744
|
+
} else {
|
|
9745
|
+
this.hideSettingsMenu({ focusButton: true });
|
|
9746
|
+
}
|
|
9747
|
+
}
|
|
9748
|
+
});
|
|
9749
|
+
resizeOption.setAttribute("role", "switch");
|
|
9750
|
+
resizeOption.setAttribute("aria-checked", "false");
|
|
9751
|
+
this._removeTooltipFromMenuItem(resizeOption);
|
|
9752
|
+
this.resizeOptionButton = resizeOption;
|
|
9753
|
+
this.resizeOptionText = resizeOption.querySelector(".".concat(classPrefix, "-settings-text"));
|
|
9754
|
+
this._updateResizeOptionState();
|
|
9755
|
+
const closeOption = createMenuItem({
|
|
9756
|
+
classPrefix,
|
|
9757
|
+
itemClass: "".concat(classPrefix, "-sign-language-settings-item"),
|
|
9758
|
+
icon: "close",
|
|
9759
|
+
label: "transcript.closeMenu",
|
|
9760
|
+
onClick: () => this.hideSettingsMenu()
|
|
9761
|
+
});
|
|
9762
|
+
this._removeTooltipFromMenuItem(closeOption);
|
|
9763
|
+
this.settingsMenu.appendChild(dragOption);
|
|
9764
|
+
this.settingsMenu.appendChild(resizeOption);
|
|
9765
|
+
this.settingsMenu.appendChild(closeOption);
|
|
9766
|
+
this.settingsMenu.style.visibility = "hidden";
|
|
9767
|
+
this.settingsMenu.style.display = "block";
|
|
9768
|
+
if ((_a = this.settingsButton) == null ? void 0 : _a.parentNode) {
|
|
9769
|
+
this.settingsButton.insertAdjacentElement("afterend", this.settingsMenu);
|
|
9770
|
+
} else if (this.wrapper) {
|
|
9771
|
+
this.wrapper.appendChild(this.settingsMenu);
|
|
9772
|
+
}
|
|
9773
|
+
this._positionSettingsMenuImmediate();
|
|
9774
|
+
requestAnimationFrame(() => {
|
|
9775
|
+
if (this.settingsMenu) {
|
|
9776
|
+
this.settingsMenu.style.visibility = "visible";
|
|
9777
|
+
}
|
|
9778
|
+
});
|
|
9779
|
+
this._attachMenuKeyboardNavigation();
|
|
9780
|
+
this.settingsMenuVisible = true;
|
|
9781
|
+
(_b = this.settingsButton) == null ? void 0 : _b.setAttribute("aria-expanded", "true");
|
|
9782
|
+
this._updateDragOptionState();
|
|
9783
|
+
this._updateResizeOptionState();
|
|
9784
|
+
focusFirstMenuItem(this.settingsMenu, ".".concat(classPrefix, "-sign-language-settings-item"));
|
|
9785
|
+
}
|
|
9786
|
+
/**
|
|
9787
|
+
* Remove tooltip from menu item
|
|
9788
|
+
*/
|
|
9789
|
+
_removeTooltipFromMenuItem(item) {
|
|
9790
|
+
const classPrefix = this.player.options.classPrefix;
|
|
9791
|
+
const tooltip = item.querySelector(".".concat(classPrefix, "-tooltip"));
|
|
9792
|
+
if (tooltip) tooltip.remove();
|
|
9793
|
+
const buttonText = item.querySelector(".".concat(classPrefix, "-button-text"));
|
|
9794
|
+
if (buttonText) buttonText.remove();
|
|
9795
|
+
}
|
|
9796
|
+
/**
|
|
9797
|
+
* Attach menu keyboard navigation
|
|
9798
|
+
*/
|
|
9799
|
+
_attachMenuKeyboardNavigation() {
|
|
9800
|
+
if (this.settingsMenuKeyHandler) {
|
|
9801
|
+
this.settingsMenu.removeEventListener("keydown", this.settingsMenuKeyHandler);
|
|
9802
|
+
}
|
|
9803
|
+
this.settingsMenuKeyHandler = attachMenuKeyboardNavigation(
|
|
9804
|
+
this.settingsMenu,
|
|
9805
|
+
this.settingsButton,
|
|
9806
|
+
".".concat(this.player.options.classPrefix, "-sign-language-settings-item"),
|
|
9807
|
+
() => this.hideSettingsMenu({ focusButton: true })
|
|
9808
|
+
);
|
|
9809
|
+
}
|
|
9810
|
+
/**
|
|
9811
|
+
* Position settings menu immediately
|
|
9812
|
+
*/
|
|
9813
|
+
_positionSettingsMenuImmediate() {
|
|
9814
|
+
if (!this.settingsMenu || !this.settingsButton) return;
|
|
9815
|
+
const buttonRect = this.settingsButton.getBoundingClientRect();
|
|
9816
|
+
const menuRect = this.settingsMenu.getBoundingClientRect();
|
|
9817
|
+
const viewportWidth = window.innerWidth;
|
|
9818
|
+
const viewportHeight = window.innerHeight;
|
|
9819
|
+
const parentContainer = this.settingsButton.parentElement;
|
|
9820
|
+
if (!parentContainer) return;
|
|
9821
|
+
const parentRect = parentContainer.getBoundingClientRect();
|
|
9822
|
+
const buttonCenterX = buttonRect.left + buttonRect.width / 2 - parentRect.left;
|
|
9823
|
+
const buttonBottom = buttonRect.bottom - parentRect.top;
|
|
9824
|
+
const buttonTop = buttonRect.top - parentRect.top;
|
|
9825
|
+
const spaceAbove = buttonRect.top;
|
|
9826
|
+
const spaceBelow = viewportHeight - buttonRect.bottom;
|
|
9827
|
+
let menuTop = buttonBottom + 8;
|
|
9828
|
+
let menuBottom = null;
|
|
9829
|
+
if (spaceBelow < menuRect.height + 20 && spaceAbove > spaceBelow) {
|
|
9830
|
+
menuTop = null;
|
|
9831
|
+
const parentHeight = parentRect.bottom - parentRect.top;
|
|
9832
|
+
menuBottom = parentHeight - buttonTop + 8;
|
|
9833
|
+
this.settingsMenu.classList.add("vidply-menu-above");
|
|
9834
|
+
} else {
|
|
9835
|
+
this.settingsMenu.classList.remove("vidply-menu-above");
|
|
9836
|
+
}
|
|
9837
|
+
let menuLeft = buttonCenterX - menuRect.width / 2;
|
|
9838
|
+
let menuRight = "auto";
|
|
9839
|
+
let transformX = "translateX(0)";
|
|
9840
|
+
const menuLeftAbsolute = buttonRect.left + buttonRect.width / 2 - menuRect.width / 2;
|
|
9841
|
+
if (menuLeftAbsolute < 10) {
|
|
9842
|
+
menuLeft = 0;
|
|
9843
|
+
} else if (menuLeftAbsolute + menuRect.width > viewportWidth - 10) {
|
|
9844
|
+
menuLeft = "auto";
|
|
9845
|
+
menuRight = 0;
|
|
9846
|
+
} else {
|
|
9847
|
+
menuLeft = buttonCenterX;
|
|
9848
|
+
transformX = "translateX(-50%)";
|
|
9849
|
+
}
|
|
9850
|
+
if (menuTop !== null) {
|
|
9851
|
+
this.settingsMenu.style.top = "".concat(menuTop, "px");
|
|
9852
|
+
this.settingsMenu.style.bottom = "auto";
|
|
9853
|
+
} else if (menuBottom !== null) {
|
|
9854
|
+
this.settingsMenu.style.top = "auto";
|
|
9855
|
+
this.settingsMenu.style.bottom = "".concat(menuBottom, "px");
|
|
9856
|
+
}
|
|
9857
|
+
if (menuLeft !== "auto") {
|
|
9858
|
+
this.settingsMenu.style.left = "".concat(menuLeft, "px");
|
|
9859
|
+
this.settingsMenu.style.right = "auto";
|
|
9860
|
+
} else {
|
|
9861
|
+
this.settingsMenu.style.left = "auto";
|
|
9862
|
+
this.settingsMenu.style.right = "".concat(menuRight, "px");
|
|
9863
|
+
}
|
|
9864
|
+
this.settingsMenu.style.transform = transformX;
|
|
9865
|
+
}
|
|
9866
|
+
/**
|
|
9867
|
+
* Position settings menu with RAF
|
|
9868
|
+
*/
|
|
9869
|
+
_positionSettingsMenu() {
|
|
9870
|
+
requestAnimationFrame(() => {
|
|
9871
|
+
setTimeout(() => {
|
|
9872
|
+
this._positionSettingsMenuImmediate();
|
|
9873
|
+
}, 10);
|
|
9874
|
+
});
|
|
9875
|
+
}
|
|
9876
|
+
/**
|
|
9877
|
+
* Toggle keyboard drag mode
|
|
9878
|
+
*/
|
|
9879
|
+
toggleKeyboardDragMode() {
|
|
9880
|
+
if (this.draggable) {
|
|
9881
|
+
const wasEnabled = this.draggable.keyboardDragMode;
|
|
9882
|
+
this.draggable.toggleKeyboardDragMode();
|
|
9883
|
+
const isEnabled = this.draggable.keyboardDragMode;
|
|
9884
|
+
if (!wasEnabled && isEnabled) {
|
|
9885
|
+
this._enableMoveMode();
|
|
9886
|
+
}
|
|
9887
|
+
this._updateDragOptionState();
|
|
9888
|
+
}
|
|
9889
|
+
}
|
|
9890
|
+
/**
|
|
9891
|
+
* Enable move mode visual feedback
|
|
9892
|
+
*/
|
|
9893
|
+
_enableMoveMode() {
|
|
9894
|
+
this.wrapper.classList.add("".concat(this.player.options.classPrefix, "-sign-move-mode"));
|
|
9895
|
+
this._updateResizeOptionState();
|
|
9896
|
+
setTimeout(() => {
|
|
9897
|
+
this.wrapper.classList.remove("".concat(this.player.options.classPrefix, "-sign-move-mode"));
|
|
9898
|
+
}, 2e3);
|
|
9899
|
+
}
|
|
9900
|
+
/**
|
|
9901
|
+
* Toggle resize mode
|
|
9902
|
+
*/
|
|
9903
|
+
toggleResizeMode({ focus = true } = {}) {
|
|
9904
|
+
if (!this.draggable) return false;
|
|
9905
|
+
if (this.draggable.pointerResizeMode) {
|
|
9906
|
+
this.draggable.disablePointerResizeMode({ focus });
|
|
9907
|
+
this._updateResizeOptionState();
|
|
9908
|
+
return false;
|
|
9909
|
+
}
|
|
9910
|
+
this.draggable.enablePointerResizeMode({ focus });
|
|
9911
|
+
this._updateResizeOptionState();
|
|
9912
|
+
return true;
|
|
9913
|
+
}
|
|
9914
|
+
/**
|
|
9915
|
+
* Update drag option state
|
|
9916
|
+
*/
|
|
9917
|
+
_updateDragOptionState() {
|
|
9918
|
+
var _a;
|
|
9919
|
+
if (!this.dragOptionButton) return;
|
|
9920
|
+
const isEnabled = !!((_a = this.draggable) == null ? void 0 : _a.keyboardDragMode);
|
|
9921
|
+
const text = isEnabled ? i18n.t("player.disableSignDragMode") : i18n.t("player.enableSignDragMode");
|
|
9922
|
+
const ariaLabel = isEnabled ? i18n.t("player.disableSignDragModeAria") : i18n.t("player.enableSignDragModeAria");
|
|
9923
|
+
this.dragOptionButton.setAttribute("aria-checked", isEnabled ? "true" : "false");
|
|
9924
|
+
this.dragOptionButton.setAttribute("aria-label", ariaLabel);
|
|
9925
|
+
if (this.dragOptionText) {
|
|
9926
|
+
this.dragOptionText.textContent = text;
|
|
9927
|
+
}
|
|
9928
|
+
}
|
|
9929
|
+
/**
|
|
9930
|
+
* Update resize option state
|
|
9931
|
+
*/
|
|
9932
|
+
_updateResizeOptionState() {
|
|
9933
|
+
var _a;
|
|
9934
|
+
if (!this.resizeOptionButton) return;
|
|
9935
|
+
const isEnabled = !!((_a = this.draggable) == null ? void 0 : _a.pointerResizeMode);
|
|
9936
|
+
const text = isEnabled ? i18n.t("player.disableSignResizeMode") : i18n.t("player.enableSignResizeMode");
|
|
9937
|
+
const ariaLabel = isEnabled ? i18n.t("player.disableSignResizeModeAria") : i18n.t("player.enableSignResizeModeAria");
|
|
9938
|
+
this.resizeOptionButton.setAttribute("aria-checked", isEnabled ? "true" : "false");
|
|
9939
|
+
this.resizeOptionButton.setAttribute("aria-label", ariaLabel);
|
|
9940
|
+
if (this.resizeOptionText) {
|
|
9941
|
+
this.resizeOptionText.textContent = text;
|
|
9942
|
+
}
|
|
9943
|
+
}
|
|
9944
|
+
/**
|
|
9945
|
+
* Save preferences
|
|
9946
|
+
*/
|
|
9947
|
+
savePreferences() {
|
|
9948
|
+
if (!this.wrapper) return;
|
|
9949
|
+
this.player.storage.saveSignLanguagePreferences({
|
|
9950
|
+
size: { width: this.wrapper.style.width }
|
|
9951
|
+
});
|
|
9952
|
+
}
|
|
9953
|
+
/**
|
|
9954
|
+
* Update sources (called when playlist changes)
|
|
9955
|
+
*/
|
|
9956
|
+
updateSources(signLanguageSrc, signLanguageSources) {
|
|
9957
|
+
this.src = signLanguageSrc || null;
|
|
9958
|
+
this.sources = signLanguageSources || {};
|
|
9959
|
+
this.currentLanguage = null;
|
|
9960
|
+
}
|
|
9961
|
+
/**
|
|
9962
|
+
* Cleanup
|
|
9963
|
+
*/
|
|
9964
|
+
cleanup() {
|
|
9965
|
+
var _a;
|
|
9966
|
+
if (this.settingsMenuVisible) {
|
|
9967
|
+
this.hideSettingsMenu({ focusButton: false });
|
|
9968
|
+
}
|
|
9969
|
+
if (this.documentClickHandler && this.documentClickHandlerAdded) {
|
|
9970
|
+
document.removeEventListener("mousedown", this.documentClickHandler, true);
|
|
9971
|
+
this.documentClickHandlerAdded = false;
|
|
9972
|
+
this.documentClickHandler = null;
|
|
9973
|
+
}
|
|
9974
|
+
if (this.settingsHandlers && this.settingsButton) {
|
|
9975
|
+
this.settingsButton.removeEventListener("click", this.settingsHandlers.click);
|
|
9976
|
+
this.settingsButton.removeEventListener("keydown", this.settingsHandlers.keydown);
|
|
9977
|
+
}
|
|
9978
|
+
this.settingsHandlers = null;
|
|
9979
|
+
if (this.handlers) {
|
|
9980
|
+
this.player.off("play", this.handlers.play);
|
|
9981
|
+
this.player.off("pause", this.handlers.pause);
|
|
9982
|
+
this.player.off("timeupdate", this.handlers.timeupdate);
|
|
9983
|
+
this.player.off("ratechange", this.handlers.ratechange);
|
|
9984
|
+
if (this.handlers.captionChange) {
|
|
9985
|
+
this.player.off("captionsenabled", this.handlers.captionChange);
|
|
9986
|
+
}
|
|
9987
|
+
this.handlers = null;
|
|
9988
|
+
}
|
|
9989
|
+
if (this.wrapper && this.customKeyHandler) {
|
|
9990
|
+
this.wrapper.removeEventListener("keydown", this.customKeyHandler);
|
|
9991
|
+
}
|
|
9992
|
+
if (this.draggable) {
|
|
9993
|
+
if (this.draggable.pointerResizeMode) {
|
|
9994
|
+
this.draggable.disablePointerResizeMode();
|
|
9995
|
+
}
|
|
9996
|
+
this.draggable.destroy();
|
|
9997
|
+
this.draggable = null;
|
|
9998
|
+
}
|
|
9999
|
+
this.interactionHandlers = null;
|
|
10000
|
+
if ((_a = this.wrapper) == null ? void 0 : _a.parentNode) {
|
|
10001
|
+
if (this.video) {
|
|
10002
|
+
this.video.pause();
|
|
10003
|
+
this.video.src = "";
|
|
10004
|
+
}
|
|
10005
|
+
this.wrapper.parentNode.removeChild(this.wrapper);
|
|
10006
|
+
}
|
|
10007
|
+
this.wrapper = null;
|
|
10008
|
+
this.video = null;
|
|
10009
|
+
this.settingsButton = null;
|
|
10010
|
+
this.settingsMenu = null;
|
|
10011
|
+
}
|
|
10012
|
+
/**
|
|
10013
|
+
* Destroy
|
|
10014
|
+
*/
|
|
10015
|
+
destroy() {
|
|
10016
|
+
this.cleanup();
|
|
10017
|
+
this.enabled = false;
|
|
10018
|
+
}
|
|
10019
|
+
};
|
|
10020
|
+
|
|
10021
|
+
// src/core/Player.js
|
|
10022
|
+
var playerInstanceCounter = 0;
|
|
10023
|
+
var Player = class _Player extends EventEmitter {
|
|
10024
|
+
constructor(element, options = {}) {
|
|
10025
|
+
super();
|
|
10026
|
+
this.element = typeof element === "string" ? document.querySelector(element) : element;
|
|
10027
|
+
if (!this.element) {
|
|
10028
|
+
throw new Error("VidPly: Element not found");
|
|
10029
|
+
}
|
|
10030
|
+
playerInstanceCounter++;
|
|
10031
|
+
this.instanceId = playerInstanceCounter;
|
|
10032
|
+
if (this.element.tagName !== "VIDEO" && this.element.tagName !== "AUDIO") {
|
|
10033
|
+
const mediaType = options.mediaType || "video";
|
|
10034
|
+
const mediaElement = document.createElement(mediaType);
|
|
10035
|
+
Array.from(this.element.attributes).forEach((attr) => {
|
|
10036
|
+
if (attr.name !== "id" && attr.name !== "class" && !attr.name.startsWith("data-")) {
|
|
10037
|
+
mediaElement.setAttribute(attr.name, attr.value);
|
|
10038
|
+
}
|
|
10039
|
+
});
|
|
10040
|
+
const tracks = this.element.querySelectorAll("track");
|
|
10041
|
+
tracks.forEach((track) => {
|
|
10042
|
+
mediaElement.appendChild(track.cloneNode(true));
|
|
10043
|
+
});
|
|
10044
|
+
this.element.innerHTML = "";
|
|
10045
|
+
this.element.appendChild(mediaElement);
|
|
10046
|
+
this.element = mediaElement;
|
|
10047
|
+
}
|
|
10048
|
+
this._originalElement = this.element;
|
|
10049
|
+
this.options = __spreadValues({
|
|
10050
|
+
// Display
|
|
10051
|
+
width: null,
|
|
10052
|
+
height: null,
|
|
8538
10053
|
poster: null,
|
|
8539
10054
|
responsive: true,
|
|
8540
10055
|
fillContainer: false,
|
|
@@ -8689,6 +10204,58 @@
|
|
|
8689
10204
|
this.settingsDialog = null;
|
|
8690
10205
|
this.metadataCueChangeHandler = null;
|
|
8691
10206
|
this.metadataAlertHandlers = /* @__PURE__ */ new Map();
|
|
10207
|
+
this.audioDescriptionManager = new AudioDescriptionManager(this);
|
|
10208
|
+
this.signLanguageManager = new SignLanguageManager(this);
|
|
10209
|
+
Object.defineProperties(this, {
|
|
10210
|
+
signLanguageWrapper: {
|
|
10211
|
+
get: () => this.signLanguageManager.wrapper,
|
|
10212
|
+
set: (v) => {
|
|
10213
|
+
this.signLanguageManager.wrapper = v;
|
|
10214
|
+
}
|
|
10215
|
+
},
|
|
10216
|
+
signLanguageVideo: {
|
|
10217
|
+
get: () => this.signLanguageManager.video,
|
|
10218
|
+
set: (v) => {
|
|
10219
|
+
this.signLanguageManager.video = v;
|
|
10220
|
+
}
|
|
10221
|
+
},
|
|
10222
|
+
signLanguageHeader: {
|
|
10223
|
+
get: () => this.signLanguageManager.header,
|
|
10224
|
+
set: (v) => {
|
|
10225
|
+
this.signLanguageManager.header = v;
|
|
10226
|
+
}
|
|
10227
|
+
},
|
|
10228
|
+
signLanguageSettingsButton: {
|
|
10229
|
+
get: () => this.signLanguageManager.settingsButton,
|
|
10230
|
+
set: (v) => {
|
|
10231
|
+
this.signLanguageManager.settingsButton = v;
|
|
10232
|
+
}
|
|
10233
|
+
},
|
|
10234
|
+
signLanguageSettingsMenu: {
|
|
10235
|
+
get: () => this.signLanguageManager.settingsMenu,
|
|
10236
|
+
set: (v) => {
|
|
10237
|
+
this.signLanguageManager.settingsMenu = v;
|
|
10238
|
+
}
|
|
10239
|
+
},
|
|
10240
|
+
signLanguageSettingsMenuVisible: {
|
|
10241
|
+
get: () => this.signLanguageManager.settingsMenuVisible,
|
|
10242
|
+
set: (v) => {
|
|
10243
|
+
this.signLanguageManager.settingsMenuVisible = v;
|
|
10244
|
+
}
|
|
10245
|
+
},
|
|
10246
|
+
signLanguageDraggable: {
|
|
10247
|
+
get: () => this.signLanguageManager.draggable,
|
|
10248
|
+
set: (v) => {
|
|
10249
|
+
this.signLanguageManager.draggable = v;
|
|
10250
|
+
}
|
|
10251
|
+
},
|
|
10252
|
+
currentSignLanguage: {
|
|
10253
|
+
get: () => this.signLanguageManager.currentLanguage,
|
|
10254
|
+
set: (v) => {
|
|
10255
|
+
this.signLanguageManager.currentLanguage = v;
|
|
10256
|
+
}
|
|
10257
|
+
}
|
|
10258
|
+
});
|
|
8692
10259
|
this.init();
|
|
8693
10260
|
}
|
|
8694
10261
|
async init() {
|
|
@@ -8951,53 +10518,7 @@
|
|
|
8951
10518
|
}
|
|
8952
10519
|
this.currentSource = src;
|
|
8953
10520
|
this._pendingSource = null;
|
|
8954
|
-
|
|
8955
|
-
for (const sourceEl of sourceElements) {
|
|
8956
|
-
const descSrc = sourceEl.getAttribute("data-desc-src");
|
|
8957
|
-
const origSrc = sourceEl.getAttribute("data-orig-src");
|
|
8958
|
-
if (descSrc || origSrc) {
|
|
8959
|
-
if (!this.audioDescriptionSourceElement) {
|
|
8960
|
-
this.audioDescriptionSourceElement = sourceEl;
|
|
8961
|
-
}
|
|
8962
|
-
if (origSrc) {
|
|
8963
|
-
if (!this.originalAudioDescriptionSource) {
|
|
8964
|
-
this.originalAudioDescriptionSource = origSrc;
|
|
8965
|
-
}
|
|
8966
|
-
if (!this.originalSrc) {
|
|
8967
|
-
this.originalSrc = origSrc;
|
|
8968
|
-
}
|
|
8969
|
-
} else {
|
|
8970
|
-
const currentSrcAttr = sourceEl.getAttribute("src");
|
|
8971
|
-
if (!this.originalAudioDescriptionSource && currentSrcAttr) {
|
|
8972
|
-
this.originalAudioDescriptionSource = currentSrcAttr;
|
|
8973
|
-
}
|
|
8974
|
-
if (!this.originalSrc && currentSrcAttr) {
|
|
8975
|
-
this.originalSrc = currentSrcAttr;
|
|
8976
|
-
}
|
|
8977
|
-
}
|
|
8978
|
-
if (descSrc && !this.audioDescriptionSrc) {
|
|
8979
|
-
this.audioDescriptionSrc = descSrc;
|
|
8980
|
-
}
|
|
8981
|
-
}
|
|
8982
|
-
}
|
|
8983
|
-
const trackElements = this.trackElements;
|
|
8984
|
-
trackElements.forEach((trackEl) => {
|
|
8985
|
-
const trackKind = trackEl.getAttribute("kind");
|
|
8986
|
-
const trackDescSrc = trackEl.getAttribute("data-desc-src");
|
|
8987
|
-
if (trackKind === "captions" || trackKind === "subtitles" || trackKind === "chapters") {
|
|
8988
|
-
if (trackDescSrc) {
|
|
8989
|
-
this.audioDescriptionCaptionTracks.push({
|
|
8990
|
-
trackElement: trackEl,
|
|
8991
|
-
originalSrc: trackEl.getAttribute("src"),
|
|
8992
|
-
describedSrc: trackDescSrc,
|
|
8993
|
-
originalTrackSrc: trackEl.getAttribute("data-orig-src") || trackEl.getAttribute("src"),
|
|
8994
|
-
explicit: true
|
|
8995
|
-
// Explicitly defined, so we should validate it
|
|
8996
|
-
});
|
|
8997
|
-
this.log("Found explicit described ".concat(trackKind, " track: ").concat(trackEl.getAttribute("src"), " -> ").concat(trackDescSrc));
|
|
8998
|
-
}
|
|
8999
|
-
}
|
|
9000
|
-
});
|
|
10521
|
+
this.audioDescriptionManager.initFromSourceElements(this.sourceElements, this.trackElements);
|
|
9001
10522
|
if (!this.originalSrc) {
|
|
9002
10523
|
this.originalSrc = src;
|
|
9003
10524
|
}
|
|
@@ -9242,6 +10763,9 @@
|
|
|
9242
10763
|
if (trackConfig.default) {
|
|
9243
10764
|
track.default = true;
|
|
9244
10765
|
}
|
|
10766
|
+
if (trackConfig.describedSrc) {
|
|
10767
|
+
track.setAttribute("data-desc-src", trackConfig.describedSrc);
|
|
10768
|
+
}
|
|
9245
10769
|
const firstChild = this.element.firstChild;
|
|
9246
10770
|
if (firstChild && firstChild.nodeType === Node.ELEMENT_NODE && firstChild.tagName !== "TRACK") {
|
|
9247
10771
|
this.element.insertBefore(track, firstChild);
|
|
@@ -9256,6 +10780,13 @@
|
|
|
9256
10780
|
this.audioDescriptionSrc = config.audioDescriptionSrc || null;
|
|
9257
10781
|
this.signLanguageSrc = config.signLanguageSrc || null;
|
|
9258
10782
|
this.originalSrc = config.src;
|
|
10783
|
+
if (this.audioDescriptionManager) {
|
|
10784
|
+
this.audioDescriptionManager.updateSources(config.audioDescriptionSrc);
|
|
10785
|
+
this.audioDescriptionManager.reinitialize();
|
|
10786
|
+
}
|
|
10787
|
+
if (this.signLanguageManager) {
|
|
10788
|
+
this.signLanguageManager.updateSources(config.signLanguageSrc, config.signLanguageSources);
|
|
10789
|
+
}
|
|
9259
10790
|
if (wasAudioDescriptionEnabled) {
|
|
9260
10791
|
this.disableAudioDescription();
|
|
9261
10792
|
}
|
|
@@ -9664,8 +11195,12 @@
|
|
|
9664
11195
|
}
|
|
9665
11196
|
return null;
|
|
9666
11197
|
}
|
|
9667
|
-
// Audio Description
|
|
11198
|
+
// Audio Description (delegated to AudioDescriptionManager)
|
|
9668
11199
|
async enableAudioDescription() {
|
|
11200
|
+
return this.audioDescriptionManager.enable();
|
|
11201
|
+
}
|
|
11202
|
+
// Legacy method body preserved for reference - can be removed after testing
|
|
11203
|
+
async _legacyEnableAudioDescription() {
|
|
9669
11204
|
const hasSourceElementsWithDesc = this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
9670
11205
|
const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;
|
|
9671
11206
|
if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {
|
|
@@ -10398,6 +11933,10 @@
|
|
|
10398
11933
|
this.emit("audiodescriptionenabled");
|
|
10399
11934
|
}
|
|
10400
11935
|
async disableAudioDescription() {
|
|
11936
|
+
return this.audioDescriptionManager.disable();
|
|
11937
|
+
}
|
|
11938
|
+
// Legacy method body preserved for reference - can be removed after testing
|
|
11939
|
+
async _legacyDisableAudioDescription() {
|
|
10401
11940
|
if (!this.originalSrc) {
|
|
10402
11941
|
return;
|
|
10403
11942
|
}
|
|
@@ -10672,64 +12211,14 @@
|
|
|
10672
12211
|
this.emit("audiodescriptiondisabled");
|
|
10673
12212
|
}
|
|
10674
12213
|
async toggleAudioDescription() {
|
|
10675
|
-
|
|
10676
|
-
const hasAudioDescriptionSrc = this.audioDescriptionSrc || this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
10677
|
-
if (descriptionTrack && hasAudioDescriptionSrc) {
|
|
10678
|
-
if (this.state.audioDescriptionEnabled) {
|
|
10679
|
-
this._audioDescriptionDesiredState = false;
|
|
10680
|
-
descriptionTrack.mode = "hidden";
|
|
10681
|
-
await this.disableAudioDescription();
|
|
10682
|
-
} else {
|
|
10683
|
-
this._audioDescriptionDesiredState = true;
|
|
10684
|
-
await this.enableAudioDescription();
|
|
10685
|
-
const enableDescriptionTrack = () => {
|
|
10686
|
-
this.invalidateTrackCache();
|
|
10687
|
-
const descTrack = this.findTextTrack("descriptions");
|
|
10688
|
-
if (descTrack) {
|
|
10689
|
-
if (descTrack.mode === "disabled") {
|
|
10690
|
-
descTrack.mode = "hidden";
|
|
10691
|
-
this.setManagedTimeout(() => {
|
|
10692
|
-
descTrack.mode = "showing";
|
|
10693
|
-
}, 50);
|
|
10694
|
-
} else {
|
|
10695
|
-
descTrack.mode = "showing";
|
|
10696
|
-
}
|
|
10697
|
-
} else if (this.element.readyState < 2) {
|
|
10698
|
-
this.setManagedTimeout(enableDescriptionTrack, 100);
|
|
10699
|
-
}
|
|
10700
|
-
};
|
|
10701
|
-
if (this.element.readyState >= 1) {
|
|
10702
|
-
this.setManagedTimeout(enableDescriptionTrack, 200);
|
|
10703
|
-
} else {
|
|
10704
|
-
this.element.addEventListener("loadedmetadata", () => {
|
|
10705
|
-
this.setManagedTimeout(enableDescriptionTrack, 200);
|
|
10706
|
-
}, { once: true });
|
|
10707
|
-
}
|
|
10708
|
-
}
|
|
10709
|
-
} else if (descriptionTrack) {
|
|
10710
|
-
if (descriptionTrack.mode === "showing") {
|
|
10711
|
-
this._audioDescriptionDesiredState = false;
|
|
10712
|
-
descriptionTrack.mode = "hidden";
|
|
10713
|
-
this.state.audioDescriptionEnabled = false;
|
|
10714
|
-
this.emit("audiodescriptiondisabled");
|
|
10715
|
-
} else {
|
|
10716
|
-
this._audioDescriptionDesiredState = true;
|
|
10717
|
-
descriptionTrack.mode = "showing";
|
|
10718
|
-
this.state.audioDescriptionEnabled = true;
|
|
10719
|
-
this.emit("audiodescriptionenabled");
|
|
10720
|
-
}
|
|
10721
|
-
} else if (hasAudioDescriptionSrc) {
|
|
10722
|
-
if (this.state.audioDescriptionEnabled) {
|
|
10723
|
-
this._audioDescriptionDesiredState = false;
|
|
10724
|
-
await this.disableAudioDescription();
|
|
10725
|
-
} else {
|
|
10726
|
-
this._audioDescriptionDesiredState = true;
|
|
10727
|
-
await this.enableAudioDescription();
|
|
10728
|
-
}
|
|
10729
|
-
}
|
|
12214
|
+
return this.audioDescriptionManager.toggle();
|
|
10730
12215
|
}
|
|
10731
|
-
// Sign Language
|
|
12216
|
+
// Sign Language (delegated to SignLanguageManager)
|
|
10732
12217
|
enableSignLanguage() {
|
|
12218
|
+
return this.signLanguageManager.enable();
|
|
12219
|
+
}
|
|
12220
|
+
// Legacy method body preserved for reference - can be removed after testing
|
|
12221
|
+
_legacyEnableSignLanguage() {
|
|
10733
12222
|
var _a;
|
|
10734
12223
|
const hasMultipleSources = Object.keys(this.signLanguageSources).length > 0;
|
|
10735
12224
|
const hasSingleSource = !!this.signLanguageSrc;
|
|
@@ -10982,23 +12471,16 @@
|
|
|
10982
12471
|
}, 150);
|
|
10983
12472
|
}
|
|
10984
12473
|
disableSignLanguage() {
|
|
10985
|
-
|
|
10986
|
-
this.hideSignLanguageSettingsMenu({ focusButton: false });
|
|
10987
|
-
}
|
|
10988
|
-
if (this.signLanguageWrapper) {
|
|
10989
|
-
this.signLanguageWrapper.style.display = "none";
|
|
10990
|
-
}
|
|
10991
|
-
this.state.signLanguageEnabled = false;
|
|
10992
|
-
this.emit("signlanguagedisabled");
|
|
12474
|
+
return this.signLanguageManager.disable();
|
|
10993
12475
|
}
|
|
10994
12476
|
toggleSignLanguage() {
|
|
10995
|
-
|
|
10996
|
-
this.disableSignLanguage();
|
|
10997
|
-
} else {
|
|
10998
|
-
this.enableSignLanguage();
|
|
10999
|
-
}
|
|
12477
|
+
return this.signLanguageManager.toggle();
|
|
11000
12478
|
}
|
|
11001
12479
|
setupSignLanguageInteraction() {
|
|
12480
|
+
return this.signLanguageManager._setupInteraction();
|
|
12481
|
+
}
|
|
12482
|
+
// Legacy method preserved for reference
|
|
12483
|
+
_legacySetupSignLanguageInteraction() {
|
|
11002
12484
|
if (!this.signLanguageWrapper) return;
|
|
11003
12485
|
const isMobile2 = window.innerWidth < 768;
|
|
11004
12486
|
const isFullscreen = this.state.fullscreen;
|
|
@@ -11136,6 +12618,10 @@
|
|
|
11136
12618
|
return langNames[langCode] || langCode.toUpperCase();
|
|
11137
12619
|
}
|
|
11138
12620
|
switchSignLanguage(langCode) {
|
|
12621
|
+
return this.signLanguageManager.switchLanguage(langCode);
|
|
12622
|
+
}
|
|
12623
|
+
// Legacy method preserved for reference
|
|
12624
|
+
_legacySwitchSignLanguage(langCode) {
|
|
11139
12625
|
if (!this.signLanguageSources[langCode] || !this.signLanguageVideo) {
|
|
11140
12626
|
return;
|
|
11141
12627
|
}
|
|
@@ -11151,6 +12637,10 @@
|
|
|
11151
12637
|
this.emit("signlanguagelanguagechanged", langCode);
|
|
11152
12638
|
}
|
|
11153
12639
|
showSignLanguageSettingsMenu() {
|
|
12640
|
+
return this.signLanguageManager.showSettingsMenu();
|
|
12641
|
+
}
|
|
12642
|
+
// Legacy method preserved for reference
|
|
12643
|
+
_legacyShowSignLanguageSettingsMenu() {
|
|
11154
12644
|
this.signLanguageSettingsMenuJustOpened = true;
|
|
11155
12645
|
setTimeout(() => {
|
|
11156
12646
|
this.signLanguageSettingsMenuJustOpened = false;
|
|
@@ -11294,25 +12784,7 @@
|
|
|
11294
12784
|
focusFirstMenuItem(this.signLanguageSettingsMenu, ".".concat(this.options.classPrefix, "-sign-language-settings-item"));
|
|
11295
12785
|
}
|
|
11296
12786
|
hideSignLanguageSettingsMenu({ focusButton = true } = {}) {
|
|
11297
|
-
|
|
11298
|
-
this.signLanguageSettingsMenu.style.display = "none";
|
|
11299
|
-
this.signLanguageSettingsMenuVisible = false;
|
|
11300
|
-
this.signLanguageSettingsMenuJustOpened = false;
|
|
11301
|
-
if (this.signLanguageSettingsMenuKeyHandler) {
|
|
11302
|
-
this.signLanguageSettingsMenu.removeEventListener("keydown", this.signLanguageSettingsMenuKeyHandler);
|
|
11303
|
-
this.signLanguageSettingsMenuKeyHandler = null;
|
|
11304
|
-
}
|
|
11305
|
-
const menuItems = Array.from(this.signLanguageSettingsMenu.querySelectorAll(".".concat(this.options.classPrefix, "-sign-language-settings-item")));
|
|
11306
|
-
menuItems.forEach((item) => {
|
|
11307
|
-
item.setAttribute("tabindex", "-1");
|
|
11308
|
-
});
|
|
11309
|
-
if (this.signLanguageSettingsButton) {
|
|
11310
|
-
this.signLanguageSettingsButton.setAttribute("aria-expanded", "false");
|
|
11311
|
-
if (focusButton) {
|
|
11312
|
-
this.signLanguageSettingsButton.focus({ preventScroll: true });
|
|
11313
|
-
}
|
|
11314
|
-
}
|
|
11315
|
-
}
|
|
12787
|
+
return this.signLanguageManager.hideSettingsMenu({ focusButton });
|
|
11316
12788
|
}
|
|
11317
12789
|
positionSignLanguageSettingsMenuImmediate() {
|
|
11318
12790
|
if (!this.signLanguageSettingsMenu || !this.signLanguageSettingsButton) return;
|
|
@@ -11416,6 +12888,13 @@
|
|
|
11416
12888
|
}
|
|
11417
12889
|
}
|
|
11418
12890
|
constrainSignLanguagePosition() {
|
|
12891
|
+
return this.signLanguageManager.constrainPosition();
|
|
12892
|
+
}
|
|
12893
|
+
saveSignLanguagePreferences() {
|
|
12894
|
+
return this.signLanguageManager.savePreferences();
|
|
12895
|
+
}
|
|
12896
|
+
// Legacy methods preserved for reference - can be removed after testing
|
|
12897
|
+
_legacyConstrainSignLanguagePosition() {
|
|
11419
12898
|
if (!this.signLanguageWrapper || !this.videoWrapper) return;
|
|
11420
12899
|
if (this.signLanguageDraggable && this.signLanguageDraggable.manuallyPositioned) {
|
|
11421
12900
|
return;
|
|
@@ -11465,7 +12944,7 @@
|
|
|
11465
12944
|
this.signLanguageWrapper.style.bottom = "auto";
|
|
11466
12945
|
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
11467
12946
|
}
|
|
11468
|
-
|
|
12947
|
+
_legacySaveSignLanguagePreferences() {
|
|
11469
12948
|
if (!this.signLanguageWrapper) return;
|
|
11470
12949
|
this.storage.saveSignLanguagePreferences({
|
|
11471
12950
|
size: {
|
|
@@ -11475,58 +12954,7 @@
|
|
|
11475
12954
|
});
|
|
11476
12955
|
}
|
|
11477
12956
|
cleanupSignLanguage() {
|
|
11478
|
-
|
|
11479
|
-
this.hideSignLanguageSettingsMenu({ focusButton: false });
|
|
11480
|
-
}
|
|
11481
|
-
if (this.signLanguageDocumentClickHandler && this.signLanguageDocumentClickHandlerAdded) {
|
|
11482
|
-
document.removeEventListener("mousedown", this.signLanguageDocumentClickHandler, true);
|
|
11483
|
-
this.signLanguageDocumentClickHandlerAdded = false;
|
|
11484
|
-
this.signLanguageDocumentClickHandler = null;
|
|
11485
|
-
}
|
|
11486
|
-
if (this.signLanguageSettingsHandlers) {
|
|
11487
|
-
if (this.signLanguageSettingsButton) {
|
|
11488
|
-
this.signLanguageSettingsButton.removeEventListener("click", this.signLanguageSettingsHandlers.settingsClick);
|
|
11489
|
-
this.signLanguageSettingsButton.removeEventListener("keydown", this.signLanguageSettingsHandlers.settingsKeydown);
|
|
11490
|
-
}
|
|
11491
|
-
this.signLanguageSettingsHandlers = null;
|
|
11492
|
-
}
|
|
11493
|
-
if (this.signLanguageHandlers) {
|
|
11494
|
-
this.off("play", this.signLanguageHandlers.play);
|
|
11495
|
-
this.off("pause", this.signLanguageHandlers.pause);
|
|
11496
|
-
this.off("timeupdate", this.signLanguageHandlers.timeupdate);
|
|
11497
|
-
this.off("ratechange", this.signLanguageHandlers.ratechange);
|
|
11498
|
-
if (this.signLanguageHandlers.captionChange) {
|
|
11499
|
-
this.off("captionsenabled", this.signLanguageHandlers.captionChange);
|
|
11500
|
-
}
|
|
11501
|
-
this.signLanguageHandlers = null;
|
|
11502
|
-
}
|
|
11503
|
-
if (this.signLanguageInteractionHandlers) {
|
|
11504
|
-
if (this.signLanguageHeader && this.signLanguageInteractionHandlers.headerKeyHandler) {
|
|
11505
|
-
this.signLanguageHeader.removeEventListener("keydown", this.signLanguageInteractionHandlers.headerKeyHandler);
|
|
11506
|
-
}
|
|
11507
|
-
if (this.signLanguageWrapper && this.signLanguageInteractionHandlers.customKeyHandler) {
|
|
11508
|
-
this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.customKeyHandler);
|
|
11509
|
-
}
|
|
11510
|
-
}
|
|
11511
|
-
if (this.signLanguageDraggable) {
|
|
11512
|
-
if (this.signLanguageDraggable.pointerResizeMode) {
|
|
11513
|
-
this.signLanguageDraggable.disablePointerResizeMode();
|
|
11514
|
-
}
|
|
11515
|
-
this.signLanguageDraggable.destroy();
|
|
11516
|
-
this.signLanguageDraggable = null;
|
|
11517
|
-
}
|
|
11518
|
-
this.signLanguageInteractionHandlers = null;
|
|
11519
|
-
if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
|
|
11520
|
-
if (this.signLanguageVideo) {
|
|
11521
|
-
this.signLanguageVideo.pause();
|
|
11522
|
-
this.signLanguageVideo.src = "";
|
|
11523
|
-
}
|
|
11524
|
-
this.signLanguageWrapper.parentNode.removeChild(this.signLanguageWrapper);
|
|
11525
|
-
}
|
|
11526
|
-
this.signLanguageWrapper = null;
|
|
11527
|
-
this.signLanguageVideo = null;
|
|
11528
|
-
this.signLanguageSettingsButton = null;
|
|
11529
|
-
this.signLanguageSettingsMenu = null;
|
|
12957
|
+
return this.signLanguageManager.cleanup();
|
|
11530
12958
|
}
|
|
11531
12959
|
// Settings
|
|
11532
12960
|
// Settings dialog removed - using individual control buttons instead
|