mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-20 13:23:34 -07:00
Reduce repeated logic between files tables
BulkRenameTorrentFilesTable now extends TorrentFilesTable, allowing for the removal of a lot of repeated logic.
This commit is contained in:
parent
73ab5dfeef
commit
afa92d865f
1 changed files with 50 additions and 185 deletions
|
@ -2344,13 +2344,20 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
prevSortedColumn = null;
|
prevSortedColumn = null;
|
||||||
prevReverseSort = null;
|
prevReverseSort = null;
|
||||||
fileTree = new window.qBittorrent.FileTree.FileTree();
|
fileTree = new window.qBittorrent.FileTree.FileTree();
|
||||||
|
supportCollapsing = true;
|
||||||
collapseState = new Map();
|
collapseState = new Map();
|
||||||
|
fileNameColumn = "name";
|
||||||
|
|
||||||
isCollapsed(id) {
|
isCollapsed(id) {
|
||||||
|
if (!this.supportCollapsing)
|
||||||
|
return false;
|
||||||
return this.collapseState.get(id)?.collapsed ?? false;
|
return this.collapseState.get(id)?.collapsed ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
expandNode(id) {
|
expandNode(id) {
|
||||||
|
if (!this.supportCollapsing)
|
||||||
|
return;
|
||||||
|
|
||||||
const state = this.collapseState.get(id);
|
const state = this.collapseState.get(id);
|
||||||
if (state !== undefined)
|
if (state !== undefined)
|
||||||
state.collapsed = false;
|
state.collapsed = false;
|
||||||
|
@ -2358,6 +2365,9 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
collapseNode(id) {
|
collapseNode(id) {
|
||||||
|
if (!this.supportCollapsing)
|
||||||
|
return;
|
||||||
|
|
||||||
const state = this.collapseState.get(id);
|
const state = this.collapseState.get(id);
|
||||||
if (state !== undefined)
|
if (state !== undefined)
|
||||||
state.collapsed = true;
|
state.collapsed = true;
|
||||||
|
@ -2365,11 +2375,17 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
expandAllNodes() {
|
expandAllNodes() {
|
||||||
|
if (!this.supportCollapsing)
|
||||||
|
return;
|
||||||
|
|
||||||
for (const [key, _] of this.collapseState)
|
for (const [key, _] of this.collapseState)
|
||||||
this.expandNode(key);
|
this.expandNode(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
collapseAllNodes() {
|
collapseAllNodes() {
|
||||||
|
if (!this.supportCollapsing)
|
||||||
|
return;
|
||||||
|
|
||||||
for (const [key, state] of this.collapseState) {
|
for (const [key, state] of this.collapseState) {
|
||||||
// collapse all nodes except root
|
// collapse all nodes except root
|
||||||
if (state.depth >= 1)
|
if (state.depth >= 1)
|
||||||
|
@ -2433,12 +2449,18 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
expandFolder(id) {
|
expandFolder(id) {
|
||||||
|
if (!this.supportCollapsing)
|
||||||
|
return;
|
||||||
|
|
||||||
const node = this.getNode(id);
|
const node = this.getNode(id);
|
||||||
if (node.isFolder)
|
if (node.isFolder)
|
||||||
this.expandNode(node.rowId);
|
this.expandNode(node.rowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
collapseFolder(id) {
|
collapseFolder(id) {
|
||||||
|
if (!this.supportCollapsing)
|
||||||
|
return;
|
||||||
|
|
||||||
const node = this.getNode(id);
|
const node = this.getNode(id);
|
||||||
if (node.isFolder)
|
if (node.isFolder)
|
||||||
this.collapseNode(node.rowId);
|
this.collapseNode(node.rowId);
|
||||||
|
@ -2463,7 +2485,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
node.depth = depth;
|
node.depth = depth;
|
||||||
node.parent = parent;
|
node.parent = parent;
|
||||||
|
|
||||||
if (node.isFolder && !this.collapseState.has(node.rowId))
|
if (node.isFolder && this.supportCollapsing && !this.collapseState.has(node.rowId))
|
||||||
this.collapseState.set(node.rowId, { depth: depth, collapsed: false });
|
this.collapseState.set(node.rowId, { depth: depth, collapsed: false });
|
||||||
|
|
||||||
this.updateRowData({
|
this.updateRowData({
|
||||||
|
@ -2657,7 +2679,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
#sortNodesByColumn(root, column) {
|
#sortNodesByColumn(root, column) {
|
||||||
const isColumnName = (column.name === "name");
|
const isColumnName = (column.name === this.fileNameColumn);
|
||||||
const isReverseSort = (this.reverseSort === "0");
|
const isReverseSort = (this.reverseSort === "0");
|
||||||
|
|
||||||
const stack = [root];
|
const stack = [root];
|
||||||
|
@ -2712,7 +2734,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
visited.pop();
|
visited.pop();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (window.qBittorrent.Misc.containsAllTerms(node.name, filterTerms)) {
|
if (window.qBittorrent.Misc.containsAllTerms(node[this.fileNameColumn], filterTerms)) {
|
||||||
ret.push(this.getRow(node));
|
ret.push(this.getRow(node));
|
||||||
|
|
||||||
const parent = node.root;
|
const parent = node.root;
|
||||||
|
@ -2736,18 +2758,18 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
this.filterTerms = filterTerms;
|
this.filterTerms = filterTerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateRowsSignature() {
|
||||||
|
const rowsData = [];
|
||||||
|
for (const { rowId } of this.getRowValues())
|
||||||
|
rowsData.push({ ...this.getNode(rowId).serialize(), collapsed: this.isCollapsed(rowId) });
|
||||||
|
return JSON.stringify(rowsData);
|
||||||
|
}
|
||||||
|
|
||||||
getFilteredAndSortedRows() {
|
getFilteredAndSortedRows() {
|
||||||
const root = this.getRoot();
|
const root = this.getRoot();
|
||||||
if (root === null)
|
if (root === null)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
const generateRowsSignature = () => {
|
|
||||||
const rowsData = [];
|
|
||||||
for (const { rowId } of this.getRowValues())
|
|
||||||
rowsData.push({ ...this.getNode(rowId).serialize(), collapsed: this.isCollapsed(rowId) });
|
|
||||||
return JSON.stringify(rowsData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasRowsChanged = function(rowsString, prevRowsStringString) {
|
const hasRowsChanged = function(rowsString, prevRowsStringString) {
|
||||||
const rowsChanged = (rowsString !== prevRowsStringString);
|
const rowsChanged = (rowsString !== prevRowsStringString);
|
||||||
const isFilterTermsChanged = this.filterTerms.reduce((acc, term, index) => {
|
const isFilterTermsChanged = this.filterTerms.reduce((acc, term, index) => {
|
||||||
|
@ -2761,13 +2783,21 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
return (rowsChanged || isFilterChanged || isSortedColumnChanged || isReverseSortChanged);
|
return (rowsChanged || isFilterChanged || isSortedColumnChanged || isReverseSortChanged);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
const rowsString = generateRowsSignature();
|
const rowsString = this.generateRowsSignature();
|
||||||
if (!hasRowsChanged(rowsString, this.prevRowsString))
|
if (!hasRowsChanged(rowsString, this.prevRowsString))
|
||||||
return this.prevFilteredRows;
|
return this.prevFilteredRows;
|
||||||
|
|
||||||
// sort, then filter
|
// sort, then filter
|
||||||
this.#sortNodesByColumn(root, this.columns[this.sortedColumn]);
|
this.#sortNodesByColumn(root, this.columns[this.sortedColumn]);
|
||||||
const rows = this.#filterNodes(root.children[0], this.filterTerms);
|
const rows = (() => {
|
||||||
|
if (this.filterTerms.length === 0) {
|
||||||
|
const nodeArray = this.fileTree.toArray();
|
||||||
|
const filteredRows = nodeArray.map(node => this.getRow(node));
|
||||||
|
return filteredRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.#filterNodes(root.children[0], this.filterTerms);
|
||||||
|
})();
|
||||||
|
|
||||||
this.prevFilterTerms = this.filterTerms;
|
this.prevFilterTerms = this.filterTerms;
|
||||||
this.prevRowsString = rowsString;
|
this.prevRowsString = rowsString;
|
||||||
|
@ -2798,61 +2828,18 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BulkRenameTorrentFilesTable extends DynamicTable {
|
class BulkRenameTorrentFilesTable extends TorrentFilesTable {
|
||||||
filterTerms = [];
|
|
||||||
prevFilterTerms = [];
|
|
||||||
prevRowsString = null;
|
|
||||||
prevFilteredRows = [];
|
|
||||||
prevSortedColumn = null;
|
|
||||||
prevReverseSort = null;
|
|
||||||
prevCheckboxNum = null;
|
prevCheckboxNum = null;
|
||||||
fileTree = new window.qBittorrent.FileTree.FileTree();
|
supportCollapsing = false;
|
||||||
|
fileNameColumn = "original";
|
||||||
|
|
||||||
setupVirtualList() {
|
setupVirtualList() {
|
||||||
super.setupVirtualList();
|
super.setupVirtualList();
|
||||||
this.rowHeight = 29;
|
this.rowHeight = 29;
|
||||||
}
|
}
|
||||||
|
|
||||||
populateTable(root) {
|
|
||||||
this.fileTree.setRoot(root);
|
|
||||||
root.children.forEach((node) => {
|
|
||||||
this.#addNodeToTable(node, 0, root);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#addNodeToTable(node, depth, parent) {
|
|
||||||
node.depth = depth;
|
|
||||||
node.parent = parent;
|
|
||||||
|
|
||||||
this.updateRowData({
|
|
||||||
rowId: node.rowId
|
|
||||||
});
|
|
||||||
|
|
||||||
node.children.forEach((child) => {
|
|
||||||
this.#addNodeToTable(child, depth + 1, node);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getRoot() {
|
|
||||||
return this.fileTree.getRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
getNode(rowId) {
|
|
||||||
return this.fileTree.getNode(rowId);
|
|
||||||
}
|
|
||||||
|
|
||||||
getRow(node) {
|
|
||||||
const rowId = this.fileTree.getRowId(node).toString();
|
|
||||||
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();
|
||||||
|
|
||||||
return nodes.filter(x => x.checked === 0);
|
return nodes.filter(x => x.checked === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3071,133 +3058,11 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
this.updateGlobalCheckbox();
|
this.updateGlobalCheckbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
#sortNodesByColumn(root, column) {
|
generateRowsSignature() {
|
||||||
const isColumnOriginal = (column.name === "original");
|
const rowsData = [];
|
||||||
const isReverseSort = (this.reverseSort === "0");
|
for (const { full_data } of this.getRowValues())
|
||||||
|
rowsData.push(full_data);
|
||||||
const stack = [root];
|
return JSON.stringify(rowsData);
|
||||||
while (stack.length > 0) {
|
|
||||||
const node = stack.pop();
|
|
||||||
|
|
||||||
node.children.sort((node1, node2) => {
|
|
||||||
// list folders before files when sorting by name
|
|
||||||
if (isColumnOriginal) {
|
|
||||||
if (node1.isFolder && !node2.isFolder)
|
|
||||||
return -1;
|
|
||||||
if (!node1.isFolder && node2.isFolder)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = column.compareRows(node1, node2);
|
|
||||||
return isReverseSort ? result : -result;
|
|
||||||
});
|
|
||||||
|
|
||||||
stack.push(...node.children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#filterNodes(root, filterTerms) {
|
|
||||||
const ret = [];
|
|
||||||
const stack = [root];
|
|
||||||
const visited = [];
|
|
||||||
|
|
||||||
while (stack.length > 0) {
|
|
||||||
const node = stack.at(-1);
|
|
||||||
|
|
||||||
if (node.isFolder) {
|
|
||||||
const lastVisited = visited.at(-1);
|
|
||||||
|
|
||||||
if ((visited.length <= 0) || (lastVisited !== node)) {
|
|
||||||
visited.push(node);
|
|
||||||
stack.push(...node.children);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// has children added or itself matches
|
|
||||||
if (lastVisited.has_children_added || window.qBittorrent.Misc.containsAllTerms(node.name, filterTerms)) {
|
|
||||||
ret.push(this.getRow(node));
|
|
||||||
delete node.has_children_added;
|
|
||||||
|
|
||||||
// propagate up
|
|
||||||
const parent = node.root;
|
|
||||||
if (parent !== undefined)
|
|
||||||
parent.has_children_added = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
visited.pop();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (window.qBittorrent.Misc.containsAllTerms(node.original, filterTerms)) {
|
|
||||||
ret.push(this.getRow(node));
|
|
||||||
|
|
||||||
const parent = node.root;
|
|
||||||
if (parent !== undefined)
|
|
||||||
parent.has_children_added = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.reverse();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter(text) {
|
|
||||||
const filterTerms = text.trim().toLowerCase().split(" ");
|
|
||||||
if ((filterTerms.length === 1) && (filterTerms[0] === ""))
|
|
||||||
this.filterTerms = [];
|
|
||||||
else
|
|
||||||
this.filterTerms = filterTerms;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFilteredAndSortedRows() {
|
|
||||||
const root = this.getRoot();
|
|
||||||
if (root === null)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
const generateRowsSignature = () => {
|
|
||||||
const rowsData = [];
|
|
||||||
for (const { full_data } of this.getRowValues())
|
|
||||||
rowsData.push(full_data);
|
|
||||||
return JSON.stringify(rowsData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasRowsChanged = function(rowsString, prevRowsStringString) {
|
|
||||||
const rowsChanged = (rowsString !== prevRowsStringString);
|
|
||||||
const isFilterTermsChanged = this.filterTerms.reduce((acc, term, index) => {
|
|
||||||
return (acc || (term !== this.prevFilterTerms[index]));
|
|
||||||
}, false);
|
|
||||||
const isFilterChanged = ((this.filterTerms.length !== this.prevFilterTerms.length)
|
|
||||||
|| ((this.filterTerms.length > 0) && isFilterTermsChanged));
|
|
||||||
const isSortedColumnChanged = (this.prevSortedColumn !== this.sortedColumn);
|
|
||||||
const isReverseSortChanged = (this.prevReverseSort !== this.reverseSort);
|
|
||||||
|
|
||||||
return (rowsChanged || isFilterChanged || isSortedColumnChanged || isReverseSortChanged);
|
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
const rowsString = generateRowsSignature();
|
|
||||||
if (!hasRowsChanged(rowsString, this.prevRowsString))
|
|
||||||
return this.prevFilteredRows;
|
|
||||||
|
|
||||||
// sort, then filter
|
|
||||||
this.#sortNodesByColumn(root, this.columns[this.sortedColumn]);
|
|
||||||
const rows = (() => {
|
|
||||||
if (this.filterTerms.length === 0) {
|
|
||||||
const nodeArray = this.fileTree.toArray();
|
|
||||||
const filteredRows = nodeArray.map(node => this.getRow(node));
|
|
||||||
return filteredRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.#filterNodes(root.children[0], this.filterTerms);
|
|
||||||
})();
|
|
||||||
|
|
||||||
this.prevFilterTerms = this.filterTerms;
|
|
||||||
this.prevRowsString = rowsString;
|
|
||||||
this.prevFilteredRows = rows;
|
|
||||||
this.prevSortedColumn = this.sortedColumn;
|
|
||||||
this.prevReverseSort = this.reverseSort;
|
|
||||||
return rows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupCommonEvents() {
|
setupCommonEvents() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue