Spaces:
Running
Running
| // ============================== | |
| // interface.js | |
| // ============================== | |
| // Store a reference to the <script> tag that loaded this file | |
| const currentScriptTag = document.currentScript; | |
| (async function() { | |
| // βββ 1. Locate the <script> and read data-config βββββββββββββββββββββββββββββββ | |
| let scriptTag = currentScriptTag; | |
| if (!scriptTag) { | |
| const scripts = document.getElementsByTagName('script'); | |
| for (let i = 0; i < scripts.length; i++) { | |
| if (scripts[i].src.includes('interface.js') && scripts[i].hasAttribute('data-config')) { | |
| scriptTag = scripts[i]; | |
| break; | |
| } | |
| } | |
| if (!scriptTag && scripts.length > 0) { | |
| scriptTag = scripts[scripts.length - 1]; | |
| } | |
| } | |
| const configUrl = scriptTag.getAttribute('data-config'); | |
| let config = {}; | |
| if (configUrl) { | |
| try { | |
| const response = await fetch(configUrl); | |
| config = await response.json(); | |
| } catch (error) { | |
| console.error("Error loading config file:", error); | |
| return; | |
| } | |
| } else { | |
| console.error("No config file provided. Please set a data-config attribute on the <script> tag."); | |
| return; | |
| } | |
| // βββ 2. If config.css_url is provided, inject a <link> to that CSS βββββββββββββ | |
| if (config.css_url) { | |
| const linkEl = document.createElement('link'); | |
| linkEl.rel = "stylesheet"; | |
| linkEl.href = config.css_url; | |
| document.head.appendChild(linkEl); | |
| } | |
| // βββ 3. Generate a unique instanceId for this widget βββββββββββββββββββββββββββ | |
| const instanceId = Math.random().toString(36).substr(2, 8); | |
| // βββ 4. Compute the aspect ratio (padding-bottom %) ββββββββββββββββββββββββββββ | |
| let aspectPercent = "100%"; | |
| if (config.aspect) { | |
| if (config.aspect.includes(":")) { | |
| const parts = config.aspect.split(":"); | |
| const w = parseFloat(parts[0]); | |
| const h = parseFloat(parts[1]); | |
| if (!isNaN(w) && !isNaN(h) && w > 0) { | |
| aspectPercent = (h / w * 100) + "%"; | |
| } | |
| } else { | |
| const aspectValue = parseFloat(config.aspect); | |
| if (!isNaN(aspectValue) && aspectValue > 0) { | |
| aspectPercent = (100 / aspectValue) + "%"; | |
| } | |
| } | |
| } else { | |
| const parentContainer = scriptTag.parentNode; | |
| const containerWidth = parentContainer.offsetWidth; | |
| const containerHeight = parentContainer.offsetHeight; | |
| if (containerWidth > 0 && containerHeight > 0) { | |
| aspectPercent = (containerHeight / containerWidth * 100) + "%"; | |
| } | |
| } | |
| // βββ 5. Create the widget container ββββββββββββββββββββββββββββββββββββββββββββ | |
| const widgetContainer = document.createElement('div'); | |
| widgetContainer.id = 'ply-widget-container-' + instanceId; | |
| widgetContainer.classList.add('ply-widget-container'); | |
| widgetContainer.style.height = "0"; | |
| widgetContainer.style.paddingBottom = aspectPercent; | |
| widgetContainer.setAttribute('data-original-aspect', aspectPercent); | |
| const tooltipsButtonHTML = config.tooltips_url | |
| ? `<button id="tooltips-toggle-${instanceId}" class="widget-button tooltips-toggle">β¦Ώ</button>` | |
| : ''; | |
| // **Entire block below is now properly wrapped as a single template literal:** | |
| widgetContainer.innerHTML = ` | |
| <div id="viewer-container-${instanceId}" class="viewer-container"> | |
| <div id="progress-dialog-${instanceId}" class="progress-dialog"> | |
| <progress id="progress-indicator-${instanceId}" max="100" value="0"></progress> | |
| </div> | |
| <button id="fullscreen-toggle-${instanceId}" class="widget-button fullscreen-toggle">β±</button> | |
| <button id="help-toggle-${instanceId}" class="widget-button help-toggle">?</button> | |
| <button id="reset-camera-btn-${instanceId}" class="widget-button reset-camera-btn"> | |
| <span class="reset-icon">β²</span> | |
| </button> | |
| ${tooltipsButtonHTML} | |
| <div id="menu-content-${instanceId}" class="menu-content"> | |
| <span id="help-close-${instanceId}" class="help-close">Γ</span> | |
| <div class="help-text"></div> | |
| </div> | |
| </div> | |
| <div id="tooltip-panel" class="tooltip-panel" style="display: none;"> | |
| <div class="tooltip-content"> | |
| <span id="tooltip-close" class="tooltip-close">Γ</span> | |
| <div id="tooltip-text" class="tooltip-text"></div> | |
| <img id="tooltip-image" class="tooltip-image" src="" alt="" style="display: none;" /> | |
| </div> | |
| </div> | |
| `; // <-- closing backtick and semicolon here fixes the stray '<' | |
| // Append to DOM | |
| scriptTag.parentNode.appendChild(widgetContainer); | |
| // βββ 6. Grab refs & hook up listeners ββββββββββββββββββββββββββββββββββββββββ | |
| // (all your existing event-listener code remains unchanged hereβ¦) | |
| // βββ 7. Load viewer.js ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| try { | |
| const viewerModule = await import('./viewer.js'); | |
| await viewerModule.initializeViewer(config, instanceId); | |
| } catch (err) { | |
| console.error("Failed to load viewer.js or initialize the 3D viewer:", err); | |
| } | |
| // βββ 8. Rest of interface.jsβ¦ ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| })(); | |