vidply 1.2.0 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +974 -946
- package/dist/dev/{vidply.AudioDescriptionManager-R47Q4YR4.js → vidply.AudioDescriptionManager-JYYLK5KB.js} +275 -19
- package/dist/dev/vidply.AudioDescriptionManager-JYYLK5KB.js.map +7 -0
- package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js → vidply.CaptionStyleMenu-47RCKQF5.js} +4 -4
- package/dist/dev/{vidply.DASHRenderer-PWEMC3BT.js → vidply.DASHRenderer-VEJ4HDHO.js} +3 -3
- package/dist/dev/vidply.DASHRenderer-VEJ4HDHO.js.map +7 -0
- package/dist/dev/{vidply.FloatingPlayerManager-PKNNNAS2.js → vidply.FloatingPlayerManager-C2UVRPZY.js} +5 -5
- package/dist/dev/vidply.FloatingPlayerManager-C2UVRPZY.js.map +7 -0
- package/dist/dev/{vidply.HLSRenderer-E7RQ74HI.js → vidply.HLSRenderer-ZVBK2TNQ.js} +4 -4
- package/dist/dev/vidply.HLSRenderer-ZVBK2TNQ.js.map +7 -0
- package/dist/dev/vidply.HTML5Renderer-HLRQUOCU.js +12 -0
- package/dist/dev/{vidply.SignLanguageManager-FET5FQZ7.js → vidply.SignLanguageManager-FLUCBW5H.js} +8 -8
- package/dist/dev/vidply.SignLanguageManager-FLUCBW5H.js.map +7 -0
- package/dist/dev/{vidply.SoundCloudRenderer-RVSJZODO.js → vidply.SoundCloudRenderer-MGMAJ7NK.js} +3 -3
- package/dist/dev/vidply.SoundCloudRenderer-MGMAJ7NK.js.map +7 -0
- package/dist/dev/{vidply.TranscriptManager-5GXOQCLX.js → vidply.TranscriptManager-Y2RYXHJW.js} +10 -10
- package/dist/dev/vidply.TranscriptManager-Y2RYXHJW.js.map +7 -0
- package/dist/dev/{vidply.VimeoRenderer-ER2LSBBW.js → vidply.VimeoRenderer-RQFQD7OE.js} +3 -3
- package/dist/dev/vidply.VimeoRenderer-RQFQD7OE.js.map +7 -0
- package/dist/dev/{vidply.YouTubeRenderer-NFTOWJAB.js → vidply.YouTubeRenderer-EU2BARZF.js} +3 -3
- package/dist/dev/vidply.YouTubeRenderer-EU2BARZF.js.map +7 -0
- package/dist/dev/{vidply.chunk-BNFIUL2Z.js → vidply.chunk-6LYZYI5G.js} +3 -3
- package/dist/dev/vidply.chunk-6LYZYI5G.js.map +7 -0
- package/dist/dev/{vidply.chunk-NQPURMQY.js → vidply.chunk-A4ESEOQ2.js} +6 -6
- package/dist/dev/vidply.chunk-A4ESEOQ2.js.map +7 -0
- package/dist/dev/{vidply.chunk-W25HUCHS.js → vidply.chunk-CGYIED2I.js} +2 -2
- package/dist/dev/vidply.chunk-CGYIED2I.js.map +7 -0
- package/dist/dev/{vidply.chunk-SK4V2DAU.js → vidply.chunk-HZ7UOKOU.js} +3 -3
- package/dist/dev/{vidply.chunk-RZWZGDV7.js → vidply.chunk-I6EDRYGJ.js} +33 -6
- package/dist/dev/vidply.chunk-I6EDRYGJ.js.map +7 -0
- package/dist/dev/{vidply.chunk-64WXMTGL.js → vidply.chunk-JKMQGLCJ.js} +5 -5
- package/dist/dev/vidply.chunk-JKMQGLCJ.js.map +7 -0
- package/dist/dev/{vidply.chunk-DZSDO3B7.js → vidply.chunk-JZNZX32Z.js} +2 -2
- package/dist/dev/{vidply.chunk-VMSQAZM7.js → vidply.chunk-P25MRJ6O.js} +2 -2
- package/dist/dev/{vidply.chunk-6RQA4ROD.js → vidply.chunk-PRFNESYA.js} +2 -2
- package/dist/dev/{vidply.chunk-KI7C3QVL.js → vidply.chunk-UI3RYCVF.js} +4 -3
- package/dist/dev/vidply.chunk-UI3RYCVF.js.map +7 -0
- package/dist/dev/{vidply.chunk-JJ47NO24.js → vidply.chunk-UNFGMABP.js} +2 -2
- package/dist/dev/vidply.chunk-UNFGMABP.js.map +7 -0
- package/dist/dev/{vidply.de-4YAT7FFM.js → vidply.de-VAUVSQXC.js} +29 -2
- package/dist/dev/vidply.de-VAUVSQXC.js.map +7 -0
- package/dist/dev/{vidply.es-LEWIRUBH.js → vidply.es-G65HFWO6.js} +29 -2
- package/dist/dev/vidply.es-G65HFWO6.js.map +7 -0
- package/dist/dev/vidply.esm.js +648 -35
- package/dist/dev/vidply.esm.js.map +3 -3
- package/dist/dev/{vidply.fr-Q4GV2NOE.js → vidply.fr-MJNOZELM.js} +29 -2
- package/dist/dev/vidply.fr-MJNOZELM.js.map +7 -0
- package/dist/dev/{vidply.ja-S6ITA6WU.js → vidply.ja-INMDHIYJ.js} +29 -2
- package/dist/dev/vidply.ja-INMDHIYJ.js.map +7 -0
- package/dist/legacy/vidply.js +1062 -34
- package/dist/legacy/vidply.js.map +3 -3
- package/dist/legacy/vidply.min.js +2 -2
- package/dist/legacy/vidply.min.meta.json +127 -55
- package/dist/prod/vidply.AudioDescriptionManager-EKWUNOPE.min.js +6 -0
- package/dist/prod/{vidply.CaptionStyleMenu-M3KVQWB5.min.js → vidply.CaptionStyleMenu-JTWSNHRQ.min.js} +2 -2
- package/dist/prod/{vidply.DASHRenderer-DN3S27AV.min.js → vidply.DASHRenderer-CIDAHFWM.min.js} +2 -2
- package/dist/prod/{vidply.FloatingPlayerManager-SKAZ4J43.min.js → vidply.FloatingPlayerManager-VZXHPCPM.min.js} +2 -2
- package/dist/prod/{vidply.HLSRenderer-62HH4YTK.min.js → vidply.HLSRenderer-Q6EFYKID.min.js} +2 -2
- package/dist/prod/vidply.HTML5Renderer-XRDJUTOO.min.js +6 -0
- package/dist/prod/{vidply.SignLanguageManager-V3OBTSSF.min.js → vidply.SignLanguageManager-JUOSA5AM.min.js} +2 -2
- package/dist/prod/{vidply.SoundCloudRenderer-CXRVZIAJ.min.js → vidply.SoundCloudRenderer-7ODD46PO.min.js} +2 -2
- package/dist/prod/{vidply.TranscriptManager-SYM3DFUY.min.js → vidply.TranscriptManager-4B2QKYGQ.min.js} +2 -2
- package/dist/prod/{vidply.VimeoRenderer-72TWRYFQ.min.js → vidply.VimeoRenderer-MR3UYLY7.min.js} +2 -2
- package/dist/prod/{vidply.YouTubeRenderer-UMHEV3KD.min.js → vidply.YouTubeRenderer-ITRTC7NR.min.js} +2 -2
- package/dist/prod/{vidply.chunk-YEENJS3Q.min.js → vidply.chunk-3EEDXU4T.min.js} +2 -2
- package/dist/prod/{vidply.chunk-P4UXOHWA.min.js → vidply.chunk-5HTX5QXW.min.js} +1 -1
- package/dist/prod/{vidply.chunk-ABPXVDLZ.min.js → vidply.chunk-6OGHHIYP.min.js} +2 -2
- package/dist/prod/{vidply.chunk-UK7YGOB5.min.js → vidply.chunk-GUPGMFUZ.min.js} +2 -2
- package/dist/prod/{vidply.chunk-WX3MVEAL.min.js → vidply.chunk-MWEBITCP.min.js} +1 -1
- package/dist/prod/{vidply.chunk-2TB6MUHO.min.js → vidply.chunk-PL3P3JHR.min.js} +1 -1
- package/dist/prod/{vidply.chunk-EKEYJWMG.min.js → vidply.chunk-QQZGV7TD.min.js} +2 -2
- package/dist/prod/{vidply.chunk-Z3YDSA7O.min.js → vidply.chunk-U5IRRYG5.min.js} +1 -1
- package/dist/prod/{vidply.chunk-TM6AXJVD.min.js → vidply.chunk-VKHV4QHA.min.js} +2 -2
- package/dist/prod/{vidply.chunk-P3PQBY7N.min.js → vidply.chunk-XA4M574A.min.js} +1 -1
- package/dist/prod/{vidply.chunk-RI3X7WHK.min.js → vidply.chunk-ZPTV4JEP.min.js} +2 -2
- package/dist/prod/{vidply.de-BCHXRQ53.min.js → vidply.de-UZHFCEZU.min.js} +2 -2
- package/dist/prod/{vidply.es-PICAKMZD.min.js → vidply.es-BOISUV2S.min.js} +2 -2
- package/dist/prod/vidply.esm.min.js +2 -2
- package/dist/prod/{vidply.fr-ZILI7CDR.min.js → vidply.fr-ICSMKPFM.min.js} +2 -2
- package/dist/prod/{vidply.ja-5WQ4OK4J.min.js → vidply.ja-VQ2HKGAY.min.js} +2 -2
- package/dist/vidply.css +5852 -5796
- package/dist/vidply.esm.min.meta.json +204 -149
- package/dist/vidply.min.css +1 -1
- package/package.json +11 -11
- package/src/controls/CaptionManager.ts +598 -598
- package/src/controls/ControlBar.ts +4191 -4159
- package/src/controls/KeyboardHelp.ts +326 -0
- package/src/controls/KeyboardManager.ts +387 -383
- package/src/controls/SettingsDialog.ts +488 -488
- package/src/controls/TranscriptManager.ts +2426 -2426
- package/src/core/AudioDescriptionManager.ts +863 -774
- package/src/core/DescriptionSpeechManager.ts +232 -0
- package/src/core/FloatingPlayerManager.ts +674 -674
- package/src/core/LazyInit.ts +80 -80
- package/src/core/MediaSessionManager.ts +341 -0
- package/src/core/MetadataAlertsManager.ts +514 -514
- package/src/core/Player.ts +2973 -2872
- package/src/core/PosterManager.ts +169 -169
- package/src/core/PseudoFullscreen.ts +179 -179
- package/src/core/ResponsiveManager.ts +231 -231
- package/src/core/ResumeManager.ts +236 -236
- package/src/core/SignLanguageManager.ts +1308 -1308
- package/src/core/ThemeManager.ts +157 -157
- package/src/features/PlaylistManager.ts +1838 -1827
- package/src/i18n/i18n.ts +223 -223
- package/src/i18n/languages/de.ts +244 -217
- package/src/i18n/languages/en.ts +245 -218
- package/src/i18n/languages/es.ts +241 -214
- package/src/i18n/languages/fr.ts +241 -214
- package/src/i18n/languages/ja.ts +241 -214
- package/src/icons/Icons.ts +168 -167
- package/src/index.ts +196 -193
- package/src/renderers/DASHRenderer.ts +1077 -1077
- package/src/renderers/HLSRenderer.ts +944 -944
- package/src/renderers/HTML5Renderer.ts +389 -389
- package/src/renderers/SoundCloudRenderer.ts +437 -437
- package/src/renderers/VimeoRenderer.ts +298 -298
- package/src/renderers/YouTubeRenderer.ts +290 -290
- package/src/styles/vidply.css +5852 -5796
- package/src/types/events.ts +128 -122
- package/src/types/globals.d.ts +313 -313
- package/src/types/options.ts +199 -182
- package/src/types/renderer.ts +58 -58
- package/src/utils/DOMUtils.ts +281 -281
- package/src/utils/DownloadInfo.ts +171 -171
- package/src/utils/DraggablePanel.ts +539 -539
- package/src/utils/DraggablePanelMenu.ts +195 -195
- package/src/utils/DraggableResizable.ts +997 -997
- package/src/utils/EventEmitter.ts +59 -59
- package/src/utils/FormUtils.ts +95 -95
- package/src/utils/MenuFactory.ts +483 -483
- package/src/utils/Sanitize.ts +70 -70
- package/src/utils/SettingsMenuFactory.ts +289 -289
- package/src/utils/StorageManager.ts +287 -287
- package/src/utils/TrackLabelUtils.ts +52 -52
- package/src/utils/UrlSafe.ts +69 -69
- package/src/utils/VideoFrameCapture.ts +114 -114
- package/src/utils/WindowComponents.ts +250 -250
- package/dist/dev/vidply.AudioDescriptionManager-R47Q4YR4.js.map +0 -7
- package/dist/dev/vidply.DASHRenderer-PWEMC3BT.js.map +0 -7
- package/dist/dev/vidply.FloatingPlayerManager-PKNNNAS2.js.map +0 -7
- package/dist/dev/vidply.HLSRenderer-E7RQ74HI.js.map +0 -7
- package/dist/dev/vidply.HTML5Renderer-BU4QJJJY.js +0 -12
- package/dist/dev/vidply.SignLanguageManager-FET5FQZ7.js.map +0 -7
- package/dist/dev/vidply.SoundCloudRenderer-RVSJZODO.js.map +0 -7
- package/dist/dev/vidply.TranscriptManager-5GXOQCLX.js.map +0 -7
- package/dist/dev/vidply.VimeoRenderer-ER2LSBBW.js.map +0 -7
- package/dist/dev/vidply.YouTubeRenderer-NFTOWJAB.js.map +0 -7
- package/dist/dev/vidply.chunk-64WXMTGL.js.map +0 -7
- package/dist/dev/vidply.chunk-BNFIUL2Z.js.map +0 -7
- package/dist/dev/vidply.chunk-JJ47NO24.js.map +0 -7
- package/dist/dev/vidply.chunk-KI7C3QVL.js.map +0 -7
- package/dist/dev/vidply.chunk-NQPURMQY.js.map +0 -7
- package/dist/dev/vidply.chunk-RZWZGDV7.js.map +0 -7
- package/dist/dev/vidply.chunk-W25HUCHS.js.map +0 -7
- package/dist/dev/vidply.de-4YAT7FFM.js.map +0 -7
- package/dist/dev/vidply.es-LEWIRUBH.js.map +0 -7
- package/dist/dev/vidply.fr-Q4GV2NOE.js.map +0 -7
- package/dist/dev/vidply.ja-S6ITA6WU.js.map +0 -7
- package/dist/prod/vidply.AudioDescriptionManager-RHLIJW5C.min.js +0 -6
- package/dist/prod/vidply.HTML5Renderer-IU5T3WEW.min.js +0 -6
- /package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js.map → vidply.CaptionStyleMenu-47RCKQF5.js.map} +0 -0
- /package/dist/dev/{vidply.HTML5Renderer-BU4QJJJY.js.map → vidply.HTML5Renderer-HLRQUOCU.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-SK4V2DAU.js.map → vidply.chunk-HZ7UOKOU.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-DZSDO3B7.js.map → vidply.chunk-JZNZX32Z.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-VMSQAZM7.js.map → vidply.chunk-P25MRJ6O.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-6RQA4ROD.js.map → vidply.chunk-PRFNESYA.js.map} +0 -0
|
@@ -1,231 +1,231 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resize / orientation / fullscreen handling extracted from Player.
|
|
3
|
-
*
|
|
4
|
-
* Three responsibilities live here:
|
|
5
|
-
*
|
|
6
|
-
* 1. Reacting to container size changes (ResizeObserver when
|
|
7
|
-
* available, `window.resize` fallback otherwise) so the control
|
|
8
|
-
* bar and the transcript panel stay correctly laid out.
|
|
9
|
-
* 2. Listening for orientation changes on mobile so the transcript
|
|
10
|
-
* panel re-positions after the viewport rotates.
|
|
11
|
-
* 3. Tracking native fullscreen changes across vendor prefixes so
|
|
12
|
-
* `state.fullscreen` stays in sync with reality — including the
|
|
13
|
-
* inert/overlay bookkeeping that's shared with the pseudo-
|
|
14
|
-
* fullscreen fallback.
|
|
15
|
-
*
|
|
16
|
-
* Every listener is attached with the Player's `lifecycleSignal`
|
|
17
|
-
* (or, for the ResizeObserver / older matchMedia listeners that
|
|
18
|
-
* don't accept AbortSignal, cleaned up explicitly in `cleanup()`).
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { PseudoFullscreenController } from './PseudoFullscreen.js';
|
|
22
|
-
import type { ControlBar } from '../controls/ControlBar.js';
|
|
23
|
-
import type { Player } from './Player.js';
|
|
24
|
-
|
|
25
|
-
export class ResponsiveManager {
|
|
26
|
-
private readonly player: Player;
|
|
27
|
-
private orientationQuery: MediaQueryList | null = null;
|
|
28
|
-
private orientationHandler: ((e: MediaQueryListEvent) => void) | null = null;
|
|
29
|
-
|
|
30
|
-
constructor(player: Player) {
|
|
31
|
-
this.player = player;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
setup(): void {
|
|
35
|
-
this.setupResizeTracking();
|
|
36
|
-
this.setupOrientationTracking();
|
|
37
|
-
this.setupFullscreenTracking();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private setupResizeTracking(): void {
|
|
41
|
-
const player = this.player;
|
|
42
|
-
|
|
43
|
-
if (typeof ResizeObserver !== 'undefined') {
|
|
44
|
-
// Preferred path: ResizeObserver fires per-container, not per-viewport,
|
|
45
|
-
// so multiple players on one page don't stomp on each other.
|
|
46
|
-
player.resizeObserver = new ResizeObserver((entries) => {
|
|
47
|
-
for (const entry of entries) {
|
|
48
|
-
const width = entry.contentRect.width;
|
|
49
|
-
|
|
50
|
-
const controlBar = player.controlBar as (ControlBar & {
|
|
51
|
-
updateControlsForViewport?: (w: number) => void
|
|
52
|
-
}) | null;
|
|
53
|
-
if (controlBar && typeof controlBar.updateControlsForViewport === 'function') {
|
|
54
|
-
controlBar.updateControlsForViewport(width);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (player.transcriptManager && player.transcriptManager.isVisible) {
|
|
58
|
-
player.transcriptManager.positionTranscript();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
player.resizeObserver.observe(player.container);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Fallback: `window.resize`. We still respect
|
|
68
|
-
// `draggableResizable.manuallyPositioned` so we don't stomp on a
|
|
69
|
-
// user-chosen transcript location.
|
|
70
|
-
player.resizeHandler = () => {
|
|
71
|
-
const width = player.container.clientWidth;
|
|
72
|
-
|
|
73
|
-
const controlBar = player.controlBar as (ControlBar & {
|
|
74
|
-
updateControlsForViewport?: (w: number) => void
|
|
75
|
-
}) | null;
|
|
76
|
-
if (controlBar && typeof controlBar.updateControlsForViewport === 'function') {
|
|
77
|
-
controlBar.updateControlsForViewport(width);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (player.transcriptManager && player.transcriptManager.isVisible) {
|
|
81
|
-
if (!player.transcriptManager.draggableResizable
|
|
82
|
-
|| !player.transcriptManager.draggableResizable.manuallyPositioned) {
|
|
83
|
-
player.transcriptManager.positionTranscript();
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
window.addEventListener('resize', player.resizeHandler, { signal: player.lifecycleSignal });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
private setupOrientationTracking(): void {
|
|
92
|
-
const player = this.player;
|
|
93
|
-
if (!window.matchMedia) return;
|
|
94
|
-
|
|
95
|
-
this.orientationHandler = () => {
|
|
96
|
-
// Wait for layout to settle before we recompute positions —
|
|
97
|
-
// otherwise `getBoundingClientRect` still reflects the
|
|
98
|
-
// pre-rotation viewport.
|
|
99
|
-
setTimeout(() => {
|
|
100
|
-
if (player.transcriptManager && player.transcriptManager.isVisible) {
|
|
101
|
-
if (!player.transcriptManager.draggableResizable
|
|
102
|
-
|| !player.transcriptManager.draggableResizable.manuallyPositioned) {
|
|
103
|
-
player.transcriptManager.positionTranscript();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}, 100);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const orientationQuery = window.matchMedia('(orientation: portrait)');
|
|
110
|
-
if (orientationQuery.addEventListener) {
|
|
111
|
-
// Modern MediaQueryList supports AddEventListenerOptions including
|
|
112
|
-
// `signal`, so teardown happens automatically via the player's
|
|
113
|
-
// lifecycle AbortController.
|
|
114
|
-
orientationQuery.addEventListener('change', this.orientationHandler, {
|
|
115
|
-
signal: player.lifecycleSignal
|
|
116
|
-
});
|
|
117
|
-
} else if ((orientationQuery as MediaQueryList).addListener) {
|
|
118
|
-
// Older Safari: no signal support; `cleanup()` will remove this
|
|
119
|
-
// explicitly below.
|
|
120
|
-
(orientationQuery as MediaQueryList).addListener(this.orientationHandler);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
this.orientationQuery = orientationQuery;
|
|
124
|
-
// Mirror the field onto the player too; some older call sites
|
|
125
|
-
// reach for `player.orientationQuery` directly.
|
|
126
|
-
player.orientationQuery = orientationQuery;
|
|
127
|
-
player.orientationHandler = this.orientationHandler;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private setupFullscreenTracking(): void {
|
|
131
|
-
const player = this.player;
|
|
132
|
-
|
|
133
|
-
player.fullscreenChangeHandler = () => {
|
|
134
|
-
const doc = document as Document & {
|
|
135
|
-
webkitFullscreenElement?: Element | null;
|
|
136
|
-
mozFullScreenElement?: Element | null;
|
|
137
|
-
msFullscreenElement?: Element | null;
|
|
138
|
-
};
|
|
139
|
-
const isFullscreen = Boolean(
|
|
140
|
-
document.fullscreenElement ||
|
|
141
|
-
doc.webkitFullscreenElement ||
|
|
142
|
-
doc.mozFullScreenElement ||
|
|
143
|
-
doc.msFullscreenElement
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
if (player.state.fullscreen === isFullscreen) return;
|
|
147
|
-
|
|
148
|
-
player.state.fullscreen = isFullscreen;
|
|
149
|
-
|
|
150
|
-
if (!player.pseudoFullscreen) {
|
|
151
|
-
player.pseudoFullscreen = new PseudoFullscreenController(player);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (isFullscreen) {
|
|
155
|
-
player.container.classList.add(`${player.options.classPrefix}-fullscreen`);
|
|
156
|
-
// CSS fallback for browsers without :has() support.
|
|
157
|
-
document.body.classList.add('vidply-fullscreen-active');
|
|
158
|
-
// Make background content inert even in real-fullscreen mode —
|
|
159
|
-
// the overlay still leaves DOM focus reachable on some browsers.
|
|
160
|
-
player.pseudoFullscreen.makeBackgroundInert();
|
|
161
|
-
} else {
|
|
162
|
-
player.container.classList.remove(`${player.options.classPrefix}-fullscreen`);
|
|
163
|
-
document.body.classList.remove('vidply-fullscreen-active');
|
|
164
|
-
player.pseudoFullscreen.restoreBackgroundInteractivity();
|
|
165
|
-
player._disablePseudoFullscreen();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
player.emit('fullscreenchange', isFullscreen);
|
|
169
|
-
|
|
170
|
-
if (player.controlBar) {
|
|
171
|
-
player.controlBar.updateFullscreenButton();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Reposition the sign-language overlay after the transition
|
|
175
|
-
// completes; drag/resize affordances differ between windowed
|
|
176
|
-
// and fullscreen on mobile so we re-install them.
|
|
177
|
-
if (player.signLanguageWrapper && player.signLanguageWrapper.style.display !== 'none') {
|
|
178
|
-
const isMobileDevice = window.innerWidth < 768;
|
|
179
|
-
if (isMobileDevice) {
|
|
180
|
-
player.setupSignLanguageInteraction();
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
player.setManagedTimeout(() => {
|
|
184
|
-
requestAnimationFrame(() => {
|
|
185
|
-
player.storage.saveSignLanguagePreferences({ size: null });
|
|
186
|
-
if (player.signLanguageWrapper) {
|
|
187
|
-
player.signLanguageWrapper.style.width = isFullscreen ? '400px' : '280px';
|
|
188
|
-
}
|
|
189
|
-
player.constrainSignLanguagePosition();
|
|
190
|
-
});
|
|
191
|
-
}, 500);
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const opts = { signal: player.lifecycleSignal };
|
|
196
|
-
document.addEventListener('fullscreenchange', player.fullscreenChangeHandler, opts);
|
|
197
|
-
document.addEventListener('webkitfullscreenchange', player.fullscreenChangeHandler, opts);
|
|
198
|
-
document.addEventListener('mozfullscreenchange', player.fullscreenChangeHandler, opts);
|
|
199
|
-
document.addEventListener('MSFullscreenChange', player.fullscreenChangeHandler, opts);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Tear down listeners that aren't covered by the Player's
|
|
204
|
-
* lifecycle AbortController. The `window.resize` and
|
|
205
|
-
* `document.fullscreenchange` listeners are already cleaned up
|
|
206
|
-
* via `{signal}`; only the ResizeObserver and old-Safari
|
|
207
|
-
* matchMedia listener need an explicit removal.
|
|
208
|
-
*/
|
|
209
|
-
cleanup(): void {
|
|
210
|
-
const player = this.player;
|
|
211
|
-
|
|
212
|
-
if (player.resizeObserver) {
|
|
213
|
-
player.resizeObserver.disconnect();
|
|
214
|
-
player.resizeObserver = null;
|
|
215
|
-
}
|
|
216
|
-
player.resizeHandler = null;
|
|
217
|
-
player.fullscreenChangeHandler = null;
|
|
218
|
-
|
|
219
|
-
if (this.orientationQuery && this.orientationHandler) {
|
|
220
|
-
if (this.orientationQuery.removeEventListener) {
|
|
221
|
-
this.orientationQuery.removeEventListener('change', this.orientationHandler);
|
|
222
|
-
} else if ((this.orientationQuery as MediaQueryList).removeListener) {
|
|
223
|
-
(this.orientationQuery as MediaQueryList).removeListener(this.orientationHandler);
|
|
224
|
-
}
|
|
225
|
-
this.orientationQuery = null;
|
|
226
|
-
this.orientationHandler = null;
|
|
227
|
-
}
|
|
228
|
-
player.orientationQuery = null;
|
|
229
|
-
player.orientationHandler = null;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Resize / orientation / fullscreen handling extracted from Player.
|
|
3
|
+
*
|
|
4
|
+
* Three responsibilities live here:
|
|
5
|
+
*
|
|
6
|
+
* 1. Reacting to container size changes (ResizeObserver when
|
|
7
|
+
* available, `window.resize` fallback otherwise) so the control
|
|
8
|
+
* bar and the transcript panel stay correctly laid out.
|
|
9
|
+
* 2. Listening for orientation changes on mobile so the transcript
|
|
10
|
+
* panel re-positions after the viewport rotates.
|
|
11
|
+
* 3. Tracking native fullscreen changes across vendor prefixes so
|
|
12
|
+
* `state.fullscreen` stays in sync with reality — including the
|
|
13
|
+
* inert/overlay bookkeeping that's shared with the pseudo-
|
|
14
|
+
* fullscreen fallback.
|
|
15
|
+
*
|
|
16
|
+
* Every listener is attached with the Player's `lifecycleSignal`
|
|
17
|
+
* (or, for the ResizeObserver / older matchMedia listeners that
|
|
18
|
+
* don't accept AbortSignal, cleaned up explicitly in `cleanup()`).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { PseudoFullscreenController } from './PseudoFullscreen.js';
|
|
22
|
+
import type { ControlBar } from '../controls/ControlBar.js';
|
|
23
|
+
import type { Player } from './Player.js';
|
|
24
|
+
|
|
25
|
+
export class ResponsiveManager {
|
|
26
|
+
private readonly player: Player;
|
|
27
|
+
private orientationQuery: MediaQueryList | null = null;
|
|
28
|
+
private orientationHandler: ((e: MediaQueryListEvent) => void) | null = null;
|
|
29
|
+
|
|
30
|
+
constructor(player: Player) {
|
|
31
|
+
this.player = player;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
setup(): void {
|
|
35
|
+
this.setupResizeTracking();
|
|
36
|
+
this.setupOrientationTracking();
|
|
37
|
+
this.setupFullscreenTracking();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private setupResizeTracking(): void {
|
|
41
|
+
const player = this.player;
|
|
42
|
+
|
|
43
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
44
|
+
// Preferred path: ResizeObserver fires per-container, not per-viewport,
|
|
45
|
+
// so multiple players on one page don't stomp on each other.
|
|
46
|
+
player.resizeObserver = new ResizeObserver((entries) => {
|
|
47
|
+
for (const entry of entries) {
|
|
48
|
+
const width = entry.contentRect.width;
|
|
49
|
+
|
|
50
|
+
const controlBar = player.controlBar as (ControlBar & {
|
|
51
|
+
updateControlsForViewport?: (w: number) => void
|
|
52
|
+
}) | null;
|
|
53
|
+
if (controlBar && typeof controlBar.updateControlsForViewport === 'function') {
|
|
54
|
+
controlBar.updateControlsForViewport(width);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (player.transcriptManager && player.transcriptManager.isVisible) {
|
|
58
|
+
player.transcriptManager.positionTranscript();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
player.resizeObserver.observe(player.container);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Fallback: `window.resize`. We still respect
|
|
68
|
+
// `draggableResizable.manuallyPositioned` so we don't stomp on a
|
|
69
|
+
// user-chosen transcript location.
|
|
70
|
+
player.resizeHandler = () => {
|
|
71
|
+
const width = player.container.clientWidth;
|
|
72
|
+
|
|
73
|
+
const controlBar = player.controlBar as (ControlBar & {
|
|
74
|
+
updateControlsForViewport?: (w: number) => void
|
|
75
|
+
}) | null;
|
|
76
|
+
if (controlBar && typeof controlBar.updateControlsForViewport === 'function') {
|
|
77
|
+
controlBar.updateControlsForViewport(width);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (player.transcriptManager && player.transcriptManager.isVisible) {
|
|
81
|
+
if (!player.transcriptManager.draggableResizable
|
|
82
|
+
|| !player.transcriptManager.draggableResizable.manuallyPositioned) {
|
|
83
|
+
player.transcriptManager.positionTranscript();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
window.addEventListener('resize', player.resizeHandler, { signal: player.lifecycleSignal });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private setupOrientationTracking(): void {
|
|
92
|
+
const player = this.player;
|
|
93
|
+
if (!window.matchMedia) return;
|
|
94
|
+
|
|
95
|
+
this.orientationHandler = () => {
|
|
96
|
+
// Wait for layout to settle before we recompute positions —
|
|
97
|
+
// otherwise `getBoundingClientRect` still reflects the
|
|
98
|
+
// pre-rotation viewport.
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
if (player.transcriptManager && player.transcriptManager.isVisible) {
|
|
101
|
+
if (!player.transcriptManager.draggableResizable
|
|
102
|
+
|| !player.transcriptManager.draggableResizable.manuallyPositioned) {
|
|
103
|
+
player.transcriptManager.positionTranscript();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}, 100);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const orientationQuery = window.matchMedia('(orientation: portrait)');
|
|
110
|
+
if (orientationQuery.addEventListener) {
|
|
111
|
+
// Modern MediaQueryList supports AddEventListenerOptions including
|
|
112
|
+
// `signal`, so teardown happens automatically via the player's
|
|
113
|
+
// lifecycle AbortController.
|
|
114
|
+
orientationQuery.addEventListener('change', this.orientationHandler, {
|
|
115
|
+
signal: player.lifecycleSignal
|
|
116
|
+
});
|
|
117
|
+
} else if ((orientationQuery as MediaQueryList).addListener) {
|
|
118
|
+
// Older Safari: no signal support; `cleanup()` will remove this
|
|
119
|
+
// explicitly below.
|
|
120
|
+
(orientationQuery as MediaQueryList).addListener(this.orientationHandler);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.orientationQuery = orientationQuery;
|
|
124
|
+
// Mirror the field onto the player too; some older call sites
|
|
125
|
+
// reach for `player.orientationQuery` directly.
|
|
126
|
+
player.orientationQuery = orientationQuery;
|
|
127
|
+
player.orientationHandler = this.orientationHandler;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private setupFullscreenTracking(): void {
|
|
131
|
+
const player = this.player;
|
|
132
|
+
|
|
133
|
+
player.fullscreenChangeHandler = () => {
|
|
134
|
+
const doc = document as Document & {
|
|
135
|
+
webkitFullscreenElement?: Element | null;
|
|
136
|
+
mozFullScreenElement?: Element | null;
|
|
137
|
+
msFullscreenElement?: Element | null;
|
|
138
|
+
};
|
|
139
|
+
const isFullscreen = Boolean(
|
|
140
|
+
document.fullscreenElement ||
|
|
141
|
+
doc.webkitFullscreenElement ||
|
|
142
|
+
doc.mozFullScreenElement ||
|
|
143
|
+
doc.msFullscreenElement
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
if (player.state.fullscreen === isFullscreen) return;
|
|
147
|
+
|
|
148
|
+
player.state.fullscreen = isFullscreen;
|
|
149
|
+
|
|
150
|
+
if (!player.pseudoFullscreen) {
|
|
151
|
+
player.pseudoFullscreen = new PseudoFullscreenController(player);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (isFullscreen) {
|
|
155
|
+
player.container.classList.add(`${player.options.classPrefix}-fullscreen`);
|
|
156
|
+
// CSS fallback for browsers without :has() support.
|
|
157
|
+
document.body.classList.add('vidply-fullscreen-active');
|
|
158
|
+
// Make background content inert even in real-fullscreen mode —
|
|
159
|
+
// the overlay still leaves DOM focus reachable on some browsers.
|
|
160
|
+
player.pseudoFullscreen.makeBackgroundInert();
|
|
161
|
+
} else {
|
|
162
|
+
player.container.classList.remove(`${player.options.classPrefix}-fullscreen`);
|
|
163
|
+
document.body.classList.remove('vidply-fullscreen-active');
|
|
164
|
+
player.pseudoFullscreen.restoreBackgroundInteractivity();
|
|
165
|
+
player._disablePseudoFullscreen();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
player.emit('fullscreenchange', isFullscreen);
|
|
169
|
+
|
|
170
|
+
if (player.controlBar) {
|
|
171
|
+
player.controlBar.updateFullscreenButton();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Reposition the sign-language overlay after the transition
|
|
175
|
+
// completes; drag/resize affordances differ between windowed
|
|
176
|
+
// and fullscreen on mobile so we re-install them.
|
|
177
|
+
if (player.signLanguageWrapper && player.signLanguageWrapper.style.display !== 'none') {
|
|
178
|
+
const isMobileDevice = window.innerWidth < 768;
|
|
179
|
+
if (isMobileDevice) {
|
|
180
|
+
player.setupSignLanguageInteraction();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
player.setManagedTimeout(() => {
|
|
184
|
+
requestAnimationFrame(() => {
|
|
185
|
+
player.storage.saveSignLanguagePreferences({ size: null });
|
|
186
|
+
if (player.signLanguageWrapper) {
|
|
187
|
+
player.signLanguageWrapper.style.width = isFullscreen ? '400px' : '280px';
|
|
188
|
+
}
|
|
189
|
+
player.constrainSignLanguagePosition();
|
|
190
|
+
});
|
|
191
|
+
}, 500);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const opts = { signal: player.lifecycleSignal };
|
|
196
|
+
document.addEventListener('fullscreenchange', player.fullscreenChangeHandler, opts);
|
|
197
|
+
document.addEventListener('webkitfullscreenchange', player.fullscreenChangeHandler, opts);
|
|
198
|
+
document.addEventListener('mozfullscreenchange', player.fullscreenChangeHandler, opts);
|
|
199
|
+
document.addEventListener('MSFullscreenChange', player.fullscreenChangeHandler, opts);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Tear down listeners that aren't covered by the Player's
|
|
204
|
+
* lifecycle AbortController. The `window.resize` and
|
|
205
|
+
* `document.fullscreenchange` listeners are already cleaned up
|
|
206
|
+
* via `{signal}`; only the ResizeObserver and old-Safari
|
|
207
|
+
* matchMedia listener need an explicit removal.
|
|
208
|
+
*/
|
|
209
|
+
cleanup(): void {
|
|
210
|
+
const player = this.player;
|
|
211
|
+
|
|
212
|
+
if (player.resizeObserver) {
|
|
213
|
+
player.resizeObserver.disconnect();
|
|
214
|
+
player.resizeObserver = null;
|
|
215
|
+
}
|
|
216
|
+
player.resizeHandler = null;
|
|
217
|
+
player.fullscreenChangeHandler = null;
|
|
218
|
+
|
|
219
|
+
if (this.orientationQuery && this.orientationHandler) {
|
|
220
|
+
if (this.orientationQuery.removeEventListener) {
|
|
221
|
+
this.orientationQuery.removeEventListener('change', this.orientationHandler);
|
|
222
|
+
} else if ((this.orientationQuery as MediaQueryList).removeListener) {
|
|
223
|
+
(this.orientationQuery as MediaQueryList).removeListener(this.orientationHandler);
|
|
224
|
+
}
|
|
225
|
+
this.orientationQuery = null;
|
|
226
|
+
this.orientationHandler = null;
|
|
227
|
+
}
|
|
228
|
+
player.orientationQuery = null;
|
|
229
|
+
player.orientationHandler = null;
|
|
230
|
+
}
|
|
231
|
+
}
|