WebUI: Convert 'Progress Bar' class to a custom element

Got rid of Mootools and manual calculation of width.

PR #22768.
This commit is contained in:
tehcneko 2025-05-27 14:16:18 +08:00 committed by GitHub
parent f47754838b
commit 48f7f6fb8c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 154 deletions

View File

@ -65,7 +65,6 @@ window.qBittorrent.DynamicTable ??= (() => {
}; };
let DynamicTableHeaderContextMenuClass = null; let DynamicTableHeaderContextMenuClass = null;
let progressColumnWidth = -1;
class DynamicTable { class DynamicTable {
setup(dynamicTableDivId, dynamicTableFixedHeaderDivId, contextMenu, useVirtualList = false) { setup(dynamicTableDivId, dynamicTableFixedHeaderDivId, contextMenu, useVirtualList = false) {
@ -1358,34 +1357,14 @@ window.qBittorrent.DynamicTable ??= (() => {
const div = td.firstElementChild; const div = td.firstElementChild;
if (div !== null) { if (div !== null) {
if (td.resized) {
td.resized = false;
div.setWidth(progressColumnWidth - 5);
}
if (div.getValue() !== progressFormatted) if (div.getValue() !== progressFormatted)
div.setValue(progressFormatted); div.setValue(progressFormatted);
} }
else { else {
if (progressColumnWidth < 0) td.append(new window.qBittorrent.ProgressBar.ProgressBar(progressFormatted));
progressColumnWidth = td.offsetWidth;
td.append(new window.qBittorrent.ProgressBar.ProgressBar(progressFormatted, {
width: progressColumnWidth - 5
}));
td.resized = false;
} }
}; };
this.columns["progress"].staticWidth = 100; this.columns["progress"].staticWidth = 100;
this.columns["progress"].onResize = function(columnName) {
const pos = this.getColumnPos(columnName);
progressColumnWidth = -1;
for (const tr of this.getTrs()) {
const td = this.getRowCells(tr)[pos];
if (progressColumnWidth < 0)
progressColumnWidth = td.offsetWidth;
td.resized = true;
this.columns[columnName].updateTd(td, this.getRow(tr.rowId));
}
}.bind(this);
// num_seeds // num_seeds
this.columns["num_seeds"].updateTd = function(td, row) { this.columns["num_seeds"].updateTd = function(td, row) {
@ -2881,14 +2860,10 @@ window.qBittorrent.DynamicTable ??= (() => {
const value = Number(this.getRowValue(row)); const value = Number(this.getRowValue(row));
const progressBar = td.firstElementChild; const progressBar = td.firstElementChild;
if (progressBar === null) { if (progressBar === null)
td.append(new window.qBittorrent.ProgressBar.ProgressBar(value, { td.append(new window.qBittorrent.ProgressBar.ProgressBar(value));
width: 80 else
}));
}
else {
progressBar.setValue(value); progressBar.setValue(value);
}
}; };
this.columns["progress"].staticWidth = 100; this.columns["progress"].staticWidth = 100;
@ -3789,34 +3764,14 @@ window.qBittorrent.DynamicTable ??= (() => {
const div = td.firstElementChild; const div = td.firstElementChild;
if (div !== null) { if (div !== null) {
if (td.resized) {
td.resized = false;
div.setWidth(progressColumnWidth - 5);
}
if (div.getValue() !== progress) if (div.getValue() !== progress)
div.setValue(progress); div.setValue(progress);
} }
else { else {
if (progressColumnWidth < 0) td.append(new window.qBittorrent.ProgressBar.ProgressBar(progress));
progressColumnWidth = td.offsetWidth;
td.append(new window.qBittorrent.ProgressBar.ProgressBar(progress, {
width: progressColumnWidth - 5
}));
td.resized = false;
} }
}; };
this.columns["progress"].staticWidth = 100; this.columns["progress"].staticWidth = 100;
this.columns["progress"].onResize = function(columnName) {
const pos = this.getColumnPos(columnName);
progressColumnWidth = -1;
for (const tr of this.getTrs()) {
const td = this.getRowCells(tr)[pos];
if (progressColumnWidth < 0)
progressColumnWidth = td.offsetWidth;
td.resized = true;
this.columns[columnName].updateTd(td, this.getRow(tr.rowId));
}
}.bind(this);
// piece_size // piece_size
this.columns["piece_size"].updateTd = function(td, row) { this.columns["piece_size"].updateTd = function(td, row) {

View File

@ -36,124 +36,82 @@ window.qBittorrent.ProgressBar ??= (() => {
}; };
}; };
let progressBars = 0; class ProgressBar extends HTMLElement {
const ProgressBar = new Class({ static #progressBarUniqueId = 0;
initialize: (value, parameters) => { static #styles = {
const vals = { height: 12,
id: `progressbar_${progressBars++}`, darkbg: "var(--color-background-blue)",
value: [value, 0].pick(), darkfg: "var(--color-text-white)",
width: 0, lightbg: "var(--color-background-default)",
height: 0, lightfg: "var(--color-text-default)",
darkbg: "var(--color-background-blue)", };
darkfg: "var(--color-text-white)",
lightbg: "var(--color-background-default)",
lightfg: "var(--color-text-default)"
};
if (parameters && (typeOf(parameters) === "object"))
Object.append(vals, parameters);
if (vals.height < 12)
vals.height = 12;
const obj = document.createElement("div"); #value = 0;
obj.id = vals.id;
obj.className = "progressbar_wrapper";
obj.style.border = "1px solid var(--color-border-default)";
obj.style.boxSizing = "content-box";
obj.style.width = `${vals.width}px`;
obj.style.height = `${vals.height}px`;
obj.style.position = "relative";
obj.style.margin = "0 auto";
obj.vals = vals;
obj.vals.value = [value, 0].pick();
const dark = document.createElement("div"); #id = ++ProgressBar.#progressBarUniqueId;
dark.id = `${vals.id}_dark`;
dark.className = "progressbar_dark";
dark.style.width = `${vals.width}px`;
dark.style.height = `${vals.height}px`;
dark.style.background = vals.darkbg;
dark.style.boxSizing = "content-box";
dark.style.color = vals.darkfg;
dark.style.position = "absolute";
dark.style.textAlign = "center";
dark.style.left = "0";
dark.style.top = "0";
dark.style.lineHeight = `${vals.height}px`;
obj.vals.dark = dark; #light = document.createElement("div");
#dark = document.createElement("div");
const light = document.createElement("div"); constructor(value) {
light.id = `${vals.id}_light`; super();
light.className = "progressbar_light";
light.style.width = `${vals.width}px`;
light.style.height = `${vals.height}px`;
light.style.background = vals.lightbg;
light.style.boxSizing = "content-box";
light.style.color = vals.lightfg;
light.style.position = "absolute";
light.style.textAlign = "center";
light.style.left = "0";
light.style.top = "0";
light.style.lineHeight = `${vals.height}px`;
obj.vals.light = light; this.#dark.style.width = "100%";
this.#dark.style.height = `${ProgressBar.#styles.height}px`;
this.#dark.style.background = ProgressBar.#styles.darkbg;
this.#dark.style.boxSizing = "content-box";
this.#dark.style.color = ProgressBar.#styles.darkfg;
this.#dark.style.position = "absolute";
this.#dark.style.textAlign = "center";
this.#dark.style.left = "0";
this.#dark.style.top = "0";
this.#dark.style.lineHeight = `${ProgressBar.#styles.height}px`;
obj.appendChild(obj.vals.dark); this.#light.style.width = "100%";
obj.appendChild(obj.vals.light); this.#light.style.height = `${ProgressBar.#styles.height}px`;
obj.getValue = ProgressBar_getValue; this.#light.style.background = ProgressBar.#styles.lightbg;
obj.setValue = ProgressBar_setValue; this.#light.style.boxSizing = "content-box";
obj.setWidth = ProgressBar_setWidth; this.#light.style.color = ProgressBar.#styles.lightfg;
if (vals.width) this.#light.style.position = "absolute";
obj.setValue(vals.value); this.#light.style.textAlign = "center";
else this.#light.style.left = "0";
setTimeout(ProgressBar_checkForParent, 0, obj.id); this.#light.style.top = "0";
return obj; this.#light.style.lineHeight = `${ProgressBar.#styles.height}px`;
this.attachShadow({ mode: "open" });
this.shadowRoot.host.id = this.#id;
this.shadowRoot.host.style.display = "block";
this.shadowRoot.host.style.border = "1px solid var(--color-border-default)";
this.shadowRoot.host.style.boxSizing = "content-box";
this.shadowRoot.host.style.height = `${ProgressBar.#styles.height}px`;
this.shadowRoot.host.style.position = "relative";
this.shadowRoot.host.style.margin = "0 auto";
this.shadowRoot.appendChild(this.#dark);
this.shadowRoot.appendChild(this.#light);
this.setValue(value);
} }
});
function ProgressBar_getValue() { getValue() {
return this.vals.value; return this.#value;
} }
function ProgressBar_setValue(value) { setValue(value) {
value = Number(value); value = Number(value);
if (Number.isNaN(value)) if (Number.isNaN(value))
value = 0; value = 0;
value = Math.min(Math.max(value, 0), 100); this.#value = Math.min(Math.max(value, 0), 100);
this.vals.value = value;
const displayedValue = `${window.qBittorrent.Misc.toFixedPointString(value, 1)}%`; const displayedValue = `${window.qBittorrent.Misc.toFixedPointString(this.#value, 1)}%`;
this.vals.dark.textContent = displayedValue; this.#dark.textContent = displayedValue;
this.vals.light.textContent = displayedValue; this.#light.textContent = displayedValue;
const r = Number(this.vals.width * (value / 100)); this.#dark.style.clipPath = `inset(0 ${100 - this.#value}% 0 0)`;
this.vals.dark.style.clipPath = `inset(0 calc(100% - ${r}px) 0 0)`; this.#light.style.clipPath = `inset(0 0 0 ${this.#value}%)`;
this.vals.light.style.clipPath = `inset(0 0 0 ${r}px)`;
}
function ProgressBar_setWidth(value) {
if (this.vals.width !== value) {
this.vals.width = value;
this.style.width = `${value}px`;
this.vals.dark.style.width = `${value}px`;
this.vals.light.style.width = `${value}px`;
this.setValue(this.vals.value);
} }
} }
const ProgressBar_checkForParent = (id) => { customElements.define("progress-bar", ProgressBar);
const obj = document.getElementById(id);
if (!obj)
return;
if (!obj.parentNode)
return setTimeout(ProgressBar_checkForParent, 100, id);
obj.style.width = "100%";
const w = obj.offsetWidth;
obj.vals.dark.style.width = `${w}px`;
obj.vals.light.style.width = `${w}px`;
obj.vals.width = w;
obj.setValue(obj.vals.value);
};
return exports(); return exports();
})(); })();