Changeset 12745


Ignore:
Timestamp:
Aug 25, 2011, 11:06:41 PM (11 years ago)
Author:
jordan
Message:

(trunk web) significant shrinkage of our memory + network footprint by only loading torrent's fields when they're needed.

Location:
trunk/web/javascript
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/web/javascript/file-row.js

    r12716 r12745  
    9191                var i = this.getIndex();
    9292                var t = this.getTorrent();
    93                 this.readAttributes(t._files[i]);
     93                this.readAttributes(t.getFile(i));
    9494                this.refreshHTML();
    9595        },
     
    9999        },
    100100        isEditable: function () {
    101                 return (this.getTorrent()._files.length>1) && !this.isDone();
     101                return (this.getTorrent().getFileCount()>1) && !this.isDone();
    102102        },
    103103
     
    105105        {
    106106                var me = this;
    107                 var file = torrent._files[i];
     107                var file = torrent.getFile(i);
    108108                var name = file.name.substring (file.name.lastIndexOf('/')+1);
    109109
  • trunk/web/javascript/torrent.js

    r12744 r12745  
    4646
    4747
    48 // fields whose values never change and are always known
    49 Torrent._StaticFields = [
    50         'hashString', 'id' ];
    51 
    52 // fields whose values never change and are known upon constructon OR
    53 // when a magnet torrent finishes downloading its metadata
    54 Torrent._MetaDataFields = [
    55         'addedDate', 'comment', 'creator', 'dateCreated',
    56         'isPrivate', 'name', 'totalSize', 'pieceCount', 'pieceSize' ];
    57 
    58 // torrent fields whose values change all the time
    59 Torrent._DynamicFields = [
    60         'desiredAvailable', 'downloadDir', 'downloadedEver', 'error',
    61         'errorString', 'eta', 'haveUnchecked', 'haveValid', 'isFinished',
    62         'leftUntilDone', 'metadataPercentComplete', 'peers', 'peersConnected',
    63         'peersGettingFromUs', 'peersSendingToUs', 'queuePosition',
    64         'rateDownload', 'rateUpload', 'recheckProgress', 'seedRatioLimit',
    65         'seedRatioMode', 'sizeWhenDone', 'status', 'trackerStats',
    66         'uploadedEver', 'uploadRatio', 'webseedsSendingToUs' ];
     48Torrent.Fields = { };
     49
     50// commonly used fields which only need to be loaded once,
     51// either on startup or when a magnet finishes downloading its metadata
     52// finishes downloading its metadata
     53Torrent.Fields.Metadata = [
     54        'addedDate',
     55        'name',
     56        'totalSize'
     57];
     58
     59// commonly used fields which need to be periodically refreshed
     60Torrent.Fields.Stats = [
     61        'error',
     62        'errorString',
     63        'eta',
     64        'isFinished',
     65        'isStalled',
     66        'leftUntilDone',
     67        'metadataPercentComplete',
     68        'peersConnected',
     69        'peersGettingFromUs',
     70        'peersSendingToUs',
     71        'percentDone',
     72        'queuePosition',
     73        'rateDownload',
     74        'rateUpload',
     75        'recheckProgress',
     76        'seedRatioMode',
     77        'sizeWhenDone',
     78        'status',
     79        'trackers',
     80        'uploadedEver',
     81        'uploadRatio'
     82];
     83
     84// fields used by the inspector which only need to be loaded once
     85Torrent.Fields.InfoExtra = [
     86        'comment',
     87        'creator',
     88        'dateCreated',
     89        'files',
     90        'hashString',
     91        'isPrivate',
     92        'pieceCount',
     93        'pieceSize'
     94];
     95
     96// fields used in the inspector which need to be periodically refreshed
     97Torrent.Fields.StatsExtra = [
     98        'activityDate',
     99        'desiredAvailable',
     100        'downloadDir',
     101        'downloadLimit',
     102        'downloadLimited',
     103        'downloadedEver',
     104        'fileStats',
     105        'haveUnchecked',
     106        'haveValid',
     107        'honorsSessionLimits',
     108        'manualAnnounceTime',
     109        'peer-limit',
     110        'peers',
     111        'seedIdleLimit',
     112        'seedIdleMode',
     113        'seedRatioLimit',
     114        'startDate',
     115        'torrentFile',
     116        'trackerStats',
     117        'uploadLimited',
     118        'uploadLimit',
     119        'webseedsSendingToUs'
     120];
    67121
    68122/***
     
    77131        {
    78132                this.fields = {};
    79                 this._files = [];
    80 
    81                 // these fields are set in the ctor and never change
    82                 for (var i=0, key; key=Torrent._StaticFields[i]; ++i) {
    83                         if (key in data) {
    84                                 this.fields[key] = data[key];
     133                this.refresh (data);
     134        },
     135
     136        setField: function(o, name, value)
     137        {
     138                var changed = !(name in o) || (o[name] !== value);
     139                if (changed)
     140                        o[name] = value;
     141                return changed;
     142        },
     143
     144        // fields.files is an array of unions of RPC's "files" and "fileStats" objects.
     145        updateFiles: function(files) {
     146                var changed = false;
     147                var myfiles = this.fields.files || [];
     148                var keys = [ 'length', 'name', 'bytesCompleted', 'wanted', 'priority' ];
     149                for (var i=0, f; f=files[i]; ++i) {
     150                        var myfile = myfiles[i] || {};
     151                        for (var j=0, key; key=keys[j]; ++j)
     152                                if(key in f)
     153                                        changed |= this.setField(myfile,key,f[key]);
     154                        myfiles[i] = myfile;
     155                }
     156                this.fields.files = myfiles;
     157                return changed;
     158        },
     159
     160        collateTrackers: function(trackers) {
     161                announces = [];
     162                for (var i=0, t; t=trackers[i]; ++i)
     163                        announces.push(t.announce.toLowerCase());
     164                return announces.join('\t');
     165        },
     166
     167        isField: function(name) {
     168                return ( name === 'id' )
     169                    || ( Torrent.Fields.Stats.indexOf(name)      !== -1 )
     170                    || ( Torrent.Fields.StatsExtra.indexOf(name) !== -1 )
     171                    || ( Torrent.Fields.InfoExtra.indexOf(name)  !== -1 )
     172                    || ( Torrent.Fields.Metadata.indexOf(name)   !== -1 );
     173        },
     174
     175        refreshFields: function(data)
     176        {
     177                var changed = false;
     178
     179                for (var key in data) {
     180                        if (this.isField(key)) switch (key) {
     181                                case 'files':
     182                                case 'fileStats': // merge files and fileStats together
     183                                        changed |= this.updateFiles(data[key]);
     184                                        break;
     185                                case 'trackerStats': // 'trackerStats' is a superset of 'trackers'...
     186                                        changed |= this.setField(this.fields,'trackers',data[key]);
     187                                case 'trackers': // ...so only save 'trackers' if we don't have it already
     188                                        if (!(key in this.fields))
     189                                                changed |= this.setField(this.fields,key,data[key]);
     190                                        break;
     191                                default:
     192                                        changed |= this.setField(this.fields,key,data[key]);
    85193                        }
    86194                }
    87195
    88                 this.initMetaData(data);
    89                 this._trackerStats = this.buildTrackerStats(data.trackerStats);
    90                 this.refresh(data);
    91         },
    92 
    93         buildTrackerStats: function(trackerStats) {
    94                 var announce = [];
    95                 var result = [];
    96                 for (var i=0, tracker; tracker=trackerStats[i]; ++i) {
    97                         var tier = result[tracker.tier] || [];
    98                         tier.push(tracker);
    99                         result[tracker.tier] = tier;
    100                         announce.push(tracker.announce);
    101                 }
    102                 this.fields.collatedTrackers = announce.join('\t');
    103                 return result;
    104         },
    105 
    106         initMetaData: function(data) {
    107 
    108                 var f = this.fields;
    109                 var changed = false;
    110 
    111                 // populate the metadata fields
    112                 for (var i=0, key; key=Torrent._MetaDataFields[i]; ++i) {
    113                         if (key in data) {
    114                                 if (f[key] !== data[key]) {
    115                                         f[key] = data[key];
    116                                         if (key === 'name')
    117                                                 f.collatedName = data.name.toLowerCase();
    118                                         changed = true;
    119                                 }
    120                         }
    121                 }
    122 
    123                 // populate the files array
    124                 if (data.files) {
    125                         for (var i=0, row; row=data.files[i]; ++i) {
    126                                 this._files[i] = {
    127                                         'index': i,
    128                                         'length': row.length,
    129                                         'name': row.name
    130                                 };
    131                         }
    132                 }
    133 
    134196                return changed;
    135197        },
    136198
    137         refreshMetaData: function(data)
    138         {
    139                 var changed = this.initMetaData(data);
    140                 if (changed)
    141                         this.fireDataChanged();
    142                 return changed;
    143         },
    144 
    145199        refresh: function(data)
    146200        {
    147                 var changed = false;
    148 
    149                 // FIXME: unnecessary coupling... this should be handled by transmission.js
    150                 if (this.needsMetaData() && (data.metadataPercentComplete >= 1))
    151                         changed |= transmission.refreshMetaData([ this.getId() ]);
    152 
    153                 var f = this.fields;
    154 
    155                 // refresh the dynamic fields
    156                 for (var i=0, key; key=Torrent._DynamicFields[i]; ++i) {
    157                         if (key in data) {
    158                                 if (f[key] !== data[key]) {
    159                                         f[key] = data[key];
    160                                         changed = true;
    161                                 }
    162                         }
    163                 }
    164 
    165                 this._trackerStats = this.buildTrackerStats(data.trackerStats);
    166 
    167                 if (data.fileStats)
    168                         changed |= this.refreshFiles(data);
    169 
    170                 if (changed)
    171                         this.fireDataChanged();
    172         },
    173 
    174         refreshFiles: function(data) {
    175                 var changed = false;
    176                 for (var i=0; i<data.fileStats.length; ++i) {
    177                         var src = data.fileStats[i];
    178                         var tgt = this._files[i];
    179                         if (!tgt) {
    180                                 changed = true;
    181                                 tgt = this._files[i] = { };
    182                         }
    183                         if (tgt.wanted !== src.wanted) {
    184                                 tgt.wanted = src.wanted;
    185                                 changed = true;
    186                         }
    187                         if (tgt.priority !== src.priority) {
    188                                 tgt.priority = src.priority;
    189                                 changed = true;
    190                         }
    191                         if (tgt.bytesCompleted !== src.bytesCompleted) {
    192                                 tgt.bytesCompleted = src.bytesCompleted;
    193                                 changed = true;
    194                         }
    195                 }
    196                 return changed;
    197         },
    198 
    199         fireDataChanged: function()
    200         {
    201                 $(this).trigger('dataChanged');
     201                if (this.refreshFields(data))
     202                        $(this).trigger('dataChanged');
    202203        },
    203204
     
    220221        getErrorString: function() { return this.fields.errorString; },
    221222        getETA: function() { return this.fields.eta; },
     223        getFile: function(i) { return this.fields.files[i]; },
     224        getFileCount: function() { return this.fields.files ? this.fields.files.length : 0; },
    222225        getHashString: function() { return this.fields.hashString; },
    223226        getHaveValid: function() { return this.fields.haveValid; },
     
    232235        getPeersSendingToUs: function() { return this.fields.peersSendingToUs; },
    233236        getPieceCount: function() { return this.fields.pieceCount; },
    234         getPieceCount: function() { return this.fields.pieceCount; },
    235237        getPieceSize: function() { return this.fields.pieceSize; },
    236238        getPrivateFlag: function() { return this.fields.isPrivate; },
     
    242244        getStatus: function() { return this.fields.status; },
    243245        getTotalSize: function() { return this.fields.totalSize; },
     246        getTrackers: function() { return this.fields.trackers; },
    244247        getUploadSpeed: function() { return this.fields.rateUpload; },
    245248        getUploadRatio: function() { return this.fields.uploadRatio; },
     
    276279                }
    277280        },
    278         trackerStats: function() { return this._trackerStats; },
    279281        seedRatioLimit: function(controller){
    280282                switch(this.getSeedRatioMode()) {
     
    363365Torrent.compareByName = function(ta, tb)
    364366{
    365         return ta.getCollatedName().compareTo(tb.getCollatedName())
    366             || Torrent.compareById(ta, tb);
     367        var i = 0;
     368        var a = ta.getCollatedName();
     369        var b = tb.getCollatedName();
     370        if (a && b)
     371                i = a.compareTo(b);
     372        if (i)
     373                return i;
     374        return Torrent.compareById(ta, tb);
    367375};
    368376Torrent.compareByQueue = function(ta, tb)
  • trunk/web/javascript/transmission.js

    r12743 r12745  
    6969
    7070                if (iPhone) {
    71                         $('#inspector_close').bind('click', function() { tr.hideInspector(); });
     71                        $('#inspector_close').bind('click', function() { tr.setInspectorVisible(false); });
    7272                        $('#preferences_link').bind('click', function(e) { tr.releaseClutchPreferencesButton(e); });
    7373                } else {
     
    7575                        $(document).bind('keyup',  function(e) { tr.keyUp(e); });
    7676                        $('#torrent_container').click(function() { tr.deselectAll(true); });
    77                         $('#inspector_link').click(function(e) { tr.toggleInspectorClicked(e); });
     77                        $('#inspector_link').click(function(e) { tr.toggleInspector(); });
    7878
    7979                        this.setupSearchBox();
     
    8787                this._inspector_peers_list     = $('#inspector_peers_list')[0];
    8888                this._inspector_trackers_list  = $('#inspector_trackers_list')[0];
    89                 this._inspector_tab_files      = $('#inspector_tab_files')[0];
    9089                this._toolbar_buttons          = $('#toolbar ul li');
    9190                this._toolbar_pause_button     = $('#toolbar #pause_selected')[0];
     
    222221
    223222                if (!iPhone && this[Prefs._ShowInspector])
    224                         this.showInspector();
     223                        this.setInspectorVisible(true);
    225224
    226225                this.initCompactMode();
     
    474473        selectionChanged: function()
    475474        {
     475                if (this[Prefs._ShowInspector])
     476                        this.refreshInspectorTorrents(true);
     477
    476478                this.updateButtonStates();
    477479                this.updateInspector();
     
    720722        },
    721723
    722         toggleInspectorClicked: function(ev) {
    723                 if (this.isButtonEnabled(ev))
    724                         this.toggleInspector();
    725         },
    726 
    727724        inspectorTabClicked: function(ev, tab) {
    728725                if (iPhone) ev.stopPropagation();
     
    741738
    742739        filesSelectAllClicked: function() {
    743                 var t = this._files_torrent;
     740                var t = this._file_torrent;
    744741                if (t)
    745742                        this.toggleFilesWantedDisplay(t, true);
    746743        },
    747744        filesDeselectAllClicked: function() {
    748                 var t = this._files_torrent;
     745                var t = this._file_torrent;
    749746                if (t)
    750747                        this.toggleFilesWantedDisplay(t, false);
     
    752749        toggleFilesWantedDisplay: function(torrent, wanted) {
    753750                var rows = [ ];
    754                 for (var i=0, row; row=this._files[i]; ++i)
    755                         if (row.isEditable() && (torrent._files[i].wanted !== wanted))
     751                for (var i=0, row; row=this._file_rows[i]; ++i)
     752                        if (row.isEditable() && (torrent.getFile(i).wanted !== wanted))
    756753                                rows.push(row);
    757754                if (rows.length > 0) {
     
    11451142                var torrents = this.getSelectedTorrents();
    11461143                if (!torrents.length && iPhone) {
    1147                         this.hideInspector();
     1144                        this.setInspectorVisible(false);
    11481145                        return;
    11491146                }
     
    13031300                this.changeFileCommand(command, [ row ]);
    13041301        },
    1305         clearFileList: function() {
     1302        clearFileList: function()
     1303        {
    13061304                $(this._inspector_file_list).empty();
    1307                 delete this._files_torrent;
    1308                 delete this._files;
    1309         },
    1310         updateFileList: function() {
    1311 
    1312                 // if the file list is hidden, clear the list
    1313                 if (this._inspector_tab_files.className.indexOf('selected') == -1) {
     1305                delete this._file_torrent;
     1306                delete this._file_rows;
     1307        },
     1308        updateFileList: function()
     1309        {
     1310                if (!$(this._inspector_file_list).is(':visible'))
     1311                        return;
     1312
     1313                var sel = this.getSelectedTorrents();
     1314                if (sel.length !== 1) {
    13141315                        this.clearFileList();
    13151316                        return;
    13161317                }
    13171318
    1318                 // if not torrent is selected, clear the list
    1319                 var selected_torrents = this.getSelectedTorrents();
    1320                 if (selected_torrents.length != 1) {
    1321                         this.clearFileList();
    1322                         return;
    1323                 }
    1324 
    1325                 // if the active torrent hasn't changed, noop
    1326                 var torrent = selected_torrents[0];
    1327                 if (this._files_torrent === torrent)
    1328                         return;
     1319                var torrent = sel[0];
     1320                if (torrent === this._files_torrent)
     1321                        if(torrent.getFileCount() === (this._files ? this._files.length: 0))
     1322                                return;
    13291323
    13301324                // build the file list
    13311325                this.clearFileList();
    1332                 this._files_torrent = torrent;
    1333                 var n = torrent._files.length;
    1334                 this._files = new Array(n);
     1326                this._file_torrent = torrent;
     1327                var n = torrent.getFileCount();
     1328                this._file_rows = [];
    13351329                var fragment = document.createDocumentFragment();
    13361330                var tr = this;
    13371331                for (var i=0; i<n; ++i) {
    1338                         var row = new FileRow(torrent, i);
     1332                        var row = this._file_rows[i] = new FileRow(torrent, i);
    13391333                        fragment.appendChild(row.getElement());
    1340                         this._files[i] = row;
    13411334                        $(row).bind('wantedToggled',function(e,row,want) {tr.onFileWantedToggled(row,want);});
    13421335                        $(row).bind('priorityToggled',function(e,row,priority) {tr.onFilePriorityToggled(row,priority);});
     
    13451338        },
    13461339
    1347         refreshFileView: function() {
    1348                 for (var i=0, row; row=this._files[i]; ++i)
    1349                         row.refresh();
    1350         },
    1351 
    1352         updatePeersLists: function() {
     1340        updatePeersLists: function()
     1341        {
     1342                if (!$(this._inspector_peers_list).is(':visible'))
     1343                        return;
     1344
    13531345                var html = [ ];
    13541346                var fmt = Transmission.fmt;
    13551347                var torrents = this.getSelectedTorrents();
    1356                 if ($(this._inspector_peers_list).is(':visible')) {
    1357                         for (var k=0, torrent; torrent=torrents[k]; ++k) {
    1358                                 var peers = torrent.getPeers();
    1359                                 html.push('<div class="inspector_group">');
    1360                                 if (torrents.length > 1) {
    1361                                         html.push('<div class="inspector_torrent_label">', torrent.getName(), '</div>');
    1362                                 }
    1363                                 if (peers.length == 0) {
    1364                                         html.push('<br></div>'); // firefox won't paint the top border if the div is empty
    1365                                         continue;
    1366                                 }
    1367                                 html.push('<table class="peer_list">',
    1368                                            '<tr class="inspector_peer_entry even">',
    1369                                            '<th class="encryptedCol"></th>',
    1370                                            '<th class="upCol">Up</th>',
    1371                                            '<th class="downCol">Down</th>',
    1372                                            '<th class="percentCol">%</th>',
    1373                                            '<th class="statusCol">Status</th>',
    1374                                            '<th class="addressCol">Address</th>',
    1375                                            '<th class="clientCol">Client</th>',
    1376                                            '</tr>');
    1377                                 for (var i=0, peer; peer=peers[i]; ++i) {
    1378                                         var parity = ((i+1) % 2 == 0 ? 'even' : 'odd');
    1379                                         html.push('<tr class="inspector_peer_entry ', parity, '">',
    1380                                                    '<td>', (peer.isEncrypted ? '<img src="images/graphics/lock_icon.png" alt="Encrypted"/>' : ''), '</td>',
    1381                                                    '<td>', (peer.rateToPeer ? fmt.speedBps(peer.rateToPeer) : ''), '</td>',
    1382                                                    '<td>', (peer.rateToClient ? fmt.speedBps(peer.rateToClient) : ''), '</td>',
    1383                                                    '<td class="percentCol">', Math.floor(peer.progress*100), '%', '</td>',
    1384                                                    '<td>', fmt.peerStatus(peer.flagStr), '</td>',
    1385                                                    '<td>', peer.address, '</td>',
    1386                                                    '<td class="clientCol">', peer.clientName, '</td>',
    1387                                                    '</tr>');
    1388                                 }
    1389                                 html.push('</table></div>');
     1348
     1349                for (var k=0, torrent; torrent=torrents[k]; ++k) {
     1350                        var peers = torrent.getPeers();
     1351                        html.push('<div class="inspector_group">');
     1352                        if (torrents.length > 1) {
     1353                                html.push('<div class="inspector_torrent_label">', torrent.getName(), '</div>');
    13901354                        }
    1391                 }
     1355                        if (!peers || !peers.length) {
     1356                                html.push('<br></div>'); // firefox won't paint the top border if the div is empty
     1357                                continue;
     1358                        }
     1359                        html.push('<table class="peer_list">',
     1360                                   '<tr class="inspector_peer_entry even">',
     1361                                   '<th class="encryptedCol"></th>',
     1362                                   '<th class="upCol">Up</th>',
     1363                                   '<th class="downCol">Down</th>',
     1364                                   '<th class="percentCol">%</th>',
     1365                                   '<th class="statusCol">Status</th>',
     1366                                   '<th class="addressCol">Address</th>',
     1367                                   '<th class="clientCol">Client</th>',
     1368                                   '</tr>');
     1369                        for (var i=0, peer; peer=peers[i]; ++i) {
     1370                                var parity = ((i+1) % 2 == 0 ? 'even' : 'odd');
     1371                                html.push('<tr class="inspector_peer_entry ', parity, '">',
     1372                                           '<td>', (peer.isEncrypted ? '<img src="images/graphics/lock_icon.png" alt="Encrypted"/>' : ''), '</td>',
     1373                                           '<td>', (peer.rateToPeer ? fmt.speedBps(peer.rateToPeer) : ''), '</td>',
     1374                                           '<td>', (peer.rateToClient ? fmt.speedBps(peer.rateToClient) : ''), '</td>',
     1375                                           '<td class="percentCol">', Math.floor(peer.progress*100), '%', '</td>',
     1376                                           '<td>', fmt.peerStatus(peer.flagStr), '</td>',
     1377                                           '<td>', peer.address, '</td>',
     1378                                           '<td class="clientCol">', peer.clientName, '</td>',
     1379                                           '</tr>');
     1380                        }
     1381                        html.push('</table></div>');
     1382                }
     1383
    13921384                setInnerHTML(this._inspector_peers_list, html.join(''));
    13931385        },
    13941386
    13951387        updateTrackersLists: function() {
    1396                 // By building up the HTML as as string, then have the browser
    1397                 // turn this into a DOM tree, this is a fast operation.
     1388                if (!$(this._inspector_trackers_list).is(':visible'))
     1389                        return;
     1390
    13981391                var tr = this;
    13991392                var html = [ ];
    14001393                var na = 'N/A';
    14011394                var torrents = this.getSelectedTorrents();
    1402                 if ($(this._inspector_trackers_list).is(':visible')) {
    1403                         for (var k=0, torrent; torrent = torrents[k]; ++k) {
    1404                                 html.push ('<div class="inspector_group">');
    1405                                 if (torrents.length > 1) {
    1406                                         html.push('<div class="inspector_torrent_label">', torrent.getName(), '</div>');
     1395
     1396                // By building up the HTML as as string, then have the browser
     1397                // turn this into a DOM tree, this is a fast operation.
     1398                for (var i=0, torrent; torrent=torrents[i]; ++i)
     1399                {
     1400                        html.push ('<div class="inspector_group">');
     1401
     1402                        if (torrents.length > 1)
     1403                                html.push('<div class="inspector_torrent_label">', torrent.getName(), '</div>');
     1404
     1405                        var tier = -1;
     1406                        var trackers = torrent.getTrackers();
     1407                        for (var j=0, tracker; tracker=trackers[j]; ++j)
     1408                        {
     1409                                if (tier != tracker.tier)
     1410                                {
     1411                                        if (tier !== -1) // close previous tier
     1412                                                html.push('</ul></div>');
     1413       
     1414                                        tier = tracker.tier;
     1415
     1416                                        html.push('<div class="inspector_group_label">',
     1417                                                  'Tier ', tier, '</div>',
     1418                                                  '<ul class="tier_list">');
    14071419                                }
    1408                                 for (var i=0, tier; tier=torrent._trackerStats[i]; ++i) {
    1409                                         html.push('<div class="inspector_group_label">',
    1410                                                   'Tier ', (i + 1), '</div>',
    1411                                                   '<ul class="tier_list">');
    1412                                         for (var j=0, tracker; tracker=tier[j]; ++j) {
    1413                                                 var lastAnnounceStatusHash = tr.lastAnnounceStatus(tracker);
    1414                                                 var announceState = tr.announceState(tracker);
    1415                                                 var lastScrapeStatusHash = tr.lastScrapeStatus(tracker);
    1416 
    1417                                                 // Display construction
    1418                                                 var parity = ((j+1) % 2 == 0 ? 'even' : 'odd');
    1419                                                 html.push('<li class="inspector_tracker_entry ', parity, '"><div class="tracker_host" title="', tracker.announce, '">',
    1420                                                           tracker.host, '</div>',
    1421                                                           '<div class="tracker_activity">',
    1422                                                           '<div>', lastAnnounceStatusHash['label'], ': ', lastAnnounceStatusHash['value'], '</div>',
    1423                                                           '<div>', announceState, '</div>',
    1424                                                           '<div>', lastScrapeStatusHash['label'], ': ', lastScrapeStatusHash['value'], '</div>',
    1425                                                           '</div><table class="tracker_stats">',
    1426                                                           '<tr><th>Seeders:</th><td>', (tracker.seederCount > -1 ? tracker.seederCount : na), '</td></tr>',
    1427                                                           '<tr><th>Leechers:</th><td>', (tracker.leecherCount > -1 ? tracker.leecherCount : na), '</td></tr>',
    1428                                                           '<tr><th>Downloads:</th><td>', (tracker.downloadCount > -1 ? tracker.downloadCount : na), '</td></tr>',
    1429                                                           '</table></li>');
    1430                                         }
    1431                                         html.push('</ul>');
    1432                                 }
    1433                                 html.push('</div>');
     1420
     1421                                var lastAnnounceStatusHash = tr.lastAnnounceStatus(tracker);
     1422                                var announceState = tr.announceState(tracker);
     1423                                var lastScrapeStatusHash = tr.lastScrapeStatus(tracker);
     1424
     1425                                // Display construction
     1426                                var parity = ((j+1) % 2 == 0 ? 'even' : 'odd');
     1427                                html.push('<li class="inspector_tracker_entry ', parity, '"><div class="tracker_host" title="', tracker.announce, '">',
     1428                                          tracker.host, '</div>',
     1429                                          '<div class="tracker_activity">',
     1430                                          '<div>', lastAnnounceStatusHash['label'], ': ', lastAnnounceStatusHash['value'], '</div>',
     1431                                          '<div>', announceState, '</div>',
     1432                                          '<div>', lastScrapeStatusHash['label'], ': ', lastScrapeStatusHash['value'], '</div>',
     1433                                          '</div><table class="tracker_stats">',
     1434                                          '<tr><th>Seeders:</th><td>', (tracker.seederCount > -1 ? tracker.seederCount : na), '</td></tr>',
     1435                                          '<tr><th>Leechers:</th><td>', (tracker.leecherCount > -1 ? tracker.leecherCount : na), '</td></tr>',
     1436                                          '<tr><th>Downloads:</th><td>', (tracker.downloadCount > -1 ? tracker.downloadCount : na), '</td></tr>',
     1437                                          '</table></li>');
    14341438                        }
    1435                 }
     1439                        if (tier !== -1) // close last tier
     1440                                        html.push('</ul></div>');
     1441
     1442                        html.push('</div>'); // inspector_group
     1443                }
     1444
    14361445                setInnerHTML(this._inspector_trackers_list, html.join(''));
    14371446        },
     
    14941503        },
    14951504
    1496         /*
    1497          * Toggle the visibility of the inspector (used by the context menu)
    1498          */
    1499         toggleInspector: function() {
    1500                 if (this[Prefs._ShowInspector])
    1501                         this.hideInspector();
    1502                 else
    1503                         this.showInspector();
    1504         },
    1505 
    1506         showInspector: function() {
    1507                 $('#torrent_inspector').show();
     1505        toggleInspector: function()
     1506        {
     1507                this.setInspectorVisible(!this[Prefs._ShowInspector]);
     1508        },
     1509        setInspectorVisible: function(visible)
     1510        {
     1511                // we collect extra stats on torrents when they're in the inspector...
     1512                clearInterval(this._periodic_inspector_refresh);
     1513                delete this._periodic_inspector_refresh;
     1514                if (visible) {
     1515                        var tr = this;
     1516                        this._periodic_inspector_refresh = setInterval(function() {tr.refreshInspectorTorrents(false);},2000);
     1517                        this.refreshInspectorTorrents(true);
     1518                }
     1519
     1520                // update the ui widgetry
     1521                $('#torrent_inspector').toggle(visible);
    15081522                if (iPhone) {
    1509                         $('body').addClass('inspector_showing');
    1510                         $('#inspector_close').show();
     1523                        $('body').toggleClass('inspector_showing',visible);
     1524                        $('#inspector_close').toggle(visible);
    15111525                        this.hideiPhoneAddressbar();
    15121526                } else {
    1513                         var w = $('#torrent_inspector').width() + 1 + 'px';
     1527                        var w = visible ? $('#torrent_inspector').width() + 1 + 'px' : '0px';
    15141528                        $('#torrent_container')[0].style.right = w;
    15151529                }
    15161530
    1517                 setInnerHTML($('ul li#context_toggle_inspector')[0], 'Hide Inspector');
    1518 
    1519                 this.setPref(Prefs._ShowInspector, true);
    1520                 this.updateInspector();
    1521         },
    1522 
    1523         /*
    1524          * Hide the inspector
    1525          */
    1526         hideInspector: function() {
    1527 
    1528                 $('#torrent_inspector').hide();
    1529 
    1530                 if (iPhone) {
    1531                         this.deselectAll();
    1532                         $('body.inspector_showing').removeClass('inspector_showing');
    1533                         $('#inspector_close').hide();
    1534                         this.hideiPhoneAddressbar();
    1535                 } else {
    1536                         $('#torrent_container')[0].style.right = '0px';
    1537                         setInnerHTML($('ul li#context_toggle_inspector')[0], 'Show Inspector');
    1538                 }
    1539 
    1540                 this.setPref(Prefs._ShowInspector, false);
    1541         },
    1542 
    1543         refreshMetaData: function(ids) {
    1544                 var tr = this;
    1545                 this.remote.getMetaDataFor(ids, function(active) { tr.updateMetaData(active); });
    1546         },
    1547 
    1548         updateMetaData: function(torrents)
    1549         {
    1550                 var tr = this;
    1551                 var refresh_files_for = [ ];
    1552                 var selected_torrents = this.getSelectedTorrents();
    1553                 jQuery.each(torrents, function() {
    1554                         var t = tr._torrents[ this.id ];
    1555                         if (t) {
    1556                                 t.refreshMetaData(this);
    1557                                 if (selected_torrents.indexOf(t) != -1)
    1558                                         refresh_files_for.push(t.getId());
     1531                setInnerHTML($('ul li#context_toggle_inspector')[0], (visible?'Hide':'Show')+' Inspector');
     1532                this.setPref(Prefs._ShowInspector, visible);
     1533                if (visible)
     1534                        this.updateInspector();
     1535        },
     1536
     1537        onTorrentChanged: function(ev)
     1538        {
     1539                this.refilterSoon();
     1540       
     1541                // if this torrent is in the inspector, refresh the inspector
     1542                if (this[Prefs._ShowInspector])
     1543                        if (this.getSelectedTorrentIds().indexOf(ev.target.getId()) !== -1)
     1544                                this.updateInspector();
     1545        },
     1546
     1547        updateFromTorrentGet: function(updates, removed_ids)
     1548        {
     1549                var new_ids = [];
     1550
     1551                for (var i=0, o; o=updates[i]; ++i) {
     1552                        var t;
     1553                        var id = o.id;
     1554                        if ((t = this._torrents[id]))
     1555                                t.refresh(o);
     1556                        else {
     1557                                t = this._torrents[id] = new Torrent(o);
     1558                                $(t).bind('dataChanged',function(ev) {tr.onTorrentChanged(ev);});
     1559                                new_ids.push(id);
    15591560                        }
    1560                 });
    1561                 if (refresh_files_for.length > 0)
    1562                         tr.remote.loadTorrentFiles(refresh_files_for);
     1561                }
     1562
     1563                if (new_ids.length) {
     1564                        var tr = this;
     1565                        this.remote.getTorrentInitial(new_ids, function(a,b){tr.updateFromTorrentGet(a,b);});
     1566                        this.refilterSoon();
     1567                }
     1568
     1569                if (removed_ids) {
     1570                        this.deleteTorrents(removed_ids);
     1571                        this.refilterSoon();
     1572                }
    15631573        },
    15641574
    15651575        refreshTorrents: function(ids) {
    1566                 var tr = this;
    15671576                if (!ids)
    15681577                        ids = 'recently-active';
    1569 
    1570                 this.remote.getUpdatedDataFor(ids, function(active, removed) { tr.updateTorrentsData(active, removed); });
    1571         },
    1572 
    1573         updateTorrentsData: function(updated, removed_ids) {
    1574                 var tr = this;
    1575                 var new_torrent_ids = [];
    1576                 var refresh_files_for = [];
    1577                 var selected_torrents = this.getSelectedTorrents();
    1578 
    1579                 for (var i=0, o; o=updated[i]; ++i) {
    1580                         var t = tr._torrents[o.id];
    1581                         if (t == null)
    1582                                 new_torrent_ids.push(o.id);
    1583                         else {
    1584                                 t.refresh(o);
    1585                                 if (selected_torrents.indexOf(t) != -1)
    1586                                         refresh_files_for.push(t.getId());
    1587                         }
    1588                 }
    1589 
    1590                 if (refresh_files_for.length > 0)
    1591                         tr.remote.loadTorrentFiles(refresh_files_for);
    1592 
    1593                 if (new_torrent_ids.length > 0)
    1594                         tr.remote.getInitialDataFor(new_torrent_ids, function(torrents) {tr.addTorrents(torrents);});
    1595 
    1596                 tr.deleteTorrents(removed_ids);
    1597 
    1598                 if (new_torrent_ids.length != 0) {
    1599                         tr.hideiPhoneAddressbar();
    1600                         tr.deselectAll(true);
    1601                 }
    1602         },
    1603 
    1604         updateTorrentsFileData: function(torrents) {
    1605                 for (var i=0, o; o=torrents[i]; ++i) {
    1606                         var t = this._torrents[o.id];
    1607                         if (t) {
    1608                                 t.refreshFiles(o);
    1609                                 if (t === this._files_torrent)
    1610                                         this.refreshFileView();
    1611                         }
    1612                 }
    1613         },
    1614 
     1578                var tr = this;
     1579                this.remote.getTorrentStats(ids, function(a,b){tr.updateFromTorrentGet(a,b);});
     1580        },
    16151581        initializeAllTorrents: function() {
    16161582                var tr = this;
    1617                 this.remote.getInitialDataFor(null ,function(torrents) { tr.addTorrents(torrents); });
     1583                this.remote.getTorrentInitial(null, function(a,b){tr.updateFromTorrentGet(a,b);});
     1584        },
     1585        refreshMetadata: function(ids) {
     1586                var tr = this;
     1587                this.remote.getTorrentMetadata(ids, function(a,b){tr.updateFromTorrentGet(a,b);});
     1588        },
     1589        refreshInspectorTorrents: function(full) {
     1590                var tr = this;
     1591                var ids = tr.getSelectedTorrentIds();
     1592                if (ids.length > 0)
     1593                        this.remote.getTorrentDetails(ids, full, function(a,b){tr.updateFromTorrentGet(a,b);});
    16181594        },
    16191595
     
    16351611                if (iPhone) {
    16361612                        if (row.isSelected())
    1637                                 this.showInspector();
     1613                                this.setInspectorVisible(true);
    16381614                        this.setSelectedRow(row);
    16391615
     
    16611637
    16621638                this._last_torrent_clicked = row.getTorrent().getId();
    1663         },
    1664 
    1665         addTorrents: function(new_torrents)
    1666         {
    1667                 var tr = this;
    1668                 var key = 'dataChanged';
    1669 
    1670                 for (var i=0, row; row=new_torrents[i]; ++i) {
    1671                         var t = new Torrent(row);
    1672                         $(t).bind(key,function() {tr.refilterSoon();});
    1673                         this._torrents[t.getId()] = t;
    1674                 }
    1675 
    1676                 this.refilterSoon();
    16771639        },
    16781640
     
    21982160        getTrackers: function()
    21992161        {
    2200                 var trackers = {};
     2162                var ret = {};
    22012163
    22022164                var torrents = this.getAllTorrents();
    22032165                for (var i=0, torrent; torrent=torrents[i]; ++i) {
    22042166                        var names = [];
    2205                         for (var j=0, tier; tier=torrent._trackerStats[j]; ++j) {
    2206                                 for (var k=0, tracker; tracker=tier[k]; ++k) {
    2207                                         var uri = parseUri(tracker.announce);
    2208                                         var domain = this.getDomainName(uri.host);
    2209                                         var name = this.getReadableDomain(domain);
    2210                                         if (!(name in trackers))
    2211                                                 trackers[name] = { 'uri': uri, 'domain': domain, 'count': 0 };
    2212                                         if (names.indexOf(name) === -1)
    2213                                                 names.push(name);
    2214                                 }
     2167                        var trackers = torrent.getTrackers();
     2168                        for (var j=0, tracker; tracker=trackers[j]; ++j) {
     2169                                var uri = parseUri(tracker.announce);
     2170                                var domain = this.getDomainName(uri.host);
     2171                                var name = this.getReadableDomain(domain);
     2172                                if (!(name in ret))
     2173                                        ret[name] = { 'uri': uri, 'domain': domain, 'count': 0 };
     2174                                if (names.indexOf(name) === -1)
     2175                                        names.push(name);
    22152176                        }
    22162177                        for (var j=0, name; name=names[j]; ++j)
    2217                                 trackers[name].count++;
    2218                 }
    2219 
    2220                 return trackers;
     2178                                ret[name].count++;
     2179                }
     2180
     2181                return ret;
    22212182        },
    22222183
  • trunk/web/javascript/transmission.remote.js

    r12716 r12745  
    3131RPC._PeerLimitGlobal        = 'peer-limit-global';
    3232RPC._PeerLimitPerTorrent    = 'peer-limit-per-torrent';
    33 RPC._PexEnabled             = 'pex-enabled';
     33RPC._PexEnabled             = 'pex-enabled';
    3434RPC._DhtEnabled             = 'dht-enabled';
    3535RPC._LpdEnabled             = 'lpd-enabled';
     
    3737RPC._BlocklistURL           = 'blocklist-url';
    3838RPC._BlocklistSize          = 'blocklist-size';
    39 RPC._UtpEnabled             = 'utp-enabled';
     39RPC._UtpEnabled             = 'utp-enabled';
    4040RPC._PeerPortRandom         = 'peer-port-random-on-start';
    4141RPC._PortForwardingEnabled  = 'port-forwarding-enabled';
    4242RPC._StartAddedTorrent      = 'start-added-torrents';
    43 RPC._QueueMoveTop                       = 'queue-move-top';
    44 RPC._QueueMoveBottom            = 'queue-move-bottom';
    45 RPC._QueueMoveUp                        = 'queue-move-up';
    46 RPC._QueueMoveDown                      = 'queue-move-down';
     43RPC._QueueMoveTop           = 'queue-move-top';
     44RPC._QueueMoveBottom        = 'queue-move-bottom';
     45RPC._QueueMoveUp            = 'queue-move-up';
     46RPC._QueueMoveDown          = 'queue-move-down';
    4747
    4848function TransmissionRemote(controller)
     
    134134        },
    135135
    136         getInitialDataFor: function(torrent_ids, callback) {
     136        getTorrentInitial: function(torrent_ids, callback) {
    137137                var o = {
    138138                        method: 'torrent-get',
    139139                        arguments: {
    140                         fields: Torrent._StaticFields.concat(Torrent._MetaDataFields,
    141                                                              Torrent._DynamicFields,
    142                                                              [ 'files', 'fileStats' ])
     140                                fields: ['id'].concat(Torrent.Fields.Metadata, Torrent.Fields.Stats)
    143141                        }
    144142                };
     
    147145                        o.arguments.ids = torrent_ids;
    148146
    149                 this.sendRequest(o, function(data){ callback(data.arguments.torrents);});
    150         },
    151 
    152         getMetaDataFor: function(torrent_ids, callback) {
     147                this.sendRequest(o, function(data){ callback(data.arguments.torrents, data.arguments.removed);});
     148        },
     149
     150        getTorrentMetadata: function(torrent_ids, callback) {
    153151                var o = {
    154152                        method: 'torrent-get',
    155153                        arguments: {
    156                         fields: Torrent._StaticFields.concat(Torrent._MetaDataFields,
    157                                                              ['files', 'fileStats'])
     154                                fields: ['id'].concat(Torrent.Fields.Metadata)
    158155                        }
    159156                };
     
    165162        },
    166163
    167         getUpdatedDataFor: function(torrent_ids, callback) {
     164        getTorrentStats: function(torrent_ids, callback) {
    168165                var o = {
    169166                        method: 'torrent-get',
    170167                        arguments: {
    171168                                'ids': torrent_ids,
    172                                 fields: [ 'id' ].concat(Torrent._DynamicFields)
     169                                fields: ['id'].concat(Torrent.Fields.Stats)
    173170                        }
    174171                };
     
    177174        },
    178175
    179         loadTorrentFiles: function(torrent_ids) {
    180                 var tr = this._controller;
    181                 this.sendRequest({
     176        /* called for the torrents in the inspector aka details dialog */
     177        getTorrentDetails: function(torrent_ids, full, callback) {
     178                var f = ['id'].concat(Torrent.Fields.StatsExtra);
     179                if (full) // these only need to be loaded once...
     180                        f = f.concat(Torrent.Fields.InfoExtra);
     181                var o = {
    182182                        method: 'torrent-get',
    183                         arguments: { fields: [ 'id', 'fileStats'], ids: torrent_ids }
    184                 }, function(data) {
    185                         tr.updateTorrentsFileData(data.arguments.torrents);
    186                 });
     183                        arguments: {
     184                                'ids': torrent_ids,
     185                                fields: f,
     186                        }
     187                };
     188                this.sendRequest(o, function(data) {callback(data.arguments.torrents,null)});
    187189        },
    188190
Note: See TracChangeset for help on using the changeset viewer.