mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
52 lines
2.4 KiB
JavaScript
52 lines
2.4 KiB
JavaScript
(() => {
|
|
function createScheduler({ load, apply, onError = () => {} }) {
|
|
let generation = 0;
|
|
let running = null;
|
|
function request({ supersede = true } = {}) {
|
|
if (running && !supersede) return running;
|
|
generation += 1;
|
|
if (running) return running;
|
|
running = (async () => {
|
|
let observed;
|
|
do {
|
|
observed = generation;
|
|
try {
|
|
const snapshot = await load();
|
|
if (observed === generation) apply(snapshot);
|
|
} catch (error) { if (observed === generation) onError(error); }
|
|
} while (observed !== generation);
|
|
})().finally(() => { running = null; });
|
|
return running;
|
|
}
|
|
return Object.freeze({ request });
|
|
}
|
|
function createProtection(document) {
|
|
const baseline = new WeakMap();
|
|
const fields = (element) => [...element.querySelectorAll('input,select,textarea')];
|
|
const signature = (field) => JSON.stringify({ value: field.value, checked: field.checked,
|
|
selected: field.tagName === 'SELECT' ? [...field.selectedOptions].map((option) => option.value) : null });
|
|
const dirty = () => new Set(fields(document).filter((field) => baseline.has(field) && baseline.get(field) !== signature(field)));
|
|
const remember = ({ preserve = new Set() } = {}) => fields(document).forEach((field) => {
|
|
if (!preserve.has(field)) baseline.set(field, signature(field));
|
|
});
|
|
function protects(element) {
|
|
if (!element) return false;
|
|
const focused = document.activeElement;
|
|
if (element.contains(focused) && focused?.matches('input,select,textarea,button,a,summary')) return true;
|
|
if (element.matches('[data-preview-token]') || element.querySelector('[data-preview-token]')) return true;
|
|
return fields(element).some((field) => baseline.has(field) && baseline.get(field) !== signature(field));
|
|
}
|
|
function complete(element) {
|
|
if (!element) return;
|
|
fields(element).forEach((field) => baseline.set(field, signature(field)));
|
|
[element, ...element.querySelectorAll('[data-preview-token]')].forEach((node) => {
|
|
delete node.dataset.previewToken;
|
|
delete node.dataset.planHash;
|
|
});
|
|
if (element.contains(document.activeElement)) document.activeElement.blur();
|
|
}
|
|
return Object.freeze({ remember, dirty, protects, complete });
|
|
}
|
|
globalThis.TorchLiveRefresh = Object.freeze({ createScheduler, createProtection });
|
|
})();
|