Files
DocsMCP/webui/app/static/app.js
T
2026-06-05 23:02:55 +01:00

160 lines
3.9 KiB
JavaScript

// WebUI Static JavaScript Utilities
// Simple helper functions shared across templates
/**
* Escape HTML to prevent XSS attacks when displaying user content
*/
function escapeHtml(text) {
if (typeof text !== 'string') return "";
var e = document.createElement('div');
try {
e.textContent = text;
return e.innerHTML;
} catch (err) {
return String(text).replace(/[&<>"']/g, function(m) {
switch (m) {
case '&': return '&amp;';
case '<': return '&lt;';
case '>': return '&gt;';
case '"': return '&quot;';
case "'": return '&#x27;';
default: return m;
}
});
}
}
/**
* Format number with thousands separators
*/
function formatNumber(num) {
if (num === null || num === undefined) return "N/A";
return new Intl.NumberFormat().format(Math.floor(num));
}
/**
* Show loading spinner
*/
function showLoading(elementId) {
var el = document.getElementById(elementId);
if (el) {
el.innerHTML = '<div class="loading-spinner">Loading...</div>';
}
}
/**
* Hide loading spinner
*/
function hideLoading(elementId) {
var el = document.getElementById(elementId);
if (el) {
el.innerHTML = "";
}
}
/**
* Create a toast notification
*/
function showToast(message, type) {
var toast = document.createElement('div');
toast.className = 'toast ' + (type || 'info');
toast.textContent = message;
toast.style.cssText = 'position:fixed;bottom:20px;right:20px;' +
'padding:12px 20px;border-radius:4px;margin-bottom:10px;' +
'background:#333;color:white;font-size:0.9rem;z-index:1000';
document.body.appendChild(toast);
setTimeout(function() {
toast.style.opacity = '0';
setTimeout(function() { toast.remove(); }, 200);
}, 3000);
}
/**
* Show error notification
*/
function showError(message) {
showToast("Error: " + message, "error");
}
/**
* Show success notification
*/
function showSuccess(message) {
showToast("Success: " + message, "success");
}
/**
* Make an API request with error handling
*/
async function apiRequest(endpoint, method = 'GET', data = null) {
const config = window.webuiConfig;
let url = config.apiUrl;
if (!url.endsWith('/')) url += '/';
url += endpoint;
const headers = {};
if (config.apiKey) {
headers['X-API-Key'] = config.apiKey;
}
try {
let response;
if (method === 'POST') {
response = await fetch(url, {
method: method,
headers: headers,
body: JSON.stringify(data)
});
} else {
response = await fetch(url, {
method: method,
headers: headers
});
}
if (!response.ok) {
throw new Error(response.statusText);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else {
return await response.text();
}
} catch (err) {
console.error('API request failed:', err);
throw err;
}
}
/**
* Initialize tooltips if using them
*/
function initTooltips() {
// Add tooltip functionality here if needed
}
/**
* Debounce function for input handling
*/
function debounce(func, wait) {
var timeout;
return function executedFunction(...args) {
var later = function() {
clearTimeout(timeout);
func.apply(this, args);
};
timeout = setTimeout(later, wait);
};
}
// Export to window for use in templates
window.escapeHtml = escapeHtml;
window.formatNumber = formatNumber;
window.showToast = showToast;
window.showError = showError;
window.showSuccess = showSuccess;