From b36c648b316474330b1e05cd62f59f5f752c1048 Mon Sep 17 00:00:00 2001 From: Jordan Lee Date: Sat, 20 Aug 2011 21:17:12 +0000 Subject: [PATCH] (trunk web) Torrent class cleanup: 1. remove some of its unnecessary coupling to other classes 2. make more of its method names consistent with each other 3. make its field names consistent with the RPC spec 4. better grouping of methods by relevance 5. syntactical cleanup --- web/javascript/file-row.js | 8 +- web/javascript/torrent-renderer.js | 73 +-- web/javascript/torrent.js | 640 +++++++++++++------------- web/javascript/transmission.js | 153 +++--- web/javascript/transmission.remote.js | 4 +- 5 files changed, 440 insertions(+), 438 deletions(-) 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