rkgk/static/framework.js

114 lines
2.8 KiB
JavaScript
Raw Normal View History

2024-08-10 23:13:20 +02:00
export function listen(...listenerSpecs) {
return new Promise((resolve) => {
let removeAllEventListeners;
let listeners = listenerSpecs.map(([element, eventName]) => {
let listener = (event) => {
removeAllEventListeners();
resolve(event);
};
element.addEventListener(eventName, listener);
return { element, eventName, func: listener };
});
removeAllEventListeners = () => {
for (let listener of listeners) {
listener.element.removeEventListener(listener.eventName, listener.func);
}
};
});
}
export function debounce(time, fn) {
// This function is kind of tricky, but basically:
//
// - we want to guarantee `fn` is called at most once every `time` milliseconds
// - at the same time, in case debounced `fn` is called during an ongoing timeout, we want to
// queue up another run, and run it immediately after `time` passes
// - at the same time, in case this catch-up condition occurs, we must also ensure there's a
// delay after `fn` is called
//
// yielding the recursive solution below.
2024-08-10 23:13:20 +02:00
let timeout = null;
let queued = null;
const callFn = (args) => {
fn(...args);
timeout = setTimeout(() => {
timeout = null;
if (queued != null) {
callFn(queued);
queued = null;
}
}, time);
};
2024-08-10 23:13:20 +02:00
return (...args) => {
if (timeout == null) {
callFn(args);
} else {
queued = args;
2024-08-10 23:13:20 +02:00
}
};
}
2025-06-19 13:48:07 +02:00
export class Pool {
constructor() {
this.pool = [];
}
alloc(ctor) {
if (this.pool.length > 0) {
return this.pool.pop();
} else {
return new ctor();
}
}
free(obj) {
this.pool.push(obj);
}
}
2025-06-19 13:48:07 +02:00
export class SaveData {
constructor(prefix) {
this.prefix = `rkgk.${prefix}`;
this.elementId = "<global>";
}
#localStorageKey(key) {
return `${this.prefix}.${this.elementId}.${key}`;
}
attachToElement(element) {
this.elementId = element.id;
2025-06-19 13:48:07 +02:00
}
getRaw(key) {
return localStorage.getItem(this.#localStorageKey(key));
}
setRaw(key, value) {
localStorage.setItem(this.#localStorageKey(key), value);
}
get(key, defaultValue) {
let value = this.getRaw(key);
if (value == null) {
return defaultValue;
} else {
try {
return JSON.parse(value);
} catch (e) {
throw new Error(`${this.#localStorageKey(key)}`, { cause: e });
}
}
}
set(key, value) {
this.setRaw(key, JSON.stringify(value));
}
}