diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index aacdb5f5d..3fb778c22 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -993,9 +993,13 @@ window.qBittorrent.DynamicTable ??= (() => { } } + getRowData(row, fullUpdate) { + return row[fullUpdate ? "full_data" : "data"]; + } + updateRow(tr, fullUpdate) { 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); 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))) this.columns[i].updateTd(tds[i], row); } - row["data"] = {}; + row.data = {}; } removeRow(rowId) { @@ -2358,25 +2362,9 @@ window.qBittorrent.DynamicTable ??= (() => { node.depth = depth; node.parent = parent; - if (node.isFolder) { - const data = { - 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); - } + this.updateRowData({ + rowId: node.rowId + }); node.children.each((child) => { this.#addNodeToTable(child, depth + 1, node); @@ -2396,6 +2384,10 @@ window.qBittorrent.DynamicTable ??= (() => { return this.rows.get(rowId); } + getRowData(row, fullUpdate) { + return this.getNode(row.rowId); + } + getSelectedRows() { const nodes = this.fileTree.toArray(); @@ -2437,10 +2429,8 @@ window.qBittorrent.DynamicTable ??= (() => { } const nodes = this.fileTree.toArray(); - for (const node of nodes) { + for (const node of nodes) node.checked = (checkbox.checked || checkbox.indeterminate) ? 0 : 1; - node.full_data.checked = node.checked; - } this.updateGlobalCheckbox(); } @@ -2448,7 +2438,6 @@ window.qBittorrent.DynamicTable ??= (() => { toggleNodeTreeCheckbox(rowId, checkState) { const node = this.getNode(rowId); node.checked = checkState; - node.full_data.checked = checkState; const checkbox = document.getElementById(`cbRename${rowId}`); checkbox.checked = node.checked === 0; checkbox.state = checkbox.checked ? "checked" : "unchecked"; @@ -2530,7 +2519,6 @@ window.qBittorrent.DynamicTable ??= (() => { for (const id of ids) { const node = that.getNode(id); node.checked = e.target.checked ? 0 : 1; - node.full_data.checked = node.checked; } that.updateGlobalCheckbox(); that.onRowSelectionChange(that.getNode(targetId)); @@ -2592,6 +2580,13 @@ window.qBittorrent.DynamicTable ??= (() => { span.id = fileNameRenamedId; 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) {} @@ -2604,7 +2599,6 @@ window.qBittorrent.DynamicTable ??= (() => { if (rowIds.includes(tr.rowId)) { const node = this.getNode(tr.rowId); node.checked = 0; - node.full_data.checked = 0; const checkbox = tr.querySelector(".RenamingCB"); checkbox.state = "checked"; @@ -2623,18 +2617,16 @@ window.qBittorrent.DynamicTable ??= (() => { while (stack.length > 0) { const node = stack.pop(); - node.children.sort((row1, row2) => { + node.children.sort((node1, node2) => { // list folders before files when sorting by name if (isColumnOriginal) { - const node1 = this.getNode(row1.data.rowId); - const node2 = this.getNode(row2.data.rowId); if (node1.isFolder && !node2.isFolder) return -1; if (!node1.isFolder && node2.isFolder) return 1; } - const result = column.compareRows(row1, row2); + const result = column.compareRows(node1, node2); return isReverseSort ? result : -result; }); @@ -2746,14 +2738,6 @@ window.qBittorrent.DynamicTable ??= (() => { 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() { const headerDiv = document.getElementById("bulkRenameFilesTableFixedHeaderDiv"); this.dynamicTableDiv.addEventListener("scroll", (e) => { @@ -2876,11 +2860,11 @@ window.qBittorrent.DynamicTable ??= (() => { } isAllCheckboxesChecked() { - return this.fileTree.toArray().every((node) => node.checked === 1); + return this.fileTree.toArray().every((node) => node.checked === window.qBittorrent.FileTree.TriState.Checked); } 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) { @@ -2894,30 +2878,12 @@ window.qBittorrent.DynamicTable ??= (() => { node.depth = depth; node.parent = parent; - if (node.isFolder) { - if (!this.collapseState.has(node.rowId)) - 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 - }; + if (node.isFolder && !this.collapseState.has(node.rowId)) + this.collapseState.set(node.rowId, { depth: depth, collapsed: false }); - node.data = data; - node.full_data = data; - this.updateRowData(data, depth); - } - else { - node.data.rowId = node.rowId; - node.full_data = node.data; - this.updateRowData(node.data); - } + this.updateRowData({ + rowId: node.rowId, + }); node.children.each((child) => { this.#addNodeToTable(child, depth + 1, node); @@ -2938,8 +2904,12 @@ window.qBittorrent.DynamicTable ??= (() => { } getRowFileId(rowId) { - const row = this.rows.get(rowId); - return row?.full_data.fileId; + const node = this.getNode(rowId); + return node.fileId; + } + + getRowData(row, fullUpdate) { + return this.getNode(row.rowId); } initColumns() { @@ -2971,6 +2941,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["checked"].updateTd = function(td, row) { const id = row.rowId; const value = this.getRowValue(row); + const fileId = that.getRowFileId(id); if (td.firstElementChild === null) { const treeImg = document.createElement("img"); @@ -2981,9 +2952,9 @@ window.qBittorrent.DynamicTable ??= (() => { const downloadCheckbox = td.children[1]; 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 - window.qBittorrent.TorrentContent.updateDownloadCheckbox(downloadCheckbox, id, row.full_data.fileId, value); + window.qBittorrent.TorrentContent.updateDownloadCheckbox(downloadCheckbox, id, fileId, value); }; this.columns["checked"].staticWidth = 50; @@ -3072,12 +3043,13 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["priority"].updateTd = function(td, row) { const id = row.rowId; const value = this.getRowValue(row); + const fileId = that.getRowFileId(id); const priorityCombo = td.firstElementChild; 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 - window.qBittorrent.TorrentContent.updatePriorityCombo(priorityCombo, id, row.full_data.fileId, value); + window.qBittorrent.TorrentContent.updatePriorityCombo(priorityCombo, id, fileId, value); }; this.columns["priority"].staticWidth = 140; @@ -3086,6 +3058,13 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["remaining"].updateTd = displaySize; if (this.columns["availability"] !== undefined) 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) { @@ -3096,18 +3075,16 @@ window.qBittorrent.DynamicTable ??= (() => { while (stack.length > 0) { const node = stack.pop(); - node.children.sort((row1, row2) => { + node.children.sort((node1, node2) => { // list folders before files when sorting by name if (isColumnName) { - const node1 = this.getNode(row1.data.rowId); - const node2 = this.getNode(row2.data.rowId); if (node1.isFolder && !node2.isFolder) return -1; if (!node1.isFolder && node2.isFolder) return 1; } - const result = column.compareRows(row1, row2); + const result = column.compareRows(node1, node2); return isReverseSort ? result : -result; }); @@ -3177,8 +3154,8 @@ window.qBittorrent.DynamicTable ??= (() => { const generateRowsSignature = () => { const rowsData = []; - for (const { full_data } of this.getRowValues()) - rowsData.push({ ...full_data, collapsed: this.isCollapsed(full_data.rowId) }); + for (const { rowId } of this.getRowValues()) + rowsData.push({ ...this.getNode(rowId).serialize(), collapsed: this.isCollapsed(rowId) }); return JSON.stringify(rowsData); }; @@ -3212,11 +3189,11 @@ window.qBittorrent.DynamicTable ??= (() => { } setIgnored(rowId, ignore) { - const row = this.rows.get(rowId.toString()); + const node = this.getNode(rowId.toString()); if (ignore) - row.full_data.remaining = 0; + node.remaining = 0; 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() { diff --git a/src/webui/www/private/scripts/file-tree.js b/src/webui/www/private/scripts/file-tree.js index c56ddeaef..13bbf0488 100644 --- a/src/webui/www/private/scripts/file-tree.js +++ b/src/webui/www/private/scripts/file-tree.js @@ -114,6 +114,7 @@ window.qBittorrent.FileTree ??= (() => { name = ""; path = ""; rowId = null; + fileId = null; size = 0; checked = TriState.Unchecked; remaining = 0; @@ -122,9 +123,22 @@ window.qBittorrent.FileTree ??= (() => { availability = 0; depth = 0; root = null; - data = null; isFolder = false; 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 { @@ -133,6 +147,7 @@ window.qBittorrent.FileTree ??= (() => { */ autoCheckFolders = true; isFolder = true; + fileId = -1; addChild(node) { this.children.push(node); diff --git a/src/webui/www/private/scripts/torrent-content.js b/src/webui/www/private/scripts/torrent-content.js index 8e3431579..932b4ab94 100644 --- a/src/webui/www/private/scripts/torrent-content.js +++ b/src/webui/www/private/scripts/torrent-content.js @@ -84,12 +84,12 @@ window.qBittorrent.TorrentContent ??= (() => { const getAllChildren = (id, fileId) => { const node = torrentFilesTable.getNode(id); - const rowIds = [node.data.rowId]; - const fileIds = [node.data.fileId]; + const rowIds = [node.rowId]; + const fileIds = [node.fileId]; const getChildFiles = (node) => { - rowIds.push(node.data.rowId); - fileIds.push(node.data.fileId); + rowIds.push(node.rowId); + fileIds.push(node.fileId); if (node.isFolder) { node.children.forEach((child) => { @@ -214,8 +214,8 @@ window.qBittorrent.TorrentContent ??= (() => { }; const getComboboxPriority = (id) => { - const row = torrentFilesTable.rows.get(id.toString()); - return normalizePriority(row.full_data.priority, 10); + const node = torrentFilesTable.getNode(id.toString()); + return normalizePriority(node.priority, 10); }; const switchGlobalCheckboxState = (e) => { @@ -230,8 +230,9 @@ window.qBittorrent.TorrentContent ??= (() => { setCheckboxUnchecked(checkbox); torrentFilesTable.rows.forEach((row) => { const rowId = row.rowId; - const fileId = row.full_data.fileId; - const isChecked = (getCheckboxState(rowId) === TriState.Checked); + const node = torrentFilesTable.getNode(rowId); + const fileId = node.fileId; + const isChecked = (node.checked === TriState.Checked); if (isChecked) { rowIds.push(rowId); fileIds.push(fileId); @@ -242,8 +243,9 @@ window.qBittorrent.TorrentContent ??= (() => { setCheckboxChecked(checkbox); torrentFilesTable.rows.forEach((row) => { const rowId = row.rowId; - const fileId = row.full_data.fileId; - const isUnchecked = (getCheckboxState(rowId) === TriState.Unchecked); + const node = torrentFilesTable.getNode(rowId); + const fileId = node.fileId; + const isUnchecked = (node.checked === TriState.Unchecked); if (isUnchecked) { rowIds.push(rowId); fileIds.push(fileId); @@ -285,11 +287,6 @@ window.qBittorrent.TorrentContent ??= (() => { checkbox.indeterminate = true; }; - const getCheckboxState = (id) => { - const row = torrentFilesTable.rows.get(id.toString()); - return Number(row.full_data.checked); - }; - const setFilePriority = (ids, fileIds, priority) => { priority = normalizePriority(priority); @@ -301,9 +298,9 @@ window.qBittorrent.TorrentContent ??= (() => { id = id.toString(); torrentFilesTable.setIgnored(id, ignore); - const row = torrentFilesTable.rows.get(id); - row.full_data.priority = priority; - row.full_data.checked = triStateFromPriority(priority); + const node = torrentFilesTable.getNode(id); + node.priority = priority; + node.checked = triStateFromPriority(priority); }); }; @@ -377,6 +374,7 @@ window.qBittorrent.TorrentContent ??= (() => { childNode.name = row.name; childNode.path = row.fileName; childNode.rowId = rowId; + childNode.fileId = row.fileId; childNode.size = row.size; childNode.checked = isChecked; childNode.remaining = remaining; @@ -384,7 +382,6 @@ window.qBittorrent.TorrentContent ??= (() => { childNode.priority = row.priority; childNode.availability = row.availability; childNode.root = parent; - childNode.data = row; parent.addChild(childNode); ++rowId; @@ -447,7 +444,7 @@ window.qBittorrent.TorrentContent ??= (() => { let indeterminateCount = 0; let desiredComboboxPriority = null; for (const sibling of siblings) { - switch (getCheckboxState(sibling.rowId)) { + switch (sibling.checked) { case TriState.Checked: ++checkedCount; break; @@ -465,7 +462,7 @@ window.qBittorrent.TorrentContent ??= (() => { desiredComboboxPriority = FilePriority.Mixed; } - const currentCheckboxState = getCheckboxState(parent.rowId); + const currentCheckboxState = parent.checked; let desiredCheckboxState = TriState.Unchecked; if ((indeterminateCount > 0) || ((checkedCount > 0) && (uncheckedCount > 0))) desiredCheckboxState = TriState.Partial; @@ -474,9 +471,9 @@ window.qBittorrent.TorrentContent ??= (() => { const currentComboboxPriority = getComboboxPriority(parent.rowId); if ((currentCheckboxState !== desiredCheckboxState) || (currentComboboxPriority !== desiredComboboxPriority)) { - const row = torrentFilesTable.rows.get(parent.rowId.toString()); - row.full_data.priority = desiredComboboxPriority; - row.full_data.checked = desiredCheckboxState; + const node = torrentFilesTable.getNode(parent.rowId.toString()); + node.priority = desiredComboboxPriority; + node.checked = desiredCheckboxState; updateParentFolder(parent.rowId); }