(trunk web) #3624 "Compact mode is very slow for large number of torrents" -- fixed.

This commit is contained in:
Jordan Lee 2011-08-16 18:49:26 +00:00
parent a1eab5b3ff
commit 485733c36a
9 changed files with 1036 additions and 1046 deletions

View File

@ -26,6 +26,8 @@
<script type="text/javascript" src="./javascript/transmission.remote.js"></script>
<script type="text/javascript" src="./javascript/transmission.js"></script>
<script type="text/javascript" src="./javascript/torrent.js"></script>
<script type="text/javascript" src="./javascript/torrent-renderer.js"></script>
<script type="text/javascript" src="./javascript/file-row.js"></script>
<script type="text/javascript" src="./javascript/dialog.js"></script>
<script type="text/javascript" src="./javascript/formatter.js"></script>
<title>Transmission Web Interface</title>
@ -194,12 +196,12 @@
</div><!-- id="inspector_tab_trackers_container" -->
<div style="display:none;" class="inspector_container" id="inspector_tab_files_container">
<div id="inspector_file_list">
<ul id="select_all_button_container">
<li id="files_deselect_all" class="select_all_button">Deselect All</li>
<li id="files_select_all" class="select_all_button">Select All</li>
</ul>
<div id="select_all_button_container">
<div id="files_deselect_all" class="select_all_button">Deselect All</div>
<div id="files_select_all" class="select_all_button">Select All</div>
</div>
<ul id="inspector_file_list">
</ul>
</div><!-- id="inspector_tab_files_container" -->
</div>

View File

@ -13,7 +13,7 @@ var resizeTimer = null;
// actually 523.10.3). We need 3.1 for CSS animation (dialog sheets) but as it
// degrades gracefully let's not worry too much.
var Safari3 = testSafari3();
var iPhone = RegExp("(iPhone|iPod)").test(navigator.userAgent);
var iPhone = RegExp("(iPhone|iPod|Android)").test(navigator.userAgent);
if (iPhone) var scroll_timeout;
if(!Array.indexOf){

175
web/javascript/file-row.js Normal file
View File

@ -0,0 +1,175 @@
/*
* Copyright © Jordan Lee
* This code is licensed under the GPL version 2.
* <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
*/
function FileRow( controller, torrent, i )
{
this.initialize( controller, torrent, i );
}
FileRow.prototype =
{
initialize: function( controller, torrent, i )
{
this._torrent = torrent;
this._index = i;
this.createRow( torrent, i );
},
getTorrent: function( )
{
return this._torrent;
},
getIndex: function( )
{
return this._index;
},
readAttributes: function(file)
{
if( file.index !== undefined && file.index !== this._index ) {
this._index = file.index;
this._dirty = true;
}
if( file.bytesCompleted !== undefined && file.bytesCompleted !== this._done ) {
this._done = file.bytesCompleted;
this._dirty = true;
}
if( file.length !== undefined && file.length !== this._size ) {
this._size = file.length;
this._dirty = true;
}
if( file.priority !== undefined && file.priority !== this._prio ) {
this._prio = file.priority;
this._dirty = true;
}
if( file.wanted !== undefined && file.wanted !== this._wanted ) {
this._wanted = file.wanted;
this._dirty = true;
}
},
refreshWantedHTML: function() {
var e = this.getElement();
var c = [ e.classNameConst ];
if(!this._wanted) { c.push( 'skip' ); }
if(this.isDone()) { c.push( 'complete' ); }
e.className = c.join(' ');
},
refreshPriorityHTML: function() {
var e = this._priority_control;
var c = [ e.classNameConst ];
switch( this._prio ) {
case 1 : c.push( 'high' ); break;
case -1 : c.push( 'low' ); break;
default : c.push( 'normal' ); break;
}
e.className = c.join(' ');
},
refreshProgressHTML: function() {
var pct = 100 * (this._size ? ( this._done / this._size ) : 1.0);
var c = [ Transmission.fmt.size(this._done),
' of ',
Transmission.fmt.size(this._size),
' (',
Transmission.fmt.percentString(pct),
'%)' ].join('');
setInnerHTML(this._progress[0], c);
},
refreshHTML: function() {
if( this._dirty ) {
this._dirty = false;
this.refreshProgressHTML();
this.refreshWantedHTML();
this.refreshPriorityHTML();
}
},
refresh: function( )
{
var i = this.getIndex( );
var t = this.getTorrent( );
this.readAttributes( t._file_model[i] );
this.refreshHTML();
},
isDone: function () {
return this._done >= this._size;
},
isEditable: function () {
return (this.getTorrent()._file_model.length>1) && !this.isDone();
},
createRow: function( torrent, i )
{
var me = this;
var file = torrent._file_model[i];
var name = file.name.substring (file.name.lastIndexOf('/')+1);
var root = document.createElement('li');
root.id = 't' + this._torrent.id() + 'f' + this._index;
root.classNameConst = 'inspector_torrent_file_list_entry ' + ((i%2)?'odd':'even');
root.className = root.classNameConst;
var wanted_div = document.createElement('div');
wanted_div.className = "file_wanted_control";
$(wanted_div).bind('click',function(e){ me.fireWantedChanged( !me._wanted ); });
var pri_div = document.createElement('div');
pri_div.classNameConst = "file_priority_control";
pri_div.className = pri_div.classNameConst;
$(pri_div).bind('click',function(ev){
var x = ev.pageX;
var e = ev.target;
while (e !== null) {
x -= e.offsetLeft;
e = e.offsetParent;
}
var prio;
if(iPhone) {
if( x < 8 ) prio = -1;
else if( x < 27 ) prio = 0;
else prio = 1;
} else {
if( x < 12 ) prio = -1;
else if( x < 23 ) prio = 0;
else prio = 1;
}
me.firePriorityChanged( prio );
});
var file_div = document.createElement('div');
file_div.className = "inspector_torrent_file_list_entry_name";
file_div.innerHTML = name.replace(/([\/_\.])/g, "$1&#8203;");
var prog_div = document.createElement('div');
prog_div.className = "inspector_torrent_file_list_entry_progress";
root.appendChild(wanted_div);
root.appendChild(pri_div);
root.appendChild(file_div);
root.appendChild(prog_div);
this._element = root;
this._priority_control = pri_div;
this._progress = $(prog_div);
this.refresh();
return root;
},
getElement: function( )
{
return this._element;
},
fireWantedChanged: function( do_want )
{
$(this).trigger('wantedToggled',[ this, do_want ]);
},
firePriorityChanged: function( priority )
{
$(this).trigger('priorityToggled',[ this, priority ]);
}
};

View File

@ -0,0 +1,370 @@
/*
* Copyright © Jordan Lee
* This code is licensed under the GPL version 2.
* <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
*/
/****
*****
*****
****/
function TorrentRendererHelper()
{
}
TorrentRendererHelper.getProgressInfo = function( controller, t )
{
var seed_ratio_limit = t.seedRatioLimit( controller );
var pct = 0;
if( t.needsMetaData( ) )
pct = t._metadataPercentComplete * 100;
else if( !t.isDone( ) )
pct = Math.round( t.getPercentDone() * 100 );
else if( seed_ratio_limit > 0 )
pct = Math.round( t._upload_ratio * 100 / seed_ratio_limit );
else
pct = 100;
var extra;
if( t.isStopped( ) )
extra = 'paused';
else if( t.isSeeding( ) )
extra = 'seeding';
else if( t.needsMetaData( ) )
extra = 'magnet';
else
extra = 'leeching';
return {
percent: pct,
complete: [ 'torrent_progress_bar', 'complete', extra ].join(' '),
incomplete: [ 'torrent_progress_bar', 'incomplete', extra ].join(' ')
};
}
TorrentRendererHelper.renderProgressbar = function( controller, t, complete, incomplete )
{
var info = TorrentRendererHelper.getProgressInfo( controller, t );
var e;
e = complete;
e.style.width = '' + info.percent + "%";
e.className = info.complete;
e.style.display = info.percent<=0 ? 'none' : 'block';
e = incomplete;
e.className = info.incomplete;
e.style.display = info.percent>=100 ? 'none' : 'block';
}
TorrentRendererHelper.formatUL = function( t )
{
return 'UL: ' + Transmission.fmt.speedBps( t.uploadSpeed( ) );
}
TorrentRendererHelper.formatDL = function( t )
{
return 'DL: ' + Transmission.fmt.speedBps( t.downloadSpeed( ) );
}
/****
*****
*****
****/
function TorrentRendererFull()
{
}
TorrentRendererFull.prototype =
{
createRow: function( )
{
var root = document.createElement( 'li' );
root.className = 'torrent';
var name = document.createElement( 'div' );
name.className = 'torrent_name';
var peers = document.createElement( 'div' );
peers.className = 'torrent_peer_details';
var complete = document.createElement( 'div' );
complete.className = 'torrent_progress_bar complete';
var incomplete = document.createElement( 'div' );
incomplete.className = 'torrent_progress_bar incomplete';
var progressbar = document.createElement( 'div' );
progressbar.className = 'torrent_progress_bar_container full';
progressbar.appendChild( complete );
progressbar.appendChild( incomplete );
var details = document.createElement( 'div' );
details.className = 'torrent_progress_details';
var image = document.createElement( 'div' );
var button = document.createElement( 'a' );
button.appendChild( image );
root.appendChild( name );
root.appendChild( peers );
root.appendChild( button );
root.appendChild( progressbar );
root.appendChild( details );
root._name_container = name;
root._peer_details_container = peers;
root._progress_details_container = details;
root._progress_complete_container = complete;
root._progress_incomplete_container = incomplete;
root._pause_resume_button_image = image;
root._toggle_running_button = button;
return root;
},
getPeerDetails: function( t )
{
var err;
if(( err = t.getErrorMessage()))
return err;
if( t.isDownloading( ) )
return [ 'Downloading from',
t.peersSendingToUs(),
'of',
t._peers_connected,
'peers',
'-',
TorrentRendererHelper.formatDL(t),
TorrentRendererHelper.formatUL(t) ].join(' ');
if( t.isSeeding( ) )
return [ 'Seeding to',
t.peersGettingFromUs(),
'of',
t._peers_connected,
'peers',
'-',
TorrentRendererHelper.formatUL(t) ].join(' ');
if( t.state() === Torrent._StatusCheck )
return [ 'Verifying local data (',
Transmission.fmt.percentString( 100.0 * t._recheckProgress ),
'% tested)' ].join('');
return t.stateStr( );
},
getProgressDetails: function( controller, t )
{
if( t.needsMetaData() ) {
var percent = 100 * t._metadataPercentComplete;
return [ "Magnetized transfer - retrieving metadata (",
Transmission.fmt.percentString( percent ),
"%)" ].join('');
}
var c;
var is_done = ( t.isDone( ) )
|| ( t.state() === Torrent._StatusSeeding );
if( is_done ) {
if( t._size == t._sizeWhenDone ) // seed: '698.05 MiB'
c = [ Transmission.fmt.size( t._size ) ];
else // partial seed: '127.21 MiB of 698.05 MiB (18.2%)'
c = [ Transmission.fmt.size( t._sizeWhenDone ),
' of ',
Transmission.fmt.size( t._size ),
' (', t.getPercentDoneStr, '%)' ];
// append UL stats: ', uploaded 8.59 GiB (Ratio: 12.3)'
c.push( ', uploaded ',
Transmission.fmt.size( t._upload_total ),
' (Ratio ',
Transmission.fmt.ratioString( t._upload_ratio ),
')' );
} else { // not done yet
c = [ Transmission.fmt.size( t._sizeWhenDone - t._leftUntilDone ),
' of ', Transmission.fmt.size( t._sizeWhenDone ),
' (', t.getPercentDoneStr(), '%)' ];
}
// maybe append eta
if( t.isActive() && ( !is_done || t.seedRatioLimit(controller)>0 ) ) {
c.push(' - ');
if (t._eta < 0 || this._eta >= Torrent._InfiniteTimeRemaining )
c.push( 'remaining time unknown' );
else
c.push( Transmission.fmt.timeInterval(t._eta),
' remaining' );
}
return c.join('');
},
render: function( controller, t, root )
{
// name
setInnerHTML( root._name_container, t.name() );
// progressbar
TorrentRendererHelper.renderProgressbar(
controller, t,
root._progress_complete_container,
root._progress_incomplete_container );
// peer details
var has_error = t._error !== Torrent._ErrNone;
var e = root._peer_details_container;
$(e).toggleClass('error',has_error);
setInnerHTML( e, this.getPeerDetails( t ) );
// progress details
e = root._progress_details_container;
setInnerHTML( e, this.getProgressDetails( controller, t ) );
// pause/resume button
var is_stopped = t.state() === Torrent._StatusStopped;
e = root._pause_resume_button_image;
e.alt = is_stopped ? 'Resume' : 'Pause';
e.className = is_stopped ? 'torrent_resume' : 'torrent_pause';
}
};
/****
*****
*****
****/
function TorrentRendererCompact()
{
}
TorrentRendererCompact.prototype =
{
createRow: function( )
{
var complete = document.createElement( 'div' );
complete.className = 'torrent_progress_bar complete';
var incomplete = document.createElement( 'div' );
incomplete.className = 'torrent_progress_bar incomplete';
var progressbar = document.createElement( 'div' );
progressbar.className = 'torrent_progress_bar_container compact';
progressbar.appendChild( complete );
progressbar.appendChild( incomplete );
var details = document.createElement( 'div' );
details.className = 'torrent_peer_details compact';
var name = document.createElement( 'div' );
name.className = 'torrent_name';
var root = document.createElement( 'li' );
root.appendChild( progressbar );
root.appendChild( details );
root.appendChild( name );
root.className = 'torrent compact';
root._progress_complete_container = complete;
root._progress_incomplete_container = incomplete;
root._details_container = details;
root._name_container = name;
return root;
},
getPeerDetails: function( t )
{
var c;
if(( c = t.getErrorMessage()))
return c;
if( t.isDownloading( ) )
return [ TorrentRendererHelper.formatDL(t),
TorrentRendererHelper.formatUL(t) ].join(' ');
if( t.isSeeding( ) )
return TorrentRendererHelper.formatUL(t);
return t.stateStr( );
},
render: function( controller, t, root )
{
// name
var is_stopped = t.state() === Torrent._StatusStopped;
var e = root._name_container;
$(e).toggleClass( 'paused', is_stopped );
setInnerHTML( e, t.name() );
// peer details
var has_error = t._error !== Torrent._ErrNone;
e = root._details_container;
$(e).toggleClass('error', has_error );
setInnerHTML( e, this.getPeerDetails( t ) );
// progressbar
TorrentRendererHelper.renderProgressbar(
controller, t,
root._progress_complete_container,
root._progress_incomplete_container );
}
};
/****
*****
*****
****/
function TorrentRow( controller, generator )
{
this.initialize( controller, generator );
}
TorrentRow.prototype =
{
initialize: function( controller, generator ) {
this._generator = generator;
var root = generator.createRow( );
this._element = root;
$(root).bind('dblclick', function(e) { controller.toggleInspector(); });
},
getElement: function( ) {
return this._element;
},
render: function( controller ) {
var tor = this.getTorrent( );
if( tor !== null )
this._generator.render( controller, tor, this.getElement( ) );
},
isSelected: function( ) {
return this.getElement().className.indexOf('selected') != -1;
},
setSelected: function( flag ) {
$(this.getElement()).toggleClass( 'selected', flag );
},
getToggleRunningButton: function( ) {
return this.getElement()._toggle_running_button;
},
setVisible: function( visible ) {
this.getElement().style.display = visible ? 'block' : 'none';
if( !visible )
this.setSelected( false );
},
isVisible: function( visible ) {
return this.getElement().style.display === 'block';
},
setTorrent: function( controller, t ) {
if( this._torrent !== t ) {
if( this._torrent )
$(this).unbind('dataChanged.renderer');
if(( this._torrent = t ))
$(this).bind('dataChanged.renderer',this.render(controller));
}
},
getTorrent: function() {
return this._torrent;
},
isEven: function() {
return this.getElement().className.indexOf('even') != -1;
},
setEven: function( even ) {
if( this.isEven() != even )
$(this.getElement()).toggleClass('even', even);
}
};

View File

@ -6,8 +6,8 @@
* Class Torrent
*/
function Torrent( transferListParent, fileListParent, controller, data) {
this.initialize( transferListParent, fileListParent, controller, data);
function Torrent( controller, data) {
this.initialize( controller, data);
}
// Constants
@ -19,13 +19,6 @@ Torrent._StatusDownload = 4; /* downloading */
Torrent._StatusSeedWait = 5; /* queeud to seed */
Torrent._StatusSeed = 6; /* seeding */
/*
Torrent._StatusWaitingToCheck = 1;
Torrent._StatusChecking = 2;
Torrent._StatusDownloading = 4;
Torrent._StatusSeeding = 8;
*/
Torrent._InfiniteTimeRemaining = 215784000; // 999 Hours - may as well be infinite
Torrent._RatioUseGlobal = 0;
@ -85,106 +78,16 @@ Torrent.prototype =
/*
* Constructor
*/
initialize: function( transferListParent, fileListParent, controller, data) {
initialize: function( controller, data) {
this._id = data.id;
this._hashString = data.hashString;
this._sizeWhenDone = data.sizeWhenDone;
this._trackerStats = this.buildTrackerStats(data.trackerStats);
this._file_model = [ ];
this._file_view = [ ];
this.initMetaData( data );
// Create a new <li> element
var top_e = document.createElement( 'li' );
top_e.className = 'torrent';
top_e.id = 'torrent_' + data.id;
top_e._torrent = this;
var element = $(top_e);
$(element).bind('dblclick', function(e) { transmission.toggleInspector(); });
element._torrent = this;
element._id = this._id;
this._element = element;
this._controller = controller;
controller._rows.push( element );
// Create the 'name' <div>
var e = document.createElement( 'div' );
e.className = 'torrent_name';
top_e.appendChild( e );
element._name_container = e;
// Create the 'peer details' <div>
e = document.createElement( 'div' );
e.className = 'torrent_peer_details';
top_e.appendChild( e );
element._peer_details_container = e;
//Create a progress bar container
top_a = document.createElement( 'div' );
top_a.className = 'torrent_progress_bar_container';
element._progress_bar_container = top_a;
// Create the 'in progress' bar
e = document.createElement( 'div' );
e.className = 'torrent_progress_bar incomplete';
e.style.width = '0%';
top_a.appendChild( e );
element._progress_complete_container = e;
// Create the 'incomplete' bar (initially hidden)
e = document.createElement( 'div' );
e.className = 'torrent_progress_bar incomplete';
e.style.display = 'none';
top_a.appendChild( e );
element._progress_incomplete_container = e;
//Add the progress bar container to the torrent
top_e.appendChild(top_a);
// Add the pause/resume button - don't specify the
// image or alt text until the 'refresh()' function
// (depends on torrent state)
var image = document.createElement( 'div' );
image.className = 'torrent_pause';
e = document.createElement( 'a' );
e.appendChild( image );
top_e.appendChild( e );
element._pause_resume_button_image = image;
if (!iPhone) $(e).bind('click', function(e) { element._torrent.clickPauseResumeButton(e); });
// Create the 'progress details' <div>
e = document.createElement( 'div' );
e.className = 'torrent_progress_details';
top_e.appendChild( e );
element._progress_details_container = e;
// Set the torrent click observer
element.bind('click', function(e){ element._torrent.clickTorrent(e) });
// Safari hack - first torrent needs to be moved down for some reason. Seems to be ok when
// using <li>'s in straight html, but adding through the DOM gets a bit odd.
if ($.browser.safari)
this._element.css('margin-top', '7px');
this.initializeTorrentFilesInspectorGroup( fileListParent );
// Update all the labels etc
this.refresh(data);
// insert the element
transferListParent.appendChild(top_e);
},
initializeTorrentFilesInspectorGroup: function( fileListParent ) {
var e = document.createElement( 'ul' );
e.className = 'inspector_torrent_file_list inspector_group';
e.style.display = 'none';
fileListParent.appendChild( e );
this._fileList = e;
},
fileList: function() {
return $(this._fileList);
},
buildTrackerStats: function(trackerStats) {
@ -221,19 +124,7 @@ Torrent.prototype =
*
*--------------------------------------------*/
/* Return the DOM element for this torrent (a <LI> element) */
element: function() {
return this._element;
},
setElement: function( element ) {
this._element = element;
element._torrent = this;
element[0]._torrent = this;
this.refreshHTML( );
},
activity: function() { return this._download_speed + this._upload_speed; },
activity: function() { return this.downloadSpeed() + this.uploadSpeed(); },
comment: function() { return this._comment; },
completed: function() { return this._completed; },
creator: function() { return this._creator; },
@ -246,14 +137,14 @@ Torrent.prototype =
|| this.peersSendingToUs() > 0
|| this.webseedsSendingToUs() > 0
|| this.state() == Torrent._StatusCheck; },
isStopped: function() { return this.state() === Torrent._StatusStopped; },
isActive: function() { return this.state() != Torrent._StatusStopped; },
isDownloading: function() { return this.state() == Torrent._StatusDownload; },
isFinished: function() { return this._isFinishedSeeding; },
isDone: function() { return this._leftUntilDone < 1; },
isSeeding: function() { return this.state() == Torrent._StatusSeed; },
name: function() { return this._name; },
queuePosition: function() { return this._queue_position; },
isQueued: function() { return ( this.state() == Torrent._StatusSeedWait )
|| ( this.state() == Torrent._StatusDownloadWait ); },
webseedsSendingToUs: function() { return this._webseeds_sending_to_us; },
peersSendingToUs: function() { return this._peers_sending_to_us; },
peersGettingFromUs: function() { return this._peers_getting_from_us; },
@ -283,96 +174,23 @@ Torrent.prototype =
trackerStats: function() { return this._trackerStats; },
uploadSpeed: function() { return this._upload_speed; },
uploadTotal: function() { return this._upload_total; },
showFileList: function() {
if(this.fileList().is(':visible'))
return;
this.ensureFileListExists();
this.refreshFileView();
this.fileList().show();
},
hideFileList: function() { this.fileList().hide(); },
seedRatioLimit: function(){
seedRatioLimit: function(controller){
switch( this._seed_ratio_mode ) {
case Torrent._RatioUseGlobal: return this._controller.seedRatioLimit();
case Torrent._RatioUseGlobal: return controller.seedRatioLimit();
case Torrent._RatioUseLocal: return this._seed_ratio_limit;
default: return -1;
}
},
getErrorMessage: function() {
if( this._error == Torrent._ErrTrackerWarning )
return 'Tracker returned a warning: ' + this._error_string;
if( this._error == Torrent._ErrTrackerError )
return 'Tracker returned an error: ' + this._error_string;
if( this._error == Torrent._ErrLocalError )
return 'Error: ' + this._error_string;
return null;
},
/*--------------------------------------------
*
* E V E N T F U N C T I O N S
*
*--------------------------------------------*/
/*
* Process a click event on this torrent
*/
clickTorrent: function( event )
{
// Prevents click carrying to parent element
// which deselects all on click
event.stopPropagation();
// but still hide the context menu if it is showing
$('#jqContextMenu').hide();
var torrent = this;
// 'Apple' button emulation on PC :
// Need settable meta-key and ctrl-key variables for mac emulation
var meta_key = event.metaKey;
var ctrl_key = event.ctrlKey;
if (event.ctrlKey && navigator.appVersion.toLowerCase().indexOf("mac") == -1) {
meta_key = true;
ctrl_key = false;
}
// Shift-Click - Highlight a range between this torrent and the last-clicked torrent
if (iPhone) {
if ( torrent.isSelected() )
torrent._controller.showInspector();
torrent._controller.setSelectedTorrent( torrent, true );
} else if (event.shiftKey) {
torrent._controller.selectRange( torrent, true );
// Need to deselect any selected text
window.focus();
// Apple-Click, not selected
} else if (!torrent.isSelected() && meta_key) {
torrent._controller.selectTorrent( torrent, true );
// Regular Click, not selected
} else if (!torrent.isSelected()) {
torrent._controller.setSelectedTorrent( torrent, true );
// Apple-Click, selected
} else if (torrent.isSelected() && meta_key) {
torrent._controller.deselectTorrent( torrent, true );
// Regular Click, selected
} else if (torrent.isSelected()) {
torrent._controller.setSelectedTorrent( torrent, true );
}
torrent._controller.setLastTorrentClicked(torrent);
},
/*
* Process a click event on the pause/resume button
*/
clickPauseResumeButton: function( event )
{
// prevent click event resulting in selection of torrent
event.stopPropagation();
// either stop or start the torrent
var torrent = this;
if( torrent.isActive( ) )
torrent._controller.stopTorrent( torrent );
else
torrent._controller.startTorrent( torrent );
},
/*--------------------------------------------
*
@ -380,22 +198,18 @@ Torrent.prototype =
*
*--------------------------------------------*/
refreshMetaData: function(data) {
fireDataChanged: function()
{
$(this).trigger('dataChanged',[]);
},
refreshMetaData: function(data)
{
this.initMetaData( data );
this.ensureFileListExists();
this.refreshFileView();
this.refreshHTML( );
this.fireDataChanged();
},
refresh: function(data) {
this.refreshData( data );
this.refreshHTML( );
},
/*
* Refresh display
*/
refreshData: function(data)
refresh: function(data)
{
if( this.needsMetaData() && ( data.metadataPercentComplete >= 1 ) )
transmission.refreshMetaData( [ this._id ] );
@ -430,6 +244,8 @@ Torrent.prototype =
if (data.fileStats)
this.refreshFileModel( data );
this.fireDataChanged();
},
refreshFileModel: function(data) {
@ -444,275 +260,6 @@ Torrent.prototype =
}
},
getErrorMessage: function()
{
if( this._error == Torrent._ErrTrackerWarning )
return 'Tracker returned a warning: ' + this._error_string;
if( this._error == Torrent._ErrTrackerError )
return 'Tracker returned an error: ' + this._error_string;
if( this._error == Torrent._ErrLocalError )
return 'Error: ' + this._error_string;
return null;
},
formatUL: function() {
return 'UL: ' + Transmission.fmt.speedBps(this._upload_speed);
},
formatDL: function() {
return 'DL: ' + Transmission.fmt.speedBps(this._download_speed);
},
getPeerDetails: function()
{
var c;
var compact_mode = this._controller[Prefs._CompactDisplayState];
if(( c = this.getErrorMessage( )))
return c;
var st = this.state( );
switch( st )
{
case Torrent._StatusStopped:
case Torrent._StatusCheckWait:
case Torrent._StatusDownloadWait:
case Torrent._StatusSeedWait:
c = this.stateStr( );
break;
case Torrent._StatusDownload:
var a = [ ];
if(!compact_mode)
a.push( 'Downloading from', this.peersSendingToUs(), 'of', this._peers_connected, 'peers', '-' );
a.push( this.formatDL(), this.formatUL() );
c = a.join(' ');
break;
case Torrent._StatusSeed:
if(compact_mode){
c = this.formatUL();
} else {
// 'Seeding to 13 of 22 peers - UL: 36.2 KiB/s'
c = [ 'Seeding to', this.peersGettingFromUs(), 'of', this._peers_connected, 'peers', '-', this.formatUL() ].join(' ');
}
break;
case Torrent._StatusCheck:
// 'Verifying local data (40% tested)'
c = [ 'Verifying local data (', Transmission.fmt.percentString( 100.0 * this._recheckProgress ), '% tested)' ].join('');
break;
}
return c;
},
refreshHTML: function() {
var c;
var e;
var progress_details;
var root = this._element;
var MaxBarWidth = 100; // reduce this to make the progress bar shorter (%)
var compact_mode = this._controller[Prefs._CompactDisplayState];
var compact = '';
if(compact_mode){
compact = ' compact';
root._peer_details_container.style.display = 'none';
} else {
root._peer_details_container.style.display = 'block';
}
root._progress_details_container.className = 'torrent_progress_details'+compact
root._progress_bar_container.className = 'torrent_progress_bar_container'+compact;
root._name_container.className = 'torrent_name'+compact;
setInnerHTML( root._name_container, this._name );
// Add the progress bar
var notDone = this._leftUntilDone > 0;
// Fix for situation
// when a verifying/downloading torrent gets state seeding
if( this._state === Torrent._StatusSeeding )
notDone = false ;
if( this.needsMetaData() ){
var metaPercentComplete = this._metadataPercentComplete * 100;
progress_details = [ "Magnetized transfer - retrieving metadata (",
Transmission.fmt.percentString( metaPercentComplete ),
"%)" ].join('');
var empty = "";
if(metaPercentComplete == 0)
empty = "empty";
root._progress_complete_container.style.width = metaPercentComplete + "%";
root._progress_complete_container.className = 'torrent_progress_bar in_progress meta ' + empty+compact;
root._progress_incomplete_container.style.width = 100 - metaPercentComplete + "%"
root._progress_incomplete_container.className = 'torrent_progress_bar incomplete compact meta'+compact;
root._progress_incomplete_container.style.display = 'block';
}
else if( notDone )
{
// Create the 'progress details' label
// Eg: '101 MiB of 631 MiB (16.02%) - 2 hr remaining'
c = [ Transmission.fmt.size( this._sizeWhenDone - this._leftUntilDone ),
' of ', Transmission.fmt.size( this._sizeWhenDone ),
' (', this.getPercentDoneStr(), '%)' ];
if( this.isActive( ) ) {
c.push( ' - ' );
if (this._eta < 0 || this._eta >= Torrent._InfiniteTimeRemaining )
c.push( 'remaining time unknown' );
else
c.push( Transmission.fmt.timeInterval(this._eta) + ' remaining' );
}
progress_details = c.join('');
// Figure out the percent completed
var css_completed_width = ( this.getPercentDone() * MaxBarWidth ).toTruncFixed( 2 );
// Update the 'in progress' bar
e = root._progress_complete_container;
c = [ 'torrent_progress_bar'+compact,
this.isActive() ? 'in_progress' : 'incomplete_stopped' ];
if(css_completed_width === 0) { c.push( 'empty' ); }
e.className = c.join(' ');
e.style.width = css_completed_width + '%';
// Update the 'incomplete' bar
e = root._progress_incomplete_container;
e.className = 'torrent_progress_bar incomplete'
e.style.width = (MaxBarWidth - css_completed_width) + '%';
e.style.display = 'block';
}
else
{
// Create the 'progress details' label
if( this._size == this._sizeWhenDone )
{
// seed: '698.05 MiB'
c = [ Transmission.fmt.size( this._size ) ];
}
else
{
// partial seed: '127.21 MiB of 698.05 MiB (18.2%)'
c = [ Transmission.fmt.size( this._sizeWhenDone ), ' of ', Transmission.fmt.size( this._size ),
' (', Transmission.fmt.percentString( 100.0 * this._sizeWhenDone / this._size ), '%)' ];
}
// append UL stats: ', uploaded 8.59 GiB (Ratio: 12.3)'
c.push( ', uploaded ', Transmission.fmt.size( this._upload_total ),
' (Ratio ', Transmission.fmt.ratioString( this._upload_ratio ), ')' );
// maybe append remaining time
if( this.isActive( ) && this.seedRatioLimit( ) > 0 )
{
c.push(' - ');
if (this._eta < 0 || this._eta >= Torrent._InfiniteTimeRemaining )
c.push( 'remaining time unknown' );
else
c.push( Transmission.fmt.timeInterval(this._eta), ' remaining' );
}
progress_details = c.join('');
var status = this.isActive() ? 'complete' : 'complete_stopped';
if(this.isActive() && this.seedRatioLimit() > 0){
status = 'complete seeding'
var seedRatioRatio = this._upload_ratio / this.seedRatioLimit();
var seedRatioPercent = Math.round( seedRatioRatio * 100 * MaxBarWidth ) / 100;
// Set progress to percent seeded
root._progress_complete_container.style.width = seedRatioPercent + '%';
// Update the 'incomplete' bar
root._progress_incomplete_container.className = 'torrent_progress_bar incomplete seeding'
root._progress_incomplete_container.style.display = 'block';
root._progress_incomplete_container.style.width = MaxBarWidth - seedRatioPercent + '%';
}
else
{
// Hide the 'incomplete' bar
root._progress_incomplete_container.className = 'torrent_progress_bar incomplete'
root._progress_incomplete_container.style.display = 'none';
// Set progress to maximum
root._progress_complete_container.style.width = MaxBarWidth + '%';
}
// Update the 'in progress' bar
e = root._progress_complete_container;
e.className = 'torrent_progress_bar ' + status;
}
var hasError = this.getErrorMessage( ) != undefined;
// Update the progress details
if(compact_mode){
progress_details = this.getPeerDetails();
$(root._progress_details_container).toggleClass('error',hasError);
} else {
$(root._peer_details_container).toggleClass('error',hasError);
}
setInnerHTML( root._progress_details_container, progress_details );
if( compact ){
var width = root._progress_details_container.offsetLeft - root._name_container.offsetLeft;
root._name_container.style.width = width + 'px';
}
else {
root._name_container.style.width = '100%';
}
// Update the peer details and pause/resume button
e = root._pause_resume_button_image;
if ( this.state() === Torrent._StatusStopped ) {
e.alt = 'Resume';
e.className = "torrent_resume"+compact;
} else {
e.alt = 'Pause';
e.className = "torrent_pause"+compact;
}
setInnerHTML( root._peer_details_container, this.getPeerDetails( ) );
this.refreshFileView( );
},
refreshFileView: function() {
if( this._file_view.length )
for( var i=0; i<this._file_model.length; ++i )
this._file_view[i].update( this._file_model[i] );
},
ensureFileListExists: function() {
if( this._file_view.length == 0 ) {
if(this._file_model.length == 1)
this._fileList.className += ' single_file';
var v, e;
for( var i=0; i<this._file_model.length; ++i ) {
v = new TorrentFile( this._file_model[i] );
this._file_view[i] = v;
e = v.domElement( );
e.className = (i % 2 ? 'even' : 'odd') + ' inspector_torrent_file_list_entry';
this._fileList.appendChild( e );
}
}
},
deleteFiles: function(){
if (this._fileList)
$(this._fileList).remove();
},
/*
* Return true if this torrent is selected
*/
isSelected: function() {
return this.element()[0].className.indexOf('selected') != -1;
},
/**
* @param filter one of Prefs._Filter*
* @param search substring to look for, or null
@ -862,208 +409,3 @@ Torrent.sortTorrents = function( torrents, sortMethod, sortDirection )
return torrents;
};
/**
* @brief fast binary search to find a torrent
* @param torrents an array of torrents sorted by Id
* @param id the id to search for
* @return the index, or -1
*/
Torrent.indexOf = function( torrents, id )
{
var low = 0;
var high = torrents.length;
while( low < high ) {
var mid = Math.floor( ( low + high ) / 2 );
if( torrents[mid].id() < id )
low = mid + 1;
else
high = mid;
}
if( ( low < torrents.length ) && ( torrents[low].id() == id ) ) {
return low;
} else {
return -1; // not found
}
};
function TorrentFile(file_data) {
this.initialize(file_data);
}
TorrentFile.prototype = {
initialize: function(file_data) {
this._dirty = true;
this._torrent = file_data.torrent;
this._index = file_data.index;
var name = file_data.name.substring (file_data.name.lastIndexOf('/')+1);
this.readAttributes(file_data);
var li = document.createElement('li');
li.id = 't' + this._torrent.id() + 'f' + this._index;
li.classNameConst = 'inspector_torrent_file_list_entry ' + ((this._index%2)?'odd':'even');
li.className = li.classNameConst;
var wanted_div = document.createElement('div');
wanted_div.className = "file_wanted_control";
var pri_div = document.createElement('div');
pri_div.classNameConst = "file_priority_control";
pri_div.className = pri_div.classNameConst;
var file_div = document.createElement('div');
file_div.className = "inspector_torrent_file_list_entry_name";
file_div.innerHTML = name.replace(/([\/_\.])/g, "$1&#8203;");
var prog_div = document.createElement('div');
prog_div.className = "inspector_torrent_file_list_entry_progress";
li.appendChild(wanted_div);
li.appendChild(pri_div);
li.appendChild(file_div);
li.appendChild(prog_div);
this._element = li;
this._priority_control = pri_div;
this._progress = $(prog_div);
},
update: function(file_data) {
this.readAttributes(file_data);
this.refreshHTML();
},
isDone: function () {
return this._done >= this._size;
},
isEditable: function () {
return (this._torrent._file_model.length>1) && !this.isDone();
},
readAttributes: function(file_data) {
if( file_data.index !== undefined && file_data.index !== this._index ) {
this._index = file_data.index;
this._dirty = true;
}
if( file_data.bytesCompleted !== undefined && file_data.bytesCompleted !== this._done ) {
this._done = file_data.bytesCompleted;
this._dirty = true;
}
if( file_data.length !== undefined && file_data.length !== this._size ) {
this._size = file_data.length;
this._dirty = true;
}
if( file_data.priority !== undefined && file_data.priority !== this._prio ) {
this._prio = file_data.priority;
this._dirty = true;
}
if( file_data.wanted !== undefined && file_data.wanted !== this._wanted ) {
this._wanted = file_data.wanted;
this._dirty = true;
}
},
element: function() {
return $(this._element);
},
domElement: function() {
return this._element;
},
setPriority: function(prio) {
if (this.isEditable()) {
var cmd;
switch( prio ) {
case 1: cmd = 'priority-high'; break;
case -1: cmd = 'priority-low'; break;
default: cmd = 'priority-normal'; break;
}
this._prio = prio;
this._dirty = true;
this._torrent._controller.changeFileCommand( cmd, this._torrent, this );
}
},
setWanted: function(wanted, process) {
this._dirty = true;
this._wanted = wanted;
if(!iPhone)
this.element().toggleClass( 'skip', !wanted );
if (process) {
var command = wanted ? 'files-wanted' : 'files-unwanted';
this._torrent._controller.changeFileCommand(command, this._torrent, this);
}
},
toggleWanted: function() {
if (this.isEditable())
this.setWanted( !this._wanted, true );
},
refreshHTML: function() {
if( this._dirty ) {
this._dirty = false;
this.refreshProgressHTML();
this.refreshWantedHTML();
this.refreshPriorityHTML();
}
},
refreshProgressHTML: function() {
var c = [ Transmission.fmt.size(this._done),
' of ',
Transmission.fmt.size(this._size),
' (',
this._size ? Transmission.fmt.percentString(100 * this._done / this._size) : '100',
'%)' ].join('');
setInnerHTML(this._progress[0], c);
},
refreshWantedHTML: function() {
var e = this.domElement();
var c = [ e.classNameConst ];
if(!this._wanted) { c.push( 'skip' ); }
if(this.isDone()) { c.push( 'complete' ); }
e.className = c.join(' ');
},
refreshPriorityHTML: function() {
var e = this._priority_control;
var c = [ e.classNameConst ];
switch( this._prio ) {
case 1 : c.push( 'high' ); break;
case -1 : c.push( 'low' ); break;
default : c.push( 'normal' ); break;
}
e.className = c.join(' ');
},
fileWantedControlClicked: function(event) {
this.toggleWanted();
},
filePriorityControlClicked: function(event, element) {
var x = event.pageX;
while (element !== null) {
x = x - element.offsetLeft;
element = element.offsetParent;
}
var prio;
if(iPhone)
{
if( x < 8 ) prio = -1;
else if( x < 27 ) prio = 0;
else prio = 1;
}
else
{
if( x < 12 ) prio = -1;
else if( x < 23 ) prio = 0;
else prio = 1;
}
this.setPriority( prio );
}
};

View File

@ -51,8 +51,6 @@ Transmission.prototype =
$('#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); });
$('.file_wanted_control').live('click', function(e){ tr.fileWantedClicked(e, this); });
$('.file_priority_control').live('click', function(e){ tr.filePriorityClicked(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); });
@ -224,6 +222,15 @@ Transmission.prototype =
});
},
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
*/
@ -251,6 +258,8 @@ Transmission.prototype =
if( !iPhone && this[Prefs._CompactDisplayState] )
$('#compact_view').selectMenuItem();
this.setCompactMode( this[Prefs._CompactDisplayState] );
},
/*
@ -362,9 +371,13 @@ Transmission.prototype =
boundingRightPad: 20,
boundingBottomPad: 5,
onContextMenu: function(e) {
var closestRow = $(e.target).closest('.torrent')[0]._torrent;
if(!closestRow.isSelected())
tr.setSelectedTorrent( closestRow, true );
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;
}
});
@ -421,45 +434,56 @@ Transmission.prototype =
{
var torrents = [ ];
for( var i=0, row; row=this._rows[i]; ++i )
if( row._torrent && ( row[0].style.display != 'none' ) )
torrents.push( row._torrent );
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 v = this.getVisibleTorrents( );
var s = [ ];
for( var i=0, row; row=v[i]; ++i )
if( row.isSelected( ) )
s.push( row );
var s = this.getSelectedRows( );
for( var i=0, row; row=s[i]; ++i )
s[i] = s[i].getTorrent();
return s;
},
getDeselectedTorrents: function() {
var visible_torrent_ids = jQuery.map(this.getVisibleTorrents(), function(t) { return t.id(); } );
var s = [ ];
jQuery.each( this.getAllTorrents( ), function() {
var visible = (-1 != jQuery.inArray(this.id(), visible_torrent_ids));
if (!this.isSelected() || !visible)
s.push( this );
} );
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.id() ];
return ret;
},
getVisibleRows: function()
{
var rows = [ ];
for( var i=0, row; row=this._rows[i]; ++i )
if( row[0].style.display != 'none' )
if( row.isVisible( ) )
rows.push( row );
return rows;
},
getTorrentIndex: function( rows, torrent )
getRowIndex: function( rows, row )
{
for( var i=0, row; row=rows[i]; ++i )
if( row._torrent == torrent )
for( var i=0, r; r=rows[i]; ++i )
if( r === row )
return i;
return null;
},
@ -479,8 +503,8 @@ Transmission.prototype =
var scrollTop = container.scrollTop( );
var innerHeight = container.innerHeight( );
var offsetTop = e[0].offsetTop;
var offsetHeight = e.outerHeight( );
var offsetTop = e.offsetTop;
var offsetHeight = $(e).outerHeight( );
if( offsetTop < scrollTop )
container.scrollTop( offsetTop );
@ -501,72 +525,57 @@ Transmission.prototype =
*
*--------------------------------------------*/
setSelectedTorrent: function( torrent, doUpdate ) {
this.deselectAll( );
this.selectTorrent( torrent, doUpdate );
setSelectedRow: function( row ) {
var rows = this.getSelectedRows( );
for( var i=0, r; r=rows[i]; ++i )
this.deselectRow( r );
this.selectRow( row );
},
selectElement: function( e, doUpdate ) {
e.addClass('selected');
if( doUpdate )
this.selectionChanged( );
},
selectRow: function( rowIndex, doUpdate ) {
this.selectElement( this._rows[rowIndex], doUpdate );
},
selectTorrent: function( torrent, doUpdate ) {
if( torrent._element )
this.selectElement( torrent._element, doUpdate );
selectRow: function( row ) {
row.setSelected( true );
this.callSelectionChangedSoon();
},
deselectElement: function( e, doUpdate ) {
e.removeClass('selected');
if( doUpdate )
this.selectionChanged( );
},
deselectTorrent: function( torrent, doUpdate ) {
if( torrent._element )
this.deselectElement( torrent._element, doUpdate );
deselectRow: function( row ) {
row.setSelected( false );
this.callSelectionChangedSoon();
},
selectAll: function( doUpdate ) {
selectAll: function( ) {
var tr = this;
for( var i=0, row; row=tr._rows[i]; ++i )
tr.selectElement( row );
if( doUpdate )
tr.selectionChanged();
tr.selectRow( row );
this.callSelectionChangedSoon();
},
deselectAll: function( doUpdate ) {
var tr = this;
for( var i=0, row; row=tr._rows[i]; ++i )
tr.deselectElement( row );
tr._last_torrent_clicked = null;
if( doUpdate )
tr.selectionChanged( );
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( torrent, doUpdate )
selectRange: function( row )
{
if( !this._last_torrent_clicked )
if( this._last_row_clicked === null )
{
this.selectTorrent( torrent );
this.selectRow( row );
}
else // select the range between the prevous & current
{
var rows = this.getVisibleRows( );
var i = this.getTorrentIndex( rows, this._last_torrent_clicked );
var end = this.getTorrentIndex( rows, torrent );
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( i );
this.selectRow( i );
this.selectRow( this._rows[i] );
this.selectRow( this._rows[i] );
}
if( doUpdate )
this.selectionChanged( );
this.callSelectionChangedSoon( );
},
selectionChanged: function()
@ -574,6 +583,13 @@ Transmission.prototype =
this.updateButtonStates();
this.updateInspector();
this.updateSelectedData();
this.selectionChangedTimer = null;
},
callSelectionChangedSoon: function()
{
if( this.selectionChangedTimer === null )
this.selectionChangedTimer = setTimeout(function(o) { o.selectionChanged(); }, 200, this);
},
/*--------------------------------------------
@ -588,28 +604,28 @@ Transmission.prototype =
keyDown: function(event)
{
var tr = this;
var sel = tr.getSelectedTorrents( );
var sel = tr.getSelectedRows( );
var rows = tr.getVisibleRows( );
var i = -1;
if( event.keyCode == 40 ) // down arrow
{
var t = sel.length ? sel[sel.length-1] : null;
i = t==null ? null : tr.getTorrentIndex(rows,t)+1;
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 t = sel.length ? sel[0] : null
i = t==null ? null : tr.getTorrentIndex(rows,t)-1;
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( i, true );
tr.selectRow( tr._rows[i], true );
tr.scrollToElement( tr._rows[i] );
}
},
@ -828,61 +844,30 @@ Transmission.prototype =
}
this.hideiPhoneAddressbar();
this.updateVisibleFileLists();
this.updatePeersLists();
this.updateTrackersLists();
},
fileWantedClicked: function(event, element){
this.extractFileFromElement(element).fileWantedControlClicked(event);
},
filePriorityClicked: function(event, element){
this.extractFileFromElement(element).filePriorityControlClicked(event, element);
this.updateFileList();
},
filesSelectAllClicked: function(event) {
var tr = this;
var ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.id(); } );
var files_list = this.toggleFilesWantedDisplay(ids, true);
for (i = 0; i < ids.length; ++i) {
if (files_list[i].length)
this.remote.filesSelectAll( [ ids[i] ], files_list[i], function() { tr.refreshTorrents( ids ); } );
}
var t = this._files_torrent;
if (t != null)
this.toggleFilesWantedDisplay(t, true);
},
filesDeselectAllClicked: function(event) {
var tr = this;
var ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.id(); } );
var files_list = this.toggleFilesWantedDisplay(ids, false);
for (i = 0; i < ids.length; ++i) {
if (files_list[i].length)
this.remote.filesDeselectAll( [ ids[i] ], files_list[i], function() { tr.refreshTorrents( ids ); } );
}
var t = this._files_torrent;
if (t != null)
this.toggleFilesWantedDisplay(t, false);
},
extractFileFromElement: function(element) {
var match = $(element).closest('.inspector_torrent_file_list_entry').attr('id').match(/^t(\d+)f(\d+)$/);
var torrent_id = match[1];
var file_id = match[2];
var torrent = this._torrents[torrent_id];
return torrent._file_view[file_id];
},
toggleFilesWantedDisplay: function(ids, wanted) {
var i, j, k, torrent, files_list = [ ];
for (i = 0; i < ids.length; ++i) {
torrent = this._torrents[ids[i]];
files_list[i] = [ ];
for (j = k = 0; j < torrent._file_view.length; ++j) {
if (torrent._file_view[j].isEditable() && torrent._file_view[j]._wanted != wanted) {
torrent._file_view[j].setWanted(wanted, false);
files_list[i][k++] = j;
}
}
torrent.refreshFileView;
toggleFilesWantedDisplay: function(torrent, wanted) {
var rows = [ ];
for( var i=0, row; row=this._files[i]; ++i )
if( row.isEditable() && (torrent._file_model[i].wanted !== wanted) )
rows.push( row );
if( rows.length > 1 ) {
var command = wanted ? 'files-wanted' : 'files-unwanted';
this.changeFileCommand( command, rows );
}
return files_list;
},
toggleFilterClicked: function(event) {
@ -1237,7 +1222,7 @@ Transmission.prototype =
// Figure out which menu has been clicked
switch ($element.parent()[0].id) {
// Display the preferences dialog
// Display the preferences dialog
case 'footer_super_menu':
if ($element[0].id == 'preferences') {
$('div#prefs_container div#pref_error').hide();
@ -1255,7 +1240,7 @@ Transmission.prototype =
$element.selectMenuItem();
else
$element.deselectMenuItem();
this.refreshDisplay( );
this.setCompactMode( this[Prefs._CompactDisplayState] );
}
else if ($element[0].id == 'homepage') {
window.open('http://www.transmissionbt.com/');
@ -1336,11 +1321,6 @@ Transmission.prototype =
return false; // to prevent the event from bubbling up
},
setLastTorrentClicked: function( torrent )
{
this._last_torrent_clicked = torrent;
},
/*
* Update the inspector with the latest data for the selected torrents
*/
@ -1407,7 +1387,7 @@ Transmission.prototype =
setInnerHTML( tab.creator, na );
setInnerHTML( tab.download_dir, na );
setInnerHTML( tab.error, na );
this.updateVisibleFileLists();
this.updateFileList();
this.updatePeersLists();
this.updateTrackersLists();
$("#torrent_inspector_size, .inspector_row > div:contains('N/A')").css('color', '#666');
@ -1491,27 +1471,67 @@ Transmission.prototype =
this.updatePeersLists();
this.updateTrackersLists();
$(".inspector_row > div:contains('N/A')").css('color', '#666');
this.updateVisibleFileLists();
this.updateFileList();
},
fileListIsVisible: function() {
return this._inspector_tab_files.className.indexOf('selected') != -1;
onFileWantedToggled: function( row, want ) {
var command = want ? 'files-wanted' : 'files-unwanted';
this.changeFileCommand( command, [ row ] );
},
updateVisibleFileLists: function() {
if( this.fileListIsVisible( ) === true ) {
var selected = this.getSelectedTorrents();
jQuery.each( selected, function() { this.showFileList(); } );
jQuery.each( this.getDeselectedTorrents(), function() { this.hideFileList(); } );
// Check if we need to display the select all buttions
if ( !selected.length ) {
if ( $("#select_all_button_container").is(':visible') )
$("#select_all_button_container").hide();
} else {
if ( !$("#select_all_button_container").is(':visible') )
$("#select_all_button_container").show();
}
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._file_model.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() {
@ -1744,11 +1764,12 @@ Transmission.prototype =
{
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( t.isSelected( ) )
if( selected_torrents.indexOf(t) != -1 )
refresh_files_for.push( t.id( ) );
}
} );
@ -1768,16 +1789,18 @@ Transmission.prototype =
var tr = this;
var new_torrent_ids = [];
var refresh_files_for = [];
jQuery.each( updated, function() {
var t = tr._torrents[this.id];
if (t){
t.refresh(this);
if(t.isSelected())
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.id());
}
else
new_torrent_ids.push(this.id);
} );
}
if(refresh_files_for.length > 0)
tr.remote.loadTorrentFiles( refresh_files_for );
@ -1796,16 +1819,14 @@ Transmission.prototype =
},
updateTorrentsFileData: function( torrents ){
var tr = this;
var listIsVisible = tr.fileListIsVisible( );
jQuery.each( torrents, function() {
var t = tr._torrents[this.id];
if (t) {
t.refreshFileModel(this);
if( listIsVisible && t.isSelected())
t.refreshFileView();
for( var i=0, o; o=torrents[i]; ++i ) {
var t = this._torrents[o.id];
if( t !== null ) {
t.refreshFileModel( o );
if( t === this._files_torrent )
this.refreshFileView();
}
} );
}
},
initializeAllTorrents: function(){
@ -1813,19 +1834,63 @@ Transmission.prototype =
this.remote.getInitialDataFor( null ,function(torrents) { tr.addTorrents(torrents); } );
},
onRowClicked: function( ev, row )
{
// Prevents click carrying to parent element
// which deselects all on click
event.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 = event.metaKey;
var ctrl_key = event.ctrlKey;
if (event.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 (event.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 transferFragment = document.createDocumentFragment( );
var fileFragment = document.createDocumentFragment( );
var tr = this;
for( var i=0, row; row=new_torrents[i]; ++i ) {
var new_torrent = new Torrent( transferFragment, fileFragment, this, row );
this._torrents[new_torrent.id()] = new_torrent;
var t = new Torrent( this, row );
this._torrents[t.id()] = t;
}
this._inspector_file_list.appendChild( fileFragment );
this._torrent_list.appendChild( transferFragment );
this.refilter( );
},
@ -1839,7 +1904,7 @@ Transmission.prototype =
if(torrent) {
removedAny = true;
var e = torrent.element();
var e = torrent.view;
if( e ) {
var row_index;
for( var i=0, row; row = tr._rows[i]; ++i ) {
@ -1855,8 +1920,6 @@ Transmission.prototype =
e.remove();
}
torrent.hideFileList();
torrent.deleteFiles();
delete tr._torrents[torrent.id()];
}
});
@ -1866,9 +1929,9 @@ Transmission.prototype =
refreshDisplay: function( )
{
var torrents = this.getVisibleTorrents();
for( var i=0; torrents[i]; ++i )
torrents[i].refreshHTML();
var rows = this.getVisibleRows( );
for( var i=0, row; row=rows[i]; ++i )
row.render( this );
},
/*
@ -1877,12 +1940,8 @@ Transmission.prototype =
setTorrentBgColors: function( )
{
var rows = this.getVisibleRows( );
for( var i=0, row; row=rows[i]; ++i ) {
var wasEven = row[0].className.indexOf('even') != -1;
var isEven = ((i+1) % 2 == 0);
if( wasEven != isEven )
row.toggleClass('even', isEven);
}
for( var i=0, row; row=rows[i]; ++i )
row.setEven((i+1) % 2 == 0);
},
updateStatusbar: function()
@ -2068,8 +2127,8 @@ Transmission.prototype =
var tr = this;
this.remote.stopTorrents( torrent_ids, function(){ tr.refreshTorrents(torrent_ids )} );
},
changeFileCommand: function(command, torrent, file) {
this.remote.changeFileCommand(command, torrent, file)
changeFileCommand: function(command, rows) {
this.remote.changeFileCommand(command, rows);
},
hideiPhoneAddressbar: function(timeInSeconds) {
@ -2114,6 +2173,16 @@ Transmission.prototype =
****
***/
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
@ -2129,23 +2198,39 @@ Transmission.prototype =
// make a backup of the selection
var sel = this.getSelectedTorrents( );
this.deselectAll( );
// hide the ones we're not keeping
// 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, 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);});
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[0].style.display = 'none';
e.setVisible(false);
}
// show the ones we're keeping
sel.sort( Torrent.compareById );
for( var i=0, len=keep.length; i<len; ++i ) {
var e = this._rows[i];
e[0].style.display = 'block';
var t = keep[i];
t.setElement( e );
if( Torrent.indexOf( sel, t.id() ) != -1 )
this.selectElement( e );
var row = this._rows[i];
var tor = keep[i];
row.setVisible( true );
row.setTorrent( this, tor );
row.setSelected( sel.indexOf( tor ) !== -1 );
}
// sync gui
@ -2174,14 +2259,16 @@ Transmission.prototype =
var havePaused = false;
var havePausedSelection = false;
for( var i=0, len=torrents.length; !haveSelection && i<len; ++i ) {
var isActive = torrents[i].isActive( );
var isSelected = torrents[i].isSelected( );
if( isActive ) haveActive = true;
if( !isActive ) havePaused = true;
if( isSelected ) haveSelection = true;
if( isSelected && isActive ) haveActiveSelection = true;
if( isSelected && !isActive ) havePausedSelection = true;
for( var i=0, row; row=this._rows[i]; ++i ) {
if( row.isVisible( ) ) {
var isActive = row.getTorrent().isActive( );
var isSelected = row.isSelected();
if( isActive ) haveActive = true;
if( !isActive ) havePaused = true;
if( isSelected ) haveSelection = true;
if( isSelected && isActive ) haveActiveSelection = true;
if( isSelected && !isActive ) havePausedSelection = true;
}
}
this.setEnabled( this._toolbar_pause_button, haveActiveSelection );

View File

@ -189,17 +189,20 @@ TransmissionRemote.prototype =
} );
},
changeFileCommand: function( command, torrent, file ) {
changeFileCommand: function( command, rows ) {
var remote = this;
var torrent_ids = [ torrent.id() ];
var torrent_ids = [ rows[0].getTorrent().id() ];
var files = [ ];
for( var i=0, row; row=rows[i]; ++i )
files.push( row.getIndex( ) );
var o = {
method: 'torrent-set',
arguments: { ids: torrent_ids }
};
o.arguments[command] = [ file._index ];
o.arguments[command] = files;
this.sendRequest( o, function( ) {
remote._controller.refreshTorrents( torrent_ids );
} );
});
},
sendTorrentSetRequests: function( method, torrent_ids, args, callback ) {
@ -287,12 +290,14 @@ TransmissionRemote.prototype =
remote._controller.loadDaemonPrefs();
} );
},
/*
filesSelectAll: function( torrent_ids, files, callback ) {
this.sendTorrentSetRequests( 'torrent-set', torrent_ids, { 'files-wanted': files }, callback );
},
filesDeselectAll: function( torrent_ids, files, callback ) {
this.sendTorrentSetRequests( 'torrent-set', torrent_ids, { 'files-unwanted': files }, callback );
},
*/
// Added queue calls
moveTorrentsToTop: function( torrent_ids, callback ) {

View File

@ -13,7 +13,7 @@ html {
body {
font: 62.5% "lucida grande", Tahoma, Verdana, Arial, Helvetica, sans-serif; /* Resets 1em to 10px */
color: #222 !important;
color: #222;/* !important; */
background: #FFF;
text-align: center;
margin: 0 0 30px;
@ -353,7 +353,6 @@ div#torrent_container {
padding: 0px;
margin: 0px;
overflow: auto;
z-index: 1;
}
ul.torrent_list {
@ -361,7 +360,6 @@ ul.torrent_list {
margin: 0;
padding: 0;
text-align: left;
z-index: 1;
cursor: default;
}
@ -382,6 +380,9 @@ ul.torrent_list li.torrent {
margin: 0 !important;
color: #666;
}
ul.torrent_list li.torrent.compact {
padding: 4px;
}
ul.torrent_list li.torrent a img {
position: relative;
@ -407,21 +408,18 @@ ul.torrent_list li.torrent div.torrent_name {
margin-bottom: 2px;
}
ul.torrent_list li.torrent div.torrent_name.compact {
float: left;
z-index: 1;
position: absolute;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
ul.torrent_list li.torrent div.torrent_name.paused {
font-size: 1.3em;
font-weight: normal;
color: #777;
}
ul.torrent_list li.torrent.selected div.torrent_name {
color: #fff;
}
ul.torrent_list li.torrent div.torrent_progress_details,
ul.torrent_list li.torrent div.torrent_peer_details {
ul.torrent_list div.torrent_progress_details,
ul.torrent_list div.torrent_peer_details {
clear: left;
font-size: 1em;
overflow: hidden;
@ -442,130 +440,125 @@ ul.torrent_list li.torrent.selected div.torrent_peer_details.error {
color: #FFF;
}
ul.torrent_list li.torrent div.torrent_progress_details.compact,
ul.torrent_list li.torrent div.torrent_peer_details.compact {
padding-top: 3px;
float: left;
}
ul.torrent_list li.torrent div.torrent_progress_details.compact {
float: right;
}
ul.torrent_list li.torrent div.torrent_progress_bar_container.compact {
position: absolute;
left: 5px;
right: 35px;
opacity:0.4;
}
/**
* Progressbar
*
* Each progressbar has three elemens: a parent container and two children,
* complete and incomplete.
*
* The only thing needed to set the progressbar percentage is to set
* the complete child's width as a percentage. This is because incomplete
* is pinned to the full width and height of the parent, and complete
* is pinned to the left side of the parent and has a higher z-index.
*
* The progressbar has different colors depending on its state, so there
* are four 'decorator' classNames: magnet, seeding, leeching, and paused.
*/
ul.torrent_list li.torrent div.torrent_progress_bar {
ul.torrent_list div.torrent_progress_bar_container {
height: 10px;
margin: 3px 0;
float: left;
line-height: 1px;
font-size: 1px;
width: 100%;
position: relative;
margin-top: 2px;
}
ul.torrent_list div.torrent_status_and_progress_bar {
/* float: right;*/
}
ul.torrent_list div.torrent_progress_bar_container.compact {
width: 50px;
position: absolute;
right: 10px;
margin-top: 2px;
/*float: right;*/
}
ul.torrent_list div.torrent_peer_details.compact {
font-size: 12px; /* matching the progressbar height (10px) + progressbar border (1px top, 1px bottom) */
margin-top: 2px;
margin-left: 10px;
margin-right: 65px; /* leave room on the right for the progressbar */
float: right; /* pins it next to progressbar & forces torrent_name to ellipsize when it bumps up against this div */
}
ul.torrent_list div.torrent_progress_bar_container.full {
margin-bottom: 5px;
}
ul.torrent_list div.torrent_progress_bar {
height: 100%;
position: absolute;
top: 0px;
left: 0px;
background-image: url('../images/progress/progress.png');
background-repeat: repeat-x;
background-color: transparent;
border: 1px solid #888;
}
ul.torrent_list div.torrent_progress_bar.complete {
z-index: 2;
}
ul.torrent_list div.torrent_progress_bar.incomplete {
z-index: 1;
width: 100%;
}
ul.torrent_list div.torrent_progress_bar.complete.paused {
background-position: left -30px;
border-color: #989898;
}
ul.torrent_list div.torrent_progress_bar.incomplete.paused {
background-position: left -20px;
border-color: #CFCFCF;
}
ul.torrent_list div.torrent_progress_bar.complete.magnet {
background-position: left -20px;
border-color: #CFCFCF;
}
ul.torrent_list div.torrent_progress_bar.incomplete.magnet {
background-position: left -50px;
border-color: #D47778;
}
ul.torrent_list div.torrent_progress_bar.complete.leeching {
background-position: left 0px;
border-color: #3D9DEA;
}
ul.torrent_list div.torrent_progress_bar.incomplete.leeching {
background-position: left -20px;
border-color: #CFCFCF;
}
ul.torrent_list div.torrent_progress_bar.complete.seeding {
background-position: left -10px;
}
ul.torrent_list div.torrent_progress_bar.incomplete.seeding {
background-position: left -40px;
border-color: #35AC47;
}
ul.torrent_list li.torrent div.torrent_progress_bar.complete {
background-position: left -10px;
border: 1px solid #29AD35;
}
ul.torrent_list li.torrent div.torrent_progress_bar.complete.seeding {
background-position: left -40px;
border: 1px solid #269e30;
border-right: none;
}
/****
***** START / STOP BUTTON
****/
ul.torrent_list li.torrent div.torrent_progress_bar.in_progress {
background-position: left 0px;
border: 1px solid #3F79EE;
border-right: none;
}
ul.torrent_list li.torrent div.torrent_progress_bar.incomplete.compact {
background: none;
border: none;
}
ul.torrent_list li.torrent div.torrent_progress_bar.incomplete {
margin-right: -10px;
background-position: left -20px;
border: 1px solid #C8CACD;
border-left: none;
}
ul.torrent_list li.torrent div.torrent_progress_bar.incomplete.seeding {
background-position: left -10px;
border: 1px solid #29AD35;
}
ul.torrent_list li.torrent div.torrent_progress_bar.incomplete_stopped {
background-position: left -30px;
border: 1px solid #939393;
border-right: none;
}
ul.torrent_list li.torrent div.torrent_progress_bar.complete_stopped {
background-position: left -30px;
border: 1px solid #939393;
}
ul.torrent_list li.torrent div.torrent_progress_bar.empty {
border-color: #c8cacd;
}
ul.torrent_list li.torrent div.torrent_progress_bar.incomplete.meta {
background-position: left -50px;
border: 1px solid #cc6068;
}
ul.torrent_list li.torrent div.torrent_progress_bar.in_progress.meta {
background-position: left -20px;
border-color: #c8cacd;
}
ul.torrent_list li.torrent div.torrent_progress_bar.in_progress.meta.empty {
border: 0 none;
}
li.torrent a div {
li.torrent a {
float: right;
position: relative;
right: -22px;
top: -16px;
top: 1px;
}
li.torrent a div {
background: url('../images/buttons/torrent_buttons.png');
height: 14px;
width: 14px;
}
li.torrent a div.compact {
top: 0px;
}
li.torrent a div.torrent_pause {
background-position: left top;
}
li.torrent a:hover div.torrent_pause {
background-position: left center;
}
li.torrent a:active div.torrent_pause {
background-position: left bottom;
}
li.torrent a div.torrent_resume {
background-position: center top;
}
li.torrent a:hover div.torrent_resume {
background-position: center center;
}
li.torrent a:active div.torrent_resume {
background-position: center bottom;
}
@ -840,10 +833,10 @@ div.tracker_host {
cursor: default;
overflow: hidden;
}
#inspector_file_list #select_all_button_container {
margin: 0;
#inspector_tab_files_container #select_all_button_container {
width: 100%;
}
#inspector_file_list ul li.select_all_button {
#inspector_tab_files_container .select_all_button {
background: transparent url(../images/buttons/tab_backgrounds.png) repeat-x scroll left -6px;
border: 1px solid #888888;
cursor: pointer;
@ -853,7 +846,7 @@ div.tracker_host {
padding: 2px 5px;
}
ul.inspector_torrent_file_list {
#inspector_file_list {
width: 100%;
margin: 0 0 0 0;
padding-bottom: 10px;

View File

@ -331,49 +331,65 @@ div.torrent_peer_details {
font-size: 10px;
}
ul.torrent_list li.torrent div.torrent_progress_bar {
height: 10px;
margin: 3px 0 3px 0;
float: left;
line-height: 1px;
font-size: 1px;
width: 100%;
background-image: url('../images/progress/progress.png');
background-repeat: repeat-x;
background-color: transparent;
}
/***
**** Progressbar
***/
ul.torrent_list li.torrent div.torrent_progress_bar.complete {
background-position: left -10px;
border: 1px solid #29AD35;
ul.torrent_list div.torrent_progress_bar_container {
height: 10px;
position: relative;
margin-top: 2px;
}
ul.torrent_list li.torrent div.torrent_progress_bar.in_progress {
background-position: left 0px;
border: 1px solid #3F79EE;
border-right: none;
ul.torrent_list div.torrent_progress_bar_container.full {
margin-bottom: 5px;
}
ul.torrent_list li.torrent div.torrent_progress_bar.incomplete {
margin-right: -10px;
background-position: left -20px;
border: 1px solid #C8CACD;
border-left: none;
ul.torrent_list div.torrent_progress_bar {
height: 100%;
position: absolute;
top: 0px;
left: 0px;
background-image: url('../images/progress/progress.png');
background-repeat: repeat-x;
border: 1px solid #888;
}
ul.torrent_list li.torrent div.torrent_progress_bar.incomplete_stopped {
background-position: left -30px;
border: 1px solid #939393;
border-right: none;
ul.torrent_list div.torrent_progress_bar.complete {
z-index: 2;
}
ul.torrent_list li.torrent div.torrent_progress_bar.complete_stopped {
background-position: left -30px;
border: 1px solid #939393;
ul.torrent_list div.torrent_progress_bar.incomplete {
z-index: 1;
width: 100%;
}
ul.torrent_list li.torrent div.torrent_progress_bar.incomplete {
margin-right: -10px;
ul.torrent_list div.torrent_progress_bar.complete.paused {
background-position: left -30px;
border-color: #989898;
}
ul.torrent_list div.torrent_progress_bar.incomplete.paused {
background-position: left -20px;
border-color: #CFCFCF;
}
ul.torrent_list div.torrent_progress_bar.complete.magnet {
background-position: left -20px;
border-color: #CFCFCF;
}
ul.torrent_list div.torrent_progress_bar.incomplete.magnet {
background-position: left -50px;
border-color: #D47778;
}
ul.torrent_list div.torrent_progress_bar.complete.leeching {
background-position: left 0px;
border-color: #3D9DEA;
}
ul.torrent_list div.torrent_progress_bar.incomplete.leeching {
background-position: left -20px;
border-color: #CFCFCF;
}
ul.torrent_list div.torrent_progress_bar.complete.seeding {
background-position: left -10px;
border-color: #35CA53;
}
ul.torrent_list div.torrent_progress_bar.incomplete.seeding {
background-position: left -40px;
border-color: #35AC47;
}
div.dialog_container {