99 lines
2.4 KiB
JavaScript
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);
|
|
})();
|