Move JavaScript code into explicit namespaces

This cleans up the global namespace by explicitly exporting shared values. All html and JavaScript files have been converted to use explicit exports except for client.js and mocha-init.js
This commit is contained in:
Thomas Piccirello 2019-08-11 23:53:20 -07:00
parent b144d3b797
commit 1439bcc864
32 changed files with 6204 additions and 5838 deletions

View file

@ -61,7 +61,7 @@
<p>QBT_TR(List of peers to add (one IP per line):)QBT_TR[CONTEXT=PeersAdditionDialog]</p> <p>QBT_TR(List of peers to add (one IP per line):)QBT_TR[CONTEXT=PeersAdditionDialog]</p>
<textarea id="peers" rows="10" style="width: 100%;" placeholder="QBT_TR(Format: IPv4:port / [IPv6]:port)QBT_TR[CONTEXT=PeersAdditionDialog]"></textarea> <textarea id="peers" rows="10" style="width: 100%;" placeholder="QBT_TR(Format: IPv4:port / [IPv6]:port)QBT_TR[CONTEXT=PeersAdditionDialog]"></textarea>
<div style="margin-top: 10px; text-align: center;"> <div style="margin-top: 10px; text-align: center;">
<button onclick="window.parent.closeWindows();">QBT_TR(Cancel)QBT_TR[CONTEXT=PeersAdditionDialog]</button> <button onclick="parent.closeWindows();">QBT_TR(Cancel)QBT_TR[CONTEXT=PeersAdditionDialog]</button>
<button id="addPeersOk">QBT_TR(Ok)QBT_TR[CONTEXT=PeersAdditionDialog]</button> <button id="addPeersOk">QBT_TR(Ok)QBT_TR[CONTEXT=PeersAdditionDialog]</button>
</div> </div>
</div> </div>

View file

@ -27,7 +27,7 @@
<label for="autoTMM">QBT_TR(Torrent Management Mode:)QBT_TR[CONTEXT=AddNewTorrentDialog]</label> <label for="autoTMM">QBT_TR(Torrent Management Mode:)QBT_TR[CONTEXT=AddNewTorrentDialog]</label>
</td> </td>
<td> <td>
<select id="autoTMM" name="autoTMM" onchange="changeTMM(this)"> <select id="autoTMM" name="autoTMM" onchange="qBittorrent.Download.changeTMM(this)">
<option selected value="false">Manual</option> <option selected value="false">Manual</option>
<option value="true">Automatic</option> <option value="true">Automatic</option>
</select> </select>
@ -63,7 +63,7 @@
</td> </td>
<td> <td>
<div class="select-watched-folder-editable"> <div class="select-watched-folder-editable">
<select id="categorySelect" onchange="changeCategorySelect(this)"> <select id="categorySelect" onchange="qBittorrent.Download.changeCategorySelect(this)">
<option selected value="\other"></option> <option selected value="\other"></option>
</select> </select>
<input name="category" type="text" value="" /> <input name="category" type="text" value="" />

View file

@ -30,18 +30,18 @@
}).activate(); }).activate();
window.addEvent('domready', function() { window.addEvent('domready', function() {
const uriAction = safeTrim(new URI().getData('action')); const uriAction = window.qBittorrent.Misc.safeTrim(new URI().getData('action'));
const uriHashes = safeTrim(new URI().getData('hashes')); const uriHashes = window.qBittorrent.Misc.safeTrim(new URI().getData('hashes'));
const uriCategoryName = safeTrim(new URI().getData('categoryName')); const uriCategoryName = window.qBittorrent.Misc.safeTrim(new URI().getData('categoryName'));
const uriSavePath = safeTrim(new URI().getData('savePath')); const uriSavePath = window.qBittorrent.Misc.safeTrim(new URI().getData('savePath'));
if (uriAction === "edit") { if (uriAction === "edit") {
if (!uriCategoryName) if (!uriCategoryName)
return false; return false;
$('categoryName').set('disabled', true); $('categoryName').set('disabled', true);
$('categoryName').set('value', escapeHtml(uriCategoryName)); $('categoryName').set('value', window.qBittorrent.Misc.escapeHtml(uriCategoryName));
$('savePath').set('value', escapeHtml(uriSavePath)); $('savePath').set('value', window.qBittorrent.Misc.escapeHtml(uriSavePath));
$('savePath').focus(); $('savePath').focus();
} }
else { else {
@ -90,7 +90,7 @@
}).send(); }).send();
}, },
onError: function() { onError: function() {
alert("QBT_TR(Unable to create category)QBT_TR[CONTEXT=HttpServer] " + escapeHtml(categoryName)); alert("QBT_TR(Unable to create category)QBT_TR[CONTEXT=HttpServer] " + window.qBittorrent.Misc.escapeHtml(categoryName));
} }
}).send(); }).send();
break; break;

View file

@ -30,8 +30,8 @@
}).activate(); }).activate();
window.addEvent('domready', function() { window.addEvent('domready', function() {
const uriAction = safeTrim(new URI().getData('action')); const uriAction = window.qBittorrent.Misc.safeTrim(new URI().getData('action'));
const uriHashes = safeTrim(new URI().getData('hashes')); const uriHashes = window.qBittorrent.Misc.safeTrim(new URI().getData('hashes'));
if (uriAction === 'create') if (uriAction === 'create')
$('legendText').innerText = 'QBT_TR(Tag:)QBT_TR[CONTEXT=TagFilterWidget]'; $('legendText').innerText = 'QBT_TR(Tag:)QBT_TR[CONTEXT=TagFilterWidget]';

View file

@ -24,21 +24,10 @@
'use strict'; 'use strict';
this.torrentsTable = new TorrentsTable(); this.torrentsTable = new window.qBittorrent.DynamicTable.TorrentsTable();
const torrentTrackersTable = new TorrentTrackersTable();
const torrentPeersTable = new TorrentPeersTable();
const torrentFilesTable = new TorrentFilesTable();
const searchResultsTable = new SearchResultsTable();
const searchPluginsTable = new SearchPluginsTable();
let updatePropertiesPanel = function() {}; let updatePropertiesPanel = function() {};
let updateTorrentData = function() {};
let updateTrackersData = function() {};
let updateTorrentPeersData = function() {};
let updateWebSeedsData = function() {};
let updateTorrentFilesData = function() {};
this.updateMainData = function() {}; this.updateMainData = function() {};
let alternativeSpeedLimits = false; let alternativeSpeedLimits = false;
let queueing_enabled = true; let queueing_enabled = true;
@ -365,12 +354,12 @@ window.addEvent('load', function() {
const create_link = function(hash, text, count) { const create_link = function(hash, text, count) {
const html = '<a href="#" onclick="setCategoryFilter(' + hash + ');return false;">' const html = '<a href="#" onclick="setCategoryFilter(' + hash + ');return false;">'
+ '<img src="images/qbt-theme/inode-directory.svg"/>' + '<img src="images/qbt-theme/inode-directory.svg"/>'
+ escapeHtml(text) + ' (' + count + ')' + '</a>'; + window.qBittorrent.Misc.escapeHtml(text) + ' (' + count + ')' + '</a>';
const el = new Element('li', { const el = new Element('li', {
id: hash, id: hash,
html: html html: html
}); });
categoriesFilterContextMenu.addTarget(el); window.qBittorrent.Filters.categoriesFilterContextMenu.addTarget(el);
return el; return el;
}; };
@ -422,12 +411,12 @@ window.addEvent('load', function() {
const createLink = function(hash, text, count) { 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/qbt-theme/inode-directory.svg"/>' + '<img src="images/qbt-theme/inode-directory.svg"/>'
+ escapeHtml(text) + ' (' + count + ')' + '</a>'; + window.qBittorrent.Misc.escapeHtml(text) + ' (' + count + ')' + '</a>';
const el = new Element('li', { const el = new Element('li', {
id: hash, id: hash,
html: html html: html
}); });
tagsFilterContextMenu.addTarget(el); window.qBittorrent.Filters.tagsFilterContextMenu.addTarget(el);
return el; return el;
}; };
@ -579,11 +568,11 @@ window.addEvent('load', function() {
updateFiltersList(); updateFiltersList();
if (update_categories) { if (update_categories) {
updateCategoryList(); updateCategoryList();
torrentsTableContextMenu.updateCategoriesSubMenu(category_list); window.qBittorrent.TransferList.contextMenu.updateCategoriesSubMenu(category_list);
} }
if (updateTags) { if (updateTags) {
updateTagList(); updateTagList();
torrentsTableContextMenu.updateTagsSubMenu(tagList); window.qBittorrent.TransferList.contextMenu.updateTagsSubMenu(tagList);
} }
if (full_update) if (full_update)
@ -603,39 +592,39 @@ window.addEvent('load', function() {
}; };
const processServerState = function() { const processServerState = function() {
let transfer_info = friendlyUnit(serverState.dl_info_speed, true); let transfer_info = window.qBittorrent.Misc.friendlyUnit(serverState.dl_info_speed, true);
if (serverState.dl_rate_limit > 0) if (serverState.dl_rate_limit > 0)
transfer_info += " [" + friendlyUnit(serverState.dl_rate_limit, true) + "]"; transfer_info += " [" + window.qBittorrent.Misc.friendlyUnit(serverState.dl_rate_limit, true) + "]";
transfer_info += " (" + friendlyUnit(serverState.dl_info_data, false) + ")"; transfer_info += " (" + window.qBittorrent.Misc.friendlyUnit(serverState.dl_info_data, false) + ")";
$("DlInfos").set('html', transfer_info); $("DlInfos").set('html', transfer_info);
transfer_info = friendlyUnit(serverState.up_info_speed, true); transfer_info = window.qBittorrent.Misc.friendlyUnit(serverState.up_info_speed, true);
if (serverState.up_rate_limit > 0) if (serverState.up_rate_limit > 0)
transfer_info += " [" + friendlyUnit(serverState.up_rate_limit, true) + "]"; transfer_info += " [" + window.qBittorrent.Misc.friendlyUnit(serverState.up_rate_limit, true) + "]";
transfer_info += " (" + friendlyUnit(serverState.up_info_data, false) + ")"; transfer_info += " (" + window.qBittorrent.Misc.friendlyUnit(serverState.up_info_data, false) + ")";
$("UpInfos").set('html', transfer_info); $("UpInfos").set('html', transfer_info);
if (speedInTitle) { if (speedInTitle) {
document.title = "QBT_TR([D: %1, U: %2] qBittorrent %3)QBT_TR[CONTEXT=MainWindow]".replace("%1", friendlyUnit(serverState.dl_info_speed, true)).replace("%2", friendlyUnit(serverState.up_info_speed, true)).replace("%3", qbtVersion()); document.title = "QBT_TR([D: %1, U: %2] qBittorrent %3)QBT_TR[CONTEXT=MainWindow]".replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.dl_info_speed, true)).replace("%2", window.qBittorrent.Misc.friendlyUnit(serverState.up_info_speed, true)).replace("%3", qbtVersion());
document.title += " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]"; document.title += " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]";
} }
else else
document.title = ("qBittorrent " + qbtVersion() + " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]"); document.title = ("qBittorrent " + qbtVersion() + " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]");
$('freeSpaceOnDisk').set('html', 'QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]'.replace("%1", friendlyUnit(serverState.free_space_on_disk))); $('freeSpaceOnDisk').set('html', 'QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]'.replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk)));
$('DHTNodes').set('html', 'QBT_TR(DHT: %1 nodes)QBT_TR[CONTEXT=StatusBar]'.replace("%1", serverState.dht_nodes)); $('DHTNodes').set('html', 'QBT_TR(DHT: %1 nodes)QBT_TR[CONTEXT=StatusBar]'.replace("%1", serverState.dht_nodes));
// Statistics dialog // Statistics dialog
if (document.getElementById("statisticspage")) { if (document.getElementById("statisticspage")) {
$('AlltimeDL').set('html', friendlyUnit(serverState.alltime_dl, false)); $('AlltimeDL').set('html', window.qBittorrent.Misc.friendlyUnit(serverState.alltime_dl, false));
$('AlltimeUL').set('html', friendlyUnit(serverState.alltime_ul, false)); $('AlltimeUL').set('html', window.qBittorrent.Misc.friendlyUnit(serverState.alltime_ul, false));
$('TotalWastedSession').set('html', friendlyUnit(serverState.total_wasted_session, false)); $('TotalWastedSession').set('html', window.qBittorrent.Misc.friendlyUnit(serverState.total_wasted_session, false));
$('GlobalRatio').set('html', serverState.global_ratio); $('GlobalRatio').set('html', serverState.global_ratio);
$('TotalPeerConnections').set('html', serverState.total_peer_connections); $('TotalPeerConnections').set('html', serverState.total_peer_connections);
$('ReadCacheHits').set('html', serverState.read_cache_hits + "%"); $('ReadCacheHits').set('html', serverState.read_cache_hits + "%");
$('TotalBuffersSize').set('html', friendlyUnit(serverState.total_buffers_size, false)); $('TotalBuffersSize').set('html', window.qBittorrent.Misc.friendlyUnit(serverState.total_buffers_size, false));
$('WriteCacheOverload').set('html', serverState.write_cache_overload + "%"); $('WriteCacheOverload').set('html', serverState.write_cache_overload + "%");
$('ReadCacheOverload').set('html', serverState.read_cache_overload + "%"); $('ReadCacheOverload').set('html', serverState.read_cache_overload + "%");
$('QueuedIOJobs').set('html', serverState.queued_io_jobs); $('QueuedIOJobs').set('html', serverState.queued_io_jobs);
$('AverageTimeInQueue').set('html', serverState.average_time_queue + " ms"); $('AverageTimeInQueue').set('html', serverState.average_time_queue + " ms");
$('TotalQueuedSize').set('html', friendlyUnit(serverState.total_queued_size, false)); $('TotalQueuedSize').set('html', window.qBittorrent.Misc.friendlyUnit(serverState.total_queued_size, false));
} }
if (serverState.connection_status == "connected") if (serverState.connection_status == "connected")
@ -790,7 +779,7 @@ window.addEvent('load', function() {
const showSearchTab = function() { const showSearchTab = function() {
if (!searchTabInitialized) { if (!searchTabInitialized) {
initSearchTab(); window.qBittorrent.Search.init();
searchTabInitialized = true; searchTabInitialized = true;
} }
@ -878,16 +867,26 @@ window.addEvent('load', function() {
MochaUI.initializeTabs('propertiesTabs'); MochaUI.initializeTabs('propertiesTabs');
updatePropertiesPanel = function() { updatePropertiesPanel = function() {
if (!$('prop_general').hasClass('invisible')) if (!$('prop_general').hasClass('invisible')) {
updateTorrentData(); if (window.qBittorrent.PropGeneral !== undefined)
else if (!$('prop_trackers').hasClass('invisible')) window.qBittorrent.PropGeneral.updateData();
updateTrackersData(); }
else if (!$('prop_peers').hasClass('invisible')) else if (!$('prop_trackers').hasClass('invisible')) {
updateTorrentPeersData(); if (window.qBittorrent.PropTrackers !== undefined)
else if (!$('prop_webseeds').hasClass('invisible')) window.qBittorrent.PropTrackers.updateData();
updateWebSeedsData(); }
else if (!$('prop_files').hasClass('invisible')) else if (!$('prop_peers').hasClass('invisible')) {
updateTorrentFilesData(); if (window.qBittorrent.PropPeers !== undefined)
window.qBittorrent.PropPeers.updateData();
}
else if (!$('prop_webseeds').hasClass('invisible')) {
if (window.qBittorrent.PropWebseeds !== undefined)
window.qBittorrent.PropWebseeds.updateData();
}
else if (!$('prop_files').hasClass('invisible')) {
if (window.qBittorrent.PropFiles !== undefined)
window.qBittorrent.PropFiles.updateData();
}
}; };
$('PropGeneralLink').addEvent('click', function(e) { $('PropGeneralLink').addEvent('click', function(e) {

View file

@ -28,497 +28,515 @@
'use strict'; 'use strict';
let lastShownContextMenu = null; if (window.qBittorrent === undefined) {
const ContextMenu = new Class({ window.qBittorrent = {};
//implements }
Implements: [Options, Events],
//options window.qBittorrent.ContextMenu = (function() {
options: { const exports = function() {
actions: {}, return {
menu: 'menu_id', ContextMenu: ContextMenu,
stopEvent: true, TorrentsTableContextMenu: TorrentsTableContextMenu,
targets: 'body', CategoriesFilterContextMenu: CategoriesFilterContextMenu,
offsets: { TagsFilterContextMenu: TagsFilterContextMenu,
x: 0, SearchPluginsTableContextMenu: SearchPluginsTableContextMenu
y: 0 };
};
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
}, },
onShow: $empty,
onHide: $empty,
onClick: $empty,
fadeSpeed: 200,
touchTimer: 600
},
//initialization //initialization
initialize: function(options) { initialize: function(options) {
//set options //set options
this.setOptions(options); this.setOptions(options);
//option diffs menu //option diffs menu
this.menu = $(this.options.menu); this.menu = $(this.options.menu);
this.targets = $$(this.options.targets); this.targets = $$(this.options.targets);
//fx //fx
this.fx = new Fx.Tween(this.menu, { this.fx = new Fx.Tween(this.menu, {
property: 'opacity', property: 'opacity',
duration: this.options.fadeSpeed, duration: this.options.fadeSpeed,
onComplete: function() { onComplete: function() {
if (this.getStyle('opacity')) { if (this.getStyle('opacity')) {
this.setStyle('visibility', 'visible'); this.setStyle('visibility', 'visible');
} }
else { else {
this.setStyle('visibility', 'hidden'); this.setStyle('visibility', 'hidden');
} }
}.bind(this.menu) }.bind(this.menu)
}); });
//hide and begin the listener //hide and begin the listener
this.hide().startListener(); this.hide().startListener();
//hide the menu
this.menu.setStyles({
'position': 'absolute',
'top': '-900000px',
'display': 'block'
});
},
adjustMenuPosition: function(e) {
this.updateMenuItems();
const scrollableMenuMaxHeight = document.documentElement.clientHeight * 0.75;
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'
});
// 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
});
}
},
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);
//hide on body click
$(document.body).addEvent('click', function() {
this.hide();
}.bind(this));
},
updateMenuItems: function() {},
//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;
},
//hide the menu //hide the menu
this.menu.setStyles({ hide: function(trigger) {
'position': 'absolute', if (this.shown) {
'top': '-900000px', this.fx.start(0);
'display': 'block' //this.menu.fade('out');
}); this.fireEvent('hide');
}, this.shown = false;
}
return this;
},
adjustMenuPosition: function(e) { setItemChecked: function(item, checked) {
this.updateMenuItems(); this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity =
checked ? '1' : '0';
return this;
},
const scrollableMenuMaxHeight = document.documentElement.clientHeight * 0.75; getItemChecked: function(item) {
return '0' != this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity;
},
if (this.menu.hasClass('scrollableMenu')) //hide an item
this.menu.setStyle('max-height', scrollableMenuMaxHeight); hideItem: function(item) {
this.menu.getElement('a[href$=' + item + ']').parentNode.addClass('invisible');
return this;
},
// draw the menu off-screen to know the menu dimensions //show an item
this.menu.setStyles({ showItem: function(item) {
left: '-999em', this.menu.getElement('a[href$=' + item + ']').parentNode.removeClass('invisible');
top: '-999em' return this;
}); },
// position the menu //disable the entire menu
let xPosMenu = e.page.x + this.options.offsets.x; disable: function() {
let yPosMenu = e.page.y + this.options.offsets.y; this.options.disabled = true;
if (xPosMenu + this.menu.offsetWidth > document.documentElement.clientWidth) return this;
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 //enable the entire menu
const uls = this.menu.getElementsByTagName('ul'); enable: function() {
for (let i = 0; i < uls.length; ++i) { this.options.disabled = false;
const ul = uls[i]; return this;
if (ul.hasClass('scrollableMenu')) },
ul.setStyle('max-height', scrollableMenuMaxHeight);
const rectParent = ul.parentNode.getBoundingClientRect(); //execute an action
const xPosOrigin = rectParent.left; execute: function(action, element) {
const yPosOrigin = rectParent.bottom; if (this.options.actions[action]) {
let xPos = xPosOrigin + rectParent.width - 1; this.options.actions[action](element, this, action);
let yPos = yPosOrigin - rectParent.height - 1; }
if (xPos + ul.offsetWidth > document.documentElement.clientWidth) return this;
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) { const TorrentsTableContextMenu = new Class({
elem.addEvent('contextmenu', function(e) { Extends: ContextMenu,
this.triggerMenu(e, elem);
}.bind(this));
elem.addEvent('click', function(e) {
this.hide();
}.bind(this));
elem.addEvent('touchstart', function(e) { updateMenuItems: function() {
e.preventDefault(); let all_are_seq_dl = true;
clearTimeout(this.touchstartTimer); let there_are_seq_dl = false;
this.hide(); 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);
const touchstartEvent = e; const h = torrentsTable.selectedRowsIds();
this.touchstartTimer = setTimeout(function() { h.each(function(item, index) {
this.triggerMenu(touchstartEvent, elem); const data = torrentsTable.rows.get(item).full_data;
}.bind(this), this.options.touchTimer);
}.bind(this));
elem.addEvent('touchend', function(e) {
e.preventDefault();
clearTimeout(this.touchstartTimer);
}.bind(this));
},
addTarget: function(t) { if (data['seq_dl'] !== true)
this.targets[this.targets.length] = t; all_are_seq_dl = false;
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);
//hide on body click
$(document.body).addEvent('click', function() {
this.hide();
}.bind(this));
},
updateMenuItems: function() {},
//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;
},
//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;
},
setItemChecked: function(item, checked) {
this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity =
checked ? '1' : '0';
return this;
},
getItemChecked: function(item) {
return '0' != this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity;
},
//hide an item
hideItem: function(item) {
this.menu.getElement('a[href$=' + item + ']').parentNode.addClass('invisible');
return this;
},
//show an item
showItem: function(item) {
this.menu.getElement('a[href$=' + item + ']').parentNode.removeClass('invisible');
return this;
},
//disable the entire menu
disable: function() {
this.options.disabled = true;
return this;
},
//enable the entire menu
enable: function() {
this.options.disabled = false;
return this;
},
//execute an action
execute: function(action, element) {
if (this.options.actions[action]) {
this.options.actions[action](element, this, action);
}
return this;
}
});
const TorrentsTableContextMenu = new Class({
Extends: ContextMenu,
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);
const h = torrentsTable.selectedRowsIds();
h.each(function(item, index) {
const data = torrentsTable.rows.get(item).full_data;
if (data['seq_dl'] !== true)
all_are_seq_dl = false;
else
there_are_seq_dl = true;
if (data['f_l_piece_prio'] !== true)
all_are_f_l_piece_prio = false;
else
there_are_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 (data['state'] != 'pausedUP' && data['state'] != 'pausedDL')
all_are_paused = false;
else
there_are_paused = true;
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 else
tag.checked = tag.checked && tagExists; there_are_seq_dl = true;
}
});
let show_seq_dl = true; if (data['f_l_piece_prio'] !== true)
all_are_f_l_piece_prio = false;
else
there_are_f_l_piece_prio = true;
if (!all_are_seq_dl && there_are_seq_dl) if (data['progress'] != 1.0) // not downloaded
show_seq_dl = false; all_are_downloaded = false;
else if (data['super_seeding'] !== true)
all_are_super_seeding = false;
let show_f_l_piece_prio = true; if (data['state'] != 'pausedUP' && data['state'] != 'pausedDL')
all_are_paused = false;
else
there_are_paused = true;
if (!all_are_f_l_piece_prio && there_are_f_l_piece_prio) if (data['force_start'] !== true)
show_f_l_piece_prio = false; all_are_force_start = false;
else
there_are_force_start = true;
if (all_are_downloaded) { if (data['auto_tmm'] === true)
this.hideItem('downloadLimit'); there_are_auto_tmm = true;
this.menu.getElement('a[href$=uploadLimit]').parentNode.addClass('separator'); else
this.hideItem('sequentialDownload'); all_are_auto_tmm = false;
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) const torrentTags = data['tags'].split(', ');
this.showItem('sequentialDownload'); for (const key in tagsSelectionState) {
else 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;
}
});
let show_seq_dl = true;
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');
this.menu.getElement('a[href$=uploadLimit]').parentNode.addClass('separator');
this.hideItem('sequentialDownload'); this.hideItem('sequentialDownload');
if (show_f_l_piece_prio)
this.showItem('firstLastPiecePrio');
else
this.hideItem('firstLastPiecePrio'); this.hideItem('firstLastPiecePrio');
this.showItem('superSeeding');
this.setItemChecked('sequentialDownload', all_are_seq_dl); this.setItemChecked('superSeeding', all_are_super_seeding);
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: '<a href="javascript:torrentNewCategoryFN();"><img src="images/qbt-theme/list-add.svg" alt="QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]"/> QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]</a>'
}));
categoryList.appendChild(new Element('li', {
html: '<a href="javascript:torrentSetCategoryFN(0);"><img src="images/qbt-theme/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();
let first = true;
Object.each(sortedCategories, function(categoryName) {
const categoryHash = genHash(categoryName);
const el = new Element('li', {
html: '<a href="javascript:torrentSetCategoryFN(\'' + categoryHash + '\');"><img src="images/qbt-theme/inode-directory.svg"/> ' + escapeHtml(categoryName) + '</a>'
});
if (first) {
el.addClass('separator');
first = false;
} }
categoryList.appendChild(el); 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');
updateTagsSubMenu: function(tagList) { if (show_seq_dl)
const contextTagList = $('contextTagList'); this.showItem('sequentialDownload');
while (contextTagList.firstChild !== null) else
contextTagList.removeChild(contextTagList.firstChild); this.hideItem('sequentialDownload');
contextTagList.appendChild(new Element('li', { if (show_f_l_piece_prio)
html: '<a href="javascript:torrentAddTagsFN();">' this.showItem('firstLastPiecePrio');
+ '<img src="images/qbt-theme/list-add.svg" alt="QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]"/>' else
+ ' QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]' this.hideItem('firstLastPiecePrio');
+ '</a>'
}));
contextTagList.appendChild(new Element('li', {
html: '<a href="javascript:torrentRemoveAllTagsFN();">'
+ '<img src="images/qbt-theme/edit-clear.svg" alt="QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]"/>'
+ ' QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]'
+ '</a>'
}));
const sortedTags = []; this.setItemChecked('sequentialDownload', all_are_seq_dl);
for (const key in tagList) this.setItemChecked('firstLastPiecePrio', all_are_f_l_piece_prio);
sortedTags.push(tagList[key].name);
sortedTags.sort();
for (let i = 0; i < sortedTags.length; ++i) { this.showItem('downloadLimit');
const tagName = sortedTags[i]; this.menu.getElement('a[href$=uploadLimit]').parentNode.removeClass('separator');
const tagHash = genHash(tagName); this.hideItem('superSeeding');
const el = new Element('li', { }
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;"> ' + escapeHtml(tagName) this.showItem('start');
+ '</a>' 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: '<a href="javascript:torrentNewCategoryFN();"><img src="images/qbt-theme/list-add.svg" alt="QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]"/> QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]</a>'
}));
categoryList.appendChild(new Element('li', {
html: '<a href="javascript:torrentSetCategoryFN(0);"><img src="images/qbt-theme/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);
}); });
if (i === 0) sortedCategories.sort();
el.addClass('separator');
contextTagList.appendChild(el); let first = true;
Object.each(sortedCategories, function(categoryName) {
const categoryHash = genHash(categoryName);
const el = new Element('li', {
html: '<a href="javascript:torrentSetCategoryFN(\'' + categoryHash + '\');"><img src="images/qbt-theme/inode-directory.svg"/> ' + window.qBittorrent.Misc.escapeHtml(categoryName) + '</a>'
});
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: '<a href="javascript:torrentAddTagsFN();">'
+ '<img src="images/qbt-theme/list-add.svg" alt="QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]"/>'
+ ' QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]'
+ '</a>'
}));
contextTagList.appendChild(new Element('li', {
html: '<a href="javascript:torrentRemoveAllTagsFN();">'
+ '<img src="images/qbt-theme/edit-clear.svg" alt="QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]"/>'
+ ' QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]'
+ '</a>'
}));
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: '<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>'
});
if (i === 0)
el.addClass('separator');
contextTagList.appendChild(el);
}
} }
} });
});
const CategoriesFilterContextMenu = new Class({ const CategoriesFilterContextMenu = new Class({
Extends: ContextMenu, Extends: ContextMenu,
updateMenuItems: function() { updateMenuItems: function() {
const id = this.options.element.id; const id = this.options.element.id;
if ((id != CATEGORIES_ALL) && (id != CATEGORIES_UNCATEGORIZED)) { if ((id != CATEGORIES_ALL) && (id != CATEGORIES_UNCATEGORIZED)) {
this.showItem('editCategory'); this.showItem('editCategory');
this.showItem('deleteCategory'); this.showItem('deleteCategory');
}
else {
this.hideItem('editCategory');
this.hideItem('deleteCategory');
}
} }
else { });
this.hideItem('editCategory');
this.hideItem('deleteCategory'); 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({ const SearchPluginsTableContextMenu = new Class({
Extends: ContextMenu, 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({ updateMenuItems: function() {
Extends: ContextMenu, 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() { this.showItem('Enabled');
const enabledColumnIndex = function(text) { this.setItemChecked('Enabled', this.options.element.getChildren("td")[enabledColumnIndex()].get("html") === "Yes");
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.showItem('Uninstall');
this.setItemChecked('Enabled', this.options.element.getChildren("td")[enabledColumnIndex()].get("html") === "Yes"); }
});
this.showItem('Uninstall'); return exports();
} })();
});

View file

@ -23,98 +23,113 @@
'use strict'; 'use strict';
let categories = {}; if (window.qBittorrent === undefined) {
let defaultSavePath = ""; window.qBittorrent = {};
}
const getCategories = function() { window.qBittorrent.Download = (function() {
new Request.JSON({ const exports = function() {
url: 'api/v2/torrents/categories', return {
noCache: true, changeCategorySelect: changeCategorySelect,
method: 'get', changeTMM: changeTMM
onSuccess: function(data) { };
if (data) { };
categories = data;
for (const i in data) { let categories = {};
const category = data[i]; let defaultSavePath = "";
const option = new Element("option");
option.set('value', category.name); const getCategories = function() {
option.set('html', category.name); new Request.JSON({
$('categorySelect').appendChild(option); url: 'api/v2/torrents/categories',
noCache: true,
method: 'get',
onSuccess: function(data) {
if (data) {
categories = data;
for (const i in data) {
const category = data[i];
const option = new Element("option");
option.set('value', category.name);
option.set('html', category.name);
$('categorySelect').appendChild(option);
}
} }
} }
} }).send();
}).send(); };
};
const getPreferences = function() { const getPreferences = function() {
new Request.JSON({ new Request.JSON({
url: 'api/v2/app/preferences', url: 'api/v2/app/preferences',
method: 'get', method: 'get',
noCache: true, noCache: true,
onFailure: function() { onFailure: function() {
alert("Could not contact qBittorrent"); alert("Could not contact qBittorrent");
}, },
onSuccess: function(pref) { onSuccess: function(pref) {
if (!pref) if (!pref)
return; return;
defaultSavePath = pref.save_path; defaultSavePath = pref.save_path;
$('savepath').setProperty('value', defaultSavePath); $('savepath').setProperty('value', defaultSavePath);
$('rootFolder').checked = pref.create_subfolder_enabled; $('rootFolder').checked = pref.create_subfolder_enabled;
$('startTorrent').checked = !pref.start_paused_enabled; $('startTorrent').checked = !pref.start_paused_enabled;
if (pref.auto_tmm_enabled == 1) { if (pref.auto_tmm_enabled == 1) {
$('autoTMM').selectedIndex = 1; $('autoTMM').selectedIndex = 1;
$('savepath').disabled = true; $('savepath').disabled = true;
}
else {
$('autoTMM').selectedIndex = 0;
}
} }
else { }).send();
$('autoTMM').selectedIndex = 0; };
const changeCategorySelect = function(item) {
if (item.value == "\\other") {
item.nextElementSibling.hidden = false;
item.nextElementSibling.value = "";
item.nextElementSibling.select();
if ($('autoTMM').selectedIndex == 1)
$('savepath').value = defaultSavePath;
}
else {
item.nextElementSibling.hidden = true;
const text = item.options[item.selectedIndex].innerHTML;
item.nextElementSibling.value = text;
if ($('autoTMM').selectedIndex == 1) {
const categoryName = item.value;
const category = categories[categoryName];
let savePath = defaultSavePath;
if (category !== undefined)
savePath = (category['savePath'] !== "") ? category['savePath'] : (defaultSavePath + categoryName);
$('savepath').value = savePath;
} }
} }
}).send(); };
};
const changeCategorySelect = function(item) { const changeTMM = function(item) {
if (item.value == "\\other") { if (item.selectedIndex == 1) {
item.nextElementSibling.hidden = false; $('savepath').disabled = true;
item.nextElementSibling.value = "";
item.nextElementSibling.select();
if ($('autoTMM').selectedIndex == 1) const categorySelect = $('categorySelect');
$('savepath').value = defaultSavePath; const categoryName = categorySelect.options[categorySelect.selectedIndex].value;
}
else {
item.nextElementSibling.hidden = true;
const text = item.options[item.selectedIndex].innerHTML;
item.nextElementSibling.value = text;
if ($('autoTMM').selectedIndex == 1) {
const categoryName = item.value;
const category = categories[categoryName]; const category = categories[categoryName];
let savePath = defaultSavePath; $('savepath').value = (category === undefined) ? "" : category['savePath'];
if (category !== undefined)
savePath = (category['savePath'] !== "") ? category['savePath'] : (defaultSavePath + categoryName);
$('savepath').value = savePath;
} }
} else {
}; $('savepath').disabled = false;
$('savepath').value = defaultSavePath;
}
};
const changeTMM = function(item) { $(window).addEventListener("load", function() {
if (item.selectedIndex == 1) { getPreferences();
$('savepath').disabled = true; getCategories();
});
const categorySelect = $('categorySelect'); return exports();
const categoryName = categorySelect.options[categorySelect.selectedIndex].value; })();
const category = categories[categoryName];
$('savepath').value = (category === undefined) ? "" : category['savePath'];
}
else {
$('savepath').disabled = false;
$('savepath').value = defaultSavePath;
}
};
$(window).addEventListener("load", function() {
getPreferences();
getCategories();
});

File diff suppressed because it is too large Load diff

View file

@ -28,149 +28,167 @@
'use strict'; 'use strict';
const FilePriority = { if (window.qBittorrent === undefined) {
"Ignored": 0, window.qBittorrent = {};
"Normal": 1, }
"High": 6,
"Maximum": 7,
"Mixed": -1
};
Object.freeze(FilePriority);
const TriState = { window.qBittorrent.FileTree = (function() {
"Unchecked": 0, const exports = function() {
"Checked": 1, return {
"Partial": 2 FilePriority: FilePriority,
}; TriState: TriState,
Object.freeze(TriState); FileTree: FileTree,
FileNode: FileNode,
FolderNode: FolderNode,
};
};
const FileTree = new Class({ const FilePriority = {
root: null, "Ignored": 0,
nodeMap: {}, "Normal": 1,
"High": 6,
"Maximum": 7,
"Mixed": -1
};
Object.freeze(FilePriority);
setRoot: function(root) { const TriState = {
this.root = root; "Unchecked": 0,
this.generateNodeMap(root); "Checked": 1,
"Partial": 2
};
Object.freeze(TriState);
if (this.root.isFolder) const FileTree = new Class({
this.root.calculateSize(); root: null,
}, nodeMap: {},
getRoot: function() { setRoot: function(root) {
return this.root; this.root = root;
}, this.generateNodeMap(root);
generateNodeMap: function(node) { if (this.root.isFolder)
// don't store root node in map this.root.calculateSize();
if (node.root !== null) { },
this.nodeMap[node.rowId] = node;
getRoot: function() {
return this.root;
},
generateNodeMap: function(node) {
// don't store root node in map
if (node.root !== null) {
this.nodeMap[node.rowId] = node;
}
node.children.each(function(child) {
this.generateNodeMap(child);
}.bind(this));
},
getNode: function(rowId) {
return (this.nodeMap[rowId] === undefined)
? null
: this.nodeMap[rowId];
},
getRowId: function(node) {
return node.rowId;
},
/**
* Returns the nodes in dfs order
*/
toArray: function() {
const nodes = [];
this.root.children.each(function(node) {
this._getArrayOfNodes(node, nodes);
}.bind(this));
return nodes;
},
_getArrayOfNodes: function(node, array) {
array.push(node);
node.children.each(function(child) {
this._getArrayOfNodes(child, array);
}.bind(this));
} }
});
node.children.each(function(child) { const FileNode = new Class({
this.generateNodeMap(child); name: "",
}.bind(this)); rowId: null,
}, size: 0,
checked: TriState.Unchecked,
remaining: 0,
progress: 0,
priority: FilePriority.Normal,
availability: 0,
depth: 0,
root: null,
data: null,
isFolder: false,
children: [],
});
getNode: function(rowId) { const FolderNode = new Class({
return (this.nodeMap[rowId] === undefined) Extends: FileNode,
? null
: this.nodeMap[rowId];
},
getRowId: function(node) { initialize: function() {
return node.rowId; this.isFolder = true;
}, },
/** addChild(node) {
* Returns the nodes in dfs order this.children.push(node);
*/ },
toArray: function() {
const nodes = [];
this.root.children.each(function(node) {
this._getArrayOfNodes(node, nodes);
}.bind(this));
return nodes;
},
_getArrayOfNodes: function(node, array) { /**
array.push(node); * Recursively calculate size of node and its children
node.children.each(function(child) { */
this._getArrayOfNodes(child, array); calculateSize: function() {
}.bind(this)); let size = 0;
} let remaining = 0;
}); let progress = 0;
let availability = 0;
let checked = TriState.Unchecked;
let priority = FilePriority.Normal;
const FileNode = new Class({ let isFirstFile = true;
name: "",
rowId: null,
size: 0,
checked: TriState.Unchecked,
remaining: 0,
progress: 0,
priority: FilePriority.Normal,
availability: 0,
depth: 0,
root: null,
data: null,
isFolder: false,
children: [],
});
const FolderNode = new Class({ this.children.each(function(node) {
Extends: FileNode, if (node.isFolder)
node.calculateSize();
initialize: function() { size += node.size;
this.isFolder = true;
},
addChild(node) { if (isFirstFile) {
this.children.push(node); priority = node.priority;
}, checked = node.checked;
isFirstFile = false;
}
else {
if (priority !== node.priority)
priority = FilePriority.Mixed;
if (checked !== node.checked)
checked = TriState.Partial;
}
/** const isIgnored = (node.priority === FilePriority.Ignored);
* Recursively calculate size of node and its children if (!isIgnored) {
*/ remaining += node.remaining;
calculateSize: function() { progress += (node.progress * node.size);
let size = 0; availability += (node.availability * node.size);
let remaining = 0; }
let progress = 0; }.bind(this));
let availability = 0;
let checked = TriState.Unchecked;
let priority = FilePriority.Normal;
let isFirstFile = true; this.size = size;
this.remaining = remaining;
this.checked = checked;
this.progress = (progress / size);
this.priority = priority;
this.availability = (availability / size);
}
});
this.children.each(function(node) { return exports();
if (node.isFolder) })();
node.calculateSize();
size += node.size;
if (isFirstFile) {
priority = node.priority;
checked = node.checked;
isFirstFile = false;
}
else {
if (priority !== node.priority)
priority = FilePriority.Mixed;
if (checked !== node.checked)
checked = TriState.Partial;
}
const isIgnored = (node.priority === FilePriority.Ignored);
if (!isIgnored) {
remaining += node.remaining;
progress += (node.progress * node.size);
availability += (node.availability * node.size);
}
}.bind(this));
this.size = size;
this.remaining = remaining;
this.checked = checked;
this.progress = (progress / size);
this.priority = priority;
this.availability = (availability / size);
}
});

View file

@ -30,32 +30,49 @@
// This file is the JavaScript implementation of base/utils/fs.cpp // This file is the JavaScript implementation of base/utils/fs.cpp
const QB_EXT = '.!qB'; if (window.qBittorrent === undefined) {
const PathSeparator = '/'; window.qBittorrent = {};
/**
* Returns the file extension part of a file name.
*/
function fileExtension(filename) {
const name = filename.endsWith(QB_EXT)
? filename.substring(0, filename.length - QB_EXT.length)
: filename;
const pointIndex = name.lastIndexOf('.');
if (pointIndex === -1)
return '';
return name.substring(pointIndex + 1);
} }
function fileName(filepath) { window.qBittorrent.Filesystem = (function() {
const slashIndex = filepath.lastIndexOf(PathSeparator); const exports = function() {
if (slashIndex === -1) return {
return filepath; PathSeparator: PathSeparator,
return filepath.substring(slashIndex + 1); fileExtension: fileExtension,
} fileName: fileName,
folderName: folderName
};
};
function folderName(filepath) { const QB_EXT = '.!qB';
const slashIndex = filepath.lastIndexOf(PathSeparator); const PathSeparator = '/';
if (slashIndex === -1)
return filepath; /**
return filepath.substring(0, slashIndex); * Returns the file extension part of a file name.
} */
const fileExtension = function(filename) {
const name = filename.endsWith(QB_EXT)
? filename.substring(0, filename.length - QB_EXT.length)
: filename;
const pointIndex = name.lastIndexOf('.');
if (pointIndex === -1)
return '';
return name.substring(pointIndex + 1);
};
const fileName = function(filepath) {
const slashIndex = filepath.lastIndexOf(PathSeparator);
if (slashIndex === -1)
return filepath;
return filepath.substring(slashIndex + 1);
};
const folderName = function(filepath) {
const slashIndex = filepath.lastIndexOf(PathSeparator);
if (slashIndex === -1)
return filepath;
return filepath.substring(0, slashIndex);
};
return exports();
})();

View file

@ -28,166 +28,188 @@
'use strict'; 'use strict';
/* if (window.qBittorrent === undefined) {
* JS counterpart of the function in src/misc.cpp window.qBittorrent = {};
*/
function friendlyUnit(value, isSpeed) {
const units = [
"QBT_TR(B)QBT_TR[CONTEXT=misc]",
"QBT_TR(KiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(MiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(GiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(TiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(PiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(EiB)QBT_TR[CONTEXT=misc]"
];
if ((value === undefined) || (value === null) || (value < 0))
return "QBT_TR(Unknown)QBT_TR[CONTEXT=misc]";
let i = 0;
while (value >= 1024.0 && i < 6) {
value /= 1024.0;
++i;
}
function friendlyUnitPrecision(sizeUnit) {
if (sizeUnit <= 2) return 1; // KiB, MiB
else if (sizeUnit === 3) return 2; // GiB
else return 3; // TiB, PiB, EiB
}
let ret;
if (i === 0)
ret = value + " " + units[i];
else {
const precision = friendlyUnitPrecision(i);
const offset = Math.pow(10, precision);
// Don't round up
ret = (Math.floor(offset * value) / offset).toFixed(precision) + " " + units[i];
}
if (isSpeed)
ret += "QBT_TR(/s)QBT_TR[CONTEXT=misc]";
return ret;
} }
/* window.qBittorrent.Misc = (function() {
* JS counterpart of the function in src/misc.cpp const exports = function() {
*/ return {
function friendlyDuration(seconds) { friendlyUnit: friendlyUnit,
const MAX_ETA = 8640000; friendlyDuration: friendlyDuration,
if (seconds < 0 || seconds >= MAX_ETA) friendlyPercentage: friendlyPercentage,
return "∞"; friendlyFloat: friendlyFloat,
if (seconds === 0) parseHtmlLinks: parseHtmlLinks,
return "0"; escapeHtml: escapeHtml,
if (seconds < 60) safeTrim: safeTrim,
return "QBT_TR(< 1m)QBT_TR[CONTEXT=misc]"; toFixedPointString: toFixedPointString,
let minutes = seconds / 60; containsAllTerms: containsAllTerms
if (minutes < 60)
return "QBT_TR(%1m)QBT_TR[CONTEXT=misc]".replace("%1", parseInt(minutes));
let hours = minutes / 60;
minutes = minutes % 60;
if (hours < 24)
return "QBT_TR(%1h %2m)QBT_TR[CONTEXT=misc]".replace("%1", parseInt(hours)).replace("%2", parseInt(minutes));
const days = hours / 24;
hours = hours % 24;
if (days < 100)
return "QBT_TR(%1d %2h)QBT_TR[CONTEXT=misc]".replace("%1", parseInt(days)).replace("%2", parseInt(hours));
return "∞";
}
function friendlyPercentage(value) {
let percentage = (value * 100).round(1);
if (isNaN(percentage) || (percentage < 0))
percentage = 0;
if (percentage > 100)
percentage = 100;
return percentage.toFixed(1) + "%";
}
function friendlyFloat(value, precision) {
return parseFloat(value).toFixed(precision);
}
/*
* From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
*/
if (!Date.prototype.toISOString) {
(function() {
function pad(number) {
if (number < 10) {
return '0' + number;
}
return number;
}
Date.prototype.toISOString = function() {
return this.getUTCFullYear()
+ '-' + pad(this.getUTCMonth() + 1)
+ '-' + pad(this.getUTCDate())
+ 'T' + pad(this.getUTCHours())
+ ':' + pad(this.getUTCMinutes())
+ ':' + pad(this.getUTCSeconds())
+ '.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5)
+ 'Z';
}; };
};
}()); /*
} * JS counterpart of the function in src/misc.cpp
*/
const friendlyUnit = function(value, isSpeed) {
const units = [
"QBT_TR(B)QBT_TR[CONTEXT=misc]",
"QBT_TR(KiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(MiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(GiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(TiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(PiB)QBT_TR[CONTEXT=misc]",
"QBT_TR(EiB)QBT_TR[CONTEXT=misc]"
];
/* if ((value === undefined) || (value === null) || (value < 0))
* JS counterpart of the function in src/misc.cpp return "QBT_TR(Unknown)QBT_TR[CONTEXT=misc]";
*/
function parseHtmlLinks(text) {
const exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
return text.replace(exp, "<a target='_blank' href='$1'>$1</a>");
}
function escapeHtml(str) { let i = 0;
const div = document.createElement('div'); while (value >= 1024.0 && i < 6) {
div.appendChild(document.createTextNode(str)); value /= 1024.0;
return div.innerHTML; ++i;
}
function safeTrim(value) {
try {
return value.trim();
}
catch (e) {
if (e instanceof TypeError)
return "";
throw e;
}
}
function toFixedPointString(number, digits) {
// Do not round up number
const power = Math.pow(10, digits);
return (Math.floor(power * number) / power).toFixed(digits);
}
/**
*
* @param {String} text the text to search
* @param {Array<String>} terms terms to search for within the text
* @returns {Boolean} true if all terms match the text, false otherwise
*/
function containsAllTerms(text, terms) {
const textToSearch = text.toLowerCase();
return terms.every((function(term) {
const isTermRequired = (term[0] === '+');
const isTermExcluded = (term[0] === '-');
if (isTermRequired || isTermExcluded) {
// ignore lonely +/-
if (term.length === 1)
return true;
term = term.substring(1);
} }
const textContainsTerm = (textToSearch.indexOf(term) !== -1); function friendlyUnitPrecision(sizeUnit) {
return isTermExcluded ? !textContainsTerm : textContainsTerm; if (sizeUnit <= 2) return 1; // KiB, MiB
})); else if (sizeUnit === 3) return 2; // GiB
} else return 3; // TiB, PiB, EiB
}
let ret;
if (i === 0)
ret = value + " " + units[i];
else {
const precision = friendlyUnitPrecision(i);
const offset = Math.pow(10, precision);
// Don't round up
ret = (Math.floor(offset * value) / offset).toFixed(precision) + " " + units[i];
}
if (isSpeed)
ret += "QBT_TR(/s)QBT_TR[CONTEXT=misc]";
return ret;
}
/*
* JS counterpart of the function in src/misc.cpp
*/
const friendlyDuration = function(seconds) {
const MAX_ETA = 8640000;
if (seconds < 0 || seconds >= MAX_ETA)
return "∞";
if (seconds === 0)
return "0";
if (seconds < 60)
return "QBT_TR(< 1m)QBT_TR[CONTEXT=misc]";
let minutes = seconds / 60;
if (minutes < 60)
return "QBT_TR(%1m)QBT_TR[CONTEXT=misc]".replace("%1", parseInt(minutes));
let hours = minutes / 60;
minutes = minutes % 60;
if (hours < 24)
return "QBT_TR(%1h %2m)QBT_TR[CONTEXT=misc]".replace("%1", parseInt(hours)).replace("%2", parseInt(minutes));
const days = hours / 24;
hours = hours % 24;
if (days < 100)
return "QBT_TR(%1d %2h)QBT_TR[CONTEXT=misc]".replace("%1", parseInt(days)).replace("%2", parseInt(hours));
return "∞";
}
const friendlyPercentage = function(value) {
let percentage = (value * 100).round(1);
if (isNaN(percentage) || (percentage < 0))
percentage = 0;
if (percentage > 100)
percentage = 100;
return percentage.toFixed(1) + "%";
}
const friendlyFloat = function(value, precision) {
return parseFloat(value).toFixed(precision);
}
/*
* From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
*/
if (!Date.prototype.toISOString) {
(function() {
function pad(number) {
if (number < 10) {
return '0' + number;
}
return number;
}
Date.prototype.toISOString = function() {
return this.getUTCFullYear()
+ '-' + pad(this.getUTCMonth() + 1)
+ '-' + pad(this.getUTCDate())
+ 'T' + pad(this.getUTCHours())
+ ':' + pad(this.getUTCMinutes())
+ ':' + pad(this.getUTCSeconds())
+ '.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5)
+ 'Z';
};
}());
}
/*
* JS counterpart of the function in src/misc.cpp
*/
const parseHtmlLinks = function(text) {
const exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
return text.replace(exp, "<a target='_blank' href='$1'>$1</a>");
}
const escapeHtml = function(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
const safeTrim = function(value) {
try {
return value.trim();
}
catch (e) {
if (e instanceof TypeError)
return "";
throw e;
}
}
const toFixedPointString = function(number, digits) {
// Do not round up number
const power = Math.pow(10, digits);
return (Math.floor(power * number) / power).toFixed(digits);
}
/**
*
* @param {String} text the text to search
* @param {Array<String>} terms terms to search for within the text
* @returns {Boolean} true if all terms match the text, false otherwise
*/
const containsAllTerms = function(text, terms) {
const textToSearch = text.toLowerCase();
return terms.every((function(term) {
const isTermRequired = (term[0] === '+');
const isTermExcluded = (term[0] === '-');
if (isTermRequired || isTermExcluded) {
// ignore lonely +/-
if (term.length === 1)
return true;
term = term.substring(1);
}
const textContainsTerm = (textToSearch.indexOf(term) !== -1);
return isTermExcluded ? !textContainsTerm : textContainsTerm;
}));
}
return exports();
})();

View file

@ -38,7 +38,7 @@
----------------------------------------------------------------- */ ----------------------------------------------------------------- */
'use strict'; 'use strict';
const LocalPreferences = new LocalPreferencesClass(); const LocalPreferences = new window.qBittorrent.LocalPreferences.LocalPreferencesClass();
let saveWindowSize = function() {}; let saveWindowSize = function() {};
let loadWindowWidth = function() {}; let loadWindowWidth = function() {};

View file

@ -28,20 +28,34 @@
'use strict'; 'use strict';
const LocalPreferencesClass = new Class({ if (window.qBittorrent === undefined) {
get: function(key, defaultValue) { window.qBittorrent = {};
const value = localStorage.getItem(key); }
return ((value === null) && (defaultValue !== undefined))
? defaultValue
: value;
},
set: function(key, value) { window.qBittorrent.LocalPreferences = (function() {
try { const exports = function() {
localStorage.setItem(key, value); return {
LocalPreferencesClass: LocalPreferencesClass
};
};
const LocalPreferencesClass = new Class({
get: function(key, defaultValue) {
const value = localStorage.getItem(key);
return ((value === null) && (defaultValue !== undefined))
? defaultValue
: value;
},
set: function(key, value) {
try {
localStorage.setItem(key, value);
}
catch (err) {
console.error(err);
}
} }
catch (err) { })
console.error(err);
} return exports();
} })();
})

View file

@ -28,113 +28,126 @@
'use strict'; 'use strict';
const ProgressBar = new Class({ if (window.qBittorrent === undefined) {
initialize: function(value, parameters) { window.qBittorrent = {};
const vals = { }
'id': 'progressbar_' + (ProgressBars++),
'value': $pick(value, 0), window.qBittorrent.ProgressBar = (function() {
'width': 0, const exports = function() {
'height': 0, return {
'darkbg': '#006', ProgressBar: ProgressBar
'darkfg': '#fff',
'lightbg': '#fff',
'lightfg': '#000'
}; };
if (parameters && $type(parameters) == 'object') $extend(vals, parameters); };
if (vals.height < 12) vals.height = 12;
const obj = new Element('div', { let ProgressBars = 0;
'id': vals.id, const ProgressBar = new Class({
'class': 'progressbar_wrapper', initialize: function(value, parameters) {
'styles': { const vals = {
'border': '1px solid #000', 'id': 'progressbar_' + (ProgressBars++),
'width': vals.width, 'value': $pick(value, 0),
'height': vals.height, 'width': 0,
'position': 'relative', 'height': 0,
'margin': '0 auto' 'darkbg': '#006',
} 'darkfg': '#fff',
}); 'lightbg': '#fff',
obj.vals = vals; 'lightfg': '#000'
obj.vals.value = $pick(value, 0); // Fix by Chris };
obj.vals.dark = new Element('div', { if (parameters && $type(parameters) == 'object') $extend(vals, parameters);
'id': vals.id + '_dark', if (vals.height < 12) vals.height = 12;
'class': 'progressbar_dark', const obj = new Element('div', {
'styles': { 'id': vals.id,
'width': vals.width, 'class': 'progressbar_wrapper',
'height': vals.height, 'styles': {
'background': vals.darkbg, 'border': '1px solid #000',
'color': vals.darkfg, 'width': vals.width,
'position': 'absolute', 'height': vals.height,
'text-align': 'center', 'position': 'relative',
'left': 0, 'margin': '0 auto'
'top': 0, }
'line-height': vals.height });
} obj.vals = vals;
}); obj.vals.value = $pick(value, 0); // Fix by Chris
obj.vals.light = new Element('div', { obj.vals.dark = new Element('div', {
'id': vals.id + '_light', 'id': vals.id + '_dark',
'class': 'progressbar_light', 'class': 'progressbar_dark',
'styles': { 'styles': {
'width': vals.width, 'width': vals.width,
'height': vals.height, 'height': vals.height,
'background': vals.lightbg, 'background': vals.darkbg,
'color': vals.lightfg, 'color': vals.darkfg,
'position': 'absolute', 'position': 'absolute',
'text-align': 'center', 'text-align': 'center',
'left': 0, 'left': 0,
'top': 0, 'top': 0,
'line-height': vals.height 'line-height': vals.height
} }
}); });
obj.appendChild(obj.vals.dark); obj.vals.light = new Element('div', {
obj.appendChild(obj.vals.light); 'id': vals.id + '_light',
obj.getValue = ProgressBar_getValue; 'class': 'progressbar_light',
obj.setValue = ProgressBar_setValue; 'styles': {
obj.setWidth = ProgressBar_setWidth; 'width': vals.width,
if (vals.width) obj.setValue(vals.value); 'height': vals.height,
else setTimeout('ProgressBar_checkForParent("' + obj.id + '")', 1); 'background': vals.lightbg,
return obj; 'color': vals.lightfg,
'position': 'absolute',
'text-align': 'center',
'left': 0,
'top': 0,
'line-height': vals.height
}
});
obj.appendChild(obj.vals.dark);
obj.appendChild(obj.vals.light);
obj.getValue = ProgressBar_getValue;
obj.setValue = ProgressBar_setValue;
obj.setWidth = ProgressBar_setWidth;
if (vals.width) obj.setValue(vals.value);
else setTimeout('ProgressBar_checkForParent("' + obj.id + '")', 1);
return obj;
}
});
function ProgressBar_getValue() {
return this.vals.value;
} }
});
function ProgressBar_getValue() { function ProgressBar_setValue(value) {
return this.vals.value; value = parseFloat(value);
} if (isNaN(value)) value = 0;
if (value > 100) value = 100;
function ProgressBar_setValue(value) { if (value < 0) value = 0;
value = parseFloat(value); this.vals.value = value;
if (isNaN(value)) value = 0; this.vals.dark.empty();
if (value > 100) value = 100; this.vals.light.empty();
if (value < 0) value = 0; this.vals.dark.appendText(value.round(1).toFixed(1) + '%');
this.vals.value = value; this.vals.light.appendText(value.round(1).toFixed(1) + '%');
this.vals.dark.empty(); const r = parseInt(this.vals.width * (value / 100));
this.vals.light.empty(); this.vals.dark.setStyle('clip', 'rect(0,' + r + 'px,' + this.vals.height + 'px,0)');
this.vals.dark.appendText(value.round(1).toFixed(1) + '%'); this.vals.light.setStyle('clip', 'rect(0,' + this.vals.width + 'px,' + this.vals.height + 'px,' + r + 'px)');
this.vals.light.appendText(value.round(1).toFixed(1) + '%');
const r = parseInt(this.vals.width * (value / 100));
this.vals.dark.setStyle('clip', 'rect(0,' + r + 'px,' + this.vals.height + 'px,0)');
this.vals.light.setStyle('clip', 'rect(0,' + this.vals.width + 'px,' + this.vals.height + 'px,' + r + 'px)');
}
function ProgressBar_setWidth(value) {
if (this.vals.width !== value) {
this.vals.width = value;
this.setStyle('width', value);
this.vals.dark.setStyle('width', value);
this.vals.light.setStyle('width', value);
this.setValue(this.vals.value);
} }
}
function ProgressBar_checkForParent(id) { function ProgressBar_setWidth(value) {
const obj = $(id); if (this.vals.width !== value) {
if (!obj) return; this.vals.width = value;
if (!obj.parentNode) return setTimeout('ProgressBar_checkForParent("' + id + '")', 1); this.setStyle('width', value);
obj.setStyle('width', '100%'); this.vals.dark.setStyle('width', value);
const w = obj.offsetWidth; this.vals.light.setStyle('width', value);
obj.vals.dark.setStyle('width', w); this.setValue(this.vals.value);
obj.vals.light.setStyle('width', w); }
obj.vals.width = w; }
obj.setValue(obj.vals.value);
}
let ProgressBars = 0; function ProgressBar_checkForParent(id) {
const obj = $(id);
if (!obj) return;
if (!obj.parentNode) return setTimeout('ProgressBar_checkForParent("' + id + '")', 1);
obj.setStyle('width', '100%');
const w = obj.offsetWidth;
obj.vals.dark.setStyle('width', w);
obj.vals.light.setStyle('width', w);
obj.vals.width = w;
obj.setValue(obj.vals.value);
}
return exports();
})();

File diff suppressed because it is too large Load diff

View file

@ -28,172 +28,186 @@
'use strict'; 'use strict';
const clearData = function() { if (window.qBittorrent === undefined) {
$('time_elapsed').set('html', ''); window.qBittorrent = {};
$('eta').set('html', ''); }
$('nb_connections').set('html', '');
$('total_downloaded').set('html', '');
$('total_uploaded').set('html', '');
$('dl_speed').set('html', '');
$('up_speed').set('html', '');
$('dl_limit').set('html', '');
$('up_limit').set('html', '');
$('total_wasted').set('html', '');
$('seeds').set('html', '');
$('peers').set('html', '');
$('share_ratio').set('html', '');
$('reannounce').set('html', '');
$('last_seen').set('html', '');
$('total_size').set('html', '');
$('pieces').set('html', '');
$('created_by').set('html', '');
$('addition_date').set('html', '');
$('completion_date').set('html', '');
$('creation_date').set('html', '');
$('torrent_hash').set('html', '');
$('save_path').set('html', '');
$('comment').set('html', '');
};
let loadTorrentDataTimer; window.qBittorrent.PropGeneral = (function() {
const loadTorrentData = function() { const exports = function() {
if ($('prop_general').hasClass('invisible') return {
|| $('propertiesPanel_collapseToggle').hasClass('panel-expand')) { updateData: updateData
// Tab changed, don't do anything };
return; };
}
const current_hash = torrentsTable.getCurrentTorrentHash();
if (current_hash === "") {
clearData();
clearTimeout(loadTorrentDataTimer);
loadTorrentDataTimer = loadTorrentData.delay(5000);
return;
}
// Display hash
$('torrent_hash').set('html', current_hash);
const url = new URI('api/v2/torrents/properties?hash=' + current_hash);
new Request.JSON({
url: url,
noCache: true,
method: 'get',
onFailure: function() {
$('error_div').set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]');
clearTimeout(loadTorrentDataTimer);
loadTorrentDataTimer = loadTorrentData.delay(10000);
},
onSuccess: function(data) {
$('error_div').set('html', '');
if (data) {
let temp;
// Update Torrent data
if (data.seeding_time > 0)
temp = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", friendlyDuration(data.time_elapsed))
.replace("%2", friendlyDuration(data.seeding_time));
else
temp = friendlyDuration(data.time_elapsed);
$('time_elapsed').set('html', temp);
$('eta').set('html', friendlyDuration(data.eta)); const clearData = function() {
$('time_elapsed').set('html', '');
$('eta').set('html', '');
$('nb_connections').set('html', '');
$('total_downloaded').set('html', '');
$('total_uploaded').set('html', '');
$('dl_speed').set('html', '');
$('up_speed').set('html', '');
$('dl_limit').set('html', '');
$('up_limit').set('html', '');
$('total_wasted').set('html', '');
$('seeds').set('html', '');
$('peers').set('html', '');
$('share_ratio').set('html', '');
$('reannounce').set('html', '');
$('last_seen').set('html', '');
$('total_size').set('html', '');
$('pieces').set('html', '');
$('created_by').set('html', '');
$('addition_date').set('html', '');
$('completion_date').set('html', '');
$('creation_date').set('html', '');
$('torrent_hash').set('html', '');
$('save_path').set('html', '');
$('comment').set('html', '');
};
temp = "QBT_TR(%1 (%2 max))QBT_TR[CONTEXT=PropertiesWidget]" let loadTorrentDataTimer;
.replace("%1", data.nb_connections) const loadTorrentData = function() {
.replace("%2", data.nb_connections_limit < 0 ? "∞" : data.nb_connections_limit); if ($('prop_general').hasClass('invisible')
$('nb_connections').set('html', temp); || $('propertiesPanel_collapseToggle').hasClass('panel-expand')) {
// Tab changed, don't do anything
temp = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]" return;
.replace("%1", friendlyUnit(data.total_downloaded)) }
.replace("%2", friendlyUnit(data.total_downloaded_session)); const current_hash = torrentsTable.getCurrentTorrentHash();
$('total_downloaded').set('html', temp); if (current_hash === "") {
clearData();
temp = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", friendlyUnit(data.total_uploaded))
.replace("%2", friendlyUnit(data.total_uploaded_session));
$('total_uploaded').set('html', temp);
temp = "QBT_TR(%1 (%2 avg.))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", friendlyUnit(data.dl_speed, true))
.replace("%2", friendlyUnit(data.dl_speed_avg, true));
$('dl_speed').set('html', temp);
temp = "QBT_TR(%1 (%2 avg.))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", friendlyUnit(data.up_speed, true))
.replace("%2", friendlyUnit(data.up_speed_avg, true));
$('up_speed').set('html', temp);
temp = (data.dl_limit == -1 ? "∞" : friendlyUnit(data.dl_limit, true));
$('dl_limit').set('html', temp);
temp = (data.up_limit == -1 ? "∞" : friendlyUnit(data.up_limit, true));
$('up_limit').set('html', temp);
$('total_wasted').set('html', friendlyUnit(data.total_wasted));
temp = "QBT_TR(%1 (%2 total))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.seeds)
.replace("%2", data.seeds_total);
$('seeds').set('html', temp);
temp = "QBT_TR(%1 (%2 total))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.peers)
.replace("%2", data.peers_total);
$('peers').set('html', temp);
$('share_ratio').set('html', data.share_ratio.toFixed(2));
$('reannounce').set('html', friendlyDuration(data.reannounce));
if (data.last_seen != -1)
temp = new Date(data.last_seen * 1000).toLocaleString();
else
temp = "QBT_TR(Never)QBT_TR[CONTEXT=PropertiesWidget]";
$('last_seen').set('html', temp);
$('total_size').set('html', friendlyUnit(data.total_size));
if (data.pieces_num != -1)
temp = "QBT_TR(%1 x %2 (have %3))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.pieces_num)
.replace("%2", friendlyUnit(data.piece_size))
.replace("%3", data.pieces_have);
else
temp = "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]";
$('pieces').set('html', temp);
$('created_by').set('html', escapeHtml(data.created_by));
if (data.addition_date != -1)
temp = new Date(data.addition_date * 1000).toLocaleString();
else
temp = "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]";
$('addition_date').set('html', temp);
if (data.completion_date != -1)
temp = new Date(data.completion_date * 1000).toLocaleString();
else
temp = "";
$('completion_date').set('html', temp);
if (data.creation_date != -1)
temp = new Date(data.creation_date * 1000).toLocaleString();
else
temp = "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]";
$('creation_date').set('html', temp);
$('save_path').set('html', data.save_path);
$('comment').set('html', parseHtmlLinks(escapeHtml(data.comment)));
}
else {
clearData();
}
clearTimeout(loadTorrentDataTimer); clearTimeout(loadTorrentDataTimer);
loadTorrentDataTimer = loadTorrentData.delay(5000); loadTorrentDataTimer = loadTorrentData.delay(5000);
return;
} }
}).send(); // Display hash
}; $('torrent_hash').set('html', current_hash);
const url = new URI('api/v2/torrents/properties?hash=' + current_hash);
new Request.JSON({
url: url,
noCache: true,
method: 'get',
onFailure: function() {
$('error_div').set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]');
clearTimeout(loadTorrentDataTimer);
loadTorrentDataTimer = loadTorrentData.delay(10000);
},
onSuccess: function(data) {
$('error_div').set('html', '');
if (data) {
let temp;
// Update Torrent data
if (data.seeding_time > 0)
temp = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyDuration(data.time_elapsed))
.replace("%2", window.qBittorrent.Misc.friendlyDuration(data.seeding_time));
else
temp = window.qBittorrent.Misc.friendlyDuration(data.time_elapsed);
$('time_elapsed').set('html', temp);
updateTorrentData = function() { $('eta').set('html', window.qBittorrent.Misc.friendlyDuration(data.eta));
clearTimeout(loadTorrentDataTimer);
loadTorrentData(); temp = "QBT_TR(%1 (%2 max))QBT_TR[CONTEXT=PropertiesWidget]"
}; .replace("%1", data.nb_connections)
.replace("%2", data.nb_connections_limit < 0 ? "∞" : data.nb_connections_limit);
$('nb_connections').set('html', temp);
temp = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyUnit(data.total_downloaded))
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.total_downloaded_session));
$('total_downloaded').set('html', temp);
temp = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyUnit(data.total_uploaded))
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.total_uploaded_session));
$('total_uploaded').set('html', temp);
temp = "QBT_TR(%1 (%2 avg.))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyUnit(data.dl_speed, true))
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.dl_speed_avg, true));
$('dl_speed').set('html', temp);
temp = "QBT_TR(%1 (%2 avg.))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyUnit(data.up_speed, true))
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.up_speed_avg, true));
$('up_speed').set('html', temp);
temp = (data.dl_limit == -1 ? "∞" : window.qBittorrent.Misc.friendlyUnit(data.dl_limit, true));
$('dl_limit').set('html', temp);
temp = (data.up_limit == -1 ? "∞" : window.qBittorrent.Misc.friendlyUnit(data.up_limit, true));
$('up_limit').set('html', temp);
$('total_wasted').set('html', window.qBittorrent.Misc.friendlyUnit(data.total_wasted));
temp = "QBT_TR(%1 (%2 total))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.seeds)
.replace("%2", data.seeds_total);
$('seeds').set('html', temp);
temp = "QBT_TR(%1 (%2 total))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.peers)
.replace("%2", data.peers_total);
$('peers').set('html', temp);
$('share_ratio').set('html', data.share_ratio.toFixed(2));
$('reannounce').set('html', window.qBittorrent.Misc.friendlyDuration(data.reannounce));
if (data.last_seen != -1)
temp = new Date(data.last_seen * 1000).toLocaleString();
else
temp = "QBT_TR(Never)QBT_TR[CONTEXT=PropertiesWidget]";
$('last_seen').set('html', temp);
$('total_size').set('html', window.qBittorrent.Misc.friendlyUnit(data.total_size));
if (data.pieces_num != -1)
temp = "QBT_TR(%1 x %2 (have %3))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.pieces_num)
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.piece_size))
.replace("%3", data.pieces_have);
else
temp = "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]";
$('pieces').set('html', temp);
$('created_by').set('html', window.qBittorrent.Misc.escapeHtml(data.created_by));
if (data.addition_date != -1)
temp = new Date(data.addition_date * 1000).toLocaleString();
else
temp = "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]";
$('addition_date').set('html', temp);
if (data.completion_date != -1)
temp = new Date(data.completion_date * 1000).toLocaleString();
else
temp = "";
$('completion_date').set('html', temp);
if (data.creation_date != -1)
temp = new Date(data.creation_date * 1000).toLocaleString();
else
temp = "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]";
$('creation_date').set('html', temp);
$('save_path').set('html', data.save_path);
$('comment').set('html', window.qBittorrent.Misc.parseHtmlLinks(window.qBittorrent.Misc.escapeHtml(data.comment)));
}
else {
clearData();
}
clearTimeout(loadTorrentDataTimer);
loadTorrentDataTimer = loadTorrentData.delay(5000);
}
}).send();
};
const updateData = function() {
clearTimeout(loadTorrentDataTimer);
loadTorrentData();
};
return exports();
})();

View file

@ -28,144 +28,160 @@
'use strict'; 'use strict';
let loadTorrentPeersTimer; if (window.qBittorrent === undefined) {
let syncTorrentPeersLastResponseId = 0; window.qBittorrent = {};
let show_flags = true; }
const loadTorrentPeersData = function() {
if ($('prop_peers').hasClass('invisible') window.qBittorrent.PropPeers = (function() {
|| $('propertiesPanel_collapseToggle').hasClass('panel-expand')) { const exports = function() {
syncTorrentPeersLastResponseId = 0; return {
torrentPeersTable.clear(); updateData: updateData
return; }
} };
const current_hash = torrentsTable.getCurrentTorrentHash();
if (current_hash === "") { const torrentPeersTable = new window.qBittorrent.DynamicTable.TorrentPeersTable();
syncTorrentPeersLastResponseId = 0; let loadTorrentPeersTimer;
torrentPeersTable.clear(); let syncTorrentPeersLastResponseId = 0;
clearTimeout(loadTorrentPeersTimer); let show_flags = true;
loadTorrentPeersTimer = loadTorrentPeersData.delay(getSyncMainDataInterval());
return; const loadTorrentPeersData = function() {
} if ($('prop_peers').hasClass('invisible')
const url = new URI('api/v2/sync/torrentPeers'); || $('propertiesPanel_collapseToggle').hasClass('panel-expand')) {
url.setData('rid', syncTorrentPeersLastResponseId); syncTorrentPeersLastResponseId = 0;
url.setData('hash', current_hash); torrentPeersTable.clear();
new Request.JSON({ return;
url: url, }
noCache: true, const current_hash = torrentsTable.getCurrentTorrentHash();
method: 'get', if (current_hash === "") {
onComplete: function() { syncTorrentPeersLastResponseId = 0;
torrentPeersTable.clear();
clearTimeout(loadTorrentPeersTimer); clearTimeout(loadTorrentPeersTimer);
loadTorrentPeersTimer = loadTorrentPeersData.delay(getSyncMainDataInterval()); loadTorrentPeersTimer = loadTorrentPeersData.delay(getSyncMainDataInterval());
}, return;
onSuccess: function(response) { }
$('error_div').set('html', ''); const url = new URI('api/v2/sync/torrentPeers');
if (response) { url.setData('rid', syncTorrentPeersLastResponseId);
const full_update = (response['full_update'] === true); url.setData('hash', current_hash);
if (full_update) new Request.JSON({
url: url,
noCache: true,
method: 'get',
onComplete: function() {
clearTimeout(loadTorrentPeersTimer);
loadTorrentPeersTimer = loadTorrentPeersData.delay(getSyncMainDataInterval());
},
onSuccess: function(response) {
$('error_div').set('html', '');
if (response) {
const full_update = (response['full_update'] === true);
if (full_update)
torrentPeersTable.clear();
if (response['rid'])
syncTorrentPeersLastResponseId = response['rid'];
if (response['peers']) {
for (const key in response['peers']) {
response['peers'][key]['rowId'] = key;
if (response['peers'][key]['client'])
response['peers'][key]['client'] = window.qBittorrent.Misc.escapeHtml(response['peers'][key]['client']);
torrentPeersTable.updateRowData(response['peers'][key]);
}
}
if (response['peers_removed']) {
response['peers_removed'].each(function(hash) {
torrentPeersTable.removeRow(hash);
});
}
torrentPeersTable.updateTable(full_update);
torrentPeersTable.altRow();
if (response['show_flags']) {
if (show_flags != response['show_flags']) {
show_flags = response['show_flags'];
torrentPeersTable.columns['country'].force_hide = !show_flags;
torrentPeersTable.updateColumn('country');
}
}
}
else {
torrentPeersTable.clear(); torrentPeersTable.clear();
if (response['rid'])
syncTorrentPeersLastResponseId = response['rid'];
if (response['peers']) {
for (const key in response['peers']) {
response['peers'][key]['rowId'] = key;
if (response['peers'][key]['client'])
response['peers'][key]['client'] = escapeHtml(response['peers'][key]['client']);
torrentPeersTable.updateRowData(response['peers'][key]);
}
} }
if (response['peers_removed']) { }
response['peers_removed'].each(function(hash) { }).send();
torrentPeersTable.removeRow(hash); };
});
}
torrentPeersTable.updateTable(full_update);
torrentPeersTable.altRow();
if (response['show_flags']) { const updateData = function() {
if (show_flags != response['show_flags']) { clearTimeout(loadTorrentPeersTimer);
show_flags = response['show_flags']; loadTorrentPeersData();
torrentPeersTable.columns['country'].force_hide = !show_flags; };
torrentPeersTable.updateColumn('country');
} const torrentPeersContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
targets: '#torrentPeersTableDiv',
menu: 'torrentPeersMenu',
actions: {
addPeer: function(element, ref) {
const hash = torrentsTable.getCurrentTorrentHash();
if (!hash)
return;
new MochaUI.Window({
id: 'addPeersPage',
title: "QBT_TR(Add Peers)QBT_TR[CONTEXT=PeersAdditionDialog]",
loadMethod: 'iframe',
contentURL: 'addpeers.html?hash=' + hash,
scrollbars: false,
resizable: false,
maximizable: false,
paddingVertical: 0,
paddingHorizontal: 0,
width: 350,
height: 240
});
},
banPeer: function(element, ref) {
const selectedPeers = torrentPeersTable.selectedRowsIds();
if (selectedPeers.length === 0)
return;
if (confirm('QBT_TR(Are you sure you want to permanently ban the selected peers?)QBT_TR[CONTEXT=PeerListWidget]')) {
new Request({
url: 'api/v2/torrents/banPeers',
noCache: true,
method: 'post',
data: {
hash: torrentsTable.getCurrentTorrentHash(),
peers: selectedPeers.join('|')
}
}).send();
} }
} }
},
offsets: {
x: -15,
y: 2
},
onShow: function() {
const selectedPeers = torrentPeersTable.selectedRowsIds();
if (selectedPeers.length >= 1) {
this.showItem('copyPeer');
this.showItem('banPeer');
}
else { else {
torrentPeersTable.clear(); this.hideItem('copyPeer');
this.hideItem('banPeer');
} }
} }
}).send(); });
};
updateTorrentPeersData = function() { new ClipboardJS('#CopyPeerInfo', {
clearTimeout(loadTorrentPeersTimer); text: function(trigger) {
loadTorrentPeersData(); return torrentPeersTable.selectedRowsIds().join("\n");
};
const torrentPeersContextMenu = new ContextMenu({
targets: '#torrentPeersTableDiv',
menu: 'torrentPeersMenu',
actions: {
addPeer: function(element, ref) {
const hash = torrentsTable.getCurrentTorrentHash();
if (!hash)
return;
new MochaUI.Window({
id: 'addPeersPage',
title: "QBT_TR(Add Peers)QBT_TR[CONTEXT=PeersAdditionDialog]",
loadMethod: 'iframe',
contentURL: 'addpeers.html?hash=' + hash,
scrollbars: false,
resizable: false,
maximizable: false,
paddingVertical: 0,
paddingHorizontal: 0,
width: 350,
height: 240
});
},
banPeer: function(element, ref) {
const selectedPeers = torrentPeersTable.selectedRowsIds();
if (selectedPeers.length === 0)
return;
if (confirm('QBT_TR(Are you sure you want to permanently ban the selected peers?)QBT_TR[CONTEXT=PeerListWidget]')) {
new Request({
url: 'api/v2/torrents/banPeers',
noCache: true,
method: 'post',
data: {
hash: torrentsTable.getCurrentTorrentHash(),
peers: selectedPeers.join('|')
}
}).send();
}
} }
}, });
offsets: {
x: -15,
y: 2
},
onShow: function() {
const selectedPeers = torrentPeersTable.selectedRowsIds();
if (selectedPeers.length >= 1) { torrentPeersTable.setup('torrentPeersTableDiv', 'torrentPeersTableFixedHeaderDiv', torrentPeersContextMenu);
this.showItem('copyPeer');
this.showItem('banPeer');
}
else {
this.hideItem('copyPeer');
this.hideItem('banPeer');
}
}
});
new ClipboardJS('#CopyPeerInfo', { return exports();
text: function(trigger) { })();
return torrentPeersTable.selectedRowsIds().join("\n");
}
});
torrentPeersTable.setup('torrentPeersTableDiv', 'torrentPeersTableFixedHeaderDiv', torrentPeersContextMenu);

View file

@ -28,195 +28,211 @@
'use strict'; 'use strict';
this.current_hash = ""; if (window.qBittorrent === undefined) {
window.qBittorrent = {};
}
let loadTrackersDataTimer; window.qBittorrent.PropTrackers = (function() {
const loadTrackersData = function() { const exports = function() {
if ($('prop_trackers').hasClass('invisible') return {
|| $('propertiesPanel_collapseToggle').hasClass('panel-expand')) { updateData: updateData
// Tab changed, don't do anything };
return; };
}
const new_hash = torrentsTable.getCurrentTorrentHash(); let current_hash = "";
if (new_hash === "") {
torrentTrackersTable.clear(); const torrentTrackersTable = new window.qBittorrent.DynamicTable.TorrentTrackersTable();
clearTimeout(loadTrackersDataTimer); let loadTrackersDataTimer;
loadTrackersDataTimer = loadTrackersData.delay(10000);
return; const loadTrackersData = function() {
} if ($('prop_trackers').hasClass('invisible')
if (new_hash != current_hash) { || $('propertiesPanel_collapseToggle').hasClass('panel-expand')) {
torrentTrackersTable.clear(); // Tab changed, don't do anything
current_hash = new_hash; return;
} }
const url = new URI('api/v2/torrents/trackers?hash=' + current_hash); const new_hash = torrentsTable.getCurrentTorrentHash();
new Request.JSON({ if (new_hash === "") {
url: url, torrentTrackersTable.clear();
noCache: true,
method: 'get',
onComplete: function() {
clearTimeout(loadTrackersDataTimer); clearTimeout(loadTrackersDataTimer);
loadTrackersDataTimer = loadTrackersData.delay(10000); loadTrackersDataTimer = loadTrackersData.delay(10000);
}, return;
onSuccess: function(trackers) { }
const selectedTrackers = torrentTrackersTable.selectedRowsIds(); if (new_hash != current_hash) {
torrentTrackersTable.clear(); torrentTrackersTable.clear();
current_hash = new_hash;
}
const url = new URI('api/v2/torrents/trackers?hash=' + current_hash);
new Request.JSON({
url: url,
noCache: true,
method: 'get',
onComplete: function() {
clearTimeout(loadTrackersDataTimer);
loadTrackersDataTimer = loadTrackersData.delay(10000);
},
onSuccess: function(trackers) {
const selectedTrackers = torrentTrackersTable.selectedRowsIds();
torrentTrackersTable.clear();
if (trackers) { if (trackers) {
trackers.each(function(tracker) { trackers.each(function(tracker) {
const url = escapeHtml(tracker.url); const url = window.qBittorrent.Misc.escapeHtml(tracker.url);
let status; let status;
switch (tracker.status) { switch (tracker.status) {
case 0: case 0:
status = "QBT_TR(Disabled)QBT_TR[CONTEXT=TrackerListWidget]"; status = "QBT_TR(Disabled)QBT_TR[CONTEXT=TrackerListWidget]";
break; break;
case 1: case 1:
status = "QBT_TR(Not contacted yet)QBT_TR[CONTEXT=TrackerListWidget]"; status = "QBT_TR(Not contacted yet)QBT_TR[CONTEXT=TrackerListWidget]";
break; break;
case 2: case 2:
status = "QBT_TR(Working)QBT_TR[CONTEXT=TrackerListWidget]"; status = "QBT_TR(Working)QBT_TR[CONTEXT=TrackerListWidget]";
break; break;
case 3: case 3:
status = "QBT_TR(Updating...)QBT_TR[CONTEXT=TrackerListWidget]"; status = "QBT_TR(Updating...)QBT_TR[CONTEXT=TrackerListWidget]";
break; break;
case 4: case 4:
status = "QBT_TR(Not working)QBT_TR[CONTEXT=TrackerListWidget]"; status = "QBT_TR(Not working)QBT_TR[CONTEXT=TrackerListWidget]";
break; break;
} }
const row = { const row = {
rowId: url, rowId: url,
tier: tracker.tier, tier: tracker.tier,
url: url, url: url,
status: status, status: status,
peers: tracker.num_peers, peers: tracker.num_peers,
seeds: (tracker.num_seeds >= 0) ? tracker.num_seeds : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]", seeds: (tracker.num_seeds >= 0) ? tracker.num_seeds : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]",
leeches: (tracker.num_leeches >= 0) ? tracker.num_leeches : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]", leeches: (tracker.num_leeches >= 0) ? tracker.num_leeches : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]",
downloaded: (tracker.num_downloaded >= 0) ? tracker.num_downloaded : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]", downloaded: (tracker.num_downloaded >= 0) ? tracker.num_downloaded : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]",
message: escapeHtml(tracker.msg) message: window.qBittorrent.Misc.escapeHtml(tracker.msg)
}; };
torrentTrackersTable.updateRowData(row); torrentTrackersTable.updateRowData(row);
}); });
torrentTrackersTable.updateTable(false); torrentTrackersTable.updateTable(false);
torrentTrackersTable.altRow(); torrentTrackersTable.altRow();
if (selectedTrackers.length > 0) if (selectedTrackers.length > 0)
torrentTrackersTable.reselectRows(selectedTrackers); torrentTrackersTable.reselectRows(selectedTrackers);
}
}
}).send();
};
const updateData = function() {
clearTimeout(loadTrackersDataTimer);
loadTrackersData();
};
const torrentTrackersContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
targets: '#torrentTrackersTableDiv',
menu: 'torrentTrackersMenu',
actions: {
AddTracker: function(element, ref) {
addTrackerFN();
},
EditTracker: function(element, ref) {
// only allow editing of one row
element.firstChild.click();
editTrackerFN(element);
},
RemoveTracker: function(element, ref) {
removeTrackerFN(element);
}
},
offsets: {
x: -15,
y: 2
},
onShow: function() {
const selectedTrackers = torrentTrackersTable.selectedRowsIds();
const containsStaticTracker = selectedTrackers.some(function(tracker) {
return (tracker.indexOf("** [") === 0);
});
if (containsStaticTracker || (selectedTrackers.length === 0)) {
this.hideItem('EditTracker');
this.hideItem('RemoveTracker');
this.hideItem('CopyTrackerUrl');
}
else {
this.showItem('EditTracker');
this.showItem('RemoveTracker');
this.showItem('CopyTrackerUrl');
} }
} }
}).send(); });
};
updateTrackersData = function() { const addTrackerFN = function() {
clearTimeout(loadTrackersDataTimer); if (current_hash.length === 0) return;
loadTrackersData(); new MochaUI.Window({
}; id: 'trackersPage',
title: "QBT_TR(Trackers addition dialog)QBT_TR[CONTEXT=TrackersAdditionDialog]",
const torrentTrackersContextMenu = new ContextMenu({ loadMethod: 'iframe',
targets: '#torrentTrackersTableDiv', contentURL: 'addtrackers.html?hash=' + current_hash,
menu: 'torrentTrackersMenu', scrollbars: true,
actions: { resizable: false,
AddTracker: function(element, ref) { maximizable: false,
addTrackerFN(); closable: true,
}, paddingVertical: 0,
EditTracker: function(element, ref) { paddingHorizontal: 0,
// only allow editing of one row width: 500,
element.firstChild.click(); height: 250,
editTrackerFN(element); onCloseComplete: function() {
}, updateData();
RemoveTracker: function(element, ref) { }
removeTrackerFN(element);
}
},
offsets: {
x: -15,
y: 2
},
onShow: function() {
const selectedTrackers = torrentTrackersTable.selectedRowsIds();
const containsStaticTracker = selectedTrackers.some(function(tracker) {
return (tracker.indexOf("** [") === 0);
}); });
};
if (containsStaticTracker || (selectedTrackers.length === 0)) { const editTrackerFN = function(element) {
this.hideItem('EditTracker'); if (current_hash.length === 0) return;
this.hideItem('RemoveTracker');
this.hideItem('CopyTrackerUrl');
}
else {
this.showItem('EditTracker');
this.showItem('RemoveTracker');
this.showItem('CopyTrackerUrl');
}
}
});
const addTrackerFN = function() { const trackerUrl = encodeURIComponent(element.childNodes[1].innerText);
if (current_hash.length === 0) return; new MochaUI.Window({
new MochaUI.Window({ id: 'trackersPage',
id: 'trackersPage', title: "QBT_TR(Tracker editing)QBT_TR[CONTEXT=TrackerListWidget]",
title: "QBT_TR(Trackers addition dialog)QBT_TR[CONTEXT=TrackersAdditionDialog]", loadMethod: 'iframe',
loadMethod: 'iframe', contentURL: 'edittracker.html?hash=' + current_hash + '&url=' + trackerUrl,
contentURL: 'addtrackers.html?hash=' + current_hash, scrollbars: true,
scrollbars: true, resizable: false,
resizable: false, maximizable: false,
maximizable: false, closable: true,
closable: true, paddingVertical: 0,
paddingVertical: 0, paddingHorizontal: 0,
paddingHorizontal: 0, width: 500,
width: 500, height: 150,
height: 250, onCloseComplete: function() {
onCloseComplete: function() { updateData();
updateTrackersData(); }
});
};
const removeTrackerFN = function(element) {
if (current_hash.length === 0) return;
const selectedTrackers = torrentTrackersTable.selectedRowsIds();
new Request({
url: 'api/v2/torrents/removeTrackers',
method: 'post',
data: {
hash: current_hash,
urls: selectedTrackers.join("|")
},
onSuccess: function() {
updateData();
}
}).send();
};
new ClipboardJS('#CopyTrackerUrl', {
text: function(trigger) {
return torrentTrackersTable.selectedRowsIds().join("\n");
} }
}); });
};
const editTrackerFN = function(element) { torrentTrackersTable.setup('torrentTrackersTableDiv', 'torrentTrackersTableFixedHeaderDiv', torrentTrackersContextMenu);
if (current_hash.length === 0) return;
const trackerUrl = encodeURIComponent(element.childNodes[1].innerText); return exports();
new MochaUI.Window({ })();
id: 'trackersPage',
title: "QBT_TR(Tracker editing)QBT_TR[CONTEXT=TrackerListWidget]",
loadMethod: 'iframe',
contentURL: 'edittracker.html?hash=' + current_hash + '&url=' + trackerUrl,
scrollbars: true,
resizable: false,
maximizable: false,
closable: true,
paddingVertical: 0,
paddingHorizontal: 0,
width: 500,
height: 150,
onCloseComplete: function() {
updateTrackersData();
}
});
};
const removeTrackerFN = function(element) {
if (current_hash.length === 0) return;
const selectedTrackers = torrentTrackersTable.selectedRowsIds();
new Request({
url: 'api/v2/torrents/removeTrackers',
method: 'post',
data: {
hash: current_hash,
urls: selectedTrackers.join("|")
},
onSuccess: function() {
updateTrackersData();
}
}).send();
};
new ClipboardJS('#CopyTrackerUrl', {
text: function(trigger) {
return torrentTrackersTable.selectedRowsIds().join("\n");
}
});
torrentTrackersTable.setup('torrentTrackersTableDiv', 'torrentTrackersTableFixedHeaderDiv', torrentTrackersContextMenu);

View file

@ -28,112 +28,126 @@
'use strict'; 'use strict';
const webseedsDynTable = new Class({ if (window.qBittorrent === undefined) {
window.qBittorrent = {};
}
initialize: function() {}, window.qBittorrent.PropWebseeds = (function() {
const exports = function() {
return {
updateData: updateData
};
};
setup: function(table) { const webseedsDynTable = new Class({
this.table = $(table);
this.rows = new Hash();
},
removeRow: function(url) { initialize: function() {},
if (this.rows.has(url)) {
const tr = this.rows.get(url); setup: function(table) {
tr.dispose(); this.table = $(table);
this.rows.erase(url); this.rows = new Hash();
},
removeRow: function(url) {
if (this.rows.has(url)) {
const tr = this.rows.get(url);
tr.dispose();
this.rows.erase(url);
return true;
}
return false;
},
removeAllRows: function() {
this.rows.each(function(tr, url) {
this.removeRow(url);
}.bind(this));
},
updateRow: function(tr, row) {
const tds = tr.getElements('td');
for (let i = 0; i < row.length; ++i) {
tds[i].set('html', row[i]);
}
return true; return true;
} },
return false;
},
removeAllRows: function() { insertRow: function(row) {
this.rows.each(function(tr, url) { const url = row[0];
this.removeRow(url); if (this.rows.has(url)) {
}.bind(this)); const tableRow = this.rows.get(url);
}, this.updateRow(tableRow, row);
return;
}
//this.removeRow(id);
const tr = new Element('tr');
this.rows.set(url, tr);
for (let i = 0; i < row.length; ++i) {
const td = new Element('td');
td.set('html', row[i]);
td.injectInside(tr);
}
tr.injectInside(this.table);
},
});
updateRow: function(tr, row) { let current_hash = "";
const tds = tr.getElements('td');
for (let i = 0; i < row.length; ++i) {
tds[i].set('html', row[i]);
}
return true;
},
insertRow: function(row) { let loadWebSeedsDataTimer;
const url = row[0]; const loadWebSeedsData = function() {
if (this.rows.has(url)) { if ($('prop_webseeds').hasClass('invisible')
const tableRow = this.rows.get(url); || $('propertiesPanel_collapseToggle').hasClass('panel-expand')) {
this.updateRow(tableRow, row); // Tab changed, don't do anything
return; return;
} }
//this.removeRow(id); const new_hash = torrentsTable.getCurrentTorrentHash();
const tr = new Element('tr'); if (new_hash === "") {
this.rows.set(url, tr); wsTable.removeAllRows();
for (let i = 0; i < row.length; ++i) {
const td = new Element('td');
td.set('html', row[i]);
td.injectInside(tr);
}
tr.injectInside(this.table);
},
});
this.current_hash = "";
let loadWebSeedsDataTimer;
const loadWebSeedsData = function() {
if ($('prop_webseeds').hasClass('invisible')
|| $('propertiesPanel_collapseToggle').hasClass('panel-expand')) {
// Tab changed, don't do anything
return;
}
const new_hash = torrentsTable.getCurrentTorrentHash();
if (new_hash === "") {
wsTable.removeAllRows();
clearTimeout(loadWebSeedsDataTimer);
loadWebSeedsDataTimer = loadWebSeedsData.delay(10000);
return;
}
if (new_hash != current_hash) {
wsTable.removeAllRows();
current_hash = new_hash;
}
const url = new URI('api/v2/torrents/webseeds?hash=' + current_hash);
new Request.JSON({
url: url,
noCache: true,
method: 'get',
onFailure: function() {
$('error_div').set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]');
clearTimeout(loadWebSeedsDataTimer);
loadWebSeedsDataTimer = loadWebSeedsData.delay(20000);
},
onSuccess: function(webseeds) {
$('error_div').set('html', '');
if (webseeds) {
// Update WebSeeds data
webseeds.each(function(webseed) {
const row = [];
row.length = 1;
row[0] = webseed.url;
wsTable.insertRow(row);
});
}
else {
wsTable.removeAllRows();
}
clearTimeout(loadWebSeedsDataTimer); clearTimeout(loadWebSeedsDataTimer);
loadWebSeedsDataTimer = loadWebSeedsData.delay(10000); loadWebSeedsDataTimer = loadWebSeedsData.delay(10000);
return;
} }
}).send(); if (new_hash != current_hash) {
}; wsTable.removeAllRows();
current_hash = new_hash;
}
const url = new URI('api/v2/torrents/webseeds?hash=' + current_hash);
new Request.JSON({
url: url,
noCache: true,
method: 'get',
onFailure: function() {
$('error_div').set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]');
clearTimeout(loadWebSeedsDataTimer);
loadWebSeedsDataTimer = loadWebSeedsData.delay(20000);
},
onSuccess: function(webseeds) {
$('error_div').set('html', '');
if (webseeds) {
// Update WebSeeds data
webseeds.each(function(webseed) {
const row = [];
row.length = 1;
row[0] = webseed.url;
wsTable.insertRow(row);
});
}
else {
wsTable.removeAllRows();
}
clearTimeout(loadWebSeedsDataTimer);
loadWebSeedsDataTimer = loadWebSeedsData.delay(10000);
}
}).send();
};
updateWebSeedsData = function() { const updateData = function() {
clearTimeout(loadWebSeedsDataTimer); clearTimeout(loadWebSeedsDataTimer);
loadWebSeedsData(); loadWebSeedsData();
}; };
const wsTable = new webseedsDynTable(); const wsTable = new webseedsDynTable();
wsTable.setup($('webseedsTable')); wsTable.setup($('webseedsTable'));
return exports();
})();

View file

@ -33,7 +33,7 @@
const path = new URI().getData('path'); const path = new URI().getData('path');
// set text field to current value // set text field to current value
if (path) if (path)
$('setLocation').value = escapeHtml(decodeURIComponent(path)); $('setLocation').value = window.qBittorrent.Misc.escapeHtml(decodeURIComponent(path));
$('setLocation').focus(); $('setLocation').focus();
$('setLocationButton').addEvent('click', function(e) { $('setLocationButton').addEvent('click', function(e) {

View file

@ -37,9 +37,9 @@
const origValues = new URI().getData('orig').split('|'); const origValues = new URI().getData('orig').split('|');
const values = { const values = {
ratioLimit: friendlyFloat(origValues[0], 2), ratioLimit: window.qBittorrent.Misc.friendlyFloat(origValues[0], 2),
seedingTimeLimit: parseInt(origValues[1]), seedingTimeLimit: parseInt(origValues[1]),
maxRatio: friendlyFloat(origValues[2], 2), maxRatio: window.qBittorrent.Misc.friendlyFloat(origValues[2], 2),
maxSeedingTime: parseInt(origValues[3]) maxSeedingTime: parseInt(origValues[3])
}; };

View file

@ -23,7 +23,7 @@
<label for="autoTMM">QBT_TR(Torrent Management Mode:)QBT_TR[CONTEXT=AddNewTorrentDialog]</label> <label for="autoTMM">QBT_TR(Torrent Management Mode:)QBT_TR[CONTEXT=AddNewTorrentDialog]</label>
</td> </td>
<td> <td>
<select id="autoTMM" name="autoTMM" onchange="changeTMM(this)"> <select id="autoTMM" name="autoTMM" onchange="qBittorrent.Download.changeTMM(this)">
<option selected value="false">Manual</option> <option selected value="false">Manual</option>
<option value="true">Automatic</option> <option value="true">Automatic</option>
</select> </select>
@ -51,7 +51,7 @@
</td> </td>
<td> <td>
<div class="select-watched-folder-editable"> <div class="select-watched-folder-editable">
<select id="categorySelect" onchange="changeCategorySelect(this)"> <select id="categorySelect" onchange="qBittorrent.Download.changeCategorySelect(this)">
<option selected value="\other"></option> <option selected value="\other"></option>
</select> </select>
<input name="category" type="text" value="" /> <input name="category" type="text" value="" />

View file

@ -681,22 +681,24 @@
<script> <script>
'use strict'; 'use strict';
$('qbittorrentVersion').innerText = ("qBittorrent " + qbtVersion() (function() {
$('qbittorrentVersion').innerText = ("qBittorrent " + qbtVersion()
+ " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]"); + " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]");
new Request.JSON({ new Request.JSON({
url: 'api/v2/app/buildInfo', url: 'api/v2/app/buildInfo',
method: 'get', method: 'get',
noCache: true, noCache: true,
onSuccess: function(info) { onSuccess: function(info) {
if (!info) return; if (!info) return;
$('qtVersion').textContent = info.qt; $('qtVersion').textContent = info.qt;
$('libtorrentVersion').textContent = info.libtorrent; $('libtorrentVersion').textContent = info.libtorrent;
$('boostVersion').textContent = info.boost; $('boostVersion').textContent = info.boost;
$('opensslVersion').textContent = info.openssl; $('opensslVersion').textContent = info.openssl;
$('zlibVersion').textContent = info.zlib; $('zlibVersion').textContent = info.zlib;
$('qbittorrentVersion').textContent += " (" + info.bitness + "-bit)"; $('qbittorrentVersion').textContent += " (" + info.bitness + "-bit)";
} }
}).send(); }).send();
})();
</script> </script>

View file

@ -13,35 +13,37 @@
<script> <script>
'use strict'; 'use strict';
MochaUI.initializeTabs('aboutTabs'); (function() {
MochaUI.initializeTabs('aboutTabs');
$('aboutAboutLink').addEvent('click', function() { $('aboutAboutLink').addEvent('click', function() {
$$('.aboutTabContent').addClass('invisible'); $$('.aboutTabContent').addClass('invisible');
$('aboutAboutContent').removeClass('invisible'); $('aboutAboutContent').removeClass('invisible');
}); });
$('aboutAuthorLink').addEvent('click', function() { $('aboutAuthorLink').addEvent('click', function() {
$$('.aboutTabContent').addClass('invisible'); $$('.aboutTabContent').addClass('invisible');
$('aboutAuthorContent').removeClass('invisible'); $('aboutAuthorContent').removeClass('invisible');
}); });
$('aboutSpecialThanksLink').addEvent('click', function() { $('aboutSpecialThanksLink').addEvent('click', function() {
$$('.aboutTabContent').addClass('invisible'); $$('.aboutTabContent').addClass('invisible');
$('aboutSpecialThanksContent').removeClass('invisible'); $('aboutSpecialThanksContent').removeClass('invisible');
}); });
$('aboutTranslatorsLink').addEvent('click', function() { $('aboutTranslatorsLink').addEvent('click', function() {
$$('.aboutTabContent').addClass('invisible'); $$('.aboutTabContent').addClass('invisible');
$('aboutTranslatorsContent').removeClass('invisible'); $('aboutTranslatorsContent').removeClass('invisible');
}); });
$('aboutLicenseLink').addEvent('click', function() { $('aboutLicenseLink').addEvent('click', function() {
$$('.aboutTabContent').addClass('invisible'); $$('.aboutTabContent').addClass('invisible');
$('aboutLicenseContent').removeClass('invisible'); $('aboutLicenseContent').removeClass('invisible');
}); });
$('aboutLibrariesLink').addEvent('click', function() { $('aboutLibrariesLink').addEvent('click', function() {
$$('.aboutTabContent').addClass('invisible'); $$('.aboutTabContent').addClass('invisible');
$('aboutLibrariesContent').removeClass('invisible'); $('aboutLibrariesContent').removeClass('invisible');
}); });
})();
</script> </script>

View file

@ -32,79 +32,94 @@
<script> <script>
'use strict'; 'use strict';
const categoriesFilterContextMenu = new CategoriesFilterContextMenu({ if (window.qBittorrent === undefined) {
targets: '.categoriesFilterContextMenuTarget', window.qBittorrent = {};
menu: 'categoriesFilterMenu', }
actions: {
createCategory: function(element, ref) { window.qBittorrent.Filters = (function() {
createCategoryFN(); const exports = function() {
return {
categoriesFilterContextMenu: categoriesFilterContextMenu,
tagsFilterContextMenu: tagsFilterContextMenu
};
};
const categoriesFilterContextMenu = new window.qBittorrent.ContextMenu.CategoriesFilterContextMenu({
targets: '.categoriesFilterContextMenuTarget',
menu: 'categoriesFilterMenu',
actions: {
createCategory: function(element, ref) {
createCategoryFN();
},
editCategory: function(element, ref) {
editCategoryFN(element.id);
},
deleteCategory: function(element, ref) {
removeCategoryFN(element.id);
},
deleteUnusedCategories: function(element, ref) {
deleteUnusedCategoriesFN();
},
startTorrentsByCategory: function(element, ref) {
startTorrentsByCategoryFN(element.id);
},
pauseTorrentsByCategory: function(element, ref) {
pauseTorrentsByCategoryFN(element.id);
},
deleteTorrentsByCategory: function(element, ref) {
deleteTorrentsByCategoryFN(element.id);
}
}, },
editCategory: function(element, ref) { offsets: {
editCategoryFN(element.id); x: -15,
y: 2
}, },
deleteCategory: function(element, ref) { onShow: function() {
removeCategoryFN(element.id); this.options.element.firstChild.click();
},
deleteUnusedCategories: function(element, ref) {
deleteUnusedCategoriesFN();
},
startTorrentsByCategory: function(element, ref) {
startTorrentsByCategoryFN(element.id);
},
pauseTorrentsByCategory: function(element, ref) {
pauseTorrentsByCategoryFN(element.id);
},
deleteTorrentsByCategory: function(element, ref) {
deleteTorrentsByCategoryFN(element.id);
} }
}, });
offsets: {
x: -15,
y: 2
},
onShow: function() {
this.options.element.firstChild.click();
}
});
const tagsFilterContextMenu = new TagsFilterContextMenu({ const tagsFilterContextMenu = new window.qBittorrent.ContextMenu.TagsFilterContextMenu({
targets: '.tagsFilterContextMenuTarget', targets: '.tagsFilterContextMenuTarget',
menu: 'tagsFilterMenu', menu: 'tagsFilterMenu',
actions: { actions: {
createTag: function(element, ref) { createTag: function(element, ref) {
createTagFN(); createTagFN();
},
deleteTag: function(element, ref) {
removeTagFN(element.id);
},
deleteUnusedTags: function(element, ref) {
deleteUnusedTagsFN();
},
startTorrentsByTag: function(element, ref) {
startTorrentsByTagFN(element.id);
},
pauseTorrentsByTag: function(element, ref) {
pauseTorrentsByTagFN(element.id);
},
deleteTorrentsByTag: function(element, ref) {
deleteTorrentsByTagFN(element.id);
}
}, },
deleteTag: function(element, ref) { offsets: {
removeTagFN(element.id); x: -15,
y: 2
}, },
deleteUnusedTags: function(element, ref) { onShow: function() {
deleteUnusedTagsFN(); this.options.element.firstChild.click();
},
startTorrentsByTag: function(element, ref) {
startTorrentsByTagFN(element.id);
},
pauseTorrentsByTag: function(element, ref) {
pauseTorrentsByTagFN(element.id);
},
deleteTorrentsByTag: function(element, ref) {
deleteTorrentsByTagFN(element.id);
} }
}, });
offsets: {
x: -15,
y: 2
},
onShow: function() {
this.options.element.firstChild.click();
}
});
if (LocalPreferences.get('filter_status_collapsed') === "true") if (LocalPreferences.get('filter_status_collapsed') === "true")
toggleFilterDisplay('status'); toggleFilterDisplay('status');
if (LocalPreferences.get('filter_category_collapsed') === "true") if (LocalPreferences.get('filter_category_collapsed') === "true")
toggleFilterDisplay('category'); toggleFilterDisplay('category');
if (LocalPreferences.get('filter_tag_collapsed') === "true") if (LocalPreferences.get('filter_tag_collapsed') === "true")
toggleFilterDisplay('tag'); toggleFilterDisplay('tag');
return exports();
})();
</script> </script>

View file

@ -20,8 +20,8 @@
<div> <div>
<input type="text" id="newPluginPath" placeholder="QBT_TR(URL or local directory)QBT_TR[CONTEXT=PluginSourceDlg]" autocorrect="off" autocapitalize="none" /> <input type="text" id="newPluginPath" placeholder="QBT_TR(URL or local directory)QBT_TR[CONTEXT=PluginSourceDlg]" autocorrect="off" autocapitalize="none" />
<div style="margin-top: 10px; text-align: center;"> <div style="margin-top: 10px; text-align: center;">
<button id="newPluginCancel" onclick="closeSearchWindow('installSearchPlugin');">QBT_TR(Cancel)QBT_TR[CONTEXT=PluginSourceDlg]</button> <button id="newPluginCancel" onclick="qBittorrent.SearchPlugins.closeSearchWindow('installSearchPlugin');">QBT_TR(Cancel)QBT_TR[CONTEXT=PluginSourceDlg]</button>
<button id="newPluginOk" onclick="newPluginOk();">QBT_TR(Ok)QBT_TR[CONTEXT=PluginSourceDlg]</button> <button id="newPluginOk" onclick="qBittorrent.InstallSearchPlugin.newPluginOk();">QBT_TR(Ok)QBT_TR[CONTEXT=PluginSourceDlg]</button>
</div> </div>
</div> </div>
</div> </div>
@ -29,41 +29,55 @@
<script> <script>
'use strict'; 'use strict';
this.initInstallSearchPlugin = function() { if (window.qBittorrent === undefined) {
new Keyboard({ window.qBittorrent = {};
defaultEventType: 'keydown', }
events: {
'Enter': function(e) {
// accept enter key as a click
new Event(e).stop();
const elem = e.event.srcElement; window.qBittorrent.InstallSearchPlugin = (function() {
if ((elem.id === "newPluginPath") || (elem.id === "newPluginOk")) const exports = function() {
newPluginOk(); return {
else if (elem.id === "newPluginCancel") newPluginOk: newPluginOk
closeSearchWindow('installSearchPlugin'); };
};
const init = function() {
new Keyboard({
defaultEventType: 'keydown',
events: {
'Enter': function(e) {
// accept enter key as a click
new Event(e).stop();
const elem = e.event.srcElement;
if ((elem.id === "newPluginPath") || (elem.id === "newPluginOk"))
newPluginOk();
else if (elem.id === "newPluginCancel")
window.qBittorrent.SearchPlugins.closeSearchWindow('installSearchPlugin');
}
} }
} }).activate();
}).activate();
$('newPluginPath').select(); $('newPluginPath').select();
}; };
this.newPluginOk = function() { const newPluginOk = function() {
const path = $("newPluginPath").get("value").trim(); const path = $("newPluginPath").get("value").trim();
if (path) if (path)
new Request({ new Request({
url: 'api/v2/search/installPlugin', url: 'api/v2/search/installPlugin',
noCache: true, noCache: true,
method: 'post', method: 'post',
data: { data: {
sources: path, sources: path,
}, },
onRequest: function() { onRequest: function() {
closeSearchWindow('installSearchPlugin'); window.qBittorrent.SearchPlugins.closeSearchWindow('installSearchPlugin');
} }
}).send(); }).send();
}; };
initInstallSearchPlugin(); init();
return exports();
})();
</script> </script>

File diff suppressed because it is too large Load diff

View file

@ -14,31 +14,33 @@
<script> <script>
'use strict'; 'use strict';
// Tabs (function() {
MochaUI.initializeTabs('preferencesTabs'); // Tabs
MochaUI.initializeTabs('preferencesTabs');
$('PrefDownloadsLink').addEvent('click', function(e) { $('PrefDownloadsLink').addEvent('click', function(e) {
$$('.PrefTab').addClass('invisible'); $$('.PrefTab').addClass('invisible');
$('DownloadsTab').removeClass('invisible'); $('DownloadsTab').removeClass('invisible');
}); });
$('PrefConnectionLink').addEvent('click', function(e) { $('PrefConnectionLink').addEvent('click', function(e) {
$$('.PrefTab').addClass('invisible'); $$('.PrefTab').addClass('invisible');
$('ConnectionTab').removeClass('invisible'); $('ConnectionTab').removeClass('invisible');
}); });
$('PrefSpeedLink').addEvent('click', function(e) { $('PrefSpeedLink').addEvent('click', function(e) {
$$('.PrefTab').addClass('invisible'); $$('.PrefTab').addClass('invisible');
$('SpeedTab').removeClass('invisible'); $('SpeedTab').removeClass('invisible');
}); });
$('PrefBittorrentLink').addEvent('click', function(e) { $('PrefBittorrentLink').addEvent('click', function(e) {
$$('.PrefTab').addClass('invisible'); $$('.PrefTab').addClass('invisible');
$('BittorrentTab').removeClass('invisible'); $('BittorrentTab').removeClass('invisible');
}); });
$('PrefWebUILink').addEvent('click', function(e) { $('PrefWebUILink').addEvent('click', function(e) {
$$('.PrefTab').addClass('invisible'); $$('.PrefTab').addClass('invisible');
$('WebUITab').removeClass('invisible'); $('WebUITab').removeClass('invisible');
}); });
$('PrefAdvancedLink').addEvent('click', function(e) { $('PrefAdvancedLink').addEvent('click', function(e) {
$$('.PrefTab').addClass('invisible'); $$('.PrefTab').addClass('invisible');
$('AdvancedTab').removeClass('invisible'); $('AdvancedTab').removeClass('invisible');
}); });
})();
</script> </script>

View file

@ -155,7 +155,9 @@
<script> <script>
'use strict'; 'use strict';
const selectedTab = $(LocalPreferences.get('selected_tab', 'PropGeneralLink')); (function() {
if (selectedTab) const selectedTab = $(LocalPreferences.get('selected_tab', 'PropGeneralLink'));
selectedTab.click(); if (selectedTab)
selectedTab.click();
})();
</script> </script>

File diff suppressed because it is too large Load diff

View file

@ -65,9 +65,9 @@
<span>QBT_TR(Warning: Be sure to comply with your country's copyright laws when downloading torrents from any of these search engines.)QBT_TR[CONTEXT=PluginSelectDlg]</span> <span>QBT_TR(Warning: Be sure to comply with your country's copyright laws when downloading torrents from any of these search engines.)QBT_TR[CONTEXT=PluginSelectDlg]</span>
<span style="font-style: italic;">QBT_TR(You can get new search engine plugins here:)QBT_TR[CONTEXT=PluginSelectDlg] <a href="http://plugins.qbittorrent.org" target="_blank">http://plugins.qbittorrent.org</a></span> <span style="font-style: italic;">QBT_TR(You can get new search engine plugins here:)QBT_TR[CONTEXT=PluginSelectDlg] <a href="http://plugins.qbittorrent.org" target="_blank">http://plugins.qbittorrent.org</a></span>
<div style="width: 100%; margin-top: 10px;"> <div style="width: 100%; margin-top: 10px;">
<button style="width: 33%; line-height: 1.4em;" onclick="installPlugin();">QBT_TR(Install new plugin)QBT_TR[CONTEXT=PluginSelectDlg]</button> <button style="width: 33%; line-height: 1.4em;" onclick="qBittorrent.SearchPlugins.installPlugin();">QBT_TR(Install new plugin)QBT_TR[CONTEXT=PluginSelectDlg]</button>
<button style="width: 33%; line-height: 1.4em;" onclick="checkForUpdates();">QBT_TR(Check for updates)QBT_TR[CONTEXT=PluginSelectDlg]</button> <button style="width: 33%; line-height: 1.4em;" onclick="qBittorrent.SearchPlugins.checkForUpdates();">QBT_TR(Check for updates)QBT_TR[CONTEXT=PluginSelectDlg]</button>
<button style="width: 32%; line-height: 1.4em;" onclick="closeSearchWindow('searchPlugins');">QBT_TR(Close)QBT_TR[CONTEXT=PluginSelectDlg]</button> <button style="width: 32%; line-height: 1.4em;" onclick="qBittorrent.SearchPlugins.closeSearchWindow('searchPlugins');">QBT_TR(Close)QBT_TR[CONTEXT=PluginSelectDlg]</button>
</div> </div>
</div> </div>
@ -79,142 +79,161 @@
<script> <script>
'use strict'; 'use strict';
this.searchPluginsTableContextMenu = undefined; if (window.qBittorrent === undefined) {
this.prevOffsetLeft = undefined; window.qBittorrent = {};
this.prevOffsetTop = undefined; }
this.initSearchPlugins = function() { window.qBittorrent.SearchPlugins = (function() {
searchPluginsTableContextMenu = new SearchPluginsTableContextMenu({ const exports = function() {
targets: '.searchPluginsTableRow', return {
menu: 'searchPluginsTableMenu', closeSearchWindow: closeSearchWindow,
actions: { installPlugin: installPlugin,
Enabled: enablePlugin, checkForUpdates: checkForUpdates,
Uninstall: uninstallPlugin updateTable: updateTable
}, };
offsets: calculateContextMenuOffsets()
});
searchPluginsTable.setup('searchPluginsTableDiv', 'searchPluginsTableFixedHeaderDiv', searchPluginsTableContextMenu);
updateSearchPluginsTable();
};
this.closeSearchWindow = function(id) {
window.parent.MochaUI.closeWindow(window.parent.$(id));
};
this.installPlugin = function(path) {
new MochaUI.Window({
id: 'installSearchPlugin',
title: "QBT_TR(Install plugin)QBT_TR[CONTEXT=PluginSourceDlg]",
loadMethod: 'xhr',
contentURL: 'views/installsearchplugin.html',
scrollbars: false,
resizable: false,
maximizable: false,
paddingVertical: 0,
paddingHorizontal: 0,
width: 500,
height: 120
});
};
this.uninstallPlugin = function() {
const plugins = searchPluginsTable.selectedRowsIds().join('|');
const url = new URI('api/v2/search/uninstallPlugin');
new Request({
url: url,
noCache: true,
method: 'post',
data: {
names: plugins,
}
}).send();
};
this.enablePlugin = function() {
const plugins = searchPluginsTable.selectedRowsIds();
let enable = true;
if (plugins && plugins.length)
enable = !getPlugin(plugins[0]).enabled;
const url = new URI('api/v2/search/enablePlugin');
new Request({
url: url,
noCache: true,
method: 'post',
data: {
names: plugins.join('|'),
enable: enable
}
}).send();
};
this.checkForUpdates = function() {
const url = new URI('api/v2/search/updatePlugins');
new Request({
url: url,
noCache: true,
method: 'post'
}).send();
};
this.calculateContextMenuOffsets = function() {
prevOffsetLeft = document.getElementById("searchPlugins").getBoundingClientRect().left;
prevOffsetTop = document.getElementById("searchPlugins").getBoundingClientRect().top;
return {
x: -(prevOffsetLeft + 20),
y: -(prevOffsetTop + 2)
}; };
};
this.updateSearchPluginsTableContextMenuOffset = function() { let searchPluginsTable;
// only re-calculate if window has moved let searchPluginsTableContextMenu;
if ((prevOffsetLeft !== document.getElementById("searchPlugins").getBoundingClientRect().left) || (prevOffsetTop !== document.getElementById("searchPlugins").getBoundingClientRect().top)) let prevOffsetLeft;
searchPluginsTableContextMenu.options.offsets = calculateContextMenuOffsets(); let prevOffsetTop;
};
this.setupSearchPluginTableEvents = function(enable) { const initSearchPlugins = function() {
if (enable) searchPluginsTable = new window.qBittorrent.DynamicTable.SearchPluginsTable();
$$(".searchPluginsTableRow").each(function(target) { searchPluginsTableContextMenu = new window.qBittorrent.ContextMenu.SearchPluginsTableContextMenu({
target.addEventListener('dblclick', enablePlugin, false); targets: '.searchPluginsTableRow',
target.addEventListener('contextmenu', updateSearchPluginsTableContextMenuOffset, true); menu: 'searchPluginsTableMenu',
actions: {
Enabled: enablePlugin,
Uninstall: uninstallPlugin
},
offsets: calculateContextMenuOffsets()
}); });
else searchPluginsTable.setup('searchPluginsTableDiv', 'searchPluginsTableFixedHeaderDiv', searchPluginsTableContextMenu);
$$(".searchPluginsTableRow").each(function(target) { updateTable();
target.removeEventListener('dblclick', enablePlugin, false); };
target.removeEventListener('contextmenu', updateSearchPluginsTableContextMenuOffset, true);
const closeSearchWindow = function(id) {
window.parent.MochaUI.closeWindow(window.parent.$(id));
};
const installPlugin = function(path) {
new MochaUI.Window({
id: 'installSearchPlugin',
title: "QBT_TR(Install plugin)QBT_TR[CONTEXT=PluginSourceDlg]",
loadMethod: 'xhr',
contentURL: 'views/installsearchplugin.html',
scrollbars: false,
resizable: false,
maximizable: false,
paddingVertical: 0,
paddingHorizontal: 0,
width: 500,
height: 120
}); });
}; };
this.updateSearchPluginsTable = function() { const uninstallPlugin = function() {
// clear event listeners const plugins = searchPluginsTable.selectedRowsIds().join('|');
setupSearchPluginTableEvents(false); const url = new URI('api/v2/search/uninstallPlugin');
new Request({
const oldPlugins = Object.keys(searchPluginsTable.rows); url: url,
// remove old rows from the table noCache: true,
for (let i = 0; i < oldPlugins.length; ++i) { method: 'post',
let found = false; data: {
for (let j = 0; j < searchPlugins.length; ++j) { names: plugins,
if (searchPlugins[j].name === oldPlugins[i]) {
found = true;
break;
} }
}).send();
};
const enablePlugin = function() {
const plugins = searchPluginsTable.selectedRowsIds();
let enable = true;
if (plugins && plugins.length)
enable = !window.qBittorrent.Search.getPlugin(plugins[0]).enabled;
const url = new URI('api/v2/search/enablePlugin');
new Request({
url: url,
noCache: true,
method: 'post',
data: {
names: plugins.join('|'),
enable: enable
}
}).send();
};
const checkForUpdates = function() {
const url = new URI('api/v2/search/updatePlugins');
new Request({
url: url,
noCache: true,
method: 'post'
}).send();
};
const calculateContextMenuOffsets = function() {
prevOffsetLeft = document.getElementById("searchPlugins").getBoundingClientRect().left;
prevOffsetTop = document.getElementById("searchPlugins").getBoundingClientRect().top;
return {
x: -(prevOffsetLeft + 20),
y: -(prevOffsetTop + 2)
};
};
const updateSearchPluginsTableContextMenuOffset = function() {
// only re-calculate if window has moved
if ((prevOffsetLeft !== document.getElementById("searchPlugins").getBoundingClientRect().left) || (prevOffsetTop !== document.getElementById("searchPlugins").getBoundingClientRect().top))
searchPluginsTableContextMenu.options.offsets = calculateContextMenuOffsets();
};
const setupSearchPluginTableEvents = function(enable) {
if (enable)
$$(".searchPluginsTableRow").each(function(target) {
target.addEventListener('dblclick', enablePlugin, false);
target.addEventListener('contextmenu', updateSearchPluginsTableContextMenuOffset, true);
});
else
$$(".searchPluginsTableRow").each(function(target) {
target.removeEventListener('dblclick', enablePlugin, false);
target.removeEventListener('contextmenu', updateSearchPluginsTableContextMenuOffset, true);
});
};
const updateTable = function() {
// clear event listeners
setupSearchPluginTableEvents(false);
const oldPlugins = Object.keys(searchPluginsTable.rows);
// remove old rows from the table
for (let i = 0; i < oldPlugins.length; ++i) {
let found = false;
for (let j = 0; j < window.qBittorrent.Search.searchPlugins.length; ++j) {
if (window.qBittorrent.Search.searchPlugins[j].name === oldPlugins[i]) {
found = true;
break;
}
}
if (!found)
searchPluginsTable.removeRow(oldPlugins[i]);
} }
if (!found)
searchPluginsTable.removeRow(oldPlugins[i]);
}
for (let i = 0; i < searchPlugins.length; ++i) { for (let i = 0; i < window.qBittorrent.Search.searchPlugins.length; ++i) {
searchPlugins[i].rowId = searchPlugins[i].name; window.qBittorrent.Search.searchPlugins[i].rowId = window.qBittorrent.Search.searchPlugins[i].name;
searchPluginsTable.updateRowData(searchPlugins[i]); searchPluginsTable.updateRowData(window.qBittorrent.Search.searchPlugins[i]);
} }
searchPluginsTable.updateTable(); searchPluginsTable.updateTable();
searchPluginsTable.altRow(); searchPluginsTable.altRow();
// add event listeners // add event listeners
setupSearchPluginTableEvents(true); setupSearchPluginTableEvents(true);
}; };
initSearchPlugins(); initSearchPlugins();
return exports();
})();
</script> </script>

View file

@ -18,81 +18,95 @@
<script> <script>
'use strict'; 'use strict';
//create a context menu if (window.qBittorrent === undefined) {
const torrentsTableContextMenu = new TorrentsTableContextMenu({ window.qBittorrent = {};
targets: '.torrentsTableContextMenuTarget', }
menu: 'torrentsTableMenu',
actions: {
start: function(element, ref) {
startFN();
},
pause: function(element, ref) {
pauseFN();
},
forceStart: function(element, ref) {
setForceStartFN();
},
delete: function(element, ref) { window.qBittorrent.TransferList = (function() {
deleteFN(); const exports = function() {
}, return {
contextMenu: contextMenu,
};
};
setLocation: function(element, ref) { //create a context menu
setLocationFN(); const contextMenu = new window.qBittorrent.ContextMenu.TorrentsTableContextMenu({
}, targets: '.torrentsTableContextMenuTarget',
menu: 'torrentsTableMenu',
actions: {
start: function(element, ref) {
startFN();
},
pause: function(element, ref) {
pauseFN();
},
forceStart: function(element, ref) {
setForceStartFN();
},
rename: function(element, ref) { delete: function(element, ref) {
renameFN(); deleteFN();
}, },
queueTop: function(element, ref) {
setQueuePositionFN('topPrio');
},
queueUp: function(element, ref) {
setQueuePositionFN('increasePrio');
},
queueDown: function(element, ref) {
setQueuePositionFN('decreasePrio');
},
queueBottom: function(element, ref) {
setQueuePositionFN('bottomPrio');
},
downloadLimit: function(element, ref) { setLocation: function(element, ref) {
downloadLimitFN(); setLocationFN();
}, },
uploadLimit: function(element, ref) {
uploadLimitFN();
},
shareRatio: function(element, ref) {
shareRatioFN();
},
sequentialDownload: function(element, ref) { rename: function(element, ref) {
toggleSequentialDownloadFN(); renameFN();
}, },
firstLastPiecePrio: function(element, ref) { queueTop: function(element, ref) {
toggleFirstLastPiecePrioFN(); setQueuePositionFN('topPrio');
}, },
queueUp: function(element, ref) {
setQueuePositionFN('increasePrio');
},
queueDown: function(element, ref) {
setQueuePositionFN('decreasePrio');
},
queueBottom: function(element, ref) {
setQueuePositionFN('bottomPrio');
},
autoTorrentManagement: function(element, ref) { downloadLimit: function(element, ref) {
autoTorrentManagementFN(); downloadLimitFN();
}, },
forceRecheck: function(element, ref) { uploadLimit: function(element, ref) {
recheckFN(); uploadLimitFN();
}, },
forceReannounce: function(element, ref) { shareRatio: function(element, ref) {
reannounceFN(); shareRatioFN();
}, },
superSeeding: function(element, ref) { sequentialDownload: function(element, ref) {
setSuperSeedingFN(!ref.getItemChecked('superSeeding')); toggleSequentialDownloadFN();
},
firstLastPiecePrio: function(element, ref) {
toggleFirstLastPiecePrioFN();
},
autoTorrentManagement: function(element, ref) {
autoTorrentManagementFN();
},
forceRecheck: function(element, ref) {
recheckFN();
},
forceReannounce: function(element, ref) {
reannounceFN();
},
superSeeding: function(element, ref) {
setSuperSeedingFN(!ref.getItemChecked('superSeeding'));
}
},
offsets: {
x: -15,
y: 2
} }
}, });
offsets: {
x: -15,
y: 2
}
});
torrentsTable.setup('torrentsTableDiv', 'torrentsTableFixedHeaderDiv', torrentsTableContextMenu); torrentsTable.setup('torrentsTableDiv', 'torrentsTableFixedHeaderDiv', contextMenu);
return exports();
})();
</script> </script>