78 lines
2.4 KiB
JavaScript
78 lines
2.4 KiB
JavaScript
/**
|
|
* 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>alert("XSS")</script>') // '<script>...'
|
|
*/
|
|
export function escapeHTML(str) {
|
|
if (str === null || str === undefined) return '';
|
|
return String(str)
|
|
.replace(/&/g, '&')
|
|
.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) + '…';
|
|
}
|