3 * Copyright (c) 2008 Ishan Arora <ishan@qbittorrent.org>,
4 * Christophe Dumez <chris@qbittorrent.org>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 torrentsTable = new TorrentsTable();
26 torrentPeersTable = new TorrentPeersTable();
27 searchResultsTable = new SearchResultsTable();
28 searchPluginsTable = new SearchPluginsTable();
30 var updatePropertiesPanel = function() {};
32 var updateTorrentData = function() {};
33 var updateTrackersData = function() {};
34 var updateTorrentPeersData = function() {};
35 var updateWebSeedsData = function() {};
36 var updateTorrentFilesData = function() {};
38 var updateMainData = function() {};
39 var alternativeSpeedLimits = false;
40 var queueing_enabled = true;
41 var serverSyncMainDataInterval = 1500;
42 var customSyncMainDataInterval = null;
46 var CATEGORIES_ALL = 1;
47 var CATEGORIES_UNCATEGORIZED = 2;
49 var category_list = {};
51 var selected_category = CATEGORIES_ALL;
52 var setCategoryFilter = function() {};
54 var selected_filter = getLocalStorageItem('selected_filter', 'all');
55 var setFilter = function() {};
56 var toggleFilterDisplay = function() {};
58 var loadSelectedCategory = function() {
59 selected_category = getLocalStorageItem('selected_category', CATEGORIES_ALL);
61 loadSelectedCategory();
63 function genHash(string) {
65 for (var i = 0; i < string.length; ++i) {
66 var c = string.charCodeAt(i);
67 hash = (c + hash * 31) | 0;
72 function getSyncMainDataInterval() {
73 return customSyncMainDataInterval ? customSyncMainDataInterval : serverSyncMainDataInterval;
76 window.addEvent('load', function() {
78 var saveColumnSizes = function() {
79 var filters_width = $('Filters').getSize().x;
80 var properties_height_rel = $('propertiesPanel').getSize().y / Window.getSize().y;
81 localStorage.setItem('filters_width', filters_width);
82 localStorage.setItem('properties_height_rel', properties_height_rel);
85 window.addEvent('resize', function() {
86 // only save sizes if the columns are visible
87 if (!$("mainColumn").hasClass("invisible"))
88 saveColumnSizes.delay(200); // Resizing might takes some time.
91 /*MochaUI.Desktop = new MochaUI.Desktop();
92 MochaUI.Desktop.desktop.setStyles({
94 'visibility': 'visible'
96 MochaUI.Desktop.initialize();
98 var buildTransfersTab = function() {
99 var filt_w = localStorage.getItem('filters_width');
100 if ($defined(filt_w))
101 filt_w = filt_w.toInt();
107 onResize: saveColumnSizes,
109 resizeLimit: [1, 300]
118 var buildSearchTab = function() {
120 id: 'searchTabColumn',
126 $("searchTabColumn").addClass("invisible");
131 MochaUI.initializeTabs('mainWindowTabsList');
133 setCategoryFilter = function(hash) {
134 selected_category = hash;
135 localStorage.setItem('selected_category', selected_category);
136 highlightSelectedCategory();
137 if (typeof torrentsTable.tableBody != 'undefined')
141 setFilter = function(f) {
142 // Visually Select the right filter
143 $("all_filter").removeClass("selectedFilter");
144 $("downloading_filter").removeClass("selectedFilter");
145 $("seeding_filter").removeClass("selectedFilter");
146 $("completed_filter").removeClass("selectedFilter");
147 $("paused_filter").removeClass("selectedFilter");
148 $("resumed_filter").removeClass("selectedFilter");
149 $("active_filter").removeClass("selectedFilter");
150 $("inactive_filter").removeClass("selectedFilter");
151 $("errored_filter").removeClass("selectedFilter");
152 $(f + "_filter").addClass("selectedFilter");
154 localStorage.setItem('selected_filter', f);
156 if (typeof torrentsTable.tableBody != 'undefined')
160 toggleFilterDisplay = function(filter) {
161 var element = filter + "FilterList";
162 localStorage.setItem('filter_' + filter + "_collapsed", !$(element).hasClass("invisible"));
163 $(element).toggleClass("invisible")
164 var parent = $(element).getParent(".filterWrapper");
165 var toggleIcon = $(parent).getChildren(".filterTitle img");
167 toggleIcon[0].toggleClass("rotate");
181 contentURL: 'filters.html',
182 onContentLoaded: function() {
183 setFilter(selected_filter);
185 column: 'filtersColumn',
190 // Show Top Toolbar is enabled by default
191 var showTopToolbar = true;
192 if (localStorage.getItem('show_top_toolbar') !== null)
193 showTopToolbar = localStorage.getItem('show_top_toolbar') == "true";
194 if (!showTopToolbar) {
195 $('showTopToolbarLink').firstChild.style.opacity = '0';
196 $('mochaToolbar').addClass('invisible');
199 // Show Status Bar is enabled by default
200 var showStatusBar = true;
201 if (localStorage.getItem('show_status_bar') !== null)
202 showStatusBar = localStorage.getItem('show_status_bar') === "true";
203 if (!showStatusBar) {
204 $('showStatusBarLink').firstChild.style.opacity = '0';
205 $('desktopFooterWrapper').addClass('invisible');
208 var speedInTitle = localStorage.getItem('speed_in_browser_title_bar') == "true";
210 $('speedInBrowserTitleBarLink').firstChild.style.opacity = '0';
212 // After showing/hiding the toolbar + status bar
213 var showSearchEngine = localStorage.getItem('show_search_engine') === "true";
214 if (!showSearchEngine) {
215 // uncheck menu option
216 $('showSearchEngineLink').firstChild.style.opacity = '0';
218 $('mainWindowTabs').addClass('invisible');
221 // After Show Top Toolbar
222 MochaUI.Desktop.setDesktopSize();
224 var syncMainDataLastResponseId = 0;
225 var serverState = {};
227 var removeTorrentFromCategoryList = function(hash) {
228 if (hash === null || hash === "")
231 Object.each(category_list, function(category) {
232 if (Object.contains(category.torrents, hash)) {
234 category.torrents.splice(category.torrents.indexOf(hash), 1);
240 var addTorrentToCategoryList = function(torrent) {
241 var category = torrent['category'];
242 if (typeof category === 'undefined')
244 if (category.length === 0) { // Empty category
245 removeTorrentFromCategoryList(torrent['hash']);
248 var categoryHash = genHash(category);
249 if (category_list[categoryHash] === null) // This should not happen
250 category_list[categoryHash] = {
254 if (!Object.contains(category_list[categoryHash].torrents, torrent['hash'])) {
255 removeTorrentFromCategoryList(torrent['hash']);
256 category_list[categoryHash].torrents = category_list[categoryHash].torrents.combine([torrent['hash']]);
262 var updateFilter = function(filter, filterTitle) {
263 $(filter + '_filter').firstChild.childNodes[1].nodeValue = filterTitle.replace('%1', torrentsTable.getFilteredTorrentsNumber(filter, CATEGORIES_ALL));
266 var updateFiltersList = function() {
267 updateFilter('all', 'QBT_TR(All (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
268 updateFilter('downloading', 'QBT_TR(Downloading (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
269 updateFilter('seeding', 'QBT_TR(Seeding (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
270 updateFilter('completed', 'QBT_TR(Completed (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
271 updateFilter('resumed', 'QBT_TR(Resumed (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
272 updateFilter('paused', 'QBT_TR(Paused (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
273 updateFilter('active', 'QBT_TR(Active (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
274 updateFilter('inactive', 'QBT_TR(Inactive (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
275 updateFilter('errored', 'QBT_TR(Errored (%1))QBT_TR[CONTEXT=StatusFilterWidget]');
278 var updateCategoryList = function() {
279 var categoryList = $('categoryFilterList');
282 categoryList.empty();
284 var create_link = function(hash, text, count) {
285 var html = '<a href="#" onclick="setCategoryFilter(' + hash + ');return false;">'
286 + '<img src="images/qbt-theme/inode-directory.svg"/>'
287 + escapeHtml(text) + ' (' + count + ')' + '</a>';
288 var el = new Element('li', {
292 categoriesFilterContextMenu.addTarget(el);
296 var all = torrentsTable.getRowIds().length;
297 var uncategorized = 0;
298 Object.each(torrentsTable.rows, function(row) {
299 if (row['full_data'].category.length === 0)
302 categoryList.appendChild(create_link(CATEGORIES_ALL, 'QBT_TR(All)QBT_TR[CONTEXT=CategoryFilterModel]', all));
303 categoryList.appendChild(create_link(CATEGORIES_UNCATEGORIZED, 'QBT_TR(Uncategorized)QBT_TR[CONTEXT=CategoryFilterModel]', uncategorized));
305 var sortedCategories = [];
306 Object.each(category_list, function(category) {
307 sortedCategories.push(category.name);
309 sortedCategories.sort();
311 Object.each(sortedCategories, function(categoryName) {
312 var categoryHash = genHash(categoryName);
313 var categoryCount = category_list[categoryHash].torrents.length;
314 categoryList.appendChild(create_link(categoryHash, categoryName, categoryCount));
317 highlightSelectedCategory();
320 var highlightSelectedCategory = function() {
321 var categoryList = $('categoryFilterList');
324 var childrens = categoryList.childNodes;
325 for (var i in childrens) {
326 if (childrens[i].id == selected_category)
327 childrens[i].className = "selectedFilter";
329 childrens[i].className = "";
333 var syncMainDataTimer;
334 var syncMainData = function() {
335 var url = new URI('api/v2/sync/maindata');
336 url.setData('rid', syncMainDataLastResponseId);
341 onFailure: function() {
342 var errorDiv = $('error_div');
344 errorDiv.set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]');
345 clearTimeout(syncMainDataTimer);
346 syncMainDataTimer = syncMainData.delay(2000);
348 onSuccess: function(response) {
349 $('error_div').set('html', '');
351 clearTimeout(torrentsFilterInputTimer);
352 var torrentsTableSelectedRows;
353 var update_categories = false;
354 var full_update = (response['full_update'] === true);
356 torrentsTableSelectedRows = torrentsTable.selectedRowsIds();
357 torrentsTable.clear();
360 if (response['rid']) {
361 syncMainDataLastResponseId = response['rid'];
363 if (response['categories']) {
364 for (var key in response['categories']) {
365 var category = response['categories'][key];
366 var categoryHash = genHash(key);
367 if (category_list[categoryHash] !== undefined) {
368 // only the save path can change for existing categories
369 category_list[categoryHash].savePath = category.savePath;
372 category_list[categoryHash] = {
374 savePath: category.savePath,
379 update_categories = true;
381 if (response['categories_removed']) {
382 response['categories_removed'].each(function(category) {
383 var categoryHash = genHash(category);
384 delete category_list[categoryHash];
386 update_categories = true;
388 if (response['torrents']) {
389 var updateTorrentList = false;
390 for (var key in response['torrents']) {
391 response['torrents'][key]['hash'] = key;
392 response['torrents'][key]['rowId'] = key;
393 if (response['torrents'][key]['state'])
394 response['torrents'][key]['status'] = response['torrents'][key]['state'];
395 torrentsTable.updateRowData(response['torrents'][key]);
396 if (addTorrentToCategoryList(response['torrents'][key]))
397 update_categories = true;
398 if (response['torrents'][key]['name'])
399 updateTorrentList = true;
402 if (updateTorrentList)
403 setupCopyEventHandler();
405 if (response['torrents_removed'])
406 response['torrents_removed'].each(function(hash) {
407 torrentsTable.removeRow(hash);
408 removeTorrentFromCategoryList(hash);
409 update_categories = true; // Always to update All category
411 torrentsTable.updateTable(full_update);
412 torrentsTable.altRow();
413 if (response['server_state']) {
414 var tmp = response['server_state'];
416 serverState[k] = tmp[k];
417 processServerState();
420 if (update_categories) {
421 updateCategoryList();
422 torrentsTableContextMenu.updateCategoriesSubMenu(category_list);
426 // re-select previously selected rows
427 torrentsTable.reselectRows(torrentsTableSelectedRows);
429 clearTimeout(syncMainDataTimer);
430 syncMainDataTimer = syncMainData.delay(getSyncMainDataInterval());
435 updateMainData = function() {
436 torrentsTable.updateTable();
437 clearTimeout(syncMainDataTimer);
438 syncMainDataTimer = syncMainData.delay(100);
441 var processServerState = function() {
442 var transfer_info = friendlyUnit(serverState.dl_info_speed, true);
443 if (serverState.dl_rate_limit > 0)
444 transfer_info += " [" + friendlyUnit(serverState.dl_rate_limit, true) + "]";
445 transfer_info += " (" + friendlyUnit(serverState.dl_info_data, false) + ")";
446 $("DlInfos").set('html', transfer_info);
447 transfer_info = friendlyUnit(serverState.up_info_speed, true);
448 if (serverState.up_rate_limit > 0)
449 transfer_info += " [" + friendlyUnit(serverState.up_rate_limit, true) + "]";
450 transfer_info += " (" + friendlyUnit(serverState.up_info_data, false) + ")";
451 $("UpInfos").set('html', transfer_info);
453 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", "${VERSION}");
454 document.title += " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]";
457 document.title = "qBittorrent ${VERSION} QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]";
458 $('freeSpaceOnDisk').set('html', 'QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]'.replace("%1", friendlyUnit(serverState.free_space_on_disk)));
459 $('DHTNodes').set('html', 'QBT_TR(DHT: %1 nodes)QBT_TR[CONTEXT=StatusBar]'.replace("%1", serverState.dht_nodes));
462 if (document.getElementById("statisticspage")) {
463 $('AlltimeDL').set('html', friendlyUnit(serverState.alltime_dl, false));
464 $('AlltimeUL').set('html', friendlyUnit(serverState.alltime_ul, false));
465 $('TotalWastedSession').set('html', friendlyUnit(serverState.total_wasted_session, false));
466 $('GlobalRatio').set('html', serverState.global_ratio);
467 $('TotalPeerConnections').set('html', serverState.total_peer_connections);
468 $('ReadCacheHits').set('html', serverState.read_cache_hits + "%");
469 $('TotalBuffersSize').set('html', friendlyUnit(serverState.total_buffers_size, false));
470 $('WriteCacheOverload').set('html', serverState.write_cache_overload + "%");
471 $('ReadCacheOverload').set('html', serverState.read_cache_overload + "%");
472 $('QueuedIOJobs').set('html', serverState.queued_io_jobs);
473 $('AverageTimeInQueue').set('html', serverState.average_time_queue + " ms");
474 $('TotalQueuedSize').set('html', friendlyUnit(serverState.total_queued_size, false));
477 if (serverState.connection_status == "connected")
478 $('connectionStatus').src = 'images/skin/connected.svg';
479 else if (serverState.connection_status == "firewalled")
480 $('connectionStatus').src = 'images/skin/firewalled.svg';
482 $('connectionStatus').src = 'images/skin/disconnected.svg';
484 if (queueing_enabled != serverState.queueing) {
485 queueing_enabled = serverState.queueing;
486 torrentsTable.columns['priority'].force_hide = !queueing_enabled;
487 torrentsTable.updateColumn('priority');
488 if (queueing_enabled) {
489 $('topPrioItem').removeClass('invisible');
490 $('increasePrioItem').removeClass('invisible');
491 $('decreasePrioItem').removeClass('invisible');
492 $('bottomPrioItem').removeClass('invisible');
493 $('queueingButtons').removeClass('invisible');
494 $('queueingMenuItems').removeClass('invisible');
497 $('topPrioItem').addClass('invisible');
498 $('increasePrioItem').addClass('invisible');
499 $('decreasePrioItem').addClass('invisible');
500 $('bottomPrioItem').addClass('invisible');
501 $('queueingButtons').addClass('invisible');
502 $('queueingMenuItems').addClass('invisible');
506 if (alternativeSpeedLimits != serverState.use_alt_speed_limits) {
507 alternativeSpeedLimits = serverState.use_alt_speed_limits;
508 updateAltSpeedIcon(alternativeSpeedLimits);
511 serverSyncMainDataInterval = Math.max(serverState.refresh_interval, 500);
514 var updateAltSpeedIcon = function(enabled) {
516 $('alternativeSpeedLimits').src = "images/slow.png";
518 $('alternativeSpeedLimits').src = "images/slow_off.png";
521 $('alternativeSpeedLimits').addEvent('click', function() {
522 // Change icon immediately to give some feedback
523 updateAltSpeedIcon(!alternativeSpeedLimits);
526 url: 'api/v2/transfer/toggleSpeedLimitsMode',
528 onComplete: function() {
529 alternativeSpeedLimits = !alternativeSpeedLimits;
532 onFailure: function() {
533 // Restore icon in case of failure
534 updateAltSpeedIcon(alternativeSpeedLimits);
539 $('DlInfos').addEvent('click', globalDownloadLimitFN);
540 $('UpInfos').addEvent('click', globalUploadLimitFN);
542 $('showTopToolbarLink').addEvent('click', function(e) {
543 showTopToolbar = !showTopToolbar;
544 localStorage.setItem('show_top_toolbar', showTopToolbar.toString());
545 if (showTopToolbar) {
546 $('showTopToolbarLink').firstChild.style.opacity = '1';
547 $('mochaToolbar').removeClass('invisible');
550 $('showTopToolbarLink').firstChild.style.opacity = '0';
551 $('mochaToolbar').addClass('invisible');
553 MochaUI.Desktop.setDesktopSize();
556 $('showStatusBarLink').addEvent('click', function(e) {
557 showStatusBar = !showStatusBar;
558 localStorage.setItem('show_status_bar', showStatusBar.toString());
560 $('showStatusBarLink').firstChild.style.opacity = '1';
561 $('desktopFooterWrapper').removeClass('invisible');
564 $('showStatusBarLink').firstChild.style.opacity = '0';
565 $('desktopFooterWrapper').addClass('invisible');
567 MochaUI.Desktop.setDesktopSize();
570 $('speedInBrowserTitleBarLink').addEvent('click', function(e) {
571 speedInTitle = !speedInTitle;
572 localStorage.setItem('speed_in_browser_title_bar', speedInTitle.toString());
574 $('speedInBrowserTitleBarLink').firstChild.style.opacity = '1';
576 $('speedInBrowserTitleBarLink').firstChild.style.opacity = '0';
577 processServerState();
580 $('showSearchEngineLink').addEvent('click', function(e) {
581 showSearchEngine = !showSearchEngine;
582 localStorage.setItem('show_search_engine', showSearchEngine.toString());
583 if (showSearchEngine) {
584 $('showSearchEngineLink').firstChild.style.opacity = '1';
585 $('mainWindowTabs').removeClass('invisible');
587 addMainWindowTabsEventListener();
588 if (!MochaUI.Panels.instances.SearchPanel)
592 $('showSearchEngineLink').firstChild.style.opacity = '0';
593 $('mainWindowTabs').addClass('invisible');
594 $("transfersTabLink").click();
596 removeMainWindowTabsEventListener();
600 $('StatisticsLink').addEvent('click', StatisticsLinkFN);
604 var showTransfersTab = function() {
605 $("filtersColumn").removeClass("invisible");
606 $("filtersColumn_handle").removeClass("invisible");
607 $("mainColumn").removeClass("invisible");
609 customSyncMainDataInterval = null;
610 clearTimeout(syncMainDataTimer);
611 syncMainDataTimer = syncMainData.delay(100);
616 var hideTransfersTab = function() {
617 $("filtersColumn").addClass("invisible");
618 $("filtersColumn_handle").addClass("invisible");
619 $("mainColumn").addClass("invisible");
620 MochaUI.Desktop.resizePanels();
623 var showSearchTab = function() {
624 $("searchTabColumn").removeClass("invisible");
625 customSyncMainDataInterval = 30000;
629 var hideSearchTab = function() {
630 $("searchTabColumn").addClass("invisible");
631 MochaUI.Desktop.resizePanels();
634 var addMainWindowTabsEventListener = function() {
635 $('transfersTabLink').addEvent('click', showTransfersTab);
636 $('searchTabLink').addEvent('click', showSearchTab);
639 var removeMainWindowTabsEventListener = function() {
640 $('transfersTabLink').removeEvent('click', showTransfersTab);
641 $('searchTabLink').removeEvent('click', showSearchTab);
644 var addSearchPanel = function() {
656 contentURL : 'search.html',
658 column : 'searchTabColumn',
674 contentURL: 'transferlist.html',
675 onContentLoaded: function() {
678 column: 'mainColumn',
679 onResize: saveColumnSizes,
682 var prop_h = localStorage.getItem('properties_height_rel');
683 if ($defined(prop_h))
684 prop_h = prop_h.toFloat() * Window.getSize().y;
686 prop_h = Window.getSize().y / 2.0;
688 id: 'propertiesPanel',
697 contentURL: 'properties_content.html',
699 css: ['css/Tabs.css', 'css/dynamicTable.css'],
700 js: ['scripts/prop-general.js', 'scripts/prop-trackers.js', 'scripts/prop-webseeds.js', 'scripts/prop-files.js'],
702 tabsURL: 'properties.html',
703 tabsOnload: function() {
704 MochaUI.initializeTabs('propertiesTabs');
706 updatePropertiesPanel = function() {
707 if (!$('prop_general').hasClass('invisible'))
709 else if (!$('prop_trackers').hasClass('invisible'))
710 updateTrackersData();
711 else if (!$('prop_peers').hasClass('invisible'))
712 updateTorrentPeersData();
713 else if (!$('prop_webseeds').hasClass('invisible'))
714 updateWebSeedsData();
715 else if (!$('prop_files').hasClass('invisible'))
716 updateTorrentFilesData();
719 $('PropGeneralLink').addEvent('click', function(e) {
720 $('prop_general').removeClass("invisible");
721 $('prop_trackers').addClass("invisible");
722 $('prop_webseeds').addClass("invisible");
723 $('prop_files').addClass("invisible");
724 $('prop_peers').addClass("invisible");
725 updatePropertiesPanel();
726 localStorage.setItem('selected_tab', this.id);
729 $('PropTrackersLink').addEvent('click', function(e) {
730 $('prop_trackers').removeClass("invisible");
731 $('prop_general').addClass("invisible");
732 $('prop_webseeds').addClass("invisible");
733 $('prop_files').addClass("invisible");
734 $('prop_peers').addClass("invisible");
735 updatePropertiesPanel();
736 localStorage.setItem('selected_tab', this.id);
739 $('PropPeersLink').addEvent('click', function(e) {
740 $('prop_peers').removeClass("invisible");
741 $('prop_trackers').addClass("invisible");
742 $('prop_general').addClass("invisible");
743 $('prop_webseeds').addClass("invisible");
744 $('prop_files').addClass("invisible");
745 updatePropertiesPanel();
746 localStorage.setItem('selected_tab', this.id);
749 $('PropWebSeedsLink').addEvent('click', function(e) {
750 $('prop_webseeds').removeClass("invisible");
751 $('prop_general').addClass("invisible");
752 $('prop_trackers').addClass("invisible");
753 $('prop_files').addClass("invisible");
754 $('prop_peers').addClass("invisible");
755 updatePropertiesPanel();
756 localStorage.setItem('selected_tab', this.id);
759 $('PropFilesLink').addEvent('click', function(e) {
760 $('prop_files').removeClass("invisible");
761 $('prop_general').addClass("invisible");
762 $('prop_trackers').addClass("invisible");
763 $('prop_webseeds').addClass("invisible");
764 $('prop_peers').addClass("invisible");
765 updatePropertiesPanel();
766 localStorage.setItem('selected_tab', this.id);
769 $('propertiesPanel_collapseToggle').addEvent('click', function(e) {
770 updatePropertiesPanel();
773 column: 'mainColumn',
777 var prevTorrentsFilterValue;
778 var torrentsFilterInputTimer = null;
779 // listen for changes to torrentsFilterInput
780 $('torrentsFilterInput').addEvent('input', function() {
781 var value = $('torrentsFilterInput').get("value");
782 if (value !== prevTorrentsFilterValue) {
783 prevTorrentsFilterValue = value;
784 clearTimeout(torrentsFilterInputTimer);
785 torrentsFilterInputTimer = setTimeout(function() {
786 torrentsTable.updateTable(false);
791 if (showSearchEngine) {
792 addMainWindowTabsEventListener();
797 function closeWindows() {
801 function setupCopyEventHandler() {
803 clipboardEvent.destroy();
805 clipboardEvent = new ClipboardJS('.copyToClipboard', {
806 text: function(trigger) {
807 switch (trigger.id) {
810 case "CopyMagnetLink":
811 return copyMagnetLinkFN();
814 case "copyDescriptionPageUrl":
815 return copySearchTorrentUrl();
823 var keyboardEvents = new Keyboard({
824 defaultEventType: 'keydown',
826 'ctrl+a': function(event) {
827 torrentsTable.selectAll();
828 event.preventDefault();
830 'delete': function(event) {
832 event.preventDefault();
837 keyboardEvents.activate();
839 var loadTorrentPeersTimer;
840 var syncTorrentPeersLastResponseId = 0;
841 var show_flags = true;
842 var loadTorrentPeersData = function() {
843 if ($('prop_peers').hasClass('invisible')
844 || $('propertiesPanel_collapseToggle').hasClass('panel-expand')) {
845 syncTorrentPeersLastResponseId = 0;
846 torrentPeersTable.clear();
849 var current_hash = torrentsTable.getCurrentTorrentHash();
850 if (current_hash === "") {
851 syncTorrentPeersLastResponseId = 0;
852 torrentPeersTable.clear();
853 clearTimeout(loadTorrentPeersTimer);
854 loadTorrentPeersTimer = loadTorrentPeersData.delay(getSyncMainDataInterval());
857 var url = new URI('api/v2/sync/torrentPeers');
858 url.setData('rid', syncTorrentPeersLastResponseId);
859 url.setData('hash', current_hash);
864 onFailure: function() {
865 $('error_div').set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]');
866 clearTimeout(loadTorrentPeersTimer);
867 loadTorrentPeersTimer = loadTorrentPeersData.delay(5000);
869 onSuccess: function(response) {
870 $('error_div').set('html', '');
872 var full_update = (response['full_update'] === true);
874 torrentPeersTable.clear();
876 if (response['rid']) {
877 syncTorrentPeersLastResponseId = response['rid'];
879 if (response['peers']) {
880 for (var key in response['peers']) {
881 response['peers'][key]['rowId'] = key;
883 if (response['peers'][key]['client'])
884 response['peers'][key]['client'] = escapeHtml(response['peers'][key]['client']);
886 torrentPeersTable.updateRowData(response['peers'][key]);
889 if (response['peers_removed'])
890 response['peers_removed'].each(function(hash) {
891 torrentPeersTable.removeRow(hash);
893 torrentPeersTable.updateTable(full_update);
894 torrentPeersTable.altRow();
896 if (response['show_flags']) {
897 if (show_flags != response['show_flags']) {
898 show_flags = response['show_flags'];
899 torrentPeersTable.columns['country'].force_hide = !show_flags;
900 torrentPeersTable.updateColumn('country');
905 torrentPeersTable.clear();
907 clearTimeout(loadTorrentPeersTimer);
908 loadTorrentPeersTimer = loadTorrentPeersData.delay(getSyncMainDataInterval());
913 updateTorrentPeersData = function() {
914 clearTimeout(loadTorrentPeersTimer);
915 loadTorrentPeersData();