Review and improve error handling and error messages

This commit is contained in:
Mathias Malmqvist
2025-09-11 19:11:47 +02:00
committed by dualshock-tools
parent 48fc4b5dce
commit c295cfa508
34 changed files with 463 additions and 338 deletions

View File

@@ -184,7 +184,7 @@ class ControllerManager {
async nvsLock() {
const res = await this.currentController.nvsLock();
if (!res.ok) {
throw new Error(this.l("NVS Lock failed: ") + String(res.error));
throw new Error(this.l("NVS Lock failed"), { cause: res.error });
}
await this.queryNvStatus(); // Refresh NVS status
@@ -197,8 +197,7 @@ class ControllerManager {
async calibrateSticksBegin() {
const res = await this.currentController.calibrateSticksBegin();
if (!res.ok) {
const detail = res.code ? (this.l("Error ") + String(res.code)) : String(res.error || "");
throw new Error(this.l("Stick calibration failed: ") + detail);
throw new Error(this.l("Stick calibration failed"), { cause: res.error });
}
}
@@ -209,8 +208,7 @@ class ControllerManager {
const res = await this.currentController.calibrateSticksSample();
if (!res.ok) {
await sleep(500);
const detail = res.code ? (this.l("Error ") + String(res.code)) : String(res.error || "");
throw new Error(this.l("Stick calibration failed: ") + detail);
throw new Error(this.l("Stick calibration failed"), { cause: res.error });
}
}
@@ -221,8 +219,7 @@ class ControllerManager {
const res = await this.currentController.calibrateSticksEnd();
if (!res.ok) {
await sleep(500);
const detail = res.code ? (this.l("Error ") + String(res.code)) : String(res.error || "");
throw new Error(this.l("Stick calibration failed: ") + detail);
throw new Error(this.l("Stick calibration failed"), { cause: res.error });
}
this.setHasChangesToWrite(true);
@@ -234,8 +231,7 @@ class ControllerManager {
async calibrateRangeBegin() {
const ret = await this.currentController.calibrateRangeBegin();
if (!ret.ok) {
const detail = ret.code ? (this.l("Error ") + String(ret.code)) : String(ret.error || "");
throw new Error(this.l("Range calibration failed: ") + detail);
throw new Error(this.l("Range calibration failed"), { cause: ret.error } );
}
}
@@ -259,8 +255,8 @@ class ControllerManager {
console.log("Range calibration end failed with unexpected error:", res);
await sleep(500);
const msg = res?.code ? (this.l("Range calibration failed: ") + this.l("Error ") + String(res.code)) : (this.l("Range calibration failed: ") + String(res?.error || ""));
return { success: false, message: msg };
const msg = res?.code ? (this.l("Range calibration failed") + this.l("Error ") + String(res.code)) : (this.l("Range calibration failed") + String(res?.error || ""));
return { success: false, message: msg, error: res?.error };
}
}

View File

@@ -94,7 +94,7 @@ class BaseController {
* Close the HID device connection
*/
async close() {
if (this.device && this.device.opened) {
if (this.device?.opened) {
await this.device.close();
}
}

View File

@@ -113,9 +113,9 @@ class DS4Controller extends BaseController {
const disable_bits = is_clone ? 1 : 0; // 1: clone
return { ok: true, infoItems, nv, disable_bits, rare };
} catch(e) {
} catch(error) {
// Return error but do not touch DOM
return { ok: false, error: e, disable_bits: 1 };
return { ok: false, error, disable_bits: 1 };
}
}
@@ -128,7 +128,7 @@ class DS4Controller extends BaseController {
return { success: true, message: this.l("Changes saved successfully") };
} catch(error) {
throw new Error(this.l("Error while saving changes: ") + String(error));
throw new Error(this.l("Error while saving changes"), { cause: error });
}
}
@@ -145,8 +145,8 @@ class DS4Controller extends BaseController {
try {
await this.sendFeatureReport(0xa0, [10,1,0]);
return { ok: true };
} catch(e) {
return { ok: false, error: e };
} catch(error) {
return { ok: false, error };
}
}
@@ -155,8 +155,8 @@ class DS4Controller extends BaseController {
try {
await this.sendFeatureReport(0xa0, [10,2,0x3e,0x71,0x7f,0x89]);
return { ok: true };
} catch(e) {
return { ok: false, error: e };
} catch(error) {
return { ok: false, error };
}
}
@@ -181,9 +181,9 @@ class DS4Controller extends BaseController {
return { ok: false, code: 1, d1, d2 };
}
return { ok: true };
} catch(e) {
la("ds4_calibrate_range_begin_failed", {"r": e});
return { ok: false, error: String(e) };
} catch(error) {
la("ds4_calibrate_range_begin_failed", {"r": error});
return { ok: false, error };
}
}
@@ -203,9 +203,9 @@ class DS4Controller extends BaseController {
}
return { ok: true };
} catch(e) {
la("ds4_calibrate_range_end_failed", {"r": e});
return { ok: false, error: String(e) };
} catch(error) {
la("ds4_calibrate_range_end_failed", {"r": error});
return { ok: false, error };
}
}
@@ -226,9 +226,9 @@ class DS4Controller extends BaseController {
}
return { ok: true };
} catch(e) {
la("ds4_calibrate_sticks_begin_failed", {"r": e});
return { ok: false, error: String(e) };
} catch(error) {
la("ds4_calibrate_sticks_begin_failed", {"r": error});
return { ok: false, error };
}
}
@@ -248,8 +248,8 @@ class DS4Controller extends BaseController {
return { ok: false, code: 2, d1, d2 };
}
return { ok: true };
} catch(e) {
return { ok: false, error: String(e) };
} catch(error) {
return { ok: false, error };
}
}
@@ -269,9 +269,9 @@ class DS4Controller extends BaseController {
}
return { ok: true };
} catch(e) {
la("ds4_calibrate_sticks_end_failed", {"r": e});
return { ok: false, error: String(e) };
} catch(error) {
la("ds4_calibrate_sticks_end_failed", {"r": error});
return { ok: false, error };
}
}
@@ -289,8 +289,8 @@ class DS4Controller extends BaseController {
default:
return { ...res, status: 'unknown', locked: null };
}
} catch (e) {
return { device: 'ds4', status: 'error', locked: null, code: 2, error: e };
} catch (error) {
return { device: 'ds4', status: 'error', locked: null, code: 2, error };
}
}

View File

@@ -160,10 +160,9 @@ class DS5Controller extends BaseController {
const pending_reboot = (nv?.status === 'pending_reboot');
return { ok: true, infoItems, nv, disable_bits, pending_reboot };
} catch(e) {
la("ds5_info_error", {"r": e})
console.error(e.stack);
return { ok: false, error: e, disable_bits: 1 };
} catch(error) {
la("ds5_info_error", {"r": error})
return { ok: false, error, disable_bits: 1 };
}
}
@@ -176,7 +175,7 @@ class DS5Controller extends BaseController {
return { success: true, message: this.l("Changes saved successfully") };
} catch(error) {
throw new Error(this.l("Error while saving changes: ") + String(error));
throw new Error(this.l("Error while saving changes"), { cause: error });
}
}
@@ -194,8 +193,8 @@ class DS5Controller extends BaseController {
await this.sendFeatureReport(0x80, [3,1]);
await this.receiveFeatureReport(0x81);
return { ok: true };
} catch(e) {
return { ok: false, error: e };
} catch(error) {
return { ok: false, error };
}
}
@@ -204,9 +203,9 @@ class DS5Controller extends BaseController {
try {
await this.sendFeatureReport(0x80, [3,2, 101, 50, 64, 12]);
const data = await this.receiveFeatureReport(0x81);
} catch(e) {
} catch(error) {
await sleep(500);
throw new Error(this.l("NVS Unlock failed: ") + e);
throw new Error(this.l("NVS Unlock failed"), { cause: error });
}
}
@@ -239,12 +238,12 @@ class DS5Controller extends BaseController {
if(data.getUint32(0, false) != 0x83010101) {
const d1 = dec2hex32(data.getUint32(0, false));
la("ds5_calibrate_sticks_begin_failed", {"d1": d1});
return { ok: false, code: 1, d1 };
throw new Error(`Stick center calibration begin failed: ${d1}`);
}
return { ok: true };
} catch(e) {
} catch(error) {
la("ds5_calibrate_sticks_begin_failed", {"r": e});
return { ok: false, error: String(e) };
return { ok: false, error };
}
}
@@ -259,12 +258,12 @@ class DS5Controller extends BaseController {
if(data.getUint32(0, false) != 0x83010101) {
const d1 = dec2hex32(data.getUint32(0, false));
la("ds5_calibrate_sticks_sample_failed", {"d1": d1});
return { ok: false, code: 2, d1 };
throw new Error(`Stick center calibration sample failed: ${d1}`);
}
return { ok: true };
} catch(e) {
} catch(error) {
la("ds5_calibrate_sticks_sample_failed", {"r": e});
return { ok: false, error: String(e) };
return { ok: false, error };
}
}
@@ -279,13 +278,13 @@ class DS5Controller extends BaseController {
if(data.getUint32(0, false) != 0x83010102) {
const d1 = dec2hex32(data.getUint32(0, false));
la("ds5_calibrate_sticks_failed", {"s": 3, "d1": d1});
return { ok: false, code: 3, d1 };
throw new Error(`Stick center calibration end failed: ${d1}`);
}
return { ok: true };
} catch(e) {
} catch(error) {
la("ds5_calibrate_sticks_end_failed", {"r": e});
return { ok: false, error: String(e) };
return { ok: false, error };
}
}
@@ -300,12 +299,12 @@ class DS5Controller extends BaseController {
if(data.getUint32(0, false) != 0x83010201) {
const d1 = dec2hex32(data.getUint32(0, false));
la("ds5_calibrate_range_begin_failed", {"d1": d1});
return { ok: false, code: 1, d1 };
throw new Error(`Stick range calibration begin failed: ${d1}`);
}
return { ok: true };
} catch(e) {
} catch(error) {
la("ds5_calibrate_range_begin_failed", {"r": e});
return { ok: false, error: String(e) };
return { ok: false, error };
}
}
@@ -321,13 +320,13 @@ class DS5Controller extends BaseController {
if(data.getUint32(0, false) != 0x83010202) {
const d1 = dec2hex32(data.getUint32(0, false));
la("ds5_calibrate_range_end_failed", {"d1": d1});
return { ok: false, code: 3, d1 };
throw new Error(`Stick range calibration end failed: ${d1}`);
}
return { ok: true };
} catch(e) {
} catch(error) {
la("ds5_calibrate_range_end_failed", {"r": e});
return { ok: false, error: String(e) };
return { ok: false, error };
}
}

View File

@@ -46,7 +46,7 @@ class DS5EdgeController extends DS5Controller {
};
}
} catch(error) {
throw new Error(this.l("Error while saving changes: ") + String(error));
throw new Error(this.l("Error while saving changes"), { cause: error });
}
}

View File

@@ -35,9 +35,66 @@ let controller = null;
function gboot() {
app.gu = crypto.randomUUID();
$("#infoshowall").hide();
async function initializeApp() {
window.addEventListener("error", (event) => {
console.error(event.error?.stack || event.message);
show_popup(event.error?.message || event.message);
});
window.addEventListener("unhandledrejection", async (event) => {
console.error("Unhandled rejection:", event.reason?.stack || event.reason);
close_all_modals();
// show_popup(event.reason?.message || event.reason);
// Format the error message for better readability
let errorMessage = "An unexpected error occurred";
if (event.reason) {
if (event.reason.message) {
errorMessage = `<strong>Error:</strong> ${event.reason.message}`;
} else if (typeof event.reason === 'string') {
errorMessage = `<strong>Error:</strong> ${event.reason}`;
}
// Collect all stack traces (main error and causes) for a single expandable section
let allStackTraces = '';
if (event.reason.stack) {
const stackTrace = event.reason.stack.replace(/\n/g, '<br>').replace(/ /g, '&nbsp;');
allStackTraces += `<strong>Main Error Stack:</strong><br>${stackTrace}`;
}
// Add error chain information if available (ES2022 error chaining)
let currentError = event.reason;
let chainLevel = 0;
while (currentError?.cause && chainLevel < 5) {
chainLevel++;
currentError = currentError.cause;
if (currentError.stack) {
const causeStackTrace = currentError.stack.replace(/\n/g, '<br>').replace(/ /g, '&nbsp;');
if (allStackTraces) allStackTraces += '<br><br>';
allStackTraces += `<strong>Cause ${chainLevel} Stack:</strong><br>${causeStackTrace}`;
}
}
// Add single expandable section if we have any stack traces
if (allStackTraces) {
errorMessage += `
<br>
<details style="margin-top: 0px;">
<summary style="cursor: pointer; color: #666;">Details</summary>
<div style="font-family: monospace; font-size: 0.85em; margin-top: 8px; padding: 8px; background-color: #f8f9fa; border-radius: 4px; overflow-x: auto;">
${allStackTraces}
</div>
</details>
`;
}
}
errorAlert(errorMessage);
// Prevent the default browser behavior (logging to console, again)
event.preventDefault();
});
await loadAllTemplates();
await init_svg_controller();
@@ -45,19 +102,6 @@ function gboot() {
show_welcome_modal();
$("input[name='displayMode']").on('change', on_stick_mode_change);
window.addEventListener("error", (event) => {
console.error(event.error?.stack || event.message);
show_popup(event.error?.message || event.message);
});
window.addEventListener("unhandledrejection", (event) => {
console.error("Unhandled rejection:", event.reason?.stack || event.reason);
close_all_modals();
show_popup(event.reason?.message || event.reason);
// Prevent the default browser behavior (logging to console, again)
event.preventDefault();
});
}
// Since modules are deferred, DOM might already be loaded
@@ -87,6 +131,9 @@ async function connect() {
la("begin");
reset_circularity_mode();
clearAllAlerts();
await sleep(200);
try {
$("#btnconnect").prop("disabled", true);
$("#connectspinner").show();
@@ -101,11 +148,16 @@ async function connect() {
if (devices.length == 0) {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
await disconnect();
return;
}
if (devices.length > 1) {
throw new Error(l("Please connect only one controller at time."));
if (devices.length > 1) { //mm: this should never happen
infoAlert(l("Please connect only one controller at time."));
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
await disconnect();
return;
}
const [device] = devices;
@@ -117,28 +169,29 @@ async function connect() {
await device.open();
la("connect", {"p": device.productId, "v": device.vendorId});
device.oninputreport = continue_connection
device.oninputreport = continue_connection; // continue below
} catch(error) {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
throw new Error(l("Error: ") + error);
await disconnect();
throw error;
}
}
async function continue_connection({data, device}) {
try {
if (!controller || controller.isConnected()) {
console.log("Already connected. Reset input report handler.");
controller?.setInputReportHandler(null);
device.oninputreport = null; // this function is called repeatedly if not cleared
return;
}
let connected = false;
// Detect if the controller is connected via USB
const reportLen = data.byteLength;
if(reportLen != 63) {
throw new Error(l("Please connect the device using a USB cable."));
// throw new Error(l("Please connect the device using a USB cable."));
infoAlert(l("The device is connected via Bluetooth. Disconnect and reconnect using a USB cable instead."));
await disconnect();
return;
}
// Helper to apply basic UI visibility based on device type
@@ -159,20 +212,18 @@ async function continue_connection({data, device}) {
info = await controllerInstance.getInfo();
} catch (error) {
if (device) {
throw new Error(l("Connected invalid device: ") + dec2hex(device.vendorId) + ":" + dec2hex(device.productId));
} else {
throw new Error(l("Failed to connect to device"));
}
const contextMessage = device
? l("Connected invalid device: ") + dec2hex(device.vendorId) + ":" + dec2hex(device.productId)
: l("Failed to connect to device");
throw new Error(contextMessage, { cause: error });
}
if(!info?.ok) {
// Not connected/failed to fetch info
if(info) console.error(JSON.stringify(info, null, 2));
throw new Error(l("Connected invalid device: ") + l("Error 1") + (info?.error ? ` (${info.error}).` : '. '));
throw new Error(l("Connected invalid device: ") + l("Error 1"), { cause: info?.error });
}
connected = true;
// Get UI configuration and device name
const ui = ControllerFactory.getUIConfig(device.productId);
applyDeviceUI(ui);
@@ -198,7 +249,9 @@ async function continue_connection({data, device}) {
// Edge-specific: pending reboot check (from nv)
if (model == "DS5_Edge" && info?.pending_reboot) {
throw new Error(l("A reboot is needed to continue using this DualSense Edge. Please disconnect and reconnect your controller."));
infoAlert(l("A reboot is needed to continue using this DualSense Edge. Please disconnect and reconnect your controller."));
await disconnect();
return;
}
// Render info collected from device
@@ -256,8 +309,7 @@ async function disconnect() {
// Wrapper function for HTML onclick handlers
function disconnectSync() {
disconnect().catch(error => {
console.error("Error during disconnect:", error);
show_popup("Error during disconnect: " + error.message);
throw new Error("Failed to disconnect", { cause: error });
});
}
@@ -269,7 +321,7 @@ async function handleDisconnectedDevice(e) {
function render_nvstatus_to_dom(nv) {
if(!nv?.status) {
throw new Error("Invalid NVS status data");
throw new Error("Invalid NVS status data", { cause: nv?.error });
}
switch (nv.status) {
@@ -676,7 +728,11 @@ async function flash_all_changes() {
const progressCallback = controller.getModel() == "DS5_Edge" ? set_edge_progress : null;
const result = await controller.flash(progressCallback);
if (result?.success) {
show_popup(result.message, result.isHtml);
if(result.isHtml) {
show_popup(result.message, result.isHtml);
} else {
successAlert(result.message);
}
}
}
@@ -833,8 +889,8 @@ const trigger_haptic_motors = (() => {
// Stop rumble after duration
clearTimeout(haptic_timeout);
haptic_timeout = setTimeout(stop_haptic_motors, 250);
} catch(e) {
throw new Error(l("Error triggering rumble: ") + e);
} catch(error) {
throw new Error(l("Error triggering rumble"), { cause: error });
}
};
})();
@@ -854,15 +910,90 @@ async function stop_haptic_motors() {
}
// Alert Management Functions
let alertCounter = 0;
/**
* Push a new alert message to the bottom of the screen
* @param {string} message - The message to display
* @param {string} type - Bootstrap alert type: 'primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark'
* @param {number} duration - Auto-dismiss duration in milliseconds (0 = no auto-dismiss)
* @param {boolean} dismissible - Whether the alert can be manually dismissed
* @returns {string} - The ID of the created alert element
*/
function pushAlert(message, type = 'info', duration = 0, dismissible = true) {
const alertContainer = document.getElementById('alert-container');
if (!alertContainer) {
console.error('Alert container not found');
return null;
}
const alertId = `alert-${++alertCounter}`;
const alertDiv = document.createElement('div');
alertDiv.id = alertId;
alertDiv.className = `alert alert-${type} alert-dismissible fade show`;
alertDiv.setAttribute('role', 'alert');
alertDiv.innerHTML = `
${message}
${dismissible ? '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' : ''}
`;
alertContainer.appendChild(alertDiv);
if (duration > 0) {
setTimeout(() => {
dismissAlert(alertId);
}, duration);
}
return alertId;
}
function dismissAlert(alertId) {
const alertElement = document.getElementById(alertId);
if (alertElement) {
const bsAlert = new bootstrap.Alert(alertElement);
bsAlert.close();
}
}
function clearAllAlerts() {
const alertContainer = document.getElementById('alert-container');
if (alertContainer) {
const alerts = alertContainer.querySelectorAll('.alert');
alerts.forEach(alert => {
const bsAlert = new bootstrap.Alert(alert);
bsAlert.close();
});
}
}
function successAlert(message, duration = 1_500) {
return pushAlert(message, 'success', duration, false);
}
function errorAlert(message, duration = 15_000) {
return pushAlert(message, 'danger', /* duration */);
}
function warningAlert(message, duration = 8_000) {
return pushAlert(message, 'warning', duration);
}
function infoAlert(message, duration = 5_000) {
return pushAlert(message, 'info', duration, false);
}
// Export functions to global scope for HTML onclick handlers
window.gboot = gboot;
window.connect = connect;
window.disconnect = disconnectSync;
window.show_faq_modal = show_faq_modal;
window.show_info_tab = show_info_tab;
window.calibrate_range = () => calibrate_range(controller, { resetStickDiagrams, show_popup });
window.calibrate_range = () => calibrate_range(controller, { resetStickDiagrams, successAlert });
window.calibrate_stick_centers = () => calibrate_stick_centers(controller, { resetStickDiagrams, show_popup, set_progress });
window.auto_calibrate_stick_centers = () => auto_calibrate_stick_centers(controller, { resetStickDiagrams, show_popup, set_progress });
window.auto_calibrate_stick_centers = () => auto_calibrate_stick_centers(controller, { resetStickDiagrams, successAlert, set_progress });
window.ds5_finetune = () => ds5_finetune(controller, { ll_data, rr_data, clear_circularity });
window.flash_all_changes = flash_all_changes;
window.reboot_controller = reboot_controller;

View File

@@ -8,10 +8,10 @@ import { l } from '../translations.js';
* Handles step-by-step manual stick center calibration
*/
export class CalibCenterModal {
constructor(controllerInstance, { resetStickDiagrams, show_popup, set_progress }) {
constructor(controllerInstance, { resetStickDiagrams, successAlert, set_progress }) {
this.controller = controllerInstance;
this.resetStickDiagrams = resetStickDiagrams;
this.show_popup = show_popup;
this.successAlert = successAlert;
this.set_progress = set_progress;
this._initEventListeners();
@@ -130,7 +130,7 @@ export class CalibCenterModal {
this.resetStickDiagrams();
if (result?.message) {
this.show_popup(result.message);
this.successAlert(result.message);
}
}

View File

@@ -7,11 +7,11 @@ import { sleep } from '../utils.js';
* Handles stick range calibration
*/
export class CalibRangeModal {
constructor(controllerInstance, { resetStickDiagrams, show_popup }) {
constructor(controllerInstance, { resetStickDiagrams, successAlert }) {
// Dependencies
this.controller = controllerInstance;
this.resetStickDiagrams = resetStickDiagrams;
this.show_popup = show_popup;
this.successAlert = successAlert;
}
async open() {
@@ -30,7 +30,7 @@ export class CalibRangeModal {
const result = await this.controller.calibrateRangeOnClose();
if (result?.message) {
this.show_popup(result.message);
this.successAlert(result.message);
}
}
}

View File

@@ -14,33 +14,28 @@ async function loadTemplate(templateName) {
return templateCache.get(templateName);
}
try {
// Check if we have bundled assets (production mode)
if (window.BUNDLED_ASSETS && window.BUNDLED_ASSETS.templates) {
const templateHtml = window.BUNDLED_ASSETS.templates[templateName];
if (templateHtml) {
templateCache.set(templateName, templateHtml);
return templateHtml;
}
// Check if we have bundled assets (production mode)
if (window.BUNDLED_ASSETS && window.BUNDLED_ASSETS.templates) {
const templateHtml = window.BUNDLED_ASSETS.templates[templateName];
if (templateHtml) {
templateCache.set(templateName, templateHtml);
return templateHtml;
}
// Fallback to fetching from server (development mode)
// Only append .html if the templateName doesn't already have an extension
const hasExtension = templateName.includes('.');
const templatePath = hasExtension ? `templates/${templateName}` : `templates/${templateName}.html`;
const response = await fetch(templatePath);
if (!response.ok) {
throw new Error(`Failed to load template: ${templateName}`);
}
const templateHtml = await response.text();
templateCache.set(templateName, templateHtml);
return templateHtml;
} catch (error) {
console.error(`Error loading template ${templateName}:`, error);
return '';
}
// Fallback to fetching from server (development mode)
// Only append .html if the templateName doesn't already have an extension
const hasExtension = templateName.includes('.');
const templatePath = hasExtension ? `templates/${templateName}` : `templates/${templateName}.html`;
const response = await fetch(templatePath);
if (!response.ok) {
throw new Error(`Failed to load template: ${templateName}`);
}
const templateHtml = await response.text();
templateCache.set(templateName, templateHtml);
return templateHtml;
}
/**
@@ -49,59 +44,48 @@ async function loadTemplate(templateName) {
* @returns {Promise<string>} - Promise that resolves with the SVG content
*/
async function loadSvgAsset(assetPath) {
try {
// Check if we have bundled assets (production mode)
if (window.BUNDLED_ASSETS && window.BUNDLED_ASSETS.svg) {
const svgContent = window.BUNDLED_ASSETS.svg[assetPath];
if (svgContent) {
return svgContent;
}
// Check if we have bundled assets (production mode)
if (window.BUNDLED_ASSETS && window.BUNDLED_ASSETS.svg) {
const svgContent = window.BUNDLED_ASSETS.svg[assetPath];
if (svgContent) {
return svgContent;
}
// Fallback to fetching from server (development mode)
const response = await fetch(`assets/${assetPath}`);
if (!response.ok) {
throw new Error(`Failed to load SVG asset: ${assetPath}`);
}
return await response.text();
} catch (error) {
console.error(`Error loading SVG asset ${assetPath}:`, error);
return '';
}
// Fallback to fetching from server (development mode)
const response = await fetch(`assets/${assetPath}`);
if (!response.ok) {
throw new Error(`Failed to load SVG asset: ${assetPath}`);
}
return await response.text();
}
/**
* Load all templates and insert them into the DOM
*/
export async function loadAllTemplates() {
try {
// Load SVG icons
const iconsHtml = await loadSvgAsset('icons.svg');
const iconsContainer = document.createElement('div');
iconsContainer.innerHTML = iconsHtml;
document.body.prepend(iconsContainer);
// Load SVG icons
const iconsHtml = await loadSvgAsset('icons.svg');
const iconsContainer = document.createElement('div');
iconsContainer.innerHTML = iconsHtml;
document.body.prepend(iconsContainer);
// Load modals
const faqModalHtml = await loadTemplate('faq-modal');
const popupModalHtml = await loadTemplate('popup-modal');
const finetuneModalHtml = await loadTemplate('finetune-modal');
const calibCenterModalHtml = await loadTemplate('calib-center-modal');
const welcomeModalHtml = await loadTemplate('welcome-modal');
const calibrateModalHtml = await loadTemplate('calibrate-modal');
const rangeModalHtml = await loadTemplate('range-modal');
const edgeProgressModalHtml = await loadTemplate('edge-progress-modal');
const edgeModalHtml = await loadTemplate('edge-modal');
const donateModalHtml = await loadTemplate('donate-modal');
// Load modals
const faqModalHtml = await loadTemplate('faq-modal');
const popupModalHtml = await loadTemplate('popup-modal');
const finetuneModalHtml = await loadTemplate('finetune-modal');
const calibCenterModalHtml = await loadTemplate('calib-center-modal');
const welcomeModalHtml = await loadTemplate('welcome-modal');
const calibrateModalHtml = await loadTemplate('calibrate-modal');
const rangeModalHtml = await loadTemplate('range-modal');
const edgeProgressModalHtml = await loadTemplate('edge-progress-modal');
const edgeModalHtml = await loadTemplate('edge-modal');
const donateModalHtml = await loadTemplate('donate-modal');
// Create modals container
const modalsContainer = document.createElement('div');
modalsContainer.id = 'modals-container';
modalsContainer.innerHTML = faqModalHtml + popupModalHtml + finetuneModalHtml + calibCenterModalHtml + welcomeModalHtml + calibrateModalHtml + rangeModalHtml + edgeProgressModalHtml + edgeModalHtml + donateModalHtml;
document.body.appendChild(modalsContainer);
console.log('All templates loaded successfully');
} catch (error) {
console.error('Error loading templates:', error);
}
// Create modals container
const modalsContainer = document.createElement('div');
modalsContainer.id = 'modals-container';
modalsContainer.innerHTML = faqModalHtml + popupModalHtml + finetuneModalHtml + calibCenterModalHtml + welcomeModalHtml + calibrateModalHtml + rangeModalHtml + edgeProgressModalHtml + edgeModalHtml + donateModalHtml;
document.body.appendChild(modalsContainer);
}