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,179 +1,179 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pseudo-fullscreen fallback for browsers / platforms (chiefly iOS
|
|
3
|
-
* Safari) where the real Fullscreen API is unavailable for video
|
|
4
|
-
* elements.
|
|
5
|
-
*
|
|
6
|
-
* Extracted from the Player class so the scroll-lock, background-inert
|
|
7
|
-
* and viewport-hijack logic lives in one focussed place. The Player
|
|
8
|
-
* still owns `state.fullscreen` and emits the `fullscreenchange`
|
|
9
|
-
* events — this controller only drives the DOM side effects.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { Player } from './Player.js';
|
|
13
|
-
|
|
14
|
-
export class PseudoFullscreenController {
|
|
15
|
-
private readonly player: Player;
|
|
16
|
-
|
|
17
|
-
// All of the "remember current style / scroll / viewport" slots used
|
|
18
|
-
// to restore state on exit. Kept private so the rest of the code
|
|
19
|
-
// base cannot poke into them.
|
|
20
|
-
private originalScrollX?: number;
|
|
21
|
-
private originalScrollY?: number;
|
|
22
|
-
private originalBodyOverflow?: string;
|
|
23
|
-
private originalBodyPosition?: string;
|
|
24
|
-
private originalBodyWidth?: string;
|
|
25
|
-
private originalBodyHeight?: string;
|
|
26
|
-
private originalHtmlOverflow?: string;
|
|
27
|
-
private originalBodyBackground?: string;
|
|
28
|
-
private originalHtmlBackground?: string;
|
|
29
|
-
private originalViewport?: string | null;
|
|
30
|
-
private inertElements: Element[] = [];
|
|
31
|
-
|
|
32
|
-
constructor(player: Player) {
|
|
33
|
-
this.player = player;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
enable(): void {
|
|
37
|
-
const { player } = this;
|
|
38
|
-
player.state.fullscreen = true;
|
|
39
|
-
player.container.classList.add(`${player.options.classPrefix}-fullscreen`);
|
|
40
|
-
|
|
41
|
-
// CSS fallback for browsers without :has() support.
|
|
42
|
-
document.body.classList.add('vidply-fullscreen-active');
|
|
43
|
-
|
|
44
|
-
// Stash the current scroll position so we can restore it on exit.
|
|
45
|
-
this.originalScrollX = window.scrollX || window.pageXOffset;
|
|
46
|
-
this.originalScrollY = window.scrollY || window.pageYOffset;
|
|
47
|
-
|
|
48
|
-
// Prevent body/html from scrolling while the player covers the viewport.
|
|
49
|
-
this.originalBodyOverflow = document.body.style.overflow;
|
|
50
|
-
this.originalBodyPosition = document.body.style.position;
|
|
51
|
-
this.originalBodyWidth = document.body.style.width;
|
|
52
|
-
this.originalBodyHeight = document.body.style.height;
|
|
53
|
-
this.originalHtmlOverflow = document.documentElement.style.overflow;
|
|
54
|
-
this.originalBodyBackground = document.body.style.background;
|
|
55
|
-
this.originalHtmlBackground = document.documentElement.style.background;
|
|
56
|
-
|
|
57
|
-
document.body.style.overflow = 'hidden';
|
|
58
|
-
document.body.style.width = '100%';
|
|
59
|
-
document.body.style.height = '100%';
|
|
60
|
-
document.body.style.background = '#000';
|
|
61
|
-
document.documentElement.style.overflow = 'hidden';
|
|
62
|
-
document.documentElement.style.background = '#000';
|
|
63
|
-
|
|
64
|
-
// iOS: reset the viewport scale so the player fills the screen, but never
|
|
65
|
-
// disable user scaling. Setting maximum-scale=1.0 / user-scalable=no would
|
|
66
|
-
// block pinch-zoom and fail WCAG 1.4.4 (Resize Text) and 1.4.10 (Reflow).
|
|
67
|
-
this.originalViewport = document.querySelector('meta[name="viewport"]')?.getAttribute('content');
|
|
68
|
-
const viewport = document.querySelector('meta[name="viewport"]');
|
|
69
|
-
if (viewport) {
|
|
70
|
-
viewport.setAttribute('content', 'width=device-width, initial-scale=1.0');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Scroll to top on iOS to prevent positioning issues.
|
|
74
|
-
window.scrollTo(0, 0);
|
|
75
|
-
|
|
76
|
-
// Make the rest of the page inert so keyboard focus cannot escape
|
|
77
|
-
// to background content that is visually covered but still alive.
|
|
78
|
-
this.makeBackgroundInert();
|
|
79
|
-
|
|
80
|
-
player.emit('fullscreenchange', true);
|
|
81
|
-
player.emit('enterfullscreen');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Make every sibling of the player container (walking up to the body)
|
|
86
|
-
* `inert`. Scripts/styles are skipped so layout-time mutations still
|
|
87
|
-
* work. Elements that were already inert are left alone so we don't
|
|
88
|
-
* accidentally clear another author's inert marker on exit.
|
|
89
|
-
*
|
|
90
|
-
* Public because the real Fullscreen API handler also calls it — we
|
|
91
|
-
* need the same inert treatment when the browser grants real
|
|
92
|
-
* fullscreen, not only in the pseudo-fallback path.
|
|
93
|
-
*/
|
|
94
|
-
makeBackgroundInert(): void {
|
|
95
|
-
this.inertElements = [];
|
|
96
|
-
let current: HTMLElement | null = this.player.container;
|
|
97
|
-
while (current && current !== document.body && current !== document.documentElement) {
|
|
98
|
-
const parentElement: HTMLElement | null = current.parentElement;
|
|
99
|
-
if (parentElement) {
|
|
100
|
-
Array.from(parentElement.children).forEach((sibling: Element) => {
|
|
101
|
-
if (
|
|
102
|
-
sibling !== current &&
|
|
103
|
-
sibling.nodeType === Node.ELEMENT_NODE &&
|
|
104
|
-
!sibling.hasAttribute('inert') &&
|
|
105
|
-
sibling.tagName !== 'SCRIPT' &&
|
|
106
|
-
sibling.tagName !== 'STYLE' &&
|
|
107
|
-
sibling.tagName !== 'LINK' &&
|
|
108
|
-
sibling.tagName !== 'META'
|
|
109
|
-
) {
|
|
110
|
-
sibling.setAttribute('inert', '');
|
|
111
|
-
this.inertElements.push(sibling);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
current = parentElement;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Public counterpart of {@link makeBackgroundInert}. */
|
|
120
|
-
restoreBackgroundInteractivity(): void {
|
|
121
|
-
if (this.inertElements.length > 0) {
|
|
122
|
-
for (const el of this.inertElements) {
|
|
123
|
-
el.removeAttribute('inert');
|
|
124
|
-
}
|
|
125
|
-
this.inertElements = [];
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
disable(): void {
|
|
130
|
-
document.body.classList.remove('vidply-fullscreen-active');
|
|
131
|
-
|
|
132
|
-
this.restoreBackgroundInteractivity();
|
|
133
|
-
|
|
134
|
-
if (this.originalBodyOverflow !== undefined) {
|
|
135
|
-
document.body.style.overflow = this.originalBodyOverflow;
|
|
136
|
-
this.originalBodyOverflow = undefined;
|
|
137
|
-
}
|
|
138
|
-
if (this.originalBodyPosition !== undefined) {
|
|
139
|
-
document.body.style.position = this.originalBodyPosition;
|
|
140
|
-
this.originalBodyPosition = undefined;
|
|
141
|
-
}
|
|
142
|
-
if (this.originalBodyWidth !== undefined) {
|
|
143
|
-
document.body.style.width = this.originalBodyWidth;
|
|
144
|
-
this.originalBodyWidth = undefined;
|
|
145
|
-
}
|
|
146
|
-
if (this.originalBodyHeight !== undefined) {
|
|
147
|
-
document.body.style.height = this.originalBodyHeight;
|
|
148
|
-
this.originalBodyHeight = undefined;
|
|
149
|
-
}
|
|
150
|
-
if (this.originalHtmlOverflow !== undefined) {
|
|
151
|
-
document.documentElement.style.overflow = this.originalHtmlOverflow;
|
|
152
|
-
this.originalHtmlOverflow = undefined;
|
|
153
|
-
}
|
|
154
|
-
if (this.originalBodyBackground !== undefined) {
|
|
155
|
-
document.body.style.background = this.originalBodyBackground;
|
|
156
|
-
this.originalBodyBackground = undefined;
|
|
157
|
-
}
|
|
158
|
-
if (this.originalHtmlBackground !== undefined) {
|
|
159
|
-
document.documentElement.style.background = this.originalHtmlBackground;
|
|
160
|
-
this.originalHtmlBackground = undefined;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (this.originalViewport !== undefined) {
|
|
164
|
-
const viewport = document.querySelector('meta[name="viewport"]');
|
|
165
|
-
if (viewport && this.originalViewport !== null) {
|
|
166
|
-
viewport.setAttribute('content', this.originalViewport);
|
|
167
|
-
}
|
|
168
|
-
this.originalViewport = undefined;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (this.originalScrollX !== undefined && this.originalScrollY !== undefined) {
|
|
172
|
-
window.scrollTo(this.originalScrollX, this.originalScrollY);
|
|
173
|
-
this.originalScrollX = undefined;
|
|
174
|
-
this.originalScrollY = undefined;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
this.player.emit('exitfullscreen');
|
|
178
|
-
}
|
|
179
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Pseudo-fullscreen fallback for browsers / platforms (chiefly iOS
|
|
3
|
+
* Safari) where the real Fullscreen API is unavailable for video
|
|
4
|
+
* elements.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from the Player class so the scroll-lock, background-inert
|
|
7
|
+
* and viewport-hijack logic lives in one focussed place. The Player
|
|
8
|
+
* still owns `state.fullscreen` and emits the `fullscreenchange`
|
|
9
|
+
* events — this controller only drives the DOM side effects.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { Player } from './Player.js';
|
|
13
|
+
|
|
14
|
+
export class PseudoFullscreenController {
|
|
15
|
+
private readonly player: Player;
|
|
16
|
+
|
|
17
|
+
// All of the "remember current style / scroll / viewport" slots used
|
|
18
|
+
// to restore state on exit. Kept private so the rest of the code
|
|
19
|
+
// base cannot poke into them.
|
|
20
|
+
private originalScrollX?: number;
|
|
21
|
+
private originalScrollY?: number;
|
|
22
|
+
private originalBodyOverflow?: string;
|
|
23
|
+
private originalBodyPosition?: string;
|
|
24
|
+
private originalBodyWidth?: string;
|
|
25
|
+
private originalBodyHeight?: string;
|
|
26
|
+
private originalHtmlOverflow?: string;
|
|
27
|
+
private originalBodyBackground?: string;
|
|
28
|
+
private originalHtmlBackground?: string;
|
|
29
|
+
private originalViewport?: string | null;
|
|
30
|
+
private inertElements: Element[] = [];
|
|
31
|
+
|
|
32
|
+
constructor(player: Player) {
|
|
33
|
+
this.player = player;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
enable(): void {
|
|
37
|
+
const { player } = this;
|
|
38
|
+
player.state.fullscreen = true;
|
|
39
|
+
player.container.classList.add(`${player.options.classPrefix}-fullscreen`);
|
|
40
|
+
|
|
41
|
+
// CSS fallback for browsers without :has() support.
|
|
42
|
+
document.body.classList.add('vidply-fullscreen-active');
|
|
43
|
+
|
|
44
|
+
// Stash the current scroll position so we can restore it on exit.
|
|
45
|
+
this.originalScrollX = window.scrollX || window.pageXOffset;
|
|
46
|
+
this.originalScrollY = window.scrollY || window.pageYOffset;
|
|
47
|
+
|
|
48
|
+
// Prevent body/html from scrolling while the player covers the viewport.
|
|
49
|
+
this.originalBodyOverflow = document.body.style.overflow;
|
|
50
|
+
this.originalBodyPosition = document.body.style.position;
|
|
51
|
+
this.originalBodyWidth = document.body.style.width;
|
|
52
|
+
this.originalBodyHeight = document.body.style.height;
|
|
53
|
+
this.originalHtmlOverflow = document.documentElement.style.overflow;
|
|
54
|
+
this.originalBodyBackground = document.body.style.background;
|
|
55
|
+
this.originalHtmlBackground = document.documentElement.style.background;
|
|
56
|
+
|
|
57
|
+
document.body.style.overflow = 'hidden';
|
|
58
|
+
document.body.style.width = '100%';
|
|
59
|
+
document.body.style.height = '100%';
|
|
60
|
+
document.body.style.background = '#000';
|
|
61
|
+
document.documentElement.style.overflow = 'hidden';
|
|
62
|
+
document.documentElement.style.background = '#000';
|
|
63
|
+
|
|
64
|
+
// iOS: reset the viewport scale so the player fills the screen, but never
|
|
65
|
+
// disable user scaling. Setting maximum-scale=1.0 / user-scalable=no would
|
|
66
|
+
// block pinch-zoom and fail WCAG 1.4.4 (Resize Text) and 1.4.10 (Reflow).
|
|
67
|
+
this.originalViewport = document.querySelector('meta[name="viewport"]')?.getAttribute('content');
|
|
68
|
+
const viewport = document.querySelector('meta[name="viewport"]');
|
|
69
|
+
if (viewport) {
|
|
70
|
+
viewport.setAttribute('content', 'width=device-width, initial-scale=1.0');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Scroll to top on iOS to prevent positioning issues.
|
|
74
|
+
window.scrollTo(0, 0);
|
|
75
|
+
|
|
76
|
+
// Make the rest of the page inert so keyboard focus cannot escape
|
|
77
|
+
// to background content that is visually covered but still alive.
|
|
78
|
+
this.makeBackgroundInert();
|
|
79
|
+
|
|
80
|
+
player.emit('fullscreenchange', true);
|
|
81
|
+
player.emit('enterfullscreen');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Make every sibling of the player container (walking up to the body)
|
|
86
|
+
* `inert`. Scripts/styles are skipped so layout-time mutations still
|
|
87
|
+
* work. Elements that were already inert are left alone so we don't
|
|
88
|
+
* accidentally clear another author's inert marker on exit.
|
|
89
|
+
*
|
|
90
|
+
* Public because the real Fullscreen API handler also calls it — we
|
|
91
|
+
* need the same inert treatment when the browser grants real
|
|
92
|
+
* fullscreen, not only in the pseudo-fallback path.
|
|
93
|
+
*/
|
|
94
|
+
makeBackgroundInert(): void {
|
|
95
|
+
this.inertElements = [];
|
|
96
|
+
let current: HTMLElement | null = this.player.container;
|
|
97
|
+
while (current && current !== document.body && current !== document.documentElement) {
|
|
98
|
+
const parentElement: HTMLElement | null = current.parentElement;
|
|
99
|
+
if (parentElement) {
|
|
100
|
+
Array.from(parentElement.children).forEach((sibling: Element) => {
|
|
101
|
+
if (
|
|
102
|
+
sibling !== current &&
|
|
103
|
+
sibling.nodeType === Node.ELEMENT_NODE &&
|
|
104
|
+
!sibling.hasAttribute('inert') &&
|
|
105
|
+
sibling.tagName !== 'SCRIPT' &&
|
|
106
|
+
sibling.tagName !== 'STYLE' &&
|
|
107
|
+
sibling.tagName !== 'LINK' &&
|
|
108
|
+
sibling.tagName !== 'META'
|
|
109
|
+
) {
|
|
110
|
+
sibling.setAttribute('inert', '');
|
|
111
|
+
this.inertElements.push(sibling);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
current = parentElement;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Public counterpart of {@link makeBackgroundInert}. */
|
|
120
|
+
restoreBackgroundInteractivity(): void {
|
|
121
|
+
if (this.inertElements.length > 0) {
|
|
122
|
+
for (const el of this.inertElements) {
|
|
123
|
+
el.removeAttribute('inert');
|
|
124
|
+
}
|
|
125
|
+
this.inertElements = [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
disable(): void {
|
|
130
|
+
document.body.classList.remove('vidply-fullscreen-active');
|
|
131
|
+
|
|
132
|
+
this.restoreBackgroundInteractivity();
|
|
133
|
+
|
|
134
|
+
if (this.originalBodyOverflow !== undefined) {
|
|
135
|
+
document.body.style.overflow = this.originalBodyOverflow;
|
|
136
|
+
this.originalBodyOverflow = undefined;
|
|
137
|
+
}
|
|
138
|
+
if (this.originalBodyPosition !== undefined) {
|
|
139
|
+
document.body.style.position = this.originalBodyPosition;
|
|
140
|
+
this.originalBodyPosition = undefined;
|
|
141
|
+
}
|
|
142
|
+
if (this.originalBodyWidth !== undefined) {
|
|
143
|
+
document.body.style.width = this.originalBodyWidth;
|
|
144
|
+
this.originalBodyWidth = undefined;
|
|
145
|
+
}
|
|
146
|
+
if (this.originalBodyHeight !== undefined) {
|
|
147
|
+
document.body.style.height = this.originalBodyHeight;
|
|
148
|
+
this.originalBodyHeight = undefined;
|
|
149
|
+
}
|
|
150
|
+
if (this.originalHtmlOverflow !== undefined) {
|
|
151
|
+
document.documentElement.style.overflow = this.originalHtmlOverflow;
|
|
152
|
+
this.originalHtmlOverflow = undefined;
|
|
153
|
+
}
|
|
154
|
+
if (this.originalBodyBackground !== undefined) {
|
|
155
|
+
document.body.style.background = this.originalBodyBackground;
|
|
156
|
+
this.originalBodyBackground = undefined;
|
|
157
|
+
}
|
|
158
|
+
if (this.originalHtmlBackground !== undefined) {
|
|
159
|
+
document.documentElement.style.background = this.originalHtmlBackground;
|
|
160
|
+
this.originalHtmlBackground = undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (this.originalViewport !== undefined) {
|
|
164
|
+
const viewport = document.querySelector('meta[name="viewport"]');
|
|
165
|
+
if (viewport && this.originalViewport !== null) {
|
|
166
|
+
viewport.setAttribute('content', this.originalViewport);
|
|
167
|
+
}
|
|
168
|
+
this.originalViewport = undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (this.originalScrollX !== undefined && this.originalScrollY !== undefined) {
|
|
172
|
+
window.scrollTo(this.originalScrollX, this.originalScrollY);
|
|
173
|
+
this.originalScrollX = undefined;
|
|
174
|
+
this.originalScrollY = undefined;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.player.emit('exitfullscreen');
|
|
178
|
+
}
|
|
179
|
+
}
|