Files
hello-htmx/static/js/loader.js
2023-05-11 00:04:47 +02:00

99 lines
2.4 KiB
JavaScript

/**
* A loading bar that hooks into htmx events to automatically indicate the
* progression of pending requests.
*
* ```html
* <div data-loader></div>
* ```
* Only the first loader will be used.
*/
(function () {
var MAX_INCREMENT = 20;
var MIN_INCREMENT = 3;
var ADVANCE_UNTIL = 90;
var pending = 0;
var increment = MAX_INCREMENT;
var timeout = null;
var interval = null;
function getLoader() {
return document.querySelector("[data-loader]");
}
function clamp(x, a, b) {
return Math.max(a, Math.min(x, b));
}
function progress(loader) {
loader.hidden = false;
var current = parseInt(loader.dataset.loader);
if (current < ADVANCE_UNTIL) {
current = Math.min(current + increment, ADVANCE_UNTIL);
loader.dataset.loader = current;
loader.style.right = 100 - current + "%";
increment = clamp(Math.floor(increment * 0.65), MIN_INCREMENT, MAX_INCREMENT);
}
}
function start() {
pending++;
if (pending > 1) {
return;
}
clearTimeout(timeout);
clearInterval(interval);
increment = MAX_INCREMENT;
var loader = getLoader();
if (!loader) {
return;
}
// Give the request a reasonable time to complete before triggering the
// loader.
timeout = setTimeout(function () {
loader.dataset.loader = 0;
loader.style.right = "100%";
loader.hidden = false;
// Increment the loader state until it reaches the threshold.
// Trickery and lies!
interval = setInterval(function () {
progress(loader)
}, 100);
}, 250);
}
function finish() {
pending--;
if (pending <= 0) {
clearTimeout(timeout);
clearInterval(interval);
var loader = getLoader();
if (!loader) {
return;
}
loader.style.right = 0;
timeout = setTimeout(function () {
loader.hidden = true;
timeout = setTimeout(function () {
loader.dataset.loader = 0;
loader.style.right = "100%";
}, 500);
}, 500);
return;
}
}
addEventListener("htmx:beforeRequest", start);
addEventListener("htmx:afterRequest", finish);
})();