MikaFil commited on
Commit
58dd504
·
verified ·
1 Parent(s): 5f9d55b

Update interface.js

Browse files
Files changed (1) hide show
  1. interface.js +169 -111
interface.js CHANGED
@@ -3,8 +3,8 @@
3
 
4
  const currentScriptTag = document.currentScript;
5
 
6
- (async function() {
7
- // 1. Locate the <script> and read data-config
8
  let scriptTag = currentScriptTag;
9
  if (!scriptTag) {
10
  const scripts = document.getElementsByTagName('script');
@@ -18,7 +18,9 @@ const currentScriptTag = document.currentScript;
18
  scriptTag = scripts[scripts.length - 1];
19
  }
20
  }
 
21
 
 
22
  const configUrl = scriptTag.getAttribute('data-config');
23
  let config = {};
24
  if (configUrl) {
@@ -26,49 +28,55 @@ const currentScriptTag = document.currentScript;
26
  const response = await fetch(configUrl);
27
  config = await response.json();
28
  } catch (error) {
 
29
  return;
30
  }
31
  } else {
 
32
  return;
33
  }
34
 
 
35
  if (config.css_url) {
36
  const linkEl = document.createElement('link');
37
- linkEl.rel = "stylesheet";
38
  linkEl.href = config.css_url;
39
  document.head.appendChild(linkEl);
40
  }
41
 
 
42
  const instanceId = Math.random().toString(36).substr(2, 8);
43
 
44
- let aspectPercent = "100%";
 
45
  if (config.aspect) {
46
- if (config.aspect.includes(":")) {
47
- const parts = config.aspect.split(":");
48
  const w = parseFloat(parts[0]);
49
  const h = parseFloat(parts[1]);
50
  if (!isNaN(w) && !isNaN(h) && w > 0) {
51
- aspectPercent = (h / w * 100) + "%";
52
  }
53
  } else {
54
  const aspectValue = parseFloat(config.aspect);
55
  if (!isNaN(aspectValue) && aspectValue > 0) {
56
- aspectPercent = (100 / aspectValue) + "%";
57
  }
58
  }
59
  } else {
60
  const parentContainer = scriptTag.parentNode;
61
- const containerWidth = parentContainer.offsetWidth;
62
  const containerHeight = parentContainer.offsetHeight;
63
  if (containerWidth > 0 && containerHeight > 0) {
64
- aspectPercent = (containerHeight / containerWidth * 100) + "%";
65
  }
66
  }
67
 
 
68
  const widgetContainer = document.createElement('div');
69
  widgetContainer.id = 'ply-widget-container-' + instanceId;
70
  widgetContainer.classList.add('ply-widget-container');
71
- widgetContainer.style.height = "0";
72
  widgetContainer.style.paddingBottom = aspectPercent;
73
  widgetContainer.setAttribute('data-original-aspect', aspectPercent);
74
 
@@ -76,6 +84,14 @@ const currentScriptTag = document.currentScript;
76
  ? `<button id="tooltips-toggle-${instanceId}" class="widget-button tooltips-toggle">⦿</button>`
77
  : '';
78
 
 
 
 
 
 
 
 
 
79
  widgetContainer.innerHTML = `
80
  <div id="viewer-container-${instanceId}" class="viewer-container">
81
  <div id="progress-dialog-${instanceId}" class="progress-dialog">
@@ -83,40 +99,41 @@ const currentScriptTag = document.currentScript;
83
  </div>
84
  <button id="fullscreen-toggle-${instanceId}" class="widget-button fullscreen-toggle">⇱</button>
85
  <button id="help-toggle-${instanceId}" class="widget-button help-toggle">?</button>
86
- <button id="reset-camera-btn-${instanceId}" class="widget-button reset-camera-btn">
87
- <span class="reset-icon">⟲</span>
88
- </button>
89
  ${tooltipsButtonHTML}
90
  <div id="menu-content-${instanceId}" class="menu-content">
91
  <span id="help-close-${instanceId}" class="help-close">×</span>
92
  <div class="help-text"></div>
93
  </div>
94
  </div>
95
- <div id="tooltip-panel" class="tooltip-panel" style="display: none;">
96
  <div class="tooltip-content">
97
- <span id="tooltip-close" class="tooltip-close">×</span>
98
- <div id="tooltip-text" class="tooltip-text"></div>
99
- <img id="tooltip-image" class="tooltip-image" src="" alt="" style="display: none;" />
100
  </div>
101
  </div>
102
  `;
103
 
104
  scriptTag.parentNode.appendChild(widgetContainer);
105
 
 
106
  const viewerContainerElem = document.getElementById('viewer-container-' + instanceId);
107
- const fullscreenToggle = document.getElementById('fullscreen-toggle-' + instanceId);
108
- const helpToggle = document.getElementById('help-toggle-' + instanceId);
109
- const helpCloseBtn = document.getElementById('help-close-' + instanceId);
110
- const resetCameraBtn = document.getElementById('reset-camera-btn-' + instanceId);
111
- const tooltipsToggleBtn = document.getElementById('tooltips-toggle-' + instanceId);
112
- const menuContent = document.getElementById('menu-content-' + instanceId);
113
- const helpTextDiv = menuContent.querySelector('.help-text');
114
- const tooltipPanel = document.getElementById('tooltip-panel');
115
- const tooltipTextDiv = document.getElementById('tooltip-text');
116
- const tooltipImage = document.getElementById('tooltip-image');
117
- const tooltipCloseBtn = document.getElementById('tooltip-close');
118
-
119
- const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
 
 
120
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
121
 
122
  const tooltipInstruction = config.tooltips_url
@@ -124,7 +141,7 @@ const currentScriptTag = document.currentScript;
124
  : '';
125
 
126
  if (isMobile) {
127
- helpTextDiv.innerHTML =
128
  '- Déplacez vous en glissant deux doigts sur l\'écran.<br>' +
129
  '- Orbitez en glissant un doigt.<br>' +
130
  '- Zoomez en pinçant avec deux doigts.<br>' +
@@ -132,7 +149,7 @@ const currentScriptTag = document.currentScript;
132
  '- Cliquez sur ⟲ pour réinitialiser la caméra.<br>' +
133
  '- Cliquez sur ⇱ pour passer en plein écran.<br>';
134
  } else {
135
- helpTextDiv.innerHTML =
136
  '- Orbitez avec le clic droit ou shift + ←↑↓→<br>' +
137
  '- Zoomez avec la molette ou ctrl + ↑↓<br>' +
138
  '- Déplacez vous avec le clic gauche ou ←↑↓→<br>' +
@@ -141,33 +158,33 @@ const currentScriptTag = document.currentScript;
141
  '- Cliquez sur ⇱ pour passer en plein écran.<br>';
142
  }
143
 
144
- // --- DYNAMIC MENU SIZING ---
145
  function setMenuContentMaxSize() {
146
  if (!isMobile) {
147
- menuContent.style.maxWidth = "";
148
- menuContent.style.maxHeight = "";
149
- menuContent.style.width = "";
150
- menuContent.style.height = "";
151
- menuContent.style.overflowY = "";
152
- menuContent.style.overflowX = "";
153
  return;
154
  }
155
- let parent = viewerContainerElem;
156
  if (parent) {
157
  const vw = parent.offsetWidth;
158
  const vh = parent.offsetHeight;
159
  if (vw && vh) {
160
- menuContent.style.maxWidth = Math.round(vw * 0.8) + "px";
161
- menuContent.style.maxHeight = Math.round(vh * 0.8) + "px";
162
- menuContent.style.width = ""; // Let it shrink if smaller
163
- menuContent.style.height = "";
164
- menuContent.style.overflowY = "auto";
165
- menuContent.style.overflowX = "auto";
166
  } else {
167
- menuContent.style.maxWidth = "80vw";
168
- menuContent.style.maxHeight = "80vh";
169
- menuContent.style.overflowY = "auto";
170
- menuContent.style.overflowX = "auto";
171
  }
172
  }
173
  }
@@ -176,13 +193,12 @@ const currentScriptTag = document.currentScript;
176
  document.addEventListener('fullscreenchange', setMenuContentMaxSize);
177
  window.addEventListener('orientationchange', setMenuContentMaxSize);
178
 
179
- // --- HELP PANEL DEFAULT VISIBILITY ---
180
  menuContent.style.display = 'block';
181
-
182
  viewerContainerElem.style.display = 'block';
183
 
 
184
  let dragHide = null;
185
-
186
  function hideTooltipPanel() {
187
  if (dragHide) {
188
  viewerContainerElem.removeEventListener('pointermove', dragHide);
@@ -194,18 +210,21 @@ const currentScriptTag = document.currentScript;
194
  menuContent.style.display = 'none';
195
  }
196
 
197
- // 7. Dynamically load viewer.js
198
  let viewerModule;
199
  try {
200
- viewerModule = await import('https://mikafil-viewer-sgos.static.hf.space/viewer.js');
 
201
  await viewerModule.initializeViewer(config, instanceId);
202
  } catch (err) {
 
203
  return;
204
  }
205
 
206
  const canvasId = 'canvas-' + instanceId;
207
  const canvasEl = document.getElementById(canvasId);
208
 
 
209
  if (tooltipsToggleBtn) {
210
  if (!config.tooltips_url) {
211
  tooltipsToggleBtn.style.display = 'none';
@@ -216,6 +235,7 @@ const currentScriptTag = document.currentScript;
216
  }
217
  }
218
 
 
219
  let isFullscreen = false;
220
  let savedState = null;
221
 
@@ -225,18 +245,18 @@ const currentScriptTag = document.currentScript;
225
  savedState = {
226
  widget: {
227
  position: widgetContainer.style.position,
228
- top: widgetContainer.style.top,
229
- left: widgetContainer.style.left,
230
- width: widgetContainer.style.width,
231
- height: widgetContainer.style.height,
232
  maxWidth: widgetContainer.style.maxWidth,
233
- maxHeight:widgetContainer.style.maxHeight,
234
  paddingBottom: widgetContainer.style.paddingBottom || originalAspect,
235
- margin: widgetContainer.style.margin,
236
  },
237
  viewer: {
238
  borderRadius: viewerContainerElem.style.borderRadius,
239
- border: viewerContainerElem.style.border,
240
  }
241
  };
242
  }
@@ -244,26 +264,27 @@ const currentScriptTag = document.currentScript;
244
  function restoreOriginalStyles() {
245
  if (!savedState) return;
246
  const aspectToUse = savedState.widget.paddingBottom;
247
- widgetContainer.style.position = savedState.widget.position || "";
248
- widgetContainer.style.top = savedState.widget.top || "";
249
- widgetContainer.style.left = savedState.widget.left || "";
250
- widgetContainer.style.width = "100%";
251
- widgetContainer.style.height = "0";
252
- widgetContainer.style.maxWidth = savedState.widget.maxWidth || "";
253
- widgetContainer.style.maxHeight = savedState.widget.maxHeight || "";
254
- widgetContainer.style.paddingBottom= aspectToUse;
255
- widgetContainer.style.margin = savedState.widget.margin || "";
 
256
  widgetContainer.classList.remove('fake-fullscreen');
257
 
258
- viewerContainerElem.style.position = "absolute";
259
- viewerContainerElem.style.top = "0";
260
- viewerContainerElem.style.left = "0";
261
- viewerContainerElem.style.right = "0";
262
- viewerContainerElem.style.bottom = "0";
263
- viewerContainerElem.style.width = "100%";
264
- viewerContainerElem.style.height = "100%";
265
- viewerContainerElem.style.borderRadius = savedState.viewer.borderRadius || "";
266
- viewerContainerElem.style.border = savedState.viewer.border || "";
267
 
268
  if (viewerModule.app) {
269
  viewerModule.app.resizeCanvas(
@@ -279,22 +300,22 @@ const currentScriptTag = document.currentScript;
279
  }
280
 
281
  function applyFullscreenStyles() {
282
- widgetContainer.style.position = 'fixed';
283
- widgetContainer.style.top = '0';
284
- widgetContainer.style.left = '0';
285
- widgetContainer.style.width = '100vw';
286
- widgetContainer.style.height = '100vh';
287
- widgetContainer.style.maxWidth = '100vw';
288
- widgetContainer.style.maxHeight = '100vh';
289
  widgetContainer.style.paddingBottom = '0';
290
- widgetContainer.style.margin = '0';
291
- widgetContainer.style.border = 'none';
292
- widgetContainer.style.borderRadius = '0';
293
 
294
- viewerContainerElem.style.width = '100%';
295
- viewerContainerElem.style.height = '100%';
296
- viewerContainerElem.style.borderRadius= '0';
297
- viewerContainerElem.style.border = 'none';
298
 
299
  if (viewerModule.app) {
300
  viewerModule.app.resizeCanvas(window.innerWidth, window.innerHeight);
@@ -307,6 +328,7 @@ const currentScriptTag = document.currentScript;
307
 
308
  function enterFullscreen() {
309
  if (!savedState) saveCurrentState();
 
310
  if (isIOS) {
311
  applyFullscreenStyles();
312
  widgetContainer.classList.add('fake-fullscreen');
@@ -325,7 +347,7 @@ const currentScriptTag = document.currentScript;
325
 
326
  function exitFullscreen() {
327
  if (document.fullscreenElement === widgetContainer && document.exitFullscreen) {
328
- document.exitFullscreen().catch(() => {});
329
  }
330
  widgetContainer.classList.remove('fake-fullscreen');
331
  restoreOriginalStyles();
@@ -350,10 +372,10 @@ const currentScriptTag = document.currentScript;
350
  setMenuContentMaxSize();
351
  });
352
 
 
353
  helpToggle.addEventListener('click', (e) => {
354
  hideTooltipPanel();
355
  e.stopPropagation();
356
- // Toggle menu panel
357
  if (menuContent.style.display === 'block') {
358
  menuContent.style.display = 'none';
359
  } else {
@@ -370,6 +392,7 @@ const currentScriptTag = document.currentScript;
370
  }
371
  });
372
 
 
373
  if (tooltipsToggleBtn) {
374
  let tooltipsVisible = !!config.showTooltipsDefault;
375
  tooltipsToggleBtn.style.opacity = tooltipsVisible ? '1' : '0.5';
@@ -377,33 +400,64 @@ const currentScriptTag = document.currentScript;
377
  hideTooltipPanel();
378
  tooltipsVisible = !tooltipsVisible;
379
  tooltipsToggleBtn.style.opacity = tooltipsVisible ? '1' : '0.5';
380
- document.dispatchEvent(new CustomEvent('toggle-tooltips', { detail: { visible: tooltipsVisible } }));
 
 
 
 
 
 
 
 
 
381
  });
382
  }
383
 
 
384
  tooltipCloseBtn.addEventListener('click', hideTooltipPanel);
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  document.addEventListener('tooltip-selected', (evt) => {
387
- // Always show panel, cancel hide first
 
 
 
 
 
 
388
  if (dragHide) {
389
  viewerContainerElem.removeEventListener('pointermove', dragHide);
390
  dragHide = null;
391
  }
392
- const { title, description, imgUrl } = evt.detail;
393
- tooltipTextDiv.innerHTML = `<strong>${title}</strong><br>${description}`;
394
- // Force a repaint: clear src before setting, for repeated images
395
  tooltipImage.style.display = 'none';
396
  tooltipImage.src = '';
397
  if (imgUrl) {
398
- tooltipImage.onload = () => {
399
- tooltipImage.style.display = 'block';
400
- };
401
  tooltipImage.src = imgUrl;
402
- } else {
403
- tooltipImage.style.display = 'none';
404
  }
405
  tooltipPanel.style.display = 'flex';
406
- // --- DELAYED pointermove handler ---
 
407
  setTimeout(() => {
408
  dragHide = (e) => {
409
  if ((e.pointerType === 'mouse' && e.buttons !== 0) || e.pointerType === 'touch') {
@@ -412,8 +466,9 @@ const currentScriptTag = document.currentScript;
412
  };
413
  viewerContainerElem.addEventListener('pointermove', dragHide);
414
  }, 100);
415
- });
416
 
 
417
  if (canvasEl) {
418
  canvasEl.addEventListener('wheel', hideTooltipPanel, { passive: true });
419
  }
@@ -434,10 +489,13 @@ const currentScriptTag = document.currentScript;
434
  setMenuContentMaxSize();
435
  });
436
 
 
437
  setTimeout(() => {
438
  saveCurrentState();
439
- document.dispatchEvent(new CustomEvent('toggle-tooltips', { detail: { visible: !!config.showTooltipsDefault } }));
 
 
 
440
  setMenuContentMaxSize();
441
  }, 200);
442
-
443
  })();
 
3
 
4
  const currentScriptTag = document.currentScript;
5
 
6
+ (async function () {
7
+ // 1) Retrouver la balise <script> porteuse de data-config
8
  let scriptTag = currentScriptTag;
9
  if (!scriptTag) {
10
  const scripts = document.getElementsByTagName('script');
 
18
  scriptTag = scripts[scripts.length - 1];
19
  }
20
  }
21
+ if (!scriptTag) return;
22
 
23
+ // 2) Charger la config
24
  const configUrl = scriptTag.getAttribute('data-config');
25
  let config = {};
26
  if (configUrl) {
 
28
  const response = await fetch(configUrl);
29
  config = await response.json();
30
  } catch (error) {
31
+ console.error('[interface.js] Failed to load config:', error);
32
  return;
33
  }
34
  } else {
35
+ console.warn('[interface.js] No data-config provided.');
36
  return;
37
  }
38
 
39
+ // 3) CSS optionnel
40
  if (config.css_url) {
41
  const linkEl = document.createElement('link');
42
+ linkEl.rel = 'stylesheet';
43
  linkEl.href = config.css_url;
44
  document.head.appendChild(linkEl);
45
  }
46
 
47
+ // 4) ID d’instance
48
  const instanceId = Math.random().toString(36).substr(2, 8);
49
 
50
+ // 5) Calcul de l’aspect
51
+ let aspectPercent = '100%';
52
  if (config.aspect) {
53
+ if (config.aspect.includes(':')) {
54
+ const parts = config.aspect.split(':');
55
  const w = parseFloat(parts[0]);
56
  const h = parseFloat(parts[1]);
57
  if (!isNaN(w) && !isNaN(h) && w > 0) {
58
+ aspectPercent = (h / w * 100) + '%';
59
  }
60
  } else {
61
  const aspectValue = parseFloat(config.aspect);
62
  if (!isNaN(aspectValue) && aspectValue > 0) {
63
+ aspectPercent = (100 / aspectValue) + '%';
64
  }
65
  }
66
  } else {
67
  const parentContainer = scriptTag.parentNode;
68
+ const containerWidth = parentContainer.offsetWidth;
69
  const containerHeight = parentContainer.offsetHeight;
70
  if (containerWidth > 0 && containerHeight > 0) {
71
+ aspectPercent = (containerHeight / containerWidth * 100) + '%';
72
  }
73
  }
74
 
75
+ // 6) Conteneur widget
76
  const widgetContainer = document.createElement('div');
77
  widgetContainer.id = 'ply-widget-container-' + instanceId;
78
  widgetContainer.classList.add('ply-widget-container');
79
+ widgetContainer.style.height = '0';
80
  widgetContainer.style.paddingBottom = aspectPercent;
81
  widgetContainer.setAttribute('data-original-aspect', aspectPercent);
82
 
 
84
  ? `<button id="tooltips-toggle-${instanceId}" class="widget-button tooltips-toggle">⦿</button>`
85
  : '';
86
 
87
+ // IDs uniques pour le panneau tooltips
88
+ const tooltipIds = {
89
+ panel: `tooltip-panel-${instanceId}`,
90
+ close: `tooltip-close-${instanceId}`,
91
+ text: `tooltip-text-${instanceId}`,
92
+ image: `tooltip-image-${instanceId}`
93
+ };
94
+
95
  widgetContainer.innerHTML = `
96
  <div id="viewer-container-${instanceId}" class="viewer-container">
97
  <div id="progress-dialog-${instanceId}" class="progress-dialog">
 
99
  </div>
100
  <button id="fullscreen-toggle-${instanceId}" class="widget-button fullscreen-toggle">⇱</button>
101
  <button id="help-toggle-${instanceId}" class="widget-button help-toggle">?</button>
102
+ <button id="reset-camera-btn-${instanceId}" class="widget-button reset-camera-btn"><span class="reset-icon">⟲</span></button>
 
 
103
  ${tooltipsButtonHTML}
104
  <div id="menu-content-${instanceId}" class="menu-content">
105
  <span id="help-close-${instanceId}" class="help-close">×</span>
106
  <div class="help-text"></div>
107
  </div>
108
  </div>
109
+ <div id="${tooltipIds.panel}" class="tooltip-panel" style="display: none;">
110
  <div class="tooltip-content">
111
+ <span id="${tooltipIds.close}" class="tooltip-close">×</span>
112
+ <div id="${tooltipIds.text}" class="tooltip-text"></div>
113
+ <img id="${tooltipIds.image}" class="tooltip-image" src="" alt="" style="display: none;" />
114
  </div>
115
  </div>
116
  `;
117
 
118
  scriptTag.parentNode.appendChild(widgetContainer);
119
 
120
+ // 7) Sélecteurs
121
  const viewerContainerElem = document.getElementById('viewer-container-' + instanceId);
122
+ const fullscreenToggle = document.getElementById('fullscreen-toggle-' + instanceId);
123
+ const helpToggle = document.getElementById('help-toggle-' + instanceId);
124
+ const helpCloseBtn = document.getElementById('help-close-' + instanceId);
125
+ const resetCameraBtn = document.getElementById('reset-camera-btn-' + instanceId);
126
+ const tooltipsToggleBtn = document.getElementById('tooltips-toggle-' + instanceId);
127
+ const menuContent = document.getElementById('menu-content-' + instanceId);
128
+ const helpTextDiv = menuContent.querySelector('.help-text');
129
+
130
+ // Tooltips (IDs uniques)
131
+ const tooltipPanel = document.getElementById(tooltipIds.panel);
132
+ const tooltipTextDiv = document.getElementById(tooltipIds.text);
133
+ const tooltipImage = document.getElementById(tooltipIds.image);
134
+ const tooltipCloseBtn = document.getElementById(tooltipIds.close);
135
+
136
+ const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
137
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
138
 
139
  const tooltipInstruction = config.tooltips_url
 
141
  : '';
142
 
143
  if (isMobile) {
144
+ helpTextDiv.innerHTML =
145
  '- Déplacez vous en glissant deux doigts sur l\'écran.<br>' +
146
  '- Orbitez en glissant un doigt.<br>' +
147
  '- Zoomez en pinçant avec deux doigts.<br>' +
 
149
  '- Cliquez sur ⟲ pour réinitialiser la caméra.<br>' +
150
  '- Cliquez sur ⇱ pour passer en plein écran.<br>';
151
  } else {
152
+ helpTextDiv.innerHTML =
153
  '- Orbitez avec le clic droit ou shift + ←↑↓→<br>' +
154
  '- Zoomez avec la molette ou ctrl + ↑↓<br>' +
155
  '- Déplacez vous avec le clic gauche ou ←↑↓→<br>' +
 
158
  '- Cliquez sur ⇱ pour passer en plein écran.<br>';
159
  }
160
 
161
+ // Menu responsive
162
  function setMenuContentMaxSize() {
163
  if (!isMobile) {
164
+ menuContent.style.maxWidth = '';
165
+ menuContent.style.maxHeight = '';
166
+ menuContent.style.width = '';
167
+ menuContent.style.height = '';
168
+ menuContent.style.overflowY = '';
169
+ menuContent.style.overflowX = '';
170
  return;
171
  }
172
+ const parent = viewerContainerElem;
173
  if (parent) {
174
  const vw = parent.offsetWidth;
175
  const vh = parent.offsetHeight;
176
  if (vw && vh) {
177
+ menuContent.style.maxWidth = Math.round(vw * 0.8) + 'px';
178
+ menuContent.style.maxHeight = Math.round(vh * 0.8) + 'px';
179
+ menuContent.style.width = '';
180
+ menuContent.style.height = '';
181
+ menuContent.style.overflowY = 'auto';
182
+ menuContent.style.overflowX = 'auto';
183
  } else {
184
+ menuContent.style.maxWidth = '80vw';
185
+ menuContent.style.maxHeight = '80vh';
186
+ menuContent.style.overflowY = 'auto';
187
+ menuContent.style.overflowX = 'auto';
188
  }
189
  }
190
  }
 
193
  document.addEventListener('fullscreenchange', setMenuContentMaxSize);
194
  window.addEventListener('orientationchange', setMenuContentMaxSize);
195
 
196
+ // Afficher l’aide par défaut
197
  menuContent.style.display = 'block';
 
198
  viewerContainerElem.style.display = 'block';
199
 
200
+ // Fonctions panneau tooltips / aide
201
  let dragHide = null;
 
202
  function hideTooltipPanel() {
203
  if (dragHide) {
204
  viewerContainerElem.removeEventListener('pointermove', dragHide);
 
210
  menuContent.style.display = 'none';
211
  }
212
 
213
+ // 8) Charger viewer.js (anti-cache multi-instance via query param)
214
  let viewerModule;
215
  try {
216
+ const viewerUrl = `https://mikafil-viewer-sgos.static.hf.space/viewer.js?i=${instanceId}`;
217
+ viewerModule = await import(viewerUrl);
218
  await viewerModule.initializeViewer(config, instanceId);
219
  } catch (err) {
220
+ console.error('[interface.js] Failed to init viewer:', err);
221
  return;
222
  }
223
 
224
  const canvasId = 'canvas-' + instanceId;
225
  const canvasEl = document.getElementById(canvasId);
226
 
227
+ // Si tooltips non dispo, masquer le bouton
228
  if (tooltipsToggleBtn) {
229
  if (!config.tooltips_url) {
230
  tooltipsToggleBtn.style.display = 'none';
 
235
  }
236
  }
237
 
238
+ // 9) Plein écran
239
  let isFullscreen = false;
240
  let savedState = null;
241
 
 
245
  savedState = {
246
  widget: {
247
  position: widgetContainer.style.position,
248
+ top: widgetContainer.style.top,
249
+ left: widgetContainer.style.left,
250
+ width: widgetContainer.style.width,
251
+ height: widgetContainer.style.height,
252
  maxWidth: widgetContainer.style.maxWidth,
253
+ maxHeight: widgetContainer.style.maxHeight,
254
  paddingBottom: widgetContainer.style.paddingBottom || originalAspect,
255
+ margin: widgetContainer.style.margin
256
  },
257
  viewer: {
258
  borderRadius: viewerContainerElem.style.borderRadius,
259
+ border: viewerContainerElem.style.border
260
  }
261
  };
262
  }
 
264
  function restoreOriginalStyles() {
265
  if (!savedState) return;
266
  const aspectToUse = savedState.widget.paddingBottom;
267
+
268
+ widgetContainer.style.position = savedState.widget.position || '';
269
+ widgetContainer.style.top = savedState.widget.top || '';
270
+ widgetContainer.style.left = savedState.widget.left || '';
271
+ widgetContainer.style.width = '100%';
272
+ widgetContainer.style.height = '0';
273
+ widgetContainer.style.maxWidth = savedState.widget.maxWidth || '';
274
+ widgetContainer.style.maxHeight = savedState.widget.maxHeight || '';
275
+ widgetContainer.style.paddingBottom = aspectToUse;
276
+ widgetContainer.style.margin = savedState.widget.margin || '';
277
  widgetContainer.classList.remove('fake-fullscreen');
278
 
279
+ viewerContainerElem.style.position = 'absolute';
280
+ viewerContainerElem.style.top = '0';
281
+ viewerContainerElem.style.left = '0';
282
+ viewerContainerElem.style.right = '0';
283
+ viewerContainerElem.style.bottom = '0';
284
+ viewerContainerElem.style.width = '100%';
285
+ viewerContainerElem.style.height = '100%';
286
+ viewerContainerElem.style.borderRadius = savedState.viewer.borderRadius || '';
287
+ viewerContainerElem.style.border = savedState.viewer.border || '';
288
 
289
  if (viewerModule.app) {
290
  viewerModule.app.resizeCanvas(
 
300
  }
301
 
302
  function applyFullscreenStyles() {
303
+ widgetContainer.style.position = 'fixed';
304
+ widgetContainer.style.top = '0';
305
+ widgetContainer.style.left = '0';
306
+ widgetContainer.style.width = '100vw';
307
+ widgetContainer.style.height = '100vh';
308
+ widgetContainer.style.maxWidth = '100vw';
309
+ widgetContainer.style.maxHeight = '100vh';
310
  widgetContainer.style.paddingBottom = '0';
311
+ widgetContainer.style.margin = '0';
312
+ widgetContainer.style.border = 'none';
313
+ widgetContainer.style.borderRadius = '0';
314
 
315
+ viewerContainerElem.style.width = '100%';
316
+ viewerContainerElem.style.height = '100%';
317
+ viewerContainerElem.style.borderRadius = '0';
318
+ viewerContainerElem.style.border = 'none';
319
 
320
  if (viewerModule.app) {
321
  viewerModule.app.resizeCanvas(window.innerWidth, window.innerHeight);
 
328
 
329
  function enterFullscreen() {
330
  if (!savedState) saveCurrentState();
331
+
332
  if (isIOS) {
333
  applyFullscreenStyles();
334
  widgetContainer.classList.add('fake-fullscreen');
 
347
 
348
  function exitFullscreen() {
349
  if (document.fullscreenElement === widgetContainer && document.exitFullscreen) {
350
+ document.exitFullscreen().catch(() => { /* noop */ });
351
  }
352
  widgetContainer.classList.remove('fake-fullscreen');
353
  restoreOriginalStyles();
 
372
  setMenuContentMaxSize();
373
  });
374
 
375
+ // 10) Aide / reset
376
  helpToggle.addEventListener('click', (e) => {
377
  hideTooltipPanel();
378
  e.stopPropagation();
 
379
  if (menuContent.style.display === 'block') {
380
  menuContent.style.display = 'none';
381
  } else {
 
392
  }
393
  });
394
 
395
+ // 11) Tooltips (bouton)
396
  if (tooltipsToggleBtn) {
397
  let tooltipsVisible = !!config.showTooltipsDefault;
398
  tooltipsToggleBtn.style.opacity = tooltipsVisible ? '1' : '0.5';
 
400
  hideTooltipPanel();
401
  tooltipsVisible = !tooltipsVisible;
402
  tooltipsToggleBtn.style.opacity = tooltipsVisible ? '1' : '0.5';
403
+
404
+ // Envoi global (compat actuel tooltips.js)
405
+ document.dispatchEvent(new CustomEvent('toggle-tooltips', {
406
+ detail: { visible: tooltipsVisible }
407
+ }));
408
+
409
+ // Envoi namespacé (si tu mets à jour tooltips.js pour l'écouter)
410
+ document.dispatchEvent(new CustomEvent(`toggle-tooltips-${instanceId}`, {
411
+ detail: { visible: tooltipsVisible, instanceId }
412
+ }));
413
  });
414
  }
415
 
416
+ // 12) Panneau tooltips : fermeture
417
  tooltipCloseBtn.addEventListener('click', hideTooltipPanel);
418
 
419
+ // 13) Gestion évènements "tooltip-selected"
420
+ // a) Évènement namespacé (préféré si tooltips.js est mis à jour)
421
+ const namespacedEvtName = `tooltip-selected-${instanceId}`;
422
+ document.addEventListener(namespacedEvtName, (evt) => {
423
+ const { title, description, imgUrl } = (evt.detail || {});
424
+ showTooltipPanel(title, description, imgUrl);
425
+ });
426
+
427
+ // b) Fallback évènement global (tooltips.js actuel)
428
+ // Pour éviter les collisions multi-instances, on ne réagit que si
429
+ // le pointeur survole VOTRE canvas au moment du clic.
430
+ let isPointerOver = false;
431
+ if (canvasEl) {
432
+ const enter = () => { isPointerOver = true; };
433
+ const leave = () => { isPointerOver = false; };
434
+ canvasEl.addEventListener('pointerenter', enter);
435
+ canvasEl.addEventListener('pointerleave', leave);
436
+ canvasEl.addEventListener('mouseenter', enter);
437
+ canvasEl.addEventListener('mouseleave', leave);
438
+ }
439
  document.addEventListener('tooltip-selected', (evt) => {
440
+ if (!isPointerOver) return; // ignorer les autres viewers
441
+ const { title, description, imgUrl } = (evt.detail || {});
442
+ showTooltipPanel(title, description, imgUrl);
443
+ });
444
+
445
+ function showTooltipPanel(title, description, imgUrl) {
446
+ // Annuler un éventuel handler différé
447
  if (dragHide) {
448
  viewerContainerElem.removeEventListener('pointermove', dragHide);
449
  dragHide = null;
450
  }
451
+ tooltipTextDiv.innerHTML = `<strong>${title || ''}</strong><br>${description || ''}`;
 
 
452
  tooltipImage.style.display = 'none';
453
  tooltipImage.src = '';
454
  if (imgUrl) {
455
+ tooltipImage.onload = () => { tooltipImage.style.display = 'block'; };
 
 
456
  tooltipImage.src = imgUrl;
 
 
457
  }
458
  tooltipPanel.style.display = 'flex';
459
+
460
+ // Cacher si on “traîne” (drag) ou touche
461
  setTimeout(() => {
462
  dragHide = (e) => {
463
  if ((e.pointerType === 'mouse' && e.buttons !== 0) || e.pointerType === 'touch') {
 
466
  };
467
  viewerContainerElem.addEventListener('pointermove', dragHide);
468
  }, 100);
469
+ }
470
 
471
+ // 14) Divers
472
  if (canvasEl) {
473
  canvasEl.addEventListener('wheel', hideTooltipPanel, { passive: true });
474
  }
 
489
  setMenuContentMaxSize();
490
  });
491
 
492
+ // 15) Init état par défaut
493
  setTimeout(() => {
494
  saveCurrentState();
495
+ // Toggler initial des tooltips
496
+ const initVisible = !!config.showTooltipsDefault;
497
+ document.dispatchEvent(new CustomEvent('toggle-tooltips', { detail: { visible: initVisible } }));
498
+ document.dispatchEvent(new CustomEvent(`toggle-tooltips-${instanceId}`, { detail: { visible: initVisible, instanceId } }));
499
  setMenuContentMaxSize();
500
  }, 200);
 
501
  })();