MikaFil commited on
Commit
90018af
·
verified ·
1 Parent(s): 902940d

Update interface.js

Browse files
Files changed (1) hide show
  1. interface.js +129 -125
interface.js CHANGED
@@ -1,26 +1,30 @@
1
  // interface.js
2
  // ==============================
3
 
4
- (async function () {
5
- // 1) Récupère toutes les balises <script src=".../interface.js" data-config="...">
6
- const scriptTags = Array.from(
7
- document.querySelectorAll('script[src*="interface.js"][data-config]')
8
- );
9
- if (!scriptTags.length) return;
10
-
11
- // 2) Initialise un viewer par balise
12
- for (const scriptTag of scriptTags) {
13
- try {
14
- await initViewerInstance(scriptTag);
15
- } catch (e) {
16
- // Évite qu'une erreur d'instance empêche les autres de se créer
17
- console.error("[interface.js] Instance init error:", e);
 
 
 
 
18
  }
19
- }
20
- })();
21
 
22
  async function initViewerInstance(scriptTag) {
23
- // --- Lire la config ---
24
  const configUrl = scriptTag.getAttribute("data-config");
25
  if (!configUrl) return;
26
 
@@ -33,11 +37,26 @@ async function initViewerInstance(scriptTag) {
33
  return;
34
  }
35
 
36
- // --- Injecter la CSS si nécessaire (une seule fois par href absolu) ---
37
- if (config.css_url) {
38
- const already = Array.from(document.querySelectorAll('link[rel="stylesheet"]'))
39
- .some(l => l.href === config.css_url || l.getAttribute("href") === config.css_url);
40
- if (!already) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  const linkEl = document.createElement("link");
42
  linkEl.rel = "stylesheet";
43
  linkEl.href = config.css_url;
@@ -45,35 +64,31 @@ async function initViewerInstance(scriptTag) {
45
  }
46
  }
47
 
48
- // --- ID unique pour l’instance ---
49
  const instanceId = Math.random().toString(36).substr(2, 8);
50
 
51
- // --- Calcul de l’aspect ratio ---
52
  let aspectPercent = "100%";
53
  if (config.aspect) {
54
- if (config.aspect.includes(":")) {
55
- const parts = config.aspect.split(":");
56
  const w = parseFloat(parts[0]);
57
  const h = parseFloat(parts[1]);
58
- if (!isNaN(w) && !isNaN(h) && w > 0) {
59
- aspectPercent = (h / w) * 100 + "%";
60
- }
61
  } else {
62
  const aspectValue = parseFloat(config.aspect);
63
- if (!isNaN(aspectValue) && aspectValue > 0) {
64
- aspectPercent = (100 / aspectValue) + "%";
65
- }
66
  }
67
  } else {
68
  const parentContainer = scriptTag.parentNode;
69
- const containerWidth = parentContainer?.offsetWidth || 0;
70
- const containerHeight = parentContainer?.offsetHeight || 0;
71
  if (containerWidth > 0 && containerHeight > 0) {
72
  aspectPercent = (containerHeight / containerWidth) * 100 + "%";
73
  }
74
  }
75
 
76
- // --- Conteneur du widget ---
77
  const widgetContainer = document.createElement("div");
78
  widgetContainer.id = "ply-widget-container-" + instanceId;
79
  widgetContainer.classList.add("ply-widget-container");
@@ -85,6 +100,7 @@ async function initViewerInstance(scriptTag) {
85
  ? `<button id="tooltips-toggle-${instanceId}" class="widget-button tooltips-toggle">⦿</button>`
86
  : "";
87
 
 
88
  widgetContainer.innerHTML = `
89
  <div id="viewer-container-${instanceId}" class="viewer-container">
90
  <div id="progress-dialog-${instanceId}" class="progress-dialog">
@@ -101,7 +117,6 @@ async function initViewerInstance(scriptTag) {
101
  <div class="help-text"></div>
102
  </div>
103
  </div>
104
-
105
  <div id="tooltip-panel-${instanceId}" class="tooltip-panel" style="display: none;">
106
  <div class="tooltip-content">
107
  <span id="tooltip-close-${instanceId}" class="tooltip-close">×</span>
@@ -111,57 +126,51 @@ async function initViewerInstance(scriptTag) {
111
  </div>
112
  `;
113
 
114
- // Insérer juste après la balise script courante
115
  scriptTag.parentNode.appendChild(widgetContainer);
116
 
117
- // --- Références DOM pour cette instance ---
118
  const viewerContainerElem = document.getElementById("viewer-container-" + instanceId);
119
- const fullscreenToggle = document.getElementById("fullscreen-toggle-" + instanceId);
120
- const helpToggle = document.getElementById("help-toggle-" + instanceId);
121
- const helpCloseBtn = document.getElementById("help-close-" + instanceId);
122
- const resetCameraBtn = document.getElementById("reset-camera-btn-" + instanceId);
123
- const tooltipsToggleBtn = document.getElementById("tooltips-toggle-" + instanceId);
124
- const menuContent = document.getElementById("menu-content-" + instanceId);
125
- const helpTextDiv = menuContent.querySelector(".help-text");
126
-
127
- const tooltipPanel = document.getElementById("tooltip-panel-" + instanceId);
128
- const tooltipTextDiv = document.getElementById("tooltip-text-" + instanceId);
129
- const tooltipImage = document.getElementById("tooltip-image-" + instanceId);
130
  const tooltipCloseBtn = document.getElementById("tooltip-close-" + instanceId);
131
 
132
- const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
133
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
134
 
135
- // --- Texte d’aide ---
136
  const tooltipInstruction = config.tooltips_url
137
  ? "- Cliquez sur ⦿ pour afficher/masquer les tooltips.<br>"
138
  : "";
139
 
140
- if (isMobile) {
141
- helpTextDiv.innerHTML =
142
- "- Déplacez vous en glissant deux doigts sur l'écran.<br>" +
143
  "- Orbitez en glissant un doigt.<br>" +
144
  "- Zoomez en pinçant avec deux doigts.<br>" +
145
  tooltipInstruction +
146
  "- Cliquez sur ⟲ pour réinitialiser la caméra.<br>" +
147
- "- Cliquez sur ⇱ pour passer en plein écran.<br>";
148
- } else {
149
- helpTextDiv.innerHTML =
150
- "- Orbitez avec le clic droit ou shift + ←↑↓→<br>" +
151
  "- Zoomez avec la molette ou ctrl + ↑↓<br>" +
152
  "- Déplacez vous avec le clic gauche ou ←↑↓→<br>" +
153
  tooltipInstruction +
154
  "- Cliquez sur ⟲ pour réinitialiser la caméra.<br>" +
155
  "- Cliquez sur ⇱ pour passer en plein écran.<br>";
156
- }
157
 
158
- // --- Taille max du menu d’aide (mobile) ---
159
  function setMenuContentMaxSize() {
160
  if (!isMobile) {
161
- menuContent.style.maxWidth = "";
162
  menuContent.style.maxHeight = "";
163
- menuContent.style.width = "";
164
- menuContent.style.height = "";
165
  menuContent.style.overflowY = "";
166
  menuContent.style.overflowX = "";
167
  return;
@@ -171,14 +180,14 @@ async function initViewerInstance(scriptTag) {
171
  const vw = parent.offsetWidth;
172
  const vh = parent.offsetHeight;
173
  if (vw && vh) {
174
- menuContent.style.maxWidth = Math.round(vw * 0.8) + "px";
175
  menuContent.style.maxHeight = Math.round(vh * 0.8) + "px";
176
- menuContent.style.width = "";
177
- menuContent.style.height = "";
178
  menuContent.style.overflowY = "auto";
179
  menuContent.style.overflowX = "auto";
180
  } else {
181
- menuContent.style.maxWidth = "80vw";
182
  menuContent.style.maxHeight = "80vh";
183
  menuContent.style.overflowY = "auto";
184
  menuContent.style.overflowX = "auto";
@@ -190,11 +199,11 @@ async function initViewerInstance(scriptTag) {
190
  document.addEventListener("fullscreenchange", setMenuContentMaxSize);
191
  window.addEventListener("orientationchange", setMenuContentMaxSize);
192
 
193
- // --- Panneau d’aide visible par défaut ---
194
  menuContent.style.display = "block";
195
  viewerContainerElem.style.display = "block";
196
 
197
- // --- Charger viewer.js avec un paramètre unique (évite le cache/état partagé) ---
198
  let viewerModule;
199
  try {
200
  const viewerUrl = `https://mikafil-viewer-sgos.static.hf.space/viewer.js?inst=${instanceId}`;
@@ -208,7 +217,7 @@ async function initViewerInstance(scriptTag) {
208
  const canvasId = "canvas-" + instanceId;
209
  const canvasEl = document.getElementById(canvasId);
210
 
211
- // --- Bouton Tooltips : cacher si URL invalide ---
212
  if (tooltipsToggleBtn) {
213
  if (!config.tooltips_url) {
214
  tooltipsToggleBtn.style.display = "none";
@@ -223,7 +232,7 @@ async function initViewerInstance(scriptTag) {
223
  }
224
  }
225
 
226
- // --- Panneau tooltips (local à l’instance) ---
227
  let dragHide = null;
228
  function hideTooltipPanel() {
229
  if (dragHide) {
@@ -240,11 +249,7 @@ async function initViewerInstance(scriptTag) {
240
  canvasEl.addEventListener("wheel", hideTooltipPanel, { passive: true });
241
  }
242
 
243
- // NB : 'tooltip-selected' est global (émis par tooltips.js).
244
- // Ici, on affiche simplement le panneau local; si plusieurs viewers sont visibles,
245
- // chacun recevra l’événement (comportement actuel).
246
  document.addEventListener("tooltip-selected", (evt) => {
247
- // Annule un hide différé si présent
248
  if (dragHide) {
249
  viewerContainerElem.removeEventListener("pointermove", dragHide);
250
  dragHide = null;
@@ -254,12 +259,13 @@ async function initViewerInstance(scriptTag) {
254
  tooltipImage.style.display = "none";
255
  tooltipImage.src = "";
256
  if (imgUrl) {
257
- tooltipImage.onload = () => { tooltipImage.style.display = "block"; };
 
 
258
  tooltipImage.src = imgUrl;
259
  }
260
  tooltipPanel.style.display = "flex";
261
 
262
- // Fermer en cas de drag (petit délai pour éviter flicker)
263
  setTimeout(() => {
264
  dragHide = (e) => {
265
  if ((e.pointerType === "mouse" && e.buttons !== 0) || e.pointerType === "touch") {
@@ -270,7 +276,7 @@ async function initViewerInstance(scriptTag) {
270
  }, 100);
271
  });
272
 
273
- // --- Plein écran ---
274
  let isFullscreen = false;
275
  let savedState = null;
276
 
@@ -279,19 +285,19 @@ async function initViewerInstance(scriptTag) {
279
  const originalAspect = widgetContainer.getAttribute("data-original-aspect") || aspectPercent;
280
  savedState = {
281
  widget: {
282
- position: widgetContainer.style.position,
283
- top: widgetContainer.style.top,
284
- left: widgetContainer.style.left,
285
- width: widgetContainer.style.width,
286
- height: widgetContainer.style.height,
287
- maxWidth: widgetContainer.style.maxWidth,
288
- maxHeight: widgetContainer.style.maxHeight,
289
- paddingBottom: widgetContainer.style.paddingBottom || originalAspect,
290
- margin: widgetContainer.style.margin
291
  },
292
  viewer: {
293
  borderRadius: viewerContainerElem.style.borderRadius,
294
- border: viewerContainerElem.style.border
295
  }
296
  };
297
  }
@@ -300,26 +306,26 @@ async function initViewerInstance(scriptTag) {
300
  if (!savedState) return;
301
  const aspectToUse = savedState.widget.paddingBottom;
302
 
303
- widgetContainer.style.position = savedState.widget.position || "";
304
- widgetContainer.style.top = savedState.widget.top || "";
305
- widgetContainer.style.left = savedState.widget.left || "";
306
- widgetContainer.style.width = "100%";
307
- widgetContainer.style.height = "0";
308
- widgetContainer.style.maxWidth = savedState.widget.maxWidth || "";
309
- widgetContainer.style.maxHeight = savedState.widget.maxHeight || "";
310
  widgetContainer.style.paddingBottom = aspectToUse;
311
- widgetContainer.style.margin = savedState.widget.margin || "";
312
  widgetContainer.classList.remove("fake-fullscreen");
313
 
314
- viewerContainerElem.style.position = "absolute";
315
- viewerContainerElem.style.top = "0";
316
- viewerContainerElem.style.left = "0";
317
- viewerContainerElem.style.right = "0";
318
- viewerContainerElem.style.bottom = "0";
319
- viewerContainerElem.style.width = "100%";
320
- viewerContainerElem.style.height = "100%";
321
  viewerContainerElem.style.borderRadius = savedState.viewer.borderRadius || "";
322
- viewerContainerElem.style.border = savedState.viewer.border || "";
323
 
324
  if (viewerModule.app) {
325
  viewerModule.app.resizeCanvas(
@@ -335,22 +341,22 @@ async function initViewerInstance(scriptTag) {
335
  }
336
 
337
  function applyFullscreenStyles() {
338
- widgetContainer.style.position = "fixed";
339
- widgetContainer.style.top = "0";
340
- widgetContainer.style.left = "0";
341
- widgetContainer.style.width = "100vw";
342
- widgetContainer.style.height = "100vh";
343
- widgetContainer.style.maxWidth = "100vw";
344
- widgetContainer.style.maxHeight = "100vh";
345
  widgetContainer.style.paddingBottom = "0";
346
- widgetContainer.style.margin = "0";
347
- widgetContainer.style.border = "none";
348
- widgetContainer.style.borderRadius = "0";
349
 
350
- viewerContainerElem.style.width = "100%";
351
- viewerContainerElem.style.height = "100%";
352
  viewerContainerElem.style.borderRadius = "0";
353
- viewerContainerElem.style.border = "none";
354
 
355
  if (viewerModule.app) {
356
  viewerModule.app.resizeCanvas(window.innerWidth, window.innerHeight);
@@ -407,7 +413,6 @@ async function initViewerInstance(scriptTag) {
407
  setMenuContentMaxSize();
408
  });
409
 
410
- // --- Aide / Reset ---
411
  helpToggle.addEventListener("click", (e) => {
412
  hideTooltipPanel();
413
  e.stopPropagation();
@@ -422,12 +427,9 @@ async function initViewerInstance(scriptTag) {
422
 
423
  resetCameraBtn.addEventListener("click", () => {
424
  hideTooltipPanel();
425
- if (viewerModule.resetViewerCamera) {
426
- viewerModule.resetViewerCamera();
427
- }
428
  });
429
 
430
- // --- Bouton Tooltips ---
431
  if (tooltipsToggleBtn) {
432
  let tooltipsVisible = !!config.showTooltipsDefault;
433
  tooltipsToggleBtn.style.opacity = tooltipsVisible ? "1" : "0.5";
@@ -443,7 +445,10 @@ async function initViewerInstance(scriptTag) {
443
 
444
  tooltipCloseBtn.addEventListener("click", hideTooltipPanel);
445
 
446
- // --- Redimensionnement ---
 
 
 
447
  window.addEventListener("resize", () => {
448
  if (viewerModule.app) {
449
  if (isFullscreen) {
@@ -458,10 +463,9 @@ async function initViewerInstance(scriptTag) {
458
  setMenuContentMaxSize();
459
  });
460
 
461
- // --- Init par défaut ---
462
  setTimeout(() => {
463
  saveCurrentState();
464
- // Propager l'état par défaut des tooltips (événement global)
465
  document.dispatchEvent(
466
  new CustomEvent("toggle-tooltips", { detail: { visible: !!config.showTooltipsDefault } })
467
  );
 
1
  // interface.js
2
  // ==============================
3
 
4
+ // Évite les doubles initialisations si le script est inclus plusieurs fois
5
+ if (!window.__PLY_IFACE_INIT_DONE__) {
6
+ window.__PLY_IFACE_INIT_DONE__ = true;
7
+
8
+ (async function () {
9
+ // Toutes les balises <script type="module" src=".../interface.js" data-config="...">
10
+ const scriptTags = Array.from(
11
+ document.querySelectorAll('script[type="module"][src*="interface.js"][data-config]')
12
+ );
13
+ if (!scriptTags.length) return;
14
+
15
+ // Une instance par balise
16
+ for (const scriptTag of scriptTags) {
17
+ try {
18
+ await initViewerInstance(scriptTag);
19
+ } catch (e) {
20
+ console.error("[interface.js] Instance init error:", e);
21
+ }
22
  }
23
+ })();
24
+ }
25
 
26
  async function initViewerInstance(scriptTag) {
27
+ // 1) Lire la config
28
  const configUrl = scriptTag.getAttribute("data-config");
29
  if (!configUrl) return;
30
 
 
37
  return;
38
  }
39
 
40
+ // 2) CSS (une seule fois par href)
41
+ try {
42
+ if (
43
+ config.css_url &&
44
+ !document.querySelector(
45
+ `link[rel="stylesheet"][href="${
46
+ (window.CSS && CSS.escape) ? CSS.escape(config.css_url) : config.css_url
47
+ }"]`
48
+ )
49
+ ) {
50
+ const linkEl = document.createElement("link");
51
+ linkEl.rel = "stylesheet";
52
+ linkEl.href = config.css_url;
53
+ document.head.appendChild(linkEl);
54
+ }
55
+ } catch {
56
+ if (
57
+ config.css_url &&
58
+ !document.querySelector(`link[rel="stylesheet"][href="${config.css_url}"]`)
59
+ ) {
60
  const linkEl = document.createElement("link");
61
  linkEl.rel = "stylesheet";
62
  linkEl.href = config.css_url;
 
64
  }
65
  }
66
 
67
+ // 3) ID unique
68
  const instanceId = Math.random().toString(36).substr(2, 8);
69
 
70
+ // 4) Aspect ratio
71
  let aspectPercent = "100%";
72
  if (config.aspect) {
73
+ if (String(config.aspect).includes(":")) {
74
+ const parts = String(config.aspect).split(":");
75
  const w = parseFloat(parts[0]);
76
  const h = parseFloat(parts[1]);
77
+ if (!isNaN(w) && !isNaN(h) && w > 0) aspectPercent = (h / w) * 100 + "%";
 
 
78
  } else {
79
  const aspectValue = parseFloat(config.aspect);
80
+ if (!isNaN(aspectValue) && aspectValue > 0) aspectPercent = 100 / aspectValue + "%";
 
 
81
  }
82
  } else {
83
  const parentContainer = scriptTag.parentNode;
84
+ const containerWidth = parentContainer.offsetWidth;
85
+ const containerHeight = parentContainer.offsetHeight;
86
  if (containerWidth > 0 && containerHeight > 0) {
87
  aspectPercent = (containerHeight / containerWidth) * 100 + "%";
88
  }
89
  }
90
 
91
+ // 5) Container du widget
92
  const widgetContainer = document.createElement("div");
93
  widgetContainer.id = "ply-widget-container-" + instanceId;
94
  widgetContainer.classList.add("ply-widget-container");
 
100
  ? `<button id="tooltips-toggle-${instanceId}" class="widget-button tooltips-toggle">⦿</button>`
101
  : "";
102
 
103
+ // HTML (tout en backticks !)
104
  widgetContainer.innerHTML = `
105
  <div id="viewer-container-${instanceId}" class="viewer-container">
106
  <div id="progress-dialog-${instanceId}" class="progress-dialog">
 
117
  <div class="help-text"></div>
118
  </div>
119
  </div>
 
120
  <div id="tooltip-panel-${instanceId}" class="tooltip-panel" style="display: none;">
121
  <div class="tooltip-content">
122
  <span id="tooltip-close-${instanceId}" class="tooltip-close">×</span>
 
126
  </div>
127
  `;
128
 
129
+ // Insérer après la balise <script> correspondante
130
  scriptTag.parentNode.appendChild(widgetContainer);
131
 
132
+ // 6) Références DOM
133
  const viewerContainerElem = document.getElementById("viewer-container-" + instanceId);
134
+ const fullscreenToggle = document.getElementById("fullscreen-toggle-" + instanceId);
135
+ const helpToggle = document.getElementById("help-toggle-" + instanceId);
136
+ const helpCloseBtn = document.getElementById("help-close-" + instanceId);
137
+ const resetCameraBtn = document.getElementById("reset-camera-btn-" + instanceId);
138
+ const tooltipsToggleBtn = document.getElementById("tooltips-toggle-" + instanceId);
139
+ const menuContent = document.getElementById("menu-content-" + instanceId);
140
+ const helpTextDiv = menuContent.querySelector(".help-text");
141
+ const tooltipPanel = document.getElementById("tooltip-panel-" + instanceId);
142
+ const tooltipTextDiv = document.getElementById("tooltip-text-" + instanceId);
143
+ const tooltipImage = document.getElementById("tooltip-image-" + instanceId);
 
144
  const tooltipCloseBtn = document.getElementById("tooltip-close-" + instanceId);
145
 
146
+ const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
147
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
148
 
 
149
  const tooltipInstruction = config.tooltips_url
150
  ? "- Cliquez sur ⦿ pour afficher/masquer les tooltips.<br>"
151
  : "";
152
 
153
+ helpTextDiv.innerHTML = isMobile
154
+ ? "- Déplacez vous en glissant deux doigts sur l'écran.<br>" +
 
155
  "- Orbitez en glissant un doigt.<br>" +
156
  "- Zoomez en pinçant avec deux doigts.<br>" +
157
  tooltipInstruction +
158
  "- Cliquez sur ⟲ pour réinitialiser la caméra.<br>" +
159
+ "- Cliquez sur ⇱ pour passer en plein écran.<br>"
160
+ : "- Orbitez avec le clic droit ou shift + ←↑↓→<br>" +
 
 
161
  "- Zoomez avec la molette ou ctrl + ↑↓<br>" +
162
  "- Déplacez vous avec le clic gauche ou ←↑↓→<br>" +
163
  tooltipInstruction +
164
  "- Cliquez sur ⟲ pour réinitialiser la caméra.<br>" +
165
  "- Cliquez sur ⇱ pour passer en plein écran.<br>";
 
166
 
167
+ // 7) Sizing dynamique
168
  function setMenuContentMaxSize() {
169
  if (!isMobile) {
170
+ menuContent.style.maxWidth = "";
171
  menuContent.style.maxHeight = "";
172
+ menuContent.style.width = "";
173
+ menuContent.style.height = "";
174
  menuContent.style.overflowY = "";
175
  menuContent.style.overflowX = "";
176
  return;
 
180
  const vw = parent.offsetWidth;
181
  const vh = parent.offsetHeight;
182
  if (vw && vh) {
183
+ menuContent.style.maxWidth = Math.round(vw * 0.8) + "px";
184
  menuContent.style.maxHeight = Math.round(vh * 0.8) + "px";
185
+ menuContent.style.width = "";
186
+ menuContent.style.height = "";
187
  menuContent.style.overflowY = "auto";
188
  menuContent.style.overflowX = "auto";
189
  } else {
190
+ menuContent.style.maxWidth = "80vw";
191
  menuContent.style.maxHeight = "80vh";
192
  menuContent.style.overflowY = "auto";
193
  menuContent.style.overflowX = "auto";
 
199
  document.addEventListener("fullscreenchange", setMenuContentMaxSize);
200
  window.addEventListener("orientationchange", setMenuContentMaxSize);
201
 
202
+ // Visibilité par défaut
203
  menuContent.style.display = "block";
204
  viewerContainerElem.style.display = "block";
205
 
206
+ // 8) Charger viewer.js (avec un param unique pour isoler les instances)
207
  let viewerModule;
208
  try {
209
  const viewerUrl = `https://mikafil-viewer-sgos.static.hf.space/viewer.js?inst=${instanceId}`;
 
217
  const canvasId = "canvas-" + instanceId;
218
  const canvasEl = document.getElementById(canvasId);
219
 
220
+ // 9) Gérer le bouton tooltips
221
  if (tooltipsToggleBtn) {
222
  if (!config.tooltips_url) {
223
  tooltipsToggleBtn.style.display = "none";
 
232
  }
233
  }
234
 
235
+ // 10) Panneau tooltips
236
  let dragHide = null;
237
  function hideTooltipPanel() {
238
  if (dragHide) {
 
249
  canvasEl.addEventListener("wheel", hideTooltipPanel, { passive: true });
250
  }
251
 
 
 
 
252
  document.addEventListener("tooltip-selected", (evt) => {
 
253
  if (dragHide) {
254
  viewerContainerElem.removeEventListener("pointermove", dragHide);
255
  dragHide = null;
 
259
  tooltipImage.style.display = "none";
260
  tooltipImage.src = "";
261
  if (imgUrl) {
262
+ tooltipImage.onload = () => {
263
+ tooltipImage.style.display = "block";
264
+ };
265
  tooltipImage.src = imgUrl;
266
  }
267
  tooltipPanel.style.display = "flex";
268
 
 
269
  setTimeout(() => {
270
  dragHide = (e) => {
271
  if ((e.pointerType === "mouse" && e.buttons !== 0) || e.pointerType === "touch") {
 
276
  }, 100);
277
  });
278
 
279
+ // 11) Plein écran & UI
280
  let isFullscreen = false;
281
  let savedState = null;
282
 
 
285
  const originalAspect = widgetContainer.getAttribute("data-original-aspect") || aspectPercent;
286
  savedState = {
287
  widget: {
288
+ position: widgetContainer.style.position,
289
+ top: widgetContainer.style.top,
290
+ left: widgetContainer.style.left,
291
+ width: widgetContainer.style.width,
292
+ height: widgetContainer.style.height,
293
+ maxWidth: widgetContainer.style.maxWidth,
294
+ maxHeight: widgetContainer.style.maxHeight,
295
+ paddingBottom: widgetContainer.style.paddingBottom || originalAspect,
296
+ margin: widgetContainer.style.margin
297
  },
298
  viewer: {
299
  borderRadius: viewerContainerElem.style.borderRadius,
300
+ border: viewerContainerElem.style.border
301
  }
302
  };
303
  }
 
306
  if (!savedState) return;
307
  const aspectToUse = savedState.widget.paddingBottom;
308
 
309
+ widgetContainer.style.position = savedState.widget.position || "";
310
+ widgetContainer.style.top = savedState.widget.top || "";
311
+ widgetContainer.style.left = savedState.widget.left || "";
312
+ widgetContainer.style.width = "100%";
313
+ widgetContainer.style.height = "0";
314
+ widgetContainer.style.maxWidth = savedState.widget.maxWidth || "";
315
+ widgetContainer.style.maxHeight = savedState.widget.maxHeight || "";
316
  widgetContainer.style.paddingBottom = aspectToUse;
317
+ widgetContainer.style.margin = savedState.widget.margin || "";
318
  widgetContainer.classList.remove("fake-fullscreen");
319
 
320
+ viewerContainerElem.style.position = "absolute";
321
+ viewerContainerElem.style.top = "0";
322
+ viewerContainerElem.style.left = "0";
323
+ viewerContainerElem.style.right = "0";
324
+ viewerContainerElem.style.bottom = "0";
325
+ viewerContainerElem.style.width = "100%";
326
+ viewerContainerElem.style.height = "100%";
327
  viewerContainerElem.style.borderRadius = savedState.viewer.borderRadius || "";
328
+ viewerContainerElem.style.border = savedState.viewer.border || "";
329
 
330
  if (viewerModule.app) {
331
  viewerModule.app.resizeCanvas(
 
341
  }
342
 
343
  function applyFullscreenStyles() {
344
+ widgetContainer.style.position = "fixed";
345
+ widgetContainer.style.top = "0";
346
+ widgetContainer.style.left = "0";
347
+ widgetContainer.style.width = "100vw";
348
+ widgetContainer.style.height = "100vh";
349
+ widgetContainer.style.maxWidth = "100vw";
350
+ widgetContainer.style.maxHeight = "100vh";
351
  widgetContainer.style.paddingBottom = "0";
352
+ widgetContainer.style.margin = "0";
353
+ widgetContainer.style.border = "none";
354
+ widgetContainer.style.borderRadius = "0";
355
 
356
+ viewerContainerElem.style.width = "100%";
357
+ viewerContainerElem.style.height = "100%";
358
  viewerContainerElem.style.borderRadius = "0";
359
+ viewerContainerElem.style.border = "none";
360
 
361
  if (viewerModule.app) {
362
  viewerModule.app.resizeCanvas(window.innerWidth, window.innerHeight);
 
413
  setMenuContentMaxSize();
414
  });
415
 
 
416
  helpToggle.addEventListener("click", (e) => {
417
  hideTooltipPanel();
418
  e.stopPropagation();
 
427
 
428
  resetCameraBtn.addEventListener("click", () => {
429
  hideTooltipPanel();
430
+ if (viewerModule.resetViewerCamera) viewerModule.resetViewerCamera();
 
 
431
  });
432
 
 
433
  if (tooltipsToggleBtn) {
434
  let tooltipsVisible = !!config.showTooltipsDefault;
435
  tooltipsToggleBtn.style.opacity = tooltipsVisible ? "1" : "0.5";
 
445
 
446
  tooltipCloseBtn.addEventListener("click", hideTooltipPanel);
447
 
448
+ document.addEventListener("keydown", (e) => {
449
+ if ((e.key === "Escape" || e.key === "Esc") && isFullscreen) exitFullscreen();
450
+ });
451
+
452
  window.addEventListener("resize", () => {
453
  if (viewerModule.app) {
454
  if (isFullscreen) {
 
463
  setMenuContentMaxSize();
464
  });
465
 
466
+ // Init par défaut
467
  setTimeout(() => {
468
  saveCurrentState();
 
469
  document.dispatchEvent(
470
  new CustomEvent("toggle-tooltips", { detail: { visible: !!config.showTooltipsDefault } })
471
  );