/** * Utility helper functions * @module utils/helpers */ /** * Escape HTML special characters to prevent XSS * Use for any user-generated content rendered via innerHTML * @param {string} str - Untrusted string * @returns {string} Escaped string safe for innerHTML * @example * escapeHTML('') // '<script>...' */ export function escapeHTML(str) { if (str === null || str === undefined) return ''; return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } /** * Format relative time (e.g., "vor 2 Stunden", "2 hours ago") * Uses Intl.RelativeTimeFormat for localization * @param {Date|string} date - Date to format * @param {string} [locale='de'] - Locale code * @returns {string} Relative time string * @example * formatRelativeTime(new Date(Date.now() - 3600000), 'de') // 'vor 1 Stunde' */ export function formatRelativeTime(date, locale = 'de') { const now = new Date(); const then = new Date(date); const diffMs = now - then; const diffSec = Math.floor(diffMs / 1000); const diffMin = Math.floor(diffSec / 60); const diffHour = Math.floor(diffMin / 60); const diffDay = Math.floor(diffHour / 24); const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }); if (diffDay > 0) return rtf.format(-diffDay, 'day'); if (diffHour > 0) return rtf.format(-diffHour, 'hour'); if (diffMin > 0) return rtf.format(-diffMin, 'minute'); return rtf.format(-diffSec, 'second'); } /** * Debounce function calls * @param {Function} fn - Function to debounce * @param {number} [delay=300] - Delay in ms * @returns {Function} Debounced function * @example * const debouncedSearch = debounce((q) => search(q), 500) */ export function debounce(fn, delay = 300) { let timeoutId return function (...args) { clearTimeout(timeoutId) timeoutId = setTimeout(() => fn.apply(this, args), delay) } } /** * Truncate string with ellipsis * @param {string} str - String to truncate * @param {number} [maxLength=100] - Maximum length * @returns {string} Truncated string * @example * truncate('Hello World', 5) // 'Hell…' */ export function truncate(str, maxLength = 100) { if (!str || str.length <= maxLength) return str; return str.slice(0, maxLength - 1) + '…'; }