Changeset 12745
- Timestamp:
- Aug 25, 2011, 11:06:41 PM (11 years ago)
- Location:
- trunk/web/javascript
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/web/javascript/file-row.js
r12716 r12745 91 91 var i = this.getIndex(); 92 92 var t = this.getTorrent(); 93 this.readAttributes(t. _files[i]);93 this.readAttributes(t.getFile(i)); 94 94 this.refreshHTML(); 95 95 }, … … 99 99 }, 100 100 isEditable: function () { 101 return (this.getTorrent(). _files.length>1) && !this.isDone();101 return (this.getTorrent().getFileCount()>1) && !this.isDone(); 102 102 }, 103 103 … … 105 105 { 106 106 var me = this; 107 var file = torrent. _files[i];107 var file = torrent.getFile(i); 108 108 var name = file.name.substring (file.name.lastIndexOf('/')+1); 109 109 -
trunk/web/javascript/torrent.js
r12744 r12745 46 46 47 47 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' ]; 48 Torrent.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 53 Torrent.Fields.Metadata = [ 54 'addedDate', 55 'name', 56 'totalSize' 57 ]; 58 59 // commonly used fields which need to be periodically refreshed 60 Torrent.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 85 Torrent.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 97 Torrent.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 ]; 67 121 68 122 /*** … … 77 131 { 78 132 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]); 85 193 } 86 194 } 87 195 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 fields112 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 array124 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.name130 };131 }132 }133 134 196 return changed; 135 197 }, 136 198 137 refreshMetaData: function(data)138 {139 var changed = this.initMetaData(data);140 if (changed)141 this.fireDataChanged();142 return changed;143 },144 145 199 refresh: function(data) 146 200 { 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'); 202 203 }, 203 204 … … 220 221 getErrorString: function() { return this.fields.errorString; }, 221 222 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; }, 222 225 getHashString: function() { return this.fields.hashString; }, 223 226 getHaveValid: function() { return this.fields.haveValid; }, … … 232 235 getPeersSendingToUs: function() { return this.fields.peersSendingToUs; }, 233 236 getPieceCount: function() { return this.fields.pieceCount; }, 234 getPieceCount: function() { return this.fields.pieceCount; },235 237 getPieceSize: function() { return this.fields.pieceSize; }, 236 238 getPrivateFlag: function() { return this.fields.isPrivate; }, … … 242 244 getStatus: function() { return this.fields.status; }, 243 245 getTotalSize: function() { return this.fields.totalSize; }, 246 getTrackers: function() { return this.fields.trackers; }, 244 247 getUploadSpeed: function() { return this.fields.rateUpload; }, 245 248 getUploadRatio: function() { return this.fields.uploadRatio; }, … … 276 279 } 277 280 }, 278 trackerStats: function() { return this._trackerStats; },279 281 seedRatioLimit: function(controller){ 280 282 switch(this.getSeedRatioMode()) { … … 363 365 Torrent.compareByName = function(ta, tb) 364 366 { 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); 367 375 }; 368 376 Torrent.compareByQueue = function(ta, tb) -
trunk/web/javascript/transmission.js
r12743 r12745 69 69 70 70 if (iPhone) { 71 $('#inspector_close').bind('click', function() { tr. hideInspector(); });71 $('#inspector_close').bind('click', function() { tr.setInspectorVisible(false); }); 72 72 $('#preferences_link').bind('click', function(e) { tr.releaseClutchPreferencesButton(e); }); 73 73 } else { … … 75 75 $(document).bind('keyup', function(e) { tr.keyUp(e); }); 76 76 $('#torrent_container').click(function() { tr.deselectAll(true); }); 77 $('#inspector_link').click(function(e) { tr.toggleInspector Clicked(e); });77 $('#inspector_link').click(function(e) { tr.toggleInspector(); }); 78 78 79 79 this.setupSearchBox(); … … 87 87 this._inspector_peers_list = $('#inspector_peers_list')[0]; 88 88 this._inspector_trackers_list = $('#inspector_trackers_list')[0]; 89 this._inspector_tab_files = $('#inspector_tab_files')[0];90 89 this._toolbar_buttons = $('#toolbar ul li'); 91 90 this._toolbar_pause_button = $('#toolbar #pause_selected')[0]; … … 222 221 223 222 if (!iPhone && this[Prefs._ShowInspector]) 224 this.s howInspector();223 this.setInspectorVisible(true); 225 224 226 225 this.initCompactMode(); … … 474 473 selectionChanged: function() 475 474 { 475 if (this[Prefs._ShowInspector]) 476 this.refreshInspectorTorrents(true); 477 476 478 this.updateButtonStates(); 477 479 this.updateInspector(); … … 720 722 }, 721 723 722 toggleInspectorClicked: function(ev) {723 if (this.isButtonEnabled(ev))724 this.toggleInspector();725 },726 727 724 inspectorTabClicked: function(ev, tab) { 728 725 if (iPhone) ev.stopPropagation(); … … 741 738 742 739 filesSelectAllClicked: function() { 743 var t = this._file s_torrent;740 var t = this._file_torrent; 744 741 if (t) 745 742 this.toggleFilesWantedDisplay(t, true); 746 743 }, 747 744 filesDeselectAllClicked: function() { 748 var t = this._file s_torrent;745 var t = this._file_torrent; 749 746 if (t) 750 747 this.toggleFilesWantedDisplay(t, false); … … 752 749 toggleFilesWantedDisplay: function(torrent, wanted) { 753 750 var rows = [ ]; 754 for (var i=0, row; row=this._file s[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)) 756 753 rows.push(row); 757 754 if (rows.length > 0) { … … 1145 1142 var torrents = this.getSelectedTorrents(); 1146 1143 if (!torrents.length && iPhone) { 1147 this. hideInspector();1144 this.setInspectorVisible(false); 1148 1145 return; 1149 1146 } … … 1303 1300 this.changeFileCommand(command, [ row ]); 1304 1301 }, 1305 clearFileList: function() { 1302 clearFileList: function() 1303 { 1306 1304 $(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) { 1314 1315 this.clearFileList(); 1315 1316 return; 1316 1317 } 1317 1318 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; 1329 1323 1330 1324 // build the file list 1331 1325 this.clearFileList(); 1332 this._file s_torrent = torrent;1333 var n = torrent. _files.length;1334 this._file s = new Array(n);1326 this._file_torrent = torrent; 1327 var n = torrent.getFileCount(); 1328 this._file_rows = []; 1335 1329 var fragment = document.createDocumentFragment(); 1336 1330 var tr = this; 1337 1331 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); 1339 1333 fragment.appendChild(row.getElement()); 1340 this._files[i] = row;1341 1334 $(row).bind('wantedToggled',function(e,row,want) {tr.onFileWantedToggled(row,want);}); 1342 1335 $(row).bind('priorityToggled',function(e,row,priority) {tr.onFilePriorityToggled(row,priority);}); … … 1345 1338 }, 1346 1339 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 1353 1345 var html = [ ]; 1354 1346 var fmt = Transmission.fmt; 1355 1347 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>'); 1390 1354 } 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 1392 1384 setInnerHTML(this._inspector_peers_list, html.join('')); 1393 1385 }, 1394 1386 1395 1387 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 1398 1391 var tr = this; 1399 1392 var html = [ ]; 1400 1393 var na = 'N/A'; 1401 1394 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">'); 1407 1419 } 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>'); 1434 1438 } 1435 } 1439 if (tier !== -1) // close last tier 1440 html.push('</ul></div>'); 1441 1442 html.push('</div>'); // inspector_group 1443 } 1444 1436 1445 setInnerHTML(this._inspector_trackers_list, html.join('')); 1437 1446 }, … … 1494 1503 }, 1495 1504 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); 1508 1522 if (iPhone) { 1509 $('body'). addClass('inspector_showing');1510 $('#inspector_close'). show();1523 $('body').toggleClass('inspector_showing',visible); 1524 $('#inspector_close').toggle(visible); 1511 1525 this.hideiPhoneAddressbar(); 1512 1526 } else { 1513 var w = $('#torrent_inspector').width() + 1 + 'px';1527 var w = visible ? $('#torrent_inspector').width() + 1 + 'px' : '0px'; 1514 1528 $('#torrent_container')[0].style.right = w; 1515 1529 } 1516 1530 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); 1559 1560 } 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 } 1563 1573 }, 1564 1574 1565 1575 refreshTorrents: function(ids) { 1566 var tr = this;1567 1576 if (!ids) 1568 1577 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 }, 1615 1581 initializeAllTorrents: function() { 1616 1582 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);}); 1618 1594 }, 1619 1595 … … 1635 1611 if (iPhone) { 1636 1612 if (row.isSelected()) 1637 this.s howInspector();1613 this.setInspectorVisible(true); 1638 1614 this.setSelectedRow(row); 1639 1615 … … 1661 1637 1662 1638 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();1677 1639 }, 1678 1640 … … 2198 2160 getTrackers: function() 2199 2161 { 2200 var trackers= {};2162 var ret = {}; 2201 2163 2202 2164 var torrents = this.getAllTorrents(); 2203 2165 for (var i=0, torrent; torrent=torrents[i]; ++i) { 2204 2166 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); 2215 2176 } 2216 2177 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; 2221 2182 }, 2222 2183 -
trunk/web/javascript/transmission.remote.js
r12716 r12745 31 31 RPC._PeerLimitGlobal = 'peer-limit-global'; 32 32 RPC._PeerLimitPerTorrent = 'peer-limit-per-torrent'; 33 RPC._PexEnabled 33 RPC._PexEnabled = 'pex-enabled'; 34 34 RPC._DhtEnabled = 'dht-enabled'; 35 35 RPC._LpdEnabled = 'lpd-enabled'; … … 37 37 RPC._BlocklistURL = 'blocklist-url'; 38 38 RPC._BlocklistSize = 'blocklist-size'; 39 RPC._UtpEnabled 39 RPC._UtpEnabled = 'utp-enabled'; 40 40 RPC._PeerPortRandom = 'peer-port-random-on-start'; 41 41 RPC._PortForwardingEnabled = 'port-forwarding-enabled'; 42 42 RPC._StartAddedTorrent = 'start-added-torrents'; 43 RPC._QueueMoveTop 44 RPC._QueueMoveBottom 45 RPC._QueueMoveUp 46 RPC._QueueMoveDown 43 RPC._QueueMoveTop = 'queue-move-top'; 44 RPC._QueueMoveBottom = 'queue-move-bottom'; 45 RPC._QueueMoveUp = 'queue-move-up'; 46 RPC._QueueMoveDown = 'queue-move-down'; 47 47 48 48 function TransmissionRemote(controller) … … 134 134 }, 135 135 136 get InitialDataFor: function(torrent_ids, callback) {136 getTorrentInitial: function(torrent_ids, callback) { 137 137 var o = { 138 138 method: 'torrent-get', 139 139 arguments: { 140 fields: Torrent._StaticFields.concat(Torrent._MetaDataFields, 141 Torrent._DynamicFields, 142 [ 'files', 'fileStats' ]) 140 fields: ['id'].concat(Torrent.Fields.Metadata, Torrent.Fields.Stats) 143 141 } 144 142 }; … … 147 145 o.arguments.ids = torrent_ids; 148 146 149 this.sendRequest(o, function(data){ callback(data.arguments.torrents );});150 }, 151 152 get MetaDataFor: 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) { 153 151 var o = { 154 152 method: 'torrent-get', 155 153 arguments: { 156 fields: Torrent._StaticFields.concat(Torrent._MetaDataFields, 157 ['files', 'fileStats']) 154 fields: ['id'].concat(Torrent.Fields.Metadata) 158 155 } 159 156 }; … … 165 162 }, 166 163 167 get UpdatedDataFor: function(torrent_ids, callback) {164 getTorrentStats: function(torrent_ids, callback) { 168 165 var o = { 169 166 method: 'torrent-get', 170 167 arguments: { 171 168 'ids': torrent_ids, 172 fields: [ 'id' ].concat(Torrent._DynamicFields)169 fields: ['id'].concat(Torrent.Fields.Stats) 173 170 } 174 171 }; … … 177 174 }, 178 175 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 = { 182 182 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)}); 187 189 }, 188 190
Note: See TracChangeset
for help on using the changeset viewer.