From c003229fcf98efc07dac28cd84e48480305db351 Mon Sep 17 00:00:00 2001 From: buinsky Date: Wed, 20 Jan 2016 16:13:54 +0300 Subject: [PATCH 01/12] WebUI: Refactor ContextMenu class --- src/webui/www/public/scripts/client.js | 28 +--- src/webui/www/public/scripts/contextmenu.js | 151 +++++++++++-------- src/webui/www/public/scripts/dynamicTable.js | 11 +- src/webui/www/public/transferlist.html | 6 +- 4 files changed, 100 insertions(+), 96 deletions(-) diff --git a/src/webui/www/public/scripts/client.js b/src/webui/www/public/scripts/client.js index 2498ceeae..a641f551f 100644 --- a/src/webui/www/public/scripts/client.js +++ b/src/webui/www/public/scripts/client.js @@ -202,30 +202,6 @@ window.addEvent('load', function () { return false; }; - var updateContextMenu = function () { - var categoryList = $('contextCategoryList'); - categoryList.empty(); - categoryList.appendChild(new Element('li', {html: 'QBT_TR(New...)QBT_TR QBT_TR(New...)QBT_TR'})); - categoryList.appendChild(new Element('li', {html: 'QBT_TR(Reset)QBT_TR QBT_TR(Reset)QBT_TR'})); - - var sortedCategories = [] - Object.each(category_list, function(category) { - sortedCategories.push(category.name); - }); - sortedCategories.sort(); - - var first = true; - Object.each(sortedCategories, function(categoryName) { - var categoryHash = genHash(categoryName); - var el = new Element('li', {html: ' ' + categoryName + ''}); - if (first) { - el.addClass('separator'); - first = false; - } - categoryList.appendChild(el); - }); - }; - var updateFilter = function(filter, filterTitle) { $(filter + '_filter').firstChild.childNodes[1].nodeValue = filterTitle.replace('%1', torrentsTable.getFilteredTorrentsNumber(filter)); }; @@ -251,7 +227,7 @@ window.addEvent('load', function () { var create_link = function(hash, text, count) { var html = '' + '' + - text + ' (' + count + ')' + ''; + escapeHtml(text) + ' (' + count + ')' + ''; return new Element('li', {id: hash, html: html}); }; @@ -357,7 +333,7 @@ window.addEvent('load', function () { updateFiltersList(); if (update_categories) { updateCategoryList(); - updateContextMenu(); + torrentsTableContextMenu.updateCategoriesSubMenu(category_list); } } clearTimeout(syncMainDataTimer); diff --git a/src/webui/www/public/scripts/contextmenu.js b/src/webui/www/public/scripts/contextmenu.js index 066696878..5b57ee559 100644 --- a/src/webui/www/public/scripts/contextmenu.js +++ b/src/webui/www/public/scripts/contextmenu.js @@ -1,12 +1,11 @@ var ContextMenu = new Class({ - //implements Implements: [Options, Events], //options options: { actions: {}, - menu: 'contextmenu', + menu: 'menu_id', stopEvent: true, targets: 'body', trigger: 'contextmenu', @@ -128,6 +127,74 @@ var ContextMenu = new Class({ }.bind(this)); }, + updateMenuItems: function () {}, + + //show menu + show: function (trigger) { + this.updateMenuItems(); + this.fx.start(1); + this.fireEvent('show'); + this.shown = true; + 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); + } + return this; + } +}); + +var TorrentsTableContextMenu = new Class({ + Extends: ContextMenu, + updateMenuItems: function () { all_are_seq_dl = true; there_are_seq_dl = false; @@ -220,69 +287,29 @@ var ContextMenu = new Class({ this.hideItem('ForceStart'); else if (!there_are_paused && !there_are_force_start) this.hideItem('Start'); - }, - //show menu - show: function(trigger) { - this.updateMenuItems(); - this.fx.start(1); - this.fireEvent('show'); - this.shown = true; - return this; - }, + updateCategoriesSubMenu : function (category_list) { + var categoryList = $('contextCategoryList'); + categoryList.empty(); + categoryList.appendChild(new Element('li', {html: 'QBT_TR(New...)QBT_TR QBT_TR(New...)QBT_TR'})); + categoryList.appendChild(new Element('li', {html: 'QBT_TR(Reset)QBT_TR QBT_TR(Reset)QBT_TR'})); - //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; - }, + var sortedCategories = [] + Object.each(category_list, function (category) { + sortedCategories.push(category.name); + }); + sortedCategories.sort(); - 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); - } - return this; + var first = true; + Object.each(sortedCategories, function (categoryName) { + var categoryHash = genHash(categoryName); + var el = new Element('li', {html: ' ' + escapeHtml(categoryName) + ''}); + if (first) { + el.addClass('separator'); + first = false; + } + categoryList.appendChild(el); + }); } - }); diff --git a/src/webui/www/public/scripts/dynamicTable.js b/src/webui/www/public/scripts/dynamicTable.js index 01f6ce3e8..574f0212a 100644 --- a/src/webui/www/public/scripts/dynamicTable.js +++ b/src/webui/www/public/scripts/dynamicTable.js @@ -300,7 +300,6 @@ var DynamicTable = new Class({ else { // else create a new row in the table var tr = new Element('tr'); - tr.addClass("menu-target"); tr['rowId'] = rows[rowPos]['rowId']; tr._this = this; @@ -358,7 +357,7 @@ var DynamicTable = new Class({ return false; }); - this.setupTrEvents(tr); + this.setupTr(tr); for (var j = 0 ; j < this.columns.length; j++) { var td = new Element('td'); @@ -393,7 +392,7 @@ var DynamicTable = new Class({ } }, - setupTrEvents : function (tr) {}, + setupTr : function (tr) {}, updateRow : function (tr, fullUpdate) { var row = this.rows.get(tr.rowId); @@ -524,11 +523,12 @@ var TorrentsTable = new Class({ else return 0; }; - // name + // name, category this.columns['name'].updateTd = function (td, row) { td.set('html', escapeHtml(this.getRowValue(row))); }; + this.columns['category'].updateTd = this.columns['name'].updateTd; // size @@ -706,7 +706,7 @@ var TorrentsTable = new Class({ return filteredRows; }, - setupTrEvents : function (tr) { + setupTr : function (tr) { tr.addEvent('dblclick', function (e) { e.stop(); this._this.selectRow(this.rowId); @@ -718,6 +718,7 @@ var TorrentsTable = new Class({ pauseFN(); return true; }); + tr.addClass("torrentsTableContextMenuTarget"); }, getCurrentTorrentHash : function () { diff --git a/src/webui/www/public/transferlist.html b/src/webui/www/public/transferlist.html index 87acf804e..51daf1715 100644 --- a/src/webui/www/public/transferlist.html +++ b/src/webui/www/public/transferlist.html @@ -9,8 +9,8 @@ From d30a799b4542803eeb2d2972e6f645ad15a177e4 Mon Sep 17 00:00:00 2001 From: buinsky Date: Wed, 20 Jan 2016 17:39:33 +0300 Subject: [PATCH 02/12] WebUI: Rename function updateCategoryFN to setCategoryFN --- src/webui/www/public/scripts/contextmenu.js | 4 ++-- src/webui/www/public/scripts/mocha-init.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webui/www/public/scripts/contextmenu.js b/src/webui/www/public/scripts/contextmenu.js index 5b57ee559..1bbd0f0bd 100644 --- a/src/webui/www/public/scripts/contextmenu.js +++ b/src/webui/www/public/scripts/contextmenu.js @@ -293,7 +293,7 @@ var TorrentsTableContextMenu = new Class({ var categoryList = $('contextCategoryList'); categoryList.empty(); categoryList.appendChild(new Element('li', {html: 'QBT_TR(New...)QBT_TR QBT_TR(New...)QBT_TR'})); - categoryList.appendChild(new Element('li', {html: 'QBT_TR(Reset)QBT_TR QBT_TR(Reset)QBT_TR'})); + categoryList.appendChild(new Element('li', {html: 'QBT_TR(Reset)QBT_TR QBT_TR(Reset)QBT_TR'})); var sortedCategories = [] Object.each(category_list, function (category) { @@ -304,7 +304,7 @@ var TorrentsTableContextMenu = new Class({ var first = true; Object.each(sortedCategories, function (categoryName) { var categoryHash = genHash(categoryName); - var el = new Element('li', {html: ' ' + escapeHtml(categoryName) + ''}); + var el = new Element('li', {html: ' ' + escapeHtml(categoryName) + ''}); if (first) { el.addClass('separator'); first = false; diff --git a/src/webui/www/public/scripts/mocha-init.js b/src/webui/www/public/scripts/mocha-init.js index 1833cadc3..86895c5dc 100644 --- a/src/webui/www/public/scripts/mocha-init.js +++ b/src/webui/www/public/scripts/mocha-init.js @@ -323,7 +323,7 @@ initializeWindows = function() { } }; - updateCategoryFN = function (categoryHash) { + setCategoryFN = function (categoryHash) { var categoryName = ''; if (categoryHash != 0) var categoryName = category_list[categoryHash].name; From a939fca4acc756be4791241d91756912990c859d Mon Sep 17 00:00:00 2001 From: buinsky Date: Wed, 20 Jan 2016 22:57:42 +0300 Subject: [PATCH 03/12] WebUI: Add empty context menu to categories filter --- src/webui/www/private/index.html | 4 ++- src/webui/www/public/css/style.css | 34 ++++++++++----------- src/webui/www/public/filters.html | 11 +++++++ src/webui/www/public/scripts/client.js | 4 ++- src/webui/www/public/scripts/contextmenu.js | 4 +++ src/webui/www/public/transferlist.html | 2 +- 6 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index 95262b825..76f1cc3f9 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -100,7 +100,7 @@
-
    + +
      +
    diff --git a/src/webui/www/public/css/style.css b/src/webui/www/public/css/style.css index ffd878386..f99d60a54 100644 --- a/src/webui/www/public/css/style.css +++ b/src/webui/www/public/css/style.css @@ -167,14 +167,14 @@ a.propButton img { /* context menu specific */ -#contextmenu { border:1px solid #999; padding:0; background:#eee; list-style-type:none; display:none;} -#contextmenu .separator { border-top:1px solid #999; } -#contextmenu li { margin:0; padding:0;} -#contextmenu li a { display:block; padding:5px 10px 5px 5px; font-size:12px; text-decoration:none; font-family:tahoma,arial,sans-serif; color:#000; } -#contextmenu li a:hover { background-color:#ddd; } -#contextmenu li a.disabled { color:#ccc; font-style:italic; } -#contextmenu li a.disabled:hover { background-color:#eee; } -#contextmenu li ul { +.contextMenu { border:1px solid #999; padding:0; background:#eee; list-style-type:none; display:none;} +.contextMenu .separator { border-top:1px solid #999; } +.contextMenu li { margin:0; padding:0;} +.contextMenu li a { display:block; padding:5px 10px 5px 5px; font-size:12px; text-decoration:none; font-family:tahoma,arial,sans-serif; color:#000; } +.contextMenu li a:hover { background-color:#ddd; } +.contextMenu li a.disabled { color:#ccc; font-style:italic; } +.contextMenu li a.disabled:hover { background-color:#eee; } +.contextMenu li ul { padding: 0; border:1px solid #999; padding:0; background:#eee; list-style-type:none; @@ -184,24 +184,24 @@ a.propButton img { margin: -29px 0 0 100%; width: 164px; } -#contextmenu li ul li a { +.contextMenu li ul li a { position: relative; } -#contextmenu li a.arrow-right, #contextmenu li a:hover.arrow-right { +.contextMenu li a.arrow-right, .contextMenu li a:hover.arrow-right { background-image: url(../images/skin/arrow-right.gif); background-repeat: no-repeat; background-position: right center; } -#contextmenu li:hover ul, -#contextmenu li.ieHover ul, -#contextmenu li li.ieHover ul, -#contextmenu li li li.ieHover ul, -#contextmenu li li:hover ul, -#contextmenu li li li:hover ul { /* lists nested under hovered list items */ +.contextMenu li:hover ul, +.contextMenu li.ieHover ul, +.contextMenu li li.ieHover ul, +.contextMenu li li li.ieHover ul, +.contextMenu li li:hover ul, +.contextMenu li li li:hover ul { /* lists nested under hovered list items */ left: auto; } -#contextmenu li img { +.contextMenu li img { width: 16px; height: 16px; margin-bottom: -4px; diff --git a/src/webui/www/public/filters.html b/src/webui/www/public/filters.html index 367ddd2a7..617af522e 100644 --- a/src/webui/www/public/filters.html +++ b/src/webui/www/public/filters.html @@ -14,3 +14,14 @@ QBT_TR(Categories)QBT_TR
    + + diff --git a/src/webui/www/public/scripts/client.js b/src/webui/www/public/scripts/client.js index a641f551f..32dce770f 100644 --- a/src/webui/www/public/scripts/client.js +++ b/src/webui/www/public/scripts/client.js @@ -228,7 +228,9 @@ window.addEvent('load', function () { var html = '' + '' + escapeHtml(text) + ' (' + count + ')' + ''; - return new Element('li', {id: hash, html: html}); + var el = new Element('li', {id: hash, html: html}); + categoriesFilterContextMenu.addTarget(el); + return el; }; var all = torrentsTable.getRowIds().length; diff --git a/src/webui/www/public/scripts/contextmenu.js b/src/webui/www/public/scripts/contextmenu.js index 1bbd0f0bd..51d1d818e 100644 --- a/src/webui/www/public/scripts/contextmenu.js +++ b/src/webui/www/public/scripts/contextmenu.js @@ -313,3 +313,7 @@ var TorrentsTableContextMenu = new Class({ }); } }); + +var CategoriesFilterContextMenu = new Class({ + Extends: ContextMenu +}); diff --git a/src/webui/www/public/transferlist.html b/src/webui/www/public/transferlist.html index 51daf1715..fb5444366 100644 --- a/src/webui/www/public/transferlist.html +++ b/src/webui/www/public/transferlist.html @@ -11,7 +11,7 @@ //create a context menu var torrentsTableContextMenu = new TorrentsTableContextMenu({ targets : '.torrentsTableContextMenuTarget', - menu : 'contextmenu', + menu : 'torrentsTableMenu', actions : { Delete : function (element, ref) { deleteFN(); From a4dca52617190d282927083c3b9a9dbcc866c7d1 Mon Sep 17 00:00:00 2001 From: buinsky Date: Thu, 21 Jan 2016 15:32:13 +0300 Subject: [PATCH 04/12] WebUI: Implement adding categories --- src/webui/webapplication.cpp | 16 +++++++++ src/webui/webapplication.h | 1 + src/webui/www/private/index.html | 1 + src/webui/www/public/filters.html | 5 +++ src/webui/www/public/newcategory.html | 37 +++++++++++++++------ src/webui/www/public/scripts/contextmenu.js | 6 ++-- src/webui/www/public/scripts/mocha-init.js | 21 ++++++++++-- 7 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index f95e387e2..5f7a1c5df 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -115,6 +115,7 @@ QMap > WebApplication::initialize ADD_ACTION(command, bottomPrio); ADD_ACTION(command, recheck); ADD_ACTION(command, setCategory); + ADD_ACTION(command, addCategory); ADD_ACTION(command, getSavePath); ADD_ACTION(version, api); ADD_ACTION(version, api_min); @@ -728,6 +729,21 @@ void WebApplication::action_command_setCategory() } } +void WebApplication::action_command_addCategory() +{ + CHECK_URI(0); + CHECK_PARAMETERS("category"); + + QString category = request().posts["category"].trimmed(); + + if (!BitTorrent::Session::isValidCategoryName(category) && !category.isEmpty()) { + status(400, tr("Incorrect category name")); + return; + } + + BitTorrent::Session::instance()->addCategory(category); +} + void WebApplication::action_command_getSavePath() { CHECK_URI(0); diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index a87acc8f8..efa446531 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -88,6 +88,7 @@ private: void action_command_bottomPrio(); void action_command_recheck(); void action_command_setCategory(); + void action_command_addCategory(); void action_command_getSavePath(); void action_version_api(); void action_version_api_min(); diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index 76f1cc3f9..2f894f140 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -126,6 +126,7 @@
  • QBT_TR(Force recheck)QBT_TR QBT_TR(Force recheck)QBT_TR
diff --git a/src/webui/www/public/filters.html b/src/webui/www/public/filters.html index 617af522e..a1bba5e3d 100644 --- a/src/webui/www/public/filters.html +++ b/src/webui/www/public/filters.html @@ -19,6 +19,11 @@ var categoriesFilterContextMenu = new CategoriesFilterContextMenu({ targets : '.categoriesFilterContextMenuTarget', menu : 'categoriesFilterMenu', + actions : { + CreateCategory : function (element, ref) { + createCategoryFN(); + } + }, offsets : { x : -15, y : 2 diff --git a/src/webui/www/public/newcategory.html b/src/webui/www/public/newcategory.html index cca0929fa..177186af3 100644 --- a/src/webui/www/public/newcategory.html +++ b/src/webui/www/public/newcategory.html @@ -31,17 +31,32 @@ return false; } var hashesList = new URI().getData('hashes'); - new Request({ - url: 'command/setCategory', - method: 'post', - data: { - hashes: hashesList, - category: categoryName - }, - onComplete: function() { - window.parent.closeWindows(); - } - }).send(); + if (!hashesList) { + new Request({ + url: 'command/addCategory', + method: 'post', + data: { + category: categoryName + }, + onComplete: function () { + window.parent.closeWindows(); + } + }).send(); + } + else + { + new Request({ + url: 'command/setCategory', + method: 'post', + data: { + hashes: hashesList, + category: categoryName + }, + onComplete: function () { + window.parent.closeWindows(); + } + }).send(); + } }); }); diff --git a/src/webui/www/public/scripts/contextmenu.js b/src/webui/www/public/scripts/contextmenu.js index 51d1d818e..717e4d5b5 100644 --- a/src/webui/www/public/scripts/contextmenu.js +++ b/src/webui/www/public/scripts/contextmenu.js @@ -292,8 +292,8 @@ var TorrentsTableContextMenu = new Class({ updateCategoriesSubMenu : function (category_list) { var categoryList = $('contextCategoryList'); categoryList.empty(); - categoryList.appendChild(new Element('li', {html: 'QBT_TR(New...)QBT_TR QBT_TR(New...)QBT_TR'})); - categoryList.appendChild(new Element('li', {html: 'QBT_TR(Reset)QBT_TR QBT_TR(Reset)QBT_TR'})); + categoryList.appendChild(new Element('li', {html: 'QBT_TR(New...)QBT_TR QBT_TR(New...)QBT_TR'})); + categoryList.appendChild(new Element('li', {html: 'QBT_TR(Reset)QBT_TR QBT_TR(Reset)QBT_TR'})); var sortedCategories = [] Object.each(category_list, function (category) { @@ -304,7 +304,7 @@ var TorrentsTableContextMenu = new Class({ var first = true; Object.each(sortedCategories, function (categoryName) { var categoryHash = genHash(categoryName); - var el = new Element('li', {html: ' ' + escapeHtml(categoryName) + ''}); + var el = new Element('li', {html: ' ' + escapeHtml(categoryName) + ''}); if (first) { el.addClass('separator'); first = false; diff --git a/src/webui/www/public/scripts/mocha-init.js b/src/webui/www/public/scripts/mocha-init.js index 86895c5dc..ae2e6a704 100644 --- a/src/webui/www/public/scripts/mocha-init.js +++ b/src/webui/www/public/scripts/mocha-init.js @@ -304,7 +304,7 @@ initializeWindows = function() { } }; - newCategoryFN = function () { + torrentNewCategoryFN = function () { var h = torrentsTable.selectedRowsIds(); if (h.length) { new MochaUI.Window({ @@ -323,7 +323,7 @@ initializeWindows = function() { } }; - setCategoryFN = function (categoryHash) { + torrentSetCategoryFN = function (categoryHash) { var categoryName = ''; if (categoryHash != 0) var categoryName = category_list[categoryHash].name; @@ -340,6 +340,23 @@ initializeWindows = function() { } }; + createCategoryFN = function () { + new MochaUI.Window({ + id: 'newCategoryPage', + title: "QBT_TR(New Category)QBT_TR", + loadMethod: 'iframe', + contentURL: 'newcategory.html', + scrollbars: false, + resizable: false, + maximizable: false, + paddingVertical: 0, + paddingHorizontal: 0, + width: 250, + height: 100 + }); + updateMainData(); + }; + ['pauseAll', 'resumeAll'].each(function(item) { addClickEvent(item, function(e) { new Event(e).stop(); From 50f2437ac3aa6c13680c90b4b6442e8ea6257505 Mon Sep 17 00:00:00 2001 From: buinsky Date: Thu, 21 Jan 2016 16:42:20 +0300 Subject: [PATCH 05/12] WebUI: Implement removing categories --- src/webui/webapplication.cpp | 10 ++++++++++ src/webui/webapplication.h | 1 + src/webui/www/private/index.html | 1 + src/webui/www/public/filters.html | 3 +++ src/webui/www/public/scripts/contextmenu.js | 9 ++++++++- src/webui/www/public/scripts/mocha-init.js | 12 ++++++++++++ 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index 5f7a1c5df..3924cd973 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -116,6 +116,7 @@ QMap > WebApplication::initialize ADD_ACTION(command, recheck); ADD_ACTION(command, setCategory); ADD_ACTION(command, addCategory); + ADD_ACTION(command, removeCategory); ADD_ACTION(command, getSavePath); ADD_ACTION(version, api); ADD_ACTION(version, api_min); @@ -744,6 +745,15 @@ void WebApplication::action_command_addCategory() BitTorrent::Session::instance()->addCategory(category); } +void WebApplication::action_command_removeCategory() +{ + CHECK_URI(0); + CHECK_PARAMETERS("category"); + + QString category = request().posts["category"].trimmed(); + BitTorrent::Session::instance()->removeCategory(category); +} + void WebApplication::action_command_getSavePath() { CHECK_URI(0); diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index efa446531..248695de8 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -89,6 +89,7 @@ private: void action_command_recheck(); void action_command_setCategory(); void action_command_addCategory(); + void action_command_removeCategory(); void action_command_getSavePath(); void action_version_api(); void action_version_api_min(); diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index 2f894f140..999b1fab9 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -127,6 +127,7 @@
diff --git a/src/webui/www/public/filters.html b/src/webui/www/public/filters.html index a1bba5e3d..295173332 100644 --- a/src/webui/www/public/filters.html +++ b/src/webui/www/public/filters.html @@ -22,6 +22,9 @@ actions : { CreateCategory : function (element, ref) { createCategoryFN(); + }, + DeleteCategory : function (element, ref) { + removeCategoryFN(element.id); } }, offsets : { diff --git a/src/webui/www/public/scripts/contextmenu.js b/src/webui/www/public/scripts/contextmenu.js index 717e4d5b5..cef6451e7 100644 --- a/src/webui/www/public/scripts/contextmenu.js +++ b/src/webui/www/public/scripts/contextmenu.js @@ -315,5 +315,12 @@ var TorrentsTableContextMenu = new Class({ }); var CategoriesFilterContextMenu = new Class({ - Extends: ContextMenu + Extends: ContextMenu, + updateMenuItems: function () { + var id = this.options.element.id; + if (id != CATEGORIES_ALL && id != CATEGORIES_UNCATEGORIZED) + this.showItem('DeleteCategory'); + else + this.hideItem('DeleteCategory'); + } }); diff --git a/src/webui/www/public/scripts/mocha-init.js b/src/webui/www/public/scripts/mocha-init.js index ae2e6a704..338e81ca7 100644 --- a/src/webui/www/public/scripts/mocha-init.js +++ b/src/webui/www/public/scripts/mocha-init.js @@ -357,6 +357,18 @@ initializeWindows = function() { updateMainData(); }; + removeCategoryFN = function (categoryHash) { + var categoryName = category_list[categoryHash].name; + new Request({ + url: 'command/removeCategory', + method: 'post', + data: { + category: categoryName + } + }).send(); + setCategoryFilter(CATEGORIES_ALL); + }; + ['pauseAll', 'resumeAll'].each(function(item) { addClickEvent(item, function(e) { new Event(e).stop(); From 24584503d9d554a12b2ebb21c9ba254b4935e254 Mon Sep 17 00:00:00 2001 From: buinsky Date: Thu, 21 Jan 2016 18:58:08 +0300 Subject: [PATCH 06/12] WebUI: Implement removing unused categories --- src/webui/webapplication.cpp | 11 ++++++----- src/webui/webapplication.h | 2 +- src/webui/www/private/index.html | 1 + src/webui/www/public/filters.html | 3 +++ src/webui/www/public/scripts/client.js | 2 +- src/webui/www/public/scripts/dynamicTable.js | 13 ++++++------- src/webui/www/public/scripts/mocha-init.js | 20 ++++++++++++++++++-- 7 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index 3924cd973..95f895bf8 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -116,7 +116,7 @@ QMap > WebApplication::initialize ADD_ACTION(command, recheck); ADD_ACTION(command, setCategory); ADD_ACTION(command, addCategory); - ADD_ACTION(command, removeCategory); + ADD_ACTION(command, removeCategories); ADD_ACTION(command, getSavePath); ADD_ACTION(version, api); ADD_ACTION(version, api_min); @@ -745,13 +745,14 @@ void WebApplication::action_command_addCategory() BitTorrent::Session::instance()->addCategory(category); } -void WebApplication::action_command_removeCategory() +void WebApplication::action_command_removeCategories() { CHECK_URI(0); - CHECK_PARAMETERS("category"); + CHECK_PARAMETERS("categories"); - QString category = request().posts["category"].trimmed(); - BitTorrent::Session::instance()->removeCategory(category); + QStringList categories = request().posts["categories"].split('\n'); + foreach (const QString &category, categories) + BitTorrent::Session::instance()->removeCategory(category); } void WebApplication::action_command_getSavePath() diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index 248695de8..722f7d5e4 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -89,7 +89,7 @@ private: void action_command_recheck(); void action_command_setCategory(); void action_command_addCategory(); - void action_command_removeCategory(); + void action_command_removeCategories(); void action_command_getSavePath(); void action_version_api(); void action_version_api_min(); diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index 999b1fab9..db49432ad 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -128,6 +128,7 @@
diff --git a/src/webui/www/public/filters.html b/src/webui/www/public/filters.html index 295173332..d35489c19 100644 --- a/src/webui/www/public/filters.html +++ b/src/webui/www/public/filters.html @@ -25,6 +25,9 @@ }, DeleteCategory : function (element, ref) { removeCategoryFN(element.id); + }, + DeleteUnusedCategories : function (element, ref) { + deleteUnusedCategoriesFN(); } }, offsets : { diff --git a/src/webui/www/public/scripts/client.js b/src/webui/www/public/scripts/client.js index 32dce770f..589614984 100644 --- a/src/webui/www/public/scripts/client.js +++ b/src/webui/www/public/scripts/client.js @@ -203,7 +203,7 @@ window.addEvent('load', function () { }; var updateFilter = function(filter, filterTitle) { - $(filter + '_filter').firstChild.childNodes[1].nodeValue = filterTitle.replace('%1', torrentsTable.getFilteredTorrentsNumber(filter)); + $(filter + '_filter').firstChild.childNodes[1].nodeValue = filterTitle.replace('%1', torrentsTable.getFilteredTorrentsNumber(filter, CATEGORIES_ALL)); }; var updateFiltersList = function() { diff --git a/src/webui/www/public/scripts/dynamicTable.js b/src/webui/www/public/scripts/dynamicTable.js index 574f0212a..d669e1d3e 100644 --- a/src/webui/www/public/scripts/dynamicTable.js +++ b/src/webui/www/public/scripts/dynamicTable.js @@ -620,7 +620,7 @@ var TorrentsTable = new Class({ }; }, - applyFilter : function (row, filterName, categoryName) { + applyFilter : function (row, filterName, categoryHash) { var state = row['full_data'].state; var inactive = false; var r; @@ -662,25 +662,24 @@ var TorrentsTable = new Class({ break; } - if (categoryName == CATEGORIES_ALL) + if (categoryHash == CATEGORIES_ALL) return true; - if (categoryName == CATEGORIES_UNCATEGORIZED && row['full_data'].category.length === 0) + if (categoryHash == CATEGORIES_UNCATEGORIZED && row['full_data'].category.length === 0) return true; - if (categoryName != genHash(row['full_data'].category)) + if (categoryHash != genHash(row['full_data'].category)) return false; return true; }, - getFilteredTorrentsNumber : function (filterName) { + getFilteredTorrentsNumber : function (filterName, categoryHash) { var cnt = 0; var rows = this.rows.getValues(); for (i = 0; i < rows.length; i++) - if (this.applyFilter(rows[i], filterName, CATEGORIES_ALL)) cnt++; - + if (this.applyFilter(rows[i], filterName, categoryHash)) cnt++; return cnt; }, diff --git a/src/webui/www/public/scripts/mocha-init.js b/src/webui/www/public/scripts/mocha-init.js index 338e81ca7..2daba0795 100644 --- a/src/webui/www/public/scripts/mocha-init.js +++ b/src/webui/www/public/scripts/mocha-init.js @@ -360,10 +360,26 @@ initializeWindows = function() { removeCategoryFN = function (categoryHash) { var categoryName = category_list[categoryHash].name; new Request({ - url: 'command/removeCategory', + url: 'command/removeCategories', method: 'post', data: { - category: categoryName + categories: categoryName + } + }).send(); + setCategoryFilter(CATEGORIES_ALL); + }; + + deleteUnusedCategoriesFN = function () { + var categories = []; + for (var hash in category_list) { + if (torrentsTable.getFilteredTorrentsNumber('all', hash) == 0) + categories.push(category_list[hash].name); + } + new Request({ + url: 'command/removeCategories', + method: 'post', + data: { + categories: categories.join('\n') } }).send(); setCategoryFilter(CATEGORIES_ALL); From f7833c9f0c07e164bc985f108067558edb74054b Mon Sep 17 00:00:00 2001 From: buinsky Date: Fri, 22 Jan 2016 08:43:07 +0300 Subject: [PATCH 07/12] WebUI: Implement start torrents by category --- src/webui/www/private/index.html | 1 + src/webui/www/public/filters.html | 3 +++ src/webui/www/public/scripts/dynamicTable.js | 11 +++++++++++ src/webui/www/public/scripts/mocha-init.js | 16 ++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index db49432ad..332572391 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -129,6 +129,7 @@
  • QBT_TR(Add category...)QBT_TR QBT_TR(Add category...)QBT_TR
  • QBT_TR(Remove category)QBT_TR QBT_TR(Remove category)QBT_TR
  • QBT_TR(Remove unused categories)QBT_TR QBT_TR(Remove unused categories)QBT_TR
  • +
  • QBT_TR(Resume torrents)QBT_TR QBT_TR(Resume torrents)QBT_TR
  • diff --git a/src/webui/www/public/filters.html b/src/webui/www/public/filters.html index d35489c19..08d50fff6 100644 --- a/src/webui/www/public/filters.html +++ b/src/webui/www/public/filters.html @@ -28,6 +28,9 @@ }, DeleteUnusedCategories : function (element, ref) { deleteUnusedCategoriesFN(); + }, + StartTorrentsByCategory : function (element, ref) { + startTorrentsByCategoryFN(element.id); } }, offsets : { diff --git a/src/webui/www/public/scripts/dynamicTable.js b/src/webui/www/public/scripts/dynamicTable.js index d669e1d3e..97078e305 100644 --- a/src/webui/www/public/scripts/dynamicTable.js +++ b/src/webui/www/public/scripts/dynamicTable.js @@ -683,6 +683,17 @@ var TorrentsTable = new Class({ return cnt; }, + getFilteredTorrentsHashes : function (filterName, categoryHash) { + var rowsHashes = []; + var rows = this.rows.getValues(); + + for (i = 0; i < rows.length; i++) + if (this.applyFilter(rows[i], filterName, categoryHash)) + rowsHashes.push(rows[i]['rowId']); + + return rowsHashes; + }, + getFilteredAndSortedRows : function () { var filteredRows = new Array(); diff --git a/src/webui/www/public/scripts/mocha-init.js b/src/webui/www/public/scripts/mocha-init.js index 2daba0795..56e3fcdff 100644 --- a/src/webui/www/public/scripts/mocha-init.js +++ b/src/webui/www/public/scripts/mocha-init.js @@ -385,6 +385,22 @@ initializeWindows = function() { setCategoryFilter(CATEGORIES_ALL); }; + startTorrentsByCategoryFN = function (categoryHash) { + var h = torrentsTable.getFilteredTorrentsHashes('all', categoryHash); + if (h.length) { + h.each(function (hash, index) { + new Request({ + url: 'command/resume', + method: 'post', + data: { + hash: hash + } + }).send(); + }); + updateMainData(); + } + }; + ['pauseAll', 'resumeAll'].each(function(item) { addClickEvent(item, function(e) { new Event(e).stop(); From 2c24c0bfbf48406b49b434587e1f0387d25648b8 Mon Sep 17 00:00:00 2001 From: buinsky Date: Fri, 22 Jan 2016 14:53:53 +0300 Subject: [PATCH 08/12] WebUI: Implement pause torrents by category --- src/webui/www/private/index.html | 1 + src/webui/www/public/filters.html | 3 +++ src/webui/www/public/scripts/mocha-init.js | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index 332572391..d0176af0d 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -130,6 +130,7 @@
  • QBT_TR(Remove category)QBT_TR QBT_TR(Remove category)QBT_TR
  • QBT_TR(Remove unused categories)QBT_TR QBT_TR(Remove unused categories)QBT_TR
  • QBT_TR(Resume torrents)QBT_TR QBT_TR(Resume torrents)QBT_TR
  • +
  • QBT_TR(Pause torrents)QBT_TR QBT_TR(Pause torrents)QBT_TR
  • diff --git a/src/webui/www/public/filters.html b/src/webui/www/public/filters.html index 08d50fff6..f7c922e8e 100644 --- a/src/webui/www/public/filters.html +++ b/src/webui/www/public/filters.html @@ -31,6 +31,9 @@ }, StartTorrentsByCategory : function (element, ref) { startTorrentsByCategoryFN(element.id); + }, + PauseTorrentsByCategory : function (element, ref) { + pauseTorrentsByCategoryFN(element.id); } }, offsets : { diff --git a/src/webui/www/public/scripts/mocha-init.js b/src/webui/www/public/scripts/mocha-init.js index 56e3fcdff..3ac1c6d67 100644 --- a/src/webui/www/public/scripts/mocha-init.js +++ b/src/webui/www/public/scripts/mocha-init.js @@ -401,6 +401,22 @@ initializeWindows = function() { } }; + pauseTorrentsByCategoryFN = function (categoryHash) { + var h = torrentsTable.getFilteredTorrentsHashes('all', categoryHash); + if (h.length) { + h.each(function (hash, index) { + new Request({ + url: 'command/pause', + method: 'post', + data: { + hash: hash + } + }).send(); + }); + updateMainData(); + } + }; + ['pauseAll', 'resumeAll'].each(function(item) { addClickEvent(item, function(e) { new Event(e).stop(); From ead592647aff5954fc719c91962b416ab75f8201 Mon Sep 17 00:00:00 2001 From: buinsky Date: Fri, 22 Jan 2016 15:13:35 +0300 Subject: [PATCH 09/12] WebUI: Implement delete torrents by category --- src/webui/www/private/index.html | 1 + src/webui/www/public/filters.html | 3 +++ src/webui/www/public/scripts/mocha-init.js | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index d0176af0d..2da2541ae 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -131,6 +131,7 @@
  • QBT_TR(Remove unused categories)QBT_TR QBT_TR(Remove unused categories)QBT_TR
  • QBT_TR(Resume torrents)QBT_TR QBT_TR(Resume torrents)QBT_TR
  • QBT_TR(Pause torrents)QBT_TR QBT_TR(Pause torrents)QBT_TR
  • +
  • QBT_TR(Delete torrents)QBT_TR QBT_TR(Delete torrents)QBT_TR
  • diff --git a/src/webui/www/public/filters.html b/src/webui/www/public/filters.html index f7c922e8e..b2e7eca2c 100644 --- a/src/webui/www/public/filters.html +++ b/src/webui/www/public/filters.html @@ -34,6 +34,9 @@ }, PauseTorrentsByCategory : function (element, ref) { pauseTorrentsByCategoryFN(element.id); + }, + DeleteTorrentsByCategory : function (element, ref) { + deleteTorrentsByCategoryFN(element.id); } }, offsets : { diff --git a/src/webui/www/public/scripts/mocha-init.js b/src/webui/www/public/scripts/mocha-init.js index 3ac1c6d67..c5e98f96b 100644 --- a/src/webui/www/public/scripts/mocha-init.js +++ b/src/webui/www/public/scripts/mocha-init.js @@ -417,6 +417,25 @@ initializeWindows = function() { } }; + deleteTorrentsByCategoryFN = function (categoryHash) { + var h = torrentsTable.getFilteredTorrentsHashes('all', categoryHash); + if (h.length) { + new MochaUI.Window({ + id: 'confirmDeletionPage', + title: "QBT_TR(Deletion confirmation)QBT_TR", + loadMethod: 'iframe', + contentURL: 'confirmdeletion.html?hashes=' + h.join("|"), + scrollbars: false, + resizable: false, + maximizable: false, + padding: 10, + width: 424, + height: 140 + }); + updateMainData(); + } + }; + ['pauseAll', 'resumeAll'].each(function(item) { addClickEvent(item, function(e) { new Event(e).stop(); From d265d2e1a04ee3914bc4a480938635db406a8736 Mon Sep 17 00:00:00 2001 From: buinsky Date: Fri, 22 Jan 2016 20:10:32 +0300 Subject: [PATCH 10/12] WebUI: Adjust context menu position --- src/webui/www/public/scripts/contextmenu.js | 68 ++++++++++++++++----- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/src/webui/www/public/scripts/contextmenu.js b/src/webui/www/public/scripts/contextmenu.js index cef6451e7..432483e00 100644 --- a/src/webui/www/public/scripts/contextmenu.js +++ b/src/webui/www/public/scripts/contextmenu.js @@ -53,6 +53,57 @@ var ContextMenu = new Class({ }); }, + adjustMenuPosition: function(e) { + this.updateMenuItems(); + + // draw the menu off-screen to know the menu dimentions + this.menu.setStyles({ + left: '-999em', + top: '-999em' + }); + + // position the menu + var xPos = e.page.x + this.options.offsets.x; + var yPos = e.page.y + this.options.offsets.y; + if (xPos + this.menu.offsetWidth > document.documentElement.clientWidth) + xPos -= this.menu.offsetWidth; + if (yPos + this.menu.offsetHeight > document.documentElement.clientHeight) + yPos -= this.menu.offsetHeight; + if (xPos < 0) + xPos = 0; + if (yPos < 0) + yPos = 0; + this.menu.setStyles({ + left: xPos, + top: yPos, + position: 'absolute', + 'z-index': '2000' + }); + + // position the sub-menu + var uls = this.menu.getElementsByTagName('ul'); + for (var i = 0; i < uls.length; i++) { + var ul = uls[i]; + var rectParent = ul.parentNode.getBoundingClientRect(); + var xPosOrigin = rectParent.left; + var yPosOrigin = rectParent.bottom; + var xPos = xPosOrigin + rectParent.width - 1; + var 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 -= (ul.offsetHeight - rectParent.height - 2); + if (xPos < 0) + xPos = 0; + if (yPos < 0) + yPos = 0; + ul.setStyles({ + 'margin-left': xPos - xPosOrigin, + 'margin-top': yPos - yPosOrigin + }); + } + }, + addTarget: function(t) { this.targets[this.targets.length] = t; t.addEvent(this.options.trigger, function(e) { @@ -64,13 +115,7 @@ var ContextMenu = new Class({ } //record this as the trigger this.options.element = $(t); - //position the menu - this.menu.setStyles({ - top: (e.page.y + this.options.offsets.y), - left: (e.page.x + this.options.offsets.x), - position: 'absolute', - 'z-index': '2000' - }); + this.adjustMenuPosition(e); //show the menu this.show(); } @@ -94,13 +139,7 @@ var ContextMenu = new Class({ } //record this as the trigger this.options.element = $(el); - //position the menu - this.menu.setStyles({ - top: (e.page.y + this.options.offsets.y), - left: (e.page.x + this.options.offsets.x), - position: 'absolute', - 'z-index': '2000' - }); + this.adjustMenuPosition(e); //show the menu this.show(); } @@ -131,7 +170,6 @@ var ContextMenu = new Class({ //show menu show: function (trigger) { - this.updateMenuItems(); this.fx.start(1); this.fireEvent('show'); this.shown = true; From fc077257d01f0ecf14401906bf5557611537f723 Mon Sep 17 00:00:00 2001 From: buinsky Date: Sat, 23 Jan 2016 12:14:05 +0300 Subject: [PATCH 11/12] WebUI: Don't show several context menus at the same time --- src/webui/www/public/scripts/contextmenu.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/webui/www/public/scripts/contextmenu.js b/src/webui/www/public/scripts/contextmenu.js index 432483e00..c8f83483e 100644 --- a/src/webui/www/public/scripts/contextmenu.js +++ b/src/webui/www/public/scripts/contextmenu.js @@ -1,3 +1,4 @@ +var lastShownContexMenu = null; var ContextMenu = new Class({ //implements Implements: [Options, Events], @@ -170,9 +171,12 @@ var ContextMenu = new Class({ //show menu show: function (trigger) { + if (lastShownContexMenu && lastShownContexMenu != this) + lastShownContexMenu.hide(); this.fx.start(1); this.fireEvent('show'); this.shown = true; + lastShownContexMenu = this; return this; }, From d63f9e751d680efb1ea2ea1e0b80b69bd3c4626d Mon Sep 17 00:00:00 2001 From: buinsky Date: Sun, 24 Jan 2016 12:19:16 +0300 Subject: [PATCH 12/12] WebUI: Select category on right click --- src/webui/www/public/filters.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/webui/www/public/filters.html b/src/webui/www/public/filters.html index b2e7eca2c..0c318fd44 100644 --- a/src/webui/www/public/filters.html +++ b/src/webui/www/public/filters.html @@ -42,6 +42,9 @@ offsets : { x : -15, y : 2 + }, + onShow: function () { + this.options.element.firstChild.click(); } });