diff --git a/javascript/simpleProgressBar.js b/javascript/simpleProgressBar.js new file mode 100644 index 000000000..75cbfe49c --- /dev/null +++ b/javascript/simpleProgressBar.js @@ -0,0 +1,82 @@ +class SimpleProgressBar { + #container = document.createElement("div"); + #progress = document.createElement("div"); + #textDiv = document.createElement("div"); + #text = document.createElement("span"); + #visible = false; + #hideTimeout = null; + #interval = null; + #max = 0; + /** @type {Set} */ + #monitoredSet; + + constructor() { + this.#container.style.cssText = "position:relative;width:100%;background-color:hsla(0,0%,36%,0.3);height:1.2rem;margin:0;padding:0;display:none;" + this.#progress.style.cssText = "position:absolute;left:0;height:100%;width:0;transition:width 200ms;" + this.#progress.style.backgroundColor = "hsla(110, 32%, 35%, 0.80)"; // alt: "#27911d" + this.#textDiv.style.cssText = "margin:auto;width:max-content;height:100%;"; + this.#text.style.cssText = "position:relative;user-select:none;color:white;" + + this.#textDiv.append(this.#text); + this.#container.append(this.#progress, this.#textDiv); + } + + setMax(max) { + this.clearProgress(); + this.#max = max; + this.#startUpdating(); + } + + attach(element) { + if (element.hasChildNodes) { + element.innerHTML = ''; + } + element.appendChild(this.#container); + } + + monitor(hashes) { + // This is required because incrementing a variable with a class method turned out to not be an atomic operation + this.#monitoredSet = hashes; + } + + clearProgress() { + this.#stopUpdating(); + clearTimeout(this.#hideTimeout); + this.#hideTimeout = null; + this.#container.style.display = "none"; + this.#visible = false; + this.#progress.style.width = "0"; + this.#text.textContent = ""; + } + + #setProgress(loaded, max) { + if (this.#hideTimeout) { + this.#hideTimeout = null; + } + + this.#progress.style.width = `${Math.floor((loaded / max) * 100)}%`; + this.#text.textContent = `${loaded}/${max}`; + + if (!this.#visible) { + this.#container.style.display = "block"; + this.#visible = true; + } + if (loaded >= max) { + this.#stopUpdating() + this.#hideTimeout = setTimeout(() => { + this.clearProgress(); + }, 1000); + } + } + + #startUpdating() { + this.#interval = setInterval(() => { + this.#setProgress(this.#monitoredSet.size, this.#max); + }, 250); + } + + #stopUpdating() { + clearInterval(this.#interval); + this.#interval = null; + } +}