diff --git a/web/javascript/file-row.js b/web/javascript/file-row.js index 11505c7c7..ee7328603 100644 --- a/web/javascript/file-row.js +++ b/web/javascript/file-row.js @@ -90,7 +90,7 @@ FileRow.prototype = { var i = this.getIndex( ); var t = this.getTorrent( ); - this.readAttributes( t._file_model[i] ); + this.readAttributes( t._files[i] ); this.refreshHTML(); }, @@ -98,17 +98,17 @@ FileRow.prototype = return this._done >= this._size; }, isEditable: function () { - return (this.getTorrent()._file_model.length>1) && !this.isDone(); + return (this.getTorrent()._files.length>1) && !this.isDone(); }, createRow: function( torrent, i ) { var me = this; - var file = torrent._file_model[i]; + var file = torrent._files[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.id = 't' + this._torrent.getId() + 'f' + this._index; root.classNameConst = 'inspector_torrent_file_list_entry ' + ((i%2)?'odd':'even'); root.className = root.classNameConst; diff --git a/web/javascript/torrent-renderer.js b/web/javascript/torrent-renderer.js index c6d9dfc4d..c9493fac3 100644 --- a/web/javascript/torrent-renderer.js +++ b/web/javascript/torrent-renderer.js @@ -19,11 +19,11 @@ TorrentRendererHelper.getProgressInfo = function( controller, t ) var pct = 0; if( t.needsMetaData( ) ) - pct = t._metadataPercentComplete * 100; + pct = t.getMetadataPercentComplete() * 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 ); + pct = Math.round( t.getUploadRatio() * 100 / seed_ratio_limit ); else pct = 100; @@ -72,12 +72,12 @@ TorrentRendererHelper.renderProgressbar = function( controller, t, progressbar ) TorrentRendererHelper.formatUL = function( t ) { - return 'UL: ' + Transmission.fmt.speedBps( t.uploadSpeed( ) ); + return 'UL: ' + Transmission.fmt.speedBps( t.getUploadSpeed( ) ); } TorrentRendererHelper.formatDL = function( t ) { - return 'DL: ' + Transmission.fmt.speedBps( t.downloadSpeed( ) ); + return 'DL: ' + Transmission.fmt.speedBps( t.getDownloadSpeed( ) ); } /**** @@ -134,9 +134,9 @@ TorrentRendererFull.prototype = if( t.isDownloading( ) ) return [ 'Downloading from', - t.peersSendingToUs(), + t.getPeersSendingToUs(), 'of', - t._peers_connected, + t.getPeersConnected(), 'peers', '-', TorrentRendererHelper.formatDL(t), @@ -144,60 +144,63 @@ TorrentRendererFull.prototype = if( t.isSeeding( ) ) return [ 'Seeding to', - t.peersGettingFromUs(), + t.getPeersGettingFromUs(), 'of', - t._peers_connected, + t.getPeersConnected(), 'peers', '-', TorrentRendererHelper.formatUL(t) ].join(' '); - if( t.state() === Torrent._StatusCheck ) + if( t.isChecking( ) ) return [ 'Verifying local data (', - Transmission.fmt.percentString( 100.0 * t._recheckProgress ), + Transmission.fmt.percentString( 100.0 * t.getRecheckProgress() ), '% tested)' ].join(''); - return t.stateStr( ); + return t.getStateString( ); }, getProgressDetails: function( controller, t ) { if( t.needsMetaData() ) { - var percent = 100 * t._metadataPercentComplete; + var percent = 100 * t.getMetadataPercentComplete(); return [ "Magnetized transfer - retrieving metadata (", Transmission.fmt.percentString( percent ), "%)" ].join(''); } var c; - var is_done = ( t.isDone( ) ) - || ( t.state() === Torrent._StatusSeeding ); + var sizeWhenDone = t.getSizeWhenDone() + var totalSize = t.getTotalSize() + var is_done = ( t.isDone( ) ) || ( t.isSeeding() ) + if( is_done ) { - if( t._size == t._sizeWhenDone ) // seed: '698.05 MiB' - c = [ Transmission.fmt.size( t._size ) ]; + if( totalSize == sizeWhenDone ) // seed: '698.05 MiB' + c = [ Transmission.fmt.size( totalSize ) ]; else // partial seed: '127.21 MiB of 698.05 MiB (18.2%)' - c = [ Transmission.fmt.size( t._sizeWhenDone ), + c = [ Transmission.fmt.size( sizeWhenDone ), ' of ', - Transmission.fmt.size( t._size ), + Transmission.fmt.size( t.getTotalSize() ), ' (', t.getPercentDoneStr, '%)' ]; // append UL stats: ', uploaded 8.59 GiB (Ratio: 12.3)' c.push( ', uploaded ', - Transmission.fmt.size( t._upload_total ), + Transmission.fmt.size( t.getUploadedEver() ), ' (Ratio ', - Transmission.fmt.ratioString( t._upload_ratio ), + Transmission.fmt.ratioString( t.getUploadRatio() ), ')' ); } else { // not done yet - c = [ Transmission.fmt.size( t._sizeWhenDone - t._leftUntilDone ), - ' of ', Transmission.fmt.size( t._sizeWhenDone ), + c = [ Transmission.fmt.size( sizeWhenDone - t.getLeftUntilDone() ), + ' of ', Transmission.fmt.size( sizeWhenDone ), ' (', t.getPercentDoneStr(), '%)' ]; } // maybe append eta - if( t.isActive() && ( !is_done || t.seedRatioLimit(controller)>0 ) ) { + if( !t.isStopped() && ( !is_done || t.seedRatioLimit(controller)>0 ) ) { c.push(' - '); - if (t._eta < 0 || this._eta >= Torrent._InfiniteTimeRemaining ) + var eta = t.getETA() + if (eta < 0 || eta >= (999*60*60) /* arbitrary */ ) c.push( 'remaining time unknown' ); else - c.push( Transmission.fmt.timeInterval(t._eta), + c.push( Transmission.fmt.timeInterval(t.getETA()), ' remaining' ); } @@ -207,13 +210,13 @@ TorrentRendererFull.prototype = render: function( controller, t, root ) { // name - setInnerHTML( root._name_container, t.name() ); + setInnerHTML( root._name_container, t.getName() ); // progressbar TorrentRendererHelper.renderProgressbar( controller, t, root._progressbar ); // peer details - var has_error = t._error !== Torrent._ErrNone; + var has_error = t.getError() !== Torrent._ErrNone; var e = root._peer_details_container; $(e).toggleClass('error',has_error); setInnerHTML( e, this.getPeerDetails( t ) ); @@ -223,10 +226,10 @@ TorrentRendererFull.prototype = 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'; + var is_stopped = t.isStopped() + e = root._pause_resume_button_image + e.alt = is_stopped ? 'Resume' : 'Pause' + e.className = is_stopped ? 'torrent_resume' : 'torrent_pause' } }; @@ -271,19 +274,19 @@ TorrentRendererCompact.prototype = TorrentRendererHelper.formatUL(t) ].join(' '); if( t.isSeeding( ) ) return TorrentRendererHelper.formatUL(t); - return t.stateStr( ); + return t.getStateString( ); }, render: function( controller, t, root ) { // name - var is_stopped = t.state() === Torrent._StatusStopped; + var is_stopped = t.isStopped() var e = root._name_container; $(e).toggleClass( 'paused', is_stopped ); - setInnerHTML( e, t.name() ); + setInnerHTML( e, t.getName() ); // peer details - var has_error = t._error !== Torrent._ErrNone; + var has_error = t.getError() !== Torrent._ErrNone; e = root._details_container; $(e).toggleClass('error', has_error ); setInnerHTML( e, this.getPeerDetails( t ) ); diff --git a/web/javascript/torrent.js b/web/javascript/torrent.js index 77c22932b..3e09859ea 100644 --- a/web/javascript/torrent.js +++ b/web/javascript/torrent.js @@ -1,411 +1,415 @@ /* - * Copyright © Dave Perrett and Malcolm Jarvis + * Copyright © Jordan Lee, 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 Torrent */ -function Torrent( controller, data) { - this.initialize( controller, data); + +function Torrent(controller, data) +{ + this.initialize(controller, data) } -// Constants -Torrent._StatusStopped = 0; /* torrent is stopped */ -Torrent._StatusCheckWait = 1; /* waiting in queue to check files */ -Torrent._StatusCheck = 2; /* checking files */ -Torrent._StatusDownloadWait = 3; /* queued to download */ -Torrent._StatusDownload = 4; /* downloading */ -Torrent._StatusSeedWait = 5; /* queeud to seed */ -Torrent._StatusSeed = 6; /* seeding */ +/*** +**** +**** Constants +**** +***/ -Torrent._InfiniteTimeRemaining = 215784000; // 999 Hours - may as well be infinite +// Torrent.fields.status +Torrent._StatusStopped = 0 +Torrent._StatusCheckWait = 1 +Torrent._StatusCheck = 2 +Torrent._StatusDownloadWait = 3 +Torrent._StatusDownload = 4 +Torrent._StatusSeedWait = 5 +Torrent._StatusSeed = 6 -Torrent._RatioUseGlobal = 0; -Torrent._RatioUseLocal = 1; -Torrent._RatioUnlimited = 2; +// Torrent.fields.seedRatioMode +Torrent._RatioUseGlobal = 0 +Torrent._RatioUseLocal = 1 +Torrent._RatioUnlimited = 2 -Torrent._ErrNone = 0; -Torrent._ErrTrackerWarning = 1; -Torrent._ErrTrackerError = 2; -Torrent._ErrLocalError = 3; +// Torrent.fields.error +Torrent._ErrNone = 0 +Torrent._ErrTrackerWarning = 1 +Torrent._ErrTrackerError = 2 +Torrent._ErrLocalError = 3 -Torrent._TrackerInactive = 0; -Torrent._TrackerWaiting = 1; -Torrent._TrackerQueued = 2; -Torrent._TrackerActive = 3; +// TrackerStats' announceState +Torrent._TrackerInactive = 0 +Torrent._TrackerWaiting = 1 +Torrent._TrackerQueued = 2 +Torrent._TrackerActive = 3 -Torrent._StaticFields = [ 'hashString', 'id' ] +// fields whose values never change and are always known +Torrent._StaticFields = [ + 'hashString', 'id' ] -Torrent._MetaDataFields = [ 'addedDate', 'comment', 'creator', 'dateCreated', - 'isPrivate', 'name', 'totalSize', 'pieceCount', 'pieceSize' ] +// fields whose values never change and are known upon constructon OR +// when a magnet torrent finishes downloading its metadata +Torrent._MetaDataFields = [ + 'addedDate', 'comment', 'creator', 'dateCreated', + 'isPrivate', 'name', 'totalSize', 'pieceCount', 'pieceSize' ] -Torrent._DynamicFields = [ 'downloadedEver', 'error', 'errorString', 'eta', - 'haveUnchecked', 'haveValid', 'leftUntilDone', 'metadataPercentComplete', - 'peers', 'peersConnected', 'peersGettingFromUs', 'peersSendingToUs', - 'queuePosition', 'rateDownload', 'rateUpload', 'recheckProgress', - 'sizeWhenDone', 'status', 'trackerStats', 'desiredAvailable', - 'uploadedEver', 'uploadRatio', 'seedRatioLimit', 'seedRatioMode', - 'downloadDir', 'isFinished' ] +// torrent fields whose values change all the time +Torrent._DynamicFields = [ + 'desiredAvailable', 'downloadDir', 'downloadedEver', 'error', + 'errorString', 'eta', 'haveUnchecked', 'haveValid', 'isFinished', + 'leftUntilDone', 'metadataPercentComplete', 'peers', 'peersConnected', + 'peersGettingFromUs', 'peersSendingToUs', 'queuePosition', + 'rateDownload', 'rateUpload', 'recheckProgress', 'seedRatioLimit', + 'seedRatioMode', 'sizeWhenDone', 'status', 'trackerStats', + 'uploadedEver', 'uploadRatio', 'webseedsSendingToUs' ] + +// tracker stats fields whose values change all the time +Torrent._TrackerStatFields = [ + 'announce', 'announceState', 'downloadCount', 'hasAnnounced', + 'hasScraped', 'host', 'isBackup', 'lastAnnouncePeerCount', + 'lastAnnounceResult', 'lastAnnounceSucceeded', 'lastAnnounceTime', + 'lastScrapeResult', 'lastScrapeSucceeded', 'lastScrapeTime', + 'leecherCount', 'nextAnnounceTime', 'seederCount' +] + + +/*** +**** +**** Methods +**** +***/ Torrent.prototype = { - initMetaData: function( data ) { - this._date = data.addedDate; - this._comment = data.comment; - this._creator = data.creator; - this._creator_date = data.dateCreated; - this._is_private = data.isPrivate; - this._name = data.name; - this._name_lc = this._name.toLowerCase( ); - this._size = data.totalSize; - this._pieceCount = data.pieceCount; - this._pieceSize = data.pieceSize; + initialize: function(controller, data) + { + this.fields = { } + this._files = [ ] - if( data.files ) { - for( var i=0, row; row=data.files[i]; ++i ) { - this._file_model[i] = { + // these fields are set in the ctor and never change + for(var i=0, key; key=Torrent._StaticFields[i]; ++i) + if(key in data) + this.fields[key] = data[key] + + this.initMetaData(data) + this._trackerStats = this.buildTrackerStats(data.trackerStats) + this.refresh(data) + }, + + buildTrackerStats: function(trackerStats) { + result = [] + for(var i=0, tracker; tracker=trackerStats[i]; ++i) { + tier = result[tracker.tier] || [] + tier[tier.length] = tracker + result[tracker.tier] = tier + } + return result + }, + + initMetaData: function(data) { + + var f = this.fields + + // populate the metadata fields + for(var i=0, key; key=Torrent._MetaDataFields[i]; ++i) { + if(key in data) { + f[key] = data[key] + if(key == 'name') + f.collatedName = data.name.toLowerCase() + } + } + + // populate the files array + if(data.files) { + for(var i=0, row; row=data.files[i]; ++i) { + this._files[i] = { 'index': i, 'torrent': this, 'length': row.length, 'name': row.name - }; + } } } }, - /* - * Constructor - */ - 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.initMetaData( data ); - - // Update all the labels etc - this.refresh(data); - }, - - buildTrackerStats: function(trackerStats) { - result = []; - for( var i=0, tracker; tracker=trackerStats[i]; ++i ) { - tier = result[tracker.tier] || []; - tier[tier.length] = { - 'host': tracker.host, - 'announce': tracker.announce, - 'hasAnnounced': tracker.hasAnnounced, - 'lastAnnounceTime': tracker.lastAnnounceTime, - 'lastAnnounceSucceeded': tracker.lastAnnounceSucceeded, - 'lastAnnounceResult': tracker.lastAnnounceResult, - 'lastAnnouncePeerCount': tracker.lastAnnouncePeerCount, - 'announceState': tracker.announceState, - 'nextAnnounceTime': tracker.nextAnnounceTime, - 'isBackup': tracker.isBackup, - 'hasScraped': tracker.hasScraped, - 'lastScrapeTime': tracker.lastScrapeTime, - 'lastScrapeSucceeded': tracker.lastScrapeSucceeded, - 'lastScrapeResult': tracker.lastScrapeResult, - 'seederCount': tracker.seederCount, - 'leecherCount': tracker.leecherCount, - 'downloadCount': tracker.downloadCount - }; - result[tracker.tier] = tier; - } - return result; - }, - - /*-------------------------------------------- - * - * S E T T E R S / G E T T E R S - * - *--------------------------------------------*/ - - activity: function() { return this.downloadSpeed() + this.uploadSpeed(); }, - comment: function() { return this._comment; }, - completed: function() { return this._completed; }, - creator: function() { return this._creator; }, - dateAdded: function() { return this._date; }, - downloadSpeed: function() { return this._download_speed; }, - downloadTotal: function() { return this._download_total; }, - hash: function() { return this._hashString; }, - id: function() { return this._id; }, - isActiveFilter: function() { return this.peersGettingFromUs() > 0 - || 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; }, - webseedsSendingToUs: function() { return this._webseeds_sending_to_us; }, - peersSendingToUs: function() { return this._peers_sending_to_us; }, - peersGettingFromUs: function() { return this._peers_getting_from_us; }, - needsMetaData: function(){ return this._metadataPercentComplete < 1 }, - getPercentDone: function() { - if( !this._sizeWhenDone ) return 1.0; - if( !this._leftUntilDone ) return 1.0; - return ( this._sizeWhenDone - this._leftUntilDone ) / this._sizeWhenDone; - }, - getPercentDoneStr: function() { - return Transmission.fmt.percentString( 100 * this.getPercentDone() ); - }, - size: function() { return this._size; }, - state: function() { return this._state; }, - stateStr: function() { - switch( this.state() ) { - case Torrent._StatusStopped: return this.isFinished() ? 'Seeding complete' : 'Paused'; - case Torrent._StatusCheckWait: return 'Queued for verification'; - case Torrent._StatusCheck: return 'Verifying local data'; - case Torrent._StatusDownloadWait: return 'Queued for download'; - case Torrent._StatusDownload: return 'Downloading'; - case Torrent._StatusSeedWait: return 'Queued for seeding'; - case Torrent._StatusSeed: return 'Seeding'; - default: return 'error'; - } - }, - trackerStats: function() { return this._trackerStats; }, - uploadSpeed: function() { return this._upload_speed; }, - uploadTotal: function() { return this._upload_total; }, - seedRatioLimit: function(controller){ - switch( this._seed_ratio_mode ) { - 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; - }, - - - /*-------------------------------------------- - * - * I N T E R F A C E F U N C T I O N S - * - *--------------------------------------------*/ - fireDataChanged: function() { - $(this).trigger('dataChanged',[]); + $(this).trigger('dataChanged',[]) }, refreshMetaData: function(data) { - this.initMetaData( data ); - this.fireDataChanged(); + this.initMetaData(data) + this.fireDataChanged() }, refresh: function(data) { - if( this.needsMetaData() && ( data.metadataPercentComplete >= 1 ) ) - transmission.refreshMetaData( [ this._id ] ); + // FIXME: unnecessary coupling... this should be handled by transmission.js + if(this.needsMetaData() && (data.metadataPercentComplete >= 1)) + transmission.refreshMetaData([ this.getId() ]) - this._completed = data.haveUnchecked + data.haveValid; - this._verified = data.haveValid; - this._leftUntilDone = data.leftUntilDone; - this._download_total = data.downloadedEver; - this._upload_total = data.uploadedEver; - this._upload_ratio = data.uploadRatio; - this._seed_ratio_limit = data.seedRatioLimit; - this._seed_ratio_mode = data.seedRatioMode; - this._download_speed = data.rateDownload; - this._upload_speed = data.rateUpload; - this._peers = data.peers; - this._peers_connected = data.peersConnected; - this._peers_getting_from_us = data.peersGettingFromUs; - this._peers_sending_to_us = data.peersSendingToUs; - this._queue_position = data.queuePosition; - this._webseeds_sending_to_us = data.webseedsSendingToUs; - this._sizeWhenDone = data.sizeWhenDone; - this._recheckProgress = data.recheckProgress; - this._error = data.error; - this._error_string = data.errorString; - this._eta = data.eta; - this._trackerStats = this.buildTrackerStats(data.trackerStats); - this._state = data.status; - this._download_dir = data.downloadDir; - this._metadataPercentComplete = data.metadataPercentComplete; - this._isFinishedSeeding = data.isFinished; - this._desiredAvailable = data.desiredAvailable; + var f = this.fields + + // refresh the dynamic fields + for(var i=0, key; key=Torrent._DynamicFields[i]; ++i) + if(key in data) + f[key] = data[key] + + this._trackerStats = this.buildTrackerStats(data.trackerStats) if (data.fileStats) - this.refreshFileModel( data ); + this.refreshFiles(data) - this.fireDataChanged(); + this.fireDataChanged() }, - refreshFileModel: function(data) { - for( var i=0; i 0 + || this.getPeersSendingToUs() > 0 + || this.getWebseedsSendingToUs() > 0 + || this.isChecking() + break case Prefs._FilterSeeding: - pass = ( s == Torrent._StatusSeed ) || ( s == Torrent._StatusSeedWait ); - break; + pass = (s == Torrent._StatusSeed) || (s == Torrent._StatusSeedWait) + break case Prefs._FilterDownloading: - pass = ( s == Torrent._StatusDownload ) || ( s == Torrent._StatusDownloadWait ); - break; + pass = (s == Torrent._StatusDownload) || (s == Torrent._StatusDownloadWait) + break case Prefs._FilterPaused: - pass = !this.isActive(); - break; + pass = this.isStopped() + break case Prefs._FilterFinished: - pass = this.isFinished(); - break; + pass = this.isFinished() + break default: - pass = true; - break; + pass = true + break } - if( !pass ) - return false; + if(!pass) + return false - if( !search || !search.length ) - return pass; + if(!search || !search.length) + return pass - return this._name_lc.indexOf( search.toLowerCase() ) !== -1; + return this.getCollatedName().indexOf(search.toLowerCase()) !== -1 } -}; +} -/** Helper function for Torrent.sortTorrents(). */ -Torrent.compareById = function( a, b ) { - return a.id() - b.id(); -}; -/** Helper function for sortTorrents(). */ -Torrent.compareByName = function( a, b ) { - var i = a._name_lc.compareTo( b._name_lc ); - if( i ) - return i; - return Torrent.compareById( a, b ); -}; +/*** +**** +**** SORTING +**** +***/ -/** Helper function for sortTorrents(). */ -Torrent.compareByQueue = function( a, b ) +Torrent.compareById = function(ta, tb) { - return a.queuePosition( ) - b.queuePosition(); -}; - -/** Helper function for sortTorrents(). */ -Torrent.compareByAge = function( a, b ) + return ta.getId() - tb.getId() +} +Torrent.compareByName = function(ta, tb) { - var a_age = a.dateAdded(); - var b_age = b.dateAdded(); - if( a_age != b_age ) - return a_age - b_age; - - return Torrent.compareByQueue( a, b ); -}; - -/** Helper function for sortTorrents(). */ -Torrent.compareByState = function( a, b ) + var i = ta.getCollatedName().compareTo(tb.getCollatedName()) + return i || Torrent.compareById(ta, tb) +} +Torrent.compareByQueue = function(ta, tb) { - var a_state = a.state( ); - var b_state = b.state( ); - if( a_state != b_state ) - return b_state - a_state; - - return Torrent.compareByQueue( a, b ); -}; - -/** Helper function for sortTorrents(). */ -Torrent.compareByActivity = function( a, b ) + return ta.getQueuePosition() - tb.getQueuePosition() +} +Torrent.compareByAge = function(ta, tb) { - var a_activity = a.activity( ); - var b_activity = b.activity( ); - if( a_activity != b_activity ) - return a_activity - b_activity; - - return Torrent.compareByState( a, b ); -}; - -/** Helper function for sortTorrents(). */ -Torrent.compareByRatio = function( a, b ) { - var a_ratio = Math.ratio( a._upload_total, a._download_total ); - var b_ratio = Math.ratio( b._upload_total, b._download_total ); - if( a_ratio != b_ratio ) - return a_ratio - b_ratio; - return Torrent.compareByState( a, b ); -}; - -Torrent.compareByProgress = function( a, b ) { - if( a.getPercentDone() !== b.getPercentDone() ) - return a.getPercentDone() - b.getPercentDone(); - return Torrent.compareByRatio( a, b ); -}; + var a = ta.getDateAdded() + var b = tb.getDateAdded() + return (b - a) || Torrent.compareByQueue(ta, tb) +} +Torrent.compareByState = function(ta, tb) +{ + var a = ta.getStatus() + var b = tb.getStatus() + return (b - a) || Torrent.compareByQueue(ta, tb) +} +Torrent.compareByActivity = function(ta, tb) +{ + var a = ta.getActivity() + var b = tb.getActivity() + return (a - b) || Torrent.compareByState(ta, tb) +} +Torrent.compareByRatio = function(a, b) +{ + var a = Math.ratio(ta.getUploadedEver(), ta.getDownloadedEver()) + var b = Math.ratio(tb.getUploadedEver(), tb.getDownloadedEver()) + return (a - b) || Torrent.compareByState(ta, tb) +} +Torrent.compareByProgress = function(ta, tb) +{ + var a = ta.getPercentDone() + var b = tb.getPercentDone() + return (a - b) || Torrent.compareByRatio(ta, tb) +} /** * @param torrents an array of Torrent objects * @param sortMethod one of Prefs._SortBy* * @param sortDirection Prefs._SortAscending or Prefs._SortDescending */ -Torrent.sortTorrents = function( torrents, sortMethod, sortDirection ) +Torrent.sortTorrents = function(torrents, sortMethod, sortDirection) { - switch( sortMethod ) + switch(sortMethod) { case Prefs._SortByActivity: - torrents.sort( this.compareByActivity ); - break; + torrents.sort(this.compareByActivity) + break case Prefs._SortByAge: - torrents.sort( this.compareByAge ); - break; + torrents.sort(this.compareByAge) + break case Prefs._SortByQueue: - torrents.sort( this.compareByQueue ); - break; + torrents.sort(this.compareByQueue) + break case Prefs._SortByProgress: - torrents.sort( this.compareByProgress ); - break; + torrents.sort(this.compareByProgress) + break case Prefs._SortByState: - torrents.sort( this.compareByState ); - break; + torrents.sort(this.compareByState) + break case Prefs._SortByName: - torrents.sort( this.compareByName ); - break; + torrents.sort(this.compareByName) + break case Prefs._SortByRatio: - torrents.sort( this.compareByRatio ); - break; + torrents.sort(this.compareByRatio) + break default: - console.warn( "unknown sort method: " + sortMethod ); - break; + console.warn("unknown sort method: " + sortMethod) + break } - if( sortDirection === Prefs._SortDescending ) - torrents.reverse( ); + if(sortDirection === Prefs._SortDescending) + torrents.reverse() - return torrents; -}; + return torrents +} diff --git a/web/javascript/transmission.js b/web/javascript/transmission.js index 983f2473a..fcaa94929 100644 --- a/web/javascript/transmission.js +++ b/web/javascript/transmission.js @@ -467,7 +467,7 @@ Transmission.prototype = ret[ key ] = this._torrents[key]; var sel = this.getSelectedTorrents( ); for( var i=0, tor; tor=sel[i]; ++i ) - delete ret[ tor.id() ]; + delete ret[ tor.getId() ]; return ret; }, @@ -862,7 +862,7 @@ Transmission.prototype = 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) ) + if( row.isEditable() && (torrent._files[i].wanted !== wanted) ) rows.push( row ); if( rows.length > 1 ) { var command = wanted ? 'files-wanted' : 'files-unwanted'; @@ -1019,7 +1019,7 @@ Transmission.prototype = updateSelectedData: function() { - var ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.id(); } ); + var ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.getId(); } ); if( ids.length > 0 ) this.periodicTorrentUpdate( ids ); else @@ -1395,46 +1395,49 @@ Transmission.prototype = } name = torrents.length == 1 - ? torrents[0].name() + ? 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( t._comment) - comment = t._comment ; - if( t._creator ) - creator = t._creator ; - if( t._download_dir) - download_dir = t._download_dir; + if(( text = t.getComment())) + comment = text + if(( text = t.getCreator())) + creator = text + if(( text = t.getDownloadDir())) + download_dir = text - hash = t.hash(); - pieces = [ t._pieceCount, 'pieces @', Transmission.fmt.mem(t._pieceSize) ].join(' '); - date_created = Transmission.fmt.timestamp( t._creator_date ); + 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 ) { - 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_upload_peers += t.peersGettingFromUs(); - total_download_peers += t.peersSendingToUs(); - total_availability += t._sizeWhenDone - t._leftUntilDone + t._desiredAvailable; + 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.stateStr(); + var s = t.getStateString(); if( total_state.indexOf( s ) == -1 ) total_state.push( s ); - if( t._is_private ) + if( t.getPrivateFlag( ) ) have_private = true; else have_public = true; @@ -1515,7 +1518,7 @@ Transmission.prototype = // build the file list this.clearFileList( ); this._files_torrent = torrent; - var n = torrent._file_model.length; + var n = torrent._files.length; this._files = new Array( n ); var fragment = document.createDocumentFragment( ); var tr = this; @@ -1541,11 +1544,12 @@ Transmission.prototype = var torrents = this.getSelectedTorrents( ); if( $(this._inspector_peers_list).is(':visible') ) { for( var k=0, torrent; torrent=torrents[k]; ++k ) { + var peers = torrent.getPeers() html.push( '
' ); if( torrents.length > 1 ) { - html.push( '
', torrent._name, '
' ); + html.push( '
', torrent.getName(), '
' ); } - if( torrent._peers.length == 0 ) { + if( peers.length == 0 ) { html.push( '
' ); // firefox won't paint the top border if the div is empty continue; } @@ -1559,7 +1563,7 @@ Transmission.prototype = 'Address', 'Client', '' ); - for( var i=0, peer; peer=torrent._peers[i]; ++i ) { + for( var i=0, peer; peer=peers[i]; ++i ) { var parity = ((i+1) % 2 == 0 ? 'even' : 'odd'); html.push( '', '', (peer.isEncrypted ? 'Encrypted' : ''), '', @@ -1588,7 +1592,7 @@ Transmission.prototype = for( var k=0, torrent; torrent = torrents[k]; ++k ) { html.push( '
' ); if( torrents.length > 1 ) { - html.push( '
', torrent._name, '
' ); + html.push( '
', torrent.getName(), '
' ); } for( var i=0, tier; tier=torrent._trackerStats[i]; ++i ) { html.push( '
', @@ -1770,7 +1774,7 @@ Transmission.prototype = if( t ) { t.refreshMetaData( this ); if( selected_torrents.indexOf(t) != -1 ) - refresh_files_for.push( t.id( ) ); + refresh_files_for.push( t.getId( ) ); } } ); if( refresh_files_for.length > 0 ) @@ -1798,7 +1802,7 @@ Transmission.prototype = else { t.refresh(o); if( selected_torrents.indexOf(t) != -1 ) - refresh_files_for.push(t.id()); + refresh_files_for.push(t.getId()); } } @@ -1822,7 +1826,7 @@ Transmission.prototype = for( var i=0, o; o=torrents[i]; ++i ) { var t = this._torrents[o.id]; if( t !== null ) { - t.refreshFileModel( o ); + t.refreshFiles( o ); if( t === this._files_torrent ) this.refreshFileView(); } @@ -1888,43 +1892,34 @@ Transmission.prototype = for( var i=0, row; row=new_torrents[i]; ++i ) { var t = new Torrent( this, row ); - this._torrents[t.id()] = t; + this._torrents[t.getId()] = t; } 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 = tr._torrents[id]; + return false - if(torrent) { - removedAny = true; - var e = torrent.view; - if( e ) { - var row_index; - for( var i=0, row; row = tr._rows[i]; ++i ) { - if( row._id == torrent._id ) - { - row_index = i; - e = tr._rows[row_index]; - break; - } - } - delete e._torrent; //remove circular refernce to help IE garbage collect - tr._rows.splice(row_index, 1) - e.remove(); - } + var keep = [ ] + var elements = [ ] - delete tr._torrents[torrent.id()]; + 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() } - }); + } - return removedAny; + this._rows = keep + + return remove.length > 0 }, refreshDisplay: function( ) @@ -1954,8 +1949,8 @@ Transmission.prototype = var upSpeed = 0; var downSpeed = 0; for( var i=0, row; row=torrents[i]; ++i ) { - upSpeed += row.uploadSpeed( ); - downSpeed += row.downloadSpeed( ); + upSpeed += row.getUploadSpeed( ); + downSpeed += row.getDownloadSpeed( ); } // update torrent count label @@ -2034,7 +2029,7 @@ Transmission.prototype = if( torrents.length == 1 ) { var torrent = torrents[0]; - var header = 'Remove ' + torrent.name() + '?'; + 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 ); } @@ -2051,7 +2046,7 @@ Transmission.prototype = if( torrents.length == 1 ) { var torrent = torrents[0], - header = 'Remove ' + torrent.name() + ' and delete data?', + 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 ); } @@ -2064,7 +2059,7 @@ Transmission.prototype = }, removeTorrents: function( torrents ) { - var torrent_ids = jQuery.map(torrents, function(t) { return t.id(); } ); + var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } ); var tr = this; this.remote.removeTorrents( torrent_ids, function(){ tr.refreshTorrents() } ); }, @@ -2091,7 +2086,7 @@ Transmission.prototype = this.startTorrents( [ torrent ], false ); }, startTorrents: function( torrents, force ) { - var torrent_ids = jQuery.map(torrents, function(t) { return t.id(); } ); + 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) } ); }, @@ -2099,7 +2094,7 @@ Transmission.prototype = this.verifyTorrents( [ torrent ] ); }, verifyTorrents: function( torrents ) { - var torrent_ids = jQuery.map(torrents, function(t) { return t.id(); } ); + var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } ); var tr = this; this.remote.verifyTorrents( torrent_ids, function(){ tr.refreshTorrents(torrent_ids) } ); }, @@ -2108,7 +2103,7 @@ Transmission.prototype = this.reannounceTorrents( [ torrent ] ); }, reannounceTorrents: function( torrents ) { - var torrent_ids = jQuery.map(torrents, function(t) { return t.id(); } ); + var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } ); var tr = this; this.remote.reannounceTorrents( torrent_ids, function(){ tr.refreshTorrents(torrent_ids) } ); }, @@ -2123,7 +2118,7 @@ Transmission.prototype = this.stopTorrents( [ torrent ] ); }, stopTorrents: function( torrents ) { - var torrent_ids = jQuery.map(torrents, function(t) { return t.id(); } ); + var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); } ); var tr = this; this.remote.stopTorrents( torrent_ids, function(){ tr.refreshTorrents(torrent_ids )} ); }, @@ -2148,22 +2143,22 @@ Transmission.prototype = // Queue moveTop: function( ) { - var torrent_ids = jQuery.map(this.getSelectedTorrents( ), function(t) { return t.id(); } ); + 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.id(); } ); + 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.id(); } ); + 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.id(); } ); + 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 )} ); }, @@ -2262,13 +2257,13 @@ Transmission.prototype = for( var i=0, row; row=this._rows[i]; ++i ) { if( row.isVisible( ) ) { - var isActive = row.getTorrent().isActive( ); + var isStopped = row.getTorrent().isStopped( ); var isSelected = row.isSelected(); - if( isActive ) haveActive = true; - if( !isActive ) havePaused = true; + if( !isStopped ) haveActive = true; + if( isStopped ) havePaused = true; if( isSelected ) haveSelection = true; - if( isSelected && isActive ) haveActiveSelection = true; - if( isSelected && !isActive ) havePausedSelection = true; + if( isSelected && !isStopped ) haveActiveSelection = true; + if( isSelected && isStopped ) havePausedSelection = true; } } diff --git a/web/javascript/transmission.remote.js b/web/javascript/transmission.remote.js index 72d9e50fa..45f85735d 100644 --- a/web/javascript/transmission.remote.js +++ b/web/javascript/transmission.remote.js @@ -191,7 +191,7 @@ TransmissionRemote.prototype = changeFileCommand: function( command, rows ) { var remote = this; - var torrent_ids = [ rows[0].getTorrent().id() ]; + var torrent_ids = [ rows[0].getTorrent().getId() ]; var files = [ ]; for( var i=0, row; row=rows[i]; ++i ) files.push( row.getIndex( ) ); @@ -244,7 +244,7 @@ TransmissionRemote.prototype = if( torrents != null ) for( var i=0, len=torrents.length; i