MikaFil commited on
Commit
a9881b5
Β·
verified Β·
1 Parent(s): 45a0db7

Create fullscreen_playcanvas.js

Browse files
Files changed (1) hide show
  1. fullscreen_playcanvas.js +276 -0
fullscreen_playcanvas.js ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // fullscreen.js
2
+ // Intègre un projet PlayCanvas via une balise <script data-src="..." data-aspect="16:9">
3
+ // Gère le plein écran natif (desktop/Android) et fake-fullscreen (iOS).
4
+
5
+ (function () {
6
+ // ─── 1. Localiser la balise <script> ────────────────────────────────────────
7
+ const scriptTag =
8
+ document.currentScript ||
9
+ (function () {
10
+ const all = document.getElementsByTagName('script');
11
+ for (let i = all.length - 1; i >= 0; i--) {
12
+ if (all[i].src && all[i].src.includes('fullscreen.js')) return all[i];
13
+ }
14
+ return all[all.length - 1];
15
+ })();
16
+
17
+ const playcanvasUrl = scriptTag.getAttribute('data-src');
18
+ if (!playcanvasUrl) {
19
+ console.warn('[fullscreen.js] Attribut data-src manquant.');
20
+ return;
21
+ }
22
+
23
+ // ─── 2. DΓ©tection plateforme ─────────────────────────────────────────────────
24
+ const isIOS =
25
+ /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
26
+ const isMobile =
27
+ isIOS || /Android/i.test(navigator.userAgent);
28
+
29
+ // ─── 3. ID d'instance (support multi-embed sur la mΓͺme page) ─────────────────
30
+ const id = Math.random().toString(36).substr(2, 8);
31
+
32
+ // ─── 4. Calcul du padding-bottom (aspect ratio) ──────────────────────────────
33
+ function computeAspectPadding(aspectStr) {
34
+ if (!aspectStr) return null;
35
+ if (aspectStr.includes(':')) {
36
+ const [w, h] = aspectStr.split(':').map(Number);
37
+ if (w > 0 && h > 0) return (h / w) * 100 + '%';
38
+ } else {
39
+ const v = parseFloat(aspectStr);
40
+ if (v > 0) return (100 / v) + '%';
41
+ }
42
+ return null;
43
+ }
44
+
45
+ const aspectPadding =
46
+ computeAspectPadding(scriptTag.getAttribute('data-aspect')) || '56.25%'; // dΓ©faut 16:9
47
+
48
+ // ─── 5. Injection du CSS ─────────────────────────────────────────────────────
49
+ const style = document.createElement('style');
50
+ style.textContent = `
51
+ .pc-embed-wrapper-${id} {
52
+ position: relative;
53
+ width: 100%;
54
+ height: 0;
55
+ padding-bottom: ${aspectPadding};
56
+ overflow: hidden;
57
+ background: #000;
58
+ box-sizing: border-box;
59
+ }
60
+ .pc-embed-wrapper-${id}.fake-fullscreen {
61
+ position: fixed !important;
62
+ top: 0 !important;
63
+ left: 0 !important;
64
+ width: 100vw !important;
65
+ height: 100vh !important;
66
+ max-width: 100vw !important;
67
+ max-height: 100vh !important;
68
+ padding-bottom: 0 !important;
69
+ margin: 0 !important;
70
+ z-index: 99999;
71
+ }
72
+ .pc-embed-inner-${id} {
73
+ position: absolute;
74
+ top: 0; left: 0;
75
+ width: 100%; height: 100%;
76
+ }
77
+ .pc-embed-inner-${id} iframe {
78
+ width: 100%; height: 100%;
79
+ border: none;
80
+ display: block;
81
+ }
82
+ .pc-fs-btn-${id} {
83
+ position: absolute;
84
+ bottom: 10px;
85
+ right: 10px;
86
+ z-index: 10;
87
+ width: 36px;
88
+ height: 36px;
89
+ border-radius: 50%;
90
+ border: none;
91
+ background: rgba(0,0,0,0.55);
92
+ color: #fff;
93
+ font-size: 18px;
94
+ line-height: 36px;
95
+ text-align: center;
96
+ cursor: pointer;
97
+ user-select: none;
98
+ -webkit-tap-highlight-color: transparent;
99
+ transition: background 0.2s;
100
+ }
101
+ .pc-fs-btn-${id}:hover {
102
+ background: rgba(0,0,0,0.8);
103
+ }
104
+ `;
105
+ document.head.appendChild(style);
106
+
107
+ // ─── 6. Construction du DOM ──────────────────────────────────────────────────
108
+ const wrapper = document.createElement('div');
109
+ wrapper.className = `pc-embed-wrapper-${id}`;
110
+ wrapper.setAttribute('data-original-padding', aspectPadding);
111
+
112
+ const inner = document.createElement('div');
113
+ inner.className = `pc-embed-inner-${id}`;
114
+
115
+ const iframe = document.createElement('iframe');
116
+ iframe.src = playcanvasUrl;
117
+ iframe.setAttribute('allowfullscreen', '');
118
+ iframe.setAttribute('allow', 'autoplay; fullscreen');
119
+ iframe.setAttribute(
120
+ 'sandbox',
121
+ 'allow-scripts allow-same-origin allow-pointer-lock allow-popups allow-forms'
122
+ );
123
+
124
+ const fsBtn = document.createElement('button');
125
+ fsBtn.className = `pc-fs-btn-${id}`;
126
+ fsBtn.title = 'Plein Γ©cran';
127
+ fsBtn.textContent = '⇱';
128
+ fsBtn.setAttribute('aria-label', 'Plein Γ©cran');
129
+
130
+ inner.appendChild(iframe);
131
+ wrapper.appendChild(inner);
132
+ wrapper.appendChild(fsBtn);
133
+ scriptTag.parentNode.insertBefore(wrapper, scriptTag.nextSibling);
134
+
135
+ // ─── 7. Γ‰tat fullscreen ──────────────────────────────────────────────────────
136
+ let isFullscreen = false;
137
+ let savedPadding = aspectPadding;
138
+
139
+ // ─── 8. Appliquer les styles plein Γ©cran ─────────────────────────────────────
140
+ function applyFullscreenStyles() {
141
+ wrapper.style.position = 'fixed';
142
+ wrapper.style.top = '0';
143
+ wrapper.style.left = '0';
144
+ wrapper.style.width = '100vw';
145
+ wrapper.style.height = '100vh';
146
+ wrapper.style.maxWidth = '100vw';
147
+ wrapper.style.maxHeight = '100vh';
148
+ wrapper.style.paddingBottom = '0';
149
+ wrapper.style.margin = '0';
150
+ wrapper.style.zIndex = '99999';
151
+ wrapper.classList.add('fake-fullscreen');
152
+ fsBtn.textContent = '⇲';
153
+ isFullscreen = true;
154
+ }
155
+
156
+ // ─── 9. Restaurer les styles normaux ─────────────────────────────────────────
157
+ function restoreStyles() {
158
+ wrapper.style.position = '';
159
+ wrapper.style.top = '';
160
+ wrapper.style.left = '';
161
+ wrapper.style.width = '100%';
162
+ wrapper.style.height = '0';
163
+ wrapper.style.maxWidth = '';
164
+ wrapper.style.maxHeight = '';
165
+ wrapper.style.paddingBottom = savedPadding;
166
+ wrapper.style.margin = '';
167
+ wrapper.style.zIndex = '';
168
+ wrapper.classList.remove('fake-fullscreen');
169
+ fsBtn.textContent = '⇱';
170
+ isFullscreen = false;
171
+ }
172
+
173
+ // ─── 10. EntrΓ©e en plein Γ©cran ───────────────────────────────────────────────
174
+ function enterFullscreen() {
175
+ savedPadding =
176
+ wrapper.getAttribute('data-original-padding') || aspectPadding;
177
+
178
+ if (isIOS) {
179
+ // iOS ne supporte pas l'API Fullscreen β†’ fake-fullscreen CSS uniquement
180
+ applyFullscreenStyles();
181
+ // Bloquer le scroll de la page hΓ΄te pendant le fake-fullscreen
182
+ document.body.style.overflow = 'hidden';
183
+ return;
184
+ }
185
+
186
+ // Tentative via l'API Fullscreen standard
187
+ const el = wrapper;
188
+ const req =
189
+ el.requestFullscreen ||
190
+ el.webkitRequestFullscreen ||
191
+ el.mozRequestFullScreen ||
192
+ el.msRequestFullscreen;
193
+
194
+ if (req) {
195
+ req.call(el)
196
+ .then(applyFullscreenStyles)
197
+ .catch(() => {
198
+ // Fallback fake-fullscreen si l'API Γ©choue (iframe cross-origin, etc.)
199
+ applyFullscreenStyles();
200
+ document.body.style.overflow = 'hidden';
201
+ });
202
+ } else {
203
+ applyFullscreenStyles();
204
+ document.body.style.overflow = 'hidden';
205
+ }
206
+ }
207
+
208
+ // ─── 11. Sortie du plein Γ©cran ───────────────────────────────────────────────
209
+ function exitFullscreen() {
210
+ if (
211
+ document.fullscreenElement === wrapper ||
212
+ document.webkitFullscreenElement === wrapper
213
+ ) {
214
+ (document.exitFullscreen || document.webkitExitFullscreen || (() => {}))
215
+ .call(document)
216
+ .catch(() => {});
217
+ }
218
+ restoreStyles();
219
+ document.body.style.overflow = '';
220
+ }
221
+
222
+ // ─── 12. Bouton fullscreen ───────────────────────────────────────────────────
223
+ fsBtn.addEventListener('click', function (e) {
224
+ e.stopPropagation();
225
+ isFullscreen ? exitFullscreen() : enterFullscreen();
226
+ });
227
+
228
+ // Touch explicite pour iOS (Γ©vite le dΓ©lai 300ms)
229
+ fsBtn.addEventListener('touchend', function (e) {
230
+ e.preventDefault();
231
+ e.stopPropagation();
232
+ isFullscreen ? exitFullscreen() : enterFullscreen();
233
+ });
234
+
235
+ // ─── 13. Γ‰couter les changements natifs fullscreen ───────────────────────────
236
+ // (ex : utilisateur appuie sur Γ‰chap)
237
+ function onFullscreenChange() {
238
+ const fsEl =
239
+ document.fullscreenElement || document.webkitFullscreenElement;
240
+
241
+ if (!fsEl && isFullscreen) {
242
+ // Le navigateur a quittΓ© le plein Γ©cran tout seul
243
+ restoreStyles();
244
+ document.body.style.overflow = '';
245
+ } else if (fsEl === wrapper && !isFullscreen) {
246
+ applyFullscreenStyles();
247
+ }
248
+ }
249
+
250
+ document.addEventListener('fullscreenchange', onFullscreenChange);
251
+ document.addEventListener('webkitfullscreenchange', onFullscreenChange);
252
+
253
+ // ─── 14. Touche Γ‰chap (fake-fullscreen) ──────────────────────────────────────
254
+ document.addEventListener('keydown', function (e) {
255
+ if ((e.key === 'Escape' || e.key === 'Esc') && isFullscreen) {
256
+ exitFullscreen();
257
+ }
258
+ });
259
+
260
+ // ─── 15. Resize : recalcul si fake-fullscreen ────────────────────────────────
261
+ window.addEventListener('resize', function () {
262
+ if (isFullscreen) {
263
+ wrapper.style.width = '100vw';
264
+ wrapper.style.height = '100vh';
265
+ }
266
+ });
267
+
268
+ window.addEventListener('orientationchange', function () {
269
+ if (isFullscreen) {
270
+ setTimeout(function () {
271
+ wrapper.style.width = '100vw';
272
+ wrapper.style.height = '100vh';
273
+ }, 200); // dΓ©lai pour laisser le navigateur recalculer les dimensions
274
+ }
275
+ });
276
+ })();