Files
glance/internal/glance/static/js/utils.js
Svilen Markov dd91a506fa Add todo widget
2025-05-08 16:59:02 +01:00

82 lines
2.0 KiB
JavaScript

export function throttledDebounce(callback, maxDebounceTimes, debounceDelay) {
let debounceTimeout;
let timesDebounced = 0;
return function () {
if (timesDebounced == maxDebounceTimes) {
clearTimeout(debounceTimeout);
timesDebounced = 0;
callback();
return;
}
clearTimeout(debounceTimeout);
timesDebounced++;
debounceTimeout = setTimeout(() => {
timesDebounced = 0;
callback();
}, debounceDelay);
};
};
export function isElementVisible(element) {
return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
}
export function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
// NOTE: inconsistent behavior between browsers when it comes to
// whether the newly opened tab gets focused or not, potentially
// depending on the event that this function is called from
export function openURLInNewTab(url, focus = true) {
const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
if (focus && newWindow != null) newWindow.focus();
}
export class Vec2 {
constructor(x, y) {
this.x = x;
this.y = y;
}
static new(x = 0, y = 0) {
return new Vec2(x, y);
}
static fromEvent(event) {
return new Vec2(event.clientX, event.clientY);
}
setFromEvent(event) {
this.x = event.clientX;
this.y = event.clientY;
return this;
}
set(x, y) {
this.x = x;
this.y = y;
return this;
}
}
export function toggleableEvents(element, eventToHandlerMap) {
return [
() => {
for (const [event, handler] of Object.entries(eventToHandlerMap)) {
element.addEventListener(event, handler);
}
},
() => {
for (const [event, handler] of Object.entries(eventToHandlerMap)) {
element.removeEventListener(event, handler);
}
}
];
}