MikaFil commited on
Commit
0aa7811
Β·
verified Β·
1 Parent(s): 8bc1807

Update fullscreen_playcanvas.js

Browse files
Files changed (1) hide show
  1. fullscreen_playcanvas.js +41 -140
fullscreen_playcanvas.js CHANGED
@@ -1,7 +1,4 @@
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 =
@@ -21,12 +18,9 @@
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) ──────────────────────────────
@@ -42,8 +36,7 @@
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');
@@ -62,9 +55,10 @@
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;
@@ -98,9 +92,6 @@
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
 
@@ -116,43 +107,38 @@
116
  const urlObj = new URL(playcanvasUrl);
117
  urlObj.searchParams.set('overlay', 'false');
118
  iframe.src = urlObj.href;
119
-
120
-
121
  iframe.setAttribute('allowfullscreen', '');
122
  iframe.setAttribute('allow', 'autoplay; fullscreen');
123
- iframe.setAttribute(
124
- 'sandbox',
125
- 'allow-scripts allow-same-origin allow-pointer-lock allow-popups allow-forms'
126
- );
127
 
128
  const fsBtn = document.createElement('button');
129
  fsBtn.className = `pc-fs-btn-${id}`;
130
- fsBtn.title = 'Plein Γ©cran';
131
  fsBtn.textContent = '⇱';
132
- fsBtn.setAttribute('aria-label', 'Plein Γ©cran');
133
 
134
  inner.appendChild(iframe);
135
  wrapper.appendChild(inner);
136
  wrapper.appendChild(fsBtn);
137
  scriptTag.parentNode.insertBefore(wrapper, scriptTag.nextSibling);
138
 
139
- // ─── 7. Γ‰tat fullscreen ──────────────────────────────────────────────────────
140
  let isFullscreen = false;
141
- let savedPadding = aspectPadding;
142
  let savedParent = null;
143
  let savedNextSibling = null;
144
 
145
- // ─── 8. Styles communs fullscreen (sans dΓ©placement DOM) ─────────────────────
146
- // UtilisΓ© par le fullscreen natif (desktop/Android).
147
- // NE PAS modifier cette fonction pour iOS β€” voir applyFakeFullscreenStyles.
 
 
 
148
  function applyFullscreenStyles() {
 
149
  wrapper.style.position = 'fixed';
150
  wrapper.style.top = '0';
151
  wrapper.style.left = '0';
152
  wrapper.style.width = '100vw';
153
- wrapper.style.height = '100vh';
154
- wrapper.style.maxWidth = '100vw';
155
- wrapper.style.maxHeight = '100vh';
156
  wrapper.style.paddingBottom = '0';
157
  wrapper.style.margin = '0';
158
  wrapper.style.zIndex = '99999';
@@ -161,50 +147,20 @@
161
  isFullscreen = true;
162
  }
163
 
164
- // ─── 9. Fake-fullscreen iOS avec tΓ©lΓ©portation DOM + correction hauteur ───────
165
- // Sur iOS Safari, 100vh inclut la barre de navigation β†’ le bas est masquΓ©.
166
- // On utilise 100dvh (dynamic viewport height) si supportΓ©, sinon on compense
167
- // avec env(safe-area-inset-bottom).
168
- // La tΓ©lΓ©portation dans <body> permet d'Γ©chapper aux stacking contexts parents.
169
  function applyFakeFullscreenStyles() {
170
  savedParent = wrapper.parentNode;
171
  savedNextSibling = wrapper.nextSibling;
172
  document.body.appendChild(wrapper);
173
-
174
- // Styles communs
175
  applyFullscreenStyles();
176
-
177
- // Correction hauteur iOS uniquement
178
- if (isIOS) {
179
- if (CSS.supports('height', '1dvh')) {
180
- // iOS 16+ : dvh exclut exactement la barre Safari
181
- wrapper.style.height = '100dvh';
182
- wrapper.style.maxHeight = '100dvh';
183
- } else {
184
- // iOS 15 et moins : compensation via safe-area-inset-bottom
185
- wrapper.style.height = 'calc(100vh - env(safe-area-inset-bottom, 0px))';
186
- wrapper.style.maxHeight = 'calc(100vh - env(safe-area-inset-bottom, 0px))';
187
- }
188
- }
189
  }
190
 
191
- // ─── 10. Restaurer les styles normaux ────────────────────────────────────────
192
  function restoreStyles() {
193
- wrapper.style.position = '';
194
- wrapper.style.top = '';
195
- wrapper.style.left = '';
196
- wrapper.style.width = '100%';
197
- wrapper.style.height = '0';
198
- wrapper.style.maxWidth = '';
199
- wrapper.style.maxHeight = '';
200
- wrapper.style.paddingBottom = savedPadding;
201
- wrapper.style.margin = '';
202
- wrapper.style.zIndex = '';
203
  wrapper.classList.remove('fake-fullscreen');
204
  fsBtn.textContent = '⇱';
205
  isFullscreen = false;
206
 
207
- // Remettre en place uniquement si on avait tΓ©lΓ©portΓ© (iOS / fallback)
208
  if (savedParent) {
209
  savedParent.insertBefore(wrapper, savedNextSibling);
210
  savedParent = null;
@@ -212,105 +168,50 @@
212
  }
213
  }
214
 
215
- // ─── 11. EntrΓ©e en plein Γ©cran ───────────────────────────────────────────────
216
  function enterFullscreen() {
217
- savedPadding =
218
- wrapper.getAttribute('data-original-padding') || aspectPadding;
219
-
220
  if (isIOS) {
221
- // iOS : fake-fullscreen avec tΓ©lΓ©portation DOM et correction hauteur
222
  applyFakeFullscreenStyles();
223
  document.body.style.overflow = 'hidden';
224
- return;
225
- }
226
-
227
- // Tentative via l'API Fullscreen standard (desktop / Android)
228
- const el = wrapper;
229
- const req =
230
- el.requestFullscreen ||
231
- el.webkitRequestFullscreen ||
232
- el.mozRequestFullScreen ||
233
- el.msRequestFullscreen;
234
-
235
- if (req) {
236
- req.call(el).catch(() => {
237
- // API refusΓ©e β†’ fallback fake avec tΓ©lΓ©portation (sans correction iOS)
238
  applyFakeFullscreenStyles();
239
  document.body.style.overflow = 'hidden';
240
- });
241
- // Sur succès, applyFullscreenStyles est appelé par onFullscreenChange
242
- } else {
243
- applyFakeFullscreenStyles();
244
- document.body.style.overflow = 'hidden';
245
  }
246
  }
247
 
248
- // ─── 12. Sortie du plein Γ©cran ───────────────────────────────────────────────
249
  function exitFullscreen() {
250
- if (
251
- document.fullscreenElement === wrapper ||
252
- document.webkitFullscreenElement === wrapper
253
- ) {
254
- (document.exitFullscreen || document.webkitExitFullscreen || (() => {}))
255
- .call(document)
256
- .catch(() => {});
257
  }
258
  restoreStyles();
259
  document.body.style.overflow = '';
260
  }
261
 
262
- // ─── 13. Bouton fullscreen ───────────────────────────────────────────────────
263
- fsBtn.addEventListener('click', function (e) {
264
  e.stopPropagation();
265
  isFullscreen ? exitFullscreen() : enterFullscreen();
266
  });
267
 
268
- // Touch explicite pour iOS (Γ©vite le dΓ©lai 300ms)
269
- fsBtn.addEventListener('touchend', function (e) {
270
- e.preventDefault();
271
- e.stopPropagation();
272
- isFullscreen ? exitFullscreen() : enterFullscreen();
273
- });
274
-
275
- // ─── 14. Γ‰couter les changements natifs fullscreen ───────────────────────────
276
- // NB : on appelle applyFullscreenStyles (sans dvh) car le fullscreen natif
277
- // gΓ¨re lui-mΓͺme la hauteur β€” pas besoin de correction iOS ici.
278
- function onFullscreenChange() {
279
- const fsEl =
280
- document.fullscreenElement || document.webkitFullscreenElement;
281
-
282
- if (!fsEl && isFullscreen) {
283
- restoreStyles();
284
- document.body.style.overflow = '';
285
- } else if (fsEl === wrapper && !isFullscreen) {
286
- applyFullscreenStyles();
287
- }
288
- }
289
-
290
- document.addEventListener('fullscreenchange', onFullscreenChange);
291
- document.addEventListener('webkitfullscreenchange', onFullscreenChange);
292
-
293
- // ─── 15. Touche Γ‰chap (fake-fullscreen iOS / fallback) ───────────────────────
294
- document.addEventListener('keydown', function (e) {
295
- if ((e.key === 'Escape' || e.key === 'Esc') && isFullscreen) {
296
- exitFullscreen();
297
- }
298
- });
299
-
300
- // ─── 16. Resize / orientation ────────────────────────────────────────────────
301
- window.addEventListener('resize', function () {
302
- if (isFullscreen) {
303
- wrapper.style.width = '100vw';
304
- wrapper.style.height = '100vh';
305
- }
306
  });
307
 
308
- window.addEventListener('orientationchange', function () {
309
  if (isFullscreen) {
310
- setTimeout(function () {
311
- wrapper.style.width = '100vw';
312
- wrapper.style.height = '100vh';
313
- }, 200);
314
  }
315
  });
316
  })();
 
1
  // fullscreen.js
 
 
 
2
  (function () {
3
  // ─── 1. Localiser la balise <script> ────────────────────────────────────────
4
  const scriptTag =
 
18
  }
19
 
20
  // ─── 2. DΓ©tection plateforme ─────────────────────────────────────────────────
21
+ const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
 
 
 
22
 
23
+ // ─── 3. ID d'instance ────────────────────────────────────────────────────────
24
  const id = Math.random().toString(36).substr(2, 8);
25
 
26
  // ─── 4. Calcul du padding-bottom (aspect ratio) ──────────────────────────────
 
36
  return null;
37
  }
38
 
39
+ const aspectPadding = computeAspectPadding(scriptTag.getAttribute('data-aspect')) || '56.25%';
 
40
 
41
  // ─── 5. Injection du CSS ─────────────────────────────────────────────────────
42
  const style = document.createElement('style');
 
55
  top: 0 !important;
56
  left: 0 !important;
57
  width: 100vw !important;
58
+ height: 100vh !important; /* Fallback */
59
+ height: 100dvh !important; /* iOS 16+ dynamique */
60
  max-width: 100vw !important;
61
+ max-height: 100dvh !important;
62
  padding-bottom: 0 !important;
63
  margin: 0 !important;
64
  z-index: 99999;
 
92
  -webkit-tap-highlight-color: transparent;
93
  transition: background 0.2s;
94
  }
 
 
 
95
  `;
96
  document.head.appendChild(style);
97
 
 
107
  const urlObj = new URL(playcanvasUrl);
108
  urlObj.searchParams.set('overlay', 'false');
109
  iframe.src = urlObj.href;
 
 
110
  iframe.setAttribute('allowfullscreen', '');
111
  iframe.setAttribute('allow', 'autoplay; fullscreen');
112
+ iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-pointer-lock allow-popups allow-forms');
 
 
 
113
 
114
  const fsBtn = document.createElement('button');
115
  fsBtn.className = `pc-fs-btn-${id}`;
 
116
  fsBtn.textContent = '⇱';
 
117
 
118
  inner.appendChild(iframe);
119
  wrapper.appendChild(inner);
120
  wrapper.appendChild(fsBtn);
121
  scriptTag.parentNode.insertBefore(wrapper, scriptTag.nextSibling);
122
 
123
+ // ─── 7. Γ‰tat & Helper ────────────────────────────────────────────────────────
124
  let isFullscreen = false;
 
125
  let savedParent = null;
126
  let savedNextSibling = null;
127
 
128
+ // DΓ©termine l'unitΓ© de hauteur Γ  utiliser
129
+ function getHeightUnit() {
130
+ return (CSS && CSS.supports && CSS.supports('height', '100dvh')) ? '100dvh' : '100vh';
131
+ }
132
+
133
+ // ─── 8. Styles Plein Γ‰cran ───────────────────────────────────────────────────
134
  function applyFullscreenStyles() {
135
+ const h = isIOS ? getHeightUnit() : '100vh';
136
  wrapper.style.position = 'fixed';
137
  wrapper.style.top = '0';
138
  wrapper.style.left = '0';
139
  wrapper.style.width = '100vw';
140
+ wrapper.style.height = h;
141
+ wrapper.style.maxHeight = h;
 
142
  wrapper.style.paddingBottom = '0';
143
  wrapper.style.margin = '0';
144
  wrapper.style.zIndex = '99999';
 
147
  isFullscreen = true;
148
  }
149
 
 
 
 
 
 
150
  function applyFakeFullscreenStyles() {
151
  savedParent = wrapper.parentNode;
152
  savedNextSibling = wrapper.nextSibling;
153
  document.body.appendChild(wrapper);
 
 
154
  applyFullscreenStyles();
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
 
 
157
  function restoreStyles() {
158
+ wrapper.style.cssText = ''; // Nettoie les styles inline
159
+ wrapper.style.paddingBottom = aspectPadding;
 
 
 
 
 
 
 
 
160
  wrapper.classList.remove('fake-fullscreen');
161
  fsBtn.textContent = '⇱';
162
  isFullscreen = false;
163
 
 
164
  if (savedParent) {
165
  savedParent.insertBefore(wrapper, savedNextSibling);
166
  savedParent = null;
 
168
  }
169
  }
170
 
171
+ // ─── 9. Gestionnaires d'Γ©vΓ©nements ───────────────────────────────────────────
172
  function enterFullscreen() {
 
 
 
173
  if (isIOS) {
 
174
  applyFakeFullscreenStyles();
175
  document.body.style.overflow = 'hidden';
176
+ } else {
177
+ const el = wrapper;
178
+ const req = el.requestFullscreen || el.webkitRequestFullscreen || el.mozRequestFullScreen || el.msRequestFullscreen;
179
+ if (req) {
180
+ req.call(el).catch(() => {
181
+ applyFakeFullscreenStyles();
182
+ document.body.style.overflow = 'hidden';
183
+ });
184
+ } else {
 
 
 
 
 
185
  applyFakeFullscreenStyles();
186
  document.body.style.overflow = 'hidden';
187
+ }
 
 
 
 
188
  }
189
  }
190
 
 
191
  function exitFullscreen() {
192
+ if (document.fullscreenElement || document.webkitFullscreenElement) {
193
+ (document.exitFullscreen || document.webkitExitFullscreen || function(){}).call(document);
 
 
 
 
 
194
  }
195
  restoreStyles();
196
  document.body.style.overflow = '';
197
  }
198
 
199
+ fsBtn.addEventListener('click', (e) => {
 
200
  e.stopPropagation();
201
  isFullscreen ? exitFullscreen() : enterFullscreen();
202
  });
203
 
204
+ document.addEventListener('fullscreenchange', () => {
205
+ const fsEl = document.fullscreenElement || document.webkitFullscreenElement;
206
+ if (!fsEl && isFullscreen) exitFullscreen();
207
+ else if (fsEl === wrapper && !isFullscreen) applyFullscreenStyles();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  });
209
 
210
+ window.addEventListener('resize', () => {
211
  if (isFullscreen) {
212
+ const h = isIOS ? getHeightUnit() : '100vh';
213
+ wrapper.style.height = h;
214
+ wrapper.style.maxHeight = h;
 
215
  }
216
  });
217
  })();