initial commit
This commit is contained in:
88
js/utils/helpers.js
Normal file
88
js/utils/helpers.js
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
export function escapeHTML(str) {
|
||||
if (str === null || str === undefined) return '';
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format price with currency symbol
|
||||
* @param {number} price - Price value
|
||||
* @param {string} currency - Currency code (EUR, USD, CHF, XMR)
|
||||
* @returns {string} - Formatted price string
|
||||
*/
|
||||
export function formatPrice(price, currency = 'EUR') {
|
||||
if (price === null || price === undefined) return '–';
|
||||
|
||||
const symbols = {
|
||||
EUR: '€',
|
||||
USD: '$',
|
||||
CHF: 'CHF',
|
||||
XMR: 'ɱ'
|
||||
};
|
||||
|
||||
const symbol = symbols[currency] || currency;
|
||||
|
||||
if (currency === 'XMR') {
|
||||
return `${price.toFixed(4)} ${symbol}`;
|
||||
}
|
||||
|
||||
return `${symbol} ${price.toFixed(2)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format relative time (e.g., "vor 2 Stunden")
|
||||
* @param {Date|string} date - Date to format
|
||||
* @param {string} locale - Locale code
|
||||
* @returns {string} - Relative time string
|
||||
*/
|
||||
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 - Delay in ms
|
||||
* @returns {Function} - Debounced function
|
||||
*/
|
||||
export function debounce(fn, delay = 300) {
|
||||
let timeoutId;
|
||||
return (...args) => {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => fn.apply(this, args), delay);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate string with ellipsis
|
||||
* @param {string} str - String to truncate
|
||||
* @param {number} maxLength - Maximum length
|
||||
* @returns {string} - Truncated string
|
||||
*/
|
||||
export function truncate(str, maxLength = 100) {
|
||||
if (!str || str.length <= maxLength) return str;
|
||||
return str.slice(0, maxLength - 1) + '…';
|
||||
}
|
||||
Reference in New Issue
Block a user