WebUI: migrate away from recursion

PR #22791.
This commit is contained in:
Chocobo1 2025-05-31 17:38:05 +08:00 committed by GitHub
commit 4b07597d54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -2476,27 +2476,51 @@ window.qBittorrent.DynamicTable ??= (() => {
}); });
} }
#filterNodes(node, filterTerms, filteredRows) { #filterNodes(root, filterTerms) {
if (node.isFolder) { const ret = [];
const childAdded = node.children.reduce((acc, child) => { const stack = [root];
// we must execute the function before ORing w/ acc or we'll stop checking child nodes after the first successful match const visited = [];
return (this.#filterNodes(child, filterTerms, filteredRows) || acc);
}, false);
if (childAdded) { while (stack.length > 0) {
const row = this.getRow(node); const node = stack.at(-1);
filteredRows.push(row);
return true; 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();
} }
if (window.qBittorrent.Misc.containsAllTerms(node.original, filterTerms)) { ret.reverse();
const row = this.getRow(node); return ret;
filteredRows.push(row);
return true;
}
return false;
} }
setFilter(text) { setFilter(text) {
@ -2518,22 +2542,15 @@ window.qBittorrent.DynamicTable ??= (() => {
return JSON.stringify(rowsData); return JSON.stringify(rowsData);
}; };
const getFilteredRows = function() { const getFilteredRows = () => {
if (this.filterTerms.length === 0) { if (this.filterTerms.length === 0) {
const nodeArray = this.fileTree.toArray(); const nodeArray = this.fileTree.toArray();
const filteredRows = nodeArray.map((node) => { const filteredRows = nodeArray.map(node => this.getRow(node));
return this.getRow(node);
});
return filteredRows; return filteredRows;
} }
const filteredRows = []; return this.#filterNodes(this.getRoot().children[0], this.filterTerms);
this.getRoot().children.each((child) => { };
this.#filterNodes(child, this.filterTerms, filteredRows);
});
filteredRows.reverse();
return filteredRows;
}.bind(this);
const hasRowsChanged = function(rowsString, prevRowsStringString) { const hasRowsChanged = function(rowsString, prevRowsStringString) {
const rowsChanged = (rowsString !== prevRowsStringString); const rowsChanged = (rowsString !== prevRowsStringString);
@ -2922,27 +2939,51 @@ window.qBittorrent.DynamicTable ??= (() => {
}); });
} }
#filterNodes(node, filterTerms, filteredRows) { #filterNodes(root, filterTerms) {
if (node.isFolder && (!this.useVirtualList || !this.isCollapsed(node.rowId))) { const ret = [];
const childAdded = node.children.toReversed().reduce((acc, child) => { const stack = [root];
// we must execute the function before ORing w/ acc or we'll stop checking child nodes after the first successful match const visited = [];
return (this.#filterNodes(child, filterTerms, filteredRows) || acc);
}, false);
if (childAdded) { while (stack.length > 0) {
const row = this.getRow(node); const node = stack.at(-1);
filteredRows.push(row);
return true; if (node.isFolder && (!this.useVirtualList || !this.isCollapsed(node.rowId))) {
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.name, filterTerms)) {
ret.push(this.getRow(node));
const parent = node.root;
if (parent !== undefined)
parent.has_children_added = true;
}
}
stack.pop();
} }
if (window.qBittorrent.Misc.containsAllTerms(node.name, filterTerms)) { ret.reverse();
const row = this.getRow(node); return ret;
filteredRows.push(row);
return true;
}
return false;
} }
setFilter(text) { setFilter(text) {
@ -2964,14 +3005,7 @@ window.qBittorrent.DynamicTable ??= (() => {
return JSON.stringify(rowsData); return JSON.stringify(rowsData);
}; };
const getFilteredRows = function() { const getFilteredRows = () => this.#filterNodes(this.getRoot().children[0], this.filterTerms);
const filteredRows = [];
this.getRoot().children.each((child) => {
this.#filterNodes(child, this.filterTerms, filteredRows);
});
filteredRows.reverse();
return filteredRows;
}.bind(this);
const hasRowsChanged = function(rowsString, prevRowsStringString) { const hasRowsChanged = function(rowsString, prevRowsStringString) {
const rowsChanged = (rowsString !== prevRowsStringString); const rowsChanged = (rowsString !== prevRowsStringString);