export function esc(str) { if (!str) return ''; return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } export function sanitizeHtml(html) { // DOMPurify is loaded globally from index.html. If it is unavailable, render // as plain text rather than attempting partial sanitization. if (!window.DOMPurify || typeof window.DOMPurify.sanitize !== 'function') { console.warn('[learningHub] DOMPurify unavailable - rendering as plain text.'); var d = document.createElement('div'); d.textContent = String(html == null ? '' : html); return d.innerHTML; } return window.DOMPurify.sanitize(html, { ALLOWED_TAGS: ['p','br','b','strong','i','em','u','s','h1','h2','h3','h4','h5','h6', 'ul','ol','li','a','blockquote','code','pre','table','thead','tbody','tr','th','td', 'hr','div','span','sub','sup','dl','dt','dd'], ALLOWED_ATTR: ['href','colspan','rowspan','class','target','rel'], ADD_ATTR: ['target'], FORBID_ATTR: ['style','onerror','onload','onclick','onmouseover'], ALLOW_DATA_ATTR: false }); }