mirror of
https://github.com/transmission/transmission.git
synced 2025-12-23 03:48:41 +00:00
1. remove some of its unnecessary coupling to other classes 2. make more of its method names consistent with each other 3. make its field names consistent with the RPC spec 4. better grouping of methods by relevance 5. syntactical cleanup
2285 lines
72 KiB
JavaScript
2285 lines
72 KiB
JavaScript
/*
|
|
* Copyright © Dave Perrett, Malcolm Jarvis and Bruno Bierbaumer
|
|
* This code is licensed under the GPL version 2.
|
|
* For details, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
*
|
|
* Class Transmission
|
|
*/
|
|
|
|
function Transmission(){
|
|
this.initialize();
|
|
}
|
|
|
|
Transmission.prototype =
|
|
{
|
|
/*--------------------------------------------
|
|
*
|
|
* C O N S T R U C T O R
|
|
*
|
|
*--------------------------------------------*/
|
|
|
|
initialize: function()
|
|
{
|
|
// Initialize the helper classes
|
|
this.remote = new TransmissionRemote(this);
|
|
|
|
// Initialize the implementation fields
|
|
this._current_search = '';
|
|
this._torrents = { };
|
|
this._rows = [ ];
|
|
|
|
// Initialize the clutch preferences
|
|
Prefs.getClutchPrefs( this );
|
|
|
|
this.preloadImages();
|
|
|
|
// Set up user events
|
|
var tr = this;
|
|
$('#pause_all_link').bind('click', function(e){ tr.stopAllClicked(e); });
|
|
$('#resume_all_link').bind('click', function(e){ tr.startAllClicked(e); });
|
|
$('#pause_selected_link').bind('click', function(e){ tr.stopSelectedClicked(e); } );
|
|
$('#resume_selected_link').bind('click', function(e){ tr.startSelectedClicked(e); });
|
|
$('#remove_link').bind('click', function(e){ tr.removeClicked(e); });
|
|
$('#filter_all_link').parent().bind('click', function(e){ tr.showAllClicked(e); });
|
|
$('#filter_active_link').parent().bind('click', function(e){ tr.showActiveClicked(e); });
|
|
$('#filter_downloading_link').parent().bind('click', function(e){ tr.showDownloadingClicked(e); });
|
|
$('#filter_seeding_link').parent().bind('click', function(e){ tr.showSeedingClicked(e); });
|
|
$('#filter_paused_link').parent().bind('click', function(e){ tr.showPausedClicked(e); });
|
|
$('#filter_finished_link').parent().bind('click', function(e){ tr.showFinishedClicked(e); });
|
|
$('#prefs_save_button').bind('click', function(e) { tr.savePrefsClicked(e); return false;});
|
|
$('#prefs_cancel_button').bind('click', function(e){ tr.cancelPrefsClicked(e); return false; });
|
|
$('#block_update_button').bind('click', function(e){ tr.blocklistUpdateClicked(e); return false; });
|
|
$('#stats_close_button').bind('click', function(e){ tr.closeStatsClicked(e); return false; });
|
|
$('.inspector_tab').bind('click', function(e){ tr.inspectorTabClicked(e, this); });
|
|
$('#files_select_all').live('click', function(e){ tr.filesSelectAllClicked(e, this); });
|
|
$('#files_deselect_all').live('click', function(e){ tr.filesDeselectAllClicked(e, this); });
|
|
$('#open_link').bind('click', function(e){ tr.openTorrentClicked(e); });
|
|
$('#upload_confirm_button').bind('click', function(e){ tr.confirmUploadClicked(e); return false;});
|
|
$('#upload_cancel_button').bind('click', function(e){ tr.cancelUploadClicked(e); return false; });
|
|
$('#turtle_button').bind('click', function(e){ tr.toggleTurtleClicked(e); return false; });
|
|
$('#prefs_tab_general_tab').click(function(e){ changeTab(this, 'prefs_tab_general') });
|
|
$('#prefs_tab_speed_tab').click(function(e){ changeTab(this, 'prefs_tab_speed') });
|
|
$('#prefs_tab_peers_tab').click(function(e){ changeTab(this, 'prefs_tab_peers') });
|
|
$('#prefs_tab_network_tab').click(function(e){ changeTab(this, 'prefs_tab_network');});
|
|
$('#torrent_upload_form').submit(function(){ $('#upload_confirm_button').click(); return false; });
|
|
$('#torrent_container').bind('dragover', function(e){ return tr.dragenter(e); });
|
|
$('#torrent_container').bind('dragenter', function(e){ return tr.dragenter(e); });
|
|
$('#torrent_container').bind('drop', function(e){ return tr.drop(e); });
|
|
// tell jQuery to copy the dataTransfer property from events over if it exists
|
|
jQuery.event.props.push("dataTransfer");
|
|
|
|
$('#torrent_upload_form').submit(function(){ $('#upload_confirm_button').click(); return false; });
|
|
|
|
if (iPhone) {
|
|
$('#inspector_close').bind('click', function(e){ tr.hideInspector(); });
|
|
$('#preferences_link').bind('click', function(e){ tr.releaseClutchPreferencesButton(e); });
|
|
} else {
|
|
$(document).bind('keydown', function(e){ tr.keyDown(e); });
|
|
$('#torrent_container').bind('click', function(e){ tr.deselectAll( true ); });
|
|
$('#filter_toggle_link').bind('click', function(e){ tr.toggleFilterClicked(e); });
|
|
$('#inspector_link').bind('click', function(e){ tr.toggleInspectorClicked(e); });
|
|
|
|
this.setupSearchBox();
|
|
this.createContextMenu();
|
|
this.createSettingsMenu();
|
|
}
|
|
this.initTurtleDropDowns();
|
|
|
|
this._torrent_list = $('#torrent_list')[0];
|
|
this._inspector_file_list = $('#inspector_file_list')[0];
|
|
this._inspector_peers_list = $('#inspector_peers_list')[0];
|
|
this._inspector_trackers_list = $('#inspector_trackers_list')[0];
|
|
this._inspector_tab_files = $('#inspector_tab_files')[0];
|
|
this._toolbar_buttons = $('#torrent_global_menu ul li');
|
|
this._toolbar_pause_button = $('li#pause_selected')[0];
|
|
this._toolbar_pause_all_button = $('li#pause_all')[0];
|
|
this._toolbar_start_button = $('li#resume_selected')[0];
|
|
this._toolbar_start_all_button = $('li#resume_all')[0];
|
|
this._toolbar_remove_button = $('li#remove')[0];
|
|
this._context_pause_button = $('li#context_pause_selected')[0];
|
|
this._context_start_button = $('li#context_resume_selected')[0];
|
|
this._context_start_now_button = $('li#context_resume_now_selected')[0];
|
|
this._context_move_top = $('li#context_move_top')[0];
|
|
this._context_move_up = $('li#context_move_up')[0];
|
|
this._context_move_down = $('li#context_move_down')[0];
|
|
this._context_move_bottom = $('li#context_move_bottom')[0];
|
|
|
|
var ti = '#torrent_inspector_';
|
|
this._inspector = { };
|
|
this._inspector._info_tab = { };
|
|
this._inspector._info_tab.availability = $(ti+'availability')[0];
|
|
this._inspector._info_tab.comment = $(ti+'comment')[0];
|
|
this._inspector._info_tab.creator_date = $(ti+'creator_date')[0];
|
|
this._inspector._info_tab.creator = $(ti+'creator')[0];
|
|
this._inspector._info_tab.download_dir = $(ti+'download_dir')[0];
|
|
this._inspector._info_tab.downloaded = $(ti+'downloaded')[0];
|
|
this._inspector._info_tab.download_from = $(ti+'download_from')[0];
|
|
this._inspector._info_tab.download_speed = $(ti+'download_speed')[0];
|
|
this._inspector._info_tab.error = $(ti+'error')[0];
|
|
this._inspector._info_tab.hash = $(ti+'hash')[0];
|
|
this._inspector._info_tab.have = $(ti+'have')[0];
|
|
this._inspector._info_tab.name = $(ti+'name')[0];
|
|
this._inspector._info_tab.progress = $(ti+'progress')[0];
|
|
this._inspector._info_tab.ratio = $(ti+'ratio')[0];
|
|
this._inspector._info_tab.secure = $(ti+'secure')[0];
|
|
this._inspector._info_tab.size = $(ti+'size')[0];
|
|
this._inspector._info_tab.state = $(ti+'state')[0];
|
|
this._inspector._info_tab.pieces = $(ti+'pieces')[0];
|
|
this._inspector._info_tab.uploaded = $(ti+'uploaded')[0];
|
|
this._inspector._info_tab.upload_speed = $(ti+'upload_speed')[0];
|
|
this._inspector._info_tab.upload_to = $(ti+'upload_to')[0];
|
|
|
|
// Setup the preference box
|
|
this.setupPrefConstraints();
|
|
|
|
// Setup the prefs gui
|
|
this.initializeSettings( );
|
|
|
|
// Get preferences & torrents from the daemon
|
|
var tr = this;
|
|
var async = false;
|
|
this.loadDaemonPrefs( async );
|
|
this.loadDaemonStats( async );
|
|
this.initializeAllTorrents();
|
|
|
|
this.togglePeriodicRefresh( true );
|
|
this.togglePeriodicSessionRefresh( true );
|
|
},
|
|
|
|
loadDaemonPrefs: function( async ){
|
|
var tr = this;
|
|
this.remote.loadDaemonPrefs( function(data){
|
|
var o = data.arguments;
|
|
Prefs.getClutchPrefs( o );
|
|
tr.updatePrefs( o );
|
|
}, async );
|
|
},
|
|
|
|
loadDaemonStats: function( async ){
|
|
var tr = this;
|
|
this.remote.loadDaemonStats( function(data){
|
|
var o = data.arguments;
|
|
tr.updateStats( o );
|
|
}, async );
|
|
},
|
|
checkPort: function( async ){
|
|
$('#port_test').text('checking ...')
|
|
var tr = this;
|
|
this.remote.checkPort( function(data){
|
|
var o = data.arguments;
|
|
tr.updatePortStatus( o );
|
|
}, async );
|
|
},
|
|
|
|
preloadImages: function() {
|
|
if (iPhone) {
|
|
this.loadImages(
|
|
'images/buttons/info_general.png',
|
|
'images/buttons/info_activity.png',
|
|
'images/buttons/info_files.png',
|
|
'images/buttons/toolbar_buttons.png',
|
|
'images/graphics/filter_bar.png',
|
|
'images/graphics/iphone_chrome.png',
|
|
'images/graphics/logo.png'
|
|
);
|
|
} else {
|
|
this.loadImages(
|
|
'images/buttons/info_general.png',
|
|
'images/buttons/info_activity.png',
|
|
'images/buttons/info_files.png',
|
|
'images/buttons/tab_backgrounds.png',
|
|
'images/buttons/toolbar_buttons.png',
|
|
'images/buttons/torrent_buttons.png',
|
|
'images/buttons/file_wanted_buttons.png',
|
|
'images/buttons/file_priority_buttons.png',
|
|
'images/graphics/chrome.png',
|
|
'images/graphics/filter_bar.png',
|
|
'images/graphics/logo.png',
|
|
'images/graphics/transfer_arrows.png',
|
|
'images/progress/progress.png'
|
|
);
|
|
}
|
|
},
|
|
loadImages: function() {
|
|
for( var i=0, row; row=arguments[i]; ++i )
|
|
jQuery("<img>").attr("src", row);
|
|
},
|
|
|
|
/*
|
|
* Set up the preference validation
|
|
*/
|
|
setupPrefConstraints: function() {
|
|
// only allow integers for speed limit & port options
|
|
$('div.preference input[@type=text]:not(#download_location,#block_url)').blur( function() {
|
|
this.value = this.value.replace(/[^0-9]/gi, '');
|
|
if (this.value == '') {
|
|
if ($(this).is('#refresh_rate')) {
|
|
this.value = 5;
|
|
} else {
|
|
this.value = 0;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
setCompactMode: function( is_compact )
|
|
{
|
|
this.torrentRenderer = is_compact ? new TorrentRendererCompact( )
|
|
: new TorrentRendererFull( );
|
|
$('ul.torrent_list li').remove();
|
|
this._rows = [];
|
|
this.refilter();
|
|
},
|
|
|
|
/*
|
|
* Load the clutch prefs and init the GUI according to those prefs
|
|
*/
|
|
initializeSettings: function( )
|
|
{
|
|
Prefs.getClutchPrefs( this );
|
|
|
|
// iPhone conditions in the section allow us to not
|
|
// include transmenu js to save some bandwidth; if we
|
|
// start using prefs on iPhone we need to weed
|
|
// transmenu refs out of that too.
|
|
|
|
$('#filter_' + this[Prefs._FilterMode] + '_link').parent().addClass('selected');
|
|
|
|
if (!iPhone) $('#sort_by_' + this[Prefs._SortMethod] ).selectMenuItem();
|
|
|
|
if (!iPhone && ( this[Prefs._SortDirection] == Prefs._SortDescending ) )
|
|
$('#reverse_sort_order').selectMenuItem();
|
|
|
|
if( this[Prefs._ShowFilter] )
|
|
this.showFilter( );
|
|
|
|
if( !iPhone && this[Prefs._ShowInspector] )
|
|
this.showInspector( );
|
|
|
|
if( !iPhone && this[Prefs._CompactDisplayState] )
|
|
$('#compact_view').selectMenuItem();
|
|
|
|
this.setCompactMode( this[Prefs._CompactDisplayState] );
|
|
},
|
|
|
|
/*
|
|
* Set up the search box
|
|
*/
|
|
setupSearchBox: function()
|
|
{
|
|
var tr = this;
|
|
var search_box = $('#torrent_search');
|
|
search_box.bind('keyup click', {transmission: this}, function(event) {
|
|
tr.setSearch(this.value);
|
|
});
|
|
if (!$.browser.safari)
|
|
{
|
|
search_box.addClass('blur');
|
|
search_box[0].value = 'Filter';
|
|
search_box.bind('blur', {transmission: this}, function(event) {
|
|
if (this.value == '') {
|
|
$(this).addClass('blur');
|
|
this.value = 'Filter';
|
|
tr.setSearch(null);
|
|
}
|
|
}).bind('focus', {}, function(event) {
|
|
if ($(this).is('.blur')) {
|
|
this.value = '';
|
|
$(this).removeClass('blur');
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
contextStopSelected: function( ) {
|
|
this.stopSelectedTorrents( );
|
|
},
|
|
contextStartSelected: function( ) {
|
|
this.startSelectedTorrents( false );
|
|
},
|
|
contextStartNowSelected: function( ) {
|
|
this.startSelectedTorrents( true );
|
|
},
|
|
contextRemoveSelected: function( ) {
|
|
this.removeSelectedTorrents( );
|
|
},
|
|
contextRemoveDataSelected: function( ) {
|
|
this.removeSelectedTorrentsAndData( );
|
|
},
|
|
contextVerifySelected: function( ) {
|
|
this.verifySelectedTorrents( );
|
|
},
|
|
contextReannounceSelected: function( ) {
|
|
this.reannounceSelectedTorrents( );
|
|
},
|
|
contextToggleInspector: function( ) {
|
|
this.toggleInspector( );
|
|
},
|
|
contextSelectAll: function( ) {
|
|
this.selectAll( true );
|
|
},
|
|
contextDeselectAll: function( ) {
|
|
this.deselectAll( true );
|
|
},
|
|
|
|
// Queue
|
|
|
|
contextMoveUp: function( ) {
|
|
this.moveUp( );
|
|
},
|
|
contextMoveDown: function( ) {
|
|
this.moveDown( );
|
|
},
|
|
contextMoveTop: function( ) {
|
|
this.moveTop( );
|
|
},
|
|
contextMoveBottom: function( ) {
|
|
this.moveBottom( );
|
|
},
|
|
|
|
/*
|
|
* Create the torrent right-click menu
|
|
*/
|
|
createContextMenu: function() {
|
|
var tr = this;
|
|
var bindings = {
|
|
context_pause_selected: function(e){ tr.contextStopSelected(e); },
|
|
context_resume_selected: function(e){ tr.contextStartSelected(e); },
|
|
context_resume_now_selected: function(e){ tr.contextStartNowSelected(e); },
|
|
context_remove: function(e){ tr.contextRemoveSelected(e); },
|
|
context_removedata: function(e){ tr.contextRemoveDataSelected(e); },
|
|
context_verify: function(e){ tr.contextVerifySelected(e); },
|
|
context_reannounce: function(e){ tr.contextReannounceSelected(e); },
|
|
context_toggle_inspector: function(e){ tr.contextToggleInspector(e); },
|
|
context_select_all: function(e){ tr.contextSelectAll(e); },
|
|
context_deselect_all: function(e){ tr.contextDeselectAll(e); },
|
|
context_move_top: function(e){ tr.contextMoveTop(e); },
|
|
context_move_up: function(e){ tr.contextMoveUp(e); },
|
|
context_move_down: function(e){ tr.contextMoveDown(e); },
|
|
context_move_bottom: function(e){ tr.contextMoveBottom(e); }
|
|
};
|
|
|
|
// Setup the context menu
|
|
$('ul#torrent_list').contextMenu('torrent_context_menu', {
|
|
bindings: bindings,
|
|
menuStyle: Menu.context.menu_style,
|
|
itemStyle: Menu.context.item_style,
|
|
itemHoverStyle: Menu.context.item_hover_style,
|
|
itemDisabledStyle: Menu.context.item_disabled_style,
|
|
shadow: false,
|
|
boundingElement: $('div#torrent_container'),
|
|
boundingRightPad: 20,
|
|
boundingBottomPad: 5,
|
|
onContextMenu: function(e) {
|
|
var closest_row = $(e.target).closest('.torrent')[0];
|
|
for( var i=0, row; row = tr._rows[i]; ++i ) {
|
|
if( row.getElement() === closest_row ) {
|
|
tr.setSelectedRow( row );
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
},
|
|
|
|
/*
|
|
* Create the footer settings menu
|
|
*/
|
|
createSettingsMenu: function() {
|
|
var tr = this;
|
|
$('#settings_menu').transMenu({
|
|
selected_char: '✔',
|
|
direction: 'up',
|
|
onClick: function(e){ return tr.processSettingsMenuEvent(e); }
|
|
});
|
|
|
|
$('#unlimited_download_rate').selectMenuItem();
|
|
$('#unlimited_upload_rate').selectMenuItem();
|
|
},
|
|
|
|
|
|
initTurtleDropDowns: function() {
|
|
var i, out, hour, mins, start, end, value, content;
|
|
// Build the list of times
|
|
out = "";
|
|
start = $('#turtle_start_time')[0];
|
|
end = $('#turtle_end_time')[0];
|
|
for (i = 0; i < 24 * 4; i++) {
|
|
hour = parseInt(i / 4);
|
|
mins = ((i % 4) * 15);
|
|
|
|
value = (i * 15);
|
|
content = hour + ":" + (mins == 0 ? "00" : mins);
|
|
start.options[i] = new Option(content, value);
|
|
end.options[i] = new Option(content, value);
|
|
}
|
|
},
|
|
|
|
/*--------------------------------------------
|
|
*
|
|
* U T I L I T I E S
|
|
*
|
|
*--------------------------------------------*/
|
|
|
|
getAllTorrents: function()
|
|
{
|
|
var torrents = [];
|
|
for(var key in this._torrents)
|
|
torrents.push(this._torrents[key]);
|
|
return torrents;
|
|
},
|
|
|
|
getVisibleTorrents: function()
|
|
{
|
|
var torrents = [ ];
|
|
for( var i=0, row; row=this._rows[i]; ++i )
|
|
if( row.isVisible( ) )
|
|
torrents.push( row.getTorrent( ) );
|
|
return torrents;
|
|
},
|
|
|
|
getSelectedRows: function()
|
|
{
|
|
var s = [ ];
|
|
|
|
for( var i=0, row; row=this._rows[i]; ++i )
|
|
if( row.isSelected( ) )
|
|
s.push( row );
|
|
|
|
return s;
|
|
},
|
|
|
|
getSelectedTorrents: function()
|
|
{
|
|
var s = this.getSelectedRows( );
|
|
|
|
for( var i=0, row; row=s[i]; ++i )
|
|
s[i] = s[i].getTorrent();
|
|
|
|
return s;
|
|
},
|
|
|
|
getDeselectedTorrents: function()
|
|
{
|
|
var ret = { };
|
|
for( var key in this._torrents )
|
|
ret[ key ] = this._torrents[key];
|
|
var sel = this.getSelectedTorrents( );
|
|
for( var i=0, tor; tor=sel[i]; ++i )
|
|
delete ret[ tor.getId() ];
|
|
return ret;
|
|
},
|
|
|
|
getVisibleRows: function()
|
|
{
|
|
var rows = [ ];
|
|
for( var i=0, row; row=this._rows[i]; ++i )
|
|
if( row.isVisible( ) )
|
|
rows.push( row );
|
|
return rows;
|
|
},
|
|
|
|
getRowIndex: function( rows, row )
|
|
{
|
|
for( var i=0, r; r=rows[i]; ++i )
|
|
if( r === row )
|
|
return i;
|
|
return null;
|
|
},
|
|
|
|
setPref: function( key, val )
|
|
{
|
|
this[key] = val;
|
|
Prefs.setValue( key, val );
|
|
},
|
|
|
|
scrollToElement: function( e )
|
|
{
|
|
if( iPhone )
|
|
return;
|
|
|
|
var container = $('#torrent_container');
|
|
var scrollTop = container.scrollTop( );
|
|
var innerHeight = container.innerHeight( );
|
|
|
|
var offsetTop = e.offsetTop;
|
|
var offsetHeight = $(e).outerHeight( );
|
|
|
|
if( offsetTop < scrollTop )
|
|
container.scrollTop( offsetTop );
|
|
else if( innerHeight + scrollTop < offsetTop + offsetHeight )
|
|
container.scrollTop( offsetTop + offsetHeight - innerHeight );
|
|
},
|
|
|
|
seedRatioLimit: function(){
|
|
if(this._prefs && this._prefs['seedRatioLimited'])
|
|
return this._prefs['seedRatioLimit'];
|
|
else
|
|
return -1;
|
|
},
|
|
|
|
/*--------------------------------------------
|
|
*
|
|
* S E L E C T I O N
|
|
*
|
|
*--------------------------------------------*/
|
|
|
|
setSelectedRow: function( row ) {
|
|
var rows = this.getSelectedRows( );
|
|
for( var i=0, r; r=rows[i]; ++i )
|
|
this.deselectRow( r );
|
|
this.selectRow( row );
|
|
},
|
|
|
|
selectRow: function( row ) {
|
|
row.setSelected( true );
|
|
this.callSelectionChangedSoon();
|
|
},
|
|
|
|
deselectRow: function( row ) {
|
|
row.setSelected( false );
|
|
this.callSelectionChangedSoon();
|
|
},
|
|
|
|
selectAll: function( ) {
|
|
var tr = this;
|
|
for( var i=0, row; row=tr._rows[i]; ++i )
|
|
tr.selectRow( row );
|
|
this.callSelectionChangedSoon();
|
|
},
|
|
deselectAll: function( ) {
|
|
for( var i=0, row; row=this._rows[i]; ++i )
|
|
this.deselectRow( row );
|
|
this.callSelectionChangedSoon();
|
|
this._last_row_clicked = null;
|
|
},
|
|
|
|
/*
|
|
* Select a range from this torrent to the last clicked torrent
|
|
*/
|
|
selectRange: function( row )
|
|
{
|
|
if( this._last_row_clicked === null )
|
|
{
|
|
this.selectRow( row );
|
|
}
|
|
else // select the range between the prevous & current
|
|
{
|
|
var rows = this.getVisibleRows( );
|
|
var i = this.getRowIndex( rows, this._last_row_clicked );
|
|
var end = this.getRowIndex( rows, row );
|
|
var step = i < end ? 1 : -1;
|
|
for( ; i!=end; i+=step )
|
|
this.selectRow( this._rows[i] );
|
|
this.selectRow( this._rows[i] );
|
|
}
|
|
|
|
this.callSelectionChangedSoon( );
|
|
},
|
|
|
|
selectionChanged: function()
|
|
{
|
|
this.updateButtonStates();
|
|
this.updateInspector();
|
|
this.updateSelectedData();
|
|
this.selectionChangedTimer = null;
|
|
},
|
|
|
|
callSelectionChangedSoon: function()
|
|
{
|
|
if( this.selectionChangedTimer === null )
|
|
this.selectionChangedTimer = setTimeout(function(o) { o.selectionChanged(); }, 200, this);
|
|
},
|
|
|
|
/*--------------------------------------------
|
|
*
|
|
* E V E N T F U N C T I O N S
|
|
*
|
|
*--------------------------------------------*/
|
|
|
|
/*
|
|
* Process key event
|
|
*/
|
|
keyDown: function(event)
|
|
{
|
|
var tr = this;
|
|
var sel = tr.getSelectedRows( );
|
|
var rows = tr.getVisibleRows( );
|
|
var i = -1;
|
|
|
|
if( event.keyCode == 40 ) // down arrow
|
|
{
|
|
var r = sel.length ? sel[sel.length-1] : null;
|
|
i = r==null ? null : tr.getRowIndex(rows,r)+1;
|
|
if( i == rows.length || i == null )
|
|
i = 0;
|
|
}
|
|
else if( event.keyCode == 38 ) // up arrow
|
|
{
|
|
var r = sel.length ? sel[0] : null
|
|
i = r==null ? null : tr.getRowIndex(rows,r)-1;
|
|
if( i == -1 || i == null )
|
|
i = rows.length - 1;
|
|
}
|
|
|
|
if( 0<=i && i<rows.length ) {
|
|
tr.deselectAll( );
|
|
tr.selectRow( tr._rows[i], true );
|
|
tr.scrollToElement( tr._rows[i] );
|
|
}
|
|
},
|
|
|
|
isButtonEnabled: function(e) {
|
|
var p = e.target ? e.target.parentNode : e.srcElement.parentNode;
|
|
return p.className!='disabled' && p.parentNode.className!='disabled';
|
|
},
|
|
|
|
stopAllClicked: function( event ) {
|
|
var tr = this;
|
|
if( tr.isButtonEnabled( event ) ) {
|
|
tr.stopAllTorrents( );
|
|
tr.hideiPhoneAddressbar( );
|
|
}
|
|
},
|
|
|
|
stopSelectedClicked: function( event ) {
|
|
var tr = this;
|
|
if( tr.isButtonEnabled( event ) ) {
|
|
tr.stopSelectedTorrents( );
|
|
tr.hideiPhoneAddressbar( );
|
|
}
|
|
},
|
|
|
|
startAllClicked: function( event ) {
|
|
var tr = this;
|
|
if( tr.isButtonEnabled( event ) ) {
|
|
tr.startAllTorrents( );
|
|
tr.hideiPhoneAddressbar( );
|
|
}
|
|
},
|
|
|
|
startSelectedClicked: function( event ) {
|
|
var tr = this;
|
|
if( tr.isButtonEnabled( event ) ) {
|
|
tr.startSelectedTorrents( false );
|
|
tr.hideiPhoneAddressbar( );
|
|
}
|
|
},
|
|
|
|
openTorrentClicked: function( event ) {
|
|
var tr = this;
|
|
if( tr.isButtonEnabled( event ) ) {
|
|
$('body').addClass('open_showing');
|
|
tr.uploadTorrentFile( );
|
|
}
|
|
tr.updateButtonStates();
|
|
},
|
|
|
|
dragenter: function( event ) {
|
|
if( event.dataTransfer && event.dataTransfer.types ) {
|
|
var types = ["text/uri-list", "text/plain"];
|
|
for( var i = 0; i < types.length; ++i ) {
|
|
if( event.dataTransfer.types.contains(types[i]) ) {
|
|
// it would be better to actually look at the links here;
|
|
// sadly, (at least with Firefox,) trying would throw.
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
event.dropEffect = "copy";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else if (event.dataTransfer) {
|
|
event.dataTransfer.dropEffect = "none";
|
|
}
|
|
return true;
|
|
},
|
|
|
|
drop: function( event ) {
|
|
if( !event.dataTransfer || !event.dataTransfer.types ) {
|
|
return true;
|
|
}
|
|
event.preventDefault();
|
|
var uris = null;
|
|
var types = ["text/uri-list", "text/plain"];
|
|
for( var i = 0; i < types.length; ++i ) {
|
|
if( event.dataTransfer.types.contains(types[i]) ) {
|
|
uris = event.dataTransfer.getData( types[i] ).split("\n");
|
|
break;
|
|
}
|
|
}
|
|
var paused = $('#prefs_form #auto_start')[0].checked;
|
|
for( i = 0; i < uris.length; ++i ) {
|
|
var uri = uris[i];
|
|
if( /^#/.test(uri) ) {
|
|
// lines which start with "#" are comments
|
|
continue;
|
|
}
|
|
if( /^[a-z-]+:/i.test(uri) ) {
|
|
// close enough to a url
|
|
this.remote.addTorrentByUrl( uri, paused );
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
hideUploadDialog: function( ) {
|
|
$('body.open_showing').removeClass('open_showing');
|
|
if (!iPhone && Safari3) {
|
|
$('div#upload_container div.dialog_window').css('top', '-205px');
|
|
setTimeout("$('#upload_container').hide();",500);
|
|
} else {
|
|
$('#upload_container').hide();
|
|
}
|
|
this.updateButtonStates();
|
|
},
|
|
|
|
cancelUploadClicked: function(event) {
|
|
this.hideUploadDialog( );
|
|
},
|
|
|
|
confirmUploadClicked: function(event) {
|
|
this.uploadTorrentFile( true );
|
|
this.hideUploadDialog( );
|
|
},
|
|
|
|
cancelPrefsClicked: function(event) {
|
|
this.hidePrefsDialog( );
|
|
},
|
|
|
|
savePrefsClicked: function(event)
|
|
{
|
|
|
|
// handle the clutch prefs locally
|
|
var tr = this;
|
|
var rate = parseInt( $('#prefs_form #refresh_rate')[0].value );
|
|
if( rate != tr[Prefs._RefreshRate] ) {
|
|
tr.setPref( Prefs._RefreshRate, rate );
|
|
tr.togglePeriodicRefresh( false );
|
|
tr.togglePeriodicRefresh( true );
|
|
}
|
|
|
|
var up_bytes = parseInt( $('#prefs_form #upload_rate' )[0].value );
|
|
var dn_bytes = parseInt( $('#prefs_form #download_rate')[0].value );
|
|
var turtle_up_bytes = parseInt( $('#prefs_form #turtle_upload_rate' )[0].value );
|
|
var turtle_dn_bytes = parseInt( $('#prefs_form #turtle_download_rate')[0].value );
|
|
|
|
// pass the new prefs upstream to the RPC server
|
|
var o = { };
|
|
o[RPC._StartAddedTorrent] = $('#prefs_form #auto_start')[0].checked;
|
|
o[RPC._PeerPort] = parseInt( $('#prefs_form #port')[0].value );
|
|
o[RPC._UpSpeedLimit] = up_bytes;
|
|
o[RPC._DownSpeedLimit] = dn_bytes;
|
|
o[RPC._DownloadDir] = $('#prefs_form #download_location')[0].value;
|
|
o[RPC._UpSpeedLimited] = $('#prefs_form #limit_upload' )[0].checked;
|
|
o[RPC._DownSpeedLimited] = $('#prefs_form #limit_download')[0].checked;
|
|
o[RPC._Encryption] = $('#prefs_form #encryption')[0].checked
|
|
? RPC._EncryptionRequired
|
|
: RPC._EncryptionPreferred;
|
|
o[RPC._TurtleDownSpeedLimit] = turtle_dn_bytes;
|
|
o[RPC._TurtleUpSpeedLimit] = turtle_up_bytes;
|
|
o[RPC._TurtleTimeEnabled] = $('#prefs_form #turtle_schedule')[0].checked;
|
|
o[RPC._TurtleTimeBegin] = parseInt( $('#prefs_form #turtle_start_time').val() );
|
|
o[RPC._TurtleTimeEnd] = parseInt( $('#prefs_form #turtle_end_time').val() );
|
|
o[RPC._TurtleTimeDay] = parseInt( $('#prefs_form #turtle_days').val() );
|
|
|
|
|
|
o[RPC._PeerLimitGlobal] = parseInt( $('#prefs_form #conn_global').val() );
|
|
o[RPC._PeerLimitPerTorrent] = parseInt( $('#prefs_form #conn_torrent').val() );
|
|
o[RPC._PexEnabled] = $('#prefs_form #conn_pex')[0].checked;
|
|
o[RPC._DhtEnabled] = $('#prefs_form #conn_dht')[0].checked;
|
|
o[RPC._LpdEnabled] = $('#prefs_form #conn_lpd')[0].checked;
|
|
o[RPC._BlocklistEnabled] = $('#prefs_form #block_enable')[0].checked;
|
|
o[RPC._BlocklistURL] = $('#prefs_form #block_url').val();
|
|
o[RPC._UtpEnabled] = $('#prefs_form #network_utp')[0].checked;
|
|
o[RPC._PeerPortRandom] = $('#prefs_form #port_rand')[0].checked;
|
|
o[RPC._PortForwardingEnabled]= $('#prefs_form #port_forward')[0].checked;
|
|
|
|
|
|
|
|
tr.remote.savePrefs( o );
|
|
|
|
tr.hidePrefsDialog( );
|
|
},
|
|
blocklistUpdateClicked: function(event){
|
|
var tr = this;
|
|
tr.remote.updateBlocklist();
|
|
},
|
|
|
|
closeStatsClicked: function(event) {
|
|
this.hideStatsDialog( );
|
|
},
|
|
|
|
removeClicked: function( event ) {
|
|
var tr = this;
|
|
if( tr.isButtonEnabled( event ) ) {
|
|
tr.removeSelectedTorrents( );
|
|
tr.hideiPhoneAddressbar( );
|
|
}
|
|
},
|
|
|
|
toggleInspectorClicked: function( event ) {
|
|
var tr = this;
|
|
if( tr.isButtonEnabled( event ) )
|
|
tr.toggleInspector( );
|
|
},
|
|
|
|
inspectorTabClicked: function(event, tab) {
|
|
if (iPhone) event.stopPropagation();
|
|
|
|
// Select the clicked tab, unselect the others,
|
|
// and display the appropriate info
|
|
var tab_ids = $(tab).parent('#inspector_tabs').find('.inspector_tab').map(
|
|
function() { return $(this).attr('id'); }
|
|
);
|
|
for( var i=0, row; row=tab_ids[i]; ++i ) {
|
|
if (tab.id == row) {
|
|
$('#'+row).addClass('selected');
|
|
$('#'+row+'_container').show();
|
|
} else {
|
|
$('#'+row).removeClass('selected');
|
|
$('#'+row+'_container').hide();
|
|
}
|
|
}
|
|
this.hideiPhoneAddressbar();
|
|
|
|
this.updatePeersLists();
|
|
this.updateTrackersLists();
|
|
this.updateFileList();
|
|
},
|
|
|
|
filesSelectAllClicked: function(event) {
|
|
var t = this._files_torrent;
|
|
if (t != null)
|
|
this.toggleFilesWantedDisplay(t, true);
|
|
},
|
|
filesDeselectAllClicked: function(event) {
|
|
var t = this._files_torrent;
|
|
if (t != null)
|
|
this.toggleFilesWantedDisplay(t, false);
|
|
},
|
|
toggleFilesWantedDisplay: function(torrent, wanted) {
|
|
var rows = [ ];
|
|
for( var i=0, row; row=this._files[i]; ++i )
|
|
if( row.isEditable() && (torrent._files[i].wanted !== wanted) )
|
|
rows.push( row );
|
|
if( rows.length > 1 ) {
|
|
var command = wanted ? 'files-wanted' : 'files-unwanted';
|
|
this.changeFileCommand( command, rows );
|
|
}
|
|
},
|
|
|
|
toggleFilterClicked: function(event) {
|
|
if (this.isButtonEnabled(event))
|
|
this.toggleFilter();
|
|
},
|
|
setFilter: function( mode )
|
|
{
|
|
// update the radiobuttons
|
|
var c;
|
|
switch( mode ) {
|
|
case Prefs._FilterAll: c = '#filter_all_link'; break;
|
|
case Prefs._FilterActive: c = '#filter_active_link'; break;
|
|
case Prefs._FilterSeeding: c = '#filter_seeding_link'; break;
|
|
case Prefs._FilterDownloading: c = '#filter_downloading_link'; break;
|
|
case Prefs._FilterPaused: c = '#filter_paused_link'; break;
|
|
case Prefs._FilterFinished: c = '#filter_finished_link'; break;
|
|
}
|
|
$(c).parent().siblings().removeClass('selected');
|
|
$(c).parent().addClass('selected');
|
|
|
|
// do the filtering
|
|
this.setPref( Prefs._FilterMode, mode );
|
|
this.refilter( );
|
|
},
|
|
showAllClicked: function( event ) {
|
|
this.setFilter( Prefs._FilterAll );
|
|
},
|
|
showActiveClicked: function( event ) {
|
|
this.setFilter( Prefs._FilterActive );
|
|
},
|
|
showDownloadingClicked: function( event ) {
|
|
this.setFilter( Prefs._FilterDownloading );
|
|
},
|
|
showSeedingClicked: function(event) {
|
|
this.setFilter( Prefs._FilterSeeding );
|
|
},
|
|
showPausedClicked: function(event) {
|
|
this.setFilter( Prefs._FilterPaused );
|
|
},
|
|
showFinishedClicked: function(event) {
|
|
this.setFilter( Prefs._FilterFinished );
|
|
},
|
|
|
|
/*
|
|
* 'Clutch Preferences' was clicked (iPhone only)
|
|
*/
|
|
releaseClutchPreferencesButton: function(event) {
|
|
$('div#prefs_container div#pref_error').hide();
|
|
$('div#prefs_container h2.dialog_heading').show();
|
|
this.showPrefsDialog( );
|
|
},
|
|
|
|
/*
|
|
* Turn the periodic ajax torrents refresh on & off
|
|
*/
|
|
togglePeriodicRefresh: function(state) {
|
|
var tr = this;
|
|
if (state && this._periodic_refresh == null) {
|
|
// sanity check
|
|
if( !this[Prefs._RefreshRate] )
|
|
this[Prefs._RefreshRate] = 5;
|
|
remote = this.remote;
|
|
this._periodic_refresh = setInterval(function(){ tr.refreshTorrents(); }, this[Prefs._RefreshRate] * 1000 );
|
|
} else {
|
|
clearInterval(this._periodic_refresh);
|
|
this._periodic_refresh = null;
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Turn the periodic ajax torrents refresh on & off for the selected torrents
|
|
*/
|
|
periodicTorrentUpdate: function( ids ) {
|
|
var tr = this;
|
|
if( ids ) {
|
|
var curIds = this._extra_data_ids;
|
|
if( curIds == null )
|
|
curIds = [ ];
|
|
if( ids.length == curIds.length ) {
|
|
var duplicate = true;
|
|
for(var i = 0; i < ids.length; i++ ) {
|
|
if( ids[i] != curIds[i] ) {
|
|
duplicate = false;
|
|
break;
|
|
}
|
|
}
|
|
if( duplicate ) return;
|
|
}
|
|
tr.refreshTorrents(ids);
|
|
clearInterval(this._metadata_refresh);
|
|
// sanity check
|
|
if( !this[Prefs._RefreshRate] ) this[Prefs._RefreshRate] = 5;
|
|
this._metadata_refresh = setInterval(function(){ tr.refreshTorrents(ids); }, this[Prefs._RefreshRate] * 1000 );
|
|
this._extra_data_ids = ids;
|
|
} else {
|
|
clearInterval(this._metadata_refresh);
|
|
this._metadata_refresh = null;
|
|
this._extra_data_ids = null;
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Turn the periodic ajax session refresh on & off
|
|
*/
|
|
togglePeriodicSessionRefresh: function(state) {
|
|
var tr = this;
|
|
if (state && this._periodic_session_refresh == null) {
|
|
// sanity check
|
|
if( !this[Prefs._SessionRefreshRate] )
|
|
this[Prefs._SessionRefreshRate] = 5;
|
|
remote = this.remote;
|
|
this._periodic_session_refresh = setInterval(
|
|
function(){ tr.loadDaemonPrefs(); }, this[Prefs._SessionRefreshRate] * 1000
|
|
);
|
|
} else {
|
|
clearInterval(this._periodic_session_refresh);
|
|
this._periodic_session_refresh = null;
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Turn the periodic ajax stats refresh on & off
|
|
*/
|
|
togglePeriodicStatsRefresh: function(state) {
|
|
var tr = this;
|
|
if (state && this._periodic_stats_refresh == null) {
|
|
// sanity check
|
|
if( !this[Prefs._SessionRefreshRate] )
|
|
this[Prefs._SessionRefreshRate] = 5;
|
|
remote = this.remote;
|
|
this._periodic_stats_refresh = setInterval(
|
|
function(){ tr.loadDaemonStats(); }, this[Prefs._SessionRefreshRate] * 1000
|
|
);
|
|
} else {
|
|
clearInterval(this._periodic_stats_refresh);
|
|
this._periodic_stats_refresh = null;
|
|
}
|
|
},
|
|
|
|
toggleTurtleClicked: function() {
|
|
// Toggle the value
|
|
this[Prefs._TurtleState] = !this[Prefs._TurtleState];
|
|
// Store the result
|
|
var args = { };
|
|
args[RPC._TurtleState] = this[Prefs._TurtleState];
|
|
this.remote.savePrefs( args );
|
|
},
|
|
|
|
updateSelectedData: function()
|
|
{
|
|
var ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.getId(); } );
|
|
if( ids.length > 0 )
|
|
this.periodicTorrentUpdate( ids );
|
|
else
|
|
this.periodicTorrentUpdate( false );
|
|
},
|
|
|
|
updateTurtleButton: function() {
|
|
var t;
|
|
var w = $('#turtle_button');
|
|
if ( this[Prefs._TurtleState] ) {
|
|
w.addClass('turtleEnabled');
|
|
w.removeClass('turtleDisabled');
|
|
t = [ 'Click to disable Temporary Speed Limits' ];
|
|
} else {
|
|
w.removeClass('turtleEnabled');
|
|
w.addClass('turtleDisabled');
|
|
t = [ 'Click to enable Temporary Speed Limits' ];
|
|
}
|
|
t.push( '(', Transmission.fmt.speed(this._prefs[RPC._TurtleUpSpeedLimit]), 'up,',
|
|
Transmission.fmt.speed(this._prefs[RPC._TurtleDownSpeedLimit]), 'down)' );
|
|
w.attr( 'title', t.join(' ') );
|
|
},
|
|
|
|
/*--------------------------------------------
|
|
*
|
|
* I N T E R F A C E F U N C T I O N S
|
|
*
|
|
*--------------------------------------------*/
|
|
|
|
showPrefsDialog: function( ) {
|
|
this.checkPort(true);
|
|
$('body').addClass('prefs_showing');
|
|
$('#prefs_container').show();
|
|
this.hideiPhoneAddressbar();
|
|
if( Safari3 )
|
|
setTimeout("$('div#prefs_container div.dialog_window').css('top', '0px');",10);
|
|
this.updateButtonStates( );
|
|
this.togglePeriodicSessionRefresh(false);
|
|
},
|
|
|
|
hidePrefsDialog: function( )
|
|
{
|
|
$('body.prefs_showing').removeClass('prefs_showing');
|
|
if (iPhone) {
|
|
this.hideiPhoneAddressbar();
|
|
$('#prefs_container').hide();
|
|
} else if (Safari3) {
|
|
$('div#prefs_container div.dialog_window').css('top', '-425px');
|
|
setTimeout("$('#prefs_container').hide();",500);
|
|
} else {
|
|
$('#prefs_container').hide();
|
|
}
|
|
this.updateButtonStates( );
|
|
this.togglePeriodicSessionRefresh(true);
|
|
},
|
|
|
|
/*
|
|
* Process got some new session data from the server
|
|
*/
|
|
updatePrefs: function( prefs )
|
|
{
|
|
// remember them for later
|
|
this._prefs = prefs;
|
|
|
|
var up_limited = prefs[RPC._UpSpeedLimited];
|
|
var dn_limited = prefs[RPC._DownSpeedLimited];
|
|
var up_limit_k = prefs[RPC._UpSpeedLimit];
|
|
var dn_limit_k = prefs[RPC._DownSpeedLimit];
|
|
var turtle_up_limit_k = prefs[RPC._TurtleUpSpeedLimit];
|
|
var turtle_dn_limit_k = prefs[RPC._TurtleDownSpeedLimit];
|
|
|
|
if( prefs.units )
|
|
Transmission.fmt.updateUnits( prefs.units );
|
|
|
|
$('div.download_location input')[0].value = prefs[RPC._DownloadDir];
|
|
$('div.port input')[0].value = prefs[RPC._PeerPort];
|
|
$('div.auto_start input')[0].checked = prefs[RPC._StartAddedTorrent];
|
|
$('input#limit_download')[0].checked = dn_limited;
|
|
$('input#download_rate')[0].value = dn_limit_k;
|
|
$('input#limit_upload')[0].checked = up_limited;
|
|
$('input#upload_rate')[0].value = up_limit_k;
|
|
$('input#refresh_rate')[0].value = prefs[Prefs._RefreshRate];
|
|
$('div.encryption input')[0].checked = prefs[RPC._Encryption] == RPC._EncryptionRequired;
|
|
$('input#turtle_download_rate')[0].value = turtle_dn_limit_k;
|
|
$('input#turtle_upload_rate')[0].value = turtle_up_limit_k;
|
|
$('input#turtle_schedule')[0].checked = prefs[RPC._TurtleTimeEnabled];
|
|
$('select#turtle_start_time').val( prefs[RPC._TurtleTimeBegin] );
|
|
$('select#turtle_end_time').val( prefs[RPC._TurtleTimeEnd] );
|
|
$('select#turtle_days').val( prefs[RPC._TurtleTimeDay] );
|
|
$('#transmission_version').text( prefs[RPC._DaemonVersion] );
|
|
|
|
$('#conn_global').val( prefs[RPC._PeerLimitGlobal] );
|
|
$('#conn_torrent').val( prefs[RPC._PeerLimitPerTorrent] );
|
|
$('#conn_pex')[0].checked = prefs[RPC._PexEnabled];
|
|
$('#conn_dht')[0].checked = prefs[RPC._DhtEnabled];
|
|
$('#conn_lpd')[0].checked = prefs[RPC._LpdEnabled];
|
|
$('#block_enable')[0].checked = prefs[RPC._BlocklistEnabled];
|
|
$('#block_url').val( prefs[RPC._BlocklistURL]);
|
|
$('#block_size').text( prefs[RPC._BlocklistSize] + ' IP rules in the list' );
|
|
$('#network_utp')[0].checked = prefs[RPC._UtpEnabled];
|
|
$('#port_rand')[0].checked = prefs[RPC._PeerPortRandom];
|
|
$('#port_forward')[0].checked = prefs[RPC._PortForwardingEnabled];
|
|
|
|
|
|
if (!iPhone)
|
|
{
|
|
setInnerHTML( $('#limited_download_rate')[0], [ 'Limit (', Transmission.fmt.speed(dn_limit_k), ')' ].join('') );
|
|
var key = dn_limited ? '#limited_download_rate'
|
|
: '#unlimited_download_rate';
|
|
$(key).deselectMenuSiblings().selectMenuItem();
|
|
|
|
setInnerHTML( $('#limited_upload_rate')[0], [ 'Limit (', Transmission.fmt.speed(up_limit_k), ')' ].join('') );
|
|
key = up_limited ? '#limited_upload_rate'
|
|
: '#unlimited_upload_rate';
|
|
$(key).deselectMenuSiblings().selectMenuItem();
|
|
}
|
|
|
|
this[Prefs._TurtleState] = prefs[RPC._TurtleState];
|
|
this.updateTurtleButton();
|
|
},
|
|
|
|
updatePortStatus: function( status ){
|
|
if(status['port-is-open'])
|
|
$('#port_test').text('Port is open');
|
|
else
|
|
$('#port_test').text('Port is closed');
|
|
},
|
|
|
|
showStatsDialog: function( ) {
|
|
this.loadDaemonStats();
|
|
$('body').addClass('stats_showing');
|
|
$('#stats_container').show();
|
|
this.hideiPhoneAddressbar();
|
|
if( Safari3 )
|
|
setTimeout("$('div#stats_container div.dialog_window').css('top', '0px');",10);
|
|
this.updateButtonStates( );
|
|
this.togglePeriodicStatsRefresh(true);
|
|
},
|
|
|
|
hideStatsDialog: function( ){
|
|
$('body.stats_showing').removeClass('stats_showing');
|
|
if (iPhone) {
|
|
this.hideiPhoneAddressbar();
|
|
$('#stats_container').hide();
|
|
} else if (Safari3) {
|
|
$('div#stats_container div.dialog_window').css('top', '-425px');
|
|
setTimeout("$('#stats_container').hide();",500);
|
|
} else {
|
|
$('#stats_container').hide();
|
|
}
|
|
this.updateButtonStates( );
|
|
this.togglePeriodicStatsRefresh(false);
|
|
},
|
|
|
|
/*
|
|
* Process got some new session stats from the server
|
|
*/
|
|
updateStats: function( stats )
|
|
{
|
|
// can't think of a reason to remember this
|
|
//this._stats = stats;
|
|
|
|
var fmt = Transmission.fmt;
|
|
var session = stats["current-stats"];
|
|
var total = stats["cumulative-stats"];
|
|
|
|
setInnerHTML( $('#stats_session_uploaded')[0], fmt.size(session["uploadedBytes"]) );
|
|
setInnerHTML( $('#stats_session_downloaded')[0], fmt.size(session["downloadedBytes"]) );
|
|
setInnerHTML( $('#stats_session_ratio')[0], fmt.ratioString(Math.ratio(session["uploadedBytes"],session["downloadedBytes"])));
|
|
setInnerHTML( $('#stats_session_duration')[0], fmt.timeInterval(session["secondsActive"]) );
|
|
setInnerHTML( $('#stats_total_count')[0], total["sessionCount"] + " times" );
|
|
setInnerHTML( $('#stats_total_uploaded')[0], fmt.size(total["uploadedBytes"]) );
|
|
setInnerHTML( $('#stats_total_downloaded')[0], fmt.size(total["downloadedBytes"]) );
|
|
setInnerHTML( $('#stats_total_ratio')[0], fmt.ratioString(Math.ratio(total["uploadedBytes"],total["downloadedBytes"])));
|
|
setInnerHTML( $('#stats_total_duration')[0], fmt.timeInterval(total["secondsActive"]) );
|
|
},
|
|
|
|
setSearch: function( search ) {
|
|
this._current_search = search ? search.trim() : null;
|
|
this.refilter( );
|
|
},
|
|
|
|
setSortMethod: function( sort_method ) {
|
|
this.setPref( Prefs._SortMethod, sort_method );
|
|
this.refilter( );
|
|
},
|
|
|
|
setSortDirection: function( direction ) {
|
|
this.setPref( Prefs._SortDirection, direction );
|
|
this.refilter( );
|
|
},
|
|
|
|
/*
|
|
* Process an event in the footer-menu
|
|
*/
|
|
processSettingsMenuEvent: function(event) {
|
|
var tr = this;
|
|
var $element = $(event.target);
|
|
|
|
// Figure out which menu has been clicked
|
|
switch ($element.parent()[0].id) {
|
|
|
|
// Display the preferences dialog
|
|
case 'footer_super_menu':
|
|
if ($element[0].id == 'preferences') {
|
|
$('div#prefs_container div#pref_error').hide();
|
|
$('div#prefs_container h2.dialog_heading').show();
|
|
tr.showPrefsDialog( );
|
|
}
|
|
else if ($element[0].id == 'statistics') {
|
|
$('div#stats_container div#stats_error').hide();
|
|
$('div#stats_container h2.dialog_heading').show();
|
|
tr.showStatsDialog( );
|
|
}
|
|
else if ($element[0].id == 'compact_view') {
|
|
this.setPref( Prefs._CompactDisplayState, !this[Prefs._CompactDisplayState])
|
|
if(this[Prefs._CompactDisplayState])
|
|
$element.selectMenuItem();
|
|
else
|
|
$element.deselectMenuItem();
|
|
this.setCompactMode( this[Prefs._CompactDisplayState] );
|
|
}
|
|
else if ($element[0].id == 'homepage') {
|
|
window.open('http://www.transmissionbt.com/');
|
|
}
|
|
else if ($element[0].id == 'tipjar') {
|
|
window.open('http://www.transmissionbt.com/donate.php');
|
|
}
|
|
break;
|
|
|
|
// Limit the download rate
|
|
case 'footer_download_rate_menu':
|
|
var args = { };
|
|
if ($element.is('#unlimited_download_rate')) {
|
|
$element.deselectMenuSiblings().selectMenuItem();
|
|
args[RPC._DownSpeedLimited] = false;
|
|
} else {
|
|
var rate_str = ($element[0].innerHTML).replace(/[^0-9]/ig, '');
|
|
var rate_val = parseInt( rate_str );
|
|
setInnerHTML( $('#limited_download_rate')[0], [ 'Limit (', Transmission.fmt.speed(rate_val), ')' ].join('') );
|
|
$('#limited_download_rate').deselectMenuSiblings().selectMenuItem();
|
|
$('div.preference input#download_rate')[0].value = rate_str;
|
|
args[RPC._DownSpeedLimit] = rate_val;
|
|
args[RPC._DownSpeedLimited] = true;
|
|
}
|
|
$('div.preference input#limit_download')[0].checked = args[RPC._DownSpeedLimited];
|
|
tr.remote.savePrefs( args );
|
|
break;
|
|
|
|
// Limit the upload rate
|
|
case 'footer_upload_rate_menu':
|
|
var args = { };
|
|
if ($element.is('#unlimited_upload_rate')) {
|
|
$element.deselectMenuSiblings().selectMenuItem();
|
|
args[RPC._UpSpeedLimited] = false;
|
|
} else {
|
|
var rate_str = ($element[0].innerHTML).replace(/[^0-9]/ig, '');
|
|
var rate_val = parseInt( rate_str );
|
|
setInnerHTML( $('#limited_upload_rate')[0], [ 'Limit (', Transmission.fmt.speed(rate_val), ')' ].join('') );
|
|
$('#limited_upload_rate').deselectMenuSiblings().selectMenuItem();
|
|
$('div.preference input#upload_rate')[0].value = rate_str;
|
|
args[RPC._UpSpeedLimit] = rate_val;
|
|
args[RPC._UpSpeedLimited] = true;
|
|
}
|
|
$('div.preference input#limit_upload')[0].checked = args[RPC._UpSpeedLimited];
|
|
tr.remote.savePrefs( args );
|
|
break;
|
|
|
|
// Sort the torrent list
|
|
case 'footer_sort_menu':
|
|
|
|
// The 'reverse sort' option state can be toggled independently of the other options
|
|
if ($element.is('#reverse_sort_order')) {
|
|
if(!$element.is('#reverse_sort_order.active')) break;
|
|
var dir;
|
|
if ($element.menuItemIsSelected()) {
|
|
$element.deselectMenuItem();
|
|
dir = Prefs._SortAscending;
|
|
} else {
|
|
$element.selectMenuItem();
|
|
dir = Prefs._SortDescending;
|
|
}
|
|
tr.setSortDirection( dir );
|
|
|
|
// Otherwise, deselect all other options (except reverse-sort) and select this one
|
|
} else {
|
|
$element.parent().find('span.selected').each( function() {
|
|
if (! $element.parent().is('#reverse_sort_order')) {
|
|
$element.parent().deselectMenuItem();
|
|
}
|
|
});
|
|
$element.selectMenuItem();
|
|
var method = $element[0].id.replace(/sort_by_/, '');
|
|
tr.setSortMethod( method );
|
|
}
|
|
break;
|
|
}
|
|
$('#settings_menu').trigger('closemenu');
|
|
return false; // to prevent the event from bubbling up
|
|
},
|
|
|
|
/*
|
|
* Update the inspector with the latest data for the selected torrents
|
|
*/
|
|
updateInspector: function()
|
|
{
|
|
if( !this[Prefs._ShowInspector] )
|
|
return;
|
|
|
|
var torrents = this.getSelectedTorrents( );
|
|
if( !torrents.length && iPhone ) {
|
|
this.hideInspector();
|
|
return;
|
|
}
|
|
|
|
var creator = 'N/A';
|
|
var comment = 'N/A';
|
|
var download_dir = 'N/A';
|
|
var date_created = 'N/A';
|
|
var error = 'None';
|
|
var hash = 'N/A';
|
|
var have_public = false;
|
|
var have_private = false;
|
|
var name;
|
|
var sizeWhenDone = 0;
|
|
var sizeDone = 0;
|
|
var total_completed = 0;
|
|
var total_download = 0;
|
|
var total_download_peers = 0;
|
|
var total_download_speed = 0;
|
|
var total_availability = 0;
|
|
var total_have = 0;
|
|
var total_size = 0;
|
|
var total_state = [ ];
|
|
var pieces = 'N/A';
|
|
var total_upload = 0;
|
|
var total_upload_peers = 0;
|
|
var total_upload_speed = 0;
|
|
var total_verified = 0;
|
|
var na = 'N/A';
|
|
var tab = this._inspector._info_tab;
|
|
|
|
$("#torrent_inspector_size, .inspector_row div").css('color', '#222');
|
|
|
|
if( torrents.length == 0 )
|
|
{
|
|
setInnerHTML( tab.name, 'No Selection' );
|
|
setInnerHTML( tab.size, na );
|
|
setInnerHTML( tab.pieces, na );
|
|
setInnerHTML( tab.hash, na );
|
|
setInnerHTML( tab.state, na );
|
|
setInnerHTML( tab.download_speed, na );
|
|
setInnerHTML( tab.upload_speed, na );
|
|
setInnerHTML( tab.uploaded, na );
|
|
setInnerHTML( tab.downloaded, na );
|
|
setInnerHTML( tab.availability, na );
|
|
setInnerHTML( tab.ratio, na );
|
|
setInnerHTML( tab.have, na );
|
|
setInnerHTML( tab.upload_to, na );
|
|
setInnerHTML( tab.download_from, na );
|
|
setInnerHTML( tab.secure, na );
|
|
setInnerHTML( tab.creator_date, na );
|
|
setInnerHTML( tab.progress, na );
|
|
setInnerHTML( tab.comment, na );
|
|
setInnerHTML( tab.creator, na );
|
|
setInnerHTML( tab.download_dir, na );
|
|
setInnerHTML( tab.error, na );
|
|
this.updateFileList();
|
|
this.updatePeersLists();
|
|
this.updateTrackersLists();
|
|
$("#torrent_inspector_size, .inspector_row > div:contains('N/A')").css('color', '#666');
|
|
return;
|
|
}
|
|
|
|
name = torrents.length == 1
|
|
? torrents[0].getName()
|
|
: torrents.length+' Transfers Selected';
|
|
|
|
if( torrents.length == 1 )
|
|
{
|
|
var text
|
|
var t = torrents[0];
|
|
var err = t.getErrorMessage( );
|
|
if( err )
|
|
error = err;
|
|
if(( text = t.getComment()))
|
|
comment = text
|
|
if(( text = t.getCreator()))
|
|
creator = text
|
|
if(( text = t.getDownloadDir()))
|
|
download_dir = text
|
|
|
|
hash = t.getHashString();
|
|
pieces = [ t.getPieceCount(), 'pieces @', Transmission.fmt.mem(t.getPieceSize()) ].join(' ');
|
|
date_created = Transmission.fmt.timestamp( t.getDateCreated() );
|
|
}
|
|
|
|
for( var i=0, t; t=torrents[i]; ++i ) {
|
|
var sizeWhenDone = t.getSizeWhenDone()
|
|
var left = t.getLeftUntilDone()
|
|
sizeWhenDone += sizeWhenDone
|
|
sizeDone += sizeWhenDone - left;
|
|
total_completed += t.getHave();
|
|
total_verified += t.getHaveValid();
|
|
total_size += t.getTotalSize();
|
|
total_upload += t.getUploadedEver();
|
|
total_download += t.getDownloadedEver();
|
|
total_upload_speed += t.getUploadSpeed();
|
|
total_download_speed += t.getDownloadSpeed();
|
|
total_upload_peers += t.getPeersGettingFromUs();
|
|
total_download_peers += t.getPeersSendingToUs();
|
|
total_availability += sizeWhenDone - left + t.getDesiredAvailable();
|
|
|
|
var s = t.getStateString();
|
|
if( total_state.indexOf( s ) == -1 )
|
|
total_state.push( s );
|
|
|
|
if( t.getPrivateFlag( ) )
|
|
have_private = true;
|
|
else
|
|
have_public = true;
|
|
}
|
|
|
|
var private_string = '';
|
|
var fmt = Transmission.fmt;
|
|
if( have_private && have_public ) private_string = 'Mixed';
|
|
else if( have_private ) private_string = 'Private Torrent';
|
|
else if( have_public ) private_string = 'Public Torrent';
|
|
|
|
setInnerHTML( tab.name, name );
|
|
setInnerHTML( tab.size, torrents.length ? fmt.size( total_size ) : na );
|
|
setInnerHTML( tab.pieces, pieces );
|
|
setInnerHTML( tab.hash, hash );
|
|
setInnerHTML( tab.state, total_state.join('/') );
|
|
setInnerHTML( tab.download_speed, torrents.length ? fmt.speedBps( total_download_speed ) : na );
|
|
setInnerHTML( tab.upload_speed, torrents.length ? fmt.speedBps( total_upload_speed ) : na );
|
|
setInnerHTML( tab.uploaded, torrents.length ? fmt.size( total_upload ) : na );
|
|
setInnerHTML( tab.downloaded, torrents.length ? fmt.size( total_download ) : na );
|
|
setInnerHTML( tab.availability, torrents.length ? fmt.percentString(Math.ratio( total_availability*100, sizeWhenDone )) + '%' : na );
|
|
setInnerHTML( tab.ratio, torrents.length ? fmt.ratioString(Math.ratio( total_upload, total_download )) : na );
|
|
setInnerHTML( tab.have, torrents.length ? fmt.size(total_completed) + ' (' + fmt.size(total_verified) + ' verified)' : na );
|
|
setInnerHTML( tab.upload_to, torrents.length ? total_upload_peers : na );
|
|
setInnerHTML( tab.download_from, torrents.length ? total_download_peers : na );
|
|
setInnerHTML( tab.secure, private_string );
|
|
setInnerHTML( tab.creator_date, date_created );
|
|
setInnerHTML( tab.progress, torrents.length ? fmt.percentString(Math.ratio( sizeDone*100, sizeWhenDone )) + '%' : na );
|
|
setInnerHTML( tab.comment, comment );
|
|
setInnerHTML( tab.creator, creator );
|
|
setInnerHTML( tab.download_dir, download_dir );
|
|
setInnerHTML( tab.error, error );
|
|
|
|
this.updatePeersLists();
|
|
this.updateTrackersLists();
|
|
$(".inspector_row > div:contains('N/A')").css('color', '#666');
|
|
this.updateFileList();
|
|
},
|
|
|
|
onFileWantedToggled: function( row, want ) {
|
|
var command = want ? 'files-wanted' : 'files-unwanted';
|
|
this.changeFileCommand( command, [ row ] );
|
|
},
|
|
onFilePriorityToggled: function( row, priority ) {
|
|
var command;
|
|
switch( priority ) {
|
|
case -1: command = 'priority-low'; break;
|
|
case 1: command = 'priority-high'; break;
|
|
default: command = 'priority-normal'; break;
|
|
}
|
|
this.changeFileCommand( command, [ row ] );
|
|
},
|
|
clearFileList: function() {
|
|
$(this._inspector_file_list).empty();
|
|
delete this._files_torrent;
|
|
delete this._files;
|
|
},
|
|
updateFileList: function() {
|
|
|
|
// if the file list is hidden, clear the list
|
|
if( this._inspector_tab_files.className.indexOf('selected') == -1 ) {
|
|
this.clearFileList( );
|
|
return;
|
|
}
|
|
|
|
// if not torrent is selected, clear the list
|
|
var selected_torrents = this.getSelectedTorrents( );
|
|
if( selected_torrents.length != 1 ) {
|
|
this.clearFileList( );
|
|
return;
|
|
}
|
|
|
|
// if the active torrent hasn't changed, noop
|
|
var torrent = selected_torrents[0];
|
|
if( this._files_torrent === torrent )
|
|
return;
|
|
|
|
// build the file list
|
|
this.clearFileList( );
|
|
this._files_torrent = torrent;
|
|
var n = torrent._files.length;
|
|
this._files = new Array( n );
|
|
var fragment = document.createDocumentFragment( );
|
|
var tr = this;
|
|
for( var i=0; i<n; ++i ) {
|
|
var row = new FileRow( this, torrent, i );
|
|
fragment.appendChild( row.getElement( ) );
|
|
this._files[i] = row;
|
|
$(row).bind('wantedToggled',function(e,row,want){tr.onFileWantedToggled(row,want);});
|
|
$(row).bind('priorityToggled',function(e,row,priority){tr.onFilePriorityToggled(row,priority);});
|
|
}
|
|
this._inspector_file_list.appendChild( fragment );
|
|
},
|
|
|
|
refreshFileView: function() {
|
|
for( var i=0, row; row=this._files[i]; ++i )
|
|
row.refresh();
|
|
},
|
|
|
|
updatePeersLists: function() {
|
|
var tr = this;
|
|
var html = [ ];
|
|
var fmt = Transmission.fmt;
|
|
var torrents = this.getSelectedTorrents( );
|
|
if( $(this._inspector_peers_list).is(':visible') ) {
|
|
for( var k=0, torrent; torrent=torrents[k]; ++k ) {
|
|
var peers = torrent.getPeers()
|
|
html.push( '<div class="inspector_group">' );
|
|
if( torrents.length > 1 ) {
|
|
html.push( '<div class="inspector_torrent_label">', torrent.getName(), '</div>' );
|
|
}
|
|
if( peers.length == 0 ) {
|
|
html.push( '<br></div>' ); // firefox won't paint the top border if the div is empty
|
|
continue;
|
|
}
|
|
html.push( '<table class="peer_list">',
|
|
'<tr class="inspector_peer_entry even">',
|
|
'<th class="encryptedCol"></th>',
|
|
'<th class="upCol">Up</th>',
|
|
'<th class="downCol">Down</th>',
|
|
'<th class="percentCol">%</th>',
|
|
'<th class="statusCol">Status</th>',
|
|
'<th class="addressCol">Address</th>',
|
|
'<th class="clientCol">Client</th>',
|
|
'</tr>' );
|
|
for( var i=0, peer; peer=peers[i]; ++i ) {
|
|
var parity = ((i+1) % 2 == 0 ? 'even' : 'odd');
|
|
html.push( '<tr class="inspector_peer_entry ', parity, '">',
|
|
'<td>', (peer.isEncrypted ? '<img src="images/graphics/lock_icon.png" alt="Encrypted"/>' : ''), '</td>',
|
|
'<td>', ( peer.rateToPeer ? fmt.speedBps(peer.rateToPeer) : '' ), '</td>',
|
|
'<td>', ( peer.rateToClient ? fmt.speedBps(peer.rateToClient) : '' ), '</td>',
|
|
'<td class="percentCol">', Math.floor(peer.progress*100), '%', '</td>',
|
|
'<td>', peer.flagStr, '</td>',
|
|
'<td>', peer.address, '</td>',
|
|
'<td class="clientCol">', peer.clientName, '</td>',
|
|
'</tr>' );
|
|
}
|
|
html.push( '</table></div>' );
|
|
}
|
|
}
|
|
setInnerHTML(this._inspector_peers_list, html.join('') );
|
|
},
|
|
|
|
updateTrackersLists: function() {
|
|
// By building up the HTML as as string, then have the browser
|
|
// turn this into a DOM tree, this is a fast operation.
|
|
var tr = this;
|
|
var html = [ ];
|
|
var na = 'N/A';
|
|
var torrents = this.getSelectedTorrents( );
|
|
if( $(this._inspector_trackers_list).is(':visible') ) {
|
|
for( var k=0, torrent; torrent = torrents[k]; ++k ) {
|
|
html.push( '<div class="inspector_group">' );
|
|
if( torrents.length > 1 ) {
|
|
html.push( '<div class="inspector_torrent_label">', torrent.getName(), '</div>' );
|
|
}
|
|
for( var i=0, tier; tier=torrent._trackerStats[i]; ++i ) {
|
|
html.push( '<div class="inspector_group_label">',
|
|
'Tier ', (i + 1), '</div>',
|
|
'<ul class="tier_list">' );
|
|
for( var j=0, tracker; tracker=tier[j]; ++j ) {
|
|
var lastAnnounceStatusHash = tr.lastAnnounceStatus(tracker);
|
|
var announceState = tr.announceState(tracker);
|
|
var lastScrapeStatusHash = tr.lastScrapeStatus(tracker);
|
|
|
|
// Display construction
|
|
var parity = ((j+1) % 2 == 0 ? 'even' : 'odd');
|
|
html.push( '<li class="inspector_tracker_entry ', parity, '"><div class="tracker_host" title="', tracker.announce, '">',
|
|
tracker.host, '</div>',
|
|
'<div class="tracker_activity">',
|
|
'<div>', lastAnnounceStatusHash['label'], ': ', lastAnnounceStatusHash['value'], '</div>',
|
|
'<div>', announceState, '</div>',
|
|
'<div>', lastScrapeStatusHash['label'], ': ', lastScrapeStatusHash['value'], '</div>',
|
|
'</div><table class="tracker_stats">',
|
|
'<tr><th>Seeders:</th><td>', (tracker.seederCount > -1 ? tracker.seederCount : na), '</td></tr>',
|
|
'<tr><th>Leechers:</th><td>', (tracker.leecherCount > -1 ? tracker.leecherCount : na), '</td></tr>',
|
|
'<tr><th>Downloads:</th><td>', (tracker.downloadCount > -1 ? tracker.downloadCount : na), '</td></tr>',
|
|
'</table></li>' );
|
|
}
|
|
html.push( '</ul>' );
|
|
}
|
|
html.push( '</div>' );
|
|
}
|
|
}
|
|
setInnerHTML(this._inspector_trackers_list, html.join(''));
|
|
},
|
|
|
|
lastAnnounceStatus: function(tracker){
|
|
var lastAnnounceLabel = 'Last Announce';
|
|
var lastAnnounce = [ 'N/A' ];
|
|
if (tracker.hasAnnounced) {
|
|
var lastAnnounceTime = Transmission.fmt.timestamp(tracker.lastAnnounceTime);
|
|
if (tracker.lastAnnounceSucceeded) {
|
|
lastAnnounce = [ lastAnnounceTime, ' (got ', Transmission.fmt.plural(tracker.lastAnnouncePeerCount, 'peer'), ')' ];
|
|
} else {
|
|
lastAnnounceLabel = 'Announce error';
|
|
lastAnnounce = [ (tracker.lastAnnounceResult ? (tracker.lastAnnounceResult + ' - ') : ''), lastAnnounceTime ];
|
|
}
|
|
}
|
|
return { 'label':lastAnnounceLabel, 'value':lastAnnounce.join('') };
|
|
},
|
|
|
|
announceState: function(tracker){
|
|
var announceState = '';
|
|
switch (tracker.announceState) {
|
|
case Torrent._TrackerActive:
|
|
announceState = 'Announce in progress';
|
|
break;
|
|
case Torrent._TrackerWaiting:
|
|
var timeUntilAnnounce = tracker.nextAnnounceTime - ((new Date()).getTime() / 1000);
|
|
if(timeUntilAnnounce < 0){
|
|
timeUntilAnnounce = 0;
|
|
}
|
|
announceState = 'Next announce in ' + Transmission.fmt.timeInterval(timeUntilAnnounce);
|
|
break;
|
|
case Torrent._TrackerQueued:
|
|
announceState = 'Announce is queued';
|
|
break;
|
|
case Torrent._TrackerInactive:
|
|
announceState = tracker.isBackup ?
|
|
'Tracker will be used as a backup' :
|
|
'Announce not scheduled';
|
|
break;
|
|
default:
|
|
announceState = 'unknown announce state: ' + tracker.announceState;
|
|
}
|
|
return announceState;
|
|
},
|
|
|
|
lastScrapeStatus: function(tracker){
|
|
var lastScrapeLabel = 'Last Scrape';
|
|
var lastScrape = 'N/A';
|
|
if (tracker.hasScraped) {
|
|
var lastScrapeTime = Transmission.fmt.timestamp(tracker.lastScrapeTime);
|
|
if (tracker.lastScrapeSucceeded) {
|
|
lastScrape = lastScrapeTime;
|
|
} else {
|
|
lastScrapeLabel = 'Scrape error';
|
|
lastScrape = (tracker.lastScrapeResult ? tracker.lastScrapeResult + ' - ' : '') + lastScrapeTime;
|
|
}
|
|
}
|
|
return {'label':lastScrapeLabel, 'value':lastScrape}
|
|
},
|
|
|
|
/*
|
|
* Toggle the visibility of the inspector (used by the context menu)
|
|
*/
|
|
toggleInspector: function() {
|
|
if( this[Prefs._ShowInspector] )
|
|
this.hideInspector( );
|
|
else
|
|
this.showInspector( );
|
|
},
|
|
|
|
showInspector: function() {
|
|
$('#torrent_inspector').show();
|
|
if (iPhone) {
|
|
$('body').addClass('inspector_showing');
|
|
$('#inspector_close').show();
|
|
this.hideiPhoneAddressbar();
|
|
} else {
|
|
var w = $('#torrent_inspector').width() + 1 + 'px';
|
|
$('#torrent_filter_bar')[0].style.right = w;
|
|
$('#torrent_container')[0].style.right = w;
|
|
}
|
|
|
|
setInnerHTML( $('ul li#context_toggle_inspector')[0], 'Hide Inspector' );
|
|
|
|
this.setPref( Prefs._ShowInspector, true );
|
|
this.updateInspector( );
|
|
this.refreshDisplay( );
|
|
},
|
|
|
|
/*
|
|
* Hide the inspector
|
|
*/
|
|
hideInspector: function() {
|
|
|
|
$('#torrent_inspector').hide();
|
|
|
|
if (iPhone) {
|
|
this.deselectAll( );
|
|
$('body.inspector_showing').removeClass('inspector_showing');
|
|
$('#inspector_close').hide();
|
|
this.hideiPhoneAddressbar();
|
|
} else {
|
|
$('#torrent_filter_bar')[0].style.right = '0px';
|
|
$('#torrent_container')[0].style.right = '0px';
|
|
setInnerHTML( $('ul li#context_toggle_inspector')[0], 'Show Inspector' );
|
|
}
|
|
|
|
this.setPref( Prefs._ShowInspector, false );
|
|
this.refreshDisplay( );
|
|
},
|
|
|
|
/*
|
|
* Toggle the visibility of the filter bar
|
|
*/
|
|
toggleFilter: function() {
|
|
if( this[Prefs._ShowFilter] )
|
|
this.hideFilter();
|
|
else
|
|
this.showFilter();
|
|
},
|
|
|
|
showFilter: function( ) {
|
|
var container_top = parseInt($('#torrent_container').position().top) + $('#torrent_filter_bar').height() + 1;
|
|
$('#torrent_container').css('top', container_top + 'px');
|
|
$('#torrent_filter_bar').show();
|
|
this.setPref( Prefs._ShowFilter, true );
|
|
},
|
|
|
|
hideFilter: function()
|
|
{
|
|
var container_top = parseInt($('#torrent_container').css('top')) - $('#torrent_filter_bar').height() - 1;
|
|
$('#torrent_container').css('top', container_top + 'px');
|
|
$('#torrent_filter_bar').hide();
|
|
this.setPref( Prefs._ShowFilter, false );
|
|
this.setFilter( Prefs._FilterAll );
|
|
},
|
|
|
|
refreshMetaData: function(ids) {
|
|
var tr = this;
|
|
this.remote.getMetaDataFor(ids, function(active, removed){ tr.updateMetaData(active); });
|
|
},
|
|
|
|
updateMetaData: function( torrents )
|
|
{
|
|
var tr = this;
|
|
var refresh_files_for = [ ];
|
|
var selected_torrents = this.getSelectedTorrents();
|
|
jQuery.each( torrents, function( ) {
|
|
var t = tr._torrents[ this.id ];
|
|
if( t ) {
|
|
t.refreshMetaData( this );
|
|
if( selected_torrents.indexOf(t) != -1 )
|
|
refresh_files_for.push( t.getId( ) );
|
|
}
|
|
} );
|
|
if( refresh_files_for.length > 0 )
|
|
tr.remote.loadTorrentFiles( refresh_files_for );
|
|
},
|
|
|
|
refreshTorrents: function(ids) {
|
|
var tr = this;
|
|
if (!ids)
|
|
ids = 'recently-active';
|
|
|
|
this.remote.getUpdatedDataFor(ids, function(active, removed){ tr.updateTorrentsData(active, removed); });
|
|
},
|
|
|
|
updateTorrentsData: function( updated, removed_ids ) {
|
|
var tr = this;
|
|
var new_torrent_ids = [];
|
|
var refresh_files_for = [];
|
|
var selected_torrents = this.getSelectedTorrents();
|
|
|
|
for( var i=0, o; o=updated[i]; ++i ) {
|
|
var t = tr._torrents[o.id];
|
|
if (t == null)
|
|
new_torrent_ids.push(o.id);
|
|
else {
|
|
t.refresh(o);
|
|
if( selected_torrents.indexOf(t) != -1 )
|
|
refresh_files_for.push(t.getId());
|
|
}
|
|
}
|
|
|
|
if(refresh_files_for.length > 0)
|
|
tr.remote.loadTorrentFiles( refresh_files_for );
|
|
|
|
if(new_torrent_ids.length > 0)
|
|
tr.remote.getInitialDataFor(new_torrent_ids, function(torrents){ tr.addTorrents(torrents) } );
|
|
|
|
var removedAny = tr.deleteTorrents(removed_ids);
|
|
|
|
if( ( new_torrent_ids.length != 0 ) || removedAny ) {
|
|
tr.hideiPhoneAddressbar();
|
|
tr.deselectAll( true );
|
|
}
|
|
|
|
this.refilter();
|
|
},
|
|
|
|
updateTorrentsFileData: function( torrents ){
|
|
for( var i=0, o; o=torrents[i]; ++i ) {
|
|
var t = this._torrents[o.id];
|
|
if( t !== null ) {
|
|
t.refreshFiles( o );
|
|
if( t === this._files_torrent )
|
|
this.refreshFileView();
|
|
}
|
|
}
|
|
},
|
|
|
|
initializeAllTorrents: function(){
|
|
var tr = this;
|
|
this.remote.getInitialDataFor( null ,function(torrents) { tr.addTorrents(torrents); } );
|
|
},
|
|
|
|
onRowClicked: function( ev, row )
|
|
{
|
|
// Prevents click carrying to parent element
|
|
// which deselects all on click
|
|
ev.stopPropagation();
|
|
// but still hide the context menu if it is showing
|
|
$('#jqContextMenu').hide();
|
|
|
|
// 'Apple' button emulation on PC :
|
|
// Need settable meta-key and ctrl-key variables for mac emulation
|
|
var meta_key = ev.metaKey;
|
|
var ctrl_key = ev.ctrlKey;
|
|
if (ev.ctrlKey && navigator.appVersion.toLowerCase().indexOf("mac") == -1) {
|
|
meta_key = true;
|
|
ctrl_key = false;
|
|
}
|
|
|
|
// Shift-Click - selects a range from the last-clicked row to this one
|
|
if (iPhone) {
|
|
if ( row.isSelected() )
|
|
this.showInspector();
|
|
this.setSelectedRow( row, true );
|
|
|
|
} else if (ev.shiftKey) {
|
|
this.selectRange( row, true );
|
|
// Need to deselect any selected text
|
|
window.focus();
|
|
|
|
// Apple-Click, not selected
|
|
} else if (!row.isSelected() && meta_key) {
|
|
this.selectRow( row, true );
|
|
|
|
// Regular Click, not selected
|
|
} else if (!row.isSelected()) {
|
|
this.setSelectedRow( row, true );
|
|
|
|
// Apple-Click, selected
|
|
} else if (row.isSelected() && meta_key) {
|
|
this.deselectRow( row );
|
|
|
|
// Regular Click, selected
|
|
} else if (row.isSelected()) {
|
|
this.setSelectedRow( row, true );
|
|
}
|
|
|
|
this._last_row_clicked = row;
|
|
},
|
|
|
|
addTorrents: function( new_torrents )
|
|
{
|
|
var tr = this;
|
|
|
|
for( var i=0, row; row=new_torrents[i]; ++i ) {
|
|
var t = new Torrent( this, row );
|
|
this._torrents[t.getId()] = t;
|
|
}
|
|
|
|
this.refilter( );
|
|
},
|
|
|
|
deleteTorrents: function(torrent_ids){
|
|
|
|
if(typeof torrent_ids == 'undefined')
|
|
return false
|
|
|
|
var keep = [ ]
|
|
var elements = [ ]
|
|
|
|
for(var i=0, row; row=this._rows[i]; ++i) {
|
|
var tor = row.getTorrent()
|
|
var tid = tor ? tor.getId() : -1
|
|
if( torrent_ids.indexOf( tid ) == -1 )
|
|
keep.push( row )
|
|
else {
|
|
delete this._torrents[ tid ]
|
|
$(row.getElement()).remove()
|
|
}
|
|
}
|
|
|
|
this._rows = keep
|
|
|
|
return remove.length > 0
|
|
},
|
|
|
|
refreshDisplay: function( )
|
|
{
|
|
var rows = this.getVisibleRows( );
|
|
for( var i=0, row; row=rows[i]; ++i )
|
|
row.render( this );
|
|
},
|
|
|
|
/*
|
|
* Set the alternating background colors for torrents
|
|
*/
|
|
setTorrentBgColors: function( )
|
|
{
|
|
var rows = this.getVisibleRows( );
|
|
for( var i=0, row; row=rows[i]; ++i )
|
|
row.setEven((i+1) % 2 == 0);
|
|
},
|
|
|
|
updateStatusbar: function()
|
|
{
|
|
var torrents = this.getAllTorrents();
|
|
var torrentCount = torrents.length;
|
|
var visibleCount = this.getVisibleTorrents().length;
|
|
|
|
// calculate the overall speed
|
|
var upSpeed = 0;
|
|
var downSpeed = 0;
|
|
for( var i=0, row; row=torrents[i]; ++i ) {
|
|
upSpeed += row.getUploadSpeed( );
|
|
downSpeed += row.getDownloadSpeed( );
|
|
}
|
|
|
|
// update torrent count label
|
|
var s;
|
|
if( torrentCount == visibleCount )
|
|
s = torrentCount + ' Transfers';
|
|
else
|
|
s = visibleCount + ' of ' + torrentCount + ' Transfers';
|
|
setInnerHTML( $('#torrent_global_transfer')[0], s );
|
|
|
|
// update the speeds
|
|
s = Transmission.fmt.speedBps( upSpeed );
|
|
if( iPhone ) s = 'UL: ' + s;
|
|
setInnerHTML( $('#torrent_global_upload')[0], s );
|
|
|
|
// download speeds
|
|
s = Transmission.fmt.speedBps( downSpeed );
|
|
if( iPhone ) s = 'DL: ' + s;
|
|
setInnerHTML( $('#torrent_global_download')[0], s );
|
|
},
|
|
|
|
/*
|
|
* Select a torrent file to upload
|
|
* FIXME
|
|
*/
|
|
uploadTorrentFile: function(confirmed)
|
|
{
|
|
// Display the upload dialog
|
|
if (! confirmed) {
|
|
$('input#torrent_upload_file').attr('value', '');
|
|
$('input#torrent_upload_url').attr('value', '');
|
|
$('input#torrent_auto_start').attr('checked', $('#prefs_form #auto_start')[0].checked);
|
|
$('#upload_container').show();
|
|
$('#torrent_upload_url').focus();
|
|
if (!iPhone && Safari3) {
|
|
setTimeout("$('div#upload_container div.dialog_window').css('top', '0px');",10);
|
|
}
|
|
|
|
// Submit the upload form
|
|
} else {
|
|
var tr = this;
|
|
var args = { };
|
|
var paused = !$('#torrent_auto_start').is(':checked');
|
|
if ('' != $('#torrent_upload_url').val()) {
|
|
tr.remote.addTorrentByUrl($('#torrent_upload_url').val(), { paused: paused });
|
|
} else {
|
|
args.url = '../upload?paused=' + paused;
|
|
args.type = 'POST';
|
|
args.data = { 'X-Transmission-Session-Id' : tr.remote._token };
|
|
args.dataType = 'xml';
|
|
args.iframe = true;
|
|
args.success = function( data ) {
|
|
tr.refreshTorrents();
|
|
tr.togglePeriodicRefresh( true );
|
|
};
|
|
tr.togglePeriodicRefresh( false );
|
|
$('#torrent_upload_form').ajaxSubmit( args );
|
|
}
|
|
}
|
|
},
|
|
|
|
removeSelectedTorrents: function() {
|
|
var torrents = this.getSelectedTorrents( );
|
|
if( torrents.length )
|
|
this.promptToRemoveTorrents( torrents );
|
|
},
|
|
|
|
removeSelectedTorrentsAndData: function() {
|
|
var torrents = this.getSelectedTorrents( );
|
|
if( torrents.length )
|
|
this.promptToRemoveTorrentsAndData( torrents );
|
|
},
|
|
|
|
promptToRemoveTorrents:function( torrents )
|
|
{
|
|
if( torrents.length == 1 )
|
|
{
|
|
var torrent = torrents[0];
|
|
var header = 'Remove ' + torrent.getName() + '?';
|
|
var message = 'Once removed, continuing the transfer will require the torrent file. Are you sure you want to remove it?';
|
|
dialog.confirm( header, message, 'Remove', 'transmission.removeTorrents', torrents );
|
|
}
|
|
else
|
|
{
|
|
var header = 'Remove ' + torrents.length + ' transfers?';
|
|
var message = 'Once removed, continuing the transfers will require the torrent files. Are you sure you want to remove them?';
|
|
dialog.confirm( header, message, 'Remove', 'transmission.removeTorrents', torrents );
|
|
}
|
|
},
|
|
|
|
promptToRemoveTorrentsAndData:function( torrents )
|
|
{
|
|
if( torrents.length == 1 )
|
|
{
|
|
var torrent = torrents[0],
|
|
header = 'Remove ' + torrent.getName() + ' and delete data?',
|
|
message = 'All data downloaded for this torrent will be deleted. Are you sure you want to remove it?';
|
|
dialog.confirm( header, message, 'Remove', 'transmission.removeTorrentsAndData', torrents );
|
|
}
|
|
else
|
|
{
|
|
var header = 'Remove ' + torrents.length + ' transfers and delete data?',
|
|
message = 'All data downloaded for these torrents will be deleted. Are you sure you want to remove them?';
|
|
dialog.confirm( header, message, 'Remove', 'transmission.removeTorrentsAndData', torrents );
|
|
}
|
|
},
|
|
|
|
removeTorrents: function( torrents ) {
|
|
var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.removeTorrents( torrent_ids, function(){ tr.refreshTorrents() } );
|
|
},
|
|
|
|
removeTorrentsAndData: function( torrents ) {
|
|
this.remote.removeTorrentsAndData( torrents );
|
|
},
|
|
|
|
verifySelectedTorrents: function() {
|
|
this.verifyTorrents( this.getSelectedTorrents( ) );
|
|
},
|
|
|
|
reannounceSelectedTorrents: function() {
|
|
this.reannounceTorrents( this.getSelectedTorrents( ) );
|
|
},
|
|
|
|
startSelectedTorrents: function( force ) {
|
|
this.startTorrents( this.getSelectedTorrents( ), force );
|
|
},
|
|
startAllTorrents: function( ) {
|
|
this.startTorrents( this.getAllTorrents( ), false );
|
|
},
|
|
startTorrent: function( torrent ) {
|
|
this.startTorrents( [ torrent ], false );
|
|
},
|
|
startTorrents: function( torrents, force ) {
|
|
var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.startTorrents( torrent_ids, force, function(){ tr.refreshTorrents(torrent_ids) } );
|
|
},
|
|
verifyTorrent: function( torrent ) {
|
|
this.verifyTorrents( [ torrent ] );
|
|
},
|
|
verifyTorrents: function( torrents ) {
|
|
var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.verifyTorrents( torrent_ids, function(){ tr.refreshTorrents(torrent_ids) } );
|
|
},
|
|
|
|
reannounceTorrent: function( torrent ) {
|
|
this.reannounceTorrents( [ torrent ] );
|
|
},
|
|
reannounceTorrents: function( torrents ) {
|
|
var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.reannounceTorrents( torrent_ids, function(){ tr.refreshTorrents(torrent_ids) } );
|
|
},
|
|
|
|
stopSelectedTorrents: function( ) {
|
|
this.stopTorrents( this.getSelectedTorrents( ) );
|
|
},
|
|
stopAllTorrents: function( ) {
|
|
this.stopTorrents( this.getAllTorrents( ) );
|
|
},
|
|
stopTorrent: function( torrent ) {
|
|
this.stopTorrents( [ torrent ] );
|
|
},
|
|
stopTorrents: function( torrents ) {
|
|
var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.stopTorrents( torrent_ids, function(){ tr.refreshTorrents(torrent_ids )} );
|
|
},
|
|
changeFileCommand: function(command, rows) {
|
|
this.remote.changeFileCommand(command, rows);
|
|
},
|
|
|
|
hideiPhoneAddressbar: function(timeInSeconds) {
|
|
var tr = this;
|
|
if( iPhone ) {
|
|
var delayLength = timeInSeconds ? timeInSeconds*1000 : 150;
|
|
// not currently supported on iPhone
|
|
if(/*document.body.scrollTop!=1 && */scroll_timeout==null) {
|
|
scroll_timeout = setTimeout(function(){ tr.doToolbarHide(); }, delayLength);
|
|
}
|
|
}
|
|
},
|
|
doToolbarHide: function() {
|
|
window.scrollTo(0,1);
|
|
scroll_timeout=null;
|
|
},
|
|
|
|
// Queue
|
|
moveTop: function( ) {
|
|
var torrent_ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.moveTorrentsToTop( torrent_ids, function(){ tr.refreshTorrents(torrent_ids )} );
|
|
},
|
|
moveUp: function( ) {
|
|
var torrent_ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.moveTorrentsUp( torrent_ids, function(){ tr.refreshTorrents(torrent_ids )} );
|
|
},
|
|
moveDown: function( ) {
|
|
var torrent_ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.moveTorrentsDown( torrent_ids, function(){ tr.refreshTorrents(torrent_ids )} );
|
|
},
|
|
moveBottom: function( ) {
|
|
var torrent_ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.getId(); } );
|
|
var tr = this;
|
|
this.remote.moveTorrentsToBottom( torrent_ids, function(){ tr.refreshTorrents(torrent_ids )} );
|
|
},
|
|
|
|
|
|
/***
|
|
****
|
|
***/
|
|
|
|
onToggleRunningClicked: function( ev )
|
|
{
|
|
var torrent = ev.data.r.getTorrent( );
|
|
|
|
if( torrent.isStopped( ) )
|
|
this.startTorrent( torrent );
|
|
else
|
|
this.stopTorrent( torrent );
|
|
},
|
|
|
|
refilter: function()
|
|
{
|
|
// decide which torrents to keep showing
|
|
var allTorrents = this.getAllTorrents( );
|
|
var keep = [ ];
|
|
for( var i=0, t; t=allTorrents[i]; ++i )
|
|
if( t.test( this[Prefs._FilterMode], this._current_search ) )
|
|
keep.push( t );
|
|
|
|
// sort the keepers
|
|
Torrent.sortTorrents( keep, this[Prefs._SortMethod],
|
|
this[Prefs._SortDirection] );
|
|
|
|
// make a backup of the selection
|
|
var sel = this.getSelectedTorrents( );
|
|
|
|
// add rows it there aren't enough
|
|
if( this._rows.length < keep.length ) {
|
|
var tr = this;
|
|
var fragment = document.createDocumentFragment( );
|
|
while( this._rows.length < keep.length ) {
|
|
var row = new TorrentRow( this.torrentRenderer );
|
|
if( !iPhone ) {
|
|
var b = row.getToggleRunningButton( );
|
|
if( b !== null ) {
|
|
$(b).bind('click', {r:row}, function(e) { tr.onToggleRunningClicked(e); });
|
|
}
|
|
}
|
|
$(row.getElement()).bind('click',{r: row}, function(ev){ tr.onRowClicked(ev,ev.data.r);});
|
|
$(row.getElement()).bind('dblclick', function(e) { tr.toggleInspector(); });
|
|
fragment.appendChild( row.getElement() );
|
|
this._rows.push( row );
|
|
}
|
|
this._torrent_list.appendChild(fragment);
|
|
}
|
|
|
|
// hide rows if there are too many
|
|
for( var i=keep.length, e; e=this._rows[i]; ++i ) {
|
|
delete e._torrent;
|
|
e.setVisible(false);
|
|
}
|
|
|
|
// show the ones we're keeping
|
|
for( var i=0, len=keep.length; i<len; ++i ) {
|
|
var row = this._rows[i];
|
|
var tor = keep[i];
|
|
row.setVisible( true );
|
|
row.setTorrent( this, tor );
|
|
row.setSelected( sel.indexOf( tor ) !== -1 );
|
|
}
|
|
|
|
// sync gui
|
|
this.setTorrentBgColors( );
|
|
this.updateStatusbar( );
|
|
this.selectionChanged( );
|
|
this.refreshDisplay( );
|
|
},
|
|
|
|
setEnabled: function( key, flag )
|
|
{
|
|
$(key).toggleClass( 'disabled', !flag );
|
|
},
|
|
|
|
updateButtonStates: function()
|
|
{
|
|
var showing_dialog = new RegExp("(prefs_showing|dialog_showing|open_showing)").test(document.body.className);
|
|
this._toolbar_buttons.toggleClass( 'disabled', showing_dialog );
|
|
|
|
if (!showing_dialog)
|
|
{
|
|
var torrents = this.getVisibleTorrents( );
|
|
var haveSelection = false;
|
|
var haveActive = false;
|
|
var haveActiveSelection = false;
|
|
var havePaused = false;
|
|
var havePausedSelection = false;
|
|
|
|
for( var i=0, row; row=this._rows[i]; ++i ) {
|
|
if( row.isVisible( ) ) {
|
|
var isStopped = row.getTorrent().isStopped( );
|
|
var isSelected = row.isSelected();
|
|
if( !isStopped ) haveActive = true;
|
|
if( isStopped ) havePaused = true;
|
|
if( isSelected ) haveSelection = true;
|
|
if( isSelected && !isStopped ) haveActiveSelection = true;
|
|
if( isSelected && isStopped ) havePausedSelection = true;
|
|
}
|
|
}
|
|
|
|
this.setEnabled( this._toolbar_pause_button, haveActiveSelection );
|
|
this.setEnabled( this._context_pause_button, haveActiveSelection );
|
|
this.setEnabled( this._toolbar_start_button, havePausedSelection );
|
|
this.setEnabled( this._context_start_button, havePausedSelection );
|
|
this.setEnabled( this._context_move_top_button, haveSelection );
|
|
this.setEnabled( this._context_move_up_button, haveSelection );
|
|
this.setEnabled( this._context_move_down_button, haveSelection );
|
|
this.setEnabled( this._context_move_bottom_button, haveSelection );
|
|
this.setEnabled( this._context_start_now_button, havePausedSelection );
|
|
this.setEnabled( this._toolbar_remove_button, haveSelection );
|
|
this.setEnabled( this._toolbar_pause_all_button, haveActive );
|
|
this.setEnabled( this._toolbar_start_all_button, havePaused );
|
|
}
|
|
}
|
|
};
|