WebUI: Use modern class syntax in context menu classes

Context menu classes are now created using vanilla JS syntax (minimal changes to reduce MooTools bits).

PR #21598.
This commit is contained in:
skomerko 2024-10-19 10:32:20 +02:00 committed by GitHub
commit 5a0914e333
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 107 additions and 131 deletions

View file

@ -46,12 +46,9 @@ window.qBittorrent.ContextMenu ??= (() => {
}; };
let lastShownContextMenu = null; let lastShownContextMenu = null;
const ContextMenu = new Class({ class ContextMenu {
// implements constructor(options) {
Implements: [Options, Events], this.options = {
// options
options: {
actions: {}, actions: {},
menu: "menu_id", menu: "menu_id",
stopEvent: true, stopEvent: true,
@ -64,13 +61,9 @@ window.qBittorrent.ContextMenu ??= (() => {
onHide: () => {}, onHide: () => {},
onClick: () => {}, onClick: () => {},
fadeSpeed: 200, fadeSpeed: 200,
touchTimer: 600 touchTimer: 600,
}, ...options
};
// initialization
initialize: function(options) {
// set options
this.setOptions(options);
// option diffs menu // option diffs menu
this.menu = $(this.options.menu); this.menu = $(this.options.menu);
@ -92,9 +85,9 @@ window.qBittorrent.ContextMenu ??= (() => {
this.menu.style.position = "absolute"; this.menu.style.position = "absolute";
this.menu.style.top = "-900000px"; this.menu.style.top = "-900000px";
this.menu.style.display = "block"; this.menu.style.display = "block";
}, }
adjustMenuPosition: function(e) { adjustMenuPosition(e) {
this.updateMenuItems(); this.updateMenuItems();
const scrollableMenuMaxHeight = document.documentElement.clientHeight * 0.75; const scrollableMenuMaxHeight = document.documentElement.clientHeight * 0.75;
@ -144,9 +137,9 @@ window.qBittorrent.ContextMenu ??= (() => {
ul.style.marginLeft = `${xPos - xPosOrigin}px`; ul.style.marginLeft = `${xPos - xPosOrigin}px`;
ul.style.marginTop = `${yPos - yPosOrigin}px`; ul.style.marginTop = `${yPos - yPosOrigin}px`;
} }
}, }
setupEventListeners: function(elem) { setupEventListeners(elem) {
elem.addEventListener("contextmenu", (e) => { elem.addEventListener("contextmenu", (e) => {
this.triggerMenu(e, elem); this.triggerMenu(e, elem);
}); });
@ -171,21 +164,21 @@ window.qBittorrent.ContextMenu ??= (() => {
if (((now - touchStartAt) >= this.options.touchTimer) && isTargetUnchanged) if (((now - touchStartAt) >= this.options.touchTimer) && isTargetUnchanged)
this.triggerMenu(touchStartEvent, elem); this.triggerMenu(touchStartEvent, elem);
}, { passive: true }); }, { passive: true });
}, }
addTarget: function(t) { addTarget(t) {
// prevent long press from selecting this text // prevent long press from selecting this text
t.style.userSelect = "none"; t.style.userSelect = "none";
this.targets[this.targets.length] = t; this.targets[this.targets.length] = t;
this.setupEventListeners(t); this.setupEventListeners(t);
}, }
searchAndAddTargets: function() { searchAndAddTargets() {
document.querySelectorAll(this.options.targets).forEach((target) => { this.addTarget(target); }); document.querySelectorAll(this.options.targets).forEach((target) => { this.addTarget(target); });
}, }
triggerMenu: function(e, el) { triggerMenu(e, el) {
if (this.options.disabled) if (this.options.disabled)
return; return;
@ -199,10 +192,10 @@ window.qBittorrent.ContextMenu ??= (() => {
this.adjustMenuPosition(e); this.adjustMenuPosition(e);
// show the menu // show the menu
this.show(); this.show();
}, }
// get things started // get things started
startListener: function() { startListener() {
/* all elements */ /* all elements */
this.targets.each((el) => { this.targets.each((el) => {
this.setupEventListeners(el); this.setupEventListeners(el);
@ -218,7 +211,7 @@ window.qBittorrent.ContextMenu ??= (() => {
if (!menuItem.classList.contains("disabled")) { if (!menuItem.classList.contains("disabled")) {
const anchor = menuItem.firstElementChild; const anchor = menuItem.firstElementChild;
this.execute(anchor.href.split("#")[1], this.options.element); this.execute(anchor.href.split("#")[1], this.options.element);
this.fireEvent("click", [anchor, e]); this.options.onClick.call(this, anchor, e);
} }
else { else {
e.stopPropagation(); e.stopPropagation();
@ -229,107 +222,103 @@ window.qBittorrent.ContextMenu ??= (() => {
$(document.body).addEventListener("click", () => { $(document.body).addEventListener("click", () => {
this.hide(); this.hide();
}); });
}, }
updateMenuItems: function() {}, updateMenuItems() {}
// show menu // show menu
show: function(trigger) { show(trigger) {
if (lastShownContextMenu && (lastShownContextMenu !== this)) if (lastShownContextMenu && (lastShownContextMenu !== this))
lastShownContextMenu.hide(); lastShownContextMenu.hide();
this.fx.start(1); this.fx.start(1);
this.fireEvent("show"); this.options.onShow.call(this);
lastShownContextMenu = this; lastShownContextMenu = this;
return this; return this;
}, }
// hide the menu // hide the menu
hide: function(trigger) { hide(trigger) {
if (lastShownContextMenu && (lastShownContextMenu.menu.style.visibility !== "hidden")) { if (lastShownContextMenu && (lastShownContextMenu.menu.style.visibility !== "hidden")) {
this.fx.start(0); this.fx.start(0);
// this.menu.fade('out'); this.options.onHide.call(this);
this.fireEvent("hide");
} }
return this; return this;
}, }
setItemChecked: function(item, checked) { setItemChecked(item, checked) {
this.menu.getElement("a[href$=" + item + "]").firstChild.style.opacity = this.menu.getElement("a[href$=" + item + "]").firstChild.style.opacity =
checked ? "1" : "0"; checked ? "1" : "0";
return this; return this;
}, }
getItemChecked: function(item) { getItemChecked(item) {
return this.menu.getElement("a[href$=" + item + "]").firstChild.style.opacity !== "0"; return this.menu.getElement("a[href$=" + item + "]").firstChild.style.opacity !== "0";
}, }
// hide an item // hide an item
hideItem: function(item) { hideItem(item) {
this.menu.getElement("a[href$=" + item + "]").parentNode.addClass("invisible"); this.menu.getElement("a[href$=" + item + "]").parentNode.addClass("invisible");
return this; return this;
}, }
// show an item // show an item
showItem: function(item) { showItem(item) {
this.menu.getElement("a[href$=" + item + "]").parentNode.removeClass("invisible"); this.menu.getElement("a[href$=" + item + "]").parentNode.removeClass("invisible");
return this; return this;
}, }
// enable/disable an item // enable/disable an item
setEnabled: function(item, enabled) { setEnabled(item, enabled) {
this.menu.querySelector(`:scope a[href$="${item}"]`).parentElement.classList.toggle("disabled", !enabled); this.menu.querySelector(`:scope a[href$="${item}"]`).parentElement.classList.toggle("disabled", !enabled);
return this; return this;
}, }
// disable the entire menu // disable the entire menu
disable: function() { disable() {
this.options.disabled = true; this.options.disabled = true;
return this; return this;
}, }
// enable the entire menu // enable the entire menu
enable: function() { enable() {
this.options.disabled = false; this.options.disabled = false;
return this; return this;
}, }
// execute an action // execute an action
execute: function(action, element) { execute(action, element) {
if (this.options.actions[action]) if (this.options.actions[action])
this.options.actions[action](element, this, action); this.options.actions[action](element, this, action);
return this; return this;
} }
}); };
const FilterListContextMenu = new Class({ class FilterListContextMenu extends ContextMenu {
Extends: ContextMenu, constructor(options) {
initialize: function(options) { super(options);
this.parent(options);
this.torrentObserver = new MutationObserver((records, observer) => { this.torrentObserver = new MutationObserver((records, observer) => {
this.updateTorrentActions(); this.updateTorrentActions();
}); });
}, }
startTorrentObserver: function() { startTorrentObserver() {
this.torrentObserver.observe(torrentsTable.tableBody, { childList: true }); this.torrentObserver.observe(torrentsTable.tableBody, { childList: true });
}, }
stopTorrentObserver: function() { stopTorrentObserver() {
this.torrentObserver.disconnect(); this.torrentObserver.disconnect();
}, }
updateTorrentActions: function() { updateTorrentActions() {
const torrentsVisible = torrentsTable.tableBody.children.length > 0; const torrentsVisible = torrentsTable.tableBody.children.length > 0;
this.setEnabled("startTorrents", torrentsVisible) this.setEnabled("startTorrents", torrentsVisible)
.setEnabled("stopTorrents", torrentsVisible) .setEnabled("stopTorrents", torrentsVisible)
.setEnabled("deleteTorrents", torrentsVisible); .setEnabled("deleteTorrents", torrentsVisible);
} }
}); };
const TorrentsTableContextMenu = new Class({ class TorrentsTableContextMenu extends ContextMenu {
Extends: ContextMenu, updateMenuItems() {
updateMenuItems: function() {
let all_are_seq_dl = true; let all_are_seq_dl = true;
let there_are_seq_dl = false; let there_are_seq_dl = false;
let all_are_f_l_piece_prio = true; let all_are_f_l_piece_prio = true;
@ -485,9 +474,9 @@ window.qBittorrent.ContextMenu ??= (() => {
const isEqual = ((count !== undefined) && (count === selectedRows.length)); const isEqual = ((count !== undefined) && (count === selectedRows.length));
categoryIcon.classList.toggle("highlightedCategoryIcon", isEqual); categoryIcon.classList.toggle("highlightedCategoryIcon", isEqual);
}); });
}, }
updateCategoriesSubMenu: function(categoryList) { updateCategoriesSubMenu(categoryList) {
const contextCategoryList = $("contextCategoryList"); const contextCategoryList = $("contextCategoryList");
contextCategoryList.getChildren().each(c => c.destroy()); contextCategoryList.getChildren().each(c => c.destroy());
@ -540,9 +529,9 @@ window.qBittorrent.ContextMenu ??= (() => {
contextCategoryList.appendChild(setCategoryItem); contextCategoryList.appendChild(setCategoryItem);
} }
}, }
updateTagsSubMenu: function(tagList) { updateTagsSubMenu(tagList) {
const contextTagList = $("contextTagList"); const contextTagList = $("contextTagList");
while (contextTagList.firstChild !== null) while (contextTagList.firstChild !== null)
contextTagList.removeChild(contextTagList.firstChild); contextTagList.removeChild(contextTagList.firstChild);
@ -598,18 +587,16 @@ window.qBittorrent.ContextMenu ??= (() => {
contextTagList.appendChild(setTagItem); contextTagList.appendChild(setTagItem);
} }
} }
}); };
const StatusesFilterContextMenu = new Class({ class StatusesFilterContextMenu extends FilterListContextMenu {
Extends: FilterListContextMenu, updateMenuItems() {
updateMenuItems: function() {
this.updateTorrentActions(); this.updateTorrentActions();
} }
}); };
const CategoriesFilterContextMenu = new Class({ class CategoriesFilterContextMenu extends FilterListContextMenu {
Extends: FilterListContextMenu, updateMenuItems() {
updateMenuItems: function() {
const id = Number(this.options.element.id); const id = Number(this.options.element.id);
if ((id !== CATEGORIES_ALL) && (id !== CATEGORIES_UNCATEGORIZED)) { if ((id !== CATEGORIES_ALL) && (id !== CATEGORIES_UNCATEGORIZED)) {
this.showItem("editCategory"); this.showItem("editCategory");
@ -627,11 +614,10 @@ window.qBittorrent.ContextMenu ??= (() => {
this.updateTorrentActions(); this.updateTorrentActions();
} }
}); };
const TagsFilterContextMenu = new Class({ class TagsFilterContextMenu extends FilterListContextMenu {
Extends: FilterListContextMenu, updateMenuItems() {
updateMenuItems: function() {
const id = Number(this.options.element.id); const id = Number(this.options.element.id);
if ((id !== TAGS_ALL) && (id !== TAGS_UNTAGGED)) if ((id !== TAGS_ALL) && (id !== TAGS_UNTAGGED))
this.showItem("deleteTag"); this.showItem("deleteTag");
@ -640,11 +626,10 @@ window.qBittorrent.ContextMenu ??= (() => {
this.updateTorrentActions(); this.updateTorrentActions();
} }
}); };
const TrackersFilterContextMenu = new Class({ class TrackersFilterContextMenu extends FilterListContextMenu {
Extends: FilterListContextMenu, updateMenuItems() {
updateMenuItems: function() {
const id = Number(this.options.element.id); const id = Number(this.options.element.id);
if ((id !== TRACKERS_ALL) && (id !== TRACKERS_TRACKERLESS)) if ((id !== TRACKERS_ALL) && (id !== TRACKERS_TRACKERLESS))
this.showItem("deleteTracker"); this.showItem("deleteTracker");
@ -653,12 +638,10 @@ window.qBittorrent.ContextMenu ??= (() => {
this.updateTorrentActions(); this.updateTorrentActions();
} }
}); };
const SearchPluginsTableContextMenu = new Class({ class SearchPluginsTableContextMenu extends ContextMenu {
Extends: ContextMenu, updateMenuItems() {
updateMenuItems: function() {
const enabledColumnIndex = function(text) { const enabledColumnIndex = function(text) {
const columns = $("searchPluginsTableFixedHeaderRow").getChildren("th"); const columns = $("searchPluginsTableFixedHeaderRow").getChildren("th");
for (let i = 0; i < columns.length; ++i) { for (let i = 0; i < columns.length; ++i) {
@ -672,11 +655,10 @@ window.qBittorrent.ContextMenu ??= (() => {
this.showItem("Uninstall"); this.showItem("Uninstall");
} }
}); };
const RssFeedContextMenu = new Class({ class RssFeedContextMenu extends ContextMenu {
Extends: ContextMenu, updateMenuItems() {
updateMenuItems: function() {
const selectedRows = window.qBittorrent.Rss.rssFeedTable.selectedRowsIds(); const selectedRows = window.qBittorrent.Rss.rssFeedTable.selectedRowsIds();
this.menu.getElement("a[href$=newSubscription]").parentNode.addClass("separator"); this.menu.getElement("a[href$=newSubscription]").parentNode.addClass("separator");
switch (selectedRows.length) { switch (selectedRows.length) {
@ -746,15 +728,12 @@ window.qBittorrent.ContextMenu ??= (() => {
break; break;
} }
} }
}); };
const RssArticleContextMenu = new Class({ class RssArticleContextMenu extends ContextMenu {};
Extends: ContextMenu
});
const RssDownloaderRuleContextMenu = new Class({ class RssDownloaderRuleContextMenu extends ContextMenu {
Extends: ContextMenu, adjustMenuPosition(e) {
adjustMenuPosition: function(e) {
this.updateMenuItems(); this.updateMenuItems();
// draw the menu off-screen to know the menu dimensions // draw the menu off-screen to know the menu dimensions
@ -774,8 +753,8 @@ window.qBittorrent.ContextMenu ??= (() => {
this.menu.style.top = `${yPosMenu}px`; this.menu.style.top = `${yPosMenu}px`;
this.menu.style.position = "absolute"; this.menu.style.position = "absolute";
this.menu.style.zIndex = "2000"; this.menu.style.zIndex = "2000";
}, }
updateMenuItems: function() { updateMenuItems() {
const selectedRows = window.qBittorrent.RssDownloader.rssDownloaderRulesTable.selectedRowsIds(); const selectedRows = window.qBittorrent.RssDownloader.rssDownloaderRulesTable.selectedRowsIds();
this.showItem("addRule"); this.showItem("addRule");
switch (selectedRows.length) { switch (selectedRows.length) {
@ -799,7 +778,7 @@ window.qBittorrent.ContextMenu ??= (() => {
break; break;
} }
} }
}); };
return exports(); return exports();
})(); })();

View file

@ -291,10 +291,8 @@ window.qBittorrent.DynamicTable ??= (() => {
}, },
setupDynamicTableHeaderContextMenuClass: function() { setupDynamicTableHeaderContextMenuClass: function() {
if (!DynamicTableHeaderContextMenuClass) { DynamicTableHeaderContextMenuClass ??= class extends window.qBittorrent.ContextMenu.ContextMenu {
DynamicTableHeaderContextMenuClass = new Class({ updateMenuItems() {
Extends: window.qBittorrent.ContextMenu.ContextMenu,
updateMenuItems: function() {
for (let i = 0; i < this.dynamicTable.columns.length; ++i) { for (let i = 0; i < this.dynamicTable.columns.length; ++i) {
if (this.dynamicTable.columns[i].caption === "") if (this.dynamicTable.columns[i].caption === "")
continue; continue;
@ -304,8 +302,7 @@ window.qBittorrent.DynamicTable ??= (() => {
this.setItemChecked(this.dynamicTable.columns[i].name, false); this.setItemChecked(this.dynamicTable.columns[i].name, false);
} }
} }
}); };
}
}, },
showColumn: function(columnName, show) { showColumn: function(columnName, show) {