Avoid duplicating torrent content data in table

All content data is already stored in the FileTree, so we now read from that data directly. We no longer store a second copy of this data in the TorrentFilesTable.
This commit is contained in:
Thomas Piccirello 2024-10-07 16:12:32 -07:00
commit 74a3d5bf76
No known key found for this signature in database
3 changed files with 93 additions and 104 deletions

View file

@ -993,9 +993,13 @@ window.qBittorrent.DynamicTable ??= (() => {
} }
} }
getRowData(row, fullUpdate) {
return row[fullUpdate ? "full_data" : "data"];
}
updateRow(tr, fullUpdate) { updateRow(tr, fullUpdate) {
const row = this.rows.get(tr.rowId); const row = this.rows.get(tr.rowId);
const data = row[fullUpdate ? "full_data" : "data"]; const data = this.getRowData(row, fullUpdate);
const tds = this.getRowCells(tr); const tds = this.getRowCells(tr);
for (let i = 0; i < this.columns.length; ++i) { for (let i = 0; i < this.columns.length; ++i) {
@ -1007,7 +1011,7 @@ window.qBittorrent.DynamicTable ??= (() => {
if (this.columns[i].dataProperties.some(prop => Object.hasOwn(data, prop))) if (this.columns[i].dataProperties.some(prop => Object.hasOwn(data, prop)))
this.columns[i].updateTd(tds[i], row); this.columns[i].updateTd(tds[i], row);
} }
row["data"] = {}; row.data = {};
} }
removeRow(rowId) { removeRow(rowId) {
@ -2358,25 +2362,9 @@ window.qBittorrent.DynamicTable ??= (() => {
node.depth = depth; node.depth = depth;
node.parent = parent; node.parent = parent;
if (node.isFolder) { this.updateRowData({
const data = { rowId: node.rowId
rowId: node.rowId, });
fileId: -1,
checked: node.checked,
path: node.path,
original: node.original,
renamed: node.renamed
};
node.data = data;
node.full_data = data;
this.updateRowData(data);
}
else {
node.data.rowId = node.rowId;
node.full_data = node.data;
this.updateRowData(node.data);
}
node.children.each((child) => { node.children.each((child) => {
this.#addNodeToTable(child, depth + 1, node); this.#addNodeToTable(child, depth + 1, node);
@ -2396,6 +2384,10 @@ window.qBittorrent.DynamicTable ??= (() => {
return this.rows.get(rowId); return this.rows.get(rowId);
} }
getRowData(row, fullUpdate) {
return this.getNode(row.rowId);
}
getSelectedRows() { getSelectedRows() {
const nodes = this.fileTree.toArray(); const nodes = this.fileTree.toArray();
@ -2437,10 +2429,8 @@ window.qBittorrent.DynamicTable ??= (() => {
} }
const nodes = this.fileTree.toArray(); const nodes = this.fileTree.toArray();
for (const node of nodes) { for (const node of nodes)
node.checked = (checkbox.checked || checkbox.indeterminate) ? 0 : 1; node.checked = (checkbox.checked || checkbox.indeterminate) ? 0 : 1;
node.full_data.checked = node.checked;
}
this.updateGlobalCheckbox(); this.updateGlobalCheckbox();
} }
@ -2448,7 +2438,6 @@ window.qBittorrent.DynamicTable ??= (() => {
toggleNodeTreeCheckbox(rowId, checkState) { toggleNodeTreeCheckbox(rowId, checkState) {
const node = this.getNode(rowId); const node = this.getNode(rowId);
node.checked = checkState; node.checked = checkState;
node.full_data.checked = checkState;
const checkbox = document.getElementById(`cbRename${rowId}`); const checkbox = document.getElementById(`cbRename${rowId}`);
checkbox.checked = node.checked === 0; checkbox.checked = node.checked === 0;
checkbox.state = checkbox.checked ? "checked" : "unchecked"; checkbox.state = checkbox.checked ? "checked" : "unchecked";
@ -2530,7 +2519,6 @@ window.qBittorrent.DynamicTable ??= (() => {
for (const id of ids) { for (const id of ids) {
const node = that.getNode(id); const node = that.getNode(id);
node.checked = e.target.checked ? 0 : 1; node.checked = e.target.checked ? 0 : 1;
node.full_data.checked = node.checked;
} }
that.updateGlobalCheckbox(); that.updateGlobalCheckbox();
that.onRowSelectionChange(that.getNode(targetId)); that.onRowSelectionChange(that.getNode(targetId));
@ -2592,6 +2580,13 @@ window.qBittorrent.DynamicTable ??= (() => {
span.id = fileNameRenamedId; span.id = fileNameRenamedId;
span.textContent = node.renamed; span.textContent = node.renamed;
}; };
for (const column of this.columns) {
column["getRowValue"] = function(row, pos = 0) {
const node = that.getNode(row.rowId);
return node[this.dataProperties[pos]];
};
}
} }
onRowSelectionChange(row) {} onRowSelectionChange(row) {}
@ -2604,7 +2599,6 @@ window.qBittorrent.DynamicTable ??= (() => {
if (rowIds.includes(tr.rowId)) { if (rowIds.includes(tr.rowId)) {
const node = this.getNode(tr.rowId); const node = this.getNode(tr.rowId);
node.checked = 0; node.checked = 0;
node.full_data.checked = 0;
const checkbox = tr.querySelector(".RenamingCB"); const checkbox = tr.querySelector(".RenamingCB");
checkbox.state = "checked"; checkbox.state = "checked";
@ -2623,18 +2617,16 @@ window.qBittorrent.DynamicTable ??= (() => {
while (stack.length > 0) { while (stack.length > 0) {
const node = stack.pop(); const node = stack.pop();
node.children.sort((row1, row2) => { node.children.sort((node1, node2) => {
// list folders before files when sorting by name // list folders before files when sorting by name
if (isColumnOriginal) { if (isColumnOriginal) {
const node1 = this.getNode(row1.data.rowId);
const node2 = this.getNode(row2.data.rowId);
if (node1.isFolder && !node2.isFolder) if (node1.isFolder && !node2.isFolder)
return -1; return -1;
if (!node1.isFolder && node2.isFolder) if (!node1.isFolder && node2.isFolder)
return 1; return 1;
} }
const result = column.compareRows(row1, row2); const result = column.compareRows(node1, node2);
return isReverseSort ? result : -result; return isReverseSort ? result : -result;
}); });
@ -2746,14 +2738,6 @@ window.qBittorrent.DynamicTable ??= (() => {
return rows; return rows;
} }
setIgnored(rowId, ignore) {
const row = this.rows.get(rowId);
if (ignore)
row.full_data.remaining = 0;
else
row.full_data.remaining = (row.full_data.size * (1.0 - (row.full_data.progress / 100)));
}
setupCommonEvents() { setupCommonEvents() {
const headerDiv = document.getElementById("bulkRenameFilesTableFixedHeaderDiv"); const headerDiv = document.getElementById("bulkRenameFilesTableFixedHeaderDiv");
this.dynamicTableDiv.addEventListener("scroll", (e) => { this.dynamicTableDiv.addEventListener("scroll", (e) => {
@ -2876,11 +2860,11 @@ window.qBittorrent.DynamicTable ??= (() => {
} }
isAllCheckboxesChecked() { isAllCheckboxesChecked() {
return this.fileTree.toArray().every((node) => node.checked === 1); return this.fileTree.toArray().every((node) => node.checked === window.qBittorrent.FileTree.TriState.Checked);
} }
isAllCheckboxesUnchecked() { isAllCheckboxesUnchecked() {
return this.fileTree.toArray().every((node) => node.checked !== 1); return this.fileTree.toArray().every((node) => node.checked !== window.qBittorrent.FileTree.TriState.Checked);
} }
populateTable(root) { populateTable(root) {
@ -2894,30 +2878,12 @@ window.qBittorrent.DynamicTable ??= (() => {
node.depth = depth; node.depth = depth;
node.parent = parent; node.parent = parent;
if (node.isFolder) { if (node.isFolder && !this.collapseState.has(node.rowId))
if (!this.collapseState.has(node.rowId))
this.collapseState.set(node.rowId, { depth: depth, collapsed: false }); this.collapseState.set(node.rowId, { depth: depth, collapsed: false });
const data = {
rowId: node.rowId,
size: node.size,
checked: node.checked,
remaining: node.remaining,
progress: node.progress,
priority: window.qBittorrent.TorrentContent.normalizePriority(node.priority),
availability: node.availability,
fileId: -1,
name: node.name
};
node.data = data; this.updateRowData({
node.full_data = data; rowId: node.rowId,
this.updateRowData(data, depth); });
}
else {
node.data.rowId = node.rowId;
node.full_data = node.data;
this.updateRowData(node.data);
}
node.children.each((child) => { node.children.each((child) => {
this.#addNodeToTable(child, depth + 1, node); this.#addNodeToTable(child, depth + 1, node);
@ -2938,8 +2904,12 @@ window.qBittorrent.DynamicTable ??= (() => {
} }
getRowFileId(rowId) { getRowFileId(rowId) {
const row = this.rows.get(rowId); const node = this.getNode(rowId);
return row?.full_data.fileId; return node.fileId;
}
getRowData(row, fullUpdate) {
return this.getNode(row.rowId);
} }
initColumns() { initColumns() {
@ -2971,6 +2941,7 @@ window.qBittorrent.DynamicTable ??= (() => {
this.columns["checked"].updateTd = function(td, row) { this.columns["checked"].updateTd = function(td, row) {
const id = row.rowId; const id = row.rowId;
const value = this.getRowValue(row); const value = this.getRowValue(row);
const fileId = that.getRowFileId(id);
if (td.firstElementChild === null) { if (td.firstElementChild === null) {
const treeImg = document.createElement("img"); const treeImg = document.createElement("img");
@ -2981,9 +2952,9 @@ window.qBittorrent.DynamicTable ??= (() => {
const downloadCheckbox = td.children[1]; const downloadCheckbox = td.children[1];
if (downloadCheckbox === undefined) if (downloadCheckbox === undefined)
td.append(window.qBittorrent.TorrentContent.createDownloadCheckbox(id, row.full_data.fileId, value)); td.append(window.qBittorrent.TorrentContent.createDownloadCheckbox(id, fileId, value));
else else
window.qBittorrent.TorrentContent.updateDownloadCheckbox(downloadCheckbox, id, row.full_data.fileId, value); window.qBittorrent.TorrentContent.updateDownloadCheckbox(downloadCheckbox, id, fileId, value);
}; };
this.columns["checked"].staticWidth = 50; this.columns["checked"].staticWidth = 50;
@ -3072,12 +3043,13 @@ window.qBittorrent.DynamicTable ??= (() => {
this.columns["priority"].updateTd = function(td, row) { this.columns["priority"].updateTd = function(td, row) {
const id = row.rowId; const id = row.rowId;
const value = this.getRowValue(row); const value = this.getRowValue(row);
const fileId = that.getRowFileId(id);
const priorityCombo = td.firstElementChild; const priorityCombo = td.firstElementChild;
if (priorityCombo === null) if (priorityCombo === null)
td.append(window.qBittorrent.TorrentContent.createPriorityCombo(id, row.full_data.fileId, value)); td.append(window.qBittorrent.TorrentContent.createPriorityCombo(id, fileId, value));
else else
window.qBittorrent.TorrentContent.updatePriorityCombo(priorityCombo, id, row.full_data.fileId, value); window.qBittorrent.TorrentContent.updatePriorityCombo(priorityCombo, id, fileId, value);
}; };
this.columns["priority"].staticWidth = 140; this.columns["priority"].staticWidth = 140;
@ -3086,6 +3058,13 @@ window.qBittorrent.DynamicTable ??= (() => {
this.columns["remaining"].updateTd = displaySize; this.columns["remaining"].updateTd = displaySize;
if (this.columns["availability"] !== undefined) if (this.columns["availability"] !== undefined)
this.columns["availability"].updateTd = displayPercentage; this.columns["availability"].updateTd = displayPercentage;
for (const column of this.columns) {
column["getRowValue"] = function(row, pos = 0) {
const node = that.getNode(row.rowId);
return node[this.dataProperties[pos]];
};
}
} }
#sortNodesByColumn(root, column) { #sortNodesByColumn(root, column) {
@ -3096,18 +3075,16 @@ window.qBittorrent.DynamicTable ??= (() => {
while (stack.length > 0) { while (stack.length > 0) {
const node = stack.pop(); const node = stack.pop();
node.children.sort((row1, row2) => { node.children.sort((node1, node2) => {
// list folders before files when sorting by name // list folders before files when sorting by name
if (isColumnName) { if (isColumnName) {
const node1 = this.getNode(row1.data.rowId);
const node2 = this.getNode(row2.data.rowId);
if (node1.isFolder && !node2.isFolder) if (node1.isFolder && !node2.isFolder)
return -1; return -1;
if (!node1.isFolder && node2.isFolder) if (!node1.isFolder && node2.isFolder)
return 1; return 1;
} }
const result = column.compareRows(row1, row2); const result = column.compareRows(node1, node2);
return isReverseSort ? result : -result; return isReverseSort ? result : -result;
}); });
@ -3177,8 +3154,8 @@ window.qBittorrent.DynamicTable ??= (() => {
const generateRowsSignature = () => { const generateRowsSignature = () => {
const rowsData = []; const rowsData = [];
for (const { full_data } of this.getRowValues()) for (const { rowId } of this.getRowValues())
rowsData.push({ ...full_data, collapsed: this.isCollapsed(full_data.rowId) }); rowsData.push({ ...this.getNode(rowId).serialize(), collapsed: this.isCollapsed(rowId) });
return JSON.stringify(rowsData); return JSON.stringify(rowsData);
}; };
@ -3212,11 +3189,11 @@ window.qBittorrent.DynamicTable ??= (() => {
} }
setIgnored(rowId, ignore) { setIgnored(rowId, ignore) {
const row = this.rows.get(rowId.toString()); const node = this.getNode(rowId.toString());
if (ignore) if (ignore)
row.full_data.remaining = 0; node.remaining = 0;
else else
row.full_data.remaining = (row.full_data.size * (1.0 - (row.full_data.progress / 100))); node.remaining = (node.size * (1.0 - (node.progress / 100)));
} }
setupCommonEvents() { setupCommonEvents() {

View file

@ -114,6 +114,7 @@ window.qBittorrent.FileTree ??= (() => {
name = ""; name = "";
path = ""; path = "";
rowId = null; rowId = null;
fileId = null;
size = 0; size = 0;
checked = TriState.Unchecked; checked = TriState.Unchecked;
remaining = 0; remaining = 0;
@ -122,9 +123,22 @@ window.qBittorrent.FileTree ??= (() => {
availability = 0; availability = 0;
depth = 0; depth = 0;
root = null; root = null;
data = null;
isFolder = false; isFolder = false;
children = []; children = [];
serialize() {
return {
name: this.name,
path: this.path,
fileId: this.fileId,
size: this.size,
checked: this.checked,
remaining: this.remaining,
progress: this.progress,
priority: this.priority,
availability: this.availability
};
}
} }
class FolderNode extends FileNode { class FolderNode extends FileNode {
@ -133,6 +147,7 @@ window.qBittorrent.FileTree ??= (() => {
*/ */
autoCheckFolders = true; autoCheckFolders = true;
isFolder = true; isFolder = true;
fileId = -1;
addChild(node) { addChild(node) {
this.children.push(node); this.children.push(node);

View file

@ -84,12 +84,12 @@ window.qBittorrent.TorrentContent ??= (() => {
const getAllChildren = (id, fileId) => { const getAllChildren = (id, fileId) => {
const node = torrentFilesTable.getNode(id); const node = torrentFilesTable.getNode(id);
const rowIds = [node.data.rowId]; const rowIds = [node.rowId];
const fileIds = [node.data.fileId]; const fileIds = [node.fileId];
const getChildFiles = (node) => { const getChildFiles = (node) => {
rowIds.push(node.data.rowId); rowIds.push(node.rowId);
fileIds.push(node.data.fileId); fileIds.push(node.fileId);
if (node.isFolder) { if (node.isFolder) {
node.children.forEach((child) => { node.children.forEach((child) => {
@ -214,8 +214,8 @@ window.qBittorrent.TorrentContent ??= (() => {
}; };
const getComboboxPriority = (id) => { const getComboboxPriority = (id) => {
const row = torrentFilesTable.rows.get(id.toString()); const node = torrentFilesTable.getNode(id.toString());
return normalizePriority(row.full_data.priority, 10); return normalizePriority(node.priority, 10);
}; };
const switchGlobalCheckboxState = (e) => { const switchGlobalCheckboxState = (e) => {
@ -230,8 +230,9 @@ window.qBittorrent.TorrentContent ??= (() => {
setCheckboxUnchecked(checkbox); setCheckboxUnchecked(checkbox);
torrentFilesTable.rows.forEach((row) => { torrentFilesTable.rows.forEach((row) => {
const rowId = row.rowId; const rowId = row.rowId;
const fileId = row.full_data.fileId; const node = torrentFilesTable.getNode(rowId);
const isChecked = (getCheckboxState(rowId) === TriState.Checked); const fileId = node.fileId;
const isChecked = (node.checked === TriState.Checked);
if (isChecked) { if (isChecked) {
rowIds.push(rowId); rowIds.push(rowId);
fileIds.push(fileId); fileIds.push(fileId);
@ -242,8 +243,9 @@ window.qBittorrent.TorrentContent ??= (() => {
setCheckboxChecked(checkbox); setCheckboxChecked(checkbox);
torrentFilesTable.rows.forEach((row) => { torrentFilesTable.rows.forEach((row) => {
const rowId = row.rowId; const rowId = row.rowId;
const fileId = row.full_data.fileId; const node = torrentFilesTable.getNode(rowId);
const isUnchecked = (getCheckboxState(rowId) === TriState.Unchecked); const fileId = node.fileId;
const isUnchecked = (node.checked === TriState.Unchecked);
if (isUnchecked) { if (isUnchecked) {
rowIds.push(rowId); rowIds.push(rowId);
fileIds.push(fileId); fileIds.push(fileId);
@ -285,11 +287,6 @@ window.qBittorrent.TorrentContent ??= (() => {
checkbox.indeterminate = true; checkbox.indeterminate = true;
}; };
const getCheckboxState = (id) => {
const row = torrentFilesTable.rows.get(id.toString());
return Number(row.full_data.checked);
};
const setFilePriority = (ids, fileIds, priority) => { const setFilePriority = (ids, fileIds, priority) => {
priority = normalizePriority(priority); priority = normalizePriority(priority);
@ -301,9 +298,9 @@ window.qBittorrent.TorrentContent ??= (() => {
id = id.toString(); id = id.toString();
torrentFilesTable.setIgnored(id, ignore); torrentFilesTable.setIgnored(id, ignore);
const row = torrentFilesTable.rows.get(id); const node = torrentFilesTable.getNode(id);
row.full_data.priority = priority; node.priority = priority;
row.full_data.checked = triStateFromPriority(priority); node.checked = triStateFromPriority(priority);
}); });
}; };
@ -377,6 +374,7 @@ window.qBittorrent.TorrentContent ??= (() => {
childNode.name = row.name; childNode.name = row.name;
childNode.path = row.fileName; childNode.path = row.fileName;
childNode.rowId = rowId; childNode.rowId = rowId;
childNode.fileId = row.fileId;
childNode.size = row.size; childNode.size = row.size;
childNode.checked = isChecked; childNode.checked = isChecked;
childNode.remaining = remaining; childNode.remaining = remaining;
@ -384,7 +382,6 @@ window.qBittorrent.TorrentContent ??= (() => {
childNode.priority = row.priority; childNode.priority = row.priority;
childNode.availability = row.availability; childNode.availability = row.availability;
childNode.root = parent; childNode.root = parent;
childNode.data = row;
parent.addChild(childNode); parent.addChild(childNode);
++rowId; ++rowId;
@ -447,7 +444,7 @@ window.qBittorrent.TorrentContent ??= (() => {
let indeterminateCount = 0; let indeterminateCount = 0;
let desiredComboboxPriority = null; let desiredComboboxPriority = null;
for (const sibling of siblings) { for (const sibling of siblings) {
switch (getCheckboxState(sibling.rowId)) { switch (sibling.checked) {
case TriState.Checked: case TriState.Checked:
++checkedCount; ++checkedCount;
break; break;
@ -465,7 +462,7 @@ window.qBittorrent.TorrentContent ??= (() => {
desiredComboboxPriority = FilePriority.Mixed; desiredComboboxPriority = FilePriority.Mixed;
} }
const currentCheckboxState = getCheckboxState(parent.rowId); const currentCheckboxState = parent.checked;
let desiredCheckboxState = TriState.Unchecked; let desiredCheckboxState = TriState.Unchecked;
if ((indeterminateCount > 0) || ((checkedCount > 0) && (uncheckedCount > 0))) if ((indeterminateCount > 0) || ((checkedCount > 0) && (uncheckedCount > 0)))
desiredCheckboxState = TriState.Partial; desiredCheckboxState = TriState.Partial;
@ -474,9 +471,9 @@ window.qBittorrent.TorrentContent ??= (() => {
const currentComboboxPriority = getComboboxPriority(parent.rowId); const currentComboboxPriority = getComboboxPriority(parent.rowId);
if ((currentCheckboxState !== desiredCheckboxState) || (currentComboboxPriority !== desiredComboboxPriority)) { if ((currentCheckboxState !== desiredCheckboxState) || (currentComboboxPriority !== desiredComboboxPriority)) {
const row = torrentFilesTable.rows.get(parent.rowId.toString()); const node = torrentFilesTable.getNode(parent.rowId.toString());
row.full_data.priority = desiredComboboxPriority; node.priority = desiredComboboxPriority;
row.full_data.checked = desiredCheckboxState; node.checked = desiredCheckboxState;
updateParentFolder(parent.rowId); updateParentFolder(parent.rowId);
} }