/* * 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("").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 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' ); if( torrents.length > 1 ) { html.push( '
', torrent.getName(), '
' ); } if( peers.length == 0 ) { html.push( '
' ); // firefox won't paint the top border if the div is empty continue; } html.push( '', '', '', '', '', '', '', '', '', '' ); for( var i=0, peer; peer=peers[i]; ++i ) { var parity = ((i+1) % 2 == 0 ? 'even' : 'odd'); html.push( '', '', '', '', '', '', '', '', '' ); } html.push( '
UpDown%StatusAddressClient
', (peer.isEncrypted ? 'Encrypted' : ''), '', ( peer.rateToPeer ? fmt.speedBps(peer.rateToPeer) : '' ), '', ( peer.rateToClient ? fmt.speedBps(peer.rateToClient) : '' ), '', Math.floor(peer.progress*100), '%', '', peer.flagStr, '', peer.address, '', peer.clientName, '
' ); } } 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( '
' ); if( torrents.length > 1 ) { html.push( '
', torrent.getName(), '
' ); } for( var i=0, tier; tier=torrent._trackerStats[i]; ++i ) { html.push( '
', 'Tier ', (i + 1), '
', '
    ' ); 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( '
  • ', tracker.host, '
    ', '
    ', '
    ', lastAnnounceStatusHash['label'], ': ', lastAnnounceStatusHash['value'], '
    ', '
    ', announceState, '
    ', '
    ', lastScrapeStatusHash['label'], ': ', lastScrapeStatusHash['value'], '
    ', '
    ', '', '', '', '
    Seeders:', (tracker.seederCount > -1 ? tracker.seederCount : na), '
    Leechers:', (tracker.leecherCount > -1 ? tracker.leecherCount : na), '
    Downloads:', (tracker.downloadCount > -1 ? tracker.downloadCount : na), '
  • ' ); } html.push( '
' ); } html.push( '
' ); } } 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