mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-20 05:13:30 -07:00
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:
parent
7031c52d16
commit
5a0914e333
2 changed files with 107 additions and 131 deletions
|
@ -46,31 +46,24 @@ window.qBittorrent.ContextMenu ??= (() => {
|
||||||
};
|
};
|
||||||
|
|
||||||
let lastShownContextMenu = null;
|
let lastShownContextMenu = null;
|
||||||
const ContextMenu = new Class({
|
class ContextMenu {
|
||||||
// implements
|
constructor(options) {
|
||||||
Implements: [Options, Events],
|
this.options = {
|
||||||
|
actions: {},
|
||||||
// options
|
menu: "menu_id",
|
||||||
options: {
|
stopEvent: true,
|
||||||
actions: {},
|
targets: "body",
|
||||||
menu: "menu_id",
|
offsets: {
|
||||||
stopEvent: true,
|
x: 0,
|
||||||
targets: "body",
|
y: 0
|
||||||
offsets: {
|
},
|
||||||
x: 0,
|
onShow: () => {},
|
||||||
y: 0
|
onHide: () => {},
|
||||||
},
|
onClick: () => {},
|
||||||
onShow: () => {},
|
fadeSpeed: 200,
|
||||||
onHide: () => {},
|
touchTimer: 600,
|
||||||
onClick: () => {},
|
...options
|
||||||
fadeSpeed: 200,
|
};
|
||||||
touchTimer: 600
|
|
||||||
},
|
|
||||||
|
|
||||||
// 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();
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -291,21 +291,18 @@ 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,
|
for (let i = 0; i < this.dynamicTable.columns.length; ++i) {
|
||||||
updateMenuItems: function() {
|
if (this.dynamicTable.columns[i].caption === "")
|
||||||
for (let i = 0; i < this.dynamicTable.columns.length; ++i) {
|
continue;
|
||||||
if (this.dynamicTable.columns[i].caption === "")
|
if (this.dynamicTable.columns[i].visible !== "0")
|
||||||
continue;
|
this.setItemChecked(this.dynamicTable.columns[i].name, true);
|
||||||
if (this.dynamicTable.columns[i].visible !== "0")
|
else
|
||||||
this.setItemChecked(this.dynamicTable.columns[i].name, true);
|
this.setItemChecked(this.dynamicTable.columns[i].name, false);
|
||||||
else
|
|
||||||
this.setItemChecked(this.dynamicTable.columns[i].name, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
showColumn: function(columnName, show) {
|
showColumn: function(columnName, show) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue