vidply 1.1.18 → 1.2.0
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/README.md +15 -8
- package/dist/dev/{vidply.AudioDescriptionManager-GJO454ID.js → vidply.AudioDescriptionManager-R47Q4YR4.js} +12 -10
- package/dist/dev/vidply.AudioDescriptionManager-R47Q4YR4.js.map +7 -0
- package/dist/dev/vidply.CaptionStyleMenu-7XHRBWUM.js +300 -0
- package/dist/dev/vidply.CaptionStyleMenu-7XHRBWUM.js.map +7 -0
- package/dist/dev/{vidply.DASHRenderer-CAIEEBIY.js → vidply.DASHRenderer-PWEMC3BT.js} +42 -35
- package/dist/dev/vidply.DASHRenderer-PWEMC3BT.js.map +7 -0
- package/dist/dev/{vidply.FloatingPlayerManager-V4UV3DSB.js → vidply.FloatingPlayerManager-PKNNNAS2.js} +10 -5
- package/dist/dev/{vidply.FloatingPlayerManager-V4UV3DSB.js.map → vidply.FloatingPlayerManager-PKNNNAS2.js.map} +2 -2
- package/dist/dev/{vidply.HLSRenderer-KQLJ6EEO.js → vidply.HLSRenderer-E7RQ74HI.js} +81 -46
- package/dist/dev/vidply.HLSRenderer-E7RQ74HI.js.map +7 -0
- package/dist/dev/vidply.HTML5Renderer-BU4QJJJY.js +12 -0
- package/dist/dev/{vidply.SignLanguageManager-3YJHYEJS.js → vidply.SignLanguageManager-FET5FQZ7.js} +14 -13
- package/dist/dev/vidply.SignLanguageManager-FET5FQZ7.js.map +7 -0
- package/dist/dev/{vidply.SoundCloudRenderer-SAJ6RQNB.js → vidply.SoundCloudRenderer-RVSJZODO.js} +30 -18
- package/dist/dev/vidply.SoundCloudRenderer-RVSJZODO.js.map +7 -0
- package/dist/dev/{vidply.TranscriptManager-KRLWUIL5.js → vidply.TranscriptManager-5GXOQCLX.js} +24 -21
- package/dist/dev/vidply.TranscriptManager-5GXOQCLX.js.map +7 -0
- package/dist/dev/{vidply.VimeoRenderer-H425TIXI.js → vidply.VimeoRenderer-ER2LSBBW.js} +8 -9
- package/dist/dev/vidply.VimeoRenderer-ER2LSBBW.js.map +7 -0
- package/dist/dev/{vidply.YouTubeRenderer-RJFSC7DO.js → vidply.YouTubeRenderer-NFTOWJAB.js} +10 -25
- package/dist/dev/vidply.YouTubeRenderer-NFTOWJAB.js.map +7 -0
- package/dist/dev/{vidply.chunk-I3Y5BLC6.js → vidply.chunk-64WXMTGL.js} +15 -48
- package/dist/dev/vidply.chunk-64WXMTGL.js.map +7 -0
- package/dist/dev/vidply.chunk-6RQA4ROD.js +57 -0
- package/dist/dev/vidply.chunk-6RQA4ROD.js.map +7 -0
- package/dist/dev/{vidply.chunk-ZR5JQPCM.js → vidply.chunk-BNFIUL2Z.js} +7 -4
- package/dist/dev/{vidply.chunk-ZR5JQPCM.js.map → vidply.chunk-BNFIUL2Z.js.map} +2 -2
- package/dist/dev/vidply.chunk-DZSDO3B7.js +87 -0
- package/dist/dev/vidply.chunk-DZSDO3B7.js.map +7 -0
- package/dist/dev/{vidply.chunk-DEVK3LVC.js → vidply.chunk-JJ47NO24.js} +5 -2
- package/dist/dev/vidply.chunk-JJ47NO24.js.map +7 -0
- package/dist/dev/{vidply.chunk-KGJQUMTY.js → vidply.chunk-KI7C3QVL.js} +2 -2
- package/dist/dev/{vidply.chunk-KGJQUMTY.js.map → vidply.chunk-KI7C3QVL.js.map} +1 -1
- package/dist/dev/{vidply.chunk-BQ3SUKRY.js → vidply.chunk-NQPURMQY.js} +35 -19
- package/dist/dev/vidply.chunk-NQPURMQY.js.map +7 -0
- package/dist/dev/{vidply.chunk-QGWFSJ7R.js → vidply.chunk-RZWZGDV7.js} +10 -9
- package/dist/dev/vidply.chunk-RZWZGDV7.js.map +7 -0
- package/dist/dev/{vidply.chunk-4VFODBFZ.js → vidply.chunk-SK4V2DAU.js} +6 -6
- package/dist/dev/vidply.chunk-SK4V2DAU.js.map +7 -0
- package/dist/dev/{vidply.chunk-PROLQGB6.js → vidply.chunk-VMSQAZM7.js} +2 -2
- package/dist/dev/{vidply.chunk-ZFY7FNCU.js → vidply.chunk-W25HUCHS.js} +28 -24
- package/dist/dev/vidply.chunk-W25HUCHS.js.map +7 -0
- package/dist/dev/{vidply.de-NCS32MR5.js → vidply.de-4YAT7FFM.js} +2 -2
- package/dist/dev/{vidply.es-KTLE6NCH.js → vidply.es-LEWIRUBH.js} +2 -2
- package/dist/dev/vidply.esm.js +216 -376
- package/dist/dev/vidply.esm.js.map +2 -2
- package/dist/dev/{vidply.fr-7CEEBQ77.js → vidply.fr-Q4GV2NOE.js} +2 -2
- package/dist/dev/{vidply.ja-5UIYTCX7.js → vidply.ja-S6ITA6WU.js} +2 -2
- package/dist/legacy/vidply.js +845 -538
- package/dist/legacy/vidply.js.map +4 -4
- package/dist/legacy/vidply.min.js +2 -2
- package/dist/legacy/vidply.min.meta.json +134 -52
- package/dist/prod/vidply.AudioDescriptionManager-RHLIJW5C.min.js +6 -0
- package/dist/prod/vidply.CaptionStyleMenu-M3KVQWB5.min.js +6 -0
- package/dist/prod/vidply.DASHRenderer-DN3S27AV.min.js +6 -0
- package/dist/prod/{vidply.FloatingPlayerManager-RRMX5WBA.min.js → vidply.FloatingPlayerManager-SKAZ4J43.min.js} +2 -2
- package/dist/prod/vidply.HLSRenderer-62HH4YTK.min.js +6 -0
- package/dist/prod/vidply.HTML5Renderer-IU5T3WEW.min.js +6 -0
- package/dist/prod/vidply.SignLanguageManager-V3OBTSSF.min.js +6 -0
- package/dist/prod/vidply.SoundCloudRenderer-CXRVZIAJ.min.js +6 -0
- package/dist/prod/vidply.TranscriptManager-SYM3DFUY.min.js +6 -0
- package/dist/prod/vidply.VimeoRenderer-72TWRYFQ.min.js +6 -0
- package/dist/prod/vidply.YouTubeRenderer-UMHEV3KD.min.js +6 -0
- package/dist/prod/vidply.chunk-2TB6MUHO.min.js +6 -0
- package/dist/prod/{vidply.chunk-TKTTOLX5.min.js → vidply.chunk-ABPXVDLZ.min.js} +1 -1
- package/dist/prod/vidply.chunk-EKEYJWMG.min.js +6 -0
- package/dist/prod/{vidply.chunk-AHEIUUN3.min.js → vidply.chunk-P3PQBY7N.min.js} +1 -1
- package/dist/prod/vidply.chunk-P4UXOHWA.min.js +6 -0
- package/dist/prod/{vidply.chunk-J45YW6UC.min.js → vidply.chunk-RI3X7WHK.min.js} +2 -2
- package/dist/prod/vidply.chunk-TM6AXJVD.min.js +6 -0
- package/dist/prod/vidply.chunk-UK7YGOB5.min.js +6 -0
- package/dist/prod/vidply.chunk-WX3MVEAL.min.js +6 -0
- package/dist/prod/vidply.chunk-YEENJS3Q.min.js +6 -0
- package/dist/prod/vidply.chunk-Z3YDSA7O.min.js +6 -0
- package/dist/prod/{vidply.de-NVBWZKXD.min.js → vidply.de-BCHXRQ53.min.js} +1 -1
- package/dist/prod/{vidply.es-EVA5ETFV.min.js → vidply.es-PICAKMZD.min.js} +1 -1
- package/dist/prod/vidply.esm.min.js +2 -2
- package/dist/prod/{vidply.fr-2BFHYAIB.min.js → vidply.fr-ZILI7CDR.min.js} +1 -1
- package/dist/prod/{vidply.ja-KLEUHUWZ.min.js → vidply.ja-5WQ4OK4J.min.js} +1 -1
- package/dist/vidply.css +148 -244
- package/dist/vidply.esm.min.meta.json +414 -238
- package/dist/vidply.min.css +1 -1
- package/package.json +10 -7
- package/src/controls/CaptionManager.ts +11 -4
- package/src/controls/CaptionStyleMenu.ts +370 -0
- package/src/controls/ControlBar.ts +93 -403
- package/src/controls/KeyboardManager.ts +78 -2
- package/src/controls/SettingsDialog.ts +32 -2
- package/src/controls/TranscriptManager.ts +12 -10
- package/src/core/AudioDescriptionManager.ts +8 -6
- package/src/core/FloatingPlayerManager.ts +11 -0
- package/src/core/MetadataAlertsManager.ts +2 -1
- package/src/core/Player.ts +32 -11
- package/src/core/PseudoFullscreen.ts +4 -2
- package/src/core/SignLanguageManager.ts +9 -7
- package/src/features/PlaylistManager.ts +41 -26
- package/src/icons/Icons.ts +1 -1
- package/src/index.ts +1 -1
- package/src/renderers/DASHRenderer.ts +42 -33
- package/src/renderers/HLSRenderer.ts +100 -54
- package/src/renderers/HTML5Renderer.ts +28 -21
- package/src/renderers/SoundCloudRenderer.ts +33 -18
- package/src/renderers/VimeoRenderer.ts +7 -7
- package/src/renderers/YouTubeRenderer.ts +14 -29
- package/src/styles/vidply.css +148 -244
- package/src/types/globals.d.ts +36 -2
- package/src/types/renderer.ts +0 -5
- package/src/utils/DOMUtils.ts +4 -3
- package/src/utils/DownloadInfo.ts +2 -2
- package/src/utils/DraggableResizable.ts +4 -1
- package/src/utils/MenuFactory.ts +36 -14
- package/src/utils/MenuUtils.ts +31 -13
- package/src/utils/PerformanceUtils.ts +23 -0
- package/src/utils/ScriptLoader.ts +137 -0
- package/src/utils/SettingsMenuFactory.ts +21 -8
- package/src/utils/StorageManager.ts +4 -1
- package/src/utils/TimeUtils.ts +3 -3
- package/dist/dev/vidply.AudioDescriptionManager-GJO454ID.js.map +0 -7
- package/dist/dev/vidply.DASHRenderer-CAIEEBIY.js.map +0 -7
- package/dist/dev/vidply.HLSRenderer-KQLJ6EEO.js.map +0 -7
- package/dist/dev/vidply.HTML5Renderer-TZTNNAQK.js +0 -12
- package/dist/dev/vidply.SignLanguageManager-3YJHYEJS.js.map +0 -7
- package/dist/dev/vidply.SoundCloudRenderer-SAJ6RQNB.js.map +0 -7
- package/dist/dev/vidply.TranscriptManager-KRLWUIL5.js.map +0 -7
- package/dist/dev/vidply.VimeoRenderer-H425TIXI.js.map +0 -7
- package/dist/dev/vidply.YouTubeRenderer-RJFSC7DO.js.map +0 -7
- package/dist/dev/vidply.chunk-4VFODBFZ.js.map +0 -7
- package/dist/dev/vidply.chunk-BQ3SUKRY.js.map +0 -7
- package/dist/dev/vidply.chunk-DEVK3LVC.js.map +0 -7
- package/dist/dev/vidply.chunk-I3Y5BLC6.js.map +0 -7
- package/dist/dev/vidply.chunk-QGWFSJ7R.js.map +0 -7
- package/dist/dev/vidply.chunk-ZFY7FNCU.js.map +0 -7
- package/dist/prod/vidply.AudioDescriptionManager-BHLFV4AX.min.js +0 -6
- package/dist/prod/vidply.DASHRenderer-EU76KE2D.min.js +0 -6
- package/dist/prod/vidply.HLSRenderer-2KUQ6CXF.min.js +0 -6
- package/dist/prod/vidply.HTML5Renderer-6MT7K3S3.min.js +0 -6
- package/dist/prod/vidply.SignLanguageManager-45XEBRUO.min.js +0 -6
- package/dist/prod/vidply.SoundCloudRenderer-UTH6RXEP.min.js +0 -6
- package/dist/prod/vidply.TranscriptManager-JEWHNZRE.min.js +0 -6
- package/dist/prod/vidply.VimeoRenderer-46FRK7KO.min.js +0 -6
- package/dist/prod/vidply.YouTubeRenderer-AB7Q7ZX3.min.js +0 -6
- package/dist/prod/vidply.chunk-3Y7DZFWE.min.js +0 -6
- package/dist/prod/vidply.chunk-CIOBWWPJ.min.js +0 -6
- package/dist/prod/vidply.chunk-H7OZCZSW.min.js +0 -6
- package/dist/prod/vidply.chunk-S7UXDVRO.min.js +0 -6
- package/dist/prod/vidply.chunk-T3GGXROP.min.js +0 -6
- package/dist/prod/vidply.chunk-YXAFRFSQ.min.js +0 -6
- /package/dist/dev/{vidply.HTML5Renderer-TZTNNAQK.js.map → vidply.HTML5Renderer-BU4QJJJY.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-PROLQGB6.js.map → vidply.chunk-VMSQAZM7.js.map} +0 -0
- /package/dist/dev/{vidply.de-NCS32MR5.js.map → vidply.de-4YAT7FFM.js.map} +0 -0
- /package/dist/dev/{vidply.es-KTLE6NCH.js.map → vidply.es-LEWIRUBH.js.map} +0 -0
- /package/dist/dev/{vidply.fr-7CEEBQ77.js.map → vidply.fr-Q4GV2NOE.js.map} +0 -0
- /package/dist/dev/{vidply.ja-5UIYTCX7.js.map → vidply.ja-S6ITA6WU.js.map} +0 -0
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* VidPly v1.
|
|
2
|
+
* VidPly v1.2.0 - Universal, Accessible Video Player
|
|
3
3
|
* (c) 2026 Matthias Peltzer
|
|
4
4
|
* Released under GPL-2.0-or-later License
|
|
5
5
|
*/
|
|
6
|
+
import {
|
|
7
|
+
loadScriptOnce
|
|
8
|
+
} from "./vidply.chunk-DZSDO3B7.js";
|
|
6
9
|
|
|
7
10
|
// src/renderers/DASHRenderer.ts
|
|
8
11
|
var DASHRenderer = class {
|
|
@@ -22,6 +25,11 @@ var DASHRenderer = class {
|
|
|
22
25
|
_pendingTimeouts;
|
|
23
26
|
_ttmlDiv;
|
|
24
27
|
_manifestUrl;
|
|
28
|
+
// Detaches all media listeners (attachMediaEvents) in destroy().
|
|
29
|
+
_listenerController;
|
|
30
|
+
// Deferred 'ready' handler from updateCaptionButtonsForStreaming, removed on
|
|
31
|
+
// destroy if it never fired.
|
|
32
|
+
_pendingReadyHandler;
|
|
25
33
|
constructor(player) {
|
|
26
34
|
this.player = player;
|
|
27
35
|
this.media = player.element;
|
|
@@ -38,6 +46,8 @@ var DASHRenderer = class {
|
|
|
38
46
|
this._pendingTimeouts = [];
|
|
39
47
|
this._ttmlDiv = null;
|
|
40
48
|
this._manifestUrl = null;
|
|
49
|
+
this._listenerController = new AbortController();
|
|
50
|
+
this._pendingReadyHandler = null;
|
|
41
51
|
}
|
|
42
52
|
async init() {
|
|
43
53
|
this.player.log("Using dash.js for DASH support");
|
|
@@ -52,7 +62,7 @@ var DASHRenderer = class {
|
|
|
52
62
|
const sourceElements = Array.from(this.media.querySelectorAll("source"));
|
|
53
63
|
let originalSrc = null;
|
|
54
64
|
if (sourceElements.length > 0) {
|
|
55
|
-
originalSrc = sourceElements[0]
|
|
65
|
+
originalSrc = sourceElements[0]?.getAttribute("src") ?? null;
|
|
56
66
|
sourceElements.forEach((source) => source.remove());
|
|
57
67
|
this.player.log("Removed <source> elements for HTML5 validity (dash.js uses MSE)");
|
|
58
68
|
}
|
|
@@ -77,7 +87,7 @@ var DASHRenderer = class {
|
|
|
77
87
|
// NOTE on pre-play preload: we deliberately do NOT set
|
|
78
88
|
// streaming.scheduling.scheduleWhilePaused = false here. While that
|
|
79
89
|
// is the documented dash.js way to suppress segment downloads while
|
|
80
|
-
// paused / before the first play, in our setup (dash.js 5.
|
|
90
|
+
// paused / before the first play, in our setup (dash.js 5.2.0 +
|
|
81
91
|
// dash.initialize(media, null, false) + attachSource at init) it
|
|
82
92
|
// tears down the SourceBuffers mid-init with
|
|
83
93
|
// "SourceBuffer has been removed from the parent media source"
|
|
@@ -159,26 +169,15 @@ var DASHRenderer = class {
|
|
|
159
169
|
}
|
|
160
170
|
/**
|
|
161
171
|
* Load dash.js. Pinned to an exact version (the previous default
|
|
162
|
-
* `5.
|
|
172
|
+
* `5.2.0` is preserved) and overridable via `options.dashScriptUrl`
|
|
163
173
|
* (URL) / `options.dashScriptIntegrity` (SRI hash). See
|
|
164
174
|
* HLSRenderer.loadHlsJs() for the SRI computation command.
|
|
165
175
|
*/
|
|
166
176
|
async loadDashJs() {
|
|
167
|
-
const defaultUrl = "https://cdn.jsdelivr.net/npm/dashjs@5.
|
|
177
|
+
const defaultUrl = "https://cdn.jsdelivr.net/npm/dashjs@5.2.0/dist/modern/umd/dash.all.min.js";
|
|
168
178
|
const url = this.player.options.dashScriptUrl || defaultUrl;
|
|
169
179
|
const integrity = this.player.options.dashScriptIntegrity;
|
|
170
|
-
return
|
|
171
|
-
const script = document.createElement("script");
|
|
172
|
-
script.src = url;
|
|
173
|
-
if (integrity) {
|
|
174
|
-
script.integrity = integrity;
|
|
175
|
-
script.crossOrigin = "anonymous";
|
|
176
|
-
script.referrerPolicy = "no-referrer";
|
|
177
|
-
}
|
|
178
|
-
script.onload = () => resolve();
|
|
179
|
-
script.onerror = () => reject(new Error("Failed to load dash.js"));
|
|
180
|
-
document.head.appendChild(script);
|
|
181
|
-
});
|
|
180
|
+
return loadScriptOnce(url, { integrity });
|
|
182
181
|
}
|
|
183
182
|
_setTimeout(fn, delay) {
|
|
184
183
|
const id = setTimeout(() => {
|
|
@@ -269,7 +268,7 @@ var DASHRenderer = class {
|
|
|
269
268
|
if (!textTracks) return total;
|
|
270
269
|
for (let i = 0; i < textTracks.length; i++) {
|
|
271
270
|
const track = textTracks[i];
|
|
272
|
-
if ((track.kind === "subtitles" || track.kind === "captions") && !track._vidplyStale && track.cues) {
|
|
271
|
+
if (track && (track.kind === "subtitles" || track.kind === "captions") && !track._vidplyStale && track.cues) {
|
|
273
272
|
total += track.cues.length;
|
|
274
273
|
}
|
|
275
274
|
}
|
|
@@ -386,7 +385,7 @@ var DASHRenderer = class {
|
|
|
386
385
|
let count = 0;
|
|
387
386
|
for (let i = 0; i < tracks.length; i++) {
|
|
388
387
|
const track = tracks[i];
|
|
389
|
-
if ((track.kind === "subtitles" || track.kind === "captions") && !track._vidplyStale) {
|
|
388
|
+
if (track && (track.kind === "subtitles" || track.kind === "captions") && !track._vidplyStale) {
|
|
390
389
|
count++;
|
|
391
390
|
}
|
|
392
391
|
}
|
|
@@ -438,22 +437,25 @@ var DASHRenderer = class {
|
|
|
438
437
|
}
|
|
439
438
|
const onReady = () => {
|
|
440
439
|
this.player.off("ready", onReady);
|
|
440
|
+
this._pendingReadyHandler = null;
|
|
441
441
|
doUpdate();
|
|
442
442
|
};
|
|
443
|
+
this._pendingReadyHandler = onReady;
|
|
443
444
|
this.player.on("ready", onReady);
|
|
444
445
|
}
|
|
445
446
|
attachMediaEvents() {
|
|
447
|
+
const { signal } = this._listenerController;
|
|
446
448
|
this.media.addEventListener("loadedmetadata", () => {
|
|
447
449
|
this.player.state.duration = this.media.duration;
|
|
448
450
|
this.player.emit("loadedmetadata");
|
|
449
|
-
});
|
|
451
|
+
}, { signal });
|
|
450
452
|
this.media.addEventListener("durationchange", () => {
|
|
451
453
|
const duration = this.media.duration;
|
|
452
454
|
if (duration && isFinite(duration) && duration > 0) {
|
|
453
455
|
this.player.state.duration = duration;
|
|
454
456
|
this.player.emit("durationchange", duration);
|
|
455
457
|
}
|
|
456
|
-
});
|
|
458
|
+
}, { signal });
|
|
457
459
|
this.media.addEventListener("play", () => {
|
|
458
460
|
this.player.state.playing = true;
|
|
459
461
|
this.player.state.paused = false;
|
|
@@ -462,7 +464,7 @@ var DASHRenderer = class {
|
|
|
462
464
|
if (this.player.options.onPlay) {
|
|
463
465
|
this.player.options.onPlay.call(this.player);
|
|
464
466
|
}
|
|
465
|
-
});
|
|
467
|
+
}, { signal });
|
|
466
468
|
this.media.addEventListener("pause", () => {
|
|
467
469
|
this.player.state.playing = false;
|
|
468
470
|
this.player.state.paused = true;
|
|
@@ -470,7 +472,7 @@ var DASHRenderer = class {
|
|
|
470
472
|
if (this.player.options.onPause) {
|
|
471
473
|
this.player.options.onPause.call(this.player);
|
|
472
474
|
}
|
|
473
|
-
});
|
|
475
|
+
}, { signal });
|
|
474
476
|
this.media.addEventListener("ended", () => {
|
|
475
477
|
this.player.state.playing = false;
|
|
476
478
|
this.player.state.paused = true;
|
|
@@ -483,19 +485,19 @@ var DASHRenderer = class {
|
|
|
483
485
|
this.player.seek(0);
|
|
484
486
|
this.player.play();
|
|
485
487
|
}
|
|
486
|
-
});
|
|
488
|
+
}, { signal });
|
|
487
489
|
this.media.addEventListener("timeupdate", () => {
|
|
488
490
|
this.player.state.currentTime = this.media.currentTime;
|
|
489
491
|
this.player.emit("timeupdate", this.media.currentTime);
|
|
490
492
|
if (this.player.options.onTimeUpdate) {
|
|
491
493
|
this.player.options.onTimeUpdate.call(this.player, this.media.currentTime);
|
|
492
494
|
}
|
|
493
|
-
});
|
|
495
|
+
}, { signal });
|
|
494
496
|
this.media.addEventListener("volumechange", () => {
|
|
495
497
|
this.player.state.volume = this.media.volume;
|
|
496
498
|
this.player.state.muted = this.media.muted;
|
|
497
499
|
this.player.emit("volumechange", this.media.volume);
|
|
498
|
-
});
|
|
500
|
+
}, { signal });
|
|
499
501
|
this.media.addEventListener("seeking", () => {
|
|
500
502
|
this.player.state.seeking = true;
|
|
501
503
|
this.player.emit("seeking");
|
|
@@ -503,22 +505,22 @@ var DASHRenderer = class {
|
|
|
503
505
|
this.player.state.buffering = true;
|
|
504
506
|
this.player.emit("waiting");
|
|
505
507
|
}
|
|
506
|
-
});
|
|
508
|
+
}, { signal });
|
|
507
509
|
this.media.addEventListener("seeked", () => {
|
|
508
510
|
this.player.state.seeking = false;
|
|
509
511
|
this.player.emit("seeked");
|
|
510
|
-
});
|
|
512
|
+
}, { signal });
|
|
511
513
|
this.media.addEventListener("waiting", () => {
|
|
512
514
|
this.player.state.buffering = true;
|
|
513
515
|
this.player.emit("waiting");
|
|
514
|
-
});
|
|
516
|
+
}, { signal });
|
|
515
517
|
this.media.addEventListener("canplay", () => {
|
|
516
518
|
this.player.state.buffering = false;
|
|
517
519
|
this.player.emit("canplay");
|
|
518
|
-
});
|
|
520
|
+
}, { signal });
|
|
519
521
|
this.media.addEventListener("error", () => {
|
|
520
522
|
this.player.handleError(this.media.error);
|
|
521
|
-
});
|
|
523
|
+
}, { signal });
|
|
522
524
|
}
|
|
523
525
|
handleDashError(e) {
|
|
524
526
|
const wrapped = e;
|
|
@@ -633,7 +635,7 @@ var DASHRenderer = class {
|
|
|
633
635
|
const bitrate = Number(rep.bandwidth || rep.bitrate) || 0;
|
|
634
636
|
const kb = bitrate > 0 ? Math.round(bitrate / 1e3) : 0;
|
|
635
637
|
let name;
|
|
636
|
-
if (height > 0 && heightCounts2[height] > 1 && kb > 0) {
|
|
638
|
+
if (height > 0 && (heightCounts2[height] ?? 0) > 1 && kb > 0) {
|
|
637
639
|
name = `${height}p (${kb} kbps)`;
|
|
638
640
|
} else if (height > 0) {
|
|
639
641
|
name = `${height}p`;
|
|
@@ -662,7 +664,7 @@ var DASHRenderer = class {
|
|
|
662
664
|
const bitrate = Number(info.bitrate) || 0;
|
|
663
665
|
const kb = bitrate > 0 ? Math.round(bitrate / 1e3) : 0;
|
|
664
666
|
let name;
|
|
665
|
-
if (height > 0 && heightCounts[height] > 1 && kb > 0) {
|
|
667
|
+
if (height > 0 && (heightCounts[height] ?? 0) > 1 && kb > 0) {
|
|
666
668
|
name = `${height}p (${kb} kbps)`;
|
|
667
669
|
} else if (height > 0) {
|
|
668
670
|
name = `${height}p`;
|
|
@@ -815,6 +817,11 @@ var DASHRenderer = class {
|
|
|
815
817
|
this._pendingTimeouts = [];
|
|
816
818
|
this._stopCueUpdatePolling();
|
|
817
819
|
this._lastKnownCueCount = 0;
|
|
820
|
+
this._listenerController.abort();
|
|
821
|
+
if (this._pendingReadyHandler) {
|
|
822
|
+
this.player.off("ready", this._pendingReadyHandler);
|
|
823
|
+
this._pendingReadyHandler = null;
|
|
824
|
+
}
|
|
818
825
|
if (this._captionEnabledHandler) {
|
|
819
826
|
this.player.off("captionsenabled", this._captionEnabledHandler);
|
|
820
827
|
this._captionEnabledHandler = null;
|
|
@@ -830,7 +837,7 @@ var DASHRenderer = class {
|
|
|
830
837
|
const textTracks = this.media.textTracks;
|
|
831
838
|
for (let i = 0; i < textTracks.length; i++) {
|
|
832
839
|
const track = textTracks[i];
|
|
833
|
-
if (track.kind === "subtitles" || track.kind === "captions") {
|
|
840
|
+
if (track && (track.kind === "subtitles" || track.kind === "captions")) {
|
|
834
841
|
track._vidplyStale = true;
|
|
835
842
|
track.mode = "disabled";
|
|
836
843
|
}
|
|
@@ -855,4 +862,4 @@ var DASHRenderer = class {
|
|
|
855
862
|
export {
|
|
856
863
|
DASHRenderer
|
|
857
864
|
};
|
|
858
|
-
//# sourceMappingURL=vidply.DASHRenderer-
|
|
865
|
+
//# sourceMappingURL=vidply.DASHRenderer-PWEMC3BT.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/renderers/DASHRenderer.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Renderer } from '../types/renderer.js';\r\nimport type { Player } from '../core/Player.js';\r\nimport { loadScriptOnce } from '../utils/ScriptLoader.js';\r\n\r\ninterface DashTextTrack {\r\n lang?: string;\r\n language?: string;\r\n srclang?: string;\r\n kind?: string;\r\n label?: string;\r\n labels?: string;\r\n isTTML?: boolean;\r\n codec?: string;\r\n mimeType?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * Shape of payloads emitted by VidPly's `captionsenabled` event when\r\n * routed into a DASH renderer. These come from CaptionManager and carry\r\n * both the language and the underlying TextTrack reference.\r\n */\r\ninterface CaptionTrackSelection {\r\n language?: string;\r\n label?: string;\r\n track?: TextTrack;\r\n}\r\n\r\ntype CaptionEnabledHandler = (track: CaptionTrackSelection) => void;\r\ntype CaptionDisabledHandler = () => void;\r\n\r\nexport class DASHRenderer implements Renderer {\r\n player: Player;\r\n media: HTMLMediaElement;\r\n dash: DashMediaPlayerInstance | null;\r\n readonly isStreaming = true;\r\n _dashSourceLoaded: boolean;\r\n _pendingSrc: string | null;\r\n _dashSubtitleTracksCount: number | undefined;\r\n _dashTextTracks: DashTextTrack[];\r\n _cueUpdateTimer: ReturnType<typeof setInterval> | null;\r\n _captionEnabledHandler: CaptionEnabledHandler | null;\r\n _captionDisabledHandler: CaptionDisabledHandler | null;\r\n _lastKnownCueCount: number;\r\n _dashTextIsTtml: boolean;\r\n _pendingTimeouts: ReturnType<typeof setTimeout>[];\r\n _ttmlDiv: HTMLElement | null;\r\n _manifestUrl: string | null;\r\n // Detaches all media listeners (attachMediaEvents) in destroy().\r\n private _listenerController: AbortController;\r\n // Deferred 'ready' handler from updateCaptionButtonsForStreaming, removed on\r\n // destroy if it never fired.\r\n private _pendingReadyHandler: (() => void) | null;\r\n\r\n constructor(player: Player) {\r\n this.player = player;\r\n this.media = player.element;\r\n this.dash = null;\r\n this._dashSourceLoaded = false;\r\n this._pendingSrc = null;\r\n this._dashSubtitleTracksCount = undefined;\r\n this._dashTextTracks = [];\r\n this._cueUpdateTimer = null;\r\n this._captionEnabledHandler = null;\r\n this._captionDisabledHandler = null;\r\n this._lastKnownCueCount = 0;\r\n this._dashTextIsTtml = false;\r\n this._pendingTimeouts = [];\r\n this._ttmlDiv = null;\r\n this._manifestUrl = null;\r\n this._listenerController = new AbortController();\r\n this._pendingReadyHandler = null;\r\n }\r\n\r\n async init() {\r\n this.player.log('Using dash.js for DASH support');\r\n await this.initDashJs();\r\n }\r\n\r\n async initDashJs() {\r\n this.media.controls = false;\r\n this.media.removeAttribute('controls');\r\n\r\n if (!window.dashjs) {\r\n await this.loadDashJs();\r\n }\r\n\r\n // Remove <source> children — dash.js manages the src via MSE\r\n const sourceElements = Array.from(this.media.querySelectorAll('source'));\r\n let originalSrc = null;\r\n if (sourceElements.length > 0) {\r\n originalSrc = sourceElements[0]?.getAttribute('src') ?? null;\r\n sourceElements.forEach(source => source.remove());\r\n this.player.log('Removed <source> elements for HTML5 validity (dash.js uses MSE)');\r\n }\r\n\r\n const dashjs = window.dashjs;\r\n if (!dashjs) {\r\n throw new Error('dash.js not available');\r\n }\r\n this.dash = dashjs.MediaPlayer().create();\r\n\r\n this.dash.updateSettings({\r\n debug: {\r\n logLevel: this.player.options.debug ? 4 : 0\r\n },\r\n streaming: {\r\n // Override dash.js default of 'lowestStartupDelay'. For audio\r\n // AdaptationSets that tie on selectionPriority and role=main (e.g.\r\n // Axinom's three en/en-low/en-high tracks), 'lowestStartupDelay'\r\n // falls through to 'highestEfficiency' which, for audio, has no\r\n // meaningful pixels-per-bit metric and collapses to \"highest\r\n // bitrate\". 'firstTrack' respects manifest order instead, which is\r\n // both predictable and closer to the MPD author's intent.\r\n selectionModeForInitialTrack: 'firstTrack',\r\n // NOTE on pre-play preload: we deliberately do NOT set\r\n // streaming.scheduling.scheduleWhilePaused = false here. While that\r\n // is the documented dash.js way to suppress segment downloads while\r\n // paused / before the first play, in our setup (dash.js 5.2.0 +\r\n // dash.initialize(media, null, false) + attachSource at init) it\r\n // tears down the SourceBuffers mid-init with\r\n // \"SourceBuffer has been removed from the parent media source\"\r\n // exceptions, which leaves the player unable to seek or play. The\r\n // PR #3785 fix that was supposed to handle the initial-playback /\r\n // autoPlay=false case is fragile against our usage pattern.\r\n // Instead we keep dash.js's default scheduling (scheduleWhilePaused\r\n // stays at its default `true`) and let the buffer caps below limit\r\n // how much is fetched before play. With a single ~6s segment size,\r\n // the visible network preload is one init segment per track plus\r\n // 1–2 media segments — the same \"first two chunks\" behavior the\r\n // user previously confirmed as acceptable for DASH.\r\n buffer: {\r\n bufferTimeAtTopQuality: 30,\r\n bufferTimeAtTopQualityLongForm: 60,\r\n // dash.js 5.x: use bufferTimeDefault (replaces removed stableBufferTime).\r\n // Keep at 12s — going lower (0 / 1) was tested but dash.js still\r\n // loads the first segment regardless because it's needed to make\r\n // the MediaSource playable, so the savings are negligible while\r\n // hurting mid-playback resilience on slow networks.\r\n bufferTimeDefault: 12,\r\n bufferToKeep: 20,\r\n bufferPruningInterval: 10\r\n },\r\n retryAttempts: {\r\n MPD: 4,\r\n MediaSegment: 6,\r\n InitializationSegment: 4,\r\n BitstreamSwitchingSegment: 4\r\n },\r\n retryIntervals: {\r\n MPD: 1000,\r\n MediaSegment: 1000,\r\n InitializationSegment: 1000,\r\n BitstreamSwitchingSegment: 1000\r\n },\r\n abr: {\r\n autoSwitchBitrate: { video: true, audio: true }\r\n },\r\n text: {\r\n defaultEnabled: true\r\n }\r\n }\r\n });\r\n\r\n // Create the TTML rendering div before initialize() so the DOM element\r\n // exists, but attach it to dash.js after initialize() because\r\n // attachTTMLRenderingDiv() requires attachView() which initialize() calls.\r\n this._ttmlDiv = document.createElement('div');\r\n this._ttmlDiv.className = 'vidply-dash-ttml';\r\n this._ttmlDiv.style.visibility = 'hidden';\r\n const wrapper = this.player.videoWrapper || this.media.parentElement;\r\n if (wrapper) {\r\n wrapper.appendChild(this._ttmlDiv);\r\n }\r\n\r\n this.dash.initialize(this.media, null, false);\r\n this.dash.attachTTMLRenderingDiv(this._ttmlDiv);\r\n\r\n // Resolve source URL\r\n let src = this.player.currentSource;\r\n\r\n if (!src && originalSrc) {\r\n src = originalSrc;\r\n }\r\n\r\n if (!src) {\r\n src = this.player.element.getAttribute('data-vidply-src');\r\n }\r\n\r\n if (!src) {\r\n const elementSrc = this.player.element.getAttribute('src') || this.player.element.src;\r\n if (elementSrc && !elementSrc.startsWith('blob:')) {\r\n src = elementSrc;\r\n }\r\n }\r\n\r\n this.player.log(`Loading DASH source: ${src}`, 'log');\r\n\r\n if (!src) {\r\n throw new Error('No DASH source found');\r\n }\r\n\r\n // Always attach the source at init so the manifest is fetched and the\r\n // seekbar / duration / quality list are available before the first play.\r\n // We deliberately don't honor `deferLoad` here: deferring attachSource\r\n // would leave duration unknown and seek requests unserviceable. The\r\n // small preload (init segments + ~1 segment of media data) that dash.js\r\n // does up to bufferTimeDefault is acceptable; in exchange the seekbar\r\n // becomes functional immediately.\r\n this._pendingSrc = src;\r\n this._manifestUrl = src;\r\n this.dash.attachSource(src);\r\n this._dashSourceLoaded = true;\r\n\r\n // Force the vidply poster overlay even though dash.js will paint the\r\n // first decoded frame into the <video> element. With MSE attached and\r\n // init/startup segments appended, the browser ignores the native\r\n // `poster` attribute and shows the first frame instead. We instead use\r\n // the `vidply-forced-poster` CSS class, which sets `<video>` to\r\n // opacity:0 and renders the poster image as a wrapper background — the\r\n // user sees the artwork until they press play, just like on a fully\r\n // native HTML5 video. The 'play' handler in Player.ts already calls\r\n // hidePosterOverlay() on first playback, so we don't need to remove it\r\n // manually here.\r\n this.player.showPosterOverlay();\r\n\r\n this.attachDashEvents();\r\n this.attachMediaEvents();\r\n this._setupCaptionSync();\r\n }\r\n\r\n /**\r\n * Load dash.js. Pinned to an exact version (the previous default\r\n * `5.2.0` is preserved) and overridable via `options.dashScriptUrl`\r\n * (URL) / `options.dashScriptIntegrity` (SRI hash). See\r\n * HLSRenderer.loadHlsJs() for the SRI computation command.\r\n */\r\n async loadDashJs(): Promise<void> {\r\n const defaultUrl = 'https://cdn.jsdelivr.net/npm/dashjs@5.2.0/dist/modern/umd/dash.all.min.js';\r\n const url: string = (this.player.options.dashScriptUrl as string | undefined) || defaultUrl;\r\n const integrity = this.player.options.dashScriptIntegrity as string | undefined;\r\n\r\n return loadScriptOnce(url, { integrity });\r\n }\r\n\r\n _setTimeout(fn: () => void, delay: number) {\r\n const id = setTimeout(() => {\r\n this._pendingTimeouts = this._pendingTimeouts.filter(t => t !== id);\r\n fn();\r\n }, delay);\r\n this._pendingTimeouts.push(id);\r\n return id;\r\n }\r\n\r\n attachDashEvents() {\r\n const dashjs = window.dashjs;\r\n const dash = this.dash;\r\n if (!dashjs || !dash) return;\r\n const dashEvents = dashjs.MediaPlayer.events;\r\n\r\n dash.on(dashEvents.MANIFEST_LOADED, (...args: unknown[]) => {\r\n const e = args[0] as { data?: unknown } | undefined;\r\n const data = e?.data ?? e;\r\n this.player.log('DASH manifest loaded');\r\n this.player.emit('dashmanifestloaded', data);\r\n\r\n if (this.player.container) {\r\n this.player.container.classList.remove('vidply-external-controls');\r\n }\r\n\r\n this._setTimeout(() => {\r\n this._checkSubtitleTracks();\r\n }, 500);\r\n });\r\n\r\n dash.on(dashEvents.QUALITY_CHANGE_RENDERED, (...args: unknown[]) => {\r\n const e = args[0] as { mediaType?: string; newQuality?: number };\r\n if (e.mediaType === 'video') {\r\n this.player.log('DASH quality changed to index ' + e.newQuality);\r\n this.player.emit('dashqualitychanged', e);\r\n }\r\n });\r\n\r\n dash.on(dashEvents.TEXT_TRACKS_ADDED, (...args: unknown[]) => {\r\n const e = args[0] as { tracks?: DashTextTrack[] } | undefined;\r\n const tracks = e?.tracks ?? [];\r\n this._dashTextTracks = tracks;\r\n this._dashTextIsTtml = tracks.some((t) =>\r\n t.isTTML || /stpp|ttml/i.test(t.codec || '') || /ttml/i.test(t.mimeType || '')\r\n );\r\n this.player.log(`DASH text tracks added: ${tracks.length} tracks, format: ${this._dashTextIsTtml ? 'TTML' : 'WebVTT'}`);\r\n this._dashSubtitleTracksCount = tracks.length;\r\n this.player.emit('dashsubtitletracksupdated', { tracks });\r\n this.updateCaptionButtonsForDash();\r\n\r\n if (tracks.length > 0) {\r\n try {\r\n dash.setTextTrack(0);\r\n } catch {\r\n // ignore if not ready yet\r\n }\r\n if (!this._dashTextIsTtml) {\r\n this._startCueUpdatePolling();\r\n }\r\n }\r\n });\r\n\r\n dash.on(dashEvents.STREAM_INITIALIZED, () => {\r\n this.player.log('DASH stream initialized');\r\n this.player.emit('dashstreaminitialized');\r\n\r\n this._setTimeout(() => {\r\n const qualities = this.getQualities();\r\n if (qualities.length > 0) {\r\n this.player.emit('dashmanifestparsed', { qualities });\r\n }\r\n }, 300);\r\n });\r\n\r\n dash.on(dashEvents.ERROR, (...args: unknown[]) => {\r\n this.handleDashError(args[0]);\r\n });\r\n\r\n dash.on(dashEvents.FRAGMENT_LOADING_COMPLETED, (...args: unknown[]) => {\r\n const e = args[0] as { request?: { mediaType?: string } } | undefined;\r\n this.player.state.buffering = false;\r\n if (e?.request?.mediaType === 'text' && !this._dashTextIsTtml) {\r\n this._setTimeout(() => {\r\n const count = this._getTotalCueCount();\r\n if (count > this._lastKnownCueCount) {\r\n this._lastKnownCueCount = count;\r\n this.player.emit('textcuesupdate');\r\n }\r\n }, 100);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Count total cues across all subtitle/caption tracks (for WebVTT DASH).\r\n */\r\n _getTotalCueCount() {\r\n const textTracks = this.media.textTracks;\r\n let total = 0;\r\n if (!textTracks) return total;\r\n for (let i = 0; i < textTracks.length; i++) {\r\n const track = textTracks[i];\r\n if (track && (track.kind === 'subtitles' || track.kind === 'captions') && !track._vidplyStale && track.cues) {\r\n total += track.cues.length;\r\n }\r\n }\r\n return total;\r\n }\r\n\r\n /**\r\n * Return true if `time` falls inside any TimeRange the SourceBuffer already\r\n * holds, with a small tolerance to absorb GOP boundaries. Used by the\r\n * seeking handler to decide whether to surface a 'waiting' event for the\r\n * spinner UI when the user scrubs while paused.\r\n */\r\n _isTimeBuffered(time: number): boolean {\r\n const buffered = this.media.buffered;\r\n if (!buffered || buffered.length === 0) return false;\r\n const tolerance = 0.25;\r\n for (let i = 0; i < buffered.length; i++) {\r\n if (time >= buffered.start(i) - tolerance && time <= buffered.end(i) + tolerance) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Sync VidPly caption track switches with dash.js so it loads\r\n * subtitle segments for the selected language.\r\n */\r\n _setupCaptionSync() {\r\n this._captionEnabledHandler = (selectedTrack) => {\r\n if (this._dashTextIsTtml) {\r\n // dash.js only renders TTML content to the rendering div when the\r\n // TextTrack mode is 'showing'. CaptionManager sets it to 'hidden',\r\n // so we override it here. VidPly's own caption overlay is skipped\r\n // via handlesOwnCaptions().\r\n if (selectedTrack.track) {\r\n selectedTrack.track.mode = 'showing';\r\n }\r\n if (this._ttmlDiv) {\r\n this._ttmlDiv.style.visibility = 'visible';\r\n }\r\n }\r\n this._syncDashTextTrack(selectedTrack);\r\n };\r\n this._captionDisabledHandler = () => {\r\n if (this._dashTextIsTtml && this._ttmlDiv) {\r\n this._ttmlDiv.style.visibility = 'hidden';\r\n }\r\n if (this.dash) {\r\n try { this.dash.setTextTrack(-1); } catch { /* ignore */ }\r\n }\r\n };\r\n this.player.on('captionsenabled', this._captionEnabledHandler);\r\n this.player.on('captionsdisabled', this._captionDisabledHandler);\r\n }\r\n\r\n /**\r\n * Map a VidPly caption track to the corresponding dash.js track index\r\n * and switch dash.js to load segments for that language.\r\n */\r\n _syncDashTextTrack(selectedTrack: CaptionTrackSelection) {\r\n if (!this.dash || !this._dashTextTracks.length) return;\r\n\r\n const lang = selectedTrack.language;\r\n if (!lang) return;\r\n\r\n const dashIndex = this._dashTextTracks.findIndex(dt => {\r\n const dtLang = dt.lang || dt.language || dt.srclang || '';\r\n if (!dtLang) return false;\r\n return dtLang === lang || dtLang.startsWith(lang) || lang.startsWith(dtLang);\r\n });\r\n\r\n if (dashIndex >= 0) {\r\n this.player.log(`Syncing DASH text track to index ${dashIndex} (${lang})`);\r\n try {\r\n this.dash.setTextTrack(dashIndex);\r\n } catch { /* ignore */ }\r\n if (!this._dashTextIsTtml) {\r\n this._lastKnownCueCount = 0;\r\n this._startCueUpdatePolling();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Poll for new WebVTT cues being added by dash.js as subtitle segments load.\r\n * Emits events for transcript refresh when new cues arrive.\r\n */\r\n _startCueUpdatePolling() {\r\n this._stopCueUpdatePolling();\r\n let prevCueCount = 0;\r\n let stableRounds = 0;\r\n\r\n this._cueUpdateTimer = setInterval(() => {\r\n const count = this._getTotalCueCount();\r\n\r\n if (count > prevCueCount) {\r\n prevCueCount = count;\r\n stableRounds = 0;\r\n this.player.emit('textcuesupdate');\r\n } else {\r\n stableRounds++;\r\n if (stableRounds >= 8) {\r\n this._stopCueUpdatePolling();\r\n if (count > 0) {\r\n this.player.emit('textcuesupdate');\r\n }\r\n }\r\n }\r\n }, 500);\r\n }\r\n\r\n _stopCueUpdatePolling() {\r\n if (this._cueUpdateTimer) {\r\n clearInterval(this._cueUpdateTimer);\r\n this._cueUpdateTimer = null;\r\n }\r\n }\r\n\r\n _checkSubtitleTracks() {\r\n if (this._dashSubtitleTracksCount !== undefined && this._dashSubtitleTracksCount > 0) {\r\n return;\r\n }\r\n const tracks = this.media.textTracks;\r\n let count = 0;\r\n for (let i = 0; i < tracks.length; i++) {\r\n const track = tracks[i];\r\n if (track && (track.kind === 'subtitles' || track.kind === 'captions') && !track._vidplyStale) {\r\n count++;\r\n }\r\n }\r\n this._dashSubtitleTracksCount = count;\r\n this.updateCaptionButtonsForDash();\r\n }\r\n\r\n updateCaptionButtonsForDash(retryCount = 0) {\r\n const tracksCount = this._dashSubtitleTracksCount || 0;\r\n\r\n const doUpdate = () => {\r\n this.player.invalidateTrackCache();\r\n\r\n if (tracksCount > 0) {\r\n if (this.player.captionManager) {\r\n const found = this.player.captionManager.refreshTracks();\r\n\r\n // dash.js fires TEXT_TRACKS_ADDED when it knows about the\r\n // tracks, but the browser TextTrackList may not yet enumerate\r\n // the new TextTrack objects synchronously. If refreshTracks\r\n // found nothing, retry a few times with increasing delays.\r\n if (found === 0 && retryCount < 5) {\r\n const delay = (retryCount + 1) * 200;\r\n this.player.log(`DASH caption tracks not yet on video element, retrying in ${delay}ms (attempt ${retryCount + 1})`, 'info');\r\n this._setTimeout(() => {\r\n this.updateCaptionButtonsForDash(retryCount + 1);\r\n }, delay);\r\n return;\r\n }\r\n }\r\n\r\n if (!this._dashTextIsTtml && this.player.transcriptManager?.isVisible) {\r\n this.player.transcriptManager.loadTranscriptData();\r\n this.player.transcriptManager.updateLanguageSelector();\r\n }\r\n\r\n if (this.player.controlBar) {\r\n this.player.controlBar.ensureCaptionsButton();\r\n if (!this._dashTextIsTtml) {\r\n this.player.controlBar.ensureCaptionStyleButton();\r\n this.player.controlBar.ensureTranscriptButton();\r\n }\r\n }\r\n } else {\r\n if (this.player.captionManager) {\r\n this.player.captionManager.refreshTracks();\r\n }\r\n\r\n if (this.player.transcriptManager?.isVisible) {\r\n this.player.transcriptManager.hideTranscript();\r\n }\r\n\r\n if (this.player.controlBar) {\r\n this.player.controlBar.removeHlsCaptionButtons(true);\r\n }\r\n }\r\n };\r\n\r\n if (this.player.controlBar) {\r\n doUpdate();\r\n return;\r\n }\r\n\r\n const onReady = () => {\r\n this.player.off('ready', onReady);\r\n this._pendingReadyHandler = null;\r\n doUpdate();\r\n };\r\n // Track so destroy() can detach it if 'ready' never fires.\r\n this._pendingReadyHandler = onReady;\r\n this.player.on('ready', onReady);\r\n }\r\n\r\n attachMediaEvents() {\r\n const { signal } = this._listenerController;\r\n\r\n this.media.addEventListener('loadedmetadata', () => {\r\n this.player.state.duration = this.media.duration;\r\n this.player.emit('loadedmetadata');\r\n }, { signal });\r\n\r\n this.media.addEventListener('durationchange', () => {\r\n const duration = this.media.duration;\r\n if (duration && isFinite(duration) && duration > 0) {\r\n this.player.state.duration = duration;\r\n this.player.emit('durationchange', duration);\r\n }\r\n }, { signal });\r\n\r\n this.media.addEventListener('play', () => {\r\n this.player.state.playing = true;\r\n this.player.state.paused = false;\r\n this.player.state.ended = false;\r\n this.player.emit('play');\r\n\r\n if (this.player.options.onPlay) {\r\n this.player.options.onPlay.call(this.player);\r\n }\r\n }, { signal });\r\n\r\n this.media.addEventListener('pause', () => {\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.emit('pause');\r\n\r\n if (this.player.options.onPause) {\r\n this.player.options.onPause.call(this.player);\r\n }\r\n }, { signal });\r\n\r\n this.media.addEventListener('ended', () => {\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.state.ended = true;\r\n this.player.emit('ended');\r\n\r\n if (this.player.options.onEnded) {\r\n this.player.options.onEnded.call(this.player);\r\n }\r\n\r\n if (this.player.options.loop) {\r\n this.player.seek(0);\r\n this.player.play();\r\n }\r\n }, { signal });\r\n\r\n this.media.addEventListener('timeupdate', () => {\r\n this.player.state.currentTime = this.media.currentTime;\r\n this.player.emit('timeupdate', this.media.currentTime);\r\n\r\n if (this.player.options.onTimeUpdate) {\r\n this.player.options.onTimeUpdate.call(this.player, this.media.currentTime);\r\n }\r\n }, { signal });\r\n\r\n this.media.addEventListener('volumechange', () => {\r\n this.player.state.volume = this.media.volume;\r\n this.player.state.muted = this.media.muted;\r\n this.player.emit('volumechange', this.media.volume);\r\n }, { signal });\r\n\r\n this.media.addEventListener('seeking', () => {\r\n this.player.state.seeking = true;\r\n this.player.emit('seeking');\r\n\r\n // Browsers do not fire `waiting` when seeking on a paused media element\r\n // — there is nothing to \"wait\" for since playback isn't requested. With\r\n // dash.js + MSE, scrubbing while paused (or before the first play)\r\n // still triggers a real fragment download, but the spinner stays hidden\r\n // because no `waiting` event reaches the buffering UI. Detect a seek\r\n // into an unbuffered range here and surface it as 'waiting' so the\r\n // spinner appears. Cleared again by the existing `canplay` /\r\n // `seeked` paths.\r\n if (!this._isTimeBuffered(this.media.currentTime)) {\r\n this.player.state.buffering = true;\r\n this.player.emit('waiting');\r\n }\r\n }, { signal });\r\n\r\n this.media.addEventListener('seeked', () => {\r\n this.player.state.seeking = false;\r\n this.player.emit('seeked');\r\n }, { signal });\r\n\r\n this.media.addEventListener('waiting', () => {\r\n this.player.state.buffering = true;\r\n this.player.emit('waiting');\r\n }, { signal });\r\n\r\n this.media.addEventListener('canplay', () => {\r\n this.player.state.buffering = false;\r\n this.player.emit('canplay');\r\n }, { signal });\r\n\r\n this.media.addEventListener('error', () => {\r\n this.player.handleError(this.media.error);\r\n }, { signal });\r\n }\r\n\r\n handleDashError(e: unknown) {\r\n const wrapped = e as { error?: { code?: number; message?: string }; code?: number; message?: string } | undefined;\r\n const error = wrapped?.error ?? wrapped;\r\n if (!error) return;\r\n const code = error.code ?? '';\r\n const message = error.message || '';\r\n this.player.log(`DASH Error - Code: ${code}, Message: ${message}`, 'warn');\r\n\r\n if (typeof code === 'number' && code >= 100) {\r\n this.player.log('Fatal DASH error', 'error');\r\n this.player.handleError(new Error(`DASH Error: ${code} - ${message}`));\r\n } else {\r\n this.player.log('Non-fatal DASH error: ' + (message || String(error)), 'warn');\r\n }\r\n }\r\n\r\n ensureLoaded() {\r\n if (!this.player.options.deferLoad) {\r\n return;\r\n }\r\n\r\n if (!this.dash) {\r\n return;\r\n }\r\n\r\n if (this._dashSourceLoaded) {\r\n return;\r\n }\r\n\r\n const src = this._pendingSrc || this.player._pendingSource || this.player.currentSource;\r\n if (!src) {\r\n return;\r\n }\r\n\r\n try {\r\n this.dash.attachSource(src);\r\n this._dashSourceLoaded = true;\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n play() {\r\n const scrollX = window.scrollX;\r\n const scrollY = window.scrollY;\r\n\r\n // Defer-load (legacy code path, kept for completeness): the source is\r\n // normally attached at init and dash.js is configured with\r\n // scheduling.scheduleWhilePaused: false to keep prefetch at zero until\r\n // play. If for any reason the source is still pending here, attach it\r\n // now. Note that media.play() is called immediately afterwards; on\r\n // modern dash.js this races cleanly because attachSource() is sync\r\n // enough for the MediaSource to be ready by the time the play promise\r\n // resolves, and the configured zero-prefetch settings make the race\r\n // window very short. The general \"no preload\" UX no longer relies on\r\n // this branch.\r\n if (this.player.options.deferLoad && this.dash && !this._dashSourceLoaded) {\r\n const src = this._pendingSrc || this.player.currentSource;\r\n if (src) {\r\n try {\r\n this.dash.attachSource(src);\r\n this._dashSourceLoaded = true;\r\n } catch {\r\n // ignore and let media.play() surface errors if any\r\n }\r\n }\r\n }\r\n\r\n const promise = this.media.play();\r\n\r\n window.scrollTo(scrollX, scrollY);\r\n\r\n if (promise !== undefined) {\r\n promise.catch(error => {\r\n this.player.log('Play failed:', error, 'warn');\r\n });\r\n }\r\n }\r\n\r\n pause() {\r\n // dash.js stops scheduling new fragment downloads once `paused` is true,\r\n // because we configured `streaming.scheduling.scheduleWhilePaused: false`\r\n // at init. Already-buffered data stays in the SourceBuffer, so a\r\n // subsequent play() resumes near-instantly while pause saves bandwidth.\r\n this.media.pause();\r\n }\r\n\r\n seek(time: number) {\r\n this.media.currentTime = time;\r\n }\r\n\r\n setVolume(volume: number) {\r\n this.media.volume = volume;\r\n }\r\n\r\n setMuted(muted: boolean) {\r\n this.media.muted = muted;\r\n }\r\n\r\n setPlaybackSpeed(speed: number) {\r\n this.media.playbackRate = speed;\r\n }\r\n\r\n switchQuality(qualityIndex: number) {\r\n if (!this.dash) return;\r\n\r\n if (qualityIndex === -1) {\r\n // Re-enable ABR auto-switching\r\n if (typeof this.dash.setAutoSwitchQualityFor === 'function') {\r\n this.dash.setAutoSwitchQualityFor('video', true);\r\n } else {\r\n this.dash.updateSettings({\r\n streaming: { abr: { autoSwitchBitrate: { video: true } } }\r\n });\r\n }\r\n } else {\r\n // Disable ABR and lock to the chosen quality\r\n if (typeof this.dash.setAutoSwitchQualityFor === 'function') {\r\n this.dash.setAutoSwitchQualityFor('video', false);\r\n } else {\r\n this.dash.updateSettings({\r\n streaming: { abr: { autoSwitchBitrate: { video: false } } }\r\n });\r\n }\r\n\r\n if (typeof this.dash.setRepresentationForTypeByIndex === 'function') {\r\n this.dash.setRepresentationForTypeByIndex('video', qualityIndex);\r\n } else if (typeof this.dash.setQualityFor === 'function') {\r\n this.dash.setQualityFor('video', qualityIndex, true);\r\n }\r\n }\r\n }\r\n\r\n getQualities() {\r\n if (!this.dash) return [];\r\n\r\n try {\r\n // dash.js v5+: getRepresentationsByType\r\n let reps = null;\r\n if (typeof this.dash.getRepresentationsByType === 'function') {\r\n reps = this.dash.getRepresentationsByType('video');\r\n }\r\n\r\n if (reps && reps.length > 0) {\r\n const heightCounts: Record<number, number> = {};\r\n reps.forEach((r: DashRepresentation) => {\r\n const h = Number(r.height) || 0;\r\n heightCounts[h] = (heightCounts[h] || 0) + 1;\r\n });\r\n\r\n return reps.map((rep: DashRepresentation, index: number) => {\r\n const height = Number(rep.height) || 0;\r\n const bitrate = Number(rep.bandwidth || rep.bitrate) || 0;\r\n const kb = bitrate > 0 ? Math.round(bitrate / 1000) : 0;\r\n let name;\r\n if (height > 0 && (heightCounts[height] ?? 0) > 1 && kb > 0) {\r\n name = `${height}p (${kb} kbps)`;\r\n } else if (height > 0) {\r\n name = `${height}p`;\r\n } else {\r\n name = kb > 0 ? `${kb} kbps` : 'Auto';\r\n }\r\n return {\r\n index,\r\n id: rep.id,\r\n height: rep.height,\r\n width: rep.width,\r\n bitrate,\r\n name\r\n };\r\n });\r\n }\r\n\r\n // Fallback: dash.js v4 and earlier\r\n const bitrateList = this.dash.getBitrateInfoListFor('video');\r\n if (!bitrateList || bitrateList.length === 0) return [];\r\n\r\n const heightCounts: Record<number, number> = {};\r\n bitrateList.forEach((info: DashBitrateInfo) => {\r\n const h = Number(info.height) || 0;\r\n heightCounts[h] = (heightCounts[h] || 0) + 1;\r\n });\r\n\r\n return bitrateList.map((info: DashBitrateInfo, index: number) => {\r\n const height = Number(info.height) || 0;\r\n const bitrate = Number(info.bitrate) || 0;\r\n const kb = bitrate > 0 ? Math.round(bitrate / 1000) : 0;\r\n let name;\r\n if (height > 0 && (heightCounts[height] ?? 0) > 1 && kb > 0) {\r\n name = `${height}p (${kb} kbps)`;\r\n } else if (height > 0) {\r\n name = `${height}p`;\r\n } else {\r\n name = kb > 0 ? `${kb} kbps` : 'Auto';\r\n }\r\n return {\r\n index,\r\n height: info.height,\r\n width: info.width,\r\n bitrate: info.bitrate,\r\n name\r\n };\r\n });\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n getCurrentQuality() {\r\n if (!this.dash) return -1;\r\n try {\r\n if (typeof this.dash.getRepresentationsByType === 'function') {\r\n const reps = this.dash.getRepresentationsByType('video');\r\n const current = this.dash.getCurrentRepresentationForType?.('video');\r\n if (current && reps) {\r\n const idx = reps.findIndex((r: DashRepresentation) => r.id === current.id);\r\n if (idx >= 0) return idx;\r\n }\r\n }\r\n return this.dash.getQualityFor('video');\r\n } catch {\r\n return -1;\r\n }\r\n }\r\n\r\n handlesOwnCaptions() {\r\n return this._dashTextIsTtml;\r\n }\r\n\r\n /**\r\n * Tell dash.js to activate the text track for `lang` so it begins\r\n * downloading subtitle segments and populating cues for that language.\r\n */\r\n activateTextTrackForLanguage(lang: string): boolean {\r\n if (!this.dash || !this._dashTextTracks.length || !lang) return false;\r\n\r\n let dashIndex = this._dashTextTracks.findIndex(dt => {\r\n const dtLang = dt.lang || dt.language || dt.srclang || '';\r\n if (!dtLang) return false;\r\n return dtLang === lang || dtLang.startsWith(lang) || lang.startsWith(dtLang);\r\n });\r\n\r\n if (dashIndex < 0) {\r\n dashIndex = this._dashTextTracks.findIndex(dt => {\r\n const dtLabel = (dt.label || dt.labels || '').toString().toLowerCase();\r\n return dtLabel.includes(lang.toLowerCase());\r\n });\r\n }\r\n\r\n if (dashIndex < 0) return false;\r\n\r\n this.player.log(`Activating DASH text track index ${dashIndex} for transcript language \"${lang}\"`);\r\n try {\r\n this.dash.setTextTrack(dashIndex);\r\n } catch { /* ignore */ }\r\n\r\n // dash.js's text scheduler only fetches segments while the video is\r\n // playing. When paused, a brief play–pause cycle forces the scheduler\r\n // to buffer text data for the newly selected track.\r\n if (this.media.paused) {\r\n const pos = this.media.currentTime;\r\n const wasMuted = this.media.muted;\r\n this.media.muted = true;\r\n const playPromise = this.media.play();\r\n const doPause = () => {\r\n if (this.media && !this.media.paused) {\r\n this.media.pause();\r\n this.media.muted = wasMuted;\r\n // Restore position in case it drifted\r\n if (Math.abs(this.media.currentTime - pos) > 0.5) {\r\n this.media.currentTime = pos;\r\n }\r\n }\r\n };\r\n if (playPromise && typeof playPromise.then === 'function') {\r\n playPromise.then(() => {\r\n this._setTimeout(doPause, 250);\r\n }).catch(() => {\r\n this.media.muted = wasMuted;\r\n });\r\n } else {\r\n this._setTimeout(doPause, 250);\r\n }\r\n }\r\n\r\n if (!this._dashTextIsTtml) {\r\n this._lastKnownCueCount = 0;\r\n this._startCueUpdatePolling();\r\n }\r\n return true;\r\n }\r\n\r\n getTextTrackURLs(): { lang: string; url: string }[] {\r\n if (!this.dash || !this._manifestUrl) return [];\r\n try {\r\n // dash.js manifest objects are loosely shaped (XML-derived), so we\r\n // walk them through index-keyed records and narrow as we go.\r\n type ManifestNode = Record<string, unknown>;\r\n const manifest = this.dash.getManifest?.() as ManifestNode | undefined;\r\n if (!manifest) return [];\r\n\r\n const baseUrl = this._manifestUrl.substring(0, this._manifestUrl.lastIndexOf('/') + 1);\r\n const results: { lang: string; url: string }[] = [];\r\n\r\n const rawPeriods = manifest.Period || manifest.period || manifest.periods || manifest;\r\n const periods = (Array.isArray(rawPeriods) ? rawPeriods : [rawPeriods]) as ManifestNode[];\r\n for (const period of periods) {\r\n const rawAdaptSets = period.AdaptationSet || period.adaptationSet || period.AdaptationSet_asArray || [];\r\n const adaptSets = (Array.isArray(rawAdaptSets) ? rawAdaptSets : [rawAdaptSets]) as ManifestNode[];\r\n for (const as of adaptSets) {\r\n const ct = String(as.contentType || as.ContentType || '');\r\n const mime = String(as.mimeType || as.MimeType || '');\r\n if (ct !== 'text' && !/text\\/vtt|application\\/ttml/i.test(mime)) continue;\r\n\r\n const lang = String(as.lang || as.language || '');\r\n const rawReps = as.Representation || as.representation || as.Representation_asArray || [];\r\n const reps = (Array.isArray(rawReps) ? rawReps : [rawReps]) as ManifestNode[];\r\n for (const rep of reps) {\r\n const bu = (rep.BaseURL || rep.baseURL || rep.BaseURL_asArray) as\r\n | string\r\n | { __text?: string }\r\n | Array<string | { __text?: string }>\r\n | undefined;\r\n let rawUrl: string | undefined;\r\n if (Array.isArray(bu)) {\r\n const first = bu[0];\r\n rawUrl = typeof first === 'string' ? first : first?.__text;\r\n } else if (typeof bu === 'string') {\r\n rawUrl = bu;\r\n } else {\r\n rawUrl = bu?.__text;\r\n }\r\n if (!rawUrl) continue;\r\n const url = rawUrl.startsWith('http') ? rawUrl : new URL(rawUrl, baseUrl).href;\r\n results.push({ lang, url });\r\n break;\r\n }\r\n }\r\n }\r\n return results;\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n supportsAutoQuality() {\r\n return true;\r\n }\r\n\r\n isAutoQuality() {\r\n if (!this.dash) return true;\r\n try {\r\n if (typeof this.dash.getAutoSwitchQualityFor === 'function') {\r\n return this.dash.getAutoSwitchQualityFor('video');\r\n }\r\n const settings = this.dash.getSettings?.();\r\n return settings?.streaming?.abr?.autoSwitchBitrate?.video !== false;\r\n } catch {\r\n return true;\r\n }\r\n }\r\n\r\n destroy() {\r\n this._pendingTimeouts.forEach(id => clearTimeout(id));\r\n this._pendingTimeouts = [];\r\n this._stopCueUpdatePolling();\r\n this._lastKnownCueCount = 0;\r\n // Detach media listeners registered in attachMediaEvents().\r\n this._listenerController.abort();\r\n // Remove the deferred 'ready' listener if it never fired.\r\n if (this._pendingReadyHandler) {\r\n this.player.off('ready', this._pendingReadyHandler);\r\n this._pendingReadyHandler = null;\r\n }\r\n\r\n if (this._captionEnabledHandler) {\r\n this.player.off('captionsenabled', this._captionEnabledHandler);\r\n this._captionEnabledHandler = null;\r\n }\r\n if (this._captionDisabledHandler) {\r\n this.player.off('captionsdisabled', this._captionDisabledHandler);\r\n this._captionDisabledHandler = null;\r\n }\r\n\r\n if (this._ttmlDiv && this._ttmlDiv.parentNode) {\r\n this._ttmlDiv.parentNode.removeChild(this._ttmlDiv);\r\n this._ttmlDiv = null;\r\n }\r\n\r\n // Mark all subtitle/caption text tracks as stale. dash.js creates\r\n // programmatic TextTrack objects that persist on the <video> element\r\n // after destroy() and cannot be removed via standard APIs. The stale\r\n // flag prevents _checkSubtitleTracks() in a new renderer instance from\r\n // treating them as tracks belonging to the current stream.\r\n const textTracks = this.media.textTracks;\r\n for (let i = 0; i < textTracks.length; i++) {\r\n const track = textTracks[i];\r\n if (track && (track.kind === 'subtitles' || track.kind === 'captions')) {\r\n track._vidplyStale = true;\r\n track.mode = 'disabled';\r\n }\r\n }\r\n\r\n if (this.dash) {\r\n try {\r\n // Silence dash.js logging during teardown to suppress harmless\r\n // SourceBuffer errors from in-flight async operations.\r\n this.dash.updateSettings({ debug: { logLevel: 0 } });\r\n // reset() cleanly detaches from MediaSource and cancels pending\r\n // buffer operations before destroy() releases all resources.\r\n this.dash.reset();\r\n } catch { /* ignore teardown errors */ }\r\n try {\r\n this.dash.destroy();\r\n } catch { /* ignore teardown errors */ }\r\n this.dash = null;\r\n }\r\n this._dashTextTracks = [];\r\n this._dashTextIsTtml = false;\r\n this._manifestUrl = null;\r\n }\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["heightCounts"]
|
|
7
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* VidPly v1.
|
|
2
|
+
* VidPly v1.2.0 - Universal, Accessible Video Player
|
|
3
3
|
* (c) 2026 Matthias Peltzer
|
|
4
4
|
* Released under GPL-2.0-or-later License
|
|
5
5
|
*/
|
|
6
6
|
import {
|
|
7
7
|
DraggableResizable
|
|
8
|
-
} from "./vidply.chunk-
|
|
8
|
+
} from "./vidply.chunk-JJ47NO24.js";
|
|
9
9
|
import {
|
|
10
10
|
createIconElement
|
|
11
|
-
} from "./vidply.chunk-
|
|
11
|
+
} from "./vidply.chunk-KI7C3QVL.js";
|
|
12
12
|
import {
|
|
13
13
|
DOMUtils,
|
|
14
14
|
i18n
|
|
15
|
-
} from "./vidply.chunk-
|
|
15
|
+
} from "./vidply.chunk-RZWZGDV7.js";
|
|
16
16
|
|
|
17
17
|
// src/core/FloatingPlayerManager.ts
|
|
18
18
|
var FLOATING_CLAIM_EVENT = "vidply:floating-claim";
|
|
@@ -345,6 +345,11 @@ var FloatingPlayerManager = class {
|
|
|
345
345
|
this.resizeHandles.forEach((handle) => shell.appendChild(handle));
|
|
346
346
|
this._onKeyDown = (event) => {
|
|
347
347
|
if (event.key === "Escape") {
|
|
348
|
+
const d = this.draggable;
|
|
349
|
+
const inEditMode = !!d && (d.keyboardDragMode || d.keyboardResizeMode || d.pointerResizeMode);
|
|
350
|
+
if (inEditMode) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
348
353
|
event.stopPropagation();
|
|
349
354
|
this.dismiss();
|
|
350
355
|
}
|
|
@@ -529,4 +534,4 @@ var FloatingPlayerManager = class {
|
|
|
529
534
|
export {
|
|
530
535
|
FloatingPlayerManager
|
|
531
536
|
};
|
|
532
|
-
//# sourceMappingURL=vidply.FloatingPlayerManager-
|
|
537
|
+
//# sourceMappingURL=vidply.FloatingPlayerManager-PKNNNAS2.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/core/FloatingPlayerManager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\r\n * Floating Player Manager\r\n *\r\n * Custom in-page Picture-in-Picture. Moves the entire player.container\r\n * into a position:fixed, draggable and resizable shell that lives outside\r\n * the document flow (appended to document.body). A transparent placeholder\r\n * preserves layout and, while floating, serves as the IntersectionObserver\r\n * sentinel so scroll-based auto-float/redock decisions stay anchored to\r\n * the original slot.\r\n *\r\n * Triggers:\r\n * - pinned: the user clicks the control-bar PiP button (only when\r\n * options.floating is true; otherwise the button uses native PiP).\r\n * Pinned floating ignores scroll-based docking.\r\n * - auto: the video is playing and the original slot has scrolled out\r\n * of the viewport. Auto-float redocks automatically when the slot\r\n * scrolls back in.\r\n *\r\n * Close button: pauses playback, exits the floating shell and marks the\r\n * current play session as dismissed so auto-float will not re-trigger\r\n * until the user presses play again (matches YouTube miniplayer UX).\r\n *\r\n * Only one player is allowed to float at a time across a page; enter()\r\n * broadcasts a 'vidply:floating-claim' CustomEvent that other managers\r\n * listen for and auto-exit on.\r\n */\r\n\r\nimport { DOMUtils } from '../utils/DOMUtils.js';\r\nimport { DraggableResizable } from '../utils/DraggableResizable.js';\r\nimport { createIconElement } from '../icons/Icons.js';\r\nimport { i18n } from '../i18n/i18n.js';\r\nimport type { Player } from './Player.js';\r\n\r\ntype FloatingState = 'pinned' | 'auto';\r\ntype ExitReason = 'manual' | 'auto' | 'dismiss' | 'claim' | 'destroy';\r\n\r\nconst FLOATING_CLAIM_EVENT = 'vidply:floating-claim';\r\nconst DEFAULT_WIDTH = 400;\r\nconst MIN_WIDTH = 240;\r\nconst EDGE_MARGIN = 16;\r\n\r\ninterface FloatingPrefs {\r\n width?: number;\r\n height?: number;\r\n left?: number;\r\n top?: number;\r\n}\r\n\r\nexport class FloatingPlayerManager {\r\n player: Player;\r\n classPrefix: string;\r\n\r\n shell: HTMLElement | null;\r\n dragHandle: HTMLElement | null;\r\n closeButton: HTMLButtonElement | null;\r\n resizeHandles: HTMLElement[];\r\n placeholder: HTMLElement | null;\r\n draggable: DraggableResizable | null;\r\n\r\n originalParent: HTMLElement | null;\r\n originalNextSibling: Node | null;\r\n\r\n intersectionObserver: IntersectionObserver | null;\r\n observerTarget: HTMLElement | null;\r\n lastRatio: number;\r\n\r\n _autoDismissedThisPlay: boolean;\r\n _playListenerAttached: boolean;\r\n _onPlayAfterDismiss: (() => void) | null;\r\n _onClaim: ((event: Event) => void) | null;\r\n _onResize: (() => void) | null;\r\n _onKeyDown: ((event: KeyboardEvent) => void) | null;\r\n _onEnterFullscreen: (() => void) | null;\r\n _destroyed: boolean;\r\n _triggerFocusEl: HTMLElement | null;\r\n _claimId: string;\r\n _lastAutoExitTime: number;\r\n\r\n constructor(player: Player) {\r\n this.player = player;\r\n this.classPrefix = player.options.classPrefix || 'vidply';\r\n\r\n this.shell = null;\r\n this.dragHandle = null;\r\n this.closeButton = null;\r\n this.resizeHandles = [];\r\n this.placeholder = null;\r\n this.draggable = null;\r\n\r\n this.originalParent = null;\r\n this.originalNextSibling = null;\r\n\r\n this.intersectionObserver = null;\r\n this.observerTarget = null;\r\n this.lastRatio = 1;\r\n\r\n this._autoDismissedThisPlay = false;\r\n this._playListenerAttached = false;\r\n this._onPlayAfterDismiss = null;\r\n this._onClaim = null;\r\n this._onResize = null;\r\n this._onKeyDown = null;\r\n this._onEnterFullscreen = null;\r\n this._destroyed = false;\r\n this._triggerFocusEl = null;\r\n this._claimId = `floating-${player.instanceId}-${Date.now()}`;\r\n this._lastAutoExitTime = 0;\r\n\r\n this._setupClaimListener();\r\n this._setupFullscreenGuard();\r\n this._startObserving();\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Public API\r\n // ---------------------------------------------------------------\r\n\r\n togglePinned(triggerEl?: HTMLElement | null) {\r\n if (this._destroyed) return;\r\n if (this.player.state.floating === 'pinned') {\r\n // Manual unpin: suppress auto-float for the remainder of the\r\n // current play session so scrolling doesn't immediately re-pop\r\n // the floating shell. A fresh 'play' event clears the flag.\r\n this._autoDismissedThisPlay = true;\r\n this._armPlayListenerToClearDismiss();\r\n this.exit('manual');\r\n return;\r\n }\r\n // If the user pins while in 'auto' mode, that's an explicit request\r\n // to float; any previous auto-dismiss flag should be cleared so the\r\n // pinned state behaves naturally.\r\n this._autoDismissedThisPlay = false;\r\n this._triggerFocusEl = triggerEl || this._activeElement();\r\n this.enter('pinned');\r\n }\r\n\r\n enter(reason: FloatingState) {\r\n if (this._destroyed) return;\r\n if (this.player.state.floating === reason) return;\r\n\r\n if (!this._canFloat(reason)) {\r\n return;\r\n }\r\n\r\n // Upgrade 'auto' -> 'pinned' without rebuilding the shell\r\n if (this.player.state.floating && this.player.state.floating !== reason) {\r\n this.player.state.floating = reason;\r\n this.player.emit('floatingchange', reason);\r\n return;\r\n }\r\n\r\n this._claimSingleton();\r\n\r\n this._ensureShell();\r\n this._mountIntoShell();\r\n this._applyInitialGeometry();\r\n\r\n this.player.state.floating = reason;\r\n this.player.emit('floatingchange', reason);\r\n\r\n // Focus the close button after a microtask so screen readers announce\r\n // the dialog opening.\r\n queueMicrotask(() => {\r\n if (this.closeButton && this.player.state.floating) {\r\n try { this.closeButton.focus({ preventScroll: true }); } catch { /* ignore */ }\r\n }\r\n });\r\n }\r\n\r\n exit(reason: ExitReason = 'manual') {\r\n if (this._destroyed && reason !== 'destroy') return;\r\n if (!this.player.state.floating) return;\r\n\r\n if (reason === 'auto') {\r\n // Record when an auto-exit occurred so the IntersectionObserver\r\n // callback can apply a cooldown before re-entering auto-float.\r\n this._lastAutoExitTime = Date.now();\r\n }\r\n\r\n this._unmountFromShell();\r\n this._teardownShell();\r\n\r\n const priorTrigger = this._triggerFocusEl;\r\n this._triggerFocusEl = null;\r\n\r\n this.player.state.floating = null;\r\n this.player.emit('floatingchange', null);\r\n\r\n // Restore focus to the element that triggered floating (pinned flow).\r\n // For scroll-based exits we leave focus untouched.\r\n if ((reason === 'manual' || reason === 'dismiss') && priorTrigger) {\r\n try { priorTrigger.focus({ preventScroll: true }); } catch { /* ignore */ }\r\n }\r\n }\r\n\r\n /**\r\n * Close button: pause, dismiss, and prevent auto-float until the next\r\n * user-initiated play event.\r\n */\r\n dismiss() {\r\n if (this._destroyed) return;\r\n this._autoDismissedThisPlay = true;\r\n this._armPlayListenerToClearDismiss();\r\n\r\n try {\r\n this.player.pause();\r\n } catch { /* ignore */ }\r\n\r\n this.exit('dismiss');\r\n }\r\n\r\n destroy() {\r\n if (this._destroyed) return;\r\n this._destroyed = true;\r\n\r\n if (this.player.state && this.player.state.floating) {\r\n try { this.exit('destroy'); } catch { /* ignore */ }\r\n }\r\n\r\n if (this.intersectionObserver) {\r\n try { this.intersectionObserver.disconnect(); } catch { /* ignore */ }\r\n this.intersectionObserver = null;\r\n }\r\n this.observerTarget = null;\r\n\r\n if (this._onClaim) {\r\n window.removeEventListener(FLOATING_CLAIM_EVENT, this._onClaim as EventListener);\r\n this._onClaim = null;\r\n }\r\n if (this._onResize) {\r\n window.removeEventListener('resize', this._onResize);\r\n this._onResize = null;\r\n }\r\n const enterFs = this._onEnterFullscreen;\r\n if (enterFs) {\r\n this.player.off('enterfullscreen', enterFs);\r\n this._onEnterFullscreen = null;\r\n }\r\n const playAfterDismiss = this._onPlayAfterDismiss;\r\n if (playAfterDismiss && this._playListenerAttached) {\r\n this.player.off('play', playAfterDismiss);\r\n this._playListenerAttached = false;\r\n this._onPlayAfterDismiss = null;\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: guards\r\n // ---------------------------------------------------------------\r\n\r\n _canFloat(reason: FloatingState): boolean {\r\n if (!this.player.options.floating) return false;\r\n if (!this.player.container) return false;\r\n if (!this.player.element || this.player.element.tagName !== 'VIDEO') return false;\r\n if (this.player.state.fullscreen) return false;\r\n\r\n // Playlist players move through multiple tracks and manage their own\r\n // UI; floating support for playlists is out of scope for this v1.\r\n if (this.player.playlistManager) return false;\r\n\r\n const minWidth = this.player.options.floatingMinViewportWidth ?? 768;\r\n if (window.innerWidth < minWidth) return false;\r\n\r\n // Auto-float only engages when the user is actively watching.\r\n if (reason === 'auto') {\r\n if (this._autoDismissedThisPlay) return false;\r\n if (this.player.state.paused) return false;\r\n // Never auto-float before the user has started playback; stops\r\n // auto-entry from firing while the page is still below the fold\r\n // on initial load.\r\n if (!this.player.state.hasStartedPlayback) return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n _claimSingleton() {\r\n try {\r\n window.dispatchEvent(new CustomEvent(FLOATING_CLAIM_EVENT, {\r\n detail: { claimId: this._claimId }\r\n }));\r\n } catch { /* ignore (older browsers) */ }\r\n }\r\n\r\n _setupClaimListener() {\r\n this._onClaim = (event: Event) => {\r\n const detail = (event as CustomEvent).detail;\r\n if (!detail || detail.claimId === this._claimId) return;\r\n if (this.player.state.floating) {\r\n this.exit('claim');\r\n }\r\n };\r\n const signal = this.player.lifecycleSignal;\r\n window.addEventListener(FLOATING_CLAIM_EVENT, this._onClaim as EventListener, { signal });\r\n\r\n this._onResize = () => {\r\n const minWidth = this.player.options.floatingMinViewportWidth ?? 768;\r\n if (this.player.state.floating && window.innerWidth < minWidth) {\r\n this.exit('auto');\r\n }\r\n };\r\n window.addEventListener('resize', this._onResize, { signal });\r\n }\r\n\r\n _setupFullscreenGuard() {\r\n const onEnterFullscreen = () => {\r\n if (this.player.state.floating) {\r\n this.exit('manual');\r\n }\r\n };\r\n this._onEnterFullscreen = onEnterFullscreen;\r\n this.player.on('enterfullscreen', onEnterFullscreen);\r\n }\r\n\r\n _armPlayListenerToClearDismiss() {\r\n if (this._playListenerAttached) return;\r\n const onPlayAfterDismiss = () => {\r\n this._autoDismissedThisPlay = false;\r\n const handler = this._onPlayAfterDismiss;\r\n if (handler) {\r\n this.player.off('play', handler);\r\n }\r\n this._playListenerAttached = false;\r\n this._onPlayAfterDismiss = null;\r\n };\r\n this._onPlayAfterDismiss = onPlayAfterDismiss;\r\n this.player.on('play', onPlayAfterDismiss);\r\n this._playListenerAttached = true;\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: IntersectionObserver for scroll-triggered auto-float\r\n // ---------------------------------------------------------------\r\n\r\n _startObserving() {\r\n if (!('IntersectionObserver' in window)) return;\r\n if (!this.player.container) return;\r\n\r\n this.observerTarget = this.player.container;\r\n this.intersectionObserver = new IntersectionObserver((entries) => {\r\n const entry = entries[entries.length - 1];\r\n if (!entry) return;\r\n this.lastRatio = entry.intersectionRatio;\r\n\r\n if (this.player.options.debug) {\r\n try {\r\n console.log('[vidply:floating] intersection', {\r\n ratio: Number(entry.intersectionRatio.toFixed(3)),\r\n state: this.player.state.floating,\r\n paused: this.player.state.paused,\r\n hasStartedPlayback: this.player.state.hasStartedPlayback,\r\n dismissed: this._autoDismissedThisPlay\r\n });\r\n } catch { /* ignore */ }\r\n }\r\n\r\n if (this.player.state.floating === 'auto') {\r\n if (entry.intersectionRatio >= 0.5) {\r\n this.exit('auto');\r\n }\r\n return;\r\n }\r\n\r\n // Pinned state: scroll is a no-op, the user has taken control.\r\n if (this.player.state.floating === 'pinned') {\r\n return;\r\n }\r\n\r\n if (entry.intersectionRatio < 0.1 && this._canFloat('auto')) {\r\n // Brief cooldown after an auto-exit prevents the layout reflow that\r\n // accompanies the placeholder→container swap from immediately\r\n // re-triggering auto-float (oscillation guard).\r\n const AUTO_EXIT_COOLDOWN_MS = 500;\r\n if (Date.now() - this._lastAutoExitTime < AUTO_EXIT_COOLDOWN_MS) return;\r\n this.enter('auto');\r\n }\r\n }, { threshold: [0, 0.1, 0.5, 0.9] });\r\n\r\n this.intersectionObserver.observe(this.observerTarget);\r\n }\r\n\r\n _retargetObserver(target: HTMLElement) {\r\n if (!this.intersectionObserver) return;\r\n if (this.observerTarget) {\r\n try { this.intersectionObserver.unobserve(this.observerTarget); } catch { /* ignore */ }\r\n }\r\n this.observerTarget = target;\r\n try { this.intersectionObserver.observe(target); } catch { /* ignore */ }\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: shell DOM\r\n // ---------------------------------------------------------------\r\n\r\n _ensureShell() {\r\n if (this.shell) return;\r\n\r\n this.shell = DOMUtils.createElement('div', {\r\n className: `${this.classPrefix}-floating-shell`,\r\n attributes: {\r\n 'role': 'dialog',\r\n 'aria-modal': 'false',\r\n 'aria-label': i18n.t('player.floatingPlayer'),\r\n 'data-vidply-floating': 'true',\r\n 'tabindex': '-1'\r\n }\r\n });\r\n\r\n this.dragHandle = DOMUtils.createElement('div', {\r\n className: `${this.classPrefix}-floating-drag-handle`,\r\n attributes: { 'aria-hidden': 'true' }\r\n });\r\n this.shell.appendChild(this.dragHandle);\r\n\r\n this.closeButton = DOMUtils.createElement('button', {\r\n className: `${this.classPrefix}-floating-close`,\r\n attributes: {\r\n 'type': 'button',\r\n 'aria-label': i18n.t('player.floatingPlayerClose'),\r\n 'title': i18n.t('player.floatingPlayerClose')\r\n }\r\n }) as HTMLButtonElement;\r\n this.closeButton.appendChild(createIconElement('close'));\r\n this.closeButton.addEventListener('click', (event) => {\r\n event.stopPropagation();\r\n this.dismiss();\r\n });\r\n this.shell.appendChild(this.closeButton);\r\n\r\n this._createResizeHandles();\r\n const shell = this.shell;\r\n this.resizeHandles.forEach(handle => shell.appendChild(handle));\r\n\r\n this._onKeyDown = (event: KeyboardEvent) => {\r\n if (event.key === 'Escape') {\r\n event.stopPropagation();\r\n this.dismiss();\r\n }\r\n };\r\n this.shell.addEventListener('keydown', this._onKeyDown as EventListener);\r\n }\r\n\r\n _createResizeHandles() {\r\n // Resize handles are always-on for the floating shell. Do NOT set\r\n // `data-vidply-managed-resize=\"true\"`: that flag is used by the\r\n // transcript / sign-language overlays to gate the handles behind\r\n // an \"R\" keypress, and DraggableResizable hides managed handles\r\n // during init() — which would leave the shell with no visible or\r\n // hittable edges/corners.\r\n const dirs = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'];\r\n this.resizeHandles = dirs.map(dir => DOMUtils.createElement('div', {\r\n className: `${this.classPrefix}-floating-resize-handle ${this.classPrefix}-floating-resize-${dir}`,\r\n attributes: {\r\n 'data-direction': dir,\r\n 'aria-hidden': 'true'\r\n }\r\n }));\r\n }\r\n\r\n _teardownShell() {\r\n if (this.draggable) {\r\n try { this.draggable.destroy(); } catch { /* ignore */ }\r\n this.draggable = null;\r\n }\r\n if (this.shell) {\r\n if (this._onKeyDown) {\r\n this.shell.removeEventListener('keydown', this._onKeyDown as EventListener);\r\n this._onKeyDown = null;\r\n }\r\n if (this.shell.parentNode) {\r\n this.shell.parentNode.removeChild(this.shell);\r\n }\r\n }\r\n this.shell = null;\r\n this.dragHandle = null;\r\n this.closeButton = null;\r\n this.resizeHandles = [];\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: mount / unmount the player.container\r\n // ---------------------------------------------------------------\r\n\r\n _mountIntoShell() {\r\n const container = this.player.container;\r\n if (!container || !container.parentNode) return;\r\n if (!this.shell) return;\r\n\r\n const rect = container.getBoundingClientRect();\r\n this.originalParent = container.parentNode as HTMLElement;\r\n this.originalNextSibling = container.nextSibling;\r\n\r\n this.placeholder = DOMUtils.createElement('div', {\r\n className: `${this.classPrefix}-floating-placeholder`,\r\n attributes: { 'aria-hidden': 'true' }\r\n });\r\n this.placeholder.style.width = `${Math.max(1, rect.width)}px`;\r\n this.placeholder.style.height = `${Math.max(1, rect.height)}px`;\r\n\r\n // Centred PiP glyph that signals \"video popped out\" in the slot the\r\n // player used to occupy. Lives as a regular child so it can inherit\r\n // currentColor and scale with the placeholder; both the icon and\r\n // the placeholder itself are removed wholesale on _unmountFromShell().\r\n const placeholderIcon = createIconElement('pip', `${this.classPrefix}-floating-placeholder-icon`);\r\n this.placeholder.appendChild(placeholderIcon);\r\n\r\n this.originalParent.insertBefore(this.placeholder, container);\r\n\r\n this.shell.appendChild(container);\r\n document.body.appendChild(this.shell);\r\n\r\n container.classList.add(`${this.classPrefix}-is-floating`);\r\n\r\n // Observe the placeholder while floating so scroll-back decisions are\r\n // anchored to the original slot instead of the moved container.\r\n this._retargetObserver(this.placeholder);\r\n }\r\n\r\n _unmountFromShell() {\r\n const container = this.player.container;\r\n\r\n if (container) {\r\n container.classList.remove(`${this.classPrefix}-is-floating`);\r\n // Clear inline sizes applied while floating\r\n container.style.removeProperty('width');\r\n container.style.removeProperty('height');\r\n }\r\n\r\n if (this.placeholder && this.placeholder.parentNode) {\r\n if (container) {\r\n this.placeholder.parentNode.insertBefore(container, this.placeholder);\r\n }\r\n this.placeholder.parentNode.removeChild(this.placeholder);\r\n } else if (container && this.originalParent) {\r\n if (this.originalNextSibling && this.originalNextSibling.parentNode === this.originalParent) {\r\n this.originalParent.insertBefore(container, this.originalNextSibling);\r\n } else {\r\n this.originalParent.appendChild(container);\r\n }\r\n }\r\n\r\n this.placeholder = null;\r\n this.originalParent = null;\r\n this.originalNextSibling = null;\r\n\r\n // Retarget the observer to the docked container\r\n if (container) {\r\n this._retargetObserver(container);\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: initial geometry + drag/resize wiring\r\n // ---------------------------------------------------------------\r\n\r\n _applyInitialGeometry() {\r\n if (!this.shell) return;\r\n\r\n const prefs = (this.player.storage?.getFloatingPreferences?.() || {}) as FloatingPrefs;\r\n\r\n const vw = window.innerWidth;\r\n const vh = window.innerHeight;\r\n\r\n let width = prefs.width && prefs.width >= MIN_WIDTH ? prefs.width : DEFAULT_WIDTH;\r\n width = Math.min(width, Math.max(MIN_WIDTH, vw - EDGE_MARGIN * 2));\r\n\r\n // If we know the source container's aspect ratio, match it by default.\r\n const containerRect = this.player.container?.getBoundingClientRect();\r\n const aspect = containerRect && containerRect.height > 0\r\n ? containerRect.width / containerRect.height\r\n : 16 / 9;\r\n const defaultHeight = Math.round(width / aspect);\r\n let height = prefs.height && prefs.height >= 100 ? prefs.height : defaultHeight;\r\n height = Math.min(height, Math.max(100, vh - EDGE_MARGIN * 2));\r\n\r\n let left: number;\r\n let top: number;\r\n\r\n if (typeof prefs.left === 'number' && typeof prefs.top === 'number') {\r\n left = Math.max(EDGE_MARGIN, Math.min(prefs.left, vw - width - EDGE_MARGIN));\r\n top = Math.max(EDGE_MARGIN, Math.min(prefs.top, vh - height - EDGE_MARGIN));\r\n } else {\r\n const pos = this.player.options.floatingPosition || 'bottom-right';\r\n switch (pos) {\r\n case 'bottom-left':\r\n left = EDGE_MARGIN;\r\n top = vh - height - EDGE_MARGIN;\r\n break;\r\n case 'top-right':\r\n left = vw - width - EDGE_MARGIN;\r\n top = EDGE_MARGIN;\r\n break;\r\n case 'top-left':\r\n left = EDGE_MARGIN;\r\n top = EDGE_MARGIN;\r\n break;\r\n case 'bottom-right':\r\n default:\r\n left = vw - width - EDGE_MARGIN;\r\n top = vh - height - EDGE_MARGIN;\r\n break;\r\n }\r\n }\r\n\r\n this.shell.style.width = `${width}px`;\r\n this.shell.style.height = `${height}px`;\r\n this.shell.style.left = `${left}px`;\r\n this.shell.style.top = `${top}px`;\r\n\r\n this._initDraggable();\r\n }\r\n\r\n _initDraggable() {\r\n if (!this.shell) return;\r\n if (this.draggable) return;\r\n\r\n this.draggable = new DraggableResizable(this.shell, {\r\n dragHandle: this.dragHandle,\r\n resizeHandles: this.resizeHandles,\r\n constrainToViewport: true,\r\n maintainAspectRatio: true,\r\n minWidth: MIN_WIDTH,\r\n minHeight: 100,\r\n maxWidth: () => Math.max(MIN_WIDTH, window.innerWidth - EDGE_MARGIN * 2),\r\n maxHeight: () => Math.max(100, window.innerHeight - EDGE_MARGIN * 2),\r\n classPrefix: `${this.classPrefix}-floating`,\r\n keyboardDragKey: 'd',\r\n keyboardResizeKey: 'r',\r\n keyboardStep: 10,\r\n keyboardStepLarge: 50,\r\n pointerResizeIndicatorText: i18n.t('player.floatingPlayerDialog'),\r\n onDragEnd: () => this._savePrefs(),\r\n onResizeEnd: () => this._savePrefs(),\r\n onDragStart: (event: Event) => {\r\n const target = event.target as HTMLElement;\r\n if (!target) return true;\r\n // Don't start drag when interacting with the close button or\r\n // with any control inside the embedded player (play/pause,\r\n // captions menu, etc.).\r\n if (target.closest(`.${this.classPrefix}-floating-close`)) return false;\r\n if (target.closest(`.${this.classPrefix}-controls`)) return false;\r\n if (target.closest(`.${this.classPrefix}-floating-resize-handle`)) return false;\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n _savePrefs() {\r\n if (!this.shell || !this.player.storage?.saveFloatingPreferences) return;\r\n const rect = this.shell.getBoundingClientRect();\r\n this.player.storage.saveFloatingPreferences({\r\n width: Math.round(rect.width),\r\n height: Math.round(rect.height),\r\n left: Math.round(rect.left),\r\n top: Math.round(rect.top)\r\n });\r\n }\r\n\r\n _activeElement(): HTMLElement | null {\r\n const active = document.activeElement;\r\n return active && active instanceof HTMLElement ? active : null;\r\n }\r\n}\r\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\r\n * Floating Player Manager\r\n *\r\n * Custom in-page Picture-in-Picture. Moves the entire player.container\r\n * into a position:fixed, draggable and resizable shell that lives outside\r\n * the document flow (appended to document.body). A transparent placeholder\r\n * preserves layout and, while floating, serves as the IntersectionObserver\r\n * sentinel so scroll-based auto-float/redock decisions stay anchored to\r\n * the original slot.\r\n *\r\n * Triggers:\r\n * - pinned: the user clicks the control-bar PiP button (only when\r\n * options.floating is true; otherwise the button uses native PiP).\r\n * Pinned floating ignores scroll-based docking.\r\n * - auto: the video is playing and the original slot has scrolled out\r\n * of the viewport. Auto-float redocks automatically when the slot\r\n * scrolls back in.\r\n *\r\n * Close button: pauses playback, exits the floating shell and marks the\r\n * current play session as dismissed so auto-float will not re-trigger\r\n * until the user presses play again (matches YouTube miniplayer UX).\r\n *\r\n * Only one player is allowed to float at a time across a page; enter()\r\n * broadcasts a 'vidply:floating-claim' CustomEvent that other managers\r\n * listen for and auto-exit on.\r\n */\r\n\r\nimport { DOMUtils } from '../utils/DOMUtils.js';\r\nimport { DraggableResizable } from '../utils/DraggableResizable.js';\r\nimport { createIconElement } from '../icons/Icons.js';\r\nimport { i18n } from '../i18n/i18n.js';\r\nimport type { Player } from './Player.js';\r\n\r\ntype FloatingState = 'pinned' | 'auto';\r\ntype ExitReason = 'manual' | 'auto' | 'dismiss' | 'claim' | 'destroy';\r\n\r\nconst FLOATING_CLAIM_EVENT = 'vidply:floating-claim';\r\nconst DEFAULT_WIDTH = 400;\r\nconst MIN_WIDTH = 240;\r\nconst EDGE_MARGIN = 16;\r\n\r\ninterface FloatingPrefs {\r\n width?: number;\r\n height?: number;\r\n left?: number;\r\n top?: number;\r\n}\r\n\r\nexport class FloatingPlayerManager {\r\n player: Player;\r\n classPrefix: string;\r\n\r\n shell: HTMLElement | null;\r\n dragHandle: HTMLElement | null;\r\n closeButton: HTMLButtonElement | null;\r\n resizeHandles: HTMLElement[];\r\n placeholder: HTMLElement | null;\r\n draggable: DraggableResizable | null;\r\n\r\n originalParent: HTMLElement | null;\r\n originalNextSibling: Node | null;\r\n\r\n intersectionObserver: IntersectionObserver | null;\r\n observerTarget: HTMLElement | null;\r\n lastRatio: number;\r\n\r\n _autoDismissedThisPlay: boolean;\r\n _playListenerAttached: boolean;\r\n _onPlayAfterDismiss: (() => void) | null;\r\n _onClaim: ((event: Event) => void) | null;\r\n _onResize: (() => void) | null;\r\n _onKeyDown: ((event: KeyboardEvent) => void) | null;\r\n _onEnterFullscreen: (() => void) | null;\r\n _destroyed: boolean;\r\n _triggerFocusEl: HTMLElement | null;\r\n _claimId: string;\r\n _lastAutoExitTime: number;\r\n\r\n constructor(player: Player) {\r\n this.player = player;\r\n this.classPrefix = player.options.classPrefix || 'vidply';\r\n\r\n this.shell = null;\r\n this.dragHandle = null;\r\n this.closeButton = null;\r\n this.resizeHandles = [];\r\n this.placeholder = null;\r\n this.draggable = null;\r\n\r\n this.originalParent = null;\r\n this.originalNextSibling = null;\r\n\r\n this.intersectionObserver = null;\r\n this.observerTarget = null;\r\n this.lastRatio = 1;\r\n\r\n this._autoDismissedThisPlay = false;\r\n this._playListenerAttached = false;\r\n this._onPlayAfterDismiss = null;\r\n this._onClaim = null;\r\n this._onResize = null;\r\n this._onKeyDown = null;\r\n this._onEnterFullscreen = null;\r\n this._destroyed = false;\r\n this._triggerFocusEl = null;\r\n this._claimId = `floating-${player.instanceId}-${Date.now()}`;\r\n this._lastAutoExitTime = 0;\r\n\r\n this._setupClaimListener();\r\n this._setupFullscreenGuard();\r\n this._startObserving();\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Public API\r\n // ---------------------------------------------------------------\r\n\r\n togglePinned(triggerEl?: HTMLElement | null) {\r\n if (this._destroyed) return;\r\n if (this.player.state.floating === 'pinned') {\r\n // Manual unpin: suppress auto-float for the remainder of the\r\n // current play session so scrolling doesn't immediately re-pop\r\n // the floating shell. A fresh 'play' event clears the flag.\r\n this._autoDismissedThisPlay = true;\r\n this._armPlayListenerToClearDismiss();\r\n this.exit('manual');\r\n return;\r\n }\r\n // If the user pins while in 'auto' mode, that's an explicit request\r\n // to float; any previous auto-dismiss flag should be cleared so the\r\n // pinned state behaves naturally.\r\n this._autoDismissedThisPlay = false;\r\n this._triggerFocusEl = triggerEl || this._activeElement();\r\n this.enter('pinned');\r\n }\r\n\r\n enter(reason: FloatingState) {\r\n if (this._destroyed) return;\r\n if (this.player.state.floating === reason) return;\r\n\r\n if (!this._canFloat(reason)) {\r\n return;\r\n }\r\n\r\n // Upgrade 'auto' -> 'pinned' without rebuilding the shell\r\n if (this.player.state.floating && this.player.state.floating !== reason) {\r\n this.player.state.floating = reason;\r\n this.player.emit('floatingchange', reason);\r\n return;\r\n }\r\n\r\n this._claimSingleton();\r\n\r\n this._ensureShell();\r\n this._mountIntoShell();\r\n this._applyInitialGeometry();\r\n\r\n this.player.state.floating = reason;\r\n this.player.emit('floatingchange', reason);\r\n\r\n // Focus the close button after a microtask so screen readers announce\r\n // the dialog opening.\r\n queueMicrotask(() => {\r\n if (this.closeButton && this.player.state.floating) {\r\n try { this.closeButton.focus({ preventScroll: true }); } catch { /* ignore */ }\r\n }\r\n });\r\n }\r\n\r\n exit(reason: ExitReason = 'manual') {\r\n if (this._destroyed && reason !== 'destroy') return;\r\n if (!this.player.state.floating) return;\r\n\r\n if (reason === 'auto') {\r\n // Record when an auto-exit occurred so the IntersectionObserver\r\n // callback can apply a cooldown before re-entering auto-float.\r\n this._lastAutoExitTime = Date.now();\r\n }\r\n\r\n this._unmountFromShell();\r\n this._teardownShell();\r\n\r\n const priorTrigger = this._triggerFocusEl;\r\n this._triggerFocusEl = null;\r\n\r\n this.player.state.floating = null;\r\n this.player.emit('floatingchange', null);\r\n\r\n // Restore focus to the element that triggered floating (pinned flow).\r\n // For scroll-based exits we leave focus untouched.\r\n if ((reason === 'manual' || reason === 'dismiss') && priorTrigger) {\r\n try { priorTrigger.focus({ preventScroll: true }); } catch { /* ignore */ }\r\n }\r\n }\r\n\r\n /**\r\n * Close button: pause, dismiss, and prevent auto-float until the next\r\n * user-initiated play event.\r\n */\r\n dismiss() {\r\n if (this._destroyed) return;\r\n this._autoDismissedThisPlay = true;\r\n this._armPlayListenerToClearDismiss();\r\n\r\n try {\r\n this.player.pause();\r\n } catch { /* ignore */ }\r\n\r\n this.exit('dismiss');\r\n }\r\n\r\n destroy() {\r\n if (this._destroyed) return;\r\n this._destroyed = true;\r\n\r\n if (this.player.state && this.player.state.floating) {\r\n try { this.exit('destroy'); } catch { /* ignore */ }\r\n }\r\n\r\n if (this.intersectionObserver) {\r\n try { this.intersectionObserver.disconnect(); } catch { /* ignore */ }\r\n this.intersectionObserver = null;\r\n }\r\n this.observerTarget = null;\r\n\r\n if (this._onClaim) {\r\n window.removeEventListener(FLOATING_CLAIM_EVENT, this._onClaim as EventListener);\r\n this._onClaim = null;\r\n }\r\n if (this._onResize) {\r\n window.removeEventListener('resize', this._onResize);\r\n this._onResize = null;\r\n }\r\n const enterFs = this._onEnterFullscreen;\r\n if (enterFs) {\r\n this.player.off('enterfullscreen', enterFs);\r\n this._onEnterFullscreen = null;\r\n }\r\n const playAfterDismiss = this._onPlayAfterDismiss;\r\n if (playAfterDismiss && this._playListenerAttached) {\r\n this.player.off('play', playAfterDismiss);\r\n this._playListenerAttached = false;\r\n this._onPlayAfterDismiss = null;\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: guards\r\n // ---------------------------------------------------------------\r\n\r\n _canFloat(reason: FloatingState): boolean {\r\n if (!this.player.options.floating) return false;\r\n if (!this.player.container) return false;\r\n if (!this.player.element || this.player.element.tagName !== 'VIDEO') return false;\r\n if (this.player.state.fullscreen) return false;\r\n\r\n // Playlist players move through multiple tracks and manage their own\r\n // UI; floating support for playlists is out of scope for this v1.\r\n if (this.player.playlistManager) return false;\r\n\r\n const minWidth = this.player.options.floatingMinViewportWidth ?? 768;\r\n if (window.innerWidth < minWidth) return false;\r\n\r\n // Auto-float only engages when the user is actively watching.\r\n if (reason === 'auto') {\r\n if (this._autoDismissedThisPlay) return false;\r\n if (this.player.state.paused) return false;\r\n // Never auto-float before the user has started playback; stops\r\n // auto-entry from firing while the page is still below the fold\r\n // on initial load.\r\n if (!this.player.state.hasStartedPlayback) return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n _claimSingleton() {\r\n try {\r\n window.dispatchEvent(new CustomEvent(FLOATING_CLAIM_EVENT, {\r\n detail: { claimId: this._claimId }\r\n }));\r\n } catch { /* ignore (older browsers) */ }\r\n }\r\n\r\n _setupClaimListener() {\r\n this._onClaim = (event: Event) => {\r\n const detail = (event as CustomEvent).detail;\r\n if (!detail || detail.claimId === this._claimId) return;\r\n if (this.player.state.floating) {\r\n this.exit('claim');\r\n }\r\n };\r\n const signal = this.player.lifecycleSignal;\r\n window.addEventListener(FLOATING_CLAIM_EVENT, this._onClaim as EventListener, { signal });\r\n\r\n this._onResize = () => {\r\n const minWidth = this.player.options.floatingMinViewportWidth ?? 768;\r\n if (this.player.state.floating && window.innerWidth < minWidth) {\r\n this.exit('auto');\r\n }\r\n };\r\n window.addEventListener('resize', this._onResize, { signal });\r\n }\r\n\r\n _setupFullscreenGuard() {\r\n const onEnterFullscreen = () => {\r\n if (this.player.state.floating) {\r\n this.exit('manual');\r\n }\r\n };\r\n this._onEnterFullscreen = onEnterFullscreen;\r\n this.player.on('enterfullscreen', onEnterFullscreen);\r\n }\r\n\r\n _armPlayListenerToClearDismiss() {\r\n if (this._playListenerAttached) return;\r\n const onPlayAfterDismiss = () => {\r\n this._autoDismissedThisPlay = false;\r\n const handler = this._onPlayAfterDismiss;\r\n if (handler) {\r\n this.player.off('play', handler);\r\n }\r\n this._playListenerAttached = false;\r\n this._onPlayAfterDismiss = null;\r\n };\r\n this._onPlayAfterDismiss = onPlayAfterDismiss;\r\n this.player.on('play', onPlayAfterDismiss);\r\n this._playListenerAttached = true;\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: IntersectionObserver for scroll-triggered auto-float\r\n // ---------------------------------------------------------------\r\n\r\n _startObserving() {\r\n if (!('IntersectionObserver' in window)) return;\r\n if (!this.player.container) return;\r\n\r\n this.observerTarget = this.player.container;\r\n this.intersectionObserver = new IntersectionObserver((entries) => {\r\n const entry = entries[entries.length - 1];\r\n if (!entry) return;\r\n this.lastRatio = entry.intersectionRatio;\r\n\r\n if (this.player.options.debug) {\r\n try {\r\n console.log('[vidply:floating] intersection', {\r\n ratio: Number(entry.intersectionRatio.toFixed(3)),\r\n state: this.player.state.floating,\r\n paused: this.player.state.paused,\r\n hasStartedPlayback: this.player.state.hasStartedPlayback,\r\n dismissed: this._autoDismissedThisPlay\r\n });\r\n } catch { /* ignore */ }\r\n }\r\n\r\n if (this.player.state.floating === 'auto') {\r\n if (entry.intersectionRatio >= 0.5) {\r\n this.exit('auto');\r\n }\r\n return;\r\n }\r\n\r\n // Pinned state: scroll is a no-op, the user has taken control.\r\n if (this.player.state.floating === 'pinned') {\r\n return;\r\n }\r\n\r\n if (entry.intersectionRatio < 0.1 && this._canFloat('auto')) {\r\n // Brief cooldown after an auto-exit prevents the layout reflow that\r\n // accompanies the placeholder→container swap from immediately\r\n // re-triggering auto-float (oscillation guard).\r\n const AUTO_EXIT_COOLDOWN_MS = 500;\r\n if (Date.now() - this._lastAutoExitTime < AUTO_EXIT_COOLDOWN_MS) return;\r\n this.enter('auto');\r\n }\r\n }, { threshold: [0, 0.1, 0.5, 0.9] });\r\n\r\n this.intersectionObserver.observe(this.observerTarget);\r\n }\r\n\r\n _retargetObserver(target: HTMLElement) {\r\n if (!this.intersectionObserver) return;\r\n if (this.observerTarget) {\r\n try { this.intersectionObserver.unobserve(this.observerTarget); } catch { /* ignore */ }\r\n }\r\n this.observerTarget = target;\r\n try { this.intersectionObserver.observe(target); } catch { /* ignore */ }\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: shell DOM\r\n // ---------------------------------------------------------------\r\n\r\n _ensureShell() {\r\n if (this.shell) return;\r\n\r\n this.shell = DOMUtils.createElement('div', {\r\n className: `${this.classPrefix}-floating-shell`,\r\n attributes: {\r\n 'role': 'dialog',\r\n 'aria-modal': 'false',\r\n 'aria-label': i18n.t('player.floatingPlayer'),\r\n 'data-vidply-floating': 'true',\r\n 'tabindex': '-1'\r\n }\r\n });\r\n\r\n this.dragHandle = DOMUtils.createElement('div', {\r\n className: `${this.classPrefix}-floating-drag-handle`,\r\n attributes: { 'aria-hidden': 'true' }\r\n });\r\n this.shell.appendChild(this.dragHandle);\r\n\r\n this.closeButton = DOMUtils.createElement('button', {\r\n className: `${this.classPrefix}-floating-close`,\r\n attributes: {\r\n 'type': 'button',\r\n 'aria-label': i18n.t('player.floatingPlayerClose'),\r\n 'title': i18n.t('player.floatingPlayerClose')\r\n }\r\n }) as HTMLButtonElement;\r\n this.closeButton.appendChild(createIconElement('close'));\r\n this.closeButton.addEventListener('click', (event) => {\r\n event.stopPropagation();\r\n this.dismiss();\r\n });\r\n this.shell.appendChild(this.closeButton);\r\n\r\n this._createResizeHandles();\r\n const shell = this.shell;\r\n this.resizeHandles.forEach(handle => shell.appendChild(handle));\r\n\r\n this._onKeyDown = (event: KeyboardEvent) => {\r\n if (event.key === 'Escape') {\r\n // If the user is in keyboard drag / resize (or pointer-resize)\r\n // mode, Escape must exit that mode first — not dismiss the\r\n // whole floating player. This listener is registered before the\r\n // DraggableResizable one, so we let the event fall through to\r\n // it (no dismiss, no stopPropagation) while a mode is active\r\n // (WCAG 2.1.1). Only a \"neutral\" Escape dismisses.\r\n const d = this.draggable;\r\n const inEditMode = !!d && (d.keyboardDragMode || d.keyboardResizeMode || d.pointerResizeMode);\r\n if (inEditMode) {\r\n return;\r\n }\r\n event.stopPropagation();\r\n this.dismiss();\r\n }\r\n };\r\n this.shell.addEventListener('keydown', this._onKeyDown as EventListener);\r\n }\r\n\r\n _createResizeHandles() {\r\n // Resize handles are always-on for the floating shell. Do NOT set\r\n // `data-vidply-managed-resize=\"true\"`: that flag is used by the\r\n // transcript / sign-language overlays to gate the handles behind\r\n // an \"R\" keypress, and DraggableResizable hides managed handles\r\n // during init() — which would leave the shell with no visible or\r\n // hittable edges/corners.\r\n const dirs = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'];\r\n this.resizeHandles = dirs.map(dir => DOMUtils.createElement('div', {\r\n className: `${this.classPrefix}-floating-resize-handle ${this.classPrefix}-floating-resize-${dir}`,\r\n attributes: {\r\n 'data-direction': dir,\r\n 'aria-hidden': 'true'\r\n }\r\n }));\r\n }\r\n\r\n _teardownShell() {\r\n if (this.draggable) {\r\n try { this.draggable.destroy(); } catch { /* ignore */ }\r\n this.draggable = null;\r\n }\r\n if (this.shell) {\r\n if (this._onKeyDown) {\r\n this.shell.removeEventListener('keydown', this._onKeyDown as EventListener);\r\n this._onKeyDown = null;\r\n }\r\n if (this.shell.parentNode) {\r\n this.shell.parentNode.removeChild(this.shell);\r\n }\r\n }\r\n this.shell = null;\r\n this.dragHandle = null;\r\n this.closeButton = null;\r\n this.resizeHandles = [];\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: mount / unmount the player.container\r\n // ---------------------------------------------------------------\r\n\r\n _mountIntoShell() {\r\n const container = this.player.container;\r\n if (!container || !container.parentNode) return;\r\n if (!this.shell) return;\r\n\r\n const rect = container.getBoundingClientRect();\r\n this.originalParent = container.parentNode as HTMLElement;\r\n this.originalNextSibling = container.nextSibling;\r\n\r\n this.placeholder = DOMUtils.createElement('div', {\r\n className: `${this.classPrefix}-floating-placeholder`,\r\n attributes: { 'aria-hidden': 'true' }\r\n });\r\n this.placeholder.style.width = `${Math.max(1, rect.width)}px`;\r\n this.placeholder.style.height = `${Math.max(1, rect.height)}px`;\r\n\r\n // Centred PiP glyph that signals \"video popped out\" in the slot the\r\n // player used to occupy. Lives as a regular child so it can inherit\r\n // currentColor and scale with the placeholder; both the icon and\r\n // the placeholder itself are removed wholesale on _unmountFromShell().\r\n const placeholderIcon = createIconElement('pip', `${this.classPrefix}-floating-placeholder-icon`);\r\n this.placeholder.appendChild(placeholderIcon);\r\n\r\n this.originalParent.insertBefore(this.placeholder, container);\r\n\r\n this.shell.appendChild(container);\r\n document.body.appendChild(this.shell);\r\n\r\n container.classList.add(`${this.classPrefix}-is-floating`);\r\n\r\n // Observe the placeholder while floating so scroll-back decisions are\r\n // anchored to the original slot instead of the moved container.\r\n this._retargetObserver(this.placeholder);\r\n }\r\n\r\n _unmountFromShell() {\r\n const container = this.player.container;\r\n\r\n if (container) {\r\n container.classList.remove(`${this.classPrefix}-is-floating`);\r\n // Clear inline sizes applied while floating\r\n container.style.removeProperty('width');\r\n container.style.removeProperty('height');\r\n }\r\n\r\n if (this.placeholder && this.placeholder.parentNode) {\r\n if (container) {\r\n this.placeholder.parentNode.insertBefore(container, this.placeholder);\r\n }\r\n this.placeholder.parentNode.removeChild(this.placeholder);\r\n } else if (container && this.originalParent) {\r\n if (this.originalNextSibling && this.originalNextSibling.parentNode === this.originalParent) {\r\n this.originalParent.insertBefore(container, this.originalNextSibling);\r\n } else {\r\n this.originalParent.appendChild(container);\r\n }\r\n }\r\n\r\n this.placeholder = null;\r\n this.originalParent = null;\r\n this.originalNextSibling = null;\r\n\r\n // Retarget the observer to the docked container\r\n if (container) {\r\n this._retargetObserver(container);\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------\r\n // Internal: initial geometry + drag/resize wiring\r\n // ---------------------------------------------------------------\r\n\r\n _applyInitialGeometry() {\r\n if (!this.shell) return;\r\n\r\n const prefs = (this.player.storage?.getFloatingPreferences?.() || {}) as FloatingPrefs;\r\n\r\n const vw = window.innerWidth;\r\n const vh = window.innerHeight;\r\n\r\n let width = prefs.width && prefs.width >= MIN_WIDTH ? prefs.width : DEFAULT_WIDTH;\r\n width = Math.min(width, Math.max(MIN_WIDTH, vw - EDGE_MARGIN * 2));\r\n\r\n // If we know the source container's aspect ratio, match it by default.\r\n const containerRect = this.player.container?.getBoundingClientRect();\r\n const aspect = containerRect && containerRect.height > 0\r\n ? containerRect.width / containerRect.height\r\n : 16 / 9;\r\n const defaultHeight = Math.round(width / aspect);\r\n let height = prefs.height && prefs.height >= 100 ? prefs.height : defaultHeight;\r\n height = Math.min(height, Math.max(100, vh - EDGE_MARGIN * 2));\r\n\r\n let left: number;\r\n let top: number;\r\n\r\n if (typeof prefs.left === 'number' && typeof prefs.top === 'number') {\r\n left = Math.max(EDGE_MARGIN, Math.min(prefs.left, vw - width - EDGE_MARGIN));\r\n top = Math.max(EDGE_MARGIN, Math.min(prefs.top, vh - height - EDGE_MARGIN));\r\n } else {\r\n const pos = this.player.options.floatingPosition || 'bottom-right';\r\n switch (pos) {\r\n case 'bottom-left':\r\n left = EDGE_MARGIN;\r\n top = vh - height - EDGE_MARGIN;\r\n break;\r\n case 'top-right':\r\n left = vw - width - EDGE_MARGIN;\r\n top = EDGE_MARGIN;\r\n break;\r\n case 'top-left':\r\n left = EDGE_MARGIN;\r\n top = EDGE_MARGIN;\r\n break;\r\n case 'bottom-right':\r\n default:\r\n left = vw - width - EDGE_MARGIN;\r\n top = vh - height - EDGE_MARGIN;\r\n break;\r\n }\r\n }\r\n\r\n this.shell.style.width = `${width}px`;\r\n this.shell.style.height = `${height}px`;\r\n this.shell.style.left = `${left}px`;\r\n this.shell.style.top = `${top}px`;\r\n\r\n this._initDraggable();\r\n }\r\n\r\n _initDraggable() {\r\n if (!this.shell) return;\r\n if (this.draggable) return;\r\n\r\n this.draggable = new DraggableResizable(this.shell, {\r\n dragHandle: this.dragHandle,\r\n resizeHandles: this.resizeHandles,\r\n constrainToViewport: true,\r\n maintainAspectRatio: true,\r\n minWidth: MIN_WIDTH,\r\n minHeight: 100,\r\n maxWidth: () => Math.max(MIN_WIDTH, window.innerWidth - EDGE_MARGIN * 2),\r\n maxHeight: () => Math.max(100, window.innerHeight - EDGE_MARGIN * 2),\r\n classPrefix: `${this.classPrefix}-floating`,\r\n keyboardDragKey: 'd',\r\n keyboardResizeKey: 'r',\r\n keyboardStep: 10,\r\n keyboardStepLarge: 50,\r\n pointerResizeIndicatorText: i18n.t('player.floatingPlayerDialog'),\r\n onDragEnd: () => this._savePrefs(),\r\n onResizeEnd: () => this._savePrefs(),\r\n onDragStart: (event: Event) => {\r\n const target = event.target as HTMLElement;\r\n if (!target) return true;\r\n // Don't start drag when interacting with the close button or\r\n // with any control inside the embedded player (play/pause,\r\n // captions menu, etc.).\r\n if (target.closest(`.${this.classPrefix}-floating-close`)) return false;\r\n if (target.closest(`.${this.classPrefix}-controls`)) return false;\r\n if (target.closest(`.${this.classPrefix}-floating-resize-handle`)) return false;\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n _savePrefs() {\r\n if (!this.shell || !this.player.storage?.saveFloatingPreferences) return;\r\n const rect = this.shell.getBoundingClientRect();\r\n this.player.storage.saveFloatingPreferences({\r\n width: Math.round(rect.width),\r\n height: Math.round(rect.height),\r\n left: Math.round(rect.left),\r\n top: Math.round(rect.top)\r\n });\r\n }\r\n\r\n _activeElement(): HTMLElement | null {\r\n const active = document.activeElement;\r\n return active && active instanceof HTMLElement ? active : null;\r\n }\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|