diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js
index d1217e7fb81..0879ce5241f 100644
--- a/src/webui/www/private/scripts/client.js
+++ b/src/webui/www/private/scripts/client.js
@@ -466,15 +466,26 @@ window.addEventListener("DOMContentLoaded", () => {
margin_left = (category_path.length - 1) * 20;
}
- const html = ``
- + ''
- + window.qBittorrent.Misc.escapeHtml(display_name) + " (" + count + ")" + "";
- const el = new Element("li", {
- id: hash,
- html: html
+ const span = document.createElement("span");
+ span.classList.add("link");
+ span.href = "#";
+ span.style.marginLeft = `${margin_left}px`;
+ span.textContent = `${display_name} (${count})`;
+ span.addEventListener("click", (event) => {
+ event.preventDefault();
+ setCategoryFilter(hash);
});
- window.qBittorrent.Filters.categoriesFilterContextMenu.addTarget(el);
- return el;
+
+ const img = document.createElement("img");
+ img.src = "images/view-categories.svg";
+ span.prepend(img);
+
+ const listItem = document.createElement("li");
+ listItem.id = hash;
+ listItem.appendChild(span);
+
+ window.qBittorrent.Filters.categoriesFilterContextMenu.addTarget(listItem);
+ return listItem;
};
const all = torrentsTable.getRowIds().length;
@@ -547,15 +558,25 @@ window.addEventListener("DOMContentLoaded", () => {
tagFilterList.getChildren().each(c => c.destroy());
const createLink = function(hash, text, count) {
- const html = ``
- + ''
- + window.qBittorrent.Misc.escapeHtml(text) + " (" + count + ")" + "";
- const el = new Element("li", {
- id: hash,
- html: html
+ const span = document.createElement("span");
+ span.classList.add("link");
+ span.href = "#";
+ span.textContent = `${text} (${count})`;
+ span.addEventListener("click", (event) => {
+ event.preventDefault();
+ setTagFilter(hash);
});
- window.qBittorrent.Filters.tagsFilterContextMenu.addTarget(el);
- return el;
+
+ const img = document.createElement("img");
+ img.src = "images/tags.svg";
+ span.prepend(img);
+
+ const listItem = document.createElement("li");
+ listItem.id = hash;
+ listItem.appendChild(span);
+
+ window.qBittorrent.Filters.tagsFilterContextMenu.addTarget(listItem);
+ return listItem;
};
const torrentsCount = torrentsTable.getRowIds().length;
@@ -623,15 +644,25 @@ window.addEventListener("DOMContentLoaded", () => {
trackerFilterList.getChildren().each(c => c.destroy());
const createLink = function(hash, text, count) {
- const html = ''
- + ''
- + window.qBittorrent.Misc.escapeHtml(text.replace("%1", count)) + "";
- const el = new Element("li", {
- id: hash,
- html: html
+ const span = document.createElement("span");
+ span.classList.add("link");
+ span.href = "#";
+ span.textContent = text.replace("%1", count);
+ span.addEventListener("click", (event) => {
+ event.preventDefault();
+ setTrackerFilter(hash);
});
- window.qBittorrent.Filters.trackersFilterContextMenu.addTarget(el);
- return el;
+
+ const img = document.createElement("img");
+ img.src = "images/trackers.svg";
+ span.prepend(img);
+
+ const listItem = document.createElement("li");
+ listItem.id = hash;
+ listItem.appendChild(span);
+
+ window.qBittorrent.Filters.trackersFilterContextMenu.addTarget(listItem);
+ return listItem;
};
const torrentsCount = torrentsTable.getRowIds().length;
diff --git a/src/webui/www/private/scripts/contextmenu.js b/src/webui/www/private/scripts/contextmenu.js
index 75dbed0fa66..6140e7ced2b 100644
--- a/src/webui/www/private/scripts/contextmenu.js
+++ b/src/webui/www/private/scripts/contextmenu.js
@@ -428,7 +428,7 @@ window.qBittorrent.ContextMenu ??= (() => {
const contextTagList = $("contextTagList");
tagList.forEach((tag, tagHash) => {
- const checkbox = contextTagList.getElement(`a[href="#Tag/${tagHash}"] input[type="checkbox"]`);
+ const checkbox = contextTagList.getElement(`a[href="#Tag/${tag.name}"] input[type="checkbox"]`);
const count = tagCount.get(tag.name);
const hasCount = (count !== undefined);
const isLesser = (count < selectedRows.length);
@@ -438,7 +438,7 @@ window.qBittorrent.ContextMenu ??= (() => {
const contextCategoryList = document.getElementById("contextCategoryList");
category_list.forEach((category, categoryHash) => {
- const categoryIcon = contextCategoryList.querySelector(`a[href$="(${categoryHash});"] img`);
+ const categoryIcon = contextCategoryList.querySelector(`a[href$="#Category/${category.name}"] img`);
const count = categoryCount.get(category.name);
const isEqual = ((count !== undefined) && (count === selectedRows.length));
categoryIcon.classList.toggle("highlightedCategoryIcon", isEqual);
@@ -448,12 +448,24 @@ window.qBittorrent.ContextMenu ??= (() => {
updateCategoriesSubMenu: function(categoryList) {
const contextCategoryList = $("contextCategoryList");
contextCategoryList.getChildren().each(c => c.destroy());
- contextCategoryList.appendChild(new Element("li", {
- html: 'QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]'
- }));
- contextCategoryList.appendChild(new Element("li", {
- html: 'QBT_TR(Reset)QBT_TR[CONTEXT=TransferListWidget]'
- }));
+
+ const createMenuItem = (text, imgURL, clickFn) => {
+ const anchor = document.createElement("a");
+ anchor.textContent = text;
+ anchor.addEventListener("click", clickFn);
+
+ const img = document.createElement("img");
+ img.src = imgURL;
+ img.alt = text;
+ anchor.prepend(img);
+
+ const item = document.createElement("li");
+ item.appendChild(anchor);
+
+ return item;
+ };
+ contextCategoryList.appendChild(createMenuItem("QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]", "images/list-add.svg", torrentNewCategoryFN));
+ contextCategoryList.appendChild(createMenuItem("QBT_TR(Reset)QBT_TR[CONTEXT=TransferListWidget]", "images/edit-clear.svg", () => { torrentSetCategoryFN(0); }));
const sortedCategories = [];
categoryList.forEach((category, hash) => sortedCategories.push({
@@ -465,14 +477,25 @@ window.qBittorrent.ContextMenu ??= (() => {
let first = true;
for (const { categoryName, categoryHash } of sortedCategories) {
- const el = new Element("li", {
- html: `${window.qBittorrent.Misc.escapeHtml(categoryName)}`
+ const anchor = document.createElement("a");
+ anchor.href = `#Category/${categoryName}`;
+ anchor.textContent = categoryName;
+ anchor.addEventListener("click", (event) => {
+ torrentSetCategoryFN(categoryHash);
});
+
+ const img = document.createElement("img");
+ img.src = "images/view-categories.svg";
+ anchor.prepend(img);
+
+ const setCategoryItem = document.createElement("li");
+ setCategoryItem.appendChild(anchor);
if (first) {
- el.addClass("separator");
+ setCategoryItem.addClass("separator");
first = false;
}
- contextCategoryList.appendChild(el);
+
+ contextCategoryList.appendChild(setCategoryItem);
}
},
@@ -481,18 +504,23 @@ window.qBittorrent.ContextMenu ??= (() => {
while (contextTagList.firstChild !== null)
contextTagList.removeChild(contextTagList.firstChild);
- contextTagList.appendChild(new Element("li", {
- html: ''
- + ''
- + " QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]"
- + ""
- }));
- contextTagList.appendChild(new Element("li", {
- html: ''
- + ''
- + " QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]"
- + ""
- }));
+ const createMenuItem = (text, imgURL, clickFn) => {
+ const anchor = document.createElement("a");
+ anchor.textContent = text;
+ anchor.addEventListener("click", clickFn);
+
+ const img = document.createElement("img");
+ img.src = imgURL;
+ img.alt = text;
+ anchor.prepend(img);
+
+ const item = document.createElement("li");
+ item.appendChild(anchor);
+
+ return item;
+ };
+ contextTagList.appendChild(createMenuItem("QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]", "images/list-add.svg", torrentAddTagsFN));
+ contextTagList.appendChild(createMenuItem("QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]", "images/edit-clear.svg", torrentRemoveAllTagsFN));
const sortedTags = [];
tagList.forEach((tag, hash) => sortedTags.push({
@@ -503,14 +531,28 @@ window.qBittorrent.ContextMenu ??= (() => {
for (let i = 0; i < sortedTags.length; ++i) {
const { tagName, tagHash } = sortedTags[i];
- const el = new Element("li", {
- html: ``
- + ' ' + window.qBittorrent.Misc.escapeHtml(tagName)
- + ""
+
+ const input = document.createElement("input");
+ input.type = "checkbox";
+ input.addEventListener("click", (event) => {
+ input.checked = !input.checked;
+ });
+
+ const anchor = document.createElement("a");
+ anchor.href = `#Tag/${tagName}`;
+ anchor.textContent = tagName;
+ anchor.addEventListener("click", (event) => {
+ event.preventDefault();
+ torrentSetTagsFN(tagHash, !input.checked);
});
+ anchor.prepend(input);
+
+ const setTagItem = document.createElement("li");
+ setTagItem.appendChild(anchor);
if (i === 0)
- el.addClass("separator");
- contextTagList.appendChild(el);
+ setTagItem.addClass("separator");
+
+ contextTagList.appendChild(setTagItem);
}
}
});
diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js
index 375497078a9..b51dd7317a3 100644
--- a/src/webui/www/private/scripts/dynamicTable.js
+++ b/src/webui/www/private/scripts/dynamicTable.js
@@ -333,10 +333,18 @@ window.qBittorrent.DynamicTable ??= (() => {
});
const createLi = function(columnName, text) {
- const html = '' + window.qBittorrent.Misc.escapeHtml(text) + "";
- return new Element("li", {
- html: html
- });
+ const anchor = document.createElement("a");
+ anchor.href = `#${columnName}`;
+ anchor.textContent = text;
+
+ const img = document.createElement("img");
+ img.src = "images/checked-completed.svg";
+ anchor.prepend(img);
+
+ const listItem = document.createElement("li");
+ listItem.appendChild(anchor);
+
+ return listItem;
};
const actions = {};
@@ -2076,8 +2084,7 @@ window.qBittorrent.DynamicTable ??= (() => {
},
id: dirImgId
});
- const html = dirImg.outerHTML + span.outerHTML;
- td.innerHTML = html;
+ td.replaceChildren(dirImg, span);
}
}
else { // is file
@@ -2089,7 +2096,7 @@ window.qBittorrent.DynamicTable ??= (() => {
"margin-left": ((node.depth + 1) * 20)
}
});
- td.innerHTML = span.outerHTML;
+ td.replaceChildren(span);
}
};
@@ -2103,7 +2110,7 @@ window.qBittorrent.DynamicTable ??= (() => {
text: value,
id: fileNameRenamedId,
});
- td.innerHTML = span.outerHTML;
+ td.replaceChildren(span);
};
},
@@ -2409,8 +2416,7 @@ window.qBittorrent.DynamicTable ??= (() => {
},
id: dirImgId
});
- const html = collapseIcon.outerHTML + dirImg.outerHTML + span.outerHTML;
- td.innerHTML = html;
+ td.replaceChildren(collapseIcon, dirImg, span);
}
}
else {
@@ -2422,7 +2428,7 @@ window.qBittorrent.DynamicTable ??= (() => {
"margin-left": ((node.depth + 1) * 20)
}
});
- td.innerHTML = span.outerHTML;
+ td.replaceChildren(span);
}
};
diff --git a/src/webui/www/private/scripts/prop-files.js b/src/webui/www/private/scripts/prop-files.js
index d8111e2d597..80248caf90c 100644
--- a/src/webui/www/private/scripts/prop-files.js
+++ b/src/webui/www/private/scripts/prop-files.js
@@ -165,32 +165,31 @@ window.qBittorrent.PropFiles ??= (() => {
return ($("comboPrio" + id) !== null);
};
- const createPriorityOptionElement = function(priority, selected, html) {
- const elem = new Element("option");
- elem.value = priority.toString();
- elem.innerHTML = html;
- if (selected)
- elem.selected = true;
- return elem;
- };
+ const createPriorityCombo = (id, fileId, selectedPriority) => {
+ const createOption = (priority, isSelected, text) => {
+ const option = document.createElement("option");
+ option.value = priority.toString();
+ option.selected = isSelected;
+ option.textContent = text;
+ return option;
+ };
- const createPriorityCombo = function(id, fileId, selectedPriority) {
- const select = new Element("select");
+ const select = document.createElement("select");
select.id = "comboPrio" + id;
select.setAttribute("data-id", id);
select.setAttribute("data-file-id", fileId);
select.addClass("combo_priority");
select.addEventListener("change", fileComboboxChanged);
- createPriorityOptionElement(FilePriority.Ignored, (FilePriority.Ignored === selectedPriority), "QBT_TR(Do not download)QBT_TR[CONTEXT=PropListDelegate]").injectInside(select);
- createPriorityOptionElement(FilePriority.Normal, (FilePriority.Normal === selectedPriority), "QBT_TR(Normal)QBT_TR[CONTEXT=PropListDelegate]").injectInside(select);
- createPriorityOptionElement(FilePriority.High, (FilePriority.High === selectedPriority), "QBT_TR(High)QBT_TR[CONTEXT=PropListDelegate]").injectInside(select);
- createPriorityOptionElement(FilePriority.Maximum, (FilePriority.Maximum === selectedPriority), "QBT_TR(Maximum)QBT_TR[CONTEXT=PropListDelegate]").injectInside(select);
+ select.appendChild(createOption(FilePriority.Ignored, (FilePriority.Ignored === selectedPriority), "QBT_TR(Do not download)QBT_TR[CONTEXT=PropListDelegate]"));
+ select.appendChild(createOption(FilePriority.Normal, (FilePriority.Normal === selectedPriority), "QBT_TR(Normal)QBT_TR[CONTEXT=PropListDelegate]"));
+ select.appendChild(createOption(FilePriority.High, (FilePriority.High === selectedPriority), "QBT_TR(High)QBT_TR[CONTEXT=PropListDelegate]"));
+ select.appendChild(createOption(FilePriority.Maximum, (FilePriority.Maximum === selectedPriority), "QBT_TR(Maximum)QBT_TR[CONTEXT=PropListDelegate]"));
// "Mixed" priority is for display only; it shouldn't be selectable
- const mixedPriorityOption = createPriorityOptionElement(FilePriority.Mixed, (FilePriority.Mixed === selectedPriority), "QBT_TR(Mixed)QBT_TR[CONTEXT=PropListDelegate]");
+ const mixedPriorityOption = createOption(FilePriority.Mixed, (FilePriority.Mixed === selectedPriority), "QBT_TR(Mixed)QBT_TR[CONTEXT=PropListDelegate]");
mixedPriorityOption.disabled = true;
- mixedPriorityOption.injectInside(select);
+ select.appendChild(mixedPriorityOption);
return select;
};
diff --git a/src/webui/www/private/scripts/prop-general.js b/src/webui/www/private/scripts/prop-general.js
index 2ef547f4ff8..1b7148547c6 100644
--- a/src/webui/www/private/scripts/prop-general.js
+++ b/src/webui/www/private/scripts/prop-general.js
@@ -67,7 +67,7 @@ window.qBittorrent.PropGeneral ??= (() => {
$("torrent_hash_v1").textContent = "";
$("torrent_hash_v2").textContent = "";
$("save_path").textContent = "";
- $("comment").innerHTML = "";
+ $("comment").textContent = "";
$("private").textContent = "";
piecesBar.clear();
};
diff --git a/src/webui/www/private/scripts/prop-webseeds.js b/src/webui/www/private/scripts/prop-webseeds.js
index 5c0d4e64d24..1feb430dc62 100644
--- a/src/webui/www/private/scripts/prop-webseeds.js
+++ b/src/webui/www/private/scripts/prop-webseeds.js
@@ -63,7 +63,7 @@ window.qBittorrent.PropWebseeds ??= (() => {
updateRow: function(tr, row) {
const tds = tr.getElements("td");
for (let i = 0; i < row.length; ++i)
- tds[i].innerHTML = row[i];
+ tds[i].textContent = row[i];
return true;
},
@@ -78,9 +78,9 @@ window.qBittorrent.PropWebseeds ??= (() => {
const tr = new Element("tr");
this.rows.set(url, tr);
for (let i = 0; i < row.length; ++i) {
- const td = new Element("td");
- td.innerHTML = row[i];
- td.injectInside(tr);
+ const td = document.createElement("td");
+ td.textContent = row[i];
+ tr.appendChild(td);
}
tr.injectInside(this.table);
},
diff --git a/src/webui/www/private/scripts/search.js b/src/webui/www/private/scripts/search.js
index c02fcfcf2cc..0bd541f5ff7 100644
--- a/src/webui/www/private/scripts/search.js
+++ b/src/webui/www/private/scripts/search.js
@@ -174,16 +174,15 @@ window.qBittorrent.Search ??= (() => {
tabElem.appendChild(getStatusIconElement("QBT_TR(Searching...)QBT_TR[CONTEXT=SearchJobWidget]", "images/queued.svg"));
- const liElement = new Element("li", {
- id: newTabId,
- class: "selected",
- html: tabElem.outerHTML,
- });
- liElement.addEventListener("click", (e) => {
- setActiveTab(liElement);
+ const listItem = document.createElement("li");
+ listItem.id = newTabId;
+ listItem.classList.add("selected");
+ listItem.addEventListener("click", (e) => {
+ setActiveTab(listItem);
$("startSearchButton").textContent = "QBT_TR(Search)QBT_TR[CONTEXT=SearchEngineWidget]";
});
- $("searchTabs").appendChild(liElement);
+ listItem.appendChild(tabElem);
+ $("searchTabs").appendChild(listItem);
// unhide the results elements
if (numSearchTabs() >= 1) {
@@ -194,7 +193,7 @@ window.qBittorrent.Search ??= (() => {
}
// select new tab
- setActiveTab(liElement);
+ setActiveTab(listItem);
searchResultsTable.clear();
resetFilters();
@@ -577,26 +576,27 @@ window.qBittorrent.Search ??= (() => {
}
};
- const getSearchCategories = function() {
- const populateCategorySelect = function(categories) {
- const categoryHtml = [];
- categories.each((category) => {
- const option = new Element("option");
+ const getSearchCategories = () => {
+ const populateCategorySelect = (categories) => {
+ const categoryOptions = [];
+
+ for (const category of categories) {
+ const option = document.createElement("option");
option.value = category.id;
option.textContent = category.name;
- categoryHtml.push(option.outerHTML);
- });
+ categoryOptions.push(option);
+ };
// first category is "All Categories"
- if (categoryHtml.length > 1) {
+ if (categoryOptions.length > 1) {
// add separator
- const option = new Element("option");
+ const option = document.createElement("option");
option.disabled = true;
option.textContent = "──────────";
- categoryHtml.splice(1, 0, option.outerHTML);
+ categoryOptions.splice(1, 0, option);
}
- $("categorySelect").innerHTML = categoryHtml.join("");
+ $("categorySelect").replaceChildren(...categoryOptions);
};
const selectedPlugin = $("pluginsSelect").value;
@@ -629,7 +629,16 @@ window.qBittorrent.Search ??= (() => {
url: new URI("api/v2/search/plugins"),
method: "get",
noCache: true,
- onSuccess: function(response) {
+ onSuccess: (response) => {
+ const createOption = (text, value, disabled = false) => {
+ const option = document.createElement("option");
+ if (value !== undefined)
+ option.value = value;
+ option.textContent = text;
+ option.disabled = disabled;
+ return option;
+ };
+
if (response !== prevSearchPluginsResponse) {
prevSearchPluginsResponse = response;
searchPlugins.length = 0;
@@ -637,9 +646,9 @@ window.qBittorrent.Search ??= (() => {
searchPlugins.push(plugin);
});
- const pluginsHtml = [];
- pluginsHtml.push('');
- pluginsHtml.push('');
+ const pluginOptions = [];
+ pluginOptions.push(createOption("QBT_TR(Only enabled)QBT_TR[CONTEXT=SearchEngineWidget]", "enabled"));
+ pluginOptions.push(createOption("QBT_TR(All plugins)QBT_TR[CONTEXT=SearchEngineWidget]", "all"));
const searchPluginsEmpty = (searchPlugins.length === 0);
if (!searchPluginsEmpty) {
@@ -656,14 +665,14 @@ window.qBittorrent.Search ??= (() => {
allPlugins.each((plugin) => {
if (plugin.enabled === true)
- pluginsHtml.push("");
+ pluginOptions.push(createOption(plugin.fullName, plugin.name));
});
- if (pluginsHtml.length > 2)
- pluginsHtml.splice(2, 0, "");
+ if (pluginOptions.length > 2)
+ pluginOptions.splice(2, 0, createOption("──────────", undefined, true));
}
- $("pluginsSelect").innerHTML = pluginsHtml.join("");
+ $("pluginsSelect").replaceChildren(...pluginOptions);
$("searchPattern").disabled = searchPluginsEmpty;
$("categorySelect").disabled = searchPluginsEmpty;