diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index 4357ded37..c48c8542a 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -483,9 +483,8 @@ window.addEventListener("DOMContentLoaded", () => { } }; - const all = torrentsTable.rows.size; let uncategorized = 0; - for (const { full_data: { category } } of torrentsTable.rows.values()) { + for (const { full_data: { category } } of torrentsTable.getRowValues()) { if (category.length === 0) uncategorized += 1; } @@ -517,7 +516,7 @@ window.addEventListener("DOMContentLoaded", () => { }); const categoriesFragment = new DocumentFragment(); - categoriesFragment.appendChild(createCategoryLink(CATEGORIES_ALL, "QBT_TR(All)QBT_TR[CONTEXT=CategoryFilterModel]", all)); + categoriesFragment.appendChild(createCategoryLink(CATEGORIES_ALL, "QBT_TR(All)QBT_TR[CONTEXT=CategoryFilterModel]", torrentsTable.getRowSize())); categoriesFragment.appendChild(createCategoryLink(CATEGORIES_UNCATEGORIZED, "QBT_TR(Uncategorized)QBT_TR[CONTEXT=CategoryFilterModel]", uncategorized)); if (useSubcategories) { @@ -581,14 +580,13 @@ window.addEventListener("DOMContentLoaded", () => { return tagFilterItem; }; - const torrentsCount = torrentsTable.rows.size; let untagged = 0; - for (const { full_data: { tags } } of torrentsTable.rows.values()) { + for (const { full_data: { tags } } of torrentsTable.getRowValues()) { if (tags.length === 0) untagged += 1; } - tagFilterList.appendChild(createLink(TAGS_ALL, "QBT_TR(All)QBT_TR[CONTEXT=TagFilterModel]", torrentsCount)); + tagFilterList.appendChild(createLink(TAGS_ALL, "QBT_TR(All)QBT_TR[CONTEXT=TagFilterModel]", torrentsTable.getRowSize())); tagFilterList.appendChild(createLink(TAGS_UNTAGGED, "QBT_TR(Untagged)QBT_TR[CONTEXT=TagFilterModel]", untagged)); const sortedTags = []; @@ -634,14 +632,13 @@ window.addEventListener("DOMContentLoaded", () => { return trackerFilterItem; }; - const torrentsCount = torrentsTable.rows.size; let trackerlessTorrentsCount = 0; - for (const { full_data: { trackers_count: trackersCount } } of torrentsTable.rows.values()) { + for (const { full_data: { trackers_count: trackersCount } } of torrentsTable.getRowValues()) { if (trackersCount === 0) trackerlessTorrentsCount += 1; } - trackerFilterList.appendChild(createLink(TRACKERS_ALL, "QBT_TR(All (%1))QBT_TR[CONTEXT=TrackerFiltersList]", torrentsCount)); + trackerFilterList.appendChild(createLink(TRACKERS_ALL, "QBT_TR(All (%1))QBT_TR[CONTEXT=TrackerFiltersList]", torrentsTable.getRowSize())); trackerFilterList.appendChild(createLink(TRACKERS_TRACKERLESS, "QBT_TR(Trackerless (%1))QBT_TR[CONTEXT=TrackerFiltersList]", trackerlessTorrentsCount)); // Remove unused trackers diff --git a/src/webui/www/private/scripts/contextmenu.js b/src/webui/www/private/scripts/contextmenu.js index e6ac92cfe..2b6891394 100644 --- a/src/webui/www/private/scripts/contextmenu.js +++ b/src/webui/www/private/scripts/contextmenu.js @@ -323,7 +323,7 @@ window.qBittorrent.ContextMenu ??= (() => { const selectedRows = torrentsTable.selectedRowsIds(); selectedRows.forEach((item, index) => { - const data = torrentsTable.rows.get(item).full_data; + const data = torrentsTable.getRow(item).full_data; if (data["seq_dl"] !== true) all_are_seq_dl = false; @@ -374,7 +374,7 @@ window.qBittorrent.ContextMenu ??= (() => { // hide renameFiles when more than 1 torrent is selected if (selectedRows.length === 1) { - const data = torrentsTable.rows.get(selectedRows[0]).full_data; + const data = torrentsTable.getRow(selectedRows[0]).full_data; const metadata_downloaded = !((data["state"] === "metaDL") || (data["state"] === "forcedMetaDL") || (data["total_size"] === -1)); // hide renameFiles when metadata hasn't been downloaded yet @@ -655,7 +655,7 @@ window.qBittorrent.ContextMenu ??= (() => { this.hideItem("copyFeedURL"); break; case 1: - if (selectedRows[0] === 0) { + if (selectedRows[0] === "0") { // menu when "unread" feed selected this.showItem("update"); this.showItem("markRead"); @@ -666,7 +666,7 @@ window.qBittorrent.ContextMenu ??= (() => { this.hideItem("updateAll"); this.hideItem("copyFeedURL"); } - else if (window.qBittorrent.Rss.rssFeedTable.rows[selectedRows[0]].full_data.dataUid === "") { + else if (window.qBittorrent.Rss.rssFeedTable.getRow(selectedRows[0]).full_data.dataUid === "") { // menu when single folder selected this.showItem("update"); this.showItem("markRead"); diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 0ed2fbdb7..be2c70518 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -76,7 +76,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.fixedTableHeader = $(dynamicTableFixedHeaderDivId).getElements("tr")[0]; this.hiddenTableHeader = $(dynamicTableDivId).getElements("tr")[0]; this.tableBody = $(dynamicTableDivId).getElements("tbody")[0]; - this.rows = new Hash(); + this.rows = new Map(); this.selectedRows = []; this.columns = []; this.contextMenu = contextMenu; @@ -665,11 +665,9 @@ window.qBittorrent.DynamicTable ??= (() => { getFilteredAndSortedRows: function() { const filteredRows = []; - const rows = this.rows.getValues(); - - for (let i = 0; i < rows.length; ++i) { - filteredRows.push(rows[i]); - filteredRows[rows[i].rowId] = rows[i]; + for (const row of this.getRowValues()) { + filteredRows.push(row); + filteredRows[row.rowId] = row; } filteredRows.sort((row1, row2) => { @@ -828,16 +826,14 @@ window.qBittorrent.DynamicTable ??= (() => { removeRow: function(rowId) { this.selectedRows.erase(rowId); - if (this.rows.has(rowId)) - this.rows.erase(rowId); + this.rows.delete(rowId); const tr = this.getTrByRowId(rowId); - if (tr !== null) - tr.destroy(); + tr?.destroy(); }, clear: function() { this.deselectAll(); - this.rows.empty(); + this.rows.clear(); const trs = this.tableBody.getElements("tr"); while (trs.length > 0) trs.pop().destroy(); @@ -848,7 +844,19 @@ window.qBittorrent.DynamicTable ??= (() => { }, getRowIds: function() { - return this.rows.getKeys(); + return this.rows.keys(); + }, + + getRowValues: function() { + return this.rows.values(); + }, + + getRowItems: function() { + return this.rows.entries(); + }, + + getRowSize: function() { + return this.rows.size; }, selectNextRow: function() { @@ -899,11 +907,6 @@ window.qBittorrent.DynamicTable ??= (() => { const TorrentsTable = new Class({ Extends: DynamicTable, - setup: function(dynamicTableDivId, dynamicTableFixedHeaderDivId, contextMenu) { - this.parent(dynamicTableDivId, dynamicTableFixedHeaderDivId, contextMenu); - this.rows = new Map(); - }, - initColumns: function() { this.newColumn("priority", "", "#", 30, true); this.newColumn("state_icon", "cursor: default", "", 22, true); @@ -1510,25 +1513,6 @@ window.qBittorrent.DynamicTable ??= (() => { return true; }, - removeRow: function(rowId) { - this.selectedRows.erase(rowId); - this.rows.delete(rowId); - const tr = this.getTrByRowId(rowId); - tr?.destroy(); - }, - - clear: function() { - this.deselectAll(); - this.rows.clear(); - const trs = this.tableBody.getElements("tr"); - while (trs.length > 0) - trs.pop().destroy(); - }, - - getRowIds: function() { - return this.rows.keys(); - }, - getFilteredTorrentsNumber: function(filterName, categoryHash, tagHash, trackerHash) { let cnt = 0; @@ -1809,7 +1793,6 @@ window.qBittorrent.DynamicTable ??= (() => { }; let filteredRows = []; - const rows = this.rows.getValues(); const searchTerms = window.qBittorrent.Search.searchText.pattern.toLowerCase().split(" "); const filterTerms = window.qBittorrent.Search.searchText.filterPattern.toLowerCase().split(" "); const sizeFilters = getSizeFilters(); @@ -1817,8 +1800,7 @@ window.qBittorrent.DynamicTable ??= (() => { const searchInTorrentName = $("searchInTorrentName").value === "names"; if (searchInTorrentName || (filterTerms.length > 0) || (window.qBittorrent.Search.searchSizeFilter.min > 0.00) || (window.qBittorrent.Search.searchSizeFilter.max > 0.00)) { - for (let i = 0; i < rows.length; ++i) { - const row = rows[i]; + for (const row of this.getRowValues()) { if (searchInTorrentName && !window.qBittorrent.Misc.containsAllTerms(row.full_data.fileName, searchTerms)) continue; @@ -1837,7 +1819,7 @@ window.qBittorrent.DynamicTable ??= (() => { } } else { - filteredRows = rows; + filteredRows = [...this.getRowValues()]; } filteredRows.sort((row1, row2) => { @@ -1962,7 +1944,7 @@ window.qBittorrent.DynamicTable ??= (() => { }, getRow: function(node) { - const rowId = this.fileTree.getRowId(node); + const rowId = this.fileTree.getRowId(node).toString(); return this.rows.get(rowId); }, @@ -2234,10 +2216,10 @@ window.qBittorrent.DynamicTable ??= (() => { if (this.getRoot() === null) return []; - const generateRowsSignature = function(rows) { - const rowsData = rows.map((row) => { - return row.full_data; - }); + const generateRowsSignature = () => { + const rowsData = []; + for (const { full_data } of this.getRowValues()) + rowsData.push(full_data); return JSON.stringify(rowsData); }; @@ -2271,7 +2253,7 @@ window.qBittorrent.DynamicTable ??= (() => { return (rowsChanged || isFilterChanged || isSortedColumnChanged || isReverseSortChanged); }.bind(this); - const rowsString = generateRowsSignature(this.rows); + const rowsString = generateRowsSignature(); if (!hasRowsChanged(rowsString, this.prevRowsString)) return this.prevFilteredRows; @@ -2368,7 +2350,7 @@ window.qBittorrent.DynamicTable ??= (() => { }, getRow: function(node) { - const rowId = this.fileTree.getRowId(node); + const rowId = this.fileTree.getRowId(node).toString(); return this.rows.get(rowId); }, @@ -2563,10 +2545,10 @@ window.qBittorrent.DynamicTable ??= (() => { if (this.getRoot() === null) return []; - const generateRowsSignature = function(rows) { - const rowsData = rows.map((row) => { - return row.full_data; - }); + const generateRowsSignature = () => { + const rowsData = []; + for (const { full_data } of this.getRowValues()) + rowsData.push(full_data); return JSON.stringify(rowsData); }; @@ -2600,7 +2582,7 @@ window.qBittorrent.DynamicTable ??= (() => { return (rowsChanged || isFilterChanged || isSortedColumnChanged || isReverseSortChanged); }.bind(this); - const rowsString = generateRowsSignature(this.rows); + const rowsString = generateRowsSignature(); if (!hasRowsChanged(rowsString, this.prevRowsString)) return this.prevFilteredRows; @@ -2618,7 +2600,7 @@ window.qBittorrent.DynamicTable ??= (() => { }, setIgnored: function(rowId, ignore) { - const row = this.rows.get(rowId); + const row = this.rows.get(rowId.toString()); if (ignore) row.full_data.remaining = 0; else @@ -2660,18 +2642,17 @@ window.qBittorrent.DynamicTable ??= (() => { setupHeaderMenu: function() {}, setupHeaderEvents: function() {}, getFilteredAndSortedRows: function() { - return this.rows.getValues(); + return [...this.getRowValues()]; }, selectRow: function(rowId) { this.selectedRows.push(rowId); this.setRowClass(); this.onSelectedRowChanged(); - const rows = this.rows.getValues(); let path = ""; - for (let i = 0; i < rows.length; ++i) { - if (rows[i].rowId === rowId) { - path = rows[i].full_data.dataPath; + for (const row of this.getRowValues()) { + if (row.rowId === rowId) { + path = row.full_data.dataPath; break; } } @@ -2702,7 +2683,7 @@ window.qBittorrent.DynamicTable ??= (() => { }, updateIcons: function() { // state_icon - this.rows.each(row => { + for (const row of this.getRowValues()) { let img_path; switch (row.full_data.status) { case "default": @@ -2743,7 +2724,7 @@ window.qBittorrent.DynamicTable ??= (() => { "width": "22px" })); } - }); + }; }, newColumn: function(name, style, caption, defaultWidth, defaultVisible) { const column = {}; @@ -2791,21 +2772,20 @@ window.qBittorrent.DynamicTable ??= (() => { setupHeaderMenu: function() {}, setupHeaderEvents: function() {}, getFilteredAndSortedRows: function() { - return this.rows.getValues(); + return [...this.getRowValues()]; }, selectRow: function(rowId) { this.selectedRows.push(rowId); this.setRowClass(); this.onSelectedRowChanged(); - const rows = this.rows.getValues(); let articleId = ""; let feedUid = ""; - for (let i = 0; i < rows.length; ++i) { - if (rows[i].rowId === rowId) { - articleId = rows[i].full_data.dataId; - feedUid = rows[i].full_data.feedUid; - this.tableBody.rows[rows[i].rowId].removeClass("unreadArticle"); + for (const row of this.getRowValues()) { + if (row.rowId === rowId) { + articleId = row.full_data.dataId; + feedUid = row.full_data.feedUid; + this.tableBody.rows[row.rowId].removeClass("unreadArticle"); break; } } @@ -2903,7 +2883,7 @@ window.qBittorrent.DynamicTable ??= (() => { setupHeaderMenu: function() {}, setupHeaderEvents: function() {}, getFilteredAndSortedRows: function() { - return this.rows.getValues(); + return [...this.getRowValues()]; }, setupTr: function(tr) { tr.addEventListener("dblclick", function(e) { @@ -2952,11 +2932,10 @@ window.qBittorrent.DynamicTable ??= (() => { this.setRowClass(); this.onSelectedRowChanged(); - const rows = this.rows.getValues(); let name = ""; - for (let i = 0; i < rows.length; ++i) { - if (rows[i].rowId === rowId) { - name = rows[i].full_data.name; + for (const row of this.getRowValues()) { + if (row.rowId === rowId) { + name = row.full_data.name; break; } } @@ -2995,7 +2974,7 @@ window.qBittorrent.DynamicTable ??= (() => { setupHeaderMenu: function() {}, setupHeaderEvents: function() {}, getFilteredAndSortedRows: function() { - return this.rows.getValues(); + return [...this.getRowValues()]; }, newColumn: function(name, style, caption, defaultWidth, defaultVisible) { const column = {}; @@ -3044,7 +3023,7 @@ window.qBittorrent.DynamicTable ??= (() => { setupHeaderMenu: function() {}, setupHeaderEvents: function() {}, getFilteredAndSortedRows: function() { - return this.rows.getValues(); + return [...this.getRowValues()]; }, newColumn: function(name, style, caption, defaultWidth, defaultVisible) { const column = {}; @@ -3160,23 +3139,22 @@ window.qBittorrent.DynamicTable ??= (() => { getFilteredAndSortedRows: function() { let filteredRows = []; - const rows = this.rows.getValues(); this.filterText = window.qBittorrent.Log.getFilterText(); const filterTerms = (this.filterText.length > 0) ? this.filterText.toLowerCase().split(" ") : []; const logLevels = window.qBittorrent.Log.getSelectedLevels(); if ((filterTerms.length > 0) || (logLevels.length < 4)) { - for (let i = 0; i < rows.length; ++i) { - if (!logLevels.includes(rows[i].full_data.type.toString())) + for (const row of this.getRowValues()) { + if (!logLevels.includes(row.full_data.type.toString())) continue; - if ((filterTerms.length > 0) && !window.qBittorrent.Misc.containsAllTerms(rows[i].full_data.message, filterTerms)) + if ((filterTerms.length > 0) && !window.qBittorrent.Misc.containsAllTerms(row.full_data.message, filterTerms)) continue; - filteredRows.push(rows[i]); + filteredRows.push(row); } } else { - filteredRows = rows; + filteredRows = [...this.getRowValues()]; } filteredRows.sort((row1, row2) => { @@ -3227,19 +3205,18 @@ window.qBittorrent.DynamicTable ??= (() => { getFilteredAndSortedRows: function() { let filteredRows = []; - const rows = this.rows.getValues(); this.filterText = window.qBittorrent.Log.getFilterText(); const filterTerms = (this.filterText.length > 0) ? this.filterText.toLowerCase().split(" ") : []; if (filterTerms.length > 0) { - for (let i = 0; i < rows.length; ++i) { - if ((filterTerms.length > 0) && !window.qBittorrent.Misc.containsAllTerms(rows[i].full_data.ip, filterTerms)) + for (const row of this.getRowValues()) { + if ((filterTerms.length > 0) && !window.qBittorrent.Misc.containsAllTerms(row.full_data.ip, filterTerms)) continue; - filteredRows.push(rows[i]); + filteredRows.push(row); } } else { - filteredRows = rows; + filteredRows = [...this.getRowValues()]; } filteredRows.sort((row1, row2) => { diff --git a/src/webui/www/private/scripts/mocha-init.js b/src/webui/www/private/scripts/mocha-init.js index 337f704c5..362e28e1d 100644 --- a/src/webui/www/private/scripts/mocha-init.js +++ b/src/webui/www/private/scripts/mocha-init.js @@ -310,7 +310,7 @@ const initializeWindows = function() { // check if all selected torrents have same share ratio for (let i = 0; i < hashes.length; ++i) { const hash = hashes[i]; - const row = torrentsTable.rows.get(hash).full_data; + const row = torrentsTable.getRow(hash).full_data; const origValues = row.ratio_limit + "|" + row.seeding_time_limit + "|" + row.inactive_seeding_time_limit + "|" + row.max_ratio + "|" + row.max_seeding_time + "|" + row.max_inactive_seeding_time; @@ -537,7 +537,7 @@ const initializeWindows = function() { if (hashes.length) { let enable = false; hashes.each((hash, index) => { - const row = torrentsTable.rows.get(hash); + const row = torrentsTable.getRow(hash); if (!row.full_data.auto_tmm) enable = true; }); @@ -601,7 +601,7 @@ const initializeWindows = function() { const hashes = torrentsTable.selectedRowsIds(); if (hashes.length) { const hash = hashes[0]; - const row = torrentsTable.rows.get(hash); + const row = torrentsTable.getRow(hash); new MochaUI.Window({ id: "setLocationPage", @@ -624,7 +624,7 @@ const initializeWindows = function() { const hashes = torrentsTable.selectedRowsIds(); if (hashes.length === 1) { const hash = hashes[0]; - const row = torrentsTable.rows.get(hash); + const row = torrentsTable.getRow(hash); if (row) { new MochaUI.Window({ id: "renamePage", @@ -648,7 +648,7 @@ const initializeWindows = function() { const hashes = torrentsTable.selectedRowsIds(); if (hashes.length === 1) { const hash = hashes[0]; - const row = torrentsTable.rows.get(hash); + const row = torrentsTable.getRow(hash); if (row) { new MochaUI.Window({ id: "multiRenamePage", @@ -1265,7 +1265,7 @@ const initializeWindows = function() { exportTorrentFN = async function() { const hashes = torrentsTable.selectedRowsIds(); for (const hash of hashes) { - const row = torrentsTable.rows.get(hash); + const row = torrentsTable.getRow(hash); if (!row) continue; diff --git a/src/webui/www/private/scripts/prop-files.js b/src/webui/www/private/scripts/prop-files.js index 6ae12fc8a..4871965ce 100644 --- a/src/webui/www/private/scripts/prop-files.js +++ b/src/webui/www/private/scripts/prop-files.js @@ -536,7 +536,7 @@ window.qBittorrent.PropFiles ??= (() => { const rowId = torrentFilesTable.selectedRowsIds()[0]; if (rowId === undefined) return; - const row = torrentFilesTable.rows[rowId]; + const row = torrentFilesTable.rows.get(rowId); if (!row) return; diff --git a/src/webui/www/private/scripts/search.js b/src/webui/www/private/scripts/search.js index b9942b98c..8a79922f3 100644 --- a/src/webui/www/private/scripts/search.js +++ b/src/webui/www/private/scripts/search.js @@ -352,7 +352,7 @@ window.qBittorrent.Search ??= (() => { searchResultsTable.reselectRows(rowsToSelect); $("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length; - $("numSearchResultsTotal").textContent = searchResultsTable.getRowIds().length; + $("numSearchResultsTotal").textContent = searchResultsTable.getRowSize(); setupSearchTableEvents(true); }; @@ -445,15 +445,14 @@ window.qBittorrent.Search ??= (() => { }; const openSearchTorrentDescriptionUrl = function() { - searchResultsTable.selectedRowsIds().each((rowId) => { - window.open(searchResultsTable.rows.get(rowId).full_data.descrLink, "_blank"); - }); + for (const rowID of searchResultsTable.selectedRowsIds()) + window.open(searchResultsTable.getRow(rowID).full_data.descrLink, "_blank"); }; const copySearchTorrentName = function() { const names = []; searchResultsTable.selectedRowsIds().each((rowId) => { - names.push(searchResultsTable.rows.get(rowId).full_data.fileName); + names.push(searchResultsTable.getRow(rowId).full_data.fileName); }); return names.join("\n"); }; @@ -461,7 +460,7 @@ window.qBittorrent.Search ??= (() => { const copySearchTorrentDownloadLink = function() { const urls = []; searchResultsTable.selectedRowsIds().each((rowId) => { - urls.push(searchResultsTable.rows.get(rowId).full_data.fileUrl); + urls.push(searchResultsTable.getRow(rowId).full_data.fileUrl); }); return urls.join("\n"); }; @@ -469,16 +468,15 @@ window.qBittorrent.Search ??= (() => { const copySearchTorrentDescriptionUrl = function() { const urls = []; searchResultsTable.selectedRowsIds().each((rowId) => { - urls.push(searchResultsTable.rows.get(rowId).full_data.descrLink); + urls.push(searchResultsTable.getRow(rowId).full_data.descrLink); }); return urls.join("\n"); }; const downloadSearchTorrent = function() { const urls = []; - searchResultsTable.selectedRowsIds().each((rowId) => { - urls.push(searchResultsTable.rows.get(rowId).full_data.fileUrl); - }); + for (const rowID of searchResultsTable.selectedRowsIds()) + urls.push(searchResultsTable.getRow(rowID).full_data.fileUrl); // only proceed if at least 1 row was selected if (!urls.length) @@ -836,7 +834,7 @@ window.qBittorrent.Search ??= (() => { searchResultsTable.updateRowData(row); $("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length; - $("numSearchResultsTotal").textContent = searchResultsTable.getRowIds().length; + $("numSearchResultsTotal").textContent = searchResultsTable.getRowSize(); searchResultsTable.updateTable(); } diff --git a/src/webui/www/private/views/log.html b/src/webui/www/private/views/log.html index 6305fe13b..2c9998659 100644 --- a/src/webui/www/private/views/log.html +++ b/src/webui/www/private/views/log.html @@ -332,7 +332,7 @@ curTab = currentSelectedTab; $("numFilteredLogs").textContent = tableInfo[curTab].instance.filteredLength(); - $("numTotalLogs").textContent = tableInfo[curTab].instance.getRowIds().length; + $("numTotalLogs").textContent = tableInfo[curTab].instance.getRowSize(); }; const syncLogData = (curTab) => { @@ -413,8 +413,8 @@ new ClipboardJS(".copyLogDataToClipboard", { text: function() { const msg = []; - tableInfo[currentSelectedTab].instance.selectedRowsIds().each((rowId) => { - msg.push(tableInfo[currentSelectedTab].instance.rows.get(rowId).full_data[(currentSelectedTab === "main") ? "message" : "ip"]); + tableInfo[currentSelectedTab].instance.selectedRowsIds().forEach((rowId) => { + msg.push(tableInfo[currentSelectedTab].instance.getRow(rowId).full_data[(currentSelectedTab === "main") ? "message" : "ip"]); }); return msg.join("\n"); diff --git a/src/webui/www/private/views/rss.html b/src/webui/www/private/views/rss.html index a02f97caa..19f27ff87 100644 --- a/src/webui/www/private/views/rss.html +++ b/src/webui/www/private/views/rss.html @@ -223,22 +223,23 @@ actions: { update: (el) => { const feedsToUpdate = new Set(); - rssFeedTable.selectedRows.each((rowId) => { - const selectedPath = rssFeedTable.rows[rowId].full_data.dataPath; - rssFeedTable.rows.filter((row) => row.full_data.dataPath.slice(0, selectedPath.length) === selectedPath) - .filter((row) => row.full_data.dataUid !== "") - .each((row) => feedsToUpdate.add(row)); - }); + for (const rowId of rssFeedTable.selectedRows) { + const selectedPath = rssFeedTable.getRow(rowId).full_data.dataPath; + for (const row of rssFeedTable.getRowValues()) { + if ((row.full_data.dataPath.slice(0, selectedPath.length) === selectedPath) && (row.full_data.dataUid !== "")) + feedsToUpdate.add(row); + } + }; feedsToUpdate.forEach((feed) => refreshFeed(feed.full_data.dataUid)); }, markRead: markSelectedAsRead, rename: (el) => { - moveItem(rssFeedTable.rows[rssFeedTable.selectedRows[0]].full_data.dataPath); + moveItem(rssFeedTable.getRow(rssFeedTable.selectedRows[0]).full_data.dataPath); }, delete: (el) => { const selectedDatapaths = rssFeedTable.selectedRows - .filter((e) => e !== 0) - .map((sRow) => rssFeedTable.rows[sRow].full_data.dataPath); + .filter((rowID) => rowID !== "0") + .map((rowID) => rssFeedTable.getRow(rowID).full_data.dataPath); // filter children const reducedDatapaths = selectedDatapaths.filter((path) => selectedDatapaths.filter((innerPath) => path.slice(0, innerPath.length) === innerPath).length === 1 @@ -262,7 +263,7 @@ rssFeedTable.deselectRow(); }); $("rssFeedTableDiv").addEventListener("contextmenu", (e) => { - if (e.toElement.nodeName === "DIV") { + if (e.target.nodeName === "DIV") { rssFeedTable.deselectAll(); rssFeedTable.deselectRow(); rssFeedContextMenu.updateMenuItems(); @@ -272,9 +273,11 @@ new ClipboardJS("#CopyFeedURL", { text: () => { let joined = ""; - rssFeedTable.selectedRows - .filter((row) => rssFeedTable.rows[row].full_data.dataUid !== "") - .each((row) => joined += rssFeedTable.rows[row].full_data.dataUrl + "\n"); + for (const rowID of rssFeedTable.selectedRows) { + const row = rssFeedTable.getRow(rowID); + if (row.full_data.dataUid !== "") + joined += `${row.full_data.dataUrl}\n`; + } return joined.slice(0, -1); } }); @@ -286,15 +289,13 @@ actions: { Download: (el) => { let dlString = ""; - rssArticleTable.selectedRows.each((row) => { - dlString += rssArticleTable.rows[row].full_data.torrentURL + "\n"; - }); + for (const rowID of rssArticleTable.selectedRows) + dlString += `${rssArticleTable.getRow(rowID).full_data.torrentURL}\n`; showDownloadPage([dlString]); }, OpenNews: (el) => { - rssArticleTable.selectedRows.each((row) => { - window.open(rssArticleTable.rows[row].full_data.link); - }); + for (const rowID of rssArticleTable.selectedRows) + window.open(rssArticleTable.getRow(rowID).full_data.link); } }, offsets: { @@ -322,7 +323,7 @@ const addRSSFeed = () => { let path = ""; if (rssFeedTable.selectedRows.length !== 0) { - const row = rssFeedTable.rows[rssFeedTable.selectedRows[0]]; + const row = rssFeedTable.getRow(rssFeedTable.selectedRows[0]); if (row.full_data.dataUid === "") { path = row.full_data.dataPath; } @@ -350,7 +351,7 @@ const addFolder = () => { let path = ""; if (rssFeedTable.selectedRows.length !== 0) { - const row = rssFeedTable.rows[rssFeedTable.selectedRows[0]]; + const row = rssFeedTable.getRow(rssFeedTable.selectedRows[0]); if (row.full_data.dataUid === "") { path = row.full_data.dataPath; } @@ -380,9 +381,10 @@ let rowCount = 0; const childFeeds = new Set(); - rssFeedTable.rows.filter((row) => row.full_data.dataPath.slice(0, path.length) === path) - .filter((row) => row.full_data.dataUid !== "") - .each((row) => childFeeds.add(row.full_data.dataUid)); + for (const row of rssFeedTable.getRowValues()) { + if ((row.full_data.dataPath.slice(0, path.length) === path) && (row.full_data.dataUid !== "")) + childFeeds.add(row.full_data.dataUid); + } let visibleArticles = []; for (const feedEntry in feedData) { @@ -490,12 +492,14 @@ recFlatten(response); // check if rows matches flattened response + const rssFeedRows = [...rssFeedTable.getRowValues()]; let match = false; - if ((rssFeedTable.rows.getLength() - 1) === flattenedResp.length) { + // subtract 'unread' row + if ((rssFeedRows.length - 1) === flattenedResp.length) { match = true; for (let i = 0; i < flattenedResp.length; ++i) { - if (((flattenedResp[i].uid ? flattenedResp[i].uid : "") !== rssFeedTable.rows[i + 1].full_data.dataUid) - || (flattenedResp[i].fullName !== rssFeedTable.rows[i + 1].full_data.dataPath)) { + if (((flattenedResp[i].uid ? flattenedResp[i].uid : "") !== rssFeedRows[i + 1].full_data.dataUid) + || (flattenedResp[i].fullName !== rssFeedRows[i + 1].full_data.dataPath)) { match = false; break; } @@ -507,7 +511,7 @@ // update status let statusDiffers = false; for (let i = 0; i < flattenedResp.length; ++i) { - const oldStatus = rssFeedTable.rows[i + 1].full_data.status; + const oldStatus = rssFeedRows[i + 1].full_data.status; let status = "default"; if (flattenedResp[i].hasError) status = "hasError"; @@ -530,8 +534,8 @@ // get currently opened feed let openedFeedPath = undefined; if (rssFeedTable.selectedRows.length !== 0) { - const lastSelectedRow = rssFeedTable.selectedRows[rssFeedTable.selectedRows.length - 1]; - openedFeedPath = rssFeedTable.rows[lastSelectedRow].full_data.dataPath; + const lastSelectedRow = rssFeedTable.selectedRows.at(-1); + openedFeedPath = rssFeedTable.getRow(lastSelectedRow).full_data.dataPath; } // check if list of articles differs @@ -554,8 +558,11 @@ const unreadDifference = newUnread - oldUnread; // find all parents (and self) and add unread difference - rssFeedTable.rows.filter((row) => r.fullName.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) - .each((row) => row.full_data.unread += unreadDifference); + for (const row of rssFeedTable.getRowValues()) { + if (r.fullName.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) + row.full_data.unread += unreadDifference; + } + needsUpdate = true; // update data @@ -582,15 +589,20 @@ if (readChanged) { needsUpdate = true; // find all items that contain this rss feed and add read difference - rssFeedTable.rows.filter((row) => r.fullName.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) - .each((row) => row.full_data.unread += readDifference); + for (const row of rssFeedTable.getRowValues()) { + if (r.fullName.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) + row.full_data.unread += readDifference; + } // if feed that is opened changed update dynamically if ((openedFeedPath !== undefined) && (r.fullName.slice(0, openedFeedPath.length) === openedFeedPath)) { for (let i = 0; i < r.articles.length; ++i) { - const matchingRow = rssArticleTable.rows.filter((row) => row.full_data.feedUid === r.uid) - .filter((row) => row.full_data.dataId === r.articles[i].id); - matchingRow[Object.keys(matchingRow)[0]].full_data.isRead = r.articles[i].isRead; + for (const row of rssArticleTable.getRowValues()) { + if ((row.full_data.feedUid === r.uid) && (row.full_data.dataId === r.articles[i].id)) { + row.full_data.isRead = r.articles[i].isRead; + break; + } + } } } } @@ -605,6 +617,7 @@ else { // full refresh rssFeedTable.clear(); + rssArticleTable.clear(); feedData = {}; pathByFeedId = new Map(); @@ -655,8 +668,10 @@ // calculate number of unread const numberOfUnread = dataEntry.articles.map((art) => !art.isRead).filter((v) => v).length; // find all items that contain this rss feed and add unread count - rssFeedTable.rows.filter((row) => dataEntry.fullName.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) - .each((row) => row.full_data.unread += numberOfUnread); + for (const row of rssFeedTable.getRowValues()) { + if (dataEntry.fullName.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) + row.full_data.unread += numberOfUnread; + } pathByFeedId.set(dataEntry.uid, dataEntry.fullName); feedData[dataEntry.uid] = dataEntry.articles; @@ -672,10 +687,10 @@ const refreshFeed = (feedUid) => { // set icon to loading - rssFeedTable.rows.forEach((row) => { + for (const row of rssFeedTable.getRowValues()) { if (row.full_data.dataUid === feedUid) row.full_data.status = "isLoading"; - }); + } rssFeedTable.updateIcons(); new Request({ @@ -738,24 +753,29 @@ } // mark rows as read - rssArticleTable.rows.each((el) => el.full_data.isRead = true); + for (const row of rssArticleTable.getRowValues()) + row.full_data.isRead = true; // find all children and set unread count to 0 - rssFeedTable.rows.filter((row) => (row.full_data.dataPath.slice(0, path.length) === path) && (path !== row.full_data.dataPath)) - .each((row) => row.full_data.unread = 0); + for (const row of rssFeedTable.getRowValues()) { + if ((row.full_data.dataPath.slice(0, path.length) === path) && (path !== row.full_data.dataPath)) + row.full_data.unread = 0; + } // find selected row let rowId, prevUnreadCount; - rssFeedTable.rows.forEach((row) => { + for (const row of rssFeedTable.getRowValues()) { if (row.full_data.dataPath === path) { rowId = row.full_data.rowId; prevUnreadCount = row.full_data.unread; } - }); + } // find all parents (and self) and subtract previous unread count - rssFeedTable.rows.filter((row) => path.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) - .each((row) => row.full_data.unread -= prevUnreadCount); + for (const row of rssFeedTable.getRowValues()) { + if (path.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) + row.full_data.unread -= prevUnreadCount; + } rssArticleTable.updateTable(false); rssFeedTable.updateTable(true); @@ -777,14 +797,15 @@ const markArticleAsRead = (path, id) => { // find row let rowId, name, uid, unread; - rssFeedTable.rows.forEach((row) => { + for (const row of rssFeedTable.getRowValues()) { if (row.full_data.dataPath === path) { rowId = row.full_data.rowId; name = row.full_data.dataPath; uid = row.full_data.dataUid; unread = row.full_data.unread; } - }); + } + // update feed data let prevReadState = true; feedData[uid].each((article) => { @@ -796,8 +817,10 @@ if (!prevReadState) { // find all items that contain this feed and subtract 1 - rssFeedTable.rows.filter((row) => path.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) - .each((row) => row.full_data.unread -= 1); + for (const row of rssFeedTable.getRowValues()) { + if (path.slice(0, row.full_data.dataPath.length) === row.full_data.dataPath) + row.full_data.unread -= 1; + } rssFeedTable.updateTable(true); @@ -818,7 +841,7 @@ const markSelectedAsRead = () => { const selectedDatapaths = rssFeedTable.selectedRows - .map((sRow) => rssFeedTable.rows[sRow].full_data.dataPath); + .map((sRow) => rssFeedTable.getRow(sRow).full_data.dataPath); // filter children const reducedDatapaths = selectedDatapaths.filter((path) => selectedDatapaths.filter((innerPath) => path.slice(0, innerPath.length) === innerPath).length === 1 diff --git a/src/webui/www/private/views/rssDownloader.html b/src/webui/www/private/views/rssDownloader.html index 151a93f6e..8c53d6584 100644 --- a/src/webui/www/private/views/rssDownloader.html +++ b/src/webui/www/private/views/rssDownloader.html @@ -404,11 +404,11 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also addRule: addRule, deleteRule: removeSelectedRule, renameRule: (el) => { - renameRule(rssDownloaderRulesTable.rows[rssDownloaderRulesTable.selectedRows[0]].full_data.name); + renameRule(rssDownloaderRulesTable.getRow(rssDownloaderRulesTable.selectedRows[0]).full_data.name); }, clearDownloadedEpisodes: (el) => { clearDownloadedEpisodes(rssDownloaderRulesTable.selectedRows - .map((sRow) => rssDownloaderRulesTable.rows[sRow].full_data.name)); + .map((sRow) => rssDownloaderRulesTable.getRow(sRow).full_data.name)); } }, offsets: { @@ -552,7 +552,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also if (rssDownloaderRulesTable.selectedRows.length === 0) return; removeRules(rssDownloaderRulesTable.selectedRows.map((sRow) => - rssDownloaderRulesTable.rows[sRow].full_data.name)); + rssDownloaderRulesTable.getRow(sRow).full_data.name)); }; const removeRules = (rules) => { @@ -588,8 +588,8 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also }; const saveSettings = () => { - const lastSelectedRow = rssDownloaderRulesTable.selectedRows[rssDownloaderRulesTable.selectedRows.length - 1]; - const rule = rssDownloaderRulesTable.rows[lastSelectedRow].full_data.name; + const lastSelectedRow = rssDownloaderRulesTable.selectedRows.at(-1); + const rule = rssDownloaderRulesTable.getRow(lastSelectedRow).full_data.name; rulesList[rule].useRegex = $("useRegEx").checked; rulesList[rule].mustContain = $("mustContainText").value; @@ -597,9 +597,9 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also rulesList[rule].episodeFilter = $("episodeFilterText").value; rulesList[rule].smartFilter = $("useSmartFilter").checked; rulesList[rule].ignoreDays = parseInt($("ignoreDaysValue").value, 10); - rulesList[rule].affectedFeeds = rssDownloaderFeedSelectionTable.rows.filter((row) => row.full_data.checked) - .map((row) => row.full_data.url) - .getValues(); + rulesList[rule].affectedFeeds = [...rssDownloaderFeedSelectionTable.getRowValues()] + .filter((row) => row.full_data.checked) + .map((row) => row.full_data.url); rulesList[rule].torrentParams.category = $("assignCategoryCombobox").value; rulesList[rule].torrentParams.tags = $("ruleAddTags").value.split(","); diff --git a/src/webui/www/private/views/searchplugins.html b/src/webui/www/private/views/searchplugins.html index 1aee0bf7e..edd321e5f 100644 --- a/src/webui/www/private/views/searchplugins.html +++ b/src/webui/www/private/views/searchplugins.html @@ -202,7 +202,7 @@ // clear event listeners setupSearchPluginTableEvents(false); - const oldPlugins = Object.keys(searchPluginsTable.rows); + const oldPlugins = [...searchPluginsTable.getRowIds()]; // remove old rows from the table for (let i = 0; i < oldPlugins.length; ++i) { let found = false;