From df8c16acc8ce72e45651bcbc7e52d657b9f4d184 Mon Sep 17 00:00:00 2001 From: CJ Ratliff Date: Tue, 18 Jul 2023 12:24:13 -0400 Subject: [PATCH] Fix for context menu on right click --- private/scripts/contextmenu.js | 1255 +++++++++++++++++--------------- 1 file changed, 660 insertions(+), 595 deletions(-) diff --git a/private/scripts/contextmenu.js b/private/scripts/contextmenu.js index 91c45b0..a053659 100644 --- a/private/scripts/contextmenu.js +++ b/private/scripts/contextmenu.js @@ -26,668 +26,733 @@ * exception statement from your version. */ -'use strict'; +'use strict' if (window.qBittorrent === undefined) { - window.qBittorrent = {}; + window.qBittorrent = {} } -window.qBittorrent.ContextMenu = (function() { - const exports = function() { - return { - ContextMenu: ContextMenu, - TorrentsTableContextMenu: TorrentsTableContextMenu, - CategoriesFilterContextMenu: CategoriesFilterContextMenu, - TagsFilterContextMenu: TagsFilterContextMenu, - SearchPluginsTableContextMenu: SearchPluginsTableContextMenu, - RssFeedContextMenu: RssFeedContextMenu, - RssArticleContextMenu: RssArticleContextMenu, - RssDownloaderRuleContextMenu: RssDownloaderRuleContextMenu - }; - }; +window.qBittorrent.ContextMenu = (function () { + const exports = function () { + return { + ContextMenu: ContextMenu, + TorrentsTableContextMenu: TorrentsTableContextMenu, + CategoriesFilterContextMenu: CategoriesFilterContextMenu, + TagsFilterContextMenu: TagsFilterContextMenu, + SearchPluginsTableContextMenu: SearchPluginsTableContextMenu, + RssFeedContextMenu: RssFeedContextMenu, + RssArticleContextMenu: RssArticleContextMenu, + RssDownloaderRuleContextMenu: RssDownloaderRuleContextMenu, + } + } - let lastShownContextMenu = null; - const ContextMenu = new Class({ - //implements - Implements: [Options, Events], + let lastShownContextMenu = null + const ContextMenu = new Class({ + //implements + Implements: [Options, Events], - //options - options: { - actions: {}, - menu: 'menu_id', - stopEvent: true, - targets: 'body', - offsets: { - x: 0, - y: 0 - }, - onShow: $empty, - onHide: $empty, - onClick: $empty, - fadeSpeed: 200, - touchTimer: 600 - }, + //options + options: { + actions: {}, + menu: 'menu_id', + stopEvent: true, + targets: 'body', + offsets: { + x: 0, + y: 0, + }, + onShow: $empty, + onHide: $empty, + onClick: $empty, + fadeSpeed: 200, + touchTimer: 600, + }, - //initialization - initialize: function(options) { - //set options - this.setOptions(options); + //initialization + initialize: function (options) { + //set options + this.setOptions(options) - //option diffs menu - this.menu = $(this.options.menu); - this.targets = $$(this.options.targets); + //option diffs menu + this.menu = $(this.options.menu) + this.targets = $$(this.options.targets) - //fx - this.fx = new Fx.Tween(this.menu, { - property: 'opacity', - duration: this.options.fadeSpeed, - onComplete: function() { - if (this.getStyle('opacity')) { - this.setStyle('visibility', 'visible'); - } - else { - this.setStyle('visibility', 'hidden'); - } - }.bind(this.menu) - }); + //fx + this.fx = new Fx.Tween(this.menu, { + property: 'opacity', + duration: this.options.fadeSpeed, + onComplete: function () { + if (this.getStyle('opacity')) { + this.setStyle('visibility', 'visible') + } else { + this.setStyle('visibility', 'hidden') + } + }.bind(this.menu), + }) - //hide and begin the listener - this.hide().startListener(); + //hide and begin the listener + this.hide().startListener() - //hide the menu - this.menu.setStyles({ - 'position': 'absolute', - 'top': '-900000px', - 'display': 'block' - }); - }, + //hide the menu + this.menu.setStyles({ + position: 'absolute', + top: '-900000px', + display: 'block', + }) + }, - adjustMenuPosition: function(e) { - this.updateMenuItems(); + adjustMenuPosition: function (e) { + this.updateMenuItems() - const scrollableMenuMaxHeight = document.documentElement.clientHeight * 0.75; + const scrollableMenuMaxHeight = + document.documentElement.clientHeight * 0.75 - if (this.menu.hasClass('scrollableMenu')) - this.menu.setStyle('max-height', scrollableMenuMaxHeight); + if (this.menu.hasClass('scrollableMenu')) + this.menu.setStyle('max-height', scrollableMenuMaxHeight) - // draw the menu off-screen to know the menu dimensions - this.menu.setStyles({ - left: '-999em', - top: '-999em' - }); + // draw the menu off-screen to know the menu dimensions + this.menu.setStyles({ + left: '-999em', + top: '-999em', + }) - // position the menu - let xPosMenu = e.page.x + this.options.offsets.x; - let yPosMenu = e.page.y + this.options.offsets.y; - if (xPosMenu + this.menu.offsetWidth > document.documentElement.clientWidth) - xPosMenu -= this.menu.offsetWidth; - if (yPosMenu + this.menu.offsetHeight > document.documentElement.clientHeight) - yPosMenu = document.documentElement.clientHeight - this.menu.offsetHeight; - if (xPosMenu < 0) - xPosMenu = 0; - if (yPosMenu < 0) - yPosMenu = 0; - this.menu.setStyles({ - left: xPosMenu, - top: yPosMenu, - position: 'absolute', - 'z-index': '2000' - }); + // position the menu + let xPosMenu = e.page.x + this.options.offsets.x + let yPosMenu = e.page.y + this.options.offsets.y + if ( + xPosMenu + this.menu.offsetWidth > + document.documentElement.clientWidth + ) + xPosMenu -= this.menu.offsetWidth + if ( + yPosMenu + this.menu.offsetHeight > + document.documentElement.clientHeight + ) + yPosMenu = + document.documentElement.clientHeight - this.menu.offsetHeight + if (xPosMenu < 0) xPosMenu = 0 + if (yPosMenu < 0) yPosMenu = 0 + this.menu.setStyles({ + left: xPosMenu, + top: yPosMenu, + position: 'absolute', + 'z-index': '2000', + }) - // position the sub-menu - const uls = this.menu.getElementsByTagName('ul'); - for (let i = 0; i < uls.length; ++i) { - const ul = uls[i]; - if (ul.hasClass('scrollableMenu')) - ul.setStyle('max-height', scrollableMenuMaxHeight); - const rectParent = ul.parentNode.getBoundingClientRect(); - const xPosOrigin = rectParent.left; - const yPosOrigin = rectParent.bottom; - let xPos = xPosOrigin + rectParent.width - 1; - let yPos = yPosOrigin - rectParent.height - 1; - if (xPos + ul.offsetWidth > document.documentElement.clientWidth) - xPos -= (ul.offsetWidth + rectParent.width - 2); - if (yPos + ul.offsetHeight > document.documentElement.clientHeight) - yPos = document.documentElement.clientHeight - ul.offsetHeight; - if (xPos < 0) - xPos = 0; - if (yPos < 0) - yPos = 0; - ul.setStyles({ - 'margin-left': xPos - xPosOrigin, - 'margin-top': yPos - yPosOrigin - }); + // position the sub-menu + const uls = this.menu.getElementsByTagName('ul') + for (let i = 0; i < uls.length; ++i) { + const ul = uls[i] + if (ul.hasClass('scrollableMenu')) + ul.setStyle('max-height', scrollableMenuMaxHeight) + const rectParent = ul.parentNode.getBoundingClientRect() + const xPosOrigin = rectParent.left + const yPosOrigin = rectParent.bottom + let xPos = xPosOrigin + rectParent.width - 1 + let yPos = yPosOrigin - rectParent.height - 1 + if (xPos + ul.offsetWidth > document.documentElement.clientWidth) + xPos -= ul.offsetWidth + rectParent.width - 2 + if (yPos + ul.offsetHeight > document.documentElement.clientHeight) + yPos = document.documentElement.clientHeight - ul.offsetHeight + if (xPos < 0) xPos = 0 + if (yPos < 0) yPos = 0 + ul.setStyles({ + 'margin-left': xPos - xPosOrigin, + 'margin-top': yPos - yPosOrigin, + }) + } + }, + + setupEventListeners: function (elem) { + elem.addEvent( + 'contextmenu', + function (e) { + this.triggerMenu(e, elem) + }.bind(this) + ) + elem.addEvent( + 'click', + function (e) { + this.hide() + }.bind(this) + ) + + elem.addEvent( + 'touchstart', + function (e) { + e.preventDefault() + clearTimeout(this.touchstartTimer) + this.hide() + + const touchstartEvent = e + this.touchstartTimer = setTimeout( + function () { + this.triggerMenu(touchstartEvent, elem) + }.bind(this), + this.options.touchTimer + ) + }.bind(this) + ) + elem.addEvent( + 'touchend', + function (e) { + e.preventDefault() + clearTimeout(this.touchstartTimer) + }.bind(this) + ) + }, + + addTarget: function (t) { + this.targets[this.targets.length] = t + this.setupEventListeners(t) + }, + + triggerMenu: function (e, el) { + if (this.options.disabled) return + + //prevent default, if told to + if (this.options.stopEvent) { + e.stop() + } + //record this as the trigger + this.options.element = $(el) + this.adjustMenuPosition(e) + //show the menu + this.show() + }, + + //get things started + startListener: function () { + /* all elements */ + this.targets.each( + function (el) { + this.setupEventListeners(el) + }.bind(this), + this + ) + + /* menu items */ + this.menu.getElements('a').each(function (item) { + item.addEvent( + 'click', + function (e) { + e.preventDefault() + if (!item.hasClass('disabled')) { + this.execute( + item.get('href').split('#')[1], + $(this.options.element) + ) + this.fireEvent('click', [item, e]) } - }, + }.bind(this) + ) + }, this) - setupEventListeners: function(elem) { - elem.addEvent('contextmenu', function(e) { - this.triggerMenu(e, elem); - }.bind(this)); - elem.addEvent('click', function(e) { - this.hide(); - }.bind(this)); + //hide on body click + $(document.body).addEvent( + 'click', + function () { + this.hide() + }.bind(this) + ) + }, - elem.addEvent('touchstart', function(e) { - e.preventDefault(); - clearTimeout(this.touchstartTimer); - this.hide(); + updateMenuItems: function () {}, - const touchstartEvent = e; - this.touchstartTimer = setTimeout(function() { - this.triggerMenu(touchstartEvent, elem); - }.bind(this), this.options.touchTimer); - }.bind(this)); - elem.addEvent('touchend', function(e) { - e.preventDefault(); - clearTimeout(this.touchstartTimer); - }.bind(this)); - }, + //show menu + show: function (trigger) { + if (lastShownContextMenu && lastShownContextMenu != this) + lastShownContextMenu.hide() + this.fx.start(1) + this.fireEvent('show') + this.shown = true + lastShownContextMenu = this + return this + }, - addTarget: function(t) { - this.targets[this.targets.length] = t; - this.setupEventListeners(t); - }, + //hide the menu + hide: function (trigger) { + if (this.shown) { + this.fx.start(0) + //this.menu.fade('out'); + this.fireEvent('hide') + this.shown = false + } + return this + }, - triggerMenu: function(e, el) { - if (this.options.disabled) - return; + setItemChecked: function (item, checked) { + this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity = + checked ? '1' : '0' + return this + }, - //prevent default, if told to - if (this.options.stopEvent) { - e.stop(); - } - //record this as the trigger - this.options.element = $(el); - this.adjustMenuPosition(e); - //show the menu - this.show(); - }, + getItemChecked: function (item) { + return ( + '0' != + this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity + ) + }, - //get things started - startListener: function() { - /* all elements */ - this.targets.each(function(el) { - this.setupEventListeners(el); - }.bind(this), this); + //hide an item + hideItem: function (item) { + this.menu + .getElement('a[href$=' + item + ']') + .parentNode.addClass('invisible') + return this + }, - /* menu items */ - this.menu.getElements('a').each(function(item) { - item.addEvent('click', function(e) { - e.preventDefault(); - if (!item.hasClass('disabled')) { - this.execute(item.get('href').split('#')[1], $(this.options.element)); - this.fireEvent('click', [item, e]); - } - }.bind(this)); - }, this); + //show an item + showItem: function (item) { + if (this.menu.getElement('a[href$=' + item + ']')) { + this.menu + .getElement('a[href$=' + item + ']') + .parentNode.removeClass('invisible') + } + return this + }, - //hide on body click - $(document.body).addEvent('click', function() { - this.hide(); - }.bind(this)); - }, + //disable the entire menu + disable: function () { + this.options.disabled = true + return this + }, - updateMenuItems: function() {}, + //enable the entire menu + enable: function () { + this.options.disabled = false + return this + }, - //show menu - show: function(trigger) { - if (lastShownContextMenu && lastShownContextMenu != this) - lastShownContextMenu.hide(); - this.fx.start(1); - this.fireEvent('show'); - this.shown = true; - lastShownContextMenu = this; - return this; - }, + //execute an action + execute: function (action, element) { + if (this.options.actions[action]) { + this.options.actions[action](element, this, action) + } + return this + }, + }) - //hide the menu - hide: function(trigger) { - if (this.shown) { - this.fx.start(0); - //this.menu.fade('out'); - this.fireEvent('hide'); - this.shown = false; - } - return this; - }, + const TorrentsTableContextMenu = new Class({ + Extends: ContextMenu, - setItemChecked: function(item, checked) { - this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity = - checked ? '1' : '0'; - return this; - }, + updateMenuItems: function () { + let all_are_seq_dl = true + let there_are_seq_dl = false + let all_are_f_l_piece_prio = true + let there_are_f_l_piece_prio = false + let all_are_downloaded = true + let all_are_paused = true + let there_are_paused = false + let all_are_force_start = true + let there_are_force_start = false + let all_are_super_seeding = true + let all_are_auto_tmm = true + let there_are_auto_tmm = false + const tagsSelectionState = Object.clone(tagList) - getItemChecked: function(item) { - return '0' != this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity; - }, + const h = torrentsTable.selectedRowsIds() + h.each(function (item, index) { + const data = torrentsTable.rows.get(item).full_data - //hide an item - hideItem: function(item) { - this.menu.getElement('a[href$=' + item + ']').parentNode.addClass('invisible'); - return this; - }, + if (data['seq_dl'] !== true) all_are_seq_dl = false + else there_are_seq_dl = true - //show an item - showItem: function(item) { - this.menu.getElement('a[href$=' + item + ']').parentNode.removeClass('invisible'); - return this; - }, + if (data['f_l_piece_prio'] !== true) all_are_f_l_piece_prio = false + else there_are_f_l_piece_prio = true - //disable the entire menu - disable: function() { - this.options.disabled = true; - return this; - }, + if (data['progress'] != 1.0) + // not downloaded + all_are_downloaded = false + else if (data['super_seeding'] !== true) all_are_super_seeding = false - //enable the entire menu - enable: function() { - this.options.disabled = false; - return this; - }, + if (data['state'] != 'pausedUP' && data['state'] != 'pausedDL') + all_are_paused = false + else there_are_paused = true - //execute an action - execute: function(action, element) { - if (this.options.actions[action]) { - this.options.actions[action](element, this, action); - } - return this; + if (data['force_start'] !== true) all_are_force_start = false + else there_are_force_start = true + + if (data['auto_tmm'] === true) there_are_auto_tmm = true + else 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 } - }); + }) - const TorrentsTableContextMenu = new Class({ - Extends: ContextMenu, + let show_seq_dl = true - updateMenuItems: function() { - let all_are_seq_dl = true; - let there_are_seq_dl = false; - let all_are_f_l_piece_prio = true; - let there_are_f_l_piece_prio = false; - let all_are_downloaded = true; - let all_are_paused = true; - let there_are_paused = false; - let all_are_force_start = true; - let there_are_force_start = false; - let all_are_super_seeding = true; - let all_are_auto_tmm = true; - let there_are_auto_tmm = false; - const tagsSelectionState = Object.clone(tagList); + // hide renameFiles when more than 1 torrent is selected + if (h.length == 1) { + const data = torrentsTable.rows.get(h[0]).full_data + let metadata_downloaded = !( + data['state'] == 'metaDL' || + data['state'] == 'forcedMetaDL' || + data['total_size'] == -1 + ) - const h = torrentsTable.selectedRowsIds(); - h.each(function(item, index) { - const data = torrentsTable.rows.get(item).full_data; + // hide renameFiles when metadata hasn't been downloaded yet + metadata_downloaded + ? this.showItem('renameFiles') + : this.hideItem('renameFiles') + } else this.hideItem('renameFiles') - if (data['seq_dl'] !== true) - all_are_seq_dl = false; - else - there_are_seq_dl = true; + if (!all_are_seq_dl && there_are_seq_dl) show_seq_dl = false - if (data['f_l_piece_prio'] !== true) - all_are_f_l_piece_prio = false; - else - there_are_f_l_piece_prio = true; + let show_f_l_piece_prio = true - if (data['progress'] != 1.0) // not downloaded - all_are_downloaded = false; - else if (data['super_seeding'] !== true) - all_are_super_seeding = false; + if (!all_are_f_l_piece_prio && there_are_f_l_piece_prio) + show_f_l_piece_prio = false - if (data['state'] != 'pausedUP' && data['state'] != 'pausedDL') - all_are_paused = false; - else - there_are_paused = true; + if (all_are_downloaded) { + this.hideItem('downloadLimit') + this.menu + .getElement('a[href$=uploadLimit]') + .parentNode.addClass('separator') + this.hideItem('sequentialDownload') + this.hideItem('firstLastPiecePrio') + this.showItem('superSeeding') + this.setItemChecked('superSeeding', all_are_super_seeding) + } else { + if (!show_seq_dl && show_f_l_piece_prio) + this.menu + .getElement('a[href$=firstLastPiecePrio]') + .parentNode.addClass('separator') + else + this.menu + .getElement('a[href$=firstLastPiecePrio]') + .parentNode.removeClass('separator') - if (data['force_start'] !== true) - all_are_force_start = false; - else - there_are_force_start = true; + if (show_seq_dl) this.showItem('sequentialDownload') + else this.hideItem('sequentialDownload') - if (data['auto_tmm'] === true) - there_are_auto_tmm = true; - else - all_are_auto_tmm = false; + if (show_f_l_piece_prio) this.showItem('firstLastPiecePrio') + else this.hideItem('firstLastPiecePrio') - 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; - } - }); + this.setItemChecked('sequentialDownload', all_are_seq_dl) + this.setItemChecked('firstLastPiecePrio', all_are_f_l_piece_prio) - let show_seq_dl = true; + this.showItem('downloadLimit') + this.menu + .getElement('a[href$=uploadLimit]') + .parentNode.removeClass('separator') + this.hideItem('superSeeding') + } - // hide renameFiles when more than 1 torrent is selected - if (h.length == 1) { - const data = torrentsTable.rows.get(h[0]).full_data; - let metadata_downloaded = !(data['state'] == 'metaDL' || data['state'] == 'forcedMetaDL' || data['total_size'] == -1); + this.showItem('start') + this.showItem('pause') + this.showItem('forceStart') + if (all_are_paused) this.hideItem('pause') + else if (all_are_force_start) this.hideItem('forceStart') + else if (!there_are_paused && !there_are_force_start) + this.hideItem('start') - // hide renameFiles when metadata hasn't been downloaded yet - metadata_downloaded - ? this.showItem('renameFiles') - : this.hideItem('renameFiles'); - } - else - this.hideItem('renameFiles'); + if (!all_are_auto_tmm && there_are_auto_tmm) { + this.hideItem('autoTorrentManagement') + } else { + this.showItem('autoTorrentManagement') + this.setItemChecked('autoTorrentManagement', all_are_auto_tmm) + } - if (!all_are_seq_dl && there_are_seq_dl) - show_seq_dl = false; + 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 + } + }, - let show_f_l_piece_prio = true; + updateCategoriesSubMenu: function (category_list) { + const categoryList = $('contextCategoryList') + categoryList.empty() + categoryList.appendChild( + new Element('li', { + html: 'New...)QBT_TR[CONTEXT=TransferListWidget] QBT_TR(New...', + }) + ) + categoryList.appendChild( + new Element('li', { + html: 'Reset)QBT_TR[CONTEXT=TransferListWidget] QBT_TR(Reset', + }) + ) - if (!all_are_f_l_piece_prio && there_are_f_l_piece_prio) - show_f_l_piece_prio = false; + const sortedCategories = [] + Object.each(category_list, function (category) { + sortedCategories.push(category.name) + }) + sortedCategories.sort() - if (all_are_downloaded) { - this.hideItem('downloadLimit'); - this.menu.getElement('a[href$=uploadLimit]').parentNode.addClass('separator'); - this.hideItem('sequentialDownload'); - this.hideItem('firstLastPiecePrio'); - this.showItem('superSeeding'); - this.setItemChecked('superSeeding', all_are_super_seeding); - } - else { - if (!show_seq_dl && show_f_l_piece_prio) - this.menu.getElement('a[href$=firstLastPiecePrio]').parentNode.addClass('separator'); - else - this.menu.getElement('a[href$=firstLastPiecePrio]').parentNode.removeClass('separator'); - - if (show_seq_dl) - this.showItem('sequentialDownload'); - else - this.hideItem('sequentialDownload'); - - if (show_f_l_piece_prio) - this.showItem('firstLastPiecePrio'); - else - this.hideItem('firstLastPiecePrio'); - - this.setItemChecked('sequentialDownload', all_are_seq_dl); - this.setItemChecked('firstLastPiecePrio', all_are_f_l_piece_prio); - - this.showItem('downloadLimit'); - this.menu.getElement('a[href$=uploadLimit]').parentNode.removeClass('separator'); - this.hideItem('superSeeding'); - } - - this.showItem('start'); - this.showItem('pause'); - this.showItem('forceStart'); - if (all_are_paused) - this.hideItem('pause'); - else if (all_are_force_start) - this.hideItem('forceStart'); - else if (!there_are_paused && !there_are_force_start) - this.hideItem('start'); - - if (!all_are_auto_tmm && there_are_auto_tmm) { - this.hideItem('autoTorrentManagement'); - } - else { - this.showItem('autoTorrentManagement'); - this.setItemChecked('autoTorrentManagement', all_are_auto_tmm); - } - - 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; - } - }, - - updateCategoriesSubMenu: function(category_list) { - const categoryList = $('contextCategoryList'); - categoryList.empty(); - categoryList.appendChild(new Element('li', { - html: 'New...)QBT_TR[CONTEXT=TransferListWidget] QBT_TR(New...' - })); - categoryList.appendChild(new Element('li', { - html: 'Reset)QBT_TR[CONTEXT=TransferListWidget] QBT_TR(Reset' - })); - - const sortedCategories = []; - Object.each(category_list, function(category) { - sortedCategories.push(category.name); - }); - sortedCategories.sort(); - - let first = true; - Object.each(sortedCategories, function(categoryName) { - const categoryHash = genHash(categoryName); - const el = new Element('li', { - html: ' ' + window.qBittorrent.Misc.escapeHtml(categoryName) + '' - }); - if (first) { - el.addClass('separator'); - first = false; - } - categoryList.appendChild(el); - }); - }, - - updateTagsSubMenu: function(tagList) { - const contextTagList = $('contextTagList'); - while (contextTagList.firstChild !== null) - contextTagList.removeChild(contextTagList.firstChild); - - contextTagList.appendChild(new Element('li', { - html: '' - + 'Add...' - + ' Add...' - + '' - })); - contextTagList.appendChild(new Element('li', { - html: '' - + 'Remove All' - + ' Remove All' - + '' - })); - - const sortedTags = []; - for (const key in tagList) - sortedTags.push(tagList[key].name); - sortedTags.sort(); - - for (let i = 0; i < sortedTags.length; ++i) { - const tagName = sortedTags[i]; - const tagHash = genHash(tagName); - const el = new Element('li', { - html: '' - + ' ' + window.qBittorrent.Misc.escapeHtml(tagName) - + '' - }); - if (i === 0) - el.addClass('separator'); - contextTagList.appendChild(el); - } + let first = true + Object.each(sortedCategories, function (categoryName) { + const categoryHash = genHash(categoryName) + const el = new Element('li', { + html: + ' ' + + window.qBittorrent.Misc.escapeHtml(categoryName) + + '', + }) + if (first) { + el.addClass('separator') + first = false } - }); + categoryList.appendChild(el) + }) + }, - const CategoriesFilterContextMenu = new Class({ - Extends: ContextMenu, - updateMenuItems: function() { - const id = this.options.element.id; - if ((id != CATEGORIES_ALL) && (id != CATEGORIES_UNCATEGORIZED)) { - this.showItem('editCategory'); - this.showItem('deleteCategory'); - if (useSubcategories) { - this.showItem('createSubcategory'); - } - else { - this.hideItem('createSubcategory'); - } - } - else { - this.hideItem('editCategory'); - this.hideItem('deleteCategory'); - this.hideItem('createSubcategory'); - } + updateTagsSubMenu: function (tagList) { + const contextTagList = $('contextTagList') + while (contextTagList.firstChild !== null) + contextTagList.removeChild(contextTagList.firstChild) + + contextTagList.appendChild( + new Element('li', { + html: + '' + + 'Add...' + + ' Add...' + + '', + }) + ) + contextTagList.appendChild( + new Element('li', { + html: + '' + + 'Remove All' + + ' Remove All' + + '', + }) + ) + + const sortedTags = [] + for (const key in tagList) sortedTags.push(tagList[key].name) + sortedTags.sort() + + for (let i = 0; i < sortedTags.length; ++i) { + const tagName = sortedTags[i] + const tagHash = genHash(tagName) + const el = new Element('li', { + html: + '" + + ' ' + + window.qBittorrent.Misc.escapeHtml(tagName) + + '', + }) + if (i === 0) el.addClass('separator') + contextTagList.appendChild(el) + } + }, + }) + + const CategoriesFilterContextMenu = new Class({ + Extends: ContextMenu, + updateMenuItems: function () { + const id = this.options.element.id + if (id != CATEGORIES_ALL && id != CATEGORIES_UNCATEGORIZED) { + this.showItem('editCategory') + this.showItem('deleteCategory') + if (useSubcategories) { + this.showItem('createSubcategory') + } else { + this.hideItem('createSubcategory') } - }); + } else { + this.hideItem('editCategory') + this.hideItem('deleteCategory') + this.hideItem('createSubcategory') + } + }, + }) - const TagsFilterContextMenu = new Class({ - Extends: ContextMenu, - updateMenuItems: function() { - const id = this.options.element.id; - if ((id !== TAGS_ALL.toString()) && (id !== TAGS_UNTAGGED.toString())) - this.showItem('deleteTag'); - else - this.hideItem('deleteTag'); - } - }); + const TagsFilterContextMenu = new Class({ + Extends: ContextMenu, + updateMenuItems: function () { + const id = this.options.element.id + if (id !== TAGS_ALL.toString() && id !== TAGS_UNTAGGED.toString()) + this.showItem('deleteTag') + else this.hideItem('deleteTag') + }, + }) - const SearchPluginsTableContextMenu = new Class({ - Extends: ContextMenu, + const SearchPluginsTableContextMenu = new Class({ + Extends: ContextMenu, - updateMenuItems: function() { - const enabledColumnIndex = function(text) { - const columns = $("searchPluginsTableFixedHeaderRow").getChildren("th"); - for (let i = 0; i < columns.length; ++i) - if (columns[i].get("html") === "Enabled") - return i; - }; + updateMenuItems: function () { + const enabledColumnIndex = function (text) { + const columns = $('searchPluginsTableFixedHeaderRow').getChildren('th') + for (let i = 0; i < columns.length; ++i) + if (columns[i].get('html') === 'Enabled') return i + } - this.showItem('Enabled'); - this.setItemChecked('Enabled', this.options.element.getChildren("td")[enabledColumnIndex()].get("html") === "Yes"); + this.showItem('Enabled') + this.setItemChecked( + 'Enabled', + this.options.element + .getChildren('td') + [enabledColumnIndex()].get('html') === 'Yes' + ) - this.showItem('Uninstall'); - } - }); + this.showItem('Uninstall') + }, + }) - const RssFeedContextMenu = new Class({ - Extends: ContextMenu, - updateMenuItems: function() { - let selectedRows = window.qBittorrent.Rss.rssFeedTable.selectedRowsIds(); - this.menu.getElement('a[href$=newSubscription]').parentNode.addClass('separator'); - switch (selectedRows.length) { - case 0: - // remove separator on top of newSubscription entry to avoid double line - this.menu.getElement('a[href$=newSubscription]').parentNode.removeClass('separator'); - // menu when nothing selected - this.hideItem('update'); - this.hideItem('markRead'); - this.hideItem('rename'); - this.hideItem('delete'); - this.showItem('newSubscription'); - this.showItem('newFolder'); - this.showItem('updateAll'); - this.hideItem('copyFeedURL'); - break; - case 1: - if (selectedRows[0] === 0) { - // menu when "unread" feed selected - this.showItem('update'); - this.showItem('markRead'); - this.hideItem('rename'); - this.hideItem('delete'); - this.showItem('newSubscription'); - this.hideItem('newFolder'); - this.hideItem('updateAll'); - this.hideItem('copyFeedURL'); - } - else if (window.qBittorrent.Rss.rssFeedTable.rows[selectedRows[0]].full_data.dataUid === '') { - // menu when single folder selected - this.showItem('update'); - this.showItem('markRead'); - this.showItem('rename'); - this.showItem('delete'); - this.showItem('newSubscription'); - this.showItem('newFolder'); - this.hideItem('updateAll'); - this.hideItem('copyFeedURL'); - } - else { - // menu when single feed selected - this.showItem('update'); - this.showItem('markRead'); - this.showItem('rename'); - this.showItem('delete'); - this.showItem('newSubscription'); - this.hideItem('newFolder'); - this.hideItem('updateAll'); - this.showItem('copyFeedURL'); - } - break; - default: - // menu when multiple items selected - this.showItem('update'); - this.showItem('markRead'); - this.hideItem('rename'); - this.showItem('delete'); - this.hideItem('newSubscription'); - this.hideItem('newFolder'); - this.hideItem('updateAll'); - this.showItem('copyFeedURL'); - break; - } - } - }); + const RssFeedContextMenu = new Class({ + Extends: ContextMenu, + updateMenuItems: function () { + let selectedRows = window.qBittorrent.Rss.rssFeedTable.selectedRowsIds() + this.menu + .getElement('a[href$=newSubscription]') + .parentNode.addClass('separator') + switch (selectedRows.length) { + case 0: + // remove separator on top of newSubscription entry to avoid double line + this.menu + .getElement('a[href$=newSubscription]') + .parentNode.removeClass('separator') + // menu when nothing selected + this.hideItem('update') + this.hideItem('markRead') + this.hideItem('rename') + this.hideItem('delete') + this.showItem('newSubscription') + this.showItem('newFolder') + this.showItem('updateAll') + this.hideItem('copyFeedURL') + break + case 1: + if (selectedRows[0] === 0) { + // menu when "unread" feed selected + this.showItem('update') + this.showItem('markRead') + this.hideItem('rename') + this.hideItem('delete') + this.showItem('newSubscription') + this.hideItem('newFolder') + this.hideItem('updateAll') + this.hideItem('copyFeedURL') + } else if ( + window.qBittorrent.Rss.rssFeedTable.rows[selectedRows[0]].full_data + .dataUid === '' + ) { + // menu when single folder selected + this.showItem('update') + this.showItem('markRead') + this.showItem('rename') + this.showItem('delete') + this.showItem('newSubscription') + this.showItem('newFolder') + this.hideItem('updateAll') + this.hideItem('copyFeedURL') + } else { + // menu when single feed selected + this.showItem('update') + this.showItem('markRead') + this.showItem('rename') + this.showItem('delete') + this.showItem('newSubscription') + this.hideItem('newFolder') + this.hideItem('updateAll') + this.showItem('copyFeedURL') + } + break + default: + // menu when multiple items selected + this.showItem('update') + this.showItem('markRead') + this.hideItem('rename') + this.showItem('delete') + this.hideItem('newSubscription') + this.hideItem('newFolder') + this.hideItem('updateAll') + this.showItem('copyFeedURL') + break + } + }, + }) - const RssArticleContextMenu = new Class({ - Extends: ContextMenu - }); + const RssArticleContextMenu = new Class({ + Extends: ContextMenu, + }) - const RssDownloaderRuleContextMenu = new Class({ - Extends: ContextMenu, - adjustMenuPosition: function(e) { - this.updateMenuItems(); + const RssDownloaderRuleContextMenu = new Class({ + Extends: ContextMenu, + adjustMenuPosition: function (e) { + this.updateMenuItems() - // draw the menu off-screen to know the menu dimensions - this.menu.setStyles({ - left: '-999em', - top: '-999em' - }); - // position the menu - let xPosMenu = e.page.x + this.options.offsets.x - $('rssdownloaderpage').offsetLeft; - let yPosMenu = e.page.y + this.options.offsets.y - $('rssdownloaderpage').offsetTop; - if ((xPosMenu + this.menu.offsetWidth) > document.documentElement.clientWidth) - xPosMenu -= this.menu.offsetWidth; - if ((yPosMenu + this.menu.offsetHeight) > document.documentElement.clientHeight) - yPosMenu = document.documentElement.clientHeight - this.menu.offsetHeight; - xPosMenu = Math.max(xPosMenu, 0); - yPosMenu = Math.max(yPosMenu, 0); + // draw the menu off-screen to know the menu dimensions + this.menu.setStyles({ + left: '-999em', + top: '-999em', + }) + // position the menu + let xPosMenu = + e.page.x + this.options.offsets.x - $('rssdownloaderpage').offsetLeft + let yPosMenu = + e.page.y + this.options.offsets.y - $('rssdownloaderpage').offsetTop + if ( + xPosMenu + this.menu.offsetWidth > + document.documentElement.clientWidth + ) + xPosMenu -= this.menu.offsetWidth + if ( + yPosMenu + this.menu.offsetHeight > + document.documentElement.clientHeight + ) + yPosMenu = + document.documentElement.clientHeight - this.menu.offsetHeight + xPosMenu = Math.max(xPosMenu, 0) + yPosMenu = Math.max(yPosMenu, 0) - this.menu.setStyles({ - left: xPosMenu, - top: yPosMenu, - position: 'absolute', - 'z-index': '2000' - }); - }, - updateMenuItems: function() { - let selectedRows = window.qBittorrent.RssDownloader.rssDownloaderRulesTable.selectedRowsIds(); - this.showItem('addRule'); - switch (selectedRows.length) { - case 0: - // menu when nothing selected - this.hideItem('deleteRule'); - this.hideItem('renameRule'); - this.hideItem('clearDownloadedEpisodes'); - break; - case 1: - // menu when single item selected - this.showItem('deleteRule'); - this.showItem('renameRule'); - this.showItem('clearDownloadedEpisodes'); - break; - default: - // menu when multiple items selected - this.showItem('deleteRule'); - this.hideItem('renameRule'); - this.showItem('clearDownloadedEpisodes'); - break; - } - } - }); + this.menu.setStyles({ + left: xPosMenu, + top: yPosMenu, + position: 'absolute', + 'z-index': '2000', + }) + }, + updateMenuItems: function () { + let selectedRows = + window.qBittorrent.RssDownloader.rssDownloaderRulesTable.selectedRowsIds() + this.showItem('addRule') + switch (selectedRows.length) { + case 0: + // menu when nothing selected + this.hideItem('deleteRule') + this.hideItem('renameRule') + this.hideItem('clearDownloadedEpisodes') + break + case 1: + // menu when single item selected + this.showItem('deleteRule') + this.showItem('renameRule') + this.showItem('clearDownloadedEpisodes') + break + default: + // menu when multiple items selected + this.showItem('deleteRule') + this.hideItem('renameRule') + this.showItem('clearDownloadedEpisodes') + break + } + }, + }) - return exports(); -})(); + return exports() +})() -Object.freeze(window.qBittorrent.ContextMenu); +Object.freeze(window.qBittorrent.ContextMenu)