frontend-hamroun
Version:
A lightweight frontend JavaScript framework with React-like syntax
144 lines (143 loc) • 4.54 kB
JavaScript
/**
* Common utility functions for the framework
*/
/**
* Creates a debounced function that delays invoking the provided function
* until after the specified wait time has elapsed since the last time it was invoked.
*/
export function debounce(func, wait) {
let timeout = null;
const debounced = function (...args) {
const later = () => {
timeout = null;
func.apply(this, args);
};
if (timeout !== null) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
};
debounced.cancel = function () {
if (timeout !== null) {
clearTimeout(timeout);
timeout = null;
}
};
return debounced;
}
/**
* Creates a throttled function that only invokes the provided function
* at most once per every wait milliseconds.
*/
export function throttle(func, wait) {
let timeout = null;
let previous = 0;
const throttled = function (...args) {
const now = Date.now();
const remaining = wait - (now - previous);
if (remaining <= 0 || remaining > wait) {
if (timeout !== null) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(this, args);
}
else if (timeout === null) {
timeout = setTimeout(() => {
previous = Date.now();
timeout = null;
func.apply(this, args);
}, remaining);
}
};
throttled.cancel = function () {
if (timeout !== null) {
clearTimeout(timeout);
timeout = null;
}
previous = 0;
};
return throttled;
}
/**
* Deep clones an object by using JSON serialization
*/
export function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
return JSON.parse(JSON.stringify(obj));
}
/**
* Creates a memoized version of a function that caches results based on arguments
*/
export function memoize(func) {
const cache = new Map();
return ((...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = func(...args);
cache.set(key, result);
return result;
});
}
/**
* Creates a UUID v4 string
*/
export function uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* Formats a date according to the specified format
*/
export function formatDate(date, format) {
const months = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
const shortMonths = months.map(m => m.slice(0, 3));
const days = [
'Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'
];
const shortDays = days.map(d => d.slice(0, 3));
const tokens = {
'YYYY': () => date.getFullYear().toString(),
'YY': () => (date.getFullYear() % 100).toString().padStart(2, '0'),
'MMMM': () => months[date.getMonth()],
'MMM': () => shortMonths[date.getMonth()],
'MM': () => (date.getMonth() + 1).toString().padStart(2, '0'),
'M': () => (date.getMonth() + 1).toString(),
'DDDD': () => days[date.getDay()],
'DDD': () => shortDays[date.getDay()],
'DD': () => date.getDate().toString().padStart(2, '0'),
'D': () => date.getDate().toString(),
'HH': () => date.getHours().toString().padStart(2, '0'),
'H': () => date.getHours().toString(),
'hh': () => (date.getHours() % 12 || 12).toString().padStart(2, '0'),
'h': () => (date.getHours() % 12 || 12).toString(),
'mm': () => date.getMinutes().toString().padStart(2, '0'),
'm': () => date.getMinutes().toString(),
'ss': () => date.getSeconds().toString().padStart(2, '0'),
's': () => date.getSeconds().toString(),
'a': () => date.getHours() < 12 ? 'am' : 'pm',
'A': () => date.getHours() < 12 ? 'AM' : 'PM'
};
const tokenRegex = new RegExp(Object.keys(tokens).join('|'), 'g');
return format.replace(tokenRegex, (match) => tokens[match]());
}
export default {
debounce,
throttle,
deepClone,
memoize,
uuid,
formatDate
};