From 57e9165bb4a46902357f1a9e13cbb36a0a53a7a3 Mon Sep 17 00:00:00 2001 From: Gabriele Date: Mon, 8 Dec 2014 21:00:00 +0100 Subject: [PATCH 01/15] WebUI: Translate page title everywhere --- src/webui/www/private/index.html | 2 +- src/webui/www/private/login.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index 7eafd52d4..ae086863d 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -3,7 +3,7 @@ - qBittorrent web User Interface + _(qBittorrent web User Interface) diff --git a/src/webui/www/private/login.html b/src/webui/www/private/login.html index 4f027033d..51dffb6d5 100644 --- a/src/webui/www/private/login.html +++ b/src/webui/www/private/login.html @@ -3,7 +3,7 @@ - qBittorrent web User Interface + _(qBittorrent web User Interface) diff --git a/src/webui/www/public/prop-general.html b/src/webui/www/public/prop-general.html deleted file mode 100644 index 029312dbe..000000000 --- a/src/webui/www/public/prop-general.html +++ /dev/null @@ -1,123 +0,0 @@ -
- _(Transfer) - - - - -
_(Uploaded:)0 Kb_(UP limit:)xx_(Share ratio:)xx
_(Downloaded:)0 Kb_(DL limit:)xx_(Connections:)xx
_(Wasted:)0 Kb_(Time active:)xx
-
- -
- _(Information) - - - - - - -
_(Save path:)xxx
_(Created on:)xxx
_(Pieces size:)xxx
_(Torrent hash:)xxx
-
- _(Comment:) -
- -
-
-
- - - - diff --git a/src/webui/www/public/prop-trackers.html b/src/webui/www/public/prop-trackers.html deleted file mode 100644 index bff7ae6e7..000000000 --- a/src/webui/www/public/prop-trackers.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - - - - - - -
_(URL) _(Status)_(Peers)_(Message)
-
- - diff --git a/src/webui/www/public/properties.html b/src/webui/www/public/properties.html index 0aa80f3cd..ecf76776b 100644 --- a/src/webui/www/public/properties.html +++ b/src/webui/www/public/properties.html @@ -1,37 +1,8 @@ - -
- -
+ +
diff --git a/src/webui/www/public/properties_content.html b/src/webui/www/public/properties_content.html new file mode 100644 index 000000000..798b30671 --- /dev/null +++ b/src/webui/www/public/properties_content.html @@ -0,0 +1,61 @@ +
+
+ _(Transfer) + + + + +
_(Uploaded:)_(UP limit:)_(Share ratio:)
_(Downloaded:)_(DL limit:)_(Connections:)
_(Wasted:)_(Time active:)
+
+ +
+ _(Information) + + + + + + +
_(Save path:)
_(Created on:)
_(Pieces size:)
_(Torrent hash:)
+
+ _(Comment:) +
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/src/webui/www/public/scripts/client.js b/src/webui/www/public/scripts/client.js index 67ab70e73..1dfa9425e 100644 --- a/src/webui/www/public/scripts/client.js +++ b/src/webui/www/public/scripts/client.js @@ -311,11 +311,33 @@ window.addEvent('load', function () { bottom : 0, left : 0 }, - contentURL : 'prop-general.html', + contentURL : 'properties_content.html', require : { - css : ['css/Tabs.css'] + css : ['css/Tabs.css'], + js : ['scripts/prop-general.js', 'scripts/prop-trackers.js', 'scripts/prop-files.js'], }, tabsURL : 'properties.html', + tabsOnload : function() { + MochaUI.initializeTabs('propertiesTabs'); + + $('PropGeneralLink').addEvent('click', function(e){ + $('prop_general').removeClass("invisible"); + $('prop_trackers').addClass("invisible"); + $('prop_files').addClass("invisible"); + }); + + $('PropTrackersLink').addEvent('click', function(e){ + $('prop_trackers').removeClass("invisible"); + $('prop_general').addClass("invisible"); + $('prop_files').addClass("invisible"); + }); + + $('PropFilesLink').addEvent('click', function(e){ + $('prop_files').removeClass("invisible"); + $('prop_general').addClass("invisible"); + $('prop_trackers').addClass("invisible"); + }); + }, column : 'mainColumn', height : prop_h }); diff --git a/src/webui/www/public/scripts/prop-files.js b/src/webui/www/public/scripts/prop-files.js new file mode 100644 index 000000000..de326d675 --- /dev/null +++ b/src/webui/www/public/scripts/prop-files.js @@ -0,0 +1,348 @@ +var waitingTorrentFiles = false; +var is_seed = true; +var current_hash = ""; + +if (!(Browser.name == "ie" && Browser.version < 9)) { + $("all_files_cb").removeClass("tristate"); + $("all_files_cb").removeClass("partial"); + $("all_files_cb").removeClass("checked"); + $("tristate_cb").style.display = "inline"; +} + +var setCBState = function(state) { + if (Browser.name == "ie" && Browser.version < 9) { + if (state == "partial") { + if (!$("all_files_cb").hasClass("partial")) { + $("all_files_cb").removeClass("checked"); + $("all_files_cb").addClass("partial"); + } + return; + } + if (state == "checked") { + if (!$("all_files_cb").hasClass("checked")) { + $("all_files_cb").removeClass("partial"); + $("all_files_cb").addClass("checked"); + } + return; + } + $("all_files_cb").removeClass("partial"); + $("all_files_cb").removeClass("checked"); + } + else { + if (state == "partial") { + $("tristate_cb").indeterminate = true; + } + else if (state == "checked") { + $("tristate_cb").indeterminate = false; + $("tristate_cb").checked = true; + } + else { + $("tristate_cb").indeterminate = false; + $("tristate_cb").checked = false; + } + } +} + +var switchCBState = function() { + // Uncheck + if ($("all_files_cb").hasClass("partial")) { + $("all_files_cb").removeClass("partial"); + // Uncheck all checkboxes + $$('input.DownloadedCB').each(function(item, index) { + item.erase("checked"); + setFilePriority(index, 0); + }); + return; + } + if ($("all_files_cb").hasClass("checked")) { + $("all_files_cb").removeClass("checked"); + // Uncheck all checkboxes + $$('input.DownloadedCB').each(function(item, index) { + item.erase("checked"); + setFilePriority(index, 0); + }); + return; + } + // Check + $("all_files_cb").addClass("checked"); + // Check all checkboxes + $$('input.DownloadedCB').each(function(item, index) { + item.set("checked", "checked"); + setFilePriority(index, 1); + }); +} + +var allCBChecked = function() { + var CBs = $$('input.DownloadedCB'); + for (var i = 0; i < CBs.length; i += 1) { + var item = CBs[i]; + if (!$defined(item.get('checked')) || !item.get('checked')) + return false; + } + return true; +} + +var allCBUnchecked = function() { + var CBs = $$('input.DownloadedCB'); + for (var i = 0; i < CBs.length; i += 1) { + var item = CBs[i]; + if ($defined(item.get('checked')) && item.get('checked')) + return false; + } + return true; +} + +var setFilePriority = function(id, priority) { + if (current_hash == "") return; + new Request({ + url: 'command/setFilePrio', + method: 'post', + data: { + 'hash': current_hash, + 'id': id, + 'priority': priority + } + }).send(); + // Display or add combobox + if (priority > 0) { + $('comboPrio' + id).set("value", 1); + $('comboPrio' + id).removeClass("invisible"); + } + else { + $('comboPrio' + id).addClass("invisible"); + } +} + +var createDownloadedCB = function(id, downloaded) { + var CB = new Element('input'); + CB.set('type', 'checkbox'); + if (downloaded) + CB.set('checked', 'checked'); + CB.set('id', 'cbPrio' + id); + CB.set('class', 'DownloadedCB'); + CB.addEvent('change', function(e) { + var checked = 0; + if ($defined($('cbPrio' + id).get('checked')) && $('cbPrio' + id).get('checked')) + checked = 1; + setFilePriority(id, checked); + if (allCBChecked()) { + setCBState("checked"); + } + else { + if (allCBUnchecked()) { + setCBState("unchecked"); + } + else { + setCBState("partial"); + } + } + }); + return CB; +} + +var createPriorityCombo = function(id, selected_prio) { + var select = new Element('select'); + select.set('id', 'comboPrio' + id); + select.addEvent('change', function(e) { + var new_prio = $('comboPrio' + id).get('value'); + setFilePriority(id, new_prio); + }); + var opt = new Element("option"); + opt.set('value', '1') + opt.set('html', "_(Normal)"); + if (selected_prio <= 1) + opt.setAttribute('selected', ''); + opt.injectInside(select); + opt = new Element("option"); + opt.set('value', '2') + opt.set('html', "_(High)"); + if (selected_prio == 2) + opt.setAttribute('selected', ''); + opt.injectInside(select); + opt = new Element("option"); + opt.set('value', '7') + opt.set('html', "_(Maximum)"); + if (selected_prio == 7) + opt.setAttribute('selected', ''); + opt.injectInside(select); + if (is_seed || selected_prio < 1) { + select.addClass("invisible"); + } + else { + select.removeClass("invisible"); + } + select.addClass("combo_priority"); + return select; +} + +var filesDynTable = new Class({ + + initialize: function() {}, + + setup: function(table) { + this.table = $(table); + this.rows = new Hash(); + }, + + removeRow: function(id) { + if (this.rows.has(id)) { + var tr = this.rows.get(id); + tr.dispose(); + this.rows.erase(id); + return true; + } + return false; + }, + + removeAllRows: function() { + this.rows.each(function(tr, id) { + this.removeRow(id); + }.bind(this)); + }, + + updateRow: function(tr, row, id) { + var tds = tr.getElements('td'); + for (var i = 0; i < row.length; i++) { + if (i == 3) { + $('pbf_' + id).setValue(row[i].toFloat()); + } + else { + if (i == 0) { + if (row[i] > 0) + tds[i].getChildren('input')[0].set('checked', 'checked'); + else + tds[i].getChildren('input')[0].removeProperty('checked') + } + else { + if (i == 4) { + if (!is_seed && row[i] > 0) { + tds[i].getChildren('select').set('value', row[i]); + $('comboPrio' + id).removeClass("invisible"); + } + else { + if (!$('comboPrio' + id).hasClass("invisible")) + $('comboPrio' + id).addClass("invisible"); + } + } + else { + tds[i].set('html', row[i]); + } + } + } + } + return true; + }, + + insertRow: function(id, row) { + if (this.rows.has(id)) { + var tr = this.rows.get(id); + this.updateRow(tr, row, id); + return; + } + //this.removeRow(id); + var tr = new Element('tr'); + this.rows.set(id, tr); + for (var i = 0; i < row.length; i++) { + var td = new Element('td'); + if (i == 3) { + td.adopt(new ProgressBar(row[i].toFloat(), { + 'id': 'pbf_' + id, + 'width': 80 + })); + } + else { + if (i == 0) { + var tree_img = new Element('img', { + src: 'images/L.gif', + style: 'margin-bottom: -2px' + }); + td.adopt(tree_img, createDownloadedCB(id, row[i])); + } + else { + if (i == 4) { + td.adopt(createPriorityCombo(id, row[i])); + } + else { + td.set('html', row[i]); + } + } + } + td.injectInside(tr); + } + tr.injectInside(this.table); + }, +}); + +var loadTorrentFilesData = function() { + if ($('prop_files').hasClass('invisible')) { + // Tab changed, don't do anything + return; + } + var new_hash = myTable.getCurrentTorrentHash(); + if (new_hash == "") { + fTable.removeAllRows(); + loadTorrentFilesData.delay(1500); + return; + } + if (new_hash != current_hash) { + fTable.removeAllRows(); + current_hash = new_hash; + } + var url = 'json/propertiesFiles/' + current_hash; + if (!waitingTorrentFiles) { + waitingTorrentFiles = true; + var request = new Request.JSON({ + url: url, + noCache: true, + method: 'get', + onFailure: function() { + $('error_div').set('html', '_(qBittorrent client is not reachable)'); + waitingTorrentFiles = false; + loadTorrentFilesData.delay(2000); + }, + onSuccess: function(files) { + $('error_div').set('html', ''); + if (files) { + // Update Trackers data + var i = 0; + files.each(function(file) { + if (i == 0) { + is_seed = file.is_seed; + } + var row = new Array(); + row.length = 4; + row[0] = file.priority; + row[1] = file.name; + row[2] = friendlyUnit(file.size, false); + row[3] = (file.progress * 100).round(1); + if (row[3] == 100.0 && file.progress < 1.0) + row[3] = 99.9 + row[4] = file.priority; + fTable.insertRow(i, row); + i++; + }.bind(this)); + // Set global CB state + if (allCBChecked()) { + setCBState("checked"); + } + else { + if (allCBUnchecked()) { + setCBState("unchecked"); + } + else { + setCBState("partial"); + } + } + } + else { + fTable.removeAllRows(); + } + waitingTorrentFiles = false; + loadTorrentFilesData.delay(1500); + } + }).send(); + } + +} +fTable = new filesDynTable(); +fTable.setup($('filesTable')); \ No newline at end of file diff --git a/src/webui/www/public/scripts/prop-general.js b/src/webui/www/public/scripts/prop-general.js new file mode 100644 index 000000000..5afe750d3 --- /dev/null +++ b/src/webui/www/public/scripts/prop-general.js @@ -0,0 +1,84 @@ +var waiting = false; + +var clearData = function() { + $('torrent_hash').set('html', ''); + $('save_path').set('html', ''); + $('creation_date').set('html', ''); + $('piece_size').set('html', ''); + $('comment').set('html', ''); + $('total_uploaded').set('html', ''); + $('total_downloaded').set('html', ''); + $('total_wasted').set('html', ''); + $('up_limit').set('html', ''); + $('dl_limit').set('html', ''); + $('time_elapsed').set('html', ''); + $('nb_connections').set('html', ''); + $('share_ratio').set('html', ''); +} + +var loadData = function() { + if ($('prop_general').hasClass('invisible')) { + // Tab changed, don't do anything + return; + } + var current_hash = myTable.getCurrentTorrentHash(); + if (current_hash == "") { + clearData(); + loadData.delay(1500); + return; + } + // Display hash + $('torrent_hash').set('html', current_hash); + var url = 'json/propertiesGeneral/' + current_hash; + if (!waiting) { + waiting = true; + var request = new Request.JSON({ + url: url, + noCache: true, + method: 'get', + onFailure: function() { + $('error_div').set('html', '_(qBittorrent client is not reachable)'); + waiting = false; + loadData.delay(2000); + }, + onSuccess: function(data) { + $('error_div').set('html', ''); + if (data) { + var temp; + // Update Torrent data + $('save_path').set('html', data.save_path); + temp = data.creation_date; + var timestamp = "_(Unknown)"; + if (temp != -1) + timestamp = new Date(data.creation_date * 1000).toISOString(); + $('creation_date').set('html', timestamp); + $('piece_size').set('html', friendlyUnit(data.piece_size)); + $('comment').set('html', data.comment); + $('total_uploaded').set('html', friendlyUnit(data.total_uploaded) + + " (" + friendlyUnit(data.total_uploaded_session) + + " (" + "_(this session)" + ")"); + $('total_downloaded').set('html', friendlyUnit(data.total_downloaded) + + " (" + friendlyUnit(data.total_downloaded_session) + + " (" + "_(this session)" + ")"); + $('total_wasted').set('html', data.total_wasted); + temp = data.up_limit; + $('up_limit').set('html', temp == -1 ? "∞" : temp); + temp = data.dl_limit; + $('dl_limit').set('html', temp == -1 ? "∞" : temp); + temp = friendlyDuration(status.active_time); + if (status.is_seed) + temp += " (" + "_(Seeded for %1)".replace("%1", status.seeding_time) + ")"; + $('time_elapsed').set('html', temp); + temp = data.nb_connections + " (" + "_(%1 max)".replace("%1", status.nb_connections_limit) + ")"; + $('nb_connections').set('html', temp); + $('share_ratio').set('html', data.share_ratio.toFixed(2)); + } + else { + clearData(); + } + waiting = false; + loadData.delay(1500); + } + }).send(); + } +} \ No newline at end of file diff --git a/src/webui/www/public/scripts/prop-trackers.js b/src/webui/www/public/scripts/prop-trackers.js new file mode 100644 index 000000000..8fbd1fe04 --- /dev/null +++ b/src/webui/www/public/scripts/prop-trackers.js @@ -0,0 +1,127 @@ +var trackersDynTable = new Class({ + + initialize: function() {}, + + setup: function(table) { + this.table = $(table); + this.rows = new Hash(); + }, + + removeRow: function(url) { + if (this.rows.has(url)) { + var 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) { + var tds = tr.getElements('td'); + for (var i = 0; i < row.length; i++) { + tds[i].set('html', row[i]); + } + return true; + }, + + insertRow: function(row) { + var url = row[0]; + if (this.rows.has(url)) { + var tr = this.rows.get(url); + this.updateRow(tr, row); + return; + } + //this.removeRow(id); + var tr = new Element('tr'); + this.rows.set(url, tr); + for (var i = 0; i < row.length; i++) { + var td = new Element('td'); + td.set('html', row[i]); + td.injectInside(tr); + } + tr.injectInside(this.table); + }, +}); + +var waitingTrackers = false; +var current_hash = ""; + +var loadTrackersData = function() { + if ($('prop_trackers').hasClass('invisible')) { + // Tab changed, don't do anything + return; + } + var new_hash = myTable.getCurrentTorrentHash(); + if (new_hash == "") { + tTable.removeAllRows(); + loadTrackersData.delay(1500); + return; + } + if (new_hash != current_hash) { + tTable.removeAllRows(); + current_hash = new_hash; + } + var url = 'json/propertiesTrackers/' + current_hash; + if (!waitingTrackers) { + waitingTrackers = true; + var request = new Request.JSON({ + url: url, + noCache: true, + method: 'get', + onFailure: function() { + $('error_div').set('html', '_(qBittorrent client is not reachable)'); + waitingTrackers = false; + loadTrackersData.delay(2000); + }, + onSuccess: function(trackers) { + $('error_div').set('html', ''); + if (trackers) { + // Update Trackers data + trackers.each(function(tracker) { + var row = new Array(); + row.length = 4; + row[0] = tracker.url; + row[1] = tracker.status; + row[2] = tracker.num_peers; + row[3] = tracker.msg; + tTable.insertRow(row); + }); + } + else { + tTable.removeAllRows(); + } + waitingTrackers = false; + loadTrackersData.delay(1500); + } + }).send(); + } + +} +tTable = new trackersDynTable(); +tTable.setup($('trackersTable')); + +// Add trackers code +$('addTrackersPlus').addEvent('click', function addTrackerDlg() { + if (current_hash.length == 0) return; + new MochaUI.Window({ + id: 'trackersPage', + title: "_(Trackers addition dialog)", + loadMethod: 'iframe', + contentURL: 'addtrackers.html?hash=' + current_hash, + scrollbars: true, + resizable: false, + maximizable: false, + closable: true, + paddingVertical: 0, + paddingHorizontal: 0, + width: 500, + height: 250 + }); +}); \ No newline at end of file From 408cc7101e31d6d61a13b5772c3a113ab55ccfff Mon Sep 17 00:00:00 2001 From: Gabriele Date: Thu, 11 Dec 2014 00:01:04 +0100 Subject: [PATCH 09/15] WebUI: Update torrent properties immediately Don't wait for new data to be fetched, request them as soon as they are required, i.e. when a property tab is loaded or when a different torrent is selected. --- src/webui/www/public/scripts/client.js | 14 +++ src/webui/www/public/scripts/dynamicTable.js | 2 +- src/webui/www/public/scripts/prop-files.js | 100 ++++++++-------- src/webui/www/public/scripts/prop-general.js | 107 +++++++++--------- src/webui/www/public/scripts/prop-trackers.js | 68 +++++------ 5 files changed, 152 insertions(+), 139 deletions(-) diff --git a/src/webui/www/public/scripts/client.js b/src/webui/www/public/scripts/client.js index 1dfa9425e..64d5c9560 100644 --- a/src/webui/www/public/scripts/client.js +++ b/src/webui/www/public/scripts/client.js @@ -24,6 +24,8 @@ myTable = new dynamicTable(); +var updatePropertiesPanel = function(){}; + var stateToImg = function (state) { if (state == "pausedUP" || state == "pausedDL") { state = "paused"; @@ -320,22 +322,34 @@ window.addEvent('load', function () { tabsOnload : function() { MochaUI.initializeTabs('propertiesTabs'); + updatePropertiesPanel = function() { + if (!$('prop_general').hasClass('invisible')) + updateTorrentData(); + else if (!$('prop_trackers').hasClass('invisible')) + updateTrackersData(); + else if (!$('prop_files').hasClass('invisible')) + updateTorrentFilesData(); + } + $('PropGeneralLink').addEvent('click', function(e){ $('prop_general').removeClass("invisible"); $('prop_trackers').addClass("invisible"); $('prop_files').addClass("invisible"); + updatePropertiesPanel(); }); $('PropTrackersLink').addEvent('click', function(e){ $('prop_trackers').removeClass("invisible"); $('prop_general').addClass("invisible"); $('prop_files').addClass("invisible"); + updatePropertiesPanel(); }); $('PropFilesLink').addEvent('click', function(e){ $('prop_files').removeClass("invisible"); $('prop_general').addClass("invisible"); $('prop_trackers').addClass("invisible"); + updatePropertiesPanel(); }); }, column : 'mainColumn', diff --git a/src/webui/www/public/scripts/dynamicTable.js b/src/webui/www/public/scripts/dynamicTable.js index 0c5b2a44f..f7e3accac 100644 --- a/src/webui/www/public/scripts/dynamicTable.js +++ b/src/webui/www/public/scripts/dynamicTable.js @@ -220,7 +220,7 @@ var dynamicTable = new Class({ temptr.addClass('selected'); } this.cur[0] = id; - // TODO: Warn Properties panel + updatePropertiesPanel(); } } return false; diff --git a/src/webui/www/public/scripts/prop-files.js b/src/webui/www/public/scripts/prop-files.js index de326d675..344522048 100644 --- a/src/webui/www/public/scripts/prop-files.js +++ b/src/webui/www/public/scripts/prop-files.js @@ -1,4 +1,3 @@ -var waitingTorrentFiles = false; var is_seed = true; var current_hash = ""; @@ -273,6 +272,7 @@ var filesDynTable = new Class({ }, }); +var loadTorrentFilesDataTimer; var loadTorrentFilesData = function() { if ($('prop_files').hasClass('invisible')) { // Tab changed, don't do anything @@ -281,7 +281,7 @@ var loadTorrentFilesData = function() { var new_hash = myTable.getCurrentTorrentHash(); if (new_hash == "") { fTable.removeAllRows(); - loadTorrentFilesData.delay(1500); + loadTorrentFilesDataTimer = loadTorrentFilesData.delay(1500); return; } if (new_hash != current_hash) { @@ -289,60 +289,60 @@ var loadTorrentFilesData = function() { current_hash = new_hash; } var url = 'json/propertiesFiles/' + current_hash; - if (!waitingTorrentFiles) { - waitingTorrentFiles = true; - var request = new Request.JSON({ - url: url, - noCache: true, - method: 'get', - onFailure: function() { - $('error_div').set('html', '_(qBittorrent client is not reachable)'); - waitingTorrentFiles = false; - loadTorrentFilesData.delay(2000); - }, - onSuccess: function(files) { - $('error_div').set('html', ''); - if (files) { - // Update Trackers data - var i = 0; - files.each(function(file) { - if (i == 0) { - is_seed = file.is_seed; - } - var row = new Array(); - row.length = 4; - row[0] = file.priority; - row[1] = file.name; - row[2] = friendlyUnit(file.size, false); - row[3] = (file.progress * 100).round(1); - if (row[3] == 100.0 && file.progress < 1.0) - row[3] = 99.9 - row[4] = file.priority; - fTable.insertRow(i, row); - i++; - }.bind(this)); - // Set global CB state - if (allCBChecked()) { - setCBState("checked"); - } - else { - if (allCBUnchecked()) { - setCBState("unchecked"); - } - else { - setCBState("partial"); - } + var request = new Request.JSON({ + url: url, + noCache: true, + method: 'get', + onFailure: function() { + $('error_div').set('html', '_(qBittorrent client is not reachable)'); + loadTorrentFilesDataTimer = loadTorrentFilesData.delay(2000); + }, + onSuccess: function(files) { + $('error_div').set('html', ''); + if (files) { + // Update Trackers data + var i = 0; + files.each(function(file) { + if (i == 0) { + is_seed = file.is_seed; } + var row = new Array(); + row.length = 4; + row[0] = file.priority; + row[1] = file.name; + row[2] = friendlyUnit(file.size, false); + row[3] = (file.progress * 100).round(1); + if (row[3] == 100.0 && file.progress < 1.0) + row[3] = 99.9 + row[4] = file.priority; + fTable.insertRow(i, row); + i++; + }.bind(this)); + // Set global CB state + if (allCBChecked()) { + setCBState("checked"); } else { - fTable.removeAllRows(); + if (allCBUnchecked()) { + setCBState("unchecked"); + } + else { + setCBState("partial"); + } } - waitingTorrentFiles = false; - loadTorrentFilesData.delay(1500); } - }).send(); - } + else { + fTable.removeAllRows(); + } + loadTorrentFilesDataTimer = loadTorrentFilesData.delay(1500); + } + }).send(); +} +var updateTorrentFilesData = function() { + clearTimeout(loadTorrentFilesDataTimer); + loadTorrentFilesData(); } + fTable = new filesDynTable(); fTable.setup($('filesTable')); \ No newline at end of file diff --git a/src/webui/www/public/scripts/prop-general.js b/src/webui/www/public/scripts/prop-general.js index 5afe750d3..4f6147009 100644 --- a/src/webui/www/public/scripts/prop-general.js +++ b/src/webui/www/public/scripts/prop-general.js @@ -1,5 +1,3 @@ -var waiting = false; - var clearData = function() { $('torrent_hash').set('html', ''); $('save_path').set('html', ''); @@ -16,7 +14,8 @@ var clearData = function() { $('share_ratio').set('html', ''); } -var loadData = function() { +var loadTorrentDataTimer; +var loadTorrentData = function() { if ($('prop_general').hasClass('invisible')) { // Tab changed, don't do anything return; @@ -24,61 +23,61 @@ var loadData = function() { var current_hash = myTable.getCurrentTorrentHash(); if (current_hash == "") { clearData(); - loadData.delay(1500); + loadTorrentDataTimer = loadTorrentData.delay(1500); return; } // Display hash $('torrent_hash').set('html', current_hash); var url = 'json/propertiesGeneral/' + current_hash; - if (!waiting) { - waiting = true; - var request = new Request.JSON({ - url: url, - noCache: true, - method: 'get', - onFailure: function() { - $('error_div').set('html', '_(qBittorrent client is not reachable)'); - waiting = false; - loadData.delay(2000); - }, - onSuccess: function(data) { - $('error_div').set('html', ''); - if (data) { - var temp; - // Update Torrent data - $('save_path').set('html', data.save_path); - temp = data.creation_date; - var timestamp = "_(Unknown)"; - if (temp != -1) - timestamp = new Date(data.creation_date * 1000).toISOString(); - $('creation_date').set('html', timestamp); - $('piece_size').set('html', friendlyUnit(data.piece_size)); - $('comment').set('html', data.comment); - $('total_uploaded').set('html', friendlyUnit(data.total_uploaded) + - " (" + friendlyUnit(data.total_uploaded_session) + - " (" + "_(this session)" + ")"); - $('total_downloaded').set('html', friendlyUnit(data.total_downloaded) + - " (" + friendlyUnit(data.total_downloaded_session) + - " (" + "_(this session)" + ")"); - $('total_wasted').set('html', data.total_wasted); - temp = data.up_limit; - $('up_limit').set('html', temp == -1 ? "∞" : temp); - temp = data.dl_limit; - $('dl_limit').set('html', temp == -1 ? "∞" : temp); - temp = friendlyDuration(status.active_time); - if (status.is_seed) - temp += " (" + "_(Seeded for %1)".replace("%1", status.seeding_time) + ")"; - $('time_elapsed').set('html', temp); - temp = data.nb_connections + " (" + "_(%1 max)".replace("%1", status.nb_connections_limit) + ")"; - $('nb_connections').set('html', temp); - $('share_ratio').set('html', data.share_ratio.toFixed(2)); - } - else { - clearData(); - } - waiting = false; - loadData.delay(1500); + var request = new Request.JSON({ + url: url, + noCache: true, + method: 'get', + onFailure: function() { + $('error_div').set('html', '_(qBittorrent client is not reachable)'); + loadTorrentDataTimer = loadTorrentData.delay(2000); + }, + onSuccess: function(data) { + $('error_div').set('html', ''); + if (data) { + var temp; + // Update Torrent data + $('save_path').set('html', data.save_path); + temp = data.creation_date; + var timestamp = "_(Unknown)"; + if (temp != -1) + timestamp = new Date(data.creation_date * 1000).toISOString(); + $('creation_date').set('html', timestamp); + $('piece_size').set('html', friendlyUnit(data.piece_size)); + $('comment').set('html', data.comment); + $('total_uploaded').set('html', friendlyUnit(data.total_uploaded) + + " (" + friendlyUnit(data.total_uploaded_session) + + " (" + "_(this session)" + ")"); + $('total_downloaded').set('html', friendlyUnit(data.total_downloaded) + + " (" + friendlyUnit(data.total_downloaded_session) + + " (" + "_(this session)" + ")"); + $('total_wasted').set('html', data.total_wasted); + temp = data.up_limit; + $('up_limit').set('html', temp == -1 ? "∞" : temp); + temp = data.dl_limit; + $('dl_limit').set('html', temp == -1 ? "∞" : temp); + temp = friendlyDuration(status.active_time); + if (status.is_seed) + temp += " (" + "_(Seeded for %1)".replace("%1", status.seeding_time) + ")"; + $('time_elapsed').set('html', temp); + temp = data.nb_connections + " (" + "_(%1 max)".replace("%1", status.nb_connections_limit) + ")"; + $('nb_connections').set('html', temp); + $('share_ratio').set('html', data.share_ratio.toFixed(2)); } - }).send(); - } + else { + clearData(); + } + loadTorrentDataTimer = loadTorrentData.delay(1500); + } + }).send(); +} + +var updateTorrentData = function() { + clearTimeout(loadTorrentDataTimer); + loadTorrentData(); } \ No newline at end of file diff --git a/src/webui/www/public/scripts/prop-trackers.js b/src/webui/www/public/scripts/prop-trackers.js index 8fbd1fe04..57baa49ce 100644 --- a/src/webui/www/public/scripts/prop-trackers.js +++ b/src/webui/www/public/scripts/prop-trackers.js @@ -50,9 +50,9 @@ var trackersDynTable = new Class({ }, }); -var waitingTrackers = false; var current_hash = ""; +var loadTrackersDataTimer; var loadTrackersData = function() { if ($('prop_trackers').hasClass('invisible')) { // Tab changed, don't do anything @@ -61,7 +61,7 @@ var loadTrackersData = function() { var new_hash = myTable.getCurrentTorrentHash(); if (new_hash == "") { tTable.removeAllRows(); - loadTrackersData.delay(1500); + loadTrackersDataTimer = loadTrackersData.delay(1500); return; } if (new_hash != current_hash) { @@ -69,41 +69,41 @@ var loadTrackersData = function() { current_hash = new_hash; } var url = 'json/propertiesTrackers/' + current_hash; - if (!waitingTrackers) { - waitingTrackers = true; - var request = new Request.JSON({ - url: url, - noCache: true, - method: 'get', - onFailure: function() { - $('error_div').set('html', '_(qBittorrent client is not reachable)'); - waitingTrackers = false; - loadTrackersData.delay(2000); - }, - onSuccess: function(trackers) { - $('error_div').set('html', ''); - if (trackers) { - // Update Trackers data - trackers.each(function(tracker) { - var row = new Array(); - row.length = 4; - row[0] = tracker.url; - row[1] = tracker.status; - row[2] = tracker.num_peers; - row[3] = tracker.msg; - tTable.insertRow(row); - }); - } - else { - tTable.removeAllRows(); - } - waitingTrackers = false; - loadTrackersData.delay(1500); + var request = new Request.JSON({ + url: url, + noCache: true, + method: 'get', + onFailure: function() { + $('error_div').set('html', '_(qBittorrent client is not reachable)'); + loadTrackersDataTimer = loadTrackersData.delay(2000); + }, + onSuccess: function(trackers) { + $('error_div').set('html', ''); + if (trackers) { + // Update Trackers data + trackers.each(function(tracker) { + var row = new Array(); + row.length = 4; + row[0] = tracker.url; + row[1] = tracker.status; + row[2] = tracker.num_peers; + row[3] = tracker.msg; + tTable.insertRow(row); + }); } - }).send(); - } + else { + tTable.removeAllRows(); + } + loadTrackersDataTimer = loadTrackersData.delay(1500); + } + }).send(); +} +var updateTrackersData = function() { + clearTimeout(loadTrackersDataTimer); + loadTrackersData(); } + tTable = new trackersDynTable(); tTable.setup($('trackersTable')); From ac507261f803c4feb834569ed9ee5830fe3f57c9 Mon Sep 17 00:00:00 2001 From: Gabriele Date: Mon, 8 Dec 2014 21:00:00 +0100 Subject: [PATCH 10/15] WebUI: Remove extra parethesis --- src/webui/www/public/scripts/prop-general.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webui/www/public/scripts/prop-general.js b/src/webui/www/public/scripts/prop-general.js index 4f6147009..31481e06c 100644 --- a/src/webui/www/public/scripts/prop-general.js +++ b/src/webui/www/public/scripts/prop-general.js @@ -52,10 +52,10 @@ var loadTorrentData = function() { $('comment').set('html', data.comment); $('total_uploaded').set('html', friendlyUnit(data.total_uploaded) + " (" + friendlyUnit(data.total_uploaded_session) + - " (" + "_(this session)" + ")"); + " _(this session)" + ")"); $('total_downloaded').set('html', friendlyUnit(data.total_downloaded) + " (" + friendlyUnit(data.total_downloaded_session) + - " (" + "_(this session)" + ")"); + " _(this session)" + ")"); $('total_wasted').set('html', data.total_wasted); temp = data.up_limit; $('up_limit').set('html', temp == -1 ? "∞" : temp); From b46ecb4351a8097efc628c435375c52ecb856bf9 Mon Sep 17 00:00:00 2001 From: Gabriele Date: Mon, 8 Dec 2014 22:00:00 +0100 Subject: [PATCH 11/15] WebUI: Decrease frequency of updates of property panel Now that the properties are loaded immediately when the selected torrent or the property tab is changed, the frequency of the updates can be reduced without affecting the user experience. New update intervals: * General: 5 seconds (10 if qBT is not reachable) * Tracker list: 10 seconds (20 if qBT is not reachable) * File list: 5 seconds (10 if qBT is not reachable) --- src/webui/www/public/scripts/prop-files.js | 6 +++--- src/webui/www/public/scripts/prop-general.js | 6 +++--- src/webui/www/public/scripts/prop-trackers.js | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/webui/www/public/scripts/prop-files.js b/src/webui/www/public/scripts/prop-files.js index 344522048..e68ab569f 100644 --- a/src/webui/www/public/scripts/prop-files.js +++ b/src/webui/www/public/scripts/prop-files.js @@ -281,7 +281,7 @@ var loadTorrentFilesData = function() { var new_hash = myTable.getCurrentTorrentHash(); if (new_hash == "") { fTable.removeAllRows(); - loadTorrentFilesDataTimer = loadTorrentFilesData.delay(1500); + loadTorrentFilesDataTimer = loadTorrentFilesData.delay(5000); return; } if (new_hash != current_hash) { @@ -295,7 +295,7 @@ var loadTorrentFilesData = function() { method: 'get', onFailure: function() { $('error_div').set('html', '_(qBittorrent client is not reachable)'); - loadTorrentFilesDataTimer = loadTorrentFilesData.delay(2000); + loadTorrentFilesDataTimer = loadTorrentFilesData.delay(10000); }, onSuccess: function(files) { $('error_div').set('html', ''); @@ -334,7 +334,7 @@ var loadTorrentFilesData = function() { else { fTable.removeAllRows(); } - loadTorrentFilesDataTimer = loadTorrentFilesData.delay(1500); + loadTorrentFilesDataTimer = loadTorrentFilesData.delay(5000); } }).send(); } diff --git a/src/webui/www/public/scripts/prop-general.js b/src/webui/www/public/scripts/prop-general.js index 31481e06c..586c66b12 100644 --- a/src/webui/www/public/scripts/prop-general.js +++ b/src/webui/www/public/scripts/prop-general.js @@ -23,7 +23,7 @@ var loadTorrentData = function() { var current_hash = myTable.getCurrentTorrentHash(); if (current_hash == "") { clearData(); - loadTorrentDataTimer = loadTorrentData.delay(1500); + loadTorrentDataTimer = loadTorrentData.delay(5000); return; } // Display hash @@ -35,7 +35,7 @@ var loadTorrentData = function() { method: 'get', onFailure: function() { $('error_div').set('html', '_(qBittorrent client is not reachable)'); - loadTorrentDataTimer = loadTorrentData.delay(2000); + loadTorrentDataTimer = loadTorrentData.delay(10000); }, onSuccess: function(data) { $('error_div').set('html', ''); @@ -72,7 +72,7 @@ var loadTorrentData = function() { else { clearData(); } - loadTorrentDataTimer = loadTorrentData.delay(1500); + loadTorrentDataTimer = loadTorrentData.delay(5000); } }).send(); } diff --git a/src/webui/www/public/scripts/prop-trackers.js b/src/webui/www/public/scripts/prop-trackers.js index 57baa49ce..fd0e7b1d8 100644 --- a/src/webui/www/public/scripts/prop-trackers.js +++ b/src/webui/www/public/scripts/prop-trackers.js @@ -61,7 +61,7 @@ var loadTrackersData = function() { var new_hash = myTable.getCurrentTorrentHash(); if (new_hash == "") { tTable.removeAllRows(); - loadTrackersDataTimer = loadTrackersData.delay(1500); + loadTrackersDataTimer = loadTrackersData.delay(10000); return; } if (new_hash != current_hash) { @@ -75,7 +75,7 @@ var loadTrackersData = function() { method: 'get', onFailure: function() { $('error_div').set('html', '_(qBittorrent client is not reachable)'); - loadTrackersDataTimer = loadTrackersData.delay(2000); + loadTrackersDataTimer = loadTrackersData.delay(20000); }, onSuccess: function(trackers) { $('error_div').set('html', ''); @@ -94,7 +94,7 @@ var loadTrackersData = function() { else { tTable.removeAllRows(); } - loadTrackersDataTimer = loadTrackersData.delay(1500); + loadTrackersDataTimer = loadTrackersData.delay(10000); } }).send(); } From 1332ca318bd65769fe6cc8e93b10142454030bc3 Mon Sep 17 00:00:00 2001 From: Gabriele Date: Mon, 8 Dec 2014 22:00:00 +0100 Subject: [PATCH 12/15] WebUI: Adjust size of columns in property panels --- src/webui/www/public/css/dynamicTable.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/webui/www/public/css/dynamicTable.css b/src/webui/www/public/css/dynamicTable.css index 153a6a57e..2799f3b85 100644 --- a/src/webui/www/public/css/dynamicTable.css +++ b/src/webui/www/public/css/dynamicTable.css @@ -65,6 +65,10 @@ margin-bottom: -4px; } +#trackers th, +#trackers td, +#torrentFiles th, +#torrentFiles td, #transferList th, #transferList td { text-overflow: ellipsis; From 005e378cbdf12fe112c3025d31cefcb153e21282 Mon Sep 17 00:00:00 2001 From: Gabriele Date: Mon, 8 Dec 2014 22:00:00 +0100 Subject: [PATCH 13/15] WebUI: Don't change cursor style for the file list Changing the cursor is misleading, no operation can be done. --- src/webui/www/public/css/dynamicTable.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/webui/www/public/css/dynamicTable.css b/src/webui/www/public/css/dynamicTable.css index 2799f3b85..8be76dfc2 100644 --- a/src/webui/www/public/css/dynamicTable.css +++ b/src/webui/www/public/css/dynamicTable.css @@ -58,6 +58,12 @@ #transferList tr.over { background-color: #ee6600; color: #fff; +} + +#myTable tr:hover, +#properties #torrentFiles tr.over, +#properties #trackers tr.over, +#transferList tr.over { cursor: pointer; } From fdc975d90051ca26b1b0fd6e00a0e7e8027779fd Mon Sep 17 00:00:00 2001 From: Gabriele Date: Mon, 8 Dec 2014 22:00:00 +0100 Subject: [PATCH 14/15] WebUI: Add readonly attribute to comment textarea Torrent comments should not be editable. --- src/webui/www/public/properties_content.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webui/www/public/properties_content.html b/src/webui/www/public/properties_content.html index 798b30671..539916b03 100644 --- a/src/webui/www/public/properties_content.html +++ b/src/webui/www/public/properties_content.html @@ -19,7 +19,7 @@
_(Comment:) - From 7a58a3fe434393c96a8d1e49ed19ece7cc0d3deb Mon Sep 17 00:00:00 2001 From: Gabriele Date: Thu, 11 Dec 2014 21:22:23 +0100 Subject: [PATCH 15/15] WebUI: Ensure that no concurrent timers exist --- src/webui/www/public/scripts/client.js | 4 ++++ src/webui/www/public/scripts/prop-files.js | 3 +++ src/webui/www/public/scripts/prop-general.js | 3 +++ src/webui/www/public/scripts/prop-trackers.js | 3 +++ 4 files changed, 13 insertions(+) diff --git a/src/webui/www/public/scripts/client.js b/src/webui/www/public/scripts/client.js index 64d5c9560..e7bd8b652 100644 --- a/src/webui/www/public/scripts/client.js +++ b/src/webui/www/public/scripts/client.js @@ -56,6 +56,7 @@ var loadTorrentsInfo = function () { method : 'get', onFailure : function () { $('error_div').set('html', '_(qBittorrent client is not reachable)'); + clearTimeout(loadTorrentsInfoTimer); loadTorrentsInfoTimer = loadTorrentsInfo.delay(2000); }, onSuccess : function (events) { @@ -138,6 +139,7 @@ var loadTorrentsInfo = function () { myTable.altRow(); } + clearTimeout(loadTorrentsInfoTimer); loadTorrentsInfoTimer = loadTorrentsInfo.delay(1500); } }).send(); @@ -233,6 +235,7 @@ window.addEvent('load', function () { method : 'get', onFailure : function () { $('error_div').set('html', '_(qBittorrent client is not reachable)'); + clearTimeout(loadTransferInfoTimer); loadTransferInfoTimer = loadTransferInfo.delay(4000); }, onSuccess : function (info) { @@ -247,6 +250,7 @@ window.addEvent('load', function () { document.title = "_(D:%1 U:%2)".replace("%1", friendlyUnit(info.dl_info_speed, true)).replace("%2", friendlyUnit(info.up_info_speed, true)); else document.title = "_(qBittorrent web User Interface)"; + clearTimeout(loadTransferInfoTimer); loadTransferInfoTimer = loadTransferInfo.delay(3000); } } diff --git a/src/webui/www/public/scripts/prop-files.js b/src/webui/www/public/scripts/prop-files.js index e68ab569f..f611c7e51 100644 --- a/src/webui/www/public/scripts/prop-files.js +++ b/src/webui/www/public/scripts/prop-files.js @@ -281,6 +281,7 @@ var loadTorrentFilesData = function() { var new_hash = myTable.getCurrentTorrentHash(); if (new_hash == "") { fTable.removeAllRows(); + clearTimeout(loadTorrentFilesDataTimer); loadTorrentFilesDataTimer = loadTorrentFilesData.delay(5000); return; } @@ -295,6 +296,7 @@ var loadTorrentFilesData = function() { method: 'get', onFailure: function() { $('error_div').set('html', '_(qBittorrent client is not reachable)'); + clearTimeout(loadTorrentFilesDataTimer); loadTorrentFilesDataTimer = loadTorrentFilesData.delay(10000); }, onSuccess: function(files) { @@ -334,6 +336,7 @@ var loadTorrentFilesData = function() { else { fTable.removeAllRows(); } + clearTimeout(loadTorrentFilesDataTimer); loadTorrentFilesDataTimer = loadTorrentFilesData.delay(5000); } }).send(); diff --git a/src/webui/www/public/scripts/prop-general.js b/src/webui/www/public/scripts/prop-general.js index 586c66b12..2d49b7d1b 100644 --- a/src/webui/www/public/scripts/prop-general.js +++ b/src/webui/www/public/scripts/prop-general.js @@ -23,6 +23,7 @@ var loadTorrentData = function() { var current_hash = myTable.getCurrentTorrentHash(); if (current_hash == "") { clearData(); + clearTimeout(loadTorrentDataTimer); loadTorrentDataTimer = loadTorrentData.delay(5000); return; } @@ -35,6 +36,7 @@ var loadTorrentData = function() { method: 'get', onFailure: function() { $('error_div').set('html', '_(qBittorrent client is not reachable)'); + clearTimeout(loadTorrentDataTimer); loadTorrentDataTimer = loadTorrentData.delay(10000); }, onSuccess: function(data) { @@ -72,6 +74,7 @@ var loadTorrentData = function() { else { clearData(); } + clearTimeout(loadTorrentDataTimer); loadTorrentDataTimer = loadTorrentData.delay(5000); } }).send(); diff --git a/src/webui/www/public/scripts/prop-trackers.js b/src/webui/www/public/scripts/prop-trackers.js index fd0e7b1d8..fe3265406 100644 --- a/src/webui/www/public/scripts/prop-trackers.js +++ b/src/webui/www/public/scripts/prop-trackers.js @@ -61,6 +61,7 @@ var loadTrackersData = function() { var new_hash = myTable.getCurrentTorrentHash(); if (new_hash == "") { tTable.removeAllRows(); + clearTimeout(loadTrackersDataTimer); loadTrackersDataTimer = loadTrackersData.delay(10000); return; } @@ -75,6 +76,7 @@ var loadTrackersData = function() { method: 'get', onFailure: function() { $('error_div').set('html', '_(qBittorrent client is not reachable)'); + clearTimeout(loadTrackersDataTimer); loadTrackersDataTimer = loadTrackersData.delay(20000); }, onSuccess: function(trackers) { @@ -94,6 +96,7 @@ var loadTrackersData = function() { else { tTable.removeAllRows(); } + clearTimeout(loadTrackersDataTimer); loadTrackersDataTimer = loadTrackersData.delay(10000); } }).send();