/* * Copyright © Dave Perrett and Malcolm Jarvis * 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() { // IE specific fixes here if ($.browser.msie) { try { document.execCommand("BackgroundImageCache", false, true); } catch(err) {} $('head').append(''); $('head').append(''); $('.dialog_container').css('height',$(window).height()+'px'); } // 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); }); $('#removedata_link').bind('click', function(e){ tr.removeDataClicked(e); }); $('#filter_all_link').parent().bind('click', function(e){ tr.showAllClicked(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); }); $('#prefs_save_button').bind('click', function(e) { tr.savePrefsClicked(e); return false;}); $('#prefs_cancel_button').bind('click', function(e){ tr.cancelPrefsClicked(e); return false; }); $('.inspector_tab').bind('click', function(e){ tr.inspectorTabClicked(e, this); }); if (iPhone) { $('#torrent_inspector').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 ); }); $('#open_link').bind('click', function(e){ tr.openTorrentClicked(e); }); $('#filter_toggle_link').bind('click', function(e){ tr.toggleFilterClicked(e); }); $('#inspector_link').bind('click', function(e){ tr.toggleInspectorClicked(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; }); this.setupSearchBox(); this.createContextMenu(); this.createSettingsMenu(); } this._torrent_list = $('#torrent_list')[0]; this._inspector_file_list = $('#inspector_file_list')[0]; // Setup the preference box this.setupPrefConstraints(); // Setup the prefs gui this.initializeSettings( ); // Get preferences & torrents from the daemon var tr = this; this.remote.loadDaemonPrefs( ); this.initalizeAllTorrents(); this.togglePeriodicRefresh( true ); }, 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; i").attr("src", arguments[i]); } }, /* * Set up the preference validation */ setupPrefConstraints: function() { // only allow integers for speed limit & port options $('div.preference input[@type=text]:not(#download_location)').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; } } }); }, /* * 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( this[Prefs._ShowInspector] ) this.showInspector( ); }, /* * 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( ); }, contextRemoveSelected: function( ) { this.removeSelectedTorrents( ); }, contextRemoveDataSelected: function( ) { this.removeSelectedTorrentsAndData( ); }, contextVerifySelected: function( ) { this.verifySelectedTorrents( ); }, contextToggleInspector: function( ) { this.toggleInspector( ); }, contextSelectAll: function( ) { this.selectAll( true ); }, contextDeselectAll: function( ) { this.deselectAll( true ); }, /* * 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_remove: function(e){ tr.contextRemoveSelected(e); }, context_removedata: function(e){ tr.contextRemoveDataSelected(e); }, context_verify: function(e){ tr.contextVerifySelected(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); } }; // 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 }); }, /* * 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(); }, /*-------------------------------------------- * * U T I L I T I E S * *--------------------------------------------*/ getAllTorrents: function() { return this._torrents; }, getVisibleTorrents: function() { var torrents = [ ]; for( var i=0, len=this._rows.length; i div:contains('N/A')").css('color', '#666'); return; } name = torrents.length == 1 ? torrents[0].name() : torrents.length+' Transfers Selected'; if( torrents.length == 1 ) { var t = torrents[0]; if( t._error_message ) { error = t._error_message ; } if( t._comment) { comment = t._comment ; } if( t._creator ) { creator = t._creator ; } hash = t.hash(); date_created = Math.formatTimestamp( t._creator_date ); } for(i = 0; i < torrents.length; ++i ) { var t = torrents[i]; sizeWhenDone += t._sizeWhenDone; sizeDone += t._sizeWhenDone - t._leftUntilDone; total_completed += t.completed(); total_verified += t._verified; total_size += t.size(); total_upload += t.uploadTotal(); total_download += t.downloadTotal(); total_upload_speed += t.uploadSpeed(); total_download_speed += t.downloadSpeed(); total_seeders += t.totalSeeders(); total_leechers += t.totalLeechers(); total_upload_peers += t.peersGettingFromUs(); total_download_peers += t.peersSendingToUs(); total_swarm_speed += t.swarmSpeed(); if( total_state == null ) total_state = t.stateStr(); else if ( total_state.search ( t.stateStr() ) == -1 ) total_state += '/' + t.stateStr(); var tracker = t._tracker; if( total_tracker == null ) total_tracker = tracker; else if ( total_tracker.search ( tracker ) == -1 ) total_tracker += ', ' + tracker; if( t._is_private ) have_private = true; else have_public = true; } var private_string = ''; if( have_private && have_public ) private_string = 'Mixed'; else if( have_private ) private_string = 'Private Torrent'; else if( have_public ) private_string = 'Public Torrent'; var ti = '#torrent_inspector_'; setInnerHTML( $(ti+'name')[0], name ); setInnerHTML( $(ti+'size')[0], torrents.length ? Math.formatBytes( total_size ) : 'N/A' ); setInnerHTML( $(ti+'tracker')[0], total_tracker.replace(/\//g, '/​') ); setInnerHTML( $(ti+'hash')[0], hash ); setInnerHTML( $(ti+'state')[0], total_state ); setInnerHTML( $(ti+'download_speed')[0], torrents.length ? Math.formatBytes( total_download_speed ) + '/s' : 'N/A' ); setInnerHTML( $(ti+'upload_speed')[0], torrents.length ? Math.formatBytes( total_upload_speed ) + '/s' : 'N/A' ); setInnerHTML( $(ti+'uploaded')[0], torrents.length ? Math.formatBytes( total_upload ) : 'N/A' ); setInnerHTML( $(ti+'downloaded')[0], torrents.length ? Math.formatBytes( total_download ) : 'N/A' ); setInnerHTML( $(ti+'ratio')[0], torrents.length ? Math.ratio( total_upload, total_download ) : 'N/A' ); setInnerHTML( $(ti+'total_seeders')[0], torrents.length ? total_seeders : 'N/A' ); setInnerHTML( $(ti+'total_leechers')[0], torrents.length ? total_leechers : 'N/A' ); setInnerHTML( $(ti+'swarm_speed')[0], torrents.length ? Math.formatBytes(total_swarm_speed) + '/s' : 'N/A' ); setInnerHTML( $(ti+'have')[0], torrents.length ? Math.formatBytes(total_completed) + ' (' + Math.formatBytes(total_verified) + ' verified)' : 'N/A' ); setInnerHTML( $(ti+'upload_to')[0], torrents.length ? total_upload_peers : 'N/A' ); setInnerHTML( $(ti+'download_from')[0], torrents.length ? total_download_peers : 'N/A' ); setInnerHTML( $(ti+'secure')[0], private_string ); setInnerHTML( $(ti+'creator_date')[0], date_created ); setInnerHTML( $(ti+'progress')[0], torrents.length ? Math.ratio( sizeDone*100, sizeWhenDone ) + '%' : 'N/A' ); setInnerHTML( $(ti+'comment')[0], comment.replace(/\//g, '/​') ); setInnerHTML( $(ti+'creator')[0], creator ); setInnerHTML( $(ti+'error')[0], error ); $(".inspector_row > div:contains('N/A')").css('color', '#666'); this.updateVisibleFileLists(); }, updateVisibleFileLists: function() { jQuery.each( this.getSelectedTorrents(), function() { this.showFileList(); } ); jQuery.each( this.getDeselectedTorrents(), function() { this.hideFileList(); } ); }, /* * 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'); 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( ); }, /* * Hide the inspector */ hideInspector: function() { $('#torrent_inspector').hide(); if (iPhone) { transmsision.deselectAll( ); $('body.inspector_showing').removeClass('inspector_showing'); 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 ); }, /* * 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 ); }, refreshTorrents: function() { var tr = this; this.remote.getUpdatedDataFor('recently-active', function(active, removed){ tr.updateTorrentsData(active, removed); }); }, updateTorrentsData: function( active, removed_ids ) { var tr = this; var new_torrent_ids = []; var refresh_files_for = []; jQuery.each( active, function() { var t = Torrent.lookup(tr._torrents, this.id); if (t){ t.refresh(this); if(t.isSelected()) refresh_files_for.push(t.id()); } else new_torrent_ids.push(this.id); } ); 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 ){ var tr = this; jQuery.each( torrents, function() { var t = Torrent.lookup(tr._torrents, this.id); if (t) t.refreshFileData(this); } ); }, initalizeAllTorrents: function(){ var tr = this; this.remote.getInitialDataFor( null ,function(torrents) { tr.addTorrents(torrents); } ); }, addTorrents: function( new_torrents ){ var tr = this; $.each( new_torrents, function(){ var torrent = this; tr._torrents.push( new Torrent( tr, torrent ) ); }); this.refilter(); }, deleteTorrents: function(torrent_ids){ if(typeof torrent_ids == 'undefined') return false; var tr = this; var removedAny = false; $.each( torrent_ids, function(index, id){ var torrent = Torrent.lookup(tr._torrents, id); if(torrent) { removedAny = true; var e = torrent.element(); if( e ) { var row_index = tr.getTorrentIndex(tr._rows, torrent); delete e._torrent; //remove circular refernce to help IE garbage collect tr._rows.splice(row_index, 1) e.remove(); } var pos = Torrent.indexOf( tr._torrents, torrent.id( ) ); torrent.hideFileList(); tr._torrents.splice( pos, 1 ); } }); return removedAny; }, /* * Set the alternating background colors for torrents */ setTorrentBgColors: function( ) { var rows = this.getVisibleRows( ); for( var i=0, len=rows.length; i