diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index b2a8c7f3e1fa..2124147687e4 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -46,18 +46,18 @@ let clipboardEvent; const CATEGORIES_ALL = 1; const CATEGORIES_UNCATEGORIZED = 2; -let category_list = {}; +const category_list = new Map(); -let selected_category = CATEGORIES_ALL; +let selected_category = Number(LocalPreferences.get('selected_category', CATEGORIES_ALL)); let setCategoryFilter = function() {}; /* Tags filter */ const TAGS_ALL = 1; const TAGS_UNTAGGED = 2; -let tagList = {}; +const tagList = new Map(); -let selectedTag = TAGS_ALL; +let selectedTag = Number(LocalPreferences.get('selected_tag', TAGS_ALL)); let setTagFilter = function() {}; /* Trackers filter */ @@ -74,16 +74,6 @@ let selected_filter = LocalPreferences.get('selected_filter', 'all'); let setFilter = function() {}; let toggleFilterDisplay = function() {}; -const loadSelectedCategory = function() { - selected_category = LocalPreferences.get('selected_category', CATEGORIES_ALL); -}; -loadSelectedCategory(); - -const loadSelectedTag = function() { - selectedTag = LocalPreferences.get('selected_tag', TAGS_ALL); -}; -loadSelectedTag(); - const loadSelectedTracker = function() { selectedTracker = LocalPreferences.get('selected_tracker', TRACKERS_ALL); }; @@ -244,7 +234,7 @@ window.addEvent('load', function() { }; setTagFilter = function(hash) { - selectedTag = hash.toString(); + selectedTag = hash; LocalPreferences.set('selected_tag', selectedTag); highlightSelectedTag(); if (torrentsTable.tableBody !== undefined) @@ -358,14 +348,11 @@ window.addEvent('load', function() { return false; let removed = false; - for (const key in category_list) { - if (!Object.hasOwn(category_list, key)) - continue; - - const category = category_list[key]; + category_list.forEach((category) => { const deleteResult = category.torrents.delete(hash); removed ||= deleteResult; - } + }); + return removed; }; @@ -379,16 +366,19 @@ window.addEvent('load', function() { removeTorrentFromCategoryList(hash); return true; } + const categoryHash = genHash(category); - if (!category_list[categoryHash]) { // This should not happen - category_list[categoryHash] = { + if (!category_list.has(categoryHash)) { // This should not happen + category_list.set(categoryHash, { name: category, - torrents: [] - }; + torrents: new Set() + }); } - if (!category_list[categoryHash].torrents.has(hash)) { + + const torrents = category_list.get(categoryHash).torrents; + if (!torrents.has(hash)) { removeTorrentFromCategoryList(hash); - category_list[categoryHash].torrents.add(hash); + torrents.add(hash); return true; } return false; @@ -399,14 +389,11 @@ window.addEvent('load', function() { return false; let removed = false; - for (const key in tagList) { - if (!Object.hasOwn(tagList, key)) - continue; - - const tag = tagList[key]; + tagList.forEach((tag) => { const deleteResult = tag.torrents.delete(hash); removed ||= deleteResult; - } + }); + return removed; }; @@ -424,14 +411,16 @@ window.addEvent('load', function() { let added = false; for (let i = 0; i < tags.length; ++i) { const tagHash = genHash(tags[i].trim()); - if (!tagList[tagHash]) { // This should not happen - tagList[tagHash] = { + if (!tagList.has(tagHash)) { // This should not happen + tagList.set(tagHash, { name: tags, torrents: new Set() - }; + }); } - if (!tagList[tagHash].torrents.has(hash)) { - tagList[tagHash].torrents.add(hash); + + const torrents = tagList.get(tagHash).torrents; + if (!torrents.has(hash)) { + torrents.add(hash); added = true; } } @@ -474,7 +463,7 @@ window.addEvent('load', function() { margin_left = (category_path.length - 1) * 20; } - const html = '<a href="#" style="margin-left: ' + margin_left + 'px" onclick="setCategoryFilter(' + hash + ');return false;">' + const html = `<a href="#" style="margin-left: ${margin_left}px;" onclick="setCategoryFilter(${hash}); return false;">` + '<img src="images/view-categories.svg"/>' + window.qBittorrent.Misc.escapeHtml(display_name) + ' (' + count + ')' + '</a>'; const el = new Element('li', { @@ -487,20 +476,26 @@ window.addEvent('load', function() { const all = torrentsTable.getRowIds().length; let uncategorized = 0; - Object.each(torrentsTable.rows, function(row) { + for (const key in torrentsTable.rows) { + if (!Object.hasOwn(torrentsTable.rows, key)) + continue; + + const row = torrentsTable.rows[key]; if (row['full_data'].category.length === 0) uncategorized += 1; - }); + } categoryList.appendChild(create_link(CATEGORIES_ALL, 'QBT_TR(All)QBT_TR[CONTEXT=CategoryFilterModel]', all)); categoryList.appendChild(create_link(CATEGORIES_UNCATEGORIZED, 'QBT_TR(Uncategorized)QBT_TR[CONTEXT=CategoryFilterModel]', uncategorized)); const sortedCategories = []; - Object.each(category_list, function(category) { - sortedCategories.push(category.name); - }); - sortedCategories.sort((leftCategory, rightCategory) => { - const leftSegments = leftCategory.split('/'); - const rightSegments = rightCategory.split('/'); + category_list.forEach((category, hash) => sortedCategories.push({ + categoryName: category.name, + categoryHash: hash, + categoryCount: category.torrents.size + })); + sortedCategories.sort((left, right) => { + const leftSegments = left.categoryName.split('/'); + const rightSegments = right.categoryName.split('/'); for (let i = 0, iMax = Math.min(leftSegments.length, rightSegments.length); i < iMax; ++i) { const compareResult = window.qBittorrent.Misc.naturalSortCollator.compare( @@ -513,15 +508,13 @@ window.addEvent('load', function() { }); for (let i = 0; i < sortedCategories.length; ++i) { - const categoryName = sortedCategories[i]; - const categoryHash = genHash(categoryName); - let categoryCount = category_list[categoryHash].torrents.size; + const { categoryName, categoryHash } = sortedCategories[i]; + let { categoryCount } = sortedCategories[i]; if (useSubcategories) { for (let j = (i + 1); - (j < sortedCategories.length) && sortedCategories[j].startsWith(categoryName + "/"); ++j) { - const hash = genHash(sortedCategories[j]); - categoryCount += category_list[hash].torrents.size; + ((j < sortedCategories.length) && sortedCategories[j].categoryName.startsWith(categoryName + "/")); ++j) { + categoryCount += sortedCategories[j].categoryCount; } } @@ -537,7 +530,7 @@ window.addEvent('load', function() { return; const children = categoryList.childNodes; for (let i = 0; i < children.length; ++i) { - if (children[i].id == selected_category) + if (Number(children[i].id) === selected_category) children[i].className = "selectedFilter"; else children[i].className = ""; @@ -552,7 +545,7 @@ window.addEvent('load', function() { tagFilterList.getChildren().each(c => c.destroy()); const createLink = function(hash, text, count) { - const html = '<a href="#" onclick="setTagFilter(' + hash + ');return false;">' + const html = `<a href="#" onclick="setTagFilter(${hash}); return false;">` + '<img src="images/tags.svg"/>' + window.qBittorrent.Misc.escapeHtml(text) + ' (' + count + ')' + '</a>'; const el = new Element('li', { @@ -573,16 +566,15 @@ window.addEvent('load', function() { tagFilterList.appendChild(createLink(TAGS_UNTAGGED, 'QBT_TR(Untagged)QBT_TR[CONTEXT=TagFilterModel]', untagged)); const sortedTags = []; - for (const key in tagList) - sortedTags.push(tagList[key].name); - sortedTags.sort(window.qBittorrent.Misc.naturalSortCollator.compare); - - for (let i = 0; i < sortedTags.length; ++i) { - const tagName = sortedTags[i]; - const tagHash = genHash(tagName); - const tagCount = tagList[tagHash].torrents.size; - tagFilterList.appendChild(createLink(tagHash, tagName, tagCount)); - } + tagList.forEach((tag, hash) => sortedTags.push({ + tagName: tag.name, + tagHash: hash, + tagSize: tag.torrents.size + })); + sortedTags.sort((left, right) => window.qBittorrent.Misc.naturalSortCollator.compare(left.tagName, right.tagName)); + + for (const { tagName, tagHash, tagSize } of sortedTags) + tagFilterList.appendChild(createLink(tagHash, tagName, tagSize)); highlightSelectedTag(); }; @@ -594,7 +586,7 @@ window.addEvent('load', function() { const children = tagFilterList.childNodes; for (let i = 0; i < children.length; ++i) - children[i].className = (children[i].id === selectedTag) ? "selectedFilter" : ""; + children[i].className = (Number(children[i].id) === selectedTag) ? "selectedFilter" : ""; }; const updateTrackerList = function() { @@ -626,14 +618,15 @@ window.addEvent('load', function() { trackerFilterList.appendChild(createLink(TRACKERS_TRACKERLESS, 'QBT_TR(Trackerless (%1))QBT_TR[CONTEXT=TrackerFiltersList]', trackerlessTorrentsCount)); // Sort trackers by hostname - const sortedList = [...trackerList.entries()].sort((left, right) => { - const leftHost = getHost(left[1].url); - const rightHost = getHost(right[1].url); - return window.qBittorrent.Misc.naturalSortCollator.compare(leftHost, rightHost); - }); - for (const [hash, tracker] of sortedList) { - trackerFilterList.appendChild(createLink(hash, (getHost(tracker.url) + ' (%1)'), tracker.torrents.length)); - } + const sortedList = []; + trackerList.forEach((tracker, hash) => sortedList.push({ + trackerHost: getHost(tracker.url), + trackerHash: hash, + trackerCount: tracker.torrents.length + })); + sortedList.sort((left, right) => window.qBittorrent.Misc.naturalSortCollator.compare(left.trackerHost, right.trackerHost)); + for (const { trackerHost, trackerHash, trackerCount } of sortedList) + trackerFilterList.appendChild(createLink(trackerHash, (trackerHost + ' (%1)'), trackerCount)); highlightSelectedTracker(); }; @@ -675,26 +668,30 @@ window.addEvent('load', function() { if (full_update) { torrentsTableSelectedRows = torrentsTable.selectedRowsIds(); torrentsTable.clear(); - category_list = {}; - tagList = {}; + category_list.clear(); + tagList.clear(); } if (response['rid']) { syncMainDataLastResponseId = response['rid']; } if (response['categories']) { for (const key in response['categories']) { - const category = response['categories'][key]; + if (!Object.hasOwn(response['categories'], key)) + continue; + + const responseCategory = response['categories'][key]; const categoryHash = genHash(key); - if (category_list[categoryHash] !== undefined) { + const category = category_list.get(categoryHash); + if (category !== undefined) { // only the save path can change for existing categories - category_list[categoryHash].savePath = category.savePath; + category.savePath = responseCategory.savePath; } else { - category_list[categoryHash] = { - name: category.name, - savePath: category.savePath, + category_list.set(categoryHash, { + name: responseCategory.name, + savePath: responseCategory.savePath, torrents: new Set() - }; + }); } } update_categories = true; @@ -702,18 +699,18 @@ window.addEvent('load', function() { if (response['categories_removed']) { response['categories_removed'].each(function(category) { const categoryHash = genHash(category); - delete category_list[categoryHash]; + category_list.delete(categoryHash); }); update_categories = true; } if (response['tags']) { for (const tag of response['tags']) { const tagHash = genHash(tag); - if (!tagList[tagHash]) { - tagList[tagHash] = { + if (!tagList.has(tagHash)) { + tagList.set(tagHash, { name: tag, torrents: new Set() - }; + }); } } updateTags = true; @@ -721,7 +718,7 @@ window.addEvent('load', function() { if (response['tags_removed']) { for (let i = 0; i < response['tags_removed'].length; ++i) { const tagHash = genHash(response['tags_removed'][i]); - delete tagList[tagHash]; + tagList.delete(tagHash); } updateTags = true; } diff --git a/src/webui/www/private/scripts/contextmenu.js b/src/webui/www/private/scripts/contextmenu.js index 70e7fea0654a..c03f09e4ea5f 100644 --- a/src/webui/www/private/scripts/contextmenu.js +++ b/src/webui/www/private/scripts/contextmenu.js @@ -311,10 +311,10 @@ window.qBittorrent.ContextMenu = (function() { let all_are_super_seeding = true; let all_are_auto_tmm = true; let there_are_auto_tmm = false; - const tagsSelectionState = Object.clone(tagList); + const tagCount = new Map(); - const h = torrentsTable.selectedRowsIds(); - h.each(function(item, index) { + const selectedRows = torrentsTable.selectedRowsIds(); + selectedRows.forEach((item, index) => { const data = torrentsTable.rows.get(item).full_data; if (data['seq_dl'] !== true) @@ -348,23 +348,15 @@ window.qBittorrent.ContextMenu = (function() { all_are_auto_tmm = false; const torrentTags = data['tags'].split(', '); - for (const key in tagsSelectionState) { - const tag = tagsSelectionState[key]; - const tagExists = torrentTags.contains(tag.name); - if ((tag.checked !== undefined) && (tag.checked != tagExists)) - tag.indeterminate = true; - if (tag.checked === undefined) - tag.checked = tagExists; - else - tag.checked = tag.checked && tagExists; + for (const tag of torrentTags) { + const count = tagCount.get(tag); + tagCount.set(tag, ((count !== undefined) ? (count + 1) : 1)); } }); - let show_seq_dl = true; - // hide renameFiles when more than 1 torrent is selected - if (h.length == 1) { - const data = torrentsTable.rows.get(h[0]).full_data; + if (selectedRows.length == 1) { + const data = torrentsTable.rows.get(selectedRows[0]).full_data; let metadata_downloaded = !(data['state'] == 'metaDL' || data['state'] == 'forcedMetaDL' || data['total_size'] == -1); // hide renameFiles when metadata hasn't been downloaded yet @@ -372,16 +364,9 @@ window.qBittorrent.ContextMenu = (function() { ? this.showItem('renameFiles') : this.hideItem('renameFiles'); } - else + else { this.hideItem('renameFiles'); - - if (!all_are_seq_dl && there_are_seq_dl) - show_seq_dl = false; - - let show_f_l_piece_prio = true; - - if (!all_are_f_l_piece_prio && there_are_f_l_piece_prio) - show_f_l_piece_prio = false; + } if (all_are_downloaded) { this.hideItem('downloadLimit'); @@ -392,6 +377,9 @@ window.qBittorrent.ContextMenu = (function() { this.setItemChecked('superSeeding', all_are_super_seeding); } else { + const show_seq_dl = (all_are_seq_dl || !there_are_seq_dl); + const show_f_l_piece_prio = (all_are_f_l_piece_prio || !there_are_f_l_piece_prio); + if (!show_seq_dl && show_f_l_piece_prio) this.menu.getElement('a[href$=firstLastPiecePrio]').parentNode.addClass('separator'); else @@ -434,42 +422,45 @@ window.qBittorrent.ContextMenu = (function() { } const contextTagList = $('contextTagList'); - for (const tagHash in tagList) { - const checkbox = contextTagList.getElement('a[href=#Tag/' + tagHash + '] input[type=checkbox]'); - const checkboxState = tagsSelectionState[tagHash]; - checkbox.indeterminate = checkboxState.indeterminate; - checkbox.checked = checkboxState.checked; - } + tagList.forEach((tag, tagHash) => { + const checkbox = contextTagList.getElement(`a[href="#Tag/${tagHash}"] input[type="checkbox"]`); + const count = tagCount.get(tag.name); + const hasCount = (count !== undefined); + const isLesser = (count < selectedRows.length); + checkbox.indeterminate = (hasCount ? isLesser : false); + checkbox.checked = (hasCount ? !isLesser : false); + }); }, - updateCategoriesSubMenu: function(category_list) { - const categoryList = $('contextCategoryList'); - categoryList.getChildren().each(c => c.destroy()); - categoryList.appendChild(new Element('li', { + updateCategoriesSubMenu: function(categoryList) { + const contextCategoryList = $('contextCategoryList'); + contextCategoryList.getChildren().each(c => c.destroy()); + contextCategoryList.appendChild(new Element('li', { html: '<a href="javascript:torrentNewCategoryFN();"><img src="images/list-add.svg" alt="QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]"/> QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]</a>' })); - categoryList.appendChild(new Element('li', { + contextCategoryList.appendChild(new Element('li', { html: '<a href="javascript:torrentSetCategoryFN(0);"><img src="images/edit-clear.svg" alt="QBT_TR(Reset)QBT_TR[CONTEXT=TransferListWidget]"/> QBT_TR(Reset)QBT_TR[CONTEXT=TransferListWidget]</a>' })); const sortedCategories = []; - Object.each(category_list, function(category) { - sortedCategories.push(category.name); - }); - sortedCategories.sort(window.qBittorrent.Misc.naturalSortCollator.compare); + categoryList.forEach((category, hash) => sortedCategories.push({ + categoryName: category.name, + categoryHash: hash + })); + sortedCategories.sort((left, right) => window.qBittorrent.Misc.naturalSortCollator.compare( + left.categoryName, right.categoryName)); let first = true; - Object.each(sortedCategories, function(categoryName) { - const categoryHash = genHash(categoryName); + for (const { categoryName, categoryHash } of sortedCategories) { const el = new Element('li', { - html: '<a href="javascript:torrentSetCategoryFN(\'' + categoryHash + '\');"><img src="images/view-categories.svg"/> ' + window.qBittorrent.Misc.escapeHtml(categoryName) + '</a>' + html: `<a href="javascript:torrentSetCategoryFN(${categoryHash});"><img src="images/view-categories.svg"/>${window.qBittorrent.Misc.escapeHtml(categoryName)}</a>` }); if (first) { el.addClass('separator'); first = false; } - categoryList.appendChild(el); - }); + contextCategoryList.appendChild(el); + } }, updateTagsSubMenu: function(tagList) { @@ -491,15 +482,16 @@ window.qBittorrent.ContextMenu = (function() { })); const sortedTags = []; - for (const key in tagList) - sortedTags.push(tagList[key].name); - sortedTags.sort(window.qBittorrent.Misc.naturalSortCollator.compare); + tagList.forEach((tag, hash) => sortedTags.push({ + tagName: tag.name, + tagHash: hash + })); + sortedTags.sort((left, right) => window.qBittorrent.Misc.naturalSortCollator.compare(left.tagName, right.tagName)); for (let i = 0; i < sortedTags.length; ++i) { - const tagName = sortedTags[i]; - const tagHash = genHash(tagName); + const { tagName, tagHash } = sortedTags[i]; const el = new Element('li', { - html: '<a href="#Tag/' + tagHash + '" onclick="event.preventDefault(); torrentSetTagsFN(\'' + tagHash + '\', !event.currentTarget.getElement(\'input[type=checkbox]\').checked);">' + html: `<a href="#Tag/${tagHash}" onclick="event.preventDefault(); torrentSetTagsFN(${tagHash}, !event.currentTarget.getElement('input[type=checkbox]').checked);">` + '<input type="checkbox" onclick="this.checked = !this.checked;"> ' + window.qBittorrent.Misc.escapeHtml(tagName) + '</a>' }); @@ -513,8 +505,8 @@ window.qBittorrent.ContextMenu = (function() { const CategoriesFilterContextMenu = new Class({ Extends: ContextMenu, updateMenuItems: function() { - const id = this.options.element.id; - if ((id != CATEGORIES_ALL) && (id != CATEGORIES_UNCATEGORIZED)) { + const id = Number(this.options.element.id); + if ((id !== CATEGORIES_ALL) && (id !== CATEGORIES_UNCATEGORIZED)) { this.showItem('editCategory'); this.showItem('deleteCategory'); if (useSubcategories) { @@ -535,8 +527,8 @@ window.qBittorrent.ContextMenu = (function() { const TagsFilterContextMenu = new Class({ Extends: ContextMenu, updateMenuItems: function() { - const id = this.options.element.id; - if ((id !== TAGS_ALL.toString()) && (id !== TAGS_UNTAGGED.toString())) + const id = Number(this.options.element.id); + if ((id !== TAGS_ALL) && (id !== TAGS_UNTAGGED)) this.showItem('deleteTag'); else this.hideItem('deleteTag'); diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 485b867b0096..b3f03a21266e 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1386,50 +1386,41 @@ window.qBittorrent.DynamicTable = (function() { break; } - const categoryHashInt = parseInt(categoryHash); - if (!isNaN(categoryHashInt)) { - switch (categoryHashInt) { - case CATEGORIES_ALL: - break; // do nothing - case CATEGORIES_UNCATEGORIZED: - if (row['full_data'].category.length !== 0) + switch (categoryHash) { + case CATEGORIES_ALL: + break; // do nothing + case CATEGORIES_UNCATEGORIZED: + if (row['full_data'].category.length !== 0) + return false; + break; // do nothing + default: + if (!useSubcategories) { + if (categoryHash !== genHash(row['full_data'].category)) return false; - break; // do nothing - default: - if (!useSubcategories) { - if (categoryHashInt !== genHash(row['full_data'].category)) - return false; - } - else { - const selectedCategoryName = category_list[categoryHash].name + "/"; - const torrentCategoryName = row['full_data'].category + "/"; - if (!torrentCategoryName.startsWith(selectedCategoryName)) - return false; - } - } + } + else { + const selectedCategoryName = category_list.get(categoryHash).name + "/"; + const torrentCategoryName = row['full_data'].category + "/"; + if (!torrentCategoryName.startsWith(selectedCategoryName)) + return false; + } + break; } - const tagHashInt = parseInt(tagHash); - const isNumber = !isNaN(tagHashInt); - if (isNumber) { - switch (tagHashInt) { - case TAGS_ALL: - break; // do nothing + switch (tagHash) { + case TAGS_ALL: + break; // do nothing - case TAGS_UNTAGGED: - if (row['full_data'].tags.length !== 0) - return false; - break; // do nothing + case TAGS_UNTAGGED: + if (row['full_data'].tags.length !== 0) + return false; + break; // do nothing - default: { - let rowTags = row['full_data'].tags.split(', '); - rowTags = rowTags.map(function(tag) { - return genHash(tag); - }); - if (!rowTags.contains(tagHashInt)) - return false; - break; - } + default: { + const tagHashes = row['full_data'].tags.split(', ').map(tag => genHash(tag)); + if (!tagHashes.contains(tagHash)) + return false; + break; } } @@ -1460,9 +1451,10 @@ window.qBittorrent.DynamicTable = (function() { let cnt = 0; const rows = this.rows.getValues(); - for (let i = 0; i < rows.length; ++i) + for (let i = 0; i < rows.length; ++i) { if (this.applyFilter(rows[i], filterName, categoryHash, tagHash, trackerHash, null)) ++cnt; + } return cnt; }, @@ -1470,9 +1462,10 @@ window.qBittorrent.DynamicTable = (function() { const rowsHashes = []; const rows = this.rows.getValues(); - for (let i = 0; i < rows.length; ++i) + for (let i = 0; i < rows.length; ++i) { if (this.applyFilter(rows[i], filterName, categoryHash, tagHash, trackerHash, null)) rowsHashes.push(rows[i]['rowId']); + } return rowsHashes; }, diff --git a/src/webui/www/private/scripts/mocha-init.js b/src/webui/www/private/scripts/mocha-init.js index 3801bc78a89d..be3577b163b6 100644 --- a/src/webui/www/private/scripts/mocha-init.js +++ b/src/webui/www/private/scripts/mocha-init.js @@ -573,20 +573,21 @@ const initializeWindows = function() { }; torrentSetCategoryFN = function(categoryHash) { - let categoryName = ''; - if (categoryHash != 0) - categoryName = category_list[categoryHash].name; const hashes = torrentsTable.selectedRowsIds(); - if (hashes.length) { - new Request({ - url: 'api/v2/torrents/setCategory', - method: 'post', - data: { - hashes: hashes.join("|"), - category: categoryName - } - }).send(); - } + if (hashes.length <= 0) + return; + + const categoryName = category_list.has(categoryHash) + ? category_list.get(categoryHash).name + : ''; + new Request({ + url: 'api/v2/torrents/setCategory', + method: 'post', + data: { + hashes: hashes.join("|"), + category: categoryName + } + }).send(); }; createCategoryFN = function() { @@ -609,7 +610,7 @@ const initializeWindows = function() { createSubcategoryFN = function(categoryHash) { const action = "createSubcategory"; - const categoryName = category_list[categoryHash].name + "/"; + const categoryName = category_list.get(categoryHash).name + "/"; new MochaUI.Window({ id: 'newSubcategoryPage', title: "QBT_TR(New Category)QBT_TR[CONTEXT=CategoryFilterWidget]", @@ -628,13 +629,12 @@ const initializeWindows = function() { editCategoryFN = function(categoryHash) { const action = "edit"; - const categoryName = category_list[categoryHash].name; - const savePath = category_list[categoryHash].savePath; + const category = category_list.get(categoryHash); new MochaUI.Window({ id: 'editCategoryPage', title: "QBT_TR(Edit Category)QBT_TR[CONTEXT=TransferListWidget]", loadMethod: 'iframe', - contentURL: new URI('newcategory.html').setData("action", action).setData("categoryName", categoryName).setData("savePath", savePath).toString(), + contentURL: new URI('newcategory.html').setData("action", action).setData("categoryName", category.name).setData("savePath", category.savePath).toString(), scrollbars: false, resizable: true, maximizable: false, @@ -647,7 +647,7 @@ const initializeWindows = function() { }; removeCategoryFN = function(categoryHash) { - const categoryName = category_list[categoryHash].name; + const categoryName = category_list.get(categoryHash).name; new Request({ url: 'api/v2/torrents/removeCategories', method: 'post', @@ -660,10 +660,11 @@ const initializeWindows = function() { deleteUnusedCategoriesFN = function() { const categories = []; - for (const hash in category_list) { + category_list.forEach((category, hash) => { if (torrentsTable.getFilteredTorrentsNumber('all', hash, TAGS_ALL, TRACKERS_ALL) === 0) - categories.push(category_list[hash].name); - } + categories.push(category.name); + }); + new Request({ url: 'api/v2/torrents/removeCategories', method: 'post', @@ -742,18 +743,19 @@ const initializeWindows = function() { }; torrentSetTagsFN = function(tagHash, isSet) { - const tagName = ((tagHash === '0') ? '' : tagList[tagHash].name); const hashes = torrentsTable.selectedRowsIds(); - if (hashes.length) { - new Request({ - url: (isSet ? 'api/v2/torrents/addTags' : 'api/v2/torrents/removeTags'), - method: 'post', - data: { - hashes: hashes.join("|"), - tags: tagName, - } - }).send(); - } + if (hashes.length <= 0) + return; + + const tagName = tagList.has(tagHash) ? tagList.get(tagHash).name : ''; + new Request({ + url: (isSet ? 'api/v2/torrents/addTags' : 'api/v2/torrents/removeTags'), + method: 'post', + data: { + hashes: hashes.join("|"), + tags: tagName, + } + }).send(); }; torrentRemoveAllTagsFN = function() { @@ -788,7 +790,7 @@ const initializeWindows = function() { }; removeTagFN = function(tagHash) { - const tagName = tagList[tagHash].name; + const tagName = tagList.get(tagHash).name; new Request({ url: 'api/v2/torrents/deleteTags', method: 'post', @@ -801,10 +803,10 @@ const initializeWindows = function() { deleteUnusedTagsFN = function() { const tags = []; - for (const hash in tagList) { + tagList.forEach((tag, hash) => { if (torrentsTable.getFilteredTorrentsNumber('all', CATEGORIES_ALL, hash, TRACKERS_ALL) === 0) - tags.push(tagList[hash].name); - } + tags.push(tag.name); + }); new Request({ url: 'api/v2/torrents/deleteTags', method: 'post', diff --git a/src/webui/www/private/views/filters.html b/src/webui/www/private/views/filters.html index d509713be666..580815d8ece0 100644 --- a/src/webui/www/private/views/filters.html +++ b/src/webui/www/private/views/filters.html @@ -65,25 +65,25 @@ createCategoryFN(); }, createSubcategory: function(element, ref) { - createSubcategoryFN(element.id); + createSubcategoryFN(Number(element.id)); }, editCategory: function(element, ref) { - editCategoryFN(element.id); + editCategoryFN(Number(element.id)); }, deleteCategory: function(element, ref) { - removeCategoryFN(element.id); + removeCategoryFN(Number(element.id)); }, deleteUnusedCategories: function(element, ref) { deleteUnusedCategoriesFN(); }, startTorrentsByCategory: function(element, ref) { - startTorrentsByCategoryFN(element.id); + startTorrentsByCategoryFN(Number(element.id)); }, pauseTorrentsByCategory: function(element, ref) { - pauseTorrentsByCategoryFN(element.id); + pauseTorrentsByCategoryFN(Number(element.id)); }, deleteTorrentsByCategory: function(element, ref) { - deleteTorrentsByCategoryFN(element.id); + deleteTorrentsByCategoryFN(Number(element.id)); } }, offsets: { @@ -103,19 +103,19 @@ createTagFN(); }, deleteTag: function(element, ref) { - removeTagFN(element.id); + removeTagFN(Number(element.id)); }, deleteUnusedTags: function(element, ref) { deleteUnusedTagsFN(); }, startTorrentsByTag: function(element, ref) { - startTorrentsByTagFN(element.id); + startTorrentsByTagFN(Number(element.id)); }, pauseTorrentsByTag: function(element, ref) { - pauseTorrentsByTagFN(element.id); + pauseTorrentsByTagFN(Number(element.id)); }, deleteTorrentsByTag: function(element, ref) { - deleteTorrentsByTagFN(element.id); + deleteTorrentsByTagFN(Number(element.id)); } }, offsets: { diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 387f4772c5c9..0b2e00f0cd0f 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -2043,7 +2043,11 @@ updateExportDirFinEnabled(); // Automatically add torrents from - for (const [folder, folderType] of Object.entries(pref.scan_dirs)) { + for (const folder in pref.scan_dirs) { + if (!Object.hasOwn(pref.scan_dirs, folder)) + continue; + + const folderType = pref.scan_dirs[folder]; let sel = ""; let other = ""; if (typeof folderType === "number") {