MikaFil commited on
Commit
21ac916
·
verified ·
1 Parent(s): 554a3a2

Update interface.js

Browse files
Files changed (1) hide show
  1. interface.js +92 -97
interface.js CHANGED
@@ -1,9 +1,13 @@
1
  // interface.js
 
2
 
 
3
  const currentScriptTag = document.currentScript;
4
 
5
  (async function() {
6
- // 1. Locate script tag and read data-config
 
 
7
  let scriptTag = currentScriptTag;
8
  if (!scriptTag) {
9
  const scripts = document.getElementsByTagName('script');
@@ -24,31 +28,43 @@ const currentScriptTag = document.currentScript;
24
  try {
25
  const response = await fetch(configUrl);
26
  config = await response.json();
27
- } catch (error) { return; }
 
 
 
 
28
  } else {
 
29
  return;
30
  }
31
 
32
- // 2. CSS injection
33
  if (config.css_url) {
34
  const linkEl = document.createElement('link');
35
  linkEl.rel = "stylesheet";
36
  linkEl.href = config.css_url;
37
  document.head.appendChild(linkEl);
 
38
  }
39
 
40
- // 3. Unique instanceId
41
  const instanceId = Math.random().toString(36).substr(2, 8);
42
 
43
- // 4. Aspect ratio calc
44
  let aspectPercent = "100%";
45
  if (config.aspect) {
46
  if (config.aspect.includes(":")) {
47
- const [w, h] = config.aspect.split(":").map(Number);
48
- if (w > 0 && h > 0) aspectPercent = (h / w * 100) + "%";
 
 
 
 
49
  } else {
50
  const aspectValue = parseFloat(config.aspect);
51
- if (!isNaN(aspectValue) && aspectValue > 0) aspectPercent = (100 / aspectValue) + "%";
 
 
52
  }
53
  } else {
54
  const parentContainer = scriptTag.parentNode;
@@ -59,7 +75,7 @@ const currentScriptTag = document.currentScript;
59
  }
60
  }
61
 
62
- // 5. Widget container
63
  const widgetContainer = document.createElement('div');
64
  widgetContainer.id = 'ply-widget-container-' + instanceId;
65
  widgetContainer.classList.add('ply-widget-container');
@@ -67,51 +83,42 @@ const currentScriptTag = document.currentScript;
67
  widgetContainer.style.paddingBottom = aspectPercent;
68
  widgetContainer.setAttribute('data-original-aspect', aspectPercent);
69
 
70
- // 5a. Ensure touch-action disables iOS Safari pinch/zoom/scroll on viewer
71
- widgetContainer.style.touchAction = 'none';
72
-
73
- // 5b. Set iOS meta viewport to prevent zoom
74
- if (!document.querySelector('meta[name="viewport"]')) {
75
- const meta = document.createElement('meta');
76
- meta.name = "viewport";
77
- meta.content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0";
78
- document.head.appendChild(meta);
79
- }
80
-
81
- // Tooltips toggle button (if configured)
82
  const tooltipsButtonHTML = config.tooltips_url
83
- ? `<button id="tooltips-toggle-${instanceId}" class="widget-button tooltips-toggle" tabindex="0" aria-label="Afficher/masquer tooltips">⦿</button>`
84
  : '';
85
 
86
- // Viewer HTML
87
  widgetContainer.innerHTML = `
88
  <div id="viewer-container-${instanceId}" class="viewer-container">
89
  <div id="progress-dialog-${instanceId}" class="progress-dialog">
90
  <progress id="progress-indicator-${instanceId}" max="100" value="0"></progress>
91
  </div>
92
- <button id="fullscreen-toggle-${instanceId}" class="widget-button fullscreen-toggle" tabindex="0" aria-label="Plein écran">⇱</button>
93
- <button id="help-toggle-${instanceId}" class="widget-button help-toggle" tabindex="0" aria-label="Aide">?</button>
94
- <button id="reset-camera-btn-${instanceId}" class="widget-button reset-camera-btn" tabindex="0" aria-label="Réinitialiser caméra">
95
  <span class="reset-icon">⟲</span>
96
  </button>
97
  ${tooltipsButtonHTML}
98
  <div id="menu-content-${instanceId}" class="menu-content">
99
- <span id="help-close-${instanceId}" class="help-close" tabindex="0" aria-label="Fermer">×</span>
100
  <div class="help-text"></div>
101
  </div>
102
  </div>
103
  <div id="tooltip-panel" class="tooltip-panel" style="display: none;">
104
  <div class="tooltip-content">
105
- <span id="tooltip-close" class="tooltip-close" tabindex="0" aria-label="Fermer">×</span>
106
  <div id="tooltip-text" class="tooltip-text"></div>
107
  <img id="tooltip-image" class="tooltip-image" src="" alt="" style="display: none;" />
108
  </div>
109
  </div>
110
  `;
111
 
 
112
  scriptTag.parentNode.appendChild(widgetContainer);
 
113
 
114
- // 6. DOM references
115
  const viewerContainerElem = document.getElementById('viewer-container-' + instanceId);
116
  const fullscreenToggle = document.getElementById('fullscreen-toggle-' + instanceId);
117
  const helpToggle = document.getElementById('help-toggle-' + instanceId);
@@ -120,27 +127,49 @@ const currentScriptTag = document.currentScript;
120
  const tooltipsToggleBtn = document.getElementById('tooltips-toggle-' + instanceId);
121
  const menuContent = document.getElementById('menu-content-' + instanceId);
122
  const helpTextDiv = menuContent.querySelector('.help-text');
123
- const tooltipPanel = document.getElementById('tooltip-panel');
124
- const tooltipTextDiv = document.getElementById('tooltip-text');
125
- const tooltipImage = document.getElementById('tooltip-image');
126
- const tooltipCloseBtn = document.getElementById('tooltip-close');
127
 
128
- // Platform detection
 
 
 
 
 
 
129
  const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
130
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
131
 
132
- // Help text
133
  const tooltipInstruction = config.tooltips_url
134
  ? '- Cliquez sur ⦿ pour afficher/masquer les tooltips.<br>'
135
  : '';
136
- helpTextDiv.innerHTML = isMobile
137
- ? '- Pour vous déplacer, glissez deux doigts sur l\'écran.<br>- Pour orbiter, utilisez un doigt.<br>- Pour zoomer, pincez avec deux doigts.<br>' + tooltipInstruction + '- ⟲ Réinitialise la caméra.<br>- ⇱ Passe en plein écran.<br>'
138
- : '- orbitez avec le clic droit<br>- zoomez avec la molette<br>- déplacez vous avec le clic gauche<br>' + tooltipInstruction + '- ⟲ Réinitialise la caméra.<br>- ⇱ Passe en plein écran.<br>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  menuContent.style.display = 'block';
140
  viewerContainerElem.style.display = 'block';
141
 
 
142
  let dragHide = null;
143
 
 
144
  function hideTooltipPanel() {
145
  if (dragHide) {
146
  viewerContainerElem.removeEventListener('pointermove', dragHide);
@@ -148,29 +177,26 @@ const currentScriptTag = document.currentScript;
148
  }
149
  tooltipPanel.style.display = 'none';
150
  }
151
- function hideHelpPanel() { menuContent.style.display = 'none'; }
 
 
152
 
153
- // 7. Load viewer.js
154
  let viewerModule;
155
  try {
156
  viewerModule = await import('https://mikafil-viewer-gs.static.hf.space/viewer.js');
 
157
  await viewerModule.initializeViewer(config, instanceId);
158
- } catch (err) { return; }
 
 
 
 
159
 
160
  const canvasId = 'canvas-' + instanceId;
161
  const canvasEl = document.getElementById(canvasId);
162
 
163
- // 7b. Fix for iOS: always use correct canvas style and prevent double-scaling
164
- if (canvasEl) {
165
- canvasEl.style.touchAction = 'none';
166
- canvasEl.style.width = '100%';
167
- canvasEl.style.height = '100%';
168
- canvasEl.style.display = 'block';
169
- // Remove any tab focus from canvas to prevent scroll-zoom
170
- canvasEl.setAttribute('tabindex', '-1');
171
- }
172
-
173
- // 8. Tooltips button conditional display
174
  if (tooltipsToggleBtn) {
175
  if (!config.tooltips_url) {
176
  tooltipsToggleBtn.style.display = 'none';
@@ -181,9 +207,10 @@ const currentScriptTag = document.currentScript;
181
  }
182
  }
183
 
184
- // 9. Fullscreen/state logic
185
  let isFullscreen = false;
186
  let savedState = null;
 
187
  function saveCurrentState() {
188
  if (isFullscreen) return;
189
  const originalAspect = widgetContainer.getAttribute('data-original-aspect') || aspectPercent;
@@ -205,6 +232,7 @@ const currentScriptTag = document.currentScript;
205
  }
206
  };
207
  }
 
208
  function restoreOriginalStyles() {
209
  if (!savedState) return;
210
  const aspectToUse = savedState.widget.paddingBottom;
@@ -235,8 +263,10 @@ const currentScriptTag = document.currentScript;
235
  viewerContainerElem.clientHeight
236
  );
237
  }
 
238
  savedState = null;
239
  }
 
240
  function applyFullscreenStyles() {
241
  widgetContainer.style.position = 'fixed';
242
  widgetContainer.style.top = '0';
@@ -262,7 +292,9 @@ const currentScriptTag = document.currentScript;
262
  fullscreenToggle.textContent = '⇲';
263
  isFullscreen = true;
264
  }
 
265
  function enterFullscreen() {
 
266
  if (!savedState) saveCurrentState();
267
  if (isIOS) {
268
  applyFullscreenStyles();
@@ -279,7 +311,9 @@ const currentScriptTag = document.currentScript;
279
  widgetContainer.classList.add('fake-fullscreen');
280
  }
281
  }
 
282
  function exitFullscreen() {
 
283
  if (document.fullscreenElement === widgetContainer && document.exitFullscreen) {
284
  document.exitFullscreen().catch(() => {});
285
  }
@@ -288,7 +322,7 @@ const currentScriptTag = document.currentScript;
288
  isFullscreen = false;
289
  }
290
 
291
- // 10. Event listeners
292
  fullscreenToggle.addEventListener('click', () => {
293
  hideTooltipPanel();
294
  isFullscreen ? exitFullscreen() : enterFullscreen();
@@ -309,6 +343,7 @@ const currentScriptTag = document.currentScript;
309
 
310
  resetCameraBtn.addEventListener('click', () => {
311
  hideTooltipPanel();
 
312
  if (viewerModule.resetViewerCamera) {
313
  viewerModule.resetViewerCamera();
314
  }
@@ -321,9 +356,11 @@ const currentScriptTag = document.currentScript;
321
  hideTooltipPanel();
322
  tooltipsVisible = !tooltipsVisible;
323
  tooltipsToggleBtn.style.opacity = tooltipsVisible ? '1' : '0.5';
 
324
  document.dispatchEvent(new CustomEvent('toggle-tooltips', { detail: { visible: tooltipsVisible } }));
325
  });
326
  }
 
327
  tooltipCloseBtn.addEventListener('click', hideTooltipPanel);
328
 
329
  document.addEventListener('tooltip-selected', (evt) => {
@@ -346,13 +383,6 @@ const currentScriptTag = document.currentScript;
346
 
347
  if (canvasEl) {
348
  canvasEl.addEventListener('wheel', hideTooltipPanel, { passive: true });
349
-
350
- // iOS pinch zoom prevention
351
- canvasEl.addEventListener('touchmove', function(e) {
352
- if (e.touches.length > 1) {
353
- e.preventDefault();
354
- }
355
- }, { passive: false });
356
  }
357
  document.addEventListener('keydown', (e) => {
358
  if ((e.key === 'Escape' || e.key === 'Esc') && isFullscreen) exitFullscreen();
@@ -370,45 +400,10 @@ const currentScriptTag = document.currentScript;
370
  }
371
  });
372
 
373
- // iOS: unlock WebGL/audio on first user gesture (if needed)
374
- if (isIOS && canvasEl) {
375
- let firstUserAction = false;
376
- function unlockWebGLAndAudio() {
377
- if (!firstUserAction) {
378
- if (viewerModule.app && viewerModule.app.graphicsDevice && viewerModule.app.graphicsDevice.canvas) {
379
- // iOS hack: force focus and dummy audio play
380
- viewerModule.app.graphicsDevice.canvas.focus && viewerModule.app.graphicsDevice.canvas.focus();
381
- try {
382
- const ctx = new AudioContext();
383
- const buffer = ctx.createBuffer(1, 1, 22050);
384
- const src = ctx.createBufferSource();
385
- src.buffer = buffer;
386
- src.connect(ctx.destination);
387
- src.start(0);
388
- } catch {}
389
- }
390
- firstUserAction = true;
391
- }
392
- }
393
- canvasEl.addEventListener('touchstart', unlockWebGLAndAudio, { once: true });
394
- canvasEl.addEventListener('mousedown', unlockWebGLAndAudio, { once: true });
395
- }
396
-
397
  setTimeout(() => {
398
  saveCurrentState();
399
  document.dispatchEvent(new CustomEvent('toggle-tooltips', { detail: { visible: !!config.showTooltipsDefault } }));
 
400
  }, 200);
401
 
402
- // Ensure ResizeObserver always triggers a correct canvas resize (iOS)
403
- if (canvasEl && window.ResizeObserver) {
404
- const resizeObs = new ResizeObserver(() => {
405
- if (viewerModule.app) {
406
- viewerModule.app.resizeCanvas(
407
- viewerContainerElem.clientWidth,
408
- viewerContainerElem.clientHeight
409
- );
410
- }
411
- });
412
- resizeObs.observe(viewerContainerElem);
413
- }
414
  })();
 
1
  // interface.js
2
+ // ==============================
3
 
4
+ // Store a reference to the <script> tag that loaded this file
5
  const currentScriptTag = document.currentScript;
6
 
7
  (async function() {
8
+ alert("[interface.js] SCRIPT BEGIN");
9
+
10
+ // 1. Locate the <script> and read data-config
11
  let scriptTag = currentScriptTag;
12
  if (!scriptTag) {
13
  const scripts = document.getElementsByTagName('script');
 
28
  try {
29
  const response = await fetch(configUrl);
30
  config = await response.json();
31
+ alert("[interface.js] Config loaded successfully");
32
+ } catch (error) {
33
+ alert("[interface.js] ERROR: Config failed to load: " + error);
34
+ return;
35
+ }
36
  } else {
37
+ alert("[interface.js] ERROR: No config file provided.");
38
  return;
39
  }
40
 
41
+ // 2. If config.css_url is provided, inject a <link> to that CSS
42
  if (config.css_url) {
43
  const linkEl = document.createElement('link');
44
  linkEl.rel = "stylesheet";
45
  linkEl.href = config.css_url;
46
  document.head.appendChild(linkEl);
47
+ alert("[interface.js] CSS injected");
48
  }
49
 
50
+ // 3. Generate a unique instanceId for this widget
51
  const instanceId = Math.random().toString(36).substr(2, 8);
52
 
53
+ // 4. Compute the aspect ratio (padding-bottom %)
54
  let aspectPercent = "100%";
55
  if (config.aspect) {
56
  if (config.aspect.includes(":")) {
57
+ const parts = config.aspect.split(":");
58
+ const w = parseFloat(parts[0]);
59
+ const h = parseFloat(parts[1]);
60
+ if (!isNaN(w) && !isNaN(h) && w > 0) {
61
+ aspectPercent = (h / w * 100) + "%";
62
+ }
63
  } else {
64
  const aspectValue = parseFloat(config.aspect);
65
+ if (!isNaN(aspectValue) && aspectValue > 0) {
66
+ aspectPercent = (100 / aspectValue) + "%";
67
+ }
68
  }
69
  } else {
70
  const parentContainer = scriptTag.parentNode;
 
75
  }
76
  }
77
 
78
+ // 5. Create the widget container (no GIF preview, no close button)
79
  const widgetContainer = document.createElement('div');
80
  widgetContainer.id = 'ply-widget-container-' + instanceId;
81
  widgetContainer.classList.add('ply-widget-container');
 
83
  widgetContainer.style.paddingBottom = aspectPercent;
84
  widgetContainer.setAttribute('data-original-aspect', aspectPercent);
85
 
86
+ // Conditionally include the “tooltips-toggle” button only if config.tooltips_url is defined
 
 
 
 
 
 
 
 
 
 
 
87
  const tooltipsButtonHTML = config.tooltips_url
88
+ ? `<button id="tooltips-toggle-${instanceId}" class="widget-button tooltips-toggle">⦿</button>`
89
  : '';
90
 
91
+ // Add the 3D-viewer HTML + tooltip + help HTML (all HTML in a template literal!)
92
  widgetContainer.innerHTML = `
93
  <div id="viewer-container-${instanceId}" class="viewer-container">
94
  <div id="progress-dialog-${instanceId}" class="progress-dialog">
95
  <progress id="progress-indicator-${instanceId}" max="100" value="0"></progress>
96
  </div>
97
+ <button id="fullscreen-toggle-${instanceId}" class="widget-button fullscreen-toggle">⇱</button>
98
+ <button id="help-toggle-${instanceId}" class="widget-button help-toggle">?</button>
99
+ <button id="reset-camera-btn-${instanceId}" class="widget-button reset-camera-btn">
100
  <span class="reset-icon">⟲</span>
101
  </button>
102
  ${tooltipsButtonHTML}
103
  <div id="menu-content-${instanceId}" class="menu-content">
104
+ <span id="help-close-${instanceId}" class="help-close">×</span>
105
  <div class="help-text"></div>
106
  </div>
107
  </div>
108
  <div id="tooltip-panel" class="tooltip-panel" style="display: none;">
109
  <div class="tooltip-content">
110
+ <span id="tooltip-close" class="tooltip-close">×</span>
111
  <div id="tooltip-text" class="tooltip-text"></div>
112
  <img id="tooltip-image" class="tooltip-image" src="" alt="" style="display: none;" />
113
  </div>
114
  </div>
115
  `;
116
 
117
+ // Append the widget container immediately after the <script> tag
118
  scriptTag.parentNode.appendChild(widgetContainer);
119
+ alert("[interface.js] Widget HTML injected");
120
 
121
+ // 6. Grab references to new DOM elements
122
  const viewerContainerElem = document.getElementById('viewer-container-' + instanceId);
123
  const fullscreenToggle = document.getElementById('fullscreen-toggle-' + instanceId);
124
  const helpToggle = document.getElementById('help-toggle-' + instanceId);
 
127
  const tooltipsToggleBtn = document.getElementById('tooltips-toggle-' + instanceId);
128
  const menuContent = document.getElementById('menu-content-' + instanceId);
129
  const helpTextDiv = menuContent.querySelector('.help-text');
 
 
 
 
130
 
131
+ // Tooltip panel elements
132
+ const tooltipPanel = document.getElementById('tooltip-panel');
133
+ const tooltipTextDiv = document.getElementById('tooltip-text');
134
+ const tooltipImage = document.getElementById('tooltip-image');
135
+ const tooltipCloseBtn = document.getElementById('tooltip-close');
136
+
137
+ // 6a. Detect mobile vs. desktop
138
  const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
139
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
140
 
141
+ // Conditionally include the French tooltip instruction line if tooltips_url exists
142
  const tooltipInstruction = config.tooltips_url
143
  ? '- Cliquez sur ⦿ pour afficher/masquer les tooltips.<br>'
144
  : '';
145
+
146
+ // Fill help text with instructions plus the two new French lines
147
+ if (isMobile) {
148
+ helpTextDiv.innerHTML =
149
+ '- Pour vous déplacer, glissez deux doigts sur l\'écran.<br>' +
150
+ '- Pour orbiter, utilisez un doigt.<br>' +
151
+ '- Pour zoomer, pincez avec deux doigts.<br>' +
152
+ tooltipInstruction +
153
+ '- ⟲ Réinitialise la caméra.<br>' +
154
+ '- ⇱ Passe en plein écran.<br>';
155
+ } else {
156
+ helpTextDiv.innerHTML =
157
+ '- orbitez avec le clic droit<br>' +
158
+ '- zoomez avec la molette<br>' +
159
+ '- déplacez vous avec le clic gauche<br>' +
160
+ tooltipInstruction +
161
+ '- ⟲ Réinitialise la caméra.<br>' +
162
+ '- ⇱ Passe en plein écran.<br>';
163
+ }
164
+
165
+ // Ensure instructions panel is visible by default
166
  menuContent.style.display = 'block';
167
  viewerContainerElem.style.display = 'block';
168
 
169
+ // Variable to hold the drag-hide listener reference
170
  let dragHide = null;
171
 
172
+ // Utilities to hide panels
173
  function hideTooltipPanel() {
174
  if (dragHide) {
175
  viewerContainerElem.removeEventListener('pointermove', dragHide);
 
177
  }
178
  tooltipPanel.style.display = 'none';
179
  }
180
+ function hideHelpPanel() {
181
+ menuContent.style.display = 'none';
182
+ }
183
 
184
+ // 7. Dynamically load viewer.js
185
  let viewerModule;
186
  try {
187
  viewerModule = await import('https://mikafil-viewer-gs.static.hf.space/viewer.js');
188
+ alert("[interface.js] viewer.js module loaded");
189
  await viewerModule.initializeViewer(config, instanceId);
190
+ alert("[interface.js] viewer.js initializeViewer() returned");
191
+ } catch (err) {
192
+ alert("[interface.js] ERROR: Failed to load or init viewer.js: " + err);
193
+ return;
194
+ }
195
 
196
  const canvasId = 'canvas-' + instanceId;
197
  const canvasEl = document.getElementById(canvasId);
198
 
199
+ // 8. Conditional display of tooltips-toggle button
 
 
 
 
 
 
 
 
 
 
200
  if (tooltipsToggleBtn) {
201
  if (!config.tooltips_url) {
202
  tooltipsToggleBtn.style.display = 'none';
 
207
  }
208
  }
209
 
210
+ // 9. Fullscreen / state-preservation logic
211
  let isFullscreen = false;
212
  let savedState = null;
213
+
214
  function saveCurrentState() {
215
  if (isFullscreen) return;
216
  const originalAspect = widgetContainer.getAttribute('data-original-aspect') || aspectPercent;
 
232
  }
233
  };
234
  }
235
+
236
  function restoreOriginalStyles() {
237
  if (!savedState) return;
238
  const aspectToUse = savedState.widget.paddingBottom;
 
263
  viewerContainerElem.clientHeight
264
  );
265
  }
266
+
267
  savedState = null;
268
  }
269
+
270
  function applyFullscreenStyles() {
271
  widgetContainer.style.position = 'fixed';
272
  widgetContainer.style.top = '0';
 
292
  fullscreenToggle.textContent = '⇲';
293
  isFullscreen = true;
294
  }
295
+
296
  function enterFullscreen() {
297
+ alert("[interface.js] Entering fullscreen");
298
  if (!savedState) saveCurrentState();
299
  if (isIOS) {
300
  applyFullscreenStyles();
 
311
  widgetContainer.classList.add('fake-fullscreen');
312
  }
313
  }
314
+
315
  function exitFullscreen() {
316
+ alert("[interface.js] Exiting fullscreen");
317
  if (document.fullscreenElement === widgetContainer && document.exitFullscreen) {
318
  document.exitFullscreen().catch(() => {});
319
  }
 
322
  isFullscreen = false;
323
  }
324
 
325
+ // 10. Hook up event listeners
326
  fullscreenToggle.addEventListener('click', () => {
327
  hideTooltipPanel();
328
  isFullscreen ? exitFullscreen() : enterFullscreen();
 
343
 
344
  resetCameraBtn.addEventListener('click', () => {
345
  hideTooltipPanel();
346
+ alert("[interface.js] Reset camera button clicked");
347
  if (viewerModule.resetViewerCamera) {
348
  viewerModule.resetViewerCamera();
349
  }
 
356
  hideTooltipPanel();
357
  tooltipsVisible = !tooltipsVisible;
358
  tooltipsToggleBtn.style.opacity = tooltipsVisible ? '1' : '0.5';
359
+ alert("[interface.js] Tooltips toggle clicked. Now: " + (tooltipsVisible ? "ON" : "OFF"));
360
  document.dispatchEvent(new CustomEvent('toggle-tooltips', { detail: { visible: tooltipsVisible } }));
361
  });
362
  }
363
+
364
  tooltipCloseBtn.addEventListener('click', hideTooltipPanel);
365
 
366
  document.addEventListener('tooltip-selected', (evt) => {
 
383
 
384
  if (canvasEl) {
385
  canvasEl.addEventListener('wheel', hideTooltipPanel, { passive: true });
 
 
 
 
 
 
 
386
  }
387
  document.addEventListener('keydown', (e) => {
388
  if ((e.key === 'Escape' || e.key === 'Esc') && isFullscreen) exitFullscreen();
 
400
  }
401
  });
402
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
403
  setTimeout(() => {
404
  saveCurrentState();
405
  document.dispatchEvent(new CustomEvent('toggle-tooltips', { detail: { visible: !!config.showTooltipsDefault } }));
406
+ alert("[interface.js] Widget setup complete!");
407
  }, 200);
408
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  })();